aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsrinidhi kasagar <srinidhi.kasagar@stericsson.com>2010-10-26 11:03:48 +0530
committersrinidhi kasagar <srinidhi.kasagar@stericsson.com>2010-10-26 11:03:48 +0530
commit18bdc623f29b6c999e922e9f89de1cd0c5db5eb5 (patch)
treee912871915c762c35ee6da9fe614e517d80d003e
parente5f399a021ed08cc3fe5e99104c7dba2c4c9fc90 (diff)
parent6a2966bf13bea310e91c6a276fcc0b86b890f21d (diff)
Merge branch 'generic_2.6.35' into android_35
Conflicts: arch/arm/common/Makefile drivers/char/tty_io.c drivers/misc/Kconfig drivers/misc/Makefile drivers/mmc/card/block.c drivers/mmc/core/core.c drivers/mmc/core/host.c drivers/mmc/core/mmc.c drivers/net/wireless/iwlwifi/iwl-agn.c include/linux/mmc/host.h kernel/printk.c Change-Id: I48bf15115731367fd39580743a0f73d12037cf24
-rw-r--r--Documentation/DocBook/Makefile7
-rw-r--r--Documentation/DocBook/cg2900.tmpl1379
-rw-r--r--Documentation/DocBook/cg2900_fm_radio.tmpl1628
-rw-r--r--Documentation/DocBook/dma.tmpl121
-rw-r--r--Documentation/DocBook/gpio.tmpl112
-rw-r--r--Documentation/DocBook/i2c.tmpl116
-rw-r--r--Documentation/DocBook/i2s.tmpl97
-rw-r--r--Documentation/DocBook/mmc.tmpl115
-rw-r--r--Documentation/DocBook/msp.tmpl104
-rw-r--r--Documentation/DocBook/prcmu-fw-api.tmpl109
-rw-r--r--Documentation/DocBook/shrm.tmpl140
-rw-r--r--Documentation/DocBook/ske_keypad.tmpl89
-rw-r--r--Documentation/DocBook/ste_ff_vibra.tmpl217
-rw-r--r--Documentation/DocBook/stmpe.tmpl120
-rw-r--r--Documentation/DocBook/tc_keypad.tmpl113
-rw-r--r--Documentation/DocBook/touchp.tmpl104
-rw-r--r--Documentation/DocBook/u8500_usb.tmpl148
-rw-r--r--Documentation/arm/memory.txt8
-rw-r--r--Documentation/arm/tcm.txt30
-rw-r--r--Documentation/networking/caif/spi_porting.txt208
-rw-r--r--Documentation/networking/phonet.txt44
-rw-r--r--MAINTAINERS13
-rw-r--r--arch/arm/Kconfig15
-rw-r--r--arch/arm/Kconfig.debug9
-rw-r--r--arch/arm/common/Makefile1
-rw-r--r--arch/arm/common/boottime.c46
-rw-r--r--arch/arm/common/gic.c46
-rw-r--r--arch/arm/configs/mop500_USB_HOST_defconfig1830
-rw-r--r--arch/arm/configs/mop500_defconfig2221
-rw-r--r--arch/arm/configs/mop500_power_defconfig2255
-rw-r--r--arch/arm/configs/realview-smp_defconfig15
-rw-r--r--arch/arm/configs/realview_defconfig15
-rw-r--r--arch/arm/configs/sim5500_defconfig1347
-rw-r--r--arch/arm/configs/sim8500_defconfig1326
-rw-r--r--arch/arm/configs/u300_defconfig37
-rw-r--r--arch/arm/configs/u5500_defconfig1384
-rw-r--r--arch/arm/include/asm/elf.h4
-rw-r--r--arch/arm/include/asm/hardware/pl080.h4
-rw-r--r--arch/arm/include/asm/io.h6
-rw-r--r--arch/arm/include/asm/kexec.h22
-rw-r--r--arch/arm/include/asm/mach/map.h2
-rw-r--r--arch/arm/include/asm/memory.h9
-rw-r--r--arch/arm/include/asm/outercache.h24
-rw-r--r--arch/arm/include/asm/setup.h21
-rw-r--r--arch/arm/include/asm/system.h2
-rw-r--r--arch/arm/kernel/Makefile1
-rw-r--r--arch/arm/kernel/crash_dump.c58
-rw-r--r--arch/arm/kernel/elf.c6
-rw-r--r--arch/arm/kernel/machine_kexec.c39
-rw-r--r--arch/arm/kernel/process.c11
-rw-r--r--arch/arm/kernel/relocate_kernel.S6
-rw-r--r--arch/arm/kernel/setup.c76
-rw-r--r--arch/arm/kernel/smp.c5
-rw-r--r--arch/arm/kernel/smp_twd.c6
-rw-r--r--arch/arm/kernel/tcm.c118
-rw-r--r--arch/arm/mach-realview/core.c30
-rw-r--r--arch/arm/mach-realview/include/mach/board-pb1176.h1
-rw-r--r--arch/arm/mach-realview/include/mach/irqs-pb1176.h2
-rw-r--r--arch/arm/mach-realview/realview_eb.c30
-rw-r--r--arch/arm/mach-realview/realview_pb1176.c46
-rw-r--r--arch/arm/mach-realview/realview_pb11mp.c9
-rw-r--r--arch/arm/mach-realview/realview_pba8.c9
-rw-r--r--arch/arm/mach-realview/realview_pbx.c9
-rw-r--r--arch/arm/mach-s3c64xx/dma.c2
-rw-r--r--arch/arm/mach-u300/clock.c133
-rw-r--r--arch/arm/mach-u300/clock.h5
-rw-r--r--arch/arm/mach-u300/core.c21
-rw-r--r--arch/arm/mach-u300/dummyspichip.c5
-rw-r--r--arch/arm/mach-u300/include/mach/gpio.h3
-rw-r--r--arch/arm/mach-u300/include/mach/memory.h8
-rw-r--r--arch/arm/mach-u300/mmc.c8
-rw-r--r--arch/arm/mach-u300/spi.c10
-rw-r--r--arch/arm/mach-u300/timer.c28
-rw-r--r--arch/arm/mach-ux500/Kconfig218
-rw-r--r--arch/arm/mach-ux500/Kconfig-arch144
-rw-r--r--arch/arm/mach-ux500/Makefile54
-rw-r--r--arch/arm/mach-ux500/board-mop500-mcde.c675
-rw-r--r--arch/arm/mach-ux500/board-mop500-msp.c209
-rw-r--r--arch/arm/mach-ux500/board-mop500-nuib.c50
-rw-r--r--arch/arm/mach-ux500/board-mop500-regulators.c792
-rw-r--r--arch/arm/mach-ux500/board-mop500-regulators.h63
-rw-r--r--arch/arm/mach-ux500/board-mop500-sdi.c296
-rw-r--r--arch/arm/mach-ux500/board-mop500.c1270
-rw-r--r--arch/arm/mach-ux500/board-mop500.h13
-rw-r--r--arch/arm/mach-ux500/board-pdp-mcde.c652
-rw-r--r--arch/arm/mach-ux500/board-u5500.c340
-rw-r--r--arch/arm/mach-ux500/cg2900_devices.c337
-rw-r--r--arch/arm/mach-ux500/clock.c1426
-rw-r--r--arch/arm/mach-ux500/clock.h184
-rw-r--r--arch/arm/mach-ux500/context-db5500.c395
-rw-r--r--arch/arm/mach-ux500/context-db8500.c386
-rw-r--r--arch/arm/mach-ux500/context.c975
-rw-r--r--arch/arm/mach-ux500/context.h57
-rwxr-xr-xarch/arm/mach-ux500/context_arm.S422
-rw-r--r--arch/arm/mach-ux500/cpu-db5500.c95
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c118
-rw-r--r--arch/arm/mach-ux500/cpu.c81
-rw-r--r--arch/arm/mach-ux500/cpufreq.c192
-rw-r--r--arch/arm/mach-ux500/cpuidle.c1228
-rw-r--r--arch/arm/mach-ux500/cpuidle.h57
-rw-r--r--arch/arm/mach-ux500/devices-common.c107
-rw-r--r--arch/arm/mach-ux500/devices-common.h80
-rw-r--r--arch/arm/mach-ux500/devices-db5500.c82
-rw-r--r--arch/arm/mach-ux500/devices-db5500.h76
-rw-r--r--arch/arm/mach-ux500/devices-db8500.c204
-rw-r--r--arch/arm/mach-ux500/devices-db8500.h98
-rw-r--r--arch/arm/mach-ux500/devices.c169
-rw-r--r--arch/arm/mach-ux500/dma-db5500.c220
-rw-r--r--arch/arm/mach-ux500/dma-db8500.c259
-rw-r--r--arch/arm/mach-ux500/gpio.c163
-rw-r--r--arch/arm/mach-ux500/hotplug.c75
-rw-r--r--arch/arm/mach-ux500/hsi.c265
-rw-r--r--arch/arm/mach-ux500/include/mach/ab8500_codec.h327
-rw-r--r--arch/arm/mach-ux500/include/mach/ab8500_codec_p.h3082
-rw-r--r--arch/arm/mach-ux500/include/mach/ab8500_codec_p_v1_0.h3037
-rw-r--r--arch/arm/mach-ux500/include/mach/ab8500_codec_v1_0.h329
-rw-r--r--arch/arm/mach-ux500/include/mach/ab8500_denc.h76
-rw-r--r--arch/arm/mach-ux500/include/mach/ab8500_gpadc.h36
-rw-r--r--arch/arm/mach-ux500/include/mach/cg2900_devices.h120
-rw-r--r--arch/arm/mach-ux500/include/mach/db5500-keypad.h25
-rw-r--r--arch/arm/mach-ux500/include/mach/db5500-regs.h28
-rw-r--r--arch/arm/mach-ux500/include/mach/db8500-regs.h17
-rw-r--r--arch/arm/mach-ux500/include/mach/debug.h52
-rw-r--r--arch/arm/mach-ux500/include/mach/devices.h38
-rw-r--r--arch/arm/mach-ux500/include/mach/gpio.h181
-rw-r--r--arch/arm/mach-ux500/include/mach/hardware.h136
-rw-r--r--arch/arm/mach-ux500/include/mach/hcl_defs.h252
-rw-r--r--arch/arm/mach-ux500/include/mach/hsi-stm.h188
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs-board-mop500.h47
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs-board-u5500.h21
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs-db5500.h108
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs-db8500.h131
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs.h92
-rw-r--r--arch/arm/mach-ux500/include/mach/isa_ioctl.h51
-rw-r--r--arch/arm/mach-ux500/include/mach/kpd.h123
-rw-r--r--arch/arm/mach-ux500/include/mach/mbox.h88
-rw-r--r--arch/arm/mach-ux500/include/mach/mmc.h384
-rw-r--r--arch/arm/mach-ux500/include/mach/msp.h974
-rw-r--r--arch/arm/mach-ux500/include/mach/mtu.h59
-rw-r--r--arch/arm/mach-ux500/include/mach/musb_db8500.h67
-rw-r--r--arch/arm/mach-ux500/include/mach/prcmu-db5500.h45
-rw-r--r--arch/arm/mach-ux500/include/mach/prcmu-fw-api.h282
-rw-r--r--arch/arm/mach-ux500/include/mach/prcmu-fw-defs_v1.h588
-rw-r--r--arch/arm/mach-ux500/include/mach/prcmu-regs.h97
-rw-r--r--arch/arm/mach-ux500/include/mach/scu.h25
-rw-r--r--arch/arm/mach-ux500/include/mach/sensors1p.h24
-rw-r--r--arch/arm/mach-ux500/include/mach/setup.h16
-rw-r--r--arch/arm/mach-ux500/include/mach/shrm.h23
-rw-r--r--arch/arm/mach-ux500/include/mach/shrm_config.h111
-rw-r--r--arch/arm/mach-ux500/include/mach/shrm_driver.h175
-rw-r--r--arch/arm/mach-ux500/include/mach/shrm_net.h43
-rw-r--r--arch/arm/mach-ux500/include/mach/shrm_private.h187
-rw-r--r--arch/arm/mach-ux500/include/mach/ste-dma40-db5500.h135
-rw-r--r--arch/arm/mach-ux500/include/mach/ste-dma40-db8500.h147
-rw-r--r--arch/arm/mach-ux500/include/mach/ste_audio_io_ioctl.h190
-rw-r--r--arch/arm/mach-ux500/include/mach/ste_audio_io_vibrator.h37
-rw-r--r--arch/arm/mach-ux500/include/mach/stm_musb.h164
-rw-r--r--arch/arm/mach-ux500/include/mach/system.h6
-rw-r--r--arch/arm/mach-ux500/include/mach/tc35893-keypad.h46
-rw-r--r--arch/arm/mach-ux500/include/mach/tee_ta_start_modem.h48
-rw-r--r--arch/arm/mach-ux500/include/mach/u8500_acodec_ab8500.h284
-rw-r--r--arch/arm/mach-ux500/include/mach/uart.h17
-rw-r--r--arch/arm/mach-ux500/localtimer.c9
-rw-r--r--arch/arm/mach-ux500/mbox.c567
-rw-r--r--arch/arm/mach-ux500/mcde.c90
-rw-r--r--arch/arm/mach-ux500/mloader_helper.c177
-rw-r--r--arch/arm/mach-ux500/modem_irq.c139
-rw-r--r--arch/arm/mach-ux500/musb_db8500.c750
-rw-r--r--arch/arm/mach-ux500/pins-db5500.h620
-rw-r--r--arch/arm/mach-ux500/pins-db8500.h742
-rw-r--r--arch/arm/mach-ux500/platsmp.c2
-rw-r--r--arch/arm/mach-ux500/pm-common.c335
-rw-r--r--arch/arm/mach-ux500/pm-common.h24
-rw-r--r--arch/arm/mach-ux500/pm.c140
-rw-r--r--arch/arm/mach-ux500/pm.h209
-rw-r--r--arch/arm/mach-ux500/prcmu-db5500.c375
-rw-r--r--arch/arm/mach-ux500/prcmu-db8500.c1777
-rw-r--r--arch/arm/mach-ux500/pwm.c461
-rw-r--r--arch/arm/mach-ux500/regulator-u8500.c584
-rw-r--r--arch/arm/mach-ux500/regulator-u8500.h45
-rw-r--r--arch/arm/mach-ux500/savecontext.S502
-rw-r--r--arch/arm/mach-ux500/sensors1p.c299
-rw-r--r--arch/arm/mach-ux500/ste-dma40-db8500.h154
-rw-r--r--arch/arm/mach-ux500/suspend.c149
-rw-r--r--arch/arm/mach-ux500/tee_service_svp.c66
-rw-r--r--arch/arm/mach-ux500/tee_ta_start_modem_svp.c56
-rw-r--r--arch/arm/mach-ux500/tee_ux500.c97
-rw-r--r--arch/arm/mach-ux500/timer-db8500-prcm.c92
-rw-r--r--arch/arm/mach-ux500/timer-rtt.c173
-rw-r--r--arch/arm/mach-ux500/timer.c301
-rw-r--r--arch/arm/mach-ux500/virt-regulator-u8500.c315
-rw-r--r--arch/arm/mach-versatile/core.c28
-rw-r--r--arch/arm/mm/cache-l2x0.c26
-rw-r--r--arch/arm/mm/init.c13
-rw-r--r--arch/arm/mm/mmu.c27
-rw-r--r--arch/arm/mm/proc-v7.S13
-rw-r--r--arch/arm/plat-iop/time.c53
-rw-r--r--arch/arm/plat-nomadik/gpio.c574
-rw-r--r--arch/arm/plat-nomadik/include/plat/gpio.h18
-rw-r--r--arch/arm/plat-nomadik/include/plat/mtu.h6
-rw-r--r--arch/arm/plat-nomadik/include/plat/pincfg.h144
-rw-r--r--arch/arm/plat-nomadik/include/plat/ske.h50
-rw-r--r--arch/arm/plat-nomadik/include/plat/ste_dma40.h239
-rw-r--r--arch/arm/plat-nomadik/timer.c47
-rw-r--r--arch/arm/plat-spear/time.c47
-rw-r--r--arch/arm/plat-versatile/Makefile4
-rw-r--r--arch/arm/plat-versatile/leds.c103
-rw-r--r--arch/arm/tools/mach-types2
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/amba/bus.c2
-rw-r--r--drivers/bluetooth/Kconfig7
-rw-r--r--drivers/bluetooth/Makefile2
-rw-r--r--drivers/bluetooth/cg2900_hci.c896
-rw-r--r--drivers/char/Makefile3
-rw-r--r--drivers/char/shrm_char.c838
-rw-r--r--drivers/char/tty_io.c1
-rw-r--r--drivers/crypto/Kconfig10
-rw-r--r--drivers/crypto/Makefile2
-rwxr-xr-xdrivers/crypto/ux500/Kconfig15
-rwxr-xr-xdrivers/crypto/ux500/Makefile11
-rwxr-xr-xdrivers/crypto/ux500/hash/Makefile9
-rwxr-xr-xdrivers/crypto/ux500/hash/hash_alg.h476
-rwxr-xr-xdrivers/crypto/ux500/hash/hash_alg_p.h26
-rwxr-xr-xdrivers/crypto/ux500/hash/hash_core.c1756
-rw-r--r--drivers/dma/Kconfig15
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/amba-pl08x.c2167
-rw-r--r--drivers/dma/coh901318.c169
-rw-r--r--drivers/dma/dmaengine.c4
-rw-r--r--drivers/dma/ste_dma40.c2281
-rw-r--r--drivers/dma/ste_dma40_ll.c206
-rw-r--r--drivers/dma/ste_dma40_ll.h120
-rw-r--r--drivers/gpio/Kconfig7
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/stmpe-gpio.c404
-rw-r--r--drivers/gpio/tc35892-gpio.c8
-rw-r--r--drivers/hwmon/Kconfig27
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/ab8500.c733
-rw-r--r--drivers/hwmon/lsm303dlh_a.c780
-rw-r--r--drivers/hwmon/lsm303dlh_m.c617
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c48
-rw-r--r--drivers/input/keyboard/Kconfig55
-rw-r--r--drivers/input/keyboard/Makefile3
-rw-r--r--drivers/input/keyboard/db5500_keypad.c422
-rw-r--r--drivers/input/keyboard/nomadik-ske-keypad.c490
-rw-r--r--drivers/input/keyboard/stmpe-keypad.c386
-rw-r--r--drivers/input/keyboard/tc35893-keypad.c942
-rw-r--r--drivers/input/misc/Kconfig20
-rw-r--r--drivers/input/misc/Makefile3
-rw-r--r--drivers/input/misc/ab8500-ponkey.c156
-rw-r--r--drivers/input/misc/ste_ff_vibra.c234
-rw-r--r--drivers/input/touchscreen/Kconfig32
-rw-r--r--drivers/input/touchscreen/Makefile3
-rw-r--r--drivers/input/touchscreen/bu21013_ts.c980
-rw-r--r--drivers/input/touchscreen/synaptics_i2c_rmi4.c951
-rw-r--r--drivers/input/touchscreen/synaptics_rmi4_touchpad.c492
-rw-r--r--drivers/leds/Kconfig10
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-lp5521.c735
-rw-r--r--drivers/leds/leds-pwm.c8
-rw-r--r--drivers/media/radio/CG2900/Makefile8
-rw-r--r--drivers/media/radio/CG2900/cg2900_fm_api.c2973
-rw-r--r--drivers/media/radio/CG2900/cg2900_fm_api.h1002
-rw-r--r--drivers/media/radio/CG2900/cg2900_fm_driver.c4610
-rw-r--r--drivers/media/radio/CG2900/cg2900_fm_driver.h1604
-rw-r--r--drivers/media/radio/CG2900/radio-cg2900.c2568
-rw-r--r--drivers/media/radio/Kconfig16
-rw-r--r--drivers/media/radio/Makefile1
-rw-r--r--drivers/mfd/Kconfig90
-rw-r--r--drivers/mfd/Makefile7
-rw-r--r--drivers/mfd/ab3100-core.c143
-rw-r--r--drivers/mfd/ab3100-otp.c16
-rw-r--r--drivers/mfd/ab3550-core.c23
-rwxr-xr-xdrivers/mfd/ab5500-core.c2157
-rw-r--r--drivers/mfd/ab8500-core.c602
-rw-r--r--drivers/mfd/ab8500-debugfs.c845
-rw-r--r--drivers/mfd/ab8500-i2c.c105
-rw-r--r--drivers/mfd/ab8500-spi.c14
-rw-r--r--drivers/mfd/ab8500-sysctrl.c79
-rw-r--r--drivers/mfd/cg2900/Makefile13
-rw-r--r--drivers/mfd/cg2900/cg2900_audio.c2872
-rw-r--r--drivers/mfd/cg2900/cg2900_char_devices.c709
-rw-r--r--drivers/mfd/cg2900/cg2900_char_devices.h36
-rw-r--r--drivers/mfd/cg2900/cg2900_chip.c2064
-rw-r--r--drivers/mfd/cg2900/cg2900_chip.h576
-rw-r--r--drivers/mfd/cg2900/cg2900_core.c2287
-rw-r--r--drivers/mfd/cg2900/cg2900_core.h303
-rw-r--r--drivers/mfd/cg2900/cg2900_debug.h77
-rw-r--r--drivers/mfd/cg2900/cg2900_uart.c1587
-rw-r--r--drivers/mfd/cg2900/hci_defines.h81
-rw-r--r--drivers/mfd/cg2900/stlc2690_chip.c1105
-rw-r--r--drivers/mfd/cg2900/stlc2690_chip.h37
-rw-r--r--drivers/mfd/stmpe.c1017
-rw-r--r--drivers/mfd/stmpe.h183
-rw-r--r--drivers/misc/Kconfig51
-rw-r--r--drivers/misc/Makefile12
-rw-r--r--drivers/misc/ab8500-pwm.c168
-rw-r--r--drivers/misc/ab8500_denc/Kconfig5
-rw-r--r--drivers/misc/ab8500_denc/Makefile4
-rw-r--r--drivers/misc/ab8500_denc/ab8500_denc.c487
-rw-r--r--drivers/misc/ab8500_denc/ab8500_denc_regs.h352
-rw-r--r--drivers/misc/ab8500_gpadc.c269
-rw-r--r--drivers/misc/arm-charlcd.c396
-rw-r--r--drivers/misc/audio_io_dev/Kconfig11
-rw-r--r--drivers/misc/audio_io_dev/Makefile9
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_ab8500_reg_defs.h329
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_core.c1207
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_core.h126
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_dev.c716
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_dev.h32
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_func.c4044
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_func.h337
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.c195
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.h56
-rw-r--r--drivers/misc/bh1780gli.c273
-rw-r--r--drivers/misc/hsi/Kconfig28
-rw-r--r--drivers/misc/hsi/Makefile8
-rw-r--r--drivers/misc/hsi/hsi-algo-stm.c1471
-rw-r--r--drivers/misc/hsi/hsi-legacy/Kconfig41
-rw-r--r--drivers/misc/hsi/hsi-legacy/Makefile9
-rw-r--r--drivers/misc/hsi/hsi-legacy/hsi_driver.c656
-rw-r--r--drivers/misc/hsi/hsi-legacy/hsi_driver.h250
-rw-r--r--drivers/misc/hsi/hsi-legacy/hsi_driver_bus.c186
-rw-r--r--drivers/misc/hsi/hsi-legacy/hsi_driver_dma.c250
-rw-r--r--drivers/misc/hsi/hsi-legacy/hsi_driver_if.c503
-rw-r--r--drivers/misc/hsi/hsi-legacy/hsi_driver_int.c481
-rw-r--r--drivers/misc/hsi/hsi-legacy/hsi_test_protocol_driver.c334
-rw-r--r--drivers/misc/hsi/hsi-stm.c719
-rw-r--r--drivers/misc/hsi/hsi.c503
-rw-r--r--drivers/misc/hsi/hsidev.c599
-rw-r--r--drivers/misc/hwmem/Makefile3
-rw-r--r--drivers/misc/hwmem/hwmem-cache.c308
-rw-r--r--drivers/misc/hwmem/hwmem-cache.h27
-rw-r--r--drivers/misc/hwmem/hwmem-cache_ux500.c79
-rw-r--r--drivers/misc/hwmem/hwmem-defs.h66
-rw-r--r--drivers/misc/hwmem/hwmem-ioctl.c470
-rw-r--r--drivers/misc/hwmem/hwmem-main.c582
-rw-r--r--drivers/misc/i2s/Kconfig29
-rw-r--r--drivers/misc/i2s/Makefile8
-rw-r--r--drivers/misc/i2s/i2s.c564
-rw-r--r--drivers/misc/i2s/i2s_test_protocol_driver.c342
-rw-r--r--drivers/misc/i2s/msp_i2s.c1952
-rw-r--r--drivers/misc/i2s/msp_i2s.h402
-rw-r--r--drivers/misc/msw/Kconfig28
-rw-r--r--drivers/misc/msw/Makefile3
-rw-r--r--drivers/misc/msw/ipc_hsi_protocol.c942
-rw-r--r--drivers/misc/msw/ipc_hsi_protocol.h71
-rw-r--r--drivers/misc/msw/ipc_protocol_if.h36
-rw-r--r--drivers/misc/msw/isa_access.c986
-rw-r--r--drivers/misc/msw/isa_access.h79
-rw-r--r--drivers/misc/shrm/Kconfig49
-rw-r--r--drivers/misc/shrm/Makefile11
-rw-r--r--drivers/misc/shrm/modem_shrm_driver.c668
-rw-r--r--drivers/misc/shrm/shrm_driver.c1440
-rw-r--r--drivers/misc/shrm/shrm_fifo.c757
-rw-r--r--drivers/misc/shrm/shrm_protocol.c1157
-rw-r--r--drivers/mmc/card/block.c59
-rw-r--r--drivers/mmc/core/core.c29
-rw-r--r--drivers/mmc/core/host.c2
-rw-r--r--drivers/mmc/core/mmc.c40
-rw-r--r--drivers/mmc/core/mmc_ops.c23
-rwxr-xr-xdrivers/mmc/core/sdio_io.c4
-rw-r--r--drivers/mmc/host/Kconfig65
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/mmc-u8500.c1806
-rw-r--r--drivers/mmc/host/mmc-u8500.h25
-rw-r--r--drivers/mmc/host/mmci.c369
-rw-r--r--drivers/mmc/host/mmci.h51
-rw-r--r--drivers/mmc/host/omap_hsmmc.c21
-rw-r--r--drivers/mmc/host/pxamci.c41
-rw-r--r--drivers/net/Makefile4
-rw-r--r--drivers/net/caif/Kconfig22
-rw-r--r--drivers/net/caif/Makefile14
-rw-r--r--drivers/net/caif/caif_serial.c3
-rw-r--r--drivers/net/caif/caif_spi.c847
-rw-r--r--drivers/net/caif/caif_spi_slave.c252
-rw-r--r--drivers/net/u8500_shrm.c329
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c2
-rw-r--r--drivers/power/Kconfig6
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/ab8500_bm.c4148
-rw-r--r--drivers/regulator/Kconfig8
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/ab3100.c5
-rw-r--r--drivers/regulator/ab8500.c750
-rw-r--r--drivers/rtc/rtc-ab3100.c2
-rw-r--r--drivers/rtc/rtc-ab8500.c103
-rw-r--r--drivers/rtc/rtc-pl031.c2
-rw-r--r--drivers/serial/8250.c37
-rw-r--r--drivers/serial/Kconfig9
-rw-r--r--drivers/serial/amba-pl011.c296
-rw-r--r--drivers/spi/Kconfig16
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/amba-pl022.c756
-rw-r--r--drivers/spi/stm_msp.c1503
-rw-r--r--drivers/tee/Kconfig13
-rw-r--r--drivers/tee/Makefile8
-rw-r--r--drivers/tee/tee_driver.c484
-rw-r--r--drivers/tee/tee_service.c17
-rw-r--r--drivers/usb/core/hub.c8
-rw-r--r--drivers/usb/gadget/composite.c8
-rw-r--r--drivers/usb/gadget/epautoconf.c25
-rw-r--r--drivers/usb/gadget/f_acm.c2
-rw-r--r--drivers/usb/gadget/f_ecm.c25
-rw-r--r--drivers/usb/gadget/file_storage.c12
-rw-r--r--drivers/usb/musb/Kconfig12
-rw-r--r--drivers/usb/musb/Makefile5
-rw-r--r--drivers/usb/musb/musb_core.c52
-rw-r--r--drivers/usb/musb/musb_core.h4
-rw-r--r--drivers/usb/musb/musb_gadget.c155
-rw-r--r--drivers/usb/musb/musb_host.c45
-rw-r--r--drivers/usb/musb/ste_config.h50
-rw-r--r--drivers/usb/musb/stm_musb.c552
-rw-r--r--drivers/usb/musb/stm_musb_dma.c740
-rw-r--r--drivers/usb/musb/stm_musb_dma.h59
-rw-r--r--drivers/video/Kconfig3
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/av8100/Kconfig23
-rw-r--r--drivers/video/av8100/Makefile10
-rw-r--r--drivers/video/av8100/av8100.c3303
-rw-r--r--drivers/video/av8100/av8100_fw.h1038
-rw-r--r--drivers/video/av8100/av8100_regs.h346
-rw-r--r--drivers/video/av8100/av8100v2_fw.h1165
-rw-r--r--drivers/video/av8100/hdmi.c1977
-rw-r--r--drivers/video/av8100/hdmi_loc.h57
-rw-r--r--drivers/video/b2r2/Kconfig6
-rw-r--r--drivers/video/b2r2/Makefile25
-rw-r--r--drivers/video/b2r2/b2r2_blt_main.c3326
-rw-r--r--drivers/video/b2r2/b2r2_core.c2613
-rw-r--r--drivers/video/b2r2/b2r2_core.h222
-rw-r--r--drivers/video/b2r2/b2r2_debug.c67
-rw-r--r--drivers/video/b2r2/b2r2_debug.h86
-rw-r--r--drivers/video/b2r2/b2r2_filters.c372
-rw-r--r--drivers/video/b2r2/b2r2_filters.h71
-rw-r--r--drivers/video/b2r2/b2r2_generic.c2839
-rw-r--r--drivers/video/b2r2/b2r2_generic.h51
-rw-r--r--drivers/video/b2r2/b2r2_global.h119
-rw-r--r--drivers/video/b2r2/b2r2_hw.h534
-rw-r--r--drivers/video/b2r2/b2r2_input_validation.c413
-rw-r--r--drivers/video/b2r2/b2r2_input_validation.h28
-rw-r--r--drivers/video/b2r2/b2r2_internal.h365
-rw-r--r--drivers/video/b2r2/b2r2_kernel_if.c37
-rw-r--r--drivers/video/b2r2/b2r2_mem_alloc.c726
-rw-r--r--drivers/video/b2r2/b2r2_mem_alloc.h140
-rw-r--r--drivers/video/b2r2/b2r2_node_gen.c80
-rw-r--r--drivers/video/b2r2/b2r2_node_split.c3599
-rw-r--r--drivers/video/b2r2/b2r2_node_split.h121
-rw-r--r--drivers/video/b2r2/b2r2_profiler/Makefile3
-rw-r--r--drivers/video/b2r2/b2r2_profiler/b2r2_profiler.c254
-rw-r--r--drivers/video/b2r2/b2r2_profiler_api.h66
-rw-r--r--drivers/video/b2r2/b2r2_profiler_socket.c105
-rw-r--r--drivers/video/b2r2/b2r2_profiler_socket.h22
-rw-r--r--drivers/video/b2r2/b2r2_structures.h226
-rw-r--r--drivers/video/b2r2/b2r2_timing.c22
-rw-r--r--drivers/video/b2r2/b2r2_timing.h22
-rw-r--r--drivers/video/b2r2/b2r2_utils.c342
-rw-r--r--drivers/video/b2r2/b2r2_utils.h50
-rw-r--r--drivers/video/backlight/pwm_bl.c7
-rw-r--r--drivers/video/mcde/Kconfig76
-rw-r--r--drivers/video/mcde/Makefile16
-rw-r--r--drivers/video/mcde/display-ab8500.c426
-rw-r--r--drivers/video/mcde/display-av8100.c718
-rw-r--r--drivers/video/mcde/display-generic_dsi.c215
-rw-r--r--drivers/video/mcde/display-sony_sy35560_dsi.c239
-rw-r--r--drivers/video/mcde/display-vuib500-dpi.c218
-rw-r--r--drivers/video/mcde/dsilink_regs.h2024
-rw-r--r--drivers/video/mcde/mcde_bus.c261
-rw-r--r--drivers/video/mcde/mcde_display.c427
-rw-r--r--drivers/video/mcde/mcde_dss.c339
-rw-r--r--drivers/video/mcde/mcde_fb.c705
-rw-r--r--drivers/video/mcde/mcde_hw.c2484
-rw-r--r--drivers/video/mcde/mcde_mod.c69
-rw-r--r--drivers/video/mcde/mcde_regs.h5297
-rw-r--r--firmware/BT_src_coeff_1.1.fw.ihex130
-rw-r--r--firmware/CG2900_1_05_SOC_generic_V11_mod.fw.ihex61
-rw-r--r--firmware/CG2900_1_0C4_1C5.fw.ihex682
-rw-r--r--firmware/Cobra_FM_SOC1_coef.fw.ihex195
-rw-r--r--firmware/Cobra_FM_SOC1_prog.fw.ihex3060
-rw-r--r--firmware/EXT_src_coeff_1.1.fw.ihex130
-rw-r--r--firmware/Makefile11
-rw-r--r--firmware/R1f.2_SoC1v20_BT_src_coeff_1.1.fw.ihex130
-rw-r--r--firmware/R1f.2_SoC1v20_Cobra_FM_SOC1_coef.fw.ihex195
-rw-r--r--firmware/R1f.2_SoC1v20_Cobra_FM_SOC1_prog.fw.ihex3060
-rw-r--r--firmware/R1f.2_SoC1v20_EXT_src_coeff_1.1.fw.ihex130
-rw-r--r--firmware/R2c_SoC2v01_BT_src_coeff_1.1.fw.ihex130
-rw-r--r--firmware/R2c_SoC2v01_Cobra_FM_SOC2_coef.fw.ihex195
-rw-r--r--firmware/R2c_SoC2v01_Cobra_FM_SOC2_prog.fw.ihex3060
-rw-r--r--firmware/R2c_SoC2v01_EXT_src_coeff_1.1.fw.ihex130
-rw-r--r--firmware/STLC2600_R6_03_01.fw.ihex29
-rw-r--r--firmware/STLC2600_R6_04_02.fw.ihex28
-rw-r--r--firmware/STLC2690_R6_03_A1_E5.fw.ihex386
-rw-r--r--firmware/STLC2690_R6_04_A2.fw.ihex334
-rw-r--r--firmware/cg2900_fm_bt_src_coeff_info.fw.ihex41
-rw-r--r--firmware/cg2900_fm_ext_src_coeff_info.fw.ihex41
-rw-r--r--firmware/cg2900_fm_fm_coeff_info.fw.ihex41
-rw-r--r--firmware/cg2900_fm_fm_prog_info.fw.ihex40
-rw-r--r--firmware/cg2900_patch_info.fw.ihex41
-rw-r--r--firmware/cg2900_settings_info.fw.ihex49
-rw-r--r--fs/mpage.c2
-rw-r--r--fs/partitions/Kconfig19
-rw-r--r--fs/partitions/Makefile1
-rwxr-xr-xfs/partitions/blkdev_parts.c127
-rwxr-xr-xfs/partitions/blkdev_parts.h14
-rw-r--r--fs/partitions/check.c4
-rw-r--r--include/linux/amba/bus.h15
-rw-r--r--include/linux/amba/mmci.h12
-rw-r--r--include/linux/amba/pl022.h13
-rw-r--r--include/linux/amba/pl08x.h222
-rw-r--r--include/linux/amba/serial.h14
-rw-r--r--include/linux/boottime.h89
-rw-r--r--include/linux/caif/caif_socket.h34
-rw-r--r--include/linux/dmaengine.h79
-rw-r--r--include/linux/hsi-legacy.h152
-rw-r--r--include/linux/hsi.h356
-rw-r--r--include/linux/hsi_test_prot.h37
-rw-r--r--include/linux/hsidev.h61
-rw-r--r--include/linux/hwmem.h500
-rw-r--r--include/linux/i2c/lp5521.h43
-rw-r--r--include/linux/i2s/i2s.h202
-rw-r--r--include/linux/i2s/i2s_test_prot.h45
-rw-r--r--include/linux/input/bu21013.h167
-rw-r--r--include/linux/input/synaptics_i2c_rmi4.h269
-rw-r--r--include/linux/leds_pwm.h1
-rw-r--r--include/linux/lsm303dlh.h117
-rw-r--r--include/linux/mfd/ab8500.h71
-rw-r--r--include/linux/mfd/ab8500/ab8500-bm.h152
-rw-r--r--include/linux/mfd/ab8500/ab8500-gpadc.h47
-rw-r--r--include/linux/mfd/ab8500/sysctrl.h254
-rw-r--r--include/linux/mfd/abx500.h50
-rw-r--r--include/linux/mfd/cg2900.h205
-rw-r--r--include/linux/mfd/cg2900_audio.h587
-rw-r--r--include/linux/mfd/stmpe.h207
-rw-r--r--include/linux/mfd/tc35892.h4
-rw-r--r--include/linux/mmc/card.h4
-rw-r--r--include/linux/mmc/core.h1
-rw-r--r--include/linux/mmc/host.h28
-rw-r--r--include/linux/mmc/mmc.h10
-rw-r--r--include/linux/phonet.h4
-rw-r--r--include/linux/pwm_backlight.h1
-rw-r--r--include/linux/regulator/ab8500.h26
-rw-r--r--include/linux/serial_8250.h5
-rw-r--r--include/linux/serial_core.h6
-rw-r--r--include/linux/spi/stm_msp.h542
-rw-r--r--include/linux/tee.h143
-rw-r--r--include/linux/usb/ch9.h10
-rw-r--r--include/linux/videodev2.h26
-rw-r--r--include/net/bluetooth/hci.h17
-rw-r--r--include/net/bluetooth/hci_core.h4
-rw-r--r--include/net/caif/caif_dev.h8
-rw-r--r--include/net/caif/caif_layer.h6
-rw-r--r--include/net/caif/caif_spi.h153
-rw-r--r--include/net/caif/cfcnfg.h16
-rw-r--r--include/net/caif/cfsrvl.h15
-rw-r--r--include/net/phonet/pep.h21
-rw-r--r--include/video/av8100.h581
-rw-r--r--include/video/b2r2_blt.h580
-rw-r--r--include/video/hdmi.h158
-rw-r--r--include/video/mcde.h400
-rw-r--r--include/video/mcde_display-ab8500.h25
-rw-r--r--include/video/mcde_display-av8100.h34
-rw-r--r--include/video/mcde_display-generic_dsi.h34
-rw-r--r--include/video/mcde_display-sony_sy35560_dsi.h45
-rw-r--r--include/video/mcde_display-vuib500-dpi.h31
-rw-r--r--include/video/mcde_display.h139
-rw-r--r--include/video/mcde_dss.h78
-rw-r--r--include/video/mcde_fb.h59
-rw-r--r--init/Kconfig9
-rw-r--r--init/Makefile1
-rw-r--r--init/boottime.c467
-rw-r--r--init/main.c6
-rw-r--r--kernel/printk.c4
-rw-r--r--kernel/time.c2
-rw-r--r--net/bluetooth/hci_conn.c97
-rw-r--r--net/bluetooth/hci_event.c4
-rw-r--r--net/bluetooth/hci_sock.c3
-rw-r--r--net/bluetooth/rfcomm/core.c10
-rw-r--r--net/caif/Kconfig7
-rw-r--r--net/caif/Makefile14
-rw-r--r--net/caif/caif_config_util.c5
-rw-r--r--net/caif/caif_dev.c36
-rw-r--r--net/caif/caif_socket.c89
-rw-r--r--net/caif/cfcnfg.c103
-rw-r--r--net/caif/cfctrl.c67
-rw-r--r--net/caif/cfdbgl.c6
-rw-r--r--net/caif/cfdgml.c18
-rw-r--r--net/caif/cffrml.c14
-rw-r--r--net/caif/cfmuxl.c14
-rw-r--r--net/caif/cfpkt_skbuff.c53
-rw-r--r--net/caif/cfrfml.c318
-rw-r--r--net/caif/cfserl.c11
-rw-r--r--net/caif/cfsrvl.c43
-rw-r--r--net/caif/cfutill.c20
-rw-r--r--net/caif/cfveil.c18
-rw-r--r--net/caif/cfvidl.c8
-rw-r--r--net/caif/chnl_net.c104
-rw-r--r--net/phonet/Kconfig11
-rw-r--r--net/phonet/pep.c440
-rwxr-xr-xscripts/checkpatch.pl14
-rw-r--r--sound/Kconfig40
-rw-r--r--sound/Makefile7
-rw-r--r--sound/ab8500_codec.c6697
-rw-r--r--sound/ab8500_codec_v1_0.c6405
-rw-r--r--sound/arm/Kconfig12
-rw-r--r--sound/arm/Makefile4
-rw-r--r--sound/arm/u8500_alsa_ab8500.c2710
-rw-r--r--sound/arm/u8500_alsa_ab8500.h165
-rw-r--r--sound/arm/u8500_alsa_hdmi.c936
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/codecs/Kconfig12
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/ab3550.c1456
-rw-r--r--sound/soc/codecs/ab3550.h336
-rw-r--r--sound/soc/codecs/av8100_audio.c334
-rw-r--r--sound/soc/codecs/av8100_audio.h22
-rw-r--r--sound/soc/codecs/cg29xx.c778
-rw-r--r--sound/soc/codecs/cg29xx.h44
-rw-r--r--sound/soc/ux500/Kconfig46
-rw-r--r--sound/soc/ux500/Makefile20
-rw-r--r--sound/soc/ux500/ux500_ab3550.c207
-rw-r--r--sound/soc/ux500/ux500_av8100.c164
-rw-r--r--sound/soc/ux500/ux500_cg29xx.c177
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c961
-rw-r--r--sound/soc/ux500/ux500_msp_dai.h56
-rw-r--r--sound/soc/ux500/ux500_pcm.c376
-rw-r--r--sound/soc/ux500/ux500_pcm.h43
-rw-r--r--sound/u8500_acodec_ab8500.c2522
-rw-r--r--tools/svpboot/Makefile21
-rw-r--r--tools/svpboot/README18
-rw-r--r--tools/svpboot/svp5500.S36
-rw-r--r--tools/svpboot/svp8500v1.S36
-rw-r--r--tools/svpboot/svp8500v2.S36
-rw-r--r--tools/svpboot/svpboot.S66
-rw-r--r--tools/svpboot/svpboot.ld11
636 files changed, 221048 insertions, 3603 deletions
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index c7e5dc7e8cb..0711a9874fe 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -14,7 +14,12 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
mac80211.xml debugobjects.xml sh.xml regulator.xml \
alsa-driver-api.xml writing-an-alsa-driver.xml \
- tracepoint.xml media.xml drm.xml
+ tracepoint.xml media.xml drm.xml \
+ u8500_usb.xml \
+ ske_keypad.xml ste_ff_vibra.xml \
+ dma.xml gpio.xml i2s.xml i2c.xml mmc.xml \
+ prcmu-fw-api.xml msp.xml \
+ touchp.xml tc_keypad.xml stmpe.xml shrm.xml
###
# The build process is as follows (targets):
diff --git a/Documentation/DocBook/cg2900.tmpl b/Documentation/DocBook/cg2900.tmpl
new file mode 100644
index 00000000000..547a6e34450
--- /dev/null
+++ b/Documentation/DocBook/cg2900.tmpl
@@ -0,0 +1,1379 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="STE-Connectivity-template">
+ <bookinfo>
+ <title>CG2900 Driver</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Henrik</firstname>
+ <surname>Possung</surname>
+ <affiliation>
+ <address>
+ <email>henrik.possung@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Par-Gunnar</firstname>
+ <surname>Hjalmdahl</surname>
+ <affiliation>
+ <address>
+ <email>par-gunnar.p.hjalmdahl@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2010</year>
+ <holder>ST-Ericsson SA</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Connectivity</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <!-- Do NOT remove the legal notice below -->
+
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+ <toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <para>
+ This documentation describes the functions provided by the ST-Ericsson Connectivity Driver for enabling
+ ST-Ericsson Connectivity Combo Controller Hardware.
+
+ </para>
+ </chapter>
+
+ <chapter id="gettingstarted">
+ <title>Getting Started</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <para>
+ There are no special compilation flags needed to build the STE connectivity driver.
+ </para>
+ <para>
+ There must be firmware and settings files that match the used chip version inside the firmware folder.
+ The files:
+ <itemizedlist>
+ <listitem><para>cg2900_patch_info.fw.org</para></listitem>
+ <listitem><para>cg2900_settings_info.fw.org</para></listitem>
+ </itemizedlist>
+ handle the mapping between chip version and correct firmware file (patch resp static settings file).
+ The necessary patch and settings files should be placed with the extension <constant>.fw.org.</constant>.
+ Note that there is a limitation in the Kernel firmware system regarding name length of a file.
+ </para>
+ <para>
+ The files:
+ <itemizedlist>
+ <listitem><para>cg2900_devices.c</para></listitem>
+ <listitem><para>include/mach/cg2900_devices.h</para></listitem>
+ </itemizedlist>
+ must exist inside the corresponding Board configuration folder.
+ </para>
+
+ <!-- TODO: If the driver needs preparations to be used
+ (special compilation flags, files in the file system,
+ knowledge about a specific domain etc), specify it here.
+ Remove this chapter completely if there is nothing
+ to mention and there is no tutorial needed.
+ Do NOT change the chapter id or title! -->
+ <!-- TODO: This guideline for this chapter may be extended
+ during the user-guide guidelines drop. -->
+
+ <section id="basic-tutorial">
+ <title>Basic Tutorial</title>
+ <para>
+ To enable the ST-Ericsson connectivity driver using KConfig go to <constant>Device Drivers -> Multifunction Device Drivers</constant>
+ and enable the STE Connectivity Driver. If BlueZ shall be used as Bluetooth stack also enable the STE HCI Connectivity driver.
+ Depending on choice the driver will either be included as LKM or built into the Kernel.
+ If building as LKM, 2 files will be generated:
+ <itemizedlist>
+ <listitem><para>cg2900.ko which contains the main driver</para></listitem>
+ <listitem><para>cg2900_hci.ko which contains the registration and mapping towards the BlueZ Bluetooth stack</para></listitem>
+ </itemizedlist>
+
+ <!-- TODO: Provide a basic tutorial, outlining how
+ to test the presence of the driver,
+ for example how to configure, compile and run the
+ example(s).
+ Several sections with different tutorials,
+ all located within the Getting Started
+ chapter may be provided. -->
+ </para>
+
+ <para>
+ <!-- TODO: This guideline for this section may be extended
+ during the user-guide guidelines drop. -->
+ </para>
+ </section>
+
+ </chapter>
+
+ <chapter id="concepts">
+ <title>Concepts</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <para>
+ The ST-Ericsson Connectivity driver works as a multiplexer between different users, such as a Bluetooth stack and a FM driver,
+ and the connectivity chip. The driver supports multiple physical transports, currently SPI and UART.
+ Apart from just transporting data between stacks and the chip, the ST-Ericsson Connectivity driver also deals with power handling,
+ powering up and down the chip and also downloading necessary patches and settings for the chip to start up properly.
+ <!-- TODO: A brief introduction about the concepts
+ which are introduced by the driver.
+ Remove this chapter completely if there are no
+ special concepts introduced by this driver.
+ Do NOT change the chapter id or title! -->
+ <!-- TODO: This guideline for this chapter may be extended
+ during the user-guide guidelines drop. -->
+ </para>
+ </chapter>
+
+ <chapter id="tasks">
+ <title>Tasks</title>
+ <!-- Do NOT change the chapter id or title! -->
+
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>Opening a channel</term>
+ <listitem>
+ <para>
+ In order to be able to send and receive data on an H:4 channel, the user (i.e. respective stack) must open the channel.
+ Opening a channel will make it possible to send data to and receive data from the connectivity controller.
+ If the controller were earlier powered down, opening a channel will also cause the controller to be powered up.
+ When chip is powered up, patches and settings for the ARM subsystem will be downloaded as well.
+ Other IPs within the controller must however download each respective patches and settings.
+ If chip was already powered up when opening the channel no patch will be automatically downloaded.
+
+ <variablelist>
+ <varlistentry>
+ <term>Opening a channel from Kernel space</term>
+ <listitem>
+ <para>
+ When a stack is placed in Kernel space, it shall open a channel by calling the API function <function>cg2900_register_user</function>.
+ This function will search for the supplied channel by using name look-up and open the channel.
+ The function will return with a device reference that shall be used when calling the other CG2900 API functions.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <variablelist>
+ <varlistentry>
+ <term>Opening a channel from User space</term>
+ <listitem>
+ <para>
+ When a stack is placed in User space, it shall open a channel by calling the syscall function <function>open</function> on the corresponding file.
+ The files are located in folder <filename>/dev/</filename> and are named <filename>cg2900_gnss</filename> and similar. Each file
+ corresponds to one H:4 channel.
+ This function will open the channel.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Closing a channel</term>
+ <listitem>
+ <para>
+ When a user, i.e. a stack has no need for a functionality, it should close the corresponding H:4 channel.
+ This is usually done when a user disables a certain feature, for example Bluetooth. The reason why the channels
+ need to be closed is that the ST-E connectivity driver will free the resources and also shutdown the controller if there are
+ no more active users of the chip. This will lower the power consumption thereby increasing battery life.
+
+ <variablelist>
+ <varlistentry>
+ <term>Closing a channel from Kernel space</term>
+ <listitem>
+ <para>
+ When a stack is placed in Kernel space, it shall close a channel by calling the API function
+ <function>cg2900_deregister_user</function>.
+ This function will close the channel and also free the allocated device that was allocated when registering.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <variablelist>
+ <varlistentry>
+ <term>Closing a channel from User space</term>
+ <listitem>
+ <para>
+ When a stack is placed in User space, it shall close a channel by calling the syscall function
+ <function>close</function> on the corresponding file.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Writing to a channel</term>
+ <listitem>
+ <para>
+ When a stack (Bluetooth, FM, or GNSS) wants to send a packet it shall perform a write operation.
+ The packet shall not contain the H:4 header since this is added by the ST-E connectivity driver.
+ All other data in the packet shall however exist in the packet in the format correct for that HCI channel.
+ The ST-E connectivity users need to perform flow control over channels so any ticket handling
+ or similar must be handled by respective stack.
+
+ <variablelist>
+ <varlistentry>
+ <term>Writing to a channel from Kernel space</term>
+ <listitem>
+ <para>
+ When a stack is placed in Kernel space, it shall start with allocating a packet of the correct size using
+ <function>cg2900_alloc_skb</function>. This function will return an sk_buff (Socket buffer) structure that
+ has necessary space reserved for ST-E driver operation.
+ The stack shall then copy the data, preferrably using <function>skb_put</function>, and then call
+ <function>cg2900_write</function> to perform the write operation. When the function returns, the buffer has
+ been transferred and there is no need for the calling function to free the buffer. If the operation fails, i.e.
+ an error code is returned, the caller must however free the buffer.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <variablelist>
+ <varlistentry>
+ <term>Writing to a channel from User space</term>
+ <listitem>
+ <para>
+ When a stack is placed in User space, it shall call the <function>write</function> function on
+ the corresponding file to perform a transmit operation. After function returns the data has been
+ copied and is considered sent.
+ The caller does not need to preserve the data.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <variablelist>
+ <varlistentry>
+ <term>Writing to FM_Radio and FM_Audio channel</term>
+ <listitem>
+ <para>
+ CG2900 driver only supports FM legacy commands. The reason is that the FM_Radio and FM_Audio uses the same H4 channel aginst the chip,
+ in order to multiplex the FM user commands the data pakets are parsed by the CG2900 driver.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Reading from a channel</term>
+ <listitem>
+ <para>
+ When a stack (Bluetooth, FM, or GNSS) wants to receive a packet it shall perform a receive operation.
+ The packet returned does not contain the H:4 header since this is removed by the ST-E connectivity driver.
+ All other data in the packet in the packet is in the format correct for that HCI channel.
+ The ST-E connectivity driver does not perform any flow control over the H:4 channel so any ticket handling
+ or similar must be handled by respective stack.
+
+ <variablelist>
+ <varlistentry>
+ <term>Reading from a channel from Kernel space</term>
+ <listitem>
+ <para>
+ When a stack is placed in Kernel space, it has to supply a callback function for the receive functionality when calling
+ <function>cg2900_register_user</function>. This callback function will be called when the ST-E connectivity driver has
+ received a packet. The packet received will always be a complete HCI packet, i.e. no fragmention on HCI layer.
+ When the packet has been received it is the responsability of the receiver to see to that the packet is freed using
+ <function>kfree_skb</function> when it is no more needed.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <variablelist>
+ <varlistentry>
+ <term>Reading from a channel from User space</term>
+ <listitem>
+ <para>
+ When a stack is placed in User space, it shall call the <function>read</function> function on
+ the corresponding file to perform a receive operation. This function will read as many bytes as there are present
+ up to the size of the supplied buffer. If no data is available the function will hang until data becomes available, reset
+ occurs, or the channel is closed.
+ For smooth operation it is recommended to use the <function>poll</function> functionality on the file, preferrably
+ from a dedicated thread. This way one thread can monitor both read and reset operations in one common thread while transmit
+ operations may continue unblocked in a separate thread.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Reset handling</term>
+ <listitem>
+ <para>
+ The stacks shall always try to avoid performing Reset operations. The Reset will result in a hardware reset of the controller
+ and will therefore cause all existing links and settings to be lost. All stacks using the controller must also be informed
+ about the reset and handle it in a proper way.
+ The reset operation should only be used when there is no other option to get the controller into a working state, for example
+ if the controller has stopped answering to commands.
+ After the hardware reset, the ST-E connectivity driver will automatically perform deregister the channel so it has to be reopened again.
+
+ <variablelist>
+ <varlistentry>
+ <term>Reset handling from Kernel space</term>
+ <listitem>
+ <para>
+ When a stack is placed in Kernel space, it initiates a Reset operation by calling <function>cg2900_reset</function>.
+ This will trigger a hardware reset of the controller. When the hardware reset is finished all registered users will be called
+ through respective reset callback. When the callback function is finished the registered device will be removed and when all
+ registered users have been informed and removed, the chip is shutdown. This is similar to a deregistration of all registered
+ channels. The stack will then have to reregister to the ST-E connectivity driver in order to use the channel once again.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <variablelist>
+ <varlistentry>
+ <term>Reset handling from User space</term>
+ <listitem>
+ <para>
+ When a stack is placed in User space, it shall call the <function>ioctl</function> function on
+ the corresponding file to perform a reset operation. The command parameter <constant>CG2900_CHAR_DEV_IOCTL_RESET</constant>
+ shall be used when calling <function>ioctl</function>.
+ When the <function>ioctl</function> returns, the stack shall close the channel and then re-open it again. This must be done so
+ the channel is registered correctly in Kernel space.
+ For smooth operation it is recommended to use the <function>poll</function> functionality on the file, preferrably
+ from a dedicated thread. This way one thread can monitor both read and reset operations in one common thread while transmit
+ operations may continue unblocked in a separate thread.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Example code Kernel space</term>
+ <listitem>
+ <para>
+ This example will register to the FM channel, write a packet, read a packet and then deregister.
+
+ <programlisting>
+ struct cg2900_device *my_dev;
+ bool event_received;
+
+ void read_cb(struct cg2900_device *dev, struct sk_buff *skb)
+ {
+ event_received = true;
+ kfree_skb(skb);
+ }
+
+ void reset_cb(struct cg2900_device *dev)
+ {
+ /* Handle reset. Device will be automatically freed by the ST-E driver */
+ my_dev = NULL;
+ }
+
+ static struct cg2900_callbacks my_cb = {
+ .read_cb = read_cb,
+ .reset_cb = reset_cb
+ };
+
+ void example_open(void)
+ {
+ my_dev = cg2900_register_user(CG2900_FM_RADIO, &amp;my_cb);
+ if (!my_dev) {
+ printk("Error! Couldn't register!\n");
+ }
+ }
+
+ void example_close(void)
+ {
+ cg2900_deregister_user(my_dev);
+ my_dev = NULL;
+ }
+
+ void example_write_and_read(uint8_t *data, int len)
+ {
+ int err;
+ struct sk_buff *skb = cg2900_alloc_skb(len, GFP_KERNEL);
+
+ if (skb) {
+ memcpy(skb_put(skb, len), data, len);
+ err = cg2900_write(my_dev, skb);
+ if (!err) {
+ event_received = false;
+
+ while (!event_received) {
+ /* Wait for ack event. Received in read_cb() above */
+ schedule_timeout_interruptible(jiffies + 50);
+ }
+ } else {
+ printk("Couldn't write to controller (%d)\n", err);
+ kfree_skb(skb);
+ }
+ }
+ }
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Example code User space</term>
+ <listitem>
+ <para>
+ This example will open the GNSS channel, write a packet, read a packet and then close the channel.
+ In this example all functions are performed in the same thread.
+ It is however adviced to perform <function>read</function> and <function>ioctl</function> read through a separate thread,
+ preferrably using <function>poll</function>.
+
+ <programlisting>
+ struct my_info_t {
+ int fd;
+ };
+
+ static struct my_info_t my_info;
+
+ /* This is a fake command and has nothing to do with real GNSS commands.
+ * Note that the command does NOT contain the H:4 header.
+ * The header is added by the ST-E Connectivity driver.
+ */
+ static const uint8_t tx_cmd[] = {0x12, 0x34, 0x56};
+
+ int main(int argc, char **argv)
+ {
+ uint8_t rx_buffer[100];
+ int rx_bytes = 0;
+ int err;
+
+ my_info.fd = open("/dev/cg2900_gnss", O_RDWR);
+ if (my_info.fd &lt; 0) {
+ printf("Error on open file: %d (%s)\n", errno, strerror(errno));
+ return errno;
+ }
+ if (0 &gt; write(my_info.fd, tx_cmd, sizeof(tx_cmd))) {
+ printf("Error on write file: %d (%s)\n", errno, strerror(errno));
+ return errno;
+ }
+ /* Read will sleep until there is data available */
+ rx_bytes = read(my_info.fd, rx_buffer, 100);
+ if (rx_bytes &gt;= 0) {
+ printf("Received %d bytes\n", rx_bytes);
+ } else {
+ printf("Error on read file: %d (%s)\n", errno, strerror(errno));
+ return errno;
+ }
+ err = close(my_info.fd);
+ if (err) {
+ printf("Error on close file: %d (%s)\n", errno, strerror(errno));
+ return errno;
+ }
+ return 0;
+ }
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <!-- TODO: Task descriptions are step by step instructions
+ for performing specific actions and tasks.
+ Each task is typically one scenario.
+ Each task is described in a separate (section).
+ (section) tags can be nested, which is
+ especially recommended if
+ the task consists of several scenarios.
+ Remove this chapter completely if there are no
+ tasks to mention and there is no tutorial needed.
+ Do NOT change the chapter id or title! -->
+ <!-- TODO: This guideline for this chapter may be extended
+ during the user-guide guidelines drop. -->
+ </para>
+ </chapter>
+
+ <chapter id="driver-configuration">
+ <title>Driver Configuration and Interaction</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <para>
+ For debug purposes the define CG2900_DEBUG_LEVEL in the file cg2900_debug.h can be changed to set how much debug printouts
+ that shall be generated.
+ <itemizedlist>
+ <listitem><para>0 - No debug</para></listitem>
+ <listitem><para>1 - Error printouts</para></listitem>
+ <listitem><para>10 - Info printouts such as start of each function</para></listitem>
+ <listitem><para>20 - Debug printouts such as descriptions of operations</para></listitem>
+ <listitem><para>25 - Data printouts without content</para></listitem>
+ <listitem><para>30 - Data printouts with content</para></listitem>
+ </itemizedlist>
+ <!-- TODO: Use this paragraph as an introduction to driver
+ configuration and interaction. Describe the big picture. -->
+ <!-- TODO: This chapter contains driver specific way to perform
+ configuration and interaction. The chapter includes a
+ number of sections. They should not be removed and if
+ the driver does not have the specific support for
+ configuration or interaction should the text "not
+ applicable" be inserted. Do NOT change the chapter id
+ or title! -->
+ <!-- TODO: This guideline for this chapter may be extended
+ during the user-guide guidelines drop. -->
+ </para>
+
+ <section id="driver-implemented-operations">
+ <title>Implemented operations in driver</title>
+ <para>
+ <!-- TODO: Describe the actual usage of the driver. Specify the actual
+ implemented operations in struct <structname>file_operations</structname>
+ and any other set of operations. Create a table with two columns
+ (see example in intro chapter how to create a table).
+ Column one list all operations supported (read,
+ write, open, close, ioctl etc) and column two a description of the
+ semantics of the operations in the specific context of the device
+ driver from the users perspective. Document the operations in a way
+ that a user of the driver can be helped. -->
+ </para>
+ <para>
+ <table>
+ <title> Supported device driver operations when using character device </title>
+ <tgroup cols="2"><tbody>
+ <row><entry> open </entry> <entry> Opening a character device will register the caller to that HCI channel.</entry> </row>
+ <row><entry> release </entry> <entry> Releasing a character device will deregister the caller from that HCI channel</entry> </row>
+ <row><entry> poll </entry> <entry> Polling a character device will check if there is data to read on that HCI channel</entry> </row>
+ <row><entry> read </entry> <entry> Reading from a character device reads from that HCI channel</entry> </row>
+ <row><entry> write </entry> <entry> Writing to a character device writes to that HCI channel</entry> </row>
+ <row><entry> unlocked_ioctl </entry> <entry> Performing IO control on a character device will perform special operations such as reset on that HCI channel</entry> </row>
+ </tbody></tgroup>
+ </table>
+ </para>
+ </section>
+
+ <section id="driver-loading">
+ <title>Driver loading parameters</title>
+ <para>
+ <!-- TODO: Describe parameters that can be specified at kernel
+ driver loading with insmod or modprobe. If the driver
+ has no parameters to be specified at load time, replace this
+ text with "Not Applicable". -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>uart_default_baud</term>
+ <listitem>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>Parameter type</term>
+ <listitem><synopsis><type>int</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Default value</term>
+ <listitem><para>115200</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Runtime readable/modifiable</term>
+ <listitem><para>Readable</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The parameter uart_default_baud in cg2900_uart.c defines the baud rate used after a chip has just been powered up.
+ It shall be set to the default baud rate of the controller.
+ For ST-Ericsson controllers STLC2690 and CG2900 this value shall be 115200.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>uart_high_baud</term>
+ <listitem>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>Parameter type</term>
+ <listitem><synopsis><type>int</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Default value</term>
+ <listitem><para>3000000</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Runtime readable/modifiable</term>
+ <listitem><para>Modifiable</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The parameter uart_high_baud in cg2900_uart.c defines the baud rate to use for normal data transfer.
+ This should normally be the highest allowed by the system with regards to flow control, clocks, etc.
+ For ST-Ericsson controllers STLC2690 and CG2900 the following values are supported:
+ <itemizedlist>
+ <listitem><para>57600</para></listitem>
+ <listitem><para>115200</para></listitem>
+ <listitem><para>230400</para></listitem>
+ <listitem><para>460800</para></listitem>
+ <listitem><para>921600</para></listitem>
+ <listitem><para>2000000</para></listitem>
+ <listitem><para>3000000</para></listitem>
+ <listitem><para>4000000</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>bd_address</term>
+ <listitem>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>Parameter type</term>
+ <listitem><synopsis><type>array (Entered as comma separated value)</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Default value</term>
+ <listitem><para>0x00 0x80 0xDE 0xAD 0xBE 0xEF</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Runtime readable/modifiable</term>
+ <listitem><para>Modifiable</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The parameter bd_address in cg2900_core.c defines the Bluetooth device address to use for the current device.
+ The value is an array of 6 bytes and shall be entered as a comma separated value.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>debug_level</term>
+ <listitem>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>Parameter type</term>
+ <listitem><synopsis><type>int</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Default value</term>
+ <listitem><para>1</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Runtime readable/modifiable</term>
+ <listitem><para>Modifiable</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The parameter debug_level in cg2900_core.c defines the debug level that is currently used.
+ The higher the debug level the more print-outs are received in the terminal window.
+ The following values are supported:
+ <itemizedlist>
+ <listitem><para>0 = No debug</para></listitem>
+ <listitem><para>1 = Error prints</para></listitem>
+ <listitem><para>10 = General info, e.g. function entries</para></listitem>
+ <listitem><para>20 = Debug info, e.g. steps in a functionality</para></listitem>
+ <listitem><para>25 = Data info, i.e. prints when data is transferred</para></listitem>
+ <listitem><para>30 = Data content, i.e. contents of the transferred data</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>sleep_timeout_ms</term>
+ <listitem>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>Parameter type</term>
+ <listitem><synopsis><type>int</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Default value</term>
+ <listitem><para>0</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Runtime readable/modifiable</term>
+ <listitem><para>Modifiable</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The parameter sleep_timeout_ms in cg2900_core.c defines the sleep timeout for data transmission in milliseconds.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ <!-- TODO: This guideline for this section may be extended
+ during the user-guide guidelines drop. -->
+ </para>
+ </section>
+
+ <section id="driver-ioctl">
+ <title>Driver IO Control</title>
+ <para>
+ <!-- TODO: Describe driver parameters that can be modified
+ in runtime. Make a list of all device-dependent request code with
+ description of arguments, meaning etc. If the driver has no IO control
+ interface, replace this text with "Not Applicable". -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><constant>CG2900_CHAR_DEV_IOCTL_RESET</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Set</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>void</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>CG2900_CHAR_DEV_IOCTL_RESET</constant> IOCTL starts a reset
+ of the connectivity chip. This will affect the current open channel and
+ all other open channels as well.
+ </para><para>
+ IOCTL value created using <constant>_IOW('U', 210, int)</constant>.
+ </para><para>
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If reset is performed without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>CG2900_CHAR_DEV_IOCTL_CHECK4RESET</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Query</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>void</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>CG2900_CHAR_DEV_IOCTL_CHECK4RESET</constant> IOCTL checks if a reset
+ has been performed on a device.
+ </para><para>
+ IOCTL value created using <constant>_IOR('U', 212, int)</constant>.
+ </para><para>
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If device is still open the IOCTL function will return 0.</para></listitem>
+ <listitem><para>If reset has occurred the IOCTL function will return 1.</para></listitem>
+ <listitem><para>If device has been closed the IOCTL function will return 2.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>CG2900_CHAR_DEV_IOCTL_GET_REVISION</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Query</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>void</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>CG2900_CHAR_DEV_IOCTL_GET_REVISION</constant> IOCTL returns the revision value
+ of the local connectivity controller if such information is available.
+ </para><para>
+ IOCTL value created using <constant>_IOR('U', 213, int)</constant>.
+ </para><para>
+ Returned values are according to information that may be retrieved from chip manufacturer.
+ It is however possible to get indications of the value by looking in the file
+ <constant>firmware/cg2900_patch_info.fw.org</constant>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>CG2900_CHAR_DEV_IOCTL_GET_SUB_VER</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Query</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>void</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>CG2900_CHAR_DEV_IOCTL_GET_SUB_VER</constant> IOCTL returns the sub-version value
+ of the local connectivity controller if such information is available.
+ </para><para>
+ IOCTL value created using <constant>_IOR('U', 214, int)</constant>.
+ </para><para>
+ Returned values are according to information that may be retrieved from chip manufacturer.
+ It is however possible to get indications of the value by looking in the file
+ <constant>firmware/cg2900_patch_info.fw.org</constant>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </section>
+
+ <section id="driver-sysfs">
+ <title>Driver Interaction with Sysfs</title>
+ <para>
+ <!-- TODO: Describe data available for read and write on the drivers
+ Sysfs entry. Specify where the entry for the device is located in
+ Sysfs such as <filename>/sys/devices/*</filename>, <filename>/sys/devices/*</filename>
+ , etc.
+ Specify the data types for the attributes. Specify if the
+ attributes are read-only or write-only. If the driver has no Sysfs
+ interface, replace this text with "Not Applicable". -->
+ Not Applicable
+ </para>
+ </section>
+
+ <section id="driver-proc">
+ <title>Driver Interaction using /proc filesystem</title>
+ <para>
+ Not Applicable
+ <!-- TODO: Describe data available for read and write on the drivers
+ /proc entry. Specify where the entry for the device is located.
+ Specify the data types for the attributes. Specify if the
+ attributes are read-only or writeonly. If the driver has no /proc
+ interface, replace this text with "Not Applicable". -->
+ </para>
+ </section>
+
+ <section id="driver-other">
+ <title>Other means for Driver Interaction</title>
+ <para>
+ <!-- TODO: Does the driver have any configurations files? Describe other means
+ for driver status access or configuration. If the driver has no other
+ means (besides the one in already described in this chapter), replace
+ this text with "Not Applicable". -->
+ Not Applicable
+ </para>
+ </section>
+
+ <section id="driver-node">
+ <title>Driver Node File</title>
+ <variablelist>
+ <varlistentry>
+ <term>CG2900 main device</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_driver0</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_driver represents the main parent node for all other character devices supplied in the ST-Ericsson connectivity driver except for the CCD Test device. It does not support any operations such as read or write.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>BT Command</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_bt_cmd</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_bt_cmd is the device for the HCI Bluetooth command channel.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>BT ACL</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_bt_acl</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_bt_acl is the device for the HCI Bluetooth ACL channel.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>BT Event</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_bt_evt</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_bt_evt is the device for the HCI Bluetooth event channel.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>FM Radio</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_fm_radio</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_fm_radio is the device for the HCI FM Radio channel.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>GNSS</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_gnss</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_gnss is the device for the HCI GNSS channel.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Debug</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_debug</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_debug is the device for the HCI Debug channel.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>ST-Ericsson Tools</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_ste_tools</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_ste_tools is the device for the HCI ST-Ericsson tools channel.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>HCI Logger</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_hci_logger</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_hci_logger is the device for the HCI logger channel.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>User Space Control</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_us_ctrl</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_us_ctrl is the device for initialization and control of the STE CONN driver.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>CCD Test stub</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_ccd_test</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_ccd_test is the device for performing module tests of the ST-Ericsson connectivity driver. It acts as a stub replacing the transport towards the chip. It is of the type Misc devices.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>BT Audio</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_bt_audio</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_bt_audio is the device for sending HCI BT Audio controll commands to the chip. </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>FM Audio</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_fm_audio</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_fm_audio is the device for sending HCI BT Audio controll commands to the chip.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Core</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_core</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The cg2900_core is a device for turn on/off the chip. NOTE other devices will also turn on/off the chip if needed.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>CG29XX Audio</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/cg2900_audio</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The cg2900_audio is a device for testing the CG2900 Audio driver from User space.
+ It replicates the normal CG2900 Audio interface through <constant>write/read</constant> operations.
+ The <constant>write</constant> command is used as following:
+ <itemizedlist>
+ <listitem><para>4 byte op code (see below)</para></listitem>
+ <listitem><para>Data field according to respective CG29XX Audio function (no session ID needed)</para></listitem>
+ </itemizedlist>
+ If the operation fails the <constant>write</constant> command operation will return the error.
+ Op codes are (4 bytes size):
+ <itemizedlist>
+ <listitem><para>0x00000001 = CHAR_DEV_OP_CODE_SET_DAI_CONF</para></listitem>
+ <listitem><para>0x00000002 = CHAR_DEV_OP_CODE_GET_DAI_CONF</para></listitem>
+ <listitem><para>0x00000003 = CHAR_DEV_OP_CODE_CONFIGURE_ENDPOINT</para></listitem>
+ <listitem><para>0x00000004 = CHAR_DEV_OP_CODE_CONNECT_AND_START_STREAM</para></listitem>
+ <listitem><para>0x00000005 = CHAR_DEV_OP_CODE_STOP_STREAM</para></listitem>
+ </itemizedlist>
+
+ The <constant>read</constant> command is used for the commands <constant>CHAR_DEV_OP_CODE_GET_DAI_CONF</constant>
+ and <constant>CHAR_DEV_OP_CODE_CONNECT_AND_START_STREAM</constant> if the corresponding commands are successful.
+ The returned data will be formatted accordingly:
+ <itemizedlist>
+ <listitem><para>4 byte op code (see below)</para></listitem>
+ <listitem><para>Data field according to normal CG29XX Audio functions, e.g. stream handle or configuration</para></listitem>
+ </itemizedlist>
+ The <constant>CHAR_DEV_OP_CODE_GET_DAI_CONF</constant> is a bit special since it require an endpoint in-parameter
+ (when calling <constant>write</constant>) to return the corresponding DAI configuration when calling <constant>read</constant>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </section>
+
+
+ </chapter>
+
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>Driver supports only one user per HCI channel.</term>
+ <listitem>
+ <para>
+ To simplify design and limitation as well as keeping the API simple and reliable, the driver only supports one user per HCI channel.
+ <!-- TODO: Briefly describe the limitation, unless all
+ information is already present in the title.
+ Use full english sentences.
+ Repeat the varlistentry for each limitation.
+ If none are known, replace this varlistentry
+ with the one below. -->
+ <!-- TODO: This guideline for this chapter may be extended
+ during the user-guide guidelines drop. -->
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+<chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ List of public functions.
+ </para>
+ <!-- Do NOT change the chapter id or title! -->
+ <!-- TODO: Replace with link to appropriate headerfile(s).
+ One per row, ensure the
+ exclamation mark is on the first column! If no
+ appropriate header file exist describing a public interface,
+ replace the inclusion with a paragraph containing the text
+ "Not Applicable" -->
+ <section id="cg2900.h">
+ <title>cg2900.h</title>
+!Einclude/linux/mfd/cg2900.h
+!Iinclude/linux/mfd/cg2900.h
+ </section>
+ <section id="cg2900_audio.h">
+ <title>cg2900_audio.h</title>
+!Einclude/linux/mfd/cg2900_audio.h
+!Iinclude/linux/mfd/cg2900_audio.h
+ </section>
+
+</chapter>
+
+<chapter id="internal-functions">
+ <title>Internal Functions Provided</title>
+ <para>
+ List of internal functions.
+ </para>
+ <!-- Do NOT change the chapter id or title! -->
+ <!-- TODO: Replace with link to appropriate headerfile(s),
+ source file(s), or both. One per row, ensure the
+ exclamation mark is on the first column! If no
+ appropriate header or source file exist describing a public interface,
+ replace the inclusion with a paragraph containing the text
+ "Not Applicable"-->
+ <section id="cg2900_core.h">
+ <title>cg2900_core.h</title>
+!Edrivers/mfd/cg2900/cg2900_core.h
+!Idrivers/mfd/cg2900/cg2900_core.h
+ </section>
+ <section id="cg2900_core.c">
+ <title>cg2900_core.c</title>
+!Idrivers/mfd/cg2900/cg2900_core.c
+ </section>
+ <section id="cg2900_uart.c">
+ <title>cg2900_uart.c</title>
+!Idrivers/mfd/cg2900/cg2900_uart.c
+ </section>
+ <section id="cg2900_chip.c">
+ <title>cg2900_chip.c</title>
+!Idrivers/mfd/cg2900/cg2900_chip.c
+ </section>
+ <section id="stlc2690_chip.c">
+ <title>stlc2690_chip.c</title>
+!Idrivers/mfd/cg2900/stlc2690_chip.c
+ </section>
+ <section id="cg2900_char_devices.h">
+ <title>cg2900_char_devices.h</title>
+!Idrivers/mfd/cg2900/cg2900_char_devices.h
+ </section>
+ <section id="cg2900_char_devices.c">
+ <title>cg2900_char_devices.c</title>
+!Idrivers/mfd/cg2900/cg2900_char_devices.c
+ </section>
+ <section id="cg2900_hci.c">
+ <title>cg2900_hci.c</title>
+!Idrivers/bluetooth/cg2900_hci.c
+ </section>
+ <section id="cg2900_audio.c">
+ <title>cg2900_audio.c</title>
+!Idrivers/mfd/cg2900/cg2900_audio.c
+ </section>
+ <section id="cg2900_devices.h">
+ <title>cg2900_devices.h</title>
+!Iarch/arm/mach-ux500/include/mach/cg2900_devices.h
+ </section>
+</chapter>
+</book>
diff --git a/Documentation/DocBook/cg2900_fm_radio.tmpl b/Documentation/DocBook/cg2900_fm_radio.tmpl
new file mode 100644
index 00000000000..4243656f203
--- /dev/null
+++ b/Documentation/DocBook/cg2900_fm_radio.tmpl
@@ -0,0 +1,1628 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="STE-CG2900-fm-driver-template">
+ <bookinfo>
+ <title>V4L FM Radio Driver for CG2900</title>
+ <authorgroup>
+ <author>
+ <firstname>Hemant</firstname>
+ <surname>Gupta</surname>
+ <affiliation>
+ <address>
+ <email>hemant.gupta@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+ <copyright>
+ <year>2010</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+ <subjectset>
+ <subject>
+ <subjectterm>Connectivity</subjectterm>
+ </subject>
+ </subjectset>
+ <legalnotice>
+ <!-- Do NOT remove the legal notice below -->
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+ <para>
+ 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.
+ </para>
+ <para>
+ 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
+ </para>
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+ <toc></toc>
+ <chapter id="intro">
+ <title>Introduction</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <para>
+ This documentation describes the functions provided by the CG2900 FM Driver.
+ </para>
+ </chapter>
+ <chapter id="gettingstarted">
+ <title>Getting Started</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <para>
+ There are no special compilation flags needed to build the CG2900
+ FM Driver.
+ </para>
+ <para>
+ There must be coeffecient and firmware files that match the used chip version inside the firmware folder.
+ The files:
+ <itemizedlist>
+ <listitem><para>cg2900_fm_bt_src_coeff_info.fw.org</para></listitem>
+ <listitem><para>cg2900_fm_ext_src_coeff_info.fw.org</para></listitem>
+ <listitem><para>cg2900_fm_fm_coeff_info.fw.org</para></listitem>
+ <listitem><para>cg2900_fm_fm_prog_info.fw.org</para></listitem>
+ </itemizedlist>
+ handle the mapping between chip version and correct firmware files (firmware and coeffecient files).
+ The necessary firmware and coeffecient files should be placed with the extension <constant>.fw.org</constant>.
+ Note that there is a limitation in the Kernel firmware system regarding name length of a file.
+ </para>
+ <section id="basic-tutorial">
+ <title>Basic Tutorial</title>
+ <para>
+ To enable the CG2900 FM Driver using KConfig go to <constant>Device Drivers -> Multimedia devices </constant>
+ and enable the following:
+ <itemizedlist>
+ <listitem><para>Video For Linux</para></listitem>
+ <listitem><para>Enable Video For Linux API 1 compatible Layer</para></listitem>
+ <listitem><para>Radio Adapters</para></listitem>
+ <listitem><para>Radio Adapter -> ST-Ericsson CG2900 FM Radio support</para></listitem>
+ </itemizedlist>
+ Select the driver as built in kernel object.
+ </para>
+ </section>
+ </chapter>
+ <chapter id="concepts">
+ <title>Concepts</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <para>
+ The CG2900 FM driver acts as an interface between Video4Linux and CG2900-Protocol Driver. It configures the FM chip in FM Rx or FM Tx mode. It also sends the unformatted RDS data to the application for decoding while in FM rx mode and sends the formatted RDS data to FM Chip while in Tx mode.
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>FM Driver Working</term>
+ <listitem>
+ <para>
+ In order to send and receive data on an H:4 channel, the FM Driver opens the channel by registering with the CG2900 Protocol driver. After this the FM driver encapsulates the user operation into specific HCI comamnds and sends that data to the CG2900 Connectivity Controller and waits till the response for the previous command is received. FM Driver in this way maintains the flow control.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+ <chapter id="Tasks">
+ <title>Tasks</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <section id="Switching-On-FM">
+ <title>Switch On FM</title>
+ <para>
+ FM specific tasks
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Switching On FM</term>
+ <listitem>
+ <para>
+ For switching on FM the character device /dev/radio0 should be opened from user space. This sets the FM Radio in Idle mode. For configuring the FM Radio in Rx or Tx mode the IOCTL's VIDIOC_S_TUNER and VIDIOC_S_MODULATOR respectively.
+ <programlisting>
+ int fd;
+ fd = open("/dev/radio0", O_RDONLY);
+ if(fd &lt; 0) {
+ printf("open:error!!!\n");
+ goto err;
+ }
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="Switching-Off-FM">
+ <title>Switch Off FM</title>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Switching Off FM</term>
+ <listitem>
+ <para>
+ For switching OFF FM the character device /dev/radio0 should be closed from user space.
+ <programlisting>
+ if(fd &gt;= 0)
+ close(fd);
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="Rx-Mode">
+ <title>Switching To FM Rx Mode</title>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Switching To FM Rx Mode</term>
+ <listitem>
+ <para>
+ For switching on FM Rx mode the IOCTL VIDIOC_S_TUNER should be called with appropriate parameters.
+ <programlisting>
+ memset(&amp;tuner, 0, sizeof(tuner));
+ tuner.index = 0;
+ tuner.rxsubchans |= V4L2_TUNER_SUB_STEREO;
+ if (ioctl(fd, VIDIOC_S_TUNER, &amp;tuner) &lt; 0) {
+ printf("VIDIOC_S_TUNER:error!!\n");
+ return;
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="Tx-Mode">
+ <title>Switching To FM Tx Mode</title>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Switching To FM Tx Mode</term>
+ <listitem>
+ <para>
+ For switching on FM Tx mode the IOCTL VIDIOC_S_MODULATOR should be
+ called with appropriate parameters.
+ <programlisting>
+ memset(&amp;modulator, 0, sizeof(modulator));
+ modulator.index = 0;
+ modulator.txsubchans |= V4L2_TUNER_SUB_STEREO;
+ if (ioctl(fd, VIDIOC_S_MODULATOR, &amp;modulator) &lt; 0) {
+ printf("VIDIOC_S_MODULATOR:error!!\n");
+ return;
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="FM-Standby">
+ <title>Standby</title>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Making the FM Radio go in Standby Mode</term>
+ <listitem>
+ <para>
+ For making the FM Radio go in Standby mode, the IOCTL VIDIOC_S_CTRL should be used. The id of the v4l2_control structure should be set to V4L2_CID_CG2900_RADIO_CHIP_STATE and the value of v4l2_control structure should be set as V4L2_CG2900_RADIO_STANDBY.
+ <programlisting>
+ struct v4l2_control sctrl;
+ int ret;
+ sctrl.id = V4L2_CID_CG2900_RADIO_CHIP_STATE;
+ sctrl.value = V4L2_CG2900_RADIO_STANDBY;
+ ret = ioctl(fd, VIDIOC_S_CTRL, &amp;sctrl);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_CTRL:error!!\n");
+ }
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="Powerup-from-standby">
+ <title>Powering Up FM From Standby Mode</title>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Powering Up FM Radio from Standby Mode</term>
+ <listitem>
+ <para>
+ For powering up FM radio again from standby mode, the IOCTL VIDIOC_S_CTRL should be used. The id of the v4l2_control structure should be set to V4L2_CID_CG2900_RADIO_CHIP_STATE and the value of v4l2_control structure should be set as V4L2_CG2900_RADIO_POWERUP.
+ <programlisting>
+ struct v4l2_control sctrl;
+ int ret;
+ sctrl.id = V4L2_CID_CG2900_RADIO_CHIP_STATE;
+ sctrl.value = V4L2_CG2900_RADIO_POWERUP;
+ ret = ioctl(fd, VIDIOC_S_CTRL, &amp;sctrl);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_CTRL:error!!\n");
+ }
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="tune-frequency">
+ <title>Tune Channel</title>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Tune to a particular station</term>
+ <listitem>
+ <para>
+ for tuning to a particular station, the IOCTL VIDIOC_S_FREQUENCY should be used. The frequency of the v4l2_frequency structure should be converted to V4L2 format.
+ <programlisting>
+ struct v4l2_frequency freq;
+ int ret;
+ /* Convert frequency in Hz to V4L2 Format */
+ freq.frequency = (frequency * 2)/ 125;
+ ret = ioctl(fd, VIDIOC_S_FREQUENCY, &amp;freq);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_FREQUENCY:error!!\n");
+ }
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="get-frequency">
+ <title>Get Tuned Channel</title>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Get the Currently tuned Station Frequncy</term>
+ <listitem>
+ <para>
+ for tuning to a particular station, the IOCTL VIDIOC_G_FREQUENCY should be used. The frequency returned in the v4l2_frequency structure would be in V4L2 format.
+ <programlisting>
+ struct v4l2_frequency freq;
+ int ret;
+ ret = ioctl(fd, VIDIOC_G_FREQUENCY, &amp;freq);
+ if (ret &lt; 0) {
+ printf("VIDIOC_G_FREQUENCY:error!!\n");
+ *frequency = 0;
+ return;
+ }
+ /* Convert frequency to Hz from V4L2 Format */
+ *frequency = (freq.frequency * 125)/2;
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="get-signal-strength">
+ <title>Retreive Signal Strength</title>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Retreive Signal Strength</term>
+ <listitem>
+ <para>
+ For retreiving the Signal strength of the currently tuned channel in FM Rx mode, IOCTL VIDIOC_G_TUNER should be called. The current signal strength would be represented by the parameter signal of the v4l2_tuner strucure.
+ <programlisting>
+ void get_signal_strength(int *rssi)
+ {
+ struct v4l2_tuner tuner;
+ int ret;
+ memset(&amp;tuner, 0, sizeof(tuner));
+ tuner.index = 0;
+ ret = ioctl(fd, VIDIOC_G_TUNER, &amp;tuner);
+ if (ret &lt; 0) {
+ printf("VIDIOC_G_TUNER:error!!\n");
+ *rssi = 0;
+ return;
+ }
+ *rssi = tuner.signal;
+ }
+ </programlisting>
+Note: Currently the retrieved signal strength is in decimals and not in "dBuV", proper external conversion required.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="band-scan">
+ <title>Band Scan</title>
+ <para>
+ <!-- Driver loading Parameters:Not Applicable -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Band Scan</term>
+ <listitem>
+ <para>
+ For doing a band scan, ie search for all available stations in the entire FM band, IOCTL VIDIOC_S_CTRL should be used with parameter id of the v4l2_control structure should be set to V4L2_CID_CG2900_RADIO_BANDSCAN and the value of v4l2_control structure should be set as V4L2_CG2900_RADIO_BANDSCAN_START. If the IOCTL returns successfully, a thread should be created to start polling to FM driver, to wait till scan is complete. When poll is complete, the found stations along with RSSI should be retrieved using the IOCTL VIDIOC_G_EXT_CTRLS should be used with parameters as described in example code.
+ <programlisting>
+ void Band_Scan()
+ {
+ struct v4l2_control sctrl
+ int ret;
+ sctrl.id = V4L2_CID_CG2900_RADIO_BANDSCAN;
+ sctrl.value = V4L2_CG2900_RADIO_BANDSCAN_START;
+ ret = ioctl(fd, VIDIOC_S_CTRL, &amp;sctrl);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_CTRL:error!!\n");
+ }
+ pthread_create(&amp;fmScanThread, NULL, FmScanThread, NULL);
+ }
+ static void *FmScanThread(void *param)
+ {
+ struct v4l2_ext_controls scanResult;
+ struct pollfd pollFd;
+ long * p = NULL;
+ int index, ret, count = 0;
+ int err;
+ pollFd.fd = fd;
+ pollFd.events = POLLRDNORM;
+ ret = poll(&amp;pollFd, 1, MAX_SCAN_SEEK_TIME);
+ if(ret)
+ {
+ if(pollFd.revents &amp; POLLRDNORM)
+ {
+ /* Get the Number OF Channels */
+ scanResult.count = 0;
+ scanResult.ctrl_class = V4L2_CTRL_CLASS_USER;
+ scanResult.controls = (struct v4l2_ext_control *) malloc(sizeof(struct v4l2_ext_control));
+ scanResult.controls->id = V4L2_CID_CG2900_RADIO_BANDSCAN_GET_RESULTS;
+ scanResult.controls->size = 0;
+ scanResult.controls->string = NULL;
+ err = ioctl(fd, VIDIOC_G_EXT_CTRLS, &amp; scanResult);
+ if (err &lt; 0 &amp; &amp; errno != ENOSPC) {
+ printf("VIDIOC_G_EXT_CTRLS:error!!\n");
+ goto err;
+ }
+ /* Allocate memory to receive the data from driver */
+ if(scanResult.controls->size &gt; 0 )
+ {
+ scanResult.controls->string = (long *)malloc(sizeof(long) * 2 * scanResult.controls->size );
+ p = scanResult.controls->string;
+ printf("\nNumber of Channels Found = %d \n", scanResult.controls->size);
+ /* Retrieve the Data now */
+ ret = ioctl(fd, VIDIOC_G_EXT_CTRLS, &amp;scanResult);
+ if (ret &lt; 0) {
+ printf("VIDIOC_G_EXT_CTRLS:error!!\n");
+ goto err;
+ }
+ for (index = 0, count = 0; index &lt; scanResult.controls->size; index ++, count +=2) {
+ printf("%d %d.%d %d\n", index + 1, MEGAHRTZ((*(p +count + 0) * 125) / 2), *(p + count + 1));
+ }
+ err:
+ free(p);
+ free(scanResult.controls);
+ }
+ else if( pollFd.revents &amp; POLLHUP)
+ {
+ printf("\nScan Cancelled By User!!\n");
+ }
+ free(scanResult.controls);
+ }
+ else if( ret == 0){
+ printf("\nError in Scanning, Timeout!!!\n");
+ }
+ return 0;
+ }
+ </programlisting>
+ Note: Currently the retrieved signal strength is in decimals and not in "dBuV", proper external conversion required.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="block-scan">
+ <title>Block Scan</title>
+ <para>
+ <!-- Driver loading Parameters:Not Applicable -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Block Scan</term>
+ <listitem>
+ <para>
+ The Block Scan functionality will take two inputs, start and stop frequency (V4L2 compliance) and enables the host to scan all channels with in that range for RSSI values. The measured channels will be stored in a list in order of channel number and the block scan feature to identify "empty" channels for transmission. And for doing a block scan, IOCTL VIDIOC_S_EXT_CTRL with parameter id of the v4l2_control structure should be set to V4L2_CID_FM_RADIO_BLOCKSCAN_START. If the IOCTL returns successfully, a thread should be created to start polling to FM driver, to wait till scan is complete. When poll is complete, the found stations along with RSSI should be retrieved using the IOCTL VIDIOC_G_EXT_CTRLS should be used with parameters as described in example code.
+ <programlisting>
+ void Block_Scan()
+ {
+ struct v4l2_ext_controls ext_ctrl;
+ long *p = NULL;
+ int index;
+ int ret_val;
+ if(1 == mode) {
+ otherOperationInProgress = 1;
+ ext_ctrl.ctrl_class = V4L2_CTRL_CLASS_USER;
+ ext_ctrl.controls = (struct v4l2_ext_control *) malloc(sizeof(struct v4l2_ext_control));
+ ext_ctrl.count = 0;
+ ext_ctrl.controls->id = V4L2_CID_CG2900_RADIO_BLOCKSCAN_START;
+ ext_ctrl.controls->size = 2;
+ ext_ctrl.controls->string = (long *)malloc(sizeof(long) * ext_ctrl.controls->size);
+ p = ext_ctrl.controls->string;
+ *p = (StartFreq * 2)/ 125;
+ *(p + 1) = (EndFreq * 2)/ 125;;
+ if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &amp;ext_ctrl) &lt; 0)
+ printf("APP_BlockScanStart:VIDIOC_S_EXT_CTRLS:error!!\n");
+ free(ext_ctrl.controls->string);
+ free(ext_ctrl.controls);
+ pthread_create(&amp;fmBlockScanThread, NULL, FmBlockScanThread, NULL);
+ }
+ static void *FmBlockScanThread(void *param)
+ {
+ struct v4l2_ext_controls blockscanResult;
+ struct pollfd pollFd;
+ long * p = NULL;
+ int index, ret;
+ int err;
+ int current_grid = -1;
+ FILE *fp;
+ long start_freq = StartFreq;
+ long next_freq_offset = 0;
+ fp = fopen("/sys/module/radio_cg2900/parameters/grid", "r");
+ if(fp != NULL)
+ {
+ /*
+ * Retrieve the currently set grid to determine the next channel is
+ * 50 Khz, 100 Khz or 200 Khz apart
+ */
+ fscanf(fp, "%d", &amp;current_grid);
+ fclose(fp);
+ }
+ if(current_grid == 0) {
+ next_freq_offset = 50000;
+ } else if (current_grid == 1) {
+ next_freq_offset = 100000;
+ } else if (current_grid == 2) {
+ next_freq_offset = 200000;
+ }
+ pollFd.fd = fd;
+ pollFd.events = POLLRDNORM;
+ ret = poll(&amp;pollFd, 1, MAX_SCAN_SEEK_TIME);
+ if(ret) {
+ if(pollFd.revents &amp; POLLRDNORM)
+ {
+ /* Get the Number Of Channels */
+ blockscanResult.count = 0;
+ blockscanResult.ctrl_class = V4L2_CTRL_CLASS_USER;
+ blockscanResult.controls = (struct v4l2_ext_control *) malloc(sizeof(struct v4l2_ext_control));
+ blockscanResult.controls->id = V4L2_CID_CG2900_RADIO_BLOCKSCAN_GET_RESULTS;
+ blockscanResult.controls->size = 0;
+ blockscanResult.controls->string = NULL;
+ err = ioctl(fd, VIDIOC_G_EXT_CTRLS, &amp;blockscanResult);
+ if (err &lt; 0 &amp;&amp; errno != ENOSPC) {
+ printf("VIDIOC_G_EXT_CTRLS:error!!\n");
+ goto err;
+ }
+ if(blockscanResult.controls->size > 0 )
+ {
+ blockscanResult.controls->string = (long *)malloc(sizeof(long) * blockscanResult.controls->size );
+ p = blockscanResult.controls->string;
+ if (ioctl(fd, VIDIOC_G_EXT_CTRLS, &amp;blockscanResult) &lt; 0) {
+ printf("VIDIOC_G_EXT_CTRLS:error!!\n");
+ goto err;
+ }
+ printf("\nSNo. RSSI\n");
+ for (index = 0; index &lt; blockscanResult.controls->size; index ++) {
+ printf("%d.%d %d\n", MEGAHRTZ(start_freq), *(p + index));
+ start_freq += next_freq_offset;
+ }
+ err:
+ free(p);
+ }
+ else if(blockscanResult.controls->size == 0)
+ {
+ printf("\nNo channels found during Block Scan!!\n");
+ }
+ free(blockscanResult.controls);
+ }
+ else if( pollFd.revents &amp; POLLHUP)
+ {
+ printf("\nBlock Scan Cancelled By User!!\n");
+ }
+ }
+ else if(ret == 0) {
+ printf("\nError in Block Scan, Timeout!!!\n");
+ }
+ otherOperationInProgress = 0;
+ return 0;
+ }
+
+ </programlisting>
+ Note: Currently the retrieved signal strength is in decimals and not in "dBuV", proper external conversion required.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="cancel-scan-seek">
+ <title>Cancel Scan</title>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Cancel Scan/Seek</term>
+ <listitem>
+ <para>
+ This is used for stopping an active Band Scan, Seek operation and Block Scan. IOCTL VIDIOC_S_CTRL should be used with parameter id of the v4l2_control structure. For Eg incase of Band scan the parameter id should be set to V4L2_CID_CG2900_RADIO_BANDSCAN and the value of v4l2_control structure should be set as V4L2_CG2900_RADIO_BANDSCAN_STOP.
+ <programlisting>
+ struct v4l2_control sctrl;
+ int ret;
+ sctrl.id = V4L2_CID_CG2900_RADIO_BANDSCAN;
+ sctrl.value = V4L2_CG2900_RADIO_BANDSCAN_STOP;
+ ret = ioctl(fd, VIDIOC_S_CTRL, &amp;sctrl);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_CTRL:error!!\n");
+ }
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="rds-receive">
+ <title>RDS Receive</title>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>RDS Receive</term>
+ <listitem>
+ <para>
+ For enabling/disabling RDS for FM Rx, IOCTL VIDIOC_S_TUNER should be used with parameter rxsubchans of the v4l2_tuner structure set to V4L2_TUNER_SUB_RDS if rds needs to be enabled and the same value must not be set in case rds is to be disabled. A thread should be created and read() should be called to receive RDS data from driver. The RDS data received from FM Driver should be parsed in user space to retrive RDS information i.e Radio Text, Program Service Name, Program Identification, Program Type, Alternate Frequency, etc.
+ <programlisting>
+ void rds_rx_set(bool enable_rds)
+ {
+ struct v4l2_tuner tuner;
+ int ret;
+ memset(&amp;tuner, 0, sizeof(tuner));
+ tuner.index = 0;
+ if(enable_rds)
+ tuner.rxsubchans |= V4L2_TUNER_SUB_RDS;
+ else
+ tuner.rxsubchans &amp; = ~V4L2_TUNER_SUB_RDS;
+ ret = ioctl(fd, VIDIOC_S_TUNER, &amp;tuner);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_TUNER:error!!\n");
+ }
+ }
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="af-update_switch">
+ <title>AF Update and Switching</title>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>AF Update &amp; Switching</term>
+ <listitem>
+ <para>Alternate Frequency (AF) Handling needs to be done in user space.</para>
+ <para>The application should use the AF RDS group data to compose a list of AFs when tuned to a new channel.</para>
+ <para>When the reception of the currently tuned frequency falls below a set threshold, it can decide to switch to one of the alternative frequencies for this channel.
+ </para>
+ <para>The application can perform an AF Update, which returns the RSSI value for all or some of the channel's AFs. Thus allowing the hardware to switch to the AF with the highest RSSI. The AF Update could be designed to stop as soon as it finds an AF with an acceptable RSSI level. In the event that all the AF RSSI values are lower than the base channel, the AF Switch would not be necessary.
+ </para>
+ <para>To know the RSSI of the alternative frequencies (V4L2 compliance), the application can use the IOCTL VIDIOC_S_CTRL with parameter id set to V4L2_CID_CG2900_RADIO_RDS_AF_UPDATE_START, and the parameter value be set as the frequency in Hz for a channel from the AF List. If this call returns successfully, the RSSI of the frequency can then be retrieved. Using IOCTL VIDIOC_G_CTRL, with the parameter id set to V4L2_CID_CG2900_RADIO_RDS_AF_UPDATE_GET_RESULT, and the output parameter value will contain the RSSI of the AF frequency.
+ </para>
+ <para>If it is still deemed necessary to switch channels, the next step is then to switch to an alternative frequency in the AF list. This can be done using the IOCTL VIDIOC_S_EXT_CTRLS, with:
+ </para>
+ <itemizedlist>
+ <listitem><para>Parameter id set to V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_START</para></listitem>
+ <listitem><para>Parameter size set to 2</para></listitem>
+ <listitem><para>Parameters filled as below (string field of the parameter) </para></listitem>
+ <listitem><para>Control class parameter set to V4L2_CTRL_CLASS_USER</para></listitem>
+ <listitem><para>The AF switch frequency in Hz</para></listitem>
+ <listitem><para>Expected PI code </para></listitem>
+ </itemizedlist>
+ <para>The application can check if the AF switch succeeded or not using the IOCTL VIDIOC_G_CTRL, with parameter id set to V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_GET_RESULT, and the output parameter value will contain the AF switch conclusion.
+ </para>
+ <para> The example code below illustrates both the aforementioned functionalities.</para>
+ <para>
+ <programlisting>
+ void PerformAFUpdate(long AF_Frequency, int *AF_Rssi)
+ {
+ struct v4l2_control sctrl, gctrl;
+ int ret;
+ sctrl.id = V4L2_CID_CG2900_RADIO_RDS_AF_UPDATE_START;
+ sctrl.value = AF_Frequency;
+ ret = ioctl(fd, VIDIOC_S_CTRL, &amp; sctrl);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_CTRL:error!!\n");
+ }
+ gctrl.id = V4L2_CID_CG2900_RADIO_RDS_AF_UPDATE_GET_RESULT;
+ ret = ioctl(fd, VIDIOC_G_CTRL, &amp; gctrl);
+ if (ret &lt; 0) {
+ printf("VIDIOC_G_CTRL:error!!\n");
+ }
+ *AF_Rssi = gctrl.value;
+ }
+ void PerformAFSwitch(long AF_BestFrequency, int AF_ExpectedPI, int *AF_SwitchConclusion)
+ {
+ struct v4l2_control gctrl;
+ struct v4l2_ext_controls ext_ctrl;
+ int ret;
+ int conclusion;
+ long freq;
+ long *p = NULL;
+ ext_ctrl.ctrl_class = V4L2_CTRL_CLASS_USER;
+ ext_ctrl.controls = (struct v4l2_ext_control *) malloc(sizeof(struct v4l2_ext_control));
+ ext_ctrl.count = 0;
+ ext_ctrl.controls->id = V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_START;
+ ext_ctrl.controls->size = 2;
+ ext_ctrl.controls->string = (long *)malloc(sizeof(long) * ext_ctrl.controls->size);
+ p = ext_ctrl.controls->string;
+ *p = (AF_BestFrequency * 2)/ 125;
+ *(p+1) = (long)AF_ExpectedPI;
+ ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &amp; ext_ctrl);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_EXT_CTRLS:error!!\n");
+ }
+ free(ext_ctrl.controls->string);
+ free(ext_ctrl.controls);
+ gctrl.id = V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_GET_RESULT;
+ ret = ioctl(fd, VIDIOC_G_CTRL, &amp; gctrl);
+ if (ret &lt; 0) {
+ printf("VIDIOC_G_CTRL:error!!\n");
+ }
+ *AF_SwitchConclusion = gctrl.value;
+ }
+ </programlisting>
+ Note: For V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_GET_RESULT returned values are:
+ <itemizedlist>
+ <listitem><para> -1 AF Switch failed, the AF-RSSI was too low.</para></listitem>
+ <listitem><para> -2 AF Switch failed, the AF-PI Doesn't correlate.</para></listitem>
+ <listitem><para> -3 AF Switch failed, the AF-RDS SYNC Lost.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="rds-transmit">
+ <title>RDS Transmit</title>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>RDS Transmit</term>
+ <listitem>
+ <para>
+ For enabling/disabling RDS for FM Tx, IOCTL VIDIOC_S_MODULATOR should be used with parameter txsubchans of the v4l2_modulator structure set to V4L2_TUNER_SUB_RDS if rds needs to be enabled and the same value must not be set in case rds is to be disabled. For Trasmitting RDS Data like PI, PTY, PSN, RT, VIDIOC_S_EXT_CTRLS IOCTL should be used with the id set to V4L2_CID_RDS_TX_PI, V4L2_CID_RDS_TX_PTY, V4L2_CID_RDS_TX_PS_NAME and V4L2_CID_RDS_TX_RADIO_TEXT respectively. Below example shows how to transmit various RDS functionalities.
+ <programlisting>
+ void rds_tx_set(bool enable_rds)
+ {
+ struct v4l2_modulator modulator;
+ int ret;
+ memset(&amp;modulator, 0, sizeof(modulator));
+ modulator.index = 0;
+ if(enable_rds)
+ modulator.txsubchans |= V4L2_TUNER_SUB_RDS;
+ else
+ modulator.txsubchans &amp; = ~V4L2_TUNER_SUB_RDS;
+ ret = ioctl(fd, VIDIOC_S_MODULATOR, &amp; modulator);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_MODULATOR:error!!\n");
+ }
+ }
+ void rds_tx_PI(void *value)
+ {
+ struct v4l2_ext_controls ext_ctrl;
+ int ret;
+ unsigned short *pi_code = (unsigned short *)value;
+ ext_ctrl.ctrl_class = V4L2_CTRL_CLASS_FM_TX;
+ ext_ctrl.controls = (struct v4l2_ext_control *) malloc(sizeof(struct v4l2_ext_control));
+ ext_ctrl.count = 0;
+ ext_ctrl.controls->id = V4L2_CID_RDS_TX_PI;
+ ext_ctrl.controls->size = 0;
+ ext_ctrl.controls->string = NULL;
+ ext_ctrl.controls->value = *pi_code;
+ ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &amp; ext_ctrl);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_EXT_CTRLS:error!!\n");
+ }
+ free(ext_ctrl.controls);
+ }
+ void rds_tx_PTY(void *value)
+ {
+ struct v4l2_ext_controls ext_ctrl;
+ int ret;
+ unsigned short *pty_code = (unsigned short *)value;
+ ext_ctrl.ctrl_class = V4L2_CTRL_CLASS_FM_TX;
+ ext_ctrl.controls = (struct v4l2_ext_control *) malloc(sizeof(struct v4l2_ext_control));
+ ext_ctrl.count = 0;
+ ext_ctrl.controls->id = V4L2_CID_RDS_TX_PTY;
+ ext_ctrl.controls->size = 0;
+ ext_ctrl.controls->string = NULL;
+ ext_ctrl.controls->value = *pty_code;
+ ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &amp; ext_ctrl);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_EXT_CTRLS:error!!\n");
+ }
+ free(ext_ctrl.controls);
+ }
+ void rds_tx_PSN(void *value)
+ {
+ struct v4l2_ext_controls ext_ctrl;
+ int ret;
+ char *psn = (char *)value;
+ ext_ctrl.ctrl_class = V4L2_CTRL_CLASS_FM_TX;
+ ext_ctrl.controls = (struct v4l2_ext_control *) malloc(sizeof(struct v4l2_ext_control));
+ ext_ctrl.count = 0;
+ ext_ctrl.controls->id = V4L2_CID_RDS_TX_PS_NAME;
+ ext_ctrl.controls->size = strlen(psn);
+ ext_ctrl.controls->value = 0;
+ ext_ctrl.controls->string = (char *)malloc(ext_ctrl.controls->size);
+ memcpy(ext_ctrl.controls->string, psn, ext_ctrl.controls->size);
+ ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &amp; ext_ctrl);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_EXT_CTRLS:error!!\n");
+ }
+ free(ext_ctrl.controls->string);
+ free(ext_ctrl.controls);
+ }
+ void rds_tx_RT(void *value)
+ {
+ struct v4l2_ext_controls ext_ctrl;
+ int ret;
+ char *radio_text = (char *)value;
+ ext_ctrl.ctrl_class = V4L2_CTRL_CLASS_FM_TX;
+ ext_ctrl.controls = (struct v4l2_ext_control *) malloc(sizeof(struct v4l2_ext_control));
+ ext_ctrl.count = 0;
+ ext_ctrl.controls->id = V4L2_CID_RDS_TX_RADIO_TEXT;
+ ext_ctrl.controls->size = strlen(radio_text);
+ ext_ctrl.controls->value = 0;
+ ext_ctrl.controls->string = (char *)malloc(ext_ctrl.controls->size);
+ memcpy(ext_ctrl.controls->string, radio_text, ext_ctrl.controls->size);
+ ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &amp; ext_ctrl);
+ if (ret &lt; 0) {
+ printf("VIDIOC_S_EXT_CTRLS:error!!\n");
+ }
+ free(ext_ctrl.controls->string);
+ free(ext_ctrl.controls);
+ }
+ </programlisting>
+ Note: RDS default parameters
+ <itemizedlist>
+ <listitem><para>Programme Identification code[PI]: Default value -> 0x1234</para></listitem>
+ <listitem><para>Programme Type[PTY]: Default value -> OTHER_MUSIC</para></listitem>
+ <listitem><para>Music/Speech switch[M/S]: Default value -> Music</para></listitem>
+ <listitem><para>Programme Service name[PS]: Default value -> FM Xmit</para></listitem>
+ <listitem><para>Radio text[RT]: Default value -> Default Radio Text</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ </chapter>
+ <chapter id="driver-configuration">
+ <title>Driver Configuration and Interaction</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <para>
+ For debug purposes the variable cg2900_fm_debug_level in the file cg2900_fm_driver.c can be changed to set how much debug printouts
+ that shall be generated.
+ <itemizedlist>
+ <listitem><para>1 = Error logs</para></listitem>
+ <listitem><para>2 = Info logs, e.g. function entries</para></listitem>
+ <listitem><para>3 = Debug logs</para></listitem>
+ <listitem><para>4 = HCI logs, i.e. contents of the transferred data</para></listitem>
+ </itemizedlist>
+ </para>
+ <section id="driver-implemented-operations">
+ <title>Implemented operations in driver</title>
+ <para>
+ </para>
+ <para>
+ <table>
+ <title> Supported device driver operations when using character device </title>
+ <tgroup cols="2"><tbody>
+ <row><entry> open </entry> <entry> Opening a character device will Initialize the FM Chip and download the firmware files.</entry> </row>
+ <row><entry> close </entry> <entry> Closes a character device will deinitialize the FM Chip.</entry> </row>
+ <row><entry> poll </entry> <entry> Polling a character device will check if there is requested data is available or not.</entry> </row>
+ <row><entry> read </entry> <entry> Reading from a character device reads RDS data from the Chip</entry> </row>
+ </tbody></tgroup>
+ </table>
+ </para>
+ </section>
+ <section id="driver-loading">
+ <title>Driver loading parameters</title>
+ <para>
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>radio_nr</term>
+ <listitem>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>Parameter type</term>
+ <listitem><synopsis><type>int</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Default value</term>
+ <listitem><para>0</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Runtime readable/modifiable</term>
+ <listitem><para>Readable</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The parameter radio_nr in radio-cg2900.c can be set to register a particular minor number with Video4Linux. Currently this parameter is set to 0 by default, signifying that the "\dev\radio0" is the character device assigned to CG2900 FM Driver in Video4Linux.
+ If the Platform has more than 1 radio drivers, the radio_nr parameter should be changed in file radio-cg2900.c.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Checking the Radio Number</term>
+ <listitem>
+ <para>
+ cat sys/module/radio_cg2900/parameters/radio_nr
+ </para>
+ <para>
+ The above command gets the radio number registered with
+ Video4Linux. This is used for opening the FM Radio
+ character device from user space.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>grid</term>
+ <listitem>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>Parameter type</term>
+ <listitem><synopsis><type>int</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Default value</term>
+ <listitem><para>1</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Runtime readable/modifiable</term>
+ <listitem><para>Readable</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The parameter grid in radio-cg2900.c defines the spacing to be used in Khz while switching on FM Radio.
+ <itemizedlist>
+ <listitem><para>0: 50 kHz (China)</para></listitem>
+ <listitem><para>1: 100 kHz (Europe, Japan)</para></listitem>
+ <listitem><para>2: 200 kHz (USA)</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Changing the Grid</term>
+ <listitem>
+ <para>
+ echo 1 &gt; /sys/module/radio_cg2900/parameters/grid.
+ </para>
+ <para>
+ The above command sets the radio band spacing between
+ two adjacent radio channels, in this case sets to 100KHz
+ suitable for Europe. The change is applicable before
+ switching on FM Radio, otherwise the change takes effect
+ from next FM switch on.
+ </para>
+ <para>
+ Note: The Grid parameter cannot be changed during FM radio is operational.
+ </para>
+ <para>
+ The user must change the grid value and restart the FM radio when moving into a different radio region.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Checking the current Grid Value</term>
+ <listitem>
+ <para>
+ cat sys/module/radio_cg2900/parameters/grid.
+ </para>
+ <para>
+ The above command gets the radio band spacing
+ between two adjacent radio channels currently set.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>band</term>
+ <listitem>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>Parameter type</term>
+ <listitem><synopsis><type>int</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Default value</term>
+ <listitem><para>0</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Runtime readable/modifiable</term>
+ <listitem><para>Readable</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The parameter band in radio-cg2900.c defines the band to be used while switching on FM Radio.
+ <itemizedlist>
+ <listitem><para>0: 87.5 - 108 MHz (USA, Europe)</para></listitem>
+ <listitem><para>1: 76 - 90 MHz (Japan)</para></listitem>
+ <listitem><para>2: 70 - 108 MHz (China wide band)</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Changing the Band</term>
+ <listitem>
+ <para>
+ echo 0 &gt; /sys/module/radio_cg2900/parameters/band.
+ </para>
+ <para>
+ The above command sets the FM band to be used.
+ In this case, it sets the FM band 87.5 - 100 MHz.
+ The change is applicable before switching on FM Radio,
+ otherwise the change takes effect from next FM switch on.
+ </para>
+ <para>
+ Note: The band parameter cannot be changed during FM radio is operational.
+ </para>
+ <para>
+ The user must change the band value and restart the FM radio when moving into a different radio region.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Checking the current Band Value</term>
+ <listitem>
+ <para>
+ cat sys/module/radio_cg2900/parameters/band.
+ </para>
+ <para>
+ The above command gets the current radio band set.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cg2900_fm_debug_level</term>
+ <listitem>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>Parameter type</term>
+ <listitem><synopsis><type>int</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Default value</term>
+ <listitem><para>1</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Runtime readable/modifiable</term>
+ <listitem><para>Readable</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The parameter CG2900_fm_debug_level in platformosapi.c defines the debug level that is currently used.
+ The higher the debug level the more print-outs are received in the terminal window.
+ The following values are supported:
+ <itemizedlist>
+ <listitem><para>1 = Error logs</para></listitem>
+ <listitem><para>2 = Info logs, e.g. function entries</para></listitem>
+ <listitem><para>3 = Debug logs</para></listitem>
+ <listitem><para>4 = HCI logs, i.e. contents of the transferred data</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Changing the Log Level</term>
+ <listitem>
+ <para>
+ echo 3 &gt; /sys/module/radio_cg2900/parameters/cg2900_fm_debug_level.
+ </para>
+ <para>
+ The above command sets the Logging level of FM Driver.
+ In this case, it set will print all the debug messages
+ except the HCI commands exchanged with FM Chip.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Checking the current Log Level</term>
+ <listitem>
+ <para>
+ cat sys/module/radio_cg2900/parameters/cg2900_fm_debug_level.
+ </para>
+ <para>
+ The above command gets the current debug log level set.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ </para>
+ </section>
+ <section id="driver-ioctl">
+ <title>Driver IO Control</title>
+ <para>
+ Describes the FM driver IO control parameters
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><constant>VIDIOC_QUERYCAP</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Get</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>v4l2_capability</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>VIDIOC_QUERYCAP</constant> IOCTL is used to query the capabilities supported by FM Driver. IF the FM Driver supports FM Rx it should set the capabilities field bit should be bitwise OR'd with V4L2_CAP_TUNER, otherwise if it supports FM Tx, the capabilities field bit should be bitwise OR'd with V4L2_CAP_MODULATOR.
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If IOCTL is able to retrive the Capabilities successfully without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>VIDIOC_G_TUNER</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Get</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>v4l2_tuner</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>VIDIOC_G_TUNER</constant> IOCTL gets the FM Radio Tuner properties supported by FM Radio. It is also used to retrieve RDS status, mono/stereo status and Signal strength of the tuned channel. These values are valid when FM is configured using IOCTL VIDIOC_S_TUNER, i.e in FM Rx mode.
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If IOCTL is able to retrive the tuner properties successfully without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ Note: Currently the retrieved signal strength is in decimals and not in "dBuV", proper external conversion required.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>VIDIOC_S_TUNER</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Set</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>v4l2_tuner</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>VIDIOC_S_TUNER</constant> IOCTL configures the FM radio in Rx mode. Only 1 FM Tuner is supported by FM Driver.
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If IOCTL is able to set the tuner properties successfully without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>VIDIOC_G_MODULATOR</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Get</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>v4l2_tuner</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>VIDIOC_G_MODULATOR</constant> IOCTL gets the FM Radio Modulator properties supported by FM Radio. It is also used to retrieve RDS status and mono/stereo status. These values are valid when FM is configured using IOCTL VIDIOC_S_MODULATOR, i.e in FM Tx mode.
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If IOCTL is able to retrive the tuner properties successfully without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>VIDIOC_S_MODULATOR</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Set</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>v4l2_modulator</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>VIDIOC_S_MODULATOR</constant> IOCTL configures the FM radio in Tx mode. Only 1 FM Modulator is supported by FM Driver.
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If IOCTL is able to set the modulator properties successfully without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>VIDIOC_S_FREQUENCY</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Set</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>v4l2_frequency</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>VIDIOC_S_FREQUENCY</constant> IOCTL sets the frequency on FM radio in Rx or Tx mode. The frequency parameter passed is in V4L2 format.
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If IOCTL is able to set the frequency successfully without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>VIDIOC_G_FREQUENCY</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Set</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>v4l2_modulator</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>VIDIOC_G_FREQUENCY</constant> IOCTL retrives the currently set frequency on FM Radio in Rx or Tx mode.
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If IOCTL is able to get the frequency successfully without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>VIDIOC_S_HW_FREQ_SEEK</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Set</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>v4l2_hw_freq_seek</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>VIDIOC_S_HW_FREQ_SEEK</constant> IOCTL starts the seek operation when FM Radio is configured in Rx mode. The direction parameter indicates the direction of seeking from the current station. At present the FM Driver ignores the wrap_Around parameter and unconditional wrap around is supported. If the operation is started successfully, the application should use poll() to identify when the seek is over.
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If IOCTL is able to start the seek successfully without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>VIDIOC_G_CTRL</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Get</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>v4l2_control</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>VIDIOC_G_CTRL</constant> IOCTL to retrive value of a paticular control. The following controls are supported by FM Driver:
+ <itemizedlist>
+ <listitem><para>
+ V4L2_CID_AUDIO_VOLUME
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_AUDIO_MUTE
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_AUDIO_BALANCE
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_CG2900_RADIO_RSSI_THRESHOLD
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_CG2900_RADIO_SELECT_ANTENNA
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_CG2900_RADIO_RDS_AF_UPDATE_GET_RESULT
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_GET_RESULT
+ </para></listitem>
+ </itemizedlist>
+ Generic returned values are:
+ <itemizedlist>
+ <listitem><para>If IOCTL is able to retrive the value of the control successfully without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ Note: For V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_GET_RESULT returned values are:
+ <itemizedlist>
+ <listitem><para> -1 AF Switch failed, the AF-RSSI was too low.</para></listitem>
+ <listitem><para> -2 AF Switch failed, the AF-PI Doesn't correlate.</para></listitem>
+ <listitem><para> -3 AF Switch failed, the AF-RDS SYNC Lost.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>VIDIOC_S_CTRL</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Set</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>v4l2_control</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>VIDIOC_S_CTRL</constant> IOCTL to set value of a paticular control. The following controls are supported by FM Driver:
+ <itemizedlist>
+ <listitem><para>
+ V4L2_CID_CG2900_RADIO_CHIP_STATE
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_CG2900_RADIO_BANDSCAN
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_CG2900_RADIO_BLOCKSCAN_START
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_CG2900_RADIO_SELECT_ANTENNA
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_CG2900_RADIO_RSSI_THRESHOLD
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_CG2900_RADIO_RDS_AF_UPDATE_START
+ </para></listitem>
+ </itemizedlist>
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If IOCTL is able to set the value of the control successfully without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>VIDIOC_G_EXT_CTRLS</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Get</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>v4l2_ext_controls</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>VIDIOC_G_EXT_CTRLS</constant> IOCTL to retrive value of a paticular control. This is used when a control class is defined or when the value to be retrieved is more than 1 parameter(s). Only V4L2_CTRL_CLASS_FM_TX class is supported for this IOCTL in FM Driver. The following controls are supported by FM Driver:
+ <itemizedlist>
+ <listitem><para>
+ V4L2_CID_RDS_TX_DEVIATION
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_PILOT_TONE_ENABLED
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_PILOT_TONE_DEVIATION
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_TUNE_PREEMPHASIS
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_TUNE_POWER_LEVEL
+ </para></listitem>
+ </itemizedlist>
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If IOCTL is able to retrive the value(s) of the control successfully without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>VIDIOC_S_EXT_CTRLS</constant></term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>Direction</term>
+ <listitem><para>Set</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Parameter</term>
+ <listitem><synopsis><type>v4l2_ext_controls</type></synopsis></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>
+ The <constant>VIDIOC_S_CTRL</constant> IOCTL to set value of a paticular control when the parameters to be set are more than 1 parameter or when a control class is defined. At present only the V4L2_CTRL_CLASS_FM_TX and V4L2_CTRL_CLASS_USER control classes are supported by FM Driver. The following controls are supported by FM Driver:
+ <itemizedlist>
+ <listitem><para>
+ V4L2_CID_RDS_TX_DEVIATION
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_RDS_TX_PI
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_RDS_TX_PTY
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_RDS_TX_PS_NAME
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_RDS_TX_RADIO_TEXT
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_PILOT_TONE_ENABLED
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_PILOT_TONE_DEVIATION
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_TUNE_PREEMPHASIS
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_TUNE_POWER_LEVEL
+ </para></listitem>
+ <listitem><para>
+ V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_START
+ </para></listitem>
+ </itemizedlist>
+ Returned values are:
+ <itemizedlist>
+ <listitem><para>If IOCTL is able to set the value of the control successfully without errors the IOCTL function will return 0.</para></listitem>
+ <listitem><para>A negative value will indicate error.</para></listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="driver-sysfs">
+ <title>Driver Interaction with Sysfs</title>
+ <para>
+ Not Applicable
+ </para>
+ </section>
+ <section id="driver-proc">
+ <title>Driver Interaction using /proc filesystem</title>
+ <para>
+ Not Applicable
+ </para>
+ </section>
+ <section id="driver-other">
+ <title>Other means for Driver Interaction</title>
+ <para>
+ Not Applicable
+ </para>
+ </section>
+ <section id="driver-node">
+ <title>Driver Node File</title>
+ <variablelist>
+ <varlistentry>
+ <term>FM Radio Device</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/radio0</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>The radio device for FM Radio.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ </chapter>
+ <chapter id="bugs">
+ <title>Known Bugs And Limitations</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>No known issues.</term>
+ <listitem>
+ <para>
+ <!-- Do NOT change the chapter id or title! -->
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+ <chapter id="internal-functions">
+ <title>Internal Functions Provided</title>
+ <para>
+ List of internal functions used in FM Driver.
+ </para>
+ <!-- Do NOT change the chapter id or title! -->
+ <section id="radio-cg2900.c">
+ <title>radio-cg2900.c</title>
+!Idrivers/media/radio/CG2900/radio-cg2900.c
+ </section>
+ <section id="cg2900_fm_api.h">
+ <title>cg2900_fm_api.h</title>
+!Idrivers/media/radio/CG2900/cg2900_fm_api.h
+ </section>
+ <section id="cg2900_fm_api.c">
+ <title>cg2900_fm_api.c</title>
+!Idrivers/media/radio/CG2900/cg2900_fm_api.c
+ </section>
+ <section id="cg2900_fm_driver.h">
+ <title>cg2900_fm_driver.h</title>
+!Idrivers/media/radio/CG2900/cg2900_fm_driver.h
+ </section>
+ <section id="cg2900_fm_driver.c">
+ <title>cg2900_fm_driver.c</title>
+!Idrivers/media/radio/CG2900/cg2900_fm_driver.c
+ </section>
+ </chapter>
+</book>
diff --git a/Documentation/DocBook/dma.tmpl b/Documentation/DocBook/dma.tmpl
new file mode 100644
index 00000000000..36d4b182b07
--- /dev/null
+++ b/Documentation/DocBook/dma.tmpl
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="DMA">
+ <bookinfo>
+ <title>DMA40</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Per</firstname>
+ <surname>Friden</surname>
+ <affiliation>
+ <address>
+ <email>per.friden@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Jonas</firstname>
+ <surname>Aaberg</surname>
+ <affiliation>
+ <address>
+ <email>jonas.aberg@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2009-2010</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Linux standard functions</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <!-- Do NOT remove the legal notice below -->
+
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This Documentation describes the API's provided by the DMA controller Driver.
+ </para>
+ </chapter>
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None</term>
+ <listitem>
+ <para>
+ None.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ This Section lists the API's provided by the DMA controller driver to client drivers.
+ </para>
+!Edrivers/dma/ste_dma40.c
+ </chapter>
+
+ <chapter id="private">
+ <title>Private Functions</title>
+ <para>
+ This Section lists the functions used internally by the DMA controller driver.
+ </para>
+!Idrivers/dma/ste_dma40.c
+ </chapter>
+
+ <chapter id="Other">
+ <title>Other Data Structures</title>
+ <para>
+ This Section lists some of the Data structure used by the DMA driver.
+ </para>
+!Iarch/arm/plat-nomadik/include/plat/ste_dma40.h
+!Idrivers/dma/ste_dma40_ll.h
+ </chapter>
+</book>
diff --git a/Documentation/DocBook/gpio.tmpl b/Documentation/DocBook/gpio.tmpl
new file mode 100644
index 00000000000..b69c2770210
--- /dev/null
+++ b/Documentation/DocBook/gpio.tmpl
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="GPIO">
+ <bookinfo>
+ <title>GPIO1B</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Alessandro</firstname>
+ <surname>Rubini</surname>
+ <affiliation>
+ <address>
+ <email>rubini@unipv.it</email>
+ </address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Prafulla</firstname>
+ <surname>WADASKAR</surname>
+ <affiliation>
+ <address>
+ <email>prafulla.wadaskar@st.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2008-2010</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Linux standard functions</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <!-- Do NOT remove the legal notice below -->
+
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This Documentation describes the API's provided by the GPIO controller Driver.
+ </para>
+ <para>
+ Only the API specific to the Ux500 platform is listed here. For the generic GPIO
+ API, see <filename>Documentation/gpio.txt</filename> in the kernel source tree.
+ </para>
+ </chapter>
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None</term>
+ <listitem>
+ <para>
+ None.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title> Public Interface </title>
+ <para>
+ This Section lists the API's provided by the GPIO controller driver to client drivers.
+ </para>
+ <para>
+ Only the API specific to the Ux500 platform is listed here. For the generic GPIO
+ API, see <filename>Documentation/gpio.txt</filename> in the kernel source tree.
+ </para>
+!Earch/arm/plat-nomadik/gpio.c
+ </chapter>
+</book>
diff --git a/Documentation/DocBook/i2c.tmpl b/Documentation/DocBook/i2c.tmpl
new file mode 100644
index 00000000000..8a4cb49204e
--- /dev/null
+++ b/Documentation/DocBook/i2c.tmpl
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="I2C">
+ <bookinfo>
+ <title>I2C</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Srinidhi</firstname>
+ <surname>Kasagar</surname>
+ <affiliation>
+ <address>
+ <email>srinidhi.kasagar@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Sachin</firstname>
+ <surname>Verma</surname>
+ <affiliation>
+ <address>
+ <email>sachin.verma@st.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2009-2010</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Linux standard functions</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <!-- Do NOT remove the legal notice below -->
+
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This Documentation describes the API's provided by the I2C controller Driver.
+ Since this driver registers the transferfunction with kernel framework, there
+ are only private functions in this I2C bus driver. This driver currently
+ works only in master mode and does 7 bit adderssing only. There is no support
+ for 10 bit addressing. The driver currently supports standard mode (100KHz)
+ and Fast mode (400KHz) operation.
+ </para>
+ </chapter>
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None</term>
+ <listitem>
+ <para>
+ None.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ Not Applicable
+ </para>
+ </chapter>
+
+ <chapter id="private">
+ <title>Private Functions</title>
+ <para>
+ This Section lists the functions used internally by the I2C controller driver.
+ </para>
+!Idrivers/i2c/busses/i2c-nomadik.c
+ </chapter>
+
+</book>
diff --git a/Documentation/DocBook/i2s.tmpl b/Documentation/DocBook/i2s.tmpl
new file mode 100644
index 00000000000..6b6c50572e2
--- /dev/null
+++ b/Documentation/DocBook/i2s.tmpl
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="I2S">
+ <bookinfo>
+ <title>I2S</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Sandeep</firstname>
+ <surname>Kaushik</surname>
+ <affiliation>
+ <address>
+ <email>sandeep.kaushik@st.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2008-2009</year>
+ <holder>STMicroelectronics Pvt Ltd</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Linux standard functions</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <!-- Do NOT remove the legal notice below -->
+
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This Documentation describes the APIs provided by the I2S Bus Driver. I2S bus supports different
+ protocols like I2S, PCM, SPI etc.
+ </para>
+ </chapter>
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None</term>
+ <listitem>
+ <para>
+ None.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ This Section lists the functions exported by the I2S bus driver. These functions cater to all the protocols
+ supported namely: I2S, PCM, SPI.
+ </para>
+!Edrivers/misc/i2s/i2s.c
+ </chapter>
+</book>
diff --git a/Documentation/DocBook/mmc.tmpl b/Documentation/DocBook/mmc.tmpl
new file mode 100644
index 00000000000..e07cdcd970e
--- /dev/null
+++ b/Documentation/DocBook/mmc.tmpl
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="SDMMMC">
+ <bookinfo>
+ <title>PL180 MMC/SD/SDIO</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Hanumath</firstname>
+ <surname>prasad</surname>
+ <affiliation>
+ <address>
+ <email>hanumath.prasad@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2009</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Storage</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <!-- Do NOT remove the legal notice below -->
+
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This documentation describes the API's provided by the SDMMC host controller driver.
+ </para>
+ </chapter>
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None</term>
+ <listitem>
+ <para>
+ None.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+ <chapter id="structs">
+ <title>Structures</title>
+ <para>
+ This chapter contains the autogenerated documentation of the structures which are
+ used in the SDMMC driver.
+ </para>
+!Iarch/arm/mach-ux500/include/mach/mmc.h
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ This chapter contains the autogenerated documentation of the kernel API functions
+ which are exported.
+ </para>
+!Edrivers/mmc/host/mmc-u8500.c
+ </chapter>
+
+ <chapter id="intfunctions">
+ <title>Internal Functions Provided</title>
+ <para>
+ This chapter contains the autogenerated documentation of the internal functions of the host controller driver.
+ </para>
+!Idrivers/mmc/host/mmc-u8500.c
+ </chapter>
+
+ </book>
diff --git a/Documentation/DocBook/msp.tmpl b/Documentation/DocBook/msp.tmpl
new file mode 100644
index 00000000000..55cec352a76
--- /dev/null
+++ b/Documentation/DocBook/msp.tmpl
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="MSP">
+ <bookinfo>
+ <title>MSP</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Sandeep</firstname>
+ <surname>Kaushik</surname>
+ <affiliation>
+ <address>
+ <email>sandeep.kaushik@st.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2008-2009</year>
+ <holder>STMicroelectronics Pvt Ltd</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Linux standard functions</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <!-- Do NOT remove the legal notice below -->
+
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This Documentation describes the API's provided by the MSP controller Driver.
+ MSP controller supports different protocols like I2S, PCM, SPI etc.
+ </para>
+ </chapter>
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None</term>
+ <listitem>
+ <para>
+ None.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ Not Applicable.
+ </para>
+ </chapter>
+
+ <chapter id="private">
+ <title>Private Functions</title>
+ <para>
+ This Section lists the functions used by the MSP controller driver.
+ These functions cater to all the protocols supported namely: I2S, PCM, SPI.
+ </para>
+!Idrivers/misc/i2s/msp_i2s.c
+ </chapter>
+</book>
diff --git a/Documentation/DocBook/prcmu-fw-api.tmpl b/Documentation/DocBook/prcmu-fw-api.tmpl
new file mode 100644
index 00000000000..2d9419de53e
--- /dev/null
+++ b/Documentation/DocBook/prcmu-fw-api.tmpl
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="STw4500">
+ <bookinfo>
+ <title>PRCMU Driver</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Sudeep Karkada</firstname>
+ <surname>Nagesha</surname>
+ <affiliation>
+ <address>
+ <email>sudeepkarkada.nagesha@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2009-2010</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Linux standard functions</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <!-- Do NOT remove the legal notice below -->
+
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This documentation describes the API provided by the PRCMU firmware interface driver.
+ </para>
+ </chapter>
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None</term>
+ <listitem>
+ <para>
+ None.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+ <chapter id="enum">
+ <title>Enumerations</title>
+ <para>
+ This chapter contains the autogenerated documentation of the structures
+ and enumerations which are used in the PRCMU firmware interface driver.
+ It is also required by the client drivers.
+ </para>
+!Iarch/arm/mach-ux500/include/mach/prcmu-fw-api.h
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ This chapter contains the autogenerated documentation of the kernel
+ API functions which are exported to the client drivers.
+ </para>
+!Earch/arm/mach-ux500/prcmu-db8500.c
+ </chapter>
+
+
+ </book>
diff --git a/Documentation/DocBook/shrm.tmpl b/Documentation/DocBook/shrm.tmpl
new file mode 100644
index 00000000000..ce5800f5263
--- /dev/null
+++ b/Documentation/DocBook/shrm.tmpl
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="SHRM">
+ <bookinfo>
+ <title>Shared Memory</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Biju</firstname>
+ <surname>Das</surname>
+ <affiliation>
+ <address>
+ <email>biju.das@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Kumar</firstname>
+ <surname>Sanghvi</surname>
+ <affiliation>
+ <address>
+ <email>kumar.sanghvi@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Arun</firstname>
+ <surname>Murthy</surname>
+ <affiliation>
+ <address>
+ <email>arun.murthy@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2009-2010</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Linux standard functions</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <!-- Do NOT remove the legal notice below -->
+ <para>
+ Licence terms: GNU General Public Licence (GPL) version 2.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This Documentation describes the ST-Ericsson's adaptation on protocol used for CMT/APE communication when SHaRedMemory is used as IPC link.
+ </para>
+ </chapter>
+
+ <chapter id="design">
+ <title>Design</title>
+ <para>
+ The APE consists Cortex A9 dual core SMP, a multimedia DSP and PRCMU. Modem consists of 2 Cortex R4 ARM processor.
+ The exchange of messages between CMT(Cellular Mobile Terminal) and APE includes copying the data to a shared area DDR. This region is accessible by both CMT and APE. The design includes 2 channels common and audio. Common channel is used for exchanging ISI, RPC and SECURITY messages. Audio channel is used for exchanging AUDIO messages. Each channel consists of 2 FIFO. One FIFO for sending message from CMT to APE and other from APE to CMT. Each of these FIFO have write and read pointer shared between APE and CMT. Writer pointer is updated on copying the message to FIFO and reader will read the messages from the read pointer upto the writer pointer. Writer and reader notifications are used to notify the completion of read/write operation(seperate for APE and CMT). Driver includes 4 queues. Once the messages are sent from CMT to APE it resides in the FIFO and then copied to one of the 4 queues based on the message type(ISI, RPC, AUDIO, SECURITY) and then the net/char device interface fetches this message from the queue and copies to the user space buffer.
+ </para>
+ </chapter>
+
+ <chapter id="concepts">
+ <title>Concepts</title>
+ <para>
+ The user space application sends ISI/RPC/AUDIO/SECURITY messages. ISI is sent through the phonet to shrm driver. For achieving this there are 2 interfaces to the shrm driver. Net interface used for exchanging the ISI message and char interface for RPC, AUDIO and SECURITY messages. On receiving any of these messages from the user space application, it is copied to a memory in kernel space. From here it is then copied to respective FIFO from where the CMT reads the message.
+ CMT(Cellular Mobile Terminal) writes messages to the respective FIFO and thereafter to respective queue. The net/char device copies this message from the queue to the user space buffer.
+ </para>
+ </chapter>
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None</term>
+ <listitem>
+ <para>
+ Assumptions
+ 1. ApeShmFifo#0 is of 128kB in size. As this is used for transmission except CS audio call data. Expected message size is 1.5kB with a max of 16kB.
+ 2. ApeShmFifo#1 is of 4kB in size. This is used for transmission of CS audio call data. Expected message size is 24kb.
+ 3. CmtShmFifo#0 is of 128kB in size. As this is used for transmission except CS audio call data. Expected message size is 1.5kB with a max of 16kB.
+ 4. CmtShmFifo#1 is of 4kB in size. This is used for transmission of CS audio call data. Expected message size is 24kb.
+ The total size of the FIFO is 264 kB.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ This Section lists the API's provided by the SHRM driver to phonet drivers.
+ </para>
+!Edrivers/net/u8500_shrm.c
+ <para>
+ This Section lists the API's provided by the SHRM driver used in transmission of RPC, AUDIO and SECURITY messages.
+ </para>
+!Edrivers/char/shrm_char.c
+ </chapter>
+
+ <chapter id="private">
+ <title>Private Functions</title>
+ <para>
+ This Section lists the functions used internally by the SHRM driver to implement FIFO management. It physically reads/writes data to/from memory.
+ </para>
+!Idrivers/misc/shrm/shrm_fifo.c
+ <para>
+ This Section lists the functions used internally by the SHRM driver to implement the SHM protocol and handle all interrupt callback.
+ </para>
+!Idrivers/misc/shrm/shrm_protocol.c
+ <para>
+ This Section lists the functions used internally by the SHRM driver to implement Modem-Host communication L1 interface specifications.
+ </para>
+!Idrivers/misc/shrm/modem_shrm_driver.c
+ </chapter>
+
+ <chapter id="Other">
+ <title>Other Data Structures</title>
+ <para>
+ This Section lists some of the Data structure used by the SHRM driver.
+ </para>
+!Iarch/arm/mach-ux500/include/mach/shrm.h
+!Iarch/arm/mach-ux500/include/mach/shrm_driver.h
+!Iarch/arm/mach-ux500/include/mach/shrm_private.h
+ </chapter>
+</book>
diff --git a/Documentation/DocBook/ske_keypad.tmpl b/Documentation/DocBook/ske_keypad.tmpl
new file mode 100644
index 00000000000..6f03ad12d07
--- /dev/null
+++ b/Documentation/DocBook/ske_keypad.tmpl
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="keypad-API-Guide">
+ <bookinfo>
+ <title>SKE Keypad</title>
+
+ <authorgroup>
+ <author>
+ <firstname>NaveenKumar</firstname>
+ <surname>Gaddipati</surname>
+ <affiliation>
+ <address>
+ <email>naveen.gaddipati@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2010</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Linux standard functions</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <para>
+ License terms: GNU General Public License (GPL) version 2.
+ </para>
+
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This documentation describes the API provided by the keypad driver for internal keypad.
+ </para>
+ </chapter>
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None</term>
+ <listitem>
+ <para>
+ None.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ This ske keypad driver doesn't export any functions.
+ </para>
+ </chapter>
+
+ <chapter id="structs">
+ <title>Structures</title>
+ <para>
+ This chapter contains the autogenerated documentation of the structures which are
+ used in the keypad driver.
+ </para>
+!Iarch/arm/mach-ux500/include/mach/kpd.h
+ </chapter>
+
+ <chapter id="intfunctions">
+ <title>Internal Functions Provided</title>
+ <para>
+ This chapter contains the autogenerated documentation of the internal functions.
+ </para>
+!Idrivers/input/keyboard/nomadik-ske-keypad.c
+ </chapter>
+
+ </book>
diff --git a/Documentation/DocBook/ste_ff_vibra.tmpl b/Documentation/DocBook/ste_ff_vibra.tmpl
new file mode 100644
index 00000000000..cf5f159bed0
--- /dev/null
+++ b/Documentation/DocBook/ste_ff_vibra.tmpl
@@ -0,0 +1,217 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="STE-Force-Feedback-Vibrator-API-Guide">
+ <bookinfo>
+ <title>Force Feedback Vibrator Driver</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Marcin</firstname>
+ <surname>Mielczarczyk</surname>
+ <affiliation>
+ <address>
+ <email>marcin.mielczarczyk@tieto.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2010</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Linux standard functions</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+ <toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This documentation describes the implementation of ST-Ericsson's
+ Force Feedback Vibrator driver for the ST-Ericsson Linux platforms.
+ </para>
+ </chapter>
+
+ <chapter id="gettingstarted">
+ <title>Getting Started</title>
+ <para>
+ There are no special compilation flags needed to build the
+ Force Feedback Vibrator driver.
+ </para>
+
+ <section id="basic-tutorial">
+ <title>Basic Tutorial</title>
+ <para>
+ To enable the Force Feedback Vibrator driver using Kconfig, go to
+ <constant> Device Drivers -&gt; Input Device Support -&gt; Miscellaneous devices </constant>
+ and enable the following:
+ <itemizedlist>
+ <listitem><para>ST-Ericsson Force Feedback Vibrator</para></listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ </chapter>
+
+ <chapter id="concepts">
+ <title>Concepts</title>
+ <para>
+ Vibrator driver registers as memless force feedback input device.
+ </para>
+ </chapter>
+
+ <chapter id="driver-configuration">
+ <title>Driver Configuration and Interaction</title>
+ <para>
+ There are no configuration parameters for Force Feedback Vibrator driver.
+ </para>
+ <section id="driver-implemented-operations">
+ <title>Implemented operations in driver</title>
+ <para>
+ All available operations are provided by Memless Input Device class driver.
+ </para>
+ <para>
+ <table>
+ <title> Supported device driver operations </title>
+ <tgroup cols="2"><tbody>
+ <row><entry> open </entry> <entry> Calls ste_ff_vibra_open() function which initializaes workqueue </entry> </row>
+ <row><entry> close </entry> <entry> Calls ste_ff_vibra_close() function which cancels and destroys workqueue </entry> </row>
+ </tbody></tgroup>
+ </table>
+ </para>
+ </section>
+ <section id="driver-loading">
+ <title>Driver loading parameters</title>
+ <para>
+ Not Applicable.
+ </para>
+ </section>
+ <section id="driver-ioctl">
+ <title>Driver IO Control</title>
+ <para>
+ Not Applicable.
+ </para>
+ </section>
+
+ <section id="driver-sysfs">
+ <title>Driver Interaction with Sysfs</title>
+ <para>
+ Not Applicable.
+ </para>
+ </section>
+ <section id="driver-proc">
+ <title>Driver Interaction using /proc filesystem</title>
+ <para>
+ Not Applicable.
+ </para>
+ </section>
+
+ <section id="driver-other">
+ <title>Other means for Driver Interaction</title>
+ <para>
+ Not Applicable.
+ </para>
+ </section>
+
+ <section id="driver-node">
+ <title>Driver Node File</title>
+ <para>
+ Force Feedback Vibrator driver provides following node files:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>eventX - Force Feedback Vibrator node file</term>
+ <listitem>
+ <variablelist>
+ <varlistentry>
+ <term>File</term>
+ <listitem><para><filename>/dev/input/eventX</filename></para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Description</term>
+ <listitem>
+ <para>Node file of Force Feedback Vibrator driver</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </section>
+
+
+ </chapter>
+
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None.</term>
+ <listitem>
+ <para>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ </para>
+ </chapter>
+
+<chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ Not Applicable.
+ </para>
+
+</chapter>
+
+<chapter id="internal-functions">
+ <title>Internal Functions Provided</title>
+ <para>
+ This chapter contains the autogenerated documentation of the internal functions.
+ </para>
+!Edrivers/input/misc/ste_ff_vibra.c
+</chapter>
+
+</book>
diff --git a/Documentation/DocBook/stmpe.tmpl b/Documentation/DocBook/stmpe.tmpl
new file mode 100644
index 00000000000..b0d8bc51af9
--- /dev/null
+++ b/Documentation/DocBook/stmpe.tmpl
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="STMPE MFD devices">
+ <bookinfo>
+ <title>STMPE IO-Port Expander guide</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Rabin</firstname>
+ <surname>Vincent</surname>
+ <affiliation>
+ <address>
+ <email>rabin.vincent@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2010</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Linux standard functions</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <para>
+ This documentation 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.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This documentation describes the driver for STMicroelectronics
+ STMPExxxx port expander devices.
+ </para>
+ </chapter>
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None.</term>
+ <listitem>
+ <para>
+ None.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ List of public interfaces in stmpe driver
+ </para>
+!Edrivers/mfd/stmpe.c
+ </chapter>
+
+ <chapter id="private">
+ <title>Private Functions</title>
+ <para>
+ STMPE Keypad driver
+ STMPE GPIO driver
+ </para>
+ <section id="stmpe-keypad.c">
+ <title>stmpe-keypad.c</title>
+!Idrivers/input/keyboard/stmpe-keypad.c
+ </section>
+ <section id="stmpe-gpio.c">
+ <title>stmpe-gpio.c</title>
+!Idrivers/gpio/stmpe-gpio.c
+ </section>
+ </chapter>
+
+ <chapter id="Other">
+ <title>Other Data Structures</title>
+ <para>
+ This Section lists some of the Data structure used by the stmpe driver and client drivers.
+ </para>
+!Iinclude/linux/mfd/stmpe.h
+!Idrivers/mfd/stmpe.h
+</chapter>
+</book>
+
diff --git a/Documentation/DocBook/tc_keypad.tmpl b/Documentation/DocBook/tc_keypad.tmpl
new file mode 100644
index 00000000000..8c69345df44
--- /dev/null
+++ b/Documentation/DocBook/tc_keypad.tmpl
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="TC35893">
+ <bookinfo>
+ <title>TC35893 Keypad</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Jayeeta</firstname>
+ <surname>Banerjee</surname>
+ <affiliation>
+ <address>
+ <email>jayeeta.banerjee@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2010</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Linux standard functions</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <!-- Do NOT remove the legal notice below -->
+
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This documentation describes the API provided by the keypad driver for TC35893 controller
+ </para>
+ </chapter>
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None</term>
+ <listitem>
+ <para>
+ None.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+ <chapter id="structs">
+ <title>Structures</title>
+ <para>
+ This chapter contains the autogenerated documentation of the structures which are
+ used in the keypad driver.
+ </para>
+!Iarch/arm/mach-ux500/include/mach/tc35893-keypad.h
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ Not Applicable.
+ </para>
+ </chapter>
+
+ <chapter id="intfunctions">
+ <title>Internal Functions Provided</title>
+ <para>
+ This chapter contains the autogenerated documentation of the internal functions.
+ </para>
+!Idrivers/input/keyboard/tc35893-keypad.c
+ </chapter>
+
+ </book>
diff --git a/Documentation/DocBook/touchp.tmpl b/Documentation/DocBook/touchp.tmpl
new file mode 100644
index 00000000000..4301b23bfc0
--- /dev/null
+++ b/Documentation/DocBook/touchp.tmpl
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="bu21013_ts">
+ <bookinfo>
+ <title>Touch screen ROHM BU21013MWV</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Naveen Kumar</firstname>
+ <surname>Gaddipati</surname>
+ <affiliation>
+ <address>
+ <email>naveen.gaddipati@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2009</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Linux standard functions</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <!-- Do NOT remove the legal notice below -->
+
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This documentation describes the functions provided by the driver of touch panel for BU21013 controller
+ </para>
+ </chapter>
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>None</term>
+ <listitem>
+ <para>
+ None.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <para>
+ Not Applicable.
+ </para>
+ </chapter>
+
+ <chapter id="intfunctions">
+ <title>Internal Functions Provided</title>
+ <para>
+ This chapter contains the autogenerated documentation of the internal functions of the Tocuh panel driver.
+ </para>
+!Idrivers/input/touchscreen/bu21013_ts.c
+ </chapter>
+
+ </book>
diff --git a/Documentation/DocBook/u8500_usb.tmpl b/Documentation/DocBook/u8500_usb.tmpl
new file mode 100644
index 00000000000..86f2e7cb7ce
--- /dev/null
+++ b/Documentation/DocBook/u8500_usb.tmpl
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="USB-FUNCTION-Guide">
+ <bookinfo>
+ <title>Montblanc USB Driver Function guide</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Raj</firstname>
+ <surname>Kumar</surname>
+ <affiliation>
+ <address>
+ <email>raj.e.kumar@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>NaveenKumar</firstname>
+ <surname>Gaddipati</surname>
+ <affiliation>
+ <address>
+ <email>naveen.gaddipati@stericsson.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2009</year>
+ <holder>ST-Ericsson</holder>
+ </copyright>
+
+ <subjectset>
+ <subject>
+ <subjectterm>Connectivity</subjectterm>
+ </subject>
+ </subjectset>
+
+ <legalnotice>
+ <para>
+ This documentation 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.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ This documentation describes ST-Ericsson's adaptation on USB external DMA and communication between Mentor USB IP controller and the USB
+ transreveiver
+ </para>
+ </chapter>
+
+ <chapter id="concepts">
+ <title>Concepts</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <para>
+ In ST-Ericsson's USB driver, the open source linux gadget stack and Mentor IP USB 2.0 driver is used. Since the USB Transceiver and Mentor USB IP controller are on different hardware, API's are defined for the communication between them. These API's are available in stm_musb.c file.
+ The ST-Ericsson's USB driver doesn't have the internal DMA dedicated for USB. So, the external system DMA is used. The integration of external DMA with the mentor chip is available in stm_musb_dma.c file.
+ Changes have been made in the musb_core.c file where endpoints are configured as per the platform and also integrated DMA specific chnages in the musb_gadget.c file. One new file ste_config.h is added which is platform specific.
+ <!-- TODO: A brief introduction about the concepts
+ which are introduced by the driver.
+ Remove this chapter completely if there are no
+ special concepts introduced by this driver.
+ Do NOT change the chapter id or title! -->
+ <!-- TODO: This guideline for this chapter may be extended
+ during the user-guide guidelines drop. -->
+ </para>
+ </chapter>
+
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <para>
+ <variablelist>
+
+ <varlistentry>
+ <term>None.</term>
+ <listitem>
+ <para>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ </para>
+ </chapter>
+
+ <chapter id="pubfunctions">
+ <title>Public Functions Provided</title>
+ <!-- Do NOT change the chapter id or title! -->
+ <para>
+ List of public interfaces in stm_musb_dma.c
+ </para>
+ <!-- TODO: Replace with link to appropriate headerfile(s), one per row, ensure the exclamation mark is on the first column! -->
+!Edrivers/usb/musb/stm_musb.c
+ </chapter>
+
+ <chapter id="internal-functions">
+ <title>Internal Functions Provided</title>
+ <para>
+ List of internal functions
+ </para>
+ <!-- Do NOT change the chapter id or title! -->
+ <!-- TODO: Replace with link to appropriate headerfile(s),
+ source file(s), or both. One per row, ensure the
+ exclamation mark is on the first column! If no
+ appropriate header or source file exist describing a public interface,
+ replace the inclusion with a paragraph containing the text
+ "Not Applicable"-->
+ <section id="stm_musb_dma.c">
+ <title>stm_musb_dma.c</title>
+!Idrivers/usb/musb/stm_musb_dma.c
+ </section>
+ <section id="stm_musb.c">
+ <title>stm_musb.c</title>
+!Idrivers/usb/musb/stm_musb.c
+ </section>
+</chapter>
+
+</book>
diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt
index eb0fae18ffb..771d48d3b33 100644
--- a/Documentation/arm/memory.txt
+++ b/Documentation/arm/memory.txt
@@ -33,7 +33,13 @@ ffff0000 ffff0fff CPU vector page.
fffe0000 fffeffff XScale cache flush area. This is used
in proc-xscale.S to flush the whole data
- cache. Free for other usage on non-XScale.
+ cache. (XScale does not have TCM.)
+
+fffe8000 fffeffff DTCM mapping area for platforms with
+ DTCM mounted inside the CPU.
+
+fffe0000 fffe7fff ITCM mapping area for platforms with
+ ITCM mounted inside the CPU.
fff00000 fffdffff Fixmap mapping region. Addresses provided
by fix_to_virt() will be located here.
diff --git a/Documentation/arm/tcm.txt b/Documentation/arm/tcm.txt
index 77fd9376e6d..7c15871c188 100644
--- a/Documentation/arm/tcm.txt
+++ b/Documentation/arm/tcm.txt
@@ -19,8 +19,8 @@ defines a CPUID_TCM register that you can read out from the
system control coprocessor. Documentation from ARM can be found
at http://infocenter.arm.com, search for "TCM Status Register"
to see documents for all CPUs. Reading this register you can
-determine if ITCM (bit 0) and/or DTCM (bit 16) is present in the
-machine.
+determine if ITCM (bits 1-0) and/or DTCM (bit 17-16) is present
+in the machine.
There is further a TCM region register (search for "TCM Region
Registers" at the ARM site) that can report and modify the location
@@ -35,7 +35,15 @@ The TCM memory can then be remapped to another address again using
the MMU, but notice that the TCM if often used in situations where
the MMU is turned off. To avoid confusion the current Linux
implementation will map the TCM 1 to 1 from physical to virtual
-memory in the location specified by the machine.
+memory in the location specified by the kernel. Currently Linux
+will map ITCM to 0xfffe0000 and on, and DTCM to 0xfffe8000 and
+on, supporting a maximum of 32KiB of ITCM and 32KiB of DTCM.
+
+Newer versions of the region registers also support dividing these
+TCMs in two separate banks, so for example an 8KiB ITCM is divided
+into two 4KiB banks with its own control registers. The idea is to
+be able to lock and hide one of the banks for use by the secure
+world (TrustZone).
TCM is used for a few things:
@@ -65,18 +73,18 @@ in <asm/tcm.h>. Using this interface it is possible to:
memory. Such a heap is great for things like saving
device state when shutting off device power domains.
-A machine that has TCM memory shall select HAVE_TCM in
-arch/arm/Kconfig for itself, and then the
-rest of the functionality will depend on the physical
-location and size of ITCM and DTCM to be defined in
-mach/memory.h for the machine. Code that needs to use
-TCM shall #include <asm/tcm.h> If the TCM is not located
-at the place given in memory.h it will be moved using
-the TCM Region registers.
+A machine that has TCM memory shall select HAVE_TCM from
+arch/arm/Kconfig for itself. Code that needs to use TCM shall
+#include <asm/tcm.h>
Functions to go into itcm can be tagged like this:
int __tcmfunc foo(int bar);
+Since these are marked to become long_calls and you may want
+to have functions called locally inside the TCM without
+wasting space, there is also the __tcmlocalfunc prefix that
+will make the call relative.
+
Variables to go into dtcm can be tagged like this:
int __tcmdata foo;
diff --git a/Documentation/networking/caif/spi_porting.txt b/Documentation/networking/caif/spi_porting.txt
new file mode 100644
index 00000000000..61d7c924745
--- /dev/null
+++ b/Documentation/networking/caif/spi_porting.txt
@@ -0,0 +1,208 @@
+- CAIF SPI porting -
+
+- CAIF SPI basics:
+
+Running CAIF over SPI needs some extra setup, owing to the nature of SPI.
+Two extra GPIOs have been added in order to negotiate the transfers
+ between the master and the slave. The minimum requirement for running
+CAIF over SPI is a SPI slave chip and two GPIOs (more details below).
+Please note that running as a slave implies that you need to keep up
+with the master clock. An overrun or underrun event is fatal.
+
+- CAIF SPI framework:
+
+To make porting as easy as possible, the CAIF SPI has been divided in
+two parts. The first part (called the interface part) deals with all
+generic functionality such as length framing, SPI frame negotiation
+and SPI frame delivery and transmission. The other part is the CAIF
+SPI slave device part, which is the module that you have to write if
+you want to run SPI CAIF on a new hardware. This part takes care of
+the physical hardware, both with regard to SPI and to GPIOs.
+
+- Implementing a CAIF SPI device:
+
+ - Functionality provided by the CAIF SPI slave device:
+
+ In order to implement a SPI device you will, as a minimum,
+ need to implement the following
+ functions:
+
+ int (*init_xfer) (struct cfspi_xfer * xfer, struct cfspi_dev *dev):
+
+ This function is called by the CAIF SPI interface to give
+ you a chance to set up your hardware to be ready to receive
+ a stream of data from the master. The xfer structure contains
+ both physical and logical adresses, as well as the total length
+ of the transfer in both directions.The dev parameter can be used
+ to map to different CAIF SPI slave devices.
+
+ void (*sig_xfer) (bool xfer, struct cfspi_dev *dev):
+
+ This function is called by the CAIF SPI interface when the output
+ (SPI_INT) GPIO needs to change state. The boolean value of the xfer
+ variable indicates whether the GPIO should be asserted (HIGH) or
+ deasserted (LOW). The dev parameter can be used to map to different CAIF
+ SPI slave devices.
+
+ - Functionality provided by the CAIF SPI interface:
+
+ void (*ss_cb) (bool assert, struct cfspi_ifc *ifc);
+
+ This function is called by the CAIF SPI slave device in order to
+ signal a change of state of the input GPIO (SS) to the interface.
+ Only active edges are mandatory to be reported.
+ This function can be called from IRQ context (recommended in order
+ not to introduce latency). The ifc parameter should be the pointer
+ returned from the platform probe function in the SPI device structure.
+
+ void (*xfer_done_cb) (struct cfspi_ifc *ifc);
+
+ This function is called by the CAIF SPI slave device in order to
+ report that a transfer is completed. This function should only be
+ called once both the transmission and the reception are completed.
+ This function can be called from IRQ context (recommended in order
+ not to introduce latency). The ifc parameter should be the pointer
+ returned from the platform probe function in the SPI device structure.
+
+ - Connecting the bits and pieces:
+
+ - Filling in the SPI slave device structure:
+
+ Connect the necessary callback functions.
+ Indicate clock speed (used to calculate toggle delays).
+ Chose a suitable name (helps debugging if you use several CAIF
+ SPI slave devices).
+ Assign your private data (can be used to map to your structure).
+
+ - Filling in the SPI slave platform device structure:
+ Add name of driver to connect to ("cfspi_sspi").
+ Assign the SPI slave device structure as platform data.
+
+- Padding:
+
+In order to optimize throughput, a number of SPI padding options are provided.
+Padding can be enabled independently for uplink and downlink transfers.
+Padding can be enabled for the head, the tail and for the total frame size.
+The padding needs to be correctly configured on both sides of the link.
+The padding can be changed via module parameters in cfspi_sspi.c or via
+the sysfs directory of the cfspi_sspi driver (before device registration).
+
+- CAIF SPI device template:
+
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <net/caif/caif_spi.h>
+
+MODULE_LICENSE("GPL");
+
+struct sspi_struct {
+ struct cfspi_dev sdev;
+ struct cfspi_xfer *xfer;
+};
+
+static struct sspi_struct slave;
+static struct platform_device slave_device;
+
+static irqreturn_t sspi_irq(int irq, void *arg)
+{
+ /* You only need to trigger on an edge to the active state of the
+ * SS signal. Once a edge is detected, the ss_cb() function should be
+ * called with the parameter assert set to true. It is OK
+ * (and even advised) to call the ss_cb() function in IRQ context in
+ * order not to add any delay. */
+
+ return IRQ_HANDLED;
+}
+
+static void sspi_complete(void *context)
+{
+ /* Normally the DMA or the SPI framework will call you back
+ * in something similar to this. The only thing you need to
+ * do is to call the xfer_done_cb() function, providing the pointer
+ * to the CAIF SPI interface. It is OK to call this function
+ * from IRQ context. */
+}
+
+static int sspi_init_xfer(struct cfspi_xfer *xfer, struct cfspi_dev *dev)
+{
+ /* Store transfer info. For a normal implementation you should
+ * set up your DMA here and make sure that you are ready to
+ * receive the data from the master SPI. */
+
+ struct sspi_struct *sspi = (struct sspi_struct *)dev->priv;
+
+ sspi->xfer = xfer;
+
+ return 0;
+}
+
+void sspi_sig_xfer(bool xfer, struct cfspi_dev *dev)
+{
+ /* If xfer is true then you should assert the SPI_INT to indicate to
+ * the master that you are ready to recieve the data from the master
+ * SPI. If xfer is false then you should de-assert SPI_INT to indicate
+ * that the transfer is done.
+ */
+
+ struct sspi_struct *sspi = (struct sspi_struct *)dev->priv;
+}
+
+static void sspi_release(struct device *dev)
+{
+ /*
+ * Here you should release your SPI device resources.
+ */
+}
+
+static int __init sspi_init(void)
+{
+ /* Here you should initialize your SPI device by providing the
+ * necessary functions, clock speed, name and private data. Once
+ * done, you can register your device with the
+ * platform_device_register() function. This function will return
+ * with the CAIF SPI interface initialized. This is probably also
+ * the place where you should set up your GPIOs, interrupts and SPI
+ * resources. */
+
+ int res = 0;
+
+ /* Initialize slave device. */
+ slave.sdev.init_xfer = sspi_init_xfer;
+ slave.sdev.sig_xfer = sspi_sig_xfer;
+ slave.sdev.clk_mhz = 13;
+ slave.sdev.priv = &slave;
+ slave.sdev.name = "spi_sspi";
+ slave_device.dev.release = sspi_release;
+
+ /* Initialize platform device. */
+ slave_device.name = "cfspi_sspi";
+ slave_device.dev.platform_data = &slave.sdev;
+
+ /* Register platform device. */
+ res = platform_device_register(&slave_device);
+ if (res) {
+ printk(KERN_WARNING "sspi_init: failed to register dev.\n");
+ return -ENODEV;
+ }
+
+ return res;
+}
+
+static void __exit sspi_exit(void)
+{
+ platform_device_del(&slave_device);
+}
+
+module_init(sspi_init);
+module_exit(sspi_exit);
diff --git a/Documentation/networking/phonet.txt b/Documentation/networking/phonet.txt
index 6e8ce09f9c7..8589d1e5635 100644
--- a/Documentation/networking/phonet.txt
+++ b/Documentation/networking/phonet.txt
@@ -166,6 +166,50 @@ The pipe protocol provides two socket options at the SOL_PNPIPE level:
or zero if encapsulation is off.
+Phonet Pipe-controller Implementation
+-------------------------------------
+
+Phonet Pipe-controller is enabled by selecting the CONFIG_PHONET_PIPECTRLR Kconfig
+option. It is useful when communicating with those Nokia Modems which do not
+implement Pipe controller in them e.g. Nokia Slim Modem used in ST-Ericsson
+U8500 platform.
+
+The implementation is based on the Data Connection Establishment Sequence
+depicted in 'Nokia Wireless Modem API - Wireless_modem_user_guide.pdf'
+document.
+
+It allows a phonet sequenced socket (host-pep) to initiate a Pipe connection
+between itself and a remote pipe-end point (e.g. modem).
+
+The implementation adds socket options at SOL_PNPIPE level:
+
+ PNPIPE_CREATE
+ It accepts an integer argument where-in
+ lower order 16 bits: pn_dev and pn_port pair for remote pep.
+ higher order 16 bits: 8 bit pipe-handle
+
+ It sends a PNS_PEP_CONNECT_REQ on sequenced socket itself. On getting
+ PNS_PEP_CONNECT_RESP, it sends PNS_PEP_CONNECT_REQ to remote pep. On
+ getting response from remote pep, it selects the best possible Flow
+ control mechanism supported by remote-pep (modem) and then it sends
+ PNS_PEP_CREATED_IND to the sequenced socket and to the remote pep.
+
+ It then updates the pipe state associated with the sequenced socket to
+ be PIPE_DISABLED.
+
+ PNPIPE_ENABLE accepts one integer value (int). If set to zero, the pipe
+ is disabled. If the value is non-zero, the pipe is enabled. If the pipe
+ is not (yet) connected, ENOTCONN is error is returned.
+
+ PNPIPE_DESTROY
+ This will send out PNS_PEP_DISCONNECT_REQ on the sequenced socket and
+ the remote pep.
+ It will also update the pipe state associated with the sequenced socket
+ to PIPE_IDLE
+
+After a pipe has been created and enabled successfully, the Pipe data can be
+exchanged between the host-pep and remote-pep (modem).
+
Authors
-------
diff --git a/MAINTAINERS b/MAINTAINERS
index 02f75fccac2..b640bcda763 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -977,12 +977,11 @@ F: drivers/input/keyboard/w90p910_keypad.c
F: drivers/input/touchscreen/w90p910_ts.c
F: drivers/watchdog/nuc900_wdt.c
F: drivers/net/arm/w90p910_ether.c
-F: drivers/mtd/nand/w90p910_nand.c
+F: drivers/mtd/nand/nuc900_nand.c
F: drivers/rtc/rtc-nuc900.c
F: drivers/spi/spi_nuc900.c
F: drivers/usb/host/ehci-w90x900.c
F: drivers/video/nuc900fb.c
-F: drivers/sound/soc/nuc900/
ARM/U300 MACHINE SUPPORT
M: Linus Walleij <linus.walleij@stericsson.com>
@@ -1431,6 +1430,16 @@ S: Maintained
F: Documentation/video4linux/cafe_ccic
F: drivers/media/video/cafe_ccic*
+CAIF NETWORK LAYER
+M: Sjur Braendeland <sjur.brandeland@stericsson.com>
+L: netdev@vger.kernel.org
+S: Supported
+F: Documentation/networking/caif/
+F: drivers/net/caif/
+F: include/linux/caif/
+F: include/net/caif/
+F: net/caif/
+
CALGARY x86-64 IOMMU
M: Muli Ben-Yehuda <muli@il.ibm.com>
M: "Jon D. Mason" <jdmason@kudzu.us>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4824fb4f401..72c61a3cdbf 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -748,6 +748,9 @@ config ARCH_U8500
select GENERIC_CLOCKEVENTS
select COMMON_CLKDEV
select ARCH_REQUIRE_GPIOLIB
+ select HAVE_CLK
+ select ARCH_HAS_CPUFREQ
+ select NOMADIK_GPIO
help
Support for ST-Ericsson's Ux500 architecture
@@ -1497,6 +1500,18 @@ config ATAGS_PROC
Should the atags used to boot the kernel be exported in an "atags"
file in procfs. Useful with kexec.
+config CRASH_DUMP
+ bool "Build kdump crash kernel (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ Build a kernel suitable for use as kdump capture kernel. This should
+ be set only on dump capture kernels. Note that dump capture kernel
+ must be loaded into different physical address than the primary kernel
+ (e.g set PHYS_OFFSET and related mach/Makefile.boot parameters
+ to match value given in 'crashkernel=size <at> start').
+
+ For more details see Documentation/kdump/kdump.txt
+
endmenu
menu "CPU Power Management"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 91344af75f3..e5bd8a09caa 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -79,6 +79,15 @@ config EARLY_PRINTK
kernel low-level debugging functions. Add earlyprintk to your
kernel parameters to enable this console.
+config PRINTK_LL
+ bool "Use printascii in printk"
+ depends on DEBUG_LL
+ help
+ Say Y here if you want to have printk send its output via the
+ kernel low-level debugging functions. This is useful if you
+ are debugging code that executes before the earlyprintk console
+ is initialized.
+
config DEBUG_ICEDCC
bool "Kernel low-level debugging via EmbeddedICE DCC channel"
depends on DEBUG_LL
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index d986c26ee35..fca831c5aea 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o
obj-$(CONFIG_COMMON_CLKDEV) += clkdev.o
obj-$(CONFIG_FIQ_GLUE) += fiq_glue.o fiq_glue_setup.o
obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger.o
+obj-$(CONFIG_BOOTTIME) += boottime.o
diff --git a/arch/arm/common/boottime.c b/arch/arm/common/boottime.c
new file mode 100644
index 00000000000..73e9e04ed37
--- /dev/null
+++ b/arch/arm/common/boottime.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009-2010
+ *
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Store boot times measured during for example u-boot startup.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/boottime.h>
+#include <linux/string.h>
+#include <asm/setup.h>
+
+static u32 bootloader_idle;
+static u32 bootloader_total;
+
+static int __init boottime_parse_tag(const struct tag *tag)
+{
+ int i;
+ char buff[BOOTTIME_MAX_NAME_LEN];
+
+ bootloader_idle = tag->u.boottime.idle;
+ bootloader_total = tag->u.boottime.total;
+
+ for (i = 0; i < tag->u.boottime.num; i++) {
+ snprintf(buff, BOOTTIME_MAX_NAME_LEN, "%s+0x0/0x0",
+ tag->u.boottime.entry[i].name);
+ buff[BOOTTIME_MAX_NAME_LEN - 1] = '\0';
+ boottime_mark_wtime(buff, tag->u.boottime.entry[i].time);
+ }
+
+ return 0;
+}
+
+__tagtable(ATAG_BOOTTIME, boottime_parse_tag);
+
+int boottime_bootloader_idle(void)
+{
+ if (bootloader_total == 0)
+ return 0;
+
+ return (int) ((bootloader_idle) / (bootloader_total / 100));
+}
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 337741f734a..7dfa9a85bc0 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -108,6 +108,51 @@ static void gic_unmask_irq(unsigned int irq)
spin_unlock(&irq_controller_lock);
}
+static int gic_set_type(unsigned int irq, unsigned int type)
+{
+ void __iomem *base = gic_dist_base(irq);
+ unsigned int gicirq = gic_irq(irq);
+ u32 enablemask = 1 << (gicirq % 32);
+ u32 enableoff = (gicirq / 32) * 4;
+ u32 confmask = 0x2 << ((gicirq % 16) * 2);
+ u32 confoff = (gicirq / 16) * 4;
+ bool enabled = false;
+ u32 val;
+
+ /* Interrupt configuration for SGIs can't be changed */
+ if (gicirq < 16)
+ return -EINVAL;
+
+ if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+ return -EINVAL;
+
+ spin_lock(&irq_controller_lock);
+
+ val = readl(base + GIC_DIST_CONFIG + confoff);
+ if (type == IRQ_TYPE_LEVEL_HIGH)
+ val &= ~confmask;
+ else if (type == IRQ_TYPE_EDGE_RISING)
+ val |= confmask;
+
+ /*
+ * As recommended by the spec, disable the interrupt before changing
+ * the configuration
+ */
+ if (readl(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
+ writel(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
+ enabled = true;
+ }
+
+ writel(val, base + GIC_DIST_CONFIG + confoff);
+
+ if (enabled)
+ writel(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
+
+ spin_unlock(&irq_controller_lock);
+
+ return 0;
+}
+
#ifdef CONFIG_SMP
static int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val)
{
@@ -161,6 +206,7 @@ static struct irq_chip gic_chip = {
.ack = gic_ack_irq,
.mask = gic_mask_irq,
.unmask = gic_unmask_irq,
+ .set_type = gic_set_type,
#ifdef CONFIG_SMP
.set_affinity = gic_set_cpu,
#endif
diff --git a/arch/arm/configs/mop500_USB_HOST_defconfig b/arch/arm/configs/mop500_USB_HOST_defconfig
new file mode 100644
index 00000000000..2512b3f21d0
--- /dev/null
+++ b/arch/arm/configs/mop500_USB_HOST_defconfig
@@ -0,0 +1,1830 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.35.7
+# Sat Oct 23 12:23:57 2010
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=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_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 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_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=18
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# 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
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_BOOTTIME is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_SLOW_WORK=y
+# CONFIG_SLOW_WORK_DEBUG is not set
+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=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+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=y
+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_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX 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_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_DOVE 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_NUC93X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE 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_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+CONFIG_ARCH_U8500=y
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+CONFIG_PLAT_NOMADIK=y
+CONFIG_NOMADIK_GPIO=y
+CONFIG_UX500_SOC_DB8500=y
+CONFIG_MACH_U8500_MOP=y
+# CONFIG_MACH_U8500_PDP is not set
+# CONFIG_MACH_U5500_BB is not set
+# CONFIG_MACH_U8500_SIMULATOR is not set
+# CONFIG_MACH_U5500_SIMULATOR is not set
+CONFIG_KEYLAYOUT_LAYOUT1=y
+# CONFIG_KEYLAYOUT_LAYOUT2 is not set
+CONFIG_U8500_CPUFREQ=y
+CONFIG_U8500_PM=y
+# CONFIG_U8500_PRCMU_TIMER is not set
+# CONFIG_U8500_SUSPEND is not set
+CONFIG_U8500_PRCMU=y
+CONFIG_UX500_CONTEXT=y
+CONFIG_MOP500_SDI=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_UX500_DEBUG_UART=2
+CONFIG_TEE_UX500=y
+CONFIG_GPIO_STM=y
+# CONFIG_U8500_SECURE is not set
+
+#
+# Debug level for STM drivers
+#
+
+#
+# Display selection
+#
+CONFIG_DISPLAY_GENERIC_PRIMARY=y
+CONFIG_DISPLAY_GENERIC_DSI_PRIMARY=y
+# CONFIG_MCDE_DISPLAY_DPI_PRIMARY is not set
+# CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_VSYNC is not set
+# CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATE_180_DEGREES is not set
+# CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC is not set
+# CONFIG_DISPLAY_GENERIC_DSI_SECONDARY is not set
+# CONFIG_DISPLAY_AB8500_TERTIARY is not set
+# CONFIG_DISPLAY_AV8100_TERTIARY is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_CACHE_L2X0=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_720789 is not set
+CONFIG_ARM_GIC=y
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# 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=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SMP=y
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=y
+CONFIG_LOCAL_TIMERS=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# 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=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=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="root=/dev/ram0 init=init rw console=ttyAMA2,115200n8 mem=256M initrd=0x800000,72M"
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP 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=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# 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_SMP=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_NVS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_PM_OPS=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=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 is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+# CONFIG_BRIDGE 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=y
+CONFIG_PHONET_PIPECTRLR=y
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_DRR is not set
+
+#
+# Classification
+#
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+CONFIG_RPS=y
+
+#
+# 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_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+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=y
+# CONFIG_MAC80211_DEBUGFS 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
+# CONFIG_CAIF is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+# CONFIG_STANDALONE is not set
+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 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
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=73728
+# CONFIG_BLK_DEV_XIP 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_AD525X_DPOT is not set
+# CONFIG_AB8500_PWM is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+CONFIG_AB8500_GPADC=y
+CONFIG_HWMEM=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_IWMC3200TOP is not set
+# CONFIG_HSI is not set
+# CONFIG_U8500_HSI_LEGACY is not set
+CONFIG_U8500_HSI_TRANSFER_MODE=0x0
+CONFIG_STM_I2S=y
+CONFIG_STM_MSP_I2S=y
+CONFIG_STM_I2S_TEST_PROTOCOL_DRIVER=y
+CONFIG_U8500_HSI_MODEM_EXTERNAL=y
+# CONFIG_U8500_HSI_MODEM_INTERNAL is not set
+CONFIG_U8500_HSI_MODEM_DIRECTION=0x1
+CONFIG_U8500_SHRM=y
+# CONFIG_SHRM_ED_V1_VERSION is not set
+CONFIG_SHRM_V1_UPDATES_VERSION=y
+# CONFIG_U8500_SHRM_LOOP_BACK is not set
+# CONFIG_U8500_SHRM_MODEM_SILENT_RESET is not set
+CONFIG_STE_AUDIO_IO_DEV=y
+# CONFIG_AB8500_DENC is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# 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 is not set
+# 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=y
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_WLAN=y
+# 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_ATH_COMMON is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_WL12XX is not set
+# CONFIG_ZD1211RW 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=m
+# CONFIG_USB_NET_CDC_EEM is not set
+CONFIG_USB_NET_DM9601=y
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=m
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_ARMLINUX is not set
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_CDC_PHONET is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# 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 is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# 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 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# 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_NOMADIK is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_TC35893_KEYPAD=y
+# CONFIG_TC_KEYPAD_POLL is not set
+CONFIG_TC_KEYPAD_INTR=y
+# 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_BU21013=y
+CONFIG_BU21013_TSC_CNTL1=y
+# CONFIG_BU21013_TSC_CNTL2 is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# 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_TOUCHSCREEN_TPS6507X is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_AMBAKMI is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 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=y
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_SERIAL_AMBA_PL011_CLOCK_CONTROL is not set
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS 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_NOMADIK is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX 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_STUB 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_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_STM_MSP_SPI is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_PL022 is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_PL061 is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 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:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_88PM860X 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_HTC_I2CPLD is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_CG2900 is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_AB5500_CORE is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+CONFIG_ABX500_CORE=y
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_AB8500_CORE=y
+CONFIG_AB8500_I2C_CORE=y
+CONFIG_AB8500_DEBUG=y
+# CONFIG_AB3550_CORE is not set
+# CONFIG_REGULATOR 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 is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=y
+# 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_MCDE=y
+CONFIG_MCDE_DISPLAY_GENERIC_DSI=y
+# CONFIG_MCDE_DISPLAY_DPI is not set
+# CONFIG_MCDE_DISPLAY_AV8100 is not set
+# CONFIG_MCDE_DISPLAY_AB8500_DENC is not set
+# CONFIG_FB_MCDE_DEBUG is not set
+# CONFIG_MCDE_FB_AVOID_REALLOC is not set
+# CONFIG_FB_ARMCLCD is not set
+CONFIG_FB_B2R2=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_TMIO 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 is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_AV8100 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=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+# CONFIG_U8500_ACODEC is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_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_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# U8500 USB support
+#
+CONFIG_U8500_USB_HS_OTG=y
+CONFIG_USB_MUSB_HOST=y
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+# CONFIG_USB_MUSB_OTG is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+# CONFIG_USB_INVENTRA_DMA is not set
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=y
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# 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_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+CONFIG_USB_GADGET_M66592=y
+CONFIG_USB_M66592=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FUNCTIONFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_NOKIA is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_WEBCAM is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ULPI is not set
+CONFIG_NOP_USB_XCEIV=y
+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_ARMMMCI is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SPI is not set
+CONFIG_MMC_U8500=y
+CONFIG_U8500_MMC_DMA=y
+# CONFIG_U8500_MMC_POLL is not set
+# CONFIG_U8500_MMC_INTR is not set
+# CONFIG_LEVELSHIFTER_HREF_V1_PLUS is not set
+CONFIG_U8500_SDIO=y
+# CONFIG_U8500_SDIO_DMA is not set
+CONFIG_U8500_SDIO_POLL=y
+# CONFIG_U8500_SDIO_INTR is not set
+CONFIG_U8500_SDIO_CARD_IRQ=y
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_GPIO is not set
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+# CONFIG_LEDS_LP5521 is not set
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# 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_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
+# 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_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_AB8500=y
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PL030 is not set
+CONFIG_RTC_DRV_PL031=y
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+# CONFIG_AMBA_PL08X is not set
+CONFIG_STE_DMA40=y
+# CONFIG_TIMB_DMA is not set
+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
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+# CONFIG_USB_IP_COMMON is not set
+# CONFIG_W35UND is not set
+# CONFIG_PRISM2_USB is not set
+# CONFIG_ECHO is not set
+# CONFIG_OTUS is not set
+# CONFIG_RT2870 is not set
+# CONFIG_COMEDI is not set
+# CONFIG_ASUS_OLED is not set
+# CONFIG_TRANZPORT is not set
+# CONFIG_POHMELFS is not set
+# CONFIG_VT6656 is not set
+# CONFIG_FB_UDL is not set
+
+#
+# RAR Register Driver
+#
+# CONFIG_IIO is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_FB_SM7XX is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_ADIS16255 is not set
+CONFIG_TEE_SUPPORT=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE 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 is not set
+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=y
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
+CONFIG_CIFS=y
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_DEBUG2=y
+# CONFIG_CIFS_DFS_UPCALL is not set
+# CONFIG_CIFS_EXPERIMENTAL 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=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_BLKDEV_PARTITION=y
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# 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=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+CONFIG_DEBUG_PREEMPT=y
+# 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 is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# 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_LKDTM is not set
+# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# 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_PREEMPT_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_DYNAMIC_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST 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 is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS 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=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_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT 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=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# 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=y
+# 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=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# 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=y
+# 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 is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# 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=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/mop500_defconfig b/arch/arm/configs/mop500_defconfig
new file mode 100644
index 00000000000..cf83d897f4d
--- /dev/null
+++ b/arch/arm/configs/mop500_defconfig
@@ -0,0 +1,2221 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.35.7
+# Sat Oct 23 12:30:11 2010
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=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_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 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_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=18
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# 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
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_BOOTTIME is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+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=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+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=y
+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_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX 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_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_DOVE 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_NUC93X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE 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_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+CONFIG_ARCH_U8500=y
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+CONFIG_PLAT_NOMADIK=y
+CONFIG_NOMADIK_GPIO=y
+CONFIG_UX500_SOC_DB8500=y
+CONFIG_MACH_U8500_MOP=y
+# CONFIG_MACH_U8500_PDP is not set
+# CONFIG_MACH_U5500_BB is not set
+# CONFIG_MACH_U8500_SIMULATOR is not set
+# CONFIG_MACH_U5500_SIMULATOR is not set
+CONFIG_KEYLAYOUT_LAYOUT1=y
+# CONFIG_KEYLAYOUT_LAYOUT2 is not set
+CONFIG_U8500_CPUFREQ=y
+CONFIG_U8500_PM=y
+CONFIG_U8500_PRCMU_TIMER=y
+# CONFIG_U8500_SUSPEND is not set
+CONFIG_U8500_PRCMU=y
+# CONFIG_U8500_REGULATOR_DEBUG is not set
+CONFIG_UX500_CONTEXT=y
+CONFIG_MOP500_SDI=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_UX500_DEBUG_UART=2
+CONFIG_SENSORS1P_MOP=y
+CONFIG_TEE_UX500=y
+CONFIG_GPIO_STM=y
+# CONFIG_U8500_SECURE is not set
+
+#
+# Debug level for STM drivers
+#
+
+#
+# Display selection
+#
+CONFIG_DISPLAY_GENERIC_PRIMARY=y
+CONFIG_DISPLAY_GENERIC_DSI_PRIMARY=y
+# CONFIG_MCDE_DISPLAY_DPI_PRIMARY is not set
+# CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_VSYNC is not set
+# CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATE_180_DEGREES is not set
+# CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC is not set
+# CONFIG_DISPLAY_GENERIC_DSI_SECONDARY is not set
+# CONFIG_DISPLAY_AB8500_TERTIARY is not set
+# CONFIG_DISPLAY_AV8100_TERTIARY is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_CACHE_L2X0=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_720789 is not set
+CONFIG_ARM_GIC=y
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# 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=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SMP=y
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=y
+CONFIG_LOCAL_TIMERS=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# 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=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=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="root=/dev/ram0 init=init rw console=ttyAMA2,115200n8 mem=256M initrd=0x800000,72M"
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP 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=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# 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_SMP=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_NVS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_PM_OPS=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=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 is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+CONFIG_NF_CONNTRACK=y
+# CONFIG_NF_CT_ACCT is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+# CONFIG_NF_CONNTRACK_FTP is not set
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CT_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+# CONFIG_NETFILTER_XT_MARK is not set
+# CONFIG_NETFILTER_XT_CONNMARK is not set
+
+#
+# Xtables targets
+#
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_HL is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+CONFIG_IP_NF_FILTER=m
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_REDIRECT is not set
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+# CONFIG_NF_NAT_FTP is not set
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_TFTP is not set
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+# CONFIG_NF_NAT_SIP is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES 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_L2TP is not set
+# CONFIG_BRIDGE 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=y
+CONFIG_PHONET_PIPECTRLR=y
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_DRR is not set
+
+#
+# Classification
+#
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+CONFIG_RPS=y
+
+#
+# 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=y
+CONFIG_BT_L2CAP=y
+# CONFIG_BT_L2CAP_EXT_FEATURES is not set
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIBTSDIO is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_MRVL is not set
+CONFIG_BT_CG2900=y
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+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=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+CONFIG_RFKILL=y
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFKILL_INPUT=y
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+# CONFIG_STANDALONE is not set
+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 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
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=73728
+# CONFIG_BLK_DEV_XIP 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_AD525X_DPOT is not set
+CONFIG_AB8500_PWM=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+CONFIG_AB8500_GPADC=y
+CONFIG_HWMEM=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_IWMC3200TOP is not set
+# CONFIG_HSI is not set
+# CONFIG_U8500_HSI_LEGACY is not set
+CONFIG_U8500_HSI_TRANSFER_MODE=0x0
+CONFIG_STM_I2S=y
+CONFIG_STM_MSP_I2S=y
+CONFIG_STM_I2S_TEST_PROTOCOL_DRIVER=y
+CONFIG_U8500_HSI_MODEM_EXTERNAL=y
+# CONFIG_U8500_HSI_MODEM_INTERNAL is not set
+CONFIG_U8500_HSI_MODEM_DIRECTION=0x1
+CONFIG_U8500_SHRM=y
+# CONFIG_SHRM_ED_V1_VERSION is not set
+CONFIG_SHRM_V1_UPDATES_VERSION=y
+# CONFIG_U8500_SHRM_LOOP_BACK is not set
+# CONFIG_U8500_SHRM_MODEM_SILENT_RESET is not set
+CONFIG_STE_AUDIO_IO_DEV=y
+# CONFIG_AB8500_DENC is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# 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 is not set
+# 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=y
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=m
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+CONFIG_WLAN=y
+# 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_ATH_COMMON is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_WL12XX is not set
+# CONFIG_ZD1211RW is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=m
+# CONFIG_USB_NET_AX8817X is not set
+CONFIG_USB_NET_CDCETHER=m
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=m
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_ARMLINUX is not set
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_HSO is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_CDC_PHONET is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# 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 is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# 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 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# 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_NOMADIK is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_STMPE=y
+CONFIG_TC35893_KEYPAD=y
+# CONFIG_TC_KEYPAD_POLL is not set
+CONFIG_TC_KEYPAD_INTR=y
+# 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_BU21013=y
+CONFIG_BU21013_TSC_CNTL1=y
+# CONFIG_BU21013_TSC_CNTL2 is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# 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_TOUCHSCREEN_TPS6507X is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_AB8500_PONKEY is not set
+# CONFIG_INPUT_AD714X is not set
+# 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=y
+# CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_STE_FF_VIBRA is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_AMBAKMI is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 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=y
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_SERIAL_AMBA_PL011_CLOCK_CONTROL is not set
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS 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_NOMADIK=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX 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_STUB 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_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_STM_MSP_SPI 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
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_PL061 is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_STMPE=y
+CONFIG_GPIO_TC35892=y
+# CONFIG_GPIO_ADP5588 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:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_AB8500_BM is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+CONFIG_SENSORS_AB8500=y
+# 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_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 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_LM73 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_LSM303DLH=y
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# 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_EMC1403 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_ADS7871 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 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 is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_88PM860X 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_HTC_I2CPLD is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+CONFIG_MFD_STMPE=y
+CONFIG_MFD_TC35892=y
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+CONFIG_MFD_CG2900=y
+CONFIG_MFD_CG2900_CHIP=y
+CONFIG_MFD_STLC2690_CHIP=y
+CONFIG_MFD_CG2900_AUDIO=y
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_AB5500_CORE is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+CONFIG_ABX500_CORE=y
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_AB8500_CORE=y
+CONFIG_AB8500_I2C_CORE=y
+CONFIG_AB8500_DEBUG=y
+# CONFIG_AB3550_CORE is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+# CONFIG_REGULATOR_DUMMY is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+CONFIG_REGULATOR_AB8500=y
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_ALLOW_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+CONFIG_IR_CORE=y
+CONFIG_VIDEO_IR=y
+CONFIG_RC_MAP=y
+CONFIG_IR_NEC_DECODER=y
+CONFIG_IR_RC5_DECODER=y
+CONFIG_IR_RC6_DECODER=y
+CONFIG_IR_JVC_DECODER=y
+CONFIG_IR_SONY_DECODER=y
+# CONFIG_IR_IMON is not set
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=y
+CONFIG_MEDIA_TUNER_TDA8290=y
+CONFIG_MEDIA_TUNER_TDA9887=y
+CONFIG_MEDIA_TUNER_TEA5761=y
+CONFIG_MEDIA_TUNER_TEA5767=y
+CONFIG_MEDIA_TUNER_MT20XX=y
+CONFIG_MEDIA_TUNER_XC2028=y
+CONFIG_MEDIA_TUNER_XC5000=y
+CONFIG_MEDIA_TUNER_MC44S803=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_V4L1=y
+# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_I2C_SI4713 is not set
+# CONFIG_RADIO_SI4713 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_RADIO_SI470X is not set
+# CONFIG_USB_MR800 is not set
+# CONFIG_RADIO_TEA5764 is not set
+# CONFIG_RADIO_SAA7706H is not set
+# CONFIG_RADIO_TEF6862 is not set
+CONFIG_RADIO_CG2900=y
+# CONFIG_DAB 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 is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=y
+# 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_MCDE=y
+CONFIG_MCDE_DISPLAY_GENERIC_DSI=y
+# CONFIG_MCDE_DISPLAY_DPI is not set
+# CONFIG_MCDE_DISPLAY_AV8100 is not set
+# CONFIG_MCDE_DISPLAY_AB8500_DENC is not set
+# CONFIG_FB_MCDE_DEBUG is not set
+# CONFIG_MCDE_FB_AVOID_REALLOC is not set
+# CONFIG_FB_ARMCLCD is not set
+CONFIG_FB_B2R2=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_TMIO 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 is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_AV8100 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=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+# CONFIG_U8500_ACODEC is not set
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+# CONFIG_SND_ARMAACI is not set
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_SOC is not set
+# 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_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_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_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# U8500 USB support
+#
+CONFIG_U8500_USB_HS_OTG=y
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+# CONFIG_USB_INVENTRA_DMA is not set
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=y
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# 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_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FUNCTIONFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_NOKIA is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_WEBCAM is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ULPI is not set
+CONFIG_NOP_USB_XCEIV=y
+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_ARMMMCI is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SPI is not set
+CONFIG_MMC_U8500=y
+CONFIG_U8500_MMC_DMA=y
+# CONFIG_U8500_MMC_POLL is not set
+# CONFIG_U8500_MMC_INTR is not set
+# CONFIG_LEVELSHIFTER_HREF_V1_PLUS is not set
+CONFIG_U8500_SDIO=y
+CONFIG_U8500_SDIO_DMA=y
+# CONFIG_U8500_SDIO_POLL is not set
+# CONFIG_U8500_SDIO_INTR is not set
+CONFIG_U8500_SDIO_CARD_IRQ=y
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_GPIO is not set
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+CONFIG_LEDS_PWM=y
+# CONFIG_LEDS_REGULATOR is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_LP5521=y
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# 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_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
+# 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_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_AB8500=y
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PL030 is not set
+CONFIG_RTC_DRV_PL031=y
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+# CONFIG_AMBA_PL08X is not set
+CONFIG_STE_DMA40=y
+# CONFIG_TIMB_DMA is not set
+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
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+# CONFIG_VIDEO_TM6000 is not set
+# CONFIG_USB_IP_COMMON is not set
+# CONFIG_W35UND is not set
+# CONFIG_PRISM2_USB is not set
+# CONFIG_ECHO is not set
+# CONFIG_OTUS is not set
+# CONFIG_RT2870 is not set
+# CONFIG_COMEDI is not set
+# CONFIG_ASUS_OLED is not set
+# CONFIG_TRANZPORT is not set
+# CONFIG_POHMELFS is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_VT6656 is not set
+# CONFIG_FB_UDL is not set
+
+#
+# RAR Register Driver
+#
+# CONFIG_IIO is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_FB_SM7XX is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_TI_ST is not set
+# CONFIG_ST_BT is not set
+# CONFIG_ADIS16255 is not set
+CONFIG_TEE_SUPPORT=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE 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 is not set
+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=y
+# 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_ECRYPT_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_LOGFS 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 is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_BLKDEV_PARTITION=y
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# 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=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+CONFIG_DEBUG_PREEMPT=y
+# 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 is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# 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_LKDTM is not set
+# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# 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_PREEMPT_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_DYNAMIC_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST 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_EARLY_PRINTK=y
+# CONFIG_PRINTK_LL is not set
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS 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=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_AEAD2=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=m
+CONFIG_CRYPTO_HASH2=m
+CONFIG_CRYPTO_RNG2=m
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=m
+CONFIG_CRYPTO_MANAGER_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_WORKQUEUE=m
+# 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=m
+# 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=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# 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 is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# 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=y
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/mop500_power_defconfig b/arch/arm/configs/mop500_power_defconfig
new file mode 100644
index 00000000000..c83f0e0e31c
--- /dev/null
+++ b/arch/arm/configs/mop500_power_defconfig
@@ -0,0 +1,2255 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.35.7
+# Thu Oct 21 16:24:19 2010
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=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_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 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_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=18
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# 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_ASHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_BOOTTIME=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+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=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+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=y
+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_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX 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_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_DOVE 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_NUC93X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE 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_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+CONFIG_ARCH_U8500=y
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+CONFIG_PLAT_NOMADIK=y
+CONFIG_NOMADIK_GPIO=y
+CONFIG_UX500_SOC_DB8500=y
+CONFIG_MACH_U8500_MOP=y
+# CONFIG_MACH_U8500_PDP is not set
+# CONFIG_MACH_U5500_BB is not set
+# CONFIG_MACH_U8500_SIMULATOR is not set
+# CONFIG_MACH_U5500_SIMULATOR is not set
+CONFIG_KEYLAYOUT_LAYOUT1=y
+# CONFIG_KEYLAYOUT_LAYOUT2 is not set
+CONFIG_U8500_CPUIDLE=y
+CONFIG_U8500_CPUFREQ=y
+CONFIG_U8500_PM=y
+CONFIG_U8500_PRCMU_TIMER=y
+# CONFIG_U8500_SUSPEND is not set
+CONFIG_U8500_PRCMU=y
+# CONFIG_U8500_REGULATOR_DEBUG is not set
+CONFIG_UX500_CONTEXT=y
+CONFIG_MOP500_SDI=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_UX500_DEBUG_UART=2
+CONFIG_SENSORS1P_MOP=y
+CONFIG_MOP500_NUIB=y
+CONFIG_TEE_UX500=y
+CONFIG_GPIO_STM=y
+# CONFIG_U8500_SECURE is not set
+
+#
+# Debug level for STM drivers
+#
+
+#
+# Display selection
+#
+CONFIG_DISPLAY_GENERIC_PRIMARY=y
+CONFIG_DISPLAY_GENERIC_DSI_PRIMARY=y
+# CONFIG_MCDE_DISPLAY_DPI_PRIMARY is not set
+# CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_VSYNC is not set
+# CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATE_180_DEGREES is not set
+# CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC is not set
+# CONFIG_DISPLAY_GENERIC_DSI_SECONDARY is not set
+# CONFIG_DISPLAY_AB8500_TERTIARY is not set
+# CONFIG_DISPLAY_AV8100_TERTIARY is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_CACHE_L2X0=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_720789 is not set
+CONFIG_ARM_GIC=y
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# 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=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SMP=y
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=y
+CONFIG_LOCAL_TIMERS=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# 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=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=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="root=/dev/ram0 init=init rw console=ttyAMA2,115200n8 mem=256M initrd=0x800000,72M"
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+CONFIG_CRASH_DUMP=y
+
+#
+# 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=y
+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=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+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
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# 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_SMP=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_NVS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_PM_OPS=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=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 is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=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 is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+# CONFIG_IPV6_SIT is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_ANDROID_PARANOID_NETWORK is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+CONFIG_NF_CONNTRACK=y
+# CONFIG_NF_CT_ACCT is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+# CONFIG_NF_CONNTRACK_FTP is not set
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CT_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+# CONFIG_NETFILTER_XT_MARK is not set
+# CONFIG_NETFILTER_XT_CONNMARK is not set
+
+#
+# Xtables targets
+#
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_HL is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+CONFIG_IP_NF_FILTER=m
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_REDIRECT is not set
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+# CONFIG_NF_NAT_FTP is not set
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_TFTP is not set
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+# CONFIG_NF_NAT_SIP is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_NF_CONNTRACK_IPV6 is not set
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES 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_L2TP is not set
+# CONFIG_BRIDGE 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=y
+CONFIG_PHONET_PIPECTRLR=y
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_DRR is not set
+
+#
+# Classification
+#
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+CONFIG_RPS=y
+
+#
+# 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=y
+CONFIG_BT_L2CAP=y
+# CONFIG_BT_L2CAP_EXT_FEATURES is not set
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIBTSDIO is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_MRVL is not set
+CONFIG_BT_CG2900=y
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+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=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+CONFIG_RFKILL=y
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFKILL_INPUT=y
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+# CONFIG_STANDALONE is not set
+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 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
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=73728
+# CONFIG_BLK_DEV_XIP 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_AD525X_DPOT is not set
+CONFIG_AB8500_PWM=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+CONFIG_SENSORS_BH1780=y
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+CONFIG_AB8500_GPADC=y
+CONFIG_HWMEM=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_IWMC3200TOP is not set
+# CONFIG_HSI is not set
+# CONFIG_U8500_HSI_LEGACY is not set
+CONFIG_U8500_HSI_TRANSFER_MODE=0x0
+CONFIG_STM_I2S=y
+CONFIG_STM_MSP_I2S=y
+CONFIG_STM_I2S_TEST_PROTOCOL_DRIVER=y
+CONFIG_U8500_HSI_MODEM_EXTERNAL=y
+# CONFIG_U8500_HSI_MODEM_INTERNAL is not set
+CONFIG_U8500_HSI_MODEM_DIRECTION=0x1
+CONFIG_U8500_SHRM=y
+# CONFIG_SHRM_ED_V1_VERSION is not set
+CONFIG_SHRM_V1_UPDATES_VERSION=y
+# CONFIG_U8500_SHRM_LOOP_BACK is not set
+# CONFIG_U8500_SHRM_MODEM_SILENT_RESET is not set
+CONFIG_STE_AUDIO_IO_DEV=y
+# CONFIG_AB8500_DENC is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# 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 is not set
+# 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=y
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=m
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+CONFIG_WLAN=y
+# 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_ATH_COMMON is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_WL12XX is not set
+# CONFIG_ZD1211RW is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=m
+# CONFIG_USB_NET_AX8817X is not set
+CONFIG_USB_NET_CDCETHER=m
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=m
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_ARMLINUX is not set
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_HSO is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_CDC_PHONET is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# 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 is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+# CONFIG_INPUT_KEYRESET is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# 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_NOMADIK is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_STMPE=y
+CONFIG_TC35893_KEYPAD=y
+# CONFIG_TC_KEYPAD_POLL is not set
+CONFIG_TC_KEYPAD_INTR=y
+# 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_BU21013=y
+CONFIG_BU21013_TSC_CNTL1=y
+# CONFIG_BU21013_TSC_CNTL2 is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# 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_TOUCHSCREEN_TPS6507X is not set
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AB8500_PONKEY=y
+# CONFIG_INPUT_AD714X is not set
+# 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=y
+# CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_STE_FF_VIBRA is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_AMBAKMI is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 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=y
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_SERIAL_AMBA_PL011_CLOCK_CONTROL is not set
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS 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_NOMADIK=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX 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_STUB 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_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_STM_MSP_SPI 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
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_PL061 is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_STMPE=y
+CONFIG_GPIO_TC35892=y
+# CONFIG_GPIO_ADP5588 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:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_AB8500_BM is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+CONFIG_SENSORS_AB8500=y
+# 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_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 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_LM73 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_LSM303DLH=y
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# 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_EMC1403 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_ADS7871 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 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 is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_88PM860X 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_HTC_I2CPLD is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+CONFIG_MFD_STMPE=y
+CONFIG_MFD_TC35892=y
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+CONFIG_MFD_CG2900=y
+CONFIG_MFD_CG2900_CHIP=y
+CONFIG_MFD_STLC2690_CHIP=y
+CONFIG_MFD_CG2900_AUDIO=y
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_AB5500_CORE is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+CONFIG_ABX500_CORE=y
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_AB8500_CORE=y
+CONFIG_AB8500_I2C_CORE=y
+CONFIG_AB8500_DEBUG=y
+# CONFIG_AB3550_CORE is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+# CONFIG_REGULATOR_DUMMY is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+CONFIG_REGULATOR_AB8500=y
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_ALLOW_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+CONFIG_IR_CORE=y
+CONFIG_VIDEO_IR=y
+CONFIG_RC_MAP=y
+CONFIG_IR_NEC_DECODER=y
+CONFIG_IR_RC5_DECODER=y
+CONFIG_IR_RC6_DECODER=y
+CONFIG_IR_JVC_DECODER=y
+CONFIG_IR_SONY_DECODER=y
+# CONFIG_IR_IMON is not set
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=y
+CONFIG_MEDIA_TUNER_TDA8290=y
+CONFIG_MEDIA_TUNER_TDA9887=y
+CONFIG_MEDIA_TUNER_TEA5761=y
+CONFIG_MEDIA_TUNER_TEA5767=y
+CONFIG_MEDIA_TUNER_MT20XX=y
+CONFIG_MEDIA_TUNER_XC2028=y
+CONFIG_MEDIA_TUNER_XC5000=y
+CONFIG_MEDIA_TUNER_MC44S803=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_V4L1=y
+# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_I2C_SI4713 is not set
+# CONFIG_RADIO_SI4713 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_RADIO_SI470X is not set
+# CONFIG_USB_MR800 is not set
+# CONFIG_RADIO_TEA5764 is not set
+# CONFIG_RADIO_SAA7706H is not set
+# CONFIG_RADIO_TEF6862 is not set
+CONFIG_RADIO_CG2900=y
+# CONFIG_DAB 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 is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=y
+# 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_MCDE=y
+CONFIG_MCDE_DISPLAY_GENERIC_DSI=y
+# CONFIG_MCDE_DISPLAY_DPI is not set
+# CONFIG_MCDE_DISPLAY_AV8100 is not set
+# CONFIG_MCDE_DISPLAY_AB8500_DENC is not set
+# CONFIG_FB_MCDE_DEBUG is not set
+# CONFIG_MCDE_FB_AVOID_REALLOC is not set
+# CONFIG_FB_ARMCLCD is not set
+CONFIG_FB_B2R2=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_TMIO 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 is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_AV8100 is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+# CONFIG_U8500_ACODEC is not set
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+# CONFIG_SND_ARMAACI is not set
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_SOC is not set
+# 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_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_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_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# U8500 USB support
+#
+CONFIG_U8500_USB_HS_OTG=y
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+# CONFIG_USB_INVENTRA_DMA is not set
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=y
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# 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_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FUNCTIONFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_NOKIA is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_WEBCAM is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ULPI is not set
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+# CONFIG_MMC_EMBEDDED_SDIO is not set
+CONFIG_MMC_PARANOID_SD_INIT=y
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_ARMMMCI is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SPI is not set
+CONFIG_MMC_U8500=y
+CONFIG_U8500_MMC_DMA=y
+# CONFIG_U8500_MMC_POLL is not set
+# CONFIG_U8500_MMC_INTR is not set
+# CONFIG_LEVELSHIFTER_HREF_V1_PLUS is not set
+CONFIG_U8500_SDIO=y
+CONFIG_U8500_SDIO_DMA=y
+# CONFIG_U8500_SDIO_POLL is not set
+# CONFIG_U8500_SDIO_INTR is not set
+CONFIG_U8500_SDIO_CARD_IRQ=y
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_GPIO is not set
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+CONFIG_LEDS_PWM=y
+# CONFIG_LEDS_REGULATOR is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_LP5521=y
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+CONFIG_SWITCH=y
+# CONFIG_SWITCH_GPIO is not set
+# 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_INTF_ALARM=y
+CONFIG_RTC_INTF_ALARM_DEV=y
+# 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_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
+# 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_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_AB8500=y
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PL030 is not set
+CONFIG_RTC_DRV_PL031=y
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+# CONFIG_AMBA_PL08X is not set
+CONFIG_STE_DMA40=y
+# CONFIG_TIMB_DMA is not set
+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
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+# CONFIG_VIDEO_TM6000 is not set
+# CONFIG_USB_IP_COMMON is not set
+# CONFIG_W35UND is not set
+# CONFIG_PRISM2_USB is not set
+# CONFIG_ECHO is not set
+# CONFIG_OTUS is not set
+# CONFIG_RT2870 is not set
+# CONFIG_COMEDI is not set
+# CONFIG_ASUS_OLED is not set
+# CONFIG_TRANZPORT is not set
+# CONFIG_POHMELFS is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_VT6656 is not set
+# CONFIG_FB_UDL is not set
+
+#
+# RAR Register Driver
+#
+# CONFIG_IIO is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_FB_SM7XX is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_TI_ST is not set
+# CONFIG_ST_BT is not set
+# CONFIG_ADIS16255 is not set
+CONFIG_TEE_SUPPORT=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE 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 is not set
+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_VMCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# 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_ECRYPT_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_LOGFS 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 is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_BLKDEV_PARTITION=y
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# 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=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+CONFIG_DEBUG_PREEMPT=y
+# 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 is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# 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_LKDTM is not set
+# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# 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_PREEMPT_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_DYNAMIC_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST 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 is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS 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=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_AEAD2=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=m
+CONFIG_CRYPTO_HASH2=m
+CONFIG_CRYPTO_RNG2=m
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=m
+CONFIG_CRYPTO_MANAGER_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_WORKQUEUE=m
+# 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=m
+# 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=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# 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 is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# 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=y
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/realview-smp_defconfig b/arch/arm/configs/realview-smp_defconfig
index 9312ef9f9bf..5ca7a61f7c0 100644
--- a/arch/arm/configs/realview-smp_defconfig
+++ b/arch/arm/configs/realview-smp_defconfig
@@ -39,6 +39,7 @@ CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_ARM_INTEGRATOR=y
+CONFIG_ARM_CHARLCD=y
CONFIG_NETDEVICES=y
CONFIG_SMSC_PHY=y
CONFIG_NET_ETHERNET=y
@@ -52,10 +53,13 @@ CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=16
# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_VERSATILE=y
+CONFIG_SPI=y
+CONFIG_GPIOLIB=y
# CONFIG_HWMON is not set
CONFIG_FB=y
CONFIG_FB_ARMCLCD=y
-# CONFIG_VGA_CONSOLE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
@@ -70,7 +74,13 @@ CONFIG_SND_ARMAACI=y
# CONFIG_USB_SUPPORT is not set
CONFIG_MMC=y
CONFIG_MMC_ARMMMCI=y
-CONFIG_INOTIFY=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_PL031=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_CRAMFS=y
@@ -80,6 +90,7 @@ CONFIG_ROOT_NFS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/arm/configs/realview_defconfig b/arch/arm/configs/realview_defconfig
index fb75192ee7e..fcaa6032805 100644
--- a/arch/arm/configs/realview_defconfig
+++ b/arch/arm/configs/realview_defconfig
@@ -38,6 +38,7 @@ CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_ARM_INTEGRATOR=y
+CONFIG_ARM_CHARLCD=y
CONFIG_NETDEVICES=y
CONFIG_SMSC_PHY=y
CONFIG_NET_ETHERNET=y
@@ -51,10 +52,13 @@ CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=16
# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_VERSATILE=y
+CONFIG_SPI=y
+CONFIG_GPIOLIB=y
# CONFIG_HWMON is not set
CONFIG_FB=y
CONFIG_FB_ARMCLCD=y
-# CONFIG_VGA_CONSOLE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
@@ -69,7 +73,13 @@ CONFIG_SND_ARMAACI=y
# CONFIG_USB_SUPPORT is not set
CONFIG_MMC=y
CONFIG_MMC_ARMMMCI=y
-CONFIG_INOTIFY=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_PL031=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_CRAMFS=y
@@ -79,6 +89,7 @@ CONFIG_ROOT_NFS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/arm/configs/sim5500_defconfig b/arch/arm/configs/sim5500_defconfig
new file mode 100644
index 00000000000..4dfebdebdc4
--- /dev/null
+++ b/arch/arm/configs/sim5500_defconfig
@@ -0,0 +1,1347 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.35.7
+# Sat Oct 23 12:51:21 2010
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=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_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 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_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# 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
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_BOOTTIME is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+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=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+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=y
+# CONFIG_FREEZER is not set
+
+#
+# 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_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX 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_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_DOVE 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_NUC93X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE 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_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+CONFIG_ARCH_U8500=y
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+CONFIG_PLAT_NOMADIK=y
+CONFIG_NOMADIK_GPIO=y
+CONFIG_UX500_SOC_DB5500=y
+# CONFIG_MACH_U8500_MOP is not set
+# CONFIG_MACH_U8500_PDP is not set
+# CONFIG_MACH_U5500_BB is not set
+# CONFIG_MACH_U8500_SIMULATOR is not set
+CONFIG_MACH_U5500_SIMULATOR=y
+CONFIG_KEYLAYOUT_LAYOUT1=y
+# CONFIG_KEYLAYOUT_LAYOUT2 is not set
+# CONFIG_UX500_CONTEXT is not set
+CONFIG_U5500_PWM=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_UX500_DEBUG_UART=0
+CONFIG_U5500_MODEM_IRQ=y
+CONFIG_U5500_MBOX=y
+CONFIG_TEE_SVP=y
+CONFIG_GPIO_STM=y
+# CONFIG_U8500_SECURE is not set
+
+#
+# Debug level for STM drivers
+#
+
+#
+# Display selection
+#
+CONFIG_U5500_MLOADER_HELPER=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_CACHE_L2X0=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_720789 is not set
+CONFIG_ARM_GIC=y
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# 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_SMP=y
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=y
+CONFIG_LOCAL_TIMERS=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# 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=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=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="cachepolicy=writealloc root=/dev/ram0 init=init rw console=ttyAMA0,115200n8 mem=24MB@0 mem=208M@48M initrd=0x3000000,60M earlyprintk memmap=0x01800000$0x01800000 mloader_helper.shm_total_size=0x00030000"
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# 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 is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=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 is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+# CONFIG_BRIDGE 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
+CONFIG_RPS=y
+
+#
+# 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_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+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=y
+# CONFIG_MAC80211_DEBUGFS 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
+# CONFIG_CAIF is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+# CONFIG_STANDALONE is not set
+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 is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=73728
+# CONFIG_BLK_DEV_XIP 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_AD525X_DPOT is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_HWMEM is not set
+# 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_HSI is not set
+# CONFIG_U8500_HSI_LEGACY is not set
+CONFIG_U8500_HSI_TRANSFER_MODE=0x0
+CONFIG_STM_I2S=y
+CONFIG_STM_MSP_I2S=y
+CONFIG_STM_I2S_TEST_PROTOCOL_DRIVER=y
+CONFIG_U8500_HSI_MODEM_EXTERNAL=y
+# CONFIG_U8500_HSI_MODEM_INTERNAL is not set
+CONFIG_U8500_HSI_MODEM_DIRECTION=0x1
+# CONFIG_U8500_SHRM is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# 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 is not set
+# 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 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_FF_MEMLESS=m
+CONFIG_INPUT_POLLDEV=m
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=y
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_DB5500 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# 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_NOMADIK is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_TC35893_KEYPAD 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_BU21013=y
+CONFIG_BU21013_TSC_CNTL1=y
+# CONFIG_BU21013_TSC_CNTL2 is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# 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_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_TOUCHSCREEN_TPS6507X is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_AMBAKMI is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_SERIAL_AMBA_PL011_CLOCK_CONTROL is not set
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS 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_NOMADIK=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB 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_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_STM_MSP_SPI is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_PL022 is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_PL061 is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 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:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_88PM860X 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_HTC_I2CPLD is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_CG2900 is not set
+# CONFIG_MFD_TC6393XB is not set
+CONFIG_AB5500_CORE=y
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+CONFIG_ABX500_CORE=y
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_AB8500_CORE is not set
+# CONFIG_AB3550_CORE is not set
+# CONFIG_REGULATOR 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 is not set
+# CONFIG_FB_B2R2 is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_AV8100 is not set
+# CONFIG_SOUND is not set
+# CONFIG_U8500_ACODEC is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC 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 is not set
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+# CONFIG_LEDS_LP5521 is not set
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# 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 is not set
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+# CONFIG_AMBA_PL08X is not set
+CONFIG_STE_DMA40=y
+# CONFIG_TIMB_DMA is not set
+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
+# CONFIG_STAGING is not set
+CONFIG_TEE_SUPPORT=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# 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_ECRYPT_FS is not set
+CONFIG_HFS_FS=m
+# CONFIG_HFSPLUS_FS is not set
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
+CONFIG_CRAMFS=m
+# CONFIG_SQUASHFS is not set
+CONFIG_VXFS_FS=m
+CONFIG_MINIX_FS=m
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+CONFIG_ROMFS_FS=m
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_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=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_BLKDEV_PARTITION=y
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# 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=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+CONFIG_DEBUG_PREEMPT=y
+# 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 is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# 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_LKDTM is not set
+# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# 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_PREEMPT_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_DYNAMIC_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST 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_EARLY_PRINTK=y
+# CONFIG_PRINTK_LL is not set
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS 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=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_AEAD2=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=m
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_HASH2=m
+CONFIG_CRYPTO_RNG2=m
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=m
+CONFIG_CRYPTO_MANAGER_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_WORKQUEUE=m
+# 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=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+# 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=m
+# 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=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# 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 is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# 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 is not set
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/sim8500_defconfig b/arch/arm/configs/sim8500_defconfig
new file mode 100644
index 00000000000..cc4fb48e107
--- /dev/null
+++ b/arch/arm/configs/sim8500_defconfig
@@ -0,0 +1,1326 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.35.7
+# Sat Oct 23 12:42:29 2010
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=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_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 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_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# 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
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_BOOTTIME is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+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=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+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=y
+# CONFIG_FREEZER is not set
+
+#
+# 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_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX 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_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_DOVE 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_NUC93X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE 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_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+CONFIG_ARCH_U8500=y
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+CONFIG_PLAT_NOMADIK=y
+CONFIG_NOMADIK_GPIO=y
+CONFIG_UX500_SOC_DB8500=y
+CONFIG_MACH_SVP8500V1=y
+CONFIG_MACH_SVP8500V2=y
+# CONFIG_MACH_U8500_MOP is not set
+# CONFIG_MACH_U8500_PDP is not set
+# CONFIG_MACH_U5500_BB is not set
+CONFIG_MACH_U8500_SIMULATOR=y
+# CONFIG_MACH_U5500_SIMULATOR is not set
+CONFIG_KEYLAYOUT_LAYOUT1=y
+# CONFIG_KEYLAYOUT_LAYOUT2 is not set
+# CONFIG_U8500_PRCMU_TIMER is not set
+# CONFIG_UX500_CONTEXT is not set
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_UX500_DEBUG_UART=2
+CONFIG_TEE_SVP=y
+CONFIG_GPIO_STM=y
+# CONFIG_U8500_SECURE is not set
+
+#
+# Debug level for STM drivers
+#
+
+#
+# Display selection
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_CACHE_L2X0=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_720789 is not set
+CONFIG_ARM_GIC=y
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# 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_SMP=y
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=y
+CONFIG_LOCAL_TIMERS=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# 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=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=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="cachepolicy=writealloc root=/dev/ram0 init=init rw console=ttyAMA2,115200n8 mem=256M initrd=0x800000,60M earlyprintk"
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# 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 is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=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 is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+# CONFIG_BRIDGE 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
+CONFIG_RPS=y
+
+#
+# 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_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+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=y
+# CONFIG_MAC80211_DEBUGFS 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
+# CONFIG_CAIF is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+# CONFIG_STANDALONE is not set
+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 is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=73728
+# CONFIG_BLK_DEV_XIP 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_AD525X_DPOT is not set
+# CONFIG_AB8500_PWM is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+CONFIG_AB8500_GPADC=y
+# CONFIG_HWMEM is not set
+# 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_HSI is not set
+# CONFIG_U8500_HSI_LEGACY is not set
+CONFIG_U8500_HSI_TRANSFER_MODE=0x0
+CONFIG_STM_I2S=y
+CONFIG_STM_MSP_I2S=y
+CONFIG_STM_I2S_TEST_PROTOCOL_DRIVER=y
+CONFIG_U8500_HSI_MODEM_EXTERNAL=y
+# CONFIG_U8500_HSI_MODEM_INTERNAL is not set
+CONFIG_U8500_HSI_MODEM_DIRECTION=0x1
+# CONFIG_U8500_SHRM is not set
+CONFIG_STE_AUDIO_IO_DEV=y
+# CONFIG_AB8500_DENC is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# 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 is not set
+# 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 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_FF_MEMLESS=m
+CONFIG_INPUT_POLLDEV=m
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=y
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_NOMADIK is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_TC35893_KEYPAD=y
+# CONFIG_TC_KEYPAD_POLL is not set
+CONFIG_TC_KEYPAD_INTR=y
+# 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_BU21013=y
+CONFIG_BU21013_TSC_CNTL1=y
+# CONFIG_BU21013_TSC_CNTL2 is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# 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_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_TOUCHSCREEN_TPS6507X is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_AMBAKMI is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_SERIAL_AMBA_PL011_CLOCK_CONTROL is not set
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS 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_NOMADIK is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB 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_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_STM_MSP_SPI is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_PL022 is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_PL061 is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 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:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_88PM860X 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_HTC_I2CPLD is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_CG2900 is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_AB5500_CORE is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+CONFIG_ABX500_CORE=y
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_AB8500_CORE=y
+CONFIG_AB8500_I2C_CORE=y
+CONFIG_AB8500_DEBUG=y
+# CONFIG_AB3550_CORE is not set
+# CONFIG_REGULATOR 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 is not set
+# CONFIG_FB_B2R2 is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_AV8100 is not set
+# CONFIG_SOUND is not set
+# CONFIG_U8500_ACODEC is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+# CONFIG_LEDS_CLASS is not set
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+# CONFIG_AMBA_PL08X is not set
+CONFIG_STE_DMA40=y
+# CONFIG_TIMB_DMA is not set
+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
+# CONFIG_STAGING is not set
+CONFIG_TEE_SUPPORT=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# 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_ECRYPT_FS is not set
+CONFIG_HFS_FS=m
+# CONFIG_HFSPLUS_FS is not set
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
+CONFIG_CRAMFS=m
+# CONFIG_SQUASHFS is not set
+CONFIG_VXFS_FS=m
+CONFIG_MINIX_FS=m
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+CONFIG_ROMFS_FS=m
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_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=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_BLKDEV_PARTITION=y
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# 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=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+CONFIG_DEBUG_PREEMPT=y
+# 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 is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# 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_LKDTM is not set
+# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# 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_PREEMPT_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_DYNAMIC_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST 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_EARLY_PRINTK=y
+# CONFIG_PRINTK_LL is not set
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS 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=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_AEAD2=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=m
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_HASH2=m
+CONFIG_CRYPTO_RNG2=m
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=m
+CONFIG_CRYPTO_MANAGER_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_WORKQUEUE=m
+# 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=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+# 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=m
+# 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=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# 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 is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# 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 is not set
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=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 46e5e074726..c1c252cdca6 100644
--- a/arch/arm/configs/u300_defconfig
+++ b/arch/arm/configs/u300_defconfig
@@ -28,26 +28,9 @@ CONFIG_CPU_IDLE=y
CONFIG_FPE_NWFPE=y
CONFIG_PM=y
# CONFIG_SUSPEND is not set
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MISC_DEVICES is not set
# CONFIG_INPUT_MOUSEDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_KEYBOARD_ATKBD is not set
@@ -58,7 +41,6 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=16
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
-CONFIG_POWER_SUPPLY=y
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
CONFIG_REGULATOR=y
@@ -66,24 +48,10 @@ CONFIG_FB=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_LCD_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_SOUND=y
-CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
-# CONFIG_SND_VERBOSE_PROCFS is not set
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-# CONFIG_SND_SPI is not set
-CONFIG_SND_SOC=y
# CONFIG_HID_SUPPORT is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_MMC=y
-CONFIG_MMC_DEBUG=y
CONFIG_MMC_ARMMMCI=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_BACKLIGHT=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_HCTOSYS is not set
CONFIG_RTC_DRV_COH901331=y
@@ -93,12 +61,11 @@ CONFIG_COH901318=y
CONFIG_FUSE_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
-# CONFIG_DETECT_SOFTLOCKUP is not set
# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
diff --git a/arch/arm/configs/u5500_defconfig b/arch/arm/configs/u5500_defconfig
new file mode 100644
index 00000000000..603b6130496
--- /dev/null
+++ b/arch/arm/configs/u5500_defconfig
@@ -0,0 +1,1384 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.35.7
+# Sat Oct 23 12:59:09 2010
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=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_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 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_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# 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
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_BOOTTIME is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+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=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+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=y
+# CONFIG_FREEZER is not set
+
+#
+# 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_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX 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_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_DOVE 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_NUC93X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE 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_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+CONFIG_ARCH_U8500=y
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+CONFIG_PLAT_NOMADIK=y
+CONFIG_NOMADIK_GPIO=y
+CONFIG_UX500_SOC_DB5500=y
+# CONFIG_MACH_U8500_MOP is not set
+# CONFIG_MACH_U8500_PDP is not set
+CONFIG_MACH_U5500_BB=y
+# CONFIG_MACH_U8500_SIMULATOR is not set
+# CONFIG_MACH_U5500_SIMULATOR is not set
+CONFIG_KEYLAYOUT_LAYOUT1=y
+# CONFIG_KEYLAYOUT_LAYOUT2 is not set
+# CONFIG_U5500_PRCMU is not set
+# CONFIG_UX500_CONTEXT is not set
+# CONFIG_U5500_PWM is not set
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_UX500_DEBUG_UART=0
+CONFIG_U5500_MODEM_IRQ=y
+CONFIG_U5500_MBOX=y
+# CONFIG_GPIO_STM is not set
+# CONFIG_U8500_SECURE is not set
+
+#
+# Debug level for STM drivers
+#
+
+#
+# Display selection
+#
+CONFIG_U5500_MLOADER_HELPER=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_CACHE_L2X0=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_720789 is not set
+CONFIG_ARM_GIC=y
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# 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_SMP=y
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=y
+CONFIG_LOCAL_TIMERS=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# 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=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=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="cachepolicy=writealloc root=/dev/ram0 init=init rw console=ttyAMA0,115200n8 mem=24MB@0 mem=208M@48M initrd=0x3000000,60M earlyprintk memmap=0x01800000$0x01800000 mloader_helper.shm_total_size=0x00030000"
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# 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 is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=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 is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+# CONFIG_BRIDGE 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
+CONFIG_RPS=y
+
+#
+# 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_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+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=y
+# CONFIG_MAC80211_DEBUGFS 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
+CONFIG_CAIF=y
+# CONFIG_CAIF_DEBUG is not set
+CONFIG_CAIF_NETDEV=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+# CONFIG_STANDALONE is not set
+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 is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=73728
+# CONFIG_BLK_DEV_XIP 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_AD525X_DPOT is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_HWMEM is not set
+# 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_IWMC3200TOP is not set
+# CONFIG_HSI is not set
+# CONFIG_U8500_HSI_LEGACY is not set
+CONFIG_U8500_HSI_TRANSFER_MODE=0x0
+CONFIG_STM_I2S=y
+CONFIG_STM_MSP_I2S=y
+# CONFIG_STM_I2S_TEST_PROTOCOL_DRIVER is not set
+CONFIG_U8500_HSI_MODEM_EXTERNAL=y
+# CONFIG_U8500_HSI_MODEM_INTERNAL is not set
+CONFIG_U8500_HSI_MODEM_DIRECTION=0x1
+# CONFIG_U8500_SHRM is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# 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 is not set
+# 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_NET_ETHERNET is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_ATH_COMMON is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_WL12XX is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_CAIF_TTY is not set
+# CONFIG_CAIF_SPI_SLAVE 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=m
+CONFIG_INPUT_POLLDEV=m
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=y
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_DB5500 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_NOMADIK is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_TC35893_KEYPAD 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_BU21013=y
+CONFIG_BU21013_TSC_CNTL1=y
+# CONFIG_BU21013_TSC_CNTL2 is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# 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_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_TOUCHSCREEN_TPS6507X is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_AMBAKMI is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_SERIAL_AMBA_PL011_CLOCK_CONTROL is not set
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS 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_NOMADIK=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB 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_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_STM_MSP_SPI is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_PL022 is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_PL061 is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 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:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_88PM860X 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_HTC_I2CPLD is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_CG2900 is not set
+# CONFIG_MFD_TC6393XB is not set
+CONFIG_AB5500_CORE=y
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+CONFIG_ABX500_CORE=y
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_AB8500_CORE is not set
+# CONFIG_AB3550_CORE is not set
+# CONFIG_REGULATOR 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 is not set
+# CONFIG_FB_B2R2 is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_AV8100 is not set
+# CONFIG_SOUND is not set
+# CONFIG_U8500_ACODEC is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT 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_ARMMMCI is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SPI is not set
+CONFIG_MMC_U8500=y
+# CONFIG_U8500_MMC_DMA is not set
+CONFIG_U8500_MMC_POLL=y
+# CONFIG_U8500_MMC_INTR is not set
+# CONFIG_LEVELSHIFTER_HREF_V1_PLUS is not set
+# CONFIG_U8500_SDIO is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+# CONFIG_LEDS_CLASS is not set
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+# CONFIG_AMBA_PL08X is not set
+CONFIG_STE_DMA40=y
+# CONFIG_TIMB_DMA is not set
+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
+# CONFIG_STAGING is not set
+CONFIG_TEE_SUPPORT=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# 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_ECRYPT_FS is not set
+CONFIG_HFS_FS=m
+# CONFIG_HFSPLUS_FS is not set
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
+CONFIG_CRAMFS=m
+# CONFIG_SQUASHFS is not set
+CONFIG_VXFS_FS=m
+CONFIG_MINIX_FS=m
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+CONFIG_ROMFS_FS=m
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_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=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_BLKDEV_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# 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=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+CONFIG_DEBUG_PREEMPT=y
+# 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 is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# 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_LKDTM is not set
+# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# 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_PREEMPT_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_DYNAMIC_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST 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_EARLY_PRINTK=y
+# CONFIG_PRINTK_LL is not set
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS 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=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_AEAD2=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=m
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_HASH2=m
+CONFIG_CRYPTO_RNG2=m
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=m
+CONFIG_CRYPTO_MANAGER_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_WORKQUEUE=m
+# 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=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+# 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=m
+# 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=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# 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 is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# 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=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index 51662feb9f1..32fe48cf199 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -94,8 +94,8 @@ struct elf32_hdr;
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
-extern int elf_check_arch(const struct elf32_hdr *);
-#define elf_check_arch elf_check_arch
+extern int arm_elf_check_arch(const struct elf32_hdr *);
+#define elf_check_arch(x) arm_elf_check_arch((const struct elf32_hdr *)(x))
extern int arm_elf_read_implies_exec(const struct elf32_hdr *, int);
#define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(&(ex), stk)
diff --git a/arch/arm/include/asm/hardware/pl080.h b/arch/arm/include/asm/hardware/pl080.h
index 6a6c66be7f6..f35b86e68dd 100644
--- a/arch/arm/include/asm/hardware/pl080.h
+++ b/arch/arm/include/asm/hardware/pl080.h
@@ -43,7 +43,7 @@
/* Per channel configuration registers */
-#define PL008_Cx_STRIDE (0x20)
+#define PL080_Cx_STRIDE (0x20)
#define PL080_Cx_BASE(x) ((0x100 + (x * 0x20)))
#define PL080_Cx_SRC_ADDR(x) ((0x100 + (x * 0x20)))
#define PL080_Cx_DST_ADDR(x) ((0x104 + (x * 0x20)))
@@ -68,6 +68,8 @@
#define PL080_CONTROL_TC_IRQ_EN (1 << 31)
#define PL080_CONTROL_PROT_MASK (0x7 << 28)
#define PL080_CONTROL_PROT_SHIFT (28)
+#define PL080_CONTROL_PROT_CACHE (1 << 30)
+#define PL080_CONTROL_PROT_BUFF (1 << 29)
#define PL080_CONTROL_PROT_SYS (1 << 28)
#define PL080_CONTROL_DST_INCR (1 << 27)
#define PL080_CONTROL_SRC_INCR (1 << 26)
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 1261b1f928d..5fa8e75ef93 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -63,6 +63,12 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
#define MT_DEVICE_CACHED 2
#define MT_DEVICE_WC 3
/*
+ * NOTE : U8500 v1.0/ED cut specific hack.
+ * look at the commit message for more details
+ */
+#define MT_BACKUP_RAM 4
+
+/*
* types 4 onwards can be found in asm/mach/map.h and are undefined
* for ioremap
*/
diff --git a/arch/arm/include/asm/kexec.h b/arch/arm/include/asm/kexec.h
index df15a0dc228..8df7e5f2feb 100644
--- a/arch/arm/include/asm/kexec.h
+++ b/arch/arm/include/asm/kexec.h
@@ -19,10 +19,26 @@
#ifndef __ASSEMBLY__
-struct kimage;
-/* Provide a dummy definition to avoid build failures. */
+/*
+ * crash_setup_regs() - save registers for the panic kernel
+ * @newregs: registers are saved here
+ * @oldregs: registers to be saved (may be %NULL)
+ *
+ * Function copies machine registers from @oldregs to @newregs. If @oldregs is
+ * %NULL then current registers are stored there.
+ */
static inline void crash_setup_regs(struct pt_regs *newregs,
- struct pt_regs *oldregs) { }
+ struct pt_regs *oldregs)
+{
+ if (oldregs) {
+ memcpy(newregs, oldregs, sizeof(*newregs));
+ } else {
+ __asm__ __volatile__ ("stmia %0, {r0 - r15}"
+ : : "r" (&newregs->ARM_r0));
+ __asm__ __volatile__ ("mrs %0, cpsr"
+ : "=r" (newregs->ARM_cpsr));
+ }
+}
#endif /* __ASSEMBLY__ */
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index 742c2aaeb02..d2fedb5aeb1 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -27,6 +27,8 @@ struct map_desc {
#define MT_MEMORY 9
#define MT_ROM 10
#define MT_MEMORY_NONCACHED 11
+#define MT_MEMORY_DTCM 12
+#define MT_MEMORY_ITCM 13
#ifdef CONFIG_MMU
extern void iotable_init(struct map_desc *, int);
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 4312ee5e3d0..ab08d977ad4 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -124,6 +124,15 @@
#endif /* !CONFIG_MMU */
/*
+ * We fix the TCM memories max 32 KiB ITCM resp DTCM at these
+ * locations
+ */
+#ifdef CONFIG_HAVE_TCM
+#define ITCM_OFFSET UL(0xfffe0000)
+#define DTCM_OFFSET UL(0xfffe8000)
+#endif
+
+/*
* Physical vs virtual RAM address space conversion. These are
* private definitions which should NOT be used outside memory.h
* files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index 25f76bae57a..fc190092527 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -25,6 +25,9 @@ struct outer_cache_fns {
void (*inv_range)(unsigned long, unsigned long);
void (*clean_range)(unsigned long, unsigned long);
void (*flush_range)(unsigned long, unsigned long);
+ void (*flush_all)(void);
+ void (*inv_all)(void);
+ void (*disable)(void);
#ifdef CONFIG_OUTER_CACHE_SYNC
void (*sync)(void);
#endif
@@ -50,6 +53,24 @@ static inline void outer_flush_range(unsigned long start, unsigned long end)
outer_cache.flush_range(start, end);
}
+static inline void outer_flush_all(void)
+{
+ if (outer_cache.flush_all)
+ outer_cache.flush_all();
+}
+
+static inline void outer_inv_all(void)
+{
+ if (outer_cache.inv_all)
+ outer_cache.inv_all();
+}
+
+static inline void outer_disable(void)
+{
+ if (outer_cache.disable)
+ outer_cache.disable();
+}
+
#else
static inline void outer_inv_range(unsigned long start, unsigned long end)
@@ -58,6 +79,9 @@ static inline void outer_clean_range(unsigned long start, unsigned long end)
{ }
static inline void outer_flush_range(unsigned long start, unsigned long end)
{ }
+static inline void outer_flush_all(void) { }
+static inline void outer_inv_all(void) { }
+static inline void outer_disable(void) { }
#endif
diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
index f392fb4437a..c35f80b2e04 100644
--- a/arch/arm/include/asm/setup.h
+++ b/arch/arm/include/asm/setup.h
@@ -143,6 +143,23 @@ struct tag_memclk {
__u32 fmemclk;
};
+/* for automatic boot timing testcases */
+#define ATAG_BOOTTIME 0x41000403
+#define BOOTTIME_MAX_NAME_LEN 64
+#define BOOTTIME_MAX 10
+
+struct boottime_entry {
+ u32 time; /* in us */
+ u8 name[BOOTTIME_MAX_NAME_LEN];
+};
+
+struct tag_boottime {
+ struct boottime_entry entry[BOOTTIME_MAX];
+ u32 idle; /* in us */
+ u32 total; /* in us */
+ u8 num;
+};
+
struct tag {
struct tag_header hdr;
union {
@@ -165,6 +182,10 @@ struct tag {
* DC21285 specific
*/
struct tag_memclk memclk;
+ /*
+ * Boot time
+ */
+ struct tag_boottime boottime;
} u;
};
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 5f4f4800273..440b50f1766 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -101,6 +101,8 @@ extern void cpu_init(void);
void arm_machine_restart(char mode, const char *cmd);
extern void (*arm_pm_restart)(char str, const char *cmd);
+void cpu_idle_wait(void);
+
#define UDBG_UNDEFINED (1 << 0)
#define UDBG_SYSCALL (1 << 1)
#define UDBG_BADABORT (1 << 2)
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 26d302c28e1..a7ca6e7f18c 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_ATAGS_PROC) += atags.o
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
obj-$(CONFIG_KGDB) += kgdb.o
+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_ARM_UNWIND) += unwind.o
obj-$(CONFIG_HAVE_TCM) += tcm.o
diff --git a/arch/arm/kernel/crash_dump.c b/arch/arm/kernel/crash_dump.c
new file mode 100644
index 00000000000..a140e0cf82b
--- /dev/null
+++ b/arch/arm/kernel/crash_dump.c
@@ -0,0 +1,58 @@
+/*
+ * arch/arm/kernel/crash_dump.c
+ *
+ * Copyright (C) 2010 Nokia Corporation.
+ * Author: Mika Westerberg
+ *
+ * This code is taken from arch/x86/kernel/crash_dump_64.c
+ * Created by: Hariprasad Nellitheertha (hari <at> in.ibm.com)
+ * Copyright (C) IBM Corporation, 2004. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/errno.h>
+#include <linux/crash_dump.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+/* stores the physical address of elf header of crash image */
+unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
+
+/**
+ * copy_oldmem_page() - copy one page from old kernel memory
+ * @pfn: page frame number to be copied
+ * @buf: buffer where the copied page is placed
+ * @csize: number of bytes to copy
+ * @offset: offset in bytes into the page
+ * @userbuf: if set, @buf is int he user address space
+ *
+ * This function copies one page from old kernel memory into buffer pointed by
+ * @buf. If @buf is in userspace, set @userbuf to %1. Returns number of bytes
+ * copied or negative error in case of failure.
+ */
+ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
+ size_t csize, unsigned long offset,
+ int userbuf)
+{
+ void *vaddr;
+
+ if (!csize)
+ return 0;
+
+ vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
+
+ if (userbuf) {
+ if (copy_to_user(buf, vaddr + offset, csize)) {
+ iounmap(vaddr);
+ return -EFAULT;
+ }
+ } else {
+ memcpy(buf, vaddr + offset, csize);
+ }
+
+ iounmap(vaddr);
+ return csize;
+}
diff --git a/arch/arm/kernel/elf.c b/arch/arm/kernel/elf.c
index d4a0da1e48f..14e501be0f1 100644
--- a/arch/arm/kernel/elf.c
+++ b/arch/arm/kernel/elf.c
@@ -4,11 +4,13 @@
#include <linux/binfmts.h>
#include <linux/elf.h>
-int elf_check_arch(const struct elf32_hdr *x)
+int arm_elf_check_arch(const struct elf32_hdr *x)
{
unsigned int eflags;
/* Make sure it's an ARM executable */
+ if (x->e_ident[EI_CLASS] != ELF_CLASS)
+ return 0;
if (x->e_machine != EM_ARM)
return 0;
@@ -35,7 +37,7 @@ int elf_check_arch(const struct elf32_hdr *x)
}
return 1;
}
-EXPORT_SYMBOL(elf_check_arch);
+EXPORT_SYMBOL(arm_elf_check_arch);
void elf_set_personality(const struct elf32_hdr *x)
{
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index 598ca61e7bc..6d71ceec095 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -13,6 +13,8 @@
#include <asm/cacheflush.h>
#include <asm/mach-types.h>
+#include <linux/smp.h>
+
extern const unsigned char relocate_new_kernel[];
extern const unsigned int relocate_new_kernel_size;
@@ -23,6 +25,8 @@ extern unsigned long kexec_indirection_page;
extern unsigned long kexec_mach_type;
extern unsigned long kexec_boot_atags;
+static atomic_t waiting_for_crash_ipi;
+
/*
* Provide a dummy crash_notes definition while crash dump arrives to arm.
* This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
@@ -41,8 +45,39 @@ void machine_shutdown(void)
{
}
+void machine_crash_nonpanic_core()
+{
+ struct pt_regs regs;
+
+ crash_setup_regs(&regs, NULL);
+ printk(KERN_EMERG "CPU %u will stop doing anything useful since another CPU has crashed\n",
+ smp_processor_id());
+ crash_save_cpu(&regs, smp_processor_id());
+ flush_cache_all();
+
+ atomic_dec(&waiting_for_crash_ipi);
+ while (1)
+ cpu_relax();
+}
+
void machine_crash_shutdown(struct pt_regs *regs)
{
+ unsigned long msecs;
+
+ atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+
+ local_irq_enable();
+ smp_call_function(machine_crash_nonpanic_core, NULL, false);
+ msecs = 1000; /* Wait at most a second for the other cpus to stop */
+ while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
+ mdelay(1);
+ msecs--;
+ }
+ local_irq_disable();
+
+ crash_save_cpu(regs, smp_processor_id());
+
+ printk(KERN_INFO "Loading crashdump kernel...\n");
}
void machine_kexec(struct kimage *image)
@@ -74,7 +109,9 @@ void machine_kexec(struct kimage *image)
(unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
printk(KERN_INFO "Bye!\n");
+ outer_flush_all();
+ outer_disable();
cpu_proc_fin();
- setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/
+ outer_inv_all();
cpu_reset(reboot_code_buffer_phys);
}
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 1a2d39a24a0..3c44103b22f 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -150,8 +150,17 @@ void cpu_idle(void)
leds_event(led_idle_start);
while (!need_resched()) {
#ifdef CONFIG_HOTPLUG_CPU
- if (cpu_is_offline(smp_processor_id()))
+ if (cpu_is_offline(smp_processor_id())) {
+
+ /* NOTE : preempt_count() should be 0 for dying CPU
+ * as the CPU will use this very thread when
+ * it is alive
+ */
+ if (preempt_count())
+ preempt_enable_no_resched();
+
cpu_die();
+ }
#endif
local_irq_disable();
diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S
index 61930eb0902..fd26f8d6515 100644
--- a/arch/arm/kernel/relocate_kernel.S
+++ b/arch/arm/kernel/relocate_kernel.S
@@ -10,6 +10,12 @@ relocate_new_kernel:
ldr r0,kexec_indirection_page
ldr r1,kexec_start_address
+ /*
+ * If there is no indirection page (we are doing crashdumps)
+ * skip any relocation.
+ */
+ cmp r0, #0
+ beq 2f
0: /* top, read another word for the indirection page */
ldr r3, [r0],#4
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 122d999bdc7..985f274de10 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -19,6 +19,8 @@
#include <linux/seq_file.h>
#include <linux/screen_info.h>
#include <linux/init.h>
+#include <linux/kexec.h>
+#include <linux/crash_dump.h>
#include <linux/root_dev.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
@@ -663,6 +665,79 @@ static int __init customize_machine(void)
}
arch_initcall(customize_machine);
+#ifdef CONFIG_KEXEC
+static inline unsigned long long get_total_mem(void)
+{
+ unsigned long total;
+
+ total = max_low_pfn - min_low_pfn;
+ return total << PAGE_SHIFT;
+}
+
+/**
+ * reserve_crashkernel() - reserves memory are for crash kernel
+ *
+ * This function reserves memory area given in "crashkernel=" kernel command
+ * line parameter. The memory reserved is used by a dump capture kernel when
+ * primary kernel is crashing.
+ */
+static void __init reserve_crashkernel(void)
+{
+ unsigned long long crash_size, crash_base;
+ unsigned long long total_mem;
+ int ret;
+
+ total_mem = get_total_mem();
+ ret = parse_crashkernel(boot_command_line, total_mem,
+ &crash_size, &crash_base);
+ if (ret)
+ return;
+
+ ret = reserve_bootmem(crash_base, crash_size, BOOTMEM_EXCLUSIVE);
+ if (ret < 0) {
+ printk(KERN_WARNING "crashkernel reservation failed - "
+ "memory is in use (0x%lx)\n", (unsigned long)crash_base);
+ return;
+ }
+
+ printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
+ "for crashkernel (System RAM: %ldMB)\n",
+ (unsigned long)(crash_size >> 20),
+ (unsigned long)(crash_base >> 20),
+ (unsigned long)(total_mem >> 20));
+
+ crashk_res.start = crash_base;
+ crashk_res.end = crash_base + crash_size - 1;
+ insert_resource(&iomem_resource, &crashk_res);
+}
+#else
+static inline void reserve_crashkernel(void) {}
+#endif /* CONFIG_KEXEC */
+
+/*
+ * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by
+ * is_kdump_kernel() to determine if we are booting after a panic. Hence
+ * ifdef it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE.
+ */
+
+#ifdef CONFIG_CRASH_DUMP
+/*
+ * elfcorehdr= specifies the location of elf core header stored by the crashed
+ * kernel. This option will be passed by kexec loader to the capture kernel.
+ */
+static int __init setup_elfcorehdr(char *arg)
+{
+ char *end;
+
+ if (!arg)
+ return -EINVAL;
+
+ elfcorehdr_addr = memparse(arg, &end);
+ return end > arg ? 0 : -EINVAL;
+}
+early_param("elfcorehdr", setup_elfcorehdr);
+#endif /* CONFIG_CRASH_DUMP */
+
void __init setup_arch(char **cmdline_p)
{
struct tag *tags = (struct tag *)&init_tags;
@@ -722,6 +797,7 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_SMP
smp_init_cpus();
#endif
+ reserve_crashkernel();
cpu_init();
tcm_init();
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index b8c3d0f689d..a4825de879e 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -425,11 +425,14 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs)
#endif
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
-static void smp_timer_broadcast(const struct cpumask *mask)
+void smp_timer_broadcast(const struct cpumask *mask)
{
send_ipi_message(mask, IPI_TIMER);
}
+#endif
+#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && \
+ !defined(CONFIG_LOCAL_TIMERS)
static void broadcast_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 7c5f0c024db..c47fcecb524 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -132,7 +132,13 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
twd_calibrate_rate();
clk->name = "local_timer";
+#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && \
+ defined(CONFIG_LOCAL_TIMERS)
+ clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
+ CLOCK_EVT_FEAT_C3STOP;
+#else
clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+#endif
clk->rating = 350;
clk->set_mode = twd_set_mode;
clk->set_next_event = twd_set_next_event;
diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c
index e50303868f1..26685c2f7a4 100644
--- a/arch/arm/kernel/tcm.c
+++ b/arch/arm/kernel/tcm.c
@@ -13,38 +13,35 @@
#include <linux/ioport.h>
#include <linux/genalloc.h>
#include <linux/string.h> /* memcpy */
-#include <asm/page.h> /* PAGE_SHIFT */
#include <asm/cputype.h>
#include <asm/mach/map.h>
#include <mach/memory.h>
#include "tcm.h"
-/* Scream and warn about misuse */
-#if !defined(ITCM_OFFSET) || !defined(ITCM_END) || \
- !defined(DTCM_OFFSET) || !defined(DTCM_END)
-#error "TCM support selected but offsets not defined!"
-#endif
-
static struct gen_pool *tcm_pool;
/* TCM section definitions from the linker */
extern char __itcm_start, __sitcm_text, __eitcm_text;
extern char __dtcm_start, __sdtcm_data, __edtcm_data;
+/* These will be increased as we run */
+u32 dtcm_end = DTCM_OFFSET;
+u32 itcm_end = ITCM_OFFSET;
+
/*
* TCM memory resources
*/
static struct resource dtcm_res = {
.name = "DTCM RAM",
.start = DTCM_OFFSET,
- .end = DTCM_END,
+ .end = DTCM_OFFSET,
.flags = IORESOURCE_MEM
};
static struct resource itcm_res = {
.name = "ITCM RAM",
.start = ITCM_OFFSET,
- .end = ITCM_END,
+ .end = ITCM_OFFSET,
.flags = IORESOURCE_MEM
};
@@ -52,8 +49,8 @@ static struct map_desc dtcm_iomap[] __initdata = {
{
.virtual = DTCM_OFFSET,
.pfn = __phys_to_pfn(DTCM_OFFSET),
- .length = (DTCM_END - DTCM_OFFSET + 1),
- .type = MT_UNCACHED
+ .length = 0,
+ .type = MT_MEMORY_DTCM
}
};
@@ -61,8 +58,8 @@ static struct map_desc itcm_iomap[] __initdata = {
{
.virtual = ITCM_OFFSET,
.pfn = __phys_to_pfn(ITCM_OFFSET),
- .length = (ITCM_END - ITCM_OFFSET + 1),
- .type = MT_UNCACHED
+ .length = 0,
+ .type = MT_MEMORY_ITCM
}
};
@@ -93,14 +90,24 @@ void tcm_free(void *addr, size_t len)
}
EXPORT_SYMBOL(tcm_free);
-
-static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size)
+static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks,
+ u32 *offset)
{
const int tcm_sizes[16] = { 0, -1, -1, 4, 8, 16, 32, 64, 128,
256, 512, 1024, -1, -1, -1, -1 };
u32 tcm_region;
int tcm_size;
+ /*
+ * If there are more than one TCM bank of this type,
+ * select the TCM bank to operate on in the TCM selection
+ * register.
+ */
+ if (banks > 1)
+ asm("mcr p15, 0, %0, c9, c2, 0"
+ : /* No output operands */
+ : "r" (bank));
+
/* Read the special TCM region register c9, 0 */
if (!type)
asm("mrc p15, 0, %0, c9, c1, 0"
@@ -111,26 +118,24 @@ static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size)
tcm_size = tcm_sizes[(tcm_region >> 2) & 0x0f];
if (tcm_size < 0) {
- pr_err("CPU: %sTCM of unknown size!\n",
- type ? "I" : "D");
+ pr_err("CPU: %sTCM%d of unknown size\n",
+ type ? "I" : "D", bank);
+ return -EINVAL;
+ } else if (tcm_size > 32) {
+ pr_err("CPU: %sTCM%d larger than 32k found\n",
+ type ? "I" : "D", bank);
+ return -EINVAL;
} else {
- pr_info("CPU: found %sTCM %dk @ %08x, %senabled\n",
+ pr_info("CPU: found %sTCM%d %dk @ %08x, %senabled\n",
type ? "I" : "D",
+ bank,
tcm_size,
(tcm_region & 0xfffff000U),
(tcm_region & 1) ? "" : "not ");
}
- if (tcm_size != expected_size) {
- pr_crit("CPU: %sTCM was detected %dk but expected %dk!\n",
- type ? "I" : "D",
- tcm_size,
- expected_size);
- /* Adjust to the expected size? what can we do... */
- }
-
/* Force move the TCM bank to where we want it, enable */
- tcm_region = offset | (tcm_region & 0x00000ffeU) | 1;
+ tcm_region = *offset | (tcm_region & 0x00000ffeU) | 1;
if (!type)
asm("mcr p15, 0, %0, c9, c1, 0"
@@ -141,10 +146,15 @@ static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size)
: /* No output operands */
: "r" (tcm_region));
- pr_debug("CPU: moved %sTCM %dk to %08x, enabled\n",
- type ? "I" : "D",
- tcm_size,
- (tcm_region & 0xfffff000U));
+ /* Increase offset */
+ *offset += (tcm_size << 10);
+
+ pr_info("CPU: moved %sTCM%d %dk to %08x, enabled\n",
+ type ? "I" : "D",
+ bank,
+ tcm_size,
+ (tcm_region & 0xfffff000U));
+ return 0;
}
/*
@@ -153,34 +163,52 @@ static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size)
void __init tcm_init(void)
{
u32 tcm_status = read_cpuid_tcmstatus();
+ u8 dtcm_banks = (tcm_status >> 16) & 0x03;
+ u8 itcm_banks = (tcm_status & 0x03);
char *start;
char *end;
char *ram;
+ int ret;
+ int i;
/* Setup DTCM if present */
- if (tcm_status & (1 << 16)) {
- setup_tcm_bank(0, DTCM_OFFSET,
- (DTCM_END - DTCM_OFFSET + 1) >> 10);
+ if (dtcm_banks > 0) {
+ for (i = 0; i < dtcm_banks; i++) {
+ ret = setup_tcm_bank(0, i, dtcm_banks, &dtcm_end);
+ if (ret)
+ return;
+ }
+ dtcm_res.end = dtcm_end - 1;
request_resource(&iomem_resource, &dtcm_res);
+ dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET;
iotable_init(dtcm_iomap, 1);
/* Copy data from RAM to DTCM */
start = &__sdtcm_data;
end = &__edtcm_data;
ram = &__dtcm_start;
+ /* This means you compiled more code than fits into DTCM */
+ BUG_ON((end - start) > (dtcm_end - DTCM_OFFSET));
memcpy(start, ram, (end-start));
pr_debug("CPU DTCM: copied data from %p - %p\n", start, end);
}
/* Setup ITCM if present */
- if (tcm_status & 1) {
- setup_tcm_bank(1, ITCM_OFFSET,
- (ITCM_END - ITCM_OFFSET + 1) >> 10);
+ if (itcm_banks > 0) {
+ for (i = 0; i < itcm_banks; i++) {
+ ret = setup_tcm_bank(1, i, itcm_banks, &itcm_end);
+ if (ret)
+ return;
+ }
+ itcm_res.end = itcm_end - 1;
request_resource(&iomem_resource, &itcm_res);
+ itcm_iomap[0].length = itcm_end - ITCM_OFFSET;
iotable_init(itcm_iomap, 1);
/* Copy code from RAM to ITCM */
start = &__sitcm_text;
end = &__eitcm_text;
ram = &__itcm_start;
+ /* This means you compiled more code than fits into ITCM */
+ BUG_ON((end - start) > (itcm_end - ITCM_OFFSET));
memcpy(start, ram, (end-start));
pr_debug("CPU ITCM: copied code from %p - %p\n", start, end);
}
@@ -208,10 +236,10 @@ static int __init setup_tcm_pool(void)
pr_debug("Setting up TCM memory pool\n");
/* Add the rest of DTCM to the TCM pool */
- if (tcm_status & (1 << 16)) {
- if (dtcm_pool_start < DTCM_END) {
+ if (tcm_status & (0x03 << 16)) {
+ if (dtcm_pool_start < dtcm_end) {
ret = gen_pool_add(tcm_pool, dtcm_pool_start,
- DTCM_END - dtcm_pool_start + 1, -1);
+ dtcm_end - dtcm_pool_start, -1);
if (ret) {
pr_err("CPU DTCM: could not add DTCM " \
"remainder to pool!\n");
@@ -219,16 +247,16 @@ static int __init setup_tcm_pool(void)
}
pr_debug("CPU DTCM: Added %08x bytes @ %08x to " \
"the TCM memory pool\n",
- DTCM_END - dtcm_pool_start + 1,
+ dtcm_end - dtcm_pool_start,
dtcm_pool_start);
}
}
/* Add the rest of ITCM to the TCM pool */
- if (tcm_status & 1) {
- if (itcm_pool_start < ITCM_END) {
+ if (tcm_status & 0x03) {
+ if (itcm_pool_start < itcm_end) {
ret = gen_pool_add(tcm_pool, itcm_pool_start,
- ITCM_END - itcm_pool_start + 1, -1);
+ itcm_end - itcm_pool_start, -1);
if (ret) {
pr_err("CPU ITCM: could not add ITCM " \
"remainder to pool!\n");
@@ -236,7 +264,7 @@ static int __init setup_tcm_pool(void)
}
pr_debug("CPU ITCM: Added %08x bytes @ %08x to " \
"the TCM memory pool\n",
- ITCM_END - itcm_pool_start + 1,
+ itcm_end - itcm_pool_start,
itcm_pool_start);
}
}
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 02e9fdeb8fa..1fa487a3ccd 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -232,6 +232,21 @@ static unsigned int realview_mmc_status(struct device *dev)
struct amba_device *adev = container_of(dev, struct amba_device, dev);
u32 mask;
+ if (machine_is_realview_pb1176()) {
+ static bool inserted = false;
+
+ /*
+ * The PB1176 does not have the status register,
+ * assume it is inserted at startup, then invert
+ * for each call so card insertion/removal will
+ * be detected anyway. This will not be called if
+ * GPIO on PL061 is active, which is the proper
+ * way to do this on the PB1176.
+ */
+ inserted = !inserted;
+ return inserted ? 0 : 1;
+ }
+
if (adev->res.start == REALVIEW_MMCI0_BASE)
mask = 1;
else
@@ -245,6 +260,7 @@ struct mmci_platform_data realview_mmc0_plat_data = {
.status = realview_mmc_status,
.gpio_wp = 17,
.gpio_cd = 16,
+ .cd_invert = true,
};
struct mmci_platform_data realview_mmc1_plat_data = {
@@ -252,6 +268,7 @@ struct mmci_platform_data realview_mmc1_plat_data = {
.status = realview_mmc_status,
.gpio_wp = 19,
.gpio_cd = 18,
+ .cd_invert = true,
};
/*
@@ -313,6 +330,12 @@ static struct clk_lookup lookups[] = {
}, { /* UART3 */
.dev_id = "fpga:uart3",
.clk = &ref24_clk,
+ }, { /* UART3 is on the dev chip in PB1176 */
+ .dev_id = "dev:uart3",
+ .clk = &ref24_clk,
+ }, { /* UART4 only exists in PB1176 */
+ .dev_id = "fpga:uart4",
+ .clk = &ref24_clk,
}, { /* KMI0 */
.dev_id = "fpga:kmi0",
.clk = &ref24_clk,
@@ -322,12 +345,15 @@ static struct clk_lookup lookups[] = {
}, { /* MMC0 */
.dev_id = "fpga:mmc0",
.clk = &ref24_clk,
- }, { /* EB:CLCD */
+ }, { /* CLCD is in the PB1176 and EB DevChip */
.dev_id = "dev:clcd",
.clk = &oscvco_clk,
}, { /* PB:CLCD */
.dev_id = "issp:clcd",
.clk = &oscvco_clk,
+ }, { /* SSP */
+ .dev_id = "dev:ssp0",
+ .clk = &ref24_clk,
}
};
@@ -342,7 +368,7 @@ static int __init clk_init(void)
return 0;
}
-arch_initcall(clk_init);
+core_initcall(clk_init);
/*
* CLCD support.
diff --git a/arch/arm/mach-realview/include/mach/board-pb1176.h b/arch/arm/mach-realview/include/mach/board-pb1176.h
index 2f5ccb29885..002ab5d8c11 100644
--- a/arch/arm/mach-realview/include/mach/board-pb1176.h
+++ b/arch/arm/mach-realview/include/mach/board-pb1176.h
@@ -26,6 +26,7 @@
/*
* Peripheral addresses
*/
+#define REALVIEW_PB1176_UART4_BASE 0x10009000 /* UART 4 */
#define REALVIEW_PB1176_SCTL_BASE 0x10100000 /* System controller */
#define REALVIEW_PB1176_SMC_BASE 0x10111000 /* SMC */
#define REALVIEW_PB1176_DMC_BASE 0x10109000 /* DMC configuration */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pb1176.h b/arch/arm/mach-realview/include/mach/irqs-pb1176.h
index 830055bb862..5c3c625e3e0 100644
--- a/arch/arm/mach-realview/include/mach/irqs-pb1176.h
+++ b/arch/arm/mach-realview/include/mach/irqs-pb1176.h
@@ -40,6 +40,7 @@
#define IRQ_DC1176_L2CC (IRQ_DC1176_GIC_START + 13)
#define IRQ_DC1176_RTC (IRQ_DC1176_GIC_START + 14)
#define IRQ_DC1176_CLCD (IRQ_DC1176_GIC_START + 15) /* CLCD controller */
+#define IRQ_DC1176_SSP (IRQ_DC1176_GIC_START + 17) /* SSP port */
#define IRQ_DC1176_UART0 (IRQ_DC1176_GIC_START + 18) /* UART 0 on development chip */
#define IRQ_DC1176_UART1 (IRQ_DC1176_GIC_START + 19) /* UART 1 on development chip */
#define IRQ_DC1176_UART2 (IRQ_DC1176_GIC_START + 20) /* UART 2 on development chip */
@@ -73,7 +74,6 @@
#define IRQ_PB1176_RTC (IRQ_PB1176_GIC_START + 25) /* Real Time Clock */
#define IRQ_PB1176_GPIO0 -1
-#define IRQ_PB1176_SSP -1
#define IRQ_PB1176_SCTL -1
#define NR_GIC_PB1176 2
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 4425018fab8..991c1f8390e 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -25,6 +25,7 @@
#include <linux/amba/bus.h>
#include <linux/amba/pl061.h>
#include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
#include <linux/io.h>
#include <mach/hardware.h>
@@ -129,6 +130,12 @@ static struct pl061_platform_data gpio2_plat_data = {
.irq_base = -1,
};
+static struct pl022_ssp_controller ssp0_plat_data = {
+ .bus_id = 0,
+ .enable_dma = 0,
+ .num_chipselect = 1,
+};
+
/*
* RealView EB AMBA devices
*/
@@ -213,7 +220,7 @@ AMBA_DEVICE(sci0, "dev:sci0", SCI, NULL);
AMBA_DEVICE(uart0, "dev:uart0", EB_UART0, NULL);
AMBA_DEVICE(uart1, "dev:uart1", EB_UART1, NULL);
AMBA_DEVICE(uart2, "dev:uart2", EB_UART2, NULL);
-AMBA_DEVICE(ssp0, "dev:ssp0", EB_SSP, NULL);
+AMBA_DEVICE(ssp0, "dev:ssp0", EB_SSP, &ssp0_plat_data);
static struct amba_device *amba_devs[] __initdata = {
&dmac_device,
@@ -324,6 +331,26 @@ static struct platform_device pmu_device = {
.resource = pmu_resources,
};
+static struct resource char_lcd_resources[] = {
+ {
+ .start = REALVIEW_CHAR_LCD_BASE,
+ .end = (REALVIEW_CHAR_LCD_BASE + SZ_4K - 1),
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_EB_CHARLCD,
+ .end = IRQ_EB_CHARLCD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device char_lcd_device = {
+ .name = "arm-charlcd",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(char_lcd_resources),
+ .resource = char_lcd_resources,
+};
+
static void __init gic_init_irq(void)
{
if (core_tile_eb11mp() || core_tile_a9mp()) {
@@ -442,6 +469,7 @@ static void __init realview_eb_init(void)
realview_flash_register(&realview_eb_flash_resource, 1);
platform_device_register(&realview_i2c_device);
+ platform_device_register(&char_lcd_device);
eth_device_register();
realview_usb_register(realview_eb_isp1761_resources);
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index 099a1f125cf..d2be12eb829 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -25,6 +25,7 @@
#include <linux/amba/bus.h>
#include <linux/amba/pl061.h>
#include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
#include <linux/io.h>
#include <mach/hardware.h>
@@ -123,6 +124,12 @@ static struct pl061_platform_data gpio2_plat_data = {
.irq_base = -1,
};
+static struct pl022_ssp_controller ssp0_plat_data = {
+ .bus_id = 0,
+ .enable_dma = 0,
+ .num_chipselect = 1,
+};
+
/*
* RealView PB1176 AMBA devices
*/
@@ -144,8 +151,6 @@ static struct pl061_platform_data gpio2_plat_data = {
#define MPMC_DMA { 0, 0 }
#define PB1176_CLCD_IRQ { IRQ_DC1176_CLCD, NO_IRQ }
#define PB1176_CLCD_DMA { 0, 0 }
-#define DMAC_IRQ { IRQ_PB1176_DMAC, NO_IRQ }
-#define DMAC_DMA { 0, 0 }
#define SCTL_IRQ { NO_IRQ, NO_IRQ }
#define SCTL_DMA { 0, 0 }
#define PB1176_WATCHDOG_IRQ { IRQ_DC1176_WATCHDOG, NO_IRQ }
@@ -166,7 +171,9 @@ static struct pl061_platform_data gpio2_plat_data = {
#define PB1176_UART2_DMA { 11, 10 }
#define PB1176_UART3_IRQ { IRQ_DC1176_UART3, NO_IRQ }
#define PB1176_UART3_DMA { 0x86, 0x87 }
-#define PB1176_SSP_IRQ { IRQ_PB1176_SSP, NO_IRQ }
+#define PB1176_UART4_IRQ { IRQ_PB1176_UART4, NO_IRQ }
+#define PB1176_UART4_DMA { 0, 0 }
+#define PB1176_SSP_IRQ { IRQ_DC1176_SSP, NO_IRQ }
#define PB1176_SSP_DMA { 9, 8 }
/* FPGA Primecells */
@@ -174,7 +181,7 @@ AMBA_DEVICE(aaci, "fpga:aaci", AACI, NULL);
AMBA_DEVICE(mmc0, "fpga:mmc0", MMCI0, &realview_mmc0_plat_data);
AMBA_DEVICE(kmi0, "fpga:kmi0", KMI0, NULL);
AMBA_DEVICE(kmi1, "fpga:kmi1", KMI1, NULL);
-AMBA_DEVICE(uart3, "fpga:uart3", PB1176_UART3, NULL);
+AMBA_DEVICE(uart4, "fpga:uart4", PB1176_UART4, NULL);
/* DevChip Primecells */
AMBA_DEVICE(smc, "dev:smc", PB1176_SMC, NULL);
@@ -188,18 +195,16 @@ AMBA_DEVICE(sci0, "dev:sci0", SCI, NULL);
AMBA_DEVICE(uart0, "dev:uart0", PB1176_UART0, NULL);
AMBA_DEVICE(uart1, "dev:uart1", PB1176_UART1, NULL);
AMBA_DEVICE(uart2, "dev:uart2", PB1176_UART2, NULL);
-AMBA_DEVICE(ssp0, "dev:ssp0", PB1176_SSP, NULL);
-
-/* Primecells on the NEC ISSP chip */
-AMBA_DEVICE(clcd, "issp:clcd", PB1176_CLCD, &clcd_plat_data);
-//AMBA_DEVICE(dmac, "issp:dmac", PB1176_DMAC, NULL);
+AMBA_DEVICE(uart3, "dev:uart3", PB1176_UART3, NULL);
+AMBA_DEVICE(ssp0, "dev:ssp0", PB1176_SSP, &ssp0_plat_data);
+AMBA_DEVICE(clcd, "dev:clcd", PB1176_CLCD, &clcd_plat_data);
static struct amba_device *amba_devs[] __initdata = {
-// &dmac_device,
&uart0_device,
&uart1_device,
&uart2_device,
&uart3_device,
+ &uart4_device,
&smc_device,
&clcd_device,
&sctl_device,
@@ -276,6 +281,26 @@ static struct platform_device pmu_device = {
.resource = &pmu_resource,
};
+static struct resource char_lcd_resources[] = {
+ {
+ .start = REALVIEW_CHAR_LCD_BASE,
+ .end = (REALVIEW_CHAR_LCD_BASE + SZ_4K - 1),
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_PB1176_CHARLCD,
+ .end = IRQ_PB1176_CHARLCD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device char_lcd_device = {
+ .name = "arm-charlcd",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(char_lcd_resources),
+ .resource = char_lcd_resources,
+};
+
static void __init gic_init_irq(void)
{
/* ARM1176 DevChip GIC, primary */
@@ -338,6 +363,7 @@ static void __init realview_pb1176_init(void)
platform_device_register(&realview_i2c_device);
realview_usb_register(realview_pb1176_isp1761_resources);
platform_device_register(&pmu_device);
+ platform_device_register(&char_lcd_device);
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index 0e07a5ccb75..d591bc00b86 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -25,6 +25,7 @@
#include <linux/amba/bus.h>
#include <linux/amba/pl061.h>
#include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
#include <linux/io.h>
#include <mach/hardware.h>
@@ -124,6 +125,12 @@ static struct pl061_platform_data gpio2_plat_data = {
.irq_base = -1,
};
+static struct pl022_ssp_controller ssp0_plat_data = {
+ .bus_id = 0,
+ .enable_dma = 0,
+ .num_chipselect = 1,
+};
+
/*
* RealView PB11MPCore AMBA devices
*/
@@ -190,7 +197,7 @@ AMBA_DEVICE(sci0, "dev:sci0", SCI, NULL);
AMBA_DEVICE(uart0, "dev:uart0", PB11MP_UART0, NULL);
AMBA_DEVICE(uart1, "dev:uart1", PB11MP_UART1, NULL);
AMBA_DEVICE(uart2, "dev:uart2", PB11MP_UART2, NULL);
-AMBA_DEVICE(ssp0, "dev:ssp0", PB11MP_SSP, NULL);
+AMBA_DEVICE(ssp0, "dev:ssp0", PB11MP_SSP, &ssp0_plat_data);
/* Primecells on the NEC ISSP chip */
AMBA_DEVICE(clcd, "issp:clcd", PB11MP_CLCD, &clcd_plat_data);
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index ac2f06f1ca5..6c37621217b 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -25,6 +25,7 @@
#include <linux/amba/bus.h>
#include <linux/amba/pl061.h>
#include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
#include <linux/io.h>
#include <asm/irq.h>
@@ -114,6 +115,12 @@ static struct pl061_platform_data gpio2_plat_data = {
.irq_base = -1,
};
+static struct pl022_ssp_controller ssp0_plat_data = {
+ .bus_id = 0,
+ .enable_dma = 0,
+ .num_chipselect = 1,
+};
+
/*
* RealView PBA8Core AMBA devices
*/
@@ -180,7 +187,7 @@ AMBA_DEVICE(sci0, "dev:sci0", SCI, NULL);
AMBA_DEVICE(uart0, "dev:uart0", PBA8_UART0, NULL);
AMBA_DEVICE(uart1, "dev:uart1", PBA8_UART1, NULL);
AMBA_DEVICE(uart2, "dev:uart2", PBA8_UART2, NULL);
-AMBA_DEVICE(ssp0, "dev:ssp0", PBA8_SSP, NULL);
+AMBA_DEVICE(ssp0, "dev:ssp0", PBA8_SSP, &ssp0_plat_data);
/* Primecells on the NEC ISSP chip */
AMBA_DEVICE(clcd, "issp:clcd", PBA8_CLCD, &clcd_plat_data);
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index 08fd683adc4..9428eff0b11 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -24,6 +24,7 @@
#include <linux/amba/bus.h>
#include <linux/amba/pl061.h>
#include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
#include <linux/io.h>
#include <asm/irq.h>
@@ -136,6 +137,12 @@ static struct pl061_platform_data gpio2_plat_data = {
.irq_base = -1,
};
+static struct pl022_ssp_controller ssp0_plat_data = {
+ .bus_id = 0,
+ .enable_dma = 0,
+ .num_chipselect = 1,
+};
+
/*
* RealView PBXCore AMBA devices
*/
@@ -202,7 +209,7 @@ AMBA_DEVICE(sci0, "dev:sci0", SCI, NULL);
AMBA_DEVICE(uart0, "dev:uart0", PBX_UART0, NULL);
AMBA_DEVICE(uart1, "dev:uart1", PBX_UART1, NULL);
AMBA_DEVICE(uart2, "dev:uart2", PBX_UART2, NULL);
-AMBA_DEVICE(ssp0, "dev:ssp0", PBX_SSP, NULL);
+AMBA_DEVICE(ssp0, "dev:ssp0", PBX_SSP, &ssp0_plat_data);
/* Primecells on the NEC ISSP chip */
AMBA_DEVICE(clcd, "issp:clcd", PBX_CLCD, &clcd_plat_data);
diff --git a/arch/arm/mach-s3c64xx/dma.c b/arch/arm/mach-s3c64xx/dma.c
index 5567e037b0d..e7d03ab41d8 100644
--- a/arch/arm/mach-s3c64xx/dma.c
+++ b/arch/arm/mach-s3c64xx/dma.c
@@ -697,7 +697,7 @@ static int s3c64xx_dma_init1(int chno, enum dma_ch chbase,
chptr->number = chno;
chptr->dmac = dmac;
chptr->regs = regptr;
- regptr += PL008_Cx_STRIDE;
+ regptr += PL080_Cx_STRIDE;
}
/* for the moment, permanently enable the controller */
diff --git a/arch/arm/mach-u300/clock.c b/arch/arm/mach-u300/clock.c
index 5af71d5ba66..60acf9e708a 100644
--- a/arch/arm/mach-u300/clock.c
+++ b/arch/arm/mach-u300/clock.c
@@ -947,6 +947,10 @@ static struct clk fast_clk = {
.lock = __SPIN_LOCK_UNLOCKED(fast_clk.lock),
};
+/*
+ * The MMCI apb_pclk is hardwired to the same terminal as the
+ * external MCI clock. Thus this will be referenced twice.
+ */
static struct clk mmcsd_clk = {
.name = "MCLK",
.parent = &fast_clk,
@@ -1024,6 +1028,10 @@ static struct clk i2c1_clk = {
.lock = __SPIN_LOCK_UNLOCKED(i2c1_clk.lock),
};
+/*
+ * The SPI apb_pclk is hardwired to the same terminal as the
+ * external SPI clock. Thus this will be referenced twice.
+ */
static struct clk spi_clk = {
.name = "SPI",
.parent = &fast_clk,
@@ -1040,10 +1048,9 @@ static struct clk spi_clk = {
};
#ifdef CONFIG_MACH_U300_BS335
-static struct clk uart1_clk = {
- .name = "UART1",
+static struct clk uart1_pclk = {
+ .name = "UART1_PCLK",
.parent = &fast_clk,
- .rate = 13000000,
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR,
@@ -1051,6 +1058,14 @@ static struct clk uart1_clk = {
.clk_val = U300_SYSCON_SBCER_UART1_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
+ .lock = __SPIN_LOCK_UNLOCKED(uart1_pclk.lock),
+};
+
+/* This one is hardwired to PLL13 */
+static struct clk uart1_clk = {
+ .name = "UART1_CLK",
+ .rate = 13000000,
+ .hw_ctrld = true,
.lock = __SPIN_LOCK_UNLOCKED(uart1_clk.lock),
};
#endif
@@ -1085,11 +1100,9 @@ static struct clk wdog_clk = {
.lock = __SPIN_LOCK_UNLOCKED(wdog_clk.lock),
};
-/* This one is hardwired to PLL13 */
-static struct clk uart_clk = {
- .name = "UARTCLK",
+static struct clk uart0_pclk = {
+ .name = "UART0_PCLK",
.parent = &slow_clk,
- .rate = 13000000,
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR,
@@ -1097,7 +1110,16 @@ static struct clk uart_clk = {
.clk_val = U300_SYSCON_SBCER_UART_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
- .lock = __SPIN_LOCK_UNLOCKED(uart_clk.lock),
+ .lock = __SPIN_LOCK_UNLOCKED(uart0_pclk.lock),
+};
+
+/* This one is hardwired to PLL13 */
+static struct clk uart0_clk = {
+ .name = "UART0_CLK",
+ .parent = &slow_clk,
+ .rate = 13000000,
+ .hw_ctrld = true,
+ .lock = __SPIN_LOCK_UNLOCKED(uart0_clk.lock),
};
static struct clk keypad_clk = {
@@ -1182,10 +1204,14 @@ static struct clk timer_clk = {
.lock = __SPIN_LOCK_UNLOCKED(timer_clk.lock),
};
+/*
+ * There is a binary divider in the hardware that divides
+ * the 13MHz PLL by 13 down to 1 MHz.
+ */
static struct clk app_timer_clk = {
.name = "TIMER_APP",
.parent = &slow_clk,
- .rate = 13000000,
+ .rate = 1000000,
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR,
@@ -1218,6 +1244,13 @@ static struct clk ppm_clk = {
.clk = clkref, \
}
+#define DEF_LOOKUP_CON(devid, conid, clkref) \
+ { \
+ .dev_id = devid, \
+ .con_id = conid, \
+ .clk = clkref, \
+ }
+
/*
* Here we only define clocks that are meaningful to
* look up through clockdevice.
@@ -1241,11 +1274,14 @@ static struct clk_lookup lookups[] = {
/* AHB bridge clocks */
DEF_LOOKUP("ahb_subsys", &ahb_subsys_clk),
DEF_LOOKUP("intcon", &intcon_clk),
+ DEF_LOOKUP_CON("intcon", "apb_pclk", &intcon_clk),
DEF_LOOKUP("mspro", &mspro_clk),
DEF_LOOKUP("pl172", &emif_clk),
+ DEF_LOOKUP_CON("pl172", "apb_pclk", &emif_clk),
/* FAST bridge clocks */
DEF_LOOKUP("fast", &fast_clk),
DEF_LOOKUP("mmci", &mmcsd_clk),
+ DEF_LOOKUP_CON("mmci", "apb_pclk", &mmcsd_clk),
/*
* The .0 and .1 identifiers on these comes from the platform device
* .id field and are assigned when the platform devices are registered.
@@ -1255,13 +1291,16 @@ static struct clk_lookup lookups[] = {
DEF_LOOKUP("stu300.0", &i2c0_clk),
DEF_LOOKUP("stu300.1", &i2c1_clk),
DEF_LOOKUP("pl022", &spi_clk),
+ DEF_LOOKUP_CON("pl022", "apb_pclk", &spi_clk),
#ifdef CONFIG_MACH_U300_BS335
DEF_LOOKUP("uart1", &uart1_clk),
+ DEF_LOOKUP_CON("uart1", "apb_pclk", &uart1_pclk),
#endif
/* SLOW bridge clocks */
DEF_LOOKUP("slow", &slow_clk),
DEF_LOOKUP("coh901327_wdog", &wdog_clk),
- DEF_LOOKUP("uart0", &uart_clk),
+ DEF_LOOKUP("uart0", &uart0_clk),
+ DEF_LOOKUP_CON("uart0", "apb_pclk", &uart0_pclk),
DEF_LOOKUP("apptimer", &app_timer_clk),
DEF_LOOKUP("coh901461-keypad", &keypad_clk),
DEF_LOOKUP("u300-gpio", &gpio_clk),
@@ -1280,64 +1319,6 @@ static void __init clk_register(void)
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
}
-/*
- * These are the clocks for cells registered as primecell drivers
- * on the AMBA bus. These must be on during AMBA device registration
- * since the bus probe will attempt to read magic configuration
- * registers for these devices. If they are deactivated these probes
- * will fail.
- *
- *
- * Please note that on emif, both RAM and NAND is connected in dual
- * RAM phones. On single RAM phones, ram is on semi and NAND on emif.
- *
- */
-void u300_clock_primecells(void)
-{
- clk_enable(&intcon_clk);
- clk_enable(&uart_clk);
-#ifdef CONFIG_MACH_U300_BS335
- clk_enable(&uart1_clk);
-#endif
- clk_enable(&spi_clk);
-
- clk_enable(&mmcsd_clk);
-
-}
-EXPORT_SYMBOL(u300_clock_primecells);
-
-void u300_unclock_primecells(void)
-{
-
- clk_disable(&intcon_clk);
- clk_disable(&uart_clk);
-#ifdef CONFIG_MACH_U300_BS335
- clk_disable(&uart1_clk);
-#endif
- clk_disable(&spi_clk);
- clk_disable(&mmcsd_clk);
-
-}
-EXPORT_SYMBOL(u300_unclock_primecells);
-
-/*
- * The interrupt controller is enabled before the clock API is registered.
- */
-void u300_enable_intcon_clock(void)
-{
- clk_enable(&intcon_clk);
-}
-EXPORT_SYMBOL(u300_enable_intcon_clock);
-
-/*
- * The timer is enabled before the clock API is registered.
- */
-void u300_enable_timer_clock(void)
-{
- clk_enable(&app_timer_clk);
-}
-EXPORT_SYMBOL(u300_enable_timer_clock);
-
#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG))
/*
* The following makes it possible to view the status (especially
@@ -1379,11 +1360,13 @@ static struct clk *clks[] = {
&spi_clk,
#ifdef CONFIG_MACH_U300_BS335
&uart1_clk,
+ &uart1_pclk,
#endif
/* SLOW bridge clocks */
&slow_clk,
&wdog_clk,
- &uart_clk,
+ &uart0_clk,
+ &uart0_pclk,
&app_timer_clk,
&keypad_clk,
&gpio_clk,
@@ -1424,7 +1407,7 @@ static int u300_clocks_show(struct seq_file *s, void *data)
chars++;
}
cdp[32] = '\0';
- if (clk->get_rate)
+ if (clk->get_rate || clk->rate != 0)
seq_printf(s,
"%s%s\t%s\t%d\t%s\t%lu Hz\n",
&cdp[0],
@@ -1433,7 +1416,7 @@ static int u300_clocks_show(struct seq_file *s, void *data)
clk->usecount ? "ON" : "OFF",
clk->usecount,
clk->hw_ctrld ? "YES" : "NO ",
- clk->get_rate(clk));
+ clk_get_rate(clk));
else
seq_printf(s,
"%s%s\t%s\t%d\t%s\t" \
@@ -1477,7 +1460,7 @@ static int __init init_clk_read_debugfs(void)
module_init(init_clk_read_debugfs);
#endif
-static int __init u300_clock_init(void)
+int __init u300_clock_init(void)
{
u16 val;
@@ -1514,10 +1497,8 @@ static int __init u300_clock_init(void)
*/
syscon_block_reset_disable(&semi_clk);
syscon_block_reset_disable(&emif_clk);
- semi_clk.enable(&semi_clk);
- emif_clk.enable(&emif_clk);
+ clk_enable(&semi_clk);
+ clk_enable(&emif_clk);
return 0;
}
-/* initialize clocking early to be available later in the boot */
-core_initcall(u300_clock_init);
diff --git a/arch/arm/mach-u300/clock.h b/arch/arm/mach-u300/clock.h
index fc6d9ccfe7e..c34f3ea3017 100644
--- a/arch/arm/mach-u300/clock.h
+++ b/arch/arm/mach-u300/clock.h
@@ -45,9 +45,6 @@ struct clk {
void (*disable) (struct clk *);
};
-void u300_clock_primecells(void);
-void u300_unclock_primecells(void);
-void u300_enable_intcon_clock(void);
-void u300_enable_timer_clock(void);
+int u300_clock_init(void);
#endif
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index 5f34eb674d6..ea41c236be0 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -19,6 +19,8 @@
#include <linux/amba/bus.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <mach/coh901318.h>
#include <asm/types.h>
@@ -1477,11 +1479,19 @@ static struct platform_device *platform_devs[] __initdata = {
void __init u300_init_irq(void)
{
u32 mask[2] = {0, 0};
+ struct clk *clk;
int i;
+ /* initialize clocking early, we want to clock the INTCON */
+ u300_clock_init();
+
+ /* Clock the interrupt controller */
+ clk = clk_get_sys("intcon", NULL);
+ BUG_ON(IS_ERR(clk));
+ clk_enable(clk);
+
for (i = 0; i < NR_IRQS; i++)
set_bit(i, (unsigned long *) &mask[0]);
- u300_enable_intcon_clock();
vic_init((void __iomem *) U300_INTCON0_VBASE, 0, mask[0], mask[0]);
vic_init((void __iomem *) U300_INTCON1_VBASE, 32, mask[1], mask[1]);
}
@@ -1561,13 +1571,6 @@ static void __init u300_init_check_chip(void)
printk(KERN_INFO "Initializing U300 system on %s baseband chip " \
"(chip ID 0x%04x)\n", chipname, val);
-#ifdef CONFIG_MACH_U300_BS26
- if ((val & 0xFF00U) != 0xc800) {
- printk(KERN_ERR "Platform configured for BS25/BS26 " \
- "with DB3150 but %s detected, expect problems!",
- chipname);
- }
-#endif
#ifdef CONFIG_MACH_U300_BS330
if ((val & 0xFF00U) != 0xd800) {
printk(KERN_ERR "Platform configured for BS330 " \
@@ -1642,12 +1645,10 @@ void __init u300_init_devices(void)
u300_spi_init(&pl022_device);
/* Register the AMBA devices in the AMBA bus abstraction layer */
- u300_clock_primecells();
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
amba_device_register(d, &iomem_resource);
}
- u300_unclock_primecells();
u300_assign_physmem();
diff --git a/arch/arm/mach-u300/dummyspichip.c b/arch/arm/mach-u300/dummyspichip.c
index 5f55012b7c9..03f79361259 100644
--- a/arch/arm/mach-u300/dummyspichip.c
+++ b/arch/arm/mach-u300/dummyspichip.c
@@ -46,7 +46,6 @@ static ssize_t dummy_looptest(struct device *dev,
* struct, this is just used here to alter the behaviour of the chip
* in order to perform tests.
*/
- struct pl022_config_chip *chip_info = spi->controller_data;
int status;
u8 txbuf[14] = {0xDE, 0xAD, 0xBE, 0xEF, 0x2B, 0xAD,
0xCA, 0xFE, 0xBA, 0xBE, 0xB1, 0x05,
@@ -72,7 +71,7 @@ static ssize_t dummy_looptest(struct device *dev,
* Force chip to 8 bit mode
* WARNING: NEVER DO THIS IN REAL DRIVER CODE, THIS SHOULD BE STATIC!
*/
- chip_info->data_size = SSP_DATA_BITS_8;
+ spi->bits_per_word = 8;
/* You should NOT DO THIS EITHER */
spi->master->setup(spi);
@@ -159,7 +158,7 @@ static ssize_t dummy_looptest(struct device *dev,
* Force chip to 16 bit mode
* WARNING: NEVER DO THIS IN REAL DRIVER CODE, THIS SHOULD BE STATIC!
*/
- chip_info->data_size = SSP_DATA_BITS_16;
+ spi->bits_per_word = 16;
/* You should NOT DO THIS EITHER */
spi->master->setup(spi);
diff --git a/arch/arm/mach-u300/include/mach/gpio.h b/arch/arm/mach-u300/include/mach/gpio.h
index 7b1fc984abb..d5a71abcbae 100644
--- a/arch/arm/mach-u300/include/mach/gpio.h
+++ b/arch/arm/mach-u300/include/mach/gpio.h
@@ -273,6 +273,9 @@ extern void gpio_pullup(unsigned gpio, int value);
extern int gpio_get_value(unsigned gpio);
extern void gpio_set_value(unsigned gpio, int value);
+#define gpio_get_value_cansleep gpio_get_value
+#define gpio_set_value_cansleep gpio_set_value
+
/* wrappers to sleep-enable the previous two functions */
static inline unsigned gpio_to_irq(unsigned gpio)
{
diff --git a/arch/arm/mach-u300/include/mach/memory.h b/arch/arm/mach-u300/include/mach/memory.h
index ab000df7fc0..bf134bcc129 100644
--- a/arch/arm/mach-u300/include/mach/memory.h
+++ b/arch/arm/mach-u300/include/mach/memory.h
@@ -35,14 +35,6 @@
#endif
/*
- * TCM memory whereabouts
- */
-#define ITCM_OFFSET 0xffff2000
-#define ITCM_END 0xffff3fff
-#define DTCM_OFFSET 0xffff4000
-#define DTCM_END 0xffff5fff
-
-/*
* We enable a real big DMA buffer if need be.
*/
#define CONSISTENT_DMA_SIZE SZ_4M
diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c
index 88506d03059..de1ac9ad221 100644
--- a/arch/arm/mach-u300/mmc.c
+++ b/arch/arm/mach-u300/mmc.c
@@ -74,16 +74,16 @@ static void _mmci_callback(struct work_struct *ws)
mdelay(20);
- mmci_card->mmc_inserted = !!gpio_get_value(U300_GPIO_PIN_MMC_CD);
+ mmci_card->mmc_inserted = !gpio_get_value(U300_GPIO_PIN_MMC_CD);
input_report_switch(mmci_card->mmc_input, KEY_INSERT,
- !mmci_card->mmc_inserted);
+ mmci_card->mmc_inserted);
input_sync(mmci_card->mmc_input);
pr_debug("MMC/SD card was %s\n",
- mmci_card->mmc_inserted ? "removed" : "inserted");
+ mmci_card->mmc_inserted ? "inserted" : "removed");
- enable_irq_on_gpio_pin(U300_GPIO_PIN_MMC_CD, !mmci_card->mmc_inserted);
+ enable_irq_on_gpio_pin(U300_GPIO_PIN_MMC_CD, mmci_card->mmc_inserted);
}
int __devinit mmc_init(struct amba_device *adev)
diff --git a/arch/arm/mach-u300/spi.c b/arch/arm/mach-u300/spi.c
index f0e887bea30..edb2c0d255c 100644
--- a/arch/arm/mach-u300/spi.c
+++ b/arch/arm/mach-u300/spi.c
@@ -30,8 +30,6 @@ static void select_dummy_chip(u32 chipselect)
}
struct pl022_config_chip dummy_chip_info = {
- /* Nominally this is LOOPBACK_DISABLED, but this is our dummy chip! */
- .lbm = LOOPBACK_ENABLED,
/*
* available POLLING_TRANSFER and INTERRUPT_TRANSFER,
* DMA_TRANSFER does not work
@@ -42,14 +40,8 @@ struct pl022_config_chip dummy_chip_info = {
.hierarchy = SSP_MASTER,
/* 0 = drive TX even as slave, 1 = do not drive TX as slave */
.slave_tx_disable = 0,
- /* LSB first */
- .endian_tx = SSP_TX_LSB,
- .endian_rx = SSP_RX_LSB,
- .data_size = SSP_DATA_BITS_8, /* used to be 12 in some default */
.rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
.tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
- .clk_phase = SSP_CLK_SECOND_EDGE,
- .clk_pol = SSP_CLK_POL_IDLE_LOW,
.ctrl_len = SSP_BITS_12,
.wait_state = SSP_MWIRE_WAIT_ZERO,
.duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
@@ -75,7 +67,7 @@ static struct spi_board_info u300_spi_devices[] = {
.bus_num = 0, /* Only one bus on this chip */
.chip_select = 0,
/* Means SPI_CS_HIGH, change if e.g low CS */
- .mode = 0,
+ .mode = SPI_MODE_1 | SPI_LSB_FIRST | SPI_LOOP,
},
#endif
};
diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c
index 26d26f5100f..3fc4472719b 100644
--- a/arch/arm/mach-u300/timer.c
+++ b/arch/arm/mach-u300/timer.c
@@ -15,6 +15,8 @@
#include <linux/clocksource.h>
#include <linux/types.h>
#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <mach/hardware.h>
@@ -23,7 +25,8 @@
#include <asm/mach/time.h>
#include <asm/mach/irq.h>
-#include "clock.h"
+/* Be able to sleep for atleast 4 seconds (usually more) */
+#define APPTIMER_MIN_RANGE 4
/*
* APP side special timer registers
@@ -307,8 +310,6 @@ static struct clock_event_device clockevent_u300_1mhz = {
.name = "GPT1",
.rating = 300, /* Reasonably fast and accurate clock event */
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- /* 22 calculated using the algorithm in arch/mips/kernel/time.c */
- .shift = 22,
.set_next_event = u300_set_next_event,
.set_mode = u300_set_mode,
};
@@ -341,8 +342,6 @@ static struct clocksource clocksource_u300_1mhz = {
.rating = 300, /* Reasonably fast and accurate clock source */
.read = u300_get_cycles,
.mask = CLOCKSOURCE_MASK(32), /* 32 bits */
- /* 22 calculated using the algorithm in arch/mips/kernel/time.c */
- .shift = 22,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -367,7 +366,15 @@ unsigned long long notrace sched_clock(void)
*/
static void __init u300_timer_init(void)
{
- u300_enable_timer_clock();
+ struct clk *clk;
+ unsigned long rate;
+
+ /* Clock the interrupt controller */
+ clk = clk_get_sys("apptimer", NULL);
+ BUG_ON(IS_ERR(clk));
+ clk_enable(clk);
+ rate = clk_get_rate(clk);
+
/*
* Disable the "OS" and "DD" timers - these are designed for Symbian!
* Example usage in cnh1601578 cpu subsystem pd_timer_app.c
@@ -405,15 +412,14 @@ static void __init u300_timer_init(void)
writel(U300_TIMER_APP_EGPT2_TIMER_ENABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT2);
- /* This is a pure microsecond clock source */
- clocksource_u300_1mhz.mult =
- clocksource_khz2mult(1000, clocksource_u300_1mhz.shift);
+ clocksource_calc_mult_shift(&clocksource_u300_1mhz,
+ rate, APPTIMER_MIN_RANGE);
if (clocksource_register(&clocksource_u300_1mhz))
printk(KERN_ERR "timer: failed to initialize clock "
"source %s\n", clocksource_u300_1mhz.name);
- clockevent_u300_1mhz.mult =
- div_sc(1000000, NSEC_PER_SEC, clockevent_u300_1mhz.shift);
+ clockevents_calc_mult_shift(&clockevent_u300_1mhz,
+ rate, APPTIMER_MIN_RANGE);
/* 32bit counter, so 32bits delta is max */
clockevent_u300_1mhz.max_delta_ns =
clockevent_delta2ns(0xffffffff, &clockevent_u300_1mhz);
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 6625e5bbf4d..52734fd52d2 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -1,16 +1,19 @@
if ARCH_U8500
-config UX500_SOC_COMMON
+config UX500_SOC_DB8500
bool
+ depends on (MACH_U8500_MOP || MACH_U8500_SIMULATOR || MACH_U8500_PDP)
default y
- select ARM_GIC
- select HAS_MTU
- select NOMADIK_GPIO
-config UX500_SOC_DB8500
+config UX500_SOC_DB5500
+ bool
+ default y
+ depends on (MACH_U5500_BB || MACH_U5500_SIMULATOR)
+
+config MACH_SVP8500V1
bool
-config UX500_SOC_DB5500
+config MACH_SVP8500V2
bool
choice
@@ -18,25 +21,208 @@ choice
default MACH_U8500_MOP
config MACH_U8500_MOP
- bool "U8500 Development platform"
- select UX500_SOC_DB8500
+ bool "U8500 MOP500/HREF"
+ select CPU_V7
+ select ARM_GIC
+ select SMP
+ help
+ Supports MOP500 target board
+
+config MACH_U8500_PDP
+ bool "U8500 PDP"
+ select CPU_V7
+ select ARM_GIC
+ select SMP
+ help
+ Supports PDP target board
+
+config MACH_U5500_BB
+ bool "U5500 Big Board"
+ select CPU_V7
+ select ARM_GIC
+ select SMP
help
- Include support for mop500 development platform
- based on U8500 architecture. The platform is based
- on early drop silicon version of 8500.
+ Supports Big Board target
-config MACH_U5500
- bool "U5500 Development platform"
- select UX500_SOC_DB5500
+config MACH_U8500_SIMULATOR
+ bool "U8500 Simulator (SVP8500)"
+ select CPU_V7
+ select ARM_GIC
+ select SMP
+ select MACH_SVP8500V1
+ select MACH_SVP8500V2
help
- Include support for the U5500 development platform.
+ Supports Simulation for u8500 platform
+
+config MACH_U5500_SIMULATOR
+ bool "U5500 Simulator (SVP5500)"
+ select CPU_V7
+ select ARM_GIC
+ select SMP
+ help
+ Supports Simulation for u5500(FairBanks) platform
+
endchoice
+choice
+ prompt "Ux500 UIB Keylayout"
+ default KEYLAYOUT_LAYOUT1
+
+config KEYLAYOUT_LAYOUT1
+ bool "UIB Keylayout 1; for generic users"
+ help
+ Supported keylayout for some numerics, power/call buttons,
+ volume control etc
+
+config KEYLAYOUT_LAYOUT2
+ bool "UIB Keylayout 2; for connectivity users"
+ help
+ Supports keylayout numerics 0-9, left/right/up/down/back/
+ enter keys and special character "."(dot)
+
+endchoice
+
+config U8500_CPUIDLE
+ tristate "CPUIdle support"
+ depends on UX500_SOC_DB8500 && CPU_IDLE && U8500_PRCMU
+ default y
+ select GENERIC_CLOCKEVENTS_BROADCAST
+ select U8500_CONTEXT
+ select UX500_CONTEXT
+ help
+ Add support for CPUIdle for U8500
+
+config U8500_CPUFREQ
+ tristate "CPUFreq support"
+ depends on UX500_SOC_DB8500 && CPU_FREQ
+ default y
+ help
+ Add support for CPU Frequency scaling for U8500
+
+config U8500_PM
+ tristate "PM Support"
+ depends on UX500_SOC_DB8500 && PM
+ default y
+ select U8500_CONTEXT
+ select UX500_CONTEXT
+ help
+ Add support for PM features for U8500
+
+config U8500_PRCMU_TIMER
+ bool "PRCMU Timer clocksource (BROKEN!)"
+ depends on UX500_SOC_DB8500
+ help
+ Add support for an always on clocksource, required for
+ proper cpuidle and suspend. NOTE: Hardware issues with
+ this timer! (It goes backwards sometimes.)
+
+config U8500_SUSPEND
+ bool "Suspend to mem and standby support"
+ depends on UX500_SOC_DB8500 && PM
+ select U8500_CONTEXT
+ select UX500_CONTEXT
+ help
+ Add support for suspend.
+
+config U8500_PRCMU
+ bool "U8500 PRCMU support"
+ depends on (MACH_U8500_MOP || MACH_U8500_PDP)
+ default n
+ help
+ Add support for PRCMU for U8500
+
+config U5500_PRCMU
+ bool "U5500 PRCMU support"
+ depends on MACH_U5500_BB
+ default n
+ help
+ Add support for PRCMU for U5500
+
+config U8500_REGULATOR_DEBUG
+ bool "Regulator debug support"
+ depends on REGULATOR_VIRTUAL_CONSUMER
+ default n
+ help
+ Add support for U8500 regulator debug
+
+config UX500_CONTEXT
+ bool "Context save/restore support for UX500"
+ depends on UX500_SOC_DB8500 || UX500_SOC_DB5500
+
+config U5500_PWM
+ bool "PWM support"
+ default y
+ depends on UX500_SOC_DB5500
+ help
+ Add support for PWM for U5500
+
+config MOP500_SDI
+ bool
+ default y
+ depends on (MACH_U8500_MOP && MMC_U8500 || MACH_U8500_PDP && MMC_U8500)
+
+config ARCH_HAS_CPU_IDLE_WAIT
+ def_bool y
+
config UX500_DEBUG_UART
int "Ux500 UART to use for low-level debug"
- default 2
+ default 2 if UX500_SOC_DB8500
+ default 0 if UX500_SOC_DB5500
help
Choose the UART on which kernel low-level debug messages should be
output.
+
+config SENSORS1P_MOP
+ tristate "HAL and Proximity sensors support"
+ depends on REGULATOR && (GPIO_STMPE2401 || GPIO_TC35892)
+ default y
+ help
+ Add support for Osram's SFH7741 Proximity Sensor and Samsumg
+ HED54XXU11 HAL Switch
+
+config U5500_MODEM_IRQ
+ bool "Modem IRQ support"
+ depends on UX500_SOC_DB5500
+ default y
+ help
+ Add support for handling IRQ:s from modem side
+
+config U5500_MBOX
+ bool "Mailbox support"
+ depends on (UX500_SOC_DB5500 && U5500_MODEM_IRQ)
+ default y
+ help
+ Add support for U5500 mailbox communication with modem side
+
+config MOP500_NUIB
+ bool "MOP500 NUIB"
+ depends on TOUCHSCREEN_SYNAPTICS_I2C_RMI4
+ default y
+ help
+ Add support for the platform data of synaptics rmi4 driver
+
+config TEE_UX500
+ bool "Trusted Execution Environment (TEE) ux500 hardware support"
+ depends on (TEE_SUPPORT && MACH_U8500_MOP)
+ default y
+ help
+ Adds TEE hardware support for ux500 platforms.
+
+config TEE_SVP
+ bool "Trusted Execution Environment (TEE) ux500 SVP support"
+ depends on (TEE_SUPPORT && (MACH_U8500_SIMULATOR || MACH_U5500_SIMULATOR))
+ default y
+ help
+ Adds TEE support for SVP in ux500 platforms.
+
+source "arch/arm/mach-ux500/Kconfig-arch"
+
+
+config U5500_MLOADER_HELPER
+ bool "mLoader helper, mem config from kernel boot args exported to sysfs"
+ default y
+ depends on UX500_SOC_DB5500
+ help
+ Link between boot args and user space program that loads the modem ELF
endif
diff --git a/arch/arm/mach-ux500/Kconfig-arch b/arch/arm/mach-ux500/Kconfig-arch
new file mode 100644
index 00000000000..2ddd4e18c63
--- /dev/null
+++ b/arch/arm/mach-ux500/Kconfig-arch
@@ -0,0 +1,144 @@
+config GPIO_STM
+ bool "STM GPIO driver support"
+ default y
+ help
+ Say yes here to support the STM GPIO device
+
+config U8500_SECURE
+ bool "Support for running in Secure mode"
+ default n
+ help
+ Build the kernel to run in Secure mode.
+
+menu "Debug level for STM drivers"
+config STM_ACODEC_DEBUG
+ int "STM ACODEC Debug Level"
+ depends on U8500_ACODEC
+ default 0
+ help
+ Sets the ACODEC debug ON/OFF for U8500 SoC
+ * 0 OFF
+ * 1 ON
+
+config STM_ALSA_DEBUG
+ int "STM ALSA Debug Level"
+ depends on SND_U8500_ALSA || SND_U8500_ALSA_AB8500
+ default 0
+ help
+ Sets the ALSA debug ON/OFF for U8500 SoC
+ * 0 OFF
+ * 1 ON
+endmenu
+
+#Configuration for MCDE setup
+
+menu "Display selection"
+
+config DISPLAY_GENERIC_PRIMARY
+ bool "Main display support"
+ depends on MACH_U8500_MOP && FB_MCDE
+ default y
+
+choice
+ prompt "Display port type"
+ depends on DISPLAY_GENERIC_PRIMARY
+ default DISPLAY_GENERIC_DSI_PRIMARY
+ help
+ Select the kind of display port used for the primary display
+
+config DISPLAY_GENERIC_DSI_PRIMARY
+ bool "DSI display"
+ select MCDE_DISPLAY_GENERIC_DSI
+ help
+ Say yes here when using a DSI display
+
+config MCDE_DISPLAY_DPI_PRIMARY
+ bool "DPI display"
+ select MCDE_DISPLAY_DPI
+ help
+ Say yes here when using a DPI display
+
+endchoice
+
+config DISPLAY_SONY_SY35560_DSI_PRIMARY
+ bool "Main display support"
+ depends on (MACH_U8500_PDP && FB_MCDE)
+ select MCDE_DISPLAY_SONY_SY35560_DSI
+ default y
+ help
+ Say yes here if main display exists
+
+config DISPLAY_GENERIC_DSI_PRIMARY_VSYNC
+ bool "Enable v-sync for primary display"
+ depends on DISPLAY_GENERIC_DSI_PRIMARY || DISPLAY_SONY_SY35560_DSI_PRIMARY
+ default n
+ help
+ Say yes to enable v-sync for primary display
+
+config DISPLAY_GENERIC_DSI_PRIMARY_ROTATE_180_DEGREES
+ bool "Rotate primary display 180 degrees"
+ depends on DISPLAY_GENERIC_DSI_PRIMARY
+ default n
+ help
+ Say yes to rotate the primary display 180 degrees
+
+config DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC
+ bool "Enable auto sync for primary display"
+ depends on DISPLAY_GENERIC_DSI_PRIMARY
+ default n
+ help
+ Say yes to enable auto sync for primary display
+
+config SONY_SY35560_ENABLE_ESD_CHECK
+ bool "Enable esd status check for primary display"
+ depends on DISPLAY_SONY_SY35560_DSI_PRIMARY
+ default n
+ help
+ Say yes to enable esd status check for primary display
+
+config DISPLAY_GENERIC_DSI_SECONDARY
+ bool "Sub display support"
+ depends on MACH_U8500_MOP && FB_MCDE
+ select MCDE_DISPLAY_GENERIC_DSI
+ default n
+ help
+ Say yes here if sub display exists
+
+config DISPLAY_GENERIC_DSI_SECONDARY_VSYNC
+ bool "Enable v-sync for secondary display"
+ depends on DISPLAY_GENERIC_DSI_SECONDARY
+ default n
+ help
+ Say yes to enable v-sync for secondary display
+
+config DISPLAY_GENERIC_DSI_SECONDARY_AUTO_SYNC
+ bool "Enable auto sync for secondary display"
+ depends on DISPLAY_GENERIC_DSI_SECONDARY
+ default n
+ help
+ Say yes to enable auto sync for secondary display
+
+config DISPLAY_AB8500_TERTIARY
+ bool "AB8500 TVout display support"
+ depends on MACH_U8500_MOP && !AV8100_SDTV && FB_MCDE
+ select MCDE_DISPLAY_AB8500_DENC
+ default n
+ help
+ Say yes here if tv out support
+
+config DISPLAY_AV8100_TERTIARY
+ bool "AV8100 HDMI/CVBS display support"
+ depends on MACH_U8500_MOP && FB_MCDE
+ select MCDE_DISPLAY_AV8100
+ default n
+ help
+ Say yes here if HDMI output support
+
+config AV8100_SDTV
+ bool "set AV8100 in CVBS mode"
+ depends on DISPLAY_AV8100_TERTIARY
+ default n
+ help
+ Say yes here if tv out support
+endmenu
+
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index 4556aea9c3c..108d12ded9c 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -2,10 +2,54 @@
# Makefile for the linux kernel, U8500 machine.
#
-obj-y := clock.o cpu.o devices.o
-obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o devices-db5500.o
-obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o
-obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o
-obj-$(CONFIG_MACH_U5500) += board-u5500.o
+ifeq ($(CONFIG_CRYPTO_DEV_UX500_HASH), m)
+ CFLAGS_devices.o += -DCONFIG_CRYPTO_DEV_UX500_HASH
+ CFLAGS_board-mop500.o += -DCONFIG_CRYPTO_DEV_UX500_HASH
+endif
+obj-y := clock.o timer.o timer-rtt.o gpio.o \
+ devices-common.o pm-common.o
+obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o devices-db5500.o \
+ dma-db5500.o
+obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o \
+ dma-db8500.o hsi.o mcde.o
+obj-$(CONFIG_REGULATOR) += regulator-u8500.o \
+ board-mop500-regulators.o
+obj-$(CONFIG_U8500_REGULATOR_DEBUG) += virt-regulator-u8500.o
+obj-$(CONFIG_ARCH_U8500) += devices.o cpu.o
+obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o board-mop500-msp.o
+obj-$(CONFIG_MACH_U8500_PDP) += board-mop500.o board-mop500-msp.o # until pdp-specific files are there
+obj-$(CONFIG_MOP500_SDI) += board-mop500-sdi.o
+obj-$(CONFIG_U8500_PRCMU_TIMER) += timer-db8500-prcm.o
+obj-$(CONFIG_MACH_U8500_PDP) += board-pdp-mcde.o
+obj-$(CONFIG_MACH_U8500_MOP) += board-mop500-mcde.o
+obj-$(CONFIG_MACH_U8500_SIMULATOR) += board-mop500.o board-mop500-msp.o
+obj-$(CONFIG_MACH_U5500_SIMULATOR) += board-u5500.o
+obj-$(CONFIG_U8500_CPUIDLE) += cpuidle.o
+obj-$(CONFIG_UX500_CONTEXT) += context.o context_arm.o context-db8500.o context-db5500.o
+
+obj-$(CONFIG_U8500_CPUFREQ) += cpufreq.o
+obj-$(CONFIG_U8500_PM) += pm.o savecontext.o
+obj-$(CONFIG_U8500_SUSPEND) += suspend.o
+obj-$(CONFIG_U8500_PRCMU) += prcmu-db8500.o
+obj-$(CONFIG_U5500_PRCMU) += prcmu-db5500.o
+obj-$(CONFIG_SENSORS1P_MOP) += sensors1p.o
+obj-$(CONFIG_MACH_U5500_BB) += board-u5500.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
+obj-$(CONFIG_USB) += musb_db8500.o
+obj-$(CONFIG_U5500_MLOADER_HELPER) += mloader_helper.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
+obj-$(CONFIG_U5500_MODEM_IRQ) += modem_irq.o
+obj-$(CONFIG_U5500_MBOX) += mbox.o
+obj-$(CONFIG_U5500_PWM) += pwm.o
+obj-$(CONFIG_MOP500_NUIB) += board-mop500-nuib.o
+obj-$(CONFIG_TEE_UX500) += tee_ux500.o
+obj-$(CONFIG_TEE_SVP) += tee_service_svp.o
+obj-$(CONFIG_TEE_SVP) += tee_ta_start_modem_svp.o
+
+ifeq ($(CONFIG_MFD_CG2900), m)
+obj-y += cg2900_devices.o
+else
+obj-$(CONFIG_MFD_CG2900) += cg2900_devices.o
+endif
+
diff --git a/arch/arm/mach-ux500/board-mop500-mcde.c b/arch/arm/mach-ux500/board-mop500-mcde.c
new file mode 100644
index 00000000000..1e71410ad98
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-mcde.c
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <video/av8100.h>
+#include <video/mcde_display.h>
+#include <video/mcde_display-generic_dsi.h>
+#include <video/mcde_display-vuib500-dpi.h>
+#include <video/mcde_display-av8100.h>
+#include <video/mcde_display-ab8500.h>
+#include <video/mcde_fb.h>
+#include <video/mcde_dss.h>
+#include <mach/ab8500_denc.h>
+
+#define DSI_UNIT_INTERVAL_0 0x9
+#define DSI_UNIT_INTERVAL_1 0x9
+#define DSI_UNIT_INTERVAL_2 0x6
+
+#define PRIMARY_DISPLAY_ID 0
+#define SECONDARY_DISPLAY_ID 1
+#define TERTIARY_DISPLAY_ID 2
+
+#ifdef CONFIG_FB_MCDE
+
+#ifdef CONFIG_MCDE_DISPLAY_DPI_PRIMARY
+static bool rotate_main;
+#else
+static bool rotate_main = true;
+#endif
+static int display_initialized_during_boot;
+
+static int __init startup_graphics_setup(char *str)
+{
+
+ if (get_option(&str, &display_initialized_during_boot) != 1)
+ display_initialized_during_boot = 0;
+
+ switch (display_initialized_during_boot) {
+ case 1:
+ pr_info("Startup graphics support\n");
+ break;
+ case 0:
+ default:
+ pr_info("No startup graphics supported\n");
+ break;
+ };
+
+ return 1;
+}
+__setup("startup_graphics=", startup_graphics_setup);
+
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY
+static struct mcde_port port0 = {
+ .type = MCDE_PORTTYPE_DSI,
+ .mode = MCDE_PORTMODE_CMD,
+ .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP,
+ .ifc = 1,
+ .link = 0,
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC
+ .sync_src = MCDE_SYNCSRC_OFF,
+ .update_auto_trig = true,
+#else
+ .sync_src = MCDE_SYNCSRC_BTA,
+ .update_auto_trig = false,
+#endif
+ .phy = {
+ .dsi = {
+ .virt_id = 0,
+ .num_data_lanes = 2,
+ .ui = DSI_UNIT_INTERVAL_0,
+ .clk_cont = false,
+ },
+ },
+};
+
+struct mcde_display_generic_platform_data generic_display0_pdata = {
+ .reset_gpio = EGPIO_PIN_15,
+ .reset_delay = 1,
+#ifdef CONFIG_REGULATOR
+ .regulator_id = "v-display",
+ .min_supply_voltage = 2500000, /* 2.5V */
+ .max_supply_voltage = 2700000 /* 2.7V */
+#endif
+};
+
+struct mcde_display_device generic_display0 = {
+ .name = "mcde_disp_generic",
+ .id = PRIMARY_DISPLAY_ID,
+ .port = &port0,
+ .chnl_id = MCDE_CHNL_A,
+ .fifo = MCDE_FIFO_C0,
+ .default_pixel_format = MCDE_OVLYPIXFMT_RGB565,
+ .native_x_res = 864,
+ .native_y_res = 480,
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_VSYNC
+ .synchronized_update = true,
+#else
+ .synchronized_update = false,
+#endif
+ /* TODO: Remove rotation buffers once ESRAM driver is completed */
+ .rotbuf1 = U8500_ESRAM_BASE + 0x20000 * 4,
+ .rotbuf2 = U8500_ESRAM_BASE + 0x20000 * 4 + 0x10000,
+ .dev = {
+ .platform_data = &generic_display0_pdata,
+ },
+};
+#endif /* CONFIG_DISPLAY_GENERIC_DSI_PRIMARY */
+
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY
+static struct mcde_port subdisplay_port = {
+ .type = MCDE_PORTTYPE_DSI,
+ .mode = MCDE_PORTMODE_CMD,
+ .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP,
+ .ifc = 1,
+ .link = 1,
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY_AUTO_SYNC
+ .sync_src = MCDE_SYNCSRC_OFF,
+ .update_auto_trig = true,
+#else
+ .sync_src = MCDE_SYNCSRC_BTA,
+ .update_auto_trig = false,
+#endif
+ .phy = {
+ .dsi = {
+ .virt_id = 0,
+ .num_data_lanes = 2,
+ .ui = DSI_UNIT_INTERVAL_1,
+ .clk_cont = false,
+ },
+ },
+
+};
+
+static struct mcde_display_generic_platform_data generic_subdisplay_pdata = {
+ .reset_gpio = EGPIO_PIN_14,
+ .reset_delay = 1,
+#ifdef CONFIG_REGULATOR
+ .regulator_id = "v-display",
+ .min_supply_voltage = 2500000, /* 2.5V */
+ .max_supply_voltage = 2700000 /* 2.7V */
+#endif
+};
+
+static struct mcde_display_device generic_subdisplay = {
+ .name = "mcde_disp_generic_subdisplay",
+ .id = SECONDARY_DISPLAY_ID,
+ .port = &subdisplay_port,
+ .chnl_id = MCDE_CHNL_C1,
+ .fifo = MCDE_FIFO_C1,
+ .default_pixel_format = MCDE_OVLYPIXFMT_RGB565,
+ .native_x_res = 864,
+ .native_y_res = 480,
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY_VSYNC
+ .synchronized_update = true,
+#else
+ .synchronized_update = false,
+#endif
+ .dev = {
+ .platform_data = &generic_subdisplay_pdata,
+ },
+};
+#endif /* CONFIG_DISPLAY_GENERIC_DSI_SECONDARY */
+
+#ifdef CONFIG_MCDE_DISPLAY_DPI_PRIMARY
+static struct mcde_port port0 = {
+ .type = MCDE_PORTTYPE_DPI,
+ .pixel_format = MCDE_PORTPIXFMT_DPI_24BPP,
+ .ifc = 0,
+ .link = 1, /* DPI channel B can only be on link 1 */
+ .sync_src = MCDE_SYNCSRC_OFF, /* sync from output formatter */
+ .update_auto_trig = true,
+ .phy = {
+ .dpi = {
+ .tv_mode = false,
+ .clock_div = 2,
+ .polarity = DPI_ACT_LOW_VSYNC | DPI_ACT_LOW_HSYNC,
+ },
+ },
+};
+
+struct mcde_display_dpi_platform_data generic_display0_pdata = {0};
+
+static int dpi_display_platform_enable(struct mcde_display_device *ddev)
+{
+ int res = 0;
+
+ dev_info(&ddev->dev, "%s\n", __func__);
+ res = stm_gpio_altfuncenable(GPIO_ALT_LCD_D_24);
+ if (res != 0)
+ goto alt_func_24bpp_failed;
+
+ res = stm_gpio_altfuncenable(GPIO_ALT_LCDB);
+ if (res != 0)
+ goto alt_func_lcd_failed;
+
+ return res;
+
+alt_func_lcd_failed:
+ (void) stm_gpio_altfuncdisable(GPIO_ALT_LCD_D_24);
+alt_func_24bpp_failed:
+ dev_warn(&ddev->dev, "Failure during %s\n", __func__);
+ return res;
+}
+
+static int dpi_display_platform_disable(struct mcde_display_device *ddev)
+{
+ int res;
+
+ dev_info(&ddev->dev, "%s\n", __func__);
+
+ res = stm_gpio_altfuncdisable(GPIO_ALT_LCDB);
+ if (res != 0)
+ goto alt_func_lcd_failed;
+
+ res = stm_gpio_altfuncdisable(GPIO_ALT_LCD_D_24);
+ if (res != 0)
+ goto alt_func_24bpp_failed;
+
+ return res;
+alt_func_24bpp_failed:
+ (void) stm_gpio_altfuncenable(GPIO_ALT_LCDB);
+alt_func_lcd_failed:
+ dev_warn(&ddev->dev, "Failure during %s\n", __func__);
+ return res;
+
+}
+
+struct mcde_display_device generic_display0 = {
+ .name = "mcde_display_dpi",
+ .id = 0,
+ .port = &port0,
+ .chnl_id = MCDE_CHNL_B,
+ .fifo = MCDE_FIFO_B,
+ .default_pixel_format = MCDE_OVLYPIXFMT_RGB565,
+ .native_x_res = 640,
+ .native_y_res = 480,
+ /* .synchronized_update: Don't care: port is set to update_auto_trig */
+ .dev = {
+ .platform_data = &generic_display0_pdata,
+ },
+ .platform_enable = dpi_display_platform_enable,
+ .platform_disable = dpi_display_platform_disable,
+};
+#endif /* CONFIG_MCDE_DISPLAY_DPI_PRIMARY */
+
+#ifdef CONFIG_DISPLAY_AB8500_TERTIARY
+static struct mcde_port port_tvout1 = {
+ .type = MCDE_PORTTYPE_DPI,
+ .pixel_format = MCDE_PORTPIXFMT_DPI_24BPP,
+ .ifc = 0,
+ .link = 1, /* channel B */
+ .sync_src = MCDE_SYNCSRC_OFF,
+ .update_auto_trig = true,
+ .phy = {
+ .dpi = {
+ .bus_width = 4, /* DDR mode */
+ .tv_mode = true,
+ .clock_div = MCDE_PORT_DPI_NO_CLOCK_DIV,
+ },
+ },
+};
+
+static struct ab8500_display_platform_data ab8500_display_pdata = {
+ /* REVIEW use "#ifdef CONFIG_REGULATOR" as with other displays */
+ /* TODO use this ID as soon as we switch to newer kernel with support or
+ * ab8500 TVout regulator
+ .regulator_id = "v-tvout",
+ */
+ /* REVIEW change name: use transform instead of convert? */
+ .rgb_2_yCbCr_convert = {
+ .matrix = {
+ {0x42, 0x81, 0x19},
+ {0xffda, 0xffb6, 0x70},
+ {0x70, 0xffa2, 0xffee},
+ },
+ .offset = {0x80, 0x10, 0x80},
+ }
+};
+
+static int ab8500_platform_enable(struct mcde_display_device *ddev)
+{
+ int res = 0;
+ /* probe checks for pdata */
+ struct ab8500_display_platform_data *pdata = ddev->dev.platform_data;
+
+ dev_info(&ddev->dev, "%s\n", __func__);
+ res = stm_gpio_altfuncenable(GPIO_ALT_LCDA_CLK);
+ if (res != 0)
+ goto alt_func_clk_failed;
+ res = stm_gpio_altfuncenable(GPIO_ALT_LCD_PANELB);
+ if (res != 0)
+ goto alt_func_panel_failed;
+
+ if (pdata->regulator) {
+ res = regulator_enable(pdata->regulator);
+ if (res != 0)
+ goto regu_failed;
+ }
+
+ return res;
+
+regu_failed:
+ (void) stm_gpio_altfuncdisable(GPIO_ALT_LCD_PANELB);
+alt_func_panel_failed:
+ (void) stm_gpio_altfuncdisable(GPIO_ALT_LCDA_CLK);
+alt_func_clk_failed:
+ dev_warn(&ddev->dev, "Failure during %s\n", __func__);
+ return res;
+}
+
+static int ab8500_platform_disable(struct mcde_display_device *ddev)
+{
+ int res;
+ /* probe checks for pdata */
+ struct ab8500_display_platform_data *pdata = ddev->dev.platform_data;
+
+ dev_info(&ddev->dev, "%s\n", __func__);
+
+ res = stm_gpio_altfuncdisable(GPIO_ALT_LCD_PANELB);
+ if (res != 0)
+ goto alt_func_failed;
+
+ if (pdata->regulator) {
+ res = regulator_disable(pdata->regulator);
+ if (res != 0)
+ goto regu_failed;
+ }
+
+ return res;
+regu_failed:
+ (void) stm_gpio_altfuncenable(GPIO_ALT_LCD_PANELB);
+alt_func_failed:
+ dev_warn(&ddev->dev, "Failure during %s\n", __func__);
+ return res;
+
+}
+
+static struct mcde_display_device tvout_ab8500_display = {
+ .name = "mcde_tv_ab8500",
+ .id = TERTIARY_DISPLAY_ID,
+ .port = &port_tvout1,
+ .chnl_id = MCDE_CHNL_B,
+ .fifo = MCDE_FIFO_B,
+ .default_pixel_format = MCDE_OVLYPIXFMT_RGB565,
+ .native_x_res = 720,
+ .native_y_res = 576,
+ /* .synchronized_update: Don't care: port is set to update_auto_trig */
+ .dev = {
+ .platform_data = &ab8500_display_pdata,
+ },
+
+ /*
+ * We might need to describe the std here:
+ * - there are different PAL / NTSC formats (do they require MCDE
+ * settings?)
+ */
+ .platform_enable = ab8500_platform_enable,
+ .platform_disable = ab8500_platform_disable,
+};
+#endif /* CONFIG_DISPLAY_AB8500_TERTIARY */
+
+#ifdef CONFIG_DISPLAY_AV8100_TERTIARY
+static struct mcde_port port2 = {
+ .type = MCDE_PORTTYPE_DSI,
+ .mode = MCDE_PORTMODE_CMD,
+ .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP,
+ .ifc = 1,
+ .link = 2,
+#ifdef CONFIG_AV8100_HWTRIG_I2SDAT3
+ .sync_src = MCDE_SYNCSRC_TE1,
+#else
+ .sync_src = MCDE_SYNCSRC_TE0,
+#endif /* CONFIG_AV8100_HWTRIG_I2SDAT3 */
+ .update_auto_trig = true,
+ .phy = {
+ .dsi = {
+ .virt_id = 0,
+ .num_data_lanes = 2,
+ .ui = DSI_UNIT_INTERVAL_2,
+ .clk_cont = false,
+ },
+ },
+};
+
+struct mcde_display_hdmi_platform_data av8100_hdmi_pdata = {
+ .reset_gpio = 0,
+ .reset_delay = 1,
+ .regulator_id = NULL, /* TODO: "display_main" */
+ .ddb_id = 1,
+ .rgb_2_yCbCr_convert = {
+ .matrix = {
+ {0x42, 0x81, 0x19},
+ {0xffda, 0xffb6, 0x70},
+ {0x70, 0xffa2, 0xffee},
+ },
+ .offset = {0x80, 0x10, 0x80},
+ }
+};
+
+static int av8100_platform_enable(struct mcde_display_device *dev)
+{
+ int ret;
+ struct mcde_display_hdmi_platform_data *pdata =
+ dev->dev.platform_data;
+
+ ret = stm_gpio_altfuncenable(GPIO_ALT_LCD_PANELA);
+ if (ret)
+ goto alt_func_failed;
+
+ if (pdata->reset_gpio)
+ gpio_set_value(pdata->reset_gpio, pdata->reset_high);
+ if (pdata->regulator)
+ ret = regulator_enable(pdata->regulator);
+alt_func_failed:
+ return ret;
+}
+
+static int av8100_platform_disable(struct mcde_display_device *dev)
+{
+ int ret;
+ struct mcde_display_hdmi_platform_data *pdata =
+ dev->dev.platform_data;
+
+ ret = stm_gpio_altfuncdisable(GPIO_ALT_LCD_PANELA);
+ if (ret)
+ goto alt_func_failed;
+
+ if (pdata->reset_gpio)
+ gpio_set_value(pdata->reset_gpio, !pdata->reset_high);
+ if (pdata->regulator)
+ ret = regulator_disable(pdata->regulator);
+alt_func_failed:
+ return ret;
+}
+
+static struct mcde_display_device av8100_hdmi = {
+ .name = "av8100_hdmi",
+ .id = TERTIARY_DISPLAY_ID,
+ .port = &port2,
+ .chnl_id = MCDE_CHNL_B,
+ .fifo = MCDE_FIFO_B,
+ .default_pixel_format = MCDE_OVLYPIXFMT_RGB565,
+#ifdef CONFIG_AV8100_SDTV
+ .native_x_res = 720,
+ .native_y_res = 576,
+#else
+ .native_x_res = 1280,
+ .native_y_res = 720,
+#endif
+ .synchronized_update = true,
+ .dev = {
+ .platform_data = &av8100_hdmi_pdata,
+ },
+ .platform_enable = av8100_platform_enable,
+ .platform_disable = av8100_platform_disable,
+};
+#endif /* CONFIG_DISPLAY_AV8100_TERTIARY */
+
+static struct fb_info *fbs[3] = { NULL, NULL, NULL };
+static struct mcde_display_device *displays[3] = { NULL, NULL, NULL };
+/*
+* This function will create the framebuffer for the display that is registered.
+*/
+static int display_postregistered_callback(struct notifier_block *nb,
+ unsigned long event, void *dev)
+{
+ struct mcde_display_device *ddev = dev;
+ u16 width, height;
+ u16 virtual_width, virtual_height;
+ u32 rotate = FB_ROTATE_UR;
+
+ if (event != MCDE_DSS_EVENT_DISPLAY_REGISTERED)
+ return 0;
+
+ if (ddev->id < PRIMARY_DISPLAY_ID || ddev->id >= ARRAY_SIZE(fbs))
+ return 0;
+
+ mcde_dss_get_native_resolution(ddev, &width, &height);
+
+ if (ddev->id == PRIMARY_DISPLAY_ID && rotate_main) {
+ swap(width, height);
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATE_180_DEGREES
+ rotate = FB_ROTATE_CCW;
+#else
+ rotate = FB_ROTATE_CW;
+#endif
+ }
+
+ virtual_width = width;
+ virtual_height = height * 2;
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC
+ if (ddev->id == PRIMARY_DISPLAY_ID)
+ virtual_height = height;
+#endif
+
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY_AUTO_SYNC
+ if (ddev->id == SECONDARY_DISPLAY_ID)
+ virtual_height = height;
+#endif
+
+ /* Create frame buffer */
+ fbs[ddev->id] = mcde_fb_create(ddev,
+ width, height,
+ virtual_width, virtual_height,
+ ddev->default_pixel_format,
+ rotate);
+
+ if (IS_ERR(fbs[ddev->id]))
+ pr_warning("Failed to create fb for display %s\n", ddev->name);
+ else
+ pr_info("Framebuffer created (%s)\n", ddev->name);
+
+ return 0;
+}
+
+static struct notifier_block display_nb = {
+ .notifier_call = display_postregistered_callback,
+};
+
+/*
+* This function is used to refresh the display (lcd, hdmi, tvout) with black
+* when the framebuffer is registered.
+* The main display will not be updated if startup graphics is displayed
+* from u-boot.
+*/
+#if defined(CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_AUTO_SYNC) || \
+ defined(CONFIG_DISPLAY_GENERIC_DSI_SECONDARY_AUTO_SYNC)
+static int framebuffer_postregistered_callback(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ int ret = 0;
+ struct fb_event *event_data = data;
+ struct fb_info *info;
+ struct fb_var_screeninfo var;
+ struct fb_fix_screeninfo fix;
+ struct mcde_fb *mfb;
+ u8 *addr;
+ int i;
+
+ if (event != FB_EVENT_FB_REGISTERED)
+ return 0;
+
+ if (!event_data)
+ return 0;
+
+ info = event_data->info;
+ mfb = to_mcde_fb(info);
+ var = info->var;
+ fix = info->fix;
+ addr = ioremap(fix.smem_start,
+ var.yres_virtual * fix.line_length);
+ memset(addr, 0x00,
+ var.yres_virtual * fix.line_length);
+ /* Apply overlay info */
+ for (i = 0; i < mfb->num_ovlys; i++) {
+ struct mcde_overlay *ovly = mfb->ovlys[i];
+ struct mcde_overlay_info ovly_info;
+ struct mcde_fb *mfb = to_mcde_fb(info);
+ memset(&ovly_info, 0, sizeof(ovly_info));
+ ovly_info.paddr = fix.smem_start +
+ fix.line_length * var.yoffset;
+ if (ovly_info.paddr + fix.line_length * var.yres
+ > fix.smem_start + fix.smem_len)
+ ovly_info.paddr = fix.smem_start;
+ ovly_info.fmt = mfb->pix_fmt;
+ ovly_info.stride = fix.line_length;
+ ovly_info.w = var.xres;
+ ovly_info.h = var.yres;
+ ovly_info.dirty.w = var.xres;
+ ovly_info.dirty.h = var.yres;
+ (void) mcde_dss_apply_overlay(ovly, &ovly_info);
+ ret = mcde_dss_update_overlay(ovly);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+#else
+static int framebuffer_postregistered_callback(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ int ret = 0;
+ struct fb_event *event_data = data;
+ struct fb_info *info;
+ struct fb_var_screeninfo var;
+ struct fb_fix_screeninfo fix;
+ struct mcde_fb *mfb;
+ u8 *addr;
+
+ if (event != FB_EVENT_FB_REGISTERED)
+ return 0;
+
+ if (!event_data)
+ return 0;
+
+ info = event_data->info;
+ mfb = to_mcde_fb(info);
+ if (mfb->id == 0 && display_initialized_during_boot)
+ goto out;
+
+
+ var = info->var;
+ fix = info->fix;
+ addr = ioremap(fix.smem_start,
+ var.yres_virtual * fix.line_length);
+ memset(addr, 0x00,
+ var.yres_virtual * fix.line_length);
+ var.yoffset = var.yoffset ? 0 : var.yres;
+ if (info->fbops->fb_pan_display)
+ ret = info->fbops->fb_pan_display(&var, info);
+out:
+ return ret;
+}
+#endif
+
+
+static struct notifier_block framebuffer_nb = {
+ .notifier_call = framebuffer_postregistered_callback,
+};
+
+int __init init_display_devices(void)
+{
+ int ret;
+
+ ret = fb_register_client(&framebuffer_nb);
+ if (ret)
+ pr_warning("Failed to register framebuffer notifier\n");
+
+ ret = mcde_dss_register_notifier(&display_nb);
+ if (ret)
+ pr_warning("Failed to register dss notifier\n");
+
+#ifdef CONFIG_DISPLAY_GENERIC_PRIMARY
+ if (display_initialized_during_boot)
+ generic_display0.power_mode = MCDE_DISPLAY_PM_STANDBY;
+ ret = mcde_display_device_register(&generic_display0);
+ if (ret)
+ pr_warning("Failed to register generic display device 0\n");
+ displays[0] = &generic_display0;
+#endif
+
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY
+ ret = mcde_display_device_register(&generic_subdisplay);
+ if (ret)
+ pr_warning("Failed to register generic sub display device\n");
+ displays[1] = &generic_subdisplay;
+#endif
+
+#ifdef CONFIG_DISPLAY_AV8100_TERTIARY
+ ret = mcde_display_device_register(&av8100_hdmi);
+ if (ret)
+ pr_warning("Failed to register av8100_hdmi\n");
+ displays[2] = &av8100_hdmi;
+#endif
+#ifdef CONFIG_DISPLAY_AB8500_TERTIARY
+ ret = mcde_display_device_register(&tvout_ab8500_display);
+ if (ret)
+ pr_warning("Failed to register ab8500 tvout device\n");
+ displays[2] = &tvout_ab8500_display;
+#endif
+
+ return ret;
+}
+
+module_init(init_display_devices);
+
+#endif
diff --git a/arch/arm/mach-ux500/board-mop500-msp.c b/arch/arm/mach-ux500/board-mop500-msp.c
new file mode 100644
index 00000000000..dcd70068022
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-msp.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/platform_device.h>
+#include <linux/i2s/i2s.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+
+#include <plat/ste_dma40.h>
+
+#include <mach/ste-dma40-db8500.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/msp.h>
+
+#include "board-mop500.h"
+#include "devices-db8500.h"
+
+static int msp_i2s_init(gpio_alt_function gpio)
+{
+ return stm_gpio_altfuncenable(gpio);
+}
+
+static int msp_i2s_exit(gpio_alt_function gpio)
+{
+ return stm_gpio_altfuncdisable(gpio);
+}
+
+static int msp13_i2s_init(gpio_alt_function gpio)
+{
+ stm_gpio_altfuncenable(gpio);
+
+ /* No error because MSP1 and MSP3 use the same pins */
+ return 0;
+}
+
+static struct stedma40_chan_cfg msp0_dma_rx = {
+ .high_priority = true,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+
+ .src_dev_type = DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+ /* data_width is set during configuration */
+};
+
+static struct stedma40_chan_cfg msp0_dma_tx = {
+ .high_priority = true,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+
+ .src_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX,
+
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+ /* data_width is set during configuration */
+};
+
+static struct msp_i2s_platform_data msp0_platform_data = {
+ .id = MSP_0_I2S_CONTROLLER,
+ .gpio_alt_func = GPIO_ALT_MSP_0,
+ .msp_i2s_dma_rx = &msp0_dma_rx,
+ .msp_i2s_dma_tx = &msp0_dma_tx,
+ .msp_i2s_init = msp_i2s_init,
+ .msp_i2s_exit = msp_i2s_exit,
+};
+
+static struct stedma40_chan_cfg msp1_dma_rx = {
+ .high_priority = true,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+
+ .src_dev_type = DB8500_DMA_DEV30_MSP1_RX, /* v2: MSP3 RX */
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+ /* data_width is set during configuration */
+};
+
+static struct stedma40_chan_cfg msp1_dma_tx = {
+ .high_priority = true,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+
+ .src_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV30_MSP1_TX,
+
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+ /* data_width is set during configuration */
+};
+
+static struct msp_i2s_platform_data msp1_platform_data = {
+ .id = MSP_1_I2S_CONTROLLER,
+ .gpio_alt_func = GPIO_ALT_MSP_1,
+ .msp_i2s_dma_rx = &msp1_dma_rx,
+ .msp_i2s_dma_tx = &msp1_dma_tx,
+ .msp_i2s_init = msp_i2s_init,
+ .msp_i2s_exit = msp_i2s_exit,
+};
+
+static struct stedma40_chan_cfg msp2_dma_rx = {
+ .high_priority = true,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+
+ .src_dev_type = DB8500_DMA_DEV14_MSP2_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+ /* data_width is set during configuration */
+};
+
+static struct stedma40_chan_cfg msp2_dma_tx = {
+ .high_priority = true,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+
+ .src_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV14_MSP2_TX,
+
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+ /* data_width is set during configuration */
+};
+
+static struct msp_i2s_platform_data msp2_platform_data = {
+ .id = MSP_2_I2S_CONTROLLER,
+ .gpio_alt_func = GPIO_ALT_MSP_2,
+ .msp_i2s_dma_rx = &msp2_dma_rx,
+ .msp_i2s_dma_tx = &msp2_dma_tx,
+ .msp_i2s_init = msp_i2s_init,
+ .msp_i2s_exit = msp_i2s_exit,
+};
+
+static struct msp_i2s_platform_data msp3_platform_data = {
+ .id = MSP_3_I2S_CONTROLLER,
+ .gpio_alt_func = GPIO_ALT_MSP_1,
+ .msp_i2s_dma_rx = &msp1_dma_rx,
+ .msp_i2s_dma_tx = NULL,
+ .msp_i2s_init = msp13_i2s_init,
+};
+
+static struct i2s_board_info stm_i2s_board_info[] __initdata = {
+ {
+ .modalias = "i2s_device.0",
+ .id = MSP_0_CONTROLLER - 1,
+ .chip_select = 0,
+ },
+ {
+ .modalias = "i2s_device.1",
+ .id = MSP_1_CONTROLLER - 1,
+ .chip_select = 1,
+ },
+ {
+ .modalias = "i2s_device.2",
+ .id = MSP_2_CONTROLLER - 1,
+ .chip_select = 2,
+ },
+ {
+ .modalias = "i2s_device.3",
+ .id = MSP_3_CONTROLLER - 1,
+ .chip_select = 3,
+ },
+};
+
+static void __init mop500_msp_fixup(void)
+{
+ if (cpu_is_u8500ed() || cpu_is_u8500v1())
+ return;
+
+ /* DMA Rx is moved to MSP3 on DB8500v2 */
+ msp1_platform_data.msp_i2s_dma_rx = NULL;
+
+ /*
+ * Don't error out if the GPIOs are busy and don't disable them on
+ * exit, MSP3 may be using them
+ */
+ msp1_platform_data.msp_i2s_init = msp13_i2s_init;
+ msp1_platform_data.msp_i2s_exit = NULL;
+
+ /* MSP2 DMA doesn't work with PSIZE == 4 on DB8500v2 */
+ msp2_dma_rx.src_info.psize = STEDMA40_PSIZE_LOG_1;
+ msp2_dma_rx.dst_info.psize = STEDMA40_PSIZE_LOG_1;
+}
+
+void __init mop500_msp_init(void)
+{
+ mop500_msp_fixup();
+
+ db8500_add_msp0_i2s(&msp0_platform_data);
+ db8500_add_msp1_i2s(&msp1_platform_data);
+ db8500_add_msp2_i2s(&msp2_platform_data);
+
+ if (cpu_is_u8500v2())
+ db8500_add_msp3_i2s(&msp3_platform_data);
+
+ i2s_register_board_info(stm_i2s_board_info,
+ ARRAY_SIZE(stm_i2s_board_info));
+}
diff --git a/arch/arm/mach-ux500/board-mop500-nuib.c b/arch/arm/mach-ux500/board-mop500-nuib.c
new file mode 100644
index 00000000000..a94ebbb1652
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-nuib.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 ST-Ericsson SA
+ *
+ * License terms:GNU General Public License (GPL) version 2
+ */
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input/synaptics_i2c_rmi4.h>
+
+#include "board-mop500.h"
+
+/* Descriptor structure.
+ * Describes the number of i2c devices on the bus that speak RMI.
+ */
+static struct synaptics_rmi4_platform_data rmi4_i2c_dev_platformdata[] = {
+ [0] = {
+ .irq_number = GPIO_TO_IRQ(84),
+ .irq_type = (IRQF_TRIGGER_FALLING | IRQF_SHARED),
+ .x_max_res = 480,
+ .y_max_res = 864,
+ .portrait_mode = true,
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATE_180_DEGREES
+ .x_flip = true,
+ .y_flip = false,
+#else
+ .x_flip = false,
+ .y_flip = true,
+#endif
+ },
+};
+
+static struct synaptics_rmi4_i2c_data rmi4_platform_data = {
+ .num_clients = ARRAY_SIZE(rmi4_i2c_dev_platformdata),
+ .platformdata = rmi4_i2c_dev_platformdata,
+};
+
+static struct i2c_board_info __initdata u8500_i2c3_devices_nuib[] = {
+ {
+ /* Touschscreen */
+ I2C_BOARD_INFO("synaptics_rmi4_i2c", 0x4B),
+ .platform_data = &rmi4_platform_data,
+ },
+};
+
+void __init mop500_nuib_init(void)
+{
+ i2c_register_board_info(3, u8500_i2c3_devices_nuib,
+ ARRAY_SIZE(u8500_i2c3_devices_nuib));
+}
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c
new file mode 100644
index 00000000000..1523fc563a3
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-regulators.c
@@ -0,0 +1,792 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * Board specific file for regulator machine initialization
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
+#include <linux/regulator/machine.h>
+
+#include <mach/devices.h>
+
+#include "board-mop500-regulators.h"
+
+/*
+ * AB8500 Regulator Configuration
+ */
+
+/* vana regulator configuration, for analogue part of displays */
+#define AB8500_VANA_REGULATOR_MIN_VOLTAGE 0
+#define AB8500_VANA_REGULATOR_MAX_VOLTAGE 1200000
+
+static struct regulator_consumer_supply ab8500_vana_consumers[] = {
+ {
+ .dev = &ux500_mcde_device.dev,
+ .supply = "v-ana",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.10",
+ .supply = "ana",
+ },
+#endif
+};
+
+struct regulator_init_data ab8500_vana_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vana",
+ .min_uV = AB8500_VANA_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VANA_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
+ .consumer_supplies = ab8500_vana_consumers,
+};
+
+#ifdef CONFIG_SENSORS1P_MOP
+extern struct platform_device sensors1p_device;
+#endif
+
+/* vaux1 regulator configuration */
+#define AB8500_VAUXN_LDO_MIN_VOLTAGE 1100000
+#define AB8500_VAUXN_LDO_MAX_VOLTAGE 3300000
+
+static struct regulator_consumer_supply ab8500_vaux1_consumers[] = {
+ {
+ .dev = NULL,
+ .supply = "v-display",
+ },
+#ifdef CONFIG_SENSORS1P_MOP
+ {
+ .dev = &sensors1p_device.dev,
+ .supply = "v-proximity",
+ },
+ {
+ .dev = &sensors1p_device.dev,
+ .supply = "v-hal",
+ },
+#endif
+ {
+ .dev = NULL,
+ .supply = "v-mmio-camera",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.0",
+ .supply = "aux1",
+ },
+#endif
+};
+
+struct regulator_init_data ab8500_vaux1_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vaux1",
+ .min_uV = AB8500_VAUXN_LDO_MIN_VOLTAGE,
+ .max_uV = AB8500_VAUXN_LDO_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
+ .consumer_supplies = ab8500_vaux1_consumers,
+};
+
+/* vaux2 regulator configuration */
+static struct regulator_consumer_supply ab8500_vaux2_consumers[] = {
+ {
+ .dev_name = "sdi4",
+ .supply = "v-eMMC",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.1",
+ .supply = "aux2",
+ },
+#endif
+};
+
+struct regulator_init_data ab8500_vaux2_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vaux2",
+ .min_uV = AB8500_VAUXN_LDO_MIN_VOLTAGE,
+ .max_uV = AB8500_VAUXN_LDO_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
+ .consumer_supplies = ab8500_vaux2_consumers,
+};
+
+/* vaux3 regulator configuration */
+static struct regulator_consumer_supply ab8500_vaux3_consumers[] = {
+ {
+ .dev_name = "sdi0",
+ .supply = "v-MMC-SD"
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.2",
+ .supply = "aux3",
+ },
+#endif
+};
+
+struct regulator_init_data ab8500_vaux3_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vaux3",
+ .min_uV = AB8500_VAUXN_LDO_MIN_VOLTAGE,
+ .max_uV = AB8500_VAUXN_LDO_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
+ .consumer_supplies = ab8500_vaux3_consumers,
+};
+
+/* vtvout regulator configuration, supply for tvout, gpadc, TVOUT LDO */
+#define AB8500_VTVOUT_LDO_MIN_VOLTAGE 0
+#define AB8500_VTVOUT_LDO_MAX_VOLTAGE 2000000
+
+static struct regulator_consumer_supply ab8500_vtvout_consumers[] = {
+ {
+ .supply = "v-tvout",
+ },
+ {
+ .supply = "ab8500-gpadc",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.4",
+ .supply = "tvout",
+ },
+#endif
+};
+
+struct regulator_init_data ab8500_vtvout_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vtvout",
+ .min_uV = AB8500_VTVOUT_LDO_MIN_VOLTAGE,
+ .max_uV = AB8500_VTVOUT_LDO_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vtvout_consumers),
+ .consumer_supplies = ab8500_vtvout_consumers,
+};
+
+/* vusb regulator configuration */
+#define AB8500_VUSB_REGULATOR_MIN_VOLTAGE 0
+#define AB8500_VUSB_REGULATOR_MAX_VOLTAGE 3300000
+
+static struct regulator_consumer_supply ab8500_vusb_consumers[] = {
+ {
+ .supply = "v-bus",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.5",
+ .supply = "usb",
+ },
+#endif
+};
+
+struct regulator_init_data ab8500_vusb_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vusb",
+ .min_uV = AB8500_VUSB_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VUSB_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vusb_consumers),
+ .consumer_supplies = ab8500_vusb_consumers,
+};
+
+/* vaudio regulator configuration, supply for ab8500-vaudio, VAUDIO LDO */
+#define AB8500_VAUDIO_REGULATOR_MIN_VOLTAGE 1925000
+#define AB8500_VAUDIO_REGULATOR_MAX_VOLTAGE 2075000
+
+static struct regulator_consumer_supply ab8500_vaudio_consumers[] = {
+ {
+ .supply = "v-audio",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.6",
+ .supply = "audio",
+ },
+#endif
+};
+
+struct regulator_init_data ab8500_vaudio_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vaudio",
+ .min_uV = AB8500_VAUDIO_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VAUDIO_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaudio_consumers),
+ .consumer_supplies = ab8500_vaudio_consumers,
+};
+
+/* vamic1 regulator configuration */
+#define AB8500_VAMIC1_REGULATOR_MIN_VOLTAGE 2000000
+#define AB8500_VAMIC1_REGULATOR_MAX_VOLTAGE 2100000
+
+static struct regulator_consumer_supply ab8500_vamic1_consumers[] = {
+ {
+ .supply = "v-amic1",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.7",
+ .supply = "anamic1",
+ },
+#endif
+};
+
+struct regulator_init_data ab8500_vamic1_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vamic1",
+ .min_uV = AB8500_VAMIC1_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VAMIC1_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
+ .consumer_supplies = ab8500_vamic1_consumers,
+};
+
+/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
+static struct regulator_consumer_supply ab8500_vamic2_consumers[] = {
+ {
+ .supply = "v-amic2",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.8",
+ .supply = "anamic2",
+ },
+#endif
+};
+
+struct regulator_init_data ab8500_vamic2_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vamic2",
+ .min_uV = AB8500_VAMIC1_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VAMIC1_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
+ .consumer_supplies = ab8500_vamic2_consumers,
+};
+
+/* supply for v-dmic, VDMIC LDO */
+#define AB8500_VDMIC_REGULATOR_MIN_VOLTAGE 1700000
+#define AB8500_VDMIC_REGULATOR_MAX_VOLTAGE 1950000
+
+static struct regulator_consumer_supply ab8500_vdmic_consumers[] = {
+ {
+ .supply = "v-dmic",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.9",
+ .supply = "dmic",
+ },
+#endif
+};
+
+struct regulator_init_data ab8500_vdmic_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vdmic",
+ .min_uV = AB8500_VDMIC_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VDMIC_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vdmic_consumers),
+ .consumer_supplies = ab8500_vdmic_consumers,
+};
+
+/* supply for v-intcore12, VINTCORE12 LDO */
+#define AB8500_VINTCORE_REGULATOR_MIN_VOLTAGE 1200000
+#define AB8500_VINTCORE_REGULATOR_MAX_VOLTAGE 1350000
+
+static struct regulator_consumer_supply ab8500_vintcore_consumers[] = {
+ {
+ .supply = "v-intcore",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.3",
+ .supply = "intcore",
+ },
+#endif
+};
+
+struct regulator_init_data ab8500_vintcore_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vintcore",
+ .min_uV = AB8500_VINTCORE_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VINTCORE_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
+ .consumer_supplies = ab8500_vintcore_consumers,
+};
+
+/*
+ * Power State Regulator Configuration
+ */
+#define U8500_VAPE_REGULATOR_MIN_VOLTAGE 1800000
+#define U8500_VAPE_REGULATOR_MAX_VOLTAGE 2000000
+
+/* vape regulator configuration */
+static struct regulator_consumer_supply u8500_vape_consumers[] = {
+ {
+ .supply = "v-ape",
+ },
+ {
+ .dev_name = "nmk-i2c.0",
+ .supply = "v-i2c",
+ },
+ {
+ .dev_name = "nmk-i2c.1",
+ .supply = "v-i2c",
+ },
+ {
+ .dev_name = "nmk-i2c.2",
+ .supply = "v-i2c",
+ },
+ {
+ .dev_name = "nmk-i2c.3",
+ .supply = "v-i2c",
+ },
+ {
+ .dev_name = "dma40.0",
+ .supply = "v-dma",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.11",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_vape_regulator = {
+ .constraints = {
+ .name = "u8500-vape",
+ .min_uV = U8500_VAPE_REGULATOR_MIN_VOLTAGE,
+ .max_uV = U8500_VAPE_REGULATOR_MAX_VOLTAGE,
+ .input_uV = 1, /* notional, for set_mode* */
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS |
+ REGULATOR_CHANGE_STATUS,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .consumer_supplies = u8500_vape_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_vape_consumers),
+};
+
+/* varm regulator_configuration */
+static struct regulator_consumer_supply u8500_varm_consumers[] = {
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.12",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_varm_regulator = {
+ .constraints = {
+ .name = "u8500-varm",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_varm_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_varm_consumers),
+};
+
+/* vmodem regulator configuration */
+static struct regulator_consumer_supply u8500_vmodem_consumers[] = {
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.13",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_vmodem_regulator = {
+ .constraints = {
+ .name = "u8500-vmodem",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_vmodem_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_vmodem_consumers),
+};
+
+/* vpll regulator configuration */
+static struct regulator_consumer_supply u8500_vpll_consumers[] = {
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.14",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_vpll_regulator = {
+ .constraints = {
+ .name = "u8500-vpll",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_vpll_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_vpll_consumers),
+};
+
+/* vsmps1 regulator configuration */
+static struct regulator_consumer_supply u8500_vsmps1_consumers[] = {
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.15",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_vsmps1_regulator = {
+ .constraints = {
+ .name = "u8500-vsmps1",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_vsmps1_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_vsmps1_consumers),
+};
+
+/* vsmsp2 regulator configuration */
+static struct regulator_consumer_supply u8500_vsmps2_consumers[] = {
+ {
+ .dev_name = "cg2900",
+ .supply = "gbf_1v8",
+ },
+ {
+ .dev_name = "cw1200",
+ .supply = "wlan_1v8",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.16",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_vsmps2_regulator = {
+ .constraints = {
+ .name = "u8500-vsmps2",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_vsmps2_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_vsmps2_consumers),
+};
+
+/* vsmps3 regulator configuration */
+static struct regulator_consumer_supply u8500_vsmps3_consumers[] = {
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.17",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_vsmps3_regulator = {
+ .constraints = {
+ .name = "u8500-vsmps3",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_vsmps3_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_vsmps3_consumers),
+};
+
+/* vrf1 regulator configuration */
+static struct regulator_consumer_supply u8500_vrf1_consumers[] = {
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.18",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_vrf1_regulator = {
+ .constraints = {
+ .name = "u8500-vrf1",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_vrf1_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_vrf1_consumers),
+};
+
+/*
+ * Power Domain Switch Configuration
+ */
+
+/* SVA MMDSP regulator switch */
+static struct regulator_consumer_supply u8500_sva_mmdsp_consumers[] = {
+ /* Add SVA MMDSP device supply here */
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.19",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_sva_mmdsp_regulator = {
+ .supply_regulator = "u8500-vape",
+ .constraints = {
+ .name = "u8500-sva-mmdsp",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_sva_mmdsp_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_sva_mmdsp_consumers),
+};
+
+/* SVA pipe regulator switch */
+static struct regulator_consumer_supply u8500_sva_pipe_consumers[] = {
+ /* Add SVA pipe device supply here */
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.20",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_sva_pipe_regulator = {
+ .supply_regulator = "u8500-vape",
+ .constraints = {
+ .name = "u8500-sva-pipe",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_sva_pipe_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_sva_pipe_consumers),
+};
+
+/* SIA MMDSP regulator switch */
+static struct regulator_consumer_supply u8500_sia_mmdsp_consumers[] = {
+ /* Add SIA MMDSP device supply here */
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.21",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_sia_mmdsp_regulator = {
+ .supply_regulator = "u8500-vape",
+ .constraints = {
+ .name = "u8500-sia-mmdsp",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_sia_mmdsp_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_sia_mmdsp_consumers),
+};
+
+/* SIA pipe regulator switch */
+static struct regulator_consumer_supply u8500_sia_pipe_consumers[] = {
+ /* Add SIA pipe device supply here */
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.22",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_sia_pipe_regulator = {
+ .supply_regulator = "u8500-vape",
+ .constraints = {
+ .name = "u8500-sia-pipe",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_sia_pipe_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_sia_pipe_consumers),
+};
+
+/* SGA regulator switch */
+static struct regulator_consumer_supply u8500_sga_consumers[] = {
+ /* Add SGA device supply here */
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.23",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_sga_regulator = {
+ .supply_regulator = "u8500-vape",
+ .constraints = {
+ .name = "u8500-sga",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_sga_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_sga_consumers),
+};
+
+/* B2R2 regulator switch */
+static struct regulator_consumer_supply u8500_b2r2_consumers[] = {
+ {
+ .dev_name = "U8500-B2R2",
+ .supply = "vsupply",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.24",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_b2r2_regulator = {
+ .supply_regulator = "u8500-vape",
+ .constraints = {
+ .name = "u8500-b2r2",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_b2r2_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_b2r2_consumers),
+};
+
+/* MCDE regulator switch */
+static struct regulator_consumer_supply u8500_mcde_consumers[] = {
+ {
+ .dev_name = "mcde",
+ .supply = "vsupply",
+ },
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.25",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_mcde_regulator = {
+ .supply_regulator = "u8500-vape",
+ .constraints = {
+ .name = "u8500-mcde",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_mcde_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_mcde_consumers),
+};
+
+/* ESRAM1 regulator switch */
+static struct regulator_consumer_supply u8500_esram1_consumers[] = {
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.26",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_esram1_regulator = {
+ .supply_regulator = "u8500-vape",
+ .constraints = {
+ .name = "u8500-esram1",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_esram1_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_esram1_consumers),
+};
+
+/* ESRAM2 regulator switch */
+static struct regulator_consumer_supply u8500_esram2_consumers[] = {
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.27",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_esram2_regulator = {
+ .supply_regulator = "u8500-vape",
+ .constraints = {
+ .name = "u8500-esram2",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_esram2_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_esram2_consumers),
+};
+
+/* ESRAM3 regulator switch */
+static struct regulator_consumer_supply u8500_esram3_consumers[] = {
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.28",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_esram3_regulator = {
+ .supply_regulator = "u8500-vape",
+ .constraints = {
+ .name = "u8500-esram3",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_esram3_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_esram3_consumers),
+};
+
+/* ESRAM4 regulator switch */
+static struct regulator_consumer_supply u8500_esram4_consumers[] = {
+#ifdef CONFIG_U8500_REGULATOR_DEBUG
+ {
+ .dev_name = "reg-virt-consumer.29",
+ .supply = "test",
+ },
+#endif
+};
+
+struct regulator_init_data u8500_esram4_regulator = {
+ .supply_regulator = "u8500-vape",
+ .constraints = {
+ .name = "u8500-esram4",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = u8500_esram4_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(u8500_esram4_consumers),
+};
+
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.h b/arch/arm/mach-ux500/board-mop500-regulators.h
new file mode 100644
index 00000000000..48f14427506
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-regulators.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * Board specific file for regulator machine initialization
+ */
+
+#ifndef REGULATOR_AB8500_H
+#define REGULATOR_AB8500_H
+
+#include <linux/regulator/machine.h>
+
+/* AB8500 regulators */
+extern struct regulator_init_data ab8500_vana_regulator;
+extern struct regulator_init_data ab8500_vaux1_regulator;
+extern struct regulator_init_data ab8500_vaux2_regulator;
+extern struct regulator_init_data ab8500_vaux3_regulator;
+extern struct regulator_init_data ab8500_vtvout_regulator;
+extern struct regulator_init_data ab8500_vusb_regulator;
+extern struct regulator_init_data ab8500_vaudio_regulator;
+extern struct regulator_init_data ab8500_vamic1_regulator;
+extern struct regulator_init_data ab8500_vamic2_regulator;
+extern struct regulator_init_data ab8500_vdmic_regulator;
+extern struct regulator_init_data ab8500_vintcore_regulator;
+
+/* U8500 specific regulators */
+extern struct regulator_init_data u8500_vape_regulator;
+extern struct regulator_init_data u8500_varm_regulator;
+extern struct regulator_init_data u8500_vmodem_regulator;
+extern struct regulator_init_data u8500_vpll_regulator;
+extern struct regulator_init_data u8500_vsmps1_regulator;
+extern struct regulator_init_data u8500_vsmps2_regulator;
+extern struct regulator_init_data u8500_vsmps3_regulator;
+extern struct regulator_init_data u8500_vrf1_regulator;
+
+/* U8500 specific power domains */
+extern struct regulator_init_data u8500_sva_mmdsp_regulator;
+extern struct regulator_init_data u8500_sva_pipe_regulator;
+extern struct regulator_init_data u8500_sia_mmdsp_regulator;
+extern struct regulator_init_data u8500_sia_pipe_regulator;
+extern struct regulator_init_data u8500_sga_regulator;
+/*
+ * NOTE! B2R2 and MCDE regulators will be merged once the clients have
+ * switched over to use the regulator API
+ */
+extern struct regulator_init_data u8500_b2r2_regulator;
+extern struct regulator_init_data u8500_mcde_regulator;
+/*
+ * NOTE! ESRAM1 and ESRAM2 regulators will be merged once the clients have
+ * switched over to use the regulator API
+ */
+extern struct regulator_init_data u8500_esram1_regulator;
+extern struct regulator_init_data u8500_esram2_regulator;
+/*
+ * NOTE! ESRAM3 and ESRAM4 regulators will be merged once the clients have
+ * switched over to use the regulator API
+ */
+extern struct regulator_init_data u8500_esram3_regulator;
+extern struct regulator_init_data u8500_esram4_regulator;
+
+#endif
diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c
new file mode 100644
index 00000000000..8a78d2e5218
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-sdi.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2010 ST-Ericsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
+#include <linux/mmc/host.h>
+#include <linux/delay.h>
+
+#include <plat/ste_dma40.h>
+
+#include <mach/devices.h>
+#include <mach/mmc.h>
+#include <mach/gpio.h>
+#include <mach/ste-dma40-db8500.h>
+
+#include "devices-db8500.h"
+
+static int dma40_mmc_pre_transfer(struct dma_chan *chan, void *data, int size)
+{
+ if (size <= 16)
+ stedma40_set_psize(chan,
+ STEDMA40_PSIZE_LOG_1,
+ STEDMA40_PSIZE_LOG_1);
+ else
+ stedma40_set_psize(chan,
+ STEDMA40_PSIZE_LOG_4,
+ STEDMA40_PSIZE_LOG_4);
+ return 0;
+}
+
+/*
+ * SDI0 (SD/MMC card)
+ */
+
+struct stedma40_chan_cfg sdi0_dma_cfg_mmc2mem = {
+ .pre_transfer = dma40_mmc_pre_transfer,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB8500_DMA_DEV29_SD_MM0_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+
+static struct stedma40_chan_cfg sdi0_dma_cfg_mem2mmc = {
+ .pre_transfer = dma40_mmc_pre_transfer,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV29_SD_MM0_TX,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+
+static int mmc_configure(struct amba_device *dev)
+{
+ int pin[2];
+ int ret;
+
+ /* Level-shifter GPIOs */
+ pin[0] = EGPIO_PIN_17;
+ pin[1] = EGPIO_PIN_18;
+
+ ret = gpio_request(pin[0], "level shifter");
+ if (!ret)
+ ret = gpio_request(pin[1], "level shifter");
+
+ if (!ret) {
+ gpio_direction_output(pin[0], 1);
+ gpio_direction_output(pin[1], 1);
+
+ gpio_set_value(pin[0], 1);
+#if defined(CONFIG_LEVELSHIFTER_HREF_V1_PLUS)
+ gpio_set_value(pin[1], 0);
+#else
+ gpio_set_value(pin[1], 1);
+#endif
+ } else
+ dev_err(&dev->dev, "unable to configure gpios\n");
+
+ return ret;
+}
+
+static int mmc_set_power(struct device *dev, int power_on)
+{
+ gpio_set_value(EGPIO_PIN_17, !!power_on);
+ return 0;
+}
+
+static int mmc_card_detect_intr_conf(int enable_or_disable)
+{
+ if (enable_or_disable)
+ enable_irq(gpio_to_irq(EGPIO_PIN_3));
+ else
+ disable_irq(gpio_to_irq(EGPIO_PIN_3));
+ return 0;
+}
+
+static void (*mmc_card_detect_callback)(void *);
+static void *mmc_card_detect_param;
+
+static irqreturn_t mmc_card_detect_handler(int irq, void *data)
+{
+ if (mmc_card_detect_callback)
+ mmc_card_detect_callback(mmc_card_detect_param);
+
+ return IRQ_HANDLED;
+}
+
+static void mmc_restore_default(struct amba_device *dev)
+{
+
+}
+
+static int mmc_card_detect(void (*callback)(void *parameter), void *host)
+{
+ int ret;
+
+ mmc_card_detect_callback = callback;
+ mmc_card_detect_param = host;
+
+ ret = request_threaded_irq(gpio_to_irq(EGPIO_PIN_3),
+ NULL, mmc_card_detect_handler,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "mmc-card-detect", NULL);
+
+ return ret;
+
+}
+
+static int mmc_get_carddetect_intr_value(void)
+{
+ return gpio_get_value(EGPIO_PIN_3);
+}
+
+static struct mmc_board mmc_data = {
+ .init = mmc_configure,
+ .exit = mmc_restore_default,
+ .set_power = mmc_set_power,
+ .card_detect = mmc_card_detect,
+ .card_detect_intr_value = mmc_get_carddetect_intr_value,
+ .card_detect_intr_conf = mmc_card_detect_intr_conf,
+ .dma_mem2mmc = &sdi0_dma_cfg_mem2mmc,
+ .dma_mmc2mem = &sdi0_dma_cfg_mmc2mem,
+ .dma_filter = stedma40_filter,
+ .level_shifter = 1,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
+ MMC_CAP_MMC_HIGHSPEED,
+ .bus_resume_flags = 0,
+#ifdef CONFIG_REGULATOR
+ .supply = "v-MMC-SD", /* tying to VAUX3 regulator */
+ .min_supply_voltage = 2900000, /* 2.9 V */
+ .max_supply_voltage = 2910000, /* 2.91 V */
+#endif
+};
+
+/*
+ * SDI1 (SDIO WLAN)
+ */
+
+struct stedma40_chan_cfg sdi1_dma_cfg_mmc2mem = {
+ .pre_transfer = dma40_mmc_pre_transfer,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB8500_DMA_DEV32_SD_MM1_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+
+static struct stedma40_chan_cfg sdi1_dma_cfg_mem2mmc = {
+ .pre_transfer = dma40_mmc_pre_transfer,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV32_SD_MM1_TX,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+
+/* sdio specific configurations */
+static int sdio_configure(struct amba_device *dev)
+{
+ int i;
+
+ for (i = 208; i <= 214; i++)
+ nmk_gpio_set_pull(i, NMK_GPIO_PULL_UP);
+
+ stm_gpio_altfuncenable(GPIO_ALT_SDIO);
+
+ return 0;
+}
+
+static void sdio_restore_default(struct amba_device *dev)
+{
+ stm_gpio_altfuncdisable(GPIO_ALT_SDIO);
+}
+
+static struct mmc_board sdi1_data = {
+ .init = sdio_configure,
+ .exit = sdio_restore_default,
+ .dma_mem2mmc = &sdi1_dma_cfg_mem2mmc,
+ .dma_mmc2mem = &sdi1_dma_cfg_mmc2mem,
+ .dma_filter = stedma40_filter,
+ .level_shifter = 0,
+#ifdef CONFIG_U8500_SDIO_CARD_IRQ
+ .caps = (MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ),
+#else
+ .caps = MMC_CAP_4_BIT_DATA,
+#endif
+ .is_sdio = 1,
+};
+
+/*
+ * SDI2 (POPed eMMC on v1)
+ */
+
+struct stedma40_chan_cfg sdi2_dma_cfg_mmc2mem = {
+ .pre_transfer = dma40_mmc_pre_transfer,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB8500_DMA_DEV28_SD_MM2_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+static struct stedma40_chan_cfg sdi2_dma_cfg_mem2mmc = {
+ .pre_transfer = dma40_mmc_pre_transfer,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV28_SD_MM2_TX,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+
+static struct mmc_board sdi2_data = {
+ .dma_mem2mmc = &sdi2_dma_cfg_mem2mmc,
+ .dma_mmc2mem = &sdi2_dma_cfg_mmc2mem,
+ .dma_filter = stedma40_filter,
+ .level_shifter = 0,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .bus_resume_flags = MMC_NEEDS_UNSAFE_RESUME,
+};
+
+/*
+ * SDI4 (On-board EMMC)
+ */
+
+struct stedma40_chan_cfg sdi4_dma_cfg_mmc2mem = {
+ .pre_transfer = dma40_mmc_pre_transfer,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB8500_DMA_DEV42_SD_MM4_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+
+static struct stedma40_chan_cfg sdi4_dma_cfg_mem2mmc = {
+ .pre_transfer = dma40_mmc_pre_transfer,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV42_SD_MM4_TX,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+
+static struct mmc_board emmc_data = {
+ .dma_mem2mmc = &sdi4_dma_cfg_mem2mmc,
+ .dma_mmc2mem = &sdi4_dma_cfg_mmc2mem,
+ .dma_filter = stedma40_filter,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA | MMC_CAP_MMC_HIGHSPEED,
+ .bus_resume_flags = MMC_NEEDS_UNSAFE_RESUME,
+#ifdef CONFIG_REGULATOR
+ .supply = "v-eMMC", /* tying to VAUX1 regulator */
+ .min_supply_voltage = 2900000, /* 2.9 V */
+ .max_supply_voltage = 2900000, /* 2.9 V */
+#endif
+};
+
+static int __init mop500_sdi_init(void)
+{
+ /* POP eMMC on v1.0 has problems with high speed */
+ if (!cpu_is_u8500v10())
+ sdi2_data.caps |= MMC_CAP_MMC_HIGHSPEED;
+
+ db8500_add_sdi2(&sdi2_data);
+ db8500_add_sdi4(&emmc_data);
+ db8500_add_sdi0(&mmc_data);
+#ifdef CONFIG_U8500_SDIO
+ db8500_add_sdi1(&sdi1_data);
+#endif
+
+ return 0;
+}
+
+fs_initcall(mop500_sdi_init);
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index bb8d7b77181..50f3b783374 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -8,70 +8,853 @@
* published by the Free Software Foundation.
*
*/
+#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/io.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl022.h>
+#include <linux/interrupt.h>
#include <linux/spi/spi.h>
+#include <linux/i2c.h>
+#include <linux/hsi.h>
+#include <linux/i2s/i2s.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/mfd/stmpe.h>
+#include <linux/mfd/tc35892.h>
+#include <linux/i2c/lp5521.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/lsm303dlh.h>
+#include <linux/input/bu21013.h>
+#include <linux/spi/stm_msp.h>
+#include <linux/leds_pwm.h>
+#include <linux/pwm_backlight.h>
+#include <linux/mfd/ab8500/ab8500-bm.h>
+#ifdef CONFIG_USB_ANDROID
+#include <linux/usb/android_composite.h>
+#endif
-#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+#include <plat/pincfg.h>
+#include <plat/ske.h>
#include <plat/i2c.h>
-#include <mach/hardware.h>
+#include <mach/devices.h>
+#include <mach/sensors1p.h>
+#include <mach/ab8500_denc.h>
#include <mach/setup.h>
+#include <mach/tc35893-keypad.h>
+#include <video/av8100.h>
#include <mach/devices.h>
+#include <mach/irqs.h>
+
+#include "devices-db8500.h"
+#include "board-mop500-regulators.h"
+#include "regulator-u8500.h"
+#include "pins-db8500.h"
+#include "board-mop500.h"
+
+#define IRQ_KP 1 /*To DO*/
+
+static pin_cfg_t mop500_pins[] = {
+ /* I2C */
+ GPIO147_I2C0_SCL,
+ GPIO148_I2C0_SDA,
+ GPIO16_I2C1_SCL,
+ GPIO17_I2C1_SDA,
+ GPIO10_I2C2_SDA,
+ GPIO11_I2C2_SCL,
+ GPIO229_I2C3_SDA,
+ GPIO230_I2C3_SCL,
+
+ /* SSP0 */
+ GPIO143_SSP0_CLK,
+ GPIO144_SSP0_FRM,
+ GPIO145_SSP0_RXD | PIN_PULL_DOWN,
+ GPIO146_SSP0_TXD,
+
+ GPIO218_GPIO | PIN_PULL_UP, /* STMPE1601 IRQ */
+ GPIO84_GPIO,
+
+ /* MMC0 (MicroSD card) */
+ GPIO18_MC0_CMDDIR | PIN_OUTPUT_HIGH,
+ GPIO19_MC0_DAT0DIR | PIN_OUTPUT_HIGH,
+ GPIO20_MC0_DAT2DIR | PIN_OUTPUT_HIGH,
+ GPIO21_MC0_DAT31DIR | PIN_OUTPUT_HIGH,
+ GPIO22_MC0_FBCLK | PIN_INPUT_NOPULL,
+ GPIO23_MC0_CLK | PIN_OUTPUT_LOW,
+ GPIO24_MC0_CMD | PIN_INPUT_PULLUP,
+ GPIO25_MC0_DAT0 | PIN_INPUT_PULLUP,
+ GPIO26_MC0_DAT1 | PIN_INPUT_PULLUP,
+ GPIO27_MC0_DAT2 | PIN_INPUT_PULLUP,
+ GPIO28_MC0_DAT3 | PIN_INPUT_PULLUP,
+
+ /* MMC2 (POP eMMC) */
+ GPIO128_MC2_CLK | PIN_OUTPUT_LOW,
+ GPIO129_MC2_CMD | PIN_INPUT_PULLUP,
+ GPIO130_MC2_FBCLK | PIN_INPUT_NOPULL,
+ GPIO131_MC2_DAT0 | PIN_INPUT_PULLUP,
+ GPIO132_MC2_DAT1 | PIN_INPUT_PULLUP,
+ GPIO133_MC2_DAT2 | PIN_INPUT_PULLUP,
+ GPIO134_MC2_DAT3 | PIN_INPUT_PULLUP,
+ GPIO135_MC2_DAT4 | PIN_INPUT_PULLUP,
+ GPIO136_MC2_DAT5 | PIN_INPUT_PULLUP,
+ GPIO137_MC2_DAT6 | PIN_INPUT_PULLUP,
+ GPIO138_MC2_DAT7 | PIN_INPUT_PULLUP,
+
+ /* MMC4 (On-board eMMC) */
+ GPIO197_MC4_DAT3 | PIN_INPUT_PULLUP,
+ GPIO198_MC4_DAT2 | PIN_INPUT_PULLUP,
+ GPIO199_MC4_DAT1 | PIN_INPUT_PULLUP,
+ GPIO200_MC4_DAT0 | PIN_INPUT_PULLUP,
+ GPIO201_MC4_CMD | PIN_INPUT_PULLUP,
+ GPIO202_MC4_FBCLK | PIN_INPUT_NOPULL,
+ GPIO203_MC4_CLK | PIN_OUTPUT_LOW,
+ GPIO204_MC4_DAT7 | PIN_INPUT_PULLUP,
+ GPIO205_MC4_DAT6 | PIN_INPUT_PULLUP,
+ GPIO206_MC4_DAT5 | PIN_INPUT_PULLUP,
+ GPIO207_MC4_DAT4 | PIN_INPUT_PULLUP,
+
+ /* SKE keypad */
+ GPIO153_KP_I7,
+ GPIO154_KP_I6,
+ GPIO155_KP_I5,
+ GPIO156_KP_I4,
+ GPIO157_KP_O7,
+ GPIO158_KP_O6,
+ GPIO159_KP_O5,
+ GPIO160_KP_O4,
+ GPIO161_KP_I3,
+ GPIO162_KP_I2,
+ GPIO163_KP_I1,
+ GPIO164_KP_I0,
+ GPIO165_KP_O3,
+ GPIO166_KP_O2,
+ GPIO167_KP_O1,
+ GPIO168_KP_O0,
+
+ /* UART */
+ GPIO0_U0_CTSn | PIN_INPUT_PULLUP,
+ GPIO1_U0_RTSn | PIN_OUTPUT_HIGH,
+ GPIO2_U0_RXD | PIN_INPUT_PULLUP,
+ GPIO3_U0_TXD | PIN_OUTPUT_HIGH,
+ GPIO4_U1_RXD | PIN_INPUT_PULLUP,
+ GPIO5_U1_TXD | PIN_OUTPUT_HIGH,
+ GPIO6_U1_CTSn | PIN_INPUT_PULLUP,
+ GPIO7_U1_RTSn | PIN_OUTPUT_HIGH,
+ GPIO29_U2_RXD | PIN_INPUT_PULLUP,
+ GPIO30_U2_TXD | PIN_OUTPUT_HIGH,
+ GPIO31_U2_CTSn | PIN_INPUT_PULLUP,
+ GPIO32_U2_RTSn | PIN_OUTPUT_HIGH,
+};
+
+static struct gpio_altfun_data gpio_altfun_table[] = {
+ __GPIO_ALT(GPIO_ALT_USB_OTG, 256, 267, 0, NMK_GPIO_ALT_A, "usb"),
+ __GPIO_ALT(GPIO_ALT_MSP_0, 12, 15, 0, NMK_GPIO_ALT_A, "msp0"),
+ __GPIO_ALT(GPIO_ALT_MSP_1, 33, 36, 0, NMK_GPIO_ALT_A, "msp1"),
+ __GPIO_ALT(GPIO_ALT_MSP_2, 193, 196, 0, NMK_GPIO_ALT_A, "msp2"),
+ __GPIO_ALT(GPIO_ALT_HSIR, 219, 221, 0, NMK_GPIO_ALT_A, "hsir"),
+ __GPIO_ALT(GPIO_ALT_HSIT, 222, 224, 0, NMK_GPIO_ALT_A, "hsit"),
+ __GPIO_ALT(GPIO_ALT_SDIO, 208, 214, 0, NMK_GPIO_ALT_A, "sdio"),
+ __GPIO_ALT(GPIO_ALT_TRACE, 70, 74, 0, NMK_GPIO_ALT_C, "stm"),
+ __GPIO_ALT(GPIO_ALT_TRACE_MIPI60, 155, 159, 0, NMK_GPIO_ALT_C, "stm"),
+ __GPIO_ALT(GPIO_ALT_LCD_PANELB, 78, 81, 1, NMK_GPIO_ALT_A,
+ "mcde tvout data"),
+ __GPIO_ALT(GPIO_ALT_LCDB, 64, 67, 0, NMK_GPIO_ALT_A, "mcde lcdb"),
+ __GPIO_ALT(GPIO_ALT_LCDA_CLK, 150, 150, 0, NMK_GPIO_ALT_B,
+ "mcde lcda/tv clk"),
+ __GPIO_ALT(GPIO_ALT_LCDA, 169, 171, 0, NMK_GPIO_ALT_B, "mcde lcda"),
+ __GPIO_ALT(GPIO_ALT_LCD_D_24, 153, 168, 1, NMK_GPIO_ALT_B,
+ "mcde lcd[24:39]"),
+ __GPIO_ALT(GPIO_ALT_LCD_D_24, 70, 77, 0, NMK_GPIO_ALT_A,
+ "mcde lcd[0:7]"),
+#ifdef CONFIG_AV8100_HWTRIG_I2SDAT3
+ __GPIO_ALT(GPIO_ALT_LCD_PANELA, 69, 69, 0, NMK_GPIO_ALT_A,
+ "mcde tvout"),
+#else
+ __GPIO_ALT(GPIO_ALT_LCD_PANELA, 68, 68, 0, NMK_GPIO_ALT_A,
+ "mcde tvout"),
+#endif /* CONFIG_AV8100_HWTRIG_I2SDAT3 */
+ __GPIO_ALT(GPIO_ALT_MMIO_INIT_BOARD, 141, 142, 0, NMK_GPIO_ALT_B,
+ "mmio"),
+ __GPIO_ALT(GPIO_ALT_MMIO_CAM_SET_I2C, 8, 9, 0, NMK_GPIO_ALT_A, "mmio"),
+ __GPIO_ALT(GPIO_ALT_MMIO_CAM_SET_EXT_CLK, 227, 228, 0, NMK_GPIO_ALT_A,
+ "mmio"),
+ __GPIO_ALT(GPIO_ALT_TP_SET_EXT_CLK, 228, 228, 0, NMK_GPIO_ALT_A,
+ "bu21013_tp"),
+};
-static void ab4500_spi_cs_control(u32 command)
+/*
+ * Initializes the key scan table (lookup table) as per schematic of
+ * the NUIB. Pre-defined scan codes to be passed to upper layer
+ * for each valid key in the matrix.
+ */
+
+u8 const kpd_lookup_tbl3[TC_KPD_ROWS][TC_KPD_COLUMNS] = {
+ {
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_BACK,
+ KEY_RESERVED,
+ KEY_RESERVED
+ },
+ {
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_1,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED
+ },
+ {
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_9,
+ KEY_RESERVED,
+ KEY_RESERVED
+ },
+ {
+ KEY_RESERVED,
+ KEY_END,
+ KEY_RESERVED,
+ KEY_RIGHT,
+ KEY_2,
+ KEY_DOWN,
+ KEY_RESERVED,
+ KEY_RESERVED
+ },
+ {
+ KEY_RESERVED,
+ KEY_POWER,
+ KEY_3,
+ KEY_0,
+ KEY_RESERVED,
+ KEY_SEND,
+ KEY_RESERVED,
+ KEY_RESERVED
+ },
+ {
+ KEY_ENTER,
+ KEY_RESERVED,
+ KEY_UP,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_7,
+ KEY_RESERVED,
+ KEY_RESERVED
+ },
+ {
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_VOLUMEUP,
+ KEY_RESERVED,
+ KEY_VOLUMEDOWN,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_MENU
+ },
+ {
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_LEFT,
+ KEY_RESERVED
+ }
+};
+
+/*
+ * ux500 keymaps
+ *
+ * Organized row-wise as on the UIB, starting at the top-left
+ *
+ * we support two key layouts, specific to requirements. The first
+ * keylayout includes controls for power/volume a few generic keys;
+ * the second key layout contains the full numeric layout, enter/back/left
+ * buttons along with a "."(dot), specifically for connectivity testing
+ */
+static const unsigned int ux500_keymap[] = {
+#ifdef CONFIG_KEYLAYOUT_LAYOUT1
+ KEY(2, 5, KEY_END),
+ KEY(4, 1, KEY_POWER),
+ KEY(3, 5, KEY_VOLUMEDOWN),
+ KEY(1, 3, KEY_3),
+ KEY(5, 2, KEY_RIGHT),
+ KEY(5, 0, KEY_9),
+
+ KEY(0, 5, KEY_MENU),
+ KEY(7, 6, KEY_ENTER),
+ KEY(4, 5, KEY_0),
+ KEY(6, 7, KEY_2),
+ KEY(3, 4, KEY_UP),
+ KEY(3, 3, KEY_DOWN),
+
+ KEY(6, 4, KEY_SEND),
+ KEY(6, 2, KEY_BACK),
+ KEY(4, 2, KEY_VOLUMEUP),
+ KEY(5, 5, KEY_1),
+ KEY(4, 3, KEY_LEFT),
+ KEY(3, 2, KEY_7),
+#else
+#ifdef CONFIG_KEYLAYOUT_LAYOUT2
+ KEY(2, 5, KEY_RIGHT),
+ KEY(4, 1, KEY_ENTER),
+ KEY(3, 5, KEY_MENU),
+ KEY(1, 3, KEY_3),
+ KEY(5, 2, KEY_6),
+ KEY(5, 0, KEY_9),
+
+ KEY(0, 5, KEY_UP),
+ KEY(7, 6, KEY_DOWN),
+ KEY(4, 5, KEY_0),
+ KEY(6, 7, KEY_2),
+ KEY(3, 4, KEY_5),
+ KEY(3, 3, KEY_8),
+
+ KEY(6, 4, KEY_LEFT),
+ KEY(6, 2, KEY_BACK),
+ KEY(4, 2, KEY_KPDOT),
+ KEY(5, 5, KEY_1),
+ KEY(4, 3, KEY_4),
+ KEY(3, 2, KEY_7),
+#else
+#warning "No keypad layout defined."
+#endif
+#endif
+};
+
+static struct matrix_keymap_data ux500_keymap_data = {
+ .keymap = ux500_keymap,
+ .keymap_size = ARRAY_SIZE(ux500_keymap),
+};
+
+/*
+ * STMPE1601
+ */
+static struct stmpe_keypad_platform_data stmpe1601_keypad_data = {
+ .debounce_ms = 64,
+ .scan_count = 8,
+ .no_autorepeat = true,
+ .keymap_data = &ux500_keymap_data,
+};
+
+static struct stmpe_platform_data stmpe1601_data = {
+ .id = 1,
+ .blocks = STMPE_BLOCK_KEYPAD,
+ .irq_trigger = IRQF_TRIGGER_FALLING,
+ .irq_base = MOP500_STMPE1601_IRQ(0),
+ .keypad = &stmpe1601_keypad_data,
+};
+
+/*
+ * Nomadik SKE keypad
+ */
+#define ROW_PIN_I0 164
+#define ROW_PIN_I1 163
+#define ROW_PIN_I2 162
+#define ROW_PIN_I3 161
+#define ROW_PIN_I4 156
+#define ROW_PIN_I5 155
+#define ROW_PIN_I6 154
+#define ROW_PIN_I7 153
+#define COL_PIN_O0 168
+#define COL_PIN_O1 167
+#define COL_PIN_O2 166
+#define COL_PIN_O3 165
+#define COL_PIN_O4 160
+#define COL_PIN_O5 159
+#define COL_PIN_O6 158
+#define COL_PIN_O7 157
+
+#define SKE_KPD_MAX_ROWS 8
+#define SKE_KPD_MAX_COLS 8
+
+static int ske_kp_rows[] = {
+ ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3,
+ ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7,
+};
+
+/*
+ * ske_set_gpio_row: request and set gpio rows
+ */
+static int ske_set_gpio_row(int gpio)
{
- /* set the FRM signal, which is CS - TODO */
+ int ret;
+
+ ret = gpio_request(gpio, "ske-kp");
+ if (ret < 0) {
+ pr_err("ske_set_gpio_row: gpio request failed\n");
+ return ret;
+ }
+
+ ret = gpio_direction_output(gpio, 1);
+ if (ret < 0) {
+ pr_err("ske_set_gpio_row: gpio direction failed\n");
+ gpio_free(gpio);
+ }
+
+ return ret;
}
-struct pl022_config_chip ab4500_chip_info = {
- .lbm = LOOPBACK_DISABLED,
- .com_mode = INTERRUPT_TRANSFER,
- .iface = SSP_INTERFACE_MOTOROLA_SPI,
- /* we can act as master only */
- .hierarchy = SSP_MASTER,
- .slave_tx_disable = 0,
- .endian_rx = SSP_RX_MSB,
- .endian_tx = SSP_TX_MSB,
- .data_size = SSP_DATA_BITS_24,
- .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
- .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
- .clk_phase = SSP_CLK_SECOND_EDGE,
- .clk_pol = SSP_CLK_POL_IDLE_HIGH,
- .cs_control = ab4500_spi_cs_control,
+/*
+ * ske_kp_init - enable the gpio configuration
+ */
+static int ske_kp_init(void)
+{
+ int ret, i;
+
+ for (i = 0; i < SKE_KPD_MAX_ROWS; i++) {
+ ret = ske_set_gpio_row(ske_kp_rows[i]);
+ if (ret < 0) {
+ pr_err("ske_kp_init: failed init\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static struct ske_keypad_platform_data mop500_ske_keypad_data = {
+ .init = ske_kp_init,
+ .keymap_data = &ux500_keymap_data,
+ .no_autorepeat = true,
+ .krow = SKE_KPD_MAX_ROWS, /* 8x8 matrix */
+ .kcol = SKE_KPD_MAX_COLS,
+ .debounce_ms = 40, /* in millsecs */
};
-static struct spi_board_info u8500_spi_devices[] = {
+static struct av8100_platform_data av8100_plat_data = {
+ .irq = GPIO_TO_IRQ(192),
+};
+
+/*
+ * TC35892 Expander
+ */
+
+static struct tc35892_gpio_platform_data tc35892_gpio_platform_data = {
+ .gpio_base = U8500_NR_GPIO,
+};
+
+static struct tc35892_platform_data tc35892_data = {
+ .gpio = &tc35892_gpio_platform_data,
+ .irq_base = MOP500_EGPIO_IRQ_BASE,
+};
+
+static struct tc35893_platform_data tc35893_data = {
+ .kcode_tbl = (u8 *)kpd_lookup_tbl3,
+ .krow = TC_KPD_ROWS,
+ .kcol = TC_KPD_COLUMNS,
+ .debounce_period = TC_KPD_DEBOUNCE_PERIOD,
+ .settle_time = TC_KPD_SETTLE_TIME,
+ .irqtype = (IRQF_TRIGGER_FALLING),
+ .irq = GPIO_TO_IRQ(218),
+ .enable_wakeup = true,
+#ifdef CONFIG_TC_KEYPAD_POLL
+ .op_mode = 1,
+#elif CONFIG_TC_KEYPAD_INTR
+ .op_mode = 0,
+#endif
+};
+
+static struct lp5521_platform_data lp5521_data = {
+ .mode = LP5521_MODE_DIRECT_CONTROL,
+ .label = "uib-led",
+ .red_present = true,
+ .green_present = true,
+ .blue_present = true,
+};
+
+/**
+ * Touch panel related platform specific initialization
+ */
+
+/**
+ * bu21013_gpio_board_init : configures the touch panel.
+ * @reset_pin: reset pin number
+ * This function can be used to configures
+ * the voltage and reset the touch panel controller.
+ */
+static int bu21013_gpio_board_init(int reset_pin)
+{
+ int retval = 0;
+ void __iomem *clk_base;
+ unsigned int clk_value;
+
+ static bool config_set;
+
+ if (!config_set) {
+ retval = stm_gpio_altfuncenable(GPIO_ALT_TP_SET_EXT_CLK);
+ if (retval < 0) {
+ printk(KERN_ERR "%s: gpio alternate failed\n",
+ __func__);
+ return retval;
+ }
+ clk_base = (void __iomem *)IO_ADDRESS(U8500_PRCMU_BASE +
+ PRCMU_CLOCK_OCR);
+ clk_value = readl(clk_base);
+ writel(TSC_EXT_CLOCK_9_6MHZ, clk_base);
+ retval = gpio_request(reset_pin, "touchp_reset");
+ if (retval) {
+ printk(KERN_ERR "Unable to request gpio reset_pin");
+ return retval;
+ }
+ retval = gpio_direction_output(reset_pin, 1);
+ if (retval < 0) {
+ printk(KERN_ERR "%s: gpio direction failed\n",
+ __func__);
+ return retval;
+ }
+ gpio_set_value(reset_pin, 1);
+ config_set = true;
+ }
+ return retval;
+}
+
+/**
+ * bu21013_gpio_board_exit : deconfigures the touch panel controller
+ * @reset_pin: reset pin number
+ * This function can be used to deconfigures the chip selection
+ * for touch panel controller.
+ */
+static int bu21013_gpio_board_exit(int reset_pin)
+{
+ int retval = 0;
+ static bool config_disable_set;
+ if (!config_disable_set) {
+ retval = gpio_direction_output(reset_pin, 0);
+ if (retval < 0) {
+ printk(KERN_ERR "%s: gpio direction failed\n",
+ __func__);
+ return retval;
+ }
+ gpio_set_value(reset_pin, 0);
+ config_disable_set = true;
+ }
+ return retval;
+}
+
+/**
+ * bu21013_read_pin_val : get the interrupt pin value
+ * This function can be used to get the interrupt pin value for touch panel
+ * controller.
+ */
+static int bu21013_read_pin_val(void)
+{
+ return gpio_get_value(TOUCH_GPIO_PIN);
+}
+
+static struct bu21013_platform_device tsc_plat_device = {
+ .cs_en = bu21013_gpio_board_init,
+ .cs_dis = bu21013_gpio_board_exit,
+ .irq_read_val = bu21013_read_pin_val,
+ .irq = GPIO_TO_IRQ(TOUCH_GPIO_PIN),
+ .cs_pin = EGPIO_PIN_13,
+ .x_max_res = 480,
+ .y_max_res = 864,
+ .touch_x_max = TOUCH_XMAX,
+ .touch_y_max = TOUCH_YMAX,
+ .portrait = true,
+ .ext_clk = false,
+#ifdef CONFIG_BU21013_TSC_CNTL1
+ .tp_cntl = 1,
+#endif
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATE_180_DEGREES
+ .x_flip = true,
+ .y_flip = false,
+#else
+ .x_flip = false,
+ .y_flip = true,
+#endif
+};
+
+static struct bu21013_platform_device tsc_cntl2_plat_device = {
+ .cs_en = bu21013_gpio_board_init,
+ .cs_dis = bu21013_gpio_board_exit,
+ .irq_read_val = bu21013_read_pin_val,
+ .irq = GPIO_TO_IRQ(TOUCH_GPIO_PIN),
+ .cs_pin = EGPIO_PIN_13,
+ .x_max_res = 480,
+ .y_max_res = 864,
+ .touch_x_max = TOUCH_XMAX,
+ .touch_y_max = TOUCH_YMAX,
+ .portrait = true,
+ .ext_clk = false,
+#ifdef CONFIG_BU21013_TSC_CNTL2
+ .tp_cntl = 2,
+#endif
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATE_180_DEGREES
+ .x_flip = true,
+ .y_flip = false,
+#else
+ .x_flip = false,
+ .y_flip = true,
+#endif
+};
+
+static struct lsm303dlh_platform_data __initdata lsm303dlh_pdata = {
+ .register_irq = NULL,
+ .free_irq = NULL,
+ .axis_map_x = 0, /* Axis map for HREF ED, HREF v1 and mop500 */
+ .axis_map_y = 1,
+ .axis_map_z = 2,
+ .negative_x = 1,
+ .negative_y = 1,
+ .negative_z = 0,
+};
+
+static struct ab3550_platform_data ab3550_plf_data = {
+ .irq = {
+ .base = 0,
+ .count = 0,
+ },
+ .dev_data = {
+ },
+ .dev_data_sz = {
+ },
+ .init_settings = NULL,
+ .init_settings_sz = 0,
+};
+
+static struct i2c_board_info __initdata mop500_i2c0_devices[] = {
{
- .modalias = "ab8500",
- .controller_data = &ab4500_chip_info,
- .max_speed_hz = 12000000,
- .bus_num = 0,
- .chip_select = 0,
- .mode = SPI_MODE_0,
- .irq = IRQ_AB4500,
+
+ I2C_BOARD_INFO("tc35892", 0x42),
+ .platform_data = &tc35892_data,
+ .irq = GPIO_TO_IRQ(217),
+ },
+ {
+ /* STMPE1601 on UIB */
+ I2C_BOARD_INFO("stmpe1601", 0x40),
+ .irq = NOMADIK_GPIO_TO_IRQ(218),
+ .platform_data = &stmpe1601_data,
+ .flags = I2C_CLIENT_WAKE, /* enable wakeup */
+ },
+ {
+ /* TC35893 keypad */
+ I2C_BOARD_INFO("tc35893-kp", 0x44),
+ .platform_data = &tc35893_data,
+ },
+ {
+ I2C_BOARD_INFO("av8100", 0x70),
+ .platform_data = &av8100_plat_data,
+ },
+ {
+ /* FIXME - address TBD, TODO */
+ I2C_BOARD_INFO("uib-kpd", 0x45),
+ },
+ {
+ /* Audio step-up */
+ I2C_BOARD_INFO("tps61052", 0x33),
+ }
+};
+static struct i2c_board_info __initdata mop500_i2c1_devices[] = {
+ {
+ /* GPS - Address TBD, FIXME */
+ I2C_BOARD_INFO("gps", 0x68),
+ },
+ {
+ /* AB3550 */
+ I2C_BOARD_INFO("ab3550", 0x4A),
+ .irq = -1,
+ .platform_data = &ab3550_plf_data,
+ }
+};
+static struct i2c_board_info __initdata mop500_i2c2_devices[] = {
+ {
+ /* ST 3D accelerometer @ 0x3A(w),0x3B(r) */
+ I2C_BOARD_INFO("lis302dl", 0x1D),
+ },
+ {
+ /* ASAHI KASEI AK8974 magnetometer, addr TBD FIXME */
+ I2C_BOARD_INFO("ak8974", 0x1),
+ },
+#if defined(CONFIG_SENSORS_BH1780)
+ {
+ /* Rohm BH1780GLI ambient light sensor */
+ I2C_BOARD_INFO("bh1780", 0x29),
+ },
+#endif
+ {
+ /* RGB LED driver, there are 1st and 2nd, TODO */
+ I2C_BOARD_INFO("lp5521", 0x33),
+ .platform_data = &lp5521_data,
+ },
+ {
+ /* LSM303DLH Accelerometer */
+ I2C_BOARD_INFO("lsm303dlh_a", 0x18),
+ .platform_data = &lsm303dlh_pdata,
+ },
+ {
+ /* LSM303DLH Magnetometer */
+ I2C_BOARD_INFO("lsm303dlh_m", 0x1E),
+ .platform_data = &lsm303dlh_pdata,
+ },
+};
+static struct i2c_board_info __initdata mop500_i2c3_devices[] = {
+ {
+ /* NFC - Address TBD, FIXME */
+ I2C_BOARD_INFO("nfc", 0x68),
+ },
+ {
+ /* Touschscreen */
+ I2C_BOARD_INFO("bu21013_tp", 0x5C),
+ .platform_data = &tsc_plat_device,
+ },
+ {
+ /* Touschscreen */
+ I2C_BOARD_INFO("bu21013_tp", 0x5D),
+ .platform_data = &tsc_cntl2_plat_device,
+ },
+};
+
+/*
+ * MSP-SPI
+ */
+
+#define NUM_MSP_CLIENTS 10
+
+static struct spi_master_cntlr mop500_msp2_spi_data = {
+ .id = MSP_2_CONTROLLER,
+ .num_chipselect = NUM_MSP_CLIENTS,
+ .base_addr = U8500_MSP2_BASE,
+ .gpio_alt_func = GPIO_ALT_MSP_2,
+ .device_name = "msp2",
+};
+
+/*
+ * SSP
+ */
+
+#define NUM_SSP_CLIENTS 10
+
+static struct pl022_ssp_controller mop500_ssp0_data = {
+ .bus_id = SSP_0_CONTROLLER,
+ .num_chipselect = NUM_SSP_CLIENTS,
+};
+
+#ifdef CONFIG_SENSORS1P_MOP
+static struct sensors1p_config sensors1p_config = {
+ /* SFH7741 */
+ .proximity = {
+ .pin = EGPIO_PIN_7,
+ .startup_time = 120, /* ms */
+ .regulator = "v-proximity",
+ },
+ /* HED54XXU11 */
+ .hal = {
+ .pin = EGPIO_PIN_8,
+ .startup_time = 100, /* Actually, I have no clue. */
+ .regulator = "v-hal",
},
};
-static struct pl022_ssp_controller ssp0_platform_data = {
- .bus_id = 0,
- /* pl022 not yet supports dma */
- .enable_dma = 0,
- /* on this platform, gpio 31,142,144,214 &
- * 224 are connected as chip selects
- */
- .num_chipselect = 5,
+struct platform_device sensors1p_device = {
+ .name = "sensors1p",
+ .dev = {
+ .platform_data = (void *)&sensors1p_config,
+ },
+};
+#endif
+#ifdef CONFIG_USB_ANDROID
+
+static char *usb_functions_adb[] = {
+#ifdef CONFIG_USB_ANDROID_MASS_STORAGE
+ "usb_mass_storage",
+#endif
+#ifdef CONFIG_USB_ANDROID_ECM
+ "ecm",
+#endif
+#ifdef CONFIG_USB_ANDROID_ACM
+ "acm",
+#endif
+#ifdef CONFIG_USB_ANDROID_ADB
+ "adb",
+#endif
+};
+
+static struct android_usb_product usb_products[] = {
+ {
+ .product_id = 0x2323,
+ .num_functions = ARRAY_SIZE(usb_functions_adb),
+ .functions = usb_functions_adb,
+ },
+};
+
+static struct android_usb_platform_data android_usb_pdata = {
+ .vendor_id = 0x04cc,
+ .product_id = 0x2323,
+ .version = 0x0100,
+ .product_name = "Android Phone",
+ .manufacturer_name = "ST-Ericsson",
+ .num_products = ARRAY_SIZE(usb_products),
+ .products = usb_products,
+ .num_functions = ARRAY_SIZE(usb_functions_adb),
+ .functions = usb_functions_adb,
};
+static struct platform_device android_usb_device = {
+ .name = "android_usb",
+ .id = -1,
+ .dev = {
+ .platform_data = &android_usb_pdata,
+ },
+};
+
+#ifdef CONFIG_USB_ANDROID_MASS_STORAGE
+static struct usb_mass_storage_platform_data mass_storage_pdata = {
+ .nluns = 2,
+ .vendor = "ST-Ericsson",
+ .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 /* CONFIG_USB_ANDROID_MASS_STORAGE */
+
+#ifdef CONFIG_USB_ANDROID_ECM
+static struct usb_ether_platform_data usb_ecm_pdata = {
+ .ethaddr = {0x02, 0x11, 0x22, 0x33, 0x44, 0x55},
+ .vendorID = 0x04cc,
+ .vendorDescr = "ST Ericsson",
+};
+
+static struct platform_device usb_ecm_device = {
+ .name = "ecm",
+ .id = -1,
+ .dev = {
+ .platform_data = &usb_ecm_pdata,
+ },
+};
+#endif /* CONFIG_USB_ANDROID_ECM */
+
+#endif /* CONFIG_USB_ANDROID */
+
#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \
-static struct nmk_i2c_controller u8500_i2c##id##_data = { \
+static struct nmk_i2c_controller mop500_i2c##id##_data = { \
/* \
* slave data setup time, which is \
* 250 ns,100ns,10ns which is 14,6,2 \
@@ -94,57 +877,402 @@ static struct nmk_i2c_controller u8500_i2c##id##_data = { \
* Tx & Rx FIFO threshold values as 1 and standard
* mode of operation
*/
-U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
+U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
+
+static struct hsi_board_info __initdata stm_hsi_devices[] = {
+ {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 0,
+ .chan_num = 0, .mode = 1},
+ {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 1,
+ .chan_num = 0, .mode = 1},
+ {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 0,
+ .chan_num = 1, .mode = 1},
+ {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 1,
+ .chan_num = 1, .mode = 1},
+ {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 0,
+ .chan_num = 2, .mode = 1},
+ {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 1,
+ .chan_num = 2, .mode = 1},
+ {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 0,
+ .chan_num = 3, .mode = 1},
+ {.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 1,
+ .chan_num = 3, .mode = 1},
+};
+
+static struct ab8500_bm_platform_data ab8500_bm_plat_data = {
+ .temp_under = 3,
+ .temp_low = 8,
+ .temp_high = 55,
+ .temp_over = 60,
+ .main_safety_tmr_h = 4,
+ .usb_safety_tmr_h = 4,
+ .bkup_bat_v = BUP_VCH_SEL_2P6V,
+ .bkup_bat_i = BUP_ICH_SEL_150UA,
+ .bat_type = {
+ {
+ .name = POWER_SUPPLY_TECHNOLOGY_LION,
+ .resis = BATTERY_NOKIA_BL_5F,
+ .termination_vol = 4200,
+ .termination_curr = 100,
+ .normal_op_cur_lvl = CH_OP_CUR_LVL_0P9,
+ .normal_ip_vol_lvl = CH_VOL_LVL_4P2,
+ .maint_a_op_cur_lvl = CH_OP_CUR_LVL_0P8,
+ .maint_a_ip_vol_lvl = CH_VOL_LVL_4P15,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_op_cur_lvl = CH_OP_CUR_LVL_0P8,
+ .maint_b_ip_vol_lvl = CH_VOL_LVL_4P1,
+ .maint_b_chg_timer_h = 200,
+ .low_high_op_cur_lvl = CH_OP_CUR_LVL_0P3,
+ .low_high_ip_vol_lvl = CH_VOL_LVL_4P0,
+ },
+ {
+ .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+ .resis = BATTERY_NOKIA_BP_5M,
+ .termination_vol = 4200,
+ .termination_curr = 100,
+ .normal_op_cur_lvl = CH_OP_CUR_LVL_0P9,
+ .normal_ip_vol_lvl = CH_VOL_LVL_4P2,
+ .maint_a_op_cur_lvl = CH_OP_CUR_LVL_0P8,
+ .maint_a_ip_vol_lvl = CH_VOL_LVL_4P15,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_op_cur_lvl = CH_OP_CUR_LVL_0P8,
+ .maint_b_ip_vol_lvl = CH_VOL_LVL_4P1,
+ .maint_b_chg_timer_h = 200,
+ .low_high_op_cur_lvl = CH_OP_CUR_LVL_0P3,
+ .low_high_ip_vol_lvl = CH_VOL_LVL_4P0,
+ }
+ },
+};
+
+static void ab8500_spi_cs_control(u32 command)
+{
+ /* set the FRM signal, which is CS - TODO */
+}
+
+struct pl022_config_chip ab8500_chip_info = {
+ .com_mode = INTERRUPT_TRANSFER,
+ .iface = SSP_INTERFACE_MOTOROLA_SPI,
+ /* we can act as master only */
+ .hierarchy = SSP_MASTER,
+ .slave_tx_disable = 0,
+ .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
+ .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
+ .cs_control = ab8500_spi_cs_control,
+};
+
+#ifdef CONFIG_AB8500_DENC
+static struct ab8500_denc_platform_data ab8500_denc_pdata = {
+ .ddr_enable = true,
+ .ddr_little_endian = false,
+};
+#endif
+
+static struct regulator_init_data *u8500_regulators[U8500_NUM_REGULATORS] = {
+ [U8500_REGULATOR_VAPE] = &u8500_vape_regulator,
+ [U8500_REGULATOR_VARM] = &u8500_varm_regulator,
+ [U8500_REGULATOR_VMODEM] = &u8500_vmodem_regulator,
+ [U8500_REGULATOR_VPLL] = &u8500_vpll_regulator,
+ [U8500_REGULATOR_VSMPS1] = &u8500_vsmps1_regulator,
+ [U8500_REGULATOR_VSMPS2] = &u8500_vsmps2_regulator,
+ [U8500_REGULATOR_VSMPS3] = &u8500_vsmps3_regulator,
+ [U8500_REGULATOR_VRF1] = &u8500_vrf1_regulator,
+ [U8500_REGULATOR_SWITCH_SVA_MMDSP] = &u8500_sva_mmdsp_regulator,
+ [U8500_REGULATOR_SWITCH_SVA_PIPE] = &u8500_sva_pipe_regulator,
+ [U8500_REGULATOR_SWITCH_SIA_MMDSP] = &u8500_sia_mmdsp_regulator,
+ [U8500_REGULATOR_SWITCH_SIA_PIPE] = &u8500_sia_pipe_regulator,
+ [U8500_REGULATOR_SWITCH_SGA] = &u8500_sga_regulator,
+ [U8500_REGULATOR_SWITCH_B2R2] = &u8500_b2r2_regulator,
+ [U8500_REGULATOR_SWITCH_MCDE] = &u8500_mcde_regulator,
+ [U8500_REGULATOR_SWITCH_ESRAM1] = &u8500_esram1_regulator,
+ [U8500_REGULATOR_SWITCH_ESRAM2] = &u8500_esram2_regulator,
+ [U8500_REGULATOR_SWITCH_ESRAM3] = &u8500_esram3_regulator,
+ [U8500_REGULATOR_SWITCH_ESRAM4] = &u8500_esram4_regulator,
+};
+
+static struct platform_device u8500_regulator_dev = {
+ .name = "u8500-regulators",
+ .id = 0,
+ .dev = {
+ .platform_data = u8500_regulators,
+ },
+};
+
+/*
+ * NOTE! The regulator configuration below must be in exactly the same order as
+ * the regulator description in the driver, see drivers/regulator/ab8500.c
+ */
+static struct ab8500_platform_data ab8500_platdata = {
+ .irq_base = MOP500_AB8500_IRQ_BASE,
+#ifdef CONFIG_REGULATOR
+ .regulator = {
+ &ab8500_vaux1_regulator,
+ &ab8500_vaux2_regulator,
+ &ab8500_vaux3_regulator,
+ &ab8500_vintcore_regulator,
+ &ab8500_vtvout_regulator,
+ &ab8500_vusb_regulator,
+ &ab8500_vaudio_regulator,
+ &ab8500_vamic1_regulator,
+ &ab8500_vamic2_regulator,
+ &ab8500_vdmic_regulator,
+ &ab8500_vana_regulator,
+ },
+#endif
+#ifdef CONFIG_AB8500_DENC
+ .denc = &ab8500_denc_pdata,
+#endif
+ .battery = &ab8500_bm_plat_data,
+};
+
+static struct resource ab8500_resources[] = {
+ [0] = {
+ .start = IRQ_AB8500,
+ .end = IRQ_AB8500,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+struct platform_device ux500_ab8500_device = {
+ .name = "ab8500-i2c",
+ .id = 0,
+ .dev = {
+ .platform_data = &ab8500_platdata,
+ },
+ .num_resources = 1,
+ .resource = ab8500_resources,
+};
+
+static struct spi_board_info u8500_spi_devices[] = {
+ {
+ .modalias = "ab8500-spi",
+ .controller_data = &ab8500_chip_info,
+ .platform_data = &ab8500_platdata,
+ .max_speed_hz = 12000000,
+ .bus_num = SSP_0_CONTROLLER,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ .irq = IRQ_DB8500_AB8500,
+ },
+};
+
+#ifdef CONFIG_LEDS_PWM
+static struct led_pwm pwm_leds_data[] = {
+ [0] = {
+ .name = "lcd-backlight",
+ .pwm_id = 1,
+ .max_brightness = 255,
+ .lth_brightness = 90,
+ .pwm_period_ns = 1023,
+ },
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY
+ [1] = {
+ .name = "sec-lcd-backlight",
+ .pwm_id = 2,
+ .max_brightness = 255,
+ .lth_brightness = 90,
+ .pwm_period_ns = 1023,
+ },
+#endif
+};
-static struct amba_device *amba_devs[] __initdata = {
- &ux500_uart0_device,
- &ux500_uart1_device,
- &ux500_uart2_device,
- &u8500_ssp0_device,
+static struct led_pwm_platform_data u8500_leds_data = {
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY
+ .num_leds = 2,
+#else
+ .num_leds = 1,
+#endif
+ .leds = &pwm_leds_data,
};
-/* add any platform devices here - TODO */
+static struct platform_device ux500_leds_device = {
+ .name = "leds_pwm",
+ .dev = {
+ .platform_data = &u8500_leds_data,
+ },
+};
+#endif
+
+#ifdef CONFIG_BACKLIGHT_PWM
+static struct platform_pwm_backlight_data u8500_backlight_data[] = {
+ [0] = {
+ .pwm_id = 1,
+ .max_brightness = 255,
+ .dft_brightness = 200,
+ .lth_brightness = 90,
+ .pwm_period_ns = 1023,
+ },
+ [1] = {
+ .pwm_id = 2,
+ .max_brightness = 255,
+ .dft_brightness = 200,
+ .lth_brightness = 90,
+ .pwm_period_ns = 1023,
+ },
+};
+
+static struct platform_device ux500_backlight_device[] = {
+ [0] = {
+ .name = "pwm-backlight",
+ .id = 0,
+ .dev = {
+ .platform_data = &u8500_backlight_data[0],
+ },
+ },
+ [1] = {
+ .name = "pwm-backlight",
+ .id = 1,
+ .dev = {
+ .platform_data = &u8500_backlight_data[1],
+ },
+ },
+};
+#endif
+
+/* Force feedback vibrator device */
+static struct platform_device ste_ff_vibra_device = {
+ .name = "ste_ff_vibra"
+};
+
+static struct platform_device *u8500_platform_devices[] __initdata = {
+ /*TODO - add platform devices here */
+#ifdef CONFIG_SENSORS1P_MOP
+ &sensors1p_device,
+#endif
+#ifdef CONFIG_LEDS_PWM
+ &ux500_leds_device,
+#endif
+#ifdef CONFIG_BACKLIGHT_PWM
+ &ux500_backlight_device[0],
+ &ux500_backlight_device[1],
+#endif
+};
static struct platform_device *platform_devs[] __initdata = {
- &u8500_i2c0_device,
- &ux500_i2c1_device,
- &ux500_i2c2_device,
- &ux500_i2c3_device,
+ &u8500_hsit_device,
+ &u8500_hsir_device,
+ &u8500_shrm_device,
+ &ste_ff_vibra_device,
+ &ux500_musb_device,
+ &ux500_hwmem_device,
+ &ux500_mcde_device,
+ &ux500_b2r2_device,
+#ifdef CONFIG_CRYPTO_DEV_UX500_HASH
+ &ux500_hash1_device,
+#endif
+#ifdef CONFIG_USB_ANDROID
+ &android_usb_device,
+#ifdef CONFIG_USB_ANDROID_MASS_STORAGE
+ &usb_mass_storage_device,
+#endif
+#ifdef CONFIG_USB_ANDROID_ECM
+ &usb_ecm_device,
+#endif
+#endif
};
-static void __init u8500_init_machine(void)
+static void __init mop500_i2c_init(void)
{
- int i;
+ db8500_add_i2c0(&mop500_i2c0_data);
+ db8500_add_i2c1(&mop500_i2c1_data);
+ db8500_add_i2c2(&mop500_i2c2_data);
+ db8500_add_i2c3(&mop500_i2c3_data);
- u8500_i2c0_device.dev.platform_data = &u8500_i2c0_data;
- ux500_i2c1_device.dev.platform_data = &u8500_i2c1_data;
- ux500_i2c2_device.dev.platform_data = &u8500_i2c2_data;
- ux500_i2c3_device.dev.platform_data = &u8500_i2c3_data;
+ i2c_register_board_info(0, ARRAY_AND_SIZE(mop500_i2c0_devices));
+ i2c_register_board_info(1, ARRAY_AND_SIZE(mop500_i2c1_devices));
+ i2c_register_board_info(2, ARRAY_AND_SIZE(mop500_i2c2_devices));
+ i2c_register_board_info(3, ARRAY_AND_SIZE(mop500_i2c3_devices));
+}
- u8500_ssp0_device.dev.platform_data = &ssp0_platform_data;
+static void __init mop500_spi_init(void)
+{
+ db8500_add_ssp0(&mop500_ssp0_data);
+ db8500_add_msp2_spi(&mop500_msp2_spi_data);
+}
- /* Register the active AMBA devices on this board */
- for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
- amba_device_register(amba_devs[i], &iomem_resource);
+static void __init mop500_uart_init(void)
+{
+ db8500_add_uart0();
+ db8500_add_uart1();
+ db8500_add_uart2();
+}
+
+static void __init mop500_init_machine(void)
+{
+ stm_gpio_set_altfunctable(gpio_altfun_table,
+ ARRAY_SIZE(gpio_altfun_table));
+
+#ifdef CONFIG_REGULATOR
+ platform_device_register(&u8500_regulator_dev);
+#endif
+
+ u8500_init_devices();
+
+ nmk_config_pins(mop500_pins, ARRAY_SIZE(mop500_pins));
platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
- spi_register_board_info(u8500_spi_devices,
+ /* If HW is early drop (ED) or V1.0 then use SPI to access AB8500 */
+ if (cpu_is_u8500ed() || cpu_is_u8500v10())
+ spi_register_board_info(u8500_spi_devices,
ARRAY_SIZE(u8500_spi_devices));
+ else /* If HW is v.1.1 or later use I2C to access AB8500 */
+ platform_device_register(&ux500_ab8500_device);
+ mop500_i2c_init();
+ mop500_msp_init();
+ mop500_spi_init();
+ mop500_uart_init();
- u8500_init_devices();
+ db8500_add_ske_keypad(&mop500_ske_keypad_data);
+
+ /* enable RTC as a wakeup capable */
+ device_init_wakeup(&ux500_rtc_device.dev, true);
+ hsi_register_board_info(stm_hsi_devices, ARRAY_SIZE(stm_hsi_devices));
+#ifdef CONFIG_MOP500_NUIB
+ mop500_nuib_init();
+#endif
+ platform_add_devices(u8500_platform_devices,
+ ARRAY_SIZE(u8500_platform_devices));
}
-MACHINE_START(U8500, "ST-Ericsson MOP500 platform")
+MACHINE_START(U8500, "ST-Ericsson U8500 Platform")
/* Maintainer: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> */
- .phys_io = U8500_UART2_BASE,
- .io_pg_offst = (IO_ADDRESS(U8500_UART2_BASE) >> 18) & 0xfffc,
- .boot_params = 0x100,
+ .phys_io = UX500_UART2_BASE,
+ .io_pg_offst = (IO_ADDRESS(UX500_UART2_BASE) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
.map_io = u8500_map_io,
.init_irq = ux500_init_irq,
- /* we re-use nomadik timer here */
- .timer = &ux500_timer,
- .init_machine = u8500_init_machine,
+ .timer = &u8500_timer,
+ .init_machine = mop500_init_machine,
+MACHINE_END
+
+MACHINE_START(NOMADIK, "ST-Ericsson U8500 Platform")
+ /* Maintainer: ST-Ericsson */
+ .phys_io = UX500_UART2_BASE,
+ .io_pg_offst = (IO_ADDRESS(UX500_UART2_BASE) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = u8500_map_io,
+ .init_irq = ux500_init_irq,
+ .timer = &u8500_timer,
+ .init_machine = mop500_init_machine,
+MACHINE_END
+
+MACHINE_START(SVP8500V1, "ST-Ericsson U8500 Simulator (V1)")
+ .phys_io = UX500_UART2_BASE,
+ .io_pg_offst = (IO_ADDRESS(UX500_UART2_BASE) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = u8500_map_io,
+ .init_irq = ux500_init_irq,
+ .timer = &u8500_timer,
+ .init_machine = mop500_init_machine,
+MACHINE_END
+
+MACHINE_START(SVP8500V2, "ST-Ericsson U8500 Simulator (V2)")
+ .phys_io = UX500_UART2_BASE,
+ .io_pg_offst = (IO_ADDRESS(UX500_UART2_BASE) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = u8500_map_io,
+ .init_irq = ux500_init_irq,
+ .timer = &u8500_timer,
+ .init_machine = mop500_init_machine,
MACHINE_END
diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h
new file mode 100644
index 00000000000..354e83657b3
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __BOARD_MOP500_H
+#define __BOARD_MOP500_H
+
+void mop500_nuib_init(void);
+void mop500_msp_init(void);
+
+#endif
diff --git a/arch/arm/mach-ux500/board-pdp-mcde.c b/arch/arm/mach-ux500/board-pdp-mcde.c
new file mode 100644
index 00000000000..1fa4da59367
--- /dev/null
+++ b/arch/arm/mach-ux500/board-pdp-mcde.c
@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <mach/ab8500_denc.h>
+#include <video/av8100.h>
+#include <video/mcde_display.h>
+#include <video/mcde_display-sony_sy35560_dsi.h>
+#include <video/mcde_display-av8100.h>
+#include <video/mcde_display-ab8500.h>
+#include <video/mcde_fb.h>
+#include <video/mcde_dss.h>
+
+#define DSI_UNIT_INTERVAL_0 0x9
+#define DSI_UNIT_INTERVAL_1 0x9
+#define DSI_UNIT_INTERVAL_2 0x6
+
+#define PRIMARY_DISPLAY_ID 0
+#define SECONDARY_DISPLAY_ID 1
+#define TERTIARY_DISPLAY_ID 2
+
+#define ROTATE_MAIN 0
+
+static int display_initialized_during_boot;
+
+static int __init startup_graphics_setup(char *str)
+{
+
+ if (get_option(&str, &display_initialized_during_boot) != 1)
+ display_initialized_during_boot = 0;
+
+ switch (display_initialized_during_boot) {
+ case 1:
+ pr_info("Startup graphics support\n");
+ break;
+ case 0:
+ default:
+ pr_info("No startup graphics supported\n");
+ break;
+ };
+
+ return 1;
+}
+__setup("startup_graphics=", startup_graphics_setup);
+
+#ifdef CONFIG_DISPLAY_SONY_SY35560_DSI_PRIMARY
+
+static int sony_sy35560_update(struct mcde_display_device *dev)
+{
+ int ret;
+
+ /* TODO: Dirty */
+ if (dev->prepare_for_update) {
+ /* TODO: Send dirty rectangle */
+ ret = dev->prepare_for_update(dev, 0, 0,
+ dev->native_x_res, dev->native_y_res);
+ if (ret < 0) {
+ dev_warn(&dev->dev,
+ "%s:Failed to prepare for update\n", __func__);
+ return ret;
+ }
+ }
+ /* TODO: Calculate & set update rect */
+ ret = mcde_chnl_update(dev->chnl_state, &dev->update_area);
+ if (ret < 0) {
+ dev_warn(&dev->dev, "%s:Failed to update channel\n", __func__);
+ return ret;
+ }
+ if (dev->first_update && dev->on_first_update)
+ dev->on_first_update(dev);
+
+ if (dev->power_mode != MCDE_DISPLAY_PM_ON && dev->set_power_mode) {
+ /* need to wait a while before turning on the display */
+ mdelay(5);
+ ret = dev->set_power_mode(dev, MCDE_DISPLAY_PM_ON);
+ if (ret < 0) {
+ dev_warn(&dev->dev,
+ "%s:Failed to set power mode to on\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ dev_vdbg(&dev->dev, "Overlay updated, chnl=%d\n", dev->chnl_id);
+
+ return 0;
+}
+
+static int sony_sy35560_platform_enable(struct mcde_display_device *dev)
+{
+ int ret = 0;
+ struct sony_sy35560_platform_data *pdata =
+ dev->dev.platform_data;
+
+ dev_info(&dev->dev, "%s: Reset & power on sony display\n", __func__);
+
+ if (pdata->regulator_id) {
+ ((struct sony_sy35560_device *)dev)->regulator =
+ regulator_get(NULL, pdata->regulator_id);
+ if (IS_ERR(((struct sony_sy35560_device *)dev)->regulator)) {
+ ret = PTR_ERR(
+ ((struct sony_sy35560_device *)dev)->regulator);
+ dev_err(&dev->dev,
+ "%s:Failed to get regulator '%s'\n",
+ __func__, pdata->regulator_id);
+ ((struct sony_sy35560_device *)dev)->regulator = NULL;
+ goto out;
+ }
+ regulator_set_voltage(
+ ((struct sony_sy35560_device *)dev)->regulator,
+ pdata->min_supply_voltage,
+ pdata->max_supply_voltage);
+ ret = regulator_enable(
+ ((struct sony_sy35560_device *)dev)->regulator);
+ if (ret < 0) {
+ dev_err(&dev->dev,
+ "%s:Failed to enable regulator\n"
+ , __func__);
+ goto out;
+ }
+ }
+
+ if (!pdata->skip_init) {
+ dev_info(&dev->dev,
+ "%s: Startup graphics disabled, doing full init\n",
+ __func__);
+ if (pdata->reset_gpio) {
+ ret = gpio_request(pdata->reset_gpio, NULL);
+ if (ret) {
+ dev_warn(&dev->dev,
+ "%s:Failed to request gpio %d\n",
+ __func__, pdata->reset_gpio);
+ goto out;
+ }
+
+ gpio_direction_output(pdata->reset_gpio, 1);
+ gpio_set_value(pdata->reset_gpio, 0);
+ mdelay(1);
+ gpio_set_value(pdata->reset_gpio, 1);
+ }
+ } else {
+ dev_info(&dev->dev,
+ "%s: Display already initialized during boot\n",
+ __func__);
+ pdata->skip_init = false;
+ }
+
+ dev->update = sony_sy35560_update;
+
+ /* TODO: Remove when DSI send command uses interrupts */
+ dev->prepare_for_update = NULL;
+
+#ifdef CONFIG_SONY_SY35560_ENABLE_ESD_CHECK
+ /* add ESD status check to workqueue */
+ queue_delayed_work(((struct sony_sy35560_device *)dev)->esd_wq,
+ &(((struct sony_sy35560_device *)dev)->esd_work),
+ SONY_SY35560_ESD_CHECK_PERIOD);
+#endif
+
+out:
+ if (pdata->reset_gpio)
+ gpio_free(pdata->reset_gpio);
+ return ret;
+}
+
+static int sony_sy35560_platform_disable(struct mcde_display_device *dev)
+{
+ dev_info(&dev->dev, "%s: Reset & power off sony display\n", __func__);
+
+ if (((struct sony_sy35560_device *)dev)->regulator) {
+ if (regulator_disable(
+ ((struct sony_sy35560_device *)dev)->regulator) < 0)
+ dev_err(&dev->dev,
+ "%s:Failed to disable regulator\n",
+ __func__);
+ }
+ return 0;
+}
+
+static struct mcde_port port0 = {
+ .type = MCDE_PORTTYPE_DSI,
+ .mode = MCDE_PORTMODE_CMD,
+ .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP,
+ .ifc = 1,
+ .link = 0,
+ .sync_src = MCDE_SYNCSRC_BTA,
+ .update_auto_trig = false,
+ .phy = {
+ .dsi = {
+ .virt_id = 0,
+ .num_data_lanes = 2,
+ .ui = DSI_UNIT_INTERVAL_0,
+ .clk_cont = false,
+ },
+ },
+};
+
+struct sony_sy35560_platform_data sony_sy35560_display0_pdata = {
+ .reset_gpio = EGPIO_PIN_15,
+#ifdef CONFIG_REGULATOR
+ .regulator_id = "v-display",
+ .min_supply_voltage = 2800000, /* 2.8V */
+ .max_supply_voltage = 2800000 /* 2.8V */
+#endif
+};
+
+struct sony_sy35560_device sony_sy35560_display0 = {
+ .base = {
+ .name = "mcde_disp_sony",
+ .id = PRIMARY_DISPLAY_ID,
+ .port = &port0,
+ .chnl_id = MCDE_CHNL_A,
+ .fifo = MCDE_FIFO_C0,
+ .default_pixel_format = MCDE_OVLYPIXFMT_RGB565,
+ .native_x_res = 480,
+ .native_y_res = 854,
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_VSYNC
+ .synchronized_update = true,
+#else
+ .synchronized_update = false,
+#endif
+ .platform_enable = sony_sy35560_platform_enable,
+ .platform_disable = sony_sy35560_platform_disable,
+ /* TODO: Remove rotation buffers once ESRAM driver
+ * is completed */
+ .rotbuf1 = U8500_ESRAM_BASE + 0x20000 * 4,
+ .rotbuf2 = U8500_ESRAM_BASE + 0x20000 * 4 + 0x10000,
+ .dev = {
+ .platform_data = &sony_sy35560_display0_pdata,
+ },
+ }
+};
+#endif /* CONFIG_DISPLAY_SONY_SY35560_DSI_PRIMARY */
+
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY
+static struct mcde_port subdisplay_port = {
+ .type = MCDE_PORTTYPE_DSI,
+ .mode = MCDE_PORTMODE_CMD,
+ .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP,
+ .ifc = 1,
+ .link = 1,
+ .sync_src = MCDE_SYNCSRC_BTA,
+ .update_auto_trig = false,
+ .phy = {
+ .dsi = {
+ .virt_id = 0,
+ .num_data_lanes = 2,
+ .ui = DSI_UNIT_INTERVAL_1,
+ .clk_cont = false,
+ },
+ },
+
+};
+
+static struct mcde_display_generic_platform_data generic_subdisplay_pdata = {
+ .reset_gpio = EGPIO_PIN_14,
+ .reset_delay = 1,
+#ifdef CONFIG_REGULATOR
+ .regulator_id = "v-display",
+ .min_supply_voltage = 2500000, /* 2.5V */
+ .max_supply_voltage = 2700000 /* 2.7V */
+#endif
+};
+
+static struct mcde_display_device generic_subdisplay = {
+ .name = "mcde_disp_generic_subdisplay",
+ .id = SECONDARY_DISPLAY_ID,
+ .port = &subdisplay_port,
+ .chnl_id = MCDE_CHNL_C1,
+ .fifo = MCDE_FIFO_C1,
+ .default_pixel_format = MCDE_OVLYPIXFMT_RGB565,
+ .native_x_res = 864,
+ .native_y_res = 480,
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY_VSYNC
+ .synchronized_update = true,
+#else
+ .synchronized_update = false,
+#endif
+ .dev = {
+ .platform_data = &generic_subdisplay_pdata,
+ },
+};
+#endif /* CONFIG_DISPLAY_GENERIC_DSI_SECONDARY */
+
+
+#ifdef CONFIG_DISPLAY_AB8500_TERTIARY
+static struct mcde_port port_tvout1 = {
+ .type = MCDE_PORTTYPE_DPI,
+ .pixel_format = MCDE_PORTPIXFMT_DPI_24BPP,
+ .ifc = 0,
+ .link = 1,
+ .sync_src = MCDE_SYNCSRC_OFF,
+ .update_auto_trig = true,
+ .phy = {
+ .dpi = {
+ .bus_width = 4, /* DDR mode */
+ },
+ },
+};
+
+static struct ab8500_display_platform_data ab8500_display_pdata = {
+ /* REVIEW use "#ifdef CONFIG_REGULATOR" as with other displays */
+ /* TODO use this ID as soon as we switch to newer kernel with support
+ * or ab8500 TVout regulator
+ .regulator_id = "v-tvout",
+ */
+ /* REVIEW change name: use transform instead of convert? */
+ .rgb_2_yCbCr_convert = {
+ .matrix = {
+ {0x42, 0x81, 0x19},
+ {0xffda, 0xffb6, 0x70},
+ {0x70, 0xffa2, 0xffee},
+ },
+ .offset = {0x80, 0x10, 0x80},
+ }
+};
+
+static int ab8500_platform_enable(struct mcde_display_device *ddev)
+{
+ int res = 0;
+ /* probe checks for pdata */
+ struct ab8500_display_platform_data *pdata = ddev->dev.platform_data;
+
+ dev_info(&ddev->dev, "%s\n", __func__);
+ res = stm_gpio_altfuncenable(GPIO_ALT_LCD_PANELB);
+ if (res != 0)
+ goto alt_func_failed;
+
+ if (pdata->regulator) {
+ res = regulator_enable(pdata->regulator);
+ if (res != 0)
+ goto regu_failed;
+ }
+
+ return res;
+
+regu_failed:
+ (void) stm_gpio_altfuncdisable(GPIO_ALT_LCD_PANELB);
+alt_func_failed:
+ dev_warn(&ddev->dev, "Failure during %s\n", __func__);
+ return res;
+}
+
+static int ab8500_platform_disable(struct mcde_display_device *ddev)
+{
+ int res;
+ /* probe checks for pdata */
+ struct ab8500_display_platform_data *pdata = ddev->dev.platform_data;
+
+ dev_info(&ddev->dev, "%s\n", __func__);
+
+ res = stm_gpio_altfuncdisable(GPIO_ALT_LCD_PANELB);
+ if (res != 0)
+ goto alt_func_failed;
+
+ if (pdata->regulator) {
+ res = regulator_disable(pdata->regulator);
+ if (res != 0)
+ goto regu_failed;
+ }
+
+ return res;
+regu_failed:
+ (void) stm_gpio_altfuncenable(GPIO_ALT_LCD_PANELB);
+alt_func_failed:
+ dev_warn(&ddev->dev, "Failure during %s\n", __func__);
+ return res;
+
+}
+
+static struct mcde_display_device tvout_ab8500_display = {
+ .name = "mcde_tv_ab8500",
+ .id = TERTIARY_DISPLAY_ID,
+ .port = &port_tvout1,
+ .chnl_id = MCDE_CHNL_B,
+ .fifo = MCDE_FIFO_B,
+ .default_pixel_format = MCDE_OVLYPIXFMT_RGB565,
+ .native_x_res = 720,
+ .native_y_res = 576,
+ .synchronized_update = true,
+ .dev = {
+ .platform_data = &ab8500_display_pdata,
+ },
+
+ /*
+ * We might need to describe the std here:
+ * - there are different PAL / NTSC formats (do they require MCDE
+ * settings?)
+ */
+ .platform_enable = ab8500_platform_enable,
+ .platform_disable = ab8500_platform_disable,
+};
+
+static struct ab8500_denc_platform_data ab8500_denc_pdata = {
+ .ddr_enable = true,
+ .ddr_little_endian = false,
+};
+
+static struct platform_device ab8500_denc = {
+ .name = "ab8500_denc",
+ .id = -1,
+ .dev = {
+ .platform_data = &ab8500_denc_pdata,
+ },
+};
+#endif /* CONFIG_DISPLAY_AB8500_TERTIARY */
+
+#ifdef CONFIG_DISPLAY_AV8100_TERTIARY
+static struct mcde_port port2 = {
+ .type = MCDE_PORTTYPE_DSI,
+ .mode = MCDE_PORTMODE_CMD,
+ .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP,
+ .ifc = 1,
+ .link = 2,
+#ifdef CONFIG_AV8100_HWTRIG_I2SDAT3
+ .sync_src = MCDE_SYNCSRC_TE1,
+#else
+ .sync_src = MCDE_SYNCSRC_TE0,
+#endif /* CONFIG_AV8100_HWTRIG_I2SDAT3 */
+ .update_auto_trig = true,
+ .phy = {
+ .dsi = {
+ .virt_id = 0,
+ .num_data_lanes = 2,
+ .ui = DSI_UNIT_INTERVAL_2,
+ .clk_cont = false,
+ },
+ },
+};
+
+struct mcde_display_hdmi_platform_data av8100_hdmi_pdata = {
+ .reset_gpio = 0,
+ .reset_delay = 1,
+ .regulator_id = NULL, /* TODO: "display_main" */
+ .ddb_id = 1,
+ .rgb_2_yCbCr_convert = {
+ .matrix = {
+ {0x42, 0x81, 0x19},
+ {0xffda, 0xffb6, 0x70},
+ {0x70, 0xffa2, 0xffee},
+ },
+ .offset = {0x80, 0x10, 0x80},
+ }
+};
+
+static int av8100_platform_enable(struct mcde_display_device *dev)
+{
+ int ret;
+ struct mcde_display_hdmi_platform_data *pdata =
+ dev->dev.platform_data;
+
+ ret = stm_gpio_altfuncenable(GPIO_ALT_LCD_PANELA);
+ if (ret)
+ goto alt_func_failed;
+
+ if (pdata->reset_gpio)
+ gpio_set_value(pdata->reset_gpio, pdata->reset_high);
+ if (pdata->regulator)
+ ret = regulator_enable(pdata->regulator);
+alt_func_failed:
+ return ret;
+}
+
+static int av8100_platform_disable(struct mcde_display_device *dev)
+{
+ int ret;
+ struct mcde_display_hdmi_platform_data *pdata =
+ dev->dev.platform_data;
+
+ ret = stm_gpio_altfuncdisable(GPIO_ALT_LCD_PANELA);
+ if (ret)
+ goto alt_func_failed;
+ if (pdata->reset_gpio)
+ gpio_set_value(pdata->reset_gpio, !pdata->reset_high);
+ if (pdata->regulator)
+ ret = regulator_disable(pdata->regulator);
+alt_func_failed:
+ return ret;
+}
+
+static struct mcde_display_device av8100_hdmi = {
+ .name = "av8100_hdmi",
+ .id = TERTIARY_DISPLAY_ID,
+ .port = &port2,
+ .chnl_id = MCDE_CHNL_B,
+ .fifo = MCDE_FIFO_B,
+ .default_pixel_format = MCDE_OVLYPIXFMT_RGB565,
+#ifdef CONFIG_AV8100_SDTV
+ .native_x_res = 720,
+ .native_y_res = 576,
+#else
+ .native_x_res = 1280,
+ .native_y_res = 720,
+#endif
+ .synchronized_update = true,
+ .dev = {
+ .platform_data = &av8100_hdmi_pdata,
+ },
+ .platform_enable = av8100_platform_enable,
+ .platform_disable = av8100_platform_disable,
+};
+#endif /* CONFIG_DISPLAY_AV8100_TERTIARY */
+
+static struct fb_info *fbs[3] = { NULL, NULL, NULL };
+static struct mcde_display_device *displays[3] = { NULL, NULL, NULL };
+
+static int display_postregistered_callback(struct notifier_block *nb,
+ unsigned long event, void *dev)
+{
+ struct mcde_display_device *ddev = dev;
+ u16 width, height;
+ u16 virtual_width, virtual_height;
+ bool rotate;
+
+ if (event != MCDE_DSS_EVENT_DISPLAY_REGISTERED)
+ return 0;
+
+ if (ddev->id < PRIMARY_DISPLAY_ID || ddev->id >= ARRAY_SIZE(fbs))
+ return 0;
+
+ mcde_dss_get_native_resolution(ddev, &width, &height);
+
+ rotate = (ddev->id == 0 && ROTATE_MAIN);
+ if (rotate) {
+ u16 tmp = height;
+ height = width;
+ width = tmp;
+ }
+
+ virtual_width = width;
+ virtual_height = height * 2;
+
+ /* Create frame buffer */
+ fbs[ddev->id] = mcde_fb_create(ddev,
+ width, height,
+ virtual_width, virtual_height,
+ ddev->default_pixel_format,
+ rotate ? FB_ROTATE_CW : FB_ROTATE_UR);
+ if (IS_ERR(fbs[ddev->id]))
+ pr_warning("Failed to create fb for display %s\n", ddev->name);
+ else
+ pr_info("Framebuffer created (%s)\n", ddev->name);
+
+ return 0;
+}
+
+static struct notifier_block display_nb = {
+ .notifier_call = display_postregistered_callback,
+};
+
+static int framebuffer_postregistered_callback(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ int ret = 0;
+ struct fb_event *event_data = data;
+ struct fb_info *info;
+ struct fb_var_screeninfo var;
+ struct fb_fix_screeninfo fix;
+ struct mcde_fb *mfb;
+ u8 *addr;
+
+ if (event != FB_EVENT_FB_REGISTERED)
+ return 0;
+
+ if (!event_data)
+ return 0;
+
+ info = event_data->info;
+ mfb = to_mcde_fb(info);
+ if (mfb->id == 0 && display_initialized_during_boot)
+ goto out;
+
+
+ var = info->var;
+ fix = info->fix;
+ addr = ioremap(fix.smem_start,
+ var.yres_virtual * fix.line_length);
+ memset(addr, 0x00,
+ var.yres_virtual * fix.line_length);
+ var.yoffset = var.yoffset ? 0 : var.yres;
+ if (info->fbops->fb_pan_display)
+ ret = info->fbops->fb_pan_display(&var, info);
+out:
+ return ret;
+}
+
+static struct notifier_block framebuffer_nb = {
+ .notifier_call = framebuffer_postregistered_callback,
+};
+
+int __init init_display_devices(void)
+{
+ int ret;
+
+ ret = fb_register_client(&framebuffer_nb);
+ if (ret)
+ pr_warning("Failed to register framebuffer notifier\n");
+
+ ret = mcde_dss_register_notifier(&display_nb);
+ if (ret)
+ pr_warning("Failed to register dss notifier\n");
+
+#ifdef CONFIG_DISPLAY_SONY_SY35560_DSI_PRIMARY
+ /* TODO: enable this code if uboot graphics should be used
+ if (display_initialized_during_boot)
+ ((struct sony_sy35560_platform_data *)sony_sy35560_display0.
+ base.dev.platform_data)->skip_init = true;
+ */
+ ret = mcde_display_device_register(
+ (struct mcde_display_device *)&sony_sy35560_display0);
+ if (ret)
+ pr_warning("Failed to register Sony sy35560 display device 0\n");
+ displays[0] = (struct mcde_display_device *)&sony_sy35560_display0;
+#endif
+
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_SECONDARY
+ ret = mcde_display_device_register(&generic_subdisplay);
+ if (ret)
+ pr_warning("Failed to register generic sub display device\n");
+ displays[1] = &generic_subdisplay;
+#endif
+
+#ifdef CONFIG_DISPLAY_AV8100_TERTIARY
+ ret = mcde_display_device_register(&av8100_hdmi);
+ if (ret)
+ pr_warning("Failed to register av8100_hdmi\n");
+ displays[2] = &av8100_hdmi;
+#endif
+#ifdef CONFIG_DISPLAY_AB8500_TERTIARY
+ ret = platform_device_register(&ab8500_denc);
+ if (ret)
+ pr_warning("Failed to register ab8500_denc device\n");
+ else {
+ ret = mcde_display_device_register(&tvout_ab8500_display);
+ if (ret)
+ pr_warning("Failed to register ab8500 tvout device\n");
+ displays[2] = &tvout_ab8500_display;
+ }
+#endif
+
+ return ret;
+}
+
+module_init(init_display_devices);
diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c
index 4430e69cf53..6c7b67623de 100644
--- a/arch/arm/mach-ux500/board-u5500.c
+++ b/arch/arm/mach-ux500/board-u5500.c
@@ -8,34 +8,358 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/amba/bus.h>
+#include <linux/amba/pl022.h>
#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/i2s/i2s.h>
+#include <linux/input/synaptics_i2c_rmi4.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mmc/host.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
-#include <mach/hardware.h>
+#include <plat/pincfg.h>
+#include <plat/i2c.h>
+#include <mach/msp.h>
#include <mach/devices.h>
#include <mach/setup.h>
+#include <mach/db5500-keypad.h>
+#include <mach/mmc.h>
-static struct amba_device *amba_board_devs[] __initdata = {
- &ux500_uart0_device,
- &ux500_uart1_device,
- &ux500_uart2_device,
+#include "pins-db5500.h"
+#include "devices-db5500.h"
+
+/*
+ * GPIO
+ */
+
+static pin_cfg_t u5500_pins[] = {
+ /* I2C */
+ GPIO3_I2C1_SCL | PIN_INPUT_PULLUP,
+ GPIO4_I2C1_SDA | PIN_INPUT_PULLUP,
+
+ /* Keypad */
+ GPIO128_KP_I0 | PIN_INPUT_PULLUP,
+ GPIO130_KP_I1 | PIN_INPUT_PULLUP,
+ GPIO132_KP_I2 | PIN_INPUT_PULLUP,
+ GPIO134_KP_I3 | PIN_INPUT_PULLUP,
+ GPIO137_KP_O4 | PIN_INPUT_PULLUP,
+ GPIO139_KP_O5 | PIN_INPUT_PULLUP,
+
+ /* MSP */
+ GPIO32_MSP0_TCK | PIN_INPUT_PULLDOWN,
+ GPIO33_MSP0_TFS | PIN_INPUT_PULLDOWN,
+ GPIO34_MSP0_TXD | PIN_INPUT_PULLDOWN,
+ GPIO35_MSP0_RXD | PIN_INPUT_PULLDOWN,
+ GPIO96_MSP1_TCK | PIN_INPUT_PULLDOWN,
+ GPIO97_MSP1_TFS | PIN_INPUT_PULLDOWN,
+ GPIO98_MSP1_TXD | PIN_INPUT_PULLDOWN,
+ GPIO99_MSP1_RXD | PIN_INPUT_PULLDOWN,
+ GPIO220_MSP2_TCK | PIN_OUTPUT_LOW,
+ GPIO221_MSP2_TFS | PIN_OUTPUT_LOW,
+ GPIO222_MSP2_TXD | PIN_OUTPUT_LOW,
+
+ /* MMC0 (POP eMMC) */
+ GPIO5_MC0_DAT0 | PIN_INPUT_PULLUP,
+ GPIO6_MC0_DAT1 | PIN_INPUT_PULLUP,
+ GPIO7_MC0_DAT2 | PIN_INPUT_PULLUP,
+ GPIO8_MC0_DAT3 | PIN_INPUT_PULLUP,
+ GPIO9_MC0_DAT4 | PIN_INPUT_PULLUP,
+ GPIO10_MC0_DAT5 | PIN_INPUT_PULLUP,
+ GPIO11_MC0_DAT6 | PIN_INPUT_PULLUP,
+ GPIO12_MC0_DAT7 | PIN_INPUT_PULLUP,
+ GPIO13_MC0_CMD | PIN_INPUT_PULLUP,
+ GPIO14_MC0_CLK | PIN_OUTPUT_LOW,
+
+ /* SPI */
+ GPIO167_SPI1_CS0n | PIN_OUTPUT_HIGH,
+ GPIO168_SPI1_RXD | PIN_INPUT_PULLDOWN,
+ GPIO169_SPI1_TXD | PIN_OUTPUT_LOW,
+ GPIO170_SPI1_CLK | PIN_OUTPUT_LOW,
+
+ /* TOUCH_IRQ */
+ GPIO179_GPIO | PIN_INPUT_PULLUP,
+};
+
+static struct gpio_altfun_data gpio_altfun_table[] = {
+ __GPIO_ALT(GPIO_ALT_I2C_4, 4, 5, 0, NMK_GPIO_ALT_B, "i2c4"),
+ __GPIO_ALT(GPIO_ALT_I2C_1, 16, 17, 0, NMK_GPIO_ALT_B, "i2c1"),
+ __GPIO_ALT(GPIO_ALT_I2C_2, 8, 9, 0, NMK_GPIO_ALT_B, "i2c2"),
+ __GPIO_ALT(GPIO_ALT_I2C_0, 147, 148, 0, NMK_GPIO_ALT_A, "i2c0"),
+ __GPIO_ALT(GPIO_ALT_I2C_3, 229, 230, 0, NMK_GPIO_ALT_C, "i2c3"),
+ __GPIO_ALT(GPIO_ALT_USB_OTG, 256, 267, 0, NMK_GPIO_ALT_A, "usb"),
+ __GPIO_ALT(GPIO_ALT_MSP_0, 12, 15, 0, NMK_GPIO_ALT_A, "msp0"),
+ __GPIO_ALT(GPIO_ALT_MSP_1, 33, 36, 0, NMK_GPIO_ALT_A, "msp1"),
+ __GPIO_ALT(GPIO_ALT_MSP_2, 192, 196, 0, NMK_GPIO_ALT_A, "msp2"),
+ __GPIO_ALT(GPIO_ALT_HSIR, 219, 221, 0, NMK_GPIO_ALT_A, "hsir"),
+ __GPIO_ALT(GPIO_ALT_HSIT, 222, 224, 0, NMK_GPIO_ALT_A, "hsit"),
+ __GPIO_ALT(GPIO_ALT_TRACE, 70, 74, 0, NMK_GPIO_ALT_C, "stm"),
+#ifndef CONFIG_FB_NOMADIK_MCDE_CHANNELB_DISPLAY_VUIB_WVGA
+ __GPIO_ALT(GPIO_ALT_LCD_PANELB_ED, 78, 85, 1, NMK_GPIO_ALT_A, "mcde tvout"),
+ __GPIO_ALT(GPIO_ALT_LCD_PANELB_ED, 150, 150, 0, NMK_GPIO_ALT_B, "mcde tvout"),
+ __GPIO_ALT(GPIO_ALT_LCD_PANELB, 78, 81, 1, NMK_GPIO_ALT_A, "mcde tvout"),
+ __GPIO_ALT(GPIO_ALT_LCD_PANELB, 150, 150, 0, NMK_GPIO_ALT_B, "mcde tvout"),
+#else
+ __GPIO_ALT(GPIO_ALT_LCD_PANELB, 153, 171, 1, NMK_GPIO_ALT_B, "mcde tvout"),
+ __GPIO_ALT(GPIO_ALT_LCD_PANELB, 64, 77, 0, NMK_GPIO_ALT_A, "mcde tvout"),
+#endif
+ __GPIO_ALT(GPIO_ALT_LCD_PANELA, 68, 68, 0, NMK_GPIO_ALT_A, "mcde tvout"),
+ __GPIO_ALT(GPIO_ALT_MMIO_INIT_BOARD, 141, 142, 0, NMK_GPIO_ALT_B, "mmio"),
+ __GPIO_ALT(GPIO_ALT_MMIO_CAM_SET_I2C, 8, 9, 0, NMK_GPIO_ALT_A, "mmio"),
+ __GPIO_ALT(GPIO_ALT_MMIO_CAM_SET_EXT_CLK, 227, 228, 0, NMK_GPIO_ALT_A, "mmio"),
+#ifdef CONFIG_TOUCHP_EXT_CLK
+ __GPIO_ALT(GPIO_ALT_TP_SET_EXT_CLK, 228, 228, 0, NMK_GPIO_ALT_A, "u8500_tp1"),
+#endif
+};
+
+/*
+ * Touchscreen
+ */
+
+static struct synaptics_rmi4_platform_data rmi4_i2c_dev_platformdata[] = {
+ [0] = {
+ .irq_number = GPIO_TO_IRQ(179),
+ .irq_type = IRQF_TRIGGER_FALLING,
+ .x_max_res = 480,
+ .y_max_res = 864,
+ .portrait_mode = true,
+#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY_ROTATE_180_DEGREES
+ .x_flip = true,
+ .y_flip = false,
+#else
+ .x_flip = false,
+ .y_flip = true,
+#endif
+ },
+};
+
+static struct synaptics_rmi4_i2c_data rmi4_platform_data = {
+ .num_clients = ARRAY_SIZE(rmi4_i2c_dev_platformdata),
+ .platformdata = rmi4_i2c_dev_platformdata,
+};
+
+/*
+ * I2C
+ */
+
+#define U5500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \
+static struct nmk_i2c_controller u5500_i2c##id##_data = { \
+ /* \
+ * slave data setup time, which is \
+ * 250 ns,100ns,10ns which is 14,6,2 \
+ * respectively for a 48 Mhz \
+ * i2c clock \
+ */ \
+ .slsu = _slsu, \
+ /* Tx FIFO threshold */ \
+ .tft = _tft, \
+ /* Rx FIFO threshold */ \
+ .rft = _rft, \
+ /* std. mode operation */ \
+ .clk_freq = clk, \
+ .sm = _sm, \
+}
+
+/*
+ * The board uses 3 i2c controllers, initialize all of
+ * them with slave data setup time of 250 ns,
+ * Tx & Rx FIFO threshold values as 1 and standard
+ * mode of operation
+ */
+
+U5500_I2C_CONTROLLER(1, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
+U5500_I2C_CONTROLLER(2, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
+U5500_I2C_CONTROLLER(3, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
+
+static struct i2c_board_info __initdata u5500_i2c1_devices[] = {
+ {
+ I2C_BOARD_INFO("synaptics_rmi4_i2c", 0x4B),
+ .platform_data = &rmi4_platform_data,
+ },
+};
+
+/*
+ * Keypad
+ */
+
+static const unsigned int u5500_keymap[] = {
+ KEY(4, 0, KEY_CAMERA), /* Camera2 */
+ KEY(4, 1, KEY_CAMERA_FOCUS), /* Camera1 */
+ KEY(4, 2, KEY_MENU),
+ KEY(4, 3, KEY_BACK),
+ KEY(5, 2, KEY_SEND),
+ KEY(5, 3, KEY_HOME),
+ KEY(8, 0, KEY_END),
+ KEY(8, 1, KEY_VOLUMEUP),
+ KEY(8, 2, KEY_VOLUMEDOWN),
+};
+
+static struct matrix_keymap_data u5500_keymap_data = {
+ .keymap = u5500_keymap,
+ .keymap_size = ARRAY_SIZE(u5500_keymap),
+};
+
+static struct db5500_keypad_platform_data u5500_keypad_board = {
+ .keymap_data = &u5500_keymap_data,
+ .no_autorepeat = true,
+ .debounce_ms = 40, /* milliseconds */
+};
+
+
+/*
+ * MSP
+ */
+
+static struct msp_i2s_platform_data u5500_msp0_data = {
+ .id = MSP_0_CONTROLLER,
};
+static struct msp_i2s_platform_data u5500_msp1_data = {
+ .id = MSP_1_CONTROLLER,
+};
+
+static struct msp_i2s_platform_data u5500_msp2_data = {
+ .id = MSP_2_CONTROLLER,
+};
+
+static struct i2s_board_info stm_i2s_board_info[] __initdata = {
+ {
+ .modalias = "i2s_device.0",
+ .id = 0,
+ .chip_select = 0,
+ },
+ {
+ .modalias = "i2s_device.1",
+ .id = 1,
+ .chip_select = 1,
+ },
+ {
+ .modalias = "i2s_device.2",
+ .id = 2,
+ .chip_select = 2,
+ },
+};
+
+static void __init u5500_msp_init(void)
+{
+ db5500_add_msp0_i2s(&u5500_msp0_data);
+ db5500_add_msp1_i2s(&u5500_msp1_data);
+ db5500_add_msp2_i2s(&u5500_msp2_data);
+
+ i2s_register_board_info(ARRAY_AND_SIZE(stm_i2s_board_info));
+}
+
+static struct mmc_board u5500_sdi0_data = {
+ .init = NULL,
+ .exit = NULL,
+ .level_shifter = 0,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA | MMC_CAP_MMC_HIGHSPEED,
+ .bus_resume_flags = MMC_NEEDS_UNSAFE_RESUME,
+};
+
+static void __init u5500_mmc_init(void)
+{
+ db5500_add_sdi0(&u5500_sdi0_data);
+}
+
+/*
+ * SPI
+ */
+
+static struct pl022_ssp_controller u5500_spi1_data = {
+ .bus_id = 1,
+ .num_chipselect = 4, /* 3 possible CS lines + 1 for tests */
+};
+
+static void __init u5500_spi_init(void)
+{
+ db5500_add_spi1(&u5500_spi1_data);
+}
+
+static struct resource ab5500_resources[] = {
+ [0] = {
+ /*TODO Change this when prcmu driver arrives */
+ .start = IRQ_DB5500_AB5500,
+ .end = IRQ_DB5500_AB5500,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct ab5500_platform_data ab5500_plf_data = {
+ .irq = {
+ .base = IRQ_AB5500_BASE,
+ .count = AB5500_NR_IRQS,
+ },
+ .dev_data = {
+ },
+ .dev_data_sz = {
+ },
+ .init_settings = NULL,
+ .init_settings_sz = 0,
+};
+
+static struct platform_device u5500_ab5500_device = {
+ .name = "ab5500-core",
+ .id = 0,
+ .dev = {
+ .platform_data = &ab5500_plf_data,
+ },
+ .num_resources = 1,
+ .resource = ab5500_resources,
+};
+
+static struct platform_device *u5500_platform_devices[] __initdata = {
+ &u5500_ab5500_device,
+};
+
+static void __init u5500_i2c_init(void)
+{
+ db5500_add_i2c1(&u5500_i2c1_data);
+ db5500_add_i2c2(&u5500_i2c2_data);
+ db5500_add_i2c3(&u5500_i2c3_data);
+
+ i2c_register_board_info(1, ARRAY_AND_SIZE(u5500_i2c1_devices));
+}
+
+static void __init u5500_uart_init(void)
+{
+ db5500_add_uart0();
+ db5500_add_uart1();
+ db5500_add_uart2();
+}
+
static void __init u5500_init_machine(void)
{
+ stm_gpio_set_altfunctable(gpio_altfun_table,
+ ARRAY_SIZE(gpio_altfun_table));
+
u5500_init_devices();
- amba_add_devices(amba_board_devs, ARRAY_SIZE(amba_board_devs));
+ nmk_config_pins(u5500_pins, ARRAY_SIZE(u5500_pins));
+
+ u5500_i2c_init();
+ u5500_msp_init();
+ u5500_spi_init();
+ u5500_uart_init();
+ u5500_mmc_init();
+
+ db5500_add_keypad(&u5500_keypad_board);
+
+ platform_device_register_simple("mloader_helper", -1, NULL, 0);
+
+ platform_add_devices(u5500_platform_devices,
+ ARRAY_SIZE(u5500_platform_devices));
}
-MACHINE_START(U8500, "ST-Ericsson U5500 Platform")
+MACHINE_START(U5500, "ST-Ericsson U5500 Platform")
.phys_io = UX500_UART0_BASE,
.io_pg_offst = (IO_ADDRESS(UX500_UART0_BASE) >> 18) & 0xfffc,
.boot_params = 0x00000100,
.map_io = u5500_map_io,
.init_irq = ux500_init_irq,
- .timer = &ux500_timer,
+ .timer = &u8500_timer,
.init_machine = u5500_init_machine,
MACHINE_END
diff --git a/arch/arm/mach-ux500/cg2900_devices.c b/arch/arm/mach-ux500/cg2900_devices.c
new file mode 100644
index 00000000000..8e7ee82ad3c
--- /dev/null
+++ b/arch/arm/mach-ux500/cg2900_devices.c
@@ -0,0 +1,337 @@
+/*
+ * arch/arm/mach-ux500/cg2900_devices.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Board specific device support for the Linux Bluetooth HCI H:4 Driver
+ * for ST-Ericsson connectivity controller.
+ */
+
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <asm-generic/errno-base.h>
+#include <asm/byteorder.h>
+#include <mach/cg2900_devices.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <plat/pincfg.h>
+#include "pins-db8500.h"
+
+/** BT_ENABLE_GPIO - GPIO to enable/disable the BT module.
+ */
+#define BT_ENABLE_GPIO (GPIO(170))
+
+/** GBF_ENA_RESET_GPIO - GPIO to enable/disable the controller.
+ */
+#define GBF_ENA_RESET_GPIO (GPIO(171))
+
+/** BT_CTS_GPIO - CTS GPIO.
+*/
+#define BT_CTS_GPIO (GPIO(0))
+
+/** GBF_ENA_RESET_NAME - Name of GPIO for enabling/disabling.
+ */
+#define GBF_ENA_RESET_NAME "gbf_ena_reset"
+
+/** GBF_ENA_RESET_NAME - Name of GPIO for enabling/disabling.
+ */
+#define BT_ENABLE_NAME "bt_enable"
+/** CG2900_DEVICE_NAME - Name for this module.
+*/
+#define CG2900_DEVICE_NAME "cg2900_driver"
+
+/** UART_LINES_NUM - Number of uart lines we want to configure.
+*/
+#define UART_LINES_NUM 4
+
+/* Bluetooth Opcode Group Field */
+#define BT_OGF_VS 0x3F
+
+/* Bluetooth Opcode Command Field */
+#define BT_OCF_VS_POWER_SWITCH_OFF 0x0140
+#define BT_OCF_VS_BT_ENABLE 0x0310
+
+#define MAKE_CMD(__ogf, __ocf) ((u16)(((u16)__ogf << 10) | __ocf))
+
+#define BT_VS_POWER_SWITCH_OFF MAKE_CMD(BT_OGF_VS, \
+ BT_OCF_VS_POWER_SWITCH_OFF)
+#define BT_VS_BT_ENABLE MAKE_CMD(BT_OGF_VS, BT_OCF_VS_BT_ENABLE)
+
+#define VS_BT_DISABLE 0x00
+#define VS_BT_ENABLE 0x01
+
+#define H4_HEADER_LENGTH 0x01
+#define BT_HEADER_LENGTH 0x03
+
+#define STLC2690_HCI_REV 0x0600
+#define CG2900_HCI_REV 0x0101
+#define CG2900_SPECIAL_HCI_REV 0x0700
+
+struct vs_power_sw_off_cmd {
+ __le16 op_code;
+ u8 len;
+ u8 gpio_0_7_pull_up;
+ u8 gpio_8_15_pull_up;
+ u8 gpio_16_20_pull_up;
+ u8 gpio_0_7_pull_down;
+ u8 gpio_8_15_pull_down;
+ u8 gpio_16_20_pull_down;
+} __attribute__((packed));
+
+struct vs_bt_enable_cmd {
+ __le16 op_code;
+ u8 len;
+ u8 enable;
+} __attribute__((packed));
+
+static u8 cg2900_hci_version;
+static u8 cg2900_lmp_version;
+static u8 cg2900_lmp_subversion;
+static u16 cg2900_hci_revision;
+static u16 cg2900_manufacturer;
+
+/* IRQ callback. */
+static struct cg2900_devices_cb *cg2900_dev_callback;
+
+/* Pin configuration for UART functions. */
+static pin_cfg_t uart0_enabled[] = {
+ GPIO0_U0_CTSn | PIN_INPUT_PULLUP,
+ GPIO1_U0_RTSn | PIN_OUTPUT_HIGH,
+ GPIO2_U0_RXD | PIN_INPUT_PULLUP,
+ GPIO3_U0_TXD | PIN_OUTPUT_HIGH,
+};
+
+/* Pin configuration for sleep mode. */
+static pin_cfg_t uart0_disabled[] = {
+ GPIO0_GPIO | PIN_INPUT_PULLUP, /* CTS pull up. */
+ GPIO1_GPIO | PIN_OUTPUT_HIGH, /* RTS high - flow off. */
+ GPIO2_GPIO | PIN_INPUT_PULLUP, /* RX pull down. */
+ GPIO3_GPIO | PIN_OUTPUT_LOW, /* TX low - break on. */
+};
+
+void cg2900_devices_enable_chip(void)
+{
+ gpio_set_value(GBF_ENA_RESET_GPIO, GPIO_HIGH);
+}
+EXPORT_SYMBOL(cg2900_devices_enable_chip);
+
+void cg2900_devices_disable_chip(void)
+{
+ gpio_set_value(GBF_ENA_RESET_GPIO, GPIO_LOW);
+ cg2900_dev_callback = NULL;
+}
+EXPORT_SYMBOL(cg2900_devices_disable_chip);
+
+void cg2900_devices_set_hci_revision(u8 hci_version,
+ u16 hci_revision,
+ u8 lmp_version,
+ u8 lmp_subversion,
+ u16 manufacturer)
+{
+ cg2900_hci_version = hci_version;
+ cg2900_hci_revision = hci_revision;
+ cg2900_lmp_version = lmp_version;
+ cg2900_lmp_subversion = lmp_subversion;
+ cg2900_manufacturer = manufacturer;
+}
+EXPORT_SYMBOL(cg2900_devices_set_hci_revision);
+
+struct sk_buff *cg2900_devices_get_power_switch_off_cmd(u16 *op_code)
+{
+ struct sk_buff *skb;
+ struct vs_power_sw_off_cmd *cmd;
+
+ /* If connected chip does not support the command return NULL */
+ if (CG2900_HCI_REV != cg2900_hci_revision &&
+ CG2900_SPECIAL_HCI_REV != cg2900_hci_revision)
+ return NULL;
+
+ skb = alloc_skb(sizeof(*cmd) + H4_HEADER_LENGTH, GFP_KERNEL);
+ if (!skb) {
+ pr_err("Could not allocate skb");
+ return NULL;
+ }
+
+ skb_reserve(skb, H4_HEADER_LENGTH);
+ cmd = (struct vs_power_sw_off_cmd *)skb_put(skb, sizeof(*cmd));
+ cmd->op_code = cpu_to_le16(BT_VS_POWER_SWITCH_OFF);
+ cmd->len = sizeof(*cmd) - BT_HEADER_LENGTH;
+ /*
+ * Enter system specific GPIO settings here:
+ * Section data[3-5] is GPIO pull-up selection
+ * Section data[6-8] is GPIO pull-down selection
+ * Each section is a bitfield where
+ * - byte 0 bit 0 is GPIO 0
+ * - byte 0 bit 1 is GPIO 1
+ * - up to
+ * - byte 2 bit 4 which is GPIO 20
+ * where each bit means:
+ * - 0: No pull-up / no pull-down
+ * - 1: Pull-up / pull-down
+ * All GPIOs are set as input.
+ */
+ cmd->gpio_0_7_pull_up = 0x00;
+ cmd->gpio_8_15_pull_up = 0x00;
+ cmd->gpio_16_20_pull_up = 0x00;
+ cmd->gpio_0_7_pull_down = 0x00;
+ cmd->gpio_8_15_pull_down = 0x00;
+ cmd->gpio_16_20_pull_down = 0x00;
+
+ if (op_code)
+ *op_code = BT_VS_POWER_SWITCH_OFF;
+
+ return skb;
+}
+EXPORT_SYMBOL(cg2900_devices_get_power_switch_off_cmd);
+
+struct sk_buff *cg2900_devices_get_bt_enable_cmd(u16 *op_code, bool bt_enable)
+{
+ struct sk_buff *skb;
+ struct vs_bt_enable_cmd *cmd;
+
+ /* If connected chip does not support the command return NULL */
+ if (CG2900_HCI_REV != cg2900_hci_revision &&
+ CG2900_SPECIAL_HCI_REV != cg2900_hci_revision)
+ return NULL;
+
+ /* CG2900 used */
+ skb = alloc_skb(sizeof(*cmd) + H4_HEADER_LENGTH, GFP_KERNEL);
+ if (!skb) {
+ pr_err("Could not allocate skb");
+ return NULL;
+ }
+
+ skb_reserve(skb, H4_HEADER_LENGTH);
+ cmd = (struct vs_bt_enable_cmd *)skb_put(skb, sizeof(*cmd));
+ cmd->op_code = cpu_to_le16(BT_VS_BT_ENABLE);
+ cmd->len = sizeof(*cmd) - BT_HEADER_LENGTH;
+ if (bt_enable)
+ cmd->enable = VS_BT_ENABLE;
+ else
+ cmd->enable = VS_BT_DISABLE;
+
+ if (op_code)
+ *op_code = BT_VS_BT_ENABLE;
+
+ return skb;
+}
+EXPORT_SYMBOL(cg2900_devices_get_bt_enable_cmd);
+
+static irqreturn_t cg2900_devices_interrupt(int irq, void *dev_id)
+{
+ disable_irq_nosync(irq);
+ if (cg2900_dev_callback && cg2900_dev_callback->interrupt_cb)
+ cg2900_dev_callback->interrupt_cb();
+
+ return IRQ_HANDLED;
+}
+
+int cg2900_devices_set_cts_irq(void)
+{
+ int err;
+
+ /*
+ * Without this delay we get interrupt on CTS immediately
+ * due to some turbulences on this line.
+ */
+ mdelay(4);
+
+ /* Disable UART functions. */
+ err = nmk_config_pins(uart0_disabled, UART_LINES_NUM);
+
+ if (err)
+ goto error;
+
+ /* Set IRQ on CTS. */
+ err = request_irq(GPIO_TO_IRQ(BT_CTS_GPIO),
+ cg2900_devices_interrupt,
+ IRQF_TRIGGER_FALLING,
+ CG2900_DEVICE_NAME,
+ NULL);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ (void)nmk_config_pins(uart0_enabled, UART_LINES_NUM);
+ pr_err("Can not set intterupt.");
+ return err;
+}
+EXPORT_SYMBOL(cg2900_devices_set_cts_irq);
+
+void cg2900_devices_unset_cts_irq(void)
+{
+ int err;
+
+ /* Restore UART settings. */
+ free_irq(GPIO_TO_IRQ(BT_CTS_GPIO), NULL);
+ err = nmk_config_pins(uart0_enabled, UART_LINES_NUM);
+ if (err)
+ pr_err("Unable to enable UART");
+}
+EXPORT_SYMBOL(cg2900_devices_unset_cts_irq);
+
+void cg2900_devices_reg_cb(struct cg2900_devices_cb *cb)
+{
+ if (!cg2900_dev_callback)
+ cg2900_dev_callback = cb;
+ else
+ pr_err("Callback already registered");
+}
+EXPORT_SYMBOL(cg2900_devices_reg_cb);
+int cg2900_devices_init(void)
+{
+ int err = 0;
+
+ err = gpio_request(GBF_ENA_RESET_GPIO, GBF_ENA_RESET_NAME);
+ if (err < 0) {
+ pr_err("gpio_request failed with err: %d", err);
+ goto finished;
+ }
+
+ err = gpio_direction_output(GBF_ENA_RESET_GPIO, GPIO_HIGH);
+ if (err < 0) {
+ pr_err("gpio_direction_output failed with err: %d", err);
+ goto error_handling;
+ }
+
+ err = gpio_request(BT_ENABLE_GPIO, BT_ENABLE_NAME);
+ if (err < 0) {
+ pr_err("gpio_request failed with err: %d", err);
+ goto finished;
+ }
+
+ err = gpio_direction_output(BT_ENABLE_GPIO, GPIO_HIGH);
+ if (err < 0) {
+ pr_err("gpio_direction_output failed with err: %d", err);
+ goto error_handling;
+ }
+
+ goto finished;
+
+error_handling:
+ gpio_free(GBF_ENA_RESET_GPIO);
+
+finished:
+ cg2900_devices_disable_chip();
+ return err;
+}
+EXPORT_SYMBOL(cg2900_devices_init);
+
+void cg2900_devices_exit(void)
+{
+ cg2900_devices_disable_chip();
+ gpio_free(GBF_ENA_RESET_GPIO);
+}
+EXPORT_SYMBOL(cg2900_devices_exit);
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
index 0a1318fc8e2..c590aa2237d 100644
--- a/arch/arm/mach-ux500/clock.c
+++ b/arch/arm/mach-ux500/clock.c
@@ -13,17 +13,22 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/mfd/ab8500/sysctrl.h>
#include <asm/clkdev.h>
-#include <plat/mtu.h>
#include <mach/hardware.h>
+#include <mach/prcmu-fw-api.h>
#include "clock.h"
-#define PRCC_PCKEN 0x00
-#define PRCC_PCKDIS 0x04
-#define PRCC_KCKEN 0x08
-#define PRCC_KCKDIS 0x0C
+#define PRCC_PCKEN 0x0
+#define PRCC_PCKDIS 0x4
+#define PRCC_KCKEN 0x8
+#define PRCC_KCKDIS 0xC
+#define PRCC_PCKSR 0x10
+#define PRCC_KCKSR 0x14
#define PRCM_YYCLKEN0_MGT_SET 0x510
#define PRCM_YYCLKEN1_MGT_SET 0x514
@@ -70,60 +75,159 @@
#define PRCM_MGT_ENABLE (1 << 8)
-static DEFINE_SPINLOCK(clocks_lock);
+static DEFINE_SPINLOCK(clk_spin_lock);
+static DEFINE_MUTEX(sysclk_mutex);
-static void __clk_enable(struct clk *clk)
+static void __iomem *prcmu_base;
+
+static int __clk_lock(struct clk *clk, unsigned long *flags)
{
- if (clk->enabled++ == 0) {
- if (clk->parent_cluster)
- __clk_enable(clk->parent_cluster);
+ if (clk->mutex) {
+ if (in_interrupt())
+ return -EINVAL;
+ mutex_lock(clk->mutex);
+ } else {
+ spin_lock_irqsave(&clk_spin_lock, *flags);
+ }
+ return 0;
+}
- if (clk->parent_periph)
- __clk_enable(clk->parent_periph);
+static void __clk_unlock(struct clk *clk, unsigned long flags)
+{
+ if (clk->mutex)
+ mutex_unlock(clk->mutex);
+ else
+ spin_unlock_irqrestore(&clk_spin_lock, flags);
+}
- if (clk->ops && clk->ops->enable)
- clk->ops->enable(clk);
+static void __clk_disable(struct clk *clk)
+{
+ if (clk == NULL)
+ return;
+ if (clk->enabled && (--clk->enabled == 0)) {
+ if ((clk->ops != NULL) && (clk->ops->disable != NULL))
+ clk->ops->disable(clk);
+ __clk_disable(clk->parent);
+ __clk_disable(clk->bus_parent);
}
+ return;
}
-int clk_enable(struct clk *clk)
+static int __clk_enable(struct clk *clk)
{
- unsigned long flags;
+ int err;
+
+ if (clk == NULL)
+ return 0;
+ if (!clk->enabled) {
+ err = __clk_enable(clk->bus_parent);
+ if (unlikely(err))
+ goto bus_parent_error;
+
+ err = __clk_enable(clk->parent);
+ if (unlikely(err))
+ goto parent_error;
+
+ if ((clk->ops != NULL) && (clk->ops->enable != NULL)) {
+ err = clk->ops->enable(clk);
+ if (unlikely(err))
+ goto enable_error;
+ }
+ }
+ clk->enabled++;
+ return 0;
- spin_lock_irqsave(&clocks_lock, flags);
- __clk_enable(clk);
- spin_unlock_irqrestore(&clocks_lock, flags);
+enable_error:
+ __clk_disable(clk->parent);
+parent_error:
+ __clk_disable(clk->bus_parent);
+bus_parent_error:
+ return err;
+}
- return 0;
+static unsigned long __clk_get_rate(struct clk *clk)
+{
+ if (clk == NULL)
+ return 0;
+
+ if ((clk->ops != NULL) && (clk->ops->get_rate != NULL))
+ return clk->ops->get_rate(clk);
+ else if (clk->rate)
+ return clk->rate;
+ else
+ return __clk_get_rate(clk->parent);
}
-EXPORT_SYMBOL(clk_enable);
-static void __clk_disable(struct clk *clk)
+int clk_enable(struct clk *clk)
{
- if (--clk->enabled == 0) {
- if (clk->ops && clk->ops->disable)
- clk->ops->disable(clk);
+ int err;
+ unsigned long flags;
- if (clk->parent_periph)
- __clk_disable(clk->parent_periph);
+ if (clk == NULL)
+ return -EINVAL;
- if (clk->parent_cluster)
- __clk_disable(clk->parent_cluster);
- }
+ err = __clk_lock(clk, &flags);
+
+ if (err)
+ goto no_lock;
+
+ err = __clk_enable(clk);
+
+ __clk_unlock(clk, flags);
+
+no_lock:
+ return err;
}
+EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *clk)
{
unsigned long flags;
+ if (clk == NULL)
+ return;
+
WARN_ON(!clk->enabled);
- spin_lock_irqsave(&clocks_lock, flags);
+ if (__clk_lock(clk, &flags))
+ goto no_lock;
+
__clk_disable(clk);
- spin_unlock_irqrestore(&clocks_lock, flags);
+
+ __clk_unlock(clk, flags);
+
+ return;
+
+no_lock:
+ pr_err("clock: %s cannot be disabled in interrupt context.\n",
+ clk->name);
}
EXPORT_SYMBOL(clk_disable);
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (clk == NULL)
+ return -EINVAL;
+ return __clk_get_rate(clk);
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ /* TODO: Decide whether this should be implemented or not. */
+ return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ /* TODO: Decide whether this should be implemented or not. */
+ return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+/* MTU operations. */
+
/*
* The MTU has a separate, rather complex muxing setup
* with alternative parents (peripheral cluster or
@@ -131,27 +235,30 @@ EXPORT_SYMBOL(clk_disable);
*/
static unsigned long clk_mtu_get_rate(struct clk *clk)
{
- void __iomem *addr = __io_address(UX500_PRCMU_BASE)
- + PRCM_TCR;
- u32 tcr = readl(addr);
- int mtu = (int) clk->data;
+ u32 tcr;
+ int mtu;
/*
* One of these is selected eventually
* TODO: Replace the constant with a reference
* to the ULP source once this is modeled.
*/
- unsigned long clk32k = 32768;
+ unsigned long clk32k;
unsigned long mturate;
unsigned long retclk;
+ tcr = readl(prcmu_base + PRCM_TCR);
+ mtu = (int)clk->cg_sel;
+ clk32k = 32768;
+
/* Get the rate from the parent as a default */
- if (clk->parent_periph)
- mturate = clk_get_rate(clk->parent_periph);
- else if (clk->parent_cluster)
- mturate = clk_get_rate(clk->parent_cluster);
- else
+ if (clk->parent) {
+ mturate = __clk_get_rate(clk->parent);
+ } else if (clk->bus_parent) {
+ mturate = __clk_get_rate(clk->bus_parent);
+ } else {
/* We need to be connected SOMEWHERE */
BUG();
+ }
/*
* Are we in doze mode?
@@ -198,420 +305,963 @@ static unsigned long clk_mtu_get_rate(struct clk *clk)
else
retclk = mturate;
- pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk);
+ pr_debug("clock: MTU%d clock rate is %lu Hz\n", mtu, retclk);
return retclk;
}
-unsigned long clk_get_rate(struct clk *clk)
-{
- unsigned long rate;
-
- /*
- * If there is a custom getrate callback for this clock,
- * it will take precedence.
- */
- if (clk->get_rate)
- return clk->get_rate(clk);
+static struct clkops mtu_clk_ops = {
+ .get_rate = clk_mtu_get_rate,
+};
- if (clk->ops && clk->ops->get_rate)
- return clk->ops->get_rate(clk);
+/* PRCMU clock operations. */
- rate = clk->rate;
- if (!rate) {
- if (clk->parent_periph)
- rate = clk_get_rate(clk->parent_periph);
- else if (clk->parent_cluster)
- rate = clk_get_rate(clk->parent_cluster);
+static int prcmu_clk_enable(struct clk *clk)
+{
+ unsigned int reg;
+
+ switch (clk->cg_sel / 32) {
+ case 0:
+ reg = PRCM_YYCLKEN0_MGT_SET;
+ break;
+ case 1:
+ reg = PRCM_YYCLKEN1_MGT_SET;
+ break;
+ default:
+ return -EINVAL;
}
+ writel(BIT(clk->cg_sel % 32), (prcmu_base + reg));
+ return 0;
+}
- return rate;
+static void prcmu_clk_disable(struct clk *clk)
+{
+ unsigned int reg;
+
+ switch (clk->cg_sel / 32) {
+ case 0:
+ reg = PRCM_YYCLKEN0_MGT_CLR;
+ break;
+ case 1:
+ reg = PRCM_YYCLKEN1_MGT_CLR;
+ break;
+ default:
+ return;
+ }
+ writel(BIT(clk->cg_sel % 32), (prcmu_base + reg));
}
-EXPORT_SYMBOL(clk_get_rate);
-long clk_round_rate(struct clk *clk, unsigned long rate)
+static unsigned long prcmu_clk_get_rate(struct clk *clk)
{
- /*TODO*/
- return rate;
+ switch (prcmu_get_ape_opp()) {
+ case APE_100_OPP:
+ return clk->rate;
+ case APE_50_OPP:
+ return clk->rate_50;
+ default:
+ return 0;
+ }
}
-EXPORT_SYMBOL(clk_round_rate);
-int clk_set_rate(struct clk *clk, unsigned long rate)
+/* These operations are for PRCMU clocks having a fixed rate. */
+static struct clkops prcmu_fixed_clk_ops = {
+ .enable = prcmu_clk_enable,
+ .disable = prcmu_clk_disable,
+};
+
+/* These operations are for clocks that are affected by the OPP, but whose rate
+ * is not settable.
+ */
+static struct clkops prcmu_scaling_clk_ops = {
+ .enable = prcmu_clk_enable,
+ .disable = prcmu_clk_disable,
+ .get_rate = prcmu_clk_get_rate,
+};
+
+/* PLL operations. */
+
+static int clk_pllsrc_enable(struct clk *clk)
{
- clk->rate = rate;
+ /* To enable pll */
return 0;
}
-EXPORT_SYMBOL(clk_set_rate);
-static void clk_prcmu_enable(struct clk *clk)
+static void clk_pllsrc_disable(struct clk *clk)
+{
+ /* To disable pll */
+}
+
+static struct clkops pll_clk_ops = {
+ .enable = clk_pllsrc_enable,
+ .disable = clk_pllsrc_disable,
+};
+
+/* PRCC clock operations. */
+
+static int prcc_pclk_enable(struct clk *clk)
{
- void __iomem *cg_set_reg = __io_address(U8500_PRCMU_BASE)
- + PRCM_YYCLKEN0_MGT_SET + clk->prcmu_cg_off;
+ void __iomem *io_base = __io_address(clk->io_base);
- writel(1 << clk->prcmu_cg_bit, cg_set_reg);
+ writel(clk->cg_sel, (io_base + PRCC_PCKEN));
+ while (!(readl(io_base + PRCC_PCKSR) & clk->cg_sel))
+ cpu_relax();
+ return 0;
}
-static void clk_prcmu_disable(struct clk *clk)
+static void prcc_pclk_disable(struct clk *clk)
{
- void __iomem *cg_clr_reg = __io_address(U8500_PRCMU_BASE)
- + PRCM_YYCLKEN0_MGT_CLR + clk->prcmu_cg_off;
+ void __iomem *io_base = __io_address(clk->io_base);
- writel(1 << clk->prcmu_cg_bit, cg_clr_reg);
+ writel(clk->cg_sel, (io_base + PRCC_PCKDIS));
}
-/* ED doesn't have the combined set/clr registers */
-static void clk_prcmu_ed_enable(struct clk *clk)
+static struct clkops prcc_pclk_ops = {
+ .enable = prcc_pclk_enable,
+ .disable = prcc_pclk_disable,
+};
+
+static int prcc_kclk_enable(struct clk *clk)
{
- void __iomem *addr = __io_address(U8500_PRCMU_BASE)
- + clk->prcmu_cg_mgt;
+ void __iomem *io_base = __io_address(clk->io_base);
- writel(readl(addr) | PRCM_MGT_ENABLE, addr);
+ writel(clk->cg_sel, (io_base + PRCC_KCKEN));
+ while (!(readl(io_base + PRCC_KCKSR) & clk->cg_sel))
+ cpu_relax();
+ return 0;
}
-static void clk_prcmu_ed_disable(struct clk *clk)
+static void prcc_kclk_disable(struct clk *clk)
{
- void __iomem *addr = __io_address(U8500_PRCMU_BASE)
- + clk->prcmu_cg_mgt;
+ void __iomem *io_base = __io_address(clk->io_base);
- writel(readl(addr) & ~PRCM_MGT_ENABLE, addr);
+ writel(clk->cg_sel, (io_base + PRCC_KCKDIS));
}
-static struct clkops clk_prcmu_ops = {
- .enable = clk_prcmu_enable,
- .disable = clk_prcmu_disable,
+static struct clkops prcc_kclk_ops = {
+ .enable = prcc_kclk_enable,
+ .disable = prcc_kclk_disable,
};
-static unsigned int clkrst_base[] = {
- [1] = U8500_CLKRST1_BASE,
- [2] = U8500_CLKRST2_BASE,
- [3] = U8500_CLKRST3_BASE,
- [5] = U8500_CLKRST5_BASE,
- [6] = U8500_CLKRST6_BASE,
- [7] = U8500_CLKRST7_BASE_ED,
-};
+/* SysClk operations. */
+
+static int request_sysclk(bool enable)
+{
+ static int requests;
+
+ if ((enable && (requests++ == 0)) || (!enable && (--requests == 0)))
+ return prcmu_request_clock(PRCMU_SYSCLK, enable);
+ return 0;
+}
-static void clk_prcc_enable(struct clk *clk)
+static int sysclk_enable(struct clk *clk)
{
- void __iomem *addr = __io_address(clkrst_base[clk->cluster]);
+ int r;
- if (clk->prcc_kernel != -1)
- writel(1 << clk->prcc_kernel, addr + PRCC_KCKEN);
+ r = request_sysclk(true);
+ if (r)
+ return r;
- if (clk->prcc_bus != -1)
- writel(1 << clk->prcc_bus, addr + PRCC_PCKEN);
+ if (clk->cg_sel) {
+ r = ab8500_sysctrl_set(AB8500_SYSULPCLKCTRL1, (u8)clk->cg_sel);
+ if (r)
+ (void)request_sysclk(false);
+ }
+ return r;
}
-static void clk_prcc_disable(struct clk *clk)
+static void sysclk_disable(struct clk *clk)
{
- void __iomem *addr = __io_address(clkrst_base[clk->cluster]);
+ int r;
- if (clk->prcc_bus != -1)
- writel(1 << clk->prcc_bus, addr + PRCC_PCKDIS);
+ if (clk->cg_sel) {
+ r = ab8500_sysctrl_clear(AB8500_SYSULPCLKCTRL1,
+ (u8)clk->cg_sel);
+ if (r)
+ goto disable_failed;
+ }
+ r = request_sysclk(false);
+ if (r)
+ goto disable_failed;
+ return;
- if (clk->prcc_kernel != -1)
- writel(1 << clk->prcc_kernel, addr + PRCC_KCKDIS);
+disable_failed:
+ pr_err("clock: failed to disable %s.\n", clk->name);
}
-static struct clkops clk_prcc_ops = {
- .enable = clk_prcc_enable,
- .disable = clk_prcc_disable,
+static struct clkops sysclk_ops = {
+ .enable = sysclk_enable,
+ .disable = sysclk_disable,
+};
+
+/* Clock sources. */
+
+static struct clk soc0_pll = {
+ .name = "soc0_pll",
+ .ops = &pll_clk_ops,
+};
+
+static struct clk soc1_pll = {
+ .name = "soc1_pll",
+ .ops = &pll_clk_ops,
+};
+
+static struct clk ddr_pll = {
+ .name = "ddr_pll",
+ .ops = &pll_clk_ops,
+};
+
+static struct clk ulp38m4 = {
+ .name = "ulp38m4",
+};
+
+static struct clk sysclk = {
+ .name = "sysclk",
+ .ops = &sysclk_ops,
+ .rate = 38400000,
+ .mutex = &sysclk_mutex,
};
-static struct clk clk_32khz = {
- .rate = 32000,
+static struct clk sysclk2 = {
+ .name = "sysclk2",
+ .ops = &sysclk_ops,
+ .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ,
+ .mutex = &sysclk_mutex,
};
+static struct clk rtc32k = {
+ .name = "rtc32k",
+ .rate = 32768,
+};
+
+/* PRCMU clocks */
+
+#define DEF_FIXED_CLK(_name, _cg_sel, _rate) \
+ struct clk _name = { \
+ .name = #_name, \
+ .ops = &prcmu_fixed_clk_ops, \
+ .cg_sel = _cg_sel, \
+ .rate = _rate, \
+ }
+
+#define DEF_SCALING_CLK(_name, _cg_sel, _rate, _rate_50) \
+ struct clk _name = { \
+ .name = #_name, \
+ .ops = &prcmu_scaling_clk_ops, \
+ .cg_sel = _cg_sel, \
+ .rate = _rate, \
+ .rate_50 = _rate_50, \
+ }
+
+static DEF_SCALING_CLK(svammdspclk, 2, 400000000, 200000000);
+static DEF_SCALING_CLK(siammdspclk, 3, 400000000, 200000000);
+static DEF_SCALING_CLK(sgaclk, 4, 200000000, 100000000);
+static DEF_FIXED_CLK(uartclk, 5, 38400000);
+static DEF_FIXED_CLK(msp02clk, 6, 19200000);
+static DEF_FIXED_CLK(msp1clk, 7, 19200000);
+static DEF_FIXED_CLK(i2cclk, 8, 24000000);
+static DEF_SCALING_CLK(sdmmcclk, 9, 100000000, 50000000);
+static DEF_FIXED_CLK(slimclk, 10, 19200000);
+static DEF_SCALING_CLK(per1clk, 11, 133330000, 66600000);
+static DEF_SCALING_CLK(per2clk, 12, 133330000, 66600000);
+static DEF_SCALING_CLK(per3clk, 13, 133330000, 66600000);
+static DEF_SCALING_CLK(per5clk, 14, 133330000, 66600000);
+static DEF_SCALING_CLK(per6clk, 15, 133330000, 66600000);
+static DEF_SCALING_CLK(per7clk, 16, 100000000, 50000000);
+static DEF_FIXED_CLK(lcdclk, 17, 48000000);
+static DEF_SCALING_CLK(bmlclk, 18, 200000000, 0);
+static DEF_SCALING_CLK(hsitxclk, 19, 100000000, 50000000);
+static DEF_SCALING_CLK(hsirxclk, 20, 200000000, 100000000);
+static DEF_FIXED_CLK(hdmiclk, 21, 76800000);
+static DEF_SCALING_CLK(apeatclk, 22, 160000000, 80000000);
+static DEF_SCALING_CLK(apetraceclk, 23, 160000000, 80000000);
+static DEF_SCALING_CLK(mcdeclk, 24, 160000000, 80000000);
+static DEF_SCALING_CLK(ipi2cclk, 25, 24000000, 0);
+static DEF_FIXED_CLK(dsialtclk, 26, 384000000);
+static DEF_SCALING_CLK(dmaclk, 27, 200000000, 100000000);
+static DEF_SCALING_CLK(b2r2clk, 28, 200000000, 100000000);
+static DEF_FIXED_CLK(tvclk, 29, 76800000);
+/* TODO: Is UNIPROCLK fixed or scaling? Rate(s)? */
+static DEF_FIXED_CLK(uniproclk, 30, 0);
+/* TODO: For SSPCLK, the spec says 24MHz, while the old driver says 48MHz. */
+static DEF_FIXED_CLK(sspclk, 31, 24000000);
+static DEF_FIXED_CLK(rngclk, 32, 19200000);
+static DEF_FIXED_CLK(uiccclk, 33, 48000000);
+
+/* PRCC clocks */
+
+#define DEF_PRCC_PCLK(_name, _io_base, _cg_bit, _parent) \
+ struct clk _name = { \
+ .name = #_name, \
+ .ops = &prcc_pclk_ops, \
+ .io_base = _io_base, \
+ .cg_sel = BIT(_cg_bit), \
+ .parent = _parent, \
+ }
+
+#define DEF_PER1_PCLK(_cg_bit, _name) \
+ DEF_PRCC_PCLK(_name, U8500_CLKRST1_BASE, _cg_bit, &per1clk)
+
+static DEF_PER1_PCLK(0, p1_pclk0);
+static DEF_PER1_PCLK(1, p1_pclk1);
+static DEF_PER1_PCLK(2, p1_pclk2);
+static DEF_PER1_PCLK(3, p1_pclk3);
+static DEF_PER1_PCLK(4, p1_pclk4);
+static DEF_PER1_PCLK(5, p1_pclk5);
+static DEF_PER1_PCLK(6, p1_pclk6);
+static DEF_PER1_PCLK(7, p1_pclk7);
+static DEF_PER1_PCLK(8, p1_pclk8);
+static DEF_PER1_PCLK(9, p1_pclk9);
+static DEF_PER1_PCLK(10, p1_pclk10);
+static DEF_PER1_PCLK(11, p1_pclk11);
+
+#define DEF_PER2_PCLK(_cg_bit, _name) \
+ DEF_PRCC_PCLK(_name, U8500_CLKRST2_BASE, _cg_bit, &per2clk)
+
+static DEF_PER2_PCLK(0, p2_pclk0);
+static DEF_PER2_PCLK(1, p2_pclk1);
+static DEF_PER2_PCLK(2, p2_pclk2);
+static DEF_PER2_PCLK(3, p2_pclk3);
+static DEF_PER2_PCLK(4, p2_pclk4);
+static DEF_PER2_PCLK(5, p2_pclk5);
+static DEF_PER2_PCLK(6, p2_pclk6);
+static DEF_PER2_PCLK(7, p2_pclk7);
+static DEF_PER2_PCLK(8, p2_pclk8);
+static DEF_PER2_PCLK(9, p2_pclk9);
+static DEF_PER2_PCLK(10, p2_pclk10);
+static DEF_PER2_PCLK(11, p2_pclk11);
+static DEF_PER2_PCLK(12, p2_pclk12);
+
+#define DEF_PER3_PCLK(_cg_bit, _name) \
+ DEF_PRCC_PCLK(_name, U8500_CLKRST3_BASE, _cg_bit, &per3clk)
+
+static DEF_PER3_PCLK(0, p3_pclk0);
+static DEF_PER3_PCLK(1, p3_pclk1);
+static DEF_PER3_PCLK(2, p3_pclk2);
+static DEF_PER3_PCLK(3, p3_pclk3);
+static DEF_PER3_PCLK(4, p3_pclk4);
+static DEF_PER3_PCLK(5, p3_pclk5);
+static DEF_PER3_PCLK(6, p3_pclk6);
+static DEF_PER3_PCLK(7, p3_pclk7);
+static DEF_PER3_PCLK(8, p3_pclk8);
+
+#define DEF_PER5_PCLK(_cg_bit, _name) \
+ DEF_PRCC_PCLK(_name, U8500_CLKRST5_BASE, _cg_bit, &per5clk)
+
+static DEF_PER5_PCLK(0, p5_pclk0);
+static DEF_PER5_PCLK(1, p5_pclk1);
+
+#define DEF_PER6_PCLK(_cg_bit, _name) \
+ DEF_PRCC_PCLK(_name, U8500_CLKRST6_BASE, _cg_bit, &per6clk)
+
+static DEF_PER6_PCLK(0, p6_pclk0);
+static DEF_PER6_PCLK(1, p6_pclk1);
+static DEF_PER6_PCLK(2, p6_pclk2);
+static DEF_PER6_PCLK(3, p6_pclk3);
+static DEF_PER6_PCLK(4, p6_pclk4);
+static DEF_PER6_PCLK(5, p6_pclk5);
+static DEF_PER6_PCLK(6, p6_pclk6);
+static DEF_PER6_PCLK(7, p6_pclk7);
+static DEF_PER6_PCLK(8, p6_pclk8);
+
+#define DEF_PER7_PCLK(_cg_bit, _name) \
+ DEF_PRCC_PCLK(_name, U8500_CLKRST7_BASE_ED, _cg_bit, &per7clk)
+
+static DEF_PER7_PCLK(0, p7_pclk0);
+static DEF_PER7_PCLK(1, p7_pclk1);
+static DEF_PER7_PCLK(2, p7_pclk2);
+static DEF_PER7_PCLK(3, p7_pclk3);
+static DEF_PER7_PCLK(4, p7_pclk4);
+
+#define DEF_PRCC_KCLK(_name, _io_base, _cg_bit, _parent) \
+ struct clk _name = { \
+ .name = #_name, \
+ .ops = &prcc_kclk_ops, \
+ .io_base = _io_base, \
+ .cg_sel = BIT(_cg_bit), \
+ .parent = _parent, \
+ }
+
+#define DEF_PER1_KCLK(_cg_bit, _name, _parent) \
+ DEF_PRCC_KCLK(_name, U8500_CLKRST1_BASE, _cg_bit, _parent)
+#define DEF_PER2_KCLK(_cg_bit, _name, _parent) \
+ DEF_PRCC_KCLK(_name, U8500_CLKRST2_BASE, _cg_bit, _parent)
+#define DEF_PER3_KCLK(_cg_bit, _name, _parent) \
+ DEF_PRCC_KCLK(_name, U8500_CLKRST3_BASE, _cg_bit, _parent)
+#define DEF_PER5_KCLK(_cg_bit, _name, _parent) \
+ DEF_PRCC_KCLK(_name, U8500_CLKRST5_BASE, _cg_bit, _parent)
+#define DEF_PER6_KCLK(_cg_bit, _name, _parent) \
+ DEF_PRCC_KCLK(_name, U8500_CLKRST6_BASE, _cg_bit, _parent)
+#define DEF_PER7_KCLK(_cg_bit, _name, _parent) \
+ DEF_PRCC_KCLK(_name, U8500_CLKRST7_BASE_ED, _cg_bit, _parent)
+
+#define DEF_PER_CLK(_name, _bus_parent, _parent) \
+ struct clk _name = { \
+ .name = #_name, \
+ .parent = _parent, \
+ .bus_parent = _bus_parent, \
+ }
+
+/* UART0 */
+static DEF_PER1_KCLK(0, p1_uart0_kclk, &uartclk);
+static DEF_PER_CLK(p1_uart0_clk, &p1_pclk0, &p1_uart0_kclk);
+
+/* UART1 */
+static DEF_PER1_KCLK(1, p1_uart1_kclk, &uartclk);
+static DEF_PER_CLK(p1_uart1_clk, &p1_pclk1, &p1_uart1_kclk);
+
+/* I2C1 */
+static DEF_PER1_KCLK(2, p1_i2c1_kclk, &i2cclk);
+static DEF_PER_CLK(p1_i2c1_clk, &p1_pclk2, &p1_i2c1_kclk);
+
+/* MSP0 */
+static DEF_PER1_KCLK(3, p1_msp0_kclk, &msp02clk);
+static DEF_PER_CLK(p1_msp0_clk, &p1_pclk3, &p1_msp0_kclk);
+
+/* MSP1 */
+static DEF_PER1_KCLK(4, p1_msp1_kclk, &msp1clk);
+static DEF_PER_CLK(p1_msp1_clk, &p1_pclk4, &p1_msp1_kclk);
+
+static DEF_PER1_KCLK(4, p1_msp1_ed_kclk, &msp02clk);
+static DEF_PER_CLK(p1_msp1_ed_clk, &p1_pclk4, &p1_msp1_ed_kclk);
+
+/* SDI0 */
+static DEF_PER1_KCLK(5, p1_sdi0_kclk, &sdmmcclk);
+static DEF_PER_CLK(p1_sdi0_clk, &p1_pclk5, &p1_sdi0_kclk);
+
+/* I2C2 */
+static DEF_PER1_KCLK(6, p1_i2c2_kclk, &i2cclk);
+static DEF_PER_CLK(p1_i2c2_clk, &p1_pclk6, &p1_i2c2_kclk);
+
+/* SPI3 */
/*
- * PRCMU level clock gating
+ * TODO:
+ * This clock was defined like this in the previous implementation, but it
+ * ought to have a parent to be useful, and not hang when enabling.
+ * The definition is kept until its parent is known, or it can be removed.
*/
+static DEF_PER1_KCLK(7, p1_spi3_ed_kclk, NULL);
+static DEF_PER_CLK(p1_spi3_ed_clk, &p1_pclk7, &p1_spi3_ed_kclk);
+
+/* SLIMBUS0 */
+static DEF_PER1_KCLK(3, p1_slimbus0_kclk, &slimclk);
+static DEF_PER_CLK(p1_slimbus0_clk, &p1_pclk8, &p1_slimbus0_kclk);
+
+/* I2C4 */
+static DEF_PER1_KCLK(9, p1_i2c4_kclk, &i2cclk);
+static DEF_PER_CLK(p1_i2c4_clk, &p1_pclk10, &p1_i2c4_kclk);
-/* Bank 0 */
-static DEFINE_PRCMU_CLK(svaclk, 0x0, 2, SVAMMDSPCLK);
-static DEFINE_PRCMU_CLK(siaclk, 0x0, 3, SIAMMDSPCLK);
-static DEFINE_PRCMU_CLK(sgaclk, 0x0, 4, SGACLK);
-static DEFINE_PRCMU_CLK_RATE(uartclk, 0x0, 5, UARTCLK, 38400000);
-static DEFINE_PRCMU_CLK(msp02clk, 0x0, 6, MSP02CLK);
-static DEFINE_PRCMU_CLK(msp1clk, 0x0, 7, MSP1CLK); /* v1 */
-static DEFINE_PRCMU_CLK_RATE(i2cclk, 0x0, 8, I2CCLK, 48000000);
-static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 50000000);
-static DEFINE_PRCMU_CLK(slimclk, 0x0, 10, SLIMCLK);
-static DEFINE_PRCMU_CLK(per1clk, 0x0, 11, PER1CLK);
-static DEFINE_PRCMU_CLK(per2clk, 0x0, 12, PER2CLK);
-static DEFINE_PRCMU_CLK(per3clk, 0x0, 13, PER3CLK);
-static DEFINE_PRCMU_CLK(per5clk, 0x0, 14, PER5CLK);
-static DEFINE_PRCMU_CLK_RATE(per6clk, 0x0, 15, PER6CLK, 133330000);
-static DEFINE_PRCMU_CLK_RATE(per7clk, 0x0, 16, PER7CLK, 100000000);
-static DEFINE_PRCMU_CLK(lcdclk, 0x0, 17, LCDCLK);
-static DEFINE_PRCMU_CLK(bmlclk, 0x0, 18, BMLCLK);
-static DEFINE_PRCMU_CLK(hsitxclk, 0x0, 19, HSITXCLK);
-static DEFINE_PRCMU_CLK(hsirxclk, 0x0, 20, HSIRXCLK);
-static DEFINE_PRCMU_CLK(hdmiclk, 0x0, 21, HDMICLK);
-static DEFINE_PRCMU_CLK(apeatclk, 0x0, 22, APEATCLK);
-static DEFINE_PRCMU_CLK(apetraceclk, 0x0, 23, APETRACECLK);
-static DEFINE_PRCMU_CLK(mcdeclk, 0x0, 24, MCDECLK);
-static DEFINE_PRCMU_CLK(ipi2clk, 0x0, 25, IPI2CCLK);
-static DEFINE_PRCMU_CLK(dsialtclk, 0x0, 26, DSIALTCLK); /* v1 */
-static DEFINE_PRCMU_CLK(dmaclk, 0x0, 27, DMACLK);
-static DEFINE_PRCMU_CLK(b2r2clk, 0x0, 28, B2R2CLK);
-static DEFINE_PRCMU_CLK(tvclk, 0x0, 29, TVCLK);
-static DEFINE_PRCMU_CLK(uniproclk, 0x0, 30, UNIPROCLK); /* v1 */
-static DEFINE_PRCMU_CLK_RATE(sspclk, 0x0, 31, SSPCLK, 48000000); /* v1 */
-
-/* Bank 1 */
-static DEFINE_PRCMU_CLK(rngclk, 0x4, 0, RNGCLK); /* v1 */
-static DEFINE_PRCMU_CLK(uiccclk, 0x4, 1, UICCCLK); /* v1 */
+/* MSP3 */
+static DEF_PER1_KCLK(10, p1_msp3_kclk, &msp1clk);
+static DEF_PER_CLK(p1_msp3_clk, &p1_pclk11, &p1_msp3_kclk);
+/* I2C3 */
+static DEF_PER2_KCLK(0, p2_i2c3_kclk, &i2cclk);
+static DEF_PER_CLK(p2_i2c3_clk, &p2_pclk0, &p2_i2c3_kclk);
+
+/* PWL */
/*
- * PRCC level clock gating
- * Format: per#, clk, PCKEN bit, KCKEN bit, parent
+ * TODO:
+ * This clock was defined like this in the previous implementation, but it
+ * ought to have a parent to be useful, and not hang when enabling.
+ * The definition is kept until its parent is known, or it can be removed.
*/
+static DEF_PER2_KCLK(1, p2_pwl_kclk, NULL);
+static DEF_PER_CLK(p2_pwl_clk, &p2_pclk3, &p2_pwl_kclk);
+
+/* SDI4 */
+static DEF_PER2_KCLK(2, p2_sdi4_kclk, &sdmmcclk);
+static DEF_PER_CLK(p2_sdi4_clk, &p2_pclk4, &p2_sdi4_kclk);
+
+/* MSP2 */
+static DEF_PER2_KCLK(3, p2_msp2_kclk, &msp02clk);
+static DEF_PER_CLK(p2_msp2_clk, &p2_pclk5, &p2_msp2_kclk);
+
+static DEF_PER2_KCLK(4, p2_msp2_ed_kclk, &msp02clk);
+static DEF_PER_CLK(p2_msp2_ed_clk, &p2_pclk6, &p2_msp2_ed_kclk);
+
+/* SDI1 */
+static DEF_PER2_KCLK(4, p2_sdi1_kclk, &sdmmcclk);
+static DEF_PER_CLK(p2_sdi1_clk, &p2_pclk6, &p2_sdi1_kclk);
+
+static DEF_PER2_KCLK(5, p2_sdi1_ed_kclk, &sdmmcclk);
+static DEF_PER_CLK(p2_sdi1_ed_clk, &p2_pclk7, &p2_sdi1_ed_kclk);
+
+/* SDI3 */
+static DEF_PER2_KCLK(5, p2_sdi3_kclk, &sdmmcclk);
+static DEF_PER_CLK(p2_sdi3_clk, &p2_pclk7, &p2_sdi3_kclk);
+
+static DEF_PER2_KCLK(6, p2_sdi3_ed_kclk, &sdmmcclk);
+static DEF_PER_CLK(p2_sdi3_ed_clk, &p2_pclk8, &p2_sdi3_ed_kclk);
+
+/* SSIRX */
+/*
+ * TODO:
+ * This clock was defined like this in the previous implementation, but it
+ * ought to have a parent to be useful, and not hang when enabling.
+ * The definition is kept until its parent is known, or it can be removed.
+ */
+static DEF_PER2_KCLK(6, p2_ssirx_kclk, NULL);
+static DEF_PER_CLK(p2_ssirx_clk, &p2_pclk9, &p2_ssirx_kclk);
+
+/* SSITX */
+/*
+ * TODO:
+ * This clock was defined like this in the previous implementation, but it
+ * ought to have a parent to be useful, and not hang when enabling.
+ * The definition is kept until its parent is known, or it can be removed.
+ */
+static DEF_PER2_KCLK(7, p2_ssitx_kclk, NULL);
+static DEF_PER_CLK(p2_ssitx_clk, &p2_pclk10, &p2_ssitx_kclk);
+
+/* SSP0 */
+static DEF_PER3_KCLK(1, p3_ssp0_kclk, &sspclk);
+static DEF_PER_CLK(p3_ssp0_clk, &p3_pclk1, &p3_ssp0_kclk);
+
+static DEF_PER3_KCLK(1, p3_ssp0_ed_kclk, &i2cclk);
+static DEF_PER_CLK(p3_ssp0_ed_clk, &p3_pclk1, &p3_ssp0_ed_kclk);
+
+/* SSP1 */
+static DEF_PER3_KCLK(2, p3_ssp1_kclk, &sspclk);
+static DEF_PER_CLK(p3_ssp1_clk, &p3_pclk2, &p3_ssp1_kclk);
+
+static DEF_PER3_KCLK(2, p3_ssp1_ed_kclk, &i2cclk);
+static DEF_PER_CLK(p3_ssp1_ed_clk, &p3_pclk2, &p3_ssp1_ed_kclk);
+
+/* I2C0 */
+static DEF_PER3_KCLK(3, p3_i2c0_kclk, &i2cclk);
+static DEF_PER_CLK(p3_i2c0_clk, &p3_pclk3, &p3_i2c0_kclk);
+
+/* SDI2 */
+static DEF_PER3_KCLK(4, p3_sdi2_kclk, &sdmmcclk);
+static DEF_PER_CLK(p3_sdi2_clk, &p3_pclk4, &p3_sdi2_kclk);
+
+/* SKE */
+static DEF_PER3_KCLK(5, p3_ske_kclk, &rtc32k);
+static DEF_PER_CLK(p3_ske_clk, &p3_pclk5, &p3_ske_kclk);
+
+/* UART2 */
+static DEF_PER3_KCLK(6, p3_uart2_kclk, &uartclk);
+static DEF_PER_CLK(p3_uart2_clk, &p3_pclk6, &p3_uart2_kclk);
+
+/* SDI5 */
+static DEF_PER3_KCLK(7, p3_sdi5_kclk, &sdmmcclk);
+static DEF_PER_CLK(p3_sdi5_clk, &p3_pclk7, &p3_sdi5_kclk);
+
+/* USB */
+/*
+ * TODO:
+ * This clock was defined like this in the previous implementation, but it
+ * ought to have a parent to be useful, and not hang when enabling.
+ * The definition is kept until its parent is known, or it can be removed.
+ */
+static DEF_PER5_KCLK(0, p5_usb_kclk, NULL);
+static DEF_PER_CLK(p5_usb_clk, &p5_pclk0, &p5_usb_kclk);
+
+static DEF_PER5_KCLK(0, p5_usb_ed_kclk, &i2cclk);
+static DEF_PER_CLK(p5_usb_ed_clk, &p5_pclk0, &p5_usb_ed_kclk);
+
+/* RNG */
+static DEF_PER6_KCLK(0, p6_rng_kclk, &rngclk);
+static DEF_PER_CLK(p6_rng_clk, &p6_pclk0, &p6_rng_kclk);
+
+static DEF_PER6_KCLK(0, p6_rng_ed_kclk, &i2cclk);
+static DEF_PER_CLK(p6_rng_ed_clk, &p6_pclk0, &p6_rng_ed_kclk);
+
+/* UNIPRO */
+static DEF_PER6_KCLK(1, p6_unipro_kclk, &uniproclk);
+static DEF_PER_CLK(p6_unipro_clk, &p6_pclk4, &p6_unipro_kclk);
+
+
+/* DMC */
+/*
+ * TODO:
+ * This clock was defined like this in the previous implementation, but it
+ * ought to have a parent to be useful, and not hang when enabling.
+ * The definition is kept until its parent is known, or it can be removed.
+ */
+static DEF_PER6_KCLK(6, p6_dmc_ed_kclk, NULL);
+static DEF_PER_CLK(p6_dmc_ed_clk, &p6_pclk6, &p6_dmc_ed_kclk);
+
+/* MTU:S */
+
+#define DEF_MTU_CLK(_cg_sel, _name, _bus_parent) \
+ struct clk _name = { \
+ .name = #_name, \
+ .ops = &mtu_clk_ops, \
+ .cg_sel = _cg_sel, \
+ .bus_parent = _bus_parent, \
+ }
+
+/* MTU0 */
+static DEF_MTU_CLK(0, p6_mtu0_clk, &p6_pclk6);
+static DEF_MTU_CLK(0, p6_mtu0_v1_clk, &p6_pclk7);
+static DEF_MTU_CLK(0, p7_mtu0_ed_clk, &p7_pclk2);
-/* Peripheral Cluster #1 */
-static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk);
-static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL);
-static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk);
-static DEFINE_PRCC_CLK(1, spi3_ed, 7, 7, NULL);
-static DEFINE_PRCC_CLK(1, spi3_v1, 7, -1, NULL);
-static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk);
-static DEFINE_PRCC_CLK(1, sdi0, 5, 5, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(1, msp1_ed, 4, 4, &clk_msp02clk);
-static DEFINE_PRCC_CLK(1, msp1_v1, 4, 4, &clk_msp1clk);
-static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk);
-static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk);
-static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk);
-static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk);
-
-/* Peripheral Cluster #2 */
-
-static DEFINE_PRCC_CLK(2, gpio1_ed, 12, -1, NULL);
-static DEFINE_PRCC_CLK(2, ssitx_ed, 11, -1, NULL);
-static DEFINE_PRCC_CLK(2, ssirx_ed, 10, -1, NULL);
-static DEFINE_PRCC_CLK(2, spi0_ed, 9, -1, NULL);
-static DEFINE_PRCC_CLK(2, sdi3_ed, 8, 6, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(2, sdi1_ed, 7, 5, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(2, msp2_ed, 6, 4, &clk_msp02clk);
-static DEFINE_PRCC_CLK(2, sdi4_ed, 4, 2, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(2, pwl_ed, 3, 1, NULL);
-static DEFINE_PRCC_CLK(2, spi1_ed, 2, -1, NULL);
-static DEFINE_PRCC_CLK(2, spi2_ed, 1, -1, NULL);
-static DEFINE_PRCC_CLK(2, i2c3_ed, 0, 0, &clk_i2cclk);
-
-static DEFINE_PRCC_CLK(2, gpio1_v1, 11, -1, NULL);
-static DEFINE_PRCC_CLK(2, ssitx_v1, 10, 7, NULL);
-static DEFINE_PRCC_CLK(2, ssirx_v1, 9, 6, NULL);
-static DEFINE_PRCC_CLK(2, spi0_v1, 8, -1, NULL);
-static DEFINE_PRCC_CLK(2, sdi3_v1, 7, 5, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(2, sdi1_v1, 6, 4, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(2, msp2_v1, 5, 3, &clk_msp02clk);
-static DEFINE_PRCC_CLK(2, sdi4_v1, 4, 2, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(2, pwl_v1, 3, 1, NULL);
-static DEFINE_PRCC_CLK(2, spi1_v1, 2, -1, NULL);
-static DEFINE_PRCC_CLK(2, spi2_v1, 1, -1, NULL);
-static DEFINE_PRCC_CLK(2, i2c3_v1, 0, 0, &clk_i2cclk);
-
-/* Peripheral Cluster #3 */
-static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL);
-static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk);
-static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz);
-static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk);
-static DEFINE_PRCC_CLK(3, ssp1_ed, 2, 2, &clk_i2cclk);
-static DEFINE_PRCC_CLK(3, ssp0_ed, 1, 1, &clk_i2cclk);
-static DEFINE_PRCC_CLK(3, ssp1_v1, 2, 2, &clk_sspclk);
-static DEFINE_PRCC_CLK(3, ssp0_v1, 1, 1, &clk_sspclk);
-static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL);
-
-/* Peripheral Cluster #4 is in the always on domain */
-
-/* Peripheral Cluster #5 */
-static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL);
-static DEFINE_PRCC_CLK(5, usb_ed, 0, 0, &clk_i2cclk);
-static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL);
-
-/* Peripheral Cluster #6 */
-
-/* MTU ID in data */
-static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1);
-static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0);
-static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL);
-static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL);
-static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL);
-static DEFINE_PRCC_CLK(6, unipro_v1, 4, 1, &clk_uniproclk);
-static DEFINE_PRCC_CLK(6, cryp1_ed, 4, -1, NULL);
-static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL);
-static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL);
-static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL);
-static DEFINE_PRCC_CLK(6, rng_ed, 0, 0, &clk_i2cclk);
-static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk);
-
-/* Peripheral Cluster #7 */
-
-static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL);
-/* MTU ID in data */
-static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1);
-static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0);
-static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL);
-static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL);
-
-static struct clk_lookup u8500_common_clks[] = {
- /* Peripheral Cluster #1 */
- CLK(gpio0, "gpio.0", NULL),
- CLK(gpio0, "gpio.1", NULL),
- CLK(slimbus0, "slimbus0", NULL),
- CLK(i2c2, "nmk-i2c.2", NULL),
- CLK(sdi0, "sdi0", NULL),
- CLK(msp0, "msp0", NULL),
- CLK(i2c1, "nmk-i2c.1", NULL),
- CLK(uart1, "uart1", NULL),
- CLK(uart0, "uart0", NULL),
-
- /* Peripheral Cluster #3 */
- CLK(gpio2, "gpio.2", NULL),
- CLK(gpio2, "gpio.3", NULL),
- CLK(gpio2, "gpio.4", NULL),
- CLK(gpio2, "gpio.5", NULL),
- CLK(sdi5, "sdi5", NULL),
- CLK(uart2, "uart2", NULL),
- CLK(ske, "ske", NULL),
- CLK(sdi2, "sdi2", NULL),
- CLK(i2c0, "nmk-i2c.0", NULL),
- CLK(fsmc, "fsmc", NULL),
-
- /* Peripheral Cluster #5 */
- CLK(gpio3, "gpio.8", NULL),
-
- /* Peripheral Cluster #6 */
- CLK(hash1, "hash1", NULL),
- CLK(pka, "pka", NULL),
- CLK(hash0, "hash0", NULL),
- CLK(cryp0, "cryp0", NULL),
-
- /* PRCMU level clock gating */
-
- /* Bank 0 */
- CLK(svaclk, "sva", NULL),
- CLK(siaclk, "sia", NULL),
- CLK(sgaclk, "sga", NULL),
- CLK(slimclk, "slim", NULL),
- CLK(lcdclk, "lcd", NULL),
- CLK(bmlclk, "bml", NULL),
- CLK(hsitxclk, "stm-hsi.0", NULL),
- CLK(hsirxclk, "stm-hsi.1", NULL),
- CLK(hdmiclk, "hdmi", NULL),
- CLK(apeatclk, "apeat", NULL),
- CLK(apetraceclk, "apetrace", NULL),
- CLK(mcdeclk, "mcde", NULL),
- CLK(ipi2clk, "ipi2", NULL),
- CLK(dmaclk, "dma40.0", NULL),
- CLK(b2r2clk, "b2r2", NULL),
- CLK(tvclk, "tv", NULL),
+/* MTU1 */
+static DEF_MTU_CLK(1, p6_mtu1_clk, &p6_pclk7);
+static DEF_MTU_CLK(1, p6_mtu1_v1_clk, &p6_pclk8);
+static DEF_MTU_CLK(1, p7_mtu1_ed_clk, &p7_pclk3);
+
+/*
+ * TODO: Ensure names match with devices and then remove unnecessary entries
+ * when all drivers use the clk API.
+ */
+
+#define CLK_LOOKUP(_clk, _dev_id, _con_id) \
+ { .dev_id = _dev_id, .con_id = _con_id, .clk = &_clk }
+
+static struct clk_lookup u8500_common_clock_sources[] = {
+ CLK_LOOKUP(soc0_pll, NULL, "soc0_pll"),
+ CLK_LOOKUP(soc1_pll, NULL, "soc1_pll"),
+ CLK_LOOKUP(ddr_pll, NULL, "ddr_pll"),
+ CLK_LOOKUP(ulp38m4, NULL, "ulp38m4"),
+ CLK_LOOKUP(sysclk, NULL, "sysclk"),
+ CLK_LOOKUP(rtc32k, NULL, "clk32k"),
+};
+
+static struct clk_lookup u8500_v2_clock_sources[] = {
+ CLK_LOOKUP(sysclk2, NULL, "sysclk2"),
+};
+
+static struct clk_lookup u8500_common_prcmu_clocks[] = {
+ CLK_LOOKUP(svammdspclk, "sva", NULL),
+ CLK_LOOKUP(siammdspclk, "sia", NULL),
+ CLK_LOOKUP(sgaclk, "sga", NULL),
+ CLK_LOOKUP(uartclk, "UART", NULL),
+ CLK_LOOKUP(msp02clk, "MSP02", NULL),
+ CLK_LOOKUP(i2cclk, "I2C", NULL),
+ CLK_LOOKUP(sdmmcclk, "sdmmc", NULL),
+ CLK_LOOKUP(slimclk, "slim", NULL),
+ CLK_LOOKUP(per1clk, "PERIPH1", NULL),
+ CLK_LOOKUP(per2clk, "PERIPH2", NULL),
+ CLK_LOOKUP(per3clk, "PERIPH3", NULL),
+ CLK_LOOKUP(per5clk, "PERIPH5", NULL),
+ CLK_LOOKUP(per6clk, "PERIPH6", NULL),
+ CLK_LOOKUP(per7clk, "PERIPH7", NULL),
+ CLK_LOOKUP(lcdclk, "lcd", NULL),
+ CLK_LOOKUP(bmlclk, "bml", NULL),
+ CLK_LOOKUP(hsitxclk, "stm-hsi.0", NULL),
+ CLK_LOOKUP(hsirxclk, "stm-hsi.1", NULL),
+ CLK_LOOKUP(lcdclk, "mcde", "lcd"),
+ CLK_LOOKUP(hdmiclk, "hdmi", NULL),
+ CLK_LOOKUP(hdmiclk, "mcde", "hdmi"),
+ CLK_LOOKUP(apeatclk, "apeat", NULL),
+ CLK_LOOKUP(apetraceclk, "apetrace", NULL),
+ CLK_LOOKUP(mcdeclk, "mcde", NULL),
+ CLK_LOOKUP(mcdeclk, "mcde", "mcde"),
+ CLK_LOOKUP(ipi2cclk, "ipi2", NULL),
+ CLK_LOOKUP(dmaclk, "dma40.0", NULL),
+ CLK_LOOKUP(b2r2clk, "b2r2", NULL),
+ CLK_LOOKUP(b2r2clk, "b2r2_bus", NULL),
+ CLK_LOOKUP(b2r2clk, "U8500-B2R2.0", NULL),
+ CLK_LOOKUP(tvclk, "tv", NULL),
+ CLK_LOOKUP(tvclk, "mcde", "tv"),
+};
+
+static struct clk_lookup u8500_common_prcc_clocks[] = {
+ /* PERIPH 1 */
+ CLK_LOOKUP(p1_uart0_clk, "uart0", NULL),
+ CLK_LOOKUP(p1_uart1_clk, "uart1", NULL),
+ CLK_LOOKUP(p1_i2c1_clk, "nmk-i2c.1", NULL),
+ CLK_LOOKUP(p1_msp0_clk, "msp0", NULL),
+ CLK_LOOKUP(p1_msp0_clk, "MSP_I2S.0", NULL),
+ CLK_LOOKUP(p1_sdi0_clk, "sdi0", NULL),
+ CLK_LOOKUP(p1_i2c2_clk, "nmk-i2c.2", NULL),
+ CLK_LOOKUP(p1_slimbus0_clk, "slimbus0", NULL),
+ CLK_LOOKUP(p1_pclk9, "gpio.0", NULL),
+ CLK_LOOKUP(p1_pclk9, "gpio.1", NULL),
+ CLK_LOOKUP(p1_pclk9, "gpioblock0", NULL),
+
+ /* PERIPH 2 */
+ CLK_LOOKUP(p2_i2c3_clk, "nmk-i2c.3", NULL),
+ CLK_LOOKUP(p2_pclk1, "spi2", NULL),
+ CLK_LOOKUP(p2_pclk2, "spi1", NULL),
+ CLK_LOOKUP(p2_pclk3, "pwl", NULL),
+ CLK_LOOKUP(p2_sdi4_clk, "sdi4", NULL),
+
+ /* PERIPH 3 */
+ CLK_LOOKUP(p3_pclk0, "fsmc", NULL),
+ CLK_LOOKUP(p3_i2c0_clk, "nmk-i2c.0", NULL),
+ CLK_LOOKUP(p3_sdi2_clk, "sdi2", NULL),
+ CLK_LOOKUP(p3_ske_clk, "ske", NULL),
+ CLK_LOOKUP(p3_ske_clk, "nmk-ske-keypad", NULL),
+ CLK_LOOKUP(p3_uart2_clk, "uart2", NULL),
+ CLK_LOOKUP(p3_sdi5_clk, "sdi5", NULL),
+ CLK_LOOKUP(p3_pclk8, "gpio.2", NULL),
+ CLK_LOOKUP(p3_pclk8, "gpio.3", NULL),
+ CLK_LOOKUP(p3_pclk8, "gpio.4", NULL),
+ CLK_LOOKUP(p3_pclk8, "gpio.5", NULL),
+ CLK_LOOKUP(p3_pclk8, "gpioblock2", NULL),
+
+ /* PERIPH 5 */
+ CLK_LOOKUP(p5_pclk1, "gpio.8", NULL),
+ CLK_LOOKUP(p5_pclk1, "gpioblock3", NULL),
+
+ /* PERIPH 6 */
+ CLK_LOOKUP(p6_pclk1, "cryp0", NULL),
+ CLK_LOOKUP(p6_pclk2, "hash0", NULL),
+ CLK_LOOKUP(p6_pclk3, "pka", NULL),
+};
+
+static struct clk_lookup u8500_ed_prcc_clocks[] = {
+ /* PERIPH 1 */
+ CLK_LOOKUP(p1_msp1_ed_clk, "msp1", NULL),
+ CLK_LOOKUP(p1_msp1_ed_clk, "MSP_I2S.1", NULL),
+ CLK_LOOKUP(p1_pclk7, "spi3", NULL),
+
+ /* PERIPH 2 */
+ CLK_LOOKUP(p2_msp2_ed_clk, "msp2", NULL),
+ CLK_LOOKUP(p2_msp2_ed_clk, "MSP_I2S.2", NULL),
+ CLK_LOOKUP(p2_sdi1_ed_clk, "sdi1", NULL),
+ CLK_LOOKUP(p2_sdi3_ed_clk, "sdi3", NULL),
+ CLK_LOOKUP(p2_pclk9, "spi0", NULL),
+ CLK_LOOKUP(p2_pclk10, "ssirx", NULL),
+ CLK_LOOKUP(p2_pclk11, "ssitx", NULL),
+ CLK_LOOKUP(p2_pclk12, "gpio.6", NULL),
+ CLK_LOOKUP(p2_pclk12, "gpio.7", NULL),
+ CLK_LOOKUP(p2_pclk12, "gpioblock1", NULL),
+
+ /* PERIPH 3 */
+ CLK_LOOKUP(p3_ssp0_ed_clk, "ssp0", NULL),
+ CLK_LOOKUP(p3_ssp1_ed_clk, "ssp1", NULL),
+
+ /* PERIPH 5 */
+ CLK_LOOKUP(p5_usb_ed_clk, "musb_hdrc.0", "usb"),
+
+ /* PERIPH 6 */
+ CLK_LOOKUP(p6_rng_ed_clk, "rng", NULL),
+ CLK_LOOKUP(p6_pclk4, "cryp1", NULL),
+ CLK_LOOKUP(p6_pclk5, "hash1", NULL),
+ CLK_LOOKUP(p6_pclk6, "dmc", NULL),
+
+ /* PERIPH 7 */
+ CLK_LOOKUP(p7_pclk0, "cfgreg", NULL),
+ CLK_LOOKUP(p7_pclk1, "wdg", NULL),
+ CLK_LOOKUP(p7_mtu0_ed_clk, "mtu0", NULL),
+ CLK_LOOKUP(p7_mtu1_ed_clk, "mtu1", NULL),
+ CLK_LOOKUP(p7_pclk4, "tzpc0", NULL),
+};
+
+static struct clk_lookup u8500_v1_v2_prcmu_clocks[] = {
+ CLK_LOOKUP(msp1clk, "MSP1", NULL),
+ CLK_LOOKUP(dsialtclk, "dsialt", NULL),
+ CLK_LOOKUP(sspclk, "SSP", NULL),
+ CLK_LOOKUP(rngclk, "rngclk", NULL),
+ CLK_LOOKUP(uiccclk, "uicc", NULL),
+};
+
+static struct clk_lookup u8500_v1_v2_prcc_clocks[] = {
+ /* PERIPH 1 */
+ CLK_LOOKUP(p1_msp1_clk, "msp1", NULL),
+ CLK_LOOKUP(p1_msp1_clk, "MSP_I2S.1", NULL),
+ CLK_LOOKUP(p1_pclk7, "spi3", NULL),
+ CLK_LOOKUP(p1_i2c4_clk, "nmk-i2c.4", NULL),
+
+ /* PERIPH 2 */
+ CLK_LOOKUP(p2_msp2_clk, "msp2", NULL),
+ CLK_LOOKUP(p2_msp2_clk, "MSP_I2S.2", NULL),
+ CLK_LOOKUP(p2_sdi1_clk, "sdi1", NULL),
+ CLK_LOOKUP(p2_sdi3_clk, "sdi3", NULL),
+ CLK_LOOKUP(p2_pclk8, "spi0", NULL),
+ CLK_LOOKUP(p2_pclk9, "ssirx", NULL),
+ CLK_LOOKUP(p2_pclk10, "ssitx", NULL),
+ CLK_LOOKUP(p2_pclk11, "gpio.6", NULL),
+ CLK_LOOKUP(p2_pclk11, "gpio.7", NULL),
+ CLK_LOOKUP(p2_pclk11, "gpioblock1", NULL),
+
+ /* PERIPH 3 */
+ CLK_LOOKUP(p3_ssp0_clk, "ssp0", NULL),
+ CLK_LOOKUP(p3_ssp1_clk, "ssp1", NULL),
+
+ /* PERIPH 5 */
+ CLK_LOOKUP(p5_pclk0, "musb_hdrc.0", "usb"),
+
+ /* PERIPH 6 */
+ CLK_LOOKUP(p6_rng_clk, "rng", NULL),
+};
+
+static struct clk_lookup u8500_v1_prcmu_clocks[] = {
+ CLK_LOOKUP(uniproclk, "uniproclk", NULL),
+};
+
+static struct clk_lookup u8500_v1_prcc_clocks[] = {
+ /* PERIPH 6 */
+ CLK_LOOKUP(p6_unipro_clk, "unipro", NULL),
+ CLK_LOOKUP(p6_pclk5, "hash1", NULL),
+ CLK_LOOKUP(p6_pclk6, "cfgreg", NULL),
+ CLK_LOOKUP(p6_mtu0_v1_clk, "mtu0", NULL),
+ CLK_LOOKUP(p6_mtu1_v1_clk, "mtu1", NULL),
};
-static struct clk_lookup u8500_ed_clks[] = {
- /* Peripheral Cluster #1 */
- CLK(spi3_ed, "spi3", NULL),
- CLK(msp1_ed, "msp1", NULL),
-
- /* Peripheral Cluster #2 */
- CLK(gpio1_ed, "gpio.6", NULL),
- CLK(gpio1_ed, "gpio.7", NULL),
- CLK(ssitx_ed, "ssitx", NULL),
- CLK(ssirx_ed, "ssirx", NULL),
- CLK(spi0_ed, "spi0", NULL),
- CLK(sdi3_ed, "sdi3", NULL),
- CLK(sdi1_ed, "sdi1", NULL),
- CLK(msp2_ed, "msp2", NULL),
- CLK(sdi4_ed, "sdi4", NULL),
- CLK(pwl_ed, "pwl", NULL),
- CLK(spi1_ed, "spi1", NULL),
- CLK(spi2_ed, "spi2", NULL),
- CLK(i2c3_ed, "nmk-i2c.3", NULL),
-
- /* Peripheral Cluster #3 */
- CLK(ssp1_ed, "ssp1", NULL),
- CLK(ssp0_ed, "ssp0", NULL),
-
- /* Peripheral Cluster #5 */
- CLK(usb_ed, "musb_hdrc.0", "usb"),
-
- /* Peripheral Cluster #6 */
- CLK(dmc_ed, "dmc", NULL),
- CLK(cryp1_ed, "cryp1", NULL),
- CLK(rng_ed, "rng", NULL),
-
- /* Peripheral Cluster #7 */
- CLK(tzpc0_ed, "tzpc0", NULL),
- CLK(mtu1_ed, "mtu1", NULL),
- CLK(mtu0_ed, "mtu0", NULL),
- CLK(wdg_ed, "wdg", NULL),
- CLK(cfgreg_ed, "cfgreg", NULL),
+static struct clk_lookup u8500_v2_prcc_clocks[] = {
+ /* PERIPH 1 */
+ CLK_LOOKUP(p1_msp3_clk, "msp3", NULL),
+ CLK_LOOKUP(p1_msp3_clk, "MSP_I2S.3", NULL),
+
+ /* PERIPH 6 */
+ CLK_LOOKUP(p6_pclk4, "hash1", NULL),
+ CLK_LOOKUP(p6_pclk5, "cfgreg", NULL),
+ CLK_LOOKUP(p6_mtu0_clk, "mtu0", NULL),
+ CLK_LOOKUP(p6_mtu1_clk, "mtu1", NULL),
};
-static struct clk_lookup u8500_v1_clks[] = {
- /* Peripheral Cluster #1 */
- CLK(i2c4, "nmk-i2c.4", NULL),
- CLK(spi3_v1, "spi3", NULL),
- CLK(msp1_v1, "msp1", NULL),
-
- /* Peripheral Cluster #2 */
- CLK(gpio1_v1, "gpio.6", NULL),
- CLK(gpio1_v1, "gpio.7", NULL),
- CLK(ssitx_v1, "ssitx", NULL),
- CLK(ssirx_v1, "ssirx", NULL),
- CLK(spi0_v1, "spi0", NULL),
- CLK(sdi3_v1, "sdi3", NULL),
- CLK(sdi1_v1, "sdi1", NULL),
- CLK(msp2_v1, "msp2", NULL),
- CLK(sdi4_v1, "sdi4", NULL),
- CLK(pwl_v1, "pwl", NULL),
- CLK(spi1_v1, "spi1", NULL),
- CLK(spi2_v1, "spi2", NULL),
- CLK(i2c3_v1, "nmk-i2c.3", NULL),
-
- /* Peripheral Cluster #3 */
- CLK(ssp1_v1, "ssp1", NULL),
- CLK(ssp0_v1, "ssp0", NULL),
-
- /* Peripheral Cluster #5 */
- CLK(usb_v1, "musb_hdrc.0", "usb"),
-
- /* Peripheral Cluster #6 */
- CLK(mtu1_v1, "mtu1", NULL),
- CLK(mtu0_v1, "mtu0", NULL),
- CLK(cfgreg_v1, "cfgreg", NULL),
- CLK(hash1, "hash1", NULL),
- CLK(unipro_v1, "unipro", NULL),
- CLK(rng_v1, "rng", NULL),
-
- /* PRCMU level clock gating */
-
- /* Bank 0 */
- CLK(uniproclk, "uniproclk", NULL),
- CLK(dsialtclk, "dsialt", NULL),
-
- /* Bank 1 */
- CLK(rngclk, "rng", NULL),
- CLK(uiccclk, "uicc", NULL),
+static void clks_register(struct clk_lookup *clks, size_t num)
+{
+ unsigned int i;
+
+ for (i = 0; i < num; i++)
+ clkdev_add(&clks[i]);
+}
+
+/* these are the clocks which are default from the bootloader */
+static const char *u8500_boot_clk[] = {
+ "uart0",
+ "uart1",
+ "uart2",
+ "gpioblock0",
+ "gpioblock1",
+ "gpioblock2",
+ "gpioblock3",
+ "mtu0",
+ "mtu1",
+ "ssp0",
+ "ssp1",
+ "spi0",
+ "spi1",
+ "spi2",
+ "spi3",
+ "msp0",
+ "msp1",
+ "msp2",
+ "nmk-i2c.0",
+ "nmk-i2c.1",
+ "nmk-i2c.2",
+ "nmk-i2c.3",
+ "nmk-i2c.4",
};
+struct clk *boot_clks[ARRAY_SIZE(u8500_boot_clk)];
+
+/* we disable a majority of peripherals enabled by default
+ * but without drivers
+ */
+static int __init u8500_boot_clk_disable(void)
+{
+ unsigned int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(u8500_boot_clk); i++) {
+ if (!boot_clks[i])
+ continue;
+
+ clk_disable(boot_clks[i]);
+ clk_put(boot_clks[i]);
+ }
+
+ return 0;
+}
+late_initcall_sync(u8500_boot_clk_disable);
+
+static void u8500_amba_clk_enable(void)
+{
+ unsigned int i = 0;
+
+ writel(~0x0 & ~(1 << 9), __io_address(U8500_PER1_BASE + 0xF000
+ + 0x04));
+ writel(~0x0, __io_address(U8500_PER1_BASE + 0xF000 + 0x0C));
+
+ writel(~0x0 & ~(1 << 11), __io_address(U8500_PER2_BASE + 0xF000
+ + 0x04));
+ writel(~0x0, __io_address(U8500_PER2_BASE + 0xF000 + 0x0C));
+
+ /*GPIO,UART2 are enabled for booting*/
+ writel(0xBF, __io_address(U8500_PER3_BASE + 0xF000 + 0x04));
+ writel(~0x0 & ~(1 << 6), __io_address(U8500_PER3_BASE + 0xF000
+ + 0x0C));
+
+ for (i = 0; i < ARRAY_SIZE(u8500_boot_clk); i++) {
+ boot_clks[i] = clk_get_sys(u8500_boot_clk[i], NULL);
+ clk_enable(boot_clks[i]);
+ }
+}
+
int __init clk_init(void)
{
if (cpu_is_u8500ed()) {
- clk_prcmu_ops.enable = clk_prcmu_ed_enable;
- clk_prcmu_ops.disable = clk_prcmu_ed_disable;
- clk_per6clk.rate = 100000000;
+ pr_err("clock: U8500 ED is no longer supported.\n");
+ return -ENOSYS;
+ }
+
+ if (cpu_is_u8500())
+ prcmu_base = __io_address(U8500_PRCMU_BASE);
+ else if (cpu_is_u5500())
+ prcmu_base = __io_address(U5500_PRCMU_BASE);
+ else {
+ pr_err("clock: Unknown DB Asic.\n");
+ return -EIO;
+ }
+
+ if (cpu_is_u8500v1()) {
+ void __iomem *sdmmclkmgt = prcmu_base + PRCM_SDMMCCLK_MGT;
+ unsigned int val;
+
+ /* Set SDMMCCLK at 100Mhz */
+ val = readl(sdmmclkmgt);
+ /*
+ * set the clock divider
+ * to configure the MCLK at 100MHZ
+ */
+ val = (val & ~SD_CLK_DIV_MASK) | SD_CLK_DIV_VAL;
+ writel(val, sdmmclkmgt);
} else if (cpu_is_u5500()) {
- /* Clock tree for U5500 not implemented yet */
- clk_prcc_ops.enable = clk_prcc_ops.disable = NULL;
- clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL;
- clk_per6clk.rate = 26000000;
+ per6clk.rate = 26000000;
+ per6clk.rate_50 = 13000000;
+ uartclk.rate = 36360000;
}
- clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
- if (cpu_is_u8500ed())
- clkdev_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks));
- else
- clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks));
+ if (cpu_is_u5500() || machine_is_svp()) {
+ sysclk_ops.enable = NULL;
+ sysclk_ops.disable = NULL;
+ prcmu_fixed_clk_ops.enable = NULL;
+ prcmu_fixed_clk_ops.disable = NULL;
+ prcmu_scaling_clk_ops.enable = NULL;
+ prcmu_scaling_clk_ops.disable = NULL;
+ prcc_pclk_ops.enable = NULL;
+ prcc_pclk_ops.disable = NULL;
+ prcc_kclk_ops.enable = NULL;
+ prcc_kclk_ops.disable = NULL;
+ }
+
+ clks_register(u8500_common_clock_sources,
+ ARRAY_SIZE(u8500_common_clock_sources));
+ clks_register(u8500_common_prcmu_clocks,
+ ARRAY_SIZE(u8500_common_prcmu_clocks));
+ clks_register(u8500_common_prcc_clocks,
+ ARRAY_SIZE(u8500_common_prcc_clocks));
+
+ if (cpu_is_u5500()) {
+ clks_register(u8500_ed_prcc_clocks,
+ ARRAY_SIZE(u8500_ed_prcc_clocks));
+ } else if (cpu_is_u8500v1()) {
+ clks_register(u8500_v1_v2_prcmu_clocks,
+ ARRAY_SIZE(u8500_v1_v2_prcmu_clocks));
+ clks_register(u8500_v1_v2_prcc_clocks,
+ ARRAY_SIZE(u8500_v1_v2_prcc_clocks));
+ clks_register(u8500_v1_prcmu_clocks,
+ ARRAY_SIZE(u8500_v1_prcmu_clocks));
+ clks_register(u8500_v1_prcc_clocks,
+ ARRAY_SIZE(u8500_v1_prcc_clocks));
+ } else if (cpu_is_u8500v2()) {
+ clks_register(u8500_v2_clock_sources,
+ ARRAY_SIZE(u8500_v2_clock_sources));
+ clks_register(u8500_v1_v2_prcmu_clocks,
+ ARRAY_SIZE(u8500_v1_v2_prcmu_clocks));
+ clks_register(u8500_v1_v2_prcc_clocks,
+ ARRAY_SIZE(u8500_v1_v2_prcc_clocks));
+ clks_register(u8500_v2_prcc_clocks,
+ ARRAY_SIZE(u8500_v2_prcc_clocks));
+ }
+
+ if (cpu_is_u8500())
+ u8500_amba_clk_enable();
return 0;
}
diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h
index a0580250152..81fd63c4acc 100644
--- a/arch/arm/mach-ux500/clock.h
+++ b/arch/arm/mach-ux500/clock.h
@@ -17,131 +17,75 @@
* control the clock. All of these functions are optional. If get_rate is
* NULL, the rate in the struct clk will be used.
*/
-struct clkops {
- void (*enable) (struct clk *);
- void (*disable) (struct clk *);
- unsigned long (*get_rate) (struct clk *);
-};
-
-/**
- * struct clk - ux500 clock structure
- * @ops: pointer to clkops struct used to control this clock
- * @name: name, for debugging
- * @enabled: refcount. positive if enabled, zero if disabled
- * @get_rate: custom callback for getting the clock rate
- * @data: custom per-clock data for example for the get_rate
- * callback
- * @rate: fixed rate for clocks which don't implement
- * ops->getrate
- * @prcmu_cg_off: address offset of the combined enable/disable register
- * (used on u8500v1)
- * @prcmu_cg_bit: bit in the combined enable/disable register (used on
- * u8500v1)
- * @prcmu_cg_mgt: address of the enable/disable register (used on
- * u8500ed)
- * @cluster: peripheral cluster number
- * @prcc_bus: bit for the bus clock in the peripheral's CLKRST
- * @prcc_kernel: bit for the kernel clock in the peripheral's CLKRST.
- * -1 if no kernel clock exists.
- * @parent_cluster: pointer to parent's cluster clk struct
- * @parent_periph: pointer to parent's peripheral clk struct
- *
- * Peripherals are organised into clusters, and each cluster has an associated
- * bus clock. Some peripherals also have a parent peripheral clock.
- *
- * In order to enable a clock for a peripheral, we need to enable:
- * (1) the parent cluster (bus) clock at the PRCMU level
- * (2) the parent peripheral clock (if any) at the PRCMU level
- * (3) the peripheral's bus & kernel clock at the PRCC level
- *
- * (1) and (2) are handled by defining clk structs (DEFINE_PRCMU_CLK) for each
- * of the cluster and peripheral clocks, and hooking these as the parents of
- * the individual peripheral clocks.
- *
- * (3) is handled by specifying the bits in the PRCC control registers required
- * to enable these clocks and modifying them in the ->enable and
- * ->disable callbacks of the peripheral clocks (DEFINE_PRCC_CLK).
- *
- * This structure describes both the PRCMU-level clocks and PRCC-level clocks.
- * The prcmu_* fields are only used for the PRCMU clocks, and the cluster,
- * prcc, and parent pointers are only used for the PRCC-level clocks.
- */
-struct clk {
- const struct clkops *ops;
- const char *name;
- unsigned int enabled;
- unsigned long (*get_rate)(struct clk *);
- void *data;
+extern int __init clk_init(void);
- unsigned long rate;
- struct list_head list;
+/*PLLSW clk src macros */
+#define PLL_SW_SOC0 0x20
+#define PLL_SW_SOC1 0x40
+#define PLL_SW_DDR 0x80
+#define PLL_SELECT_BITS 0xE0
- /* These three are only for PRCMU clks */
+/*Mode clk src macros */
+#define MODE_NO_CLK 0x0
+#define MODE_CLK32KHZ 0x1
+#define MODE_CLK38_4MHZ 0x2
+#define MODE_PLL_CLK 0x4
- unsigned int prcmu_cg_off;
- unsigned int prcmu_cg_bit;
- unsigned int prcmu_cg_mgt;
+/* Function declarion */
+void update_clk_tree(void);
- /* The rest are only for PRCC clks */
+/*CLK38 clk src macros */
+#define CLK38_SRC 0x400
+#define CLK38 0x200
+/* Clock enable bit */
+#define ENABLE_BIT 0x100
- int cluster;
- unsigned int prcc_bus;
- unsigned int prcc_kernel;
+#define SD_CLK_DIV_MASK 0x1F
+#define SD_CLK_DIV_VAL 8
- struct clk *parent_cluster;
- struct clk *parent_periph;
+struct clkops {
+ int (*enable)(struct clk *);
+ void (*disable)(struct clk *);
+ unsigned long (*get_rate)(struct clk *);
+ void (*set_rate)(struct clk *, unsigned long);
+ int (*set_parent)(struct clk *, struct clk *);
};
-#define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \
-struct clk clk_##_name = { \
- .name = #_name, \
- .ops = &clk_prcmu_ops, \
- .prcmu_cg_off = _cg_off, \
- .prcmu_cg_bit = _cg_bit, \
- .prcmu_cg_mgt = PRCM_##_reg##_MGT \
- }
-
-#define DEFINE_PRCMU_CLK_RATE(_name, _cg_off, _cg_bit, _reg, _rate) \
-struct clk clk_##_name = { \
- .name = #_name, \
- .ops = &clk_prcmu_ops, \
- .prcmu_cg_off = _cg_off, \
- .prcmu_cg_bit = _cg_bit, \
- .rate = _rate, \
- .prcmu_cg_mgt = PRCM_##_reg##_MGT \
- }
-
-#define DEFINE_PRCC_CLK(_pclust, _name, _bus_en, _kernel_en, _kernclk) \
-struct clk clk_##_name = { \
- .name = #_name, \
- .ops = &clk_prcc_ops, \
- .cluster = _pclust, \
- .prcc_bus = _bus_en, \
- .prcc_kernel = _kernel_en, \
- .parent_cluster = &clk_per##_pclust##clk, \
- .parent_periph = _kernclk \
- }
-
-#define DEFINE_PRCC_CLK_CUSTOM(_pclust, _name, _bus_en, _kernel_en, _kernclk, _callback, _data) \
-struct clk clk_##_name = { \
- .name = #_name, \
- .ops = &clk_prcc_ops, \
- .cluster = _pclust, \
- .prcc_bus = _bus_en, \
- .prcc_kernel = _kernel_en, \
- .parent_cluster = &clk_per##_pclust##clk, \
- .parent_periph = _kernclk, \
- .get_rate = _callback, \
- .data = (void *) _data \
- }
-
-
-#define CLK(_clk, _devname, _conname) \
- { \
- .clk = &clk_##_clk, \
- .dev_id = _devname, \
- .con_id = _conname, \
- }
-
-int __init clk_db8500_ed_fixup(void);
-int __init clk_init(void);
+/**
+ * struct clk
+ * @ops: The hardware specific operations defined for the clock.
+ * @name: The name of the clock.
+ * @mutex: The mutex to lock when operating on the clock. %NULL means that
+ * the common clock spinlock will be used.
+ * @enabled: A reference counter of the enable requests for the clock.
+ * @opp100: A flag saying whether the clock is requested to run at the
+ * OPP 100%% frequency.
+ * @rate: The frequency of the clock. For scalable and scaling clocks,
+ * this is the OPP 100%% frequency.
+ * @rate_50: The frequency of the clock at OPP 50%, for scalable and scaling
+ * clocks.
+ * @io_base: An IO memory base address, meaningful only when considered
+ * together with the defined @ops.
+ * @cg_sel: Clock gate selector, meaningful only when considered together
+ * with the specified @ops.
+ * @parent: The current (or only) parent clock of the clock.
+ * @bus_parent: The (optional) auxiliary bus clock "parent" of the clock.
+ * @parents: A list of the possible parents the clock can have. This should
+ * be a %NULL-terminated &struct_clk array. Present if and only
+ * if clk_set_parent() is implemented for the clock.
+ */
+struct clk {
+ const struct clkops *ops;
+ const char *name;
+ struct mutex *mutex;
+ unsigned int enabled;
+ bool opp100;
+ unsigned long rate;
+ unsigned long rate_50;
+ unsigned int io_base;
+ u32 cg_sel;
+ struct clk *parent;
+ struct clk *bus_parent;
+ struct clk **parents;
+ struct list_head list;
+};
diff --git a/arch/arm/mach-ux500/context-db5500.c b/arch/arm/mach-ux500/context-db5500.c
new file mode 100644
index 00000000000..f9a8376620f
--- /dev/null
+++ b/arch/arm/mach-ux500/context-db5500.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>,
+ * Rickard Andersson <rickard.andersson@stericsson.com>,
+ * Sundar Iyer <sundar.iyer@stericsson.com>,
+ * ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ */
+
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+
+#include "context.h"
+
+/* These registers are DB5500 specific */
+#define NODE_HIBW1_ESRAM_IN_0_PRIORITY 0x0
+#define NODE_HIBW1_ESRAM_IN_1_PRIORITY 0x4
+
+#define NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT 0x18
+#define NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT 0x1C
+#define NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT 0x20
+
+#define NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT 0x24
+#define NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT 0x28
+#define NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT 0x2C
+
+#define NODE_HIBW1_DDR_IN_0_PRIORITY 0x400
+#define NODE_HIBW1_DDR_IN_1_PRIORITY 0x404
+#define NODE_HIBW1_DDR_IN_2_PRIORITY 0x408
+
+#define NODE_HIBW1_DDR_IN_0_LIMIT 0x424
+#define NODE_HIBW1_DDR_IN_1_LIMIT 0x428
+#define NODE_HIBW1_DDR_IN_2_LIMIT 0x42C
+
+#define NODE_HIBW1_DDR_OUT_0_PRIORITY 0x430
+
+#define NODE_HIBW2_ESRAM_IN_0_PRIORITY 0x800
+#define NODE_HIBW2_ESRAM_IN_1_PRIORITY 0x804
+
+#define NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT 0x818
+#define NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT 0x81C
+#define NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT 0x820
+
+#define NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT 0x824
+#define NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT 0x828
+#define NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT 0x82C
+
+#define NODE_HIBW2_DDR_IN_0_PRIORITY 0xC00
+#define NODE_HIBW2_DDR_IN_1_PRIORITY 0xC04
+#define NODE_HIBW2_DDR_IN_2_PRIORITY 0xC08
+
+#define NODE_HIBW2_DDR_IN_0_LIMIT 0xC24
+#define NODE_HIBW2_DDR_IN_1_LIMIT 0xC28
+#define NODE_HIBW2_DDR_IN_2_LIMIT 0xC2C
+
+#define NODE_HIBW2_DDR_OUT_0_PRIORITY 0xC30
+
+#define NODE_ESRAM0_IN_0_PRIORITY 0x1000
+#define NODE_ESRAM0_IN_1_PRIORITY 0x1004
+#define NODE_ESRAM0_IN_2_PRIORITY 0x1008
+
+#define NODE_ESRAM0_IN_0_LIMIT 0x1024
+#define NODE_ESRAM0_IN_1_LIMIT 0x1028
+#define NODE_ESRAM0_IN_2_LIMIT 0x102C
+#define NODE_ESRAM0_OUT_0_PRIORITY 0x1030
+
+#define NODE_ESRAM1_2_IN_0_PRIORITY 0x1400
+#define NODE_ESRAM1_2_IN_1_PRIORITY 0x1404
+#define NODE_ESRAM1_2_IN_2_PRIORITY 0x1408
+
+#define NODE_ESRAM1_2_IN_0_ARB_1_LIMIT 0x1424
+#define NODE_ESRAM1_2_IN_1_ARB_1_LIMIT 0x1428
+#define NODE_ESRAM1_2_IN_2_ARB_1_LIMIT 0x142C
+#define NODE_ESRAM1_2_OUT_0_PRIORITY 0x1430
+
+#define NODE_ESRAM3_4_IN_0_PRIORITY 0x1800
+#define NODE_ESRAM3_4_IN_1_PRIORITY 0x1804
+#define NODE_ESRAM3_4_IN_2_PRIORITY 0x1808
+
+#define NODE_ESRAM3_4_IN_0_ARB_1_LIMIT 0x1824
+#define NODE_ESRAM3_4_IN_1_ARB_1_LIMIT 0x1828
+#define NODE_ESRAM3_4_IN_2_ARB_1_LIMIT 0x182C
+#define NODE_ESRAM3_4_OUT_0_PRIORITY 0x1830
+
+/*
+ * Save ICN (Interconnect or Interconnect nodes) configuration registers
+ * TODO: This can be optimized, for example if we have
+ * a static ICN configuration.
+ */
+
+static struct {
+ void __iomem *base;
+ u32 hibw1_esram_in_pri[2];
+ u32 hibw1_esram_in0_arb[3];
+ u32 hibw1_esram_in1_arb[3];
+ u32 hibw1_ddr_in_prio[3];
+ u32 hibw1_ddr_in_limit[3];
+ u32 hibw1_ddr_out_prio_reg;
+
+ /* HiBw2 node registers */
+ u32 hibw2_esram_in_pri[2];
+ u32 hibw2_esram_in0_arblimit[3];
+ u32 hibw2_esram_in1_arblimit[3];
+ u32 hibw2_ddr_in_prio[3];
+ u32 hibw2_ddr_in_limit[3];
+ u32 hibw2_ddr_out_prio_reg;
+
+ /* ESRAM node registers */
+ u32 esram_in_prio[3];
+ u32 esram_in_lim[3];
+ u32 esram_out_prio_reg;
+
+ u32 esram12_in_prio[3];
+ u32 esram12_in_arb_lim[3];
+ u32 esram12_out_prio_reg;
+
+ u32 esram34_in_prio[3];
+ u32 esram34_in_arb_lim[3];
+ u32 esram34_out_prio;
+} context_icn;
+
+
+void u5500_context_save_icn(void)
+{
+ /* hibw1 */
+ context_icn.hibw1_esram_in_pri[0] =
+ readl(context_icn.base + NODE_HIBW1_ESRAM_IN_0_PRIORITY);
+ context_icn.hibw1_esram_in_pri[1] =
+ readl(context_icn.base + NODE_HIBW1_ESRAM_IN_1_PRIORITY);
+
+ context_icn.hibw1_esram_in0_arb[0] =
+ readl(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT);
+ context_icn.hibw1_esram_in0_arb[1] =
+ readl(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT);
+ context_icn.hibw1_esram_in0_arb[2] =
+ readl(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT);
+
+ context_icn.hibw1_esram_in1_arb[0] =
+ readl(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT);
+ context_icn.hibw1_esram_in1_arb[1] =
+ readl(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT);
+ context_icn.hibw1_esram_in1_arb[2] =
+ readl(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT);
+
+ context_icn.hibw1_ddr_in_prio[0] =
+ readl(context_icn.base + NODE_HIBW1_DDR_IN_0_PRIORITY);
+ context_icn.hibw1_ddr_in_prio[1] =
+ readl(context_icn.base + NODE_HIBW1_DDR_IN_1_PRIORITY);
+ context_icn.hibw1_ddr_in_prio[2] =
+ readl(context_icn.base + NODE_HIBW1_DDR_IN_2_PRIORITY);
+
+ context_icn.hibw1_ddr_in_limit[0] =
+ readl(context_icn.base + NODE_HIBW1_DDR_IN_0_LIMIT);
+ context_icn.hibw1_ddr_in_limit[1] =
+ readl(context_icn.base + NODE_HIBW1_DDR_IN_1_LIMIT);
+ context_icn.hibw1_ddr_in_limit[2] =
+ readl(context_icn.base + NODE_HIBW1_DDR_IN_2_LIMIT);
+
+ context_icn.hibw1_ddr_out_prio_reg =
+ readl(context_icn.base + NODE_HIBW1_DDR_OUT_0_PRIORITY);
+
+ /* hibw2 */
+ context_icn.hibw2_esram_in_pri[0] =
+ readl(context_icn.base + NODE_HIBW2_ESRAM_IN_0_PRIORITY);
+ context_icn.hibw2_esram_in_pri[1] =
+ readl(context_icn.base + NODE_HIBW2_ESRAM_IN_1_PRIORITY);
+
+ context_icn.hibw2_esram_in0_arblimit[0] =
+ readl(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT);
+ context_icn.hibw2_esram_in0_arblimit[1] =
+ readl(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT);
+ context_icn.hibw2_esram_in0_arblimit[2] =
+ readl(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT);
+
+ context_icn.hibw2_esram_in1_arblimit[0] =
+ readl(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT);
+ context_icn.hibw2_esram_in1_arblimit[1] =
+ readl(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT);
+ context_icn.hibw2_esram_in1_arblimit[2] =
+ readl(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT);
+
+ context_icn.hibw2_ddr_in_prio[0] =
+ readl(context_icn.base + NODE_HIBW2_DDR_IN_0_PRIORITY);
+ context_icn.hibw2_ddr_in_prio[1] =
+ readl(context_icn.base + NODE_HIBW2_DDR_IN_1_PRIORITY);
+ context_icn.hibw2_ddr_in_prio[2] =
+ readl(context_icn.base + NODE_HIBW2_DDR_IN_2_PRIORITY);
+
+ context_icn.hibw2_ddr_in_limit[0] =
+ readl(context_icn.base + NODE_HIBW2_DDR_IN_0_LIMIT);
+ context_icn.hibw2_ddr_in_limit[1] =
+ readl(context_icn.base + NODE_HIBW2_DDR_IN_1_LIMIT);
+ context_icn.hibw2_ddr_in_limit[2] =
+ readl(context_icn.base + NODE_HIBW2_DDR_IN_2_LIMIT);
+
+ context_icn.hibw2_ddr_out_prio_reg =
+ readl(context_icn.base + NODE_HIBW2_DDR_OUT_0_PRIORITY);
+
+ /* ESRAM0 */
+ context_icn.esram_in_prio[0] =
+ readl(context_icn.base + NODE_ESRAM0_IN_0_PRIORITY);
+ context_icn.esram_in_prio[1] =
+ readl(context_icn.base + NODE_ESRAM0_IN_1_PRIORITY);
+ context_icn.esram_in_prio[2] =
+ readl(context_icn.base + NODE_ESRAM0_IN_2_PRIORITY);
+
+ context_icn.esram_in_lim[0] =
+ readl(context_icn.base + NODE_ESRAM0_IN_0_LIMIT);
+ context_icn.esram_in_lim[1] =
+ readl(context_icn.base + NODE_ESRAM0_IN_1_LIMIT);
+ context_icn.esram_in_lim[2] =
+ readl(context_icn.base + NODE_ESRAM0_IN_2_LIMIT);
+
+ context_icn.esram_out_prio_reg =
+ readl(context_icn.base + NODE_ESRAM0_OUT_0_PRIORITY);
+
+ /* ESRAM1-2 */
+ context_icn.esram12_in_prio[0] =
+ readl(context_icn.base + NODE_ESRAM1_2_IN_0_PRIORITY);
+ context_icn.esram12_in_prio[1] =
+ readl(context_icn.base + NODE_ESRAM1_2_IN_1_PRIORITY);
+ context_icn.esram12_in_prio[2] =
+ readl(context_icn.base + NODE_ESRAM1_2_IN_2_PRIORITY);
+
+ context_icn.esram12_in_arb_lim[0] =
+ readl(context_icn.base + NODE_ESRAM1_2_IN_0_ARB_1_LIMIT);
+ context_icn.esram12_in_arb_lim[1] =
+ readl(context_icn.base + NODE_ESRAM1_2_IN_1_ARB_1_LIMIT);
+ context_icn.esram12_in_arb_lim[2] =
+ readl(context_icn.base + NODE_ESRAM1_2_IN_2_ARB_1_LIMIT);
+
+ context_icn.esram12_out_prio_reg =
+ readl(context_icn.base + NODE_ESRAM1_2_OUT_0_PRIORITY);
+
+ /* ESRAM3-4 */
+ context_icn.esram34_in_prio[0] =
+ readl(context_icn.base + NODE_ESRAM3_4_IN_0_PRIORITY);
+ context_icn.esram34_in_prio[1] =
+ readl(context_icn.base + NODE_ESRAM3_4_IN_1_PRIORITY);
+ context_icn.esram34_in_prio[2] =
+ readl(context_icn.base + NODE_ESRAM3_4_IN_2_PRIORITY);
+
+ context_icn.esram34_in_arb_lim[0] =
+ readl(context_icn.base + NODE_ESRAM3_4_IN_0_ARB_1_LIMIT);
+ context_icn.esram34_in_arb_lim[1] =
+ readl(context_icn.base + NODE_ESRAM3_4_IN_1_ARB_1_LIMIT);
+ context_icn.esram34_in_arb_lim[2] =
+ readl(context_icn.base + NODE_ESRAM3_4_IN_2_ARB_1_LIMIT);
+
+ context_icn.esram34_out_prio =
+ readl(context_icn.base + NODE_ESRAM3_4_OUT_0_PRIORITY);
+}
+
+/*
+ * Restore ICN configuration registers
+ */
+void u5500_context_restore_icn(void)
+{
+
+ /* hibw1 */
+ writel(context_icn.hibw1_esram_in_pri[0],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_0_PRIORITY);
+ writel(context_icn.hibw1_esram_in_pri[1],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_1_PRIORITY);
+
+ writel(context_icn.hibw1_esram_in0_arb[0],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT);
+ writel(context_icn.hibw1_esram_in0_arb[1],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT);
+ writel(context_icn.hibw1_esram_in0_arb[2],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT);
+
+ writel(context_icn.hibw1_esram_in1_arb[0],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT);
+ writel(context_icn.hibw1_esram_in1_arb[1],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT);
+ writel(context_icn.hibw1_esram_in1_arb[2],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT);
+
+ writel(context_icn.hibw1_ddr_in_prio[0],
+ context_icn.base + NODE_HIBW1_DDR_IN_0_PRIORITY);
+ writel(context_icn.hibw1_ddr_in_prio[1],
+ context_icn.base + NODE_HIBW1_DDR_IN_1_PRIORITY);
+ writel(context_icn.hibw1_ddr_in_prio[2],
+ context_icn.base + NODE_HIBW1_DDR_IN_2_PRIORITY);
+
+ writel(context_icn.hibw1_ddr_in_limit[0],
+ context_icn.base + NODE_HIBW1_DDR_IN_0_LIMIT);
+ writel(context_icn.hibw1_ddr_in_limit[1],
+ context_icn.base + NODE_HIBW1_DDR_IN_1_LIMIT);
+ writel(context_icn.hibw1_ddr_in_limit[2],
+ context_icn.base + NODE_HIBW1_DDR_IN_2_LIMIT);
+
+ writel(context_icn.hibw1_ddr_out_prio_reg,
+ context_icn.base + NODE_HIBW1_DDR_OUT_0_PRIORITY);
+
+ /* hibw2 */
+ writel(context_icn.hibw2_esram_in_pri[0],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_0_PRIORITY);
+ writel(context_icn.hibw2_esram_in_pri[1],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_1_PRIORITY);
+
+ writel(context_icn.hibw2_esram_in0_arblimit[0],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT);
+ writel(context_icn.hibw2_esram_in0_arblimit[1],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT);
+ writel(context_icn.hibw2_esram_in0_arblimit[2],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT);
+
+ writel(context_icn.hibw2_esram_in1_arblimit[0],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT);
+ writel(context_icn.hibw2_esram_in1_arblimit[1],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT);
+ writel(context_icn.hibw2_esram_in1_arblimit[2],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT);
+
+ writel(context_icn.hibw2_ddr_in_prio[0],
+ context_icn.base + NODE_HIBW2_DDR_IN_0_PRIORITY);
+ writel(context_icn.hibw2_ddr_in_prio[1],
+ context_icn.base + NODE_HIBW2_DDR_IN_1_PRIORITY);
+ writel(context_icn.hibw2_ddr_in_prio[2],
+ context_icn.base + NODE_HIBW2_DDR_IN_2_PRIORITY);
+
+ writel(context_icn.hibw2_ddr_in_limit[0],
+ context_icn.base + NODE_HIBW2_DDR_IN_0_LIMIT);
+ writel(context_icn.hibw2_ddr_in_limit[1],
+ context_icn.base + NODE_HIBW2_DDR_IN_1_LIMIT);
+ writel(context_icn.hibw2_ddr_in_limit[2],
+ context_icn.base + NODE_HIBW2_DDR_IN_2_LIMIT);
+
+ writel(context_icn.hibw2_ddr_out_prio_reg,
+ context_icn.base + NODE_HIBW2_DDR_OUT_0_PRIORITY);
+
+ /* ESRAM0 */
+ writel(context_icn.esram_in_prio[0],
+ context_icn.base + NODE_ESRAM0_IN_0_PRIORITY);
+ writel(context_icn.esram_in_prio[1],
+ context_icn.base + NODE_ESRAM0_IN_1_PRIORITY);
+ writel(context_icn.esram_in_prio[2],
+ context_icn.base + NODE_ESRAM0_IN_2_PRIORITY);
+
+ writel(context_icn.esram_in_lim[0],
+ context_icn.base + NODE_ESRAM0_IN_0_LIMIT);
+ writel(context_icn.esram_in_lim[1],
+ context_icn.base + NODE_ESRAM0_IN_1_LIMIT);
+ writel(context_icn.esram_in_lim[2],
+ context_icn.base + NODE_ESRAM0_IN_2_LIMIT);
+
+ writel(context_icn.esram_out_prio_reg,
+ context_icn.base + NODE_ESRAM0_OUT_0_PRIORITY);
+
+ /* ESRAM1-2 */
+ writel(context_icn.esram12_in_prio[0],
+ context_icn.base + NODE_ESRAM1_2_IN_0_PRIORITY);
+ writel(context_icn.esram12_in_prio[1],
+ context_icn.base + NODE_ESRAM1_2_IN_1_PRIORITY);
+ writel(context_icn.esram12_in_prio[2],
+ context_icn.base + NODE_ESRAM1_2_IN_2_PRIORITY);
+
+ writel(context_icn.esram12_in_arb_lim[0],
+ context_icn.base + NODE_ESRAM1_2_IN_0_ARB_1_LIMIT);
+ writel(context_icn.esram12_in_arb_lim[1],
+ context_icn.base + NODE_ESRAM1_2_IN_1_ARB_1_LIMIT);
+ writel(context_icn.esram12_in_arb_lim[2],
+ context_icn.base + NODE_ESRAM1_2_IN_2_ARB_1_LIMIT);
+
+ writel(context_icn.esram12_out_prio_reg,
+ context_icn.base + NODE_ESRAM1_2_OUT_0_PRIORITY);
+
+ /* ESRAM3-4 */
+ writel(context_icn.esram34_in_prio[0],
+ context_icn.base + NODE_ESRAM3_4_IN_0_PRIORITY);
+ writel(context_icn.esram34_in_prio[1],
+ context_icn.base + NODE_ESRAM3_4_IN_1_PRIORITY);
+ writel(context_icn.esram34_in_prio[2],
+ context_icn.base + NODE_ESRAM3_4_IN_2_PRIORITY);
+
+ writel(context_icn.esram34_in_arb_lim[0],
+ context_icn.base + NODE_ESRAM3_4_IN_0_ARB_1_LIMIT);
+ writel(context_icn.esram34_in_arb_lim[1],
+ context_icn.base + NODE_ESRAM3_4_IN_1_ARB_1_LIMIT);
+ writel(context_icn.esram34_in_arb_lim[2],
+ context_icn.base + NODE_ESRAM3_4_IN_2_ARB_1_LIMIT);
+
+ writel(context_icn.esram34_out_prio,
+ context_icn.base + NODE_ESRAM3_4_OUT_0_PRIORITY);
+
+}
+
+void u5500_context_init(void)
+{
+ context_icn.base = ioremap(U5500_ICN_BASE, SZ_4K);
+}
diff --git a/arch/arm/mach-ux500/context-db8500.c b/arch/arm/mach-ux500/context-db8500.c
new file mode 100644
index 00000000000..17bb5a02829
--- /dev/null
+++ b/arch/arm/mach-ux500/context-db8500.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ */
+
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+
+#include "context.h"
+
+/*
+ * ST-Interconnect context
+ */
+
+/* priority, bw limiter register offsets */
+#define NODE_HIBW1_ESRAM_IN_0_PRIORITY 0x00
+#define NODE_HIBW1_ESRAM_IN_1_PRIORITY 0x04
+#define NODE_HIBW1_ESRAM_IN_2_PRIORITY 0x08
+#define NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT 0x24
+#define NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT 0x28
+#define NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT 0x2C
+#define NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT 0x30
+#define NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT 0x34
+#define NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT 0x38
+#define NODE_HIBW1_ESRAM_IN_2_ARB_1_LIMIT 0x3C
+#define NODE_HIBW1_ESRAM_IN_2_ARB_2_LIMIT 0x40
+#define NODE_HIBW1_ESRAM_IN_2_ARB_3_LIMIT 0x44
+#define NODE_HIBW1_DDR_IN_0_PRIORITY 0x400
+#define NODE_HIBW1_DDR_IN_1_PRIORITY 0x404
+#define NODE_HIBW1_DDR_IN_2_PRIORITY 0x408
+#define NODE_HIBW1_DDR_IN_0_LIMIT 0x424
+#define NODE_HIBW1_DDR_IN_1_LIMIT 0x428
+#define NODE_HIBW1_DDR_IN_2_LIMIT 0x42C
+#define NODE_HIBW1_DDR_OUT_0_PRIORITY 0x430
+#define NODE_HIBW2_ESRAM_IN_0_PRIORITY 0x800
+#define NODE_HIBW2_ESRAM_IN_1_PRIORITY 0x804
+#define NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT 0x818
+#define NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT 0x81C
+#define NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT 0x820
+#define NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT 0x824
+#define NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT 0x828
+#define NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT 0x82C
+#define NODE_HIBW2_DDR_IN_0_PRIORITY 0xC00
+#define NODE_HIBW2_DDR_IN_1_PRIORITY 0xC04
+#define NODE_HIBW2_DDR_IN_2_PRIORITY 0xC08
+#define NODE_HIBW2_DDR_IN_3_PRIORITY 0xC0C
+#define NODE_HIBW2_DDR_IN_0_LIMIT 0xC30
+#define NODE_HIBW2_DDR_IN_1_LIMIT 0xC34
+#define NODE_ESRAM1_2_IN_0_PRIORITY 0x1400
+#define NODE_ESRAM1_2_IN_1_PRIORITY 0x1404
+#define NODE_ESRAM1_2_IN_2_PRIORITY 0x1408
+#define NODE_ESRAM1_2_IN_3_PRIORITY 0x140C
+#define NODE_ESRAM1_2_IN_0_ARB_1_LIMIT 0x1430
+#define NODE_ESRAM1_2_IN_0_ARB_2_LIMIT 0x1434
+#define NODE_ESRAM1_2_IN_1_ARB_1_LIMIT 0x1438
+#define NODE_ESRAM1_2_IN_1_ARB_2_LIMIT 0x143C
+#define NODE_ESRAM1_2_IN_2_ARB_1_LIMIT 0x1440
+#define NODE_ESRAM1_2_IN_2_ARB_2_LIMIT 0x1444
+#define NODE_ESRAM1_2_IN_3_ARB_1_LIMIT 0x1448
+#define NODE_ESRAM1_2_IN_3_ARB_2_LIMIT 0x144C
+#define NODE_ESRAM3_4_IN_0_PRIORITY 0x1800
+#define NODE_ESRAM3_4_IN_1_PRIORITY 0x1804
+#define NODE_ESRAM3_4_IN_2_PRIORITY 0x1808
+#define NODE_ESRAM3_4_IN_3_PRIORITY 0x180C
+#define NODE_ESRAM3_4_IN_0_ARB_1_LIMIT 0x1830
+#define NODE_ESRAM3_4_IN_0_ARB_2_LIMIT 0x1834
+#define NODE_ESRAM3_4_IN_1_ARB_1_LIMIT 0x1838
+#define NODE_ESRAM3_4_IN_1_ARB_2_LIMIT 0x183C
+#define NODE_ESRAM3_4_IN_2_ARB_1_LIMIT 0x1840
+#define NODE_ESRAM3_4_IN_2_ARB_2_LIMIT 0x1844
+#define NODE_ESRAM3_4_IN_3_ARB_1_LIMIT 0x1848
+#define NODE_ESRAM3_4_IN_3_ARB_2_LIMIT 0x184C
+
+static struct {
+ void __iomem *base;
+ u32 hibw1_esram_in_pri[3];
+ u32 hibw1_esram_in0_arb[3];
+ u32 hibw1_esram_in1_arb[3];
+ u32 hibw1_esram_in2_arb[3];
+ u32 hibw1_ddr_in_prio[3];
+ u32 hibw1_ddr_in_limit[3];
+ u32 hibw1_ddr_out_prio;
+
+ /* HiBw2 node registers */
+ u32 hibw2_esram_in_pri[2];
+ u32 hibw2_esram_in0_arblimit[3];
+ u32 hibw2_esram_in1_arblimit[3];
+ u32 hibw2_ddr_in_prio[4];
+ u32 hibw2_ddr_in_limit[4];
+ u32 hibw2_ddr_out_prio;
+
+ /* ESRAM node registers */
+ u32 esram_in_prio[4];
+ u32 esram_in_lim[4];
+ u32 esram12_in_prio[4];
+ u32 esram12_in_arb_lim[8];
+ u32 esram34_in_prio[4];
+ u32 esram34_in_arb_lim[8];
+} context_icn;
+
+/**
+ * u8500_context_save_icn() - save ICN context
+ *
+ */
+void u8500_context_save_icn(void)
+{
+
+ context_icn.hibw1_esram_in_pri[0] =
+ readb(context_icn.base + NODE_HIBW1_ESRAM_IN_0_PRIORITY);
+ context_icn.hibw1_esram_in_pri[1] =
+ readb(context_icn.base + NODE_HIBW1_ESRAM_IN_1_PRIORITY);
+ context_icn.hibw1_esram_in_pri[2] =
+ readb(context_icn.base + NODE_HIBW1_ESRAM_IN_2_PRIORITY);
+
+ context_icn.hibw1_esram_in0_arb[0] =
+ readb(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT);
+ context_icn.hibw1_esram_in0_arb[1] =
+ readb(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT);
+ context_icn.hibw1_esram_in0_arb[2] =
+ readb(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT);
+
+ context_icn.hibw1_esram_in1_arb[0] =
+ readb(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT);
+ context_icn.hibw1_esram_in1_arb[1] =
+ readb(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT);
+ context_icn.hibw1_esram_in1_arb[2] =
+ readb(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT);
+
+ context_icn.hibw1_esram_in2_arb[0] =
+ readb(context_icn.base + NODE_HIBW1_ESRAM_IN_2_ARB_1_LIMIT);
+ context_icn.hibw1_esram_in2_arb[1] =
+ readb(context_icn.base + NODE_HIBW1_ESRAM_IN_2_ARB_2_LIMIT);
+ context_icn.hibw1_esram_in2_arb[2] =
+ readb(context_icn.base + NODE_HIBW1_ESRAM_IN_2_ARB_3_LIMIT);
+
+ context_icn.hibw1_ddr_in_prio[0] =
+ readb(context_icn.base + NODE_HIBW1_DDR_IN_0_PRIORITY);
+ context_icn.hibw1_ddr_in_prio[1] =
+ readb(context_icn.base + NODE_HIBW1_DDR_IN_1_PRIORITY);
+ context_icn.hibw1_ddr_in_prio[2] =
+ readb(context_icn.base + NODE_HIBW1_DDR_IN_2_PRIORITY);
+
+ context_icn.hibw1_ddr_in_limit[0] =
+ readb(context_icn.base + NODE_HIBW1_DDR_IN_0_LIMIT);
+ context_icn.hibw1_ddr_in_limit[1] =
+ readb(context_icn.base + NODE_HIBW1_DDR_IN_1_LIMIT);
+ context_icn.hibw1_ddr_in_limit[2] =
+ readb(context_icn.base + NODE_HIBW1_DDR_IN_2_LIMIT);
+
+ context_icn.hibw1_ddr_out_prio =
+ readb(context_icn.base + NODE_HIBW1_DDR_OUT_0_PRIORITY);
+
+ context_icn.hibw2_esram_in_pri[0] =
+ readb(context_icn.base + NODE_HIBW2_ESRAM_IN_0_PRIORITY);
+ context_icn.hibw2_esram_in_pri[1] =
+ readb(context_icn.base + NODE_HIBW2_ESRAM_IN_1_PRIORITY);
+
+ context_icn.hibw2_esram_in0_arblimit[0] =
+ readb(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT);
+ context_icn.hibw2_esram_in0_arblimit[1] =
+ readb(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT);
+ context_icn.hibw2_esram_in0_arblimit[2] =
+ readb(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT);
+
+ context_icn.hibw2_esram_in1_arblimit[0] =
+ readb(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT);
+ context_icn.hibw2_esram_in1_arblimit[1] =
+ readb(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT);
+ context_icn.hibw2_esram_in1_arblimit[2] =
+ readb(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT);
+
+ context_icn.hibw2_ddr_in_prio[0] =
+ readb(context_icn.base + NODE_HIBW2_DDR_IN_0_PRIORITY);
+ context_icn.hibw2_ddr_in_prio[1] =
+ readb(context_icn.base + NODE_HIBW2_DDR_IN_1_PRIORITY);
+ context_icn.hibw2_ddr_in_prio[2] =
+ readb(context_icn.base + NODE_HIBW2_DDR_IN_2_PRIORITY);
+ context_icn.hibw2_ddr_in_prio[3] =
+ readb(context_icn.base + NODE_HIBW2_DDR_IN_3_PRIORITY);
+
+ context_icn.hibw2_ddr_in_limit[0] =
+ readb(context_icn.base + NODE_HIBW2_DDR_IN_0_LIMIT);
+ context_icn.hibw2_ddr_in_limit[1] =
+ readb(context_icn.base + NODE_HIBW2_DDR_IN_1_LIMIT);
+
+ context_icn.esram12_in_prio[0] =
+ readb(context_icn.base + NODE_ESRAM1_2_IN_0_PRIORITY);
+ context_icn.esram12_in_prio[1] =
+ readb(context_icn.base + NODE_ESRAM1_2_IN_1_PRIORITY);
+ context_icn.esram12_in_prio[2] =
+ readb(context_icn.base + NODE_ESRAM1_2_IN_2_PRIORITY);
+ context_icn.esram12_in_prio[3] =
+ readb(context_icn.base + NODE_ESRAM1_2_IN_3_PRIORITY);
+
+ context_icn.esram12_in_arb_lim[0] =
+ readb(context_icn.base + NODE_ESRAM1_2_IN_0_ARB_1_LIMIT);
+ context_icn.esram12_in_arb_lim[1] =
+ readb(context_icn.base + NODE_ESRAM1_2_IN_0_ARB_2_LIMIT);
+ context_icn.esram12_in_arb_lim[2] =
+ readb(context_icn.base + NODE_ESRAM1_2_IN_1_ARB_1_LIMIT);
+ context_icn.esram12_in_arb_lim[3] =
+ readb(context_icn.base + NODE_ESRAM1_2_IN_1_ARB_2_LIMIT);
+ context_icn.esram12_in_arb_lim[4] =
+ readb(context_icn.base + NODE_ESRAM1_2_IN_2_ARB_1_LIMIT);
+ context_icn.esram12_in_arb_lim[5] =
+ readb(context_icn.base + NODE_ESRAM1_2_IN_2_ARB_2_LIMIT);
+ context_icn.esram12_in_arb_lim[6] =
+ readb(context_icn.base + NODE_ESRAM1_2_IN_3_ARB_1_LIMIT);
+ context_icn.esram12_in_arb_lim[7] =
+ readb(context_icn.base + NODE_ESRAM1_2_IN_3_ARB_2_LIMIT);
+
+ context_icn.esram34_in_prio[0] =
+ readb(context_icn.base + NODE_ESRAM3_4_IN_0_PRIORITY);
+ context_icn.esram34_in_prio[1] =
+ readb(context_icn.base + NODE_ESRAM3_4_IN_1_PRIORITY);
+ context_icn.esram34_in_prio[2] =
+ readb(context_icn.base + NODE_ESRAM3_4_IN_2_PRIORITY);
+ context_icn.esram34_in_prio[3] =
+ readb(context_icn.base + NODE_ESRAM3_4_IN_3_PRIORITY);
+
+ context_icn.esram34_in_arb_lim[0] =
+ readb(context_icn.base + NODE_ESRAM3_4_IN_0_ARB_1_LIMIT);
+ context_icn.esram34_in_arb_lim[1] =
+ readb(context_icn.base + NODE_ESRAM3_4_IN_0_ARB_2_LIMIT);
+ context_icn.esram34_in_arb_lim[2] =
+ readb(context_icn.base + NODE_ESRAM3_4_IN_1_ARB_1_LIMIT);
+ context_icn.esram34_in_arb_lim[3] =
+ readb(context_icn.base + NODE_ESRAM3_4_IN_1_ARB_2_LIMIT);
+ context_icn.esram34_in_arb_lim[4] =
+ readb(context_icn.base + NODE_ESRAM3_4_IN_2_ARB_1_LIMIT);
+ context_icn.esram34_in_arb_lim[5] =
+ readb(context_icn.base + NODE_ESRAM3_4_IN_2_ARB_2_LIMIT);
+ context_icn.esram34_in_arb_lim[6] =
+ readb(context_icn.base + NODE_ESRAM3_4_IN_3_ARB_1_LIMIT);
+ context_icn.esram34_in_arb_lim[7] =
+ readb(context_icn.base + NODE_ESRAM3_4_IN_3_ARB_2_LIMIT);
+
+}
+
+/**
+ * u8500_context_restore_icn() - restore ICN context
+ *
+ */
+void u8500_context_restore_icn(void)
+{
+ writel(context_icn.hibw1_esram_in_pri[0],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_0_PRIORITY);
+ writel(context_icn.hibw1_esram_in_pri[1],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_1_PRIORITY);
+ writel(context_icn.hibw1_esram_in_pri[2],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_2_PRIORITY);
+
+ writel(context_icn.hibw1_esram_in0_arb[0],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT);
+ writel(context_icn.hibw1_esram_in0_arb[1],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT);
+ writel(context_icn.hibw1_esram_in0_arb[2],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT);
+
+ writel(context_icn.hibw1_esram_in1_arb[0],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT);
+ writel(context_icn.hibw1_esram_in1_arb[1],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT);
+ writel(context_icn.hibw1_esram_in1_arb[2],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT);
+
+ writel(context_icn.hibw1_esram_in2_arb[0],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_2_ARB_1_LIMIT);
+ writel(context_icn.hibw1_esram_in2_arb[1],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_2_ARB_2_LIMIT);
+ writel(context_icn.hibw1_esram_in2_arb[2],
+ context_icn.base + NODE_HIBW1_ESRAM_IN_2_ARB_3_LIMIT);
+
+ writel(context_icn.hibw1_ddr_in_prio[0],
+ context_icn.base + NODE_HIBW1_DDR_IN_0_PRIORITY);
+ writel(context_icn.hibw1_ddr_in_prio[1],
+ context_icn.base + NODE_HIBW1_DDR_IN_1_PRIORITY);
+ writel(context_icn.hibw1_ddr_in_prio[2],
+ context_icn.base + NODE_HIBW1_DDR_IN_2_PRIORITY);
+
+ writel(context_icn.hibw1_ddr_in_limit[0],
+ context_icn.base + NODE_HIBW1_DDR_IN_0_LIMIT);
+ writel(context_icn.hibw1_ddr_in_limit[1],
+ context_icn.base + NODE_HIBW1_DDR_IN_1_LIMIT);
+ writel(context_icn.hibw1_ddr_in_limit[2],
+ context_icn.base + NODE_HIBW1_DDR_IN_2_LIMIT);
+
+ writel(context_icn.hibw1_ddr_out_prio,
+ context_icn.base + NODE_HIBW1_DDR_OUT_0_PRIORITY);
+
+ writel(context_icn.hibw2_esram_in_pri[0],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_0_PRIORITY);
+ writel(context_icn.hibw2_esram_in_pri[1],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_1_PRIORITY);
+
+ writel(context_icn.hibw2_esram_in0_arblimit[0],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT);
+ writel(context_icn.hibw2_esram_in0_arblimit[1],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT);
+ writel(context_icn.hibw2_esram_in0_arblimit[2],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT);
+
+ writel(context_icn.hibw2_esram_in1_arblimit[0],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT);
+ writel(context_icn.hibw2_esram_in1_arblimit[1],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT);
+ writel(context_icn.hibw2_esram_in1_arblimit[2],
+ context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT);
+
+ writel(context_icn.hibw2_ddr_in_prio[0],
+ context_icn.base + NODE_HIBW2_DDR_IN_0_PRIORITY);
+ writel(context_icn.hibw2_ddr_in_prio[1],
+ context_icn.base + NODE_HIBW2_DDR_IN_1_PRIORITY);
+ writel(context_icn.hibw2_ddr_in_prio[2],
+ context_icn.base + NODE_HIBW2_DDR_IN_2_PRIORITY);
+ writel(context_icn.hibw2_ddr_in_prio[3],
+ context_icn.base + NODE_HIBW2_DDR_IN_3_PRIORITY);
+
+ writel(context_icn.hibw2_ddr_in_limit[0],
+ context_icn.base + NODE_HIBW2_DDR_IN_0_LIMIT);
+ writel(context_icn.hibw2_ddr_in_limit[1],
+ context_icn.base + NODE_HIBW2_DDR_IN_1_LIMIT);
+
+ writel(context_icn.esram12_in_prio[0],
+ context_icn.base + NODE_ESRAM1_2_IN_0_PRIORITY);
+ writel(context_icn.esram12_in_prio[1],
+ context_icn.base + NODE_ESRAM1_2_IN_1_PRIORITY);
+ writel(context_icn.esram12_in_prio[2],
+ context_icn.base + NODE_ESRAM1_2_IN_2_PRIORITY);
+ writel(context_icn.esram12_in_prio[3],
+ context_icn.base + NODE_ESRAM1_2_IN_3_PRIORITY);
+
+ writel(context_icn.esram12_in_arb_lim[0],
+ context_icn.base + NODE_ESRAM1_2_IN_0_ARB_1_LIMIT);
+ writel(context_icn.esram12_in_arb_lim[1],
+ context_icn.base + NODE_ESRAM1_2_IN_0_ARB_2_LIMIT);
+ writel(context_icn.esram12_in_arb_lim[2],
+ context_icn.base + NODE_ESRAM1_2_IN_1_ARB_1_LIMIT);
+ writel(context_icn.esram12_in_arb_lim[3],
+ context_icn.base + NODE_ESRAM1_2_IN_1_ARB_2_LIMIT);
+ writel(context_icn.esram12_in_arb_lim[4],
+ context_icn.base + NODE_ESRAM1_2_IN_2_ARB_1_LIMIT);
+ writel(context_icn.esram12_in_arb_lim[5],
+ context_icn.base + NODE_ESRAM1_2_IN_2_ARB_2_LIMIT);
+ writel(context_icn.esram12_in_arb_lim[6],
+ context_icn.base + NODE_ESRAM1_2_IN_3_ARB_1_LIMIT);
+ writel(context_icn.esram12_in_arb_lim[7],
+ context_icn.base + NODE_ESRAM1_2_IN_3_ARB_2_LIMIT);
+
+ writel(context_icn.esram34_in_prio[0],
+ context_icn.base + NODE_ESRAM3_4_IN_0_PRIORITY);
+ writel(context_icn.esram34_in_prio[1],
+ context_icn.base + NODE_ESRAM3_4_IN_1_PRIORITY);
+ writel(context_icn.esram34_in_prio[2],
+ context_icn.base + NODE_ESRAM3_4_IN_2_PRIORITY);
+ writel(context_icn.esram34_in_prio[3],
+ context_icn.base + NODE_ESRAM3_4_IN_3_PRIORITY);
+
+ writel(context_icn.esram34_in_arb_lim[0],
+ context_icn.base + NODE_ESRAM3_4_IN_0_ARB_1_LIMIT);
+ writel(context_icn.esram34_in_arb_lim[1],
+ context_icn.base + NODE_ESRAM3_4_IN_0_ARB_2_LIMIT);
+ writel(context_icn.esram34_in_arb_lim[2],
+ context_icn.base + NODE_ESRAM3_4_IN_1_ARB_1_LIMIT);
+ writel(context_icn.esram34_in_arb_lim[3],
+ context_icn.base + NODE_ESRAM3_4_IN_1_ARB_2_LIMIT);
+ writel(context_icn.esram34_in_arb_lim[4],
+ context_icn.base + NODE_ESRAM3_4_IN_2_ARB_1_LIMIT);
+ writel(context_icn.esram34_in_arb_lim[5],
+ context_icn.base + NODE_ESRAM3_4_IN_2_ARB_2_LIMIT);
+ writel(context_icn.esram34_in_arb_lim[6],
+ context_icn.base + NODE_ESRAM3_4_IN_3_ARB_1_LIMIT);
+ writel(context_icn.esram34_in_arb_lim[7],
+ context_icn.base + NODE_ESRAM3_4_IN_3_ARB_2_LIMIT);
+
+}
+
+void u8500_context_init(void)
+{
+ context_icn.base = ioremap(U8500_ICN_BASE, SZ_8K);
+}
diff --git a/arch/arm/mach-ux500/context.c b/arch/arm/mach-ux500/context.c
new file mode 100644
index 00000000000..220afc636de
--- /dev/null
+++ b/arch/arm/mach-ux500/context.c
@@ -0,0 +1,975 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>,
+ * Rickard Andersson <rickard.andersson@stericsson.com>,
+ * Jonas Aaberg <jonas.aberg@stericsson.com>,
+ * Sundar Iyer <sundar.iyer@stericsson.com> for
+ * ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/smp.h>
+#include <linux/percpu.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/notifier.h>
+#include <linux/amba/serial.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/scu.h>
+#include <mach/gpio.h>
+
+#include "context.h"
+
+/*
+ * TODO:
+ * - Use the "UX500*"-macros instead where possible
+ * - Check what is saved during apsleep and deepsleep of gpio.
+ */
+
+#define U8500_BACKUPRAM_SIZE SZ_64K
+
+/* Special dedicated addresses in backup RAM */
+#define U8500_EXT_RAM_LOC_BACKUPRAM_ADDR 0x80151FDC
+#define U8500_CPU0_CP15_CR_BACKUPRAM_ADDR 0x80151F80
+#define U8500_CPU1_CP15_CR_BACKUPRAM_ADDR 0x80151FA0
+#define U8500_CPU0_BACKUPRAM_LOG_ADDR_BACKUPRAM_ADDR 0x80151FD8
+#define U8500_CPU1_BACKUPRAM_LOG_ADDR_BACKUPRAM_ADDR 0x80151FE0
+
+#define GIC_DIST_ENABLE_NS 0x0
+
+/* 32 interrupts fits in 4 bytes */
+#define GIC_DIST_ENABLE_SET_COMMON_NUM ((DBX500_NR_INTERNAL_IRQS - \
+ IRQ_SHPI_START) / 32)
+#define GIC_DIST_ENABLE_SET_CPU_NUM (IRQ_SHPI_START / 32)
+#define GIC_DIST_ENABLE_SET_SPI0 GIC_DIST_ENABLE_SET
+#define GIC_DIST_ENABLE_SET_SPI32 (GIC_DIST_ENABLE_SET + IRQ_SHPI_START / 8)
+
+#define GIC_DIST_PRI_COMMON_NUM ((DBX500_NR_INTERNAL_IRQS - IRQ_SHPI_START) / 4)
+#define GIC_DIST_PRI_CPU_NUM (IRQ_SHPI_START / 4)
+#define GIC_DIST_PRI_SPI0 GIC_DIST_PRI
+#define GIC_DIST_PRI_SPI32 (GIC_DIST_PRI + IRQ_SHPI_START)
+
+#define GIC_DIST_SPI_TARGET_COMMON_NUM ((DBX500_NR_INTERNAL_IRQS - \
+ IRQ_SHPI_START) / 4)
+#define GIC_DIST_SPI_TARGET_CPU_NUM (IRQ_SHPI_START / 4)
+#define GIC_DIST_SPI_TARGET_SPI0 GIC_DIST_TARGET
+#define GIC_DIST_SPI_TARGET_SPI32 (GIC_DIST_TARGET + IRQ_SHPI_START)
+
+/* 16 interrupts per 4 bytes */
+#define GIC_DIST_CONFIG_COMMON_NUM ((DBX500_NR_INTERNAL_IRQS - IRQ_SHPI_START) \
+ / 16)
+#define GIC_DIST_CONFIG_CPU_NUM (IRQ_SHPI_START / 16)
+#define GIC_DIST_CONFIG_SPI0 GIC_DIST_CONFIG
+#define GIC_DIST_CONFIG_SPI32 (GIC_DIST_CONFIG + IRQ_SHPI_START / 4)
+
+/* TODO! Move STM reg offsets to suitable place */
+#define STM_CR_OFFSET 0x00
+#define STM_MMC_OFFSET 0x08
+#define STM_TER_OFFSET 0x10
+
+#define TPIU_PORT_SIZE 0x4
+#define TPIU_TRIGGER_COUNTER 0x104
+#define TPIU_TRIGGER_MULTIPLIER 0x108
+#define TPIU_CURRENT_TEST_PATTERN 0x204
+#define TPIU_TEST_PATTERN_REPEAT 0x208
+#define TPIU_FORMATTER 0x304
+#define TPIU_FORMATTER_SYNC 0x308
+#define TPIU_LOCK_ACCESS_REGISTER 0xFB0
+
+#define TPIU_UNLOCK_CODE 0xc5acce55
+
+#define SCU_FILTER_STARTADDR 0x40
+#define SCU_FILTER_ENDADDR 0x44
+#define SCU_ACCESS_CTRL_SAC 0x50
+
+/*
+ * Periph clock cluster context
+ */
+#define PRCC_BCK_EN 0x00
+#define PRCC_KCK_EN 0x08
+#define PRCC_BCK_STATUS 0x10
+#define PRCC_KCK_STATUS 0x14
+
+/* The context of the Trace Port Interface Unit (TPIU) */
+static struct {
+ void __iomem *base;
+ u32 port_size;
+ u32 trigger_counter;
+ u32 trigger_multiplier;
+ u32 current_test_pattern;
+ u32 test_pattern_repeat;
+ u32 formatter;
+ u32 formatter_sync;
+} context_tpiu;
+
+static struct {
+ void __iomem *base;
+ u32 cr;
+ u32 mmc;
+ u32 ter;
+} context_stm_ape;
+
+struct context_gic_cpu {
+ void __iomem *base;
+ u32 ctrl;
+ u32 primask;
+ u32 binpoint;
+};
+static DEFINE_PER_CPU(struct context_gic_cpu, context_gic_cpu);
+
+static struct {
+ void __iomem *base;
+ u32 ns;
+ u32 enable_set[GIC_DIST_ENABLE_SET_COMMON_NUM]; /* IRQ 32 to 160 */
+ u32 priority_level[GIC_DIST_PRI_COMMON_NUM];
+ u32 spi_target[GIC_DIST_SPI_TARGET_COMMON_NUM];
+ u32 config[GIC_DIST_CONFIG_COMMON_NUM];
+} context_gic_dist_common;
+
+struct context_gic_dist_cpu {
+ void __iomem *base;
+ u32 enable_set[GIC_DIST_ENABLE_SET_CPU_NUM]; /* IRQ 0 to 31 */
+ u32 priority_level[GIC_DIST_PRI_CPU_NUM];
+ u32 spi_target[GIC_DIST_SPI_TARGET_CPU_NUM];
+ u32 config[GIC_DIST_CONFIG_CPU_NUM];
+};
+static DEFINE_PER_CPU(struct context_gic_dist_cpu, context_gic_dist_cpu);
+
+#define UX500_NR_GPIO_BANKS 8
+
+static struct {
+ void __iomem *base;
+ u32 dat;
+ /* dat_set */
+ /* dat_clr */
+ u32 pdis;
+ u32 dir;
+ /* dir_set */
+ /* dir_clr */
+ u32 slpm;
+ u32 altfunc_a;
+ u32 altfunc_b;
+ u32 rimsc;
+ u32 fsmsc;
+ /* int_status */
+ /* int_clr */
+ u32 rwmsc;
+ u32 fwmsc;
+ /* wks */
+} context_gpio[UX500_NR_GPIO_BANKS];
+
+static struct {
+ void __iomem *base;
+ u32 ctrl;
+ u32 cpu_pwrstatus;
+ u32 inv_all_nonsecure;
+ u32 filter_start_addr;
+ u32 filter_end_addr;
+ u32 access_ctrl_sac;
+} context_scu;
+
+#define UX500_NR_PRCC_BANKS 5
+static struct {
+ void __iomem *base;
+ u32 bus_clk;
+ u32 kern_clk;
+} context_prcc[UX500_NR_PRCC_BANKS];
+
+#define UX500_NR_UARTS 3
+static struct {
+ void __iomem *base;
+ /* dr */
+ /* rsr_err */
+ u32 dma_wm;
+ u32 timeout;
+ /* fr */
+ u32 lcrh_rx;
+ u32 ilpr;
+ u32 ibrd;
+ u32 fbrd;
+ u32 lcrh_tx;
+ u32 cr;
+ u32 ifls;
+ u32 imsc;
+ /* ris */
+ /* mis */
+ /* icr */
+ u32 dmacr;
+ u32 xfcr;
+ u32 xon1;
+ u32 xon2;
+ u32 xoff1;
+ u32 xoff2;
+ u32 itcr;
+ u32 itip;
+ /* itop */
+ /* tdr */
+ u32 abcr;
+ /* absr */
+ /* abfmt */
+ /* abdr */
+ /* abdfr */
+ /* abmr */
+ u32 abimsc;
+ /* abris */
+ /* abmis */
+ /* abicr */
+ /* id_product_h_xy */
+ /* id_provider */
+ /* periphid0 */
+ /* periphid1 */
+ /* periphid2 */
+ /* periphid3 */
+ /* pcellid0 */
+ /* pcellid1 */
+ /* pcellid2 */
+ /* pcellid3 */
+} context_uart[UX500_NR_UARTS];
+
+static u32 backup_sram_storage[NR_CPUS] = {
+ IO_ADDRESS(U8500_CPU0_CP15_CR_BACKUPRAM_ADDR),
+ IO_ADDRESS(U8500_CPU1_CP15_CR_BACKUPRAM_ADDR),
+};
+
+/*
+ * Stacks and stack pointers
+ */
+static DEFINE_PER_CPU(u32, varm_core_backup_stack[1024]);
+static DEFINE_PER_CPU(u32 *, varm_core_pointer);
+
+static ATOMIC_NOTIFIER_HEAD(context_notifier_list);
+
+/* UART2(console) context */
+static void __iomem *uart_backup_base, *uart_register_base;
+
+/**
+ * ux500_save_uart_context() - save uart2 (console) context
+ *
+ */
+void ux500_save_uart_context(void)
+{
+ /* FIXME : blind memcpy must be replaced */
+ memcpy(uart_backup_base, uart_register_base, SZ_4K);
+ return;
+}
+
+/**
+ * ux500_restore_uart_context() - restore uart2 (console) context
+ *
+ */
+void ux500_restore_uart_context(void)
+{
+ memcpy(uart_register_base, uart_backup_base, SZ_4K);
+ return;
+}
+
+/*
+ * Register a simple callback for handling context save/restore
+ */
+int context_notifier_register(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&context_notifier_list, nb);
+}
+EXPORT_SYMBOL(context_notifier_register);
+
+/*
+ * Remove a previously registered callback
+ */
+int context_notifier_unregister(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&context_notifier_list, nb);
+}
+EXPORT_SYMBOL(context_notifier_unregister);
+
+static void save_uart(void)
+{
+ int i;
+
+ for (i = 0; i < UX500_NR_UARTS; i++) {
+ context_uart[i].dma_wm =
+ readl(context_uart[i].base + ST_UART011_DMAWM);
+ context_uart[i].timeout =
+ readl(context_uart[i].base + ST_UART011_TIMEOUT);
+ context_uart[i].lcrh_rx =
+ readl(context_uart[i].base + ST_UART011_LCRH_RX);
+ context_uart[i].ilpr =
+ readl(context_uart[i].base + UART01x_ILPR);
+ context_uart[i].ibrd =
+ readl(context_uart[i].base + UART011_IBRD);
+ context_uart[i].fbrd =
+ readl(context_uart[i].base + UART011_FBRD);
+ context_uart[i].lcrh_tx =
+ readl(context_uart[i].base + ST_UART011_LCRH_TX);
+ context_uart[i].cr =
+ readl(context_uart[i].base + UART011_CR);
+ context_uart[i].ifls =
+ readl(context_uart[i].base + UART011_IFLS);
+ context_uart[i].imsc =
+ readl(context_uart[i].base + UART011_IMSC);
+ context_uart[i].dmacr =
+ readl(context_uart[i].base + UART011_DMACR);
+ context_uart[i].xfcr =
+ readl(context_uart[i].base + ST_UART011_XFCR);
+ context_uart[i].xon1 =
+ readl(context_uart[i].base + ST_UART011_XON1);
+ context_uart[i].xon2 =
+ readl(context_uart[i].base + ST_UART011_XON2);
+ context_uart[i].xoff1 =
+ readl(context_uart[i].base + ST_UART011_XOFF1);
+ context_uart[i].xoff2 =
+ readl(context_uart[i].base + ST_UART011_XOFF2);
+ context_uart[i].itcr =
+ readl(context_uart[i].base + ST_UART011_ITCR);
+ context_uart[i].itip =
+ readl(context_uart[i].base + ST_UART011_ITIP);
+ context_uart[i].abcr =
+ readl(context_uart[i].base + ST_UART011_ABCR);
+ context_uart[i].abimsc =
+ readl(context_uart[i].base + ST_UART011_ABIMSC);
+ }
+}
+
+static void restore_uart(void)
+{
+ int i;
+
+ for (i = 0; i < UX500_NR_UARTS; i++) {
+ writel(context_uart[i].dma_wm,
+ context_uart[i].base + ST_UART011_DMAWM);
+ writel(context_uart[i].timeout,
+ context_uart[i].base + ST_UART011_TIMEOUT);
+ writel(context_uart[i].lcrh_rx,
+ context_uart[i].base + ST_UART011_LCRH_RX);
+ writel(context_uart[i].ilpr,
+ context_uart[i].base + UART01x_ILPR);
+ writel(context_uart[i].ibrd,
+ context_uart[i].base + UART011_IBRD);
+ writel(context_uart[i].fbrd,
+ context_uart[i].base + UART011_FBRD);
+ writel(context_uart[i].lcrh_tx,
+ context_uart[i].base + ST_UART011_LCRH_TX);
+ writel(context_uart[i].cr,
+ context_uart[i].base + UART011_CR);
+ writel(context_uart[i].ifls,
+ context_uart[i].base + UART011_IFLS);
+ writel(context_uart[i].imsc,
+ context_uart[i].base + UART011_IMSC);
+ writel(context_uart[i].dmacr,
+ context_uart[i].base + UART011_DMACR);
+ writel(context_uart[i].xfcr,
+ context_uart[i].base + ST_UART011_XFCR);
+ writel(context_uart[i].xon1,
+ context_uart[i].base + ST_UART011_XON1);
+ writel(context_uart[i].xon2,
+ context_uart[i].base + ST_UART011_XON2);
+ writel(context_uart[i].xoff1,
+ context_uart[i].base + ST_UART011_XOFF1);
+ writel(context_uart[i].xoff2,
+ context_uart[i].base + ST_UART011_XOFF2);
+ writel(context_uart[i].itcr,
+ context_uart[i].base + ST_UART011_ITCR);
+ writel(context_uart[i].itip,
+ context_uart[i].base + ST_UART011_ITIP);
+ writel(context_uart[i].abcr,
+ context_uart[i].base + ST_UART011_ABCR);
+ writel(context_uart[i].abimsc,
+ context_uart[i].base + ST_UART011_ABIMSC);
+ }
+}
+
+static void save_prcc(void)
+{
+ int i;
+
+ for (i = 0; i < UX500_NR_PRCC_BANKS; i++) {
+ context_prcc[i].bus_clk =
+ readl(context_prcc[i].base + PRCC_BCK_STATUS);
+ context_prcc[i].kern_clk =
+ readl(context_prcc[i].base + PRCC_KCK_STATUS);
+ }
+}
+
+static void restore_prcc(void)
+{
+ int i;
+
+ for (i = 0; i < UX500_NR_PRCC_BANKS; i++) {
+ writel(context_prcc[i].bus_clk,
+ context_prcc[i].base + PRCC_BCK_EN);
+ writel(context_prcc[i].kern_clk,
+ context_prcc[i].base + PRCC_KCK_EN);
+ }
+}
+
+static void save_stm_ape(void)
+{
+ /*
+ * TODO: Check with PRCMU developers how STM is handled by PRCMU
+ * firmware. According to DB5500 design spec there is a "flush"
+ * mechanism supposed to be used by the PRCMU before power down,
+ * PRCMU fw might save/restore the following three registers
+ * at the same time.
+ */
+ context_stm_ape.cr = readl(context_stm_ape.base +
+ STM_CR_OFFSET);
+ context_stm_ape.mmc = readl(context_stm_ape.base +
+ STM_MMC_OFFSET);
+ context_stm_ape.ter = readl(context_stm_ape.base +
+ STM_TER_OFFSET);
+}
+
+static void restore_stm_ape(void)
+{
+ writel(context_stm_ape.ter,
+ context_stm_ape.base + STM_TER_OFFSET);
+ writel(context_stm_ape.mmc,
+ context_stm_ape.base + STM_MMC_OFFSET);
+ writel(context_stm_ape.cr,
+ context_stm_ape.base + STM_CR_OFFSET);
+}
+
+/*
+ * Save the context of the Trace Port Interface Unit (TPIU).
+ * Saving/restoring is needed for the PTM tracing to work together
+ * with the sleep states ApSleep and ApDeepSleep.
+ */
+static void save_tpiu(void)
+{
+ context_tpiu.port_size = readl(context_tpiu.base +
+ TPIU_PORT_SIZE);
+ context_tpiu.trigger_counter = readl(context_tpiu.base +
+ TPIU_TRIGGER_COUNTER);
+ context_tpiu.trigger_multiplier = readl(context_tpiu.base +
+ TPIU_TRIGGER_MULTIPLIER);
+ context_tpiu.current_test_pattern = readl(context_tpiu.base +
+ TPIU_CURRENT_TEST_PATTERN);
+ context_tpiu.test_pattern_repeat = readl(context_tpiu.base +
+ TPIU_TEST_PATTERN_REPEAT);
+ context_tpiu.formatter = readl(context_tpiu.base +
+ TPIU_FORMATTER);
+ context_tpiu.formatter_sync = readl(context_tpiu.base +
+ TPIU_FORMATTER_SYNC);
+}
+
+/*
+ * Restore the context of the Trace Port Interface Unit (TPIU).
+ * Saving/restoring is needed for the PTM tracing to work together
+ * with the sleep states ApSleep and ApDeepSleep.
+ */
+static void restore_tpiu(void)
+{
+ writel(TPIU_UNLOCK_CODE,
+ context_tpiu.base + TPIU_LOCK_ACCESS_REGISTER);
+
+ writel(context_tpiu.port_size,
+ context_tpiu.base + TPIU_PORT_SIZE);
+ writel(context_tpiu.trigger_counter,
+ context_tpiu.base + TPIU_TRIGGER_COUNTER);
+ writel(context_tpiu.trigger_multiplier,
+ context_tpiu.base + TPIU_TRIGGER_MULTIPLIER);
+ writel(context_tpiu.current_test_pattern,
+ context_tpiu.base + TPIU_CURRENT_TEST_PATTERN);
+ writel(context_tpiu.test_pattern_repeat,
+ context_tpiu.base + TPIU_TEST_PATTERN_REPEAT);
+ writel(context_tpiu.formatter,
+ context_tpiu.base + TPIU_FORMATTER);
+ writel(context_tpiu.formatter_sync,
+ context_tpiu.base + TPIU_FORMATTER_SYNC);
+}
+
+/*
+ * Save GIC CPU IF registers
+ *
+ * This is per cpu so it needs to be called for each one.
+ */
+
+static void save_gic_if_cpu(struct context_gic_cpu *c_gic_cpu)
+{
+ c_gic_cpu->ctrl = readl(c_gic_cpu->base + GIC_CPU_CTRL);
+ c_gic_cpu->primask = readl(c_gic_cpu->base + GIC_CPU_PRIMASK);
+ c_gic_cpu->binpoint = readl(c_gic_cpu->base + GIC_CPU_BINPOINT);
+}
+
+/*
+ * Restore GIC CPU IF registers
+ *
+ * This is per cpu so it needs to be called for each one.
+ */
+static void restore_gic_if_cpu(struct context_gic_cpu *c_gic_cpu)
+{
+ writel(c_gic_cpu->ctrl, c_gic_cpu->base + GIC_CPU_CTRL);
+ writel(c_gic_cpu->primask, c_gic_cpu->base + GIC_CPU_PRIMASK);
+ writel(c_gic_cpu->binpoint, c_gic_cpu->base + GIC_CPU_BINPOINT);
+}
+
+/*
+ * Save GIC Distributor Common registers
+ *
+ * This context is common. Only one CPU needs to call.
+ *
+ * Save SPI (Shared Peripheral Interrupt) settings, IRQ 32-159.
+ */
+
+static void save_gic_dist_common(void)
+{
+ int i;
+
+ context_gic_dist_common.ns = readl(context_gic_dist_common.base +
+ GIC_DIST_ENABLE_NS);
+
+ for (i = 0; i < GIC_DIST_ENABLE_SET_COMMON_NUM; i++)
+ context_gic_dist_common.enable_set[i] =
+ readl(context_gic_dist_common.base +
+ GIC_DIST_ENABLE_SET_SPI32 + i * 4);
+
+ for (i = 0; i < GIC_DIST_PRI_COMMON_NUM; i++)
+ context_gic_dist_common.priority_level[i] =
+ readl(context_gic_dist_common.base +
+ GIC_DIST_PRI_SPI32 + i * 4);
+
+ for (i = 0; i < GIC_DIST_SPI_TARGET_COMMON_NUM; i++)
+ context_gic_dist_common.spi_target[i] =
+ readl(context_gic_dist_common.base +
+ GIC_DIST_SPI_TARGET_SPI32 + i * 4);
+
+ for (i = 0; i < GIC_DIST_CONFIG_COMMON_NUM; i++)
+ context_gic_dist_common.spi_target[i] =
+ readl(context_gic_dist_common.base +
+ GIC_DIST_CONFIG_SPI32 + i * 4);
+}
+
+/*
+ * Restore GIC Distributor Common registers
+ *
+ * This context is common. Only one CPU needs to call.
+ *
+ * Save SPI (Shared Peripheral Interrupt) settings, IRQ 32-159.
+ */
+static void restore_gic_dist_common(void)
+{
+
+ int i;
+
+ for (i = 0; i < GIC_DIST_CONFIG_COMMON_NUM; i++)
+ writel(context_gic_dist_common.spi_target[i],
+ context_gic_dist_common.base +
+ GIC_DIST_CONFIG_SPI32 + i * 4);
+
+ for (i = 0; i < GIC_DIST_SPI_TARGET_COMMON_NUM; i++)
+ writel(context_gic_dist_common.spi_target[i],
+ context_gic_dist_common.base +
+ GIC_DIST_SPI_TARGET_SPI32 + i * 4);
+
+ for (i = 0; i < GIC_DIST_PRI_COMMON_NUM; i++)
+ writel(context_gic_dist_common.priority_level[i],
+ context_gic_dist_common.base +
+ GIC_DIST_PRI_SPI32 + i * 4);
+
+ for (i = 0; i < GIC_DIST_ENABLE_SET_COMMON_NUM; i++)
+ writel(context_gic_dist_common.enable_set[i],
+ context_gic_dist_common.base +
+ GIC_DIST_ENABLE_SET_SPI32 + i * 4);
+
+ writel(context_gic_dist_common.ns,
+ context_gic_dist_common.base + GIC_DIST_ENABLE_NS);
+}
+
+
+
+/*
+ * Save GIC Dist CPU registers
+ *
+ * This needs to be called by all cpu:s which will not call
+ * save_gic_dist_common(). Only the registers of the GIC which are
+ * banked will be saved.
+ */
+static void save_gic_dist_cpu(struct context_gic_dist_cpu *c_gic)
+{
+ int i;
+
+ for (i = 0; i < GIC_DIST_ENABLE_SET_CPU_NUM; i++)
+ c_gic->enable_set[i] =
+ readl(c_gic->base +
+ GIC_DIST_ENABLE_SET_SPI0 + i * 4);
+
+ for (i = 0; i < GIC_DIST_PRI_CPU_NUM; i++)
+ c_gic->priority_level[i] =
+ readl(c_gic->base +
+ GIC_DIST_PRI_SPI0 + i * 4);
+
+ for (i = 0; i < GIC_DIST_SPI_TARGET_CPU_NUM; i++)
+ c_gic->spi_target[i] =
+ readl(c_gic->base +
+ GIC_DIST_SPI_TARGET_SPI0 + i * 4);
+
+ for (i = 0; i < GIC_DIST_CONFIG_CPU_NUM; i++)
+ c_gic->spi_target[i] =
+ readl(c_gic->base +
+ GIC_DIST_CONFIG_SPI0 + i * 4);
+}
+
+/*
+ * Restore GIC Dist CPU registers
+ *
+ * This needs to be called by all cpu:s which will not call
+ * restore_gic_dist_common(). Only the registers of the GIC which are
+ * banked will be saved.
+ */
+static void restore_gic_dist_cpu(struct context_gic_dist_cpu *c_gic)
+{
+
+ int i;
+
+ for (i = 0; i < GIC_DIST_CONFIG_CPU_NUM; i++)
+ writel(c_gic->spi_target[i],
+ c_gic->base +
+ GIC_DIST_CONFIG_SPI0 + i * 4);
+
+ for (i = 0; i < GIC_DIST_SPI_TARGET_CPU_NUM; i++)
+ writel(c_gic->spi_target[i],
+ c_gic->base +
+ GIC_DIST_SPI_TARGET_SPI0 + i * 4);
+
+ for (i = 0; i < GIC_DIST_PRI_CPU_NUM; i++)
+ writel(c_gic->priority_level[i],
+ c_gic->base +
+ GIC_DIST_PRI_SPI0 + i * 4);
+
+ for (i = 0; i < GIC_DIST_ENABLE_SET_CPU_NUM; i++)
+ writel(c_gic->enable_set[i],
+ c_gic->base +
+ GIC_DIST_ENABLE_SET_SPI0 + i * 4);
+}
+static void save_scu(void)
+{
+ context_scu.ctrl =
+ readl(context_scu.base + SCU_CTRL);
+ context_scu.cpu_pwrstatus =
+ readl(context_scu.base + SCU_CPU_STATUS);
+ context_scu.inv_all_nonsecure =
+ readl(context_scu.base + SCU_INVALIDATE);
+ context_scu.filter_start_addr =
+ readl(context_scu.base + SCU_FILTER_STARTADDR);
+ context_scu.filter_end_addr =
+ readl(context_scu.base + SCU_FILTER_ENDADDR);
+ context_scu.access_ctrl_sac =
+ readl(context_scu.base + SCU_ACCESS_CTRL_SAC);
+}
+
+static void restore_scu(void)
+{
+ writel(context_scu.ctrl,
+ context_scu.base + SCU_CTRL);
+ writel(context_scu.cpu_pwrstatus,
+ context_scu.base + SCU_CPU_STATUS);
+ writel(context_scu.inv_all_nonsecure,
+ context_scu.base + SCU_INVALIDATE);
+ writel(context_scu.filter_start_addr,
+ context_scu.base + SCU_FILTER_STARTADDR);
+ writel(context_scu.filter_end_addr,
+ context_scu.base + SCU_FILTER_ENDADDR);
+ writel(context_scu.access_ctrl_sac,
+ context_scu.base + SCU_ACCESS_CTRL_SAC);
+}
+
+/*
+ * Save GPIO periph context
+ */
+static void save_gpio(void)
+{
+ int i;
+
+ for (i = 0; i < UX500_NR_GPIO_BANKS; i++) {
+ context_gpio[i].dat =
+ readl(context_gpio[i].base + NMK_GPIO_DAT);
+ context_gpio[i].pdis =
+ readl(context_gpio[i].base + NMK_GPIO_PDIS);
+ context_gpio[i].dir =
+ readl(context_gpio[i].base + NMK_GPIO_DIR);
+ context_gpio[i].slpm =
+ readl(context_gpio[i].base + NMK_GPIO_SLPC);
+ context_gpio[i].altfunc_a =
+ readl(context_gpio[i].base + NMK_GPIO_AFSLA);
+ context_gpio[i].altfunc_b =
+ readl(context_gpio[i].base + NMK_GPIO_AFSLB);
+ context_gpio[i].rimsc =
+ readl(context_gpio[i].base + NMK_GPIO_RIMSC);
+ context_gpio[i].fsmsc =
+ readl(context_gpio[i].base + NMK_GPIO_FWIMSC);
+ context_gpio[i].rwmsc =
+ readl(context_gpio[i].base + NMK_GPIO_RWIMSC);
+ context_gpio[i].fwmsc =
+ readl(context_gpio[i].base + NMK_GPIO_FWIMSC);
+ }
+}
+
+/*
+ * Restore GPIO periph context
+ */
+static void restore_gpio(void)
+{
+ int i;
+
+ for (i = 0; i < UX500_NR_GPIO_BANKS; i++) {
+ writel(context_gpio[i].dat,
+ context_gpio[i].base + NMK_GPIO_DAT);
+ writel(context_gpio[i].pdis,
+ context_gpio[i].base + NMK_GPIO_PDIS);
+ writel(context_gpio[i].dir,
+ context_gpio[i].base + NMK_GPIO_DIR);
+ writel(context_gpio[i].slpm,
+ context_gpio[i].base + NMK_GPIO_SLPC);
+ writel(context_gpio[i].altfunc_a,
+ context_gpio[i].base + NMK_GPIO_AFSLA);
+ writel(context_gpio[i].altfunc_b,
+ context_gpio[i].base + NMK_GPIO_AFSLB);
+ writel(context_gpio[i].rimsc,
+ context_gpio[i].base + NMK_GPIO_RIMSC);
+ writel(context_gpio[i].fsmsc,
+ context_gpio[i].base + NMK_GPIO_FWIMSC);
+ writel(context_gpio[i].rwmsc,
+ context_gpio[i].base + NMK_GPIO_RWIMSC);
+ writel(context_gpio[i].fwmsc,
+ context_gpio[i].base + NMK_GPIO_FWIMSC);
+ }
+}
+
+/*
+ * Save VAPE context
+ */
+void context_vape_save(void)
+{
+ atomic_notifier_call_chain(&context_notifier_list,
+ CONTEXT_SAVE, NULL);
+
+ save_gpio();
+ /*save_uart();*/
+
+ ux500_save_uart_context();
+
+ if (cpu_is_u5500())
+ u5500_context_save_icn();
+ if (cpu_is_u8500())
+ u8500_context_save_icn();
+
+ save_stm_ape();
+
+ save_prcc();
+
+ save_tpiu();
+}
+
+/*
+ * Restore VAPE context
+ */
+void context_vape_restore(void)
+{
+
+ restore_tpiu();
+
+ restore_prcc();
+
+ restore_stm_ape();
+
+ if (cpu_is_u5500())
+ u5500_context_restore_icn();
+ if (cpu_is_u8500())
+ u8500_context_restore_icn();
+
+ /*restore_uart();*/
+ ux500_restore_uart_context();
+
+ restore_gpio();
+
+ atomic_notifier_call_chain(&context_notifier_list,
+ CONTEXT_RESTORE, NULL);
+}
+
+/*
+ * Save common
+ *
+ * This function must be called once for all cores before going to deep sleep.
+ */
+void context_varm_save_common(void)
+{
+
+ /* Save common parts */
+ save_gic_dist_common();
+ save_scu();
+}
+
+/*
+ * Restore common
+ *
+ * This function must be called once for all cores when waking up from deep
+ * sleep.
+ */
+void context_varm_restore_common(void)
+{
+ /* Restore common parts */
+ restore_scu();
+ restore_gic_dist_common();
+}
+
+/*
+ * Save core
+ *
+ * This function must be called once for each cpu core before going to deep
+ * sleep.
+ */
+void context_varm_save_core(void)
+{
+ int cpu = smp_processor_id();
+
+ per_cpu(varm_core_pointer, cpu) = per_cpu(varm_core_backup_stack, cpu);
+
+ /* Save core */
+ context_save_cp15_registers(&per_cpu(varm_core_pointer, cpu));
+ save_gic_if_cpu(&per_cpu(context_gic_cpu, cpu));
+ save_gic_dist_cpu(&per_cpu(context_gic_dist_cpu, cpu));
+}
+
+/*
+ * Restore core
+ *
+ * This function must be called once for each cpu core when waking up from
+ * deep sleep.
+ */
+void context_varm_restore_core(void)
+{
+ int cpu = smp_processor_id();
+
+ /* Restore core */
+ restore_gic_dist_cpu(&per_cpu(context_gic_dist_cpu, cpu));
+ restore_gic_if_cpu(&per_cpu(context_gic_cpu, cpu));
+ context_restore_cp15_registers(&per_cpu(varm_core_pointer, cpu));
+}
+
+/*
+ * Save CPU registers
+ *
+ * This function saves ARM registers.
+ */
+void context_save_cpu_registers(void)
+{
+ int cpu = smp_processor_id();
+
+ context_save_arm_registers(&per_cpu(varm_core_pointer, cpu));
+}
+
+/*
+ * Restore CPU registers
+ *
+ * This function restores ARM registers.
+ */
+void context_restore_cpu_registers(void)
+{
+ int cpu = smp_processor_id();
+
+ context_restore_arm_registers(&per_cpu(varm_core_pointer, cpu));
+}
+
+/*
+ * This function stores CP15 registers related to cache and mmu
+ * in backup SRAM. It also stores stack pointer, CPSR
+ * and return address for the PC in backup SRAM and
+ * does wait for interrupt.
+ */
+void context_save_to_sram_and_wfi(bool cleanL2cache)
+{
+ int cpu = smp_processor_id();
+
+ context_save_to_sram_and_wfi_internal(backup_sram_storage[cpu],
+ cleanL2cache);
+}
+
+static int __init context_init(void)
+{
+ int i;
+ void __iomem *ux500_backup_ptr;
+
+ /* allocate backup pointers for UART context */
+ uart_register_base = ioremap(U8500_UART2_BASE, SZ_4K);
+ if (!uart_register_base)
+ printk(KERN_WARNING "u8500-pm: uart register base NULL\n");
+
+ uart_backup_base = kzalloc(SZ_4K, GFP_KERNEL);
+ if (!uart_backup_base)
+ printk(KERN_WARNING "u8500-pm: uart register backup NULL\n");
+
+ /* allocate backup pointer for RAM data */
+ ux500_backup_ptr = (void *)__get_free_pages(GFP_KERNEL,
+ get_order(U8500_BACKUPRAM_SIZE));
+
+ if (!ux500_backup_ptr) {
+ pr_warning("context: could not allocate backup memory\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * ROM code addresses to store backup contents,
+ * pass the physical address of back up to ROM code
+ */
+ writel(virt_to_phys(ux500_backup_ptr),
+ IO_ADDRESS(U8500_EXT_RAM_LOC_BACKUPRAM_ADDR));
+
+ /* Give logical address to backup RAM. For both CPUs */
+ *(u32 *)IO_ADDRESS(U8500_CPU0_BACKUPRAM_LOG_ADDR_BACKUPRAM_ADDR) =
+ IO_ADDRESS(U8500_BACKUPRAM0_BASE);
+ *(u32 *)IO_ADDRESS(U8500_CPU1_BACKUPRAM_LOG_ADDR_BACKUPRAM_ADDR) =
+ IO_ADDRESS(U8500_BACKUPRAM0_BASE);
+
+ /* FIXME: To UX500 */
+ context_tpiu.base = ioremap(U8500_TPIU_BASE, SZ_4K);
+ context_stm_ape.base = ioremap(UX500(STM_REG), SZ_4K);
+ context_scu.base = ioremap(UX500_SCU_BASE, SZ_4K);
+
+ for (i = 0; i < num_possible_cpus(); i++) {
+ per_cpu(context_gic_cpu, i).base = ioremap(UX500_GIC_CPU_BASE,
+ SZ_4K);
+ per_cpu(context_gic_dist_cpu, i).base =
+ ioremap(UX500_GIC_DIST_BASE,
+ SZ_4K);
+ }
+
+ context_gic_dist_common.base = ioremap(UX500_GIC_DIST_BASE, SZ_4K);
+
+ context_gpio[0].base = ioremap(GPIO_BANK0_BASE, SZ_4K);
+ context_gpio[1].base = ioremap(GPIO_BANK1_BASE, SZ_4K);
+ context_gpio[2].base = ioremap(GPIO_BANK2_BASE, SZ_4K);
+ context_gpio[3].base = ioremap(GPIO_BANK3_BASE, SZ_4K);
+ context_gpio[4].base = ioremap(GPIO_BANK4_BASE, SZ_4K);
+ context_gpio[5].base = ioremap(GPIO_BANK5_BASE, SZ_4K);
+ context_gpio[6].base = ioremap(GPIO_BANK6_BASE, SZ_4K);
+ context_gpio[7].base = ioremap(GPIO_BANK7_BASE, SZ_4K);
+
+ /* PERIPH4 is always on, so no need saving prcc */
+ context_prcc[0].base = ioremap(UX500_CLKRST1_BASE, SZ_4K);
+ context_prcc[1].base = ioremap(UX500_CLKRST2_BASE, SZ_4K);
+ context_prcc[2].base = ioremap(UX500_CLKRST3_BASE, SZ_4K);
+ context_prcc[3].base = ioremap(UX500_CLKRST5_BASE, SZ_4K);
+ context_prcc[4].base = ioremap(UX500_CLKRST6_BASE, SZ_4K);
+
+ context_uart[0].base = ioremap(UX500_UART0_BASE, SZ_4K);
+ context_uart[1].base = ioremap(UX500_UART1_BASE, SZ_4K);
+ context_uart[2].base = ioremap(UX500_UART2_BASE, SZ_4K);
+
+ if (cpu_is_u8500()) {
+ u8500_context_init();
+ } else if (cpu_is_u5500()) {
+ u5500_context_init();
+ } else {
+ printk(KERN_ERR "context: unknown hardware!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+subsys_initcall(context_init);
+
diff --git a/arch/arm/mach-ux500/context.h b/arch/arm/mach-ux500/context.h
new file mode 100644
index 00000000000..9752ba6c13f
--- /dev/null
+++ b/arch/arm/mach-ux500/context.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
+ * Rickard Andersson <rickard.andersson@stericsson.com> for
+ * ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ */
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+#include <linux/notifier.h>
+
+#define CONTEXT_SAVE 0
+#define CONTEXT_RESTORE 1
+
+int context_notifier_register(struct notifier_block *nb);
+int context_notifier_unregister(struct notifier_block *nb);
+
+void context_vape_save(void);
+void context_vape_restore(void);
+
+void context_varm_save_common(void);
+void context_varm_restore_common(void);
+
+void context_varm_save_core(void);
+void context_varm_restore_core(void);
+
+void context_save_cpu_registers(void);
+void context_restore_cpu_registers(void);
+
+/*
+ * cleanL2cache - Indicate if L2 cache should be cleaned.
+ * Note that L1 cache is always cleaned.
+ */
+void context_save_to_sram_and_wfi(bool cleanL2cache);
+
+void context_clean_l1_cache_all(void);
+void context_save_arm_registers(u32 **backup_stack);
+void context_restore_arm_registers(u32 **backup_stack);
+
+void context_save_cp15_registers(u32 **backup_stack);
+void context_restore_cp15_registers(u32 **backup_stack);
+
+void context_save_to_sram_and_wfi_internal(u32 backup_sram_storage,
+ bool cleanL2cache);
+
+/* DB specific functions in either context-db8500 or context-db5500 */
+void u8500_context_save_icn(void);
+void u8500_context_restore_icn(void);
+void u8500_context_init(void);
+
+void u5500_context_save_icn(void);
+void u5500_context_restore_icn(void);
+void u5500_context_init(void);
+
+#endif
diff --git a/arch/arm/mach-ux500/context_arm.S b/arch/arm/mach-ux500/context_arm.S
new file mode 100755
index 00000000000..e991fb46eb3
--- /dev/null
+++ b/arch/arm/mach-ux500/context_arm.S
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
+ * Rickard Andersson <rickard.andersson@stericsson.com> for
+ * ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ */
+
+#include <linux/linkage.h>
+#include <mach/hardware.h>
+#include <asm/hardware/cache-l2x0.h>
+
+/*
+ * Save and increment macro
+ */
+.macro SAVE_AND_INCREMENT FROM_REG TO_REG
+ str \FROM_REG, [\TO_REG], #+4
+.endm
+
+/*
+ * Decrement and restore macro
+ */
+.macro DECREMENT_AND_RESTORE FROM_REG TO_REG
+ ldr \TO_REG, [\FROM_REG, #-4]!
+.endm
+
+/*
+ * Save ARM registers
+ *
+ * This function must be called in supervisor mode.
+ *
+ * r0 = address to backup stack pointer
+ *
+ * Backup stack operations:
+ * + {sp, lr}^
+ * + cpsr
+ * + {r3, r8-r14} (FIQ mode: r3=spsr)
+ * + {r3, r13, r14} (IRQ mode: r3=spsr)
+ * + {r3, r13, r14} (abort mode: r3=spsr)
+ * + {r3, r13, r14} (undef mode: r3=spsr)
+ */
+ .align
+ .section ".text", "ax"
+ENTRY(context_save_arm_registers)
+ stmfd sp!, {r1, r2, r3, lr} @ Save on stack
+ ldr r1, [r0] @ Read backup stack pointer
+
+ stmia r1, {sp, lr}^ @ Store user mode sp and lr
+ @ registers
+ add r1, r1, #8 @ Update backup pointer (not
+ @ done in previous instruction)
+
+ mrs r2, cpsr @ Get CPSR
+ SAVE_AND_INCREMENT r2 r1 @ Save CPSR register
+ orr r2, r2, #0xc0 @ Disable FIQ and IRQ
+ bic r2, r2, #0x1f @ Setup r2 to change mode
+
+ @ The suffix to CPSR refers to which field(s) of the CPSR is
+ @ rereferenced (you can specify one or more). Defined fields are:
+ @
+ @ c - control
+ @ x - extension
+ @ s - status
+ @ f - flags
+
+ orr r3, r2, #0x11 @ Save FIQ mode registers
+ msr cpsr_cxsf, r3
+ mrs r3, spsr
+ stmia r1!, {r3, r8-r14}
+
+ orr r3, r2, #0x12 @ Save IRQ mode registers
+ msr cpsr_cxsf, r3
+ mrs r3, spsr
+ stmia r1!, {r3, r13, r14}
+
+ orr r3, r2, #0x17 @ Save abort mode registers +
+ @ common mode registers
+ msr cpsr_cxsf, r3
+ mrs r3, spsr
+ stmia r1!, {r3, r13, r14}
+
+ orr r3, r2, #0x1B @ Save undef mode registers
+ msr cpsr_cxsf, r3
+ mrs r3, spsr
+ stmia r1!, {r3, r13, r14}
+
+ orr r3, r2, #0x13 @ Return to supervisor mode
+ msr cpsr_cxsf, r3
+
+ str r1, [r0] @ Write backup stack pointer
+ ldmfd sp!, {r1, r2, r3, pc} @ Restore registers and return
+
+
+
+/*
+ * Restore ARM registers
+ *
+ * This function must be called in supervisor mode.
+ *
+ * r0 = address to backup stack pointer
+ *
+ * Backup stack operations:
+ * - {r3, r13, r14} (undef mode: spsr=r3)
+ * - {r3, r13, r14} (abort mode: spsr=r3)
+ * - {r3, r13, r14} (IRQ mode: spsr=r3)
+ * - {r3, r8-r14} (FIQ mode: spsr=r3)
+ * - cpsr
+ * - {sp, lr}^
+ */
+ .align
+ .section ".text", "ax"
+ENTRY(context_restore_arm_registers)
+ stmfd sp!, {r1, r2, r3, lr} @ Save on stack
+ ldr r1, [r0] @ Read backup stack pointer
+
+ mrs r2, cpsr @ Get CPSR
+ orr r2, r2, #0xc0 @ Disable FIQ and IRQ
+ bic r2, r2, #0x1f @ Setup r2 to change mode
+
+ orr r3, r2, #0x1b @ Restore undef mode registers
+ msr cpsr_cxsf, r3
+ ldmdb r1!, {r3, r13, r14}
+ msr spsr_cxsf, r3
+
+ orr r3, r2, #0x17 @ Restore abort mode registers
+ msr cpsr_cxsf, r3
+ ldmdb r1!, {r3, r13, r14}
+ msr spsr_cxsf, r3
+
+ orr r3, r2, #0x12 @ Restore IRQ mode registers
+ msr cpsr_cxsf, r3
+ ldmdb r1!, {r3, r13, r14}
+ msr spsr_cxsf, r3
+
+ orr r3, r2, #0x11 @ Restore FIQ mode registers
+ msr cpsr_cxsf, r3
+ ldmdb r1!, {r3, r8-r14}
+ msr spsr_cxsf, r3
+
+ DECREMENT_AND_RESTORE r1 r3 @ Restore cpsr register
+ msr cpsr_cxsf, r3
+
+ ldmdb r1, {sp, lr}^ @ Restore sp and lr registers
+ sub r1, r1, #8 @ Update backup pointer (not
+ @ done in previous instruction)
+
+ str r1, [r0] @ Write backup stack pointer
+ ldmfd sp!, {r1, r2, r3, pc} @ Restore registers and return
+
+
+
+/*
+ * Save CP15 registers
+ *
+ * This function must be called in supervisor mode.
+ *
+ * r0 = address to backup stack pointer
+ *
+ * TTBR0, TTBR1, TTBRC, DACR CP15 registers are restored by boot ROM from SRAM.
+ */
+ .align 4
+ .section ".text", "ax"
+ENTRY(context_save_cp15_registers)
+ stmfd sp!, {r1, r2, lr} @ Save on stack
+ ldr r1, [r0] @ Read backup stack pointer
+
+ mrc p15, 0, r2, c12, c0, 0 @ Read Non-secure Vector Base
+ @ Address Register
+ SAVE_AND_INCREMENT r2 r1
+
+ mrc p15, 0, r2, c10, c2, 0 @ Access primary memory region
+ @ remap register
+ SAVE_AND_INCREMENT r2 r1
+ mrc p15, 0, r2, c10, c2, 1 @ Access normal memory region
+ @ remap register
+ SAVE_AND_INCREMENT r2 r1
+
+ mrc p15, 0, r2, c13, c0, 1 @ Read Context ID Register
+ SAVE_AND_INCREMENT r2 r1
+ mrc p15, 0, r2, c13, c0, 2 @ Read Thread ID registers,
+ @ this register is both user
+ @ and privileged R/W accessible
+ SAVE_AND_INCREMENT r2 r1
+ mrc p15, 0, r2, c13, c0, 3 @ Read Thread ID registers,
+ @ this register is user
+ @ read-only and privileged R/W
+ @ accessible.
+ SAVE_AND_INCREMENT r2 r1
+ mrc p15, 0, r2, c13, c0, 4 @ Read Thread ID registers,
+ @ this register is privileged
+ @ R/W accessible only.
+ SAVE_AND_INCREMENT r2 r1
+
+ mrc p15, 2, r2, c0, c0, 0 @ Cache Size Selection Register
+ SAVE_AND_INCREMENT r2 r1
+
+ mrc p15, 0, r2, c9, c12, 0 @ Read PMNC Register
+ SAVE_AND_INCREMENT r2 r1
+ mrc p15, 0, r2, c9, c12, 1 @ Read PMCNTENSET Register
+ SAVE_AND_INCREMENT r2 r1
+ mrc p15, 0, r2, c9, c12, 5 @ Read PMSELR Register
+ SAVE_AND_INCREMENT r2 r1
+ mrc p15, 0, r2, c9, c13, 0 @ Read PMCCNTR Register
+ SAVE_AND_INCREMENT r2 r1
+ mrc p15, 0, r2, c9, c13, 1 @ Read PMXEVTYPER Register
+ SAVE_AND_INCREMENT r2 r1
+ mrc p15, 0, r2, c9, c14, 0 @ Read PMUSERENR Register
+ SAVE_AND_INCREMENT r2 r1
+ mrc p15, 0, r2, c9, c14, 1 @ Read PMINTENSET Register
+ SAVE_AND_INCREMENT r2 r1
+ mrc p15, 0, r2, c9, c14, 2 @ Read PMINTENCLR Register
+ SAVE_AND_INCREMENT r2 r1
+
+ str r1, [r0] @ Write backup stack pointer
+ ldmfd sp!, {r1, r2, pc} @ Restore registers and return
+
+
+
+/*
+ * Restore CP15 registers
+ *
+ * This function must be called in supervisor mode.
+ *
+ * r0 = address to backup stack pointer
+ */
+ .align 4
+ .section ".text", "ax"
+ENTRY(context_restore_cp15_registers)
+ stmfd sp!, {r1, r2, lr} @ Save on stack
+ ldr r1, [r0] @ Read backup stack pointer
+
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c9, c14, 2 @ Write PMINTENCLR Register
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c9, c14, 1 @ Write PMINTENSET Register
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c9, c14, 0 @ Write PMUSERENR Register
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c9, c13, 1 @ Write PMXEVTYPER Register
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c9, c13, 0 @ Write PMCCNTR Register
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c9, c12, 5 @ Write PMSELR Register
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c9, c12, 1 @ Write PMCNTENSET Register
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c9, c12, 0 @ Write PMNC Register
+
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 2, r2, c0, c0, 0 @ Cache Size Selection Register
+
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c13, c0, 4 @ Write Thread ID registers,
+ @ this register is privileged
+ @ R/W accessible only
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c13, c0, 3 @ Write Thread ID registers,
+ @ this register is user
+ @ read-only and privileged R/W
+ @ accessible
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c13, c0, 2 @ Write Thread ID registers,
+ @ this register is both user
+ @ and privileged R/W accessible
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c13, c0, 1 @ Write Context ID Register
+
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c10, c2, 1 @ Access normal memory region
+ @ remap register
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c10, c2, 0 @ Access primary memory region
+ @ remap register
+
+ DECREMENT_AND_RESTORE r1 r2
+ mcr p15, 0, r2, c12, c0, 0 @ Write Non-secure Vector Base
+ @ Address Register
+
+ str r1, [r0] @ Write backup stack pointer
+ ldmfd sp!, {r1, r2, pc} @ Restore registers and return
+
+
+/*
+ * L1 cache clean function. Commit 'dirty' data from L1
+ * to L2 cache.
+ *
+ * r0, r1, r2, used locally
+ *
+ */
+ .align 4
+ .section ".text", "ax"
+ENTRY(context_clean_l1_cache_all)
+
+ mov r0, #0 @ swith to cache level 0
+ @ (L1 cache)
+ mcr p15, 2, r0, c0, c0, 0 @ select current cache level
+ @ in cssr
+
+ dmb
+ mov r1, #0 @ r1 = way index
+wayLoopL1clean:
+ mov r0, #0 @ r0 = line index
+lineLoopL1clean:
+ mov r2, r1, lsl #30 @ TODO: OK to hard-code
+ @ SoC-specific L1 cache details?
+ add r2, r0, lsl #5
+ mcr p15, 0, r2, c7, c10, 2 @ Clean cache by set/way
+ add r0, r0, #1
+ cmp r0, #256 @ TODO: Ok with hard-coded
+ @ set/way sizes or do we have to
+ @ read them from ARM regs? Is it
+ @ set correctly in silicon?
+ bne lineLoopL1clean
+ add r1, r1, #1
+ cmp r1, #4 @ TODO: Ditto, sizes...
+ bne wayLoopL1clean
+
+ dsb
+ isb
+ mov pc, lr
+
+ENDPROC(context_clean_l1_cache_all)
+
+
+/*
+ * L2 cache clean function. Commit from PL310 L2 cache
+ * controller to DDR SDRAM.
+ *
+ * r0, r2 used locally
+ *
+ */
+ .align 4
+ .section ".text", "ax"
+ENTRY(ux500_clean_l2_cache_all)
+
+ ldr r0, =IO_ADDRESS(UX500_L2CC_BASE)
+
+ ldr r1, =0xff @ TODO: Ok to assume 8-way cache
+ @ on Ux500?
+ str r1, [r0, #L2X0_CLEAN_WAY]
+ L2busywaitLoopClean:
+ ldr r1, [r0, #L2X0_CLEAN_WAY]
+ cmp r1, #0 @ All bits in L2X0_CLEAN_WAY
+ @ will be zero once clean is
+ @ finished
+ bne L2busywaitLoopClean
+
+ ldr r1, =0x0
+ str r1, [r0, #L2X0_CACHE_SYNC]
+ @ l2x0 C code busy-wait here to
+ @ ensure no background op is
+ @ running.
+ @ In our case we have already
+ @ checked this after the cache
+ @ clean and CACHE_SYNC is atomic
+ @ according to refman
+ mov pc, lr
+
+ENDPROC(ux500_clean_l2_cache_all)
+
+
+/*
+ * Last saves and WFI
+ *
+ * r0 = address to backup_sram_storage base adress
+ * r1 = indicate whether L2 cache should be cleaned
+ */
+ .align 4
+ .section ".text", "ax"
+ENTRY(context_save_to_sram_and_wfi_internal)
+
+ stmfd sp!, {r2-r12, lr} @ save on stack.
+
+ mrc p15, 0, r2, c1, c0, 0 @ read cp15 system control
+ @ register
+ str r2, [r0, #0x00]
+ mrc p15, 0, r2, c2, c0, 0 @ read cp15 ttb0 register
+ str r2, [r0, #0x04]
+ mrc p15, 0, r2, c2, c0, 1 @ read cp15 ttb1 register
+ str r2, [r0, #0x08]
+ mrc p15, 0, r2, c2, c0, 2 @ read cp15 ttb control register
+ str r2, [r0, #0x0C]
+ mrc p15, 0, r2, c3, c0, 0 @ read domain access control
+ @ register
+ str r2, [r0, #0x10]
+
+ ldr r2, =return_here
+ str r2, [r0, #0x14] @ save program counter restore
+ @ value to backup_sram_storage
+ mrs r2, cpsr
+ str r2, [r0, #0x18] @ save cpsr to
+ @ backup_sram_storage
+ str sp, [r0, #0x1c] @ save sp to backup_sram_storage
+
+ mov r4, r1 @ Set r4 = cleanL2cache, r2
+ @ will be destroyed by
+ @ v7_clean_l1_cache_all
+
+/*
+ TODO: Temporary removal!
+ bl ux500_clean_l1_cache_all @ Commit all dirty data in L1
+ @ cache to L2 without
+ @ invalidating
+*/
+ dsb
+ cmp r4, #0
+ blne ux500_clean_l2_cache_all @ If r2 != FALSE then clean all
+ @ dirty data in L2 cache, no
+ @ invalidate
+
+ dsb @ data synchronization barrier
+ isb @ instruction synchronization
+ @ barrier
+ wfi @ wait for interrupt
+
+return_here: @ both cores return here
+ @ now we are out deep sleep
+ @ with all the context lost
+ @ except pc, sp and cpsr
+
+ ldmfd sp!, {r2-r12, pc} @ restore from stack
diff --git a/arch/arm/mach-ux500/cpu-db5500.c b/arch/arm/mach-ux500/cpu-db5500.c
index e9278f6d67a..35bfb4d3391 100644
--- a/arch/arm/mach-ux500/cpu-db5500.c
+++ b/arch/arm/mach-ux500/cpu-db5500.c
@@ -14,14 +14,101 @@
#include <mach/hardware.h>
#include <mach/devices.h>
#include <mach/setup.h>
+#include <mach/irqs.h>
static struct map_desc u5500_io_desc[] __initdata = {
+ __IO_DEV_DESC(U5500_RTC_BASE, SZ_4K),
__IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K),
__IO_DEV_DESC(U5500_GPIO1_BASE, SZ_4K),
__IO_DEV_DESC(U5500_GPIO2_BASE, SZ_4K),
__IO_DEV_DESC(U5500_GPIO3_BASE, SZ_4K),
__IO_DEV_DESC(U5500_GPIO4_BASE, SZ_4K),
__IO_DEV_DESC(U5500_PRCMU_BASE, SZ_4K),
+ __IO_DEV_DESC(U5500_PRCMU_TCDM_BASE, SZ_4K),
+};
+
+static struct resource mbox0_resources[] = {
+ {
+ .name = "mbox_peer",
+ .start = U5500_MBOX0_PEER_START,
+ .end = U5500_MBOX0_PEER_END,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "mbox_local",
+ .start = U5500_MBOX0_LOCAL_START,
+ .end = U5500_MBOX0_LOCAL_END,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "mbox_irq",
+ .start = MBOX_PAIR0_VIRT_IRQ,
+ .end = MBOX_PAIR0_VIRT_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct resource mbox1_resources[] = {
+ {
+ .name = "mbox_peer",
+ .start = U5500_MBOX1_PEER_START,
+ .end = U5500_MBOX1_PEER_END,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "mbox_local",
+ .start = U5500_MBOX1_LOCAL_START,
+ .end = U5500_MBOX1_LOCAL_END,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "mbox_irq",
+ .start = MBOX_PAIR1_VIRT_IRQ,
+ .end = MBOX_PAIR1_VIRT_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct resource mbox2_resources[] = {
+ {
+ .name = "mbox_peer",
+ .start = U5500_MBOX2_PEER_START,
+ .end = U5500_MBOX2_PEER_END,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "mbox_local",
+ .start = U5500_MBOX2_LOCAL_START,
+ .end = U5500_MBOX2_LOCAL_END,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "mbox_irq",
+ .start = MBOX_PAIR2_VIRT_IRQ,
+ .end = MBOX_PAIR2_VIRT_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device mbox0_device = {
+ .id = 0,
+ .name = "mbox",
+ .resource = mbox0_resources,
+ .num_resources = ARRAY_SIZE(mbox0_resources),
+};
+
+static struct platform_device mbox1_device = {
+ .id = 1,
+ .name = "mbox",
+ .resource = mbox1_resources,
+ .num_resources = ARRAY_SIZE(mbox1_resources),
+};
+
+static struct platform_device mbox2_device = {
+ .id = 2,
+ .name = "mbox",
+ .resource = mbox2_resources,
+ .num_resources = ARRAY_SIZE(mbox2_resources),
};
static struct platform_device *u5500_platform_devs[] __initdata = {
@@ -33,6 +120,13 @@ static struct platform_device *u5500_platform_devs[] __initdata = {
&u5500_gpio_devs[5],
&u5500_gpio_devs[6],
&u5500_gpio_devs[7],
+ &mbox0_device,
+ &mbox1_device,
+ &mbox2_device,
+ &u5500_pwm0_device,
+ &u5500_pwm1_device,
+ &u5500_pwm2_device,
+ &u5500_pwm3_device,
};
void __init u5500_map_io(void)
@@ -45,6 +139,7 @@ void __init u5500_map_io(void)
void __init u5500_init_devices(void)
{
ux500_init_devices();
+ db5500_dma_init();
platform_add_devices(u5500_platform_devs,
ARRAY_SIZE(u5500_platform_devs));
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index f21c444edd9..7a8551b0793 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -32,27 +32,102 @@ static struct platform_device *platform_devs[] __initdata = {
&u8500_gpio_devs[6],
&u8500_gpio_devs[7],
&u8500_gpio_devs[8],
- &u8500_dma40_device,
};
/* minimum static i/o mapping required to boot U8500 platforms */
static struct map_desc u8500_io_desc[] __initdata = {
+ __IO_DEV_DESC(U8500_RTC_BASE, SZ_4K),
+ __IO_DEV_DESC(U8500_MSP0_BASE, SZ_4K),
+ __IO_DEV_DESC(U8500_MSP1_BASE, SZ_4K),
+ __IO_DEV_DESC(U8500_MSP2_BASE, SZ_4K),
__IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K),
+ __IO_DEV_DESC(U8500_ASIC_ID_BASE, SZ_4K),
+ __IO_DEV_DESC(U8500_STM_REG_BASE, SZ_4K),
+ {IO_ADDRESS(U8500_BACKUPRAM0_BASE),
+ __phys_to_pfn(U8500_BACKUPRAM0_BASE), SZ_8K, MT_BACKUP_RAM},
+ __MEM_DEV_DESC(U8500_BOOT_ROM_BASE, SZ_1M),
};
static struct map_desc u8500ed_io_desc[] __initdata = {
__IO_DEV_DESC(U8500_MTU0_BASE_ED, SZ_4K),
+ __IO_DEV_DESC(U8500_MTU1_BASE_ED, SZ_4K),
__IO_DEV_DESC(U8500_CLKRST7_BASE_ED, SZ_8K),
};
static struct map_desc u8500v1_io_desc[] __initdata = {
- __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K),
+ __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE_V1, SZ_4K),
};
+static struct map_desc u8500v2_io_desc[] __initdata = {
+ __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K),
+};
+/*
+ * Functions to differentiate between later ASICs
+ * We look into the end of the ROM to locate the hardcoded ASIC ID.
+ * This is only needed to differentiate between minor revisions and
+ * process variants of an ASIC, the major revisions are encoded in
+ * the cpuid.
+ */
+#define U8500_ASIC_ID_LOC_ED_V1 (U8500_BOOT_ROM_BASE + 0x1FFF4)
+#define U8500_ASIC_ID_LOC_V2 (U8500_BOOT_ROM_BASE + 0x1DBF4)
+#define U8500_ASIC_REV_ED 0x01
+#define U8500_ASIC_REV_V10 0xA0
+#define U8500_ASIC_REV_V11 0xA1
+#define U8500_ASIC_REV_V20 0xB0
+
+/**
+ * struct db8500_asic_id - fields of the ASIC ID
+ * @process: the manufacturing process, 0x40 is 40 nm
+ * 0x00 is "standard"
+ * @partnumber: hithereto 0x8500 for DB8500
+ * @revision: version code in the series
+ * This field definion is not formally defined but makes
+ * sense.
+ */
+struct db8500_asic_id {
+ u8 process;
+ u16 partnumber;
+ u8 revision;
+};
+
+/* This isn't going to change at runtime */
+static struct db8500_asic_id db8500_id;
+
+static void __init get_db8500_asic_id(void)
+{
+ u32 asicid;
+
+ if (cpu_is_u8500v1() || cpu_is_u8500ed())
+ asicid = readl(__io_address(U8500_ASIC_ID_LOC_ED_V1));
+ else if (cpu_is_u8500v2())
+ asicid = readl(__io_address(U8500_ASIC_ID_LOC_V2));
+ else
+ BUG();
+
+ db8500_id.process = (asicid >> 24);
+ db8500_id.partnumber = (asicid >> 16) & 0xFFFFU;
+ db8500_id.revision = asicid & 0xFFU;
+}
+
+bool cpu_is_u8500v10(void)
+{
+ return (db8500_id.revision == U8500_ASIC_REV_V10);
+}
+
+bool cpu_is_u8500v11(void)
+{
+ return (db8500_id.revision == U8500_ASIC_REV_V11);
+}
+
+bool cpu_is_u8500v20(void)
+{
+ return (db8500_id.revision == U8500_ASIC_REV_V20);
+}
+
void __init u8500_map_io(void)
{
ux500_map_io();
@@ -61,19 +136,52 @@ void __init u8500_map_io(void)
if (cpu_is_u8500ed())
iotable_init(u8500ed_io_desc, ARRAY_SIZE(u8500ed_io_desc));
- else
+ else if (cpu_is_u8500v1())
iotable_init(u8500v1_io_desc, ARRAY_SIZE(u8500v1_io_desc));
+ else if (cpu_is_u8500v2())
+ iotable_init(u8500v2_io_desc, ARRAY_SIZE(u8500v2_io_desc));
+
+ /* Read out the ASIC ID as early as we can */
+ get_db8500_asic_id();
}
+static void __init u8500_earlydrop_fixup(void)
+{
+ u8500_shrm_device.resource[1].start = IRQ_CA_WAKE_REQ_ED;
+ u8500_shrm_device.resource[1].end = IRQ_CA_WAKE_REQ_ED;
+ u8500_shrm_device.resource[2].start = IRQ_AC_READ_NOTIFICATION_0_ED;
+ u8500_shrm_device.resource[2].end = IRQ_AC_READ_NOTIFICATION_0_ED;
+ u8500_shrm_device.resource[3].start = IRQ_AC_READ_NOTIFICATION_1_ED;
+ u8500_shrm_device.resource[3].end = IRQ_AC_READ_NOTIFICATION_1_ED;
+ u8500_shrm_device.resource[4].start = IRQ_CA_MSG_PEND_NOTIFICATION_0_ED;
+ u8500_shrm_device.resource[4].end = IRQ_CA_MSG_PEND_NOTIFICATION_0_ED;
+ u8500_shrm_device.resource[5].start = IRQ_CA_MSG_PEND_NOTIFICATION_1_ED;
+ u8500_shrm_device.resource[5].end = IRQ_CA_MSG_PEND_NOTIFICATION_1_ED;
+}
/*
* This function is called from the board init
*/
void __init u8500_init_devices(void)
{
- ux500_init_devices();
+ /* Display some ASIC boilerplate */
+ pr_info("DB8500: process: %02x, revision ID: 0x%02x\n",
+ db8500_id.process, db8500_id.revision);
+ if (cpu_is_u8500ed())
+ pr_info("DB8500: Early Drop (ED)\n");
+ else if (cpu_is_u8500v10())
+ pr_info("DB8500: version 1.0\n");
+ else if (cpu_is_u8500v11())
+ pr_info("DB8500: version 1.1\n");
+ else if (cpu_is_u8500v20())
+ pr_info("DB8500: version 2.0\n");
+ else
+ pr_warning("ASIC: UNKNOWN SILICON VERSION!\n");
if (cpu_is_u8500ed())
- dma40_u8500ed_fixup();
+ u8500_earlydrop_fixup();
+
+ db8500_dma_init();
+ ux500_init_devices();
/* Register the platform devices */
platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index e0fd747e447..3d54ac17092 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -10,20 +10,21 @@
#include <linux/io.h>
#include <linux/clk.h>
+#include <asm/cacheflush.h>
#include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/map.h>
-#include <asm/localtimer.h>
#include <plat/mtu.h>
#include <mach/hardware.h>
#include <mach/setup.h>
#include <mach/devices.h>
+#include <mach/prcmu-fw-api.h>
#include "clock.h"
static struct map_desc ux500_io_desc[] __initdata = {
__IO_DEV_DESC(UX500_UART0_BASE, SZ_4K),
+ __IO_DEV_DESC(UX500_UART1_BASE, SZ_4K),
__IO_DEV_DESC(UX500_UART2_BASE, SZ_4K),
__IO_DEV_DESC(UX500_GIC_CPU_BASE, SZ_4K),
@@ -44,8 +45,10 @@ static struct map_desc ux500_io_desc[] __initdata = {
__IO_DEV_DESC(UX500_BACKUPRAM0_BASE, SZ_8K),
};
+static struct platform_device *ux500_platform_devs[] __initdata = {
+};
static struct amba_device *ux500_amba_devs[] __initdata = {
- &ux500_pl031_device,
+ &ux500_rtc_device,
};
void __init ux500_map_io(void)
@@ -55,6 +58,21 @@ void __init ux500_map_io(void)
void __init ux500_init_devices(void)
{
+ void __iomem *l2x0_base = __io_address(UX500_L2CC_BASE);
+
+ /*
+ * Unlock Data and Instruction Lock if locked. This is done here
+ * instead of in l2x0_init since doing it there appears to cause the
+ * second core boot to occasionaly fail.
+ */
+ if (readl_relaxed(l2x0_base + L2X0_LOCKDOWN_WAY_D) & 0xFF)
+ writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D);
+
+ if (readl_relaxed(l2x0_base + L2X0_LOCKDOWN_WAY_I) & 0xFF)
+ writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I);
+
+ platform_add_devices(ux500_platform_devs,
+ ARRAY_SIZE(ux500_platform_devs));
amba_add_devices(ux500_amba_devs, ARRAY_SIZE(ux500_amba_devs));
}
@@ -67,10 +85,45 @@ void __init ux500_init_irq(void)
* Init clocks here so that they are available for system timer
* initialization.
*/
+ prcmu_early_init();
clk_init();
}
#ifdef CONFIG_CACHE_L2X0
+static inline void ux500_cache_wait(void __iomem *reg, unsigned long mask)
+{
+ /* wait for the operation to complete */
+ while (readl(reg) & mask)
+ ;
+}
+
+static inline void ux500_cache_sync(void)
+{
+ void __iomem *base = __io_address(UX500_L2CC_BASE);
+ writel(0, base + L2X0_CACHE_SYNC);
+ ux500_cache_wait(base + L2X0_CACHE_SYNC, 1);
+}
+
+/* The L2 cache cannot be turned off in the non-secure world.
+ Dummy until a secure service is in place */
+static void ux500_l2x0_disable(void) {}
+
+/* This is only called when doing a kexec, just after turning off the L2
+ and L1 cache, and it is surrounded by a spinlock in the generic version.
+ However, we're not really turning off the L2 cache right now and the
+ PL310 does not support exclusive accesses (used to implement the spinlock).
+ So, the invalidation needs to be done without the spinlock. */
+static void ux500_l2x0_inv_all(void)
+{
+ void __iomem *l2x0_base = __io_address(UX500_L2CC_BASE);
+ uint32_t l2x0_way_mask = (1<<16) - 1; /* Bitmask of active ways */
+
+ /* invalidate all ways */
+ writel(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
+ ux500_cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
+ ux500_cache_sync();
+}
+
static int ux500_l2x0_init(void)
{
void __iomem *l2x0_base;
@@ -80,26 +133,12 @@ static int ux500_l2x0_init(void)
/* 64KB way size, 8 way associativity, force WA */
l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff);
+ /* Override invalidate function */
+ outer_cache.disable = ux500_l2x0_disable;
+ outer_cache.inv_all = ux500_l2x0_inv_all;
+
return 0;
}
early_initcall(ux500_l2x0_init);
#endif
-static void __init ux500_timer_init(void)
-{
-#ifdef CONFIG_LOCAL_TIMERS
- /* Setup the local timer base */
- twd_base = __io_address(UX500_TWD_BASE);
-#endif
- /* Setup the MTU base */
- if (cpu_is_u8500ed())
- mtu_base = __io_address(U8500_MTU0_BASE_ED);
- else
- mtu_base = __io_address(UX500_MTU0_BASE);
-
- nmdk_timer_init();
-}
-
-struct sys_timer ux500_timer = {
- .init = ux500_timer_init,
-};
diff --git a/arch/arm/mach-ux500/cpufreq.c b/arch/arm/mach-ux500/cpufreq.c
new file mode 100644
index 00000000000..e0ac272a393
--- /dev/null
+++ b/arch/arm/mach-ux500/cpufreq.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+#include <mach/prcmu-fw-api.h>
+#include <mach/prcmu-regs.h>
+
+static struct cpufreq_frequency_table freq_table[] = {
+ [0] = {
+ .index = 0,
+ .frequency = 200000,
+ },
+ [1] = {
+ .index = 1,
+ .frequency = 300000,
+ },
+ [2] = {
+ .index = 2,
+ .frequency = 600000,
+ },
+ [3] = {
+ .index = 3,
+ .frequency = CPUFREQ_TABLE_END,
+ },
+};
+
+static struct freq_attr *u8500_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static int u8500_cpufreq_verify_speed(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static int u8500_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct cpufreq_freqs freqs;
+ unsigned int idx;
+ enum arm_opp op;
+
+
+ /* scale the target frequency to one of the extremes supported */
+ if (target_freq < policy->cpuinfo.min_freq)
+ target_freq = policy->cpuinfo.min_freq;
+ if (target_freq > policy->cpuinfo.max_freq)
+ target_freq = policy->cpuinfo.max_freq;
+
+ /* Lookup the next frequency */
+ if (cpufreq_frequency_table_target
+ (policy, freq_table, target_freq, relation, &idx)) {
+ return -EINVAL;
+ }
+
+ freqs.old = policy->cur;
+ freqs.new = freq_table[idx].frequency;
+ freqs.cpu = policy->cpu;
+
+ if (freqs.old == freqs.new)
+ return 0;
+
+ /* pre-change notification */
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ switch (idx) {
+ case 0:
+ op = ARM_EXTCLK;
+ break;
+ case 1:
+ op = ARM_50_OPP;
+ break;
+ case 2:
+ op = ARM_100_OPP;
+ break;
+ default:
+ pr_err("u8500-cpufreq: Error getting OPP level\n");
+ return -EINVAL;
+ }
+
+ /* request the PRCM unit for opp change */
+ if (prcmu_set_arm_opp(op)) {
+ pr_err("u8500-cpufreq: Failed to set OPP level\n");
+ return -EINVAL;
+ }
+
+ /* Request 100% APE OPP, via PRCMU QoS, if ARM opp is 100% */
+ if (op == ARM_100_OPP) {
+ if (prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
+ "cpufreq", 100) < 0)
+ pr_err("u8500-cpufreq : Add QoS failed\n");
+ } else
+ prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "cpufreq");
+
+ /* post change notification */
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return 0;
+}
+
+static unsigned int u8500_cpufreq_getspeed(unsigned int cpu)
+{
+ /* request the prcm to get the current ARM opp */
+ enum arm_opp opp = prcmu_get_arm_opp();
+
+ switch (opp) {
+ case ARM_EXTCLK:
+ return freq_table[0].frequency;
+ case ARM_50_OPP:
+ return freq_table[1].frequency;
+ case ARM_100_OPP:
+ return freq_table[2].frequency;
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static int __cpuinit u8500_cpufreq_init(struct cpufreq_policy *policy)
+{
+ int res;
+
+ if (cpu_is_u8500v2()) {
+ freq_table[1].frequency = 400000;
+ freq_table[2].frequency = 800000;
+ }
+
+ /* get policy fields based on the table */
+ res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ if (!res)
+ cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+ else {
+ pr_err("u8500-cpufreq : Failed to read policy table\n");
+ return res;
+ }
+
+ policy->min = policy->cpuinfo.min_freq;
+ policy->max = policy->cpuinfo.max_freq;
+ policy->cur = u8500_cpufreq_getspeed(policy->cpu);
+
+ /* Request 100% APE OPP, via PRCMU QoS, if ARM opp is 100% */
+ if (policy->cur == policy->max) {
+ if (prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
+ "cpufreq", 100) < 0)
+ pr_err("u8500-cpufreq : Add QoS failed\n");
+ }
+
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ /*
+ * FIXME : Need to take time measurement across the target()
+ * function with no/some/all drivers in the notification
+ * list.
+ */
+ policy->cpuinfo.transition_latency = 200 * 1000; /* in ns */
+
+ /* policy sharing between dual CPUs */
+ cpumask_copy(policy->cpus, &cpu_present_map);
+
+ policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+
+ return 0;
+}
+
+static struct cpufreq_driver u8500_cpufreq_driver = {
+ .flags = CPUFREQ_STICKY,
+ .verify = u8500_cpufreq_verify_speed,
+ .target = u8500_cpufreq_target,
+ .get = u8500_cpufreq_getspeed,
+ .init = u8500_cpufreq_init,
+ .name = "U8500",
+ .attr = u8500_cpufreq_attr,
+};
+
+static int __init u8500_cpufreq_register(void)
+{
+ pr_info("cpufreq for u8500 started\n");
+ return cpufreq_register_driver(&u8500_cpufreq_driver);
+}
+device_initcall(u8500_cpufreq_register);
diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c
new file mode 100644
index 00000000000..ee7dad4cf0a
--- /dev/null
+++ b/arch/arm/mach-ux500/cpuidle.c
@@ -0,0 +1,1228 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Rickard Andersson <rickard.andersson@stericsson.com> for
+ * ST-Ericsson. Loosly based on cpuidle.c by Sundar Iyer.
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/hrtimer.h>
+#include <linux/sched.h>
+#include <linux/tick.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+
+#include <asm/hardware/gic.h>
+#include <mach/prcmu-fw-api.h>
+#include <mach/prcmu-regs.h>
+#include "cpuidle.h"
+#include "context.h"
+#include "pm-common.h"
+#include "regulator-u8500.h"
+
+#define NUM_CSTATES 5
+#define MAX_INT 0x7ffffff;
+#define DEEP_SLEEP_WAKE_UP_LATENCY 8500
+#define SLEEP_WAKE_UP_LATENCY 200
+#define UL_PLL_START_UP_LATENCY 8000
+#define DBG_BUF_SIZE 5000
+#define APE_ON_TIMER_INTERVAL 5 /* Seconds */
+
+enum sleep_state {
+ STATE_AP_WFI,
+ STATE_AP_IDLE,
+ STATE_AP_SLEEP,
+ STATE_AP_DEEP_SLEEP
+};
+
+/* Idle statistics */
+struct idle_stat {
+ u32 ap_idle_counter;
+ u32 ap_sleep_counter;
+ u32 ap_deep_sleep_counter;
+};
+
+struct cstate cstates[] = {
+ {
+ .enter_sleep_latency = 0,
+ .wakeup_latency = 0,
+ .threshold = 0,
+ .power_usage = 10,
+ .APE = APE_ON,
+ .ARM = ARM_ON,
+ .ARM_PLL = ARM_PLL_ON,
+ .UL_PLL = UL_PLL_ON,
+ .ESRAM = ESRAM_RET,
+ .flags = CPUIDLE_FLAG_SHALLOW | CPUIDLE_FLAG_TIME_VALID,
+ .desc = "Wait for interrupt",
+ },
+ {
+ .enter_sleep_latency = 400,
+ .wakeup_latency = 50,
+ .threshold = 500,
+ .power_usage = 5,
+ .APE = APE_ON,
+ .ARM = ARM_RET,
+ .ARM_PLL = ARM_PLL_ON,
+ .UL_PLL = UL_PLL_ON,
+ .ESRAM = ESRAM_RET,
+ .flags = CPUIDLE_FLAG_SHALLOW | CPUIDLE_FLAG_TIME_VALID,
+ .desc = "ApIdle",
+ },
+ {
+ .enter_sleep_latency = 400,
+ .wakeup_latency = 170,
+ .threshold = 600,
+ .power_usage = 4,
+ .APE = APE_ON,
+ .ARM = ARM_RET,
+ .ARM_PLL = ARM_PLL_OFF,
+ .UL_PLL = UL_PLL_ON,
+ .ESRAM = ESRAM_RET,
+ .flags = CPUIDLE_FLAG_SHALLOW | CPUIDLE_FLAG_TIME_VALID,
+ .desc = "ApIdle, ARM PLL off",
+ },
+ {
+ .enter_sleep_latency = 50,
+ .wakeup_latency = SLEEP_WAKE_UP_LATENCY,
+ .threshold = 800,
+ .power_usage = 3,
+ .APE = APE_OFF,
+ .ARM = ARM_RET,
+ .ARM_PLL = ARM_PLL_OFF,
+ .UL_PLL = UL_PLL_ON,
+ .ESRAM = ESRAM_RET,
+ .flags = CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_TIME_VALID,
+ .desc = "ApSleep",
+ },
+ {
+ .enter_sleep_latency = 200,
+ .wakeup_latency = DEEP_SLEEP_WAKE_UP_LATENCY,
+ .threshold = 8700,
+ .power_usage = 1,
+ .APE = APE_OFF,
+ .ARM = ARM_OFF,
+ .ARM_PLL = ARM_PLL_OFF,
+ .UL_PLL = UL_PLL_OFF,
+ .ESRAM = ESRAM_RET,
+ .flags = CPUIDLE_FLAG_DEEP | CPUIDLE_FLAG_TIME_VALID,
+ .desc = "ApDeepsleep, UL PLL off",
+ },
+
+};
+
+static void migrate_to_always_on_timer(int cpu);
+static void migrate_to_local_timer(int cpu);
+
+static DEFINE_SPINLOCK(cpuidle_lock);
+static bool restore_ape; /* protected by cpuidle_lock */
+static bool restore_arm_common; /* protected by cpuidle_lock */
+static DEFINE_PER_CPU(bool, restore_arm_core); /* protected by cpuidle_lock */
+static DEFINE_PER_CPU(bool, ready_deep_sleep);
+static DEFINE_PER_CPU(bool, always_on_timer_migrated);
+static DEFINE_PER_CPU(ktime_t, sched_wake_up); /* protected by cpuidle_lock */
+static DEFINE_PER_CPU(struct cpuidle_device, cpuidle_dev);
+static bool force_APE_on;
+static u8 deepest_allowed_state = 2;
+
+
+#ifdef CONFIG_DEBUG_FS
+ /* These variables are protected by cpuidle_lock */
+static DEFINE_PER_CPU(unsigned long long, ap_idle_time);
+static DEFINE_PER_CPU(unsigned long long, ap_sleep_time);
+static DEFINE_PER_CPU(unsigned long long, ap_deep_sleep_time);
+static struct idle_stat stat;
+static ktime_t time_zero;
+static struct delayed_work cpuidle_work;
+static bool dbg_console_enable;
+static void __iomem *uart2_base;
+#endif
+
+#ifdef CPUIDLE_DBG
+static void dbg_mess(char *dbg_string)
+{
+ static char dbg_buf[DBG_BUF_SIZE];
+ static int index; /* protected by cpuidle_lock */
+ int str_len;
+ int smp_no_len;
+ int head_len;
+ unsigned long iflags;
+ static const char * const smp_no_str = "\n %d:";
+ static const char * const head_str = ":HEAD->";
+
+ spin_lock_irqsave(&cpuidle_lock, iflags);
+
+ str_len = strlen(dbg_string);
+ smp_no_len = strlen(smp_no_str);
+ head_len = strlen(head_str);
+
+ if (index > head_len) {
+ /* Remove last head printing */
+ index -= head_len;
+ }
+
+ if ((index + str_len + smp_no_len + head_len) > DBG_BUF_SIZE)
+ index = 0; /* Non perfect wrapping... */
+
+ sprintf(&dbg_buf[index], smp_no_str, smp_processor_id());
+ index += smp_no_len;
+
+ strcpy(&dbg_buf[index], dbg_string);
+ index += str_len;
+
+ strcpy(&dbg_buf[index], head_str);
+ index += head_len;
+
+ spin_unlock_irqrestore(&cpuidle_lock, iflags);
+}
+#else
+#define dbg_mess(x)
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+
+#define UART2_RX_GPIO_PIN_MASK 0x20000000
+#define GPIO_BK0_DAT (IO_ADDRESS(U8500_PER1_BASE + 0xE000))
+#define UART2_GPIO_PIN_NR 29
+
+static void dbg_handle_console_uart_during_resume_ape(void)
+{
+ if (dbg_console_enable) {
+
+ u32 WKS_reg_value;
+
+ read_gpio_wake_up_status(0, &WKS_reg_value);
+
+ if (WKS_reg_value & UART2_RX_GPIO_PIN_MASK) {
+
+ cancel_delayed_work_sync(&cpuidle_work);
+ force_APE_on = true;
+ schedule_delayed_work(&cpuidle_work,
+ msecs_to_jiffies(APE_ON_TIMER_INTERVAL *
+ 1000));
+ }
+
+ /* Disable pull up on uart2 rx */
+ writel(readl(GPIO_BK0_DAT) & (~UART2_RX_GPIO_PIN_MASK),
+ GPIO_BK0_DAT);
+ }
+
+}
+
+#define UART011_MIS_RTIS (1 << 6) /* receive timeout interrupt status */
+#define UART011_MIS_RXIS (1 << 4) /* receive interrupt status */
+#define UART011_MIS 0x40 /* Masked interrupt status register */
+
+static void dbg_handle_console_uart(void)
+{
+ if (dbg_console_enable) {
+
+ u32 status = readw(uart2_base + UART011_MIS);
+
+ if (status & (UART011_MIS_RTIS | UART011_MIS_RXIS)) {
+ cancel_delayed_work_sync(&cpuidle_work);
+ force_APE_on = true;
+ schedule_delayed_work(&cpuidle_work,
+ msecs_to_jiffies(APE_ON_TIMER_INTERVAL *
+ 1000));
+ }
+ }
+}
+
+static void dbg_cpuidle_work_function(struct work_struct *work)
+{
+ force_APE_on = false;
+}
+
+static void dbg_handle_console_uart_init(void)
+{
+ uart2_base = ioremap(UX500_UART2_BASE, SZ_4K);
+ INIT_DELAYED_WORK(&cpuidle_work, dbg_cpuidle_work_function);
+
+ /* pull up enable on uart2 rx */
+ writel(readl(GPIO_BK0_DAT) | UART2_RX_GPIO_PIN_MASK, GPIO_BK0_DAT);
+ set_irq_type(GPIO_TO_IRQ(UART2_GPIO_PIN_NR), IRQ_TYPE_EDGE_BOTH);
+ set_irq_wake(GPIO_TO_IRQ(UART2_GPIO_PIN_NR), 1);
+}
+
+void dbg_log_time_state(enum sleep_state sleep_state, ktime_t start,
+ ktime_t stop)
+{
+ unsigned long iflags;
+ int cpu;
+ s64 diff;
+
+ cpu = smp_processor_id();
+
+ diff = ktime_to_us(ktime_sub(stop, start));
+
+ spin_lock_irqsave(&cpuidle_lock, iflags);
+
+ switch (sleep_state) {
+
+ case STATE_AP_IDLE:
+ stat.ap_idle_counter++;
+ per_cpu(ap_idle_time, cpu) += diff;
+ break;
+
+ case STATE_AP_SLEEP:
+ stat.ap_sleep_counter++;
+ per_cpu(ap_sleep_time, cpu) += diff;
+ break;
+
+ case STATE_AP_DEEP_SLEEP:
+ stat.ap_deep_sleep_counter++;
+ per_cpu(ap_deep_sleep_time, cpu) += diff;
+ break;
+
+ default:
+ break;
+ }
+
+ spin_unlock_irqrestore(&cpuidle_lock, iflags);
+}
+
+static ssize_t set_deepest_state(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+
+ char buf[32];
+ ssize_t buf_size;
+ long unsigned int i;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ if (strict_strtoul(buf, 0, &i) != 0)
+ return buf_size;
+
+ if (i > ARRAY_SIZE(cstates) - 1)
+ i = ARRAY_SIZE(cstates) - 1;
+
+ deepest_allowed_state = i;
+
+ pr_debug("cpuidle: changed deepest allowed sleep state to %d.\n",
+ deepest_allowed_state);
+
+ return buf_size;
+}
+
+static int deepest_state_print(struct seq_file *s, void *p)
+{
+ seq_printf(s, "Deepest allowed sleep state is %d\n",
+ deepest_allowed_state);
+
+ return 0;
+}
+
+static ssize_t stats_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int cpu;
+
+ printk(KERN_INFO "\nreset\n");
+
+ stat.ap_idle_counter = 0;
+ stat.ap_sleep_counter = 0;
+ stat.ap_deep_sleep_counter = 0;
+
+ for_each_possible_cpu(cpu) {
+ per_cpu(ap_idle_time, cpu) = 0;
+ per_cpu(ap_sleep_time, cpu) = 0;
+ per_cpu(ap_deep_sleep_time, cpu) = 0;
+ }
+
+ time_zero = ktime_get();
+
+ return count;
+}
+
+static int stats_print(struct seq_file *s, void *p)
+{
+ unsigned int cpu;
+ unsigned long long perc_ap_idle = 0;
+ unsigned long long perc_ap_sleep = 0;
+ unsigned long long perc_ap_deep_sleep = 0;
+ s64 uptime_in_us;
+
+ seq_printf(s, "ApIdle counter: %d\n"
+ "ApSleep counter: %d\n"
+ "ApDeepSleep counter: %d\n",
+ stat.ap_idle_counter,
+ stat.ap_sleep_counter,
+ stat.ap_deep_sleep_counter);
+
+ uptime_in_us = ktime_to_us(ktime_sub(ktime_get(), time_zero));
+
+ /* Take all online cpus inte account */
+ uptime_in_us *= num_online_cpus();
+
+ /* We want the end result in percentage */
+ do_div(uptime_in_us, 100);
+
+ /* Check how much each core has sent the system to ApIdle */
+ for_each_online_cpu(cpu)
+ perc_ap_idle += per_cpu(ap_idle_time, cpu);
+
+ do_div(perc_ap_idle, uptime_in_us);
+
+ /* Check how much each core has sent the system to ApSleep */
+ for_each_online_cpu(cpu)
+ perc_ap_sleep += per_cpu(ap_sleep_time, cpu);
+
+ do_div(perc_ap_sleep, uptime_in_us);
+
+ /* Check how much each core has sent the system to ApDeepSleep */
+ for_each_online_cpu(cpu)
+ perc_ap_deep_sleep += per_cpu(ap_deep_sleep_time, cpu);
+
+ do_div(perc_ap_deep_sleep, uptime_in_us);
+
+ seq_printf(s,
+ "\nApIdle (%%): %d\n"
+ "ApSleep (%%): %d\n"
+ "ApDeepSleep (%%): %d\n",
+ (int)perc_ap_idle,
+ (int)perc_ap_sleep,
+ (int)perc_ap_deep_sleep);
+
+ return 0;
+}
+
+static ssize_t dbg_console(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+
+ char buf[32];
+ ssize_t buf_size;
+ long unsigned int i;
+ static bool first_time = true;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ if (strict_strtoul(buf, 0, &i) != 0)
+ return buf_size;
+
+ if (i > 0) {
+ if (first_time) {
+ first_time = false;
+ dbg_handle_console_uart_init();
+ }
+ smp_mb();
+ dbg_console_enable = true;
+ } else
+ dbg_console_enable = false;
+
+ pr_debug("cpuidle: debug console status %d.\n",
+ dbg_console_enable);
+
+ return buf_size;
+}
+
+static int dbg_console_print(struct seq_file *s, void *p)
+{
+ seq_printf(s, "debug console status %d\n",
+ dbg_console_enable);
+
+ return 0;
+}
+
+static int deepest_state_open_file(struct inode *inode, struct file *file)
+{
+ return single_open(file, deepest_state_print, inode->i_private);
+}
+
+static int stats_open_file(struct inode *inode, struct file *file)
+{
+ return single_open(file, stats_print, inode->i_private);
+}
+
+static int dbg_console_open_file(struct inode *inode, struct file *file)
+{
+ return single_open(file, dbg_console_print, inode->i_private);
+}
+
+static const struct file_operations deepest_state_fops = {
+ .open = deepest_state_open_file,
+ .write = set_deepest_state,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations stats_fops = {
+ .open = stats_open_file,
+ .write = stats_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations dbg_console_fops = {
+ .open = dbg_console_open_file,
+ .write = dbg_console,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static struct dentry *cpuidle_dir;
+static struct dentry *deepest_state_file;
+static struct dentry *stats_file;
+static struct dentry *dbg_console_file;
+
+static void setup_debugfs(void)
+{
+ cpuidle_dir = debugfs_create_dir("cpuidle", NULL);
+ if (!cpuidle_dir)
+ goto exit_no_debugfs;
+
+ deepest_state_file = debugfs_create_file("deepest_state",
+ S_IWUGO, cpuidle_dir, NULL,
+ &deepest_state_fops);
+ if (!deepest_state_file)
+ goto exit_destroy_dir;
+
+ stats_file = debugfs_create_file("stats",
+ S_IRUGO, cpuidle_dir, NULL,
+ &stats_fops);
+ if (!stats_file)
+ goto exit_destroy_deepest_state;
+
+ dbg_console_file = debugfs_create_file("dbg_console_enable",
+ S_IWUGO, cpuidle_dir, NULL,
+ &dbg_console_fops);
+ if (!dbg_console_file)
+ goto exit_destroy_stats;
+
+
+ return;
+
+exit_destroy_stats:
+ debugfs_remove(stats_file);
+exit_destroy_deepest_state:
+ debugfs_remove(deepest_state_file);
+exit_destroy_dir:
+ debugfs_remove(cpuidle_dir);
+exit_no_debugfs:
+ return;
+}
+
+static inline void remove_debugfs(void)
+{
+ debugfs_remove(deepest_state_file);
+ debugfs_remove(cpuidle_dir);
+}
+#else
+#define dbg_handle_console_uart_during_resume_ape(x)
+#define dbg_handle_console_uart(x)
+#define dbg_log_time_state(x, y, z)
+#define setup_debugfs(x)
+#define remove_debugfs(x)
+#endif
+
+static void do_nothing(void *unused)
+{
+}
+
+/*
+ * cpu_idle_wait - Used to ensure that all the CPUs discard old value of
+ * pm_idle and update to new pm_idle value. Required while changing pm_idle
+ * handler on SMP systems.
+ *
+ * Caller must have changed pm_idle to the new value before the call. Old
+ * pm_idle value will not be used by any CPU after the return of this function.
+ */
+void cpu_idle_wait(void)
+{
+ smp_mb();
+ /* kick all the CPUs so that they exit out of pm_idle */
+ smp_call_function(do_nothing, NULL, 1);
+}
+EXPORT_SYMBOL_GPL(cpu_idle_wait);
+
+static void migrate_to_always_on_timer(int cpu)
+{
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
+ &cpu);
+
+ per_cpu(always_on_timer_migrated, cpu) = true;
+ smp_wmb();
+}
+
+static void migrate_to_local_timer(int cpu)
+{
+ /* Use the ARM local timer for this cpu */
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
+ &cpu);
+
+ per_cpu(always_on_timer_migrated, cpu) = false;
+ smp_wmb();
+}
+
+static void restore_sequence(void)
+{
+ unsigned long iflags;
+ ktime_t t;
+ int this_cpu;
+
+ this_cpu = smp_processor_id();
+
+
+ spin_lock_irqsave(&cpuidle_lock, iflags);
+
+ /*
+ * Remove wake up time i.e. set wake up
+ * far ahead
+ */
+ t = ktime_add_us(ktime_get(), 1000000000); /* 16 minutes ahead */
+ per_cpu(sched_wake_up, this_cpu) = t;
+ smp_wmb();
+
+ smp_rmb();
+ if (per_cpu(restore_arm_core, this_cpu)) {
+
+ per_cpu(restore_arm_core, this_cpu) = false;
+ smp_wmb();
+
+ context_varm_restore_core();
+ }
+
+ smp_rmb();
+ if (restore_arm_common) {
+
+ restore_arm_common = false;
+ smp_wmb();
+
+ /* Restore gic settings */
+ context_varm_restore_common();
+ }
+
+ smp_rmb();
+ if (restore_ape) {
+
+ restore_ape = false;
+ smp_wmb();
+
+ /*
+ * APE has been turned off. Save GPIO wake up cause before
+ * clearing ioforce.
+ */
+ context_vape_restore();
+
+ catch_gpio_wake_up_status();
+
+ /* Restore IO ring */
+ prcmu_clr_ioforce();
+
+ dbg_handle_console_uart_during_resume_ape();
+
+ }
+
+ spin_unlock_irqrestore(&cpuidle_lock, iflags);
+
+ smp_rmb();
+ if (per_cpu(always_on_timer_migrated, this_cpu))
+ migrate_to_local_timer(this_cpu);
+
+
+}
+
+static void prcmu_set_wakeup_timer(int timerticks)
+{
+ /* TODO: Set-up the PRCMU timer */
+}
+
+/**
+ * get_remaining_sleep_time() - returns remaining sleep time in
+ * microseconds (us)
+ */
+static int get_remaining_sleep_time(void)
+{
+ ktime_t now;
+ int cpu;
+ unsigned long iflags;
+ int t;
+ int remaining_sleep_time = MAX_INT;
+
+ now = ktime_get();
+
+ /*
+ * Check next schedule to expire considering both
+ * cpus
+ */
+ spin_lock_irqsave(&cpuidle_lock, iflags);
+ for_each_online_cpu(cpu) {
+ t = ktime_to_us(ktime_sub(per_cpu(sched_wake_up, cpu),
+ now));
+ if (t < remaining_sleep_time)
+ remaining_sleep_time = t;
+ }
+ spin_unlock_irqrestore(&cpuidle_lock, iflags);
+
+ return remaining_sleep_time;
+}
+
+static bool cores_ready_deep_sleep(void)
+{
+ int cpu;
+ int this_cpu;
+
+ this_cpu = smp_processor_id();
+
+ for_each_possible_cpu(cpu) {
+ if (cpu != this_cpu) {
+ smp_rmb();
+ if (!per_cpu(ready_deep_sleep, cpu))
+ return false;
+ }
+ }
+
+ return true;
+
+}
+
+static bool cores_timer_migrated(void)
+{
+ int cpu;
+ int this_cpu;
+
+ this_cpu = smp_processor_id();
+
+ for_each_possible_cpu(cpu) {
+ if (cpu != this_cpu) {
+ smp_rmb();
+ if (!per_cpu(always_on_timer_migrated, cpu))
+ return false;
+ }
+ }
+
+ return true;
+
+}
+
+static struct cstate *determine_sleep_state(int idle_cpus,
+ struct cstate *gov_cstate)
+{
+ int i;
+ int sleep_time;
+ bool power_state_req;
+
+ if (idle_cpus < num_possible_cpus()) {
+ /* Go to most shallow sleep state */
+ return &cstates[0];
+ }
+
+ power_state_req = power_state_active_is_enabled();
+
+ sleep_time = get_remaining_sleep_time();
+
+ /*
+ * Never go deeper than the governor recommends even though it might be
+ * possible from a scheduled wake up point of view
+ */
+ i = gov_cstate - cstates;
+
+ if (i > deepest_allowed_state)
+ i = deepest_allowed_state;
+
+ /*
+ * The variable "i" now contains the index of the deepest sleep state
+ * we can go to right now
+ */
+
+ while (i > 0) {
+ if (sleep_time > cstates[i].threshold) {
+
+ /* We sleep long enough for this state */
+
+ if ((cstates[i].ARM != ARM_ON) &&
+ !cores_timer_migrated()) {
+ /*
+ * This sleep state needs timer migration,
+ * but other cpu has not migrated its timer
+ */
+ i--;
+ } else if (cstates[i].APE == APE_OFF) {
+
+ /* This state says APE should be off */
+
+ if (!(power_state_req || force_APE_on)) {
+
+ /* APE can be turned off for sure */
+
+ if (cstates[i].ARM == ARM_OFF) {
+ /* Deep sleep state */
+
+ if (cores_ready_deep_sleep()) {
+ /* OK with deep sleep */
+
+ break; /* valid state */
+ } else {
+ /* Not OK state */
+ i--;
+ }
+
+
+ } else {
+ /* Valid Sleep state */
+ break;
+ }
+ } else {
+ /* Can not turn off APE */
+ i--;
+ }
+
+ } else {
+ /* OK state */
+ break;
+ }
+ } else {
+ /*
+ * We do not sleep long enough for this state =>
+ * go to next
+ */
+ i--;
+ }
+ } /* while */
+ return &cstates[i];
+
+}
+
+static int enter_sleep(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+{
+ ktime_t t1, t2;
+ s64 diff;
+ int ret;
+ bool pending_int;
+ int cpu;
+ int this_cpu;
+ struct cstate *target_cstate;
+ struct cstate *gov_cstate;
+ unsigned long iflags;
+ int idle_cpus;
+ static atomic_t idle_cpus_counter = ATOMIC_INIT(0);
+
+ local_irq_disable();
+
+ t1 = ktime_get(); /* Time now */
+ this_cpu = smp_processor_id();
+
+ /* Save scheduled wake up for this cpu */
+ spin_lock_irqsave(&cpuidle_lock, iflags);
+ per_cpu(sched_wake_up, this_cpu) =
+ ktime_add(t1, tick_nohz_get_sleep_length());
+ spin_unlock_irqrestore(&cpuidle_lock, iflags);
+
+ /*
+ * Retrive the cstate that the governor recommends
+ * for this CPU
+ */
+ gov_cstate = cpuidle_get_statedata(state);
+
+ idle_cpus = atomic_inc_return(&idle_cpus_counter);
+
+ /*
+ * Determine sleep state considering both CPUs and
+ * shared resources like e.g. VAPE
+ */
+ target_cstate = determine_sleep_state(idle_cpus,
+ gov_cstate);
+
+ if (target_cstate->ARM == ARM_ON) {
+
+ if (gov_cstate->ARM == ARM_OFF) {
+
+ dbg_mess("WFI_prep");
+
+ /*
+ * Can not turn off arm now, but it might be
+ * possible later, so prepare for it by saving
+ * context of cpu etc already now.
+ */
+
+ /*
+ * ARM timers will stop during ARM retention or
+ * ARM off mode. Use always-on-timer instead.
+ */
+ migrate_to_always_on_timer(this_cpu);
+
+ context_varm_save_core();
+ context_save_cpu_registers();
+ per_cpu(ready_deep_sleep, this_cpu) = true;
+ smp_wmb();
+
+ /*
+ * Save return address to SRAM and set this
+ * CPU in WFI
+ */
+ context_save_to_sram_and_wfi(false);
+
+ per_cpu(ready_deep_sleep, this_cpu) = false;
+ smp_wmb();
+
+ context_restore_cpu_registers();
+
+ } else if (gov_cstate->ARM != ARM_ON) {
+
+ /*
+ * Can not go ApIdle or deeper now, but it
+ * might be possible later, so prepare for it
+ */
+
+ /*
+ * ARM timers will stop during ARM retention or
+ * ARM off mode. Use always-on-timer instead.
+ */
+ migrate_to_always_on_timer(this_cpu);
+
+ dbg_mess("WFI_prep2");
+
+ __asm__ __volatile__
+ ("dsb\n\t" "wfi\n\t" : : : "memory");
+
+
+ } else { /* Just WFI */
+
+ dbg_mess("WFI");
+
+ __asm__ __volatile__
+ ("dsb\n\t" "wfi\n\t" : : : "memory");
+ }
+
+ restore_sequence();
+
+ goto exit;
+ }
+
+ if (target_cstate->APE == APE_OFF) {
+ /*
+ * Moved here for testing. We do not want to restore
+ * experimental GPIO settings
+ */
+ context_vape_save();
+ }
+
+ prcmu_configure_wakeup_events((PRCMU_WAKEUPBY_ARMITMGMT |
+ PRCMU_WAKEUPBY_GPIOS |
+ PRCMU_WAKEUPBY_RTCRTT),
+ 0, 0);
+
+ /* Decouple GIC from the interrupt bus */
+ decouple_gic();
+
+ migrate_to_always_on_timer(this_cpu);
+
+ /* Check pending interrupts */
+ pending_int = pending_gic_interrupt();
+
+ idle_cpus = atomic_read(&idle_cpus_counter);
+
+ /*
+ * Check if we have a pending interrupt or if sleep
+ * state has changed after GIC has been frozen
+ */
+ if (pending_int ||
+ (target_cstate != determine_sleep_state(idle_cpus, gov_cstate))) {
+ /* Pending interrupt or sleep state has changed => abort */
+
+ prcmu_configure_wakeup_events(0, 0, 0);
+
+ /* Recouple GIC with the interrupt bus */
+ recouple_gic();
+ migrate_to_local_timer(this_cpu);
+
+ goto exit;
+ }
+
+ /*
+ * Copy GIC interrupt settings to
+ * PRCMU interrupt settings
+ */
+ copy_gic_settings_to_prcmu();
+
+ /* Clean the cache before slowing down cpu frequency */
+ context_clean_l1_cache_all();
+
+ run_arm_on_ext_clk(target_cstate->ARM_PLL);
+
+ if (pending_prcmu_interrupt()) {
+
+ /* An interrupt found => abort */
+
+ run_arm_on_arm_pll(target_cstate->ARM_PLL);
+
+ prcmu_configure_wakeup_events(0, 0, 0);
+
+ /* Recouple GIC with the interrupt bus */
+ recouple_gic();
+
+ migrate_to_local_timer(this_cpu);
+
+ goto exit;
+
+ }
+
+ /*
+ * No PRCMU interrupt was pending => continue
+ * the sleeping stages
+ */
+ if (target_cstate->APE == APE_OFF) {
+
+ /* We are going to sleep or deep sleep. */
+
+ prcmu_set_ioforce();
+
+ spin_lock_irqsave(&cpuidle_lock, iflags);
+ restore_ape = true;
+ smp_wmb();
+ spin_unlock_irqrestore(&cpuidle_lock, iflags);
+
+ if (target_cstate->ARM == ARM_OFF) {
+
+ /* Save gic settings */
+ context_varm_save_common();
+
+ if (target_cstate->UL_PLL == UL_PLL_OFF) {
+ /* ULPLL should be turned off */
+
+ int time;
+
+ time = get_remaining_sleep_time();
+
+ /* Compensate for ULPLL start up time */
+ time -= UL_PLL_START_UP_LATENCY;
+
+ /* TODO: Compensate for ESRAM0 handling time
+ * if (!target_cstate->ESRAM)
+ * Compensate...
+ */
+
+ if (time > 0)
+ prcmu_set_wakeup_timer(time);
+ /* TODO: Control ULPLL */
+ }
+
+ context_varm_save_core();
+
+ spin_lock_irqsave(&cpuidle_lock, iflags);
+ restore_arm_common = true;
+ for_each_online_cpu(cpu) {
+ per_cpu(restore_arm_core,
+ cpu) = true;
+ smp_wmb();
+ }
+
+ spin_unlock_irqrestore(&cpuidle_lock, iflags);
+
+ context_save_cpu_registers();
+
+ per_cpu(ready_deep_sleep, this_cpu) = true;
+ smp_wmb();
+
+ dbg_mess("ApDeep");
+
+ /* ApDeepSleep */
+ prcmu_set_power_state(PRCMU_AP_DEEP_SLEEP);
+
+ /*
+ * Save return address to SRAM and set this CPU in WFI.
+ * This is last core to enter sleep, so we need to
+ * clean both L2 and L1 caches
+ */
+ context_save_to_sram_and_wfi(true);
+
+ dbg_log_time_state(STATE_AP_DEEP_SLEEP, t1,
+ ktime_get());
+
+ } else {
+ /*
+ * Prepare for possible future deep sleep. We do not
+ * need to save varm common context at this stage
+ * because we can not go from ApSleep directly to
+ * ApDeepSleep without waking up any CPU
+ */
+
+ context_varm_save_core();
+
+ context_save_cpu_registers();
+
+ per_cpu(ready_deep_sleep, this_cpu) = true;
+ smp_wmb();
+
+ dbg_mess("ApSleep");
+
+ /* ApSleep */
+ prcmu_set_power_state(PRCMU_AP_SLEEP);
+
+ /* Handle DDR, ULPLL, SOC PLL and ARM PLL via
+ prcmu-API. */
+
+ context_save_to_sram_and_wfi(false);
+
+ dbg_log_time_state(STATE_AP_SLEEP, t1, ktime_get());
+
+ }
+
+ } else { /* We are going to Idle state */
+
+ context_varm_save_core();
+
+ context_save_cpu_registers();
+
+ per_cpu(ready_deep_sleep, this_cpu) = true;
+ smp_wmb();
+
+ dbg_mess("ApIdle");
+
+ /* ApIdle */
+ prcmu_set_power_state(PRCMU_AP_IDLE);
+
+ context_save_to_sram_and_wfi(false);
+
+ dbg_log_time_state(STATE_AP_IDLE, t1, ktime_get());
+ }
+
+ /* The PRCMU restores ARM PLL and recouples the GIC */
+
+ per_cpu(ready_deep_sleep, this_cpu) = false;
+ smp_wmb();
+
+ context_restore_cpu_registers();
+ restore_sequence();
+
+exit:
+ prcmu_configure_wakeup_events(0, 0, 0);
+
+ atomic_dec(&idle_cpus_counter);
+
+ /* We might have chosen another state than what the
+ governor recommended */
+ if (target_cstate != gov_cstate) {
+ int i;
+
+ /* Determine state index */
+ i = target_cstate - cstates;
+
+ /* Update last state pointer used by CPUIDLE subsystem */
+ dev->last_state = &(dev->states[i]);
+ }
+
+ t2 = ktime_get();
+ diff = ktime_to_us(ktime_sub(t2, t1));
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+
+ ret = (int)diff;
+
+ dbg_handle_console_uart();
+
+ local_irq_enable();
+
+ return ret;
+}
+
+static void init_cstates(unsigned int cpu)
+{
+ int i;
+ struct cstate *cstate;
+ struct cpuidle_state *state;
+ struct cpuidle_device *dev;
+
+ dev = &per_cpu(cpuidle_dev, cpu);
+ dev->cpu = cpu;
+
+ for (i = 0; i < ARRAY_SIZE(cstates); i++) {
+ cstate = &cstates[i];
+ state = &dev->states[i];
+
+ cpuidle_set_statedata(state, cstate);
+
+ state->exit_latency =
+ cstate->enter_sleep_latency + cstate->wakeup_latency;
+ state->target_residency = cstate->threshold;
+ state->flags = cstate->flags;
+ state->enter = enter_sleep;
+ state->power_usage = cstate->power_usage;
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
+ strncpy(state->desc, cstate->desc, CPUIDLE_DESC_LEN);
+ }
+
+ dev->state_count = ARRAY_SIZE(cstates);
+
+ dev->safe_state = &dev->states[0]; /* Currently not used */
+
+ if (cpuidle_register_device(dev)) {
+ printk(KERN_ERR "cpuidle %s: register device failed\n",
+ __func__);
+ return;
+ }
+
+ pr_debug("cpuidle driver initiated for CPU%d.\n", cpu);
+}
+
+struct cpuidle_driver cpuidle_drv = {
+ .name = "cpuidle_driver",
+ .owner = THIS_MODULE,
+};
+
+static int __init cpuidle_driver_init(void)
+{
+ int result = 0;
+ int cpu;
+
+ result = cpuidle_register_driver(&cpuidle_drv);
+ if (result < 0)
+ return result;
+
+ for_each_online_cpu(cpu)
+ init_cstates(cpu);
+
+ /* Expose debugfs interface */
+ setup_debugfs();
+
+ return result;
+}
+
+static void __exit cpuidle_driver_exit(void)
+{
+ int cpu;
+ struct cpuidle_device *dev;
+
+ remove_debugfs();
+
+ for_each_possible_cpu(cpu) {
+ dev = &per_cpu(cpuidle_dev, cpu);
+ cpuidle_unregister_device(dev);
+ }
+
+ cpuidle_unregister_driver(&cpuidle_drv);
+}
+
+module_init(cpuidle_driver_init);
+module_exit(cpuidle_driver_exit);
+
+MODULE_DESCRIPTION("U8500 cpuidle driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rickard Andersson <rickard.andersson@stericsson.com>");
diff --git a/arch/arm/mach-ux500/cpuidle.h b/arch/arm/mach-ux500/cpuidle.h
new file mode 100644
index 00000000000..e6eed753ac9
--- /dev/null
+++ b/arch/arm/mach-ux500/cpuidle.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Rickard Andersson <rickard.andersson@stericsson.com> for
+ * ST-Ericsson. Loosly based on cpuidle.c by Sundar Iyer.
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ */
+
+#ifndef __CPUIDLE_H
+#define __CPUIDLE_H
+
+#include <linux/cpuidle.h>
+
+enum ARM {
+ ARM_OFF,
+ ARM_RET,
+ ARM_ON
+};
+
+enum APE {
+ APE_OFF,
+ APE_ON
+};
+
+enum ARM_PLL {
+ ARM_PLL_OFF,
+ ARM_PLL_ON
+};
+
+enum UL_PLL {
+ UL_PLL_OFF,
+ UL_PLL_ON
+};
+
+enum ESRAM {
+ ESRAM_OFF,
+ ESRAM_RET
+};
+
+struct cstate {
+ /* Required state of different hardwares */
+ enum ARM ARM;
+ enum APE APE;
+ enum ARM_PLL ARM_PLL;
+ enum UL_PLL UL_PLL;
+ /* ESRAM = ESRAM_RET means that ESRAM context to be kept */
+ enum ESRAM ESRAM;
+
+ u32 enter_sleep_latency;
+ u32 wakeup_latency;
+ u32 power_usage;
+ u32 threshold;
+ u32 flags;
+ char desc[CPUIDLE_DESC_LEN];
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/devices-common.c b/arch/arm/mach-ux500/devices-common.c
new file mode 100644
index 00000000000..9376a246f86
--- /dev/null
+++ b/arch/arm/mach-ux500/devices-common.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
+
+#include <mach/hardware.h>
+
+#include "devices-common.h"
+
+struct amba_device *
+dbx500_add_amba_device(const char *name, resource_size_t base,
+ int irq, void *pdata, unsigned int periphid)
+{
+ struct amba_device *dev;
+ int ret;
+
+ dev = kzalloc(sizeof *dev, GFP_KERNEL);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ dev->dev.init_name = name;
+
+ dev->res.start = base;
+ dev->res.end = base + SZ_4K - 1;
+ dev->res.flags = IORESOURCE_MEM;
+
+ dev->dma_mask = DMA_BIT_MASK(32);
+ dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ dev->irq[0] = irq;
+ dev->irq[1] = NO_IRQ;
+
+ dev->periphid = periphid;
+
+ dev->dev.platform_data = pdata;
+
+ ret = amba_device_register(dev, &iomem_resource);
+ if (ret) {
+ kfree(dev);
+ return ERR_PTR(ret);
+ }
+
+ return dev;
+}
+
+static struct platform_device *
+dbx500_add_platform_device(const char *name, int id, void *pdata,
+ struct resource *res, int resnum)
+{
+ struct platform_device *dev;
+ int ret;
+
+ dev = platform_device_alloc(name, id);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
+
+ ret = platform_device_add_resources(dev, res, resnum);
+ if (ret)
+ goto out_free;
+
+ dev->dev.platform_data = pdata;
+
+ ret = platform_device_add(dev);
+ if (ret)
+ goto out_free;
+
+ return dev;
+
+out_free:
+ platform_device_put(dev);
+ return ERR_PTR(ret);
+}
+
+struct platform_device *
+dbx500_add_platform_device_4k1irq(const char *name, int id,
+ resource_size_t base,
+ int irq, void *pdata)
+{
+ struct resource resources[] = {
+ [0] = {
+ .start = base,
+ .end = base + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = irq,
+ .end = irq,
+ .flags = IORESOURCE_IRQ,
+ }
+ };
+
+ return dbx500_add_platform_device(name, id, pdata, resources,
+ ARRAY_SIZE(resources));
+}
diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h
new file mode 100644
index 00000000000..0dd8f06f93e
--- /dev/null
+++ b/arch/arm/mach-ux500/devices-common.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __DEVICES_COMMON_H
+#define __DEVICES_COMMON_H
+
+extern struct amba_device *
+dbx500_add_amba_device(const char *name, resource_size_t base,
+ int irq, void *pdata, unsigned int periphid);
+
+extern struct platform_device *
+dbx500_add_platform_device_4k1irq(const char *name, int id,
+ resource_size_t base,
+ int irq, void *pdata);
+
+struct spi_master_cntlr;
+
+static inline struct amba_device *
+dbx500_add_msp_spi(const char *name, resource_size_t base, int irq,
+ struct spi_master_cntlr *pdata)
+{
+ return dbx500_add_amba_device(name, base, irq, pdata, MSP_PER_ID);
+}
+
+struct pl022_ssp_controller;
+
+static inline struct amba_device *
+dbx500_add_spi(const char *name, resource_size_t base, int irq,
+ struct pl022_ssp_controller *pdata)
+{
+ return dbx500_add_amba_device(name, base, irq, pdata, SPI_PER_ID);
+}
+
+struct mmc_board;
+
+static inline struct amba_device *
+dbx500_add_sdi(const char *name, resource_size_t base, int irq,
+ struct mmc_board *pdata)
+{
+ return dbx500_add_amba_device(name, base, irq, pdata, SDI_PER_ID);
+}
+
+static inline struct amba_device *
+dbx500_add_uart(const char *name, resource_size_t base, int irq)
+{
+ return dbx500_add_amba_device(name, base, irq, NULL, 0);
+}
+
+struct nmk_i2c_controller;
+
+static inline struct platform_device *
+dbx500_add_i2c(int id, resource_size_t base, int irq,
+ struct nmk_i2c_controller *pdata)
+{
+ return dbx500_add_platform_device_4k1irq("nmk-i2c", id, base, irq,
+ pdata);
+}
+
+struct msp_i2s_platform_data;
+
+static inline struct platform_device *
+dbx500_add_msp_i2s(int id, resource_size_t base, int irq,
+ struct msp_i2s_platform_data *pdata)
+{
+ return dbx500_add_platform_device_4k1irq("MSP_I2S", id, base, irq,
+ pdata);
+}
+
+static inline struct amba_device *
+dbx500_add_rtc(resource_size_t base, int irq)
+{
+ return dbx500_add_amba_device("rtc-pl031", base, irq, NULL,
+ RTC_PER_ID);
+}
+
+#endif
diff --git a/arch/arm/mach-ux500/devices-db5500.c b/arch/arm/mach-ux500/devices-db5500.c
index 33e5b56bebb..180d0be60b6 100644
--- a/arch/arm/mach-ux500/devices-db5500.c
+++ b/arch/arm/mach-ux500/devices-db5500.c
@@ -7,20 +7,21 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
+#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <mach/hardware.h>
#include <mach/devices.h>
static struct nmk_gpio_platform_data u5500_gpio_data[] = {
- GPIO_DATA("GPIO-0-31", 0),
- GPIO_DATA("GPIO-32-63", 32), /* 36..63 not routed to pin */
- GPIO_DATA("GPIO-64-95", 64), /* 83..95 not routed to pin */
- GPIO_DATA("GPIO-96-127", 96), /* 102..127 not routed to pin */
- GPIO_DATA("GPIO-128-159", 128), /* 149..159 not routed to pin */
- GPIO_DATA("GPIO-160-191", 160),
- GPIO_DATA("GPIO-192-223", 192),
- GPIO_DATA("GPIO-224-255", 224), /* 228..255 not routed to pin */
+ GPIO_DATA("GPIO-0-31", 0, 32),
+ GPIO_DATA("GPIO-32-63", 32, 4), /* 36..63 not routed to pin */
+ GPIO_DATA("GPIO-64-95", 64, 19), /* 83..95 not routed to pin */
+ GPIO_DATA("GPIO-96-127", 96, 6), /* 102..127 not routed to pin */
+ GPIO_DATA("GPIO-128-159", 128, 21), /* 149..159 not routed to pin */
+ GPIO_DATA("GPIO-160-191", 160, 32),
+ GPIO_DATA("GPIO-192-223", 192, 32),
+ GPIO_DATA("GPIO-224-255", 224, 4), /* 228..255 not routed to pin */
};
static struct resource u5500_gpio_resources[] = {
@@ -44,3 +45,68 @@ struct platform_device u5500_gpio_devs[] = {
GPIO_DEVICE(6),
GPIO_DEVICE(7),
};
+
+#define U5500_PWM_SIZE 0x20
+static struct resource u5500_pwm0_resource[] = {
+ {
+ .name = "PWM_BASE",
+ .start = U5500_PWM_BASE,
+ .end = U5500_PWM_BASE + U5500_PWM_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource u5500_pwm1_resource[] = {
+ {
+ .name = "PWM_BASE",
+ .start = U5500_PWM_BASE + U5500_PWM_SIZE,
+ .end = U5500_PWM_BASE + U5500_PWM_SIZE * 2 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource u5500_pwm2_resource[] = {
+ {
+ .name = "PWM_BASE",
+ .start = U5500_PWM_BASE + U5500_PWM_SIZE * 2,
+ .end = U5500_PWM_BASE + U5500_PWM_SIZE * 3 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource u5500_pwm3_resource[] = {
+ {
+ .name = "PWM_BASE",
+ .start = U5500_PWM_BASE + U5500_PWM_SIZE * 3,
+ .end = U5500_PWM_BASE + U5500_PWM_SIZE * 4 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device u5500_pwm0_device = {
+ .id = 0,
+ .name = "pwm",
+ .resource = u5500_pwm0_resource,
+ .num_resources = ARRAY_SIZE(u5500_pwm0_resource),
+};
+
+struct platform_device u5500_pwm1_device = {
+ .id = 1,
+ .name = "pwm",
+ .resource = u5500_pwm1_resource,
+ .num_resources = ARRAY_SIZE(u5500_pwm1_resource),
+};
+
+struct platform_device u5500_pwm2_device = {
+ .id = 2,
+ .name = "pwm",
+ .resource = u5500_pwm2_resource,
+ .num_resources = ARRAY_SIZE(u5500_pwm2_resource),
+};
+
+struct platform_device u5500_pwm3_device = {
+ .id = 3,
+ .name = "pwm",
+ .resource = u5500_pwm3_resource,
+ .num_resources = ARRAY_SIZE(u5500_pwm3_resource),
+};
diff --git a/arch/arm/mach-ux500/devices-db5500.h b/arch/arm/mach-ux500/devices-db5500.h
new file mode 100644
index 00000000000..fd1e3ed1ae2
--- /dev/null
+++ b/arch/arm/mach-ux500/devices-db5500.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __DEVICES_DB5500_H
+#define __DEVICES_DB5500_H
+
+#include "devices-common.h"
+
+#define db5500_add_i2c1(pdata) \
+ dbx500_add_i2c(1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata)
+#define db5500_add_i2c2(pdata) \
+ dbx500_add_i2c(2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata)
+#define db5500_add_i2c3(pdata) \
+ dbx500_add_i2c(3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata)
+
+struct db5500_keypad_platform_data;
+
+static inline struct platform_device *
+db5500_add_keypad(struct db5500_keypad_platform_data *pdata)
+{
+ return dbx500_add_platform_device_4k1irq("db5500-keypad", -1,
+ U5500_KEYPAD_BASE,
+ IRQ_DB5500_KBD, pdata);
+}
+
+#define db5500_add_msp0_i2s(pdata) \
+ dbx500_add_msp_i2s(0, U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata)
+#define db5500_add_msp1_i2s(pdata) \
+ dbx500_add_msp_i2s(1, U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata)
+#define db5500_add_msp2_i2s(pdata) \
+ dbx500_add_msp_i2s(2, U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata)
+
+#define db5500_add_msp0_spi(pdata) \
+ dbx500_add_msp_spi("msp0", U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata)
+#define db5500_add_msp1_spi(pdata) \
+ dbx500_add_msp_spi("msp1", U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata)
+#define db5500_add_msp2_spi(pdata) \
+ dbx500_add_msp_spi("msp2", U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata)
+
+#define db5500_add_rtc() \
+ dbx500_add_rtc(U5500_RTC_BASE, IRQ_DB5500_RTC);
+
+#define db5500_add_sdi0(pdata) \
+ dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata)
+#define db5500_add_sdi1(pdata) \
+ dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata)
+#define db5500_add_sdi2(pdata) \
+ dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata)
+#define db5500_add_sdi3(pdata) \
+ dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata)
+#define db5500_add_sdi4(pdata) \
+ dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata)
+
+#define db5500_add_spi0(pdata) \
+ dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata)
+#define db5500_add_spi1(pdata) \
+ dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata)
+#define db5500_add_spi2(pdata) \
+ dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata)
+#define db5500_add_spi3(pdata) \
+ dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata)
+
+#define db5500_add_uart0() \
+ dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0)
+#define db5500_add_uart1() \
+ dbx500_add_uart("uart1", U5500_UART1_BASE, IRQ_DB5500_UART1)
+#define db5500_add_uart2() \
+ dbx500_add_uart("uart2", U5500_UART2_BASE, IRQ_DB5500_UART2)
+#define db5500_add_uart3() \
+ dbx500_add_uart("uart3", U5500_UART3_BASE, IRQ_DB5500_UART3)
+
+#endif
diff --git a/arch/arm/mach-ux500/devices-db8500.c b/arch/arm/mach-ux500/devices-db8500.c
index 82290342194..82179095e5b 100644
--- a/arch/arm/mach-ux500/devices-db8500.c
+++ b/arch/arm/mach-ux500/devices-db8500.c
@@ -9,26 +9,25 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/amba/bus.h>
-#include <plat/ste_dma40.h>
#include <mach/hardware.h>
#include <mach/setup.h>
-#include "ste-dma40-db8500.h"
static struct nmk_gpio_platform_data u8500_gpio_data[] = {
- GPIO_DATA("GPIO-0-31", 0),
- GPIO_DATA("GPIO-32-63", 32), /* 37..63 not routed to pin */
- GPIO_DATA("GPIO-64-95", 64),
- GPIO_DATA("GPIO-96-127", 96), /* 98..127 not routed to pin */
- GPIO_DATA("GPIO-128-159", 128),
- GPIO_DATA("GPIO-160-191", 160), /* 172..191 not routed to pin */
- GPIO_DATA("GPIO-192-223", 192),
- GPIO_DATA("GPIO-224-255", 224), /* 231..255 not routed to pin */
- GPIO_DATA("GPIO-256-288", 256), /* 268..288 not routed to pin */
+ GPIO_DATA("GPIO-0-31", 0, 32),
+ GPIO_DATA("GPIO-32-63", 32, 5), /* 37..63 not routed to pin */
+ GPIO_DATA("GPIO-64-95", 64, 32),
+ GPIO_DATA("GPIO-96-127", 96, 2), /* 98..127 not routed to pin */
+ GPIO_DATA("GPIO-128-159", 128, 32),
+ GPIO_DATA("GPIO-160-191", 160, 12), /* 172..191 not routed to pin */
+ GPIO_DATA("GPIO-192-223", 192, 32),
+ GPIO_DATA("GPIO-224-255", 224, 7), /* 231..255 not routed to pin */
+ GPIO_DATA("GPIO-256-288", 256, 12), /* 268..288 not routed to pin */
};
static struct resource u8500_gpio_resources[] = {
@@ -55,162 +54,53 @@ struct platform_device u8500_gpio_devs[] = {
GPIO_DEVICE(8),
};
-struct amba_device u8500_ssp0_device = {
- .dev = {
- .coherent_dma_mask = ~0,
- .init_name = "ssp0",
- },
- .res = {
- .start = U8500_SSP0_BASE,
- .end = U8500_SSP0_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
- .irq = {IRQ_SSP0, NO_IRQ },
- /* ST-Ericsson modified id */
- .periphid = SSP_PER_ID,
-};
-
-static struct resource u8500_i2c0_resources[] = {
- [0] = {
- .start = U8500_I2C0_BASE,
- .end = U8500_I2C0_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_I2C0,
- .end = IRQ_I2C0,
- .flags = IORESOURCE_IRQ,
- }
-};
-
-struct platform_device u8500_i2c0_device = {
- .name = "nmk-i2c",
- .id = 0,
- .resource = u8500_i2c0_resources,
- .num_resources = ARRAY_SIZE(u8500_i2c0_resources),
-};
-
-static struct resource u8500_i2c4_resources[] = {
+static struct resource u8500_shrm_resources[] = {
[0] = {
- .start = U8500_I2C4_BASE,
- .end = U8500_I2C4_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_I2C4,
- .end = IRQ_I2C4,
- .flags = IORESOURCE_IRQ,
- }
-};
-
-struct platform_device u8500_i2c4_device = {
- .name = "nmk-i2c",
- .id = 4,
- .resource = u8500_i2c4_resources,
- .num_resources = ARRAY_SIZE(u8500_i2c4_resources),
-};
-
-static struct resource dma40_resources[] = {
- [0] = {
- .start = U8500_DMA_BASE,
- .end = U8500_DMA_BASE + SZ_4K - 1,
+ .start = U8500_SHRM_GOP_INTERRUPT_BASE,
+ .end = U8500_SHRM_GOP_INTERRUPT_BASE + ((4*4)-1),
+ .name = "shrm_gop_register_base",
.flags = IORESOURCE_MEM,
- .name = "base",
},
[1] = {
- .start = U8500_DMA_LCPA_BASE,
- .end = U8500_DMA_LCPA_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- .name = "lcpa",
+ .start = IRQ_CA_WAKE_REQ_V1,
+ .end = IRQ_CA_WAKE_REQ_V1,
+ .name = "ca_irq_wake_req",
+ .flags = IORESOURCE_IRQ,
},
[2] = {
- .start = U8500_DMA_LCLA_BASE,
- .end = U8500_DMA_LCLA_BASE + 16 * 1024 - 1,
- .flags = IORESOURCE_MEM,
- .name = "lcla",
+ .start = IRQ_AC_READ_NOTIFICATION_0_V1,
+ .end = IRQ_AC_READ_NOTIFICATION_0_V1,
+ .name = "ac_read_notification_0_irq",
+ .flags = IORESOURCE_IRQ,
},
[3] = {
- .start = IRQ_DMA,
- .end = IRQ_DMA,
- .flags = IORESOURCE_IRQ}
-};
-
-/* Default configuration for physcial memcpy */
-struct stedma40_chan_cfg dma40_memcpy_conf_phy = {
- .channel_type = (STEDMA40_CHANNEL_IN_PHY_MODE |
- STEDMA40_LOW_PRIORITY_CHANNEL |
- STEDMA40_PCHAN_BASIC_MODE),
- .dir = STEDMA40_MEM_TO_MEM,
-
- .src_info.endianess = STEDMA40_LITTLE_ENDIAN,
- .src_info.data_width = STEDMA40_BYTE_WIDTH,
- .src_info.psize = STEDMA40_PSIZE_PHY_1,
-
- .dst_info.endianess = STEDMA40_LITTLE_ENDIAN,
- .dst_info.data_width = STEDMA40_BYTE_WIDTH,
- .dst_info.psize = STEDMA40_PSIZE_PHY_1,
-
-};
-/* Default configuration for logical memcpy */
-struct stedma40_chan_cfg dma40_memcpy_conf_log = {
- .channel_type = (STEDMA40_CHANNEL_IN_LOG_MODE |
- STEDMA40_LOW_PRIORITY_CHANNEL |
- STEDMA40_LCHAN_SRC_LOG_DST_LOG |
- STEDMA40_NO_TIM_FOR_LINK),
- .dir = STEDMA40_MEM_TO_MEM,
-
- .src_info.endianess = STEDMA40_LITTLE_ENDIAN,
- .src_info.data_width = STEDMA40_BYTE_WIDTH,
- .src_info.psize = STEDMA40_PSIZE_LOG_1,
-
- .dst_info.endianess = STEDMA40_LITTLE_ENDIAN,
- .dst_info.data_width = STEDMA40_BYTE_WIDTH,
- .dst_info.psize = STEDMA40_PSIZE_LOG_1,
-
-};
-
-/*
- * Mapping between destination event lines and physical device address.
- * The event line is tied to a device and therefor the address is constant.
- */
-static const dma_addr_t dma40_tx_map[STEDMA40_NR_DEV];
-
-/* Mapping between source event lines and physical device address */
-static const dma_addr_t dma40_rx_map[STEDMA40_NR_DEV];
-
-/* Reserved event lines for memcpy only */
-static int dma40_memcpy_event[] = {
- STEDMA40_MEMCPY_TX_1,
- STEDMA40_MEMCPY_TX_2,
- STEDMA40_MEMCPY_TX_3,
- STEDMA40_MEMCPY_TX_4,
-};
-
-static struct stedma40_platform_data dma40_plat_data = {
- .dev_len = STEDMA40_NR_DEV,
- .dev_rx = dma40_rx_map,
- .dev_tx = dma40_tx_map,
- .memcpy = dma40_memcpy_event,
- .memcpy_len = ARRAY_SIZE(dma40_memcpy_event),
- .memcpy_conf_phy = &dma40_memcpy_conf_phy,
- .memcpy_conf_log = &dma40_memcpy_conf_log,
- .llis_per_log = 8,
+ .start = IRQ_AC_READ_NOTIFICATION_1_V1,
+ .end = IRQ_AC_READ_NOTIFICATION_1_V1,
+ .name = "ac_read_notification_1_irq",
+ .flags = IORESOURCE_IRQ,
+ },
+ [4] = {
+ .start = IRQ_CA_MSG_PEND_NOTIFICATION_0_V1,
+ .end = IRQ_CA_MSG_PEND_NOTIFICATION_0_V1,
+ .name = "ca_msg_pending_notification_0_irq",
+ .flags = IORESOURCE_IRQ,
+ },
+ [5] = {
+ .start = IRQ_CA_MSG_PEND_NOTIFICATION_1_V1,
+ .end = IRQ_CA_MSG_PEND_NOTIFICATION_1_V1,
+ .name = "ca_msg_pending_notification_1_irq",
+ .flags = IORESOURCE_IRQ,
+ }
};
-struct platform_device u8500_dma40_device = {
+struct platform_device u8500_shrm_device = {
+ .name = "u8500_shrm",
+ .id = 0,
.dev = {
- .platform_data = &dma40_plat_data,
+ .init_name = "shrm_bus",
+ .coherent_dma_mask = ~0,
},
- .name = "dma40",
- .id = 0,
- .num_resources = ARRAY_SIZE(dma40_resources),
- .resource = dma40_resources
-};
-void dma40_u8500ed_fixup(void)
-{
- dma40_plat_data.memcpy = NULL;
- dma40_plat_data.memcpy_len = 0;
- dma40_resources[0].start = U8500_DMA_BASE_ED;
- dma40_resources[0].end = U8500_DMA_BASE_ED + SZ_4K - 1;
-}
+ .num_resources = ARRAY_SIZE(u8500_shrm_resources),
+ .resource = u8500_shrm_resources
+};
diff --git a/arch/arm/mach-ux500/devices-db8500.h b/arch/arm/mach-ux500/devices-db8500.h
new file mode 100644
index 00000000000..0ab8778102f
--- /dev/null
+++ b/arch/arm/mach-ux500/devices-db8500.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __DEVICES_DB8500_H
+#define __DEVICES_DB8500_H
+
+#include "devices-common.h"
+
+struct ske_keypad_platform_data;
+struct pl022_ssp_controller;
+
+static inline struct platform_device *
+db8500_add_ske_keypad(struct ske_keypad_platform_data *pdata)
+{
+ return dbx500_add_platform_device_4k1irq("nmk-ske-keypad", -1,
+ U8500_SKE_BASE,
+ IRQ_DB8500_KB, pdata);
+}
+
+static inline struct amba_device *
+db8500_add_ssp(const char *name, resource_size_t base, int irq,
+ struct pl022_ssp_controller *pdata)
+{
+ return dbx500_add_amba_device(name, base, irq, pdata, 0);
+}
+
+
+#define db8500_add_i2c0(pdata) \
+ dbx500_add_i2c(0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
+#define db8500_add_i2c1(pdata) \
+ dbx500_add_i2c(1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata)
+#define db8500_add_i2c2(pdata) \
+ dbx500_add_i2c(2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata)
+#define db8500_add_i2c3(pdata) \
+ dbx500_add_i2c(3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata)
+#define db8500_add_i2c4(pdata) \
+ dbx500_add_i2c(4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata)
+
+#define db8500_add_msp0_i2s(pdata) \
+ dbx500_add_msp_i2s(0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
+#define db8500_add_msp1_i2s(pdata) \
+ dbx500_add_msp_i2s(1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
+#define db8500_add_msp2_i2s(pdata) \
+ dbx500_add_msp_i2s(2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
+#define db8500_add_msp3_i2s(pdata) \
+ dbx500_add_msp_i2s(3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
+
+#define db8500_add_msp0_spi(pdata) \
+ dbx500_add_msp_spi("msp0", U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
+#define db8500_add_msp1_spi(pdata) \
+ dbx500_add_msp_spi("msp1", U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
+#define db8500_add_msp2_spi(pdata) \
+ dbx500_add_msp_spi("msp2", U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
+#define db8500_add_msp3_spi(pdata) \
+ dbx500_add_msp_spi("msp3", U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
+
+#define db8500_add_rtc() \
+ dbx500_add_rtc(U8500_RTC_BASE, IRQ_DB8500_RTC);
+
+#define db8500_add_sdi0(pdata) \
+ dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata)
+#define db8500_add_sdi1(pdata) \
+ dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata)
+#define db8500_add_sdi2(pdata) \
+ dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata)
+#define db8500_add_sdi3(pdata) \
+ dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata)
+#define db8500_add_sdi4(pdata) \
+ dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata)
+#define db8500_add_sdi5(pdata) \
+ dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata)
+
+#define db8500_add_ssp0(pdata) \
+ db8500_add_ssp("ssp0", U8500_SSP0_BASE, IRQ_DB8500_SSP0, pdata)
+#define db8500_add_ssp1(pdata) \
+ db8500_add_ssp("ssp1", U8500_SSP1_BASE, IRQ_DB8500_SSP1, pdata)
+
+#define db8500_add_spi0(pdata) \
+ dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata)
+#define db8500_add_spi1(pdata) \
+ dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata)
+#define db8500_add_spi2(pdata) \
+ dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata)
+#define db8500_add_spi3(pdata) \
+ dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata)
+
+#define db8500_add_uart0() \
+ dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0)
+#define db8500_add_uart1() \
+ dbx500_add_uart("uart1", U8500_UART1_BASE, IRQ_DB8500_UART1)
+#define db8500_add_uart2() \
+ dbx500_add_uart("uart2", U8500_UART2_BASE, IRQ_DB8500_UART2)
+
+#endif
diff --git a/arch/arm/mach-ux500/devices.c b/arch/arm/mach-ux500/devices.c
index 8a268893cb7..878f0ce076b 100644
--- a/arch/arm/mach-ux500/devices.c
+++ b/arch/arm/mach-ux500/devices.c
@@ -7,17 +7,84 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/serial.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/usb/musb.h>
#include <linux/amba/bus.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/setup.h>
+#include <mach/irqs.h>
#include <mach/hardware.h>
+#include <mach/devices.h>
#include <mach/setup.h>
+#include <linux/hwmem.h>
+
+static struct resource b2r2_resources[] = {
+ [0] = {
+ .start = UX500_B2R2_BASE,
+ .end = UX500_B2R2_BASE + ((4*1024)-1),
+ .name = "b2r2_base",
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = PRCM_B2R2CLK_MGT_REG,
+ .end = PRCM_B2R2CLK_MGT_REG + (sizeof(u32) - 1),
+ .name = "prcm_b2r2_clk",
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device ux500_b2r2_device = {
+ .name = "U8500-B2R2",
+ .id = 0,
+ .dev = {
+ .init_name = "b2r2_bus",
+ .coherent_dma_mask = ~0,
+ },
+ .num_resources = ARRAY_SIZE(b2r2_resources),
+ .resource = b2r2_resources,
+};
+
+static struct hwmem_platform_data hwmem_pdata = {
+ .start = 0,
+ .size = 0,
+};
+
+static int __init early_hwmem(char *p)
+{
+ hwmem_pdata.size = memparse(p, &p);
+
+ if (*p != '@')
+ goto no_at;
+
+ hwmem_pdata.start = memparse(p + 1, &p);
-#define __MEM_4K_RESOURCE(x) \
- .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
+ return 0;
-struct amba_device ux500_pl031_device = {
+no_at:
+ hwmem_pdata.size = 0;
+
+ return -EINVAL;
+}
+early_param("hwmem", early_hwmem);
+
+struct platform_device ux500_hwmem_device = {
+ .name = "hwmem",
+ .dev = {
+ .platform_data = &hwmem_pdata,
+ },
+};
+
+struct amba_device ux500_rtc_device = {
.dev = {
.init_name = "pl031",
},
@@ -29,53 +96,73 @@ struct amba_device ux500_pl031_device = {
.irq = {IRQ_RTC_RTT, NO_IRQ},
};
-struct amba_device ux500_uart0_device = {
- .dev = { .init_name = "uart0" },
- __MEM_4K_RESOURCE(UX500_UART0_BASE),
- .irq = {IRQ_UART0, NO_IRQ},
+#ifdef CONFIG_CRYPTO_DEV_UX500_HASH
+static struct resource ux500_hash1_resources[] = {
+ [0] = {
+ .start = UX500_HASH1_BASE,
+ .end = UX500_HASH1_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ }
};
-struct amba_device ux500_uart1_device = {
- .dev = { .init_name = "uart1" },
- __MEM_4K_RESOURCE(UX500_UART1_BASE),
- .irq = {IRQ_UART1, NO_IRQ},
+struct platform_device ux500_hash1_device = {
+ .name = "hash1",
+ .id = -1,
+ .num_resources = 1,
+ .resource = ux500_hash1_resources
};
+#endif
-struct amba_device ux500_uart2_device = {
- .dev = { .init_name = "uart2" },
- __MEM_4K_RESOURCE(UX500_UART2_BASE),
- .irq = {IRQ_UART2, NO_IRQ},
+#if defined(CONFIG_USB_MUSB_HOST)
+#define MUSB_MODE MUSB_HOST
+#elif defined(CONFIG_USB_MUSB_PERIPHERAL)
+#define MUSB_MODE MUSB_PERIPHERAL
+#elif defined(CONFIG_USB_MUSB_OTG)
+#define MUSB_MODE MUSB_OTG
+#else
+#define MUSB_MODE MUSB_UNDEFINED
+#endif
+static struct musb_hdrc_config musb_hdrc_hs_otg_config = {
+ .multipoint = true, /* multipoint device */
+ .dyn_fifo = true, /* supports dynamic fifo sizing */
+ .num_eps = 16, /* number of endpoints _with_ ep0 */
+ .ram_bits = 16, /* ram address size */
};
-#define UX500_I2C_RESOURCES(id, size) \
-static struct resource ux500_i2c##id##_resources[] = { \
- [0] = { \
- .start = UX500_I2C##id##_BASE, \
- .end = UX500_I2C##id##_BASE + size - 1, \
- .flags = IORESOURCE_MEM, \
- }, \
- [1] = { \
- .start = IRQ_I2C##id, \
- .end = IRQ_I2C##id, \
- .flags = IORESOURCE_IRQ \
- } \
-}
+static struct musb_hdrc_platform_data musb_hdrc_hs_otg_platform_data = {
+ .mode = MUSB_MODE,
+ .clock = "usb", /* for clk_get() */
+ .config = &musb_hdrc_hs_otg_config,
+};
-UX500_I2C_RESOURCES(1, SZ_4K);
-UX500_I2C_RESOURCES(2, SZ_4K);
-UX500_I2C_RESOURCES(3, SZ_4K);
+static struct resource usb_resources[] = {
+ [0] = {
+ .name = "usb-mem",
+ .start = UX500_USBOTG_BASE,
+ .end = (UX500_USBOTG_BASE + SZ_64K - 1),
+ .flags = IORESOURCE_MEM,
+ },
-#define UX500_I2C_PDEVICE(cid) \
-struct platform_device ux500_i2c##cid##_device = { \
- .name = "nmk-i2c", \
- .id = cid, \
- .num_resources = 2, \
- .resource = ux500_i2c##cid##_resources, \
-}
+ [1] = {
+ .name = "usb-irq",
+ .start = IRQ_USBOTG,
+ .end = IRQ_USBOTG,
+ .flags = IORESOURCE_IRQ,
+ },
+};
-UX500_I2C_PDEVICE(1);
-UX500_I2C_PDEVICE(2);
-UX500_I2C_PDEVICE(3);
+struct platform_device ux500_musb_device = {
+ .name = "musb_hdrc",
+ .id = 0,
+ .dev = {
+ .init_name = "musb_hdrc.0", /* for clk_get() */
+ .platform_data = &musb_hdrc_hs_otg_platform_data,
+ .dma_mask = (u64 *)0xFFFFFFFF,
+ .coherent_dma_mask = (u64)0xFFFFFFFF
+ },
+ .num_resources = ARRAY_SIZE(usb_resources),
+ .resource = usb_resources,
+};
void __init amba_add_devices(struct amba_device *devs[], int num)
{
diff --git a/arch/arm/mach-ux500/dma-db5500.c b/arch/arm/mach-ux500/dma-db5500.c
new file mode 100644
index 00000000000..0027946eb29
--- /dev/null
+++ b/arch/arm/mach-ux500/dma-db5500.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
+ * Author: Rabin Vincent <rabinv.vincent@stericsson.com> for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <plat/ste_dma40.h>
+#include <mach/setup.h>
+#include <mach/ste-dma40-db5500.h>
+
+static struct resource dma40_resources[] = {
+ [0] = {
+ .start = U5500_DMA_BASE,
+ .end = U5500_DMA_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ .name = "base",
+ },
+ [1] = {
+ .start = U5500_DMA_LCPA_BASE,
+ .end = U5500_DMA_LCPA_BASE + 2 * SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ .name = "lcpa",
+ },
+ [2] = {
+ .start = IRQ_DB5500_DMA,
+ .end = IRQ_DB5500_DMA,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+/* Default configuration for physical memcpy */
+static struct stedma40_chan_cfg dma40_memcpy_conf_phy = {
+ .mode = STEDMA40_MODE_PHYSICAL,
+ .dir = STEDMA40_MEM_TO_MEM,
+
+ .src_info.data_width = STEDMA40_BYTE_WIDTH,
+ .src_info.psize = STEDMA40_PSIZE_PHY_1,
+ .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
+
+ .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+ .dst_info.psize = STEDMA40_PSIZE_PHY_1,
+ .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
+};
+
+/* Default configuration for logical memcpy */
+static struct stedma40_chan_cfg dma40_memcpy_conf_log = {
+ .dir = STEDMA40_MEM_TO_MEM,
+
+ .src_info.data_width = STEDMA40_BYTE_WIDTH,
+ .src_info.psize = STEDMA40_PSIZE_LOG_1,
+ .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
+
+ .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_1,
+ .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
+};
+
+/*
+ * Mapping between soruce event lines and physical device address This was
+ * created assuming that the event line is tied to a device and therefore the
+ * address is constant, however this is not true for at least USB, and the
+ * values are just placeholders for USB. This table is preserved and used for
+ * now.
+ */
+static const dma_addr_t dma40_rx_map[DB5500_DMA_NR_DEV] = {
+ [DB5500_DMA_DEV0_SPI0_RX] = 0,
+ [DB5500_DMA_DEV1_SPI1_RX] = 0,
+ [DB5500_DMA_DEV2_SPI2_RX] = 0,
+ [DB5500_DMA_DEV3_SPI3_RX] = 0,
+ [DB5500_DMA_DEV4_USB_OTG_IEP_1_9] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV5_USB_OTG_IEP_2_10] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV6_USB_OTG_IEP_3_11] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV7_IRDA_RFS] = 0,
+ [DB5500_DMA_DEV8_IRDA_FIFO_RX] = 0,
+ [DB5500_DMA_DEV9_MSP0_RX] = U5500_MSP0_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV10_MSP1_RX] = U5500_MSP1_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV11_MSP2_RX] = U5500_MSP2_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV12_UART0_RX] = 0,
+ [DB5500_DMA_DEV13_UART1_RX] = 0,
+ [DB5500_DMA_DEV14_UART2_RX] = 0,
+ [DB5500_DMA_DEV15_UART3_RX] = 0,
+ [DB5500_DMA_DEV16_USB_OTG_IEP_8] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV17_USB_OTG_IEP_1_9] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV18_USB_OTG_IEP_2_10] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV19_USB_OTG_IEP_3_11] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV20_USB_OTG_IEP_4_12] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV21_USB_OTG_IEP_5_13] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV22_USB_OTG_IEP_6_14] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV23_USB_OTG_IEP_7_15] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV24_SDMMC0_RX] = U5500_SDI0_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV25_SDMMC1_RX] = U5500_SDI1_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV26_SDMMC2_RX] = U5500_SDI2_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV27_SDMMC3_RX] = U5500_SDI3_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV28_SDMMC4_RX] = U5500_SDI4_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ /* 29 - 32 not used */
+ [DB5500_DMA_DEV33_SDMMC0_RX] = U5500_SDI0_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV34_SDMMC1_RX] = U5500_SDI1_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV35_SDMMC2_RX] = U5500_SDI2_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV36_SDMMC3_RX] = U5500_SDI3_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV37_SDMMC4_RX] = U5500_SDI4_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV38_USB_OTG_IEP_8] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV39_USB_OTG_IEP_1_9] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV40_USB_OTG_IEP_2_10] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV41_USB_OTG_IEP_3_11] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV42_USB_OTG_IEP_4_12] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV43_USB_OTG_IEP_5_13] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV44_USB_OTG_IEP_6_14] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV45_USB_OTG_IEP_7_15] = U5500_USBOTG_BASE,
+ /* 46 not used */
+ [DB5500_DMA_DEV47_MCDE_RX] = 0,
+ [DB5500_DMA_DEV48_CRYPTO1_RX] = 0,
+ /* 49, 50 not used */
+ [DB5500_DMA_DEV49_I2C1_RX] = 0,
+ [DB5500_DMA_DEV50_I2C3_RX] = 0,
+ [DB5500_DMA_DEV51_I2C2_RX] = 0,
+ /* 54 - 60 not used */
+ [DB5500_DMA_DEV61_CRYPTO0_RX] = 0,
+ /* 62, 63 not used */
+};
+
+/* Mapping between destination event lines and physical device address */
+static const dma_addr_t dma40_tx_map[DB5500_DMA_NR_DEV] = {
+ [DB5500_DMA_DEV0_SPI0_TX] = 0,
+ [DB5500_DMA_DEV1_SPI1_TX] = 0,
+ [DB5500_DMA_DEV2_SPI2_TX] = 0,
+ [DB5500_DMA_DEV3_SPI3_TX] = 0,
+ [DB5500_DMA_DEV4_USB_OTG_OEP_1_9] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV5_USB_OTG_OEP_2_10] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV6_USB_OTG_OEP_3_11] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV7_IRRC_TX] = 0,
+ [DB5500_DMA_DEV8_IRDA_FIFO_TX] = 0,
+ [DB5500_DMA_DEV9_MSP0_TX] = U5500_MSP0_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV10_MSP1_TX] = U5500_MSP1_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV11_MSP2_TX] = U5500_MSP2_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV12_UART0_TX] = 0,
+ [DB5500_DMA_DEV13_UART1_TX] = 0,
+ [DB5500_DMA_DEV14_UART2_TX] = 0,
+ [DB5500_DMA_DEV15_UART3_TX] = 0,
+ [DB5500_DMA_DEV16_USB_OTG_OEP_8] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV17_USB_OTG_OEP_1_9] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV18_USB_OTG_OEP_2_10] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV19_USB_OTG_OEP_3_11] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV20_USB_OTG_OEP_4_12] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV21_USB_OTG_OEP_5_13] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV22_USB_OTG_OEP_6_14] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV23_USB_OTG_OEP_7_15] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV24_SDMMC0_TX] = U5500_SDI0_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV25_SDMMC1_TX] = U5500_SDI1_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV26_SDMMC2_TX] = U5500_SDI2_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV27_SDMMC3_TX] = U5500_SDI3_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV28_SDMMC4_TX] = U5500_SDI4_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ /* 29 - 31 not used */
+ [DB5500_DMA_DEV32_FSMC_TX] = 0,
+ [DB5500_DMA_DEV33_SDMMC0_TX] = U5500_SDI0_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV34_SDMMC1_TX] = U5500_SDI1_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV35_SDMMC2_TX] = U5500_SDI2_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV36_SDMMC3_TX] = U5500_SDI3_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV37_SDMMC4_TX] = U5500_SDI4_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB5500_DMA_DEV38_USB_OTG_OEP_8] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV39_USB_OTG_OEP_1_9] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV40_USB_OTG_OEP_2_10] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV41_USB_OTG_OEP_3_11] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV42_USB_OTG_OEP_4_12] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV43_USB_OTG_OEP_5_13] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV44_USB_OTG_OEP_6_14] = U5500_USBOTG_BASE,
+ [DB5500_DMA_DEV45_USB_OTG_OEP_7_15] = U5500_USBOTG_BASE,
+ /* 46 not used */
+ [DB5500_DMA_DEV47_STM_TX] = 0,
+ [DB5500_DMA_DEV48_CRYPTO1_TX] = 0,
+ [DB5500_DMA_DEV49_CRYPTO1_TX_HASH1_TX] = 0,
+ [DB5500_DMA_DEV50_HASH1_TX] = 0,
+ [DB5500_DMA_DEV51_I2C1_TX] = 0,
+ [DB5500_DMA_DEV52_I2C3_TX] = 0,
+ [DB5500_DMA_DEV53_I2C2_TX] = 0,
+ /* 54, 55 not used */
+ [DB5500_DMA_MEMCPY_TX_1] = 0,
+ [DB5500_DMA_MEMCPY_TX_2] = 0,
+ [DB5500_DMA_MEMCPY_TX_3] = 0,
+ [DB5500_DMA_MEMCPY_TX_4] = 0,
+ [DB5500_DMA_MEMCPY_TX_5] = 0,
+ [DB5500_DMA_DEV61_CRYPTO0_TX] = 0,
+ [DB5500_DMA_DEV62_CRYPTO0_TX_HASH0_TX] = 0,
+ [DB5500_DMA_DEV63_HASH0_TX] = 0,
+};
+
+static struct stedma40_platform_data dma40_plat_data = {
+ .dev_len = ARRAY_SIZE(dma40_rx_map),
+ .dev_rx = dma40_rx_map,
+ .dev_tx = dma40_tx_map,
+ .memcpy_conf_phy = &dma40_memcpy_conf_phy,
+ .memcpy_conf_log = &dma40_memcpy_conf_log,
+ /* Audio is using physical channel 2 from MMDSP */
+ .disabled_channels = {2, -1},
+};
+
+static struct platform_device dma40_device = {
+ .dev = {
+ .platform_data = &dma40_plat_data,
+ },
+ .name = "dma40",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dma40_resources),
+ .resource = dma40_resources
+};
+
+void __init db5500_dma_init(void)
+{
+ int ret;
+
+ ret = platform_device_register(&dma40_device);
+ if (ret)
+ dev_err(&dma40_device.dev, "unable to register device: %d\n", ret);
+
+}
diff --git a/arch/arm/mach-ux500/dma-db8500.c b/arch/arm/mach-ux500/dma-db8500.c
new file mode 100644
index 00000000000..6dec6a14a7a
--- /dev/null
+++ b/arch/arm/mach-ux500/dma-db8500.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ *
+ * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/hsi.h>
+#include <linux/hsi-legacy.h>
+
+#include <plat/ste_dma40.h>
+
+#include <mach/hsi-stm.h>
+#include <mach/setup.h>
+#include <mach/ste-dma40-db8500.h>
+
+static struct resource dma40_resources[] = {
+ [0] = {
+ .start = U8500_DMA_BASE,
+ .end = U8500_DMA_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ .name = "base",
+ },
+ [1] = {
+ .start = U8500_DMA_LCPA_BASE,
+ .end = U8500_DMA_LCPA_BASE + 2 * SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ .name = "lcpa",
+ },
+ [2] = {
+ .start = IRQ_DMA,
+ .end = IRQ_DMA,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+/* Default configuration for physcial memcpy */
+static struct stedma40_chan_cfg dma40_memcpy_conf_phy = {
+ .mode = STEDMA40_MODE_PHYSICAL,
+ .dir = STEDMA40_MEM_TO_MEM,
+
+ .src_info.data_width = STEDMA40_BYTE_WIDTH,
+ .src_info.psize = STEDMA40_PSIZE_PHY_1,
+ .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
+
+ .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+ .dst_info.psize = STEDMA40_PSIZE_PHY_1,
+ .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
+
+};
+
+/* Default configuration for logical memcpy */
+static struct stedma40_chan_cfg dma40_memcpy_conf_log = {
+ .dir = STEDMA40_MEM_TO_MEM,
+
+ .src_info.data_width = STEDMA40_BYTE_WIDTH,
+ .src_info.psize = STEDMA40_PSIZE_LOG_1,
+ .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
+
+ .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_1,
+ .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
+
+};
+
+/*
+ * Mapping between soruce event lines and physical device address
+ * This was created assuming that the event line is tied to a device and
+ * therefore the address is constant, however this is not true for at least
+ * USB, and the values are just placeholders for USB. This table is preserved
+ * and used for now.
+ */
+static dma_addr_t dma40_rx_map[DB8500_DMA_NR_DEV] = {
+ [DB8500_DMA_DEV0_SPI0_RX] = 0,
+ [DB8500_DMA_DEV1_SD_MMC0_RX] = 0,
+ [DB8500_DMA_DEV2_SD_MMC1_RX] = 0,
+ [DB8500_DMA_DEV3_SD_MMC2_RX] = 0,
+ [DB8500_DMA_DEV4_I2C1_RX] = 0,
+ [DB8500_DMA_DEV5_I2C3_RX] = 0,
+ [DB8500_DMA_DEV6_I2C2_RX] = 0,
+ [DB8500_DMA_DEV7_I2C4_RX] = 0,
+ [DB8500_DMA_DEV8_SSP0_RX] = 0,
+ [DB8500_DMA_DEV9_SSP1_RX] = 0,
+ [DB8500_DMA_DEV10_MCDE_RX] = 0,
+ [DB8500_DMA_DEV11_UART2_RX] = 0,
+ [DB8500_DMA_DEV12_UART1_RX] = 0,
+ [DB8500_DMA_DEV13_UART0_RX] = 0,
+ [DB8500_DMA_DEV14_MSP2_RX] = U8500_MSP2_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV15_I2C0_RX] = 0,
+ [DB8500_DMA_DEV16_USB_OTG_IEP_7_15] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV17_USB_OTG_IEP_6_14] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV18_USB_OTG_IEP_5_13] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV19_USB_OTG_IEP_4_12] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV20_SLIM0_CH0_RX_HSI_RX_CH0] = U8500_HSIR_BASE + 0x0 + HSI_RX_BUFFERX,
+ [DB8500_DMA_DEV21_SLIM0_CH1_RX_HSI_RX_CH1] = U8500_HSIR_BASE + 0x4 + HSI_RX_BUFFERX,
+ [DB8500_DMA_DEV22_SLIM0_CH2_RX_HSI_RX_CH2] = U8500_HSIR_BASE + 0x8 + HSI_RX_BUFFERX,
+ [DB8500_DMA_DEV23_SLIM0_CH3_RX_HSI_RX_CH3] = U8500_HSIR_BASE + 0xC + HSI_RX_BUFFERX,
+ [DB8500_DMA_DEV24_SRC_SXA0_RX_TX] = 0,
+ [DB8500_DMA_DEV25_SRC_SXA1_RX_TX] = 0,
+ [DB8500_DMA_DEV26_SRC_SXA2_RX_TX] = 0,
+ [DB8500_DMA_DEV27_SRC_SXA3_RX_TX] = 0,
+ [DB8500_DMA_DEV28_SD_MM2_RX] = U8500_SDI2_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV29_SD_MM0_RX] = U8500_SDI0_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV30_MSP1_RX] = U8500_MSP1_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX] = U8500_MSP0_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV32_SD_MM1_RX] = U8500_SDI1_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV33_SPI2_RX] = 0,
+ [DB8500_DMA_DEV34_I2C3_RX2] = 0,
+ [DB8500_DMA_DEV35_SPI1_RX] = 0,
+ [DB8500_DMA_DEV36_USB_OTG_IEP_3_11] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV37_USB_OTG_IEP_2_10] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV38_USB_OTG_IEP_1_9] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV39_USB_OTG_IEP_8] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV40_SPI3_RX] = 0,
+ [DB8500_DMA_DEV41_SD_MM3_RX] = 0,
+ [DB8500_DMA_DEV42_SD_MM4_RX] = U8500_SDI4_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV43_SD_MM5_RX] = 0,
+ [DB8500_DMA_DEV44_SRC_SXA4_RX_TX] = 0,
+ [DB8500_DMA_DEV45_SRC_SXA5_RX_TX] = 0,
+ [DB8500_DMA_DEV46_SLIM0_CH8_RX_SRC_SXA6_RX_TX] = 0,
+ [DB8500_DMA_DEV47_SLIM0_CH9_RX_SRC_SXA7_RX_TX] = 0,
+ [DB8500_DMA_DEV48_CAC1_RX] = 0,
+ /* 49, 50 and 51 are not used */
+ [DB8500_DMA_DEV52_SLIM0_CH4_RX_HSI_RX_CH4] = 0,
+ [DB8500_DMA_DEV53_SLIM0_CH5_RX_HSI_RX_CH5] = 0,
+ [DB8500_DMA_DEV54_SLIM0_CH6_RX_HSI_RX_CH6] = 0,
+ [DB8500_DMA_DEV55_SLIM0_CH7_RX_HSI_RX_CH7] = 0,
+ /* 56, 57, 58, 59 and 60 are not used */
+ [DB8500_DMA_DEV61_CAC0_RX] = 0,
+ /* 62 and 63 are not used */
+};
+
+/* Mapping between destination event lines and physical device address */
+static const dma_addr_t dma40_tx_map[DB8500_DMA_NR_DEV] = {
+ [DB8500_DMA_DEV0_SPI0_TX] = 0,
+ [DB8500_DMA_DEV1_SD_MMC0_TX] = 0,
+ [DB8500_DMA_DEV2_SD_MMC1_TX] = 0,
+ [DB8500_DMA_DEV3_SD_MMC2_TX] = 0,
+ [DB8500_DMA_DEV4_I2C1_TX] = 0,
+ [DB8500_DMA_DEV5_I2C3_TX] = 0,
+ [DB8500_DMA_DEV6_I2C2_TX] = 0,
+ [DB8500_DMA_DEV7_I2C4_TX] = 0,
+ [DB8500_DMA_DEV8_SSP0_TX] = 0,
+ [DB8500_DMA_DEV9_SSP1_TX] = 0,
+ /* 10 is not used*/
+ [DB8500_DMA_DEV11_UART2_TX] = 0,
+ [DB8500_DMA_DEV12_UART1_TX] = 0,
+ [DB8500_DMA_DEV13_UART0_TX] = 0,
+ [DB8500_DMA_DEV14_MSP2_TX] = U8500_MSP2_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV15_I2C0_TX] = 0,
+ [DB8500_DMA_DEV16_USB_OTG_OEP_7_15] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV17_USB_OTG_OEP_6_14] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV18_USB_OTG_OEP_5_13] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV19_USB_OTG_OEP_4_12] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV20_SLIM0_CH0_TX_HSI_TX_CH0] = U8500_HSIT_BASE + 0x0 + HSI_TX_BUFFERX,
+ [DB8500_DMA_DEV21_SLIM0_CH1_TX_HSI_TX_CH1] = U8500_HSIT_BASE + 0x4 + HSI_TX_BUFFERX,
+ [DB8500_DMA_DEV22_SLIM0_CH2_TX_HSI_TX_CH2] = U8500_HSIT_BASE + 0x8 + HSI_TX_BUFFERX,
+ [DB8500_DMA_DEV23_SLIM0_CH3_TX_HSI_TX_CH3] = U8500_HSIT_BASE + 0xC + HSI_TX_BUFFERX,
+ [DB8500_DMA_DEV24_DST_SXA0_RX_TX] = 0,
+ [DB8500_DMA_DEV25_DST_SXA1_RX_TX] = 0,
+ [DB8500_DMA_DEV26_DST_SXA2_RX_TX] = 0,
+ [DB8500_DMA_DEV27_DST_SXA3_RX_TX] = 0,
+ [DB8500_DMA_DEV28_SD_MM2_TX] = U8500_SDI2_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV29_SD_MM0_TX] = U8500_SDI0_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV30_MSP1_TX] = U8500_MSP1_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX] = U8500_MSP0_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV32_SD_MM1_TX] = U8500_SDI1_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV33_SPI2_TX] = 0,
+ [DB8500_DMA_DEV34_I2C3_TX2] = 0,
+ [DB8500_DMA_DEV35_SPI1_TX] = 0,
+ [DB8500_DMA_DEV36_USB_OTG_OEP_3_11] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV37_USB_OTG_OEP_2_10] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV38_USB_OTG_OEP_1_9] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV39_USB_OTG_OEP_8] = U8500_USBOTG_BASE,
+ [DB8500_DMA_DEV40_SPI3_TX] = 0,
+ [DB8500_DMA_DEV41_SD_MM3_TX] = 0,
+ [DB8500_DMA_DEV42_SD_MM4_TX] = U8500_SDI4_BASE + SD_MMC_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV43_SD_MM5_TX] = 0,
+ [DB8500_DMA_DEV44_DST_SXA4_RX_TX] = 0,
+ [DB8500_DMA_DEV45_DST_SXA5_RX_TX] = 0,
+ [DB8500_DMA_DEV46_SLIM0_CH8_TX_DST_SXA6_RX_TX] = 0,
+ [DB8500_DMA_DEV47_SLIM0_CH9_TX_DST_SXA7_RX_TX] = 0,
+ [DB8500_DMA_DEV48_CAC1_TX] = 0,
+ [DB8500_DMA_DEV49_CAC1_TX_HAC1_TX] = 0,
+ [DB8500_DMA_DEV50_HAC1_TX] = 0,
+ [DB8500_DMA_MEMCPY_TX_0] = 0,
+ [DB8500_DMA_DEV52_SLIM1_CH4_TX_HSI_TX_CH4] = 0,
+ [DB8500_DMA_DEV53_SLIM1_CH5_TX_HSI_TX_CH5] = 0,
+ [DB8500_DMA_DEV54_SLIM1_CH6_TX_HSI_TX_CH6] = 0,
+ [DB8500_DMA_DEV55_SLIM1_CH7_TX_HSI_TX_CH7] = 0,
+ [DB8500_DMA_MEMCPY_TX_1] = 0,
+ [DB8500_DMA_MEMCPY_TX_2] = 0,
+ [DB8500_DMA_MEMCPY_TX_3] = 0,
+ [DB8500_DMA_MEMCPY_TX_4] = 0,
+ [DB8500_DMA_MEMCPY_TX_5] = 0,
+ [DB8500_DMA_DEV61_CAC0_TX] = 0,
+ [DB8500_DMA_DEV62_CAC0_TX_HAC0_TX] = 0,
+ [DB8500_DMA_DEV63_HAC0_TX] = 0,
+};
+
+/* Reserved event lines for memcpy only */
+static int dma40_memcpy_event[] = {
+ DB8500_DMA_MEMCPY_TX_0,
+ DB8500_DMA_MEMCPY_TX_1,
+ DB8500_DMA_MEMCPY_TX_2,
+ DB8500_DMA_MEMCPY_TX_3,
+ DB8500_DMA_MEMCPY_TX_4,
+ DB8500_DMA_MEMCPY_TX_5,
+};
+
+static struct stedma40_platform_data dma40_plat_data = {
+ .dev_len = ARRAY_SIZE(dma40_rx_map),
+ .dev_rx = dma40_rx_map,
+ .dev_tx = dma40_tx_map,
+ .memcpy = dma40_memcpy_event,
+ .memcpy_len = ARRAY_SIZE(dma40_memcpy_event),
+ .memcpy_conf_phy = &dma40_memcpy_conf_phy,
+ .memcpy_conf_log = &dma40_memcpy_conf_log,
+ /* Audio is using physical channel 2 from MMDSP */
+ .disabled_channels = {2, -1},
+};
+
+static struct platform_device dma40_device = {
+ .dev = {
+ .platform_data = &dma40_plat_data,
+ },
+ .name = "dma40",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dma40_resources),
+ .resource = dma40_resources
+};
+
+void __init db8500_dma_init(void)
+{
+ int ret;
+
+ if (cpu_is_u8500ed()) {
+ dma40_plat_data.memcpy = NULL;
+ dma40_plat_data.memcpy_len = 0;
+ dma40_resources[0].start = U8500_DMA_BASE_ED;
+ dma40_resources[0].end = U8500_DMA_BASE_ED + SZ_4K - 1;
+ dma40_resources[1].start = U8500_DMA_LCPA_BASE_ED;
+ dma40_resources[1].end = U8500_DMA_LCPA_BASE_ED + 2 * SZ_1K - 1;
+ }
+
+ /* On DB8500v2+, RX line 30 is connected to MSP3 instead of MSP1 */
+ if (!cpu_is_u8500ed() && !cpu_is_u8500v1())
+ dma40_rx_map[DB8500_DMA_DEV30_MSP3_RX] = U8500_MSP3_BASE
+ + MSP_TX_RX_REG_OFFSET;
+
+ ret = platform_device_register(&dma40_device);
+ if (ret)
+ dev_err(&dma40_device.dev, "unable to register device: %d\n", ret);
+
+}
diff --git a/arch/arm/mach-ux500/gpio.c b/arch/arm/mach-ux500/gpio.c
new file mode 100644
index 00000000000..34b5624316d
--- /dev/null
+++ b/arch/arm/mach-ux500/gpio.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2010 ST-Ericsson
+ * Copyright (C) 2009 STMicroelectronics
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <mach/hardware.h>
+
+static struct gpio_altfun_data *altfun_table;
+static int altfun_table_size;
+static DEFINE_MUTEX(altfun_lock);
+
+/**
+ * stm_gpio_set_altfunctable - set the alternate function table
+ * @table: pointer to the altfunction table
+ * @size: number of elements in the table
+ */
+int stm_gpio_set_altfunctable(struct gpio_altfun_data *table, int size)
+{
+ int ret = 0;
+
+ mutex_lock(&altfun_lock);
+
+ if (altfun_table) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ altfun_table = table;
+ altfun_table_size = size;
+
+out:
+ mutex_unlock(&altfun_lock);
+ return ret;
+}
+
+/**
+ * stm_gpio_altfuncenable - enables alternate functions for
+ * the given set of GPIOs
+ * @alt_func: GPIO altfunction to disable
+ *
+ * Enable the given set of alternate functions. Error will be returned if any
+ * of the pins or invalid or busy.
+ */
+int stm_gpio_altfuncenable(gpio_alt_function alt_func)
+{
+ int i, j, found = false;
+ int ret = -EINVAL;
+ int start, end;
+
+ mutex_lock(&altfun_lock);
+ for (i = 0; i < altfun_table_size; i++) {
+ if (altfun_table[i].altfun != alt_func)
+ continue;
+
+ start = altfun_table[i].start;
+ end = altfun_table[i].end;
+ if (start > end) {
+ j = start;
+ start = end;
+ end = j;
+ }
+
+ found = true;
+
+ if (!gpio_is_valid(start) || !gpio_is_valid(end)) {
+ printk(KERN_ERR
+ "%s: GPIO range %d-%d for %s is not valid for\n",
+ __func__, start, end, altfun_table[i].dev_name);
+ goto out;
+ }
+
+ for (j = start; j <= end; j++) {
+ if (gpio_request(j, altfun_table[i].dev_name) < 0) {
+ printk(KERN_ERR
+ "%s:Failed to set %s, GPIO %d is busy\n",
+ __func__, altfun_table[i].dev_name, j);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ nmk_gpio_set_mode(j, altfun_table[i].type);
+ }
+ }
+
+ if (found)
+ ret = 0;
+
+out:
+ mutex_unlock(&altfun_lock);
+ return ret;
+}
+EXPORT_SYMBOL(stm_gpio_altfuncenable);
+
+/**
+ * stm_gpio_altfuncdisable - disable the alternate functions for
+ * the given set of GPIOs.
+ * @alt_func: GPIO altfunction enum
+ *
+ * Disable the given set of alternate functions. Error will be returned if any
+ * of the pins or invalid.
+ **/
+int stm_gpio_altfuncdisable(gpio_alt_function alt_func)
+{
+ bool found = false;
+ int ret = -EINVAL;
+ int i, j;
+ int start, end;
+
+ mutex_lock(&altfun_lock);
+ for (i = 0; i < altfun_table_size; i++) {
+ if (altfun_table[i].altfun != alt_func)
+ continue;
+ start = altfun_table[i].start;
+ end = altfun_table[i].end;
+ if (start > end) {
+ j = start;
+ start = end;
+ end = j;
+ }
+
+ found = true;
+
+ if (!gpio_is_valid(start) || !gpio_is_valid(end)) {
+ printk(KERN_ERR
+ "%s: GPIO range %d-%d for %s is out of bound\n",
+ __func__, start, end, altfun_table[i].dev_name);
+ goto out;
+ }
+
+ for (j = start; j <= end; j++) {
+ /* Reset the pin - input, gpio */
+ gpio_direction_input(j);
+ nmk_gpio_set_mode(j, NMK_GPIO_ALT_GPIO);
+ gpio_free(j);
+ }
+ }
+
+ if (!found)
+ printk(KERN_ERR
+ "%s: Didn't find any GPIO alt interface named '%s'\n",
+ __func__, altfun_table[i].dev_name);
+
+ if (found)
+ ret = 0;
+
+out:
+ mutex_unlock(&altfun_lock);
+ return ret;
+}
+EXPORT_SYMBOL(stm_gpio_altfuncdisable);
diff --git a/arch/arm/mach-ux500/hotplug.c b/arch/arm/mach-ux500/hotplug.c
new file mode 100644
index 00000000000..b782a03024b
--- /dev/null
+++ b/arch/arm/mach-ux500/hotplug.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Based on ARM realview platform
+ *
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/completion.h>
+
+#include <asm/cacheflush.h>
+
+extern volatile int pen_release;
+
+static DECLARE_COMPLETION(cpu_killed);
+
+static inline void platform_do_lowpower(unsigned int cpu)
+{
+ flush_cache_all();
+
+ /* we put the platform to just WFI */
+ for (;;) {
+ __asm__ __volatile__("dsb\n\t" "wfi\n\t"
+ : : : "memory");
+ if (pen_release == cpu) {
+ /*
+ * OK, proper wakeup, we're done
+ */
+ break;
+ }
+ }
+}
+
+int platform_cpu_kill(unsigned int cpu)
+{
+ return wait_for_completion_timeout(&cpu_killed, 5000);
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+void platform_cpu_die(unsigned int cpu)
+{
+#ifdef DEBUG
+ unsigned int this_cpu = hard_smp_processor_id();
+
+ if (cpu != this_cpu) {
+ printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n",
+ this_cpu, cpu);
+ BUG();
+ }
+#endif
+
+ printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
+ complete(&cpu_killed);
+
+ /* directly enter low power state, skipping secure registers */
+ platform_do_lowpower(cpu);
+}
+
+int platform_cpu_disable(unsigned int cpu)
+{
+ /*
+ * we don't allow CPU 0 to be shutdown (it is still too special
+ * e.g. clock tick interrupts)
+ */
+ return cpu == 0 ? -EPERM : 0;
+}
diff --git a/arch/arm/mach-ux500/hsi.c b/arch/arm/mach-ux500/hsi.c
new file mode 100644
index 00000000000..b508f94c2ef
--- /dev/null
+++ b/arch/arm/mach-ux500/hsi.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2010 ST-Ericsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <linux/hsi.h>
+#include <linux/hsi-legacy.h>
+
+#include <mach/hsi-stm.h>
+#include <mach/devices.h>
+#include <mach/hardware.h>
+#include <mach/ste-dma40-db8500.h>
+
+static struct hsi_plat_data hsit_platform_data = {
+ .dev_type = 0x0 /** transmitter */ ,
+ .mode = 0x2 /** frame mode */ ,
+ .divisor = 0x12 /** half HSIT freq */ ,
+ .parity = 0x0 /** no parity */ ,
+ .channels = 0x4 /** 4 channels */ ,
+ .flushbits = 0x0 /** none */ ,
+ .priority = 0x3 /** ch0,ch1 high while ch2,ch3 low */ ,
+ .burstlen = 0x0 /** infinite b2b */ ,
+ .preamble = 0x0 /** none */ ,
+ .dataswap = 0x0 /** no swap */ ,
+ .framelen = 0x1f /** 32 bits all channels */ ,
+ .ch_base_span = {[0] = {.base = 0x0, .span = 0x3},
+ [1] = {.base = 0x4, .span = 0x3},
+ [2] = {.base = 0x8, .span = 0x7},
+ [3] = {.base = 0x10, .span = 0x7}
+ },
+#ifdef CONFIG_STN8500_HSI_LEGACY
+ .currmode = CONFIG_STN8500_HSI_TRANSFER_MODE,
+#else
+ .currmode = 1,
+#endif
+ .hsi_dma_info = {
+ [0] = {
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .high_priority = true,
+ .dst_dev_type = DB8500_DMA_DEV20_SLIM0_CH0_TX_HSI_TX_CH0,
+ .src_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ .dst_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ },
+ [1] = {
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .high_priority = true,
+ .dst_dev_type = DB8500_DMA_DEV21_SLIM0_CH1_TX_HSI_TX_CH1,
+ .src_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ .dst_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ },
+ [2] = {
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .high_priority = true,
+ .dst_dev_type = DB8500_DMA_DEV22_SLIM0_CH2_TX_HSI_TX_CH2,
+ .src_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ .dst_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ },
+ [3] = {
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .high_priority = true,
+ .dst_dev_type = DB8500_DMA_DEV23_SLIM0_CH3_TX_HSI_TX_CH3,
+ .src_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ .dst_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ },
+ },
+ .watermark = 0x2 /** 1 free entries for all channels */ ,
+ .gpio_alt_func = GPIO_ALT_HSIT,
+};
+
+static struct hsi_plat_data hsir_platform_data = {
+ .dev_type = 0x1 /** receiver */ ,
+ .mode = 0x3 /** pipelined */ ,
+ .threshold = 0x22 /** 35 zero bits for break */ ,
+ .parity = 0x0 /** no parity */ ,
+ .detector = 0x0 /** oversampling */ ,
+ .channels = 0x4 /** 4 channels */ ,
+ .realtime = 0x0 /** disabled,no overwrite,all channels */ ,
+ .framelen = 0x1f /** 32 bits all channels */ ,
+ .preamble = 0x0 /** max timeout cycles */ ,
+ .ch_base_span = {[0] = {.base = 0x0, .span = 0x3},
+ [1] = {.base = 0x4, .span = 0x3},
+ [2] = {.base = 0x8, .span = 0x7},
+ [3] = {.base = 0x10, .span = 0x7}
+ },
+#ifdef CONFIG_STN8500_HSI_LEGACY
+ .currmode = CONFIG_STN8500_HSI_TRANSFER_MODE,
+#else
+ .currmode = 1,
+#endif
+ .timeout = 0x0 /** immediate updation of channel buffer */ ,
+ .hsi_dma_info = {
+ [0] = {
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .high_priority = true,
+ .src_dev_type = DB8500_DMA_DEV20_SLIM0_CH0_RX_HSI_RX_CH0,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ .dst_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ },
+ [1] = {
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .high_priority = true,
+ .src_dev_type = DB8500_DMA_DEV21_SLIM0_CH1_RX_HSI_RX_CH1,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ .dst_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ },
+ [2] = {
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .high_priority = true,
+ .src_dev_type = DB8500_DMA_DEV22_SLIM0_CH2_RX_HSI_RX_CH2,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ .dst_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ },
+ [3] = {
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .high_priority = true,
+ .src_dev_type = DB8500_DMA_DEV23_SLIM0_CH3_RX_HSI_RX_CH3,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ .dst_info = {
+ .data_width = STEDMA40_WORD_WIDTH,
+ .psize = STEDMA40_PSIZE_LOG_4,
+ },
+ },
+ },
+ .watermark = 0x2 /** 1 'occupated' entry for all channels */ ,
+ .gpio_alt_func = GPIO_ALT_HSIR,
+};
+
+static struct resource u8500_hsit_resource[] = {
+ [0] = {
+ .start = U8500_HSIT_BASE,
+ .end = U8500_HSIT_BASE + (SZ_4K - 1),
+ .name = "hsit_iomem_base",
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_HSITD0,
+ .end = IRQ_HSITD1,
+ .name = "hsit_irq",
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource u8500_hsir_resource[] = {
+ [0] = {
+ .start = U8500_HSIR_BASE,
+ .end = U8500_HSIR_BASE + (SZ_4K - 1),
+ .name = "hsir_iomem_base",
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_HSIRD0,
+ .end = IRQ_HSIRD1,
+ .name = "hsir_irq",
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = IRQ_HSIR_EXCEP,
+ .end = IRQ_HSIR_EXCEP,
+ .name = "hsir_irq_excep",
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = IRQ_HSIR_CH0_OVRRUN,
+ .end = IRQ_HSIR_CH0_OVRRUN,
+ .name = "hsir_irq_ch0_overrun",
+ .flags = IORESOURCE_IRQ,
+ },
+ [4] = {
+ .start = IRQ_HSIR_CH1_OVRRUN,
+ .end = IRQ_HSIR_CH1_OVRRUN,
+ .name = "hsir_irq_ch1_overrun",
+ .flags = IORESOURCE_IRQ,
+ },
+ [5] = {
+ .start = IRQ_HSIR_CH2_OVRRUN,
+ .end = IRQ_HSIR_CH2_OVRRUN,
+ .name = "hsir_irq_ch2_overrun",
+ .flags = IORESOURCE_IRQ,
+ },
+ [6] = {
+ .start = IRQ_HSIR_CH3_OVRRUN,
+ .end = IRQ_HSIR_CH3_OVRRUN,
+ .name = "hsir_irq_ch3_overrun",
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device u8500_hsit_device = {
+ .name = "stm-hsi",
+ .id = 0,
+ .dev = {
+ .platform_data = &hsit_platform_data,
+ },
+ .num_resources = ARRAY_SIZE(u8500_hsit_resource),
+ .resource = u8500_hsit_resource,
+};
+
+struct platform_device u8500_hsir_device = {
+ .name = "stm-hsi",
+ .id = 1,
+ .dev = {
+ .platform_data = &hsir_platform_data,
+ },
+ .num_resources = ARRAY_SIZE(u8500_hsir_resource),
+ .resource = u8500_hsir_resource,
+};
diff --git a/arch/arm/mach-ux500/include/mach/ab8500_codec.h b/arch/arm/mach-ux500/include/mach/ab8500_codec.h
new file mode 100644
index 00000000000..d45dea66b5d
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/ab8500_codec.h
@@ -0,0 +1,327 @@
+/*****************************************************************************/
+/**
+* © ST-Ericsson, 2009 - All rights reserved
+* Reproduction and Communication of this document is strictly prohibited
+* unless specifically authorized in writing by ST-Ericsson
+*
+* \brief Public header file for AB8500 Codec
+* \author ST-Ericsson
+*/
+/*****************************************************************************/
+
+#ifndef _AB8500_CODEC_H_
+#define _AB8500_CODEC_H_
+
+/*---------------------------------------------------------------------
+ * Includes
+ *--------------------------------------------------------------------*/
+#include "hcl_defs.h"
+#include "debug.h"
+#include <mach/ab8500_codec_p.h>
+
+/*---------------------------------------------------------------------
+ * Define
+ *--------------------------------------------------------------------*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+ typedef enum {
+ AB8500_CODEC_OK,
+ AB8500_CODEC_ERROR,
+ AB8500_CODEC_UNSUPPORTED_FEATURE,
+ AB8500_CODEC_INVALID_PARAMETER,
+ AB8500_CODEC_CONFIG_NOT_COHERENT,
+ AB8500_CODEC_TRANSACTION_FAILED
+ } t_ab8500_codec_error;
+
+ typedef enum {
+ AB8500_CODEC_MASTER_MODE_DISABLE,
+ AB8500_CODEC_MASTER_MODE_ENABLE
+ } t_ab8500_codec_master_mode;
+
+ typedef enum {
+ AB8500_CODEC_SLOT0,
+ AB8500_CODEC_SLOT1,
+ AB8500_CODEC_SLOT2,
+ AB8500_CODEC_SLOT3,
+ AB8500_CODEC_SLOT4,
+ AB8500_CODEC_SLOT5,
+ AB8500_CODEC_SLOT6,
+ AB8500_CODEC_SLOT7,
+ AB8500_CODEC_SLOT8,
+ AB8500_CODEC_SLOT9,
+ AB8500_CODEC_SLOT10,
+ AB8500_CODEC_SLOT11,
+ AB8500_CODEC_SLOT12,
+ AB8500_CODEC_SLOT13,
+ AB8500_CODEC_SLOT14,
+ AB8500_CODEC_SLOT15,
+ AB8500_CODEC_SLOT16,
+ AB8500_CODEC_SLOT17,
+ AB8500_CODEC_SLOT18,
+ AB8500_CODEC_SLOT19,
+ AB8500_CODEC_SLOT20,
+ AB8500_CODEC_SLOT21,
+ AB8500_CODEC_SLOT22,
+ AB8500_CODEC_SLOT23,
+ AB8500_CODEC_SLOT24,
+ AB8500_CODEC_SLOT25,
+ AB8500_CODEC_SLOT26,
+ AB8500_CODEC_SLOT27,
+ AB8500_CODEC_SLOT28,
+ AB8500_CODEC_SLOT29,
+ AB8500_CODEC_SLOT30,
+ AB8500_CODEC_SLOT31,
+ AB8500_CODEC_SLOT_UNDEFINED
+ } t_ab8500_codec_slot;
+
+ typedef enum {
+ AB8500_CODEC_DA_CHANNEL_NUMBER_1,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_2,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_3,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_4,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_5,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_6,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED
+ } t_ab8500_codec_da_channel_number;
+
+ typedef enum {
+ AB8500_CODEC_SRC_STATE_DISABLE,
+ AB8500_CODEC_SRC_STATE_ENABLE
+ } t_ab8500_codec_src_state;
+
+ typedef enum {
+ AB8500_CODEC_DEST_STATE_DISABLE,
+ AB8500_CODEC_DEST_STATE_ENABLE
+ } t_ab8500_codec_dest_state;
+
+ typedef struct {
+ t_ab8500_codec_cr27_if1_bitclk_osr cr27_if1_bitclk_osr;
+ t_ab8500_codec_cr27_if0_bitclk_osr cr27_if0_bitclk_osr;
+ t_ab8500_codec_cr28_if0wl cr28_if0wl;
+ t_ab8500_codec_cr30_if1wl cr30_if1wl;
+ t_ab8500_codec_cr28_bitclk0p cr28_bitclk0p;
+ t_ab8500_codec_cr28_if0del cr28_if0del;
+ } t_ab8500_codec_tdm_config;
+
+ typedef struct {
+ t_ab8500_codec_cr104_bfifoint cr104_bfifoint;
+ t_ab8500_codec_cr105_bfifotx cr105_bfifotx;
+ t_ab8500_codec_cr106_bfifofsext cr106_bfifofsext;
+ t_ab8500_codec_cr106_bfifomsk cr106_bfifomsk;
+ t_ab8500_codec_cr106_bfifomstr cr106_bfifomstr;
+ t_ab8500_codec_cr106_bfifostrt cr106_bfifostrt;
+ t_ab8500_codec_cr107_bfifosampnr cr107_bfifosampnr;
+ t_ab8500_codec_cr108_bfifowakeup cr108_bfifowakeup;
+ } t_ab8500_codec_burst_fifo_config;
+
+/************************************************************/
+/*---------------------------------------------------------------------
+ * Exported APIs
+ *--------------------------------------------------------------------*/
+/* Initialization */
+ t_ab8500_codec_error AB8500_CODEC_Init(IN t_uint8
+ slave_address_of_codec);
+ t_ab8500_codec_error AB8500_CODEC_Reset(void);
+
+/* Audio Codec basic configuration */
+ t_ab8500_codec_error AB8500_CODEC_SetModeAndDirection(IN
+ t_ab8500_codec_direction
+ ab8500_codec_direction,
+ IN
+ t_ab8500_codec_mode
+ ab8500_codec_mode_in,
+ IN
+ t_ab8500_codec_mode
+ ab8500_codec_mode_out,
+ IN
+ t_ab8500_codec_tdm_config
+ const *const
+ p_tdm_config);
+ t_ab8500_codec_error AB8500_CODEC_SelectInput(IN t_ab8500_codec_src
+ ab8500_codec_src);
+ t_ab8500_codec_error AB8500_CODEC_SelectOutput(IN t_ab8500_codec_dest
+ ab8500_codec_dest);
+
+/* Burst FIFO configuration */
+ t_ab8500_codec_error AB8500_CODEC_ConfigureBurstFifo(IN
+ t_ab8500_codec_burst_fifo_config
+ const *const
+ p_burst_fifo_config);
+ t_ab8500_codec_error AB8500_CODEC_EnableBurstFifo(void);
+ t_ab8500_codec_error AB8500_CODEC_DisableBurstFifo(void);
+
+/* Audio Codec Master mode configuration */
+ t_ab8500_codec_error AB8500_CODEC_SetMasterMode(IN
+ t_ab8500_codec_master_mode
+ mode);
+
+/* APIs to be implemented by user */
+ t_ab8500_codec_error AB8500_CODEC_Write(IN t_uint8 register_offset,
+ IN t_uint8 count,
+ IN t_uint8 * p_data);
+ t_ab8500_codec_error AB8500_CODEC_Read(IN t_uint8 register_offset,
+ IN t_uint8 count,
+ IN t_uint8 * p_dummy_data,
+ IN t_uint8 * p_data);
+
+/* Volume Management */
+ t_ab8500_codec_error AB8500_CODEC_SetSrcVolume(IN t_ab8500_codec_src
+ src_device,
+ IN t_uint8
+ in_left_volume,
+ IN t_uint8
+ in_right_volume);
+ t_ab8500_codec_error AB8500_CODEC_SetDestVolume(IN t_ab8500_codec_dest
+ dest_device,
+ IN t_uint8
+ out_left_volume,
+ IN t_uint8
+ out_right_volume);
+
+/* Power management */
+ t_ab8500_codec_error AB8500_CODEC_PowerDown(void);
+ t_ab8500_codec_error AB8500_CODEC_PowerUp(void);
+
+/* Interface Management */
+ t_ab8500_codec_error AB8500_CODEC_SelectInterface(IN
+ t_ab8500_codec_audio_interface
+ audio_interface);
+ t_ab8500_codec_error AB8500_CODEC_GetInterface(OUT
+ t_ab8500_codec_audio_interface
+ * p_audio_interface);
+
+/* Slot Allocation */
+ t_ab8500_codec_error AB8500_CODEC_ADSlotAllocation(IN
+ t_ab8500_codec_slot
+ ad_slot,
+ IN
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation
+ value);
+ t_ab8500_codec_error AB8500_CODEC_DASlotAllocation(IN
+ t_ab8500_codec_da_channel_number
+ channel_number,
+ IN
+ t_ab8500_codec_cr51_to_cr56_sltoda
+ slot);
+
+/* Loopback Management */
+ t_ab8500_codec_error AB8500_CODEC_SetAnalogLoopback(IN t_uint8
+ out_left_volume,
+ IN t_uint8
+ out_right_volume);
+ t_ab8500_codec_error AB8500_CODEC_RemoveAnalogLoopback(void);
+
+/* Bypass Management */
+ t_ab8500_codec_error AB8500_CODEC_EnableBypassMode(void);
+ t_ab8500_codec_error AB8500_CODEC_DisableBypassMode(void);
+
+/* Power Control Management */
+ t_ab8500_codec_error AB8500_CODEC_SrcPowerControl(IN t_ab8500_codec_src
+ src_device,
+ t_ab8500_codec_src_state
+ state);
+ t_ab8500_codec_error AB8500_CODEC_DestPowerControl(IN
+ t_ab8500_codec_dest
+ dest_device,
+ t_ab8500_codec_dest_state
+ state);
+
+/* Version Management */
+ t_ab8500_codec_error AB8500_CODEC_GetVersion(OUT t_version * p_version);
+
+#if 0
+/* Debug management */
+ t_ab8500_codec_error AB8500_CODEC_SetDbgLevel(IN t_dbg_level dbg_level);
+ t_ab8500_codec_error AB8500_CODEC_GetDbgLevel(OUT t_dbg_level *
+ p_dbg_level);
+#endif
+
+/*
+** following is added by $kardad$
+*/
+
+/* duplicate copy of enum from msp.h */
+/* for MSPConfiguration.in_clock_freq parameter to select msp clock freq */
+ typedef enum {
+ CODEC_MSP_INPUT_FREQ_1MHZ = 1024,
+ CODEC_MSP_INPUT_FREQ_2MHZ = 2048,
+ CODEC_MSP_INPUT_FREQ_3MHZ = 3072,
+ CODEC_MSP_INPUT_FREQ_4MHZ = 4096,
+ CODEC_MSP_INPUT_FREQ_5MHZ = 5760,
+ CODEC_MSP_INPUT_FREQ_6MHZ = 6144,
+ CODEC_MSP_INPUT_FREQ_8MHZ = 8192,
+ CODEC_MSP_INPUT_FREQ_11MHZ = 11264,
+ CODEC_MSP_INPUT_FREQ_12MHZ = 12288,
+ CODEC_MSP_INPUT_FREQ_16MHZ = 16384,
+ CODEC_MSP_INPUT_FREQ_22MHZ = 22579,
+ CODEC_MSP_INPUT_FREQ_24MHZ = 24576,
+ CODEC_MSP_INPUT_FREQ_48MHZ = 49152
+ } codec_msp_in_clock_freq_type;
+
+/* msp clock source internal/external for srg_clock_sel */
+ typedef enum {
+ CODEC_MSP_APB_CLOCK = 0,
+ CODEC_MSP_SCK_CLOCK = 2,
+ CODEC_MSP_SCK_SYNC_CLOCK = 3
+ } codec_msp_srg_clock_sel_type;
+
+/* Sample rate supported by Codec */
+
+ typedef enum {
+ CODEC_FREQUENCY_DONT_CHANGE = -100,
+ CODEC_SAMPLING_FREQ_RESET = -1,
+ CODEC_SAMPLING_FREQ_MINLIMIT = 7,
+ CODEC_SAMPLING_FREQ_8KHZ = 8, /*default */
+ CODEC_SAMPLING_FREQ_11KHZ = 11,
+ CODEC_SAMPLING_FREQ_12KHZ = 12,
+ CODEC_SAMPLING_FREQ_16KHZ = 16,
+ CODEC_SAMPLING_FREQ_22KHZ = 22,
+ CODEC_SAMPLING_FREQ_24KHZ = 24,
+ CODEC_SAMPLING_FREQ_32KHZ = 32,
+ CODEC_SAMPLING_FREQ_44KHZ = 44,
+ CODEC_SAMPLING_FREQ_48KHZ = 48,
+ CODEC_SAMPLING_FREQ_64KHZ = 64, /*the frequencies below this line are not supported in stw5094A */
+ CODEC_SAMPLING_FREQ_88KHZ = 88,
+ CODEC_SAMPLING_FREQ_96KHZ = 96,
+ CODEC_SAMPLING_FREQ_128KHZ = 128,
+ CODEC_SAMPLING_FREQ_176KHZ = 176,
+ CODEC_SAMPLING_FREQ_192KHZ = 192,
+ CODEC_SAMPLING_FREQ_MAXLIMIT = 193
+ } t_codec_sample_frequency;
+
+#define RESET -1
+#define DEFAULT -100
+/***********************************************************/
+/*
+** following stuff is added to compile code without debug print support $kardad$
+*/
+
+#define DBGEXIT(cr)
+#define DBGEXIT0(cr)
+#define DBGEXIT1(cr,ch,p1)
+#define DBGEXIT2(cr,ch,p1,p2)
+#define DBGEXIT3(cr,ch,p1,p2,p3)
+#define DBGEXIT4(cr,ch,p1,p2,p3,p4)
+#define DBGEXIT5(cr,ch,p1,p2,p3,p4,p5)
+#define DBGEXIT6(cr,ch,p1,p2,p3,p4,p5,p6)
+
+#define DBGENTER()
+#define DBGENTER0()
+#define DBGENTER1(ch,p1)
+#define DBGENTER2(ch,p1,p2)
+#define DBGENTER3(ch,p1,p2,p3)
+#define DBGENTER4(ch,p1,p2,p3,p4)
+#define DBGENTER5(ch,p1,p2,p3,p4,p5)
+#define DBGENTER6(ch,p1,p2,p3,p4,p5,p6)
+
+#define DBGPRINT(dbg_level,dbg_string)
+#define DBGPRINTHEX(dbg_level,dbg_string,uint32)
+#define DBGPRINTDEC(dbg_level,dbg_string,uint32)
+/***********************************************************/
+
+#ifdef __cplusplus
+} /* allow C++ to use these headers */
+#endif /* __cplusplus */
+#endif /* _AB8500_CODEC_H_ */
+/* End of file ab8500_codec.h*/
diff --git a/arch/arm/mach-ux500/include/mach/ab8500_codec_p.h b/arch/arm/mach-ux500/include/mach/ab8500_codec_p.h
new file mode 100644
index 00000000000..847a1729e44
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/ab8500_codec_p.h
@@ -0,0 +1,3082 @@
+/*****************************************************************************/
+/**
+* © ST-Ericsson, 2009 - All rights reserved
+* Reproduction and Communication of this document is strictly prohibited
+* unless specifically authorized in writing by ST-Ericsson
+ *
+* \brief Private Header file for AB8500 CODEC
+* \author ST-Ericsson
+ */
+/*****************************************************************************/
+
+#ifndef _AB8500_CODECP_H_
+#define _AB8500_CODECP_H_
+
+/*----------------------------------------------------------------------------
+ * Includes
+ *---------------------------------------------------------------------------*/
+#include "hcl_defs.h"
+
+#define AB8500_CODEC_HCL_VERSION_ID 2
+#define AB8500_CODEC_HCL_MAJOR_ID 0
+#define AB8500_CODEC_HCL_MINOR_ID 0
+
+#define AB8500_CODEC_MASK_ONE_BIT 0x1UL
+#define AB8500_CODEC_MASK_TWO_BITS 0x3UL
+#define AB8500_CODEC_MASK_THREE_BITS 0x7UL
+#define AB8500_CODEC_MASK_FOUR_BITS 0xFUL
+#define AB8500_CODEC_MASK_FIVE_BITS 0x1FUL
+#define AB8500_CODEC_MASK_SIX_BITS 0x3FUL
+#define AB8500_CODEC_MASK_SEVEN_BITS 0x7FUL
+#define AB8500_CODEC_MASK_EIGHT_BITS 0xFFUL
+
+#define AB8500_CODEC_WRITE_BITS(reg, val, bit_nb, pos) (reg) = ((t_uint8) ((((reg) & (~(bit_nb << pos))) | (((val) & bit_nb) << pos))))
+
+#define AB8500_CODEC_BLOCK 0x0D
+
+#define AB8500_CODEC_MASK_TWO_MS_BITS 0xC0UL
+#define AB8500_CODEC_MASK_SIX_LS_BITS 0x3FUL
+
+/* Genepi AudioCodec Control Registers */
+
+#define AB8500_CODEC_CR0 0x00
+#define AB8500_CODEC_CR1 0x01
+#define AB8500_CODEC_CR2 0x02
+#define AB8500_CODEC_CR3 0x03
+#define AB8500_CODEC_CR4 0x04
+#define AB8500_CODEC_CR5 0x05
+#define AB8500_CODEC_CR6 0x06
+#define AB8500_CODEC_CR7 0x07
+#define AB8500_CODEC_CR8 0x08
+#define AB8500_CODEC_CR9 0x09
+#define AB8500_CODEC_CR10 0x0A
+#define AB8500_CODEC_CR11 0x0B
+#define AB8500_CODEC_CR12 0x0C
+#define AB8500_CODEC_CR13 0x0D
+#define AB8500_CODEC_CR14 0x0E
+#define AB8500_CODEC_CR15 0x0F
+#define AB8500_CODEC_CR16 0x10
+#define AB8500_CODEC_CR17 0x11
+#define AB8500_CODEC_CR18 0x12
+#define AB8500_CODEC_CR19 0x13
+#define AB8500_CODEC_CR20 0x14
+#define AB8500_CODEC_CR21 0x15
+#define AB8500_CODEC_CR22 0x16
+#define AB8500_CODEC_CR23 0x17
+#define AB8500_CODEC_CR24 0x18
+#define AB8500_CODEC_CR25 0x19
+#define AB8500_CODEC_CR26 0x1A
+#define AB8500_CODEC_CR27 0x1B
+#define AB8500_CODEC_CR28 0x1C
+#define AB8500_CODEC_CR29 0x1D
+#define AB8500_CODEC_CR30 0x1E
+#define AB8500_CODEC_CR31 0x1F
+#define AB8500_CODEC_CR32 0x20
+#define AB8500_CODEC_CR33 0x21
+#define AB8500_CODEC_CR34 0x22
+#define AB8500_CODEC_CR35 0x23
+#define AB8500_CODEC_CR36 0x24
+#define AB8500_CODEC_CR37 0x25
+#define AB8500_CODEC_CR38 0x26
+#define AB8500_CODEC_CR39 0x27
+#define AB8500_CODEC_CR40 0x28
+#define AB8500_CODEC_CR41 0x29
+#define AB8500_CODEC_CR42 0x2A
+#define AB8500_CODEC_CR43 0x2B
+#define AB8500_CODEC_CR44 0x2C
+#define AB8500_CODEC_CR45 0x2D
+#define AB8500_CODEC_CR46 0x2E
+#define AB8500_CODEC_CR47 0x2F
+#define AB8500_CODEC_CR48 0x30
+#define AB8500_CODEC_CR49 0x31
+#define AB8500_CODEC_CR50 0x32
+#define AB8500_CODEC_CR51 0x33
+#define AB8500_CODEC_CR52 0x34
+#define AB8500_CODEC_CR53 0x35
+#define AB8500_CODEC_CR54 0x36
+#define AB8500_CODEC_CR55 0x37
+#define AB8500_CODEC_CR56 0x38
+#define AB8500_CODEC_CR57 0x39
+#define AB8500_CODEC_CR58 0x3A
+#define AB8500_CODEC_CR59 0x3B
+#define AB8500_CODEC_CR60 0x3C
+#define AB8500_CODEC_CR61 0x3D
+#define AB8500_CODEC_CR62 0x3E
+#define AB8500_CODEC_CR63 0x3F
+#define AB8500_CODEC_CR64 0x40
+#define AB8500_CODEC_CR65 0x41
+#define AB8500_CODEC_CR66 0x42
+#define AB8500_CODEC_CR67 0x43
+#define AB8500_CODEC_CR68 0x44
+#define AB8500_CODEC_CR69 0x45
+#define AB8500_CODEC_CR70 0x46
+#define AB8500_CODEC_CR71 0x47
+#define AB8500_CODEC_CR72 0x48
+#define AB8500_CODEC_CR73 0x49
+#define AB8500_CODEC_CR74 0x4A
+#define AB8500_CODEC_CR75 0x4B
+#define AB8500_CODEC_CR76 0x4C
+#define AB8500_CODEC_CR77 0x4D
+#define AB8500_CODEC_CR78 0x4E
+#define AB8500_CODEC_CR79 0x4F
+#define AB8500_CODEC_CR80 0x50
+#define AB8500_CODEC_CR81 0x51
+#define AB8500_CODEC_CR82 0x52
+#define AB8500_CODEC_CR83 0x53
+#define AB8500_CODEC_CR84 0x54
+#define AB8500_CODEC_CR85 0x55
+#define AB8500_CODEC_CR86 0x56
+#define AB8500_CODEC_CR87 0x57
+#define AB8500_CODEC_CR88 0x58
+#define AB8500_CODEC_CR89 0x59
+#define AB8500_CODEC_CR90 0x5A
+#define AB8500_CODEC_CR91 0x5B
+#define AB8500_CODEC_CR92 0x5C
+#define AB8500_CODEC_CR93 0x5D
+#define AB8500_CODEC_CR94 0x5E
+#define AB8500_CODEC_CR95 0x5F
+#define AB8500_CODEC_CR96 0x60
+#define AB8500_CODEC_CR97 0x61
+#define AB8500_CODEC_CR98 0x62
+#define AB8500_CODEC_CR99 0x63
+#define AB8500_CODEC_CR100 0x64
+#define AB8500_CODEC_CR101 0x65
+#define AB8500_CODEC_CR102 0x66
+#define AB8500_CODEC_CR103 0x67
+#define AB8500_CODEC_CR104 0x68
+#define AB8500_CODEC_CR105 0x69
+#define AB8500_CODEC_CR106 0x6A
+#define AB8500_CODEC_CR107 0x6B
+#define AB8500_CODEC_CR108 0x6C
+#define AB8500_CODEC_CR109 0x6D
+
+/* CR0-CR0x0000 */
+#define AB8500_CODEC_CR0_POWERUP 7
+#define AB8500_CODEC_CR0_ENAANA 3
+
+/* CR1-CR0x0001 */
+#define AB8500_CODEC_CR1_SWRESET 7
+
+/* CR2-CR0x0002 */
+#define AB8500_CODEC_CR2_ENAD1 7
+#define AB8500_CODEC_CR2_ENAD2 6
+#define AB8500_CODEC_CR2_ENAD3 5
+#define AB8500_CODEC_CR2_ENAD4 4
+#define AB8500_CODEC_CR2_ENAD5 3
+#define AB8500_CODEC_CR2_ENAD6 2
+
+/* CR3-CR0x0003 */
+#define AB8500_CODEC_CR3_ENDA1 7
+#define AB8500_CODEC_CR3_ENDA2 6
+#define AB8500_CODEC_CR3_ENDA3 5
+#define AB8500_CODEC_CR3_ENDA4 4
+#define AB8500_CODEC_CR3_ENDA5 3
+#define AB8500_CODEC_CR3_ENDA6 2
+
+/* CR4-CR0x0004 */
+#define AB8500_CODEC_CR4_LOWPOWHS 7
+#define AB8500_CODEC_CR4_LOWPOWDACHS 5
+#define AB8500_CODEC_CR4_LOWPOWEAR 4
+#define AB8500_CODEC_CR4_EAR_SEL_CM 2
+#define AB8500_CODEC_CR4_HS_HP_DIS 1
+#define AB8500_CODEC_CR4_EAR_HP_DIS 0
+
+/* CR5-CR0x0005 */
+#define AB8500_CODEC_CR5_ENMIC1 7
+#define AB8500_CODEC_CR5_ENMIC2 6
+#define AB8500_CODEC_CR5_ENLINL 5
+#define AB8500_CODEC_CR5_ENLINR 4
+#define AB8500_CODEC_CR5_MUTMIC1 3
+#define AB8500_CODEC_CR5_MUTMIC2 2
+#define AB8500_CODEC_CR5_MUTELINL 1
+#define AB8500_CODEC_CR5_MUTELINR 0
+
+/* CR6-CR0x0006 */
+#define AB8500_CODEC_CR6_ENDMIC1 7
+#define AB8500_CODEC_CR6_ENDMIC2 6
+#define AB8500_CODEC_CR6_ENDMIC3 5
+#define AB8500_CODEC_CR6_ENDMIC4 4
+#define AB8500_CODEC_CR6_ENDMIC5 3
+#define AB8500_CODEC_CR6_ENDMIC6 2
+
+/* CR7-CR0x0007 */
+#define AB8500_CODEC_CR7_MIC1SEL 7
+#define AB8500_CODEC_CR7_LINRSEL 6
+#define AB8500_CODEC_CR7_ENDRVHSL 5
+#define AB8500_CODEC_CR7_ENDRVHSR 4
+#define AB8500_CODEC_CR7_ENADCMIC 2
+#define AB8500_CODEC_CR7_ENADCLINL 1
+#define AB8500_CODEC_CR7_ENADCLINR 0
+
+/* CR8-CR0x0008 */
+#define AB8500_CODEC_CR8_CP_DIS_PLDWN 7
+#define AB8500_CODEC_CR8_ENEAR 6
+#define AB8500_CODEC_CR8_ENHSL 5
+#define AB8500_CODEC_CR8_ENHSR 4
+#define AB8500_CODEC_CR8_ENHFL 3
+#define AB8500_CODEC_CR8_ENHFR 2
+#define AB8500_CODEC_CR8_ENVIBL 1
+#define AB8500_CODEC_CR8_ENVIBR 0
+
+/* CR9-CR0x0009 */
+#define AB8500_CODEC_CR9_ENADACEAR 6
+#define AB8500_CODEC_CR9_ENADACHSL 5
+#define AB8500_CODEC_CR9_ENADACHSR 4
+#define AB8500_CODEC_CR9_ENADACHFL 3
+#define AB8500_CODEC_CR9_ENADACHFR 2
+#define AB8500_CODEC_CR9_ENADACVIBL 1
+#define AB8500_CODEC_CR9_ENADACVIBR 0
+
+/* CR10-CR0x000A */
+#define AB8500_CODEC_CR10_MUTEEAR 6
+#define AB8500_CODEC_CR10_MUTEHSL 5
+#define AB8500_CODEC_CR10_MUTEHSR 4
+#define AB8500_CODEC_CR10_MUTEHFL 3
+#define AB8500_CODEC_CR10_MUTEHFR 2
+#define AB8500_CODEC_CR10_MUTEVIBL 1
+#define AB8500_CODEC_CR10_MUTEVIBR 0
+
+/* CR11-CR0x000B */
+#define AB8500_CODEC_CR11_ENSHORTPWD 7
+#define AB8500_CODEC_CR11_EARSHORTDIS 6
+#define AB8500_CODEC_CR11_HSLSHORTDIS 5
+#define AB8500_CODEC_CR11_HSRSHORTDIS 4
+#define AB8500_CODEC_CR11_HFLSHORTDIS 3
+#define AB8500_CODEC_CR11_HFRSHORTDIS 2
+#define AB8500_CODEC_CR11_VIBLSHORTDIS 1
+#define AB8500_CODEC_CR11_VIBRSHORTDIS 0
+
+/* CR12-CR0x000C */
+#define AB8500_CODEC_CR12_ENCPHS 7
+#define AB8500_CODEC_CR12_HSAUTOTIME 4
+#define AB8500_CODEC_CR12_HSAUTOENSEL 1
+#define AB8500_CODEC_CR12_HSAUTOEN 0
+
+/* CR13-CR0x000D */
+#define AB8500_CODEC_CR13_ENVDET_HTHRESH 4
+#define AB8500_CODEC_CR13_ENVDET_LTHRESH 0
+
+/* CR14-CR0x000E */
+#define AB8500_CODEC_CR14_SMPSLVEN 7
+#define AB8500_CODEC_CR14_ENVDETSMPSEN 6
+#define AB8500_CODEC_CR14_CPLVEN 5
+#define AB8500_CODEC_CR14_ENVDETCPEN 4
+#define AB8500_CODEC_CR14_ENVDET_TIME 0
+
+/* CR15-CR0x000F */
+#define AB8500_CODEC_CR15_PWMTOVIBL 7
+#define AB8500_CODEC_CR15_PWMTOVIBR 6
+#define AB8500_CODEC_CR15_PWMLCTRL 5
+#define AB8500_CODEC_CR15_PWMRCTRL 4
+#define AB8500_CODEC_CR15_PWMNLCTRL 3
+#define AB8500_CODEC_CR15_PWMPLCTRL 2
+#define AB8500_CODEC_CR15_PWMNRCTRL 1
+#define AB8500_CODEC_CR15_PWMPRCTRL 0
+
+/* CR16-CR0x0010 */
+#define AB8500_CODEC_CR16_PWMNLPOL 7
+#define AB8500_CODEC_CR16_PWMNLDUTYCYCLE 0
+
+/* CR17-CR0x0011 */
+#define AB8500_CODEC_CR17_PWMPLPOL 7
+#define AB8500_CODEC_CR17_PWMLPDUTYCYCLE 0
+
+/* CR18-CR0x0012 */
+#define AB8500_CODEC_CR18_PWMNRPOL 7
+#define AB8500_CODEC_CR18_PWMNRDUTYCYCLE 0
+
+/* CR19-CR0x0013 */
+#define AB8500_CODEC_CR19_PWMPRPOL 7
+#define AB8500_CODEC_CR19_PWMRPDUTYCYCLE 0
+
+/* CR20-CR0x0014 */
+#define AB8500_CODEC_CR20_EN_SE_MIC1 7
+#define AB8500_CODEC_CR20_MIC1_GAIN 0
+
+/* CR21-CR0x0015 */
+#define AB8500_CODEC_CR21_EN_SE_MIC2 7
+#define AB8500_CODEC_CR21_MIC2_GAIN 0
+
+/* CR22-CR0x0016 */
+#define AB8500_CODEC_CR22_HSL_GAIN 5
+#define AB8500_CODEC_CR22_LINL_GAIN 0
+
+/* CR23-CR0x0017 */
+#define AB8500_CODEC_CR23_HSR_GAIN 5
+#define AB8500_CODEC_CR23_LINR_GAIN 0
+
+/* CR24-CR0x0018 */
+#define AB8500_CODEC_CR24_LINTOHSL_GAIN 0
+
+/* CR25-CR0x0019 */
+#define AB8500_CODEC_CR25_LINTOHSR_GAIN 0
+
+/* CR26-CR0x001A */
+#define AB8500_CODEC_CR26_AD1NH 7
+#define AB8500_CODEC_CR26_AD2NH 6
+#define AB8500_CODEC_CR26_AD3NH 5
+#define AB8500_CODEC_CR26_AD4NH 4
+#define AB8500_CODEC_CR26_AD1_VOICE 3
+#define AB8500_CODEC_CR26_AD2_VOICE 2
+#define AB8500_CODEC_CR26_AD3_VOICE 1
+#define AB8500_CODEC_CR26_AD4_VOICE 0
+
+/* CR27-CR0x001B */
+#define AB8500_CODEC_CR27_EN_MASTGEN 7
+#define AB8500_CODEC_CR27_IF1_BITCLK_OSR 5
+#define AB8500_CODEC_CR27_ENFS_BITCLK1 4
+#define AB8500_CODEC_CR27_IF0_BITCLK_OSR 1
+#define AB8500_CODEC_CR27_ENFS_BITCLK0 0
+
+/* CR28-CR0x001C */
+#define AB8500_CODEC_CR28_FSYNC0P 6
+#define AB8500_CODEC_CR28_BITCLK0P 5
+#define AB8500_CODEC_CR28_IF0DEL 4
+#define AB8500_CODEC_CR28_IF0FORMAT 2
+#define AB8500_CODEC_CR28_IF0WL 0
+
+/* CR29-CR0x001D */
+#define AB8500_CODEC_CR29_IF0DATOIF1AD 7
+#define AB8500_CODEC_CR29_IF0CKTOIF1CK 6
+#define AB8500_CODEC_CR29_IF1MASTER 5
+#define AB8500_CODEC_CR29_IF1DATOIF0AD 3
+#define AB8500_CODEC_CR29_IF1CKTOIF0CK 2
+#define AB8500_CODEC_CR29_IF0MASTER 1
+#define AB8500_CODEC_CR29_IF0BFIFOEN 0
+
+/* CR30-CR0x001E */
+#define AB8500_CODEC_CR30_FSYNC1P 6
+#define AB8500_CODEC_CR30_BITCLK1P 5
+#define AB8500_CODEC_CR30_IF1DEL 4
+#define AB8500_CODEC_CR30_IF1FORMAT 2
+#define AB8500_CODEC_CR30_IF1WL 0
+
+/* CR31-CR0x001F */
+#define AB8500_CODEC_CR31_ADOTOSLOT1 4
+#define AB8500_CODEC_CR31_ADOTOSLOT0 0
+
+/* CR32-CR0x0020 */
+#define AB8500_CODEC_CR32_ADOTOSLOT3 4
+#define AB8500_CODEC_CR32_ADOTOSLOT2 0
+
+/* CR33-CR0x0021 */
+#define AB8500_CODEC_CR33_ADOTOSLOT5 4
+#define AB8500_CODEC_CR33_ADOTOSLOT4 0
+
+/* CR34-CR0x0022 */
+#define AB8500_CODEC_CR34_ADOTOSLOT7 4
+#define AB8500_CODEC_CR34_ADOTOSLOT6 0
+
+/* CR35-CR0x0023 */
+#define AB8500_CODEC_CR35_ADOTOSLOT9 4
+#define AB8500_CODEC_CR35_ADOTOSLOT8 0
+
+/* CR36-CR0x0024 */
+#define AB8500_CODEC_CR36_ADOTOSLOT11 4
+#define AB8500_CODEC_CR36_ADOTOSLOT10 0
+
+/* CR37-CR0x0025 */
+#define AB8500_CODEC_CR37_ADOTOSLOT13 4
+#define AB8500_CODEC_CR37_ADOTOSLOT12 0
+
+/* CR38-CR0x0026 */
+#define AB8500_CODEC_CR38_ADOTOSLOT15 4
+#define AB8500_CODEC_CR38_ADOTOSLOT14 0
+
+/* CR39-CR0x0027 */
+#define AB8500_CODEC_CR39_ADOTOSLOT17 4
+#define AB8500_CODEC_CR39_ADOTOSLOT16 0
+
+/* CR40-CR0x0028 */
+#define AB8500_CODEC_CR40_ADOTOSLOT19 4
+#define AB8500_CODEC_CR40_ADOTOSLOT18 0
+
+/* CR41-CR0x0029 */
+#define AB8500_CODEC_CR41_ADOTOSLOT21 4
+#define AB8500_CODEC_CR41_ADOTOSLOT20 0
+
+/* CR42-CR0x002A */
+#define AB8500_CODEC_CR42_ADOTOSLOT23 4
+#define AB8500_CODEC_CR42_ADOTOSLOT22 0
+
+/* CR43-CR0x002B */
+#define AB8500_CODEC_CR43_ADOTOSLOT25 4
+#define AB8500_CODEC_CR43_ADOTOSLOT24 0
+
+/* CR44-CR0x002C */
+#define AB8500_CODEC_CR44_ADOTOSLOT27 4
+#define AB8500_CODEC_CR44_ADOTOSLOT26 0
+
+/* CR45-CR0x002D */
+#define AB8500_CODEC_CR45_ADOTOSLOT29 4
+#define AB8500_CODEC_CR45_ADOTOSLOT28 0
+
+/* CR46-CR0x002E */
+#define AB8500_CODEC_CR46_ADOTOSLOT31 4
+#define AB8500_CODEC_CR46_ADOTOSLOT30 0
+
+/* CR47-CR0x002F */
+#define AB8500_CODEC_CR47_HIZ_SL7 7
+#define AB8500_CODEC_CR47_HIZ_SL6 6
+#define AB8500_CODEC_CR47_HIZ_SL5 5
+#define AB8500_CODEC_CR47_HIZ_SL4 4
+#define AB8500_CODEC_CR47_HIZ_SL3 3
+#define AB8500_CODEC_CR47_HIZ_SL2 2
+#define AB8500_CODEC_CR47_HIZ_SL1 1
+#define AB8500_CODEC_CR47_HIZ_SL0 0
+
+/* CR48-CR0x0030 */
+#define AB8500_CODEC_CR48_HIZ_SL15 7
+#define AB8500_CODEC_CR48_HIZ_SL14 6
+#define AB8500_CODEC_CR48_HIZ_SL13 5
+#define AB8500_CODEC_CR48_HIZ_SL12 4
+#define AB8500_CODEC_CR48_HIZ_SL11 3
+#define AB8500_CODEC_CR48_HIZ_SL10 2
+#define AB8500_CODEC_CR48_HIZ_SL9 1
+#define AB8500_CODEC_CR48_HIZ_SL8 0
+
+/* CR49-CR0x0031 */
+#define AB8500_CODEC_CR49_HIZ_SL23 7
+#define AB8500_CODEC_CR49_HIZ_SL22 6
+#define AB8500_CODEC_CR49_HIZ_SL21 5
+#define AB8500_CODEC_CR49_HIZ_SL20 4
+#define AB8500_CODEC_CR49_HIZ_SL19 3
+#define AB8500_CODEC_CR49_HIZ_SL18 2
+#define AB8500_CODEC_CR49_HIZ_SL17 1
+#define AB8500_CODEC_CR49_HIZ_SL16 0
+
+/* CR50-CR0x0032 */
+#define AB8500_CODEC_CR50_HIZ_SL31 7
+#define AB8500_CODEC_CR50_HIZ_SL30 6
+#define AB8500_CODEC_CR50_HIZ_SL29 5
+#define AB8500_CODEC_CR50_HIZ_SL28 4
+#define AB8500_CODEC_CR50_HIZ_SL27 3
+#define AB8500_CODEC_CR50_HIZ_SL26 2
+#define AB8500_CODEC_CR50_HIZ_SL25 1
+#define AB8500_CODEC_CR50_HIZ_SL24 0
+
+/* CR51-CR0x0033 */
+#define AB8500_CODEC_CR51_DA12_VOICE 7
+#define AB8500_CODEC_CR51_SLDAI1TOSLADO1 5
+#define AB8500_CODEC_CR51_SLTODA1 0
+
+/* CR52-CR0x0034 */
+#define AB8500_CODEC_CR52_SLDAI1TOSLADO2 5
+#define AB8500_CODEC_CR52_SLTODA2 0
+
+/* CR53-CR0x0035 */
+#define AB8500_CODEC_CR53_DA34_VOICE 7
+#define AB8500_CODEC_CR53_SLDAI1TOSLADO3 5
+#define AB8500_CODEC_CR53_SLTODA3 0
+
+/* CR54-CR0x0036 */
+#define AB8500_CODEC_CR54_SLDAI1TOSLADO4 5
+#define AB8500_CODEC_CR54_SLTODA4 0
+
+/* CR55-CR0x0037 */
+#define AB8500_CODEC_CR55_DA56_VOICE 7
+#define AB8500_CODEC_CR55_SLDAI1TOSLADO5 5
+#define AB8500_CODEC_CR55_SLTODA5 0
+
+/* CR56-CR0x0038 */
+#define AB8500_CODEC_CR56_SLDAI1TOSLADO6 5
+#define AB8500_CODEC_CR56_SLTODA6 0
+
+/* CR57-CR0x0039 */
+#define AB8500_CODEC_CR57_BFIFULL_MSK 6
+#define AB8500_CODEC_CR57_BFIEMPT_MSK 5
+#define AB8500_CODEC_CR57_DACHAN_MSK 4
+#define AB8500_CODEC_CR57_GAIN_MSK 3
+#define AB8500_CODEC_CR57_DSPAD_MSK 2
+#define AB8500_CODEC_CR57_DSPDA_MSK 1
+#define AB8500_CODEC_CR57_STFIR_MSK 0
+
+/* CR58-CR0x003A */
+#define AB8500_CODEC_CR58_BFIFULL_EV 6
+#define AB8500_CODEC_CR58_BFIEMPT_EV 5
+#define AB8500_CODEC_CR58_DACHAN_EV 4
+#define AB8500_CODEC_CR58_GAIN_EV 3
+#define AB8500_CODEC_CR58_DSPAD_EV 2
+#define AB8500_CODEC_CR58_DSPDA_EV 1
+#define AB8500_CODEC_CR58_STFIR_EV 0
+
+/* CR59-CR0x003B */
+#define AB8500_CODEC_CR59_VSSREADY_MSK 7
+#define AB8500_CODEC_CR59_SHRTVIBL_MSK 6
+#define AB8500_CODEC_CR59_SHRTVIBR_MSK 5
+#define AB8500_CODEC_CR59_SHRTHFL_MSK 4
+#define AB8500_CODEC_CR59_SHRTHFR_MSK 3
+#define AB8500_CODEC_CR59_SHRTHSL_MSK 2
+#define AB8500_CODEC_CR59_SHRTHSR_MSK 1
+#define AB8500_CODEC_CR59_SHRTEAR_MSK 0
+
+/* CR60-CR0x003C */
+#define AB8500_CODEC_CR60_VSSREADY_EV 7
+#define AB8500_CODEC_CR60_SHRTVIBL_EV 6
+#define AB8500_CODEC_CR60_SHRTVIBR_EV 5
+#define AB8500_CODEC_CR60_SHRTHFL_EV 4
+#define AB8500_CODEC_CR60_SHRTHFR_EV 3
+#define AB8500_CODEC_CR60_SHRTHSL_EV 2
+#define AB8500_CODEC_CR60_SHRTHSR_EV 1
+#define AB8500_CODEC_CR60_SHRTEAR_EV 0
+
+/* CR61-CR0x003D */
+#define AB8500_CODEC_CR61_REVISION 2
+#define AB8500_CODEC_CR61_FADE_SPEED 0
+
+/* CR62-CR0x003E */
+#define AB8500_CODEC_CR62_DMIC1SINC3 5
+#define AB8500_CODEC_CR62_DMIC2SINC3 4
+#define AB8500_CODEC_CR62_DMIC3SINC3 3
+#define AB8500_CODEC_CR62_DMIC4SINC3 2
+#define AB8500_CODEC_CR62_DMIC5SINC3 1
+#define AB8500_CODEC_CR62_DMIC6SINC3 0
+
+/* CR63-CR0x003F */
+#define AB8500_CODEC_CR63_DATOHSLEN 7
+#define AB8500_CODEC_CR63_DATOHSREN 6
+#define AB8500_CODEC_CR63_AD1SEL 5
+#define AB8500_CODEC_CR63_AD2SEL 4
+#define AB8500_CODEC_CR63_AD3SEL 3
+#define AB8500_CODEC_CR63_AD5SEL 2
+#define AB8500_CODEC_CR63_AD6SEL 1
+#define AB8500_CODEC_CR63_ANCSEL 0
+
+/* CR64-CR0x0040 */
+#define AB8500_CODEC_CR64_DATOHFREN 7
+#define AB8500_CODEC_CR64_DATOHFLEN 6
+#define AB8500_CODEC_CR64_HFRSEL 5
+#define AB8500_CODEC_CR64_HFLSEL 4
+#define AB8500_CODEC_CR64_STFIR1SEL 2
+#define AB8500_CODEC_CR64_STFIR2SEL 0
+
+/* CR65-CR0x0041 */
+#define AB8500_CODEC_CR65_FADEDIS_AD1 6
+#define AB8500_CODEC_CR65_AD1GAIN 0
+
+/* CR66-CR0x0042 */
+#define AB8500_CODEC_CR66_FADEDIS_AD2 6
+#define AB8500_CODEC_CR66_AD2GAIN 0
+
+/* CR67-CR0x0043 */
+#define AB8500_CODEC_CR67_FADEDIS_AD3 6
+#define AB8500_CODEC_CR67_AD3GAIN 0
+
+/* CR68-CR0x0044 */
+#define AB8500_CODEC_CR68_FADEDIS_AD4 6
+#define AB8500_CODEC_CR68_AD4GAIN 0
+
+/* CR69-CR0x0045 */
+#define AB8500_CODEC_CR69_FADEDIS_AD5 6
+#define AB8500_CODEC_CR69_AD5GAIN 0
+
+/* CR70-CR0x0046 */
+#define AB8500_CODEC_CR70_FADEDIS_AD6 6
+#define AB8500_CODEC_CR70_AD6GAIN 0
+
+/* CR71-CR0x0047 */
+#define AB8500_CODEC_CR71_FADEDIS_DA1 6
+#define AB8500_CODEC_CR71_DA1GAIN 0
+
+/* CR72-CR0x0048 */
+#define AB8500_CODEC_CR72_FADEDIS_DA2 6
+#define AB8500_CODEC_CR72_DA2GAIN 0
+
+/* CR73-CR0x0049 */
+#define AB8500_CODEC_CR73_FADEDIS_DA3 6
+#define AB8500_CODEC_CR73_DA3GAIN 0
+
+/* CR74-CR0x004A */
+#define AB8500_CODEC_CR74_FADEDIS_DA4 6
+#define AB8500_CODEC_CR74_DA4GAIN 0
+
+/* CR75-CR0x004B */
+#define AB8500_CODEC_CR75_FADEDIS_DA5 6
+#define AB8500_CODEC_CR75_DA5GAIN 0
+
+/* CR76-CR0x004C */
+#define AB8500_CODEC_CR76_FADEDIS_DA6 6
+#define AB8500_CODEC_CR76_DA6GAIN 0
+
+/* CR77-CR0x004D */
+#define AB8500_CODEC_CR77_FADEDIS_AD1L 6
+#define AB8500_CODEC_CR77_AD1LBGAIN 0
+
+/* CR78-CR0x004E */
+#define AB8500_CODEC_CR78_FADEDIS_AD2L 6
+#define AB8500_CODEC_CR78_AD2LBGAIN 0
+
+/* CR79-CR0x004F */
+#define AB8500_CODEC_CR79_HSSINC1 7
+#define AB8500_CODEC_CR79_FADEDIS_HSL 4
+#define AB8500_CODEC_CR79_HSLDGAIN 0
+
+/* CR80-CR0x0050 */
+#define AB8500_CODEC_CR80_FADEDIS_HSR 4
+#define AB8500_CODEC_CR80_HSRDGAIN 0
+
+/* CR81-CR0x0051 */
+#define AB8500_CODEC_CR81_STFIR1GAIN 0
+
+/* CR82-CR0x0052 */
+#define AB8500_CODEC_CR82_STFIR2GAIN 0
+
+/* CR83-CR0x0053 */
+#define AB8500_CODEC_CR83_ENANC 2
+#define AB8500_CODEC_CR83_ANCIIRINIT 1
+#define AB8500_CODEC_CR83_ANCFIRUPDATE 0
+
+/* CR84-CR0x0054 */
+#define AB8500_CODEC_CR84_ANCINSHIFT 0
+
+/* CR85-CR0x0055 */
+#define AB8500_CODEC_CR85_ANCFIROUTSHIFT 0
+
+/* CR86-CR0x0056 */
+#define AB8500_CODEC_CR86_ANCSHIFTOUT 0
+
+/* CR87-CR0x0057 */
+#define AB8500_CODEC_CR87_ANCFIRCOEFF_MSB 0
+
+/* CR88-CR0x0058 */
+#define AB8500_CODEC_CR88_ANCFIRCOEFF_LSB 0
+
+/* CR89-CR0x0059 */
+#define AB8500_CODEC_CR89_ANCIIRCOEFF_MSB 0
+
+/* CR90-CR0x005A */
+#define AB8500_CODEC_CR90_ANCIIRCOEFF_LSB 0
+
+/* CR91-CR0x005B */
+#define AB8500_CODEC_CR91_ANCWARPDEL_MSB 0
+
+/* CR92-CR0x005C */
+#define AB8500_CODEC_CR92_ANCWARPDEL_LSB 0
+
+/* CR93-CR0x005D */
+#define AB8500_CODEC_CR93_ANCFIRPEAK_MSB 0
+
+/* CR94-CR0x005E */
+#define AB8500_CODEC_CR94_ANCFIRPEAK_LSB 0
+
+/* CR95-CR0x005F */
+#define AB8500_CODEC_CR95_ANCIIRPEAK_MSB 0
+
+/* CR96-CR0x0060 */
+#define AB8500_CODEC_CR96_ANCIIRPEAK_LSB 0
+
+/* CR97-CR0x0061 */
+#define AB8500_CODEC_CR97_STFIR_SET 7
+#define AB8500_CODEC_CR97_STFIR_ADDR 0
+
+/* CR98-CR0x0062 */
+#define AB8500_CODEC_CR98_STFIR_COEFF_MSB 0
+
+/* CR99-CR0x0063 */
+#define AB8500_CODEC_CR99_STFIR_COEFF_LSB 0
+
+/* CR100-CR0x0064 */
+#define AB8500_CODEC_CR100_ENSTFIRS 2
+#define AB8500_CODEC_CR100_STFIRSTOIF1 1
+#define AB8500_CODEC_CR100_STFIR_BUSY 0
+
+/* CR101-CR0x0065 */
+#define AB8500_CODEC_CR101_PARLHF 7
+#define AB8500_CODEC_CR101_PARLVIB 6
+#define AB8500_CODEC_CR101_CLASSDVIBLSWAPEN 3
+#define AB8500_CODEC_CR101_CLASSDVIBRSWAPEN 2
+#define AB8500_CODEC_CR101_CLASSDHFLSWAPEN 1
+#define AB8500_CODEC_CR101_CLASSDHFRSWAPEN 0
+
+/* CR102-CR0x0066 */
+#define AB8500_CODEC_CR102_CLASSD_FIRBYP 4
+#define AB8500_CODEC_CR102_CLASSD_HIGHVOLEN 0
+
+/* CR103-CR0x0067 */
+#define AB8500_CODEC_CR103_CLASSD_DITHERHPGAIN 4
+#define AB8500_CODEC_CR103_CLASSD_DITHERWGAIN 0
+
+/* CR104-CR0x0068 */
+#define AB8500_CODEC_CR104_BFIFOINT 0
+
+/* CR105-CR0x0069 */
+#define AB8500_CODEC_CR105_BFIFOTX 0
+
+/* CR106-CR0x006A */
+#define AB8500_CODEC_CR106_BFIFOFSEXT 4
+#define AB8500_CODEC_CR106_BFIFOMSK 2
+#define AB8500_CODEC_CR106_BFIFOMSTR 1
+#define AB8500_CODEC_CR106_BFIFOSTRT 0
+
+/* CR107-CR0x006B */
+#define AB8500_CODEC_CR107_BFIFOSAMPNR 0
+
+/* CR108-CR0x006C */
+#define AB8500_CODEC_CR108_BFIFOWAKEUP 0
+
+/* CR109-CR0x006D */
+#define AB8500_CODEC_CR109_BFIFOSAMPLES 0
+
+/* For SetVolume API*/
+#define AB8500_CODEC_MAX_VOLUME 100
+
+/* Analog MIC1 & MIC2 */
+#define AB8500_CODEC_MIC_VOLUME_MAX 31
+#define AB8500_CODEC_MIC_VOLUME_MEDIUM 15
+#define AB8500_CODEC_MIC_VOLUME_MIN 0
+
+/* Line-in */
+#define AB8500_CODEC_LINEIN_VOLUME_MAX 31
+#define AB8500_CODEC_LINEIN_VOLUME_MEDIUM 15
+#define AB8500_CODEC_LINEIN_VOLUME_MIN 0
+
+/* HeadSet */
+#define AB8500_CODEC_HEADSET_VOLUME_MAX 0
+#define AB8500_CODEC_HEADSET_VOLUME_MEDIUM 3
+#define AB8500_CODEC_HEADSET_VOLUME_MIN 7
+
+/* HeadSet Digital */
+#define AB8500_CODEC_HEADSET_D_VOLUME_MAX 0
+#define AB8500_CODEC_HEADSET_D_VOLUME_MEDIUM 7
+#define AB8500_CODEC_HEADSET_D_VOLUME_MIN 15
+#define AB8500_CODEC_HEADSET_D_VOLUME_0DB 8
+
+/* Digital AD Path */
+#define AB8500_CODEC_AD_D_VOLUME_MAX 0
+#define AB8500_CODEC_AD_D_VOLUME_MEDIUM 31
+#define AB8500_CODEC_AD_D_VOLUME_MIN 63
+
+/* Digital DA Path */
+#define AB8500_CODEC_DA_D_VOLUME_MAX 0
+#define AB8500_CODEC_DA_D_VOLUME_MEDIUM 31
+#define AB8500_CODEC_DA_D_VOLUME_MIN 63
+
+/* EarPiece Digital */
+#define AB8500_CODEC_EARPIECE_D_VOLUME_MAX 0
+#define AB8500_CODEC_EARPIECE_D_VOLUME_MEDIUM 7
+#define AB8500_CODEC_EARPIECE_D_VOLUME_MIN 15
+
+/* AD1 loopback to HFL & HFR Digital */
+#define AB8500_CODEC_AD_LB_TO_HF_L_R_VOLUME_MAX 0
+#define AB8500_CODEC_AD_LB_TO_HF_L_R_VOLUME_MEDIUM 31
+#define AB8500_CODEC_AD_LB_TO_HF_L_R_VOLUME_MIN 63
+
+/* Line-in to HSL & HSR */
+#define AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MAX 0
+#define AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MEDIUM 9
+#define AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN 18
+#define AB8500_CODEC_LINEIN_TO_HS_L_R_LOOP_OPEN 19
+
+/* Vibrator */
+#define AB8500_CODEC_VIBRATOR_VOLUME_MAX 100
+#define AB8500_CODEC_VIBRATOR_VOLUME_MEDIUM 50
+#define AB8500_CODEC_VIBRATOR_VOLUME_MIN 0
+
+/* CR0 - 7 */
+typedef enum {
+ AB8500_CODEC_CR0_POWERUP_OFF,
+ AB8500_CODEC_CR0_POWERUP_ON
+} t_ab8500_codec_cr0_powerup;
+
+/* CR0 - 3 */
+typedef enum {
+ AB8500_CODEC_CR0_ENAANA_OFF,
+ AB8500_CODEC_CR0_ENAANA_ON
+} t_ab8500_codec_cr0_enaana;
+
+/* CR1 - 7 */
+typedef enum {
+ AB8500_CODEC_CR1_SWRESET_DISABLED,
+ AB8500_CODEC_CR1_SWRESET_ENABLED
+} t_ab8500_codec_cr1_swreset;
+
+/* CR2 - 7 */
+typedef enum {
+ AB8500_CODEC_CR2_ENAD1_DISABLED,
+ AB8500_CODEC_CR2_ENAD1_ENABLED
+} t_ab8500_codec_cr2_enad1;
+
+/* CR2 - 6 */
+typedef enum {
+ AB8500_CODEC_CR2_ENAD2_DISABLED,
+ AB8500_CODEC_CR2_ENAD2_ENABLED
+} t_ab8500_codec_cr2_enad2;
+
+/* CR2 - 5 */
+typedef enum {
+ AB8500_CODEC_CR2_ENAD3_DISABLED,
+ AB8500_CODEC_CR2_ENAD3_ENABLED
+} t_ab8500_codec_cr2_enad3;
+
+/* CR2 - 4 */
+typedef enum {
+ AB8500_CODEC_CR2_ENAD4_DISABLED,
+ AB8500_CODEC_CR2_ENAD4_ENABLED
+} t_ab8500_codec_cr2_enad4;
+
+/* CR2 - 3 */
+typedef enum {
+ AB8500_CODEC_CR2_ENAD5_DISABLED,
+ AB8500_CODEC_CR2_ENAD5_ENABLED
+} t_ab8500_codec_cr2_enad5;
+
+/* CR2 - 2 */
+typedef enum {
+ AB8500_CODEC_CR2_ENAD6_DISABLED,
+ AB8500_CODEC_CR2_ENAD6_ENABLED
+} t_ab8500_codec_cr2_enad6;
+
+/* CR3 - 7 */
+typedef enum {
+ AB8500_CODEC_CR3_ENDA1_DISABLED,
+ AB8500_CODEC_CR3_ENDA1_ENABLED
+} t_ab8500_codec_cr3_enda1;
+
+/* CR3 - 6 */
+typedef enum {
+ AB8500_CODEC_CR3_ENDA2_DISABLED,
+ AB8500_CODEC_CR3_ENDA2_ENABLED
+} t_ab8500_codec_cr3_enda2;
+
+/* CR3 - 5 */
+typedef enum {
+ AB8500_CODEC_CR3_ENDA3_DISABLED,
+ AB8500_CODEC_CR3_ENDA3_ENABLED
+} t_ab8500_codec_cr3_enda3;
+
+/* CR3 - 4 */
+typedef enum {
+ AB8500_CODEC_CR3_ENDA4_DISABLED,
+ AB8500_CODEC_CR3_ENDA4_ENABLED
+} t_ab8500_codec_cr3_enda4;
+
+/* CR3 - 3 */
+typedef enum {
+ AB8500_CODEC_CR3_ENDA5_DISABLED,
+ AB8500_CODEC_CR3_ENDA5_ENABLED
+} t_ab8500_codec_cr3_enda5;
+
+/* CR3 - 2 */
+typedef enum {
+ AB8500_CODEC_CR3_ENDA6_DISABLED,
+ AB8500_CODEC_CR3_ENDA6_ENABLED
+} t_ab8500_codec_cr3_enda6;
+
+/* CR4 - 7 */
+typedef enum {
+ AB8500_CODEC_CR4_LOWPOWHS_NORMAL,
+ AB8500_CODEC_CR4_LOWPOWHS_LP
+} t_ab8500_codec_cr4_lowpowhs;
+
+/* CR4 - 6:5 */
+typedef enum {
+ AB8500_CODEC_CR4_LOWPOWDACHS_NORMAL,
+ AB8500_CODEC_CR4_LOWPOWDACHS_DRIVERS_LP,
+ AB8500_CODEC_CR4_LOWPOWDACHS_LP,
+ AB8500_CODEC_CR4_LOWPOWDACHS_BOTH_LP
+} t_ab8500_codec_cr4_lowpowdachs;
+
+/* CR4 - 4 */
+typedef enum {
+ AB8500_CODEC_CR4_LOWPOWEAR_NORMAL,
+ AB8500_CODEC_CR4_LOWPOWEAR_LP
+} t_ab8500_codec_cr4_lowpowear;
+
+/* CR4 - 3:2 */
+typedef enum {
+ AB8500_CODEC_CR4_EAR_SEL_CM_0_95V,
+ AB8500_CODEC_CR4_EAR_SEL_CM_1_1V,
+ AB8500_CODEC_CR4_EAR_SEL_CM_1_27V,
+ AB8500_CODEC_CR4_EAR_SEL_CM_1_58V
+} t_ab8500_codec_cr4_ear_sel_cm;
+
+/* CR4 - 1 */
+typedef enum {
+ AB8500_CODEC_CR4_HS_HP_DIS_FILTER_ENABLED,
+ AB8500_CODEC_CR4_HS_HP_DIS_FILTER_DISABLED
+} t_ab8500_codec_cr4_hs_hp_dis;
+
+/* CR4 - 0 */
+typedef enum {
+ AB8500_CODEC_CR4_EAR_HP_DIS_FILTER_ENABLED,
+ AB8500_CODEC_CR4_EAR_HP_DIS_FILTER_DISABLED
+} t_ab8500_codec_cr4_ear_hp_dis;
+
+/* CR5 - 7 */
+typedef enum {
+ AB8500_CODEC_CR5_ENMIC1_DISABLED,
+ AB8500_CODEC_CR5_ENMIC1_ENABLED
+} t_ab8500_codec_cr5_enmic1;
+
+/* CR5 - 6 */
+typedef enum {
+ AB8500_CODEC_CR5_ENMIC2_DISABLED,
+ AB8500_CODEC_CR5_ENMIC2_ENABLED
+} t_ab8500_codec_cr5_enmic2;
+
+/* CR5 - 5 */
+typedef enum {
+ AB8500_CODEC_CR5_ENLINL_DISABLED,
+ AB8500_CODEC_CR5_ENLINL_ENABLED
+} t_ab8500_codec_cr5_enlinl;
+
+/* CR5 - 4 */
+typedef enum {
+ AB8500_CODEC_CR5_ENLINR_DISABLED,
+ AB8500_CODEC_CR5_ENLINR_ENABLED
+} t_ab8500_codec_cr5_enlinr;
+
+/* CR5 - 3 */
+typedef enum {
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED,
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED
+} t_ab8500_codec_cr5_mutmic1;
+
+/* CR5 - 2 */
+typedef enum {
+ AB8500_CODEC_CR5_MUTMIC2_DISABLED,
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED
+} t_ab8500_codec_cr5_mutmic2;
+
+/* CR5 - 1 */
+typedef enum {
+ AB8500_CODEC_CR5_MUTLINL_DISABLED,
+ AB8500_CODEC_CR5_MUTLINL_ENABLED
+} t_ab8500_codec_cr5_mutlinl;
+
+/* CR5 - 0 */
+typedef enum {
+ AB8500_CODEC_CR5_MUTLINR_DISABLED,
+ AB8500_CODEC_CR5_MUTLINR_ENABLED
+} t_ab8500_codec_cr5_mutlinr;
+
+/* CR6 - 7 */
+typedef enum {
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED,
+ AB8500_CODEC_CR6_ENDMIC1_ENABLED
+} t_ab8500_codec_cr6_endmic1;
+
+/* CR6 - 6 */
+typedef enum {
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED,
+ AB8500_CODEC_CR6_ENDMIC2_ENABLED
+} t_ab8500_codec_cr6_endmic2;
+
+/* CR6 - 5 */
+typedef enum {
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED,
+ AB8500_CODEC_CR6_ENDMIC3_ENABLED
+} t_ab8500_codec_cr6_endmic3;
+
+/* CR6 - 4 */
+typedef enum {
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED,
+ AB8500_CODEC_CR6_ENDMIC4_ENABLED
+} t_ab8500_codec_cr6_endmic4;
+
+/* CR6 - 3 */
+typedef enum {
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED,
+ AB8500_CODEC_CR6_ENDMIC5_ENABLED
+} t_ab8500_codec_cr6_endmic5;
+
+/* CR6 - 2 */
+typedef enum {
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED,
+ AB8500_CODEC_CR6_ENDMIC6_ENABLED
+} t_ab8500_codec_cr6_endmic6;
+
+/* CR7 - 7 */
+typedef enum {
+ AB8500_CODEC_CR7_MIC1SEL_MIC1A,
+ AB8500_CODEC_CR7_MIC1SEL_MIC1B
+} t_ab8500_codec_cr7_mic1sel;
+
+/* CR7 - 6 */
+typedef enum {
+ AB8500_CODEC_CR7_LINRSEL_MIC2,
+ AB8500_CODEC_CR7_LINRSEL_LINR
+} t_ab8500_codec_cr7_linrsel;
+
+/* CR7 - 5 */
+typedef enum {
+ AB8500_CODEC_CR7_ENDRVHSL_DISABLED,
+ AB8500_CODEC_CR7_ENDRVHSL_ENABLED
+} t_ab8500_codec_cr7_endrvhsl;
+
+/* CR7 - 4 */
+typedef enum {
+ AB8500_CODEC_CR7_ENDRVHSR_DISABLED,
+ AB8500_CODEC_CR7_ENDRVHSR_ENABLED
+} t_ab8500_codec_cr7_endrvhsr;
+
+/* CR7 - 2 */
+typedef enum {
+ AB8500_CODEC_CR7_ENADCMIC_DISABLED,
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED
+} t_ab8500_codec_cr7_enadcmic;
+
+/* CR7 - 1 */
+typedef enum {
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED,
+ AB8500_CODEC_CR7_ENADCLINL_ENABLED
+} t_ab8500_codec_cr7_enadclinl;
+
+/* CR7 - 0 */
+typedef enum {
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED,
+ AB8500_CODEC_CR7_ENADCLINR_ENABLED
+} t_ab8500_codec_cr7_enadclinr;
+
+/* CR8 - 7 */
+typedef enum {
+ AB8500_CODEC_CR8_CP_DIS_PLDWN_ENABLED,
+ AB8500_CODEC_CR8_CP_DIS_PLDWN_DISABLED
+} t_ab8500_codec_cr8_cp_dis_pldwn;
+
+/* CR8 - 6 */
+typedef enum {
+ AB8500_CODEC_CR8_ENEAR_DISABLED,
+ AB8500_CODEC_CR8_ENEAR_ENABLED
+} t_ab8500_codec_cr8_enear;
+
+/* CR8 - 5 */
+typedef enum {
+ AB8500_CODEC_CR8_ENHSL_DISABLED,
+ AB8500_CODEC_CR8_ENHSL_ENABLED
+} t_ab8500_codec_cr8_enhsl;
+
+/* CR8 - 4 */
+typedef enum {
+ AB8500_CODEC_CR8_ENHSR_DISABLED,
+ AB8500_CODEC_CR8_ENHSR_ENABLED
+} t_ab8500_codec_cr8_enhsr;
+
+/* CR8 - 3 */
+typedef enum {
+ AB8500_CODEC_CR8_ENHFL_DISABLED,
+ AB8500_CODEC_CR8_ENHFL_ENABLED
+} t_ab8500_codec_cr8_enhfl;
+
+/* CR8 - 2 */
+typedef enum {
+ AB8500_CODEC_CR8_ENHFR_DISABLED,
+ AB8500_CODEC_CR8_ENHFR_ENABLED
+} t_ab8500_codec_cr8_enhfr;
+
+/* CR8 - 1 */
+typedef enum {
+ AB8500_CODEC_CR8_ENVIBL_DISABLED,
+ AB8500_CODEC_CR8_ENVIBL_ENABLED
+} t_ab8500_codec_cr8_envibl;
+
+/* CR8 - 0 */
+typedef enum {
+ AB8500_CODEC_CR8_ENVIBR_DISABLED,
+ AB8500_CODEC_CR8_ENVIBR_ENABLED
+} t_ab8500_codec_cr8_envibr;
+
+/* CR9 - 6 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACEAR_DISABLED,
+ AB8500_CODEC_CR9_ENDACEAR_ENABLED
+} t_ab8500_codec_cr9_endacear;
+
+/* CR9 - 5 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACHSL_DISABLED,
+ AB8500_CODEC_CR9_ENDACHSL_ENABLED
+} t_ab8500_codec_cr9_endachsl;
+
+/* CR9 - 4 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACHSR_DISABLED,
+ AB8500_CODEC_CR9_ENDACHSR_ENABLED
+} t_ab8500_codec_cr9_endachsr;
+
+/* CR9 - 3 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACHFL_DISABLED,
+ AB8500_CODEC_CR9_ENDACHFL_ENABLED
+} t_ab8500_codec_cr9_endachfl;
+
+/* CR9 - 2 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACHFR_DISABLED,
+ AB8500_CODEC_CR9_ENDACHFR_ENABLED
+} t_ab8500_codec_cr9_endachfr;
+
+/* CR9 - 1 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACVIBL_DISABLED,
+ AB8500_CODEC_CR9_ENDACVIBL_ENABLED
+} t_ab8500_codec_cr9_endacvibl;
+
+/* CR9 - 0 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACVIBR_DISABLED,
+ AB8500_CODEC_CR9_ENDACVIBR_ENABLED
+} t_ab8500_codec_cr9_endacvibr;
+
+/* CR10 - 6 */
+typedef enum {
+ AB8500_CODEC_CR10_MUTEEAR_DISABLED,
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED
+} t_ab8500_codec_cr10_muteear;
+
+/* CR10 - 5 */
+typedef enum {
+ AB8500_CODEC_CR10_MUTEHSL_DISABLED,
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED
+} t_ab8500_codec_cr10_mutehsl;
+
+/* CR10 - 4 */
+typedef enum {
+ AB8500_CODEC_CR10_MUTEHSR_DISABLED,
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED
+} t_ab8500_codec_cr10_mutehsr;
+
+/* CR10 - 3 */
+typedef enum {
+ AB8500_CODEC_CR10_MUTEHFL_DISABLED,
+ AB8500_CODEC_CR10_MUTEHFL_ENABLED
+} t_ab8500_codec_cr10_mutehfl;
+
+/* CR10 - 2 */
+typedef enum {
+ AB8500_CODEC_CR10_MUTEHFR_DISABLED,
+ AB8500_CODEC_CR10_MUTEHFR_ENABLED
+} t_ab8500_codec_cr10_mutehfr;
+
+/* CR10 - 1 */
+typedef enum {
+ AB8500_CODEC_CR10_MUTEVIBL_DISABLED,
+ AB8500_CODEC_CR10_MUTEVIBL_ENABLED
+} t_ab8500_codec_cr10_mutevibl;
+
+/* CR10 - 0 */
+typedef enum {
+ AB8500_CODEC_CR10_MUTEVIBR_DISABLED,
+ AB8500_CODEC_CR10_MUTEVIBR_ENABLED
+} t_ab8500_codec_cr10_mutevibr;
+
+/* CR11 - 7 */
+typedef enum {
+ AB8500_CODEC_CR11_EARSHORTPWD_DISABLED,
+ AB8500_CODEC_CR11_EARSHORTPWD_ENABLED
+} t_ab8500_codec_cr11_earshortpwd;
+
+/* CR11 - 6 */
+typedef enum {
+ AB8500_CODEC_CR11_EARSHORTDIS_ENABLED,
+ AB8500_CODEC_CR11_EARSHORTDIS_DISABLED
+} t_ab8500_codec_cr11_earshortdis;
+
+/* CR11 - 5 */
+typedef enum {
+ AB8500_CODEC_CR11_HSLSHORTDIS_ENABLED,
+ AB8500_CODEC_CR11_HSLSHORTDIS_DISABLED
+} t_ab8500_codec_cr11_hslshortdis;
+
+/* CR11 - 4 */
+typedef enum {
+ AB8500_CODEC_CR11_HSRSHORTDIS_ENABLED,
+ AB8500_CODEC_CR11_HSRSHORTDIS_DISABLED
+} t_ab8500_codec_cr11_hsrshortdis;
+
+/* CR11 - 3 */
+typedef enum {
+ AB8500_CODEC_CR11_HFLSHORTDIS_ENABLED,
+ AB8500_CODEC_CR11_HFLSHORTDIS_DISABLED
+} t_ab8500_codec_cr11_hflshortdis;
+
+/* CR11 - 2 */
+typedef enum {
+ AB8500_CODEC_CR11_HFRSHORTDIS_ENABLED,
+ AB8500_CODEC_CR11_HFRSHORTDIS_DISABLED
+} t_ab8500_codec_cr11_hfrshortdis;
+
+/* CR11 - 1 */
+typedef enum {
+ AB8500_CODEC_CR11_VIBLSHORTDIS_ENABLED,
+ AB8500_CODEC_CR11_VIBLSHORTDIS_DISABLED
+} t_ab8500_codec_cr11_viblshortdis;
+
+/* CR11 - 0 */
+typedef enum {
+ AB8500_CODEC_CR11_VIBRSHORTDIS_ENABLED,
+ AB8500_CODEC_CR11_VIBRSHORTDIS_DISABLED
+} t_ab8500_codec_cr11_vibrshortdis;
+
+/* CR12 - 7 */
+typedef enum {
+ AB8500_CODEC_CR12_ENCPHS_DISABLED,
+ AB8500_CODEC_CR12_ENCPHS_ENABLED
+} t_ab8500_codec_cr12_encphs;
+
+/* CR12 - 6:4 */
+typedef enum {
+ AB8500_CODEC_CR12_HSAUTOTIME_6_6USEC,
+ AB8500_CODEC_CR12_HSAUTOTIME_13_3USEC,
+ AB8500_CODEC_CR12_HSAUTOTIME_26_6USEC,
+ AB8500_CODEC_CR12_HSAUTOTIME_53_2USEC,
+ AB8500_CODEC_CR12_HSAUTOTIME_106_4USEC,
+ AB8500_CODEC_CR12_HSAUTOTIME_212_8USEC,
+ AB8500_CODEC_CR12_HSAUTOTIME_425_6USEC,
+ AB8500_CODEC_CR12_HSAUTOTIME_851_2USEC,
+} t_ab8500_codec_cr12_hsautotime;
+
+/* CR12 - 1 */
+typedef enum {
+ AB8500_CODEC_CR12_HSAUTOENSEL_DISABLED,
+ AB8500_CODEC_CR12_HSAUTOENSEL_ENABLED
+} t_ab8500_codec_cr12_hsautoensel;
+
+/* CR12 - 0 */
+typedef enum {
+ AB8500_CODEC_CR12_HSAUTOEN_DISABLED,
+ AB8500_CODEC_CR12_HSAUTOEN_ENABLED
+} t_ab8500_codec_cr12_hsautoen;
+
+/* CR13 - 7:4 */
+typedef enum {
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_25,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_50,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_100,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_150,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_200,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_250,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_300,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_350,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_400,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_450,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_500,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_550,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_600,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_650,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_700,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_750
+} t_ab8500_codec_cr13_envdet_hthresh;
+
+/* CR13 - 3:0 */
+typedef enum {
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_25,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_50,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_100,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_150,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_200,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_250,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_300,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_350,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_400,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_450,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_500,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_550,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_600,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_650,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_700,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_750
+} t_ab8500_codec_cr13_envdet_lthresh;
+
+/* CR14 - 7 */
+typedef enum {
+ AB8500_CODEC_CR14_SMPSLVEN_HIGHVOLTAGE,
+ AB8500_CODEC_CR14_SMPSLVEN_LOWVOLTAGE
+} t_ab8500_codec_cr14_smpslven;
+
+/* CR14 - 6 */
+typedef enum {
+ AB8500_CODEC_CR14_ENVDETSMPSEN_DISABLED,
+ AB8500_CODEC_CR14_ENVDETSMPSEN_ENABLED
+} t_ab8500_codec_cr14_envdetsmpsen;
+
+/* CR14 - 5 */
+typedef enum {
+ AB8500_CODEC_CR14_CPLVEN_HIGHVOLTAGE,
+ AB8500_CODEC_CR14_CPLVEN_LOWVOLTAGE
+} t_ab8500_codec_cr14_cplven;
+
+/* CR14 - 4 */
+typedef enum {
+ AB8500_CODEC_CR14_ENVDETCPEN_DISABLED,
+ AB8500_CODEC_CR14_ENVDETCPEN_ENABLED
+} t_ab8500_codec_cr14_envdetcpen;
+
+/* CR14 - 3:0 */
+typedef enum {
+ AB8500_CODEC_CR14_ENVET_TIME_27USEC,
+ AB8500_CODEC_CR14_ENVET_TIME_53USEC,
+ AB8500_CODEC_CR14_ENVET_TIME_106USEC,
+ AB8500_CODEC_CR14_ENVET_TIME_212USEC,
+ AB8500_CODEC_CR14_ENVET_TIME_424USEC,
+ AB8500_CODEC_CR14_ENVET_TIME_848USEC,
+ AB8500_CODEC_CR14_ENVET_TIME_1MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_3MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_6MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_13MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_27MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_54MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_109MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_218MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_436MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_872MSEC,
+} t_ab8500_codec_cr14_envet_time;
+
+/* CR15 - 7 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMTOVIBL_DA_PATH,
+ AB8500_CODEC_CR15_PWMTOVIBL_PWM
+} t_ab8500_codec_cr15_pwmtovibl;
+
+/* CR15 - 6 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMTOVIBR_DA_PATH,
+ AB8500_CODEC_CR15_PWMTOVIBR_PWM
+} t_ab8500_codec_cr15_pwmtovibr;
+
+/* CR15 - 5 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLGPOL,
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE
+} t_ab8500_codec_cr15_pwmlctrl;
+
+/* CR15 - 4 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRGPOL,
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE
+} t_ab8500_codec_cr15_pwmrctrl;
+
+/* CR15 - 3 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLGPOL,
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE
+} t_ab8500_codec_cr15_pwmnlctrl;
+
+/* CR15 - 2 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLGPOL,
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE
+} t_ab8500_codec_cr15_pwmplctrl;
+
+/* CR15 - 1 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRGPOL,
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE
+} t_ab8500_codec_cr15_pwmnrctrl;
+
+/* CR15 - 0 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRGPOL,
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE
+} t_ab8500_codec_cr15_pwmprctrl;
+
+/* CR16 - 7 */
+typedef enum {
+ AB8500_CODEC_CR16_PWMNLPOL_GNDVIB,
+ AB8500_CODEC_CR16_PWMNLPOL_VINVIB
+} t_ab8500_codec_cr16_pwmnlpol;
+
+/* CR16 - 6:0 */
+typedef t_uint8 t_ab8500_codec_cr16_pwmnldutycycle;
+
+/* CR17 - 7 */
+typedef enum {
+ AB8500_CODEC_CR17_PWMPLPOL_GNDVIB,
+ AB8500_CODEC_CR17_PWMPLPOL_VINVIB
+} t_ab8500_codec_cr17_pwmplpol;
+
+/* CR17 - 6:0 */
+typedef t_uint8 t_ab8500_codec_cr17_pwmpldutycycle;
+
+/* CR18 - 7 */
+typedef enum {
+ AB8500_CODEC_CR18_PWMNRPOL_GNDVIB,
+ AB8500_CODEC_CR18_PWMNRPOL_VINVIB
+} t_ab8500_codec_cr18_pwmnrpol;
+
+/* CR18 - 6:0 */
+typedef t_uint8 t_ab8500_codec_cr18_pwmnrdutycycle;
+
+/* CR19 - 7 */
+typedef enum {
+ AB8500_CODEC_CR19_PWMPRPOL_GNDVIB,
+ AB8500_CODEC_CR19_PWMPRPOL_VINVIB
+} t_ab8500_codec_cr19_pwmprpol;
+
+/* CR19 - 6:0 */
+typedef t_uint8 t_ab8500_codec_cr19_pwmprdutycycle;
+
+/* CR20 - 7 */
+typedef enum {
+ AB8500_CODEC_CR20_EN_SE_MIC1_DIFFERENTIAL,
+ AB8500_CODEC_CR20_EN_SE_MIC1_SINGLE
+} t_ab8500_codec_cr20_en_se_mic1;
+
+/* CR20 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr20_mic1_gain;
+
+/* CR21 - 7 */
+typedef enum {
+ AB8500_CODEC_CR21_EN_SE_MIC2_DIFFERENTIAL,
+ AB8500_CODEC_CR21_EN_SE_MIC2_SINGLE
+} t_ab8500_codec_cr21_en_se_mic2;
+
+/* CR21 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr21_mic2_gain;
+
+/* CR22 - 7:5 */
+typedef t_uint8 t_ab8500_codec_cr22_hsl_gain;
+
+/* CR22 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr22_linl_gain;
+
+/* CR23 - 7:5 */
+typedef t_uint8 t_ab8500_codec_cr23_hsr_gain;
+
+/* CR23 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr23_linr_gain;
+
+/* CR24 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr24_lintohsl_gain;
+
+/* CR25 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr25_lintohsr_gain;
+
+/* CR26 - 7 */
+typedef enum {
+ AB8500_CODEC_CR26_AD1NH_FILTER_ENABLED,
+ AB8500_CODEC_CR26_AD1NH_FILTER_DISABLED
+} t_ab8500_codec_cr26_ad1nh;
+
+/* CR26 - 6 */
+typedef enum {
+ AB8500_CODEC_CR26_AD2NH_FILTER_ENABLED,
+ AB8500_CODEC_CR26_AD2NH_FILTER_DISABLED
+} t_ab8500_codec_cr26_ad2nh;
+
+/* CR26 - 5 */
+typedef enum {
+ AB8500_CODEC_CR26_AD3NH_FILTER_ENABLED,
+ AB8500_CODEC_CR26_AD3NH_FILTER_DISABLED
+} t_ab8500_codec_cr26_ad3nh;
+
+/* CR26 - 4 */
+typedef enum {
+ AB8500_CODEC_CR26_AD4NH_FILTER_ENABLED,
+ AB8500_CODEC_CR26_AD4NH_FILTER_DISABLED
+} t_ab8500_codec_cr26_ad4nh;
+
+/* CR26 - 3 */
+typedef enum {
+ AB8500_CODEC_CR26_AD1_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR26_AD1_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr26_ad1_voice;
+
+/* CR26 - 2 */
+typedef enum {
+ AB8500_CODEC_CR26_AD2_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR26_AD2_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr26_ad2_voice;
+
+/* CR26 - 1 */
+typedef enum {
+ AB8500_CODEC_CR26_AD3_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR26_AD3_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr26_ad3_voice;
+
+/* CR26 - 0 */
+typedef enum {
+ AB8500_CODEC_CR26_AD4_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR26_AD4_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr26_ad4_voice;
+
+/* CR27 - 7 */
+typedef enum {
+ AB8500_CODEC_CR27_EN_MASTGEN_DISABLED,
+ AB8500_CODEC_CR27_EN_MASTGEN_ENABLED
+} t_ab8500_codec_cr27_en_mastgen;
+
+/* CR27 - 6:5 */
+typedef enum {
+ AB8500_CODEC_CR27_IF1_BITCLK_OSR_32,
+ AB8500_CODEC_CR27_IF1_BITCLK_OSR_64,
+ AB8500_CODEC_CR27_IF1_BITCLK_OSR_128,
+ AB8500_CODEC_CR27_IF1_BITCLK_OSR_256
+} t_ab8500_codec_cr27_if1_bitclk_osr;
+
+/* CR27 - 4 */
+typedef enum {
+ AB8500_CODEC_CR27_ENFS_BITCLK1_DISABLED,
+ AB8500_CODEC_CR27_ENFS_BITCLK1_ENABLED
+} t_ab8500_codec_cr27_enfs_bitclk1;
+
+/* CR27 - 2:1 */
+typedef enum {
+ AB8500_CODEC_CR27_IF0_BITCLK_OSR_32,
+ AB8500_CODEC_CR27_IF0_BITCLK_OSR_64,
+ AB8500_CODEC_CR27_IF0_BITCLK_OSR_128,
+ AB8500_CODEC_CR27_IF0_BITCLK_OSR_256
+} t_ab8500_codec_cr27_if0_bitclk_osr;
+
+/* CR27 - 0 */
+typedef enum {
+ AB8500_CODEC_CR27_ENFS_BITCLK0_DISABLED,
+ AB8500_CODEC_CR27_ENFS_BITCLK0_ENABLED
+} t_ab8500_codec_cr27_enfs_bitclk0;
+
+/* CR28 - 6 */
+typedef enum {
+ AB8500_CODEC_CR28_FSYNC0P_RISING_EDGE,
+ AB8500_CODEC_CR28_FSYNC0P_FALLING_EDGE
+} t_ab8500_codec_cr28_fsync0p;
+
+/* CR28 - 5 */
+typedef enum {
+ AB8500_CODEC_CR28_BITCLK0P_RISING_EDGE,
+ AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE
+} t_ab8500_codec_cr28_bitclk0p;
+
+/* CR28 - 4 */
+typedef enum {
+ AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED,
+ AB8500_CODEC_CR28_IF0DEL_DELAYED
+} t_ab8500_codec_cr28_if0del;
+
+/* CR28 - 3:2 */
+typedef enum {
+ AB8500_CODEC_CR28_IF0FORMAT_DISABLED,
+ AB8500_CODEC_CR28_IF0FORMAT_TDM,
+ AB8500_CODEC_CR28_IF0FORMAT_I2S_LEFTALIGNED
+} t_ab8500_codec_cr28_if0format;
+
+/* CR28 - 1:0 */
+typedef enum {
+ AB8500_CODEC_CR28_IF0WL_16BITS,
+ AB8500_CODEC_CR28_IF0WL_20BITS,
+ AB8500_CODEC_CR28_IF0WL_24BITS,
+ AB8500_CODEC_CR28_IF0WL_32BITS
+} t_ab8500_codec_cr28_if0wl;
+
+/* CR29 - 7 */
+typedef enum {
+ AB8500_CODEC_CR29_IF0DATOIF1AD_NOTSENT,
+ AB8500_CODEC_CR29_IF0DATOIF1AD_SENT
+} t_ab8500_codec_cr29_if0datoif1ad;
+
+/* CR29 - 6 */
+typedef enum {
+ AB8500_CODEC_CR29_IF0CKTOIF1CK_NOTSENT,
+ AB8500_CODEC_CR29_IF0CKTOIF1CK_SENT
+} t_ab8500_codec_cr29_if0cktoif1ck;
+
+/* CR29 - 5 */
+typedef enum {
+ AB8500_CODEC_CR29_IF1MASTER_FS1CK1_INPUT,
+ AB8500_CODEC_CR29_IF1MASTER_FS1CK1_OUTPUT
+} t_ab8500_codec_cr29_if1master;
+
+/* CR29 - 3 */
+typedef enum {
+ AB8500_CODEC_CR29_IF1DATOIF0AD_NOTSENT,
+ AB8500_CODEC_CR29_IF1DATOIF0AD_SENT
+} t_ab8500_codec_cr29_if1datoif0ad;
+
+/* CR29 - 2 */
+typedef enum {
+ AB8500_CODEC_CR29_IF1CKTOIF0CK_NOTSENT,
+ AB8500_CODEC_CR29_IF1CKTOIF0CK_SENT
+} t_ab8500_codec_cr29_if1cktoif0ck;
+
+/* CR29 - 1 */
+typedef enum {
+ AB8500_CODEC_CR29_IF0MASTER_FS0CK0_INPUT,
+ AB8500_CODEC_CR29_IF0MASTER_FS0CK0_OUTPUT
+} t_ab8500_codec_cr29_if0master;
+
+/* CR29 - 0 */
+typedef enum {
+ AB8500_CODEC_CR29_IF0BFIFOEN_NORMAL_MODE,
+ AB8500_CODEC_CR29_IF0BFIFOEN_BURST_MODE
+} t_ab8500_codec_cr29_if0bfifoen;
+
+/* CR30 - 6 */
+typedef enum {
+ AB8500_CODEC_CR30_FSYNC1P_RISING_EDGE,
+ AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE
+} t_ab8500_codec_cr30_fsync1p;
+
+/* CR30 - 5 */
+typedef enum {
+ AB8500_CODEC_CR30_BITCLK1P_RISING_EDGE,
+ AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE
+} t_ab8500_codec_cr30_bitclk1p;
+
+/* CR30 - 4 */
+typedef enum {
+ AB8500_CODEC_CR30_IF1DEL_NOT_DELAYED,
+ AB8500_CODEC_CR30_IF1DEL_DELAYED
+} t_ab8500_codec_cr30_if1del;
+
+/* CR30 - 3:2 */
+typedef enum {
+ AB8500_CODEC_CR30_IF1FORMAT_DISABLED,
+ AB8500_CODEC_CR30_IF1FORMAT_TDM,
+ AB8500_CODEC_CR30_IF1FORMAT_I2S_LEFTALIGNED
+} t_ab8500_codec_cr30_if1format;
+
+/* CR30 - 1:0 */
+typedef enum {
+ AB8500_CODEC_CR30_IF1WL_16BITS,
+ AB8500_CODEC_CR30_IF1WL_20BITS,
+ AB8500_CODEC_CR30_IF1WL_24BITS,
+ AB8500_CODEC_CR30_IF1WL_32BITS
+} t_ab8500_codec_cr30_if1wl;
+
+/* CR31:46 - 7:4 or 3:0 */
+/* In ab8500_codec.h */
+
+/* CR47:50 - 7/6/5/4/3/2/1/0 */
+typedef enum {
+ AB8500_CODEC_CR47_TO_CR50_HIZ_SL_LOW_IMPEDANCE,
+ AB8500_CODEC_CR47_TO_CR50_HIZ_SL_HIGH_IMPEDANCE,
+} t_ab8500_codec_cr47_to_cr50_hiz_sl;
+
+/* CR51 - 7 */
+typedef enum {
+ AB8500_CODEC_CR51_DA12_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR51_DA12_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr51_da12_voice;
+
+/* CR51 - 5 */
+typedef enum {
+ AB8500_CODEC_CR51_SLDAI1TOSLADO1_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR51_SLDAI1TOSLADO1_LOOPEDBACK
+} t_ab8500_codec_cr51_sldai1toslado1;
+
+/* CR51:56 - 4:0 */
+/* In ab8500_codec.h */
+
+/* CR52 - 5 */
+typedef enum {
+ AB8500_CODEC_CR52_SLDAI2TOSLADO2_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR52_SLDAI2TOSLADO2_LOOPEDBACK
+} t_ab8500_codec_cr52_sldai2toslado2;
+
+/* CR53 - 7 */
+typedef enum {
+ AB8500_CODEC_CR53_DA34_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR53_DA34_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr53_da34_voice;
+
+/* CR53 - 5 */
+typedef enum {
+ AB8500_CODEC_CR53_SLDAI3TOSLADO3_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR53_SLDAI3TOSLADO3_LOOPEDBACK
+} t_ab8500_codec_cr53_sldai3toslado3;
+
+/* CR54 - 5 */
+typedef enum {
+ AB8500_CODEC_CR54_SLDAI4TOSLADO4_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR54_SLDAI4TOSLADO4_LOOPEDBACK
+} t_ab8500_codec_cr54_sldai4toslado4;
+
+/* CR55 - 7 */
+typedef enum {
+ AB8500_CODEC_CR55_DA56_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR55_DA56_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr55_da56_voice;
+
+/* CR55 - 6:5 */
+typedef enum {
+ AB8500_CODEC_CR55_SLDAI5TOSLADO5_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR55_SLDAI5TOSLADO5_DA_IN1_LOOPEDBACK,
+ AB8500_CODEC_CR55_SLDAI5TOSLADO5_DA_IN3_LOOPEDBACK,
+ AB8500_CODEC_CR55_SLDAI5TOSLADO5_DA_IN5_LOOPEDBACK
+} t_ab8500_codec_cr55_sldai5toslado5;
+
+/* CR56 - 6:5 */
+typedef enum {
+ AB8500_CODEC_CR56_SLDAI6TOSLADO7_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR56_SLDAI6TOSLADO7_DA_IN2_LOOPEDBACK,
+ AB8500_CODEC_CR56_SLDAI6TOSLADO7_DA_IN4_LOOPEDBACK,
+ AB8500_CODEC_CR56_SLDAI6TOSLADO7_DA_IN6_LOOPEDBACK
+} t_ab8500_codec_cr56_sldai6toslado7;
+
+/* CR57 - 6 */
+typedef enum {
+ AB8500_CODEC_CR57_BFIFULL_MSK_MASKED,
+ AB8500_CODEC_CR57_BFIFULL_MSK_ENABLED
+} t_ab8500_codec_cr57_bfifull_msk;
+
+/* CR57 - 5 */
+typedef enum {
+ AB8500_CODEC_CR57_BFIEMPT_MSK_MASKED,
+ AB8500_CODEC_CR57_BFIEMPT_MSK_ENABLED
+} t_ab8500_codec_cr57_bfiempt_msk;
+
+/* CR57 - 4 */
+typedef enum {
+ AB8500_CODEC_CR57_DACHAN_MSK_MASKED,
+ AB8500_CODEC_CR57_DACHAN_MSK_ENABLED
+} t_ab8500_codec_cr57_dachan_msk;
+
+/* CR57 - 3 */
+typedef enum {
+ AB8500_CODEC_CR57_GAIN_MSK_MASKED,
+ AB8500_CODEC_CR57_GAIN_MSK_ENABLED
+} t_ab8500_codec_cr57_gain_msk;
+
+/* CR57 - 2 */
+typedef enum {
+ AB8500_CODEC_CR57_DSPAD_MSK_MASKED,
+ AB8500_CODEC_CR57_DSPAD_MSK_ENABLED
+} t_ab8500_codec_cr57_dspad_msk;
+
+/* CR57 - 1 */
+typedef enum {
+ AB8500_CODEC_CR57_DSPDA_MSK_MASKED,
+ AB8500_CODEC_CR57_DSPDA_MSK_ENABLED
+} t_ab8500_codec_cr57_dspda_msk;
+
+/* CR57 - 0 */
+typedef enum {
+ AB8500_CODEC_CR57_STFIR_MSK_MASKED,
+ AB8500_CODEC_CR57_STFIR_MSK_ENABLED
+} t_ab8500_codec_cr57_stfir_msk;
+
+/* CR58 - Read Only */
+/* CR58 - 6 */
+typedef enum {
+ AB8500_CODEC_CR58_BFIFULL_EV_NOT_FULL,
+ AB8500_CODEC_CR58_BFIFULL_EV_FULL
+} t_ab8500_codec_cr58_bfifull_ev;
+
+/* CR58 - 5 */
+typedef enum {
+ AB8500_CODEC_CR58_BFIEMPT_EV_NOT_EMPTY,
+ AB8500_CODEC_CR58_BFIEMPT_EV_EMPTY
+} t_ab8500_codec_cr58_bfiempt_ev;
+
+/* CR58 - 4 */
+typedef enum {
+ AB8500_CODEC_CR58_DACHAN_EV_NO_SATURATION,
+ AB8500_CODEC_CR58_DACHAN_EV_SATURATION
+} t_ab8500_codec_cr58_dachan_ev;
+
+/* CR58 - 3 */
+typedef enum {
+ AB8500_CODEC_CR58_GAIN_EV_NO_SATURATION,
+ AB8500_CODEC_CR58_GAIN_EV_SATURATION
+} t_ab8500_codec_cr58_gain_ev;
+
+/* CR58 - 2 */
+typedef enum {
+ AB8500_CODEC_CR58_DSPAD_EV_NO_SATURATION,
+ AB8500_CODEC_CR58_DSPAD_EV_SATURATION
+} t_ab8500_codec_cr58_dspad_ev;
+
+/* CR58 - 1 */
+typedef enum {
+ AB8500_CODEC_CR58_DSPDA_EV_NO_SATURATION,
+ AB8500_CODEC_CR58_DSPDA_EV_SATURATION
+} t_ab8500_codec_cr58_dspda_ev;
+
+/* CR58 - 0 */
+typedef enum {
+ AB8500_CODEC_CR58_STFIR_EV_NO_SATURATION,
+ AB8500_CODEC_CR58_STFIR_EV_SATURATION
+} t_ab8500_codec_cr58_stfir_ev;
+
+/* CR59 - 7 */
+typedef enum {
+ AB8500_CODEC_CR59_VSSREADY_MSK_MASKED,
+ AB8500_CODEC_CR59_VSSREADY_MSK_ENABLED
+} t_ab8500_codec_cr59_vssready_msk;
+
+/* CR59 - 6 */
+typedef enum {
+ AB8500_CODEC_CR59_SHRTVIBL_MSK_MASKED,
+ AB8500_CODEC_CR59_SHRTVIBL_MSK_ENABLED
+} t_ab8500_codec_cr59_shrtvibl_msk;
+
+/* CR59 - 5 */
+typedef enum {
+ AB8500_CODEC_CR59_SHRTVIBR_MSK_MASKED,
+ AB8500_CODEC_CR59_SHRTVIBR_MSK_ENABLED
+} t_ab8500_codec_cr59_shrtvibr_msk;
+
+/* CR59 - 4 */
+typedef enum {
+ AB8500_CODEC_CR59_SHRTHFL_MSK_MASKED,
+ AB8500_CODEC_CR59_SHRTHFL_MSK_ENABLED
+} t_ab8500_codec_cr59_shrthfl_msk;
+
+/* CR59 - 3 */
+typedef enum {
+ AB8500_CODEC_CR59_SHRTHFR_MSK_MASKED,
+ AB8500_CODEC_CR59_SHRTHFR_MSK_ENABLED
+} t_ab8500_codec_cr59_shrthfr_msk;
+
+/* CR59 - 2 */
+typedef enum {
+ AB8500_CODEC_CR59_SHRTHSL_MSK_MASKED,
+ AB8500_CODEC_CR59_SHRTHSL_MSK_ENABLED
+} t_ab8500_codec_cr59_shrthsl_msk;
+
+/* CR59 - 1 */
+typedef enum {
+ AB8500_CODEC_CR59_SHRTHSR_MSK_MASKED,
+ AB8500_CODEC_CR59_SHRTHSR_MSK_ENABLED
+} t_ab8500_codec_cr59_shrthsr_msk;
+
+/* CR59 - 0 */
+typedef enum {
+ AB8500_CODEC_CR59_SHRTEAR_MSK_MASKED,
+ AB8500_CODEC_CR59_SHRTEAR_MSK_ENABLED
+} t_ab8500_codec_cr59_shrtear_msk;
+
+/* CR60 - Read Only */
+/* CR60 - 7 */
+typedef enum {
+ AB8500_CODEC_CR60_VSSREADY_EV_NOT_READY,
+ AB8500_CODEC_CR60_VSSREADY_EV_READY
+} t_ab8500_codec_cr60_vssready_ev;
+
+/* CR60 - 6 */
+typedef enum {
+ AB8500_CODEC_CR60_SHRTVIBL_EV_NO_SHORTCIRCUIT,
+ AB8500_CODEC_CR60_SHRTVIBL_EV_SHORTCIRCUIT
+} t_ab8500_codec_cr60_shrtvibl_ev;
+
+/* CR60 - 5 */
+typedef enum {
+ AB8500_CODEC_CR60_SHRTVIBR_EV_NO_SHORTCIRCUIT,
+ AB8500_CODEC_CR60_SHRTVIBR_EV_SHORTCIRCUIT
+} t_ab8500_codec_cr60_shrtvibr_ev;
+
+/* CR60 - 4 */
+typedef enum {
+ AB8500_CODEC_CR60_SHRTHFL_EV_NO_SHORTCIRCUIT,
+ AB8500_CODEC_CR60_SHRTHFL_EV_SHORTCIRCUIT
+} t_ab8500_codec_cr60_shrthfl_ev;
+
+/* CR60 - 3 */
+typedef enum {
+ AB8500_CODEC_CR60_SHRTHFR_EV_NO_SHORTCIRCUIT,
+ AB8500_CODEC_CR60_SHRTHFR_EV_SHORTCIRCUIT
+} t_ab8500_codec_cr60_shrthfr_ev;
+
+/* CR60 - 2 */
+typedef enum {
+ AB8500_CODEC_CR60_SHRTHSL_EV_NO_SHORTCIRCUIT,
+ AB8500_CODEC_CR60_SHRTHSL_EV_SHORTCIRCUIT
+} t_ab8500_codec_cr60_shrthsl_ev;
+
+/* CR60 - 1 */
+typedef enum {
+ AB8500_CODEC_CR60_SHRTHSR_EV_NO_SHORTCIRCUIT,
+ AB8500_CODEC_CR60_SHRTHSR_EV_SHORTCIRCUIT
+} t_ab8500_codec_cr60_shrthsr_ev;
+
+/* CR60 - 0 */
+typedef enum {
+ AB8500_CODEC_CR60_SHRTEAR_EV_NO_SHORTCIRCUIT,
+ AB8500_CODEC_CR60_SHRTEAR_EV_SHORTCIRCUIT
+} t_ab8500_codec_cr60_shrtear_ev;
+
+/* CR61 - 6:2 - Read Only */
+typedef enum {
+ AB8500_CODEC_CR61_REVISION_1_0,
+ AB8500_CODEC_CR61_REVISION_TBD
+} t_ab8500_codec_cr61_revision;
+
+/* CR61 - 1:0 */
+typedef enum {
+ AB8500_CODEC_CR61_FADE_SPEED_1MS,
+ AB8500_CODEC_CR61_FADE_SPEED_4MS,
+ AB8500_CODEC_CR61_FADE_SPEED_8MS,
+ AB8500_CODEC_CR61_FADE_SPEED_16MS
+} t_ab8500_codec_cr61_fade_speed;
+
+/* CR62 - Read Only */
+/* CR62 - 5 */
+typedef enum {
+ AB8500_CODEC_CR62_DMIC1SINC3_SINC5_SELECTED,
+ AB8500_CODEC_CR62_DMIC1SINC3_SINC3_SELECTED
+} t_ab8500_codec_cr62_dmic1sinc3;
+
+/* CR62 - 4 */
+typedef enum {
+ AB8500_CODEC_CR62_DMIC2SINC3_SINC5_SELECTED,
+ AB8500_CODEC_CR62_DMIC2SINC3_SINC3_SELECTED
+} t_ab8500_codec_cr62_dmic2sinc3;
+
+/* CR62 - 3 */
+typedef enum {
+ AB8500_CODEC_CR62_DMIC3SINC3_SINC5_SELECTED,
+ AB8500_CODEC_CR62_DMIC3SINC3_SINC3_SELECTED
+} t_ab8500_codec_cr62_dmic3sinc3;
+
+/* CR62 - 2 */
+typedef enum {
+ AB8500_CODEC_CR62_DMIC4SINC3_SINC5_SELECTED,
+ AB8500_CODEC_CR62_DMIC4SINC3_SINC3_SELECTED
+} t_ab8500_codec_cr62_dmic4sinc3;
+
+/* CR62 - 1 */
+typedef enum {
+ AB8500_CODEC_CR62_DMIC5SINC3_SINC5_SELECTED,
+ AB8500_CODEC_CR62_DMIC5SINC3_SINC3_SELECTED
+} t_ab8500_codec_cr62_dmic5sinc3;
+
+/* CR62 - 0 */
+typedef enum {
+ AB8500_CODEC_CR62_DMIC6SINC3_SINC5_SELECTED,
+ AB8500_CODEC_CR62_DMIC6SINC3_SINC3_SELECTED
+} t_ab8500_codec_cr62_dmic6sinc3;
+
+/* CR63 - 7 */
+typedef enum {
+ AB8500_CODEC_CR63_DATOHSLEN_DISABLED,
+ AB8500_CODEC_CR63_DATOHSLEN_ENABLED
+} t_ab8500_codec_cr63_datohslen;
+
+/* CR63 - 6 */
+typedef enum {
+ AB8500_CODEC_CR63_DATOHSREN_DISABLED,
+ AB8500_CODEC_CR63_DATOHSREN_ENABLED
+} t_ab8500_codec_cr63_datohsren;
+
+/* CR63 - 5 */
+typedef enum {
+ AB8500_CODEC_CR63_AD1SEL_LINLADL_SELECTED,
+ AB8500_CODEC_CR63_AD1SEL_DMIC1_SELECTED
+} t_ab8500_codec_cr63_ad1sel;
+
+/* CR63 - 4 */
+typedef enum {
+ AB8500_CODEC_CR63_AD2SEL_LINRADR_SELECTED,
+ AB8500_CODEC_CR63_AD2SEL_DMIC2_SELECTED
+} t_ab8500_codec_cr63_ad2sel;
+
+/* CR63 - 3 */
+typedef enum {
+ AB8500_CODEC_CR63_AD3SEL_ADMO_SELECTED,
+ AB8500_CODEC_CR63_AD3SEL_DMIC3_SELECTED
+} t_ab8500_codec_cr63_ad3sel;
+
+/* CR63 - 2 */
+typedef enum {
+ AB8500_CODEC_CR63_AD5SEL_AMADR_SELECTED,
+ AB8500_CODEC_CR63_AD5SEL_DMIC5_SELECTED
+} t_ab8500_codec_cr63_ad5sel;
+
+/* CR63 - 1 */
+typedef enum {
+ AB8500_CODEC_CR63_AD6SEL_ADMO_SELECTED,
+ AB8500_CODEC_CR63_AD6SEL_DMIC6_SELECTED
+} t_ab8500_codec_cr63_ad6sel;
+
+/* CR63 - 0 */
+typedef enum {
+ AB8500_CODEC_CR63_ANCSEL_NOT_MIXED_IN_EAR,
+ AB8500_CODEC_CR63_ANCSEL_MIXED_IN_EAR
+} t_ab8500_codec_cr63_ancsel;
+
+/* CR64 - 7 */
+typedef enum {
+ AB8500_CODEC_CR64_DATOHFREN_NOT_MIXED_TO_HFR,
+ AB8500_CODEC_CR64_DATOHFREN_MIXED_TO_HFR
+} t_ab8500_codec_cr64_datohfren;
+
+/* CR64 - 6 */
+typedef enum {
+ AB8500_CODEC_CR64_DATOHFLEN_NOT_MIXED_TO_HFL,
+ AB8500_CODEC_CR64_DATOHFLEN_MIXED_TO_HFL
+} t_ab8500_codec_cr64_datohflen;
+
+/* CR64 - 5 */
+typedef enum {
+ AB8500_CODEC_CR64_HFRSEL_DA4_MIXED_TO_HFR,
+ AB8500_CODEC_CR64_HFRSEL_ANC_MIXED_TO_HFR
+} t_ab8500_codec_cr64_hfrsel;
+
+/* CR64 - 4 */
+typedef enum {
+ AB8500_CODEC_CR64_HFLSEL_DA3_MIXED_TO_HFL,
+ AB8500_CODEC_CR64_HFLSEL_ANC_MIXED_TO_HFL
+} t_ab8500_codec_cr64_hflsel;
+
+/* CR64 - 3:2 */
+typedef enum {
+ AB8500_CODEC_CR64_STFIR1SEL_AD_OUT1_SELECTED,
+ AB8500_CODEC_CR64_STFIR1SEL_AD_OUT3_SELECTED,
+ AB8500_CODEC_CR64_STFIR1SEL_DA_IN1_SELECTED
+} t_ab8500_codec_cr64_stfir1sel;
+
+/* CR64 - 1:0 */
+typedef enum {
+ AB8500_CODEC_CR64_STFIR2SEL_AD_OUT2_SELECTED,
+ AB8500_CODEC_CR64_STFIR2SEL_AD_OUT4_SELECTED,
+ AB8500_CODEC_CR64_STFIR2SEL_DA_IN2_SELECTED
+} t_ab8500_codec_cr64_stfir2sel;
+
+/* CR65 - 6 */
+typedef enum {
+ AB8500_CODEC_CR65_FADEDIS_AD1_ENABLED,
+ AB8500_CODEC_CR65_FADEDIS_AD1_DISABLED
+} t_ab8500_codec_cr65_fadedis_ad1;
+
+/* CR65 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr65_ad1gain;
+
+/* CR66 - 6 */
+typedef enum {
+ AB8500_CODEC_CR66_FADEDIS_AD2_ENABLED,
+ AB8500_CODEC_CR66_FADEDIS_AD2_DISABLED
+} t_ab8500_codec_cr66_fadedis_ad2;
+
+/* CR66 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr66_ad2gain;
+
+/* CR67 - 6 */
+typedef enum {
+ AB8500_CODEC_CR67_FADEDIS_AD3_ENABLED,
+ AB8500_CODEC_CR67_FADEDIS_AD3_DISABLED
+} t_ab8500_codec_cr67_fadedis_ad3;
+
+/* CR67 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr67_ad3gain;
+
+/* CR68 - 6 */
+typedef enum {
+ AB8500_CODEC_CR68_FADEDIS_AD4_ENABLED,
+ AB8500_CODEC_CR68_FADEDIS_AD4_DISABLED
+} t_ab8500_codec_cr68_fadedis_ad4;
+
+/* CR68 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr68_ad4gain;
+
+/* CR69 - 6 */
+typedef enum {
+ AB8500_CODEC_CR69_FADEDIS_AD5_ENABLED,
+ AB8500_CODEC_CR69_FADEDIS_AD5_DISABLED
+} t_ab8500_codec_cr69_fadedis_ad5;
+
+/* CR69 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr69_ad5gain;
+
+/* CR70 - 6 */
+typedef enum {
+ AB8500_CODEC_CR70_FADEDIS_AD6_ENABLED,
+ AB8500_CODEC_CR70_FADEDIS_AD6_DISABLED
+} t_ab8500_codec_cr70_fadedis_ad6;
+
+/* CR70 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr70_ad6gain;
+
+/* CR71 - 6 */
+typedef enum {
+ AB8500_CODEC_CR71_FADEDIS_DA1_ENABLED,
+ AB8500_CODEC_CR71_FADEDIS_DA1_DISABLED
+} t_ab8500_codec_cr71_fadedis_da1;
+
+/* CR71 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr71_da1gain;
+
+/* CR72 - 6 */
+typedef enum {
+ AB8500_CODEC_CR72_FADEDIS_DA2_ENABLED,
+ AB8500_CODEC_CR72_FADEDIS_DA2_DISABLED
+} t_ab8500_codec_cr72_fadedis_da2;
+
+/* CR72 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr72_da2gain;
+
+/* CR73 - 6 */
+typedef enum {
+ AB8500_CODEC_CR73_FADEDIS_DA3_ENABLED,
+ AB8500_CODEC_CR73_FADEDIS_DA3_DISABLED
+} t_ab8500_codec_cr73_fadedis_da3;
+
+/* CR73 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr73_da3gain;
+
+/* CR74 - 6 */
+typedef enum {
+ AB8500_CODEC_CR74_FADEDIS_DA4_ENABLED,
+ AB8500_CODEC_CR74_FADEDIS_DA4_DISABLED
+} t_ab8500_codec_cr74_fadedis_da4;
+
+/* CR74 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr74_da4gain;
+
+/* CR75 - 6 */
+typedef enum {
+ AB8500_CODEC_CR75_FADEDIS_DA5_ENABLED,
+ AB8500_CODEC_CR75_FADEDIS_DA5_DISABLED
+} t_ab8500_codec_cr75_fadedis_da5;
+
+/* CR75 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr75_da5gain;
+
+/* CR76 - 6 */
+typedef enum {
+ AB8500_CODEC_CR76_FADEDIS_DA6_ENABLED,
+ AB8500_CODEC_CR76_FADEDIS_DA6_DISABLED
+} t_ab8500_codec_cr76_fadedis_da6;
+
+/* CR76 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr76_da6gain;
+
+/* CR77 - 6 */
+typedef enum {
+ AB8500_CODEC_CR77_FADEDIS_AD1L_TO_HFL_ENABLED,
+ AB8500_CODEC_CR77_FADEDIS_AD1L_TO_HFL_DISABLED
+} t_ab8500_codec_cr77_fadedis_ad1l;
+
+/* CR77 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr77_ad1lbgain_to_hfl;
+
+/* CR78 - 6 */
+typedef enum {
+ AB8500_CODEC_CR78_FADEDIS_AD2L_TO_HFR_ENABLED,
+ AB8500_CODEC_CR78_FADEDIS_AD2L_TO_HFR_DISABLED
+} t_ab8500_codec_cr78_fadedis_ad2l;
+
+/* CR78 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr78_ad2lbgain_to_hfr;
+
+/* CR79 - 7 */
+typedef enum {
+ AB8500_CODEC_CR79_HSSINC1_SINC3_CHOOSEN,
+ AB8500_CODEC_CR79_HSSINC1_SINC1_CHOOSEN
+} t_ab8500_codec_cr79_hssinc1;
+
+/* CR79 - 4 */
+typedef enum {
+ AB8500_CODEC_CR79_FADEDIS_HSL_ENABLED,
+ AB8500_CODEC_CR79_FADEDIS_HSL_DISABLED
+} t_ab8500_codec_cr79_fadedis_hsl;
+
+/* CR79 - 3:0 */
+typedef t_uint8 t_ab8500_codec_cr79_hsldgain;
+
+/* CR80 - 4 */
+typedef enum {
+ AB8500_CODEC_CR80_FADEDIS_HSR_ENABLED,
+ AB8500_CODEC_CR80_FADEDIS_HSR_DISABLED
+} t_ab8500_codec_cr80_fadedis_hsr;
+
+/* CR80 - 3:0 */
+typedef t_uint8 t_ab8500_codec_cr80_hsrdgain;
+
+/* CR81 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr81_stfir1gain;
+
+/* CR82 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr82_stfir2gain;
+
+/* CR83 - 2 */
+typedef enum {
+ AB8500_CODEC_CR83_ENANC_DISABLED,
+ AB8500_CODEC_CR83_ENANC_ENABLED
+} t_ab8500_codec_cr83_enanc;
+
+/* CR83 - 1 */
+typedef enum {
+ AB8500_CODEC_CR83_ANCIIRINIT_NOT_STARTED,
+ AB8500_CODEC_CR83_ANCIIRINIT_STARTED
+} t_ab8500_codec_cr83_anciirinit;
+
+/* CR83 - 0 */
+typedef enum {
+ AB8500_CODEC_CR83_ANCFIRUPDATE_RESETTED,
+ AB8500_CODEC_CR83_ANCFIRUPDATE_NOT_RESETTED
+} t_ab8500_codec_cr83_ancfirupdate;
+
+/* CR84 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr84_ancinshift;
+
+/* CR85 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr85_ancfiroutshift;
+
+/* CR86 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr86_ancshiftout;
+
+/* CR87 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr87_ancfircoeff_msb;
+
+/* CR88 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr88_ancfircoeff_lsb;
+
+/* CR89 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr89_anciircoeff_msb;
+
+/* CR90 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr90_anciircoeff_lsb;
+
+/* CR91 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr91_ancwarpdel_msb;
+
+/* CR92 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr92_ancwarpdel_lsb;
+
+/* CR93 - Read Only */
+/* CR93 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr93_ancfirpeak_msb;
+
+/* CR94 - Read Only */
+/* CR94 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr94_ancfirpeak_lsb;
+
+/* CR95 - Read Only */
+/* CR95 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr95_anciirpeak_msb;
+
+/* CR96 - Read Only */
+/* CR96 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr96_anciirpeak_lsb;
+
+/* CR97 - 7 */
+typedef enum {
+ AB8500_CODEC_CR97_STFIR_SET_LAST_NOT_APPLIED,
+ AB8500_CODEC_CR97_STFIR_SET_LAST_APPLIED
+} t_ab8500_codec_cr97_stfir_set;
+
+/* CR97 - 6:0 */
+typedef t_uint8 t_ab8500_codec_cr97_stfir_addr;
+
+/* CR98 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr98_stfir_coeff_msb;
+
+/* CR99 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr99_stfir_coeff_lsb;
+
+/* CR100 - 2 */
+typedef enum {
+ AB8500_CODEC_CR100_ENSTFIRS_DISABLED,
+ AB8500_CODEC_CR100_ENSTFIRS_ENABLED
+} t_ab8500_codec_cr100_enstfirs;
+
+/* CR100 - 1 */
+typedef enum {
+ AB8500_CODEC_CR100_STFIRSTOIF1_AUD_IF0_DATA_RATE,
+ AB8500_CODEC_CR100_STFIRSTOIF1_AUD_IF1_DATA_RATE
+} t_ab8500_codec_cr100_stfirstoif1;
+
+/* CR100 - 0 */
+typedef enum {
+ AB8500_CODEC_CR100_STFIR_BUSY_READY,
+ AB8500_CODEC_CR100_STFIR_BUSY_NOT_READY
+} t_ab8500_codec_cr100_stfir_busy;
+
+/* CR101 - 7 */
+typedef enum {
+ AB8500_CODEC_CR101_PARLHF_INDEPENDENT,
+ AB8500_CODEC_CR101_PARLHF_BRIDGED
+} t_ab8500_codec_cr101_parlhf;
+
+/* CR101 - 6 */
+typedef enum {
+ AB8500_CODEC_CR101_PARLVIB_INDEPENDENT,
+ AB8500_CODEC_CR101_PARLVIB_BRIDGED
+} t_ab8500_codec_cr101_parlvib;
+
+/* CR101 - 3 */
+typedef enum {
+ AB8500_CODEC_CR101_CLASSD_VIBLSWAPEN_DISABLED,
+ AB8500_CODEC_CR101_CLASSD_VIBLSWAPEN_ENABLED
+} t_ab8500_codec_cr101_classd_viblswapen;
+
+/* CR101 - 2 */
+typedef enum {
+ AB8500_CODEC_CR101_CLASSD_VIBRSWAPEN_DISABLED,
+ AB8500_CODEC_CR101_CLASSD_VIBRSWAPEN_ENABLED
+} t_ab8500_codec_cr101_classd_vibrswapen;
+
+/* CR101 - 1 */
+typedef enum {
+ AB8500_CODEC_CR101_CLASSD_HFLSWAPEN_DISABLED,
+ AB8500_CODEC_CR101_CLASSD_HFLSWAPEN_ENABLED
+} t_ab8500_codec_cr101_classd_hflswapen;
+
+/* CR101 - 0 */
+typedef enum {
+ AB8500_CODEC_CR101_CLASSD_HFRSWAPEN_DISABLED,
+ AB8500_CODEC_CR101_CLASSD_HFRSWAPEN_ENABLED
+} t_ab8500_codec_cr101_classd_hfrswapen;
+
+/* CR102 - 7:4 */
+typedef enum {
+ AB8500_CODEC_CR102_CLASSD_FIRBYP_ALL_ENABLED = 0,
+ AB8500_CODEC_CR102_CLASSD_FIRBYP_HFL_BYPASSED = 1,
+ AB8500_CODEC_CR102_CLASSD_FIRBYP_HFR_BYPASSED = 2,
+ AB8500_CODEC_CR102_CLASSD_FIRBYP_VIBL_BYPASSED = 4,
+ AB8500_CODEC_CR102_CLASSD_FIRBYP_VIBR_BYPASSED = 8
+} t_ab8500_codec_cr102_classd_firbyp;
+
+/* CR102 - 3:0 */
+typedef enum {
+ AB8500_CODEC_CR102_CLASSD_HIGHVOLEN_DISABLED = 0,
+ AB8500_CODEC_CR102_CLASSD_HIGHVOLEN_HFL_HIGHVOL = 1,
+ AB8500_CODEC_CR102_CLASSD_HIGHVOLEN_HFR_HIGHVOL = 2,
+ AB8500_CODEC_CR102_CLASSD_HIGHVOLEN_VIBL_HIGHVOL = 4,
+ AB8500_CODEC_CR102_CLASSD_HIGHVOLEN_VIBR_HIGHVOL = 8
+} t_ab8500_codec_cr102_classd_highvolen;
+
+/* CR103 - 7:4 */
+typedef t_uint8 t_ab8500_codec_cr103_classd_ditherhpgain;
+
+/* CR103 - 3:0 */
+typedef t_uint8 t_ab8500_codec_cr103_classd_ditherwgain;
+
+/* CR104 - 5:0 */
+/* In ab8500_codec.h */
+
+/* CR105 - 7:0 */
+/* In ab8500_codec.h */
+
+/* CR106 - 6:4 */
+/* In ab8500_codec.h */
+
+/* CR106 - 2 */
+/* In ab8500_codec.h */
+
+/* CR106 - 1 */
+/* In ab8500_codec.h */
+
+/* CR106 - 0 */
+/* In ab8500_codec.h */
+
+/* CR107 - 7:0 */
+/* In ab8500_codec.h */
+
+/* CR108 - 7:0 */
+/* In ab8500_codec.h */
+
+/* CR109 - Read Only */
+/* CR109 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr109_bfifosamples;
+
+typedef enum {
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT3,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT4,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT5,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT6,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT7,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT8,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_ZEROS,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_IS_TRISTATE = 15,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_UNDEFINED
+} t_ab8500_codec_cr31_to_cr46_ad_data_allocation;
+
+typedef enum {
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT00,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT01,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT02,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT03,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT04,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT05,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT06,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT07,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT08,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT09,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT10,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT11,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT12,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT13,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT14,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT15,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT16,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT17,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT18,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT19,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT20,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT21,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT22,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT23,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT24,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT25,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT26,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT27,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT28,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT29,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT30,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT31,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT_UNDEFINED
+} t_ab8500_codec_cr51_to_cr56_sltoda;
+
+/* CR104 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr104_bfifoint;
+
+/* CR105 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr105_bfifotx;
+
+/* CR106 - 6:4 */
+typedef enum {
+ AB8500_CODEC_CR106_BFIFOFSEXT_NO_EXTRA_CLK,
+ AB8500_CODEC_CR106_BFIFOFSEXT_1SLOT_EXTRA_CLK,
+ AB8500_CODEC_CR106_BFIFOFSEXT_2SLOT_EXTRA_CLK,
+ AB8500_CODEC_CR106_BFIFOFSEXT_3SLOT_EXTRA_CLK,
+ AB8500_CODEC_CR106_BFIFOFSEXT_4SLOT_EXTRA_CLK,
+ AB8500_CODEC_CR106_BFIFOFSEXT_5SLOT_EXTRA_CLK,
+ AB8500_CODEC_CR106_BFIFOFSEXT_6SLOT_EXTRA_CLK
+} t_ab8500_codec_cr106_bfifofsext;
+
+/* CR106 - 2 */
+typedef enum {
+ AB8500_CODEC_CR106_BFIFOMSK_AD_DATA0_UNMASKED,
+ AB8500_CODEC_CR106_BFIFOMSK_AD_DATA0_MASKED
+} t_ab8500_codec_cr106_bfifomsk;
+
+/* CR106 - 1 */
+typedef enum {
+ AB8500_CODEC_CR106_BFIFOMSTR_SLAVE_MODE,
+ AB8500_CODEC_CR106_BFIFOMSTR_MASTER_MODE
+} t_ab8500_codec_cr106_bfifomstr;
+
+/* CR106 - 0 */
+typedef enum {
+ AB8500_CODEC_CR106_BFIFOSTRT_STOPPED,
+ AB8500_CODEC_CR106_BFIFOSTRT_RUNNING
+} t_ab8500_codec_cr106_bfifostrt;
+
+/* CR107 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr107_bfifosampnr;
+
+/* CR108 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr108_bfifowakeup;
+
+/*configuration structure for AB8500 Codec*/
+typedef struct {
+ /* CR0 */
+ t_ab8500_codec_cr0_powerup cr0_powerup;
+ t_ab8500_codec_cr0_enaana cr0_enaana;
+
+ /* CR1 */
+ t_ab8500_codec_cr1_swreset cr1_swreset;
+
+ /* CR2 */
+ t_ab8500_codec_cr2_enad1 cr2_enad1;
+ t_ab8500_codec_cr2_enad2 cr2_enad2;
+ t_ab8500_codec_cr2_enad3 cr2_enad3;
+ t_ab8500_codec_cr2_enad4 cr2_enad4;
+ t_ab8500_codec_cr2_enad5 cr2_enad5;
+ t_ab8500_codec_cr2_enad6 cr2_enad6;
+
+ /* CR3 */
+ t_ab8500_codec_cr3_enda1 cr3_enda1;
+ t_ab8500_codec_cr3_enda2 cr3_enda2;
+ t_ab8500_codec_cr3_enda3 cr3_enda3;
+ t_ab8500_codec_cr3_enda4 cr3_enda4;
+ t_ab8500_codec_cr3_enda5 cr3_enda5;
+ t_ab8500_codec_cr3_enda6 cr3_enda6;
+
+ /* CR4 */
+ t_ab8500_codec_cr4_lowpowhs cr4_lowpowhs;
+ t_ab8500_codec_cr4_lowpowdachs cr4_lowpowdachs;
+ t_ab8500_codec_cr4_lowpowear cr4_lowpowear;
+ t_ab8500_codec_cr4_ear_sel_cm cr4_ear_sel_cm;
+ t_ab8500_codec_cr4_hs_hp_dis cr4_hs_hp_dis;
+ t_ab8500_codec_cr4_ear_hp_dis cr4_ear_hp_dis;
+
+ /* CR5 */
+ t_ab8500_codec_cr5_enmic1 cr5_enmic1;
+ t_ab8500_codec_cr5_enmic2 cr5_enmic2;
+ t_ab8500_codec_cr5_enlinl cr5_enlinl;
+ t_ab8500_codec_cr5_enlinr cr5_enlinr;
+ t_ab8500_codec_cr5_mutmic1 cr5_mutmic1;
+ t_ab8500_codec_cr5_mutmic2 cr5_mutmic2;
+ t_ab8500_codec_cr5_mutlinl cr5_mutlinl;
+ t_ab8500_codec_cr5_mutlinr cr5_mutlinr;
+
+ /* CR6 */
+ t_ab8500_codec_cr6_endmic1 cr6_endmic1;
+ t_ab8500_codec_cr6_endmic2 cr6_endmic2;
+ t_ab8500_codec_cr6_endmic3 cr6_endmic3;
+ t_ab8500_codec_cr6_endmic4 cr6_endmic4;
+ t_ab8500_codec_cr6_endmic5 cr6_endmic5;
+ t_ab8500_codec_cr6_endmic6 cr6_endmic6;
+
+ /* CR7 */
+ t_ab8500_codec_cr7_mic1sel cr7_mic1sel;
+ t_ab8500_codec_cr7_linrsel cr7_linrsel;
+ t_ab8500_codec_cr7_endrvhsl cr7_endrvhsl;
+ t_ab8500_codec_cr7_endrvhsr cr7_endrvhsr;
+ t_ab8500_codec_cr7_enadcmic cr7_enadcmic;
+ t_ab8500_codec_cr7_enadclinl cr7_enadclinl;
+ t_ab8500_codec_cr7_enadclinr cr7_enadclinr;
+
+ /* CR8 */
+ t_ab8500_codec_cr8_cp_dis_pldwn cr8_cp_dis_pldwn;
+ t_ab8500_codec_cr8_enear cr8_enear;
+ t_ab8500_codec_cr8_enhsl cr8_enhsl;
+ t_ab8500_codec_cr8_enhsr cr8_enhsr;
+ t_ab8500_codec_cr8_enhfl cr8_enhfl;
+ t_ab8500_codec_cr8_enhfr cr8_enhfr;
+ t_ab8500_codec_cr8_envibl cr8_envibl;
+ t_ab8500_codec_cr8_envibr cr8_envibr;
+
+ /* CR9 */
+ t_ab8500_codec_cr9_endacear cr9_endacear;
+ t_ab8500_codec_cr9_endachsl cr9_endachsl;
+ t_ab8500_codec_cr9_endachsr cr9_endachsr;
+ t_ab8500_codec_cr9_endachfl cr9_endachfl;
+ t_ab8500_codec_cr9_endachfr cr9_endachfr;
+ t_ab8500_codec_cr9_endacvibl cr9_endacvibl;
+ t_ab8500_codec_cr9_endacvibr cr9_endacvibr;
+
+ /* CR10 */
+ t_ab8500_codec_cr10_muteear cr10_muteear;
+ t_ab8500_codec_cr10_mutehsl cr10_mutehsl;
+ t_ab8500_codec_cr10_mutehsr cr10_mutehsr;
+ t_ab8500_codec_cr10_mutehfl cr10_mutehfl;
+ t_ab8500_codec_cr10_mutehfr cr10_mutehfr;
+ t_ab8500_codec_cr10_mutevibl cr10_mutevibl;
+ t_ab8500_codec_cr10_mutevibr cr10_mutevibr;
+
+ /* CR11 */
+ t_ab8500_codec_cr11_earshortpwd cr11_earshortpwd;
+ t_ab8500_codec_cr11_earshortdis cr11_earshortdis;
+ t_ab8500_codec_cr11_hslshortdis cr11_hslshortdis;
+ t_ab8500_codec_cr11_hsrshortdis cr11_hsrshortdis;
+ t_ab8500_codec_cr11_hflshortdis cr11_hflshortdis;
+ t_ab8500_codec_cr11_hfrshortdis cr11_hfrshortdis;
+ t_ab8500_codec_cr11_viblshortdis cr11_viblshortdis;
+ t_ab8500_codec_cr11_vibrshortdis cr11_vibrshortdis;
+
+ /* CR12 */
+ t_ab8500_codec_cr12_encphs cr12_encphs;
+ t_ab8500_codec_cr12_hsautotime cr12_hsautotime;
+ t_ab8500_codec_cr12_hsautoensel cr12_hsautoensel;
+ t_ab8500_codec_cr12_hsautoen cr12_hsautoen;
+
+ /* CR13 */
+ t_ab8500_codec_cr13_envdet_hthresh cr13_envdet_hthresh;
+ t_ab8500_codec_cr13_envdet_lthresh cr13_envdet_lthresh;
+
+ /* CR14 */
+ t_ab8500_codec_cr14_smpslven cr14_smpslven;
+ t_ab8500_codec_cr14_envdetsmpsen cr14_envdetsmpsen;
+ t_ab8500_codec_cr14_cplven cr14_cplven;
+ t_ab8500_codec_cr14_envdetcpen cr14_envdetcpen;
+ t_ab8500_codec_cr14_envet_time cr14_envet_time;
+
+ /* CR15 */
+ t_ab8500_codec_cr15_pwmtovibl cr15_pwmtovibl;
+ t_ab8500_codec_cr15_pwmtovibr cr15_pwmtovibr;
+ t_ab8500_codec_cr15_pwmlctrl cr15_pwmlctrl;
+ t_ab8500_codec_cr15_pwmrctrl cr15_pwmrctrl;
+ t_ab8500_codec_cr15_pwmnlctrl cr15_pwmnlctrl;
+ t_ab8500_codec_cr15_pwmplctrl cr15_pwmplctrl;
+ t_ab8500_codec_cr15_pwmnrctrl cr15_pwmnrctrl;
+ t_ab8500_codec_cr15_pwmprctrl cr15_pwmprctrl;
+
+ /* CR16 */
+ t_ab8500_codec_cr16_pwmnlpol cr16_pwmnlpol;
+ t_ab8500_codec_cr16_pwmnldutycycle cr16_pwmnldutycycle;
+
+ /* CR17 */
+ t_ab8500_codec_cr17_pwmplpol cr17_pwmplpol;
+ t_ab8500_codec_cr17_pwmpldutycycle cr17_pwmpldutycycle;
+
+ /* CR18 */
+ t_ab8500_codec_cr18_pwmnrpol cr18_pwmnrpol;
+ t_ab8500_codec_cr18_pwmnrdutycycle cr18_pwmnrdutycycle;
+
+ /* CR19 */
+ t_ab8500_codec_cr19_pwmprpol cr19_pwmprpol;
+ t_ab8500_codec_cr19_pwmprdutycycle cr19_pwmprdutycycle;
+
+ /* CR20 */
+ t_ab8500_codec_cr20_en_se_mic1 cr20_en_se_mic1;
+ t_ab8500_codec_cr20_mic1_gain cr20_mic1_gain;
+
+ /* CR21 */
+ t_ab8500_codec_cr21_en_se_mic2 cr21_en_se_mic2;
+ t_ab8500_codec_cr21_mic2_gain cr21_mic2_gain;
+
+ /* CR22 */
+ t_ab8500_codec_cr22_hsl_gain cr22_hsl_gain;
+ t_ab8500_codec_cr22_linl_gain cr22_linl_gain;
+
+ /* CR23 */
+ t_ab8500_codec_cr23_hsr_gain cr23_hsr_gain;
+ t_ab8500_codec_cr23_linr_gain cr23_linr_gain;
+
+ /* CR24 */
+ t_ab8500_codec_cr24_lintohsl_gain cr24_lintohsl_gain;
+
+ /* CR25 */
+ t_ab8500_codec_cr25_lintohsr_gain cr25_lintohsr_gain;
+
+ /* CR26 */
+ t_ab8500_codec_cr26_ad1nh cr26_ad1nh;
+ t_ab8500_codec_cr26_ad2nh cr26_ad2nh;
+ t_ab8500_codec_cr26_ad3nh cr26_ad3nh;
+ t_ab8500_codec_cr26_ad4nh cr26_ad4nh;
+ t_ab8500_codec_cr26_ad1_voice cr26_ad1_voice;
+ t_ab8500_codec_cr26_ad2_voice cr26_ad2_voice;
+ t_ab8500_codec_cr26_ad3_voice cr26_ad3_voice;
+ t_ab8500_codec_cr26_ad4_voice cr26_ad4_voice;
+
+ /* CR27 */
+ t_ab8500_codec_cr27_en_mastgen cr27_en_mastgen;
+ t_ab8500_codec_cr27_if1_bitclk_osr cr27_if1_bitclk_osr;
+ t_ab8500_codec_cr27_enfs_bitclk1 cr27_enfs_bitclk1;
+ t_ab8500_codec_cr27_if0_bitclk_osr cr27_if0_bitclk_osr;
+ t_ab8500_codec_cr27_enfs_bitclk0 cr27_enfs_bitclk0;
+
+ /* CR28 */
+ t_ab8500_codec_cr28_fsync0p cr28_fsync0p;
+ t_ab8500_codec_cr28_bitclk0p cr28_bitclk0p;
+ t_ab8500_codec_cr28_if0del cr28_if0del;
+ t_ab8500_codec_cr28_if0format cr28_if0format;
+ t_ab8500_codec_cr28_if0wl cr28_if0wl;
+
+ /* CR29 */
+ t_ab8500_codec_cr29_if0datoif1ad cr29_if0datoif1ad;
+ t_ab8500_codec_cr29_if0cktoif1ck cr29_if0cktoif1ck;
+ t_ab8500_codec_cr29_if1master cr29_if1master;
+ t_ab8500_codec_cr29_if1datoif0ad cr29_if1datoif0ad;
+ t_ab8500_codec_cr29_if1cktoif0ck cr29_if1cktoif0ck;
+ t_ab8500_codec_cr29_if0master cr29_if0master;
+ t_ab8500_codec_cr29_if0bfifoen cr29_if0bfifoen;
+
+ /* CR30 */
+ t_ab8500_codec_cr30_fsync1p cr30_fsync1p;
+ t_ab8500_codec_cr30_bitclk1p cr30_bitclk1p;
+ t_ab8500_codec_cr30_if1del cr30_if1del;
+ t_ab8500_codec_cr30_if1format cr30_if1format;
+ t_ab8500_codec_cr30_if1wl cr30_if1wl;
+
+ /* CR31 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr31_adotoslot1;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr31_adotoslot0;
+
+ /* CR32 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr32_adotoslot3;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr32_adotoslot2;
+
+ /* CR33 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr33_adotoslot5;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr33_adotoslot4;
+
+ /* CR34 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr34_adotoslot7;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr34_adotoslot6;
+
+ /* CR35 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr35_adotoslot9;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr35_adotoslot8;
+
+ /* CR36 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr36_adotoslot11;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr36_adotoslot10;
+
+ /* CR37 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr37_adotoslot13;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr37_adotoslot12;
+
+ /* CR38 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr38_adotoslot15;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr38_adotoslot14;
+
+ /* CR39 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr39_adotoslot17;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr39_adotoslot16;
+
+ /* CR40 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr40_adotoslot19;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr40_adotoslot18;
+
+ /* CR41 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr41_adotoslot21;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr41_adotoslot20;
+
+ /* CR42 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr42_adotoslot23;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr42_adotoslot22;
+
+ /* CR43 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr43_adotoslot25;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr43_adotoslot24;
+
+ /* CR44 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr44_adotoslot27;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr44_adotoslot26;
+
+ /* CR45 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr45_adotoslot29;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr45_adotoslot28;
+
+ /* CR46 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr46_adotoslot31;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr46_adotoslot30;
+
+ /* CR47 */
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl7;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl6;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl5;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl4;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl3;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl2;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl1;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl0;
+
+ /* CR48 */
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl15;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl14;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl13;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl12;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl11;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl10;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl9;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl8;
+
+ /* CR49 */
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl23;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl22;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl21;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl20;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl19;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl18;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl17;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl16;
+
+ /* CR50 */
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl31;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl30;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl29;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl28;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl27;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl26;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl25;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl24;
+
+ /* CR51 */
+ t_ab8500_codec_cr51_da12_voice cr51_da12_voice;
+ t_ab8500_codec_cr51_sldai1toslado1 cr51_sldai1toslado1;
+ t_ab8500_codec_cr51_to_cr56_sltoda cr51_sltoda1;
+
+ /* CR52 */
+ t_ab8500_codec_cr52_sldai2toslado2 cr52_sldai2toslado2;
+ t_ab8500_codec_cr51_to_cr56_sltoda cr52_sltoda2;
+
+ /* CR53 */
+ t_ab8500_codec_cr53_da34_voice cr53_da34_voice;
+ t_ab8500_codec_cr53_sldai3toslado3 cr53_sldai3toslado3;
+ t_ab8500_codec_cr51_to_cr56_sltoda cr53_sltoda3;
+
+ /* CR54 */
+ t_ab8500_codec_cr54_sldai4toslado4 cr54_sldai4toslado4;
+ t_ab8500_codec_cr51_to_cr56_sltoda cr54_sltoda4;
+
+ /* CR55 */
+ t_ab8500_codec_cr55_da56_voice cr55_da56_voice;
+ t_ab8500_codec_cr55_sldai5toslado5 cr55_sldai5toslado5;
+ t_ab8500_codec_cr51_to_cr56_sltoda cr55_sltoda5;
+
+ /* CR56 */
+ t_ab8500_codec_cr56_sldai6toslado7 cr56_sldai6toslado7;
+ t_ab8500_codec_cr51_to_cr56_sltoda cr56_sltoda6;
+
+ /* CR57 */
+ t_ab8500_codec_cr57_bfifull_msk cr57_bfifull_msk;
+ t_ab8500_codec_cr57_bfiempt_msk cr57_bfiempt_msk;
+ t_ab8500_codec_cr57_dachan_msk cr57_dachan_msk;
+ t_ab8500_codec_cr57_gain_msk cr57_gain_msk;
+ t_ab8500_codec_cr57_dspad_msk cr57_dspad_msk;
+ t_ab8500_codec_cr57_dspda_msk cr57_dspda_msk;
+ t_ab8500_codec_cr57_stfir_msk cr57_stfir_msk;
+
+ /* CR58 */
+ t_ab8500_codec_cr58_bfifull_ev cr58_bfifull_ev;
+ t_ab8500_codec_cr58_bfiempt_ev cr58_bfiempt_ev;
+ t_ab8500_codec_cr58_dachan_ev cr58_dachan_ev;
+ t_ab8500_codec_cr58_gain_ev cr58_gain_ev;
+ t_ab8500_codec_cr58_dspad_ev cr58_dspad_ev;
+ t_ab8500_codec_cr58_dspda_ev cr58_dspda_ev;
+ t_ab8500_codec_cr58_stfir_ev cr58_stfir_ev;
+
+ /* CR59 */
+ t_ab8500_codec_cr59_vssready_msk cr59_vssready_msk;
+ t_ab8500_codec_cr59_shrtvibl_msk cr59_shrtvibl_msk;
+ t_ab8500_codec_cr59_shrtvibr_msk cr59_shrtvibr_msk;
+ t_ab8500_codec_cr59_shrthfl_msk cr59_shrthfl_msk;
+ t_ab8500_codec_cr59_shrthfr_msk cr59_shrthfr_msk;
+ t_ab8500_codec_cr59_shrthsl_msk cr59_shrthsl_msk;
+ t_ab8500_codec_cr59_shrthsr_msk cr59_shrthsr_msk;
+ t_ab8500_codec_cr59_shrtear_msk cr59_shrtear_msk;
+
+ /* CR60 */
+ t_ab8500_codec_cr60_vssready_ev cr60_vssready_ev;
+ t_ab8500_codec_cr60_shrtvibl_ev cr60_shrtvibl_ev;
+ t_ab8500_codec_cr60_shrtvibr_ev cr60_shrtvibr_ev;
+ t_ab8500_codec_cr60_shrthfl_ev cr60_shrthfl_ev;
+ t_ab8500_codec_cr60_shrthfr_ev cr60_shrthfr_ev;
+ t_ab8500_codec_cr60_shrthsl_ev cr60_shrthsl_ev;
+ t_ab8500_codec_cr60_shrthsr_ev cr60_shrthsr_ev;
+ t_ab8500_codec_cr60_shrtear_ev cr60_shrtear_ev;
+
+ /* CR61 */
+ t_ab8500_codec_cr61_revision cr61_revision;
+ t_ab8500_codec_cr61_fade_speed cr61_fade_speed;
+
+ /* CR62 */
+ t_ab8500_codec_cr62_dmic1sinc3 cr62_dmic1sinc3;
+ t_ab8500_codec_cr62_dmic2sinc3 cr62_dmic2sinc3;
+ t_ab8500_codec_cr62_dmic3sinc3 cr62_dmic3sinc3;
+ t_ab8500_codec_cr62_dmic4sinc3 cr62_dmic4sinc3;
+ t_ab8500_codec_cr62_dmic5sinc3 cr62_dmic5sinc3;
+ t_ab8500_codec_cr62_dmic6sinc3 cr62_dmic6sinc3;
+
+ /* CR63 */
+ t_ab8500_codec_cr63_datohslen cr63_datohslen;
+ t_ab8500_codec_cr63_datohsren cr63_datohsren;
+ t_ab8500_codec_cr63_ad1sel cr63_ad1sel;
+ t_ab8500_codec_cr63_ad2sel cr63_ad2sel;
+ t_ab8500_codec_cr63_ad3sel cr63_ad3sel;
+ t_ab8500_codec_cr63_ad5sel cr63_ad5sel;
+ t_ab8500_codec_cr63_ad6sel cr63_ad6sel;
+ t_ab8500_codec_cr63_ancsel cr63_ancsel;
+
+ /* CR64 */
+ t_ab8500_codec_cr64_datohfren cr64_datohfren;
+ t_ab8500_codec_cr64_datohflen cr64_datohflen;
+ t_ab8500_codec_cr64_hfrsel cr64_hfrsel;
+ t_ab8500_codec_cr64_hflsel cr64_hflsel;
+ t_ab8500_codec_cr64_stfir1sel cr64_stfir1sel;
+ t_ab8500_codec_cr64_stfir2sel cr64_stfir2sel;
+
+ /* CR65 */
+ t_ab8500_codec_cr65_fadedis_ad1 cr65_fadedis_ad1;
+ t_ab8500_codec_cr65_ad1gain cr65_ad1gain;
+
+ /* CR66 */
+ t_ab8500_codec_cr66_fadedis_ad2 cr66_fadedis_ad2;
+ t_ab8500_codec_cr66_ad2gain cr66_ad2gain;
+
+ /* CR67 */
+ t_ab8500_codec_cr67_fadedis_ad3 cr67_fadedis_ad3;
+ t_ab8500_codec_cr67_ad3gain cr67_ad3gain;
+
+ /* CR68 */
+ t_ab8500_codec_cr68_fadedis_ad4 cr68_fadedis_ad4;
+ t_ab8500_codec_cr68_ad4gain cr68_ad4gain;
+
+ /* CR69 */
+ t_ab8500_codec_cr69_fadedis_ad5 cr69_fadedis_ad5;
+ t_ab8500_codec_cr69_ad5gain cr69_ad5gain;
+
+ /* CR70 */
+ t_ab8500_codec_cr70_fadedis_ad6 cr70_fadedis_ad6;
+ t_ab8500_codec_cr70_ad6gain cr70_ad6gain;
+
+ /* CR71 */
+ t_ab8500_codec_cr71_fadedis_da1 cr71_fadedis_da1;
+ t_ab8500_codec_cr71_da1gain cr71_da1gain;
+
+ /* CR72 */
+ t_ab8500_codec_cr72_fadedis_da2 cr72_fadedis_da2;
+ t_ab8500_codec_cr72_da2gain cr72_da2gain;
+
+ /* CR73 */
+ t_ab8500_codec_cr73_fadedis_da3 cr73_fadedis_da3;
+ t_ab8500_codec_cr73_da3gain cr73_da3gain;
+
+ /* CR74 */
+ t_ab8500_codec_cr74_fadedis_da4 cr74_fadedis_da4;
+ t_ab8500_codec_cr74_da4gain cr74_da4gain;
+
+ /* CR75 */
+ t_ab8500_codec_cr75_fadedis_da5 cr75_fadedis_da5;
+ t_ab8500_codec_cr75_da5gain cr75_da5gain;
+
+ /* CR76 */
+ t_ab8500_codec_cr76_fadedis_da6 cr76_fadedis_da6;
+ t_ab8500_codec_cr76_da6gain cr76_da6gain;
+
+ /* CR77 */
+ t_ab8500_codec_cr77_fadedis_ad1l cr77_fadedis_ad1l;
+ t_ab8500_codec_cr77_ad1lbgain_to_hfl cr77_ad1lbgain_to_hfl;
+
+ /* CR78 */
+ t_ab8500_codec_cr78_fadedis_ad2l cr78_fadedis_ad2l;
+ t_ab8500_codec_cr78_ad2lbgain_to_hfr cr78_ad2lbgain_to_hfr;
+
+ /* CR79 */
+ t_ab8500_codec_cr79_hssinc1 cr79_hssinc1;
+ t_ab8500_codec_cr79_fadedis_hsl cr79_fadedis_hsl;
+ t_ab8500_codec_cr79_hsldgain cr79_hsldgain;
+
+ /* CR80 */
+ t_ab8500_codec_cr80_fadedis_hsr cr80_fadedis_hsr;
+ t_ab8500_codec_cr80_hsrdgain cr80_hsrdgain;
+
+ /* CR81 */
+ t_ab8500_codec_cr81_stfir1gain cr81_stfir1gain;
+
+ /* CR82 */
+ t_ab8500_codec_cr82_stfir2gain cr82_stfir2gain;
+
+ /* CR83 */
+ t_ab8500_codec_cr83_enanc cr83_enanc;
+ t_ab8500_codec_cr83_anciirinit cr83_anciirinit;
+ t_ab8500_codec_cr83_ancfirupdate cr83_ancfirupdate;
+
+ /* CR84 */
+ t_ab8500_codec_cr84_ancinshift cr84_ancinshift;
+
+ /* CR85 */
+ t_ab8500_codec_cr85_ancfiroutshift cr85_ancfiroutshift;
+
+ /* CR86 */
+ t_ab8500_codec_cr86_ancshiftout cr86_ancshiftout;
+
+ /* CR87 */
+ t_ab8500_codec_cr87_ancfircoeff_msb cr87_ancfircoeff_msb;
+
+ /* CR88 */
+ t_ab8500_codec_cr88_ancfircoeff_lsb cr88_ancfircoeff_lsb;
+
+ /* CR89 */
+ t_ab8500_codec_cr89_anciircoeff_msb cr89_anciircoeff_msb;
+
+ /* CR90 */
+ t_ab8500_codec_cr90_anciircoeff_lsb cr90_anciircoeff_lsb;
+
+ /* CR91 */
+ t_ab8500_codec_cr91_ancwarpdel_msb cr91_ancwarpdel_msb;
+
+ /* CR92 */
+ t_ab8500_codec_cr92_ancwarpdel_lsb cr92_ancwarpdel_lsb;
+
+ /* CR93 */
+ t_ab8500_codec_cr93_ancfirpeak_msb cr93_ancfirpeak_msb;
+
+ /* CR94 */
+ t_ab8500_codec_cr94_ancfirpeak_lsb cr94_ancfirpeak_lsb;
+
+ /* CR95 */
+ t_ab8500_codec_cr95_anciirpeak_msb cr95_anciirpeak_msb;
+
+ /* CR96 */
+ t_ab8500_codec_cr96_anciirpeak_lsb cr96_anciirpeak_lsb;
+
+ /* CR97 */
+ t_ab8500_codec_cr97_stfir_set cr97_stfir_set;
+ t_ab8500_codec_cr97_stfir_addr cr97_stfir_addr;
+
+ /* CR98 */
+ t_ab8500_codec_cr98_stfir_coeff_msb cr98_stfir_coeff_msb;
+
+ /* CR99 */
+ t_ab8500_codec_cr99_stfir_coeff_lsb cr99_stfir_coeff_lsb;
+
+ /* CR100 */
+ t_ab8500_codec_cr100_enstfirs cr100_enstfirs;
+ t_ab8500_codec_cr100_stfirstoif1 cr100_stfirstoif1;
+ t_ab8500_codec_cr100_stfir_busy cr100_stfir_busy;
+
+ /* CR101 */
+ t_ab8500_codec_cr101_parlhf cr101_parlhf;
+ t_ab8500_codec_cr101_parlvib cr101_parlvib;
+ t_ab8500_codec_cr101_classd_viblswapen cr101_classd_viblswapen;
+ t_ab8500_codec_cr101_classd_vibrswapen cr101_classd_vibrswapen;
+ t_ab8500_codec_cr101_classd_hflswapen cr101_classd_hflswapen;
+ t_ab8500_codec_cr101_classd_hfrswapen cr101_classd_hfrswapen;
+
+ /* CR102 */
+ t_ab8500_codec_cr102_classd_firbyp cr102_classd_firbyp;
+ t_ab8500_codec_cr102_classd_highvolen cr102_classd_highvolen;
+
+ /* CR103 */
+ t_ab8500_codec_cr103_classd_ditherhpgain cr103_classd_ditherhpgain;
+ t_ab8500_codec_cr103_classd_ditherwgain cr103_classd_ditherwgain;
+
+ /* CR104 */
+ t_ab8500_codec_cr104_bfifoint cr104_bfifoint;
+
+ /* CR105 */
+ t_ab8500_codec_cr105_bfifotx cr105_bfifotx;
+
+ /* CR106 */
+ t_ab8500_codec_cr106_bfifofsext cr106_bfifofsext;
+ t_ab8500_codec_cr106_bfifomsk cr106_bfifomsk;
+ t_ab8500_codec_cr106_bfifomstr cr106_bfifomstr;
+ t_ab8500_codec_cr106_bfifostrt cr106_bfifostrt;
+
+ /* CR107 */
+ t_ab8500_codec_cr107_bfifosampnr cr107_bfifosampnr;
+
+ /* CR108 */
+ t_ab8500_codec_cr108_bfifowakeup cr108_bfifowakeup;
+
+ /* CR109 */
+ t_ab8500_codec_cr109_bfifosamples cr109_bfifosamples;
+
+} t_ab8500_codec_configuration;
+
+typedef enum {
+ AB8500_CODEC_DIRECTION_IN,
+ AB8500_CODEC_DIRECTION_OUT,
+ AB8500_CODEC_DIRECTION_INOUT
+} t_ab8500_codec_direction;
+
+typedef enum {
+ AB8500_CODEC_MODE_HIFI,
+ AB8500_CODEC_MODE_VOICE,
+ AB8500_CODEC_MODE_MANUAL_SETTING
+} t_ab8500_codec_mode;
+
+typedef enum {
+ AB8500_CODEC_AUDIO_INTERFACE_0,
+ AB8500_CODEC_AUDIO_INTERFACE_1
+} t_ab8500_codec_audio_interface;
+
+typedef enum {
+ AB8500_CODEC_SRC_LINEIN,
+ AB8500_CODEC_SRC_MICROPHONE_1A,
+ AB8500_CODEC_SRC_MICROPHONE_1B,
+ AB8500_CODEC_SRC_MICROPHONE_2,
+ AB8500_CODEC_SRC_D_MICROPHONE_1,
+ AB8500_CODEC_SRC_D_MICROPHONE_2,
+ AB8500_CODEC_SRC_D_MICROPHONE_3,
+ AB8500_CODEC_SRC_D_MICROPHONE_4,
+ AB8500_CODEC_SRC_D_MICROPHONE_5,
+ AB8500_CODEC_SRC_D_MICROPHONE_6,
+ AB8500_CODEC_SRC_FM_RX,
+ AB8500_CODEC_SRC_ALL
+} t_ab8500_codec_src;
+
+typedef enum {
+ AB8500_CODEC_DEST_HEADSET,
+ AB8500_CODEC_DEST_EARPIECE,
+ AB8500_CODEC_DEST_HANDSFREE,
+ AB8500_CODEC_DEST_VIBRATOR_L,
+ AB8500_CODEC_DEST_VIBRATOR_R,
+ AB8500_CODEC_DEST_ALL
+} t_ab8500_codec_dest;
+
+typedef struct {
+ t_uint8 slave_address_of_ab8500_codec;
+ t_ab8500_codec_direction ab8500_codec_direction;
+ t_ab8500_codec_mode ab8500_codec_mode_in;
+ t_ab8500_codec_mode ab8500_codec_mode_out;
+ t_ab8500_codec_audio_interface audio_interface;
+ t_ab8500_codec_src ab8500_codec_src;
+ t_ab8500_codec_dest ab8500_codec_dest;
+ t_uint8 in_left_volume;
+ t_uint8 in_right_volume;
+ t_uint8 out_left_volume;
+ t_uint8 out_right_volume;
+
+ t_ab8500_codec_configuration ab8500_codec_configuration;
+} t_ab8500_codec_system_context;
+#endif /* _AB8500_CODECP_H_ */
+
+/* End of file AB8500_CODECP.h */
diff --git a/arch/arm/mach-ux500/include/mach/ab8500_codec_p_v1_0.h b/arch/arm/mach-ux500/include/mach/ab8500_codec_p_v1_0.h
new file mode 100644
index 00000000000..866cd0c80f1
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/ab8500_codec_p_v1_0.h
@@ -0,0 +1,3037 @@
+/*****************************************************************************/
+/**
+* © ST-Ericsson, 2009 - All rights reserved
+* Reproduction and Communication of this document is strictly prohibited
+* unless specifically authorized in writing by ST-Ericsson
+*
+* \brief Private Header file for AB8500 CODEC
+* \author ST-Ericsson
+*/
+/*****************************************************************************/
+
+#ifndef _AB8500_CODECP_V1_0_H_
+#define _AB8500_CODECP_V1_0_H_
+
+/*----------------------------------------------------------------------------
+ * Includes
+ *---------------------------------------------------------------------------*/
+#include "hcl_defs.h"
+
+#define AB8500_CODEC_HCL_VERSION_ID 3
+#define AB8500_CODEC_HCL_MAJOR_ID 0
+#define AB8500_CODEC_HCL_MINOR_ID 0
+
+#define AB8500_CODEC_MASK_ONE_BIT 0x1UL
+#define AB8500_CODEC_MASK_TWO_BITS 0x3UL
+#define AB8500_CODEC_MASK_THREE_BITS 0x7UL
+#define AB8500_CODEC_MASK_FOUR_BITS 0xFUL
+#define AB8500_CODEC_MASK_FIVE_BITS 0x1FUL
+#define AB8500_CODEC_MASK_SIX_BITS 0x3FUL
+#define AB8500_CODEC_MASK_SEVEN_BITS 0x7FUL
+#define AB8500_CODEC_MASK_EIGHT_BITS 0xFFUL
+
+#define AB8500_CODEC_WRITE_BITS(reg, val, bit_nb, pos) (reg) = ((t_uint8) ((((reg) & (~(bit_nb << pos))) | (((val) & bit_nb) << pos))))
+
+#define AB8500_CODEC_BLOCK 0x0D
+
+#define AB8500_CODEC_MASK_TWO_MS_BITS 0xC0UL
+#define AB8500_CODEC_MASK_SIX_LS_BITS 0x3FUL
+
+/* Genepi AudioCodec Control Registers */
+
+#define AB8500_CODEC_CR0 0x00
+#define AB8500_CODEC_CR1 0x01
+#define AB8500_CODEC_CR2 0x02
+#define AB8500_CODEC_CR3 0x03
+#define AB8500_CODEC_CR4 0x04
+#define AB8500_CODEC_CR5 0x05
+#define AB8500_CODEC_CR6 0x06
+#define AB8500_CODEC_CR7 0x07
+#define AB8500_CODEC_CR8 0x08
+#define AB8500_CODEC_CR9 0x09
+#define AB8500_CODEC_CR10 0x0A
+#define AB8500_CODEC_CR11 0x0B
+#define AB8500_CODEC_CR12 0x0C
+#define AB8500_CODEC_CR13 0x0D
+#define AB8500_CODEC_CR14 0x0E
+#define AB8500_CODEC_CR15 0x0F
+#define AB8500_CODEC_CR16 0x10
+#define AB8500_CODEC_CR17 0x11
+#define AB8500_CODEC_CR18 0x12
+#define AB8500_CODEC_CR19 0x13
+#define AB8500_CODEC_CR20 0x14
+#define AB8500_CODEC_CR21 0x15
+#define AB8500_CODEC_CR22 0x16
+#define AB8500_CODEC_CR23 0x17
+#define AB8500_CODEC_CR24 0x18
+#define AB8500_CODEC_CR25 0x19
+#define AB8500_CODEC_CR26 0x1A
+#define AB8500_CODEC_CR27 0x1B
+#define AB8500_CODEC_CR28 0x1C
+#define AB8500_CODEC_CR29 0x1D
+#define AB8500_CODEC_CR30 0x1E
+#define AB8500_CODEC_CR31 0x1F
+#define AB8500_CODEC_CR32 0x20
+#define AB8500_CODEC_CR33 0x21
+#define AB8500_CODEC_CR34 0x22
+#define AB8500_CODEC_CR35 0x23
+#define AB8500_CODEC_CR36 0x24
+#define AB8500_CODEC_CR37 0x25
+#define AB8500_CODEC_CR38 0x26
+#define AB8500_CODEC_CR39 0x27
+#define AB8500_CODEC_CR40 0x28
+#define AB8500_CODEC_CR41 0x29
+#define AB8500_CODEC_CR42 0x2A
+#define AB8500_CODEC_CR43 0x2B
+#define AB8500_CODEC_CR44 0x2C
+#define AB8500_CODEC_CR45 0x2D
+#define AB8500_CODEC_CR46 0x2E
+#define AB8500_CODEC_CR47 0x2F
+#define AB8500_CODEC_CR48 0x30
+#define AB8500_CODEC_CR49 0x31
+#define AB8500_CODEC_CR50 0x32
+#define AB8500_CODEC_CR51 0x33
+#define AB8500_CODEC_CR52 0x34
+#define AB8500_CODEC_CR53 0x35
+#define AB8500_CODEC_CR54 0x36
+#define AB8500_CODEC_CR55 0x37
+#define AB8500_CODEC_CR56 0x38
+#define AB8500_CODEC_CR57 0x39
+#define AB8500_CODEC_CR58 0x3A
+#define AB8500_CODEC_CR59 0x3B
+#define AB8500_CODEC_CR60 0x3C
+#define AB8500_CODEC_CR61 0x3D
+#define AB8500_CODEC_CR62 0x3E
+#define AB8500_CODEC_CR63 0x3F
+#define AB8500_CODEC_CR64 0x40
+#define AB8500_CODEC_CR65 0x41
+#define AB8500_CODEC_CR66 0x42
+#define AB8500_CODEC_CR67 0x43
+#define AB8500_CODEC_CR68 0x44
+#define AB8500_CODEC_CR69 0x45
+#define AB8500_CODEC_CR70 0x46
+#define AB8500_CODEC_CR71 0x47
+#define AB8500_CODEC_CR72 0x48
+#define AB8500_CODEC_CR73 0x49
+#define AB8500_CODEC_CR74 0x4A
+#define AB8500_CODEC_CR75 0x4B
+#define AB8500_CODEC_CR76 0x4C
+#define AB8500_CODEC_CR77 0x4D
+#define AB8500_CODEC_CR78 0x4E
+#define AB8500_CODEC_CR79 0x4F
+#define AB8500_CODEC_CR80 0x50
+#define AB8500_CODEC_CR81 0x51
+#define AB8500_CODEC_CR82 0x52
+#define AB8500_CODEC_CR83 0x53
+#define AB8500_CODEC_CR84 0x54
+#define AB8500_CODEC_CR85 0x55
+#define AB8500_CODEC_CR86 0x56
+#define AB8500_CODEC_CR87 0x57
+#define AB8500_CODEC_CR88 0x58
+#define AB8500_CODEC_CR89 0x59
+#define AB8500_CODEC_CR90 0x5A
+#define AB8500_CODEC_CR91 0x5B
+#define AB8500_CODEC_CR92 0x5C
+#define AB8500_CODEC_CR93 0x5D
+#define AB8500_CODEC_CR94 0x5E
+#define AB8500_CODEC_CR95 0x5F
+#define AB8500_CODEC_CR96 0x60
+#define AB8500_CODEC_CR97 0x61
+#define AB8500_CODEC_CR98 0x62
+#define AB8500_CODEC_CR99 0x63
+#define AB8500_CODEC_CR100 0x64
+#define AB8500_CODEC_CR101 0x65
+#define AB8500_CODEC_CR102 0x66
+#define AB8500_CODEC_CR103 0x67
+#define AB8500_CODEC_CR104 0x68
+#define AB8500_CODEC_CR105 0x69
+#define AB8500_CODEC_CR106 0x6A
+#define AB8500_CODEC_CR107 0x6B
+#define AB8500_CODEC_CR108 0x6C
+#define AB8500_CODEC_CR109 0x6D
+#define AB8500_CODEC_CR110 0x6E
+#define AB8500_CODEC_CR111 0x6F
+
+/* CR0-CR0x0000 */
+#define AB8500_CODEC_CR0_POWERUP 7
+#define AB8500_CODEC_CR0_ENAANA 3
+
+/* CR1-CR0x0001 */
+#define AB8500_CODEC_CR1_SWRESET 7
+
+/* CR2-CR0x0002 */
+#define AB8500_CODEC_CR2_ENAD1 7
+#define AB8500_CODEC_CR2_ENAD2 6
+#define AB8500_CODEC_CR2_ENAD3 5
+#define AB8500_CODEC_CR2_ENAD4 4
+#define AB8500_CODEC_CR2_ENAD5 3
+#define AB8500_CODEC_CR2_ENAD6 2
+
+/* CR3-CR0x0003 */
+#define AB8500_CODEC_CR3_ENDA1 7
+#define AB8500_CODEC_CR3_ENDA2 6
+#define AB8500_CODEC_CR3_ENDA3 5
+#define AB8500_CODEC_CR3_ENDA4 4
+#define AB8500_CODEC_CR3_ENDA5 3
+#define AB8500_CODEC_CR3_ENDA6 2
+
+/* CR4-CR0x0004 */
+#define AB8500_CODEC_CR4_LOWPOWHS 7
+#define AB8500_CODEC_CR4_LOWPOWDACHS 5
+#define AB8500_CODEC_CR4_LOWPOWEAR 4
+#define AB8500_CODEC_CR4_EAR_SEL_CM 2
+#define AB8500_CODEC_CR4_HS_HP_EN 1
+
+/* CR5-CR0x0005 */
+#define AB8500_CODEC_CR5_ENMIC1 7
+#define AB8500_CODEC_CR5_ENMIC2 6
+#define AB8500_CODEC_CR5_ENLINL 5
+#define AB8500_CODEC_CR5_ENLINR 4
+#define AB8500_CODEC_CR5_MUTMIC1 3
+#define AB8500_CODEC_CR5_MUTMIC2 2
+#define AB8500_CODEC_CR5_MUTELINL 1
+#define AB8500_CODEC_CR5_MUTELINR 0
+
+/* CR6-CR0x0006 */
+#define AB8500_CODEC_CR6_ENDMIC1 7
+#define AB8500_CODEC_CR6_ENDMIC2 6
+#define AB8500_CODEC_CR6_ENDMIC3 5
+#define AB8500_CODEC_CR6_ENDMIC4 4
+#define AB8500_CODEC_CR6_ENDMIC5 3
+#define AB8500_CODEC_CR6_ENDMIC6 2
+
+/* CR7-CR0x0007 */
+#define AB8500_CODEC_CR7_MIC1SEL 7
+#define AB8500_CODEC_CR7_LINRSEL 6
+#define AB8500_CODEC_CR7_ENDRVHSL 5
+#define AB8500_CODEC_CR7_ENDRVHSR 4
+#define AB8500_CODEC_CR7_ENADCMIC 2
+#define AB8500_CODEC_CR7_ENADCLINL 1
+#define AB8500_CODEC_CR7_ENADCLINR 0
+
+/* CR8-CR0x0008 */
+#define AB8500_CODEC_CR8_CP_DIS_PLDWN 7
+#define AB8500_CODEC_CR8_ENEAR 6
+#define AB8500_CODEC_CR8_ENHSL 5
+#define AB8500_CODEC_CR8_ENHSR 4
+#define AB8500_CODEC_CR8_ENHFL 3
+#define AB8500_CODEC_CR8_ENHFR 2
+#define AB8500_CODEC_CR8_ENVIBL 1
+#define AB8500_CODEC_CR8_ENVIBR 0
+
+/* CR9-CR0x0009 */
+#define AB8500_CODEC_CR9_ENADACEAR 6
+#define AB8500_CODEC_CR9_ENADACHSL 5
+#define AB8500_CODEC_CR9_ENADACHSR 4
+#define AB8500_CODEC_CR9_ENADACHFL 3
+#define AB8500_CODEC_CR9_ENADACHFR 2
+#define AB8500_CODEC_CR9_ENADACVIBL 1
+#define AB8500_CODEC_CR9_ENADACVIBR 0
+
+/* CR10-CR0x000A */
+#define AB8500_CODEC_CR10_MUTEEAR 6
+#define AB8500_CODEC_CR10_MUTEHSL 5
+#define AB8500_CODEC_CR10_MUTEHSR 4
+
+/* CR11-CR0x000B */
+#define AB8500_CODEC_CR11_ENSHORTPWD 7
+#define AB8500_CODEC_CR11_EARSHORTDIS 6
+#define AB8500_CODEC_CR11_HSSHORTDIS 5
+#define AB8500_CODEC_CR11_HSPULLDEN 4
+#define AB8500_CODEC_CR11_HSOSCEN 2
+#define AB8500_CODEC_CR11_HSFADEN 1
+#define AB8500_CODEC_CR11_HSZCDDIS 0
+
+/* CR12-CR0x000C */
+#define AB8500_CODEC_CR12_ENCPHS 7
+#define AB8500_CODEC_CR12_HSAUTOEN 0
+
+/* CR13-CR0x000D */
+#define AB8500_CODEC_CR13_ENVDET_HTHRESH 4
+#define AB8500_CODEC_CR13_ENVDET_LTHRESH 0
+
+/* CR14-CR0x000E */
+#define AB8500_CODEC_CR14_SMPSLVEN 7
+#define AB8500_CODEC_CR14_ENVDETSMPSEN 6
+#define AB8500_CODEC_CR14_CPLVEN 5
+#define AB8500_CODEC_CR14_ENVDETCPEN 4
+#define AB8500_CODEC_CR14_ENVDET_TIME 0
+
+/* CR15-CR0x000F */
+#define AB8500_CODEC_CR15_PWMTOVIBL 7
+#define AB8500_CODEC_CR15_PWMTOVIBR 6
+#define AB8500_CODEC_CR15_PWMLCTRL 5
+#define AB8500_CODEC_CR15_PWMRCTRL 4
+#define AB8500_CODEC_CR15_PWMNLCTRL 3
+#define AB8500_CODEC_CR15_PWMPLCTRL 2
+#define AB8500_CODEC_CR15_PWMNRCTRL 1
+#define AB8500_CODEC_CR15_PWMPRCTRL 0
+
+/* CR16-CR0x0010 */
+#define AB8500_CODEC_CR16_PWMNLPOL 7
+#define AB8500_CODEC_CR16_PWMNLDUTYCYCLE 0
+
+/* CR17-CR0x0011 */
+#define AB8500_CODEC_CR17_PWMPLPOL 7
+#define AB8500_CODEC_CR17_PWMLPDUTYCYCLE 0
+
+/* CR18-CR0x0012 */
+#define AB8500_CODEC_CR18_PWMNRPOL 7
+#define AB8500_CODEC_CR18_PWMNRDUTYCYCLE 0
+
+/* CR19-CR0x0013 */
+#define AB8500_CODEC_CR19_PWMPRPOL 7
+#define AB8500_CODEC_CR19_PWMRPDUTYCYCLE 0
+
+/* CR20-CR0x0014 */
+#define AB8500_CODEC_CR20_EN_SE_MIC1 7
+#define AB8500_CODEC_CR20_LOW_POW_MIC1 6
+#define AB8500_CODEC_CR20_MIC1_GAIN 0
+
+/* CR21-CR0x0015 */
+#define AB8500_CODEC_CR21_EN_SE_MIC2 7
+#define AB8500_CODEC_CR21_LOW_POW_MIC2 6
+#define AB8500_CODEC_CR21_MIC2_GAIN 0
+
+/* CR22-CR0x0016 */
+#define AB8500_CODEC_CR22_HSL_GAIN 4
+#define AB8500_CODEC_CR22_HSR_GAIN 0
+
+/* CR23-CR0x0017 */
+#define AB8500_CODEC_CR23_LINL_GAIN 4
+#define AB8500_CODEC_CR23_LINR_GAIN 0
+
+/* CR24-CR0x0018 */
+#define AB8500_CODEC_CR24_LINTOHSL_GAIN 0
+
+/* CR25-CR0x0019 */
+#define AB8500_CODEC_CR25_LINTOHSR_GAIN 0
+
+/* CR26-CR0x001A */
+#define AB8500_CODEC_CR26_AD1NH 7
+#define AB8500_CODEC_CR26_AD2NH 6
+#define AB8500_CODEC_CR26_AD3NH 5
+#define AB8500_CODEC_CR26_AD4NH 4
+#define AB8500_CODEC_CR26_AD1_VOICE 3
+#define AB8500_CODEC_CR26_AD2_VOICE 2
+#define AB8500_CODEC_CR26_AD3_VOICE 1
+#define AB8500_CODEC_CR26_AD4_VOICE 0
+
+/* CR27-CR0x001B */
+#define AB8500_CODEC_CR27_EN_MASTGEN 7
+#define AB8500_CODEC_CR27_IF1_BITCLK_OSR 5
+#define AB8500_CODEC_CR27_ENFS_BITCLK1 4
+#define AB8500_CODEC_CR27_IF0_BITCLK_OSR 1
+#define AB8500_CODEC_CR27_ENFS_BITCLK0 0
+
+/* CR28-CR0x001C */
+#define AB8500_CODEC_CR28_FSYNC0P 6
+#define AB8500_CODEC_CR28_BITCLK0P 5
+#define AB8500_CODEC_CR28_IF0DEL 4
+#define AB8500_CODEC_CR28_IF0FORMAT 2
+#define AB8500_CODEC_CR28_IF0WL 0
+
+/* CR29-CR0x001D */
+#define AB8500_CODEC_CR29_IF0DATOIF1AD 7
+#define AB8500_CODEC_CR29_IF0CKTOIF1CK 6
+#define AB8500_CODEC_CR29_IF1MASTER 5
+#define AB8500_CODEC_CR29_IF1DATOIF0AD 3
+#define AB8500_CODEC_CR29_IF1CKTOIF0CK 2
+#define AB8500_CODEC_CR29_IF0MASTER 1
+#define AB8500_CODEC_CR29_IF0BFIFOEN 0
+
+/* CR30-CR0x001E */
+#define AB8500_CODEC_CR30_FSYNC1P 6
+#define AB8500_CODEC_CR30_BITCLK1P 5
+#define AB8500_CODEC_CR30_IF1DEL 4
+#define AB8500_CODEC_CR30_IF1FORMAT 2
+#define AB8500_CODEC_CR30_IF1WL 0
+
+/* CR31-CR0x001F */
+#define AB8500_CODEC_CR31_ADOTOSLOT1 4
+#define AB8500_CODEC_CR31_ADOTOSLOT0 0
+
+/* CR32-CR0x0020 */
+#define AB8500_CODEC_CR32_ADOTOSLOT3 4
+#define AB8500_CODEC_CR32_ADOTOSLOT2 0
+
+/* CR33-CR0x0021 */
+#define AB8500_CODEC_CR33_ADOTOSLOT5 4
+#define AB8500_CODEC_CR33_ADOTOSLOT4 0
+
+/* CR34-CR0x0022 */
+#define AB8500_CODEC_CR34_ADOTOSLOT7 4
+#define AB8500_CODEC_CR34_ADOTOSLOT6 0
+
+/* CR35-CR0x0023 */
+#define AB8500_CODEC_CR35_ADOTOSLOT9 4
+#define AB8500_CODEC_CR35_ADOTOSLOT8 0
+
+/* CR36-CR0x0024 */
+#define AB8500_CODEC_CR36_ADOTOSLOT11 4
+#define AB8500_CODEC_CR36_ADOTOSLOT10 0
+
+/* CR37-CR0x0025 */
+#define AB8500_CODEC_CR37_ADOTOSLOT13 4
+#define AB8500_CODEC_CR37_ADOTOSLOT12 0
+
+/* CR38-CR0x0026 */
+#define AB8500_CODEC_CR38_ADOTOSLOT15 4
+#define AB8500_CODEC_CR38_ADOTOSLOT14 0
+
+/* CR39-CR0x0027 */
+#define AB8500_CODEC_CR39_ADOTOSLOT17 4
+#define AB8500_CODEC_CR39_ADOTOSLOT16 0
+
+/* CR40-CR0x0028 */
+#define AB8500_CODEC_CR40_ADOTOSLOT19 4
+#define AB8500_CODEC_CR40_ADOTOSLOT18 0
+
+/* CR41-CR0x0029 */
+#define AB8500_CODEC_CR41_ADOTOSLOT21 4
+#define AB8500_CODEC_CR41_ADOTOSLOT20 0
+
+/* CR42-CR0x002A */
+#define AB8500_CODEC_CR42_ADOTOSLOT23 4
+#define AB8500_CODEC_CR42_ADOTOSLOT22 0
+
+/* CR43-CR0x002B */
+#define AB8500_CODEC_CR43_ADOTOSLOT25 4
+#define AB8500_CODEC_CR43_ADOTOSLOT24 0
+
+/* CR44-CR0x002C */
+#define AB8500_CODEC_CR44_ADOTOSLOT27 4
+#define AB8500_CODEC_CR44_ADOTOSLOT26 0
+
+/* CR45-CR0x002D */
+#define AB8500_CODEC_CR45_ADOTOSLOT29 4
+#define AB8500_CODEC_CR45_ADOTOSLOT28 0
+
+/* CR46-CR0x002E */
+#define AB8500_CODEC_CR46_ADOTOSLOT31 4
+#define AB8500_CODEC_CR46_ADOTOSLOT30 0
+
+/* CR47-CR0x002F */
+#define AB8500_CODEC_CR47_HIZ_SL7 7
+#define AB8500_CODEC_CR47_HIZ_SL6 6
+#define AB8500_CODEC_CR47_HIZ_SL5 5
+#define AB8500_CODEC_CR47_HIZ_SL4 4
+#define AB8500_CODEC_CR47_HIZ_SL3 3
+#define AB8500_CODEC_CR47_HIZ_SL2 2
+#define AB8500_CODEC_CR47_HIZ_SL1 1
+#define AB8500_CODEC_CR47_HIZ_SL0 0
+
+/* CR48-CR0x0030 */
+#define AB8500_CODEC_CR48_HIZ_SL15 7
+#define AB8500_CODEC_CR48_HIZ_SL14 6
+#define AB8500_CODEC_CR48_HIZ_SL13 5
+#define AB8500_CODEC_CR48_HIZ_SL12 4
+#define AB8500_CODEC_CR48_HIZ_SL11 3
+#define AB8500_CODEC_CR48_HIZ_SL10 2
+#define AB8500_CODEC_CR48_HIZ_SL9 1
+#define AB8500_CODEC_CR48_HIZ_SL8 0
+
+/* CR49-CR0x0031 */
+#define AB8500_CODEC_CR49_HIZ_SL23 7
+#define AB8500_CODEC_CR49_HIZ_SL22 6
+#define AB8500_CODEC_CR49_HIZ_SL21 5
+#define AB8500_CODEC_CR49_HIZ_SL20 4
+#define AB8500_CODEC_CR49_HIZ_SL19 3
+#define AB8500_CODEC_CR49_HIZ_SL18 2
+#define AB8500_CODEC_CR49_HIZ_SL17 1
+#define AB8500_CODEC_CR49_HIZ_SL16 0
+
+/* CR50-CR0x0032 */
+#define AB8500_CODEC_CR50_HIZ_SL31 7
+#define AB8500_CODEC_CR50_HIZ_SL30 6
+#define AB8500_CODEC_CR50_HIZ_SL29 5
+#define AB8500_CODEC_CR50_HIZ_SL28 4
+#define AB8500_CODEC_CR50_HIZ_SL27 3
+#define AB8500_CODEC_CR50_HIZ_SL26 2
+#define AB8500_CODEC_CR50_HIZ_SL25 1
+#define AB8500_CODEC_CR50_HIZ_SL24 0
+
+/* CR51-CR0x0033 */
+#define AB8500_CODEC_CR51_DA12_VOICE 7
+#define AB8500_CODEC_CR51_SWAP_DA12_34 6
+#define AB8500_CODEC_CR51_SLDAI7TOSLADO1 5
+#define AB8500_CODEC_CR51_SLTODA1 0
+
+/* CR52-CR0x0034 */
+#define AB8500_CODEC_CR52_SLDAI8TOSLADO2 5
+#define AB8500_CODEC_CR52_SLTODA2 0
+
+/* CR53-CR0x0035 */
+#define AB8500_CODEC_CR53_DA34_VOICE 7
+#define AB8500_CODEC_CR53_SLDAI7TOSLADO3 5
+#define AB8500_CODEC_CR53_SLTODA3 0
+
+/* CR54-CR0x0036 */
+#define AB8500_CODEC_CR54_SLDAI8TOSLADO4 5
+#define AB8500_CODEC_CR54_SLTODA4 0
+
+/* CR55-CR0x0037 */
+#define AB8500_CODEC_CR55_DA56_VOICE 7
+#define AB8500_CODEC_CR55_SLDAI7TOSLADO5 5
+#define AB8500_CODEC_CR55_SLTODA5 0
+
+/* CR56-CR0x0038 */
+#define AB8500_CODEC_CR56_SLDAI8TOSLADO6 5
+#define AB8500_CODEC_CR56_SLTODA6 0
+
+/* CR57-CR0x0039 */
+#define AB8500_CODEC_CR57_SLDAI8TOSLADO7 5
+#define AB8500_CODEC_CR57_SLTODA7 0
+
+/* CR58-CR0x003A */
+#define AB8500_CODEC_CR58_SLDAI7TOSLADO8 5
+#define AB8500_CODEC_CR58_SLTODA8 0
+
+/* CR59-CR0x003B */
+#define AB8500_CODEC_CR59_PARLHF 7
+#define AB8500_CODEC_CR59_PARLVIB 6
+#define AB8500_CODEC_CR59_CLASSDVIB1SWAPEN 3
+#define AB8500_CODEC_CR59_CLASSDVIB2SWAPEN 2
+#define AB8500_CODEC_CR59_CLASSDHFLSWAPEN 1
+#define AB8500_CODEC_CR59_CLASSDHFRSWAPEN 0
+
+/* CR60-CR0x003C */
+#define AB8500_CODEC_CR60_CLASSD_FIR_BYP 4
+#define AB8500_CODEC_CR60_CLASSD_HIGHVOL_EN 0
+
+/* CR61-CR0x003D */
+#define AB8500_CODEC_CR61_CLASSD_DITH_HPGAIN 4
+#define AB8500_CODEC_CR61_CLASSD_DITH_WGAIN 0
+
+/* CR62-CR0x003E */
+#define AB8500_CODEC_CR62_DMIC1SINC3 5
+#define AB8500_CODEC_CR62_DMIC2SINC3 4
+#define AB8500_CODEC_CR62_DMIC3SINC3 3
+#define AB8500_CODEC_CR62_DMIC4SINC3 2
+#define AB8500_CODEC_CR62_DMIC5SINC3 1
+#define AB8500_CODEC_CR62_DMIC6SINC3 0
+
+/* CR63-CR0x003F */
+#define AB8500_CODEC_CR63_DATOHSLEN 7
+#define AB8500_CODEC_CR63_DATOHSREN 6
+#define AB8500_CODEC_CR63_AD1SEL 5
+#define AB8500_CODEC_CR63_AD2SEL 4
+#define AB8500_CODEC_CR63_AD3SEL 3
+#define AB8500_CODEC_CR63_AD5SEL 2
+#define AB8500_CODEC_CR63_AD6SEL 1
+#define AB8500_CODEC_CR63_ANCSEL 0
+
+/* CR64-CR0x0040 */
+#define AB8500_CODEC_CR64_DATOHFREN 7
+#define AB8500_CODEC_CR64_DATOHFLEN 6
+#define AB8500_CODEC_CR64_HFRSEL 5
+#define AB8500_CODEC_CR64_HFLSEL 4
+#define AB8500_CODEC_CR64_STFIR1SEL 2
+#define AB8500_CODEC_CR64_STFIR2SEL 0
+
+/* CR65-CR0x0041 */
+#define AB8500_CODEC_CR65_FADEDIS_AD1 6
+#define AB8500_CODEC_CR65_AD1GAIN 0
+
+/* CR66-CR0x0042 */
+#define AB8500_CODEC_CR66_FADEDIS_AD2 6
+#define AB8500_CODEC_CR66_AD2GAIN 0
+
+/* CR67-CR0x0043 */
+#define AB8500_CODEC_CR67_FADEDIS_AD3 6
+#define AB8500_CODEC_CR67_AD3GAIN 0
+
+/* CR68-CR0x0044 */
+#define AB8500_CODEC_CR68_FADEDIS_AD4 6
+#define AB8500_CODEC_CR68_AD4GAIN 0
+
+/* CR69-CR0x0045 */
+#define AB8500_CODEC_CR69_FADEDIS_AD5 6
+#define AB8500_CODEC_CR69_AD5GAIN 0
+
+/* CR70-CR0x0046 */
+#define AB8500_CODEC_CR70_FADEDIS_AD6 6
+#define AB8500_CODEC_CR70_AD6GAIN 0
+
+/* CR71-CR0x0047 */
+#define AB8500_CODEC_CR71_FADEDIS_DA1 6
+#define AB8500_CODEC_CR71_DA1GAIN 0
+
+/* CR72-CR0x0048 */
+#define AB8500_CODEC_CR72_FADEDIS_DA2 6
+#define AB8500_CODEC_CR72_DA2GAIN 0
+
+/* CR73-CR0x0049 */
+#define AB8500_CODEC_CR73_FADEDIS_DA3 6
+#define AB8500_CODEC_CR73_DA3GAIN 0
+
+/* CR74-CR0x004A */
+#define AB8500_CODEC_CR74_FADEDIS_DA4 6
+#define AB8500_CODEC_CR74_DA4GAIN 0
+
+/* CR75-CR0x004B */
+#define AB8500_CODEC_CR75_FADEDIS_DA5 6
+#define AB8500_CODEC_CR75_DA5GAIN 0
+
+/* CR76-CR0x004C */
+#define AB8500_CODEC_CR76_FADEDIS_DA6 6
+#define AB8500_CODEC_CR76_DA6GAIN 0
+
+/* CR77-CR0x004D */
+#define AB8500_CODEC_CR77_FADEDIS_AD1L 6
+#define AB8500_CODEC_CR77_AD1LBGAIN 0
+
+/* CR78-CR0x004E */
+#define AB8500_CODEC_CR78_FADEDIS_AD2L 6
+#define AB8500_CODEC_CR78_AD2LBGAIN 0
+
+/* CR79-CR0x004F */
+#define AB8500_CODEC_CR79_HSSINC1 7
+#define AB8500_CODEC_CR79_FADEDIS_HSL 4
+#define AB8500_CODEC_CR79_HSLDGAIN 0
+
+/* CR80-CR0x0050 */
+#define AB8500_CODEC_CR80_FADE_SPEED 6
+#define AB8500_CODEC_CR80_FADEDIS_HSR 4
+#define AB8500_CODEC_CR80_HSRDGAIN 0
+
+/* CR81-CR0x0051 */
+#define AB8500_CODEC_CR81_STFIR1GAIN 0
+
+/* CR82-CR0x0052 */
+#define AB8500_CODEC_CR82_STFIR2GAIN 0
+
+/* CR83-CR0x0053 */
+#define AB8500_CODEC_CR83_ENANC 2
+#define AB8500_CODEC_CR83_ANCIIRINIT 1
+#define AB8500_CODEC_CR83_ANCFIRUPDATE 0
+
+/* CR84-CR0x0054 */
+#define AB8500_CODEC_CR84_ANCINSHIFT 0
+
+/* CR85-CR0x0055 */
+#define AB8500_CODEC_CR85_ANCFIROUTSHIFT 0
+
+/* CR86-CR0x0056 */
+#define AB8500_CODEC_CR86_ANCSHIFTOUT 0
+
+/* CR87-CR0x0057 */
+#define AB8500_CODEC_CR87_ANCFIRCOEFF_MSB 0
+
+/* CR88-CR0x0058 */
+#define AB8500_CODEC_CR88_ANCFIRCOEFF_LSB 0
+
+/* CR89-CR0x0059 */
+#define AB8500_CODEC_CR89_ANCIIRCOEFF_MSB 0
+
+/* CR90-CR0x005A */
+#define AB8500_CODEC_CR90_ANCIIRCOEFF_LSB 0
+
+/* CR91-CR0x005B */
+#define AB8500_CODEC_CR91_ANCWARPDEL_MSB 0
+
+/* CR92-CR0x005C */
+#define AB8500_CODEC_CR92_ANCWARPDEL_LSB 0
+
+/* CR93-CR0x005D */
+#define AB8500_CODEC_CR93_ANCFIRPEAK_MSB 0
+
+/* CR94-CR0x005E */
+#define AB8500_CODEC_CR94_ANCFIRPEAK_LSB 0
+
+/* CR95-CR0x005F */
+#define AB8500_CODEC_CR95_ANCIIRPEAK_MSB 0
+
+/* CR96-CR0x0060 */
+#define AB8500_CODEC_CR96_ANCIIRPEAK_LSB 0
+
+/* CR97-CR0x0061 */
+#define AB8500_CODEC_CR97_STFIR_SET 7
+#define AB8500_CODEC_CR97_STFIR_ADDR 0
+
+/* CR98-CR0x0062 */
+#define AB8500_CODEC_CR98_STFIR_COEFF_MSB 0
+
+/* CR99-CR0x0063 */
+#define AB8500_CODEC_CR99_STFIR_COEFF_LSB 0
+
+/* CR100-CR0x0064 */
+#define AB8500_CODEC_CR100_ENSTFIRS 2
+#define AB8500_CODEC_CR100_STFIRSTOIF1 1
+#define AB8500_CODEC_CR100_STFIR_BUSY 0
+
+/* CR101-CR0x0065 */
+#define AB8500_CODEC_CR101_HSOFFSTMASK 7
+#define AB8500_CODEC_CR101_FIFOFULLMASK 6
+#define AB8500_CODEC_CR101_FIFOEMPTYMASK 5
+#define AB8500_CODEC_CR101_DASATMASK 4
+#define AB8500_CODEC_CR101_ADSATMASK 3
+#define AB8500_CODEC_CR101_ADDSPMASK 2
+#define AB8500_CODEC_CR101_DADSPMASK 1
+#define AB8500_CODEC_CR101_FIRSIDMASK 0
+
+/* CR102-CR0x0066 */
+#define AB8500_CODEC_CR102_IT_HSOFFST 7
+#define AB8500_CODEC_CR102_IT_FIFOFULL 6
+#define AB8500_CODEC_CR102_IT_FIFOEMPTY 5
+#define AB8500_CODEC_CR102_IT_DASAT 4
+#define AB8500_CODEC_CR102_IT_ADSAT 3
+#define AB8500_CODEC_CR102_IT_ADDSP 2
+#define AB8500_CODEC_CR102_IT_DADSP 1
+#define AB8500_CODEC_CR102_IT_FIRSID 0
+
+/* CR103-CR0x0067 */
+#define AB8500_CODEC_CR103_VSSREADYMASK 7
+#define AB8500_CODEC_CR103_SHORTHSLMASK 2
+#define AB8500_CODEC_CR103_SHORTHSRMASK 1
+#define AB8500_CODEC_CR103_SHORTEARMASK 0
+
+/* CR104-CR0x0068 */
+#define AB8500_CODEC_CR104_IT_VSSREADY 7
+#define AB8500_CODEC_CR104_IT_SHORTHSL 2
+#define AB8500_CODEC_CR104_IT_SHORTHSR 1
+#define AB8500_CODEC_CR104_IT_SHORTEAR 0
+
+/* CR105-CR0x0069 */
+#define AB8500_CODEC_CR105_BFIFOMASK 7
+#define AB8500_CODEC_CR105_BFIFOINT 0
+
+/* CR106-CR0x006A */
+#define AB8500_CODEC_CR106_BFIFOTX 0
+
+/* CR107-CR0x006B */
+#define AB8500_CODEC_CR107_BFIFOEXSL 5
+#define AB8500_CODEC_CR107_PREBITCLK0 2
+#define AB8500_CODEC_CR107_BFIFOMAST 1
+#define AB8500_CODEC_CR107_BFIFORUN 0
+
+/* CR108-CR0x006C */
+#define AB8500_CODEC_CR108_BFIFOFRAMESW 0
+
+/* CR109-CR0x006D */
+#define AB8500_CODEC_CR109_BFIFOWAKEUP 0
+
+/* CR110-CR0x006E */
+#define AB8500_CODEC_CR110_BFIFOSAMPLE 0
+
+/* CR111-CR0x006F */
+#define AB8500_CODEC_CR111_AUD_IP_REV 0
+
+/* For SetVolume API*/
+#define AB8500_CODEC_MAX_VOLUME 100
+
+/* Analog MIC1 & MIC2 */
+#define AB8500_CODEC_MIC_VOLUME_MAX 31
+#define AB8500_CODEC_MIC_VOLUME_MEDIUM 15
+#define AB8500_CODEC_MIC_VOLUME_MIN 0
+
+/* Line-in */
+#define AB8500_CODEC_LINEIN_VOLUME_MAX 15
+#define AB8500_CODEC_LINEIN_VOLUME_MEDIUM 7
+#define AB8500_CODEC_LINEIN_VOLUME_MIN 0
+
+/* HeadSet */
+#define AB8500_CODEC_HEADSET_VOLUME_MAX 13
+#define AB8500_CODEC_HEADSET_VOLUME_MEDIUM 6
+#define AB8500_CODEC_HEADSET_VOLUME_MIN 0
+
+/* HeadSet Digital */
+#define AB8500_CODEC_HEADSET_D_VOLUME_MAX 0
+#define AB8500_CODEC_HEADSET_D_VOLUME_MEDIUM 7
+#define AB8500_CODEC_HEADSET_D_VOLUME_MIN 15
+#define AB8500_CODEC_HEADSET_D_VOLUME_0DB 8
+
+/* Digital AD Path */
+#define AB8500_CODEC_AD_D_VOLUME_MAX 0
+#define AB8500_CODEC_AD_D_VOLUME_MEDIUM 31
+#define AB8500_CODEC_AD_D_VOLUME_MIN 63
+
+/* Digital DA Path */
+#define AB8500_CODEC_DA_D_VOLUME_MAX 0
+#define AB8500_CODEC_DA_D_VOLUME_MEDIUM 31
+#define AB8500_CODEC_DA_D_VOLUME_MIN 63
+
+/* EarPiece Digital */
+#define AB8500_CODEC_EARPIECE_D_VOLUME_MAX 0
+#define AB8500_CODEC_EARPIECE_D_VOLUME_MEDIUM 7
+#define AB8500_CODEC_EARPIECE_D_VOLUME_MIN 15
+
+/* AD1 loopback to HFL & HFR Digital */
+#define AB8500_CODEC_AD_LB_TO_HF_L_R_VOLUME_MAX 0
+#define AB8500_CODEC_AD_LB_TO_HF_L_R_VOLUME_MEDIUM 31
+#define AB8500_CODEC_AD_LB_TO_HF_L_R_VOLUME_MIN 63
+
+/* Line-in to HSL & HSR */
+#define AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MAX 0
+#define AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MEDIUM 9
+#define AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN 18
+#define AB8500_CODEC_LINEIN_TO_HS_L_R_LOOP_OPEN 19
+
+/* Vibrator */
+#define AB8500_CODEC_VIBRATOR_VOLUME_MAX 100
+#define AB8500_CODEC_VIBRATOR_VOLUME_MEDIUM 50
+#define AB8500_CODEC_VIBRATOR_VOLUME_MIN 0
+
+/* CR0 - 7 */
+typedef enum {
+ AB8500_CODEC_CR0_POWERUP_OFF,
+ AB8500_CODEC_CR0_POWERUP_ON
+} t_ab8500_codec_cr0_powerup;
+
+/* CR0 - 3 */
+typedef enum {
+ AB8500_CODEC_CR0_ENAANA_OFF,
+ AB8500_CODEC_CR0_ENAANA_ON
+} t_ab8500_codec_cr0_enaana;
+
+/* CR1 - 7 */
+typedef enum {
+ AB8500_CODEC_CR1_SWRESET_DISABLED,
+ AB8500_CODEC_CR1_SWRESET_ENABLED
+} t_ab8500_codec_cr1_swreset;
+
+/* CR2 - 7 */
+typedef enum {
+ AB8500_CODEC_CR2_ENAD1_DISABLED,
+ AB8500_CODEC_CR2_ENAD1_ENABLED
+} t_ab8500_codec_cr2_enad1;
+
+/* CR2 - 6 */
+typedef enum {
+ AB8500_CODEC_CR2_ENAD2_DISABLED,
+ AB8500_CODEC_CR2_ENAD2_ENABLED
+} t_ab8500_codec_cr2_enad2;
+
+/* CR2 - 5 */
+typedef enum {
+ AB8500_CODEC_CR2_ENAD3_DISABLED,
+ AB8500_CODEC_CR2_ENAD3_ENABLED
+} t_ab8500_codec_cr2_enad3;
+
+/* CR2 - 4 */
+typedef enum {
+ AB8500_CODEC_CR2_ENAD4_DISABLED,
+ AB8500_CODEC_CR2_ENAD4_ENABLED
+} t_ab8500_codec_cr2_enad4;
+
+/* CR2 - 3 */
+typedef enum {
+ AB8500_CODEC_CR2_ENAD5_DISABLED,
+ AB8500_CODEC_CR2_ENAD5_ENABLED
+} t_ab8500_codec_cr2_enad5;
+
+/* CR2 - 2 */
+typedef enum {
+ AB8500_CODEC_CR2_ENAD6_DISABLED,
+ AB8500_CODEC_CR2_ENAD6_ENABLED
+} t_ab8500_codec_cr2_enad6;
+
+/* CR3 - 7 */
+typedef enum {
+ AB8500_CODEC_CR3_ENDA1_DISABLED,
+ AB8500_CODEC_CR3_ENDA1_ENABLED
+} t_ab8500_codec_cr3_enda1;
+
+/* CR3 - 6 */
+typedef enum {
+ AB8500_CODEC_CR3_ENDA2_DISABLED,
+ AB8500_CODEC_CR3_ENDA2_ENABLED
+} t_ab8500_codec_cr3_enda2;
+
+/* CR3 - 5 */
+typedef enum {
+ AB8500_CODEC_CR3_ENDA3_DISABLED,
+ AB8500_CODEC_CR3_ENDA3_ENABLED
+} t_ab8500_codec_cr3_enda3;
+
+/* CR3 - 4 */
+typedef enum {
+ AB8500_CODEC_CR3_ENDA4_DISABLED,
+ AB8500_CODEC_CR3_ENDA4_ENABLED
+} t_ab8500_codec_cr3_enda4;
+
+/* CR3 - 3 */
+typedef enum {
+ AB8500_CODEC_CR3_ENDA5_DISABLED,
+ AB8500_CODEC_CR3_ENDA5_ENABLED
+} t_ab8500_codec_cr3_enda5;
+
+/* CR3 - 2 */
+typedef enum {
+ AB8500_CODEC_CR3_ENDA6_DISABLED,
+ AB8500_CODEC_CR3_ENDA6_ENABLED
+} t_ab8500_codec_cr3_enda6;
+
+/* CR4 - 7 */
+typedef enum {
+ AB8500_CODEC_CR4_LOWPOWHS_NORMAL,
+ AB8500_CODEC_CR4_LOWPOWHS_LP
+} t_ab8500_codec_cr4_lowpowhs;
+
+/* CR4 - 6:5 */
+typedef enum {
+ AB8500_CODEC_CR4_LOWPOWDACHS_NORMAL,
+ AB8500_CODEC_CR4_LOWPOWDACHS_DRIVERS_LP,
+ AB8500_CODEC_CR4_LOWPOWDACHS_LP,
+ AB8500_CODEC_CR4_LOWPOWDACHS_BOTH_LP
+} t_ab8500_codec_cr4_lowpowdachs;
+
+/* CR4 - 4 */
+typedef enum {
+ AB8500_CODEC_CR4_LOWPOWEAR_NORMAL,
+ AB8500_CODEC_CR4_LOWPOWEAR_LP
+} t_ab8500_codec_cr4_lowpowear;
+
+/* CR4 - 3:2 */
+typedef enum {
+ AB8500_CODEC_CR4_EAR_SEL_CM_0_95V,
+ AB8500_CODEC_CR4_EAR_SEL_CM_1_1V,
+ AB8500_CODEC_CR4_EAR_SEL_CM_1_27V,
+ AB8500_CODEC_CR4_EAR_SEL_CM_1_58V
+} t_ab8500_codec_cr4_ear_sel_cm;
+
+/* CR4 - 1 */
+typedef enum {
+ AB8500_CODEC_CR4_HS_HP_EN_FILTER_DISABLED,
+ AB8500_CODEC_CR4_HS_HP_EN_FILTER_ENABLED
+} t_ab8500_codec_cr4_hs_hp_en;
+
+/* CR5 - 7 */
+typedef enum {
+ AB8500_CODEC_CR5_ENMIC1_DISABLED,
+ AB8500_CODEC_CR5_ENMIC1_ENABLED
+} t_ab8500_codec_cr5_enmic1;
+
+/* CR5 - 6 */
+typedef enum {
+ AB8500_CODEC_CR5_ENMIC2_DISABLED,
+ AB8500_CODEC_CR5_ENMIC2_ENABLED
+} t_ab8500_codec_cr5_enmic2;
+
+/* CR5 - 5 */
+typedef enum {
+ AB8500_CODEC_CR5_ENLINL_DISABLED,
+ AB8500_CODEC_CR5_ENLINL_ENABLED
+} t_ab8500_codec_cr5_enlinl;
+
+/* CR5 - 4 */
+typedef enum {
+ AB8500_CODEC_CR5_ENLINR_DISABLED,
+ AB8500_CODEC_CR5_ENLINR_ENABLED
+} t_ab8500_codec_cr5_enlinr;
+
+/* CR5 - 3 */
+typedef enum {
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED,
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED
+} t_ab8500_codec_cr5_mutmic1;
+
+/* CR5 - 2 */
+typedef enum {
+ AB8500_CODEC_CR5_MUTMIC2_DISABLED,
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED
+} t_ab8500_codec_cr5_mutmic2;
+
+/* CR5 - 1 */
+typedef enum {
+ AB8500_CODEC_CR5_MUTLINL_DISABLED,
+ AB8500_CODEC_CR5_MUTLINL_ENABLED
+} t_ab8500_codec_cr5_mutlinl;
+
+/* CR5 - 0 */
+typedef enum {
+ AB8500_CODEC_CR5_MUTLINR_DISABLED,
+ AB8500_CODEC_CR5_MUTLINR_ENABLED
+} t_ab8500_codec_cr5_mutlinr;
+
+/* CR6 - 7 */
+typedef enum {
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED,
+ AB8500_CODEC_CR6_ENDMIC1_ENABLED
+} t_ab8500_codec_cr6_endmic1;
+
+/* CR6 - 6 */
+typedef enum {
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED,
+ AB8500_CODEC_CR6_ENDMIC2_ENABLED
+} t_ab8500_codec_cr6_endmic2;
+
+/* CR6 - 5 */
+typedef enum {
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED,
+ AB8500_CODEC_CR6_ENDMIC3_ENABLED
+} t_ab8500_codec_cr6_endmic3;
+
+/* CR6 - 4 */
+typedef enum {
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED,
+ AB8500_CODEC_CR6_ENDMIC4_ENABLED
+} t_ab8500_codec_cr6_endmic4;
+
+/* CR6 - 3 */
+typedef enum {
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED,
+ AB8500_CODEC_CR6_ENDMIC5_ENABLED
+} t_ab8500_codec_cr6_endmic5;
+
+/* CR6 - 2 */
+typedef enum {
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED,
+ AB8500_CODEC_CR6_ENDMIC6_ENABLED
+} t_ab8500_codec_cr6_endmic6;
+
+/* CR7 - 7 */
+typedef enum {
+ AB8500_CODEC_CR7_MIC1SEL_MIC1A,
+ AB8500_CODEC_CR7_MIC1SEL_MIC1B
+} t_ab8500_codec_cr7_mic1sel;
+
+/* CR7 - 6 */
+typedef enum {
+ AB8500_CODEC_CR7_LINRSEL_MIC2,
+ AB8500_CODEC_CR7_LINRSEL_LINR
+} t_ab8500_codec_cr7_linrsel;
+
+/* CR7 - 5 */
+typedef enum {
+ AB8500_CODEC_CR7_ENDRVHSL_DISABLED,
+ AB8500_CODEC_CR7_ENDRVHSL_ENABLED
+} t_ab8500_codec_cr7_endrvhsl;
+
+/* CR7 - 4 */
+typedef enum {
+ AB8500_CODEC_CR7_ENDRVHSR_DISABLED,
+ AB8500_CODEC_CR7_ENDRVHSR_ENABLED
+} t_ab8500_codec_cr7_endrvhsr;
+
+/* CR7 - 2 */
+typedef enum {
+ AB8500_CODEC_CR7_ENADCMIC_DISABLED,
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED
+} t_ab8500_codec_cr7_enadcmic;
+
+/* CR7 - 1 */
+typedef enum {
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED,
+ AB8500_CODEC_CR7_ENADCLINL_ENABLED
+} t_ab8500_codec_cr7_enadclinl;
+
+/* CR7 - 0 */
+typedef enum {
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED,
+ AB8500_CODEC_CR7_ENADCLINR_ENABLED
+} t_ab8500_codec_cr7_enadclinr;
+
+/* CR8 - 7 */
+typedef enum {
+ AB8500_CODEC_CR8_CP_DIS_PLDWN_ENABLED,
+ AB8500_CODEC_CR8_CP_DIS_PLDWN_DISABLED
+} t_ab8500_codec_cr8_cp_dis_pldwn;
+
+/* CR8 - 6 */
+typedef enum {
+ AB8500_CODEC_CR8_ENEAR_DISABLED,
+ AB8500_CODEC_CR8_ENEAR_ENABLED
+} t_ab8500_codec_cr8_enear;
+
+/* CR8 - 5 */
+typedef enum {
+ AB8500_CODEC_CR8_ENHSL_DISABLED,
+ AB8500_CODEC_CR8_ENHSL_ENABLED
+} t_ab8500_codec_cr8_enhsl;
+
+/* CR8 - 4 */
+typedef enum {
+ AB8500_CODEC_CR8_ENHSR_DISABLED,
+ AB8500_CODEC_CR8_ENHSR_ENABLED
+} t_ab8500_codec_cr8_enhsr;
+
+/* CR8 - 3 */
+typedef enum {
+ AB8500_CODEC_CR8_ENHFL_DISABLED,
+ AB8500_CODEC_CR8_ENHFL_ENABLED
+} t_ab8500_codec_cr8_enhfl;
+
+/* CR8 - 2 */
+typedef enum {
+ AB8500_CODEC_CR8_ENHFR_DISABLED,
+ AB8500_CODEC_CR8_ENHFR_ENABLED
+} t_ab8500_codec_cr8_enhfr;
+
+/* CR8 - 1 */
+typedef enum {
+ AB8500_CODEC_CR8_ENVIBL_DISABLED,
+ AB8500_CODEC_CR8_ENVIBL_ENABLED
+} t_ab8500_codec_cr8_envibl;
+
+/* CR8 - 0 */
+typedef enum {
+ AB8500_CODEC_CR8_ENVIBR_DISABLED,
+ AB8500_CODEC_CR8_ENVIBR_ENABLED
+} t_ab8500_codec_cr8_envibr;
+
+/* CR9 - 6 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACEAR_DISABLED,
+ AB8500_CODEC_CR9_ENDACEAR_ENABLED
+} t_ab8500_codec_cr9_endacear;
+
+/* CR9 - 5 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACHSL_DISABLED,
+ AB8500_CODEC_CR9_ENDACHSL_ENABLED
+} t_ab8500_codec_cr9_endachsl;
+
+/* CR9 - 4 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACHSR_DISABLED,
+ AB8500_CODEC_CR9_ENDACHSR_ENABLED
+} t_ab8500_codec_cr9_endachsr;
+
+/* CR9 - 3 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACHFL_DISABLED,
+ AB8500_CODEC_CR9_ENDACHFL_ENABLED
+} t_ab8500_codec_cr9_endachfl;
+
+/* CR9 - 2 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACHFR_DISABLED,
+ AB8500_CODEC_CR9_ENDACHFR_ENABLED
+} t_ab8500_codec_cr9_endachfr;
+
+/* CR9 - 1 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACVIBL_DISABLED,
+ AB8500_CODEC_CR9_ENDACVIBL_ENABLED
+} t_ab8500_codec_cr9_endacvibl;
+
+/* CR9 - 0 */
+typedef enum {
+ AB8500_CODEC_CR9_ENDACVIBR_DISABLED,
+ AB8500_CODEC_CR9_ENDACVIBR_ENABLED
+} t_ab8500_codec_cr9_endacvibr;
+
+/* CR10 - 6 */
+typedef enum {
+ AB8500_CODEC_CR10_MUTEEAR_DISABLED,
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED
+} t_ab8500_codec_cr10_muteear;
+
+/* CR10 - 5 */
+typedef enum {
+ AB8500_CODEC_CR10_MUTEHSL_DISABLED,
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED
+} t_ab8500_codec_cr10_mutehsl;
+
+/* CR10 - 4 */
+typedef enum {
+ AB8500_CODEC_CR10_MUTEHSR_DISABLED,
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED
+} t_ab8500_codec_cr10_mutehsr;
+
+/* CR11 - 7 */
+typedef enum {
+ AB8500_CODEC_CR11_ENSHORTPWD_DISABLED,
+ AB8500_CODEC_CR11_ENSHORTPWD_ENABLED
+} t_ab8500_codec_cr11_enshortpwd;
+
+/* CR11 - 6 */
+typedef enum {
+ AB8500_CODEC_CR11_EARSHORTDIS_ENABLED,
+ AB8500_CODEC_CR11_EARSHORTDIS_DISABLED
+} t_ab8500_codec_cr11_earshortdis;
+
+/* CR11 - 5 */
+typedef enum {
+ AB8500_CODEC_CR11_HSSHORTDIS_ENABLED,
+ AB8500_CODEC_CR11_HSSHORTDIS_DISABLED
+} t_ab8500_codec_cr11_hsshortdis;
+
+/* CR11 - 4 */
+typedef enum {
+ AB8500_CODEC_CR11_HSPULLDEN_HIGH,
+ AB8500_CODEC_CR11_HSPULLDEN_DOWN
+} t_ab8500_codec_cr11_hspullden;
+
+/* CR11 - 2 */
+typedef enum {
+ AB8500_CODEC_CR11_HSOSCEN_SYSTEMCLOCK,
+ AB8500_CODEC_CR11_HSOSCEN_LOCALOSC
+} t_ab8500_codec_cr11_hsoscen;
+
+/* CR11 - 1 */
+typedef enum {
+ AB8500_CODEC_CR11_HSFADEN_FADING,
+ AB8500_CODEC_CR11_HSFADEN_IMMEDIATELY
+} t_ab8500_codec_cr11_hsfaden;
+
+/* CR11 - 0 */
+typedef enum {
+ AB8500_CODEC_CR11_HSZCDDIS_ONZEROCROSS,
+ AB8500_CODEC_CR11_HSZCDDIS_WITHOUTZEROCROSS
+} t_ab8500_codec_cr11_hszcddis;
+
+/* CR12 - 7 */
+typedef enum {
+ AB8500_CODEC_CR12_ENCPHS_DISABLED,
+ AB8500_CODEC_CR12_ENCPHS_ENABLED
+} t_ab8500_codec_cr12_encphs;
+
+/* CR12 - 0 */
+typedef enum {
+ AB8500_CODEC_CR12_HSAUTOEN_DISABLED,
+ AB8500_CODEC_CR12_HSAUTOEN_ENABLED
+} t_ab8500_codec_cr12_hsautoen;
+
+/* CR13 - 7:4 */
+typedef enum {
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_25,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_50,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_100,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_150,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_200,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_250,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_300,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_350,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_400,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_450,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_500,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_550,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_600,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_650,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_700,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH_750
+} t_ab8500_codec_cr13_envdet_hthresh;
+
+/* CR13 - 3:0 */
+typedef enum {
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_25,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_50,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_100,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_150,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_200,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_250,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_300,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_350,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_400,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_450,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_500,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_550,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_600,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_650,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_700,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH_750
+} t_ab8500_codec_cr13_envdet_lthresh;
+
+/* CR14 - 7 */
+typedef enum {
+ AB8500_CODEC_CR14_SMPSLVEN_HIGHVOLTAGE,
+ AB8500_CODEC_CR14_SMPSLVEN_LOWVOLTAGE
+} t_ab8500_codec_cr14_smpslven;
+
+/* CR14 - 6 */
+typedef enum {
+ AB8500_CODEC_CR14_ENVDETSMPSEN_DISABLED,
+ AB8500_CODEC_CR14_ENVDETSMPSEN_ENABLED
+} t_ab8500_codec_cr14_envdetsmpsen;
+
+/* CR14 - 5 */
+typedef enum {
+ AB8500_CODEC_CR14_CPLVEN_HIGHVOLTAGE,
+ AB8500_CODEC_CR14_CPLVEN_LOWVOLTAGE
+} t_ab8500_codec_cr14_cplven;
+
+/* CR14 - 4 */
+typedef enum {
+ AB8500_CODEC_CR14_ENVDETCPEN_DISABLED,
+ AB8500_CODEC_CR14_ENVDETCPEN_ENABLED
+} t_ab8500_codec_cr14_envdetcpen;
+
+/* CR14 - 3:0 */
+typedef enum {
+ AB8500_CODEC_CR14_ENVET_TIME_27USEC,
+ AB8500_CODEC_CR14_ENVET_TIME_53USEC,
+ AB8500_CODEC_CR14_ENVET_TIME_106USEC,
+ AB8500_CODEC_CR14_ENVET_TIME_212USEC,
+ AB8500_CODEC_CR14_ENVET_TIME_424USEC,
+ AB8500_CODEC_CR14_ENVET_TIME_848USEC,
+ AB8500_CODEC_CR14_ENVET_TIME_1MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_3MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_6MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_13MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_27MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_54MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_109MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_218MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_436MSEC,
+ AB8500_CODEC_CR14_ENVET_TIME_872MSEC,
+} t_ab8500_codec_cr14_envet_time;
+
+/* CR15 - 7 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMTOVIBL_DA_PATH,
+ AB8500_CODEC_CR15_PWMTOVIBL_PWM
+} t_ab8500_codec_cr15_pwmtovibl;
+
+/* CR15 - 6 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMTOVIBR_DA_PATH,
+ AB8500_CODEC_CR15_PWMTOVIBR_PWM
+} t_ab8500_codec_cr15_pwmtovibr;
+
+/* CR15 - 5 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLGPOL,
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE
+} t_ab8500_codec_cr15_pwmlctrl;
+
+/* CR15 - 4 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRGPOL,
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE
+} t_ab8500_codec_cr15_pwmrctrl;
+
+/* CR15 - 3 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLGPOL,
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE
+} t_ab8500_codec_cr15_pwmnlctrl;
+
+/* CR15 - 2 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLGPOL,
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE
+} t_ab8500_codec_cr15_pwmplctrl;
+
+/* CR15 - 1 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRGPOL,
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE
+} t_ab8500_codec_cr15_pwmnrctrl;
+
+/* CR15 - 0 */
+typedef enum {
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRGPOL,
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE
+} t_ab8500_codec_cr15_pwmprctrl;
+
+/* CR16 - 7 */
+typedef enum {
+ AB8500_CODEC_CR16_PWMNLPOL_GNDVIB,
+ AB8500_CODEC_CR16_PWMNLPOL_VINVIB
+} t_ab8500_codec_cr16_pwmnlpol;
+
+/* CR16 - 6:0 */
+typedef t_uint8 t_ab8500_codec_cr16_pwmnldutycycle;
+
+/* CR17 - 7 */
+typedef enum {
+ AB8500_CODEC_CR17_PWMPLPOL_GNDVIB,
+ AB8500_CODEC_CR17_PWMPLPOL_VINVIB
+} t_ab8500_codec_cr17_pwmplpol;
+
+/* CR17 - 6:0 */
+typedef t_uint8 t_ab8500_codec_cr17_pwmpldutycycle;
+
+/* CR18 - 7 */
+typedef enum {
+ AB8500_CODEC_CR18_PWMNRPOL_GNDVIB,
+ AB8500_CODEC_CR18_PWMNRPOL_VINVIB
+} t_ab8500_codec_cr18_pwmnrpol;
+
+/* CR18 - 6:0 */
+typedef t_uint8 t_ab8500_codec_cr18_pwmnrdutycycle;
+
+/* CR19 - 7 */
+typedef enum {
+ AB8500_CODEC_CR19_PWMPRPOL_GNDVIB,
+ AB8500_CODEC_CR19_PWMPRPOL_VINVIB
+} t_ab8500_codec_cr19_pwmprpol;
+
+/* CR19 - 6:0 */
+typedef t_uint8 t_ab8500_codec_cr19_pwmprdutycycle;
+
+/* CR20 - 7 */
+typedef enum {
+ AB8500_CODEC_CR20_EN_SE_MIC1_DIFFERENTIAL,
+ AB8500_CODEC_CR20_EN_SE_MIC1_SINGLE
+} t_ab8500_codec_cr20_en_se_mic1;
+
+/* CR20 - 6 */
+typedef enum {
+ AB8500_CODEC_CR20_LOW_POW_MIC1_NORMAL,
+ AB8500_CODEC_CR20_LOW_POW_MIC1_LOW_POWER
+} t_ab8500_codec_cr20_low_pow_mic1;
+
+/* CR20 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr20_mic1_gain;
+
+/* CR21 - 7 */
+typedef enum {
+ AB8500_CODEC_CR21_EN_SE_MIC2_DIFFERENTIAL,
+ AB8500_CODEC_CR21_EN_SE_MIC2_SINGLE
+} t_ab8500_codec_cr21_en_se_mic2;
+
+/* CR21 - 6 */
+typedef enum {
+ AB8500_CODEC_CR21_LOW_POW_MIC2_NORMAL,
+ AB8500_CODEC_CR21_LOW_POW_MIC2_LOW_POWER
+} t_ab8500_codec_cr21_low_pow_mic2;
+
+/* CR21 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr21_mic2_gain;
+
+/* CR22 - 7:4 */
+typedef t_uint8 t_ab8500_codec_cr22_hsl_gain;
+
+/* CR22 - 3:0 */
+typedef t_uint8 t_ab8500_codec_cr22_hsr_gain;
+
+/* CR23 - 7:4 */
+typedef t_uint8 t_ab8500_codec_cr23_linl_gain;
+
+/* CR23 - 3:0 */
+typedef t_uint8 t_ab8500_codec_cr23_linr_gain;
+
+/* CR24 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr24_lintohsl_gain;
+
+/* CR25 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr25_lintohsr_gain;
+
+/* CR26 - 7 */
+typedef enum {
+ AB8500_CODEC_CR26_AD1NH_FILTER_ENABLED,
+ AB8500_CODEC_CR26_AD1NH_FILTER_DISABLED
+} t_ab8500_codec_cr26_ad1nh;
+
+/* CR26 - 6 */
+typedef enum {
+ AB8500_CODEC_CR26_AD2NH_FILTER_ENABLED,
+ AB8500_CODEC_CR26_AD2NH_FILTER_DISABLED
+} t_ab8500_codec_cr26_ad2nh;
+
+/* CR26 - 5 */
+typedef enum {
+ AB8500_CODEC_CR26_AD3NH_FILTER_ENABLED,
+ AB8500_CODEC_CR26_AD3NH_FILTER_DISABLED
+} t_ab8500_codec_cr26_ad3nh;
+
+/* CR26 - 4 */
+typedef enum {
+ AB8500_CODEC_CR26_AD4NH_FILTER_ENABLED,
+ AB8500_CODEC_CR26_AD4NH_FILTER_DISABLED
+} t_ab8500_codec_cr26_ad4nh;
+
+/* CR26 - 3 */
+typedef enum {
+ AB8500_CODEC_CR26_AD1_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR26_AD1_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr26_ad1_voice;
+
+/* CR26 - 2 */
+typedef enum {
+ AB8500_CODEC_CR26_AD2_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR26_AD2_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr26_ad2_voice;
+
+/* CR26 - 1 */
+typedef enum {
+ AB8500_CODEC_CR26_AD3_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR26_AD3_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr26_ad3_voice;
+
+/* CR26 - 0 */
+typedef enum {
+ AB8500_CODEC_CR26_AD4_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR26_AD4_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr26_ad4_voice;
+
+/* CR27 - 7 */
+typedef enum {
+ AB8500_CODEC_CR27_EN_MASTGEN_DISABLED,
+ AB8500_CODEC_CR27_EN_MASTGEN_ENABLED
+} t_ab8500_codec_cr27_en_mastgen;
+
+/* CR27 - 6:5 */
+/* In ab8500_codec.h */
+
+/* CR27 - 4 */
+typedef enum {
+ AB8500_CODEC_CR27_ENFS_BITCLK1_DISABLED,
+ AB8500_CODEC_CR27_ENFS_BITCLK1_ENABLED
+} t_ab8500_codec_cr27_enfs_bitclk1;
+
+/* CR27 - 2:1 */
+/* In ab8500_codec.h */
+
+/* CR27 - 0 */
+typedef enum {
+ AB8500_CODEC_CR27_ENFS_BITCLK0_DISABLED,
+ AB8500_CODEC_CR27_ENFS_BITCLK0_ENABLED
+} t_ab8500_codec_cr27_enfs_bitclk0;
+
+/* CR28 - 6 */
+typedef enum {
+ AB8500_CODEC_CR28_FSYNC0P_RISING_EDGE,
+ AB8500_CODEC_CR28_FSYNC0P_FALLING_EDGE
+} t_ab8500_codec_cr28_fsync0p;
+
+/* CR28 - 5 */
+typedef enum {
+ AB8500_CODEC_CR28_BITCLK0P_RISING_EDGE,
+ AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE
+} t_ab8500_codec_cr28_bitclk0p;
+
+/* CR28 - 4 */
+typedef enum {
+ AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED,
+ AB8500_CODEC_CR28_IF0DEL_DELAYED
+} t_ab8500_codec_cr28_if0del;
+
+/* CR28 - 3:2 */
+typedef enum {
+ AB8500_CODEC_CR28_IF0FORMAT_DISABLED,
+ AB8500_CODEC_CR28_IF0FORMAT_TDM,
+ AB8500_CODEC_CR28_IF0FORMAT_I2S_LEFTALIGNED
+} t_ab8500_codec_cr28_if0format;
+
+/* CR28 - 1:0 */
+/* In ab8500_codec.h */
+
+/* CR29 - 7 */
+typedef enum {
+ AB8500_CODEC_CR29_IF0DATOIF1AD_NOTSENT,
+ AB8500_CODEC_CR29_IF0DATOIF1AD_SENT
+} t_ab8500_codec_cr29_if0datoif1ad;
+
+/* CR29 - 6 */
+typedef enum {
+ AB8500_CODEC_CR29_IF0CKTOIF1CK_NOTSENT,
+ AB8500_CODEC_CR29_IF0CKTOIF1CK_SENT
+} t_ab8500_codec_cr29_if0cktoif1ck;
+
+/* CR29 - 5 */
+typedef enum {
+ AB8500_CODEC_CR29_IF1MASTER_FS1CK1_INPUT,
+ AB8500_CODEC_CR29_IF1MASTER_FS1CK1_OUTPUT
+} t_ab8500_codec_cr29_if1master;
+
+/* CR29 - 3 */
+typedef enum {
+ AB8500_CODEC_CR29_IF1DATOIF0AD_NOTSENT,
+ AB8500_CODEC_CR29_IF1DATOIF0AD_SENT
+} t_ab8500_codec_cr29_if1datoif0ad;
+
+/* CR29 - 2 */
+typedef enum {
+ AB8500_CODEC_CR29_IF1CKTOIF0CK_NOTSENT,
+ AB8500_CODEC_CR29_IF1CKTOIF0CK_SENT
+} t_ab8500_codec_cr29_if1cktoif0ck;
+
+/* CR29 - 1 */
+typedef enum {
+ AB8500_CODEC_CR29_IF0MASTER_FS0CK0_INPUT,
+ AB8500_CODEC_CR29_IF0MASTER_FS0CK0_OUTPUT
+} t_ab8500_codec_cr29_if0master;
+
+/* CR29 - 0 */
+typedef enum {
+ AB8500_CODEC_CR29_IF0BFIFOEN_NORMAL_MODE,
+ AB8500_CODEC_CR29_IF0BFIFOEN_BURST_MODE
+} t_ab8500_codec_cr29_if0bfifoen;
+
+/* CR30 - 6 */
+typedef enum {
+ AB8500_CODEC_CR30_FSYNC1P_RISING_EDGE,
+ AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE
+} t_ab8500_codec_cr30_fsync1p;
+
+/* CR30 - 5 */
+typedef enum {
+ AB8500_CODEC_CR30_BITCLK1P_RISING_EDGE,
+ AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE
+} t_ab8500_codec_cr30_bitclk1p;
+
+/* CR30 - 4 */
+typedef enum {
+ AB8500_CODEC_CR30_IF1DEL_NOT_DELAYED,
+ AB8500_CODEC_CR30_IF1DEL_DELAYED
+} t_ab8500_codec_cr30_if1del;
+
+/* CR30 - 3:2 */
+typedef enum {
+ AB8500_CODEC_CR30_IF1FORMAT_DISABLED,
+ AB8500_CODEC_CR30_IF1FORMAT_TDM,
+ AB8500_CODEC_CR30_IF1FORMAT_I2S_LEFTALIGNED
+} t_ab8500_codec_cr30_if1format;
+
+/* CR30 - 1:0 */
+/* In ab8500_codec.h */
+
+/* CR31:46 - 7:4 or 3:0 */
+/* In ab8500_codec.h */
+
+/* CR47:50 - 7/6/5/4/3/2/1/0 */
+typedef enum {
+ AB8500_CODEC_CR47_TO_CR50_HIZ_SL_LOW_IMPEDANCE,
+ AB8500_CODEC_CR47_TO_CR50_HIZ_SL_HIGH_IMPEDANCE,
+} t_ab8500_codec_cr47_to_cr50_hiz_sl;
+
+/* CR51 - 7 */
+typedef enum {
+ AB8500_CODEC_CR51_DA12_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR51_DA12_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr51_da12_voice;
+
+/* CR51 - 6 */
+typedef enum {
+ AB8500_CODEC_CR51_SWAPDA12_34_NORMAL,
+ AB8500_CODEC_CR51_SWAPDA12_34_SWAPPED
+} t_ab8500_codec_cr51_swapda12_34;
+
+/* CR51 - 5 */
+typedef enum {
+ AB8500_CODEC_CR51_SLDAI7TOSLADO1_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR51_SLDAI7TOSLADO1_LOOPEDBACK
+} t_ab8500_codec_cr51_sldai7toslado1;
+
+/* CR51:58 - 4:0 */
+/* In ab8500_codec.h */
+
+/* CR52 - 5 */
+typedef enum {
+ AB8500_CODEC_CR52_SLDAI8TOSLADO2_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR52_SLDAI8TOSLADO2_LOOPEDBACK
+} t_ab8500_codec_cr52_sldai8toslado2;
+
+/* CR53 - 7 */
+typedef enum {
+ AB8500_CODEC_CR53_DA34_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR53_DA34_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr53_da34_voice;
+
+/* CR53 - 5 */
+typedef enum {
+ AB8500_CODEC_CR53_SLDAI7TOSLADO3_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR53_SLDAI7TOSLADO3_LOOPEDBACK
+} t_ab8500_codec_cr53_sldai7toslado3;
+
+/* CR54 - 5 */
+typedef enum {
+ AB8500_CODEC_CR54_SLDAI8TOSLADO4_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR54_SLDAI8TOSLADO4_LOOPEDBACK
+} t_ab8500_codec_cr54_sldai8toslado4;
+
+/* CR55 - 7 */
+typedef enum {
+ AB8500_CODEC_CR55_DA56_VOICE_AUDIOFILTER,
+ AB8500_CODEC_CR55_DA56_VOICE_LOWLATENCYFILTER
+} t_ab8500_codec_cr55_da56_voice;
+
+/* CR55 - 5 */
+typedef enum {
+ AB8500_CODEC_CR55_SLDAI7TOSLADO5_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR55_SLDAI7TOSLADO5_LOOPEDBACK
+} t_ab8500_codec_cr55_sldai7toslado5;
+
+/* CR56 - 5 */
+typedef enum {
+ AB8500_CODEC_CR56_SLDAI8TOSLADO6_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR56_SLDAI8TOSLADO6_LOOPEDBACK
+} t_ab8500_codec_cr56_sldai8toslado6;
+
+/* CR57 - 5 */
+typedef enum {
+ AB8500_CODEC_CR57_SLDAI8TOSLADO7_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR57_SLDAI8TOSLADO7_LOOPEDBACK
+} t_ab8500_codec_cr57_sldai8toslado7;
+
+/* CR58 - 5 */
+typedef enum {
+ AB8500_CODEC_CR58_SLDAI7TOSLADO8_NOT_LOOPEDBACK,
+ AB8500_CODEC_CR58_SLDAI7TOSLADO8_LOOPEDBACK
+} t_ab8500_codec_cr58_sldai7toslado8;
+
+/* CR59 - 7 */
+typedef enum {
+ AB8500_CODEC_CR59_PARLHF_INDEPENDENT,
+ AB8500_CODEC_CR59_PARLHF_BRIDGED
+} t_ab8500_codec_cr59_parlhf;
+
+/* CR59 - 6 */
+typedef enum {
+ AB8500_CODEC_CR59_PARLVIB_INDEPENDENT,
+ AB8500_CODEC_CR59_PARLVIB_BRIDGED
+} t_ab8500_codec_cr59_parlvib;
+
+/* CR59 - 3 */
+typedef enum {
+ AB8500_CODEC_CR59_CLASSDVIB1_SWAPEN_DISABLED,
+ AB8500_CODEC_CR59_CLASSDVIB1_SWAPEN_ENABLED
+} t_ab8500_codec_cr59_classdvib1_swapen;
+
+/* CR59 - 2 */
+typedef enum {
+ AB8500_CODEC_CR59_CLASSDVIB2_SWAPEN_DISABLED,
+ AB8500_CODEC_CR59_CLASSDVIB2_SWAPEN_ENABLED
+} t_ab8500_codec_cr59_classdvib2_swapen;
+
+/* CR59 - 1 */
+typedef enum {
+ AB8500_CODEC_CR59_CLASSDHFL_SWAPEN_DISABLED,
+ AB8500_CODEC_CR59_CLASSDHFL_SWAPEN_ENABLED
+} t_ab8500_codec_cr59_classdhfl_swapen;
+
+/* CR59 - 0 */
+typedef enum {
+ AB8500_CODEC_CR59_CLASSDHFR_SWAPEN_DISABLED,
+ AB8500_CODEC_CR59_CLASSDHFR_SWAPEN_ENABLED
+} t_ab8500_codec_cr59_classdhfr_swapen;
+
+/* CR60 - 7:4 */
+typedef enum {
+ AB8500_CODEC_CR60_CLASSD_FIRBYP_ALL_ENABLED = 0,
+ AB8500_CODEC_CR60_CLASSD_FIRBYP_LEFT_HF_BYPASSED = 1,
+ AB8500_CODEC_CR60_CLASSD_FIRBYP_RIGHT_HF_BYPASSED = 2,
+ AB8500_CODEC_CR60_CLASSD_FIRBYP_VIBRA1_BYPASSED = 4,
+ AB8500_CODEC_CR60_CLASSD_FIRBYP_VIBRA2_BYPASSED = 8
+} t_ab8500_codec_cr60_classd_firbyp;
+
+/* CR60 - 3:0 */
+typedef enum {
+ AB8500_CODEC_CR60_CLASSD_HIGHVOLEN_DISABLED = 0,
+ AB8500_CODEC_CR60_CLASSD_HIGHVOLEN_LEFT_HF = 1,
+ AB8500_CODEC_CR60_CLASSD_HIGHVOLEN_RIGHT_HF = 2,
+ AB8500_CODEC_CR60_CLASSD_HIGHVOLEN_VIBRA1 = 4,
+ AB8500_CODEC_CR60_CLASSD_HIGHVOLEN_VIBRA2 = 8
+} t_ab8500_codec_cr60_classd_highvolen;
+
+/* CR61 - 7:4 */
+typedef t_uint8 t_ab8500_codec_cr61_classddith_hpgain;
+
+/* CR61 - 3:0 */
+typedef t_uint8 t_ab8500_codec_cr61_classddith_wgain;
+
+/* CR62 - Read Only */
+/* CR62 - 5 */
+typedef enum {
+ AB8500_CODEC_CR62_DMIC1SINC3_SINC5_SELECTED,
+ AB8500_CODEC_CR62_DMIC1SINC3_SINC3_SELECTED
+} t_ab8500_codec_cr62_dmic1sinc3;
+
+/* CR62 - 4 */
+typedef enum {
+ AB8500_CODEC_CR62_DMIC2SINC3_SINC5_SELECTED,
+ AB8500_CODEC_CR62_DMIC2SINC3_SINC3_SELECTED
+} t_ab8500_codec_cr62_dmic2sinc3;
+
+/* CR62 - 3 */
+typedef enum {
+ AB8500_CODEC_CR62_DMIC3SINC3_SINC5_SELECTED,
+ AB8500_CODEC_CR62_DMIC3SINC3_SINC3_SELECTED
+} t_ab8500_codec_cr62_dmic3sinc3;
+
+/* CR62 - 2 */
+typedef enum {
+ AB8500_CODEC_CR62_DMIC4SINC3_SINC5_SELECTED,
+ AB8500_CODEC_CR62_DMIC4SINC3_SINC3_SELECTED
+} t_ab8500_codec_cr62_dmic4sinc3;
+
+/* CR62 - 1 */
+typedef enum {
+ AB8500_CODEC_CR62_DMIC5SINC3_SINC5_SELECTED,
+ AB8500_CODEC_CR62_DMIC5SINC3_SINC3_SELECTED
+} t_ab8500_codec_cr62_dmic5sinc3;
+
+/* CR62 - 0 */
+typedef enum {
+ AB8500_CODEC_CR62_DMIC6SINC3_SINC5_SELECTED,
+ AB8500_CODEC_CR62_DMIC6SINC3_SINC3_SELECTED
+} t_ab8500_codec_cr62_dmic6sinc3;
+
+/* CR63 - 7 */
+typedef enum {
+ AB8500_CODEC_CR63_DATOHSLEN_DISABLED,
+ AB8500_CODEC_CR63_DATOHSLEN_ENABLED
+} t_ab8500_codec_cr63_datohslen;
+
+/* CR63 - 6 */
+typedef enum {
+ AB8500_CODEC_CR63_DATOHSREN_DISABLED,
+ AB8500_CODEC_CR63_DATOHSREN_ENABLED
+} t_ab8500_codec_cr63_datohsren;
+
+/* CR63 - 5 */
+typedef enum {
+ AB8500_CODEC_CR63_AD1SEL_LINLADL_SELECTED,
+ AB8500_CODEC_CR63_AD1SEL_DMIC1_SELECTED
+} t_ab8500_codec_cr63_ad1sel;
+
+/* CR63 - 4 */
+typedef enum {
+ AB8500_CODEC_CR63_AD2SEL_LINRADR_SELECTED,
+ AB8500_CODEC_CR63_AD2SEL_DMIC2_SELECTED
+} t_ab8500_codec_cr63_ad2sel;
+
+/* CR63 - 3 */
+typedef enum {
+ AB8500_CODEC_CR63_AD3SEL_ADMO_SELECTED,
+ AB8500_CODEC_CR63_AD3SEL_DMIC3_SELECTED
+} t_ab8500_codec_cr63_ad3sel;
+
+/* CR63 - 2 */
+typedef enum {
+ AB8500_CODEC_CR63_AD5SEL_AMADR_SELECTED,
+ AB8500_CODEC_CR63_AD5SEL_DMIC5_SELECTED
+} t_ab8500_codec_cr63_ad5sel;
+
+/* CR63 - 1 */
+typedef enum {
+ AB8500_CODEC_CR63_AD6SEL_ADMO_SELECTED,
+ AB8500_CODEC_CR63_AD6SEL_DMIC6_SELECTED
+} t_ab8500_codec_cr63_ad6sel;
+
+/* CR63 - 0 */
+typedef enum {
+ AB8500_CODEC_CR63_ANCSEL_NOT_MIXED_IN_EAR,
+ AB8500_CODEC_CR63_ANCSEL_MIXED_IN_EAR
+} t_ab8500_codec_cr63_ancsel;
+
+/* CR64 - 7 */
+typedef enum {
+ AB8500_CODEC_CR64_DATOHFREN_NOT_MIXED_TO_HFR,
+ AB8500_CODEC_CR64_DATOHFREN_MIXED_TO_HFR
+} t_ab8500_codec_cr64_datohfren;
+
+/* CR64 - 6 */
+typedef enum {
+ AB8500_CODEC_CR64_DATOHFLEN_NOT_MIXED_TO_HFL,
+ AB8500_CODEC_CR64_DATOHFLEN_MIXED_TO_HFL
+} t_ab8500_codec_cr64_datohflen;
+
+/* CR64 - 5 */
+typedef enum {
+ AB8500_CODEC_CR64_HFRSEL_DA4_MIXED_TO_HFR,
+ AB8500_CODEC_CR64_HFRSEL_ANC_MIXED_TO_HFR
+} t_ab8500_codec_cr64_hfrsel;
+
+/* CR64 - 4 */
+typedef enum {
+ AB8500_CODEC_CR64_HFLSEL_DA3_MIXED_TO_HFL,
+ AB8500_CODEC_CR64_HFLSEL_ANC_MIXED_TO_HFL
+} t_ab8500_codec_cr64_hflsel;
+
+/* CR64 - 3:2 */
+typedef enum {
+ AB8500_CODEC_CR64_STFIR1SEL_AD_OUT1_SELECTED,
+ AB8500_CODEC_CR64_STFIR1SEL_AD_OUT3_SELECTED,
+ AB8500_CODEC_CR64_STFIR1SEL_DA_IN1_SELECTED
+} t_ab8500_codec_cr64_stfir1sel;
+
+/* CR64 - 1:0 */
+typedef enum {
+ AB8500_CODEC_CR64_STFIR2SEL_AD_OUT2_SELECTED,
+ AB8500_CODEC_CR64_STFIR2SEL_AD_OUT4_SELECTED,
+ AB8500_CODEC_CR64_STFIR2SEL_DA_IN2_SELECTED
+} t_ab8500_codec_cr64_stfir2sel;
+
+/* CR65 - 6 */
+typedef enum {
+ AB8500_CODEC_CR65_FADEDIS_AD1_ENABLED,
+ AB8500_CODEC_CR65_FADEDIS_AD1_DISABLED
+} t_ab8500_codec_cr65_fadedis_ad1;
+
+/* CR65 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr65_ad1gain;
+
+/* CR66 - 6 */
+typedef enum {
+ AB8500_CODEC_CR66_FADEDIS_AD2_ENABLED,
+ AB8500_CODEC_CR66_FADEDIS_AD2_DISABLED
+} t_ab8500_codec_cr66_fadedis_ad2;
+
+/* CR66 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr66_ad2gain;
+
+/* CR67 - 6 */
+typedef enum {
+ AB8500_CODEC_CR67_FADEDIS_AD3_ENABLED,
+ AB8500_CODEC_CR67_FADEDIS_AD3_DISABLED
+} t_ab8500_codec_cr67_fadedis_ad3;
+
+/* CR67 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr67_ad3gain;
+
+/* CR68 - 6 */
+typedef enum {
+ AB8500_CODEC_CR68_FADEDIS_AD4_ENABLED,
+ AB8500_CODEC_CR68_FADEDIS_AD4_DISABLED
+} t_ab8500_codec_cr68_fadedis_ad4;
+
+/* CR68 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr68_ad4gain;
+
+/* CR69 - 6 */
+typedef enum {
+ AB8500_CODEC_CR69_FADEDIS_AD5_ENABLED,
+ AB8500_CODEC_CR69_FADEDIS_AD5_DISABLED
+} t_ab8500_codec_cr69_fadedis_ad5;
+
+/* CR69 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr69_ad5gain;
+
+/* CR70 - 6 */
+typedef enum {
+ AB8500_CODEC_CR70_FADEDIS_AD6_ENABLED,
+ AB8500_CODEC_CR70_FADEDIS_AD6_DISABLED
+} t_ab8500_codec_cr70_fadedis_ad6;
+
+/* CR70 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr70_ad6gain;
+
+/* CR71 - 6 */
+typedef enum {
+ AB8500_CODEC_CR71_FADEDIS_DA1_ENABLED,
+ AB8500_CODEC_CR71_FADEDIS_DA1_DISABLED
+} t_ab8500_codec_cr71_fadedis_da1;
+
+/* CR71 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr71_da1gain;
+
+/* CR72 - 6 */
+typedef enum {
+ AB8500_CODEC_CR72_FADEDIS_DA2_ENABLED,
+ AB8500_CODEC_CR72_FADEDIS_DA2_DISABLED
+} t_ab8500_codec_cr72_fadedis_da2;
+
+/* CR72 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr72_da2gain;
+
+/* CR73 - 6 */
+typedef enum {
+ AB8500_CODEC_CR73_FADEDIS_DA3_ENABLED,
+ AB8500_CODEC_CR73_FADEDIS_DA3_DISABLED
+} t_ab8500_codec_cr73_fadedis_da3;
+
+/* CR73 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr73_da3gain;
+
+/* CR74 - 6 */
+typedef enum {
+ AB8500_CODEC_CR74_FADEDIS_DA4_ENABLED,
+ AB8500_CODEC_CR74_FADEDIS_DA4_DISABLED
+} t_ab8500_codec_cr74_fadedis_da4;
+
+/* CR74 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr74_da4gain;
+
+/* CR75 - 6 */
+typedef enum {
+ AB8500_CODEC_CR75_FADEDIS_DA5_ENABLED,
+ AB8500_CODEC_CR75_FADEDIS_DA5_DISABLED
+} t_ab8500_codec_cr75_fadedis_da5;
+
+/* CR75 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr75_da5gain;
+
+/* CR76 - 6 */
+typedef enum {
+ AB8500_CODEC_CR76_FADEDIS_DA6_ENABLED,
+ AB8500_CODEC_CR76_FADEDIS_DA6_DISABLED
+} t_ab8500_codec_cr76_fadedis_da6;
+
+/* CR76 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr76_da6gain;
+
+/* CR77 - 6 */
+typedef enum {
+ AB8500_CODEC_CR77_FADEDIS_AD1L_TO_HFL_ENABLED,
+ AB8500_CODEC_CR77_FADEDIS_AD1L_TO_HFL_DISABLED
+} t_ab8500_codec_cr77_fadedis_ad1l;
+
+/* CR77 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr77_ad1lbgain_to_hfl;
+
+/* CR78 - 6 */
+typedef enum {
+ AB8500_CODEC_CR78_FADEDIS_AD2L_TO_HFR_ENABLED,
+ AB8500_CODEC_CR78_FADEDIS_AD2L_TO_HFR_DISABLED
+} t_ab8500_codec_cr78_fadedis_ad2l;
+
+/* CR78 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr78_ad2lbgain_to_hfr;
+
+/* CR79 - 7 */
+typedef enum {
+ AB8500_CODEC_CR79_HSSINC1_SINC3_CHOOSEN,
+ AB8500_CODEC_CR79_HSSINC1_SINC1_CHOOSEN
+} t_ab8500_codec_cr79_hssinc1;
+
+/* CR79 - 4 */
+typedef enum {
+ AB8500_CODEC_CR79_FADEDIS_HSL_ENABLED,
+ AB8500_CODEC_CR79_FADEDIS_HSL_DISABLED
+} t_ab8500_codec_cr79_fadedis_hsl;
+
+/* CR79 - 3:0 */
+typedef t_uint8 t_ab8500_codec_cr79_hsldgain;
+
+/* CR80 - 7:6 */
+typedef enum {
+ AB8500_CODEC_CR80_FADE_SPEED_1MS,
+ AB8500_CODEC_CR80_FADE_SPEED_4MS,
+ AB8500_CODEC_CR80_FADE_SPEED_8MS,
+ AB8500_CODEC_CR80_FADE_SPEED_16MS,
+} t_ab8500_codec_cr80_fade_speed;
+
+/* CR80 - 4 */
+typedef enum {
+ AB8500_CODEC_CR80_FADEDIS_HSR_ENABLED,
+ AB8500_CODEC_CR80_FADEDIS_HSR_DISABLED
+} t_ab8500_codec_cr80_fadedis_hsr;
+
+/* CR80 - 3:0 */
+typedef t_uint8 t_ab8500_codec_cr80_hsrdgain;
+
+/* CR81 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr81_stfir1gain;
+
+/* CR82 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr82_stfir2gain;
+
+/* CR83 - 2 */
+typedef enum {
+ AB8500_CODEC_CR83_ENANC_DISABLED,
+ AB8500_CODEC_CR83_ENANC_ENABLED
+} t_ab8500_codec_cr83_enanc;
+
+/* CR83 - 1 */
+typedef enum {
+ AB8500_CODEC_CR83_ANCIIRINIT_NOT_STARTED,
+ AB8500_CODEC_CR83_ANCIIRINIT_STARTED
+} t_ab8500_codec_cr83_anciirinit;
+
+/* CR83 - 0 */
+typedef enum {
+ AB8500_CODEC_CR83_ANCFIRUPDATE_RESETTED,
+ AB8500_CODEC_CR83_ANCFIRUPDATE_NOT_RESETTED
+} t_ab8500_codec_cr83_ancfirupdate;
+
+/* CR84 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr84_ancinshift;
+
+/* CR85 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr85_ancfiroutshift;
+
+/* CR86 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr86_ancshiftout;
+
+/* CR87 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr87_ancfircoeff_msb;
+
+/* CR88 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr88_ancfircoeff_lsb;
+
+/* CR89 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr89_anciircoeff_msb;
+
+/* CR90 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr90_anciircoeff_lsb;
+
+/* CR91 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr91_ancwarpdel_msb;
+
+/* CR92 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr92_ancwarpdel_lsb;
+
+/* CR93 - Read Only */
+/* CR93 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr93_ancfirpeak_msb;
+
+/* CR94 - Read Only */
+/* CR94 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr94_ancfirpeak_lsb;
+
+/* CR95 - Read Only */
+/* CR95 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr95_anciirpeak_msb;
+
+/* CR96 - Read Only */
+/* CR96 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr96_anciirpeak_lsb;
+
+/* CR97 - 7 */
+typedef enum {
+ AB8500_CODEC_CR97_STFIR_SET_LAST_NOT_APPLIED,
+ AB8500_CODEC_CR97_STFIR_SET_LAST_APPLIED
+} t_ab8500_codec_cr97_stfir_set;
+
+/* CR97 - 6:0 */
+typedef t_uint8 t_ab8500_codec_cr97_stfir_addr;
+
+/* CR98 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr98_stfir_coeff_msb;
+
+/* CR99 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr99_stfir_coeff_lsb;
+
+/* CR100 - 2 */
+typedef enum {
+ AB8500_CODEC_CR100_ENSTFIRS_DISABLED,
+ AB8500_CODEC_CR100_ENSTFIRS_ENABLED
+} t_ab8500_codec_cr100_enstfirs;
+
+/* CR100 - 1 */
+typedef enum {
+ AB8500_CODEC_CR100_STFIRSTOIF1_AUD_IF0_DATA_RATE,
+ AB8500_CODEC_CR100_STFIRSTOIF1_AUD_IF1_DATA_RATE
+} t_ab8500_codec_cr100_stfirstoif1;
+
+/* CR100 - 0 */
+typedef enum {
+ AB8500_CODEC_CR100_STFIR_BUSY_READY,
+ AB8500_CODEC_CR100_STFIR_BUSY_NOT_READY
+} t_ab8500_codec_cr100_stfir_busy;
+
+/* CR101 - 7 */
+typedef enum {
+ AB8500_CODEC_CR101_HSOFFST_MASK_MASKED,
+ AB8500_CODEC_CR101_HSOFFST_MASK_ENABLED
+} t_ab8500_codec_cr101_hsoffst_mask;
+
+/* CR101 - 6 */
+typedef enum {
+ AB8500_CODEC_CR101_FIFOFULL_MASK_MASKED,
+ AB8500_CODEC_CR101_FIFOFULL_MASK_ENABLED
+} t_ab8500_codec_cr101_fifofull_mask;
+
+/* CR101 - 5 */
+typedef enum {
+ AB8500_CODEC_CR101_FIFOEMPTY_MASK_MASKED,
+ AB8500_CODEC_CR101_FIFOEMPTY_MASK_ENABLED
+} t_ab8500_codec_cr101_fifoempty_mask;
+
+/* CR101 - 4 */
+typedef enum {
+ AB8500_CODEC_CR101_DASAT_MASK_MASKED,
+ AB8500_CODEC_CR101_DASAT_MASK_ENABLED
+} t_ab8500_codec_cr101_dasat_mask;
+
+/* CR101 - 3 */
+typedef enum {
+ AB8500_CODEC_CR101_ADSAT_MASK_MASKED,
+ AB8500_CODEC_CR101_ADSAT_MASK_ENABLED
+} t_ab8500_codec_cr101_adsat_mask;
+
+/* CR101 - 2 */
+typedef enum {
+ AB8500_CODEC_CR101_ADDSP_MASK_MASKED,
+ AB8500_CODEC_CR101_ADDSP_MASK_ENABLED
+} t_ab8500_codec_cr101_addsp_mask;
+
+/* CR101 - 1 */
+typedef enum {
+ AB8500_CODEC_CR101_DADSP_MASK_MASKED,
+ AB8500_CODEC_CR101_DADSP_MASK_ENABLED
+} t_ab8500_codec_cr101_dadsp_mask;
+
+/* CR101 - 0 */
+typedef enum {
+ AB8500_CODEC_CR101_FIRSID_MASK_MASKED,
+ AB8500_CODEC_CR101_FIRSID_MASK_ENABLED
+} t_ab8500_codec_cr101_firsid_mask;
+
+/* CR102 - Read Only */
+/* CR102 - 7 */
+typedef enum {
+ AB8500_CODEC_CR102_IT_HSOFFST_ON,
+ AB8500_CODEC_CR102_IT_HSOFFST_OFF
+} t_ab8500_codec_cr102_it_hsoffst;
+
+/* CR102 - 6 */
+typedef enum {
+ AB8500_CODEC_CR102_IT_FIFOFULL_NOT_FULL,
+ AB8500_CODEC_CR102_IT_FIFOFULL_FULL
+} t_ab8500_codec_cr102_it_fifofull;
+
+/* CR102 - 5 */
+typedef enum {
+ AB8500_CODEC_CR102_IT_FIFOEMPTY_NOT_EMPTY,
+ AB8500_CODEC_CR102_IT_FIFOEMPTY_EMPTY
+} t_ab8500_codec_cr102_it_fifoempty;
+
+/* CR102 - 4 */
+typedef enum {
+ AB8500_CODEC_CR102_IT_DASAT_NO_SATURATION,
+ AB8500_CODEC_CR102_IT_DASAT_SATURATION
+} t_ab8500_codec_cr102_it_dasat;
+
+/* CR102 - 3 */
+typedef enum {
+ AB8500_CODEC_CR102_IT_ADSAT_NO_SATURATION,
+ AB8500_CODEC_CR102_IT_ADSAT_SATURATION
+} t_ab8500_codec_cr102_it_adsat;
+
+/* CR102 - 2 */
+typedef enum {
+ AB8500_CODEC_CR102_IT_ADDSP_NO_SATURATION,
+ AB8500_CODEC_CR102_IT_ADDSP_SATURATION
+} t_ab8500_codec_cr102_it_addsp;
+
+/* CR102 - 1 */
+typedef enum {
+ AB8500_CODEC_CR102_IT_DADSP_NO_SATURATION,
+ AB8500_CODEC_CR102_IT_DADSP_SATURATION
+} t_ab8500_codec_cr102_it_dadsp;
+
+/* CR102 - 0 */
+typedef enum {
+ AB8500_CODEC_CR102_IT_FIRSID_NO_SATURATION,
+ AB8500_CODEC_CR102_IT_FIRSID_SATURATION
+} t_ab8500_codec_cr102_it_firsid;
+
+/* CR103 - 7 */
+typedef enum {
+ AB8500_CODEC_CR103_VSSREADY_MASK_MASKED,
+ AB8500_CODEC_CR103_VSSREADY_MASK_ENABLED
+} t_ab8500_codec_cr103_vssready_mask;
+
+/* CR103 - 2 */
+typedef enum {
+ AB8500_CODEC_CR103_SHORTHSL_MASK_MASKED,
+ AB8500_CODEC_CR103_SHORTHSL_MASK_ENABLED
+} t_ab8500_codec_cr103_shorthsl_mask;
+
+/* CR103 - 1 */
+typedef enum {
+ AB8500_CODEC_CR103_SHORTHSR_MASK_MASKED,
+ AB8500_CODEC_CR103_SHORTHSR_MASK_ENABLED
+} t_ab8500_codec_cr103_shorthsr_mask;
+
+/* CR103 - 0 */
+typedef enum {
+ AB8500_CODEC_CR103_SHORTEAR_MASK_MASKED,
+ AB8500_CODEC_CR103_SHORTEAR_MASK_ENABLED
+} t_ab8500_codec_cr103_shortear_mask;
+
+/* CR104 - Read Only */
+/* CR104 - 7 */
+typedef enum {
+ AB8500_CODEC_CR104_IT_VSSREADY_NOT_READY,
+ AB8500_CODEC_CR104_IT_VSSREADY_READY
+} t_ab8500_codec_cr104_it_vssready;
+
+/* CR104 - 2 */
+typedef enum {
+ AB8500_CODEC_CR104_IT_SHORTHSL_NOT_DETECTED,
+ AB8500_CODEC_CR104_IT_SHORTHSL_DETECTED
+} t_ab8500_codec_cr104_it_shorthsl;
+
+/* CR104 - 1 */
+typedef enum {
+ AB8500_CODEC_CR104_IT_SHORTHSR_NOT_DETECTED,
+ AB8500_CODEC_CR104_IT_SHORTHSR_DETECTED
+} t_ab8500_codec_cr104_it_shorthsr;
+
+/* CR104 - 0 */
+typedef enum {
+ AB8500_CODEC_CR104_IT_SHORTEAR_NOT_DETECTED,
+ AB8500_CODEC_CR104_IT_SHORTEAR_DETECTED
+} t_ab8500_codec_cr104_it_shortear;
+
+/* CR105 - 7 */
+/* In ab8500_codec.h */
+
+/* CR105 - 5:0 */
+/* In ab8500_codec.h */
+
+/* CR106 - 7:0 */
+/* In ab8500_codec.h */
+
+/* CR107 - 7:0 */
+/* In ab8500_codec.h */
+
+/* CR108 - 7:0 */
+/* In ab8500_codec.h */
+
+/* CR109 - 7:0 */
+/* In ab8500_codec.h */
+
+/* CR110 - Read Only */
+/* CR110 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr110_bfifosamples;
+
+/* CR111 - Read Only */
+/* CR111 - 4:0 */
+typedef t_uint8 t_ab8500_codec_cr111_aud_ip_rev;
+
+/* CR27 - 6:5 */
+typedef enum {
+ AB8500_CODEC_CR27_IF1_BITCLK_OSR_32,
+ AB8500_CODEC_CR27_IF1_BITCLK_OSR_64,
+ AB8500_CODEC_CR27_IF1_BITCLK_OSR_128,
+ AB8500_CODEC_CR27_IF1_BITCLK_OSR_256
+} t_ab8500_codec_cr27_if1_bitclk_osr;
+
+/* CR27 - 2:1 */
+typedef enum {
+ AB8500_CODEC_CR27_IF0_BITCLK_OSR_32,
+ AB8500_CODEC_CR27_IF0_BITCLK_OSR_64,
+ AB8500_CODEC_CR27_IF0_BITCLK_OSR_128,
+ AB8500_CODEC_CR27_IF0_BITCLK_OSR_256
+} t_ab8500_codec_cr27_if0_bitclk_osr;
+
+/* CR28 - 1:0 */
+typedef enum {
+ AB8500_CODEC_CR28_IF0WL_16BITS,
+ AB8500_CODEC_CR28_IF0WL_20BITS,
+ AB8500_CODEC_CR28_IF0WL_24BITS,
+ AB8500_CODEC_CR28_IF0WL_32BITS
+} t_ab8500_codec_cr28_if0wl;
+
+/* CR30 - 1:0 */
+typedef enum {
+ AB8500_CODEC_CR30_IF1WL_16BITS,
+ AB8500_CODEC_CR30_IF1WL_20BITS,
+ AB8500_CODEC_CR30_IF1WL_24BITS,
+ AB8500_CODEC_CR30_IF1WL_32BITS
+} t_ab8500_codec_cr30_if1wl;
+
+/* CR105 - 7 */
+typedef enum {
+ AB8500_CODEC_CR105_BFIFOMSK_AD_DATA0_UNMASKED,
+ AB8500_CODEC_CR105_BFIFOMSK_AD_DATA0_MASKED
+} t_ab8500_codec_cr105_bfifomsk;
+
+/* CR105 - 5:0 */
+typedef t_uint8 t_ab8500_codec_cr105_bfifoint;
+
+/* CR106 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr106_bfifotx;
+
+/* CR107 - 7:5 */
+typedef enum {
+ AB8500_CODEC_CR107_BFIFOEXSL_0_EXTRA_SLOT,
+ AB8500_CODEC_CR107_BFIFOEXSL_1_EXTRA_SLOT,
+ AB8500_CODEC_CR107_BFIFOEXSL_2_EXTRA_SLOT,
+ AB8500_CODEC_CR107_BFIFOEXSL_3_EXTRA_SLOT,
+ AB8500_CODEC_CR107_BFIFOEXSL_4_EXTRA_SLOT,
+ AB8500_CODEC_CR107_BFIFOEXSL_5_EXTRA_SLOT,
+ AB8500_CODEC_CR107_BFIFOEXSL_6_EXTRA_SLOT,
+} t_ab8500_codec_cr107_bfifoexsl;
+
+/* CR107 - 4:2 */
+typedef enum {
+ AB8500_CODEC_CR107_PREBITCLK0_0_EXTRA_CLK,
+ AB8500_CODEC_CR107_PREBITCLK0_1_EXTRA_CLK,
+ AB8500_CODEC_CR107_PREBITCLK0_2_EXTRA_CLK,
+ AB8500_CODEC_CR107_PREBITCLK0_3_EXTRA_CLK,
+ AB8500_CODEC_CR107_PREBITCLK0_4_EXTRA_CLK,
+ AB8500_CODEC_CR107_PREBITCLK0_5_EXTRA_CLK,
+ AB8500_CODEC_CR107_PREBITCLK0_6_EXTRA_CLK,
+ AB8500_CODEC_CR107_PREBITCLK0_7_EXTRA_CLK
+} t_ab8500_codec_cr107_prebitclk0;
+
+/* CR107 - 1 */
+typedef enum {
+ AB8500_CODEC_CR107_BFIFOMAST_SLAVE_MODE,
+ AB8500_CODEC_CR107_BFIFOMAST_MASTER_MODE
+} t_ab8500_codec_cr107_bfifomast;
+
+/* CR107 - 0 */
+typedef enum {
+ AB8500_CODEC_CR107_BFIFORUN_STOPPED,
+ AB8500_CODEC_CR107_BFIFORUN_RUNNING
+} t_ab8500_codec_cr107_bfiforun;
+
+/* CR108 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr108_bfifoframsw;
+
+/* CR109 - 7:0 */
+typedef t_uint8 t_ab8500_codec_cr109_bfifowakeup;
+
+typedef enum {
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT3,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT4,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT5,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT6,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT7,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT8,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_ZEROS,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_IS_TRISTATE = 15,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_UNDEFINED
+} t_ab8500_codec_cr31_to_cr46_ad_data_allocation;
+
+typedef enum {
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT00,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT01,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT02,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT03,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT04,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT05,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT06,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT07,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT08,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT09,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT10,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT11,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT12,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT13,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT14,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT15,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT16,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT17,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT18,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT19,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT20,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT21,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT22,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT23,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT24,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT25,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT26,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT27,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT28,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT29,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT30,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT31,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT_UNDEFINED
+} t_ab8500_codec_cr51_to_cr58_sltoda;
+
+/*configuration structure for AB8500 Codec*/
+typedef struct {
+ /* CR0 */
+ t_ab8500_codec_cr0_powerup cr0_powerup;
+ t_ab8500_codec_cr0_enaana cr0_enaana;
+
+ /* CR1 */
+ t_ab8500_codec_cr1_swreset cr1_swreset;
+
+ /* CR2 */
+ t_ab8500_codec_cr2_enad1 cr2_enad1;
+ t_ab8500_codec_cr2_enad2 cr2_enad2;
+ t_ab8500_codec_cr2_enad3 cr2_enad3;
+ t_ab8500_codec_cr2_enad4 cr2_enad4;
+ t_ab8500_codec_cr2_enad5 cr2_enad5;
+ t_ab8500_codec_cr2_enad6 cr2_enad6;
+
+ /* CR3 */
+ t_ab8500_codec_cr3_enda1 cr3_enda1;
+ t_ab8500_codec_cr3_enda2 cr3_enda2;
+ t_ab8500_codec_cr3_enda3 cr3_enda3;
+ t_ab8500_codec_cr3_enda4 cr3_enda4;
+ t_ab8500_codec_cr3_enda5 cr3_enda5;
+ t_ab8500_codec_cr3_enda6 cr3_enda6;
+
+ /* CR4 */
+ t_ab8500_codec_cr4_lowpowhs cr4_lowpowhs;
+ t_ab8500_codec_cr4_lowpowdachs cr4_lowpowdachs;
+ t_ab8500_codec_cr4_lowpowear cr4_lowpowear;
+ t_ab8500_codec_cr4_ear_sel_cm cr4_ear_sel_cm;
+ t_ab8500_codec_cr4_hs_hp_en cr4_hs_hp_en;
+
+ /* CR5 */
+ t_ab8500_codec_cr5_enmic1 cr5_enmic1;
+ t_ab8500_codec_cr5_enmic2 cr5_enmic2;
+ t_ab8500_codec_cr5_enlinl cr5_enlinl;
+ t_ab8500_codec_cr5_enlinr cr5_enlinr;
+ t_ab8500_codec_cr5_mutmic1 cr5_mutmic1;
+ t_ab8500_codec_cr5_mutmic2 cr5_mutmic2;
+ t_ab8500_codec_cr5_mutlinl cr5_mutlinl;
+ t_ab8500_codec_cr5_mutlinr cr5_mutlinr;
+
+ /* CR6 */
+ t_ab8500_codec_cr6_endmic1 cr6_endmic1;
+ t_ab8500_codec_cr6_endmic2 cr6_endmic2;
+ t_ab8500_codec_cr6_endmic3 cr6_endmic3;
+ t_ab8500_codec_cr6_endmic4 cr6_endmic4;
+ t_ab8500_codec_cr6_endmic5 cr6_endmic5;
+ t_ab8500_codec_cr6_endmic6 cr6_endmic6;
+
+ /* CR7 */
+ t_ab8500_codec_cr7_mic1sel cr7_mic1sel;
+ t_ab8500_codec_cr7_linrsel cr7_linrsel;
+ t_ab8500_codec_cr7_endrvhsl cr7_endrvhsl;
+ t_ab8500_codec_cr7_endrvhsr cr7_endrvhsr;
+ t_ab8500_codec_cr7_enadcmic cr7_enadcmic;
+ t_ab8500_codec_cr7_enadclinl cr7_enadclinl;
+ t_ab8500_codec_cr7_enadclinr cr7_enadclinr;
+
+ /* CR8 */
+ t_ab8500_codec_cr8_cp_dis_pldwn cr8_cp_dis_pldwn;
+ t_ab8500_codec_cr8_enear cr8_enear;
+ t_ab8500_codec_cr8_enhsl cr8_enhsl;
+ t_ab8500_codec_cr8_enhsr cr8_enhsr;
+ t_ab8500_codec_cr8_enhfl cr8_enhfl;
+ t_ab8500_codec_cr8_enhfr cr8_enhfr;
+ t_ab8500_codec_cr8_envibl cr8_envibl;
+ t_ab8500_codec_cr8_envibr cr8_envibr;
+
+ /* CR9 */
+ t_ab8500_codec_cr9_endacear cr9_endacear;
+ t_ab8500_codec_cr9_endachsl cr9_endachsl;
+ t_ab8500_codec_cr9_endachsr cr9_endachsr;
+ t_ab8500_codec_cr9_endachfl cr9_endachfl;
+ t_ab8500_codec_cr9_endachfr cr9_endachfr;
+ t_ab8500_codec_cr9_endacvibl cr9_endacvibl;
+ t_ab8500_codec_cr9_endacvibr cr9_endacvibr;
+
+ /* CR10 */
+ t_ab8500_codec_cr10_muteear cr10_muteear;
+ t_ab8500_codec_cr10_mutehsl cr10_mutehsl;
+ t_ab8500_codec_cr10_mutehsr cr10_mutehsr;
+
+ /* CR11 */
+ t_ab8500_codec_cr11_enshortpwd cr11_enshortpwd;
+ t_ab8500_codec_cr11_earshortdis cr11_earshortdis;
+ t_ab8500_codec_cr11_hsshortdis cr11_hsshortdis;
+ t_ab8500_codec_cr11_hspullden cr11_hspullden;
+ t_ab8500_codec_cr11_hsoscen cr11_hsoscen;
+ t_ab8500_codec_cr11_hsfaden cr11_hsfaden;
+ t_ab8500_codec_cr11_hszcddis cr11_hszcddis;
+
+ /* CR12 */
+ t_ab8500_codec_cr12_encphs cr12_encphs;
+ t_ab8500_codec_cr12_hsautoen cr12_hsautoen;
+
+ /* CR13 */
+ t_ab8500_codec_cr13_envdet_hthresh cr13_envdet_hthresh;
+ t_ab8500_codec_cr13_envdet_lthresh cr13_envdet_lthresh;
+
+ /* CR14 */
+ t_ab8500_codec_cr14_smpslven cr14_smpslven;
+ t_ab8500_codec_cr14_envdetsmpsen cr14_envdetsmpsen;
+ t_ab8500_codec_cr14_cplven cr14_cplven;
+ t_ab8500_codec_cr14_envdetcpen cr14_envdetcpen;
+ t_ab8500_codec_cr14_envet_time cr14_envet_time;
+
+ /* CR15 */
+ t_ab8500_codec_cr15_pwmtovibl cr15_pwmtovibl;
+ t_ab8500_codec_cr15_pwmtovibr cr15_pwmtovibr;
+ t_ab8500_codec_cr15_pwmlctrl cr15_pwmlctrl;
+ t_ab8500_codec_cr15_pwmrctrl cr15_pwmrctrl;
+ t_ab8500_codec_cr15_pwmnlctrl cr15_pwmnlctrl;
+ t_ab8500_codec_cr15_pwmplctrl cr15_pwmplctrl;
+ t_ab8500_codec_cr15_pwmnrctrl cr15_pwmnrctrl;
+ t_ab8500_codec_cr15_pwmprctrl cr15_pwmprctrl;
+
+ /* CR16 */
+ t_ab8500_codec_cr16_pwmnlpol cr16_pwmnlpol;
+ t_ab8500_codec_cr16_pwmnldutycycle cr16_pwmnldutycycle;
+
+ /* CR17 */
+ t_ab8500_codec_cr17_pwmplpol cr17_pwmplpol;
+ t_ab8500_codec_cr17_pwmpldutycycle cr17_pwmpldutycycle;
+
+ /* CR18 */
+ t_ab8500_codec_cr18_pwmnrpol cr18_pwmnrpol;
+ t_ab8500_codec_cr18_pwmnrdutycycle cr18_pwmnrdutycycle;
+
+ /* CR19 */
+ t_ab8500_codec_cr19_pwmprpol cr19_pwmprpol;
+ t_ab8500_codec_cr19_pwmprdutycycle cr19_pwmprdutycycle;
+
+ /* CR20 */
+ t_ab8500_codec_cr20_en_se_mic1 cr20_en_se_mic1;
+ t_ab8500_codec_cr20_low_pow_mic1 cr20_low_pow_mic1;
+ t_ab8500_codec_cr20_mic1_gain cr20_mic1_gain;
+
+ /* CR21 */
+ t_ab8500_codec_cr21_en_se_mic2 cr21_en_se_mic2;
+ t_ab8500_codec_cr21_low_pow_mic2 cr21_low_pow_mic2;
+ t_ab8500_codec_cr21_mic2_gain cr21_mic2_gain;
+
+ /* CR22 */
+ t_ab8500_codec_cr22_hsl_gain cr22_hsl_gain;
+ t_ab8500_codec_cr22_hsr_gain cr22_hsr_gain;
+
+ /* CR23 */
+ t_ab8500_codec_cr23_linl_gain cr23_linl_gain;
+ t_ab8500_codec_cr23_linr_gain cr23_linr_gain;
+
+ /* CR24 */
+ t_ab8500_codec_cr24_lintohsl_gain cr24_lintohsl_gain;
+
+ /* CR25 */
+ t_ab8500_codec_cr25_lintohsr_gain cr25_lintohsr_gain;
+
+ /* CR26 */
+ t_ab8500_codec_cr26_ad1nh cr26_ad1nh;
+ t_ab8500_codec_cr26_ad2nh cr26_ad2nh;
+ t_ab8500_codec_cr26_ad3nh cr26_ad3nh;
+ t_ab8500_codec_cr26_ad4nh cr26_ad4nh;
+ t_ab8500_codec_cr26_ad1_voice cr26_ad1_voice;
+ t_ab8500_codec_cr26_ad2_voice cr26_ad2_voice;
+ t_ab8500_codec_cr26_ad3_voice cr26_ad3_voice;
+ t_ab8500_codec_cr26_ad4_voice cr26_ad4_voice;
+
+ /* CR27 */
+ t_ab8500_codec_cr27_en_mastgen cr27_en_mastgen;
+ t_ab8500_codec_cr27_if1_bitclk_osr cr27_if1_bitclk_osr;
+ t_ab8500_codec_cr27_enfs_bitclk1 cr27_enfs_bitclk1;
+ t_ab8500_codec_cr27_if0_bitclk_osr cr27_if0_bitclk_osr;
+ t_ab8500_codec_cr27_enfs_bitclk0 cr27_enfs_bitclk0;
+
+ /* CR28 */
+ t_ab8500_codec_cr28_fsync0p cr28_fsync0p;
+ t_ab8500_codec_cr28_bitclk0p cr28_bitclk0p;
+ t_ab8500_codec_cr28_if0del cr28_if0del;
+ t_ab8500_codec_cr28_if0format cr28_if0format;
+ t_ab8500_codec_cr28_if0wl cr28_if0wl;
+
+ /* CR29 */
+ t_ab8500_codec_cr29_if0datoif1ad cr29_if0datoif1ad;
+ t_ab8500_codec_cr29_if0cktoif1ck cr29_if0cktoif1ck;
+ t_ab8500_codec_cr29_if1master cr29_if1master;
+ t_ab8500_codec_cr29_if1datoif0ad cr29_if1datoif0ad;
+ t_ab8500_codec_cr29_if1cktoif0ck cr29_if1cktoif0ck;
+ t_ab8500_codec_cr29_if0master cr29_if0master;
+ t_ab8500_codec_cr29_if0bfifoen cr29_if0bfifoen;
+
+ /* CR30 */
+ t_ab8500_codec_cr30_fsync1p cr30_fsync1p;
+ t_ab8500_codec_cr30_bitclk1p cr30_bitclk1p;
+ t_ab8500_codec_cr30_if1del cr30_if1del;
+ t_ab8500_codec_cr30_if1format cr30_if1format;
+ t_ab8500_codec_cr30_if1wl cr30_if1wl;
+
+ /* CR31 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr31_adotoslot1;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr31_adotoslot0;
+
+ /* CR32 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr32_adotoslot3;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr32_adotoslot2;
+
+ /* CR33 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr33_adotoslot5;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr33_adotoslot4;
+
+ /* CR34 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr34_adotoslot7;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr34_adotoslot6;
+
+ /* CR35 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr35_adotoslot9;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr35_adotoslot8;
+
+ /* CR36 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr36_adotoslot11;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr36_adotoslot10;
+
+ /* CR37 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr37_adotoslot13;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr37_adotoslot12;
+
+ /* CR38 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr38_adotoslot15;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr38_adotoslot14;
+
+ /* CR39 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr39_adotoslot17;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr39_adotoslot16;
+
+ /* CR40 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr40_adotoslot19;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr40_adotoslot18;
+
+ /* CR41 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr41_adotoslot21;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr41_adotoslot20;
+
+ /* CR42 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr42_adotoslot23;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr42_adotoslot22;
+
+ /* CR43 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr43_adotoslot25;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr43_adotoslot24;
+
+ /* CR44 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr44_adotoslot27;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr44_adotoslot26;
+
+ /* CR45 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr45_adotoslot29;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr45_adotoslot28;
+
+ /* CR46 */
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr46_adotoslot31;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation cr46_adotoslot30;
+
+ /* CR47 */
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl7;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl6;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl5;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl4;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl3;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl2;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl1;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr47_hiz_sl0;
+
+ /* CR48 */
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl15;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl14;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl13;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl12;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl11;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl10;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl9;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr48_hiz_sl8;
+
+ /* CR49 */
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl23;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl22;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl21;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl20;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl19;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl18;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl17;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr49_hiz_sl16;
+
+ /* CR50 */
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl31;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl30;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl29;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl28;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl27;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl26;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl25;
+ t_ab8500_codec_cr47_to_cr50_hiz_sl cr50_hiz_sl24;
+
+ /* CR51 */
+ t_ab8500_codec_cr51_da12_voice cr51_da12_voice;
+ t_ab8500_codec_cr51_swapda12_34 cr51_swapda12_34;
+ t_ab8500_codec_cr51_sldai7toslado1 cr51_sldai7toslado1;
+ t_ab8500_codec_cr51_to_cr58_sltoda cr51_sltoda1;
+
+ /* CR52 */
+ t_ab8500_codec_cr52_sldai8toslado2 cr52_sldai8toslado2;
+ t_ab8500_codec_cr51_to_cr58_sltoda cr52_sltoda2;
+
+ /* CR53 */
+ t_ab8500_codec_cr53_da34_voice cr53_da34_voice;
+ t_ab8500_codec_cr53_sldai7toslado3 cr53_sldai7toslado3;
+ t_ab8500_codec_cr51_to_cr58_sltoda cr53_sltoda3;
+
+ /* CR54 */
+ t_ab8500_codec_cr54_sldai8toslado4 cr54_sldai8toslado4;
+ t_ab8500_codec_cr51_to_cr58_sltoda cr54_sltoda4;
+
+ /* CR55 */
+ t_ab8500_codec_cr55_da56_voice cr55_da56_voice;
+ t_ab8500_codec_cr55_sldai7toslado5 cr55_sldai7toslado5;
+ t_ab8500_codec_cr51_to_cr58_sltoda cr55_sltoda5;
+
+ /* CR56 */
+ t_ab8500_codec_cr56_sldai8toslado6 cr56_sldai8toslado6;
+ t_ab8500_codec_cr51_to_cr58_sltoda cr56_sltoda6;
+
+ /* CR57 */
+ t_ab8500_codec_cr57_sldai8toslado7 cr57_sldai8toslado7;
+ t_ab8500_codec_cr51_to_cr58_sltoda cr57_sltoda7;
+
+ /* CR58 */
+ t_ab8500_codec_cr58_sldai7toslado8 cr58_sldai7toslado8;
+ t_ab8500_codec_cr51_to_cr58_sltoda cr58_sltoda8;
+
+ /* CR59 */
+ t_ab8500_codec_cr59_parlhf cr59_parlhf;
+ t_ab8500_codec_cr59_parlvib cr59_parlvib;
+ t_ab8500_codec_cr59_classdvib1_swapen cr59_classdvib1_swapen;
+ t_ab8500_codec_cr59_classdvib2_swapen cr59_classdvib2_swapen;
+ t_ab8500_codec_cr59_classdhfl_swapen cr59_classdhfl_swapen;
+ t_ab8500_codec_cr59_classdhfr_swapen cr59_classdhfr_swapen;
+
+ /* CR60 */
+ t_ab8500_codec_cr60_classd_firbyp cr60_classd_firbyp;
+ t_ab8500_codec_cr60_classd_highvolen cr60_classd_highvolen;
+
+ /* CR61 */
+ t_ab8500_codec_cr61_classddith_hpgain cr61_classddith_hpgain;
+ t_ab8500_codec_cr61_classddith_wgain cr61_classddith_wgain;
+
+ /* CR62 */
+ t_ab8500_codec_cr62_dmic1sinc3 cr62_dmic1sinc3;
+ t_ab8500_codec_cr62_dmic2sinc3 cr62_dmic2sinc3;
+ t_ab8500_codec_cr62_dmic3sinc3 cr62_dmic3sinc3;
+ t_ab8500_codec_cr62_dmic4sinc3 cr62_dmic4sinc3;
+ t_ab8500_codec_cr62_dmic5sinc3 cr62_dmic5sinc3;
+ t_ab8500_codec_cr62_dmic6sinc3 cr62_dmic6sinc3;
+
+ /* CR63 */
+ t_ab8500_codec_cr63_datohslen cr63_datohslen;
+ t_ab8500_codec_cr63_datohsren cr63_datohsren;
+ t_ab8500_codec_cr63_ad1sel cr63_ad1sel;
+ t_ab8500_codec_cr63_ad2sel cr63_ad2sel;
+ t_ab8500_codec_cr63_ad3sel cr63_ad3sel;
+ t_ab8500_codec_cr63_ad5sel cr63_ad5sel;
+ t_ab8500_codec_cr63_ad6sel cr63_ad6sel;
+ t_ab8500_codec_cr63_ancsel cr63_ancsel;
+
+ /* CR64 */
+ t_ab8500_codec_cr64_datohfren cr64_datohfren;
+ t_ab8500_codec_cr64_datohflen cr64_datohflen;
+ t_ab8500_codec_cr64_hfrsel cr64_hfrsel;
+ t_ab8500_codec_cr64_hflsel cr64_hflsel;
+ t_ab8500_codec_cr64_stfir1sel cr64_stfir1sel;
+ t_ab8500_codec_cr64_stfir2sel cr64_stfir2sel;
+
+ /* CR65 */
+ t_ab8500_codec_cr65_fadedis_ad1 cr65_fadedis_ad1;
+ t_ab8500_codec_cr65_ad1gain cr65_ad1gain;
+
+ /* CR66 */
+ t_ab8500_codec_cr66_fadedis_ad2 cr66_fadedis_ad2;
+ t_ab8500_codec_cr66_ad2gain cr66_ad2gain;
+
+ /* CR67 */
+ t_ab8500_codec_cr67_fadedis_ad3 cr67_fadedis_ad3;
+ t_ab8500_codec_cr67_ad3gain cr67_ad3gain;
+
+ /* CR68 */
+ t_ab8500_codec_cr68_fadedis_ad4 cr68_fadedis_ad4;
+ t_ab8500_codec_cr68_ad4gain cr68_ad4gain;
+
+ /* CR69 */
+ t_ab8500_codec_cr69_fadedis_ad5 cr69_fadedis_ad5;
+ t_ab8500_codec_cr69_ad5gain cr69_ad5gain;
+
+ /* CR70 */
+ t_ab8500_codec_cr70_fadedis_ad6 cr70_fadedis_ad6;
+ t_ab8500_codec_cr70_ad6gain cr70_ad6gain;
+
+ /* CR71 */
+ t_ab8500_codec_cr71_fadedis_da1 cr71_fadedis_da1;
+ t_ab8500_codec_cr71_da1gain cr71_da1gain;
+
+ /* CR72 */
+ t_ab8500_codec_cr72_fadedis_da2 cr72_fadedis_da2;
+ t_ab8500_codec_cr72_da2gain cr72_da2gain;
+
+ /* CR73 */
+ t_ab8500_codec_cr73_fadedis_da3 cr73_fadedis_da3;
+ t_ab8500_codec_cr73_da3gain cr73_da3gain;
+
+ /* CR74 */
+ t_ab8500_codec_cr74_fadedis_da4 cr74_fadedis_da4;
+ t_ab8500_codec_cr74_da4gain cr74_da4gain;
+
+ /* CR75 */
+ t_ab8500_codec_cr75_fadedis_da5 cr75_fadedis_da5;
+ t_ab8500_codec_cr75_da5gain cr75_da5gain;
+
+ /* CR76 */
+ t_ab8500_codec_cr76_fadedis_da6 cr76_fadedis_da6;
+ t_ab8500_codec_cr76_da6gain cr76_da6gain;
+
+ /* CR77 */
+ t_ab8500_codec_cr77_fadedis_ad1l cr77_fadedis_ad1l;
+ t_ab8500_codec_cr77_ad1lbgain_to_hfl cr77_ad1lbgain_to_hfl;
+
+ /* CR78 */
+ t_ab8500_codec_cr78_fadedis_ad2l cr78_fadedis_ad2l;
+ t_ab8500_codec_cr78_ad2lbgain_to_hfr cr78_ad2lbgain_to_hfr;
+
+ /* CR79 */
+ t_ab8500_codec_cr79_hssinc1 cr79_hssinc1;
+ t_ab8500_codec_cr79_fadedis_hsl cr79_fadedis_hsl;
+ t_ab8500_codec_cr79_hsldgain cr79_hsldgain;
+
+ /* CR80 */
+ t_ab8500_codec_cr80_fade_speed cr80_fade_speed;
+ t_ab8500_codec_cr80_fadedis_hsr cr80_fadedis_hsr;
+ t_ab8500_codec_cr80_hsrdgain cr80_hsrdgain;
+
+ /* CR81 */
+ t_ab8500_codec_cr81_stfir1gain cr81_stfir1gain;
+
+ /* CR82 */
+ t_ab8500_codec_cr82_stfir2gain cr82_stfir2gain;
+
+ /* CR83 */
+ t_ab8500_codec_cr83_enanc cr83_enanc;
+ t_ab8500_codec_cr83_anciirinit cr83_anciirinit;
+ t_ab8500_codec_cr83_ancfirupdate cr83_ancfirupdate;
+
+ /* CR84 */
+ t_ab8500_codec_cr84_ancinshift cr84_ancinshift;
+
+ /* CR85 */
+ t_ab8500_codec_cr85_ancfiroutshift cr85_ancfiroutshift;
+
+ /* CR86 */
+ t_ab8500_codec_cr86_ancshiftout cr86_ancshiftout;
+
+ /* CR87 */
+ t_ab8500_codec_cr87_ancfircoeff_msb cr87_ancfircoeff_msb;
+
+ /* CR88 */
+ t_ab8500_codec_cr88_ancfircoeff_lsb cr88_ancfircoeff_lsb;
+
+ /* CR89 */
+ t_ab8500_codec_cr89_anciircoeff_msb cr89_anciircoeff_msb;
+
+ /* CR90 */
+ t_ab8500_codec_cr90_anciircoeff_lsb cr90_anciircoeff_lsb;
+
+ /* CR91 */
+ t_ab8500_codec_cr91_ancwarpdel_msb cr91_ancwarpdel_msb;
+
+ /* CR92 */
+ t_ab8500_codec_cr92_ancwarpdel_lsb cr92_ancwarpdel_lsb;
+
+ /* CR93 */
+ t_ab8500_codec_cr93_ancfirpeak_msb cr93_ancfirpeak_msb;
+
+ /* CR94 */
+ t_ab8500_codec_cr94_ancfirpeak_lsb cr94_ancfirpeak_lsb;
+
+ /* CR95 */
+ t_ab8500_codec_cr95_anciirpeak_msb cr95_anciirpeak_msb;
+
+ /* CR96 */
+ t_ab8500_codec_cr96_anciirpeak_lsb cr96_anciirpeak_lsb;
+
+ /* CR97 */
+ t_ab8500_codec_cr97_stfir_set cr97_stfir_set;
+ t_ab8500_codec_cr97_stfir_addr cr97_stfir_addr;
+
+ /* CR98 */
+ t_ab8500_codec_cr98_stfir_coeff_msb cr98_stfir_coeff_msb;
+
+ /* CR99 */
+ t_ab8500_codec_cr99_stfir_coeff_lsb cr99_stfir_coeff_lsb;
+
+ /* CR100 */
+ t_ab8500_codec_cr100_enstfirs cr100_enstfirs;
+ t_ab8500_codec_cr100_stfirstoif1 cr100_stfirstoif1;
+ t_ab8500_codec_cr100_stfir_busy cr100_stfir_busy;
+
+ /* CR101 */
+ t_ab8500_codec_cr101_hsoffst_mask cr101_hsoffst_mask;
+ t_ab8500_codec_cr101_fifofull_mask cr101_fifofull_mask;
+ t_ab8500_codec_cr101_fifoempty_mask cr101_fifoempty_mask;
+ t_ab8500_codec_cr101_dasat_mask cr101_dasat_mask;
+ t_ab8500_codec_cr101_adsat_mask cr101_adsat_mask;
+ t_ab8500_codec_cr101_addsp_mask cr101_addsp_mask;
+ t_ab8500_codec_cr101_dadsp_mask cr101_dadsp_mask;
+ t_ab8500_codec_cr101_firsid_mask cr101_firsid_mask;
+
+ /* CR102 */
+ t_ab8500_codec_cr102_it_hsoffst cr102_it_hsoffst;
+ t_ab8500_codec_cr102_it_fifofull cr102_it_fifofull;
+ t_ab8500_codec_cr102_it_fifoempty cr102_it_fifoempty;
+ t_ab8500_codec_cr102_it_dasat cr102_it_dasat;
+ t_ab8500_codec_cr102_it_adsat cr102_it_adsat;
+ t_ab8500_codec_cr102_it_addsp cr102_it_addsp;
+ t_ab8500_codec_cr102_it_dadsp cr102_it_dadsp;
+ t_ab8500_codec_cr102_it_firsid cr102_it_firsid;
+
+ /* CR103 */
+ t_ab8500_codec_cr103_vssready_mask cr103_vssready_mask;
+ t_ab8500_codec_cr103_shorthsl_mask cr103_shorthsl_mask;
+ t_ab8500_codec_cr103_shorthsr_mask cr103_shorthsr_mask;
+ t_ab8500_codec_cr103_shortear_mask cr103_shortear_mask;
+
+ /* CR104 */
+ t_ab8500_codec_cr104_it_vssready cr104_it_vssready;
+ t_ab8500_codec_cr104_it_shorthsl cr104_it_shorthsl;
+ t_ab8500_codec_cr104_it_shorthsr cr104_it_shorthsr;
+ t_ab8500_codec_cr104_it_shortear cr104_it_shortear;
+
+ /* CR105 */
+ t_ab8500_codec_cr105_bfifomsk cr105_bfifomsk;
+ t_ab8500_codec_cr105_bfifoint cr105_bfifoint;
+
+ /* CR106 */
+ t_ab8500_codec_cr106_bfifotx cr106_bfifotx;
+
+ /* CR107 */
+ t_ab8500_codec_cr107_bfifoexsl cr107_bfifoexsl;
+ t_ab8500_codec_cr107_prebitclk0 cr107_prebitclk0;
+ t_ab8500_codec_cr107_bfifomast cr107_bfifomast;
+ t_ab8500_codec_cr107_bfiforun cr107_bfiforun;
+
+ /* CR108 */
+ t_ab8500_codec_cr108_bfifoframsw cr108_bfifoframsw;
+
+ /* CR109 */
+ t_ab8500_codec_cr109_bfifowakeup cr109_bfifowakeup;
+
+ /* CR110 */
+ t_ab8500_codec_cr110_bfifosamples cr110_bfifosamples;
+
+ /* CR111 */
+ t_ab8500_codec_cr111_aud_ip_rev cr111_aud_ip_rev;
+
+} t_ab8500_codec_configuration;
+
+typedef enum {
+ AB8500_CODEC_DIRECTION_IN,
+ AB8500_CODEC_DIRECTION_OUT,
+ AB8500_CODEC_DIRECTION_INOUT
+} t_ab8500_codec_direction;
+
+typedef enum {
+ AB8500_CODEC_AUDIO_INTERFACE_0,
+ AB8500_CODEC_AUDIO_INTERFACE_1
+} t_ab8500_codec_audio_interface;
+
+typedef enum {
+ AB8500_CODEC_MODE_HIFI,
+ AB8500_CODEC_MODE_VOICE,
+ AB8500_CODEC_MODE_MANUAL_SETTING
+} t_ab8500_codec_mode;
+
+typedef enum {
+ AB8500_CODEC_DEST_HEADSET,
+ AB8500_CODEC_DEST_EARPIECE,
+ AB8500_CODEC_DEST_HANDSFREE,
+ AB8500_CODEC_DEST_VIBRATOR_L,
+ AB8500_CODEC_DEST_VIBRATOR_R,
+ AB8500_CODEC_DEST_FM_TX,
+ AB8500_CODEC_DEST_ALL
+} t_ab8500_codec_dest;
+
+typedef enum {
+ AB8500_CODEC_SRC_LINEIN,
+ AB8500_CODEC_SRC_MICROPHONE_1A,
+ AB8500_CODEC_SRC_MICROPHONE_1B,
+ AB8500_CODEC_SRC_MICROPHONE_2,
+ AB8500_CODEC_SRC_D_MICROPHONE_1,
+ AB8500_CODEC_SRC_D_MICROPHONE_2,
+ AB8500_CODEC_SRC_D_MICROPHONE_3,
+ AB8500_CODEC_SRC_D_MICROPHONE_4,
+ AB8500_CODEC_SRC_D_MICROPHONE_5,
+ AB8500_CODEC_SRC_D_MICROPHONE_6,
+ AB8500_CODEC_SRC_D_MICROPHONE_12,
+ AB8500_CODEC_SRC_D_MICROPHONE_34,
+ AB8500_CODEC_SRC_D_MICROPHONE_56,
+ AB8500_CODEC_SRC_FM_RX,
+ AB8500_CODEC_SRC_ALL
+} t_ab8500_codec_src;
+
+typedef struct {
+ t_uint8 slave_address_of_ab8500_codec;
+ t_ab8500_codec_direction ab8500_codec_direction;
+ t_ab8500_codec_mode ab8500_codec_mode_in;
+ t_ab8500_codec_mode ab8500_codec_mode_out;
+ t_ab8500_codec_audio_interface audio_interface;
+ t_ab8500_codec_src ab8500_codec_src;
+ t_ab8500_codec_dest ab8500_codec_dest;
+ t_uint8 in_left_volume;
+ t_uint8 in_right_volume;
+ t_uint8 out_left_volume;
+ t_uint8 out_right_volume;
+
+ t_ab8500_codec_configuration ab8500_codec_configuration;
+} t_ab8500_codec_system_context;
+
+#endif /* _AB8500_CODECP_H_ */
+
+/* End of file AB8500_CODECP.h */
diff --git a/arch/arm/mach-ux500/include/mach/ab8500_codec_v1_0.h b/arch/arm/mach-ux500/include/mach/ab8500_codec_v1_0.h
new file mode 100644
index 00000000000..a5b8a57f341
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/ab8500_codec_v1_0.h
@@ -0,0 +1,329 @@
+/*****************************************************************************/
+/**
+* © ST-Ericsson, 2009 - All rights reserved
+* Reproduction and Communication of this document is strictly prohibited
+* unless specifically authorized in writing by ST-Ericsson
+*
+* \brief Public header file for AB8500 Codec
+* \author ST-Ericsson
+*/
+/*****************************************************************************/
+
+#ifndef _AB8500_CODEC_V1_0_H_
+#define _AB8500_CODEC_V1_0_H_
+
+/*---------------------------------------------------------------------
+ * Includes
+ *--------------------------------------------------------------------*/
+#include "hcl_defs.h"
+#include "debug.h"
+#include <mach/ab8500_codec_p_v1_0.h>
+/*---------------------------------------------------------------------
+ * Define
+ *--------------------------------------------------------------------*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+ typedef enum {
+ AB8500_CODEC_OK,
+ AB8500_CODEC_ERROR,
+ AB8500_CODEC_UNSUPPORTED_FEATURE,
+ AB8500_CODEC_INVALID_PARAMETER,
+ AB8500_CODEC_CONFIG_NOT_COHERENT,
+ AB8500_CODEC_TRANSACTION_FAILED
+ } t_ab8500_codec_error;
+
+ typedef enum {
+ AB8500_CODEC_SRC_STATE_DISABLE,
+ AB8500_CODEC_SRC_STATE_ENABLE
+ } t_ab8500_codec_src_state;
+
+ typedef enum {
+ AB8500_CODEC_DEST_STATE_DISABLE,
+ AB8500_CODEC_DEST_STATE_ENABLE
+ } t_ab8500_codec_dest_state;
+
+ typedef enum {
+ AB8500_CODEC_MASTER_MODE_DISABLE,
+ AB8500_CODEC_MASTER_MODE_ENABLE
+ } t_ab8500_codec_master_mode;
+
+ typedef enum {
+ AB8500_CODEC_SLOT0,
+ AB8500_CODEC_SLOT1,
+ AB8500_CODEC_SLOT2,
+ AB8500_CODEC_SLOT3,
+ AB8500_CODEC_SLOT4,
+ AB8500_CODEC_SLOT5,
+ AB8500_CODEC_SLOT6,
+ AB8500_CODEC_SLOT7,
+ AB8500_CODEC_SLOT8,
+ AB8500_CODEC_SLOT9,
+ AB8500_CODEC_SLOT10,
+ AB8500_CODEC_SLOT11,
+ AB8500_CODEC_SLOT12,
+ AB8500_CODEC_SLOT13,
+ AB8500_CODEC_SLOT14,
+ AB8500_CODEC_SLOT15,
+ AB8500_CODEC_SLOT16,
+ AB8500_CODEC_SLOT17,
+ AB8500_CODEC_SLOT18,
+ AB8500_CODEC_SLOT19,
+ AB8500_CODEC_SLOT20,
+ AB8500_CODEC_SLOT21,
+ AB8500_CODEC_SLOT22,
+ AB8500_CODEC_SLOT23,
+ AB8500_CODEC_SLOT24,
+ AB8500_CODEC_SLOT25,
+ AB8500_CODEC_SLOT26,
+ AB8500_CODEC_SLOT27,
+ AB8500_CODEC_SLOT28,
+ AB8500_CODEC_SLOT29,
+ AB8500_CODEC_SLOT30,
+ AB8500_CODEC_SLOT31,
+ AB8500_CODEC_SLOT_UNDEFINED
+ } t_ab8500_codec_slot;
+
+ typedef enum {
+ AB8500_CODEC_DA_CHANNEL_NUMBER_1,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_2,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_3,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_4,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_5,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_6,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_7,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_8,
+ AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED
+ } t_ab8500_codec_da_channel_number;
+
+ typedef struct {
+ t_ab8500_codec_cr105_bfifomsk cr105_bfifomsk;
+ t_ab8500_codec_cr105_bfifoint cr105_bfifoint;
+ t_ab8500_codec_cr106_bfifotx cr106_bfifotx;
+ t_ab8500_codec_cr107_bfifoexsl cr107_bfifoexsl;
+ t_ab8500_codec_cr107_prebitclk0 cr107_prebitclk0;
+ t_ab8500_codec_cr107_bfifomast cr107_bfifomast;
+ t_ab8500_codec_cr107_bfiforun cr107_bfiforun;
+ t_ab8500_codec_cr108_bfifoframsw cr108_bfifoframsw;
+ t_ab8500_codec_cr109_bfifowakeup cr109_bfifowakeup;
+ } t_ab8500_codec_burst_fifo_config;
+
+ typedef struct {
+ t_ab8500_codec_cr27_if1_bitclk_osr cr27_if1_bitclk_osr;
+ t_ab8500_codec_cr27_if0_bitclk_osr cr27_if0_bitclk_osr;
+ t_ab8500_codec_cr28_if0wl cr28_if0wl;
+ t_ab8500_codec_cr30_if1wl cr30_if1wl;
+ t_ab8500_codec_cr28_bitclk0p cr28_bitclk0p;
+ t_ab8500_codec_cr28_if0del cr28_if0del;
+ } t_ab8500_codec_tdm_config;
+
+/************************************************************/
+/*---------------------------------------------------------------------
+ * Exported APIs
+ *--------------------------------------------------------------------*/
+/* Initialization */
+ t_ab8500_codec_error AB8500_CODEC_Init(IN t_uint8
+ slave_address_of_codec);
+ t_ab8500_codec_error AB8500_CODEC_Reset(void);
+
+/* Audio Codec basic configuration */
+ t_ab8500_codec_error AB8500_CODEC_SetModeAndDirection(IN
+ t_ab8500_codec_direction
+ ab8500_codec_direction,
+ IN
+ t_ab8500_codec_mode
+ ab8500_codec_mode_in,
+ IN
+ t_ab8500_codec_mode
+ ab8500_codec_mode_out,
+ IN
+ t_ab8500_codec_tdm_config
+ const *const
+ p_tdm_config);
+ t_ab8500_codec_error AB8500_CODEC_SelectInput(IN t_ab8500_codec_src
+ ab8500_codec_src);
+ t_ab8500_codec_error AB8500_CODEC_SelectOutput(IN t_ab8500_codec_dest
+ ab8500_codec_dest);
+
+/* Burst FIFO configuration */
+ t_ab8500_codec_error AB8500_CODEC_ConfigureBurstFifo(IN
+ t_ab8500_codec_burst_fifo_config
+ const *const
+ p_burst_fifo_config);
+ t_ab8500_codec_error AB8500_CODEC_EnableBurstFifo(void);
+ t_ab8500_codec_error AB8500_CODEC_DisableBurstFifo(void);
+
+/* Audio Codec Master mode configuration */
+ t_ab8500_codec_error AB8500_CODEC_SetMasterMode(IN
+ t_ab8500_codec_master_mode
+ mode);
+
+/* APIs to be implemented by user */
+ t_ab8500_codec_error AB8500_CODEC_Write(IN t_uint8 register_offset,
+ IN t_uint8 count,
+ IN t_uint8 * p_data);
+ t_ab8500_codec_error AB8500_CODEC_Read(IN t_uint8 register_offset,
+ IN t_uint8 count,
+ IN t_uint8 * p_dummy_data,
+ IN t_uint8 * p_data);
+
+/* Volume Management */
+ t_ab8500_codec_error AB8500_CODEC_SetSrcVolume(IN t_ab8500_codec_src
+ src_device,
+ IN t_uint8
+ in_left_volume,
+ IN t_uint8
+ in_right_volume);
+ t_ab8500_codec_error AB8500_CODEC_SetDestVolume(IN t_ab8500_codec_dest
+ dest_device,
+ IN t_uint8
+ out_left_volume,
+ IN t_uint8
+ out_right_volume);
+
+/* Power management */
+ t_ab8500_codec_error AB8500_CODEC_PowerDown(void);
+ t_ab8500_codec_error AB8500_CODEC_PowerUp(void);
+
+/* Interface Management */
+ t_ab8500_codec_error AB8500_CODEC_SelectInterface(IN
+ t_ab8500_codec_audio_interface
+ audio_interface);
+ t_ab8500_codec_error AB8500_CODEC_GetInterface(OUT
+ t_ab8500_codec_audio_interface
+ * p_audio_interface);
+
+/* Slot Allocation */
+ t_ab8500_codec_error AB8500_CODEC_ADSlotAllocation(IN
+ t_ab8500_codec_slot
+ ad_slot,
+ IN
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation
+ value);
+ t_ab8500_codec_error AB8500_CODEC_DASlotAllocation(IN
+ t_ab8500_codec_da_channel_number
+ channel_number,
+ IN
+ t_ab8500_codec_cr51_to_cr58_sltoda
+ slot);
+
+/* Loopback Management */
+ t_ab8500_codec_error AB8500_CODEC_SetAnalogLoopback(IN t_uint8
+ out_left_volume,
+ IN t_uint8
+ out_right_volume);
+ t_ab8500_codec_error AB8500_CODEC_RemoveAnalogLoopback(void);
+
+/* Bypass Management */
+ t_ab8500_codec_error AB8500_CODEC_EnableBypassMode(void);
+ t_ab8500_codec_error AB8500_CODEC_DisableBypassMode(void);
+
+/* Power Control Management */
+ t_ab8500_codec_error AB8500_CODEC_SrcPowerControl(IN t_ab8500_codec_src
+ src_device,
+ t_ab8500_codec_src_state
+ state);
+ t_ab8500_codec_error AB8500_CODEC_DestPowerControl(IN
+ t_ab8500_codec_dest
+ dest_device,
+ t_ab8500_codec_dest_state
+ state);
+
+/* Version Management */
+ t_ab8500_codec_error AB8500_CODEC_GetVersion(OUT t_version * p_version);
+
+#if 0
+/* Debug management */
+ t_ab8500_codec_error AB8500_CODEC_SetDbgLevel(IN t_dbg_level dbg_level);
+ t_ab8500_codec_error AB8500_CODEC_GetDbgLevel(OUT t_dbg_level *
+ p_dbg_level);
+#endif
+
+/*
+** following is added by $kardad$
+*/
+
+/* duplicate copy of enum from msp.h */
+/* for MSPConfiguration.in_clock_freq parameter to select msp clock freq */
+ typedef enum {
+ CODEC_MSP_INPUT_FREQ_1MHZ = 1024,
+ CODEC_MSP_INPUT_FREQ_2MHZ = 2048,
+ CODEC_MSP_INPUT_FREQ_3MHZ = 3072,
+ CODEC_MSP_INPUT_FREQ_4MHZ = 4096,
+ CODEC_MSP_INPUT_FREQ_5MHZ = 5760,
+ CODEC_MSP_INPUT_FREQ_6MHZ = 6144,
+ CODEC_MSP_INPUT_FREQ_8MHZ = 8192,
+ CODEC_MSP_INPUT_FREQ_11MHZ = 11264,
+ CODEC_MSP_INPUT_FREQ_12MHZ = 12288,
+ CODEC_MSP_INPUT_FREQ_16MHZ = 16384,
+ CODEC_MSP_INPUT_FREQ_22MHZ = 22579,
+ CODEC_MSP_INPUT_FREQ_24MHZ = 24576,
+ CODEC_MSP_INPUT_FREQ_48MHZ = 49152
+ } codec_msp_in_clock_freq_type;
+
+/* msp clock source internal/external for srg_clock_sel */
+ typedef enum {
+ CODEC_MSP_APB_CLOCK = 0,
+ CODEC_MSP_SCK_CLOCK = 2,
+ CODEC_MSP_SCK_SYNC_CLOCK = 3
+ } codec_msp_srg_clock_sel_type;
+
+/* Sample rate supported by Codec */
+
+ typedef enum {
+ CODEC_FREQUENCY_DONT_CHANGE = -100,
+ CODEC_SAMPLING_FREQ_RESET = -1,
+ CODEC_SAMPLING_FREQ_MINLIMIT = 7,
+ CODEC_SAMPLING_FREQ_8KHZ = 8, /*default */
+ CODEC_SAMPLING_FREQ_11KHZ = 11,
+ CODEC_SAMPLING_FREQ_12KHZ = 12,
+ CODEC_SAMPLING_FREQ_16KHZ = 16,
+ CODEC_SAMPLING_FREQ_22KHZ = 22,
+ CODEC_SAMPLING_FREQ_24KHZ = 24,
+ CODEC_SAMPLING_FREQ_32KHZ = 32,
+ CODEC_SAMPLING_FREQ_44KHZ = 44,
+ CODEC_SAMPLING_FREQ_48KHZ = 48,
+ CODEC_SAMPLING_FREQ_64KHZ = 64, /*the frequencies below this line are not supported in stw5094A */
+ CODEC_SAMPLING_FREQ_88KHZ = 88,
+ CODEC_SAMPLING_FREQ_96KHZ = 96,
+ CODEC_SAMPLING_FREQ_128KHZ = 128,
+ CODEC_SAMPLING_FREQ_176KHZ = 176,
+ CODEC_SAMPLING_FREQ_192KHZ = 192,
+ CODEC_SAMPLING_FREQ_MAXLIMIT = 193
+ } t_codec_sample_frequency;
+
+#define RESET -1
+#define DEFAULT -100
+/***********************************************************/
+/*
+** following stuff is added to compile code without debug print support $kardad$
+*/
+
+#define DBGEXIT(cr)
+#define DBGEXIT0(cr)
+#define DBGEXIT1(cr,ch,p1)
+#define DBGEXIT2(cr,ch,p1,p2)
+#define DBGEXIT3(cr,ch,p1,p2,p3)
+#define DBGEXIT4(cr,ch,p1,p2,p3,p4)
+#define DBGEXIT5(cr,ch,p1,p2,p3,p4,p5)
+#define DBGEXIT6(cr,ch,p1,p2,p3,p4,p5,p6)
+
+#define DBGENTER()
+#define DBGENTER0()
+#define DBGENTER1(ch,p1)
+#define DBGENTER2(ch,p1,p2)
+#define DBGENTER3(ch,p1,p2,p3)
+#define DBGENTER4(ch,p1,p2,p3,p4)
+#define DBGENTER5(ch,p1,p2,p3,p4,p5)
+#define DBGENTER6(ch,p1,p2,p3,p4,p5,p6)
+
+#define DBGPRINT(dbg_level,dbg_string)
+#define DBGPRINTHEX(dbg_level,dbg_string,uint32)
+#define DBGPRINTDEC(dbg_level,dbg_string,uint32)
+/***********************************************************/
+
+#ifdef __cplusplus
+} /* allow C++ to use these headers */
+#endif /* __cplusplus */
+#endif /* _AB8500_CODEC_H_ */
+/* End of file ab8500_codec.h*/
diff --git a/arch/arm/mach-ux500/include/mach/ab8500_denc.h b/arch/arm/mach-ux500/include/mach/ab8500_denc.h
new file mode 100644
index 00000000000..917f75d01a1
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/ab8500_denc.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * AB8500 tvout driver interface
+ *
+ * Author: Marcel Tunnissen <marcel.tuennissen@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __AB8500_DENC__H__
+#define __AB8500_DENC__H__
+
+struct ab8500_denc_platform_data {
+ /* Platform info */
+ bool ddr_enable;
+ bool ddr_little_endian;
+};
+
+enum ab8500_denc_TV_std {
+ TV_STD_PAL_BDGHI,
+ TV_STD_PAL_N,
+ TV_STD_PAL_M,
+ TV_STD_NTSC_M,
+};
+
+enum ab8500_denc_cr_filter_bandwidth {
+ TV_CR_NTSC_LOW_DEF_FILTER,
+ TV_CR_PAL_LOW_DEF_FILTER,
+ TV_CR_NTSC_HIGH_DEF_FILTER,
+ TV_CR_PAL_HIGH_DEF_FILTER,
+};
+
+enum ab8500_denc_phase_reset_mode {
+ TV_PHASE_RST_MOD_DISABLE,
+ TV_PHASE_RST_MOD_FROM_PHASE_BUF,
+ TV_PHASE_RST_MOD_FROM_INC_DFS,
+ TV_PHASE_RST_MOD_RST,
+};
+
+enum ab8500_denc_plug_time {
+ TV_PLUG_TIME_0_5S,
+ TV_PLUG_TIME_1S,
+ TV_PLUG_TIME_1_5S,
+ TV_PLUG_TIME_2S,
+ TV_PLUG_TIME_2_5S,
+ TV_PLUG_TIME_3S,
+};
+
+struct ab8500_denc_conf {
+ /* register settings for DENC_configuration */
+ bool act_output;
+ enum ab8500_denc_TV_std TV_std;
+ bool progressive;
+ bool test_pattern;
+ bool partial_blanking;
+ bool blank_all;
+ bool black_level_setup;
+ enum ab8500_denc_cr_filter_bandwidth cr_filter;
+ bool suppress_col;
+ enum ab8500_denc_phase_reset_mode phase_reset_mode;
+ bool dac_enable;
+ bool act_dc_output;
+};
+
+void ab8500_denc_power_up(void);
+void ab8500_denc_power_down(void);
+void ab8500_denc_reset(bool hard);
+
+void ab8500_denc_regu_setup(bool enable_v_tv, bool enable_lp_mode);
+void ab8500_denc_conf(struct ab8500_denc_conf *conf);
+void ab8500_denc_conf_plug_detect(bool enable, bool load_RC,
+ enum ab8500_denc_plug_time time);
+void ab8500_denc_mask_int_plug_det(bool plug, bool unplug);
+#endif /* __AB8500_DENC__H__ */
+
diff --git a/arch/arm/mach-ux500/include/mach/ab8500_gpadc.h b/arch/arm/mach-ux500/include/mach/ab8500_gpadc.h
new file mode 100644
index 00000000000..4289dcfc0aa
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/ab8500_gpadc.h
@@ -0,0 +1,36 @@
+/*
+ * ab8500_gpadc.c - AB8500 GPADC Driver
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Licensed under GPLv2.
+ *
+ * Author: Arun R Murthy <arun.murthy@stericsson.com>
+ */
+
+#ifndef _AB8500_GPADC_H
+#define _Ab8500_GPADC_H
+
+/* GPADC source: From datasheer(ADCSwSel[4:0] in GPADCCtrl2) */
+#define BAT_CTRL 0x01
+#define ACC_DETECT1 0x04
+#define ACC_DETECT2 0x05
+#define MAIN_BAT_V 0x08
+#define BK_BAT_V 0x0C
+#define VBUS_V 0x09
+#define MAIN_CHARGER_V 0x03
+#define MAIN_CHARGER_C 0x0A
+#define USB_CHARGER_C 0x0B
+#define DIE_TEMP 0x0D
+#define BTEMP_BALL 0x02
+
+struct ab8500_gpadc_device_info {
+ struct completion ab8500_gpadc_complete;
+ struct mutex ab8500_gpadc_lock;
+#if defined(CONFIG_REGULATOR)
+ struct regulator *regu;
+#endif
+};
+
+int ab8500_gpadc_conversion(int input);
+
+#endif /* _AB8500_GPADC_H */
diff --git a/arch/arm/mach-ux500/include/mach/cg2900_devices.h b/arch/arm/mach-ux500/include/mach/cg2900_devices.h
new file mode 100644
index 00000000000..2db25b39148
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/cg2900_devices.h
@@ -0,0 +1,120 @@
+/*
+ * arch/arm/mach-ux500/include/mach/cg2900_devices.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Board specific device support for the Linux Bluetooth HCI H4 Driver
+ * for ST-Ericsson connectivity controller.
+ */
+
+#ifndef _CG2900_DEVICES_H_
+#define _CG2900_DEVICES_H_
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+
+/**
+ * struct cg2900_devices_cb - Callback structure for cg2900_devices user.
+ * @interrupt_cb: Callback function called when interrupt on CTS occurred.
+ *
+ * Defines the callback functions provided from the caller.
+ */
+struct cg2900_devices_cb {
+ void (*interrupt_cb)(void);
+};
+
+/**
+ * cg2900_devices_enable_chip() - Enable the controller.
+ */
+extern void cg2900_devices_enable_chip(void);
+
+/**
+ * cg2900_devices_disable_chip() - Disable the controller.
+ */
+extern void cg2900_devices_disable_chip(void);
+
+/**
+ * cg2900_devices_set_hci_revision() - Stores HCI revision info for the connected connectivity controller.
+ * @hci_version: HCI version from the controller.
+ * @hci_revision: HCI revision from the controller.
+ * @lmp_version: LMP version from the controller.
+ * @lmp_subversion: LMP subversion from the controller.
+ * @manufacturer: Manufacturer ID from the controller.
+ *
+ * See Bluetooth specification and white paper for used controller for details
+ * about parameters.
+ */
+extern void cg2900_devices_set_hci_revision(u8 hci_version,
+ u16 hci_revision,
+ u8 lmp_version,
+ u8 lmp_subversion,
+ u16 manufacturer);
+
+/**
+ * cg2900_devices_get_power_switch_off_cmd() - Get HCI power switch off command to use based on connected connectivity controller.
+ * @op_code: HCI opcode in generated packet. NULL if not needed.
+ *
+ * This command does not add the H4 channel header in front of the message.
+ *
+ * Returns:
+ * NULL if no command shall be sent,
+ * sk_buffer with command otherwise.
+ */
+extern struct sk_buff *cg2900_devices_get_power_switch_off_cmd(u16 *op_code);
+
+/**
+ * cg2900_devices_get_bt_enable_cmd() - Get HCI BT enable command to use based on connected connectivity controller.
+ * @op_code: HCI opcode in generated packet. NULL if not needed.
+ * @bt_enable: true if Bluetooth IP shall be enabled, false otherwise.
+ *
+ * This command does not add the H4 channel header in front of the message.
+ *
+ * Returns:
+ * NULL if no command shall be sent,
+ * sk_buffer with command otherwise.
+ */
+extern struct sk_buff *cg2900_devices_get_bt_enable_cmd(u16 *op_code,
+ bool bt_enable);
+
+/**
+ * cg2900_devices_init() - Initialize the board config.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * Error codes from gpio_request and gpio_direction_output.
+ */
+extern int cg2900_devices_init(void);
+
+/**
+ * cg2900_devices_exit() - Exit function for the board config.
+ */
+extern void cg2900_devices_exit(void);
+
+/**
+ * cg2900_devices_unset_cts_irq() - Disable interrupt on CTS.
+ */
+extern void cg2900_devices_unset_cts_irq(void);
+
+/**
+ * cg2900_devices_set_cts_irq() - Enable interrupt on CTS.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * Error codes from request_irq and nmk_config_pins.
+ */
+extern int cg2900_devices_set_cts_irq(void);
+
+/**
+ * cg2900_devices_reg_cb() - Register callbacks from upper layer.
+ *@cb: Callback structure from upper layer.
+ *
+ */
+extern void cg2900_devices_reg_cb(struct cg2900_devices_cb *cb);
+#endif /* _CG2900_DEVICES_H_ */
diff --git a/arch/arm/mach-ux500/include/mach/db5500-keypad.h b/arch/arm/mach-ux500/include/mach/db5500-keypad.h
new file mode 100644
index 00000000000..66b4c07f838
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/db5500-keypad.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License, version 2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ */
+
+#ifndef __DB5500_KEYPAD_H
+#define __DB5500_KEYPAD_H
+
+#include <linux/input/matrix_keypad.h>
+
+/**
+ * struct db5500_keypad_platform_data - structure for platform specific data
+ * @keymap_data: matrix scan code table for keycodes
+ * @debounce_ms: platform specific debounce time
+ * @no_autorepeat: flag for auto repetition
+ */
+struct db5500_keypad_platform_data {
+ const struct matrix_keymap_data *keymap_data;
+ u8 debounce_ms;
+ bool no_autorepeat;
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/db5500-regs.h b/arch/arm/mach-ux500/include/mach/db5500-regs.h
index 545c80fc802..612d9ee890c 100644
--- a/arch/arm/mach-ux500/include/mach/db5500-regs.h
+++ b/arch/arm/mach-ux500/include/mach/db5500-regs.h
@@ -29,7 +29,9 @@
#define U5500_NAND0_BASE 0x60000000
#define U5500_NAND1_BASE 0x70000000
#define U5500_TWD_BASE 0xa0410600
+#define U5500_ICN_BASE 0xA0040000
#define U5500_B2R2_BASE 0xa0200000
+#define U5500_BOOT_ROM_BASE 0x90000000
#define U5500_FSMC_BASE (U5500_PER1_BASE + 0x0000)
#define U5500_SDI0_BASE (U5500_PER1_BASE + 0x1000)
@@ -60,6 +62,7 @@
#define U5500_MSP1_BASE (U5500_PER4_BASE + 0x9000)
#define U5500_GPIO2_BASE (U5500_PER4_BASE + 0xA000)
#define U5500_CDETECT_BASE (U5500_PER4_BASE + 0xF000)
+#define U5500_PRCMU_TCDM_BASE (U5500_PER4_BASE + 0x18000)
#define U5500_SPI0_BASE (U5500_PER5_BASE + 0x0000)
#define U5500_SPI1_BASE (U5500_PER5_BASE + 0x1000)
@@ -83,7 +86,7 @@
#define U5500_HASH0_BASE (U5500_PER6_BASE + 0x1000)
#define U5500_HASH1_BASE (U5500_PER6_BASE + 0x2000)
#define U5500_PKA_BASE (U5500_PER6_BASE + 0x4000)
-#define U5500_PKAM_BASE (U5500_PER6_BASE + 0x5000)
+#define U5500_PKAM_BASE (U5500_PER6_BASE + 0x5100)
#define U5500_MTU0_BASE (U5500_PER6_BASE + 0x6000)
#define U5500_MTU1_BASE (U5500_PER6_BASE + 0x7000)
#define U5500_CR_BASE (U5500_PER6_BASE + 0x8000)
@@ -100,4 +103,27 @@
#define U5500_GPIOBANK6_BASE (U5500_GPIO4_BASE + 0x80)
#define U5500_GPIOBANK7_BASE (U5500_GPIO4_BASE + 0x100)
+#define U5500_MBOX_BASE (U5500_MODEM_BASE + 0xFFD1000)
+#define U5500_MBOX0_PEER_START (U5500_MBOX_BASE + 0x40)
+#define U5500_MBOX0_PEER_END (U5500_MBOX_BASE + 0x5F)
+#define U5500_MBOX0_LOCAL_START (U5500_MBOX_BASE + 0x60)
+#define U5500_MBOX0_LOCAL_END (U5500_MBOX_BASE + 0x7F)
+#define U5500_MBOX1_PEER_START (U5500_MBOX_BASE + 0x80)
+#define U5500_MBOX1_PEER_END (U5500_MBOX_BASE + 0x9F)
+#define U5500_MBOX1_LOCAL_START (U5500_MBOX_BASE + 0xA0)
+#define U5500_MBOX1_LOCAL_END (U5500_MBOX_BASE + 0xBF)
+#define U5500_MBOX2_PEER_START (U5500_MBOX_BASE + 0x00)
+#define U5500_MBOX2_PEER_END (U5500_MBOX_BASE + 0x1F)
+#define U5500_MBOX2_LOCAL_START (U5500_MBOX_BASE + 0x20)
+#define U5500_MBOX2_LOCAL_END (U5500_MBOX_BASE + 0x3F)
+
+#define U5500_ACCCON_BASE_SEC (0xBFFF0000)
+#define U5500_ACCCON_BASE (0xBFFF1000)
+#define U5500_ACCCON_CPUVEC_RESET_ADDR_OFFSET (0x00000020)
+#define U5500_ACCCON_ACC_CPU_CTRL_OFFSET (0x000000BC)
+
+#define U5500_ESRAM_BASE 0x40000000
+#define U5500_ESRAM_DMA_LCPA_OFFSET 0x10000
+#define U5500_DMA_LCPA_BASE (U5500_ESRAM_BASE + U5500_ESRAM_DMA_LCPA_OFFSET)
+
#endif
diff --git a/arch/arm/mach-ux500/include/mach/db8500-regs.h b/arch/arm/mach-ux500/include/mach/db8500-regs.h
index 85fc6a80b38..fe21eef4c23 100644
--- a/arch/arm/mach-ux500/include/mach/db8500-regs.h
+++ b/arch/arm/mach-ux500/include/mach/db8500-regs.h
@@ -15,9 +15,9 @@
#define U8500_ESRAM_BANK2 (U8500_ESRAM_BANK1 + U8500_ESRAM_BANK_SIZE)
#define U8500_ESRAM_BANK3 (U8500_ESRAM_BANK2 + U8500_ESRAM_BANK_SIZE)
#define U8500_ESRAM_BANK4 (U8500_ESRAM_BANK3 + U8500_ESRAM_BANK_SIZE)
-/* Use bank 4 for DMA LCLA and LCPA */
-#define U8500_DMA_LCLA_BASE U8500_ESRAM_BANK4
-#define U8500_DMA_LCPA_BASE (U8500_ESRAM_BANK4 + 0x4000)
+/* Use bank 4 for DMA LCPA */
+#define U8500_DMA_LCPA_BASE U8500_ESRAM_BANK4
+#define U8500_DMA_LCPA_BASE_ED (U8500_ESRAM_BANK4 + 0x4000)
#define U8500_PER3_BASE 0x80000000
#define U8500_STM_BASE 0x80100000
@@ -27,6 +27,7 @@
#define U8500_B2R2_BASE 0x80130000
#define U8500_HSEM_BASE 0x80140000
#define U8500_PER4_BASE 0x80150000
+#define U8500_TPIU_BASE 0x80190000
#define U8500_ICN_BASE 0x81000000
#define U8500_BOOT_ROM_BASE 0x90000000
@@ -72,8 +73,10 @@
/* per6 base addressess */
#define U8500_RNG_BASE (U8500_PER6_BASE + 0x0000)
-#define U8500_PKA_BASE (U8500_PER6_BASE + 0x1000)
-#define U8500_PKAM_BASE (U8500_PER6_BASE + 0x2000)
+#define U8500_HASH0_BASE (U8500_PER6_BASE + 0x1000)
+#define U8500_HASH1_BASE (U8500_PER6_BASE + 0x2000)
+#define U8500_PKA_BASE (U8500_PER6_BASE + 0x4000)
+#define U8500_PKAM_BASE (U8500_PER6_BASE + 0x5100)
#define U8500_MTU0_BASE (U8500_PER6_BASE + 0x6000) /* v1 */
#define U8500_MTU1_BASE (U8500_PER6_BASE + 0x7000) /* v1 */
#define U8500_CR_BASE (U8500_PER6_BASE + 0x8000) /* v1 */
@@ -94,7 +97,8 @@
#define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000)
#define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000)
#define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000)
-#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x0f000)
+#define U8500_PRCMU_TCDM_BASE_V1 (U8500_PER4_BASE + 0x0f000)
+#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x68000)
/* per3 base addresses */
#define U8500_FSMC_BASE (U8500_PER3_BASE + 0x0000)
@@ -125,6 +129,7 @@
#define U8500_I2C1_BASE (U8500_PER1_BASE + 0x2000)
#define U8500_MSP0_BASE (U8500_PER1_BASE + 0x3000)
#define U8500_MSP1_BASE (U8500_PER1_BASE + 0x4000)
+#define U8500_MSP3_BASE (U8500_PER1_BASE + 0x5000)
#define U8500_SDI0_BASE (U8500_PER1_BASE + 0x6000)
#define U8500_I2C2_BASE (U8500_PER1_BASE + 0x8000)
#define U8500_SPI3_BASE (U8500_PER1_BASE + 0x9000)
diff --git a/arch/arm/mach-ux500/include/mach/debug.h b/arch/arm/mach-ux500/include/mach/debug.h
new file mode 100644
index 00000000000..3567d7f5b38
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/debug.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009 STMicroelectronics
+ *
+ * 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 __INC_DBG_H
+#define __INC_DBG_H
+
+/* Store a submitter ID, unique for each HCL. */
+
+struct driver_debug_st {
+ int mtd;
+ int gpio;
+ int mmc;
+ int ssp;
+ int mtu;
+ int msp;
+ int spi;
+ int touch;
+ int dma;
+ int rtc;
+ int acodec;
+ int tourg;
+ int alsa;
+ int keypad;
+ int mcde;
+ int power;
+ int i2c;
+ int hsi;
+};
+
+#define stm_error(format, arg...) printk(KERN_ERR DRIVER_DEBUG_PFX ":ERROR " format "\n" , ## arg)
+#define stm_warn(format, arg...) printk(KERN_WARNING DRIVER_DEBUG_PFX ":WARNING " format "\n" , ## arg)
+#define stm_info(format, arg...) printk(KERN_INFO DRIVER_DEBUG_PFX ":INFO" format "\n" , ## arg)
+
+
+#define stm_dbg(debug, format, arg...) (!(DRIVER_DEBUG)) ? ({do {} while(0); }) : debug == 1 ? (printk(DRIVER_DBG DRIVER_DEBUG_PFX ": " format "\n" , ## arg)) : ({do {} while (0); })
+
+#define stm_dbg2(debug, format, arg...) (!(DRIVER_DEBUG)) ? ({do {} while(0); }) : debug == 2 ? (printk(DRIVER_DBG DRIVER_DEBUG_PFX ": " format "\n" , ## arg)) : ({do {} while (0); })
+
+#define stm_dbg3(debug, format, arg...) (!(DRIVER_DEBUG)) ? ({do {} while(0); }) : debug == 3 ? (printk(DRIVER_DBG DRIVER_DEBUG_PFX ": " format "\n" , ## arg)) : ({do {} while (0); })
+
+#define stm_dbg4(format, arg...) (DRIVER_DEBUG & 1) ? (printk(DRIVER_DBG DRIVER_DEBUG_PFX ": " format "\n" , ## arg)) : ({do {} while (0); })
+
+extern struct driver_debug_st DBG_ST;
+#endif
+
+/* __INC_DBG_H */
+
+/* End of file - debug.h */
diff --git a/arch/arm/mach-ux500/include/mach/devices.h b/arch/arm/mach-ux500/include/mach/devices.h
index c2b2f257494..c68252c671f 100644
--- a/arch/arm/mach-ux500/include/mach/devices.h
+++ b/arch/arm/mach-ux500/include/mach/devices.h
@@ -13,20 +13,30 @@ struct amba_device;
extern struct platform_device u5500_gpio_devs[];
extern struct platform_device u8500_gpio_devs[];
-extern struct amba_device ux500_pl031_device;
-extern struct amba_device u8500_ssp0_device;
-extern struct amba_device ux500_uart0_device;
-extern struct amba_device ux500_uart1_device;
-extern struct amba_device ux500_uart2_device;
-
-extern struct platform_device ux500_i2c1_device;
-extern struct platform_device ux500_i2c2_device;
-extern struct platform_device ux500_i2c3_device;
-
-extern struct platform_device u8500_i2c0_device;
-extern struct platform_device u8500_i2c4_device;
-extern struct platform_device u8500_dma40_device;
+extern struct platform_device ux500_mcde_device;
+extern struct platform_device u8500_hsit_device;
+extern struct platform_device u8500_hsir_device;
+extern struct platform_device u8500_shrm_device;
+extern struct platform_device ux500_b2r2_device;
+extern struct platform_device ux500_hwmem_device;
+extern struct amba_device ux500_rtc_device;
+extern struct platform_device ux500_hash1_device;
+extern struct platform_device ux500_musb_device;
+extern struct platform_device u5500_pwm0_device;
+extern struct platform_device u5500_pwm1_device;
+extern struct platform_device u5500_pwm2_device;
+extern struct platform_device u5500_pwm3_device;
+
+#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
+
+/**
+ * Touchpanel related macros declaration
+ */
+#define TOUCH_GPIO_PIN 84
-void dma40_u8500ed_fixup(void);
+#define TOUCH_XMAX 384
+#define TOUCH_YMAX 704
+#define PRCMU_CLOCK_OCR 0x1CC
+#define TSC_EXT_CLOCK_9_6MHZ 0x840000
#endif
diff --git a/arch/arm/mach-ux500/include/mach/gpio.h b/arch/arm/mach-ux500/include/mach/gpio.h
index d548a622e7d..5e8f9b031ce 100644
--- a/arch/arm/mach-ux500/include/mach/gpio.h
+++ b/arch/arm/mach-ux500/include/mach/gpio.h
@@ -9,15 +9,181 @@
#include <plat/gpio.h>
+/* Used by test applications */
+#define GPIO_TOTAL_PINS 267
+
+/* Defines for GPIO configuration */
+#define GPIO_BANK0_BASE (U8500_PER1_BASE + 0xE000)
+#define GPIO_BANK1_BASE (U8500_PER1_BASE + 0xE000 + 0x80)
+#define GPIO_BANK2_BASE (U8500_PER3_BASE + 0xE000)
+#define GPIO_BANK3_BASE (U8500_PER3_BASE + 0xE000 + 0x80)
+#define GPIO_BANK4_BASE (U8500_PER3_BASE + 0xE000 + 0x100)
+#define GPIO_BANK5_BASE (U8500_PER3_BASE + 0xE000 + 0x180)
+#define GPIO_BANK6_BASE (U8500_PER2_BASE + 0xE000)
+#define GPIO_BANK7_BASE (U8500_PER2_BASE + 0xE000 + 0x80)
+#define GPIO_BANK8_BASE (U8500_PER5_BASE + 0x1E000)
+
+#define _GPIO_BK0_BASE IO_ADDRESS(GPIO_BANK0_BASE)
+
+#define GPIO_BK0_DAT (_GPIO_BK0_BASE)
+#define GPIO_BK0_DATS (_GPIO_BK0_BASE + 0x4)
+#define GPIO_BK0_DATC (_GPIO_BK0_BASE + 0x8)
+#define GPIO_BK0_DIR (_GPIO_BK0_BASE + 0x10)
+#define GPIO_BK0_FSLA (_GPIO_BK0_BASE + 0x20)
+#define GPIO_BK0_FSLB (_GPIO_BK0_BASE + 0x24)
+#define GPIO_BK0_RWMSC (_GPIO_BK0_BASE + 0x50)
+#define GPIO_BK0_FWMSC (_GPIO_BK0_BASE + 0x54)
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
+#define gpio_to_irq __gpio_to_irq
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+ if (irq < NR_IRQS)
+ return IRQ_TO_GPIO(irq);
+ else
+ return -EINVAL;
+}
+
+enum {
+ EGPIO_PIN_0 = U8500_NR_GPIO,
+ EGPIO_PIN_1,
+ EGPIO_PIN_2,
+ EGPIO_PIN_3,
+ EGPIO_PIN_4,
+ EGPIO_PIN_5,
+ EGPIO_PIN_6,
+ EGPIO_PIN_7,
+ EGPIO_PIN_8,
+ EGPIO_PIN_9,
+ EGPIO_PIN_10,
+ EGPIO_PIN_11,
+ EGPIO_PIN_12,
+ EGPIO_PIN_13,
+ EGPIO_PIN_14,
+ EGPIO_PIN_15,
+ EGPIO_PIN_16,
+ EGPIO_PIN_17,
+ EGPIO_PIN_18,
+ EGPIO_PIN_19,
+ EGPIO_PIN_20,
+ EGPIO_PIN_21,
+ EGPIO_PIN_22,
+ EGPIO_PIN_23,
+};
+
+/* Don't use in new code -- use the plain numbers */
+#define GPIO_LOW 0
+#define GPIO_HIGH 1
+#define GPIO_DATA_LOW 0
+#define GPIO_DATA_HIGH 1
+#define GPIO(x) (x)
+
+/*
+ * Alternate Function:
+ * refered in altfun_table to pointout particular altfun to be enabled
+ * when using GPIO_ALT_FUNCTION A/B/C enable/disable operation
+ */
+typedef enum {
+ GPIO_ALT_I2C_0,
+ GPIO_ALT_I2C_1,
+ GPIO_ALT_I2C_2,
+ GPIO_ALT_I2C_3,
+ GPIO_ALT_I2C_4,
+ GPIO_ALT_MSP_0,
+ GPIO_ALT_MSP_1,
+ GPIO_ALT_MSP_2,
+ GPIO_ALT_MSP_3,
+ GPIO_ALT_MM_CARD,
+ GPIO_ALT_SD_CARD,
+ GPIO_ALT_DMA_0,
+ GPIO_ALT_DMA_1,
+ GPIO_ALT_HSIR,
+ GPIO_ALT_CCIR656_INPUT,
+ GPIO_ALT_CCIR656_OUTPUT,
+ GPIO_ALT_LCD_PANELA,
+ GPIO_ALT_LCD_PANELB_ED,
+ GPIO_ALT_LCD_PANELB,
+ GPIO_ALT_MDIF,
+ GPIO_ALT_SDRAM,
+ GPIO_ALT_HAMAC_AUDIO_DBG,
+ GPIO_ALT_HAMAC_VIDEO_DBG,
+ GPIO_ALT_CLOCK_RESET,
+ GPIO_ALT_TSP,
+ GPIO_ALT_IRDA,
+ GPIO_ALT_USB_MINIMUM,
+ GPIO_ALT_USB_I2C,
+ GPIO_ALT_OWM,
+ GPIO_ALT_PWL,
+ GPIO_ALT_FSMC,
+ GPIO_ALT_COMP_FLASH,
+ GPIO_ALT_SRAM_NOR_FLASH,
+ GPIO_ALT_FSMC_ADDLINE_0_TO_15,
+ GPIO_ALT_SCROLL_KEY,
+ GPIO_ALT_MSHC,
+ GPIO_ALT_HPI,
+ GPIO_ALT_USB_OTG,
+ GPIO_ALT_SDIO,
+ GPIO_ALT_HSMMC,
+ GPIO_ALT_FSMC_ADD_DATA_0_TO_25,
+ GPIO_ALT_HSIT,
+ GPIO_ALT_NOR,
+ GPIO_ALT_NAND,
+ GPIO_ALT_KEYPAD,
+ GPIO_ALT_VPIP,
+ GPIO_ALT_CAM,
+ GPIO_ALT_CCP1,
+ GPIO_ALT_EMMC,
+ GPIO_ALT_SDMMC,
+ GPIO_ALT_TRACE,
+ GPIO_ALT_MMIO_INIT_BOARD,
+ GPIO_ALT_MMIO_CAM_SET_I2C,
+ GPIO_ALT_MMIO_CAM_SET_EXT_CLK,
+ GPIO_ALT_TRACE_MIPI60,
+ GPIO_ALT_SDMMC2,
+ GPIO_ALT_TP_SET_EXT_CLK,
+ GPIO_ALT_LCD_D_8,
+ GPIO_ALT_LCD_D_16,
+ GPIO_ALT_LCD_D_18,
+ GPIO_ALT_LCD_D_24,
+ GPIO_ALT_LCDA,
+ GPIO_ALT_LCDA_CLK,
+ GPIO_ALT_LCDB,
+ GPIO_ALT_FUNMAX /* Add new alt func before this */
+} gpio_alt_function;
+
+struct gpio_altfun_data {
+ gpio_alt_function altfun;
+ int start;
+ int end;
+ int cont;
+ int type;
+ char dev_name[20];
+};
+
+extern int stm_gpio_set_altfunctable(struct gpio_altfun_data *table, int size);
+extern int stm_gpio_altfuncenable(gpio_alt_function alt_func);
+extern int stm_gpio_altfuncdisable(gpio_alt_function alt_func);
+
+#define __GPIO_ALT(_fun, _start, _end, _cont, _type, _name) { \
+ .altfun = _fun, \
+ .start = _start, \
+ .end = _end, \
+ .cont = _cont, \
+ .type = _type, \
+ .dev_name = _name }
+
#define __GPIO_RESOURCE(soc, block) \
{ \
- .start = soc##_GPIOBANK##block##_BASE, \
- .end = soc##_GPIOBANK##block##_BASE + 127, \
+ .start = U##soc##_GPIOBANK##block##_BASE, \
+ .end = U##soc##_GPIOBANK##block##_BASE + 127, \
.flags = IORESOURCE_MEM, \
}, \
{ \
- .start = IRQ_GPIO##block, \
- .end = IRQ_GPIO##block, \
+ .start = IRQ_DB##soc##_GPIO##block, \
+ .end = IRQ_DB##soc##_GPIO##block, \
.flags = IORESOURCE_IRQ, \
}
@@ -32,18 +198,19 @@
}, \
}
-#define GPIO_DATA(_name, first) \
+#define GPIO_DATA(_name, first, num) \
{ \
.name = _name, \
.first_gpio = first, \
.first_irq = NOMADIK_GPIO_TO_IRQ(first), \
+ .num_gpio = num, \
}
#ifdef CONFIG_UX500_SOC_DB8500
-#define GPIO_RESOURCE(block) __GPIO_RESOURCE(U8500, block)
+#define GPIO_RESOURCE(block) __GPIO_RESOURCE(8500, block)
#define GPIO_DEVICE(block) __GPIO_DEVICE(u8500, block)
#elif defined(CONFIG_UX500_SOC_DB5500)
-#define GPIO_RESOURCE(block) __GPIO_RESOURCE(U5500, block)
+#define GPIO_RESOURCE(block) __GPIO_RESOURCE(5500, block)
#define GPIO_DEVICE(block) __GPIO_DEVICE(u5500, block)
#endif
diff --git a/arch/arm/mach-ux500/include/mach/hardware.h b/arch/arm/mach-ux500/include/mach/hardware.h
index 8656379a830..1534e7a1544 100644
--- a/arch/arm/mach-ux500/include/mach/hardware.h
+++ b/arch/arm/mach-ux500/include/mach/hardware.h
@@ -51,10 +51,6 @@
#define UX500_GIC_CPU_BASE UX500(GIC_CPU)
#define UX500_GIC_DIST_BASE UX500(GIC_DIST)
-#define UX500_I2C1_BASE UX500(I2C1)
-#define UX500_I2C2_BASE UX500(I2C2)
-#define UX500_I2C3_BASE UX500(I2C3)
-
#define UX500_L2CC_BASE UX500(L2CC)
#define UX500_MCDE_BASE UX500(MCDE)
#define UX500_MTU0_BASE UX500(MTU0)
@@ -62,21 +58,12 @@
#define UX500_PRCMU_BASE UX500(PRCMU)
#define UX500_RNG_BASE UX500(RNG)
+#define UX500_HASH0_BASE UX500(HASH0)
+#define UX500_HASH1_BASE UX500(HASH1)
#define UX500_RTC_BASE UX500(RTC)
#define UX500_SCU_BASE UX500(SCU)
-#define UX500_SDI0_BASE UX500(SDI0)
-#define UX500_SDI1_BASE UX500(SDI1)
-#define UX500_SDI2_BASE UX500(SDI2)
-#define UX500_SDI3_BASE UX500(SDI3)
-#define UX500_SDI4_BASE UX500(SDI4)
-
-#define UX500_SPI0_BASE UX500(SPI0)
-#define UX500_SPI1_BASE UX500(SPI1)
-#define UX500_SPI2_BASE UX500(SPI2)
-#define UX500_SPI3_BASE UX500(SPI3)
-
#define UX500_SIA_BASE UX500(SIA)
#define UX500_SVA_BASE UX500(SVA)
@@ -89,12 +76,89 @@
#define UX500_USBOTG_BASE UX500(USBOTG)
/* ST-Ericsson modified pl022 id */
-#define SSP_PER_ID 0x01080022
+#define SSP_PER_ID 0x01080022
+#define SSP_PER_MASK 0x0fffffff
+
+/* SSP specific declaration */
+#define SPI_PER_ID 0x00080023
+#define SPI_PER_MASK 0x0fffffff
+
+/* MSP specific declaration */
+#define MSP_PER_ID 0x00280021
+#define MSP_PER_MASK 0x00ffffff
+
+/* DMA specific declaration */
+#define DMA_PER_ID 0x8A280080
+#define DMA_PER_MASK 0xffffffff
+
+#define GPIO_PER_ID 0x1f380060
+#define GPIO_PER_MASK 0xffffffff
+
+/* RTC specific declaration */
+#define RTC_PER_ID 0x00280031
+#define RTC_PER_MASK 0x00ffffff
+
+/*
+ * FIFO offsets for IPs
+ */
+#define I2C_TX_REG_OFFSET (0x10)
+#define I2C_RX_REG_OFFSET (0x18)
+#define UART_TX_RX_REG_OFFSET (0)
+#define MSP_TX_RX_REG_OFFSET (0)
+#define SSP_TX_RX_REG_OFFSET (0x8)
+#define SPI_TX_RX_REG_OFFSET (0x8)
+#define SD_MMC_TX_RX_REG_OFFSET (0x80)
+
+#define MSP_0_CONTROLLER 1
+#define MSP_1_CONTROLLER 2
+#define MSP_2_CONTROLLER 3
+#define MSP_3_CONTROLLER 4
+
+#define SSP_0_CONTROLLER 4
+#define SSP_1_CONTROLLER 5
+
+#define SPI023_0_CONTROLLER 6
+#define SPI023_1_CONTROLLER 7
+#define SPI023_2_CONTROLLER 8
+#define SPI023_3_CONTROLLER 9
+
+/* MSP related board specific declaration************************/
+
+#define MSP_DATA_DELAY MSP_DELAY_0
+#define MSP_TX_CLOCK_EDGE MSP_FALLING_EDGE
+#define MSP_RX_CLOCK_EDGE MSP_FALLING_EDGE
+#define NUM_MSP_CONTROLLER 3
+
+/* I2C configuration
+ * * *
+ * * */
+#define I2C0_LP_OWNADDR 0x31
+#define I2C1_LP_OWNADDR 0x60
+#define I2C2_LP_OWNADDR 0x70
+#define I2C3_LP_OWNADDR 0x80
+#define I2C4_LP_OWNADDR 0x90
+
+/* SDMMC specific declarations */
+#define SDI_PER_ID 0x00480180
+#define SDI_PER_MASK 0x00ffffff
+/* B2R2 clock management register */
+#define PRCM_B2R2CLK_MGT_REG 0x80157078 /** B2R2 clock selection */
+
+#define U8500_DSI_LINK1_BASE 0xA0351000
+#define U8500_DSI_LINK_SIZE 0x1000
+#define U8500_DSI_LINK_COUNT 0x3
+#define U8500_DSI_LINK2_BASE (U8500_DSI_LINK1_BASE + U8500_DSI_LINK_SIZE)
+#define U8500_DSI_LINK3_BASE (U8500_DSI_LINK2_BASE + U8500_DSI_LINK_SIZE)
#ifndef __ASSEMBLY__
#include <asm/cputype.h>
+#include <asm/mach-types.h>
+static inline bool machine_is_svp(void)
+{
+ return machine_is_svp8500v1() || machine_is_svp8500v2();
+}
static inline bool cpu_is_u8500(void)
{
#ifdef CONFIG_UX500_SOC_DB8500
@@ -104,16 +168,52 @@ static inline bool cpu_is_u8500(void)
#endif
}
+#define CPUID_DB8500ED 0x410fc090
+#define CPUID_DB8500V1 0x411fc091
+#define CPUID_DB8500V2 0x412fc091
+
static inline bool cpu_is_u8500ed(void)
{
- return cpu_is_u8500() && (read_cpuid_id() & 15) == 0;
+ /*
+ * SVP8500 unfortunately does not update the MIDR register on silicon
+ * revisions, but instead maintains the old ED value.
+ */
+ if (machine_is_svp())
+ return false;
+
+ return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500ED);
}
static inline bool cpu_is_u8500v1(void)
{
- return cpu_is_u8500() && (read_cpuid_id() & 15) == 1;
+ if (machine_is_svp8500v1())
+ return true;
+ else if (machine_is_svp8500v2())
+ return false;
+
+ return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V1);
}
+static inline bool cpu_is_u8500v2(void)
+{
+ if (machine_is_svp8500v1())
+ return false;
+ else if (machine_is_svp8500v2())
+ return true;
+
+ return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V2);
+}
+
+#ifdef CONFIG_UX500_SOC_DB8500
+bool cpu_is_u8500v10(void);
+bool cpu_is_u8500v11(void);
+bool cpu_is_u8500v20(void);
+#else
+static inline bool cpu_is_u8500v10(void) { return false; }
+static inline bool cpu_is_u8500v11(void) { return false; }
+static inline bool cpu_is_u8500v20(void) { return false; }
+#endif
+
static inline bool cpu_is_u5500(void)
{
#ifdef CONFIG_UX500_SOC_DB5500
diff --git a/arch/arm/mach-ux500/include/mach/hcl_defs.h b/arch/arm/mach-ux500/include/mach/hcl_defs.h
new file mode 100644
index 00000000000..efd37608cb3
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/hcl_defs.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _HCL_DEFS_H
+#define _HCL_DEFS_H
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+//#include "platform_os.h"
+
+/*-----------------------------------------------------------------------------
+ * Type definition
+ *---------------------------------------------------------------------------*/
+typedef unsigned char t_uint8;
+typedef signed char t_sint8;
+typedef unsigned short t_uint16;
+typedef signed short t_sint16;
+typedef unsigned long t_uint32;
+typedef signed long t_sint32;
+
+typedef unsigned int t_bitfield;
+
+
+
+#if !defined(FALSE) && !defined(TRUE)
+typedef int t_bool;
+#define FALSE 0
+#define TRUE 1
+#endif
+
+/*
+ * Definition of the different kind of addresses manipulated into a system with MMU
+ * (handle physical AND logical addresses)
+ */
+
+
+typedef t_uint32 t_physical_address;
+typedef t_uint32 t_logical_address;
+
+
+
+/*
+ * Global frequency enumuration
+ * Added to avoid frequency conversion function which is required to convert one HCL
+ * frequency enumuration values to another HCL frequency enumuration values.
+ */
+
+/*typedef enum {
+ HCL_FREQ_NOT_SUPPORTED=-1,
+ HCL_FREQ_8KHZ ,
+ HCL_FREQ_11_25KHZ,
+ HCL_FREQ_12KHZ,
+ HCL_FREQ_16KHZ,
+ HCL_FREQ_22_05KHZ,
+ HCL_FREQ_22_5KHZ,
+ HCL_FREQ_24KHZ,
+ HCL_FREQ_32KHZ,
+ HCL_FREQ_44KHZ,
+ HCL_FREQ_44_1KHZ,
+ HCL_FREQ_48KHZ,
+ HCL_FREQ_64KHZ,
+ HCL_FREQ_88KHZ,
+ HCL_FREQ_88_2KHZ,
+ HCL_FREQ_96KHZ,
+ HCL_FREQ_128KHZ,
+ HCL_FREQ_176_4KHZ,
+ HCL_FREQ_192KHZ,
+
+ HCL_FREQ_1MHZ,
+ HCL_FREQ_2MHZ,
+ HCL_FREQ_3MHZ,
+ HCL_FREQ_4MHZ,
+ HCL_FREQ_5MHZ,
+ HCL_FREQ_6MHZ,
+ HCL_FREQ_8MHZ,
+ HCL_FREQ_11MHZ,
+ HCL_FREQ_12MHZ,
+ HCL_FREQ_16MHZ,
+ HCL_FREQ_22MHZ,
+ HCL_FREQ_24MHZ,
+ HCL_FREQ_48MHZ
+} t_frequency;
+
+*/
+
+typedef struct {
+ t_physical_address physical;
+ t_logical_address logical;
+} t_system_address;
+
+
+/*
+ * Define a type used to manipulate size of various buffers
+ */
+typedef t_uint32 t_size;
+
+typedef struct {
+ t_bitfield minor:8;
+ t_bitfield major:8;
+ t_bitfield version:16;
+} t_version;
+
+
+
+
+/*-----------------------------------------------------------------------------
+ * Keyword definition
+ *---------------------------------------------------------------------------*/
+#define PUBLIC /* Extern by default */
+#define PRIVATE static
+
+#ifndef NULL
+#define NULL (0)
+#endif /* ndef NULL */
+
+
+/*-----------------------------------------------------------------------------
+ * Bit setting or clearing
+ *---------------------------------------------------------------------------*/
+#define HCL_SET_BITS(reg,mask) ((reg) |= (mask))
+#define HCL_CLEAR_BITS(reg,mask) ((reg) &= ~(mask))
+#define HCL_READ_BITS(reg,mask) ((reg) & (mask))
+#define HCL_WRITE_BITS(reg,val,mask) ((reg) = (((reg) & ~(mask)) | ((val) & (mask))))
+#define HCL_READ_REG(reg) (reg)
+#define HCL_WRITE_REG(reg,val) ((reg) = (val))
+
+/*-----------------------------------------------------------------------------
+ * field offset extraction from a structure
+ *---------------------------------------------------------------------------*/
+#define HCL_BITFIELD_OFFSET(typeName, fieldName) (t_uint32)(&(((typeName *)0)->fieldName))
+
+/*-----------------------------------------------------------------------------
+ * Bit mask definition
+ *---------------------------------------------------------------------------*/
+#define MASK_NULL8 0x00
+#define MASK_NULL16 0x0000
+#define MASK_NULL32 0x00000000
+#define MASK_ALL8 0xFF
+#define MASK_ALL16 0xFFFF
+#define MASK_ALL32 0xFFFFFFFF
+
+#define MASK_BIT0 (1UL<<0)
+#define MASK_BIT1 (1UL<<1)
+#define MASK_BIT2 (1UL<<2)
+#define MASK_BIT3 (1UL<<3)
+#define MASK_BIT4 (1UL<<4)
+#define MASK_BIT5 (1UL<<5)
+#define MASK_BIT6 (1UL<<6)
+#define MASK_BIT7 (1UL<<7)
+#define MASK_BIT8 (1UL<<8)
+#define MASK_BIT9 (1UL<<9)
+#define MASK_BIT10 (1UL<<10)
+#define MASK_BIT11 (1UL<<11)
+#define MASK_BIT12 (1UL<<12)
+#define MASK_BIT13 (1UL<<13)
+#define MASK_BIT14 (1UL<<14)
+#define MASK_BIT15 (1UL<<15)
+#define MASK_BIT16 (1UL<<16)
+#define MASK_BIT17 (1UL<<17)
+#define MASK_BIT18 (1UL<<18)
+#define MASK_BIT19 (1UL<<19)
+#define MASK_BIT20 (1UL<<20)
+#define MASK_BIT21 (1UL<<21)
+#define MASK_BIT22 (1UL<<22)
+#define MASK_BIT23 (1UL<<23)
+#define MASK_BIT24 (1UL<<24)
+#define MASK_BIT25 (1UL<<25)
+#define MASK_BIT26 (1UL<<26)
+#define MASK_BIT27 (1UL<<27)
+#define MASK_BIT28 (1UL<<28)
+#define MASK_BIT29 (1UL<<29)
+#define MASK_BIT30 (1UL<<30)
+#define MASK_BIT31 (1UL<<31)
+
+/*-----------------------------------------------------------------------------
+ * quartet shift definition
+ *---------------------------------------------------------------------------*/
+#define MASK_QUARTET (0xFUL)
+#define SHIFT_QUARTET0 0
+#define SHIFT_QUARTET1 4
+#define SHIFT_QUARTET2 8
+#define SHIFT_QUARTET3 12
+#define SHIFT_QUARTET4 16
+#define SHIFT_QUARTET5 20
+#define SHIFT_QUARTET6 24
+#define SHIFT_QUARTET7 28
+#define MASK_QUARTET0 (MASK_QUARTET << SHIFT_QUARTET0)
+#define MASK_QUARTET1 (MASK_QUARTET << SHIFT_QUARTET1)
+#define MASK_QUARTET2 (MASK_QUARTET << SHIFT_QUARTET2)
+#define MASK_QUARTET3 (MASK_QUARTET << SHIFT_QUARTET3)
+#define MASK_QUARTET4 (MASK_QUARTET << SHIFT_QUARTET4)
+#define MASK_QUARTET5 (MASK_QUARTET << SHIFT_QUARTET5)
+#define MASK_QUARTET6 (MASK_QUARTET << SHIFT_QUARTET6)
+#define MASK_QUARTET7 (MASK_QUARTET << SHIFT_QUARTET7)
+
+/*-----------------------------------------------------------------------------
+ * Byte shift definition
+ *---------------------------------------------------------------------------*/
+#define MASK_BYTE (0xFFUL)
+#define SHIFT_BYTE0 0
+#define SHIFT_BYTE1 8
+#define SHIFT_BYTE2 16
+#define SHIFT_BYTE3 24
+#define MASK_BYTE0 (MASK_BYTE << SHIFT_BYTE0)
+#define MASK_BYTE1 (MASK_BYTE << SHIFT_BYTE1)
+#define MASK_BYTE2 (MASK_BYTE << SHIFT_BYTE2)
+#define MASK_BYTE3 (MASK_BYTE << SHIFT_BYTE3)
+
+/*-----------------------------------------------------------------------------
+ * Halfword shift definition
+ *---------------------------------------------------------------------------*/
+#define MASK_HALFWORD (0xFFFFUL)
+#define SHIFT_HALFWORD0 0
+#define SHIFT_HALFWORD1 16
+#define MASK_HALFWORD0 (MASK_HALFWORD << SHIFT_HALFWORD0)
+#define MASK_HALFWORD1 (MASK_HALFWORD << SHIFT_HALFWORD1)
+
+/*-----------------------------------------------------------------------------
+ * Global constants definition
+ *---------------------------------------------------------------------------*/
+ #define ONE_KB (1024)
+ #define ONE_MB (ONE_KB * ONE_KB)
+
+
+/*-----------------------------------------------------------------------------
+ * Address translation macros declaration
+ *---------------------------------------------------------------------------*/
+
+#define ARM_TO_AHB_ADDR(addr) (addr)
+#define AHB_TO_ARM_ADDR(addr) (addr)
+
+/* For input parameters - would not be changed by the API */
+#define IN
+/* For output parameters - would be changes by the API */
+#define OUT
+/* For input-output parameters - provides input to the API but would be changed by the API */
+#define INOUT
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _HCL_DEFS_H */
+
+/* End of file hcl_defs.h */
+
+
diff --git a/arch/arm/mach-ux500/include/mach/hsi-stm.h b/arch/arm/mach-ux500/include/mach/hsi-stm.h
new file mode 100644
index 00000000000..584de78b73a
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/hsi-stm.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2007 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __HSI_STM_H__
+#define __HSI_STM_H__
+
+#include <plat/ste_dma40.h>
+
+#define HSI_DRIVER_AUTHOR "STMicroelectronics"
+#define HSI_DRIVER_DESC "High-Speed Synchronous Serial Interface Driver"
+
+#define DRIVER_NAME "DRIVER HSI"
+/* enables/disables debug msgs */
+#define DRIVER_DEBUG 0
+/* msg header represents this module */
+#define DRIVER_DEBUG_PFX DRIVER_NAME
+#define DRIVER_DBG KERN_ERR
+
+#define HSI_DRIVER_NAME "hsi_driver"
+
+#define HSI_DEVICE_NAME "hsi_device"
+#define HSI_TX_PREFIX "hsi_tx:"
+#define HSI_RX_PREFIX "hsi_rx:"
+#define HSI_PREFIX "hsi:"
+/** HSIT register offsets */
+#define HSI_TX_ID 0x0
+#define HSI_TX_MODE 0x4
+#define HSI_TX_STATE 0x8
+#define HSI_TX_IOSTATE 0xC
+#define HSI_TX_BUFSTATE 0x10
+#define HSI_TX_DIVISOR 0x14
+#define HSI_TX_PARITY 0x18
+#define HSI_TX_BREAK 0x1C
+#define HSI_TX_CHANNELS 0x20
+#define HSI_TX_FLUSHBITS 0x24
+#define HSI_TX_PRIORITY 0x28
+#define HSI_TX_BURSTLEN 0x2C
+#define HSI_TX_PREAMBLE 0x30
+#define HSI_TX_DATASWAP 0x34
+#define HSI_TX_FRAMELENX 0x80
+#define HSI_TX_BUFFERX 0xC0
+#define HSI_TX_BASEX 0x100
+#define HSI_TX_SPANX 0x140
+#define HSI_TX_GAUGEX 0x180
+#define HSI_TX_WATERMARKX 0x1C0
+#define HSI_TX_DMAEN 0x200
+#define HSI_TX_WATERMARKIS 0x204
+#define HSI_TX_WATERMARKIM 0x208
+#define HSI_TX_WATERMARKIC 0x20C
+#define HSI_TX_WATERMARKID 0x210
+#define HSI_TX_PERIPHID0 0xFE0
+#define HSI_TX_PERIPHID1 0xFE4
+#define HSI_TX_PERIPHID2 0xFE8
+#define HSI_TX_PERIPHID3 0xFEC
+
+
+/** HSIT register offsets */
+#define HSI_RX_ID 0x0
+#define HSI_RX_MODE 0x4
+#define HSI_RX_STATE 0x8
+#define HSI_RX_BUFSTATE 0xC
+#define HSI_RX_THRESHOLD 0x10
+#define HSI_RX_PARITY 0x14
+#define HSI_RX_DETECTOR 0x18
+#define HSI_RX_EXCEP 0x1C
+#define HSI_RX_ACK 0x20
+#define HSI_RX_CHANNELS 0x24
+#define HSI_RX_REALTIME 0x28
+#define HSI_RX_OVERRUN 0x2C
+#define HSI_RX_OVERRUNACK 0x30
+#define HSI_RX_PREAMBLE 0x34
+#define HSI_RX_PIPEGAUGE 0x38
+#define HSI_RX_TIMEOUT 0x3C
+#define HSI_RX_BUFFERX 0x80
+#define HSI_RX_FRAMELENX 0xC0
+#define HSI_RX_BASEX 0x100
+#define HSI_RX_SPANX 0x140
+#define HSI_RX_GAUGEX 0x180
+#define HSI_RX_WATERMARKX 0x1C0
+#define HSI_RX_DMAEN 0x200
+#define HSI_RX_WATERMARKIS 0x204
+#define HSI_RX_WATERMARKIM 0x208
+#define HSI_RX_WATERMARKIC 0x20C
+#define HSI_RX_WATERMARKID 0x210
+#define HSI_RX_OVERRUNMIS 0x214
+#define HSI_RX_OVERRUNIM 0x218
+#define HSI_RX_EXCEPMIS 0x21C
+#define HSI_RX_EXCEPIM 0x220
+#define HSI_RX_PERIPHID0 0xFE0
+#define HSI_RX_PERIPHID1 0xFE4
+#define HSI_RX_PERIPHID2 0xFE8
+#define HSI_RX_PERIPHID3 0xFEC
+
+/*
+ * Masks used to enable or disable the reception of certain hardware events
+ * for the hsi_device_drivers
+ */
+#define HSI_EVENT_CLEAR 0x00
+#define HSI_EVENT_MASK 0xFF
+#define HSI_EVENT_BREAK_DETECTED_MASK 0x01
+#define HSI_EVENT_ERROR_MASK 0x02
+
+#define HSI_CH_OPEN 0x1
+
+#define ANY_HSI_CONTROLLER -1
+#define ANY_CHANNEL -1
+#define CHANNEL(channel) (1<<channel)
+
+
+#define HSI_MAX_FRAMELEN 32
+#define PLAT_HSI_MAX_CHANNELS 8
+
+struct base_span {
+ u8 base;
+ u8 span;
+};
+
+struct hsi_plat_data {
+ u8 dev_type;
+ u8 mode;
+ u8 parity;
+ u8 priority;
+ u8 channels;
+ u8 threshold;
+ u8 flushbits;
+ u8 dataswap;
+ u8 realtime;
+ u8 detector;
+ u8 framelen;
+ u8 watermark;
+ u8 currmode;
+ gpio_alt_function gpio_alt_func;
+ u32 divisor;
+ u32 burstlen;
+ u32 preamble;
+ u32 timeout;
+ struct base_span ch_base_span[PLAT_HSI_MAX_CHANNELS];
+ struct stedma40_chan_cfg hsi_dma_info[PLAT_HSI_MAX_CHANNELS];
+ struct hsi_controller *controller;
+};
+
+struct hsi_algorithm;
+extern struct hsi_algorithm hsi_algo;
+int hsi_read_interrupt_mode(struct hsi_channel *chnl);
+int hsi_write_interrupt_mode(struct hsi_channel *chnl);
+void hsi_cancel_write_interrupt_mode(struct hsi_channel *chnl);
+void hsi_cancel_read_interrupt_mode(struct hsi_channel *chnl);
+
+irqreturn_t hsi_tx_irq_handler(int irq, void *ctrlr);
+irqreturn_t hsi_rx_irq_handler(int irq, void *ctrlr);
+irqreturn_t hsi_rxexcep_irq_handler(int irq, void *ctrlr);
+
+void do_hsi_tx_tasklet(unsigned long ctrlr);
+void do_hsi_rx_tasklet(unsigned long ctrlr);
+void do_hsi_tx_dma_tasklet(unsigned long ctrlr);
+void do_hsi_rx_dma_tasklet(unsigned long ctrlr);
+void do_hsi_rxexcep_tasklet(unsigned long ctrlr);
+void hsi_u8_writer(struct hsi_channel *ch);
+void hsi_u8_reader(struct hsi_channel *ch);
+void hsi_u16_writer(struct hsi_channel *ch);
+void hsi_u16_reader(struct hsi_channel *ch);
+void hsi_u32_writer(struct hsi_channel *ch);
+void hsi_u32_reader(struct hsi_channel *ch);
+void hsi_dma_read_eot_handler(void *data);
+void hsi_dma_write_eot_handler(void *data);
+
+void hsi_cancel_write_dma_mode(struct hsi_channel *chnl);
+void hsi_cancel_read_dma_mode(struct hsi_channel *chnl);
+/*DMA Functions*/
+int hsi_read_dma_mode(struct hsi_channel *chnl);
+int hsi_write_dma_mode(struct hsi_channel *chnl);
+
+#endif /* __HSI_STM_H__ */
diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
new file mode 100644
index 00000000000..575178c0cdf
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __MACH_IRQS_BOARD_MOP500_H
+#define __MACH_IRQS_BOARD_MOP500_H
+
+#define AB8500_NR_IRQS 112
+
+#define MOP500_AB8500_IRQ_BASE IRQ_BOARD_START
+#define MOP500_AB8500_IRQ_END (MOP500_AB8500_IRQ_BASE \
+ + AB8500_NR_IRQS)
+
+/* TC3589X irqs */
+#define TC35892_NR_INTERNAL_IRQS 8
+#define TC35892_INT_GPIO(x) (TC35892_NR_INTERNAL_IRQS + (x))
+#define TC35892_NR_GPIOS 24
+#define TC35892_NR_IRQS TC35892_INT_GPIO(TC35892_NR_GPIOS)
+
+#define MOP500_EGPIO_NR_IRQS TC35892_NR_IRQS
+
+#define MOP500_EGPIO_IRQ_BASE MOP500_AB8500_IRQ_END
+#define MOP500_EGPIO_IRQ(x) (MOP500_EGPIO_IRQ_BASE + (x))
+#define MOP500_EGPIO_IRQ_END (MOP500_EGPIO_IRQ_BASE \
+ + MOP500_EGPIO_NR_IRQS)
+/* STMPE1601 irqs */
+#define STMPE_NR_INTERNAL_IRQS 9
+#define STMPE_INT_GPIO(x) (STMPE_NR_INTERNAL_IRQS + (x))
+#define STMPE_NR_GPIOS 24
+#define STMPE_NR_IRQS STMPE_INT_GPIO(STMPE_NR_GPIOS)
+
+#define MOP500_STMPE1601_IRQBASE MOP500_EGPIO_IRQ_END
+#define MOP500_STMPE1601_IRQ(x) (MOP500_STMPE1601_IRQBASE + (x))
+
+#define MOP500_NR_IRQS MOP500_STMPE1601_IRQ(STMPE_NR_INTERNAL_IRQS)
+
+#define MOP500_IRQ_END MOP500_NR_IRQS
+
+#if MOP500_IRQ_END > IRQ_BOARD_END
+#undef IRQ_BOARD_END
+#define IRQ_BOARD_END MOP500_IRQ_END
+#endif
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h b/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h
new file mode 100644
index 00000000000..29d972c7717
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __MACH_IRQS_BOARD_U5500_H
+#define __MACH_IRQS_BOARD_U5500_H
+
+#define AB5500_NR_IRQS 5
+#define IRQ_AB5500_BASE IRQ_BOARD_START
+#define IRQ_AB5500_END (IRQ_AB5500_BASE + AB5500_NR_IRQS)
+
+#define U5500_IRQ_END IRQ_AB5500_END
+
+#if IRQ_BOARD_END < U5500_IRQ_END
+#undef IRQ_BOARD_END
+#define IRQ_BOARD_END U5500_IRQ_END
+#endif
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs-db5500.h b/arch/arm/mach-ux500/include/mach/irqs-db5500.h
new file mode 100644
index 00000000000..92b1fbf32bb
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/irqs-db5500.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __MACH_IRQS_DB5500_H
+#define __MACH_IRQS_DB5500_H
+
+#define IRQ_DB5500_MTU0 (IRQ_SHPI_START + 4)
+#define IRQ_DB5500_SPI2 (IRQ_SHPI_START + 6)
+#define IRQ_DB5500_PMU0 (IRQ_SHPI_START + 7)
+#define IRQ_DB5500_SPI0 (IRQ_SHPI_START + 8)
+#define IRQ_DB5500_RTT (IRQ_SHPI_START + 9)
+#define IRQ_DB5500_PKA (IRQ_SHPI_START + 10)
+#define IRQ_DB5500_UART0 (IRQ_SHPI_START + 11)
+#define IRQ_DB5500_I2C3 (IRQ_SHPI_START + 12)
+#define IRQ_DB5500_L2CC (IRQ_SHPI_START + 13)
+#define IRQ_DB5500_MSP0 (IRQ_SHPI_START + 14)
+#define IRQ_DB5500_CRYP1 (IRQ_SHPI_START + 15)
+#define IRQ_DB5500_PMU1 (IRQ_SHPI_START + 16)
+#define IRQ_DB5500_MTU1 (IRQ_SHPI_START + 17)
+#define IRQ_DB5500_RTC (IRQ_SHPI_START + 18)
+#define IRQ_DB5500_UART1 (IRQ_SHPI_START + 19)
+#define IRQ_DB5500_USB_WAKEUP (IRQ_SHPI_START + 20)
+#define IRQ_DB5500_I2C0 (IRQ_SHPI_START + 21)
+#define IRQ_DB5500_I2C1 (IRQ_SHPI_START + 22)
+#define IRQ_DB5500_USBOTG (IRQ_SHPI_START + 23)
+#define IRQ_DB5500_DMA_SECURE (IRQ_SHPI_START + 24)
+#define IRQ_DB5500_DMA (IRQ_SHPI_START + 25)
+#define IRQ_DB5500_UART2 (IRQ_SHPI_START + 26)
+#define IRQ_DB5500_ICN_PMU1 (IRQ_SHPI_START + 27)
+#define IRQ_DB5500_ICN_PMU2 (IRQ_SHPI_START + 28)
+#define IRQ_DB5500_UART3 (IRQ_SHPI_START + 29)
+#define IRQ_DB5500_SPI3 (IRQ_SHPI_START + 30)
+#define IRQ_DB5500_SDMMC4 (IRQ_SHPI_START + 31)
+#define IRQ_DB5500_IRRC (IRQ_SHPI_START + 33)
+#define IRQ_DB5500_IRDA_FT (IRQ_SHPI_START + 34)
+#define IRQ_DB5500_IRDA_SD (IRQ_SHPI_START + 35)
+#define IRQ_DB5500_IRDA_FI (IRQ_SHPI_START + 36)
+#define IRQ_DB5500_IRDA_FD (IRQ_SHPI_START + 37)
+#define IRQ_DB5500_FSMC_CODEREADY (IRQ_SHPI_START + 38)
+#define IRQ_DB5500_FSMC_NANDWAIT (IRQ_SHPI_START + 39)
+#define IRQ_DB5500_AB5500 (IRQ_SHPI_START + 40)
+#define IRQ_DB5500_SDMMC2 (IRQ_SHPI_START + 41)
+#define IRQ_DB5500_SIA (IRQ_SHPI_START + 42)
+#define IRQ_DB5500_SIA2 (IRQ_SHPI_START + 43)
+#define IRQ_DB5500_HVA (IRQ_SHPI_START + 44)
+#define IRQ_DB5500_HVA2 (IRQ_SHPI_START + 45)
+#define IRQ_DB5500_PRCMU0 (IRQ_SHPI_START + 46)
+#define IRQ_DB5500_PRCMU1 (IRQ_SHPI_START + 47)
+#define IRQ_DB5500_DISP (IRQ_SHPI_START + 48)
+#define IRQ_DB5500_SDMMC1 (IRQ_SHPI_START + 50)
+#define IRQ_DB5500_MSP1 (IRQ_SHPI_START + 52)
+#define IRQ_DB5500_KBD (IRQ_SHPI_START + 53)
+#define IRQ_DB5500_I2C2 (IRQ_SHPI_START + 55)
+#define IRQ_DB5500_B2R2 (IRQ_SHPI_START + 56)
+#define IRQ_DB5500_CRYP0 (IRQ_SHPI_START + 57)
+#define IRQ_DB5500_SDMMC3 (IRQ_SHPI_START + 59)
+#define IRQ_DB5500_SDMMC0 (IRQ_SHPI_START + 60)
+#define IRQ_DB5500_HSEM (IRQ_SHPI_START + 61)
+#define IRQ_DB5500_SBAG (IRQ_SHPI_START + 63)
+#define IRQ_DB5500_MODEM (IRQ_SHPI_START + 65)
+#define IRQ_DB5500_SPI1 (IRQ_SHPI_START + 96)
+#define IRQ_DB5500_MSP2 (IRQ_SHPI_START + 98)
+#define IRQ_DB5500_SRPTIMER (IRQ_SHPI_START + 101)
+#define IRQ_DB5500_CTI0 (IRQ_SHPI_START + 108)
+#define IRQ_DB5500_CTI1 (IRQ_SHPI_START + 109)
+#define IRQ_DB5500_ICN_ERR (IRQ_SHPI_START + 110)
+#define IRQ_DB5500_MALI_PPMMU (IRQ_SHPI_START + 112)
+#define IRQ_DB5500_MALI_PP (IRQ_SHPI_START + 113)
+#define IRQ_DB5500_MALI_GPMMU (IRQ_SHPI_START + 114)
+#define IRQ_DB5500_MALI_GP (IRQ_SHPI_START + 115)
+#define IRQ_DB5500_MALI (IRQ_SHPI_START + 116)
+#define IRQ_DB5500_PRCMU_SEM (IRQ_SHPI_START + 118)
+#define IRQ_DB5500_GPIO0 (IRQ_SHPI_START + 119)
+#define IRQ_DB5500_GPIO1 (IRQ_SHPI_START + 120)
+#define IRQ_DB5500_GPIO2 (IRQ_SHPI_START + 121)
+#define IRQ_DB5500_GPIO3 (IRQ_SHPI_START + 122)
+#define IRQ_DB5500_GPIO4 (IRQ_SHPI_START + 123)
+#define IRQ_DB5500_GPIO5 (IRQ_SHPI_START + 124)
+#define IRQ_DB5500_GPIO6 (IRQ_SHPI_START + 125)
+#define IRQ_DB5500_GPIO7 (IRQ_SHPI_START + 126)
+
+#ifdef CONFIG_UX500_SOC_DB5500
+
+/*
+ * After the GPIO ones we reserve a range of IRQ:s in which virtual
+ * IRQ:s representing modem IRQ:s can be allocated
+ */
+#define IRQ_MODEM_EVENTS_BASE IRQ_SOC_START
+#define IRQ_MODEM_EVENTS_NBR 72
+#define IRQ_MODEM_EVENTS_END (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
+
+/* List of virtual IRQ:s that are allocated from the range above */
+#define MBOX_PAIR0_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 43)
+#define MBOX_PAIR1_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 45)
+#define MBOX_PAIR2_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 41)
+
+#if IRQ_SOC_END < IRQ_MODEM_EVENTS_END
+#undef IRQ_SOC_END
+#define IRQ_SOC_END IRQ_MODEM_EVENTS_END
+#endif
+
+#endif /* CONFIG_UX500_SOC_DB5500 */
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs-db8500.h b/arch/arm/mach-ux500/include/mach/irqs-db8500.h
new file mode 100644
index 00000000000..9fbf67bebbc
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/irqs-db8500.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __MACH_IRQS_DB8500_H
+#define __MACH_IRQS_DB8500_H
+
+#define IRQ_DB8500_MTU0 (IRQ_SHPI_START + 4)
+#define IRQ_DB8500_SPI2 (IRQ_SHPI_START + 6)
+#define IRQ_DB8500_PMU (IRQ_SHPI_START + 7)
+#define IRQ_DB8500_SPI0 (IRQ_SHPI_START + 8)
+#define IRQ_DB8500_RTT (IRQ_SHPI_START + 9)
+#define IRQ_DB8500_PKA (IRQ_SHPI_START + 10)
+#define IRQ_DB8500_UART0 (IRQ_SHPI_START + 11)
+#define IRQ_DB8500_I2C3 (IRQ_SHPI_START + 12)
+#define IRQ_DB8500_L2CC (IRQ_SHPI_START + 13)
+#define IRQ_DB8500_SSP0 (IRQ_SHPI_START + 14)
+#define IRQ_DB8500_CRYP1 (IRQ_SHPI_START + 15)
+#define IRQ_DB8500_MSP1_RX (IRQ_SHPI_START + 16)
+#define IRQ_DB8500_MTU1 (IRQ_SHPI_START + 17)
+#define IRQ_DB8500_RTC (IRQ_SHPI_START + 18)
+#define IRQ_DB8500_UART1 (IRQ_SHPI_START + 19)
+#define IRQ_DB8500_USB_WAKEUP (IRQ_SHPI_START + 20)
+#define IRQ_DB8500_I2C0 (IRQ_SHPI_START + 21)
+#define IRQ_DB8500_I2C1 (IRQ_SHPI_START + 22)
+#define IRQ_DB8500_USBOTG (IRQ_SHPI_START + 23)
+#define IRQ_DB8500_DMA_SECURE (IRQ_SHPI_START + 24)
+#define IRQ_DB8500_DMA (IRQ_SHPI_START + 25)
+#define IRQ_DB8500_UART2 (IRQ_SHPI_START + 26)
+#define IRQ_DB8500_ICN_PMU1 (IRQ_SHPI_START + 27)
+#define IRQ_DB8500_ICN_PMU2 (IRQ_SHPI_START + 28)
+#define IRQ_DB8500_HSIR_EXCEP (IRQ_SHPI_START + 29)
+#define IRQ_DB8500_MSP0 (IRQ_SHPI_START + 31)
+#define IRQ_DB8500_HSIR_CH0_OVRRUN (IRQ_SHPI_START + 32)
+#define IRQ_DB8500_HSIR_CH1_OVRRUN (IRQ_SHPI_START + 33)
+#define IRQ_DB8500_HSIR_CH2_OVRRUN (IRQ_SHPI_START + 34)
+#define IRQ_DB8500_HSIR_CH3_OVRRUN (IRQ_SHPI_START + 35)
+#define IRQ_DB8500_HSIR_CH4_OVRRUN (IRQ_SHPI_START + 36)
+#define IRQ_DB8500_HSIR_CH5_OVRRUN (IRQ_SHPI_START + 37)
+#define IRQ_DB8500_HSIR_CH6_OVRRUN (IRQ_SHPI_START + 38)
+#define IRQ_DB8500_HSIR_CH7_OVRRUN (IRQ_SHPI_START + 39)
+#define IRQ_DB8500_AB8500 (IRQ_SHPI_START + 40)
+#define IRQ_DB8500_SDMMC2 (IRQ_SHPI_START + 41)
+#define IRQ_DB8500_SIA (IRQ_SHPI_START + 42)
+#define IRQ_DB8500_SIA2 (IRQ_SHPI_START + 43)
+#define IRQ_DB8500_SVA (IRQ_SHPI_START + 44)
+#define IRQ_DB8500_SVA2 (IRQ_SHPI_START + 45)
+#define IRQ_DB8500_PRCMU0 (IRQ_SHPI_START + 46)
+#define IRQ_DB8500_PRCMU1 (IRQ_SHPI_START + 47)
+#define IRQ_DB8500_DISP (IRQ_SHPI_START + 48)
+#define IRQ_DB8500_SPI3 (IRQ_SHPI_START + 49)
+#define IRQ_DB8500_SDMMC1 (IRQ_SHPI_START + 50)
+#define IRQ_DB8500_I2C4 (IRQ_SHPI_START + 51)
+#define IRQ_DB8500_SSP1 (IRQ_SHPI_START + 52)
+#define IRQ_DB8500_SKE (IRQ_SHPI_START + 53)
+#define IRQ_DB8500_KB (IRQ_SHPI_START + 54)
+#define IRQ_DB8500_I2C2 (IRQ_SHPI_START + 55)
+#define IRQ_DB8500_B2R2 (IRQ_SHPI_START + 56)
+#define IRQ_DB8500_CRYP0 (IRQ_SHPI_START + 57)
+#define IRQ_DB8500_SDMMC3 (IRQ_SHPI_START + 59)
+#define IRQ_DB8500_SDMMC0 (IRQ_SHPI_START + 60)
+#define IRQ_DB8500_HSEM (IRQ_SHPI_START + 61)
+#define IRQ_DB8500_MSP1 (IRQ_SHPI_START + 62)
+#define IRQ_DB8500_SBAG (IRQ_SHPI_START + 63)
+#define IRQ_DB8500_SPI1 (IRQ_SHPI_START + 96)
+#define IRQ_DB8500_SRPTIMER (IRQ_SHPI_START + 97)
+#define IRQ_DB8500_MSP2 (IRQ_SHPI_START + 98)
+#define IRQ_DB8500_SDMMC4 (IRQ_SHPI_START + 99)
+#define IRQ_DB8500_SDMMC5 (IRQ_SHPI_START + 100)
+#define IRQ_DB8500_HSIRD0 (IRQ_SHPI_START + 104)
+#define IRQ_DB8500_HSIRD1 (IRQ_SHPI_START + 105)
+#define IRQ_DB8500_HSITD0 (IRQ_SHPI_START + 106)
+#define IRQ_DB8500_HSITD1 (IRQ_SHPI_START + 107)
+#define IRQ_DB8500_CTI0 (IRQ_SHPI_START + 108)
+#define IRQ_DB8500_CTI1 (IRQ_SHPI_START + 109)
+#define IRQ_DB8500_ICN_ERR (IRQ_SHPI_START + 110)
+#define IRQ_DB8500_MALI_PPMMU (IRQ_SHPI_START + 112)
+#define IRQ_DB8500_MALI_PP (IRQ_SHPI_START + 113)
+#define IRQ_DB8500_MALI_GPMMU (IRQ_SHPI_START + 114)
+#define IRQ_DB8500_MALI_GP (IRQ_SHPI_START + 115)
+#define IRQ_DB8500_MALI (IRQ_SHPI_START + 116)
+#define IRQ_DB8500_PRCMU_SEM (IRQ_SHPI_START + 118)
+#define IRQ_DB8500_GPIO0 (IRQ_SHPI_START + 119)
+#define IRQ_DB8500_GPIO1 (IRQ_SHPI_START + 120)
+#define IRQ_DB8500_GPIO2 (IRQ_SHPI_START + 121)
+#define IRQ_DB8500_GPIO3 (IRQ_SHPI_START + 122)
+#define IRQ_DB8500_GPIO4 (IRQ_SHPI_START + 123)
+#define IRQ_DB8500_GPIO5 (IRQ_SHPI_START + 124)
+#define IRQ_DB8500_GPIO6 (IRQ_SHPI_START + 125)
+#define IRQ_DB8500_GPIO7 (IRQ_SHPI_START + 126)
+#define IRQ_DB8500_GPIO8 (IRQ_SHPI_START + 127)
+
+#ifdef CONFIG_UX500_SOC_DB8500
+
+/* Virtual interrupts corresponding to the PRCMU wakeups. */
+#define IRQ_PRCMU_BASE IRQ_SOC_START
+#define NUM_PRCMU_WAKEUPS (IRQ_PRCMU_END - IRQ_PRCMU_BASE)
+
+#define IRQ_PRCMU_RTC (IRQ_PRCMU_BASE)
+#define IRQ_PRCMU_RTT0 (IRQ_PRCMU_BASE + 1)
+#define IRQ_PRCMU_RTT1 (IRQ_PRCMU_BASE + 2)
+#define IRQ_PRCMU_HSI0 (IRQ_PRCMU_BASE + 3)
+#define IRQ_PRCMU_HSI1 (IRQ_PRCMU_BASE + 4)
+#define IRQ_PRCMU_CA_WAKE (IRQ_PRCMU_BASE + 5)
+#define IRQ_PRCMU_USB (IRQ_PRCMU_BASE + 6)
+#define IRQ_PRCMU_ABB (IRQ_PRCMU_BASE + 7)
+#define IRQ_PRCMU_ABB_FIFO (IRQ_PRCMU_BASE + 8)
+#define IRQ_PRCMU_ARM (IRQ_PRCMU_BASE + 9)
+#define IRQ_PRCMU_MODEM_SW_RESET_REQ (IRQ_PRCMU_BASE + 10)
+#define IRQ_PRCMU_GPIO0 (IRQ_PRCMU_BASE + 11)
+#define IRQ_PRCMU_GPIO1 (IRQ_PRCMU_BASE + 12)
+#define IRQ_PRCMU_GPIO2 (IRQ_PRCMU_BASE + 13)
+#define IRQ_PRCMU_GPIO3 (IRQ_PRCMU_BASE + 14)
+#define IRQ_PRCMU_GPIO4 (IRQ_PRCMU_BASE + 15)
+#define IRQ_PRCMU_GPIO5 (IRQ_PRCMU_BASE + 16)
+#define IRQ_PRCMU_GPIO6 (IRQ_PRCMU_BASE + 17)
+#define IRQ_PRCMU_GPIO7 (IRQ_PRCMU_BASE + 18)
+#define IRQ_PRCMU_GPIO8 (IRQ_PRCMU_BASE + 19)
+#define IRQ_PRCMU_CA_SLEEP (IRQ_PRCMU_BASE + 20)
+#define IRQ_PRCMU_END (IRQ_PRCMU_BASE + 21)
+
+#if IRQ_SOC_END < IRQ_PRCMU_END
+#undef IRQ_SOC_END
+#define IRQ_SOC_END IRQ_PRCMU_END
+#endif
+
+#endif /* CONFIG_UX500_SOC_DB8500 */
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs.h b/arch/arm/mach-ux500/include/mach/irqs.h
index 7970684b1d0..d274b46c582 100644
--- a/arch/arm/mach-ux500/include/mach/irqs.h
+++ b/arch/arm/mach-ux500/include/mach/irqs.h
@@ -20,59 +20,73 @@
/* Interrupt numbers generic for shared peripheral */
#define IRQ_MTU0 (IRQ_SHPI_START + 4)
-#define IRQ_SPI2 (IRQ_SHPI_START + 6)
-#define IRQ_SPI0 (IRQ_SHPI_START + 8)
-#define IRQ_UART0 (IRQ_SHPI_START + 11)
-#define IRQ_I2C3 (IRQ_SHPI_START + 12)
-#define IRQ_SSP0 (IRQ_SHPI_START + 14)
#define IRQ_MTU1 (IRQ_SHPI_START + 17)
#define IRQ_RTC_RTT (IRQ_SHPI_START + 18)
-#define IRQ_UART1 (IRQ_SHPI_START + 19)
-#define IRQ_I2C0 (IRQ_SHPI_START + 21)
-#define IRQ_I2C1 (IRQ_SHPI_START + 22)
#define IRQ_USBOTG (IRQ_SHPI_START + 23)
#define IRQ_DMA (IRQ_SHPI_START + 25)
-#define IRQ_UART2 (IRQ_SHPI_START + 26)
#define IRQ_HSIR_EXCEP (IRQ_SHPI_START + 29)
-#define IRQ_MSP0 (IRQ_SHPI_START + 31)
#define IRQ_HSIR_CH0_OVRRUN (IRQ_SHPI_START + 32)
#define IRQ_HSIR_CH1_OVRRUN (IRQ_SHPI_START + 33)
#define IRQ_HSIR_CH2_OVRRUN (IRQ_SHPI_START + 34)
#define IRQ_HSIR_CH3_OVRRUN (IRQ_SHPI_START + 35)
-#define IRQ_AB4500 (IRQ_SHPI_START + 40)
+#define IRQ_AB8500 (IRQ_SHPI_START + 40)
+#define IRQ_SIA_IT0 (IRQ_SHPI_START + 42)
+#define IRQ_SIA_IT1 (IRQ_SHPI_START + 43)
+#define IRQ_SVA_IT0 (IRQ_SHPI_START + 44)
+#define IRQ_SVA_IT1 (IRQ_SHPI_START + 45)
+#define IRQ_PRCM_ACK_MBOX (IRQ_SHPI_START + 47)
#define IRQ_DISP (IRQ_SHPI_START + 48)
-#define IRQ_SiPI3 (IRQ_SHPI_START + 49)
-#define IRQ_I2C4 (IRQ_SHPI_START + 51)
-#define IRQ_SSP1 (IRQ_SHPI_START + 52)
-#define IRQ_I2C2 (IRQ_SHPI_START + 55)
-#define IRQ_SDMMC0 (IRQ_SHPI_START + 60)
-#define IRQ_MSP1 (IRQ_SHPI_START + 62)
-#define IRQ_SPI1 (IRQ_SHPI_START + 96)
-#define IRQ_MSP2 (IRQ_SHPI_START + 98)
-#define IRQ_SDMMC4 (IRQ_SHPI_START + 99)
+#define IRQ_HWSEM (IRQ_SHPI_START + 61)
+#define IRQ_MODEM (IRQ_SHPI_START + 65)
#define IRQ_HSIRD0 (IRQ_SHPI_START + 104)
#define IRQ_HSIRD1 (IRQ_SHPI_START + 105)
#define IRQ_HSITD0 (IRQ_SHPI_START + 106)
#define IRQ_HSITD1 (IRQ_SHPI_START + 107)
-#define IRQ_GPIO0 (IRQ_SHPI_START + 119)
-#define IRQ_GPIO1 (IRQ_SHPI_START + 120)
-#define IRQ_GPIO2 (IRQ_SHPI_START + 121)
-#define IRQ_GPIO3 (IRQ_SHPI_START + 122)
-#define IRQ_GPIO4 (IRQ_SHPI_START + 123)
-#define IRQ_GPIO5 (IRQ_SHPI_START + 124)
-#define IRQ_GPIO6 (IRQ_SHPI_START + 125)
-#define IRQ_GPIO7 (IRQ_SHPI_START + 126)
-#define IRQ_GPIO8 (IRQ_SHPI_START + 127)
-
-/* There are 128 shared peripheral interrupts assigned to
- * INTID[160:32]. The first 32 interrupts are reserved.
- */
-#define U8500_SOC_NR_IRQS 161
+#define IRQ_B2R2 (IRQ_SHPI_START + 56)
+
+#define IRQ_CA_WAKE_REQ_ED (IRQ_SHPI_START + 71)
+#define IRQ_AC_READ_NOTIFICATION_0_ED (IRQ_SHPI_START + 66)
+#define IRQ_AC_READ_NOTIFICATION_1_ED (IRQ_SHPI_START + 64)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_0_ED (IRQ_SHPI_START + 67)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_1_ED (IRQ_SHPI_START + 65)
+
+#define IRQ_CA_WAKE_REQ_V1 (IRQ_SHPI_START + 83)
+#define IRQ_AC_READ_NOTIFICATION_0_V1 (IRQ_SHPI_START + 78)
+#define IRQ_AC_READ_NOTIFICATION_1_V1 (IRQ_SHPI_START + 76)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_0_V1 (IRQ_SHPI_START + 79)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_1_V1 (IRQ_SHPI_START + 77)
+
+#define DBX500_NR_INTERNAL_IRQS 160
/* After chip-specific IRQ numbers we have the GPIO ones */
-#define NOMADIK_NR_GPIO 288
-#define NOMADIK_GPIO_TO_IRQ(gpio) ((gpio) + U8500_SOC_NR_IRQS)
-#define NOMADIK_IRQ_TO_GPIO(irq) ((irq) - U8500_SOC_NR_IRQS)
-#define NR_IRQS NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
+#define U8500_NR_GPIO 268
+#define GPIO_TO_IRQ(gpio) (gpio + DBX500_NR_INTERNAL_IRQS)
+#define IRQ_TO_GPIO(irq) (irq - DBX500_NR_INTERNAL_IRQS)
+
+#define NOMADIK_GPIO_TO_IRQ GPIO_TO_IRQ
+#define NOMADIK_IRQ_TO_GPIO IRQ_TO_GPIO
+#define IRQ_GPIO_END NOMADIK_GPIO_TO_IRQ(U8500_NR_GPIO)
+
+#define IRQ_SOC_START IRQ_GPIO_END
+/* This will be overridden by SoC-specific irq headers */
+#define IRQ_SOC_END IRQ_SOC_START
+
+#include <mach/irqs-db5500.h>
+#include <mach/irqs-db8500.h>
+
+#define IRQ_BOARD_START IRQ_SOC_END
+/* This will be overridden by board-specific irq headers */
+#define IRQ_BOARD_END IRQ_BOARD_START
+
+#if defined(CONFIG_MACH_U8500_MOP) || defined(CONFIG_MACH_U8500_PDP) || \
+ defined(CONFIG_MACH_U8500_SIMULATOR)
+#include <mach/irqs-board-mop500.h>
+#endif
+
+#if defined(CONFIG_MACH_U5500_BB) || defined(CONFIG_MACH_U5500_SIMULATOR)
+#include <mach/irqs-board-u5500.h>
+#endif
+
+#define NR_IRQS IRQ_BOARD_END
-#endif /*ASM_ARCH_IRQS_H*/
+#endif /* ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-ux500/include/mach/isa_ioctl.h b/arch/arm/mach-ux500/include/mach/isa_ioctl.h
new file mode 100644
index 00000000000..b05726f8c3c
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/isa_ioctl.h
@@ -0,0 +1,51 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright ST Ericsson, 2009. */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2.1 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
+/* See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*---------------------------------------------------------------------------*/
+#ifndef __MODEM_IPC_INCLUDED
+#define __MODEM_IPC_INCLUDED
+
+#define DLP_IOCTL_MAGIC_NUMBER 'M'
+#define COMMON_BUFFER_SIZE (1024*1024)
+
+/**
+DLP Message Structure for Userland
+*/
+struct t_dlp_message{
+ unsigned int offset;
+ unsigned int size;
+};
+
+/**
+mmap constants.
+*/
+enum t_dlp_mmap_params {
+ MMAP_DLQUEUE,
+ MMAP_ULQUEUE
+};
+
+/**
+DLP IOCTLs for Userland
+*/
+#define DLP_IOC_ALLOCATE_BUFFER \
+ _IOWR(DLP_IOCTL_MAGIC_NUMBER, 0, struct t_dlp_message *)
+#define DLP_IOC_DEALLOCATE_BUFFER \
+ _IOWR(DLP_IOCTL_MAGIC_NUMBER, 1, struct t_dlp_message *)
+#define DLP_IOC_GET_MESSAGE \
+ _IOWR(DLP_IOCTL_MAGIC_NUMBER, 2, struct t_dlp_message *)
+#define DLP_IOC_PUT_MESSAGE \
+ _IOWR(DLP_IOCTL_MAGIC_NUMBER, 3, struct t_dlp_message *)
+
+#endif /*__MODEM_IPC_INCLUDED*/
+
diff --git a/arch/arm/mach-ux500/include/mach/kpd.h b/arch/arm/mach-ux500/include/mach/kpd.h
new file mode 100644
index 00000000000..ffff8eea193
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/kpd.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright STMicroelectronics, 2009.
+ * Copyright (C) 2009 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ */
+
+#ifndef __U8500_KPD_H
+#define __U8500_KPD_H
+
+#ifndef CONFIG_AUTOSCAN_ENABLED
+#define CONFIG_AUTOSCAN_ENABLED 1
+#endif
+#include <mach/hardware.h>
+#include <linux/clk.h>
+
+#define MAX_KPROW 8
+#define MAX_KPCOL 8
+#define MAX_KEYS (MAX_KPROW * MAX_KPCOL)
+/*keypad related Constants*/
+#define KEYPAD_RELEASE_PERIOD 11 /*11 msec, repeate key scan time */
+#define KEYPAD_SCAN_PERIOD 4 /*4msec for new keypress */
+#define KEYPAD_STATE_DEFAULT 0
+#define KEYPAD_STATE_PRESSED 1
+#define KEYPAD_STATE_PRESSACK 2
+#define KEYPAD_STATE_RELEASED 3
+#define KEYPAD_STATE_RELEASEACK 2
+
+#define KPINTR_LKBIT 0 /*bit used for interrupt locking */
+
+struct keypad_t;
+/**
+ * struct keypad_device - Device data structure for platform specific data
+ * @init: pointer to keypad init function
+ * @exit: pointer to keypad deinitialisation function
+ * @autoscan_check: pointer to read autoscan status function
+ * currently
+ * @autoscan_disable: pointer to autoscan feature disable function,
+ * not used currently
+ * @autoscan_results: pointer to read autoscan results function
+ * @autoscan_en: pointer to enable autoscan feature function
+ * currently
+ * @irqen: pointer to enable irq function
+ * @irqdis: pointer to disable irq function
+ * @kcode_tbl: lookup table for keycodes
+ * @krow: mask for available rows, value is 0xFF
+ * @kcol: mask for available columns, value is 0xFF
+ * @irqdis_int: pointer to disable irq function, to be called from ISR
+ * @debounce_period: platform specific debounce time, can be fine tuned later
+ * @irqtype: type of interrupt
+ * @irq: irq no,
+ * @int_status: interrupt status
+ * @int_line_behaviour: dynamis interrupt line behaviour
+ * @enable_wakeup: specifies if keypad event can wake up system from sleep
+ */
+struct keypad_device {
+ int (*init)(struct keypad_t *kp);
+ int (*exit)(struct keypad_t *kp);
+ int (*autoscan_check)(void);
+ void (*autoscan_disable)(void);
+ int (*autoscan_results)(struct keypad_t *kp);
+ void (*autoscan_en)(void);
+ int (*irqen)(struct keypad_t *kp);
+ int (*irqdis)(struct keypad_t *kp);
+ u8 *kcode_tbl;
+ u8 krow;
+ u8 kcol;
+ int (*irqdis_int)(struct keypad_t *kp);
+ u8 debounce_period;
+ unsigned long irqtype;
+ u8 irq;
+ u8 int_status;
+ u8 int_line_behaviour;
+ bool enable_wakeup;
+};
+/**
+ * struct keypad_t - keypad data structure used internally by keypad driver
+ * @irq: irq no
+ * @mode: 0 for interrupt mode, 1 for polling mode
+ * @ske_regs: ske regsiters base address
+ * @cr_lock: spinlock variable
+ * @key_state: array for saving keystates
+ * @lockbits: used for synchronisation in ISR
+ * @inp_dev: pointer to input device object
+ * @kscan_work: work queue
+ * @board: keypad platform device
+ * @key_cnt: count the keys pressed
+ * @clk: clock structure pointer
+ */
+struct keypad_t {
+ int irq;
+ int mode;
+ void __iomem *ske_regs;
+ int key_state[MAX_KPROW][MAX_KPCOL];
+ unsigned long lockbits;
+ spinlock_t cr_lock;
+ struct input_dev *inp_dev;
+ struct delayed_work kscan_work;
+ struct keypad_device *board;
+ int key_cnt;
+ struct clk *clk;
+};
+/**
+ * enum kp_int_status - enum for INTR status
+ * @KP_INT_DISABLED: interrupt disabled
+ * @KP_INT_ENABLED: interrupt enabled
+ */
+enum kp_int_status {
+ KP_INT_DISABLED = 0,
+ KP_INT_ENABLED,
+};
+/**
+ *enum kp_int_line_behaviour - enum for kp_int_line dynamic status
+ * @INT_LINE_NOTSET: IRQ not asserted
+ * @INT_LINE_SET: IRQ asserted
+ */
+enum kp_int_line_behaviour {
+ INT_LINE_NOTSET = 0,
+ INT_LINE_SET,
+};
+#endif /*__U8500_KPD_H*/
diff --git a/arch/arm/mach-ux500/include/mach/mbox.h b/arch/arm/mach-ux500/include/mach/mbox.h
new file mode 100644
index 00000000000..7f9da4d2fbd
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/mbox.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
+ * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __INC_STE_MBOX_H
+#define __INC_STE_MBOX_H
+
+#define MBOX_BUF_SIZE 16
+#define MBOX_NAME_SIZE 8
+
+/**
+ * mbox_recv_cb_t - Definition of the mailbox callback.
+ * @mbox_msg: The mailbox message.
+ * @priv: The clients private data as specified in the call to mbox_setup.
+ *
+ * This function will be called upon reception of new mailbox messages.
+ */
+typedef void mbox_recv_cb_t (u32 mbox_msg, void *priv);
+
+/**
+ * struct mbox - Mailbox instance struct
+ * @list: Linked list head.
+ * @pdev: Pointer to device struct.
+ * @cb: Callback function. Will be called
+ * when new data is received.
+ * @client_data: Clients private data. Will be sent back
+ * in the callback function.
+ * @virtbase_peer: Virtual address for outgoing mailbox.
+ * @virtbase_local: Virtual address for incoming mailbox.
+ * @buffer: Then internal queue for outgoing messages.
+ * @name: Name of this mailbox.
+ * @buffer_available: Completion variable to achieve "blocking send".
+ * This variable will be signaled when there is
+ * internal buffer space available.
+ * @client_blocked: To keep track if any client is currently
+ * blocked.
+ * @lock: Spinlock to protect this mailbox instance.
+ * @write_index: Index in internal buffer to write to.
+ * @read_index: Index in internal buffer to read from.
+ * @allocated: Indicates whether this particular mailbox
+ * id has been allocated by someone.
+ */
+struct mbox {
+ struct list_head list;
+ struct platform_device *pdev;
+ mbox_recv_cb_t *cb;
+ void *client_data;
+ void __iomem *virtbase_peer;
+ void __iomem *virtbase_local;
+ u32 buffer[MBOX_BUF_SIZE];
+ char name[MBOX_NAME_SIZE];
+ struct completion buffer_available;
+ u8 client_blocked;
+ spinlock_t lock;
+ u8 write_index;
+ u8 read_index;
+ bool allocated;
+};
+
+/**
+ * mbox_setup - Set up a mailbox and return its instance.
+ * @mbox_id: The ID number of the mailbox. 0 or 1 for modem CPU,
+ * 2 for modem DSP.
+ * @mbox_cb: Pointer to the callback function to be called when a new message
+ * is received.
+ * @priv: Client user data which will be returned in the callback.
+ *
+ * Returns a mailbox instance to be specified in subsequent calls to mbox_send.
+ */
+struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv);
+
+/**
+ * mbox_send - Send a mailbox message.
+ * @mbox: Mailbox instance (returned by mbox_setup)
+ * @mbox_msg: The mailbox message to send.
+ * @block: Specifies whether this call will block until send is possible,
+ * or return an error if the mailbox buffer is full.
+ *
+ * Returns 0 on success or a negative error code on error. -ENOMEM indicates
+ * that the internal buffer is full and you have to try again later (or
+ * specify "block" in order to block until send is possible).
+ */
+int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block);
+
+#endif /*INC_STE_MBOX_H*/
diff --git a/arch/arm/mach-ux500/include/mach/mmc.h b/arch/arm/mach-ux500/include/mach/mmc.h
new file mode 100644
index 00000000000..8ff829d304c
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/mmc.h
@@ -0,0 +1,384 @@
+/*
+ * Overview:
+ * SD/EMMC driver for u8500 platform
+ *
+ * Copyright (C) 2009 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*-------------------------------------------------------------------------
+ * SDI controller configuration
+ * Kernel entry point for sdmmc/emmc chip
+ *-------------------------------------------------------------------------
+ * <VERSION>v1.0.0
+ *-------------------------------------------------------------------------
+ */
+/*------------------------------i-----------------------------------------*/
+
+#ifndef MACH_MMC_H
+#define MACH_MMC_H
+
+#include <linux/dmaengine.h>
+
+/*
+ * SDI Power register offset
+ */
+#define MMCIPOWER 0x000
+/*
+ * SDI Power register bits
+ */
+#define MCI_PWR_OFF 0x00
+#define MCI_PWR_UP 0x02
+#define MCI_PWR_ON 0x03
+#define MCI_STATE_ENABLE 0x38
+#define MCI_OPEN_DRAIN (1 << 6)
+#define MCI_FBCLK_ENABLE (1 << 7)
+#define MCI_POWER_IOS_MASK \
+ (MCI_PWR_ON | MCI_DIREN_CMD | MCI_DIREN_DAT0 | MCI_DIREN_DAT2 | \
+ MCI_DIREN_DAT31 | MCI_DIREN_DAT74 | MCI_OPEN_DRAIN)
+#define MCI_DIREN_CMD (1<<3)
+#define MCI_DIREN_DAT0 (1<<4)
+#define MCI_DIREN_DAT2 (1<<2)
+#define MCI_DIREN_DAT31 (1<<5)
+#define MCI_DIREN_DAT74 (1<<8)
+#define MCI_DIREN_1BIT (MCI_DIREN_CMD|MCI_DIREN_DAT0)
+#define MCI_DIREN_4BIT (MCI_DIREN_CMD|MCI_DIREN_DAT0|MCI_DIREN_DAT31)
+/* #define MCI_DIREN_8BIT (MCI_DIREN_CMD|MCI_DIREN_DAT0|MCI_DIREN_DAT31)*/
+#define MCI_DIREN_BIT (MCI_DIREN_CMD|MCI_DIREN_DAT0|MCI_DIREN_DAT31|\
+ MCI_DIREN_DAT2|MCI_DIREN_DAT74)
+/*
+ * SDI Clock register offset
+ */
+#define MMCICLOCK 0x004
+/*
+ * SDI Power register bits
+ */
+#define MCI_CLK_ENABLE (1 << 8)
+#define MCI_CLK_PWRSAVE (1 << 9)
+#define MCI_CLK_BYPASS (1 << 10)
+#define MCI_BUS_WIDTH_1 (0 << 11)
+#define MCI_BUS_WIDTH_4 (1 << 11)
+#define MCI_BUS_WIDTH_8 (2 << 11)
+#define MCI_HWFC_EN (1 << 14)
+#define MCI_NEG_EDGE (1 << 13)
+/*
+ * SDI Arguement register offset
+ */
+#define MMCIARGUMENT 0x008
+/*
+ * SDI Command register offset
+ */
+#define MMCICOMMAND 0x00c
+/*
+ * SDI command register bits
+ */
+#define MCI_CPSM_RESPONSE (1 << 6)
+#define MCI_CPSM_LONGRSP (1 << 7)
+#define MCI_CPSM_INTERRUPT (1 << 8)
+#define MCI_CPSM_PENDING (1 << 9)
+#define MCI_CPSM_ENABLE (1 << 10)
+
+/*
+ * SDI RespCMD register offset
+ */
+#define MMCIRESPCMD 0x010
+/*
+ * SDI Response0 register offset
+ */
+#define MMCIRESPONSE0 0x014
+/*
+ * SDI Response1 register offset
+ */
+#define MMCIRESPONSE1 0x018
+/*
+ * SDI Response2 register offset
+ */
+#define MMCIRESPONSE2 0x01c
+/*
+ * SDI Response3 register offset
+ */
+#define MMCIRESPONSE3 0x020
+/*
+ * SDI Datatimer register offset
+ */
+#define MMCIDATATIMER 0x024
+/*
+ * SDI DataLength register offset
+ */
+#define MMCIDATALENGTH 0x028
+/*
+ * SDI Data control register offset
+ */
+#define MMCIDATACTRL 0x02c
+/*
+ * SDI Data control register bits
+ */
+#define MCI_DPSM_ENABLE (1 << 0)
+#define MCI_DPSM_DIRECTION (1 << 1)
+#define MCI_DPSM_MODE (1 << 2)
+#define MCI_DPSM_DMAENABLE (1 << 3)
+#define MCI_DPSM_DMAreqctl (1 << 12)
+#define MCI_SDIO_ENABLE (1 << 11)
+
+/*
+ * SDI Data Count register offset
+ */
+#define MMCIDATACNT 0x030
+/*
+ * SDI Status register offset
+ */
+#define MMCISTATUS 0x034
+/*
+ * SDI Status register bits
+ */
+#define MCI_CMDCRCFAIL (1 << 0)
+#define MCI_DATACRCFAIL (1 << 1)
+#define MCI_CMDTIMEOUT (1 << 2)
+#define MCI_DATATIMEOUT (1 << 3)
+#define MCI_TXUNDERRUN (1 << 4)
+#define MCI_RXOVERRUN (1 << 5)
+#define MCI_CMDRESPEND (1 << 6)
+#define MCI_CMDSENT (1 << 7)
+#define MCI_DATAEND (1 << 8)
+#define MCI_STBITERR (1 << 9)
+#define MCI_DATABLOCKEND (1 << 10)
+#define MCI_CMDACTIVE (1 << 11)
+#define MCI_TXACTIVE (1 << 12)
+#define MCI_RXACTIVE (1 << 13)
+#define MCI_TXFIFOHALFEMPTY (1 << 14)
+#define MCI_RXFIFOHALFFULL (1 << 15)
+#define MCI_TXFIFOFULL (1 << 16)
+#define MCI_RXFIFOFULL (1 << 17)
+#define MCI_TXFIFOEMPTY (1 << 18)
+#define MCI_RXFIFOEMPTY (1 << 19)
+#define MCI_TXDATAAVLBL (1 << 20)
+#define MCI_RXDATAAVLBL (1 << 21)
+#define MCI_SDIOIT (1 << 22)
+/*
+ * SDI Clear register offset
+ */
+#define MMCICLEAR 0x038
+#define MCI_CMDCRCFAILCLR (1 << 0)
+#define MCI_DATACRCFAILCLR (1 << 1)
+#define MCI_CMDTIMEOUTCLR (1 << 2)
+#define MCI_DATATIMEOUTCLR (1 << 3)
+#define MCI_TXUNDERRUNCLR (1 << 4)
+#define MCI_RXOVERRUNCLR (1 << 5)
+#define MCI_CMDRESPENDCLR (1 << 6)
+#define MCI_CMDSENTCLR (1 << 7)
+#define MCI_DATAENDCLR (1 << 8)
+#define MCI_DATABLOCKENDCLR (1 << 10)
+#define MCI_SDIOITCLR (1 << 22)
+/*
+ * SDI Mask register offset
+ */
+#define MMCIMASK0 0x03c
+/*
+ * SDI Mask register bits
+ */
+#define MCI_CMDCRCFAILMASK (1 << 0)
+#define MCI_DATACRCFAILMASK (1 << 1)
+#define MCI_CMDTIMEOUTMASK (1 << 2)
+#define MCI_DATATIMEOUTMASK (1 << 3)
+#define MCI_TXUNDERRUNMASK (1 << 4)
+#define MCI_RXOVERRUNMASK (1 << 5)
+#define MCI_CMDRESPENDMASK (1 << 6)
+#define MCI_CMDSENTMASK (1 << 7)
+#define MCI_DATAENDMASK (1 << 8)
+#define MCI_DATABLOCKENDMASK (1 << 10)
+#define MCI_CMDACTIVEMASK (1 << 11)
+#define MCI_TXACTIVEMASK (1 << 12)
+#define MCI_RXACTIVEMASK (1 << 13)
+#define MCI_TXFIFOHALFEMPTYMASK (1 << 14)
+#define MCI_RXFIFOHALFFULLMASK (1 << 15)
+#define MCI_TXFIFOFULLMASK (1 << 16)
+#define MCI_RXFIFOFULLMASK (1 << 17)
+#define MCI_TXFIFOEMPTYMASK (1 << 18)
+#define MCI_RXFIFOEMPTYMASK (1 << 19)
+#define MCI_TXDATAAVLBLMASK (1 << 20)
+#define MCI_RXDATAAVLBLMASK (1 << 21)
+#define MCI_SDIOITMASK (1 << 22)
+
+#define MMCIMASK1 0x040
+#define MMCIFIFOCNT 0x048
+#define MMCIFIFO 0x080 /* to 0x0bc */
+
+#define MCI_DATA_ERR \
+ (MCI_RXOVERRUN | MCI_TXUNDERRUN | MCI_DATATIMEOUT | \
+ MCI_DATACRCFAIL | MCI_STBITERR)
+#define MCI_IRQENABLE \
+ (MCI_CMDCRCFAIL | MCI_DATACRCFAIL | MCI_CMDTIMEOUT | \
+ MCI_DATATIMEOUT | MCI_TXUNDERRUN | MCI_RXOVERRUN | \
+ MCI_CMDRESPEND | MCI_CMDSENT | MCI_DATABLOCKEND)
+#define MCI_DATA_IRQ (MCI_DATA_ERR | MCI_DATAEND)
+#define MCI_XFER_IRQ_MASK \
+ (MCI_TXFIFOEMPTY | MCI_TXFIFOHALFEMPTY | \
+ MCI_RXFIFOHALFFULL | MCI_RXDATAAVLBL)
+#define MCI_CMD_IRQ \
+ (MCI_CMDCRCFAIL | MCI_CMDTIMEOUT | MCI_CMDRESPEND | \
+ MCI_CMDSENT)
+#define MCI_XFER_IRQ \
+ (MCI_TXFIFOHALFEMPTY | MCI_RXFIFOHALFFULL)
+
+/*
+ * The size of the FIFO in bytes.
+ */
+#define MCI_FIFOSIZE 16
+#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
+#define NR_SG 16
+#define MMC_MAX_REQ_SIZE SZ_4M
+#define MMC_MAX_SEG_SIZE SZ_64K
+#define MMC_HOST_BLK_SIZE 512
+#define MMC_MAX_PHY_SEGMENTS 128
+#define MMC_MAX_HW_SEGMENTS 128
+
+#define OCR_AVAIL (MMC_VDD_17_18 | MMC_VDD_18_19 | \
+ /*MMC_VDD_28_29 |*/ \
+ MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_32_33 | \
+ MMC_VDD_33_34)
+#define INVALID_PIPEID (-1)
+
+/**
+ * struct u8500_mmci_host - host device structure
+ * @base: pointer to the device baseaddress
+ * @mrq: pointer to the request structure
+ * @cmd: pointer to the command structure
+ * @data: pointer to the data structure
+ * @mmc: pointer to the mmc_host structure
+ * @clk: pointer to the clock structure
+ * @data_xfered: variable which updates the data_transfered
+ * @lock: spinlock variable
+ * @sg_ptr: scatter list pointer
+ * @mclk: master clock
+ * @cclk: card clock
+ * @card_detect_intr_value: callback for the carddetection
+ * @oldstat: card detection value
+ * @dmach_mmc2mem: dma pipeid card to memory
+ * @dmach_mem2mmc: dma pipeid from memory to card
+ * @dma_fifo_addr: dma fifo address
+ * @dma_fifo_dev_type_rx: rx channel number
+ * @dma_fifo_dev_type_tx: tx channel number
+ * @level_shifter: variable for checking level shifter
+ * @dma: ponter to dma_addr_t structure
+ * @caps: host capabilities
+ * @bus_resume_flags: Type of MMC bus resume requested.
+ * @sg_len: scatter gather length
+ * @sg_off: offset address
+ * @size: data size
+ * @buffer: buffer used in polling mode
+ * @dma_buffer: buffer used in dma mode
+ * @dma_done: variable for dma completion
+ * @devicemode: variable for device mode
+ * @is_sdio: variable for sdio
+ * @board: pointer to the board structure
+ * @regulator: pointer to the regulator structure
+ * @sdio_setirq: set irq status for SDIO
+ * @sdio_irqstatus: current irq status for SDIO
+ * @aligned_blksz: aligned block size value for SDIO
+ * @aligned_size: aligned size value for SDIO
+ * @reg_context: array to store register context
+ *
+ * host controller Internal device structure
+ */
+struct u8500_mmci_host {
+ void __iomem *base;
+ struct mmc_request *mrq;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ struct mmc_host *mmc;
+ struct clk *clk;
+#ifdef CONFIG_REGULATOR
+ struct regulator *regulator;
+#endif
+ unsigned int data_xfered;
+ spinlock_t lock;
+ unsigned int mclk;
+ unsigned int cclk;
+ int (*card_detect_intr_value) (void);
+ unsigned int oldstat;
+ struct dma_chan *dmach_mmc2mem;
+ struct dma_chan *dmach_mem2mmc;
+ struct stedma40_chan_cfg *dma_mem2mmc;
+ struct stedma40_chan_cfg *dma_mmc2mem;
+ dma_filter_fn dma_filter;
+ unsigned int level_shifter;
+ dma_addr_t dma;
+ unsigned long caps; /* Host capabilities */
+ unsigned int bus_resume_flags;
+ unsigned int sg_len;
+ /* pio stuff */
+ struct scatterlist *sg_ptr;
+ unsigned int sg_off;
+ unsigned int size;
+ unsigned int *buffer;
+ unsigned int *dma_buffer;
+ void *dma_done; /* completion data */
+ int devicemode;
+ unsigned int is_sdio;
+ int sdio_setirq;
+ int sdio_irqstatus;
+ int aligned_blksz;
+ int aligned_size;
+ struct mmc_board *board;
+ unsigned long reg_context[2];
+};
+
+/* Define the current mode */
+#define MCI_DMAMODE 0x01
+#define MCI_POLLINGMODE 0x02
+#define MCI_INTERRUPTMODE 0x03
+#define MCI_ALLINTERRUPTS (0x007FFFFF)
+#define MMCCLRSTATICFLAGS (0x000007FF)
+#define MCI_MAXVOLTTRIAL (200) /* 200 times */
+#define MAX_FREQ (24000000)
+#define MAX_DATA (64*512)
+#define MMC_HOST_CLK_MAX 100000000
+#define MMC_CLK_DIV 0xFF
+/*
+ * different card states
+ */
+enum card_state {
+ CARD_STATE_EMPTY = -1,
+ CARD_STATE_IDLE,
+ CARD_STATE_READY,
+ CARD_STATE_IDENT,
+ CARD_STATE_STBY,
+ CARD_STATE_TRAN,
+ CARD_STATE_DATA,
+ CARD_STATE_RCV,
+ CARD_STATE_PRG,
+ CARD_STATE_DIS,
+};
+/*
+ * struct mmc_board - mmc board dependent structure
+ * @init: function pointer for mmc board related initialization
+ * @exit: function pointer for mmc board related de-initialization
+ *
+ * SDMMC platfoem dependent structure
+ */
+struct mmc_board {
+ int (*init) (struct amba_device *dev);
+ void (*exit) (struct amba_device *dev);
+ int (*set_power) (struct device *dev, int power_on);
+ int (*card_detect_intr_conf) (int enable_or_disable);
+ int (*card_detect)(void (*callback)(void *parameter), void *);
+ int (*card_detect_intr_value) (void);
+ struct stedma40_chan_cfg *dma_mem2mmc;
+ struct stedma40_chan_cfg *dma_mmc2mem;
+ dma_filter_fn dma_filter;
+ unsigned int level_shifter;
+ unsigned long caps; /* Host capabilities */
+ unsigned int bus_resume_flags;
+ int is_sdio; /* To check if the bus is SD/MMC or sdio */
+#ifdef CONFIG_REGULATOR
+ const char *supply;
+ int min_supply_voltage;
+ int max_supply_voltage;
+#endif
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/msp.h b/arch/arm/mach-ux500/include/mach/msp.h
new file mode 100644
index 00000000000..57ef8ad1001
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/msp.h
@@ -0,0 +1,974 @@
+/*
+ * Copyright (c) 2009 STMicroelectronics
+ *
+ * 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 _STM_MSP_HEADER
+#define _STM_MSP_HEADER
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/dmaengine.h>
+#include <linux/i2s/i2s.h>
+#include <linux/irqreturn.h>
+#include <linux/bitops.h>
+#include <plat/ste_dma40.h>
+#include <mach/gpio.h>
+#include <linux/spi/stm_msp.h>
+
+/* Generic config struct. Use the actual values defined below for global
+ * control register
+ */
+
+enum msp_state {
+ MSP_STATE_IDLE = 0,
+ MSP_STATE_CONFIGURED = 1,
+ MSP_STATE_RUN = 2,
+};
+
+enum msp_rx_comparison_enable_mode {
+ MSP_COMPARISON_DISABLED = 0,
+ MSP_COMPARISON_NONEQUAL_ENABLED = 2,
+ MSP_COMPARISON_EQUAL_ENABLED = 3
+};
+
+#define RMCEN_BIT 0
+#define RMCSF_BIT 1
+#define RCMPM_BIT 3
+#define TMCEN_BIT 5
+#define TNCSF_BIT 6
+
+struct msp_multichannel_config {
+ bool rx_multichannel_enable;
+ bool tx_multichannel_enable;
+ enum msp_rx_comparison_enable_mode rx_comparison_enable_mode;
+ u8 padding;
+ u32 comparison_value;
+ u32 comparison_mask;
+ u32 rx_channel_0_enable;
+ u32 rx_channel_1_enable;
+ u32 rx_channel_2_enable;
+ u32 rx_channel_3_enable;
+ u32 tx_channel_0_enable;
+ u32 tx_channel_1_enable;
+ u32 tx_channel_2_enable;
+ u32 tx_channel_3_enable;
+};
+
+/**
+ * struct msp_protocol_desc- MSP Protocol desc structure per MSP.
+ * @rx_phase_mode: rx_phase_mode whether single or dual.
+ * @tx_phase_mode: tx_phase_mode whether single or dual.
+ * @rx_phase2_start_mode: rx_phase2_start_mode whether imediate or after
+ * some delay.
+ * @tx_phase2_start_mode: tx_phase2_start_mode whether imediate or after
+ * some delay.
+ * @rx_bit_transfer_format: MSP or LSB.
+ * @tx_bit_transfer_format: MSP or LSB.
+ * @rx_frame_length_1: Frame1 length 1,2,3..
+ * @rx_frame_length_2: Frame2 length 1,2,3..
+ * @tx_frame_length_1: Frame1 length 1,2,3..
+ * @tx_frame_length_2: Frame2 length 1,2,3..
+ * @rx_element_length_1: Element1 length 1,2,...
+ * @rx_element_length_2: Element2 length 1,2,...
+ * @tx_element_length_1: Element1 length 1,2,...
+ * @tx_element_length_2: Element2 length 1,2,...
+ * @rx_data_delay: Delay in clk cycle after frame sync
+ * @tx_data_delay: Delay in clk cycle after frame sync
+ * @rx_clock_pol: Rxpol whether rising or falling.It indicates pol of bit clock.
+ * @tx_clock_pol: Txpol whether rising or falling.It indicates pol of bit clock.
+ * @rx_frame_sync_pol: Frame sync pol whether rising or Falling.
+ * @tx_frame_sync_pol: Frame sync pol whether rising or Falling.
+ * @rx_half_word_swap: Word swap half word, full word.
+ * @tx_half_word_swap: Word swap half word, full word.
+ * @compression_mode: Compression mode whether Alaw or Ulaw or disabled.
+ * @expansion_mode: Compression mode whether Alaw or Ulaw or disabled.
+ * @spi_clk_mode: Spi clock mode to be enabled or not.
+ * @spi_burst_mode: Spi burst mode to be enabled or not.
+ * @frame_sync_ignore: Frame sync to be ignored or not. Ignore in case of Audio
+ * codec acting as Master.
+ * @frame_period: Frame period (clk cycles) after which new frame sync occurs.
+ * @frame_width: Frame width (clk cycles) after which frame sycn changes state.
+ * @total_clocks_for_one_frame: No. of clk cycles per frame.
+ *
+ * Main Msp protocol descriptor data structure to be used to store various info
+ * in transmit or recevie configuration registers of an MSP.
+ */
+
+struct msp_protocol_desc {
+ u32 rx_phase_mode;
+ u32 tx_phase_mode;
+ u32 rx_phase2_start_mode;
+ u32 tx_phase2_start_mode;
+ u32 rx_bit_transfer_format;
+ u32 tx_bit_transfer_format;
+ u32 rx_frame_length_1;
+ u32 rx_frame_length_2;
+ u32 tx_frame_length_1;
+ u32 tx_frame_length_2;
+ u32 rx_element_length_1;
+ u32 rx_element_length_2;
+ u32 tx_element_length_1;
+ u32 tx_element_length_2;
+ u32 rx_data_delay;
+ u32 tx_data_delay;
+ u32 rx_clock_pol;
+ u32 tx_clock_pol;
+ u32 rx_frame_sync_pol;
+ u32 tx_frame_sync_pol;
+ u32 rx_half_word_swap;
+ u32 tx_half_word_swap;
+ u32 compression_mode;
+ u32 expansion_mode;
+ u32 spi_clk_mode;
+ u32 spi_burst_mode;
+ u32 frame_sync_ignore;
+ u32 frame_period;
+ u32 frame_width;
+ u32 total_clocks_for_one_frame;
+};
+
+/**
+ * struct trans_data - MSP transfer data structure used during xfer.
+ * @message: i2s message.
+ * @msp: msp structure.
+ * @tx_handler: callback handler for transmit path.
+ * @rx_handler: callback handler for receive path.
+ * @tx_callback_data: callback data for transmit.
+ * @rx_callback_data: callback data for receive.
+ *
+ */
+struct trans_data {
+ struct i2s_message message;
+ struct msp *msp;
+ void (*tx_handler) (void *data);
+ void (*rx_handler) (void *data);
+ void *tx_callback_data;
+ void *rx_callback_data;
+};
+
+/**
+ * struct msp_config- MSP configuration structure used by i2s client.
+ * @input_clock_freq: Input clock frequency default is 48MHz.
+ * @rx_clock_sel: Receive clock selection (Provided by Sample Gen or external
+ * source).
+ * @tx_clock_sel: Transmit clock selection (Provided by Sample Gen or external.
+ * source).
+ * @srg_clock_sel: APB clock or clock dervied from Slave (Audio codec).
+ * @rx_frame_sync_pol: Receive frame sync polarity.
+ * @tx_frame_sync_pol: Transmit frame sync polarity.
+ * @rx_frame_sync_sel: Rx frame sync signal is provided by which source.
+ * External source or by frame generator logic.
+ * @tx_frame_sync_sel: Tx frame sync signal is provided by which source.
+ * External source or by frame generator logic.
+ * @rx_fifo_config: Receive fifo enable or not.
+ * @tx_fifo_config: Transmit fifo enable or not.
+ * @spi_clk_mode: In case of SPI protocol spi modes: Normal, Zero delay or
+ * half cycle delay.
+ * @spi_burst_mode: Spi burst mode is enabled or not.
+ * @loopback_enable: Loopback mode.
+ * @tx_data_enable: Transmit extra delay enable.
+ * @default_protocol_desc: Flag to indicate client defined protocol desc or
+ * statically defined in msp.h.
+ * @protocol_desc: Protocol desc structure filled by i2s client driver.
+ * In case client defined default_prtocol_desc as 0.
+ * @multichannel_configured: multichannel configuration structure.
+ * @multichannel_config: multichannel is enabled or not.
+ * @direction: Transmit, Receive or Both.
+ * @work_mode: Dma, Polling or Interrupt.
+ * @protocol: I2S, PCM, etc.
+ * @frame_freq: Sampling freq at which data is sampled.
+ * @frame_size: size of element.
+ * @data_size: data size which defines the format in which data is written on
+ * transmit or receive fifo. Only three modes 8,16,32 are supported.
+ * @def_elem_len: Flag to indicate whether default element length is to be used
+ * or should be changed acc to data size defined by user at run time.
+ * @iodelay: value for the MSP_IODLY register
+ * @handler: callback handler in case of interrupt or dma.
+ * @tx_callback_data: Callback data for transmit.
+ * @rx_callback_data: Callback data for receive.
+ *
+ * Main Msp configuration data structure used by i2s client driver to fill
+ * various info like data size, frequency etc.
+ */
+struct msp_config {
+ unsigned int input_clock_freq;
+ unsigned int rx_clock_sel;
+ unsigned int tx_clock_sel;
+ unsigned int srg_clock_sel;
+ unsigned int rx_frame_sync_pol;
+ unsigned int tx_frame_sync_pol;
+ unsigned int rx_frame_sync_sel;
+ unsigned int tx_frame_sync_sel;
+ unsigned int rx_fifo_config;
+ unsigned int tx_fifo_config;
+ unsigned int spi_clk_mode;
+ unsigned int spi_burst_mode;
+ unsigned int loopback_enable;
+ unsigned int tx_data_enable;
+ unsigned int default_protocol_desc;
+ struct msp_protocol_desc protocol_desc;
+ int multichannel_configured;
+ struct msp_multichannel_config multichannel_config;
+ unsigned int direction;
+ unsigned int work_mode;
+ unsigned int protocol;
+ unsigned int frame_freq;
+ unsigned int frame_size;
+ enum msp_data_size data_size;
+ unsigned int def_elem_len;
+ unsigned int iodelay;
+ void (*handler) (void *data);
+ void *tx_callback_data;
+ void *rx_callback_data;
+
+};
+
+/*** Protocols ***/
+enum msp_protocol {
+ MSP_I2S_PROTOCOL,
+ MSP_PCM_PROTOCOL,
+ MSP_PCM_COMPAND_PROTOCOL,
+ MSP_AC97_PROTOCOL,
+ MSP_MASTER_SPI_PROTOCOL,
+ MSP_SLAVE_SPI_PROTOCOL,
+ MSP_INVALID_PROTOCOL
+};
+
+/*** Sample Frequencies ***/
+/* These are no longer required, frequencies in Hz can be used directly */
+enum msp_sample_freq {
+ MSP_SAMPLE_FREQ_NOT_SUPPORTED = -1,
+ MSP_SAMPLE_FREQ_8KHZ = 8000,
+ MSP_SAMPLE_FREQ_12KHZ = 12000,
+ MSP_SAMPLE_FREQ_16KHZ = 16000,
+ MSP_SAMPLE_FREQ_24KHZ = 24000,
+ MSP_SAMPLE_FREQ_32KHZ = 32000,
+ MSP_SAMPLE_FREQ_44KHZ = 44000,
+ MSP_SAMPLE_FREQ_48KHZ = 48000,
+ MSP_SAMPLE_FREQ_64KHZ = 64000,
+ MSP_SAMPLE_FREQ_88KHZ = 88000,
+ MSP_SAMPLE_FREQ_96KHZ = 96000,
+ MSP_SAMPLE_FREQ_22KHZ = 22000,
+ MSP_SAMPLE_FREQ_11KHZ = 11000
+};
+
+/*** Input Frequencies ***/
+/* These are no longer required, frequencies in Hz can be used directly */
+enum msp_in_clock_freq {
+ MSP_INPUT_FREQ_1MHZ = 1000,
+ MSP_INPUT_FREQ_2MHZ = 2000,
+ MSP_INPUT_FREQ_3MHZ = 3000,
+ MSP_INPUT_FREQ_4MHZ = 4000,
+ MSP_INPUT_FREQ_5MHZ = 5000,
+ MSP_INPUT_FREQ_6MHZ = 6000,
+ MSP_INPUT_FREQ_8MHZ = 8000,
+ MSP_INPUT_FREQ_11MHZ = 11000,
+ MSP_INPUT_FREQ_12MHZ = 12000,
+ MSP_INPUT_FREQ_16MHZ = 16000,
+ MSP_INPUT_FREQ_22MHZ = 22000,
+ MSP_INPUT_FREQ_24MHZ = 24000,
+ MSP_INPUT_FREQ_48MHZ = 48000
+};
+
+#define MSP_INPUT_FREQ_APB 48000000
+
+/*** Stereo mode. Used for APB data accesses as 16 bits accesses (mono),
+ * 32 bits accesses (stereo).
+ ***/
+enum msp_stereo_mode {
+ MSP_MONO,
+ MSP_STEREO
+};
+
+/* Direction (Transmit/Receive mode) */
+enum msp_direction {
+ MSP_TRANSMIT_MODE,
+ MSP_RECEIVE_MODE,
+ MSP_BOTH_T_R_MODE
+};
+
+/* Dma mode should be used for large transfers,
+ * polling mode should be used for transfers of a few bytes
+ */
+enum msp_xfer_mode {
+ MSP_DMA_MODE,
+ MSP_POLLING_MODE,
+ MSP_INTERRUPT_MODE
+};
+
+/* User client for the MSP */
+enum msp_user {
+ MSP_NO_USER = 0,
+ MSP_USER_SPI,
+ MSP_USER_ALSA,
+ MSP_USER_SAA,
+};
+
+/*Flag structure for MSPx*/
+struct msp_flag {
+ struct semaphore lock;
+ enum msp_user user;
+};
+
+/* User client for the MSP */
+enum msp_mode {
+ MSP_NO_MODE = 0,
+ MSP_MODE_SPI,
+ MSP_MODE_NON_SPI,
+};
+
+/* Transmit and receive configuration register */
+#define MSP_BIG_ENDIAN 0x00000000
+#define MSP_LITTLE_ENDIAN 0x00001000
+#define MSP_UNEXPECTED_FS_ABORT 0x00000000
+#define MSP_UNEXPECTED_FS_IGNORE 0x00008000
+#define MSP_NON_MODE_BIT_MASK 0x00009000
+
+/* Global configuration register */
+#define RX_ENABLE 0x00000001
+#define RX_FIFO_ENABLE 0x00000002
+#define RX_SYNC_SRG 0x00000010
+#define RX_CLK_POL_RISING 0x00000020
+#define RX_CLK_SEL_SRG 0x00000040
+#define TX_ENABLE 0x00000100
+#define TX_FIFO_ENABLE 0x00000200
+#define TX_SYNC_SRG_PROG 0x00001800
+#define TX_SYNC_SRG_AUTO 0x00001000
+#define TX_CLK_POL_RISING 0x00002000
+#define TX_CLK_SEL_SRG 0x00004000
+#define TX_EXTRA_DELAY_ENABLE 0x00008000
+#define SRG_ENABLE 0x00010000
+#define FRAME_GEN_ENABLE 0x00100000
+#define SRG_CLK_SEL_APB 0x00000000
+#define RX_FIFO_SYNC_HI 0x00000000
+#define TX_FIFO_SYNC_HI 0x00000000
+#define SPI_CLK_MODE_NORMAL 0x00000000
+
+/* SPI Clock Modes enumertion
+ * SPI clock modes of MSP provides compatibility with
+ * the SPI protocol.MSP supports 2 SPI transfer formats.
+ * MSP_ZERO_DELAY_SPI_MODE:MSP transmits data over Tx/Rx
+ * Lines immediately after MSPTCK/MSPRCK rising/falling edge.
+ * MSP_HALF_CYCLE_DELY_SPI_MODE:MSP transmits data one-half cycle
+ * ahead of the rising/falling edge of the MSPTCK
+ */
+
+#define MSP_FRAME_SIZE_AUTO -1
+
+
+#define MSP_DR 0x00
+#define MSP_GCR 0x04
+#define MSP_TCF 0x08
+#define MSP_RCF 0x0c
+#define MSP_SRG 0x10
+#define MSP_FLR 0x14
+#define MSP_DMACR 0x18
+
+#define MSP_IMSC 0x20
+#define MSP_RIS 0x24
+#define MSP_MIS 0x28
+#define MSP_ICR 0x2c
+#define MSP_MCR 0x30
+#define MSP_RCV 0x34
+#define MSP_RCM 0x38
+
+#define MSP_TCE0 0x40
+#define MSP_TCE1 0x44
+#define MSP_TCE2 0x48
+#define MSP_TCE3 0x4c
+
+#define MSP_RCE0 0x60
+#define MSP_RCE1 0x64
+#define MSP_RCE2 0x68
+#define MSP_RCE3 0x6c
+#define MSP_IODLY 0x70
+
+#define MSP_ITCR 0x80
+#define MSP_ITIP 0x84
+#define MSP_ITOP 0x88
+#define MSP_TSTDR 0x8c
+
+#define MSP_PID0 0xfe0
+#define MSP_PID1 0xfe4
+#define MSP_PID2 0xfe8
+#define MSP_PID3 0xfec
+
+#define MSP_CID0 0xff0
+#define MSP_CID1 0xff4
+#define MSP_CID2 0xff8
+#define MSP_CID3 0xffc
+
+/* Single or dual phase mode */
+enum msp_phase_mode {
+ MSP_SINGLE_PHASE,
+ MSP_DUAL_PHASE
+};
+
+/* Frame length */
+enum msp_frame_length {
+ MSP_FRAME_LENGTH_1 = 0,
+ MSP_FRAME_LENGTH_2 = 1,
+ MSP_FRAME_LENGTH_4 = 3,
+ MSP_FRAME_LENGTH_8 = 7,
+ MSP_FRAME_LENGTH_12 = 11,
+ MSP_FRAME_LENGTH_16 = 15,
+ MSP_FRAME_LENGTH_20 = 19,
+ MSP_FRAME_LENGTH_32 = 31,
+ MSP_FRAME_LENGTH_48 = 47,
+ MSP_FRAME_LENGTH_64 = 63
+};
+
+/* Element length */
+enum msp_elem_length {
+ MSP_ELEM_LENGTH_8 = 0,
+ MSP_ELEM_LENGTH_10 = 1,
+ MSP_ELEM_LENGTH_12 = 2,
+ MSP_ELEM_LENGTH_14 = 3,
+ MSP_ELEM_LENGTH_16 = 4,
+ MSP_ELEM_LENGTH_20 = 5,
+ MSP_ELEM_LENGTH_24 = 6,
+ MSP_ELEM_LENGTH_32 = 7
+};
+
+enum msp_data_xfer_width {
+ MSP_DATA_TRANSFER_WIDTH_BYTE,
+ MSP_DATA_TRANSFER_WIDTH_HALFWORD,
+ MSP_DATA_TRANSFER_WIDTH_WORD
+};
+
+enum msp_frame_sync {
+ MSP_FRAME_SYNC_UNIGNORE = 0,
+ MSP_FRAME_SYNC_IGNORE = 1,
+
+};
+
+enum msp_phase2_start_mode {
+ MSP_PHASE2_START_MODE_IMEDIATE,
+ MSP_PHASE2_START_MODE_FRAME_SYNC
+};
+
+enum msp_btf {
+ MSP_BTF_MS_BIT_FIRST = 0,
+ MSP_BTF_LS_BIT_FIRST = 1
+};
+
+enum msp_frame_sync_pol {
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH = 0,
+ MSP_FRAME_SYNC_POL_ACTIVE_LOW = 1
+};
+
+/* Data delay (in bit clock cycles) */
+enum msp_delay {
+ MSP_DELAY_0 = 0,
+ MSP_DELAY_1 = 1,
+ MSP_DELAY_2 = 2,
+ MSP_DELAY_3 = 3
+};
+
+/* Configurations of clocks (transmit, receive or sample rate generator) */
+enum msp_edge {
+ MSP_FALLING_EDGE = 0,
+ MSP_RISING_EDGE = 1,
+};
+
+enum msp_hws {
+ MSP_HWS_NO_SWAP = 0,
+ MSP_HWS_BYTE_SWAP_IN_WORD = 1,
+ MSP_HWS_BYTE_SWAP_IN_EACH_HALF_WORD = 2,
+ MSP_HWS_HALF_WORD_SWAP_IN_WORD = 3
+};
+
+enum msp_compress_mode {
+ MSP_COMPRESS_MODE_LINEAR = 0,
+ MSP_COMPRESS_MODE_MU_LAW = 2,
+ MSP_COMPRESS_MODE_A_LAW = 3
+};
+
+enum msp_spi_clock_mode {
+ MSP_SPI_CLOCK_MODE_NON_SPI = 0,
+ MSP_SPI_CLOCK_MODE_ZERO_DELAY = 2,
+ MSP_SPI_CLOCK_MODE_HALF_CYCLE_DELAY = 3
+};
+
+enum msp_spi_burst_mode {
+ MSP_SPI_BURST_MODE_DISABLE = 0,
+ MSP_SPI_BURST_MODE_ENABLE = 1
+};
+
+enum msp_expand_mode {
+ MSP_EXPAND_MODE_LINEAR = 0,
+ MSP_EXPAND_MODE_LINEAR_SIGNED = 1,
+ MSP_EXPAND_MODE_MU_LAW = 2,
+ MSP_EXPAND_MODE_A_LAW = 3
+};
+
+/* Protocol dependant parameters list */
+#define RX_ENABLE_MASK BIT(0)
+#define RX_FIFO_ENABLE_MASK BIT(1)
+#define RX_FRAME_SYNC_MASK BIT(2)
+#define DIRECT_COMPANDING_MASK BIT(3)
+#define RX_SYNC_SEL_MASK BIT(4)
+#define RX_CLK_POL_MASK BIT(5)
+#define RX_CLK_SEL_MASK BIT(6)
+#define LOOPBACK_MASK BIT(7)
+#define TX_ENABLE_MASK BIT(8)
+#define TX_FIFO_ENABLE_MASK BIT(9)
+#define TX_FRAME_SYNC_MASK BIT(10)
+#define TX_MSP_TDR_TSR BIT(11)
+#define TX_SYNC_SEL_MASK (BIT(12) | BIT(11))
+#define TX_CLK_POL_MASK BIT(13)
+#define TX_CLK_SEL_MASK BIT(14)
+#define TX_EXTRA_DELAY_MASK BIT(15)
+#define SRG_ENABLE_MASK BIT(16)
+#define SRG_CLK_POL_MASK BIT(17)
+#define SRG_CLK_SEL_MASK (BIT(19) | BIT(18))
+#define FRAME_GEN_EN_MASK BIT(20)
+#define SPI_CLK_MODE_MASK (BIT(22) | BIT(21))
+#define SPI_BURST_MODE_MASK BIT(23)
+
+#define RXEN_SHIFT 0
+#define RFFEN_SHIFT 1
+#define RFSPOL_SHIFT 2
+#define DCM_SHIFT 3
+#define RFSSEL_SHIFT 4
+#define RCKPOL_SHIFT 5
+#define RCKSEL_SHIFT 6
+#define LBM_SHIFT 7
+#define TXEN_SHIFT 8
+#define TFFEN_SHIFT 9
+#define TFSPOL_SHIFT 10
+#define TFSSEL_SHIFT 11
+#define TCKPOL_SHIFT 13
+#define TCKSEL_SHIFT 14
+#define TXDDL_SHIFT 15
+#define SGEN_SHIFT 16
+#define SCKPOL_SHIFT 17
+#define SCKSEL_SHIFT 18
+#define FGEN_SHIFT 20
+#define SPICKM_SHIFT 21
+#define TBSWAP_SHIFT 28
+
+#define RCKPOL_MASK BIT(0)
+#define TCKPOL_MASK BIT(0)
+#define SPICKM_MASK (BIT(1) | BIT(0))
+#define MSP_RX_CLKPOL_BIT(n) ((n & RCKPOL_MASK) << RCKPOL_SHIFT)
+#define MSP_TX_CLKPOL_BIT(n) ((n & TCKPOL_MASK) << TCKPOL_SHIFT)
+#define MSP_SPI_CLK_MODE_BITS(n) ((n & SPICKM_MASK) << SPICKM_SHIFT)
+
+
+
+/* Use this to clear the clock mode bits to non-spi */
+#define MSP_NON_SPI_CLK_MASK (BIT(22) | BIT(21))
+
+#define P1ELEN_SHIFT 0
+#define P1FLEN_SHIFT 3
+#define DTYP_SHIFT 10
+#define ENDN_SHIFT 12
+#define DDLY_SHIFT 13
+#define FSIG_SHIFT 15
+#define P2ELEN_SHIFT 16
+#define P2FLEN_SHIFT 19
+#define P2SM_SHIFT 26
+#define P2EN_SHIFT 27
+#define FRAME_SYNC_SHIFT 15
+
+
+#define P1ELEN_MASK 0x00000007
+#define P2ELEN_MASK 0x00070000
+#define P1FLEN_MASK 0x00000378
+#define P2FLEN_MASK 0x03780000
+#define DDLY_MASK 0x00003000
+#define DTYP_MASK 0x00000600
+#define P2SM_MASK 0x04000000
+#define P2EN_MASK 0x08000000
+#define ENDN_MASK 0x00001000
+#define TFSPOL_MASK 0x00000400
+#define TBSWAP_MASK 0x30000000
+#define COMPANDING_MODE_MASK 0x00000c00
+#define FRAME_SYNC_MASK 0x00008000
+
+#define MSP_P1_ELEM_LEN_BITS(n) (n & P1ELEN_MASK)
+#define MSP_P2_ELEM_LEN_BITS(n) (((n) << P2ELEN_SHIFT) & P2ELEN_MASK)
+#define MSP_P1_FRAME_LEN_BITS(n) (((n) << P1FLEN_SHIFT) & P1FLEN_MASK)
+#define MSP_P2_FRAME_LEN_BITS(n) (((n) << P2FLEN_SHIFT) & P2FLEN_MASK)
+#define MSP_DATA_DELAY_BITS(n) (((n) << DDLY_SHIFT) & DDLY_MASK)
+#define MSP_DATA_TYPE_BITS(n) (((n) << DTYP_SHIFT) & DTYP_MASK)
+#define MSP_P2_START_MODE_BIT(n) ((n << P2SM_SHIFT) & P2SM_MASK)
+#define MSP_P2_ENABLE_BIT(n) ((n << P2EN_SHIFT) & P2EN_MASK)
+#define MSP_SET_ENDIANNES_BIT(n) ((n << ENDN_SHIFT) & ENDN_MASK)
+#define MSP_FRAME_SYNC_POL(n) ((n << TFSPOL_SHIFT) & TFSPOL_MASK)
+#define MSP_DATA_WORD_SWAP(n) ((n << TBSWAP_SHIFT) & TBSWAP_MASK)
+#define MSP_SET_COMPANDING_MODE(n) ((n << DTYP_SHIFT) & COMPANDING_MODE_MASK)
+#define MSP_SET_FRAME_SYNC_IGNORE(n) ((n << FRAME_SYNC_SHIFT) & \
+ FRAME_SYNC_MASK)
+
+/* Flag register */
+#define RX_BUSY BIT(0)
+#define RX_FIFO_EMPTY BIT(1)
+#define RX_FIFO_FULL BIT(2)
+#define TX_BUSY BIT(3)
+#define TX_FIFO_EMPTY BIT(4)
+#define TX_FIFO_FULL BIT(5)
+
+#define RBUSY_SHIFT 0
+#define RFE_SHIFT 1
+#define RFU_SHIFT 2
+#define TBUSY_SHIFT 3
+#define TFE_SHIFT 4
+#define TFU_SHIFT 5
+
+/* Multichannel control register */
+#define RMCEN_SHIFT 0
+#define RMCSF_SHIFT 1
+#define RCMPM_SHIFT 3
+#define TMCEN_SHIFT 5
+#define TNCSF_SHIFT 6
+
+/* Sample rate generator register */
+#define SCKDIV_SHIFT 0
+#define FRWID_SHIFT 10
+#define FRPER_SHIFT 16
+
+#define SCK_DIV_MASK 0x0000003FF
+#define FRAME_WIDTH_BITS(n) (((n) << FRWID_SHIFT) & 0x0000FC00)
+#define FRAME_PERIOD_BITS(n) (((n) << FRPER_SHIFT) & 0x1FFF0000)
+
+/* DMA controller register */
+#define RX_DMA_ENABLE BIT(0)
+#define TX_DMA_ENABLE BIT(1)
+
+#define RDMAE_SHIFT 0
+#define TDMAE_SHIFT 1
+
+/* Interrupt Register */
+#define RECEIVE_SERVICE_INT BIT(0)
+#define RECEIVE_OVERRUN_ERROR_INT BIT(1)
+#define RECEIVE_FRAME_SYNC_ERR_INT BIT(2)
+#define RECEIVE_FRAME_SYNC_INT BIT(3)
+#define TRANSMIT_SERVICE_INT BIT(4)
+#define TRANSMIT_UNDERRUN_ERR_INT BIT(5)
+#define TRANSMIT_FRAME_SYNC_ERR_INT BIT(6)
+#define TRANSMIT_FRAME_SYNC_INT BIT(7)
+#define ALL_INT 0x000000ff
+
+/*
+ * Protocol configuration values I2S:
+ * Single phase, 16 bits, 2 words per frame
+ */
+#define I2S_PROTOCOL_DESC \
+{ \
+ MSP_SINGLE_PHASE, \
+ MSP_SINGLE_PHASE, \
+ MSP_PHASE2_START_MODE_IMEDIATE, \
+ MSP_PHASE2_START_MODE_IMEDIATE, \
+ MSP_BTF_MS_BIT_FIRST, \
+ MSP_BTF_MS_BIT_FIRST, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_ELEM_LENGTH_32, \
+ MSP_ELEM_LENGTH_32, \
+ MSP_ELEM_LENGTH_32, \
+ MSP_ELEM_LENGTH_32, \
+ MSP_DELAY_1, \
+ MSP_DELAY_1, \
+ MSP_RISING_EDGE, \
+ MSP_RISING_EDGE, \
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \
+ MSP_HWS_NO_SWAP, \
+ MSP_HWS_NO_SWAP, \
+ MSP_COMPRESS_MODE_LINEAR, \
+ MSP_EXPAND_MODE_LINEAR, \
+ MSP_SPI_CLOCK_MODE_NON_SPI, \
+ MSP_SPI_BURST_MODE_DISABLE, \
+ MSP_FRAME_SYNC_IGNORE, \
+ 31, \
+ 15, \
+ 32, \
+}
+
+#define PCM_PROTOCOL_DESC \
+{ \
+ MSP_DUAL_PHASE, \
+ MSP_DUAL_PHASE, \
+ MSP_PHASE2_START_MODE_FRAME_SYNC, \
+ MSP_PHASE2_START_MODE_FRAME_SYNC, \
+ MSP_BTF_MS_BIT_FIRST, \
+ MSP_BTF_MS_BIT_FIRST, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_ELEM_LENGTH_16, \
+ MSP_ELEM_LENGTH_16, \
+ MSP_ELEM_LENGTH_16, \
+ MSP_ELEM_LENGTH_16, \
+ MSP_DELAY_0, \
+ MSP_DELAY_0, \
+ MSP_FALLING_EDGE, \
+ MSP_FALLING_EDGE, \
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \
+ MSP_HWS_NO_SWAP, \
+ MSP_HWS_NO_SWAP, \
+ MSP_COMPRESS_MODE_LINEAR, \
+ MSP_EXPAND_MODE_LINEAR, \
+ MSP_SPI_CLOCK_MODE_NON_SPI, \
+ MSP_SPI_BURST_MODE_DISABLE, \
+ MSP_FRAME_SYNC_IGNORE, \
+ 255, \
+ 0, \
+ 256, \
+}
+
+/* Companded PCM: Single phase, 8 bits, 1 word per frame */
+#define PCM_COMPAND_PROTOCOL_DESC \
+{ \
+ MSP_SINGLE_PHASE, \
+ MSP_SINGLE_PHASE, \
+ MSP_PHASE2_START_MODE_FRAME_SYNC, \
+ MSP_PHASE2_START_MODE_FRAME_SYNC, \
+ MSP_BTF_MS_BIT_FIRST, \
+ MSP_BTF_MS_BIT_FIRST, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_DELAY_0, \
+ MSP_DELAY_0, \
+ MSP_FALLING_EDGE, \
+ MSP_RISING_EDGE, \
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \
+ MSP_HWS_NO_SWAP, \
+ MSP_HWS_NO_SWAP, \
+ MSP_COMPRESS_MODE_LINEAR, \
+ MSP_EXPAND_MODE_LINEAR, \
+ MSP_SPI_CLOCK_MODE_NON_SPI, \
+ MSP_SPI_BURST_MODE_DISABLE, \
+ MSP_FRAME_SYNC_IGNORE, \
+ 255, \
+ 0, \
+ 256, \
+}
+
+/*
+ * AC97: Double phase, 1 element of 16 bits during first phase,
+ * 12 elements of 20 bits in second phase.
+ */
+#define AC97_PROTOCOL_DESC \
+{ \
+ MSP_DUAL_PHASE, \
+ MSP_DUAL_PHASE, \
+ MSP_PHASE2_START_MODE_FRAME_SYNC, \
+ MSP_PHASE2_START_MODE_FRAME_SYNC, \
+ MSP_BTF_MS_BIT_FIRST, \
+ MSP_BTF_MS_BIT_FIRST, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_12, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_12, \
+ MSP_ELEM_LENGTH_16, \
+ MSP_ELEM_LENGTH_20, \
+ MSP_ELEM_LENGTH_16, \
+ MSP_ELEM_LENGTH_20, \
+ MSP_DELAY_1, \
+ MSP_DELAY_1, \
+ MSP_FALLING_EDGE, \
+ MSP_RISING_EDGE, \
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \
+ MSP_HWS_NO_SWAP, \
+ MSP_HWS_NO_SWAP, \
+ MSP_COMPRESS_MODE_LINEAR, \
+ MSP_EXPAND_MODE_LINEAR, \
+ MSP_SPI_CLOCK_MODE_NON_SPI, \
+ MSP_SPI_BURST_MODE_DISABLE, \
+ MSP_FRAME_SYNC_IGNORE, \
+ 255, \
+ 0, \
+ 256, \
+}
+
+#define SPI_MASTER_PROTOCOL_DESC \
+{ \
+ MSP_SINGLE_PHASE, \
+ MSP_SINGLE_PHASE, \
+ MSP_PHASE2_START_MODE_FRAME_SYNC, \
+ MSP_PHASE2_START_MODE_FRAME_SYNC, \
+ MSP_BTF_MS_BIT_FIRST, \
+ MSP_BTF_MS_BIT_FIRST, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_DELAY_1, \
+ MSP_DELAY_1, \
+ MSP_RISING_EDGE, \
+ MSP_FALLING_EDGE, \
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \
+ MSP_HWS_NO_SWAP, \
+ MSP_HWS_NO_SWAP, \
+ MSP_COMPRESS_MODE_LINEAR, \
+ MSP_EXPAND_MODE_LINEAR, \
+ MSP_SPI_CLOCK_MODE_NON_SPI, \
+ MSP_SPI_BURST_MODE_DISABLE, \
+ MSP_FRAME_SYNC_IGNORE, \
+ 255, \
+ 0, \
+ 256, \
+}
+
+#define SPI_SLAVE_PROTOCOL_DESC \
+{ \
+ MSP_SINGLE_PHASE, \
+ MSP_SINGLE_PHASE, \
+ MSP_PHASE2_START_MODE_FRAME_SYNC, \
+ MSP_PHASE2_START_MODE_FRAME_SYNC, \
+ MSP_BTF_MS_BIT_FIRST, \
+ MSP_BTF_MS_BIT_FIRST, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_DELAY_1, \
+ MSP_DELAY_1, \
+ MSP_RISING_EDGE, \
+ MSP_FALLING_EDGE, \
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, \
+ MSP_HWS_NO_SWAP, \
+ MSP_HWS_NO_SWAP, \
+ MSP_COMPRESS_MODE_LINEAR, \
+ MSP_EXPAND_MODE_LINEAR, \
+ MSP_SPI_CLOCK_MODE_NON_SPI, \
+ MSP_SPI_BURST_MODE_DISABLE, \
+ MSP_FRAME_SYNC_IGNORE, \
+ 255, \
+ 0, \
+ 256, \
+}
+
+#define MSP_FRAME_PERIOD_IN_MONO_MODE 256
+#define MSP_FRAME_PERIOD_IN_STEREO_MODE 32
+#define MSP_FRAME_WIDTH_IN_STEREO_MODE 16
+
+/*
+ * No of registers to backup during
+ * suspend resume
+ */
+#define MAX_MSP_BACKUP_REGS 36
+
+enum enum_i2s_controller {
+ MSP_0_I2S_CONTROLLER = 1,
+ MSP_1_I2S_CONTROLLER,
+ MSP_2_I2S_CONTROLLER,
+ MSP_3_I2S_CONTROLLER,
+};
+
+/**
+ * struct msp - Main msp controller data structure per MSP.
+ * @work_mode: Mode i.e dma, polling or interrupt.
+ * @id: Controller id like MSP1 or MSP2 etc.
+ * @msp_io_error: To indicate error while transferring.
+ * @registers: MSP's register base address.
+ * @actual_data_size: Data size in which data needs to send or receive.
+ * @irq: MSP's irq number.
+ * @i2s_cont: MSP's Controller's structure pointer created per MSP.
+ * @gpio_alt_func: Gpio Alt function id of particular msp.
+ * @lock: semaphore lock acquired while configuring msp.
+ * @dma_cfg_tx: TX DMA configuration
+ * @dma_cfg_rx: RX DMA configuration
+ * @tx_pipeid: TX DMA channel
+ * @rx_pipeid: RX DMA channel
+ * @msp_state: Current state of msp.
+ * @read: Function pointer for read, u8_msp_read,u16_msp_read,u32_msp_read.
+ * @write: Function pointer for write, u8_msp_write,u16_msp_write,u32_msp_write.
+ * @transfer: Function pointer for type of transfer i.e dma,polling or interrupt
+ * @xfer_data: MSP's transfer data structure. Contains info about current xfer.
+ * @plat_init: MSP's initialization function.
+ * @plat_exit: MSP's Exit function.
+ * @notify_timer: Timer used in Polling mode to prevent hang.
+ * @polling_flag: Flag used in error handling while polling.
+ * @def_elem_len: Flag indicates whether default elem len to be used in
+ * protocol_desc or not.
+ * @vape_opp_constraint: 1 if constraint is applied to have vape at 100OPP; 0 otherwise
+ * @infinite: true if an infinite transfer has been configured
+ *
+ * Main Msp private data structure to be used to store various info of a
+ * particular MSP.Longer description
+ */
+struct msp {
+ int work_mode;
+ enum enum_i2s_controller id;
+ int msp_io_error;
+ void __iomem *registers;
+ enum msp_data_size actual_data_size;
+ int irq;
+ struct i2s_controller *i2s_cont;
+ u32 gpio_alt_func;
+ struct semaphore lock;
+ struct stedma40_chan_cfg *dma_cfg_rx;
+ struct stedma40_chan_cfg *dma_cfg_tx;
+ struct dma_chan *tx_pipeid;
+ struct dma_chan *rx_pipeid;
+ enum msp_state msp_state;
+ void (*read) (struct trans_data *xfer_data);
+ void (*write) (struct trans_data *xfer_data);
+ int (*transfer) (struct msp *msp, struct i2s_message *message);
+ struct trans_data xfer_data;
+ int (*plat_init) (u32);
+ int (*plat_exit) (u32);
+ struct timer_list notify_timer;
+ int polling_flag;
+ int def_elem_len;
+ struct clk *clk;
+ unsigned int direction;
+ int users;
+ int loopback_enable;
+ u32 backup_regs[MAX_MSP_BACKUP_REGS];
+ int vape_opp_constraint;
+ bool infinite;
+};
+
+/**
+ * struct msp_i2s_platform_data - Main msp controller platform data structure.
+ * @id: Controller id like MSP1 or MSP2 etc.
+ * @gpio_alt_func: Gpio Alt function id of particular msp.
+ * @msp_i2s_dma_rx: RX DMA channel config
+ * @msp_i2s_dma_tx: RX DMA channel config
+ * msp_i2s_init@: MSP's initialization function.
+ * @msp_i2s_exit: MSP's Exit function.
+ * @backup_regs: used for backup registers during suspend resume.
+ *
+ * Platform data structure passed by devices.c file.
+ */
+struct msp_i2s_platform_data {
+ enum enum_i2s_controller id;
+ u32 gpio_alt_func;
+ struct stedma40_chan_cfg *msp_i2s_dma_rx;
+ struct stedma40_chan_cfg *msp_i2s_dma_tx;
+ int (*msp_i2s_init) (u32);
+ int (*msp_i2s_exit) (u32);
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/mtu.h b/arch/arm/mach-ux500/include/mach/mtu.h
new file mode 100644
index 00000000000..d778c24e3e3
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/mtu.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson SA
+ * MultiTimerUnit register definitions, copied from Nomadik 8815
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __ASM_ARCH_MTU_H
+#define __ASM_ARCH_MTU_H
+
+/*
+ * The MTU device hosts four different counters, with 4 set of
+ * registers. These are register names.
+ */
+
+#define MTU_IMSC 0x00 /* Interrupt mask set/clear */
+#define MTU_RIS 0x04 /* Raw interrupt status */
+#define MTU_MIS 0x08 /* Masked interrupt status */
+#define MTU_ICR 0x0C /* Interrupt clear register */
+
+/* per-timer registers take 0..3 as argument */
+#define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */
+#define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */
+#define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */
+#define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */
+
+/* bits for the control register */
+#define MTU_CRn_ENA 0x80
+#define MTU_CRn_PERIODIC 0x40 /* if 0 = free-running */
+#define MTU_CRn_PRESCALE_MASK 0x0c
+#define MTU_CRn_PRESCALE_1 0x00
+#define MTU_CRn_PRESCALE_16 0x04
+#define MTU_CRn_PRESCALE_256 0x08
+#define MTU_CRn_32BITS 0x02
+#define MTU_CRn_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR*/
+
+/* Other registers are usual amba/primecell registers, currently not used */
+#define MTU_ITCR 0xff0
+#define MTU_ITOP 0xff4
+
+#define MTU_PERIPH_ID0 0xfe0
+#define MTU_PERIPH_ID1 0xfe4
+#define MTU_PERIPH_ID2 0xfe8
+#define MTU_PERIPH_ID3 0xfeC
+
+#define MTU_PCELL0 0xff0
+#define MTU_PCELL1 0xff4
+#define MTU_PCELL2 0xff8
+#define MTU_PCELL3 0xffC
+
+
+#ifdef CONFIG_LOCAL_TIMERS
+extern void __iomem *twd_base;
+#endif
+
+#endif /* __ASM_ARCH_MTU_H */
+
diff --git a/arch/arm/mach-ux500/include/mach/musb_db8500.h b/arch/arm/mach-ux500/include/mach/musb_db8500.h
new file mode 100644
index 00000000000..a247c3bd0fd
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/musb_db8500.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009 ST Ericsson.
+ *
+ * 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.
+ */
+
+/* AB8500 USB macros
+ */
+#define AB8500_REV_10 0x10
+#define AB8500_REV_11 0x11
+#define AB8500_REV_20 0x20
+#define AB8500_USB_HOST 0x68
+#define AB8500_USB_LINK_STATUS_UPDT_DONE 135
+#define AB8500_IT_MASK20_MASK 0xFB
+#define AB8500_IT_MASK21_MASK 0xBE
+#define AB8500_IT_MASK2_MASK 0x3F
+#define AB8500_IT_MASK12_MASK 0x7F
+#define AB8500_SRC_INT_USB_DEVICE 0x80
+#define AB8500_SRC_INT_USB_HOST 0x04
+#define AB8500_VBUS_ENABLE 0x1
+#define AB8500_VBUS_DISABLE 0x0
+#define AB8500_USB_HOST_ENABLE 0x1
+#define AB8500_USB_HOST_DISABLE 0x0
+#define AB8500_USB_DEVICE_ENABLE 0x2
+#define AB8500_USB_DEVICE_DISABLE 0x0
+#define AB8500_MAIN_WATCHDOG_ENABLE 0x1
+#define AB8500_MAIN_WATCHDOG_KICK 0x2
+#define AB8500_MAIN_WATCHDOG_DISABLE 0x0
+#define AB8500_USB_ADP_ENABLE 0x1
+
+/* USB Macros
+ */
+#define WATCHDOG_DELAY 10
+#define WATCHDOG_DELAY_US 100
+#define USB_ENABLE 1
+#define USB_DISABLE 0
+
+/* UsbLineStatus register - usb types */
+enum {
+ USB_LINK_NOT_CONFIGURED,
+ USB_LINK_STD_HOST_NC,
+ USB_LINK_STD_HOST_C_NS,
+ USB_LINK_STD_HOST_C_S,
+ USB_LINK_HOST_CHG_NM,
+ USB_LINK_HOST_CHG_HS,
+ USB_LINK_HOST_CHG_HS_CHIRP,
+ USB_LINK_DEDICATED_CHG,
+ USB_LINK_ACA_RID_A,
+ USB_LINK_ACA_RID_B,
+ USB_LINK_ACA_RID_C_NM,
+ USB_LINK_ACA_RID_C_HS,
+ USB_LINK_ACA_RID_C_HS_CHIRP,
+ USB_LINK_HM_IDGND,
+ USB_LINK_RESERVED,
+ USB_LINK_NOT_VALID_LINK,
+};
+
+
+/* Specific functions for USB Phy enable and disable
+ */
+int musb_phy_en(u8 mode);
+int musb_force_detect(u8 mode);
+void usb_kick_watchdog(void);
+void usb_host_phy_en(int);
+void usb_device_phy_en(int);
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-db5500.h b/arch/arm/mach-ux500/include/mach/prcmu-db5500.h
new file mode 100644
index 00000000000..f240e84360f
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/prcmu-db5500.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * U5500 PRCMU API.
+ */
+#ifndef __MACH_PRCMU_U5500_H
+#define __MACH_PRCMU_U5500_H
+
+#ifdef CONFIG_U5500_PRCMU
+
+void prcmu_early_init(void);
+
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+
+#else /* !CONFIG_U5500_PRCMU */
+
+static inline void prcmu_early_init(void)
+{
+}
+
+static inline int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ return -ENOSYS;
+}
+
+static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ return -ENOSYS;
+}
+
+#endif /* CONFIG_U5500_PRCMU */
+
+static inline int prcmu_config_abb_event_readout(u32 abb_events)
+{
+#ifdef CONFIG_MACH_U5500_SIMULATOR
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+#endif /* __MACH_PRCMU_U5500_H */
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-fw-api.h b/arch/arm/mach-ux500/include/mach/prcmu-fw-api.h
new file mode 100644
index 00000000000..716bb04b8a8
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/prcmu-fw-api.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
+ *
+ * PRCMU f/w APIs
+ */
+#ifndef __MACH_PRCMU_FW_API_H
+#define __MACH_PRCMU_FW_API_H
+
+#include <linux/interrupt.h>
+#include "prcmu-fw-defs_v1.h"
+
+/* PRCMU Wakeup defines */
+#define PRCMU_WAKEUPBY_MODEM_SW_RESET_REQ (0x1 << 20)
+#define PRCMU_WAKEUPBY_MODEM (0x1 << 5)
+#define PRCMU_WAKEUPBY_ARMITMGMT (0x1 << 17)
+#define PRCMU_WAKEUPBY_APE4500INT (0x1 << 7)
+#define PRCMU_WAKEUPBY_GPIOS (0xff800000)
+#define PRCMU_WAKEUPBY_RTCRTT (0x3)
+#define PRCMU_WAKEUPBY_AB8500_NONE (0x0)
+
+#define LOW_POWER_WAKEUP 1
+#define EXE_WAKEUP 0
+
+/* PRCMU QoS APE OPP class */
+#define PRCMU_QOS_APE_OPP 1
+#define PRCMU_QOS_DEFAULT_VALUE -1
+
+/**
+ * enum hw_acc_dev - enum for hw accelerators
+ * @HW_ACC_SVAMMDSP: for SVAMMDSP
+ * @HW_ACC_SVAPIPE: for SVAPIPE
+ * @HW_ACC_SIAMMDSP: for SIAMMDSP
+ * @HW_ACC_SIAPIPE: for SIAPIPE
+ * @HW_ACC_SGA: for SGA
+ * @HW_ACC_B2R2: for B2R2
+ * @HW_ACC_MCDE: for MCDE
+ * @HW_ACC_ESRAM1: for ESRAM1
+ * @HW_ACC_ESRAM2: for ESRAM2
+ * @HW_ACC_ESRAM3: for ESRAM3
+ * @HW_ACC_ESRAM4: for ESRAM4
+ *
+ * Different hw accelerators which can be turned ON/
+ * OFF or put into retention the ESRAMs.
+ * Used with EPOD API.
+ */
+enum hw_acc_dev{
+ HW_ACC_SVAMMDSP = 0,
+ HW_ACC_SVAPIPE = 1,
+ HW_ACC_SIAMMDSP = 2,
+ HW_ACC_SIAPIPE = 3,
+ HW_ACC_SGA = 4,
+ HW_ACC_B2R2 = 0x005,
+ HW_ACC_MCDE = 0x105,
+ HW_ACC_ESRAM1 = 0x006,
+ HW_ACC_ESRAM2 = 0x106,
+ HW_ACC_ESRAM3 = 0x007,
+ HW_ACC_ESRAM4 = 0x107,
+};
+
+/**
+ * union sia_sva_pwron_enable - Power ON for SIA-SVA
+ * @req_field: requested state for hardware semaphore,
+ * ab4500 fifo.
+ * @complete_field:
+ *
+ */
+union sia_sva_pwron_enable {
+ struct {
+ u8 hsem:1;
+ u8 fifo_4500_it:1;
+ u8 bit_fill:6;
+ } req_field;
+ u8 complete_field;
+};
+
+/**
+ * struct sia_sva_auto_power - Auto power policy struct
+ * @sia_pwr_policy: SIA power policy
+ * @sva_pwr_policy: SVA power policy
+ * @sia_pwron_enable: SIA power ON Enable
+ * @sva_pwron_enable: SVA power ON Enable
+ * @auto_pwron_enable: Auto power ON Enable
+ *
+ */
+struct sia_sva_auto_power {
+ enum sia_sva_pwr_policy sia_pwr_policy:4;
+ enum sia_sva_pwr_policy sva_pwr_policy:4;
+ union sia_sva_pwron_enable sia_pwron_enable;
+ union sia_sva_pwron_enable sva_pwron_enable;
+ enum auto_enable auto_pwron_enable;
+};
+
+/*
+ * Clock identifiers.
+ * This is expected to grow.
+ */
+enum prcmu_clock {
+ PRCMU_SYSCLK = 0xFF
+};
+
+#if defined(CONFIG_U8500_PRCMU) || defined(CONFIG_U5500_PRCMU)
+void __init prcmu_early_init(void);
+#else
+static inline void __init prcmu_early_init(void) {}
+#endif
+
+#ifdef CONFIG_U8500_PRCMU
+
+int prcmu_set_rc_a2p(enum romcode_write);
+enum romcode_read prcmu_get_rc_p2a(void);
+enum ap_pwrst prcmu_get_xp70_current_state(void);
+int prcmu_set_power_state(u8 state);
+void prcmu_config_abb_event_readout(u32 abb_events);
+int prcmu_set_arm_opp(u8 opp);
+int prcmu_get_arm_opp(void);
+int prcmu_get_ape_opp(void);
+/* NOTE! Use regulator framework instead */
+int __deprecated prcmu_set_hwacc(u16 hw_acc_dev, u8 state);
+int prcmu_set_irq_wakeup(u32 irq);
+int prcmu_configure_auto_pwr_mgt(
+ struct sia_sva_auto_power,
+ struct sia_sva_auto_power);
+
+int prcmu_request_clock(u8 clock, bool enable);
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+
+int prcmu_ac_wake_req(void);
+int prcmu_ac_sleep_req(void);
+void prcmu_system_reset(void);
+int prcmu_enable_mcde(void);
+
+/*
+ * Functions calling prcmu_apply_ap_state_transition should be rewritten to
+ * use prcmu_set_power_state instead.
+ */
+int __deprecated prcmu_apply_ap_state_transition(
+ enum ap_pwrst_trans transition,
+ enum ddr_pwrst ddr_state_req,
+ int _4500_fifo_wakeup);
+/*
+ * prcmu_configure_wakeup_events and prcmu_set_callback_* are deprecated.
+ * Use request_irq on the respective irqs instead, and enable and disable
+ * them as necessary.
+ */
+int __deprecated prcmu_configure_wakeup_events(u32 dbb_events, u32 abb_events,
+ int low_power);
+
+int prcmu_qos_requirement(int pm_qos_class);
+int prcmu_qos_add_requirement(int pm_qos_class, char *name, s32 value);
+int prcmu_qos_update_requirement(int pm_qos_class, char *name, s32 new_value);
+void prcmu_qos_remove_requirement(int pm_qos_class, char *name);
+
+#else /* !CONFIG_U8500_PRCMU */
+
+static inline int prcmu_set_rc_a2p(enum romcode_write code)
+{
+ return 0;
+}
+
+static inline enum romcode_read prcmu_get_rc_p2a(void)
+{
+ return INIT;
+}
+
+static inline enum ap_pwrst prcmu_get_xp70_current_state(void)
+{
+ return AP_EXECUTE;
+}
+
+static inline int prcmu_set_power_state(u8 state)
+{
+ return 0;
+}
+
+static inline void prcmu_config_abb_event_readout(u32 abb_events) {}
+
+static inline int prcmu_set_arm_opp(u8 opp)
+{
+ return 0;
+}
+
+static inline int prcmu_get_arm_opp(void)
+{
+ return ARM_100_OPP;
+}
+
+static inline int prcmu_get_ape_opp(void)
+{
+ return APE_100_OPP;
+}
+
+static inline int prcmu_set_hwacc(u16 hw_acc_dev, u8 state)
+{
+ return 0;
+}
+
+static inline int prcmu_set_irq_wakeup(u32 irq)
+{
+ return 0;
+}
+
+static inline int prcmu_configure_auto_pwr_mgt(struct sia_sva_auto_power sleep,
+ struct sia_sva_auto_power idle)
+{
+ return 0;
+}
+
+static inline int prcmu_request_clock(u8 clock, bool enable)
+{
+ return 0;
+}
+
+static inline int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ return -ENOSYS;
+}
+
+static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ return -ENOSYS;
+}
+
+static inline int prcmu_ac_wake_req(void)
+{
+ return 0;
+}
+
+static inline int prcmu_ac_sleep_req(void)
+{
+ return 0;
+}
+
+static inline void prcmu_system_reset(void) {}
+
+static inline int prcmu_enable_mcde(void)
+{
+ return 0;
+}
+
+static inline int __deprecated prcmu_apply_ap_state_transition(
+ enum ap_pwrst_trans transition,
+ enum ddr_pwrst ddr_state_req,
+ int _4500_fifo_wakeup)
+{
+ return 0;
+}
+
+static inline int __deprecated prcmu_configure_wakeup_events(u32 dbb_events,
+ u32 abb_events, int low_power)
+{
+ return 0;
+}
+
+static inline int prcmu_qos_requirement(int prcmu_qos_class)
+{
+ return 0;
+}
+
+static inline int prcmu_qos_add_requirement(int prcmu_qos_class,
+ char *name, s32 value)
+{
+ return 0;
+}
+
+static inline int prcmu_qos_update_requirement(int prcmu_qos_class,
+ char *name, s32 new_value)
+{
+ return 0;
+}
+
+static inline void prcmu_qos_remove_requirement(int prcmu_qos_class, char *name)
+{
+}
+
+#endif /* CONFIG_U8500_PRCMU */
+
+#endif /* __MACH_PRCMU_FW_API_V1_H */
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-fw-defs_v1.h b/arch/arm/mach-ux500/include/mach/prcmu-fw-defs_v1.h
new file mode 100644
index 00000000000..b27f4edd863
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/prcmu-fw-defs_v1.h
@@ -0,0 +1,588 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
+ *
+ * PRCMU definitions for U8500 v1.0 cut
+ */
+#ifndef __MACH_PRCMU_FW_DEFS_V1_H
+#define __MACH_PRCMU_FW_DEFS_V1_H
+
+#include <linux/interrupt.h>
+
+/**
+ * enum state - ON/OFF state definition
+ * @OFF: State is ON
+ * @ON: State is OFF
+ *
+ */
+enum state {
+ OFF = 0x0,
+ ON = 0x1,
+};
+
+/**
+ * enum ret_state - general purpose On/Off/Retention states
+ *
+ */
+enum ret_state {
+ OFFST = 0,
+ ONST = 1,
+ RETST = 2
+};
+
+
+/**
+ * enum clk_arm - ARM Cortex A9 clock schemes
+ * @A9_OFF:
+ * @A9_BOOT:
+ * @A9_OPPT1:
+ * @A9_OPPT2:
+ * @A9_EXTCLK:
+ */
+enum clk_arm {
+ A9_OFF,
+ A9_BOOT,
+ A9_OPPT1,
+ A9_OPPT2,
+ A9_EXTCLK
+};
+
+/**
+ * enum clk_gen - GEN#0/GEN#1 clock schemes
+ * @GEN_OFF:
+ * @GEN_BOOT:
+ * @GEN_OPPT1:
+ */
+enum clk_gen {
+ GEN_OFF,
+ GEN_BOOT,
+ GEN_OPPT1,
+};
+
+/* some information between arm and xp70 */
+
+/**
+ * enum romcode_write - Romcode message written by A9 AND read by XP70
+ * @RDY_2_DS: Value set when ApDeepSleep state can be executed by XP70
+ * @RDY_2_XP70_RST: Value set when 0x0F has been successfully polled by the
+ * romcode. The xp70 will go into self-reset
+ */
+enum romcode_write {
+ RDY_2_DS = 0x09,
+ RDY_2_XP70_RST = 0x10
+};
+
+/**
+ * enum romcode_read - Romcode message written by XP70 and read by A9
+ * @INIT: Init value when romcode field is not used
+ * @FS_2_DS: Value set when power state is going from ApExecute to
+ * ApDeepSleep
+ * @END_DS: Value set when ApDeepSleep power state is reached coming from
+ * ApExecute state
+ * @DS_TO_FS: Value set when power state is going from ApDeepSleep to
+ * ApExecute
+ * @END_FS: Value set when ApExecute power state is reached coming from
+ * ApDeepSleep state
+ * @SWR: Value set when power state is going to ApReset
+ * @END_SWR: Value set when the xp70 finished executing ApReset actions and
+ * waits for romcode acknowledgment to go to self-reset
+ */
+enum romcode_read {
+ INIT = 0x00,
+ FS_2_DS = 0x0A,
+ END_DS = 0x0B,
+ DS_TO_FS = 0x0C,
+ END_FS = 0x0D,
+ SWR = 0x0E,
+ END_SWR = 0x0F
+};
+
+
+/**
+ * enum pingpong
+ * @PING: value is 0
+ * @PONG: value is 1
+ *
+ * implementation issue: the values are chosen the way that
+ * we can change from ping to pong (resp. pong to ping) by
+ * simply using the 'not' operator in C, e.g. toggling operation:
+ * t_PingPong p = ping; p = ~p;
+ */
+enum pingpong {
+ PING = 0x00,
+ PONG = 0xFF
+};
+
+/**
+ * enum wkup_reason_fdst
+ * @EVTWR: event has been read by ARM
+ * @EVTST: event has been sent by PRCMU FW
+ * @EVTRD: event has been written by PRCMU FW
+ */
+enum wkup_reason_fdst {
+ /* WRF has been written but neither sent nor read by the arm */
+ EVTWR = 1,
+ /* WRF has been written and sent, but not yet read by the arm */
+ EVTST = 2,
+ /* WRF has been written, sent and read by the arm */
+ EVTRD = 0
+}; /* Wake-up reason Field State */
+
+
+
+/**
+ * enum ap_pwrst - current power states defined in PRCMU firmware
+ * @NO_PWRST: Current power state init
+ * @AP_BOOT: Current power state is apBoot
+ * @AP_EXECUTE: Current power state is apExecute
+ * @AP_DEEP_SLEEP: Current power state is apDeepSleep
+ * @AP_SLEEP: Current power state is apSleep
+ * @AP_IDLE: Current power state is apIdle
+ * @AP_RESET: Current power state is apReset
+ */
+enum ap_pwrst {
+ NO_PWRST = 0x00,
+ AP_BOOT = 0x01,
+ AP_EXECUTE = 0x02,
+ AP_DEEP_SLEEP = 0x03,
+ AP_SLEEP = 0x04,
+ AP_IDLE = 0x05,
+ AP_RESET = 0x06
+};
+
+/**
+ * enum ap_pwrst_trans - Transition states defined in PRCMU firmware
+ * @NO_TRANSITION: No power state transition
+ * @APEXECUTE_TO_APSLEEP: Power state transition from ApExecute to ApSleep
+ * @APIDLE_TO_APSLEEP: Power state transition from ApIdle to ApSleep
+ * @APBOOT_TO_APEXECUTE: Power state transition from ApBoot to ApExecute
+ * @APEXECUTE_TO_APDEEPSLEEP: Power state transition from ApExecute to
+ * ApDeepSleep
+ * @APEXECUTE_TO_APIDLE: Power state transition from ApExecute to ApIdle
+ */
+enum ap_pwrst_trans {
+ NO_TRANSITION = 0x00,
+ APEXECUTE_TO_APSLEEP = 0x01,
+ APIDLE_TO_APSLEEP = 0x02, /* To be removed */
+ PRCMU_AP_SLEEP = 0x01,
+ APBOOT_TO_APEXECUTE = 0x03,
+ APEXECUTE_TO_APDEEPSLEEP = 0x04, /* To be removed */
+ PRCMU_AP_DEEP_SLEEP = 0x04,
+ APEXECUTE_TO_APIDLE = 0x05, /* To be removed */
+ PRCMU_AP_IDLE = 0x05,
+};
+
+/**
+ * enum ddr_pwrst - DDR power states definition
+ * @DDR_PWR_STATE_UNCHANGED: SDRAM and DDR controller state is unchanged
+ * @DDR_PWR_STATE_ON:
+ * @DDR_PWR_STATE_OFFLOWLAT:
+ * @DDR_PWR_STATE_OFFHIGHLAT:
+ */
+enum ddr_pwrst {
+ DDR_PWR_STATE_UNCHANGED = 0x00,
+ DDR_PWR_STATE_ON = 0x01,
+ DDR_PWR_STATE_OFFLOWLAT = 0x02,
+ DDR_PWR_STATE_OFFHIGHLAT = 0x03
+};
+
+/**
+ * enum arm_opp - ARM OPP states definition
+ * @ARM_NO_CHANGE: The ARM operating point is unchanged
+ * @ARM_100_OPP: The new ARM operating point is arm100opp
+ * @ARM_50_OPP: The new ARM operating point is arm100opp
+ * @ARM_EXTCLK: The new ARM operating point is armExtClk
+ */
+enum arm_opp {
+ ARM_NO_CHANGE = 0x00,
+ ARM_100_OPP = 0x02,
+ ARM_50_OPP = 0x03,
+ ARM_EXTCLK = 0x07
+};
+
+/**
+ * enum ape_opp - APE OPP states definition
+ * @APE_NO_CHANGE: The APE operating point is unchanged
+ * @APE_100_OPP: The new APE operating point is ape100opp
+ */
+enum ape_opp {
+ APE_NO_CHANGE = 0x00,
+ APE_100_OPP = 0x02,
+ APE_50_OPP = 0x03
+};
+
+/**
+ * enum hw_acc_state - State definition for hardware accelerator
+ * @HW_NO_CHANGE: The hardware accelerator state must remain unchanged
+ * @HW_OFF: The hardware accelerator must be switched off
+ * @HW_OFF_RAMRET: The hardware accelerator must be switched off with its
+ * internal RAM in retention
+ * @HW_ON: The hwa hadware accelerator hwa must be switched on
+ */
+enum hw_acc_state {
+ HW_NO_CHANGE = 0x00,
+ HW_OFF = 0x01,
+ HW_OFF_RAMRET = 0x02,
+ HW_ON = 0x03
+};
+
+/**
+ * enum mbox_2_arm_stat - Status messages definition for mbox_arm
+ * @BOOT_TO_EXECUTEOK: The apBoot to apExecute state transition has been
+ * completed
+ * @DEEPSLEEPOK: The apExecute to apDeepSleep state transition has been
+ * completed
+ * @SLEEPOK: The apExecute to apSleep state transition has been completed
+ * @IDLEOK: The apExecute to apIdle state transition has been completed
+ * @SOFTRESETOK: The A9 watchdog/ SoftReset state has been completed
+ * @SOFTRESETGO : The A9 watchdog/SoftReset state is on going
+ * @BOOT_TO_EXECUTE: The apBoot to apExecute state transition is on going
+ * @EXECUTE_TO_DEEPSLEEP: The apExecute to apDeepSleep state transition is on
+ * going
+ * @DEEPSLEEP_TO_EXECUTE: The apDeepSleep to apExecute state transition is on
+ * going
+ * @DEEPSLEEP_TO_EXECUTEOK: The apDeepSleep to apExecute state transition has
+ * been completed
+ * @EXECUTE_TO_SLEEP: The apExecute to apSleep state transition is on going
+ * @SLEEP_TO_EXECUTE: The apSleep to apExecute state transition is on going
+ * @SLEEP_TO_EXECUTEOK: The apSleep to apExecute state transition has been
+ * completed
+ * @EXECUTE_TO_IDLE: The apExecute to apIdle state transition is on going
+ * @IDLE_TO_EXECUTE: The apIdle to apExecute state transition is on going
+ * @IDLE_TO_EXECUTEOK: The apIdle to apExecute state transition has been
+ * completed
+ * @INIT_STATUS: Status init
+ */
+enum ap_pwrsttr_status {
+ BOOT_TO_EXECUTEOK = 0xFF,
+ DEEPSLEEPOK = 0xFE,
+ SLEEPOK = 0xFD,
+ IDLEOK = 0xFC,
+ SOFTRESETOK = 0xFB,
+ SOFTRESETGO = 0xFA,
+ BOOT_TO_EXECUTE = 0xF9,
+ EXECUTE_TO_DEEPSLEEP = 0xF8,
+ DEEPSLEEP_TO_EXECUTE = 0xF7,
+ DEEPSLEEP_TO_EXECUTEOK = 0xF6,
+ EXECUTE_TO_SLEEP = 0xF5,
+ SLEEP_TO_EXECUTE = 0xF4,
+ SLEEP_TO_EXECUTEOK = 0xF3,
+ EXECUTE_TO_IDLE = 0xF2,
+ IDLE_TO_EXECUTE = 0xF1,
+ IDLE_TO_EXECUTEOK = 0xF0,
+ RDYTODS_RETURNTOEXE = 0xEF,
+ NORDYTODS_RETURNTOEXE = 0xEE,
+ EXETOSLEEP_RETURNTOEXE = 0xED,
+ EXETOIDLE_RETURNTOEXE = 0xEC,
+ INIT_STATUS = 0xEB,
+
+ /*error messages */
+ INITERROR = 0x00,
+ PLLARMLOCKP_ER = 0x01,
+ PLLDDRLOCKP_ER = 0x02,
+ PLLSOCLOCKP_ER = 0x03,
+ PLLSOCK1LOCKP_ER = 0x04,
+ ARMWFI_ER = 0x05,
+ SYSCLKOK_ER = 0x06,
+ I2C_NACK_DATA_ER = 0x07,
+ BOOT_ER = 0x08,
+ I2C_STATUS_ALWAYS_1 = 0x0A,
+ I2C_NACK_REG_ADDR_ER = 0x0B,
+ I2C_NACK_DATA0123_ER = 0x1B,
+ I2C_NACK_ADDR_ER = 0x1F,
+ CURAPPWRSTISNOT_BOOT = 0x20,
+ CURAPPWRSTISNOT_EXECUTE = 0x21,
+ CURAPPWRSTISNOT_SLEEPMODE = 0x22,
+ CURAPPWRSTISNOT_CORRECTFORIT10 = 0x23,
+ FIFO4500WUISNOT_WUPEVENT = 0x24,
+ PLL32KLOCKP_ER = 0x29,
+ DDRDEEPSLEEPOK_ER = 0x2A,
+ ROMCODEREADY_ER = 0x50,
+ WUPBEFOREDS = 0x51,
+ DDRCONFIG_ER = 0x52,
+ WUPBEFORESLEEP = 0x53,
+ WUPBEFOREIDLE = 0x54
+}; /* earlier called as mbox_2_arm_stat */
+
+
+/**
+ * enum dvfs_stat - DVFS status messages definition
+ * @DVFS_GO: A state transition DVFS is on going
+ * @DVFS_ARM100OPPOK: The state transition DVFS has been completed for 100OPP
+ * @DVFS_ARM50OPPOK: The state transition DVFS has been completed for 50OPP
+ * @DVFS_ARMEXTCLKOK: The state transition DVFS has been completed for EXTCLK
+ * @DVFS_NOCHGTCLKOK: The state transition DVFS has been completed for
+ * NOCHGCLK
+ * @DVFS_INITSTATUS: Value init
+ */
+enum dvfs_stat {
+ DVFS_GO = 0xFF,
+ DVFS_ARM100OPPOK = 0xFE,
+ DVFS_ARM50OPPOK = 0xFD,
+ DVFS_ARMEXTCLKOK = 0xFC,
+ DVFS_NOCHGTCLKOK = 0xFB,
+ DVFS_INITSTATUS = 0x00
+};
+
+/**
+ * enum mbox_2_arm_hwacc_pwr_stat - Hardware Accelarator status message
+ * @HWACC_PWRST_GO: A state transition on hardware accelerator is on going
+ * @HWACC_PWRST_OK: The state transition on hardware accelerator has been
+ * completed
+ * @HWACC_PWRSTATUS_INIT: Value init
+ */
+enum mbox_2_arm_hwacc_pwr_stat {
+ HWACC_PWRST_GO = 0xFF,
+ HWACC_PWRST_OK = 0xFE,
+ HWACC_PWRSTATUS_INIT = 0x00
+};
+
+/**
+ * enum sva_mmdsp_stat - SVA MMDSP status messages
+ * @SVA_MMDSP_GO: SVAMMDSP interrupt has happened
+ * @SVA_MMDSP_INIT: Status init
+ */
+enum sva_mmdsp_stat {
+ SVA_MMDSP_GO = 0xFF,
+ SVA_MMDSP_INIT = 0x00
+};
+
+/**
+ * enum sia_mmdsp_stat - SIA MMDSP status messages
+ * @SIA_MMDSP_GO: SIAMMDSP interrupt has happened
+ * @SIA_MMDSP_INIT: Status init
+ */
+enum sia_mmdsp_stat {
+ SIA_MMDSP_GO = 0xFF,
+ SIA_MMDSP_INIT = 0x00
+};
+
+/**
+ * enum intr_wakeup - Configure STW4500 FIFO interrupt as wake-up
+ * @NTR_NOT_AS_WAKEUP: The 4500 fifo interrupt is not configured as a
+ * wake-up event
+ * @INTR_AS_WAKEUP: The 4500 fifo interrupt is configured as a wake-up event
+ */
+enum intr_wakeup {
+ INTR_NOT_AS_WAKEUP = 0x0,
+ INTR_AS_WAKEUP = 0x1
+};
+
+/**
+ * enum mbox_to_arm_err - Error messages definition
+ * @INIT_ERR: Init value
+ * @PLLARMLOCKP_ERR: PLLARM has not been correctly locked in given time
+ * @PLLDDRLOCKP_ERR: PLLDDR has not been correctly locked in the given time
+ * @PLLSOC0LOCKP_ERR: PLLSOC0 has not been correctly locked in the given time
+ * @PLLSOC1LOCKP_ERR: PLLSOC1 has not been correctly locked in the given time
+ * @ARMWFI_ERR: The ARM WFI has not been correctly executed in the given time
+ * @SYSCLKOK_ERR: The SYSCLK is not available in the given time
+ * @BOOT_ERR: Romcode has not validated the XP70 self reset in the given time
+ * @ROMCODESAVECONTEXT: The Romcode didn.t correctly save it secure context
+ * @VARMHIGHSPEEDVALTO_ERR: The ARM high speed supply value transfered
+ * through I2C has not been correctly executed in the given time
+ * @VARMHIGHSPEEDACCESS_ERR: The command value of VarmHighSpeedVal transfered
+ * through I2C has not been correctly executed in the given time
+ * @VARMLOWSPEEDVALTO_ERR:The ARM low speed supply value transfered through
+ * I2C has not been correctly executed in the given time
+ * @VARMLOWSPEEDACCESS_ERR: The command value of VarmLowSpeedVal transfered
+ * through I2C has not been correctly executed in the given time
+ * @VARMRETENTIONVALTO_ERR: The ARM retention supply value transfered through
+ * I2C has not been correctly executed in the given time
+ * @VARMRETENTIONACCESS_ERR: The command value of VarmRetentionVal transfered
+ * through I2C has not been correctly executed in the given time
+ * @VAPEHIGHSPEEDVALTO_ERR: The APE highspeed supply value transfered through
+ * I2C has not been correctly executed in the given time
+ * @VSAFEHPVALTO_ERR: The SAFE high power supply value transfered through I2C
+ * has not been correctly executed in the given time
+ * @VMODSEL1VALTO_ERR: The MODEM sel1 supply value transfered through I2C has
+ * not been correctly executed in the given time
+ * @VMODSEL2VALTO_ERR: The MODEM sel2 supply value transfered through I2C has
+ * not been correctly executed in the given time
+ * @VARMOFFACCESS_ERR: The command value of Varm ON/OFF transfered through
+ * I2C has not been correctly executed in the given time
+ * @VAPEOFFACCESS_ERR: The command value of Vape ON/OFF transfered through
+ * I2C has not been correctly executed in the given time
+ * @VARMRETACCES_ERR: The command value of Varm retention ON/OFF transfered
+ * through I2C has not been correctly executed in the given time
+ * @CURAPPWRSTISNOTBOOT:Generated when Arm want to do power state transition
+ * ApBoot to ApExecute but the power current state is not Apboot
+ * @CURAPPWRSTISNOTEXECUTE: Generated when Arm want to do power state
+ * transition from ApExecute to others power state but the
+ * power current state is not ApExecute
+ * @CURAPPWRSTISNOTSLEEPMODE: Generated when wake up events are transmitted
+ * but the power current state is not ApDeepSleep/ApSleep/ApIdle
+ * @CURAPPWRSTISNOTCORRECTDBG: Generated when wake up events are transmitted
+ * but the power current state is not correct
+ * @ARMREGU1VALTO_ERR:The ArmRegu1 value transferred through I2C has not
+ * been correctly executed in the given time
+ * @ARMREGU2VALTO_ERR: The ArmRegu2 value transferred through I2C has not
+ * been correctly executed in the given time
+ * @VAPEREGUVALTO_ERR: The VApeRegu value transfered through I2C has not
+ * been correctly executed in the given time
+ * @VSMPS3REGUVALTO_ERR: The VSmps3Regu value transfered through I2C has not
+ * been correctly executed in the given time
+ * @VMODREGUVALTO_ERR: The VModemRegu value transfered through I2C has not
+ * been correctly executed in the given time
+ */
+enum mbox_to_arm_err {
+ INIT_ERR = 0x00,
+ PLLARMLOCKP_ERR = 0x01,
+ PLLDDRLOCKP_ERR = 0x02,
+ PLLSOC0LOCKP_ERR = 0x03,
+ PLLSOC1LOCKP_ERR = 0x04,
+ ARMWFI_ERR = 0x05,
+ SYSCLKOK_ERR = 0x06,
+ BOOT_ERR = 0x07,
+ ROMCODESAVECONTEXT = 0x08,
+ VARMHIGHSPEEDVALTO_ERR = 0x10,
+ VARMHIGHSPEEDACCESS_ERR = 0x11,
+ VARMLOWSPEEDVALTO_ERR = 0x12,
+ VARMLOWSPEEDACCESS_ERR = 0x13,
+ VARMRETENTIONVALTO_ERR = 0x14,
+ VARMRETENTIONACCESS_ERR = 0x15,
+ VAPEHIGHSPEEDVALTO_ERR = 0x16,
+ VSAFEHPVALTO_ERR = 0x17,
+ VMODSEL1VALTO_ERR = 0x18,
+ VMODSEL2VALTO_ERR = 0x19,
+ VARMOFFACCESS_ERR = 0x1A,
+ VAPEOFFACCESS_ERR = 0x1B,
+ VARMRETACCES_ERR = 0x1C,
+ CURAPPWRSTISNOTBOOT = 0x20,
+ CURAPPWRSTISNOTEXECUTE = 0x21,
+ CURAPPWRSTISNOTSLEEPMODE = 0x22,
+ CURAPPWRSTISNOTCORRECTDBG = 0x23,
+ ARMREGU1VALTO_ERR = 0x24,
+ ARMREGU2VALTO_ERR = 0x25,
+ VAPEREGUVALTO_ERR = 0x26,
+ VSMPS3REGUVALTO_ERR = 0x27,
+ VMODREGUVALTO_ERR = 0x28
+};
+
+enum hw_acc {
+ SVAMMDSP = 0,
+ SVAPIPE = 1,
+ SIAMMDSP = 2,
+ SIAPIPE = 3,
+ SGA = 4,
+ B2R2MCDE = 5,
+ ESRAM12 = 6,
+ ESRAM34 = 7,
+};
+
+enum reqmb0_header {
+ PWRSTTRH = 0,
+ WKUPCFG_EXEH = 1,
+ WKUP_EXEH = 2,
+ RDWKUPACKH = 3,
+ WKUPCFG_SLEEPH = 4,
+ WKUP_SLEEPH = 5,
+};
+
+enum cs_pwrmgt {
+ PWRDNCS0 = 0,
+ WKUPCS0 = 1,
+ PWRDNCS1 = 2,
+ WKUPCS1 = 3
+};
+
+enum reqmb2_header {
+ DPS_H = 0,
+ HW_ACCT_AUTO_PWR_H = 1,
+};
+
+
+/* Defs related to autonomous power management */
+
+/**
+ * enum sia_sva_pwr_policy - Power policy
+ * @NO_CHGT: No change
+ * @DSPOFF_HWPOFF:
+ * @DSPOFFRAMRET_HWPOFF:
+ * @DSPCLKOFF_HWPOFF:
+ * @DSPCLKOFF_HWPCLKOFF:
+ *
+ */
+enum sia_sva_pwr_policy {
+ NO_CHGT = 0x0,
+ DSPOFF_HWPOFF = 0x1,
+ DSPOFFRAMRET_HWPOFF = 0x2,
+ DSPCLKOFF_HWPOFF = 0x3,
+ DSPCLKOFF_HWPCLKOFF = 0x4,
+};
+
+/**
+ * enum auto_enable - Auto Power enable
+ * @AUTO_OFF:
+ * @AUTO_ON:
+ *
+ */
+enum auto_enable {
+ AUTO_OFF = 0x0,
+ AUTO_ON = 0x1,
+};
+
+
+/**
+ * enum reqmb4_header -Header type for mail box 4
+ * @MEMSTH: The ARM can set what are the expected memory states depending on
+ * the AP power states.
+ * @PARTIALREFRESHH: ARM has to update MR16 & MR17 of SDRAM register, for
+ * partial-refresh of SDRAM, via this mailbox
+ * @AUTOREFRESHH: Enable to change cycle count before enabling automatic
+ * DDR self-refresh
+ * @CSPWRDNH: Enables to lock/unlock one of SDRAM memory cut in self-refresh
+ * In V2,this service will enable to put CS in pwrdn
+ * @SYSCLKH: Enables to switch SYSCLK ON/OFF on the AP side
+ * @USBWKUPH: Used to enable USB wakeup event of PRCMU
+ */
+enum reqmb4_header {
+ MEM_ST_H = 1,
+ AUTO_REFRESH_H = 2,
+ CS_PWRDN_H = 3,
+ PARTIAL_S_REFRESH_H = 4,
+ AUTO_PWR_H = 6,
+ USB_WKUP_H = 7,
+ SYSCLK_H = 0xE,
+ WORKAROUND2_H = 0xF
+};
+
+enum ack_mb4_status {
+ ACKMB4_INIT = 0,
+ SYSCLKON_OK = 1,
+ DDRON_OK = 2
+};
+
+enum I2C_op {
+ I2CWRITE = 0,
+ I2CREAD = 1
+};
+
+enum ack_mb5_status {
+ ACKMB5_INIT = 0x00,
+ I2C_WR_OK = 0x01,
+ I2C_RD_OK = 0x02,
+ SYSCLK_OK = 0x03,
+ I2C_TIMEOUT = 0x11,
+ SYSCLK_ER = 0x12,
+ /*Error Status resent by PRCM_HWI2C_SR*/
+ I2CWR_NACK_DATA_ER = 0x07,
+ I2CWR_NACK_REG_ADDR_ER = 0x0B,
+ I2CRDWR_NACK_DATA0123_ER = 0x1B,
+ I2CWR_NACK_ADDR_ER = 0x1F,
+ I2CRD_NACK_ADDR_INIT_ER = 0x0F,
+ I2CRD_NACK_REG_ADDR_INIT_ER = 0x13,
+ I2CRD_NACK_ADDR_ER = 0x17
+};
+
+enum ack_mb7_status {
+ MOD_SW_RESET_REQ = 0x03,
+ CA_SLEEP_REQ = 0x02,
+ HOST_PORT_ACK = 0x01,
+ ACKMB7_INIT = 0x00
+};
+
+#endif /* __MACH_PRCMU_FW_DEFS_V1_H */
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-regs.h b/arch/arm/mach-ux500/include/mach/prcmu-regs.h
new file mode 100644
index 00000000000..187a62f1ae6
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/prcmu-regs.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+#ifndef __MACH_PRCMU_REGS_H
+#define __MACH_PRCMU_REGS_H
+
+#include <mach/hardware.h>
+
+#define _PRCMU_BASE __io_address(UX500_PRCMU_BASE)
+
+#define PRCM_ARM_PLLDIVPS (_PRCMU_BASE + 0x118)
+#define PRCM_PLLARM_LOCKP (_PRCMU_BASE + 0x0a8)
+#define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114)
+#define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98)
+#define PRCM_ARMCLKFIX_MGT (_PRCMU_BASE + 0x0)
+#define PRCM_A9_RESETN_CLR (_PRCMU_BASE + 0x1f4)
+#define PRCM_A9_RESETN_SET (_PRCMU_BASE + 0x1f0)
+#define PRCM_ARM_LS_CLAMP (_PRCMU_BASE + 0x30c)
+#define PRCM_SRAM_A9 (_PRCMU_BASE + 0x308)
+
+/* ARM WFI Standby signal register */
+#define PRCM_ARM_WFI_STANDBY (_PRCMU_BASE + 0x130)
+#define PRCM_IOCR (_PRCMU_BASE + 0x310)
+
+/* CPU mailbox registers */
+#define PRCM_MBOX_CPU_VAL (_PRCMU_BASE + 0x0fc)
+#define PRCM_MBOX_CPU_SET (_PRCMU_BASE + 0x100)
+#define PRCM_MBOX_CPU_CLR (_PRCMU_BASE + 0x104)
+
+/* Dual A9 core interrupt management unit registers */
+#define PRCM_A9_MASK_REQ (_PRCMU_BASE + 0x328)
+#define PRCM_A9_MASK_ACK (_PRCMU_BASE + 0x32c)
+#define PRCM_ARMITMSK31TO0 (_PRCMU_BASE + 0x11c)
+#define PRCM_ARMITMSK63TO32 (_PRCMU_BASE + 0x120)
+#define PRCM_ARMITMSK95TO64 (_PRCMU_BASE + 0x124)
+#define PRCM_ARMITMSK127TO96 (_PRCMU_BASE + 0x128)
+#define PRCM_POWER_STATE_VAL (_PRCMU_BASE + 0x25C)
+#define PRCM_ARMITVAL31TO0 (_PRCMU_BASE + 0x260)
+#define PRCM_ARMITVAL63TO32 (_PRCMU_BASE + 0x264)
+#define PRCM_ARMITVAL95TO64 (_PRCMU_BASE + 0x268)
+#define PRCM_ARMITVAL127TO96 (_PRCMU_BASE + 0x26C)
+
+#define PRCM_HOSTACCESS_REQ (_PRCMU_BASE + 0x334)
+#define ARM_WAKEUP_MODEM 0x1
+
+#define PRCM_ARM_IT1_CLEAR (_PRCMU_BASE + 0x48C)
+#define PRCM_ARM_IT1_VAL (_PRCMU_BASE + 0x494)
+#define PRCM_HOLD_EVT (_PRCMU_BASE + 0x174)
+
+#define PRCM_ITSTATUS0 (_PRCMU_BASE + 0x148)
+#define PRCM_ITSTATUS1 (_PRCMU_BASE + 0x150)
+#define PRCM_ITSTATUS2 (_PRCMU_BASE + 0x158)
+#define PRCM_ITSTATUS3 (_PRCMU_BASE + 0x160)
+#define PRCM_ITSTATUS4 (_PRCMU_BASE + 0x168)
+#define PRCM_ITSTATUS5 (_PRCMU_BASE + 0x484)
+#define PRCM_ITCLEAR5 (_PRCMU_BASE + 0x488)
+#define PRCM_ARMIT_MASKXP70_IT (_PRCMU_BASE + 0x1018)
+
+/* System reset register */
+#define PRCM_APE_SOFTRST (_PRCMU_BASE + 0x228)
+
+/* PRCM Timer 5 */
+#define PRCM_TIMER_5_REF (_PRCMU_BASE + 0x45C)
+#define PRCM_TIMER_5_DOWNCOUNT (_PRCMU_BASE + 0x460)
+#define PRCM_TIMER_5_MODE (_PRCMU_BASE + 0x464)
+
+/* Level shifter and clamp control registers */
+#define PRCM_MMIP_LS_CLAMP_SET (_PRCMU_BASE + 0x420)
+#define PRCM_MMIP_LS_CLAMP_CLR (_PRCMU_BASE + 0x424)
+
+/* PRCMU clock/PLL/reset registers */
+#define PRCM_PLLDSI_FREQ (_PRCMU_BASE + 0x500)
+#define PRCM_PLLDSI_ENABLE (_PRCMU_BASE + 0x504)
+#define PRCM_LCDCLK_MGT (_PRCMU_BASE + 0x044)
+#define PRCM_MCDECLK_MGT (_PRCMU_BASE + 0x064)
+#define PRCM_HDMICLK_MGT (_PRCMU_BASE + 0x058)
+#define PRCM_TVCLK_MGT (_PRCMU_BASE + 0x07c)
+#define PRCM_DSI_PLLOUT_SEL (_PRCMU_BASE + 0x530)
+#define PRCM_DSITVCLK_DIV (_PRCMU_BASE + 0x52C)
+#define PRCM_APE_RESETN_SET (_PRCMU_BASE + 0x1E4)
+#define PRCM_APE_RESETN_CLR (_PRCMU_BASE + 0x1E8)
+
+/* ePOD and memory power signal control registers */
+#define PRCM_EPOD_C_SET (_PRCMU_BASE + 0x410)
+#define PRCM_SRAM_LS_SLEEP (_PRCMU_BASE + 0x304)
+
+/* Debug power control unit registers */
+#define PRCM_POWER_STATE_SET (_PRCMU_BASE + 0x254)
+
+/* Miscellaneous unit registers */
+#define PRCM_DSI_SW_RESET (_PRCMU_BASE + 0x324)
+
+#endif /* __MACH_PRCMU__REGS_H */
diff --git a/arch/arm/mach-ux500/include/mach/scu.h b/arch/arm/mach-ux500/include/mach/scu.h
new file mode 100644
index 00000000000..a09e86a9d3c
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/scu.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __ASMARM_ARCH_SCU_H
+#define __ASMARM_ARCH_SCU_H
+
+#include <mach/hardware.h>
+
+#define SCU_BASE U8500_SCU_BASE
+/*
+ * * SCU registers
+ * */
+#define SCU_CTRL 0x00
+#define SCU_CONFIG 0x04
+#define SCU_CPU_STATUS 0x08
+#define SCU_INVALIDATE 0x0c
+#define SCU_FPGA_REVISION 0x10
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/sensors1p.h b/arch/arm/mach-ux500/include/mach/sensors1p.h
new file mode 100644
index 00000000000..544e1d8bab5
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/sensors1p.h
@@ -0,0 +1,24 @@
+
+/*
+ * Copyright (C) 2009-2010 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Header file for 1 pin gpio sensors;
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ *
+ */
+
+#ifndef __ASM_ARCH_SFH7741_H
+#define __ASM_ARCH_SFH7741_H
+
+struct sensor_config {
+ int pin;
+ int startup_time; /* in ms */
+ char regulator[32];
+};
+
+struct sensors1p_config {
+ struct sensor_config hal;
+ struct sensor_config proximity;
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h
index e978dbd9e21..687a74f1fb2 100644
--- a/arch/arm/mach-ux500/include/mach/setup.h
+++ b/arch/arm/mach-ux500/include/mach/setup.h
@@ -23,13 +23,16 @@ extern void __init u5500_init_devices(void);
extern void __init u8500_init_devices(void);
extern void __init ux500_init_irq(void);
-/* We re-use nomadik_timer for this platform */
-extern void nmdk_timer_init(void);
extern void __init amba_add_devices(struct amba_device *devs[], int num);
struct sys_timer;
-extern struct sys_timer ux500_timer;
+extern struct sys_timer u8500_timer;
+extern void __init db8500_prcm_timer_init(void);
+extern void __init db5500_dma_init(void);
+extern void __init db8500_dma_init(void);
+
+extern void __init u8500v2_msp_fixup(void);
#define __IO_DEV_DESC(x, sz) { \
.virtual = IO_ADDRESS(x), \
@@ -38,4 +41,11 @@ extern struct sys_timer ux500_timer;
.type = MT_DEVICE, \
}
+#define __MEM_DEV_DESC(x, sz) { \
+ .virtual = IO_ADDRESS(x), \
+ .pfn = __phys_to_pfn(x), \
+ .length = sz, \
+ .type = MT_MEMORY, \
+}
+
#endif /* __ASM_ARCH_SETUP_H */
diff --git a/arch/arm/mach-ux500/include/mach/shrm.h b/arch/arm/mach-ux500/include/mach/shrm.h
new file mode 100644
index 00000000000..6deeeb16ba8
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/shrm.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson
+ * Author: Kumar Sanghavi <kumar.sanghvi@stericsson.com> for ST-Ericsson
+ * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHM_DRIVER_IF_H__
+#define __SHM_DRIVER_IF_H__
+
+#include <linux/device.h>
+
+/* forward declaration */
+struct shrm_dev;
+
+typedef void (*rx_cb)(void *data, unsigned int length);
+typedef void (*received_msg_handler)(unsigned char l2_header,
+ void *msg_ptr, unsigned int length,
+ struct shrm_dev *shrm);
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/shrm_config.h b/arch/arm/mach-ux500/include/mach/shrm_config.h
new file mode 100644
index 00000000000..a82b35ef77b
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/shrm_config.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson
+ * Author: Kumar Sanghavi <kumar.sanghvi@stericsson.com> for ST-Ericsson
+ * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHRM_CONFIG_H
+#define __SHRM_CONFIG_H
+
+
+/*
+Note: modem need to define IPC as a non-cacheable area.
+In Cortex R4 MPU requires that base address of NC area is aligned on a
+region-sized boundary.On modem side, only 1 NC area can be defined, hence
+the whole IPC area must be defined as NC (at least).
+
+*/
+
+/* cache line size = 32bytes*/
+#define SHM_CACHE_LINE 32
+#define SHM_PTR_SIZE 4
+
+/* FIFO 0 address configuration */
+/* ---------------------------- */
+/* 128KB */
+#define SHM_FIFO_0_SIZE (128*1024)
+
+
+/* == APE addresses == */
+#ifdef CONFIG_SHRM_V1_UPDATES_VERSION
+#define SHM_IPC_BASE_AMCU 0x06F80000
+#else
+#define SHM_IPC_BASE_AMCU 0x06000000
+#endif
+
+/* offset pointers */
+#define SHM_ACFIFO_0_WRITE_AMCU SHM_IPC_BASE_AMCU
+#define SHM_ACFIFO_0_READ_AMCU (SHM_ACFIFO_0_WRITE_AMCU + SHM_PTR_SIZE)
+#define SHM_CAFIFO_0_WRITE_AMCU (SHM_ACFIFO_0_WRITE_AMCU + SHM_CACHE_LINE)
+#define SHM_CAFIFO_0_READ_AMCU (SHM_CAFIFO_0_WRITE_AMCU + SHM_PTR_SIZE)
+/* FIFO start */
+#define SHM_ACFIFO_0_START_AMCU (SHM_CAFIFO_0_WRITE_AMCU + SHM_CACHE_LINE)
+#define SHM_CAFIFO_0_START_AMCU (SHM_ACFIFO_0_START_AMCU + SHM_FIFO_0_SIZE)
+
+
+/* == CMT addresses ==*/
+#define SHM_IPC_BASE_CMCU (SHM_IPC_BASE_AMCU+0x08000000)
+/* offset pointers */
+#define SHM_ACFIFO_0_WRITE_CMCU SHM_IPC_BASE_CMCU
+#define SHM_ACFIFO_0_READ_CMCU (SHM_ACFIFO_0_WRITE_CMCU + SHM_PTR_SIZE)
+#define SHM_CAFIFO_0_WRITE_CMCU (SHM_ACFIFO_0_WRITE_CMCU + SHM_CACHE_LINE)
+#define SHM_CAFIFO_0_READ_CMCU (SHM_CAFIFO_0_WRITE_CMCU + SHM_PTR_SIZE)
+/* FIFO*/
+#define SHM_ACFIFO_0_START_CMCU (SHM_CAFIFO_0_WRITE_CMCU + SHM_CACHE_LINE)
+#define SHM_CAFIFO_0_START_CMCU (SHM_ACFIFO_0_START_CMCU + SHM_FIFO_0_SIZE)
+
+
+/* ADSP addresses*/
+#define SHM_ACFIFO_0_START_ADSP 0x0
+#define SHM_CAFIFO_0_START_ADSP 0x0
+#define SHM_ACFIFO_0_WRITE_ADSP 0x0
+#define SHM_ACFIFO_0_READ_ADSP 0x0
+#define SHM_CAFIFO_0_WRITE_ADSP 0x0
+#define SHM_CAFIFO_0_READ_ADSP 0x0
+
+/* FIFO 1 address configuration */
+/* ---------------------------- */
+
+
+/* FIFO 1 - 4K */
+#define SHM_FIFO_1_SIZE (4*1024)
+
+
+/* == APE addresses == */
+#define SHM_ACFIFO_1_WRITE_AMCU (SHM_CAFIFO_0_START_AMCU + SHM_FIFO_0_SIZE)
+#define SHM_ACFIFO_1_READ_AMCU (SHM_ACFIFO_1_WRITE_AMCU + SHM_PTR_SIZE)
+#define SHM_CAFIFO_1_WRITE_AMCU (SHM_ACFIFO_1_WRITE_AMCU + SHM_CACHE_LINE)
+#define SHM_CAFIFO_1_READ_AMCU (SHM_CAFIFO_1_WRITE_AMCU + SHM_PTR_SIZE)
+/* FIFO*/
+#define SHM_ACFIFO_1_START_AMCU (SHM_CAFIFO_1_WRITE_AMCU + SHM_CACHE_LINE)
+#define SHM_CAFIFO_1_START_AMCU (SHM_ACFIFO_1_START_AMCU + SHM_FIFO_1_SIZE)
+
+
+/* == CMT addresses ==*/
+#define SHM_ACFIFO_1_WRITE_CMCU (SHM_CAFIFO_0_START_CMCU + SHM_FIFO_0_SIZE)
+#define SHM_ACFIFO_1_READ_CMCU (SHM_ACFIFO_1_WRITE_CMCU + SHM_PTR_SIZE)
+#define SHM_CAFIFO_1_WRITE_CMCU (SHM_ACFIFO_1_WRITE_CMCU + SHM_CACHE_LINE)
+#define SHM_CAFIFO_1_READ_CMCU (SHM_CAFIFO_1_WRITE_CMCU + SHM_PTR_SIZE)
+/* FIFO1 start */
+#define SHM_ACFIFO_1_START_CMCU (SHM_CAFIFO_1_WRITE_CMCU + SHM_CACHE_LINE)
+#define SHM_CAFIFO_1_START_CMCU (SHM_ACFIFO_1_START_CMCU + SHM_FIFO_1_SIZE)
+
+
+/* ADSP addresses*/
+#define SHM_ACFIFO_1_START_ADSP 0x0
+#define SHM_CAFIFO_1_START_ADSP 0x0
+#define SHM_ACFIFO_1_WRITE_ADSP 0x0
+#define SHM_ACFIFO_1_READ_ADSP 0x0
+#define SHM_CAFIFO_1_WRITE_ADSP 0x0
+#define SHM_CAFIFO_1_READ_ADSP 0x0
+
+
+#define U8500_SHM_FIFO_APE_COMMON_BASE (SHM_ACFIFO_0_START_AMCU)
+#define U8500_SHM_FIFO_CMT_COMMON_BASE (SHM_CAFIFO_0_START_AMCU)
+#define U8500_SHM_FIFO_APE_AUDIO_BASE (SHM_ACFIFO_1_START_AMCU)
+#define U8500_SHM_FIFO_CMT_AUDIO_BASE (SHM_CAFIFO_1_START_AMCU)
+
+#endif /* __SHRM_CONFIG_H */
diff --git a/arch/arm/mach-ux500/include/mach/shrm_driver.h b/arch/arm/mach-ux500/include/mach/shrm_driver.h
new file mode 100644
index 00000000000..5480a43a076
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/shrm_driver.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson
+ * Author: Kumar Sanghavi <kumar.sanghvi@stericsson.com> for ST-Ericsson
+ * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHRM_DRIVER_H__
+#define __SHRM_DRIVER_H__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+
+#include <mach/shrm.h>
+
+#include <linux/cdev.h>
+
+#define ISA_DEVICES 6
+
+#define BOOT_INIT (0)
+#define BOOT_INFO_SYNC (1)
+#define BOOT_DONE (2)
+#define BOOT_UNKNOWN (3)
+
+/**
+ * struct shrm_dev - shrm device information
+ * @ca_wake_irq: CMT wake interrupt number
+ * @ac_read_notif_0_irq: ape-cmt common channel read notify interrupt
+ * @ac_read_notif_1_irq: ape-cmt audio channel read notify interrupt
+ * @ca_msg_pending_notif_0_irq: cmt-ape common channel msg pending interrupt
+ * @ca_msg_pending_notif_1_irq: cmt-ape audio channel msg pending interrupt
+ * @intr_base: interrupt base register address
+ * @ape_common_fifo_base: ape side common channel fifo base addr
+ * @ape_audio_fifo_base: ape side audio channel fifo base addr
+ * @cmt_common_fifo_base: cmt side common channel fifo base addr
+ * @cmt_audio_fifo_base: cmt side audio channel fifo base addr
+ * @ape_common_fifo_base_phy: physical addr of ape common fifo
+ * @ape_audio_fifo_base_phy: physical addr of ape audio fifo
+ * @cmt_common_fifo_base_phy: physical addr of cmt common fifo
+ * @cmt_audio_fifo_base_phy: physical addr of cmt audio fifo
+ * @ape_common_fifo_size: ape side common channel fifo size
+ * @ape_audio_fifo_size: ape side audio channel fifo size
+ * @cmt_common_fifo_size: cmt side common channel fifo size
+ * @cmt_audio_fifo_size: cmt side audio channel fifo size
+ * @netdev_flag_up: flag to indicate up/down of netwok device
+ * @ac_common_shared_wptr: ape-cmt common channel write pointer
+ * @ac_common_shared_rptr: ape-cmt common channel read pointer
+ * @ca_common_shared_wptr: cmt-ape common channel write pointer
+ * @ca_common_shared_rptr: cmt-ape common channel read pointer
+ * @ac_audio_shared_wptr: ape-cmt audio channel write pointer
+ * @ac_audio_shared_rptr: ape-cmt audio channel read pointer
+ * @ca_audio_shared_wptr: cmt-ape audio channel write pointer
+ * @ca_audio_shared_rptr: cmt-ape audio channel read pointer
+ * @dev: pointer to the driver device
+ * @ndev: pointer to the network device structure
+ * @isa_context: pointer to t_isa_driver_sontext dtructure
+ */
+struct shrm_dev {
+ u8 ca_wake_irq;
+ u8 ac_read_notif_0_irq;
+ u8 ac_read_notif_1_irq;
+ u8 ca_msg_pending_notif_0_irq;
+ u8 ca_msg_pending_notif_1_irq;
+ void __iomem *intr_base;
+ void __iomem *ape_common_fifo_base;
+ void __iomem *ape_audio_fifo_base;
+ void __iomem *cmt_common_fifo_base;
+ void __iomem *cmt_audio_fifo_base;
+
+ u32 *ape_common_fifo_base_phy;
+ u32 *ape_audio_fifo_base_phy;
+ u32 *cmt_common_fifo_base_phy;
+ u32 *cmt_audio_fifo_base_phy;
+
+ int ape_common_fifo_size;
+ int ape_audio_fifo_size;
+ int cmt_common_fifo_size;
+ int cmt_audio_fifo_size;
+ int netdev_flag_up;
+
+ void __iomem *ac_common_shared_wptr;
+ void __iomem *ac_common_shared_rptr;
+ void __iomem *ca_common_shared_wptr;
+ void __iomem *ca_common_shared_rptr;
+
+ void __iomem *ac_audio_shared_wptr;
+ void __iomem *ac_audio_shared_rptr;
+ void __iomem *ca_audio_shared_wptr;
+ void __iomem *ca_audio_shared_rptr;
+
+ struct device *dev;
+ struct net_device *ndev;
+ struct isa_driver_context *isa_context;
+};
+
+/**
+ * struct queue_element - information to add an element to queue
+ * @entry: list entry
+ * @offset: message offset
+ * @size: message size
+ * @no: total number of messages
+ */
+struct queue_element {
+ struct list_head entry;
+ u32 offset;
+ u32 size;
+ u32 no;
+};
+
+/**
+ * struct message_queue - ISI, RPC, AUDIO, SECURITY message queue information
+ * @fifo_base: pointer to the respective fifo base
+ * @size: size of the data to be read
+ * @readptr: fifo read pointer
+ * @writeptr: fifo write pointer
+ * @no: total number of messages
+ * @update_lock: spinlock for protecting the queue read operation
+ * @q_rp: queue write pointer
+ * @wq_readable: wait queue head
+ * @msg_list: message list
+ * @shrm: pointer to shrm device information structure
+ */
+struct message_queue {
+ u8 *fifo_base;
+ u32 size;
+ u32 readptr;
+ u32 writeptr;
+ u32 no;
+ spinlock_t update_lock;
+ atomic_t q_rp;
+ wait_queue_head_t wq_readable;
+ struct list_head msg_list;
+ struct shrm_dev *shrm;
+};
+
+/**
+ * struct isadev_context - shrm char interface context
+ * @dl_queue: structre to store the queue related info
+ * @device_id: message id(ISI, RPC, AUDIO, SECURITY)
+ */
+struct isadev_context {
+ struct message_queue dl_queue;
+ u8 device_id;
+ void *addr;
+};
+
+/**
+ * struct isa_driver_context - shrm char interface device information
+ * @is_open: flag to check the usage of queue
+ * @isadev: pointer to struct t_isadev_context
+ * @common_tx: spinlock for protecting common channel
+ * @tx_audio_mutex: mutex for protecting audio channel
+ * @cdev: character device structre
+ * @shm_class: pointer to the class structure
+ */
+struct isa_driver_context {
+ atomic_t is_open[ISA_DEVICES];
+ struct isadev_context *isadev;
+ spinlock_t common_tx;
+ struct mutex tx_audio_mutex;
+ struct cdev cdev;
+ struct class *shm_class;
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/shrm_net.h b/arch/arm/mach-ux500/include/mach/shrm_net.h
new file mode 100644
index 00000000000..91b889e197f
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/shrm_net.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009
+ *
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHRM_NET_H
+#define __SHRM_NET_H
+
+#define SHRM_HLEN 1
+#define PHONET_ALEN 1
+
+#define PN_PIPE 0xD9
+#define PN_DEV_HOST 0x00
+#define PN_LINK_ADDR 0x26
+#define PN_TX_QUEUE_LEN 3
+
+#define RESOURCE_ID_INDEX 3
+#define SRC_OBJ_INDEX 7
+#define MSG_ID_INDEX 9
+#define PIPE_HDL_INDEX 10
+#define NETLINK_SHRM 17
+
+/**
+ * struct shrm_net_iface_priv - shrm net interface device information
+ * @shrm_device: pointer to the shrm device information structure
+ * @iface_num: flag used to indicate the up/down of netdev
+ */
+struct shrm_net_iface_priv {
+ struct shrm_dev *shrm_device;
+ unsigned int iface_num;
+};
+
+int shrm_register_netdev(struct shrm_dev *shrm_dev_data);
+int shrm_net_receive(struct net_device *dev, unsigned char *data);
+int shrm_suspend_netdev(struct net_device *dev);
+int shrm_resume_netdev(struct net_device *dev);
+int shrm_stop_netdev(struct net_device *dev);
+int shrm_start_netdev(struct net_device *dev);
+void shrm_unregister_netdev(struct shrm_dev *shrm_dev_data);
+
+#endif /* __SHRM_NET_H */
diff --git a/arch/arm/mach-ux500/include/mach/shrm_private.h b/arch/arm/mach-ux500/include/mach/shrm_private.h
new file mode 100644
index 00000000000..0af1c1b9cb3
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/shrm_private.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson
+ * Author: Kumar Sanghavi <kumar.sanghvi@stericsson.com> for ST-Ericsson
+ * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHRM_PRIVATE_INCLUDED
+#define __SHRM_PRIVATE_INCLUDED
+
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <mach/shrm.h>
+
+#define GOP_OUTPUT_REGISTER_BASE (0x0)
+#define GOP_SET_REGISTER_BASE (0x4)
+#define GOP_CLEAR_REGISTER_BASE (0x8)
+#define GOP_TOGGLE_REGISTER_BASE (0xc)
+
+
+#define GOP_AUDIO_AC_READ_NOTIFICATION_BIT (0)
+#define GOP_AUDIO_CA_MSG_PENDING_NOTIFICATION_BIT (1)
+#define GOP_COMMON_AC_READ_NOTIFICATION_BIT (2)
+#define GOP_COMMON_CA_MSG_PENDING_NOTIFICATION_BIT (3)
+#define GOP_CA_WAKE_REQ_BIT (7)
+#define GOP_AUDIO_CA_READ_NOTIFICATION_BIT (23)
+#define GOP_AUDIO_AC_MSG_PENDING_NOTIFICATION_BIT (24)
+#define GOP_COMMON_CA_READ_NOTIFICATION_BIT (25)
+#define GOP_COMMON_AC_MSG_PENDING_NOTIFICATION_BIT (26)
+#define GOP_CA_WAKE_ACK_BIT (27)
+
+#define L2_MSG_MAPID_OFFSET (24)
+#define L1_MSG_MAPID_OFFSET (28)
+
+#define SHRM_SLEEP_STATE (0)
+#define SHRM_PTR_FREE (1)
+#define SHRM_PTR_BUSY (2)
+#define SHRM_IDLE (3)
+
+#define ISI_MESSAGING (0)
+#define RPC_MESSAGING (1)
+#define AUDIO_MESSAGING (2)
+#define SECURITY_MESSAGING (3)
+#define COMMON_LOOPBACK_MESSAGING (0xC0)
+#define AUDIO_LOOPBACK_MESSAGING (0x80)
+
+#define COMMON_CHANNEL 0
+#define AUDIO_CHANNEL 1
+
+typedef void (*MSG_PENDING_NOTIF)(const u32 Wptr);
+
+/**
+ * struct fifo_write_params - parameters used for FIFO write operation.
+ * @writer_local_rptr: pointer to local read buffer
+ * @writer_local_wptr: pointer to local write buffer
+ * @shared_wptr: write pointer shared by cmt and ape
+ * @shared_rptr: read pointer shared by cmt and ape
+ * @availablesize: available memory in fifo
+ * @end_addr_fifo: fifo end addr
+ * @fifo_virtual_addr: fifo virtual addr
+ *
+ * On writting a message to FIFO the same has to be read by the modem before
+ * writing the next message to the FIFO. In oder to over come this a local
+ * write and read pointer is used for internal purpose.
+ */
+struct fifo_write_params {
+ u32 writer_local_rptr;
+ u32 writer_local_wptr;
+ u32 shared_wptr;
+ u32 shared_rptr;
+ u32 availablesize;
+ u32 end_addr_fifo;
+ u32 *fifo_virtual_addr;
+
+} ;
+
+/**
+ * struct fifo_read_params - parameters used for FIFO read operation
+ * @reader_local_rptr: pointer to local read buffer
+ * @reader_local_wptr: pointer to local write buffer
+ * @shared_wptr: write pointer shared by cmt and ape
+ * @shared_rptr: read pointer shared by cmt and ape
+ * @availablesize: available memory in fifo
+ * @end_addr_fifo: fifo end add
+ * @fifo_virtual_addr: fifo virtual addr
+ */
+struct fifo_read_params{
+ u32 reader_local_rptr;
+ u32 reader_local_wptr;
+ u32 shared_wptr;
+ u32 shared_rptr;
+ u32 availablesize;
+ u32 end_addr_fifo;
+ u32 *fifo_virtual_addr;
+
+} ;
+
+int shrm_protocol_init(struct shrm_dev *shrm,
+ received_msg_handler common_rx_handler,
+ received_msg_handler audio_rx_handler);
+void shm_fifo_init(struct shrm_dev *shrm);
+int shm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
+ u8 l2header, void *addr, u32 length);
+int shm_write_msg(struct shrm_dev *shrm,
+ u8 l2_header, void *addr, u32 length);
+
+u8 is_the_only_one_unread_message(struct shrm_dev *shrm,
+ u8 channel, u32 length);
+u8 read_remaining_messages_common(void);
+u8 read_remaining_messages_audio(void);
+u8 read_one_l2msg_audio(struct shrm_dev *shrm,
+ u8 *p_l2_msg, u32 *p_len);
+u8 read_one_l2msg_common(struct shrm_dev *shrm,
+ u8 *p_l2_msg, u32 *p_len);
+void receive_messages_common(struct shrm_dev *shrm);
+void receive_messages_audio(struct shrm_dev *shrm);
+
+void update_ac_common_writer_local_rptr_with_shared_rptr(
+ struct shrm_dev *shrm);
+void update_ac_audio_writer_local_rptr_with_shared_rptr(
+ struct shrm_dev *shrm);
+void update_ca_common_reader_local_wptr_with_shared_wptr(
+ struct shrm_dev *shrm);
+void update_ca_audio_reader_local_wptr_with_shared_wptr(
+ struct shrm_dev *shrm);
+void update_ac_common_shared_wptr_with_writer_local_wptr(
+ struct shrm_dev *shrm);
+void update_ac_audio_shared_wptr_with_writer_local_wptr(
+ struct shrm_dev *shrm);
+void update_ca_common_shared_rptr_with_reader_local_rptr(
+ struct shrm_dev *shrm);
+void update_ca_audio_shared_rptr_with_reader_local_rptr(
+ struct shrm_dev *shrm);
+
+
+void get_writer_pointers(u8 msg_type, u32 *WriterLocalRptr, \
+ u32 *WriterLocalWptr, u32 *SharedWptr);
+void get_reader_pointers(u8 msg_type, u32 *ReaderLocalRptr, \
+ u32 *ReaderLocalWptr, u32 *SharedRptr);
+u8 read_boot_info_req(struct shrm_dev *shrm,
+ u32 *pConfig,
+ u32 *pVersion);
+void write_boot_info_resp(struct shrm_dev *shrm, u32 Config,
+ u32 Version);
+
+void send_ac_msg_pending_notification_0(struct shrm_dev *shrm);
+void send_ac_msg_pending_notification_1(struct shrm_dev *shrm);
+void ca_msg_read_notification_0(struct shrm_dev *shrm);
+void ca_msg_read_notification_1(struct shrm_dev *shrm);
+
+void set_ca_msg_0_read_notif_send(u8 val);
+u8 get_ca_msg_0_read_notif_send(void);
+void set_ca_msg_1_read_notif_send(u8 val);
+u8 get_ca_msg_1_read_notif_send(void);
+
+irqreturn_t ca_wake_irq_handler(int irq, void *ctrlr);
+irqreturn_t ac_read_notif_0_irq_handler(int irq, void *ctrlr);
+irqreturn_t ac_read_notif_1_irq_handler(int irq, void *ctrlr);
+irqreturn_t ca_msg_pending_notif_0_irq_handler(int irq, void *ctrlr);
+irqreturn_t ca_msg_pending_notif_1_irq_handler(int irq, void *ctrlr);
+
+void shm_ca_msgpending_0_tasklet(unsigned long);
+void shm_ca_msgpending_1_tasklet(unsigned long);
+void shm_ac_read_notif_0_tasklet(unsigned long);
+void shm_ac_read_notif_1_tasklet(unsigned long);
+void shm_ca_wake_req_tasklet(unsigned long);
+
+u8 get_boot_state(void);
+
+int get_ca_wake_req_state(void);
+
+/* shrm character interface */
+int isa_init(struct shrm_dev *shrm);
+void isa_exit(struct shrm_dev *shrm);
+int add_msg_to_queue(struct message_queue *q, u32 size);
+ssize_t isa_read(struct file *filp, char __user *buf, size_t len,
+ loff_t *ppos);
+int get_size_of_new_msg(struct message_queue *q);
+int remove_msg_from_queue(struct message_queue *q);
+void shrm_char_reset_queues(struct shrm_dev *shrm);
+int shrm_get_cdev_index(u8 l2_header);
+int shrm_get_cdev_l2header(u8 idx);
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/ste-dma40-db5500.h b/arch/arm/mach-ux500/include/mach/ste-dma40-db5500.h
new file mode 100644
index 00000000000..cb2110c3285
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/ste-dma40-db5500.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * DB5500-SoC-specific configuration for DMA40
+ */
+
+#ifndef STE_DMA40_DB5500_H
+#define STE_DMA40_DB5500_H
+
+#define DB5500_DMA_NR_DEV 64
+
+enum dma_src_dev_type {
+ DB5500_DMA_DEV0_SPI0_RX = 0,
+ DB5500_DMA_DEV1_SPI1_RX = 1,
+ DB5500_DMA_DEV2_SPI2_RX = 2,
+ DB5500_DMA_DEV3_SPI3_RX = 3,
+ DB5500_DMA_DEV4_USB_OTG_IEP_1_9 = 4,
+ DB5500_DMA_DEV5_USB_OTG_IEP_2_10 = 5,
+ DB5500_DMA_DEV6_USB_OTG_IEP_3_11 = 6,
+ DB5500_DMA_DEV7_IRDA_RFS = 7,
+ DB5500_DMA_DEV8_IRDA_FIFO_RX = 8,
+ DB5500_DMA_DEV9_MSP0_RX = 9,
+ DB5500_DMA_DEV10_MSP1_RX = 10,
+ DB5500_DMA_DEV11_MSP2_RX = 11,
+ DB5500_DMA_DEV12_UART0_RX = 12,
+ DB5500_DMA_DEV13_UART1_RX = 13,
+ DB5500_DMA_DEV14_UART2_RX = 14,
+ DB5500_DMA_DEV15_UART3_RX = 15,
+ DB5500_DMA_DEV16_USB_OTG_IEP_8 = 16,
+ DB5500_DMA_DEV17_USB_OTG_IEP_1_9 = 17,
+ DB5500_DMA_DEV18_USB_OTG_IEP_2_10 = 18,
+ DB5500_DMA_DEV19_USB_OTG_IEP_3_11 = 19,
+ DB5500_DMA_DEV20_USB_OTG_IEP_4_12 = 20,
+ DB5500_DMA_DEV21_USB_OTG_IEP_5_13 = 21,
+ DB5500_DMA_DEV22_USB_OTG_IEP_6_14 = 22,
+ DB5500_DMA_DEV23_USB_OTG_IEP_7_15 = 23,
+ DB5500_DMA_DEV24_SDMMC0_RX = 24,
+ DB5500_DMA_DEV25_SDMMC1_RX = 25,
+ DB5500_DMA_DEV26_SDMMC2_RX = 26,
+ DB5500_DMA_DEV27_SDMMC3_RX = 27,
+ DB5500_DMA_DEV28_SDMMC4_RX = 28,
+ /* 29 - 32 not used */
+ DB5500_DMA_DEV33_SDMMC0_RX = 33,
+ DB5500_DMA_DEV34_SDMMC1_RX = 34,
+ DB5500_DMA_DEV35_SDMMC2_RX = 35,
+ DB5500_DMA_DEV36_SDMMC3_RX = 36,
+ DB5500_DMA_DEV37_SDMMC4_RX = 37,
+ DB5500_DMA_DEV38_USB_OTG_IEP_8 = 38,
+ DB5500_DMA_DEV39_USB_OTG_IEP_1_9 = 39,
+ DB5500_DMA_DEV40_USB_OTG_IEP_2_10 = 40,
+ DB5500_DMA_DEV41_USB_OTG_IEP_3_11 = 41,
+ DB5500_DMA_DEV42_USB_OTG_IEP_4_12 = 42,
+ DB5500_DMA_DEV43_USB_OTG_IEP_5_13 = 43,
+ DB5500_DMA_DEV44_USB_OTG_IEP_6_14 = 44,
+ DB5500_DMA_DEV45_USB_OTG_IEP_7_15 = 45,
+ /* 46 not used */
+ DB5500_DMA_DEV47_MCDE_RX = 47,
+ DB5500_DMA_DEV48_CRYPTO1_RX = 48,
+ /* 49, 50 not used */
+ DB5500_DMA_DEV49_I2C1_RX = 51,
+ DB5500_DMA_DEV50_I2C3_RX = 52,
+ DB5500_DMA_DEV51_I2C2_RX = 53,
+ /* 54 - 60 not used */
+ DB5500_DMA_DEV61_CRYPTO0_RX = 61,
+ /* 62, 63 not used */
+};
+
+enum dma_dest_dev_type {
+ DB5500_DMA_DEV0_SPI0_TX = 0,
+ DB5500_DMA_DEV1_SPI1_TX = 1,
+ DB5500_DMA_DEV2_SPI2_TX = 2,
+ DB5500_DMA_DEV3_SPI3_TX = 3,
+ DB5500_DMA_DEV4_USB_OTG_OEP_1_9 = 4,
+ DB5500_DMA_DEV5_USB_OTG_OEP_2_10 = 5,
+ DB5500_DMA_DEV6_USB_OTG_OEP_3_11 = 6,
+ DB5500_DMA_DEV7_IRRC_TX = 7,
+ DB5500_DMA_DEV8_IRDA_FIFO_TX = 8,
+ DB5500_DMA_DEV9_MSP0_TX = 9,
+ DB5500_DMA_DEV10_MSP1_TX = 10,
+ DB5500_DMA_DEV11_MSP2_TX = 11,
+ DB5500_DMA_DEV12_UART0_TX = 12,
+ DB5500_DMA_DEV13_UART1_TX = 13,
+ DB5500_DMA_DEV14_UART2_TX = 14,
+ DB5500_DMA_DEV15_UART3_TX = 15,
+ DB5500_DMA_DEV16_USB_OTG_OEP_8 = 16,
+ DB5500_DMA_DEV17_USB_OTG_OEP_1_9 = 17,
+ DB5500_DMA_DEV18_USB_OTG_OEP_2_10 = 18,
+ DB5500_DMA_DEV19_USB_OTG_OEP_3_11 = 19,
+ DB5500_DMA_DEV20_USB_OTG_OEP_4_12 = 20,
+ DB5500_DMA_DEV21_USB_OTG_OEP_5_13 = 21,
+ DB5500_DMA_DEV22_USB_OTG_OEP_6_14 = 22,
+ DB5500_DMA_DEV23_USB_OTG_OEP_7_15 = 23,
+ DB5500_DMA_DEV24_SDMMC0_TX = 24,
+ DB5500_DMA_DEV25_SDMMC1_TX = 25,
+ DB5500_DMA_DEV26_SDMMC2_TX = 26,
+ DB5500_DMA_DEV27_SDMMC3_TX = 27,
+ DB5500_DMA_DEV28_SDMMC4_TX = 28,
+ /* 29 - 31 not used */
+ DB5500_DMA_DEV32_FSMC_TX = 32,
+ DB5500_DMA_DEV33_SDMMC0_TX = 33,
+ DB5500_DMA_DEV34_SDMMC1_TX = 34,
+ DB5500_DMA_DEV35_SDMMC2_TX = 35,
+ DB5500_DMA_DEV36_SDMMC3_TX = 36,
+ DB5500_DMA_DEV37_SDMMC4_TX = 37,
+ DB5500_DMA_DEV38_USB_OTG_OEP_8 = 38,
+ DB5500_DMA_DEV39_USB_OTG_OEP_1_9 = 39,
+ DB5500_DMA_DEV40_USB_OTG_OEP_2_10 = 40,
+ DB5500_DMA_DEV41_USB_OTG_OEP_3_11 = 41,
+ DB5500_DMA_DEV42_USB_OTG_OEP_4_12 = 42,
+ DB5500_DMA_DEV43_USB_OTG_OEP_5_13 = 43,
+ DB5500_DMA_DEV44_USB_OTG_OEP_6_14 = 44,
+ DB5500_DMA_DEV45_USB_OTG_OEP_7_15 = 45,
+ /* 46 not used */
+ DB5500_DMA_DEV47_STM_TX = 47,
+ DB5500_DMA_DEV48_CRYPTO1_TX = 48,
+ DB5500_DMA_DEV49_CRYPTO1_TX_HASH1_TX = 49,
+ DB5500_DMA_DEV50_HASH1_TX = 50,
+ DB5500_DMA_DEV51_I2C1_TX = 51,
+ DB5500_DMA_DEV52_I2C3_TX = 52,
+ DB5500_DMA_DEV53_I2C2_TX = 53,
+ /* 54, 55 not used */
+ DB5500_DMA_MEMCPY_TX_1 = 56,
+ DB5500_DMA_MEMCPY_TX_2 = 57,
+ DB5500_DMA_MEMCPY_TX_3 = 58,
+ DB5500_DMA_MEMCPY_TX_4 = 59,
+ DB5500_DMA_MEMCPY_TX_5 = 60,
+ DB5500_DMA_DEV61_CRYPTO0_TX = 61,
+ DB5500_DMA_DEV62_CRYPTO0_TX_HASH0_TX = 62,
+ DB5500_DMA_DEV63_HASH0_TX = 63,
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/ste-dma40-db8500.h b/arch/arm/mach-ux500/include/mach/ste-dma40-db8500.h
new file mode 100644
index 00000000000..64c494f0836
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/ste-dma40-db8500.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * DB8500-SoC-specific configuration for DMA40
+ */
+#ifndef STE_DMA40_DB8500_H
+#define STE_DMA40_DB8500_H
+
+#define DB8500_DMA_NR_DEV 64
+/*
+ * All entries with double names are multiplexed
+ * and can never be used at the same time.
+ */
+
+enum dma_src_dev_type {
+ DB8500_DMA_DEV0_SPI0_RX = 0,
+ DB8500_DMA_DEV1_SD_MMC0_RX = 1,
+ DB8500_DMA_DEV2_SD_MMC1_RX = 2,
+ DB8500_DMA_DEV3_SD_MMC2_RX = 3,
+ DB8500_DMA_DEV4_I2C1_RX = 4,
+ DB8500_DMA_DEV5_I2C3_RX = 5,
+ DB8500_DMA_DEV6_I2C2_RX = 6,
+ DB8500_DMA_DEV7_I2C4_RX = 7, /* Only on V1 and later */
+ DB8500_DMA_DEV8_SSP0_RX = 8,
+ DB8500_DMA_DEV9_SSP1_RX = 9,
+ DB8500_DMA_DEV10_MCDE_RX = 10,
+ DB8500_DMA_DEV11_UART2_RX = 11,
+ DB8500_DMA_DEV12_UART1_RX = 12,
+ DB8500_DMA_DEV13_UART0_RX = 13,
+ DB8500_DMA_DEV14_MSP2_RX = 14,
+ DB8500_DMA_DEV15_I2C0_RX = 15,
+ DB8500_DMA_DEV16_USB_OTG_IEP_7_15 = 16,
+ DB8500_DMA_DEV17_USB_OTG_IEP_6_14 = 17,
+ DB8500_DMA_DEV18_USB_OTG_IEP_5_13 = 18,
+ DB8500_DMA_DEV19_USB_OTG_IEP_4_12 = 19,
+ DB8500_DMA_DEV20_SLIM0_CH0_RX_HSI_RX_CH0 = 20,
+ DB8500_DMA_DEV21_SLIM0_CH1_RX_HSI_RX_CH1 = 21,
+ DB8500_DMA_DEV22_SLIM0_CH2_RX_HSI_RX_CH2 = 22,
+ DB8500_DMA_DEV23_SLIM0_CH3_RX_HSI_RX_CH3 = 23,
+ DB8500_DMA_DEV24_SRC_SXA0_RX_TX = 24,
+ DB8500_DMA_DEV25_SRC_SXA1_RX_TX = 25,
+ DB8500_DMA_DEV26_SRC_SXA2_RX_TX = 26,
+ DB8500_DMA_DEV27_SRC_SXA3_RX_TX = 27,
+ DB8500_DMA_DEV28_SD_MM2_RX = 28,
+ DB8500_DMA_DEV29_SD_MM0_RX = 29,
+ DB8500_DMA_DEV30_MSP1_RX = 30,
+ /* On DB8500v2, MSP3 RX replaces MSP1 RX */
+ DB8500_DMA_DEV30_MSP3_RX = 30,
+ DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX = 31,
+ DB8500_DMA_DEV32_SD_MM1_RX = 32,
+ DB8500_DMA_DEV33_SPI2_RX = 33,
+ DB8500_DMA_DEV34_I2C3_RX2 = 34,
+ DB8500_DMA_DEV35_SPI1_RX = 35,
+ DB8500_DMA_DEV36_USB_OTG_IEP_3_11 = 36,
+ DB8500_DMA_DEV37_USB_OTG_IEP_2_10 = 37,
+ DB8500_DMA_DEV38_USB_OTG_IEP_1_9 = 38,
+ DB8500_DMA_DEV39_USB_OTG_IEP_8 = 39,
+ DB8500_DMA_DEV40_SPI3_RX = 40,
+ DB8500_DMA_DEV41_SD_MM3_RX = 41,
+ DB8500_DMA_DEV42_SD_MM4_RX = 42,
+ DB8500_DMA_DEV43_SD_MM5_RX = 43,
+ DB8500_DMA_DEV44_SRC_SXA4_RX_TX = 44,
+ DB8500_DMA_DEV45_SRC_SXA5_RX_TX = 45,
+ DB8500_DMA_DEV46_SLIM0_CH8_RX_SRC_SXA6_RX_TX = 46,
+ DB8500_DMA_DEV47_SLIM0_CH9_RX_SRC_SXA7_RX_TX = 47,
+ DB8500_DMA_DEV48_CAC1_RX = 48,
+ /* 49, 50 and 51 are not used */
+ DB8500_DMA_DEV52_SLIM0_CH4_RX_HSI_RX_CH4 = 52,
+ DB8500_DMA_DEV53_SLIM0_CH5_RX_HSI_RX_CH5 = 53,
+ DB8500_DMA_DEV54_SLIM0_CH6_RX_HSI_RX_CH6 = 54,
+ DB8500_DMA_DEV55_SLIM0_CH7_RX_HSI_RX_CH7 = 55,
+ /* 56, 57, 58, 59 and 60 are not used */
+ DB8500_DMA_DEV61_CAC0_RX = 61,
+ /* 62 and 63 are not used */
+};
+
+enum dma_dest_dev_type {
+ DB8500_DMA_DEV0_SPI0_TX = 0,
+ DB8500_DMA_DEV1_SD_MMC0_TX = 1,
+ DB8500_DMA_DEV2_SD_MMC1_TX = 2,
+ DB8500_DMA_DEV3_SD_MMC2_TX = 3,
+ DB8500_DMA_DEV4_I2C1_TX = 4,
+ DB8500_DMA_DEV5_I2C3_TX = 5,
+ DB8500_DMA_DEV6_I2C2_TX = 6,
+ DB8500_DMA_DEV7_I2C4_TX = 7, /* Only on V1 and later */
+ DB8500_DMA_DEV8_SSP0_TX = 8,
+ DB8500_DMA_DEV9_SSP1_TX = 9,
+ /* 10 is not used*/
+ DB8500_DMA_DEV11_UART2_TX = 11,
+ DB8500_DMA_DEV12_UART1_TX = 12,
+ DB8500_DMA_DEV13_UART0_TX = 13,
+ DB8500_DMA_DEV14_MSP2_TX = 14,
+ DB8500_DMA_DEV15_I2C0_TX = 15,
+ DB8500_DMA_DEV16_USB_OTG_OEP_7_15 = 16,
+ DB8500_DMA_DEV17_USB_OTG_OEP_6_14 = 17,
+ DB8500_DMA_DEV18_USB_OTG_OEP_5_13 = 18,
+ DB8500_DMA_DEV19_USB_OTG_OEP_4_12 = 19,
+ DB8500_DMA_DEV20_SLIM0_CH0_TX_HSI_TX_CH0 = 20,
+ DB8500_DMA_DEV21_SLIM0_CH1_TX_HSI_TX_CH1 = 21,
+ DB8500_DMA_DEV22_SLIM0_CH2_TX_HSI_TX_CH2 = 22,
+ DB8500_DMA_DEV23_SLIM0_CH3_TX_HSI_TX_CH3 = 23,
+ DB8500_DMA_DEV24_DST_SXA0_RX_TX = 24,
+ DB8500_DMA_DEV25_DST_SXA1_RX_TX = 25,
+ DB8500_DMA_DEV26_DST_SXA2_RX_TX = 26,
+ DB8500_DMA_DEV27_DST_SXA3_RX_TX = 27,
+ DB8500_DMA_DEV28_SD_MM2_TX = 28,
+ DB8500_DMA_DEV29_SD_MM0_TX = 29,
+ DB8500_DMA_DEV30_MSP1_TX = 30,
+ DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX = 31,
+ DB8500_DMA_DEV32_SD_MM1_TX = 32,
+ DB8500_DMA_DEV33_SPI2_TX = 33,
+ DB8500_DMA_DEV34_I2C3_TX2 = 34,
+ DB8500_DMA_DEV35_SPI1_TX = 35,
+ DB8500_DMA_DEV36_USB_OTG_OEP_3_11 = 36,
+ DB8500_DMA_DEV37_USB_OTG_OEP_2_10 = 37,
+ DB8500_DMA_DEV38_USB_OTG_OEP_1_9 = 38,
+ DB8500_DMA_DEV39_USB_OTG_OEP_8 = 39,
+ DB8500_DMA_DEV40_SPI3_TX = 40,
+ DB8500_DMA_DEV41_SD_MM3_TX = 41,
+ DB8500_DMA_DEV42_SD_MM4_TX = 42,
+ DB8500_DMA_DEV43_SD_MM5_TX = 43,
+ DB8500_DMA_DEV44_DST_SXA4_RX_TX = 44,
+ DB8500_DMA_DEV45_DST_SXA5_RX_TX = 45,
+ DB8500_DMA_DEV46_SLIM0_CH8_TX_DST_SXA6_RX_TX = 46,
+ DB8500_DMA_DEV47_SLIM0_CH9_TX_DST_SXA7_RX_TX = 47,
+ DB8500_DMA_DEV48_CAC1_TX = 48,
+ DB8500_DMA_DEV49_CAC1_TX_HAC1_TX = 49,
+ DB8500_DMA_DEV50_HAC1_TX = 50,
+ DB8500_DMA_MEMCPY_TX_0 = 51,
+ DB8500_DMA_DEV52_SLIM1_CH4_TX_HSI_TX_CH4 = 52,
+ DB8500_DMA_DEV53_SLIM1_CH5_TX_HSI_TX_CH5 = 53,
+ DB8500_DMA_DEV54_SLIM1_CH6_TX_HSI_TX_CH6 = 54,
+ DB8500_DMA_DEV55_SLIM1_CH7_TX_HSI_TX_CH7 = 55,
+ DB8500_DMA_MEMCPY_TX_1 = 56,
+ DB8500_DMA_MEMCPY_TX_2 = 57,
+ DB8500_DMA_MEMCPY_TX_3 = 58,
+ DB8500_DMA_MEMCPY_TX_4 = 59,
+ DB8500_DMA_MEMCPY_TX_5 = 60,
+ DB8500_DMA_DEV61_CAC0_TX = 61,
+ DB8500_DMA_DEV62_CAC0_TX_HAC0_TX = 62,
+ DB8500_DMA_DEV63_HAC0_TX = 63,
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/ste_audio_io_ioctl.h b/arch/arm/mach-ux500/include/mach/ste_audio_io_ioctl.h
new file mode 100644
index 00000000000..fab511975e3
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/ste_audio_io_ioctl.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#ifndef _AUDIOIO_IOCTL_H_
+#define _AUDIOIO_IOCTL_H_
+
+
+#define AUDIOIO_IOC_MAGIC 'N'
+#define AUDIOIO_READ_REGISTER _IOWR(AUDIOIO_IOC_MAGIC, 1,\
+ struct audioio_data_t)
+#define AUDIOIO_WRITE_REGISTER _IOW(AUDIOIO_IOC_MAGIC, 2,\
+ struct audioio_data_t)
+#define AUDIOIO_PWR_CTRL_TRNSDR _IOW(AUDIOIO_IOC_MAGIC, 3,\
+ struct audioio_pwr_ctrl_t)
+#define AUDIOIO_PWR_STS_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 4,\
+ struct audioio_pwr_ctrl_t)
+#define AUDIOIO_LOOP_CTRL _IOW(AUDIOIO_IOC_MAGIC, 5,\
+ struct audioio_loop_ctrl_t)
+#define AUDIOIO_LOOP_STS _IOR(AUDIOIO_IOC_MAGIC, 6,\
+ struct audioio_loop_ctrl_t)
+#define AUDIOIO_GET_TRNSDR_GAIN_CAPABILITY _IOR(AUDIOIO_IOC_MAGIC, 7,\
+ struct audioio_get_gain_t)
+#define AUDIOIO_GAIN_CAP_LOOP _IOR(AUDIOIO_IOC_MAGIC, 8,\
+ struct audioio_gain_loop_t)
+#define AUDIOIO_SUPPORT_LOOP _IOR(AUDIOIO_IOC_MAGIC, 9,\
+ struct audioio_support_loop_t)
+#define AUDIOIO_GAIN_DESC_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 10,\
+ struct audioio_gain_desc_trnsdr_t)
+#define AUDIOIO_GAIN_CTRL_TRNSDR _IOW(AUDIOIO_IOC_MAGIC, 11,\
+ struct audioio_gain_ctrl_trnsdr_t)
+#define AUDIOIO_GAIN_QUERY_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 12,\
+ struct audioio_gain_ctrl_trnsdr_t)
+#define AUDIOIO_MUTE_CTRL_TRNSDR _IOW(AUDIOIO_IOC_MAGIC, 13,\
+ struct audioio_mute_trnsdr_t)
+#define AUDIOIO_MUTE_STS_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 14,\
+ struct audioio_mute_trnsdr_t)
+#define AUDIOIO_FADE_CTRL _IOW(AUDIOIO_IOC_MAGIC, 15,\
+ struct audioio_fade_ctrl_t)
+#define AUDIOIO_BURST_CTRL _IOW(AUDIOIO_IOC_MAGIC, 16,\
+ struct audioio_burst_ctrl_t)
+#define AUDIOIO_READ_ALL_ACODEC_REGS_CTRL _IOW(AUDIOIO_IOC_MAGIC, 17,\
+ struct audioio_read_all_acodec_reg_ctrl_t)
+#define AUDIOIO_FSBITCLK_CTRL _IOW(AUDIOIO_IOC_MAGIC, 18,\
+ struct audioio_fsbitclk_ctrl_t)
+#define AUDIOIO_PSEUDOBURST_CTRL _IOW(AUDIOIO_IOC_MAGIC, 19,\
+ struct audioio_pseudoburst_ctrl_t)
+#define AUDIOIO_AUDIOCODEC_PWR_CTRL _IOW(AUDIOIO_IOC_MAGIC, 20, \
+ struct audioio_acodec_pwr_ctrl_t)
+/* audio codec channel ids */
+#define EAR_CH 0
+#define HS_CH 1
+#define IHF_CH 2
+#define VIBL_CH 3
+#define VIBR_CH 4
+#define MIC1A_CH 5
+#define MIC1B_CH 6
+#define MIC2_CH 7
+#define LIN_CH 8
+#define DMIC12_CH 9
+#define DMIC34_CH 10
+#define DMIC56_CH 11
+#define MULTI_MIC_CH 12
+#define FMRX_CH 13
+#define FMTX_CH 14
+#define BLUETOOTH_CH 15
+
+#define MAX_NO_TRANSDUCERS 16
+
+#define AUDIOIO_TRUE 1
+#define AUDIOIO_FALSE 0
+
+enum AUDIOIO_COMMON_SWITCH {
+ AUDIOIO_COMMON_OFF = 0,
+ AUDIOIO_COMMON_ON,
+ AUDIOIO_COMMON_ALLCHANNEL_UNSUPPORTED = 0xFFFF
+};
+
+enum AUDIOIO_HAL_HW_LOOPS {
+ AUDIOIO_NOLOOP = 0,
+ AUDIOIO_SIDETONE_LOOP = 0xFFFF
+};
+
+
+enum AUDIOIO_FADE_PERIOD {
+ e_FADE_00,
+ e_FADE_01,
+ e_FADE_10,
+ e_FADE_11
+};
+
+enum AUDIOIO_CH_INDEX {
+ e_CHANNEL_1 = 0x01,
+ e_CHANNEL_2 = 0x02,
+ e_CHANNEL_3 = 0x04,
+ e_CHANNEL_4 = 0x08,
+ e_CHANNEL_ALL = 0x0f
+};
+
+struct audioio_data_t {
+ unsigned char block;
+ unsigned char addr;
+ unsigned char data;
+};
+
+struct audioio_pwr_ctrl_t {
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+ int channel_type;
+ enum AUDIOIO_CH_INDEX channel_index;
+};
+
+struct audioio_acodec_pwr_ctrl_t {
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+};
+
+struct audioio_loop_ctrl_t {
+ enum AUDIOIO_HAL_HW_LOOPS hw_loop;
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+ int channel_type;
+ enum AUDIOIO_CH_INDEX channel_index;
+};
+
+struct audioio_get_gain_t {
+ unsigned int num_channels;
+ unsigned short max_num_gain;
+};
+
+struct audioio_gain_loop_t {
+ unsigned short num_loop;
+ unsigned short max_gains;
+};
+
+struct audioio_support_loop_t {
+ unsigned short spprtd_loop_index;
+};
+
+struct audioio_gain_desc_trnsdr_t {
+ enum AUDIOIO_CH_INDEX channel_index;
+ int channel_type;
+ unsigned short gain_index;
+ int min_gain;
+ int max_gain;
+ unsigned int gain_step;
+};
+
+struct audioio_gain_ctrl_trnsdr_t {
+ enum AUDIOIO_CH_INDEX channel_index;
+ int channel_type;
+ unsigned short gain_index;
+ int gain_value;
+ unsigned int linear;
+};
+
+struct audioio_mute_trnsdr_t {
+ int channel_type;
+ enum AUDIOIO_CH_INDEX channel_index;
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+};
+
+struct audioio_fade_ctrl_t {
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+ enum AUDIOIO_FADE_PERIOD fade_period;
+ int channel_type;
+ enum AUDIOIO_CH_INDEX channel_index;
+};
+
+struct audioio_burst_ctrl_t {
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+ int channel_type;
+ int burst_fifo_interrupt_sample_count;
+ int burst_fifo_length;/* BFIFOTx */
+ int burst_fifo_switch_frame;
+ int burst_fifo_sample_number;
+};
+
+struct audioio_read_all_acodec_reg_ctrl_t {
+ unsigned char data[200];
+};
+
+struct audioio_fsbitclk_ctrl_t {
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+};
+
+struct audioio_pseudoburst_ctrl_t {
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/ste_audio_io_vibrator.h b/arch/arm/mach-ux500/include/mach/ste_audio_io_vibrator.h
new file mode 100644
index 00000000000..6b6a558e90a
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/ste_audio_io_vibrator.h
@@ -0,0 +1,37 @@
+/*
+* Overview:
+* Header File defining vibrator kernel space interface
+*
+* Copyright (C) 2010 ST Ericsson
+*
+* 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 _STE_AUDIO_IO_VIBRATOR_H_
+#define _STE_AUDIO_IO_VIBRATOR_H_
+
+/* Client definitions which can use vibrator, defined as bitmask */
+#define STE_AUDIOIO_CLIENT_AUDIO_L 1
+#define STE_AUDIOIO_CLIENT_AUDIO_R 2
+#define STE_AUDIOIO_CLIENT_FF_VIBRA 4
+#define STE_AUDIOIO_CLIENT_TIMED_VIBRA 8
+
+/*
+ * Define vibrator's maximum speed allowed
+ * Duty cycle supported by vibrator's PWM is 0-100
+ */
+#define STE_AUDIOIO_VIBRATOR_MAX_SPEED 100
+
+/* Vibrator speed structure */
+struct ste_vibra_speed {
+ unsigned char positive;
+ unsigned char negative;
+};
+
+/* Vibrator control function - uses PWM source */
+int ste_audioio_vibrator_pwm_control(int client,
+ struct ste_vibra_speed left_speed, struct ste_vibra_speed right_speed);
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/stm_musb.h b/arch/arm/mach-ux500/include/mach/stm_musb.h
new file mode 100644
index 00000000000..5181952735c
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/stm_musb.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2009 STMicroelectronics
+ * Copyright (C) 2009 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MUSB_U8500_H__
+#define __MUSB_U8500_H__
+
+#include <mach/hardware.h>
+
+/*
+ * TODO: We don't want dependencies from a generic driver (power/ab8500_bm)
+ * towards a enum in machine specific header files. This should be changed
+ */
+enum ab8500_usb_state {
+ AB8500_BM_USB_STATE_RESET_HS, /* HighSpeed Reset */
+ AB8500_BM_USB_STATE_RESET_FS, /* FullSpeed/LowSpeed Reset */
+ AB8500_BM_USB_STATE_CONFIGURED,
+ AB8500_BM_USB_STATE_SUSPEND,
+ AB8500_BM_USB_STATE_RESUME,
+ AB8500_BM_USB_STATE_MAX,
+};
+
+/*
+ * U8500-specific definitions
+ */
+
+/*
+ * Top-level Control and Status Registers
+ */
+#define OTG_DMASEL 0x200 /* OTG DMA Selector Register */
+#define OTG_TOPCTRL 0x204 /* OTG Top Control Register */
+
+/*
+ * ULPI-specific Registers
+ */
+#define OTG_UVBCTRL 0x70 /* OTG ULPI VBUS Control Register*/
+#define OTG_UCKIT 0x71 /* OTG ULPI CarKit Control Register*/
+#define OTG_UINTMASK 0x72 /* OTG ULPI INT Mask Register*/
+#define OTG_UINTSRC 0x73 /* OTG ULPI INT Source Register*/
+#define OTG_UREGDATA 0x74 /* OTG ULPI Reg Data Register*/
+#define OTG_UREGADDR 0x75 /* OTG ULPI Reg Address Register*/
+#define OTG_UREGCTRL 0x76 /* OTG ULPI Reg Control Register*/
+#define OTG_URAWDATA 0x77 /* OTG ULPI Raw Data Register*/
+
+/*
+ * OTG Top Control Register Bits
+ */
+#define OTG_TOPCTRL_MODE_ULPI (1 << 0) /* Activate ULPI interface*/
+#define OTG_TOPCTRL_UDDR (1 << 1) /* Activate ULPI double-data rate mode */
+#define OTG_TOPCTRL_SRST (1 << 2) /* OTG core soft reset*/
+#define OTG_TOPCTRL_XGATE (1 << 3) /* Activate transceiver clock*/
+#define OTG_TOPCTRL_I2C_OFF (1 << 4) /* Switch off I2C controller*/
+#define OTG_TOPCTRL_HDEV (1 << 5) /* Select host mode with FS interface*/
+#define OTG_TOPCTRL_VBUSLO (1 << 6) /* Enable VBUS for FS transceivers*/
+
+/*
+ * OTG ULPI VBUS Control Register Bits
+ */
+#define OTG_UVBCTRL_EXTVB (1 << 0) /* Use External VBUS*/
+#define OTG_UVBCTRL_EXTVI (1 << 1) /* Use External VBUS Indicator*/
+
+/*
+ * OTG ULPI Reg Control Register Bits
+ */
+#define OTG_UREGCTRL_REGREQ (1 << 0) /* Request ULPI register access */
+#define OTG_UREGCTRL_REGCMP (1 << 1) /* ULPI register access completion flag */
+#define OTG_UREGCTRL_URW (1 << 2) /* Request read from register access */
+
+/*
+ * STULPI01/STULPI05-specific definitions
+ */
+
+/*
+ * Registers accessors (different offsets for read/write/set/clear functions)
+ */
+#define ULPI_REG_READ(x) (x + 0)
+#define ULPI_REG_WRITE(x) (x + 0)
+#define ULPI_REG_SET(x) (x + 1)
+#define ULPI_REG_CLEAR(x) (x + 2)
+
+/*
+ * STULPI01/STULPI05 Registers
+ */
+#define ULPI_VIDLO 0x00 /* Vendor ID Low (Read Only) */
+#define ULPI_VIDHI 0x01 /* Vendor ID High (Read Only) */
+#define ULPI_PIDLO 0x02 /* Product ID Low (Read Only) */
+#define ULPI_PIDHI 0x03 /* Product ID High (Read Only) */
+#define ULPI_FCTRL 0x04 /* Function Control Register */
+#define ULPI_ICTRL 0x07 /* Interface Control Register */
+#define ULPI_OCTRL 0x0A /* OTG Control Register */
+#define ULPI_INTENRIS 0x0D /* Interrupt Enable Rising */
+#define ULPI_INTENFAL 0x10 /* Interrupt Enable Falling */
+#define ULPI_INTSTATU 0x13 /* Interrupt Status (Read Only) */
+#define ULPI_INTLATCH 0x14 /* Interrupt Latch (Read Only) */
+#define ULPI_DEBUG 0x15 /* Debug Register (Read Only) */
+#define ULPI_SCRATCH 0x16 /* Scratch Register */
+#define ULPI_CCTRL 0x19 /* Carkit Control Register */
+#define ULPI_PCTRL 0x3D /* Power Control Register */
+#define ULPI_ULINKSTAT 0x39 /* USB Link Status & Control Register */
+
+/*
+ * Vendor and Product IDs
+ */
+#define ULPI_VIDLO_VALUE 0x83 /*Vendor ID Low*/
+#define ULPI_VIDHI_VALUE 0x04 /*Vendor ID High*/
+#define ULPI_PIDLO_VALUE 0x4B /*Product ID Low*/
+#define ULPI_PIDHI_VALUE 0x4F /*Product ID High*/
+
+/**
+ * STULPI Function Control Register Bits
+ */
+#define ULPI_FCTRL_HSEN (0 << 0)
+#define ULPI_FCTRL_FSEN (1 << 0)
+#define ULPI_FCTRL_LSEN (2 << 0)
+#define ULPI_FCTRL_FSLSEN (3 << 0)
+#define ULPI_FCTRL_TSELECT (1 << 2)
+#define ULPI_FCTRL_OM_NORM (0 << 3)
+#define ULPI_FCTRL_OM_NONDRIV (1 << 3)
+#define ULPI_FCTRL_OM_NRZIDIS (2 << 3)
+#define ULPI_FCTRL_OM_NOSYNC (3 << 3)
+#define ULPI_FCTRL_RESET (1 << 5)
+#define ULPI_FCTRL_NOSUSPEND (1 << 6)
+
+/*
+ * STULPI Interface Control Register Bits
+ */
+#define ULPI_ICTRL_6PINSERIAL (1 << 0)
+#define ULPI_ICTRL_3PINSERIAL (1 << 1)
+#define ULPI_ICTRL_CARKITEN (1 << 2)
+#define ULPI_ICTRL_PSCLOCKEN (1 << 3)
+#define ULPI_ICTRL_VBUSINV (1 << 5)
+#define ULPI_ICTRL_IPASSTHRU (1 << 6)
+#define ULPI_ICTRL_IPROTDIS (1 << 7)
+
+/*
+ * STULPI OTG Control Register Bits
+ */
+#define ULPI_OCTRL_IDPULLUP (1 << 0)
+#define ULPI_OCTRL_DPPULLDOWN (1 << 1)
+#define ULPI_OCTRL_DMPULLDOWN (1 << 2)
+#define ULPI_OCTRL_DISCHRGVBUS (1 << 3)
+#define ULPI_OCTRL_CHRGVBUS (1 << 4)
+#define ULPI_OCTRL_DRVVBUS (1 << 5)
+#define ULPI_OCTRL_DRVVBUSEXT (1 << 6)
+#define ULPI_OCTRL_EXTVBUSIND (1 << 7)
+
+/*
+ * STULPI USB Link Status & Control Register
+ */
+#define ULPI_ULINKSTAT_CHARSPEED_MODE (3 << 5)
+#define ULPI_ULINKSTAT_SUSPEND_MODE (1 << 7)
+
+/* function prototypes */
+void ab8500_bm_usb_state_changed_wrapper(u8 bm_usb_state);
+void ab8500_bm_ulpi_set_char_speed_mode(u8 mode);
+void ab8500_bm_ulpi_set_char_suspend_mode(u8 suspend);
+
+#endif/* __MUSB_U8500_H__ */
diff --git a/arch/arm/mach-ux500/include/mach/system.h b/arch/arm/mach-ux500/include/mach/system.h
index c0cd8006f1a..4fff1c94e58 100644
--- a/arch/arm/mach-ux500/include/mach/system.h
+++ b/arch/arm/mach-ux500/include/mach/system.h
@@ -8,6 +8,8 @@
#ifndef __ASM_ARCH_SYSTEM_H
#define __ASM_ARCH_SYSTEM_H
+#include <mach/prcmu-fw-api.h>
+
static inline void arch_idle(void)
{
/*
@@ -19,7 +21,9 @@ static inline void arch_idle(void)
static inline void arch_reset(char mode, const char *cmd)
{
- /* yet to be implemented - TODO */
+#ifdef CONFIG_UX500_SOC_DB8500
+ prcmu_system_reset();
+#endif
}
#endif
diff --git a/arch/arm/mach-ux500/include/mach/tc35893-keypad.h b/arch/arm/mach-ux500/include/mach/tc35893-keypad.h
new file mode 100644
index 00000000000..be66de2ee99
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/tc35893-keypad.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com> for ST-Ericsson
+ */
+
+#ifndef __TC35893_KEYPAD_H
+#define __TC35893_KEYPAD_H
+
+/*
+ * Keypad related platform specific constants
+ * These values may be modified for fine tuning
+ */
+#define TC_KPD_ROWS 0x8
+#define TC_KPD_COLUMNS 0x8
+#define TC_KPD_DEBOUNCE_PERIOD 0xA3
+#define TC_KPD_SETTLE_TIME 0xA3
+
+/**
+ * struct tc35893_platform_data - data structure for platform specific data
+ * @kcode_tbl: lookup table for keycodes
+ * @krow: mask for available rows, value is 0xFF
+ * @kcol: mask for available columns, value is 0xFF
+ * @debounce_period: platform specific debounce time
+ * @settle_time: platform specific settle down time
+ * @irqtype: type of interrupt, falling or rising edge
+ * @irq: irq no,
+ * @enable_wakeup: specifies if keypad event can wake up system from sleep
+ * @scan_enable: represents keypad hardware scan enable status
+ * @op_mode: Specifies polling of interrupt mode
+ */
+struct tc35893_platform_data {
+ u8 *kcode_tbl;
+ u8 krow;
+ u8 kcol;
+ u8 debounce_period;
+ u8 settle_time;
+ unsigned long irqtype;
+ int irq;
+ bool enable_wakeup;
+ unsigned char scan_enable;
+ int op_mode;
+};
+
+#endif /*__TC35893_KEYPAD_H*/
diff --git a/arch/arm/mach-ux500/include/mach/tee_ta_start_modem.h b/arch/arm/mach-ux500/include/mach/tee_ta_start_modem.h
new file mode 100644
index 00000000000..6978b7314c5
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/tee_ta_start_modem.h
@@ -0,0 +1,48 @@
+/*
+ * Data types and interface for TEE application for starting the modem.
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef TEE_TA_START_MODEM_H
+#define TEE_TA_START_MODEM_H
+
+#define COMMAND_ID_START_MODEM 0x00000001
+
+#define UUID_TEE_TA_START_MODEM_LOW 0x8AD94107
+#define UUID_TEE_TA_START_MODEM_MID 0x6E50
+#define UUID_TEE_TA_START_MODEM_HIGH 0x418E
+#define UUID_TEE_TA_START_MODEM_CLOCKSEQ \
+ {0xB1, 0x14, 0x75, 0x7D, 0x60, 0x21, 0xBD, 0x36}
+
+struct mcore_segment_descr {
+ void *segment;
+ void *hash;
+ u32 size;
+};
+
+struct access_image_descr {
+ void *elf_hdr;
+ void *pgm_hdr_tbl;
+ void *signature;
+ unsigned long nbr_segment;
+ struct mcore_segment_descr *descr;
+};
+
+/* TODO: To be redefined with only info needed by Secure world. */
+struct tee_ta_start_modem {
+ void *access_mem_start;
+ u32 shared_mem_size;
+ u32 access_private_mem_size;
+ struct access_image_descr access_image_descr;
+};
+
+/**
+ * This is the function to handle the modem release.
+ */
+int tee_ta_start_modem(struct tee_ta_start_modem *data);
+
+#endif
+
diff --git a/arch/arm/mach-ux500/include/mach/u8500_acodec_ab8500.h b/arch/arm/mach-ux500/include/mach/u8500_acodec_ab8500.h
new file mode 100644
index 00000000000..0575bbdb730
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/u8500_acodec_ab8500.h
@@ -0,0 +1,284 @@
+/* Header file for u8500 audiocodec specific data structures, enums
+ * and private & public functions.
+ * Author: Deepak Karda
+ * Copyright (C) 2009 ST-Ericsson Pvt. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _U8500_ACODEC_AB8500_H_
+#define _U8500_ACODEC_AB8500_H_
+
+#include <mach/ab8500.h>
+#include <linux/i2s/i2s.h>
+
+#ifdef CONFIG_U8500_AB8500_CUT10
+#include <mach/ab8500_codec_v1_0.h>
+//#include <mach/ab8500_codec_p_v1_0.h>
+#else /*CONFIG_U8500_4500_ED */
+#include <mach/ab8500_codec.h>
+#include <mach/ab8500_codec_p.h>
+#endif
+
+#define NUMBER_OUTPUT_DEVICE 5
+#define NUMBER_INPUT_DEVICE 13
+#define NUMBER_LOOPBACK_STATE 2
+#define NUMBER_SWITCH_STATE 2
+#define NUMBER_POWER_STATE 2
+#define NUMBER_TDM_MODE_STATE 2
+#define NUMBER_DIRECT_RENDERING_STATE 2
+#define NUMBER_PCM_RENDERING_STATE 3
+
+#define CODEC_MUTE 0x20
+#define DEFAULT_VOLUME 0x64
+#define DEFAULT_GAIN 0x32
+#define VOL_MAX 0x64
+#define VOL_MIN 0x00
+#define DEFAULT_OUTPUT_DEVICE AB8500_CODEC_DEST_HEADSET
+#define DEFAULT_INPUT_DEVICE AB8500_CODEC_SRC_D_MICROPHONE_1
+#define DEFAULT_LOOPBACK_STATE DISABLE
+#define DEFAULT_SWITCH_STATE DISABLE
+#define DEFAULT_TDM8_CH_MODE_STATE DISABLE
+#define DEFAULT_DIRECT_RENDERING_STATE DISABLE
+#define DEFAULT_BURST_FIFO_STATE RENDERING_DISABLE
+#define DEFAULT_FM_PLAYBACK_STATE RENDERING_DISABLE
+#define DEFAULT_FM_TX_STATE RENDERING_DISABLE
+
+#define MIN_RATE_PLAYBACK 48000
+#define MAX_RATE_PLAYBACK 48000
+#define MIN_RATE_CAPTURE 48000
+#define MAX_RATE_CAPTURE 48000
+#define MAX_NO_OF_RATES 1
+
+#define ALSA_MSP_BT_NUM 0
+#define ALSA_MSP_PCM_NUM 1
+#define ALSA_MSP_HDMI_NUM 2
+
+#define I2S_CLIENT_MSP0 0
+#define I2S_CLIENT_MSP1 1
+#define I2S_CLIENT_MSP2 2
+
+typedef enum {
+ DISABLE,
+ ENABLE
+} t_u8500_bool_state;
+
+typedef enum {
+ RENDERING_DISABLE,
+ RENDERING_ENABLE,
+ RENDERING_PENDING
+} t_u8500_pmc_rendering_state;
+
+typedef enum {
+ ACODEC_CONFIG_REQUIRED,
+ ACODEC_CONFIG_NOT_REQUIRED
+} t_u8500_acodec_config_need;
+
+typedef enum {
+ CLASSICAL_MODE,
+ TDM_8_CH_MODE
+} t_u8500_mode;
+
+typedef struct {
+ unsigned int left_volume;
+ unsigned int right_volume;
+ unsigned int mute_state;
+ t_u8500_bool_state power_state;
+} u8500_io_dev_config_t;
+
+typedef enum {
+ NO_USER = 0,
+ USER_ALSA = 2, /*To make it equivalent to user id for MSP */
+ USER_SAA,
+} t_acodec_user;
+
+typedef struct {
+ u8500_io_dev_config_t output_config[NUMBER_OUTPUT_DEVICE];
+ u8500_io_dev_config_t input_config[NUMBER_INPUT_DEVICE];
+ //t_acodec_user user;
+ t_acodec_user cur_user;
+} t_u8500_codec_system_context;
+
+typedef enum {
+ T_CODEC_SAMPLING_FREQ_48KHZ = 48,
+} acodec_sample_frequency;
+
+struct acodec_configuration {
+ t_ab8500_codec_direction direction;
+ acodec_sample_frequency input_frequency;
+ acodec_sample_frequency output_frequency;
+ codec_msp_srg_clock_sel_type mspClockSel;
+ codec_msp_in_clock_freq_type mspInClockFreq;
+ u32 channels;
+ t_acodec_user user;
+ t_u8500_acodec_config_need acodec_config_need;
+ t_u8500_bool_state direct_rendering_mode;
+ t_u8500_bool_state tdm8_ch_mode;
+ t_u8500_bool_state digital_loopback;
+ void (*handler) (void *data);
+ void *tx_callback_data;
+ void *rx_callback_data;
+};
+
+typedef enum {
+ ACODEC_DISABLE_ALL,
+ ACODEC_DISABLE_TRANSMIT,
+ ACODEC_DISABLE_RECEIVE,
+} t_acodec_disable;
+
+struct i2sdrv_data {
+ struct i2s_device *i2s;
+ spinlock_t i2s_lock;
+ /* buffer is NULL unless this device is open (users > 0) */
+ int flag;
+ u32 tx_status;
+ u32 rx_status;
+};
+
+#define MAX_I2S_CLIENTS 3 //0=BT, 1=ACODEC, 2=HDMI
+
+/*extern t_ab8500_codec_error u8500_acodec_set_volume(int input_vol_left,
+ int input_vol_right,
+ int output_vol_left,
+ int output_vol_right, t_acodec_user user);*/
+
+extern t_ab8500_codec_error u8500_acodec_open(int client_id, int stream_id);
+//extern t_ab8500_codec_error u8500_acodec_pause_transfer(void);
+//extern t_ab8500_codec_error u8500_acodec_unpause_transfer(void);
+extern t_ab8500_codec_error u8500_acodec_send_data(int client_id, void *data,
+ size_t bytes, int dma_flag);
+extern t_ab8500_codec_error u8500_acodec_receive_data(int client_id, void *data,
+ size_t bytes,
+ int dma_flag);
+extern t_ab8500_codec_error u8500_acodec_close(int client_id,
+ t_acodec_disable flag);
+extern t_ab8500_codec_error u8500_acodec_tx_rx_data(int client_id,
+ void *tx_data,
+ size_t tx_bytes,
+ void *rx_data,
+ size_t rx_bytes,
+ int dma_flag);
+
+extern t_ab8500_codec_error u8500_acodec_set_output_volume(t_ab8500_codec_dest
+ dest_device,
+ int left_volume,
+ int right_volume,
+ t_acodec_user user);
+
+extern t_ab8500_codec_error u8500_acodec_get_output_volume(t_ab8500_codec_dest
+ dest_device,
+ int *p_left_volume,
+ int *p_right_volume,
+ t_acodec_user user);
+
+extern t_ab8500_codec_error u8500_acodec_set_input_volume(t_ab8500_codec_src
+ src_device,
+ int left_volume,
+ int right_volume,
+ t_acodec_user user);
+
+extern t_ab8500_codec_error u8500_acodec_get_input_volume(t_ab8500_codec_src
+ src_device,
+ int *p_left_volume,
+ int *p_right_volume,
+ t_acodec_user user);
+
+extern t_ab8500_codec_error u8500_acodec_toggle_analog_lpbk(t_u8500_bool_state
+ lpbk_state,
+ t_acodec_user user);
+
+extern t_ab8500_codec_error u8500_acodec_toggle_digital_lpbk(t_u8500_bool_state
+ lpbk_state,
+ t_ab8500_codec_dest
+ dest_device,
+ t_ab8500_codec_src
+ src_device,
+ t_acodec_user user,
+ t_u8500_bool_state
+ tdm8_ch_mode);
+
+extern t_ab8500_codec_error
+u8500_acodec_toggle_playback_mute_control(t_ab8500_codec_dest dest_device,
+ t_u8500_bool_state mute_state,
+ t_acodec_user user);
+extern t_ab8500_codec_error
+u8500_acodec_toggle_capture_mute_control(t_ab8500_codec_src src_device,
+ t_u8500_bool_state mute_state,
+ t_acodec_user user);
+
+extern t_ab8500_codec_error u8500_acodec_enable_audio_mode(struct
+ acodec_configuration
+ *acodec_config);
+/*extern t_ab8500_codec_error u8500_acodec_enable_voice_mode(struct acodec_configuration *acodec_config);*/
+
+extern t_ab8500_codec_error u8500_acodec_select_input(t_ab8500_codec_src
+ input_device,
+ t_acodec_user user,
+ t_u8500_mode mode);
+extern t_ab8500_codec_error u8500_acodec_select_output(t_ab8500_codec_dest
+ output_device,
+ t_acodec_user user,
+ t_u8500_mode mode);
+
+extern t_ab8500_codec_error u8500_acodec_allocate_ad_slot(t_ab8500_codec_src
+ input_device,
+ t_u8500_mode mode);
+extern t_ab8500_codec_error u8500_acodec_unallocate_ad_slot(t_ab8500_codec_src
+ input_device,
+ t_u8500_mode mode);
+extern t_ab8500_codec_error u8500_acodec_allocate_da_slot(t_ab8500_codec_dest
+ output_device,
+ t_u8500_mode mode);
+extern t_ab8500_codec_error u8500_acodec_unallocate_da_slot(t_ab8500_codec_dest
+ output_device,
+ t_u8500_mode mode);
+
+extern t_ab8500_codec_error u8500_acodec_set_src_power_cntrl(t_ab8500_codec_src
+ input_device,
+ t_u8500_bool_state
+ pwr_state);
+extern t_ab8500_codec_error
+u8500_acodec_set_dest_power_cntrl(t_ab8500_codec_dest output_device,
+ t_u8500_bool_state pwr_state);
+
+extern t_u8500_bool_state u8500_acodec_get_src_power_state(t_ab8500_codec_src
+ input_device);
+extern t_u8500_bool_state u8500_acodec_get_dest_power_state(t_ab8500_codec_dest
+ output_device);
+extern t_ab8500_codec_error
+u8500_acodec_set_burst_mode_fifo(t_u8500_pmc_rendering_state fifo_state);
+
+extern t_ab8500_codec_error u8500_acodec_unsetuser(t_acodec_user user);
+extern t_ab8500_codec_error u8500_acodec_setuser(t_acodec_user user);
+
+extern void codec_power_init(void);
+extern void u8500_acodec_powerdown(void);
+
+//t_ab8500_codec_error acodec_msp_enable(t_touareg_codec_sample_frequency freq,int channels, t_acodec_user user);
+
+#define TRG_CODEC_ADDRESS_ON_SPI_BUS (0x0D)
+
+extern int ab8500_write(u8 block, u32 adr, u8 data);
+extern int ab8500_read(u8 block, u32 adr);
+
+#if 0
+#define FUNC_ENTER() printk("\n -Enter : %s",__FUNCTION__)
+#define FUNC_EXIT() printk("\n -Exit : %s",__FUNCTION__)
+#else
+#define FUNC_ENTER()
+#define FUNC_EXIT()
+#endif
+#endif /*END OF HEADSER FILE */
diff --git a/arch/arm/mach-ux500/include/mach/uart.h b/arch/arm/mach-ux500/include/mach/uart.h
new file mode 100644
index 00000000000..22feb1f84da
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/uart.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson SA
+ *
+ * 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 _U8500_UART_H_
+#define _U8500_UART_H_
+
+struct uart_amba_plat_data {
+ void (*init) (void);
+ void (*exit) (void);
+};
+
+#endif /* _U8500_UART_H_ */
diff --git a/arch/arm/mach-ux500/localtimer.c b/arch/arm/mach-ux500/localtimer.c
index 2288f6a7c51..df8dc05c123 100644
--- a/arch/arm/mach-ux500/localtimer.c
+++ b/arch/arm/mach-ux500/localtimer.c
@@ -18,11 +18,20 @@
#include <asm/smp_twd.h>
#include <asm/localtimer.h>
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+void smp_timer_broadcast(const struct cpumask *mask);
+#endif
+
/*
* Setup the local clock events for a CPU.
*/
void __cpuinit local_timer_setup(struct clock_event_device *evt)
{
evt->irq = IRQ_LOCALTIMER;
+
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+ evt->broadcast = smp_timer_broadcast;
+#endif
+
twd_timer_setup(evt);
}
diff --git a/arch/arm/mach-ux500/mbox.c b/arch/arm/mach-ux500/mbox.c
new file mode 100644
index 00000000000..63435389c54
--- /dev/null
+++ b/arch/arm/mach-ux500/mbox.c
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
+ * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+/*
+ * Mailbox nomenclature:
+ *
+ * APE MODEM
+ * mbox pairX
+ * ..........................
+ * . .
+ * . peer .
+ * . send ---- .
+ * . --> | | .
+ * . | | .
+ * . ---- .
+ * . .
+ * . local .
+ * . rec ---- .
+ * . | | <-- .
+ * . | | .
+ * . ---- .
+ * .........................
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/completion.h>
+#include <mach/mbox.h>
+
+#define MBOX_NAME "mbox"
+
+#define MBOX_FIFO_DATA 0x000
+#define MBOX_FIFO_ADD 0x004
+#define MBOX_FIFO_REMOVE 0x008
+#define MBOX_FIFO_THRES_FREE 0x00C
+#define MBOX_FIFO_THRES_OCCUP 0x010
+#define MBOX_FIFO_STATUS 0x014
+
+#define MBOX_DISABLE_IRQ 0x4
+#define MBOX_ENABLE_IRQ 0x0
+#define MBOX_LATCH 1
+
+/* Global list of all mailboxes */
+static struct list_head mboxs = LIST_HEAD_INIT(mboxs);
+
+static struct mbox *get_mbox_with_id(u8 id)
+{
+ u8 i;
+ struct list_head *pos = &mboxs;
+ for (i = 0; i <= id; i++)
+ pos = pos->next;
+
+ return (struct mbox *) list_entry(pos, struct mbox, list);
+}
+
+int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block)
+{
+ int res = 0;
+
+ spin_lock(&mbox->lock);
+
+ dev_dbg(&(mbox->pdev->dev),
+ "About to buffer 0x%X to mailbox 0x%X."
+ " ri = %d, wi = %d\n",
+ mbox_msg, (u32)mbox, mbox->read_index,
+ mbox->write_index);
+
+ /* Check if write buffer is full */
+ while (((mbox->write_index + 1) % MBOX_BUF_SIZE) == mbox->read_index) {
+ if (!block) {
+ dev_dbg(&(mbox->pdev->dev),
+ "Buffer full in non-blocking call! "
+ "Returning -ENOMEM!\n");
+ res = -ENOMEM;
+ goto exit;
+ }
+ spin_unlock(&mbox->lock);
+ dev_dbg(&(mbox->pdev->dev),
+ "Buffer full in blocking call! Sleeping...\n");
+ mbox->client_blocked = 1;
+ wait_for_completion(&mbox->buffer_available);
+ dev_dbg(&(mbox->pdev->dev),
+ "Blocking send was woken up! Trying again...\n");
+ spin_lock(&mbox->lock);
+ }
+
+ mbox->buffer[mbox->write_index] = mbox_msg;
+ mbox->write_index = (mbox->write_index + 1) % MBOX_BUF_SIZE;
+
+ /*
+ * Indicate that we want an IRQ as soon as there is a slot
+ * in the FIFO
+ */
+ writel(MBOX_ENABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+
+exit:
+ spin_unlock(&mbox->lock);
+ return res;
+}
+EXPORT_SYMBOL(mbox_send);
+
+#if defined(CONFIG_DEBUG_FS)
+/*
+ * Expected input: <value> <nbr sends>
+ * Example: "echo 0xdeadbeef 4 > mbox-node" sends 0xdeadbeef 4 times
+ */
+static ssize_t mbox_write_fifo(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ unsigned long mbox_mess;
+ unsigned long nbr_sends;
+ unsigned long i;
+ char int_buf[16];
+ char *token;
+ char *val;
+
+ struct mbox *mbox = (struct mbox *) dev->platform_data;
+
+ strncpy((char *) &int_buf, buf, sizeof(int_buf));
+ token = (char *) &int_buf;
+
+ /* Parse message */
+ val = strsep(&token, " ");
+ if ((val == NULL) || (strict_strtoul(val, 16, &mbox_mess) != 0))
+ mbox_mess = 0xDEADBEEF;
+
+ val = strsep(&token, " ");
+ if ((val == NULL) || (strict_strtoul(val, 10, &nbr_sends) != 0))
+ nbr_sends = 1;
+
+ dev_dbg(dev, "Will write 0x%lX %ld times using data struct at 0x%X\n",
+ mbox_mess, nbr_sends, (u32) mbox);
+
+ for (i = 0; i < nbr_sends; i++)
+ mbox_send(mbox, mbox_mess, true);
+
+ return count;
+}
+
+static ssize_t mbox_read_fifo(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int mbox_value;
+ struct mbox *mbox = (struct mbox *) dev->platform_data;
+
+ if ((readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7) <= 0)
+ return sprintf(buf, "Mailbox is empty\n");
+
+ mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
+ writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
+
+ return sprintf(buf, "0x%X\n", mbox_value);
+}
+
+static DEVICE_ATTR(fifo, S_IWUGO | S_IRUGO, mbox_read_fifo, mbox_write_fifo);
+
+static int mbox_show(struct seq_file *s, void *data)
+{
+ struct list_head *pos;
+ u8 mbox_index = 0;
+
+ list_for_each(pos, &mboxs) {
+ struct mbox *m =
+ (struct mbox *) list_entry(pos, struct mbox, list);
+ if (m == NULL) {
+ seq_printf(s,
+ "Unable to retrieve mailbox %d\n",
+ mbox_index);
+ continue;
+ }
+
+ spin_lock(&m->lock);
+ if ((m->virtbase_peer == NULL) || (m->virtbase_local == NULL)) {
+ seq_printf(s, "MAILBOX %d not setup or corrupt\n",
+ mbox_index);
+ spin_unlock(&m->lock);
+ continue;
+ }
+
+ seq_printf(s,
+ "===========================\n"
+ " MAILBOX %d\n"
+ " PEER MAILBOX DUMP\n"
+ "---------------------------\n"
+ "FIFO: 0x%X (%d)\n"
+ "Free Threshold: 0x%.2X (%d)\n"
+ "Occupied Threshold: 0x%.2X (%d)\n"
+ "Status: 0x%.2X (%d)\n"
+ " Free spaces (ot): %d (%d)\n"
+ " Occup spaces (ot): %d (%d)\n"
+ "===========================\n"
+ " LOCAL MAILBOX DUMP\n"
+ "---------------------------\n"
+ "FIFO: 0x%.X (%d)\n"
+ "Free Threshold: 0x%.2X (%d)\n"
+ "Occupied Threshold: 0x%.2X (%d)\n"
+ "Status: 0x%.2X (%d)\n"
+ " Free spaces (ot): %d (%d)\n"
+ " Occup spaces (ot): %d (%d)\n"
+ "===========================\n"
+ "write_index: %d\n"
+ "read_index : %d\n"
+ "===========================\n"
+ "\n",
+ mbox_index,
+ readl(m->virtbase_peer + MBOX_FIFO_DATA),
+ readl(m->virtbase_peer + MBOX_FIFO_DATA),
+ readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
+ readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
+ readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
+ readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
+ readl(m->virtbase_peer + MBOX_FIFO_STATUS),
+ readl(m->virtbase_peer + MBOX_FIFO_STATUS),
+ (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 4) & 0x7,
+ (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 7) & 0x1,
+ (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 0) & 0x7,
+ (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 3) & 0x1,
+ readl(m->virtbase_local + MBOX_FIFO_DATA),
+ readl(m->virtbase_local + MBOX_FIFO_DATA),
+ readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
+ readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
+ readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
+ readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
+ readl(m->virtbase_local + MBOX_FIFO_STATUS),
+ readl(m->virtbase_local + MBOX_FIFO_STATUS),
+ (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 4) & 0x7,
+ (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 7) & 0x1,
+ (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 0) & 0x7,
+ (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 3) & 0x1,
+ m->write_index, m->read_index);
+ mbox_index++;
+ spin_unlock(&m->lock);
+ }
+
+ return 0;
+}
+
+static int mbox_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mbox_show, NULL);
+}
+
+static const struct file_operations mbox_operations = {
+ .owner = THIS_MODULE,
+ .open = mbox_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+
+static irqreturn_t mbox_irq(int irq, void *arg)
+{
+ u32 mbox_value;
+ int nbr_occup;
+ int nbr_free;
+ struct mbox *mbox = (struct mbox *) arg;
+
+ spin_lock(&mbox->lock);
+
+ dev_dbg(&(mbox->pdev->dev),
+ "mbox IRQ [%d] received. ri = %d, wi = %d\n",
+ irq, mbox->read_index, mbox->write_index);
+
+ /*
+ * Check if we have any outgoing messages, and if there is space for
+ * them in the FIFO.
+ */
+ if (mbox->read_index != mbox->write_index) {
+ /*
+ * Check by reading FREE for LOCAL since that indicates
+ * OCCUP for PEER
+ */
+ nbr_free = (readl(mbox->virtbase_local + MBOX_FIFO_STATUS)
+ >> 4) & 0x7;
+ dev_dbg(&(mbox->pdev->dev),
+ "Status indicates %d empty spaces in the FIFO!\n",
+ nbr_free);
+
+ while ((nbr_free > 0) &&
+ (mbox->read_index != mbox->write_index)) {
+ /* Write the message and latch it into the FIFO */
+ writel(mbox->buffer[mbox->read_index],
+ (mbox->virtbase_peer + MBOX_FIFO_DATA));
+ writel(MBOX_LATCH,
+ (mbox->virtbase_peer + MBOX_FIFO_ADD));
+ dev_dbg(&(mbox->pdev->dev),
+ "Wrote message 0x%X to addr 0x%X\n",
+ mbox->buffer[mbox->read_index],
+ (u32) (mbox->virtbase_peer + MBOX_FIFO_DATA));
+
+ nbr_free--;
+ mbox->read_index =
+ (mbox->read_index + 1) % MBOX_BUF_SIZE;
+ }
+
+ /*
+ * Check if we still want IRQ:s when there is free
+ * space to send
+ */
+ if (mbox->read_index != mbox->write_index) {
+ dev_dbg(&(mbox->pdev->dev),
+ "Still have messages to send, but FIFO full. "
+ "Request IRQ again!\n");
+ writel(MBOX_ENABLE_IRQ,
+ mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+ } else {
+ dev_dbg(&(mbox->pdev->dev),
+ "No more messages to send. "
+ "Do not request IRQ again!\n");
+ writel(MBOX_DISABLE_IRQ,
+ mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+ }
+
+ /*
+ * Check if we can signal any blocked clients that it is OK to
+ * start buffering again
+ */
+ if (mbox->client_blocked &&
+ (((mbox->write_index + 1) % MBOX_BUF_SIZE)
+ != mbox->read_index)) {
+ dev_dbg(&(mbox->pdev->dev),
+ "Waking up blocked client\n");
+ complete(&mbox->buffer_available);
+ mbox->client_blocked = 0;
+ }
+ }
+
+ /* Check if we have any incoming messages */
+ nbr_occup = readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7;
+ if (nbr_occup == 0)
+ goto exit;
+
+ if (mbox->cb == NULL) {
+ dev_dbg(&(mbox->pdev->dev), "No receive callback registered, "
+ "leaving %d incoming messages in fifo!\n", nbr_occup);
+ goto exit;
+ }
+
+ /* Read and acknowledge the message */
+ mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
+ writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
+
+ /* Notify consumer of new mailbox message */
+ dev_dbg(&(mbox->pdev->dev), "Calling callback for message 0x%X!\n",
+ mbox_value);
+ mbox->cb(mbox_value, mbox->client_data);
+
+exit:
+ dev_dbg(&(mbox->pdev->dev), "Exit mbox IRQ. ri = %d, wi = %d\n",
+ mbox->read_index, mbox->write_index);
+ spin_unlock(&mbox->lock);
+
+ return IRQ_HANDLED;
+}
+
+/* Setup is executed once for each mbox pair */
+struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv)
+{
+ struct resource *resource;
+ int irq;
+ int res;
+ struct mbox *mbox;
+
+ mbox = get_mbox_with_id(mbox_id);
+ if (mbox == NULL) {
+ dev_err(&(mbox->pdev->dev), "Incorrect mailbox id: %d!\n",
+ mbox_id);
+ goto exit;
+ }
+
+ /*
+ * Check if mailbox has been allocated to someone else,
+ * otherwise allocate it
+ */
+ if (mbox->allocated) {
+ dev_err(&(mbox->pdev->dev), "Mailbox number %d is busy!\n",
+ mbox_id);
+ mbox = NULL;
+ goto exit;
+ }
+ mbox->allocated = true;
+
+ dev_dbg(&(mbox->pdev->dev), "Initiating mailbox number %d: 0x%X...\n",
+ mbox_id, (u32)mbox);
+
+ mbox->client_data = priv;
+ mbox->cb = mbox_cb;
+
+ /* Get addr for peer mailbox and ioremap it */
+ resource = platform_get_resource_byname(mbox->pdev,
+ IORESOURCE_MEM,
+ "mbox_peer");
+ if (resource == NULL) {
+ dev_err(&(mbox->pdev->dev),
+ "Unable to retrieve mbox peer resource\n");
+ mbox = NULL;
+ goto exit;
+ }
+ dev_dbg(&(mbox->pdev->dev),
+ "Resource name: %s start: 0x%X, end: 0x%X\n",
+ resource->name, resource->start, resource->end);
+ mbox->virtbase_peer =
+ ioremap(resource->start, resource->end - resource->start);
+ if (!mbox->virtbase_peer) {
+ dev_err(&(mbox->pdev->dev), "Unable to ioremap peer mbox\n");
+ mbox = NULL;
+ goto exit;
+ }
+ dev_dbg(&(mbox->pdev->dev),
+ "ioremapped peer physical: (0x%X-0x%X) to virtual: 0x%X\n",
+ resource->start, resource->end, (u32) mbox->virtbase_peer);
+
+ /* Get addr for local mailbox and ioremap it */
+ resource = platform_get_resource_byname(mbox->pdev,
+ IORESOURCE_MEM,
+ "mbox_local");
+ if (resource == NULL) {
+ dev_err(&(mbox->pdev->dev),
+ "Unable to retrieve mbox local resource\n");
+ mbox = NULL;
+ goto exit;
+ }
+ dev_dbg(&(mbox->pdev->dev),
+ "Resource name: %s start: 0x%X, end: 0x%X\n",
+ resource->name, resource->start, resource->end);
+ mbox->virtbase_local =
+ ioremap(resource->start, resource->end - resource->start);
+ if (!mbox->virtbase_local) {
+ dev_err(&(mbox->pdev->dev), "Unable to ioremap local mbox\n");
+ mbox = NULL;
+ goto exit;
+ }
+ dev_dbg(&(mbox->pdev->dev),
+ "ioremapped local physical: (0x%X-0x%X) to virtual: 0x%X\n",
+ resource->start, resource->end, (u32) mbox->virtbase_peer);
+
+ init_completion(&mbox->buffer_available);
+ mbox->client_blocked = 0;
+
+ /* Get IRQ for mailbox and allocate it */
+ irq = platform_get_irq_byname(mbox->pdev, "mbox_irq");
+ if (irq < 0) {
+ dev_err(&(mbox->pdev->dev),
+ "Unable to retrieve mbox irq resource\n");
+ mbox = NULL;
+ goto exit;
+ }
+
+ dev_dbg(&(mbox->pdev->dev), "Allocating irq %d...\n", irq);
+ res = request_irq(irq, mbox_irq, 0, mbox->name, (void *) mbox);
+ if (res < 0) {
+ dev_err(&(mbox->pdev->dev),
+ "Unable to allocate mbox irq %d\n", irq);
+ mbox = NULL;
+ goto exit;
+ }
+
+ /* Set up mailbox to not launch IRQ on free space in mailbox */
+ writel(MBOX_DISABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+
+ /*
+ * Set up mailbox to launch IRQ on new message if we have
+ * a callback set. If not, do not raise IRQ, but keep message
+ * in FIFO for manual retrieval
+ */
+ if (mbox_cb != NULL)
+ writel(MBOX_ENABLE_IRQ,
+ mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
+ else
+ writel(MBOX_DISABLE_IRQ,
+ mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
+
+#if defined(CONFIG_DEBUG_FS)
+ res = device_create_file(&(mbox->pdev->dev), &dev_attr_fifo);
+ if (res != 0)
+ dev_warn(&(mbox->pdev->dev),
+ "Unable to create mbox sysfs entry");
+
+ (void) debugfs_create_file("mbox", S_IFREG | S_IRUGO, NULL,
+ NULL, &mbox_operations);
+#endif
+
+ dev_info(&(mbox->pdev->dev),
+ "Mailbox driver with index %d initated!\n", mbox_id);
+
+exit:
+ return mbox;
+}
+EXPORT_SYMBOL(mbox_setup);
+
+
+int __init mbox_probe(struct platform_device *pdev)
+{
+ struct mbox local_mbox;
+ struct mbox *mbox;
+ int res = 0;
+ dev_dbg(&(pdev->dev), "Probing mailbox (pdev = 0x%X)...\n", (u32) pdev);
+
+ memset(&local_mbox, 0x0, sizeof(struct mbox));
+
+ /* Associate our mbox data with the platform device */
+ res = platform_device_add_data(pdev,
+ (void *) &local_mbox,
+ sizeof(struct mbox));
+ if (res != 0) {
+ dev_err(&(pdev->dev),
+ "Unable to allocate driver platform data!\n");
+ goto exit;
+ }
+
+ mbox = (struct mbox *) pdev->dev.platform_data;
+ mbox->pdev = pdev;
+ mbox->write_index = 0;
+ mbox->read_index = 0;
+
+ INIT_LIST_HEAD(&(mbox->list));
+ list_add_tail(&(mbox->list), &mboxs);
+
+ sprintf(mbox->name, "%s", MBOX_NAME);
+ spin_lock_init(&mbox->lock);
+
+ dev_info(&(pdev->dev), "Mailbox driver loaded\n");
+
+exit:
+ return res;
+}
+
+static struct platform_driver mbox_driver = {
+ .driver = {
+ .name = MBOX_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mbox_init(void)
+{
+ return platform_driver_probe(&mbox_driver, mbox_probe);
+}
+
+module_init(mbox_init);
+
+void __exit mbox_exit(void)
+{
+ platform_driver_unregister(&mbox_driver);
+}
+
+module_exit(mbox_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MBOX driver");
diff --git a/arch/arm/mach-ux500/mcde.c b/arch/arm/mach-ux500/mcde.c
new file mode 100644
index 00000000000..0ad4af928cd
--- /dev/null
+++ b/arch/arm/mach-ux500/mcde.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * MOP500/HREF500 ed/v1 Display platform devices
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <video/mcde.h>
+
+static struct resource mcde_resources[] = {
+ [0] = {
+ .name = MCDE_IO_AREA,
+ .start = U8500_MCDE_BASE,
+ .end = U8500_MCDE_BASE + 0x1000 - 1, /* TODO: Fix size */
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = MCDE_IO_AREA,
+ .start = U8500_DSI_LINK1_BASE,
+ .end = U8500_DSI_LINK1_BASE + U8500_DSI_LINK_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .name = MCDE_IO_AREA,
+ .start = U8500_DSI_LINK2_BASE,
+ .end = U8500_DSI_LINK2_BASE + U8500_DSI_LINK_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [3] = {
+ .name = MCDE_IO_AREA,
+ .start = U8500_DSI_LINK3_BASE,
+ .end = U8500_DSI_LINK3_BASE + U8500_DSI_LINK_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [4] = {
+ .name = MCDE_IRQ,
+ .start = IRQ_DISP,
+ .end = IRQ_DISP,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static void dev_release_noop(struct device *dev)
+{
+ /* Do nothing */
+}
+
+static struct mcde_platform_data mcde_pdata = {
+ .num_dsilinks = 3,
+ /*
+ * [0] = 3: 24 bits DPI: connect LSB Ch B to D[0:7]
+ * [3] = 4: 24 bits DPI: connect MID Ch B to D[24:31]
+ * [4] = 5: 24 bits DPI: connect MSB Ch B to D[32:39]
+ *
+ * [1] = 3: TV out : connect LSB Ch B to D[8:15]
+ */
+#define DONT_CARE 0
+ .outmux = { 3, 3, DONT_CARE, 4, 5 },
+#undef DONT_CARE
+ .syncmux = 0x00, /* DPI channel A and B on output pins A and B resp */
+ .regulator_id = "v-ana",
+ .clock_dsi_id = "hdmi",
+ .clock_dsi_lp_id = "tv",
+ .clock_dpi_id = "lcd",
+ .clock_mcde_id = "mcde",
+};
+
+struct platform_device ux500_mcde_device = {
+ .name = "mcde",
+ .id = -1,
+ .dev = {
+ .release = dev_release_noop,
+ .platform_data = &mcde_pdata,
+ },
+ .num_resources = ARRAY_SIZE(mcde_resources),
+ .resource = mcde_resources,
+};
+
+
+
+
diff --git a/arch/arm/mach-ux500/mloader_helper.c b/arch/arm/mach-ux500/mloader_helper.c
new file mode 100644
index 00000000000..4d5816f9ab3
--- /dev/null
+++ b/arch/arm/mach-ux500/mloader_helper.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors: Jonas Aaberg <jonas.aberg@stericsson.com>
+ * Paer-Olof Haakansson <par-olof.hakansson@stericsson.com>
+ * for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/slab.h>
+
+static ssize_t mloader_sysfs_addr(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+static ssize_t mloader_sysfs_finalize(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+
+static DEVICE_ATTR(addr, S_IRUSR|S_IRGRP, mloader_sysfs_addr, NULL);
+static DEVICE_ATTR(finalize, S_IWUSR, NULL, mloader_sysfs_finalize);
+
+static unsigned int bootargs_memmap_modem_start;
+static unsigned int bootargs_memmap_modem_total_size;
+
+static unsigned int mloader_helper_shm_total_size;
+module_param_named(shm_total_size, mloader_helper_shm_total_size, uint, 0600);
+MODULE_PARM_DESC(shm_total_size, "Total Size of SHM shared memory");
+
+static int __init bootargs_memmap(char *str)
+{
+ char *start_val_str;
+
+ bootargs_memmap_modem_total_size = simple_strtoul(str, NULL, 0);
+
+ start_val_str = strchr(str, '$');
+
+ if (start_val_str == NULL)
+ return -EINVAL;
+
+ bootargs_memmap_modem_start = simple_strtoul(start_val_str + 1, NULL, 0);
+
+ return 1;
+}
+__setup("memmap=", bootargs_memmap);
+
+static int __init bootargs_shm_total_size(char *str)
+{
+ mloader_helper_shm_total_size = simple_strtoul(str, NULL, 0);
+
+ return 1;
+}
+__setup(" mloader_helper.shm_total_size=", bootargs_shm_total_size);
+
+static int __exit mloader_remove(struct platform_device *pdev)
+{
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_addr.attr);
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_finalize.attr);
+
+ return 0;
+}
+
+
+static struct platform_driver mloader_driver = {
+ .driver = {
+ .name = "mloader_helper",
+ },
+ .remove = __exit_p(mloader_remove),
+};
+
+struct mloader_helper {
+ struct work_struct work;
+ struct platform_device *pdev;
+};
+
+static void mloader_clean_up(struct work_struct *work)
+{
+ struct mloader_helper *m = container_of(work,
+ struct mloader_helper,
+ work);
+
+ /* Remove this module */
+ platform_device_unregister(m->pdev);
+
+ platform_driver_unregister(&mloader_driver);
+ kfree(m);
+
+}
+
+static ssize_t mloader_sysfs_addr(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0x%x 0x%x 0x%x\n",
+ bootargs_memmap_modem_start,
+ bootargs_memmap_modem_total_size,
+ mloader_helper_shm_total_size);
+}
+
+static ssize_t mloader_sysfs_finalize(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mloader_helper *m;
+
+ m = kmalloc(sizeof(struct mloader_helper), GFP_KERNEL);
+
+ m->pdev = container_of(dev,
+ struct platform_device,
+ dev);
+
+ INIT_WORK(&m->work, mloader_clean_up);
+
+ /* The module can not remove itself while being in a sysfs function,
+ * it has to use a workqueue.
+ */
+ schedule_work(&m->work);
+
+ return count;
+}
+
+static void mloader_release(struct device *dev)
+{
+ /* Nothing to release */
+}
+
+static int __init mloader_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ pdev->dev.release = mloader_release;
+
+ ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_addr.attr);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_finalize.attr);
+
+ if (ret) {
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_addr.attr);
+ return ret;
+ }
+
+ return 0;
+
+}
+
+static int __init mloader_init(void)
+{
+/*
+ * mLoader_helper for Fairbanks. It exports the physical
+ * address where the modem side ELF should be located in a sysfs
+ * file to make it available for a user space utility.
+ * When the mLoader utility has picked up these settings, this module is no
+ * longer needed and can be removed by writing to sysfs finalize.
+ *
+ * The modem side should be loaded via mmap'ed /dev/mem
+ *
+ */
+
+ return platform_driver_probe(&mloader_driver, mloader_probe);
+}
+module_init(mloader_init);
+
+
+static void __exit mloader_exit(void)
+{
+ platform_driver_unregister(&mloader_driver);
+}
+module_exit(mloader_exit);
+
+MODULE_AUTHOR("Jonas Aaberg <jonas.aberg@stericsson.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-ux500/modem_irq.c b/arch/arm/mach-ux500/modem_irq.c
new file mode 100644
index 00000000000..3187f887116
--- /dev/null
+++ b/arch/arm/mach-ux500/modem_irq.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
+ * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#define MODEM_INTCON_BASE_ADDR 0xBFFD3000
+#define MODEM_INTCON_SIZE 0xFFF
+
+#define DEST_IRQ41_OFFSET 0x2A4
+#define DEST_IRQ43_OFFSET 0x2AC
+#define DEST_IRQ45_OFFSET 0x2B4
+
+#define PRIO_IRQ41_OFFSET 0x6A4
+#define PRIO_IRQ43_OFFSET 0x6AC
+#define PRIO_IRQ45_OFFSET 0x6B4
+
+#define ALLOW_IRQ_OFFSET 0x104
+
+#define MODEM_INTCON_CPU_NBR 0x1
+#define MODEM_INTCON_PRIO_HIGH 0x0
+
+#define MODEM_INTCON_ALLOW_IRQ41 0x0200
+#define MODEM_INTCON_ALLOW_IRQ43 0x0800
+#define MODEM_INTCON_ALLOW_IRQ45 0x2000
+
+#define MODEM_IRQ_REG_OFFSET 0x4
+
+struct modem_irq {
+ void __iomem *modem_intcon_base;
+};
+
+
+static void setup_modem_intcon(void __iomem *modem_intcon_base)
+{
+ /* IC_DESTINATION_BASE_ARRAY - Which CPU to receive the IRQ */
+ writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ41_OFFSET);
+ writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ43_OFFSET);
+ writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ45_OFFSET);
+
+ /* IC_PRIORITY_BASE_ARRAY - IRQ priority in modem IRQ controller */
+ writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ41_OFFSET);
+ writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ43_OFFSET);
+ writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ45_OFFSET);
+
+ /* IC_ALLOW_ARRAY - IRQ enable */
+ writel(MODEM_INTCON_ALLOW_IRQ41 |
+ MODEM_INTCON_ALLOW_IRQ43 |
+ MODEM_INTCON_ALLOW_IRQ45,
+ modem_intcon_base + ALLOW_IRQ_OFFSET);
+}
+
+static irqreturn_t modem_cpu_irq_handler(int irq, void *data)
+{
+ int real_irq;
+ int virt_irq;
+ struct modem_irq *mi = (struct modem_irq *)data;
+
+ /* Read modem side IRQ number from modem IRQ controller */
+ real_irq = readl(mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET) & 0xFF;
+ virt_irq = IRQ_MODEM_EVENTS_BASE + real_irq;
+
+ pr_debug("modem_irq: Worker read addr 0x%X and got value 0x%X "
+ "which will be 0x%X (%d) which translates to "
+ "virtual IRQ 0x%X (%d)!\n",
+ (u32)mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET,
+ real_irq,
+ real_irq & 0xFF,
+ real_irq & 0xFF,
+ virt_irq,
+ virt_irq);
+
+ if (virt_irq != 0)
+ generic_handle_irq(virt_irq);
+
+ pr_debug("modem_irq: Done handling virtual IRQ %d!\n", virt_irq);
+
+ return IRQ_HANDLED;
+}
+
+static void create_virtual_irq(int irq, struct irq_chip *modem_irq_chip)
+{
+ set_irq_chip(irq, modem_irq_chip);
+ set_irq_handler(irq, handle_simple_irq);
+ set_irq_flags(irq, IRQF_VALID);
+
+ pr_debug("modem_irq: Created virtual IRQ %d\n", irq);
+}
+
+static int modem_irq_init(void)
+{
+ int err;
+ static struct irq_chip modem_irq_chip;
+ struct modem_irq *mi;
+
+ pr_info("modem_irq: Set up IRQ handler for incoming modem IRQ %d\n",
+ IRQ_DB5500_MODEM);
+
+ mi = kmalloc(sizeof(struct modem_irq), GFP_KERNEL);
+ if (!mi) {
+ pr_err("modem_irq: Could not allocate device\n");
+ return -ENOMEM;
+ }
+
+ mi->modem_intcon_base =
+ ioremap(MODEM_INTCON_BASE_ADDR, MODEM_INTCON_SIZE);
+ pr_debug("modem_irq: ioremapped modem_intcon_base from "
+ "phy 0x%x to virt 0x%x\n", MODEM_INTCON_BASE_ADDR,
+ (u32)mi->modem_intcon_base);
+
+ setup_modem_intcon(mi->modem_intcon_base);
+
+ modem_irq_chip = dummy_irq_chip;
+ modem_irq_chip.name = "modem_irq";
+
+ /* Create the virtual IRQ:s needed */
+ create_virtual_irq(MBOX_PAIR0_VIRT_IRQ, &modem_irq_chip);
+ create_virtual_irq(MBOX_PAIR1_VIRT_IRQ, &modem_irq_chip);
+ create_virtual_irq(MBOX_PAIR2_VIRT_IRQ, &modem_irq_chip);
+
+ err = request_threaded_irq(IRQ_DB5500_MODEM, NULL,
+ modem_cpu_irq_handler, IRQF_ONESHOT,
+ "modem_irq", mi);
+ if (err)
+ pr_err("modem_irq: Could not register IRQ %d\n",
+ IRQ_DB5500_MODEM);
+
+ return 0;
+}
+
+arch_initcall(modem_irq_init);
diff --git a/arch/arm/mach-ux500/musb_db8500.c b/arch/arm/mach-ux500/musb_db8500.c
new file mode 100644
index 00000000000..18ea1156118
--- /dev/null
+++ b/arch/arm/mach-ux500/musb_db8500.c
@@ -0,0 +1,750 @@
+/*
+ * Copyright (C) 2009 ST Ericsson.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/usb/musb.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/ab8500.h>
+#include <mach/musb_db8500.h>
+
+#define AB8500_MAIN_WDOG_CTRL_REG 0x01
+#define AB8500_REGU_VUSB_CTRL_REG 0x82
+#define AB8500_USB_LINE_STAT_REG 0x80
+#define AB8500_USB_LINE_CTRL1_REG 0x81
+#define AB8500_USB_LINE_CTRL2_REG 0x82
+#define AB8500_USB_LINE_CTRL3_REG 0x83
+#define AB8500_USB_LINE_CTRL4_REG 0x84
+#define AB8500_USB_LINE_CTRL5_REG 0x85
+#define AB8500_USB_OTG_CTRL_REG 0x87
+#define AB8500_USB_OTG_STAT_REG 0x88
+#define AB8500_USB_OTG_STAT_REG 0x88
+#define AB8500_USB_CTRL_SPARE_REG 0x89
+#define AB8500_USB_PHY_CTRL_REG 0x8A /*only in Cut1.0*/
+/* Introduced in v2 */
+#define AB8500_USB_ADP_CTRL_REG 0x93
+
+#define AB8500_IT_MASK2_REG 0x41
+#define AB8500_IT_MASK12_REG 0x4B
+#define AB8500_IT_MASK20_REG 0x53
+#define AB8500_IT_MASK21_REG 0x54
+#define AB8500_IT_SOURCE2_REG 0x01
+#define AB8500_IT_SOURCE20_REG 0x13
+
+#ifdef CONFIG_REGULATOR
+#include <linux/regulator/consumer.h>
+struct regulator *musb_vape_supply, *musb_vbus_supply;
+#endif
+
+int boot_time_flag = USB_DISABLE;
+static struct completion usb_link_status_update;
+
+struct device *device;
+
+int irq_host_insert;
+int irq_host_remove;
+int irq_device_insert;
+int irq_device_remove;
+int irq_link_status_update;
+/*
+ * work queue for USB cable insertion processing
+ */
+static struct work_struct usb_host_insert;
+static struct work_struct usb_device_insert;
+static struct workqueue_struct *usb_cable_wq;
+
+static void usb_host_insert_work(struct work_struct *work);
+static void usb_device_insert_work(struct work_struct *work);
+
+/**
+ * stm_musb_states - Different states of musb_chip
+ *
+ * Used for USB cable plug-in state machine
+ */
+enum stm_musb_states {
+ USB_IDLE,
+ USB_DEVICE,
+ USB_HOST,
+};
+enum stm_musb_states stm_musb_curr_state = USB_IDLE;
+
+void musb_set_session(void);
+
+/**
+ * usb_kick_watchdog() - Kick the watch dog timer
+ *
+ * This function used to Kick the watch dog timer
+ */
+void usb_kick_watchdog(void)
+{
+ int ab8500_rev;
+
+ ab8500_rev = abx500_get_chip_id(device);
+ if (ab8500_rev < 0)
+ dev_err(device, "get chip id failed\n");
+ if ((ab8500_rev == AB8500_REV_11)
+ || (ab8500_rev == AB8500_REV_20)) {
+ abx500_set_register_interruptible(device,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WDOG_CTRL_REG,
+ AB8500_MAIN_WATCHDOG_ENABLE);
+ udelay(WATCHDOG_DELAY_US);
+ abx500_set_register_interruptible(device,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WDOG_CTRL_REG,
+ (AB8500_MAIN_WATCHDOG_ENABLE
+ | AB8500_MAIN_WATCHDOG_KICK));
+ udelay(WATCHDOG_DELAY_US);
+ abx500_set_register_interruptible(device,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WDOG_CTRL_REG,
+ AB8500_MAIN_WATCHDOG_DISABLE);
+ udelay(WATCHDOG_DELAY_US);
+ } else if (ab8500_rev == AB8500_REV_10) {
+ abx500_set_register_interruptible(device,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WDOG_CTRL_REG,
+ AB8500_MAIN_WATCHDOG_ENABLE);
+ abx500_set_register_interruptible(device,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WDOG_CTRL_REG,
+ (AB8500_MAIN_WATCHDOG_ENABLE
+ | AB8500_MAIN_WATCHDOG_KICK));
+ mdelay(WATCHDOG_DELAY);
+ abx500_set_register_interruptible(device,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WDOG_CTRL_REG,
+ AB8500_MAIN_WATCHDOG_DISABLE);
+ mdelay(WATCHDOG_DELAY);
+ }
+}
+/**
+ * usb_host_phy_en() - for enabling the 5V to usb host
+ * @enable: to enabling the Phy for host.
+ *
+ * This function used to set the voltage for USB host mode
+ */
+void usb_host_phy_en(int enable)
+{
+ u8 ab8500_rev;
+ int ret;
+ u8 val = 0;
+ u16 res;
+
+ ab8500_rev = abx500_get_chip_id(device);
+ if (ab8500_rev < 0)
+ dev_err(device, "get chip id failed\n");
+ if (ab8500_rev == AB8500_REV_20) {
+ if (enable == USB_ENABLE) {
+ if (boot_time_flag != USB_ENABLE) {
+ /* Generally On getting the VBUS
+ * rising edge/ID pin detect
+ * interrupt, within 250ms,
+ * the register UsbLineStatus
+ * is updated with valid data.
+ * So, in this case, 400ms is
+ * considered for timeout.
+ */
+ res = wait_for_completion_timeout(
+ &usb_link_status_update,
+ 400);
+ WARN_ON(!res);
+ }
+ ret = abx500_get_register_interruptible(device,
+ AB8500_USB, AB8500_USB_LINE_STAT_REG, &val);
+ if (ret < 0)
+ dev_err(device, "Read USB_LINE failed\n");
+ /* Get the USB type */
+ val = (val >> 3) & 0x0F;
+ if (val == USB_LINK_HM_IDGND) {
+ #ifdef CONFIG_REGULATOR
+ regulator_set_optimum_mode(
+ musb_vape_supply,
+ 1);
+ #endif
+ /* Enable the PHY */
+ abx500_set_register_interruptible(device,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_HOST_ENABLE);
+ }
+ } else { /* enable == USB_DISABLE */
+ if (boot_time_flag)
+ boot_time_flag = USB_DISABLE;
+
+ #ifdef CONFIG_REGULATOR
+ regulator_set_optimum_mode(musb_vape_supply, 0);
+ #endif
+ abx500_set_register_interruptible(device, AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_HOST_DISABLE);
+ }
+ } else if ((ab8500_rev == AB8500_REV_10)
+ || (ab8500_rev == AB8500_REV_11)) {
+ if (enable == USB_ENABLE) {
+ if (boot_time_flag) {
+ abx500_set_register_interruptible(device,
+ AB8500_REGU_CTRL1,
+ AB8500_REGU_VUSB_CTRL_REG,
+ AB8500_VBUS_ENABLE);
+ abx500_set_register_interruptible(device,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_HOST_ENABLE);
+ } else {
+ #ifdef CONFIG_REGULATOR
+ regulator_enable(musb_vbus_supply);
+ regulator_set_optimum_mode(musb_vape_supply, 1);
+ #else
+ abx500_set_register_interruptible(device,
+ AB8500_REGU_CTRL1,
+ AB8500_REGU_VUSB_CTRL_REG,
+ AB8500_VBUS_ENABLE);
+ #endif
+ abx500_set_register_interruptible(device,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_HOST_ENABLE);
+ }
+ } else {
+ if (boot_time_flag) {
+ abx500_set_register_interruptible(device,
+ AB8500_REGU_CTRL1,
+ AB8500_REGU_VUSB_CTRL_REG,
+ AB8500_VBUS_DISABLE);
+ abx500_set_register_interruptible(device,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_HOST_DISABLE);
+ boot_time_flag = USB_DISABLE;
+ } else {
+ #ifdef CONFIG_REGULATOR
+ regulator_disable(musb_vbus_supply);
+ regulator_set_optimum_mode(musb_vape_supply, 0);
+ #else
+ abx500_set_register_interruptible(device,
+ AB8500_REGU_CTRL1,
+ AB8500_REGU_VUSB_CTRL_REG,
+ AB8500_VBUS_DISABLE);
+ #endif
+ abx500_set_register_interruptible(device,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_HOST_DISABLE);
+ }
+ }
+ }
+}
+/**
+ * usb_host_insert_handler() - Detect the USB host cable insertion
+ *
+ * This function used to detect the USB host cable insertion.
+ */
+static irqreturn_t usb_host_insert_handler(int irq, void *data)
+{
+ int ab8500_rev;
+
+ if (stm_musb_curr_state == USB_IDLE) {
+ stm_musb_curr_state = USB_HOST;
+ ab8500_rev = abx500_get_chip_id(device);
+ if (ab8500_rev < 0) {
+ dev_err(device, "get chip id failed\n");
+ return ab8500_rev;
+ }
+ if ((ab8500_rev == AB8500_REV_10)
+ || (ab8500_rev == AB8500_REV_11)) {
+ usb_host_phy_en(USB_ENABLE);
+ musb_set_session();
+ } else if (ab8500_rev == AB8500_REV_20) {
+ init_completion(&usb_link_status_update);
+ /* schedule a thread to handle insert */
+ queue_work(usb_cable_wq, &usb_host_insert);
+ }
+ }
+ return IRQ_HANDLED;
+}
+/**
+ * usb_host_remove_handler() - Removed the USB host cable
+ *
+ * This function used to detect the USB host cable removed.
+ */
+static irqreturn_t usb_host_remove_handler(int irq, void *data)
+{
+ int ab8500_rev;
+ if (stm_musb_curr_state == USB_HOST) {
+ stm_musb_curr_state = USB_IDLE;
+ ab8500_rev = abx500_get_chip_id(device);
+ if (ab8500_rev < 0) {
+ dev_err(device, "get chip id failed\n");
+ return ab8500_rev;
+ }
+ if (ab8500_rev == AB8500_REV_20)
+ init_completion(&usb_link_status_update);
+
+ usb_host_phy_en(USB_DISABLE);
+ }
+ return IRQ_HANDLED;
+}
+/**
+ * usb_device_phy_en() - for enabling the 5V to usb gadget
+ * @enable: to enabling the Phy for device.
+ *
+ * This function used to set the voltage for USB gadget mode.
+ */
+void usb_device_phy_en(int enable)
+{
+ int ab8500_rev;
+ int ret;
+ u8 val = 0;
+ u16 res = 0;
+
+ ab8500_rev = abx500_get_chip_id(device);
+ if (ab8500_rev < 0)
+ dev_err(device, "get chip id failed\n");
+ if (ab8500_rev == AB8500_REV_20) {
+ if (enable == USB_ENABLE) {
+ usb_kick_watchdog();
+ if (boot_time_flag != USB_ENABLE) {
+ /* Generally On getting the VBUS rising
+ * edge/ID pin detect interrupt, within
+ * 250ms, the register UsbLineStatus/charge
+ * Detect complete is updated with valid data.
+ * So, in this case, 400ms is considered for
+ * timeout.
+ */
+ res = wait_for_completion_timeout
+ (&usb_link_status_update,
+ 400);
+ WARN_ON(!res);
+ }
+ ret = abx500_get_register_interruptible(device,
+ AB8500_USB, AB8500_USB_LINE_STAT_REG, &val);
+ if (ret < 0)
+ dev_err(device, "Read USB_LINE failed\n");
+ /* Get the USB type */
+ val = (val >> 3) & 0x0F;
+ if ((val >= USB_LINK_STD_HOST_NC)
+ && (val <= USB_LINK_HOST_CHG_HS_CHIRP)) {
+ abx500_set_register_interruptible(device,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_DEVICE_ENABLE);
+ #ifdef CONFIG_REGULATOR
+ regulator_set_optimum_mode(
+ musb_vape_supply,
+ 1);
+ #endif
+ }
+ } else { /* enable == USB_DISABLE */
+ if (boot_time_flag)
+ boot_time_flag = USB_DISABLE;
+
+ abx500_set_register_interruptible(device,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_DEVICE_DISABLE);
+ #ifdef CONFIG_REGULATOR
+ regulator_set_optimum_mode(musb_vape_supply,
+ 0);
+ #endif
+ }
+ } else if ((ab8500_rev == AB8500_REV_10)
+ || (ab8500_rev == AB8500_REV_11)) {
+ if (enable == USB_ENABLE) {
+ usb_kick_watchdog();
+ if (boot_time_flag) {
+ abx500_set_register_interruptible(device,
+ AB8500_REGU_CTRL1,
+ AB8500_REGU_VUSB_CTRL_REG,
+ AB8500_VBUS_ENABLE);
+ abx500_set_register_interruptible(device,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_DEVICE_ENABLE);
+ } else {
+ #ifdef CONFIG_REGULATOR
+ regulator_set_optimum_mode(musb_vape_supply, 1);
+ #endif
+ abx500_set_register_interruptible(device,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_DEVICE_ENABLE);
+ }
+ } else {
+ if (boot_time_flag) {
+ abx500_set_register_interruptible(device,
+ AB8500_REGU_CTRL1,
+ AB8500_REGU_VUSB_CTRL_REG,
+ AB8500_VBUS_DISABLE);
+ abx500_set_register_interruptible(device,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_DEVICE_DISABLE);
+ boot_time_flag = USB_DISABLE;
+ } else {
+ #ifdef CONFIG_REGULATOR
+ regulator_disable(musb_vbus_supply);
+ regulator_set_optimum_mode(musb_vape_supply, 0);
+ #else
+ abx500_set_register_interruptible(device,
+ AB8500_REGU_CTRL1,
+ AB8500_REGU_VUSB_CTRL_REG,
+ AB8500_VBUS_DISABLE);
+ #endif
+ abx500_set_register_interruptible(device,
+ AB8500_USB,
+ AB8500_USB_PHY_CTRL_REG,
+ AB8500_USB_DEVICE_DISABLE);
+ }
+ }
+ }
+}
+/**
+ * usb_device_insert_handler() - for enabling the 5V to usb device
+ *
+ * This function used to set the voltage for USB device mode
+ */
+static irqreturn_t usb_device_insert_handler(int irq, void *data)
+{
+ int ab8500_rev = 0;
+ if (stm_musb_curr_state == USB_IDLE) {
+ stm_musb_curr_state = USB_DEVICE;
+ ab8500_rev = abx500_get_chip_id(device);
+ if (ab8500_rev < 0) {
+ dev_err(device, "get chip id failed\n");
+ return ab8500_rev;
+ }
+ if ((ab8500_rev == AB8500_REV_10)
+ || (ab8500_rev == AB8500_REV_11)) {
+ usb_device_phy_en(USB_ENABLE);
+ } else if (ab8500_rev == AB8500_REV_20) {
+ init_completion(&usb_link_status_update);
+ /* schedule a thread to handle insert */
+ queue_work(usb_cable_wq, &usb_device_insert);
+ }
+ }
+ return IRQ_HANDLED;
+}
+/**
+ * usb_device_remove_handler() - remove the 5V to usb device
+ *
+ * This function used to remove the voltage for USB device mode.
+ */
+static irqreturn_t usb_device_remove_handler(int irq, void *data)
+{
+ int ab8500_rev = 0;
+ if (stm_musb_curr_state == USB_DEVICE) {
+ stm_musb_curr_state = USB_IDLE;
+ ab8500_rev = abx500_get_chip_id(device);
+ if (ab8500_rev < 0) {
+ dev_err(device, "get chip id failed\n");
+ return ab8500_rev;
+ }
+ if (ab8500_rev == AB8500_REV_20)
+ init_completion(&usb_link_status_update);
+
+ usb_device_phy_en(USB_DISABLE);
+ }
+ return IRQ_HANDLED;
+}
+
+/**
+ * usb_link_status_update_handler() - USB Link status update complete
+ *
+ * This function is used to signal the completion of
+ * USB Link status register update
+ */
+static irqreturn_t usb_link_status_update_handler(int irq, void *data)
+{
+ complete(&usb_link_status_update);
+ return IRQ_HANDLED;
+}
+
+/**
+ * musb_phy_en : register USB callback handlers for ab8500
+ * @mode: value for mode.
+ *
+ * This function is used to register USB callback handlers for ab8500.
+ */
+int musb_phy_en(u8 mode)
+{
+ int ab8500_rev;
+ int ret;
+
+ if (!device)
+ return -EINVAL;
+ ab8500_rev = abx500_get_chip_id(device);
+ if (ab8500_rev < 0) {
+ dev_err(device, "get chip id failed\n");
+ return ab8500_rev;
+ }
+
+#ifdef CONFIG_REGULATOR
+ musb_vape_supply = regulator_get(NULL, "v-ape");
+ if (IS_ERR(musb_vape_supply)) {
+ ret = PTR_ERR(musb_vape_supply);
+ return -1;
+ }
+ regulator_enable(musb_vape_supply);
+ /*
+ * When usb cable is not connected, set_optimum to 0 to release any
+ * OPP constraints on the APE domain with respect to the USB client.
+ * This is done to run APE at low power OPP when usb is not used.
+ */
+ regulator_set_optimum_mode(musb_vape_supply, 0);
+
+ if ((ab8500_rev == AB8500_REV_10)
+ || (ab8500_rev == AB8500_REV_11)) {
+ musb_vbus_supply = regulator_get(NULL, "v-bus");
+ if (IS_ERR(musb_vbus_supply)) {
+ ret = PTR_ERR(musb_vbus_supply);
+ return -1;
+ }
+ }
+#endif
+
+ if ((ab8500_rev == AB8500_REV_10)
+ || (ab8500_rev == AB8500_REV_11)
+ || (ab8500_rev == AB8500_REV_20)) {
+ if (mode == MUSB_HOST || mode == MUSB_OTG) {
+ abx500_set_register_interruptible(device,
+ AB8500_INTERRUPT,
+ AB8500_IT_MASK20_REG,
+ AB8500_IT_MASK20_MASK);
+ ret = request_threaded_irq(irq_host_insert, NULL,
+ usb_host_insert_handler,
+ IRQF_SHARED, "usb-host-insert", device);
+ if (ret < 0) {
+ printk(KERN_ERR "failed to set the callback"
+ " handler for usb host"
+ " insertion\n");
+ return ret;
+ }
+ abx500_set_register_interruptible(device,
+ AB8500_INTERRUPT,
+ AB8500_IT_MASK21_REG,
+ AB8500_IT_MASK21_MASK);
+ ret = request_threaded_irq(irq_host_remove, NULL,
+ usb_host_remove_handler,
+ IRQF_SHARED, "usb-host-remove", device);
+ if (ret < 0) {
+ printk(KERN_ERR "failed to set the callback"
+ " handler for usb host"
+ " removal\n");
+ return ret;
+ }
+ if (ab8500_rev == AB8500_REV_20) {
+ /* Enable ADP */
+ abx500_set_register_interruptible(device,
+ AB8500_USB,
+ AB8500_USB_ADP_CTRL_REG,
+ AB8500_USB_ADP_ENABLE);
+ }
+ }
+ if ((mode == MUSB_PERIPHERAL) || (mode == MUSB_OTG)) {
+ abx500_set_register_interruptible(device,
+ AB8500_INTERRUPT,
+ AB8500_IT_MASK2_REG,
+ AB8500_IT_MASK2_MASK);
+ ret = request_threaded_irq(irq_device_insert, NULL,
+ usb_device_insert_handler,
+ IRQF_SHARED, "usb-device-insert", device);
+ if (ret < 0) {
+ printk(KERN_ERR "failed to set the callback"
+ " handler for usb device"
+ " insertion\n");
+ return ret;
+ }
+ ret = request_threaded_irq(irq_device_remove, NULL,
+ usb_device_remove_handler,
+ IRQF_SHARED, "usb-device-remove", device);
+ if (ret < 0) {
+ printk(KERN_ERR "failed to set the callback"
+ " handler for usb host"
+ " removal\n");
+ return ret;
+ }
+ }
+ if (ab8500_rev == AB8500_REV_20) {
+ /* create a thread for work */
+ usb_cable_wq = create_singlethread_workqueue(
+ "usb_cable_wq");
+ if (usb_cable_wq == NULL)
+ return -ENOMEM;
+
+ INIT_WORK(&usb_host_insert, usb_host_insert_work);
+ INIT_WORK(&usb_device_insert, usb_device_insert_work);
+
+ /* Required for Host, Device and OTG mode */
+ init_completion(&usb_link_status_update);
+ abx500_set_register_interruptible(device,
+ AB8500_INTERRUPT,
+ AB8500_IT_MASK12_REG,
+ AB8500_IT_MASK12_MASK);
+ ret = request_threaded_irq(irq_link_status_update,
+ NULL, usb_link_status_update_handler,
+ IRQF_SHARED, "usb-link-status-update", device);
+ if (ret < 0) {
+ printk(KERN_ERR "failed to set the callback"
+ " handler for usb charge"
+ " detect done\n");
+ return ret;
+ }
+ }
+ usb_kick_watchdog();
+ }
+ return 0;
+}
+/**
+ * musb_force_detect : detect the USB cable during boot time.
+ * @mode: value for mode.
+ *
+ * This function is used to detect the USB cable during boot time.
+ */
+int musb_force_detect(u8 mode)
+{
+ int ret;
+ int ab8500_rev;
+ u8 usb_status = 0;
+
+ if (!device)
+ return -EINVAL;
+ ab8500_rev = abx500_get_chip_id(device);
+ if (ab8500_rev < 0) {
+ dev_err(device, "get chip id failed\n");
+ return ab8500_rev;
+ }
+ if ((ab8500_rev == AB8500_REV_10)
+ || (ab8500_rev == AB8500_REV_11)
+ || (ab8500_rev == AB8500_REV_20)) {
+
+ if (mode == MUSB_HOST || mode == MUSB_OTG) {
+ ret = abx500_get_register_interruptible(device,
+ AB8500_INTERRUPT, AB8500_IT_SOURCE20_REG,
+ &usb_status);
+ if (ret < 0) {
+ dev_err(device, "Read IT 20 failed\n");
+ return ret;
+ }
+ if (usb_status & AB8500_SRC_INT_USB_HOST) {
+ boot_time_flag = USB_ENABLE;
+ if (ab8500_rev == AB8500_REV_10)
+ usb_host_phy_en(USB_ENABLE);
+ }
+ }
+ if (mode == MUSB_PERIPHERAL || mode == MUSB_OTG) {
+ ret = abx500_get_register_interruptible(device,
+ AB8500_INTERRUPT, AB8500_IT_SOURCE2_REG,
+ &usb_status);
+ if (ret < 0) {
+ dev_err(device, "Read IT 2 failed\n");
+ return ret;
+ }
+ if (usb_status & AB8500_SRC_INT_USB_DEVICE) {
+ boot_time_flag = USB_ENABLE;
+ usb_device_phy_en(USB_ENABLE);
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * usb_host_insert_work : work handler for host cable insert.
+ * @work: work structure
+ *
+ * This function is used to handle the host cable insert work.
+ */
+static void usb_host_insert_work(struct work_struct *work)
+{
+ usb_host_phy_en(USB_ENABLE);
+ musb_set_session();
+}
+
+/**
+ * usb_device_insert_work : work handler for device cable insert.
+ * @work: work structure
+ *
+ * This function is used to handle the device cable insert work.
+ */
+static void usb_device_insert_work(struct work_struct *work)
+{
+ usb_device_phy_en(USB_ENABLE);
+}
+
+static int __devinit ab8500_musb_probe(struct platform_device *pdev)
+{
+ device = &pdev->dev;
+ irq_host_insert = platform_get_irq_byname(pdev, "ID_WAKEUP_R");
+ if (irq_host_insert < 0) {
+ dev_err(&pdev->dev, "Host insert irq not found, err %d\n",
+ irq_host_insert);
+ return irq_host_insert;
+ }
+
+ irq_host_remove = platform_get_irq_byname(pdev, "ID_WAKEUP_F");
+ if (irq_host_remove < 0) {
+ dev_err(&pdev->dev, "Host remove irq not found, err %d\n",
+ irq_host_remove);
+ return irq_host_remove;
+ }
+
+ irq_device_insert = platform_get_irq_byname(pdev, "VBUS_DET_R");
+ if (irq_device_insert < 0) {
+ dev_err(&pdev->dev, "Device insert irq not found, err %d\n",
+ irq_device_insert);
+ return irq_device_insert;
+ }
+
+ irq_device_remove = platform_get_irq_byname(pdev, "VBUS_DET_F");
+ if (irq_device_remove < 0) {
+ dev_err(&pdev->dev, "Device remove irq not found, err %d\n",
+ irq_device_remove);
+ return irq_device_remove;
+ }
+
+ irq_link_status_update = platform_get_irq_byname(pdev,
+ "USB_LINK_STATUS");
+ if (irq_link_status_update < 0) {
+ dev_err(&pdev->dev, "USB Link status irq not found, err %d\n",
+ irq_link_status_update);
+ return irq_link_status_update;
+ }
+
+ return 0;
+}
+
+static int __devexit ab8500_musb_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver ab8500_musb_driver = {
+ .driver = {
+ .name = "ab8500-usb",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_musb_probe,
+ .remove = __devexit_p(ab8500_musb_remove),
+};
+
+static int __init ab8500_musb_init(void)
+{
+ return platform_driver_register(&ab8500_musb_driver);
+}
+module_init(ab8500_musb_init);
+
+static void __exit ab8500_musb_exit(void)
+{
+ platform_driver_unregister(&ab8500_musb_driver);
+}
+module_exit(ab8500_musb_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-ux500/pins-db5500.h b/arch/arm/mach-ux500/pins-db5500.h
new file mode 100644
index 00000000000..bf50c21fe69
--- /dev/null
+++ b/arch/arm/mach-ux500/pins-db5500.h
@@ -0,0 +1,620 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ */
+
+#ifndef __MACH_DB5500_PINS_H
+#define __MACH_DB5500_PINS_H
+
+#define GPIO0_GPIO PIN_CFG(0, GPIO)
+#define GPIO0_SM_CS3n PIN_CFG(0, ALT_A)
+
+#define GPIO1_GPIO PIN_CFG(1, GPIO)
+#define GPIO1_SM_A3 PIN_CFG(1, ALT_A)
+
+#define GPIO2_GPIO PIN_CFG(2, GPIO)
+#define GPIO2_SM_A4 PIN_CFG(2, ALT_A)
+#define GPIO2_SM_AVD PIN_CFG(2, ALT_B)
+
+#define GPIO3_GPIO PIN_CFG(3, GPIO)
+#define GPIO3_I2C1_SCL PIN_CFG(3, ALT_A)
+
+#define GPIO4_GPIO PIN_CFG(4, GPIO)
+#define GPIO4_I2C1_SDA PIN_CFG(4, ALT_A)
+
+#define GPIO5_GPIO PIN_CFG(5, GPIO)
+#define GPIO5_MC0_DAT0 PIN_CFG(5, ALT_A)
+#define GPIO5_SM_ADQ8 PIN_CFG(5, ALT_B)
+
+#define GPIO6_GPIO PIN_CFG(6, GPIO)
+#define GPIO6_MC0_DAT1 PIN_CFG(6, ALT_A)
+#define GPIO6_SM_ADQ0 PIN_CFG(6, ALT_B)
+
+#define GPIO7_GPIO PIN_CFG(7, GPIO)
+#define GPIO7_MC0_DAT2 PIN_CFG(7, ALT_A)
+#define GPIO7_SM_ADQ9 PIN_CFG(7, ALT_B)
+
+#define GPIO8_GPIO PIN_CFG(8, GPIO)
+#define GPIO8_MC0_DAT3 PIN_CFG(8, ALT_A)
+#define GPIO8_SM_ADQ1 PIN_CFG(8, ALT_B)
+
+#define GPIO9_GPIO PIN_CFG(9, GPIO)
+#define GPIO9_MC0_DAT4 PIN_CFG(9, ALT_A)
+#define GPIO9_SM_ADQ10 PIN_CFG(9, ALT_B)
+
+#define GPIO10_GPIO PIN_CFG(10, GPIO)
+#define GPIO10_MC0_DAT5 PIN_CFG(10, ALT_A)
+#define GPIO10_SM_ADQ2 PIN_CFG(10, ALT_B)
+
+#define GPIO11_GPIO PIN_CFG(11, GPIO)
+#define GPIO11_MC0_DAT6 PIN_CFG(11, ALT_A)
+#define GPIO11_SM_ADQ11 PIN_CFG(11, ALT_B)
+
+#define GPIO12_GPIO PIN_CFG(12, GPIO)
+#define GPIO12_MC0_DAT7 PIN_CFG(12, ALT_A)
+#define GPIO12_SM_ADQ3 PIN_CFG(12, ALT_B)
+
+#define GPIO13_GPIO PIN_CFG(13, GPIO)
+#define GPIO13_MC0_CMD PIN_CFG(13, ALT_A)
+#define GPIO13_SM_BUSY0n PIN_CFG(13, ALT_B)
+#define GPIO13_SM_WAIT0n PIN_CFG(13, ALT_C)
+
+#define GPIO14_GPIO PIN_CFG(14, GPIO)
+#define GPIO14_MC0_CLK PIN_CFG(14, ALT_A)
+#define GPIO14_SM_CS1n PIN_CFG(14, ALT_B)
+#define GPIO14_SM_CKO PIN_CFG(14, ALT_C)
+
+#define GPIO15_GPIO PIN_CFG(15, GPIO)
+#define GPIO15_SM_A5 PIN_CFG(15, ALT_A)
+#define GPIO15_SM_CLE PIN_CFG(15, ALT_B)
+
+#define GPIO16_GPIO PIN_CFG(16, GPIO)
+#define GPIO16_MC2_CMD PIN_CFG(16, ALT_A)
+#define GPIO16_SM_OEn PIN_CFG(16, ALT_B)
+
+#define GPIO17_GPIO PIN_CFG(17, GPIO)
+#define GPIO17_MC2_CLK PIN_CFG(17, ALT_A)
+#define GPIO17_SM_WEn PIN_CFG(17, ALT_B)
+
+#define GPIO18_GPIO PIN_CFG(18, GPIO)
+#define GPIO18_SM_A6 PIN_CFG(18, ALT_A)
+#define GPIO18_SM_ALE PIN_CFG(18, ALT_B)
+#define GPIO18_SM_AVDn PIN_CFG(18, ALT_C)
+
+#define GPIO19_GPIO PIN_CFG(19, GPIO)
+#define GPIO19_MC2_DAT1 PIN_CFG(19, ALT_A)
+#define GPIO19_SM_ADQ4 PIN_CFG(19, ALT_B)
+
+#define GPIO20_GPIO PIN_CFG(20, GPIO)
+#define GPIO20_MC2_DAT3 PIN_CFG(20, ALT_A)
+#define GPIO20_SM_ADQ5 PIN_CFG(20, ALT_B)
+
+#define GPIO21_GPIO PIN_CFG(21, GPIO)
+#define GPIO21_MC2_DAT5 PIN_CFG(21, ALT_A)
+#define GPIO21_SM_ADQ6 PIN_CFG(21, ALT_B)
+
+#define GPIO22_GPIO PIN_CFG(22, GPIO)
+#define GPIO22_MC2_DAT7 PIN_CFG(22, ALT_A)
+#define GPIO22_SM_ADQ7 PIN_CFG(22, ALT_B)
+
+#define GPIO23_GPIO PIN_CFG(23, GPIO)
+#define GPIO23_MC2_DAT0 PIN_CFG(23, ALT_A)
+#define GPIO23_SM_ADQ12 PIN_CFG(23, ALT_B)
+#define GPIO23_MC0_DAT1 PIN_CFG(23, ALT_C)
+
+#define GPIO24_GPIO PIN_CFG(24, GPIO)
+#define GPIO24_MC2_DAT2 PIN_CFG(24, ALT_A)
+#define GPIO24_SM_ADQ13 PIN_CFG(24, ALT_B)
+#define GPIO24_MC0_DAT3 PIN_CFG(24, ALT_C)
+
+#define GPIO25_GPIO PIN_CFG(25, GPIO)
+#define GPIO25_MC2_DAT4 PIN_CFG(25, ALT_A)
+#define GPIO25_SM_ADQ14 PIN_CFG(25, ALT_B)
+#define GPIO25_MC0_CMD PIN_CFG(25, ALT_C)
+
+#define GPIO26_GPIO PIN_CFG(26, GPIO)
+#define GPIO26_MC2_DAT6 PIN_CFG(26, ALT_A)
+#define GPIO26_SM_ADQ15 PIN_CFG(26, ALT_B)
+
+#define GPIO27_GPIO PIN_CFG(27, GPIO)
+#define GPIO27_SM_CS0n PIN_CFG(27, ALT_A)
+#define GPIO27_SM_PS0n PIN_CFG(27, ALT_B)
+
+#define GPIO28_GPIO PIN_CFG(28, GPIO)
+#define GPIO28_U0_TXD PIN_CFG(28, ALT_A)
+#define GPIO28_SM_A0 PIN_CFG(28, ALT_B)
+
+#define GPIO29_GPIO PIN_CFG(29, GPIO)
+#define GPIO29_U0_RXD PIN_CFG(29, ALT_A)
+#define GPIO29_SM_A1 PIN_CFG(29, ALT_B)
+#define GPIO29_PWM_0 PIN_CFG(29, ALT_C)
+
+#define GPIO30_GPIO PIN_CFG(30, GPIO)
+#define GPIO30_MC0_DAT5 PIN_CFG(30, ALT_A)
+#define GPIO30_SM_A2 PIN_CFG(30, ALT_B)
+#define GPIO30_PWM_1 PIN_CFG(30, ALT_C)
+
+#define GPIO31_GPIO PIN_CFG(31, GPIO)
+#define GPIO31_MC0_DAT7 PIN_CFG(31, ALT_A)
+#define GPIO31_SM_CS2n PIN_CFG(31, ALT_B)
+#define GPIO31_PWM_2 PIN_CFG(31, ALT_C)
+
+#define GPIO32_GPIO PIN_CFG(32, GPIO)
+#define GPIO32_MSP0_TCK PIN_CFG(32, ALT_A)
+#define GPIO32_ACCI2S0_SCK PIN_CFG(32, ALT_B)
+
+#define GPIO33_GPIO PIN_CFG(33, GPIO)
+#define GPIO33_MSP0_TFS PIN_CFG(33, ALT_A)
+#define GPIO33_ACCI2S0_WS PIN_CFG(33, ALT_B)
+
+#define GPIO34_GPIO PIN_CFG(34, GPIO)
+#define GPIO34_MSP0_TXD PIN_CFG(34, ALT_A)
+#define GPIO34_ACCI2S0_DLD PIN_CFG(34, ALT_B)
+
+#define GPIO35_GPIO PIN_CFG(35, GPIO)
+#define GPIO35_MSP0_RXD PIN_CFG(35, ALT_A)
+#define GPIO35_ACCI2S0_ULD PIN_CFG(35, ALT_B)
+
+#define GPIO64_GPIO PIN_CFG(64, GPIO)
+#define GPIO64_USB_DAT0 PIN_CFG(64, ALT_A)
+#define GPIO64_U0_TXD PIN_CFG(64, ALT_B)
+
+#define GPIO65_GPIO PIN_CFG(65, GPIO)
+#define GPIO65_USB_DAT1 PIN_CFG(65, ALT_A)
+#define GPIO65_U0_RXD PIN_CFG(65, ALT_B)
+
+#define GPIO66_GPIO PIN_CFG(66, GPIO)
+#define GPIO66_USB_DAT2 PIN_CFG(66, ALT_A)
+
+#define GPIO67_GPIO PIN_CFG(67, GPIO)
+#define GPIO67_USB_DAT3 PIN_CFG(67, ALT_A)
+
+#define GPIO68_GPIO PIN_CFG(68, GPIO)
+#define GPIO68_USB_DAT4 PIN_CFG(68, ALT_A)
+
+#define GPIO69_GPIO PIN_CFG(69, GPIO)
+#define GPIO69_USB_DAT5 PIN_CFG(69, ALT_A)
+
+#define GPIO70_GPIO PIN_CFG(70, GPIO)
+#define GPIO70_USB_DAT6 PIN_CFG(70, ALT_A)
+
+#define GPIO71_GPIO PIN_CFG(71, GPIO)
+#define GPIO71_USB_DAT7 PIN_CFG(71, ALT_A)
+
+#define GPIO72_GPIO PIN_CFG(72, GPIO)
+#define GPIO72_USB_STP PIN_CFG(72, ALT_A)
+
+#define GPIO73_GPIO PIN_CFG(73, GPIO)
+#define GPIO73_USB_DIR PIN_CFG(73, ALT_A)
+
+#define GPIO74_GPIO PIN_CFG(74, GPIO)
+#define GPIO74_USB_NXT PIN_CFG(74, ALT_A)
+
+#define GPIO75_GPIO PIN_CFG(75, GPIO)
+#define GPIO75_USB_XCLK PIN_CFG(75, ALT_A)
+
+#define GPIO76_GPIO PIN_CFG(76, GPIO)
+
+#define GPIO77_GPIO PIN_CFG(77, GPIO)
+#define GPIO77_ACCTX_ON PIN_CFG(77, ALT_A)
+
+#define GPIO78_GPIO PIN_CFG(78, GPIO)
+#define GPIO78_IRQn PIN_CFG(78, ALT_A)
+
+#define GPIO79_GPIO PIN_CFG(79, GPIO)
+#define GPIO79_ACCSIM_Clk PIN_CFG(79, ALT_A)
+
+#define GPIO80_GPIO PIN_CFG(80, GPIO)
+#define GPIO80_ACCSIM_Da PIN_CFG(80, ALT_A)
+
+#define GPIO81_GPIO PIN_CFG(81, GPIO)
+#define GPIO81_ACCSIM_Reset PIN_CFG(81, ALT_A)
+
+#define GPIO82_GPIO PIN_CFG(82, GPIO)
+#define GPIO82_ACCSIM_DDir PIN_CFG(82, ALT_A)
+
+#define GPIO96_GPIO PIN_CFG(96, GPIO)
+#define GPIO96_MSP1_TCK PIN_CFG(96, ALT_A)
+#define GPIO96_PRCMU_DEBUG3 PIN_CFG(96, ALT_B)
+#define GPIO96_PRCMU_DEBUG7 PIN_CFG(96, ALT_C)
+
+#define GPIO97_GPIO PIN_CFG(97, GPIO)
+#define GPIO97_MSP1_TFS PIN_CFG(97, ALT_A)
+#define GPIO97_PRCMU_DEBUG2 PIN_CFG(97, ALT_B)
+#define GPIO97_PRCMU_DEBUG6 PIN_CFG(97, ALT_C)
+
+#define GPIO98_GPIO PIN_CFG(98, GPIO)
+#define GPIO98_MSP1_TXD PIN_CFG(98, ALT_A)
+#define GPIO98_PRCMU_DEBUG1 PIN_CFG(98, ALT_B)
+#define GPIO98_PRCMU_DEBUG5 PIN_CFG(98, ALT_C)
+
+#define GPIO99_GPIO PIN_CFG(99, GPIO)
+#define GPIO99_MSP1_RXD PIN_CFG(99, ALT_A)
+#define GPIO99_PRCMU_DEBUG0 PIN_CFG(99, ALT_B)
+#define GPIO99_PRCMU_DEBUG4 PIN_CFG(99, ALT_C)
+
+#define GPIO100_GPIO PIN_CFG(100, GPIO)
+#define GPIO100_I2C0_SCL PIN_CFG(100, ALT_A)
+
+#define GPIO101_GPIO PIN_CFG(101, GPIO)
+#define GPIO101_I2C0_SDA PIN_CFG(101, ALT_A)
+
+#define GPIO128_GPIO PIN_CFG(128, GPIO)
+#define GPIO128_KP_I0 PIN_CFG(128, ALT_A)
+#define GPIO128_BUSMON_D0 PIN_CFG(128, ALT_B)
+
+#define GPIO129_GPIO PIN_CFG(129, GPIO)
+#define GPIO129_KP_O0 PIN_CFG(129, ALT_A)
+#define GPIO129_BUSMON_D1 PIN_CFG(129, ALT_B)
+
+#define GPIO130_GPIO PIN_CFG(130, GPIO)
+#define GPIO130_KP_I1 PIN_CFG(130, ALT_A)
+#define GPIO130_BUSMON_D2 PIN_CFG(130, ALT_B)
+
+#define GPIO131_GPIO PIN_CFG(131, GPIO)
+#define GPIO131_KP_O1 PIN_CFG(131, ALT_A)
+#define GPIO131_BUSMON_D3 PIN_CFG(131, ALT_B)
+
+#define GPIO132_GPIO PIN_CFG(132, GPIO)
+#define GPIO132_KP_I2 PIN_CFG(132, ALT_A)
+#define GPIO132_ETM_D15 PIN_CFG(132, ALT_B)
+#define GPIO132_STMAPE_CLK PIN_CFG(132, ALT_C)
+
+#define GPIO133_GPIO PIN_CFG(133, GPIO)
+#define GPIO133_KP_O2 PIN_CFG(133, ALT_A)
+#define GPIO133_ETM_D14 PIN_CFG(133, ALT_B)
+#define GPIO133_U0_RXD PIN_CFG(133, ALT_C)
+
+#define GPIO134_GPIO PIN_CFG(134, GPIO)
+#define GPIO134_KP_I3 PIN_CFG(134, ALT_A)
+#define GPIO134_ETM_D13 PIN_CFG(134, ALT_B)
+#define GPIO134_STMAPE_DAT0 PIN_CFG(134, ALT_C)
+
+#define GPIO135_GPIO PIN_CFG(135, GPIO)
+#define GPIO135_KP_O3 PIN_CFG(135, ALT_A)
+#define GPIO135_ETM_D12 PIN_CFG(135, ALT_B)
+#define GPIO135_STMAPE_DAT1 PIN_CFG(135, ALT_C)
+
+#define GPIO136_GPIO PIN_CFG(136, GPIO)
+#define GPIO136_KP_I4 PIN_CFG(136, ALT_A)
+#define GPIO136_ETM_D11 PIN_CFG(136, ALT_B)
+#define GPIO136_STMAPE_DAT2 PIN_CFG(136, ALT_C)
+
+#define GPIO137_GPIO PIN_CFG(137, GPIO)
+#define GPIO137_KP_O4 PIN_CFG(137, ALT_A)
+#define GPIO137_ETM_D10 PIN_CFG(137, ALT_B)
+#define GPIO137_STMAPE_DAT3 PIN_CFG(137, ALT_C)
+
+#define GPIO138_GPIO PIN_CFG(138, GPIO)
+#define GPIO138_KP_I5 PIN_CFG(138, ALT_A)
+#define GPIO138_ETM_D9 PIN_CFG(138, ALT_B)
+#define GPIO138_U0_TXD PIN_CFG(138, ALT_C)
+
+#define GPIO139_GPIO PIN_CFG(139, GPIO)
+#define GPIO139_KP_O5 PIN_CFG(139, ALT_A)
+#define GPIO139_ETM_D8 PIN_CFG(139, ALT_B)
+#define GPIO139_BUSMON_D11 PIN_CFG(139, ALT_C)
+
+#define GPIO140_GPIO PIN_CFG(140, GPIO)
+#define GPIO140_KP_I6 PIN_CFG(140, ALT_A)
+#define GPIO140_ETM_D7 PIN_CFG(140, ALT_B)
+#define GPIO140_STMAPE_CLK PIN_CFG(140, ALT_C)
+
+#define GPIO141_GPIO PIN_CFG(141, GPIO)
+#define GPIO141_KP_O6 PIN_CFG(141, ALT_A)
+#define GPIO141_ETM_D6 PIN_CFG(141, ALT_B)
+#define GPIO141_U0_RXD PIN_CFG(141, ALT_C)
+
+#define GPIO142_GPIO PIN_CFG(142, GPIO)
+#define GPIO142_KP_I7 PIN_CFG(142, ALT_A)
+#define GPIO142_ETM_D5 PIN_CFG(142, ALT_B)
+#define GPIO142_STMAPE_DAT0 PIN_CFG(142, ALT_C)
+
+#define GPIO143_GPIO PIN_CFG(143, GPIO)
+#define GPIO143_KP_O7 PIN_CFG(143, ALT_A)
+#define GPIO143_ETM_D4 PIN_CFG(143, ALT_B)
+#define GPIO143_STMAPE_DAT1 PIN_CFG(143, ALT_C)
+
+#define GPIO144_GPIO PIN_CFG(144, GPIO)
+#define GPIO144_I2C3_SCL PIN_CFG(144, ALT_A)
+#define GPIO144_ETM_D3 PIN_CFG(144, ALT_B)
+#define GPIO144_STMAPE_DAT2 PIN_CFG(144, ALT_C)
+
+#define GPIO145_GPIO PIN_CFG(145, GPIO)
+#define GPIO145_I2C3_SDA PIN_CFG(145, ALT_A)
+#define GPIO145_ETM_D2 PIN_CFG(145, ALT_B)
+#define GPIO145_STMAPE_DAT3 PIN_CFG(145, ALT_C)
+
+#define GPIO146_GPIO PIN_CFG(146, GPIO)
+#define GPIO146_PWM_0 PIN_CFG(146, ALT_A)
+#define GPIO146_ETM_D1 PIN_CFG(146, ALT_B)
+
+#define GPIO147_GPIO PIN_CFG(147, GPIO)
+#define GPIO147_PWM_1 PIN_CFG(147, ALT_A)
+#define GPIO147_ETM_D0 PIN_CFG(147, ALT_B)
+
+#define GPIO148_GPIO PIN_CFG(148, GPIO)
+#define GPIO148_PWM_2 PIN_CFG(148, ALT_A)
+#define GPIO148_ETM_CLK PIN_CFG(148, ALT_B)
+
+#define GPIO160_GPIO PIN_CFG(160, GPIO)
+#define GPIO160_CLKOUT_REQn PIN_CFG(160, ALT_A)
+
+#define GPIO161_GPIO PIN_CFG(161, GPIO)
+#define GPIO161_CLKOUT_0 PIN_CFG(161, ALT_A)
+
+#define GPIO162_GPIO PIN_CFG(162, GPIO)
+#define GPIO162_CLKOUT_1 PIN_CFG(162, ALT_A)
+
+#define GPIO163_GPIO PIN_CFG(163, GPIO)
+
+#define GPIO164_GPIO PIN_CFG(164, GPIO)
+#define GPIO164_GPS_START PIN_CFG(164, ALT_A)
+
+#define GPIO165_GPIO PIN_CFG(165, GPIO)
+#define GPIO165_SPI1_CS2n PIN_CFG(165, ALT_A)
+#define GPIO165_U3_RXD PIN_CFG(165, ALT_B)
+#define GPIO165_BUSMON_D20 PIN_CFG(165, ALT_C)
+
+#define GPIO166_GPIO PIN_CFG(166, GPIO)
+#define GPIO166_SPI1_CS1n PIN_CFG(166, ALT_A)
+#define GPIO166_U3_TXD PIN_CFG(166, ALT_B)
+#define GPIO166_BUSMON_D21 PIN_CFG(166, ALT_C)
+
+#define GPIO167_GPIO PIN_CFG(167, GPIO)
+#define GPIO167_SPI1_CS0n PIN_CFG(167, ALT_A)
+#define GPIO167_U3_RTSn PIN_CFG(167, ALT_B)
+#define GPIO167_BUSMON_D22 PIN_CFG(167, ALT_C)
+
+#define GPIO168_GPIO PIN_CFG(168, GPIO)
+#define GPIO168_SPI1_RXD PIN_CFG(168, ALT_A)
+#define GPIO168_U3_CTSn PIN_CFG(168, ALT_B)
+#define GPIO168_BUSMON_D23 PIN_CFG(168, ALT_C)
+
+#define GPIO169_GPIO PIN_CFG(169, GPIO)
+#define GPIO169_SPI1_TXD PIN_CFG(169, ALT_A)
+#define GPIO169_DDR_RC PIN_CFG(169, ALT_B)
+#define GPIO169_BUSMON_D24 PIN_CFG(169, ALT_C)
+
+#define GPIO170_GPIO PIN_CFG(170, GPIO)
+#define GPIO170_SPI1_CLK PIN_CFG(170, ALT_A)
+
+#define GPIO171_GPIO PIN_CFG(171, GPIO)
+#define GPIO171_MC3_DAT0 PIN_CFG(171, ALT_A)
+#define GPIO171_SPI3_RXD PIN_CFG(171, ALT_B)
+#define GPIO171_BUSMON_D25 PIN_CFG(171, ALT_C)
+
+#define GPIO172_GPIO PIN_CFG(172, GPIO)
+#define GPIO172_MC3_DAT1 PIN_CFG(172, ALT_A)
+#define GPIO172_SPI3_CS1n PIN_CFG(172, ALT_B)
+#define GPIO172_BUSMON_D26 PIN_CFG(172, ALT_C)
+
+#define GPIO173_GPIO PIN_CFG(173, GPIO)
+#define GPIO173_MC3_DAT2 PIN_CFG(173, ALT_A)
+#define GPIO173_SPI3_CS2n PIN_CFG(173, ALT_B)
+#define GPIO173_BUSMON_D27 PIN_CFG(173, ALT_C)
+
+#define GPIO174_GPIO PIN_CFG(174, GPIO)
+#define GPIO174_MC3_DAT3 PIN_CFG(174, ALT_A)
+#define GPIO174_SPI3_CS0n PIN_CFG(174, ALT_B)
+#define GPIO174_BUSMON_D28 PIN_CFG(174, ALT_C)
+
+#define GPIO175_GPIO PIN_CFG(175, GPIO)
+#define GPIO175_MC3_CMD PIN_CFG(175, ALT_A)
+#define GPIO175_SPI3_TXD PIN_CFG(175, ALT_B)
+#define GPIO175_BUSMON_D29 PIN_CFG(175, ALT_C)
+
+#define GPIO176_GPIO PIN_CFG(176, GPIO)
+#define GPIO176_MC3_CLK PIN_CFG(176, ALT_A)
+#define GPIO176_SPI3_CLK PIN_CFG(176, ALT_B)
+
+#define GPIO177_GPIO PIN_CFG(177, GPIO)
+#define GPIO177_U2_RXD PIN_CFG(177, ALT_A)
+#define GPIO177_I2C3_SCL PIN_CFG(177, ALT_B)
+#define GPIO177_BUSMON_D30 PIN_CFG(177, ALT_C)
+
+#define GPIO178_GPIO PIN_CFG(178, GPIO)
+#define GPIO178_U2_TXD PIN_CFG(178, ALT_A)
+#define GPIO178_I2C3_SDA PIN_CFG(178, ALT_B)
+#define GPIO178_BUSMON_D31 PIN_CFG(178, ALT_C)
+
+#define GPIO179_GPIO PIN_CFG(179, GPIO)
+#define GPIO179_U2_CTSn PIN_CFG(179, ALT_A)
+#define GPIO179_U3_RXD PIN_CFG(179, ALT_B)
+#define GPIO179_BUSMON_D32 PIN_CFG(179, ALT_C)
+
+#define GPIO180_GPIO PIN_CFG(180, GPIO)
+#define GPIO180_U2_RTSn PIN_CFG(180, ALT_A)
+#define GPIO180_U3_TXD PIN_CFG(180, ALT_B)
+#define GPIO180_BUSMON_D33 PIN_CFG(180, ALT_C)
+
+#define GPIO185_GPIO PIN_CFG(185, GPIO)
+#define GPIO185_SPI3_CS2n PIN_CFG(185, ALT_A)
+#define GPIO185_MC4_DAT0 PIN_CFG(185, ALT_B)
+
+#define GPIO186_GPIO PIN_CFG(186, GPIO)
+#define GPIO186_SPI3_CS1n PIN_CFG(186, ALT_A)
+#define GPIO186_MC4_DAT1 PIN_CFG(186, ALT_B)
+
+#define GPIO187_GPIO PIN_CFG(187, GPIO)
+#define GPIO187_SPI3_CS0n PIN_CFG(187, ALT_A)
+#define GPIO187_MC4_DAT2 PIN_CFG(187, ALT_B)
+
+#define GPIO188_GPIO PIN_CFG(188, GPIO)
+#define GPIO188_SPI3_RXD PIN_CFG(188, ALT_A)
+#define GPIO188_MC4_DAT3 PIN_CFG(188, ALT_B)
+
+#define GPIO189_GPIO PIN_CFG(189, GPIO)
+#define GPIO189_SPI3_TXD PIN_CFG(189, ALT_A)
+#define GPIO189_MC4_CMD PIN_CFG(189, ALT_B)
+
+#define GPIO190_GPIO PIN_CFG(190, GPIO)
+#define GPIO190_SPI3_CLK PIN_CFG(190, ALT_A)
+#define GPIO190_MC4_CLK PIN_CFG(190, ALT_B)
+
+#define GPIO191_GPIO PIN_CFG(191, GPIO)
+#define GPIO191_MC1_DAT0 PIN_CFG(191, ALT_A)
+#define GPIO191_MC4_DAT4 PIN_CFG(191, ALT_B)
+#define GPIO191_STMAPE_DAT0 PIN_CFG(191, ALT_C)
+
+#define GPIO192_GPIO PIN_CFG(192, GPIO)
+#define GPIO192_MC1_DAT1 PIN_CFG(192, ALT_A)
+#define GPIO192_MC4_DAT5 PIN_CFG(192, ALT_B)
+#define GPIO192_STMAPE_DAT1 PIN_CFG(192, ALT_C)
+
+#define GPIO193_GPIO PIN_CFG(193, GPIO)
+#define GPIO193_MC1_DAT2 PIN_CFG(193, ALT_A)
+#define GPIO193_MC4_DAT6 PIN_CFG(193, ALT_B)
+#define GPIO193_STMAPE_DAT2 PIN_CFG(193, ALT_C)
+
+#define GPIO194_GPIO PIN_CFG(194, GPIO)
+#define GPIO194_MC1_DAT3 PIN_CFG(194, ALT_A)
+#define GPIO194_MC4_DAT7 PIN_CFG(194, ALT_B)
+#define GPIO194_STMAPE_DAT3 PIN_CFG(194, ALT_C)
+
+#define GPIO195_GPIO PIN_CFG(195, GPIO)
+#define GPIO195_MC1_CLK PIN_CFG(195, ALT_A)
+#define GPIO195_STMAPE_CLK PIN_CFG(195, ALT_B)
+#define GPIO195_BUSMON_CLK PIN_CFG(195, ALT_C)
+
+#define GPIO196_GPIO PIN_CFG(196, GPIO)
+#define GPIO196_MC1_CMD PIN_CFG(196, ALT_A)
+#define GPIO196_U0_RXD PIN_CFG(196, ALT_B)
+#define GPIO196_BUSMON_D38 PIN_CFG(196, ALT_C)
+
+#define GPIO197_GPIO PIN_CFG(197, GPIO)
+#define GPIO197_MC1_CMDDIR PIN_CFG(197, ALT_A)
+#define GPIO197_BUSMON_D39 PIN_CFG(197, ALT_B)
+
+#define GPIO198_GPIO PIN_CFG(198, GPIO)
+#define GPIO198_MC1_FBCLK PIN_CFG(198, ALT_A)
+
+#define GPIO199_GPIO PIN_CFG(199, GPIO)
+#define GPIO199_MC1_DAT0DIR PIN_CFG(199, ALT_A)
+#define GPIO199_BUSMON_D40 PIN_CFG(199, ALT_B)
+
+#define GPIO200_GPIO PIN_CFG(200, GPIO)
+#define GPIO200_U1_TXD PIN_CFG(200, ALT_A)
+#define GPIO200_ACCU0_RTSn PIN_CFG(200, ALT_B)
+
+#define GPIO201_GPIO PIN_CFG(201, GPIO)
+#define GPIO201_U1_RXD PIN_CFG(201, ALT_A)
+#define GPIO201_ACCU0_CTSn PIN_CFG(201, ALT_B)
+
+#define GPIO202_GPIO PIN_CFG(202, GPIO)
+#define GPIO202_U1_CTSn PIN_CFG(202, ALT_A)
+#define GPIO202_ACCU0_RXD PIN_CFG(202, ALT_B)
+
+#define GPIO203_GPIO PIN_CFG(203, GPIO)
+#define GPIO203_U1_RTSn PIN_CFG(203, ALT_A)
+#define GPIO203_ACCU0_TXD PIN_CFG(203, ALT_B)
+
+#define GPIO204_GPIO PIN_CFG(204, GPIO)
+#define GPIO204_SPI0_CS2n PIN_CFG(204, ALT_A)
+#define GPIO204_ACCGPIO_000 PIN_CFG(204, ALT_B)
+#define GPIO204_LCD_VSI1 PIN_CFG(204, ALT_C)
+
+#define GPIO205_GPIO PIN_CFG(205, GPIO)
+#define GPIO205_SPI0_CS1n PIN_CFG(205, ALT_A)
+#define GPIO205_ACCGPIO_001 PIN_CFG(205, ALT_B)
+#define GPIO205_LCD_D3 PIN_CFG(205, ALT_C)
+
+#define GPIO206_GPIO PIN_CFG(206, GPIO)
+#define GPIO206_SPI0_CS0n PIN_CFG(206, ALT_A)
+#define GPIO206_ACCGPIO_002 PIN_CFG(206, ALT_B)
+#define GPIO206_LCD_D2 PIN_CFG(206, ALT_C)
+
+#define GPIO207_GPIO PIN_CFG(207, GPIO)
+#define GPIO207_SPI0_RXD PIN_CFG(207, ALT_A)
+#define GPIO207_ACCGPIO_003 PIN_CFG(207, ALT_B)
+#define GPIO207_LCD_D1 PIN_CFG(207, ALT_C)
+
+#define GPIO208_GPIO PIN_CFG(208, GPIO)
+#define GPIO208_SPI0_TXD PIN_CFG(208, ALT_A)
+#define GPIO208_ACCGPIO_004 PIN_CFG(208, ALT_B)
+#define GPIO208_LCD_D0 PIN_CFG(208, ALT_C)
+
+#define GPIO209_GPIO PIN_CFG(209, GPIO)
+#define GPIO209_SPI0_CLK PIN_CFG(209, ALT_A)
+#define GPIO209_ACCGPIO_005 PIN_CFG(209, ALT_B)
+#define GPIO209_LCD_CLK PIN_CFG(209, ALT_C)
+
+#define GPIO210_GPIO PIN_CFG(210, GPIO)
+#define GPIO210_LCD_VSO PIN_CFG(210, ALT_A)
+#define GPIO210_PRCMU_PWRCTRL1 PIN_CFG(210, ALT_B)
+
+#define GPIO211_GPIO PIN_CFG(211, GPIO)
+#define GPIO211_LCD_VSI0 PIN_CFG(211, ALT_A)
+#define GPIO211_PRCMU_PWRCTRL2 PIN_CFG(211, ALT_B)
+
+#define GPIO212_GPIO PIN_CFG(212, GPIO)
+#define GPIO212_SPI2_CS2n PIN_CFG(212, ALT_A)
+#define GPIO212_LCD_HSO PIN_CFG(212, ALT_B)
+
+#define GPIO213_GPIO PIN_CFG(213, GPIO)
+#define GPIO213_SPI2_CS1n PIN_CFG(213, ALT_A)
+#define GPIO213_LCD_DE PIN_CFG(213, ALT_B)
+#define GPIO213_BUSMON_D16 PIN_CFG(213, ALT_C)
+
+#define GPIO214_GPIO PIN_CFG(214, GPIO)
+#define GPIO214_SPI2_CS0n PIN_CFG(214, ALT_A)
+#define GPIO214_LCD_D7 PIN_CFG(214, ALT_B)
+#define GPIO214_BUSMON_D17 PIN_CFG(214, ALT_C)
+
+#define GPIO215_GPIO PIN_CFG(215, GPIO)
+#define GPIO215_SPI2_RXD PIN_CFG(215, ALT_A)
+#define GPIO215_LCD_D6 PIN_CFG(215, ALT_B)
+#define GPIO215_BUSMON_D18 PIN_CFG(215, ALT_C)
+
+#define GPIO216_GPIO PIN_CFG(216, GPIO)
+#define GPIO216_SPI2_CLK PIN_CFG(216, ALT_A)
+#define GPIO216_LCD_D5 PIN_CFG(216, ALT_B)
+
+#define GPIO217_GPIO PIN_CFG(217, GPIO)
+#define GPIO217_SPI2_TXD PIN_CFG(217, ALT_A)
+#define GPIO217_LCD_D4 PIN_CFG(217, ALT_B)
+#define GPIO217_BUSMON_D19 PIN_CFG(217, ALT_C)
+
+#define GPIO218_GPIO PIN_CFG(218, GPIO)
+#define GPIO218_I2C2_SCL PIN_CFG(218, ALT_A)
+#define GPIO218_LCD_VSO PIN_CFG(218, ALT_B)
+
+#define GPIO219_GPIO PIN_CFG(219, GPIO)
+#define GPIO219_I2C2_SDA PIN_CFG(219, ALT_A)
+#define GPIO219_LCD_D3 PIN_CFG(219, ALT_B)
+
+#define GPIO220_GPIO PIN_CFG(220, GPIO)
+#define GPIO220_MSP2_TCK PIN_CFG(220, ALT_A)
+#define GPIO220_LCD_D2 PIN_CFG(220, ALT_B)
+
+#define GPIO221_GPIO PIN_CFG(221, GPIO)
+#define GPIO221_MSP2_TFS PIN_CFG(221, ALT_A)
+#define GPIO221_LCD_D1 PIN_CFG(221, ALT_B)
+
+#define GPIO222_GPIO PIN_CFG(222, GPIO)
+#define GPIO222_MSP2_TXD PIN_CFG(222, ALT_A)
+#define GPIO222_LCD_D0 PIN_CFG(222, ALT_B)
+
+#define GPIO223_GPIO PIN_CFG(223, GPIO)
+#define GPIO223_MSP2_RXD PIN_CFG(223, ALT_A)
+#define GPIO223_LCD_CLK PIN_CFG(223, ALT_B)
+
+#define GPIO224_GPIO PIN_CFG(224, GPIO)
+#define GPIO224_PRCMU_PWRCTRL0 PIN_CFG(224, ALT_A)
+#define GPIO224_LCD_VSI1 PIN_CFG(224, ALT_B)
+
+#define GPIO225_GPIO PIN_CFG(225, GPIO)
+#define GPIO225_PRCMU_PWRCTRL1 PIN_CFG(225, ALT_A)
+#define GPIO225_IRDA_RXD PIN_CFG(225, ALT_B)
+
+#define GPIO226_GPIO PIN_CFG(226, GPIO)
+#define GPIO226_PRCMU_PWRCTRL2 PIN_CFG(226, ALT_A)
+#define GPIO226_IRRC_DAT PIN_CFG(226, ALT_B)
+
+#define GPIO227_GPIO PIN_CFG(227, GPIO)
+#define GPIO227_IRRC_DAT PIN_CFG(227, ALT_A)
+#define GPIO227_IRDA_TXD PIN_CFG(227, ALT_B)
+
+#endif
diff --git a/arch/arm/mach-ux500/pins-db8500.h b/arch/arm/mach-ux500/pins-db8500.h
new file mode 100644
index 00000000000..f923764ee16
--- /dev/null
+++ b/arch/arm/mach-ux500/pins-db8500.h
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ */
+
+#ifndef __MACH_PINS_DB8500_H
+#define __MACH_PINS_DB8500_H
+
+/*
+ * TODO: Eventually encode all non-board specific pull up/down configuration
+ * here.
+ */
+
+#define GPIO0_GPIO PIN_CFG(0, GPIO)
+#define GPIO0_U0_CTSn PIN_CFG(0, ALT_A)
+#define GPIO0_TRIG_OUT PIN_CFG(0, ALT_B)
+#define GPIO0_IP_TDO PIN_CFG(0, ALT_C)
+
+#define GPIO1_GPIO PIN_CFG(1, GPIO)
+#define GPIO1_U0_RTSn PIN_CFG(1, ALT_A)
+#define GPIO1_TRIG_IN PIN_CFG(1, ALT_B)
+#define GPIO1_IP_TDI PIN_CFG(1, ALT_C)
+
+#define GPIO2_GPIO PIN_CFG(2, GPIO)
+#define GPIO2_U0_RXD PIN_CFG(2, ALT_A)
+#define GPIO2_NONE PIN_CFG(2, ALT_B)
+#define GPIO2_IP_TMS PIN_CFG(2, ALT_C)
+
+#define GPIO3_GPIO PIN_CFG(3, GPIO)
+#define GPIO3_U0_TXD PIN_CFG(3, ALT_A)
+#define GPIO3_NONE PIN_CFG(3, ALT_B)
+#define GPIO3_IP_TCK PIN_CFG(3, ALT_C)
+
+#define GPIO4_GPIO PIN_CFG(4, GPIO)
+#define GPIO4_U1_RXD PIN_CFG(4, ALT_A)
+#define GPIO4_I2C4_SCL PIN_CFG_PULL(4, ALT_B, UP)
+#define GPIO4_IP_TRSTn PIN_CFG(4, ALT_C)
+
+#define GPIO5_GPIO PIN_CFG(5, GPIO)
+#define GPIO5_U1_TXD PIN_CFG(5, ALT_A)
+#define GPIO5_I2C4_SDA PIN_CFG_PULL(5, ALT_B, UP)
+#define GPIO5_IP_GPIO6 PIN_CFG(5, ALT_C)
+
+#define GPIO6_GPIO PIN_CFG(6, GPIO)
+#define GPIO6_U1_CTSn PIN_CFG(6, ALT_A)
+#define GPIO6_I2C1_SCL PIN_CFG_PULL(6, ALT_B, UP)
+#define GPIO6_IP_GPIO0 PIN_CFG(6, ALT_C)
+
+#define GPIO7_GPIO PIN_CFG(7, GPIO)
+#define GPIO7_U1_RTSn PIN_CFG(7, ALT_A)
+#define GPIO7_I2C1_SDA PIN_CFG_PULL(7, ALT_B, UP)
+#define GPIO7_IP_GPIO1 PIN_CFG(7, ALT_C)
+
+#define GPIO8_GPIO PIN_CFG(8, GPIO)
+#define GPIO8_IPI2C_SDA PIN_CFG_PULL(8, ALT_A, UP)
+#define GPIO8_I2C2_SDA PIN_CFG_PULL(8, ALT_B, UP)
+
+#define GPIO9_GPIO PIN_CFG(9, GPIO)
+#define GPIO9_IPI2C_SCL PIN_CFG_PULL(9, ALT_A, UP)
+#define GPIO9_I2C2_SCL PIN_CFG_PULL(9, ALT_B, UP)
+
+#define GPIO10_GPIO PIN_CFG(10, GPIO)
+#define GPIO10_IPI2C_SDA PIN_CFG_PULL(10, ALT_A, UP)
+#define GPIO10_I2C2_SDA PIN_CFG_PULL(10, ALT_B, UP)
+#define GPIO10_IP_GPIO3 PIN_CFG(10, ALT_C)
+
+#define GPIO11_GPIO PIN_CFG(11, GPIO)
+#define GPIO11_IPI2C_SCL PIN_CFG_PULL(11, ALT_A, UP)
+#define GPIO11_I2C2_SCL PIN_CFG_PULL(11, ALT_B, UP)
+#define GPIO11_IP_GPIO2 PIN_CFG(11, ALT_C)
+
+#define GPIO12_GPIO PIN_CFG(12, GPIO)
+#define GPIO12_MSP0_TXD PIN_CFG(12, ALT_A)
+#define GPIO12_MSP0_RXD PIN_CFG(12, ALT_B)
+
+#define GPIO13_GPIO PIN_CFG(13, GPIO)
+#define GPIO13_MSP0_TFS PIN_CFG(13, ALT_A)
+
+#define GPIO14_GPIO PIN_CFG(14, GPIO)
+#define GPIO14_MSP0_TCK PIN_CFG(14, ALT_A)
+
+#define GPIO15_GPIO PIN_CFG(15, GPIO)
+#define GPIO15_MSP0_RXD PIN_CFG(15, ALT_A)
+#define GPIO15_MSP0_TXD PIN_CFG(15, ALT_B)
+
+#define GPIO16_GPIO PIN_CFG(16, GPIO)
+#define GPIO16_MSP0_RFS PIN_CFG(16, ALT_A)
+#define GPIO16_I2C1_SCL PIN_CFG_PULL(16, ALT_B, UP)
+#define GPIO16_SLIM0_DAT PIN_CFG(16, ALT_C)
+
+#define GPIO17_GPIO PIN_CFG(17, GPIO)
+#define GPIO17_MSP0_RCK PIN_CFG(17, ALT_A)
+#define GPIO17_I2C1_SDA PIN_CFG_PULL(17, ALT_B, UP)
+#define GPIO17_SLIM0_CLK PIN_CFG(17, ALT_C)
+
+#define GPIO18_GPIO PIN_CFG(18, GPIO)
+#define GPIO18_MC0_CMDDIR PIN_CFG_PULL(18, ALT_A, UP)
+#define GPIO18_U2_RXD PIN_CFG(18, ALT_B)
+#define GPIO18_MS_IEP PIN_CFG(18, ALT_C)
+
+#define GPIO19_GPIO PIN_CFG(19, GPIO)
+#define GPIO19_MC0_DAT0DIR PIN_CFG_PULL(19, ALT_A, UP)
+#define GPIO19_U2_TXD PIN_CFG(19, ALT_B)
+#define GPIO19_MS_DAT0DIR PIN_CFG(19, ALT_C)
+
+#define GPIO20_GPIO PIN_CFG(20, GPIO)
+#define GPIO20_MC0_DAT2DIR PIN_CFG_PULL(20, ALT_A, UP)
+#define GPIO20_UARTMOD_TXD PIN_CFG(20, ALT_B)
+#define GPIO20_IP_TRIGOUT PIN_CFG(20, ALT_C)
+
+#define GPIO21_GPIO PIN_CFG(21, GPIO)
+#define GPIO21_MC0_DAT31DIR PIN_CFG_PULL(21, ALT_A, UP)
+#define GPIO21_MSP0_SCK PIN_CFG(21, ALT_B)
+#define GPIO21_MS_DAT31DIR PIN_CFG(21, ALT_C)
+
+#define GPIO22_GPIO PIN_CFG(22, GPIO)
+#define GPIO22_MC0_FBCLK PIN_CFG_PULL(22, ALT_A, UP)
+#define GPIO22_UARTMOD_RXD PIN_CFG(22, ALT_B)
+#define GPIO22_MS_FBCLK PIN_CFG(22, ALT_C)
+
+#define GPIO23_GPIO PIN_CFG(23, GPIO)
+#define GPIO23_MC0_CLK PIN_CFG_PULL(23, ALT_A, UP)
+#define GPIO23_STMMOD_CLK PIN_CFG(23, ALT_B)
+#define GPIO23_MS_CLK PIN_CFG(23, ALT_C)
+
+#define GPIO24_GPIO PIN_CFG(24, GPIO)
+#define GPIO24_MC0_CMD PIN_CFG_PULL(24, ALT_A, UP)
+#define GPIO24_UARTMOD_RXD PIN_CFG(24, ALT_B)
+#define GPIO24_MS_BS PIN_CFG(24, ALT_C)
+
+#define GPIO25_GPIO PIN_CFG(25, GPIO)
+#define GPIO25_MC0_DAT0 PIN_CFG_PULL(25, ALT_A, UP)
+#define GPIO25_STMMOD_DAT0 PIN_CFG(25, ALT_B)
+#define GPIO25_MS_DAT0 PIN_CFG(25, ALT_C)
+
+#define GPIO26_GPIO PIN_CFG(26, GPIO)
+#define GPIO26_MC0_DAT1 PIN_CFG_PULL(26, ALT_A, UP)
+#define GPIO26_STMMOD_DAT1 PIN_CFG(26, ALT_B)
+#define GPIO26_MS_DAT1 PIN_CFG(26, ALT_C)
+
+#define GPIO27_GPIO PIN_CFG(27, GPIO)
+#define GPIO27_MC0_DAT2 PIN_CFG_PULL(27, ALT_A, UP)
+#define GPIO27_STMMOD_DAT2 PIN_CFG(27, ALT_B)
+#define GPIO27_MS_DAT2 PIN_CFG(27, ALT_C)
+
+#define GPIO28_GPIO PIN_CFG(28, GPIO)
+#define GPIO28_MC0_DAT3 PIN_CFG_PULL(28, ALT_A, UP)
+#define GPIO28_STMMOD_DAT3 PIN_CFG(28, ALT_B)
+#define GPIO28_MS_DAT3 PIN_CFG(28, ALT_C)
+
+#define GPIO29_GPIO PIN_CFG(29, GPIO)
+#define GPIO29_MC0_DAT4 PIN_CFG(29, ALT_A)
+#define GPIO29_SPI3_CLK PIN_CFG(29, ALT_B)
+#define GPIO29_U2_RXD PIN_CFG(29, ALT_C)
+
+#define GPIO30_GPIO PIN_CFG(30, GPIO)
+#define GPIO30_MC0_DAT5 PIN_CFG(30, ALT_A)
+#define GPIO30_SPI3_RXD PIN_CFG(30, ALT_B)
+#define GPIO30_U2_TXD PIN_CFG(30, ALT_C)
+
+#define GPIO31_GPIO PIN_CFG(31, GPIO)
+#define GPIO31_MC0_DAT6 PIN_CFG(31, ALT_A)
+#define GPIO31_SPI3_FRM PIN_CFG(31, ALT_B)
+#define GPIO31_U2_CTSn PIN_CFG(31, ALT_C)
+
+#define GPIO32_GPIO PIN_CFG(32, GPIO)
+#define GPIO32_MC0_DAT7 PIN_CFG(32, ALT_A)
+#define GPIO32_SPI3_TXD PIN_CFG(32, ALT_B)
+#define GPIO32_U2_RTSn PIN_CFG(32, ALT_C)
+
+#define GPIO33_GPIO PIN_CFG(33, GPIO)
+#define GPIO33_MSP1_TXD PIN_CFG(33, ALT_A)
+#define GPIO33_MSP1_RXD PIN_CFG(33, ALT_B)
+#define GPIO33_U0_DTRn PIN_CFG(33, ALT_C)
+
+#define GPIO34_GPIO PIN_CFG(34, GPIO)
+#define GPIO34_MSP1_TFS PIN_CFG(34, ALT_A)
+#define GPIO34_NONE PIN_CFG(34, ALT_B)
+#define GPIO34_U0_DCDn PIN_CFG(34, ALT_C)
+
+#define GPIO35_GPIO PIN_CFG(35, GPIO)
+#define GPIO35_MSP1_TCK PIN_CFG(35, ALT_A)
+#define GPIO35_NONE PIN_CFG(35, ALT_B)
+#define GPIO35_U0_DSRn PIN_CFG(35, ALT_C)
+
+#define GPIO36_GPIO PIN_CFG(36, GPIO)
+#define GPIO36_MSP1_RXD PIN_CFG(36, ALT_A)
+#define GPIO36_MSP1_TXD PIN_CFG(36, ALT_B)
+#define GPIO36_U0_RIn PIN_CFG(36, ALT_C)
+
+#define GPIO64_GPIO PIN_CFG(64, GPIO)
+#define GPIO64_LCDB_DE PIN_CFG(64, ALT_A)
+#define GPIO64_KP_O1 PIN_CFG(64, ALT_B)
+#define GPIO64_IP_GPIO4 PIN_CFG(64, ALT_C)
+
+#define GPIO65_GPIO PIN_CFG(65, GPIO)
+#define GPIO65_LCDB_HSO PIN_CFG(65, ALT_A)
+#define GPIO65_KP_O0 PIN_CFG(65, ALT_B)
+#define GPIO65_IP_GPIO5 PIN_CFG(65, ALT_C)
+
+#define GPIO66_GPIO PIN_CFG(66, GPIO)
+#define GPIO66_LCDB_VSO PIN_CFG(66, ALT_A)
+#define GPIO66_KP_I1 PIN_CFG(66, ALT_B)
+#define GPIO66_IP_GPIO6 PIN_CFG(66, ALT_C)
+
+#define GPIO67_GPIO PIN_CFG(67, GPIO)
+#define GPIO67_LCDB_CLK PIN_CFG(67, ALT_A)
+#define GPIO67_KP_I0 PIN_CFG(67, ALT_B)
+#define GPIO67_IP_GPIO7 PIN_CFG(67, ALT_C)
+
+#define GPIO68_GPIO PIN_CFG(68, GPIO)
+#define GPIO68_LCD_VSI0 PIN_CFG(68, ALT_A)
+#define GPIO68_KP_O7 PIN_CFG(68, ALT_B)
+#define GPIO68_SM_CLE PIN_CFG(68, ALT_C)
+
+#define GPIO69_GPIO PIN_CFG(69, GPIO)
+#define GPIO69_LCD_VSI1 PIN_CFG(69, ALT_A)
+#define GPIO69_KP_I7 PIN_CFG(69, ALT_B)
+#define GPIO69_SM_ALE PIN_CFG(69, ALT_C)
+
+#define GPIO70_GPIO PIN_CFG(70, GPIO)
+#define GPIO70_LCD_D0 PIN_CFG(70, ALT_A)
+#define GPIO70_KP_O5 PIN_CFG(70, ALT_B)
+#define GPIO70_STMAPE_CLK PIN_CFG(70, ALT_C)
+
+#define GPIO71_GPIO PIN_CFG(71, GPIO)
+#define GPIO71_LCD_D1 PIN_CFG(71, ALT_A)
+#define GPIO71_KP_O4 PIN_CFG(71, ALT_B)
+#define GPIO71_STMAPE_DAT3 PIN_CFG(71, ALT_C)
+
+#define GPIO72_GPIO PIN_CFG(72, GPIO)
+#define GPIO72_LCD_D2 PIN_CFG(72, ALT_A)
+#define GPIO72_KP_O3 PIN_CFG(72, ALT_B)
+#define GPIO72_STMAPE_DAT2 PIN_CFG(72, ALT_C)
+
+#define GPIO73_GPIO PIN_CFG(73, GPIO)
+#define GPIO73_LCD_D3 PIN_CFG(73, ALT_A)
+#define GPIO73_KP_O2 PIN_CFG(73, ALT_B)
+#define GPIO73_STMAPE_DAT1 PIN_CFG(73, ALT_C)
+
+#define GPIO74_GPIO PIN_CFG(74, GPIO)
+#define GPIO74_LCD_D4 PIN_CFG(74, ALT_A)
+#define GPIO74_KP_I5 PIN_CFG(74, ALT_B)
+#define GPIO74_STMAPE_DAT0 PIN_CFG(74, ALT_C)
+
+#define GPIO75_GPIO PIN_CFG(75, GPIO)
+#define GPIO75_LCD_D5 PIN_CFG(75, ALT_A)
+#define GPIO75_KP_I4 PIN_CFG(75, ALT_B)
+#define GPIO75_U2_RXD PIN_CFG(75, ALT_C)
+
+#define GPIO76_GPIO PIN_CFG(76, GPIO)
+#define GPIO76_LCD_D6 PIN_CFG(76, ALT_A)
+#define GPIO76_KP_I3 PIN_CFG(76, ALT_B)
+#define GPIO76_U2_TXD PIN_CFG(76, ALT_C)
+
+#define GPIO77_GPIO PIN_CFG(77, GPIO)
+#define GPIO77_LCD_D7 PIN_CFG(77, ALT_A)
+#define GPIO77_KP_I2 PIN_CFG(77, ALT_B)
+#define GPIO77_NONE PIN_CFG(77, ALT_C)
+
+#define GPIO78_GPIO PIN_CFG(78, GPIO)
+#define GPIO78_LCD_D8 PIN_CFG(78, ALT_A)
+#define GPIO78_KP_O6 PIN_CFG(78, ALT_B)
+#define GPIO78_IP_GPIO2 PIN_CFG(78, ALT_C)
+
+#define GPIO79_GPIO PIN_CFG(79, GPIO)
+#define GPIO79_LCD_D9 PIN_CFG(79, ALT_A)
+#define GPIO79_KP_I6 PIN_CFG(79, ALT_B)
+#define GPIO79_IP_GPIO3 PIN_CFG(79, ALT_C)
+
+#define GPIO80_GPIO PIN_CFG(80, GPIO)
+#define GPIO80_LCD_D10 PIN_CFG(80, ALT_A)
+#define GPIO80_KP_SKA0 PIN_CFG(80, ALT_B)
+#define GPIO80_IP_GPIO4 PIN_CFG(80, ALT_C)
+
+#define GPIO81_GPIO PIN_CFG(81, GPIO)
+#define GPIO81_LCD_D11 PIN_CFG(81, ALT_A)
+#define GPIO81_KP_SKB0 PIN_CFG(81, ALT_B)
+#define GPIO81_IP_GPIO5 PIN_CFG(81, ALT_C)
+
+#define GPIO82_GPIO PIN_CFG(82, GPIO)
+#define GPIO82_LCD_D12 PIN_CFG(82, ALT_A)
+#define GPIO82_KP_O5 PIN_CFG(82, ALT_B)
+
+#define GPIO83_GPIO PIN_CFG(83, GPIO)
+#define GPIO83_LCD_D13 PIN_CFG(83, ALT_A)
+#define GPIO83_KP_O4 PIN_CFG(83, ALT_B)
+
+#define GPIO84_GPIO PIN_CFG(84, GPIO)
+#define GPIO84_LCD_D14 PIN_CFG(84, ALT_A)
+#define GPIO84_KP_I5 PIN_CFG(84, ALT_B)
+
+#define GPIO85_GPIO PIN_CFG(85, GPIO)
+#define GPIO85_LCD_D15 PIN_CFG(85, ALT_A)
+#define GPIO85_KP_I4 PIN_CFG(85, ALT_B)
+
+#define GPIO86_GPIO PIN_CFG(86, GPIO)
+#define GPIO86_LCD_D16 PIN_CFG(86, ALT_A)
+#define GPIO86_SM_ADQ0 PIN_CFG(86, ALT_B)
+#define GPIO86_MC5_DAT0 PIN_CFG(86, ALT_C)
+
+#define GPIO87_GPIO PIN_CFG(87, GPIO)
+#define GPIO87_LCD_D17 PIN_CFG(87, ALT_A)
+#define GPIO87_SM_ADQ1 PIN_CFG(87, ALT_B)
+#define GPIO87_MC5_DAT1 PIN_CFG(87, ALT_C)
+
+#define GPIO88_GPIO PIN_CFG(88, GPIO)
+#define GPIO88_LCD_D18 PIN_CFG(88, ALT_A)
+#define GPIO88_SM_ADQ2 PIN_CFG(88, ALT_B)
+#define GPIO88_MC5_DAT2 PIN_CFG(88, ALT_C)
+
+#define GPIO89_GPIO PIN_CFG(89, GPIO)
+#define GPIO89_LCD_D19 PIN_CFG(89, ALT_A)
+#define GPIO89_SM_ADQ3 PIN_CFG(89, ALT_B)
+#define GPIO89_MC5_DAT3 PIN_CFG(89, ALT_C)
+
+#define GPIO90_GPIO PIN_CFG(90, GPIO)
+#define GPIO90_LCD_D20 PIN_CFG(90, ALT_A)
+#define GPIO90_SM_ADQ4 PIN_CFG(90, ALT_B)
+#define GPIO90_MC5_CMD PIN_CFG(90, ALT_C)
+
+#define GPIO91_GPIO PIN_CFG(91, GPIO)
+#define GPIO91_LCD_D21 PIN_CFG(91, ALT_A)
+#define GPIO91_SM_ADQ5 PIN_CFG(91, ALT_B)
+#define GPIO91_MC5_FBCLK PIN_CFG(91, ALT_C)
+
+#define GPIO92_GPIO PIN_CFG(92, GPIO)
+#define GPIO92_LCD_D22 PIN_CFG(92, ALT_A)
+#define GPIO92_SM_ADQ6 PIN_CFG(92, ALT_B)
+#define GPIO92_MC5_CLK PIN_CFG(92, ALT_C)
+
+#define GPIO93_GPIO PIN_CFG(93, GPIO)
+#define GPIO93_LCD_D23 PIN_CFG(93, ALT_A)
+#define GPIO93_SM_ADQ7 PIN_CFG(93, ALT_B)
+#define GPIO93_MC5_DAT4 PIN_CFG(93, ALT_C)
+
+#define GPIO94_GPIO PIN_CFG(94, GPIO)
+#define GPIO94_KP_O7 PIN_CFG(94, ALT_A)
+#define GPIO94_SM_ADVn PIN_CFG(94, ALT_B)
+#define GPIO94_MC5_DAT5 PIN_CFG(94, ALT_C)
+
+#define GPIO95_GPIO PIN_CFG(95, GPIO)
+#define GPIO95_KP_I7 PIN_CFG(95, ALT_A)
+#define GPIO95_SM_CS0n PIN_CFG(95, ALT_B)
+#define GPIO95_SM_PS0n PIN_CFG(95, ALT_C)
+
+#define GPIO96_GPIO PIN_CFG(96, GPIO)
+#define GPIO96_KP_O6 PIN_CFG(96, ALT_A)
+#define GPIO96_SM_OEn PIN_CFG(96, ALT_B)
+#define GPIO96_MC5_DAT6 PIN_CFG(96, ALT_C)
+
+#define GPIO97_GPIO PIN_CFG(97, GPIO)
+#define GPIO97_KP_I6 PIN_CFG(97, ALT_A)
+#define GPIO97_SM_WEn PIN_CFG(97, ALT_B)
+#define GPIO97_MC5_DAT7 PIN_CFG(97, ALT_C)
+
+#define GPIO128_GPIO PIN_CFG(128, GPIO)
+#define GPIO128_MC2_CLK PIN_CFG_PULL(128, ALT_A, UP)
+#define GPIO128_SM_CKO PIN_CFG(128, ALT_B)
+
+#define GPIO129_GPIO PIN_CFG(129, GPIO)
+#define GPIO129_MC2_CMD PIN_CFG_PULL(129, ALT_A, UP)
+#define GPIO129_SM_WAIT0n PIN_CFG(129, ALT_B)
+
+#define GPIO130_GPIO PIN_CFG(130, GPIO)
+#define GPIO130_MC2_FBCLK PIN_CFG_PULL(130, ALT_A, UP)
+#define GPIO130_SM_FBCLK PIN_CFG(130, ALT_B)
+#define GPIO130_MC2_RSTN PIN_CFG(130, ALT_C)
+
+#define GPIO131_GPIO PIN_CFG(131, GPIO)
+#define GPIO131_MC2_DAT0 PIN_CFG_PULL(131, ALT_A, UP)
+#define GPIO131_SM_ADQ8 PIN_CFG(131, ALT_B)
+
+#define GPIO132_GPIO PIN_CFG(132, GPIO)
+#define GPIO132_MC2_DAT1 PIN_CFG_PULL(132, ALT_A, UP)
+#define GPIO132_SM_ADQ9 PIN_CFG(132, ALT_B)
+
+#define GPIO133_GPIO PIN_CFG(133, GPIO)
+#define GPIO133_MC2_DAT2 PIN_CFG_PULL(133, ALT_A, UP)
+#define GPIO133_SM_ADQ10 PIN_CFG(133, ALT_B)
+
+#define GPIO134_GPIO PIN_CFG(134, GPIO)
+#define GPIO134_MC2_DAT3 PIN_CFG_PULL(134, ALT_A, UP)
+#define GPIO134_SM_ADQ11 PIN_CFG(134, ALT_B)
+
+#define GPIO135_GPIO PIN_CFG(135, GPIO)
+#define GPIO135_MC2_DAT4 PIN_CFG_PULL(135, ALT_A, UP)
+#define GPIO135_SM_ADQ12 PIN_CFG(135, ALT_B)
+
+#define GPIO136_GPIO PIN_CFG(136, GPIO)
+#define GPIO136_MC2_DAT5 PIN_CFG_PULL(136, ALT_A, UP)
+#define GPIO136_SM_ADQ13 PIN_CFG(136, ALT_B)
+
+#define GPIO137_GPIO PIN_CFG(137, GPIO)
+#define GPIO137_MC2_DAT6 PIN_CFG_PULL(137, ALT_A, UP)
+#define GPIO137_SM_ADQ14 PIN_CFG(137, ALT_B)
+
+#define GPIO138_GPIO PIN_CFG(138, GPIO)
+#define GPIO138_MC2_DAT7 PIN_CFG_PULL(138, ALT_A, UP)
+#define GPIO138_SM_ADQ15 PIN_CFG(138, ALT_B)
+
+#define GPIO139_GPIO PIN_CFG(139, GPIO)
+#define GPIO139_SSP1_RXD PIN_CFG(139, ALT_A)
+#define GPIO139_SM_WAIT1n PIN_CFG(139, ALT_B)
+#define GPIO139_KP_O8 PIN_CFG(139, ALT_C)
+
+#define GPIO140_GPIO PIN_CFG(140, GPIO)
+#define GPIO140_SSP1_TXD PIN_CFG(140, ALT_A)
+#define GPIO140_IP_GPIO7 PIN_CFG(140, ALT_B)
+#define GPIO140_KP_SKA1 PIN_CFG(140, ALT_C)
+
+#define GPIO141_GPIO PIN_CFG(141, GPIO)
+#define GPIO141_SSP1_CLK PIN_CFG(141, ALT_A)
+#define GPIO141_IP_GPIO2 PIN_CFG(141, ALT_B)
+#define GPIO141_KP_O9 PIN_CFG(141, ALT_C)
+
+#define GPIO142_GPIO PIN_CFG(142, GPIO)
+#define GPIO142_SSP1_FRM PIN_CFG(142, ALT_A)
+#define GPIO142_IP_GPIO3 PIN_CFG(142, ALT_B)
+#define GPIO142_KP_SKB1 PIN_CFG(142, ALT_C)
+
+#define GPIO143_GPIO PIN_CFG(143, GPIO)
+#define GPIO143_SSP0_CLK PIN_CFG(143, ALT_A)
+
+#define GPIO144_GPIO PIN_CFG(144, GPIO)
+#define GPIO144_SSP0_FRM PIN_CFG(144, ALT_A)
+
+#define GPIO145_GPIO PIN_CFG(145, GPIO)
+#define GPIO145_SSP0_RXD PIN_CFG(145, ALT_A)
+
+#define GPIO146_GPIO PIN_CFG(146, GPIO)
+#define GPIO146_SSP0_TXD PIN_CFG(146, ALT_A)
+
+#define GPIO147_GPIO PIN_CFG(147, GPIO)
+#define GPIO147_I2C0_SCL PIN_CFG_PULL(147, ALT_A, UP)
+
+#define GPIO148_GPIO PIN_CFG(148, GPIO)
+#define GPIO148_I2C0_SDA PIN_CFG_PULL(148, ALT_A, UP)
+
+#define GPIO149_GPIO PIN_CFG(149, GPIO)
+#define GPIO149_IP_GPIO0 PIN_CFG(149, ALT_A)
+#define GPIO149_SM_CS1n PIN_CFG(149, ALT_B)
+#define GPIO149_SM_PS1n PIN_CFG(149, ALT_C)
+
+#define GPIO150_GPIO PIN_CFG(150, GPIO)
+#define GPIO150_IP_GPIO1 PIN_CFG(150, ALT_A)
+#define GPIO150_LCDA_CLK PIN_CFG(150, ALT_B)
+
+#define GPIO151_GPIO PIN_CFG(151, GPIO)
+#define GPIO151_KP_SKA0 PIN_CFG(151, ALT_A)
+#define GPIO151_LCD_VSI0 PIN_CFG(151, ALT_B)
+#define GPIO151_KP_O8 PIN_CFG(151, ALT_C)
+
+#define GPIO152_GPIO PIN_CFG(152, GPIO)
+#define GPIO152_KP_SKB0 PIN_CFG(152, ALT_A)
+#define GPIO152_LCD_VSI1 PIN_CFG(152, ALT_B)
+#define GPIO152_KP_O9 PIN_CFG(152, ALT_C)
+
+#define GPIO153_GPIO PIN_CFG(153, GPIO)
+#define GPIO153_KP_I7 PIN_CFG_PULL(153, ALT_A, DOWN)
+#define GPIO153_LCD_D24 PIN_CFG(153, ALT_B)
+#define GPIO153_U2_RXD PIN_CFG(153, ALT_C)
+
+#define GPIO154_GPIO PIN_CFG(154, GPIO)
+#define GPIO154_KP_I6 PIN_CFG_PULL(154, ALT_A, DOWN)
+#define GPIO154_LCD_D25 PIN_CFG(154, ALT_B)
+#define GPIO154_U2_TXD PIN_CFG(154, ALT_C)
+
+#define GPIO155_GPIO PIN_CFG(155, GPIO)
+#define GPIO155_KP_I5 PIN_CFG_PULL(155, ALT_A, DOWN)
+#define GPIO155_LCD_D26 PIN_CFG(155, ALT_B)
+#define GPIO155_STMAPE_CLK PIN_CFG(155, ALT_C)
+
+#define GPIO156_GPIO PIN_CFG(156, GPIO)
+#define GPIO156_KP_I4 PIN_CFG_PULL(156, ALT_A, DOWN)
+#define GPIO156_LCD_D27 PIN_CFG(156, ALT_B)
+#define GPIO156_STMAPE_DAT3 PIN_CFG(156, ALT_C)
+
+#define GPIO157_GPIO PIN_CFG(157, GPIO)
+#define GPIO157_KP_O7 PIN_CFG_PULL(157, ALT_A, UP)
+#define GPIO157_LCD_D28 PIN_CFG(157, ALT_B)
+#define GPIO157_STMAPE_DAT2 PIN_CFG(157, ALT_C)
+
+#define GPIO158_GPIO PIN_CFG(158, GPIO)
+#define GPIO158_KP_O6 PIN_CFG_PULL(158, ALT_A, UP)
+#define GPIO158_LCD_D29 PIN_CFG(158, ALT_B)
+#define GPIO158_STMAPE_DAT1 PIN_CFG(158, ALT_C)
+
+#define GPIO159_GPIO PIN_CFG(159, GPIO)
+#define GPIO159_KP_O5 PIN_CFG_PULL(159, ALT_A, UP)
+#define GPIO159_LCD_D30 PIN_CFG(159, ALT_B)
+#define GPIO159_STMAPE_DAT0 PIN_CFG(159, ALT_C)
+
+#define GPIO160_GPIO PIN_CFG(160, GPIO)
+#define GPIO160_KP_O4 PIN_CFG_PULL(160, ALT_A, UP)
+#define GPIO160_LCD_D31 PIN_CFG(160, ALT_B)
+#define GPIO160_NONE PIN_CFG(160, ALT_C)
+
+#define GPIO161_GPIO PIN_CFG(161, GPIO)
+#define GPIO161_KP_I3 PIN_CFG_PULL(161, ALT_A, DOWN)
+#define GPIO161_LCD_D32 PIN_CFG(161, ALT_B)
+#define GPIO161_UARTMOD_RXD PIN_CFG(161, ALT_C)
+
+#define GPIO162_GPIO PIN_CFG(162, GPIO)
+#define GPIO162_KP_I2 PIN_CFG_PULL(162, ALT_A, DOWN)
+#define GPIO162_LCD_D33 PIN_CFG(162, ALT_B)
+#define GPIO162_UARTMOD_TXD PIN_CFG(162, ALT_C)
+
+#define GPIO163_GPIO PIN_CFG(163, GPIO)
+#define GPIO163_KP_I1 PIN_CFG_PULL(163, ALT_A, DOWN)
+#define GPIO163_LCD_D34 PIN_CFG(163, ALT_B)
+#define GPIO163_STMMOD_CLK PIN_CFG(163, ALT_C)
+
+#define GPIO164_GPIO PIN_CFG(164, GPIO)
+#define GPIO164_KP_I0 PIN_CFG_PULL(164, ALT_A, UP)
+#define GPIO164_LCD_D35 PIN_CFG(164, ALT_B)
+#define GPIO164_STMMOD_DAT3 PIN_CFG(164, ALT_C)
+
+#define GPIO165_GPIO PIN_CFG(165, GPIO)
+#define GPIO165_KP_O3 PIN_CFG_PULL(165, ALT_A, UP)
+#define GPIO165_LCD_D36 PIN_CFG(165, ALT_B)
+#define GPIO165_STMMOD_DAT2 PIN_CFG(165, ALT_C)
+
+#define GPIO166_GPIO PIN_CFG(166, GPIO)
+#define GPIO166_KP_O2 PIN_CFG_PULL(166, ALT_A, UP)
+#define GPIO166_LCD_D37 PIN_CFG(166, ALT_B)
+#define GPIO166_STMMOD_DAT1 PIN_CFG(166, ALT_C)
+
+#define GPIO167_GPIO PIN_CFG(167, GPIO)
+#define GPIO167_KP_O1 PIN_CFG_PULL(167, ALT_A, UP)
+#define GPIO167_LCD_D38 PIN_CFG(167, ALT_B)
+#define GPIO167_STMMOD_DAT0 PIN_CFG(167, ALT_C)
+
+#define GPIO168_GPIO PIN_CFG(168, GPIO)
+#define GPIO168_KP_O0 PIN_CFG_PULL(168, ALT_A, UP)
+#define GPIO168_LCD_D39 PIN_CFG(168, ALT_B)
+#define GPIO168_NONE PIN_CFG(168, ALT_C)
+
+#define GPIO169_GPIO PIN_CFG(169, GPIO)
+#define GPIO169_RF_PURn PIN_CFG(169, ALT_A)
+#define GPIO169_LCDA_DE PIN_CFG(169, ALT_B)
+#define GPIO169_USBSIM_PDC PIN_CFG(169, ALT_C)
+
+#define GPIO170_GPIO PIN_CFG(170, GPIO)
+#define GPIO170_MODEM_STATE PIN_CFG(170, ALT_A)
+#define GPIO170_LCDA_VSO PIN_CFG(170, ALT_B)
+#define GPIO170_KP_SKA1 PIN_CFG(170, ALT_C)
+
+#define GPIO171_GPIO PIN_CFG(171, GPIO)
+#define GPIO171_MODEM_PWREN PIN_CFG(171, ALT_A)
+#define GPIO171_LCDA_HSO PIN_CFG(171, ALT_B)
+#define GPIO171_KP_SKB1 PIN_CFG(171, ALT_C)
+
+#define GPIO192_GPIO PIN_CFG(192, GPIO)
+#define GPIO192_MSP2_SCK PIN_CFG(192, ALT_A)
+
+#define GPIO193_GPIO PIN_CFG(193, GPIO)
+#define GPIO193_MSP2_TXD PIN_CFG(193, ALT_A)
+
+#define GPIO194_GPIO PIN_CFG(194, GPIO)
+#define GPIO194_MSP2_TCK PIN_CFG(194, ALT_A)
+
+#define GPIO195_GPIO PIN_CFG(195, GPIO)
+#define GPIO195_MSP2_TFS PIN_CFG(195, ALT_A)
+
+#define GPIO196_GPIO PIN_CFG(196, GPIO)
+#define GPIO196_MSP2_RXD PIN_CFG(196, ALT_A)
+
+#define GPIO197_GPIO PIN_CFG(197, GPIO)
+#define GPIO197_MC4_DAT3 PIN_CFG_PULL(197, ALT_A, UP)
+
+#define GPIO198_GPIO PIN_CFG(198, GPIO)
+#define GPIO198_MC4_DAT2 PIN_CFG_PULL(198, ALT_A, UP)
+
+#define GPIO199_GPIO PIN_CFG(199, GPIO)
+#define GPIO199_MC4_DAT1 PIN_CFG_PULL(199, ALT_A, UP)
+
+#define GPIO200_GPIO PIN_CFG(200, GPIO)
+#define GPIO200_MC4_DAT0 PIN_CFG_PULL(200, ALT_A, UP)
+
+#define GPIO201_GPIO PIN_CFG(201, GPIO)
+#define GPIO201_MC4_CMD PIN_CFG_PULL(201, ALT_A, UP)
+
+#define GPIO202_GPIO PIN_CFG(202, GPIO)
+#define GPIO202_MC4_FBCLK PIN_CFG_PULL(202, ALT_A, UP)
+#define GPIO202_PWL PIN_CFG(202, ALT_B)
+#define GPIO202_MC4_RSTN PIN_CFG(202, ALT_C)
+
+#define GPIO203_GPIO PIN_CFG(203, GPIO)
+#define GPIO203_MC4_CLK PIN_CFG_PULL(203, ALT_A, UP)
+
+#define GPIO204_GPIO PIN_CFG(204, GPIO)
+#define GPIO204_MC4_DAT7 PIN_CFG_PULL(204, ALT_A, UP)
+
+#define GPIO205_GPIO PIN_CFG(205, GPIO)
+#define GPIO205_MC4_DAT6 PIN_CFG_PULL(205, ALT_A, UP)
+
+#define GPIO206_GPIO PIN_CFG(206, GPIO)
+#define GPIO206_MC4_DAT5 PIN_CFG_PULL(206, ALT_A, UP)
+
+#define GPIO207_GPIO PIN_CFG(207, GPIO)
+#define GPIO207_MC4_DAT4 PIN_CFG_PULL(207, ALT_A, UP)
+
+#define GPIO208_GPIO PIN_CFG(208, GPIO)
+#define GPIO208_MC1_CLK PIN_CFG(208, ALT_A)
+
+#define GPIO209_GPIO PIN_CFG(209, GPIO)
+#define GPIO209_MC1_FBCLK PIN_CFG(209, ALT_A)
+#define GPIO209_SPI1_CLK PIN_CFG(209, ALT_B)
+
+#define GPIO210_GPIO PIN_CFG(210, GPIO)
+#define GPIO210_MC1_CMD PIN_CFG(210, ALT_A)
+
+#define GPIO211_GPIO PIN_CFG(211, GPIO)
+#define GPIO211_MC1_DAT0 PIN_CFG(211, ALT_A)
+
+#define GPIO212_GPIO PIN_CFG(212, GPIO)
+#define GPIO212_MC1_DAT1 PIN_CFG(212, ALT_A)
+#define GPIO212_SPI1_FRM PIN_CFG(212, ALT_B)
+
+#define GPIO213_GPIO PIN_CFG(213, GPIO)
+#define GPIO213_MC1_DAT2 PIN_CFG(213, ALT_A)
+#define GPIO213_SPI1_TXD PIN_CFG(213, ALT_B)
+
+#define GPIO214_GPIO PIN_CFG(214, GPIO)
+#define GPIO214_MC1_DAT3 PIN_CFG(214, ALT_A)
+#define GPIO214_SPI1_RXD PIN_CFG(214, ALT_B)
+
+#define GPIO215_GPIO PIN_CFG(215, GPIO)
+#define GPIO215_MC1_CMDDIR PIN_CFG(215, ALT_A)
+#define GPIO215_MC3_DAT2DIR PIN_CFG(215, ALT_B)
+#define GPIO215_CLKOUT1 PIN_CFG(215, ALT_C)
+
+#define GPIO216_GPIO PIN_CFG(216, GPIO)
+#define GPIO216_MC1_DAT2DIR PIN_CFG(216, ALT_A)
+#define GPIO216_MC3_CMDDIR PIN_CFG(216, ALT_B)
+#define GPIO216_I2C3_SDA PIN_CFG_PULL(216, ALT_C, UP)
+
+#define GPIO217_GPIO PIN_CFG(217, GPIO)
+#define GPIO217_MC1_DAT0DIR PIN_CFG(217, ALT_A)
+#define GPIO217_MC3_DAT31DIR PIN_CFG(217, ALT_B)
+#define GPIO217_CLKOUT2 PIN_CFG(217, ALT_C)
+
+#define GPIO218_GPIO PIN_CFG(218, GPIO)
+#define GPIO218_MC1_DAT31DIR PIN_CFG(218, ALT_A)
+#define GPIO218_MC3_DAT0DIR PIN_CFG(218, ALT_B)
+#define GPIO218_I2C3_SCL PIN_CFG_PULL(218, ALT_C, UP)
+
+#define GPIO219_GPIO PIN_CFG(219, GPIO)
+#define GPIO219_HSIR_FLA0 PIN_CFG(219, ALT_A)
+#define GPIO219_MC3_CLK PIN_CFG(219, ALT_B)
+
+#define GPIO220_GPIO PIN_CFG(220, GPIO)
+#define GPIO220_HSIR_DAT0 PIN_CFG(220, ALT_A)
+#define GPIO220_MC3_FBCLK PIN_CFG(220, ALT_B)
+#define GPIO220_SPI0_CLK PIN_CFG(220, ALT_C)
+
+#define GPIO221_GPIO PIN_CFG(221, GPIO)
+#define GPIO221_HSIR_RDY0 PIN_CFG(221, ALT_A)
+#define GPIO221_MC3_CMD PIN_CFG(221, ALT_B)
+
+#define GPIO222_GPIO PIN_CFG(222, GPIO)
+#define GPIO222_HSIT_FLA0 PIN_CFG(222, ALT_A)
+#define GPIO222_MC3_DAT0 PIN_CFG(222, ALT_B)
+
+#define GPIO223_GPIO PIN_CFG(223, GPIO)
+#define GPIO223_HSIT_DAT0 PIN_CFG(223, ALT_A)
+#define GPIO223_MC3_DAT1 PIN_CFG(223, ALT_B)
+#define GPIO223_SPI0_FRM PIN_CFG(223, ALT_C)
+
+#define GPIO224_GPIO PIN_CFG(224, GPIO)
+#define GPIO224_HSIT_RDY0 PIN_CFG(224, ALT_A)
+#define GPIO224_MC3_DAT2 PIN_CFG(224, ALT_B)
+#define GPIO224_SPI0_TXD PIN_CFG(224, ALT_C)
+
+#define GPIO225_GPIO PIN_CFG(225, GPIO)
+#define GPIO225_HSIT_CAWAKE0 PIN_CFG(225, ALT_A)
+#define GPIO225_MC3_DAT3 PIN_CFG(225, ALT_B)
+#define GPIO225_SPI0_RXD PIN_CFG(225, ALT_C)
+
+#define GPIO226_GPIO PIN_CFG(226, GPIO)
+#define GPIO226_HSIT_ACWAKE0 PIN_CFG(226, ALT_A)
+#define GPIO226_PWL PIN_CFG(226, ALT_B)
+#define GPIO226_USBSIM_PDC PIN_CFG(226, ALT_C)
+
+#define GPIO227_GPIO PIN_CFG(227, GPIO)
+#define GPIO227_CLKOUT1 PIN_CFG(227, ALT_A)
+
+#define GPIO228_GPIO PIN_CFG(228, GPIO)
+#define GPIO228_CLKOUT2 PIN_CFG(228, ALT_A)
+
+#define GPIO229_GPIO PIN_CFG(229, GPIO)
+#define GPIO229_CLKOUT1 PIN_CFG(229, ALT_A)
+#define GPIO229_PWL PIN_CFG(229, ALT_B)
+#define GPIO229_I2C3_SDA PIN_CFG_PULL(229, ALT_C, UP)
+
+#define GPIO230_GPIO PIN_CFG(230, GPIO)
+#define GPIO230_CLKOUT2 PIN_CFG(230, ALT_A)
+#define GPIO230_PWL PIN_CFG(230, ALT_B)
+#define GPIO230_I2C3_SCL PIN_CFG_PULL(230, ALT_C, UP)
+
+#define GPIO256_GPIO PIN_CFG(256, GPIO)
+#define GPIO256_USB_NXT PIN_CFG(256, ALT_A)
+
+#define GPIO257_GPIO PIN_CFG(257, GPIO)
+#define GPIO257_USB_STP PIN_CFG(257, ALT_A)
+
+#define GPIO258_GPIO PIN_CFG(258, GPIO)
+#define GPIO258_USB_XCLK PIN_CFG(258, ALT_A)
+#define GPIO258_NONE PIN_CFG(258, ALT_B)
+#define GPIO258_DDR_TRIG PIN_CFG(258, ALT_C)
+
+#define GPIO259_GPIO PIN_CFG(259, GPIO)
+#define GPIO259_USB_DIR PIN_CFG(259, ALT_A)
+
+#define GPIO260_GPIO PIN_CFG(260, GPIO)
+#define GPIO260_USB_DAT7 PIN_CFG(260, ALT_A)
+
+#define GPIO261_GPIO PIN_CFG(261, GPIO)
+#define GPIO261_USB_DAT6 PIN_CFG(261, ALT_A)
+
+#define GPIO262_GPIO PIN_CFG(262, GPIO)
+#define GPIO262_USB_DAT5 PIN_CFG(262, ALT_A)
+
+#define GPIO263_GPIO PIN_CFG(263, GPIO)
+#define GPIO263_USB_DAT4 PIN_CFG(263, ALT_A)
+
+#define GPIO264_GPIO PIN_CFG(264, GPIO)
+#define GPIO264_USB_DAT3 PIN_CFG(264, ALT_A)
+
+#define GPIO265_GPIO PIN_CFG(265, GPIO)
+#define GPIO265_USB_DAT2 PIN_CFG(265, ALT_A)
+
+#define GPIO266_GPIO PIN_CFG(266, GPIO)
+#define GPIO266_USB_DAT1 PIN_CFG(266, ALT_A)
+
+#define GPIO267_GPIO PIN_CFG(267, GPIO)
+#define GPIO267_USB_DAT0 PIN_CFG(267, ALT_A)
+
+#endif
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index 438ef16aec9..9e4c678de78 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -78,6 +78,8 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
outer_clean_range(__pa(&pen_release), __pa(&pen_release) + 1);
+ smp_cross_call(cpumask_of(cpu));
+
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
if (pen_release == -1)
diff --git a/arch/arm/mach-ux500/pm-common.c b/arch/arm/mach-ux500/pm-common.c
new file mode 100644
index 00000000000..251f1ef5fe5
--- /dev/null
+++ b/arch/arm/mach-ux500/pm-common.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Rickard Andersson <rickard.andersson@stericsson.com> for
+ * ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/smp.h>
+#include <linux/percpu.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <mach/prcmu-regs.h>
+#include <mach/gpio.h>
+
+#define PRCM_PLLARM_ENABLE_PLL_ENABLE 0x1
+#define PRCM_PLLARM_ENABLE_COUNT_ON 0x100
+#define PRCM_ARM_CHGCLKREQ_EXT_CLK 0x1
+#define PRCM_PLLARM_LOCKP_LOCKP3 0x2
+#define PRCM_ARM_PLLDIVPSARM_BRM_RATE (0x3f)
+#define PRCM_ARM_PLLDIVPS_MASK (0xf)
+
+#define GPIO_WKS 0x58
+
+#define GPIO_BK0_WKS (IO_ADDRESS(GPIO_BANK0_BASE) + GPIO_WKS)
+#define GPIO_BK1_WKS (IO_ADDRESS(GPIO_BANK1_BASE) + GPIO_WKS)
+#define GPIO_BK2_WKS (IO_ADDRESS(GPIO_BANK2_BASE) + GPIO_WKS)
+#define GPIO_BK3_WKS (IO_ADDRESS(GPIO_BANK3_BASE) + GPIO_WKS)
+#define GPIO_BK4_WKS (IO_ADDRESS(GPIO_BANK4_BASE) + GPIO_WKS)
+#define GPIO_BK5_WKS (IO_ADDRESS(GPIO_BANK5_BASE) + GPIO_WKS)
+#define GPIO_BK6_WKS (IO_ADDRESS(GPIO_BANK6_BASE) + GPIO_WKS)
+#define GPIO_BK7_WKS (IO_ADDRESS(GPIO_BANK7_BASE) + GPIO_WKS)
+#define GPIO_BK8_WKS (IO_ADDRESS(GPIO_BANK8_BASE) + GPIO_WKS)
+
+static u32 GPIO_WKS_reg_address[] = {GPIO_BK0_WKS,
+ GPIO_BK1_WKS,
+ GPIO_BK2_WKS,
+ GPIO_BK3_WKS,
+ GPIO_BK4_WKS,
+ GPIO_BK5_WKS,
+ GPIO_BK6_WKS,
+ GPIO_BK7_WKS,
+ GPIO_BK8_WKS};
+
+static u32 GPIO_WKS_reg_val[ARRAY_SIZE(GPIO_WKS_reg_address)];
+
+#ifdef ENABLE_ARM_FREQ_RAMP
+static u32 ARM_PLLDIVPS_rate;
+#endif
+
+#ifdef ENABLE_ARM_FREQ_RAMP
+/*
+ * Ramp down the ARM frequency in order to reduce voltage
+ * overshoot/undershoot
+ */
+void run_arm_on_ext_clk(bool keep_arm_pll_on)
+{
+ u32 val;
+ val = readl(PRCM_ARM_PLLDIVPS);
+
+ /*
+ * TODO: create new function
+ * cpu_is_u8500v2_or_later() for
+ * more secure code.
+ * Investigate if ramp down should start
+ * from current frequency.
+ */
+ if (cpu_is_u8500v2()) {
+
+ /*
+ * Store the current rate value. Is needed if
+ * we need to restore the frequency
+ */
+ ARM_PLLDIVPS_rate = val & PRCM_ARM_PLLDIVPSARM_BRM_RATE;
+
+ /* Slow down the cpu's */
+ if ((val & PRCM_ARM_PLLDIVPSARM_BRM_RATE) > 11) {
+ val = (val & ~PRCM_ARM_PLLDIVPSARM_BRM_RATE) | 11;
+ writel(val, PRCM_ARM_PLLDIVPS);
+ udelay(30); /* Wait for voltage to stabilize */
+ }
+ if ((val & PRCM_ARM_PLLDIVPSARM_BRM_RATE) > 5) {
+ val = (val & ~PRCM_ARM_PLLDIVPSARM_BRM_RATE) | 5;
+ writel(val, PRCM_ARM_PLLDIVPS);
+ udelay(30); /* Wait for voltage to stabilize */
+ }
+ if ((val & PRCM_ARM_PLLDIVPSARM_BRM_RATE) > 2) {
+ val = (val & ~PRCM_ARM_PLLDIVPSARM_BRM_RATE) | 2;
+ writel(val, PRCM_ARM_PLLDIVPS);
+ }
+
+ } else {
+
+ ARM_PLLDIVPS_rate = val & PRCM_ARM_PLLDIVPS_MASK;
+
+ /* Slow down the cpu's */
+ if ((val & PRCM_ARM_PLLDIVPS_MASK) < 3) {
+ writel(3, PRCM_ARM_PLLDIVPS);
+ udelay(30); /* Wait for voltage to stabilize */
+ }
+ if ((val & PRCM_ARM_PLLDIVPS_MASK) < 7) {
+ writel(7, PRCM_ARM_PLLDIVPS);
+ udelay(30); /* Wait for voltage to stabilize */
+ }
+ if ((val & PRCM_ARM_PLLDIVPS_MASK) < 15)
+ writel(15, PRCM_ARM_PLLDIVPS);
+ }
+
+ /* switch to external clock */
+ writel(readl(PRCM_ARM_CHGCLKREQ) | PRCM_ARM_CHGCLKREQ_EXT_CLK,
+ PRCM_ARM_CHGCLKREQ);
+
+ if (keep_arm_pll_on) {
+ /* Leave ARM PLL on */
+ writel(readl(PRCM_PLLARM_ENABLE) &
+ (~PRCM_PLLARM_ENABLE_COUNT_ON),
+ PRCM_PLLARM_ENABLE);
+ } else {
+ /* Stop ARM PLL */
+ writel(readl(PRCM_PLLARM_ENABLE) &
+ (~PRCM_PLLARM_ENABLE_PLL_ENABLE),
+ PRCM_PLLARM_ENABLE);
+ }
+}
+#else
+inline void run_arm_on_ext_clk(bool keep_arm_pll_on)
+{
+}
+#endif
+
+#ifdef ENABLE_ARM_FREQ_RAMP
+void run_arm_on_arm_pll(bool arm_pll_state)
+{
+ if (arm_pll_state) {
+ /* ARM PLL is still on, set "counton" bit */
+ writel(readl(PRCM_PLLARM_ENABLE) | PRCM_PLLARM_ENABLE_COUNT_ON,
+ PRCM_PLLARM_ENABLE);
+ } else {
+ /* ARM PLL was stopped => turn on */
+ writel(readl(PRCM_PLLARM_ENABLE) |
+ PRCM_PLLARM_ENABLE_PLL_ENABLE,
+ PRCM_PLLARM_ENABLE);
+
+ /* Wait for PLL to lock */
+ while (!(readl(PRCM_PLLARM_LOCKP) & PRCM_PLLARM_LOCKP_LOCKP3))
+ cpu_relax();
+ }
+
+ writel(readl(PRCM_ARM_CHGCLKREQ) & ~PRCM_ARM_CHGCLKREQ_EXT_CLK,
+ PRCM_ARM_CHGCLKREQ);
+
+ if (cpu_is_u8500v2()) {
+ u32 val;
+
+ val = readl(PRCM_ARM_PLLDIVPS);
+
+ /* Ramp up the ARM PLL */
+ if (ARM_PLLDIVPS_rate >= 2) {
+ val = (val & ~PRCM_ARM_PLLDIVPSARM_BRM_RATE) | 2;
+ writel(val, PRCM_ARM_PLLDIVPS);
+ udelay(30); /* Wait for voltage to stabilize */
+ }
+ if (ARM_PLLDIVPS_rate >= 5) {
+ val = (val & ~PRCM_ARM_PLLDIVPSARM_BRM_RATE) | 5;
+ writel(val, PRCM_ARM_PLLDIVPS);
+ udelay(30); /* Wait for voltage to stabilize */
+ }
+ if (ARM_PLLDIVPS_rate >= 11) {
+ val = (val & ~PRCM_ARM_PLLDIVPSARM_BRM_RATE) | 11;
+ writel(val, PRCM_ARM_PLLDIVPS);
+ }
+ } else {
+
+ /* Ramp up the ARM PLL */
+ if (ARM_PLLDIVPS_rate <= 15) {
+ writel(15, PRCM_ARM_PLLDIVPS);
+ udelay(30); /* Wait for voltage to stabilize */
+ }
+ if (ARM_PLLDIVPS_rate <= 7) {
+ writel(7, PRCM_ARM_PLLDIVPS);
+ udelay(30); /* Wait for voltage to stabilize */
+ }
+ if (ARM_PLLDIVPS_rate <= 3)
+ writel(3, PRCM_ARM_PLLDIVPS);
+ }
+}
+#else
+inline void run_arm_on_arm_pll(bool arm_pll_state)
+{
+}
+#endif
+
+#define PRCM_A9_MASK_INT 0x1
+
+/* Decouple GIC from the interrupt bus */
+void decouple_gic(void)
+{
+ writel(PRCM_A9_MASK_INT, PRCM_A9_MASK_REQ);
+ while (!readl(PRCM_A9_MASK_REQ))
+ cpu_relax();
+
+ /* TODO: Use the ack bit when possible */
+ udelay(100);
+}
+
+/* Recouple GIC with the interrupt bus */
+void recouple_gic(void)
+{
+ writel((readl(PRCM_A9_MASK_REQ) & ~PRCM_A9_MASK_INT), PRCM_A9_MASK_REQ);
+
+ /* TODO: Use the ack bit when possible */
+}
+
+#define GIC_NUMBER_REGS 5
+#define GIC_NUMBER_SPI_REGS 4
+
+bool pending_gic_interrupt(void)
+{
+ u32 pr; /* Pending register */
+ u32 er; /* Enable register */
+
+ u32 gic_set_pending_addr; /* Offset 0x200 */
+ u32 gic_set_enable_addr; /* Offset 0x100 */
+
+ int i;
+
+ gic_set_pending_addr = IO_ADDRESS(U8500_GIC_DIST_BASE) +
+ GIC_DIST_PENDING_SET;
+
+ gic_set_enable_addr = IO_ADDRESS(U8500_GIC_DIST_BASE) +
+ GIC_DIST_ENABLE_SET;
+
+ /* 5 registers. STI & PPI not skipped */
+ for (i = 0; i < GIC_NUMBER_REGS; i++) {
+
+ pr = readl(gic_set_pending_addr);
+ er = readl(gic_set_enable_addr);
+
+ if (pr & er)
+ return true; /* There is a pending interrupt */
+
+ gic_set_pending_addr += 4; /* Move to next register */
+ gic_set_enable_addr += 4; /* Move to next register */
+ }
+
+ return false;
+}
+
+bool pending_prcmu_interrupt(void)
+{
+ u32 it;
+ u32 im;
+ void __iomem *prcmu_itval_addr;
+ void __iomem *prcmu_itmask_addr;
+ int i;
+
+ prcmu_itval_addr = PRCM_ARMITVAL31TO0;
+ prcmu_itmask_addr = PRCM_ARMITMSK31TO0;
+
+ for (i = 0; i < GIC_NUMBER_SPI_REGS; i++) { /* There are 4 registers */
+
+ it = readl(prcmu_itval_addr);
+ im = readl(prcmu_itmask_addr);
+
+ if (it & im)
+ return true; /* There is a pending interrupt */
+
+ prcmu_itval_addr += 4; /* Move to next register */
+ prcmu_itmask_addr += 4; /* Move to next register */
+ }
+
+ return false;
+}
+
+#define PRCM_IOCR_SET_IOFORCE 0x1
+
+void prcmu_set_ioforce(void)
+{
+ writel(readl(PRCM_IOCR) | PRCM_IOCR_SET_IOFORCE, PRCM_IOCR);
+}
+
+void prcmu_clr_ioforce(void)
+{
+ writel(readl(PRCM_IOCR) & ~PRCM_IOCR_SET_IOFORCE, PRCM_IOCR);
+}
+
+void copy_gic_settings_to_prcmu(void)
+{
+ u32 er; /* Enable register */
+
+ void __iomem *prcmu_itmsk_addr;
+ u32 gic_set_enable_addr;
+
+ int i;
+
+ prcmu_itmsk_addr = PRCM_ARMITMSK31TO0;
+ gic_set_enable_addr = IO_ADDRESS(U8500_GIC_DIST_BASE) +
+ GIC_DIST_ENABLE_SET + 4; /* Skip STI and PPI */
+
+ for (i = 0; i < GIC_NUMBER_SPI_REGS; i++) { /* 4*32 SPI interrupts */
+
+ er = readl(gic_set_enable_addr);
+ writel(er, prcmu_itmsk_addr);
+
+ prcmu_itmsk_addr += 4; /* Move to next register */
+ gic_set_enable_addr += 4; /* Move to next register */
+ }
+
+}
+
+void catch_gpio_wake_up_status(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(GPIO_WKS_reg_address); i++)
+ GPIO_WKS_reg_val[i] = readl(GPIO_WKS_reg_address[i]);
+}
+
+int read_gpio_wake_up_status(unsigned int bank_number, u32 *WKS_reg_value)
+{
+ int ret;
+
+ if (bank_number < ARRAY_SIZE(GPIO_WKS_reg_address)) {
+ *WKS_reg_value = GPIO_WKS_reg_val[bank_number];
+ ret = 0;
+ } else {
+ *WKS_reg_value = 0;
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
diff --git a/arch/arm/mach-ux500/pm-common.h b/arch/arm/mach-ux500/pm-common.h
new file mode 100644
index 00000000000..528ce467882
--- /dev/null
+++ b/arch/arm/mach-ux500/pm-common.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Rickard Andersson <rickard.andersson@stericsson.com> for
+ * ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ */
+
+#ifndef PM_COMMON_H
+#define PM_COMMON_H
+
+void run_arm_on_ext_clk(bool keep_arm_pll_on);
+void run_arm_on_arm_pll(bool arm_pll_state);
+void decouple_gic(void);
+void recouple_gic(void);
+bool pending_gic_interrupt(void);
+bool pending_prcmu_interrupt(void);
+void prcmu_set_ioforce(void);
+void prcmu_clr_ioforce(void);
+void copy_gic_settings_to_prcmu(void);
+void catch_gpio_wake_up_status(void);
+int read_gpio_wake_up_status(unsigned int bank_number, u32 *WKS_reg_value);
+
+#endif
diff --git a/arch/arm/mach-ux500/pm.c b/arch/arm/mach-ux500/pm.c
new file mode 100644
index 00000000000..71abef1a0b8
--- /dev/null
+++ b/arch/arm/mach-ux500/pm.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ */
+
+#include <linux/suspend.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/mfd/ab8500/sysctrl.h>
+
+#include <mach/gpio.h>
+
+#define U8500_EXT_BACKUPRAM_ADDR (0x80151FDC)
+#define U8500_CPU0_PUBLIC_BACKUP (0x80151FD8)
+#define U8500_CPU1_PUBLIC_BACKUP (0x80151FE0)
+#define U8500_BACKUPRAM_SIZE (64 * 1024)
+
+/* pointers for backups/contexts to be saved */
+dma_addr_t *arm_cntxt_cpu0, *arm_cntxt_cpu1, *ux500_backup_ptr;
+
+/*
+ * This function is used for shuting down the u8500 system by
+ * turning off the ab8500
+ */
+void u8500_pm_poweroff(void)
+{
+ sigset_t old;
+ sigset_t all;
+
+ sigfillset(&all);
+ if (!sigprocmask(SIG_BLOCK, &all, &old)) {
+ (void)ab8500_sysctrl_set(AB8500_STW4500CTRL1,
+ AB8500_STW4500CTRL1_SWOFF);
+ (void)sigprocmask(SIG_SETMASK, &old, NULL);
+ }
+}
+
+/*
+ * FIXME : replace this hack for console gpio
+ * this config makes the gpio29 pins pull up
+ * by deflt
+ */
+#define CONSOLE_GPIO_HACK (0x60000000)
+
+static int u8500_pm_begin(suspend_state_t state)
+{
+ return 0;
+}
+
+static int u8500_pm_prepare(void)
+{
+ return 0;
+}
+
+static int u8500_pm_enter(suspend_state_t state)
+{
+ /* Temporary disabling deeper sleep states */
+ __asm__ __volatile__("dsb\n\t" "wfi\n\t" : : : "memory");
+ return 0;
+}
+
+static void u8500_pm_finish(void)
+{
+
+}
+
+static int u8500_pm_valid(suspend_state_t state)
+{
+ return (state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY);
+}
+
+static struct platform_suspend_ops u8500_pm_ops = {
+ .begin = u8500_pm_begin,
+ .prepare = u8500_pm_prepare,
+ .enter = u8500_pm_enter,
+ .finish = u8500_pm_finish,
+ .valid = u8500_pm_valid,
+};
+
+/* FIXME : remove this later when board files have such defines */
+#define MOP500_UART2RX_GPIO (29)
+
+static int __init u8500_pm_init(void)
+{
+ /*
+ * TODO: Clean-up this function and make it match to context.c's
+ * init function.
+ */
+
+ /* allocate backup pointers for CPU0/1 */
+ arm_cntxt_cpu1 = kzalloc(SZ_1K, GFP_KERNEL);
+ if (!arm_cntxt_cpu1) {
+ pr_warning("ux500-pm: backup ptr allocation failed\n");
+ return -ENOMEM;
+ }
+
+ arm_cntxt_cpu0 = kzalloc(SZ_1K, GFP_KERNEL);
+ if (!arm_cntxt_cpu0) {
+ pr_warning("ux500-pm: backup ptr allocation failed\n");
+ return -ENOMEM;
+ }
+
+ /* make the UART2-Rx/GPIO29 as a wakeup event */
+ set_irq_type(GPIO_TO_IRQ(MOP500_UART2RX_GPIO), IRQ_TYPE_EDGE_BOTH);
+ set_irq_wake(GPIO_TO_IRQ(MOP500_UART2RX_GPIO), 1);
+
+ /* allocate backup pointer for RAM data */
+ ux500_backup_ptr = (void *)__get_free_pages(GFP_KERNEL,
+ get_order(U8500_BACKUPRAM_SIZE));
+ if (!ux500_backup_ptr) {
+ pr_warning("ux500-pm: couldnt allocate backup ptr\n");
+ return -ENOMEM;
+ }
+
+ /* BACKUPRAM addresses to store backup contents */
+ /* pass the physical address of back up to ROM code */
+ writel(virt_to_phys(ux500_backup_ptr),
+ __io_address(U8500_EXT_BACKUPRAM_ADDR));
+ writel(__io_address(U8500_BACKUPRAM0_BASE),
+ __io_address(U8500_CPU0_PUBLIC_BACKUP));
+ writel(__io_address(U8500_BACKUPRAM0_BASE),
+ __io_address(U8500_CPU1_PUBLIC_BACKUP));
+
+ /* register the global power off hook */
+ pm_power_off = u8500_pm_poweroff;
+#ifndef CONFIG_U8500_SUSPEND
+ suspend_set_ops(&u8500_pm_ops);
+#endif
+
+ return 0;
+}
+
+device_initcall(u8500_pm_init);
diff --git a/arch/arm/mach-ux500/pm.h b/arch/arm/mach-ux500/pm.h
new file mode 100644
index 00000000000..70d99400a81
--- /dev/null
+++ b/arch/arm/mach-ux500/pm.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ * power management generic file
+ */
+
+#ifndef _PM_H_
+#define _PM_H_
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/suspend.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/memory.h>
+
+#include <asm/system.h>
+
+#include <mach/scu.h>
+#include <mach/prcmu-regs.h>
+#include <mach/prcmu-fw-api.h>
+#include <mach/prcmu-fw-defs_v1.h>
+
+/* Peripheral Context Save/Restore */
+
+/*
+ * GPIO periph
+ */
+struct ux500_gpio_regs {
+ uint32_t gpio_dat;
+ uint32_t gpio_dat_set;
+ uint32_t gpio_dat_clr;
+ uint32_t gpio_pdis;
+ uint32_t gpio_dir;
+ uint32_t gpio_dir_set;
+ uint32_t gpio_dir_clr;
+ uint32_t gpio_slpm;
+ uint32_t gpio_altfunc_a;
+ uint32_t gpio_altfunc_b;
+ uint32_t gpio_rimsc;
+ uint32_t gpio_fsmsc;
+ uint32_t gpio_int_status;
+ uint32_t gpio_int_clr;
+ uint32_t gpio_rwmsc;
+ uint32_t gpio_fwmsc;
+ uint32_t gpio_wakeup_status;
+};
+
+#define UX500_NR_GPIO_BANKS (8)
+#define GPIO_BANK_BASE(x) IO_ADDRESS(GPIO_BANK##x##_BASE)
+
+/*
+ * A9 sub system GIC context
+ */
+#define UX500_GIC_REG_SET (100)
+
+static uint32_t gic_enable_set_reg[UX500_GIC_REG_SET];
+static uint32_t gic_dist_config[UX500_GIC_REG_SET];
+static uint32_t gic_dist_target[UX500_GIC_REG_SET];
+
+/*
+ * Periph clock cluster context
+ */
+#define PRCC_BCK_EN 0x00
+#define PRCC_KCK_EN 0x08
+#define PRCC_BCK_STATUS 0x10
+#define PRCC_KCK_STATUS 0x14
+
+#define UX500_NR_PRCC_BANKS (5)
+#define PRCC_BANK_BASE(x) IO_ADDRESS(U8500_PER##x##_BASE)
+
+struct ux500_prcc_contxt {
+ uint32_t periph_bus_clk;
+ uint32_t periph_kern_clk;
+};
+
+/*
+ * ST-Interconnect context
+ */
+/* priority, bw limiter register offsets */
+#define NODE_HIBW1_ESRAM_IN_0_PRIORITY_REG 0x00
+#define NODE_HIBW1_ESRAM_IN_1_PRIORITY_REG 0x04
+#define NODE_HIBW1_ESRAM_IN_2_PRIORITY_REG 0x08
+#define NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT_REG 0x24
+#define NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT_REG 0x28
+#define NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT_REG 0x2C
+#define NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT_REG 0x30
+#define NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT_REG 0x34
+#define NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT_REG 0x38
+#define NODE_HIBW1_ESRAM_IN_2_ARB_1_LIMIT_REG 0x3C
+#define NODE_HIBW1_ESRAM_IN_2_ARB_2_LIMIT_REG 0x40
+#define NODE_HIBW1_ESRAM_IN_2_ARB_3_LIMIT_REG 0x44
+#define NODE_HIBW1_DDR_IN_0_PRIORITY_REG 0x400
+#define NODE_HIBW1_DDR_IN_1_PRIORITY_REG 0x404
+#define NODE_HIBW1_DDR_IN_2_PRIORITY_REG 0x408
+#define NODE_HIBW1_DDR_IN_0_LIMIT_REG 0x424
+#define NODE_HIBW1_DDR_IN_1_LIMIT_REG 0x428
+#define NODE_HIBW1_DDR_IN_2_LIMIT_REG 0x42C
+#define NODE_HIBW1_DDR_OUT_0_PRIORITY_REG 0x430
+#define NODE_HIBW2_ESRAM_IN_0_PRIORITY_REG 0x800
+#define NODE_HIBW2_ESRAM_IN_1_PRIORITY_REG 0x804
+#define NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT_REG 0x818
+#define NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT_REG 0x81C
+#define NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT_REG 0x820
+#define NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT_REG 0x824
+#define NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT_REG 0x828
+#define NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT_REG 0x82C
+#define NODE_HIBW2_DDR_IN_0_PRIORITY_REG 0xC00
+#define NODE_HIBW2_DDR_IN_1_PRIORITY_REG 0xC04
+#define NODE_HIBW2_DDR_IN_2_PRIORITY_REG 0xC08
+#define NODE_HIBW2_DDR_IN_3_PRIORITY_REG 0xC0C
+#define NODE_HIBW2_DDR_IN_0_LIMIT_REG 0xC30
+#define NODE_HIBW2_DDR_IN_1_LIMIT_REG 0xC34
+#define NODE_ESRAM1_2_IN_0_PRIORITY_REG 0x1400
+#define NODE_ESRAM1_2_IN_1_PRIORITY_REG 0x1404
+#define NODE_ESRAM1_2_IN_2_PRIORITY_REG 0x1408
+#define NODE_ESRAM1_2_IN_3_PRIORITY_REG 0x140C
+#define NODE_ESRAM1_2_IN_0_ARB_1_LIMIT_REG 0x1430
+#define NODE_ESRAM1_2_IN_0_ARB_2_LIMIT_REG 0x1434
+#define NODE_ESRAM1_2_IN_1_ARB_1_LIMIT_REG 0x1438
+#define NODE_ESRAM1_2_IN_1_ARB_2_LIMIT_REG 0x143C
+#define NODE_ESRAM1_2_IN_2_ARB_1_LIMIT_REG 0x1440
+#define NODE_ESRAM1_2_IN_2_ARB_2_LIMIT_REG 0x1444
+#define NODE_ESRAM1_2_IN_3_ARB_1_LIMIT_REG 0x1448
+#define NODE_ESRAM1_2_IN_3_ARB_2_LIMIT_REG 0x144C
+#define NODE_ESRAM3_4_IN_0_PRIORITY_REG 0x1800
+#define NODE_ESRAM3_4_IN_1_PRIORITY_REG 0x1804
+#define NODE_ESRAM3_4_IN_2_PRIORITY_REG 0x1808
+#define NODE_ESRAM3_4_IN_3_PRIORITY_REG 0x180C
+#define NODE_ESRAM3_4_IN_0_ARB_1_LIMIT_REG 0x1830
+#define NODE_ESRAM3_4_IN_0_ARB_2_LIMIT_REG 0x1834
+#define NODE_ESRAM3_4_IN_1_ARB_1_LIMIT_REG 0x1838
+#define NODE_ESRAM3_4_IN_1_ARB_2_LIMIT_REG 0x183C
+#define NODE_ESRAM3_4_IN_2_ARB_1_LIMIT_REG 0x1840
+#define NODE_ESRAM3_4_IN_2_ARB_2_LIMIT_REG 0x1844
+#define NODE_ESRAM3_4_IN_3_ARB_1_LIMIT_REG 0x1848
+#define NODE_ESRAM3_4_IN_3_ARB_2_LIMIT_REG 0x184C
+
+struct ux500_interconnect_contxt {
+ uint32_t ux500_hibw1_esram_in_pri_regs[3];
+ uint32_t ux500_hibw1_esram_in0_arb_regs[3];
+ uint32_t ux500_hibw1_esram_in1_arb_regs[3];
+ uint32_t ux500_hibw1_esram_in2_arb_regs[3];
+ uint32_t ux500_hibw1_ddr_in_prio_regs[3];
+ uint32_t ux500_hibw1_ddr_in_limit_regs[3];
+ uint32_t ux500_hibw1_ddr_out_prio_reg;
+
+ /* HiBw2 node registers */
+ uint32_t ux500_hibw2_esram_in_pri_regs[2];
+ uint32_t ux500_hibw2_esram_in0_arblimit_regs[3];
+ uint32_t ux500_hibw2_esram_in1_arblimit_regs[3];
+ uint32_t ux500_hibw2_ddr_in_prio_regs[4];
+ uint32_t ux500_hibw2_ddr_in_limit_regs[4];
+ uint32_t ux500_hibw2_ddr_out_prio_reg;
+
+ /* ESRAM node registers */
+ uint32_t ux500_esram_in_prio_regs[4];
+ uint32_t ux500_esram_in_lim_regs[4];
+ uint32_t ux500_esram12_in_prio_regs[4];
+ uint32_t ux500_esram12_in_arb_lim_regs[8];
+ uint32_t ux500_esram34_in_prio_regs[4];
+ uint32_t ux500_esram34_in_arb_lim_regs[8];
+};
+
+/*
+ * SCU context
+ */
+#define SCU_FILTER_STARTADDR 0x40
+#define SCU_FILTER_ENDADDR 0x44
+#define SCU_ACCESS_CTRL_SAC 0x50
+
+struct ux500_scu_context {
+ uint32_t scu_ctrl;
+ uint32_t scu_cpu_pwrstatus;
+ uint32_t scu_inv_all_nonsecure;
+ uint32_t scu_filter_start_addr;
+ uint32_t scu_filter_end_addr;
+ uint32_t scu_access_ctrl_sac;
+};
+
+/* helpers to save/restore contexts */
+void ux500_save_gic_context(void);
+void ux500_restore_gic_context(void);
+
+void ux500_save_uart_context(void);
+void ux500_restore_uart_context(void);
+
+void ux500_save_prcc_context(void);
+void ux500_restore_prcc_context(void);
+
+void ux500_save_icn_context(void);
+void ux500_restore_icn_context(void);
+
+void ux500_save_scu_context(void);
+void ux500_restore_scu_context(void);
+
+void ux500_cpu_context_deepsleep(uint8_t cpu);
+
+void ux500_save_gpio_context(void);
+void ux500_restore_gpio_context(void);
+
+#endif /* _PM_H */
diff --git a/arch/arm/mach-ux500/prcmu-db5500.c b/arch/arm/mach-ux500/prcmu-db5500.c
new file mode 100644
index 00000000000..e55c0bf8dd9
--- /dev/null
+++ b/arch/arm/mach-ux500/prcmu-db5500.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
+ *
+ * U5500 PRCM Unit interface driver
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/prcmu-regs.h>
+#include <mach/prcmu-db5500.h>
+#include <mach/db5500-regs.h>
+
+#define _PRCM_MB_HEADER (tcdm_base + 0xFE8)
+#define PRCM_REQ_MB0_HEADER (_PRCM_MB_HEADER + 0x0)
+#define PRCM_REQ_MB1_HEADER (_PRCM_MB_HEADER + 0x1)
+#define PRCM_REQ_MB2_HEADER (_PRCM_MB_HEADER + 0x2)
+#define PRCM_REQ_MB3_HEADER (_PRCM_MB_HEADER + 0x3)
+#define PRCM_REQ_MB4_HEADER (_PRCM_MB_HEADER + 0x4)
+#define PRCM_REQ_MB5_HEADER (_PRCM_MB_HEADER + 0x5)
+#define PRCM_REQ_MB6_HEADER (_PRCM_MB_HEADER + 0x6)
+#define PRCM_REQ_MB7_HEADER (_PRCM_MB_HEADER + 0x7)
+#define PRCM_ACK_MB0_HEADER (_PRCM_MB_HEADER + 0x8)
+#define PRCM_ACK_MB1_HEADER (_PRCM_MB_HEADER + 0x9)
+#define PRCM_ACK_MB2_HEADER (_PRCM_MB_HEADER + 0xa)
+#define PRCM_ACK_MB3_HEADER (_PRCM_MB_HEADER + 0xb)
+#define PRCM_ACK_MB4_HEADER (_PRCM_MB_HEADER + 0xc)
+#define PRCM_ACK_MB5_HEADER (_PRCM_MB_HEADER + 0xd)
+#define PRCM_ACK_MB6_HEADER (_PRCM_MB_HEADER + 0xe)
+#define PRCM_ACK_MB7_HEADER (_PRCM_MB_HEADER + 0xf)
+
+/* Req Mailboxes */
+#define PRCM_REQ_MB0 (tcdm_base + 0xFD8)
+#define PRCM_REQ_MB1 (tcdm_base + 0xFCC)
+#define PRCM_REQ_MB2 (tcdm_base + 0xFC4)
+#define PRCM_REQ_MB3 (tcdm_base + 0xFC0)
+#define PRCM_REQ_MB4 (tcdm_base + 0xF98)
+#define PRCM_REQ_MB5 (tcdm_base + 0xF90)
+#define PRCM_REQ_MB6 (tcdm_base + 0xF8C)
+#define PRCM_REQ_MB7 (tcdm_base + 0xF84)
+
+/* Ack Mailboxes */
+#define PRCM_ACK_MB0 (tcdm_base + 0xF38)
+#define PRCM_ACK_MB1 (tcdm_base + 0xF30)
+#define PRCM_ACK_MB2 (tcdm_base + 0xF24)
+#define PRCM_ACK_MB3 (tcdm_base + 0xF20)
+#define PRCM_ACK_MB4 (tcdm_base + 0xF1C)
+#define PRCM_ACK_MB5 (tcdm_base + 0xF14)
+#define PRCM_ACK_MB6 (tcdm_base + 0xF0C)
+#define PRCM_ACK_MB7 (tcdm_base + 0xF08)
+
+enum mb_return_code {
+ RC_SUCCESS,
+ RC_FAIL,
+};
+
+/* Mailbox 0 headers. */
+enum mb0_header {
+ /* request */
+ RMB0H_PWR_STATE_TRANS = 1,
+ RMB0H_WAKE_UP_CFG,
+ RMB0H_RD_WAKE_UP_ACK,
+ /* acknowledge */
+ AMB0H_WAKE_UP = 1,
+};
+
+/* Mailbox 5 headers. */
+enum mb5_header {
+ MB5H_I2C_WRITE = 1,
+ MB5H_I2C_READ,
+};
+
+/* Request mailbox 5 fields. */
+#define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0)
+#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1)
+#define PRCM_REQ_MB5_I2C_SIZE (PRCM_REQ_MB5 + 2)
+#define PRCM_REQ_MB5_I2C_DATA (PRCM_REQ_MB5 + 4)
+
+/* Acknowledge mailbox 5 fields. */
+#define PRCM_ACK_MB5_RETURN_CODE (PRCM_ACK_MB5 + 0)
+#define PRCM_ACK_MB5_I2C_DATA (PRCM_ACK_MB5 + 4)
+
+#define NUM_MB 8
+#define MBOX_BIT BIT
+#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
+
+/*
+ * mb0_transfer - state needed for mailbox 0 communication.
+ * @lock: The transaction lock.
+ */
+static struct {
+ spinlock_t lock;
+} mb0_transfer;
+
+/*
+ * mb5_transfer - state needed for mailbox 5 communication.
+ * @lock: The transaction lock.
+ * @work: The transaction completion structure.
+ * @ack: Reply ("acknowledge") data.
+ */
+static struct {
+ struct mutex lock;
+ struct completion work;
+ struct {
+ u8 header;
+ u8 status;
+ u8 value[4];
+ } ack;
+} mb5_transfer;
+
+/* PRCMU TCDM base IO address. */
+static __iomem void *tcdm_base;
+
+/**
+ * prcmu_abb_read() - Read register value(s) from the ABB.
+ * @slave: The I2C slave address.
+ * @reg: The (start) register address.
+ * @value: The read out value(s).
+ * @size: The number of registers to read.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be <= 4.
+ */
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ int r;
+
+ if ((size < 1) || (4 < size))
+ return -EINVAL;
+
+ mutex_lock(&mb5_transfer.lock);
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+ cpu_relax();
+ writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
+ writeb(reg, PRCM_REQ_MB5_I2C_REG);
+ writeb(size, PRCM_REQ_MB5_I2C_SIZE);
+ writeb(MB5H_I2C_READ, PRCM_REQ_MB5_HEADER);
+
+ writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+ wait_for_completion(&mb5_transfer.work);
+
+ r = 0;
+ if ((mb5_transfer.ack.header == MB5H_I2C_READ) &&
+ (mb5_transfer.ack.status == RC_SUCCESS))
+ memcpy(value, mb5_transfer.ack.value, (size_t)size);
+ else
+ r = -EIO;
+
+ mutex_unlock(&mb5_transfer.lock);
+
+ return r;
+}
+
+/**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave: The I2C slave address.
+ * @reg: The (start) register address.
+ * @value: The value(s) to write.
+ * @size: The number of registers to write.
+ *
+ * Writes register value(s) to the ABB.
+ * @size has to be <= 4.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ int r;
+
+ if ((size < 1) || (4 < size))
+ return -EINVAL;
+
+ mutex_lock(&mb5_transfer.lock);
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+ cpu_relax();
+ writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
+ writeb(reg, PRCM_REQ_MB5_I2C_REG);
+ writeb(size, PRCM_REQ_MB5_I2C_SIZE);
+ memcpy_toio(PRCM_REQ_MB5_I2C_DATA, value, size);
+ writeb(MB5H_I2C_WRITE, PRCM_REQ_MB5_HEADER);
+
+ writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+ wait_for_completion(&mb5_transfer.work);
+
+ if ((mb5_transfer.ack.header == MB5H_I2C_WRITE) &&
+ (mb5_transfer.ack.status == RC_SUCCESS))
+ r = 0;
+ else
+ r = -EIO;
+
+ mutex_unlock(&mb5_transfer.lock);
+
+ return r;
+}
+
+static void ack_dbb_wakeup(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+ cpu_relax();
+
+ writeb(RMB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER);
+ writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
+
+ spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+static inline void print_unknown_header_warning(u8 n, u8 header)
+{
+ pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
+ header, n);
+}
+
+static bool read_mailbox_0(void)
+{
+ bool r;
+ u8 header;
+
+ header = readb(PRCM_ACK_MB0_HEADER);
+ switch (header) {
+ case AMB0H_WAKE_UP:
+ r = true;
+ break;
+ default:
+ print_unknown_header_warning(0, header);
+ r = false;
+ break;
+ }
+ writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
+ return r;
+}
+
+static bool read_mailbox_1(void)
+{
+ writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_2(void)
+{
+ writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_3(void)
+{
+ writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_4(void)
+{
+ writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_5(void)
+{
+ u8 header;
+
+ header = readb(PRCM_ACK_MB5_HEADER);
+ switch (header) {
+ case MB5H_I2C_READ:
+ memcpy_fromio(mb5_transfer.ack.value, PRCM_ACK_MB5_I2C_DATA, 4);
+ case MB5H_I2C_WRITE:
+ mb5_transfer.ack.header = header;
+ mb5_transfer.ack.status = readb(PRCM_ACK_MB5_RETURN_CODE);
+ complete(&mb5_transfer.work);
+ break;
+ default:
+ print_unknown_header_warning(5, header);
+ break;
+ }
+ writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_6(void)
+{
+ writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_7(void)
+{
+ writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool (* const read_mailbox[NUM_MB])(void) = {
+ read_mailbox_0,
+ read_mailbox_1,
+ read_mailbox_2,
+ read_mailbox_3,
+ read_mailbox_4,
+ read_mailbox_5,
+ read_mailbox_6,
+ read_mailbox_7
+};
+
+static irqreturn_t prcmu_irq_handler(int irq, void *data)
+{
+ u32 bits;
+ u8 n;
+ irqreturn_t r;
+
+ bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
+ if (unlikely(!bits))
+ return IRQ_NONE;
+
+ r = IRQ_HANDLED;
+ for (n = 0; bits; n++) {
+ if (bits & MBOX_BIT(n)) {
+ bits -= MBOX_BIT(n);
+ if (read_mailbox[n]())
+ r = IRQ_WAKE_THREAD;
+ }
+ }
+ return r;
+}
+
+static irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
+{
+ ack_dbb_wakeup();
+ return IRQ_HANDLED;
+}
+
+void __init prcmu_early_init(void)
+{
+ tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE);
+ spin_lock_init(&mb0_transfer.lock);
+ mutex_init(&mb5_transfer.lock);
+ init_completion(&mb5_transfer.work);
+}
+
+/**
+ * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
+ *
+ */
+int __init prcmu_init(void)
+{
+ int r = 0;
+
+ /* Clean up the mailbox interrupts after pre-kernel code. */
+ writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLEAR);
+
+ r = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler,
+ prcmu_irq_thread_fn, 0, "prcmu", NULL);
+ if (r < 0) {
+ pr_err("prcmu: Failed to allocate IRQ_DB5500_PRCMU1.\n");
+ return -EBUSY;
+ }
+ return 0;
+}
+
+arch_initcall(prcmu_init);
diff --git a/arch/arm/mach-ux500/prcmu-db8500.c b/arch/arm/mach-ux500/prcmu-db8500.c
new file mode 100644
index 00000000000..c375e5a1894
--- /dev/null
+++ b/arch/arm/mach-ux500/prcmu-db8500.c
@@ -0,0 +1,1777 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
+ *
+ * U8500 PRCM Unit interface driver
+ *
+ * Quality Of Service:
+ * The QoS solution for the PRCMU is a copy, with some modifications,
+ * of the one in kernel/pm_qos_params.c.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/prcmu-regs.h>
+#include <mach/prcmu-fw-api.h>
+#include <mach/prcmu-fw-defs_v1.h>
+#include <mach/db8500-regs.h>
+
+#define PRCM_BOOT_STATUS (tcdm_base + 0xFFF)
+#define PRCM_ROMCODE_A2P (tcdm_base + 0xFFE)
+#define PRCM_ROMCODE_P2A (tcdm_base + 0xFFD)
+#define PRCM_XP70_CUR_PWR_STATE (tcdm_base + 0xFFC) /* 4 BYTES */
+
+#define _PRCM_MBOX_HEADER (tcdm_base + 0xFE8)/*16 bytes*/
+#define PRCM_MBOX_HEADER_REQ_MB0 (_PRCM_MBOX_HEADER + 0x0)
+#define PRCM_MBOX_HEADER_REQ_MB1 (_PRCM_MBOX_HEADER + 0x1)
+#define PRCM_MBOX_HEADER_REQ_MB2 (_PRCM_MBOX_HEADER + 0x2)
+#define PRCM_MBOX_HEADER_REQ_MB3 (_PRCM_MBOX_HEADER + 0x3)
+#define PRCM_MBOX_HEADER_REQ_MB4 (_PRCM_MBOX_HEADER + 0x4)
+#define PRCM_MBOX_HEADER_REQ_MB5 (_PRCM_MBOX_HEADER + 0x5)
+#define PRCM_MBOX_HEADER_REQ_MB6 (_PRCM_MBOX_HEADER + 0x6)
+#define PRCM_MBOX_HEADER_REQ_MB7 (_PRCM_MBOX_HEADER + 0x7)
+#define PRCM_MBOX_HEADER_ACK_MB0 (_PRCM_MBOX_HEADER + 0x8)
+#define PRCM_MBOX_HEADER_ACK_MB1 (_PRCM_MBOX_HEADER + 0x9)
+#define PRCM_MBOX_HEADER_ACK_MB2 (_PRCM_MBOX_HEADER + 0xA)
+#define PRCM_MBOX_HEADER_ACK_MB3 (_PRCM_MBOX_HEADER + 0xB)
+#define PRCM_MBOX_HEADER_ACK_MB4 (_PRCM_MBOX_HEADER + 0xC)
+#define PRCM_MBOX_HEADER_ACK_MB5 (_PRCM_MBOX_HEADER + 0xD)
+#define PRCM_MBOX_HEADER_ACK_MB6 (_PRCM_MBOX_HEADER + 0xE)
+#define PRCM_MBOX_HEADER_ACK_MB7 (_PRCM_MBOX_HEADER + 0xF)
+
+/*Req Mailboxes */
+#define PRCM_REQ_MB0 (tcdm_base + 0xFDC) /* 12 bytes */
+#define PRCM_REQ_MB1 (tcdm_base + 0xFD0) /* 12 bytes */
+#define PRCM_REQ_MB2 (tcdm_base + 0xFC0) /* 16 bytes */
+#define PRCM_REQ_MB3 (tcdm_base + 0xE4C) /* 372 bytes */
+#define PRCM_REQ_MB4 (tcdm_base + 0xE48) /* 4 bytes */
+#define PRCM_REQ_MB5 (tcdm_base + 0xE44) /* 4 bytes */
+#define PRCM_REQ_MB6 (tcdm_base + 0xE40) /* 4 bytes */
+#define PRCM_REQ_MB7 (tcdm_base + 0xE3C) /* 4 bytes */
+
+/*Ack Mailboxes */
+#define PRCM_ACK_MB0 (tcdm_base + 0xE08) /* 52 bytes */
+#define PRCM_ACK_MB1 (tcdm_base + 0xE04) /* 4 bytes */
+#define PRCM_ACK_MB2 (tcdm_base + 0xE00) /* 4 bytes */
+#define PRCM_ACK_MB3 (tcdm_base + 0xDFC) /* 4 bytes */
+#define PRCM_ACK_MB4 (tcdm_base + 0xDF8) /* 4 bytes */
+#define PRCM_ACK_MB5 (tcdm_base + 0xDF4) /* 4 bytes */
+#define PRCM_ACK_MB6 (tcdm_base + 0xDF0) /* 4 bytes */
+#define PRCM_ACK_MB7 (tcdm_base + 0xDEC) /* 4 bytes */
+
+/* Mailbox 0 REQs */
+#define PRCM_REQ_MB0_PWRSTTRH (PRCM_REQ_MB0 + 0x0)
+#define PRCM_REQ_MB0_PWRSTTRH_APPWRST (PRCM_REQ_MB0 + 0x0)
+#define PRCM_REQ_MB0_PWRSTTRH_APPLLST (PRCM_REQ_MB0 + 0x1)
+#define PRCM_REQ_MB0_PWRSTTRH_ULPCLKST (PRCM_REQ_MB0 + 0x2)
+#define PRCM_REQ_MB0_PWRSTTRH_BYTEFILL (PRCM_REQ_MB0 + 0x3)
+#define PRCM_REQ_MB0_WKUP_8500 (PRCM_REQ_MB0 + 0x4)
+#define PRCM_REQ_MB0_WKUP_4500 (PRCM_REQ_MB0 + 0x8)
+
+/* Mailbox 0 ACKs */
+#define PRCM_ACK_MB0_AP_PWRST_STATUS (PRCM_ACK_MB0 + 0x0)
+#define PRCM_ACK_MB0_PINGPONG_RDP (PRCM_ACK_MB0 + 0x1)
+#define PRCM_ACK_MB0_PINGPONG_WKUP_RST_0 (PRCM_ACK_MB0 + 0x2)
+#define PRCM_ACK_MB0_PINGPONG_WKUP_RST_1 (PRCM_ACK_MB0 + 0x3)
+#define PRCM_ACK_MB0_WK0_EVENT_8500 (tcdm_base + 0xE0C)
+#define PRCM_ACK_MB0_WK0_EVENT_4500 (tcdm_base + 0xE10)
+#define PRCM_ACK_MB0_WK1_EVENT_8500 (tcdm_base + 0xE24)
+#define PRCM_ACK_MB0_WK1_EVENT_4500 (tcdm_base + 0xE28)
+#define PRCM_ACK_MB0_EVENT_4500_NUMBERS 20
+
+/* Mailbox 1 Requests */
+#define PRCM_REQ_MB1_ARMOPP (PRCM_REQ_MB1 + 0x0)
+#define PRCM_REQ_MB1_APEOPP (PRCM_REQ_MB1 + 0x1)
+#define PRCM_REQ_MB1_BOOSTOPP (PRCM_REQ_MB1 + 0x2)
+
+/* Mailbox 1 ACKs */
+#define PRCM_ACK_MB1_CURR_ARMOPP (PRCM_ACK_MB1 + 0x0)
+#define PRCM_ACK_MB1_CURR_APEOPP (PRCM_ACK_MB1 + 0x1)
+#define PRCM_ACK_MB1_CURR_BOOSTOPP (PRCM_ACK_MB1 + 0x2)
+#define PRCM_ACK_MB1_CURR_DVFS_STATUS (PRCM_ACK_MB1 + 0x3)
+
+/* Mailbox 2 REQs */
+#define PRCM_REQ_MB2_DPS_SVAMMDSP (PRCM_REQ_MB2 + 0x0)
+#define PRCM_REQ_MB2_DPS_SVAPIPE (PRCM_REQ_MB2 + 0x1)
+#define PRCM_REQ_MB2_DPS_SIAMMDSP (PRCM_REQ_MB2 + 0x2)
+#define PRCM_REQ_MB2_DPS_SIAPIPE (PRCM_REQ_MB2 + 0x3)
+#define PRCM_REQ_MB2_DPS_SGA (PRCM_REQ_MB2 + 0x4)
+#define PRCM_REQ_MB2_DPS_B2R2MCDE (PRCM_REQ_MB2 + 0x5)
+#define PRCM_REQ_MB2_DPS_ESRAM12 (PRCM_REQ_MB2 + 0x6)
+#define PRCM_REQ_MB2_DPS_ESRAM34 (PRCM_REQ_MB2 + 0x7)
+#define PRCM_REQ_MB2_AUTOPWR_APSLEEP (PRCM_REQ_MB2 + 0x8)
+#define PRCM_REQ_MB2_AUTOPWR_APSLEEP_SIA_PWRON_ENABLE (PRCM_REQ_MB2 + 0x9)
+#define PRCM_REQ_MB2_AUTOPWR_APSLEEP_SVA_PWRON_ENABLE (PRCM_REQ_MB2 + 0xA)
+#define PRCM_REQ_MB2_AUTOPWR_APSLEEP_AUTO_PWRON_ENABLE (PRCM_REQ_MB2 + 0xB)
+#define PRCM_REQ_MB2_AUTOPWR_APIDLE (PRCM_REQ_MB2 + 0xC)
+#define PRCM_REQ_MB2_AUTOPWR_APIDLE_SIA_PWRON_ENABLE (PRCM_REQ_MB2 + 0xD)
+#define PRCM_REQ_MB2_AUTOPWR_APIDLE_SVA_PWRON_ENABLE (PRCM_REQ_MB2 + 0xE)
+#define PRCM_REQ_MB2_AUTOPWR_APIDLE_AUTO_PWRON_ENABLE (PRCM_REQ_MB2 + 0xF)
+
+/* Mailbox 4 Requests */
+#define PRCM_REQ_MB4_DDR_ST_AP_IDLE_SLEEP (PRCM_REQ_MB4 + 0x0)
+#define PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE (PRCM_REQ_MB4 + 0x1)
+#define PRCM_REQ_MB4_SYSCLKMGT (PRCM_REQ_MB4 + 0x0)
+
+/* Mailbox 5 Requests */
+#define PRCM_REQ_MB5_I2C_SLAVE_OP (PRCM_REQ_MB5 + 0x0)
+#define PRCM_REQ_MB5_I2C_HW_BITS (PRCM_REQ_MB5 + 0x1)
+#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 0x2)
+#define PRCM_REQ_MB5_I2C_VAL (PRCM_REQ_MB5 + 0x3)
+#define PRCMU_I2C_WRITE(slave) \
+ (((slave) << 1) | I2CWRITE | (cpu_is_u8500v2() ? BIT(6) : 0))
+#define PRCMU_I2C_READ(slave) \
+ (((slave) << 1) | I2CREAD | (cpu_is_u8500v2() ? BIT(6) : 0))
+#define PRCMU_I2C_STOP_EN BIT(3)
+
+/* Mailbox 5 ACKs */
+#define PRCM_ACK_MB5_I2C_STATUS (PRCM_ACK_MB5 + 0x1)
+#define PRCM_ACK_MB5_I2C_VAL (PRCM_ACK_MB5 + 0x3)
+
+#define NUM_MB 8
+#define MBOX_BIT BIT
+#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
+
+/*
+ * This vector maps irq numbers to the bits in the bit field used in
+ * communication with the PRCMU firmware.
+ *
+ * The reason for having this is to keep the irq numbers contiguous even though
+ * the bits in the bit field are not. (The bits also have a tendency to move
+ * around, to further complicate matters.)
+ */
+#define IRQ_INDEX(_name) ((IRQ_PRCMU_##_name) - IRQ_PRCMU_BASE)
+static u32 prcmu_irq_bit[NUM_PRCMU_WAKEUPS] = {
+ [IRQ_INDEX(RTC)] = BIT(0),
+ [IRQ_INDEX(RTT0)] = BIT(1),
+ [IRQ_INDEX(RTT1)] = BIT(2),
+ [IRQ_INDEX(HSI0)] = BIT(3),
+ [IRQ_INDEX(HSI1)] = BIT(4),
+ [IRQ_INDEX(CA_WAKE)] = BIT(5),
+ [IRQ_INDEX(USB)] = BIT(6),
+ [IRQ_INDEX(ABB)] = BIT(7),
+ [IRQ_INDEX(ABB_FIFO)] = BIT(8),
+ [IRQ_INDEX(CA_SLEEP)] = BIT(10),
+ [IRQ_INDEX(ARM)] = BIT(17),
+ [IRQ_INDEX(MODEM_SW_RESET_REQ)] = BIT(20),
+ [IRQ_INDEX(GPIO0)] = BIT(23),
+ [IRQ_INDEX(GPIO1)] = BIT(24),
+ [IRQ_INDEX(GPIO2)] = BIT(25),
+ [IRQ_INDEX(GPIO3)] = BIT(26),
+ [IRQ_INDEX(GPIO4)] = BIT(27),
+ [IRQ_INDEX(GPIO5)] = BIT(28),
+ [IRQ_INDEX(GPIO6)] = BIT(29),
+ [IRQ_INDEX(GPIO7)] = BIT(30),
+ [IRQ_INDEX(GPIO8)] = BIT(31)
+};
+
+/*
+ * mb0_transfer - state needed for mailbox 0 communication.
+ * @lock: The transaction lock.
+ * @dbb_events_lock: A lock used to handle concurrent access to (parts of)
+ * the request data.
+ * @mask_work: Work structure used for (un)masking wakeup interrupts.
+ * @req: Request data that need to persist between requests.
+ */
+static struct {
+ spinlock_t lock;
+ spinlock_t dbb_events_lock;
+ struct work_struct mask_work;
+ struct {
+ u32 dbb_events;
+ u32 abb_events;
+ u8 ap_pll_state;
+ u8 ulp_clk_state;
+ } req;
+ /*
+ * The remaining fields are for temporary backwards compatibility,
+ * and should be removed as soon as possible.
+ * They are used to make the old wakeup configuration implementation
+ * possible to use (with a few limitations) until the migration to
+ * the (virtual) irqs has been completed.
+ */
+ u32 dbb_events_as_irqs;
+ u32 dbb_exe;
+ u32 dbb_sleep;
+} mb0_transfer;
+
+/*
+ * mb1_transfer - state needed for mailbox 1 communication.
+ * @lock: The transaction lock.
+ * @work: The transaction completion structure.
+ * @ack: Reply ("acknowledge") data.
+ */
+static struct {
+ struct mutex lock;
+ struct completion work;
+ struct {
+ u8 arm_opp;
+ u8 ape_opp;
+ } ack;
+} mb1_transfer;
+
+/*
+ * mb2_transfer - state needed for mailbox 2 communication.
+ * @lock: The transaction lock.
+ * @work: The transaction completion structure.
+ * @failed: Flag used to record a failed transaction.
+ * @ack: Reply ("acknowledge") data.
+ */
+static struct {
+ struct mutex lock;
+ struct completion work;
+ bool failed;
+ struct {
+ u8 status;
+ } ack;
+} mb2_transfer;
+
+/*
+ * mb4_transfer - state needed for mailbox 4 communication.
+ * @lock: The transaction lock.
+ */
+static struct {
+ struct mutex lock;
+ struct completion work;
+ struct {
+ u8 status;
+ } ack;
+} mb4_transfer;
+
+/*
+ * mb5_transfer - state needed for mailbox 5 communication.
+ * @lock: The transaction lock.
+ * @work: The transaction completion structure.
+ * @failed: Flag used to record a failed transaction.
+ * @ack: Reply ("acknowledge") data.
+ */
+static struct {
+ struct mutex lock;
+ struct completion work;
+ bool failed;
+ struct {
+ u8 status;
+ u8 value;
+ } ack;
+} mb5_transfer;
+
+/*
+ * hw_acc_state - state used for handling the shared hw_acc controls.
+ * @b2r2_mcde: The last requested states for B2R2 and MCDE.
+ * @esram12: The last requested states for ESRAM1 and ESRAM2.
+ * @esram34: The last requested states for ESRAM3 and ESRAM4.
+ */
+static struct {
+ u8 b2r2_mcde[2];
+ u8 esram12[2];
+ u8 esram34[2];
+} hw_acc_state = {{HW_OFF, HW_OFF}, {HW_OFF, HW_OFF}, {HW_OFF, HW_OFF} };
+
+/* Spinlocks */
+static DEFINE_SPINLOCK(req_mb0_lock);
+static DEFINE_SPINLOCK(irq_wake_lock);
+static DEFINE_SPINLOCK(ac_wake_lock);
+
+/* Global var to runtime determine TCDM base for v2 or v1 */
+static __iomem void *tcdm_base;
+
+/*
+* Used by MCDE to setup all necessary PRCMU registers
+*/
+#define PRCMU_CLAMP_DSS_DSIPLL 0x00600C00
+#define PRCMU_RESET_DSS 0x0000000C
+#define PRCMU_ENABLE_DSS_MEM 0x00200000
+#define PRCMU_ENABLE_DSS_LOGIC 0x00100000
+#define PRCMU_DSS_SLEEP_OUTPUT_MASK 0x400
+#define PRCMU_UNCLAMP_DSS_DSIPLL 0x00600C00
+#define PRCMU_POWER_ON_DSI 0x00008000
+
+#define PRCMU_CLK_PLL_DIV_SHIFT 0
+#define PRCMU_CLK_PLL_SW_SHIFT 5
+#define PRCMU_CLK_EN (1 << 8)
+#define PRCMU_CLK_38 (1 << 9)
+#define PRCMU_CLK_38_SRC (1 << 10)
+#define PRCMU_CLK_38_DIV (1 << 11)
+
+#define PRCMU_DSI_CLOCK_SETTING 0x00000148
+/* DPI 50000000 Hz */
+#define PRCMU_DPI_CLOCK_SETTING (PRCMU_CLK_EN | \
+ (1 << PRCMU_CLK_PLL_SW_SHIFT) | \
+ (16 << PRCMU_CLK_PLL_DIV_SHIFT))
+#define PRCMU_DSI_LP_CLOCK_SETTING 0x00000F00
+#define PRCMU_PLLDSI_FREQ_SETTING 0x00020123
+
+#define PRCMU_ENABLE_PLLDSI 0x00000001
+#define PRCMU_RELEASE_RESET_DSS 0x0000400C
+#define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000202
+#define PRCMU_ENABLE_ESCAPE_CLOCK 0x07010101
+#define PRCMU_DSI_RESET_SW 0x00000007
+
+#define PRCMU_MCDE_DELAY 10
+
+/*
+ * locking rule: all changes to requirements or prcmu_qos_object list
+ * and prcmu_qos_objects need to happen with prcmu_qos_lock
+ * held, taken with _irqsave. One lock to rule them all
+ */
+struct requirement_list {
+ struct list_head list;
+ union {
+ s32 value;
+ s32 usec;
+ s32 kbps;
+ };
+ char *name;
+};
+
+static s32 max_compare(s32 v1, s32 v2);
+
+struct prcmu_qos_object {
+ struct requirement_list requirements;
+ struct miscdevice prcmu_qos_power_miscdev;
+ char *name;
+ s32 default_value;
+ atomic_t target_value;
+ s32 (*comparitor)(s32, s32);
+};
+
+static struct prcmu_qos_object null_qos;
+
+static struct prcmu_qos_object ape_opp_qos = {
+ .requirements = {
+ LIST_HEAD_INIT(ape_opp_qos.requirements.list)
+ },
+ .name = "ape_opp",
+ /* Target val=100 will force 100% APE OPP */
+ .default_value = 50,
+ .target_value = ATOMIC_INIT(0),
+ .comparitor = max_compare
+};
+
+static struct prcmu_qos_object *prcmu_qos_array[] = {
+ &null_qos,
+ &ape_opp_qos
+};
+
+static DEFINE_SPINLOCK(prcmu_qos_lock);
+
+int prcmu_enable_mcde(void)
+{
+#ifndef CONFIG_REGULATOR /* Only for V10 */
+ u32 temp;
+#endif
+ /* Clamp DSS out, DSIPLL in/out, (why not DSS input?) */
+ writel(PRCMU_CLAMP_DSS_DSIPLL, PRCM_MMIP_LS_CLAMP_SET);
+ mdelay(PRCMU_MCDE_DELAY);
+ /* Enable DSS_M_INITN, DSS_L_RESETN, DSIPLL_RESETN resets */
+ writel(PRCMU_RESET_DSS, PRCM_APE_RESETN_CLR);
+ mdelay(PRCMU_MCDE_DELAY);
+#ifndef CONFIG_REGULATOR /* Only for V10 */
+ /* Power on DSS mem */
+ writel(PRCMU_ENABLE_DSS_MEM, PRCM_EPOD_C_SET);
+ mdelay(PRCMU_MCDE_DELAY);
+ /* Power on DSS logic */
+ writel(PRCMU_ENABLE_DSS_LOGIC, PRCM_EPOD_C_SET);
+ mdelay(PRCMU_MCDE_DELAY);
+ /* Release DSS_SLEEP */
+ temp = readl(PRCM_SRAM_LS_SLEEP);
+ writel(temp & ~PRCMU_DSS_SLEEP_OUTPUT_MASK, PRCM_SRAM_LS_SLEEP);
+ mdelay(PRCMU_MCDE_DELAY);
+#endif
+ /* Unclamp DSS out, DSIPLL in/out, (why not DSS input?) */
+ writel(PRCMU_UNCLAMP_DSS_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
+ mdelay(PRCMU_MCDE_DELAY);
+#ifndef CONFIG_REGULATOR /* Only for V10 */
+ /* Power on CSI_DSI */
+ writel(PRCMU_POWER_ON_DSI, PRCM_POWER_STATE_SET);
+ mdelay(PRCMU_MCDE_DELAY);
+#endif
+ /* HDMI and TVCLK Should be handled somewhere else */
+ /* PLLDIV=8, PLLSW=2, CLKEN=1 */
+ writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
+ mdelay(PRCMU_MCDE_DELAY);
+ /* PLLDIV=14, PLLSW=2, CLKEN=1 */
+ writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
+ mdelay(PRCMU_MCDE_DELAY);
+ writel(PRCMU_DPI_CLOCK_SETTING, PRCM_LCDCLK_MGT);
+ mdelay(PRCMU_MCDE_DELAY);
+
+ /* D=43, N=1, R=4, SELDIV2=0 */
+ writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
+ mdelay(PRCMU_MCDE_DELAY);
+ /* Start DSI PLL */
+ writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
+ mdelay(PRCMU_MCDE_DELAY);
+ /* Release DSS_M_INITN, DSS_L_RESETN, DSIPLL_RESETN */
+ writel(PRCMU_RELEASE_RESET_DSS, PRCM_APE_RESETN_SET);
+ mdelay(PRCMU_MCDE_DELAY);
+ /* DSI0=phi/2, DSI1=phi/2 */
+ writel(PRCMU_DSI_PLLOUT_SEL_SETTING, PRCM_DSI_PLLOUT_SEL);
+ mdelay(PRCMU_MCDE_DELAY);
+ /* Enable ESC clk 0/1/2, div2=3, div1=0x17, div0=0x17 */
+ writel(PRCMU_ENABLE_ESCAPE_CLOCK, PRCM_DSITVCLK_DIV);
+ mdelay(PRCMU_MCDE_DELAY);
+ /* Release DSI reset 0/1/2 */
+ writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET);
+ mdelay(PRCMU_MCDE_DELAY);
+ return 0;
+}
+
+/**
+ * prcmu_get_boot_status - PRCMU boot status checking
+ * Returns: the current PRCMU boot status
+ */
+int prcmu_get_boot_status(void)
+{
+ return readb(PRCM_BOOT_STATUS);
+}
+
+/**
+ * prcmu_set_rc_a2p - This function is used to run few power state sequences
+ * @val: Value to be set, i.e. transition requested
+ * Returns: 0 on success, -EINVAL on invalid argument
+ *
+ * This function is used to run the following power state sequences -
+ * any state to ApReset, ApDeepSleep to ApExecute, ApExecute to ApDeepSleep
+ */
+int prcmu_set_rc_a2p(enum romcode_write val)
+{
+ if (val < RDY_2_DS || val > RDY_2_XP70_RST)
+ return -EINVAL;
+ writeb(val, PRCM_ROMCODE_A2P);
+ return 0;
+}
+
+/**
+ * prcmu_get_rc_p2a - This function is used to get power state sequences
+ * Returns: the power transition that has last happened
+ *
+ * This function can return the following transitions-
+ * any state to ApReset, ApDeepSleep to ApExecute, ApExecute to ApDeepSleep
+ */
+enum romcode_read prcmu_get_rc_p2a(void)
+{
+ return readb(PRCM_ROMCODE_P2A);
+}
+
+/**
+ * prcmu_get_current_mode - Return the current XP70 power mode
+ * Returns: Returns the current AP(ARM) power mode: init,
+ * apBoot, apExecute, apDeepSleep, apSleep, apIdle, apReset
+ */
+enum ap_pwrst prcmu_get_xp70_current_state(void)
+{
+ return readb(PRCM_XP70_CUR_PWR_STATE);
+}
+
+int prcmu_set_power_state(u8 state)
+{
+ unsigned long flags;
+
+ if ((state < APEXECUTE_TO_APSLEEP) || (APEXECUTE_TO_APIDLE < state))
+ return -EINVAL;
+
+ spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+ cpu_relax();
+
+ writeb(PWRSTTRH, PRCM_MBOX_HEADER_REQ_MB0);
+ writeb(state, PRCM_REQ_MB0_PWRSTTRH_APPWRST);
+ writeb(mb0_transfer.req.ap_pll_state, PRCM_REQ_MB0_PWRSTTRH_APPLLST);
+ writeb(mb0_transfer.req.ulp_clk_state, PRCM_REQ_MB0_PWRSTTRH_ULPCLKST);
+ writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
+
+ spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+
+ return 0;
+}
+
+/* This function should only be called while mb0_transfer.lock is held. */
+static void config_wakeups(u32 dbb_events, u32 abb_events)
+{
+ const u8 header[2] = {WKUPCFG_EXEH, WKUPCFG_SLEEPH};
+ unsigned int i;
+
+ /* CA_SLEEP is not yet part of the mailbox 0 wakeups. */
+ dbb_events &= ~prcmu_irq_bit[IRQ_INDEX(CA_SLEEP)];
+
+ /* Temporary backward compatibility hack. */
+ dbb_events |= ((mb0_transfer.dbb_sleep | mb0_transfer.dbb_exe) &
+ ~mb0_transfer.dbb_events_as_irqs);
+
+ for (i = 0; i < 2; i++) {
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+ cpu_relax();
+ writel(dbb_events, PRCM_REQ_MB0_WKUP_8500);
+ writel(abb_events, PRCM_REQ_MB0_WKUP_4500);
+ writeb(header[i], PRCM_MBOX_HEADER_REQ_MB0);
+ writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
+ }
+}
+
+/**
+ * prcmu_configure_wakeup_events - configure DB8500 and AB8500 events
+ * @dbb_events: DB8500 wakeup events
+ * @abb_events: AB8500 wakeup events
+ * @low_power: Configure for low power mode
+ *
+ * THIS FUNCTION IS DEPRECATED, AND WILL BE REMOVED IN THE NEAR FUTURE.
+ */
+int prcmu_configure_wakeup_events(u32 dbb_events, u32 abb_events,
+ int low_power)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+ if (low_power)
+ mb0_transfer.dbb_sleep = dbb_events;
+ else
+ mb0_transfer.dbb_exe = dbb_events;
+
+ config_wakeups(mb0_transfer.req.dbb_events,
+ mb0_transfer.req.abb_events);
+ dbb_events &= mb0_transfer.dbb_events_as_irqs;
+
+ spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+
+ if (dbb_events) {
+ pr_warning("%s: configuration conflicting with irqs "
+ "(%.8X).\n", __func__, dbb_events);
+ }
+ return 0;
+}
+
+void prcmu_config_abb_event_readout(u32 abb_events)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+ mb0_transfer.req.abb_events = abb_events;
+ config_wakeups(mb0_transfer.req.dbb_events, abb_events);
+
+ spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+/**
+ * prcmu_set_arm_opp - set the appropriate ARM OPP
+ * @opp: The new ARM operating point to which transition is to be made
+ * Returns: 0 on success, non-zero on failure
+ *
+ * This function sets the the operating point of the ARM.
+ */
+int prcmu_set_arm_opp(u8 opp)
+{
+ int r;
+
+ if (opp < ARM_NO_CHANGE || opp > ARM_EXTCLK)
+ return -EINVAL;
+
+ r = 0;
+ mutex_lock(&mb1_transfer.lock);
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+ cpu_relax();
+
+ writeb(0, PRCM_MBOX_HEADER_REQ_MB0);
+ writeb(opp, PRCM_REQ_MB1_ARMOPP);
+ writeb(APE_NO_CHANGE, PRCM_REQ_MB1_APEOPP);
+ writeb(OFF, PRCM_REQ_MB1_BOOSTOPP);
+
+ writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
+ wait_for_completion(&mb1_transfer.work);
+
+ if (mb1_transfer.ack.arm_opp != opp)
+ r = -EIO;
+
+ mutex_unlock(&mb1_transfer.lock);
+ return r;
+}
+
+/**
+ * prcmu_get_arm_opp - get the current ARM OPP
+ *
+ * Returns: the current ARM OPP
+ */
+int prcmu_get_arm_opp(void)
+{
+ return readb(PRCM_ACK_MB1_CURR_ARMOPP);
+}
+
+static int set_ape_opp(u8 opp)
+{
+ int r = 0;
+ mutex_lock(&mb1_transfer.lock);
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+ cpu_relax();
+
+ writeb(0, PRCM_MBOX_HEADER_REQ_MB0);
+ writeb(ARM_NO_CHANGE, PRCM_REQ_MB1_ARMOPP);
+ writeb(opp, PRCM_REQ_MB1_APEOPP);
+ writeb(OFF, PRCM_REQ_MB1_BOOSTOPP);
+
+ writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
+ wait_for_completion(&mb1_transfer.work);
+
+ if (mb1_transfer.ack.ape_opp != opp)
+ r = -EIO;
+
+ mutex_unlock(&mb1_transfer.lock);
+ return r;
+}
+
+/**
+ * prcmu_get_ape_opp - get the current APE OPP
+ *
+ * Returns: the current APE OPP
+ */
+int prcmu_get_ape_opp(void)
+{
+ return readb(PRCM_ACK_MB1_CURR_APEOPP);
+}
+
+/**
+ * prcmu_set_hwacc - set the power state of a h/w accelerator
+ * @hw_acc_dev: The hardware accelerator (enum hw_acc_dev).
+ * @state: The new power state (enum hw_acc_state).
+ *
+ * This function sets the power state of a hardware accelerator.
+ * This function should not be called from interrupt context.
+ */
+int prcmu_set_hwacc(u16 hw_acc_dev, u8 state)
+{
+ int r;
+ unsigned int i;
+ u8 old_state;
+ u8 alt_state;
+
+ if (state == HW_NO_CHANGE)
+ return 0;
+ if (state > HW_ON)
+ return -EINVAL;
+
+ i = (hw_acc_dev >> 8) & 1;
+ hw_acc_dev &= 0xFF;
+
+ mutex_lock(&mb2_transfer.lock);
+
+ if (mb2_transfer.failed) {
+ r = -EIO;
+ goto unlock_and_return;
+ }
+
+ switch (hw_acc_dev) {
+ case B2R2MCDE:
+ alt_state = hw_acc_state.b2r2_mcde[1 - i];
+ old_state = max(hw_acc_state.b2r2_mcde[i], alt_state);
+ hw_acc_state.b2r2_mcde[i] = state;
+ break;
+ case ESRAM12:
+ alt_state = hw_acc_state.esram12[1 - i];
+ old_state = max(hw_acc_state.esram12[i], alt_state);
+ hw_acc_state.esram12[i] = state;
+ break;
+ case ESRAM34:
+ alt_state = hw_acc_state.esram34[1 - i];
+ old_state = max(hw_acc_state.esram34[i], alt_state);
+ hw_acc_state.esram34[i] = state;
+ break;
+ case SVAMMDSP:
+ case SVAPIPE:
+ case SIAMMDSP:
+ case SIAPIPE:
+ case SGA:
+ alt_state = state;
+ old_state = HW_NO_CHANGE;
+ break;
+ default:
+ r = -EINVAL;
+ goto unlock_and_return;
+ }
+ state = max(state, alt_state);
+ if (state == old_state) {
+ r = 0;
+ goto unlock_and_return;
+ }
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(2))
+ cpu_relax();
+
+ for (i = 0; i < 8; i++) {
+ writeb((u8)((i == hw_acc_dev) ? state : HW_NO_CHANGE),
+ PRCM_REQ_MB2 + i);
+ }
+ writeb(DPS_H, PRCM_MBOX_HEADER_REQ_MB2);
+
+ writel(MBOX_BIT(2), PRCM_MBOX_CPU_SET);
+
+ /*
+ * The current firmware version does not handle errors correctly,
+ * and we cannot recover if there is an error.
+ * This is expected to change when the firmware is updated.
+ */
+ if (!wait_for_completion_timeout(&mb2_transfer.work,
+ msecs_to_jiffies(500))) {
+ pr_err("prcmu: set_hwacc() failed.\n"
+ "prcmu: Please check your firmware version.\n");
+ mb2_transfer.failed = true;
+ r = -EIO;
+ goto unlock_and_return;
+ }
+
+ r = ((mb2_transfer.ack.status == HWACC_PWRST_OK) ? 0 : -EIO);
+
+unlock_and_return:
+ mutex_unlock(&mb2_transfer.lock);
+ return r;
+}
+
+/**
+ * prcmu_configure_auto_pwr_mgt - Configure Auto Pwr Mgt
+ * @apsleep: Policy for ApSleep
+ * @apidle: Policy for ApIdle
+ *
+ * Use this API to configure autonomous power management
+ * and controlling hw semaphores
+ */
+int prcmu_configure_auto_pwr_mgt(struct sia_sva_auto_power apsleep,
+ struct sia_sva_auto_power apidle)
+{
+ /* Not implemented in firmware yet. */
+ return -ENOSYS;
+}
+
+/**
+ * prcmu_set_irq_wakeup - set the ARM IRQ wake-up events
+ * @irq: ARM IRQ that needs to be set as wake up source
+ * Returns: 0 on success, -EINVAL on invalid argument
+ */
+int prcmu_set_irq_wakeup(u32 irq)
+{
+ void __iomem *mask_reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_wake_lock, flags);
+
+ if (irq < 32) {
+ mask_reg = PRCM_ARMITMSK31TO0;
+ } else if (irq < 64) {
+ mask_reg = PRCM_ARMITMSK63TO32;
+ irq -= 32;
+ } else if (irq < 96) {
+ mask_reg = PRCM_ARMITMSK95TO64;
+ irq -= 64;
+ } else if (irq < 128) {
+ mask_reg = PRCM_ARMITMSK127TO96;
+ irq -= 96;
+ } else {
+ spin_unlock_irqrestore(&irq_wake_lock, flags);
+ return -EINVAL;
+ }
+
+ writel(1 << irq | readl((unsigned long *)(mask_reg)),
+ (unsigned long *)(mask_reg));
+
+ spin_unlock_irqrestore(&irq_wake_lock, flags);
+
+ return 0;
+}
+
+/* FIXME : get these from platform/header files instead */
+/* GIC BAse Address */
+#define GIC_BASE_ADDR IO_ADDRESS(0xA0411000)
+
+/* ITs enabled for GIC. 104 is due to skipping of the STI and PPI sets.
+ * * Rfer page 648 of the DB8500V1 spec v2.5
+ * */
+#define DIST_ENABLE_SET (GIC_BASE_ADDR + 0x104)
+
+/**
+ * prcmu_apply_ap_state_transition - PRCMU State Transition function
+ * @transition: Transition to be requested to move to new AP power mode
+ * @ddr_state_req: Power mode of DDR to which DDR needs to be switched
+ * @_4500_fifo_wakeup: 4500 fifo interrupt to be configured as wakeup or not
+ * Returns: 0 on success, -EINVAL on failure
+ *
+ * NOTES: This routine assumes that ARM side housekeeping that
+ * needs to be done before entering sleep/deep-sleep, eg. the routines
+ * begin(), prepare() in platform_suspend_ops have done their job
+ * this routine only makes the required state transition and post-transition
+ * ARM side handling e.g. calling WFI for the non-boot cpus for idle/sleep
+ * or either waiting for the go-ahead from the deep-sleep secure interrupt
+ * handler and then setting the romcode before entering wfi. The typical
+ * users of this routine are the CPUIdle and LDM suspend ie. pm_suspend().
+ * The accelerators also need this service but currently this routine does
+ * not support it. This also assumes that the non-boot cpu's are in wfi
+ * and not wfe.
+ *
+ * THIS FUNCTION IS DEPRECATED, AND WILL BE REMOVED IN THE NEAR FUTURE.
+ */
+int prcmu_apply_ap_state_transition(enum ap_pwrst_trans transition,
+ enum ddr_pwrst ddr_state_req,
+ int _4500_fifo_wakeup)
+{
+ int ret = 0;
+ unsigned int val = 0, tmp ;
+
+ switch (transition) {
+ case APEXECUTE_TO_APIDLE:
+ /* Copy the current GIC set enable config as wakeup */
+ for (val = 0; val < 4; val++) {
+ tmp = readl(DIST_ENABLE_SET + (val * 4));
+ writel(tmp, PRCM_ARMITMSK31TO0 + (val * 4));
+ }
+
+ prcmu_configure_wakeup_events((PRCMU_WAKEUPBY_ARMITMGMT |
+ PRCMU_WAKEUPBY_MODEM |
+ PRCMU_WAKEUPBY_MODEM_SW_RESET_REQ),
+ PRCMU_WAKEUPBY_AB8500_NONE,
+ EXE_WAKEUP);
+
+ spin_lock(&req_mb0_lock);
+
+ /* As per the sync logic, we are supposed to be the final CPU.
+ * If the other CPU isnt in wfi, better exit by putting
+ * ourselves in wfi
+ */
+ if (smp_processor_id()) {
+ if (!(readl(PRCM_ARM_WFI_STANDBY) & 0x8)) {
+ spin_unlock(&req_mb0_lock);
+ __asm__ __volatile__(
+ "dsb\n\t" "wfi\n\t" : : : "memory");
+ return 0;
+ }
+ } else /* running on CPU0, check for CPU1 WFI standby */ {
+ if (!(readl(PRCM_ARM_WFI_STANDBY) & 0x10)) {
+ spin_unlock(&req_mb0_lock);
+ __asm__ __volatile__(
+ "dsb\n\t" "wfi\n\t" : : : "memory");
+ return 0;
+ }
+ }
+
+ /* FIXME : temporary hack to let UART2 interrupts enable the
+ * wake-up from ARM
+ */
+ if (!(readl(PRCM_ARMITMSK31TO0) & 0x04000000))
+ writel((readl(PRCM_ARMITMSK31TO0) | 0x04000000),
+ PRCM_ARMITMSK31TO0);
+
+ /* FIXME : tempoeary hack to wake up from RTC */
+ if (!(readl(PRCM_ARMITMSK31TO0) & 0x40000))
+ writel((readl(PRCM_ARMITMSK31TO0) | 0x40000),
+ PRCM_ARMITMSK31TO0);
+
+ /* FIXME : later on, the ARM should not request a Idle if one
+ * of the ITSTATUS0/5 are still alive!!!
+ */
+ if (readl(PRCM_ITSTATUS0) == 0x80) {
+ printk(KERN_WARNING "PRCM_ITSTATUS0 Not cleared\n");
+ spin_unlock(&req_mb0_lock);
+ __asm__ __volatile__(
+ "dsb\n\t" "wfi\n\t" : : : "memory");
+ return -EBUSY;
+ }
+
+ /* REQUEST POWER XSITION */
+ (void)prcmu_set_power_state(APEXECUTE_TO_APIDLE);
+ spin_unlock(&req_mb0_lock);
+
+ /* here comes the wfi */
+ __asm__ __volatile__("dsb\n\t" "wfi\n\t" : : : "memory");
+
+ prcmu_configure_wakeup_events((PRCMU_WAKEUPBY_MODEM |
+ PRCMU_WAKEUPBY_MODEM_SW_RESET_REQ),
+ PRCMU_WAKEUPBY_AB8500_NONE, EXE_WAKEUP);
+
+ break;
+
+ case APEXECUTE_TO_APSLEEP:
+ case APEXECUTE_TO_APDEEPSLEEP:
+ (void)prcmu_set_power_state(transition);
+ __asm__ __volatile__("dsb\n\t" "wfi\n\t" : : : "memory");
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+
+}
+
+static int request_sysclk(bool enable)
+{
+ int r;
+ int state;
+
+ r = 0;
+ state = (enable ? ON : OFF);
+
+ mutex_lock(&mb4_transfer.lock);
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+ cpu_relax();
+
+ writeb(SYSCLK_H, PRCM_MBOX_HEADER_REQ_MB4);
+ /*
+ * We use writel, since the firmware API specifies the SysClkMgt
+ * field as an enum (which is an int).
+ */
+ writel(state, PRCM_REQ_MB4_SYSCLKMGT);
+
+ writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
+
+ /* The firmware only sends an ACK if we want to enable the SysClk. */
+ if (enable) {
+ wait_for_completion(&mb4_transfer.work);
+ if (mb4_transfer.ack.status != SYSCLKON_OK)
+ r = -EIO;
+ }
+
+ mutex_unlock(&mb4_transfer.lock);
+
+ return r;
+}
+
+/**
+ * prcmu_request_clock() - Request for a clock to be enabled or disabled.
+ * @clock: The clock for which the request is made.
+ * @enable: Whether the clock should be enabled (true) or disabled (false).
+ *
+ * Currently only SysClk is supported by the U8500 firmware, but this is
+ * expected to change.
+ */
+int prcmu_request_clock(u8 clock, bool enable)
+{
+ if (clock == PRCMU_SYSCLK)
+ return request_sysclk(enable);
+ else
+ return -EINVAL;
+}
+
+/**
+ * prcmu_abb_read() - Read register value(s) from the ABB.
+ * @slave: The I2C slave address.
+ * @reg: The (start) register address.
+ * @value: The read out value(s).
+ * @size: The number of registers to read.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ int r;
+
+ if (size != 1)
+ return -EINVAL;
+
+ if (cpu_is_u8500v11() || cpu_is_u8500v2())
+ mutex_lock(&mb5_transfer.lock);
+ else
+ mutex_lock(&mb4_transfer.lock);
+
+ if (mb5_transfer.failed) {
+ mb5_transfer.failed = false;
+ } else {
+ if (cpu_is_u8500v11() || cpu_is_u8500v2()) {
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+ cpu_relax();
+ } else {
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+ cpu_relax();
+ }
+ }
+ writeb(PRCMU_I2C_READ(slave), PRCM_REQ_MB5_I2C_SLAVE_OP);
+ writeb(PRCMU_I2C_STOP_EN, PRCM_REQ_MB5_I2C_HW_BITS);
+ writeb(reg, PRCM_REQ_MB5_I2C_REG);
+ writeb(0, PRCM_REQ_MB5_I2C_VAL);
+
+ writeb(ACKMB5_INIT, PRCM_ACK_MB5_I2C_STATUS);
+
+ if (cpu_is_u8500v11() || cpu_is_u8500v2()) {
+ /* No header. */
+ writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+ } else {
+ writeb(WORKAROUND2_H, PRCM_MBOX_HEADER_REQ_MB4);
+ writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
+ }
+
+ /*
+ * If the transaction fails, the current firmware does not
+ * send any reply, but it does update the status.
+ * The mailbox should not be read from here, but we have no
+ * other way to catch this, and the mailbox is only used for
+ * one thing.
+ */
+ while (true) {
+ u8 status;
+
+ if (wait_for_completion_timeout(&mb5_transfer.work,
+ msecs_to_jiffies(5))) {
+ r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
+ break;
+ }
+ status = readb(PRCM_ACK_MB5_I2C_STATUS);
+ if ((status != ACKMB5_INIT) && (status != I2C_RD_OK)) {
+ mb5_transfer.failed = true;
+ r = -EIO;
+ break;
+ }
+ }
+
+ if (!r)
+ *value = mb5_transfer.ack.value;
+
+ if (cpu_is_u8500v11() || cpu_is_u8500v2())
+ mutex_unlock(&mb5_transfer.lock);
+ else
+ mutex_unlock(&mb4_transfer.lock);
+
+ return r;
+}
+
+/**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave: The I2C slave address.
+ * @reg: The (start) register address.
+ * @value: The value(s) to write.
+ * @size: The number of registers to write.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ int r;
+
+ if (size != 1)
+ return -EINVAL;
+
+ if (cpu_is_u8500v11() || cpu_is_u8500v2())
+ mutex_lock(&mb5_transfer.lock);
+ else
+ mutex_lock(&mb4_transfer.lock);
+
+ if (mb5_transfer.failed) {
+ mb5_transfer.failed = false;
+ } else {
+ if (cpu_is_u8500v11() || cpu_is_u8500v2()) {
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+ cpu_relax();
+ } else {
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+ cpu_relax();
+ }
+ }
+ writeb(PRCMU_I2C_WRITE(slave), PRCM_REQ_MB5_I2C_SLAVE_OP);
+ writeb(PRCMU_I2C_STOP_EN, PRCM_REQ_MB5_I2C_HW_BITS);
+ writeb(reg, PRCM_REQ_MB5_I2C_REG);
+ writeb(*value, PRCM_REQ_MB5_I2C_VAL);
+
+ writeb(ACKMB5_INIT, PRCM_ACK_MB5_I2C_STATUS);
+
+ if (cpu_is_u8500v11() || cpu_is_u8500v2()) {
+ /* No header. */
+ writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+ } else {
+ writeb(WORKAROUND2_H, PRCM_MBOX_HEADER_REQ_MB4);
+ writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
+ }
+
+ /*
+ * If the transaction fails, the current firmware does not
+ * send any reply, but it does update the status.
+ * The mailbox should not be read from here, but we have no
+ * other way to catch this, and the mailbox is only used for
+ * one thing.
+ */
+ while (true) {
+ u8 status;
+
+ if (wait_for_completion_timeout(&mb5_transfer.work,
+ msecs_to_jiffies(5))) {
+ r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
+ break;
+ }
+ status = readb(PRCM_ACK_MB5_I2C_STATUS);
+ if ((status != ACKMB5_INIT) && (status != I2C_WR_OK)) {
+ mb5_transfer.failed = true;
+ r = -EIO;
+ break;
+ }
+ }
+
+ if (cpu_is_u8500v11() || cpu_is_u8500v2())
+ mutex_unlock(&mb5_transfer.lock);
+ else
+ mutex_unlock(&mb4_transfer.lock);
+
+ return r;
+}
+
+/**
+ * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
+ */
+int prcmu_ac_wake_req()
+{
+ u32 val;
+ unsigned long flags;
+ int timeout = 1000;
+
+ spin_lock_irqsave(&ac_wake_lock, flags);
+
+ val = readl(PRCM_HOSTACCESS_REQ);
+
+ /* If prcm_hostaccess_req is already active, just return. */
+ if (val & ARM_WAKEUP_MODEM)
+ goto unlock_and_return;
+
+ writel((val | ARM_WAKEUP_MODEM), PRCM_HOSTACCESS_REQ);
+ while ((readb(PRCM_ACK_MB7) != HOST_PORT_ACK) && timeout--)
+ cpu_relax();
+ val = readb(PRCM_ACK_MB7);
+
+unlock_and_return:
+ spin_unlock_irqrestore(&ac_wake_lock, flags);
+
+ if (timeout)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+/**
+ * prcmu_ac_sleep_req - called when ARM no longer needs to talk to modem
+ */
+int prcmu_ac_sleep_req()
+{
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ac_wake_lock, flags);
+
+ val = readl(PRCM_HOSTACCESS_REQ);
+ writel((val & ~ARM_WAKEUP_MODEM), PRCM_HOSTACCESS_REQ);
+
+ spin_unlock_irqrestore(&ac_wake_lock, flags);
+
+ return 0;
+}
+
+/**
+ * prcmu_system_reset - System reset
+ *
+ * Sets the APE_SOFRST register which fires interrupt to fw
+ */
+void prcmu_system_reset(void)
+{
+ writel(1, PRCM_APE_SOFTRST);
+}
+
+static void ack_dbb_wakeup(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+ cpu_relax();
+
+ writeb(RDWKUPACKH, PRCM_MBOX_HEADER_REQ_MB0);
+ writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
+
+ spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+static inline void print_unknown_header_warning(u8 n, u8 header)
+{
+ pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
+ header, n);
+}
+
+static bool read_mailbox_0(void)
+{
+ bool r;
+ u32 ev;
+ unsigned int n;
+ u8 header;
+
+ header = readb(PRCM_MBOX_HEADER_ACK_MB0);
+ switch (header) {
+ case WKUP_EXEH:
+ case WKUP_SLEEPH:
+ if (readb(PRCM_ACK_MB0_PINGPONG_RDP) & 1)
+ ev = readl(PRCM_ACK_MB0_WK1_EVENT_8500);
+ else
+ ev = readl(PRCM_ACK_MB0_WK0_EVENT_8500);
+ ev &= mb0_transfer.req.dbb_events;
+
+ /* CA_SLEEP is currently delivered in mailbox 7. */
+ ev &= ~prcmu_irq_bit[IRQ_INDEX(CA_SLEEP)];
+
+ for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) {
+ if (ev & prcmu_irq_bit[n])
+ generic_handle_irq(IRQ_PRCMU_BASE + n);
+ }
+ r = true;
+ break;
+ default:
+ print_unknown_header_warning(0, header);
+ r = false;
+ break;
+ }
+ writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
+ return r;
+}
+
+static bool read_mailbox_1(void)
+{
+ mb1_transfer.ack.arm_opp = readb(PRCM_ACK_MB1_CURR_ARMOPP);
+ mb1_transfer.ack.ape_opp = readb(PRCM_ACK_MB1_CURR_APEOPP);
+ complete(&mb1_transfer.work);
+ writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_2(void)
+{
+ if (!mb2_transfer.failed) {
+ mb2_transfer.ack.status = readb(PRCM_ACK_MB2);
+ complete(&mb2_transfer.work);
+ }
+ writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_3(void)
+{
+ writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_4(void)
+{
+ u8 header;
+
+ header = readb(PRCM_MBOX_HEADER_ACK_MB4);
+ switch (header) {
+ case SYSCLK_H:
+ mb4_transfer.ack.status = readb(PRCM_ACK_MB4);
+ complete(&mb4_transfer.work);
+ break;
+ default:
+ print_unknown_header_warning(4, header);
+ break;
+ }
+ writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_5(void)
+{
+ mb5_transfer.ack.status = readb(PRCM_ACK_MB5_I2C_STATUS);
+ mb5_transfer.ack.value = readb(PRCM_ACK_MB5_I2C_VAL);
+ complete(&mb5_transfer.work);
+ writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_6(void)
+{
+ writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_7(void)
+{
+ u8 header;
+
+ header = readb(PRCM_ACK_MB7);
+ switch (header) {
+ case CA_SLEEP_REQ:
+ if (mb0_transfer.req.dbb_events &
+ prcmu_irq_bit[IRQ_INDEX(CA_SLEEP)])
+ generic_handle_irq(IRQ_PRCMU_CA_SLEEP);
+ break;
+ case HOST_PORT_ACK:
+ /* TODO: I have been told that this never happens, although
+ * it should. This has to be investigated further.
+ */
+ pr_warning("prcmu: HOST_PORT_ACK received in mailbox 7.\n");
+ break;
+ default:
+ print_unknown_header_warning(7, header);
+ break;
+ }
+ writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool (* const read_mailbox[NUM_MB])(void) = {
+ read_mailbox_0,
+ read_mailbox_1,
+ read_mailbox_2,
+ read_mailbox_3,
+ read_mailbox_4,
+ read_mailbox_5,
+ read_mailbox_6,
+ read_mailbox_7
+};
+
+/* static helper function */
+static s32 max_compare(s32 v1, s32 v2)
+{
+ return max(v1, v2);
+}
+
+static void update_target(int target)
+{
+ s32 extreme_value;
+ struct requirement_list *node;
+ unsigned long flags;
+ int update = 0;
+ u8 op;
+
+ spin_lock_irqsave(&prcmu_qos_lock, flags);
+ extreme_value = prcmu_qos_array[target]->default_value;
+ list_for_each_entry(node,
+ &prcmu_qos_array[target]->requirements.list, list) {
+ extreme_value = prcmu_qos_array[target]->comparitor(
+ extreme_value, node->value);
+ }
+ if (atomic_read(&prcmu_qos_array[target]->target_value)
+ != extreme_value) {
+ update = 1;
+ atomic_set(&prcmu_qos_array[target]->target_value,
+ extreme_value);
+ pr_info("prcmu qos: new target for qos %d is %d\n", target,
+ atomic_read(&prcmu_qos_array[target]->target_value));
+ }
+ spin_unlock_irqrestore(&prcmu_qos_lock, flags);
+
+ if (update) {
+ switch (extreme_value) {
+ case 50:
+ op = APE_50_OPP;
+ pr_debug("prcmu qos: set ape opp to 50%%\n");
+ break;
+ case 100:
+ op = APE_100_OPP;
+ pr_debug("prcmu qos: set ape opp to 100%%\n");
+ break;
+ default:
+ pr_err("prcmu qos: Incorrect target value (%d)",
+ extreme_value);
+ return;
+ }
+ set_ape_opp(op);
+ }
+}
+
+/**
+ * prcmu_qos_requirement - returns current prcmu qos expectation
+ * @prcmu_qos_class: identification of which qos value is requested
+ *
+ * This function returns the current target value in an atomic manner.
+ */
+int prcmu_qos_requirement(int prcmu_qos_class)
+{
+ return atomic_read(&prcmu_qos_array[prcmu_qos_class]->target_value);
+}
+EXPORT_SYMBOL_GPL(prcmu_qos_requirement);
+
+/**
+ * prcmu_qos_add_requirement - inserts new qos request into the list
+ * @prcmu_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ * @value: defines the qos request
+ *
+ * This function inserts a new entry in the prcmu_qos_class list of requested
+ * qos performance characteristics. It recomputes the aggregate QoS
+ * expectations for the prcmu_qos_class of parameters.
+ */
+int prcmu_qos_add_requirement(int prcmu_qos_class, char *name, s32 value)
+{
+ struct requirement_list *dep;
+ unsigned long flags;
+
+ dep = kzalloc(sizeof(struct requirement_list), GFP_KERNEL);
+ if (dep < 0)
+ return -ENOMEM;
+
+ if (value == PRCMU_QOS_DEFAULT_VALUE)
+ dep->value = prcmu_qos_array[prcmu_qos_class]->default_value;
+ else
+ dep->value = value;
+ dep->name = kstrdup(name, GFP_KERNEL);
+ if (!dep->name)
+ goto cleanup;
+
+ spin_lock_irqsave(&prcmu_qos_lock, flags);
+ list_add(&dep->list,
+ &prcmu_qos_array[prcmu_qos_class]->requirements.list);
+ spin_unlock_irqrestore(&prcmu_qos_lock, flags);
+ update_target(prcmu_qos_class);
+
+ return 0;
+
+cleanup:
+ kfree(dep);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(prcmu_qos_add_requirement);
+
+/**
+ * prcmu_qos_update_requirement - modifies an existing qos request
+ * @prcmu_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ * @value: defines the qos request
+ *
+ * Updates an existing qos requirement for the prcmu_qos_class of parameters
+ * along with updating the target prcmu_qos_class value.
+ *
+ * If the named request isn't in the list then no change is made.
+ */
+int prcmu_qos_update_requirement(int prcmu_qos_class, char *name, s32 new_value)
+{
+ unsigned long flags;
+ struct requirement_list *node;
+ int pending_update = 0;
+
+ spin_lock_irqsave(&prcmu_qos_lock, flags);
+ list_for_each_entry(node,
+ &prcmu_qos_array[prcmu_qos_class]->requirements.list, list) {
+ if (strcmp(node->name, name) == 0) {
+ if (new_value == PRCMU_QOS_DEFAULT_VALUE)
+ node->value =
+ prcmu_qos_array[prcmu_qos_class]->default_value;
+ else
+ node->value = new_value;
+ pending_update = 1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&prcmu_qos_lock, flags);
+ if (pending_update)
+ update_target(prcmu_qos_class);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(prcmu_qos_update_requirement);
+
+/**
+ * prcmu_qos_remove_requirement - modifies an existing qos request
+ * @prcmu_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ *
+ * Will remove named qos request from prcmu_qos_class list of parameters and
+ * recompute the current target value for the prcmu_qos_class.
+ */
+void prcmu_qos_remove_requirement(int prcmu_qos_class, char *name)
+{
+ unsigned long flags;
+ struct requirement_list *node;
+ int pending_update = 0;
+
+ spin_lock_irqsave(&prcmu_qos_lock, flags);
+ list_for_each_entry(node,
+ &prcmu_qos_array[prcmu_qos_class]->requirements.list, list) {
+ if (strcmp(node->name, name) == 0) {
+ kfree(node->name);
+ list_del(&node->list);
+ kfree(node);
+ pending_update = 1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&prcmu_qos_lock, flags);
+ if (pending_update)
+ update_target(prcmu_qos_class);
+}
+EXPORT_SYMBOL_GPL(prcmu_qos_remove_requirement);
+
+#define PID_NAME_LEN 32
+
+static int prcmu_qos_power_open(struct inode *inode, struct file *filp)
+{
+ int ret;
+ char name[PID_NAME_LEN];
+ long prcmu_qos_class = PRCMU_QOS_APE_OPP;
+
+ filp->private_data = (void *)prcmu_qos_class;
+ snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
+ ret = prcmu_qos_add_requirement(prcmu_qos_class, name,
+ PRCMU_QOS_DEFAULT_VALUE);
+ if (ret >= 0)
+ return 0;
+
+ return -EPERM;
+}
+
+static int prcmu_qos_power_release(struct inode *inode, struct file *filp)
+{
+ int prcmu_qos_class;
+ char name[PID_NAME_LEN];
+
+ prcmu_qos_class = (long)filp->private_data;
+ snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
+ prcmu_qos_remove_requirement(prcmu_qos_class, name);
+
+ return 0;
+}
+
+static ssize_t prcmu_qos_power_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ s32 value;
+ int prcmu_qos_class;
+ char name[PID_NAME_LEN];
+
+ prcmu_qos_class = (long)filp->private_data;
+ if (count != sizeof(s32))
+ return -EINVAL;
+ if (copy_from_user(&value, buf, sizeof(s32)))
+ return -EFAULT;
+ snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
+ prcmu_qos_update_requirement(prcmu_qos_class, name, value);
+
+ return sizeof(s32);
+}
+
+/* Functions to provide QoS to user space */
+static const struct file_operations prcmu_qos_power_fops = {
+ .write = prcmu_qos_power_write,
+ .open = prcmu_qos_power_open,
+ .release = prcmu_qos_power_release,
+};
+
+static int register_prcmu_qos_misc(struct prcmu_qos_object *qos)
+{
+ qos->prcmu_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
+ qos->prcmu_qos_power_miscdev.name = qos->name;
+ qos->prcmu_qos_power_miscdev.fops = &prcmu_qos_power_fops;
+
+ return misc_register(&qos->prcmu_qos_power_miscdev);
+}
+
+static irqreturn_t prcmu_irq_handler(int irq, void *data)
+{
+ u32 bits;
+ u8 n;
+ irqreturn_t r;
+
+ bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
+ if (unlikely(!bits))
+ return IRQ_NONE;
+
+ r = IRQ_HANDLED;
+ for (n = 0; bits; n++) {
+ if (bits & MBOX_BIT(n)) {
+ bits -= MBOX_BIT(n);
+ if (read_mailbox[n]())
+ r = IRQ_WAKE_THREAD;
+ }
+ }
+ return r;
+}
+
+static irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
+{
+ ack_dbb_wakeup();
+ return IRQ_HANDLED;
+}
+
+static void prcmu_mask_work(struct work_struct *work)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+ config_wakeups(mb0_transfer.req.dbb_events,
+ mb0_transfer.req.abb_events);
+
+ spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+static void prcmu_irq_mask(unsigned int irq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.dbb_events_lock, flags);
+
+ mb0_transfer.req.dbb_events &= ~prcmu_irq_bit[irq - IRQ_PRCMU_BASE];
+ mb0_transfer.dbb_events_as_irqs |= prcmu_irq_bit[irq - IRQ_PRCMU_BASE];
+
+ spin_unlock_irqrestore(&mb0_transfer.dbb_events_lock, flags);
+
+ if (irq != IRQ_PRCMU_CA_SLEEP)
+ schedule_work(&mb0_transfer.mask_work);
+}
+
+static void prcmu_irq_unmask(unsigned int irq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.dbb_events_lock, flags);
+
+ mb0_transfer.req.dbb_events |= prcmu_irq_bit[irq - IRQ_PRCMU_BASE];
+ mb0_transfer.dbb_events_as_irqs |= prcmu_irq_bit[irq - IRQ_PRCMU_BASE];
+
+ spin_unlock_irqrestore(&mb0_transfer.dbb_events_lock, flags);
+
+ if (irq != IRQ_PRCMU_CA_SLEEP)
+ schedule_work(&mb0_transfer.mask_work);
+}
+
+static void noop(unsigned int irq)
+{
+}
+
+static struct irq_chip prcmu_irq_chip = {
+ .name = "prcmu",
+ .disable = prcmu_irq_mask,
+ .ack = noop,
+ .mask = prcmu_irq_mask,
+ .unmask = prcmu_irq_unmask,
+};
+
+void __init prcmu_early_init(void)
+{
+ unsigned int i;
+
+ if (cpu_is_u8500v1()) {
+ tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1);
+ } else if (cpu_is_u8500v2()) {
+ tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
+ } else {
+ pr_err("prcmu: Unsupported chip version\n");
+ BUG();
+ }
+
+ spin_lock_init(&mb0_transfer.lock);
+ spin_lock_init(&mb0_transfer.dbb_events_lock);
+ mutex_init(&mb1_transfer.lock);
+ init_completion(&mb1_transfer.work);
+ mutex_init(&mb2_transfer.lock);
+ init_completion(&mb2_transfer.work);
+ mutex_init(&mb4_transfer.lock);
+ init_completion(&mb4_transfer.work);
+ mutex_init(&mb5_transfer.lock);
+ init_completion(&mb5_transfer.work);
+ mb5_transfer.failed = false;
+
+ INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work);
+
+ /*
+ * TODO: These should be configurable through the API.
+ * We keep them on for now.
+ */
+ mb0_transfer.req.ap_pll_state = 1;
+ mb0_transfer.req.ulp_clk_state = 1;
+
+ /* Initalize irqs. */
+ for (i = 0; i < NUM_PRCMU_WAKEUPS; i++) {
+ unsigned int irq;
+
+ irq = IRQ_PRCMU_BASE + i;
+ set_irq_chip(irq, &prcmu_irq_chip);
+ set_irq_flags(irq, IRQF_VALID);
+ set_irq_handler(irq, handle_simple_irq);
+ }
+}
+
+/* This function is temporary, until an API has been decided. */
+static void config_ddr_power(void)
+{
+ mutex_lock(&mb4_transfer.lock);
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+ cpu_relax();
+
+ writeb(MEM_ST_H, PRCM_MBOX_HEADER_REQ_MB4);
+ writeb(((DDR_PWR_STATE_ON << 4) | DDR_PWR_STATE_ON),
+ PRCM_REQ_MB4_DDR_ST_AP_IDLE_SLEEP);
+ writeb(DDR_PWR_STATE_ON, PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE);
+
+ writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
+
+ mutex_unlock(&mb4_transfer.lock);
+}
+
+/**
+ * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
+ *
+ */
+int __init prcmu_init(void)
+{
+ int err = 0;
+
+ /* Clean up the mailbox interrupts after pre-kernel code. */
+ writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLEAR);
+
+ err = request_threaded_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler,
+ prcmu_irq_thread_fn, 0, "prcmu", NULL);
+ if (err < 0) {
+ pr_err("prcmu: Failed to allocate IRQ_DB8500_PRCMU1.\n");
+ err = -EBUSY;
+ goto no_irq_return;
+ }
+
+ if (prcmu_get_xp70_current_state() == AP_BOOT) {
+ prcmu_apply_ap_state_transition(APBOOT_TO_APEXECUTE,
+ DDR_PWR_STATE_UNCHANGED, 0);
+ } else if (prcmu_get_xp70_current_state() == AP_EXECUTE) {
+ pr_info("prcmu: Firmware booted.\n");
+ } else {
+ pr_warning("prcmu: Firmware not yet booted.\n");
+ err = -ENODEV;
+ goto err_return;
+ }
+ config_ddr_power();
+
+ return 0;
+
+err_return:
+ free_irq(IRQ_DB8500_PRCMU1, NULL);
+no_irq_return:
+ return err;
+}
+
+arch_initcall(prcmu_init);
+
+static int prcmu_qos_power_init(void)
+{
+ int ret = 0;
+
+ ret = register_prcmu_qos_misc(&ape_opp_qos);
+ if (ret < 0)
+ printk(KERN_ERR "prcmu qos: setup failed\n");
+
+ return ret;
+}
+
+late_initcall(prcmu_qos_power_init);
diff --git a/arch/arm/mach-ux500/pwm.c b/arch/arm/mach-ux500/pwm.c
new file mode 100644
index 00000000000..37f6bd481c5
--- /dev/null
+++ b/arch/arm/mach-ux500/pwm.c
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for
+ * ST-Ericsson.
+ * Author: Magnus Templing <magnus.templing@stericsson.com> for
+ * ST-Ericsson.
+ *
+ * PWM (Pulse Width Modulator) driver for the DB5500 digital baseband
+ * controller. Based on arch/arm/mach-pxa/pwm.c.
+ */
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+/* Register offsets */
+#define PWM_CONTROL_REG_OFFSET 0x00
+#define PWM_DUTY_REG_OFFSET 0x04
+#define PWM_PERIOD_REG_OFFSET 0x08
+#define PWM_BURST_REG_OFFSET 0x10
+#define PWM_SEQUENCE_REG_OFFSET 0x14
+#define PWM_DELAY_REG_OFFSET 0x18
+
+/* CONTROL_REG */
+#define PWM_CONTROL_REG_ENABLE_POS 0
+#define PWM_CONTROL_REG_CBM_POS 1
+#define PWM_CONTROL_REG_PRESCALER_POS 2
+#define PWM_CONTROL_REG_DISABLE 0
+#define PWM_CONTROL_REG_ENABLE 1
+#define PWM_CONTROL_REG_CBM_ENABLE 1
+
+#define PWM_BURST_REG_ONE_PULSE_PER_BURST 0
+#define PWM_SEQUENCE_REG_ONE_BURST_PER_SEQUENCE 0
+#define PWM_DELAY_REG_NO_DELAY 0
+#define PWM_PRESCALE 25
+
+struct pwm_device {
+ struct list_head node;
+ struct platform_device *pdev;
+
+ void __iomem *mmio_base;
+
+ unsigned int pwm_id;
+ unsigned int use_count;
+};
+
+static DEFINE_MUTEX(pwm_lock);
+static LIST_HEAD(pwm_list);
+#if defined(CONFIG_DEBUG_FS)
+static void init_debugfs(void);
+#else
+#define init_debugfs(x)
+#endif
+
+/*
+ * PWM_CLK_RATE = 26000000 Hz
+ *
+ * period_ns = 10^9 * (PWM_PRESCALE + 1) * period / PWM_CLK_RATE
+ * duty_ns = 10^9 * (PWM_PRESCALE + 1) * dc / PWM_CLK_RATE
+ *
+ * period = period_ns * 26000000 / 10^9 / 26 => period = period_ns / 1000
+ * dc = duty_ns * 26000000 / 10^9 / 26 => dc = duty_ns / 1000
+ */
+#define MAGIC_DIVISOR (1000)
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ u32 period;
+ u32 dc;
+
+ dev_dbg(&pwm->pdev->dev, "%s duty_ns: %d period_ns: %d\n",
+ __func__, duty_ns, period_ns);
+
+ if (pwm == NULL || period_ns == 0 || duty_ns >= period_ns) {
+ dev_err(&pwm->pdev->dev, "%s INVALID ARGUMENTS!\n", __func__);
+ return -EINVAL;
+ }
+
+ period = period_ns / MAGIC_DIVISOR;
+ dc = duty_ns / MAGIC_DIVISOR;
+
+ writel(period, pwm->mmio_base + PWM_PERIOD_REG_OFFSET);
+ writel(dc, pwm->mmio_base + PWM_DUTY_REG_OFFSET);
+ writel(PWM_BURST_REG_ONE_PULSE_PER_BURST,
+ pwm->mmio_base + PWM_BURST_REG_OFFSET);
+ writel(PWM_SEQUENCE_REG_ONE_BURST_PER_SEQUENCE,
+ pwm->mmio_base + PWM_SEQUENCE_REG_OFFSET);
+ writel(PWM_DELAY_REG_NO_DELAY, pwm->mmio_base + PWM_DELAY_REG_OFFSET);
+
+ return 0;
+}
+EXPORT_SYMBOL(pwm_config);
+
+int pwm_enable(struct pwm_device *pwm)
+{
+ u32 val;
+
+ val = (PWM_CONTROL_REG_ENABLE << PWM_CONTROL_REG_ENABLE_POS);
+ val |= (PWM_CONTROL_REG_CBM_ENABLE << PWM_CONTROL_REG_CBM_POS);
+ val |= (PWM_PRESCALE << PWM_CONTROL_REG_PRESCALER_POS);
+
+ writel(val, pwm->mmio_base + PWM_CONTROL_REG_OFFSET);
+
+ return 0;
+}
+EXPORT_SYMBOL(pwm_enable);
+
+void pwm_disable(struct pwm_device *pwm)
+{
+ writel(PWM_CONTROL_REG_DISABLE,
+ pwm->mmio_base + PWM_CONTROL_REG_OFFSET);
+}
+EXPORT_SYMBOL(pwm_disable);
+
+struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+ struct pwm_device *pwm;
+ bool found = false;
+
+ mutex_lock(&pwm_lock);
+
+ list_for_each_entry(pwm, &pwm_list, node) {
+ if (pwm->pwm_id == pwm_id) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ if (pwm->use_count == 0)
+ pwm->use_count++;
+ else
+ pwm = ERR_PTR(-EBUSY);
+ } else {
+ pwm = ERR_PTR(-ENOENT);
+ }
+
+ mutex_unlock(&pwm_lock);
+ return pwm;
+}
+EXPORT_SYMBOL(pwm_request);
+
+void pwm_free(struct pwm_device *pwm)
+{
+ mutex_lock(&pwm_lock);
+
+ if (pwm->use_count)
+ pwm->use_count--;
+ else
+ dev_warn(&pwm->pdev->dev, "PWM device already freed\n");
+
+ mutex_unlock(&pwm_lock);
+}
+EXPORT_SYMBOL(pwm_free);
+
+int __init pwm_probe(struct platform_device *pdev)
+{
+ struct pwm_device *pwm;
+ struct resource *r;
+ int ret = 0;
+
+ dev_dbg(&pdev->dev, "%s\n", __func__);
+
+ pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+ if (pwm == NULL) {
+ dev_err(&pdev->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ pwm->pwm_id = pdev->id;
+ pwm->pdev = pdev;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ dev_err(&pdev->dev, "no memory resource defined\n");
+ ret = -ENODEV;
+ goto err_free;
+ }
+
+ 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;
+ goto err_free;
+ }
+
+ mutex_lock(&pwm_lock);
+ list_add_tail(&pwm->node, &pwm_list);
+ mutex_unlock(&pwm_lock);
+
+ platform_set_drvdata(pdev, pwm);
+
+ init_debugfs();
+
+ return 0;
+
+err_free:
+ kfree(pwm);
+ return ret;
+}
+
+static int __devexit pwm_remove(struct platform_device *pdev)
+{
+ struct pwm_device *pwm;
+
+ pwm = platform_get_drvdata(pdev);
+ if (pwm == NULL)
+ return -ENODEV;
+
+ mutex_lock(&pwm_lock);
+ list_del(&pwm->node);
+ mutex_unlock(&pwm_lock);
+
+ iounmap(pwm->mmio_base);
+
+ kfree(pwm);
+ return 0;
+}
+
+static struct platform_driver pwm_driver = {
+ .driver = {
+ .name = "pwm",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(pwm_remove),
+};
+
+static int __init pwm_init(void)
+{
+ int ret = 0;
+
+ ret = platform_driver_probe(&pwm_driver, pwm_probe);
+ if (ret) {
+ pr_err("PWM: probe failed ret=%d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static int pwm_dump(struct seq_file *s, void *data)
+{
+ struct list_head *pos;
+ struct pwm_device *pwm;
+ int pwm_index = 0;
+
+ mutex_lock(&pwm_lock);
+
+ list_for_each(pos, &pwm_list) {
+ pwm = (struct pwm_device *)
+ list_entry(pos, struct pwm_device, node);
+
+ seq_printf(s, "===========================\n"
+ " PWM DUMP %d\n"
+ " mmio_base: 0x%p\n"
+ " CONTROL : 0x%X\n"
+ " DUTY : 0x%X\n"
+ " PERIOD : 0x%X\n"
+ " BURST : 0x%X\n"
+ " SEQUENCE : 0x%X\n"
+ " DELAY : 0x%X\n",
+ pwm_index,
+ pwm->mmio_base,
+ readl(pwm->mmio_base + PWM_CONTROL_REG_OFFSET),
+ readl(pwm->mmio_base + PWM_DUTY_REG_OFFSET),
+ readl(pwm->mmio_base + PWM_PERIOD_REG_OFFSET),
+ readl(pwm->mmio_base + PWM_BURST_REG_OFFSET),
+ readl(pwm->mmio_base + PWM_SEQUENCE_REG_OFFSET),
+ readl(pwm->mmio_base + PWM_DELAY_REG_OFFSET));
+ pwm_index++;
+ }
+
+ mutex_unlock(&pwm_lock);
+
+ return 0;
+}
+
+static int pwm_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pwm_dump, NULL);
+}
+
+static int get_value(char **c, char *s, int *v)
+{
+ char *val;
+ long value;
+ int ret = -1;
+
+ if (c != NULL) {
+ val = strsep(c, s);
+
+ if (val) {
+ ret = strict_strtol(val, 10, &value);
+
+ if (!ret)
+ *v = value;
+ }
+ }
+
+ return ret;
+}
+
+#define MAX_BUFFER_SIZE 64
+
+static int pwm_write_raw(struct file *file, const char __user *buffer,
+ size_t size, loff_t *offset)
+{
+ char int_buf[MAX_BUFFER_SIZE];
+ char *token;
+ u32 period;
+ u32 dc;
+ u32 burst;
+ u32 seq;
+ u32 delay;
+ u32 ctrl;
+ int max_size = max(size, strlen(buffer));
+
+ struct pwm_device *pwm = (struct pwm_device *)
+ list_first_entry(&pwm_list, struct pwm_device, node);
+
+ /* Copy the buffer since strsep alters it */
+ strncpy((char *) &int_buf, (char*)buffer, max_size);
+
+ token = (char *) &int_buf;
+
+ if (get_value(&token, " ", &period)) {
+ dev_err(&pwm->pdev->dev, "%s 1\n", __func__);
+ return size;
+ }
+
+ if (get_value(&token, " ", &dc)) {
+ dev_err(&pwm->pdev->dev, "%s 2\n", __func__);
+ return size;
+ }
+
+ if (get_value(&token, " ", &burst)) {
+ dev_err(&pwm->pdev->dev, "%s 3\n", __func__);
+ return size;
+ }
+
+ if (get_value(&token, " ", &seq)) {
+ dev_err(&pwm->pdev->dev, "%s 4\n", __func__);
+ return size;
+ }
+
+ if (get_value(&token, " ", &delay)) {
+ dev_err(&pwm->pdev->dev, "%s 5\n", __func__);
+ return size;
+ }
+
+ if (get_value(&token, "\n", &ctrl)) {
+ dev_err(&pwm->pdev->dev, "%s 6\n", __func__);
+ return size;
+ }
+
+ dev_dbg(&pwm->pdev->dev,
+ "%s p: 0x%X d: 0x%X b: 0x%X s: 0x%X d: 0x%X c: 0x%X\n"
+ , __func__, period, dc, burst, seq, delay, ctrl);
+
+ writel(period, pwm->mmio_base + PWM_PERIOD_REG_OFFSET);
+ writel(dc , pwm->mmio_base + PWM_DUTY_REG_OFFSET);
+ writel(burst , pwm->mmio_base + PWM_BURST_REG_OFFSET);
+ writel(seq , pwm->mmio_base + PWM_SEQUENCE_REG_OFFSET);
+ writel(delay , pwm->mmio_base + PWM_DELAY_REG_OFFSET);
+ writel(ctrl , pwm->mmio_base + PWM_CONTROL_REG_OFFSET);
+
+ return size;
+}
+
+static int pwm_write(struct file *file,
+ const char __user *buffer,
+ size_t size, loff_t *offset)
+{
+ char int_buf[MAX_BUFFER_SIZE];
+ char *token;
+ u32 period = 0;
+ u32 dc = 0;
+ u32 ctrl = 0;
+ int max_size = max(size, strlen(buffer));
+
+ struct pwm_device *pwm = (struct pwm_device *)
+ list_first_entry(&pwm_list, struct pwm_device, node);
+
+ /* Copy the buffer since strsep alters it */
+ strncpy((char *) &int_buf, (char*)buffer, max((int) size, max_size));
+
+ token = (char *) &int_buf;
+
+ if (get_value(&token, " ", &period)) {
+ dev_err(&pwm->pdev->dev, "%s 1\n", __func__);
+ return size;
+ }
+
+ if (get_value(&token, " ", &dc)) {
+ dev_err(&pwm->pdev->dev, "%s 2\n", __func__);
+ return size;
+ }
+
+ if (get_value(&token, "\n", &ctrl)) {
+ dev_err(&pwm->pdev->dev, "%s 3\n", __func__);
+ return size;
+ }
+
+ dev_dbg(&pwm->pdev->dev, "%s p: 0x%X d: 0x%X c: 0x%X\n",
+ __func__, period, dc, ctrl);
+
+ if (ctrl == 0)
+ pwm_disable(pwm);
+ else {
+ pwm_config(pwm, dc, period);
+ pwm_enable(pwm);
+ }
+
+ return size;
+}
+
+static const struct file_operations pwm_operations = {
+ .owner = THIS_MODULE,
+ .open = pwm_open,
+ .read = seq_read,
+ .write = pwm_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations pwm_operations_raw = {
+ .owner = THIS_MODULE,
+ .open = pwm_open,
+ .read = seq_read,
+ .write = pwm_write_raw,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void init_debugfs(void)
+{
+ (void) debugfs_create_file("pwm_if", S_IFREG | S_IRUGO | S_IWUGO,
+ NULL, NULL, &pwm_operations);
+ (void) debugfs_create_file("pwm_raw", S_IFREG | S_IRUGO | S_IWUGO,
+ NULL, NULL, &pwm_operations_raw);
+}
+#endif
+
+module_init(pwm_init);
+
+static void __exit pwm_exit(void)
+{
+ platform_driver_unregister(&pwm_driver);
+}
+module_exit(pwm_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-ux500/regulator-u8500.c b/arch/arm/mach-ux500/regulator-u8500.c
new file mode 100644
index 00000000000..754e9cad2df
--- /dev/null
+++ b/arch/arm/mach-ux500/regulator-u8500.c
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * Platform specific regulators on U8500
+ *
+ * NOTE! The power domains in here will be updated once B2R2 and MCDE are
+ * converted to use the regulator API.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#include "regulator-u8500.h"
+
+/* for vape opp - to be removed */
+#include <mach/prcmu-fw-defs_v1.h>
+#include <mach/prcmu-fw-api.h>
+
+/*
+ * power state reference count
+ */
+static int power_state_active_cnt; /* will initialize to zero */
+
+static void power_state_active_enable(void)
+{
+ power_state_active_cnt++;
+}
+
+static int power_state_active_disable(void)
+{
+ if (power_state_active_cnt <= 0) {
+ pr_err("power state: unbalanced enable/disable calls\n");
+ return -EINVAL;
+ }
+
+ power_state_active_cnt--;
+ return 0;
+}
+
+/*
+ * Exported interface for CPUIdle only. This function is called when interrupts
+ * are turned off. Hence, no locking.
+ */
+int power_state_active_is_enabled(void)
+{
+ return (power_state_active_cnt > 0);
+}
+
+/**
+ * struct u8500_regulator_info - u8500 regulator information
+ * @dev: device pointer
+ * @desc: regulator description
+ * @rdev: regulator device pointer
+ * @is_enabled: status of the regulator
+ * @hwacc_id: id for HW accelerator (used with power domains, to be updated)
+ * @operating_point: operating point (only for vape, to be removed)
+ *
+ */
+struct u8500_regulator_info {
+ struct device *dev;
+ struct regulator_desc desc;
+ struct regulator_dev *rdev;
+ bool is_enabled;
+ u16 hwacc_id;
+ unsigned int operating_point;
+};
+
+static int u8500_regulator_enable(struct regulator_dev *rdev)
+{
+ struct u8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n",
+ info->desc.name);
+
+ info->is_enabled = 1;
+ power_state_active_enable();
+
+ return 0;
+}
+
+static int u8500_regulator_disable(struct regulator_dev *rdev)
+{
+ struct u8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n",
+ info->desc.name);
+
+ info->is_enabled = 0;
+ ret = power_state_active_disable();
+
+ return ret;
+}
+
+static int u8500_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct u8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-%s-is_enabled (is_enabled):"
+ " %i\n", info->desc.name, info->is_enabled);
+
+ return info->is_enabled;
+}
+
+/* u8500 regulator operations */
+static struct regulator_ops u8500_regulator_ops = {
+ .enable = u8500_regulator_enable,
+ .disable = u8500_regulator_disable,
+ .is_enabled = u8500_regulator_is_enabled,
+};
+
+/* for vape opp - to be removed */
+static int regulator_vape_get_voltage(struct regulator_dev *rdev)
+{
+ struct u8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-%s-get_voltage (voltage):"
+ " %i\n", info->desc.name, 1);
+
+ return 1; /* return non-zero value for set_optimum_mode to work */
+}
+
+/* for vape opp - to be removed */
+static int regulator_vape_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct u8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-%s-set_mode (mode): %d\n",
+ info->desc.name, mode);
+
+ /*
+ * we map here the various mode as
+ * REGULATOR_MODE_IDLE - APE OPP 50
+ * REGULATOR_MODE_NORMAL - APE OPP 100
+ *
+ */
+ switch (mode) {
+ case REGULATOR_MODE_IDLE:
+ if (info->operating_point == APE_50_OPP)
+ return 0;
+ /* drop requirement for 100% APE OPP, via PRCMU QoS */
+ prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
+ "db8500-regulator");
+ info->operating_point = APE_50_OPP;
+ break;
+ case REGULATOR_MODE_NORMAL:
+ if (info->operating_point == APE_100_OPP)
+ return 0;
+ /* request 100% APE OPP, via PRCMU QoS */
+ if (prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
+ "db8500-regulator", 100)) {
+ dev_dbg(rdev_get_dev(rdev),
+ "APE 100OPP DVFS failed\n");
+ return -EINVAL;
+ }
+ info->operating_point = APE_100_OPP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* for vape opp - to be removed */
+static unsigned int regulator_vape_get_mode(struct regulator_dev *rdev)
+{
+ struct u8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-%s-get_mode (mode): %d\n",
+ info->desc.name, REGULATOR_MODE_NORMAL);
+
+ return REGULATOR_MODE_NORMAL;
+}
+
+/* for vape opp - to be removed */
+static unsigned int regulator_vape_get_optimum_mode(struct regulator_dev *rdev,
+ int input_uV, int output_uV, int load_uA)
+{
+ struct u8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-%s-get_optimum_mode"
+ " (input_uV, output_uV, load_uA): %d, %d, %d\n",
+ info->desc.name, input_uV, output_uV, load_uA);
+
+ /* load_uA will be non-zero if any non-dvfs client is active */
+ if (load_uA > 0)
+ return REGULATOR_MODE_NORMAL;
+ else
+ return REGULATOR_MODE_IDLE;
+}
+
+/* for vape opp - to be removed */
+static struct regulator_ops regulator_vape_ops = {
+ .get_voltage = regulator_vape_get_voltage,
+ .set_mode = regulator_vape_set_mode,
+ .get_mode = regulator_vape_get_mode,
+ .get_optimum_mode = regulator_vape_get_optimum_mode,
+ .enable = u8500_regulator_enable,
+ .disable = u8500_regulator_disable,
+ .is_enabled = u8500_regulator_is_enabled,
+};
+
+static int u8500_regulator_switch_enable(struct regulator_dev *rdev)
+{
+ struct u8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-enable\n",
+ info->desc.name);
+
+ ret = prcmu_set_hwacc(info->hwacc_id, HW_ON);
+ if (ret < 0)
+ goto out;
+
+ info->is_enabled = 1;
+out:
+ return ret;
+}
+
+static int u8500_regulator_switch_disable(struct regulator_dev *rdev)
+{
+ struct u8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-disable\n",
+ info->desc.name);
+
+ ret = prcmu_set_hwacc(info->hwacc_id, HW_OFF);
+ if (ret < 0)
+ goto out;
+
+ info->is_enabled = 0;
+out:
+ return ret;
+}
+
+static int u8500_regulator_switch_is_enabled(struct regulator_dev *rdev)
+{
+ struct u8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "regulator-switch-%s-is_enabled (is_enabled): %i\n",
+ info->desc.name, info->is_enabled);
+
+ return info->is_enabled;
+}
+
+static struct regulator_ops u8500_regulator_switch_ops = {
+ .enable = u8500_regulator_switch_enable,
+ .disable = u8500_regulator_switch_disable,
+ .is_enabled = u8500_regulator_switch_is_enabled,
+};
+
+/* regulator info */
+static struct u8500_regulator_info
+ u8500_regulator_info[U8500_NUM_REGULATORS] = {
+ [U8500_REGULATOR_VAPE] = {
+ .desc = {
+ .name = "u8500-vape",
+ .id = U8500_REGULATOR_VAPE,
+ .ops = &regulator_vape_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [U8500_REGULATOR_VARM] = {
+ .desc = {
+ .name = "u8500-varm",
+ .id = U8500_REGULATOR_VARM,
+ .ops = &u8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [U8500_REGULATOR_VMODEM] = {
+ .desc = {
+ .name = "u8500-vmodem",
+ .id = U8500_REGULATOR_VMODEM,
+ .ops = &u8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [U8500_REGULATOR_VPLL] = {
+ .desc = {
+ .name = "u8500-vpll",
+ .id = U8500_REGULATOR_VPLL,
+ .ops = &u8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [U8500_REGULATOR_VSMPS1] = {
+ .desc = {
+ .name = "u8500-vsmps1",
+ .id = U8500_REGULATOR_VSMPS1,
+ .ops = &u8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [U8500_REGULATOR_VSMPS2] = {
+ .desc = {
+ .name = "u8500-vsmps2",
+ .id = U8500_REGULATOR_VSMPS2,
+ .ops = &u8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [U8500_REGULATOR_VSMPS3] = {
+ .desc = {
+ .name = "u8500-vsmps3",
+ .id = U8500_REGULATOR_VSMPS3,
+ .ops = &u8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [U8500_REGULATOR_VRF1] = {
+ .desc = {
+ .name = "u8500-vrf1",
+ .id = U8500_REGULATOR_VRF1,
+ .ops = &u8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [U8500_REGULATOR_SWITCH_SVA_MMDSP] = {
+ .desc = {
+ .name = "u8500-sva-mmdsp",
+ .id = U8500_REGULATOR_SWITCH_SVA_MMDSP,
+ .ops = &u8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .hwacc_id = HW_ACC_SVAMMDSP,
+ },
+ [U8500_REGULATOR_SWITCH_SVA_PIPE] = {
+ .desc = {
+ .name = "u8500-sva-pipe",
+ .id = U8500_REGULATOR_SWITCH_SVA_PIPE,
+ .ops = &u8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .hwacc_id = HW_ACC_SVAPIPE,
+ },
+ [U8500_REGULATOR_SWITCH_SIA_MMDSP] = {
+ .desc = {
+ .name = "u8500-sia-mmdsp",
+ .id = U8500_REGULATOR_SWITCH_SIA_MMDSP,
+ .ops = &u8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .hwacc_id = HW_ACC_SIAMMDSP,
+ },
+ [U8500_REGULATOR_SWITCH_SIA_PIPE] = {
+ .desc = {
+ .name = "u8500-sia-pipe",
+ .id = U8500_REGULATOR_SWITCH_SIA_PIPE,
+ .ops = &u8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .hwacc_id = HW_ACC_SIAPIPE,
+ },
+ [U8500_REGULATOR_SWITCH_SGA] = {
+ .desc = {
+ .name = "u8500-sga",
+ .id = U8500_REGULATOR_SWITCH_SGA,
+ .ops = &u8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .hwacc_id = HW_ACC_SGA,
+ },
+ /*
+ * NOTE! B2R2 and MCDE regulators will be merged once the clients have
+ * switched over to use the regulator API.
+ */
+ [U8500_REGULATOR_SWITCH_B2R2] = {
+ .desc = {
+ .name = "u8500-b2r2",
+ .id = U8500_REGULATOR_SWITCH_B2R2,
+ .ops = &u8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .hwacc_id = HW_ACC_B2R2,
+ },
+ [U8500_REGULATOR_SWITCH_MCDE] = {
+ .desc = {
+ .name = "u8500-mcde",
+ .id = U8500_REGULATOR_SWITCH_MCDE,
+ .ops = &u8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .hwacc_id = HW_ACC_MCDE,
+ },
+ /*
+ * NOTE! ESRAM1 and ESRAM2 regulators will be merged once the clients
+ * have switched over to use the regulator API.
+ */
+ [U8500_REGULATOR_SWITCH_ESRAM1] = {
+ .desc = {
+ .name = "u8500-esram1",
+ .id = U8500_REGULATOR_SWITCH_ESRAM1,
+ .ops = &u8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .hwacc_id = HW_ACC_ESRAM1,
+ },
+ [U8500_REGULATOR_SWITCH_ESRAM2] = {
+ .desc = {
+ .name = "u8500-esram2",
+ .id = U8500_REGULATOR_SWITCH_ESRAM2,
+ .ops = &u8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .hwacc_id = HW_ACC_ESRAM2,
+ },
+ /*
+ * NOTE! ESRAM3 and ESRAM4 regulators will be merged once the clients
+ * have switched over to use the regulator API.
+ */
+ [U8500_REGULATOR_SWITCH_ESRAM3] = {
+ .desc = {
+ .name = "u8500-esram3",
+ .id = U8500_REGULATOR_SWITCH_ESRAM3,
+ .ops = &u8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .hwacc_id = HW_ACC_ESRAM3,
+ },
+ [U8500_REGULATOR_SWITCH_ESRAM4] = {
+ .desc = {
+ .name = "u8500-esram4",
+ .id = U8500_REGULATOR_SWITCH_ESRAM4,
+ .ops = &u8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .hwacc_id = HW_ACC_ESRAM4,
+ },
+};
+
+static int __devinit u8500_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_init_data **u8500_init_data =
+ dev_get_platdata(&pdev->dev);
+ int i, err;
+
+ /* register all regulators */
+ for (i = 0; i < ARRAY_SIZE(u8500_regulator_info); i++) {
+ struct u8500_regulator_info *info;
+ struct regulator_init_data *init_data = u8500_init_data[i];
+
+ /* assign per-regulator data */
+ info = &u8500_regulator_info[i];
+ info->dev = &pdev->dev;
+
+ /* register with the regulator framework */
+ info->rdev = regulator_register(&info->desc, &pdev->dev,
+ init_data, info);
+ if (IS_ERR(info->rdev)) {
+ err = PTR_ERR(info->rdev);
+ dev_err(&pdev->dev, "failed to register %s: err %i\n",
+ info->desc.name, err);
+
+ /* if failing, unregister all earlier regulators */
+ i--;
+ while (i >= 0) {
+ info = &u8500_regulator_info[i];
+ regulator_unregister(info->rdev);
+ i--;
+ }
+ return err;
+ }
+
+ dev_vdbg(rdev_get_dev(info->rdev),
+ "regulator-%s-probed\n", info->desc.name);
+ }
+
+ return 0;
+}
+
+static int __devexit u8500_regulator_remove(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(u8500_regulator_info); i++) {
+ struct u8500_regulator_info *info;
+ info = &u8500_regulator_info[i];
+
+ dev_vdbg(rdev_get_dev(info->rdev),
+ "regulator-%s-remove\n", info->desc.name);
+
+ regulator_unregister(info->rdev);
+ }
+
+ return 0;
+}
+
+static struct platform_driver u8500_regulator_driver = {
+ .driver = {
+ .name = "u8500-regulators",
+ .owner = THIS_MODULE,
+ },
+ .probe = u8500_regulator_probe,
+ .remove = __devexit_p(u8500_regulator_remove),
+};
+
+static int __init u8500_regulator_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&u8500_regulator_driver);
+ if (ret < 0) {
+ printk(KERN_INFO "u8500_regulator: platform_driver_register fails\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit u8500_regulator_exit(void)
+{
+ platform_driver_unregister(&u8500_regulator_driver);
+}
+
+/* replaced subsys_initcall as regulators must be turned on early */
+arch_initcall(u8500_regulator_init);
+module_exit(u8500_regulator_exit);
+
+MODULE_AUTHOR("STMicroelectronics/ST-Ericsson");
+MODULE_DESCRIPTION("U8500 regulator driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/arch/arm/mach-ux500/regulator-u8500.h b/arch/arm/mach-ux500/regulator-u8500.h
new file mode 100644
index 00000000000..f0285ca12b9
--- /dev/null
+++ b/arch/arm/mach-ux500/regulator-u8500.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * Interface to platform specific regulators on U8500
+ */
+
+#ifndef __REGULATOR_H__
+#define __REGULATOR_H__
+
+/* Number of U8500 regulators and regulator enumeration */
+enum u8500_regulator_id {
+ U8500_REGULATOR_VAPE,
+ U8500_REGULATOR_VARM,
+ U8500_REGULATOR_VMODEM,
+ U8500_REGULATOR_VPLL,
+ U8500_REGULATOR_VSMPS1,
+ U8500_REGULATOR_VSMPS2,
+ U8500_REGULATOR_VSMPS3,
+ U8500_REGULATOR_VRF1,
+ U8500_REGULATOR_SWITCH_SVA_MMDSP,
+ U8500_REGULATOR_SWITCH_SVA_PIPE,
+ U8500_REGULATOR_SWITCH_SIA_MMDSP,
+ U8500_REGULATOR_SWITCH_SIA_PIPE,
+ U8500_REGULATOR_SWITCH_SGA,
+ U8500_REGULATOR_SWITCH_B2R2,
+ U8500_REGULATOR_SWITCH_MCDE,
+ U8500_REGULATOR_SWITCH_ESRAM1,
+ U8500_REGULATOR_SWITCH_ESRAM2,
+ U8500_REGULATOR_SWITCH_ESRAM3,
+ U8500_REGULATOR_SWITCH_ESRAM4,
+ U8500_NUM_REGULATORS
+};
+
+/*
+ * Exported interface for CPUIdle only. This function is called with all
+ * interrupts turned off.
+ */
+int power_state_active_is_enabled(void);
+
+#endif
+
diff --git a/arch/arm/mach-ux500/savecontext.S b/arch/arm/mach-ux500/savecontext.S
new file mode 100644
index 00000000000..bcb679017f2
--- /dev/null
+++ b/arch/arm/mach-ux500/savecontext.S
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ * Author: David Paris <david.paris-nonst@stericsson.com>
+ *
+ * ux500 core context/save for low power modes
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <mach/hardware.h>
+#include <asm/hardware/cache-l2x0.h>
+
+
+/* Define for DeepSleep specific case */
+#define _BACKUPRAM1_BASE IO_ADDRESS(U8500_BACKUPRAM1_BASE)
+
+#define BACKUPRAMCPU0 (_BACKUPRAM1_BASE + 0xF80)
+#define BACKUPRAMCPU1 (_BACKUPRAM1_BASE + 0xFA0)
+
+#define UX500L2CCBASE IO_ADDRESS(UX500_L2CC_BASE)
+
+ENTRY(ux500_cpu_context_deepsleep)
+ .code 32
+ .extern prcmu_apply_ap_state_transition
+
+ push {r0-r4, lr}
+
+ mov r2, r0
+ cmp r0, #0
+ bne load_cpu1_ctxt
+
+ ldr r0, =BACKUPRAMCPU0
+ b common_ctxt
+
+load_cpu1_ctxt:
+ ldr r0, =BACKUPRAMCPU1
+
+common_ctxt:
+ /* Save SystemControl Register */
+ mrc p15, 0, r1, c1, c0, 0
+ str r1,[r0,#0x00]
+
+ /* Save TTBR0 */
+ mrc p15, 0, r1, c2, c0, 0
+ str r1,[r0,#0x04]
+
+ /* Save TTBR1 */
+ mrc p15, 0, r1, c2, c0, 1
+ str r1,[r0,#0x08]
+
+ /* save TTBRC */
+ mrc p15, 0, r1, c2, c0, 2
+ str r1,[r0,#0x0C]
+
+ /* Save DACR */
+ mrc p15, 0, r1, c3, c0, 0
+ str r1,[r0,#0x10]
+
+ cmp r2, #0
+ bne store_ret_addr_for_cpu1
+
+ ldr r1, =_return_from_deepsleep_cpu0
+ str r1,[r0,#0x14]
+ b common_continue
+
+store_ret_addr_for_cpu1:
+ ldr r1, =_return_from_deepsleep_cpu1
+ str r1,[r0,#0x14]
+
+common_continue:
+ /* save CPSR */
+ mrs r1, cpsr
+ str r1,[r0,#0x18]
+
+ /* save Current stack (Must not be used after) */
+ str sp,[r0,#0x1C]
+
+ /* Save ARM Context */
+ mov r0, r2
+ bl save_processor_context
+
+ cmp r2, #0
+ bne _cpu1_wait_deepsleep
+
+ stmfd sp!, {r0, r1, r2}
+ bl ux500_flush_all
+ ldmfd sp!, {r0, r1, r2}
+
+ mov r0, #0x4 /* APEXECUTE_TO_APDEEPSLEEP */
+ mov r1, #0x0 /* DDR_PWR_STATE_UNCHANGED */
+ mov r2, #0x0 /* INTR_NOT_AS_WAKEUP */
+
+ bl prcmu_apply_ap_state_transition
+
+ b _return_from_deepsleep_cpu0
+
+_cpu1_wait_deepsleep:
+ dsb
+ wfi
+ b _return_from_deepsleep_cpu1
+
+_return_from_deepsleep_cpu0:
+ mov r0, #0
+
+ b _exit_deeps
+
+_return_from_deepsleep_cpu1:
+ mov r0, #1
+
+_exit_deeps:
+ bl restore_processor_context
+
+ pop {r0-r4, pc}
+ENDPROC(ux500_cpu_context_deepsleep)
+
+ENTRY(save_processor_context)
+ .extern arm_cntxt_cpu0
+ .extern arm_cntxt_cpu1
+
+ .code 32
+
+ push {r0-r3, lr}
+
+ /* load the backup pointer accordingly */
+ cmp r0, #0
+ bne save_cpu1_ctxt
+ ldr r1, =arm_cntxt_cpu0
+ b save_ctxt
+
+save_cpu1_ctxt:
+ ldr r1, =arm_cntxt_cpu1
+
+save_ctxt:
+ ldr r1, [r1]
+
+ mrs r2, cpsr
+ str r2, [r1], #+4
+
+ /* clear up all mode bits which change with the mode. */
+ bic r2, r2, #0xf
+
+ /*
+ * enter all modes and save banked registers
+ * suffix to CPSR : c-control, f-flags, s-status, x-xtension
+ */
+
+ /*
+ * Enter FIQ mode, Interrupts disabled
+ * Save: r8-r14 and spsr
+ * Assume: r2 depicts the processor in Supervisor mode
+ */
+ orr r3, r2, #0x1
+ msr cpsr_cxsf, r3
+ mrs r3, spsr
+ stmia r1!, {r3,r8-r14}
+
+ /*
+ * Enter IRQ mode, Interrupts disabled
+ * Save: r13,r14 and spsr
+ */
+ orr r3, r2, #0x2
+ msr cpsr_cxsf, r3 /* Enter IRQ mode with IRQ/FIQ disable */
+ mrs r3, spsr
+ stmia r1!, {r3,r13,r14}
+
+ /*
+ * Enter Abort mode, irq/fiq disabled
+ * Save: r13,r14 and sps
+ */
+ orr r3, r2, #0x7
+ msr cpsr_cxsf, r3
+ mrs r3, spsr
+ stmia r1!, {r3, r4-r14}
+
+ /*
+ * Enter Undef mode, irq/fiq disable
+ * Save: r13,r14 and spsr
+ */
+ orr r3, r2, #0xB
+ msr cpsr_cxsf, r3
+ mrs r3, spsr
+ stmia r1!, {r3,r13,r14}
+
+ /* go back to the SVC mode now */
+ orr r3, r2, #0x3
+ msr cpsr_cxsf, r3
+
+ /* in SVC mode, save all CP15 configs */
+
+ /* Non-secure Vector Base Address Register */
+ mrc p15, 0, r2, c12, c0, 0
+ str r2, [r1], #4
+
+ /* Primary Region Remap reg */
+ mrc p15, 0, r2, c10, c2, 0
+ str r2, [r1], #4
+
+ mrc p15, 0, r2, c10, c2, 1
+ str r2, [r1], #4
+
+ /* Context ID reg */
+ mrc p15, 0, r2, c13, c0, 1
+ str r2, [r1], #4
+
+ /* Thread ID registers */
+ mrc p15, 0, r2, c13, c0, 2
+ str r2, [r1], #4
+
+ mrc p15, 0, r2, c13, c0, 3
+ str r2, [r1], #4
+
+ mrc p15, 0, r2, c13, c0, 4
+ str r2, [r1], #4
+
+ /* Cache Size Selection Register */
+ mrc p15, 2, r2, c0, c0, 0
+ str r2, [r1], #4
+
+ /* PMNC */
+ mrc p15, 0, r2, c9, c12, 0
+ str r2, [r1], #4
+
+ /* PMCNTENSET register */
+ mrc p15, 0, r2, c9, c12, 1
+ str r2, [r1], #4
+
+ /* PMSELR register */
+ mrc p15, 0, r2, c9, c12, 5
+ str r2, [r1], #4
+
+ /* PMCCNTR register */
+ mrc p15, 0, r2, c9, c13, 0
+ str r2, [r1], #4
+
+ /* PMXEVTYPER register */
+ mrc p15, 0, r2, c9, c13, 1
+ str r2, [r1], #4
+
+ /* PMUSERENR register */
+ mrc p15, 0, r2, c9, c14, 0
+ str r2, [r1], #4
+
+ /* PMINTENSET register */
+ mrc p15, 0, r2, c9, c14, 1
+ str r2, [r1], #4
+
+ /* PMINTENCLR register */
+ mrc p15, 0, r2, c9, c14, 2
+ str r2, [r1], #4
+
+ /* CPACR register */
+ mrc p15, 0, r2, c1, c0, 2
+ str r2, [r1], #4
+
+ cmp r0, #0
+ bne backup_ptr_cpu1
+
+ ldr r0, =arm_cntxt_cpu0
+ b update_backup_ptr
+
+backup_ptr_cpu1:
+ ldr r0, =arm_cntxt_cpu1
+
+update_backup_ptr:
+ str r1, [r0]
+
+ pop {r0-r3,pc}
+ENDPROC(save_processor_context)
+
+
+ENTRY (restore_processor_context)
+ .code 32
+ .extern arm_cntxt_cpu0
+ .extern arm_cntxt_cpu1
+
+ push {r0-r3, lr}
+
+ cmp r0, #0
+ bne restore_cpu1_cntxt
+ ldr r1, =arm_cntxt_cpu0
+ b restore_cntxt
+
+restore_cpu1_cntxt:
+ ldr r1, =arm_cntxt_cpu1
+
+restore_cntxt:
+ ldr r1, [r1]
+
+ /* restore the CP15 configs */
+ sub r1, r1, #4
+
+ /* CPACR register */
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c1, c0, 2
+
+ /* PMINTENCLR register */
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c9, c14, 2
+
+ /* PMINTENSET register */
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c9, c14, 1
+
+ /* PMUSERENR register */
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c9, c14, 0
+
+ /* PMXEVTYPER register */
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c9, c13, 1
+
+ /* PMCCNTR register */
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c9, c13, 0
+
+ /* PMSELR register */
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c9, c12, 5
+
+ /* PMCNTENSET register */
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c9, c12, 1
+
+ /* PMNC register */
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c9, c12, 0
+
+ /* Cache Size Selection register */
+ ldr r2, [r1], #-4
+ mcr p15, 2, r2, c0, c0, 0
+
+ /* Thread IDs registers */
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c13, c0, 4
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c13, c0, 3
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c13, c0, 2
+
+ /* Context ID register */
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c13, c0, 1
+
+ /* memory region map registers */
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c10, c2, 1
+ ldr r2, [r1], #-4
+ mcr p15, 0, r2, c10, c2, 0
+
+ /* Non-secure Vector Base Address register */
+ ldr r2, [r1]
+ mcr p15, 0, r2, c12, c0, 0
+
+ /* backup the value of cpsr */
+ mrs r2, cpsr
+ orr r2, r2, #0xC0
+ bic r2, r2, #0xf
+
+ /*
+ * Enter Undef mode, irq/fiq disabled
+ * restore: r13,r14 and spsr
+ */
+ orr r3, r2, #0xB
+ msr cpsr_cxsf, r3
+ ldmdb r1!, {r3,r13,r14}
+ msr spsr_cxsf, r3
+
+ /*
+ * Enter Abort mode, irq/fiq disabled
+ * restore: r13,r14 and spsr
+ */
+ orr r3, r2, #0x7
+ msr cpsr_cxsf, r3
+ ldmdb r1!, {r3, r4-r14}
+ msr spsr_cxsf, r3
+
+ /*
+ * Enter IRQ mode, irq disabled
+ * restore: r13,r14 and spsr
+ */
+ orr r3, r2, #0x2
+ msr cpsr_cxsf, r3
+ ldmdb r1!, {r3,r13,r14}
+ msr spsr_cxsf, r3
+
+ /*
+ * Enter FIQ mode, irq disabled
+ * restore: r13,r14 and spsr
+ */
+ orr r3, r2, #0x1
+ msr cpsr_cxsf, r3
+ ldmdb r1!, {r3,r8-r14}
+ msr spsr_cxsf, r3
+
+ /*
+ * Enter SVC mode, irq disabled
+ * restore: cpsr
+ */
+ orr r3, r2, #0x3
+ msr cpsr_cxsf, r3
+
+ ldr r2, [r1, #-4]!
+ msr cpsr, r2
+ msr cpsr_cxsf, r3
+
+ cmp r0, #0
+ bne backup_ptr_restore_cpu1
+ ldr r0, =arm_cntxt_cpu0
+ b update_backup_restore_ptr
+
+backup_ptr_restore_cpu1:
+ ldr r0, =arm_cntxt_cpu1
+
+update_backup_restore_ptr:
+ sub r1, r1, #4
+ str r1, [r0]
+
+ pop {r0-r3, pc}
+ENDPROC(restore_processor_context)
+
+ENTRY(ux500_flush_all)
+ .code 32
+
+ /*
+ * Flush the entire cache system.
+ * The data cache flush is now achieved using atomic clean/invalidates
+ * working outwards from L1 cache. This is done using Set/Way based
+ * cache maintainance instructions.
+ * The instruction cache can still be invalidated back to the point of
+ * unification in a single instruction.
+ *
+ */
+ stmfd sp!, {r4-r5, r7, r9-r11, lr}
+ mrc p15, 1, r0, c0, c0, 1 @ read clidr
+ ands r3, r0, #0x7000000 @ extract loc from clidr
+ mov r3, r3, lsr #23 @ left align loc bit field
+ beq finished @ if loc is 0, no need to clean
+ mov r10, #0 @ start clean at cache level 0
+loop1:
+ add r2, r10, r10, lsr #1 @ work 3x current cache level
+ mov r1, r0, lsr r2 @ extract cache type from clidr
+ and r1, r1, #7 @ mask bits for current cache
+ cmp r1, #2 @ see cache at this level
+ blt skip @ skip if no cache, or i-cache
+ mcr p15, 2, r10, c0, c0, 0 @ select current cache level
+ isb @ isb to sych new cssr&csidr
+ mrc p15, 1, r1, c0, c0, 0 @ read the new csidr
+ and r2, r1, #7 @ extract length of cache lines
+ add r2, r2, #4 @ add 4 (line length offset)
+ ldr r4, =0x3ff
+ ands r4, r4, r1, lsr #3 @ find maximum on the way size
+ clz r5, r4 @ bit position of way size inc
+ ldr r7, =0x7fff
+ ands r7, r7, r1, lsr #13 @ max number of the index size
+loop2:
+ mov r9, r4 @ create copy of max way size
+loop3:
+ orr r11, r10, r9, lsl r5 @ way and cache number into r11
+ orr r11, r11, r7, lsl r2 @ way and cache number into r11
+ mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way
+ subs r9, r9, #1 @ decrement the way
+ bge loop3
+ subs r7, r7, #1 @ decrement the index
+ bge loop2
+skip:
+ add r10, r10, #2 @ increment cache number
+ cmp r3, r10
+ bgt loop1
+finished:
+ mov r10, #0 @ swith back to cache level 0
+ mcr p15, 2, r10, c0, c0, 0 @ current cache level in cssr
+ dsb
+ isb
+
+ /* L2 cache cleaning */
+
+ ldr r0, =UX500L2CCBASE
+ ldr r2, [r0, #L2X0_AUX_CTRL]
+
+ ldr r2, =0xff
+ str r2, [r0, #L2X0_CLEAN_WAY]
+ 2:
+ ldr r3, [r0, #L2X0_CLEAN_WAY]
+ cmp r3, #0
+ bne 2b
+
+ ldr r2, =0xff
+ str r2, [r0, #L2X0_INV_WAY]
+ 1:
+ ldr r3, [r0, #L2X0_INV_WAY]
+ cmp r3, #0
+ bne 1b
+
+ mcr p15, 0, r0, c7, c5, 6 @ flush BTAC/BTB
+ isb
+
+ ldmfd sp!, {r4-r5,r7,r9-r11, pc}
+
+ENDPROC(ux500_flush_all)
diff --git a/arch/arm/mach-ux500/sensors1p.c b/arch/arm/mach-ux500/sensors1p.c
new file mode 100644
index 00000000000..4b8938d95ad
--- /dev/null
+++ b/arch/arm/mach-ux500/sensors1p.c
@@ -0,0 +1,299 @@
+
+/*
+ * Copyright (C) 2009-2010 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Simple userspace interface for
+ * Proximity Sensor Osram SFH 7741 and HAL switch Samsung HED54XXU11
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ *
+ * This driver is only there for making Android happy. It is not ment
+ * for mainline.
+ */
+
+
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+
+#include <mach/sensors1p.h>
+
+struct sensor {
+ struct regulator *regulator;
+ int pin;
+ int startup_time;
+ int active;
+ u64 when_enabled;
+};
+
+struct sensors1p {
+ struct sensor hal;
+ struct sensor proximity;
+};
+
+static int sensors1p_power_write(struct device *dev,
+ struct sensor *s, const char *buf)
+{
+ int val;
+
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ if (val != 0 && val != 1)
+ return -EINVAL;
+
+ if (val != s->active) {
+ if (val) {
+ regulator_enable(s->regulator);
+ s->when_enabled = get_jiffies_64() +
+ msecs_to_jiffies(s->startup_time);
+ } else
+ regulator_disable(s->regulator);
+ }
+ s->active = val;
+
+ return strnlen(buf, PAGE_SIZE);
+
+}
+
+static ssize_t sensors1p_sysfs_hal_active_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+
+ struct sensors1p *s = platform_get_drvdata(container_of(dev,
+ struct platform_device,
+ dev));
+ return sensors1p_power_write(dev, &s->hal, buf);
+
+}
+
+static ssize_t sensors1p_sysfs_proximity_active_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+
+
+ struct sensors1p *s = platform_get_drvdata(container_of(dev,
+ struct platform_device,
+ dev));
+ return sensors1p_power_write(dev, &s->proximity, buf);
+
+}
+
+static ssize_t sensors1p_sysfs_hal_active_get(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct sensors1p *s = platform_get_drvdata(container_of(dev,
+ struct platform_device,
+ dev));
+ return sprintf(buf, "%d", s->hal.active);
+}
+
+static ssize_t sensors1p_sysfs_proximity_active_get(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct sensors1p *s = platform_get_drvdata(container_of(dev,
+ struct platform_device,
+ dev));
+ return sprintf(buf, "%d", s->proximity.active);
+}
+
+static int sensors1p_read(struct device *dev, struct sensor *s, char *buf)
+{
+ int ret;
+
+ if (!s->active)
+ return -EINVAL;
+
+ /* Only wait if read() is called before the sensor is up and running
+ * Since jiffies wraps, always sleep maximum time.
+ */
+ if (time_before64(get_jiffies_64(), s->when_enabled))
+ mdelay(s->startup_time);
+
+ /* For some odd reason, setting direction in the probe function fails */
+ ret = gpio_direction_input(s->pin);
+
+ if (ret)
+ dev_err(dev, "Failed to set GPIO pin %d to input.\n", s->pin);
+ else
+ ret = gpio_get_value(s->pin);
+
+ return sprintf(buf, "%d", ret);
+}
+
+static ssize_t sensors1p_sysfs_hal_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct sensors1p *s = platform_get_drvdata(container_of(dev,
+ struct platform_device,
+ dev));
+ return sensors1p_read(dev, &s->hal, buf);
+}
+
+static ssize_t sensors1p_sysfs_proximity_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct sensors1p *s = platform_get_drvdata(container_of(dev,
+ struct platform_device,
+ dev));
+ return sensors1p_read(dev, &s->proximity, buf);
+}
+
+static DEVICE_ATTR(proximity_activate, 0666,
+ sensors1p_sysfs_proximity_active_get,
+ sensors1p_sysfs_proximity_active_set);
+static DEVICE_ATTR(hal_activate, 0666,
+ sensors1p_sysfs_hal_active_get,
+ sensors1p_sysfs_hal_active_set);
+static DEVICE_ATTR(proximity, 0444, sensors1p_sysfs_proximity_show, NULL);
+static DEVICE_ATTR(hal, 0444, sensors1p_sysfs_hal_show, NULL);
+
+static struct attribute *sensors1p_attrs[] = {
+ &dev_attr_proximity_activate.attr,
+ &dev_attr_hal_activate.attr,
+ &dev_attr_proximity.attr,
+ &dev_attr_hal.attr,
+ NULL,
+};
+
+static struct attribute_group sensors1p_attr_group = {
+ .name = NULL,
+ .attrs = sensors1p_attrs,
+};
+
+static int __init sensors1p_probe(struct platform_device *pdev)
+{
+ int err = -EINVAL;
+ struct sensors1p_config *c;
+ struct sensors1p *s = NULL;
+
+ if (!pdev)
+ goto out;
+
+ c = pdev->dev.platform_data;
+
+ if (c == NULL) {
+ dev_err(&pdev->dev, "Error: Missconfigured.\n");
+ goto out;
+ }
+
+ s = kzalloc(sizeof(struct sensors1p), GFP_KERNEL);
+
+ if (s == NULL) {
+ dev_err(&pdev->dev,
+ "Could not allocate struct memory!\n");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ s->hal.pin = c->hal.pin;
+ err = gpio_request(c->hal.pin, "hal sensor");
+ if (err < 0) {
+ dev_err(&pdev->dev, "gpio_request failed with err: %d", err);
+ goto err_hal_gpio;
+ }
+
+ s->proximity.pin = c->proximity.pin;
+ err = gpio_request(c->proximity.pin, "proximity sensor");
+ if (err < 0) {
+ dev_err(&pdev->dev, "gpio_request failed with err: %d", err);
+ goto err_proximity_gpio;
+ }
+
+ s->hal.startup_time = s->hal.startup_time;
+ s->proximity.startup_time = s->proximity.startup_time;
+
+
+ s->hal.regulator = regulator_get(&pdev->dev, c->hal.regulator);
+
+ if (IS_ERR(s->hal.regulator)) {
+ dev_err(&pdev->dev, "regulator_get(\"%s\") failed.\n",
+ c->hal.regulator);
+ err = PTR_ERR(s->hal.regulator);
+ goto err_hal_reg;
+ }
+ s->proximity.regulator = regulator_get(&pdev->dev,
+ c->proximity.regulator);
+
+ if (IS_ERR(s->proximity.regulator)) {
+ dev_err(&pdev->dev, "regulator_get(\"%s\") failed.\n",
+ c->proximity.regulator);
+ err = PTR_ERR(s->proximity.regulator);
+ goto err_proximity_reg;
+ }
+
+ err = sysfs_create_group(&pdev->dev.kobj, &sensors1p_attr_group);
+
+ if (err) {
+ dev_err(&pdev->dev, "Failed to create sysfs entries.\n");
+ goto err_sysfs;
+ }
+
+ platform_set_drvdata(pdev, s);
+
+ return 0;
+
+err_sysfs:
+ regulator_put(s->proximity.regulator);
+err_proximity_reg:
+ regulator_put(s->hal.regulator);
+err_hal_reg:
+ gpio_free(s->proximity.pin);
+err_proximity_gpio:
+ gpio_free(s->hal.pin);
+err_hal_gpio:
+ kfree(s);
+out:
+ return err;
+}
+
+static int __exit sensors1p_remove(struct platform_device *pdev)
+{
+ struct sensors1p *s = platform_get_drvdata(pdev);
+
+ sysfs_remove_group(&pdev->dev.kobj, &sensors1p_attr_group);
+ gpio_free(s->hal.pin);
+ gpio_free(s->proximity.pin);
+ regulator_put(s->hal.regulator);
+ regulator_put(s->proximity.regulator);
+ kfree(s);
+ return 0;
+}
+
+static struct platform_driver sensors1p_driver = {
+ .probe = sensors1p_probe,
+ .remove = __exit_p(sensors1p_remove),
+ .driver = {
+ .name = "sensors1p",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sensors1p_init(void)
+{
+ return platform_driver_register(&sensors1p_driver);
+}
+
+static void __exit sensors1p_exit(void)
+{
+ platform_driver_unregister(&sensors1p_driver);
+}
+
+late_initcall(sensors1p_init);
+module_exit(sensors1p_exit);
+
+MODULE_AUTHOR("Jonas Aaberg <jonas.aberg@stericsson.com>");
+MODULE_DESCRIPTION("One pin gpio sensors driver (Proximity+HAL)");
+MODULE_LICENSE("GPLv2");
diff --git a/arch/arm/mach-ux500/ste-dma40-db8500.h b/arch/arm/mach-ux500/ste-dma40-db8500.h
deleted file mode 100644
index e7016278dfa..00000000000
--- a/arch/arm/mach-ux500/ste-dma40-db8500.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * arch/arm/mach-ux500/ste_dma40_db8500.h
- * DB8500-SoC-specific configuration for DMA40
- *
- * Copyright (C) ST-Ericsson 2007-2010
- * License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
- */
-#ifndef STE_DMA40_DB8500_H
-#define STE_DMA40_DB8500_H
-
-#define STEDMA40_NR_DEV 64
-
-enum dma_src_dev_type {
- STEDMA40_DEV_SPI0_RX = 0,
- STEDMA40_DEV_SD_MMC0_RX = 1,
- STEDMA40_DEV_SD_MMC1_RX = 2,
- STEDMA40_DEV_SD_MMC2_RX = 3,
- STEDMA40_DEV_I2C1_RX = 4,
- STEDMA40_DEV_I2C3_RX = 5,
- STEDMA40_DEV_I2C2_RX = 6,
- STEDMA40_DEV_I2C4_RX = 7, /* Only on V1 */
- STEDMA40_DEV_SSP0_RX = 8,
- STEDMA40_DEV_SSP1_RX = 9,
- STEDMA40_DEV_MCDE_RX = 10,
- STEDMA40_DEV_UART2_RX = 11,
- STEDMA40_DEV_UART1_RX = 12,
- STEDMA40_DEV_UART0_RX = 13,
- STEDMA40_DEV_MSP2_RX = 14,
- STEDMA40_DEV_I2C0_RX = 15,
- STEDMA40_DEV_USB_OTG_IEP_8 = 16,
- STEDMA40_DEV_USB_OTG_IEP_1_9 = 17,
- STEDMA40_DEV_USB_OTG_IEP_2_10 = 18,
- STEDMA40_DEV_USB_OTG_IEP_3_11 = 19,
- STEDMA40_DEV_SLIM0_CH0_RX_HSI_RX_CH0 = 20,
- STEDMA40_DEV_SLIM0_CH1_RX_HSI_RX_CH1 = 21,
- STEDMA40_DEV_SLIM0_CH2_RX_HSI_RX_CH2 = 22,
- STEDMA40_DEV_SLIM0_CH3_RX_HSI_RX_CH3 = 23,
- STEDMA40_DEV_SRC_SXA0_RX_TX = 24,
- STEDMA40_DEV_SRC_SXA1_RX_TX = 25,
- STEDMA40_DEV_SRC_SXA2_RX_TX = 26,
- STEDMA40_DEV_SRC_SXA3_RX_TX = 27,
- STEDMA40_DEV_SD_MM2_RX = 28,
- STEDMA40_DEV_SD_MM0_RX = 29,
- STEDMA40_DEV_MSP1_RX = 30,
- /*
- * This channel is either SlimBus or MSP,
- * never both at the same time.
- */
- STEDMA40_SLIM0_CH0_RX = 31,
- STEDMA40_DEV_MSP0_RX = 31,
- STEDMA40_DEV_SD_MM1_RX = 32,
- STEDMA40_DEV_SPI2_RX = 33,
- STEDMA40_DEV_I2C3_RX2 = 34,
- STEDMA40_DEV_SPI1_RX = 35,
- STEDMA40_DEV_USB_OTG_IEP_4_12 = 36,
- STEDMA40_DEV_USB_OTG_IEP_5_13 = 37,
- STEDMA40_DEV_USB_OTG_IEP_6_14 = 38,
- STEDMA40_DEV_USB_OTG_IEP_7_15 = 39,
- STEDMA40_DEV_SPI3_RX = 40,
- STEDMA40_DEV_SD_MM3_RX = 41,
- STEDMA40_DEV_SD_MM4_RX = 42,
- STEDMA40_DEV_SD_MM5_RX = 43,
- STEDMA40_DEV_SRC_SXA4_RX_TX = 44,
- STEDMA40_DEV_SRC_SXA5_RX_TX = 45,
- STEDMA40_DEV_SRC_SXA6_RX_TX = 46,
- STEDMA40_DEV_SRC_SXA7_RX_TX = 47,
- STEDMA40_DEV_CAC1_RX = 48,
- /* RX channels 49 and 50 are unused */
- STEDMA40_DEV_MSHC_RX = 51,
- STEDMA40_DEV_SLIM1_CH0_RX_HSI_RX_CH4 = 52,
- STEDMA40_DEV_SLIM1_CH1_RX_HSI_RX_CH5 = 53,
- STEDMA40_DEV_SLIM1_CH2_RX_HSI_RX_CH6 = 54,
- STEDMA40_DEV_SLIM1_CH3_RX_HSI_RX_CH7 = 55,
- /* RX channels 56 thru 60 are unused */
- STEDMA40_DEV_CAC0_RX = 61,
- /* RX channels 62 and 63 are unused */
-};
-
-enum dma_dest_dev_type {
- STEDMA40_DEV_SPI0_TX = 0,
- STEDMA40_DEV_SD_MMC0_TX = 1,
- STEDMA40_DEV_SD_MMC1_TX = 2,
- STEDMA40_DEV_SD_MMC2_TX = 3,
- STEDMA40_DEV_I2C1_TX = 4,
- STEDMA40_DEV_I2C3_TX = 5,
- STEDMA40_DEV_I2C2_TX = 6,
- STEDMA50_DEV_I2C4_TX = 7, /* Only on V1 */
- STEDMA40_DEV_SSP0_TX = 8,
- STEDMA40_DEV_SSP1_TX = 9,
- /* TX channel 10 is unused */
- STEDMA40_DEV_UART2_TX = 11,
- STEDMA40_DEV_UART1_TX = 12,
- STEDMA40_DEV_UART0_TX= 13,
- STEDMA40_DEV_MSP2_TX = 14,
- STEDMA40_DEV_I2C0_TX = 15,
- STEDMA40_DEV_USB_OTG_OEP_8 = 16,
- STEDMA40_DEV_USB_OTG_OEP_1_9 = 17,
- STEDMA40_DEV_USB_OTG_OEP_2_10= 18,
- STEDMA40_DEV_USB_OTG_OEP_3_11 = 19,
- STEDMA40_DEV_SLIM0_CH0_TX_HSI_TX_CH0 = 20,
- STEDMA40_DEV_SLIM0_CH1_TX_HSI_TX_CH1 = 21,
- STEDMA40_DEV_SLIM0_CH2_TX_HSI_TX_CH2 = 22,
- STEDMA40_DEV_SLIM0_CH3_TX_HSI_TX_CH3 = 23,
- STEDMA40_DEV_DST_SXA0_RX_TX = 24,
- STEDMA40_DEV_DST_SXA1_RX_TX = 25,
- STEDMA40_DEV_DST_SXA2_RX_TX = 26,
- STEDMA40_DEV_DST_SXA3_RX_TX = 27,
- STEDMA40_DEV_SD_MM2_TX = 28,
- STEDMA40_DEV_SD_MM0_TX = 29,
- STEDMA40_DEV_MSP1_TX = 30,
- /*
- * This channel is either SlimBus or MSP,
- * never both at the same time.
- */
- STEDMA40_SLIM0_CH0_TX = 31,
- STEDMA40_DEV_MSP0_TX = 31,
- STEDMA40_DEV_SD_MM1_TX = 32,
- STEDMA40_DEV_SPI2_TX = 33,
- /* Secondary I2C3 channel */
- STEDMA40_DEV_I2C3_TX2 = 34,
- STEDMA40_DEV_SPI1_TX = 35,
- STEDMA40_DEV_USB_OTG_OEP_4_12 = 36,
- STEDMA40_DEV_USB_OTG_OEP_5_13 = 37,
- STEDMA40_DEV_USB_OTG_OEP_6_14 = 38,
- STEDMA40_DEV_USB_OTG_OEP_7_15 = 39,
- STEDMA40_DEV_SPI3_TX = 40,
- STEDMA40_DEV_SD_MM3_TX = 41,
- STEDMA40_DEV_SD_MM4_TX = 42,
- STEDMA40_DEV_SD_MM5_TX = 43,
- STEDMA40_DEV_DST_SXA4_RX_TX = 44,
- STEDMA40_DEV_DST_SXA5_RX_TX = 45,
- STEDMA40_DEV_DST_SXA6_RX_TX = 46,
- STEDMA40_DEV_DST_SXA7_RX_TX = 47,
- STEDMA40_DEV_CAC1_TX = 48,
- STEDMA40_DEV_CAC1_TX_HAC1_TX = 49,
- STEDMA40_DEV_HAC1_TX = 50,
- STEDMA40_MEMXCPY_TX_0 = 51,
- STEDMA40_DEV_SLIM1_CH0_TX_HSI_TX_CH4 = 52,
- STEDMA40_DEV_SLIM1_CH1_TX_HSI_TX_CH5 = 53,
- STEDMA40_DEV_SLIM1_CH2_TX_HSI_TX_CH6 = 54,
- STEDMA40_DEV_SLIM1_CH3_TX_HSI_TX_CH7 = 55,
- STEDMA40_MEMCPY_TX_1 = 56,
- STEDMA40_MEMCPY_TX_2 = 57,
- STEDMA40_MEMCPY_TX_3 = 58,
- STEDMA40_MEMCPY_TX_4 = 59,
- STEDMA40_MEMCPY_TX_5 = 60,
- STEDMA40_DEV_CAC0_TX = 61,
- STEDMA40_DEV_CAC0_TX_HAC0_TX = 62,
- STEDMA40_DEV_HAC0_TX = 63,
-};
-
-#endif
diff --git a/arch/arm/mach-ux500/suspend.c b/arch/arm/mach-ux500/suspend.c
new file mode 100644
index 00000000000..d13904f8c4a
--- /dev/null
+++ b/arch/arm/mach-ux500/suspend.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Authors: Rickard Andersson <rickard.andersson@stericsson.com>,
+ * Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ */
+
+#include <linux/suspend.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/prcmu-fw-api.h>
+#include <mach/prcmu-regs.h>
+
+#include "context.h"
+#include "pm-common.h"
+
+#define CONSOLE_GPIO_HACK 0x60000000
+#define MOP500_UART2RX_GPIO 29
+
+static int suspend_mem(void)
+{
+ /* TODO: Complete */
+ dsb();
+ __asm__ __volatile__("wfi\n\t" : : : "memory");
+ return 0;
+}
+
+static int suspend_standby(void)
+{
+
+ /*
+ * TODO: Please make sure if we need to copy the GIC
+ * settings to the PRCMU or not in ApSleep!
+ */
+
+ /*
+ * FIXME : replace these with generic APIs. this is
+ * a hack!!
+ */
+ writel(readl(GPIO_BK0_DAT) | CONSOLE_GPIO_HACK, GPIO_BK0_DAT);
+
+ /* configure the prcm for a sleep wakeup */
+ /* TODO: Replace with proper prcmu call */
+ prcmu_configure_wakeup_events(PRCMU_WAKEUPBY_MODEM |
+ PRCMU_WAKEUPBY_ARMITMGMT |
+ PRCMU_WAKEUPBY_APE4500INT |
+ PRCMU_WAKEUPBY_GPIOS |
+ /* TODO: RTC/RTT wakeup, really needed?*/
+ PRCMU_WAKEUPBY_RTCRTT,
+ 0x0,
+ LOW_POWER_WAKEUP);
+
+ context_vape_save();
+
+ decouple_gic();
+
+ /* TODO: Use proper define */
+ run_arm_on_ext_clk(0);
+
+ if (pending_gic_interrupt()) {
+ /* TODO: Change when prcmufw API changed */
+ prcmu_configure_wakeup_events(0, 0, 0);
+ /* TODO: Use proper define */
+ run_arm_on_arm_pll(0);
+ /* Recouple GIC with the interrupt bus */
+ recouple_gic();
+ return 0;
+ }
+ prcmu_set_ioforce();
+
+ (void) prcmu_set_power_state(APEXECUTE_TO_APSLEEP);
+ dsb();
+ __asm__ __volatile__("wfi\n\t" : : : "memory");
+
+ context_vape_restore();
+
+ /* Catch pending GIC interrupts */
+ catch_gpio_wake_up_status();
+
+ /* APE was turned off, restore IO ring */
+ prcmu_clr_ioforce();
+ return 0;
+}
+
+static int ux500_suspend_enter(suspend_state_t state)
+{
+ int ret;
+
+ switch (state) {
+ case PM_SUSPEND_MEM:
+ ret = suspend_mem();
+ break;
+ case PM_SUSPEND_STANDBY:
+ ret = suspend_standby();
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int ux500_suspend_valid(suspend_state_t state)
+{
+ return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY;
+}
+
+static void ux500_suspend_finish(void)
+{
+
+}
+
+static int ux500_suspend_begin(suspend_state_t state)
+{
+ return 0;
+}
+
+static int ux500_suspend_prepare(void)
+{
+ return 0;
+}
+
+static struct platform_suspend_ops ux500_suspend_ops = {
+ .begin = ux500_suspend_begin,
+ .prepare = ux500_suspend_prepare,
+ .enter = ux500_suspend_enter,
+ .finish = ux500_suspend_finish,
+ .valid = ux500_suspend_valid,
+};
+
+static __init int ux500_suspend_init(void)
+{
+
+ /* make the UART2-Rx/GPIO29 as a wakeup event */
+ /* FIXME: This should not be hardcoded here */
+ set_irq_type(GPIO_TO_IRQ(MOP500_UART2RX_GPIO), IRQ_TYPE_EDGE_BOTH);
+ set_irq_wake(GPIO_TO_IRQ(MOP500_UART2RX_GPIO), 1);
+
+ suspend_set_ops(&ux500_suspend_ops);
+ return 0;
+}
+
+device_initcall(ux500_suspend_init);
diff --git a/arch/arm/mach-ux500/tee_service_svp.c b/arch/arm/mach-ux500/tee_service_svp.c
new file mode 100644
index 00000000000..aa65dd961a0
--- /dev/null
+++ b/arch/arm/mach-ux500/tee_service_svp.c
@@ -0,0 +1,66 @@
+/*
+ * TEE service to handle the calls to trusted applications in SVP.
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/tee.h>
+#include <linux/err.h>
+#include "mach/tee_ta_start_modem.h"
+
+static int cmp_uuid_start_modem(struct tee_uuid *uuid)
+{
+ int ret = -EINVAL;
+
+ if (uuid == NULL)
+ return -EINVAL;
+
+ /* This handles the calls to TA for start the modem */
+ if ((uuid->timeLow == UUID_TEE_TA_START_MODEM_LOW) &&
+ (uuid->timeMid == UUID_TEE_TA_START_MODEM_MID) &&
+ (uuid->timeHiAndVersion == UUID_TEE_TA_START_MODEM_HIGH)) {
+
+ u8 clockSeqAndNode[TEE_UUID_CLOCK_SIZE] =
+ UUID_TEE_TA_START_MODEM_CLOCKSEQ;
+
+ ret = memcmp(uuid->clockSeqAndNode, clockSeqAndNode,
+ TEE_UUID_CLOCK_SIZE);
+ }
+
+ return ret;
+}
+
+int call_sec_world(struct tee_session *ts, int sec_cmd)
+{
+ int ret = 0;
+
+ if (ts == NULL)
+ return -EINVAL;
+
+ if (cmp_uuid_start_modem(ts->uuid))
+ return -EINVAL;
+
+ switch (ts->cmd) {
+ case COMMAND_ID_START_MODEM:
+ ret = tee_ta_start_modem((struct tee_ta_start_modem *)
+ ts->op);
+ if (ret) {
+ ts->err = TEED_ERROR_GENERIC;
+ ts->origin = TEED_ORIGIN_TEE_APPLICATION;
+ pr_err("tee_ta_start_modem() failed!\n");
+ return ret;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* TODO: to handle more trusted applications. */
+
+ return ret;
+}
diff --git a/arch/arm/mach-ux500/tee_ta_start_modem_svp.c b/arch/arm/mach-ux500/tee_ta_start_modem_svp.c
new file mode 100644
index 00000000000..12337b93154
--- /dev/null
+++ b/arch/arm/mach-ux500/tee_ta_start_modem_svp.c
@@ -0,0 +1,56 @@
+/*
+ * Trusted application for starting the modem.
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/elf.h>
+#include <mach/hardware.h>
+
+#include "mach/tee_ta_start_modem.h"
+
+static int reset_modem(unsigned long modem_start_addr)
+{
+ void __iomem *base = ioremap(U5500_ACCCON_BASE_SEC, 0x2FF);
+ if (!base)
+ return -ENOMEM;
+
+ pr_info("[%s] Setting modem start address!\n", __func__);
+ writel(base + (U5500_ACCCON_CPUVEC_RESET_ADDR_OFFSET/sizeof(uint32_t)),
+ modem_start_addr);
+
+ pr_info("[%s] resetting the modem!\n", __func__);
+ writel(base + (U5500_ACCCON_ACC_CPU_CTRL_OFFSET/sizeof(uint32_t)), 1);
+
+ iounmap(base);
+
+ return 0;
+}
+
+int tee_ta_start_modem(struct tee_ta_start_modem *data)
+{
+ int ret = 0;
+ struct elfhdr *elfhdr;
+ void __iomem *vaddr;
+
+ vaddr = ioremap((unsigned long)data->access_image_descr.elf_hdr,
+ sizeof(struct elfhdr));
+ if (!vaddr)
+ return -ENOMEM;
+
+ elfhdr = (struct elfhdr *)readl(vaddr);
+ pr_info("Reading in kernel:elfhdr 0x%x:elfhdr->entry=0x%x\n",
+ (uint32_t)elfhdr, (uint32_t)elfhdr->e_entry);
+
+ pr_info("[%s] reset modem()...\n", __func__);
+ ret = reset_modem(elfhdr->e_entry);
+
+ iounmap(vaddr);
+
+ return ret;
+}
diff --git a/arch/arm/mach-ux500/tee_ux500.c b/arch/arm/mach-ux500/tee_ux500.c
new file mode 100644
index 00000000000..2e6a2e89f0d
--- /dev/null
+++ b/arch/arm/mach-ux500/tee_ux500.c
@@ -0,0 +1,97 @@
+/*
+ * TEE service to handle the calls to trusted applications.
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#include <linux/kernel.h>
+#include <linux/tee.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+
+#include <mach/hardware.h>
+
+#define ISSWAPI_EXECUTE_TA 0x11000001
+#define ISSWAPI_CLOSE_TA 0x11000002
+
+#define SEC_ROM_NO_FLAG_MASK 0x0000
+
+static u32 call_sec_rom_bridge(u32 service_id, u32 cfg, ...)
+{
+ typedef u32 (*bridge_func)(u32, u32, va_list);
+ static bridge_func hw_sec_rom_pub_bridge;
+ va_list ap;
+ u32 ret;
+
+ if (cpu_is_u8500())
+ hw_sec_rom_pub_bridge = (bridge_func)
+ ((u32)IO_ADDRESS(U8500_BOOT_ROM_BASE + 0x18300));
+ else if (cpu_is_u5500())
+ hw_sec_rom_pub_bridge = (bridge_func)
+ ((u32)IO_ADDRESS(U5500_BOOT_ROM_BASE + 0x18300));
+ else {
+ pr_err("tee-ux500: Unknown DB Asic!\n");
+ return -EIO;
+ }
+
+ va_start(ap, cfg);
+ ret = hw_sec_rom_pub_bridge(service_id, cfg, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+int call_sec_world(struct tee_session *ts, int sec_cmd)
+{
+ /*
+ * ts->ta and ts->uuid is set to NULL when opening the device,
+ * hence it should be safe to just do the call here.
+ */
+
+ switch (sec_cmd) {
+ case TEED_INVOKE:
+ if (!ts->uuid) {
+ call_sec_rom_bridge(ISSWAPI_EXECUTE_TA,
+ SEC_ROM_NO_FLAG_MASK,
+ virt_to_phys(&ts->id),
+ NULL,
+ virt_to_phys(ts->ta),
+ ts->cmd,
+ virt_to_phys((void *)(ts->op)),
+ virt_to_phys((void *)(&ts->err)),
+ virt_to_phys((void *)(&ts->origin)));
+ } else {
+ call_sec_rom_bridge(ISSWAPI_EXECUTE_TA,
+ SEC_ROM_NO_FLAG_MASK,
+ virt_to_phys(&ts->id),
+ virt_to_phys(ts->uuid),
+ virt_to_phys(ts->ta),
+ ts->cmd,
+ virt_to_phys((void *)(ts->op)),
+ virt_to_phys((void *)(&ts->err)),
+ virt_to_phys((void *)(&ts->origin)));
+ }
+ break;
+
+ case TEED_CLOSE_SESSION:
+ call_sec_rom_bridge(ISSWAPI_CLOSE_TA,
+ SEC_ROM_NO_FLAG_MASK,
+ ts->id,
+ NULL,
+ virt_to_phys(ts->ta),
+ virt_to_phys((void *)(&ts->err)));
+
+ /* Since the TEE Client API does NOT take care of
+ * the return value, we print a warning here if
+ * something went wrong in secure world.
+ */
+ if (ts->err != TEED_SUCCESS)
+ pr_warning("[%s] failed in secure world\n",
+ __func__);
+
+ break;
+ }
+
+ return 0;
+}
diff --git a/arch/arm/mach-ux500/timer-db8500-prcm.c b/arch/arm/mach-ux500/timer-db8500-prcm.c
new file mode 100644
index 00000000000..e6b398ffd92
--- /dev/null
+++ b/arch/arm/mach-ux500/timer-db8500-prcm.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ * DB8500-PRCM Timer
+ * The PRCM has 5 timers which are available in a always-on
+ * power domain. we use the Timer 5 for our always-on clock source.
+ */
+#include <linux/io.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+#include <linux/jiffies.h>
+#include <mach/setup.h>
+#include <mach/prcmu-regs.h>
+
+#define RATE_32K (32768)
+
+#define TIMER_MODE_CONTINOUS (0x1)
+#define TIMER_DOWNCOUNT_VAL (0xffffffff)
+
+/*
+ * clocksource: the prcm timer is a decrementing counters, so we negate
+ * the value being read.
+ */
+static cycle_t db8500_prcm_read_timer(struct clocksource *cs)
+{
+ static u32 delta;
+ static u32 old = 0xffffffff;
+ static int print_once = 1;
+ u32 count;
+
+ if (print_once) {
+ print_once = 0;
+ printk(KERN_ERR "*******************************************************************************\n");
+ printk(KERN_ERR "* You have compiled your kernel with the PRCMU timer clocksource *\n");
+ printk(KERN_ERR "* On db8500 v1.0, v1.1 and v2.0, it frequently jumps backwards in time *\n");
+ printk(KERN_ERR "* It is not in use by default, but can be used via: \"echo db8500-prcm-timer5 >*\n");
+ printk(KERN_ERR "* /sys/devices/system/clocksource/clocksource0/current_clocksource\") *\n");
+ }
+
+ count = readl(PRCM_TIMER_5_DOWNCOUNT);
+
+ /*
+ * WARNING: PRCMU timer 3, 4 and 5 jumps backwards in time
+ * about 20 times a minute.
+ */
+
+ /* Check backwards and handle restart */
+ if ((count > old) && (count - old) < 0xf0000000)
+ delta += count - old + 1;
+
+ old = count;
+
+ count -= delta;
+ return ~count;
+}
+
+static struct clocksource db8500_prcm_clksrc = {
+ .name = "db8500-prcm-timer5",
+ /* FIXME: Worst timer ever due to hw issues */
+ .rating = 0,
+ .read = db8500_prcm_read_timer,
+ .shift = 10,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+void __init db8500_prcm_timer_init(void)
+{
+ /*
+ * The A9 sub system expects the timer to be configured as
+ * a continous looping timer. If this timer is not configured
+ * in such a mode, then do so.
+ * Later on, when the PRCM decides to init this timer, the A9
+ * can rest assure that it need not init the timer
+ */
+ if (readl(PRCM_TIMER_5_MODE) != TIMER_MODE_CONTINOUS) {
+ writel(TIMER_MODE_CONTINOUS, PRCM_TIMER_5_MODE);
+ writel(TIMER_DOWNCOUNT_VAL, PRCM_TIMER_5_REF);
+ }
+
+ /* register the clock source */
+ db8500_prcm_clksrc.mult = clocksource_hz2mult(RATE_32K,
+ db8500_prcm_clksrc.shift);
+
+ clocksource_register(&db8500_prcm_clksrc);
+
+ return;
+}
+
diff --git a/arch/arm/mach-ux500/timer-rtt.c b/arch/arm/mach-ux500/timer-rtt.c
new file mode 100644
index 00000000000..88f61830dbd
--- /dev/null
+++ b/arch/arm/mach-ux500/timer-rtt.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/clockchips.h>
+#include <asm/smp.h>
+#include <asm/mach/time.h>
+
+#define RATE_32K 32768
+#define LATCH_32K ((RATE_32K + HZ/2) / HZ)
+
+#define WRITE_DELAY 130 /* in us */
+#define WRITE_DELAY_32KHZ_TICKS ((WRITE_DELAY * RATE_32K) / 1000000)
+
+#define RTT_IMSC 0x04
+#define RTT_ICR 0x10
+#define RTT_DR 0x14
+#define RTT_LR 0x18
+#define RTT_CR 0x1C
+
+#define RTT_CR_RTTEN (1 << 1)
+#define RTT_CR_RTTOS (1 << 0)
+
+#define RTC_IMSC 0x10
+#define RTC_RIS 0x14
+#define RTC_MIS 0x18
+#define RTC_ICR 0x1C
+#define RTC_TDR 0x20
+#define RTC_TLR1 0x24
+#define RTC_TCR 0x28
+
+#define RTC_TCR_RTTOS (1 << 0)
+#define RTC_TCR_RTTEN (1 << 1)
+#define RTC_TCR_RTTSS (1 << 2)
+
+#define RTC_IMSC_TIMSC (1 << 1)
+#define RTC_ICR_TIC (1 << 1)
+
+static void __iomem *rtc_base;
+static void __iomem *rtt0_base;
+
+static void rtc_writel(unsigned long val, unsigned long addr)
+{
+ writel(val, rtc_base + addr);
+}
+
+static unsigned long rtc_readl(unsigned long addr)
+{
+ return readl(rtc_base + addr);
+}
+
+static void u8500_rtc_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ rtc_writel(RTC_TCR_RTTSS, RTC_TCR);
+ rtc_writel(LATCH_32K, RTC_TLR1);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ rtc_writel(0, RTC_TCR);
+ break;
+
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ rtc_writel(0, RTC_TCR);
+ break;
+
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+
+ }
+}
+
+#include <linux/delay.h>
+static int u8500_rtc_set_event(unsigned long delta,
+ struct clock_event_device *dev)
+{
+
+ rtc_writel(RTC_TCR_RTTOS, RTC_TCR);
+ udelay(WRITE_DELAY);
+
+ /*
+ * Compensate for the time that it takes to start the
+ * timer
+ */
+ if (delta > WRITE_DELAY_32KHZ_TICKS * 2)
+ delta -= WRITE_DELAY_32KHZ_TICKS * 2;
+ else
+ delta = 1;
+ rtc_writel(delta, RTC_TLR1);
+ udelay(WRITE_DELAY);
+
+ rtc_writel(RTC_TCR_RTTOS | RTC_TCR_RTTEN, RTC_TCR);
+ udelay(WRITE_DELAY);
+
+
+ return 0;
+}
+
+static irqreturn_t u8500_rtc_interrupt(int irq, void *dev)
+{
+ struct clock_event_device *clkevt = dev;
+
+ /* we make sure if this is our rtt isr */
+ if (rtc_readl(RTC_MIS) & 0x2) {
+ rtc_writel(RTC_ICR_TIC, RTC_ICR);
+ clkevt->event_handler(clkevt);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+/*
+ * Added here as asm/smp.h is removed in v2.6.34 and
+ * this funcitons is needed for current PM setup.
+ */
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+void smp_timer_broadcast(const struct cpumask *mask);
+#endif
+
+static struct clock_event_device u8500_rtc = {
+ .name = "rtc",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .rating = 300,
+ .set_next_event = u8500_rtc_set_event,
+ .set_mode = u8500_rtc_set_mode,
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+ .broadcast = smp_timer_broadcast,
+#endif
+ .irq = IRQ_RTC_RTT,
+ .cpumask = cpu_all_mask,
+};
+
+static struct irqaction u8500_rtc_irq = {
+ .name = "rtc",
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_SHARED,
+ .handler = u8500_rtc_interrupt,
+ .dev_id = &u8500_rtc,
+};
+
+void u8500_rtc_init(unsigned int cpu)
+{
+ if (cpu_is_u8500()) {
+ rtc_base = __io_address(U8500_RTC_BASE);
+ rtt0_base = __io_address(U8500_RTT0_BASE);
+ } else if (cpu_is_u5500()) {
+ rtc_base = __io_address(U5500_RTC_BASE);
+ rtt0_base = __io_address(U5500_RTT0_BASE);
+ } else {
+ pr_err("timer-rtt: Unknown DB Asic!\n");
+ return;
+ }
+
+ rtc_writel(0, RTC_TCR);
+ rtc_writel(1, RTC_ICR);
+ rtc_writel(RTC_IMSC_TIMSC, RTC_IMSC);
+
+ u8500_rtc.mult = div_sc(RATE_32K, NSEC_PER_SEC, u8500_rtc.shift);
+ u8500_rtc.max_delta_ns = clockevent_delta2ns(0xffffffff, &u8500_rtc);
+ u8500_rtc.min_delta_ns = clockevent_delta2ns(0xff, &u8500_rtc);
+
+ setup_irq(IRQ_RTC_RTT, &u8500_rtc_irq);
+ clockevents_register_device(&u8500_rtc);
+}
diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c
new file mode 100644
index 00000000000..78204ec9416
--- /dev/null
+++ b/arch/arm/mach-ux500/timer.c
@@ -0,0 +1,301 @@
+/*
+ * linux/arch/arm/mach-u8500/timer.c
+ *
+ * Copyright (C) 2008 STMicroelectronics
+ * Copyright (C) 2009 Alessandro Rubini, somewhat based on at91sam926x
+ * Copyright (C) 2009 ST-Ericsson SA
+ * added support to u8500 platform, heavily based on 8815
+ * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.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/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/jiffies.h>
+#include <linux/boottime.h>
+#include <asm/mach/time.h>
+#include <mach/mtu.h>
+#include <mach/setup.h>
+
+#define TIMER_CTRL 0x80 /* No divisor */
+#define TIMER_PERIODIC 0x40
+#define TIMER_SZ32BIT 0x02
+
+static u32 u8500_count; /* accumulated count */
+static u32 u8500_cycle; /* write-once */
+static __iomem void *mtu0_base;
+static __iomem void *mtu1_base;
+
+/*
+ * clocksource: the MTU device is a decrementing counters, so we negate
+ * the value being read.
+ */
+static cycle_t u8500_read_timer(struct clocksource *cs)
+{
+ u32 count = readl(mtu1_base + MTU_VAL(0));
+ return ~count;
+}
+/*
+ * Kernel assumes that sched_clock can be called early
+ * but the MTU may not yet be initialized.
+ */
+static cycle_t u8500_read_timer_dummy(struct clocksource *cs)
+{
+ return 0;
+}
+
+
+static void u8500_timer_reset(void);
+
+static void u8500_clocksource_resume(struct clocksource *cs)
+{
+ u8500_timer_reset();
+}
+
+static struct clocksource u8500_clksrc = {
+ .name = "mtu_1",
+ .rating = 120,
+ .read = u8500_read_timer_dummy,
+ .shift = 20,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .resume = u8500_clocksource_resume,
+};
+
+/*
+ * Clockevent device: currently only periodic mode is supported
+ */
+static void u8500_clkevt_mode(enum clock_event_mode mode,
+ struct clock_event_device *dev)
+{
+ unsigned long flags;
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* enable interrupts -- and count current value? */
+ raw_local_irq_save(flags);
+ writel(1, mtu0_base + MTU_IMSC);
+ raw_local_irq_restore(flags);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ BUG(); /* Not yet supported */
+ /* FALLTHROUGH */
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ /* disable irq */
+ raw_local_irq_save(flags);
+ writel(0, mtu0_base + MTU_IMSC);
+ raw_local_irq_restore(flags);
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static struct clock_event_device u8500_clkevt = {
+ .name = "mtu_0",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .shift = 32,
+ .rating = 100,
+ .set_mode = u8500_clkevt_mode,
+ .irq = IRQ_MTU0,
+};
+
+
+/*
+ * Override the global weak sched_clock symbol with this
+ * local implementation which uses the clocksource to get some
+ * better resolution when scheduling the kernel. We accept that
+ * this wraps around for now, since it is just a relative time
+ * stamp. (Inspired by OMAP implementation.)
+ */
+unsigned long long notrace sched_clock(void)
+{
+ return clocksource_cyc2ns(u8500_clksrc.read(NULL),
+ u8500_clksrc.mult,
+ u8500_clksrc.shift);
+}
+
+/*
+ * IRQ Handler for the timer 0 of the MTU block. The irq is not shared
+ * as we are the only users of mtu0 by now.
+ */
+static irqreturn_t u8500_timer_interrupt(int irq, void *dev_id)
+{
+ /* ack: "interrupt clear register" */
+ writel(1 << 0, mtu0_base + MTU_ICR);
+
+ u8500_clkevt.event_handler(&u8500_clkevt);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+static struct irqaction u8500_timer_irq = {
+ .name = "U8500 Timer Tick",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = u8500_timer_interrupt,
+};
+
+static void u8500_timer_reset(void)
+{
+ u32 cr;
+
+ writel(0, mtu0_base + MTU_CR(0)); /* off */
+ writel(0, mtu1_base + MTU_CR(0)); /* off */
+
+ /* Timer: configure load and background-load, and fire it up */
+ writel(u8500_cycle, mtu0_base + MTU_LR(0));
+ writel(u8500_cycle, mtu0_base + MTU_BGLR(0));
+ cr = MTU_CRn_PERIODIC | (MTU_CRn_PRESCALE_1 << 2) | MTU_CRn_32BITS;
+ writel(cr, mtu0_base + MTU_CR(0));
+ writel(cr | MTU_CRn_ENA, mtu0_base + MTU_CR(0));
+
+ /* CS: configure load and background-load, and fire it up */
+ writel(u8500_cycle, mtu1_base + MTU_LR(0));
+ writel(u8500_cycle, mtu1_base + MTU_BGLR(0));
+ cr = (MTU_CRn_PRESCALE_1 << 2) | MTU_CRn_32BITS;
+ writel(cr, mtu1_base + MTU_CR(0));
+ writel(cr | MTU_CRn_ENA, mtu1_base + MTU_CR(0));
+}
+
+#ifdef CONFIG_BOOTTIME
+static unsigned long boottime_mtu_rate;
+
+#define MTU_TICKS_TO_US(x) (10 * (x) / (10 * (boottime_mtu_rate / 16) / 1000000))
+#define MTU_BOOTTIME_TIMER 2
+
+static unsigned long __init boottime_mtu_time(void)
+{
+ unsigned long count = ~readl(mtu0_base + MTU_VAL(MTU_BOOTTIME_TIMER));
+ return MTU_TICKS_TO_US(count);
+}
+
+static int __init boottime_mtu_alloc(void)
+{
+ u32 cr;
+ u32 val;
+ struct clk *clk0;
+
+ clk0 = clk_get_sys("mtu0", NULL);
+ BUG_ON(IS_ERR(clk0));
+
+ clk_enable(clk0);
+
+ boottime_mtu_rate = clk_get_rate(clk0);
+
+ /* Check that the timer is actually running */
+ cr = readl(mtu0_base + MTU_CR(MTU_BOOTTIME_TIMER));
+ val = readl(mtu0_base + MTU_VAL(MTU_BOOTTIME_TIMER));
+
+ if (cr != (MTU_CRn_PRESCALE_16 | MTU_CRn_32BITS | MTU_CRn_ENA) ||
+ val == 0) {
+ printk(KERN_INFO
+ "boottime: MTU timer %d not configured in boot loader\n",
+ MTU_BOOTTIME_TIMER);
+ /* Start the timer now */
+ cr = MTU_CRn_PRESCALE_16 | MTU_CRn_32BITS | MTU_CRn_ENA;
+ writel(cr, mtu0_base + MTU_CR(MTU_BOOTTIME_TIMER));
+ writel(0, mtu0_base + MTU_LR(MTU_BOOTTIME_TIMER));
+ }
+
+ return 0;
+}
+
+static void __init boottime_mtu_free(void)
+{
+ struct clk *clk0;
+
+ clk0 = clk_get_sys("mtu0", NULL);
+
+ writel(0, mtu0_base + MTU_CR(MTU_BOOTTIME_TIMER)); /* off */
+ clk_disable(clk0);
+}
+
+struct boottime_timer __initdata boottime_timer = {
+ .init = boottime_mtu_alloc,
+ .get_time = boottime_mtu_time,
+ .finalize = boottime_mtu_free,
+};
+#endif
+
+static void __init u8500_timer_init(void)
+{
+ unsigned long rate;
+ struct clk *clk0;
+ struct clk *clk1;
+ int bits;
+
+#ifdef CONFIG_LOCAL_TIMERS
+ twd_base = (void *)IO_ADDRESS(UX500_TWD_BASE);
+#endif
+ clk0 = clk_get_sys("mtu0", NULL);
+ BUG_ON(IS_ERR(clk0));
+
+ clk1 = clk_get_sys("mtu1", NULL);
+ BUG_ON(IS_ERR(clk1));
+
+ clk_enable(clk0);
+ clk_enable(clk1);
+
+ rate = clk_get_rate(clk0);
+ u8500_cycle = (rate + HZ/2) / HZ;
+
+ /* Save global pointer to mtu, used by functions above */
+ if (cpu_is_u8500ed()) {
+ mtu0_base = (void *)IO_ADDRESS(U8500_MTU0_BASE_ED);
+ mtu1_base = (void *)IO_ADDRESS(U8500_MTU1_BASE_ED);
+ } else {
+ mtu0_base = (void *)IO_ADDRESS(UX500_MTU0_BASE);
+ mtu1_base = (void *)IO_ADDRESS(UX500_MTU1_BASE);
+ }
+
+ /* Init the timer and register clocksource */
+ u8500_timer_reset();
+
+#if defined(CONFIG_UX500_SOC_DB8500) && defined(CONFIG_U8500_PRCMU_TIMER)
+ /* register db8500-prcmu timer as always-on clock source */
+ if (cpu_is_u8500() && !machine_is_svp())
+ db8500_prcm_timer_init();
+#endif
+
+ /* Now the scheduling clock is ready */
+ u8500_clksrc.read = u8500_read_timer;
+
+ boottime_activate(&boottime_timer);
+
+ u8500_clksrc.mult = clocksource_hz2mult(rate, u8500_clksrc.shift);
+ bits = 8*sizeof(u8500_count);
+
+ clocksource_register(&u8500_clksrc);
+
+ /* Register irq and clockevents */
+ setup_irq(IRQ_MTU0, &u8500_timer_irq);
+ u8500_clkevt.mult = div_sc(rate, NSEC_PER_SEC, u8500_clkevt.shift);
+ u8500_clkevt.cpumask = cpumask_of(0);
+ clockevents_register_device(&u8500_clkevt);
+ {
+ extern void u8500_rtc_init(unsigned int cpu);
+ u8500_rtc_init(0);
+ }
+}
+
+static void u8500_timer_suspend(void)
+{
+ /* not supported yet */
+}
+
+struct sys_timer u8500_timer = {
+ .init = u8500_timer_init,
+ .suspend = u8500_timer_suspend,
+ .resume = u8500_timer_reset,
+};
diff --git a/arch/arm/mach-ux500/virt-regulator-u8500.c b/arch/arm/mach-ux500/virt-regulator-u8500.c
new file mode 100644
index 00000000000..64b1b0192d6
--- /dev/null
+++ b/arch/arm/mach-ux500/virt-regulator-u8500.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * Board specific file for configuration of virtual regulators. These virtual
+ * regulators are used for debug purposes. They connect to the regulator device
+ * just like any other consumer and expose controls in sysfs, so that
+ * regulators can be controlled from user space.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+/*
+ * Configuration for AB8500 virtual regulators
+ */
+static struct platform_device u8500_aux1_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 0,
+ .dev = {
+ .platform_data = "aux1",
+ },
+};
+
+static struct platform_device u8500_aux2_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 1,
+ .dev = {
+ .platform_data = "aux2",
+ },
+};
+
+static struct platform_device u8500_aux3_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 2,
+ .dev = {
+ .platform_data = "aux3",
+ },
+};
+
+static struct platform_device u8500_intcore_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 3,
+ .dev = {
+ .platform_data = "intcore",
+ },
+};
+
+static struct platform_device u8500_tvout_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 4,
+ .dev = {
+ .platform_data = "tvout",
+ },
+};
+
+static struct platform_device u8500_usb_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 5,
+ .dev = {
+ .platform_data = "usb",
+ },
+};
+
+static struct platform_device u8500_audio_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 6,
+ .dev = {
+ .platform_data = "audio",
+ },
+};
+
+static struct platform_device u8500_anamic1_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 7,
+ .dev = {
+ .platform_data = "anamic1",
+ },
+};
+
+static struct platform_device u8500_anamic2_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 8,
+ .dev = {
+ .platform_data = "anamic2",
+ },
+};
+
+static struct platform_device u8500_dmic_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 9,
+ .dev = {
+ .platform_data = "dmic",
+ },
+};
+
+static struct platform_device u8500_ana_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 10,
+ .dev = {
+ .platform_data = "ana",
+ },
+};
+
+/*
+ * Configuration for other U8500 virtual regulators
+ */
+static struct platform_device u8500_ape_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 11,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_arm_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 12,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_modem_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 13,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_pll_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 14,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_smps1_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 15,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_smps2_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 16,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_smps3_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 17,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_rf1_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 18,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+/*
+ * Configuration for U8500 power domain virtual regulators
+ */
+static struct platform_device u8500_sva_mmdsp_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 19,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_sva_pipe_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 20,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_sia_mmdsp_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 21,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_sia_pipe_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 22,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_sga_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 23,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_b2r2_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 24,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_mcde_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 25,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_esram1_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 26,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_esram2_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 27,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_esram3_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 28,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device u8500_esram4_virtual_regulator_device = {
+ .name = "reg-virt-consumer",
+ .id = 29,
+ .dev = {
+ .platform_data = "test",
+ },
+};
+
+static struct platform_device *u8500_virtual_regulator_devices[] = {
+ &u8500_aux1_virtual_regulator_device,
+ &u8500_aux2_virtual_regulator_device,
+ &u8500_aux3_virtual_regulator_device,
+ &u8500_intcore_virtual_regulator_device,
+ &u8500_tvout_virtual_regulator_device,
+ &u8500_usb_virtual_regulator_device,
+ &u8500_audio_virtual_regulator_device,
+ &u8500_anamic1_virtual_regulator_device,
+ &u8500_anamic2_virtual_regulator_device,
+ &u8500_dmic_virtual_regulator_device,
+ &u8500_ana_virtual_regulator_device,
+ &u8500_ape_virtual_regulator_device,
+ &u8500_arm_virtual_regulator_device,
+ &u8500_modem_virtual_regulator_device,
+ &u8500_pll_virtual_regulator_device,
+ &u8500_smps1_virtual_regulator_device,
+ &u8500_smps2_virtual_regulator_device,
+ &u8500_smps3_virtual_regulator_device,
+ &u8500_rf1_virtual_regulator_device,
+ &u8500_sva_mmdsp_virtual_regulator_device,
+ &u8500_sva_pipe_virtual_regulator_device,
+ &u8500_sia_mmdsp_virtual_regulator_device,
+ &u8500_sia_pipe_virtual_regulator_device,
+ &u8500_sga_virtual_regulator_device,
+ &u8500_b2r2_virtual_regulator_device,
+ &u8500_mcde_virtual_regulator_device,
+ &u8500_esram1_virtual_regulator_device,
+ &u8500_esram2_virtual_regulator_device,
+ &u8500_esram3_virtual_regulator_device,
+ &u8500_esram4_virtual_regulator_device,
+};
+
+static int __init u8500_virtual_regulator_init(void)
+{
+ int ret;
+
+ ret = platform_add_devices(u8500_virtual_regulator_devices,
+ ARRAY_SIZE(u8500_virtual_regulator_devices));
+ if (ret != 0)
+ pr_err("Failed to register U8500 virtual regulator devices:"
+ " %d\n", ret);
+
+ return ret;
+}
+module_init(u8500_virtual_regulator_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com");
+MODULE_DESCRIPTION("Configuration of u8500 virtual regulators");
+MODULE_ALIAS("platform:u8500-virtual-regulator");
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 3dff8641b03..6ccd2618a97 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -28,6 +28,7 @@
#include <linux/amba/clcd.h>
#include <linux/amba/pl061.h>
#include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
#include <linux/io.h>
#include <linux/gfp.h>
@@ -354,6 +355,21 @@ static struct mmci_platform_data mmc0_plat_data = {
.gpio_cd = -1,
};
+static struct resource char_lcd_resources[] = {
+ {
+ .start = VERSATILE_CHAR_LCD_BASE,
+ .end = (VERSATILE_CHAR_LCD_BASE + SZ_4K - 1),
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device char_lcd_device = {
+ .name = "arm-charlcd",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(char_lcd_resources),
+ .resource = char_lcd_resources,
+};
+
/*
* Clock handling
*/
@@ -425,6 +441,9 @@ static struct clk_lookup lookups[] = {
}, { /* MMC1 */
.dev_id = "fpga:0b",
.clk = &ref24_clk,
+ }, { /* SSP */
+ .dev_id = "dev:f4",
+ .clk = &ref24_clk,
}, { /* CLCD */
.dev_id = "dev:20",
.clk = &osc4_clk,
@@ -703,6 +722,12 @@ static struct pl061_platform_data gpio1_plat_data = {
.irq_base = IRQ_GPIO1_START,
};
+static struct pl022_ssp_controller ssp0_plat_data = {
+ .bus_id = 0,
+ .enable_dma = 0,
+ .num_chipselect = 1,
+};
+
#define AACI_IRQ { IRQ_AACI, NO_IRQ }
#define AACI_DMA { 0x80, 0x81 }
#define MMCI0_IRQ { IRQ_MMCI0A,IRQ_SIC_MMCI0B }
@@ -772,7 +797,7 @@ AMBA_DEVICE(sci0, "dev:f0", SCI, NULL);
AMBA_DEVICE(uart0, "dev:f1", UART0, NULL);
AMBA_DEVICE(uart1, "dev:f2", UART1, NULL);
AMBA_DEVICE(uart2, "dev:f3", UART2, NULL);
-AMBA_DEVICE(ssp0, "dev:f4", SSP, NULL);
+AMBA_DEVICE(ssp0, "dev:f4", SSP, &ssp0_plat_data);
static struct amba_device *amba_devs[] __initdata = {
&dmac_device,
@@ -843,6 +868,7 @@ void __init versatile_init(void)
platform_device_register(&versatile_flash_device);
platform_device_register(&versatile_i2c_device);
platform_device_register(&smc91x_device);
+ platform_device_register(&char_lcd_device);
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 9982eb385c0..47b40af48fe 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -103,12 +103,26 @@ static void l2x0_cache_sync(void)
spin_unlock_irqrestore(&l2x0_lock, flags);
}
+static void l2x0_flush_all(void)
+{
+ unsigned long flags;
+
+ /* clean all ways */
+ spin_lock_irqsave(&l2x0_lock, flags);
+ writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY);
+ cache_wait(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask);
+ cache_sync();
+ spin_unlock_irqrestore(&l2x0_lock, flags);
+}
+
static inline void l2x0_inv_all(void)
{
unsigned long flags;
/* invalidate all ways */
spin_lock_irqsave(&l2x0_lock, flags);
+ /* Invalidating when L2 is enabled is a nono */
+ BUG_ON(readl(l2x0_base + L2X0_CTRL) & 1);
writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
cache_sync();
@@ -206,6 +220,15 @@ static void l2x0_flush_range(unsigned long start, unsigned long end)
spin_unlock_irqrestore(&l2x0_lock, flags);
}
+static void l2x0_disable(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&l2x0_lock, flags);
+ writel(0, l2x0_base + L2X0_CTRL);
+ spin_unlock_irqrestore(&l2x0_lock, flags);
+}
+
void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
{
__u32 aux;
@@ -263,6 +286,9 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
outer_cache.clean_range = l2x0_clean_range;
outer_cache.flush_range = l2x0_flush_range;
outer_cache.sync = l2x0_cache_sync;
+ outer_cache.flush_all = l2x0_flush_all;
+ outer_cache.inv_all = l2x0_inv_all;
+ outer_cache.disable = l2x0_disable;
printk(KERN_INFO "%s cache controller enabled\n", type);
printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n",
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index f6a99946532..e00404e6f45 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -529,6 +529,11 @@ void __init mem_init(void)
{
unsigned long reserved_pages, free_pages;
int i, node;
+#ifdef CONFIG_HAVE_TCM
+ /* These pointers are filled in on TCM detection */
+ extern u32 dtcm_end;
+ extern u32 itcm_end;
+#endif
#ifndef CONFIG_DISCONTIGMEM
max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
@@ -611,6 +616,10 @@ void __init mem_init(void)
printk(KERN_NOTICE "Virtual kernel memory layout:\n"
" vector : 0x%08lx - 0x%08lx (%4ld kB)\n"
+#ifdef CONFIG_HAVE_TCM
+ " DTCM : 0x%08lx - 0x%08lx (%4ld kB)\n"
+ " ITCM : 0x%08lx - 0x%08lx (%4ld kB)\n"
+#endif
" fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
#ifdef CONFIG_MMU
" DMA : 0x%08lx - 0x%08lx (%4ld MB)\n"
@@ -627,6 +636,10 @@ void __init mem_init(void)
MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
(PAGE_SIZE)),
+#ifdef CONFIG_HAVE_TCM
+ MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
+ MLK(ITCM_OFFSET, (unsigned long) itcm_end),
+#endif
MLK(FIXADDR_START, FIXADDR_TOP),
#ifdef CONFIG_MMU
MLM(CONSISTENT_BASE, CONSISTENT_END),
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 28589417118..293e91862ef 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -258,6 +258,33 @@ static struct mem_type mem_types[] = {
.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
.domain = DOMAIN_KERNEL,
},
+ [MT_MEMORY_DTCM] = {
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG |
+ L_PTE_DIRTY | L_PTE_WRITE,
+ .prot_l1 = PMD_TYPE_TABLE,
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
+ .domain = DOMAIN_KERNEL,
+ },
+ [MT_MEMORY_ITCM] = {
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+ L_PTE_USER | L_PTE_EXEC,
+ .prot_l1 = PMD_TYPE_TABLE,
+ .domain = DOMAIN_IO,
+ },
+ /* NOTE : this is only a temporary hack!!!
+ * The U8500 ED/V1.0 cuts require such a
+ * memory type for deep sleep resume.
+ * This is expected to be solved in cut v2.0
+ * and we clean this up then. for more details
+ * look @ the commit message please
+ */
+ [MT_BACKUP_RAM] = {
+ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED |
+ L_PTE_SHARED | L_PTE_EXEC,
+ .prot_l1 = PMD_TYPE_TABLE,
+ .prot_sect = PROT_SECT_DEVICE | PMD_SECT_S,
+ .domain = DOMAIN_IO,
+ },
};
const struct mem_type *get_mem_type(unsigned int type)
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 7aaf88a3b7a..e4b039bb190 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -66,7 +66,18 @@ ENDPROC(cpu_v7_proc_fin)
*/
.align 5
ENTRY(cpu_v7_reset)
- mov pc, r0
+ mov r4, r0
+ mov ip, #0
+ bl v7_flush_kern_cache_all @ invalidate I,D caches
+ dsb @ drain WB
+#ifdef CONFIG_MMU
+ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
+#endif
+ mrc p15, 0, ip, c1, c0, 0 @ ctrl register
+ bic ip, ip, #0x000f @ ............wcam
+ bic ip, ip, #0x1100 @ ...i...s........
+ mcr p15, 0, ip, c1, c0, 0 @ ctrl register
+ mov pc, r4
ENDPROC(cpu_v7_reset)
/*
diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
index 6c8a02ad98e..85d3e55ca4a 100644
--- a/arch/arm/plat-iop/time.c
+++ b/arch/arm/plat-iop/time.c
@@ -29,6 +29,11 @@
#include <mach/time.h>
/*
+ * Minimum clocksource/clockevent timer range in seconds
+ */
+#define IOP_MIN_RANGE 4
+
+/*
* IOP clocksource (free-running timer 1).
*/
static cycle_t iop_clocksource_read(struct clocksource *unused)
@@ -44,27 +49,6 @@ static struct clocksource iop_clocksource = {
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
-static void __init iop_clocksource_set_hz(struct clocksource *cs, unsigned int hz)
-{
- u64 temp;
- u32 shift;
-
- /* Find shift and mult values for hz. */
- shift = 32;
- do {
- temp = (u64) NSEC_PER_SEC << shift;
- do_div(temp, hz);
- if ((temp >> 32) == 0)
- break;
- } while (--shift != 0);
-
- cs->shift = shift;
- cs->mult = (u32) temp;
-
- printk(KERN_INFO "clocksource: %s uses shift %u mult %#x\n",
- cs->name, cs->shift, cs->mult);
-}
-
/*
* IOP sched_clock() implementation via its clocksource.
*/
@@ -130,27 +114,6 @@ static struct clock_event_device iop_clockevent = {
.set_mode = iop_set_mode,
};
-static void __init iop_clockevent_set_hz(struct clock_event_device *ce, unsigned int hz)
-{
- u64 temp;
- u32 shift;
-
- /* Find shift and mult values for hz. */
- shift = 32;
- do {
- temp = (u64) hz << shift;
- do_div(temp, NSEC_PER_SEC);
- if ((temp >> 32) == 0)
- break;
- } while (--shift != 0);
-
- ce->shift = shift;
- ce->mult = (u32) temp;
-
- printk(KERN_INFO "clockevent: %s uses shift %u mult %#lx\n",
- ce->name, ce->shift, ce->mult);
-}
-
static irqreturn_t
iop_timer_interrupt(int irq, void *dev_id)
{
@@ -190,7 +153,8 @@ void __init iop_init_time(unsigned long tick_rate)
*/
write_tmr0(timer_ctl & ~IOP_TMR_EN);
setup_irq(IRQ_IOP_TIMER0, &iop_timer_irq);
- iop_clockevent_set_hz(&iop_clockevent, tick_rate);
+ clockevents_calc_mult_shift(&iop_clockevent,
+ tick_rate, IOP_MIN_RANGE);
iop_clockevent.max_delta_ns =
clockevent_delta2ns(0xfffffffe, &iop_clockevent);
iop_clockevent.min_delta_ns =
@@ -207,6 +171,7 @@ void __init iop_init_time(unsigned long tick_rate)
write_trr1(0xffffffff);
write_tcr1(0xffffffff);
write_tmr1(timer_ctl);
- iop_clocksource_set_hz(&iop_clocksource, tick_rate);
+ clocksource_calc_mult_shift(&iop_clocksource, tick_rate,
+ IOP_MIN_RANGE);
clocksource_register(&iop_clocksource);
}
diff --git a/arch/arm/plat-nomadik/gpio.c b/arch/arm/plat-nomadik/gpio.c
index 5a6ef252c38..19f16db9d83 100644
--- a/arch/arm/plat-nomadik/gpio.c
+++ b/arch/arm/plat-nomadik/gpio.c
@@ -23,6 +23,7 @@
#include <linux/irq.h>
#include <linux/slab.h>
+#include <plat/pincfg.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
@@ -34,7 +35,6 @@
* Symbols in this file are called "nmk_gpio" for "nomadik gpio"
*/
-#define NMK_GPIO_PER_CHIP 32
struct nmk_gpio_chip {
struct gpio_chip chip;
void __iomem *addr;
@@ -44,30 +44,287 @@ struct nmk_gpio_chip {
/* Keep track of configured edges */
u32 edge_rising;
u32 edge_falling;
+ u32 backup[10];
};
+static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip,
+ unsigned offset, int gpio_mode)
+{
+ u32 bit = 1 << offset;
+ u32 afunc, bfunc;
+
+ afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit;
+ bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit;
+ if (gpio_mode & NMK_GPIO_ALT_A)
+ afunc |= bit;
+ if (gpio_mode & NMK_GPIO_ALT_B)
+ bfunc |= bit;
+ writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA);
+ writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB);
+}
+
+static void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip,
+ unsigned offset, enum nmk_gpio_slpm mode)
+{
+ u32 bit = 1 << offset;
+ u32 slpm;
+
+ slpm = readl(nmk_chip->addr + NMK_GPIO_SLPC);
+ if (mode == NMK_GPIO_SLPM_NOCHANGE)
+ slpm |= bit;
+ else
+ slpm &= ~bit;
+ writel(slpm, nmk_chip->addr + NMK_GPIO_SLPC);
+}
+
+static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip,
+ unsigned offset, enum nmk_gpio_pull pull)
+{
+ u32 bit = 1 << offset;
+ u32 pdis;
+
+ pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS);
+ if (pull == NMK_GPIO_PULL_NONE)
+ pdis |= bit;
+ else
+ pdis &= ~bit;
+ writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS);
+
+ if (pull == NMK_GPIO_PULL_UP)
+ writel(bit, nmk_chip->addr + NMK_GPIO_DATS);
+ else if (pull == NMK_GPIO_PULL_DOWN)
+ writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
+}
+
+static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip,
+ unsigned offset)
+{
+ writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
+}
+
+static void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip,
+ unsigned offset, int val)
+{
+ if (val)
+ writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATS);
+ else
+ writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATC);
+}
+
+static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip,
+ unsigned offset, int val)
+{
+ writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
+ __nmk_gpio_set_output(nmk_chip, offset, val);
+}
+
+static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
+ pin_cfg_t cfg, bool sleep)
+{
+ static const char *afnames[] = {
+ [NMK_GPIO_ALT_GPIO] = "GPIO",
+ [NMK_GPIO_ALT_A] = "A",
+ [NMK_GPIO_ALT_B] = "B",
+ [NMK_GPIO_ALT_C] = "C"
+ };
+ static const char *pullnames[] = {
+ [NMK_GPIO_PULL_NONE] = "none",
+ [NMK_GPIO_PULL_UP] = "up",
+ [NMK_GPIO_PULL_DOWN] = "down",
+ [3] /* illegal */ = "??"
+ };
+ static const char *slpmnames[] = {
+ [NMK_GPIO_SLPM_INPUT] = "input/wakeup",
+ [NMK_GPIO_SLPM_NOCHANGE] = "no-change/no-wakeup",
+ };
+
+ int pin = PIN_NUM(cfg);
+ int pull = PIN_PULL(cfg);
+ int af = PIN_ALT(cfg);
+ int slpm = PIN_SLPM(cfg);
+ int output = PIN_DIR(cfg);
+ int val = PIN_VAL(cfg);
+
+ dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n",
+ pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm],
+ output ? "output " : "input",
+ output ? (val ? "high" : "low") : "");
+
+ if (sleep) {
+ int slpm_pull = PIN_SLPM_PULL(cfg);
+ int slpm_output = PIN_SLPM_DIR(cfg);
+ int slpm_val = PIN_SLPM_VAL(cfg);
+
+ /*
+ * The SLPM_* values are normal values + 1 to allow zero to
+ * mean "same as normal".
+ */
+ if (slpm_pull)
+ pull = slpm_pull - 1;
+ if (slpm_output)
+ output = slpm_output - 1;
+ if (slpm_val)
+ val = slpm_val - 1;
+
+ dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n",
+ pin,
+ slpm_pull ? pullnames[pull] : "same",
+ slpm_output ? (output ? "output" : "input") : "same",
+ slpm_val ? (val ? "high" : "low") : "same");
+ }
+
+ if (output)
+ __nmk_gpio_make_output(nmk_chip, offset, val);
+ else {
+ __nmk_gpio_make_input(nmk_chip, offset);
+ __nmk_gpio_set_pull(nmk_chip, offset, pull);
+ }
+
+ __nmk_gpio_set_slpm(nmk_chip, offset, slpm);
+ __nmk_gpio_set_mode(nmk_chip, offset, af);
+}
+
+/**
+ * nmk_config_pin - configure a pin's mux attributes
+ * @cfg: pin confguration
+ *
+ * Configures a pin's mode (alternate function or GPIO), its pull up status,
+ * and its sleep mode based on the specified configuration. The @cfg is
+ * usually one of the SoC specific macros defined in mach/<soc>-pins.h. These
+ * are constructed using, and can be further enhanced with, the macros in
+ * plat/pincfg.h.
+ *
+ * If a pin's mode is set to GPIO, it is configured as an input to avoid
+ * side-effects. The gpio can be manipulated later using standard GPIO API
+ * calls.
+ */
+int nmk_config_pin(pin_cfg_t cfg, bool sleep)
+{
+ struct nmk_gpio_chip *nmk_chip;
+ int gpio = PIN_NUM(cfg);
+ unsigned long flags;
+
+ nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ if (!nmk_chip)
+ return -EINVAL;
+
+ spin_lock_irqsave(&nmk_chip->lock, flags);
+ __nmk_config_pin(nmk_chip, gpio - nmk_chip->chip.base, cfg, sleep);
+ spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(nmk_config_pin);
+
+/**
+ * nmk_config_pins - configure several pins at once
+ * @cfgs: array of pin configurations
+ * @num: number of elments in the array
+ *
+ * Configures several pins using nmk_config_pin(). Refer to that function for
+ * further information.
+ */
+int nmk_config_pins(pin_cfg_t *cfgs, int num)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ ret = nmk_config_pin(cfgs[i], false);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(nmk_config_pins);
+
+int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ ret = nmk_config_pin(cfgs[i], true);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(nmk_config_pins_sleep);
+
+/**
+ * nmk_gpio_set_slpm() - configure the sleep mode of a pin
+ * @gpio: pin number
+ * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE,
+ *
+ * Sets the sleep mode of a pin. If @mode is NMK_GPIO_SLPM_INPUT, the pin is
+ * changed to an input (with pullup/down enabled) in sleep and deep sleep. If
+ * @mode is NMK_GPIO_SLPM_NOCHANGE, the pin remains in the state it was
+ * configured even when in sleep and deep sleep.
+ *
+ * On DB8500v2 onwards, this setting loses the previous meaning and instead
+ * indicates if wakeup detection is enabled on the pin. Note that
+ * enable_irq_wake() will automatically enable wakeup detection.
+ */
+int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
+{
+ struct nmk_gpio_chip *nmk_chip;
+ unsigned long flags;
+
+ nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ if (!nmk_chip)
+ return -EINVAL;
+
+ spin_lock_irqsave(&nmk_chip->lock, flags);
+ __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, mode);
+ spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+ return 0;
+}
+
+/**
+ * nmk_gpio_set_pull() - enable/disable pull up/down on a gpio
+ * @gpio: pin number
+ * @pull: one of NMK_GPIO_PULL_DOWN, NMK_GPIO_PULL_UP, and NMK_GPIO_PULL_NONE
+ *
+ * Enables/disables pull up/down on a specified pin. This only takes effect if
+ * the pin is configured as an input (either explicitly or by the alternate
+ * function).
+ *
+ * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
+ * configured as an input. Otherwise, due to the way the controller registers
+ * work, this function will change the value output on the pin.
+ */
+int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
+{
+ struct nmk_gpio_chip *nmk_chip;
+ unsigned long flags;
+
+ nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ if (!nmk_chip)
+ return -EINVAL;
+
+ spin_lock_irqsave(&nmk_chip->lock, flags);
+ __nmk_gpio_set_pull(nmk_chip, gpio - nmk_chip->chip.base, pull);
+ spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+ return 0;
+}
+
/* Mode functions */
int nmk_gpio_set_mode(int gpio, int gpio_mode)
{
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
- u32 afunc, bfunc, bit;
nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
if (!nmk_chip)
return -EINVAL;
- bit = 1 << (gpio - nmk_chip->chip.base);
-
spin_lock_irqsave(&nmk_chip->lock, flags);
- afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit;
- bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit;
- if (gpio_mode & NMK_GPIO_ALT_A)
- afunc |= bit;
- if (gpio_mode & NMK_GPIO_ALT_B)
- bfunc |= bit;
- writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA);
- writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB);
+ __nmk_gpio_set_mode(nmk_chip, gpio - nmk_chip->chip.base, gpio_mode);
spin_unlock_irqrestore(&nmk_chip->lock, flags);
return 0;
@@ -99,6 +356,38 @@ static inline int nmk_gpio_get_bitmask(int gpio)
return 1 << (gpio % 32);
}
+static unsigned int nmk_gpio_irq_startup(unsigned int irq)
+{
+ int gpio = NOMADIK_IRQ_TO_GPIO(irq);
+ int status = 0;
+
+ status = gpio_request(gpio, "IRQ");
+ if (status < 0) {
+ printk(KERN_ERR "GPIO-request failed\n");
+ return status;
+ }
+
+ gpio_direction_input(gpio);
+ nmk_gpio_set_mode(gpio, NMK_GPIO_ALT_GPIO);
+
+ /* go on as default_startup() */
+ get_irq_chip(irq)->enable(irq);
+
+ return 0;
+}
+
+static void nmk_gpio_irq_shutdown(unsigned int irq)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+ int gpio = NOMADIK_IRQ_TO_GPIO(irq);
+
+ /* default_shutdown() */
+ desc->chip->mask(irq);
+ desc->status |= IRQ_MASKED;
+
+ gpio_free(gpio);
+}
+
static void nmk_gpio_irq_ack(unsigned int irq)
{
int gpio;
@@ -111,32 +400,41 @@ static void nmk_gpio_irq_ack(unsigned int irq)
writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC);
}
+enum nmk_gpio_irq_type {
+ NORMAL,
+ WAKE,
+};
+
static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip,
- int gpio, bool enable)
+ int gpio, enum nmk_gpio_irq_type which,
+ bool enable)
{
+ u32 rimsc = which == WAKE ? NMK_GPIO_RWIMSC : NMK_GPIO_RIMSC;
+ u32 fimsc = which == WAKE ? NMK_GPIO_FWIMSC : NMK_GPIO_FIMSC;
u32 bitmask = nmk_gpio_get_bitmask(gpio);
u32 reg;
/* we must individually set/clear the two edges */
if (nmk_chip->edge_rising & bitmask) {
- reg = readl(nmk_chip->addr + NMK_GPIO_RIMSC);
+ reg = readl(nmk_chip->addr + rimsc);
if (enable)
reg |= bitmask;
else
reg &= ~bitmask;
- writel(reg, nmk_chip->addr + NMK_GPIO_RIMSC);
+ writel(reg, nmk_chip->addr + rimsc);
}
if (nmk_chip->edge_falling & bitmask) {
- reg = readl(nmk_chip->addr + NMK_GPIO_FIMSC);
+ reg = readl(nmk_chip->addr + fimsc);
if (enable)
reg |= bitmask;
else
reg &= ~bitmask;
- writel(reg, nmk_chip->addr + NMK_GPIO_FIMSC);
+ writel(reg, nmk_chip->addr + fimsc);
}
}
-static void nmk_gpio_irq_modify(unsigned int irq, bool enable)
+static int nmk_gpio_irq_modify(unsigned int irq, enum nmk_gpio_irq_type which,
+ bool enable)
{
int gpio;
struct nmk_gpio_chip *nmk_chip;
@@ -147,26 +445,55 @@ static void nmk_gpio_irq_modify(unsigned int irq, bool enable)
nmk_chip = get_irq_chip_data(irq);
bitmask = nmk_gpio_get_bitmask(gpio);
if (!nmk_chip)
- return;
+ return -EINVAL;
spin_lock_irqsave(&nmk_chip->lock, flags);
- __nmk_gpio_irq_modify(nmk_chip, gpio, enable);
+ __nmk_gpio_irq_modify(nmk_chip, gpio, which, enable);
spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+ return 0;
}
static void nmk_gpio_irq_mask(unsigned int irq)
{
- nmk_gpio_irq_modify(irq, false);
-};
+ nmk_gpio_irq_modify(irq, NORMAL, false);
+}
static void nmk_gpio_irq_unmask(unsigned int irq)
{
- nmk_gpio_irq_modify(irq, true);
+ nmk_gpio_irq_modify(irq, NORMAL, true);
+}
+
+static int nmk_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+ struct nmk_gpio_chip *nmk_chip;
+ unsigned long flags;
+ int gpio;
+
+ gpio = NOMADIK_IRQ_TO_GPIO(irq);
+ nmk_chip = get_irq_chip_data(irq);
+ if (!nmk_chip)
+ return -EINVAL;
+
+ spin_lock_irqsave(&nmk_chip->lock, flags);
+#ifdef CONFIG_ARCH_U8500
+ if (cpu_is_u8500v2()) {
+ __nmk_gpio_set_slpm(nmk_chip, gpio,
+ on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
+ : NMK_GPIO_SLPM_WAKEUP_DISABLE);
+ }
+#endif
+ __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
+ spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+ return 0;
}
static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
{
- bool enabled = !(irq_to_desc(irq)->status & IRQ_DISABLED);
+ struct irq_desc *desc = irq_to_desc(irq);
+ bool enabled = !(desc->status & IRQ_DISABLED);
+ bool wake = desc->wake_depth;
int gpio;
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
@@ -186,7 +513,10 @@ static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
spin_lock_irqsave(&nmk_chip->lock, flags);
if (enabled)
- __nmk_gpio_irq_modify(nmk_chip, gpio, false);
+ __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, false);
+
+ if (wake)
+ __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, false);
nmk_chip->edge_rising &= ~bitmask;
if (type & IRQ_TYPE_EDGE_RISING)
@@ -197,7 +527,10 @@ static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
nmk_chip->edge_falling |= bitmask;
if (enabled)
- __nmk_gpio_irq_modify(nmk_chip, gpio, true);
+ __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, true);
+
+ if (wake)
+ __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true);
spin_unlock_irqrestore(&nmk_chip->lock, flags);
@@ -206,10 +539,13 @@ static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
static struct irq_chip nmk_gpio_irq_chip = {
.name = "Nomadik-GPIO",
+ .startup = nmk_gpio_irq_startup,
+ .shutdown = nmk_gpio_irq_shutdown,
.ack = nmk_gpio_irq_ack,
.mask = nmk_gpio_irq_mask,
.unmask = nmk_gpio_irq_unmask,
.set_type = nmk_gpio_irq_set_type,
+ .set_wake = nmk_gpio_irq_set_wake,
};
static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
@@ -244,7 +580,7 @@ static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
int i;
first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
- for (i = first_irq; i < first_irq + NMK_GPIO_PER_CHIP; i++) {
+ for (i = first_irq; i < first_irq + nmk_chip->chip.ngpio; i++) {
set_irq_chip(i, &nmk_gpio_irq_chip);
set_irq_handler(i, handle_edge_irq);
set_irq_flags(i, IRQF_VALID);
@@ -266,49 +602,146 @@ static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
return 0;
}
+static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct nmk_gpio_chip *nmk_chip =
+ container_of(chip, struct nmk_gpio_chip, chip);
+ u32 bit = 1 << offset;
+
+ return (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0;
+}
+
+static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
+ int val)
+{
+ struct nmk_gpio_chip *nmk_chip =
+ container_of(chip, struct nmk_gpio_chip, chip);
+
+ __nmk_gpio_set_output(nmk_chip, offset, val);
+}
+
static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
int val)
{
struct nmk_gpio_chip *nmk_chip =
container_of(chip, struct nmk_gpio_chip, chip);
- writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
+ __nmk_gpio_make_output(nmk_chip, offset, val);
+
return 0;
}
-static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
+static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct nmk_gpio_chip *nmk_chip =
container_of(chip, struct nmk_gpio_chip, chip);
- u32 bit = 1 << offset;
- return (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0;
+ return NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base) + offset;
}
-static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
- int val)
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/seq_file.h>
+
+static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
+ int mode;
+ unsigned i;
+ unsigned gpio = chip->base;
+ int is_out;
struct nmk_gpio_chip *nmk_chip =
container_of(chip, struct nmk_gpio_chip, chip);
- u32 bit = 1 << offset;
-
- if (val)
- writel(bit, nmk_chip->addr + NMK_GPIO_DATS);
- else
- writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
+ const char *modes[] = {
+ [NMK_GPIO_ALT_GPIO] = "gpio",
+ [NMK_GPIO_ALT_A] = "altA",
+ [NMK_GPIO_ALT_B] = "altB",
+ [NMK_GPIO_ALT_C] = "altC",
+ };
+
+ for (i = 0; i < chip->ngpio; i++, gpio++) {
+ const char *label = gpiochip_is_requested(chip, i);
+ bool pull;
+ u32 bit = 1 << i;
+
+ if (!label)
+ continue;
+
+ is_out = readl(nmk_chip->addr + NMK_GPIO_DIR) & bit;
+ pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
+ mode = nmk_gpio_get_mode(gpio);
+ seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
+ gpio, label,
+ is_out ? "out" : "in ",
+ chip->get
+ ? (chip->get(chip, i) ? "hi" : "lo")
+ : "? ",
+ (mode < 0) ? "unknown" : modes[mode],
+ pull ? "pull" : "none");
+
+ if (!is_out) {
+ int irq = gpio_to_irq(gpio);
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ /* This races with request_irq(), set_irq_type(),
+ * and set_irq_wake() ... but those are "rare".
+ *
+ * More significantly, trigger type flags aren't
+ * currently maintained by genirq.
+ */
+ if (irq >= 0 && desc->action) {
+ char *trigger;
+
+ switch (desc->status & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_NONE:
+ trigger = "(default)";
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ trigger = "edge-falling";
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ trigger = "edge-rising";
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ trigger = "edge-both";
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ trigger = "level-high";
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ trigger = "level-low";
+ break;
+ default:
+ trigger = "?trigger?";
+ break;
+ }
+
+ seq_printf(s, " irq-%d %s%s",
+ irq, trigger,
+ (desc->status & IRQ_WAKEUP)
+ ? " wakeup" : "");
+ }
+ }
+
+ seq_printf(s, "\n");
+ }
}
+#else
+#define nmk_gpio_dbg_show NULL
+#endif
+
/* This structure is replicated for each GPIO block allocated at probe time */
static struct gpio_chip nmk_gpio_template = {
.direction_input = nmk_gpio_make_input,
.get = nmk_gpio_get_input,
.direction_output = nmk_gpio_make_output,
.set = nmk_gpio_set_output,
- .ngpio = NMK_GPIO_PER_CHIP,
+ .to_irq = nmk_gpio_to_irq,
+ .dbg_show = nmk_gpio_dbg_show,
.can_sleep = 0,
};
-static int __init nmk_gpio_probe(struct platform_device *dev)
+static int __devinit nmk_gpio_probe(struct platform_device *dev)
{
struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
struct nmk_gpio_chip *nmk_chip;
@@ -364,6 +797,7 @@ static int __init nmk_gpio_probe(struct platform_device *dev)
chip = &nmk_chip->chip;
chip->base = pdata->first_gpio;
+ chip->ngpio = pdata->num_gpio;
chip->label = pdata->name;
chip->dev = &dev->dev;
chip->owner = THIS_MODULE;
@@ -393,22 +827,51 @@ out:
return ret;
}
-static int __exit nmk_gpio_remove(struct platform_device *dev)
+#ifdef CONFIG_PM
+static int nmk_gpio_pm(struct platform_device *dev, bool suspend)
{
- struct nmk_gpio_chip *nmk_chip;
- struct resource *res;
-
- res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ struct nmk_gpio_chip *nmk_chip = platform_get_drvdata(dev);
+ int i;
+ static const unsigned int regs[] = {
+ NMK_GPIO_DAT,
+ NMK_GPIO_PDIS,
+ NMK_GPIO_DIR,
+ NMK_GPIO_AFSLA,
+ NMK_GPIO_AFSLB,
+ NMK_GPIO_SLPC,
+ NMK_GPIO_RIMSC,
+ NMK_GPIO_FIMSC,
+ NMK_GPIO_RWIMSC,
+ NMK_GPIO_FWIMSC,
+ };
+
+ BUILD_BUG_ON(ARRAY_SIZE(nmk_chip->backup) != ARRAY_SIZE(regs));
+
+ /* XXX: is this sufficient? what about pull-up/down configuration? */
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ if (suspend)
+ nmk_chip->backup[i] = readl(nmk_chip->addr + regs[i]);
+ else
+ writel(nmk_chip->backup[i], nmk_chip->addr + regs[i]);
+ }
- nmk_chip = platform_get_drvdata(dev);
- gpiochip_remove(&nmk_chip->chip);
- clk_disable(nmk_chip->clk);
- clk_put(nmk_chip->clk);
- kfree(nmk_chip);
- release_mem_region(res->start, resource_size(res));
return 0;
}
+static int nmk_gpio_suspend(struct platform_device *dev, pm_message_t state)
+{
+ return nmk_gpio_pm(dev, true);
+}
+
+static int nmk_gpio_resume(struct platform_device *dev)
+{
+ return nmk_gpio_pm(dev, false);
+}
+#else
+#define nmk_gpio_suspend NULL
+#define nmk_gpio_resume NULL
+#endif
static struct platform_driver nmk_gpio_driver = {
.driver = {
@@ -416,9 +879,8 @@ static struct platform_driver nmk_gpio_driver = {
.name = "gpio",
},
.probe = nmk_gpio_probe,
- .remove = __exit_p(nmk_gpio_remove),
- .suspend = NULL, /* to be done */
- .resume = NULL,
+ .suspend = nmk_gpio_suspend,
+ .resume = nmk_gpio_resume,
};
static int __init nmk_gpio_init(void)
@@ -426,7 +888,7 @@ static int __init nmk_gpio_init(void)
return platform_driver_register(&nmk_gpio_driver);
}
-arch_initcall(nmk_gpio_init);
+core_initcall(nmk_gpio_init);
MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini");
MODULE_DESCRIPTION("Nomadik GPIO Driver");
diff --git a/arch/arm/plat-nomadik/include/plat/gpio.h b/arch/arm/plat-nomadik/include/plat/gpio.h
index 4200811249c..d745f3ac0a6 100644
--- a/arch/arm/plat-nomadik/include/plat/gpio.h
+++ b/arch/arm/plat-nomadik/include/plat/gpio.h
@@ -55,6 +55,23 @@
#define NMK_GPIO_ALT_B 2
#define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B)
+/* Pull up/down values */
+enum nmk_gpio_pull {
+ NMK_GPIO_PULL_NONE,
+ NMK_GPIO_PULL_UP,
+ NMK_GPIO_PULL_DOWN,
+};
+
+/* Sleep mode */
+enum nmk_gpio_slpm {
+ NMK_GPIO_SLPM_INPUT,
+ NMK_GPIO_SLPM_WAKEUP_ENABLE = NMK_GPIO_SLPM_INPUT,
+ NMK_GPIO_SLPM_NOCHANGE,
+ NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE,
+};
+
+extern int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode);
+extern int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull);
extern int nmk_gpio_set_mode(int gpio, int gpio_mode);
extern int nmk_gpio_get_mode(int gpio);
@@ -65,6 +82,7 @@ struct nmk_gpio_platform_data {
char *name;
int first_gpio;
int first_irq;
+ int num_gpio;
};
#endif /* __ASM_PLAT_GPIO_H */
diff --git a/arch/arm/plat-nomadik/include/plat/mtu.h b/arch/arm/plat-nomadik/include/plat/mtu.h
index 42c907258b1..65704a3d424 100644
--- a/arch/arm/plat-nomadik/include/plat/mtu.h
+++ b/arch/arm/plat-nomadik/include/plat/mtu.h
@@ -1,6 +1,12 @@
#ifndef __PLAT_MTU_H
#define __PLAT_MTU_H
+/*
+ * Guaranteed runtime conversion range in seconds for
+ * the clocksource and clockevent.
+ */
+#define MTU_MIN_RANGE 4
+
/* should be set by the platform code */
extern void __iomem *mtu_base;
diff --git a/arch/arm/plat-nomadik/include/plat/pincfg.h b/arch/arm/plat-nomadik/include/plat/pincfg.h
new file mode 100644
index 00000000000..05a3936ae6d
--- /dev/null
+++ b/arch/arm/plat-nomadik/include/plat/pincfg.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ *
+ * Based on arch/arm/mach-pxa/include/mach/mfp.h:
+ * Copyright (C) 2007 Marvell International Ltd.
+ * eric miao <eric.miao@marvell.com>
+ */
+
+#ifndef __PLAT_PINCFG_H
+#define __PLAT_PINCFG_H
+
+/*
+ * pin configurations are represented by 32-bit integers:
+ *
+ * bit 0.. 8 - Pin Number (512 Pins Maximum)
+ * bit 9..10 - Alternate Function Selection
+ * bit 11..12 - Pull up/down state
+ * bit 13 - Sleep mode behaviour
+ * bit 14 - Direction
+ * bit 15 - Value (if output)
+ * bit 16..18 - SLPM pull up/down state
+ * bit 19..20 - SLPM direction
+ * bit 21..22 - SLPM Value (if output)
+ *
+ * to facilitate the definition, the following macros are provided
+ *
+ * PIN_CFG_DEFAULT - default config (0):
+ * pull up/down = disabled
+ * sleep mode = input/wakeup
+ * direction = input
+ * value = low
+ * SLPM direction = same as normal
+ * SLPM pull = same as normal
+ * SLPM value = same as normal
+ *
+ * PIN_CFG - default config with alternate function
+ * PIN_CFG_PULL - default config with alternate function and pull up/down
+ */
+
+typedef unsigned long pin_cfg_t;
+
+#define PIN_NUM_MASK 0x1ff
+#define PIN_NUM(x) ((x) & PIN_NUM_MASK)
+
+#define PIN_ALT_SHIFT 9
+#define PIN_ALT_MASK (0x3 << PIN_ALT_SHIFT)
+#define PIN_ALT(x) (((x) & PIN_ALT_MASK) >> PIN_ALT_SHIFT)
+#define PIN_GPIO (NMK_GPIO_ALT_GPIO << PIN_ALT_SHIFT)
+#define PIN_ALT_A (NMK_GPIO_ALT_A << PIN_ALT_SHIFT)
+#define PIN_ALT_B (NMK_GPIO_ALT_B << PIN_ALT_SHIFT)
+#define PIN_ALT_C (NMK_GPIO_ALT_C << PIN_ALT_SHIFT)
+
+#define PIN_PULL_SHIFT 11
+#define PIN_PULL_MASK (0x3 << PIN_PULL_SHIFT)
+#define PIN_PULL(x) (((x) & PIN_PULL_MASK) >> PIN_PULL_SHIFT)
+#define PIN_PULL_NONE (NMK_GPIO_PULL_NONE << PIN_PULL_SHIFT)
+#define PIN_PULL_UP (NMK_GPIO_PULL_UP << PIN_PULL_SHIFT)
+#define PIN_PULL_DOWN (NMK_GPIO_PULL_DOWN << PIN_PULL_SHIFT)
+
+#define PIN_SLPM_SHIFT 13
+#define PIN_SLPM_MASK (0x1 << PIN_SLPM_SHIFT)
+#define PIN_SLPM(x) (((x) & PIN_SLPM_MASK) >> PIN_SLPM_SHIFT)
+#define PIN_SLPM_MAKE_INPUT (NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT)
+#define PIN_SLPM_NOCHANGE (NMK_GPIO_SLPM_NOCHANGE << PIN_SLPM_SHIFT)
+/* These two replace the above in DB8500v2+ */
+#define PIN_SLPM_WAKEUP_ENABLE (NMK_GPIO_SLPM_WAKEUP_ENABLE << PIN_SLPM_SHIFT)
+#define PIN_SLPM_WAKEUP_DISABLE (NMK_GPIO_SLPM_WAKEUP_DISABLE << PIN_SLPM_SHIFT)
+
+#define PIN_DIR_SHIFT 14
+#define PIN_DIR_MASK (0x1 << PIN_DIR_SHIFT)
+#define PIN_DIR(x) (((x) & PIN_DIR_MASK) >> PIN_DIR_SHIFT)
+#define PIN_DIR_INPUT (0 << PIN_DIR_SHIFT)
+#define PIN_DIR_OUTPUT (1 << PIN_DIR_SHIFT)
+
+#define PIN_VAL_SHIFT 15
+#define PIN_VAL_MASK (0x1 << PIN_VAL_SHIFT)
+#define PIN_VAL(x) (((x) & PIN_VAL_MASK) >> PIN_VAL_SHIFT)
+#define PIN_VAL_LOW (0 << PIN_VAL_SHIFT)
+#define PIN_VAL_HIGH (1 << PIN_VAL_SHIFT)
+
+#define PIN_SLPM_PULL_SHIFT 16
+#define PIN_SLPM_PULL_MASK (0x7 << PIN_SLPM_PULL_SHIFT)
+#define PIN_SLPM_PULL(x) \
+ (((x) & PIN_SLPM_PULL_MASK) >> PIN_SLPM_PULL_SHIFT)
+#define PIN_SLPM_PULL_NONE \
+ ((1 + NMK_GPIO_PULL_NONE) << PIN_SLPM_PULL_SHIFT)
+#define PIN_SLPM_PULL_UP \
+ ((1 + NMK_GPIO_PULL_UP) << PIN_SLPM_PULL_SHIFT)
+#define PIN_SLPM_PULL_DOWN \
+ ((1 + NMK_GPIO_PULL_DOWN) << PIN_SLPM_PULL_SHIFT)
+
+#define PIN_SLPM_DIR_SHIFT 19
+#define PIN_SLPM_DIR_MASK (0x3 << PIN_SLPM_DIR_SHIFT)
+#define PIN_SLPM_DIR(x) \
+ (((x) & PIN_SLPM_DIR_MASK) >> PIN_SLPM_DIR_SHIFT)
+#define PIN_SLPM_DIR_INPUT ((1 + 0) << PIN_SLPM_DIR_SHIFT)
+#define PIN_SLPM_DIR_OUTPUT ((1 + 1) << PIN_SLPM_DIR_SHIFT)
+
+#define PIN_SLPM_VAL_SHIFT 21
+#define PIN_SLPM_VAL_MASK (0x3 << PIN_SLPM_VAL_SHIFT)
+#define PIN_SLPM_VAL(x) \
+ (((x) & PIN_SLPM_VAL_MASK) >> PIN_SLPM_VAL_SHIFT)
+#define PIN_SLPM_VAL_LOW ((1 + 0) << PIN_SLPM_VAL_SHIFT)
+#define PIN_SLPM_VAL_HIGH ((1 + 1) << PIN_SLPM_VAL_SHIFT)
+
+/* Shortcuts. Use these instead of separate DIR, PULL, and VAL. */
+#define PIN_INPUT_PULLDOWN (PIN_DIR_INPUT | PIN_PULL_DOWN)
+#define PIN_INPUT_PULLUP (PIN_DIR_INPUT | PIN_PULL_UP)
+#define PIN_INPUT_NOPULL (PIN_DIR_INPUT | PIN_PULL_NONE)
+#define PIN_OUTPUT_LOW (PIN_DIR_OUTPUT | PIN_VAL_LOW)
+#define PIN_OUTPUT_HIGH (PIN_DIR_OUTPUT | PIN_VAL_HIGH)
+
+#define PIN_SLPM_INPUT_PULLDOWN (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_DOWN)
+#define PIN_SLPM_INPUT_PULLUP (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_UP)
+#define PIN_SLPM_INPUT_NOPULL (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_NONE)
+#define PIN_SLPM_OUTPUT_LOW (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_LOW)
+#define PIN_SLPM_OUTPUT_HIGH (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_HIGH)
+
+#define PIN_CFG_DEFAULT (0)
+
+#define PIN_CFG(num, alt) \
+ (PIN_CFG_DEFAULT |\
+ (PIN_NUM(num) | PIN_##alt))
+
+#define PIN_CFG_INPUT(num, alt, pull) \
+ (PIN_CFG_DEFAULT |\
+ (PIN_NUM(num) | PIN_##alt | PIN_INPUT_##pull))
+
+#define PIN_CFG_OUTPUT(num, alt, val) \
+ (PIN_CFG_DEFAULT |\
+ (PIN_NUM(num) | PIN_##alt | PIN_OUTPUT_##val))
+
+#define PIN_CFG_PULL(num, alt, pull) \
+ ((PIN_CFG_DEFAULT & ~PIN_PULL_MASK) |\
+ (PIN_NUM(num) | PIN_##alt | PIN_PULL_##pull))
+
+extern int nmk_config_pin(pin_cfg_t cfg, bool sleep);
+extern int nmk_config_pins(pin_cfg_t *cfgs, int num);
+extern int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num);
+
+#endif
diff --git a/arch/arm/plat-nomadik/include/plat/ske.h b/arch/arm/plat-nomadik/include/plat/ske.h
new file mode 100644
index 00000000000..31382fbc07d
--- /dev/null
+++ b/arch/arm/plat-nomadik/include/plat/ske.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
+ *
+ * ux500 Scroll key and Keypad Encoder (SKE) header
+ */
+
+#ifndef __SKE_H
+#define __SKE_H
+
+#include <linux/input/matrix_keypad.h>
+
+/* register definitions for SKE peripheral */
+#define SKE_CR 0x00
+#define SKE_VAL0 0x04
+#define SKE_VAL1 0x08
+#define SKE_DBCR 0x0C
+#define SKE_IMSC 0x10
+#define SKE_RIS 0x14
+#define SKE_MIS 0x18
+#define SKE_ICR 0x1C
+
+/*
+ * Keypad module
+ */
+
+/**
+ * struct keypad_platform_data - structure for platform specific data
+ * @init: pointer to keypad init function
+ * @exit: pointer to keypad deinitialisation function
+ * @keymap_data: matrix scan code table for keycodes
+ * @krow: maximum number of rows
+ * @kcol: maximum number of columns
+ * @debounce_ms: platform specific debounce time
+ * @no_autorepeat: flag for auto repetition
+ * @wakeup_enable: allow waking up the system
+ */
+struct ske_keypad_platform_data {
+ int (*init)(void);
+ int (*exit)(void);
+ const struct matrix_keymap_data *keymap_data;
+ u8 krow;
+ u8 kcol;
+ u8 debounce_ms;
+ bool no_autorepeat;
+ bool wakeup_enable;
+};
+#endif /*__SKE_KPD_H*/
diff --git a/arch/arm/plat-nomadik/include/plat/ste_dma40.h b/arch/arm/plat-nomadik/include/plat/ste_dma40.h
index 4d12ea4ca36..4e9ba8a1d11 100644
--- a/arch/arm/plat-nomadik/include/plat/ste_dma40.h
+++ b/arch/arm/plat-nomadik/include/plat/ste_dma40.h
@@ -1,10 +1,8 @@
/*
- * arch/arm/plat-nomadik/include/plat/ste_dma40.h
- *
- * Copyright (C) ST-Ericsson 2007-2010
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
@@ -15,42 +13,26 @@
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/dmaengine.h>
+#include <linux/version.h>
/* dev types for memcpy */
#define STEDMA40_DEV_DST_MEMORY (-1)
#define STEDMA40_DEV_SRC_MEMORY (-1)
-/*
- * Description of bitfields of channel_type variable is available in
- * the info structure.
- */
-
-/* Priority */
-#define STEDMA40_INFO_PRIO_TYPE_POS 2
-#define STEDMA40_HIGH_PRIORITY_CHANNEL (0x1 << STEDMA40_INFO_PRIO_TYPE_POS)
-#define STEDMA40_LOW_PRIORITY_CHANNEL (0x2 << STEDMA40_INFO_PRIO_TYPE_POS)
-
-/* Mode */
-#define STEDMA40_INFO_CH_MODE_TYPE_POS 6
-#define STEDMA40_CHANNEL_IN_PHY_MODE (0x1 << STEDMA40_INFO_CH_MODE_TYPE_POS)
-#define STEDMA40_CHANNEL_IN_LOG_MODE (0x2 << STEDMA40_INFO_CH_MODE_TYPE_POS)
-#define STEDMA40_CHANNEL_IN_OPER_MODE (0x3 << STEDMA40_INFO_CH_MODE_TYPE_POS)
-
-/* Mode options */
-#define STEDMA40_INFO_CH_MODE_OPT_POS 8
-#define STEDMA40_PCHAN_BASIC_MODE (0x1 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_PCHAN_MODULO_MODE (0x2 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_PCHAN_DOUBLE_DST_MODE (0x3 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_LCHAN_SRC_PHY_DST_LOG (0x1 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_LCHAN_SRC_LOG_DST_PHS (0x2 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_LCHAN_SRC_LOG_DST_LOG (0x3 << STEDMA40_INFO_CH_MODE_OPT_POS)
-
-/* Interrupt */
-#define STEDMA40_INFO_TIM_POS 10
-#define STEDMA40_NO_TIM_FOR_LINK (0x0 << STEDMA40_INFO_TIM_POS)
-#define STEDMA40_TIM_FOR_LINK (0x1 << STEDMA40_INFO_TIM_POS)
+enum stedma40_mode {
+ STEDMA40_MODE_LOGICAL = 0,
+ STEDMA40_MODE_PHYSICAL,
+ STEDMA40_MODE_OPERATION,
+};
-/* End of channel_type configuration */
+enum stedma40_mode_opt {
+ STEDMA40_PCHAN_BASIC_MODE = 0,
+ STEDMA40_LCHAN_SRC_LOG_DST_LOG = 0,
+ STEDMA40_PCHAN_MODULO_MODE,
+ STEDMA40_PCHAN_DOUBLE_DST_MODE,
+ STEDMA40_LCHAN_SRC_PHY_DST_LOG,
+ STEDMA40_LCHAN_SRC_LOG_DST_PHY,
+};
#define STEDMA40_ESIZE_8_BIT 0x0
#define STEDMA40_ESIZE_16_BIT 0x1
@@ -73,43 +55,53 @@
#define STEDMA40_PSIZE_LOG_8 STEDMA40_PSIZE_PHY_8
#define STEDMA40_PSIZE_LOG_16 STEDMA40_PSIZE_PHY_16
+/* Maximum number of possible physical channels */
+#define STEDMA40_MAX_PHYS 32
+
enum stedma40_flow_ctrl {
STEDMA40_NO_FLOW_CTRL,
STEDMA40_FLOW_CTRL,
};
-enum stedma40_endianess {
- STEDMA40_LITTLE_ENDIAN,
- STEDMA40_BIG_ENDIAN
-};
-
enum stedma40_periph_data_width {
- STEDMA40_BYTE_WIDTH = STEDMA40_ESIZE_8_BIT,
- STEDMA40_HALFWORD_WIDTH = STEDMA40_ESIZE_16_BIT,
- STEDMA40_WORD_WIDTH = STEDMA40_ESIZE_32_BIT,
+ STEDMA40_BYTE_WIDTH = STEDMA40_ESIZE_8_BIT,
+ STEDMA40_HALFWORD_WIDTH = STEDMA40_ESIZE_16_BIT,
+ STEDMA40_WORD_WIDTH = STEDMA40_ESIZE_32_BIT,
STEDMA40_DOUBLEWORD_WIDTH = STEDMA40_ESIZE_64_BIT
};
-struct stedma40_half_channel_info {
- enum stedma40_endianess endianess;
- enum stedma40_periph_data_width data_width;
- int psize;
- enum stedma40_flow_ctrl flow_ctrl;
-};
-
enum stedma40_xfer_dir {
- STEDMA40_MEM_TO_MEM,
+ STEDMA40_MEM_TO_MEM = 1,
STEDMA40_MEM_TO_PERIPH,
STEDMA40_PERIPH_TO_MEM,
STEDMA40_PERIPH_TO_PERIPH
};
+/**
+ * struct stedma40_chan_cfg - dst/src channel configurration
+ *
+ * @big_endian: true if src/dst should be read as big_endian
+ * @data_width: Data width of the src/dst hardware
+ * @psize: Burst size
+ * @flow_ctrl: Flow control on/off.
+ */
+struct stedma40_half_channel_info {
+ bool big_endian;
+ enum stedma40_periph_data_width data_width;
+ int psize;
+ enum stedma40_flow_ctrl flow_ctrl;
+};
+
/**
* struct stedma40_chan_cfg - Structure to be filled by client drivers.
*
* @dir: MEM 2 MEM, PERIPH 2 MEM , MEM 2 PERIPH, PERIPH 2 PERIPH
- * @channel_type: priority, mode, mode options and interrupt configuration.
+ * @high_priority: true if high-priority
+ * @realtime: true if realtime mode is to be enabled. Only available on DMA40
+ * version 3+, i.e DB8500v2+
+ * @mode: channel mode: physical, logical, or operation
+ * @mode_opt: options for the chosen channel mode
* @src_dev_type: Src device type
* @dst_dev_type: Dst device type
* @src_info: Parameters for dst half channel
@@ -126,7 +118,12 @@ enum stedma40_xfer_dir {
*/
struct stedma40_chan_cfg {
enum stedma40_xfer_dir dir;
- unsigned int channel_type;
+
+ bool high_priority;
+ bool realtime;
+ enum stedma40_mode mode;
+ enum stedma40_mode_opt mode_opt;
+
int src_dev_type;
int dst_dev_type;
struct stedma40_half_channel_info src_info;
@@ -147,8 +144,8 @@ struct stedma40_chan_cfg {
* @memcpy_len: length of memcpy
* @memcpy_conf_phy: default configuration of physical channel memcpy
* @memcpy_conf_log: default configuration of logical channel memcpy
- * @llis_per_log: number of max linked list items per logical channel
- *
+ * @disabled_channels: A vector, ending with -1, that marks physical channels
+ * that are for different reasons not available for the driver.
*/
struct stedma40_platform_data {
u32 dev_len;
@@ -158,16 +155,40 @@ struct stedma40_platform_data {
u32 memcpy_len;
struct stedma40_chan_cfg *memcpy_conf_phy;
struct stedma40_chan_cfg *memcpy_conf_log;
- unsigned int llis_per_log;
+ int disabled_channels[STEDMA40_MAX_PHYS];
+};
+
+struct d40_desc;
+
+/**
+ * struct stedma40_cyclic_desc - Cyclic DMA descriptor
+ * @d40d: DMA driver internal descriptor
+ * @period_callback: callback to be called after every link/period if
+ * the DMA_PREP_INTERRUPT flag is used when preparing
+ * the transaction
+ * @period_callback_param: handle passed to the period_callback
+ *
+ * A pointer to a structure of this type is returned from the
+ * stedma40_cyclic_prep_sg() function. The period_callback and
+ * period_callback_param members can be set by the client.
+ */
+struct stedma40_cyclic_desc {
+ struct d40_desc *d40d;
+ dma_async_tx_callback period_callback;
+ void *period_callback_param;
};
+int stedma40_set_dev_addr(struct dma_chan *chan,
+ dma_addr_t src_dev_addr,
+ dma_addr_t dst_dev_addr);
+
/**
* setdma40_set_psize() - Used for changing the package size of an
* already configured dma channel.
*
* @chan: dmaengine handle
- * @src_psize: new package side for src. (STEDMA40_PSIZE*)
- * @src_psize: new package side for dst. (STEDMA40_PSIZE*)
+ * @src_psize: new package size for src. (STEDMA40_PSIZE*)
+ * @dst_psize: new package size for dst. (STEDMA40_PSIZE*)
*
* returns 0 on ok, otherwise negative error number.
*/
@@ -175,6 +196,79 @@ int stedma40_set_psize(struct dma_chan *chan,
int src_psize,
int dst_psize);
+/*
+ * stedma40_get_src_addr - get current source address
+ * @chan: the DMA channel
+ *
+ * Returns the physical address of the current source element to be read by the
+ * DMA.
+ */
+dma_addr_t stedma40_get_src_addr(struct dma_chan *chan);
+
+/*
+ * stedma40_get_dst_addr - get current destination address
+ * @chan: the DMA channel
+ *
+ * Returns the physical address of the current destination element to be
+ * written by the DMA.
+ */
+dma_addr_t stedma40_get_dst_addr(struct dma_chan *chan);
+
+/**
+ * stedma40_cyclic_prep_sg - prepare a cyclic DMA transfer
+ * @chan: the DMA channel to prepare
+ * @sgl: scatter list
+ * @sg_len: number of links in the scatter list
+ * @direction: transfer direction, to or from device
+ * @dma_flags: DMA_PREP_INTERRUPT if a callback is required after every link.
+ * See period_callback in struct stedma40_cyclic_desc.
+ *
+ * Must be called before trying to start a cyclic DMA transfer. Returns
+ * ERR_PTR(-errno) on failure.
+ */
+struct stedma40_cyclic_desc *
+stedma40_cyclic_prep_sg(struct dma_chan *chan,
+ struct scatterlist *sgl,
+ unsigned int sg_len,
+ enum dma_data_direction direction,
+ unsigned long dma_flags);
+
+/**
+ * stedma40_cyclic_start - start the cyclic DMA transfer
+ * @chan: the DMA channel to start
+ *
+ * The cyclic DMA must have been prepared earlier with
+ * stedma40_cyclic_prep_sg().
+ */
+int stedma40_cyclic_start(struct dma_chan *chan);
+
+/**
+ * stedma40_cyclic_stop() - stop the cyclic DMA transfer
+ * @chan: the DMA channel to stop
+ *
+ * Stops a cyclic DMA transfer which was previously started with
+ * stedma40_cyclic_start().
+ */
+void stedma40_cyclic_stop(struct dma_chan *chan);
+
+/**
+ * stedma40_cyclic_free() - free cyclic DMA resources
+ * @chan: the DMA channel
+ *
+ * Must be called to free any resources used for cyclic DMA which have been
+ * allocated in stedma40_cyclic_prep_sg().
+ */
+void stedma40_cyclic_free(struct dma_chan *chan);
+
+/**
+ * setdma40_residue() - Returna the remaining bytes to transfer.
+ *
+ * @chan: dmaengine handle
+ *
+ * returns 0 or positive number of remaning bytes.
+ */
+u32 stedma40_residue(struct dma_chan *chan);
+
/**
* stedma40_filter() - Provides stedma40_chan_cfg to the
* ste_dma40 dma driver via the dmaengine framework.
@@ -187,7 +281,6 @@ int stedma40_set_psize(struct dma_chan *chan,
*
*
*/
-
bool stedma40_filter(struct dma_chan *chan, void *data);
/**
@@ -202,38 +295,10 @@ bool stedma40_filter(struct dma_chan *chan, void *data);
* list.
* @flags: is actually enum dma_ctrl_flags. See dmaengine.h
*/
-
struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
struct scatterlist *sgl_dst,
struct scatterlist *sgl_src,
unsigned int sgl_len,
unsigned long flags);
-/**
- * stedma40_slave_mem() - Transfers a raw data buffer to or from a slave
- * (=device)
- *
- * @chan: dmaengine handle
- * @addr: source or destination physicall address.
- * @size: bytes to transfer
- * @direction: direction of transfer
- * @flags: is actually enum dma_ctrl_flags. See dmaengine.h
- */
-
-static inline struct
-dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan,
- dma_addr_t addr,
- unsigned int size,
- enum dma_data_direction direction,
- unsigned long flags)
-{
- struct scatterlist sg;
- sg_init_table(&sg, 1);
- sg.dma_address = addr;
- sg.length = size;
-
- return chan->device->device_prep_slave_sg(chan, &sg, 1,
- direction, flags);
-}
-
#endif
diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c
index 08aaa4a7f65..aedf9c1d645 100644
--- a/arch/arm/plat-nomadik/timer.c
+++ b/arch/arm/plat-nomadik/timer.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-nomadik/timer.c
+ * linux/arch/arm/plat-nomadik/timer.c
*
* Copyright (C) 2008 STMicroelectronics
* Copyright (C) 2010 Alessandro Rubini
@@ -42,7 +42,6 @@ static struct clocksource nmdk_clksrc = {
.rating = 200,
.read = nmdk_read_timer_dummy,
.mask = CLOCKSOURCE_MASK(32),
- .shift = 20,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -76,12 +75,18 @@ static void nmdk_clkevt_mode(enum clock_event_mode mode,
cr = readl(mtu_base + MTU_CR(1));
writel(0, mtu_base + MTU_LR(1));
writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(1));
- writel(0x2, mtu_base + MTU_IMSC);
+ writel(1 << 1, mtu_base + MTU_IMSC);
break;
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
/* disable irq */
writel(0, mtu_base + MTU_IMSC);
+ /* disable timer */
+ cr = readl(mtu_base + MTU_CR(1));
+ cr &= ~MTU_CRn_ENA;
+ writel(cr, mtu_base + MTU_CR(1));
+ /* load some high default value */
+ writel(0xffffffff, mtu_base + MTU_LR(1));
break;
case CLOCK_EVT_MODE_RESUME:
break;
@@ -98,7 +103,6 @@ static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev)
static struct clock_event_device nmdk_clkevt = {
.name = "mtu_1",
.features = CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
.rating = 200,
.set_mode = nmdk_clkevt_mode,
.set_next_event = nmdk_clkevt_next,
@@ -127,30 +131,29 @@ void __init nmdk_timer_init(void)
{
unsigned long rate;
struct clk *clk0;
- struct clk *clk1;
- u32 cr;
+ u32 cr = MTU_CRn_32BITS;
clk0 = clk_get_sys("mtu0", NULL);
BUG_ON(IS_ERR(clk0));
- clk1 = clk_get_sys("mtu1", NULL);
- BUG_ON(IS_ERR(clk1));
-
clk_enable(clk0);
- clk_enable(clk1);
/*
- * Tick rate is 2.4MHz for Nomadik and 110MHz for ux500:
- * use a divide-by-16 counter if it's more than 16MHz
+ * Tick rate is 2.4MHz for Nomadik and 2.4Mhz, 100MHz or 133 MHz
+ * for ux500.
+ * Use a divide-by-16 counter if the tick rate is more than 32MHz.
+ * At 32 MHz, the timer (with 32 bit counter) can be programmed
+ * to wake-up at a max 127s a head in time. Dividing a 2.4 MHz timer
+ * with 16 gives too low timer resolution.
*/
- cr = MTU_CRn_32BITS;;
rate = clk_get_rate(clk0);
- if (rate > 16 << 20) {
+ if (rate > 32000000) {
rate /= 16;
cr |= MTU_CRn_PRESCALE_16;
} else {
cr |= MTU_CRn_PRESCALE_1;
}
+ clocksource_calc_mult_shift(&nmdk_clksrc, rate, MTU_MIN_RANGE);
/* Timer 0 is the free running clocksource */
writel(cr, mtu_base + MTU_CR(0));
@@ -158,7 +161,6 @@ void __init nmdk_timer_init(void)
writel(0, mtu_base + MTU_BGLR(0));
writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
- nmdk_clksrc.mult = clocksource_hz2mult(rate, nmdk_clksrc.shift);
/* Now the scheduling clock is ready */
nmdk_clksrc.read = nmdk_read_timer;
@@ -166,17 +168,12 @@ void __init nmdk_timer_init(void)
pr_err("timer: failed to initialize clock source %s\n",
nmdk_clksrc.name);
- /* Timer 1 is used for events, fix according to rate */
- cr = MTU_CRn_32BITS;
- rate = clk_get_rate(clk1);
- if (rate > 16 << 20) {
- rate /= 16;
- cr |= MTU_CRn_PRESCALE_16;
- } else {
- cr |= MTU_CRn_PRESCALE_1;
- }
+ /* Timer 1 is used for events */
+
+ clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE);
+
writel(cr | MTU_CRn_ONESHOT, mtu_base + MTU_CR(1)); /* off, currently */
- nmdk_clkevt.mult = div_sc(rate, NSEC_PER_SEC, nmdk_clkevt.shift);
+
nmdk_clkevt.max_delta_ns =
clockevent_delta2ns(0xffffffff, &nmdk_clkevt);
nmdk_clkevt.min_delta_ns =
diff --git a/arch/arm/plat-spear/time.c b/arch/arm/plat-spear/time.c
index a1025d38f38..ab211652e4c 100644
--- a/arch/arm/plat-spear/time.c
+++ b/arch/arm/plat-spear/time.c
@@ -58,6 +58,11 @@
#define INT_STATUS 0x1
+/*
+ * Minimum clocksource/clockevent timer range in seconds
+ */
+#define SPEAR_MIN_RANGE 4
+
static __iomem void *gpt_base;
static struct clk *gpt_clk;
@@ -66,44 +71,6 @@ static void clockevent_set_mode(enum clock_event_mode mode,
static int clockevent_next_event(unsigned long evt,
struct clock_event_device *clk_event_dev);
-/*
- * Following clocksource_set_clock and clockevent_set_clock picked
- * from arch/mips/kernel/time.c
- */
-
-void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock)
-{
- u64 temp;
- u32 shift;
-
- /* Find a shift value */
- for (shift = 32; shift > 0; shift--) {
- temp = (u64) NSEC_PER_SEC << shift;
- do_div(temp, clock);
- if ((temp >> 32) == 0)
- break;
- }
- cs->shift = shift;
- cs->mult = (u32) temp;
-}
-
-void __init clockevent_set_clock(struct clock_event_device *cd,
- unsigned int clock)
-{
- u64 temp;
- u32 shift;
-
- /* Find a shift value */
- for (shift = 32; shift > 0; shift--) {
- temp = (u64) clock << shift;
- do_div(temp, NSEC_PER_SEC);
- if ((temp >> 32) == 0)
- break;
- }
- cd->shift = shift;
- cd->mult = (u32) temp;
-}
-
static cycle_t clocksource_read_cycles(struct clocksource *cs)
{
return (cycle_t) readw(gpt_base + COUNT(CLKSRC));
@@ -138,7 +105,7 @@ static void spear_clocksource_init(void)
val |= CTRL_ENABLE ;
writew(val, gpt_base + CR(CLKSRC));
- clocksource_set_clock(&clksrc, tick_rate);
+ clocksource_calc_mult_shift(&clksrc, tick_rate, SPEAR_MIN_RANGE);
/* register the clocksource */
clocksource_register(&clksrc);
@@ -233,7 +200,7 @@ static void __init spear_clockevent_init(void)
tick_rate = clk_get_rate(gpt_clk);
tick_rate >>= CTRL_PRESCALER16;
- clockevent_set_clock(&clkevt, tick_rate);
+ clockevents_calc_mult_shift(&clkevt, tick_rate, SPEAR_MIN_RANGE);
clkevt.max_delta_ns = clockevent_delta2ns(0xfff0,
&clkevt);
diff --git a/arch/arm/plat-versatile/Makefile b/arch/arm/plat-versatile/Makefile
index 9b1a66816aa..5cf88e8427b 100644
--- a/arch/arm/plat-versatile/Makefile
+++ b/arch/arm/plat-versatile/Makefile
@@ -2,3 +2,7 @@ obj-y := clock.o
obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o
obj-$(CONFIG_ARCH_REALVIEW) += sched-clock.o
obj-$(CONFIG_ARCH_VERSATILE) += sched-clock.o
+ifeq ($(CONFIG_LEDS_CLASS),y)
+obj-$(CONFIG_ARCH_REALVIEW) += leds.o
+obj-$(CONFIG_ARCH_VERSATILE) += leds.o
+endif
diff --git a/arch/arm/plat-versatile/leds.c b/arch/arm/plat-versatile/leds.c
new file mode 100644
index 00000000000..3169fa555ea
--- /dev/null
+++ b/arch/arm/plat-versatile/leds.c
@@ -0,0 +1,103 @@
+/*
+ * Driver for the 8 user LEDs found on the RealViews and Versatiles
+ * Based on DaVinci's DM365 board code
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Linus Walleij <triad@df.lth.se>
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+#ifdef VERSATILE_SYS_BASE
+#define LEDREG (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET)
+#endif
+
+#ifdef REALVIEW_SYS_BASE
+#define LEDREG (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET)
+#endif
+
+struct versatile_led {
+ struct led_classdev cdev;
+ u8 mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+ const char *name;
+ const char *trigger;
+} versatile_leds[] = {
+ { "versatile:0", "heartbeat", },
+ { "versatile:1", "mmc0", },
+ { "versatile:2", },
+ { "versatile:3", },
+ { "versatile:4", },
+ { "versatile:5", },
+ { "versatile:6", },
+ { "versatile:7", },
+};
+
+static void versatile_led_set(struct led_classdev *cdev,
+ enum led_brightness b)
+{
+ struct versatile_led *led = container_of(cdev,
+ struct versatile_led, cdev);
+ u32 reg = readl(LEDREG);
+
+ if (b != LED_OFF)
+ reg |= led->mask;
+ else
+ reg &= ~led->mask;
+ writel(reg, LEDREG);
+}
+
+static enum led_brightness versatile_led_get(struct led_classdev *cdev)
+{
+ struct versatile_led *led = container_of(cdev,
+ struct versatile_led, cdev);
+ u32 reg = readl(LEDREG);
+
+ return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
+
+static int __init versatile_leds_init(void)
+{
+ int i;
+
+ /* All ON */
+ writel(0xff, LEDREG);
+ for (i = 0; i < ARRAY_SIZE(versatile_leds); i++) {
+ struct versatile_led *led;
+
+ led = kzalloc(sizeof(*led), GFP_KERNEL);
+ if (!led)
+ break;
+
+ led->cdev.name = versatile_leds[i].name;
+ led->cdev.brightness_set = versatile_led_set;
+ led->cdev.brightness_get = versatile_led_get;
+ led->cdev.default_trigger = versatile_leds[i].trigger;
+ led->mask = BIT(i);
+
+ if (led_classdev_register(NULL, &led->cdev) < 0) {
+ kfree(led);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(versatile_leds_init);
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 48cbdcb6bbd..2d2b0d8d2bb 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -2950,3 +2950,5 @@ davinci_dm365_dvr MACH_DAVINCI_DM365_DVR DAVINCI_DM365_DVR 2963
netviz MACH_NETVIZ NETVIZ 2964
flexibity MACH_FLEXIBITY FLEXIBITY 2965
wlan_computer MACH_WLAN_COMPUTER WLAN_COMPUTER 2966
+svp8500v1 MACH_SVP8500V1 SVP8500V1 2967
+svp8500v2 MACH_SVP8500V2 SVP8500V2 2968
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 6781b709cac..b313ed5050e 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -113,4 +113,6 @@ source "drivers/xen/Kconfig"
source "drivers/staging/Kconfig"
source "drivers/platform/Kconfig"
+
+source "drivers/tee/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 445143b4e83..d479e20c196 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -114,3 +114,5 @@ obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
obj-y += platform/
obj-y += ieee802154/
+obj-$(CONFIG_TEE_SUPPORT) += tee/
+
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index f60b2b6a093..7cfcfcb814b 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -252,7 +252,7 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
iounmap(tmp);
- if (cid == 0xb105f00d)
+ if (cid == AMBA_CID)
dev->periphid = pid;
if (!dev->periphid) {
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 058fbccf2f5..aeb1b8c6e81 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -207,4 +207,11 @@ config BT_ATH3K
Say Y here to compile support for "Atheros firmware download driver"
into the kernel or say M to compile it as module (ath3k).
+config BT_CG2900
+ tristate "ST-Ericsson CG2900 driver"
+ depends on MFD_CG2900 && BT
+ help
+ Select if BlueZ shall be used as Bluetooth stack with
+ ST-Ericsson CG2900 Connectivity controller
+
endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 7e5aed59812..86cab82053a 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -19,6 +19,8 @@ obj-$(CONFIG_BT_ATH3K) += ath3k.o
obj-$(CONFIG_BT_MRVL) += btmrvl.o
obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
+obj-$(CONFIG_BT_CG2900) += cg2900_hci.o
+
btmrvl-y := btmrvl_main.o
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
diff --git a/drivers/bluetooth/cg2900_hci.c b/drivers/bluetooth/cg2900_hci.c
new file mode 100644
index 00000000000..de1ada8ed32
--- /dev/null
+++ b/drivers/bluetooth/cg2900_hci.c
@@ -0,0 +1,896 @@
+/*
+ * drivers/bluetooth/cg2900_hci.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth HCI H:4 Driver for ST-Ericsson CG2900 connectivity controller
+ * towards the BlueZ Bluetooth stack.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <asm/byteorder.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+#include <net/bluetooth/hci_core.h>
+
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+
+#include <linux/mfd/cg2900.h>
+#include <mach/cg2900_devices.h>
+
+/* module_param declared in cg2900_core.c */
+extern int cg2900_debug_level;
+
+#define NAME "CG2900 HCI"
+
+/* Debug defines */
+#define CG2900_DBG_DATA(fmt, arg...) \
+do { \
+ if (cg2900_debug_level >= 25) \
+ printk(KERN_DEBUG NAME " %s: " fmt "\n" , __func__ , ## arg); \
+} while (0)
+
+#define CG2900_DBG(fmt, arg...) \
+do { \
+ if (cg2900_debug_level >= 20) \
+ printk(KERN_DEBUG NAME " %s: " fmt "\n" , __func__ , ## arg); \
+} while (0)
+
+#define CG2900_INFO(fmt, arg...) \
+do { \
+ if (cg2900_debug_level >= 10) \
+ printk(KERN_INFO NAME ": " fmt "\n" , ## arg); \
+} while (0)
+
+#define CG2900_ERR(fmt, arg...) \
+do { \
+ if (cg2900_debug_level >= 1) \
+ printk(KERN_ERR NAME " %s: " fmt "\n" , __func__ , ## arg); \
+} while (0)
+
+#define CG2900_SET_STATE(__name, __var, __new_state) \
+do { \
+ CG2900_DBG("New %s: 0x%X", __name, (uint32_t)__new_state); \
+ __var = __new_state; \
+} while (0)
+
+/* HCI device type */
+#define HCI_CG2900 HCI_VIRTUAL
+
+/* Wait for 5 seconds for a response to our requests */
+#define RESP_TIMEOUT 5000
+
+/* State-setting defines */
+#define SET_RESET_STATE(__hci_reset_new_state) \
+ CG2900_SET_STATE("reset_state", hci_info->reset_state, \
+ __hci_reset_new_state)
+#define SET_ENABLE_STATE(__hci_enable_new_state) \
+ CG2900_SET_STATE("enable_state", hci_info->enable_state, \
+ __hci_enable_new_state)
+
+/* Bluetooth error codes */
+#define HCI_ERR_NO_ERROR 0x00
+#define HCI_ERR_CMD_DISALLOWED 0x0C
+
+/**
+ * enum reset_state - RESET-states of the HCI driver.
+ *
+ * @RESET_IDLE: No reset in progress.
+ * @RESET_ACTIVATED: Reset in progress.
+ * @RESET_UNREGISTERED: hdev is unregistered.
+ */
+
+enum reset_state {
+ RESET_IDLE,
+ RESET_ACTIVATED,
+ RESET_UNREGISTERED
+};
+
+/**
+ * enum enable_state - ENABLE-states of the HCI driver.
+ *
+ * @ENABLE_IDLE: The HCI driver is loaded but not opened.
+ * @ENABLE_WAITING_BT_ENABLED_CC: The HCI driver is waiting for a command
+ * complete event from the BT chip as a
+ * response to a BT Enable (true) command.
+ * @ENABLE_BT_ENABLED: The BT chip is enabled.
+ * @ENABLE_WAITING_BT_DISABLED_CC: The HCI driver is waiting for a command
+ * complete event from the BT chip as a
+ * response to a BT Enable (false) command.
+ * @ENABLE_BT_DISABLED: The BT chip is disabled.
+ * @ENABLE_BT_ERROR: The HCI driver is in a bad state, some
+ * thing has failed and is not expected to
+ * work properly.
+ */
+enum enable_state {
+ ENABLE_IDLE,
+ ENABLE_WAITING_BT_ENABLED_CC,
+ ENABLE_BT_ENABLED,
+ ENABLE_WAITING_BT_DISABLED_CC,
+ ENABLE_BT_DISABLED,
+ ENABLE_BT_ERROR
+};
+
+/**
+ * struct hci_info - Specifies HCI driver private data.
+ *
+ * This type specifies CG2900 HCI driver private data.
+ *
+ * @bt_cmd: Device structure for BT command channel.
+ * @bt_evt: Device structure for BT event channel.
+ * @bt_acl: Device structure for BT ACL channel.
+ * @hdev: Device structure for HCI device.
+ * @reset_state: Device enum for HCI driver reset state.
+ * @enable_state: Device enum for HCI driver BT enable state.
+ */
+struct hci_info {
+ struct cg2900_device *bt_cmd;
+ struct cg2900_device *bt_evt;
+ struct cg2900_device *bt_acl;
+ struct hci_dev *hdev;
+ enum reset_state reset_state;
+ enum enable_state enable_state;
+};
+
+/**
+ * struct dev_info - Specifies private data used when receiving callbacks from CPD.
+ *
+ * @hdev: Device structure for HCI device.
+ * @hci_data_type: Type of data according to BlueZ.
+ */
+struct dev_info {
+ struct hci_dev *hdev;
+ u8 hci_data_type;
+};
+
+/* Variables where LSB and MSB for bt_enable command is stored */
+static u16 bt_enable_cmd;
+
+static struct hci_info *hci_info;
+
+/*
+ * hci_wait_queue - Main Wait Queue in HCI driver.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(hci_wait_queue);
+
+/* Internal function declarations */
+static int register_to_bluez(void);
+
+/* Internal functions */
+
+/**
+ * remove_bt_users() - Unregister and remove any existing BT users.
+ * @info: HCI driver info structure.
+ */
+static void remove_bt_users(struct hci_info *info)
+{
+ if (info->bt_cmd) {
+ kfree(info->bt_cmd->user_data);
+ info->bt_cmd->user_data = NULL;
+ cg2900_deregister_user(info->bt_cmd);
+ info->bt_cmd = NULL;
+ }
+
+ if (info->bt_evt) {
+ kfree(info->bt_evt->user_data);
+ info->bt_evt->user_data = NULL;
+ cg2900_deregister_user(info->bt_evt);
+ info->bt_evt = NULL;
+ }
+
+ if (info->bt_acl) {
+ kfree(info->bt_acl->user_data);
+ info->bt_acl->user_data = NULL;
+ cg2900_deregister_user(info->bt_acl);
+ info->bt_acl = NULL;
+ }
+}
+
+/**
+ * hci_read_cb() - Callback for handling data received from CG2900 driver.
+ * @dev: Device receiving data.
+ * @skb: Buffer with data coming from device.
+ */
+static void hci_read_cb(struct cg2900_device *dev, struct sk_buff *skb)
+{
+ int err = 0;
+ struct dev_info *dev_info;
+ struct hci_event_hdr *evt;
+ struct hci_ev_cmd_complete *cmd_complete;
+ struct hci_ev_cmd_status *cmd_status;
+ u8 status;
+
+ if (!skb) {
+ CG2900_ERR("NULL supplied for skb");
+ return;
+ }
+
+ if (!dev) {
+ CG2900_ERR("dev == NULL");
+ goto fin_free_skb;
+ }
+
+ dev_info = (struct dev_info *)dev->user_data;
+
+ if (!dev_info) {
+ CG2900_ERR("dev_info == NULL");
+ goto fin_free_skb;
+ }
+
+ evt = (struct hci_event_hdr *)skb->data;
+ cmd_complete = (struct hci_ev_cmd_complete *)(skb->data + sizeof(*evt));
+ cmd_status = (struct hci_ev_cmd_status *)(skb->data + sizeof(*evt));
+
+ /*
+ * Check if HCI Driver it self is expecting a Command Complete packet
+ * from the chip after a BT Enable command.
+ */
+ if ((hci_info->enable_state == ENABLE_WAITING_BT_ENABLED_CC ||
+ hci_info->enable_state == ENABLE_WAITING_BT_DISABLED_CC) &&
+ hci_info->bt_evt->h4_channel == dev->h4_channel &&
+ evt->evt == HCI_EV_CMD_COMPLETE &&
+ le16_to_cpu(cmd_complete->opcode) == bt_enable_cmd) {
+ /*
+ * This is the command complete event for
+ * the HCI_Cmd_VS_Bluetooth_Enable.
+ * Check result and update state.
+ *
+ * The BT chip is enabled/disabled. Either it was enabled/
+ * disabled now (status NO_ERROR) or it was already enabled/
+ * disabled (assuming status CMD_DISALLOWED is already enabled/
+ * disabled).
+ */
+ status = *(skb->data + sizeof(*evt) + sizeof(*cmd_complete));
+ if (status != HCI_ERR_NO_ERROR &&
+ status != HCI_ERR_CMD_DISALLOWED) {
+ CG2900_ERR("Could not enable/disable BT core (0x%X)",
+ status);
+ SET_ENABLE_STATE(ENABLE_BT_ERROR);
+ goto fin_free_skb;
+ }
+
+ if (hci_info->enable_state == ENABLE_WAITING_BT_ENABLED_CC) {
+ SET_ENABLE_STATE(ENABLE_BT_ENABLED);
+ CG2900_INFO("BT core is enabled");
+ } else {
+ SET_ENABLE_STATE(ENABLE_BT_DISABLED);
+ CG2900_INFO("BT core is disabled");
+ }
+
+ /* Wake up whom ever is waiting for this result. */
+ wake_up_interruptible(&hci_wait_queue);
+ goto fin_free_skb;
+ } else if ((hci_info->enable_state == ENABLE_WAITING_BT_DISABLED_CC ||
+ hci_info->enable_state == ENABLE_WAITING_BT_ENABLED_CC) &&
+ hci_info->bt_evt->h4_channel == dev->h4_channel &&
+ evt->evt == HCI_EV_CMD_STATUS &&
+ le16_to_cpu(cmd_status->opcode) == bt_enable_cmd) {
+ /*
+ * Clear the status events since the Bluez is not expecting
+ * them.
+ */
+ CG2900_DBG("HCI Driver received Command Status(for "
+ "BT enable): 0x%X", cmd_status->status);
+ /*
+ * This is the command status event for
+ * the HCI_Cmd_VS_Bluetooth_Enable.
+ * Just free the packet.
+ */
+ goto fin_free_skb;
+ } else {
+ bt_cb(skb)->pkt_type = dev_info->hci_data_type;
+ skb->dev = (struct net_device *)dev_info->hdev;
+ /* Update BlueZ stats */
+ dev_info->hdev->stat.byte_rx += skb->len;
+ if (bt_cb(skb)->pkt_type == HCI_ACLDATA_PKT)
+ dev_info->hdev->stat.acl_rx++;
+ else
+ dev_info->hdev->stat.evt_rx++;
+
+ CG2900_DBG_DATA("Data receive %d bytes", skb->len);
+
+ /* Provide BlueZ with received frame*/
+ err = hci_recv_frame(skb);
+ /* If err, skb have been freed in hci_recv_frame() */
+ if (err)
+ CG2900_ERR("Failed in supplying packet to BlueZ (%d)",
+ err);
+ }
+
+ return;
+
+fin_free_skb:
+ kfree_skb(skb);
+}
+
+/**
+ * hci_reset_cb() - Callback for handling reset from CG2900 driver.
+ * @dev: CPD device resetting.
+ */
+static void hci_reset_cb(struct cg2900_device *dev)
+{
+ int err;
+ struct hci_dev *hdev;
+ struct dev_info *dev_info;
+ struct hci_info *info;
+
+ CG2900_INFO("BluezDriver: hci_reset_cb");
+
+ if (!dev) {
+ CG2900_ERR("NULL supplied for dev");
+ return;
+ }
+
+ dev_info = (struct dev_info *)dev->user_data;
+ if (!dev_info) {
+ CG2900_ERR("NULL supplied for dev_info");
+ return;
+ }
+
+ hdev = dev_info->hdev;
+ if (!hdev) {
+ CG2900_ERR("NULL supplied for hdev");
+ return;
+ }
+
+ info = (struct hci_info *)hdev->driver_data;
+ if (!info) {
+ CG2900_ERR("NULL supplied for driver_data");
+ return;
+ }
+
+ switch (dev_info->hci_data_type) {
+
+ case HCI_EVENT_PKT:
+ info->bt_evt = NULL;
+ break;
+
+ case HCI_COMMAND_PKT:
+ info->bt_cmd = NULL;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ info->bt_acl = NULL;
+ break;
+
+ default:
+ CG2900_ERR("Unknown HCI data type:%d",
+ dev_info->hci_data_type);
+ return;
+ }
+
+ SET_RESET_STATE(RESET_ACTIVATED);
+
+ /* Free userdata as device info structure will be freed by CG2900
+ * when this callback returns */
+ kfree(dev->user_data);
+ dev->user_data = NULL;
+
+ /*
+ * Continue to deregister hdev if all channels has been reset else
+ * return.
+ */
+ if (info->bt_evt || info->bt_cmd || info->bt_acl)
+ return;
+
+ /*
+ * Deregister HCI device. Close and Destruct functions should
+ * in turn be called by BlueZ.
+ */
+ CG2900_INFO("Deregister HCI device");
+ err = hci_unregister_dev(hdev);
+ if (err)
+ CG2900_ERR("Can not deregister HCI device! (%d)", err);
+ /*
+ * Now we are in trouble. Try to register a new hdev
+ * anyway even though this will cost some memory.
+ */
+
+ wait_event_interruptible_timeout(hci_wait_queue,
+ (RESET_UNREGISTERED == hci_info->reset_state),
+ msecs_to_jiffies(RESP_TIMEOUT));
+ if (RESET_UNREGISTERED != hci_info->reset_state)
+ /*
+ * Now we are in trouble. Try to register a new hdev
+ * anyway even though this will cost some memory.
+ */
+ CG2900_ERR("Timeout expired. Could not deregister HCI device");
+
+ /* Init and register hdev */
+ CG2900_INFO("Register HCI device");
+ err = register_to_bluez();
+ if (err)
+ CG2900_ERR("HCI Device registration error (%d).", err);
+}
+
+/*
+ * struct cg2900_cb - Specifies callback structure for CG2900 user.
+ *
+ * @read_cb: Callback function called when data is received from
+ * the controller.
+ * @reset_cb: Callback function called when the controller has been reset.
+ */
+static struct cg2900_callbacks cg2900_cb = {
+ .read_cb = hci_read_cb,
+ .reset_cb = hci_reset_cb
+};
+
+/**
+ * open_from_hci() - Open HCI interface.
+ * @hdev: HCI device being opened.
+ *
+ * BlueZ callback function for opening HCI interface to device.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL if NULL pointer is supplied.
+ * -EOPNOTSUPP if supplied packet type is not supported.
+ * -EBUSY if device is already opened.
+ * -EACCES if opening of channels failed.
+ */
+static int open_from_hci(struct hci_dev *hdev)
+{
+ struct hci_info *info;
+ struct dev_info *dev_info;
+ struct sk_buff *enable_cmd;
+ int err;
+
+ CG2900_INFO("Open ST-Ericsson connectivity HCI driver");
+
+ if (!hdev) {
+ CG2900_ERR("NULL supplied for hdev");
+ return -EINVAL;
+ }
+
+ info = (struct hci_info *)hdev->driver_data;
+ if (!info) {
+ CG2900_ERR("NULL supplied for driver_data");
+ return -EINVAL;
+ }
+
+ if (test_and_set_bit(HCI_RUNNING, &(hdev->flags))) {
+ CG2900_ERR("Device already opened!");
+ return -EBUSY;
+ }
+
+ if (!(info->bt_cmd)) {
+ info->bt_cmd = cg2900_register_user(CG2900_BT_CMD,
+ &cg2900_cb);
+ if (info->bt_cmd) {
+ dev_info = kmalloc(sizeof(*dev_info), GFP_KERNEL);
+ if (dev_info) {
+ dev_info->hdev = hdev;
+ dev_info->hci_data_type = HCI_COMMAND_PKT;
+ }
+ info->bt_cmd->user_data = dev_info;
+ } else {
+ CG2900_ERR("Couldn't register CG2900_BT_CMD to CG2900");
+ err = -EACCES;
+ goto handle_error;
+ }
+ }
+
+ if (!(info->bt_evt)) {
+ info->bt_evt = cg2900_register_user(CG2900_BT_EVT,
+ &cg2900_cb);
+ if (info->bt_evt) {
+ dev_info = kmalloc(sizeof(*dev_info), GFP_KERNEL);
+ if (dev_info) {
+ dev_info->hdev = hdev;
+ dev_info->hci_data_type = HCI_EVENT_PKT;
+ }
+ info->bt_evt->user_data = dev_info;
+ } else {
+ CG2900_ERR("Couldn't register CG2900_BT_EVT to CG2900");
+ err = -EACCES;
+ goto handle_error;
+ }
+ }
+
+ if (!(info->bt_acl)) {
+ info->bt_acl = cg2900_register_user(CG2900_BT_ACL,
+ &cg2900_cb);
+ if (info->bt_acl) {
+ dev_info = kmalloc(sizeof(*dev_info), GFP_KERNEL);
+ if (dev_info) {
+ dev_info->hdev = hdev;
+ dev_info->hci_data_type = HCI_ACLDATA_PKT;
+ }
+ info->bt_acl->user_data = dev_info;
+ } else {
+ CG2900_ERR("Couldn't register CG2900_BT_ACL to CG2900");
+ err = -EACCES;
+ goto handle_error;
+ }
+ }
+
+ if (info->reset_state == RESET_ACTIVATED)
+ SET_RESET_STATE(RESET_IDLE);
+
+ /*
+ * Call platform specific function that returns the chip dependent
+ * bt enable(true) HCI command.
+ * If NULL is returned, then no bt_enable command should be sent to the
+ * chip.
+ */
+ enable_cmd = cg2900_devices_get_bt_enable_cmd(&bt_enable_cmd, true);
+ if (!enable_cmd) {
+ /* The chip is enabled by default */
+ SET_ENABLE_STATE(ENABLE_BT_ENABLED);
+ return 0;
+ }
+
+ /* Set the HCI state before sending command to chip. */
+ SET_ENABLE_STATE(ENABLE_WAITING_BT_ENABLED_CC);
+
+ /* Send command to chip */
+ cg2900_write(info->bt_cmd, enable_cmd);
+
+ /*
+ * Wait for callback to receive command complete and then wake us up
+ * again.
+ */
+ wait_event_interruptible_timeout(hci_wait_queue,
+ (info->enable_state == ENABLE_BT_ENABLED),
+ msecs_to_jiffies(RESP_TIMEOUT));
+ /* Check the current state to se that it worked. */
+ if (info->enable_state != ENABLE_BT_ENABLED) {
+ CG2900_ERR("Could not enable BT core (%d)", info->enable_state);
+ err = -EACCES;
+ SET_ENABLE_STATE(ENABLE_BT_DISABLED);
+ goto handle_error;
+ }
+
+ return 0;
+
+handle_error:
+ remove_bt_users(info);
+ clear_bit(HCI_RUNNING, &(hdev->flags));
+ return err;
+
+}
+
+/**
+ * flush_from_hci() - Flush HCI interface.
+ * @hdev: HCI device being flushed.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL if NULL pointer is supplied.
+ */
+static int flush_from_hci(struct hci_dev *hdev)
+{
+ CG2900_INFO("flush_from_hci");
+
+ if (!hdev) {
+ CG2900_ERR("NULL supplied for hdev");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * close_from_hci() - Close HCI interface.
+ * @hdev: HCI device being closed.
+ *
+ * BlueZ callback function for closing HCI interface.
+ * It flushes the interface first.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL if NULL pointer is supplied.
+ * -EOPNOTSUPP if supplied packet type is not supported.
+ * -EBUSY if device is not opened.
+ */
+static int close_from_hci(struct hci_dev *hdev)
+{
+ struct hci_info *info = NULL;
+ struct sk_buff *enable_cmd;
+
+ CG2900_INFO("close_from_hci");
+
+ if (!hdev) {
+ CG2900_ERR("NULL supplied for hdev");
+ return -EINVAL;
+ }
+
+ info = (struct hci_info *)hdev->driver_data;
+ if (!info) {
+ CG2900_ERR("NULL supplied for driver_data");
+ return -EINVAL;
+ }
+
+ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) {
+ CG2900_ERR("Device already closed!");
+ return -EBUSY;
+ }
+
+ flush_from_hci(hdev);
+
+ /* Do not do this if there is an reset ongoing */
+ if (hci_info->reset_state == RESET_ACTIVATED)
+ goto remove_users;
+
+ /*
+ * Get the chip dependent BT Enable HCI command. The command parameter
+ * shall be set to false to disable the BT core.
+ * If NULL is returned, then no BT Enable command should be sent to the
+ * chip.
+ */
+ enable_cmd = cg2900_devices_get_bt_enable_cmd(&bt_enable_cmd, false);
+ if (!enable_cmd) {
+ /*
+ * The chip is enabled by default and we should not disable it.
+ */
+ SET_ENABLE_STATE(ENABLE_BT_ENABLED);
+ goto remove_users;
+ }
+
+ /* Set the HCI state before sending command to chip */
+ SET_ENABLE_STATE(ENABLE_WAITING_BT_DISABLED_CC);
+
+ /* Send command to chip */
+ cg2900_write(info->bt_cmd, enable_cmd);
+
+ /*
+ * Wait for callback to receive command complete and then wake us up
+ * again.
+ */
+ wait_event_interruptible_timeout(hci_wait_queue,
+ (info->enable_state == ENABLE_BT_DISABLED),
+ msecs_to_jiffies(RESP_TIMEOUT));
+ /* Check the current state to se that it worked. */
+ if (info->enable_state != ENABLE_BT_DISABLED) {
+ CG2900_ERR("Could not disable BT core.");
+ SET_ENABLE_STATE(ENABLE_BT_ENABLED);
+ }
+
+remove_users:
+ /* Finally deregister all users and free allocated data */
+ remove_bt_users(info);
+ return 0;
+}
+
+/**
+ * send_from_hci() - Send packet to device.
+ * @skb: sk buffer to be sent.
+ *
+ * BlueZ callback function for sending sk buffer.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL if NULL pointer is supplied.
+ * -EOPNOTSUPP if supplied packet type is not supported.
+ * Error codes from cg2900_write.
+ */
+static int send_from_hci(struct sk_buff *skb)
+{
+ struct hci_dev *hdev;
+ struct hci_info *info;
+ int err = 0;
+
+ if (!skb) {
+ CG2900_ERR("NULL supplied for skb");
+ return -EINVAL;
+ }
+
+ hdev = (struct hci_dev *)(skb->dev);
+ if (!hdev) {
+ CG2900_ERR("NULL supplied for hdev");
+ return -EINVAL;
+ }
+
+ info = (struct hci_info *)hdev->driver_data;
+ if (!info) {
+ CG2900_ERR("NULL supplied for info");
+ return -EINVAL;
+ }
+
+ /* Update BlueZ stats */
+ hdev->stat.byte_tx += skb->len;
+
+ CG2900_DBG_DATA("Data transmit %d bytes", skb->len);
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ CG2900_DBG("Sending HCI_COMMAND_PKT");
+ err = cg2900_write(info->bt_cmd, skb);
+ hdev->stat.cmd_tx++;
+ break;
+ case HCI_ACLDATA_PKT:
+ CG2900_DBG("Sending HCI_ACLDATA_PKT");
+ err = cg2900_write(info->bt_acl, skb);
+ hdev->stat.acl_tx++;
+ break;
+ default:
+ CG2900_ERR("Trying to transmit unsupported packet type "
+ "(0x%.2X)", bt_cb(skb)->pkt_type);
+ err = -EOPNOTSUPP;
+ break;
+ };
+
+ return err;
+}
+
+/**
+ * destruct_from_hci() - Destruct HCI interface.
+ * @hdev: HCI device being destructed.
+ */
+static void destruct_from_hci(struct hci_dev *hdev)
+{
+ CG2900_INFO("destruct_from_hci");
+
+ if (!hci_info)
+ return;
+
+ /* When being reset, register a new hdev when hdev is deregistered */
+ if (hci_info->reset_state == RESET_ACTIVATED) {
+ if (hci_info->hdev)
+ hci_free_dev(hci_info->hdev);
+ SET_RESET_STATE(RESET_UNREGISTERED);
+ }
+}
+
+/**
+ * notify_from_hci() - Notification from the HCI interface.
+ * @hdev: HCI device notifying.
+ * @evt: Notification event.
+ */
+static void notify_from_hci(struct hci_dev *hdev, unsigned int evt)
+{
+ CG2900_INFO("notify_from_hci - evt = 0x%.2X", evt);
+}
+
+/**
+ * ioctl_from_hci() - Handle IOCTL call to the HCI interface.
+ * @hdev: HCI device.
+ * @cmd: IOCTL command.
+ * @arg: IOCTL argument.
+ *
+ * Returns:
+ * -EINVAL if NULL is supplied for hdev.
+ * -EPERM otherwise since current driver supports no IOCTL.
+ */
+static int ioctl_from_hci(struct hci_dev *hdev, unsigned int cmd,
+ unsigned long arg)
+{
+ CG2900_INFO("ioctl_from_hci - cmd 0x%X", cmd);
+ CG2900_DBG("DIR: %d, TYPE: %d, NR: %d, SIZE: %d",
+ _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd),
+ _IOC_SIZE(cmd));
+
+ if (!hdev) {
+ CG2900_ERR("NULL supplied for hdev");
+ return -EINVAL;;
+ }
+
+ return -EPERM;
+}
+
+/**
+ * register_to_bluez() - Initialize module.
+ *
+ * Alloc, init, and register HCI device to BlueZ.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ENOMEM if allocation fails.
+ * Error codes from hci_register_dev.
+ */
+static int register_to_bluez(void)
+{
+ int err;
+
+ hci_info->hdev = hci_alloc_dev();
+ if (!hci_info->hdev) {
+ CG2900_ERR("Could not allocate mem for HCI driver");
+ return -ENOMEM;
+ }
+
+ hci_info->hdev->bus = HCI_CG2900;
+ hci_info->hdev->driver_data = hci_info;
+ hci_info->hdev->owner = THIS_MODULE;
+ hci_info->hdev->open = open_from_hci;
+ hci_info->hdev->close = close_from_hci;
+ hci_info->hdev->flush = flush_from_hci;
+ hci_info->hdev->send = send_from_hci;
+ hci_info->hdev->destruct = destruct_from_hci;
+ hci_info->hdev->notify = notify_from_hci;
+ hci_info->hdev->ioctl = ioctl_from_hci;
+
+ err = hci_register_dev(hci_info->hdev);
+ if (err) {
+ CG2900_ERR("Can not register HCI device (%d)", err);
+ hci_free_dev(hci_info->hdev);
+ }
+
+ SET_ENABLE_STATE(ENABLE_IDLE);
+ SET_RESET_STATE(RESET_IDLE);
+
+ return err;
+}
+
+/**
+ * hci_init() - Initialize module.
+ *
+ * Allocate and initialize private data. Register to BlueZ.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ENOMEM if allocation fails.
+ * Error codes from register_to_bluez.
+ */
+static int __init hci_init(void)
+{
+ int err;
+ CG2900_INFO("hci_init");
+
+ /* Initialize private data. */
+ hci_info = kzalloc(sizeof(*hci_info), GFP_KERNEL);
+ if (!hci_info) {
+ CG2900_ERR("Could not alloc hci_info struct.");
+ return -ENOMEM;
+ }
+
+ /* Init and register hdev */
+ err = register_to_bluez();
+ if (err) {
+ CG2900_ERR("HCI Device registration error (%d)", err);
+ kfree(hci_info);
+ hci_info = NULL;
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * hci_exit() - Remove module.
+ *
+ * Remove HCI device from CG2900 driver.
+ */
+static void __exit hci_exit(void)
+{
+ int err = 0;
+
+ CG2900_INFO("hci_exit");
+
+ if (!hci_info)
+ return;
+
+ if (!hci_info->hdev)
+ goto finished;
+
+ err = hci_unregister_dev(hci_info->hdev);
+ if (err)
+ CG2900_ERR("Can not unregister HCI device (%d)", err);
+ hci_free_dev(hci_info->hdev);
+
+finished:
+ kfree(hci_info);
+ hci_info = NULL;
+}
+
+module_init(hci_init);
+module_exit(hci_exit);
+
+MODULE_AUTHOR("Par-Gunnar Hjalmdahl ST-Ericsson");
+MODULE_AUTHOR("Henrik Possung ST-Ericsson");
+MODULE_AUTHOR("Josef Kindberg ST-Ericsson");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Linux Bluetooth HCI H:4 Driver for ST-Ericsson controller");
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 6bf2571536c..41d71912b37 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -112,6 +112,9 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o
obj-$(CONFIG_RAMOOPS) += ramoops.o
obj-$(CONFIG_JS_RTC) += js-rtc.o
+ifdef CONFIG_PHONET
+obj-$(CONFIG_U8500_SHRM) += shrm_char.o
+endif
js-rtc-y = rtc.o
# Files generated that shall be removed upon make clean
diff --git a/drivers/char/shrm_char.c b/drivers/char/shrm_char.c
new file mode 100644
index 00000000000..e087790cfbe
--- /dev/null
+++ b/drivers/char/shrm_char.c
@@ -0,0 +1,838 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson
+ * Author: Kumar Sanghavi <kumar.sanghvi@stericsson.com> for ST-Ericsson
+ * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+
+#include <mach/isa_ioctl.h>
+#include <mach/shrm_driver.h>
+#include <mach/shrm_private.h>
+#include <mach/shrm_config.h>
+#include <mach/shrm.h>
+
+
+#define NAME "IPC_ISA"
+/* L2 header for common loopback device is 0xc0 and hence 0xc0+1 = 193*/
+#define MAX_L2_HEADERS 193
+
+#define SIZE_OF_FIFO (512*1024)
+
+static u8 message_fifo[ISA_DEVICES][SIZE_OF_FIFO];
+
+static u8 wr_rpc_msg[10*1024];
+static u8 wr_sec_msg[10*1024];
+static u8 wr_audio_msg[10*1024];
+
+struct map_device {
+ u8 l2_header;
+ u8 idx;
+ char *name;
+};
+
+static struct map_device map_dev[] = {
+ {ISI_MESSAGING, 0, "isi"},
+ {RPC_MESSAGING, 1, "rpc"},
+ {AUDIO_MESSAGING, 2, "modemaudio"},
+ {SECURITY_MESSAGING, 3, "sec"},
+ {COMMON_LOOPBACK_MESSAGING, 4, "common_loopback"},
+ {AUDIO_LOOPBACK_MESSAGING, 5, "audio_loopback"},
+};
+
+/*
+ * int major:This variable is exported to user as module_param to specify
+ * major number at load time
+ */
+static int major;
+module_param(major, int, 0);
+MODULE_PARM_DESC(major, "Major device number");
+/* global fops mutex */
+static DEFINE_MUTEX(isa_lock);
+
+/**
+ * shrm_get_cdev_index() - return the index mapped to l2 header
+ * @l2_header: L2 header
+ *
+ * struct map_device maps the index(count) with the device L2 header.
+ * This function returns the index for the provided L2 header in case
+ * of success else -ve value.
+ */
+int shrm_get_cdev_index(u8 l2_header)
+{
+ u8 cnt;
+ for (cnt = 0; cnt < ISA_DEVICES; cnt++) {
+ if (map_dev[cnt].l2_header == l2_header)
+ return map_dev[cnt].idx;
+ }
+ return -EINVAL;
+}
+
+/**
+ * shrm_get_cdev_l2header() - return l2_header mapped to the index
+ * @idx: index
+ *
+ * struct map_device maps the index(count) with the device L2 header.
+ * This function returns the L2 header for the given index in case
+ * of success else -ve value.
+ */
+int shrm_get_cdev_l2header(u8 idx)
+{
+ u8 cnt;
+ for (cnt = 0; cnt < ISA_DEVICES; cnt++) {
+ if (map_dev[cnt].idx == idx)
+ return map_dev[cnt].l2_header;
+ }
+ return -EINVAL;
+}
+
+void shrm_char_reset_queues(struct shrm_dev *shrm)
+{
+ struct isadev_context *isadev;
+ struct isa_driver_context *isa_context;
+ struct queue_element *cur_msg = NULL;
+ struct list_head *cur_msg_ptr = NULL;
+ struct list_head *msg_ptr;
+ struct message_queue *q;
+ int no_dev;
+
+ dev_info(shrm->dev, "%s: Resetting char device queues\n", __func__);
+ isa_context = shrm->isa_context;
+ for (no_dev = 0 ; no_dev < ISA_DEVICES ; no_dev++) {
+ isadev = &isa_context->isadev[no_dev];
+ q = &isadev->dl_queue;
+
+ /* empty out the msg queue */
+ list_for_each_safe(cur_msg_ptr, msg_ptr, &q->msg_list) {
+ cur_msg = list_entry(cur_msg_ptr,
+ struct queue_element, entry);
+ list_del(cur_msg_ptr);
+ kfree(cur_msg);
+ }
+
+ /* reset the msg queue pointers */
+ q->size = SIZE_OF_FIFO;
+ q->readptr = 0;
+ q->writeptr = 0;
+ q->no = 0;
+ atomic_set(&q->q_rp, 0);
+ }
+}
+
+/**
+ * create_queue() - To create FIFO for Tx and Rx message buffering.
+ * @q: message queue.
+ * @devicetype: device type 0-isi,1-rpc,2-audio,3-security,
+ * 4-common_loopback, 5-audio_loopback.
+ * @shrm: pointer to the shrm device information structure
+ *
+ * This function creates a FIFO buffer of n_bytes size using
+ * dma_alloc_coherent(). It also initializes all queue handling
+ * locks, queue management pointers. It also initializes message list
+ * which occupies this queue.
+ */
+static int create_queue(struct message_queue *q, u32 devicetype,
+ struct shrm_dev *shrm)
+{
+ q->fifo_base = (u8 *)&message_fifo[devicetype];
+ q->size = SIZE_OF_FIFO;
+ q->readptr = 0;
+ q->writeptr = 0;
+ q->no = 0;
+ q->shrm = shrm;
+ spin_lock_init(&q->update_lock);
+ INIT_LIST_HEAD(&q->msg_list);
+ init_waitqueue_head(&q->wq_readable);
+ atomic_set(&q->q_rp, 0);
+
+ return 0;
+}
+
+static void delete_queue(struct message_queue *q)
+{
+ q->size = 0;
+ q->readptr = 0;
+ q->writeptr = 0;
+}
+
+/**
+ * add_msg_to_queue() - Add a message inside queue
+ * @q: message queue
+ * @size: size in bytes
+ *
+ * This function tries to allocate n_bytes of size in FIFO q.
+ * It returns negative number when no memory can be allocated
+ * currently.
+ */
+int add_msg_to_queue(struct message_queue *q, u32 size)
+{
+ struct queue_element *new_msg = NULL;
+ struct shrm_dev *shrm = q->shrm;
+
+ dev_dbg(shrm->dev, "%s IN q->writeptr=%d\n", __func__, q->writeptr);
+ new_msg = kmalloc(sizeof(struct queue_element), GFP_ATOMIC);
+ if (new_msg == NULL) {
+ dev_err(shrm->dev, "unable to allocate memory\n");
+ return -ENOMEM;
+ }
+ new_msg->offset = q->writeptr;
+ new_msg->size = size;
+ new_msg->no = q->no++;
+
+ /* check for overflow condition */
+ if (q->readptr <= q->writeptr) {
+ if (((q->writeptr-q->readptr) + size) >= q->size) {
+ dev_err(shrm->dev, "Buffer overflow !!\n");
+ BUG_ON(((q->writeptr-q->readptr) + size) >= q->size);
+ }
+ } else {
+ if ((q->writeptr + size) >= q->readptr) {
+ dev_err(shrm->dev, "Buffer overflow !!\n");
+ BUG_ON((q->writeptr + size) >= q->readptr);
+ }
+ }
+ q->writeptr = (q->writeptr + size) % q->size;
+ if (list_empty(&q->msg_list)) {
+ list_add_tail(&new_msg->entry, &q->msg_list);
+ /* There can be 2 blocking calls read and another select */
+ atomic_set(&q->q_rp, 1);
+ wake_up_interruptible(&q->wq_readable);
+ } else
+ list_add_tail(&new_msg->entry, &q->msg_list);
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return 0;
+}
+
+/**
+ * remove_msg_from_queue() - To remove a message from the msg queue.
+ * @q: message queue
+ *
+ * This function delets a message from the message list associated with message
+ * queue q and also updates read ptr.
+ * If the message list is empty, then, event is set to block the select and
+ * read calls of the paricular queue.
+ *
+ * The message list is FIFO style and message is always added to tail and
+ * removed from head.
+ */
+int remove_msg_from_queue(struct message_queue *q)
+{
+ struct queue_element *old_msg = NULL;
+ struct shrm_dev *shrm = q->shrm;
+ struct list_head *msg;
+
+ dev_dbg(shrm->dev, "%s IN q->readptr %d\n", __func__, q->readptr);
+
+ list_for_each(msg, &q->msg_list) {
+ old_msg = list_entry(msg, struct queue_element, entry);
+ if (old_msg == NULL) {
+ dev_err(shrm->dev, "no message found\n");
+ return -EFAULT;
+ }
+ break;
+ }
+ list_del(msg);
+ q->readptr = (q->readptr + old_msg->size)%q->size;
+ if (list_empty(&q->msg_list)) {
+ dev_dbg(shrm->dev, "List is empty setting RP= 0\n");
+ atomic_set(&q->q_rp, 0);
+ }
+ kfree(old_msg);
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return 0;
+}
+
+/**
+ * get_size_of_new_msg() - retrieve new message from message list
+ * @q: message queue
+ *
+ * This function will retrieve most recent message from the corresponding
+ * queue list. New message is always retrieved from head side.
+ * It returns new message no, offset if FIFO and size.
+ */
+int get_size_of_new_msg(struct message_queue *q)
+{
+ struct queue_element *new_msg = NULL;
+ struct list_head *msg_list;
+ struct shrm_dev *shrm = q->shrm;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ spin_lock_bh(&q->update_lock);
+ list_for_each(msg_list, &q->msg_list) {
+ new_msg = list_entry(msg_list, struct queue_element, entry);
+ if (new_msg == NULL) {
+ spin_unlock_bh(&q->update_lock);
+ dev_err(shrm->dev, "no message found\n");
+ return -EFAULT;
+ }
+ break;
+ }
+ spin_unlock_bh(&q->update_lock);
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return new_msg->size;
+}
+
+/**
+ * isa_select() - shrm char interface driver select interface
+ * @filp: file descriptor pointer
+ * @wait: poll_table_struct pointer
+ *
+ * This function is used to perform non-blocking read operations. It allows
+ * a process to determine whether it can read from one or more open files
+ * without blocking. These calls can also block a process until any of a
+ * given set of file descriptors becomes available for reading.
+ * If a file is ready to read, POLLIN | POLLRDNORM bitmask is returned.
+ * The driver method is called whenever the user-space program performs a select
+ * system call involving a file descriptor associated with the driver.
+ */
+static u32 isa_select(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ struct isadev_context *isadev = filp->private_data;
+ struct shrm_dev *shrm = isadev->dl_queue.shrm;
+ struct message_queue *q;
+ u32 mask = 0;
+ u32 m = iminor(filp->f_path.dentry->d_inode);
+ u8 idx = shrm_get_cdev_index(m);
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (isadev->device_id != idx)
+ return -1;
+
+ q = &isadev->dl_queue;
+ poll_wait(filp, &q->wq_readable, wait);
+ if (atomic_read(&q->q_rp) == 1)
+ mask = POLLIN | POLLRDNORM;
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return mask;
+}
+
+/**
+ * isa_read() - Read from device
+ * @filp: file descriptor
+ * @buf: user buffer pointer
+ * @len: size of requested data transfer
+ * @ppos: not used
+ *
+ * It reads a oldest message from queue and copies it into user buffer and
+ * returns its size.
+ * If there is no message present in queue, then it blocks until new data is
+ * available.
+ */
+ssize_t isa_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
+{
+ u32 size = 0;
+ int ret;
+ char *psrc;
+ struct isadev_context *isadev = (struct isadev_context *)
+ filp->private_data;
+ struct shrm_dev *shrm = isadev->dl_queue.shrm;
+ struct message_queue *q;
+ u32 msgsize;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (len <= 0)
+ return -EFAULT;
+
+ q = &isadev->dl_queue;
+ spin_lock_bh(&q->update_lock);
+
+ if (list_empty(&q->msg_list)) {
+ spin_unlock_bh(&q->update_lock);
+ dev_dbg(shrm->dev, "Waiting for Data\n");
+ if (wait_event_interruptible(q->wq_readable,
+ atomic_read(&q->q_rp) == 1))
+ return -ERESTARTSYS;
+ } else
+ spin_unlock_bh(&q->update_lock);
+ msgsize = get_size_of_new_msg(q);
+
+ if ((q->readptr+msgsize) >= q->size) {
+ dev_dbg(shrm->dev, "Inside Loop Back\n");
+ psrc = (char *)buf;
+ size = (q->size-q->readptr);
+ /* Copy First Part of msg */
+ if (copy_to_user(psrc,
+ (u8 *)(q->fifo_base+q->readptr),
+ size)) {
+ dev_err(shrm->dev, "copy_to_user failed\n");
+ return -EFAULT;
+ }
+ psrc += size;
+ /* Copy Second Part of msg at the top of fifo */
+ if (copy_to_user(psrc,
+ (u8 *)(q->fifo_base),
+ (msgsize-size))) {
+ dev_err(shrm->dev, "copy_to_user failed\n");
+ return -EFAULT;
+ }
+ } else {
+ if (copy_to_user(buf,
+ (u8 *)(q->fifo_base + q->readptr),
+ msgsize)) {
+ dev_err(shrm->dev, "copy_to_user failed\n");
+ return -EFAULT;
+ }
+ }
+ spin_lock_bh(&q->update_lock);
+ ret = remove_msg_from_queue(q);
+ if (ret < 0) {
+ dev_err(shrm->dev,
+ "Remove msg from message queue failed\n");
+ msgsize = ret;
+ }
+ spin_unlock_bh(&q->update_lock);
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return msgsize;
+}
+
+/**
+ * isa_write() - Write to shrm char device
+ * @filp: file descriptor
+ * @buf: user buffer pointer
+ * @len: size of requested data transfer
+ * @ppos: not used
+ *
+ * It checks if there is space available in queue, and copies the message
+ * inside queue. If there is no space, it blocks until space becomes available.
+ * It also schedules transfer thread to transmit the newly added message.
+ */
+ssize_t isa_write(struct file *filp, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ struct isadev_context *isadev = filp->private_data;
+ struct shrm_dev *shrm = isadev->dl_queue.shrm;
+ struct message_queue *q;
+ void *addr = 0;
+ int err, l2_header;
+ int ret = 0;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (len <= 0 || buf == NULL)
+ return -EFAULT;
+ q = &isadev->dl_queue;
+ l2_header = shrm_get_cdev_l2header(isadev->device_id);
+ if (l2_header < 0) {
+ dev_err(shrm->dev, "failed to get L2 header\n");
+ return l2_header;
+ }
+
+ switch (l2_header) {
+ case RPC_MESSAGING:
+ dev_dbg(shrm->dev, "RPC\n");
+ addr = (void *)wr_rpc_msg;
+ break;
+ case AUDIO_MESSAGING:
+ dev_dbg(shrm->dev, "Audio\n");
+ addr = (void *)wr_audio_msg;
+ break;
+ case SECURITY_MESSAGING:
+ dev_dbg(shrm->dev, "Security\n");
+ addr = (void *)wr_sec_msg;
+ break;
+ case COMMON_LOOPBACK_MESSAGING:
+ dev_dbg(shrm->dev, "Common loopback\n");
+ addr = isadev->addr;
+ break;
+ case AUDIO_LOOPBACK_MESSAGING:
+ dev_dbg(shrm->dev, "Audio loopback\n");
+ addr = isadev->addr;
+ break;
+ default:
+ dev_dbg(shrm->dev, "Wrong device\n");
+ return -EFAULT;
+ }
+
+ if (copy_from_user(addr, buf, len)) {
+ dev_err(shrm->dev, "copy_from_user failed\n");
+ return -EFAULT;
+ }
+ /* Write msg to Fifo */
+ if ((l2_header == AUDIO_MESSAGING) ||
+ (l2_header == AUDIO_LOOPBACK_MESSAGING)) {
+ mutex_lock(&shrm->isa_context->tx_audio_mutex);
+ err = shm_write_msg(shrm, l2_header, addr, len);
+ if (!err)
+ ret = len;
+ else
+ ret = err;
+ mutex_unlock(&shrm->isa_context->tx_audio_mutex);
+ } else {
+ spin_lock_bh(&shrm->isa_context->common_tx);
+ err = shm_write_msg(shrm, l2_header, addr, len);
+ if (!err)
+ ret = len;
+ else
+ ret = err;
+ spin_unlock_bh(&shrm->isa_context->common_tx);
+ }
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return ret;
+}
+
+/**
+ * isa_ioctl() - To handle different ioctl commands supported by driver.
+ * @inode: structure is used by the kernel internally to represent files
+ * @filp: file descriptor pointer
+ * @cmd: ioctl command
+ * @arg: input param
+ *
+ * Following ioctls are supported by this driver.
+ * DLP_IOCTL_ALLOCATE_BUFFER - To allocate buffer for new uplink message.
+ * This ioctl is called with required message size. It returns offset for
+ * the allocates space in the queue. DLP_IOCTL_PUT_MESSAGE - To indicate
+ * new uplink message available in queuq for transmission. Message is copied
+ * from offset location returned by previous ioctl before calling this ioctl.
+ * DLP_IOCTL_GET_MESSAGE - To check if any downlink message is available in
+ * queue. It returns offset for new message inside queue.
+ * DLP_IOCTL_DEALLOCATE_BUFFER - To deallocate any buffer allocate for
+ * downlink message once the message is copied. Message is copied from offset
+ * location returned by previous ioctl before calling this ioctl.
+ */
+static int isa_ioctl(struct inode *inode, struct file *filp,
+ unsigned cmd, unsigned long arg)
+{
+ int err = 0;
+ struct isadev_context *isadev = filp->private_data;
+ struct shrm_dev *shrm = isadev->dl_queue.shrm;
+ u32 m = iminor(inode);
+
+ isadev = (struct isadev_context *)filp->private_data;
+
+ if (isadev->device_id != m)
+ return -EINVAL;
+
+ switch (cmd) {
+ case DLP_IOC_ALLOCATE_BUFFER:
+ dev_dbg(shrm->dev, "DLP_IOC_ALLOCATE_BUFFER\n");
+ break;
+ case DLP_IOC_PUT_MESSAGE:
+ dev_dbg(shrm->dev, "DLP_IOC_PUT_MESSAGE\n");
+ break;
+ case DLP_IOC_GET_MESSAGE:
+ dev_dbg(shrm->dev, "DLP_IOC_GET_MESSAGE\n");
+ break;
+ case DLP_IOC_DEALLOCATE_BUFFER:
+ dev_dbg(shrm->dev, "DLP_IOC_DEALLOCATE_BUFFER\n");
+ break;
+ default:
+ dev_dbg(shrm->dev, "Unknown IOCTL\n");
+ err = -EFAULT;
+ break;
+ }
+ return err;
+}
+/**
+ * isa_mmap() - Maps kernel queue memory to user space.
+ * @filp: file descriptor pointer
+ * @vma: virtual area memory structure.
+ *
+ * This function maps kernel FIFO into user space. This function
+ * shall be called twice to map both uplink and downlink buffers.
+ */
+static int isa_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct isadev_context *isadev = filp->private_data;
+ struct shrm_dev *shrm = isadev->dl_queue.shrm;
+
+ u32 m = iminor(filp->f_path.dentry->d_inode);
+ dev_dbg(shrm->dev, "%s %d\n", __func__, m);
+
+ return 0;
+}
+
+/**
+ * isa_close() - Close device file
+ * @inode: structure is used by the kernel internally to represent files
+ * @filp: device file descriptor
+ *
+ * This function deletes structues associated with this file, deletes
+ * queues, flushes and destroys workqueus and closes this file.
+ * It also unregisters itself from l2mux driver.
+ */
+static int isa_close(struct inode *inode, struct file *filp)
+{
+ struct isadev_context *isadev = filp->private_data;
+ struct shrm_dev *shrm = isadev->dl_queue.shrm;
+ struct isa_driver_context *isa_context = shrm->isa_context;
+ u8 m;
+ int idx;
+
+ mutex_lock(&isa_lock);
+ m = iminor(filp->f_path.dentry->d_inode);
+ idx = shrm_get_cdev_index(m);
+ if (idx < 0) {
+ dev_err(shrm->dev, "failed to get index\n");
+ return idx;
+ }
+ dev_dbg(shrm->dev, "isa_close %d", m);
+
+ if (atomic_dec_and_test(&isa_context->is_open[idx])) {
+ atomic_inc(&isa_context->is_open[idx]);
+ dev_err(shrm->dev, "Device not opened yet\n");
+ mutex_unlock(&isa_lock);
+ return -ENODEV;
+ }
+ atomic_set(&isa_context->is_open[idx], 1);
+
+ switch (m) {
+ case RPC_MESSAGING:
+ dev_info(shrm->dev, "Close RPC_MESSAGING Device\n");
+ break;
+ case AUDIO_MESSAGING:
+ dev_info(shrm->dev, "Close AUDIO_MESSAGING Device\n");
+ break;
+ case SECURITY_MESSAGING:
+ dev_info(shrm->dev, "CLose SECURITY_MESSAGING Device\n");
+ break;
+ case COMMON_LOOPBACK_MESSAGING:
+ kfree(isadev->addr);
+ dev_info(shrm->dev, "Close COMMON_LOOPBACK_MESSAGING Device\n");
+ break;
+ case AUDIO_LOOPBACK_MESSAGING:
+ kfree(isadev->addr);
+ dev_info(shrm->dev, "Close AUDIO_LOOPBACK_MESSAGING Device\n");
+ break;
+ default:
+ dev_info(shrm->dev, "No such device present\n");
+ mutex_unlock(&isa_lock);
+ return -ENODEV;
+ };
+ mutex_unlock(&isa_lock);
+ return 0;
+}
+/**
+ * isa_open() - Open device file
+ * @inode: structure is used by the kernel internally to represent files
+ * @filp: device file descriptor
+ *
+ * This function performs initialization tasks needed to open SHM channel.
+ * Following tasks are performed.
+ * -return if device is already opened
+ * -create uplink FIFO
+ * -create downlink FIFO
+ * -init delayed workqueue thread
+ * -register to l2mux driver
+ */
+static int isa_open(struct inode *inode, struct file *filp)
+{
+ int err = 0;
+ u8 m;
+ int idx;
+ struct isadev_context *isadev;
+ struct isa_driver_context *isa_context = container_of(
+ inode->i_cdev,
+ struct isa_driver_context,
+ cdev);
+ struct shrm_dev *shrm = isa_context->isadev->dl_queue.shrm;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (get_boot_state() != BOOT_DONE) {
+ dev_err(shrm->dev, "Boot is not done\n");
+ return -EBUSY;
+ }
+ mutex_lock(&isa_lock);
+ m = iminor(inode);
+
+ if ((m != RPC_MESSAGING) &&
+ (m != AUDIO_LOOPBACK_MESSAGING) &&
+ (m != COMMON_LOOPBACK_MESSAGING) &&
+ (m != AUDIO_MESSAGING) &&
+ (m != SECURITY_MESSAGING)) {
+ dev_err(shrm->dev, "No such device present\n");
+ mutex_unlock(&isa_lock);
+ return -ENODEV;
+ }
+ idx = shrm_get_cdev_index(m);
+ if (idx < 0) {
+ dev_err(shrm->dev, "failed to get index\n");
+ return idx;
+ }
+ if (!atomic_dec_and_test(&isa_context->is_open[idx])) {
+ atomic_inc(&isa_context->is_open[idx]);
+ dev_err(shrm->dev, "Device already opened\n");
+ mutex_unlock(&isa_lock);
+ return -EBUSY;
+ }
+ isadev = &isa_context->isadev[idx];
+ if (filp != NULL)
+ filp->private_data = isadev;
+
+ switch (m) {
+ case RPC_MESSAGING:
+ dev_info(shrm->dev, "Open RPC_MESSAGING Device\n");
+ break;
+ case AUDIO_MESSAGING:
+ dev_info(shrm->dev, "Open AUDIO_MESSAGING Device\n");
+ break;
+ case SECURITY_MESSAGING:
+ dev_info(shrm->dev, "Open SECURITY_MESSAGING Device\n");
+ break;
+ case COMMON_LOOPBACK_MESSAGING:
+ isadev->addr = kzalloc(10 * 1024, GFP_KERNEL);
+ if (!isadev->addr) {
+ mutex_unlock(&isa_lock);
+ return -ENOMEM;
+ }
+ dev_info(shrm->dev, "Open COMMON_LOOPBACK_MESSAGING Device\n");
+ break;
+ case AUDIO_LOOPBACK_MESSAGING:
+ isadev->addr = kzalloc(10 * 1024, GFP_KERNEL);
+ if (!isadev->addr) {
+ mutex_unlock(&isa_lock);
+ return -ENOMEM;
+ }
+ dev_info(shrm->dev, "Open AUDIO_LOOPBACK_MESSAGING Device\n");
+ break;
+ };
+
+ mutex_unlock(&isa_lock);
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return err;
+}
+
+const struct file_operations isa_fops = {
+ .owner = THIS_MODULE,
+ .open = isa_open,
+ .release = isa_close,
+ .ioctl = isa_ioctl,
+ .mmap = isa_mmap,
+ .read = isa_read,
+ .write = isa_write,
+ .poll = isa_select,
+};
+
+/**
+ * isa_init() - module insertion function
+ * @shrm: pointer to the shrm device information structure
+ *
+ * This function registers module as a character driver using
+ * register_chrdev_region() or alloc_chrdev_region. It adds this
+ * driver to system using cdev_add() call. Major number is dynamically
+ * allocated using alloc_chrdev_region() by default or left to user to specify
+ * it during load time. For this variable major is used as module_param
+ * Nodes to be created using
+ * mknod /dev/isi c $major 0
+ * mknod /dev/rpc c $major 1
+ * mknod /dev/audio c $major 2
+ * mknod /dev/sec c $major 3
+ */
+int isa_init(struct shrm_dev *shrm)
+{
+ dev_t dev_id;
+ int retval, no_dev;
+ struct isadev_context *isadev;
+ struct isa_driver_context *isa_context;
+
+ isa_context = kzalloc(sizeof(struct isa_driver_context),
+ GFP_KERNEL);
+ if (isa_context == NULL) {
+ dev_err(shrm->dev, "Failed to alloc memory\n");
+ return -ENOMEM;
+ }
+ shrm->isa_context = isa_context;
+ if (major) {
+ dev_id = MKDEV(major, MAX_L2_HEADERS);
+ retval = register_chrdev_region(dev_id, ISA_DEVICES, NAME);
+ } else {
+ /*
+ * L2 header of loopback device is 192(0xc0). As per the shrm
+ * protocol the minor id of the deivce is mapped to the
+ * L2 header.
+ */
+ retval = alloc_chrdev_region(&dev_id, 0, MAX_L2_HEADERS, NAME);
+ major = MAJOR(dev_id);
+ }
+ dev_dbg(shrm->dev, " major %d\n", major);
+
+ cdev_init(&isa_context->cdev, &isa_fops);
+ isa_context->cdev.owner = THIS_MODULE;
+ retval = cdev_add(&isa_context->cdev, dev_id, MAX_L2_HEADERS);
+ if (retval) {
+ dev_err(shrm->dev, "Failed to add char device\n");
+ return retval;
+ }
+ /* create class and device */
+ isa_context->shm_class = class_create(THIS_MODULE, NAME);
+ if (IS_ERR(isa_context->shm_class)) {
+ dev_err(shrm->dev, "Error creating shrm class\n");
+ cdev_del(&isa_context->cdev);
+ retval = PTR_ERR(isa_context->shm_class);
+ kfree(isa_context);
+ return retval;
+ }
+
+ for (no_dev = 0; no_dev < ISA_DEVICES; no_dev++) {
+ atomic_set(&isa_context->is_open[no_dev], 1);
+ device_create(isa_context->shm_class, NULL,
+ MKDEV(MAJOR(dev_id),
+ map_dev[no_dev].l2_header), NULL,
+ map_dev[no_dev].name);
+ }
+
+ isa_context->isadev = kzalloc(sizeof
+ (struct isadev_context)*ISA_DEVICES,
+ GFP_KERNEL);
+ if (isa_context->isadev == NULL) {
+ dev_err(shrm->dev, "Failed to alloc memory\n");
+ return -ENOMEM;
+ }
+ for (no_dev = 0 ; no_dev < ISA_DEVICES ; no_dev++) {
+ isadev = &isa_context->isadev[no_dev];
+ isadev->device_id = no_dev;
+ retval = create_queue(&isadev->dl_queue,
+ isadev->device_id, shrm);
+
+ if (retval < 0) {
+ dev_err(shrm->dev, "create dl_queue failed\n");
+ delete_queue(&isadev->dl_queue);
+ kfree(isadev);
+ return retval;
+ }
+ }
+ mutex_init(&isa_context->tx_audio_mutex);
+ spin_lock_init(&isa_context->common_tx);
+ dev_dbg(shrm->dev, " SHM Char Driver added\n");
+ return retval;
+}
+
+void isa_exit(struct shrm_dev *shrm)
+{
+ int no_dev;
+ struct isadev_context *isadev;
+ struct isa_driver_context *isa_context = shrm->isa_context;
+ dev_t dev_id = MKDEV(major, 0);
+
+ for (no_dev = 0 ; no_dev < ISA_DEVICES ; no_dev++) {
+ device_destroy(isa_context->shm_class,
+ MKDEV(MAJOR(dev_id),
+ map_dev[no_dev].l2_header));
+ isadev = &isa_context->isadev[no_dev];
+ delete_queue(&isadev->dl_queue);
+ kfree(isadev);
+ }
+ class_destroy(isa_context->shm_class);
+ cdev_del(&isa_context->cdev);
+ unregister_chrdev_region(dev_id, ISA_DEVICES);
+ kfree(isa_context);
+ dev_dbg(shrm->dev, " SHM Char Driver removed\n");
+}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 507441ac6ed..900e3264480 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -3149,4 +3149,3 @@ int __init tty_init(void)
#endif
return 0;
}
-
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index fbf94cf496f..f1058449caa 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -243,4 +243,14 @@ config CRYPTO_DEV_OMAP_SHAM
OMAP processors have SHA1/MD5 hw accelerator. Select this if you
want to use the OMAP module for SHA1/MD5 algorithms.
+config CRYPTO_DEV_UX500
+ tristate "Driver for ST-Ericsson UX500 crypto hardware acceleration"
+ #depends on ARCH_U8500
+ select CRYPTO_ALGAPI
+ help
+ Driver for ST-Ericsson UX500 crypto engine.
+
+if CRYPTO_DEV_UX500
+ source "drivers/crypto/ux500/Kconfig"
+endif # if CRYPTO_DEV_UX500
endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 6dbbe00c452..7aeb5604454 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -9,4 +9,4 @@ obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
-
+obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
diff --git a/drivers/crypto/ux500/Kconfig b/drivers/crypto/ux500/Kconfig
new file mode 100755
index 00000000000..4ac419757d0
--- /dev/null
+++ b/drivers/crypto/ux500/Kconfig
@@ -0,0 +1,15 @@
+
+config CRYPTO_DEV_UX500_HASH
+ tristate "UX500 crypto driver for HASH block"
+ depends on ARCH_U8500
+ select CRYPTO_ALGAPI
+ select CRYPTO_HASH
+ select CRYPTO_HMAC
+ help
+ This selects the UX500 hash driver for the HASH hardware.
+ Depends on U8500/STM DMA if running in DMA mode.
+
+config CRYPTO_DEV_UX500_DEBUG_INFO
+ tristate "Enable UX500 crypto drivers debug info"
+ help
+ This is to enable the debug info for UX500 crypto drivers.
diff --git a/drivers/crypto/ux500/Makefile b/drivers/crypto/ux500/Makefile
new file mode 100755
index 00000000000..4c187857120
--- /dev/null
+++ b/drivers/crypto/ux500/Makefile
@@ -0,0 +1,11 @@
+
+ifeq ($(CONFIG_CRYPTO_DEV_UX500_DEBUG_INFO),y)
+ EXTRA_CFLAGS += -D__DEBUG
+else
+ EXTRA_CFLAGS += -D__RELEASE
+endif
+
+obj-$(CONFIG_CRYPTO_DEV_UX500_HASH) += hash/
+
+
+
diff --git a/drivers/crypto/ux500/hash/Makefile b/drivers/crypto/ux500/hash/Makefile
new file mode 100755
index 00000000000..613330a4ca4
--- /dev/null
+++ b/drivers/crypto/ux500/hash/Makefile
@@ -0,0 +1,9 @@
+
+ifeq ($(CONFIG_CRYPTO_DEV_UX500_DEBUG_INFO),y)
+ EXTRA_CFLAGS += -D__DEBUG
+else
+ EXTRA_CFLAGS += -D__RELEASE
+endif
+
+obj-$(CONFIG_CRYPTO_DEV_UX500_HASH) += u8500_hash.o
+u8500_hash-objs := hash_core.o
diff --git a/drivers/crypto/ux500/hash/hash_alg.h b/drivers/crypto/ux500/hash/hash_alg.h
new file mode 100755
index 00000000000..e1f7c2eb60b
--- /dev/null
+++ b/drivers/crypto/ux500/hash/hash_alg.h
@@ -0,0 +1,476 @@
+#ifndef _HASH_ALG_H
+#define _HASH_ALG_H
+/*
+ * Copyright (C) 2010 ST-Ericsson.
+ * Copyright (C) 2010 STMicroelectronics.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <mach/hcl_defs.h>
+
+/* Number of bytes the message digest */
+#define HASH_MSG_DIGEST_SIZE 32
+#define HASH_BLOCK_SIZE 64
+
+#define __HASH_ENHANCED
+
+/* Version defines */
+#define HASH_HCL_VERSION_ID 1
+#define HASH_HCL_MAJOR_ID 2
+#define HASH_HCL_MINOR_ID 1
+
+#define MAX_HASH_DEVICE 2
+
+/* Maximum value of the length's high word */
+#define HASH_HIGH_WORD_MAX_VAL 0xFFFFFFFFUL
+
+/* Power on Reset values HASH registers */
+#define HASH_RESET_CONTROL_REG_VALUE 0x0
+#define HASH_RESET_START_REG_VALUE 0x0
+
+/* Number of context swap registers */
+#define HASH_CSR_COUNT 52
+
+#define HASH_RESET_CSRX_REG_VALUE 0x0
+#define HASH_RESET_CSFULL_REG_VALUE 0x0
+#define HASH_RESET_CSDATAIN_REG_VALUE 0x0
+
+#define HASH_RESET_INDEX_VAL 0x0
+#define HASH_RESET_BIT_INDEX_VAL 0x0
+#define HASH_RESET_BUFFER_VAL 0x0
+#define HASH_RESET_LEN_HIGH_VAL 0x0
+#define HASH_RESET_LEN_LOW_VAL 0x0
+
+/* Control register bitfields */
+#define HASH_CR_RESUME_MASK 0x11FCF
+
+#define HASH_CR_SWITCHON_POS 31
+#define HASH_CR_SWITCHON_MASK MASK_BIT31
+
+#define HASH_CR_EMPTYMSG_POS 20
+#define HASH_CR_EMPTYMSG_MASK MASK_BIT20
+
+#define HASH_CR_DINF_POS 12
+#define HASH_CR_DINF_MASK MASK_BIT12
+
+#define HASH_CR_NBW_POS 8
+#define HASH_CR_NBW_MASK 0x00000F00UL
+
+#define HASH_CR_LKEY_POS 16
+#define HASH_CR_LKEY_MASK MASK_BIT16
+
+#define HASH_CR_ALGO_POS 7
+#define HASH_CR_ALGO_MASK MASK_BIT7
+
+#define HASH_CR_MODE_POS 6
+#define HASH_CR_MODE_MASK MASK_BIT6
+
+#define HASH_CR_DATAFORM_POS 4
+#define HASH_CR_DATAFORM_MASK (MASK_BIT4 | MASK_BIT5)
+
+#define HASH_CR_DMAE_POS 3
+#define HASH_CR_DMAE_MASK MASK_BIT3
+
+#define HASH_CR_INIT_POS 2
+#define HASH_CR_INIT_MASK MASK_BIT2
+
+#define HASH_CR_PRIVN_POS 1
+#define HASH_CR_PRIVN_MASK MASK_BIT1
+
+#define HASH_CR_SECN_POS 0
+#define HASH_CR_SECN_MASK MASK_BIT0
+
+/* Start register bitfields */
+#define HASH_STR_DCAL_POS 8
+#define HASH_STR_DCAL_MASK MASK_BIT8
+
+#define HASH_STR_NBLW_POS 0
+#define HASH_STR_NBLW_MASK 0x0000001FUL
+
+#define HASH_NBLW_MAX_VAL 0x1F
+
+/* PrimeCell IDs */
+#define HASH_P_ID0 0xE0
+#define HASH_P_ID1 0x05
+#define HASH_P_ID2 0x38
+#define HASH_P_ID3 0x00
+#define HASH_CELL_ID0 0x0D
+#define HASH_CELL_ID1 0xF0
+#define HASH_CELL_ID2 0x05
+#define HASH_CELL_ID3 0xB1
+
+#define HASH_SET_DIN(val) HCL_WRITE_REG(g_sys_ctx.registry[hid]->din, (val))
+
+#define HASH_INITIALIZE \
+ HCL_WRITE_BITS( \
+ g_sys_ctx.registry[hid]->cr, \
+ 0x01 << HASH_CR_INIT_POS, \
+ HASH_CR_INIT_MASK)
+
+#define HASH_SET_DATA_FORMAT(data_format) \
+ HCL_WRITE_BITS( \
+ g_sys_ctx.registry[hid]->cr, \
+ (u32) (data_format) << HASH_CR_DATAFORM_POS, \
+ HASH_CR_DATAFORM_MASK)
+
+#define HASH_GET_HX(pos) \
+ HCL_READ_REG(g_sys_ctx.registry[hid]->hx[pos])
+
+#define HASH_SET_HX(pos, val) \
+ HCL_WRITE_REG(g_sys_ctx.registry[hid]->hx[pos], (val));
+
+#define HASH_SET_NBLW(val) \
+ HCL_WRITE_BITS( \
+ g_sys_ctx.registry[hid]->str, \
+ (u32) (val) << HASH_STR_NBLW_POS, \
+ HASH_STR_NBLW_MASK)
+
+#define HASH_SET_DCAL \
+ HCL_WRITE_BITS( \
+ g_sys_ctx.registry[hid]->str, \
+ 0x01 << HASH_STR_DCAL_POS, \
+ HASH_STR_DCAL_MASK)
+
+/**
+ * struct uint64 - Structure to handle 64 bits integers.
+ * @high_word: Most significant bits
+ * @high_word: Least significant bits
+ *
+ * Used to handle 64 bits integers.
+ */
+struct uint64 {
+ u32 high_word;
+ u32 low_word;
+};
+
+/**
+ * struct hash_register - Contains all registers in u8500 hash hardware.
+ * @cr: HASH control register (0x000)
+ * @din: HASH data input register (0x004)
+ * @str: HASH start register (0x008)
+ * @hx: HASH digest register 0..7 (0x00c-0x01C)
+ * @padding0: Reserved (0x02C)
+ * @itcr: Integration test control register (0x080)
+ * @itip: Integration test input register (0x084)
+ * @itop: Integration test output register (0x088)
+ * @padding1: Reserved (0x08C)
+ * @csfull: HASH context full register (0x0F8)
+ * @csdatain: HASH context swap data input register (0x0FC)
+ * @csrx: HASH context swap register 0..51 (0x100-0x1CC)
+ * @padding2: Reserved (0x1D0)
+ * @periphid0: HASH peripheral identification register 0 (0xFE0)
+ * @periphid1: HASH peripheral identification register 1 (0xFE4)
+ * @periphid2: HASH peripheral identification register 2 (0xFE8)
+ * @periphid3: HASH peripheral identification register 3 (0xFEC)
+ * @cellid0: HASH PCell identification register 0 (0xFF0)
+ * @cellid1: HASH PCell identification register 1 (0xFF4)
+ * @cellid2: HASH PCell identification register 2 (0xFF8)
+ * @cellid3: HASH PCell identification register 3 (0xFFC)
+ *
+ * The device communicates to the HASH via 32-bit-wide control registers
+ * accessible via the 32-bit width AMBA rev. 2.0 AHB Bus. Below is a structure
+ * with the registers used.
+ */
+struct hash_register {
+ u32 cr;
+ u32 din;
+ u32 str;
+ u32 hx[8];
+
+ u32 padding0[(0x080 - 0x02C) >> 2];
+
+ u32 itcr;
+ u32 itip;
+ u32 itop;
+
+ u32 padding1[(0x0F8 - 0x08C) >> 2];
+
+ u32 csfull;
+ u32 csdatain;
+ u32 csrx[HASH_CSR_COUNT];
+
+ u32 padding2[(0xFE0 - 0x1D0) >> 2];
+
+ u32 periphid0;
+ u32 periphid1;
+ u32 periphid2;
+ u32 periphid3;
+
+ u32 cellid0;
+ u32 cellid1;
+ u32 cellid2;
+ u32 cellid3;
+};
+
+/**
+ * struct hash_state - Hash context state.
+ * @temp_cr: Temporary HASH Control Register
+ * @str_reg: HASH Start Register
+ * @din_reg: HASH Data Input Register
+ * @csr[52]: HASH Context Swap Registers 0-39
+ * @csfull: HASH Context Swap Registers 40 ie Status flags
+ * @csdatain: HASH Context Swap Registers 41 ie Input data
+ * @buffer: Working buffer for messages going to the hardware
+ * @length: Length of the part of the message hashed so far (floor(N/64) * 64)
+ * @index: Valid number of bytes in buffer (N % 64)
+ * @bit_index: Valid number of bits in buffer (N % 8)
+ *
+ * This structure is used between context switches, i.e. when ongoing jobs are
+ * interupted with new jobs. When this happens we need to store intermediate
+ * results in software.
+ *
+ * WARNING: "index" is the member of the structure, to be sure that "buffer"
+ * is aligned on a 4-bytes boundary. This is highly implementation dependent
+ * and MUST be checked whenever this code is ported on new platforms.
+ */
+struct hash_state {
+ u32 temp_cr;
+ u32 str_reg;
+ u32 din_reg;
+ u32 csr[52];
+ u32 csfull;
+ u32 csdatain;
+ u32 buffer[HASH_BLOCK_SIZE / sizeof(u32)];
+ struct uint64 length;
+ u8 index;
+ u8 bit_index;
+};
+
+/**
+ * struct hash_system_context - Structure for the global system context.
+ * @registry: Pointer to the registry of the hash hardware
+ * @state: State of the hash device
+ */
+struct hash_system_context {
+ /* Pointer to HASH registers structure */
+ volatile struct hash_register *registry[MAX_HASH_DEVICE];
+
+ /* State of HASH device */
+ struct hash_state state[MAX_HASH_DEVICE];
+};
+
+/**
+ * enum hash_device_id - HASH device ID.
+ * @HASH_DEVICE_ID_0: Hash hardware with ID 0
+ * @HASH_DEVICE_ID_1: Hash hardware with ID 1
+ */
+enum hash_device_id {
+ HASH_DEVICE_ID_0 = 0,
+ HASH_DEVICE_ID_1 = 1
+};
+
+/**
+ * enum hash_data_format - HASH data format.
+ * @HASH_DATA_32_BITS: 32 bits data format
+ * @HASH_DATA_16_BITS: 16 bits data format
+ * @HASH_DATA_8_BITS: 8 bits data format
+ * @HASH_DATA_1_BITS: 1 bit data format
+ */
+enum hash_data_format {
+ HASH_DATA_32_BITS = 0x0,
+ HASH_DATA_16_BITS = 0x1,
+ HASH_DATA_8_BITS = 0x2,
+ HASH_DATA_1_BIT = 0x3
+};
+
+/**
+ * enum hash_device_state - Device state
+ * @DISABLE: Disable the hash hardware
+ * @ENABLE: Enable the hash hardware
+ */
+enum hash_device_state {
+ DISABLE = 0,
+ ENABLE = 1
+};
+
+/**
+ * struct hash_protection_config - Device protection configuration.
+ * @privilege_access: FIXME, add comment.
+ * @secure_access: FIXME, add comment.
+ */
+struct hash_protection_config {
+ int privilege_access;
+ int secure_access;
+};
+
+/**
+ * enum hash_input_status - Data Input flag status.
+ * @HASH_DIN_EMPTY: Indicates that nothing is in data registers
+ * @HASH_DIN_FULL: Indicates that data registers are full
+ */
+enum hash_input_status {
+ HASH_DIN_EMPTY = 0,
+ HASH_DIN_FULL = 1
+};
+
+/**
+ * Number of words already pushed
+ */
+enum hash_nbw_pushed {
+ HASH_NBW_00 = 0x00,
+ HASH_NBW_01 = 0x01,
+ HASH_NBW_02 = 0x02,
+ HASH_NBW_03 = 0x03,
+ HASH_NBW_04 = 0x04,
+ HASH_NBW_05 = 0x05,
+ HASH_NBW_06 = 0x06,
+ HASH_NBW_07 = 0x07,
+ HASH_NBW_08 = 0x08,
+ HASH_NBW_09 = 0x09,
+ HASH_NBW_10 = 0x0A,
+ HASH_NBW_11 = 0x0B,
+ HASH_NBW_12 = 0x0C,
+ HASH_NBW_13 = 0x0D,
+ HASH_NBW_14 = 0x0E,
+ HASH_NBW_15 = 0x0F
+};
+
+/**
+ * struct hash_device_status - Device status for DINF, NBW, and NBLW bit
+ * fields.
+ * @dinf_status: HASH data in full flag
+ * @nbw_status: Number of words already pushed
+ * @nblw_status: Number of Valid Bits Last Word of the Message
+ */
+struct hash_device_status {
+ int dinf_status;
+ int nbw_status;
+ u8 nblw_status;
+};
+
+/**
+ * enum hash_dma_request - Enumeration for HASH DMA request types.
+ */
+enum hash_dma_request {
+ HASH_DISABLE_DMA_REQ = 0x0,
+ HASH_ENABLE_DMA_REQ = 0x1
+};
+
+/**
+ * enum hash_digest_cal - Enumeration for digest calculation.
+ * @HASH_DISABLE_DCAL: Indicates that DCAL bit is not set/used.
+ * @HASH_ENABLE_DCAL: Indicates that DCAL bit is set/used.
+ */
+enum hash_digest_cal {
+ HASH_DISABLE_DCAL = 0x0,
+ HASH_ENABLE_DCAL = 0x1
+};
+
+/**
+ * enum hash_algo - Enumeration for selecting between SHA1 or SHA2 algorithm
+ * @HASH_ALGO_SHA1: Indicates that SHA1 is used.
+ * @HASH_ALGO_SHA2: Indicates that SHA2 (SHA256) is used.
+ */
+enum hash_algo {
+ HASH_ALGO_SHA1 = 0x0,
+ HASH_ALGO_SHA2 = 0x1
+};
+
+/**
+ * enum hash_op - Enumeration for selecting between HASH or HMAC mode
+ * @HASH_OPER_MODE_HASH: Indicates usage of normal HASH mode
+ * @HASH_OPER_MODE_HMAC: Indicates usage of HMAC
+ */
+enum hash_op {
+ HASH_OPER_MODE_HASH = 0x0,
+ HASH_OPER_MODE_HMAC = 0x1
+};
+
+/**
+ * enum hash_key_type - Enumeration for selecting between long and short key.
+ * @HASH_SHORT_KEY: Key used is shorter or equal to block size (64 bytes)
+ * @HASH_LONG_KEY: Key used is greater than block size (64 bytes)
+ */
+enum hash_key_type {
+ HASH_SHORT_KEY = 0x0,
+ HASH_LONG_KEY = 0x1
+};
+
+/**
+ * struct hash_config - Configuration data for the hardware
+ * @data_format: Format of data entered into the hash data in register
+ * @algorithm: Algorithm selection bit
+ * @oper_mode: Operating mode selection bit
+ * @hmac_key: Long key selection bit HMAC mode
+ */
+struct hash_config {
+ int data_format;
+ int algorithm;
+ int oper_mode;
+ int hmac_key;
+};
+
+
+/**
+ * enum hash_error - Error codes for hash.
+ */
+enum hash_error {
+ HASH_OK = 0,
+ HASH_MSG_LENGTH_OVERFLOW,
+ HASH_INTERNAL_ERROR,
+ HASH_NOT_CONFIGURED,
+ HASH_REQUEST_PENDING,
+ HASH_REQUEST_NOT_APPLICABLE,
+ HASH_INVALID_PARAMETER,
+ HASH_UNSUPPORTED_FEATURE,
+ HASH_UNSUPPORTED_HW
+};
+
+int hash_init_base_address(int hash_device_id, t_logical_address base_address);
+
+int HASH_GetVersion(t_version *p_version);
+
+int HASH_Reset(int hash_devive_id);
+
+int HASH_ConfigureDmaRequest(int hash_device_id, int request_state);
+
+int HASH_ConfigureLastValidBits(int hash_device_id, u8 nblw_val);
+
+int HASH_ConfigureDigestCal(int hash_device_id, int dcal_state);
+
+int HASH_ConfigureProtection(int hash_device_id,
+ struct hash_protection_config
+ *p_protect_config);
+
+int hash_setconfiguration(int hash_device_id, struct hash_config *p_config);
+
+int hash_begin(int hash_device_id);
+
+int hash_get_digest(int hash_device_id, u8 digest[HASH_MSG_DIGEST_SIZE]);
+
+int HASH_ClockGatingOff(int hash_device_id);
+
+struct hash_device_status HASH_GetDeviceStatus(int hash_device_id);
+
+t_bool HASH_IsDcalOngoing(int hash_device_id);
+
+int hash_hw_update(int hash_device_id,
+ const u8 *p_data_buffer,
+ u32 msg_length);
+
+int hash_end(int hash_device_id, u8 digest[HASH_MSG_DIGEST_SIZE]);
+
+int hash_compute(int hash_device_id,
+ const u8 *p_data_buffer,
+ u32 msg_length,
+ struct hash_config *p_hash_config,
+ u8 digest[HASH_MSG_DIGEST_SIZE]);
+
+int hash_end_key(int hash_device_id);
+
+int hash_save_state(int hash_device_id, struct hash_state *state);
+
+int hash_resume_state(int hash_device_id, const struct hash_state *state);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/drivers/crypto/ux500/hash/hash_alg_p.h b/drivers/crypto/ux500/hash/hash_alg_p.h
new file mode 100755
index 00000000000..c85faaeba6f
--- /dev/null
+++ b/drivers/crypto/ux500/hash/hash_alg_p.h
@@ -0,0 +1,26 @@
+/*****************************************************************************/
+/**
+* � ST-Ericsson, 2009 - All rights reserved
+* Reproduction and Communication of this document is strictly prohibited
+* unless specifically authorized in writing by ST-Ericsson
+*
+* static Header file of HASH Processor
+* Specification release related to this implementation: A_V2.2
+* AUTHOR : ST-Ericsson
+*/
+/*****************************************************************************/
+
+#ifndef _HASH_P_H_
+#define _HASH_P_H_
+
+/*--------------------------------------------------------------------------*
+ * Includes *
+ *--------------------------------------------------------------------------*/
+#include "hash_alg.h"
+
+/*--------------------------------------------------------------------------*
+ * Defines *
+ *--------------------------------------------------------------------------*/
+
+#endif /* End _HASH_P_H_ */
+
diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c
new file mode 100755
index 00000000000..fd5f8a870bf
--- /dev/null
+++ b/drivers/crypto/ux500/hash/hash_core.c
@@ -0,0 +1,1756 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for Nomadik hardware crypto engine.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#include <linux/crypto.h>
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+
+#include <mach/debug.h>
+#include <mach/hardware.h>
+
+#include "hash_alg.h"
+
+#define DRIVER_NAME "DRIVER HASH"
+/* enables/disables debug msgs */
+#define DRIVER_DEBUG 1
+#define DRIVER_DEBUG_PFX DRIVER_NAME
+#define DRIVER_DBG KERN_ERR
+
+#define MAX_HASH_DIGEST_BYTE_SIZE 32
+#define HASH_BLOCK_BYTE_SIZE 64
+
+#define HASH_ACC_SYNC_CONTROL
+#ifdef HASH_ACC_SYNC_CONTROL
+static struct mutex hash_hw_acc_mutex;
+#endif
+
+int debug;
+static int mode;
+static int contextsaving;
+static struct hash_system_context g_sys_ctx;
+
+/**
+ * struct hash_driver_data - IO Base and clock.
+ * @base: The IO base for the block
+ * @clk: FIXME, add comment
+ */
+struct hash_driver_data {
+ void __iomem *base;
+ struct clk *clk;
+};
+
+/**
+ * struct hash_ctx - The context used for hash calculations.
+ * @key: The key used in the operation
+ * @keylen: The length of the key
+ * @updated: Indicates if hardware is initialized for new operations
+ * @state: The state of the current calculations
+ * @config: The current configuration
+ */
+struct hash_ctx {
+ u8 key[HASH_BLOCK_BYTE_SIZE];
+ u32 keylen;
+ u8 updated;
+ struct hash_state state;
+ struct hash_config config;
+};
+
+/**
+ * struct hash_tfm_ctx - Transform context
+ * @key: The key stored in the transform context
+ * @keylen: The length of the key in the transform context
+ */
+struct hash_tfm_ctx {
+ u8 key[HASH_BLOCK_BYTE_SIZE];
+ u32 keylen;
+};
+
+/* Declaration of functions */
+static void hash_messagepad(int hid, const u32 *message, u8 index_bytes);
+
+/**
+ * hexdump - Dumps buffers in hex.
+ * @buf: The buffer to dump
+ * @len: The length of the buffer
+ */
+static void hexdump(unsigned char *buf, unsigned int len)
+{
+ print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
+ 16, 1, buf, len, false);
+}
+
+/**
+ * clear_reg_str - Clear the registry hash_str.
+ * @hid: Hardware device ID
+ *
+ * This function will clear the dcal bit and the nblw bits.
+ */
+static inline void clear_reg_str(int hid)
+{
+ /* We will only clear the valid registers and not the reserved */
+ g_sys_ctx.registry[hid]->str &= ~HASH_STR_DCAL_MASK;
+ g_sys_ctx.registry[hid]->str &= ~HASH_STR_NBLW_MASK;
+}
+
+/**
+ * write_nblw - Writes the number of valid bytes to nblw.
+ * @hid: Hardware device ID
+ * @bytes: The number of valid bytes in last word of a message
+ *
+ * Note that this function only writes, i.e. it does not clear the registry
+ * before it writes the new data.
+ */
+static inline void write_nblw(int hid, int bytes)
+{
+ g_sys_ctx.registry[hid]->str |=
+ ((bytes * 8) & HASH_STR_NBLW_MASK);
+}
+
+/**
+ * write_dcal - Write/set the dcal bit.
+ * @hid: Hardware device ID
+ */
+static inline void write_dcal(int hid)
+{
+ g_sys_ctx.registry[hid]->str |= (1 << HASH_STR_DCAL_POS);
+}
+
+/**
+ * pad_message - Function that pads a message.
+ * @hid: Hardware device ID
+ *
+ * FIXME: This function should be replaced.
+ */
+static inline void pad_message(int hid)
+{
+ hash_messagepad(hid, g_sys_ctx.state[hid].buffer,
+ g_sys_ctx.state[hid].index);
+}
+
+/**
+ * write_key - Writes the key to the hardware registries.
+ * @hid: Hardware device ID
+ * @key: The key used in the operation
+ * @keylen: The length of the key
+ *
+ * Note that in this function we DO NOT write to the NBLW registry even though
+ * the hardware reference manual says so. There must be incorrect information in
+ * the manual or there must be a bug in the state machine in the hardware.
+ */
+static void write_key(int hid, const u8 *key, u32 keylen)
+{
+ u32 word = 0;
+ clear_reg_str(hid);
+
+ while (keylen >= 4) {
+ word = ((u32) (key[3] & 255) << 24) |
+ ((u32) (key[2] & 255) << 16) |
+ ((u32) (key[1] & 255) << 8) |
+ ((u32) (key[0] & 255));
+
+ HASH_SET_DIN(word);
+ keylen -= 4;
+ key += 4;
+ }
+
+ /* This takes care of the remaining bytes on the last word */
+ if (keylen) {
+ word = 0;
+ while (keylen) {
+ word |= (key[keylen - 1] << (8 * (keylen - 1)));
+ keylen--;
+ }
+ HASH_SET_DIN(word);
+ }
+
+ write_dcal(hid);
+}
+
+/**
+ * init_hash_hw - Initialise the hash hardware for a new calculation.
+ * @desc: The hash descriptor for the job
+ *
+ * This function will enable the bits needed to clear and start a new
+ * calculation.
+ */
+static int init_hash_hw(struct shash_desc *desc)
+{
+ int ret = 0;
+ int hash_error = HASH_OK;
+ struct hash_ctx *ctx = shash_desc_ctx(desc);
+
+ stm_dbg(debug, "[init_hash_hw] (ctx=0x%x)!", (u32)ctx);
+
+ hash_error = hash_setconfiguration(HASH_DEVICE_ID_1, &ctx->config);
+ if (hash_error != HASH_OK) {
+ stm_error("hash_setconfiguration() failed!");
+ ret = -1;
+ goto out;
+ }
+
+ hash_error = hash_begin(HASH_DEVICE_ID_1);
+ if (hash_error != HASH_OK) {
+ stm_error("hash_begin() failed!");
+ ret = -1;
+ goto out;
+ }
+
+ if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC) {
+ stm_dbg(debug, "[init_hash_hw] update key=0x%0x, len=%d",
+ (u32) ctx->key, ctx->keylen);
+ write_key(HASH_DEVICE_ID_1, ctx->key, ctx->keylen);
+ }
+
+out:
+ return ret;
+}
+
+/**
+ * hash_init - Common hash init function for SHA1/SHA2 (SHA256).
+ * @desc: The hash descriptor for the job
+ *
+ * Initialize structures and copy the key from the transform context to the
+ * descriptor context if the mode is HMAC.
+ */
+static int hash_init(struct shash_desc *desc)
+{
+ struct hash_ctx *ctx = shash_desc_ctx(desc);
+ struct hash_tfm_ctx *tfm_ctx = crypto_tfm_ctx(&desc->tfm->base);
+
+ stm_dbg(debug, "[hash_init]: (ctx=0x%x)!", (u32)ctx);
+
+ if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC) {
+ if (tfm_ctx->key) {
+ memcpy(ctx->key, tfm_ctx->key, tfm_ctx->keylen);
+ ctx->keylen = tfm_ctx->keylen;
+ }
+ }
+
+ memset(&ctx->state, 0, sizeof(struct hash_state));
+ ctx->updated = 0;
+
+ return 0;
+}
+
+/**
+ * hash_update - The hash update function for SHA1/SHA2 (SHA256).
+ * @desc: The hash descriptor for the job
+ * @data: Message that should be hashed
+ * @len: The length of the message that should be hashed
+ */
+static int hash_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ int ret = 0;
+ int hash_error = HASH_OK;
+ struct hash_ctx *ctx = shash_desc_ctx(desc);
+
+ stm_dbg(debug, "[hash_update]: (ctx=0x%x, data=0x%x, len=%d)!",
+ (u32)ctx, (u32)data, len);
+
+#ifdef HASH_ACC_SYNC_CONTROL
+ mutex_lock(&hash_hw_acc_mutex);
+#endif
+
+ if (!ctx->updated) {
+ ret = init_hash_hw(desc);
+ if (ret) {
+ stm_error("init_hash_hw() failed!");
+ goto out;
+ }
+ }
+
+ if (contextsaving) {
+ if (ctx->updated) {
+ hash_error =
+ hash_resume_state(HASH_DEVICE_ID_1, &ctx->state);
+ if (hash_error != HASH_OK) {
+ stm_error("hash_resume_state() failed!");
+ ret = -1;
+ goto out;
+ }
+ }
+ }
+
+ /* NOTE: The length of the message is in the form of number of bits */
+ hash_error = hash_hw_update(HASH_DEVICE_ID_1, data, len * 8);
+ if (hash_error != HASH_OK) {
+ stm_error("hash_hw_update() failed!");
+ ret = -1;
+ goto out;
+ }
+
+ if (contextsaving) {
+ hash_error =
+ hash_save_state(HASH_DEVICE_ID_1, &ctx->state);
+ if (hash_error != HASH_OK) {
+ stm_error("hash_save_state() failed!");
+ ret = -1;
+ goto out;
+ }
+
+ }
+ ctx->updated = 1;
+
+out:
+#ifdef HASH_ACC_SYNC_CONTROL
+ mutex_unlock(&hash_hw_acc_mutex);
+#endif
+ return ret;
+}
+
+/**
+ * hash_final - The hash final function for SHA1/SHA2 (SHA256).
+ * @desc: The hash descriptor for the job
+ * @out: Pointer for the calculated digest
+ */
+static int hash_final(struct shash_desc *desc, u8 *out)
+{
+ int ret = 0;
+ int hash_error = HASH_OK;
+ struct hash_ctx *ctx = shash_desc_ctx(desc);
+
+ int digestsize = crypto_shash_digestsize(desc->tfm);
+ u8 digest[HASH_MSG_DIGEST_SIZE];
+
+ stm_dbg(debug, "[hash_final]: (ctx=0x%x)!", (u32) ctx);
+
+#ifdef HASH_ACC_SYNC_CONTROL
+ mutex_lock(&hash_hw_acc_mutex);
+#endif
+
+ if (contextsaving) {
+ hash_error = hash_resume_state(HASH_DEVICE_ID_1, &ctx->state);
+
+ if (hash_error != HASH_OK) {
+ stm_error("hash_resume_state() failed!");
+ ret = -1;
+ goto out;
+ }
+ }
+
+ pad_message(HASH_DEVICE_ID_1);
+
+ if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC)
+ write_key(HASH_DEVICE_ID_1, ctx->key, ctx->keylen);
+
+ hash_error = hash_get_digest(HASH_DEVICE_ID_1, digest);
+
+ memcpy(out, digest, digestsize);
+
+out:
+#ifdef HASH_ACC_SYNC_CONTROL
+ mutex_unlock(&hash_hw_acc_mutex);
+#endif
+
+ return ret;
+}
+
+/**
+ * hash_setkey - The setkey function for providing the key during HMAC
+ * calculations.
+ * @tfm: Pointer to the transform
+ * @key: The key used in the operation
+ * @keylen: The length of the key
+ * @alg: The algorithm to use in the operation
+ */
+static int hash_setkey(struct crypto_shash *tfm, const u8 *key,
+ unsigned int keylen, int alg)
+{
+ int ret = 0;
+ int hash_error = HASH_OK;
+
+ struct hash_tfm_ctx *ctx_tfm = crypto_shash_ctx(tfm);
+
+ stm_dbg(debug, "[hash_setkey]: (ctx_tfm=0x%x, key=0x%x, keylen=%d)!",
+ (u32) ctx_tfm, (u32) key, keylen);
+
+ /* Truncate the key to block size */
+ if (keylen > HASH_BLOCK_BYTE_SIZE) {
+ struct hash_config config;
+ u8 digest[MAX_HASH_DIGEST_BYTE_SIZE];
+ unsigned int digestsize = crypto_shash_digestsize(tfm);
+
+ config.algorithm = alg;
+ config.data_format = HASH_DATA_8_BITS;
+ config.oper_mode = HASH_OPER_MODE_HASH;
+
+#ifdef HASH_ACC_SYNC_CONTROL
+ mutex_lock(&hash_hw_acc_mutex);
+#endif
+ hash_error = hash_compute(HASH_DEVICE_ID_1, key, keylen * 8,
+ &config, digest);
+#ifdef HASH_ACC_SYNC_CONTROL
+ mutex_unlock(&hash_hw_acc_mutex);
+#endif
+ if (hash_error != HASH_OK) {
+ stm_error("Error: hash_compute() failed!");
+ ret = -1;
+ goto out;
+ }
+
+ memcpy(ctx_tfm->key, digest, digestsize);
+ ctx_tfm->keylen = digestsize;
+ } else {
+ memcpy(ctx_tfm->key, key, keylen);
+ ctx_tfm->keylen = keylen;
+ }
+
+out:
+ return ret;
+}
+
+/**
+ * sha1_init - SHA1 init function.
+ * @desc: The hash descriptor for the job
+ */
+static int sha1_init(struct shash_desc *desc)
+{
+ struct hash_ctx *ctx = shash_desc_ctx(desc);
+
+ stm_dbg(debug, "[sha1_init]: (ctx=0x%x)!", (u32) ctx);
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = HASH_ALGO_SHA1;
+ ctx->config.oper_mode = HASH_OPER_MODE_HASH;
+
+ return hash_init(desc);
+}
+
+/**
+ * sha256_init - SHA2 (SHA256) init function.
+ * @desc: The hash descriptor for the job
+ */
+static int sha256_init(struct shash_desc *desc)
+{
+ struct hash_ctx *ctx = shash_desc_ctx(desc);
+
+ stm_dbg(debug, "[sha256_init]: (ctx=0x%x)!", (u32) ctx);
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = HASH_ALGO_SHA2;
+ ctx->config.oper_mode = HASH_OPER_MODE_HASH;
+
+ return hash_init(desc);
+}
+
+/**
+ * hmac_sha1_init - SHA1 HMAC init function.
+ * @desc: The hash descriptor for the job
+ */
+static int hmac_sha1_init(struct shash_desc *desc)
+{
+ struct hash_ctx *ctx = shash_desc_ctx(desc);
+
+ stm_dbg(debug, "[hmac_sha1_init]: (ctx=0x%x)!", (u32) ctx);
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = HASH_ALGO_SHA1;
+ ctx->config.oper_mode = HASH_OPER_MODE_HMAC;
+ ctx->config.hmac_key = HASH_SHORT_KEY;
+
+ return hash_init(desc);
+}
+
+/**
+ * hmac_sha256_init - SHA2 (SHA256) HMAC init function.
+ * @desc: The hash descriptor for the job
+ */
+static int hmac_sha256_init(struct shash_desc *desc)
+{
+ struct hash_ctx *ctx = shash_desc_ctx(desc);
+
+ stm_dbg(debug, "[hmac_sha256_init]: (ctx=0x%x)!", (u32) ctx);
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = HASH_ALGO_SHA2;
+ ctx->config.oper_mode = HASH_OPER_MODE_HMAC;
+ ctx->config.hmac_key = HASH_SHORT_KEY;
+
+ return hash_init(desc);
+}
+
+/**
+ * hmac_sha1_setkey - SHA1 HMAC setkey function.
+ * @tfm: Pointer to the transform
+ * @key: The key used in the operation
+ * @keylen: The length of the key
+ */
+static int hmac_sha1_setkey(struct crypto_shash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ stm_dbg(debug, "[hmac_sha1_setkey]: (tfm=0x%x, key=0x%x, keylen=%d)!",
+ (u32) tfm, (u32) key, keylen);
+
+ return hash_setkey(tfm, key, keylen, HASH_ALGO_SHA1);
+}
+
+/**
+ * hmac_sha256_setkey - SHA2 (SHA256) HMAC setkey function.
+ * @tfm: Pointer to the transform
+ * @key: The key used in the operation
+ * @keylen: The length of the key
+ */
+static int hmac_sha256_setkey(struct crypto_shash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ stm_dbg(debug, "[hmac_sha256_setkey]: (tfm=0x%x, key=0x%x, keylen=%d)!",
+ (u32) tfm, (u32) key, keylen);
+
+ return hash_setkey(tfm, key, keylen, HASH_ALGO_SHA2);
+}
+
+static struct shash_alg sha1_alg = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .init = sha1_init,
+ .update = hash_update,
+ .final = hash_final,
+ .descsize = sizeof(struct hash_ctx),
+ .base = {
+ .cra_name = "sha1",
+ .cra_driver_name = "sha1-u8500",
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
+ CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct hash_tfm_ctx),
+ .cra_module = THIS_MODULE,
+ }
+};
+
+static struct shash_alg sha256_alg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .init = sha256_init,
+ .update = hash_update,
+ .final = hash_final,
+ .descsize = sizeof(struct hash_ctx),
+ .base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "sha256-u8500",
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
+ CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct hash_tfm_ctx),
+ .cra_module = THIS_MODULE,
+ }
+};
+
+static struct shash_alg hmac_sha1_alg = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .init = hmac_sha1_init,
+ .update = hash_update,
+ .final = hash_final,
+ .setkey = hmac_sha1_setkey,
+ .descsize = sizeof(struct hash_ctx),
+ .base = {
+ .cra_name = "hmac(sha1)",
+ .cra_driver_name = "hmac(sha1-u8500)",
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
+ CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct hash_tfm_ctx),
+ .cra_module = THIS_MODULE,
+ }
+};
+
+static struct shash_alg hmac_sha256_alg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .init = hmac_sha256_init,
+ .update = hash_update,
+ .final = hash_final,
+ .setkey = hmac_sha256_setkey,
+ .descsize = sizeof(struct hash_ctx),
+ .base = {
+ .cra_name = "hmac(sha256)",
+ .cra_driver_name = "hmac(sha256-u8500)",
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
+ CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct hash_tfm_ctx),
+ .cra_module = THIS_MODULE,
+ }
+};
+
+/**
+ * u8500_hash_probe - Function that probes the hash hardware.
+ * @pdev: The platform device
+ */
+static int u8500_hash_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ int hash_error = HASH_OK;
+ struct resource *res = NULL;
+ struct hash_driver_data *hash_drv_data;
+
+ stm_dbg(debug, "[u8500_hash_probe]: (pdev=0x%x)", (u32) pdev);
+
+ stm_dbg(debug, "[u8500_hash_probe]: Calling kzalloc()!");
+ hash_drv_data = kzalloc(sizeof(struct hash_driver_data), GFP_KERNEL);
+ if (!hash_drv_data) {
+ stm_dbg(debug, "kzalloc() failed!");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ stm_dbg(debug, "[u8500_hash_probe]: Calling platform_get_resource()!");
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ stm_dbg(debug, "platform_get_resource() failed");
+ ret = -ENODEV;
+ goto out_kfree;
+ }
+
+ stm_dbg(debug, "[u8500_hash_probe]: Calling request_mem_region()!");
+ res = request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name);
+ if (res == NULL) {
+ stm_dbg(debug, "request_mem_region() failed");
+ ret = -EBUSY;
+ goto out_kfree;
+ }
+
+ stm_dbg(debug, "[u8500_hash_probe]: Calling ioremap()!");
+ hash_drv_data->base = ioremap(res->start, res->end - res->start + 1);
+ if (!hash_drv_data->base) {
+ stm_error
+ ("[u8500_hash] ioremap of hash1 register memory failed!");
+ ret = -ENOMEM;
+ goto out_free_mem;
+ }
+
+ stm_dbg(debug, "[u8500_hash_probe]: Calling clk_get()!");
+ /* Enable the clk for HASH1 hardware block */
+ hash_drv_data->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(hash_drv_data->clk)) {
+ stm_error("clk_get() failed!");
+ ret = PTR_ERR(hash_drv_data->clk);
+ goto out_unmap;
+ }
+
+ stm_dbg(debug, "[u8500_hash_probe]: Calling clk_enable()!");
+ ret = clk_enable(hash_drv_data->clk);
+ if (ret) {
+ stm_error("clk_enable() failed!");
+ goto out_unmap;
+ }
+
+ stm_dbg(debug,
+ "[u8500_hash_probe]: Calling hash_init_base_address()->"
+ "(base=0x%x,DEVICE_ID=%d)!",
+ (u32) hash_drv_data->base, HASH_DEVICE_ID_1);
+
+ /* Setting base address */
+ hash_error =
+ hash_init_base_address(HASH_DEVICE_ID_1,
+ (t_logical_address) hash_drv_data->base);
+ if (hash_error != HASH_OK) {
+ stm_error("hash_init_base_address() failed!");
+ ret = -1; /*TODO: what error code should be used here!? */
+ goto out_clk;
+ }
+#ifdef HASH_ACC_SYNC_CONTROL
+ stm_dbg(debug, "[u8500_hash_probe]: Calling mutex_init()!");
+ mutex_init(&hash_hw_acc_mutex);
+#endif
+
+ if (mode == 0) {
+ stm_dbg(debug,
+ "[u8500_hash_probe]: To register all algorithms!");
+
+ ret = crypto_register_shash(&sha1_alg);
+ if (ret) {
+ stm_error("Could not register sha1_alg!");
+ goto out_clk;
+ }
+ stm_dbg(debug, "[u8500_hash_probe]: sha1_alg registered!");
+
+ ret = crypto_register_shash(&sha256_alg);
+ if (ret) {
+ stm_error("Could not register sha256_alg!");
+ goto out_unreg1;
+ }
+ stm_dbg(debug, "[u8500_hash_probe]: sha256_alg registered!");
+
+ ret = crypto_register_shash(&hmac_sha1_alg);
+ if (ret) {
+ stm_error("Could not register hmac_sha1_alg!");
+ goto out_unreg2;
+ }
+ stm_dbg(debug, "[u8500_hash_probe]: hmac_sha1_alg registered!");
+
+ ret = crypto_register_shash(&hmac_sha256_alg);
+ if (ret) {
+ stm_error("Could not register hmac_sha256_alg!");
+ goto out_unreg3;
+ }
+ stm_dbg(debug,
+ "[u8500_hash_probe]: hmac_sha256_alg registered!");
+ }
+
+ if (mode == 10) {
+ stm_dbg(debug,
+ "[u8500_hash_probe]: To register only sha1 and sha256"
+ " algorithms!");
+
+ ret = crypto_register_shash(&sha1_alg);
+ if (ret) {
+ stm_error("Could not register sha1_alg!");
+ goto out_clk;
+ }
+
+ ret = crypto_register_shash(&sha256_alg);
+ if (ret) {
+ stm_error("Could not register sha256_alg!");
+ goto out_unreg1_tmp;
+ }
+ }
+
+ stm_dbg(debug, "[u8500_hash_probe]: Calling platform_set_drvdata()!");
+ platform_set_drvdata(pdev, hash_drv_data);
+ return 0;
+
+ if (mode == 0) {
+out_unreg1:
+ crypto_unregister_shash(&sha1_alg);
+out_unreg2:
+ crypto_unregister_shash(&sha256_alg);
+out_unreg3:
+ crypto_unregister_shash(&hmac_sha1_alg);
+ }
+
+ if (mode == 10) {
+out_unreg1_tmp:
+ crypto_unregister_shash(&sha1_alg);
+ }
+
+out_clk:
+ clk_disable(hash_drv_data->clk);
+ clk_put(hash_drv_data->clk);
+
+out_unmap:
+ iounmap(hash_drv_data->base);
+
+out_free_mem:
+ release_mem_region(res->start, res->end - res->start + 1);
+
+out_kfree:
+ kfree(hash_drv_data);
+out:
+ return ret;
+}
+
+/**
+ * u8500_hash_remove - Function that removes the hash device from the platform.
+ * @pdev: The platform device
+ */
+static int u8500_hash_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct hash_driver_data *hash_drv_data;
+
+ stm_dbg(debug, "[u8500_hash_remove]: (pdev=0x%x)", (u32) pdev);
+
+ stm_dbg(debug, "[u8500_hash_remove]: Calling platform_get_drvdata()!");
+ hash_drv_data = platform_get_drvdata(pdev);
+
+ if (mode == 0) {
+ stm_dbg(debug,
+ "[u8500_hash_remove]: To unregister all algorithms!");
+ crypto_unregister_shash(&sha1_alg);
+ crypto_unregister_shash(&sha256_alg);
+ crypto_unregister_shash(&hmac_sha1_alg);
+ crypto_unregister_shash(&hmac_sha256_alg);
+ }
+
+ if (mode == 10) {
+ stm_dbg(debug,
+ "[u8500_hash_remove]: To unregister only sha1 and "
+ "sha256 algorithms!");
+ crypto_unregister_shash(&sha1_alg);
+ crypto_unregister_shash(&sha256_alg);
+ }
+#ifdef HASH_ACC_SYNC_CONTROL
+ stm_dbg(debug, "[u8500_hash_remove]: Calling mutex_destroy()!");
+ mutex_destroy(&hash_hw_acc_mutex);
+#endif
+
+ stm_dbg(debug, "[u8500_hash_remove]: Calling clk_disable()!");
+ clk_disable(hash_drv_data->clk);
+
+ stm_dbg(debug, "[u8500_hash_remove]: Calling clk_put()!");
+ clk_put(hash_drv_data->clk);
+
+ stm_dbg(debug, "[u8500_hash_remove]: Calling iounmap(): base = 0x%x",
+ (u32) hash_drv_data->base);
+ iounmap(hash_drv_data->base);
+
+ stm_dbg(debug, "[u8500_hash_remove]: Calling platform_get_resource()!");
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ stm_dbg(debug,
+ "[u8500_hash_remove]: Calling release_mem_region()"
+ "->res->start=0x%x, res->end = 0x%x!",
+ res->start, res->end);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ stm_dbg(debug, "[u8500_hash_remove]: Calling kfree()!");
+ kfree(hash_drv_data);
+
+ return 0;
+}
+
+static struct platform_driver hash_driver = {
+ .probe = u8500_hash_probe,
+ .remove = u8500_hash_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "hash1",
+ },
+};
+
+/**
+ * u8500_hash_mod_init - The kernel module init function.
+ */
+static int __init u8500_hash_mod_init(void)
+{
+ stm_dbg(debug, "u8500_hash_mod_init() is called!");
+
+ return platform_driver_register(&hash_driver);
+}
+
+/**
+ * u8500_hash_mod_fini - The kernel module exit function.
+ */
+static void __exit u8500_hash_mod_fini(void)
+{
+ stm_dbg(debug, "u8500_hash_mod_fini() is called!");
+
+ platform_driver_unregister(&hash_driver);
+ return;
+}
+
+/**
+ * hash_processblock - This function processes a single block of 512 bits (64
+ * bytes), word aligned, starting at message.
+ * @hid: Hardware device ID
+ * @message: Block (512 bits) of message to be written to the HASH hardware
+ *
+ * Reentrancy: Non Re-entrant.
+ */
+static void hash_processblock(int hid, const u32 *message)
+{
+ u32 count;
+
+ HCL_CLEAR_BITS(g_sys_ctx.registry[hid]->str,
+ HASH_STR_DCAL_MASK);
+ HCL_CLEAR_BITS(g_sys_ctx.registry[hid]->str,
+ HASH_STR_NBLW_MASK);
+
+ /* Partially unrolled loop */
+ for (count = 0; count < (HASH_BLOCK_SIZE / sizeof(u32));
+ count += 4) {
+ HASH_SET_DIN(message[0]);
+ HASH_SET_DIN(message[1]);
+ HASH_SET_DIN(message[2]);
+ HASH_SET_DIN(message[3]);
+ message += 4;
+ }
+}
+
+/**
+ * hash_messagepad - Pads a message and write the nblw bits.
+ * @hid: Hardware device ID
+ * @message: Last word of a message
+ * @index_bytes: The number of bytes in the last message
+ *
+ * This function manages the final part of the digest calculation, when less
+ * than 512 bits (64 bytes) remain in message. This means index_bytes < 64.
+ *
+ * Reentrancy: Non Re-entrant.
+ */
+static void hash_messagepad(int hid, const u32 *message, u8 index_bytes)
+{
+ stm_dbg(debug, "[u8500_hash_alg] hash_messagepad"
+ "(bytes in final msg=%d))", index_bytes);
+
+ clear_reg_str(hid);
+
+ /* Main loop */
+ while (index_bytes >= 4) {
+ HASH_SET_DIN(message[0]);
+ index_bytes -= 4;
+ message++;
+ }
+
+ if (index_bytes)
+ HASH_SET_DIN(message[0]);
+
+ /* num_of_bytes == 0 => NBLW <- 0 (32 bits valid in DATAIN) */
+ HASH_SET_NBLW(index_bytes * 8);
+ stm_dbg(debug, "[u8500_hash_alg] hash_messagepad -> DIN=0x%08x NBLW=%d",
+ g_sys_ctx.registry[hid]->din,
+ g_sys_ctx.registry[hid]->str);
+ HASH_SET_DCAL;
+ stm_dbg(debug, "[u8500_hash_alg] hash_messagepad d -> "
+ "DIN=0x%08x NBLW=%d",
+ g_sys_ctx.registry[hid]->din,
+ g_sys_ctx.registry[hid]->str);
+
+}
+
+/**
+ * hash_incrementlength - Increments the length of the current message.
+ * @hid: Hardware device ID
+ * @incr: Length of message processed already
+ *
+ * Overflow cannot occur, because conditions for overflow are checked in
+ * hash_hw_update.
+ */
+static void hash_incrementlength(int hid, u32 incr)
+{
+ g_sys_ctx.state[hid].length.low_word += incr;
+
+ /* Check for wrap-around */
+ if (g_sys_ctx.state[hid].length.low_word < incr)
+ g_sys_ctx.state[hid].length.high_word++;
+}
+
+/**
+ * hash_setconfiguration - Sets the required configuration for the hash
+ * hardware.
+ * @hid: Hardware device ID
+ * @p_config: Pointer to a configuration structure
+ *
+ * Reentrancy: Non Re-entrant
+ * Reentrancy issues:
+ * 1. Global variable registry(cofiguration register,
+ * parameter register, divider register) is being modified
+ *
+ * Comments 1. : User need to call hash_begin API after calling this
+ * API i.e. the current configuration is set only when
+ * bit INIT is set and we set INIT bit in hash_begin.
+ * Changing the configuration during a computation has
+ * no effect so we first set configuration by calling
+ * this API and then set the INIT bit for the HASH
+ * processor and the curent configuration is taken into
+ * account. As reading INIT bit (with correct protection
+ * rights) will always return 0b so we can't make a check
+ * at software level. So the user has to initialize the
+ * device for new configuration to take in to effect.
+ * 2. The default value of data format is 00b ie the format
+ * of data entered in HASH_DIN register is 32-bit data.
+ * The data written in HASH_DIN is used directly by the
+ * HASH processing, without re ordering.
+ */
+int hash_setconfiguration(int hid, struct hash_config *p_config)
+{
+ int hash_error = HASH_OK;
+
+ stm_dbg(debug, "[u8500_hash_alg] hash_setconfiguration())");
+
+ if (!((HASH_DEVICE_ID_0 == hid)
+ || (HASH_DEVICE_ID_1 == hid))) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+ HASH_SET_DATA_FORMAT(p_config->data_format);
+
+ HCL_SET_BITS(g_sys_ctx.registry[hid]->cr,
+ HASH_CR_EMPTYMSG_MASK);
+
+ /* This bit selects between SHA-1 or SHA-2 algorithm */
+ if (HASH_ALGO_SHA2 == p_config->algorithm) {
+ HCL_CLEAR_BITS(g_sys_ctx.registry[hid]->cr,
+ HASH_CR_ALGO_MASK);
+ } else { /* SHA1 algorithm */
+
+ HCL_SET_BITS(g_sys_ctx.registry[hid]->cr,
+ HASH_CR_ALGO_MASK);
+ }
+
+ /* This bit selects between HASH or HMAC mode for the selected
+ algorithm */
+ if (HASH_OPER_MODE_HASH == p_config->oper_mode) {
+ HCL_CLEAR_BITS(g_sys_ctx.registry
+ [hid]->cr, HASH_CR_MODE_MASK);
+ } else { /* HMAC mode */
+
+ HCL_SET_BITS(g_sys_ctx.registry[hid]->cr,
+ HASH_CR_MODE_MASK);
+
+ /* This bit selects between short key (<= 64 bytes) or long key
+ (>64 bytes) in HMAC mode */
+ if (HASH_SHORT_KEY == p_config->hmac_key) {
+ HCL_CLEAR_BITS(g_sys_ctx.registry[hid]->cr,
+ HASH_CR_LKEY_MASK);
+ } else {
+ HCL_SET_BITS(g_sys_ctx.registry[hid]->cr,
+ HASH_CR_LKEY_MASK);
+ }
+ }
+
+ return hash_error;
+}
+
+/**
+ * hash_begin - This routine resets some globals and initializes the hash
+ * hardware.
+ * @hid: Hardware device ID
+ *
+ * Reentrancy: Non Re-entrant
+ *
+ * Comments 1. : User need to call hash_setconfiguration API before
+ * calling this API i.e. the current configuration is set
+ * only when bit INIT is set and we set INIT bit in
+ * hash_begin. Changing the configuration during a
+ * computation has no effect so we first set
+ * configuration by calling this API and then set the
+ * INIT bit for the HASH processor and the current
+ * configuration is taken into account. As reading INIT
+ * bit (with correct protection rights) will always
+ * return 0b so we can't make a check at software level.
+ * So the user has to initialize the device for new
+ * configuration to take in to effect.
+ */
+int hash_begin(int hid)
+{
+ int hash_error = HASH_OK;
+
+ /* HW and SW initializations */
+ /* Note: there is no need to initialize buffer and digest members */
+
+ stm_dbg(debug, "[u8500_hash_alg] hash_begin())");
+
+ if (!((HASH_DEVICE_ID_0 == hid)
+ || (HASH_DEVICE_ID_1 == hid))) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+ g_sys_ctx.state[hid].index = 0;
+ g_sys_ctx.state[hid].bit_index = 0;
+ g_sys_ctx.state[hid].length.high_word = 0;
+ g_sys_ctx.state[hid].length.low_word = 0;
+
+ HASH_INITIALIZE;
+
+ HCL_CLEAR_BITS(g_sys_ctx.registry[hid]->str,
+ HASH_STR_DCAL_MASK);
+ HCL_CLEAR_BITS(g_sys_ctx.registry[hid]->str,
+ HASH_STR_NBLW_MASK);
+
+ return hash_error;
+}
+
+/**
+ * hash_hw_update - Updates current HASH computation hashing another part of
+ * the message.
+ * @hid: Hardware device ID
+ * @p_data_buffer: Byte array containing the message to be hashed (caller
+ * allocated)
+ * @msg_length: Length of message to be hashed (in bits)
+ *
+ * Reentrancy: Non Re-entrant
+ */
+int hash_hw_update(int hid, const u8 *p_data_buffer, u32 msg_length)
+{
+ int hash_error = HASH_OK;
+ u8 index;
+ u8 *p_buffer;
+ u32 count;
+
+ stm_dbg(debug, "[u8500_hash_alg] hash_hw_update(msg_length=%d / %d), "
+ "in=%d, bin=%d))",
+ msg_length,
+ msg_length / 8,
+ g_sys_ctx.state[hid].index,
+ g_sys_ctx.state[hid].bit_index);
+
+ if (!((HASH_DEVICE_ID_0 == hid)
+ || (HASH_DEVICE_ID_1 == hid))) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+ index = g_sys_ctx.state[hid].index;
+
+ p_buffer = (u8 *)g_sys_ctx.state[hid].buffer;
+
+ /* Number of bytes in the message */
+ msg_length /= 8;
+
+ /* Check parameters */
+ if (NULL == p_data_buffer) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+ /* Check if g_sys_ctx.state.length + msg_length
+ overflows */
+ if (msg_length >
+ (g_sys_ctx.state[hid].length.low_word + msg_length)
+ && HASH_HIGH_WORD_MAX_VAL ==
+ (g_sys_ctx.state[hid].length.high_word)) {
+ hash_error = HASH_MSG_LENGTH_OVERFLOW;
+ stm_error("[u8500_hash_alg] HASH_MSG_LENGTH_OVERFLOW!");
+ return hash_error;
+ }
+
+ /* Main loop */
+ while (0 != msg_length) {
+ if ((index + msg_length) < HASH_BLOCK_SIZE) {
+ for (count = 0; count < msg_length; count++) {
+ /*TODO: memcpy? */
+ p_buffer[index + count] =
+ *(p_data_buffer + count);
+ }
+
+ index += msg_length;
+ msg_length = 0;
+ } else {
+ /* if 'p_data_buffer' is four byte aligned and local
+ * buffer does not have any data, we can write data
+ * directly from 'p_data_buffer' to HW peripheral,
+ * otherwise we first copy data to a local buffer
+ */
+ if ((0 == (((u32) p_data_buffer) % 4))
+ && (0 == index)) {
+ hash_processblock(hid,
+ (const u32 *)p_data_buffer);
+ } else {
+ for (count = 0;
+ count < (u32)(HASH_BLOCK_SIZE - index);
+ count++) {
+ p_buffer[index + count] =
+ *(p_data_buffer + count);
+ }
+
+ hash_processblock(hid, (const u32 *)p_buffer);
+ }
+
+ hash_incrementlength(hid, HASH_BLOCK_SIZE);
+ p_data_buffer += (HASH_BLOCK_SIZE - index);
+ msg_length -= (HASH_BLOCK_SIZE - index);
+ index = 0;
+ }
+ }
+
+ g_sys_ctx.state[hid].index = index;
+
+ stm_dbg(debug, "[u8500_hash_alg] hash_hw_update END(msg_length=%d in "
+ "bits, in=%d, bin=%d))",
+ msg_length,
+ g_sys_ctx.state[hid].index,
+ g_sys_ctx.state[hid].bit_index);
+
+ return hash_error;
+}
+
+/**
+ * hash_end_key - Function that ends a message, i.e. pad and triggers the last
+ * calculation.
+ * @hid: Hardware device ID
+ *
+ * This function also clear the registries that have been involved in
+ * computation.
+ */
+int hash_end_key(int hid)
+{
+ int hash_error = HASH_OK;
+ u8 count = 0;
+
+ stm_dbg(debug, "[u8500_hash_alg] hash_end_key(index=%d))",
+ g_sys_ctx.state[hid].index);
+
+ hash_messagepad(hid, g_sys_ctx.state[hid].buffer,
+ g_sys_ctx.state[hid].index);
+
+ /* Wait till the DCAL bit get cleared, So that we get the final
+ * message digest not intermediate value.
+ */
+ while (g_sys_ctx.registry[hid]->str & HASH_STR_DCAL_MASK)
+ ;
+
+ /* Reset the HASH state */
+ g_sys_ctx.state[hid].index = 0;
+ g_sys_ctx.state[hid].bit_index = 0;
+
+ for (count = 0; count < HASH_BLOCK_SIZE / sizeof(u32); count++)
+ g_sys_ctx.state[hid].buffer[count] = 0;
+
+ g_sys_ctx.state[hid].length.high_word = 0;
+ g_sys_ctx.state[hid].length.low_word = 0;
+
+ return hash_error;
+}
+
+/**
+ * hash_resume_state - Function that resumes the state of an calculation.
+ * @hid: Hardware device ID
+ * @device_state: The state to be restored in the hash hardware
+ *
+ * Reentrancy: Non Re-entrant
+ */
+int hash_resume_state(int hid, const struct hash_state *device_state)
+{
+ u32 temp_cr;
+ int hash_error = HASH_OK;
+ s32 count;
+
+ stm_dbg(debug, "[u8500_hash_alg] hash_resume_state(state(0x%x)))",
+ (u32) device_state);
+
+ if (NULL == device_state) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+ if (!((HASH_DEVICE_ID_0 == hid)
+ || (HASH_DEVICE_ID_1 == hid))) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+ /* Check correctness of index and length members */
+ if (device_state->index > HASH_BLOCK_SIZE
+ || (device_state->length.low_word % HASH_BLOCK_SIZE) != 0) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+ for (count = 0; count < (s32) (HASH_BLOCK_SIZE / sizeof(u32));
+ count++) {
+ g_sys_ctx.state[hid].buffer[count] =
+ device_state->buffer[count];
+ }
+
+ g_sys_ctx.state[hid].index = device_state->index;
+ g_sys_ctx.state[hid].bit_index = device_state->bit_index;
+ g_sys_ctx.state[hid].length = device_state->length;
+
+ HASH_INITIALIZE;
+
+ temp_cr = device_state->temp_cr;
+ g_sys_ctx.registry[hid]->cr =
+ temp_cr & HASH_CR_RESUME_MASK;
+
+ for (count = 0; count < HASH_CSR_COUNT; count++) {
+ if ((count >= 36) &&
+ !(g_sys_ctx.registry[hid]->cr &
+ HASH_CR_MODE_MASK)) {
+ break;
+ }
+ g_sys_ctx.registry[hid]->csrx[count] =
+ device_state->csr[count];
+ }
+
+ g_sys_ctx.registry[hid]->csfull = device_state->csfull;
+ g_sys_ctx.registry[hid]->csdatain = device_state->csdatain;
+
+ g_sys_ctx.registry[hid]->str = device_state->str_reg;
+ g_sys_ctx.registry[hid]->cr = temp_cr;
+
+ return hash_error;
+}
+
+/**
+ * hash_save_state - Function that saves the state of hardware.
+ * @hid: Hardware device ID
+ * @device_state: The strucure where the hardware state should be saved
+ *
+ * Reentrancy: Non Re-entrant
+ */
+int hash_save_state(int hid, struct hash_state *device_state)
+{
+ u32 temp_cr;
+ u32 count;
+ int hash_error = HASH_OK;
+
+ stm_dbg(debug, "[u8500_hash_alg] hash_save_state( state(0x%x)))",
+ (u32) device_state);
+
+ if (NULL == device_state) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+ if (!((HASH_DEVICE_ID_0 == hid)
+ || (HASH_DEVICE_ID_1 == hid))) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+ for (count = 0; count < HASH_BLOCK_SIZE / sizeof(u32); count++) {
+ device_state->buffer[count] =
+ g_sys_ctx.state[hid].buffer[count];
+ }
+
+ device_state->index = g_sys_ctx.state[hid].index;
+ device_state->bit_index = g_sys_ctx.state[hid].bit_index;
+ device_state->length = g_sys_ctx.state[hid].length;
+
+ /* Write dummy value to force digest intermediate calculation. This
+ * actually makes sure that there isn't any ongoing calculation in the
+ * hardware.
+ */
+ while (g_sys_ctx.registry[hid]->str & HASH_STR_DCAL_MASK)
+ ;
+
+ temp_cr = g_sys_ctx.registry[hid]->cr;
+
+ device_state->str_reg = g_sys_ctx.registry[hid]->str;
+
+ device_state->din_reg = g_sys_ctx.registry[hid]->din;
+
+ for (count = 0; count < HASH_CSR_COUNT; count++) {
+ if ((count >= 36)
+ && !(g_sys_ctx.registry[hid]->cr &
+ HASH_CR_MODE_MASK)) {
+ break;
+ }
+
+ device_state->csr[count] =
+ g_sys_ctx.registry[hid]->csrx[count];
+ }
+
+ device_state->csfull = g_sys_ctx.registry[hid]->csfull;
+ device_state->csdatain = g_sys_ctx.registry[hid]->csdatain;
+
+ /* end if */
+ device_state->temp_cr = temp_cr;
+
+ return hash_error;
+}
+
+/**
+ * hash_end - Ends current HASH computation, passing back the hash to the user.
+ * @hid: Hardware device ID
+ * @digest: User allocated byte array for the calculated digest
+ *
+ * Reentrancy: Non Re-entrant
+ */
+int hash_end(int hid, u8 digest[HASH_MSG_DIGEST_SIZE])
+{
+ int hash_error = HASH_OK;
+ u32 count;
+ /* Standard SHA-1 digest for null string for HASH mode */
+ u8 zero_message_hash_sha1[HASH_MSG_DIGEST_SIZE] = {
+ 0xDA, 0x39, 0xA3, 0xEE,
+ 0x5E, 0x6B, 0x4B, 0x0D,
+ 0x32, 0x55, 0xBF, 0xEF,
+ 0x95, 0x60, 0x18, 0x90,
+ 0xAF, 0xD8, 0x07, 0x09,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ /* Standard SHA-2 digest for null string for HASH mode */
+ u8 zero_message_hash_sha2[HASH_MSG_DIGEST_SIZE] = {
+ 0xD4, 0x1D, 0x8C, 0xD9,
+ 0x8F, 0x00, 0xB2, 0x04,
+ 0xE9, 0x80, 0x09, 0x98,
+ 0xEC, 0xF8, 0x42, 0x7E,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ /* Standard SHA-1 digest for null string for HMAC mode,with no key */
+ u8 zero_message_hmac_sha1[HASH_MSG_DIGEST_SIZE] = {
+ 0xFB, 0xDB, 0x1D, 0x1B,
+ 0x18, 0xAA, 0x6C, 0x08,
+ 0x32, 0x4B, 0x7D, 0x64,
+ 0xB7, 0x1F, 0xB7, 0x63,
+ 0x70, 0x69, 0x0E, 0x1D,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ /* Standard SHA2 digest for null string for HMAC mode,with no key */
+ u8 zero_message_hmac_sha2[HASH_MSG_DIGEST_SIZE] = {
+ 0x74, 0xE6, 0xF7, 0x29,
+ 0x8A, 0x9C, 0x2D, 0x16,
+ 0x89, 0x35, 0xF5, 0x8C,
+ 0x00, 0x1B, 0xAD, 0x88,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ stm_dbg(debug, "[u8500_hash_alg] hash_end(digest array (0x%x)))",
+ (u32) digest);
+
+ if (NULL == digest) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+ if (!((HASH_DEVICE_ID_0 == hid)
+ || (HASH_DEVICE_ID_1 == hid))) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+ if (0 == g_sys_ctx.state[hid].index &&
+ 0 == g_sys_ctx.state[hid].length.high_word &&
+ 0 == g_sys_ctx.state[hid].length.low_word) {
+ if (g_sys_ctx.registry[hid]->cr & HASH_CR_MODE_MASK) {
+ if (g_sys_ctx.registry[hid]->cr & HASH_CR_ALGO_MASK) {
+ /* hash of an empty message was requested */
+ for (count = 0; count < HASH_MSG_DIGEST_SIZE;
+ count++) {
+ digest[count] =
+ zero_message_hmac_sha1[count];
+ }
+ } else { /* SHA-2 algo */
+
+ /* hash of an empty message was requested */
+ for (count = 0; count < HASH_MSG_DIGEST_SIZE;
+ count++) {
+ digest[count] =
+ zero_message_hmac_sha2[count];
+ }
+ }
+ } else { /* HASH mode */
+
+ if (g_sys_ctx.registry[hid]->cr & HASH_CR_ALGO_MASK) {
+ /* hash of an empty message was requested */
+ for (count = 0; count < HASH_MSG_DIGEST_SIZE;
+ count++) {
+ digest[count] =
+ zero_message_hash_sha1[count];
+ }
+ } else { /* SHA-2 algo */
+
+ /* hash of an empty message was requested */
+ for (count = 0; count < HASH_MSG_DIGEST_SIZE;
+ count++) {
+ digest[count] =
+ zero_message_hash_sha2[count];
+ }
+ }
+ }
+
+ HASH_SET_DCAL;
+ } else {
+ hash_messagepad(hid,
+ g_sys_ctx.state[hid].buffer,
+ g_sys_ctx.state[hid].index);
+
+ /* Wait till the DCAL bit get cleared, So that we get the final
+ * message digest not intermediate value. */
+ while (g_sys_ctx.registry[hid]->str & HASH_STR_DCAL_MASK)
+ ;
+
+ hash_error = hash_get_digest(hid, digest);
+
+ /* Reset the HASH state */
+ g_sys_ctx.state[hid].index = 0;
+ g_sys_ctx.state[hid].bit_index = 0;
+ for (count = 0; count < HASH_BLOCK_SIZE / sizeof(u32);
+ count++) {
+ g_sys_ctx.state[hid].buffer[count]
+ = 0;
+ }
+
+ g_sys_ctx.state[hid].length.high_word = 0;
+ g_sys_ctx.state[hid].length.low_word = 0;
+ }
+
+ if (debug)
+ hexdump(digest, HASH_MSG_DIGEST_SIZE);
+
+ return hash_error;
+}
+
+/**
+ * hash_initialize_globals - Initialize global variables to their default reset
+ * value.
+ * @hid: Hardware device ID
+ *
+ * Reentrancy: Non Re-entrant, global structure g_sys_ctx elements are being
+ * modified
+ */
+static void hash_initialize_globals(int hid)
+{
+ u8 loop_count;
+
+ /* Resetting the values of global variables except the registry */
+ g_sys_ctx.state[hid].temp_cr = HASH_RESET_INDEX_VAL;
+ g_sys_ctx.state[hid].str_reg = HASH_RESET_INDEX_VAL;
+ g_sys_ctx.state[hid].din_reg = HASH_RESET_INDEX_VAL;
+
+ for (loop_count = 0; loop_count < HASH_CSR_COUNT; loop_count++) {
+ g_sys_ctx.state[hid].csr[loop_count] =
+ HASH_RESET_CSRX_REG_VALUE;
+ }
+
+ g_sys_ctx.state[hid].csfull = HASH_RESET_CSFULL_REG_VALUE;
+ g_sys_ctx.state[hid].csdatain = HASH_RESET_CSDATAIN_REG_VALUE;
+
+ for (loop_count = 0; loop_count < (HASH_BLOCK_SIZE / sizeof(u32));
+ loop_count++) {
+ g_sys_ctx.state[hid].buffer[loop_count] =
+ HASH_RESET_BUFFER_VAL;
+ }
+
+ g_sys_ctx.state[hid].length.high_word = HASH_RESET_LEN_HIGH_VAL;
+ g_sys_ctx.state[hid].length.low_word = HASH_RESET_LEN_LOW_VAL;
+ g_sys_ctx.state[hid].index = HASH_RESET_INDEX_VAL;
+ g_sys_ctx.state[hid].bit_index = HASH_RESET_BIT_INDEX_VAL;
+}
+
+/**
+ * hash_reset - This routine will reset the global variable to default reset
+ * value and HASH registers to their power on reset values.
+ * @hid: Hardware device ID
+ *
+ * Reentrancy: Non Re-entrant, global structure g_sys_ctx elements are being
+ * modified.
+ */
+int hash_reset(int hid)
+{
+ int hash_error = HASH_OK;
+ u8 loop_count;
+
+ if (!((HASH_DEVICE_ID_0 == hid)
+ || (HASH_DEVICE_ID_1 == hid))) {
+ hash_error = HASH_INVALID_PARAMETER;
+
+ return hash_error;
+ }
+
+ /* Resetting the values of global variables except the registry */
+ hash_initialize_globals(hid);
+
+ /* Resetting HASH control register to power-on-reset values */
+ g_sys_ctx.registry[hid]->str = HASH_RESET_START_REG_VALUE;
+
+ for (loop_count = 0; loop_count < HASH_CSR_COUNT; loop_count++) {
+ g_sys_ctx.registry[hid]->csrx[loop_count] =
+ HASH_RESET_CSRX_REG_VALUE;
+ }
+
+ g_sys_ctx.registry[hid]->csfull = HASH_RESET_CSFULL_REG_VALUE;
+ g_sys_ctx.registry[hid]->csdatain =
+ HASH_RESET_CSDATAIN_REG_VALUE;
+
+ /* Resetting the HASH Control reg. This also reset the PRIVn and SECn
+ * bits and hence the device registers will not be accessed anymore and
+ * should be done in the last HASH register access statement.
+ */
+ g_sys_ctx.registry[hid]->cr = HASH_RESET_CONTROL_REG_VALUE;
+
+ return hash_error;
+}
+
+/**
+ * hash_init_base_address - This routine initializes hash register base
+ * address. It also checks for peripheral Ids and PCell Ids.
+ * @hid: Hardware device ID
+ * @base_address: Hash hardware base address
+ *
+ * Reentrancy: Non Re-entrant, global variable registry (register base address)
+ * is being modified.
+ */
+int hash_init_base_address(int hid, t_logical_address base_address)
+{
+ int hash_error = HASH_OK;
+
+ stm_dbg(debug, "[u8500_hash_alg] hash_init_base_address())");
+
+ if (!((HASH_DEVICE_ID_0 == hid)
+ || (HASH_DEVICE_ID_1 == hid))) {
+ hash_error = HASH_INVALID_PARAMETER;
+
+ return hash_error;
+ }
+
+ if (0 != base_address) {
+ /*--------------------------------------*
+ * Initializing the registers structure *
+ *--------------------------------------*/
+ g_sys_ctx.registry[hid] = (struct hash_register *) base_address;
+
+ /*--------------------------*
+ * Checking Peripheral Ids *
+ *--------------------------*/
+ if ((HASH_P_ID0 ==
+ g_sys_ctx.registry[hid]->periphid0)
+ && (HASH_P_ID1 ==
+ g_sys_ctx.registry[hid]->periphid1)
+ && (HASH_P_ID2 ==
+ g_sys_ctx.registry[hid]->periphid2)
+ && (HASH_P_ID3 ==
+ g_sys_ctx.registry[hid]->periphid3)
+ && (HASH_CELL_ID0 ==
+ g_sys_ctx.registry[hid]->cellid0)
+ && (HASH_CELL_ID1 ==
+ g_sys_ctx.registry[hid]->cellid1)
+ && (HASH_CELL_ID2 ==
+ g_sys_ctx.registry[hid]->cellid2)
+ && (HASH_CELL_ID3 ==
+ g_sys_ctx.registry[hid]->cellid3)
+ ) {
+
+ /* Resetting the values of global variables except the
+ registry */
+ hash_initialize_globals(hid);
+ hash_error = HASH_OK;
+ return hash_error;
+ } else {
+ hash_error = HASH_UNSUPPORTED_HW;
+ stm_error("[u8500_hash_alg] HASH_UNSUPPORTED_HW!");
+ return hash_error;
+ }
+ } /* end if */
+ else {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+}
+
+/**
+ * hash_get_digest - Gets the digest.
+ * @hid: Hardware device ID
+ * @digest: User allocated byte array for the calculated digest
+ *
+ * Reentrancy: Non Re-entrant, global variable registry (hash control register)
+ * is being modified.
+ *
+ * Note that, if this is called before the final message has been handle it will
+ * return the intermediate message digest.
+ */
+int hash_get_digest(int hid, u8 *digest)
+{
+ u32 temp_hx_val, count;
+ int hash_error = HASH_OK;
+
+ stm_dbg(debug,
+ "[u8500_hash_alg] hash_get_digest(digest array:(0x%x))",
+ (u32) digest);
+
+ if (!((HASH_DEVICE_ID_0 == hid)
+ || (HASH_DEVICE_ID_1 == hid))) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+ /* Copy result into digest array */
+ for (count = 0; count < (HASH_MSG_DIGEST_SIZE / sizeof(u32));
+ count++) {
+ temp_hx_val = HASH_GET_HX(count);
+ digest[count * 4] = (u8) ((temp_hx_val >> 24) & 0xFF);
+ digest[count * 4 + 1] = (u8) ((temp_hx_val >> 16) & 0xFF);
+ digest[count * 4 + 2] = (u8) ((temp_hx_val >> 8) & 0xFF);
+ digest[count * 4 + 3] = (u8) ((temp_hx_val >> 0) & 0xFF);
+ }
+
+ return hash_error;
+}
+
+/**
+ * hash_compute - Performs a complete HASH calculation on the message passed.
+ * @hid: Hardware device ID
+ * @p_data_buffer: Pointer to the message to be hashed
+ * @msg_length: The length of the message
+ * @p_hash_config: Structure with configuration data for the hash hardware
+ * @digest: User allocated byte array for the calculated digest
+ *
+ * Reentrancy: Non Re-entrant
+ */
+int hash_compute(int hid,
+ const u8 *p_data_buffer,
+ u32 msg_length,
+ struct hash_config *p_hash_config,
+ u8 digest[HASH_MSG_DIGEST_SIZE]) {
+ int hash_error = HASH_OK;
+
+ stm_dbg(debug, "[u8500_hash_alg] hash_compute())");
+
+ if (!((HASH_DEVICE_ID_0 == hid)
+ || (HASH_DEVICE_ID_1 == hid))) {
+ hash_error = HASH_INVALID_PARAMETER;
+ stm_error("[u8500_hash_alg] HASH_INVALID_PARAMETER!");
+ return hash_error;
+ }
+
+
+ /* WARNING: return code must be checked if
+ * behaviour of hash_begin changes.
+ */
+ hash_error = hash_setconfiguration(hid, p_hash_config);
+ if (HASH_OK != hash_error) {
+ stm_error("[u8500_hash_alg] hash_setconfiguration() failed!");
+ return hash_error;
+ }
+
+ hash_error = hash_begin(hid);
+ if (HASH_OK != hash_error) {
+ stm_error("[u8500_hash_alg] hash_begin() failed!");
+ return hash_error;
+ }
+
+ hash_error = hash_hw_update(hid, p_data_buffer, msg_length);
+ if (HASH_OK != hash_error) {
+ stm_error("[u8500_hash_alg] hash_hw_update() failed!");
+ return hash_error;
+ }
+
+ hash_error = hash_end(hid, digest);
+ if (HASH_OK != hash_error) {
+ stm_error("[u8500_hash_alg] hash_end() failed!");
+ return hash_error;
+ }
+
+ return hash_error;
+}
+
+module_init(u8500_hash_mod_init);
+module_exit(u8500_hash_mod_fini);
+
+module_param(mode, int, 0);
+module_param(debug, int, 0);
+module_param(contextsaving, int, 0);
+
+MODULE_DESCRIPTION("Driver for ST-Ericsson U8500 HASH engine.");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("sha1-u8500");
+MODULE_ALIAS("sha256-u8500");
+MODULE_ALIAS("hmac(sha1-u8500)");
+MODULE_ALIAS("hmac(sha256-u8500)");
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 9e01e96fee9..6f76878f622 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -33,15 +33,22 @@ if DMADEVICES
comment "DMA Devices"
-config ASYNC_TX_DISABLE_CHANNEL_SWITCH
+config ASYNC_TX_ENABLE_CHANNEL_SWITCH
bool
+config AMBA_PL08X
+ bool "ARM PrimeCell PL080 or PL081 support"
+ depends on ARM_AMBA && EXPERIMENTAL
+ select DMA_ENGINE
+ help
+ Platform has a PL08x DMAC device
+ which can provide DMA engine support
+
config INTEL_IOATDMA
tristate "Intel I/OAT DMA support"
depends on PCI && X86
select DMA_ENGINE
select DCA
- select ASYNC_TX_DISABLE_CHANNEL_SWITCH
select ASYNC_TX_DISABLE_PQ_VAL_DMA
select ASYNC_TX_DISABLE_XOR_VAL_DMA
help
@@ -56,6 +63,7 @@ config INTEL_IOP_ADMA
tristate "Intel IOP ADMA support"
depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX
select DMA_ENGINE
+ select ASYNC_TX_ENABLE_CHANNEL_SWITCH
help
Enable support for the Intel(R) IOP Series RAID engines.
@@ -80,6 +88,7 @@ config FSL_DMA
tristate "Freescale Elo and Elo Plus DMA support"
depends on FSL_SOC
select DMA_ENGINE
+ select ASYNC_TX_ENABLE_CHANNEL_SWITCH
---help---
Enable support for the Freescale Elo and Elo Plus DMA controllers.
The Elo is the DMA controller on some 82xx and 83xx parts, and the
@@ -96,6 +105,7 @@ config MV_XOR
bool "Marvell XOR engine support"
depends on PLAT_ORION
select DMA_ENGINE
+ select ASYNC_TX_ENABLE_CHANNEL_SWITCH
---help---
Enable support for the Marvell XOR engine.
@@ -153,6 +163,7 @@ config AMCC_PPC440SPE_ADMA
depends on 440SPe || 440SP
select DMA_ENGINE
select ARCH_HAS_ASYNC_TX_FIND_CHANNEL
+ select ASYNC_TX_ENABLE_CHANNEL_SWITCH
help
Enable support for the AMCC PPC440SPe RAID engines.
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 0fe5ebbfda5..c51dbc83ac2 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
obj-$(CONFIG_TIMB_DMA) += timb_dma.o
obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
obj-$(CONFIG_PL330_DMA) += pl330.o
+obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
new file mode 100644
index 00000000000..b605cc9ac3a
--- /dev/null
+++ b/drivers/dma/amba-pl08x.c
@@ -0,0 +1,2167 @@
+/*
+ * Copyright (c) 2006 ARM Ltd.
+ * Copyright (c) 2010 ST-Ericsson SA
+ *
+ * Author: Peter Pearse <peter.pearse@arm.com>
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is iin this distribution in the
+ * file called COPYING.
+ *
+ * Documentation: ARM DDI 0196G == PL080
+ * Documentation: ARM DDI 0218E == PL081
+ *
+ * PL080 & PL081 both have 16 sets of DMA signals that can be routed to
+ * any channel.
+ *
+ * The PL080 has 8 channels available for simultaneous use, and the PL081
+ * has only two channels. So on these DMA controllers the number of channels
+ * and the number of incoming DMA signals are two totally different things.
+ * It is usually not possible to theoretically handle all physical signals,
+ * so a multiplexing scheme with possible denial of use is necessary.
+ *
+ * The PL080 has a dual bus master, PL081 has a single master.
+ *
+ * Memory to peripheral transfer may be visualized as
+ * Get data from memory to DMAC
+ * Until no data left
+ * On burst request from peripheral
+ * Destination burst from DMAC to peripheral
+ * Clear burst request
+ * Raise terminal count interrupt
+ *
+ * For peripherals with a FIFO:
+ * Source burst size == half the depth of the peripheral FIFO
+ * Destination burst size == the depth of the peripheral FIFO
+ *
+ * (Bursts are irrelevant for mem to mem transfers - there are no burst
+ * signals, the DMA controller will simply facilitate its AHB master.)
+ *
+ * ASSUMES default (little) endianness for DMA transfers
+ *
+ * Only DMAC flow control is implemented
+ *
+ * Global TODO:
+ * - Break out common code from arch/arm/mach-s3c64xx and share
+ */
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/dmapool.h>
+#include <linux/amba/bus.h>
+#include <linux/dmaengine.h>
+#include <linux/amba/pl08x.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <asm/hardware/pl080.h>
+#include <asm/dma.h>
+#include <asm/mach/dma.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+
+#define DRIVER_NAME "pl08xdmac"
+
+/**
+ * struct vendor_data - vendor-specific config parameters
+ * for PL08x derivates
+ * @name: the name of this specific variant
+ * @channels: the number of channels available in this variant
+ * @dualmaster: whether this version supports dual AHB masters
+ * or not.
+ */
+struct vendor_data {
+ char *name;
+ u8 channels;
+ bool dualmaster;
+};
+
+/*
+ * PL08X private data structures
+ * An LLI struct - see pl08x TRM
+ * Note that next uses bit[0] as a bus bit,
+ * start & end do not - their bus bit info
+ * is in cctl
+ */
+struct lli {
+ dma_addr_t src;
+ dma_addr_t dst;
+ dma_addr_t next;
+ u32 cctl;
+};
+
+/**
+ * struct pl08x_driver_data - the local state holder for the PL08x
+ * @slave: slave engine for this instance
+ * @memcpy: memcpy engine for this instance
+ * @base: virtual memory base (remapped) for the PL08x
+ * @adev: the corresponding AMBA (PrimeCell) bus entry
+ * @vd: vendor data for this PL08x variant
+ * @pd: platform data passed in from the platform/machine
+ * @phy_chans: array of data for the physical channels
+ * @pool: a pool for the LLI descriptors
+ * @pool_ctr: counter of LLIs in the pool
+ * @lock: a spinlock for this struct
+ */
+struct pl08x_driver_data {
+ struct dma_device slave;
+ struct dma_device memcpy;
+ void __iomem *base;
+ struct amba_device *adev;
+ struct vendor_data *vd;
+ struct pl08x_platform_data *pd;
+ struct pl08x_phy_chan *phy_chans;
+ struct dma_pool *pool;
+ int pool_ctr;
+ spinlock_t lock;
+};
+
+/*
+ * PL08X specific defines
+ */
+
+/*
+ * Memory boundaries: the manual for PL08x says that the controller
+ * cannot read past a 1KiB boundary, so these defines are used to
+ * create transfer LLIs that do not cross such boundaries.
+ */
+#define PL08X_BOUNDARY_SHIFT (10) /* 1KB 0x400 */
+#define PL08X_BOUNDARY_SIZE (1 << PL08X_BOUNDARY_SHIFT)
+
+/* Minimum period between work queue runs */
+#define PL08X_WQ_PERIODMIN 20
+
+/* Size (bytes) of each LLI buffer allocated for one transfer */
+# define PL08X_LLI_TSFR_SIZE 0x2000
+
+/* Maximimum times we call dma_pool_alloc on this pool without freeing */
+#define PL08X_MAX_ALLOCS 0x40
+#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct lli))
+#define PL08X_ALIGN 8
+
+static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan)
+{
+ return container_of(chan, struct pl08x_dma_chan, chan);
+}
+
+/*
+ * Physical channel handling
+ */
+
+/* Whether a certain channel is busy or not */
+static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch)
+{
+ unsigned int val;
+
+ val = readl(ch->base + PL080_CH_CONFIG);
+ return val & PL080_CONFIG_ACTIVE;
+}
+
+/*
+ * Set the initial DMA register values i.e. those for the first LLI
+ * The next lli pointer and the configuration interrupt bit have
+ * been set when the LLIs were constructed
+ */
+static void pl08x_set_cregs(struct pl08x_driver_data *pl08x,
+ struct pl08x_phy_chan *ch)
+{
+ /* Wait for channel inactive */
+ while (pl08x_phy_channel_busy(ch))
+ ;
+
+ dev_vdbg(&pl08x->adev->dev,
+ "WRITE channel %d: csrc=%08x, cdst=%08x, "
+ "cctl=%08x, clli=%08x, ccfg=%08x\n",
+ ch->id,
+ ch->csrc,
+ ch->cdst,
+ ch->cctl,
+ ch->clli,
+ ch->ccfg);
+
+ writel(ch->csrc, ch->base + PL080_CH_SRC_ADDR);
+ writel(ch->cdst, ch->base + PL080_CH_DST_ADDR);
+ writel(ch->clli, ch->base + PL080_CH_LLI);
+ writel(ch->cctl, ch->base + PL080_CH_CONTROL);
+ writel(ch->ccfg, ch->base + PL080_CH_CONFIG);
+}
+
+static inline void pl08x_config_phychan_for_txd(struct pl08x_dma_chan *plchan)
+{
+ struct pl08x_channel_data *cd = plchan->cd;
+ struct pl08x_phy_chan *phychan = plchan->phychan;
+ struct pl08x_txd *txd = plchan->at;
+
+ /* Copy the basic control register calculated at transfer config */
+ phychan->csrc = txd->csrc;
+ phychan->cdst = txd->cdst;
+ phychan->clli = txd->clli;
+ phychan->cctl = txd->cctl;
+
+ /* Assign the signal to the proper control registers */
+ phychan->ccfg = cd->ccfg;
+ phychan->ccfg &= ~PL080_CONFIG_SRC_SEL_MASK;
+ phychan->ccfg &= ~PL080_CONFIG_DST_SEL_MASK;
+ /* If it wasn't set from AMBA, ignore it */
+ if (txd->direction == DMA_TO_DEVICE)
+ /* Select signal as destination */
+ phychan->ccfg |=
+ (phychan->signal << PL080_CONFIG_DST_SEL_SHIFT);
+ else if (txd->direction == DMA_FROM_DEVICE)
+ /* Select signal as source */
+ phychan->ccfg |=
+ (phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT);
+ /* Always enable error interrupts */
+ phychan->ccfg |= PL080_CONFIG_ERR_IRQ_MASK;
+ /* Always enable terminal interrupts */
+ phychan->ccfg |= PL080_CONFIG_TC_IRQ_MASK;
+}
+
+/*
+ * Enable the DMA channel
+ * Assumes all other configuration bits have been set
+ * as desired before this code is called
+ */
+static void pl08x_enable_phy_chan(struct pl08x_driver_data *pl08x,
+ struct pl08x_phy_chan *ch)
+{
+ u32 val;
+
+ /*
+ * Do not access config register until channel shows as disabled
+ */
+ while (readl(pl08x->base + PL080_EN_CHAN) & (1 << ch->id))
+ ;
+
+ /*
+ * Do not access config register until channel shows as inactive
+ */
+ val = readl(ch->base + PL080_CH_CONFIG);
+ while ((val & PL080_CONFIG_ACTIVE) || (val & PL080_CONFIG_ENABLE))
+ val = readl(ch->base + PL080_CH_CONFIG);
+
+ writel(val | PL080_CONFIG_ENABLE, ch->base + PL080_CH_CONFIG);
+}
+
+/*
+ * Overall DMAC remains enabled always.
+ *
+ * Disabling individual channels could lose data.
+ *
+ * Disable the peripheral DMA after disabling the DMAC
+ * in order to allow the DMAC FIFO to drain, and
+ * hence allow the channel to show inactive
+ *
+ */
+static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
+{
+ u32 val;
+
+ /* Set the HALT bit and wait for the FIFO to drain */
+ val = readl(ch->base + PL080_CH_CONFIG);
+ val |= PL080_CONFIG_HALT;
+ writel(val, ch->base + PL080_CH_CONFIG);
+
+ /* Wait for channel inactive */
+ while (pl08x_phy_channel_busy(ch))
+ ;
+}
+
+static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
+{
+ u32 val;
+
+ /* Clear the HALT bit */
+ val = readl(ch->base + PL080_CH_CONFIG);
+ val &= ~PL080_CONFIG_HALT;
+ writel(val, ch->base + PL080_CH_CONFIG);
+}
+
+
+/* Stops the channel */
+static void pl08x_stop_phy_chan(struct pl08x_phy_chan *ch)
+{
+ u32 val;
+
+ pl08x_pause_phy_chan(ch);
+
+ /* Disable channel */
+ val = readl(ch->base + PL080_CH_CONFIG);
+ val &= ~PL080_CONFIG_ENABLE;
+ val &= ~PL080_CONFIG_ERR_IRQ_MASK;
+ val &= ~PL080_CONFIG_TC_IRQ_MASK;
+ writel(val, ch->base + PL080_CH_CONFIG);
+}
+
+static inline u32 get_bytes_in_cctl(u32 cctl)
+{
+ /* The source width defines the number of bytes */
+ u32 bytes = cctl & PL080_CONTROL_TRANSFER_SIZE_MASK;
+
+ switch (cctl >> PL080_CONTROL_SWIDTH_SHIFT) {
+ case PL080_WIDTH_8BIT:
+ break;
+ case PL080_WIDTH_16BIT:
+ bytes *= 2;
+ break;
+ case PL080_WIDTH_32BIT:
+ bytes *= 4;
+ break;
+ }
+ return bytes;
+}
+
+/* The channel should be paused when calling this */
+static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
+{
+ struct pl08x_phy_chan *ch;
+ struct pl08x_txd *txdi = NULL;
+ struct pl08x_txd *txd;
+ unsigned long flags;
+ u32 bytes = 0;
+
+ spin_lock_irqsave(&plchan->lock, flags);
+
+ ch = plchan->phychan;
+ txd = plchan->at;
+
+ /*
+ * Next follow the LLIs to get the number of pending bytes in the
+ * currently active transaction.
+ */
+ if (ch && txd) {
+ struct lli *llis_va = txd->llis_va;
+ struct lli *llis_bus = (struct lli *) txd->llis_bus;
+ u32 clli = readl(ch->base + PL080_CH_LLI);
+
+ /* First get the bytes in the current active LLI */
+ bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL));
+
+ if (clli) {
+ int i = 0;
+
+ /* Forward to the LLI pointed to by clli */
+ while ((clli != (u32) &(llis_bus[i])) &&
+ (i < MAX_NUM_TSFR_LLIS))
+ i++;
+
+ while (clli) {
+ bytes += get_bytes_in_cctl(llis_va[i].cctl);
+ /*
+ * A clli of 0x00000000 will terminate the
+ * LLI list
+ */
+ clli = llis_va[i].next;
+ i++;
+ }
+ }
+ }
+
+ /* Sum up all queued transactions */
+ if (!list_empty(&plchan->desc_list)) {
+ list_for_each_entry(txdi, &plchan->desc_list, node) {
+ bytes += txdi->len;
+ }
+
+ }
+
+ spin_unlock_irqrestore(&plchan->lock, flags);
+
+ return bytes;
+}
+
+/*
+ * Allocate a physical channel for a virtual channel
+ */
+static struct pl08x_phy_chan *
+pl08x_get_phy_channel(struct pl08x_driver_data *pl08x,
+ struct pl08x_dma_chan *virt_chan)
+{
+ struct pl08x_phy_chan *ch = NULL;
+ unsigned long flags;
+ int i;
+
+ /*
+ * Try to locate a physical channel to be used for
+ * this transfer. If all are taken return NULL and
+ * the requester will have to cope by using some fallback
+ * PIO mode or retrying later.
+ */
+ for (i = 0; i < pl08x->vd->channels; i++) {
+ ch = &pl08x->phy_chans[i];
+
+ spin_lock_irqsave(&ch->lock, flags);
+
+ if (!ch->serving) {
+ ch->serving = virt_chan;
+ ch->signal = -1;
+ spin_unlock_irqrestore(&ch->lock, flags);
+ break;
+ }
+
+ spin_unlock_irqrestore(&ch->lock, flags);
+ }
+
+ if (i == pl08x->vd->channels) {
+ /* No physical channel available, cope with it */
+ return NULL;
+ }
+
+ return ch;
+}
+
+static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x,
+ struct pl08x_phy_chan *ch)
+{
+ unsigned long flags;
+
+ /* Stop the channel and clear its interrupts */
+ pl08x_stop_phy_chan(ch);
+ writel((1 << ch->id), pl08x->base + PL080_ERR_CLEAR);
+ writel((1 << ch->id), pl08x->base + PL080_TC_CLEAR);
+
+ /* Mark it as free */
+ spin_lock_irqsave(&ch->lock, flags);
+ ch->serving = NULL;
+ spin_unlock_irqrestore(&ch->lock, flags);
+}
+
+/*
+ * LLI handling
+ */
+
+static inline unsigned int pl08x_get_bytes_for_cctl(unsigned int coded)
+{
+ switch (coded) {
+ case PL080_WIDTH_8BIT:
+ return 1;
+ case PL080_WIDTH_16BIT:
+ return 2;
+ case PL080_WIDTH_32BIT:
+ return 4;
+ default:
+ break;
+ }
+ BUG();
+ return 0;
+}
+
+static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth,
+ u32 tsize)
+{
+ u32 retbits = cctl;
+
+ /* Remove all src, dst and transfersize bits */
+ retbits &= ~PL080_CONTROL_DWIDTH_MASK;
+ retbits &= ~PL080_CONTROL_SWIDTH_MASK;
+ retbits &= ~PL080_CONTROL_TRANSFER_SIZE_MASK;
+
+ /* Then set the bits according to the parameters */
+ switch (srcwidth) {
+ case 1:
+ retbits |= PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT;
+ break;
+ case 2:
+ retbits |= PL080_WIDTH_16BIT << PL080_CONTROL_SWIDTH_SHIFT;
+ break;
+ case 4:
+ retbits |= PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT;
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ switch (dstwidth) {
+ case 1:
+ retbits |= PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT;
+ break;
+ case 2:
+ retbits |= PL080_WIDTH_16BIT << PL080_CONTROL_DWIDTH_SHIFT;
+ break;
+ case 4:
+ retbits |= PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT;
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ retbits |= tsize << PL080_CONTROL_TRANSFER_SIZE_SHIFT;
+ return retbits;
+}
+
+/*
+ * Autoselect a master bus to use for the transfer
+ * this prefers the destination bus if both available
+ * if fixed address on one bus the other will be chosen
+ */
+void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus,
+ struct pl08x_bus_data *dst_bus, struct pl08x_bus_data **mbus,
+ struct pl08x_bus_data **sbus, u32 cctl)
+{
+ if (!(cctl & PL080_CONTROL_DST_INCR)) {
+ *mbus = src_bus;
+ *sbus = dst_bus;
+ } else if (!(cctl & PL080_CONTROL_SRC_INCR)) {
+ *mbus = dst_bus;
+ *sbus = src_bus;
+ } else {
+ if (dst_bus->buswidth == 4) {
+ *mbus = dst_bus;
+ *sbus = src_bus;
+ } else if (src_bus->buswidth == 4) {
+ *mbus = src_bus;
+ *sbus = dst_bus;
+ } else if (dst_bus->buswidth == 2) {
+ *mbus = dst_bus;
+ *sbus = src_bus;
+ } else if (src_bus->buswidth == 2) {
+ *mbus = src_bus;
+ *sbus = dst_bus;
+ } else {
+ /* src_bus->buswidth == 1 */
+ *mbus = dst_bus;
+ *sbus = src_bus;
+ }
+ }
+}
+
+/*
+ * Fills in one LLI for a certain transfer descriptor
+ * and advance the counter
+ */
+int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x,
+ struct pl08x_txd *txd, int num_llis, int len,
+ u32 cctl, u32 *remainder)
+{
+ struct lli *llis_va = txd->llis_va;
+ struct lli *llis_bus = (struct lli *) txd->llis_bus;
+
+ BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS);
+
+ llis_va[num_llis].cctl = cctl;
+ llis_va[num_llis].src = txd->srcbus.addr;
+ llis_va[num_llis].dst = txd->dstbus.addr;
+
+ /*
+ * On versions with dual masters, you can optionally AND on
+ * PL080_LLI_LM_AHB2 to the LLI to tell the hardware to read
+ * in new LLIs with that controller, but we always try to
+ * choose AHB1 to point into memory. The idea is to have AHB2
+ * fixed on the peripheral and AHB1 messing around in the
+ * memory. So we don't manipulate this bit currently.
+ */
+
+ llis_va[num_llis].next =
+ (dma_addr_t)((u32) &(llis_bus[num_llis + 1]));
+
+ if (cctl & PL080_CONTROL_SRC_INCR)
+ txd->srcbus.addr += len;
+ if (cctl & PL080_CONTROL_DST_INCR)
+ txd->dstbus.addr += len;
+
+ *remainder -= len;
+
+ return num_llis + 1;
+}
+
+/*
+ * Return number of bytes to fill to boundary, or len
+ */
+static inline u32 pl08x_pre_boundary(u32 addr, u32 len)
+{
+ u32 boundary;
+
+ boundary = ((addr >> PL08X_BOUNDARY_SHIFT) + 1)
+ << PL08X_BOUNDARY_SHIFT;
+
+ if (boundary < addr + len)
+ return boundary - addr;
+ else
+ return len;
+}
+
+/*
+ * This fills in the table of LLIs for the transfer descriptor
+ * Note that we assume we never have to change the burst sizes
+ * Return 0 for error
+ */
+static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
+ struct pl08x_txd *txd)
+{
+ struct pl08x_channel_data *cd = txd->cd;
+ struct pl08x_bus_data *mbus, *sbus;
+ u32 remainder;
+ int num_llis = 0;
+ u32 cctl;
+ int max_bytes_per_lli;
+ int total_bytes = 0;
+ struct lli *llis_va;
+ struct lli *llis_bus;
+
+ if (!txd) {
+ dev_err(&pl08x->adev->dev, "%s no descriptor\n", __func__);
+ return 0;
+ }
+
+ txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT,
+ &txd->llis_bus);
+ if (!txd->llis_va) {
+ dev_err(&pl08x->adev->dev, "%s no memory for llis\n", __func__);
+ return 0;
+ }
+
+ pl08x->pool_ctr++;
+
+ /*
+ * Initialize bus values for this transfer
+ * from the passed optimal values
+ */
+ if (!cd) {
+ dev_err(&pl08x->adev->dev, "%s no channel data\n", __func__);
+ return 0;
+ }
+
+ /* Get the default CCTL from the platform data */
+ cctl = cd->cctl;
+
+ /*
+ * On the PL080 we have two bus masters and we
+ * should select one for source and one for
+ * destination. We try to use AHB2 for the
+ * bus which does not increment (typically the
+ * peripheral) else we just choose something.
+ */
+ cctl &= ~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2);
+ if (pl08x->vd->dualmaster) {
+ if (cctl & PL080_CONTROL_SRC_INCR)
+ /* Source increments, use AHB2 for destination */
+ cctl |= PL080_CONTROL_DST_AHB2;
+ else if (cctl & PL080_CONTROL_DST_INCR)
+ /* Destination increments, use AHB2 for source */
+ cctl |= PL080_CONTROL_SRC_AHB2;
+ else
+ /* Just pick something, source AHB1 dest AHB2 */
+ cctl |= PL080_CONTROL_DST_AHB2;
+ }
+
+ /* Find maximum width of the source bus */
+ txd->srcbus.maxwidth =
+ pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_SWIDTH_MASK) >>
+ PL080_CONTROL_SWIDTH_SHIFT);
+
+ /* Find maximum width of the destination bus */
+ txd->dstbus.maxwidth =
+ pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >>
+ PL080_CONTROL_DWIDTH_SHIFT);
+
+ /* Set up the bus widths to the maximum */
+ txd->srcbus.buswidth = txd->srcbus.maxwidth;
+ txd->dstbus.buswidth = txd->dstbus.maxwidth;
+ dev_vdbg(&pl08x->adev->dev,
+ "%s source bus is %d bytes wide, dest bus is %d bytes wide\n",
+ __func__, txd->srcbus.buswidth, txd->dstbus.buswidth);
+
+
+ /*
+ * Bytes transferred == tsize * MIN(buswidths), not max(buswidths)
+ */
+ max_bytes_per_lli = min(txd->srcbus.buswidth, txd->dstbus.buswidth) *
+ PL080_CONTROL_TRANSFER_SIZE_MASK;
+ dev_vdbg(&pl08x->adev->dev,
+ "%s max bytes per lli = %d\n",
+ __func__, max_bytes_per_lli);
+
+ /* We need to count this down to zero */
+ remainder = txd->len;
+ dev_vdbg(&pl08x->adev->dev,
+ "%s remainder = %d\n",
+ __func__, remainder);
+
+ /*
+ * Choose bus to align to
+ * - prefers destination bus if both available
+ * - if fixed address on one bus chooses other
+ * - modifies cctl to choose an apropriate master
+ */
+ pl08x_choose_master_bus(&txd->srcbus, &txd->dstbus,
+ &mbus, &sbus, cctl);
+
+
+ /*
+ * The lowest bit of the LLI register
+ * is also used to indicate which master to
+ * use for reading the LLIs.
+ */
+
+ if (txd->len < mbus->buswidth) {
+ /*
+ * Less than a bus width available
+ * - send as single bytes
+ */
+ while (remainder) {
+ dev_vdbg(&pl08x->adev->dev,
+ "%s single byte LLIs for a transfer of "
+ "less than a bus width (remain %08x)\n",
+ __func__, remainder);
+ cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
+ num_llis =
+ pl08x_fill_lli_for_desc(pl08x, txd, num_llis, 1,
+ cctl, &remainder);
+ total_bytes++;
+ }
+ } else {
+ /*
+ * Make one byte LLIs until master bus is aligned
+ * - slave will then be aligned also
+ */
+ while ((mbus->addr) % (mbus->buswidth)) {
+ dev_vdbg(&pl08x->adev->dev,
+ "%s adjustment lli for less than bus width "
+ "(remain %08x)\n",
+ __func__, remainder);
+ cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
+ num_llis = pl08x_fill_lli_for_desc
+ (pl08x, txd, num_llis, 1, cctl, &remainder);
+ total_bytes++;
+ }
+
+ /*
+ * Master now aligned
+ * - if slave is not then we must set its width down
+ */
+ if (sbus->addr % sbus->buswidth) {
+ dev_dbg(&pl08x->adev->dev,
+ "%s set down bus width to one byte\n",
+ __func__);
+
+ sbus->buswidth = 1;
+ }
+
+ /*
+ * Make largest possible LLIs until less than one bus
+ * width left
+ */
+ while (remainder > (mbus->buswidth - 1)) {
+ int lli_len, target_len;
+ int tsize;
+ int odd_bytes;
+
+ /*
+ * If enough left try to send max possible,
+ * otherwise try to send the remainder
+ */
+ target_len = remainder;
+ if (remainder > max_bytes_per_lli)
+ target_len = max_bytes_per_lli;
+
+ /*
+ * Set bus lengths for incrementing busses
+ * to number of bytes which fill to next memory
+ * boundary
+ */
+ if (cctl & PL080_CONTROL_SRC_INCR)
+ txd->srcbus.fill_bytes =
+ pl08x_pre_boundary(
+ txd->srcbus.addr,
+ remainder);
+ else
+ txd->srcbus.fill_bytes =
+ max_bytes_per_lli;
+
+ if (cctl & PL080_CONTROL_DST_INCR)
+ txd->dstbus.fill_bytes =
+ pl08x_pre_boundary(
+ txd->dstbus.addr,
+ remainder);
+ else
+ txd->dstbus.fill_bytes =
+ max_bytes_per_lli;
+
+ /*
+ * Find the nearest
+ */
+ lli_len = min(txd->srcbus.fill_bytes,
+ txd->dstbus.fill_bytes);
+
+ BUG_ON(lli_len > remainder);
+
+ if (lli_len <= 0) {
+ dev_err(&pl08x->adev->dev,
+ "%s lli_len is %d, <= 0\n",
+ __func__, lli_len);
+ return 0;
+ }
+
+ if (lli_len == target_len) {
+ /*
+ * Can send what we wanted
+ */
+ /*
+ * Maintain alignment
+ */
+ lli_len = (lli_len/mbus->buswidth) *
+ mbus->buswidth;
+ odd_bytes = 0;
+ } else {
+ /*
+ * So now we know how many bytes to transfer
+ * to get to the nearest boundary
+ * The next lli will past the boundary
+ * - however we may be working to a boundary
+ * on the slave bus
+ * We need to ensure the master stays aligned
+ */
+ odd_bytes = lli_len % mbus->buswidth;
+ /*
+ * - and that we are working in multiples
+ * of the bus widths
+ */
+ lli_len -= odd_bytes;
+
+ }
+
+ if (lli_len) {
+ /*
+ * Check against minimum bus alignment:
+ * Calculate actual transfer size in relation
+ * to bus width an get a maximum remainder of
+ * the smallest bus width - 1
+ */
+ /* FIXME: use round_down()? */
+ tsize = lli_len / min(mbus->buswidth,
+ sbus->buswidth);
+ lli_len = tsize * min(mbus->buswidth,
+ sbus->buswidth);
+
+ if (target_len != lli_len) {
+ dev_vdbg(&pl08x->adev->dev,
+ "%s can't send what we want. Desired %08x, lli of %08x bytes in txd of %08x\n",
+ __func__, target_len, lli_len, txd->len);
+ }
+
+ cctl = pl08x_cctl_bits(cctl,
+ txd->srcbus.buswidth,
+ txd->dstbus.buswidth,
+ tsize);
+
+ dev_vdbg(&pl08x->adev->dev,
+ "%s fill lli with single lli chunk of size %08x (remainder %08x)\n",
+ __func__, lli_len, remainder);
+ num_llis = pl08x_fill_lli_for_desc(pl08x, txd,
+ num_llis, lli_len, cctl,
+ &remainder);
+ total_bytes += lli_len;
+ }
+
+
+ if (odd_bytes) {
+ /*
+ * Creep past the boundary,
+ * maintaining master alignment
+ */
+ int j;
+ for (j = 0; (j < mbus->buswidth)
+ && (remainder); j++) {
+ cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
+ dev_vdbg(&pl08x->adev->dev,
+ "%s align with boundardy, single byte (remain %08x)\n",
+ __func__, remainder);
+ num_llis =
+ pl08x_fill_lli_for_desc(pl08x,
+ txd, num_llis, 1,
+ cctl, &remainder);
+ total_bytes++;
+ }
+ }
+ }
+
+ /*
+ * Send any odd bytes
+ */
+ if (remainder < 0) {
+ dev_err(&pl08x->adev->dev, "%s remainder not fitted 0x%08x bytes\n",
+ __func__, remainder);
+ return 0;
+ }
+
+ while (remainder) {
+ cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
+ dev_vdbg(&pl08x->adev->dev,
+ "%s align with boundardy, single odd byte (remain %d)\n",
+ __func__, remainder);
+ num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis,
+ 1, cctl, &remainder);
+ total_bytes++;
+ }
+ }
+ if (total_bytes != txd->len) {
+ dev_err(&pl08x->adev->dev,
+ "%s size of encoded lli:s don't match total txd, transferred 0x%08x from size 0x%08x\n",
+ __func__, total_bytes, txd->len);
+ return 0;
+ }
+
+ if (num_llis >= MAX_NUM_TSFR_LLIS) {
+ dev_err(&pl08x->adev->dev,
+ "%s need to increase MAX_NUM_TSFR_LLIS from 0x%08x\n",
+ __func__, (u32) MAX_NUM_TSFR_LLIS);
+ return 0;
+ }
+ /*
+ * Decide whether this is a loop or a terminated transfer
+ */
+ llis_va = txd->llis_va;
+ llis_bus = (struct lli *) txd->llis_bus;
+
+ if (cd->circular_buffer) {
+ /*
+ * Loop the circular buffer so that the next element
+ * points back to the beginning of the LLI.
+ */
+ llis_va[num_llis - 1].next =
+ (dma_addr_t)((unsigned int)&(llis_bus[0]));
+ } else {
+ /*
+ * On non-circular buffers, the final LLI terminates
+ * the LLI.
+ */
+ llis_va[num_llis - 1].next = 0;
+ /*
+ * The final LLI element shall also fire an interrupt
+ */
+ llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN;
+ }
+
+ /* Now store the channel register values */
+ txd->csrc = llis_va[0].src;
+ txd->cdst = llis_va[0].dst;
+ if (num_llis > 1)
+ txd->clli = llis_va[0].next;
+ else
+ txd->clli = 0;
+
+ txd->cctl = llis_va[0].cctl;
+ /* ccfg will be set at physical channel allocation time */
+
+#ifdef VERBOSE_DEBUG
+ {
+ int i;
+
+ for (i = 0; i < num_llis; i++) {
+ dev_vdbg(&pl08x->adev->dev,
+ "lli %d @%p: csrc=%08x, cdst=%08x, cctl=%08x, clli=%08x\n",
+ i,
+ &llis_va[i],
+ llis_va[i].src,
+ llis_va[i].dst,
+ llis_va[i].cctl,
+ llis_va[i].next
+ );
+ }
+ }
+#endif
+
+ return num_llis;
+}
+
+/* You should call this with the struct pl08x lock held */
+static void pl08x_free_txd(struct pl08x_driver_data *pl08x,
+ struct pl08x_txd *txd)
+{
+ if (!txd)
+ dev_err(&pl08x->adev->dev,
+ "%s no descriptor to free\n",
+ __func__);
+
+ /* Free the LLI */
+ dma_pool_free(pl08x->pool, txd->llis_va,
+ txd->llis_bus);
+
+ pl08x->pool_ctr--;
+
+ kfree(txd);
+}
+
+static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
+ struct pl08x_dma_chan *plchan)
+{
+ struct pl08x_txd *txdi = NULL;
+ struct pl08x_txd *next;
+
+ if (!list_empty(&plchan->desc_list)) {
+ list_for_each_entry_safe(txdi,
+ next, &plchan->desc_list, node) {
+ list_del(&txdi->node);
+ pl08x_free_txd(pl08x, txdi);
+ }
+
+ }
+}
+
+/*
+ * The DMA ENGINE API
+ */
+static int pl08x_alloc_chan_resources(struct dma_chan *chan)
+{
+ return 0;
+}
+
+static void pl08x_free_chan_resources(struct dma_chan *chan)
+{
+}
+
+/*
+ * This should be called with the channel plchan->lock held
+ */
+static int prep_phy_channel(struct pl08x_dma_chan *plchan,
+ struct pl08x_txd *txd)
+{
+ struct pl08x_driver_data *pl08x = plchan->host;
+ struct pl08x_phy_chan *ch;
+ int ret;
+
+ /* Check if we already have a channel */
+ if (plchan->phychan)
+ return 0;
+
+ ch = pl08x_get_phy_channel(pl08x, plchan);
+ if (!ch) {
+ /* No physical channel available, cope with it */
+ dev_dbg(&pl08x->adev->dev, "no physical channel available for xfer on %s\n", plchan->name);
+ return -EBUSY;
+ }
+
+ /*
+ * OK we have a physical channel: for memcpy() this is all we
+ * need, but for slaves the physical signals may be muxed!
+ * Can the platform allow us to use this channel?
+ */
+ if (plchan->slave &&
+ ch->signal < 0 &&
+ pl08x->pd->get_signal) {
+ ret = pl08x->pd->get_signal(plchan);
+ if (ret < 0) {
+ dev_dbg(&pl08x->adev->dev,
+ "unable to use physical channel %d for transfer on %s due to platform restrictions\n",
+ ch->id, plchan->name);
+ /* Release physical channel & return */
+ pl08x_put_phy_channel(pl08x, ch);
+ return -EBUSY;
+ }
+ ch->signal = ret;
+ }
+
+ dev_dbg(&pl08x->adev->dev, "allocated physical channel %d and signal %d for xfer on %s\n",
+ ch->id,
+ ch->signal,
+ plchan->name);
+
+ plchan->phychan = ch;
+
+ return 0;
+}
+
+static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan);
+
+ atomic_inc(&plchan->last_issued);
+ tx->cookie = atomic_read(&plchan->last_issued);
+ /* This unlock follows the lock in the prep() function */
+ spin_unlock_irqrestore(&plchan->lock, plchan->lockflags);
+
+ return tx->cookie;
+}
+
+static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt(
+ struct dma_chan *chan, unsigned long flags)
+{
+ struct dma_async_tx_descriptor *retval = NULL;
+
+ return retval;
+}
+
+/*
+ * Code accessing dma_async_is_complete() in a tight loop
+ * may give problems - could schedule where indicated.
+ * If slaves are relying on interrupts to signal completion this
+ * function must not be called with interrupts disabled
+ */
+static enum dma_status
+pl08x_dma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ dma_cookie_t last_used;
+ dma_cookie_t last_complete;
+ enum dma_status ret;
+ u32 bytesleft = 0;
+
+ last_used = atomic_read(&plchan->last_issued);
+ last_complete = plchan->lc;
+
+ ret = dma_async_is_complete(cookie, last_complete, last_used);
+ if (ret == DMA_SUCCESS) {
+ dma_set_tx_state(txstate, last_complete, last_used, 0);
+ return ret;
+ }
+
+ /*
+ * schedule(); could be inserted here
+ */
+
+ /*
+ * This cookie not complete yet
+ */
+ last_used = atomic_read(&plchan->last_issued);
+ last_complete = plchan->lc;
+
+ /* Get number of bytes left in the active transactions and queue */
+ bytesleft = pl08x_getbytes_chan(plchan);
+
+ dma_set_tx_state(txstate, last_complete, last_used,
+ bytesleft);
+
+ if (plchan->state == PL08X_CHAN_PAUSED)
+ return DMA_PAUSED;
+
+ /* Whether waiting or running, we're in progress */
+ return DMA_IN_PROGRESS;
+}
+
+/* PrimeCell DMA extension */
+struct burst_table {
+ int burstwords;
+ u32 reg;
+};
+
+static const struct burst_table burst_sizes[] = {
+ {
+ .burstwords = 256,
+ .reg = (PL080_BSIZE_256 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_256 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 128,
+ .reg = (PL080_BSIZE_128 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_128 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 64,
+ .reg = (PL080_BSIZE_64 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_64 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 32,
+ .reg = (PL080_BSIZE_32 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_32 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 16,
+ .reg = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 8,
+ .reg = (PL080_BSIZE_8 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_8 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 4,
+ .reg = (PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 1,
+ .reg = (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+};
+
+static void dma_set_runtime_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+ struct pl08x_channel_data *cd = plchan->cd;
+ enum dma_slave_buswidth addr_width;
+ u32 maxburst;
+ u32 cctl = 0;
+ /* Mask out all except src and dst channel */
+ u32 ccfg = cd->ccfg & 0x000003DEU;
+ int i = 0;
+
+ /* Transfer direction */
+ plchan->runtime_direction = config->direction;
+ if (config->direction == DMA_TO_DEVICE) {
+ plchan->runtime_addr = config->dst_addr;
+ cctl |= PL080_CONTROL_SRC_INCR;
+ ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ addr_width = config->dst_addr_width;
+ maxburst = config->dst_maxburst;
+ } else if (config->direction == DMA_FROM_DEVICE) {
+ plchan->runtime_addr = config->src_addr;
+ cctl |= PL080_CONTROL_DST_INCR;
+ ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ addr_width = config->src_addr_width;
+ maxburst = config->src_maxburst;
+ } else {
+ dev_err(&pl08x->adev->dev,
+ "bad runtime_config: alien transfer direction\n");
+ return;
+ }
+
+ switch (addr_width) {
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ cctl |= (PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT) |
+ (PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT);
+ break;
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ cctl |= (PL080_WIDTH_16BIT << PL080_CONTROL_SWIDTH_SHIFT) |
+ (PL080_WIDTH_16BIT << PL080_CONTROL_DWIDTH_SHIFT);
+ break;
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ cctl |= (PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT) |
+ (PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT);
+ break;
+ default:
+ dev_err(&pl08x->adev->dev,
+ "bad runtime_config: alien address width\n");
+ return;
+ }
+
+ /*
+ * Now decide on a maxburst:
+ * If this channel will only request single transfers, set
+ * this down to ONE element.
+ */
+ if (plchan->cd->single) {
+ cctl |= (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT);
+ } else {
+ while (i < ARRAY_SIZE(burst_sizes)) {
+ if (burst_sizes[i].burstwords <= maxburst)
+ break;
+ i++;
+ }
+ cctl |= burst_sizes[i].reg;
+ }
+
+ /* Access the cell in privileged mode, non-bufferable, non-cacheable */
+ cctl &= ~PL080_CONTROL_PROT_MASK;
+ cctl |= PL080_CONTROL_PROT_SYS;
+
+ /* Modify the default channel data to fit PrimeCell request */
+ cd->cctl = cctl;
+ cd->ccfg = ccfg;
+
+ dev_dbg(&pl08x->adev->dev,
+ "configured channel %s (%s) for %s, data width %d, "
+ "maxburst %d words, LE, CCTL=%08x, CCFG=%08x\n",
+ dma_chan_name(chan), plchan->name,
+ (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
+ addr_width,
+ maxburst,
+ cctl, ccfg);
+}
+
+/*
+ * Slave transactions callback to the slave device to allow
+ * synchronization of slave DMA signals with the DMAC enable
+ */
+static void pl08x_issue_pending(struct dma_chan *chan)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+ unsigned long flags;
+
+ spin_lock_irqsave(&plchan->lock, flags);
+ /* Something is already active */
+ if (plchan->at) {
+ spin_unlock_irqrestore(&plchan->lock, flags);
+ return;
+ }
+
+ /* Didn't get a physical channel so waiting for it ... */
+ if (plchan->state == PL08X_CHAN_WAITING)
+ return;
+
+ /* Take the first element in the queue and execute it */
+ if (!list_empty(&plchan->desc_list)) {
+ struct pl08x_txd *next;
+
+ next = list_first_entry(&plchan->desc_list,
+ struct pl08x_txd,
+ node);
+ list_del(&next->node);
+ plchan->at = next;
+ plchan->state = PL08X_CHAN_RUNNING;
+
+ /* Configure the physical channel for the active txd */
+ pl08x_config_phychan_for_txd(plchan);
+ pl08x_set_cregs(pl08x, plchan->phychan);
+ pl08x_enable_phy_chan(pl08x, plchan->phychan);
+ }
+
+ spin_unlock_irqrestore(&plchan->lock, flags);
+}
+
+static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
+ struct pl08x_txd *txd)
+{
+ int num_llis;
+ struct pl08x_driver_data *pl08x = plchan->host;
+ int ret;
+
+ num_llis = pl08x_fill_llis_for_desc(pl08x, txd);
+
+ if (!num_llis)
+ return -EINVAL;
+
+ spin_lock_irqsave(&plchan->lock, plchan->lockflags);
+
+ /*
+ * If this device is not using a circular buffer then
+ * queue this new descriptor for transfer.
+ * The descriptor for a circular buffer continues
+ * to be used until the channel is freed.
+ */
+ if (txd->cd->circular_buffer)
+ dev_err(&pl08x->adev->dev,
+ "%s attempting to queue a circular buffer\n",
+ __func__);
+ else
+ list_add_tail(&txd->node,
+ &plchan->desc_list);
+
+ /*
+ * See if we already have a physical channel allocated,
+ * else this is the time to try to get one.
+ */
+ ret = prep_phy_channel(plchan, txd);
+ if (ret) {
+ /*
+ * No physical channel available, we will
+ * stack up the memcpy channels until there is a channel
+ * available to handle it whereas slave transfers may
+ * have been denied due to platform channel muxing restrictions
+ * and since there is no guarantee that this will ever be
+ * resolved, and since the signal must be aquired AFTER
+ * aquiring the physical channel, we will let them be NACK:ed
+ * with -EBUSY here. The drivers can alway retry the prep()
+ * call if they are eager on doing this using DMA.
+ */
+ if (plchan->slave) {
+ pl08x_free_txd_list(pl08x, plchan);
+ spin_unlock_irqrestore(&plchan->lock, plchan->lockflags);
+ return -EBUSY;
+ }
+ /* Do this memcpy whenever there is a channel ready */
+ plchan->state = PL08X_CHAN_WAITING;
+ plchan->waiting = txd;
+ } else
+ /*
+ * Else we're all set, paused and ready to roll,
+ * status will switch to PL08X_CHAN_RUNNING when
+ * we call issue_pending(). If there is something
+ * running on the channel already we don't change
+ * its state.
+ */
+ if (plchan->state == PL08X_CHAN_IDLE)
+ plchan->state = PL08X_CHAN_PAUSED;
+
+ /*
+ * Notice that we leave plchan->lock locked on purpose:
+ * it will be unlocked in the subsequent tx_submit()
+ * call. This is a consequence of the current API.
+ */
+
+ return 0;
+}
+
+/*
+ * Initialize a descriptor to be used by memcpy submit
+ */
+static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
+ struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+ size_t len, unsigned long flags)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+ struct pl08x_txd *txd;
+ int ret;
+
+ txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT);
+ if (!txd) {
+ dev_err(&pl08x->adev->dev,
+ "%s no memory for descriptor\n", __func__);
+ return NULL;
+ }
+
+ dma_async_tx_descriptor_init(&txd->tx, chan);
+ txd->direction = DMA_NONE;
+ txd->srcbus.addr = src;
+ txd->dstbus.addr = dest;
+
+ /* Set platform data for m2m */
+ txd->cd = &pl08x->pd->memcpy_channel;
+ /* Both to be incremented or the code will break */
+ txd->cd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR;
+ txd->tx.tx_submit = pl08x_tx_submit;
+ txd->tx.callback = NULL;
+ txd->tx.callback_param = NULL;
+ txd->len = len;
+
+ INIT_LIST_HEAD(&txd->node);
+ ret = pl08x_prep_channel_resources(plchan, txd);
+ if (ret)
+ return NULL;
+ /*
+ * NB: the channel lock is held at this point so tx_submit()
+ * must be called in direct succession.
+ */
+
+ return &txd->tx;
+}
+
+struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_data_direction direction,
+ unsigned long flags)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+ struct pl08x_txd *txd;
+ int ret;
+
+ /*
+ * Current implementation ASSUMES only one sg
+ */
+ if (sg_len != 1) {
+ dev_err(&pl08x->adev->dev, "%s prepared too long sglist\n",
+ __func__);
+ BUG();
+ }
+
+ dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
+ __func__, sgl->length, plchan->name);
+
+ txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT);
+ if (!txd) {
+ dev_err(&pl08x->adev->dev, "%s no txd\n", __func__);
+ return NULL;
+ }
+
+ dma_async_tx_descriptor_init(&txd->tx, chan);
+
+ if (direction != plchan->runtime_direction)
+ dev_err(&pl08x->adev->dev, "%s DMA setup does not match "
+ "the direction configured for the PrimeCell\n",
+ __func__);
+
+ /*
+ * Set up addresses, the PrimeCell configured address
+ * will take precedence since this may configure the
+ * channel target address dynamically at runtime.
+ */
+ txd->direction = direction;
+ if (direction == DMA_TO_DEVICE) {
+ txd->srcbus.addr = sgl->dma_address;
+ if (plchan->runtime_addr)
+ txd->dstbus.addr = plchan->runtime_addr;
+ else
+ txd->dstbus.addr = plchan->cd->addr;
+ } else if (direction == DMA_FROM_DEVICE) {
+ if (plchan->runtime_addr)
+ txd->srcbus.addr = plchan->runtime_addr;
+ else
+ txd->srcbus.addr = plchan->cd->addr;
+ txd->dstbus.addr = sgl->dma_address;
+ } else {
+ dev_err(&pl08x->adev->dev,
+ "%s direction unsupported\n", __func__);
+ return NULL;
+ }
+ txd->cd = plchan->cd;
+ txd->tx.tx_submit = pl08x_tx_submit;
+ txd->tx.callback = NULL;
+ txd->tx.callback_param = NULL;
+ txd->len = sgl->length;
+ INIT_LIST_HEAD(&txd->node);
+
+ ret = pl08x_prep_channel_resources(plchan, txd);
+ if (ret)
+ return NULL;
+ /*
+ * NB: the channel lock is held at this point so tx_submit()
+ * must be called in direct succession.
+ */
+
+ return &txd->tx;
+}
+
+static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+ unsigned long flags;
+ int ret = 0;
+
+ /* Controls applicable to inactive channels */
+ if (cmd == DMA_SLAVE_CONFIG) {
+ dma_set_runtime_config(chan,
+ (struct dma_slave_config *)
+ arg);
+ return 0;
+ }
+
+ /*
+ * Anything succeeds on channels with no physical allocation and
+ * no queued transfers.
+ */
+ spin_lock_irqsave(&plchan->lock, flags);
+ if (!plchan->phychan && !plchan->at) {
+ spin_unlock_irqrestore(&plchan->lock, flags);
+ return 0;
+ }
+
+ switch (cmd) {
+ case DMA_TERMINATE_ALL:
+ plchan->state = PL08X_CHAN_IDLE;
+
+ if (plchan->phychan) {
+ pl08x_stop_phy_chan(plchan->phychan);
+
+ /*
+ * Mark physical channel as free and free any slave
+ * signal
+ */
+ if ((plchan->phychan->signal >= 0) &&
+ pl08x->pd->put_signal) {
+ pl08x->pd->put_signal(plchan);
+ plchan->phychan->signal = -1;
+ }
+ pl08x_put_phy_channel(pl08x, plchan->phychan);
+ plchan->phychan = NULL;
+ }
+ /* Stop any pending tasklet */
+ tasklet_disable(&plchan->tasklet);
+ /* Dequeue jobs and free LLIs */
+ if (plchan->at) {
+ pl08x_free_txd(pl08x, plchan->at);
+ plchan->at = NULL;
+ }
+ /* Dequeue jobs not yet fired as well */
+ pl08x_free_txd_list(pl08x, plchan);
+ break;
+ case DMA_PAUSE:
+ pl08x_pause_phy_chan(plchan->phychan);
+ plchan->state = PL08X_CHAN_PAUSED;
+ break;
+ case DMA_RESUME:
+ pl08x_resume_phy_chan(plchan->phychan);
+ plchan->state = PL08X_CHAN_RUNNING;
+ break;
+ default:
+ /* Unknown command */
+ ret = -ENXIO;
+ break;
+ }
+
+ spin_unlock_irqrestore(&plchan->lock, flags);
+
+ return ret;
+}
+
+bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ char *name = chan_id;
+
+ /* Check that the channel is not taken! */
+ if (!strcmp(plchan->name, name))
+ return true;
+
+ return false;
+}
+
+/*
+ * Just check that the device is there and active
+ * TODO: turn this bit on/off depending on the number of
+ * physical channels actually used, if it is zero... well
+ * shut it off. That will save some power. Cut the clock
+ * at the same time.
+ */
+static void pl08x_ensure_on(struct pl08x_driver_data *pl08x)
+{
+ u32 val;
+
+ val = readl(pl08x->base + PL080_CONFIG);
+ val &= ~(PL080_CONFIG_M2_BE | PL080_CONFIG_M1_BE | PL080_CONFIG_ENABLE);
+ /* We implictly clear bit 1 and that means little-endian mode */
+ val |= PL080_CONFIG_ENABLE;
+ writel(val, pl08x->base + PL080_CONFIG);
+}
+
+static void pl08x_tasklet(unsigned long data)
+{
+ struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data;
+ struct pl08x_phy_chan *phychan = plchan->phychan;
+ struct pl08x_driver_data *pl08x = plchan->host;
+
+ if (!plchan)
+ BUG();
+
+ spin_lock(&plchan->lock);
+
+ if (plchan->at) {
+ dma_async_tx_callback callback =
+ plchan->at->tx.callback;
+ void *callback_param =
+ plchan->at->tx.callback_param;
+
+ /*
+ * Update last completed
+ */
+ plchan->lc =
+ (plchan->at->tx.cookie);
+
+ /*
+ * Callback to signal completion
+ */
+ if (callback)
+ callback(callback_param);
+
+ /*
+ * Device callbacks should NOT clear
+ * the current transaction on the channel
+ * Linus: sometimes they should?
+ */
+ if (!plchan->at)
+ BUG();
+
+ /*
+ * Free the descriptor if it's not for a device
+ * using a circular buffer
+ */
+ if (!plchan->at->cd->circular_buffer) {
+ pl08x_free_txd(pl08x, plchan->at);
+ plchan->at = NULL;
+ }
+ /*
+ * else descriptor for circular
+ * buffers only freed when
+ * client has disabled dma
+ */
+ }
+ /*
+ * If a new descriptor is queued, set it up
+ * plchan->at is NULL here
+ */
+ if (!list_empty(&plchan->desc_list)) {
+ struct pl08x_txd *next;
+
+ next = list_first_entry(&plchan->desc_list,
+ struct pl08x_txd,
+ node);
+ list_del(&next->node);
+ plchan->at = next;
+ /* Configure the physical channel for the next txd */
+ pl08x_config_phychan_for_txd(plchan);
+ pl08x_set_cregs(pl08x, plchan->phychan);
+ pl08x_enable_phy_chan(pl08x, plchan->phychan);
+ } else {
+ struct pl08x_dma_chan *waiting = NULL;
+
+ /*
+ * No more jobs, so free up the physical channel
+ * Free any allocated signal on slave transfers too
+ */
+ if ((phychan->signal >= 0) && pl08x->pd->put_signal) {
+ pl08x->pd->put_signal(plchan);
+ phychan->signal = -1;
+ }
+ pl08x_put_phy_channel(pl08x, phychan);
+ plchan->phychan = NULL;
+ plchan->state = PL08X_CHAN_IDLE;
+
+ /*
+ * And NOW before anyone else can grab that free:d
+ * up physical channel, see if there is some memcpy
+ * pending that seriously needs to start because of
+ * being stacked up while we were choking the
+ * physical channels with data.
+ */
+ list_for_each_entry(waiting, &pl08x->memcpy.channels,
+ chan.device_node) {
+ if (waiting->state == PL08X_CHAN_WAITING &&
+ waiting->waiting != NULL) {
+ int ret;
+
+ /* This should REALLY not fail now */
+ ret = prep_phy_channel(waiting,
+ waiting->waiting);
+ BUG_ON(ret);
+ waiting->state = PL08X_CHAN_RUNNING;
+ waiting->waiting = NULL;
+ pl08x_issue_pending(&waiting->chan);
+ break;
+ }
+ }
+ }
+
+ spin_unlock(&plchan->lock);
+}
+
+static irqreturn_t pl08x_irq(int irq, void *dev)
+{
+ struct pl08x_driver_data *pl08x = dev;
+ u32 mask = 0;
+ u32 val;
+ int i;
+
+ val = readl(pl08x->base + PL080_ERR_STATUS);
+ if (val) {
+ /*
+ * An error interrupt (on one or more channels)
+ */
+ dev_err(&pl08x->adev->dev,
+ "%s error interrupt, register value 0x%08x\n",
+ __func__, val);
+ /*
+ * Simply clear ALL PL08X error interrupts,
+ * regardless of channel and cause
+ * FIXME: should be 0x00000003 on PL081 really.
+ */
+ writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR);
+ }
+ val = readl(pl08x->base + PL080_INT_STATUS);
+ for (i = 0; i < pl08x->vd->channels; i++) {
+ if ((1 << i) & val) {
+ /* Locate physical channel */
+ struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i];
+ struct pl08x_dma_chan *plchan = phychan->serving;
+
+ /* Schedule tasklet on this channel */
+ tasklet_schedule(&plchan->tasklet);
+
+ mask |= (1 << i);
+ }
+ }
+ /*
+ * Clear only the terminal interrupts on channels we processed
+ */
+ writel(mask, pl08x->base + PL080_TC_CLEAR);
+
+ return mask ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*
+ * Initialise the DMAC memcpy/slave channels.
+ * Make a local wrapper to hold required data
+ */
+static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
+ struct dma_device *dmadev,
+ unsigned int channels,
+ bool slave)
+{
+ struct pl08x_dma_chan *chan;
+ int i;
+
+ INIT_LIST_HEAD(&dmadev->channels);
+ /*
+ * Register as many many memcpy as we have physical channels,
+ * we won't always be able to use all but the code will have
+ * to cope with that situation.
+ */
+ for (i = 0; i < channels; i++) {
+ chan = kzalloc(sizeof(struct pl08x_dma_chan), GFP_KERNEL);
+ if (!chan) {
+ dev_err(&pl08x->adev->dev,
+ "%s no memory for channel\n", __func__);
+ return -ENOMEM;
+ }
+
+ chan->host = pl08x;
+ chan->state = PL08X_CHAN_IDLE;
+
+ if (slave) {
+ chan->slave = true;
+ chan->name = pl08x->pd->slave_channels[i].bus_id;
+ chan->cd = &pl08x->pd->slave_channels[i];
+ } else {
+ chan->cd = &pl08x->pd->memcpy_channel;
+ chan->name = kasprintf(GFP_KERNEL, "memcpy%d", i);
+ if (!chan->name) {
+ kfree(chan);
+ return -ENOMEM;
+ }
+ }
+ dev_info(&pl08x->adev->dev,
+ "initialize virtual channel \"%s\"\n",
+ chan->name);
+
+ chan->chan.device = dmadev;
+ atomic_set(&chan->last_issued, 0);
+ chan->lc = atomic_read(&chan->last_issued);
+
+ spin_lock_init(&chan->lock);
+ INIT_LIST_HEAD(&chan->desc_list);
+ tasklet_init(&chan->tasklet, pl08x_tasklet,
+ (unsigned long) chan);
+
+ list_add_tail(&chan->chan.device_node, &dmadev->channels);
+ }
+ dev_info(&pl08x->adev->dev, "initialized %d virtual %s channels\n",
+ i, slave ? "slave" : "memcpy");
+ return i;
+}
+
+static void pl08x_free_virtual_channels(struct dma_device *dmadev)
+{
+ struct pl08x_dma_chan *chan = NULL;
+ struct pl08x_dma_chan *next;
+
+ list_for_each_entry_safe(chan,
+ next, &dmadev->channels, chan.device_node) {
+ list_del(&chan->chan.device_node);
+ kfree(chan);
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+static const char *pl08x_state_str(enum pl08x_dma_chan_state state)
+{
+ switch (state) {
+ case PL08X_CHAN_IDLE:
+ return "idle";
+ case PL08X_CHAN_RUNNING:
+ return "running";
+ case PL08X_CHAN_PAUSED:
+ return "paused";
+ case PL08X_CHAN_WAITING:
+ return "waiting";
+ default:
+ break;
+ }
+ return "UNKNOWN STATE";
+}
+
+static int pl08x_debugfs_show(struct seq_file *s, void *data)
+{
+ struct pl08x_driver_data *pl08x = s->private;
+ struct pl08x_dma_chan *chan;
+ struct pl08x_phy_chan *ch;
+ unsigned long flags;
+ int i;
+
+ seq_printf(s, "PL08x physical channels:\n");
+ seq_printf(s, "CHANNEL:\tUSER:\n");
+ seq_printf(s, "--------\t-----\n");
+ for (i = 0; i < pl08x->vd->channels; i++) {
+ struct pl08x_dma_chan *virt_chan;
+
+ ch = &pl08x->phy_chans[i];
+
+ spin_lock_irqsave(&ch->lock, flags);
+ virt_chan = ch->serving;
+
+ seq_printf(s, "%d\t\t%s\n",
+ ch->id, virt_chan ? virt_chan->name : "(none)");
+
+ spin_unlock_irqrestore(&ch->lock, flags);
+ }
+
+ seq_printf(s, "\nPL08x virtual memcpy channels:\n");
+ seq_printf(s, "CHANNEL:\tSTATE:\n");
+ seq_printf(s, "--------\t------\n");
+ list_for_each_entry(chan, &pl08x->memcpy.channels, chan.device_node) {
+ seq_printf(s, "%s\t\t\%s\n", chan->name,
+ pl08x_state_str(chan->state));
+ }
+
+ seq_printf(s, "\nPL08x virtual slave channels:\n");
+ seq_printf(s, "CHANNEL:\tSTATE:\n");
+ seq_printf(s, "--------\t------\n");
+ list_for_each_entry(chan, &pl08x->slave.channels, chan.device_node) {
+ seq_printf(s, "%s\t\t\%s\n", chan->name,
+ pl08x_state_str(chan->state));
+ }
+
+ return 0;
+}
+
+static int pl08x_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pl08x_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations pl08x_debugfs_operations = {
+ .open = pl08x_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
+{
+ /* Expose a simple debugfs interface to view all clocks */
+ (void) debugfs_create_file(dev_name(&pl08x->adev->dev), S_IFREG | S_IRUGO,
+ NULL, pl08x,
+ &pl08x_debugfs_operations);
+}
+
+#else
+static inline void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
+{
+}
+#endif
+
+static int pl08x_probe(struct amba_device *adev, struct amba_id *id)
+{
+ struct pl08x_driver_data *pl08x;
+ struct vendor_data *vd = id->data;
+ int ret = 0;
+ int i;
+
+ ret = amba_request_regions(adev, NULL);
+ if (ret)
+ return ret;
+
+ /* Create the driver state holder */
+ pl08x = kzalloc(sizeof(struct pl08x_driver_data), GFP_KERNEL);
+ if (!pl08x) {
+ ret = -ENOMEM;
+ goto out_no_pl08x;
+ }
+
+ /* Initialize memcpy engine */
+ dma_cap_set(DMA_MEMCPY, pl08x->memcpy.cap_mask);
+ pl08x->memcpy.dev = &adev->dev;
+ pl08x->memcpy.device_alloc_chan_resources = pl08x_alloc_chan_resources;
+ pl08x->memcpy.device_free_chan_resources = pl08x_free_chan_resources;
+ pl08x->memcpy.device_prep_dma_memcpy = pl08x_prep_dma_memcpy;
+ pl08x->memcpy.device_prep_dma_interrupt = pl08x_prep_dma_interrupt;
+ pl08x->memcpy.device_tx_status = pl08x_dma_tx_status;
+ pl08x->memcpy.device_issue_pending = pl08x_issue_pending;
+ pl08x->memcpy.device_control = pl08x_control;
+
+ /* Initialize slave engine */
+ dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
+ pl08x->slave.dev = &adev->dev;
+ pl08x->slave.device_alloc_chan_resources = pl08x_alloc_chan_resources;
+ pl08x->slave.device_free_chan_resources = pl08x_free_chan_resources;
+ pl08x->slave.device_prep_dma_interrupt = pl08x_prep_dma_interrupt;
+ pl08x->slave.device_tx_status = pl08x_dma_tx_status;
+ pl08x->slave.device_issue_pending = pl08x_issue_pending;
+ pl08x->slave.device_prep_slave_sg = pl08x_prep_slave_sg;
+ pl08x->slave.device_control = pl08x_control;
+
+ /* Get the platform data */
+ pl08x->pd = dev_get_platdata(&adev->dev);
+ if (!pl08x->pd) {
+ dev_err(&adev->dev, "no platform data supplied\n");
+ goto out_no_platdata;
+ }
+
+ /* Assign useful pointers to the driver state */
+ pl08x->adev = adev;
+ pl08x->vd = vd;
+
+ /* A DMA memory pool for LLIs, align on 1-byte boundary */
+ pl08x->pool = dma_pool_create(DRIVER_NAME, &pl08x->adev->dev,
+ PL08X_LLI_TSFR_SIZE, PL08X_ALIGN, 0);
+ if (!pl08x->pool) {
+ ret = -ENOMEM;
+ goto out_no_lli_pool;
+ }
+
+ spin_lock_init(&pl08x->lock);
+
+ pl08x->base = ioremap(adev->res.start, resource_size(&adev->res));
+ if (!pl08x->base) {
+ ret = -ENOMEM;
+ goto out_no_ioremap;
+ }
+
+ /* Turn on the PL08x */
+ pl08x_ensure_on(pl08x);
+
+ /*
+ * Attach the interrupt handler
+ */
+ writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR);
+ writel(0x000000FF, pl08x->base + PL080_TC_CLEAR);
+
+ ret = request_irq(adev->irq[0], pl08x_irq, IRQF_DISABLED,
+ vd->name, pl08x);
+ if (ret) {
+ dev_err(&adev->dev, "%s failed to request interrupt %d\n",
+ __func__, adev->irq[0]);
+ goto out_no_irq;
+ }
+
+ /* Initialize physical channels */
+ pl08x->phy_chans = kmalloc((vd->channels * sizeof(struct pl08x_phy_chan)),
+ GFP_KERNEL);
+ if (!pl08x->phy_chans) {
+ dev_err(&adev->dev, "%s failed to allocate "
+ "physical channel holders\n",
+ __func__);
+ goto out_no_phychans;
+ }
+
+ for (i = 0; i < vd->channels; i++) {
+ struct pl08x_phy_chan *ch = &pl08x->phy_chans[i];
+
+ ch->id = i;
+ ch->base = pl08x->base + PL080_Cx_BASE(i);
+ spin_lock_init(&ch->lock);
+ ch->serving = NULL;
+ ch->signal = -1;
+ dev_info(&adev->dev,
+ "physical channel %d is %s\n", i,
+ pl08x_phy_channel_busy(ch) ? "BUSY" : "FREE");
+ }
+
+ /* Register as many memcpy channels as there are physical channels */
+ ret = pl08x_dma_init_virtual_channels(pl08x, &pl08x->memcpy,
+ pl08x->vd->channels, false);
+ if (ret <= 0) {
+ dev_warn(&pl08x->adev->dev,
+ "%s failed to enumerate memcpy channels - %d\n",
+ __func__, ret);
+ goto out_no_memcpy;
+ }
+ pl08x->memcpy.chancnt = ret;
+
+ /* Register slave channels */
+ ret = pl08x_dma_init_virtual_channels(pl08x, &pl08x->slave,
+ pl08x->pd->num_slave_channels,
+ true);
+ if (ret <= 0) {
+ dev_warn(&pl08x->adev->dev,
+ "%s failed to enumerate slave channels - %d\n",
+ __func__, ret);
+ goto out_no_slave;
+ }
+ pl08x->slave.chancnt = ret;
+
+ ret = dma_async_device_register(&pl08x->memcpy);
+ if (ret) {
+ dev_warn(&pl08x->adev->dev,
+ "%s failed to register memcpy as an async device - %d\n",
+ __func__, ret);
+ goto out_no_memcpy_reg;
+ }
+
+ ret = dma_async_device_register(&pl08x->slave);
+ if (ret) {
+ dev_warn(&pl08x->adev->dev,
+ "%s failed to register slave as an async device - %d\n",
+ __func__, ret);
+ goto out_no_slave_reg;
+ }
+
+ amba_set_drvdata(adev, pl08x);
+ init_pl08x_debugfs(pl08x);
+ dev_info(&pl08x->adev->dev, "ARM(R) %s DMA block initialized @%08x\n",
+ vd->name, adev->res.start);
+ return 0;
+
+out_no_slave_reg:
+ dma_async_device_unregister(&pl08x->memcpy);
+out_no_memcpy_reg:
+ pl08x_free_virtual_channels(&pl08x->slave);
+out_no_slave:
+ pl08x_free_virtual_channels(&pl08x->memcpy);
+out_no_memcpy:
+ kfree(pl08x->phy_chans);
+out_no_phychans:
+ free_irq(adev->irq[0], pl08x);
+out_no_irq:
+ iounmap(pl08x->base);
+out_no_ioremap:
+ dma_pool_destroy(pl08x->pool);
+out_no_lli_pool:
+out_no_platdata:
+ kfree(pl08x);
+out_no_pl08x:
+ amba_release_regions(adev);
+ return ret;
+}
+
+/* PL080 has 8 channels and the PL080 have just 2 */
+static struct vendor_data vendor_pl080 = {
+ .name = "PL080",
+ .channels = 8,
+ .dualmaster = true,
+};
+
+static struct vendor_data vendor_pl081 = {
+ .name = "PL081",
+ .channels = 2,
+ .dualmaster = false,
+};
+
+static struct amba_id pl08x_ids[] = {
+ /* PL080 */
+ {
+ .id = 0x00041080,
+ .mask = 0x000fffff,
+ .data = &vendor_pl080,
+ },
+ /* PL081 */
+ {
+ .id = 0x00041081,
+ .mask = 0x000fffff,
+ .data = &vendor_pl081,
+ },
+ /* Nomadik 8815 PL080 variant */
+ {
+ .id = 0x00280880,
+ .mask = 0x00ffffff,
+ .data = &vendor_pl080,
+ },
+ { 0, 0 },
+};
+
+static struct amba_driver pl08x_amba_driver = {
+ .drv.name = DRIVER_NAME,
+ .id_table = pl08x_ids,
+ .probe = pl08x_probe,
+};
+
+static int __init pl08x_init(void)
+{
+ int retval;
+ retval = amba_driver_register(&pl08x_amba_driver);
+ if (retval)
+ printk(KERN_WARNING DRIVER_NAME
+ "failed to register as an amba device (%d)\n",
+ retval);
+ return retval;
+}
+subsys_initcall(pl08x_init);
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index a724e6be1b4..557e2272e5b 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -72,6 +72,9 @@ struct coh901318_chan {
unsigned long nbr_active_done;
unsigned long busy;
+ u32 runtime_addr;
+ u32 runtime_ctrl;
+
struct coh901318_base *base;
};
@@ -190,6 +193,9 @@ static inline struct coh901318_chan *to_coh901318_chan(struct dma_chan *chan)
static inline dma_addr_t
cohc_dev_addr(struct coh901318_chan *cohc)
{
+ /* Runtime supplied address will take precedence */
+ if (cohc->runtime_addr)
+ return cohc->runtime_addr;
return cohc->base->platform->chan_conf[cohc->id].dev_addr;
}
@@ -1055,6 +1061,14 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
params = cohc_chan_param(cohc);
config = params->config;
+ /*
+ * Add runtime-specific control on top, make
+ * sure the bits you set per peripheral channel are
+ * cleared in the default config from the platform.
+ */
+ ctrl_chained |= cohc->runtime_ctrl;
+ ctrl_last |= cohc->runtime_ctrl;
+ ctrl |= cohc->runtime_ctrl;
if (direction == DMA_TO_DEVICE) {
u32 tx_flags = COH901318_CX_CTRL_PRDD_SOURCE |
@@ -1113,6 +1127,12 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
if (ret)
goto err_lli_fill;
+ /*
+ * Set the default ctrl for the channel to the one from the lli,
+ * things may have changed due to odd buffer alignment etc.
+ */
+ coh901318_set_ctrl(cohc, lli->control);
+
COH_DBG(coh901318_list_print(cohc, lli));
/* Pick a descriptor to handle this transfer */
@@ -1175,6 +1195,146 @@ coh901318_issue_pending(struct dma_chan *chan)
spin_unlock_irqrestore(&cohc->lock, flags);
}
+/*
+ * Here we wrap in the runtime dma control interface
+ */
+struct burst_table {
+ int burst_8bit;
+ int burst_16bit;
+ int burst_32bit;
+ u32 reg;
+};
+
+static const struct burst_table burst_sizes[] = {
+ {
+ .burst_8bit = 64,
+ .burst_16bit = 32,
+ .burst_32bit = 16,
+ .reg = COH901318_CX_CTRL_BURST_COUNT_64_BYTES,
+ },
+ {
+ .burst_8bit = 48,
+ .burst_16bit = 24,
+ .burst_32bit = 12,
+ .reg = COH901318_CX_CTRL_BURST_COUNT_48_BYTES,
+ },
+ {
+ .burst_8bit = 32,
+ .burst_16bit = 16,
+ .burst_32bit = 8,
+ .reg = COH901318_CX_CTRL_BURST_COUNT_32_BYTES,
+ },
+ {
+ .burst_8bit = 16,
+ .burst_16bit = 8,
+ .burst_32bit = 4,
+ .reg = COH901318_CX_CTRL_BURST_COUNT_16_BYTES,
+ },
+ {
+ .burst_8bit = 8,
+ .burst_16bit = 4,
+ .burst_32bit = 2,
+ .reg = COH901318_CX_CTRL_BURST_COUNT_8_BYTES,
+ },
+ {
+ .burst_8bit = 4,
+ .burst_16bit = 2,
+ .burst_32bit = 1,
+ .reg = COH901318_CX_CTRL_BURST_COUNT_4_BYTES,
+ },
+ {
+ .burst_8bit = 2,
+ .burst_16bit = 1,
+ .burst_32bit = 0,
+ .reg = COH901318_CX_CTRL_BURST_COUNT_2_BYTES,
+ },
+ {
+ .burst_8bit = 1,
+ .burst_16bit = 0,
+ .burst_32bit = 0,
+ .reg = COH901318_CX_CTRL_BURST_COUNT_1_BYTE,
+ },
+};
+
+static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct coh901318_chan *cohc = to_coh901318_chan(chan);
+ dma_addr_t addr;
+ enum dma_slave_buswidth addr_width;
+ u32 maxburst;
+ u32 runtime_ctrl = 0;
+ int i = 0;
+
+ /* We only support mem to per or per to mem transfers */
+ if (config->direction == DMA_FROM_DEVICE) {
+ addr = config->src_addr;
+ addr_width = config->src_addr_width;
+ maxburst = config->src_maxburst;
+ } else if (config->direction == DMA_TO_DEVICE) {
+ addr = config->dst_addr;
+ addr_width = config->dst_addr_width;
+ maxburst = config->dst_maxburst;
+ } else {
+ dev_err(COHC_2_DEV(cohc), "illegal channel mode\n");
+ return;
+ }
+
+ dev_dbg(COHC_2_DEV(cohc), "configure channel for %d byte transfers\n",
+ addr_width);
+ switch (addr_width) {
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ runtime_ctrl |=
+ COH901318_CX_CTRL_SRC_BUS_SIZE_8_BITS |
+ COH901318_CX_CTRL_DST_BUS_SIZE_8_BITS;
+
+ while (i < ARRAY_SIZE(burst_sizes)) {
+ if (burst_sizes[i].burst_8bit <= maxburst)
+ break;
+ i++;
+ }
+
+ break;
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ runtime_ctrl |=
+ COH901318_CX_CTRL_SRC_BUS_SIZE_16_BITS |
+ COH901318_CX_CTRL_DST_BUS_SIZE_16_BITS;
+
+ while (i < ARRAY_SIZE(burst_sizes)) {
+ if (burst_sizes[i].burst_16bit <= maxburst)
+ break;
+ i++;
+ }
+
+ break;
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ /* Direction doesn't matter here, it's 32/32 bits */
+ runtime_ctrl |=
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS;
+
+ while (i < ARRAY_SIZE(burst_sizes)) {
+ if (burst_sizes[i].burst_32bit <= maxburst)
+ break;
+ i++;
+ }
+
+ break;
+ default:
+ dev_err(COHC_2_DEV(cohc),
+ "bad runtimeconfig: alien address width\n");
+ return;
+ }
+
+ runtime_ctrl |= burst_sizes[i].reg;
+ dev_dbg(COHC_2_DEV(cohc),
+ "selected burst size %d bytes for address width %d bytes, maxburst %d\n",
+ burst_sizes[i].burst_8bit, addr_width, maxburst);
+
+ cohc->runtime_addr = addr;
+ cohc->runtime_ctrl = runtime_ctrl;
+}
+
static int
coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
unsigned long arg)
@@ -1184,6 +1344,14 @@ coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
struct coh901318_desc *cohd;
void __iomem *virtbase = cohc->base->virtbase;
+ if (cmd == DMA_SLAVE_CONFIG) {
+ struct dma_slave_config *config =
+ (struct dma_slave_config *) arg;
+
+ coh901318_dma_set_runtimeconfig(chan, config);
+ return 0;
+ }
+
if (cmd == DMA_PAUSE) {
coh901318_pause(chan);
return 0;
@@ -1240,6 +1408,7 @@ coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
return 0;
}
+
void coh901318_base_init(struct dma_device *dma, const int *pick_chans,
struct coh901318_base *base)
{
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 9d31d5eb95c..7eced641ae7 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -702,7 +702,7 @@ int dma_async_device_register(struct dma_device *device)
BUG_ON(!device->dev);
/* note: this only matters in the
- * CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH=y case
+ * CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=n case
*/
if (device_has_all_tx_types(device))
dma_cap_set(DMA_ASYNC_TX, device->cap_mask);
@@ -976,7 +976,7 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
struct dma_chan *chan)
{
tx->chan = chan;
- #ifndef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH
+ #ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
spin_lock_init(&tx->lock);
#endif
}
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index c426829f6ab..c95c1dee71b 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -1,24 +1,33 @@
/*
- * driver/dma/ste_dma40.c
- *
- * Copyright (C) ST-Ericsson 2007-2010
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
- *
*/
#include <linux/kernel.h>
-#include <linux/slab.h>
#include <linux/dmaengine.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/pm.h>
+#include <linux/err.h>
+
+#include <asm/atomic.h>
#include <plat/ste_dma40.h>
#include "ste_dma40_ll.h"
+#ifdef CONFIG_STE_DMA40_DEBUG
+#include "ste_dma40_debug.h"
+#define MARK sted40_history_text((char *)__func__)
+#else
+#define MARK
+#endif
+
#define D40_NAME "dma40"
#define D40_PHY_CHAN -1
@@ -30,14 +39,21 @@
/* Maximum iterations taken before giving up suspending a channel */
#define D40_SUSPEND_MAX_IT 500
+/* Hardware requirement on LCLA alignment */
+#define LCLA_ALIGNMENT 0x40000
+
+/* Max number of links per event group */
+#define D40_LCLA_LINK_PER_EVENT_GRP 128
+#define D40_LCLA_END D40_LCLA_LINK_PER_EVENT_GRP
+
+/* Attempts before giving up to trying to get pages that are aligned */
+#define MAX_LCLA_ALLOC_ATTEMPTS 256
+
+/* Bit markings for allocation map */
#define D40_ALLOC_FREE (1 << 31)
#define D40_ALLOC_PHY (1 << 30)
#define D40_ALLOC_LOG_FREE 0
-/* The number of free d40_desc to keep in memory before starting
- * to kfree() them */
-#define D40_DESC_CACHE_SIZE 50
-
/* Hardware designer of the block */
#define D40_PERIPHID2_DESIGNER 0x8
@@ -56,6 +72,31 @@ enum d40_command {
D40_DMA_SUSPENDED = 3
};
+/*
+ * These are the registers that has to be saved and later restored
+ * when the DMA hw is powered off.
+ */
+static u32 d40_backup_regs[] = {
+ D40_DREG_GCC,
+ D40_DREG_LCPA,
+ D40_DREG_LCLA,
+ D40_DREG_PRMSE,
+ D40_DREG_PRMSO,
+ D40_DREG_PRMOE,
+ D40_DREG_PRMOO,
+};
+
+static u32 d40_backup_regs_chan[] = {
+ D40_CHAN_REG_SSCFG,
+ D40_CHAN_REG_SSELT,
+ D40_CHAN_REG_SSPTR,
+ D40_CHAN_REG_SSLNK,
+ D40_CHAN_REG_SDCFG,
+ D40_CHAN_REG_SDELT,
+ D40_CHAN_REG_SDPTR,
+ D40_CHAN_REG_SDLNK,
+};
+
/**
* struct d40_lli_pool - Structure for keeping LLIs in memory
*
@@ -68,9 +109,9 @@ enum d40_command {
*/
struct d40_lli_pool {
void *base;
- int size;
+ int size;
/* Space for dst and src, plus an extra for padding */
- u8 pre_alloc_lli[3 * sizeof(struct d40_phy_lli)];
+ u8 pre_alloc_lli[3 * sizeof(struct d40_phy_lli)];
};
/**
@@ -80,54 +121,58 @@ struct d40_lli_pool {
* points into the lli_pool, to base if lli_len > 1 or to pre_alloc_lli if
* lli_len equals one.
* @lli_log: Same as above but for logical channels.
+ * @last_lcla: lcla used for last link (logical channels)
* @lli_pool: The pool with two entries pre-allocated.
- * @lli_len: Number of LLI's in lli_pool
- * @lli_tcount: Number of LLIs processed in the transfer. When equals lli_len
- * then this transfer job is done.
+ * @lli_len: Number of llis of current descriptor.
+ * @lli_current: Number of transfered llis.
+ * @lcla_alloc: Number of LCLA entries allocated.
* @txd: DMA engine struct. Used for among other things for communication
* during a transfer.
* @node: List entry.
- * @dir: The transfer direction of this job.
* @is_in_client_list: true if the client owns this descriptor.
+ * @is_hw_linked: true if this job will automatically be continued for
+ * the previous one.
+ * @cyclic: true if this is a cyclic job
*
* This descriptor is used for both logical and physical transfers.
*/
-
struct d40_desc {
/* LLI physical */
struct d40_phy_lli_bidir lli_phy;
/* LLI logical */
struct d40_log_lli_bidir lli_log;
+ struct d40_log_lli *last_lcla;
struct d40_lli_pool lli_pool;
- u32 lli_len;
- u32 lli_tcount;
+ int lli_len;
+ int lli_current;
+ int lcla_alloc;
struct dma_async_tx_descriptor txd;
struct list_head node;
- enum dma_data_direction dir;
bool is_in_client_list;
+ bool is_hw_linked;
+ bool cyclic;
};
/**
* struct d40_lcla_pool - LCLA pool settings and data.
*
- * @base: The virtual address of LCLA.
- * @phy: Physical base address of LCLA.
- * @base_size: size of lcla.
+ * @base: The virtual address of LCLA. 18 bit aligned.
+ * @base_unaligned: The orignal kmalloc pointer, if kmalloc is used.
+ * This pointer is only there for clean-up on error.
+ * @pages: The number of pages needed for all physical channels.
+ * Only used later for clean-up on error
* @lock: Lock to protect the content in this struct.
- * @alloc_map: Mapping between physical channel and LCLA entries.
- * @num_blocks: The number of entries of alloc_map. Equals to the
- * number of physical channels.
+ * @alloc_map: big map over which LCLA entry is own by which job.
*/
struct d40_lcla_pool {
void *base;
- dma_addr_t phy;
- resource_size_t base_size;
+ void *base_unaligned;
+ int pages;
spinlock_t lock;
- u32 *alloc_map;
- int num_blocks;
+ struct d40_desc **alloc_map;
};
/**
@@ -140,9 +185,7 @@ struct d40_lcla_pool {
* this physical channel. Can also be free or physically allocated.
* @allocated_dst: Same as for src but is dst.
* allocated_dst and allocated_src uses the D40_ALLOC* defines as well as
- * event line number. Both allocated_src and allocated_dst can not be
- * allocated to a physical channel, since the interrupt handler has then
- * no way of figure out which one the interrupt belongs to.
+ * event line number.
*/
struct d40_phy_res {
spinlock_t lock;
@@ -163,22 +206,25 @@ struct d40_base;
* @pending_tx: The number of pending transfers. Used between interrupt handler
* and tasklet.
* @busy: Set to true when transfer is ongoing on this channel.
- * @phy_chan: Pointer to physical channel which this instance runs on.
+ * @phy_chan: Pointer to physical channel which this instance runs on. If this
+ * point is NULL, then the channel is not allocated.
* @chan: DMA engine handle.
* @tasklet: Tasklet that gets scheduled from interrupt context to complete a
* transfer and call client callback.
* @client: Cliented owned descriptor list.
* @active: Active descriptor.
+ * @done: Completed jobs
* @queue: Queued jobs.
- * @free: List of free descripts, ready to be reused.
- * @free_len: Number of descriptors in the free list.
* @dma_cfg: The client configuration of this dma channel.
+ * @configured: whether the dma_cfg configuration is valid
* @base: Pointer to the device instance struct.
+ * @cdesc: Cyclic descriptor
* @src_def_cfg: Default cfg register setting for src.
* @dst_def_cfg: Default cfg register setting for dst.
* @log_def: Default logical channel settings.
- * @lcla: Space for one dst src pair for logical channel transfers.
* @lcpa: Pointer to dst and src lcpa settings.
+ * @src_dev_addr: device source address for the channel transfer.
+ * @dst_dev_addr: device destination address for the channel transfer.
*
* This struct can either "be" a logical or a physical channel.
*/
@@ -194,17 +240,19 @@ struct d40_chan {
struct tasklet_struct tasklet;
struct list_head client;
struct list_head active;
+ struct list_head done;
struct list_head queue;
- struct list_head free;
- int free_len;
struct stedma40_chan_cfg dma_cfg;
+ bool configured;
struct d40_base *base;
+ struct stedma40_cyclic_desc *cdesc;
/* Default register configurations */
u32 src_def_cfg;
u32 dst_def_cfg;
struct d40_def_lcsp log_def;
- struct d40_lcla_elem lcla;
struct d40_log_lli_full *lcpa;
+ dma_addr_t src_dev_addr;
+ dma_addr_t dst_dev_addr;
};
/**
@@ -213,8 +261,12 @@ struct d40_chan {
* @interrupt_lock: Lock used to make sure one interrupt is handle a time.
* @execmd_lock: Lock for execute command usage since several channels share
* the same physical register.
+ * @pm_gcc_lock: global clock control lock. Lock used when modifying the
+ * clocking of different parts of the DMA block. Used for limiting the
+ * power usage.
* @dev: The device structure.
* @virtbase: The virtual base address of the DMA's register.
+ * @rev: silicon revision detected.
* @clk: Pointer to the DMA clock structure.
* @phy_start: Physical memory start of the DMA registers.
* @phy_size: Size of the DMA register map.
@@ -240,12 +292,20 @@ struct d40_chan {
* @lcpa_base: The virtual mapped address of LCPA.
* @phy_lcpa: The physical address of the LCPA.
* @lcpa_size: The size of the LCPA area.
+ * @desc_slab: cache for descriptors.
+ * @usage: The number of dma executions. Used by suspend to determite if
+ * the dma can suspend or not.
+ * @reg_val_backup: Here the values of some hardware registers are stored
+ * before the DMA is powered off. They are restored when the power is back on.
+ * @reg_val_backup_chan: Backup data for standard channel parameter registers.
*/
struct d40_base {
spinlock_t interrupt_lock;
spinlock_t execmd_lock;
+ spinlock_t pm_gcc_lock;
struct device *dev;
void __iomem *virtbase;
+ u8 rev:4;
struct clk *clk;
phys_addr_t phy_start;
resource_size_t phy_size;
@@ -266,6 +326,11 @@ struct d40_base {
void *lcpa_base;
dma_addr_t phy_lcpa;
resource_size_t lcpa_size;
+ struct kmem_cache *desc_slab;
+ atomic_t usage;
+ u32 reg_val_backup
+ [ARRAY_SIZE(d40_backup_regs)];
+ u32 *reg_val_backup_chan;
};
/**
@@ -330,9 +395,6 @@ static int d40_pool_lli_alloc(struct d40_desc *d40d,
align);
d40d->lli_phy.dst = PTR_ALIGN(d40d->lli_phy.src + lli_len,
align);
-
- d40d->lli_phy.src_addr = virt_to_phys(d40d->lli_phy.src);
- d40d->lli_phy.dst_addr = virt_to_phys(d40d->lli_phy.dst);
}
return 0;
@@ -347,27 +409,67 @@ static void d40_pool_lli_free(struct d40_desc *d40d)
d40d->lli_log.dst = NULL;
d40d->lli_phy.src = NULL;
d40d->lli_phy.dst = NULL;
- d40d->lli_phy.src_addr = 0;
- d40d->lli_phy.dst_addr = 0;
+ d40d->last_lcla = NULL;
}
-static dma_cookie_t d40_assign_cookie(struct d40_chan *d40c,
- struct d40_desc *desc)
+static int d40_lcla_alloc_one(struct d40_chan *d40c,
+ struct d40_desc *d40d)
{
- dma_cookie_t cookie = d40c->chan.cookie;
+ unsigned long flags;
+ int i;
+ int ret = -EINVAL;
- if (++cookie < 0)
- cookie = 1;
+ spin_lock_irqsave(&d40c->base->lcla_pool.lock, flags);
- d40c->chan.cookie = cookie;
- desc->txd.cookie = cookie;
+ /*
+ * Allocate both src and dst at the same time, therefore the half
+ * start on 1 since 0 can't be used since zero is used as end marker.
+ */
+ for (i = 1 ; i < D40_LCLA_LINK_PER_EVENT_GRP / 2; i++) {
+ int idx = d40c->phy_chan->num * D40_LCLA_LINK_PER_EVENT_GRP + i;
- return cookie;
+ if (!d40c->base->lcla_pool.alloc_map[idx]) {
+ d40c->base->lcla_pool.alloc_map[idx] = d40d;
+ d40d->lcla_alloc++;
+ ret = i;
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&d40c->base->lcla_pool.lock, flags);
+
+ return ret;
}
-static void d40_desc_reset(struct d40_desc *d40d)
+static int d40_lcla_free_all(struct d40_chan *d40c,
+ struct d40_desc *d40d)
{
- d40d->lli_tcount = 0;
+ unsigned long flags;
+ int i;
+ int ret = -EINVAL;
+
+ if (d40c->log_num == D40_PHY_CHAN)
+ return 0;
+
+ spin_lock_irqsave(&d40c->base->lcla_pool.lock, flags);
+
+ for (i = 1 ; i < D40_LCLA_LINK_PER_EVENT_GRP / 2; i++) {
+ int idx = d40c->phy_chan->num * D40_LCLA_LINK_PER_EVENT_GRP + i;
+
+ if (d40c->base->lcla_pool.alloc_map[idx] == d40d) {
+ d40c->base->lcla_pool.alloc_map[idx] = NULL;
+ d40d->lcla_alloc--;
+ if (d40d->lcla_alloc == 0) {
+ ret = 0;
+ break;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&d40c->base->lcla_pool.lock, flags);
+
+ return ret;
+
}
static void d40_desc_remove(struct d40_desc *d40d)
@@ -377,45 +479,37 @@ static void d40_desc_remove(struct d40_desc *d40d)
static struct d40_desc *d40_desc_get(struct d40_chan *d40c)
{
- struct d40_desc *desc;
- struct d40_desc *d;
- struct d40_desc *_d;
+ struct d40_desc *desc = NULL;
if (!list_empty(&d40c->client)) {
- list_for_each_entry_safe(d, _d, &d40c->client, node)
+ struct d40_desc *d;
+ struct d40_desc *_d;
+
+ list_for_each_entry_safe(d, _d, &d40c->client, node) {
if (async_tx_test_ack(&d->txd)) {
d40_pool_lli_free(d);
d40_desc_remove(d);
desc = d;
- goto out;
+ memset(desc, 0, sizeof(struct d40_desc));
+ break;
}
+ }
}
- if (list_empty(&d40c->free)) {
- /* Alloc new desc because we're out of used ones */
- desc = kzalloc(sizeof(struct d40_desc), GFP_NOWAIT);
- if (desc == NULL)
- goto out;
+ if (!desc)
+ desc = kmem_cache_zalloc(d40c->base->desc_slab, GFP_NOWAIT);
+
+ if (desc)
INIT_LIST_HEAD(&desc->node);
- } else {
- /* Reuse an old desc. */
- desc = list_first_entry(&d40c->free,
- struct d40_desc,
- node);
- list_del(&desc->node);
- d40c->free_len--;
- }
-out:
+
return desc;
}
static void d40_desc_free(struct d40_chan *d40c, struct d40_desc *d40d)
{
- if (d40c->free_len < D40_DESC_CACHE_SIZE) {
- list_add_tail(&d40d->node, &d40c->free);
- d40c->free_len++;
- } else
- kfree(d40d);
+
+ d40_lcla_free_all(d40c, d40d);
+ kmem_cache_free(d40c->base->desc_slab, d40d);
}
static void d40_desc_submit(struct d40_chan *d40c, struct d40_desc *desc)
@@ -423,6 +517,112 @@ static void d40_desc_submit(struct d40_chan *d40c, struct d40_desc *desc)
list_add_tail(&desc->node, &d40c->active);
}
+static void d40_desc_done(struct d40_chan *d40c, struct d40_desc *desc)
+{
+ list_add_tail(&desc->node, &d40c->done);
+}
+
+static int d40_desc_log_lli_to_lcxa(struct d40_chan *d40c,
+ struct d40_desc *d40d,
+ bool use_lcpa)
+{
+ struct d40_log_lli_bidir *lli = &d40d->lli_log;
+ int curr_lcla = -EINVAL;
+ int first_lcla = 0;
+
+ if ((d40d->lli_len - d40d->lli_current) > 1 ||
+ d40d->cyclic || !use_lcpa) {
+
+ curr_lcla = d40_lcla_alloc_one(d40c, d40d);
+ first_lcla = curr_lcla;
+ }
+
+ if (!d40d->cyclic && use_lcpa) {
+ d40_log_lli_lcpa_write(d40c->lcpa,
+ &lli->dst[d40d->lli_current],
+ &lli->src[d40d->lli_current],
+ curr_lcla,
+ curr_lcla == -EINVAL);
+
+ d40d->lli_current++;
+ }
+
+ /*
+ * Run only in LCPA space for non-cyclic. For cyclic, caller
+ * will handle the error.
+ */
+ if (first_lcla < 0)
+ return first_lcla;
+
+ for (; d40d->lli_current < d40d->lli_len; d40d->lli_current++) {
+ int lli_current = d40d->lli_current;
+ struct d40_log_lli *lcla;
+ int next_lcla;
+ bool interrupt;
+
+ if (d40d->lli_current + 1 < d40d->lli_len)
+ next_lcla = d40_lcla_alloc_one(d40c, d40d);
+ else
+ next_lcla = d40d->cyclic ? first_lcla : -EINVAL;
+
+ interrupt = d40d->cyclic
+ ? d40d->txd.flags & DMA_PREP_INTERRUPT
+ : next_lcla == -EINVAL;
+
+ if (d40d->cyclic && curr_lcla == first_lcla) {
+ /*
+ * For cyclic transactions, the first link is
+ * present in both LCPA and LCLA space because
+ * we can't link back to the one in LCPA space.
+ */
+ d40_log_lli_lcpa_write(d40c->lcpa,
+ &lli->dst[lli_current],
+ &lli->src[lli_current],
+ next_lcla,
+ interrupt);
+ }
+
+ lcla = d40c->base->lcla_pool.base +
+ d40c->phy_chan->num * 1024 +
+ 8 * curr_lcla * 2;
+
+ d40_log_lli_lcla_write(lcla,
+ &lli->dst[lli_current],
+ &lli->src[lli_current],
+ next_lcla,
+ interrupt);
+
+ if (d40d->lli_current == d40d->lli_len - 1)
+ d40d->last_lcla = lcla;
+
+ (void) dma_map_single(d40c->base->dev, lcla,
+ 2 * sizeof(struct d40_log_lli),
+ DMA_TO_DEVICE);
+
+ curr_lcla = next_lcla;
+
+ if (curr_lcla == -EINVAL || curr_lcla == first_lcla) {
+ d40d->lli_current++;
+ break;
+ }
+
+ }
+
+ return first_lcla;
+}
+
+static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d)
+{
+ if (d40c->log_num == D40_PHY_CHAN) {
+ d40_phy_lli_write(d40c->base->virtbase,
+ d40c->phy_chan->num,
+ d40d->lli_phy.dst,
+ d40d->lli_phy.src);
+ d40d->lli_current = d40d->lli_len;
+ } else
+ (void) d40_desc_log_lli_to_lcxa(d40c, d40d, true);
+}
+
static struct d40_desc *d40_first_active_get(struct d40_chan *d40c)
{
struct d40_desc *d;
@@ -454,82 +654,26 @@ static struct d40_desc *d40_first_queued(struct d40_chan *d40c)
return d;
}
-/* Support functions for logical channels */
-
-static int d40_lcla_id_get(struct d40_chan *d40c,
- struct d40_lcla_pool *pool)
+static struct d40_desc *d40_first_done(struct d40_chan *d40c)
{
- int src_id = 0;
- int dst_id = 0;
- struct d40_log_lli *lcla_lidx_base =
- pool->base + d40c->phy_chan->num * 1024;
- int i;
- int lli_per_log = d40c->base->plat_data->llis_per_log;
-
- if (d40c->lcla.src_id >= 0 && d40c->lcla.dst_id >= 0)
- return 0;
-
- if (pool->num_blocks > 32)
- return -EINVAL;
-
- spin_lock(&pool->lock);
-
- for (i = 0; i < pool->num_blocks; i++) {
- if (!(pool->alloc_map[d40c->phy_chan->num] & (0x1 << i))) {
- pool->alloc_map[d40c->phy_chan->num] |= (0x1 << i);
- break;
- }
- }
- src_id = i;
- if (src_id >= pool->num_blocks)
- goto err;
-
- for (; i < pool->num_blocks; i++) {
- if (!(pool->alloc_map[d40c->phy_chan->num] & (0x1 << i))) {
- pool->alloc_map[d40c->phy_chan->num] |= (0x1 << i);
- break;
- }
- }
-
- dst_id = i;
- if (dst_id == src_id)
- goto err;
-
- d40c->lcla.src_id = src_id;
- d40c->lcla.dst_id = dst_id;
- d40c->lcla.dst = lcla_lidx_base + dst_id * lli_per_log + 1;
- d40c->lcla.src = lcla_lidx_base + src_id * lli_per_log + 1;
-
+ if (list_empty(&d40c->done))
+ return NULL;
- spin_unlock(&pool->lock);
- return 0;
-err:
- spin_unlock(&pool->lock);
- return -EINVAL;
+ return list_first_entry(&d40c->done, struct d40_desc, node);
}
-static void d40_lcla_id_put(struct d40_chan *d40c,
- struct d40_lcla_pool *pool,
- int id)
-{
- if (id < 0)
- return;
-
- d40c->lcla.src_id = -1;
- d40c->lcla.dst_id = -1;
+/* Support functions for logical channels */
- spin_lock(&pool->lock);
- pool->alloc_map[d40c->phy_chan->num] &= (~(0x1 << id));
- spin_unlock(&pool->lock);
-}
static int d40_channel_execute_command(struct d40_chan *d40c,
enum d40_command command)
{
- int status, i;
+ u32 status;
+ int i;
void __iomem *active_reg;
int ret = 0;
unsigned long flags;
+ u32 wmask;
spin_lock_irqsave(&d40c->base->execmd_lock, flags);
@@ -547,7 +691,14 @@ static int d40_channel_execute_command(struct d40_chan *d40c,
goto done;
}
- writel(command << D40_CHAN_POS(d40c->phy_chan->num), active_reg);
+#ifdef CONFIG_STE_DMA40_DEBUG
+ if (command == D40_DMA_RUN)
+ sted40_history_snapshot();
+#endif
+
+ wmask = 0xffffffff & ~(D40_CHAN_POS_MASK(d40c->phy_chan->num));
+ writel(wmask | (command << D40_CHAN_POS(d40c->phy_chan->num)),
+ active_reg);
if (command == D40_DMA_SUSPEND_REQ) {
@@ -573,6 +724,9 @@ static int d40_channel_execute_command(struct d40_chan *d40c,
"[%s]: unable to suspend the chl %d (log: %d) status %x\n",
__func__, d40c->phy_chan->num, d40c->log_num,
status);
+#ifdef CONFIG_STE_DMA40_DEBUG
+ sted40_history_dump();
+#endif
dump_stack();
ret = -EBUSY;
}
@@ -586,41 +740,112 @@ done:
static void d40_term_all(struct d40_chan *d40c)
{
struct d40_desc *d40d;
- struct d40_desc *d;
- struct d40_desc *_d;
+
+ /* Release completed descriptors */
+ while ((d40d = d40_first_done(d40c))) {
+ d40_desc_remove(d40d);
+ d40_desc_free(d40c, d40d);
+ }
/* Release active descriptors */
while ((d40d = d40_first_active_get(d40c))) {
d40_desc_remove(d40d);
-
- /* Return desc to free-list */
d40_desc_free(d40c, d40d);
}
/* Release queued descriptors waiting for transfer */
while ((d40d = d40_first_queued(d40c))) {
d40_desc_remove(d40d);
-
- /* Return desc to free-list */
d40_desc_free(d40c, d40d);
}
- /* Release client owned descriptors */
- if (!list_empty(&d40c->client))
- list_for_each_entry_safe(d, _d, &d40c->client, node) {
- d40_pool_lli_free(d);
- d40_desc_remove(d);
- /* Return desc to free-list */
- d40_desc_free(d40c, d40d);
+ d40c->pending_tx = 0;
+ d40c->busy = false;
+}
+
+/*
+ * I'm not so sure that this actually matters. It seems like security
+ * is changing the GCC register as well.
+ * TODO: Investigate.
+ */
+static void d40_power_off(struct d40_base *base, int phy_num)
+{
+ u32 gcc;
+ int i;
+ int j;
+ int p;
+ unsigned long flags;
+
+ atomic_dec(&base->usage);
+
+ /*
+ * Disable the rest of the code because of GCC register HW bugs on v1
+ * which are not worth working around. Revisit later.
+ */
+ return;
+
+ /*
+ * Power off event group related to physical channel, if
+ * the other physical channels that belong to the same
+ * event group are not in use
+ */
+
+ for (j = 0; j < base->num_phy_chans; j += D40_GROUP_SIZE) {
+
+ for (i = 0; i < 2; i++) {
+ p = (((phy_num & (base->num_phy_chans - 1)) + i)
+ & (D40_GROUP_SIZE - 1)) + j;
+ if (p == phy_num)
+ continue;
+ /*
+ * If another physical channel in the same group is
+ * allocated, just return.
+ */
+ if (base->phy_res[p].allocated_dst == D40_ALLOC_PHY ||
+ base->phy_res[p].allocated_src == D40_ALLOC_PHY) {
+ return;
+ }
}
+ }
- d40_lcla_id_put(d40c, &d40c->base->lcla_pool,
- d40c->lcla.src_id);
- d40_lcla_id_put(d40c, &d40c->base->lcla_pool,
- d40c->lcla.dst_id);
+ spin_lock_irqsave(&base->pm_gcc_lock, flags);
+ gcc = readl(base->virtbase + D40_DREG_GCC);
- d40c->pending_tx = 0;
- d40c->busy = false;
+ gcc &= ~D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(phy_num),
+ D40_DREG_GCC_SRC);
+ gcc &= ~D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(phy_num),
+ D40_DREG_GCC_DST);
+
+ writel(gcc, base->virtbase + D40_DREG_GCC);
+
+ spin_unlock_irqrestore(&base->pm_gcc_lock, flags);
+}
+
+static void d40_power_on(struct d40_base *base, int phy_num)
+{
+ u32 gcc;
+ unsigned long flags;
+
+ atomic_inc(&base->usage);
+
+ /*
+ * Disable the rest of the code because of GCC register HW bugs on v1
+ * which are not worth working around. Revisit later.
+ */
+ return;
+
+ /* Power on event group related to physical channel */
+ spin_lock_irqsave(&base->pm_gcc_lock, flags);
+ gcc = readl(base->virtbase + D40_DREG_GCC);
+
+ gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(phy_num),
+ D40_DREG_GCC_SRC);
+ gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(phy_num),
+ D40_DREG_GCC_DST);
+
+ writel(gcc, base->virtbase + D40_DREG_GCC);
+
+ spin_unlock_irqrestore(&base->pm_gcc_lock, flags);
}
static void d40_config_set_event(struct d40_chan *d40c, bool do_enable)
@@ -628,6 +853,7 @@ static void d40_config_set_event(struct d40_chan *d40c, bool do_enable)
u32 val;
unsigned long flags;
+ /* Notice, that disable requires the physical channel to be stopped */
if (do_enable)
val = D40_ACTIVATE_EVENTLINE;
else
@@ -661,45 +887,49 @@ static void d40_config_set_event(struct d40_chan *d40c, bool do_enable)
static u32 d40_chan_has_events(struct d40_chan *d40c)
{
- u32 val = 0;
+ u32 val;
- /* If SSLNK or SDLNK is zero all events are disabled */
- if ((d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM) ||
- (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH))
- val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
- d40c->phy_chan->num * D40_DREG_PCDELTA +
- D40_CHAN_REG_SSLNK);
-
- if (d40c->dma_cfg.dir != STEDMA40_PERIPH_TO_MEM)
- val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
- d40c->phy_chan->num * D40_DREG_PCDELTA +
- D40_CHAN_REG_SDLNK);
+ val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SSLNK);
+
+ val |= readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SDLNK);
return val;
}
-static void d40_config_enable_lidx(struct d40_chan *d40c)
+static u32 d40_get_prmo(struct d40_chan *d40c)
{
- /* Set LIDX for lcla */
- writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
- D40_SREG_ELEM_LOG_LIDX_MASK,
- d40c->base->virtbase + D40_DREG_PCBASE +
- d40c->phy_chan->num * D40_DREG_PCDELTA + D40_CHAN_REG_SDELT);
+ static const unsigned int phy_map[] = {
+ [STEDMA40_PCHAN_BASIC_MODE]
+ = D40_DREG_PRMO_PCHAN_BASIC,
+ [STEDMA40_PCHAN_MODULO_MODE]
+ = D40_DREG_PRMO_PCHAN_MODULO,
+ [STEDMA40_PCHAN_DOUBLE_DST_MODE]
+ = D40_DREG_PRMO_PCHAN_DOUBLE_DST,
+ };
+ static const unsigned int log_map[] = {
+ [STEDMA40_LCHAN_SRC_PHY_DST_LOG]
+ = D40_DREG_PRMO_LCHAN_SRC_PHY_DST_LOG,
+ [STEDMA40_LCHAN_SRC_LOG_DST_PHY]
+ = D40_DREG_PRMO_LCHAN_SRC_LOG_DST_PHY,
+ [STEDMA40_LCHAN_SRC_LOG_DST_LOG]
+ = D40_DREG_PRMO_LCHAN_SRC_LOG_DST_LOG,
+ };
- writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
- D40_SREG_ELEM_LOG_LIDX_MASK,
- d40c->base->virtbase + D40_DREG_PCBASE +
- d40c->phy_chan->num * D40_DREG_PCDELTA + D40_CHAN_REG_SSELT);
+ if (d40c->log_num == D40_PHY_CHAN)
+ return phy_map[d40c->dma_cfg.mode_opt];
+ else
+ return log_map[d40c->dma_cfg.mode_opt];
}
-static int d40_config_write(struct d40_chan *d40c)
+static void d40_config_write(struct d40_chan *d40c)
{
u32 addr_base;
u32 var;
- int res;
- res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
- if (res)
- return res;
+ d40_power_on(d40c->base, d40c->phy_chan->num);
/* Odd addresses are even addresses + 4 */
addr_base = (d40c->phy_chan->num % 2) * 4;
@@ -709,8 +939,7 @@ static int d40_config_write(struct d40_chan *d40c)
writel(var, d40c->base->virtbase + D40_DREG_PRMSE + addr_base);
/* Setup operational mode option register */
- var = ((d40c->dma_cfg.channel_type >> STEDMA40_INFO_CH_MODE_OPT_POS) &
- 0x3) << D40_CHAN_POS(d40c->phy_chan->num);
+ var = d40_get_prmo(d40c) << D40_CHAN_POS(d40c->phy_chan->num);
writel(var, d40c->base->virtbase + D40_DREG_PRMOE + addr_base);
@@ -725,38 +954,300 @@ static int d40_config_write(struct d40_chan *d40c)
d40c->phy_chan->num * D40_DREG_PCDELTA +
D40_CHAN_REG_SDCFG);
- d40_config_enable_lidx(d40c);
+ /* Set LIDX for lcla */
+ writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
+ D40_SREG_ELEM_LOG_LIDX_MASK,
+ d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SDELT);
+
+ writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
+ D40_SREG_ELEM_LOG_LIDX_MASK,
+ d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SSELT);
+
}
+ d40_power_off(d40c->base, d40c->phy_chan->num);
+}
+
+static u32 d40_residue(struct d40_chan *d40c)
+{
+ u32 num_elt;
+
+ if (d40c->log_num != D40_PHY_CHAN)
+ num_elt = (readl(&d40c->lcpa->lcsp2) &
+ D40_MEM_LCSP2_ECNT_MASK) >> D40_MEM_LCSP2_ECNT_POS;
+ else
+ num_elt = (readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SDELT) &
+ D40_SREG_ELEM_PHY_ECNT_MASK) >>
+ D40_SREG_ELEM_PHY_ECNT_POS;
+ return num_elt * (1 << d40c->dma_cfg.dst_info.data_width);
+}
+
+static bool d40_tx_is_linked(struct d40_chan *d40c)
+{
+ bool is_link;
+
+ if (d40c->log_num != D40_PHY_CHAN)
+ is_link = readl(&d40c->lcpa->lcsp3) & D40_MEM_LCSP3_DLOS_MASK;
+ else
+ is_link = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SDLNK) &
+ D40_SREG_LNK_PHYS_LNK_MASK;
+ return is_link;
+}
+
+static int d40_pause(struct dma_chan *chan)
+{
+ struct d40_chan *d40c =
+ container_of(chan, struct d40_chan, chan);
+ int res = 0;
+ unsigned long flags;
+
+ if (!d40c->busy)
+ return 0;
+
+ spin_lock_irqsave(&d40c->lock, flags);
+
+ res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
+ if (res == 0) {
+ if (d40c->log_num != D40_PHY_CHAN) {
+ d40_config_set_event(d40c, false);
+ /* Resume the other logical channels if any */
+ if (d40_chan_has_events(d40c))
+ res = d40_channel_execute_command(d40c,
+ D40_DMA_RUN);
+ }
+ }
+
+ spin_unlock_irqrestore(&d40c->lock, flags);
return res;
}
-static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d)
+static int d40_resume(struct dma_chan *chan)
{
+ struct d40_chan *d40c =
+ container_of(chan, struct d40_chan, chan);
+ int res = 0;
+ unsigned long flags;
- if (d40d->lli_phy.dst && d40d->lli_phy.src) {
- d40_phy_lli_write(d40c->base->virtbase,
- d40c->phy_chan->num,
- d40d->lli_phy.dst,
- d40d->lli_phy.src);
- d40d->lli_tcount = d40d->lli_len;
- } else if (d40d->lli_log.dst && d40d->lli_log.src) {
- u32 lli_len;
- struct d40_log_lli *src = d40d->lli_log.src;
- struct d40_log_lli *dst = d40d->lli_log.dst;
+ if (!d40c->busy)
+ return 0;
- src += d40d->lli_tcount;
- dst += d40d->lli_tcount;
+ spin_lock_irqsave(&d40c->lock, flags);
- if (d40d->lli_len <= d40c->base->plat_data->llis_per_log)
- lli_len = d40d->lli_len;
- else
- lli_len = d40c->base->plat_data->llis_per_log;
- d40d->lli_tcount += lli_len;
- d40_log_lli_write(d40c->lcpa, d40c->lcla.src,
- d40c->lcla.dst,
- dst, src,
- d40c->base->plat_data->llis_per_log);
+ if (d40c->base->rev == 0)
+ if (d40c->log_num != D40_PHY_CHAN) {
+ res = d40_channel_execute_command(d40c,
+ D40_DMA_SUSPEND_REQ);
+ goto no_suspend;
+ }
+
+ /* If bytes left to transfer or linked tx resume job */
+ if (d40_residue(d40c) || d40_tx_is_linked(d40c)) {
+
+ if (d40c->log_num != D40_PHY_CHAN)
+ d40_config_set_event(d40c, true);
+
+ res = d40_channel_execute_command(d40c, D40_DMA_RUN);
}
+
+no_suspend:
+ spin_unlock_irqrestore(&d40c->lock, flags);
+ return res;
+}
+
+static bool __d40_tx_submit_link_log(struct d40_chan *d40c,
+ struct d40_desc *d40d,
+ struct d40_desc *prev)
+{
+ struct d40_log_lli *lastlcla = prev->last_lcla;
+ struct d40_log_lli_bidir *lli = &prev->lli_log;
+ int lastidx = prev->lli_len - 1;
+ int los;
+
+ los = d40_desc_log_lli_to_lcxa(d40c, d40d, false);
+ if (los < 0)
+ return false;
+
+ dma_sync_single_for_cpu(d40c->base->dev, virt_to_phys(lastlcla),
+ 2 * sizeof(struct d40_log_lli),
+ DMA_TO_DEVICE);
+
+ d40_log_lli_lcla_write(lastlcla,
+ &lli->dst[lastidx],
+ &lli->src[lastidx],
+ los,
+ true);
+
+ dma_sync_single_for_device(d40c->base->dev, virt_to_phys(lastlcla),
+ 2 * sizeof(struct d40_log_lli),
+ DMA_TO_DEVICE);
+
+ return true;
+}
+
+static bool d40_tx_submit_link_log(struct d40_chan *d40c,
+ struct d40_desc *d40d,
+ struct d40_desc *prev)
+{
+ struct d40_log_lli_bidir *lli = &prev->lli_log;
+ int lastidx = prev->lli_len - 1;
+ unsigned int secnt;
+ int active_slos;
+ int last_slos;
+
+ /*
+ * An only-LCPA transfer will either be transmitting the last link or
+ * be completed.
+ */
+ if (!prev->last_lcla)
+ return false;
+
+ /* We don't support linking to incompletely linked transfers */
+ if (prev->lli_current != prev->lli_len)
+ return false;
+
+ /* A transfer must be ongoing. */
+ secnt = (d40c->lcpa->lcsp0 & D40_MEM_LCSP0_ECNT_MASK)
+ >> D40_MEM_LCSP0_ECNT_POS;
+ if (!secnt) {
+ dev_vdbg(d40c->base->dev, "%s: secnt %u\n", __func__, secnt);
+ return false;
+ }
+
+ /*
+ * We don't support linking while the last link is being transmitted.
+ */
+ active_slos = (d40c->lcpa->lcsp1 & D40_MEM_LCSP1_SLOS_MASK)
+ >> D40_MEM_LCSP1_SLOS_POS;
+ last_slos = (lli->src[lastidx].lcsp13 & D40_MEM_LCSP1_SLOS_MASK)
+ >> D40_MEM_LCSP1_SLOS_POS;
+ if (active_slos == last_slos) {
+ dev_vdbg(d40c->base->dev, "%s: activ %d last %d secnt %u\n",
+ __func__, active_slos, last_slos, secnt);
+ return false;
+ }
+
+ dev_vdbg(d40c->base->dev,
+ "%s: active %#x last %#x, lli_len %d secnt %u\n",
+ __func__, active_slos, last_slos, prev->lli_len, secnt);
+
+ /*
+ * We're either transferring one of this desc's links or one from an
+ * earlier linked one. Either way, update this desc's last link.
+ */
+ return __d40_tx_submit_link_log(d40c, d40d, prev);
+}
+
+static bool __d40_tx_submit_link_phy(struct d40_chan *d40c,
+ struct d40_desc *d40d,
+ struct d40_desc *prev)
+{
+ int lastidx = prev->lli_len - 1;
+ struct d40_phy_lli *lastsrc = &prev->lli_phy.src[lastidx];
+ struct d40_phy_lli *lastdst = &prev->lli_phy.dst[lastidx];
+ struct d40_phy_lli *thissrc = &d40d->lli_phy.src[0];
+ struct d40_phy_lli *thisdst = &d40d->lli_phy.dst[0];
+ unsigned int val;
+
+ dma_sync_single_for_cpu(d40c->base->dev, virt_to_phys(lastsrc),
+ sizeof(*lastsrc), DMA_TO_DEVICE);
+
+ dma_sync_single_for_cpu(d40c->base->dev, virt_to_phys(lastdst),
+ sizeof(*lastdst), DMA_TO_DEVICE);
+
+ /* Keep the settings */
+ val = lastsrc->reg_lnk & ~D40_SREG_LNK_PHYS_LNK_MASK;
+ lastsrc->reg_lnk = val | virt_to_phys(thissrc);
+
+ val = lastdst->reg_lnk & ~D40_SREG_LNK_PHYS_LNK_MASK;
+ lastdst->reg_lnk = val | virt_to_phys(thisdst);
+
+ dma_sync_single_for_device(d40c->base->dev, virt_to_phys(lastsrc),
+ sizeof(*lastsrc), DMA_TO_DEVICE);
+
+ dma_sync_single_for_device(d40c->base->dev, virt_to_phys(lastdst),
+ sizeof(*lastdst), DMA_TO_DEVICE);
+
+ return true;
+}
+
+static bool d40_tx_submit_link_phy(struct d40_chan *d40c,
+ struct d40_desc *d40d,
+ struct d40_desc *prev)
+{
+
+ struct d40_phy_lli *lastsrc = &prev->lli_phy.src[prev->lli_len - 1];
+ unsigned int active_lnk;
+ unsigned int last_lnk;
+ unsigned int secnt;
+
+ /* A transfer must be ongoing. */
+ secnt = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SSELT) >> D40_SREG_ELEM_LOG_ECNT_POS;
+ if (!secnt) {
+ dev_vdbg(d40c->base->dev, "%s: secnt %u\n", __func__, secnt);
+ return false;
+ }
+
+ active_lnk = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SSLNK);
+
+ dma_sync_single_for_cpu(d40c->base->dev, virt_to_phys(lastsrc),
+ sizeof(*lastsrc), DMA_TO_DEVICE);
+
+ last_lnk = lastsrc->reg_lnk;
+
+ dma_sync_single_for_device(d40c->base->dev, virt_to_phys(lastsrc),
+ sizeof(*lastsrc), DMA_TO_DEVICE);
+
+ /*
+ * We don't support linking while the last link is being transmitted.
+ */
+ if (active_lnk == last_lnk) {
+ dev_vdbg(d40c->base->dev, "%s: active %d last %d secnt %u\n",
+ __func__, active_lnk, last_lnk, secnt);
+ return false;
+ }
+
+ dev_vdbg(d40c->base->dev,
+ "%s: activ %#x last %#x, lli_len %d secnt %u\n",
+ __func__, active_lnk, last_lnk, prev->lli_len, secnt);
+
+ /*
+ * We're either transferring one of this desc's links or one from an
+ * earlier linked one. Either way, update this desc's last link.
+ */
+ return __d40_tx_submit_link_phy(d40c, d40d, prev);
+}
+
+static bool d40_tx_submit_link(struct d40_chan *d40c, struct d40_desc *d40d)
+{
+ struct d40_desc *prev;
+ bool hwlinked;
+
+ if (list_empty(&d40c->active))
+ return false;
+
+ prev = list_entry(d40c->active.prev, struct d40_desc, node);
+
+ if (d40c->log_num == D40_PHY_CHAN)
+ hwlinked = d40_tx_submit_link_phy(d40c, d40d, prev);
+ else
+ hwlinked = d40_tx_submit_link_log(d40c, d40d, prev);
+
+ if (hwlinked)
+ dev_dbg(d40c->base->dev, "%s: hwlinked d40d %p prev %p\n",
+ __func__, d40d, prev);
+
+ return hwlinked;
}
static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx)
@@ -767,11 +1258,31 @@ static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx)
struct d40_desc *d40d = container_of(tx, struct d40_desc, txd);
unsigned long flags;
+ (void) d40_pause(&d40c->chan);
+
spin_lock_irqsave(&d40c->lock, flags);
- tx->cookie = d40_assign_cookie(d40c, d40d);
+ d40c->chan.cookie++;
- d40_desc_queue(d40c, d40d);
+ if (d40c->chan.cookie < 0)
+ d40c->chan.cookie = 1;
+
+ d40d->txd.cookie = d40c->chan.cookie;
+
+ d40d->is_hw_linked = d40_tx_submit_link(d40c, d40d);
+ if (d40d->is_hw_linked) {
+ /* Linked, therefore already active */
+ d40_desc_submit(d40c, d40d);
+ } else
+ d40_desc_queue(d40c, d40d);
+
+ spin_unlock_irqrestore(&d40c->lock, flags);
+
+ (void) d40_resume(&d40c->chan);
+ spin_lock_irqsave(&d40c->lock, flags);
+
+ if (!d40c->busy)
+ d40_power_off(d40c->base, d40c->phy_chan->num);
spin_unlock_irqrestore(&d40c->lock, flags);
@@ -780,18 +1291,22 @@ static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx)
static int d40_start(struct d40_chan *d40c)
{
- int err;
- if (d40c->log_num != D40_PHY_CHAN) {
- err = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
- if (err)
- return err;
- d40_config_set_event(d40c, true);
+ if (d40c->base->rev == 0) {
+ int err;
+
+ if (d40c->log_num != D40_PHY_CHAN) {
+ err = d40_channel_execute_command(d40c,
+ D40_DMA_SUSPEND_REQ);
+ if (err)
+ return err;
+ }
}
- err = d40_channel_execute_command(d40c, D40_DMA_RUN);
+ if (d40c->log_num != D40_PHY_CHAN)
+ d40_config_set_event(d40c, true);
- return err;
+ return d40_channel_execute_command(d40c, D40_DMA_RUN);
}
static struct d40_desc *d40_queue_start(struct d40_chan *d40c)
@@ -811,14 +1326,25 @@ static struct d40_desc *d40_queue_start(struct d40_chan *d40c)
/* Add to active queue */
d40_desc_submit(d40c, d40d);
- /* Initiate DMA job */
- d40_desc_load(d40c, d40d);
+ /*
+ * If this job is already linked in hw,
+ * do not submit it.
+ */
- /* Start dma job */
- err = d40_start(d40c);
+ /*
+ * TODO: make sure is_hw_linked work all the time with logical
+ * jobs
+ */
+ if (!d40d->is_hw_linked) {
+ /* Initiate DMA job */
+ d40_desc_load(d40c, d40d);
- if (err)
- return NULL;
+ /* Start dma job */
+ err = d40_start(d40c);
+
+ if (err)
+ return NULL;
+ }
}
return d40d;
@@ -828,49 +1354,75 @@ static struct d40_desc *d40_queue_start(struct d40_chan *d40c)
static void dma_tc_handle(struct d40_chan *d40c)
{
struct d40_desc *d40d;
+ bool islastactive;
- if (!d40c->phy_chan)
+ if (d40c->cdesc) {
+ d40c->pending_tx++;
+ tasklet_schedule(&d40c->tasklet);
return;
+ }
/* Get first active entry from list */
+redo:
d40d = d40_first_active_get(d40c);
if (d40d == NULL)
return;
- if (d40d->lli_tcount < d40d->lli_len) {
+ d40_lcla_free_all(d40c, d40d);
+ if (d40d->lli_current < d40d->lli_len) {
d40_desc_load(d40c, d40d);
/* Start dma job */
(void) d40_start(d40c);
return;
}
- if (d40_queue_start(d40c) == NULL)
+ /*
+ * More than one active happens when we have
+ * hw linked transfers.
+ */
+ islastactive = list_is_last(&d40d->node, &d40c->active);
+ if (islastactive && d40_queue_start(d40c) == NULL)
d40c->busy = false;
+ d40_desc_remove(d40d);
+ d40_desc_done(d40c, d40d);
+
d40c->pending_tx++;
tasklet_schedule(&d40c->tasklet);
+ /*
+ * When we have multiple active transfers, there is a chance that we
+ * might miss some link interrupts if the time to perform each link is
+ * very small (mostly with mem-to-mem transfers). So, if the hardware
+ * is not transmitting any more links, assume that all the active
+ * transfers are complete.
+ */
+ if (!islastactive && !d40_tx_is_linked(d40c))
+ goto redo;
}
static void dma_tasklet(unsigned long data)
{
struct d40_chan *d40c = (struct d40_chan *) data;
- struct d40_desc *d40d_fin;
+ struct d40_desc *d40d;
unsigned long flags;
dma_async_tx_callback callback;
void *callback_param;
spin_lock_irqsave(&d40c->lock, flags);
- /* Get first active entry from list */
- d40d_fin = d40_first_active_get(d40c);
-
- if (d40d_fin == NULL)
- goto err;
+ if (d40c->cdesc)
+ d40d = d40c->cdesc->d40d;
+ else {
+ /* Get first active entry from list */
+ d40d = d40_first_done(d40c);
+ if (d40d == NULL)
+ goto err;
- d40c->completed = d40d_fin->txd.cookie;
+ d40c->completed = d40d->txd.cookie;
+ }
/*
* If terminating a channel pending_tx is set to zero.
@@ -882,20 +1434,23 @@ static void dma_tasklet(unsigned long data)
}
/* Callback to client */
- callback = d40d_fin->txd.callback;
- callback_param = d40d_fin->txd.callback_param;
-
- if (async_tx_test_ack(&d40d_fin->txd)) {
- d40_pool_lli_free(d40d_fin);
- d40_desc_remove(d40d_fin);
- /* Return desc to free-list */
- d40_desc_free(d40c, d40d_fin);
+
+ if (d40c->cdesc) {
+ callback = d40c->cdesc->period_callback;
+ callback_param = d40c->cdesc->period_callback_param;
} else {
- d40_desc_reset(d40d_fin);
- if (!d40d_fin->is_in_client_list) {
- d40_desc_remove(d40d_fin);
- list_add_tail(&d40d_fin->node, &d40c->client);
- d40d_fin->is_in_client_list = true;
+ callback = d40d->txd.callback;
+ callback_param = d40d->txd.callback_param;
+
+ if (async_tx_test_ack(&d40d->txd)) {
+ d40_pool_lli_free(d40d);
+ d40_desc_remove(d40d);
+ d40_desc_free(d40c, d40d);
+ } else if (!d40d->is_in_client_list) {
+ d40_desc_remove(d40d);
+ d40_lcla_free_all(d40c, d40d);
+ list_add_tail(&d40d->node, &d40c->client);
+ d40d->is_in_client_list = true;
}
}
@@ -906,7 +1461,7 @@ static void dma_tasklet(unsigned long data)
spin_unlock_irqrestore(&d40c->lock, flags);
- if (callback)
+ if (callback && (d40d->txd.flags & DMA_PREP_INTERRUPT))
callback(callback_param);
return;
@@ -920,7 +1475,7 @@ static void dma_tasklet(unsigned long data)
static irqreturn_t d40_handle_interrupt(int irq, void *data)
{
- static const struct d40_interrupt_lookup il[] = {
+ static struct d40_interrupt_lookup il[] = {
{D40_DREG_LCTIS0, D40_DREG_LCICR0, false, 0},
{D40_DREG_LCTIS1, D40_DREG_LCICR1, false, 32},
{D40_DREG_LCTIS2, D40_DREG_LCICR2, false, 64},
@@ -935,7 +1490,6 @@ static irqreturn_t d40_handle_interrupt(int irq, void *data)
int i;
u32 regs[ARRAY_SIZE(il)];
- u32 tmp;
u32 idx;
u32 row;
long chan = -1;
@@ -944,7 +1498,9 @@ static irqreturn_t d40_handle_interrupt(int irq, void *data)
struct d40_base *base = data;
spin_lock_irqsave(&base->interrupt_lock, flags);
-
+#ifdef CONFIG_STE_DMA40_DEBUG
+ sted40_history_text("IRQ enter");
+#endif
/* Read interrupt status of both logical and physical channels */
for (i = 0; i < ARRAY_SIZE(il); i++)
regs[i] = readl(base->virtbase + il[i].src);
@@ -961,49 +1517,83 @@ static irqreturn_t d40_handle_interrupt(int irq, void *data)
row = chan / BITS_PER_LONG;
idx = chan & (BITS_PER_LONG - 1);
- /* ACK interrupt */
- tmp = readl(base->virtbase + il[row].clr);
- tmp |= 1 << idx;
- writel(tmp, base->virtbase + il[row].clr);
-
if (il[row].offset == D40_PHY_CHAN)
d40c = base->lookup_phy_chans[idx];
else
d40c = base->lookup_log_chans[il[row].offset + idx];
+
+ if (!d40c) {
+ /*
+ * No error because this can happen if something else
+ * in the system is using the channel.
+ */
+ continue;
+ }
+
+ /* ACK interrupt */
+ writel(1 << idx, base->virtbase + il[row].clr);
+
spin_lock(&d40c->lock);
- if (!il[row].is_error)
+ if (!il[row].is_error) {
+
dma_tc_handle(d40c);
- else
- dev_err(base->dev, "[%s] IRQ chan: %ld offset %d idx %d\n",
+ } else {
+ dev_err(base->dev, "[%s] Error IRQ chan: %ld offset %d idx %d\n",
__func__, chan, il[row].offset, idx);
+#ifdef CONFIG_STE_DMA40_DEBUG
+ sted40_history_dump();
+#endif
+ }
spin_unlock(&d40c->lock);
}
-
+#ifdef CONFIG_STE_DMA40_DEBUG
+ sted40_history_text("IRQ leave");
+#endif
spin_unlock_irqrestore(&base->interrupt_lock, flags);
return IRQ_HANDLED;
}
-
static int d40_validate_conf(struct d40_chan *d40c,
struct stedma40_chan_cfg *conf)
{
int res = 0;
u32 dst_event_group = D40_TYPE_TO_GROUP(conf->dst_dev_type);
u32 src_event_group = D40_TYPE_TO_GROUP(conf->src_dev_type);
- bool is_log = (conf->channel_type & STEDMA40_CHANNEL_IN_OPER_MODE)
- == STEDMA40_CHANNEL_IN_LOG_MODE;
+ bool is_log = conf->mode == STEDMA40_MODE_LOGICAL;
+
+ if (!conf->dir) {
+ dev_err(&d40c->chan.dev->device, "[%s] Invalid direction.\n",
+ __func__);
+ res = -EINVAL;
+ }
+
+ if (conf->dst_dev_type != STEDMA40_DEV_DST_MEMORY &&
+ d40c->base->plat_data->dev_tx[conf->dst_dev_type] == 0) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Invalid TX channel address (%d)\n",
+ __func__, conf->dst_dev_type);
+ res = -EINVAL;
+ }
+
+ if (conf->src_dev_type != STEDMA40_DEV_SRC_MEMORY &&
+ d40c->base->plat_data->dev_rx[conf->src_dev_type] == 0) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Invalid RX channel address (%d)\n",
+ __func__, conf->src_dev_type);
+ res = -EINVAL;
+ }
- if (d40c->dma_cfg.dir == STEDMA40_MEM_TO_PERIPH &&
+ if (conf->dir == STEDMA40_MEM_TO_PERIPH &&
dst_event_group == STEDMA40_DEV_DST_MEMORY) {
dev_err(&d40c->chan.dev->device, "[%s] Invalid dst\n",
__func__);
res = -EINVAL;
}
- if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM &&
+ if (conf->dir == STEDMA40_PERIPH_TO_MEM &&
src_event_group == STEDMA40_DEV_SRC_MEMORY) {
dev_err(&d40c->chan.dev->device, "[%s] Invalid src\n",
__func__);
@@ -1038,11 +1628,16 @@ static int d40_validate_conf(struct d40_chan *d40c,
return res;
}
-static bool d40_alloc_mask_set(struct d40_phy_res *phy, bool is_src,
- int log_event_line, bool is_log)
+static bool d40_alloc_mask_set(struct d40_phy_res *phy,
+ bool is_src, int log_event_line, bool is_log,
+ bool *first_user)
{
unsigned long flags;
spin_lock_irqsave(&phy->lock, flags);
+
+ *first_user = ((phy->allocated_src | phy->allocated_dst)
+ == D40_ALLOC_FREE);
+
if (!is_log) {
/* Physical interrupts are masked per physical full channel */
if (phy->allocated_src == D40_ALLOC_FREE &&
@@ -1097,7 +1692,6 @@ static bool d40_alloc_mask_free(struct d40_phy_res *phy, bool is_src,
spin_lock_irqsave(&phy->lock, flags);
if (!log_event_line) {
- /* Physical interrupts are masked per physical full channel */
phy->allocated_dst = D40_ALLOC_FREE;
phy->allocated_src = D40_ALLOC_FREE;
is_free = true;
@@ -1124,7 +1718,7 @@ out:
return is_free;
}
-static int d40_allocate_channel(struct d40_chan *d40c)
+static int d40_allocate_channel(struct d40_chan *d40c, bool *first_phy_user)
{
int dev_type;
int event_group;
@@ -1134,9 +1728,7 @@ static int d40_allocate_channel(struct d40_chan *d40c)
int j;
int log_num;
bool is_src;
- bool is_log = (d40c->dma_cfg.channel_type & STEDMA40_CHANNEL_IN_OPER_MODE)
- == STEDMA40_CHANNEL_IN_LOG_MODE;
-
+ bool is_log = d40c->dma_cfg.mode == STEDMA40_MODE_LOGICAL;
phys = d40c->base->phy_res;
@@ -1162,15 +1754,18 @@ static int d40_allocate_channel(struct d40_chan *d40c)
for (i = 0; i < d40c->base->num_phy_chans; i++) {
if (d40_alloc_mask_set(&phys[i], is_src,
- 0, is_log))
+ 0, is_log,
+ first_phy_user))
goto found_phy;
}
} else
for (j = 0; j < d40c->base->num_phy_chans; j += 8) {
int phy_num = j + event_group * 2;
for (i = phy_num; i < phy_num + 2; i++) {
- if (d40_alloc_mask_set(&phys[i], is_src,
- 0, is_log))
+ if (d40_alloc_mask_set(&phys[i],
+ is_src, 0,
+ is_log,
+ first_phy_user))
goto found_phy;
}
}
@@ -1194,13 +1789,15 @@ found_phy:
if (is_src) {
for (i = phy_num; i < phy_num + 2; i++) {
if (d40_alloc_mask_set(&phys[i], is_src,
- event_line, is_log))
+ event_line, is_log,
+ first_phy_user))
goto found_log;
}
} else {
for (i = phy_num + 1; i >= phy_num; i--) {
if (d40_alloc_mask_set(&phys[i], is_src,
- event_line, is_log))
+ event_line, is_log,
+ first_phy_user))
goto found_log;
}
}
@@ -1221,30 +1818,6 @@ out:
}
-static int d40_config_chan(struct d40_chan *d40c,
- struct stedma40_chan_cfg *info)
-{
-
- /* Fill in basic CFG register values */
- d40_phy_cfg(&d40c->dma_cfg, &d40c->src_def_cfg,
- &d40c->dst_def_cfg, d40c->log_num != D40_PHY_CHAN);
-
- if (d40c->log_num != D40_PHY_CHAN) {
- d40_log_cfg(&d40c->dma_cfg,
- &d40c->log_def.lcsp1, &d40c->log_def.lcsp3);
-
- if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM)
- d40c->lcpa = d40c->base->lcpa_base +
- d40c->dma_cfg.src_dev_type * 32;
- else
- d40c->lcpa = d40c->base->lcpa_base +
- d40c->dma_cfg.dst_dev_type * 32 + 16;
- }
-
- /* Write channel configuration to the DMA */
- return d40_config_write(d40c);
-}
-
static int d40_config_memcpy(struct d40_chan *d40c)
{
dma_cap_mask_t cap = d40c->chan.device->cap_mask;
@@ -1267,18 +1840,27 @@ static int d40_config_memcpy(struct d40_chan *d40c)
return 0;
}
-
static int d40_free_dma(struct d40_chan *d40c)
{
int res = 0;
- u32 event, dir;
+ u32 event;
struct d40_phy_res *phy = d40c->phy_chan;
bool is_src;
+ struct d40_desc *d;
+ struct d40_desc *_d;
/* Terminate all queued and active transfers */
d40_term_all(d40c);
+ /* Release client owned descriptors */
+ if (!list_empty(&d40c->client))
+ list_for_each_entry_safe(d, _d, &d40c->client, node) {
+ d40_pool_lli_free(d);
+ d40_desc_remove(d);
+ d40_desc_free(d40c, d);
+ }
+
if (phy == NULL) {
dev_err(&d40c->chan.dev->device, "[%s] phy == null\n",
__func__);
@@ -1292,22 +1874,12 @@ static int d40_free_dma(struct d40_chan *d40c)
return -EINVAL;
}
-
- res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
- if (res) {
- dev_err(&d40c->chan.dev->device, "[%s] suspend\n",
- __func__);
- return res;
- }
-
if (d40c->dma_cfg.dir == STEDMA40_MEM_TO_PERIPH ||
d40c->dma_cfg.dir == STEDMA40_MEM_TO_MEM) {
event = D40_TYPE_TO_EVENT(d40c->dma_cfg.dst_dev_type);
- dir = D40_CHAN_REG_SDLNK;
is_src = false;
} else if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM) {
event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type);
- dir = D40_CHAN_REG_SSLNK;
is_src = true;
} else {
dev_err(&d40c->chan.dev->device,
@@ -1315,22 +1887,19 @@ static int d40_free_dma(struct d40_chan *d40c)
return -EINVAL;
}
+ res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
+ if (res) {
+ dev_err(&d40c->chan.dev->device, "[%s] suspend failed\n",
+ __func__);
+ return res;
+ }
+
if (d40c->log_num != D40_PHY_CHAN) {
- /*
- * Release logical channel, deactivate the event line during
- * the time physical res is suspended.
- */
- writel((D40_DEACTIVATE_EVENTLINE << D40_EVENTLINE_POS(event)) &
- D40_EVENTLINE_MASK(event),
- d40c->base->virtbase + D40_DREG_PCBASE +
- phy->num * D40_DREG_PCDELTA + dir);
+ /* Release logical channel, deactivate the event line */
+ d40_config_set_event(d40c, false);
d40c->base->lookup_log_chans[d40c->log_num] = NULL;
- /*
- * Check if there are more logical allocation
- * on this phy channel.
- */
if (!d40_alloc_mask_free(phy, is_src, event)) {
/* Resume the other logical channels if any */
if (d40_chan_has_events(d40c)) {
@@ -1345,8 +1914,10 @@ static int d40_free_dma(struct d40_chan *d40c)
}
return 0;
}
- } else
- d40_alloc_mask_free(phy, is_src, 0);
+
+ } else {
+ (void) d40_alloc_mask_free(phy, is_src, 0);
+ }
/* Release physical channel */
res = d40_channel_execute_command(d40c, D40_DMA_STOP);
@@ -1355,39 +1926,14 @@ static int d40_free_dma(struct d40_chan *d40c)
"[%s] Failed to stop channel\n", __func__);
return res;
}
+
+ d40_power_off(d40c->base, phy->num);
+
d40c->phy_chan = NULL;
- /* Invalidate channel type */
- d40c->dma_cfg.channel_type = 0;
+ d40c->configured = false;
d40c->base->lookup_phy_chans[phy->num] = NULL;
return 0;
-
-
-}
-
-static int d40_pause(struct dma_chan *chan)
-{
- struct d40_chan *d40c =
- container_of(chan, struct d40_chan, chan);
- int res;
-
- unsigned long flags;
-
- spin_lock_irqsave(&d40c->lock, flags);
-
- res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
- if (res == 0) {
- if (d40c->log_num != D40_PHY_CHAN) {
- d40_config_set_event(d40c, false);
- /* Resume the other logical channels if any */
- if (d40_chan_has_events(d40c))
- res = d40_channel_execute_command(d40c,
- D40_DMA_RUN);
- }
- }
-
- spin_unlock_irqrestore(&d40c->lock, flags);
- return res;
}
static bool d40_is_paused(struct d40_chan *d40c)
@@ -1397,7 +1943,6 @@ static bool d40_is_paused(struct d40_chan *d40c)
void __iomem *active_reg;
u32 status;
u32 event;
- int res;
spin_lock_irqsave(&d40c->lock, flags);
@@ -1416,111 +1961,34 @@ static bool d40_is_paused(struct d40_chan *d40c)
goto _exit;
}
- res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
- if (res != 0)
- goto _exit;
-
if (d40c->dma_cfg.dir == STEDMA40_MEM_TO_PERIPH ||
- d40c->dma_cfg.dir == STEDMA40_MEM_TO_MEM)
+ d40c->dma_cfg.dir == STEDMA40_MEM_TO_MEM) {
event = D40_TYPE_TO_EVENT(d40c->dma_cfg.dst_dev_type);
- else if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM)
+ status = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SDLNK);
+ } else if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM) {
event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type);
- else {
+ status = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SSLNK);
+ } else {
dev_err(&d40c->chan.dev->device,
"[%s] Unknown direction\n", __func__);
goto _exit;
}
- status = d40_chan_has_events(d40c);
+
status = (status & D40_EVENTLINE_MASK(event)) >>
D40_EVENTLINE_POS(event);
if (status != D40_DMA_RUN)
is_paused = true;
-
- /* Resume the other logical channels if any */
- if (d40_chan_has_events(d40c))
- res = d40_channel_execute_command(d40c,
- D40_DMA_RUN);
-
_exit:
spin_unlock_irqrestore(&d40c->lock, flags);
return is_paused;
}
-
-static bool d40_tx_is_linked(struct d40_chan *d40c)
-{
- bool is_link;
-
- if (d40c->log_num != D40_PHY_CHAN)
- is_link = readl(&d40c->lcpa->lcsp3) & D40_MEM_LCSP3_DLOS_MASK;
- else
- is_link = readl(d40c->base->virtbase + D40_DREG_PCBASE +
- d40c->phy_chan->num * D40_DREG_PCDELTA +
- D40_CHAN_REG_SDLNK) &
- D40_SREG_LNK_PHYS_LNK_MASK;
- return is_link;
-}
-
-static u32 d40_residue(struct d40_chan *d40c)
-{
- u32 num_elt;
-
- if (d40c->log_num != D40_PHY_CHAN)
- num_elt = (readl(&d40c->lcpa->lcsp2) & D40_MEM_LCSP2_ECNT_MASK)
- >> D40_MEM_LCSP2_ECNT_POS;
- else
- num_elt = (readl(d40c->base->virtbase + D40_DREG_PCBASE +
- d40c->phy_chan->num * D40_DREG_PCDELTA +
- D40_CHAN_REG_SDELT) &
- D40_SREG_ELEM_PHY_ECNT_MASK) >> D40_SREG_ELEM_PHY_ECNT_POS;
- return num_elt * (1 << d40c->dma_cfg.dst_info.data_width);
-}
-
-static int d40_resume(struct dma_chan *chan)
-{
- struct d40_chan *d40c =
- container_of(chan, struct d40_chan, chan);
- int res = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&d40c->lock, flags);
-
- if (d40c->log_num != D40_PHY_CHAN) {
- res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
- if (res)
- goto out;
-
- /* If bytes left to transfer or linked tx resume job */
- if (d40_residue(d40c) || d40_tx_is_linked(d40c)) {
- d40_config_set_event(d40c, true);
- res = d40_channel_execute_command(d40c, D40_DMA_RUN);
- }
- } else if (d40_residue(d40c) || d40_tx_is_linked(d40c))
- res = d40_channel_execute_command(d40c, D40_DMA_RUN);
-
-out:
- spin_unlock_irqrestore(&d40c->lock, flags);
- return res;
-}
-
-static u32 stedma40_residue(struct dma_chan *chan)
-{
- struct d40_chan *d40c =
- container_of(chan, struct d40_chan, chan);
- u32 bytes_left;
- unsigned long flags;
-
- spin_lock_irqsave(&d40c->lock, flags);
- bytes_left = d40_residue(d40c);
- spin_unlock_irqrestore(&d40c->lock, flags);
-
- return bytes_left;
-}
-
-/* Public DMA functions in addition to the DMA engine framework */
-
int stedma40_set_psize(struct dma_chan *chan,
int src_psize,
int dst_psize)
@@ -1534,8 +2002,10 @@ int stedma40_set_psize(struct dma_chan *chan,
if (d40c->log_num != D40_PHY_CHAN) {
d40c->log_def.lcsp1 &= ~D40_MEM_LCSP1_SCFG_PSIZE_MASK;
d40c->log_def.lcsp3 &= ~D40_MEM_LCSP1_SCFG_PSIZE_MASK;
- d40c->log_def.lcsp1 |= src_psize << D40_MEM_LCSP1_SCFG_PSIZE_POS;
- d40c->log_def.lcsp3 |= dst_psize << D40_MEM_LCSP1_SCFG_PSIZE_POS;
+ d40c->log_def.lcsp1 |= src_psize
+ << D40_MEM_LCSP1_SCFG_PSIZE_POS;
+ d40c->log_def.lcsp3 |= dst_psize
+ << D40_MEM_LCSP1_SCFG_PSIZE_POS;
goto out;
}
@@ -1566,37 +2036,31 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
struct scatterlist *sgl_dst,
struct scatterlist *sgl_src,
unsigned int sgl_len,
- unsigned long flags)
+ unsigned long dma_flags)
{
int res;
struct d40_desc *d40d;
struct d40_chan *d40c = container_of(chan, struct d40_chan,
chan);
- unsigned long flg;
- int lli_max = d40c->base->plat_data->llis_per_log;
+ unsigned long flags;
+ if (d40c->phy_chan == NULL) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Unallocated channel.\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
- spin_lock_irqsave(&d40c->lock, flg);
+ spin_lock_irqsave(&d40c->lock, flags);
d40d = d40_desc_get(d40c);
if (d40d == NULL)
goto err;
- memset(d40d, 0, sizeof(struct d40_desc));
d40d->lli_len = sgl_len;
-
- d40d->txd.flags = flags;
+ d40d->lli_current = 0;
+ d40d->txd.flags = dma_flags;
if (d40c->log_num != D40_PHY_CHAN) {
- if (sgl_len > 1)
- /*
- * Check if there is space available in lcla. If not,
- * split list into 1-length and run only in lcpa
- * space.
- */
- if (d40_lcla_id_get(d40c,
- &d40c->base->lcla_pool) != 0)
- lli_max = 1;
if (d40_pool_lli_alloc(d40d, sgl_len, true) < 0) {
dev_err(&d40c->chan.dev->device,
@@ -1604,25 +2068,17 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
goto err;
}
- (void) d40_log_sg_to_lli(d40c->lcla.src_id,
- sgl_src,
+ (void) d40_log_sg_to_lli(sgl_src,
sgl_len,
d40d->lli_log.src,
d40c->log_def.lcsp1,
- d40c->dma_cfg.src_info.data_width,
- flags & DMA_PREP_INTERRUPT, lli_max,
- d40c->base->plat_data->llis_per_log);
+ d40c->dma_cfg.src_info.data_width);
- (void) d40_log_sg_to_lli(d40c->lcla.dst_id,
- sgl_dst,
+ (void) d40_log_sg_to_lli(sgl_dst,
sgl_len,
d40d->lli_log.dst,
d40c->log_def.lcsp3,
- d40c->dma_cfg.dst_info.data_width,
- flags & DMA_PREP_INTERRUPT, lli_max,
- d40c->base->plat_data->llis_per_log);
-
-
+ d40c->dma_cfg.dst_info.data_width);
} else {
if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) {
dev_err(&d40c->chan.dev->device,
@@ -1634,11 +2090,12 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
sgl_len,
0,
d40d->lli_phy.src,
- d40d->lli_phy.src_addr,
+ virt_to_phys(d40d->lli_phy.src),
d40c->src_def_cfg,
d40c->dma_cfg.src_info.data_width,
d40c->dma_cfg.src_info.psize,
- true);
+ false,
+ false);
if (res < 0)
goto err;
@@ -1647,28 +2104,32 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
sgl_len,
0,
d40d->lli_phy.dst,
- d40d->lli_phy.dst_addr,
+ virt_to_phys(d40d->lli_phy.dst),
d40c->dst_def_cfg,
d40c->dma_cfg.dst_info.data_width,
d40c->dma_cfg.dst_info.psize,
- true);
+ false,
+ false);
if (res < 0)
goto err;
(void) dma_map_single(d40c->base->dev, d40d->lli_phy.src,
d40d->lli_pool.size, DMA_TO_DEVICE);
+
}
dma_async_tx_descriptor_init(&d40d->txd, chan);
d40d->txd.tx_submit = d40_tx_submit;
- spin_unlock_irqrestore(&d40c->lock, flg);
+ spin_unlock_irqrestore(&d40c->lock, flags);
return &d40d->txd;
err:
- spin_unlock_irqrestore(&d40c->lock, flg);
+ if (d40d)
+ d40_desc_free(d40c, d40d);
+ spin_unlock_irqrestore(&d40c->lock, flags);
return NULL;
}
EXPORT_SYMBOL(stedma40_memcpy_sg);
@@ -1687,10 +2148,45 @@ bool stedma40_filter(struct dma_chan *chan, void *data)
} else
err = d40_config_memcpy(d40c);
+ if (!err)
+ d40c->configured = true;
+
return err == 0;
}
EXPORT_SYMBOL(stedma40_filter);
+static void __d40_set_prio_rt(struct d40_chan *d40c, int dev_type, bool src)
+{
+ bool realtime = d40c->dma_cfg.realtime;
+ bool highprio = d40c->dma_cfg.high_priority;
+ u32 prioreg = highprio ? D40_DREG_PSEG1 : D40_DREG_PCEG1;
+ u32 rtreg = realtime ? D40_DREG_RSEG1 : D40_DREG_RCEG1;
+ u32 event = D40_TYPE_TO_EVENT(dev_type);
+ u32 group = D40_TYPE_TO_GROUP(dev_type);
+ u32 bit = 1 << event;
+
+ /* Destination event lines are stored in the upper halfword */
+ if (!src)
+ bit <<= 16;
+
+ writel(bit, d40c->base->virtbase + prioreg + group * 4);
+ writel(bit, d40c->base->virtbase + rtreg + group * 4);
+}
+
+static void d40_set_prio_realtime(struct d40_chan *d40c)
+{
+ if (d40c->base->rev < 3)
+ return;
+
+ if ((d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM) ||
+ (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH))
+ __d40_set_prio_rt(d40c, d40c->dma_cfg.src_dev_type, true);
+
+ if ((d40c->dma_cfg.dir == STEDMA40_MEM_TO_PERIPH) ||
+ (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH))
+ __d40_set_prio_rt(d40c, d40c->dma_cfg.dst_dev_type, false);
+}
+
/* DMA ENGINE functions */
static int d40_alloc_chan_resources(struct dma_chan *chan)
{
@@ -1698,46 +2194,60 @@ static int d40_alloc_chan_resources(struct dma_chan *chan)
unsigned long flags;
struct d40_chan *d40c =
container_of(chan, struct d40_chan, chan);
+ bool is_free_phy;
spin_lock_irqsave(&d40c->lock, flags);
d40c->completed = chan->cookie = 1;
- /*
- * If no dma configuration is set (channel_type == 0)
- * use default configuration
- */
- if (d40c->dma_cfg.channel_type == 0) {
+ if (!d40c->configured) {
err = d40_config_memcpy(d40c);
- if (err)
- goto err_alloc;
+ if (err) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Failed to configure memcpy channel\n",
+ __func__);
+ goto fail;
+ }
}
- err = d40_allocate_channel(d40c);
+ err = d40_allocate_channel(d40c, &is_free_phy);
if (err) {
dev_err(&d40c->chan.dev->device,
"[%s] Failed to allocate channel\n", __func__);
- goto err_alloc;
+ goto fail;
}
- err = d40_config_chan(d40c, &d40c->dma_cfg);
- if (err) {
- dev_err(&d40c->chan.dev->device,
- "[%s] Failed to configure channel\n",
- __func__);
- goto err_config;
+ /* Fill in basic CFG register values */
+ d40_phy_cfg(&d40c->dma_cfg, &d40c->src_def_cfg,
+ &d40c->dst_def_cfg, d40c->log_num != D40_PHY_CHAN);
+
+ d40_set_prio_realtime(d40c);
+
+ if (d40c->log_num != D40_PHY_CHAN) {
+ d40_log_cfg(&d40c->dma_cfg,
+ &d40c->log_def.lcsp1, &d40c->log_def.lcsp3);
+
+ if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM)
+ d40c->lcpa = d40c->base->lcpa_base +
+ d40c->dma_cfg.src_dev_type *
+ D40_LCPA_CHAN_SIZE;
+ else
+ d40c->lcpa = d40c->base->lcpa_base +
+ d40c->dma_cfg.dst_dev_type *
+ D40_LCPA_CHAN_SIZE + D40_LCPA_CHAN_DST_DELTA;
}
- spin_unlock_irqrestore(&d40c->lock, flags);
- return 0;
+ /*
+ * Only write channel configuration to the DMA if the physical
+ * resource is free. In case of multiple logical channels
+ * on the same physical resource, only the first write is necessary.
+ */
- err_config:
- (void) d40_free_dma(d40c);
- err_alloc:
+ if (is_free_phy)
+ d40_config_write(d40c);
+fail:
spin_unlock_irqrestore(&d40c->lock, flags);
- dev_err(&d40c->chan.dev->device,
- "[%s] Channel allocation failed\n", __func__);
- return -EINVAL;
+ return err;
}
static void d40_free_chan_resources(struct dma_chan *chan)
@@ -1747,6 +2257,12 @@ static void d40_free_chan_resources(struct dma_chan *chan)
int err;
unsigned long flags;
+ if (d40c->phy_chan == NULL) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Cannot free unallocated channel\n", __func__);
+ return;
+ }
+
spin_lock_irqsave(&d40c->lock, flags);
err = d40_free_dma(d40c);
@@ -1761,15 +2277,21 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
dma_addr_t dst,
dma_addr_t src,
size_t size,
- unsigned long flags)
+ unsigned long dma_flags)
{
struct d40_desc *d40d;
struct d40_chan *d40c = container_of(chan, struct d40_chan,
chan);
- unsigned long flg;
+ unsigned long flags;
int err = 0;
- spin_lock_irqsave(&d40c->lock, flg);
+ if (d40c->phy_chan == NULL) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Channel is not allocated.\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+
+ spin_lock_irqsave(&d40c->lock, flags);
d40d = d40_desc_get(d40c);
if (d40d == NULL) {
@@ -1778,9 +2300,7 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
goto err;
}
- memset(d40d, 0, sizeof(struct d40_desc));
-
- d40d->txd.flags = flags;
+ d40d->txd.flags = dma_flags;
dma_async_tx_descriptor_init(&d40d->txd, chan);
@@ -1794,22 +2314,21 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
goto err;
}
d40d->lli_len = 1;
+ d40d->lli_current = 0;
d40_log_fill_lli(d40d->lli_log.src,
src,
size,
- 0,
d40c->log_def.lcsp1,
d40c->dma_cfg.src_info.data_width,
- true, true);
+ true);
d40_log_fill_lli(d40d->lli_log.dst,
dst,
size,
- 0,
d40c->log_def.lcsp3,
d40c->dma_cfg.dst_info.data_width,
- true, true);
+ true);
} else {
@@ -1848,28 +2367,72 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
d40d->lli_pool.size, DMA_TO_DEVICE);
}
- spin_unlock_irqrestore(&d40c->lock, flg);
+ spin_unlock_irqrestore(&d40c->lock, flags);
return &d40d->txd;
err_fill_lli:
dev_err(&d40c->chan.dev->device,
"[%s] Failed filling in PHY LLI\n", __func__);
- d40_pool_lli_free(d40d);
err:
- spin_unlock_irqrestore(&d40c->lock, flg);
+ if (d40d)
+ d40_desc_free(d40c, d40d);
+ spin_unlock_irqrestore(&d40c->lock, flags);
return NULL;
}
+static dma_addr_t d40_dev_rx_addr(struct d40_chan *d40c)
+{
+ dma_addr_t dev_addr = 0;
+
+ if (d40c->src_dev_addr)
+ dev_addr = d40c->src_dev_addr;
+ else
+ dev_addr = d40c->base->plat_data->
+ dev_rx[d40c->dma_cfg.src_dev_type];
+
+ return dev_addr;
+}
+
+static dma_addr_t d40_dev_tx_addr(struct d40_chan *d40c)
+{
+ dma_addr_t dev_addr = 0;
+
+ if (d40c->dst_dev_addr)
+ dev_addr = d40c->dst_dev_addr;
+ else
+ dev_addr = d40c->base->plat_data->
+ dev_tx[d40c->dma_cfg.dst_dev_type];
+
+ return dev_addr;
+}
+
+int stedma40_set_dev_addr(struct dma_chan *chan,
+ dma_addr_t src_dev_addr,
+ dma_addr_t dst_dev_addr)
+{
+ struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&d40c->lock, flags);
+
+ d40c->src_dev_addr = src_dev_addr;
+ d40c->dst_dev_addr = dst_dev_addr;
+
+ spin_unlock_irqrestore(&d40c->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(stedma40_set_dev_addr);
+
static int d40_prep_slave_sg_log(struct d40_desc *d40d,
struct d40_chan *d40c,
struct scatterlist *sgl,
unsigned int sg_len,
enum dma_data_direction direction,
- unsigned long flags)
+ unsigned long dma_flags)
{
dma_addr_t dev_addr = 0;
int total_size;
- int lli_max = d40c->base->plat_data->llis_per_log;
if (d40_pool_lli_alloc(d40d, sg_len, true) < 0) {
dev_err(&d40c->chan.dev->device,
@@ -1878,43 +2441,22 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d,
}
d40d->lli_len = sg_len;
- d40d->lli_tcount = 0;
+ d40d->lli_current = 0;
- if (sg_len > 1)
- /*
- * Check if there is space available in lcla.
- * If not, split list into 1-length and run only
- * in lcpa space.
- */
- if (d40_lcla_id_get(d40c, &d40c->base->lcla_pool) != 0)
- lli_max = 1;
-
- if (direction == DMA_FROM_DEVICE) {
- dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type];
- total_size = d40_log_sg_to_dev(&d40c->lcla,
- sgl, sg_len,
- &d40d->lli_log,
- &d40c->log_def,
- d40c->dma_cfg.src_info.data_width,
- d40c->dma_cfg.dst_info.data_width,
- direction,
- flags & DMA_PREP_INTERRUPT,
- dev_addr, lli_max,
- d40c->base->plat_data->llis_per_log);
- } else if (direction == DMA_TO_DEVICE) {
- dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type];
- total_size = d40_log_sg_to_dev(&d40c->lcla,
- sgl, sg_len,
- &d40d->lli_log,
- &d40c->log_def,
- d40c->dma_cfg.src_info.data_width,
- d40c->dma_cfg.dst_info.data_width,
- direction,
- flags & DMA_PREP_INTERRUPT,
- dev_addr, lli_max,
- d40c->base->plat_data->llis_per_log);
- } else
+ if (direction == DMA_FROM_DEVICE)
+ dev_addr = d40_dev_rx_addr(d40c);
+ else if (direction == DMA_TO_DEVICE)
+ dev_addr = d40_dev_tx_addr(d40c);
+ else
return -EINVAL;
+
+ total_size = d40_log_sg_to_dev(sgl, sg_len,
+ &d40d->lli_log,
+ &d40c->log_def,
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width,
+ direction,
+ dev_addr);
if (total_size < 0)
return -EINVAL;
@@ -1926,7 +2468,7 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
struct scatterlist *sgl,
unsigned int sgl_len,
enum dma_data_direction direction,
- unsigned long flags)
+ unsigned long dma_flags)
{
dma_addr_t src_dev_addr;
dma_addr_t dst_dev_addr;
@@ -1939,13 +2481,13 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
}
d40d->lli_len = sgl_len;
- d40d->lli_tcount = 0;
+ d40d->lli_current = 0;
if (direction == DMA_FROM_DEVICE) {
dst_dev_addr = 0;
- src_dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type];
+ src_dev_addr = d40_dev_rx_addr(d40c);
} else if (direction == DMA_TO_DEVICE) {
- dst_dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type];
+ dst_dev_addr = d40_dev_tx_addr(d40c);
src_dev_addr = 0;
} else
return -EINVAL;
@@ -1954,11 +2496,12 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
sgl_len,
src_dev_addr,
d40d->lli_phy.src,
- d40d->lli_phy.src_addr,
+ virt_to_phys(d40d->lli_phy.src),
d40c->src_def_cfg,
d40c->dma_cfg.src_info.data_width,
d40c->dma_cfg.src_info.psize,
- true);
+ d40d->cyclic,
+ d40d->txd.flags & DMA_PREP_INTERRUPT);
if (res < 0)
return res;
@@ -1966,11 +2509,12 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
sgl_len,
dst_dev_addr,
d40d->lli_phy.dst,
- d40d->lli_phy.dst_addr,
+ virt_to_phys(d40d->lli_phy.dst),
d40c->dst_def_cfg,
d40c->dma_cfg.dst_info.data_width,
d40c->dma_cfg.dst_info.psize,
- true);
+ d40d->cyclic,
+ d40d->txd.flags & DMA_PREP_INTERRUPT);
if (res < 0)
return res;
@@ -1979,53 +2523,63 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
return 0;
}
-static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan,
- struct scatterlist *sgl,
- unsigned int sg_len,
- enum dma_data_direction direction,
- unsigned long flags)
+static struct dma_async_tx_descriptor *
+d40_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_data_direction direction,
+ unsigned long dma_flags)
{
struct d40_desc *d40d;
struct d40_chan *d40c = container_of(chan, struct d40_chan,
chan);
- unsigned long flg;
+ unsigned long flags;
int err;
+
+ if (d40c->phy_chan == NULL) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Cannot prepare unallocated channel\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+
if (d40c->dma_cfg.pre_transfer)
d40c->dma_cfg.pre_transfer(chan,
d40c->dma_cfg.pre_transfer_data,
sg_dma_len(sgl));
- spin_lock_irqsave(&d40c->lock, flg);
+ spin_lock_irqsave(&d40c->lock, flags);
d40d = d40_desc_get(d40c);
- spin_unlock_irqrestore(&d40c->lock, flg);
if (d40d == NULL)
- return NULL;
-
- memset(d40d, 0, sizeof(struct d40_desc));
+ goto err;
if (d40c->log_num != D40_PHY_CHAN)
err = d40_prep_slave_sg_log(d40d, d40c, sgl, sg_len,
- direction, flags);
+ direction, dma_flags);
else
err = d40_prep_slave_sg_phy(d40d, d40c, sgl, sg_len,
- direction, flags);
+ direction, dma_flags);
if (err) {
dev_err(&d40c->chan.dev->device,
"[%s] Failed to prepare %s slave sg job: %d\n",
__func__,
d40c->log_num != D40_PHY_CHAN ? "log" : "phy", err);
- return NULL;
+ goto err;
}
- d40d->txd.flags = flags;
+ d40d->txd.flags = dma_flags;
dma_async_tx_descriptor_init(&d40d->txd, chan);
d40d->txd.tx_submit = d40_tx_submit;
+ spin_unlock_irqrestore(&d40c->lock, flags);
return &d40d->txd;
+
+err:
+ if (d40d)
+ d40_desc_free(d40c, d40d);
+ spin_unlock_irqrestore(&d40c->lock, flags);
+ return NULL;
}
static enum dma_status d40_tx_status(struct dma_chan *chan,
@@ -2033,10 +2587,18 @@ static enum dma_status d40_tx_status(struct dma_chan *chan,
struct dma_tx_state *txstate)
{
struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
+ unsigned long flags;
dma_cookie_t last_used;
dma_cookie_t last_complete;
int ret;
+ if (d40c->phy_chan == NULL) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Cannot read status of unallocated channel\n",
+ __func__);
+ return -EINVAL;
+ }
+
last_complete = d40c->completed;
last_used = chan->cookie;
@@ -2045,8 +2607,14 @@ static enum dma_status d40_tx_status(struct dma_chan *chan,
else
ret = dma_async_is_complete(cookie, last_complete, last_used);
- dma_set_tx_state(txstate, last_complete, last_used,
- stedma40_residue(chan));
+ if (txstate) {
+ txstate->last = last_complete;
+ txstate->used = last_used;
+
+ spin_lock_irqsave(&d40c->lock, flags);
+ txstate->residue = d40_residue(d40c);
+ spin_unlock_irqrestore(&d40c->lock, flags);
+ }
return ret;
}
@@ -2056,6 +2624,14 @@ static void d40_issue_pending(struct dma_chan *chan)
struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
unsigned long flags;
+ if (d40c->phy_chan == NULL) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Channel is not allocated!\n", __func__);
+ return;
+ }
+
+ d40_power_on(d40c->base, d40c->phy_chan->num);
+
spin_lock_irqsave(&d40c->lock, flags);
/* Busy means that pending jobs are already being processed */
@@ -2065,17 +2641,64 @@ static void d40_issue_pending(struct dma_chan *chan)
spin_unlock_irqrestore(&d40c->lock, flags);
}
+static void d40_terminate_all(struct dma_chan *chan)
+{
+ unsigned long flags;
+ struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
+ int ret;
+
+ spin_lock_irqsave(&d40c->lock, flags);
+
+ ret = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
+ if (ret)
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Failed to suspend channel\n", __func__);
+ else {
+ bool stop = true;
+
+ if (d40c->log_num != D40_PHY_CHAN) {
+ d40_config_set_event(d40c, false);
+
+ /* Resume the other logical channels if any */
+ if (d40_chan_has_events(d40c)) {
+ stop = false;
+ ret = d40_channel_execute_command(d40c,
+ D40_DMA_RUN);
+ if (ret)
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Failed to run channel\n",
+ __func__);
+ }
+ }
+
+ if (stop) {
+ ret = d40_channel_execute_command(d40c, D40_DMA_STOP);
+ if (ret)
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Failed to stop channel\n",
+ __func__);
+ }
+ }
+
+ d40_term_all(d40c);
+ spin_unlock_irqrestore(&d40c->lock, flags);
+}
+
static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
unsigned long arg)
{
unsigned long flags;
struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
+ if (d40c->phy_chan == NULL) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Channel is not allocated!\n", __func__);
+ return -EINVAL;
+ }
+
switch (cmd) {
case DMA_TERMINATE_ALL:
- spin_lock_irqsave(&d40c->lock, flags);
- d40_term_all(d40c);
- spin_unlock_irqrestore(&d40c->lock, flags);
+ d40_terminate_all(chan);
return 0;
case DMA_PAUSE:
return d40_pause(chan);
@@ -2087,6 +2710,189 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
return -ENXIO;
}
+dma_addr_t stedma40_get_src_addr(struct dma_chan *chan)
+{
+ struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
+ dma_addr_t addr;
+
+ if (d40c->log_num == D40_PHY_CHAN)
+ addr = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SSPTR);
+ else {
+ unsigned long lower;
+ unsigned long upper;
+
+ /*
+ * There is a potential for overflow between the time the two
+ * halves of the pointer are read.
+ */
+ lower = d40c->lcpa->lcsp0 & D40_MEM_LCSP0_SPTR_MASK;
+ upper = d40c->lcpa->lcsp1 & D40_MEM_LCSP1_SPTR_MASK;
+
+ addr = upper | lower;
+ }
+
+ return addr;
+}
+EXPORT_SYMBOL(stedma40_get_src_addr);
+
+dma_addr_t stedma40_get_dst_addr(struct dma_chan *chan)
+{
+ struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
+ dma_addr_t addr;
+
+ if (d40c->log_num == D40_PHY_CHAN)
+ addr = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SDPTR);
+ else {
+ unsigned long lower;
+ unsigned long upper;
+
+ lower = d40c->lcpa->lcsp2 & D40_MEM_LCSP2_DPTR_MASK;
+ upper = d40c->lcpa->lcsp3 & D40_MEM_LCSP3_DPTR_MASK;
+
+ addr = upper | lower;
+ }
+
+ return addr;
+}
+EXPORT_SYMBOL(stedma40_get_dst_addr);
+
+int stedma40_cyclic_start(struct dma_chan *chan)
+{
+ struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ spin_lock_irqsave(&d40c->lock, flags);
+
+ if (!d40c->cdesc)
+ goto out;
+
+ ret = d40_start(d40c);
+
+out:
+ spin_unlock_irqrestore(&d40c->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(stedma40_cyclic_start);
+
+void stedma40_cyclic_stop(struct dma_chan *chan)
+{
+ d40_terminate_all(chan);
+}
+EXPORT_SYMBOL(stedma40_cyclic_stop);
+
+void stedma40_cyclic_free(struct dma_chan *chan)
+{
+ struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
+ struct stedma40_cyclic_desc *cdesc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&d40c->lock, flags);
+
+ cdesc = d40c->cdesc;
+ if (!cdesc) {
+ spin_unlock_irqrestore(&d40c->lock, flags);
+ return;
+ }
+
+ d40c->cdesc = NULL;
+ d40_lcla_free_all(d40c, cdesc->d40d);
+
+ spin_unlock_irqrestore(&d40c->lock, flags);
+
+ kfree(cdesc);
+}
+EXPORT_SYMBOL(stedma40_cyclic_free);
+
+struct stedma40_cyclic_desc *
+stedma40_cyclic_prep_sg(struct dma_chan *chan,
+ struct scatterlist *sgl,
+ unsigned int sg_len,
+ enum dma_data_direction direction,
+ unsigned long dma_flags)
+{
+ struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
+ struct stedma40_cyclic_desc *cdesc;
+ struct d40_desc *d40d;
+ unsigned long flags;
+ void *mem;
+ int err;
+
+ mem = kzalloc(sizeof(struct stedma40_cyclic_desc)
+ + sizeof(struct d40_desc), GFP_KERNEL);
+ if (!mem)
+ return ERR_PTR(-ENOMEM);
+
+ cdesc = mem;
+ d40d = cdesc->d40d = mem + sizeof(struct stedma40_cyclic_desc);
+
+ spin_lock_irqsave(&d40c->lock, flags);
+
+ if (d40c->phy_chan == NULL) {
+ dev_err(&chan->dev->device,
+ "[%s] Cannot prepare unallocated channel\n", __func__);
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (d40c->cdesc || d40c->busy) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Cannot prepare cyclic job for busy channel\n",
+ __func__);
+ err = -EBUSY;
+ goto out;
+ }
+
+ d40d->cyclic = true;
+ d40d->txd.flags = dma_flags;
+ INIT_LIST_HEAD(&d40d->node);
+
+ if (d40c->log_num != D40_PHY_CHAN)
+ err = d40_prep_slave_sg_log(d40d, d40c, sgl, sg_len,
+ direction, dma_flags);
+ else
+ err = d40_prep_slave_sg_phy(d40d, d40c, sgl, sg_len,
+ direction, dma_flags);
+ if (err) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Failed to prepare %s slave sg job: %d\n",
+ __func__,
+ d40c->log_num != D40_PHY_CHAN ? "log" : "phy", err);
+ goto out;
+ }
+
+ d40_desc_load(d40c, d40d);
+
+ /*
+ * Couldn't get enough LCLA. We don't support splitting of cyclic
+ * jobs.
+ */
+ if (d40d->lli_current != d40d->lli_len) {
+ dev_err(&chan->dev->device,
+ "[%s] Couldn't prepare cyclic job: not enough LCLA",
+ __func__);
+ err = -EBUSY;
+ goto out;
+ }
+
+ d40c->cdesc = cdesc;
+
+ spin_unlock_irqrestore(&d40c->lock, flags);
+ return cdesc;
+
+out:
+ if (d40c->phy_chan)
+ d40_lcla_free_all(d40c, cdesc->d40d);
+ kfree(cdesc);
+ spin_unlock_irqrestore(&d40c->lock, flags);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(stedma40_cyclic_prep_sg);
+
/* Initialization functions */
static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma,
@@ -2103,21 +2909,15 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma,
d40c->base = base;
d40c->chan.device = dma;
- /* Invalidate lcla element */
- d40c->lcla.src_id = -1;
- d40c->lcla.dst_id = -1;
-
spin_lock_init(&d40c->lock);
d40c->log_num = D40_PHY_CHAN;
- INIT_LIST_HEAD(&d40c->free);
+ INIT_LIST_HEAD(&d40c->done);
INIT_LIST_HEAD(&d40c->active);
INIT_LIST_HEAD(&d40c->queue);
INIT_LIST_HEAD(&d40c->client);
- d40c->free_len = 0;
-
tasklet_init(&d40c->tasklet, dma_tasklet,
(unsigned long) d40c);
@@ -2142,8 +2942,8 @@ static int __init d40_dmaengine_init(struct d40_base *base,
base->dma_slave.device_prep_dma_memcpy = d40_prep_memcpy;
base->dma_slave.device_prep_slave_sg = d40_prep_slave_sg;
base->dma_slave.device_tx_status = d40_tx_status;
- base->dma_slave.device_issue_pending = d40_issue_pending;
base->dma_slave.device_control = d40_control;
+ base->dma_slave.device_issue_pending = d40_issue_pending;
base->dma_slave.dev = base->dev;
err = dma_async_device_register(&base->dma_slave);
@@ -2166,8 +2966,8 @@ static int __init d40_dmaengine_init(struct d40_base *base,
base->dma_memcpy.device_prep_dma_memcpy = d40_prep_memcpy;
base->dma_memcpy.device_prep_slave_sg = d40_prep_slave_sg;
base->dma_memcpy.device_tx_status = d40_tx_status;
- base->dma_memcpy.device_issue_pending = d40_issue_pending;
base->dma_memcpy.device_control = d40_control;
+ base->dma_memcpy.device_issue_pending = d40_issue_pending;
base->dma_memcpy.dev = base->dev;
/*
* This controller can only access address at even
@@ -2196,8 +2996,9 @@ static int __init d40_dmaengine_init(struct d40_base *base,
base->dma_both.device_prep_dma_memcpy = d40_prep_memcpy;
base->dma_both.device_prep_slave_sg = d40_prep_slave_sg;
base->dma_both.device_tx_status = d40_tx_status;
- base->dma_both.device_issue_pending = d40_issue_pending;
base->dma_both.device_control = d40_control;
+ base->dma_both.device_issue_pending = d40_issue_pending;
+
base->dma_both.dev = base->dev;
base->dma_both.copy_align = 2;
err = dma_async_device_register(&base->dma_both);
@@ -2217,6 +3018,80 @@ failure1:
return err;
}
+/* Suspend resume functionality */
+#ifdef CONFIG_PM
+static int d40_save_restore_registers(struct d40_base *base, bool save)
+{
+ int odd_even_bit = -2;
+ u32 val[2];
+ int i;
+
+ /*
+ * TODO: update the allocation map to mark secure registers and
+ * use that instead this piece below.
+ */
+ val[0] = readl(base->virtbase + D40_DREG_PRSME);
+ val[1] = readl(base->virtbase + D40_DREG_PRSMO);
+
+ /* Save all standard channel parameter registers */
+ for (i = 0; i < base->num_phy_chans; i++) {
+ int idx = i * ARRAY_SIZE(d40_backup_regs_chan);
+ u32 *backup = &base->reg_val_backup_chan[idx];
+ int j;
+
+ /* Ignore channels in secure mode */
+ odd_even_bit += 2 * ((i % 2) == 0);
+ if (((val[i % 2] >> odd_even_bit) & D40_DREG_PRSM_MODE_MASK)
+ == D40_DREG_PRSM_MODE_SECURE)
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(d40_backup_regs_chan); j++) {
+ void __iomem *addr = base->virtbase
+ + D40_DREG_PCBASE
+ + i * D40_DREG_PCDELTA
+ + d40_backup_regs_chan[j];
+
+ if (save)
+ backup[j] = readl(addr);
+ else
+ writel(backup[j], addr);
+ }
+ }
+
+ /* Save global registers */
+ for (i = 0 ; i < ARRAY_SIZE(d40_backup_regs) ; i++) {
+ void __iomem *addr = base->virtbase + d40_backup_regs[i];
+
+ if (save)
+ base->reg_val_backup[i] = readl(addr);
+ else
+ writel(base->reg_val_backup[i], addr);
+ }
+
+ /* Enable all clocks -- revisit after HW bug is fixed */
+ writel(D40_DREG_GCC_ENABLE_ALL, base->virtbase + D40_DREG_GCC);
+
+ return 0;
+}
+
+static int d40_pm_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct d40_base *base = platform_get_drvdata(pdev);
+
+ return d40_save_restore_registers(base, true);
+}
+
+static int d40_pm_resume(struct platform_device *pdev)
+{
+ struct d40_base *base = platform_get_drvdata(pdev);
+
+ return d40_save_restore_registers(base, false);
+}
+#else
+#define d40_pm_suspend NULL
+#define d40_pm_resume NULL
+#endif
+
/* Initialization functions. */
static int __init d40_phy_res_init(struct d40_base *base)
@@ -2224,6 +3099,7 @@ static int __init d40_phy_res_init(struct d40_base *base)
int i;
int num_phy_chans_avail = 0;
u32 val[2];
+ u32 gcc = D40_DREG_GCC_ENA;
int odd_even_bit = -2;
val[0] = readl(base->virtbase + D40_DREG_PRSME);
@@ -2232,10 +3108,17 @@ static int __init d40_phy_res_init(struct d40_base *base)
for (i = 0; i < base->num_phy_chans; i++) {
base->phy_res[i].num = i;
odd_even_bit += 2 * ((i % 2) == 0);
- if (((val[i % 2] >> odd_even_bit) & 3) == 1) {
+ if (((val[i % 2] >> odd_even_bit) & D40_DREG_PRSM_MODE_MASK)
+ == D40_DREG_PRSM_MODE_SECURE) {
/* Mark security only channels as occupied */
base->phy_res[i].allocated_src = D40_ALLOC_PHY;
base->phy_res[i].allocated_dst = D40_ALLOC_PHY;
+
+ gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(i),
+ D40_DREG_GCC_DST);
+ gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(i),
+ D40_DREG_GCC_SRC);
+
} else {
base->phy_res[i].allocated_src = D40_ALLOC_FREE;
base->phy_res[i].allocated_dst = D40_ALLOC_FREE;
@@ -2243,6 +3126,16 @@ static int __init d40_phy_res_init(struct d40_base *base)
}
spin_lock_init(&base->phy_res[i].lock);
}
+
+ /* Mark disabled channels as occupied */
+ for (i = 0; base->plat_data->disabled_channels[i] != -1; i++) {
+ int chan = base->plat_data->disabled_channels[i];
+
+ base->phy_res[chan].allocated_src = D40_ALLOC_PHY;
+ base->phy_res[chan].allocated_dst = D40_ALLOC_PHY;
+ num_phy_chans_avail--;
+ }
+
dev_info(base->dev, "%d of %d physical DMA channels available\n",
num_phy_chans_avail, base->num_phy_chans);
@@ -2260,6 +3153,9 @@ static int __init d40_phy_res_init(struct d40_base *base)
val[0] = val[0] >> 2;
}
+ /* Enable all clocks -- revisit after HW bug is fixed */
+ writel(D40_DREG_GCC_ENABLE_ALL, base->virtbase + D40_DREG_GCC);
+
return num_phy_chans_avail;
}
@@ -2271,9 +3167,10 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
{ .reg = D40_DREG_PERIPHID1, .val = 0x0000},
/*
* D40_DREG_PERIPHID2 Depends on HW revision:
- * MOP500/HREF ED has 0x0008,
+ * DB8500ed has 0x0008,
* ? has 0x0018,
- * HREF V1 has 0x0028
+ * DB8500v1 has 0x0028
+ * DB8500v2 has 0x0038
*/
{ .reg = D40_DREG_PERIPHID3, .val = 0x0000},
@@ -2291,6 +3188,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
int num_log_chans = 0;
int num_phy_chans;
int i;
+ u32 val;
clk = clk_get(&pdev->dev, NULL);
@@ -2300,6 +3198,10 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
goto failure;
}
+ /*
+ * Since the secure world does not handle clock, we have to
+ * let it run all the time
+ */
clk_enable(clk);
/* Get IO for DMAC base address */
@@ -2329,12 +3231,13 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
}
}
- i = readl(virtbase + D40_DREG_PERIPHID2);
+ /* Get silicon revision */
+ val = readl(virtbase + D40_DREG_PERIPHID2);
- if ((i & 0xf) != D40_PERIPHID2_DESIGNER) {
+ if ((val & 0xf) != D40_PERIPHID2_DESIGNER) {
dev_err(&pdev->dev,
"[%s] Unknown designer! Got %x wanted %x\n",
- __func__, i & 0xf, D40_PERIPHID2_DESIGNER);
+ __func__, val & 0xf, D40_PERIPHID2_DESIGNER);
goto failure;
}
@@ -2342,7 +3245,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
num_phy_chans = 4 * (readl(virtbase + D40_DREG_ICFG) & 0x7) + 4;
dev_info(&pdev->dev, "hardware revision: %d @ 0x%x\n",
- (i >> 4) & 0xf, res->start);
+ (val >> 4) & 0xf, res->start);
plat_data = pdev->dev.platform_data;
@@ -2364,6 +3267,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
goto failure;
}
+ base->rev = (val >> 4) & 0xf;
base->clk = clk;
base->num_phy_chans = num_phy_chans;
base->num_log_chans = num_log_chans;
@@ -2375,6 +3279,8 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
base->phy_chans = ((void *)base) + ALIGN(sizeof(struct d40_base), 4);
base->log_chans = &base->phy_chans[num_phy_chans];
+ atomic_set(&base->usage, 1);
+
base->phy_res = kzalloc(num_phy_chans * sizeof(struct d40_phy_res),
GFP_KERNEL);
if (!base->phy_res)
@@ -2397,15 +3303,30 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
if (!base->lookup_log_chans)
goto failure;
}
- base->lcla_pool.alloc_map = kzalloc(num_phy_chans * sizeof(u32),
+
+ base->reg_val_backup_chan = kmalloc(sizeof(u32) *
+ base->num_phy_chans *
+ ARRAY_SIZE(d40_backup_regs_chan),
GFP_KERNEL);
+ if (!base->reg_val_backup_chan)
+ goto failure;
+
+ base->lcla_pool.alloc_map =
+ kzalloc(num_phy_chans * sizeof(struct d40_desc *)
+ * D40_LCLA_LINK_PER_EVENT_GRP, GFP_KERNEL);
if (!base->lcla_pool.alloc_map)
goto failure;
+ base->desc_slab = kmem_cache_create(D40_NAME, sizeof(struct d40_desc),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL);
+ if (base->desc_slab == NULL)
+ goto failure;
+
return base;
failure:
- if (clk) {
+ if (!IS_ERR(clk)) {
clk_disable(clk);
clk_put(clk);
}
@@ -2419,6 +3340,7 @@ failure:
if (base) {
kfree(base->lcla_pool.alloc_map);
+ kfree(base->reg_val_backup_chan);
kfree(base->lookup_log_chans);
kfree(base->lookup_phy_chans);
kfree(base->phy_res);
@@ -2431,9 +3353,9 @@ failure:
static void __init d40_hw_init(struct d40_base *base)
{
- static const struct d40_reg_val dma_init_reg[] = {
+ static struct d40_reg_val dma_init_reg[] = {
/* Clock every part of the DMA block from start */
- { .reg = D40_DREG_GCC, .val = 0x0000ff01},
+ { .reg = D40_DREG_GCC, .val = D40_DREG_GCC_ENABLE_ALL},
/* Interrupts on all logical channels */
{ .reg = D40_DREG_LCMIS0, .val = 0xFFFFFFFF},
@@ -2495,6 +3417,81 @@ static void __init d40_hw_init(struct d40_base *base)
}
+static int __init d40_lcla_allocate(struct d40_base *base)
+{
+ unsigned long *page_list;
+ int i;
+ int j;
+ int ret = 0;
+
+ /*
+ * This is somewhat ugly. We need 8192 bytes that are 18 bit aligned,
+ * To full fill this hardware requirement without wasting 256 kb
+ * we allocate pages until we get an aligned one.
+ */
+ page_list = kmalloc(sizeof(unsigned long) * MAX_LCLA_ALLOC_ATTEMPTS,
+ GFP_KERNEL);
+
+ if (!page_list) {
+ ret = -ENOMEM;
+ goto failure;
+ }
+
+ /* Calculating how many pages that are required */
+ base->lcla_pool.pages = SZ_1K * base->num_phy_chans / PAGE_SIZE;
+
+ for (i = 0; i < MAX_LCLA_ALLOC_ATTEMPTS; i++) {
+ page_list[i] = __get_free_pages(GFP_KERNEL,
+ base->lcla_pool.pages);
+ if (!page_list[i]) {
+
+ dev_err(base->dev,
+ "[%s] Failed to allocate %d pages.\n",
+ __func__, base->lcla_pool.pages);
+
+ for (j = 0; j < i; j++)
+ free_pages(page_list[j], base->lcla_pool.pages);
+ goto failure;
+ }
+
+ if ((virt_to_phys((void *)page_list[i]) &
+ (LCLA_ALIGNMENT - 1)) == 0)
+ break;
+ }
+
+ for (j = 0; j < i; j++)
+ free_pages(page_list[j], base->lcla_pool.pages);
+
+ if (i < MAX_LCLA_ALLOC_ATTEMPTS) {
+ base->lcla_pool.base = (void *)page_list[i];
+ } else {
+ /*
+ * After many attempts, no succees with finding the correct
+ * alignment try with allocating a big buffer.
+ */
+ dev_warn(base->dev,
+ "[%s] Failed to get %d pages @ 18 bit align.\n",
+ __func__, base->lcla_pool.pages);
+ base->lcla_pool.base_unaligned = kmalloc(SZ_1K *
+ base->num_phy_chans +
+ LCLA_ALIGNMENT,
+ GFP_KERNEL);
+ if (!base->lcla_pool.base_unaligned) {
+ ret = -ENOMEM;
+ goto failure;
+ }
+
+ base->lcla_pool.base = PTR_ALIGN(base->lcla_pool.base_unaligned,
+ LCLA_ALIGNMENT);
+ }
+
+ writel(virt_to_phys(base->lcla_pool.base),
+ base->virtbase + D40_DREG_LCLA);
+failure:
+ kfree(page_list);
+ return ret;
+}
+
static int __init d40_probe(struct platform_device *pdev)
{
int err;
@@ -2515,6 +3512,7 @@ static int __init d40_probe(struct platform_device *pdev)
spin_lock_init(&base->interrupt_lock);
spin_lock_init(&base->execmd_lock);
+ spin_lock_init(&base->pm_gcc_lock);
/* Get IO for logical channel parameter address */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lcpa");
@@ -2554,48 +3552,25 @@ static int __init d40_probe(struct platform_device *pdev)
__func__);
goto failure;
}
- /* Get IO for logical channel link address */
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lcla");
- if (!res) {
- ret = -ENOENT;
- dev_err(&pdev->dev,
- "[%s] No \"lcla\" resource defined\n",
- __func__);
- goto failure;
- }
- base->lcla_pool.base_size = resource_size(res);
- base->lcla_pool.phy = res->start;
+ ret = d40_lcla_allocate(base);
- if (request_mem_region(res->start, resource_size(res),
- D40_NAME " I/O lcla") == NULL) {
- ret = -EBUSY;
- dev_err(&pdev->dev,
- "[%s] Failed to request LCLA region 0x%x-0x%x\n",
- __func__, res->start, res->end);
+ if (ret) {
+ dev_err(&pdev->dev, "[%s] Failed to allocate LCLA area\n",
+ __func__);
goto failure;
- }
- val = readl(base->virtbase + D40_DREG_LCLA);
- if (res->start != val && val != 0) {
- dev_warn(&pdev->dev,
- "[%s] Mismatch LCLA dma 0x%x, def 0x%x\n",
- __func__, val, res->start);
- } else
- writel(res->start, base->virtbase + D40_DREG_LCLA);
- base->lcla_pool.base = ioremap(res->start, resource_size(res));
- if (!base->lcla_pool.base) {
- ret = -ENOMEM;
- dev_err(&pdev->dev,
- "[%s] Failed to ioremap LCLA 0x%x-0x%x\n",
- __func__, res->start, res->end);
- goto failure;
}
+#ifdef CONFIG_STE_DMA40_DEBUG
+ sted40_history_set_virtbase(base->virtbase,
+ base->lcpa_base,
+ base->lcpa_size,
+ base->lcla_pool.base,
+ SZ_1K * base->num_phy_chans);
+#endif
spin_lock_init(&base->lcla_pool.lock);
- base->lcla_pool.num_blocks = base->num_phy_chans;
-
base->irq = platform_get_irq(pdev, 0);
ret = request_irq(base->irq, d40_handle_interrupt, 0, D40_NAME, base);
@@ -2611,16 +3586,26 @@ static int __init d40_probe(struct platform_device *pdev)
d40_hw_init(base);
+ atomic_dec(&base->usage);
+
+ base->reg_val_backup_chan = kmalloc(sizeof(u32) * base->num_phy_chans *
+ ARRAY_SIZE(d40_backup_regs_chan), GFP_KERNEL);
+
dev_info(base->dev, "initialized\n");
return 0;
failure:
if (base) {
+ if (base->desc_slab)
+ kmem_cache_destroy(base->desc_slab);
if (base->virtbase)
iounmap(base->virtbase);
- if (base->lcla_pool.phy)
- release_mem_region(base->lcla_pool.phy,
- base->lcla_pool.base_size);
+ if (!base->lcla_pool.base_unaligned && base->lcla_pool.base)
+ free_pages((unsigned long)base->lcla_pool.base,
+ base->lcla_pool.pages);
+
+ kfree(base->lcla_pool.base_unaligned);
+
if (base->phy_lcpa)
release_mem_region(base->phy_lcpa,
base->lcpa_size);
@@ -2648,6 +3633,8 @@ static struct platform_driver d40_driver = {
.owner = THIS_MODULE,
.name = D40_NAME,
},
+ .suspend = d40_pm_suspend,
+ .resume = d40_pm_resume,
};
int __init stedma40_init(void)
diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c
index 561fdd8a80c..f284f9e88c8 100644
--- a/drivers/dma/ste_dma40_ll.c
+++ b/drivers/dma/ste_dma40_ll.c
@@ -1,16 +1,20 @@
/*
- * driver/dma/ste_dma40_ll.c
- *
- * Copyright (C) ST-Ericsson 2007-2010
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
#include <linux/kernel.h>
#include <plat/ste_dma40.h>
#include "ste_dma40_ll.h"
+#ifdef CONFIG_STE_DMA40_DEBUG
+#include "ste_dma40_debug.h"
+#define MARK sted40_history_text((char *)__func__)
+#else
+#define MARK
+#endif
/* Sets up proper LCSP1 and LCSP3 register for a logical channel */
void d40_log_cfg(struct stedma40_chan_cfg *cfg,
@@ -39,16 +43,13 @@ void d40_log_cfg(struct stedma40_chan_cfg *cfg,
cfg->dir == STEDMA40_PERIPH_TO_PERIPH)
l3 |= 1 << D40_MEM_LCSP3_DCFG_MST_POS;
- l3 |= 1 << D40_MEM_LCSP3_DCFG_TIM_POS;
l3 |= 1 << D40_MEM_LCSP3_DCFG_EIM_POS;
l3 |= cfg->dst_info.psize << D40_MEM_LCSP3_DCFG_PSIZE_POS;
l3 |= cfg->dst_info.data_width << D40_MEM_LCSP3_DCFG_ESIZE_POS;
- l3 |= 1 << D40_MEM_LCSP3_DTCP_POS;
l1 |= 1 << D40_MEM_LCSP1_SCFG_EIM_POS;
l1 |= cfg->src_info.psize << D40_MEM_LCSP1_SCFG_PSIZE_POS;
l1 |= cfg->src_info.data_width << D40_MEM_LCSP1_SCFG_ESIZE_POS;
- l1 |= 1 << D40_MEM_LCSP1_STCP_POS;
*lcsp1 = l1;
*lcsp3 = l3;
@@ -113,13 +114,15 @@ void d40_phy_cfg(struct stedma40_chan_cfg *cfg,
src |= 1 << D40_SREG_CFG_LOG_GIM_POS;
}
- if (cfg->channel_type & STEDMA40_HIGH_PRIORITY_CHANNEL) {
+ if (cfg->high_priority) {
src |= 1 << D40_SREG_CFG_PRI_POS;
dst |= 1 << D40_SREG_CFG_PRI_POS;
}
- src |= cfg->src_info.endianess << D40_SREG_CFG_LBE_POS;
- dst |= cfg->dst_info.endianess << D40_SREG_CFG_LBE_POS;
+ if (cfg->src_info.big_endian)
+ src |= 1 << D40_SREG_CFG_LBE_POS;
+ if (cfg->dst_info.big_endian)
+ dst |= 1 << D40_SREG_CFG_LBE_POS;
*src_cfg = src;
*dst_cfg = dst;
@@ -198,13 +201,15 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
u32 reg_cfg,
u32 data_width,
int psize,
- bool term_int)
+ bool cyclic,
+ bool cyclic_int)
{
int total_size = 0;
int i;
struct scatterlist *current_sg = sg;
dma_addr_t next_lli_phys;
dma_addr_t dst;
+ bool interrupt;
int err = 0;
for_each_sg(sg, current_sg, sg_len, i) {
@@ -213,16 +218,18 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
/* If this scatter list entry is the last one, no next link */
if (sg_len - 1 == i)
- next_lli_phys = 0;
+ next_lli_phys = cyclic ? lli_phys : 0;
else
next_lli_phys = ALIGN(lli_phys + (i + 1) *
sizeof(struct d40_phy_lli),
D40_LLI_ALIGN);
+ interrupt = cyclic ? cyclic_int : !next_lli_phys;
+
if (target)
dst = target;
else
- dst = sg_phys(current_sg);
+ dst = sg_dma_address(current_sg);
err = d40_phy_fill_lli(&lli[i],
dst,
@@ -230,7 +237,7 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
psize,
next_lli_phys,
reg_cfg,
- !next_lli_phys,
+ interrupt,
data_width,
target == dst);
if (err)
@@ -238,7 +245,7 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
}
return total_size;
- err:
+err:
return err;
}
@@ -271,11 +278,64 @@ void d40_phy_lli_write(void __iomem *virtbase,
/* DMA logical lli operations */
+static void d40_log_lli_link(struct d40_log_lli *lli_dst,
+ struct d40_log_lli *lli_src,
+ int next,
+ bool interrupt)
+{
+ u32 slos = 0;
+ u32 dlos = 0;
+
+ if (next != -EINVAL) {
+ slos = next * 2;
+ dlos = next * 2 + 1;
+ }
+
+ if (interrupt) {
+ lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK;
+ lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK;
+ }
+
+ lli_src->lcsp13 = (lli_src->lcsp13 & ~D40_MEM_LCSP1_SLOS_MASK) |
+ (slos << D40_MEM_LCSP1_SLOS_POS);
+
+ lli_dst->lcsp13 = (lli_dst->lcsp13 & ~D40_MEM_LCSP1_SLOS_MASK) |
+ (dlos << D40_MEM_LCSP1_SLOS_POS);
+}
+
+void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
+ struct d40_log_lli *lli_dst,
+ struct d40_log_lli *lli_src,
+ int next,
+ bool interrupt)
+{
+ d40_log_lli_link(lli_dst, lli_src, next, interrupt);
+
+ writel(lli_src->lcsp02, &lcpa[0].lcsp0);
+ writel(lli_src->lcsp13, &lcpa[0].lcsp1);
+ writel(lli_dst->lcsp02, &lcpa[0].lcsp2);
+ writel(lli_dst->lcsp13, &lcpa[0].lcsp3);
+}
+
+void d40_log_lli_lcla_write(struct d40_log_lli *lcla,
+ struct d40_log_lli *lli_dst,
+ struct d40_log_lli *lli_src,
+ int next,
+ bool interrupt)
+{
+ d40_log_lli_link(lli_dst, lli_src, next, interrupt);
+
+ writel(lli_src->lcsp02, &lcla[0].lcsp02);
+ writel(lli_src->lcsp13, &lcla[0].lcsp13);
+ writel(lli_dst->lcsp02, &lcla[1].lcsp02);
+ writel(lli_dst->lcsp13, &lcla[1].lcsp13);
+}
+
void d40_log_fill_lli(struct d40_log_lli *lli,
dma_addr_t data, u32 data_size,
- u32 lli_next_off, u32 reg_cfg,
+ u32 reg_cfg,
u32 data_width,
- bool term_int, bool addr_inc)
+ bool addr_inc)
{
lli->lcsp13 = reg_cfg;
@@ -290,165 +350,69 @@ void d40_log_fill_lli(struct d40_log_lli *lli,
if (addr_inc)
lli->lcsp13 |= D40_MEM_LCSP1_SCFG_INCR_MASK;
- lli->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK;
- /* If this scatter list entry is the last one, no next link */
- lli->lcsp13 |= (lli_next_off << D40_MEM_LCSP1_SLOS_POS) &
- D40_MEM_LCSP1_SLOS_MASK;
-
- if (term_int)
- lli->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK;
- else
- lli->lcsp13 &= ~D40_MEM_LCSP1_SCFG_TIM_MASK;
}
-int d40_log_sg_to_dev(struct d40_lcla_elem *lcla,
- struct scatterlist *sg,
+int d40_log_sg_to_dev(struct scatterlist *sg,
int sg_len,
struct d40_log_lli_bidir *lli,
struct d40_def_lcsp *lcsp,
u32 src_data_width,
u32 dst_data_width,
enum dma_data_direction direction,
- bool term_int, dma_addr_t dev_addr, int max_len,
- int llis_per_log)
+ dma_addr_t dev_addr)
{
int total_size = 0;
struct scatterlist *current_sg = sg;
int i;
- u32 next_lli_off_dst;
- u32 next_lli_off_src;
-
- next_lli_off_src = 0;
- next_lli_off_dst = 0;
for_each_sg(sg, current_sg, sg_len, i) {
total_size += sg_dma_len(current_sg);
- /*
- * If this scatter list entry is the last one or
- * max length, terminate link.
- */
- if (sg_len - 1 == i || ((i+1) % max_len == 0)) {
- next_lli_off_src = 0;
- next_lli_off_dst = 0;
- } else {
- if (next_lli_off_dst == 0 &&
- next_lli_off_src == 0) {
- /* The first lli will be at next_lli_off */
- next_lli_off_dst = (lcla->dst_id *
- llis_per_log + 1);
- next_lli_off_src = (lcla->src_id *
- llis_per_log + 1);
- } else {
- next_lli_off_dst++;
- next_lli_off_src++;
- }
- }
-
if (direction == DMA_TO_DEVICE) {
d40_log_fill_lli(&lli->src[i],
- sg_phys(current_sg),
+ sg_dma_address(current_sg),
sg_dma_len(current_sg),
- next_lli_off_src,
lcsp->lcsp1, src_data_width,
- term_int && !next_lli_off_src,
true);
d40_log_fill_lli(&lli->dst[i],
dev_addr,
sg_dma_len(current_sg),
- next_lli_off_dst,
lcsp->lcsp3, dst_data_width,
- /* No next == terminal interrupt */
- term_int && !next_lli_off_dst,
false);
} else {
d40_log_fill_lli(&lli->dst[i],
- sg_phys(current_sg),
+ sg_dma_address(current_sg),
sg_dma_len(current_sg),
- next_lli_off_dst,
lcsp->lcsp3, dst_data_width,
- /* No next == terminal interrupt */
- term_int && !next_lli_off_dst,
true);
d40_log_fill_lli(&lli->src[i],
dev_addr,
sg_dma_len(current_sg),
- next_lli_off_src,
lcsp->lcsp1, src_data_width,
- term_int && !next_lli_off_src,
false);
}
}
return total_size;
}
-int d40_log_sg_to_lli(int lcla_id,
- struct scatterlist *sg,
+int d40_log_sg_to_lli(struct scatterlist *sg,
int sg_len,
struct d40_log_lli *lli_sg,
u32 lcsp13, /* src or dst*/
- u32 data_width,
- bool term_int, int max_len, int llis_per_log)
+ u32 data_width)
{
int total_size = 0;
struct scatterlist *current_sg = sg;
int i;
- u32 next_lli_off = 0;
for_each_sg(sg, current_sg, sg_len, i) {
total_size += sg_dma_len(current_sg);
- /*
- * If this scatter list entry is the last one or
- * max length, terminate link.
- */
- if (sg_len - 1 == i || ((i+1) % max_len == 0))
- next_lli_off = 0;
- else {
- if (next_lli_off == 0)
- /* The first lli will be at next_lli_off */
- next_lli_off = lcla_id * llis_per_log + 1;
- else
- next_lli_off++;
- }
-
d40_log_fill_lli(&lli_sg[i],
- sg_phys(current_sg),
+ sg_dma_address(current_sg),
sg_dma_len(current_sg),
- next_lli_off,
lcsp13, data_width,
- term_int && !next_lli_off,
true);
}
return total_size;
}
-
-void d40_log_lli_write(struct d40_log_lli_full *lcpa,
- struct d40_log_lli *lcla_src,
- struct d40_log_lli *lcla_dst,
- struct d40_log_lli *lli_dst,
- struct d40_log_lli *lli_src,
- int llis_per_log)
-{
- u32 slos = 0;
- u32 dlos = 0;
- int i;
-
- lcpa->lcsp0 = lli_src->lcsp02;
- lcpa->lcsp1 = lli_src->lcsp13;
- lcpa->lcsp2 = lli_dst->lcsp02;
- lcpa->lcsp3 = lli_dst->lcsp13;
-
- slos = lli_src->lcsp13 & D40_MEM_LCSP1_SLOS_MASK;
- dlos = lli_dst->lcsp13 & D40_MEM_LCSP3_DLOS_MASK;
-
- for (i = 0; (i < llis_per_log) && slos && dlos; i++) {
- writel(lli_src[i+1].lcsp02, &lcla_src[i].lcsp02);
- writel(lli_src[i+1].lcsp13, &lcla_src[i].lcsp13);
- writel(lli_dst[i+1].lcsp02, &lcla_dst[i].lcsp02);
- writel(lli_dst[i+1].lcsp13, &lcla_dst[i].lcsp13);
-
- slos = lli_src[i+1].lcsp13 & D40_MEM_LCSP1_SLOS_MASK;
- dlos = lli_dst[i+1].lcsp13 & D40_MEM_LCSP3_DLOS_MASK;
- }
-}
diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h
index 2029280cb33..22b5fd76f96 100644
--- a/drivers/dma/ste_dma40_ll.h
+++ b/drivers/dma/ste_dma40_ll.h
@@ -1,10 +1,8 @@
/*
- * driver/dma/ste_dma40_ll.h
- *
- * Copyright (C) ST-Ericsson 2007-2010
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson SA
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson SA
* License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
#ifndef STE_DMA40_LL_H
#define STE_DMA40_LL_H
@@ -13,8 +11,13 @@
#define D40_DREG_PCDELTA (8 * 4)
#define D40_LLI_ALIGN 16 /* LLI alignment must be 16 bytes. */
+#define D40_LCPA_CHAN_SIZE 32
+#define D40_LCPA_CHAN_DST_DELTA 16
+
#define D40_TYPE_TO_GROUP(type) (type / 16)
#define D40_TYPE_TO_EVENT(type) (type % 16)
+#define D40_GROUP_SIZE 8
+#define D40_PHYS_TO_GROUP(phys) ((phys & (D40_GROUP_SIZE - 1)) / 2)
/* Most bits of the CFG register are the same in log as in phy mode */
#define D40_SREG_CFG_MST_POS 15
@@ -93,10 +96,13 @@
/* LCSP2 */
#define D40_MEM_LCSP2_ECNT_POS 16
+#define D40_MEM_LCSP2_DPTR_POS 0
#define D40_MEM_LCSP2_ECNT_MASK (0xFFFF << D40_MEM_LCSP2_ECNT_POS)
+#define D40_MEM_LCSP2_DPTR_MASK (0xFFFF << D40_MEM_LCSP2_DPTR_POS)
/* LCSP3 */
+#define D40_MEM_LCSP3_DPTR_POS 16
#define D40_MEM_LCSP3_DCFG_MST_POS 15
#define D40_MEM_LCSP3_DCFG_TIM_POS 14
#define D40_MEM_LCSP3_DCFG_EIM_POS 13
@@ -106,6 +112,7 @@
#define D40_MEM_LCSP3_DLOS_POS 1
#define D40_MEM_LCSP3_DTCP_POS 0
+#define D40_MEM_LCSP3_DPTR_MASK (0xFFFF << D40_MEM_LCSP3_DPTR_POS)
#define D40_MEM_LCSP3_DLOS_MASK (0x7F << D40_MEM_LCSP3_DLOS_POS)
#define D40_MEM_LCSP3_DTCP_MASK (0x1 << D40_MEM_LCSP3_DTCP_POS)
@@ -122,13 +129,32 @@
/* DMA Register Offsets */
#define D40_DREG_GCC 0x000
+#define D40_DREG_GCC_ENA 0x1
+/* This assumes that there are only 4 event groups */
+#define D40_DREG_GCC_ENABLE_ALL 0xff01
+#define D40_DREG_GCC_EVTGRP_POS 8
+#define D40_DREG_GCC_SRC 0
+#define D40_DREG_GCC_DST 1
+#define D40_DREG_GCC_EVTGRP_ENA(x, y) \
+ (1 << (D40_DREG_GCC_EVTGRP_POS + 2 * x + y))
+
#define D40_DREG_PRTYP 0x004
#define D40_DREG_PRSME 0x008
#define D40_DREG_PRSMO 0x00C
+#define D40_DREG_PRSM_MODE_MASK 0x3
+#define D40_DREG_PRSM_MODE_SECURE 0x1
+
#define D40_DREG_PRMSE 0x010
#define D40_DREG_PRMSO 0x014
#define D40_DREG_PRMOE 0x018
#define D40_DREG_PRMOO 0x01C
+#define D40_DREG_PRMO_PCHAN_BASIC 0x1
+#define D40_DREG_PRMO_PCHAN_MODULO 0x2
+#define D40_DREG_PRMO_PCHAN_DOUBLE_DST 0x3
+#define D40_DREG_PRMO_LCHAN_SRC_PHY_DST_LOG 0x1
+#define D40_DREG_PRMO_LCHAN_SRC_LOG_DST_PHY 0x2
+#define D40_DREG_PRMO_LCHAN_SRC_LOG_DST_LOG 0x3
+
#define D40_DREG_LCPA 0x020
#define D40_DREG_LCLA 0x024
#define D40_DREG_ACTIVE 0x050
@@ -155,6 +181,22 @@
#define D40_DREG_LCEIS1 0x0B4
#define D40_DREG_LCEIS2 0x0B8
#define D40_DREG_LCEIS3 0x0BC
+#define D40_DREG_PSEG1 0x110
+#define D40_DREG_PSEG2 0x114
+#define D40_DREG_PSEG3 0x118
+#define D40_DREG_PSEG4 0x11C
+#define D40_DREG_PCEG1 0x120
+#define D40_DREG_PCEG2 0x124
+#define D40_DREG_PCEG3 0x128
+#define D40_DREG_PCEG4 0x12C
+#define D40_DREG_RSEG1 0x130
+#define D40_DREG_RSEG2 0x134
+#define D40_DREG_RSEG3 0x138
+#define D40_DREG_RSEG4 0x13C
+#define D40_DREG_RCEG1 0x140
+#define D40_DREG_RCEG2 0x144
+#define D40_DREG_RCEG3 0x148
+#define D40_DREG_RCEG4 0x14C
#define D40_DREG_STFU 0xFC8
#define D40_DREG_ICFG 0xFCC
#define D40_DREG_PERIPHID0 0xFE0
@@ -196,8 +238,6 @@ struct d40_phy_lli {
*
* @src: Register settings for src channel.
* @dst: Register settings for dst channel.
- * @dst_addr: Physical destination address.
- * @src_addr: Physical source address.
*
* All DMA transfers have a source and a destination.
*/
@@ -205,8 +245,6 @@ struct d40_phy_lli {
struct d40_phy_lli_bidir {
struct d40_phy_lli *src;
struct d40_phy_lli *dst;
- dma_addr_t dst_addr;
- dma_addr_t src_addr;
};
@@ -268,29 +306,16 @@ struct d40_def_lcsp {
u32 lcsp1;
};
-/**
- * struct d40_lcla_elem - Info for one LCA element.
- *
- * @src_id: logical channel src id
- * @dst_id: logical channel dst id
- * @src: LCPA formated src parameters
- * @dst: LCPA formated dst parameters
- *
- */
-struct d40_lcla_elem {
- int src_id;
- int dst_id;
- struct d40_log_lli *src;
- struct d40_log_lli *dst;
-};
-
/* Physical channels */
void d40_phy_cfg(struct stedma40_chan_cfg *cfg,
- u32 *src_cfg, u32 *dst_cfg, bool is_log);
+ u32 *src_cfg,
+ u32 *dst_cfg,
+ bool is_log);
void d40_log_cfg(struct stedma40_chan_cfg *cfg,
- u32 *lcsp1, u32 *lcsp2);
+ u32 *lcsp1,
+ u32 *lcsp2);
int d40_phy_sg_to_lli(struct scatterlist *sg,
int sg_len,
@@ -300,7 +325,8 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
u32 reg_cfg,
u32 data_width,
int psize,
- bool term_int);
+ bool cyclic,
+ bool cyclic_int);
int d40_phy_fill_lli(struct d40_phy_lli *lli,
dma_addr_t data,
@@ -320,35 +346,35 @@ void d40_phy_lli_write(void __iomem *virtbase,
/* Logical channels */
void d40_log_fill_lli(struct d40_log_lli *lli,
- dma_addr_t data, u32 data_size,
- u32 lli_next_off, u32 reg_cfg,
+ dma_addr_t data,
+ u32 data_size,
+ u32 reg_cfg,
u32 data_width,
- bool term_int, bool addr_inc);
+ bool addr_inc);
-int d40_log_sg_to_dev(struct d40_lcla_elem *lcla,
- struct scatterlist *sg,
+int d40_log_sg_to_dev(struct scatterlist *sg,
int sg_len,
struct d40_log_lli_bidir *lli,
struct d40_def_lcsp *lcsp,
u32 src_data_width,
u32 dst_data_width,
enum dma_data_direction direction,
- bool term_int, dma_addr_t dev_addr, int max_len,
- int llis_per_log);
-
-void d40_log_lli_write(struct d40_log_lli_full *lcpa,
- struct d40_log_lli *lcla_src,
- struct d40_log_lli *lcla_dst,
- struct d40_log_lli *lli_dst,
- struct d40_log_lli *lli_src,
- int llis_per_log);
-
-int d40_log_sg_to_lli(int lcla_id,
- struct scatterlist *sg,
+ dma_addr_t dev_addr);
+
+int d40_log_sg_to_lli(struct scatterlist *sg,
int sg_len,
struct d40_log_lli *lli_sg,
u32 lcsp13, /* src or dst*/
- u32 data_width,
- bool term_int, int max_len, int llis_per_log);
+ u32 data_width);
+
+void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
+ struct d40_log_lli *lli_dst,
+ struct d40_log_lli *lli_src,
+ int next, bool interrupt);
+
+void d40_log_lli_lcla_write(struct d40_log_lli *lcla,
+ struct d40_log_lli *lli_dst,
+ struct d40_log_lli *lli_src,
+ int next, bool interrupt);
#endif /* STE_DMA40_LLI_H */
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 7face915b96..38d6910e1c6 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -195,6 +195,13 @@ config GPIO_PCF857X
This driver provides an in-kernel interface to those GPIOs using
platform-neutral GPIO calls.
+config GPIO_STMPE
+ bool "STMPE GPIOs"
+ depends on MFD_STMPE
+ help
+ This enables support for the GPIOs found on the STMPE I/O
+ Expanders.
+
config GPIO_TC35892
bool "TC35892 GPIOs"
depends on MFD_TC35892
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index e53dcff49b4..372c8e762d4 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o
obj-$(CONFIG_GPIO_PCA953X) += pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
obj-$(CONFIG_GPIO_PL061) += pl061.o
+obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o
obj-$(CONFIG_GPIO_TC35892) += tc35892-gpio.o
obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o
obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o
diff --git a/drivers/gpio/stmpe-gpio.c b/drivers/gpio/stmpe-gpio.c
new file mode 100644
index 00000000000..7c9e6a052c4
--- /dev/null
+++ b/drivers/gpio/stmpe-gpio.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/stmpe.h>
+
+/*
+ * These registers are modified under the irq bus lock and cached to avoid
+ * unnecessary writes in bus_sync_unlock.
+ */
+enum { REG_RE, REG_FE, REG_IE };
+
+#define CACHE_NR_REGS 3
+#define CACHE_NR_BANKS (STMPE_NR_GPIOS / 8)
+
+struct stmpe_gpio {
+ struct gpio_chip chip;
+ struct stmpe *stmpe;
+ struct device *dev;
+ struct mutex irq_lock;
+
+ int irq_base;
+ unsigned norequest_mask;
+
+ /* Caches of interrupt control registers for bus_lock */
+ u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
+ u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
+};
+
+static inline struct stmpe_gpio *to_stmpe_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct stmpe_gpio, chip);
+}
+
+static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+ struct stmpe *stmpe = stmpe_gpio->stmpe;
+ u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB] - (offset / 8);
+ u8 mask = 1 << (offset % 8);
+ int ret;
+
+ ret = stmpe_reg_read(stmpe, reg);
+ if (ret < 0)
+ return ret;
+
+ return ret & mask;
+}
+
+static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+ struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+ struct stmpe *stmpe = stmpe_gpio->stmpe;
+ int which = val ? STMPE_IDX_GPSR_LSB : STMPE_IDX_GPCR_LSB;
+ u8 reg = stmpe->regs[which] - (offset / 8);
+ u8 mask = 1 << (offset % 8);
+
+ stmpe_reg_write(stmpe, reg, mask);
+}
+
+static int stmpe_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int val)
+{
+ struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+ struct stmpe *stmpe = stmpe_gpio->stmpe;
+ u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
+ u8 mask = 1 << (offset % 8);
+
+ stmpe_gpio_set(chip, offset, val);
+
+ return stmpe_set_bits(stmpe, reg, mask, mask);
+}
+
+static int stmpe_gpio_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+ struct stmpe *stmpe = stmpe_gpio->stmpe;
+ u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
+ u8 mask = 1 << (offset % 8);
+
+ return stmpe_set_bits(stmpe, reg, mask, 0);
+}
+
+static int stmpe_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+
+ return stmpe_gpio->irq_base + offset;
+}
+
+static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+ struct stmpe *stmpe = stmpe_gpio->stmpe;
+
+ if (stmpe_gpio->norequest_mask & (1 << offset))
+ return -EINVAL;
+
+ return stmpe_set_altfunc(stmpe, 1 << offset, STMPE_BLOCK_GPIO);
+}
+
+static struct gpio_chip template_chip = {
+ .label = "stmpe",
+ .owner = THIS_MODULE,
+ .direction_input = stmpe_gpio_direction_input,
+ .get = stmpe_gpio_get,
+ .direction_output = stmpe_gpio_direction_output,
+ .set = stmpe_gpio_set,
+ .to_irq = stmpe_gpio_to_irq,
+ .request = stmpe_gpio_request,
+ .can_sleep = 1,
+};
+
+static int stmpe_gpio_irq_set_type(unsigned int irq, unsigned int type)
+{
+ struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
+ int offset = irq - stmpe_gpio->irq_base;
+ int regoffset = offset / 8;
+ int mask = 1 << (offset % 8);
+
+ if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
+ return -EINVAL;
+
+ if (type == IRQ_TYPE_EDGE_RISING)
+ stmpe_gpio->regs[REG_RE][regoffset] |= mask;
+ else
+ stmpe_gpio->regs[REG_RE][regoffset] &= ~mask;
+
+ if (type == IRQ_TYPE_EDGE_FALLING)
+ stmpe_gpio->regs[REG_FE][regoffset] |= mask;
+ else
+ stmpe_gpio->regs[REG_FE][regoffset] &= ~mask;
+
+ return 0;
+}
+
+static void stmpe_gpio_irq_lock(unsigned int irq)
+{
+ struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
+
+ mutex_lock(&stmpe_gpio->irq_lock);
+}
+
+static void stmpe_gpio_irq_sync_unlock(unsigned int irq)
+{
+ struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
+ struct stmpe *stmpe = stmpe_gpio->stmpe;
+ int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
+ static const u8 regmap[] = {
+ [REG_RE] = STMPE_IDX_GPRER_LSB,
+ [REG_FE] = STMPE_IDX_GPFER_LSB,
+ [REG_IE] = STMPE_IDX_IEGPIOR_LSB,
+ };
+ int i, j;
+
+ for (i = 0; i < CACHE_NR_REGS; i++) {
+ for (j = 0; j < num_banks; j++) {
+ u8 old = stmpe_gpio->oldregs[i][j];
+ u8 new = stmpe_gpio->regs[i][j];
+
+ if (new == old)
+ continue;
+
+ stmpe_gpio->oldregs[i][j] = new;
+ stmpe_reg_write(stmpe, stmpe->regs[regmap[i]] - j, new);
+ }
+ }
+
+ mutex_unlock(&stmpe_gpio->irq_lock);
+}
+
+static void stmpe_gpio_irq_mask(unsigned int irq)
+{
+ struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
+ int offset = irq - stmpe_gpio->irq_base;
+ int regoffset = offset / 8;
+ int mask = 1 << (offset % 8);
+
+ stmpe_gpio->regs[REG_IE][regoffset] &= ~mask;
+}
+
+static void stmpe_gpio_irq_unmask(unsigned int irq)
+{
+ struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
+ int offset = irq - stmpe_gpio->irq_base;
+ int regoffset = offset / 8;
+ int mask = 1 << (offset % 8);
+
+ stmpe_gpio->regs[REG_IE][regoffset] |= mask;
+}
+
+static struct irq_chip stmpe_gpio_irq_chip = {
+ .name = "stmpe-gpio",
+ .bus_lock = stmpe_gpio_irq_lock,
+ .bus_sync_unlock = stmpe_gpio_irq_sync_unlock,
+ .mask = stmpe_gpio_irq_mask,
+ .unmask = stmpe_gpio_irq_unmask,
+ .set_type = stmpe_gpio_irq_set_type,
+};
+
+static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
+{
+ struct stmpe_gpio *stmpe_gpio = dev;
+ struct stmpe *stmpe = stmpe_gpio->stmpe;
+ u8 statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_MSB];
+ int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
+ u8 status[num_banks];
+ int ret;
+ int i;
+
+ ret = stmpe_block_read(stmpe, statmsbreg, num_banks, status);
+ if (ret < 0)
+ return IRQ_NONE;
+
+ for (i = 0; i < num_banks; i++) {
+ int bank = num_banks - i - 1;
+ unsigned int enabled = stmpe_gpio->regs[REG_IE][bank];
+ unsigned int stat = status[i];
+
+ stat &= enabled;
+ if (!stat)
+ continue;
+
+ while (stat) {
+ int bit = __ffs(stat);
+ int line = bank * 8 + bit;
+
+ handle_nested_irq(stmpe_gpio->irq_base + line);
+ stat &= ~(1 << bit);
+ }
+
+ stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
+ stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB] + i,
+ status[i]);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio)
+{
+ int base = stmpe_gpio->irq_base;
+ int irq;
+
+ for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) {
+ set_irq_chip_data(irq, stmpe_gpio);
+ set_irq_chip_and_handler(irq, &stmpe_gpio_irq_chip,
+ handle_simple_irq);
+ set_irq_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ set_irq_noprobe(irq);
+#endif
+ }
+
+ return 0;
+}
+
+static void stmpe_gpio_irq_remove(struct stmpe_gpio *stmpe_gpio)
+{
+ int base = stmpe_gpio->irq_base;
+ int irq;
+
+ for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) {
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, 0);
+#endif
+ set_irq_chip_and_handler(irq, NULL, NULL);
+ set_irq_chip_data(irq, NULL);
+ }
+}
+
+static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
+{
+ struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
+ struct stmpe_gpio_platform_data *pdata;
+ struct stmpe_gpio *stmpe_gpio;
+ int ret;
+ int irq;
+
+ pdata = stmpe->pdata->gpio;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
+ if (!stmpe_gpio)
+ return -ENOMEM;
+
+ mutex_init(&stmpe_gpio->irq_lock);
+
+ stmpe_gpio->dev = &pdev->dev;
+ stmpe_gpio->stmpe = stmpe;
+ stmpe_gpio->norequest_mask = pdata ? pdata->norequest_mask : 0;
+
+ stmpe_gpio->chip = template_chip;
+ stmpe_gpio->chip.ngpio = stmpe->num_gpios;
+ stmpe_gpio->chip.dev = &pdev->dev;
+ stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
+
+ stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
+
+ ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
+ if (ret)
+ goto out_free;
+
+ ret = stmpe_gpio_irq_init(stmpe_gpio);
+ if (ret)
+ goto out_disable;
+
+ ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
+ "stmpe-gpio", stmpe_gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
+ goto out_removeirq;
+ }
+
+ ret = gpiochip_add(&stmpe_gpio->chip);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
+ goto out_freeirq;
+ }
+
+ if (pdata && pdata->setup)
+ pdata->setup(stmpe, stmpe_gpio->chip.base);
+
+ platform_set_drvdata(pdev, stmpe_gpio);
+
+ return 0;
+
+out_freeirq:
+ free_irq(irq, stmpe_gpio);
+out_removeirq:
+ stmpe_gpio_irq_remove(stmpe_gpio);
+out_disable:
+ stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
+out_free:
+ kfree(stmpe_gpio);
+ return ret;
+}
+
+static int __devexit stmpe_gpio_remove(struct platform_device *pdev)
+{
+ struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev);
+ struct stmpe *stmpe = stmpe_gpio->stmpe;
+ struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio;
+ int irq = platform_get_irq(pdev, 0);
+ int ret;
+
+ if (pdata && pdata->remove)
+ pdata->remove(stmpe, stmpe_gpio->chip.base);
+
+ ret = gpiochip_remove(&stmpe_gpio->chip);
+ if (ret < 0) {
+ dev_err(stmpe_gpio->dev,
+ "unable to remove gpiochip: %d\n", ret);
+ return ret;
+ }
+
+ stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
+
+ free_irq(irq, stmpe_gpio);
+ stmpe_gpio_irq_remove(stmpe_gpio);
+ platform_set_drvdata(pdev, NULL);
+ kfree(stmpe_gpio);
+
+ return 0;
+}
+
+static struct platform_driver stmpe_gpio_driver = {
+ .driver.name = "stmpe-gpio",
+ .driver.owner = THIS_MODULE,
+ .probe = stmpe_gpio_probe,
+ .remove = __devexit_p(stmpe_gpio_remove),
+};
+
+static int __init stmpe_gpio_init(void)
+{
+ return platform_driver_register(&stmpe_gpio_driver);
+}
+subsys_initcall(stmpe_gpio_init);
+
+static void __exit stmpe_gpio_exit(void)
+{
+ platform_driver_unregister(&stmpe_gpio_driver);
+}
+module_exit(stmpe_gpio_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMPExxxx GPIO driver");
+MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
diff --git a/drivers/gpio/tc35892-gpio.c b/drivers/gpio/tc35892-gpio.c
index 1be6288780d..7e10c935a04 100644
--- a/drivers/gpio/tc35892-gpio.c
+++ b/drivers/gpio/tc35892-gpio.c
@@ -322,6 +322,9 @@ static int __devinit tc35892_gpio_probe(struct platform_device *pdev)
goto out_freeirq;
}
+ if (pdata->setup)
+ pdata->setup(tc35892, tc35892_gpio->chip.base);
+
platform_set_drvdata(pdev, tc35892_gpio);
return 0;
@@ -338,9 +341,14 @@ out_free:
static int __devexit tc35892_gpio_remove(struct platform_device *pdev)
{
struct tc35892_gpio *tc35892_gpio = platform_get_drvdata(pdev);
+ struct tc35892 *tc35892 = tc35892_gpio->tc35892;
+ struct tc35892_gpio_platform_data *pdata = tc35892->pdata->gpio;
int irq = platform_get_irq(pdev, 0);
int ret;
+ if (pdata->remove)
+ pdata->remove(tc35892, tc35892_gpio->chip.base);
+
ret = gpiochip_remove(&tc35892_gpio->chip);
if (ret < 0) {
dev_err(tc35892_gpio->dev,
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index e19cf8eb6cc..1dac968e635 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -39,6 +39,19 @@ config HWMON_DEBUG_CHIP
comment "Native drivers"
+config SENSORS_AB8500
+ tristate "AB8500 thermal monitoring"
+ depends on AB8500_CORE
+ default n
+ help
+ If you say yes here you get support for the thermal sensor part
+ of the AB8500 chip. The driver includes thermal management for
+ AB8500 die and two GPADC channels. The GPADC channel are preferably
+ used to access sensors outside the AB8500 chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called ab8500-temp.
+
config SENSORS_ABITUGURU
tristate "Abit uGuru (rev 1 & 2)"
depends on X86 && EXPERIMENTAL
@@ -603,6 +616,20 @@ config SENSORS_LM93
This driver can also be built as a module. If so, the module
will be called lm93.
+config SENSORS_LSM303DLH
+ tristate "ST LSM303DLH 3-axis accelerometer and 3-axis magnetometer"
+ depends on I2C
+ default n
+ help
+ This driver provides support for the LSM303DLH chip which includes a
+ 3-axis accelerometer and a 3-axis magnetometer.
+
+ This driver can also be built as modules. If so, the module for
+ accelerometer will be called lsm303dlh_a and for magnetometer it will
+ be called lsm303dlh_m.
+
+ Say Y here if you have a device containing lsm303dlh chip.
+
config SENSORS_LTC4215
tristate "Linear Technology LTC4215"
depends on I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 2138ceb1a71..ce821c7b94f 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_SENSORS_W83793) += w83793.o
obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
+obj-$(CONFIG_SENSORS_AB8500) += ab8500.o
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
obj-$(CONFIG_SENSORS_AD7414) += ad7414.o
@@ -74,6 +75,7 @@ obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_LM92) += lm92.o
obj-$(CONFIG_SENSORS_LM93) += lm93.o
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
+obj-$(CONFIG_SENSORS_LSM303DLH) += lsm303dlh_a.o lsm303dlh_m.o
obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
diff --git a/drivers/hwmon/ab8500.c b/drivers/hwmon/ab8500.c
new file mode 100644
index 00000000000..9b093188406
--- /dev/null
+++ b/drivers/hwmon/ab8500.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Martin Persson <martin.persson@stericsson.com> for
+ * ST-Ericsson.
+ * License terms: GNU Gereral Public License (GPL) version 2
+ *
+ * Note:
+ *
+ * AB8500 does not provide auto ADC, so to monitor the required
+ * temperatures, a periodic work is used. It is more important
+ * to not wake up the CPU than to perform this job, hence the use
+ * of a deferred delay.
+ *
+ * A deferred delay for thermal monitor is considered safe because:
+ * If the chip gets too hot during a sleep state it's most likely
+ * due to external factors, such as the surrounding temperature.
+ * I.e. no SW decisions will make any difference.
+ *
+ * If/when the AB8500 thermal warning temperature is reached (threshold
+ * cannot be changed by SW), an interrupt is set and the driver
+ * notifies user space via a sysfs event. If a shut down is not
+ * triggered by user space within a certain time frame,
+ * pm_power off is called.
+ *
+ * If/when AB8500 thermal shutdown temperature is reached a hardware
+ * shutdown of the AB8500 will occur.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/hwmon.h>
+#include <linux/sysfs.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/mfd/ab8500/ab8500-gpadc.h>
+#include <linux/pm.h>
+
+/*
+ * If AB8500 warm interrupt is set, user space will be notified.
+ * If user space doesn't shut down the platform within this time
+ * frame, this driver will. Time unit is ms.
+ */
+#define DEFAULT_POWER_OFF_DELAY 10000
+
+#define NUM_SENSORS 4
+
+/* The driver monitors GPADC - ADC_AUX1 and ADC_AUX2 */
+#define NUM_MONITORED_SENSORS 2
+
+struct ab8500_temp {
+ struct platform_device *pdev;
+ struct device *hwmon_dev;
+ struct ab8500 *ab8500;
+ u8 gpadc_addr[NUM_SENSORS];
+ unsigned long min[NUM_SENSORS];
+ unsigned long max[NUM_SENSORS];
+ unsigned long max_hyst[NUM_SENSORS];
+ unsigned long crit[NUM_SENSORS];
+ unsigned long min_alarm[NUM_SENSORS];
+ unsigned long max_alarm[NUM_SENSORS];
+ unsigned long max_hyst_alarm[NUM_SENSORS];
+ unsigned long crit_alarm[NUM_SENSORS];
+ struct delayed_work work;
+ struct delayed_work power_off_work;
+ struct mutex lock;
+ /* Delay (ms) between temperature readings */
+ unsigned long gpadc_monitor_delay;
+ /* Delay (ms) before power off */
+ unsigned long power_off_delay;
+};
+
+/*
+ * Thresholds are considered inactive if set to 0.
+ * To avoid confusion for user space applications,
+ * the temp monitor delay is set to 0 if all thresholds
+ * are 0.
+ */
+static bool find_active_thresholds(struct ab8500_temp *data)
+{
+ int i;
+ for (i = 0; i < NUM_MONITORED_SENSORS; i++)
+ if (data->max[i] != 0 || data->max_hyst[i] != 0
+ || data->min[i] != 0)
+ return true;
+
+ dev_dbg(&data->pdev->dev, "No active thresholds,"
+ "cancel deferred job (if it exists)"
+ "and reset temp monitor delay\n");
+ mutex_lock(&data->lock);
+ data->gpadc_monitor_delay = 0;
+ cancel_delayed_work_sync(&data->work);
+ mutex_unlock(&data->lock);
+ return false;
+}
+
+static void thermal_power_off(struct work_struct *work)
+{
+ struct ab8500_temp *data = container_of(work, struct ab8500_temp,
+ power_off_work.work);
+
+ dev_warn(&data->pdev->dev, "Power off due to AB8500 thermal warning\n");
+ pm_power_off();
+}
+
+static void gpadc_monitor(struct work_struct *work)
+{
+ unsigned long delay_in_jiffies;
+ int val, i, ret;
+ /* Container for alarm node name */
+ char alarm_node[30];
+
+ bool updated_min_alarm = false;
+ bool updated_max_alarm = false;
+ bool updated_max_hyst_alarm = false;
+ struct ab8500_temp *data = container_of(work, struct ab8500_temp,
+ work.work);
+
+ for (i = 0; i < NUM_MONITORED_SENSORS; i++) {
+ /* Thresholds are considered inactive if set to 0 */
+ if (data->max[i] == 0 && data->max_hyst[i] == 0
+ && data->min[i] == 0)
+ continue;
+
+ val = ab8500_gpadc_convert(data->ab8500->gpadc,
+ data->gpadc_addr[i]);
+ if (val < 0) {
+ dev_err(&data->pdev->dev, "GPADC read failed\n");
+ continue;
+ }
+ /*
+ * 1350*x/1023 is the formula to convert from RAW GPADC data
+ * to voltage for AdcAux1 and AdcAux2 on the AB8500.
+ */
+ val = (1350 * val) / 1023;
+
+ mutex_lock(&data->lock);
+ if (data->min[i] != 0) {
+ if (val < data->min[i]) {
+ if (data->min_alarm[i] == 0) {
+ data->min_alarm[i] = 1;
+ updated_min_alarm = true;
+ }
+ } else {
+ if (data->min_alarm[i] == 1) {
+ data->min_alarm[i] = 0;
+ updated_min_alarm = true;
+ }
+ }
+
+ }
+ if (data->max[i] != 0) {
+ if (val > data->max[i]) {
+ if (data->max_alarm[i] == 0) {
+ data->max_alarm[i] = 1;
+ updated_max_alarm = true;
+ }
+ } else {
+ if (data->max_alarm[i] == 1) {
+ data->max_alarm[i] = 0;
+ updated_max_alarm = true;
+ }
+ }
+
+ }
+ if (data->max_hyst[i] != 0) {
+ if (val > data->max_hyst[i]) {
+ if (data->max_hyst_alarm[i] == 0) {
+ data->max_hyst_alarm[i] = 1;
+ updated_max_hyst_alarm = true;
+ }
+ } else {
+ if (data->max_hyst_alarm[i] == 1) {
+ data->max_hyst_alarm[i] = 0;
+ updated_max_hyst_alarm = true;
+ }
+ }
+ }
+ mutex_unlock(&data->lock);
+
+ /* hwmon attr index starts at 1, thus "i+1" below */
+ if (updated_min_alarm) {
+ ret = snprintf(alarm_node, 16, "temp%d_min_alarm",
+ (i + 1));
+ if (ret < 0) {
+ dev_err(&data->pdev->dev,
+ "Unable to update alarm node (%d)",
+ ret);
+ break;
+ }
+ sysfs_notify(&data->hwmon_dev->kobj, NULL, alarm_node);
+ }
+ if (updated_max_alarm) {
+ ret = snprintf(alarm_node, 16, "temp%d_max_alarm",
+ (i + 1));
+ if (ret < 0) {
+ dev_err(&data->pdev->dev,
+ "Unable to update alarm node (%d)",
+ ret);
+ break;
+ }
+ sysfs_notify(&data->hwmon_dev->kobj, NULL, alarm_node);
+ }
+ if (updated_max_hyst_alarm) {
+ ret = snprintf(alarm_node, 21, "temp%d_max_hyst_alarm",
+ (i + 1));
+ if (ret < 0) {
+ dev_err(&data->pdev->dev,
+ "Unable to update alarm node (%d)",
+ ret);
+ break;
+ }
+ sysfs_notify(&data->hwmon_dev->kobj, NULL, alarm_node);
+ }
+ }
+ delay_in_jiffies = msecs_to_jiffies(data->gpadc_monitor_delay);
+ schedule_delayed_work(&data->work, delay_in_jiffies);
+}
+
+static inline void gpadc_monitor_exit(struct platform_device *pdev)
+{
+ struct ab8500_temp *data = platform_get_drvdata(pdev);
+ cancel_delayed_work_sync(&data->work);
+}
+
+static ssize_t set_temp_monitor_delay(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int res;
+ unsigned long delay_in_jiffies, delay_in_s;
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+
+ if (!find_active_thresholds(data)) {
+ dev_dbg(dev, "No thresholds to monitor, disregarding delay\n");
+ return count;
+ }
+ res = strict_strtoul(buf, 10, &delay_in_s);
+ if (res < 0)
+ return res;
+
+ mutex_lock(&data->lock);
+ data->gpadc_monitor_delay = delay_in_s * 1000;
+ mutex_unlock(&data->lock);
+ delay_in_jiffies = msecs_to_jiffies(data->gpadc_monitor_delay);
+ schedule_delayed_work(&data->work, delay_in_jiffies);
+
+ return count;
+}
+
+static ssize_t set_temp_power_off_delay(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int res;
+ unsigned long delay_in_jiffies, delay_in_s;
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+
+ res = strict_strtoul(buf, 10, &delay_in_s);
+ if (res < 0)
+ return res;
+
+ mutex_lock(&data->lock);
+ data->power_off_delay = delay_in_s * 1000;
+ mutex_unlock(&data->lock);
+ delay_in_jiffies = msecs_to_jiffies(data->power_off_delay);
+
+ return count;
+}
+
+static ssize_t show_temp_monitor_delay(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ /* return time in s, not ms */
+ return sprintf(buf, "%lu\n", (data->gpadc_monitor_delay) / 1000);
+}
+
+static ssize_t show_temp_power_off_delay(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ /* return time in s, not ms */
+ return sprintf(buf, "%lu\n", (data->power_off_delay) / 1000);
+}
+
+/* HWMON sysfs interface */
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ /*
+ * To avoid confusion between sensor label and chip name, the function
+ * "show_label" is not used to return the chip name.
+ */
+ return sprintf(buf, "ab8500\n");
+}
+
+static ssize_t show_label(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ char *name;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int index = attr->index;
+
+ /*
+ * Make sure these labels correspond to the attribute indexes
+ * used when calling SENSOR_DEVICE_ATRR.
+ * Temperature sensors outside ab8500 (read via GPADC) are marked
+ * with prefix ext_
+ */
+ switch (index) {
+ case 1:
+ name = "ext_rtc_xtal";
+ break;
+ case 2:
+ name = "ext_db8500";
+ break;
+ case 3:
+ name = "battery";
+ break;
+ case 4:
+ name = "ab8500";
+ break;
+ default:
+ return -EINVAL;
+ }
+ return sprintf(buf, "%s\n", name);
+}
+
+static ssize_t show_input(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int val;
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ /* hwmon attr index starts at 1, thus "attr->index-1" below */
+ u8 gpadc_addr = data->gpadc_addr[attr->index - 1];
+
+ val = ab8500_gpadc_convert(data->ab8500->gpadc, gpadc_addr);
+ if (val < 0) {
+ dev_err(&data->pdev->dev, "GPADC read failed\n");
+ } else {
+ /*
+ * 1350*x/1023 is the formula to convert from RAW GPADC data
+ * to voltage for AdcAux1 and AdcAux2 on the AB8500.
+ */
+ val = (1350 * val) / 1023;
+ }
+ return sprintf(buf, "%d\n", val);
+}
+
+/* set functions (RW nodes) */
+static ssize_t set_min(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int res = strict_strtoul(buf, 10, &val);
+ if (res < 0)
+ return res;
+
+ mutex_lock(&data->lock);
+ /*
+ * Threshold is considered inactive if set to 0
+ * hwmon attr index starts at 1, thus "attr->index-1" below
+ */
+ if (val == 0)
+ data->min_alarm[attr->index - 1] = 0;
+
+ data->min[attr->index - 1] = val;
+ mutex_unlock(&data->lock);
+ if (val == 0)
+ (void) find_active_thresholds(data);
+
+ return count;
+}
+
+static ssize_t set_max(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int res = strict_strtoul(buf, 10, &val);
+ if (res < 0)
+ return res;
+
+ mutex_lock(&data->lock);
+ /*
+ * Threshold is considered inactive if set to 0
+ * hwmon attr index starts at 1, thus "attr->index-1" below
+ */
+ if (val == 0)
+ data->max_alarm[attr->index - 1] = 0;
+
+ data->max[attr->index - 1] = val;
+ mutex_unlock(&data->lock);
+ if (val == 0)
+ (void) find_active_thresholds(data);
+
+ return count;
+}
+
+static ssize_t set_max_hyst(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int res = strict_strtoul(buf, 10, &val);
+ if (res < 0)
+ return res;
+
+ mutex_lock(&data->lock);
+ /*
+ * Threshold is considered inactive if set to 0
+ * hwmon attr index starts at 1, thus "attr->index-1" below
+ */
+ if (val == 0)
+ data->max_hyst_alarm[attr->index - 1] = 0;
+
+ data->max_hyst[attr->index - 1] = val;
+ mutex_unlock(&data->lock);
+ if (val == 0)
+ (void) find_active_thresholds(data);
+
+ return count;
+}
+
+/*
+ * show functions (RO nodes)
+ * Notice that min/max/max_hyst refer to millivolts and not millidegrees
+ */
+static ssize_t show_min(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ /* hwmon attr index starts at 1, thus "attr->index-1" below */
+ return sprintf(buf, "%ld\n", data->min[attr->index - 1]);
+}
+
+static ssize_t show_max(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ /* hwmon attr index starts at 1, thus "attr->index-1" below */
+ return sprintf(buf, "%ld\n", data->max[attr->index - 1]);
+}
+
+static ssize_t show_max_hyst(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ /* hwmon attr index starts at 1, thus "attr->index-1" below */
+ return sprintf(buf, "%ld\n", data->max_hyst[attr->index - 1]);
+}
+
+/* Alarms */
+static ssize_t show_min_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ /* hwmon attr index starts at 1, thus "attr->index-1" below */
+ return sprintf(buf, "%ld\n", data->min_alarm[attr->index - 1]);
+}
+
+static ssize_t show_max_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ /* hwmon attr index starts at 1, thus "attr->index-1" below */
+ return sprintf(buf, "%ld\n", data->max_alarm[attr->index - 1]);
+}
+
+static ssize_t show_max_hyst_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ /* hwmon attr index starts at 1, thus "attr->index-1" below */
+ return sprintf(buf, "%ld\n", data->max_hyst_alarm[attr->index - 1]);
+}
+
+static ssize_t show_crit_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct ab8500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ /* hwmon attr index starts at 1, thus "attr->index-1" below */
+ return sprintf(buf, "%ld\n", data->crit_alarm[attr->index - 1]);
+}
+
+/*These node are not included in the kernel hwmon sysfs interface */
+static SENSOR_DEVICE_ATTR(temp_monitor_delay, S_IRUGO | S_IWUSR,
+ show_temp_monitor_delay, set_temp_monitor_delay, 0);
+static SENSOR_DEVICE_ATTR(temp_power_off_delay, S_IRUGO | S_IWUSR,
+ show_temp_power_off_delay,
+ set_temp_power_off_delay, 0);
+
+/* Chip name, required by hwmon*/
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+/* GPADC - ADC_AUX1 */
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_min, set_min, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_max, set_max, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+ show_max_hyst, set_max_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_min_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_max_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst_alarm, S_IRUGO,
+ show_max_hyst_alarm, NULL, 1);
+
+/* GPADC - ADC_AUX2 */
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min, set_min, 2);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max, set_max, 2);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IWUSR | S_IRUGO,
+ show_max_hyst, set_max_hyst, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_min_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_max_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst_alarm, S_IRUGO,
+ show_max_hyst_alarm, NULL, 2);
+
+/* GPADC - BTEMP_BALL */
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, show_label, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_input, NULL, 3);
+
+/* AB8500 */
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, show_label, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO,
+ show_crit_alarm, NULL, 4);
+
+static struct attribute *ab8500_temp_attributes[] = {
+ &sensor_dev_attr_temp_power_off_delay.dev_attr.attr,
+ &sensor_dev_attr_temp_monitor_delay.dev_attr.attr,
+ &sensor_dev_attr_name.dev_attr.attr,
+ /* GPADC - ADC_AUX1 */
+ &sensor_dev_attr_temp1_label.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst_alarm.dev_attr.attr,
+ /* GPADC - ADC_AUX2 */
+ &sensor_dev_attr_temp2_label.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst_alarm.dev_attr.attr,
+ /* GPADC - BTEMP_BALL */
+ &sensor_dev_attr_temp3_label.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ /* AB8500 */
+ &sensor_dev_attr_temp4_label.dev_attr.attr,
+ &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group ab8500_temp_group = {
+ .attrs = ab8500_temp_attributes,
+};
+
+static irqreturn_t ab8500_temp_irq_handler(int irq, void *irq_data)
+{
+ unsigned long delay_in_jiffies;
+ struct platform_device *pdev = irq_data;
+ struct ab8500_temp *data = platform_get_drvdata(pdev);
+
+ /*
+ * Make sure the magic numbers below corresponds to the node
+ * used for AB8500 thermal warning from HW.
+ */
+ mutex_lock(&data->lock);
+ data->crit_alarm[3] = 1;
+ mutex_unlock(&data->lock);
+ sysfs_notify(&pdev->dev.kobj, NULL, "temp4_crit_alarm");
+ dev_info(&pdev->dev, "AB8500 thermal warning, power off in %lu s\n",
+ data->power_off_delay);
+ delay_in_jiffies = msecs_to_jiffies(data->power_off_delay);
+ schedule_delayed_work(&data->power_off_work, delay_in_jiffies);
+ return IRQ_HANDLED;
+}
+
+static int setup_irqs(struct platform_device *pdev)
+{
+ int ret;
+ int irq = platform_get_irq_byname(pdev, "AB8500_TEMP_WARM");
+
+ if (irq < 0)
+ dev_err(&pdev->dev, "Get irq by name failed\n");
+
+ ret = request_threaded_irq(irq, NULL, ab8500_temp_irq_handler,
+ 0, "ab8500-temp", pdev);
+ if (ret < 0)
+ dev_err(&pdev->dev, "Request threaded irq failed (%d)\n", ret);
+
+ return ret;
+}
+
+static int __devinit ab8500_temp_probe(struct platform_device *pdev)
+{
+ struct ab8500_temp *data;
+ int err;
+
+ data = kzalloc(sizeof(struct ab8500_temp), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ err = setup_irqs(pdev);
+ if (err < 0)
+ goto exit;
+
+ if (pdev->dev.parent != NULL)
+ data->ab8500 = dev_get_drvdata(pdev->dev.parent);
+ else {
+ dev_err(&pdev->dev, "GPADC not present in AB8500 device\n");
+ goto exit;
+ }
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
+ goto exit;
+ }
+
+ INIT_DELAYED_WORK_DEFERRABLE(&data->work, gpadc_monitor);
+ INIT_DELAYED_WORK(&data->power_off_work, thermal_power_off);
+
+ /*
+ * Setup HW defined data.
+ *
+ * Reference hardware (HREF):
+ *
+ * GPADC - ADC_AUX1, connected to NTC R2148 next to RTC_XTAL on HREF
+ * GPADC - ADC_AUX2, connected to NTC R2150 near DB8500 on HREF
+ * Hence, temp#_min/max/max_hyst refer to millivolts and not
+ * millidegrees
+ *
+ * HREF HW does not support reading AB8500 temperature. BUT an
+ * AB8500 IRQ will be launched if die crit temp limit is reached.
+ *
+ * Also:
+ * Battery temperature thresholds will not be exposed via hwmon.
+ *
+ * Make sure indexes correspond to the attribute indexes
+ * used when calling SENSOR_DEVICE_ATRR
+ */
+ data->gpadc_addr[0] = ADC_AUX1;
+ data->gpadc_addr[1] = ADC_AUX2;
+ data->gpadc_addr[2] = BTEMP_BALL;
+
+ mutex_init(&data->lock);
+ data->pdev = pdev;
+ data->power_off_delay = DEFAULT_POWER_OFF_DELAY;
+
+ platform_set_drvdata(pdev, data);
+
+ err = sysfs_create_group(&pdev->dev.kobj, &ab8500_temp_group);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Create sysfs group failed (%d)\n", err);
+ goto exit_platform_data;
+ }
+
+ return 0;
+
+exit_platform_data:
+ platform_set_drvdata(pdev, NULL);
+exit:
+ kfree(data);
+ return err;
+}
+
+static int __devexit ab8500_temp_remove(struct platform_device *pdev)
+{
+ struct ab8500_temp *data = platform_get_drvdata(pdev);
+
+ gpadc_monitor_exit(pdev);
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &ab8500_temp_group);
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+ return 0;
+}
+
+/* No action required in suspend/resume, thus the lack of functions */
+static struct platform_driver ab8500_temp_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ab8500-temp",
+ },
+ .probe = ab8500_temp_probe,
+ .remove = __devexit_p(ab8500_temp_remove),
+};
+
+static int __init ab8500_temp_init(void)
+{
+ return platform_driver_register(&ab8500_temp_driver);
+}
+
+static void __exit ab8500_temp_exit(void)
+{
+ platform_driver_unregister(&ab8500_temp_driver);
+}
+
+MODULE_AUTHOR("Martin Persson <martin.persson@stericsson.com>");
+MODULE_DESCRIPTION("AB8500 temperature driver");
+MODULE_LICENSE("GPL");
+
+module_init(ab8500_temp_init)
+module_exit(ab8500_temp_exit)
diff --git a/drivers/hwmon/lsm303dlh_a.c b/drivers/hwmon/lsm303dlh_a.c
new file mode 100644
index 00000000000..99d6655b36d
--- /dev/null
+++ b/drivers/hwmon/lsm303dlh_a.c
@@ -0,0 +1,780 @@
+/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
+*
+* File Name : lsm303dlh_a_char.c
+* Authors : MH - C&I BU - Application Team
+* : Carmine Iascone (carmine.iascone@st.com)
+* : Matteo Dameno (matteo.dameno@st.com)
+* Version : V 0.3
+* Date : 24/02/2010
+* Description : LSM303DLH 6D module sensor API
+*
+********************************************************************************
+*
+* Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+* Copyright 2010 (c) ST-Ericsson AB
+*
+********************************************************************************
+*
+* 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.
+*
+* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
+* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE
+* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*
+* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
+*
+******************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/uaccess.h>
+#include <linux/lsm303dlh.h>
+#include <linux/miscdevice.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+
+/* Temp defines till GPIO extender driver is fixed. */
+/* #define A_USE_INT */
+/* #define A_USE_GPIO_EXTENDER_INT */
+
+/* lsm303dlh accelerometer registers */
+#define WHO_AM_I 0x0F
+
+/* ctrl 1: pm2 pm1 pm0 dr1 dr0 zenable yenable zenable */
+#define CTRL_REG1 0x20 /* power control reg */
+#define CTRL_REG2 0x21 /* power control reg */
+#define CTRL_REG3 0x22 /* power control reg */
+#define CTRL_REG4 0x23 /* interrupt control reg */
+#define CTRL_REG5 0x24 /* interrupt control reg */
+#define AXISDATA_REG 0x28
+#define INT1_SRC_A_REG 0x31 /* interrupt 1 source reg */
+#define INT2_SRC_A_REG 0x35 /* interrupt 2 source reg */
+#define MULTIPLE_I2C_TR 0x80 /* Multiple byte transfer enable */
+
+/* Sensitivity adjustment */
+#define SHIFT_ADJ_2G 4 /* 1/16*/
+#define SHIFT_ADJ_4G 3 /* 2/16*/
+#define SHIFT_ADJ_8G 2 /* ~3.9/16*/
+
+/* Control register 1 */
+#define LSM303DLH_A_CR1_PM_BIT 5
+#define LSM303DLH_A_CR1_PM_MASK (0x7 << LSM303DLH_A_CR1_PM_BIT)
+#define LSM303DLH_A_CR1_DR_BIT 3
+#define LSM303DLH_A_CR1_DR_MASK (0x3 << LSM303DLH_A_CR1_DR_BIT)
+#define LSM303DLH_A_CR1_EN_BIT 0
+#define LSM303DLH_A_CR1_EN_MASK (0x7 << LSM303DLH_A_CR1_EN_BIT)
+
+/* Control register 2 */
+#define LSM303DLH_A_CR4_ST_BIT 1
+#define LSM303DLH_A_CR4_ST_MASK (0x1 << LSM303DLH_A_CR4_ST_BIT)
+#define LSM303DLH_A_CR4_STS_BIT 3
+#define LSM303DLH_A_CR4_STS_MASK (0x1 << LSM303DLH_A_CR4_STS_BIT)
+#define LSM303DLH_A_CR4_FS_BIT 4
+#define LSM303DLH_A_CR4_FS_MASK (0x3 << LSM303DLH_A_CR4_FS_BIT)
+#define LSM303DLH_A_CR4_BLE_BIT 6
+#define LSM303DLH_A_CR4_BLE_MASK (0x3 << LSM303DLH_A_CR4_BLE_BIT)
+
+/* Control register 3 */
+#define LSM303DLH_A_CR3_I1_BIT 0
+#define LSM303DLH_A_CR3_I1_MASK (0x3 << LSM303DLH_A_CR3_I1_BIT)
+#define LSM303DLH_A_CR3_LIR1_BIT 2
+#define LSM303DLH_A_CR3_LIR1_MASK (0x1 << LSM303DLH_A_CR3_LIR1_BIT)
+#define LSM303DLH_A_CR3_I2_BIT 3
+#define LSM303DLH_A_CR3_I2_MASK (0x3 << LSM303DLH_A_CR3_I2_BIT)
+#define LSM303DLH_A_CR3_LIR2_BIT 5
+#define LSM303DLH_A_CR3_LIR2_MASK (0x1 << LSM303DLH_A_CR3_LIR2_BIT)
+#define LSM303DLH_A_CR3_PPOD_BIT 6
+#define LSM303DLH_A_CR3_PPOD_MASK (0x1 << LSM303DLH_A_CR3_PPOD_BIT)
+#define LSM303DLH_A_CR3_IHL_BIT 7
+#define LSM303DLH_A_CR3_IHL_MASK (0x1 << LSM303DLH_A_CR3_IHL_BIT)
+
+#define LSM303DLH_A_CR3_I_SELF 0x0
+#define LSM303DLH_A_CR3_I_OR 0x1
+#define LSM303DLH_A_CR3_I_DATA 0x2
+#define LSM303DLH_A_CR3_I_BOOT 0x3
+
+#define LSM303DLH_A_CR3_LIR_LATCH 0x1
+
+/*
+ * lsm303dlh_a acceleration data
+ * brief Structure containing acceleration values for x,y and z-axis in
+ * signed short
+ */
+
+struct lsm303dlh_a_t {
+ short x; /* < x-axis acceleration data. Range -2048 to 2047. */
+ short y; /* < y-axis acceleration data. Range -2048 to 2047. */
+ short z; /* < z-axis acceleration data. Range -2048 to 2047. */
+};
+
+struct lsm303dlh_a_data {
+ struct i2c_client *client;
+ struct lsm303dlh_platform_data pdata;
+ struct input_dev *input_dev;
+ struct work_struct work;
+ u8 shift_adj;
+ u8 ctrl_1;
+ u8 mode;
+ u8 rate;
+ short ms;
+ atomic_t user_count;
+#ifndef A_USE_INT
+ struct task_struct *kthread;
+#endif
+};
+
+static struct lsm303dlh_a_data *file_private;
+
+/* set lsm303dlh accelerometer bandwidth */
+int lsm303dlh_a_set_rate(struct lsm303dlh_a_data *ldata, unsigned char bw)
+{
+ unsigned char data;
+
+ data = i2c_smbus_read_byte_data(ldata->client, CTRL_REG1);
+ data &= ~LSM303DLH_A_CR1_DR_MASK;
+ ldata->rate = bw;
+ data |= ((bw << LSM303DLH_A_CR1_DR_BIT) & LSM303DLH_A_CR1_DR_MASK);
+
+ return i2c_smbus_write_byte_data(ldata->client, CTRL_REG1, data);
+}
+
+/* read selected bandwidth from lsm303dlh_acc */
+int lsm303dlh_a_get_bandwidth(struct lsm303dlh_a_data *ldata, unsigned char *bw)
+{
+ unsigned char data;
+
+ data = i2c_smbus_read_byte_data(ldata->client, CTRL_REG1);
+ data &= LSM303DLH_A_CR1_DR_MASK;
+ data >>= LSM303DLH_A_CR1_DR_BIT;
+
+ return data;
+}
+
+#ifndef A_USE_INT
+static int lsm303dlh_a_kthread(void *data);
+#endif
+
+
+int lsm303dlh_a_set_mode(struct lsm303dlh_a_data *ldata, unsigned char mode)
+{
+ unsigned char data;
+ int res;
+
+ data = i2c_smbus_read_byte_data(ldata->client, CTRL_REG1);
+
+ data &= ~LSM303DLH_A_CR1_PM_MASK;
+ ldata->mode = mode;
+ data |= ((mode << LSM303DLH_A_CR1_PM_BIT) & LSM303DLH_A_CR1_PM_MASK);
+
+ res = i2c_smbus_write_byte_data(ldata->client, CTRL_REG1, data);
+ if (res < 0)
+ return res;
+
+#ifndef A_USE_INT
+ if (mode) {
+ if (!ldata->kthread) {
+ ldata->kthread = kthread_run(lsm303dlh_a_kthread, ldata,
+ "klsm303dlh_a");
+ if (IS_ERR(ldata->kthread))
+ return PTR_ERR(ldata->kthread);
+ }
+ } else {
+ if (ldata->kthread) {
+ kthread_stop(ldata->kthread);
+ ldata->kthread = NULL;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+int lsm303dlh_a_set_range(struct lsm303dlh_a_data *ldata, unsigned char range)
+{
+ switch (range) {
+ case LSM303DLH_A_RANGE_2G:
+ ldata->shift_adj = SHIFT_ADJ_2G;
+ break;
+ case LSM303DLH_A_RANGE_4G:
+ ldata->shift_adj = SHIFT_ADJ_4G;
+ break;
+ case LSM303DLH_A_RANGE_8G:
+ ldata->shift_adj = SHIFT_ADJ_8G;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ range <<= LSM303DLH_A_CR4_FS_BIT;
+
+ return i2c_smbus_write_byte_data(ldata->client, CTRL_REG4, range);
+}
+
+/* i2c read routine for lsm303dlh accelerometer */
+static char lsm303dlh_a_i2c_read(struct lsm303dlh_a_data *ldata,
+ unsigned char reg_addr,
+ unsigned char *data,
+ unsigned char len)
+{
+ int res;
+
+ res = i2c_smbus_read_i2c_block_data(ldata->client,
+ reg_addr | MULTIPLE_I2C_TR, len, data);
+ if(res < 0) {
+ dev_err(&ldata->client->dev, "failed to read %#x: %d\n",
+ reg_addr, res);
+ return res;
+ }
+
+ return len;
+}
+
+/* X,Y and Z-axis acceleration data readout */
+int lsm303dlh_a_read_xyz(struct lsm303dlh_a_data *ldata,
+ struct lsm303dlh_a_t *data)
+{
+ int res;
+ unsigned char acc_data[6];
+ int hw_d[3] = { 0 };
+
+ /* check lsm303dlh_a_client */
+ if (ldata->client == NULL) {
+ printk(KERN_ERR "I2C driver not install\n");
+ return -EFAULT;
+ }
+
+ res = lsm303dlh_a_i2c_read(ldata, AXISDATA_REG, &acc_data[0], 6);
+
+ if (res >= 0) {
+ hw_d[0] = (short) (((acc_data[1]) << 8) | acc_data[0]);
+ hw_d[1] = (short) (((acc_data[3]) << 8) | acc_data[2]);
+ hw_d[2] = (short) (((acc_data[5]) << 8) | acc_data[4]);
+
+ hw_d[0] >>= ldata->shift_adj;
+ hw_d[1] >>= ldata->shift_adj;
+ hw_d[2] >>= ldata->shift_adj;
+
+ data->x = ldata->pdata.negative_x ?
+ -hw_d[ldata->pdata.axis_map_x] :
+ hw_d[ldata->pdata.axis_map_x];
+ data->y = ldata->pdata.negative_y ?
+ -hw_d[ldata->pdata.axis_map_y] :
+ hw_d[ldata->pdata.axis_map_y];
+ data->z = ldata->pdata.negative_z ?
+ -hw_d[ldata->pdata.axis_map_z] :
+ hw_d[ldata->pdata.axis_map_z];
+ }
+
+ return res;
+}
+
+/* open command for lsm303dlh_a device file */
+static int lsm303dlh_a_open(struct inode *inode, struct file *filp)
+{
+ struct lsm303dlh_a_data *ldata = file_private;
+
+ filp->private_data = ldata;
+
+ if (ldata->client == NULL) {
+ printk(KERN_ERR"I2C driver not install\n");
+ return -EINVAL;
+ }
+
+ atomic_inc(&ldata->user_count);
+
+ dev_dbg(&ldata->client->dev, "lsm303dlh_a has been opened\n");
+
+ return 0;
+}
+
+/* release command for lsm303dlh_a device file */
+static int lsm303dlh_a_close(struct inode *inode, struct file *filp)
+{
+ struct lsm303dlh_a_data *ldata = filp->private_data;
+ int res;
+
+ res = atomic_dec_and_test(&ldata->user_count);
+
+#ifndef A_USE_INT
+ if ((res) && (ldata->kthread)) {
+ kthread_stop(ldata->kthread);
+ ldata->kthread = NULL;
+ }
+#endif
+
+ dev_dbg(&ldata->client->dev, "lsm303dlh_a has been closed\n");
+
+ return 0;
+}
+
+/* ioctl command for lsm303dlh_a device file */
+static int lsm303dlh_a_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ unsigned char buf[1];
+ struct lsm303dlh_a_data *ldata = filp->private_data;
+
+ /* check lsm303dlh_a_client */
+ if (ldata->client == NULL) {
+ printk(KERN_ERR "I2C driver not install\n");
+ return -EFAULT;
+ }
+
+ /* cmd mapping */
+
+ switch (cmd) {
+
+ case LSM303DLH_A_SET_RANGE:
+ if (copy_from_user(buf, (unsigned char *)arg, 1) != 0) {
+ dev_err(&ldata->client->dev, "copy_from_user error\n");
+ return -EFAULT;
+ }
+ err = lsm303dlh_a_set_range(ldata, buf[0]);
+ return err;
+
+ case LSM303DLH_A_SET_MODE:
+ if (copy_from_user(buf, (unsigned char *)arg, 1) != 0) {
+ dev_err(&ldata->client->dev, "copy_from_user error\n");
+ return -EFAULT;
+ }
+ err = lsm303dlh_a_set_mode(ldata, buf[0]);
+
+ return err;
+
+ case LSM303DLH_A_SET_RATE:
+ if (copy_from_user(buf, (unsigned char *)arg, 1) != 0) {
+ dev_err(&ldata->client->dev, "copy_from_user error\n");
+ return -EFAULT;
+ }
+ err = lsm303dlh_a_set_rate(ldata, buf[0]);
+ return err;
+
+ case LSM303DLH_A_GET_MODE:
+ if (copy_to_user((unsigned char *)arg,
+ &ldata->mode, sizeof(ldata->mode)) != 0) {
+ dev_err(&ldata->client->dev, "copy_to_user error\n");
+ return -EFAULT;
+ }
+ return 0;
+
+ default:
+ return 0;
+ }
+}
+
+#ifndef A_USE_INT
+static int lsm303dlh_a_calculate_ms(struct lsm303dlh_a_data *ldata)
+{
+ int ms;
+ if (ldata->mode == LSM303DLH_A_MODE_NORMAL) {
+ if (ldata->rate == LSM303DLH_A_RATE_50)
+ ms = 20;
+ else if (ldata->rate == LSM303DLH_A_RATE_100)
+ ms = 10;
+ else if (ldata->rate == LSM303DLH_A_RATE_400)
+ ms = 2;
+ else if (ldata->rate == LSM303DLH_A_RATE_1000)
+ ms = 1;
+ else
+ ms = 1000;
+ } else {
+ if (ldata->mode == LSM303DLH_A_MODE_LP_HALF)
+ ms = 2000;
+ else if (ldata->mode == LSM303DLH_A_MODE_LP_1)
+ ms = 1000;
+ else if (ldata->mode == LSM303DLH_A_MODE_LP_2)
+ ms = 500;
+ else if (ldata->mode == LSM303DLH_A_MODE_LP_5)
+ ms = 200;
+ else if (ldata->mode == LSM303DLH_A_MODE_LP_10)
+ ms = 100;
+ else
+ ms = 1000;
+ }
+ return ms;
+}
+#endif /* A_USE_INT */
+
+#ifdef A_USE_INT
+static void lsm303dlh_a_work_func(struct work_struct *work)
+#else
+static void lsm303dlh_a_work_func(struct lsm303dlh_a_data *ldata)
+#endif /* A_USE_INT */
+{
+ int res;
+ struct lsm303dlh_a_t abuf;
+
+#ifdef A_USE_INT
+ struct lsm303dlh_a_data *ldata =
+ container_of(work, struct lsm303dlh_a_data, work);
+#endif
+
+ /* Clear interrupt. */
+ res = i2c_smbus_read_byte_data(ldata->client, INT1_SRC_A_REG);
+
+ res = lsm303dlh_a_read_xyz(ldata, &abuf);
+
+ if (res >= 0) {
+ input_report_abs(ldata->input_dev, ABS_X, abuf.x);
+ input_report_abs(ldata->input_dev, ABS_Y, abuf.y);
+ input_report_abs(ldata->input_dev, ABS_Z, abuf.z);
+
+ input_sync(ldata->input_dev);
+ }
+
+#ifdef A_USE_INT
+ enable_irq(ldata->client->irq);
+#endif
+}
+
+#ifndef A_USE_INT
+/*
+ * Kthread polling function
+ * @data: unused - here to conform to threadfn prototype
+ */
+static int lsm303dlh_a_kthread(void *data)
+{
+ struct lsm303dlh_a_data *ldata = data;
+
+ while (!kthread_should_stop()) {
+ lsm303dlh_a_work_func(ldata);
+ try_to_freeze();
+ msleep_interruptible(lsm303dlh_a_calculate_ms(ldata));
+ }
+
+ return 0;
+}
+#endif /* A_USE_INT */
+
+#ifdef A_USE_INT
+#ifdef A_USE_GPIO_EXTENDER_INT
+void lsm303dlh_a_interrupt(void *dev_id)
+#else
+static irqreturn_t lsm303dlh_a_interrupt(int irq, void *dev_id)
+#endif /* A_USE_GPIO_EXTENDER_INT */
+{
+ struct lsm303dlh_a_data *ldata = dev_id;
+#ifndef A_USE_GPIO_EXTENDER_INT
+ disable_irq(ldata->client->irq);
+#endif /* A_USE_GPIO_EXTENDER_INT */
+ schedule_work(&ldata->work);
+
+#ifndef A_USE_GPIO_EXTENDER_INT
+ return IRQ_HANDLED;
+#endif /* A_USE_GPIO_EXTENDER_INT */
+}
+#endif /* A_USE_GPIO_EXTENDER_INT */
+
+static const struct file_operations lsm303dlh_a_fops = {
+ .owner = THIS_MODULE,
+ .open = lsm303dlh_a_open,
+ .release = lsm303dlh_a_close,
+ .ioctl = lsm303dlh_a_ioctl,
+};
+
+static struct miscdevice lsm303dlh_a_misc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "lsm303dlh_a",
+ .fops = &lsm303dlh_a_fops,
+};
+
+static int lsm303dlh_a_validate_pdata(struct lsm303dlh_a_data *adata)
+{
+ if ((adata->pdata.axis_map_x > 2) ||
+ (adata->pdata.axis_map_y > 2) ||
+ (adata->pdata.axis_map_z > 2) ||
+ (adata->pdata.axis_map_x == adata->pdata.axis_map_y) ||
+ (adata->pdata.axis_map_x == adata->pdata.axis_map_z) ||
+ (adata->pdata.axis_map_y == adata->pdata.axis_map_z)) {
+ dev_err(&adata->client->dev,
+ "invalid axis_map value x:%u y:%u z%u\n",
+ adata->pdata.axis_map_x, adata->pdata.axis_map_y,
+ adata->pdata.axis_map_z);
+ return -EINVAL;
+ }
+
+ /* Only allow 0 and 1 */
+ if ((adata->pdata.negative_x > 1) ||
+ (adata->pdata.negative_y > 1) ||
+ (adata->pdata.negative_z > 1)) {
+ dev_err(&adata->client->dev,
+ "invalid negate value x:%u y:%u z:%u\n",
+ adata->pdata.negative_x, adata->pdata.negative_y,
+ adata->pdata.negative_z);
+ return -EINVAL;
+ }
+
+#ifdef A_USE_GPIO_EXTENDER_INT
+ if ((!adata->pdata.free_irq) || (!adata->pdata.register_irq))
+ return -EINVAL;
+#endif /* A_USE_GPIO_EXTENDER_INT */
+
+ return 0;
+}
+
+static int lsm303dlh_a_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ int err = 0;
+ int tempvalue;
+ struct lsm303dlh_a_data *ldata;
+
+ if (client->dev.platform_data == NULL) {
+ dev_err(&client->dev, "platform data is NULL. exiting.\n");
+ err = -ENODEV;
+ goto exit;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /*
+ * OK. For now, we presume we have a valid client. We now create the
+ * client structure, even though we cannot fill it completely yet.
+ */
+ ldata = kzalloc(sizeof(*ldata), GFP_KERNEL);
+ if (ldata == NULL) {
+ dev_err(&client->dev,
+ "failed to allocate memory for module data\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, ldata);
+ ldata->client = client;
+
+ file_private = ldata;
+
+ memcpy(&ldata->pdata, client->dev.platform_data, sizeof(ldata->pdata));
+
+ err = lsm303dlh_a_validate_pdata(ldata);
+ if (err < 0) {
+ dev_err(&client->dev, "failed to validate platform data\n");
+ goto exit_kfree;
+ }
+
+ err = i2c_smbus_read_byte(client);
+ if (err < 0) {
+ dev_err(&client->dev, "i2c_smbus_read_byte error!!\n");
+ err = -ENOMEM;
+ goto exit_kfree;
+ } else {
+ dev_info(&client->dev, "lsm303dlh_a Device detected!\n");
+ }
+
+ /* read chip id */
+ tempvalue = i2c_smbus_read_byte_data(client, WHO_AM_I);
+ if ((tempvalue & 0x00FF) == 0x0032) {
+ dev_err(&client->dev, "i2c driver registered!\n");
+ } else {
+ err = -EINVAL;
+ ldata->client = NULL;
+ goto exit_kfree;
+ }
+
+#ifdef A_USE_INT
+ INIT_WORK(&ldata->work, lsm303dlh_a_work_func);
+#ifdef A_USE_GPIO_EXTENDER_INT
+ if (ldata->pdata.register_irq(&client->dev, client,
+ lsm303dlh_a_interrupt)) {
+#else
+ if (request_irq(client->irq, lsm303dlh_a_interrupt,
+ IRQF_TRIGGER_HIGH, "lsm303dlh_a", ldata)) {
+#endif /* A_USE_GPIO_EXTENDER_INT */
+ err = -EBUSY;
+ dev_err(&client->dev, "request irq failed\n");
+ goto exit_kfree;
+ }
+#endif /* A_USE_INT */
+
+ /* Set active high, latched interrupt when data is ready. */
+ if (i2c_smbus_write_byte_data(client, CTRL_REG3,
+ ((LSM303DLH_A_CR3_I_DATA << LSM303DLH_A_CR3_I1_BIT) |
+ (LSM303DLH_A_CR3_LIR_LATCH << LSM303DLH_A_CR3_LIR1_BIT)))) {
+ dev_err(&client->dev, "interrutp configuration failed\n");
+ err = -EINVAL;
+ goto exit_free_irq;
+ }
+
+ if (misc_register(&lsm303dlh_a_misc_device)) {
+ dev_err(&client->dev, "misc_register failed\n");
+ err = -EINVAL;
+ goto exit_free_irq;
+ }
+
+ ldata->input_dev = input_allocate_device();
+ if (!ldata->input_dev) {
+ err = -ENOMEM;
+ dev_err(&client->dev, "Failed to allocate input device\n");
+ goto exit_deregister_misc;
+ }
+
+ set_bit(EV_ABS, ldata->input_dev->evbit);
+
+ /* x-axis acceleration */
+ input_set_abs_params(ldata->input_dev, ABS_X, -2048, 2047, 0, 0);
+ /* y-axis acceleration */
+ input_set_abs_params(ldata->input_dev, ABS_Y, -2048, 2047, 0, 0);
+ /* z-axis acceleration */
+ input_set_abs_params(ldata->input_dev, ABS_Z, -2048, 2047, 0, 0);
+
+ ldata->input_dev->name = "compass";
+
+ err = input_register_device(ldata->input_dev);
+ if (err) {
+ dev_err(&client->dev, "Unable to register input device: %s\n",
+ ldata->input_dev->name);
+ goto exit_deregister_misc;
+ }
+
+ return 0;
+
+exit_deregister_misc:
+ misc_deregister(&lsm303dlh_a_misc_device);
+exit_free_irq:
+#ifdef A_USE_INT
+#ifdef A_USE_GPIO_EXTENDER_INT
+ ldata->pdata.free_irq(&client->dev);
+#else
+ free_irq(client->irq, ldata);
+#endif /* A_USE_GPIO_EXTENDER_INT */
+#endif /* A_USE_INT */
+
+exit_kfree:
+ kfree(ldata);
+exit:
+ dev_info(&client->dev, "%s: Driver Initialization failed\n", __FILE__);
+ return err;
+}
+
+static int lsm303dlh_a_remove(struct i2c_client *client)
+{
+ struct lsm303dlh_a_data *ldata = i2c_get_clientdata(client);
+
+ dev_info(&client->dev, "lsm303dlh_a driver removing\n");
+#ifdef A_USE_INT
+#ifdef A_USE_GPIO_EXTENDER_INT
+ ldata->pdata.free_irq(&client->dev);
+#else
+ free_irq(client->irq, ldata);
+#endif /* A_USE_GPIO_EXTENDER_INT */
+#endif /* A_USE_INT */
+
+ misc_deregister(&lsm303dlh_a_misc_device);
+
+ input_unregister_device(ldata->input_dev);
+
+ kfree(ldata);
+
+ return 0;
+}
+#ifdef CONFIG_PM
+static int lsm303dlh_a_suspend(struct i2c_client *client, pm_message_t state)
+{
+ int res;
+ struct lsm303dlh_a_data *ldata = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "lsm303dlh_a_suspend\n");
+
+ res = i2c_smbus_read_byte_data(ldata->client, CTRL_REG1);
+ if (res < 0)
+ return res;
+
+ ldata->ctrl_1 = res & 0xFF;
+
+ /* Put sensor to sleep mode. */
+ res = i2c_smbus_write_byte_data(ldata->client, CTRL_REG1, 0);
+ if (res)
+ return res;
+
+ ldata->mode = 0;
+
+#if defined(A_USE_INT) && !defined(A_USE_GPIO_EXTENDER_INT)
+ disable_irq(client->irq);
+#endif
+
+ return 0;
+}
+
+static int lsm303dlh_a_resume(struct i2c_client *client)
+{
+ int res;
+ struct lsm303dlh_a_data *ldata = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "lsm303dlh_a_resume\n");
+
+ /* Resume sensor state. */
+ res = i2c_smbus_write_byte_data(ldata->client, CTRL_REG1,
+ ldata->ctrl_1);
+ if (res)
+ return res;
+
+ ldata->mode = ((ldata->ctrl_1 & LSM303DLH_A_CR1_PM_MASK) >>
+ LSM303DLH_A_CR1_PM_BIT);
+
+#if defined(A_USE_INT) && !defined(A_USE_GPIO_EXTENDER_INT)
+ enable_irq(client->irq);
+#endif
+
+ return 0;
+}
+#endif
+
+static const struct i2c_device_id lsm303dlh_a_id[] = {
+ { "lsm303dlh_a", 0 },
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, lsm303dlh_a_id);
+
+static struct i2c_driver lsm303dlh_a_driver = {
+ .class = I2C_CLASS_HWMON,
+ .probe = lsm303dlh_a_probe,
+ .remove = __devexit_p(lsm303dlh_a_remove),
+ .id_table = lsm303dlh_a_id,
+#ifdef CONFIG_PM
+ .suspend = lsm303dlh_a_suspend,
+ .resume = lsm303dlh_a_resume,
+#endif
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "lsm303dlh_a",
+ },
+};
+
+static int __init lsm303dlh_a_init(void)
+{
+ return i2c_add_driver(&lsm303dlh_a_driver);
+}
+
+static void __exit lsm303dlh_a_exit(void)
+{
+ printk(KERN_INFO "lsm303dlh_a exit\n");
+
+ i2c_del_driver(&lsm303dlh_a_driver);
+ return;
+}
+
+module_init(lsm303dlh_a_init);
+module_exit(lsm303dlh_a_exit);
+
+MODULE_DESCRIPTION("lsm303dlh accelerometer driver");
+MODULE_AUTHOR("STMicroelectronics");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hwmon/lsm303dlh_m.c b/drivers/hwmon/lsm303dlh_m.c
new file mode 100644
index 00000000000..88ede7b923b
--- /dev/null
+++ b/drivers/hwmon/lsm303dlh_m.c
@@ -0,0 +1,617 @@
+/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
+*
+* File Name : lsm303dlh_m.c
+* Authors : MH - C&I BU - Application Team
+* : Carmine Iascone (carmine.iascone@st.com)
+* : Matteo Dameno (matteo.dameno@st.com)
+* Version : V 0.3
+* Date : 24/02/2010
+*
+********************************************************************************
+*
+* Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+* Copyright 2010 (c) ST-Ericsson AB
+*
+********************************************************************************
+*
+* 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.
+*
+* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
+* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE
+* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*
+* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
+*
+*******************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/uaccess.h>
+#include <linux/lsm303dlh.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+
+/* lsm303dlh magnetometer registers */
+#define IRA_REG_M 0x0A
+
+/* Magnetometer registers */
+#define CRA_REG_M 0x00 /* Configuration register A */
+#define CRB_REG_M 0x01 /* Configuration register B */
+#define MR_REG_M 0x02 /* Mode register */
+#define SR_REG_M 0x09 /* Status register */
+
+/* Output register start address*/
+#define OUT_X_M 0x03
+#define OUT_Y_M 0x05
+#define OUT_Z_M 0x07
+
+/* Magnetometer X-Y gain */
+#define XY_GAIN_1_3 1055 /* XY gain at 1.3G */
+#define XY_GAIN_1_9 795 /* XY gain at 1.9G */
+#define XY_GAIN_2_5 635 /* XY gain at 2.5G */
+#define XY_GAIN_4_0 430 /* XY gain at 4.0G */
+#define XY_GAIN_4_7 375 /* XY gain at 4.7G */
+#define XY_GAIN_5_6 320 /* XY gain at 5.6G */
+#define XY_GAIN_8_1 230 /* XY gain at 8.1G */
+
+/* Magnetometer Z gain */
+#define Z_GAIN_1_3 950 /* Z gain at 1.3G */
+#define Z_GAIN_1_9 710 /* Z gain at 1.9G */
+#define Z_GAIN_2_5 570 /* Z gain at 2.5G */
+#define Z_GAIN_4_0 385 /* Z gain at 4.0G */
+#define Z_GAIN_4_7 335 /* Z gain at 4.7G */
+#define Z_GAIN_5_6 285 /* Z gain at 5.6G */
+#define Z_GAIN_8_1 205 /* Z gain at 8.1G */
+
+/* Control A regsiter. */
+#define LSM303DLH_M_CRA_DO_BIT 2
+#define LSM303DLH_M_CRA_DO_MASK (0x7 << LSM303DLH_M_CRA_DO_BIT)
+#define LSM303DLH_M_CRA_MS_BIT 0
+#define LSM303DLH_M_CRA_MS_MASK (0x3 << LSM303DLH_M_CRA_MS_BIT)
+
+/* Control B regsiter. */
+#define LSM303DLH_M_CRB_GN_BIT 5
+#define LSM303DLH_M_CRB_GN_MASK (0x7 << LSM303DLH_M_CRB_GN_BIT)
+
+/* Control Mode regsiter. */
+#define LSM303DLH_M_MR_MD_BIT 0
+#define LSM303DLH_M_MR_MD_MASK (0x3 << LSM303DLH_M_MR_MD_BIT)
+
+/* Control Status regsiter. */
+#define LSM303DLH_M_SR_RDY_BIT 0
+#define LSM303DLH_M_SR_RDY_MASK (0x1 << LSM303DLH_M_SR_RDY_BIT)
+#define LSM303DLH_M_SR_LOC_BIT 1
+#define LSM303DLH_M_SR_LCO_MASK (0x1 << LSM303DLH_M_SR_LOC_BIT)
+#define LSM303DLH_M_SR_REN_BIT 2
+#define LSM303DLH_M_SR_REN_MASK (0x1 << LSM303DLH_M_SR_REN_BIT)
+
+/*
+ * LSM303DLH_M magnetometer local data
+ */
+struct lsm303dlh_m_data{
+ struct i2c_client *client;
+ struct lsm303dlh_platform_data pdata;
+ short gain[3];
+ short ms_delay;
+ unsigned char mode;
+};
+
+static struct lsm303dlh_m_data *file_private;
+
+/* set lsm303dlh magnetometer bandwidth */
+int lsm303dlh_m_set_rate(struct lsm303dlh_m_data *ldata, unsigned char bw)
+{
+ unsigned char data = 0;
+ int res;
+
+ switch (bw) {
+ case LSM303DLH_M_RATE_00_75:
+ ldata->ms_delay = 1334;
+ break;
+ case LSM303DLH_M_RATE_01_50:
+ ldata->ms_delay = 667;
+ break;
+ case LSM303DLH_M_RATE_03_00:
+ ldata->ms_delay = 334;
+ break;
+ case LSM303DLH_M_RATE_07_50:
+ ldata->ms_delay = 134;
+ break;
+ case LSM303DLH_M_RATE_15_00:
+ ldata->ms_delay = 67;
+ break;
+ case LSM303DLH_M_RATE_30_00:
+ ldata->ms_delay = 34;
+ break;
+ case LSM303DLH_M_RATE_75_00:
+ ldata->ms_delay = 14;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ data |= ((bw << LSM303DLH_M_CRA_DO_BIT) & LSM303DLH_M_CRA_DO_MASK);
+
+ res = i2c_smbus_write_byte_data(ldata->client, CRA_REG_M, data);
+
+ /* 100ms delay needed after setting mode. */
+ msleep(100);
+
+ return res;
+}
+
+/* read selected bandwidth from lsm303dlh_mag */
+int lsm303dlh_m_get_bandwidth(struct lsm303dlh_m_data *ldata, unsigned char *bw)
+{
+ unsigned char data;
+
+ data = i2c_smbus_read_byte_data(ldata->client, CRA_REG_M);
+ data &= LSM303DLH_M_CRA_DO_MASK;
+ data >>= LSM303DLH_M_CRA_DO_BIT;
+
+ return data;
+}
+
+/* i2c read routine for lsm303dlh magnetometer */
+static int lsm303dlh_m_one_axis(struct lsm303dlh_m_data *ldata,
+ unsigned char reg_addr,
+ u8 negative,
+ short *axis_data)
+{
+ s32 read_data;
+ short data;
+
+ /* No global client pointer? */
+ if (ldata->client == NULL)
+ return -EINVAL;
+
+ /* MSB is at lower address. */
+ read_data = i2c_smbus_read_word_data(ldata->client, reg_addr);
+ if (read_data < 0)
+ return -EINVAL;
+
+ data = ((read_data & 0xFF) << 8) | ((read_data >> 8) & 0xFF);
+
+ *axis_data = negative ? -data : data;
+
+ return 0;
+}
+
+
+/* X,Y and Z-axis magnetometer data readout
+ * param *data pointer to \ref 6 bytes buffer for x,y,z data readout
+ * note data will be read by multi-byte protocol into a 6 byte structure
+ */
+ssize_t lsm303dlh_m_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ int res;
+ short xyz_data[3];
+ struct lsm303dlh_m_data *ldata = filp->private_data;
+
+ if (count < sizeof(xyz_data))
+ return -EINVAL;
+
+ while (1) {
+ res = i2c_smbus_read_byte_data(ldata->client, SR_REG_M);
+ if (res < 0)
+ return res;
+
+ if (res & LSM303DLH_M_SR_RDY_MASK)
+ break;
+
+ /* Wait for sampling period. */
+ if (msleep_interruptible(ldata->ms_delay))
+ return -EINTR;
+ }
+
+ res = lsm303dlh_m_one_axis(ldata, OUT_X_M, ldata->pdata.negative_x,
+ &xyz_data[ldata->pdata.axis_map_x]);
+ if (res != 0)
+ return -EINVAL;
+
+ res = lsm303dlh_m_one_axis(ldata, OUT_Y_M, ldata->pdata.negative_y,
+ &xyz_data[ldata->pdata.axis_map_y]);
+ if (res != 0)
+ return -EINVAL;
+
+ res = lsm303dlh_m_one_axis(ldata, OUT_Z_M, ldata->pdata.negative_z,
+ &xyz_data[ldata->pdata.axis_map_z]);
+ if (res != 0)
+ return -EINVAL;
+
+ dev_dbg(&ldata->client->dev, "Hx= %d, Hy= %d, Hz= %d\n",
+ xyz_data[ldata->pdata.axis_map_x],
+ xyz_data[ldata->pdata.axis_map_y],
+ xyz_data[ldata->pdata.axis_map_z]);
+
+ if (copy_to_user(buf, xyz_data, sizeof(xyz_data)) != 0) {
+ dev_err(&ldata->client->dev, "copy_to error\n");
+ res = -EFAULT;
+ }
+
+ return sizeof(xyz_data);
+}
+
+int lsm303dlh_m_set_range(struct lsm303dlh_m_data *ldata, unsigned char range)
+{
+ short xy_gain;
+ short z_gain;
+
+ switch (range) {
+ case LSM303DLH_M_RANGE_1_3G:
+ xy_gain = XY_GAIN_1_3;
+ z_gain = Z_GAIN_1_3;
+ break;
+ case LSM303DLH_M_RANGE_1_9G:
+ xy_gain = XY_GAIN_1_9;
+ z_gain = Z_GAIN_1_9;
+ break;
+ case LSM303DLH_M_RANGE_2_5G:
+ xy_gain = XY_GAIN_2_5;
+ z_gain = Z_GAIN_2_5;
+ break;
+ case LSM303DLH_M_RANGE_4_0G:
+ xy_gain = XY_GAIN_4_0;
+ z_gain = Z_GAIN_4_0;
+ break;
+ case LSM303DLH_M_RANGE_4_7G:
+ xy_gain = XY_GAIN_4_7;
+ z_gain = Z_GAIN_4_7;
+ break;
+ case LSM303DLH_M_RANGE_5_6G:
+ xy_gain = XY_GAIN_5_6;
+ z_gain = Z_GAIN_5_6;
+ break;
+ case LSM303DLH_M_RANGE_8_1G:
+ xy_gain = XY_GAIN_8_1;
+ z_gain = Z_GAIN_8_1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ldata->gain[ldata->pdata.axis_map_x] = xy_gain;
+ ldata->gain[ldata->pdata.axis_map_y] = xy_gain;
+ ldata->gain[ldata->pdata.axis_map_z] = z_gain;
+
+ range <<= LSM303DLH_M_CRB_GN_BIT;
+
+ return i2c_smbus_write_byte_data(ldata->client, CRB_REG_M, range);
+
+}
+
+int lsm303dlh_m_set_mode(struct lsm303dlh_m_data *ldata, unsigned char mode)
+{
+ s32 res;
+ mode = (mode << LSM303DLH_M_MR_MD_BIT) & LSM303DLH_M_MR_MD_MASK;
+
+ res = i2c_smbus_write_byte_data(ldata->client, MR_REG_M, mode);
+ if (res < 0)
+ return res;
+
+ ldata->mode = (mode >> LSM303DLH_M_MR_MD_BIT);
+ return 0;
+}
+
+/* open command for lsm303dlh_m device file */
+static int lsm303dlh_m_open(struct inode *inode, struct file *filp)
+{
+ struct lsm303dlh_m_data *ldata = file_private;
+
+ filp->private_data = ldata;
+
+ if (ldata->client == NULL) {
+ printk(KERN_ERR"I2C driver not install\n");
+ return -EINVAL;
+ } else if (filp->f_flags & O_NONBLOCK) {
+ dev_err(&ldata->client->dev,
+ "Non Blocking operations are not supported\n");
+ return -EAGAIN;
+ }
+
+ dev_dbg(&ldata->client->dev, "lsm303dlh_m has been opened\n");
+
+ return 0;
+}
+
+/* release command for lsm303dlh_m device file */
+static int lsm303dlh_m_close(struct inode *inode, struct file *filp)
+{
+ struct lsm303dlh_m_data *ldata = filp->private_data;
+
+ dev_dbg(&ldata->client->dev, "lsm303dlh_m has been closed\n");
+ return 0;
+}
+
+
+/* ioctl command for lsm303dlh_m device file */
+static int lsm303dlh_m_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ unsigned char data[6];
+ struct lsm303dlh_m_data *ldata = filp->private_data;
+
+ /* check lsm303dlh_m_client */
+ if (ldata->client == NULL) {
+ printk(KERN_ERR"I2C driver not install\n");
+ return -EFAULT;
+ }
+
+ /* cmd mapping */
+ switch (cmd) {
+
+ case LSM303DLH_M_SET_RANGE:
+ if (copy_from_user(data, (unsigned char *)arg, 1) != 0) {
+ dev_err(&ldata->client->dev, "copy_from_user error\n");
+ return -EFAULT;
+ }
+ err = lsm303dlh_m_set_range(ldata, *data);
+ return err;
+
+ case LSM303DLH_M_SET_RATE:
+ if (copy_from_user(data, (unsigned char *)arg, 1) != 0) {
+ dev_err(&ldata->client->dev, "copy_from_user error\n");
+ return -EFAULT;
+ }
+ err = lsm303dlh_m_set_rate(ldata, *data);
+ return err;
+
+ case LSM303DLH_M_SET_MODE:
+ if (copy_from_user(data, (unsigned char *)arg, 1) != 0) {
+ dev_err(&ldata->client->dev, "copy_from_user error\n");
+ return -EFAULT;
+ }
+ err = lsm303dlh_m_set_mode(ldata, *data);
+ return err;
+
+ case LSM303DLH_M_GET_GAIN:
+ if (copy_to_user((unsigned char *)arg,
+ ldata->gain, sizeof(ldata->gain)) != 0) {
+ dev_err(&ldata->client->dev, "copy_to_user error\n");
+ return -EFAULT;
+ }
+ return 0;
+
+ case LSM303DLH_M_GET_MODE:
+ if (copy_to_user((unsigned char *)arg,
+ &ldata->mode, sizeof(ldata->mode)) != 0) {
+ dev_err(&ldata->client->dev, "copy_to_user error\n");
+ return -EFAULT;
+ }
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct file_operations lsm303dlh_m_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = lsm303dlh_m_read,
+ .open = lsm303dlh_m_open,
+ .release = lsm303dlh_m_close,
+ .ioctl = lsm303dlh_m_ioctl,
+};
+
+static struct miscdevice lsm303dlh_m_misc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "lsm303dlh_m",
+ .fops = &lsm303dlh_m_fops,
+};
+
+static int lsm303dlh_m_validate_pdata(struct lsm303dlh_m_data *mdata)
+{
+ if ((mdata->pdata.axis_map_x > 2) ||
+ (mdata->pdata.axis_map_y > 2) ||
+ (mdata->pdata.axis_map_z > 2) ||
+ (mdata->pdata.axis_map_x == mdata->pdata.axis_map_y) ||
+ (mdata->pdata.axis_map_x == mdata->pdata.axis_map_z) ||
+ (mdata->pdata.axis_map_y == mdata->pdata.axis_map_z)) {
+ dev_err(&mdata->client->dev,
+ "invalid axis_map value x:%u y:%u z%u\n",
+ mdata->pdata.axis_map_x, mdata->pdata.axis_map_y,
+ mdata->pdata.axis_map_z);
+ return -EINVAL;
+ }
+
+ /* Only allow 0 and 1 */
+ if ((mdata->pdata.negative_x > 1) ||
+ (mdata->pdata.negative_y > 1) ||
+ (mdata->pdata.negative_z > 1)) {
+ dev_err(&mdata->client->dev,
+ "invalid negate value x:%u y:%u z:%u\n",
+ mdata->pdata.negative_x, mdata->pdata.negative_y,
+ mdata->pdata.negative_z);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int lsm303dlh_m_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ int err = 0;
+ int tempvalue;
+ struct lsm303dlh_m_data *ldata;
+
+ if (client->dev.platform_data == NULL) {
+ dev_err(&client->dev, "platform data is NULL. exiting.\n");
+ err = -ENODEV;
+ goto exit;
+ }
+
+#if 0 /* TEMP */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
+ goto exit;
+#endif
+
+ /*
+ * OK. For now, we presume we have a valid client. We now create the
+ * client structure, even though we cannot fill it completely yet.
+ */
+
+ ldata = kzalloc(sizeof(*ldata), GFP_KERNEL);
+
+ if (ldata == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ file_private = ldata;
+
+ /* Initialize gain by 1 to avoid any divided by 0 errors */
+ ldata->gain[0] = 1;
+ ldata->gain[1] = 1;
+ ldata->gain[2] = 1;
+
+ ldata->mode = LSM303DLH_M_MODE_SLEEP;
+
+ i2c_set_clientdata(client, ldata);
+ ldata->client = client;
+
+ memcpy(&ldata->pdata, client->dev.platform_data, sizeof(ldata->pdata));
+ err = lsm303dlh_m_validate_pdata(ldata);
+ if (err < 0) {
+ dev_err(&client->dev, "failed to validate platform data\n");
+ goto exit_kfree;
+ }
+
+ err = i2c_smbus_read_byte(client);
+ if (err < 0) {
+ dev_err(&client->dev, "i2c_smbus_read_byte error!!\n");
+ err = -ENODEV;
+ goto exit_kfree;
+ } else {
+ dev_info(&client->dev, "LSM303DLH_M Device detected!\n");
+ }
+
+ /* read chip id */
+ tempvalue = i2c_smbus_read_word_data(client, IRA_REG_M);
+ if ((tempvalue & 0x00FF) == 0x0048) {
+ dev_info(&client->dev, "I2C driver registered!\n");
+ } else {
+ ldata->client = NULL;
+ err = -EINVAL;
+ goto exit_kfree;
+ }
+
+ if (misc_register(&lsm303dlh_m_misc_device)) {
+ dev_err(&client->dev, "misc_register failed\n");
+ err = -EINVAL;
+ goto error;
+ }
+
+ return 0;
+
+error:
+ dev_err(&client->dev, "%s: Driver Initialization failed\n", __FILE__);
+exit_kfree:
+ kfree(ldata);
+exit:
+ return err;
+}
+
+static int lsm303dlh_m_remove(struct i2c_client *client)
+{
+ struct lsm303dlh_m_data *data = i2c_get_clientdata(client);
+
+ dev_info(&client->dev, "LSM303DLH_M driver removing\n");
+
+ misc_deregister(&lsm303dlh_m_misc_device);
+
+ kfree(data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int lsm303dlh_m_suspend(struct i2c_client *client, pm_message_t state)
+{
+ s32 reg_data;
+ struct lsm303dlh_m_data *ldata = i2c_get_clientdata(client);
+
+ dev_info(&client->dev, "lsm303dlh_m_suspend\n");
+
+ reg_data = i2c_smbus_read_byte_data(ldata->client, CRA_REG_M);
+ if (reg_data < 0)
+ return reg_data;
+
+ ldata->mode = (reg_data & 0xFF);
+
+ lsm303dlh_m_set_mode(ldata, LSM303DLH_M_MODE_SLEEP);
+
+ return 0;
+}
+
+static int lsm303dlh_m_resume(struct i2c_client *client)
+{
+ struct lsm303dlh_m_data *ldata = i2c_get_clientdata(client);
+
+ dev_info(&client->dev, "lsm303dlh_m_resume\n");
+
+ lsm303dlh_m_set_mode(ldata, ldata->mode);
+
+ return 0;
+}
+#endif
+
+static const struct i2c_device_id lsm303dlh_m_id[] = {
+ { "lsm303dlh_m", 0 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, lsm303dlh_m_id);
+
+static struct i2c_driver lsm303dlh_m_driver = {
+ .class = I2C_CLASS_HWMON,
+ .probe = lsm303dlh_m_probe,
+ .remove = __devexit_p(lsm303dlh_m_remove),
+ .id_table = lsm303dlh_m_id,
+ #ifdef CONFIG_PM
+ .suspend = lsm303dlh_m_suspend,
+ .resume = lsm303dlh_m_resume,
+ #endif
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "lsm303dlh_m",
+ },
+};
+
+static int __init lsm303dlh_m_init(void)
+{
+ /* Add i2c driver for lsm303dlh magnetometer */
+ return i2c_add_driver(&lsm303dlh_m_driver);
+}
+
+static void __exit lsm303dlh_m_exit(void)
+{
+ i2c_del_driver(&lsm303dlh_m_driver);
+ return;
+}
+
+module_init(lsm303dlh_m_init);
+module_exit(lsm303dlh_m_exit);
+
+MODULE_DESCRIPTION("lsm303dlh magnetometer driver");
+MODULE_AUTHOR("STMicroelectronics");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 73de8ade10b..49a8674070b 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -22,6 +22,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/regulator/consumer.h>
#include <plat/i2c.h>
@@ -103,6 +104,9 @@
/* maximum threshold value */
#define MAX_I2C_FIFO_THRESHOLD 15
+/* delay for i2c transfers */
+#define I2C_DELAY 150
+
enum i2c_status {
I2C_NOP,
I2C_ON_GOING,
@@ -118,7 +122,7 @@ enum i2c_operation {
};
/* controller response timeout in ms */
-#define I2C_TIMEOUT_MS 500
+#define I2C_TIMEOUT_MS 2000
/**
* struct i2c_nmk_client - client specific data
@@ -160,6 +164,7 @@ struct nmk_i2c_dev {
int stop;
struct completion xfer_complete;
int result;
+ struct regulator *regulator;
};
/* controller's abort causes */
@@ -250,6 +255,8 @@ static int init_hw(struct nmk_i2c_dev *dev)
{
int stat;
+ clk_enable(dev->clk);
+
stat = flush_i2c_fifo(dev);
if (stat)
return stat;
@@ -263,6 +270,9 @@ static int init_hw(struct nmk_i2c_dev *dev)
dev->cli.operation = I2C_NO_OPERATION;
+ clk_disable(dev->clk);
+
+ udelay(I2C_DELAY);
return 0;
}
@@ -559,6 +569,11 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
if (status)
return status;
+ if (dev->regulator)
+ regulator_enable(dev->regulator);
+
+ clk_enable(dev->clk);
+
/* setup the i2c controller */
setup_i2c_controller(dev);
@@ -566,7 +581,9 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
if (unlikely(msgs[i].flags & I2C_M_TEN)) {
dev_err(&dev->pdev->dev, "10 bit addressing"
"not supported\n");
- return -EINVAL;
+
+ status = -EINVAL;
+ goto out;
}
dev->cli.slave_adr = msgs[i].addr;
dev->cli.buffer = msgs[i].buf;
@@ -591,10 +608,18 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
dev_err(&dev->pdev->dev, "%s\n",
cause >= ARRAY_SIZE(abort_causes)
? "unknown reason" : abort_causes[cause]);
- return status;
+
+ goto out;
}
- mdelay(1);
+ udelay(I2C_DELAY);
}
+
+out:
+ clk_disable(dev->clk);
+
+ if (dev->regulator)
+ regulator_disable(dev->regulator);
+
/* return the no. messages processed */
if (status)
return status;
@@ -850,6 +875,14 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
goto err_irq;
}
+ dev->regulator = regulator_get(&pdev->dev, "v-i2c");
+ if (IS_ERR(dev->regulator)) {
+ dev_err(&pdev->dev, "could not get i2c regulator\n");
+ ret = PTR_ERR(dev->regulator);
+ dev->regulator = NULL;
+ goto err_no_regulator;
+ }
+
dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) {
dev_err(&pdev->dev, "could not get i2c clock\n");
@@ -857,8 +890,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
goto err_no_clk;
}
- clk_enable(dev->clk);
-
adap = &dev->adap;
adap->dev.parent = &pdev->dev;
adap->owner = THIS_MODULE;
@@ -895,10 +926,11 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
return 0;
err_init_hw:
- clk_disable(dev->clk);
err_add_adap:
clk_put(dev->clk);
err_no_clk:
+ regulator_put(dev->regulator);
+ err_no_regulator:
free_irq(dev->irq, dev);
err_irq:
iounmap(dev->virtbase);
@@ -928,8 +960,8 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)
iounmap(dev->virtbase);
if (res)
release_mem_region(res->start, resource_size(res));
- clk_disable(dev->clk);
clk_put(dev->clk);
+ regulator_put(dev->regulator);
platform_set_drvdata(pdev, NULL);
kfree(dev);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 1ba25145b33..1e09cc5a909 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -143,6 +143,16 @@ config KEYBOARD_BFIN
To compile this driver as a module, choose M here: the
module will be called bf54x-keys.
+config KEYBOARD_DB5500
+ tristate "DB5500 keyboard"
+ depends on UX500_SOC_DB5500
+ help
+ Say Y here to enable the on-chip keypad controller on the
+ ST-Ericsson U5500 platform.
+
+ To compile this driver as a module, choose M here: the
+ module will be called db5500_keypad.
+
config KEYBOARD_LKKBD
tristate "DECstation/VAXstation LK201/LK401 keyboard"
select SERIO
@@ -315,6 +325,16 @@ config KEYBOARD_NEWTON
To compile this driver as a module, choose M here: the
module will be called newtonkbd.
+config KEYBOARD_NOMADIK
+ tristate "ST-Ericsson Nomadik SKE keyboard"
+ depends on PLAT_NOMADIK
+ help
+ Say Y here if you want to use a keypad provided on the SKE controller
+ used on the Ux500 and Nomadik platforms
+
+ To compile this driver as a module, choose M here: the
+ module will be called nmk-ske-keypad.
+
config KEYBOARD_OPENCORES
tristate "OpenCores Keyboard Controller"
help
@@ -374,6 +394,16 @@ config KEYBOARD_SH_KEYSC
To compile this driver as a module, choose M here: the
module will be called sh_keysc.
+config KEYBOARD_STMPE
+ tristate "STMPE keypad support"
+ depends on MFD_STMPE
+ help
+ Say Y here if you want to use the keypad controller on STMPE I/O
+ expanders.
+
+ To compile this driver as a module, choose M here: the module will be
+ called stmpe-keypad.
+
config KEYBOARD_DAVINCI
tristate "TI DaVinci Key Scan"
depends on ARCH_DAVINCI_DM365
@@ -404,6 +434,31 @@ config KEYBOARD_TWL4030
To compile this driver as a module, choose M here: the
module will be called twl4030_keypad.
+config TC35893_KEYPAD
+ tristate "TC35893 keypad controller"
+ depends on I2C
+ default y
+ help
+ Say Y here if you want to use the keypad controller on
+ TC35893 I/O expander.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tc35893-keypad
+
+ choice
+ prompt "Driver mode"
+ depends on TC35893_KEYPAD
+ default TC_KEYPAD_INTR
+
+ config TC_KEYPAD_POLL
+ depends on TC35893_KEYPAD
+ bool "Polling mode"
+
+ config TC_KEYPAD_INTR
+ depends on TC35893_KEYPAD
+ bool "Interrupt mode"
+ endchoice
+
config KEYBOARD_XTKBD
tristate "XT keyboard"
select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 4596d0c6f92..652c05dcca9 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
+obj-$(CONFIG_KEYBOARD_DB5500) += db5500_keypad.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o
@@ -27,12 +28,14 @@ obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
+obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
+obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
diff --git a/drivers/input/keyboard/db5500_keypad.c b/drivers/input/keyboard/db5500_keypad.c
new file mode 100644
index 00000000000..a6d0fe08961
--- /dev/null
+++ b/drivers/input/keyboard/db5500_keypad.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License, version 2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ */
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <mach/db5500-keypad.h>
+
+#define KEYPAD_CTR 0x0
+#define KEYPAD_IRQ_CLEAR 0x4
+#define KEYPAD_INT_ENABLE 0x8
+#define KEYPAD_INT_STATUS 0xC
+#define KEYPAD_ARRAY_01 0x18
+
+#define KEYPAD_NUM_ARRAY_REGS 5
+
+#define KEYPAD_CTR_WRITE_IRQ_ENABLE (1 << 10)
+#define KEYPAD_CTR_SCAN_ENABLE (1 << 7)
+
+#define KEYPAD_ARRAY_CHANGEBIT (1 << 15)
+
+#define KEYPAD_DEBOUNCE_PERIOD_MIN 5 /* ms */
+#define KEYPAD_DEBOUNCE_PERIOD_MAX 80 /* ms */
+
+#define KEYPAD_GND_ROW 8
+
+#define KEYPAD_MAX_ROWS 9
+#define KEYPAD_MAX_COLS 8
+#define KEYPAD_ROW_SHIFT 4
+#define KEYPAD_KEYMAP_SIZE \
+ (KEYPAD_MAX_ROWS * KEYPAD_MAX_COLS)
+
+/**
+ * struct db5500_keypad - data structure used by keypad driver
+ * @irq: irq number
+ * @base: keypad registers base address
+ * @input: pointer to input device object
+ * @board: keypad platform data
+ * @keymap: matrix scan code table for keycodes
+ * @clk: clock structure pointer
+ * @previous_set: previous set of registers
+ */
+struct db5500_keypad {
+ int irq;
+ void __iomem *base;
+ struct input_dev *input;
+ const struct db5500_keypad_platform_data *board;
+ unsigned short keymap[KEYPAD_KEYMAP_SIZE];
+ struct clk *clk;
+ u8 previous_set[KEYPAD_MAX_ROWS];
+};
+
+/*
+ * By default all column reads are 1111 1111b. Any press will pull the column
+ * down, leading to a 0 in any of these locations. We invert these values so
+ * that a 1 means means "column pressed".
+ *
+ * If curr changes from the previous from 0 to 1, we report it as a key press.
+ * If curr changes from the previous from 1 to 0, we report it as a key
+ * release.
+ */
+static void db5500_keypad_report(struct db5500_keypad *keypad, int row,
+ u8 curr, u8 previous)
+{
+ struct input_dev *input = keypad->input;
+ u8 changed = curr ^ previous;
+
+ while (changed) {
+ int col = __ffs(changed);
+ bool press = curr & BIT(col);
+ int code = MATRIX_SCAN_CODE(row, col, KEYPAD_ROW_SHIFT);
+
+ input_event(input, EV_MSC, MSC_SCAN, code);
+ input_report_key(input, keypad->keymap[code], press);
+ input_sync(input);
+
+ changed &= ~BIT(col);
+ }
+}
+
+static irqreturn_t db5500_keypad_irq(int irq, void *dev_id)
+{
+ struct db5500_keypad *keypad = dev_id;
+ u8 current_set[ARRAY_SIZE(keypad->previous_set)];
+ int tries = 100;
+ bool changebit;
+ u32 data_reg;
+ u8 allrows;
+ u8 common;
+ int i;
+
+ writel(0x1, keypad->base + KEYPAD_IRQ_CLEAR);
+
+again:
+ if (!tries--) {
+ dev_warn(&keypad->input->dev, "values failed to stabilize\n");
+ return IRQ_HANDLED;
+ }
+
+ changebit = readl(keypad->base + KEYPAD_ARRAY_01)
+ & KEYPAD_ARRAY_CHANGEBIT;
+
+ for (i = 0; i < KEYPAD_NUM_ARRAY_REGS; i++) {
+ data_reg = readl(keypad->base + KEYPAD_ARRAY_01 + 4 * i);
+
+ /* If the change bit changed, we need to reread the data */
+ if (changebit != !!(data_reg & KEYPAD_ARRAY_CHANGEBIT))
+ goto again;
+
+ current_set[2 * i] = ~(data_reg & 0xff);
+
+ /* Last array reg has only one valid set of columns */
+ if (i != KEYPAD_NUM_ARRAY_REGS - 1)
+ current_set[2 * i + 1] = ~((data_reg & 0xff0000) >> 16);
+ }
+
+ allrows = current_set[KEYPAD_GND_ROW];
+
+ /*
+ * Sometimes during a GND row release, an incorrect report is received
+ * where the ARRAY8 all rows setting does not match the other ARRAY*
+ * rows. Ignore this report; the correct one has been observed to
+ * follow it.
+ */
+ common = 0xff;
+ for (i = 0; i < KEYPAD_GND_ROW; i++)
+ common &= current_set[i];
+
+ if ((allrows & common) != common)
+ return IRQ_HANDLED;
+
+ for (i = 0; i < ARRAY_SIZE(current_set); i++) {
+ /*
+ * If there is an allrows press (GND row), we need to ignore
+ * the allrows values from the reset of the ARRAYs.
+ */
+ if (i < KEYPAD_GND_ROW && allrows)
+ current_set[i] &= ~allrows;
+
+ if (keypad->previous_set[i] == current_set[i])
+ continue;
+
+ db5500_keypad_report(keypad, i, current_set[i],
+ keypad->previous_set[i]);
+ }
+
+ /* update the reference set of array registers */
+ memcpy(keypad->previous_set, current_set, sizeof(keypad->previous_set));
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit db5500_keypad_chip_init(struct db5500_keypad *keypad)
+{
+ int debounce = keypad->board->debounce_ms;
+ int debounce_hits = 0;
+ int timeout = 100;
+ u32 val;
+
+ if (debounce < KEYPAD_DEBOUNCE_PERIOD_MIN)
+ debounce = KEYPAD_DEBOUNCE_PERIOD_MIN;
+
+ if (debounce > KEYPAD_DEBOUNCE_PERIOD_MAX) {
+ debounce_hits = DIV_ROUND_UP(debounce,
+ KEYPAD_DEBOUNCE_PERIOD_MAX) - 1;
+ debounce = KEYPAD_DEBOUNCE_PERIOD_MAX;
+ }
+
+ /* Convert the milliseconds to the bit mask */
+ debounce = DIV_ROUND_UP(debounce, KEYPAD_DEBOUNCE_PERIOD_MIN) - 1;
+
+ writel(KEYPAD_CTR_SCAN_ENABLE
+ | ((debounce_hits & 0x7) << 4)
+ | debounce, keypad->base + KEYPAD_CTR);
+
+ do {
+ val = readl(keypad->base + KEYPAD_CTR);
+ } while ((!(val & KEYPAD_CTR_WRITE_IRQ_ENABLE)) && --timeout);
+
+ if (!timeout)
+ return -EINVAL;
+
+ writel(0x1, keypad->base + KEYPAD_INT_ENABLE);
+
+ return 0;
+}
+
+static int __devinit db5500_keypad_probe(struct platform_device *pdev)
+{
+ const struct db5500_keypad_platform_data *plat;
+ struct db5500_keypad *keypad;
+ struct resource *res;
+ struct input_dev *input;
+ void __iomem *base;
+ struct clk *clk;
+ int ret;
+ int irq;
+
+ plat = pdev->dev.platform_data;
+ if (!plat) {
+ dev_err(&pdev->dev, "invalid keypad platform data\n");
+ ret = -EINVAL;
+ goto out_ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get keypad irq\n");
+ ret = -EINVAL;
+ goto out_ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "missing platform resources\n");
+ ret = -EINVAL;
+ goto out_ret;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ ret = -EBUSY;
+ goto out_ret;
+ }
+
+ base = ioremap(res->start, resource_size(res));
+ if (!base) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ ret = -ENXIO;
+ goto out_freerequest_memregions;
+ }
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "failed to clk_get\n");
+
+ /*
+ * FIXME: error out here once DB5500 clock framework is in
+ * place, and remove all the !IS_ERR(clk) checks.
+ */
+ }
+
+ keypad = kzalloc(sizeof(struct db5500_keypad), GFP_KERNEL);
+ if (!keypad) {
+ dev_err(&pdev->dev, "failed to allocate keypad memory\n");
+ ret = -ENOMEM;
+ goto out_freeclk;
+ }
+
+ input = input_allocate_device();
+ if (!input) {
+ dev_err(&pdev->dev, "failed to input_allocate_device\n");
+ ret = -ENOMEM;
+ goto out_freekeypad;
+ }
+
+ input->id.bustype = BUS_HOST;
+ input->name = "db5500-keypad";
+ input->dev.parent = &pdev->dev;
+
+ input->keycode = keypad->keymap;
+ input->keycodesize = sizeof(keypad->keymap[0]);
+ input->keycodemax = ARRAY_SIZE(keypad->keymap);
+
+ input_set_capability(input, EV_MSC, MSC_SCAN);
+
+ __set_bit(EV_KEY, input->evbit);
+ if (!plat->no_autorepeat)
+ __set_bit(EV_REP, input->evbit);
+
+ matrix_keypad_build_keymap(plat->keymap_data, KEYPAD_ROW_SHIFT,
+ input->keycode, input->keybit);
+
+ ret = input_register_device(input);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "unable to register input device: %d\n", ret);
+ goto out_freeinput;
+ }
+
+ keypad->irq = irq;
+ keypad->board = plat;
+ keypad->input = input;
+ keypad->base = base;
+ keypad->clk = clk;
+
+ /* allocations are sane, we begin HW initialization */
+ if (!IS_ERR(keypad->clk))
+ clk_enable(keypad->clk);
+
+ ret = db5500_keypad_chip_init(keypad);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to init keypad hardware\n");
+ goto out_unregisterinput;
+ }
+
+ ret = request_threaded_irq(keypad->irq, NULL, db5500_keypad_irq,
+ IRQF_ONESHOT, "db5500-keypad", keypad);
+ if (ret) {
+ dev_err(&pdev->dev, "allocate irq %d failed\n", keypad->irq);
+ goto out_unregisterinput;
+ }
+
+ device_init_wakeup(&pdev->dev, true);
+
+ platform_set_drvdata(pdev, keypad);
+
+ return 0;
+
+out_unregisterinput:
+ input_unregister_device(input);
+ input = NULL;
+ if (!IS_ERR(keypad->clk))
+ clk_disable(keypad->clk);
+out_freeinput:
+ input_free_device(input);
+out_freekeypad:
+ kfree(keypad);
+out_freeclk:
+ if (!IS_ERR(clk))
+ clk_put(clk);
+ iounmap(base);
+out_freerequest_memregions:
+ release_mem_region(res->start, resource_size(res));
+out_ret:
+ return ret;
+}
+
+static int __devexit db5500_keypad_remove(struct platform_device *pdev)
+{
+ struct db5500_keypad *keypad = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ free_irq(keypad->irq, keypad);
+ input_unregister_device(keypad->input);
+
+ if (!IS_ERR(keypad->clk)) {
+ clk_disable(keypad->clk);
+ clk_put(keypad->clk);
+ }
+
+ iounmap(keypad->base);
+ release_mem_region(res->start, resource_size(res));
+ kfree(keypad);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int db5500_keypad_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct db5500_keypad *keypad = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(irq);
+ else
+ /* disable IRQ here */
+
+ return 0;
+}
+
+static int db5500_keypad_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct db5500_keypad *keypad = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(irq);
+ else
+ /* enable IRQ here */
+
+ return 0;
+}
+
+static const struct dev_pm_ops db5500_keypad_dev_pm_ops = {
+ .suspend = db5500_keypad_suspend,
+ .resume = db5500_keypad_resume,
+};
+#endif
+
+static struct platform_driver db5500_keypad_driver = {
+ .driver = {
+ .name = "db5500-keypad",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &db5500_keypad_dev_pm_ops,
+#endif
+ },
+ .probe = db5500_keypad_probe,
+ .remove = __devexit_p(db5500_keypad_remove),
+};
+
+static int __init db5500_keypad_init(void)
+{
+ return platform_driver_register(&db5500_keypad_driver);
+}
+module_init(db5500_keypad_init);
+
+static void __exit db5500_keypad_exit(void)
+{
+ platform_driver_unregister(&db5500_keypad_driver);
+}
+module_exit(db5500_keypad_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("DB5500 Keypad Driver");
+MODULE_ALIAS("platform:db5500-keypad");
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
new file mode 100644
index 00000000000..4261f8647de
--- /dev/null
+++ b/drivers/input/keyboard/nomadik-ske-keypad.c
@@ -0,0 +1,490 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ * License terms:GNU General Public License (GPL) version 2
+ *
+ * Keypad controller driver for the SKE (Scroll Key Encoder) module used in
+ * the Nomadik 8815 and Ux500 platforms.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#include <plat/ske.h>
+
+/* SKE_CR bits */
+#define SKE_KPMLT (0x1 << 6)
+#define SKE_KPCN (0x7 << 3)
+#define SKE_KPASEN (0x1 << 2)
+#define SKE_KPASON (0x1 << 7)
+
+/* SKE_IMSC bits */
+#define SKE_KPIMA (0x1 << 2)
+
+/* SKE_ICR bits */
+#define SKE_KPICS (0x1 << 3)
+#define SKE_KPICA (0x1 << 2)
+
+/* SKE_RIS bits */
+#define SKE_KPRISA (0x1 << 2)
+
+#define SKE_KEYPAD_ROW_SHIFT 3
+#define SKE_KPD_KEYMAP_SIZE (8 * 8)
+
+/* keypad auto scan registers */
+#define SKE_ASR0 0x20
+#define SKE_ASR1 0x24
+#define SKE_ASR2 0x28
+#define SKE_ASR3 0x2C
+
+#define SKE_NUM_ASRX_REGISTERS (4)
+
+/**
+ * struct ske_keypad - data structure used by keypad driver
+ * @irq: irq no
+ * @reg_base: ske regsiters base address
+ * @input: pointer to input device object
+ * @board: keypad platform device
+ * @keymap: matrix scan code table for keycodes
+ * @clk: clock structure pointer
+ * @enable: flag to enable the driver event
+ */
+struct ske_keypad {
+ int irq;
+ void __iomem *reg_base;
+ struct input_dev *input;
+ const struct ske_keypad_platform_data *board;
+ unsigned short keymap[SKE_KPD_KEYMAP_SIZE];
+ struct clk *clk;
+ spinlock_t ske_keypad_lock;
+ bool enable;
+};
+
+static void ske_keypad_set_bits(struct ske_keypad *keypad, u16 addr,
+ u8 mask, u8 data)
+{
+ u32 ret;
+
+ spin_lock(&keypad->ske_keypad_lock);
+
+ ret = readl(keypad->reg_base + addr);
+ ret &= ~mask;
+ ret |= data;
+ writel(ret, keypad->reg_base + addr);
+
+ spin_unlock(&keypad->ske_keypad_lock);
+}
+
+static ssize_t ske_show_attr_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ske_keypad *keypad = platform_get_drvdata(pdev);
+ return sprintf(buf, "%d\n", keypad->enable);
+}
+
+static ssize_t ske_store_attr_enable(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ske_keypad *keypad = platform_get_drvdata(pdev);
+ unsigned long val;
+
+ if (strict_strtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if ((val != 0) && (val != 1))
+ return -EINVAL;
+
+ if (keypad->enable != val) {
+ keypad->enable = val ? true : false;
+ if (!keypad->enable) {
+ disable_irq(keypad->irq);
+ ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
+ clk_disable(keypad->clk);
+ } else {
+ clk_enable(keypad->clk);
+ enable_irq(keypad->irq);
+ ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+ }
+ }
+ return count;
+}
+
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
+ ske_show_attr_enable, ske_store_attr_enable);
+
+static struct attribute *ske_keypad_attrs[] = {
+ &dev_attr_enable.attr,
+ NULL,
+};
+
+static struct attribute_group ske_attr_group = {
+ .attrs = ske_keypad_attrs,
+};
+
+/*
+ * ske_keypad_chip_init: init keypad controller configuration
+ *
+ * Enable Multi key press detection, auto scan mode
+ */
+static int __devinit ske_keypad_chip_init(struct ske_keypad *keypad)
+{
+ u32 value;
+ int timeout = keypad->board->debounce_ms;
+
+ /* check SKE_RIS to be 0 */
+ while ((readl(keypad->reg_base + SKE_RIS) != 0x00000000) && timeout--)
+ cpu_relax();
+
+ if (!timeout)
+ return -EINVAL;
+
+ /*
+ * set debounce value
+ * keypad dbounce is configured in DBCR[15:8]
+ * dbounce value in steps of 32/32.768 ms
+ */
+ spin_lock(&keypad->ske_keypad_lock);
+ value = readl(keypad->reg_base + SKE_DBCR);
+ value = value & 0xff;
+ value |= ((keypad->board->debounce_ms * 32000)/32768) << 8;
+ writel(value, keypad->reg_base + SKE_DBCR);
+ spin_unlock(&keypad->ske_keypad_lock);
+
+ /* enable multi key detection */
+ ske_keypad_set_bits(keypad, SKE_CR, 0x0, SKE_KPMLT);
+
+ /*
+ * set up the number of columns
+ * KPCN[5:3] defines no. of keypad columns to be auto scanned
+ */
+ value = (keypad->board->kcol - 1) << 3;
+ ske_keypad_set_bits(keypad, SKE_CR, SKE_KPCN, value);
+
+ /* clear keypad interrupt for auto(and pending SW) scans */
+ ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA | SKE_KPICS);
+
+ /* un-mask keypad interrupts */
+ ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+
+ /* enable automatic scan */
+ ske_keypad_set_bits(keypad, SKE_CR, 0x0, SKE_KPASEN);
+
+ return 0;
+}
+
+static void ske_keypad_read_data(struct ske_keypad *keypad)
+{
+ struct input_dev *input = keypad->input;
+ u16 status;
+ int col = 0, row = 0, code;
+ int ske_asr, ske_ris, key_pressed, i;
+
+ /*
+ * Read the auto scan registers
+ *
+ * Each SKE_ASRx (x=0 to x=3) contains two row values.
+ * lower byte contains row value for column 2*x,
+ * upper byte contains row value for column 2*x + 1
+ */
+ for (i = 0; i < SKE_NUM_ASRX_REGISTERS; i++) {
+ ske_asr = readl(keypad->reg_base + SKE_ASR0 + (4 * i));
+ if (!ske_asr)
+ continue;
+
+ /* now that ASRx is zero, find out the column x and row y*/
+ if (ske_asr & 0xff) {
+ col = i * 2;
+ status = ske_asr & 0xff;
+ } else {
+ col = (i * 2) + 1;
+ status = (ske_asr & 0xff00) >> 8;
+ }
+
+ /* find out the row */
+ row = __ffs(status);
+
+ code = MATRIX_SCAN_CODE(row, col, SKE_KEYPAD_ROW_SHIFT);
+ ske_ris = readl(keypad->reg_base + SKE_RIS);
+ key_pressed = ske_ris & SKE_KPRISA;
+
+ input_event(input, EV_MSC, MSC_SCAN, code);
+ input_report_key(input, keypad->keymap[code], key_pressed);
+ input_sync(input);
+ }
+}
+
+static irqreturn_t ske_keypad_irq(int irq, void *dev_id)
+{
+ struct ske_keypad *keypad = dev_id;
+ int retries = 20;
+
+ /* disable auto scan interrupt; mask the interrupt generated */
+ ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
+ ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA);
+
+ while ((readl(keypad->reg_base + SKE_CR) & SKE_KPASON) && --retries)
+ msleep(5);
+
+ if (retries) {
+ /* SKEx registers are stable and can be read */
+ ske_keypad_read_data(keypad);
+ }
+
+ /* enable auto scan interrupts */
+ ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit ske_keypad_probe(struct platform_device *pdev)
+{
+ struct ske_keypad *keypad;
+ struct resource *res = NULL;
+ struct input_dev *input;
+ struct clk *clk;
+ void __iomem *reg_base;
+ int ret = 0;
+ int irq;
+ struct ske_keypad_platform_data *plat = pdev->dev.platform_data;
+
+ if (!plat) {
+ dev_err(&pdev->dev, "invalid keypad platform data\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get keypad irq\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "missing platform resources\n");
+ return -ENXIO;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ return -EBUSY;
+ }
+
+ reg_base = ioremap(res->start, resource_size(res));
+ if (!reg_base) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ ret = -ENXIO;
+ goto out_freerequest_memregions;
+ }
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "failed to clk_get\n");
+ ret = PTR_ERR(clk);
+ goto out_freeioremap;
+ }
+
+ /* resources are sane; we begin allocation */
+ keypad = kzalloc(sizeof(struct ske_keypad), GFP_KERNEL);
+ if (!keypad) {
+ dev_err(&pdev->dev, "failed to allocate keypad memory\n");
+ goto out_freeclk;
+ }
+
+ input = input_allocate_device();
+ if (!input) {
+ dev_err(&pdev->dev, "failed to input_allocate_device\n");
+ ret = -ENOMEM;
+ goto out_freekeypad;
+ }
+
+ input->id.bustype = BUS_HOST;
+ input->name = "ux500-ske-keypad";
+ input->dev.parent = &pdev->dev;
+
+ input->keycode = keypad->keymap;
+ input->keycodesize = sizeof(keypad->keymap[0]);
+ input->keycodemax = ARRAY_SIZE(keypad->keymap);
+
+ input_set_capability(input, EV_MSC, MSC_SCAN);
+ input_set_drvdata(input, keypad);
+
+ __set_bit(EV_KEY, input->evbit);
+ if (!plat->no_autorepeat)
+ __set_bit(EV_REP, input->evbit);
+
+ matrix_keypad_build_keymap(plat->keymap_data, SKE_KEYPAD_ROW_SHIFT,
+ input->keycode, input->keybit);
+
+ ret = input_register_device(input);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "unable to register input device: %d\n", ret);
+ goto out_freeinput;
+ }
+
+ keypad->board = plat;
+ keypad->irq = irq;
+ keypad->board = plat;
+ keypad->input = input;
+ keypad->reg_base = reg_base;
+ keypad->clk = clk;
+ keypad->enable = true;
+
+ /* allocations are sane, we begin HW initialization */
+ clk_enable(keypad->clk);
+
+ if (!keypad->board->init) {
+ dev_err(&pdev->dev, "NULL board initialization helper\n");
+ ret = -EINVAL;
+ goto out_unregisterinput;
+ }
+
+ if (keypad->board->init() < 0) {
+ dev_err(&pdev->dev, "unable to set keypad board config\n");
+ ret = -EINVAL;
+ goto out_unregisterinput;
+ }
+
+ ret = ske_keypad_chip_init(keypad);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to init keypad hardware\n");
+ goto out_unregisterinput;
+ }
+
+ ret = request_threaded_irq(keypad->irq, NULL, ske_keypad_irq,
+ IRQF_ONESHOT, "ske-keypad", keypad);
+ if (ret) {
+ dev_err(&pdev->dev, "allocate irq %d failed\n", keypad->irq);
+ goto out_unregisterinput;
+ }
+
+ /* sysfs implementation for dynamic enable/disable the input event */
+ ret = sysfs_create_group(&pdev->dev.kobj, &ske_attr_group);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to create sysfs entries\n");
+ goto out_free_irq;
+ }
+
+ device_init_wakeup(&pdev->dev, true);
+
+ platform_set_drvdata(pdev, keypad);
+
+ return 0;
+
+out_free_irq:
+ free_irq(keypad->irq, keypad);
+out_unregisterinput:
+ input_unregister_device(input);
+ input = NULL;
+ clk_disable(keypad->clk);
+out_freeinput:
+ input_free_device(input);
+out_freekeypad:
+ kfree(keypad);
+out_freeclk:
+ clk_put(keypad->clk);
+out_freeioremap:
+ iounmap(reg_base);
+out_freerequest_memregions:
+ release_mem_region(res->start, resource_size(res));
+ return ret;
+}
+
+static int __devexit ske_keypad_remove(struct platform_device *pdev)
+{
+ struct ske_keypad *keypad = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ free_irq(keypad->irq, keypad);
+
+ input_unregister_device(keypad->input);
+
+ sysfs_remove_group(&pdev->dev.kobj, &ske_attr_group);
+ clk_disable(keypad->clk);
+ clk_put(keypad->clk);
+
+ if (keypad->board->exit)
+ keypad->board->exit();
+
+ iounmap(keypad->reg_base);
+ release_mem_region(res->start, resource_size(res));
+ kfree(keypad);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ske_keypad_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ske_keypad *keypad = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(irq);
+ else
+ ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
+
+ return 0;
+}
+
+static int ske_keypad_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ske_keypad *keypad = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(irq);
+ else
+ ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ske_keypad_dev_pm_ops = {
+ .suspend = ske_keypad_suspend,
+ .resume = ske_keypad_resume,
+};
+#endif
+
+struct platform_driver ske_keypad_driver = {
+ .driver = {
+ .name = "nmk-ske-keypad",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &ske_keypad_dev_pm_ops,
+#endif
+ },
+ .probe = ske_keypad_probe,
+ .remove = __devexit_p(ske_keypad_remove),
+};
+
+static int __init ske_keypad_init(void)
+{
+ return platform_driver_register(&ske_keypad_driver);
+}
+module_init(ske_keypad_init);
+
+static void __exit ske_keypad_exit(void)
+{
+ platform_driver_unregister(&ske_keypad_driver);
+}
+module_exit(ske_keypad_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Naveen Kumar <naveen.gaddipati@stericsson.com> / Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("Nomadik Scroll-Key-Encoder Keypad Driver");
+MODULE_ALIAS("platform:nomadik-ske-keypad");
diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c
new file mode 100644
index 00000000000..ab7610ca10e
--- /dev/null
+++ b/drivers/input/keyboard/stmpe-keypad.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/mfd/stmpe.h>
+
+/* These are at the same addresses in all STMPE variants */
+#define STMPE_KPC_COL 0x60
+#define STMPE_KPC_ROW_MSB 0x61
+#define STMPE_KPC_ROW_LSB 0x62
+#define STMPE_KPC_CTRL_MSB 0x63
+#define STMPE_KPC_CTRL_LSB 0x64
+#define STMPE_KPC_COMBI_KEY_0 0x65
+#define STMPE_KPC_COMBI_KEY_1 0x66
+#define STMPE_KPC_COMBI_KEY_2 0x67
+#define STMPE_KPC_DATA_BYTE0 0x68
+#define STMPE_KPC_DATA_BYTE1 0x69
+#define STMPE_KPC_DATA_BYTE2 0x6a
+#define STMPE_KPC_DATA_BYTE3 0x6b
+#define STMPE_KPC_DATA_BYTE4 0x6c
+
+#define STMPE_KPC_CTRL_LSB_SCAN (0x1 << 0)
+#define STMPE_KPC_CTRL_LSB_DEBOUNCE (0x7f << 1)
+#define STMPE_KPC_CTRL_MSB_SCAN_COUNT (0xf << 4)
+
+#define STMPE_KPC_ROW_MSB_ROWS 0xff
+
+#define STMPE_KPC_DATA_UP (0x1 << 7)
+#define STMPE_KPC_DATA_ROW (0xf << 3)
+#define STMPE_KPC_DATA_COL (0x7 << 0)
+#define STMPE_KPC_DATA_NOKEY_MASK 0x78
+
+#define STMPE_KEYPAD_MAX_DEBOUNCE 127
+#define STMPE_KEYPAD_MAX_SCAN_COUNT 15
+
+#define STMPE_KEYPAD_MAX_ROWS 8
+#define STMPE_KEYPAD_MAX_COLS 8
+#define STMPE_KEYPAD_ROW_SHIFT 3
+#define STMPE_KEYPAD_KEYMAP_SIZE \
+ (STMPE_KEYPAD_MAX_ROWS * STMPE_KEYPAD_MAX_COLS)
+
+/**
+ * struct stmpe_keypad_variant - model-specific attributes
+ * @auto_increment: whether the KPC_DATA_BYTE register address
+ * auto-increments on multiple read
+ * @num_data: number of data bytes
+ * @num_normal_data: number of normal keys' data bytes
+ * @max_cols: maximum number of columns supported
+ * @max_rows: maximum number of rows supported
+ * @col_gpios: bitmask of gpios which can be used for columns
+ * @row_gpios: bitmask of gpios which can be used for rows
+ */
+struct stmpe_keypad_variant {
+ bool auto_increment;
+ int num_data;
+ int num_normal_data;
+ int max_cols;
+ int max_rows;
+ unsigned int col_gpios;
+ unsigned int row_gpios;
+};
+
+static const struct stmpe_keypad_variant stmpe_keypad_variants[] = {
+ [STMPE1601] = {
+ .auto_increment = true,
+ .num_data = 5,
+ .num_normal_data = 3,
+ .max_cols = 8,
+ .max_rows = 8,
+ .col_gpios = 0x000ff, /* GPIO 0 - 7 */
+ .row_gpios = 0x0ff00, /* GPIO 8 - 15 */
+ },
+ [STMPE2401] = {
+ .auto_increment = false,
+ .num_data = 3,
+ .num_normal_data = 2,
+ .max_cols = 8,
+ .max_rows = 12,
+ .col_gpios = 0x0000ff, /* GPIO 0 - 7*/
+ .row_gpios = 0x1fef00, /* GPIO 8-14, 16-20 */
+ },
+ [STMPE2403] = {
+ .auto_increment = true,
+ .num_data = 5,
+ .num_normal_data = 3,
+ .max_cols = 8,
+ .max_rows = 12,
+ .col_gpios = 0x0000ff, /* GPIO 0 - 7*/
+ .row_gpios = 0x1fef00, /* GPIO 8-14, 16-20 */
+ },
+};
+
+struct stmpe_keypad {
+ struct stmpe *stmpe;
+ struct input_dev *input;
+ const struct stmpe_keypad_variant *variant;
+ const struct stmpe_keypad_platform_data *plat;
+
+ unsigned int rows;
+ unsigned int cols;
+
+ unsigned short keymap[STMPE_KEYPAD_KEYMAP_SIZE];
+};
+
+static int stmpe_keypad_read_data(struct stmpe_keypad *keypad, u8 *data)
+{
+ const struct stmpe_keypad_variant *variant = keypad->variant;
+ struct stmpe *stmpe = keypad->stmpe;
+ int ret;
+ int i;
+
+ if (variant->auto_increment)
+ return stmpe_block_read(stmpe, STMPE_KPC_DATA_BYTE0,
+ variant->num_data, data);
+
+ for (i = 0; i < variant->num_data; i++) {
+ ret = stmpe_reg_read(stmpe, STMPE_KPC_DATA_BYTE0 + i);
+ if (ret < 0)
+ return ret;
+
+ data[i] = ret;
+ }
+
+ return 0;
+}
+
+static irqreturn_t stmpe_keypad_irq(int irq, void *dev)
+{
+ struct stmpe_keypad *keypad = dev;
+ struct input_dev *input = keypad->input;
+ const struct stmpe_keypad_variant *variant = keypad->variant;
+ u8 fifo[variant->num_data];
+ int ret;
+ int i;
+
+ ret = stmpe_keypad_read_data(keypad, fifo);
+ if (ret < 0)
+ return IRQ_NONE;
+
+ for (i = 0; i < variant->num_normal_data; i++) {
+ u8 data = fifo[i];
+ int row = (data & STMPE_KPC_DATA_ROW) >> 3;
+ int col = data & STMPE_KPC_DATA_COL;
+ int code = MATRIX_SCAN_CODE(row, col, STMPE_KEYPAD_ROW_SHIFT);
+ bool up = data & STMPE_KPC_DATA_UP;
+
+ if ((data & STMPE_KPC_DATA_NOKEY_MASK)
+ == STMPE_KPC_DATA_NOKEY_MASK)
+ continue;
+
+ input_event(input, EV_MSC, MSC_SCAN, code);
+ input_report_key(input, keypad->keymap[code], !up);
+ input_sync(input);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad)
+{
+ const struct stmpe_keypad_variant *variant = keypad->variant;
+ unsigned int col_gpios = variant->col_gpios;
+ unsigned int row_gpios = variant->row_gpios;
+ struct stmpe *stmpe = keypad->stmpe;
+ unsigned int pins = 0;
+ int i;
+
+ /*
+ * Figure out which pins need to be set to the keypad alternate
+ * function.
+ *
+ * {cols,rows}_gpios are bitmasks of which pins on the chip can be used
+ * for the keypad.
+ *
+ * keypad->{cols,rows} are a bitmask of which pins (of the ones useable
+ * for the keypad) are used on the board.
+ */
+
+ for (i = 0; i < variant->max_cols; i++) {
+ int num = __ffs(col_gpios);
+
+ if (keypad->cols & (1 << i))
+ pins |= 1 << num;
+
+ col_gpios &= ~(1 << num);
+ }
+
+ for (i = 0; i < variant->max_rows; i++) {
+ int num = __ffs(row_gpios);
+
+ if (keypad->rows & (1 << i))
+ pins |= 1 << num;
+
+ row_gpios &= ~(1 << num);
+ }
+
+ return stmpe_set_altfunc(stmpe, pins, STMPE_BLOCK_KEYPAD);
+}
+
+static int __devinit stmpe_keypad_chip_init(struct stmpe_keypad *keypad)
+{
+ const struct stmpe_keypad_platform_data *plat = keypad->plat;
+ const struct stmpe_keypad_variant *variant = keypad->variant;
+ struct stmpe *stmpe = keypad->stmpe;
+ int ret;
+
+ if (plat->debounce_ms > STMPE_KEYPAD_MAX_DEBOUNCE)
+ return -EINVAL;
+
+ if (plat->scan_count > STMPE_KEYPAD_MAX_SCAN_COUNT)
+ return -EINVAL;
+
+ ret = stmpe_enable(stmpe, STMPE_BLOCK_KEYPAD);
+ if (ret < 0)
+ return ret;
+
+ ret = stmpe_keypad_altfunc_init(keypad);
+ if (ret < 0)
+ return ret;
+
+ ret = stmpe_reg_write(stmpe, STMPE_KPC_COL, keypad->cols);
+ if (ret < 0)
+ return ret;
+
+ ret = stmpe_reg_write(stmpe, STMPE_KPC_ROW_LSB, keypad->rows);
+ if (ret < 0)
+ return ret;
+
+ if (variant->max_rows > 8) {
+ ret = stmpe_set_bits(stmpe, STMPE_KPC_ROW_MSB,
+ STMPE_KPC_ROW_MSB_ROWS,
+ keypad->rows >> 8);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = stmpe_set_bits(stmpe, STMPE_KPC_CTRL_MSB,
+ STMPE_KPC_CTRL_MSB_SCAN_COUNT,
+ plat->scan_count << 4);
+ if (ret < 0)
+ return ret;
+
+ return stmpe_set_bits(stmpe, STMPE_KPC_CTRL_LSB,
+ STMPE_KPC_CTRL_LSB_SCAN |
+ STMPE_KPC_CTRL_LSB_DEBOUNCE,
+ STMPE_KPC_CTRL_LSB_SCAN |
+ (plat->debounce_ms << 1));
+}
+
+static int __devinit stmpe_keypad_probe(struct platform_device *pdev)
+{
+ struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
+ struct stmpe_keypad_platform_data *plat;
+ struct stmpe_keypad *keypad;
+ struct input_dev *input;
+ int ret;
+ int irq;
+ int i;
+
+ plat = stmpe->pdata->keypad;
+ if (!plat)
+ return -ENODEV;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ keypad = kzalloc(sizeof(struct stmpe_keypad), GFP_KERNEL);
+ if (!keypad)
+ return -ENOMEM;
+
+ input = input_allocate_device();
+ if (!input) {
+ ret = -ENOMEM;
+ goto out_freekeypad;
+ }
+
+ input->name = "STMPE keypad";
+ input->id.bustype = BUS_I2C;
+ input->dev.parent = &pdev->dev;
+
+ input_set_capability(input, EV_MSC, MSC_SCAN);
+
+ __set_bit(EV_KEY, input->evbit);
+ if (!plat->no_autorepeat)
+ __set_bit(EV_REP, input->evbit);
+
+ input->keycode = keypad->keymap;
+ input->keycodesize = sizeof(keypad->keymap[0]);
+ input->keycodemax = ARRAY_SIZE(keypad->keymap);
+
+ matrix_keypad_build_keymap(plat->keymap_data, STMPE_KEYPAD_ROW_SHIFT,
+ input->keycode, input->keybit);
+
+ for (i = 0; i < plat->keymap_data->keymap_size; i++) {
+ unsigned int key = plat->keymap_data->keymap[i];
+
+ keypad->cols |= 1 << KEY_COL(key);
+ keypad->rows |= 1 << KEY_ROW(key);
+ }
+
+ keypad->stmpe = stmpe;
+ keypad->plat = plat;
+ keypad->input = input;
+ keypad->variant = &stmpe_keypad_variants[stmpe->partnum];
+
+ ret = stmpe_keypad_chip_init(keypad);
+ if (ret < 0)
+ goto out_freeinput;
+
+ ret = input_register_device(input);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "unable to register input device: %d\n", ret);
+ goto out_freeinput;
+ }
+
+ ret = request_threaded_irq(irq, NULL, stmpe_keypad_irq, IRQF_ONESHOT,
+ "stmpe-keypad", keypad);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
+ goto out_unregisterinput;
+ }
+
+ platform_set_drvdata(pdev, keypad);
+
+ return 0;
+
+out_unregisterinput:
+ input_unregister_device(input);
+ input = NULL;
+out_freeinput:
+ input_free_device(input);
+out_freekeypad:
+ kfree(keypad);
+ return ret;
+}
+
+static int __devexit stmpe_keypad_remove(struct platform_device *pdev)
+{
+ struct stmpe_keypad *keypad = platform_get_drvdata(pdev);
+ struct stmpe *stmpe = keypad->stmpe;
+ int irq = platform_get_irq(pdev, 0);
+
+ stmpe_disable(stmpe, STMPE_BLOCK_KEYPAD);
+
+ free_irq(irq, keypad);
+ input_unregister_device(keypad->input);
+ platform_set_drvdata(pdev, NULL);
+ kfree(keypad);
+
+ return 0;
+}
+
+static struct platform_driver stmpe_keypad_driver = {
+ .driver.name = "stmpe-keypad",
+ .driver.owner = THIS_MODULE,
+ .probe = stmpe_keypad_probe,
+ .remove = __devexit_p(stmpe_keypad_remove),
+};
+
+static int __init stmpe_keypad_init(void)
+{
+ return platform_driver_register(&stmpe_keypad_driver);
+}
+module_init(stmpe_keypad_init);
+
+static void __exit stmpe_keypad_exit(void)
+{
+ platform_driver_unregister(&stmpe_keypad_driver);
+}
+module_exit(stmpe_keypad_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMPExxxx keypad driver");
+MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
diff --git a/drivers/input/keyboard/tc35893-keypad.c b/drivers/input/keyboard/tc35893-keypad.c
new file mode 100644
index 00000000000..5f2515c8086
--- /dev/null
+++ b/drivers/input/keyboard/tc35893-keypad.c
@@ -0,0 +1,942 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com> for ST-Ericsson
+ */
+
+
+/* Keypad driver Version */
+#define TC_KEYPAD_VER_MAJOR 1
+#define TC_KEYPAD_VER_MINOR 0
+#define TC_KEYPAD_VER_RELEASE 0
+
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/completion.h>
+#include <linux/bitops.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <mach/tc35893-keypad.h>
+
+/* Maximum supported keypad matrix row/columns size */
+#define TC_MAX_KPROW 8
+#define TC_MAX_KPCOL 12
+
+/* keypad related Constants */
+#define TC_KEYPAD_RELEASE_PERIOD 11 /*110 Msec, repeate key scan time */
+#define TC_KEYPAD_SCAN_PERIOD 4 /*40Msec for new keypress */
+#define TC_MAX_DEBOUNCE_SETTLE 0xFF
+#define DEDICATED_KEY_VAL 0xFF
+#define KPINTR_LKBIT 0 /*bit used for interrupt locking */
+
+/* Keyboard Configuration Registers Index */
+#define TC_KBDSETTLE_REG 0x01
+#define TC_KBDBOUNCE 0x02
+#define TC_KBDSIZE 0x03
+#define TC_KBCFG_LSB 0x04
+#define TC_KBCFG_MSB 0x05
+#define TC_KBDRIS 0x06
+#define TC_KBDMIS 0x07
+#define TC_KBDIC 0x08
+#define TC_KBDMSK 0x09
+#define TC_KBDCODE0 0x0B
+#define TC_KBDCODE1 0x0C
+#define TC_KBDCODE2 0x0D
+#define TC_KBDCODE3 0x0E
+#define TC_EVTCODE_FIFO 0x10
+
+/* System registers Index */
+#define TC_MANUFACTURE_CODE 0x80
+#define TC_VERSION_ID 0x81
+#define TC_I2CSA 0x82
+#define TC_IOCFG 0xA7
+
+/* clock control registers */
+#define TC_CLKMODE 0x88
+#define TC_CLKCFG 0x89
+#define TC_CLKEN 0x8A
+
+/* Reset Control registers */
+#define TC_RSTCTRL 0x82
+#define TC_RSTINTCLR 0x84
+
+/* special function register and drive config registers */
+#define TC_KBDMFS 0x8F
+#define TC_IRQST 0x91
+#define TC_DRIVE0_LSB 0xA0
+#define TC_DRIVE0_MSB 0xA1
+#define TC_DRIVE1_LSB 0xA2
+#define TC_DRIVE1_MSB 0xA3
+#define TC_DRIVE2_LSB 0xA4
+#define TC_DRIVE2_MSB 0xA5
+#define TC_DRIVE3 0xA6
+
+/* Pull up/down configuration registers */
+#define TC_IOCFG 0xA7
+#define TC_IOPULLCFG0_LSB 0xAA
+#define TC_IOPULLCFG0_MSB 0xAB
+#define TC_IOPULLCFG1_LSB 0xAC
+#define TC_IOPULLCFG1_MSB 0xAD
+#define TC_IOPULLCFG2_LSB 0xAE
+
+/* Pull up/down masks */
+#define TC_NO_PULL_MASK 0x0
+#define TC_PULL_DOWN_MASK 0x1
+#define TC_PULL_UP_MASK 0x2
+#define TC_PULLUP_ALL_MASK 0xAA
+#define TC_IO_PULL_VAL(index, mask) ((mask)<<((index)%4)*2))
+
+/* Bit masks for IOCFG register */
+#define IOCFG_BALLCFG 0x01
+#define IOCFG_IG 0x08
+
+#define KP_EVCODE_COL_MASK 0x0F
+#define KP_EVCODE_ROW_MASK 0x70
+#define KP_RELEASE_EVT_MASK 0x80
+
+#define KP_ROW_SHIFT 4
+
+#define KP_NO_VALID_KEY_MASK 0x7F
+
+
+#define TC_MAN_CODE_VAL 0x03
+#define TC_SW_VERSION 0x80
+
+/* bit masks for RESTCTRL register */
+#define TC_KBDRST 0x2
+#define TC_IRQRST 0x10
+#define TC_RESET_ALL 0x1B
+/* KBDMFS register bit mask */
+#define TC_KBDMFS_EN 0x1
+
+/* CLKEN register bitmask */
+#define KPD_CLK_EN 0x1
+
+/* RSTINTCLR register bit mask */
+#define IRQ_CLEAR 0x1
+
+/* bit masks for keyboard interrupts*/
+#define TC_EVT_LOSS_INT 0x8
+#define TC_EVT_INT 0x4
+#define TC_KBD_LOSS_INT 0x2
+#define TC_KBD_INT 0x1
+
+/* bit masks for keyboard interrupt clear*/
+#define TC_EVT_INT_CLR 0x2
+#define TC_KBD_INT_CLR 0x1
+
+/* Macro for key definition */
+#define TC_KEY(col, row) ((col) + ((row) << KP_ROW_SHIFT))
+
+#define EVT_BUF_SIZE 8
+
+struct tc35893_info {
+ unsigned char chip_id;
+ unsigned char version_id;
+};
+
+/**
+* struct t_tc35893_key_status - Data structure for key status during last scan.
+* @nb_events: count of events received due to key press/release
+* @event_buf: To save all key changed key event code, used to save
+* data from event FIFO
+* @
+*/
+struct t_tc35893_key_status {
+ unsigned char nb_events;
+ unsigned char event_buf[EVT_BUF_SIZE];
+};
+
+/**
+ * struct tc_keypad - keypad data structure used internally by keypad driver
+ * @mode: 0 for interrupt mode, 1 for polling mode
+ * @lockbits: used for synchronisation in ISR
+ * @inp_dev: pointer to input device object
+ * @kscan_work: work queue
+ * @board: keypad platform device
+ * @client: i2c client data structure
+ * @lock: internal sync primitive
+ * @keyp_cnt: keeps count of total number of keys pressed at
+ * any point of time.
+ */
+struct tc_keypad {
+ int mode;
+ unsigned long lockbits;
+ struct input_dev *inp_dev;
+ struct delayed_work kscan_work;
+ struct tc35893_platform_data *board;
+ struct i2c_client *client;
+ struct mutex lock;
+ int keyp_cnt;
+};
+
+
+/**
+ * tc35893_write_byte() - Write a single byte
+ * @client: i2c client pointer
+ * @reg: register offset
+ * @data: data byte to be written
+ *
+ * This funtion uses smbus byte write API to write a single byte to tc35893
+ **/
+static int tc35893_write_byte(struct i2c_client *client,
+ unsigned char reg, unsigned char data)
+{
+ int ret;
+ ret = i2c_smbus_write_byte_data(client, reg, data);
+ if (ret < 0)
+ dev_err(&client->dev, "Error in writing reg %x: error = %d\n",
+ reg, ret);
+ return ret;
+}
+
+/**
+ * tc35893_read_byte() - Read a single byte
+ * @client: i2c client data pointer
+ * @reg: register offset
+ * @val: data read
+ *
+ * This funtion uses smbus byte read API to read a byte from the given offset.
+ **/
+static int tc35893_read_byte(struct i2c_client *client, unsigned char reg,
+ unsigned char *val)
+{
+ int ret;
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0)
+ dev_err(&client->dev, "Error in reading reg %x: error = %d\n",
+ reg, ret);
+ *val = ret;
+ return ret;
+}
+
+/**
+ * tc35893_read_info(struct tc_keypad *kp) - read the chip information
+ * @kp: keypad data structure pointer
+ *
+ * This function read tc35893 chip and version ID
+ * and returns error if chip id or version id is not correct.
+ * This function can be called to check if UIB is connected or not.
+ */
+static int tc35893_read_info(struct tc_keypad *kp)
+{
+ unsigned char manufacture_code, version_id;
+ int ret;
+
+ /* read the chip id and version id */
+ if ((!kp) || (!kp->client))
+ return -EIO;
+ /* TC35893 probe failed */
+ ret = tc35893_read_byte(kp->client, TC_MANUFACTURE_CODE,
+ &manufacture_code);
+ if (ret < 0)
+ return ret;
+
+ ret = tc35893_read_byte(kp->client, TC_VERSION_ID,
+ &version_id);
+ if (ret < 0)
+ return ret;
+
+ if ((manufacture_code != TC_MAN_CODE_VAL) ||
+ (version_id != TC_SW_VERSION)) {
+ dev_err(&kp->client->dev,
+ "Incorrect manufacture code:%x version id:%x\n"
+ , manufacture_code, version_id);
+ return -EIO;
+ } else {
+ dev_info(&kp->client->dev,
+ "manufacture code: %x, version id:%x\n",
+ manufacture_code, version_id);
+ }
+ return 0;
+}
+
+
+/**
+ * tc35893_kp_key_irqdis- disables keypad interrupt
+ *
+ * @kp: pointer to keypad data structure
+ *
+ * disables keypad interrupt
+ */
+static int tc35893_kp_key_irqdis(struct tc_keypad *kp)
+{
+ /* Disable KEYPAD interrupt of tc35893 */
+ int err;
+ unsigned char reg_val;
+
+ mutex_lock(&kp->lock);
+ err = tc35893_read_byte(kp->client, TC_KBDMSK, &reg_val);
+ if (err < 0)
+ goto error_out;
+ reg_val |= (TC_EVT_LOSS_INT | TC_EVT_INT);
+ err = tc35893_write_byte(kp->client, TC_KBDMSK, reg_val);
+error_out:
+ mutex_unlock(&kp->lock);
+ return err;
+}
+
+/**
+ * tc35893_kp_key_irqen- enables keypad interrupt
+ *
+ * @kp: pointer to keypad data structure
+ *
+ * enables keypad interrupt
+ */
+static int tc35893_kp_key_irqen(struct tc_keypad *kp)
+{
+ /* Enable KEYPAD interrupt of tc35893*/
+ int err;
+ unsigned char reg_val;
+
+ mutex_lock(&kp->lock);
+ err = tc35893_read_byte(kp->client, TC_KBDMSK, &reg_val);
+ if (err < 0)
+ goto error_out;
+ reg_val &= ~(TC_EVT_LOSS_INT | TC_EVT_INT);
+ err = tc35893_write_byte(kp->client, TC_KBDMSK, reg_val);
+error_out:
+ mutex_unlock(&kp->lock);
+ return err;
+}
+
+
+/**
+ * tc35893_kp_key_irqclear- clears all keypad interrupts
+ *
+ * @kp: pointer to keypad data structure
+ *
+ * clears keypad interrupt
+ */
+static int tc35893_kp_key_irqclear(struct tc_keypad *kp)
+{
+ /* Clear KEYPAD interrupt of tc35893 */
+ int err;
+
+ mutex_lock(&kp->lock);
+ err = tc35893_write_byte(kp->client, TC_KBDIC,
+ (TC_EVT_INT_CLR | TC_KBD_INT_CLR));
+ mutex_unlock(&kp->lock);
+ return err;
+}
+
+/**
+ * tc35893_kp_init_key_hardware - keypad hardware initialization
+ * @kp: keypad configuration for this platform
+ *
+ * Initializes the keypad hardware specific parameters.
+ * This function will be called by tc35893_keypad_init function during init
+ * Initialize keypad interrupt handler for interrupt mode operation if enabled
+ * Initialize Keyscan matrix
+ *
+ */
+static int tc35893_kp_init_key_hardware(struct tc_keypad *kp)
+{
+ int err;
+ unsigned char reg_val;
+
+ if (!kp || !kp->client || !kp->board)
+ return -EINVAL;
+ dev_dbg(&kp->client->dev, "tc35893_kp_init_key_hardware\n");
+
+ /*
+ * Check if tc35893 is initialised properly, otherwise exit from here
+ */
+ err = tc35893_read_info(kp);
+ if (err < 0) {
+ dev_err(&kp->client->dev,
+ "Error in keypad init, keypad controller not initialised.\n");
+ return err;
+ }
+
+ /*
+ * Checking configurations against max possible
+ * row, column and debounce value;
+ */
+ if ((kp->board->kcol > TC_MAX_KPCOL) || (kp->board->krow > TC_MAX_KPROW)
+ || (kp->board->debounce_period > TC_MAX_DEBOUNCE_SETTLE) ||
+ (kp->board->settle_time > TC_MAX_DEBOUNCE_SETTLE)) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&kp->lock);
+
+ /* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */
+ reg_val = ((kp->board->krow & 0xF) << KP_ROW_SHIFT) |
+ (kp->board->kcol & 0xF);
+ err = tc35893_write_byte(kp->client, TC_KBDSIZE, reg_val);
+ if (err < 0)
+ goto error_out;
+
+
+ /* configure dedicated key config, no dedicated key selected */
+ err = tc35893_write_byte(kp->client, TC_KBCFG_LSB, DEDICATED_KEY_VAL);
+ if (err < 0)
+ goto error_out;
+ err = tc35893_write_byte(kp->client, TC_KBCFG_MSB, DEDICATED_KEY_VAL);
+ if (err < 0)
+ goto error_out;
+
+ /* Configure settle time */
+ err = tc35893_write_byte(kp->client, TC_KBDSETTLE_REG,
+ kp->board->settle_time);
+ if (err < 0)
+ goto error_out;
+
+ /* Configure debounce time */
+ err = tc35893_write_byte(kp->client, TC_KBDBOUNCE,
+ kp->board->debounce_period);
+ if (err < 0)
+ goto error_out;
+
+
+ /* Start of initialise keypad GPIOs */
+ err = tc35893_read_byte(kp->client, TC_IOCFG, &reg_val);
+ if (err < 0)
+ goto error_out;
+ reg_val |= IOCFG_IG;
+ err = tc35893_write_byte(kp->client, TC_IOCFG, reg_val);
+ if (err < 0)
+ goto error_out;
+
+
+ /* Configure pull-up resistors for all row GPIOs */
+ err = tc35893_write_byte(kp->client, TC_IOPULLCFG0_LSB,
+ TC_PULLUP_ALL_MASK);
+ if (err < 0)
+ goto error_out;
+ err = tc35893_write_byte(kp->client, TC_IOPULLCFG0_MSB,
+ TC_PULLUP_ALL_MASK);
+ if (err < 0)
+ goto error_out;
+
+ /* Configure pull-up resistors for all column GPIOs */
+ err = tc35893_write_byte(kp->client, TC_IOPULLCFG1_LSB,
+ TC_PULLUP_ALL_MASK);
+ if (err < 0)
+ goto error_out;
+
+ err = tc35893_write_byte(kp->client, TC_IOPULLCFG1_MSB,
+ TC_PULLUP_ALL_MASK);
+ if (err < 0)
+ goto error_out;
+
+ err = tc35893_write_byte(kp->client, TC_IOPULLCFG2_LSB,
+ TC_PULLUP_ALL_MASK);
+
+error_out:
+ mutex_unlock(&kp->lock);
+ return err;
+}
+
+/**
+ * tc35893_keypressed - This function read keypad data registers
+ * @keys: output parameter, returns keys pressed.
+ * @kp: keypad data structure pointer
+ *
+ * This function can be used in both polling or interrupt mode.
+ */
+static int tc35893_keypressed(struct t_tc35893_key_status *keys,
+ struct tc_keypad *kp)
+{
+ int retval;
+
+ if (!keys || !kp || !kp->client)
+ return -EINVAL;
+
+ keys->nb_events = 0;
+
+ do {
+ retval = tc35893_read_byte(kp->client, TC_EVTCODE_FIFO,
+ &keys->event_buf[keys->nb_events]);
+ if (retval < 0)
+ return retval;
+ dev_dbg(&kp->client->dev, "Key[%d] = %x \n", keys->nb_events,
+ keys->event_buf[keys->nb_events]);
+ keys->nb_events++;
+
+ } while (((keys->event_buf[keys->nb_events-1] & KP_NO_VALID_KEY_MASK) !=
+ KP_NO_VALID_KEY_MASK) && (keys->nb_events < EVT_BUF_SIZE));
+
+
+ if (keys->nb_events < EVT_BUF_SIZE)
+ keys->nb_events--;
+ /* discard the last read with no valid key code */
+
+ return retval;
+}
+
+
+/**
+ * tc35893_kp_results_autoscan : This function gets scanned key code
+ * @kp: keypad data pointer
+ *
+ * This function can be used in both polling or interrupt mode.
+ */
+static int tc35893_kp_results_autoscan(struct tc_keypad *kp)
+{
+ int err;
+ struct t_tc35893_key_status keys;
+ u8 kcode, i, row_index, col_index;
+
+ /* read key data from tc35893 */
+ err = tc35893_keypressed(&keys, kp);
+ if (err < 0) {
+ dev_err(&kp->client->dev, "Error in keycode scanning\n");
+ return err;
+ }
+
+ if (!keys.nb_events)
+ return kp->keyp_cnt;
+
+ /* Report any new event to input subsystem */
+ for (i = 0; i < keys.nb_events; i++) {
+ col_index = (keys.event_buf[i] & KP_EVCODE_COL_MASK);
+ row_index = (keys.event_buf[i] & KP_EVCODE_ROW_MASK)
+ >> KP_ROW_SHIFT;
+ kcode = kp->board->kcode_tbl
+ [(row_index * TC_KPD_COLUMNS) + col_index];
+
+ if (kcode == KEY_RESERVED) {
+ dev_err(&kp->client->dev,
+ "Error in key detection. Key not present\n");
+ continue;
+ }
+
+ if (keys.event_buf[i] & KP_RELEASE_EVT_MASK) {
+ input_report_key(kp->inp_dev, kcode, 0);
+ dev_dbg(&kp->client->dev,
+ "key (%d, %d)-->UP, kcode = %x\n",
+ row_index, col_index, kcode);
+ kp->keyp_cnt--;
+ } else {
+ input_report_key(kp->inp_dev, kcode, 1);
+ dev_dbg(&kp->client->dev,
+ "key (%d, %d)-->DOWN, kcode = %x\n",
+ row_index, col_index, kcode);
+ kp->keyp_cnt++;
+ }
+ }
+
+ return kp->keyp_cnt;
+}
+
+
+/**
+ * tc35893_kp_wq_kscan - work queue for keypad scanning
+ * @work: pointer to keypad data
+ *
+ * Executes at each scan tick, execute the key press/release function,
+ * Generates key press/release event message for input subsystem for valid key
+ * events, enables keypad interrupts (for int mode)
+ */
+static void tc35893_kp_wq_kscan(struct work_struct *work)
+{
+ int key_cnt;
+ struct tc_keypad *kp;
+
+ kp = container_of((struct delayed_work *)work,
+ struct tc_keypad, kscan_work);
+ if (!kp->board->op_mode)
+ tc35893_kp_key_irqdis(kp);
+ /* Get the key scan codes */
+ key_cnt = tc35893_kp_results_autoscan(kp);
+
+ if (kp->board->op_mode) {
+ if (0 == key_cnt) {
+ /*if no key is pressed and polling mode */
+ schedule_delayed_work(&kp->kscan_work,
+ TC_KEYPAD_SCAN_PERIOD);
+ } else {
+ /*if key is pressed and hold condition */
+ dev_dbg(&kp->client->dev,
+ "Work queue: pressed and hold\n");
+ schedule_delayed_work(&kp->kscan_work,
+ TC_KEYPAD_RELEASE_PERIOD);
+ }
+ } else {
+ /* if interrupt mode then just enable iterrupt and return */
+ clear_bit(KPINTR_LKBIT, &kp->lockbits);
+ tc35893_kp_key_irqclear(kp);
+ tc35893_kp_key_irqen(kp);
+ }
+}
+
+/**
+ * tc35893_kp_init_keypad - keypad parameter initialization
+ * @kp: pointer to keypad data
+ *
+ * Initializes Keybits to enable keyevents
+ * Initializes Initial keypress status to default
+ * Calls the keypad platform specific init function.
+ */
+static int tc35893_kp_init_keypad(struct tc_keypad *kp)
+{
+ int row, column, err;
+ u8 *p_kcode = kp->board->kcode_tbl;
+
+ err = tc35893_kp_init_key_hardware(kp);
+ if (err < 0)
+ return err;
+
+ for (row = 0; row < TC_KPD_ROWS; row++) {
+ for (column = 0; column < TC_KPD_ROWS; column++) {
+ /*set keybits for the keycodes in use */
+ set_bit(*p_kcode, kp->inp_dev->keybit);
+ p_kcode++;
+ }
+ }
+ return err;
+}
+
+#ifdef CONFIG_PM
+/**
+ * tc35893_kp_suspend - suspend keypad
+ * @client: i2c client pointer
+ * @state: power down level
+ */
+static int tc35893_kp_suspend(struct i2c_client *client, pm_message_t state)
+{
+ struct tc35893_platform_data *board;
+ struct tc_keypad *kp;
+
+ if (!client)
+ return -EINVAL;
+
+ board = client->dev.platform_data;
+ kp = i2c_get_clientdata(client);
+ if (!board || !kp)
+ return -EINVAL;
+
+ if (board->op_mode) {
+ dev_dbg(&client->dev, "Enabling interrupt \n");
+ tc35893_kp_key_irqen(kp);
+ }
+
+ if (!device_may_wakeup(&client->dev)) {
+ dev_dbg(&client->dev, "Disabling interrupt\n");
+ tc35893_kp_key_irqdis(kp);
+ }
+ return 0;
+}
+
+/**
+ * tc35893_kp_resume - resumes keypad
+ * @client: i2c client data
+ */
+
+static int tc35893_kp_resume(struct i2c_client *client)
+{
+ struct tc35893_platform_data *board;
+ struct tc_keypad *kp;
+
+ if (!client)
+ return -EINVAL;
+
+ board = client->dev.platform_data;
+ kp = i2c_get_clientdata(client);
+ if (!board || !kp)
+ return -EINVAL;
+
+ if (board->op_mode) {
+ dev_dbg(&client->dev, "Disabling interrupt\n");
+ tc35893_kp_key_irqdis(kp);
+ }
+
+ if (!device_may_wakeup(&client->dev)) {
+ dev_dbg(&client->dev, "Enabling interrupt\n");
+ tc35893_kp_key_irqen(kp);
+ }
+ return 0;
+}
+
+#else
+#define tc35893_kp_suspend NULL
+#define tc35893_kp_resume NULL
+#endif /* CONFIG_PM */
+
+
+/* tc35893 keypad controller functions */
+
+/**
+ * tc35893_kp_irh - keypad interrupt handler
+ * @irq: interrupt no.
+ * @dev : keypad data structure pointer
+ * checks for valid interrupt, disables interrupt to avoid any nested interrupt
+ * starts work queue for further key processing with debouncing logic
+ */
+static irqreturn_t tc35893_kp_irh(int irq, void *dev)
+{
+ struct tc_keypad *kp = (struct tc_keypad *)dev;
+
+ /*
+ * prefer BUG_ON instead of just returning IRQ_NONE
+ * otherwise spurious interrupt will keep on coming.
+ */
+ BUG_ON(!kp || !kp->board || !kp->client);
+
+ dev_dbg(&kp->client->dev, "Kp interrupt\n");
+
+ if (irq != kp->board->irq)
+ return IRQ_NONE;
+
+ if (!(test_bit(KPINTR_LKBIT, &kp->lockbits))) {
+ set_bit(KPINTR_LKBIT, &kp->lockbits);
+
+ /* tc35893_kp_key_irqdis(kp); */
+ schedule_delayed_work(&kp->kscan_work, 0);
+ }
+ return IRQ_HANDLED;
+}
+
+
+
+/**
+ * tc35893_kp_probe - keypad module probe function
+ * @client: i2c client data pointer
+ * @id: i2c device id pointer
+ *
+ * Allocates data memory, registers the module with input subsystem,
+ * initializes keypad default condition, initializes keypad interrupt handler
+ * for interrupt mode operation, initializes keypad work queues functions for
+ * polling mode operation
+ */
+static int __init tc35893_kp_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tc_keypad *kp;
+ int err;
+ unsigned char manufacture_code, version_id, reg_val;
+ struct tc35893_platform_data *keypad_board;
+
+ if (!client || !id)
+ return -EINVAL;
+
+ keypad_board = client->dev.platform_data;
+ if (!keypad_board) {
+ dev_err(&client->dev, "keypad platform data not defined\n");
+ err = -EINVAL;
+ goto err_kzalloc;
+ }
+
+ /* Allocate keypad data structure */
+ kp = kzalloc(sizeof(struct tc_keypad), GFP_KERNEL);
+ if (!kp) {
+ err = -ENOMEM;
+ goto err_kzalloc;
+ }
+ kp->client = client;
+ if (!keypad_board->irq) {
+ dev_err(&client->dev, "keypad irq not defined\n");
+ err = -EINVAL;
+ goto err_board;
+ }
+ kp->board = keypad_board;
+
+ /* Allocate and initialise input device */
+ kp->inp_dev = input_allocate_device();
+ if (!kp->inp_dev) {
+ dev_err(&client->dev,
+ "Could not allocate memory for the device\n");
+ err = -ENOMEM;
+ goto err_board;
+ }
+
+ kp->inp_dev->evbit[0] = BIT(EV_KEY);
+ kp->inp_dev->name = client->name;
+ kp->inp_dev->phys = "stkpd/input0";
+
+ kp->inp_dev->id.product = TC_KEYPAD_VER_MAJOR;
+ kp->inp_dev->id.version = TC_KEYPAD_VER_MINOR * 0x0ff +
+ TC_KEYPAD_VER_RELEASE;
+
+ mutex_init(&kp->lock);
+
+ clear_bit(KPINTR_LKBIT, &kp->lockbits);
+ i2c_set_clientdata(client, kp);
+
+
+ /* Reset and initialise TC keypad controller */
+ /* issue soft reset for all the modules */
+ err = tc35893_write_byte(client, TC_RSTCTRL, TC_RESET_ALL);
+ if (err < 0)
+ return err;
+
+ err = tc35893_read_byte(client, TC_RSTCTRL, &reg_val);
+ if (err < 0)
+ return err;
+
+ reg_val &= ~(TC_KBDRST | TC_IRQRST);
+ /* take keyboard and IRQ out of reset*/
+ err = tc35893_write_byte(client, TC_RSTCTRL, reg_val);
+ if (err < 0)
+ return err;
+
+ /*configure the KBDMFS*/
+ err = tc35893_write_byte(client, TC_KBDMFS, TC_KBDMFS_EN);
+ if (err < 0)
+ return err;
+
+ err = tc35893_read_byte(client, TC_MANUFACTURE_CODE, &manufacture_code);
+ if (err < 0)
+ return err;
+ err = tc35893_read_byte(client, TC_VERSION_ID, &version_id);
+ if (err < 0)
+ return err;
+
+ /* Now configure clock */
+ err = tc35893_write_byte(client, TC_CLKEN, KPD_CLK_EN);
+ if (err < 0)
+ return err;
+
+ err = tc35893_read_byte(client, TC_CLKEN, &reg_val);
+ if (err < 0)
+ return err;
+
+ dev_info(&client->dev, "chip id: %x, version id:%x \n",
+ manufacture_code, version_id);
+
+ err = tc35893_write_byte(client, TC_RSTINTCLR, IRQ_CLEAR);
+ if (err < 0)
+ return err;
+
+ /* End of --- Reset and initialise TC keypad controller */
+
+ err = tc35893_kp_init_keypad(kp);
+ if (err < 0)
+ goto err_init_kpd;
+
+ if (input_register_device(kp->inp_dev) < 0) {
+ dev_err(&client->dev, "Could not register input device\n");
+ err = -1;
+ goto err_init_kpd;
+ } else {
+ dev_dbg(&client->dev,
+ "Registered keypad module with input subsystem\n");
+ }
+
+ /* Initialize keypad workques */
+ INIT_DELAYED_WORK(&kp->kscan_work, tc35893_kp_wq_kscan);
+
+ /* Enable wakeup from keypad */
+ device_init_wakeup(&client->dev, kp->board->enable_wakeup);
+ device_set_wakeup_capable(&client->dev, kp->board->enable_wakeup);
+
+ /* Initialize keypad interrupt handler */
+ if (!kp->board->op_mode) { /* true if interrupt mode operation */
+
+ err = request_irq(kp->board->irq, tc35893_kp_irh,
+ kp->board->irqtype, kp->inp_dev->name, kp);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Could not allocate irq %d,error %d\n",
+ kp->board->irq, err);
+ goto err_inp_reg;
+ }
+ tc35893_kp_key_irqen(kp);
+
+ } else {
+ /* Schedule workqueue for polling mode operaion. */
+ schedule_delayed_work(&kp->kscan_work, TC_KEYPAD_SCAN_PERIOD);
+ dev_info(&client->dev, "Keypad polling started\n");
+ }
+
+ dev_info(&client->dev, "Module initialized Ver(%d.%d.%d)\n",
+ TC_KEYPAD_VER_MAJOR, TC_KEYPAD_VER_MINOR,
+ TC_KEYPAD_VER_RELEASE);
+ return 0;
+
+err_inp_reg:
+ /* unregistering device */
+ input_unregister_device(kp->inp_dev);
+err_init_kpd:
+ input_free_device(kp->inp_dev);
+err_board:
+ kfree(kp);
+err_kzalloc:
+ return err;
+}
+
+/**
+ * tc35893_kp_remove - keypad module remove function
+ *
+ * @client: i2c client pointer
+ *
+ * Disables Keypad interrupt if any, frees allocated keypad interrupt if any,
+ * cancels keypad work queues if any, deallocate used GPIO pin, unregisters the
+ * module, frees used memory
+ */
+static int __exit tc35893_kp_remove(struct i2c_client *client)
+{
+ struct tc35893_platform_data *board;
+ struct tc_keypad *kp;
+
+ if (!client)
+ return -EINVAL;
+
+ board = client->dev.platform_data;
+ kp = i2c_get_clientdata(client);
+ if (!board || !kp)
+ return -EINVAL;
+
+ /* disable all interrupts */
+ tc35893_kp_key_irqdis(kp);
+
+ /* cancel and flush keypad work queues if any */
+ cancel_delayed_work(&kp->kscan_work);
+ cancel_delayed_work_sync(&kp->kscan_work);
+ /* block until work struct's callback terminates */
+ input_unregister_device(kp->inp_dev);
+ free_irq(kp->board->irq, kp);
+ i2c_set_clientdata(client, NULL);
+ input_free_device(kp->inp_dev);
+ kfree(kp);
+ return 0;
+}
+
+static const struct i2c_device_id tc35893_id[] = {
+ { "tc35893-kp", 23 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tc35893_id);
+
+
+static struct i2c_driver tc35893kpd_driver = {
+ .driver = {
+ .name = "tc35893-kp",
+ .owner = THIS_MODULE,
+ },
+ .probe = tc35893_kp_probe,
+ .remove = __exit_p(tc35893_kp_remove),
+ .suspend = tc35893_kp_suspend,
+ .resume = tc35893_kp_resume,
+ .id_table = tc35893_id,
+};
+
+static int __init tc35893_kp_init(void)
+{
+ return i2c_add_driver(&tc35893kpd_driver);
+}
+
+static void __exit tc35893_kp_exit(void)
+{
+ return i2c_del_driver(&tc35893kpd_driver);
+}
+
+module_init(tc35893_kp_init);
+module_exit(tc35893_kp_exit);
+
+MODULE_AUTHOR("jayeeta banerjee");
+MODULE_DESCRIPTION("tc35893 keyboard driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 7861016b621..3c5a7bdb0b9 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -22,6 +22,16 @@ config INPUT_88PM860X_ONKEY
To compile this driver as a module, choose M here: the module
will be called 88pm860x_onkey.
+config INPUT_AB8500_PONKEY
+ tristate "AB8500 Pon (PowerOn) Key"
+ depends on AB8500_CORE
+ help
+ Say Y here to use the PowerOn Key for ST-Ericsson's AB8500
+ Mix-Sig PMIC.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ab8500-ponkey.
+
config INPUT_AD714X
tristate "Analog Devices AD714x Capacitance Touch Sensor"
help
@@ -406,4 +416,14 @@ config INPUT_PCAP
To compile this driver as a module, choose M here: the
module will be called pcap_keys.
+config INPUT_STE_FF_VIBRA
+ tristate "ST-Ericsson Force Feedback Vibrator"
+ depends on STE_AUDIO_IO_DEV
+ select INPUT_FF_MEMLESS
+ help
+ This option enables support for ST-Ericsson's Vibrator which
+ registers as an input force feedback driver.
+
+ To compile this driver as a module, choose M here. The module will
+ be called ste_ff_vibra.
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index d234834f5b8..6005dd72d0a 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -5,6 +5,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
+obj-$(CONFIG_INPUT_AB8500_PONKEY) += ab8500-ponkey.o
obj-$(CONFIG_INPUT_AD714X) += ad714x.o
obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o
obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o
@@ -39,4 +40,4 @@ obj-$(CONFIG_INPUT_WINBOND_CIR) += winbond-cir.o
obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
-
+obj-$(CONFIG_INPUT_STE_FF_VIBRA) += ste_ff_vibra.o
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c
new file mode 100644
index 00000000000..35b2998c727
--- /dev/null
+++ b/drivers/input/misc/ab8500-ponkey.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ * AB8500 Power-On Key handler
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/slab.h>
+
+/**
+ * struct ab8500_ponkey_info - ab8500 ponkey information
+ * @input_dev: pointer to input device
+ * @ab8500: ab8500 parent
+ * @irq_dbf: irq number for falling transition
+ * @irq_dbr: irq number for rising transition
+ */
+struct ab8500_ponkey_info {
+ struct input_dev *idev;
+ struct ab8500 *ab8500;
+ int irq_dbf;
+ int irq_dbr;
+};
+
+/* AB8500 gives us an interrupt when ONKEY is held */
+static irqreturn_t ab8500_ponkey_handler(int irq, void *data)
+{
+ struct ab8500_ponkey_info *info = data;
+
+ if (irq == info->irq_dbf)
+ input_report_key(info->idev, KEY_POWER, true);
+ else if (irq == info->irq_dbr)
+ input_report_key(info->idev, KEY_POWER, false);
+
+ input_sync(info->idev);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit ab8500_ponkey_probe(struct platform_device *pdev)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+ struct ab8500_ponkey_info *info;
+ int irq_dbf, irq_dbr, ret;
+
+ irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF");
+ if (irq_dbf < 0) {
+ dev_err(&pdev->dev, "No IRQ for ONKEY_DBF,error=%d\n", irq_dbf);
+ return irq_dbf;
+ }
+
+ irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR");
+ if (irq_dbr < 0) {
+ dev_err(&pdev->dev, "No IRQ for ONKEY_DBR,error=%d\n", irq_dbr);
+ return irq_dbr;
+ }
+
+ info = kzalloc(sizeof(struct ab8500_ponkey_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->ab8500 = ab8500;
+ info->irq_dbf = irq_dbf;
+ info->irq_dbr = irq_dbr;
+
+ info->idev = input_allocate_device();
+ if (!info->idev) {
+ dev_err(ab8500->dev, "Failed to allocate input dev\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ info->idev->name = "AB8500 POn(PowerOn) Key";
+ info->idev->dev.parent = &pdev->dev;
+ info->idev->evbit[0] = BIT_MASK(EV_KEY);
+ info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+
+ ret = input_register_device(info->idev);
+ if (ret) {
+ dev_err(ab8500->dev, "Can't register input device: %d\n", ret);
+ goto out_unfreedevice;
+ }
+
+ ret = request_threaded_irq(info->irq_dbf, NULL, ab8500_ponkey_handler,
+ 0, "ab8500-ponkey-dbf", info);
+ if (ret < 0) {
+ dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",
+ info->irq_dbf, ret);
+ goto out_unregisterdevice;
+ }
+
+ ret = request_threaded_irq(info->irq_dbr, NULL, ab8500_ponkey_handler,
+ 0, "ab8500-ponkey-dbr", info);
+ if (ret < 0) {
+ dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",
+ info->irq_dbr, ret);
+ goto out_irq_dbf;
+ }
+
+ platform_set_drvdata(pdev, info);
+
+ return 0;
+
+out_irq_dbf:
+ free_irq(info->irq_dbf, info);
+out_unregisterdevice:
+ input_unregister_device(info->idev);
+ info->idev = NULL;
+out_unfreedevice:
+ input_free_device(info->idev);
+out:
+ kfree(info);
+ return ret;
+}
+
+static int __devexit ab8500_ponkey_remove(struct platform_device *pdev)
+{
+ struct ab8500_ponkey_info *info = platform_get_drvdata(pdev);
+
+ free_irq(info->irq_dbf, info);
+ free_irq(info->irq_dbr, info);
+ input_unregister_device(info->idev);
+ kfree(info);
+ return 0;
+}
+
+static struct platform_driver ab8500_ponkey_driver = {
+ .driver = {
+ .name = "ab8500-poweron-key",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_ponkey_probe,
+ .remove = __devexit_p(ab8500_ponkey_remove),
+};
+
+static int __init ab8500_ponkey_init(void)
+{
+ return platform_driver_register(&ab8500_ponkey_driver);
+}
+module_init(ab8500_ponkey_init);
+
+static void __exit ab8500_ponkey_exit(void)
+{
+ platform_driver_unregister(&ab8500_ponkey_driver);
+}
+module_exit(ab8500_ponkey_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("ST-Ericsson AB8500 Power-ON(Pon) Key driver");
diff --git a/drivers/input/misc/ste_ff_vibra.c b/drivers/input/misc/ste_ff_vibra.c
new file mode 100644
index 00000000000..9038e6be046
--- /dev/null
+++ b/drivers/input/misc/ste_ff_vibra.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Marcin Mielczarczyk <marcin.mielczarczyk@tieto.com>
+ * for ST-Ericsson
+ * License Terms: GNU General Public License v2
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <mach/ste_audio_io_vibrator.h>
+
+#define FF_VIBRA_DOWN 0x0000 /* 0 degrees */
+#define FF_VIBRA_LEFT 0x4000 /* 90 degrees */
+#define FF_VIBRA_UP 0x8000 /* 180 degrees */
+#define FF_VIBRA_RIGHT 0xC000 /* 270 degrees */
+
+/**
+ * struct vibra_info - Vibrator information structure
+ * @idev: Pointer to input device structure
+ * @vibra_workqueue: Pointer to vibrator workqueue structure
+ * @vibra_work: Vibrator work
+ * @direction: Vibration direction
+ * @speed: Vibration speed
+ *
+ * Structure vibra_info holds vibrator informations
+ **/
+struct vibra_info {
+ struct input_dev *idev;
+ struct workqueue_struct *vibra_workqueue;
+ struct work_struct vibra_work;
+ int direction;
+ unsigned char speed;
+};
+
+/**
+ * vibra_play_work() - Vibrator work, sets speed and direction
+ * @work: Pointer to work structure
+ *
+ * This function is called from workqueue, turns on/off vibrator
+ **/
+static void vibra_play_work(struct work_struct *work)
+{
+ struct vibra_info *vinfo = container_of(work,
+ struct vibra_info, vibra_work);
+ struct ste_vibra_speed left_speed = {
+ .positive = 0,
+ .negative = 0,
+ };
+ struct ste_vibra_speed right_speed = {
+ .positive = 0,
+ .negative = 0,
+ };
+
+ /* Divide by 2 because supported range by PWM is 0-100 */
+ vinfo->speed /= 2;
+
+ if ((vinfo->direction > FF_VIBRA_DOWN) &&
+ (vinfo->direction < FF_VIBRA_UP)) {
+ /* 1 - 179 degrees, turn on left vibrator */
+ left_speed.positive = vinfo->speed;
+ } else if (vinfo->direction > FF_VIBRA_UP) {
+ /* more than 180 degrees, turn on right vibrator */
+ right_speed.positive = vinfo->speed;
+ } else {
+ /* 0 (down) or 180 (up) degrees, turn on 2 vibrators */
+ left_speed.positive = vinfo->speed;
+ right_speed.positive = vinfo->speed;
+ }
+
+ ste_audioio_vibrator_pwm_control(STE_AUDIOIO_CLIENT_FF_VIBRA,
+ left_speed, right_speed);
+}
+
+/**
+ * vibra_play() - Memless device control function
+ * @idev: Pointer to input device structure
+ * @data: Pointer to private data (not used)
+ * @effect: Pointer to force feedback effect structure
+ *
+ * This function controls memless device
+ *
+ * Returns:
+ * 0 - success
+ **/
+static int vibra_play(struct input_dev *idev, void *data,
+ struct ff_effect *effect)
+{
+ struct vibra_info *vinfo = input_get_drvdata(idev);
+
+ vinfo->direction = effect->direction;
+ vinfo->speed = effect->u.rumble.strong_magnitude >> 8;
+ if (!vinfo->speed)
+ /* Shift weak magnitude to make it feelable on vibrator */
+ vinfo->speed = effect->u.rumble.weak_magnitude >> 9;
+
+ queue_work(vinfo->vibra_workqueue, &vinfo->vibra_work);
+
+ return 0;
+}
+
+/**
+ * ste_ff_vibra_open() - Input device open function
+ * @idev: Pointer to input device structure
+ *
+ * This function is called on opening input device
+ *
+ * Returns:
+ * -ENOMEM - no memory left
+ * 0 - success
+ **/
+static int ste_ff_vibra_open(struct input_dev *idev)
+{
+ struct vibra_info *vinfo = input_get_drvdata(idev);
+
+ vinfo->vibra_workqueue =
+ create_singlethread_workqueue("ste_ff-ff-vibra");
+ if (!vinfo->vibra_workqueue) {
+ dev_err(&idev->dev, "couldn't create vibra workqueue\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/**
+ * ste_ff_vibra_close() - Input device close function
+ * @idev: Pointer to input device structure
+ *
+ * This function is called on closing input device
+ **/
+static void ste_ff_vibra_close(struct input_dev *idev)
+{
+ struct vibra_info *vinfo = input_get_drvdata(idev);
+
+ cancel_work_sync(&vinfo->vibra_work);
+ INIT_WORK(&vinfo->vibra_work, vibra_play_work);
+ destroy_workqueue(vinfo->vibra_workqueue);
+ vinfo->vibra_workqueue = NULL;
+}
+
+static int __devinit ste_ff_vibra_probe(struct platform_device *pdev)
+{
+ struct vibra_info *vinfo;
+ int ret;
+
+ vinfo = kmalloc(sizeof *vinfo, GFP_KERNEL);
+ if (!vinfo) {
+ dev_err(&pdev->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ vinfo->idev = input_allocate_device();
+ if (!vinfo->idev) {
+ dev_err(&pdev->dev, "failed to allocate input device\n");
+ ret = -ENOMEM;
+ goto exit_vinfo_free;
+ }
+
+ vinfo->idev->name = "ste-ff-vibra";
+ vinfo->idev->dev.parent = pdev->dev.parent;
+ vinfo->idev->open = ste_ff_vibra_open;
+ vinfo->idev->close = ste_ff_vibra_close;
+ INIT_WORK(&vinfo->vibra_work, vibra_play_work);
+ __set_bit(FF_RUMBLE, vinfo->idev->ffbit);
+
+ ret = input_ff_create_memless(vinfo->idev, NULL, vibra_play);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to create memless device\n");
+ goto exit_idev_free;
+ }
+
+ ret = input_register_device(vinfo->idev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register input device\n");
+ goto exit_destroy_memless;
+ }
+
+ input_set_drvdata(vinfo->idev, vinfo);
+ platform_set_drvdata(pdev, vinfo);
+ return 0;
+
+exit_destroy_memless:
+ input_ff_destroy(vinfo->idev);
+exit_idev_free:
+ input_free_device(vinfo->idev);
+exit_vinfo_free:
+ kfree(vinfo);
+ return ret;
+}
+
+static int __devexit ste_ff_vibra_remove(struct platform_device *pdev)
+{
+ struct vibra_info *vinfo = platform_get_drvdata(pdev);
+
+ /*
+ * Function device_release() will call input_dev_release()
+ * which will free ff and input device. No need to call
+ * input_ff_destroy() and input_free_device() explicitly.
+ */
+ input_unregister_device(vinfo->idev);
+ kfree(vinfo);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ste_ff_vibra_driver = {
+ .driver = {
+ .name = "ste_ff_vibra",
+ .owner = THIS_MODULE,
+ },
+ .probe = ste_ff_vibra_probe,
+ .remove = __devexit_p(ste_ff_vibra_remove)
+};
+
+static int __init ste_ff_vibra_init(void)
+{
+ return platform_driver_register(&ste_ff_vibra_driver);
+}
+module_init(ste_ff_vibra_init);
+
+static void __exit ste_ff_vibra_exit(void)
+{
+ platform_driver_unregister(&ste_ff_vibra_driver);
+}
+module_exit(ste_ff_vibra_exit);
+
+MODULE_AUTHOR("Marcin Mielczarczyk <marcin.mielczarczyk@tieto.com>");
+MODULE_DESCRIPTION("STE Force Feedback Vibrator Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index c4e276a5660..39470dbbd9b 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -99,6 +99,28 @@ config TOUCHSCREEN_BITSY
To compile this driver as a module, choose M here: the
module will be called h3600_ts_input.
+config TOUCHSCREEN_BU21013
+ tristate "BU21013 based touch panel controllers"
+ depends on I2C
+ default y
+ help
+ Say Y here if you have a bu21013 touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bu21013_ts.
+
+config BU21013_TSC_CNTL1
+ bool "Touch panel1 with BU21013 controller"
+ depends on TOUCHSCREEN_BU21013
+ default y
+
+config BU21013_TSC_CNTL2
+ bool "Touch panel2 with BU21013 controller2"
+ depends on TOUCHSCREEN_BU21013
+
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X
@@ -609,4 +631,14 @@ config TOUCHSCREEN_TPS6507X
To compile this driver as a module, choose M here: the
module will be called tps6507x_ts.
+config TOUCHSCREEN_SYNAPTICS_I2C_RMI4
+ tristate "Synaptics i2c rmi4 touchscreen"
+ depends on I2C_NOMADIK
+ help
+ Say Y here if you have a Synaptics RMI4 and
+ want to enable support for the built-in touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called synaptics_rmi4.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 055952218cd..c352c3a6cac 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
@@ -48,3 +49,5 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
+synaptics_rmi4_ts-y := synaptics_i2c_rmi4.o synaptics_rmi4_touchpad.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_rmi4_ts.o
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c
new file mode 100644
index 00000000000..da9cd0ad15f
--- /dev/null
+++ b/drivers/input/touchscreen/bu21013_ts.c
@@ -0,0 +1,980 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * License terms:GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/input/bu21013.h>
+#include <linux/slab.h>
+
+#define PEN_DOWN_INTR 0
+#define PEN_UP_INTR 1
+#define RESET_DELAY 30
+#define POLLING_DELAY 100
+#define MAX_TOOL_WIDTH 15
+#define MAX_TOUCH_MAJOR 255
+#define MAX_TOUCH_MINOR 15
+#define MAX_PRESSURE 1
+#define PENUP_TIMEOUT (2)
+#define SCALE_FACTOR 1000
+#define DELTA_MIN 16
+#define MASK_BITS 0x03
+#define SHIFT_8 8
+#define SHIFT_2 2
+#define LENGTH_OF_BUFFER 11
+
+#define DRIVER_TP "bu21013_tp"
+
+/**
+ * struct bu21013_ts_data - touch panel data structure
+ * @client: pointer to the i2c client
+ * @chip: pointer to the touch panel controller
+ * @in_dev: pointer to the input device structure
+ * @penirq_timer: variable to the timer list structure
+ * @timer_handler: variable to work structure for timer
+ * @gpio_handler: variable to work structure for gpio interrupt
+ * @board_flag: variable to indicate the href v1 board
+ * @intr_pin: interrupt pin value
+ * @x_pos: x position for two co-ordinates
+ * @y_pos: y position for two co-ordinates
+ * @factor_x: x scale factor
+ * @factor_y: y scale factor
+ * @previous_press_reported: last reported flag
+ * @touchp_kobj: pointer to kernel object for touch panel
+ * @penup_timer: timeout value
+ *
+ * Touch panel data structure
+ */
+struct bu21013_ts_data {
+ struct i2c_client *client;
+ struct bu21013_platform_device *chip;
+ struct input_dev *in_dev;
+ struct timer_list penirq_timer;
+ struct work_struct timer_wq_handler;
+ struct work_struct gpio_wq_handler;
+ unsigned int intr_pin;
+ signed short x_pos[2];
+ signed short y_pos[2];
+ int factor_x;
+ int factor_y;
+ bool previous_press_reported;
+ struct kobject *touchp_kobj;
+ int penup_timer;
+};
+
+/* Global variable to maintain the sys data for two controllers */
+struct bu21013_ts_data *tp1_sys_data, *tp2_sys_data;
+
+static int bu21013_init_chip(struct bu21013_ts_data *data);
+
+/*
+ * sysfs is used to change the touchpanel1 parameters
+ * and also enable the external clock dynamically
+ */
+static ssize_t touchp1_attr_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ u8 timeout;
+ u8 sys_ext_clock;
+
+ if (strcmp(attr->name, "timeout_value") == 0) {
+ timeout = tp1_sys_data->penup_timer;
+ sprintf(buf, "%d\n", timeout);
+ } else if (strcmp(attr->name, "ext_clk") == 0) {
+ sys_ext_clock = tp1_sys_data->chip->ext_clk;
+ sprintf(buf, "%d\n", sys_ext_clock);
+ }
+ return strlen(buf);
+}
+static ssize_t touchp1_attr_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t len)
+{
+ int ret = 0;
+ int timeout;
+ int sys_ext_clock;
+
+ if (strcmp(attr->name, "timeout_value") == 0) {
+ ret = sscanf(buf, "%d", &timeout);
+ if (ret == 1)
+ tp1_sys_data->penup_timer = timeout;
+ } else if (strcmp(attr->name, "ext_clk") == 0) {
+ ret = sscanf(buf, "%d", &sys_ext_clock);
+ if ((ret == 1) &&
+ (tp1_sys_data->chip->ext_clk != sys_ext_clock)) {
+ tp1_sys_data->chip->ext_clk = sys_ext_clock;
+ bu21013_init_chip(tp1_sys_data);
+ }
+ }
+ return ret == 1 ? len : -EINVAL;
+}
+
+/*
+ * sysfs is used to change the touchpanel2 parameters
+ * and also enable the external clock dynamically
+ */
+static ssize_t touchp2_attr_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ u8 timeout;
+ u8 sys_ext_clock;
+
+ if (strcmp(attr->name, "timeout_value") == 0) {
+ timeout = tp2_sys_data->penup_timer;
+ sprintf(buf, "%d\n", timeout);
+ } else if (strcmp(attr->name, "ext_clk") == 0) {
+ sys_ext_clock = tp2_sys_data->chip->ext_clk;
+ sprintf(buf, "%d\n", sys_ext_clock);
+ }
+ return strlen(buf);
+}
+static ssize_t touchp2_attr_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t len)
+{
+ int ret = 0;
+ int timeout;
+ int sys_ext_clock;
+
+ if (strcmp(attr->name, "timeout_value") == 0) {
+ ret = sscanf(buf, "%d", &timeout);
+ if (ret == 1)
+ tp2_sys_data->penup_timer = timeout;
+ } else if (strcmp(attr->name, "ext_clk") == 0) {
+ ret = sscanf(buf, "%d", &sys_ext_clock);
+ if ((ret == 1) &&
+ (tp2_sys_data->chip->ext_clk != sys_ext_clock)) {
+ tp2_sys_data->chip->ext_clk = sys_ext_clock;
+ bu21013_init_chip(tp2_sys_data);
+ }
+ }
+ return ret == 1 ? len : -EINVAL;
+}
+
+
+static struct attribute touchp_timeout = {.name = "timeout_value",
+ .mode = 0666};
+static struct attribute touchp_ext_clk = {.name = "ext_clk", .mode = 0666};
+
+static struct attribute *touchp_attribute[] = {
+ &touchp_timeout,
+ &touchp_ext_clk,
+ NULL
+};
+
+static const struct sysfs_ops touchp1_sysfs_ops = {
+ .show = touchp1_attr_show,
+ .store = touchp1_attr_store,
+};
+
+static const struct sysfs_ops touchp2_sysfs_ops = {
+ .show = touchp2_attr_show,
+ .store = touchp2_attr_store,
+};
+
+static struct kobj_type ktype_touchp1 = {
+ .sysfs_ops = &touchp1_sysfs_ops,
+ .default_attrs = touchp_attribute,
+};
+static struct kobj_type ktype_touchp2 = {
+ .sysfs_ops = &touchp2_sysfs_ops,
+ .default_attrs = touchp_attribute,
+};
+
+/*
+ * bu21013_get_number_of_bits() - count the bits in given value
+ * @val: read bits from this value
+ * @range: maximum number of bits
+ *
+ * Read the number of bits from the given value
+ * and returns integer
+ */
+static inline int bu21013_get_number_of_bits(unsigned int val, int range)
+{
+ int i;
+ int num = 0;
+ unsigned int mask = 1;
+
+ for (i = 0; i < range; i++) {
+ if (val & mask)
+ num++;
+ mask = mask << 1;
+ }
+ return num;
+}
+/**
+ * bu21013_report_pen_down() - reports the pen down event
+ * @data:bu21013_ts_data structure pointer
+ * @count:touch count
+ *
+ * This function used to report the pen down interrupt to
+ * input subsystem and returns none
+ */
+static void bu21013_report_pen_down(struct bu21013_ts_data *data, int count)
+{
+ short pt0x;
+ short pt0y;
+ short pt1x;
+ short pt1y;
+ if (data->chip->portrait) {
+ pt0x = data->x_pos[0];
+ pt0y = data->y_pos[0];
+ pt1x = data->x_pos[1];
+ pt1y = data->y_pos[1];
+ } else {
+ pt0x = data->y_pos[0];
+ pt0y = data->x_pos[0];
+ pt1x = data->y_pos[1];
+ pt1y = data->x_pos[1];
+ }
+
+ input_report_abs(data->in_dev, ABS_X, pt0x);
+ input_report_abs(data->in_dev, ABS_Y, pt0y);
+ input_report_abs(data->in_dev, ABS_PRESSURE, 1);
+ input_report_abs(data->in_dev, ABS_TOOL_WIDTH, 1);
+ input_report_key(data->in_dev, BTN_TOUCH, 1);
+
+ if (count > 1) {
+ input_report_key(data->in_dev, BTN_2, 1);
+ input_report_abs(data->in_dev, ABS_HAT0X, pt1x);
+ input_report_abs(data->in_dev, ABS_HAT0Y, pt1y);
+ }
+ input_report_abs(data->in_dev, ABS_MT_TOUCH_MAJOR, 1);
+ input_report_abs(data->in_dev, ABS_MT_TOUCH_MINOR, 1);
+ input_report_key(data->in_dev, ABS_MT_WIDTH_MAJOR, 1);
+ input_report_abs(data->in_dev, ABS_MT_POSITION_X, pt0x);
+ input_report_abs(data->in_dev, ABS_MT_POSITION_Y, pt0y);
+ input_mt_sync(data->in_dev);
+
+ if (count > 1) {
+ input_report_abs(data->in_dev, ABS_MT_TOUCH_MAJOR, 1);
+ input_report_key(data->in_dev, ABS_MT_WIDTH_MAJOR, 1);
+ input_report_abs(data->in_dev, ABS_MT_POSITION_X, pt1x);
+ input_report_abs(data->in_dev, ABS_MT_POSITION_Y, pt1y);
+ input_mt_sync(data->in_dev);
+ }
+ input_sync(data->in_dev);
+ data->previous_press_reported = count;
+}
+/**
+ * bu21013_report_pen_up() - reports the pen up event
+ * @data:bu21013_ts_data structure pointer
+ *
+ * This function used to report the pen up interrupt
+ * to input subsystem and returns none
+ */
+static void bu21013_report_pen_up(struct bu21013_ts_data *data)
+{
+ input_report_abs(data->in_dev, ABS_PRESSURE, 0);
+ input_report_abs(data->in_dev, ABS_TOOL_WIDTH, 0);
+ input_report_key(data->in_dev, BTN_TOUCH, 0);
+ input_report_key(data->in_dev, BTN_2, 0);
+ input_report_abs(data->in_dev, ABS_MT_TOUCH_MAJOR, 0);
+ input_report_key(data->in_dev, ABS_MT_WIDTH_MAJOR, 0);
+ input_mt_sync(data->in_dev);
+ input_sync(data->in_dev);
+ data->previous_press_reported = 0;
+}
+/**
+ * bu21013_touch_calc() - calculates the co-ordinates delta
+ * @data: bu21013_ts_data structure pointer
+ * @x: x position
+ * @y: y position
+ * @count: touch count
+ *
+ * This function calculates the exact co-ordinates with respect to
+ * display resolution and returns none
+ */
+static void bu21013_touch_calc
+ (struct bu21013_ts_data *data, int x, int y, int count)
+{
+ data->x_pos[count] = x * data->factor_x / SCALE_FACTOR;
+ data->y_pos[count] = y * data->factor_y / SCALE_FACTOR;
+ if ((data->chip->portrait) && (data->chip->x_flip))
+ data->x_pos[count] =
+ data->chip->x_max_res - data->x_pos[count];
+ if ((data->chip->portrait) && (data->chip->y_flip))
+ data->y_pos[count] =
+ data->chip->y_max_res - data->y_pos[count];
+}
+/**
+ * bu21013_verify_delta() - verify the co-ordinates delta
+ * @x1: x1 position
+ * @y1: y1 position
+ * @x2: x2 position
+ * @y2: y2 position
+ *
+ * This function verifies the delta of the
+ * co-ordinates and returns boolean.
+ */
+static bool bu21013_verify_delta(int x1, int y1, int x2, int y2)
+{
+ int delta_x, delta_y;
+ if ((x1 != 0) && (y1 != 0)) {
+ delta_x = x2 - x1;
+ if (x1 > x2)
+ delta_x = x1 - x2;
+ delta_y = y2 - y1;
+ if (y1 > y2)
+ delta_y = y1 - y2;
+ if ((delta_x < DELTA_MIN) || (delta_y < DELTA_MIN))
+ return false;
+ }
+ return true;
+}
+
+/**
+ * bu21013_do_touch_report(): Get the touch co-ordinates
+ * @data:bu21013_ts_data structure pointer
+ *
+ * Get the touch co-ordinates from touch sensor registers and writes
+ * into device structure and returns integer.
+ */
+static int bu21013_do_touch_report(struct bu21013_ts_data *data)
+{
+ u8 buf[LENGTH_OF_BUFFER];
+ int finger1_valid = 0;
+ int finger2_valid = 0;
+ unsigned int finger1_pos_x;
+ unsigned int finger1_pos_y;
+ unsigned int finger2_pos_x;
+ unsigned int finger2_pos_y;
+ int number_of_active_x_sensors;
+ int number_of_active_y_sensors;
+ int total_number_of_active_sensors;
+ int finger_down_count = 0;
+ int ret = 0;
+ int retry_count = 5;
+
+ if (data->client == NULL)
+ return -EINVAL;
+
+ do {
+ ret = i2c_smbus_read_i2c_block_data
+ (data->client, BU21013_SENSORS_BTN_0_7_REG,
+ LENGTH_OF_BUFFER, buf);
+ retry_count--;
+ if ((ret < LENGTH_OF_BUFFER) && (!retry_count))
+ return -EINVAL;
+ } while (ret < LENGTH_OF_BUFFER);
+
+ number_of_active_x_sensors =
+ bu21013_get_number_of_bits((buf[0] & BU21013_SENSORS_EN_0_7),
+ BU21013_NUMBER_OF_X_SENSORS);
+
+ number_of_active_y_sensors = bu21013_get_number_of_bits
+ ((((buf[1] & BU21013_SENSORS_EN_8_15) |
+ ((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2),
+ BU21013_NUMBER_OF_Y_SENSORS);
+
+ if (((number_of_active_x_sensors != 0) &&
+ (number_of_active_y_sensors == 0)) ||
+ ((number_of_active_x_sensors == 0) &&
+ (number_of_active_y_sensors != 0)))
+ return 0;
+
+ total_number_of_active_sensors =
+ number_of_active_x_sensors + number_of_active_y_sensors;
+
+ finger1_pos_x = buf[3] << SHIFT_2 | (buf[4] & MASK_BITS);
+ finger1_pos_y = buf[5] << SHIFT_2 | (buf[6] & MASK_BITS);
+ finger2_pos_x = buf[7] << SHIFT_2 | (buf[8] & MASK_BITS);
+ finger2_pos_y = buf[9] << SHIFT_2 | (buf[10] & MASK_BITS);
+
+ if (total_number_of_active_sensors) {
+ if ((finger2_pos_x != 0) && (finger2_pos_y != 0)) {
+ if ((finger1_pos_x == 0) || (finger1_pos_y == 0))
+ return 0;
+ ret = bu21013_verify_delta(finger1_pos_x,
+ finger1_pos_y, finger2_pos_x, finger2_pos_y);
+ if (!ret)
+ total_number_of_active_sensors = 0;
+ }
+ }
+
+ if (total_number_of_active_sensors) {
+ finger1_valid = 1;
+ if ((finger1_pos_x == 0) || (finger1_pos_y == 0) ||
+ (finger1_pos_x >= data->chip->touch_x_max) ||
+ (finger1_pos_y >= data->chip->touch_y_max))
+ finger1_valid = 0;
+ finger2_valid = 1;
+ if ((finger2_pos_x == 0) || (finger2_pos_y == 0) ||
+ (finger2_pos_x >= data->chip->touch_x_max) ||
+ (finger2_pos_y >= data->chip->touch_y_max))
+ finger2_valid = 0;
+ if ((finger1_valid == 0) && (finger2_valid == 0))
+ return 0;
+ if (finger1_valid) {
+ bu21013_touch_calc(data, finger1_pos_x,
+ finger1_pos_y, finger_down_count);
+ finger_down_count++;
+ }
+ if (finger2_valid) {
+ bu21013_touch_calc(data, finger2_pos_x,
+ finger2_pos_y, finger_down_count);
+ finger_down_count++;
+ }
+ }
+
+ if (finger_down_count > 0)
+ bu21013_report_pen_down(data, finger_down_count);
+ else {
+ if (data->previous_press_reported)
+ bu21013_report_pen_up(data);
+ }
+
+ return ret;
+}
+
+/**
+ * bu21013_timer_start() - start the timer
+ * @data:bu21013_ts_data structure pointer
+ *
+ * This funtion used to run the timer and returns none.
+ */
+static inline void bu21013_timer_start(struct bu21013_ts_data *data)
+{
+ mod_timer(&data->penirq_timer,
+ jiffies + msecs_to_jiffies(data->penup_timer));
+}
+
+/**
+ * bu21013_timer_wq() - work queue for timer handler
+ * @work:work_struct structure pointer
+ *
+ * This timer work queue used during polling of the co-ordinates
+ * for every timeout period and returns none
+ */
+static void bu21013_timer_wq(struct work_struct *work)
+{
+ struct bu21013_ts_data *data =
+ container_of(work, struct bu21013_ts_data, timer_wq_handler);
+ struct task_struct *tsk = current;
+ struct i2c_client *i2c = data->client;
+ int retval;
+
+ set_task_state(tsk, TASK_INTERRUPTIBLE);
+ retval = bu21013_do_touch_report(data);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "get co-ordinates failed\n");
+ return;
+ }
+ data->intr_pin = data->chip->irq_read_val();
+ if (data->intr_pin == PEN_DOWN_INTR)
+ bu21013_timer_start(data);
+ else
+ enable_irq(data->chip->irq);
+}
+
+/**
+ * bu21013_gpio_int_wq() - work queue for gpio interrupt handler
+ * @work:work_struct structure pointer
+ *
+ * This gpio work queue used to get the co-ordinates
+ * of the pen down interrupt and returns none
+ */
+static void bu21013_gpio_int_wq(struct work_struct *work)
+{
+ struct bu21013_ts_data *data =
+ container_of(work, struct bu21013_ts_data, gpio_wq_handler);
+ struct i2c_client *i2c = data->client;
+ struct task_struct *tsk = current;
+ int retval;
+
+ set_task_state(tsk, TASK_INTERRUPTIBLE);
+ disable_irq(data->chip->irq);
+ retval = bu21013_do_touch_report(data);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "get co-ordinates failed\n");
+ return;
+ }
+ bu21013_timer_start(data);
+}
+
+/**
+ * bu21013_gpio_irq() - gpio callback handler for touch interrupt
+ * @irq: irq value
+ * @device_data:void pointer
+ *
+ * This gpio callback handler for gpio interrupt
+ * and assigns the task and returns irqreturn_t.
+ */
+static irqreturn_t bu21013_gpio_irq(int irq, void *device_data)
+{
+ struct bu21013_ts_data *data = (struct bu21013_ts_data *)device_data;
+ schedule_work(&data->gpio_wq_handler);
+ return IRQ_HANDLED;
+}
+
+/**
+ * bu21013_timer_callback() - callback handler for timer
+ * @dev_data:touch screen data
+ *
+ * This timer callback handler used to schedule the work during
+ * polling of pen down interrupts and returns none
+ */
+static void bu21013_timer_callback(unsigned long dev_data)
+{
+ struct bu21013_ts_data *data = (struct bu21013_ts_data *)dev_data;
+ schedule_work(&data->timer_wq_handler);
+}
+
+/**
+ * bu21013_init_chip() - power on sequence for the bu21013 controller
+ * @data: device structure pointer
+ *
+ * This function is used to power on
+ * the bu21013 controller and returns integer.
+ */
+static int bu21013_init_chip(struct bu21013_ts_data *data)
+{
+ int retval;
+ struct i2c_client *i2c = data->client;
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_RESET_REG,
+ BU21013_RESET_ENABLE);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_RESET reg write failed\n");
+ goto err;
+ }
+ mdelay(RESET_DELAY);
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_0_7_REG,
+ BU21013_SENSORS_EN_0_7);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_SENSOR_0_7 reg write failed\n");
+ goto err;
+ }
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_8_15_REG,
+ BU21013_SENSORS_EN_8_15);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_SENSOR_8_15 reg write failed\n");
+ goto err;
+ }
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_16_23_REG,
+ BU21013_SENSORS_EN_16_23);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_SENSOR_16_23 reg write failed\n");
+ goto err;
+ }
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE1_REG,
+ (BU21013_POS_MODE1_0 | BU21013_POS_MODE1_1));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_POS_MODE1 reg write failed\n");
+ goto err;
+ }
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE2_REG,
+ (BU21013_POS_MODE2_ZERO | BU21013_POS_MODE2_AVG1 |
+ BU21013_POS_MODE2_AVG2 | BU21013_POS_MODE2_EN_RAW |
+ BU21013_POS_MODE2_MULTI));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_POS_MODE2 reg write failed\n");
+ goto err;
+ }
+ if (data->chip->ext_clk)
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
+ (BU21013_CLK_MODE_EXT | BU21013_CLK_MODE_CALIB));
+ else
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
+ (BU21013_CLK_MODE_DIV | BU21013_CLK_MODE_CALIB));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_CLK_MODE reg write failed\n");
+ goto err;
+ }
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_IDLE_REG,
+ (BU21013_IDLET_0 | BU21013_IDLE_INTERMIT_EN));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_IDLE reg write failed\n");
+ goto err;
+ }
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE_REG,
+ BU21013_INT_MODE_LEVEL);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_INT_MODE reg write failed\n");
+ goto err;
+ }
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_FILTER_REG,
+ (BU21013_DELTA_0_6 |
+ BU21013_FILTER_EN));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_FILTER reg write failed\n");
+ goto err;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_ON_REG,
+ (BU21013_TH_ON_3 | BU21013_TH_ON_4));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_TH_ON reg write failed\n");
+ goto err;
+ }
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG,
+ BU21013_TH_OFF_4);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n");
+ goto err;
+ }
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_GAIN_REG,
+ (BU21013_GAIN_0 | BU21013_GAIN_1));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_GAIN reg write failed\n");
+ goto err;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_OFFSET_MODE_REG,
+ BU21013_OFFSET_MODE_DEFAULT);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_OFFSET_MODE reg write failed\n");
+ goto err;
+ }
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_XY_EDGE_REG,
+ (BU21013_X_EDGE_0 | BU21013_X_EDGE_2 |
+ BU21013_Y_EDGE_1 | BU21013_Y_EDGE_3));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_XY_EDGE reg write failed\n");
+ goto err;
+ }
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_DONE_REG,
+ BU21013_DONE);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_REG_DONE reg write failed\n");
+ goto err;
+ }
+
+ data->x_pos[0] = 0;
+ data->x_pos[1] = 0;
+ data->y_pos[0] = 0;
+ data->y_pos[1] = 0;
+ data->previous_press_reported = 0;
+
+ data->factor_x = (data->chip->x_max_res * SCALE_FACTOR /
+ data->chip->touch_x_max);
+ data->factor_y = (data->chip->y_max_res * SCALE_FACTOR /
+ data->chip->touch_y_max);
+err:
+ return retval;
+}
+
+#ifdef CONFIG_PM
+/**
+ * bu21013_suspend() - suspend the touch screen controller
+ * @client: pointer to i2c client structure
+ * @mesg: message from power manager
+ *
+ * This funtion is used to suspend the
+ * touch panel controller and returns integer
+ */
+static int bu21013_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq(bu21013_data->chip->irq);
+ else
+ disable_irq(bu21013_data->chip->irq);
+
+ return 0;
+}
+
+/**
+ * bu21013_resume() - resume the touch screen controller
+ * @client: pointer to i2c client structure
+ *
+ * This funtion is used to resume the touch panel
+ * controller and returns integer.
+ */
+static int bu21013_resume(struct i2c_client *client)
+{
+ int retval;
+ struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);
+
+ retval = bu21013_init_chip(bu21013_data);
+ if (retval < 0) {
+ dev_err(&client->dev, "tsc config failed\n");
+ goto err;
+ }
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq(bu21013_data->chip->irq);
+ else
+ enable_irq(bu21013_data->chip->irq);
+
+ return 0;
+err:
+ kfree(bu21013_data);
+ return retval;
+}
+#endif
+
+/**
+ * bu21013_sysfs() - sys fs parameters
+ * @tp_kobj: kernel object structure pointer
+ *
+ * This function uses to initialize the sysfs for touch panel
+ * based on the controller number
+ */
+int bu21013_sysfs(struct kobject *tp_kobj , int ctrl)
+{
+ int retval = 0;
+
+ tp_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
+ if (tp_kobj == NULL) {
+ retval = -ENOMEM;
+ goto err;
+ }
+ if (ctrl == 1)
+ tp_kobj->ktype = &ktype_touchp1;
+ else if (ctrl == 2)
+ tp_kobj->ktype = &ktype_touchp2;
+ kobject_init(tp_kobj, tp_kobj->ktype);
+ if (ctrl == 1)
+ retval = kobject_set_name(tp_kobj, "touchp1");
+ else if (ctrl == 2)
+ retval = kobject_set_name(tp_kobj, "touchp2");
+ if (retval) {
+ kfree(tp_kobj);
+ goto err;
+ }
+ if (ctrl == 1)
+ retval = kobject_add(tp_kobj, NULL, "touchp1");
+ else if (ctrl == 2)
+ retval = kobject_add(tp_kobj, NULL, "touchp2");
+ if (retval) {
+ kfree(tp_kobj);
+ goto err;
+ }
+ return 0;
+err:
+ return retval;
+}
+/**
+ * bu21013_probe() - initialzes the i2c-client touchscreen driver
+ * @i2c: i2c client structure pointer
+ * @id:i2c device id pointer
+ *
+ * This function used to initializes the i2c-client touchscreen
+ * driver and returns integer.
+ */
+static int bu21013_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ int retval;
+ struct bu21013_ts_data *bu21013_data;
+ struct input_dev *in_dev;
+ short x_max;
+ short y_max;
+ struct bu21013_platform_device *pdata = i2c->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(&i2c->dev, "platform data not defined\n");
+ retval = -EINVAL;
+ return retval;
+ }
+
+ if (!pdata->tp_cntl) {
+ dev_err(&i2c->dev, "controller is not enabled\n");
+ retval = -EINVAL;
+ return retval;
+ }
+
+ bu21013_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL);
+ if (!bu21013_data) {
+ dev_err(&i2c->dev, "device memory alloc failed\n");
+ retval = -ENOMEM;
+ return retval;
+ }
+
+ /* allocate input device */
+ in_dev = input_allocate_device();
+ if (!in_dev) {
+ dev_err(&i2c->dev, "input device memory alloc failed\n");
+ retval = -ENOMEM;
+ goto err_alloc;
+ }
+ bu21013_data->in_dev = in_dev;
+
+ bu21013_data->chip = pdata;
+ bu21013_data->client = i2c;
+ bu21013_data->penup_timer = PENUP_TIMEOUT;
+
+ if (bu21013_data->chip->portrait) {
+ x_max = pdata->x_max_res;
+ y_max = pdata->y_max_res;
+ } else {
+ x_max = pdata->y_max_res;
+ y_max = pdata->x_max_res;
+ }
+
+ INIT_WORK(&bu21013_data->timer_wq_handler, bu21013_timer_wq);
+ INIT_WORK(&bu21013_data->gpio_wq_handler, bu21013_gpio_int_wq);
+
+ init_timer(&bu21013_data->penirq_timer);
+ bu21013_data->penirq_timer.data = (unsigned long)bu21013_data;
+ bu21013_data->penirq_timer.function = bu21013_timer_callback;
+ i2c_set_clientdata(i2c, bu21013_data);
+
+ /* configure the gpio pins */
+ if (pdata->cs_en) {
+ retval = pdata->cs_en(pdata->cs_pin);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "chip init failed\n");
+ goto err_init_cs;
+ }
+ }
+
+ /* configure the touch panel controller */
+ retval = bu21013_init_chip(bu21013_data);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "error in bu21013 config\n");
+ goto err_init_config;
+ }
+
+ /* register the device to input subsystem */
+ in_dev->name = DRIVER_TP;
+ set_bit(EV_SYN, in_dev->evbit);
+ set_bit(EV_KEY, in_dev->evbit);
+ set_bit(EV_ABS, in_dev->evbit);
+ set_bit(BTN_TOUCH, in_dev->keybit);
+
+ input_set_abs_params(in_dev, ABS_X, 0, x_max, 0, 0);
+ input_set_abs_params(in_dev, ABS_Y, 0, y_max, 0, 0);
+ input_set_abs_params(in_dev, ABS_PRESSURE, 0, MAX_PRESSURE, 0, 0);
+ input_set_abs_params(in_dev, ABS_TOOL_WIDTH, 0, MAX_TOOL_WIDTH, 0, 0);
+
+ set_bit(BTN_2, in_dev->keybit);
+ input_set_abs_params(in_dev, ABS_HAT0X, 0, x_max, 0, 0);
+ input_set_abs_params(in_dev, ABS_HAT0Y, 0, y_max, 0, 0);
+ input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, x_max, 0, 0);
+ input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, y_max, 0, 0);
+ input_set_abs_params(in_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_TOUCH_MAJOR,
+ 0, 0);
+ input_set_abs_params
+ (in_dev, ABS_MT_TOUCH_MINOR, 0, MAX_TOUCH_MINOR, 0, 0);
+ input_set_abs_params(in_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+ input_set_abs_params(in_dev, ABS_MT_WIDTH_MAJOR, 0, MAX_TOOL_WIDTH,
+ 0, 0);
+ retval = input_register_device(in_dev);
+ if (retval)
+ goto err_input_register;
+
+ retval = request_irq(pdata->irq, bu21013_gpio_irq,
+ (IRQF_TRIGGER_FALLING | IRQF_SHARED),
+ DRIVER_TP, bu21013_data);
+ if (retval) {
+ dev_err(&i2c->dev, "request irq %d failed\n", pdata->irq);
+ goto err_init_irq;
+ }
+
+ retval = bu21013_sysfs(bu21013_data->touchp_kobj, pdata->tp_cntl);
+ if (retval)
+ goto err_init_sys;
+ /*
+ * to maintain the each device data, we are storing
+ * in global varaiables for tuning the touch screen
+ */
+ if (pdata->tp_cntl == 1)
+ tp1_sys_data = bu21013_data;
+ else if (pdata->tp_cntl == 2)
+ tp2_sys_data = bu21013_data;
+
+ dev_dbg(&i2c->dev, "init done");
+
+ return retval;
+err_init_sys:
+ free_irq(pdata->irq, bu21013_data);
+err_init_irq:
+ input_unregister_device(bu21013_data->in_dev);
+ bu21013_data->in_dev = NULL;
+err_input_register:
+err_init_config:
+ pdata->cs_dis(pdata->cs_pin);
+err_init_cs:
+ del_timer_sync(&bu21013_data->penirq_timer);
+ cancel_work_sync(&bu21013_data->timer_wq_handler);
+ cancel_work_sync(&bu21013_data->gpio_wq_handler);
+ input_free_device(bu21013_data->in_dev);
+err_alloc:
+ kfree(bu21013_data);
+ return retval;
+}
+/**
+ * bu21013_remove() - removes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ *
+ * This function uses to remove the i2c-client
+ * touchscreen driver and returns integer.
+ */
+static int __devexit bu21013_remove(struct i2c_client *client)
+{
+ struct bu21013_ts_data *data = i2c_get_clientdata(client);
+
+ del_timer_sync(&data->penirq_timer);
+ cancel_work_sync(&data->timer_wq_handler);
+ cancel_work_sync(&data->gpio_wq_handler);
+
+ if (data->chip != NULL) {
+ free_irq(data->chip->irq, data);
+ data->chip->cs_dis(data->chip->cs_pin);
+ }
+ input_unregister_device(data->in_dev);
+ kfree(data);
+
+ return 0;
+}
+
+static const struct i2c_device_id bu21013_id[] = {
+ { DRIVER_TP, 0 },
+ { DRIVER_TP, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bu21013_id);
+
+static struct i2c_driver bu21013_driver = {
+ .driver = {
+ .name = DRIVER_TP,
+ .owner = THIS_MODULE,
+ },
+ .probe = bu21013_probe,
+#ifdef CONFIG_PM
+ .suspend = bu21013_suspend,
+ .resume = bu21013_resume,
+#endif
+ .remove = __devexit_p(bu21013_remove),
+ .id_table = bu21013_id,
+};
+
+/**
+ * bu21013_init() - initializes the bu21013 touchscreen driver
+ *
+ * This function used to initializes the bu21013
+ * touchscreen driver and returns integer.
+ */
+static int __init bu21013_init(void)
+{
+ return i2c_add_driver(&bu21013_driver);
+}
+
+/**
+ * bu21013_exit() - de-initializes the bu21013 touchscreen driver
+ *
+ * This function uses to de-initializes the bu21013
+ * touchscreen driver and returns none.
+ */
+static void __exit bu21013_exit(void)
+{
+ i2c_del_driver(&bu21013_driver);
+}
+
+module_init(bu21013_init);
+module_exit(bu21013_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("NAVEEN KUMAR G");
+MODULE_DESCRIPTION("bu21013 touch screen controller driver");
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
new file mode 100644
index 00000000000..15c558567e1
--- /dev/null
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -0,0 +1,951 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver.
+ * Copyright (c) 2007-2010, Synaptics Incorporated
+ *
+ * Author: Js HA <js.ha@stericsson.com> for ST-Ericsson
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Copyright 2010 (c) ST-Ericsson AB
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ *#############################################################################
+ */
+
+#include <linux/hrtimer.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input/synaptics_i2c_rmi4.h>
+
+/* TODO: for multiple device support will need a per-device mutex */
+#define DRIVER_NAME "synaptics_rmi4_i2c"
+
+#define PDT_START_SCAN_LOCATION (0x00E9)
+#define PDT_END_SCAN_LOCATION (0x000A)
+#define PDT_ENTRY_SIZE (0x0006)
+#define MAX_ERROR_REPORT 6
+#define MAX_RETRY_COUNT 5
+#define READ_DELAY 10
+#define STD_QUERY_LEN 21
+#define PAGE_LEN 2
+#define TX_BUF_LEN 17
+
+static struct synaptics_rmi4_function_handler
+ fn_handler_table[RMI4_FUNCTION_HANDLER_TABLE_SIZE] = {
+ /* Fn $11 */
+ {
+ SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM,
+ synpatics_rmi4_touchpad_report,
+ synpatics_rmi4_touchpad_config,
+ synpatics_rmi4_touchpad_init,
+ synpatics_rmi4_touchpad_detect
+ },
+};
+
+/**
+ * synaptics_rmi4_find_fn_handler() - find the function handler for rmi4 device
+ * @fn_number: function number
+ *
+ * This function is here to provide a way for external modules to access the
+ * functions list. It will try to find a matching function base on the passed
+ * in RMI4 function number and return the pointer to the struct rmi4 function
+ * handler if a match is found or NULL if not found.
+ */
+static struct synaptics_rmi4_function_handler *synaptics_rmi4_find_fn_handler
+ (int fn_number)
+{
+ int index;
+ bool found = false;
+
+ for (index = 0; index < RMI4_FUNCTION_HANDLER_TABLE_SIZE; index++) {
+ if (fn_number ==
+ fn_handler_table[index].fn_number) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return NULL;
+ return &(fn_handler_table[index]);
+}
+
+/**
+ * synaptics_rmi4_set_page() - sets the page
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address:set the address of the page
+ *
+ * This function is used to set the page and returns integer.
+ */
+static int synaptics_rmi4_set_page(struct synaptics_rmi4_data *pdata,
+ unsigned int address)
+{
+ unsigned char txbuf[PAGE_LEN];
+ int retval;
+ unsigned int page;
+ struct i2c_client *i2c = pdata->i2c_client;
+
+ page = ((address >> 8) & MASK_8BIT);
+ if (page != pdata->current_page) {
+ txbuf[0] = MASK_8BIT;
+ txbuf[1] = page;
+ retval = i2c_master_send(i2c, txbuf, PAGE_LEN);
+ if (retval != PAGE_LEN)
+ dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval);
+ else
+ pdata->current_page = page;
+ } else
+ retval = PAGE_LEN;
+ return retval;
+}
+/**
+ * synaptics_rmi4_i2c_byte_read() - read the single byte of data
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address:read the data from this offset
+ * @data: pointer to hold the read data
+ *
+ * This function is to read the single byte of data and returns integer.
+ */
+static int synaptics_rmi4_i2c_byte_read(struct synaptics_rmi4_data *pdata,
+ unsigned short address,
+ unsigned char *valp)
+{
+ int retval = 0;
+ int retry_count = 0;
+ int index;
+ struct i2c_client *i2c = pdata->i2c_client;
+
+ mutex_lock(&(pdata->rmi4_page_mutex));
+ retval = synaptics_rmi4_set_page(pdata, address);
+ if (retval != PAGE_LEN)
+ goto exit;
+ index = address & MASK_8BIT;
+retry:
+ retval = i2c_smbus_read_i2c_block_data(i2c, index, 1, valp);
+ if (retval != 1) {
+ if (++retry_count == MAX_RETRY_COUNT) {
+ dev_err(&i2c->dev, "%s:offset 0x%04x failed:%d\n",
+ __func__, address, retval);
+ goto exit;
+ } else {
+ synaptics_rmi4_set_page(pdata, address);
+ goto retry;
+ }
+ }
+exit:
+ mutex_unlock(&(pdata->rmi4_page_mutex));
+ return retval;
+}
+/**
+ * synaptics_rmi4_i2c_block_read() - read the block of data
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address:read the block of data from this offset
+ * @valp: pointer to a buffer containing the data to be read
+ * @size: number of bytes to read
+ *
+ * This function is to read the block of data and returns integer.
+ */
+static int synaptics_rmi4_i2c_block_read(struct synaptics_rmi4_data *pdata,
+ unsigned short address,
+ unsigned char *valp, int size)
+{
+ int retval = 0;
+ int retry_count = 0;
+ int index;
+ struct i2c_client *i2c = pdata->i2c_client;
+
+ mutex_lock(&(pdata->rmi4_page_mutex));
+ retval = synaptics_rmi4_set_page(pdata, address);
+ if (retval != PAGE_LEN)
+ goto exit;
+ index = address & MASK_8BIT;
+retry:
+ retval = i2c_smbus_read_i2c_block_data(i2c, index, size, valp);
+ if (retval != size) {
+ if (++retry_count == MAX_RETRY_COUNT)
+ dev_err(&i2c->dev,
+ "%s:address 0x%04x size %d failed:%d\n",
+ __func__, address, size, retval);
+ else {
+ synaptics_rmi4_set_page(pdata, address);
+ goto retry;
+ }
+ }
+exit:
+ mutex_unlock(&(pdata->rmi4_page_mutex));
+ return retval;
+}
+
+/**
+ * synaptics_rmi4_i2c_byte_write() - write the single byte data
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address:write the block of data from this offset
+ * @data: data to be write
+ *
+ * This function is to write the single byte data and returns integer.
+ */
+static int synaptics_rmi4_i2c_byte_write(struct synaptics_rmi4_data *pdata,
+ unsigned short address,
+ unsigned char data)
+{
+ unsigned char txbuf[2];
+ int retval = 0;
+ struct i2c_client *i2c = pdata->i2c_client;
+
+ /* Can't have anyone else changing the page behind our backs */
+ mutex_lock(&(pdata->rmi4_page_mutex));
+
+ retval = synaptics_rmi4_set_page(pdata, address);
+ if (retval != PAGE_LEN)
+ goto exit;
+ txbuf[0] = address & MASK_8BIT;
+ txbuf[1] = data;
+ retval = i2c_master_send(pdata->i2c_client, txbuf, 2);
+ /* Add in retry on writes only in certian error return values */
+ if (retval != 2) {
+ dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval);
+ retval = -EIO;
+ } else
+ retval = 1;
+exit:
+ mutex_unlock(&(pdata->rmi4_page_mutex));
+ return retval;
+}
+/**
+ * synaptics_rmi4_i2c_block_write() - write the block of data
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address:write the block of data from this offset
+ * @valp: pointer to a buffer containing the data to be written
+ * @size: number of bytes to write
+ *
+ * This function is to write the block of data and returns integer.
+ */
+static int synaptics_rmi4_i2c_block_write(struct synaptics_rmi4_data *pdata,
+ unsigned short address,
+ unsigned char *valp, int size)
+{
+ unsigned char *txbuf;
+ int retval = 0;
+ int i;
+ /*
+ * Use this buffer for fast writes of 16
+ * bytes or less. The first byte will
+ * contain the address at which to start
+ * the write.
+ */
+ unsigned char txbuf_most[TX_BUF_LEN];
+ struct i2c_client *i2c = pdata->i2c_client;
+
+ if (size < sizeof(txbuf_most))
+ /* Avoid an allocation if we can help it */
+ txbuf = txbuf_most;
+ else {
+ /* over 16 bytes write we'll need to allocate a temp buffer */
+ txbuf = kmalloc(size + 1, GFP_KERNEL);
+ if (!txbuf) {
+ dev_err(&i2c->dev, "no memory for tx buffer\n");
+ return -ENOMEM;
+ }
+ }
+ /*
+ * It stinks here that we have to copy the buffer.
+ * We copy from valp to txbuf leaving
+ * the first location open for the address
+ */
+ for (i = 0; i < size; i++)
+ txbuf[i + 1] = valp[i];
+ /* Can't have anyone else changing the page behind our backs */
+ mutex_lock(&(pdata->rmi4_page_mutex));
+
+ retval = synaptics_rmi4_set_page(pdata, address);
+ if (retval != PAGE_LEN)
+ goto exit;
+ /* put the address in the first byte */
+ txbuf[0] = address & MASK_8BIT;
+ retval = i2c_master_send(i2c, txbuf, size + 1);
+ /* add in retyr on writes only in certain error return values */
+ if (retval != (size + 1)) {
+ retval = -EIO;
+ dev_err(&i2c->dev, "%s:failed: %d\n", __func__, retval);
+ goto exit;
+ } else
+ retval = size;
+exit:
+ mutex_unlock(&(pdata->rmi4_page_mutex));
+ if (txbuf != txbuf_most)
+ kfree(txbuf);
+ return retval;
+}
+/**
+ * synaptics_rmi4_report_device() - reports the rmi4 device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn
+ *
+ * This function is used to call the report function of the rmi4 device.
+ */
+static int synaptics_rmi4_report_device(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi)
+{
+ bool found = false;
+ int touch = 0;
+ struct i2c_client *client = pdata->i2c_client;
+ struct synaptics_rmi4_function_handler *hfn;
+ static int num_error_reports;
+ hfn = synaptics_rmi4_find_fn_handler(rfi->fn_number);
+ if (hfn) {
+ found = true;
+ if (hfn->pfunc_report)
+ touch = hfn->pfunc_report(pdata, rfi);
+ else
+ num_error_reports++;
+ }
+ if (!found) {
+ num_error_reports++;
+ if (num_error_reports < MAX_ERROR_REPORT)
+ dev_err(&client->dev, "%s:report not supported\n",
+ __func__);
+ }
+ return touch;
+}
+/**
+ * synaptics_rmi4_sensor_report() - reports to input subsystem
+ * @pdata: pointer to synaptics_rmi4_data structure
+ *
+ * This function is used to reads in all data sources and reports
+ * them to the input subsystem.
+ */
+static int synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *pdata)
+{
+ unsigned char intr_status[4];
+ /* number of touch points - fingers or buttons */
+ int touch = 0;
+ unsigned int retval;
+ struct synaptics_rmi4_fn *rfi;
+ struct synaptics_rmi4_device_info *rmi;
+ struct i2c_client *client = pdata->i2c_client;
+
+ /*
+ * Get the interrupt status from the function $01
+ * control register+1 to find which source(s) were interrupting
+ * so we can read the data from the source(s) (2D sensor, buttons..)
+ */
+ retval = pdata->block_read(pdata, pdata->fn01_data_base_addr + 1,
+ intr_status,
+ pdata->number_of_interrupt_register);
+ if (retval != pdata->number_of_interrupt_register) {
+ dev_err(&client->dev,
+ "could not read interrupt status registers\n");
+ return 0;
+ }
+ /*
+ * check each function that has data sources and if the interrupt for
+ * that triggered then call that RMI4 functions report() function to
+ * gather data and report it to the input subsystem
+ */
+ rmi = &(pdata->rmi4_mod_info);
+ list_for_each_entry(rfi, &rmi->support_fn_list, link) {
+ if (rfi->num_of_data_sources) {
+ if (intr_status[rfi->index_to_intr_reg] &
+ rfi->intr_mask)
+ touch = synaptics_rmi4_report_device(pdata,
+ rfi);
+ }
+ }
+ /* return the number of touch points */
+ return touch;
+}
+
+/**
+ * synaptics_rmi4_work() - to schedule work and restart the timer
+ * @rmi4_work: pointer to work_struct structure
+ *
+ * This is the scheduled work for every restart of the timer
+ * during polling.
+ */
+static void synaptics_rmi4_work(struct work_struct *rmi4_work)
+{
+ struct synaptics_rmi4_data *pdata =
+ container_of(rmi4_work, struct synaptics_rmi4_data, work);
+ if (!(pdata->polling_required)) {
+ if (!pdata->touch_pressed)
+ disable_irq(pdata->irq_number);
+ synaptics_rmi4_sensor_report(pdata);
+ if (pdata->touch_pressed)
+ hrtimer_start(&pdata->timer,
+ ktime_set(0, RMI4_TOUCH_POLLING_TIME_IN_PRESSED),
+ HRTIMER_MODE_REL);
+ else
+ enable_irq(pdata->irq_number);
+ } else {
+ synaptics_rmi4_sensor_report(pdata);
+ if (pdata->touch_pressed)
+ hrtimer_start(&pdata->timer,
+ ktime_set(0, RMI4_TOUCH_POLLING_TIME_IN_PRESSED),
+ HRTIMER_MODE_REL);
+ else
+ hrtimer_start(&pdata->timer,
+ ktime_set(0, RMI4_TOUCH_POLLING_TIME_IN_IDLE),
+ HRTIMER_MODE_REL);
+ }
+}
+
+/**
+ * synaptics_rmi4_poll_timer() - to schedule work and restart the timer
+ * @htimer: pointer to hrtimer structure
+ *
+ * This is the timer function for polling. It has to schedule work
+ * and restart the timer.
+ */
+static enum hrtimer_restart synaptics_rmi4_poll_timer(struct hrtimer *htimer)
+{
+ struct synaptics_rmi4_data *pdata =
+ container_of(htimer, struct synaptics_rmi4_data, timer);
+ schedule_work(&pdata->work);
+ return HRTIMER_NORESTART;
+}
+
+/**
+ * synaptics_rmi4_init_fn_handler() - initialize the rmi4 device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ *
+ * This function calls init for all of the functions on the functions list and
+ * passes in the input_dev ptr so that each fn can store it for later use.
+ */
+static int synaptics_rmi4_init_fn_handler(struct synaptics_rmi4_data *pdata)
+{
+ int index;
+ int retval = 0;
+
+ for (index = 0; index < RMI4_FUNCTION_HANDLER_TABLE_SIZE; index++) {
+ if (fn_handler_table[index].pfunc_init)
+ retval = fn_handler_table[index].pfunc_init(pdata);
+ }
+ return retval;
+}
+
+/**
+ * synaptics_rmi4_detect_device() - detect the rmi4 device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn
+ * @rmi_fd: variable to synaptics_rmi4_fn_desc
+ * @count: count the number of interrupts
+ *
+ * This function is used to call the detect function of rmi4 device.
+ */
+static inline
+int synaptics_rmi4_detect_device(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi,
+ struct synaptics_rmi4_fn_desc rmi_fd,
+ unsigned char count)
+{
+ int index;
+ /*
+ * Get the ptr to the detect function
+ * based on the function number
+ */
+ for (index = 0; index < RMI4_FUNCTION_HANDLER_TABLE_SIZE; index++) {
+ if (rmi_fd.fn_number == fn_handler_table[index].fn_number)
+ fn_handler_table[index].pfunc_detect(pdata, rfi,
+ &rmi_fd,
+ count);
+ }
+ return 0;
+}
+
+/**
+ * synaptics_rmi4_i2c_query_device() - query the rmi4 device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ *
+ * This function is used to query the rmi4 device.
+ */
+static int synaptics_rmi4_i2c_query_device(struct synaptics_rmi4_data *pdata)
+{
+ int i;
+ bool found = false;
+ int retval;
+ unsigned char std_queries[STD_QUERY_LEN];
+ unsigned char intr_count = 0;
+ int data_sources = 0;
+ unsigned int ctrl_offset;
+ struct synaptics_rmi4_fn *rfi;
+ struct synaptics_rmi4_fn_desc rmi_fd;
+ struct synaptics_rmi4_function_handler *hfn;
+ struct synaptics_rmi4_device_info *rmi;
+ struct i2c_client *client = pdata->i2c_client;
+
+ /*
+ * init the physical drivers RMI module
+ * info list of functions
+ */
+ INIT_LIST_HEAD(&pdata->rmi4_mod_info.support_fn_list);
+
+ /*
+ * Read the Page Descriptor Table to determine what functions
+ * are present
+ */
+ for (i = PDT_START_SCAN_LOCATION; i > PDT_END_SCAN_LOCATION;
+ i -= PDT_ENTRY_SIZE) {
+ retval = pdata->block_read(pdata, i,
+ (unsigned char *)&rmi_fd, sizeof(rmi_fd));
+ if (retval == sizeof(rmi_fd)) {
+ rfi = NULL;
+ if (rmi_fd.fn_number) {
+ switch (rmi_fd.fn_number & MASK_8BIT) {
+ case SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM:
+ pdata->fn01_query_base_addr =
+ rmi_fd.query_base_addr;
+ pdata->fn01_ctrl_base_addr =
+ rmi_fd.ctrl_base_addr;
+ pdata->fn01_data_base_addr =
+ rmi_fd.data_base_addr;
+ break;
+
+ default:
+ if (rmi_fd.intr_src_count) {
+ rfi = kmalloc(sizeof(*rfi),
+ GFP_KERNEL);
+ if (!rfi) {
+ dev_err(&client->dev,
+ "%s:kmalloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ retval =
+ synaptics_rmi4_detect_device
+ (pdata,
+ rfi,
+ rmi_fd,
+ intr_count);
+ if (retval < 0)
+ return retval;
+ }
+ break;
+ }
+ /* interrupt count for next iteration */
+ intr_count += (rmi_fd.intr_src_count &
+ MASK_3BIT);
+ /*
+ * We only want to add functions to the list
+ * that have data associated with them.
+ */
+ if (rfi && rmi_fd.intr_src_count) {
+ /*
+ * link this function info to
+ * the RMI module infos
+ * list of functions
+ */
+ mutex_lock(&(pdata->fn_list_mutex));
+ list_add_tail(&rfi->link,
+ &pdata->rmi4_mod_info.support_fn_list);
+ mutex_unlock(&(pdata->fn_list_mutex));
+ }
+ } else {
+ /*
+ * A zero in the function number
+ * signals the end of the PDT
+ */
+ dev_dbg(&client->dev,
+ "%s:Found End of PDT\n", __func__);
+ break;
+ }
+ } else {
+ /* failed to read next PDT entry - end PDT
+ scan - this may result in an incomplete set
+ of recognized functions - should probably
+ return an error but the driver may still be
+ viable for diagnostics and debugging so let's
+ let it continue. */
+ dev_err(&client->dev, "%s: Read Error 0x%x\n",
+ __func__, retval);
+ break;
+ }
+ }
+ /*
+ * calculate the interrupt register count - used in the
+ * ISR to read the correct number of interrupt registers
+ */
+ pdata->number_of_interrupt_register = (intr_count + 7) / 8;
+ /*
+ * Function $01 will be used to query the product properties,
+ * and product ID so we had to read the PDT above first to get
+ * the Fn $01 query address and prior to filling in the product
+ * info. NOTE: Even an unflashed device will still have FN $01.
+ */
+
+ /* Load up the standard queries and get the RMI4 module info */
+ retval = pdata->block_read(pdata,
+ pdata->fn01_query_base_addr,
+ std_queries,
+ sizeof(std_queries));
+ if (retval != sizeof(std_queries)) {
+ dev_err(&client->dev, "%s:Failed reading queries\n",
+ __func__);
+ return -EIO;
+ }
+
+ /* Currently supported RMI version is 4.0 */
+ pdata->rmi4_mod_info.version_major = 4;
+ pdata->rmi4_mod_info.version_minor = 0;
+ /*
+ * get manufacturer id, product_props, product info,
+ * date code, tester id, serial num and product id (name)
+ */
+ pdata->rmi4_mod_info.manufacturer_id = std_queries[0];
+ pdata->rmi4_mod_info.product_props = std_queries[1];
+ pdata->rmi4_mod_info.product_info[0] = std_queries[2];
+ pdata->rmi4_mod_info.product_info[1] = std_queries[3];
+ /* year - 2001-2032 */
+ pdata->rmi4_mod_info.date_code[0] = std_queries[4] & MASK_5BIT;
+ /* month - 1-12 */
+ pdata->rmi4_mod_info.date_code[1] = std_queries[5] & MASK_4BIT;
+ /* day - 1-31 */
+ pdata->rmi4_mod_info.date_code[2] = std_queries[6] & MASK_5BIT;
+ pdata->rmi4_mod_info.tester_id = ((std_queries[7] & MASK_7BIT) << 8) |
+ (std_queries[8] & MASK_7BIT);
+ pdata->rmi4_mod_info.serial_number =
+ ((std_queries[9] & MASK_7BIT) << 8) |
+ (std_queries[10] & MASK_7BIT);
+ memcpy(pdata->rmi4_mod_info.product_id_string, &std_queries[11], 10);
+
+ /* Check if this is a Synaptics device - report if not. */
+ if (pdata->rmi4_mod_info.manufacturer_id != 1)
+ dev_err(&client->dev, "%s: non-Synaptics mfg id:%d\n",
+ __func__, pdata->rmi4_mod_info.manufacturer_id);
+ list_for_each_entry(rfi, &pdata->rmi4_mod_info.support_fn_list, link)
+ data_sources += rfi->num_of_data_sources;
+ if (data_sources) {
+ rmi = &(pdata->rmi4_mod_info);
+ list_for_each_entry(rfi, &rmi->support_fn_list, link) {
+ if (rfi->num_of_data_sources) {
+ /*
+ * check if function number matches
+ * if so call that config function
+ */
+ hfn =
+ synaptics_rmi4_find_fn_handler(rfi->fn_number);
+ if (hfn) {
+ found = true;
+ if (hfn->pfunc_config)
+ hfn->pfunc_config(pdata, rfi);
+ else
+ break;
+ }
+ if (!found)
+ dev_err(&client->dev,
+ "%s:fn_number not supported\n",
+ __func__);
+ /*
+ * Turn on interrupts for this
+ * function's data sources.
+ */
+ ctrl_offset = pdata->fn01_ctrl_base_addr + 1 +
+ rfi->index_to_intr_reg;
+ retval = pdata->byte_write(pdata, ctrl_offset,
+ rfi->intr_mask);
+ if (retval < 0)
+ return retval;
+ }
+ }
+ } else
+ pdata->polling_required = false;
+ return 0;
+}
+
+/**
+ * synaptics_rmi4_irq_callback() - callback handler for attention line
+ * @irq: irq value
+ * @info:void pointer
+ *
+ * This function is interrupt callback handler. It just notifies the
+ * application layer that attention is required.
+ */
+static irqreturn_t synaptics_rmi4_irq_callback(int irq, void *info)
+{
+ struct synaptics_rmi4_data *pdata =
+ (struct synaptics_rmi4_data *)info;
+ schedule_work(&(pdata->work));
+ return IRQ_HANDLED;
+}
+/**
+ * synaptics_rmi4_probe() - Initialze the i2c-client touchscreen driver
+ * @i2c: i2c client structure pointer
+ * @id:i2c device id pointer
+ *
+ * This function will allocate and initialize the instance
+ * data and request the irq and set the instance data as the clients
+ * platform data then register the physical driver which will do a scan of
+ * the rmi4 Physical Device Table and enumerate any rmi4 functions that
+ * have data sources associated with them.
+ */
+static int synaptics_rmi4_probe
+ (struct i2c_client *client, const struct i2c_device_id *dev_id)
+{
+ struct synaptics_rmi4_data *prmi4_data;
+ struct synaptics_rmi4_i2c_data *rmii2cdata;
+ struct synaptics_rmi4_platform_data *platformdata = NULL;
+ int retval;
+ int i;
+ bool found = false;
+
+ /* Allocate and initialize the instance data for this client */
+ prmi4_data = kzalloc(sizeof(struct synaptics_rmi4_data) * 2,
+ GFP_KERNEL);
+ if (!prmi4_data) {
+ dev_err(&client->dev, "%s: no memory allocated\n", __func__);
+ return -ENOMEM;
+ }
+ prmi4_data->input_dev = input_allocate_device();
+ if (prmi4_data->input_dev == NULL) {
+ dev_err(&client->dev, "%s:input device alloc failed\n",
+ __func__);
+ retval = -ENOMEM;
+ goto err_input;
+ }
+ mutex_init(&(prmi4_data->fn_list_mutex));
+ mutex_init(&(prmi4_data->rmi4_page_mutex));
+ /* Initialize the platform i2c data */
+ rmii2cdata = ((struct synaptics_rmi4_i2c_data *)
+ (client->dev.platform_data));
+ /*
+ * Loop through the platform data and locate the one that matches
+ * the i2c_client I2C address
+ */
+ for (i = 0; i < rmii2cdata->num_clients; i++) {
+ platformdata = &(rmii2cdata->platformdata[i]);
+ prmi4_data->instance_number = i;
+ found = true;
+ /*
+ * set the device name using the instance_no appended
+ * to DRIVER_NAME to make a unique name
+ */
+ dev_set_name(&client->dev, "synaptics_rmi4_i2c%d\n",
+ prmi4_data->instance_number);
+ /*
+ * Determine if we need to poll (inefficient) or
+ * use interrupts.
+ */
+ prmi4_data->irq_number = platformdata->irq_number;
+ if (platformdata->irq_number)
+ prmi4_data->polling_required = false;
+ else
+ prmi4_data->polling_required = true;
+ }
+ /*
+ * if went through all the platform data list and didn't find a match
+ * then notify that we are defaulting to polling
+ */
+ if (!found)
+ dev_err(&client->dev, "%s: No platform data match found\n",
+ __func__);
+ /* Store the instance data in the i2c_client - we need to do this prior
+ * to calling register_physical_driver since it may use the read, write
+ * functions. If nothing was found then the id fields will be set to 0
+ * for the irq and the default will be set to polling required so we
+ * will still work but in polling mode.
+ */
+ i2c_set_clientdata(client, prmi4_data);
+ /*
+ * Copy i2c_client pointer into RTID's i2c_client pointer for
+ * later use in rmi4_read, rmi4_write, etc.
+ */
+ prmi4_data->i2c_client = client;
+ /* So we set the page correctly the first time */
+ prmi4_data->current_page = MASK_16BIT;
+ prmi4_data->touch_pressed = 0;
+ prmi4_data->x_max_res = platformdata->x_max_res;
+ prmi4_data->y_max_res = platformdata->y_max_res;
+ prmi4_data->portrait_mode = platformdata->portrait_mode;
+ prmi4_data->x_flip = platformdata->x_flip;
+ prmi4_data->y_flip = platformdata->y_flip;
+ prmi4_data->byte_read = synaptics_rmi4_i2c_byte_read;
+ prmi4_data->byte_write = synaptics_rmi4_i2c_byte_write;
+ prmi4_data->block_read = synaptics_rmi4_i2c_block_read;
+ prmi4_data->block_write = synaptics_rmi4_i2c_block_write;
+ /* Initialize the function handlers for rmi4*/
+ retval = synaptics_rmi4_init_fn_handler(prmi4_data);
+ if (retval) {
+ dev_err(&client->dev, "%s:rmi4 init Failed\n", __func__);
+ goto err_init;
+ }
+ /*initialize the input device parameters */
+ prmi4_data->input_dev->name = DRIVER_NAME;
+ prmi4_data->input_dev->phys = "Synaptics_Clearpad";
+ retval = input_register_device(prmi4_data->input_dev);
+ if (retval) {
+ dev_err(&client->dev, "%s:input register failed\n", __func__);
+ goto err_init;
+ }
+ /*
+ * Register physical driver - this will call the detect function that
+ * will then scan the device and determine the supported
+ * rmi4 functions.
+ */
+ retval = synaptics_rmi4_i2c_query_device(prmi4_data);
+ if (retval) {
+ dev_err(&client->dev, "%s: rmi4 query device failed\n",
+ __func__);
+ goto err_query_dev;
+ }
+ INIT_WORK(&(prmi4_data->work), synaptics_rmi4_work);
+ hrtimer_init(&(prmi4_data->timer), CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ prmi4_data->timer.function = synaptics_rmi4_poll_timer;
+ if (prmi4_data->irq_number) {
+ retval = request_irq(prmi4_data->irq_number,
+ synaptics_rmi4_irq_callback,
+ prmi4_data->irq_type,
+ DRIVER_NAME, prmi4_data);
+ if (retval) {
+ dev_err(&client->dev, "%s:Unable to get attn irq %d\n",
+ __func__, prmi4_data->irq_number);
+ free_irq(prmi4_data->irq_number, prmi4_data);
+ prmi4_data->polling_required = true;
+ }
+ }
+ /*
+ * if we need to set up the polling callback and
+ * worker thread.
+ */
+ if (prmi4_data->polling_required) {
+ /* So set up the polling timer and timer function.*/
+ dev_dbg(&client->dev, "%s: start pollling\n", __func__);
+ hrtimer_start(&(prmi4_data->timer), ktime_set(1, 0),
+ HRTIMER_MODE_REL);
+ }
+ dev_dbg(&client->dev, "%s: done\n", __func__);
+ return retval;
+err_query_dev:
+ i2c_set_clientdata(client, NULL);
+ input_unregister_device(prmi4_data->input_dev);
+err_init:
+ input_free_device(prmi4_data->input_dev);
+ prmi4_data->input_dev = NULL;
+err_input:
+ kfree(prmi4_data);
+ return retval;
+}
+/**
+ * synaptics_rmi4_remove() - Removes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ *
+ * This funtion uses to remove the i2c-client
+ * touchscreen driver and returns integer.
+ */
+static int synaptics_rmi4_remove(struct i2c_client *client)
+{
+ struct synaptics_rmi4_data *pdata = i2c_get_clientdata(client);
+ /* Stop the polling timer */
+ hrtimer_cancel(&(pdata->timer));
+ if (pdata->irq_number)
+ free_irq(pdata->irq_number, pdata);
+ /* Make sure all scheduled work is stopped */
+ flush_scheduled_work();
+ /* Unregister everything */
+ input_unregister_device(pdata->input_dev);
+ kfree(pdata);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ * synaptics_rmi4_suspend() - suspend the touch screen controller
+ * @client: pointer to i2c client structure
+ * @mesg: message from power manager
+ *
+ * This funtion is used to suspend the
+ * touch panel controller and returns integer
+ */
+static int synaptics_rmi4_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ /* Touch sleep mode */
+ struct synaptics_rmi4_data *pdata = i2c_get_clientdata(client);
+ if (!pdata->polling_required)
+ disable_irq(pdata->irq_number);
+ else
+ hrtimer_cancel(&pdata->timer);
+ synaptics_rmi4_i2c_byte_write(pdata,
+ pdata->fn01_ctrl_base_addr + 1, 0x0);
+ return 0;
+}
+/**
+ * synaptics_rmi4_resume() - resume the touch screen controller
+ * @client: pointer to i2c client structure
+ *
+ * This funtion is used to resume the touch panel
+ * controller and returns integer.
+ */
+static int synaptics_rmi4_resume(struct i2c_client *client)
+{
+ struct synaptics_rmi4_data *pdata = i2c_get_clientdata(client);
+ if (!pdata->polling_required) {
+ enable_irq(pdata->irq_number);
+ synaptics_rmi4_i2c_byte_write(pdata,
+ pdata->fn01_ctrl_base_addr + 1, 0x8);
+ } else
+ hrtimer_start(&pdata->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+ return 0;
+}
+#endif
+
+static const struct i2c_device_id synaptics_rmi4_id_table[] = {
+ { DRIVER_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
+
+static struct i2c_driver synaptics_rmi4_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = synaptics_rmi4_probe,
+ .remove = synaptics_rmi4_remove,
+#ifdef CONFIG_PM
+ .suspend = synaptics_rmi4_suspend,
+ .resume = synaptics_rmi4_resume,
+#endif
+ .id_table = synaptics_rmi4_id_table,
+};
+/**
+ * synaptics_rmi4_init() - Initialize the touchscreen driver
+ *
+ * This funtion uses to initializes the synaptics
+ * touchscreen driver and returns integer.
+ */
+static int __init synaptics_rmi4_init(void)
+{
+ return i2c_add_driver(&synaptics_rmi4_driver);
+}
+/**
+ * synaptics_rmi4_exit() - De-initialize the touchscreen driver
+ *
+ * This funtion uses to de-initialize the synaptics
+ * touchscreen driver and returns none.
+ */
+static void __exit synaptics_rmi4_exit(void)
+{
+ i2c_del_driver(&synaptics_rmi4_driver);
+}
+
+
+module_init(synaptics_rmi4_init);
+module_exit(synaptics_rmi4_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("naveen.gaddipati@stericsson.com, js.ha@stericsson.com");
+MODULE_DESCRIPTION("synaptics rmi4 i2c touch Driver");
+MODULE_ALIAS("i2c:synaptics_rmi4_ts");
diff --git a/drivers/input/touchscreen/synaptics_rmi4_touchpad.c b/drivers/input/touchscreen/synaptics_rmi4_touchpad.c
new file mode 100644
index 00000000000..074dc4b4d28
--- /dev/null
+++ b/drivers/input/touchscreen/synaptics_rmi4_touchpad.c
@@ -0,0 +1,492 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver.
+ * Copyright (c) 2007-2010, Synaptics Incorporated
+ *
+ * Author: Js HA <js.ha@stericsson.com> for ST-Ericsson
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Copyright 2010 (c) ST-Ericsson AB
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ *#############################################################################
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/input.h>
+#include <linux/input/synaptics_i2c_rmi4.h>
+
+#define SCALE_FACTOR 1000
+#define DATA_BUF_LEN 32
+#define BUF_LEN 37
+#define QUERY_LEN 9
+#define DATA_LEN 12
+#define HAS_TAP 0x01
+#define HAS_PALMDETECT 0x01
+#define HAS_ROTATE 0x02
+#define HAS_TAPANDHOLD 0x02
+#define HAS_DOUBLETAP 0x04
+#define HAS_EARLYTAP 0x08
+#define HAS_RELEASE 0x08
+#define HAS_FLICK 0x10
+#define HAS_PRESS 0x20
+#define HAS_PINCH 0x40
+
+/**
+ * synpatics_rmi4_touchpad_report_up() - reports the finger up state
+ * @pdata: pointer to synaptics_rmi4_data structure
+ *
+ * This function calls to reports the finger up for the input subsystem
+ */
+static void synpatics_rmi4_touchpad_report_up(struct synaptics_rmi4_data *pdata)
+{
+ if (pdata->touch_pressed) {
+ input_report_abs(pdata->input_dev, ABS_PRESSURE, 0);
+ input_report_abs(pdata->input_dev, ABS_TOOL_WIDTH, 0);
+ input_report_key(pdata->input_dev, BTN_TOUCH, 0);
+ input_report_key(pdata->input_dev, BTN_2, 0);
+ input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MAJOR, 0);
+ input_report_key(pdata->input_dev, ABS_MT_WIDTH_MAJOR, 0);
+ input_mt_sync(pdata->input_dev);
+ pdata->touch_pressed = 0;
+ }
+}
+/**
+ * synpatics_rmi4_touchpad_report_down() - reports the finger down state
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @count: finger down count
+ *
+ * This function calls to reports the finger down for the input subsystem
+ */
+static
+void synpatics_rmi4_touchpad_report_down(struct synaptics_rmi4_data *pdata,
+ int count)
+{
+ int x[2];
+ int y[2];
+ int finger;
+ for (finger = 0; finger < 2; finger++) {
+ if (pdata->portrait_mode) {
+ x[finger] = pdata->x[finger];
+ y[finger] = pdata->y[finger];
+ } else {
+ x[finger] = pdata->y[finger];
+ y[finger] = pdata->x[finger];
+ }
+ }
+ input_report_abs(pdata->input_dev, ABS_X, x[0]);
+ input_report_abs(pdata->input_dev, ABS_Y, y[0]);
+ input_report_abs(pdata->input_dev, ABS_PRESSURE, 1);
+ input_report_abs(pdata->input_dev, ABS_TOOL_WIDTH, 1);
+ input_report_key(pdata->input_dev, BTN_TOUCH, 1);
+ if (count > 1) {
+ input_report_key(pdata->input_dev, BTN_2, 1);
+ input_report_abs(pdata->input_dev, ABS_HAT0X, x[1]);
+ input_report_abs(pdata->input_dev, ABS_HAT0Y, y[1]);
+ }
+ input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MAJOR, 1);
+ input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MINOR, 1);
+ input_report_abs(pdata->input_dev, ABS_MT_POSITION_X, x[0]);
+ input_report_abs(pdata->input_dev, ABS_MT_POSITION_Y, y[0]);
+ input_mt_sync(pdata->input_dev);
+ if (count > 1) {
+ input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MAJOR, 1);
+ input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MINOR, 1);
+ input_report_abs(pdata->input_dev, ABS_MT_POSITION_X, x[1]);
+ input_report_abs(pdata->input_dev, ABS_MT_POSITION_Y, y[1]);
+ input_mt_sync(pdata->input_dev);
+ }
+ pdata->touch_pressed = count;
+}
+/**
+ * synpatics_rmi4_touchpad_calc() - calculates the co-ordinates
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @count: finger down count
+ *
+ * This function calls to calculates the co-ordinates
+ */
+static
+void synpatics_rmi4_touchpad_calc(struct synaptics_rmi4_data *pdata, int count)
+{
+ pdata->x[count] =
+ pdata->x[count] * pdata->factor_x / SCALE_FACTOR;
+ pdata->y[count] =
+ pdata->y[count] * pdata->factor_y / SCALE_FACTOR;
+ pdata->wx[count] =
+ pdata->wx[count] * pdata->factor_x / SCALE_FACTOR + 1;
+ pdata->wy[count] =
+ pdata->wy[count] * pdata->factor_y / SCALE_FACTOR + 1;
+ if (pdata->x[count] < 0)
+ pdata->x[count] = 0;
+ else if (pdata->x[count] >= pdata->x_max_res)
+ pdata->x[count] = pdata->x_max_res - 1;
+ if (pdata->y[count] < 0)
+ pdata->y[count] = 0;
+ else if (pdata->y[count] >= pdata->y_max_res)
+ pdata->y[count] = pdata->y_max_res - 1;
+ if (pdata->portrait_mode && pdata->x_flip)
+ pdata->x[count] = pdata->x_max_res - pdata->x[count];
+ if (pdata->portrait_mode && pdata->y_flip)
+ pdata->y[count] = pdata->y_max_res - pdata->y[count];
+}
+/**
+ * synpatics_rmi4_touchpad_report() - reports for the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn structure
+ *
+ * This function calls to reports for the rmi4 touchpad device
+ */
+int synpatics_rmi4_touchpad_report(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi)
+{
+ /* number of touch points - fingers down in this case */
+ int touch_count = 0;
+ int finger;
+ int fingers_supported;
+ int finger_registers;
+ int reg;
+ int finger_shift;
+ int finger_status;
+ unsigned short data_base_addr;
+ unsigned short data_offset;
+ unsigned char data_reg_blk_size;
+ unsigned char values[2];
+ unsigned char data[DATA_LEN];
+ int retval;
+
+ /* get 2D sensor finger data */
+ /*
+ * First get the finger status field - the size of the finger status
+ * field is determined by the number of finger supporte - 2 bits per
+ * finger, so the number of registers to read is:
+ * registerCount = ceil(numberOfFingers/4).
+ * Read the required number of registers and check each 2 bit field to
+ * determine if a finger is down:
+ * 00 = finger not present,
+ * 01 = finger present and data accurate,
+ * 10 = finger present but data may not be accurate,
+ * 11 = reserved for product use.
+ */
+ fingers_supported = rfi->num_of_data_points;
+ finger_registers = (fingers_supported + 3)/4;
+ data_base_addr = rfi->fn_desc.data_base_addr;
+ retval = pdata->block_read(pdata, data_base_addr, values,
+ finger_registers);
+ if (retval != finger_registers) {
+ printk(KERN_ERR "%s:read status registers failed\n", __func__);
+ return 0;
+ }
+ /*
+ * For each finger present, read the proper number of registers
+ * to get absolute data.
+ */
+ data_reg_blk_size = rfi->size_of_data_register_block;
+ for (finger = 0; finger < fingers_supported; finger++) {
+ /* determine which data byte the finger status is in */
+ reg = finger/4;
+ /* bit shift to get finger's status */
+ finger_shift = (finger % 4) * 2;
+ finger_status = (values[reg] >> finger_shift) & 3;
+ /*
+ * if finger status indicates a finger is present then
+ * read the finger data and report it
+ */
+ if (finger_status == 1 || finger_status == 2) {
+ /* Read the finger data */
+ data_offset = data_base_addr +
+ ((finger * data_reg_blk_size) +
+ finger_registers);
+ retval = pdata->block_read(pdata, data_offset, data,
+ data_reg_blk_size);
+ if (retval != data_reg_blk_size) {
+ printk(KERN_ERR "%s:read data failed\n",
+ __func__);
+ return 0;
+ } else {
+ pdata->x[touch_count] =
+ (data[0] << 4) | (data[2] & MASK_4BIT);
+ pdata->y[touch_count] =
+ (data[1] << 4) |
+ ((data[2] >> 4) & MASK_4BIT);
+ pdata->z[touch_count] = (data[4]);
+ pdata->wy[touch_count] =
+ (data[3] >> 4) & MASK_4BIT;
+ pdata->wx[touch_count] =
+ (data[3] & MASK_4BIT);
+ synpatics_rmi4_touchpad_calc(pdata,
+ touch_count);
+ }
+ /* number of active touch points */
+ touch_count++;
+ }
+ }
+ if (touch_count > 0)
+ synpatics_rmi4_touchpad_report_down(pdata, touch_count);
+ else
+ synpatics_rmi4_touchpad_report_up(pdata);
+ /* sync after groups of events */
+ input_sync(pdata->input_dev);
+ /* return the number of touch points */
+ return touch_count;
+}
+EXPORT_SYMBOL_GPL(synpatics_rmi4_touchpad_report);
+
+/**
+ * synpatics_rmi4_touchpad_config() - confiures the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn structure
+ *
+ * This function calls to confiures the rmi4 touchpad device
+ */
+int synpatics_rmi4_touchpad_config(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi)
+{
+ /*
+ * For the data source - print info and do any
+ * source specific configuration.
+ */
+ unsigned char data[BUF_LEN];
+ int retval = 0;
+ /* Get and print some info about the data source... */
+ /* To Query 2D devices we need to read from the address obtained
+ * from the function descriptor stored in the RMI function info.
+ */
+ retval = pdata->block_read(pdata, rfi->fn_desc.query_base_addr,
+ data, QUERY_LEN);
+ if (retval != QUERY_LEN)
+ printk(KERN_ERR "%s:read query registers failed\n", __func__);
+ else {
+ retval = pdata->block_read(pdata,
+ rfi->fn_desc.ctrl_base_addr,
+ data, DATA_BUF_LEN);
+ if (retval != DATA_BUF_LEN) {
+ printk(KERN_ERR "%s:read control registers failed\n",
+ __func__);
+ return retval;
+ }
+ /* Store these for use later*/
+ pdata->sensor_max_x = ((data[6] & MASK_8BIT) << 0) |
+ ((data[7] & MASK_4BIT) << 8);
+ pdata->sensor_max_y = ((data[8] & MASK_5BIT) << 0) |
+ ((data[9] & MASK_4BIT) << 8);
+ pdata->factor_x = (pdata->x_max_res * SCALE_FACTOR /
+ pdata->sensor_max_x);
+ pdata->factor_y = (pdata->y_max_res * SCALE_FACTOR /
+ pdata->sensor_max_y);
+ }
+ return retval;
+}
+EXPORT_SYMBOL_GPL(synpatics_rmi4_touchpad_config);
+
+/**
+ * synpatics_rmi4_touchpad_init() - initialize the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ *
+ * This function initialize any function $11 specific params and settings
+ * to input subsysten.
+ */
+int synpatics_rmi4_touchpad_init(struct synaptics_rmi4_data *pdata)
+{
+ int x_max;
+ int y_max;
+
+ if (pdata->portrait_mode) {
+ x_max = pdata->x_max_res;
+ y_max = pdata->y_max_res;
+ } else {
+ x_max = pdata->y_max_res;
+ y_max = pdata->x_max_res;
+ }
+ set_bit(EV_SYN, pdata->input_dev->evbit);
+ set_bit(EV_KEY, pdata->input_dev->evbit);
+ set_bit(EV_ABS, pdata->input_dev->evbit);
+ set_bit(BTN_TOUCH, pdata->input_dev->keybit);
+
+ input_set_abs_params(pdata->input_dev, ABS_X, 0, x_max, 0, 0);
+ input_set_abs_params(pdata->input_dev, ABS_Y, 0, y_max, 0, 0);
+ input_set_abs_params(pdata->input_dev, ABS_PRESSURE, 0,
+ RMI4_TOUCH_MAX_PRESSURE, 0, 0);
+ input_set_abs_params(pdata->input_dev, ABS_TOOL_WIDTH, 0,
+ RMI4_TOUCH_MAX_TOOL_WIDTH, 0, 0);
+ set_bit(BTN_2, pdata->input_dev->keybit);
+ input_set_abs_params(pdata->input_dev, ABS_HAT0X, 0, x_max, 0, 0);
+ input_set_abs_params(pdata->input_dev, ABS_HAT0Y, 0, y_max, 0, 0);
+ input_set_abs_params(pdata->input_dev, ABS_MT_POSITION_X, 0, x_max,
+ 0, 0);
+ input_set_abs_params(pdata->input_dev, ABS_MT_POSITION_Y, 0, y_max,
+ 0, 0);
+ input_set_abs_params(pdata->input_dev, ABS_MT_TOUCH_MAJOR, 0,
+ RMI4_TOUCH_MAX_TOOL_WIDTH,
+ 0, 0);
+ input_set_abs_params(pdata->input_dev, ABS_MT_TOUCH_MINOR, 0,
+ RMI4_TOUCH_MAX_TOOL_WIDTH,
+ 0, 0);
+ input_set_abs_params(pdata->input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+ input_set_abs_params(pdata->input_dev, ABS_MT_WIDTH_MAJOR, 0,
+ RMI4_TOUCH_MAX_TOOL_WIDTH,
+ 0, 0);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(synpatics_rmi4_touchpad_init);
+
+/**
+ * synpatics_rmi4_touchpad_detect() - detects the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn structure
+ * @fd: pointer to synaptics_rmi4_fn_desc structure
+ * @interruptcount: count the number of interrupts
+ *
+ * This function calls to detects the rmi4 touchpad device
+ */
+int synpatics_rmi4_touchpad_detect(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int interruptcount)
+{
+ unsigned char queries[QUERY_LEN];
+ unsigned short intr_offset;
+ unsigned char abs_data_size;
+ unsigned char abs_data_blk_size;
+ unsigned char egr_0, egr_1;
+ unsigned int all_data_blk_size;
+ int has_pinch, has_flick, has_tap;
+ int has_tapandhold, has_doubletap;
+ int has_earlytap, has_press;
+ int has_palmdetect, has_rotate;
+ int has_rel;
+ int i;
+ int retval;
+
+ rfi->fn_desc.query_base_addr = fd->query_base_addr;
+ rfi->fn_desc.data_base_addr = fd->data_base_addr;
+ rfi->fn_desc.intr_src_count = fd->intr_src_count;
+ rfi->fn_desc.fn_number = fd->fn_number;
+ rfi->fn_number = fd->fn_number;
+ rfi->num_of_data_sources = fd->intr_src_count;
+ rfi->fn_desc.ctrl_base_addr = fd->ctrl_base_addr;
+ rfi->fn_desc.cmd_base_addr = fd->cmd_base_addr;
+ /*
+ * need to get number of fingers supported, data size, etc.
+ * to be used when getting data since the number of registers to
+ * read depends on the number of fingers supported and data size.
+ */
+ retval = pdata->block_read(pdata, fd->query_base_addr, queries,
+ sizeof(queries));
+ if (retval != sizeof(queries)) {
+ printk(KERN_ERR "%s:read function query registers\n",
+ __func__);
+ return retval;
+ }
+ /*
+ * 2D data sources have only 3 bits for the number of fingers
+ * supported - so the encoding is a bit wierd.
+ */
+ /* default number of fingers supported */
+ rfi->num_of_data_points = 2;
+ if ((queries[1] & MASK_3BIT) <= 4)
+ /* add 1 since zero based */
+ rfi->num_of_data_points = (queries[1] & MASK_3BIT) + 1;
+ else {
+ /*
+ * a value of 5 is up to 10 fingers - 6 and 7 are reserved
+ * (shouldn't get these i int retval;n a normal 2D source).
+ */
+ if ((queries[1] & MASK_3BIT) == 5)
+ rfi->num_of_data_points = 10;
+ }
+ /* Need to get interrupt info for handling interrupts */
+ rfi->index_to_intr_reg = (interruptcount + 7)/8;
+ if (rfi->index_to_intr_reg != 0)
+ rfi->index_to_intr_reg -= 1;
+ /*
+ * loop through interrupts for each source in fn $11
+ * and or in a bit to the interrupt mask for each.
+ */
+ intr_offset = interruptcount % 8;
+ rfi->intr_mask = 0;
+ for (i = intr_offset;
+ i < ((fd->intr_src_count & MASK_3BIT) + intr_offset); i++)
+ rfi->intr_mask |= 1 << i;
+
+ /* Size of just the absolute data for one finger */
+ abs_data_size = queries[5] & MASK_2BIT;
+ /* One each for X and Y, one for LSB for X & Y, one for W, one for Z */
+ abs_data_blk_size = 3 + (2 * (abs_data_size == 0 ? 1 : 0));
+ rfi->size_of_data_register_block = abs_data_blk_size;
+
+ /*
+ * need to determine the size of data to read - this depends on
+ * conditions such as whether Relative data is reported and if Gesture
+ * data is reported.
+ */
+ egr_0 = queries[7];
+ egr_1 = queries[8];
+
+ /*
+ * Get info about what EGR data is supported, whether it has
+ * Relative data supported, etc.
+ */
+ has_pinch = egr_0 & HAS_PINCH;
+ has_flick = egr_0 & HAS_FLICK;
+ has_tap = egr_0 & HAS_TAP;
+ has_earlytap = egr_0 & HAS_EARLYTAP;
+ has_press = egr_0 & HAS_PRESS;
+ has_rotate = egr_1 & HAS_ROTATE;
+ has_rel = queries[1] & HAS_RELEASE;
+ has_tapandhold = egr_0 & HAS_TAPANDHOLD;
+ has_doubletap = egr_0 & HAS_DOUBLETAP;
+ has_palmdetect = egr_1 & HAS_PALMDETECT;
+
+ /*
+ * Size of all data including finger status, absolute data for each
+ * finger, relative data and EGR data
+ */
+ all_data_blk_size =
+ /* finger status, four fingers per register */
+ ((rfi->num_of_data_points + 3) / 4) +
+ /* absolute data, per finger times number of fingers */
+ (abs_data_blk_size * rfi->num_of_data_points) +
+ /*
+ * two relative registers (if relative is being reported)
+ */
+ 2 * has_rel +
+ /*
+ * F11_2D_data8 is only present if the egr_0
+ * register is non-zero.
+ */
+ !!(egr_0) +
+ /*
+ * F11_2D_data9 is only present if either egr_0 or
+ * egr_1 registers are non-zero.
+ */
+ (egr_0 || egr_1) +
+ /*
+ * F11_2D_data10 is only present if EGR_PINCH or EGR_FLICK of
+ * egr_0 reports as 1.
+ */
+ !!(has_pinch | has_flick) +
+ /*
+ * F11_2D_data11 and F11_2D_data12 are only present if
+ * EGR_FLICK of egr_0 reports as 1.
+ */
+ 2 * !!(has_flick);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(synpatics_rmi4_touchpad_detect);
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 65dd7501cb5..ec30a67574d 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -295,6 +295,16 @@ config LEDS_DELL_NETBOOKS
This adds support for the Latitude 2100 and similar
notebooks that have an external LED.
+config LEDS_LP5521
+ tristate "LED Support for the LP5521 LEDs"
+ depends on LEDS_CLASS && I2C
+ help
+ If you say 'Y' here you get support for the National Semiconductor
+ LP5521 LED driver used in n8x0 boards.
+
+ This driver can be built as a module by choosing 'M'. The module
+ will be called leds-lp5521.
+
config LEDS_MC13783
tristate "LED Support for MC13783 PMIC"
depends on MFD_MC13783
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index b68fcf6d56d..53c28fbf8b5 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
+obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o
obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o
obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
new file mode 100644
index 00000000000..f5a25ff747c
--- /dev/null
+++ b/drivers/leds/leds-lp5521.c
@@ -0,0 +1,735 @@
+/*
+ * lp5521.c - LP5521 LED Driver
+ *
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * Written by Mathias Nyman <mathias.nyman@xxxxxxxxx>
+ * Updated by Felipe Balbi <felipe.balbi@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/i2c/lp5521.h>
+
+#define LP5521_DRIVER_NAME "lp5521"
+
+#define LP5521_REG_R_PWM 0x02
+#define LP5521_REG_B_PWM 0x04
+#define LP5521_REG_ENABLE 0x00
+#define LP5521_REG_OP_MODE 0x01
+#define LP5521_REG_G_PWM 0x03
+#define LP5521_REG_R_CNTRL 0x05
+#define LP5521_REG_G_CNTRL 0x06
+#define LP5521_REG_B_CNTRL 0x07
+#define LP5521_REG_MISC 0x08
+#define LP5521_REG_R_CHANNEL_PC 0x09
+#define LP5521_REG_G_CHANNEL_PC 0x0a
+#define LP5521_REG_B_CHANNEL_PC 0x0b
+#define LP5521_REG_STATUS 0x0c
+#define LP5521_REG_RESET 0x0d
+#define LP5521_REG_GPO 0x0e
+#define LP5521_REG_R_PROG_MEM 0x10
+#define LP5521_REG_G_PROG_MEM 0x30
+#define LP5521_REG_B_PROG_MEM 0x50
+
+#define LP5521_CURRENT_1m5 0x0f
+#define LP5521_CURRENT_3m1 0x1f
+#define LP5521_CURRENT_4m7 0x2f
+#define LP5521_CURRENT_6m3 0x3f
+#define LP5521_CURRENT_7m9 0x4f
+#define LP5521_CURRENT_9m5 0x5f
+#define LP5521_CURRENT_11m1 0x6f
+#define LP5521_CURRENT_12m7 0x7f
+#define LP5521_CURRENT_14m3 0x8f
+#define LP5521_CURRENT_15m9 0x9f
+#define LP5521_CURRENT_17m5 0xaf
+#define LP5521_CURRENT_19m1 0xbf
+#define LP5521_CURRENT_20m7 0xcf
+#define LP5521_CURRENT_22m3 0xdf
+#define LP5521_CURRENT_23m9 0xef
+#define LP5521_CURRENT_25m5 0xff
+
+#define LP5521_PROGRAM_LENGTH 32 /* in bytes */
+
+struct lp5521_chip {
+ /* device lock */
+ struct mutex lock;
+ struct i2c_client *client;
+
+ struct work_struct red_work;
+ struct work_struct green_work;
+ struct work_struct blue_work;
+
+ struct led_classdev ledr;
+ struct led_classdev ledg;
+ struct led_classdev ledb;
+
+ enum lp5521_mode mode;
+
+ int red;
+ int green;
+ int blue;
+};
+
+static int lp5521_set_mode(struct lp5521_chip *chip,
+ enum lp5521_mode mode);
+
+static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int lp5521_read(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int lp5521_configure(struct i2c_client *client)
+{
+ int ret = 0;
+
+ /* Enable chip and set light to logarithmic mode */
+ ret |= lp5521_write(client, LP5521_REG_ENABLE, 0xc0);
+
+ /* setting all color pwms to direct control mode */
+ ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3f);
+
+ /* setting current to 4.7 mA for all channels */
+ ret |= lp5521_write(client, LP5521_REG_R_CNTRL, LP5521_CURRENT_4m7);
+ ret |= lp5521_write(client, LP5521_REG_G_CNTRL, LP5521_CURRENT_4m7);
+ ret |= lp5521_write(client, LP5521_REG_B_CNTRL, LP5521_CURRENT_4m7);
+
+ /* Enable auto-powersave, set charge pump to auto, red to battery */
+ ret |= lp5521_write(client, LP5521_REG_MISC, 0x3c);
+
+ /* initialize all channels pwm to zero */
+ ret |= lp5521_write(client, LP5521_REG_R_PWM, 0);
+ ret |= lp5521_write(client, LP5521_REG_G_PWM, 0);
+ ret |= lp5521_write(client, LP5521_REG_B_PWM, 0);
+
+ /* Not much can be done about errors at this point */
+ return ret;
+}
+
+static int lp5521_load_program(struct lp5521_chip *chip, u8 * pattern)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ /* Enter load program mode for all led channels */
+ ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); /* 0001 0101 */
+ if (ret)
+ return ret;
+
+ if (chip->red)
+ ret |= i2c_smbus_write_i2c_block_data(client,
+ LP5521_REG_R_PROG_MEM,
+ LP5521_PROGRAM_LENGTH,
+ pattern);
+ if (chip->green)
+ ret |= i2c_smbus_write_i2c_block_data(client,
+ LP5521_REG_G_PROG_MEM,
+ LP5521_PROGRAM_LENGTH,
+ pattern);
+ if (chip->blue)
+ ret |= i2c_smbus_write_i2c_block_data(client,
+ LP5521_REG_B_PROG_MEM,
+ LP5521_PROGRAM_LENGTH,
+ pattern);
+
+ return ret;
+}
+
+static int lp5521_run_program(struct lp5521_chip *chip)
+{
+ struct i2c_client *client = chip->client;
+ int reg;
+ u8 mask = 0xc0;
+ u8 exec_state = 0;
+
+ reg = lp5521_read(client, LP5521_REG_ENABLE);
+ if (reg < 0)
+ return reg;
+
+ reg &= mask;
+
+ /* set all active channels exec state to countinous run */
+ exec_state |= (chip->red << 5);
+ exec_state |= (chip->green << 3);
+ exec_state |= (chip->blue << 1);
+
+ reg |= exec_state;
+
+ if (lp5521_write(client, LP5521_REG_ENABLE, reg))
+ dev_dbg(&client->dev, "failed writing to register %02x\n",
+ LP5521_REG_ENABLE);
+
+ /* set op-mode to run for active channels, disabled for others */
+ if (lp5521_write(client, LP5521_REG_OP_MODE, exec_state))
+ dev_dbg(&client->dev, "failed writing to register %02x\n",
+ LP5521_REG_OP_MODE);
+
+ return 0;
+}
+
+/*--------------------------------------------------------------*/
+/* Sysfs interface */
+/*--------------------------------------------------------------*/
+
+static ssize_t show_active_channels(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct lp5521_chip *chip = dev_get_drvdata(dev);
+ char channels[4];
+ int pos = 0;
+
+ if (chip->red)
+ pos += sprintf(channels + pos, "r");
+ if (chip->green)
+ pos += sprintf(channels + pos, "g");
+ if (chip->blue)
+ pos += sprintf(channels + pos, "b");
+
+ channels[pos] = '\0';
+
+ return sprintf(buf, "%s\n", channels);
+}
+
+static ssize_t store_active_channels(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct lp5521_chip *chip = dev_get_drvdata(dev);
+
+ chip->red = 0;
+ chip->green = 0;
+ chip->blue = 0;
+
+ if (strchr(buf, 'r') != NULL)
+ chip->red = 1;
+ if (strchr(buf, 'b') != NULL)
+ chip->blue = 1;
+ if (strchr(buf, 'g') != NULL)
+ chip->green = 1;
+
+ return len;
+}
+
+static ssize_t show_color(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int r, g, b;
+
+ r = lp5521_read(client, LP5521_REG_R_PWM);
+ g = lp5521_read(client, LP5521_REG_G_PWM);
+ b = lp5521_read(client, LP5521_REG_B_PWM);
+
+ if (r < 0 || g < 0 || b < 0)
+ return -EINVAL;
+
+ return sprintf(buf, "%.2x:%.2x:%.2x\n", r, g, b);
+}
+
+static ssize_t store_color(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lp5521_chip *chip = i2c_get_clientdata(client);
+ int ret;
+ unsigned r, g, b;
+
+
+ ret = sscanf(buf, "%2x:%2x:%2x", &r, &g, &b);
+ if (ret != 3)
+ return -EINVAL;
+
+ mutex_lock(&chip->lock);
+
+ ret = lp5521_write(client, LP5521_REG_R_PWM, (u8) r);
+ ret = lp5521_write(client, LP5521_REG_G_PWM, (u8) g);
+ ret = lp5521_write(client, LP5521_REG_B_PWM, (u8) b);
+
+ mutex_unlock(&chip->lock);
+
+ return len;
+}
+
+static ssize_t store_load(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct lp5521_chip *chip = dev_get_drvdata(dev);
+ int ret, nrchars, offset = 0, i = 0;
+ char c[3];
+ unsigned cmd;
+ u8 pattern[LP5521_PROGRAM_LENGTH] = { 0 };
+
+ while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) {
+
+ /* separate sscanfs because length is working only for %s */
+ ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
+ ret = sscanf(c, "%2x", &cmd);
+ if (ret != 1)
+ goto fail;
+ pattern[i] = (u8) cmd;
+
+ offset += nrchars;
+ i++;
+ }
+
+ /* pattern commands are always two bytes long */
+ if (i % 2)
+ goto fail;
+
+ mutex_lock(&chip->lock);
+
+ ret = lp5521_load_program(chip, pattern);
+ mutex_unlock(&chip->lock);
+
+ if (ret) {
+ dev_err(dev, "lp5521 failed loading pattern\n");
+ return ret;
+ }
+
+ return len;
+fail:
+ dev_err(dev, "lp5521 wrong pattern format\n");
+ return -EINVAL;
+}
+
+static ssize_t show_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lp5521_chip *chip = dev_get_drvdata(dev);
+ char *mode;
+
+ mutex_lock(&chip->lock);
+ switch (chip->mode) {
+ case LP5521_MODE_RUN:
+ mode = "run";
+ break;
+ case LP5521_MODE_LOAD:
+ mode = "load";
+ break;
+ case LP5521_MODE_DIRECT_CONTROL:
+ mode = "direct";
+ break;
+ default:
+ mode = "undefined";
+ }
+ mutex_unlock(&chip->lock);
+
+ return sprintf(buf, "%s\n", mode);
+}
+
+static ssize_t store_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct lp5521_chip *chip = dev_get_drvdata(dev);
+
+ mutex_lock(&chip->lock);
+
+ if (sysfs_streq(buf, "run"))
+ lp5521_set_mode(chip, LP5521_MODE_RUN);
+ else if (sysfs_streq(buf, "load"))
+ lp5521_set_mode(chip, LP5521_MODE_LOAD);
+ else if (sysfs_streq(buf, "direct"))
+ lp5521_set_mode(chip, LP5521_MODE_DIRECT_CONTROL);
+ else
+ len = -EINVAL;
+
+ mutex_unlock(&chip->lock);
+
+ return len;
+}
+
+static ssize_t show_current(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int r, g, b;
+
+ r = lp5521_read(client, LP5521_REG_R_CNTRL);
+ g = lp5521_read(client, LP5521_REG_G_CNTRL);
+ b = lp5521_read(client, LP5521_REG_B_CNTRL);
+
+ if (r < 0 || g < 0 || b < 0)
+ return -EINVAL;
+
+ r >>= 4;
+ g >>= 4;
+ b >>= 4;
+
+ return sprintf(buf, "%x %x %x\n", r, g, b);
+}
+
+static ssize_t store_current(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct lp5521_chip *chip = dev_get_drvdata(dev);
+ struct i2c_client *client = chip->client;
+ int ret;
+ unsigned curr;
+
+ ret = sscanf(buf, "%1x", &curr);
+ if (ret != 1)
+ return -EINVAL;
+
+ /* current level is determined by the 4 upper bits, rest is ones */
+ curr = (curr << 4) | 0x0f;
+
+ mutex_lock(&chip->lock);
+
+ ret |= lp5521_write(client, LP5521_REG_R_CNTRL, (u8) curr);
+ ret |= lp5521_write(client, LP5521_REG_G_CNTRL, (u8) curr);
+ ret |= lp5521_write(client, LP5521_REG_B_CNTRL, (u8) curr);
+
+ mutex_unlock(&chip->lock);
+
+ return len;
+}
+
+static DEVICE_ATTR(color, S_IRUGO | S_IWUGO, show_color, store_color);
+static DEVICE_ATTR(load, S_IWUGO, NULL, store_load);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUGO, show_mode, store_mode);
+static DEVICE_ATTR(active_channels, S_IRUGO | S_IWUGO,
+ show_active_channels, store_active_channels);
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current,
+ store_current);
+
+static int lp5521_register_sysfs(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ int ret;
+
+ ret = device_create_file(dev, &dev_attr_color);
+ if (ret)
+ goto fail1;
+ ret = device_create_file(dev, &dev_attr_load);
+ if (ret)
+ goto fail2;
+ ret = device_create_file(dev, &dev_attr_active_channels);
+ if (ret)
+ goto fail3;
+ ret = device_create_file(dev, &dev_attr_mode);
+ if (ret)
+ goto fail4;
+ ret = device_create_file(dev, &dev_attr_led_current);
+ if (ret)
+ goto fail5;
+
+ return 0;
+
+fail5:
+ device_remove_file(dev, &dev_attr_mode);
+fail4:
+ device_remove_file(dev, &dev_attr_active_channels);
+fail3:
+ device_remove_file(dev, &dev_attr_load);
+fail2:
+ device_remove_file(dev, &dev_attr_color);
+fail1:
+ return ret;
+}
+
+static void lp5521_unregister_sysfs(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+
+ device_remove_file(dev, &dev_attr_led_current);
+ device_remove_file(dev, &dev_attr_mode);
+ device_remove_file(dev, &dev_attr_active_channels);
+ device_remove_file(dev, &dev_attr_color);
+ device_remove_file(dev, &dev_attr_load);
+}
+
+/*--------------------------------------------------------------*/
+/* Set chip operating mode */
+/*--------------------------------------------------------------*/
+
+static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode)
+{
+ struct i2c_client *client = chip->client;
+ int ret = 0;
+
+ /* if in that mode already do nothing, except for run */
+ if (chip->mode == mode && mode != LP5521_MODE_RUN)
+ return 0;
+
+ switch (mode) {
+ case LP5521_MODE_RUN:
+ ret = lp5521_run_program(chip);
+ break;
+ case LP5521_MODE_LOAD:
+ ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15);
+ break;
+ case LP5521_MODE_DIRECT_CONTROL:
+ ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3F);
+ break;
+ default:
+ dev_dbg(&client->dev, "unsupported mode %d\n", mode);
+ }
+
+ chip->mode = mode;
+
+ return ret;
+}
+
+static void lp5521_red_work(struct work_struct *work)
+{
+ struct lp5521_chip *chip =
+ container_of(work, struct lp5521_chip, red_work);
+ int ret;
+
+ ret = lp5521_configure(chip->client);
+ if (ret) {
+ dev_dbg(&chip->client->dev,
+ "could not configure lp5521, %d\n", ret);
+ return;
+ }
+
+ ret = lp5521_write(chip->client, LP5521_REG_R_PWM, chip->red);
+ if (ret)
+ dev_dbg(&chip->client->dev,
+ "could not set brightness, %d\n", ret);
+}
+
+static void lp5521_red_set(struct led_classdev *led,
+ enum led_brightness value)
+{
+ struct lp5521_chip *chip =
+ container_of(led, struct lp5521_chip, ledr);
+
+ chip->red = value;
+ schedule_work(&chip->red_work);
+}
+
+static void lp5521_green_work(struct work_struct *work)
+{
+ struct lp5521_chip *chip =
+ container_of(work, struct lp5521_chip, green_work);
+ int ret;
+
+ ret = lp5521_configure(chip->client);
+ if (ret) {
+ dev_dbg(&chip->client->dev,
+ "could not configure lp5521, %d\n", ret);
+ return;
+ }
+
+ ret = lp5521_write(chip->client, LP5521_REG_G_PWM, chip->green);
+ if (ret)
+ dev_dbg(&chip->client->dev,
+ "could not set brightness, %d\n", ret);
+}
+
+static void lp5521_green_set(struct led_classdev *led,
+ enum led_brightness value)
+{
+ struct lp5521_chip *chip =
+ container_of(led, struct lp5521_chip, ledg);
+
+ chip->green = value;
+ schedule_work(&chip->green_work);
+}
+
+static void lp5521_blue_work(struct work_struct *work)
+{
+ struct lp5521_chip *chip =
+ container_of(work, struct lp5521_chip, blue_work);
+ int ret;
+
+ ret = lp5521_configure(chip->client);
+ if (ret) {
+ dev_dbg(&chip->client->dev,
+ "could not configure lp5521, %d\n", ret);
+ return;
+ }
+
+ ret = lp5521_write(chip->client, LP5521_REG_B_PWM, chip->blue);
+ if (ret)
+ dev_dbg(&chip->client->dev,
+ "could not set brightness, %d\n", ret);
+}
+
+static void lp5521_blue_set(struct led_classdev *led,
+ enum led_brightness value)
+{
+ struct lp5521_chip *chip =
+ container_of(led, struct lp5521_chip, ledb);
+
+ chip->blue = value;
+ schedule_work(&chip->blue_work);
+}
+
+/*--------------------------------------------------------------*/
+/* Probe, Attach, Remove */
+/*--------------------------------------------------------------*/
+
+static int __init lp5521_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lp5521_platform_data *pdata = client->dev.platform_data;
+ struct lp5521_chip *chip;
+ char name[16];
+ int ret = 0;
+
+ if (!pdata) {
+ dev_err(&client->dev, "platform_data is missing\n");
+ return -EINVAL;
+ }
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->client = client;
+ strncpy(client->name, LP5521_DRIVER_NAME, I2C_NAME_SIZE);
+ i2c_set_clientdata(client, chip);
+
+ mutex_init(&chip->lock);
+
+ INIT_WORK(&chip->red_work, lp5521_red_work);
+ INIT_WORK(&chip->green_work, lp5521_green_work);
+ INIT_WORK(&chip->blue_work, lp5521_blue_work);
+
+ ret = lp5521_configure(client);
+ if (ret < 0) {
+ dev_err(&client->dev, "lp5521 error configuring chip \n");
+ goto fail1;
+ }
+
+ /* Set default values */
+ chip->mode = pdata->mode;
+ chip->red = pdata->red_present;
+ chip->green = pdata->green_present;
+ chip->blue = pdata->blue_present;
+
+ chip->ledr.brightness_set = lp5521_red_set;
+ chip->ledr.default_trigger = NULL;
+ snprintf(name, sizeof(name), "%s::red", pdata->label);
+ chip->ledr.name = name;
+ ret = led_classdev_register(&client->dev, &chip->ledr);
+ if (ret < 0) {
+ dev_dbg(&client->dev, "failed to register led %s, %d\n",
+ chip->ledb.name, ret);
+ goto fail1;
+ }
+
+ chip->ledg.brightness_set = lp5521_green_set;
+ chip->ledg.default_trigger = NULL;
+ snprintf(name, sizeof(name), "%s::green", pdata->label);
+ chip->ledg.name = name;
+ ret = led_classdev_register(&client->dev, &chip->ledg);
+ if (ret < 0) {
+ dev_dbg(&client->dev, "failed to register led %s, %d\n",
+ chip->ledb.name, ret);
+ goto fail2;
+ }
+
+ chip->ledb.brightness_set = lp5521_blue_set;
+ chip->ledb.default_trigger = NULL;
+ snprintf(name, sizeof(name), "%s::blue", pdata->label);
+ chip->ledb.name = name;
+ ret = led_classdev_register(&client->dev, &chip->ledb);
+ if (ret < 0) {
+ dev_dbg(&client->dev, "failed to register led %s, %d\n",
+ chip->ledb.name, ret);
+ goto fail3;
+ }
+
+ ret = lp5521_register_sysfs(client);
+ if (ret) {
+ dev_err(&client->dev,
+ "lp5521 registering sysfs failed \n");
+ goto fail4;
+ }
+
+ return 0;
+
+fail4:
+ led_classdev_unregister(&chip->ledb);
+fail3:
+ led_classdev_unregister(&chip->ledg);
+fail2:
+ led_classdev_unregister(&chip->ledr);
+fail1:
+ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+
+ return ret;
+}
+
+static int __exit lp5521_remove(struct i2c_client *client)
+{
+ struct lp5521_chip *chip = i2c_get_clientdata(client);
+
+ lp5521_unregister_sysfs(client);
+ i2c_set_clientdata(client, NULL);
+
+ led_classdev_unregister(&chip->ledb);
+ led_classdev_unregister(&chip->ledg);
+ led_classdev_unregister(&chip->ledr);
+
+ kfree(chip);
+
+ return 0;
+}
+
+static const struct i2c_device_id lp5521_id[] = {
+ {LP5521_DRIVER_NAME, 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, lp5521_id);
+
+static struct i2c_driver lp5521_driver = {
+ .driver = {
+ .name = LP5521_DRIVER_NAME,
+ },
+ .probe = lp5521_probe,
+ .remove = __exit_p(lp5521_remove),
+ .id_table = lp5521_id,
+};
+
+static int __init lp5521_init(void)
+{
+ return i2c_add_driver(&lp5521_driver);
+}
+
+module_init(lp5521_init);
+
+static void __exit lp5521_exit(void)
+{
+ i2c_del_driver(&lp5521_driver);
+}
+
+module_exit(lp5521_exit);
+
+MODULE_AUTHOR("Mathias Nyman <mathias.nyman@xxxxxxxxx>");
+MODULE_DESCRIPTION("lp5521 LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index da3fa8dcdf5..a8bf77af0ee 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -27,6 +27,7 @@ struct led_pwm_data {
struct led_classdev cdev;
struct pwm_device *pwm;
unsigned int active_low;
+ unsigned int lth_brightness;
unsigned int period;
};
@@ -42,7 +43,10 @@ static void led_pwm_set(struct led_classdev *led_cdev,
pwm_config(led_dat->pwm, 0, period);
pwm_disable(led_dat->pwm);
} else {
- pwm_config(led_dat->pwm, brightness * period / max, period);
+ brightness = led_dat->lth_brightness + (brightness *
+ (led_dat->period - led_dat->lth_brightness) / max);
+ pwm_config(led_dat->pwm, brightness, led_dat->period);
+
pwm_enable(led_dat->pwm);
}
}
@@ -78,6 +82,8 @@ static int led_pwm_probe(struct platform_device *pdev)
led_dat->cdev.default_trigger = cur_led->default_trigger;
led_dat->active_low = cur_led->active_low;
led_dat->period = cur_led->pwm_period_ns;
+ led_dat->lth_brightness = cur_led->lth_brightness *
+ (cur_led->pwm_period_ns / cur_led->max_brightness);
led_dat->cdev.brightness_set = led_pwm_set;
led_dat->cdev.brightness = LED_OFF;
led_dat->cdev.max_brightness = cur_led->max_brightness;
diff --git a/drivers/media/radio/CG2900/Makefile b/drivers/media/radio/CG2900/Makefile
new file mode 100644
index 00000000000..c0cd99372da
--- /dev/null
+++ b/drivers/media/radio/CG2900/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the CG2900 FM Radio Driver
+#
+
+radio_cg2900-objs := radio-cg2900.o cg2900_fm_api.o cg2900_fm_driver.o
+
+obj-$(CONFIG_RADIO_CG2900) += radio_cg2900.o
+
diff --git a/drivers/media/radio/CG2900/cg2900_fm_api.c b/drivers/media/radio/CG2900/cg2900_fm_api.c
new file mode 100644
index 00000000000..248802165e1
--- /dev/null
+++ b/drivers/media/radio/CG2900/cg2900_fm_api.c
@@ -0,0 +1,2973 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Linux FM Host API's for ST-Ericsson FM Chip.
+ *
+ * Author: Hemant Gupta <hemant.gupta@stericsson.com> for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/kthread.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include "cg2900_fm_driver.h"
+
+#define CG2900_FM_BT_SRC_COEFF_INFO_FILE "cg2900_fm_bt_src_coeff_info.fw"
+#define CG2900_FM_EXT_SRC_COEFF_INFO_FILE "cg2900_fm_ext_src_coeff_info.fw"
+#define CG2900_FM_FM_COEFF_INFO_FILE "cg2900_fm_fm_coeff_info.fw"
+#define CG2900_FM_FM_PROG_INFO_FILE "cg2900_fm_fm_prog_info.fw"
+#define CG2900_FM_LINE_BUFFER_LENGTH 128
+#define CG2900_FM_FILENAME_MAX 128
+#define FW_FILE_PARAM_LEN 3
+/* RDS Tx PTY set to Other music */
+#define OTHER_MUSIC 15
+
+static bool fm_rds_status;
+static bool fm_prev_rds_status;
+static u16 program_identification_code;
+static u16 default_program_identification_code = 0x1234;
+static u16 program_type_code;
+static u16 default_program_type_code = OTHER_MUSIC;
+static char program_service[MAX_PSN_SIZE];
+static char default_program_service[MAX_PSN_SIZE] = "FM-Xmit ";
+static char radio_text[MAX_RT_SIZE];
+static char default_radio_text[MAX_RT_SIZE] = "Default Radio Text "
+ "Default Radio Text Default Radio Text Default";
+static bool a_b_flag;
+u8 fm_event;
+static struct mutex rds_mutex;
+struct cg2900_fm_rds_buf fm_rds_buf[MAX_RDS_BUFFER][MAX_RDS_GROUPS];
+struct cg2900_fm_rds_info fm_rds_info;
+static enum cg2900_fm_state fm_state;
+static enum cg2900_fm_mode fm_mode;
+static struct cg2900_version_info version_info;
+
+/**
+ * cg2900_fm_get_one_line_of_text()- Get One line of text from a file.
+ *
+ * Replacement function for stdio function fgets.This function extracts one
+ * line of text from input file.
+ *
+ * @wr_buffer: Buffer to copy text to.
+ * @max_nbr_of_bytes: Max number of bytes to read, i.e. size of rd_buffer.
+ * @rd_buffer: Data to parse.
+ * @bytes_copied: Number of bytes copied to wr_buffer.
+ *
+ * Returns:
+ * Pointer to next data to read.
+ */
+static char *cg2900_fm_get_one_line_of_text(
+ char *wr_buffer,
+ int max_nbr_of_bytes,
+ char *rd_buffer,
+ int *bytes_copied
+ )
+{
+ char *curr_wr = wr_buffer;
+ char *curr_rd = rd_buffer;
+ char in_byte;
+
+ *bytes_copied = 0;
+
+ do {
+ *curr_wr = *curr_rd;
+ in_byte = *curr_wr;
+ curr_wr++;
+ curr_rd++;
+ (*bytes_copied)++;
+ } while ((*bytes_copied <= max_nbr_of_bytes) && (in_byte != '\0')
+ && (in_byte != '\n'));
+ *curr_wr = '\0';
+ return curr_rd;
+}
+
+/**
+ * cg2900_fm_get_file_to_load() - Parse info file and find correct target file.
+ *
+ * @fw: Firmware structure containing file data.
+ * @file_name: (out) Pointer to name of requested file.
+ *
+ * Returns:
+ * True, if target file was found,
+ * False, otherwise.
+ */
+static bool cg2900_fm_get_file_to_load(
+ const struct firmware *fw,
+ char **file_name
+ )
+{
+ char *line_buffer;
+ char *curr_file_buffer;
+ int bytes_left_to_parse = fw->size;
+ int bytes_read = 0;
+ bool file_found = false;
+
+ curr_file_buffer = (char *)&(fw->data[0]);
+
+ line_buffer = kmalloc(CG2900_FM_LINE_BUFFER_LENGTH,
+ GFP_KERNEL);
+
+ if (line_buffer == NULL) {
+ FM_ERR_REPORT("Failed to allocate:"
+ "file_name 0x%X, line_buffer 0x%X",
+ (unsigned int)file_name,
+ (unsigned int)line_buffer);
+ goto error;
+ }
+
+ while (!file_found) {
+ /* Get one line of text from the file to parse */
+ curr_file_buffer =
+ cg2900_fm_get_one_line_of_text(line_buffer,
+ min
+ (CG2900_FM_LINE_BUFFER_LENGTH,
+ (int)(fw->size -
+ bytes_read)),
+ curr_file_buffer,
+ &bytes_read);
+
+ bytes_left_to_parse -= bytes_read;
+ if (bytes_left_to_parse <= 0) {
+ /* End of file => Leave while loop */
+ FM_ERR_REPORT("Reached end of file."
+ "No file found!");
+ break;
+ }
+
+ /*
+ * Check if the line of text is a comment
+ * or not, comments begin with '#'
+ */
+ if (*line_buffer != '#') {
+ u32 hci_rev = 0;
+ u32 lmp_sub = 0;
+
+ FM_DEBUG_REPORT("Found a valid line <%s>",
+ line_buffer);
+
+ /*
+ * Check if we can find the correct
+ * HCI revision and LMP subversion
+ * as well as a file name in the text line
+ * Store the filename if the actual file can
+ * be found in the file system
+ */
+ if (sscanf(line_buffer, "%x%x%s",
+ (unsigned int *)&hci_rev,
+ (unsigned int *)&lmp_sub,
+ *file_name) == FW_FILE_PARAM_LEN
+ && hci_rev == version_info.revision
+ && lmp_sub == version_info.sub_version) {
+ FM_INFO_REPORT("File name = %s "
+ "HCI Revision"
+ "= 0x%04X LMP "
+ "Subversion = 0x%04X",
+ *file_name,
+ (unsigned int)hci_rev,
+ (unsigned int)lmp_sub);
+
+ /*
+ * Name has already been stored above.
+ * Nothing more to do
+ */
+ file_found = true;
+ } else {
+ /*Zero the name buffer so it is clear to next read*/
+ memset(*file_name, 0x00,
+ CG2900_FM_FILENAME_MAX);
+ }
+ }
+ }
+ kfree(line_buffer);
+error:
+ return file_found;
+}
+
+/**
+ * cg2900_fm_load_firmware() - Loads the FM Coeffecients and F/W file(s)
+ *
+ * @device: Pointer to char device requesting the operation.
+ *
+ * Returns:
+ * 0, if firmware download is successful
+ * -ENOENT, file not found.
+ * -ENOMEM, out of memory
+ */
+static int cg2900_fm_load_firmware(
+ struct device *device
+ )
+{
+ int err;
+ bool file_found;
+ int result = 0;
+ const struct firmware *bt_src_coeff_info;
+ const struct firmware *ext_src_coeff_info;
+ const struct firmware *fm_coeff_info;
+ const struct firmware *fm_prog_info;
+ char *bt_src_coeff_file_name = NULL;
+ char *ext_src_coeff_file_name = NULL;
+ char *fm_coeff_file_name = NULL;
+ char *fm_prog_file_name = NULL;
+
+ FM_INFO_REPORT("+cg2900_fm_load_firmware");
+
+ /* Open bt_src_coeff info file. */
+ err = request_firmware(&bt_src_coeff_info,
+ CG2900_FM_BT_SRC_COEFF_INFO_FILE, device);
+ if (err) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't get bt_src_coeff info file");
+ result = -ENOENT;
+ goto error;
+ }
+
+ /*
+ * Now we have the bt_src_coeff info file.
+ * See if we can find the right bt_src_coeff file as well
+ */
+ bt_src_coeff_file_name = kmalloc(CG2900_FM_FILENAME_MAX,
+ GFP_KERNEL);
+ if (bt_src_coeff_file_name == NULL) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't allocate memory for "
+ "bt_src_coeff_file_name");
+ release_firmware(bt_src_coeff_info);
+ result = -ENOMEM;
+ goto error;
+ }
+ file_found = cg2900_fm_get_file_to_load(bt_src_coeff_info,
+ &bt_src_coeff_file_name);
+
+ /* Now we are finished with the bt_src_coeff info file */
+ release_firmware(bt_src_coeff_info);
+
+ if (!file_found) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't find bt_src_coeff file!! "
+ "Major error!!!");
+ result = -ENOENT;
+ goto error;
+ }
+
+ /* Open ext_src_coeff info file. */
+ err = request_firmware(&ext_src_coeff_info,
+ CG2900_FM_EXT_SRC_COEFF_INFO_FILE, device);
+ if (err) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't get ext_src_coeff_info info file");
+ result = -ENOENT;
+ goto error;
+ }
+
+ /*
+ * Now we have the ext_src_coeff info file. See if we can
+ * find the right ext_src_coeff file as well
+ */
+ ext_src_coeff_file_name = kmalloc(CG2900_FM_FILENAME_MAX,
+ GFP_KERNEL);
+ if (ext_src_coeff_file_name == NULL) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't allocate memory for "
+ "ext_src_coeff_file_name");
+ release_firmware(ext_src_coeff_info);
+ result = -ENOMEM;
+ goto error;
+ }
+ file_found = cg2900_fm_get_file_to_load(ext_src_coeff_info,
+ &ext_src_coeff_file_name);
+
+ /* Now we are finished with the ext_src_coeff info file */
+ release_firmware(ext_src_coeff_info);
+
+ if (!file_found) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't find ext_src_coeff_info "
+ "file!!! Major error!");
+ result = -ENOENT;
+ goto error;
+ }
+
+ /* Open fm_coeff info file. */
+ err = request_firmware(&fm_coeff_info,
+ CG2900_FM_FM_COEFF_INFO_FILE, device);
+ if (err) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't get fm_coeff info file");
+ result = -ENOENT;
+ goto error;
+ }
+
+ /*
+ * Now we have the fm_coeff_info info file.
+ * See if we can find the right fm_coeff_info file as well
+ */
+ fm_coeff_file_name = kmalloc(CG2900_FM_FILENAME_MAX,
+ GFP_KERNEL);
+ if (fm_coeff_file_name == NULL) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't allocate memory for "
+ "fm_coeff_file_name");
+ release_firmware(fm_coeff_info);
+ result = -ENOMEM;
+ goto error;
+ }
+ file_found = cg2900_fm_get_file_to_load(fm_coeff_info,
+ &fm_coeff_file_name);
+
+ /* Now we are finished with the fm_coeff info file */
+ release_firmware(fm_coeff_info);
+
+ if (!file_found) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't find fm_coeff file!!! "
+ "Major error!");
+ result = -ENOENT;
+ goto error;
+ }
+
+ /* Open fm_prog info file. */
+ err = request_firmware(&fm_prog_info,
+ CG2900_FM_FM_PROG_INFO_FILE, device);
+ if (err) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't get fm_prog_info info file");
+ result = -ENOENT;
+ goto error;
+ }
+
+ /*
+ * Now we have the fm_prog info file.
+ * See if we can find the right fm_prog file as well
+ */
+ fm_prog_file_name = kmalloc(CG2900_FM_FILENAME_MAX,
+ GFP_KERNEL);
+ if (fm_prog_file_name == NULL) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't allocate memory for "
+ "fm_prog_file_name");
+ release_firmware(fm_prog_info);
+ result = -ENOMEM;
+ goto error;
+ }
+ file_found = cg2900_fm_get_file_to_load(fm_prog_info,
+ &fm_prog_file_name);
+
+ /* Now we are finished with fm_prog patch info file */
+ release_firmware(fm_prog_info);
+
+ if (!file_found) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't find fm_prog_info file!!! "
+ "Major error!");
+ result = -ENOENT;
+ goto error;
+ }
+
+ /* OK. Now it is time to download the firmware */
+ err = request_firmware(&bt_src_coeff_info,
+ bt_src_coeff_file_name, device);
+ if (err < 0) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't get bt_src_coeff file, err = %d", err);
+ result = -ENOENT;
+ goto error;
+ }
+
+ FM_INFO_REPORT("cg2900_fm_load_firmware: Downloading %s of %d bytes",
+ bt_src_coeff_file_name, bt_src_coeff_info->size);
+ if (fmd_send_fm_firmware((u8 *) bt_src_coeff_info->data,
+ bt_src_coeff_info->size)) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: Error in "
+ "downloading %s", bt_src_coeff_file_name);
+ release_firmware(bt_src_coeff_info);
+ result = -ENOENT;
+ goto error;
+ }
+
+ /* Now we are finished with the bt_src_coeff info file */
+ release_firmware(bt_src_coeff_info);
+ err = request_firmware(&ext_src_coeff_info,
+ ext_src_coeff_file_name, device);
+ if (err < 0) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't get ext_src_coeff file, err = %d", err);
+ result = -ENOENT;
+ goto error;
+ }
+
+ FM_INFO_REPORT("cg2900_fm_load_firmware: Downloading %s of %d bytes",
+ ext_src_coeff_file_name, ext_src_coeff_info->size);
+ if (fmd_send_fm_firmware((u8 *) ext_src_coeff_info->data,
+ ext_src_coeff_info->size)) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: Error in "
+ "downloading %s", ext_src_coeff_file_name);
+ release_firmware(ext_src_coeff_info);
+ result = -ENOENT;
+ goto error;
+ }
+
+ /* Now we are finished with the bt_src_coeff info file */
+ release_firmware(ext_src_coeff_info);
+
+ err = request_firmware(&fm_coeff_info, fm_coeff_file_name, device);
+ if (err < 0) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't get fm_coeff file, err = %d", err);
+ result = -ENOENT;
+ goto error;
+ }
+
+ FM_INFO_REPORT("cg2900_fm_load_firmware: Downloading %s of %d bytes",
+ fm_coeff_file_name, fm_coeff_info->size);
+ if (fmd_send_fm_firmware((u8 *) fm_coeff_info->data,
+ fm_coeff_info->size)) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: Error in "
+ "downloading %s", fm_coeff_file_name);
+ release_firmware(fm_coeff_info);
+ result = -ENOENT;
+ goto error;
+ }
+
+ /* Now we are finished with the bt_src_coeff info file */
+ release_firmware(fm_coeff_info);
+
+ err = request_firmware(&fm_prog_info, fm_prog_file_name, device);
+ if (err < 0) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: "
+ "Couldn't get fm_prog file, err = %d", err);
+ result = -ENOENT;
+ goto error;
+ }
+
+ FM_INFO_REPORT("cg2900_fm_load_firmware: Downloading %s of %d bytes",
+ fm_prog_file_name, fm_prog_info->size);
+ if (fmd_send_fm_firmware((u8 *) fm_prog_info->data,
+ fm_prog_info->size)) {
+ FM_ERR_REPORT("cg2900_fm_load_firmware: Error in "
+ "downloading %s", fm_prog_file_name);
+ release_firmware(fm_prog_info);
+ result = -ENOENT;
+ goto error;
+ }
+
+ /* Now we are finished with the bt_src_coeff info file */
+ release_firmware(fm_prog_info);
+
+error:
+ /* Free Allocated memory */
+ if (bt_src_coeff_file_name != NULL)
+ kfree(bt_src_coeff_file_name);
+ if (ext_src_coeff_file_name != NULL)
+ kfree(ext_src_coeff_file_name);
+ if (fm_coeff_file_name != NULL)
+ kfree(fm_coeff_file_name);
+ if (fm_prog_file_name != NULL)
+ kfree(fm_prog_file_name);
+ FM_DEBUG_REPORT("-cg2900_fm_load_firmware: returning %d",
+ result);
+ return result;
+}
+
+/**
+ * cg2900_fm_transmit_rds_groups()- Transmits the RDS Groups.
+ *
+ * Stores the RDS Groups in Chip's buffer and each group is
+ * transmitted every 87.6 ms.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise
+ */
+static int cg2900_fm_transmit_rds_groups(void)
+{
+ int result = 0;
+ u16 group_position = 0;
+ u8 block1[2];
+ u8 block2[2];
+ u8 block3[2];
+ u8 block4[2];
+ int index1 = 0;
+ int index2 = 0;
+ int group_0B_count = 0;
+ int group_2A_count = 0;
+
+ FM_INFO_REPORT("cg2900_fm_transmit_rds_groups");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_transmit_rds_groups: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ while (group_position < 20 && result == 0) {
+ if (group_position < 4) {
+ /* Transmit PSN in Group 0B */
+ block1[0] = program_identification_code;
+ block1[1] = program_identification_code >> 8;
+ /* M/S bit set to Music */
+ if (group_0B_count % 4 == 0) {
+ /* Manipulate DI bit */
+ block2[0] =
+ (0x08 | ((program_type_code & 0x07)
+ << 5))
+ + group_0B_count;
+ } else {
+ block2[0] =
+ (0x0C | ((program_type_code & 0x07)
+ << 5))
+ + group_0B_count;
+ }
+ block2[1] =
+ 0x08 | ((program_type_code & 0x18) >> 3);
+ block3[0] = program_identification_code;
+ block3[1] = program_identification_code >> 8;
+ block4[0] = program_service[index1 + 1];
+ block4[1] = program_service[index1 + 0];
+ index1 += 2;
+ group_0B_count++;
+ } else {
+ /* Transmit RT in Group 2A */
+ block1[0] = program_identification_code;
+ block1[1] = program_identification_code >> 8;
+ if (a_b_flag)
+ block2[0] = (0x10 |
+ ((program_type_code & 0x07)
+ << 5)) + group_2A_count;
+ else
+ block2[0] = (0x00 |
+ ((program_type_code & 0x07)
+ << 5)) + group_2A_count;
+ block2[1] = 0x20 | ((program_type_code & 0x18)
+ >> 3);
+ block3[0] = radio_text[index2 + 1];
+ block3[1] = radio_text[index2 + 0];
+ block4[0] = radio_text[index2 + 3];
+ block4[1] = radio_text[index2 + 2];
+ index2 += 4;
+ group_2A_count++;
+ }
+ FM_DEBUG_REPORT("%02x%02x "
+ "%02x%02x "
+ "%02x%02x "
+ "%02x%02x ",
+ block1[1], block1[0],
+ block2[1], block2[0],
+ block3[1], block3[0],
+ block4[1], block4[0]);
+ result = fmd_tx_set_group(
+ group_position,
+ block1,
+ block2,
+ block3,
+ block4);
+ group_position++;
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_transmit_rds_groups: "
+ "fmd_tx_set_group failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ break;
+ }
+ }
+ a_b_flag = !a_b_flag;
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_transmit_rds_groups: returning %d",
+ result);
+ return result;
+}
+
+/**
+ * cg2900_fm_driver_callback()- Callback function indicating the event.
+ *
+ * This callback function is called on receiving irpt_CommandSucceeded,
+ * irpt_CommandFailed, irpt_bufferFull, etc from FM chip.
+ * @event: event for which the callback function was caled
+ * from FM Driver.
+ * @event_successful: Signifying whether the event is called from FM Driver
+ * on receiving irpt_OperationSucceeded or irpt_OperationFailed.
+ */
+static void cg2900_fm_driver_callback(
+ u8 event,
+ bool event_successful
+ )
+{
+ FM_INFO_REPORT("cg2900_fm_driver_callback: "
+ "event = %02x, event_successful = %x",
+ event, event_successful);
+
+ if (event_successful) {
+ switch (event) {
+ case FMD_EVENT_GEN_POWERUP:
+ FM_DEBUG_REPORT("FMD_EVENT_GEN_POWERUP");
+ break;
+ case FMD_EVENT_ANTENNA_STATUS_CHANGED:
+ FM_DEBUG_REPORT("FMD_EVENT_ANTENNA_STATUS_CHANGED");
+ break;
+ case FMD_EVENT_FREQUENCY_CHANGED:
+ FM_DEBUG_REPORT("FMD_EVENT_FREQUENCY_CHANGED ");
+ break;
+
+ case FMD_EVENT_SEEK_STOPPED:
+ FM_DEBUG_REPORT("FMD_EVENT_SEEK_STOPPED");
+ fm_event = CG2900_EVENT_SCAN_CANCELLED;
+ wake_up_poll_queue();
+ break;
+
+ case FMD_EVENT_SEEK_COMPLETED:
+ FM_DEBUG_REPORT("FMD_EVENT_SEEK_COMPLETED");
+ fm_event = CG2900_EVENT_SEARCH_CHANNEL_FOUND;
+ wake_up_poll_queue();
+ break;
+
+ case FMD_EVENT_SCAN_BAND_COMPLETED:
+ FM_DEBUG_REPORT("FMD_EVENT_SCAN_BAND_COMPLETED");
+ fm_event = CG2900_EVENT_SCAN_CHANNELS_FOUND;
+ wake_up_poll_queue();
+ break;
+
+ case FMD_EVENT_BLOCK_SCAN_COMPLETED:
+ FM_DEBUG_REPORT("FMD_EVENT_BLOCK_SCAN_COMPLETED");
+ fm_event = CG2900_EVENT_BLOCK_SCAN_CHANNELS_FOUND;
+ wake_up_poll_queue();
+ break;
+
+ case FMD_EVENT_AF_UPDATE_SWITCH_COMPLETE:
+ FM_DEBUG_REPORT("FMD_EVENT_AF_UPDATE_SWITCH_COMPLETE");
+ break;
+
+ case FMD_EVENT_RDSGROUP_RCVD:
+ FM_DEBUG_REPORT("FMD_EVENT_RDSGROUP_RCVD");
+ fmd_set_rds_sem();
+ break;
+
+ default:
+ FM_INFO_REPORT("cg2900_fm_driver_callback: "
+ "Unknown event = %x", event);
+ break;
+ }
+ } else {
+ switch (event) {
+ /*
+ * Seek stop, band scan, seek, block scan could
+ * fail for some reason so wake up poll queue
+ */
+ case FMD_EVENT_SEEK_STOPPED:
+ FM_ERR_REPORT("FMD_EVENT_SEEK_STOPPED");
+ fm_event = CG2900_EVENT_SCAN_CANCELLED;
+ wake_up_poll_queue();
+ break;
+ case FMD_EVENT_SEEK_COMPLETED:
+ FM_ERR_REPORT("FMD_EVENT_SEEK_COMPLETED");
+ fm_event = CG2900_EVENT_SEARCH_CHANNEL_FOUND;
+ wake_up_poll_queue();
+ break;
+ case FMD_EVENT_SCAN_BAND_COMPLETED:
+ FM_ERR_REPORT("FMD_EVENT_SCAN_BAND_COMPLETED");
+ fm_event = CG2900_EVENT_SCAN_CHANNELS_FOUND;
+ wake_up_poll_queue();
+ break;
+ case FMD_EVENT_BLOCK_SCAN_COMPLETED:
+ FM_ERR_REPORT("FMD_EVENT_BLOCK_SCAN_COMPLETED");
+ fm_event = CG2900_EVENT_BLOCK_SCAN_CHANNELS_FOUND;
+ wake_up_poll_queue();
+ break;
+ default:
+ FM_ERR_REPORT("cg2900_fm_driver_callback: "
+ "event = %x failed!!!!", event);
+ break;
+ }
+ }
+}
+
+/**
+ * cg2900_fm_rds_callback()- Function to retrieve the RDS groups.
+ *
+ * This is called when the chip has received enough RDS groups
+ * so an interrupt irpt_BufferFull is generated to read the groups.
+ */
+static void cg2900_fm_rds_callback(void)
+{
+ u8 index = 0;
+ u16 rds_local_buf_count;
+ int result;
+ FM_INFO_REPORT("cg2900_fm_rds_callback");
+
+ /*
+ * Wait till interrupt is RDS Buffer
+ * full interrupt is received
+ */
+ fmd_get_rds_sem();
+
+ if (!fm_rds_status)
+ return;
+
+ /* RDS Data available, Read the Groups */
+ mutex_lock(&rds_mutex);
+ result = fmd_int_bufferfull(&rds_local_buf_count);
+
+ if (0 != result)
+ goto error;
+
+ while (index < rds_local_buf_count) {
+ /*
+ * Status are in reverse order because of Endianness
+ * of status byte received from chip
+ */
+ result = fmd_rx_get_low_level_rds_groups(
+ index,
+ &fm_rds_buf[fm_rds_info.rds_head][index].block1,
+ &fm_rds_buf[fm_rds_info.rds_head][index].block2,
+ &fm_rds_buf[fm_rds_info.rds_head][index].block3,
+ &fm_rds_buf[fm_rds_info.rds_head][index].block4,
+ &fm_rds_buf[fm_rds_info.rds_head][index].status2,
+ &fm_rds_buf[fm_rds_info.rds_head][index].status1,
+ &fm_rds_buf[fm_rds_info.rds_head][index].status4,
+ &fm_rds_buf[fm_rds_info.rds_head][index].status3);
+ FM_INFO_REPORT("%04x %04x %04x %04x %02x %02x %02x %02x",
+ fm_rds_buf[fm_rds_info.rds_head][index].block1,
+ fm_rds_buf[fm_rds_info.rds_head][index].block2,
+ fm_rds_buf[fm_rds_info.rds_head][index].block3,
+ fm_rds_buf[fm_rds_info.rds_head][index].block4,
+ fm_rds_buf[fm_rds_info.rds_head][index].status1,
+ fm_rds_buf[fm_rds_info.rds_head][index].status2,
+ fm_rds_buf[fm_rds_info.rds_head][index].status3,
+ fm_rds_buf[fm_rds_info.rds_head][index].status4);
+
+ if (0 != result)
+
+ goto error;
+
+ if (!fm_rds_status)
+ return;
+
+ index++;
+ }
+ fm_rds_info.rds_head++;
+ if (fm_rds_info.rds_head == MAX_RDS_BUFFER)
+ fm_rds_info.rds_head = 0;
+ wake_up_read_queue();
+error:
+ mutex_unlock(&rds_mutex);
+}
+
+int cg2900_fm_init(void)
+{
+ int result = 0;
+
+ FM_INFO_REPORT("cg2900_fm_init");
+
+ if (CG2900_FM_STATE_DEINITIALIZED != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_init: Already Initialized");
+ result = -EINVAL;
+ goto error;
+ }
+
+ mutex_init(&rds_mutex);
+
+ memset(&fm_rds_info, 0, sizeof(struct cg2900_fm_rds_info));
+ memset(&version_info, 0, sizeof(struct cg2900_version_info));
+ memset(
+ fm_rds_buf,
+ 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+
+ /* Initalize the Driver */
+ if (fmd_init() != 0) {
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Register the callback */
+ if (fmd_register_callback(
+ (fmd_radio_cb) cg2900_fm_driver_callback) != 0) {
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* initialize global variables */
+ fm_event = CG2900_EVENT_NO_EVENT;
+ fm_state = CG2900_FM_STATE_INITIALIZED;
+ fm_mode = CG2900_FM_IDLE_MODE;
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_init: returning %d",
+ result);
+ return result;
+
+}
+
+int cg2900_fm_deinit(void)
+{
+ int result = 0;
+
+ FM_INFO_REPORT("cg2900_fm_deinit");
+
+ if (CG2900_FM_STATE_INITIALIZED != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_deinit: Already de-Initialized");
+ result = -EINVAL;
+ goto error;
+ }
+ fmd_exit();
+ mutex_destroy(&rds_mutex);
+ fm_state = CG2900_FM_STATE_DEINITIALIZED;
+ fm_mode = CG2900_FM_IDLE_MODE;
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_deinit: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_switch_on(
+ struct device *device
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_switch_on");
+
+ if (CG2900_FM_STATE_INITIALIZED != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_switch_on: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ /* Enable FM IP */
+ FM_DEBUG_REPORT("cg2900_fm_switch_on: " "Sending FM IP Enable");
+
+ if (fmd_send_fm_ip_enable()) {
+ FM_ERR_REPORT("cg2900_fm_switch_on: "
+ "Error in fmd_send_fm_ip_enable");
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Now Download the Coefficient Files and FM Firmware */
+ if (cg2900_fm_load_firmware(device) != 0) {
+ FM_ERR_REPORT("cg2900_fm_switch_on: "
+ "Error in downloading firmware");
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Power up FM */
+ result = fmd_power_up();
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_switch_on: "
+ "fmd_power_up failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Switch Mode To Idle */
+ result = fmd_set_mode(FMD_MODE_IDLE);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_switch_on: "
+ "fmd_set_mode failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Enable the Ref Clk */
+ FM_DEBUG_REPORT("cg2900_fm_switch_on: "
+ "Sending fmd_select_ref_clk");
+ result = fmd_select_ref_clk(0x0001);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_switch_on: "
+ "fmd_select_ref_clk failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Select the Frequency of Ref Clk (28 MHz) */
+ FM_DEBUG_REPORT("cg2900_fm_switch_on: "
+ "Sending fmd_set_ref_clk_pll");
+ result = fmd_set_ref_clk_pll(0x32C8);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_switch_on: "
+ "fmd_select_ref_clk_pll failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ fm_state = CG2900_FM_STATE_SWITCHED_ON;
+ fm_mode = CG2900_FM_IDLE_MODE;
+ memset(&fm_rds_info, 0, sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_switch_on: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_switch_off(void)
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_switch_off");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state ||
+ CG2900_FM_STATE_STAND_BY != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_switch_off: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ /* Stop the RDS Thread if it is running */
+ if (fm_rds_status) {
+ fm_rds_status = false;
+ fmd_stop_rds_thread();
+ }
+ result = fmd_goto_power_down();
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_switch_off: "
+ "fmd_goto_power_down failed = %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ if (0 == result) {
+ if (fmd_send_fm_ip_disable()) {
+ FM_ERR_REPORT("cg2900_fm_switch_off: "
+ "Problem in fmd_send_fm_ip_"
+ "disable");
+ result = -EINVAL;
+ goto error;
+ }
+ }
+ if (0 == result) {
+ fm_state = CG2900_FM_STATE_INITIALIZED;
+ fm_mode = CG2900_FM_IDLE_MODE;
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_switch_off: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_standby(void)
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_standby");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_standby: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_goto_standby();
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_standby: "
+ "FMLGotoStandby failed, "
+ "err = %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ fm_state = CG2900_FM_STATE_STAND_BY;
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_standby: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_power_up_from_standby(void)
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_power_up_from_standby");
+
+ if (CG2900_FM_STATE_STAND_BY != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_power_up_from_standby: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ /* Power up FM */
+ result = fmd_power_up();
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_power_up_from_standby: "
+ "fmd_power_up failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ } else {
+ fm_state = CG2900_FM_STATE_SWITCHED_ON;
+ if (CG2900_FM_TX_MODE == fm_mode) {
+ /* Enable the PA */
+ result = fmd_tx_set_pa(true);
+ if (0 != result) {
+ FM_ERR_REPORT
+ ("cg2900_fm_power_up_from_standby:"
+ " fmd_tx_set_pa " "failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ }
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_power_up_from_standby: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_set_rx_default_settings(
+ u32 freq,
+ u8 band,
+ u8 grid,
+ bool enable_rds,
+ bool enable_stereo
+ )
+{
+ int result;
+ u8 vol_in_percentage;
+
+ FM_INFO_REPORT("cg2900_fm_set_rx_default_settings: freq = %d Hz, "
+ "band = %d, grid = %d, RDS = %d, Stereo Mode = %d",
+ freq, band, grid, enable_rds, enable_stereo);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_set_rx_default_settings: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ fm_mode = CG2900_FM_RX_MODE;
+
+ FM_DEBUG_REPORT("cg2900_fm_set_rx_default_settings: "
+ "Sending Set mode to Rx");
+ result = fmd_set_mode(FMD_MODE_RX);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_rx_default_settings: "
+ "fmd_set_mode failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Set the Grid */
+ FM_DEBUG_REPORT("cg2900_fm_set_rx_default_settings: "
+ "Sending fmd_rx_set_grid ");
+ result = fmd_rx_set_grid(grid);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_rx_default_settings: "
+ "fmd_rx_set_grid failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Set the Band */
+ FM_DEBUG_REPORT("cg2900_fm_set_rx_default_settings: "
+ "Sending Set fmd_set_freq_range");
+ result = fmd_set_freq_range(band);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_rx_default_settings: "
+ "fmd_set_freq_range failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Set the Frequency */
+ FM_DEBUG_REPORT("cg2900_fm_set_rx_default_settings: "
+ "Sending Set fmd_rx_set_frequency");
+ result = fmd_rx_set_frequency(
+ freq / FREQUENCY_CONVERTOR_KHZ_HZ);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_rx_default_settings: "
+ "fmd_rx_set_frequency failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ FM_DEBUG_REPORT("cg2900_fm_set_rx_default_settings: "
+ "SetFrequency interrupt received, "
+ "Sending Set fmd_rx_set_stereo_mode");
+
+ if (enable_stereo) {
+ /* Set the Stereo Blending mode */
+ result = fmd_rx_set_stereo_mode(
+ FMD_STEREOMODE_BLENDING);
+ } else {
+ /* Set the Mono mode */
+ result = fmd_rx_set_stereo_mode(
+ FMD_STEREOMODE_MONO);
+ }
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_rx_default_settings: "
+ "fmd_rx_set_stereo_mode "
+ "failed %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ FM_DEBUG_REPORT("cg2900_fm_set_rx_default_settings: "
+ "Sending Set rds");
+
+ if (enable_rds) {
+ /* Enable RDS */
+ a_b_flag = false;
+ result = cg2900_fm_rds_on();
+ } else {
+ /* Disable RDS */
+ result = cg2900_fm_rds_off();
+ }
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_rx_default_settings: "
+ "cg2900_fm_rds_on "
+ "failed %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Set the Analog Out Volume to Max */
+ vol_in_percentage = (u8)
+ (((u16) (MAX_ANALOG_VOLUME) * 100)
+ / MAX_ANALOG_VOLUME);
+ result = fmd_set_volume(vol_in_percentage);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_switch_on: "
+ "FMRSetVolume failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_set_rx_default_settings: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_set_tx_default_settings(
+ u32 freq,
+ u8 band,
+ u8 grid,
+ bool enable_rds,
+ bool enable_stereo
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_set_tx_default_settings: freq = %d Hz, "
+ "band = %d, grid = %d, RDS = %d, Stereo Mode = %d",
+ freq, band, grid, enable_rds, enable_stereo);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_set_tx_default_settings: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ fm_mode = CG2900_FM_TX_MODE;
+ if (fm_rds_status) {
+ fm_rds_status = false;
+ fmd_stop_rds_thread();
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ /* Give 50 ms delay to exit the rDS thread */
+ schedule_timeout_interruptible(msecs_to_jiffies(50));
+ }
+
+ /* Switch To Tx mode */
+ FM_DEBUG_REPORT("cg2900_fm_set_tx_default_settings: "
+ "Sending Set mode to Tx");
+ result = fmd_set_mode(FMD_MODE_TX);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_tx_default_settings: "
+ "fmd_set_mode failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Set the Grid */
+ FM_DEBUG_REPORT("cg2900_fm_set_tx_default_settings: "
+ "Sending fmd_tx_set_grid ");
+ result = fmd_tx_set_grid(grid);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_tx_default_settings: "
+ "fmd_tx_set_grid failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Set the Band */
+ FM_DEBUG_REPORT("cg2900_fm_set_tx_default_settings: "
+ "Sending fmd_tx_set_freq_range");
+ result = fmd_tx_set_freq_range(band);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_tx_default_settings: "
+ "fmd_tx_set_freq_range failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Set the Band */
+ FM_DEBUG_REPORT("cg2900_fm_set_tx_default_settings: "
+ "Sending fmd_tx_set_preemphasis");
+ result = fmd_tx_set_preemphasis(FMD_EMPHASIS_75US);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_switch_on: "
+ "fmd_tx_set_preemphasis failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Set the Frequency */
+ FM_DEBUG_REPORT("cg2900_fm_set_tx_default_settings: "
+ "Sending Set fmd_tx_set_frequency");
+ result = fmd_tx_set_frequency(
+ freq / FREQUENCY_CONVERTOR_KHZ_HZ);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_switch_on: "
+ "fmd_tx_set_frequency failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ FM_DEBUG_REPORT("cg2900_fm_set_tx_default_settings: "
+ "SetFrequency interrupt received, "
+ "Sending Set fmd_tx_enable_stereo_mode");
+
+ /* Set the Stereo mode */
+ result = fmd_tx_enable_stereo_mode(enable_stereo);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_tx_default_settings: "
+ "fmd_tx_enable_stereo_mode "
+ "failed %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ FM_DEBUG_REPORT("cg2900_fm_set_tx_default_settings: "
+ "Sending Set fmd_tx_set_pa");
+
+ /* Enable the PA */
+ result = fmd_tx_set_pa(true);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_tx_default_settings: "
+ "fmd_tx_set_pa "
+ "failed %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ FM_DEBUG_REPORT("cg2900_fm_set_tx_default_settings: "
+ "set PA interrupt received, "
+ "Sending Set fmd_tx_set_signal_strength");
+
+ /* Set the Signal Strength to Max */
+ result = fmd_tx_set_signal_strength(
+ MAX_POWER_LEVEL);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_tx_default_settings: "
+ "fmd_tx_set_signal_strength "
+ "failed %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Enable Tx RDS */
+ FM_DEBUG_REPORT("cg2900_fm_set_tx_default_settings: "
+ "Sending Set cg2900_fm_tx_rds");
+ result = cg2900_fm_tx_rds(enable_rds);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_tx_default_settings: "
+ "cg2900_fm_tx_rds "
+ "failed %x", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_set_tx_default_settings: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_set_grid(
+ u8 grid
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_set_grid: Grid = %d", grid);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_set_grid: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_rx_set_grid(grid);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_grid: "
+ "fmd_rx_set_grid failed");
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_set_grid: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_set_band(
+ u8 band
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_set_band: Band = %d", band);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_set_band: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_set_freq_range(band);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_band: "
+ "fmd_set_freq_range failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_set_band: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_search_up_freq(void)
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_search_up_freq");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_search_up_freq: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ if (fm_rds_status) {
+ /* Stop RDS if it is active */
+ result = cg2900_fm_rds_off();
+ fm_prev_rds_status = true;
+ }
+ result = fmd_rx_seek(CG2900_DIR_UP);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_search_up_freq: "
+ "Error Code %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ result = 0;
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_search_up_freq: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_search_down_freq(void)
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_search_down_freq");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_search_down_freq: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ if (fm_rds_status) {
+ /* Stop RDS if it is active */
+ result = cg2900_fm_rds_off();
+ fm_prev_rds_status = true;
+ }
+ result = fmd_rx_seek(CG2900_DIR_DOWN);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_search_down_freq: "
+ "Error Code %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ result = 0;
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_search_down_freq: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_start_band_scan(void)
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_start_band_scan");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_start_band_scan: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ if (fm_rds_status) {
+ /* Stop RDS if it is active */
+ result = cg2900_fm_rds_off();
+ fm_prev_rds_status = true;
+ }
+ result = fmd_rx_scan_band(DEFAULT_CHANNELS_TO_SCAN);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_start_band_scan: "
+ "Error Code %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ result = 0;
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_start_band_scan: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_stop_scan(void)
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_stop_scan");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_stop_scan: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_rx_stop_seeking();
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_stop_scan: "
+ "Error Code %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ result = 0;
+ if (fm_prev_rds_status) {
+ /* Restart RDS if it was active earlier */
+ cg2900_fm_rds_on();
+ fm_prev_rds_status = false;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_stop_scan: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_get_scan_result(
+ u16 *num_of_scanfreq,
+ u32 *scan_freq,
+ u32 *scan_freq_rssi_level
+ )
+{
+ int result;
+ u32 cnt;
+ u32 index;
+ u32 minfreq;
+ u32 maxfreq;
+ u16 channels[3];
+ u16 rssi[3];
+ u8 freq_range;
+ u8 max_channels = 0;
+
+ FM_INFO_REPORT("cg2900_fm_get_scan_result");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_get_scan_result: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_get_freq_range(&freq_range);
+
+ if (0 == result)
+ result = fmd_get_freq_range_properties(
+ freq_range,
+ &minfreq,
+ &maxfreq);
+ result =
+ fmd_rx_get_max_channels_to_scan(&max_channels);
+
+ if (0 != result) {
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* In 1 iteration we can retreive max 3 channels */
+ cnt = (max_channels / 3) + 1;
+ while ((cnt--) && (result == 0)) {
+ /*
+ * Get all channels, including empty ones.
+ * In 1 iteration at max 3 channels can be found.
+ */
+ result = fmd_rx_get_scan_band_info(cnt * 3,
+ num_of_scanfreq,
+ channels, rssi);
+ if (0 == result) {
+ index = cnt * 3;
+ /* Convert Freq to Hz from channel number */
+ scan_freq[index] = (minfreq +
+ channels[0] *
+ CHANNEL_FREQ_CONVERTER_MHZ) *
+ FREQUENCY_CONVERTOR_KHZ_HZ;
+ scan_freq_rssi_level[index] = rssi[0];
+ /* Convert Freq to Hz from channel number */
+ scan_freq[index + 1] = (minfreq +
+ channels[1] *
+ CHANNEL_FREQ_CONVERTER_MHZ) *
+ FREQUENCY_CONVERTOR_KHZ_HZ;
+ scan_freq_rssi_level[index + 1] = rssi[1];
+ /* Check if we donot overwrite the array */
+ if (cnt < (max_channels / 3)) {
+ /* Convert Freq to Hz from channel number */
+ scan_freq[index + 2] = (minfreq +
+ channels[2] *
+ CHANNEL_FREQ_CONVERTER_MHZ) *
+ FREQUENCY_CONVERTOR_KHZ_HZ;
+ scan_freq_rssi_level[index + 2]
+ = rssi[2];
+ }
+ }
+ }
+ if (fm_prev_rds_status) {
+ /* Restart RDS if it was active earlier */
+ result = cg2900_fm_rds_on();
+ fm_prev_rds_status = false;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_get_scan_result: returning %d",
+ result);
+ return result;
+
+}
+
+int cg2900_fm_start_block_scan(
+ u32 start_freq,
+ u32 end_freq
+ )
+{
+ int result;
+ u8 antenna;
+
+ FM_INFO_REPORT("cg2900_fm_start_block_scan");
+
+ FM_DEBUG_REPORT("cg2900_fm_start_block_scan: Start Freq = %d, "
+ "End Freq = %d", start_freq, end_freq);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_start_block_scan: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ if (fm_rds_status) {
+ /* Stop RDS if it is active */
+ result = cg2900_fm_rds_off();
+ fm_prev_rds_status = true;
+ }
+ result = fmd_get_antenna(
+ &antenna);
+ result = fmd_rx_block_scan(
+ start_freq/FREQUENCY_CONVERTOR_KHZ_HZ,
+ end_freq/FREQUENCY_CONVERTOR_KHZ_HZ,
+ antenna);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_start_block_scan: "
+ "Error Code %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ result = 0;
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_start_block_scan: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_get_block_scan_result(
+ u16 *num_of_scanchan,
+ u16 *scan_freq_rssi_level
+ )
+{
+ int result = 0;
+ u32 cnt;
+ u32 index;
+ u16 rssi[6];
+
+ FM_INFO_REPORT("cg2900_fm_get_block_scan_result");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_get_block_scan_result: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ cnt = 33;
+ while ((cnt--) && (result == 0)) {
+ /* Get all channels, including empty ones */
+ result = fmd_rx_get_block_scan_result(
+ cnt * 6,
+ num_of_scanchan,
+ rssi);
+ if (0 == result) {
+ index = cnt * 6;
+ scan_freq_rssi_level[index]
+ = rssi[0];
+ scan_freq_rssi_level[index + 1]
+ = rssi[1];
+ scan_freq_rssi_level[index + 2]
+ = rssi[2];
+ scan_freq_rssi_level[index + 3]
+ = rssi[3];
+ scan_freq_rssi_level[index + 4]
+ = rssi[4];
+ scan_freq_rssi_level[index + 5]
+ = rssi[5];
+ }
+ }
+ if (CG2900_FM_RX_MODE == fm_mode) {
+ if (fm_prev_rds_status) {
+ /* Restart RDS if it was active earlier*/
+ result = cg2900_fm_rds_on();
+ fm_prev_rds_status = false;
+ }
+ } else if (CG2900_FM_TX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_get_block_scan_result:"
+ " Sending Set fmd_tx_set_pa");
+
+ /* Enable the PA */
+ result = fmd_tx_set_pa(true);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_get_block_scan_result:"
+ " fmd_tx_set_pa "
+ "failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_get_block_scan_result: returning %d",
+ result);
+ return result;
+
+}
+
+int cg2900_fm_tx_rds(
+ bool enable_rds
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_rds: enable_rds = %d", enable_rds);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_rds: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ if (enable_rds) {
+ /* Set the Tx Buffer Size */
+ result = fmd_tx_buffer_set_size(
+ MAX_RDS_GROUPS - 2);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_rds: "
+ "fmd_tx_buffer_set_size "
+ "failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ } else {
+ result = fmd_tx_set_rds(true);
+ }
+
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_rds: "
+ "fmd_tx_set_rds "
+ "failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ program_identification_code =
+ default_program_identification_code;
+ program_type_code = default_program_type_code;
+ memcpy(program_service,
+ default_program_service,
+ MAX_PSN_SIZE);
+ memcpy(radio_text,
+ default_radio_text, MAX_RT_SIZE);
+ radio_text[strlen(radio_text)] = 0x0D;
+ cg2900_fm_transmit_rds_groups();
+ result = 0;
+ } else {
+ result = fmd_tx_set_rds(false);
+
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_rds: "
+ "fmd_tx_set_rds "
+ "failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_rds: returning %d",
+ result);
+
+ return result;
+}
+
+int cg2900_fm_tx_set_pi_code(
+ u16 pi_code
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_set_pi_code: PI = %04x", pi_code);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_pi_code: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ program_identification_code = pi_code;
+ result = cg2900_fm_transmit_rds_groups();
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_set_pi_code: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_set_pty_code(
+ u16 pty_code
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_set_pty_code: PTY = %04x", pty_code);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_pty_code: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ program_type_code = pty_code;
+ result = cg2900_fm_transmit_rds_groups();
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_set_pty_code: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_set_program_station_name(
+ char *psn,
+ u8 len
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_set_program_station_name: PSN = %s",
+ psn);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_program_station_name: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ if (len < (MAX_PSN_SIZE - 1)) {
+ int count = len - 1;
+ while (count < (MAX_PSN_SIZE - 1))
+ psn[count++] = ' ';
+ }
+ memcpy(program_service, psn, MAX_PSN_SIZE);
+ result = cg2900_fm_transmit_rds_groups();
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_set_program_station_name: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_set_radio_text(
+ char *rt,
+ u8 len
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_set_radio_text: RT = %s", rt);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_radio_text: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ rt[len] = 0x0D;
+ memcpy(radio_text, rt, len + 1);
+
+ result = cg2900_fm_transmit_rds_groups();
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_set_radio_text: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_get_rds_deviation(
+ u16 *deviation
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_get_rds_deviation");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_get_rds_deviation: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_tx_get_rds_deviation(deviation);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_get_rds_deviation: "
+ "fmd_tx_get_rds_deviation failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_get_rds_deviation: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_set_rds_deviation(
+ u16 deviation
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_set_rds_deviation: deviation = %d",
+ deviation);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_rds_deviation: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_tx_set_rds_deviation(deviation);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_rds_deviation: "
+ "fmd_tx_set_rds_deviation failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_set_rds_deviation: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_get_pilot_tone_status(
+ bool *enable
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_get_pilot_tone_status");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_get_pilot_tone_status: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_tx_get_stereo_mode(enable);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_get_pilot_tone_status: "
+ "fmd_tx_get_stereo_mode failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_get_pilot_tone_status: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_set_pilot_tone_status(
+ bool enable
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_set_pilot_tone_status: enable = %d",
+ enable);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_pilot_tone_status: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_tx_enable_stereo_mode(enable);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_pilot_tone_status: "
+ "fmd_tx_enable_stereo_mode failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_set_pilot_tone_status: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_get_pilot_deviation(
+ u16 *deviation
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_get_pilot_deviation");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_get_pilot_deviation: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_tx_get_pilot_deviation(deviation);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_get_pilot_deviation: "
+ "fmd_tx_get_pilot_deviation failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_get_pilot_deviation: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_set_pilot_deviation(
+ u16 deviation
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_set_pilot_deviation: deviation = %d",
+ deviation);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_pilot_deviation: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_tx_set_pilot_deviation(deviation);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_pilot_deviation: "
+ "fmd_tx_set_pilot_deviation failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_set_pilot_deviation: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_get_preemphasis(
+ u8 *preemphasis
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_get_preemphasis");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_get_preemphasis: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_tx_get_preemphasis(preemphasis);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_get_preemphasis: "
+ "fmd_tx_get_preemphasis failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_get_preemphasis: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_set_preemphasis(
+ u8 preemphasis
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_set_preemphasis: preemphasis = %d",
+ preemphasis);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_preemphasis: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_tx_set_preemphasis(preemphasis);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_preemphasis: "
+ "fmd_tx_set_preemphasis failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_set_preemphasis: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_get_power_level(
+ u16 *power_level
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_get_power_level");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_get_power_level: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_tx_get_signal_strength(power_level);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_get_power_level: "
+ "fmd_tx_get_signal_strength failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_get_power_level: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_tx_set_power_level(
+ u16 power_level
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_tx_set_power_level: power_level = %d",
+ power_level);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_power_level: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_tx_set_signal_strength(power_level);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_tx_set_power_level: "
+ "fmd_tx_set_preemphasis failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_tx_set_power_level: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_set_audio_balance(
+ s8 balance
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_set_audio_balance, balance = %d", balance);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_set_audio_balance: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_set_balance(balance);
+ if (0 != result) {
+ FM_ERR_REPORT("FMRSetAudioBalance : "
+ "Failed in fmd_set_balance, err = %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_set_audio_balance: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_set_volume(
+ u8 vol_level
+ )
+{
+ int result;
+ u8 vol_in_percentage;
+
+ FM_INFO_REPORT("cg2900_fm_set_volume: Volume Level = %d", vol_level);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_set_volume: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ vol_in_percentage =
+ (u8) (((u16) (vol_level) * 100) / MAX_ANALOG_VOLUME);
+ result = fmd_set_volume(vol_in_percentage);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_increase_volume: "
+ "FMRSetVolume failed, err = %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_set_volume: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_get_volume(
+ u8 *vol_level
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_get_volume");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_get_volume: "
+ "Invalid state of FM Driver = %d", fm_state);
+ *vol_level = 0;
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_get_volume(vol_level);
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_get_volume: returning %d, VolLevel = %d",
+ result, *vol_level);
+ return result;
+}
+
+int cg2900_fm_rds_off(void)
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_rds_off");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_rds_off: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_rx_set_rds(FMD_SWITCH_OFF_RDS);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_rds_off: fmd_rx_set_rds failed, "
+ "err = %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ /* Stop the RDS Thread */
+ fm_rds_status = false;
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ FM_DEBUG_REPORT("cg2900_fm_rds_off: "
+ "Stopping RDS Thread");
+ fmd_stop_rds_thread();
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_rds_off: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_rds_on(void)
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_rds_on");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_rds_on: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ FM_DEBUG_REPORT("cg2900_fm_rds_on:"
+ " Sending fmd_rx_buffer_set_size");
+ result = fmd_rx_buffer_set_size(MAX_RDS_GROUPS);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_rds_on: fmd_rx_buffer_set_size"
+ "failed, err = %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ FM_DEBUG_REPORT("cg2900_fm_rds_on: Sending "
+ "fmd_rx_buffer_set_threshold");
+ result = fmd_rx_buffer_set_threshold(MAX_RDS_GROUPS - 1);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_rds_on: fmd_rx_buffer_set_threshold "
+ "failed, err = %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ FM_DEBUG_REPORT("cg2900_fm_rds_on: Sending fmd_rx_set_rds");
+ result = fmd_rx_set_rds(FMD_SWITCH_ON_RDS_ENHANCED_MODE);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_rds_on: fmd_rx_set_rds failed, "
+ "err = %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ /* Start the RDS Thread to read the RDS Buffers */
+ fm_rds_status = true;
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ fmd_start_rds_thread(cg2900_fm_rds_callback);
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_rds_on: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_get_rds_status(
+ bool *rds_status
+ )
+{
+ int result = 0;
+
+ FM_INFO_REPORT("cg2900_fm_get_rds_status");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_get_rds_status: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ if (CG2900_FM_RX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_get_rds_status: "
+ "fmd_rx_get_rds");
+ result = fmd_rx_get_rds(rds_status);
+ } else if (CG2900_FM_TX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_get_rds_status: "
+ "fmd_tx_get_rds");
+ result = fmd_tx_get_rds(rds_status);
+ }
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_get_rds_status: "
+ "fmd_get_rds failed, Error Code %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_get_rds_status: returning %d, "
+ "rds_status = %d", result,
+ *rds_status);
+ return result;
+}
+
+int cg2900_fm_mute(void)
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_mute");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_mute: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+
+ /* Mute Analog DAC */
+ result = fmd_set_mute(true);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_mute: "
+ "fmd_set_mute failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ /* Mute Ext Src */
+ result = fmd_ext_set_mute(true);
+ if (0 != result) {
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_mute: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_unmute(void)
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_unmute");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_unmute: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ /* Unmute Analog DAC */
+ result = fmd_set_mute(false);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_mute: "
+ "fmd_set_mute failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ /* Unmute Ext Src */
+ result = fmd_ext_set_mute(false);
+ if (0 != result) {
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_unmute: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_get_frequency(
+ u32 *freq
+ )
+{
+ int result = 0;
+ u32 currentFreq = 0;
+
+ FM_INFO_REPORT("cg2900_fm_get_frequency");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_get_frequency: "
+ "Invalid state of FM Driver = %d", fm_state);
+ *freq = 0;
+ result = -EINVAL;
+ goto error;
+ }
+ if (CG2900_FM_RX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_get_frequency: "
+ "fmd_rx_get_frequency");
+ result = fmd_rx_get_frequency(
+ (u32 *) &currentFreq);
+ } else if (CG2900_FM_TX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_get_frequency: "
+ "fmd_tx_get_frequency");
+ result = fmd_tx_get_frequency(
+ (u32 *) &currentFreq);
+ }
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_get_frequency: "
+ "fmd_rx_get_frequency failed %d",
+ (unsigned int)result);
+ *freq = 0;
+ result = -EINVAL;
+ goto error;
+ }
+ /* Convert To Hz */
+ *freq = currentFreq * FREQUENCY_CONVERTOR_KHZ_HZ;
+ FM_DEBUG_REPORT("cg2900_fm_get_frequency: "
+ "Current Frequency = %d Hz", *freq);
+ if (fm_prev_rds_status) {
+ /* Restart RDS if it was active earlier */
+ cg2900_fm_rds_on();
+ fm_prev_rds_status = false;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_get_frequency: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_set_frequency(
+ u32 new_freq
+ )
+{
+ int result = 0;
+
+ FM_INFO_REPORT("cg2900_fm_set_frequency, new_freq = %d",
+ (int)new_freq);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_set_frequency: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ if (CG2900_FM_RX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_set_frequency: "
+ "fmd_rx_set_frequency");
+ result = fmd_rx_set_frequency(
+ new_freq / FREQUENCY_CONVERTOR_KHZ_HZ);
+ } else if (CG2900_FM_TX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_set_frequency: "
+ "fmd_tx_set_frequency");
+ result = fmd_tx_set_frequency(
+ new_freq / FREQUENCY_CONVERTOR_KHZ_HZ);
+ }
+ if (result != 0) {
+ FM_ERR_REPORT("cg2900_fm_set_frequency: "
+ "fmd_rx_set_frequency failed %x",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ if (CG2900_FM_TX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_set_frequency:"
+ " Sending Set" "fmd_tx_set_pa");
+
+ /* Enable the PA */
+ result = fmd_tx_set_pa(true);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_frequency:"
+ " fmd_tx_set_pa "
+ "failed %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ result = 0;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_set_frequency: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_get_signal_strength(
+ u16 *signal_strength
+ )
+{
+ int result = 0;
+
+ FM_INFO_REPORT("cg2900_fm_get_signal_strength");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_get_signal_strength: "
+ "Invalid state of FM Driver = %d", fm_state);
+ *signal_strength = 0;
+ result = -EINVAL;
+ goto error;
+ }
+ if (CG2900_FM_RX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_get_signal_strength: "
+ "fmd_rx_get_signal_strength");
+ result = fmd_rx_get_signal_strength(
+ signal_strength);
+ } else if (CG2900_FM_TX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_get_signal_strength: "
+ "fmd_tx_get_signal_strength");
+ result = fmd_tx_get_signal_strength(
+ signal_strength);
+ }
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_get_signal_strength: "
+ "Error Code %d", (unsigned int)result);
+ *signal_strength = 0;
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_get_signal_strength: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_af_update_get_result(
+ u16 *af_update_rssi
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_af_update_get_result");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_af_update_get_result: "
+ "Invalid state of FM Driver = %d", fm_state);
+ *af_update_rssi = 0;
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_rx_get_af_update_result(af_update_rssi);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_af_update_get_result: "
+ "Error Code %d", (unsigned int)result);
+ *af_update_rssi = 0;
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_af_update_get_result: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_af_update_start(
+ u32 af_freq
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_af_update_start");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_af_update_start: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_rx_af_update_start(
+ af_freq / FREQUENCY_CONVERTOR_KHZ_HZ);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_af_update_start: "
+ "Error Code %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_af_update_start: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_af_switch_get_result(
+ u16 *af_switch_conclusion
+ )
+{
+ int result;
+ u16 af_rssi;
+ u16 af_pi;
+
+ FM_INFO_REPORT("cg2900_fm_af_switch_get_result");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_af_switch_get_result: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_rx_get_af_switch_results(
+ af_switch_conclusion,
+ &af_rssi, &af_pi);
+
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_af_switch_get_result: "
+ "Error Code %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+ FM_DEBUG_REPORT("cg2900_fm_af_switch_get_result: "
+ "AF Switch conclusion = %d "
+ "AF Switch RSSI level = %d "
+ "AF Switch PI code = %d ",
+ *af_switch_conclusion, af_rssi, af_pi);
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_af_switch_get_result: returning %d",
+ result);
+ return result;
+
+}
+
+int cg2900_fm_af_switch_start(
+ u32 af_switch_freq,
+ u16 af_switch_pi
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_af_switch_start");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_af_switch_start: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_rx_af_switch_start(
+ af_switch_freq / FREQUENCY_CONVERTOR_KHZ_HZ,
+ af_switch_pi);
+
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_af_switch_start: "
+ "Error Code %d", (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_af_switch_start: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_get_mode(
+ u8 *cur_mode
+ )
+{
+ int result = 0;
+ bool stereo_mode;
+
+ FM_INFO_REPORT("cg2900_fm_get_mode");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_get_mode: "
+ "Invalid state of FM Driver = %d", fm_state);
+ *cur_mode = CG2900_MODE_MONO;
+ result = -EINVAL;
+ goto error;
+ }
+ if (CG2900_FM_RX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_get_mode: "
+ "fmd_rx_get_stereo_mode");
+ result = fmd_rx_get_stereo_mode(cur_mode);
+ switch (*cur_mode) {
+ case FMD_STEREOMODE_OFF:
+ case FMD_STEREOMODE_BLENDING:
+ *cur_mode = CG2900_MODE_STEREO;
+ break;
+ case FMD_STEREOMODE_MONO:
+ default:
+ *cur_mode = CG2900_MODE_MONO;
+ break;
+ }
+ } else if (CG2900_FM_TX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_get_mode: "
+ "fmd_tx_get_stereo_mode");
+ result = fmd_tx_get_stereo_mode(&stereo_mode);
+ if (stereo_mode)
+ *cur_mode = CG2900_MODE_STEREO;
+ else
+ *cur_mode = CG2900_MODE_MONO;
+ }
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_get_mode: "
+ "fmd_get_stereo_mode failed, "
+ "Error Code %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_get_mode: returning %d, mode = %d",
+ result, *cur_mode);
+ return result;
+}
+
+int cg2900_fm_set_mode(
+ u8 mode
+ )
+{
+ int result = 0;
+ bool enable_stereo_mode = false;
+
+ FM_INFO_REPORT("cg2900_fm_set_mode: mode = %d", mode);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_set_mode: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ if (CG2900_FM_RX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_set_mode: "
+ "fmd_rx_set_stereo_mode");
+ result = fmd_rx_set_stereo_mode(mode);
+ } else if (CG2900_FM_TX_MODE == fm_mode) {
+ FM_DEBUG_REPORT("cg2900_fm_set_mode: "
+ "fmd_tx_set_stereo_mode");
+ if (mode == CG2900_MODE_STEREO)
+ enable_stereo_mode = true;
+ result =
+ fmd_tx_enable_stereo_mode(
+ enable_stereo_mode);
+ }
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_mode: "
+ "fmd_rx_set_stereo_mode failed, "
+ "Error Code %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_set_mode: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_select_antenna(
+ u8 antenna
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_select_antenna: Antenna = %d", antenna);
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_select_antenna: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_set_antenna(antenna);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_select_antenna: "
+ "fmd_set_antenna failed, Error Code %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_select_antenna: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_get_antenna(
+ u8 *antenna
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_get_antenna");
+
+ if (CG2900_FM_STATE_SWITCHED_ON != fm_state) {
+ FM_ERR_REPORT("cg2900_fm_get_antenna: "
+ "Invalid state of FM Driver = %d", fm_state);
+ result = -EINVAL;
+ goto error;
+ }
+ result = fmd_get_antenna(antenna);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_get_antenna: "
+ "fmd_get_antenna failed, Error Code %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_get_antenna: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_get_rssi_threshold(
+ u16 *rssi_thresold
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_get_rssi_threshold");
+
+ result = fmd_rx_get_stop_level(rssi_thresold);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_get_rssi_threshold: "
+ "fmd_rx_get_stop_level failed, Error Code %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_get_rssi_threshold: returning %d",
+ result);
+ return result;
+}
+
+int cg2900_fm_set_rssi_threshold(
+ u16 rssi_thresold
+ )
+{
+ int result;
+
+ FM_INFO_REPORT("cg2900_fm_set_rssi_threshold: "
+ "RssiThresold = %d", rssi_thresold);
+
+ result = fmd_rx_set_stop_level(rssi_thresold);
+ if (0 != result) {
+ FM_ERR_REPORT("cg2900_fm_set_rssi_threshold: "
+ "fmd_rx_set_stop_level failed, Error Code %d",
+ (unsigned int)result);
+ result = -EINVAL;
+ goto error;
+ }
+
+error:
+ FM_DEBUG_REPORT("cg2900_fm_set_rssi_threshold: returning %d",
+ result);
+ return result;
+}
+
+void cg2900_fm_set_chip_version(
+ u16 revision,
+ u16 sub_version
+ )
+{
+ version_info.revision = revision;
+ version_info.sub_version = sub_version;
+}
+
+
+MODULE_AUTHOR("Hemant Gupta");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/radio/CG2900/cg2900_fm_api.h b/drivers/media/radio/CG2900/cg2900_fm_api.h
new file mode 100644
index 00000000000..fe6bd974ce8
--- /dev/null
+++ b/drivers/media/radio/CG2900/cg2900_fm_api.h
@@ -0,0 +1,1002 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Linux FM Host API's for ST-Ericsson FM Chip.
+ *
+ * Author: Hemant Gupta <hemant.gupta@stericsson.com> for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef CG2900_FM_API_H
+#define CG2900_FM_API_H
+
+#include <linux/device.h>
+
+/* Callback function to receive RDS Data. */
+typedef void (*cg2900_fm_rds_cb)(void);
+
+/**
+ * struct cg2900_fm_rds_buf - RDS Group Receiving Structure
+ *
+ * @block1: RDS Block A
+ * @block2: RDS Block B
+ * @block3: RDS Block C
+ * @block4: RDS Block D
+ * @status1: Status of received RDS Block A
+ * @status2: Status of received RDS Block B
+ * @status3: Status of received RDS Block C
+ * @status4: Status of received RDS Block D
+ *
+ * Structure for receiving the RDS Group from FM Chip.
+ */
+struct cg2900_fm_rds_buf {
+ u16 block1;
+ u16 block2;
+ u16 block3;
+ u16 block4;
+ u8 status1;
+ u8 status2;
+ u8 status3;
+ u8 status4;
+};
+
+/**
+ * struct cg2900_fm_rds_info - RDS Information Structure
+ *
+ * @rds_head: RDS Queue Head for storing next valid data.
+ * @rds_tail: RDS Queue Tail for retreiving next valid data.
+ * @rds_group_sent: Number of RDS Groups sent to Application.
+ * @rds_block_sent: Number of RDS Blocks sent to Application.
+ *
+ * Structure for storing the RDS data queue information.
+ */
+struct cg2900_fm_rds_info {
+ u8 rds_head;
+ u8 rds_tail;
+ u8 rds_group_sent;
+ u8 rds_block_sent;
+};
+
+/**
+ * struct cg2900_version_info - Chip HCI Version Info
+ *
+ * @revision: Revision of the controller, e.g. to indicate that it is
+ * a CG2900 controller.
+ * @sub_version: Subversion of the controller, e.g. to indicate a certain
+ * tape-out of the controller.
+ *
+ * Structure for storing the HCI Version Information of the Controller.
+ */
+struct cg2900_version_info {
+ u16 revision;
+ u16 sub_version;
+};
+
+/**
+ * enum cg2900_fm_state - States of FM Driver.
+ *
+ * @CG2900_FM_STATE_DEINITIALIZED: FM driver is not initialized.
+ * @CG2900_FM_STATE_INITIALIZED: FM driver is initialized.
+ * @CG2900_FM_STATE_SWITCHED_ON: FM driver is switched on and in active state.
+ * @CG2900_FM_STATE_STAND_BY: FM Radio is switched on but not in active state.
+ *
+ * Various states of FM Driver.
+ */
+enum cg2900_fm_state {
+ CG2900_FM_STATE_DEINITIALIZED,
+ CG2900_FM_STATE_INITIALIZED,
+ CG2900_FM_STATE_SWITCHED_ON,
+ CG2900_FM_STATE_STAND_BY
+};
+
+/**
+ * enum cg2900_fm_mode - FM Driver Command state .
+ *
+ * @CG2900_FM_IDLE_MODE: FM Radio is in Idle Mode.
+ * @CG2900_FM_RX_MODE: FM Radio is configured in Rx mode.
+ * @CG2900_FM_TX_MODE: FM Radio is configured in Tx mode.
+ *
+ * Various Modes of the FM Radio.
+ */
+enum cg2900_fm_mode {
+ CG2900_FM_IDLE_MODE,
+ CG2900_FM_RX_MODE,
+ CG2900_FM_TX_MODE
+};
+
+/**
+ * enum cg2900_fm_band - Various Frequency band supported.
+ *
+ * @CG2900_FM_BAND_US_EU: European / US Band.
+ * @CG2900_FM_BAND_JAPAN: Japan Band.
+ * @CG2900_FM_BAND_CHINA: China Band.
+ * @CG2900_FM_BAND_CUSTOM: Custom Band.
+ *
+ * Various Frequency band supported.
+ */
+enum cg2900_fm_band {
+ CG2900_FM_BAND_US_EU,
+ CG2900_FM_BAND_JAPAN,
+ CG2900_FM_BAND_CHINA,
+ CG2900_FM_BAND_CUSTOM
+};
+
+/**
+ * enum cg2900_fm_grid - Various Frequency grids supported.
+ *
+ * @CG2900_FM_GRID_50: 50 kHz spacing.
+ * @CG2900_FM_GRID_100: 100 kHz spacing.
+ * @CG2900_FM_GRID_200: 200 kHz spacing.
+ *
+ * Various Frequency grids supported.
+ */
+enum cg2900_fm_grid {
+ CG2900_FM_GRID_50,
+ CG2900_FM_GRID_100,
+ CG2900_FM_GRID_200
+};
+
+/**
+ * enum cg2900_fm_event - Various Events reported by FM API layer.
+ *
+ * @CG2900_EVENT_NO_EVENT: No Event.
+ * @CG2900_EVENT_SEARCH_CHANNEL_FOUND: Seek operation is completed.
+ * @CG2900_EVENT_SCAN_CHANNELS_FOUND: Band Scan is completed.
+ * @CG2900_EVENT_BLOCK_SCAN_CHANNELS_FOUND: Block Scan is completed.
+ * @CG2900_EVENT_SCAN_CANCELLED: Scan/Seek is cancelled.
+ *
+ * Various Events reported by FM API layer.
+ */
+enum cg2900_fm_event {
+ CG2900_EVENT_NO_EVENT,
+ CG2900_EVENT_SEARCH_CHANNEL_FOUND,
+ CG2900_EVENT_SCAN_CHANNELS_FOUND,
+ CG2900_EVENT_BLOCK_SCAN_CHANNELS_FOUND,
+ CG2900_EVENT_SCAN_CANCELLED
+};
+
+/**
+ * enum cg2900_fm_direction - Directions used while seek.
+ *
+ * @CG2900_DIR_DOWN: Search in downwards direction.
+ * @CG2900_DIR_UP: Search in upwards direction.
+ *
+ * Directions used while seek.
+ */
+enum cg2900_fm_direction {
+ CG2900_DIR_DOWN,
+ CG2900_DIR_UP
+};
+
+/**
+ * enum cg2900_fm_stereo_mode - Stereo Modes.
+ *
+ * @CG2900_MODE_MONO: Mono Mode.
+ * @CG2900_MODE_STEREO: Stereo Mode.
+ *
+ * Stereo Modes.
+ */
+enum cg2900_fm_stereo_mode {
+ CG2900_MODE_MONO,
+ CG2900_MODE_STEREO
+};
+
+#define CG2900_FM_DEFAULT_RSSI_THRESHOLD 100
+#define MAX_RDS_BUFFER 10
+#define MAX_RDS_GROUPS 22
+#define MIN_ANALOG_VOLUME 0
+#define MAX_ANALOG_VOLUME 20
+#define NUM_OF_RDS_BLOCKS 4
+#define RDS_BLOCK_MASK 0x1C
+#define RDS_ERROR_STATUS_MASK 0x03
+#define RDS_UPTO_TWO_BITS_CORRECTED 0x01
+#define RDS_UPTO_FIVE_BITS_CORRECTED 0x02
+#define MAX_RT_SIZE 65
+#define MAX_PSN_SIZE 9
+#define DEFAULT_CHANNELS_TO_SCAN 32
+#define MAX_CHANNELS_TO_SCAN 99
+#define MAX_CHANNELS_FOR_BLOCK_SCAN 198
+
+extern u8 fm_event;
+extern struct cg2900_fm_rds_buf fm_rds_buf[MAX_RDS_BUFFER][MAX_RDS_GROUPS];
+extern struct cg2900_fm_rds_info fm_rds_info;
+
+/**
+ * cg2900_fm_init()- Initializes FM Radio.
+ *
+ * Initializes the Variables and structures required for FM Driver.
+ * It also registers the callback to receive the events for command
+ * completion, etc
+ *
+ * Returns:
+ * 0, if Initialization successful
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_init(void);
+
+/**
+ * cg2900_fm_deinit()- De-initializes FM Radio.
+ *
+ * De-initializes the Variables and structures required for FM Driver.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_deinit(void);
+
+/**
+ * cg2900_fm_switch_on()- Start up procedure of the FM radio.
+ *
+ * @device: Character device requesting the operation.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_switch_on(
+ struct device *device
+ );
+
+/**
+ * cg2900_fm_switch_off()- Switches off FM radio
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_switch_off(void);
+
+/**
+ * cg2900_fm_standby()- Makes the FM Radio Go in Standby mode.
+ *
+ * The FM Radio memorizes the the last state, i.e. Volume, last
+ * tuned station, etc that helps in resuming quickly to previous state.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_standby(void);
+
+/**
+ * cg2900_fm_power_up_from_standby()- Power Up FM Radio from Standby mode.
+ *
+ * It retruns the FM radio to the same state as it was before
+ * going to Standby.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_power_up_from_standby(void);
+
+/**
+ * cg2900_fm_set_rx_default_settings()- Loads FM Rx Default Settings.
+ *
+ * @freq: Frequency in Hz to be set on the FM Radio.
+ * @band: Band To be Set.
+ * (0: US/EU, 1: Japan, 2: China, 3: Custom)
+ * @grid: Grid specifying Spacing.
+ * (0: 50 KHz, 1: 100 KHz, 2: 200 Khz)
+ * @enable_rds: Flag indicating enable or disable rds transmission.
+ * @enable_stereo: Flag indicating enable or disable stereo mode.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_set_rx_default_settings(
+ u32 freq,
+ u8 band,
+ u8 grid,
+ bool enable_rds,
+ bool enable_stereo
+ );
+
+/**
+ * cg2900_fm_set_tx_default_settings()- Loads FM Tx Default Settings.
+ *
+ * @freq: Frequency in Hz to be set on the FM Radio.
+ * @band: Band To be Set.
+ * (0: US/EU, 1: Japan, 2: China, 3: Custom)
+ * @grid: Grid specifying Spacing.
+ * (0: 50 KHz, 1: 100 KHz, 2: 200 Khz)
+ * @enable_rds: Flag indicating enable or disable rds transmission.
+ * @enable_stereo: Flag indicating enable or disable stereo mode.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_set_tx_default_settings(
+ u32 freq,
+ u8 band,
+ u8 grid,
+ bool enable_rds,
+ bool enable_stereo
+ );
+
+/**
+ * cg2900_fm_set_grid()- Sets the Grid on the FM Radio.
+ *
+ * @grid: Grid specifying Spacing.
+ * (0: 50 KHz,1: 100 KHz,2: 200 Khz)
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_set_grid(
+ u8 grid
+ );
+
+/**
+ * cg2900_fm_set_band()- Sets the Band on the FM Radio.
+ *
+ * @band: Band specifying Region.
+ * (0: US_EU,1: Japan,2: China,3: Custom)
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_set_band(
+ u8 band
+ );
+
+/**
+ * cg2900_fm_search_up_freq()- seek Up.
+ *
+ * Searches the next available station in Upward Direction
+ * starting from the Current freq.
+ *
+ * If the operation is started successfully, the chip will generate the
+ * irpt_OperationSucced. interrupt when the operation is completed
+ * and will tune to the next available frequency.
+ * If no station is found, the chip is still tuned to the original station
+ * before starting the search
+ * Till the interrupt is received, no more API's should be called
+ * except cg2900_fm_stop_scan
+ *
+ * Returns:
+ * 0, if operation started successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_search_up_freq(void);
+
+/**
+ * cg2900_fm_search_down_freq()- seek Down.
+ *
+ * Searches the next available station in Downward Direction
+ * starting from the Current freq.
+ *
+ * If the operation is started successfully, the chip will generate
+ * the irpt_OperationSucced. interrupt when the operation is completed.
+ * and will tune to the next available frequency. If no station is found,
+ * the chip is still tuned to the original station before starting the search.
+ * Till the interrupt is received, no more API's should be called
+ * except cg2900_fm_stop_scan.
+ *
+ * Returns:
+ * 0, if operation started successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_search_down_freq(void);
+
+/**
+ * cg2900_fm_start_band_scan()- Band Scan.
+ *
+ * Searches for available Stations in the entire Band starting from
+ * current freq.
+ * If the operation is started successfully, the chip will generate
+ * the irpt_OperationSucced. interrupt when the operation is completed.
+ * After completion the chip will still be tuned the original station before
+ * starting the Scan. on reception of interrupt, the host should call the AP
+ * cg2900_fm_get_scan_result() to retrieve the Stations and corresponding
+ * RSSI of stations found in the Band.
+ * Till the interrupt is received, no more API's should be called
+ * except cg2900_fm_stop_scan, cg2900_fm_switch_off, cg2900_fm_standby and
+ * cg2900_fm_get_frequency.
+ *
+ * Returns:
+ * 0, if operation started successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_start_band_scan(void);
+
+/**
+ * cg2900_fm_stop_scan()- Stops an active ongoing seek or Band Scan.
+ *
+ * If the operation is started successfully, the chip will generate the
+ * irpt_OperationSucced interrupt when the operation is completed.
+ * Till the interrupt is received, no more API's should be called.
+ *
+ * Returns:
+ * 0, if operation started successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_stop_scan(void);
+
+/**
+ * cg2900_fm_get_scan_result()- Retreives Band Scan Result
+ *
+ * Retrieves the Scan Band Results of the stations found and
+ * the corressponding RSSI values of the stations.
+ * @num_of_scanfreq: (out) Number of Stations found
+ * during Scanning.
+ * @scan_freq: (out) Frequency of Stations in Hz
+ * found during Scanning.
+ * @scan_freq_rssi_level: (out) RSSI level of Stations
+ * found during Scanning.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_get_scan_result(
+ u16 *num_of_scanfreq,
+ u32 *scan_freq,
+ u32 *scan_freq_rssi_level
+ );
+
+/**
+ * cg2900_fm_start_block_scan()- Block Scan.
+ *
+ * Searches for RSSI level of all the channels between the start and stop
+ * channels. If the operation is started successfully, the chip will generate
+ * the irpt_OperationSucced interrupt when the operation is completed.
+ * After completion the chip will still be tuned the original station before
+ * starting the Scan. On reception of interrupt, the host should call the AP
+ * cg2900_fm_get_block_scan_result() to retrieve the RSSI of channels.
+ * Till the interrupt is received, no more API's should be called from Host
+ * except cg2900_fm_stop_scan, cg2900_fm_switch_off, cg2900_fm_standby and
+ * cg2900_fm_get_frequency.
+ * @start_freq: Start channel block scan Frequency.
+ * @end_freq: End channel block scan Frequency
+ *
+ * Returns:
+ * 0, if operation started successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_start_block_scan(
+ u32 start_freq,
+ u32 end_freq
+ );
+
+/**
+ * cg2900_fm_get_scan_result()- Retreives Band Scan Result
+ *
+ * Retrieves the Scan Band Results of the stations found and
+ * the corressponding RSSI values of the stations.
+ * @num_of_scanchan: (out) Number of Stations found
+ * during Scanning.
+ * @scan_freq_rssi_level: (out) RSSI level of Stations
+ * found during Scanning.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_get_block_scan_result(
+ u16 *num_of_scanchan,
+ u16 *scan_freq_rssi_level
+ );
+
+/**
+ * cg2900_fm_tx_get_rds_deviation()- Gets RDS Deviation.
+ *
+ * Retrieves the RDS Deviation level set for FM Tx.
+ * @deviation: (out) Rds Deviation.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_get_rds_deviation(
+ u16 *deviation
+ );
+
+/**
+ * cg2900_fm_tx_set_rds_deviation()- Sets RDS Deviation.
+ *
+ * Sets the RDS Deviation level on FM Tx.
+ * @deviation: Rds Deviation to set on FM Tx.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_set_rds_deviation(
+ u16 deviation
+ );
+
+/**
+ * cg2900_fm_tx_set_pi_code()- Sets PI code for RDS Transmission.
+ *
+ * Sets the Program Identification code to be transmitted.
+ * @pi_code: PI code to be transmitted.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_set_pi_code(
+ u16 pi_code
+ );
+
+/**
+ * cg2900_fm_tx_set_pty_code()- Sets PTY code for RDS Transmission.
+ *
+ * Sets the Program Type code to be transmitted.
+ * @pty_code: PTY code to be transmitted.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_set_pty_code(
+ u16 pty_code
+ );
+
+/**
+ * cg2900_fm_tx_set_program_station_name()- Sets PSN for RDS Transmission.
+ *
+ * Sets the Program Station Name to be transmitted.
+ * @psn: Program Station Name to be transmitted.
+ * @len: Length of Program Station Name to be transmitted.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_set_program_station_name(
+ char *psn,
+ u8 len
+ );
+
+/**
+ * cg2900_fm_tx_set_radio_text()- Sets RT for RDS Transmission.
+ *
+ * Sets the radio text to be transmitted.
+ * @rt: Radio Text to be transmitted.
+ * @len: Length of Radio Text to be transmitted.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_set_radio_text(
+ char *rt,
+ u8 len
+ );
+
+/**
+ * cg2900_fm_tx_get_rds_deviation()- Gets Pilot Tone status
+ *
+ * Gets the current status of pilot tone for FM Tx.
+ * @enable: (out) Flag indicating Pilot Tone is enabled or disabled.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_get_pilot_tone_status(
+ bool *enable
+ );
+
+/**
+ * cg2900_fm_tx_set_pilot_tone_status()- Enables/Disables Pilot Tone.
+ *
+ * Enables or disables the pilot tone for FM Tx.
+ * @enable: Flag indicating enabling or disabling Pilot Tone.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_set_pilot_tone_status(
+ bool enable
+ );
+
+/**
+ * cg2900_fm_tx_get_pilot_deviation()- Gets Pilot Deviation.
+ *
+ * Retrieves the Pilot Tone Deviation level set for FM Tx.
+ * @deviation: (out) Pilot Tone Deviation.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_get_pilot_deviation(
+ u16 *deviation
+ );
+
+/**
+ * cg2900_fm_tx_set_pilot_deviation()- Sets Pilot Deviation.
+ *
+ * Sets the Pilot Tone Deviation level on FM Tx.
+ * @deviation: Pilot Tone Deviation to set.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_set_pilot_deviation(
+ u16 deviation
+ );
+
+/**
+ * cg2900_fm_tx_get_preemphasis()- Gets Pre-emhasis level.
+ *
+ * Retrieves the Preemphasis level set for FM Tx.
+ * @preemphasis: (out) Preemphasis level.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_get_preemphasis(
+ u8 *preemphasis
+ );
+
+/**
+ * cg2900_fm_tx_set_preemphasis()- Sets Pre-emhasis level.
+ *
+ * Sets the Preemphasis level on FM Tx.
+ * @preemphasis: Preemphasis level.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_set_preemphasis(
+ u8 preemphasis
+ );
+
+/**
+ * cg2900_fm_tx_get_power_level()- Gets Power level.
+ *
+ * Retrieves the Power level set for FM Tx.
+ * @power_level: (out) Power level.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_get_power_level(
+ u16 *power_level
+ );
+
+/**
+ * cg2900_fm_tx_set_power_level()- Sets Power level.
+ *
+ * Sets the Power level for FM Tx.
+ * @power_level: Power level.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_set_power_level(
+ u16 power_level
+ );
+
+/**
+ * cg2900_fm_tx_rds()- Enable or disable Tx RDS.
+ *
+ * Enable or disable RDS transmission.
+ * @enable_rds: Flag indicating enabling or disabling RDS.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_tx_rds(
+ bool enable_rds
+ );
+
+/**
+ * cg2900_fm_set_audio_balance()- Sets Audio Balance.
+ *
+ * @balance: Audio Balnce to be Set in Percentage.
+ * (-100: Right Mute.... 0: Both on.... 100: Left Mute)
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_set_audio_balance(
+ s8 balance
+ );
+
+/**
+ * cg2900_fm_set_volume()- Sets the Analog Out Gain of FM Chip.
+ *
+ * @vol_level: Volume Level to be set on Tuner (0-20).
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_set_volume(
+ u8 vol_level
+ );
+
+/**
+ * cg2900_fm_get_volume()- Gets the currently set Analog Out Gain of FM Chip.
+ *
+ * @vol_level: (out)Volume Level set on Tuner (0-20).
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_get_volume(
+ u8 *vol_level
+ );
+
+/**
+ * cg2900_fm_rds_off()- Disables the RDS decoding algorithm in FM chip
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_rds_off(void);
+
+/**
+ * cg2900_fm_rds_on()- Enables the RDS decoding algorithm in FM chip
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_rds_on(void);
+
+/**
+ * cg2900_fm_get_rds_status()- Retrieves the status whether RDS is enabled or not
+ *
+ * @rds_status: (out) Status of RDS
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_get_rds_status(
+ bool *rds_status
+ );
+
+/**
+ * cg2900_fm_mute()- Mutes the Audio output from FM Chip
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_mute(void);
+
+/**
+ * cg2900_fm_unmute()- Unmutes the Audio output from FM Chip
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_unmute(void);
+
+/**
+ * cg2900_fm_get_frequency()- Gets the Curently tuned Frequency on FM Radio
+ *
+ * @freq: (out) Frequency in Hz set on the FM Radio.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_get_frequency(
+ u32 *freq
+ );
+
+/**
+ * cg2900_fm_set_frequency()- Sets the frequency on FM Radio
+ *
+ * @new_freq: Frequency in Hz to be set on the FM Radio.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_set_frequency(
+ u32 new_freq
+ );
+
+/**
+ * cg2900_fm_get_signal_strength()- Gets the RSSI level.
+ *
+ * @signal_strength: (out) RSSI level of the currently
+ * tuned frequency.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_get_signal_strength(
+ u16 *signal_strength
+ );
+
+/**
+ * cg2900_fm_get_af_updat()- Retrives results of AF Update
+ *
+ * @af_update_rssi: (out) RSSI level of the Alternative frequency.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_af_update_get_result(
+ u16 *af_update_rssi
+ );
+
+
+/**
+ * cg2900_fm_af_update_start()- PErforms AF Update.
+ *
+ * @af_freq: AF frequency in Hz whose RSSI is to be retrived.
+ * tuned frequency.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+
+int cg2900_fm_af_update_start(
+ u32 af_freq
+ );
+
+/**
+ * cg2900_fm_af_switch_get_result()- Retrives the AF switch result.
+ *
+ * @af_switch_conclusion: (out) Conclusion of the AF Switch.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_af_switch_get_result(
+ u16 *af_switch_conclusion
+ );
+
+/**
+ * cg2900_fm_af_switch_start()- PErforms AF switch.
+ *
+ * @af_switch_freq: Alternate Frequency in Hz to be switched.
+ * @af_switch_pi: picode of the Alternative frequency.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_af_switch_start(
+ u32 af_switch_freq,
+ u16 af_switch_pi
+ );
+
+/**
+ * cg2900_fm_get_mode()- Gets the mode of the Radio tuner.
+ *
+ * @cur_mode: (out) Current mode set on FM Radio
+ * (0: Stereo, 1: Mono, 2: Blending, 3: Switching).
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_get_mode(
+ u8 *cur_mode
+ );
+
+/**
+ * cg2900_fm_set_mode()- Sets the mode on the Radio tuner.
+ *
+ * @mode: mode to be set on FM Radio
+ * (0: Stereo, 1: Mono, 2: Blending, 3: Switching.)
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_set_mode(
+ u8 mode
+ );
+
+/**
+ * cg2900_fm_select_antenna()- Selects the Antenna of the Radio tuner.
+ *
+ * @antenna: (0: Embedded, 1: Wired.)
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_select_antenna(
+ u8 antenna
+ );
+
+/**
+ * cg2900_fm_get_antenna()- Retreives the currently selected antenna.
+ *
+ * @antenna: out (0: Embedded, 1: Wired.)
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_get_antenna(
+ u8 *antenna
+ );
+
+/**
+ * cg2900_fm_get_rssi_threshold()- Gets the rssi threshold currently
+ *
+ * set on FM radio.
+ * @rssi_thresold: (out) Current rssi threshold set.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_get_rssi_threshold(
+ u16 *rssi_thresold
+ );
+
+/**
+ * cg2900_fm_set_rssi_threshold()- Sets the rssi threshold to be used during
+ *
+ * Band Scan and seek Stations
+ * @rssi_thresold: rssi threshold to be set.
+ *
+ * Returns:
+ * 0, if operation completed successfully.
+ * -EINVAL, otherwise.
+ */
+int cg2900_fm_set_rssi_threshold(
+ u16 rssi_thresold
+ );
+
+/**
+ * cg2900_handle_device_reset()- Handle The reset of Device
+ */
+void cg2900_handle_device_reset(void);
+
+/**
+ * wake_up_poll_queue()- Wakes up the Task waiting on Poll Queue.
+ * This function is called when Scan Band or seek has completed.
+ */
+void wake_up_poll_queue(void);
+
+/**
+ * void wake_up_read_queue()- Wakes up the Task waiting on Read Queue.
+ * This function is called when RDS data is available for reading by
+ * application.
+ */
+void wake_up_read_queue(void);
+
+/**
+ * void cg2900_fm_set_chip_version()- Sets the Version of the Controller.
+ *
+ * This function is used to update the Chip Version information at time
+ * of intitialization of FM driver.
+ * @revision: Revision of the controller, e.g. to indicate that it is
+ * a CG2900 controller.
+ * @sub_version: Subversion of the controller, e.g. to indicate a certain
+ * tape-out of the controller.
+ */
+void cg2900_fm_set_chip_version(
+ u16 revision,
+ u16 sub_version
+ );
+
+#endif /* CG2900_FM_API_H */
diff --git a/drivers/media/radio/CG2900/cg2900_fm_driver.c b/drivers/media/radio/CG2900/cg2900_fm_driver.c
new file mode 100644
index 00000000000..086f2ae9619
--- /dev/null
+++ b/drivers/media/radio/CG2900/cg2900_fm_driver.c
@@ -0,0 +1,4610 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Linux FM Driver for CG2900 FM Chip
+ *
+ * Author: Hemant Gupta <hemant.gupta@stericsson.com> for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/time.h>
+#include <linux/mfd/cg2900.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <asm-generic/errno-base.h>
+#include <mach/cg2900_devices.h>
+#include "cg2900_fm_driver.h"
+
+/*
+ * Macro for printing the HCI Packet received from Protocol Driver
+ * to FM Driver.
+ */
+#define CG2900_HEX_READ_PACKET_DUMP \
+ if (cg2900_fm_debug_level == FM_HCI_PACKET_LOGS) \
+ fmd_hexdump('<', skb->data, skb->len);
+
+/* Macro for printing the HCI Packet sent to Protocol Driver from FM Driver */
+#define CG2900_HEX_WRITE_PACKET_DUMP \
+ if (cg2900_fm_debug_level == FM_HCI_PACKET_LOGS) \
+ fmd_hexdump('>', send_buffer, num_bytes);
+
+/* Converts the given value to ASCII format*/
+#define ASCVAL(x)(((x) <= 9) ? (x) + '0' : (x) - 10 + 'a')
+
+/* The receive Packet's 1st byte indicates the packet length */
+#define FM_GET_PKT_LEN(__data) __data[0]
+
+/* The receive Packet's following bytes are the actual data. */
+#define FM_GET_RSP_PKT_ADDR(__data) (&__data[1])
+
+/*
+ * LSB consists of shifting the command Id by 3 bits
+ * to left and ORING with the number of parameters of the
+ * command.
+ */
+#define FM_CMD_GET_LSB(__cmd_id, __num_param) \
+ ((u8)(((__cmd_id << 3) & 0x00FF) | __num_param))
+
+/* MSB consists of shifting the command Id by 5 bits to right. */
+#define FM_CMD_GET_MSB(__cmd_id) \
+ ((u8)(__cmd_id >> 5))
+
+/*
+ * Command id is mapped as shifting the MSB 5 bits to left and
+ * ORING with LSB shifted 3 bits to right.
+ */
+#define FM_GET_CMD_ID(__data) \
+ ((u16)((__data[2] << 5) | __data[1] >> 3))
+
+/*
+ * Number of parameters in the response packet are the last 3 bits
+ * of the 1st byte of the received packet.
+ */
+#define FM_GET_NUM_PARAMS(__data) \
+ ((u16)((__data[1] & 0x07)))
+
+/* Function Id is mapped to the 1st byte of the received packet */
+#define FM_GET_FUNCTION_ID(__data) __data[0]
+
+/*
+ * Block Id of the FM Firmware downloaded is mapped to the
+ * 2nd byte of the received packet.
+ */
+#define FM_GET_BLOCK_ID(__data) __data[1]
+
+/* Status of the received packet is mapped to the 4th byte. */
+#define FM_GET_STATUS(__data) __data[3]
+
+/*
+ * For PG1 of CG2900, the FM Interrupt is mapped
+ * to the 3rd and 4th byte of the received packet.
+ */
+#define FM_GET_PGI_INTERRUPT(__data) \
+ ((u16)(__data[3] << 8 | __data[2]))
+
+/*
+ * For PG2 of CG2900, the FM Interrupt is mapped
+ * to the 5th and 6th byte of the received packet.
+ */
+#define FM_GET_PG2_INTERRUPT(__data) \
+ ((u16)(__data[5] << 8 | __data[4]))
+
+#define FM_GET_NUM_RDS_GRPS(__data) __data[0]
+
+/* Response buffer starts from the 4th byte if the response buffer */
+#define FM_GET_RSP_BUFFER_ADDR(__data) (&__data[3])
+
+/* FM Function buffer starts from the 5th byte if the response buffer */
+#define FM_GET_FUNCTION_ADDR(__data) (&__data[4])
+
+/*
+ * Maximum time for chip to respond including the Command
+ * Competion interrupts for some commands. This time has been
+ * adjusted to cater to increased communication time with chip
+ * when debug level is set to 4.
+ */
+#define MAX_RESPONSE_TIME_IN_MS 5000
+
+/*
+ * enum fmd_gocmd_t - FM Driver Command state.
+ *
+ * @FMD_STATE_NONE: FM Driver in Idle state
+ * @FMD_STATE_MODE: FM Driver in setmode state
+ * @FMD_STATE_FREQUENCY: FM Driver in Set frequency state.
+ * @FMD_STATE_PA: FM Driver in SetPA state.
+ * @FMD_STATE_PA_LEVEL: FM Driver in Setpalevl state.
+ * @FMD_STATE_ANTENNA: FM Driver in Setantenna state
+ * @FMD_STATE_MUTE: FM Driver in Setmute state
+ * @FMD_STATE_SEEK: FM Driver in seek mode
+ * @FMD_STATE_SEEK_STOP: FM Driver in seek stop level state.
+ * @FMD_STATE_SCAN_BAND: FM Driver in Scanband mode
+ * @FMD_STATE_TX_SET_CTRL: FM Driver in RDS control state
+ * @FMD_STATE_TX_SET_THRSHLD: FM Driver in RDS threshld state
+ * @FMD_STATE_GEN_POWERUP: FM Driver in Power UP state.
+ * @FMD_STATE_SELECT_REF_CLK: FM Driver in Select Reference clock state.
+ * @FMD_STATE_SET_REF_CLK_PLL: FM Driver in Set Reference Freq state.
+ * @FMD_STATE_BLOCK_SCAN: FM Driver in Block Scan state.
+ * @FMD_STATE_AF_UPDATE: FM Driver in AF Update State.
+ * @FMD_STATE_AF_SWITCH: FM Driver in AF Switch State.
+ * @FMD_STATE_LAST: Last State of FM Driver
+ *
+ * Various states of the FM driver.
+ */
+enum fmd_gocmd {
+ FMD_STATE_NONE,
+ FMD_STATE_MODE,
+ FMD_STATE_FREQUENCY,
+ FMD_STATE_PA,
+ FMD_STATE_PA_LEVEL,
+ FMD_STATE_ANTENNA,
+ FMD_STATE_MUTE,
+ FMD_STATE_SEEK,
+ FMD_STATE_SEEK_STOP,
+ FMD_STATE_SCAN_BAND,
+ FMD_STATE_TX_SET_CTRL,
+ FMD_STATE_TX_SET_THRSHLD,
+ FMD_STATE_GEN_POWERUP,
+ FMD_STATE_SELECT_REF_CLK,
+ FMD_STATE_SET_REF_CLK_PLL,
+ FMD_STATE_BLOCK_SCAN,
+ FMD_STATE_AF_UPDATE,
+ FMD_STATE_AF_SWITCH,
+ FMD_STATE_LAST
+};
+
+/**
+ * struct fmd_rdsgroup_t - Rds group structure.
+ *
+ * @block: Array for RDS Block(s) received.
+ * @status: Array of Status of corresponding RDS block(s).
+ *
+ * It stores the value and status of a particular RDS group
+ * received.
+ */
+struct fmd_rds_group {
+ u16 block[NUM_OF_RDS_BLOCKS];
+ u8 status[NUM_OF_RDS_BLOCKS];
+};
+
+/**
+ * struct fmd_states_info - Main FM state info structure.
+ *
+ * @fmd_initialized: Flag indicating FM Driver is initialized or not
+ * @rx_freq_range: Receiver freq range
+ * @rx_volume: Receiver volume level
+ * @rx_antenna: Receiver Antenna
+ * @rx_seek_stop_level: RDS seek stop Level
+ * @rx_rds_on: Receiver RDS ON
+ * @rx_stereo_mode: Receiver Stereo mode
+ * @max_channels_to_scan: Maximum Number of channels to Scan.
+ * @tx_freq_range: Transmitter freq Range
+ * @tx_preemphasis: Transmitter Pre emphiasis level
+ * @tx_stereo_mode: Transmitter stero mode
+ * @tx_rds_on: Enable RDS
+ * @tx_pilot_dev: PIlot freq deviation
+ * @tx_rds_dev: RDS deviation
+ * @tx_strength: TX Signal Stregnth
+ * @irq_index: Index where last interrupt is added to Interrupt queue
+ * @interrupt_available_for_processing: Flag indicating if interrupt is
+ * available for processing or not.
+ * @interrupt_queue: Circular Queue to store the received interrupt from chip.
+ * @gocmd: Command which is in progress.
+ * @rds_group: Array of RDS group Buffer
+ * @callback: Callback registered by upper layers.
+ */
+struct fmd_states_info {
+ bool fmd_initialized;
+ u8 rx_freq_range;
+ u8 rx_volume;
+ u8 rx_antenna;
+ u16 rx_seek_stop_level;
+ bool rx_rds_on;
+ u8 rx_stereo_mode;
+ u8 tx_freq_range;
+ u8 tx_preemphasis;
+ bool tx_stereo_mode;
+ u8 max_channels_to_scan;
+ bool tx_rds_on;
+ u16 tx_pilot_dev;
+ u16 tx_rds_dev;
+ u16 tx_strength;
+ u8 irq_index;
+ bool interrupt_available_for_processing;
+ u16 interrupt_queue[MAX_COUNT_OF_IRQS];
+ enum fmd_gocmd gocmd;
+ struct fmd_rds_group rds_group[MAX_RDS_GROUPS];
+ fmd_radio_cb callback;
+};
+
+/**
+ * struct fmd_data - Main structure for FM data exchange.
+ *
+ * @cmd_id: Command Id of the command being exchanged.
+ * @num_parameters: Number of parameters
+ * @parameters: FM data parameters.
+ */
+struct fmd_data {
+ u32 cmd_id;
+ u16 num_parameters;
+ u8 *parameters;
+};
+
+static struct fmd_states_info fmd_state_info;
+static struct fmd_data fmd_data;
+static struct semaphore cmd_sem;
+static struct semaphore rds_sem;
+static struct semaphore interrupt_sem;
+static struct task_struct *rds_thread_task;
+static struct task_struct *irq_thread_task;
+static struct cg2900_device *cg2900_fm_cmd_evt;
+static struct mutex write_mutex;
+static struct mutex send_cmd_mutex;
+static struct mutex read_mutex;
+static spinlock_t fmd_spinlock;
+
+/* Debug Level
+ * 1: Only Error Logs
+ * 2: Info Logs
+ * 3: Debug Logs
+ * 4: HCI Logs
+ */
+unsigned short cg2900_fm_debug_level = FM_ERROR_LOGS;
+EXPORT_SYMBOL(cg2900_fm_debug_level);
+
+static cg2900_fm_rds_cb cb_rds_func;
+static bool rds_thread_required;
+static bool irq_thread_required;
+
+static char event_name[FMD_EVENT_LAST_ELEMENT][MAX_NAME_SIZE] = {
+ "FMD_EVENT_OPERATION_COMPLETED",
+ "FMD_EVENT_ANTENNA_STATUS_CHANGED",
+ "FMD_EVENT_FREQUENCY_CHANGED",
+ "FMD_EVENT_SEEK_COMPLETED",
+ "FMD_EVENT_SCAN_BAND_COMPLETED",
+ "FMD_EVENT_BLOCK_SCAN_COMPLETED",
+ "FMD_EVENT_AF_UPDATE_SWITCH_COMPLETE",
+ "FMD_EVENT_MONO_STEREO_TRANSITION_COMPLETE",
+ "FMD_EVENT_SEEK_STOPPED",
+ "FMD_EVENT_GEN_POWERUP",
+ "FMD_EVENT_RDSGROUP_RCVD",
+};
+
+static char interrupt_name[MAX_COUNT_OF_IRQS][MAX_NAME_SIZE] = {
+ "IRPT_OPERATION_SUCCEEDED",
+ "IRPT_OPERATION_FAILED",
+ "IRPT_NOT_DEFINED",
+ "IRPT_RX_BUFFER_FULL_OR_TX_BUFFER_EMPTY",
+ "IRPT_RX_SIGNAL_QUALITY_LOW_OR_TX_MUTE_STATUS_CHANGED",
+ "IRPT_MONO_STEREO_TRANSITION",
+ "IRPT_RX_RDS_SYNC_FOUND_OR_TX_INPUT_OVERDRIVE",
+ "IRPT_RDS_SYNC_LOST",
+ "IRPT_PI_CODE_CHANGED",
+ "IRPT_REQUESTED_BLOCK_AVAILABLE",
+ "IRPT_NOT_DEFINED",
+ "IRPT_NOT_DEFINED",
+ "IRPT_NOT_DEFINED",
+ "IRPT_NOT_DEFINED",
+ "IRPT_WARM_BOOT_READY",
+ "IRPT_COLD_BOOT_READY",
+};
+
+
+static void fmd_hexdump(
+ char prompt,
+ u8 *buffer,
+ int num_bytes
+ );
+static u8 fmd_get_event(
+ enum fmd_gocmd gocmd
+ );
+static void fmd_event_name(
+ u8 event,
+ char *event_name
+ );
+static char *fmd_get_fm_function_name(
+ u8 fm_function
+ );
+static void fmd_interrupt_name(
+ u16 interrupt,
+ char *interrupt_name
+ );
+static void fmd_add_interrupt_to_queue(
+ u16 interrupt
+ );
+static void fmd_process_interrupt(
+ u16 interrupt
+ );
+static void fmd_callback(
+ u8 event,
+ bool event_successful
+ );
+static int fmd_rx_frequency_to_channel(
+ u32 freq,
+ u16 *channel
+ );
+static int fmd_rx_channel_to_frequency(
+ u16 channel_number,
+ u32 *frequency
+ );
+static int fmd_tx_frequency_to_channel(
+ u32 freq,
+ u16 *channel
+ );
+static int fmd_tx_channel_to_frequency(
+ u16 channel_number,
+ u32 *frequency
+ );
+static bool fmd_go_cmd_busy(void);
+static int fmd_send_cmd_and_read_resp(
+ const u16 cmd_id,
+ const u16 num_parameters,
+ const u16 *parameters,
+ u16 *resp_num_parameters,
+ u16 *resp_parameters
+ );
+static int fmd_send_cmd(
+ const u16 cmd_id,
+ const u16 num_parameters,
+ const u16 *parameters
+ );
+static int fmd_read_resp(
+ u16 *cmd_id,
+ u16 *num_parameters,
+ u16 *parameters
+ );
+static void fmd_process_fm_function(
+ u8 *packet_buffer
+ );
+static int fmd_write_file_block(
+ u32 file_block_id,
+ u8 *file_block,
+ u16 file_block_length
+ );
+static void fmd_receive_data(
+ u16 packet_length,
+ u8 *packet_buffer
+ );
+static int fmd_rds_thread(
+ void *data
+ );
+static void fmd_start_irq_thread(void);
+static void fmd_stop_irq_thread(void);
+static int fmd_irq_thread(
+ void *data
+ );
+static int fmd_send_packet(
+ u16 num_bytes,
+ u8 *send_buffer
+ );
+static int fmd_get_cmd_sem(void);
+static void fmd_set_cmd_sem(void);
+static void fmd_get_interrupt_sem(void);
+static void fmd_set_interrupt_sem(void);
+static bool fmd_driver_init(void);
+static void fmd_driver_exit(void);
+
+static void fmd_read_cb(
+ struct cg2900_device *dev,
+ struct sk_buff *skb
+ );
+
+static void fmd_reset_cb(
+ struct cg2900_device *dev
+ );
+
+
+/* structure declared in time.h */
+struct timespec time_spec;
+
+/**
+ * struct cg2900_fm_cb - Specifies callback structure for cg2900 user.
+ *
+ * @read_cb: Callback function called when data is received from the
+ * controller
+ * @reset_cb: Callback function called when the controller has been reset
+ * This type specifies callback structure for cg2900 user.
+ */
+static struct cg2900_callbacks cg2900_fm_cb = {
+ .read_cb = fmd_read_cb,
+ .reset_cb = fmd_reset_cb
+};
+
+
+/**
+ * fmd_hexdump() - Displays the HCI Data Bytes exchanged with FM Chip.
+ *
+ * @prompt: Prompt signifying the direction '<' for Rx '>' for Tx
+ * @buffer: Buffer to be displayed.
+ * @num_bytes: Number of bytes of the buffer.
+ */
+ static void fmd_hexdump(
+ char prompt,
+ u8 *buffer,
+ int num_bytes
+ )
+{
+ int i;
+ u8 tmp_val;
+ struct timespec time;
+ static u8 pkt_write[MAX_BUFFER_SIZE], *pkt_ptr;
+
+ getnstimeofday(&time);
+ sprintf(pkt_write, "\n[%08x:%08x] [%04x] %c",
+ (unsigned int)time.tv_sec,
+ (unsigned int)time.tv_nsec,
+ num_bytes, prompt);
+
+ pkt_ptr = pkt_write + strlen(pkt_write);
+ if (buffer == NULL)
+ return;
+
+ /* Copy the buffer only if the input buffer is not NULL */
+ for (i = 0; i < num_bytes; i++) {
+ *pkt_ptr++ = ' ';
+ tmp_val = buffer[i] >> 4;
+ *pkt_ptr++ = ASCVAL(tmp_val);
+ tmp_val = buffer[i] & 0x0F;
+ *pkt_ptr++ = ASCVAL(tmp_val);
+ if (i > 20) {
+ /* Print only 20 bytes at max */
+ break;
+ }
+ }
+ *pkt_ptr++ = '\0';
+ FM_HEX_REPORT("%s", pkt_write);
+}
+
+/**
+ * fmd_get_event() - Returns the Event based on FM Driver State.
+ *
+ * @gocmd: Pending FM Command
+ *
+ * Returns: Corresponding Event
+ */
+static u8 fmd_get_event(
+ enum fmd_gocmd gocmd
+ )
+{
+ u8 event = FMD_EVENT_OPERATION_COMPLETED;
+ switch (gocmd) {
+ case FMD_STATE_ANTENNA:
+ event = FMD_EVENT_ANTENNA_STATUS_CHANGED;
+ break;
+ case FMD_STATE_FREQUENCY:
+ event = FMD_EVENT_FREQUENCY_CHANGED;
+ break;
+ case FMD_STATE_SEEK:
+ event = FMD_EVENT_SEEK_COMPLETED;
+ break;
+ case FMD_STATE_SCAN_BAND:
+ event = FMD_EVENT_SCAN_BAND_COMPLETED;
+ break;
+ case FMD_STATE_BLOCK_SCAN:
+ event = FMD_EVENT_BLOCK_SCAN_COMPLETED;
+ break;
+ case FMD_STATE_AF_UPDATE:
+ /* Drop Down */
+ case FMD_STATE_AF_SWITCH:
+ event = FMD_EVENT_AF_UPDATE_SWITCH_COMPLETE;
+ break;
+ case FMD_STATE_SEEK_STOP:
+ event = FMD_EVENT_SEEK_STOPPED;
+ break;
+ default:
+ event = FMD_EVENT_OPERATION_COMPLETED;
+ break;
+ }
+ return event;
+}
+
+/**
+ * fmd_event_name() - Converts the event to a displayable string.
+ *
+ * @event: Event that has occurred.
+ * @eventname: (out) Buffer to store event name.
+ */
+static void fmd_event_name(
+ u8 event,
+ char *eventname
+ )
+{
+ if (eventname == NULL) {
+ FM_ERR_REPORT("fmd_event_name: Output Buffer is NULL");
+ return;
+ }
+ if (event < FMD_EVENT_LAST_ELEMENT)
+ strcpy(eventname, event_name[event]);
+ else
+ strcpy(eventname, "FMD_EVENT_UNKNOWN");
+}
+
+/**
+ * fmd_get_fm_function_name() - Returns the FM Fucntion name.
+ *
+ * @fm_function: Function whose name is to be retrieved.
+ *
+ * Returns FM Function Name.
+ */
+static char *fmd_get_fm_function_name(
+ u8 fm_function
+ )
+{
+ switch (fm_function) {
+ case FM_FUNCTION_ENABLE:
+ return "FM_FUNCTION_ENABLE";
+ break;
+ case FM_FUNCTION_DISABLE:
+ return "FM_FUNCTION_DISABLE";
+ break;
+ case FM_FUNCTION_RESET:
+ return "FM_FUNCTION_RESET";
+ break;
+ case FM_FUNCTION_WRITE_COMMAND:
+ return "FM_FUNCTION_WRITE_COMMAND";
+ break;
+ case FM_FUNCTION_SET_INT_MASK_ALL:
+ return "FM_FUNCTION_SET_INT_MASK_ALL";
+ break;
+ case FM_FUNCTION_GET_INT_MASK_ALL:
+ return "FM_FUNCTION_GET_INT_MASK_ALL";
+ break;
+ case FM_FUNCTION_SET_INT_MASK:
+ return "FM_FUNCTION_SET_INT_MASK";
+ break;
+ case FM_FUNCTION_GET_INT_MASK:
+ return "FM_FUNCTION_GET_INT_MASK";
+ break;
+ case FM_FUNCTION_FIRMWARE_DOWNLOAD:
+ return "FM_FUNCTION_FIRMWARE_DOWNLOAD";
+ break;
+ default:
+ return "FM_FUNCTION_UNKNOWN";
+ break;
+ }
+}
+
+/**
+ * fmd_interrupt_name() - Converts the interrupt to a displayable string.
+ *
+ * @interrupt: interrupt received from FM Chip
+ * @interruptname: (out) Buffer to store interrupt name.
+ */
+static void fmd_interrupt_name(
+ u16 interrupt,
+ char *interruptname
+ )
+{
+ int index;
+
+ if (interruptname == NULL) {
+ FM_ERR_REPORT("fmd_interrupt_name: Output Buffer is NULL!!!");
+ return;
+ }
+ /* Convert Interrupt to Bit */
+ for (index = 0; index < MAX_COUNT_OF_IRQS; index++) {
+ if (interrupt & (1 << index)) {
+ /* Match found, break the loop */
+ break;
+ }
+ }
+ if (index < MAX_COUNT_OF_IRQS)
+ strcpy(interruptname, interrupt_name[index]);
+ else
+ strcpy(interruptname, "IRPT_UNKNOWN");
+}
+
+/**
+ * fmd_add_interrupt_to_queue() - Add interrupt to IRQ Queue.
+ *
+ * @interrupt: interrupt received from FM Chip
+ */
+static void fmd_add_interrupt_to_queue(
+ u16 interrupt
+ )
+{
+ FM_DEBUG_REPORT("fmd_add_interrupt_to_queue : "
+ "Interrupt Received = %04x", (u16) interrupt);
+
+ /* Reset the index if it reaches the array limit */
+ if (fmd_state_info.irq_index > MAX_COUNT_OF_IRQS - 1) {
+ spin_lock(&fmd_spinlock);
+ fmd_state_info.irq_index = 0;
+ spin_unlock(&fmd_spinlock);
+ }
+
+ spin_lock(&fmd_spinlock);
+ fmd_state_info.interrupt_queue[fmd_state_info.irq_index] = interrupt;
+ fmd_state_info.irq_index++;
+ spin_unlock(&fmd_spinlock);
+ if (!fmd_state_info.interrupt_available_for_processing) {
+ spin_lock(&fmd_spinlock);
+ fmd_state_info.interrupt_available_for_processing = true;
+ spin_unlock(&fmd_spinlock);
+ fmd_set_interrupt_sem();
+ }
+}
+
+/**
+ * fmd_process_interrupt() - Processes the Interrupt.
+ *
+ * This function processes the interrupt received from FM Chip
+ * and calls the corresponding callback registered by upper layers with
+ * proper parameters.
+ * @interrupt: interrupt received from FM Chip
+ */
+static void fmd_process_interrupt(
+ u16 interrupt
+ )
+{
+ char irpt_name[MAX_NAME_SIZE];
+
+ fmd_interrupt_name(interrupt, irpt_name);
+ FM_DEBUG_REPORT("%s", irpt_name);
+ if ((interrupt & IRPT_OPERATION_SUCCEEDED) |
+ (interrupt & IRPT_OPERATION_FAILED)) {
+ bool event_status = (interrupt & IRPT_OPERATION_SUCCEEDED);
+ u8 event = fmd_get_event(fmd_state_info.gocmd);
+
+ switch (fmd_state_info.gocmd) {
+ case FMD_STATE_MODE:
+ /* Mode has been changed. */
+ case FMD_STATE_MUTE:
+ /* FM radio is Muter or Unmuted */
+ case FMD_STATE_PA:
+ /* Power Amplifier has been enabled/disabled */
+ case FMD_STATE_PA_LEVEL:
+ /* Power Amplifier Level has been changed. */
+ case FMD_STATE_GEN_POWERUP:
+ /* Gen Power Up Success confirmation received. */
+ case FMD_STATE_SELECT_REF_CLK:
+ /* Reference Clock has been selected. */
+ case FMD_STATE_SET_REF_CLK_PLL:
+ /* Reference Clock frequency has been changed. */
+ case FMD_STATE_TX_SET_CTRL:
+ /* Tx Control has been set. */
+ case FMD_STATE_TX_SET_THRSHLD:
+ /* Tx Threashold has been set. */
+ /* Set State to None and set the waiting semaphore. */
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ fmd_set_cmd_sem();
+ break;
+ case FMD_STATE_ANTENNA:
+ /* Antenna status has been changed. */
+ case FMD_STATE_SEEK_STOP:
+ /* Band scan, seek or block scan has completed. */
+ case FMD_STATE_AF_UPDATE:
+ /* AF Update has completed. */
+ case FMD_STATE_AF_SWITCH:
+ /* AF Switch has completed. */
+ case FMD_STATE_FREQUENCY:
+ /* Frequency has been changed. */
+ /*
+ * Set State to None, set the waiting semaphore,
+ * and inform upper layer.
+ */
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ fmd_set_cmd_sem();
+ fmd_callback(
+ event,
+ event_status);
+ break;
+ case FMD_STATE_SEEK:
+ /* Seek has completed. */
+ case FMD_STATE_SCAN_BAND:
+ /* Band scan has completed. */
+ case FMD_STATE_BLOCK_SCAN:
+ /* Block scan has completed. */
+ /*
+ * Set State to None. No need to set the
+ * semaphore since this is an asyncronous event.
+ */
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ /* Inform Upper layer. */
+ fmd_callback(event, event_status);
+ break;
+ default:
+ /* Do Nothing */
+ FM_ERR_REPORT("Default %s case of "\
+ "interrupt processing", event_status ? \
+ "Success" : "Failed");
+ break;
+ }
+ }
+
+ if (interrupt & IRPT_RX_BUFFERFULL_TX_BUFFEREMPTY) {
+ /*
+ * RDS Buffer Full or RDS Buffer Empty
+ * interrupt received from chip, indicating
+ * that RDS data is available if chip
+ * is in Rx mode or RDS data can be send
+ * to chip in case of Tx mode. Inform the
+ * upper layers about this interrupt.
+ */
+ fmd_callback(
+ FMD_EVENT_RDSGROUP_RCVD,
+ true);
+ }
+
+ if (interrupt & IRPT_RX_MONO_STEREO_TRANSITION) {
+ /*
+ * Mono Stereo Transition interrupt
+ * received from chip, inform the
+ * upper layers about it.
+ */
+ fmd_callback(
+ FMD_EVENT_MONO_STEREO_TRANSITION_COMPLETE,
+ true);
+ }
+
+ if ((interrupt & IRPT_COLD_BOOT_READY) |
+ (interrupt & IRPT_WARM_BOOT_READY)) {
+ switch (fmd_state_info.gocmd) {
+ case FMD_STATE_GEN_POWERUP:
+ /*
+ * Cold Boot/ Warm Boot Interrupt received from
+ * chip, indicating transition from
+ * power off/standby state to active state.
+ * Inform the upper layers about it.
+ */
+ fmd_callback(
+ FMD_EVENT_GEN_POWERUP,
+ true);
+ /* Set State to None and set the waiting semaphore. */
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ fmd_set_cmd_sem();
+ break;
+ default:
+ /* Do Nothing */
+ break;
+ }
+ }
+}
+
+/**
+ * fmd_callback() - Callback function for upper layers.
+ *
+ * Callback function that calls the registered callback of upper
+ * layers with proper parameters.
+ * @event: event for which the callback function was called
+ * from FM Driver.
+ * @event_successful: Signifying whether the event is called from FM
+ * Driver on receiving irpt_Operation_Succeeded or irpt_Operation_Failed.
+ */
+static void fmd_callback(
+ u8 event,
+ bool event_successful
+ )
+{
+ char event_name_string[MAX_NAME_SIZE];
+
+ fmd_event_name(event, event_name_string);
+
+ FM_DEBUG_REPORT("%s %x, %d", event_name_string,
+ (unsigned int)event , (unsigned int)event_successful);
+
+ if (fmd_state_info.callback)
+ fmd_state_info.callback(
+ event,
+ event_successful);
+}
+
+/**
+ * fmd_rx_frequency_to_channel() - Converts Rx frequency to channel number.
+ *
+ * Converts the Frequency in kHz to corresponding Channel number.
+ * This is used for FM Rx.
+ * @freq: Frequency in kHz.
+ * @channel: Channel Number corresponding to the given Frequency.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameters are not valid.
+ *
+ */
+static int fmd_rx_frequency_to_channel(
+ u32 freq,
+ u16 *channel
+ )
+{
+ u8 range;
+ int result;
+ u32 min_freq;
+ u32 max_freq;
+
+ if (channel == NULL) {
+ result = -EINVAL;
+ goto error;
+ }
+
+ result = fmd_get_freq_range(
+ &range);
+
+ if (result != 0)
+ goto error;
+
+ result = fmd_get_freq_range_properties(
+ range,
+ &min_freq,
+ &max_freq);
+
+ if (result != 0)
+ goto error;
+
+ if (freq > max_freq)
+ freq = max_freq;
+ else if (freq < min_freq)
+ freq = min_freq;
+
+ /*
+ * Frequency in kHz needs to be divided with 50 kHz to get
+ * channel number for all FM Bands
+ */
+ *channel = (u16)((freq - min_freq) / CHANNEL_FREQ_CONVERTER_MHZ);
+ result = 0;
+error:
+ return result;
+}
+
+/**
+ * fmd_rx_channel_to_frequency() - Converts Rx Channel number to frequency.
+ *
+ * Converts the Channel Number to corresponding Frequency in kHz.
+ * This is used for FM Rx.
+ * @channel_number: Channel Number to be converted.
+ * @frequency: Frequency corresponding to the corresponding channel in kHz.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameters are not valid.
+ *
+ */
+static int fmd_rx_channel_to_frequency(
+ u16 channel_number,
+ u32 *frequency
+ )
+{
+ u8 range;
+ int result;
+ u32 min_freq;
+ u32 max_freq;
+
+ if (frequency == NULL) {
+ result = -EINVAL;
+ goto error;
+ }
+
+ result = fmd_get_freq_range(
+ &range);
+
+ if (result != 0)
+ goto error;
+
+ result = fmd_get_freq_range_properties(
+ range,
+ &min_freq,
+ &max_freq);
+
+ if (result != 0)
+ goto error;
+
+ /*
+ * Channel Number needs to be multiplied with 50 kHz to get
+ * frequency in kHz for all FM Bands
+ */
+ *frequency = min_freq + (channel_number * CHANNEL_FREQ_CONVERTER_MHZ);
+
+ if (*frequency > max_freq)
+ *frequency = max_freq;
+ else if (*frequency < min_freq)
+ *frequency = min_freq;
+
+error:
+ return result;
+}
+
+/**
+ * fmd_tx_frequency_to_channel() - Converts Tx frequency to channel number.
+ *
+ * Converts the Frequency in kHz to corresponding Channel number.
+ * This is used for FM Tx.
+ * @freq: Frequency in kHz.
+ * @channel: (out)Channel Number corresponding to the given Frequency.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameters are not valid.
+ */
+static int fmd_tx_frequency_to_channel(
+ u32 freq,
+ u16 *channel
+ )
+{
+ u8 range;
+ int result;
+ u32 min_freq;
+ u32 max_freq;
+
+ if (channel == NULL) {
+ result = -EINVAL;
+ goto error;
+ }
+
+ result = fmd_tx_get_freq_range(
+ &range);
+
+ if (result != 0)
+ goto error;
+
+ result = fmd_get_freq_range_properties(
+ range,
+ &min_freq,
+ &max_freq);
+
+ if (result != 0)
+ goto error;
+
+ if (freq > max_freq)
+ freq = max_freq;
+ else if (freq < min_freq)
+ freq = min_freq;
+
+ /*
+ * Frequency in kHz needs to be divided with 50 kHz to get
+ * channel number for all FM Bands
+ */
+ *channel = (u16)((freq - min_freq) / CHANNEL_FREQ_CONVERTER_MHZ);
+ result = 0;
+error:
+ return result;
+}
+
+/**
+ * fmd_tx_channel_to_frequency() - Converts Tx Channel number to frequency.
+ *
+ * Converts the Channel Number to corresponding Frequency in kHz.
+ * This is used for FM Tx.
+ * @channel_number: Channel Number to be converted.
+ * @frequency: Frequency corresponding to the corresponding channel
+ * in kHz.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameters are not valid.
+ */
+static int fmd_tx_channel_to_frequency(
+ u16 channel_number,
+ u32 *frequency
+ )
+{
+ u8 range;
+ int result;
+ u32 min_freq;
+ u32 max_freq;
+
+ if (frequency == NULL) {
+ result = -EINVAL;
+ goto error;
+ }
+
+ result = fmd_tx_get_freq_range(
+ &range);
+
+ if (result != 0)
+ goto error;
+
+ result = fmd_get_freq_range_properties(
+ range,
+ &min_freq,
+ &max_freq);
+
+ if (result != 0)
+ goto error;
+
+ /*
+ * Channel Number needs to be multiplied with 50 kHz to get
+ * frequency in kHz for all FM Bands
+ */
+ *frequency = min_freq + (channel_number * CHANNEL_FREQ_CONVERTER_MHZ);
+
+ if (*frequency > max_freq)
+ *frequency = max_freq;
+ else if (*frequency < min_freq)
+ *frequency = min_freq;
+
+ result = 0;
+error:
+ return result;
+}
+
+/**
+ * fmd_go_cmd_busy() - Function to check if FM Driver is busy or idle
+ *
+ * Returns:
+ * false if FM Driver is Idle
+ * true otherwise
+ */
+static bool fmd_go_cmd_busy(void)
+{
+ return (fmd_state_info.gocmd != FMD_STATE_NONE);
+}
+
+/**
+ * fmd_read_cb() - Handle Received Data
+ *
+ * This function handles data received from connectivity protocol driver.
+ * @dev: Device receiving data.
+ * @skb: Buffer with data coming form device.
+ */
+static void fmd_read_cb(
+ struct cg2900_device *dev,
+ struct sk_buff *skb
+ )
+{
+ FM_INFO_REPORT("fmd_read_cb");
+
+ if (skb->data == NULL || skb->len == 0)
+ goto error;
+
+ mutex_lock(&read_mutex);
+ CG2900_HEX_READ_PACKET_DUMP;
+ /*
+ * The first byte is length of bytes following bytes
+ * Rest of the bytes are the actual data
+ */
+ fmd_receive_data(
+ FM_GET_PKT_LEN(skb->data),
+ FM_GET_RSP_PKT_ADDR(skb->data));
+
+error:
+ kfree_skb(skb);
+ mutex_unlock(&read_mutex);
+}
+
+/**
+ * fmd_receive_data() - Processes the FM data received from device.
+ *
+ * @packet_length: Length of received Data Packet
+ * @packet_buffer: Received Data buffer.
+ */
+static void fmd_receive_data(
+ u16 packet_length,
+ u8 *packet_buffer
+ )
+{
+ if (packet_buffer == NULL) {
+ FM_ERR_REPORT("fmd_receive_data: Buffer = NULL");
+ return;
+ }
+
+ if (packet_length == FM_PG1_INTERRUPT_EVENT_LEN &&
+ packet_buffer[0] == FM_CATENA_OPCODE &&
+ packet_buffer[1] == FM_EVENT_ID) {
+ /* PG 1.0 interrupt Handling */
+ u16 interrupt = FM_GET_PGI_INTERRUPT(packet_buffer);
+ FM_DEBUG_REPORT("interrupt = %04x",
+ (unsigned int)interrupt);
+ fmd_add_interrupt_to_queue(interrupt);
+ } else if (packet_length == FM_PG2_INTERRUPT_EVENT_LEN &&
+ packet_buffer[0] == FM_SUCCESS_STATUS &&
+ packet_buffer[1] == FM_CATENA_OPCODE &&
+ packet_buffer[2] == FM_EVENT &&
+ packet_buffer[3] == FM_EVENT_ID) {
+ /* PG 2.0 interrupt Handling */
+ u16 interrupt = FM_GET_PG2_INTERRUPT(packet_buffer);
+ FM_DEBUG_REPORT("interrupt = %04x",
+ (unsigned int)interrupt);
+ fmd_add_interrupt_to_queue(interrupt);
+ } else if (packet_buffer[0] == FM_SUCCESS_STATUS &&
+ packet_buffer[1] == FM_CATENA_OPCODE &&
+ packet_buffer[2] == FM_WRITE) {
+ /* Command Complete or RDS Data Handling */
+ u8 fm_status = FM_GET_STATUS(packet_buffer);;
+ switch (fm_status) {
+ case FM_CMD_STATUS_CMD_SUCCESS:
+ fmd_process_fm_function(
+ FM_GET_FUNCTION_ADDR(packet_buffer));
+ break;
+ case FM_CMD_STATUS_HCI_ERR_HW_FAILURE:
+ FM_DEBUG_REPORT(
+ "FM_CMD_STATUS_HCI_ERR_HW_FAILURE");
+ break;
+ case FM_CMD_STATUS_HCI_ERR_INVALID_PARAMETERS:
+ FM_DEBUG_REPORT(
+ "FM_CMD_STATUS_HCI_ERR_INVALID_PARAMETERS");
+ break;
+ case FM_CMD_STATUS_IP_UNINIT:
+ FM_DEBUG_REPORT(
+ "FM_CMD_STATUS_IP_UNINIT");
+ break;
+ case FM_CMD_STATUS_HCI_ERR_UNSPECIFIED_ERROR:
+ FM_DEBUG_REPORT(
+ "FM_CMD_STATUS_HCI_ERR_UNSPECIFIED_ERROR");
+ break;
+ case FM_CMD_STATUS_HCI_ERR_CMD_DISALLOWED:
+ FM_DEBUG_REPORT(
+ "FM_CMD_STATUS_HCI_ERR_CMD_DISALLOWED");
+ break;
+ case FM_CMD_STATUS_WRONG_SEQ_NUM:
+ FM_DEBUG_REPORT(
+ "FM_CMD_STATUS_WRONG_SEQ_NUM");
+ break;
+ case FM_CMD_STATUS_UNKNOWN_FILE_TYPE:
+ FM_DEBUG_REPORT(
+ "FM_CMD_STATUS_UNKNOWN_FILE_TYPE");
+ break;
+ case FM_CMD_STATUS_FILE_VERSION_MISMATCH:
+ FM_DEBUG_REPORT(
+ "FM_CMD_STATUS_FILE_VERSION_MISMATCH");
+ break;
+ default:
+ FM_DEBUG_REPORT(
+ "Unknown Status = %02x", fm_status);
+ break;
+ }
+ }
+}
+
+/**
+ * fmd_reset_cb() - Reset callback fuction.
+ *
+ * @dev: CPD device reseting.
+ */
+static void fmd_reset_cb(struct cg2900_device *dev)
+{
+ FM_INFO_REPORT("fmd_reset_cb: Device Reset");
+ cg2900_handle_device_reset();
+}
+
+/**
+ * fmd_rds_thread() - Thread for receiving RDS data from Chip.
+ *
+ * @data: Data beng passed as parameter on starting the thread.
+ */
+static int fmd_rds_thread(
+ void *data
+ )
+{
+ FM_INFO_REPORT("fmd_rds_thread Created Successfully");
+ while (rds_thread_required) {
+ if (cb_rds_func)
+ cb_rds_func();
+ /* Give 100 ms for context switching */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+ }
+ FM_DEBUG_REPORT("fmd_rds_thread Exiting!!!");
+ return 0;
+}
+
+/**
+ * fmd_start_irq_thread() - Function for starting Interrupt Thread.
+ */
+static void fmd_start_irq_thread(void)
+{
+ FM_INFO_REPORT("fmd_start_irq_thread");
+ irq_thread_task = kthread_create(fmd_irq_thread, NULL, "irq_thread");
+ if (IS_ERR(irq_thread_task)) {
+ FM_ERR_REPORT("fmd_start_irq_thread: "
+ "Unable to Create irq_thread");
+ irq_thread_task = NULL;
+ return;
+ }
+ wake_up_process(irq_thread_task);
+}
+
+/**
+ * fmd_stop_irq_thread() - Function for stopping Interrupt Thread.
+ */
+static void fmd_stop_irq_thread(void)
+{
+ FM_INFO_REPORT("fmd_stop_irq_thread");
+ kthread_stop(irq_thread_task);
+ irq_thread_task = NULL;
+ FM_DEBUG_REPORT("-fmd_stop_irq_thread");
+}
+
+/**
+ * fmd_irq_thread() - Thread for processing Interrupts received from Chip.
+ *
+ * @data: Data being passed as parameter on starting the thread.
+ */
+
+static int fmd_irq_thread(
+ void *data
+ )
+{
+ int index;
+
+ FM_INFO_REPORT("fmd_irq_thread Created Successfully");
+
+ while (irq_thread_required) {
+ if (!fmd_state_info.interrupt_available_for_processing) {
+ FM_DEBUG_REPORT("fmd_irq_thread: Waiting on irq sem "
+ "interrupt_available_for_processing = %d "
+ "fmd_state_info.fmd_initialized = %d",
+ fmd_state_info.interrupt_available_for_processing,
+ fmd_state_info.fmd_initialized);
+ fmd_get_interrupt_sem();
+ FM_DEBUG_REPORT("fmd_irq_thread: Waiting on irq sem "
+ "interrupt_available_for_processing = %d "
+ "fmd_state_info.fmd_initialized = %d",
+ fmd_state_info.interrupt_available_for_processing,
+ fmd_state_info.fmd_initialized);
+ }
+ index = 0;
+
+ if (fmd_state_info.interrupt_available_for_processing) {
+ while (index < MAX_COUNT_OF_IRQS) {
+ if (fmd_state_info.interrupt_queue[index]
+ != IRPT_INVALID) {
+ FM_DEBUG_REPORT("fmd_process_interrupt "
+ "Interrupt = %04x",
+ fmd_state_info.
+ interrupt_queue[index]);
+ fmd_process_interrupt(
+ fmd_state_info.interrupt_queue[index]);
+ fmd_state_info.interrupt_queue[index]
+ = IRPT_INVALID;
+ }
+ index++;
+ }
+ }
+ fmd_state_info.interrupt_available_for_processing = false;
+ }
+ FM_DEBUG_REPORT("fmd_irq_thread Exiting!!!");
+ return 0;
+}
+
+/**
+ * fmd_send_packet() - Sends the FM HCI Packet to the CG2900 Protocol Driver.
+ *
+ * @num_bytes: Number of bytes of Data to be sent including
+ * Channel Identifier (08)
+ * @send_buffer: Buffer containing the Data to be sent to Chip.
+ *
+ * Returns:
+ * 0, If packet was sent successfully to
+ * CG2900 Protocol Driver, otherwise the corresponding error.
+ * -EINVAL If parameters are not valid.
+ * -EIO If there is an Input/Output Error.
+ */
+static int fmd_send_packet(
+ u16 num_bytes,
+ u8 *send_buffer
+ )
+{
+ int err;
+ struct sk_buff *skb;
+
+ FM_INFO_REPORT("fmd_send_packet");
+
+ if (send_buffer == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ if (cg2900_fm_cmd_evt == NULL) {
+ FM_ERR_REPORT("fmd_send_packet: FM Driver is not "\
+ "registered with protocol driver");
+ err = -EIO;
+ goto error;
+ }
+
+ mutex_lock(&write_mutex);
+ CG2900_HEX_WRITE_PACKET_DUMP;
+ skb = cg2900_alloc_skb(num_bytes, GFP_KERNEL);
+
+ if (!skb) {
+ FM_ERR_REPORT("fmd_send_packet:Couldn't " \
+ "allocate sk_buff with length %d", num_bytes);
+ err = -EIO;
+ goto error;
+ }
+ /*
+ * Copy the buffer removing the FM Header as this
+ * would be done by Protocol Driver
+ */
+ memcpy(skb_put(skb, num_bytes), send_buffer, num_bytes);
+ err = cg2900_write(cg2900_fm_cmd_evt, skb);
+
+ if (err) {
+ FM_ERR_REPORT("fmd_send_packet: "
+ "Failed to send(%d) bytes using "
+ "cg2900_write, err = %d",
+ num_bytes, err);
+ kfree(skb);
+ err = -EIO;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ mutex_unlock(&write_mutex);
+ FM_DEBUG_REPORT("fmd_send_packet returning %d", err);
+ return err;
+}
+
+/**
+ * fmd_get_cmd_sem() - Block on Command Semaphore.
+ *
+ * This is required to ensure Flow Control in FM Driver.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ETIME if timeout occurs.
+ */
+static int fmd_get_cmd_sem(void)
+{
+ int ret_val;
+
+ FM_INFO_REPORT("fmd_get_cmd_sem");
+
+ ret_val = down_timeout(&cmd_sem,
+ msecs_to_jiffies(MAX_RESPONSE_TIME_IN_MS));
+
+ if (ret_val)
+ FM_ERR_REPORT("fmd_get_cmd_sem: down_timeout "
+ "returned error = %d", ret_val);
+
+ return ret_val;
+}
+
+/**
+ * fmd_set_cmd_sem() - Unblock on Command Semaphore.
+ *
+ * This is required to ensure Flow Control in FM Driver.
+ */
+static void fmd_set_cmd_sem(void)
+{
+ FM_DEBUG_REPORT("fmd_set_cmd_sem");
+
+ up(&cmd_sem);
+}
+
+/**
+ * fmd_get_interrupt_sem() - Block on Interrupt Semaphore.
+ *
+ * Till Interrupt is received, Interrupt Task is blocked.
+ */
+static void fmd_get_interrupt_sem(void)
+{
+ int ret_val;
+
+ FM_DEBUG_REPORT("fmd_get_interrupt_sem");
+
+ ret_val = down_killable(&interrupt_sem);
+
+ if (ret_val)
+ FM_ERR_REPORT("fmd_get_interrupt_sem: down_killable "
+ "returned error = %d", ret_val);
+}
+
+/**
+ * fmd_set_interrupt_sem() - Unblock on Interrupt Semaphore.
+ *
+ * on receiving Interrupt, Interrupt Task is un-blocked.
+ */
+static void fmd_set_interrupt_sem(void)
+{
+ FM_DEBUG_REPORT("fmd_set_interrupt_sem");
+ up(&interrupt_sem);
+}
+
+/**
+ * fmd_driver_init()- Initializes the Mutex, Semaphore, etc for FM Driver.
+ *
+ * It also registers FM Driver with the Protocol Driver.
+ *
+ * Returns:
+ * true if initialization is successful
+ * false if initiialization fails.
+ */
+static bool fmd_driver_init(void)
+{
+ bool ret_val;
+ struct cg2900_rev_data rev_data;
+
+ FM_INFO_REPORT("fmd_driver_init");
+ /* Initialize the semaphores */
+ sema_init(&cmd_sem, 0);
+ sema_init(&rds_sem, 0);
+ sema_init(&interrupt_sem, 0);
+ cb_rds_func = NULL;
+ rds_thread_required = false;
+ irq_thread_required = true;
+ cg2900_fm_cmd_evt = NULL;
+ /* Create Mutex For Reading and Writing */
+ mutex_init(&read_mutex);
+ mutex_init(&write_mutex);
+ mutex_init(&send_cmd_mutex);
+ spin_lock_init(&fmd_spinlock);
+ fmd_start_irq_thread();
+
+ /* Register the FM Driver with Connectivity Protocol Driver */
+ cg2900_fm_cmd_evt = cg2900_register_user(
+ CG2900_FM_RADIO, &cg2900_fm_cb);
+
+ if (!cg2900_fm_cmd_evt) {
+ FM_ERR_REPORT("fmd_driver_init: "
+ "Couldn't register CG2900_FM_RADIO to Protocol Driver."
+ "Either chip is not connected or "
+ "Protocol Driver is not initialized");
+ ret_val = false;
+ goto error;
+ }
+
+ if (!cg2900_get_local_revision(&rev_data)) {
+ FM_DEBUG_REPORT("No revision data available");
+ ret_val = false;
+ goto error;
+ }
+
+ FM_DEBUG_REPORT("Read revision data revision %04x "
+ "sub_version %04x",
+ rev_data.revision, rev_data.sub_version);
+ cg2900_fm_set_chip_version(rev_data.revision, rev_data.sub_version);
+ ret_val = true;
+
+error:
+ FM_DEBUG_REPORT("fmd_driver_init: Returning %d", ret_val);
+ return ret_val;
+}
+
+/**
+ * fmd_driver_exit() - Deinitializes the mutex, semaphores, etc.
+ *
+ * It also deregisters FM Driver with the Protocol Driver.
+ *
+ */
+static void fmd_driver_exit(void)
+{
+ FM_INFO_REPORT("fmd_driver_exit");
+ irq_thread_required = false;
+ mutex_destroy(&write_mutex);
+ mutex_destroy(&read_mutex);
+ mutex_destroy(&send_cmd_mutex);
+ fmd_stop_irq_thread();
+ /* Deregister the FM Driver with Connectivity Protocol Driver */
+ if (cg2900_fm_cmd_evt != NULL)
+ cg2900_deregister_user(cg2900_fm_cmd_evt);
+}
+
+/**
+ * fmd_send_cmd_and_read_resp() - Send command and read response.
+ *
+ * This function sends the HCI Command to Protocol Driver and
+ * Reads back the Response Packet.
+ * @cmd_id: Command Id to be sent to FM Chip.
+ * @num_parameters: Number of parameters of the command sent.
+ * @parameters: Buffer containing the Buffer to be sent.
+ * @resp_num_parameters: (out) Number of paramters of the response packet.
+ * @resp_parameters: (out) Buffer of the response packet.
+ *
+ * Returns:
+ * 0: If the command is sent successfully and the
+ * response received is also correct.
+ * -EINVAL: If the received response is not correct.
+ * -EIO: If there is an input/output error.
+ * -EINVAL: If parameters are not valid.
+ */
+static int fmd_send_cmd_and_read_resp(
+ const u16 cmd_id,
+ const u16 num_parameters,
+ const u16 *parameters,
+ u16 *resp_num_parameters,
+ u16 *resp_parameters
+ )
+{
+ int result;
+ u16 read_cmd_id = CMD_ID_NONE;
+
+ FM_INFO_REPORT("fmd_send_cmd_and_read_resp");
+
+ mutex_lock(&send_cmd_mutex);
+ result = fmd_send_cmd(
+ cmd_id,
+ num_parameters,
+ parameters);
+
+ if (result != 0)
+ goto error;
+
+ result = fmd_read_resp(
+ &read_cmd_id,
+ resp_num_parameters,
+ resp_parameters);
+
+ if (result != 0)
+ goto error;
+
+ /*
+ * Check that the response belongs to the sent command
+ */
+ if (read_cmd_id != cmd_id)
+ result = -EINVAL;
+
+error:
+ mutex_unlock(&send_cmd_mutex);
+ FM_DEBUG_REPORT("fmd_send_cmd_and_read_resp: "
+ "returning %d", result);
+ return result;
+}
+
+/**
+ * fmd_send_cmd() - This function sends the HCI Command
+ * to Protocol Driver.
+ *
+ * @cmd_id: Command Id to be sent to FM Chip.
+ * @num_parameters: Number of parameters of the command sent.
+ * @parameters: Buffer containing the Buffer to be sent.
+ *
+ * Returns:
+ * 0: If the command is sent successfully to Lower Layers.
+ * -EIO: If there is an input/output error.
+ * -EINVAL: If parameters are not valid.
+ */
+static int fmd_send_cmd(
+ const u16 cmd_id ,
+ const u16 num_parameters,
+ const u16 *parameters
+ )
+{
+ /*
+ * Total Length includes 6 bytes HCI Header
+ * and remaining bytes depending on number of paramters.
+ */
+ u16 total_length = num_parameters * sizeof(u16) + FM_HCI_CMD_HEADER_LEN;
+ /*
+ * Parameter Length includes 5 bytes HCI Header
+ * and remaining bytes depending on number of paramters.
+ */
+ u16 param_length = num_parameters * sizeof(u16) + FM_HCI_CMD_PARAM_LEN;
+ u8 *fm_data = kmalloc(total_length, GFP_KERNEL);
+ int err = -EINVAL;
+
+ FM_INFO_REPORT("fmd_send_cmd");
+
+ if (fm_data == NULL) {
+ err = -EIO;
+ goto error;
+ }
+
+ if (num_parameters && parameters == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ /* HCI encapsulation */
+ fm_data[0] = param_length;
+ fm_data[1] = FM_CATENA_OPCODE;
+ fm_data[2] = FM_WRITE;
+ fm_data[3] = FM_FUNCTION_WRITE_COMMAND;
+ fm_data[4] = FM_CMD_GET_LSB(cmd_id, num_parameters);
+ fm_data[5] = FM_CMD_GET_MSB(cmd_id);
+
+ memcpy(
+ (fm_data + FM_HCI_CMD_HEADER_LEN),
+ (void *)parameters,
+ num_parameters * sizeof(u16));
+
+ /* Send the Packet */
+ err = fmd_send_packet(total_length , fm_data);
+
+error:
+ kfree(fm_data);
+ FM_DEBUG_REPORT("fmd_send_cmd: "
+ "returning %d", err);
+ return err;
+}
+
+/**
+ * fmd_read_resp() - This function reads the response packet of the previous
+ * command sent to FM Chip and copies it to the buffer provided as parameter.
+ *
+ * @cmd_id: (out) Command Id received from FM Chip.
+ * @num_parameters: (out) Number of paramters of the response packet.
+ * @parameters: (out) Buffer of the response packet.
+ *
+ * Returns:
+ * 0: If the response buffer is copied successfully.
+ * -EINVAL: If parameters are not valid.
+ * -ETIME: Otherwise
+ */
+static int fmd_read_resp(
+ u16 *cmd_id,
+ u16 *num_parameters,
+ u16 *parameters
+ )
+{
+ int err;
+ FM_INFO_REPORT("fmd_read_resp");
+
+ /* Wait till response of the command is received */
+ if (fmd_get_cmd_sem()) {
+ err = -ETIME;
+ goto error;
+ }
+
+ /* Check if the parameters are valid */
+ if (cmd_id == NULL || (fmd_data.num_parameters &&
+ (num_parameters == NULL || parameters == NULL))) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ /* Fill the arguments */
+ *cmd_id = fmd_data.cmd_id;
+ if (fmd_data.num_parameters) {
+ *num_parameters = fmd_data.num_parameters;
+ memcpy(
+ parameters,
+ fmd_data.parameters,
+ (*num_parameters * sizeof(u16)));
+ }
+
+ err = 0;
+
+error:
+ FM_DEBUG_REPORT("fmd_read_resp: "
+ "returning %d", err);
+ return err;
+}
+
+/**
+ * fmd_process_fm_function() - Process FM Function.
+ *
+ * This function processes the Response buffer received
+ * from lower layers for the FM function and performs the necessary action to
+ * parse the same.
+ * @packet_buffer: Received Buffer.
+ */
+static void fmd_process_fm_function(
+ u8 *packet_buffer
+ )
+{
+ u8 fm_function_id;
+ u8 block_id;
+
+ if (packet_buffer == NULL)
+ return;
+
+ fm_function_id = FM_GET_FUNCTION_ID(packet_buffer);
+ switch (fm_function_id) {
+ case FM_FUNCTION_ENABLE:
+ case FM_FUNCTION_DISABLE:
+ case FM_FUNCTION_RESET:
+ FM_DEBUG_REPORT(
+ "fmd_process_fm_function: "
+ "command success received for %s",
+ fmd_get_fm_function_name(fm_function_id));
+ /* Release the semaphore since response is received */
+ fmd_set_cmd_sem();
+ break;
+ case FM_FUNCTION_WRITE_COMMAND:
+ FM_DEBUG_REPORT(
+ "fmd_process_fm_function: "
+ "command success received for %s",
+ fmd_get_fm_function_name(fm_function_id));
+
+ fmd_data.cmd_id = FM_GET_CMD_ID(packet_buffer);
+ fmd_data.num_parameters =
+ FM_GET_NUM_PARAMS(packet_buffer);
+
+ FM_DEBUG_REPORT(
+ "fmd_process_fm_function: "
+ "Cmd Id = 0x%04x, Num Of Parms = %02x",
+ fmd_data.cmd_id, fmd_data.num_parameters);
+
+ if (fmd_data.num_parameters) {
+ fmd_data.parameters =
+ FM_GET_RSP_BUFFER_ADDR(packet_buffer);
+ memcpy(fmd_data.parameters,
+ FM_GET_RSP_BUFFER_ADDR(packet_buffer),
+ fmd_data.num_parameters * sizeof(u16));
+ }
+ /* Release the semaphore since response is received */
+ fmd_set_cmd_sem();
+ break;
+ case FM_FUNCTION_FIRMWARE_DOWNLOAD:
+ block_id = FM_GET_BLOCK_ID(packet_buffer);
+ FM_DEBUG_REPORT(
+ "fmd_process_fm_function: "
+ "command success received for %s"
+ "block id = %02x",
+ fmd_get_fm_function_name(fm_function_id),
+ block_id);
+ /* Release the semaphore since response is received */
+ fmd_set_cmd_sem();
+ break;
+ default:
+ FM_ERR_REPORT(
+ "fmd_process_fm_function: "
+ "default case: command success received for %s",
+ fmd_get_fm_function_name(fm_function_id));
+ break;
+ }
+}
+
+/**
+ * fmd_write_file_block() - download firmware.
+ *
+ * This Function adds the header for downloading
+ * the firmware and coeffecient files and sends it to Protocol Driver.
+ * @file_block_id: Block ID of the F/W to be transmitted to FM Chip
+ * @file_block: Buffer containing the bytes to be sent.
+ * @file_block_length: Size of the Firmware buffer.
+ *
+ * Returns:
+ * 0: If there is no error.
+ * -EINVAL: If parameters are not valid.
+ * -ETIME: Otherwise
+ */
+static int fmd_write_file_block(
+ u32 file_block_id,
+ u8 *file_block,
+ u16 file_block_length
+ )
+{
+ int err;
+
+ FM_INFO_REPORT("fmd_write_file_block");
+ if (file_block == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ mutex_lock(&send_cmd_mutex);
+ file_block[0] = file_block_length + FM_HCI_WRITE_FILE_BLK_PARAM_LEN;
+ file_block[1] = FM_CATENA_OPCODE;
+ file_block[2] = FM_WRITE;
+ file_block[3] = FM_FUNCTION_FIRMWARE_DOWNLOAD;
+ file_block[4] = file_block_id;
+ /* Send the Packet */
+ err = fmd_send_packet(
+ file_block_length +
+ FM_HCI_WRITE_FILE_BLK_HEADER_LEN,
+ file_block);
+
+ /* wait till response comes */
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+
+error:
+ mutex_unlock(&send_cmd_mutex);
+ FM_DEBUG_REPORT("fmd_write_file_block: "
+ "returning %d", err);
+ return err;
+}
+
+int fmd_init(void)
+{
+ int err;
+
+ if (!fmd_driver_init()) {
+ err = -EIO;
+ goto error;
+ }
+
+ memset(&fmd_state_info, 0, sizeof(fmd_state_info));
+ fmd_state_info.fmd_initialized = true;
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ fmd_state_info.callback = NULL;
+ fmd_state_info.rx_freq_range = FMD_FREQRANGE_EUROAMERICA;
+ fmd_state_info.rx_stereo_mode = FMD_STEREOMODE_BLENDING;
+ fmd_state_info.rx_volume = MAX_ANALOG_VOLUME;
+ fmd_state_info.rx_antenna = FMD_ANTENNA_EMBEDDED;
+ fmd_state_info.rx_rds_on = false;
+ fmd_state_info.rx_seek_stop_level = DEFAULT_RSSI_THRESHOLD;
+ fmd_state_info.tx_freq_range = FMD_FREQRANGE_EUROAMERICA;
+ fmd_state_info.tx_preemphasis = FMD_EMPHASIS_75US;
+ fmd_state_info.tx_pilot_dev = DEFAULT_PILOT_DEVIATION;
+ fmd_state_info.tx_rds_dev = DEFAULT_RDS_DEVIATION;
+ fmd_state_info.tx_strength = MAX_POWER_LEVEL;
+ fmd_state_info.max_channels_to_scan = DEFAULT_CHANNELS_TO_SCAN;
+ fmd_state_info.tx_stereo_mode = true;
+ fmd_state_info.irq_index = 0;
+ spin_lock_init(&fmd_spinlock);
+ err = 0;
+
+error:
+ FM_DEBUG_REPORT("fmd_init returning = %d", err);
+ return err;
+}
+
+void fmd_exit(void)
+{
+ fmd_set_interrupt_sem();
+ fmd_driver_exit();
+ memset(&fmd_state_info, 0, sizeof(fmd_state_info));
+}
+
+int fmd_register_callback(
+ fmd_radio_cb callback
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ fmd_state_info.callback = callback;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_get_version(
+ u16 *version
+ )
+{
+ int err;
+ int io_result;
+ u16 response_count;
+ u16 response_data[CMD_GET_VERSION_RSP_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (version == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_GEN_GET_VERSION,
+ CMD_GET_VERSION_PARAM_LEN,
+ NULL,
+ &response_count,
+ response_data);
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ memcpy(version,
+ response_data,
+ sizeof(u16) * CMD_GET_VERSION_RSP_PARAM_LEN);
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_set_mode(
+ u8 mode
+ )
+{
+ int err;
+ u16 parameters[CMD_GOTO_MODE_PARAM_LEN];
+ int io_result;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (mode > FMD_MODE_TX) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = mode;
+
+ fmd_state_info.gocmd = FMD_STATE_MODE;
+ FM_ERR_REPORT("Sending Set Mode");
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_GEN_GOTO_MODE,
+ CMD_GOTO_MODE_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_get_freq_range_properties(
+ u8 range,
+ u32 *min_freq,
+ u32 *max_freq
+ )
+{
+ int err;
+
+ if (min_freq == NULL || max_freq == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ switch (range) {
+ case FMD_FREQRANGE_EUROAMERICA:
+ *min_freq = FMD_EU_US_MIN_FREQ_IN_KHZ;
+ *max_freq = FMD_EU_US_MAX_FREQ_IN_KHZ;
+ break;
+ case FMD_FREQRANGE_JAPAN:
+ *min_freq = FMD_JAPAN_MIN_FREQ_IN_KHZ;
+ *max_freq = FMD_JAPAN_MAX_FREQ_IN_KHZ;
+ break;
+ case FMD_FREQRANGE_CHINA:
+ *min_freq = FMD_CHINA_MIN_FREQ_IN_KHZ;
+ *max_freq = FMD_CHINA_MAX_FREQ_IN_KHZ;
+ break;
+ default:
+ *min_freq = FMD_EU_US_MIN_FREQ_IN_KHZ;
+ *max_freq = FMD_EU_US_MAX_FREQ_IN_KHZ;
+ break;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_set_antenna(
+ u8 antenna
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SET_ANTENNA_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (antenna > FMD_ANTENNA_WIRED) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = antenna;
+
+ fmd_state_info.gocmd = FMD_STATE_ANTENNA;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SET_ANTENNA,
+ CMD_SET_ANTENNA_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.rx_antenna = antenna;
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_get_antenna(
+ u8 *antenna
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ *antenna = fmd_state_info.rx_antenna;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_set_freq_range(
+ u8 range
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_TN_SET_BAND_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ parameters[0] = range;
+ parameters[1] = FMD_MIN_CHANNEL_NUMBER;
+ parameters[2] = FMD_MAX_CHANNEL_NUMBER;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_TN_SET_BAND,
+ CMD_TN_SET_BAND_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+ fmd_state_info.rx_freq_range = range;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_get_freq_range(
+ u8 *range
+ )
+{
+ int err;
+
+ if (range == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ *range = fmd_state_info.rx_freq_range;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_set_grid(
+ u8 grid
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_TN_SET_GRID_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (grid > FMD_GRID_200KHZ) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = grid;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_TN_SET_GRID,
+ CMD_TN_SET_GRID_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_set_frequency(
+ u32 freq
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SP_TUNE_SET_CHANNEL_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (freq > FMD_EU_US_MAX_FREQ_IN_KHZ ||
+ freq < FMD_CHINA_MIN_FREQ_IN_KHZ) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ io_result = fmd_rx_frequency_to_channel(
+ freq,
+ &parameters[0]);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.gocmd = FMD_STATE_FREQUENCY;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SP_TUNE_SET_CHANNEL,
+ CMD_SP_TUNE_SET_CHANNEL_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_get_frequency(
+ u32 *freq
+ )
+{
+ int err;
+ int io_result;
+ u16 response_count;
+ u16 response_data[CMD_SP_TUNE_GET_CHANNEL_RSP_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (freq == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SP_TUNE_GET_CHANNEL,
+ CMD_SP_TUNE_GET_CHANNEL_PARAM_LEN,
+ NULL,
+ &response_count,
+ response_data);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ io_result = fmd_rx_channel_to_frequency(
+ response_data[0], /* 1st byte is the Frequency */
+ freq);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_set_stereo_mode(
+ u8 mode
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_RP_STEREO_SET_MODE_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (mode > FMD_STEREOMODE_BLENDING) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = mode;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_RP_STEREO_SET_MODE,
+ CMD_RP_STEREO_SET_MODE_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.rx_stereo_mode = mode;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_get_stereo_mode(
+ u8 *mode
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (mode == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *mode = fmd_state_info.rx_stereo_mode;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_get_signal_strength(
+ u16 *strength
+ )
+{
+ int err;
+ int io_result;
+ u16 response_count;
+ u16 response_data[CMD_RP_GET_RSSI_RSP_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (strength == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_RP_GET_RSSI,
+ CMD_RP_GET_RSSI_PARAM_LEN,
+ NULL,
+ &response_count,
+ response_data);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ *strength = response_data[0]; /* 1st byte is the signal strength */
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_set_stop_level(
+ u16 stoplevel
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ fmd_state_info.rx_seek_stop_level = stoplevel;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_get_stop_level(
+ u16 *stop_level
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (stop_level == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *stop_level = fmd_state_info.rx_seek_stop_level;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_seek(
+ bool upwards
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SP_SEARCH_START_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (upwards)
+ parameters[0] = 0x0000;
+ else
+ parameters[0] = 0x0001;
+ parameters[1] = fmd_state_info.rx_seek_stop_level;
+ parameters[2] = DEFAULT_PEAK_NOISE_VALUE;
+ parameters[3] = DEFAULT_AVERAGE_NOISE_MAX_VALUE;
+ fmd_state_info.gocmd = FMD_STATE_SEEK;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SP_SEARCH_START,
+ CMD_SP_SEARCH_START_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_scan_band(
+ u8 max_channels_to_scan
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SP_SCAN_START_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (max_channels_to_scan > MAX_CHANNELS_TO_SCAN) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = max_channels_to_scan;
+ parameters[1] = fmd_state_info.rx_seek_stop_level;
+ parameters[2] = DEFAULT_PEAK_NOISE_VALUE;
+ parameters[3] = DEFAULT_AVERAGE_NOISE_MAX_VALUE;
+
+ fmd_state_info.gocmd = FMD_STATE_SCAN_BAND;
+ fmd_state_info.max_channels_to_scan = max_channels_to_scan;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SP_SCAN_START,
+ CMD_SP_SCAN_START_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_get_max_channels_to_scan(
+ u8 *max_channels_to_scan
+ )
+{
+ int err;
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (max_channels_to_scan == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *max_channels_to_scan = fmd_state_info.max_channels_to_scan;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_get_scan_band_info(
+ u32 index,
+ u16 *num_channels,
+ u16 *channels,
+ u16 *rssi
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SP_SCAN_GET_RESULT_PARAM_LEN];
+ u16 response_count;
+ u16 response_data[CMD_SP_SCAN_GET_RESULT_RSP_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (num_channels == NULL || rssi == NULL || channels == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = index;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SP_SCAN_GET_RESULT,
+ CMD_SP_SCAN_GET_RESULT_PARAM_LEN,
+ parameters,
+ &response_count,
+ response_data);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ /* 1st byte indicates number of channels found */
+ *num_channels = response_data[0];
+ /* 2nd byte indicates 1st channel number */
+ channels[0] = response_data[1];
+ /* 3rd byte indicates RSSI of corresponding channel */
+ rssi[0] = response_data[2];
+ /* 4th byte indicates 2nd channel number */
+ channels[1] = response_data[3];
+ /* 5th byte indicates RSSI of corresponding channel */
+ rssi[1] = response_data[4];
+ /* 6th byte indicates 3rd channel number */
+ channels[2] = response_data[5];
+ /* 7th byte indicates RSSI of corresponding channel */
+ rssi[2] = response_data[6];
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_block_scan(
+ u32 start_freq,
+ u32 stop_freq,
+ u8 antenna
+ )
+{
+ u16 start_channel;
+ u16 stop_channel;
+ int err;
+ int io_result;
+ u16 parameters[CMD_SP_BLOCK_SCAN_START_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (antenna > FMD_ANTENNA_WIRED) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ if (start_freq > FMD_EU_US_MAX_FREQ_IN_KHZ ||
+ start_freq < FMD_CHINA_MIN_FREQ_IN_KHZ) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ if (stop_freq > FMD_EU_US_MAX_FREQ_IN_KHZ ||
+ stop_freq < FMD_CHINA_MIN_FREQ_IN_KHZ) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ /* Convert the start frequency to corresponsing channel */
+ io_result = fmd_rx_frequency_to_channel(
+ start_freq,
+ &start_channel);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ /* Convert the end frequency to corresponsing channel */
+ io_result = fmd_rx_frequency_to_channel(
+ stop_freq,
+ &stop_channel);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ parameters[0] = start_channel;
+ parameters[1] = stop_channel;
+ parameters[2] = antenna;
+
+ fmd_state_info.gocmd = FMD_STATE_BLOCK_SCAN;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SP_BLOCK_SCAN_START,
+ CMD_SP_BLOCK_SCAN_START_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_get_block_scan_result(
+ u32 index,
+ u16 *num_channels,
+ u16 *rssi
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SP_BLOCK_SCAN_GET_RESULT_PARAM_LEN];
+ u16 response_count;
+ u16 response_data[CMD_SP_BLOCK_SCAN_GET_RESULT_RSP_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (num_channels == NULL || rssi == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = index;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SP_BLOCK_SCAN_GET_RESULT,
+ CMD_SP_BLOCK_SCAN_GET_RESULT_PARAM_LEN,
+ parameters,
+ &response_count,
+ response_data);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ /*
+ * Response packet has 1st byte as the number
+ * of channels, and the remaining 6 bytes as
+ * rssi values of the channels.
+ */
+ *num_channels = response_data[0];
+ rssi[0] = response_data[1];
+ rssi[1] = response_data[2];
+ rssi[2] = response_data[3];
+ rssi[3] = response_data[4];
+ rssi[4] = response_data[5];
+ rssi[5] = response_data[6];
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_stop_seeking(void)
+{
+ int err;
+ int io_result;
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (!(fmd_state_info.gocmd == FMD_STATE_SEEK ||
+ fmd_state_info.gocmd == FMD_STATE_SCAN_BAND)) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ fmd_state_info.gocmd = FMD_STATE_SEEK_STOP;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SP_STOP,
+ CMD_SP_STOP_PARAM_LEN,
+ NULL,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_af_update_start(
+ u32 freq
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SP_AF_UPDATE_START_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ io_result = fmd_rx_frequency_to_channel(
+ freq,
+ &parameters[0]);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.gocmd = FMD_STATE_AF_UPDATE;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SP_AF_UPDATE_START,
+ CMD_SP_AF_UPDATE_START_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ goto error;
+ }
+
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_get_af_update_result(
+ u16 *af_level
+ )
+{
+ int err;
+ int io_result;
+ u16 response_count;
+ u16 response_data[CMD_SP_AF_UPDATE_GET_RESULT_RSP_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (af_level == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SP_AF_UPDATE_GET_RESULT,
+ CMD_SP_AF_UPDATE_GET_RESULT_PARAM_LEN,
+ NULL,
+ &response_count,
+ response_data);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ /*
+ * 1st byte of response packet is the
+ * RSSI of the AF Frequency.
+ */
+ *af_level = response_data[0];
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_af_switch_start(
+ u32 freq,
+ u16 picode
+ )
+{
+
+ int err;
+ int io_result;
+ u16 parameters[CMD_SP_AF_SWITCH_START_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ io_result = fmd_rx_frequency_to_channel(
+ freq,
+ &parameters[0]);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ parameters[1] = picode;
+ parameters[2] = 0xFFFF; /* PI Mask */
+ parameters[3] = fmd_state_info.rx_seek_stop_level;
+ parameters[4] = 0x0000; /* Unmute when AF's PI matches expected PI */
+
+ fmd_state_info.gocmd = FMD_STATE_AF_SWITCH;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SP_AF_SWITCH_START,
+ CMD_SP_AF_SWITCH_START_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_get_af_switch_results(
+ u16 *afs_conclusion,
+ u16 *afs_level,
+ u16 *afs_pi
+ )
+{
+ int err;
+ int io_result;
+ u16 response_count;
+ u16 response_data[CMD_SP_AF_SWITCH_GET_RESULT_RWSP_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (afs_conclusion == NULL ||
+ afs_level == NULL ||
+ afs_pi == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_SP_AF_SWITCH_GET_RESULT,
+ CMD_SP_AF_SWITCH_GET_RESULT_PARAM_LEN,
+ NULL,
+ &response_count,
+ response_data);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ *afs_conclusion = response_data[0];
+ *afs_level = response_data[1];
+ *afs_pi = response_data[2];
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_get_rds(
+ bool *on
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (on == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *on = fmd_state_info.rx_rds_on;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_buffer_set_size(
+ u8 size
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_DP_BUFFER_SET_SIZE_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (size > MAX_RDS_GROUPS) {
+ err = -EIO;
+ goto error;
+ }
+
+ parameters[0] = size;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_DP_BUFFER_SET_SIZE,
+ CMD_DP_BUFFER_SET_SIZE_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_buffer_set_threshold(
+ u8 threshold
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_DP_BUFFER_SET_THRESHOLD_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (threshold > MAX_RDS_GROUPS) {
+ err = -EIO;
+ goto error;
+ }
+
+ parameters[0] = threshold;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_DP_BUFFER_SET_THRESHOLD,
+ CMD_DP_BUFFER_SET_THRESHOLD_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_set_rds(
+ u8 on_off_state
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_DP_SET_CONTROL_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ switch (on_off_state) {
+ case FMD_SWITCH_ON_RDS_SIMULATOR:
+ parameters[0] = 0xFFFF;
+ break;
+ case FMD_SWITCH_OFF_RDS:
+ default:
+ parameters[0] = 0x0000;
+ fmd_state_info.rx_rds_on = false;
+ break;
+ case FMD_SWITCH_ON_RDS:
+ parameters[0] = 0x0001;
+ fmd_state_info.rx_rds_on = true;
+ break;
+ case FMD_SWITCH_ON_RDS_ENHANCED_MODE:
+ parameters[0] = 0x0002;
+ fmd_state_info.rx_rds_on = true;
+ break;
+ }
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_DP_SET_CONTROL,
+ CMD_DP_SET_CONTROL_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_rx_get_low_level_rds_groups(
+ u8 index,
+ u16 *block1,
+ u16 *block2,
+ u16 *block3,
+ u16 *block4,
+ u8 *status1,
+ u8 *status2,
+ u8 *status3,
+ u8 *status4
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (block1 == NULL ||
+ block2 == NULL ||
+ block3 == NULL ||
+ block4 == NULL ||
+ status1 == NULL ||
+ status2 == NULL ||
+ status3 == NULL ||
+ status4 == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *block1 = fmd_state_info.rds_group[index].block[0];
+ *block2 = fmd_state_info.rds_group[index].block[1];
+ *block3 = fmd_state_info.rds_group[index].block[2];
+ *block4 = fmd_state_info.rds_group[index].block[3];
+ *status1 = fmd_state_info.rds_group[index].status[0];
+ *status2 = fmd_state_info.rds_group[index].status[1];
+ *status3 = fmd_state_info.rds_group[index].status[2];
+ *status4 = fmd_state_info.rds_group[index].status[3];
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_set_pa(
+ bool on
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_PA_SET_MODE_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (on)
+ parameters[0] = 0x0001;
+ else
+ parameters[0] = 0x0000;
+
+ fmd_state_info.gocmd = FMD_STATE_PA;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_PA_SET_MODE,
+ CMD_PA_SET_MODE_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_set_signal_strength(
+ u16 strength
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_PA_SET_CONTROL_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if ((strength > MAX_POWER_LEVEL)
+ || (strength < MIN_POWER_LEVEL)) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = strength;
+
+ fmd_state_info.gocmd = FMD_STATE_PA_LEVEL;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_PA_SET_CONTROL,
+ CMD_PA_SET_CONTROL_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.tx_strength = strength;
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_get_signal_strength(
+ u16 *strength
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (strength == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *strength = fmd_state_info.tx_strength;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_set_freq_range(
+ u8 range
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_TN_SET_BAND_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (range > FMD_FREQRANGE_CHINA) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = range;
+ parameters[1] = FMD_MIN_CHANNEL_NUMBER;
+ parameters[2] = FMD_MAX_CHANNEL_NUMBER;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_TN_SET_BAND,
+ CMD_TN_SET_BAND_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.tx_freq_range = range;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_get_freq_range(
+ u8 *range
+ )
+{
+ int err;
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (range == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *range = fmd_state_info.tx_freq_range;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_set_grid(
+ u8 grid
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_TN_SET_GRID_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (grid > FMD_GRID_200KHZ) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = grid;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_TN_SET_GRID,
+ CMD_TN_SET_GRID_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_set_preemphasis(
+ u8 preemphasis
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_RP_SET_PREEMPHASIS_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ switch (preemphasis) {
+ case FMD_EMPHASIS_50US:
+ parameters[0] = FMD_EMPHASIS_50US;
+ break;
+ case FMD_EMPHASIS_75US:
+ default:
+ parameters[0] = FMD_EMPHASIS_75US;
+ break;
+ }
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_RP_SET_PREEMPHASIS,
+ CMD_RP_SET_PREEMPHASIS_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.tx_preemphasis = preemphasis;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_get_preemphasis(
+ u8 *preemphasis
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (preemphasis == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *preemphasis = fmd_state_info.tx_preemphasis;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_set_frequency(
+ u32 freq
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SP_TUNE_SET_CHANNEL_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (freq > FMD_EU_US_MAX_FREQ_IN_KHZ ||
+ freq < FMD_CHINA_MIN_FREQ_IN_KHZ) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ io_result = fmd_tx_frequency_to_channel(
+ freq,
+ &parameters[0]);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.gocmd = FMD_STATE_FREQUENCY;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_SP_TUNE_SET_CHANNEL,
+ CMD_SP_TUNE_SET_CHANNEL_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_get_frequency(
+ u32 *freq
+ )
+{
+ int err;
+ int io_result;
+ u16 response_count;
+ u16 response_data[CMD_SP_TUNE_GET_CHANNEL_RSP_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (freq == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_SP_TUNE_GET_CHANNEL,
+ CMD_SP_TUNE_GET_CHANNEL_PARAM_LEN,
+ NULL,
+ &response_count,
+ response_data);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ io_result = fmd_tx_channel_to_frequency(
+ response_data[0], /* 1st byte is the Frequency */
+ freq);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_enable_stereo_mode(
+ bool enable_stereo_mode
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_RP_STEREO_SET_MODE_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ parameters[0] = enable_stereo_mode;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_RP_STEREO_SET_MODE,
+ CMD_RP_STEREO_SET_MODE_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.tx_stereo_mode = enable_stereo_mode;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_get_stereo_mode(
+ bool *stereo_mode
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (stereo_mode == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *stereo_mode = fmd_state_info.tx_stereo_mode;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_set_pilot_deviation(
+ u16 deviation
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_RP_SET_PILOT_DEVIATION_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (deviation > MAX_PILOT_DEVIATION) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = deviation;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_RP_SET_PILOT_DEVIATION,
+ CMD_RP_SET_PILOT_DEVIATION_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.tx_pilot_dev = deviation;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_get_pilot_deviation(
+ u16 *deviation
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (deviation == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *deviation = fmd_state_info.tx_pilot_dev;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_set_rds_deviation(
+ u16 deviation
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_RP_SET_RDS_DEVIATION_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (deviation > MAX_RDS_DEVIATION) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = deviation;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_RP_SET_RDS_DEVIATION,
+ CMD_RP_SET_RDS_DEVIATION_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.tx_rds_dev = deviation;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_get_rds_deviation(
+ u16 *deviation
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (deviation == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *deviation = fmd_state_info.tx_rds_dev;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_set_rds(
+ bool on
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_DP_SET_CONTROL_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (on)
+ parameters[0] = 0x0001;
+ else
+ parameters[0] = 0x0000;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_DP_SET_CONTROL,
+ CMD_DP_SET_CONTROL_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.tx_rds_on = on;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_set_group(
+ u16 position,
+ u8 *block1,
+ u8 *block2,
+ u8 *block3,
+ u8 *block4
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_DP_BUFFER_SET_GROUP_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (block1 == NULL ||
+ block2 == NULL ||
+ block3 == NULL ||
+ block4 == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ parameters[0] = position;
+ memcpy(&parameters[1], block1, sizeof(u16));
+ memcpy(&parameters[2], block2, sizeof(u16));
+ memcpy(&parameters[3], block3, sizeof(u16));
+ memcpy(&parameters[4], block4, sizeof(u16));
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_DP_BUFFER_SET_GROUP,
+ CMD_DP_BUFFER_SET_GROUP_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_tx_buffer_set_size(
+ u16 buffer_size
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_DP_BUFFER_SET_SIZE_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ parameters[0] = buffer_size;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_FMT_DP_BUFFER_SET_SIZE,
+ CMD_DP_BUFFER_SET_SIZE_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+
+}
+
+int fmd_tx_get_rds(
+ bool *on
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (on == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *on = fmd_state_info.tx_rds_on;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_set_balance(
+ s8 balance
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SET_BALANCE_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ /* Convert balance from percentage to chip number */
+ parameters[0] = (((s16)balance) * FMD_MAX_BALANCE) / 100;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_AUP_SET_BALANCE,
+ CMD_SET_BALANCE_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_set_volume(
+ u8 volume
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SET_VOLUME_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ /* Convert volume from percentage to chip number */
+ parameters[0] = (((u16)volume) * FMD_MAX_VOLUME) / 100;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_AUP_SET_VOLUME,
+ CMD_SET_VOLUME_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ fmd_state_info.rx_volume = volume;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_get_volume(
+ u8 *volume
+ )
+{
+ int err;
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (volume == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ *volume = fmd_state_info.rx_volume;
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_set_mute(
+ bool mute_on
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SET_MUTE_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (!mute_on)
+ parameters[0] = 0x0000;
+ else
+ parameters[0] = 0x0001;
+ parameters[1] = 0x0001;
+
+ fmd_state_info.gocmd = FMD_STATE_MUTE;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_AUP_SET_MUTE,
+ CMD_SET_MUTE_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_ext_set_mute(
+ bool mute_on
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_EXT_SET_MUTE_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ if (!mute_on)
+ parameters[0] = 0x0000;
+ else
+ parameters[0] = 0x0001;
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_AUP_EXT_SET_MUTE,
+ CMD_EXT_SET_MUTE_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_power_up(void)
+{
+ int err;
+ int io_result;
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ fmd_state_info.gocmd = FMD_STATE_GEN_POWERUP;
+ FM_ERR_REPORT("Sending Gen Power Up");
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_GEN_POWERUP,
+ CMD_POWERUP_PARAM_LEN,
+ NULL,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_goto_standby(void)
+{
+ int err;
+ int io_result;
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_GEN_GOTO_STANDBY,
+ CMD_GOTO_STANDBY_PARAM_LEN,
+ NULL,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_goto_power_down(void)
+{
+ int err;
+ int io_result;
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_GEN_GOTO_POWERDOWN,
+ CMD_GOTO_POWERDOWN_PARAM_LEN,
+ NULL,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ err = io_result;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_select_ref_clk(
+ u16 ref_clk
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SELECT_REFERENCE_CLOCK_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ parameters[0] = ref_clk;
+
+ fmd_state_info.gocmd = FMD_STATE_SELECT_REF_CLK;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_GEN_SELECT_REFERENCE_CLOCK,
+ CMD_SELECT_REFERENCE_CLOCK_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_set_ref_clk_pll(
+ u16 freq
+ )
+{
+ int err;
+ int io_result;
+ u16 parameters[CMD_SET_REFERENCE_CLOCK_PLL_PARAM_LEN];
+
+ if (fmd_go_cmd_busy()) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!fmd_state_info.fmd_initialized) {
+ err = -ENOEXEC;
+ goto error;
+ }
+
+ parameters[0] = freq;
+
+ fmd_state_info.gocmd = FMD_STATE_SET_REF_CLK_PLL;
+ io_result = fmd_send_cmd_and_read_resp(
+ CMD_GEN_SET_REFERENCE_CLOCK_PLL,
+ CMD_SET_REFERENCE_CLOCK_PLL_PARAM_LEN,
+ parameters,
+ NULL,
+ NULL);
+
+ if (io_result != 0) {
+ fmd_state_info.gocmd = FMD_STATE_NONE;
+ err = io_result;
+ goto error;
+ }
+
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+ else
+ err = 0;
+
+error:
+ return err;
+}
+
+int fmd_send_fm_ip_enable(void)
+{
+ int err;
+ u8 fm_ip_enable_cmd[CMD_IP_ENABLE_CMD_LEN];
+
+ mutex_lock(&send_cmd_mutex);
+ fm_ip_enable_cmd[0] = CMD_IP_ENABLE_PARAM_LEN;
+ fm_ip_enable_cmd[1] = FM_CATENA_OPCODE;
+ fm_ip_enable_cmd[2] = FM_WRITE ;
+ fm_ip_enable_cmd[3] = FM_FUNCTION_ENABLE;
+
+ /* Send the Packet */
+ err = fmd_send_packet(
+ CMD_IP_ENABLE_CMD_LEN,
+ fm_ip_enable_cmd);
+
+ /* Check the ErrorCode */
+ if (err != 0)
+ goto error;
+
+ /* wait till response comes */
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+
+error:
+ mutex_unlock(&send_cmd_mutex);
+ return err;
+}
+
+int fmd_send_fm_ip_disable(void)
+{
+ int err;
+ u8 fm_ip_disable_cmd[CMD_IP_DISABLE_CMD_LEN];
+
+ mutex_lock(&send_cmd_mutex);
+ fm_ip_disable_cmd[0] = CMD_IP_DISABLE_PARAM_LEN;
+ fm_ip_disable_cmd[1] = FM_CATENA_OPCODE;
+ fm_ip_disable_cmd[2] = FM_WRITE ;
+ fm_ip_disable_cmd[3] = FM_FUNCTION_DISABLE;
+
+ /* Send the Packet */
+ err = fmd_send_packet(
+ CMD_IP_DISABLE_CMD_LEN,
+ fm_ip_disable_cmd);
+
+ /* Check the ErrorCode */
+ if (err != 0)
+ goto error;
+
+ /* wait till response comes */
+ if (fmd_get_cmd_sem())
+ err = -ETIME;
+
+error:
+ mutex_unlock(&send_cmd_mutex);
+ return err;
+}
+
+int fmd_send_fm_firmware(
+ u8 *fw_buffer,
+ u16 fw_size
+ )
+{
+ int err;
+ u16 bytes_to_write = ST_WRITE_FILE_BLK_SIZE -
+ FM_HCI_WRITE_FILE_BLK_PARAM_LEN;
+ u16 bytes_remaining = fw_size;
+ u8 fm_firmware_data[ST_WRITE_FILE_BLK_SIZE + FM_HCI_CMD_HEADER_LEN];
+ u32 block_id = 0;
+
+ if (fw_buffer == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ while (bytes_remaining > 0) {
+ if (bytes_remaining <
+ (ST_WRITE_FILE_BLK_SIZE -
+ FM_HCI_WRITE_FILE_BLK_PARAM_LEN))
+ bytes_to_write = bytes_remaining;
+
+ /*
+ * Five bytes of HCI Header for FM Firmware
+ * so shift the firmware data by 5 bytes
+ */
+ memcpy(
+ fm_firmware_data + FM_HCI_WRITE_FILE_BLK_HEADER_LEN,
+ fw_buffer, bytes_to_write);
+ err = fmd_write_file_block(
+ block_id,
+ fm_firmware_data,
+ bytes_to_write);
+ if (err) {
+ FM_DEBUG_REPORT("fmd_send_fm_firmware: "
+ "Failed to download %d Block "
+ "error = %d", (unsigned int)block_id, err);
+ goto error;
+ }
+ /*
+ * Increment the Block Id by 1, since one
+ * block is successfully transmitted
+ * to the chip.
+ */
+ block_id++;
+ /*
+ * Increment the next firmware buffer equal
+ * to the number of bytes transmitted.
+ */
+ fw_buffer += bytes_to_write;
+ /*
+ * Decrement the number of bytes remaining
+ * equal to number of bytes transmitted successfully.
+ */
+ bytes_remaining -= bytes_to_write;
+
+ if (block_id == ST_MAX_NUMBER_OF_FILE_BLOCKS)
+ block_id = 0;
+ }
+
+error:
+ return err;
+}
+
+int fmd_int_bufferfull(
+ u16 *number_of_rds_groups
+ )
+{
+ u16 response_count;
+ u16 response_data[CMD_DP_BUFFER_GET_GROUP_COUNT_PARAM_LEN];
+ u16 index = 0;
+ u16 rds_group_count;
+ u8 result = -ENOEXEC;
+ struct fmd_rds_group rds_group;
+
+ if (!fmd_state_info.rx_rds_on)
+ goto error;
+
+ /* get group count*/
+ result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_DP_BUFFER_GET_GROUP_COUNT,
+ CMD_DP_BUFFER_GET_GROUP_COUNT_PARAM_LEN,
+ NULL,
+ &response_count,
+ response_data);
+
+ if (result != 0)
+ goto error;
+
+ /* read RDS groups */
+ rds_group_count = FM_GET_NUM_RDS_GRPS(response_data);
+ if (rds_group_count > MAX_RDS_GROUPS)
+ rds_group_count = MAX_RDS_GROUPS;
+
+ *number_of_rds_groups = rds_group_count;
+
+ if (rds_group_count) {
+ FM_DEBUG_REPORT("rds_group_count = %d", rds_group_count);
+ while (rds_group_count-- && fmd_state_info.rx_rds_on) {
+ result = fmd_send_cmd_and_read_resp(
+ CMD_FMR_DP_BUFFER_GET_GROUP,
+ CMD_DP_BUFFER_GET_GROUP_PARAM_LEN,
+ NULL,
+ &response_count,
+ (u16 *)&rds_group);
+
+ if (result != 0)
+ goto error;
+
+ if (fmd_state_info.rx_rds_on)
+ fmd_state_info.rds_group[index++] = rds_group;
+ }
+ }
+error:
+ return result;
+}
+
+void fmd_start_rds_thread(
+ cg2900_fm_rds_cb cb_func
+ )
+{
+ FM_INFO_REPORT("fmd_start_rds_thread");
+ cb_rds_func = cb_func;
+ rds_thread_required = true;
+ rds_thread_task = kthread_create(fmd_rds_thread, NULL, "rds_thread");
+ if (IS_ERR(rds_thread_task)) {
+ FM_ERR_REPORT("fmd_start_rds_thread: "
+ "Unable to Create rds_thread");
+ rds_thread_task = NULL;
+ rds_thread_required = false;
+ return;
+ }
+ wake_up_process(rds_thread_task);
+}
+
+void fmd_stop_rds_thread(void)
+{
+ FM_INFO_REPORT("fmd_stop_rds_thread");
+ /* In case thread is waiting, set the rds sem */
+ fmd_set_rds_sem();
+ cb_rds_func = NULL;
+ rds_thread_required = false;
+ if (rds_thread_task) {
+ kthread_stop(rds_thread_task);
+ rds_thread_task = NULL;
+ return;
+ }
+}
+
+void fmd_get_rds_sem(void)
+{
+ int ret_val;
+
+ FM_DEBUG_REPORT("fmd_get_rds_sem");
+ ret_val = down_killable(&rds_sem);
+
+ if (ret_val)
+ FM_ERR_REPORT("fmd_get_rds_sem: down_killable "
+ "returned error = %d", ret_val);
+}
+
+void fmd_set_rds_sem(void)
+{
+ FM_DEBUG_REPORT("fmd_set_rds_sem");
+ up(&rds_sem);
+}
+
+MODULE_AUTHOR("Hemant Gupta");
+MODULE_LICENSE("GPL v2");
+
+module_param(cg2900_fm_debug_level, ushort, S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(cg2900_fm_debug_level, "cg2900_fm_debug_level: "
+ " *1: Only Error Logs* "
+ " 2: Info Logs "
+ " 3: Debug Logs "
+ " 4: HCI Logs");
+
diff --git a/drivers/media/radio/CG2900/cg2900_fm_driver.h b/drivers/media/radio/CG2900/cg2900_fm_driver.h
new file mode 100644
index 00000000000..af2fe5b04be
--- /dev/null
+++ b/drivers/media/radio/CG2900/cg2900_fm_driver.h
@@ -0,0 +1,1604 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Linux FM Driver for CG2900 FM Chip
+ *
+ * Author: Hemant Gupta <hemant.gupta@stericsson.com> for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef _FMDRIVER_H_
+#define _FMDRIVER_H_
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/smp_lock.h>
+#include <linux/semaphore.h>
+#include <linux/version.h>
+#include <linux/kthread.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mutex.h>
+#include "cg2900_fm_api.h"
+
+/* structure declared in cg2900_fm_driver.c */
+extern struct timespec time_spec;
+
+/* module_param declared in cg2900_fm_driver.c */
+extern unsigned short cg2900_fm_debug_level;
+
+/**
+ * enum fmd_debug_levels - FM Driver Debug Levels.
+ *
+ * @FM_NO_LOGS: No Logs are displayed.
+ * @FM_ERROR_LOGS: Only Error Logs are displayed.
+ * @FM_INFO_LOGS: Function Entry logs are displayed.
+ * @FM_DEBUG_LOGS: Full debugging support.
+ * @FM_HCI_PACKET_LOGS: HCI Packet Sent/received to/by
+ * FM Driver are displayed.
+ *
+ * Various debug levels for FM Driver.
+ */
+enum fmd_debug_levels {
+ FM_NO_LOGS,
+ FM_ERROR_LOGS,
+ FM_INFO_LOGS,
+ FM_DEBUG_LOGS,
+ FM_HCI_PACKET_LOGS
+};
+
+#define FM_HEX_REPORT(fmt, arg...) \
+ if (cg2900_fm_debug_level == FM_HCI_PACKET_LOGS) { \
+ printk(KERN_INFO fmt "\r\n" , ## arg); \
+ }
+
+#define FM_DEBUG_REPORT(fmt, arg...) \
+ if (cg2900_fm_debug_level > FM_INFO_LOGS && \
+ cg2900_fm_debug_level < FM_HCI_PACKET_LOGS) { \
+ getnstimeofday(&time_spec); \
+ printk(KERN_INFO "\n[%08x:%08x] " \
+ "CG2900_FM_Driver: " fmt "\r\n" , \
+ (unsigned int)time_spec.tv_sec, \
+ (unsigned int)time_spec.tv_nsec, ## arg); \
+ }
+
+#define FM_INFO_REPORT(fmt, arg...) \
+ if (cg2900_fm_debug_level > FM_ERROR_LOGS && \
+ cg2900_fm_debug_level < FM_HCI_PACKET_LOGS) { \
+ getnstimeofday(&time_spec); \
+ printk(KERN_INFO "\n[%08x:%08x] " \
+ "CG2900_FM_Driver: " fmt "\r\n" , \
+ (unsigned int)time_spec.tv_sec, \
+ (unsigned int)time_spec.tv_nsec, ## arg); \
+ }
+
+#define FM_ERR_REPORT(fmt, arg...) \
+ if (cg2900_fm_debug_level >= FM_ERROR_LOGS) { \
+ getnstimeofday(&time_spec); \
+ printk(KERN_ERR "\n[%08x:%08x] " \
+ "CG2900_FM_Driver: " fmt "\r\n" , \
+ (unsigned int)time_spec.tv_sec, \
+ (unsigned int)time_spec.tv_nsec, ## arg); \
+ }
+
+#define MAX_COUNT_OF_IRQS 16
+#define MAX_BUFFER_SIZE 512
+#define MAX_NAME_SIZE 100
+/* Minimum Power level for CG2900. The value is in units of dBuV */
+#define MIN_POWER_LEVEL 88
+/* Maximum Power level for CG2900. The value is in units of dBuV */
+#define MAX_POWER_LEVEL 123
+/* Minimum RDS Deviation value for CG2900. The value is in units of 10 Hz */
+#define MIN_RDS_DEVIATION 0
+/* Default RDS Deviation value for CG2900. The value is in units of 10 Hz */
+#define DEFAULT_RDS_DEVIATION 200
+/* Maximum RDS Deviation value for CG2900. The value is in units of 10 Hz */
+#define MAX_RDS_DEVIATION 750
+#define FMD_EU_US_MIN_FREQ_IN_KHZ 87500
+#define FMD_EU_US_MAX_FREQ_IN_KHZ 108000
+#define FMD_JAPAN_MIN_FREQ_IN_KHZ 76000
+#define FMD_JAPAN_MAX_FREQ_IN_KHZ 90000
+#define FMD_CHINA_MIN_FREQ_IN_KHZ 70000
+#define FMD_CHINA_MAX_FREQ_IN_KHZ 108000
+#define FMD_MIN_CHANNEL_NUMBER 0
+#define FMD_MAX_CHANNEL_NUMBER 760
+/*
+ * Maximum supported balance for CG2900. This is just a hexadecimal number
+ * with no units.
+ */
+#define FMD_MAX_BALANCE 0x7FFF
+/*
+ * Maximum supported volume for CG2900. This is just a hexadecimal number
+ * with no units.
+ */
+#define FMD_MAX_VOLUME 0x7FFF
+/* Minimum Program Identification value as per RDS specification */
+#define MIN_PI_VALUE 0x0000
+/* Maximum Program Identification value as per RDS specification */
+#define MAX_PI_VALUE 0xFFFF
+/* Minimum Program Type code value as per RDS specification */
+#define MIN_PTY_VALUE 0
+/* Maximum Program Type code value as per RDS specification */
+#define MAX_PTY_VALUE 31
+/* Minimum Pilot Deviation value for CG2900. The value is in units of 10 Hz */
+#define MIN_PILOT_DEVIATION 0
+/* Default Pilot Deviation value for CG2900. The value is in units of 10 Hz */
+#define DEFAULT_PILOT_DEVIATION 675
+/* Maximum Pilot Deviation value for CG2900. The value is in units of 10 Hz */
+#define MAX_PILOT_DEVIATION 1000
+/*
+ * Default RSSI Threshold for a channel to be considered valid for CG2900.
+ * This is just a hexadecimal number with no units.
+ */
+#define DEFAULT_RSSI_THRESHOLD 0x0100
+/*
+ * Default Peak Noise level for a channel to be considered valid for CG2900.
+ * This is just a hexadecimal number with no units.
+ */
+#define DEFAULT_PEAK_NOISE_VALUE 0x0035
+/*
+ * Default Average Noise level for a channel to be considered valid for CG2900.
+ * This is just a hexadecimal number with no units.
+ */
+#define DEFAULT_AVERAGE_NOISE_MAX_VALUE 0x0030
+#define FREQUENCY_CONVERTOR_KHZ_HZ 1000
+#define CHANNEL_FREQ_CONVERTER_MHZ 50
+/* Interrupt(s) for CG2900 */
+#define IRPT_INVALID 0x0000
+#define IRPT_OPERATION_SUCCEEDED 0x0001
+#define IRPT_OPERATION_FAILED 0x0002
+#define IRPT_RX_BUFFERFULL_TX_BUFFEREMPTY 0x0008
+#define IRPT_RX_SIGNAL_QUALITYLOW_MUTE_STATUS_CHANGED 0x0010
+#define IRPT_RX_MONO_STEREO_TRANSITION 0x0020
+#define IRPT_TX_OVERMODULATION 0x0030
+#define IRPT_RX_RDS_SYNCFOUND_TX_OVERDRIVE 0x0040
+#define IRPT_RDS_SYNC_LOST 0x0080
+#define IRPT_PI_CODE_CHANGED 0x0100
+#define IRPT_REQUESTED_BLOCK_AVAILABLE 0x0200
+#define IRPT_BUFFER_CLEARED 0x2000
+#define IRPT_WARM_BOOT_READY 0x4000
+#define IRPT_COLD_BOOT_READY 0x8000
+/* FM Commands Id */
+#define CMD_ID_NONE 0x0000
+#define CMD_AUP_EXT_SET_MUTE 0x01E2
+#define CMD_AUP_SET_BALANCE 0x0042
+#define CMD_AUP_SET_MUTE 0x0062
+#define CMD_AUP_SET_VOLUME 0x0022
+#define CMD_FMR_DP_BUFFER_GET_GROUP 0x0303
+#define CMD_FMR_DP_BUFFER_GET_GROUP_COUNT 0x0323
+#define CMD_FMR_DP_BUFFER_SET_SIZE 0x0343
+#define CMD_FMR_DP_BUFFER_SET_THRESHOLD 0x06C3
+#define CMD_FMR_DP_SET_CONTROL 0x02A3
+#define CMD_FMR_RP_GET_RSSI 0x0083
+#define CMD_FMR_RP_STEREO_SET_MODE 0x0123
+#define CMD_FMR_SET_ANTENNA 0x0663
+#define CMD_FMR_SP_AF_SWITCH_GET_RESULT 0x0603
+#define CMD_FMR_SP_AF_SWITCH_START 0x04A3
+#define CMD_FMR_SP_AF_UPDATE_GET_RESULT 0x0483
+#define CMD_FMR_SP_AF_UPDATE_START 0x0463
+#define CMD_FMR_SP_BLOCK_SCAN_GET_RESULT 0x06A3
+#define CMD_FMR_SP_BLOCK_SCAN_START 0x0683
+#define CMD_FMR_SP_SCAN_GET_RESULT 0x0423
+#define CMD_FMR_SP_SCAN_START 0x0403
+#define CMD_FMR_SP_SEARCH_START 0x03E3
+#define CMD_FMR_SP_STOP 0x0383
+#define CMD_FMR_SP_TUNE_GET_CHANNEL 0x03A3
+#define CMD_FMR_SP_TUNE_SET_CHANNEL 0x03C3
+#define CMD_FMR_TN_SET_BAND 0x0023
+#define CMD_FMR_TN_SET_GRID 0x0043
+#define CMD_FMT_DP_BUFFER_GET_POSITION 0x0204
+#define CMD_FMT_DP_BUFFER_SET_GROUP 0x0244
+#define CMD_FMT_DP_BUFFER_SET_SIZE 0x0224
+#define CMD_FMT_DP_BUFFER_SET_THRESHOLD 0x0284
+#define CMD_FMT_DP_SET_CONTROL 0x0264
+#define CMD_FMT_PA_SET_CONTROL 0x01A4
+#define CMD_FMT_PA_SET_MODE 0x01E4
+#define CMD_FMT_RP_SET_PILOT_DEVIATION 0x02A4
+#define CMD_FMT_RP_SET_PREEMPHASIS 0x00C4
+#define CMD_FMT_RP_SET_RDS_DEVIATION 0x0344
+#define CMD_FMT_RP_STEREO_SET_MODE 0x0164
+#define CMD_FMT_SP_TUNE_GET_CHANNEL 0x0184
+#define CMD_FMT_SP_TUNE_SET_CHANNEL 0x0064
+#define CMD_FMT_TN_SET_BAND 0x0024
+#define CMD_FMT_TN_SET_GRID 0x0044
+#define CMD_GEN_GET_MODE 0x0021
+#define CMD_GEN_GET_REGISTER_VALUE 0x00E1
+#define CMD_GEN_GET_VERSION 0x00C1
+#define CMD_GEN_GOTO_MODE 0x0041
+#define CMD_GEN_GOTO_POWERDOWN 0x0081
+#define CMD_GEN_GOTO_STANDBY 0x0061
+#define CMD_GEN_POWERUP 0x0141
+#define CMD_GEN_SELECT_REFERENCE_CLOCK 0x0201
+#define CMD_GEN_SET_REFERENCE_CLOCK 0x0161
+#define CMD_GEN_SET_REFERENCE_CLOCK_PLL 0x01A1
+#define CMD_GEN_SET_REGISTER_VALUE 0x0101
+/* FM Command Id Parameter Length */
+#define CMD_GET_VERSION_PARAM_LEN 0
+#define CMD_GET_VERSION_RSP_PARAM_LEN 7
+#define CMD_GOTO_MODE_PARAM_LEN 1
+#define CMD_SET_ANTENNA_PARAM_LEN 1
+#define CMD_TN_SET_BAND_PARAM_LEN 3
+#define CMD_TN_SET_GRID_PARAM_LEN 1
+#define CMD_SP_TUNE_SET_CHANNEL_PARAM_LEN 1
+#define CMD_SP_TUNE_GET_CHANNEL_PARAM_LEN 0
+#define CMD_SP_TUNE_GET_CHANNEL_RSP_PARAM_LEN 1
+#define CMD_RP_STEREO_SET_MODE_PARAM_LEN 1
+#define CMD_RP_GET_RSSI_PARAM_LEN 0
+#define CMD_RP_GET_RSSI_RSP_PARAM_LEN 1
+#define CMD_SP_SEARCH_START_PARAM_LEN 4
+#define CMD_SP_SCAN_START_PARAM_LEN 4
+#define CMD_SP_SCAN_GET_RESULT_PARAM_LEN 1
+#define CMD_SP_SCAN_GET_RESULT_RSP_PARAM_LEN 7
+#define CMD_SP_BLOCK_SCAN_START_PARAM_LEN 3
+#define CMD_SP_BLOCK_SCAN_GET_RESULT_PARAM_LEN 1
+#define CMD_SP_BLOCK_SCAN_GET_RESULT_RSP_PARAM_LEN 7
+#define CMD_SP_STOP_PARAM_LEN 0
+#define CMD_SP_AF_UPDATE_START_PARAM_LEN 1
+#define CMD_SP_AF_UPDATE_GET_RESULT_PARAM_LEN 0
+#define CMD_SP_AF_UPDATE_GET_RESULT_RSP_PARAM_LEN 1
+#define CMD_SP_AF_SWITCH_START_PARAM_LEN 5
+#define CMD_SP_AF_SWITCH_GET_RESULT_PARAM_LEN 0
+#define CMD_SP_AF_SWITCH_GET_RESULT_RWSP_PARAM_LEN 3
+#define CMD_DP_BUFFER_SET_SIZE_PARAM_LEN 1
+#define CMD_DP_BUFFER_SET_THRESHOLD_PARAM_LEN 1
+#define CMD_DP_SET_CONTROL_PARAM_LEN 1
+#define CMD_PA_SET_MODE_PARAM_LEN 1
+#define CMD_PA_SET_CONTROL_PARAM_LEN 1
+#define CMD_RP_SET_PREEMPHASIS_PARAM_LEN 1
+#define CMD_RP_SET_PILOT_DEVIATION_PARAM_LEN 1
+#define CMD_RP_SET_RDS_DEVIATION_PARAM_LEN 1
+#define CMD_DP_BUFFER_SET_GROUP_PARAM_LEN 5
+#define CMD_SET_BALANCE_PARAM_LEN 1
+#define CMD_SET_VOLUME_PARAM_LEN 1
+#define CMD_SET_MUTE_PARAM_LEN 2
+#define CMD_EXT_SET_MUTE_PARAM_LEN 1
+#define CMD_POWERUP_PARAM_LEN 0
+#define CMD_GOTO_STANDBY_PARAM_LEN 0
+#define CMD_GOTO_POWERDOWN_PARAM_LEN 0
+#define CMD_SELECT_REFERENCE_CLOCK_PARAM_LEN 1
+#define CMD_SET_REFERENCE_CLOCK_PLL_PARAM_LEN 1
+#define CMD_DP_BUFFER_GET_GROUP_COUNT_PARAM_LEN 0
+#define CMD_DP_BUFFER_GET_GROUP_PARAM_LEN 0
+#define CMD_IP_ENABLE_CMD_LEN 4
+#define CMD_IP_ENABLE_PARAM_LEN 3
+#define CMD_IP_DISABLE_CMD_LEN 4
+#define CMD_IP_DISABLE_PARAM_LEN 3
+/* FM HCI Command and event specific */
+#define FM_WRITE 0x00
+#define FM_READ 0x01
+#define FM_CATENA_OPCODE 0xFE
+#define HCI_CMD_FM 0xFD50
+#define HCI_CMD_VS_WRITE_FILE_BLOCK 0xFC2E
+#define FM_EVENT_ID 0x15
+#define FM_SUCCESS_STATUS 0x00
+#define FM_EVENT 0x01
+#define HCI_COMMAND_COMPLETE_EVENT 0x0E
+#define HCI_VS_DBG_EVENT 0xFF
+#define ST_WRITE_FILE_BLK_SIZE 254
+#define ST_MAX_NUMBER_OF_FILE_BLOCKS 256
+#define FM_PG1_INTERRUPT_EVENT_LEN 0x04
+#define FM_PG2_INTERRUPT_EVENT_LEN 0x06
+#define FM_HCI_CMD_HEADER_LEN 6
+#define FM_HCI_CMD_PARAM_LEN 5
+#define FM_HCI_WRITE_FILE_BLK_HEADER_LEN 5
+#define FM_HCI_WRITE_FILE_BLK_PARAM_LEN 4
+#define HCI_PACKET_INDICATOR_CMD 0x01
+#define HCI_PACKET_INDICATOR_EVENT 0x04
+#define HCI_PACKET_INDICATOR_FM_CMD_EVT 0x08
+/* FM Functions specific to CG2900 */
+#define FM_FUNCTION_ENABLE 0x00
+#define FM_FUNCTION_DISABLE 0x01
+#define FM_FUNCTION_RESET 0x02
+#define FM_FUNCTION_WRITE_COMMAND 0x10
+#define FM_FUNCTION_SET_INT_MASK_ALL 0x20
+#define FM_FUNCTION_GET_INT_MASK_ALL 0x21
+#define FM_FUNCTION_SET_INT_MASK 0x22
+#define FM_FUNCTION_GET_INT_MASK 0x23
+#define FM_FUNCTION_FIRMWARE_DOWNLOAD 0x30
+/* Command succeeded */
+#define FM_CMD_STATUS_CMD_SUCCESS 0x00
+/* HCI_ERR_HW_FAILURE when no response from the IP */
+#define FM_CMD_STATUS_HCI_ERR_HW_FAILURE 0x03
+/* HCI_ERR_INVALID_PARAMETERS. */
+#define FM_CMD_STATUS_HCI_ERR_INVALID_PARAMETERS 0x12
+/* When the host tries to send a command to an IP that hasn't been
+ * initialized.
+ */
+#define FM_CMD_STATUS_IP_UNINIT 0x15
+/* HCI_ERR_UNSPECIFIED_ERROR: any other error */
+#define FM_CMD_STATUS_HCI_ERR_UNSPECIFIED_ERROR 0x1F
+/* HCI_ERR_CMD_DISALLOWED when the host asks for an unauthorized operation
+ * (FM state transition for instance)
+ */
+#define FM_CMD_STATUS_HCI_ERR_CMD_DISALLOWED 0x0C
+/* Wrong sequence number for FM FW download command */
+#define FM_CMD_STATUS_WRONG_SEQ_NUM 0xF1
+/* Unknown file type for FM FW download command */
+#define FM_CMD_STATUS_UNKNOWN_FILE_TYPE 0xF2
+/* File version mismatch for FM FW download command */
+#define FM_CMD_STATUS_FILE_VERSION_MISMATCH 0xF3
+
+
+/**
+ * enum fmd_event - Events received.
+ *
+ * @FMD_EVENT_OPERATION_COMPLETED: Previous operation has been completed.
+ * @FMD_EVENT_ANTENNA_STATUS_CHANGED: Antenna has been changed.
+ * @FMD_EVENT_FREQUENCY_CHANGED: Frequency has been changed.
+ * @FMD_EVENT_SEEK_COMPLETED: Seek operation has completed.
+ * @FMD_EVENT_SCAN_BAND_COMPLETED: Band Scan completed.
+ * @FMD_EVENT_BLOCK_SCAN_COMPLETED: Block Scan completed.
+ * @FMD_EVENT_AF_UPDATE_SWITCH_COMPLETE: Af Update or AF Switch is complete.
+ * @FMD_EVENT_MONO_STEREO_TRANSITION_COMPLETE: Mono stereo transition is
+ * completed.
+ * @FMD_EVENT_SEEK_STOPPED: Previous Seek/Band Scan/ Block Scan operation is
+ * stopped.
+ * @FMD_EVENT_GEN_POWERUP: FM IP Powerup has been powered up.
+ * @FMD_EVENT_RDSGROUP_RCVD: RDS Groups Full interrupt.
+ * @FMD_EVENT_LAST_ELEMENT: Last event, used for keeping count of
+ * number of events.
+ *
+ * Various events received from FM driver for Upper Layer(s) processing.
+ */
+enum fmd_event {
+ FMD_EVENT_OPERATION_COMPLETED,
+ FMD_EVENT_ANTENNA_STATUS_CHANGED,
+ FMD_EVENT_FREQUENCY_CHANGED,
+ FMD_EVENT_SEEK_COMPLETED,
+ FMD_EVENT_SCAN_BAND_COMPLETED,
+ FMD_EVENT_BLOCK_SCAN_COMPLETED,
+ FMD_EVENT_AF_UPDATE_SWITCH_COMPLETE,
+ FMD_EVENT_MONO_STEREO_TRANSITION_COMPLETE,
+ FMD_EVENT_SEEK_STOPPED,
+ FMD_EVENT_GEN_POWERUP,
+ FMD_EVENT_RDSGROUP_RCVD,
+ FMD_EVENT_LAST_ELEMENT
+};
+
+/**
+ * enum fmd_mode - FM Driver Modes.
+ *
+ * @FMD_MODE_IDLE: FM Driver in Idle mode.
+ * @FMD_MODE_RX: FM Driver in Rx mode.
+ * @FMD_MODE_TX: FM Driver in Tx mode.
+ *
+ * Various Modes of FM Radio.
+ */
+enum fmd_mode {
+ FMD_MODE_IDLE,
+ FMD_MODE_RX,
+ FMD_MODE_TX
+};
+
+/**
+ * enum fmd_antenna - Antenna selection.
+ *
+ * @FMD_ANTENNA_EMBEDDED: Embedded Antenna.
+ * @FMD_ANTENNA_WIRED: Wired Antenna.
+ *
+ * Antenna to be used for FM Radio.
+ */
+enum fmd_antenna {
+ FMD_ANTENNA_EMBEDDED,
+ FMD_ANTENNA_WIRED
+};
+
+/**
+ * enum fmd_grid - Grid used on FM Radio.
+ *
+ * @FMD_GRID_50KHZ: 50 kHz grid spacing.
+ * @FMD_GRID_100KHZ: 100 kHz grid spacing.
+ * @FMD_GRID_200KHZ: 200 kHz grid spacing.
+ *
+ * Spacing used on FM Radio.
+ */
+enum fmd_grid {
+ FMD_GRID_50KHZ,
+ FMD_GRID_100KHZ,
+ FMD_GRID_200KHZ
+};
+
+/**
+ * enum fmd_emphasis - De-emphasis/Pre-emphasis level.
+ *
+ * @FMD_EMPHASIS_50US: 50 us de-emphasis/pre-emphasis level.
+ * @FMD_EMPHASIS_75US: 75 us de-emphasis/pre-emphasis level.
+ *
+ * De-emphasis/Pre-emphasis level used on FM Radio.
+ */
+enum fmd_emphasis {
+ FMD_EMPHASIS_50US = 1,
+ FMD_EMPHASIS_75US = 2
+};
+
+/**
+ * enum fmd_freq_range - Frequency range.
+ *
+ * @FMD_FREQRANGE_EUROAMERICA: EU/US Range (87.5 - 108 MHz).
+ * @FMD_FREQRANGE_JAPAN: Japan Range (76 - 90 MHz).
+ * @FMD_FREQRANGE_CHINA: China Range (70 - 108 MHz).
+ *
+ * Various Frequency range(s) supported by FM Radio.
+ */
+enum fmd_freq_range {
+ FMD_FREQRANGE_EUROAMERICA,
+ FMD_FREQRANGE_JAPAN,
+ FMD_FREQRANGE_CHINA
+};
+
+/**
+ * enum fmd_stereo_mode - FM Driver Stereo Modes.
+ *
+ * @FMD_STEREOMODE_OFF: Streo Blending Off.
+ * @FMD_STEREOMODE_MONO: Mono Mode.
+ * @FMD_STEREOMODE_BLENDING: Blending Mode.
+ *
+ * Various Stereo Modes of FM Radio.
+ */
+enum fmd_stereo_mode {
+ FMD_STEREOMODE_OFF,
+ FMD_STEREOMODE_MONO,
+ FMD_STEREOMODE_BLENDING
+};
+
+/**
+ * enum fmd_pilot_tone - Pilot Tone Selection
+ *
+ * @FMD_PILOT_TONE_DISABLED: Pilot Tone to be disabled.
+ * @FMD_PILOT_TONE_ENABLED: Pilot Tone to be enabled.
+ *
+ * Pilot Tone to be enabled or disabled.
+ */
+enum fmd_pilot_tone {
+ FMD_PILOT_TONE_DISABLED,
+ FMD_PILOT_TONE_ENABLED
+};
+
+/**
+ * enum fmd_output - Output of Sample Rate Converter.
+ *
+ * @FMD_OUTPUT_DISABLED: Sample Rate converter in disabled.
+ * @FMD_OUTPUT_I2S: I2S Output from Sample rate converter.
+ * @FMD_OUTPUT_PARALLEL: Parallel output from sample rate converter.
+ *
+ * Sample Rate Converter's output to be set on Connectivity Controller.
+ */
+enum fmd_output {
+ FMD_OUTPUT_DISABLED,
+ FMD_OUTPUT_I2S,
+ FMD_OUTPUT_PARALLEL
+};
+
+/**
+ * enum fmd_input - Audio Input to Sample Rate Converter.
+ *
+ * @FMD_INPUT_ANALOG: Selects the ADC's as audio source
+ * @FMD_INPUT_DIGITAL: Selects Digital Input as audio source.
+ *
+ * Audio Input source for Sample Rate Converter.
+ */
+enum fmd_input {
+ FMD_INPUT_ANALOG,
+ FMD_INPUT_DIGITAL
+};
+
+/**
+ * enum fmd_rds_mode - RDS Mode to be selected for FM Rx.
+ *
+ * @FMD_SWITCH_OFF_RDS: RDS Decoding disabled in FM Chip.
+ * @FMD_SWITCH_ON_RDS: RDS Decoding enabled in FM Chip.
+ * @FMD_SWITCH_ON_RDS_ENHANCED_MODE: Enhanced RDS Mode.
+ * @FMD_SWITCH_ON_RDS_SIMULATOR: RDS Simulator switched on in FM Chip.
+ *
+ * RDS Mode to be selected for FM Rx.
+ */
+enum fmd_rds_mode {
+ FMD_SWITCH_OFF_RDS,
+ FMD_SWITCH_ON_RDS,
+ FMD_SWITCH_ON_RDS_ENHANCED_MODE,
+ FMD_SWITCH_ON_RDS_SIMULATOR
+};
+
+/* Callback function to receive radio events. */
+typedef void(*fmd_radio_cb)(
+ u8 event,
+ bool event_successful
+ );
+
+/**
+ * fmd_init() - Initialize the FM Driver internal structures.
+ *
+ * Returns:
+ * 0, if no error.
+ * -EIO, if there is an error.
+ */
+int fmd_init(void);
+
+/**
+ * fmd_exit() - De-initialize the FM Driver.
+ */
+void fmd_exit(void);
+
+/**
+ * fmd_register_callback() - Function to register callback function.
+ *
+ * This function registers the callback function provided by upper layers.
+ * @callback: Fmradio call back Function pointer
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_register_callback(
+ fmd_radio_cb callback
+ );
+
+/**
+ * fmd_get_version() - Retrieves the FM HW and FW version.
+ *
+ * @version: (out) Version Array
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameters are not valid.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_get_version(
+ u16 *version
+ );
+
+/**
+ * fmd_set_mode() - Starts a transition to the given mode.
+ *
+ * @mode: Transition mode
+ *
+ * Returns:
+ * 0, if set mode done successfully.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_set_mode(
+ u8 mode
+ );
+
+/**
+ * fmd_get_freq_range_properties() - Retrieves Freq Range Properties.
+ *
+ * @range: range of freq
+ * @min_freq: (out) Minimum Frequency of the Band in kHz.
+ * @max_freq: (out) Maximum Frequency of the Band in kHz
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ */
+int fmd_get_freq_range_properties(
+ u8 range,
+ u32 *min_freq,
+ u32 *max_freq
+ );
+
+/**
+ * fmd_set_antenna() - Selects the antenna to be used in receive mode.
+ *
+ * embedded - Selects the embedded antenna, wired- Selects the wired antenna.
+ * @antenna: Antenna Type
+ *
+ * Returns:
+ * 0, if set antenna done successfully.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_set_antenna(
+ u8 antenna
+ );
+
+/**
+ * fmd_get_antenna() - Retrieves the currently used antenna type.
+ *
+ * @antenna: (out) Antenna Selected on FM Radio.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_get_antenna(
+ u8 *antenna
+ );
+
+/**
+ * fmd_set_freq_range() - Sets the FM band.
+ *
+ * @range: freq range
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_set_freq_range(
+ u8 range
+ );
+
+/**
+ * fmd_get_freq_range() - Gets the FM band currently in use.
+ *
+ * @range: (out) Frequency Range set on FM Radio.
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ */
+int fmd_get_freq_range(
+ u8 *range
+ );
+
+/**
+ * fmd_rx_set_grid() - Sets the tuning grid.
+ *
+ * @grid: Tuning grid size
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_set_grid(
+ u8 grid
+ );
+
+/**
+ * fmd_rx_set_frequency() - Sets the FM Channel.
+ *
+ * @freq: Frequency to Set in Khz
+ *
+ * Returns:
+ * 0, if set frequency done successfully.
+ * -EINVAL, if parameters are invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_set_frequency(
+ u32 freq
+ );
+
+/**
+ * fmd_rx_get_frequency() - Gets the currently used FM Channel.
+ *
+ * @freq: (out) Current Frequency set on FM Radio.
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameters are invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_get_frequency(
+ u32 *freq
+ );
+
+/**
+ * fmd_rx_set_stereo_mode() - Sets the stereomode functionality.
+ *
+ * @mode: FMD_STEREOMODE_MONO, FMD_STEREOMODE_STEREO and
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_set_stereo_mode(
+ u8 mode
+ );
+
+/**
+ * fmd_rx_get_stereo_mode() - Gets the currently used FM mode.
+ *
+ * FMD_STEREOMODE_MONO, FMD_STEREOMODE_STEREO and
+ * FMD_STEREOMODE_AUTO.
+ * @mode: (out) Mode set on FM Radio, stereo or mono.
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_rx_get_stereo_mode(
+ u8 *mode
+ );
+
+/**
+ * fmd_rx_get_signal_strength() - Gets the RSSI level of current frequency.
+ *
+ * @strength: (out) RSSI level of current channel.
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_get_signal_strength(
+ u16 *strength
+ );
+
+/**
+ * fmd_rx_set_stop_level() - Sets the FM Rx Seek stop level.
+ *
+ * @stoplevel: seek stop level
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_rx_set_stop_level(
+ u16 stoplevel
+ );
+
+/**
+ * fmd_rx_get_stop_level() - Gets the current FM Rx Seek stop level.
+ *
+ * @stoplevel: (out) RSSI Threshold set on FM Radio.
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_rx_get_stop_level(
+ u16 *stoplevel
+ );
+
+/**
+ * fmd_rx_seek() - Perform FM Seek.
+ *
+ * Starts searching relative to the actual channel with
+ * a specific direction, stop.
+ * level and optional noise levels
+ * @upwards: scan up
+ *
+ * Returns:
+ * 0, if seek started successfully.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_seek(
+ bool upwards
+ );
+
+/**
+ * fmd_rx_stop_seeking() - Stops a currently active seek or scan band.
+ *
+ * Returns:
+ * 0, if stop seek done successfully.
+ * -ENOEXEC, if preconditions are violated.
+ * -ENOEXEC, if FM Driver is
+ * not currently in Seek or Scan State..
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_stop_seeking(void);
+
+/**
+ * fmd_rx_af_update_start() - Perform AF update.
+ *
+ * This is used to switch to a shortly tune to a AF freq,
+ * measure its RSSI and tune back to the original frequency.
+ * @freq: Alternative frequncy in KHz to be set for AF updation.
+ *
+ * Returns:
+ * -EBUSY, if FM Driver is not in idle state.
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ */
+int fmd_rx_af_update_start(
+ u32 freq
+ );
+
+/**
+ * fmd_rx_get_af_update_result() - Retrive result of AF update.
+ *
+ * Retrive the RSSI level of the Alternative frequency.
+ * @af_level: RSSI level of the Alternative frequency.
+ *
+ * Returns:
+ * -EBUSY, if FM Driver is not in idle state.
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ */
+int fmd_rx_get_af_update_result(
+ u16 *af_level
+ );
+
+/**
+ * fmd_af_switch_start() -Performs AF switch.
+ *
+ * @freq: Frequency to Set in Khz.
+ * @picode:programable id,unique for each station.
+ *
+ * Returns:
+ * -EBUSY, if FM Driver is not in idle state.
+ * 0, if no error and if AF switch started successfully.
+ * -ENOEXEC, if preconditions are violated.
+ */
+int fmd_rx_af_switch_start(
+ u32 freq,
+ u16 picode
+ );
+
+/**
+ * fmd_rx_get_af_switch_results() -Retrieves the results of AF Switch.
+ *
+ * @afs_conclusion: Conclusion of AF switch.
+ * @afs_level: RSSI level of the Alternative frequnecy.
+ * @afs_pi: PI code of the alternative channel (if found).
+ *
+ * Returns:
+ * -EBUSY, if FM Driver is not in idle state.
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ */
+int fmd_rx_get_af_switch_results(
+ u16 *afs_conclusion,
+ u16 *afs_level,
+ u16 *afs_pi
+ );
+
+/**
+ * fmd_rx_scan_band() - Starts Band Scan.
+ *
+ * Starts scanning the active band for the strongest
+ * channels above a threshold.
+ * @max_channels_to_scan: Maximum number of channels to scan.
+ *
+ * Returns:
+ * 0, if scan band started successfully.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_scan_band(
+ u8 max_channels_to_scan
+ );
+
+/**
+ * fmd_rx_get_max_channels_to_scan() - Retreives the maximum channels.
+ *
+ * Retrieves the maximum number of channels that can be found during
+ * band scann.
+ * @max_channels_to_scan: (out) Maximum number of channels to scan.
+ *
+ * Returns:
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if parameter is invalid.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_get_max_channels_to_scan(
+ u8 *max_channels_to_scan
+ );
+
+/**
+ * fmd_rx_get_scan_band_info() - Retrieves Channels found during scanning.
+ *
+ * Retrieves the scanned active band
+ * for the strongest channels above a threshold.
+ * @index: (out) Index value to retrieve the channels.
+ * @numchannels: (out) Number of channels found during Band Scan.
+ * @channels: (out) Channels found during band scan.
+ * @rssi: (out) Rssi of channels found during Band scan.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_get_scan_band_info(
+ u32 index,
+ u16 *numchannels,
+ u16 *channels,
+ u16 *rssi
+ );
+
+/**
+ * fmd_rx_block_scan() - Starts Block Scan.
+ *
+ * Starts block scan for retriving the RSSI level of channels
+ * in the given block.
+ * @start_freq: Starting frequency of the block from where scanning has
+ * to be started.
+ * @stop_freq: End frequency of the block to be scanned.
+ * @antenna: Antenna to be used during scanning.
+ *
+ * Returns:
+ * 0, if scan band started successfully.
+ * -EINVAL, if parameters are invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_block_scan(
+ u32 start_freq,
+ u32 stop_freq,
+ u8 antenna
+ );
+
+/**
+ * fmd_rx_get_block_scan_result() - Retrieves RSSI Level of channels.
+ *
+ * Retrieves the RSSI level of the channels in the block.
+ * @index: (out) Index value to retrieve the channels.
+ * @numchannels: (out) Number of channels found during Band Scan.
+ * @rssi: (out) Rssi of channels found during Band scan.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_get_block_scan_result(
+ u32 index,
+ u16 *numchannels,
+ u16 *rssi
+ );
+
+/**
+ * fmd_rx_get_rds() - Gets the current status of RDS transmission.
+ *
+ * @on: (out) RDS status
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_rx_get_rds(
+ bool *on
+ );
+
+/**
+ * fmd_rx_buffer_set_size() - Sets the number of groups that the data buffer.
+ * can contain and clears the buffer.
+ *
+ * @size: buffer size
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_buffer_set_size(
+ u8 size
+ );
+
+/**
+ * fmd_rx_buffer_set_threshold() - RDS Buffer Threshold level in FM Chip.
+ *
+ * Sets the group number at which the RDS buffer full interrupt must be
+ * generated. The interrupt will be set after reception of the group.
+ * @threshold: threshold level.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_buffer_set_threshold(
+ u8 threshold
+ );
+
+/**
+ * fmd_rx_set_rds() - Enables or disables demodulation of RDS data.
+ *
+ * @on_off_state : Rx Set ON /OFF control
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_rx_set_rds(
+ u8 on_off_state
+ );
+
+/**
+ * fmd_rx_get_low_level_rds_groups() - Gets Low level RDS group data.
+ *
+ * @index: RDS group index
+ * @block1: (out) RDS Block 1
+ * @block2: (out) RDS Block 2
+ * @block3: (out) RDS Block 3
+ * @block4: (out) RDS Block 4
+ * @status1: (out) RDS data status 1
+ * @status2: (out) RDS data status 2
+ * @status3: (out) RDS data status 3
+ * @status4: (out) RDS data status 4
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_rx_get_low_level_rds_groups(
+ u8 index,
+ u16 *block1,
+ u16 *block2,
+ u16 *block3,
+ u16 *block4,
+ u8 *status1,
+ u8 *status2,
+ u8 *status3,
+ u8 *status4
+ );
+
+/**
+ * fmd_tx_set_pa() - Enables or disables the Power Amplifier.
+ *
+ * @on: Power Amplifier current state to set
+ *
+ * Returns:
+ * 0, if set Power Amplifier done successfully.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_set_pa(
+ bool on
+ );
+
+/**
+ * fmd_tx_set_signal_strength() - Sets the RF-level of the output FM signal.
+ *
+ * @strength: Signal strength to be set for FM Tx in dBuV.
+ *
+ * Returns:
+ * 0, if set RSSI Level done successfully.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_set_signal_strength(
+ u16 strength
+ );
+
+/**
+ * fmd_tx_get_signal_strength() - Retrieves current RSSI of FM Tx.
+ *
+ * @strength: (out) Strength of signal being transmitted in dBuV.
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_tx_get_signal_strength(
+ u16 *strength
+ );
+
+/**
+ * fmd_tx_set_freq_range() - Sets the FM band and specifies the custom band.
+ *
+ * @range: Freq range to set on FM Tx.
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_set_freq_range(
+ u8 range
+ );
+
+/**
+ * fmd_tx_get_freq_range() - Gets the FM band currently in use.
+ *
+ * @range: (out) Frequency Range set on Fm Tx.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ */
+int fmd_tx_get_freq_range(
+ u8 *range
+ );
+
+/**
+ * fmd_tx_set_grid() - Sets the tuning grid size.
+ *
+ * @grid: FM Grid (50 Khz, 100 Khz, 200 Khz) to be set for FM Tx.
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_set_grid(
+ u8 grid
+ );
+
+/**
+ * fmd_tx_get_grid() - Gets the current tuning grid size.
+ *
+ * @grid: (out) FM Grid (50 Khz, 100 Khz, 200 Khz) currently set on FM Tx.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_tx_get_grid(
+ u8 *grid
+ );
+
+/**
+ * fmd_tx_set_preemphasis() - Sets the Preemphasis characteristic of the Tx.
+ *
+ * @preemphasis: Pre-emphasis level to be set for FM Tx.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_set_preemphasis(
+ u8 preemphasis
+ );
+
+/**
+ * fmd_tx_get_preemphasis() - Gets the currently used Preemphasis char of th FM Tx.
+ *
+ * @preemphasis: (out) Preemphasis Level used for FM Tx.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_tx_get_preemphasis(
+ u8 *preemphasis
+ );
+
+/**
+ * fmd_tx_set_frequency() - Sets the FM Channel for Tx.
+ *
+ * @freq: Freq to be set for transmission.
+ *
+ * Returns:
+ * 0, if set frequency done successfully.
+ * -EINVAL, if parameters are invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_set_frequency(
+ u32 freq
+ );
+
+/**
+ * fmd_rx_get_frequency() - Gets the currently used Channel for Tx.
+ *
+ * @freq: (out) Frequency set on FM Tx.
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameters are invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_get_frequency(
+ u32 *freq
+ );
+
+/**
+ * fmd_tx_enable_stereo_mode() - Sets Stereo mode state for TX.
+ *
+ * @enable_stereo_mode: Flag indicating enabling or disabling Stereo mode.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_enable_stereo_mode(
+ bool enable_stereo_mode
+ );
+
+/**
+ * fmd_tx_get_stereo_mode() - Gets the currently used FM Tx stereo mode.
+ *
+ * @stereo_mode: (out) Stereo Mode state set on FM Tx.
+ *
+ * Returns:
+ * 0, if no error.
+ * -EINVAL, if parameter is invalid.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_tx_get_stereo_mode(
+ bool *stereo_mode
+ );
+
+/**
+ * fmd_tx_set_pilot_deviation() - Sets pilot deviation in HZ
+ *
+ * @deviation: Pilot deviation in HZ to set on FM Tx.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_set_pilot_deviation(
+ u16 deviation
+ );
+
+/**
+ * fmd_tx_get_pilot_deviation() - Retrieves the current pilot deviation.
+ *
+ * @deviation: (out) Pilot deviation set on FM Tx.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_tx_get_pilot_deviation(
+ u16 *deviation
+ );
+
+/**
+ * fmd_tx_set_rds_deviation() - Sets Rds deviation in HZ.
+ *
+ * @deviation: RDS deviation in HZ.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_set_rds_deviation(
+ u16 deviation
+ );
+
+/**
+ * fmd_tx_get_rds_deviation() - Retrieves the current Rds deviation.
+ *
+ * @deviation: (out) RDS deviation currently set.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_tx_get_rds_deviation(
+ u16 *deviation
+ );
+
+/**
+ * fmd_tx_set_rds() - Enables or disables RDS transmission for Tx.
+ *
+ * @on: Boolean - RDS ON
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_set_rds(
+ bool on
+ );
+
+/**
+ * fmd_rx_get_rds() - Gets the current status of RDS transmission for FM Tx.
+ *
+ * @on: (out) Rds enabled or disabled.
+ *
+ *Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_tx_get_rds(
+ bool *on
+ );
+
+/**
+ * fmd_tx_set_group() - Programs a grp on a certain position in the RDS buffer.
+ *
+ * @position: RDS group position
+ * @block1: Data to be transmitted in Block 1
+ * @block2: Data to be transmitted in Block 2
+ * @block3: Data to be transmitted in Block 3
+ * @block4: Data to be transmitted in Block 4
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if parameters are invalid.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_set_group(
+ u16 position,
+ u8 *block1,
+ u8 *block2,
+ u8 *block3,
+ u8 *block4
+ );
+
+/**
+ * fmd_tx_buffer_set_size() - Controls the size of the RDS buffer in groups.
+ *
+ * @buffer_size: RDS buffer size.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_tx_buffer_set_size(
+ u16 buffer_size
+ );
+
+/**
+ * fmd_set_volume() - Sets the receive audio volume.
+ *
+ * @volume: Audio volume level
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_set_volume(
+ u8 volume
+ );
+
+/**
+ * fmd_get_volume() - Retrives the current audio volume.
+ *
+ * @volume: Analog Volume level.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if parameter is invalid.
+ * -EBUSY, if FM Driver is not in idle state.
+ */
+int fmd_get_volume(
+ u8 *volume
+ );
+
+/**
+ * fmd_set_balance() - Controls the receiver audio balance.
+ *
+ * @balance: Audio balance level
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_set_balance(
+ s8 balance
+ );
+
+/**
+ * fmd_set_mute() - Enables or disables muting of the analog audio(DAC).
+ *
+ * @mute_on: bool of mute on
+ *
+ * Returns:
+ * 0, if mute done successfully.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_set_mute(
+ bool mute_on
+ );
+
+/**
+ * fmd_ext_set_mute() - Enables or disables muting of the audio channel.
+ *
+ * @mute_on: bool to Mute
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_ext_set_mute(
+ bool mute_on
+ );
+
+/**
+ * fmd_power_up() - Puts the system in Powerup state.
+ *
+ * Returns:
+ * 0, if power up command sent successfully to chip.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_power_up(void);
+
+/**
+ * fmd_goto_standby() - Puts the system in standby mode.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_goto_standby(void);
+
+/**
+ * fmd_goto_power_down() - Puts the system in Powerdown mode.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_goto_power_down(void);
+
+/**
+ * fmd_select_ref_clk() - Selects the FM reference clock.
+ *
+ * @ref_clk: Ref Clock.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_select_ref_clk(
+ u16 ref_clk
+ );
+
+/**
+ * fmd_set_ref_clk_pll() - Sets the freq of Referece Clock.
+ *
+ * Sets frequency and offset correction properties of the external
+ * reference clock of the PLL
+ * @freq: PLL Frequency/ 2 in kHz.
+ *
+ * Returns:
+ * 0, if no error.
+ * -ENOEXEC, if preconditions are violated.
+ * -EBUSY, if FM Driver is not in idle state.
+ * -EINVAL, if wrong response received from chip.
+ */
+int fmd_set_ref_clk_pll(
+ u16 freq
+ );
+
+/**
+ * fmd_send_fm_ip_enable()- Enables the FM IP.
+ *
+ * Returns:
+ * 0: If there is no error.
+ * -ETIME: Otherwise
+ */
+int fmd_send_fm_ip_enable(void);
+
+/**
+ * fmd_send_fm_ip_disable()- Disables the FM IP.
+ *
+ * Returns:
+ * 0, If there is no error.
+ * -ETIME: Otherwise
+ */
+int fmd_send_fm_ip_disable(void);
+
+/**
+ * fmd_send_fm_firmware() - Send the FM Firmware File to Device.
+ *
+ * @fw_buffer: Firmware to be downloaded.
+ * @fw_size: Size of firmware to be downloaded.
+ *
+ * Returns:
+ * 0, If there is no error.
+ * -ETIME: Otherwise
+ */
+int fmd_send_fm_firmware(
+ u8 *fw_buffer,
+ u16 fw_size
+ );
+
+/**
+ * fmd_int_bufferfull() - RDS Groups availabe for reading by Host.
+ *
+ * Gets the number of groups that are available in the
+ * buffer. This function is called in RX mode to read RDS groups.
+ * @number_of_rds_groups: Number of RDS groups ready to
+ * be read from the Host.
+ *
+ * Returns:
+ * 0, If there is no error.
+ * corresponding error Otherwise
+ */
+int fmd_int_bufferfull(
+ u16 *number_of_rds_groups
+ );
+
+/**
+ * fmd_start_rds_thread() - Starts the RDS Thread for receiving RDS Data.
+ *
+ * This is started by Application when it wants to receive RDS Data.
+ * @cb_func: Callback function for receiving RDS Data
+ */
+void fmd_start_rds_thread(
+ cg2900_fm_rds_cb cb_func
+ );
+/**
+ * fmd_stop_rds_thread() - Stops the RDS Thread when Application does not
+ * want to receive RDS.
+ */
+void fmd_stop_rds_thread(void);
+
+/**
+ * fmd_get_rds_sem() - Block on RDS Semaphore.
+ * Till irpt_BufferFull is received, RDS Task is blocked.
+ */
+void fmd_get_rds_sem(void);
+
+/**
+ * fmd_set_rds_sem() - Unblock on RDS Semaphore.
+ * on receiving irpt_BufferFull, RDS Task is un-blocked.
+ */
+void fmd_set_rds_sem(void);
+
+#endif /* _FMDRIVER_H_ */
diff --git a/drivers/media/radio/CG2900/radio-cg2900.c b/drivers/media/radio/CG2900/radio-cg2900.c
new file mode 100644
index 00000000000..5356a0ef63f
--- /dev/null
+++ b/drivers/media/radio/CG2900/radio-cg2900.c
@@ -0,0 +1,2568 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Linux Wrapper for V4l2 FM Driver for CG2900.
+ *
+ * Author: Hemant Gupta <hemant.gupta@stericsson.com> for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include<linux/init.h>
+#include<linux/videodev2.h>
+#include"linux/videodev.h"
+#include<media/v4l2-ioctl.h>
+#include<media/v4l2-common.h>
+#include<linux/module.h>
+#include<linux/string.h>
+#include<linux/wait.h>
+#include"cg2900_fm_driver.h"
+
+#define RADIO_CG2900_VERSION KERNEL_VERSION(1, 1, 0)
+#define BANNER "ST-Ericsson FM Radio Card driver v1.1.0"
+
+#define FMR_HZ_TO_MHZ_CONVERTER 1000000
+#define FMR_EU_US_LOW_FREQ_IN_MHZ 87.5
+#define FMR_EU_US_HIGH_FREQ_IN_MHZ 108
+#define FMR_JAPAN_LOW_FREQ_IN_MHZ 76
+#define FMR_JAPAN_HIGH_FREQ_IN_MHZ 90
+#define FMR_CHINA_LOW_FREQ_IN_MHZ 70
+#define FMR_CHINA_HIGH_FREQ_IN_MHZ 108
+#define FMR_MAX_BLOCK_SCAN_CHANNELS 198
+#define FMR_CHINA_GRID_IN_HZ 50000
+#define FMR_EUROPE_GRID_IN_HZ 100000
+#define FMR_USA_GRID_IN_HZ 200000
+#define FMR_AF_SWITCH_DATA_SIZE 2
+#define FMR_BLOCK_SCAN_DATA_SIZE 2
+
+/* freq in Hz to V4l2 freq (units of 62.5Hz) */
+#define HZ_TO_V4L2(X) (2*(X)/125)
+/* V4l2 freq (units of 62.5Hz) to freq in Hz */
+#define V4L2_TO_HZ(X) (((X)*125)/(2))
+
+static int cg2900_open(
+ struct file *file
+ );
+static int cg2900_release(
+ struct file *file
+ );
+static ssize_t cg2900_read(
+ struct file *file,
+ char __user *data,
+ size_t count,
+ loff_t *pos
+ );
+static unsigned int cg2900_poll(
+ struct file *file,
+ struct poll_table_struct *wait
+ );
+static int vidioc_querycap(
+ struct file *file,
+ void *priv,
+ struct v4l2_capability *query_caps
+ );
+static int vidioc_get_tuner(
+ struct file *file,
+ void *priv,
+ struct v4l2_tuner *tuner
+ );
+static int vidioc_set_tuner(
+ struct file *file,
+ void *priv,
+ struct v4l2_tuner *tuner
+ );
+static int vidioc_get_modulator(
+ struct file *file,
+ void *priv,
+ struct v4l2_modulator *modulator
+ );
+static int vidioc_set_modulator(
+ struct file *file,
+ void *priv,
+ struct v4l2_modulator *modulator
+ );
+static int vidioc_get_frequency(
+ struct file *file,
+ void *priv,
+ struct v4l2_frequency *freq
+ );
+static int vidioc_set_frequency(
+ struct file *file,
+ void *priv,
+ struct v4l2_frequency *freq
+ );
+static int vidioc_query_ctrl(
+ struct file *file,
+ void *priv,
+ struct v4l2_queryctrl *query_ctrl
+ );
+static int vidioc_get_ctrl(
+ struct file *file,
+ void *priv,
+ struct v4l2_control *ctrl
+ );
+static int vidioc_set_ctrl(
+ struct file *file,
+ void *priv,
+ struct v4l2_control *ctrl
+ );
+static int vidioc_get_ext_ctrls(
+ struct file *file,
+ void *priv,
+ struct v4l2_ext_controls *ext_ctrl
+ );
+static int vidioc_set_ext_ctrls(
+ struct file *file,
+ void *priv,
+ struct v4l2_ext_controls *ext_ctrl
+ );
+static int vidioc_set_hw_freq_seek(
+ struct file *file,
+ void *priv,
+ struct v4l2_hw_freq_seek *freq_seek
+ );
+static int vidioc_get_audio(
+ struct file *file,
+ void *priv,
+ struct v4l2_audio *audio
+ );
+static int vidioc_set_audio(
+ struct file *file,
+ void *priv,
+ struct v4l2_audio *audio
+ );
+static int vidioc_get_input(
+ struct file *filp,
+ void *priv,
+ unsigned int *input
+ );
+static int vidioc_set_input(
+ struct file *filp,
+ void *priv,
+ unsigned int input
+ );
+static void cg2900_convert_err_to_v4l2(
+ char status_byte,
+ char *out_byte
+ );
+
+static int __init cg2900_init(void);
+static void __exit cg2900_exit(void);
+
+static u32 freq_low;
+static u32 freq_high;
+
+/* Module Parameters */
+static int radio_nr = -1;
+static int grid;
+static int band;
+
+/* cg2900_poll_queue - Main Wait Queue for polling (Scan/Seek) */
+static wait_queue_head_t cg2900_poll_queue;
+
+/* cg2900_read_queue - Main Wait Queue for receiving RDS Data */
+static DECLARE_WAIT_QUEUE_HEAD(cg2900_read_queue);
+
+/**
+ * enum fm_seek_status - Seek status of FM Radio.
+ *
+ * @FMR_SEEK_NONE: No seek in progress.
+ * @FMR_SEEK_IN_PROGRESS: Seek is in progress.
+ *
+ * Seek status of FM Radio.
+ */
+enum fm_seek_status {
+ FMR_SEEK_NONE,
+ FMR_SEEK_IN_PROGRESS
+};
+
+/**
+ * enum fm_power_state - Power states of FM Radio.
+ *
+ * @FMR_SWITCH_OFF: FM Radio is switched off.
+ * @FMR_SWITCH_ON: FM Radio is switched on.
+ * @FMR_STANDBY: FM Radio in standby state.
+ *
+ * Power states of FM Radio.
+ */
+enum fm_power_state {
+ FMR_SWITCH_OFF,
+ FMR_SWITCH_ON,
+ FMR_STANDBY
+};
+
+/**
+ * struct cg2900_device - Stores FM Device Info.
+ *
+ * @state: state of FM Radio
+ * @muted: FM Radio Mute/Unmute status
+ * @seekstatus: seek status
+ * @rx_rds_enabled: Rds enable/disable status for FM Rx
+ * @tx_rds_enabled: Rds enable/disable status for FM Tx
+ * @rx_stereo_status: Stereo Mode status for FM Rx
+ * @tx_stereo_status: Stereo Mode status for FM Tx
+ * @volume: Analog Volume Gain of FM Radio
+ * @rssi_threshold: rssi Thresold set on FM Radio
+ * @frequency: Frequency tuned on FM Radio in V4L2 Format
+ * @audiopath: Audio Balance
+ * @wait_on_read_queue: Flag for waiting on read queue.
+ * @fm_mode: Enum for storing the current FM Mode.
+ *
+ * FM Driver Information Structure.
+ */
+struct cg2900_device {
+ u8 state;
+ u8 muted;
+ u8 seekstatus;
+ bool rx_rds_enabled;
+ bool tx_rds_enabled;
+ bool rx_stereo_status;
+ bool tx_stereo_status;
+ int volume;
+ u16 rssi_threshold;
+ u32 frequency;
+ u32 audiopath;
+ bool wait_on_read_queue;
+ enum cg2900_fm_mode fm_mode;
+};
+
+/* Global Structure to store the maintain FM Driver device info */
+static struct cg2900_device cg2900_device;
+
+/* V4l2 File Operation Structure */
+static const struct v4l2_file_operations cg2900_fops = {
+ .owner = THIS_MODULE,
+ .open = cg2900_open,
+ .release = cg2900_release,
+ .read = cg2900_read,
+ .poll = cg2900_poll,
+ .ioctl = video_ioctl2,
+};
+
+/* V4L2 IOCTL Operation Structure */
+static const struct v4l2_ioctl_ops cg2900_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_tuner = vidioc_get_tuner,
+ .vidioc_s_tuner = vidioc_set_tuner,
+ .vidioc_g_modulator = vidioc_get_modulator,
+ .vidioc_s_modulator = vidioc_set_modulator,
+ .vidioc_g_frequency = vidioc_get_frequency,
+ .vidioc_s_frequency = vidioc_set_frequency,
+ .vidioc_queryctrl = vidioc_query_ctrl,
+ .vidioc_g_ctrl = vidioc_get_ctrl,
+ .vidioc_s_ctrl = vidioc_set_ctrl,
+ .vidioc_g_ext_ctrls = vidioc_get_ext_ctrls,
+ .vidioc_s_ext_ctrls = vidioc_set_ext_ctrls,
+ .vidioc_s_hw_freq_seek = vidioc_set_hw_freq_seek,
+ .vidioc_g_audio = vidioc_get_audio,
+ .vidioc_s_audio = vidioc_set_audio,
+ .vidioc_g_input = vidioc_get_input,
+ .vidioc_s_input = vidioc_set_input,
+};
+
+/* V4L2 Video Device Structure */
+static struct video_device cg2900_video_device = {
+ .name = "STE CG2900 FM Rx/Tx Radio",
+ .vfl_type = VID_TYPE_TUNER | VID_TYPE_CAPTURE,
+ .fops = &cg2900_fops,
+ .ioctl_ops = &cg2900_ioctl_ops,
+ .release = video_device_release_empty,
+};
+
+static u16 no_of_scan_freq;
+static u16 no_of_block_scan_freq;
+static u32 scanfreq_rssi_level[MAX_CHANNELS_TO_SCAN];
+static u16 block_scan_rssi_level[MAX_CHANNELS_FOR_BLOCK_SCAN];
+static u32 scanfreq[MAX_CHANNELS_TO_SCAN];
+static struct mutex fm_mutex;
+static spinlock_t fm_spinlock;
+static int users;
+
+/**
+ * vidioc_querycap()- Query FM Driver Capabilities.
+ *
+ * This function is used to query the capabilities of the
+ * FM Driver. This function is called when the application issues the IOCTL
+ * VIDIOC_QUERYCAP.
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @query_caps: v4l2_capability structure.
+ *
+ * Returns: 0
+ */
+static int vidioc_querycap(
+ struct file *file,
+ void *priv,
+ struct v4l2_capability *query_caps
+ )
+{
+ FM_INFO_REPORT("vidioc_querycap");
+ memset(
+ query_caps,
+ 0,
+ sizeof(*query_caps)
+ );
+ strlcpy(
+ query_caps->driver,
+ "CG2900 Driver",
+ sizeof(query_caps->driver)
+ );
+ strlcpy(
+ query_caps->card,
+ "CG2900 FM Radio",
+ sizeof(query_caps->card)
+ );
+ strcpy(
+ query_caps->bus_info,
+ "platform"
+ );
+ query_caps->version = RADIO_CG2900_VERSION;
+ query_caps->capabilities =
+ V4L2_CAP_TUNER |
+ V4L2_CAP_MODULATOR |
+ V4L2_CAP_RADIO |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_RDS_CAPTURE |
+ V4L2_CAP_HW_FREQ_SEEK |
+ V4L2_CAP_RDS_OUTPUT;
+ FM_DEBUG_REPORT("vidioc_querycap returning 0");
+ return 0;
+}
+
+/**
+ * vidioc_get_tuner()- Get FM Tuner Features.
+ *
+ * This function is used to get the tuner features.
+ * This function is called when the application issues the IOCTL
+ * VIDIOC_G_TUNER
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @tuner: v4l2_tuner structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_get_tuner(
+ struct file *file,
+ void *priv,
+ struct v4l2_tuner *tuner
+ )
+{
+ int status = 0;
+ u8 mode;
+ bool rds_enabled;
+ u16 rssi;
+ int ret_val = -EINVAL;
+
+ FM_INFO_REPORT("vidioc_get_tuner");
+
+ if (tuner->index > 0) {
+ FM_ERR_REPORT("vidioc_get_tuner: Only 1 tuner supported");
+ goto error;
+ }
+
+ memset(tuner, 0, sizeof(*tuner));
+ strcpy(tuner->name, "CG2900 FM Receiver");
+ tuner->type = V4L2_TUNER_RADIO;
+ tuner->rangelow = HZ_TO_V4L2(freq_low);
+ tuner->rangehigh = HZ_TO_V4L2(freq_high);
+ tuner->capability =
+ V4L2_TUNER_CAP_LOW /* Frequency steps = 1/16 kHz */
+ | V4L2_TUNER_CAP_STEREO /* Can receive stereo */
+ | V4L2_TUNER_CAP_RDS; /* Supports RDS Capture */
+
+ if (cg2900_device.fm_mode == CG2900_FM_RX_MODE) {
+
+ status = cg2900_fm_get_mode(&mode);
+
+ FM_DEBUG_REPORT("vidioc_get_tuner: mode = %d, ", mode);
+
+ if (0 != status) {
+ /* Get mode API failed, set mode to mono */
+ tuner->audmode = V4L2_TUNER_MODE_MONO;
+ tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
+ goto error;
+ }
+
+ switch (mode) {
+ case CG2900_MODE_STEREO:
+ tuner->audmode = V4L2_TUNER_MODE_STEREO;
+ tuner->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ break;
+ case CG2900_MODE_MONO:
+ default:
+ tuner->audmode = V4L2_TUNER_MODE_MONO;
+ tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
+ break;
+ }
+
+ status = cg2900_fm_get_rds_status(&rds_enabled);
+
+ if (0 != status) {
+ tuner->rxsubchans &= ~V4L2_TUNER_SUB_RDS;
+ goto error;
+ }
+
+ if (rds_enabled)
+ tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
+ else
+ tuner->rxsubchans &= ~V4L2_TUNER_SUB_RDS;
+ } else {
+ tuner->audmode = V4L2_TUNER_MODE_MONO;
+ tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
+ }
+
+ if (cg2900_device.fm_mode == CG2900_FM_RX_MODE) {
+ status = cg2900_fm_get_signal_strength(&rssi);
+
+ if (0 != status) {
+ tuner->signal = 0;
+ goto error;
+ }
+ tuner->signal = rssi;
+ } else {
+ tuner->signal = 0;
+ }
+
+ ret_val = 0;
+
+error:
+ FM_DEBUG_REPORT("vidioc_get_tuner: returning %d", ret_val);
+ return ret_val;
+}
+
+/**
+ * vidioc_set_tuner()- Set FM Tuner Features.
+ *
+ * This function is used to set the tuner features.
+ * It also sets the default FM Rx settings.
+ * This function is called when the application issues the IOCTL
+ * VIDIOC_S_TUNER
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @tuner: v4l2_tuner structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_set_tuner(
+ struct file *file,
+ void *priv,
+ struct v4l2_tuner *tuner
+ )
+{
+ bool rds_status = false;
+ bool stereo_status = false;
+ int status = 0;
+ int ret_val = -EINVAL;
+
+ FM_INFO_REPORT("vidioc_set_tuner");
+ if (tuner->index != 0) {
+ FM_ERR_REPORT("vidioc_set_tuner: Only 1 tuner supported");
+ goto error;
+ }
+
+ if (cg2900_device.fm_mode != CG2900_FM_RX_MODE) {
+ /*
+ * FM Rx mode should be configured
+ * as earlier mode was not FM Rx
+ */
+ if (CG2900_FM_BAND_US_EU == band) {
+ freq_low = FMR_EU_US_LOW_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ freq_high = FMR_EU_US_HIGH_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ } else if (CG2900_FM_BAND_JAPAN == band) {
+ freq_low = FMR_JAPAN_LOW_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ freq_high = FMR_JAPAN_HIGH_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ } else if (CG2900_FM_BAND_CHINA == band) {
+ freq_low = FMR_CHINA_LOW_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ freq_high = FMR_CHINA_HIGH_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ }
+ cg2900_device.fm_mode = CG2900_FM_RX_MODE;
+ cg2900_device.rx_rds_enabled =
+ (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) ?
+ true : false;
+ if (tuner->rxsubchans & V4L2_TUNER_SUB_STEREO)
+ stereo_status = true;
+ else if (tuner->rxsubchans & V4L2_TUNER_SUB_MONO)
+ stereo_status = false;
+ cg2900_device.rx_stereo_status = stereo_status;
+ status = cg2900_fm_set_rx_default_settings(freq_low,
+ band,
+ grid,
+ cg2900_device.rx_rds_enabled,
+ cg2900_device.rx_stereo_status);
+
+ if (0 != status) {
+ FM_ERR_REPORT("vidioc_set_tuner: "
+ "cg2900_fm_set_rx_default_settings returned "
+ " %d", status);
+ goto error;
+ }
+ status = cg2900_fm_set_rssi_threshold(
+ cg2900_device.rssi_threshold);
+ if (0 != status) {
+ FM_ERR_REPORT("vidioc_set_tuner: "
+ "cg2900_fm_set_rssi_threshold returned "
+ " %d", status);
+ goto error;
+ }
+ } else {
+ /*
+ * Mode was FM Rx only, change the RDS settings or stereo mode
+ * if they are changed by application
+ */
+ rds_status = (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) ?
+ true : false;
+ if (tuner->rxsubchans & V4L2_TUNER_SUB_STEREO)
+ stereo_status = true;
+ else if (tuner->rxsubchans & V4L2_TUNER_SUB_MONO)
+ stereo_status = false;
+ if (stereo_status != cg2900_device.rx_stereo_status) {
+ cg2900_device.rx_stereo_status = stereo_status;
+ if (stereo_status)
+ status =
+ cg2900_fm_set_mode(
+ FMD_STEREOMODE_BLENDING);
+ else
+ status = cg2900_fm_set_mode(
+ FMD_STEREOMODE_MONO);
+
+ if (0 != status) {
+ FM_ERR_REPORT("vidioc_set_tuner: "
+ "cg2900_fm_set_mode returned "
+ " %d", status);
+ goto error;
+ }
+ }
+ if (rds_status != cg2900_device.rx_rds_enabled) {
+ cg2900_device.rx_rds_enabled = rds_status;
+ if (rds_status)
+ status = cg2900_fm_rds_on();
+ else
+ status = cg2900_fm_rds_off();
+
+ if (0 != status) {
+ FM_ERR_REPORT("vidioc_set_tuner: "
+ "cg2900_fm_rds returned "
+ " %d", status);
+ goto error;
+ }
+ }
+ }
+
+ ret_val = 0;
+
+error:
+ FM_DEBUG_REPORT("vidioc_set_tuner: returning %d", ret_val);
+ return ret_val;
+}
+
+/**
+ * vidioc_get_modulator()- Get FM Modulator Features.
+ *
+ * This function is used to get the modulator features.
+ * This function is called when the application issues the IOCTL
+ * VIDIOC_G_MODULATOR
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @modulator: v4l2_modulator structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_get_modulator(
+ struct file *file,
+ void *priv,
+ struct v4l2_modulator *modulator
+ )
+{
+ int status = 0;
+ bool rds_enabled;
+ u8 mode;
+ int ret_val = -EINVAL;
+
+ FM_INFO_REPORT("vidioc_get_modulator");
+
+ if (modulator->index > 0) {
+ FM_ERR_REPORT("vidioc_get_modulator: Only 1 "
+ "modulator supported");
+ goto error;
+ }
+
+ memset(modulator, 0, sizeof(*modulator));
+ strcpy(modulator->name, "CG2900 FM Transmitter");
+ modulator->rangelow = freq_low;
+ modulator->rangehigh = freq_high;
+ modulator->capability = V4L2_TUNER_CAP_NORM /* Freq steps = 1/16 kHz */
+ | V4L2_TUNER_CAP_STEREO /* Can receive stereo */
+ | V4L2_TUNER_CAP_RDS; /* Supports RDS Capture */
+
+ if (cg2900_device.fm_mode == CG2900_FM_TX_MODE) {
+ status = cg2900_fm_get_mode(&mode);
+ FM_DEBUG_REPORT("vidioc_get_modulator: mode = %d", mode);
+ if (0 != status) {
+ /* Get mode API failed, set mode to mono */
+ modulator->txsubchans = V4L2_TUNER_SUB_MONO;
+ goto error;
+ }
+ switch (mode) {
+ /* Stereo */
+ case CG2900_MODE_STEREO:
+ modulator->txsubchans = V4L2_TUNER_SUB_STEREO;
+ break;
+ /* Mono */
+ case CG2900_MODE_MONO:
+ modulator->txsubchans = V4L2_TUNER_SUB_MONO;
+ break;
+ /* Switching or Blending, set mode as Stereo */
+ default:
+ modulator->txsubchans = V4L2_TUNER_SUB_STEREO;
+ }
+ status = cg2900_fm_get_rds_status(&rds_enabled);
+ if (0 != status) {
+ modulator->txsubchans &= ~V4L2_TUNER_SUB_RDS;
+ goto error;
+ }
+ if (rds_enabled)
+ modulator->txsubchans |= V4L2_TUNER_SUB_RDS;
+ else
+ modulator->txsubchans &= ~V4L2_TUNER_SUB_RDS;
+ } else
+ modulator->txsubchans = V4L2_TUNER_SUB_MONO;
+
+ ret_val = 0;
+
+error:
+ FM_DEBUG_REPORT("vidioc_get_modulator: returning %d",
+ ret_val);
+ return ret_val;
+}
+
+/**
+ * vidioc_set_modulator()- Set FM Modulator Features.
+ *
+ * This function is used to set the Modulaotr features.
+ * It also sets the default FM Tx settings.
+ * This function is called when the application issues the IOCTL
+ * VIDIOC_S_MODULATOR
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @modulator: v4l2_modulator structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_set_modulator(
+ struct file *file,
+ void *priv,
+ struct v4l2_modulator *modulator
+ )
+{
+ bool rds_status = false;
+ bool stereo_status = false;
+ int status = 0;
+ int ret_val = -EINVAL;
+
+ FM_INFO_REPORT("vidioc_set_modulator");
+ if (modulator->index != 0) {
+ FM_ERR_REPORT("vidioc_set_modulator: Only 1 "
+ "modulator supported");
+ goto error;
+ }
+
+ if (cg2900_device.fm_mode != CG2900_FM_TX_MODE) {
+ /*
+ * FM Tx mode should be configured as
+ * earlier mode was not FM Tx
+ */
+ if (band == CG2900_FM_BAND_US_EU) {
+ freq_low = FMR_EU_US_LOW_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ freq_high = FMR_EU_US_HIGH_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ } else if (band == CG2900_FM_BAND_JAPAN) {
+ freq_low = FMR_JAPAN_LOW_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ freq_high = FMR_JAPAN_HIGH_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ } else if (band == CG2900_FM_BAND_CHINA) {
+ freq_low = FMR_CHINA_LOW_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ freq_high = FMR_CHINA_HIGH_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ }
+ cg2900_device.fm_mode = CG2900_FM_TX_MODE;
+ cg2900_device.rx_rds_enabled = false;
+ cg2900_device.tx_rds_enabled =
+ (modulator->txsubchans & V4L2_TUNER_SUB_RDS) ?
+ true : false;
+ if (modulator->txsubchans & V4L2_TUNER_SUB_STEREO)
+ stereo_status = true;
+ else if (modulator->txsubchans & V4L2_TUNER_SUB_MONO)
+ stereo_status = false;
+ cg2900_device.tx_stereo_status = stereo_status;
+
+ status = cg2900_fm_set_tx_default_settings(freq_low,
+ band,
+ grid,
+ cg2900_device.tx_rds_enabled,
+ cg2900_device.
+ tx_stereo_status);
+
+ if (0 != status) {
+ FM_ERR_REPORT("vidioc_set_modulator: "
+ "cg2900_fm_set_tx_default_settings returned "
+ " %d", status);
+ goto error;
+ }
+ } else {
+ /*
+ * Mode was FM Tx only, change the RDS settings or stereo mode
+ * if they are changed by application
+ */
+ rds_status = (modulator->txsubchans & V4L2_TUNER_SUB_RDS) ?
+ true : false;
+ if (modulator->txsubchans & V4L2_TUNER_SUB_STEREO)
+ stereo_status = true;
+ else if (modulator->txsubchans & V4L2_TUNER_SUB_MONO)
+ stereo_status = false;
+ if (stereo_status != cg2900_device.tx_stereo_status) {
+ cg2900_device.tx_stereo_status = stereo_status;
+ status = cg2900_fm_set_mode(stereo_status);
+ if (0 != status) {
+ FM_ERR_REPORT("vidioc_set_modulator: "
+ "cg2900_fm_set_mode returned "
+ " %d", status);
+ goto error;
+ }
+ }
+ if (rds_status != cg2900_device.tx_rds_enabled) {
+ cg2900_device.tx_rds_enabled = rds_status;
+ status = cg2900_fm_tx_rds(rds_status);
+ if (0 != status) {
+ FM_ERR_REPORT("vidioc_set_modulator: "
+ "cg2900_fm_tx_rds returned "
+ " %d", status);
+ goto error;
+ }
+ }
+ }
+
+ ret_val = 0;
+
+error:
+ FM_DEBUG_REPORT("vidioc_set_modulator: returning %d",
+ ret_val);
+ return ret_val;
+}
+
+/**
+ * vidioc_get_frequency()- Get the Current FM Frequnecy.
+ *
+ * This function is used to get the currently tuned
+ * frequency on FM Radio. This function is called when the application
+ * issues the IOCTL VIDIOC_G_FREQUENCY
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @freq: v4l2_frequency structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_get_frequency(
+ struct file *file,
+ void *priv,
+ struct v4l2_frequency *freq
+ )
+{
+ int status;
+ u32 frequency;
+ int ret_val = -EINVAL;
+
+ FM_INFO_REPORT("vidioc_get_frequency: Status = %d",
+ cg2900_device.seekstatus);
+
+ status = cg2900_fm_get_frequency(&frequency);
+
+ if (0 != status) {
+ freq->frequency = cg2900_device.frequency;
+ goto error;
+ }
+
+ if (cg2900_device.seekstatus == FMR_SEEK_IN_PROGRESS) {
+ /* Check if seek is finished or not */
+ if (CG2900_EVENT_SEARCH_CHANNEL_FOUND == fm_event) {
+ /* seek is finished */
+ spin_lock(&fm_spinlock);
+ cg2900_device.frequency = HZ_TO_V4L2(frequency);
+ freq->frequency = cg2900_device.frequency;
+ cg2900_device.seekstatus = FMR_SEEK_NONE;
+ fm_event = CG2900_EVENT_NO_EVENT;
+ spin_unlock(&fm_spinlock);
+ }
+ } else {
+ spin_lock(&fm_spinlock);
+ cg2900_device.frequency = HZ_TO_V4L2(frequency);
+ freq->frequency = cg2900_device.frequency;
+ spin_unlock(&fm_spinlock);
+ }
+ ret_val = 0;
+
+error:
+ FM_DEBUG_REPORT("vidioc_get_frequency: returning = %d",
+ ret_val);
+ return ret_val;
+}
+
+/**
+ * vidioc_set_frequency()- Set the FM Frequnecy.
+ *
+ * This function is used to set the frequency
+ * on FM Radio. This function is called when the application
+ * issues the IOCTL VIDIOC_S_FREQUENCY
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @freq: v4l2_frequency structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_set_frequency(
+ struct file *file,
+ void *priv,
+ struct v4l2_frequency *freq
+ )
+{
+ u32 frequency = freq->frequency;
+ int status;
+ int ret_val = -EINVAL;
+
+ FM_INFO_REPORT("vidioc_set_frequency: Frequency = "
+ "%d ", V4L2_TO_HZ(frequency));
+
+ spin_lock(&fm_spinlock);
+ fm_event = CG2900_EVENT_NO_EVENT;
+ no_of_scan_freq = 0;
+ spin_unlock(&fm_spinlock);
+
+ cg2900_device.seekstatus = FMR_SEEK_NONE;
+ cg2900_device.frequency = frequency;
+ status = cg2900_fm_set_frequency(V4L2_TO_HZ(frequency));
+
+ if (0 != status)
+ goto error;
+
+ ret_val = 0;
+
+error:
+ FM_DEBUG_REPORT("vidioc_set_frequency: returning = %d",
+ ret_val);
+ return ret_val;
+}
+
+/**
+ * vidioc_query_ctrl()- Query the FM Driver control features.
+ *
+ * This function is used to query the control features on FM Radio.
+ * This function is called when the application
+ * issues the IOCTL VIDIOC_QUERYCTRL
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @query_ctrl: v4l2_queryctrl structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_query_ctrl(
+ struct file *file,
+ void *priv,
+ struct v4l2_queryctrl *query_ctrl
+ )
+{
+ int ret_val = -EINVAL;
+
+ FM_INFO_REPORT("vidioc_query_ctrl");
+ /* Check which control is requested */
+ switch (query_ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ FM_DEBUG_REPORT("vidioc_query_ctrl: V4L2_CID_AUDIO_MUTE");
+ query_ctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+ query_ctrl->minimum = 0;
+ query_ctrl->maximum = 1;
+ query_ctrl->step = 1;
+ query_ctrl->default_value = 0;
+ query_ctrl->flags = 0;
+ strncpy(query_ctrl->name, "CG2900 Mute", 32);
+ ret_val = 0;
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ FM_DEBUG_REPORT("vidioc_query_ctrl: V4L2_CID_AUDIO_VOLUME");
+
+ strncpy(query_ctrl->name, "CG2900 Volume", 32);
+ query_ctrl->minimum = MIN_ANALOG_VOLUME;
+ query_ctrl->maximum = MAX_ANALOG_VOLUME;
+ query_ctrl->step = 1;
+ query_ctrl->default_value = MAX_ANALOG_VOLUME;
+ query_ctrl->flags = 0;
+ query_ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ ret_val = 0;
+ break;
+
+ case V4L2_CID_AUDIO_BALANCE:
+ FM_DEBUG_REPORT("vidioc_query_ctrl: V4L2_CID_AUDIO_BALANCE ");
+ strncpy(query_ctrl->name, "CG2900 Audio Balance", 32);
+ query_ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ query_ctrl->minimum = 0x0000;
+ query_ctrl->maximum = 0xFFFF;
+ query_ctrl->step = 0x0001;
+ query_ctrl->default_value = 0x0000;
+ query_ctrl->flags = 0;
+ ret_val = 0;
+ break;
+
+ case V4L2_CID_AUDIO_BASS:
+ FM_DEBUG_REPORT("vidioc_query_ctrl: "
+ "V4L2_CID_AUDIO_BASS (unsupported)");
+ break;
+
+ case V4L2_CID_AUDIO_TREBLE:
+ FM_DEBUG_REPORT("vidioc_query_ctrl: "
+ "V4L2_CID_AUDIO_TREBLE (unsupported)");
+ break;
+
+ default:
+ FM_DEBUG_REPORT("vidioc_query_ctrl: "
+ "--> unsupported id = %d", (int)query_ctrl->id);
+ break;
+ }
+
+ FM_DEBUG_REPORT("vidioc_query_ctrl: returning = %d",
+ ret_val);
+ return ret_val;
+}
+
+/**
+ * vidioc_get_ctrl()- Get the value of a particular Control.
+ *
+ * This function is used to get the value of a
+ * particular control from the FM Driver. This function is called
+ * when the application issues the IOCTL VIDIOC_G_CTRL
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @ctrl: v4l2_control structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_get_ctrl(
+ struct file *file,
+ void *priv,
+ struct v4l2_control *ctrl
+ )
+{
+ int status;
+ u8 value;
+ u16 rssi;
+ u8 antenna;
+ u16 conclusion;
+ int ret_val = -EINVAL;
+
+ FM_INFO_REPORT("vidioc_get_ctrl");
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ status = cg2900_fm_get_volume(&value);
+ if (0 == status) {
+ ctrl->value = value;
+ cg2900_device.volume = value;
+ ret_val = 0;
+ }
+ break;
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = cg2900_device.muted;
+ ret_val = 0;
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ ctrl->value = cg2900_device.audiopath;
+ ret_val = 0;
+ break;
+ case V4L2_CID_CG2900_RADIO_RSSI_THRESHOLD:
+ ctrl->value = cg2900_device.rssi_threshold;
+ ret_val = 0;
+ break;
+ case V4L2_CID_CG2900_RADIO_SELECT_ANTENNA:
+ status = cg2900_fm_get_antenna(&antenna);
+ FM_DEBUG_REPORT("vidioc_get_ctrl: Antenna = %d", antenna);
+ if (0 == status) {
+ ctrl->value = antenna;
+ ret_val = 0;
+ }
+ break;
+ case V4L2_CID_CG2900_RADIO_RDS_AF_UPDATE_GET_RESULT:
+ status = cg2900_fm_af_update_get_result(&rssi);
+ FM_DEBUG_REPORT("vidioc_get_ctrl: AF RSSI Level = %d", rssi);
+ if (0 == status) {
+ ctrl->value = rssi;
+ ret_val = 0;
+ }
+ break;
+ case V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_GET_RESULT:
+ status = cg2900_fm_af_switch_get_result(&conclusion);
+ FM_DEBUG_REPORT("vidioc_get_ctrl: AF Switch conclusion = %d",
+ conclusion);
+ if (0 != status)
+ break;
+ if (conclusion == 0) {
+ ctrl->value = conclusion;
+ FM_DEBUG_REPORT("vidioc_get_ctrl: "
+ "AF Switch conclusion = %d",
+ ctrl->value);
+ ret_val = 0;
+ } else {
+ /*
+ * Convert positive error code returned by chip
+ * into negative error codes to be in line with linux.
+ */
+ ctrl->value = -conclusion;
+ FM_ERR_REPORT("vidioc_get_ctrl: "
+ "AF-Switch failed with value %d", (__s32)ctrl->value);
+ ret_val = 0;
+ }
+ break;
+ default:
+ FM_DEBUG_REPORT("vidioc_get_ctrl: "
+ "unsupported (id = %d)", (int)ctrl->id);
+ ret_val = -EINVAL;
+ }
+ FM_DEBUG_REPORT("vidioc_get_ctrl: returning = %d",
+ ret_val);
+ return ret_val;
+}
+
+/**
+ * vidioc_set_ctrl()- Set the value of a particular Control.
+ *
+ * This function is used to set the value of a
+ * particular control from the FM Driver. This function is called when the
+ * application issues the IOCTL VIDIOC_S_CTRL
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @ctrl: v4l2_control structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -ERANGE when the parameter is out of range.
+ * -EINVAL: otherwise
+ */
+static int vidioc_set_ctrl(
+ struct file *file,
+ void *priv,
+ struct v4l2_control *ctrl
+ )
+{
+ int status;
+ int ret_val = -EINVAL;
+ FM_INFO_REPORT("vidioc_set_ctrl");
+ /* Check which control is requested */
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ FM_DEBUG_REPORT("vidioc_set_ctrl: "
+ "V4L2_CID_AUDIO_MUTE, "
+ "value = %d", ctrl->value);
+ if (ctrl->value > 1 && ctrl->value < 0) {
+ ret_val = -ERANGE;
+ break;
+ }
+
+ if (ctrl->value) {
+ FM_DEBUG_REPORT("vidioc_set_ctrl: Ctrl_Id = "
+ "V4L2_CID_AUDIO_MUTE, "
+ "Muting the Radio");
+ status = cg2900_fm_mute();
+ } else {
+ FM_DEBUG_REPORT("vidioc_set_ctrl: "
+ "Ctrl_Id = V4L2_CID_AUDIO_MUTE, "
+ "UnMuting the Radio");
+ status = cg2900_fm_unmute();
+ }
+ if (0 == status) {
+ cg2900_device.muted = ctrl->value;
+ ret_val = 0;
+ }
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ FM_DEBUG_REPORT("vidioc_set_ctrl: "
+ "V4L2_CID_AUDIO_VOLUME, "
+ "value = %d", ctrl->value);
+ if (ctrl->value > MAX_ANALOG_VOLUME &&
+ ctrl->value < MIN_ANALOG_VOLUME) {
+ ret_val = -ERANGE;
+ break;
+ }
+ status = cg2900_fm_set_volume(ctrl->value);
+ if (0 == status) {
+ cg2900_device.volume = ctrl->value;
+ ret_val = 0;
+ }
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ FM_DEBUG_REPORT("vidioc_set_ctrl: "
+ "V4L2_CID_AUDIO_BALANCE, "
+ "value = %d", ctrl->value);
+ status = cg2900_fm_set_audio_balance(ctrl->value);
+ if (0 == status) {
+ cg2900_device.audiopath = ctrl->value;
+ ret_val = 0;
+ }
+ break;
+ case V4L2_CID_CG2900_RADIO_CHIP_STATE:
+ FM_DEBUG_REPORT("vidioc_set_ctrl: "
+ "V4L2_CID_CG2900_RADIO_CHIP_STATE, "
+ "value = %d", ctrl->value);
+ if (V4L2_CG2900_RADIO_STANDBY == ctrl->value)
+ status = cg2900_fm_standby();
+ else if (V4L2_CG2900_RADIO_POWERUP == ctrl->value)
+ status = cg2900_fm_power_up_from_standby();
+ else
+ break;
+ if (0 != status)
+ break;
+ if (V4L2_CG2900_RADIO_STANDBY == ctrl->value)
+ cg2900_device.state = FMR_STANDBY;
+ else if (V4L2_CG2900_RADIO_POWERUP == ctrl->value)
+ cg2900_device.state = FMR_SWITCH_ON;
+ ret_val = 0;
+ break;
+ case V4L2_CID_CG2900_RADIO_SELECT_ANTENNA:
+ FM_DEBUG_REPORT("vidioc_set_ctrl: "
+ "V4L2_CID_CG2900_RADIO_SELECT_ANTENNA, "
+ "value = %d", ctrl->value);
+ status = cg2900_fm_select_antenna(ctrl->value);
+ if (0 == status)
+ ret_val = 0;
+ break;
+ case V4L2_CID_CG2900_RADIO_BANDSCAN:
+ FM_DEBUG_REPORT("vidioc_set_ctrl: "
+ "V4L2_CID_CG2900_RADIO_BANDSCAN, "
+ "value = %d", ctrl->value);
+ if (V4L2_CG2900_RADIO_BANDSCAN_START == ctrl->value) {
+ cg2900_device.seekstatus = FMR_SEEK_IN_PROGRESS;
+ no_of_scan_freq = 0;
+ status = cg2900_fm_start_band_scan();
+ } else if (V4L2_CG2900_RADIO_BANDSCAN_STOP == ctrl->value) {
+ status = cg2900_fm_stop_scan();
+ cg2900_device.seekstatus = FMR_SEEK_NONE;
+ } else
+ break;
+ if (0 == status)
+ ret_val = 0;
+ break;
+ case V4L2_CID_CG2900_RADIO_RSSI_THRESHOLD:
+ FM_DEBUG_REPORT("vidioc_set_ctrl: "
+ "V4L2_CID_CG2900_RADIO_RSSI_THRESHOLD "
+ "= %d", ctrl->value);
+ status = cg2900_fm_set_rssi_threshold(ctrl->value);
+ if (0 == status) {
+ cg2900_device.rssi_threshold = ctrl->value;
+ ret_val = 0;
+ }
+ break;
+ case V4L2_CID_CG2900_RADIO_RDS_AF_UPDATE_START:
+ FM_DEBUG_REPORT("vidioc_set_ctrl: "
+ "V4L2_CID_CG2900_RADIO_RDS_AF_UPDATE_START "
+ "freq = %d Hz", ctrl->value);
+ status = cg2900_fm_af_update_start(ctrl->value);
+ if (0 == status)
+ ret_val = 0;
+ break;
+ default:
+ FM_DEBUG_REPORT("vidioc_set_ctrl: "
+ "unsupported (id = %d)", (int)ctrl->id);
+ }
+ FM_DEBUG_REPORT("vidioc_set_ctrl: returning = %d",
+ ret_val);
+ return ret_val;
+}
+
+/**
+ * vidioc_get_ext_ctrls()- Get the values of a particular control.
+ *
+ * This function is used to get the value of a
+ * particular control from the FM Driver. This is used when the data to
+ * be received is more than 1 paramter. This function is called when the
+ * application issues the IOCTL VIDIOC_G_EXT_CTRLS
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @ext_ctrl: v4l2_ext_controls structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -ENOSPC: when there is no space to copy the data into the buffer provided
+ * by application.
+ * -EINVAL: otherwise
+ */
+static int vidioc_get_ext_ctrls(
+ struct file *file,
+ void *priv,
+ struct v4l2_ext_controls *ext_ctrl
+ )
+{
+ u32 *dest_buffer;
+ int index = 0;
+ int count = 0;
+ int ret_val = -EINVAL;
+ int status;
+
+ FM_INFO_REPORT("vidioc_get_ext_ctrls: Id = %04x,"
+ "ext_ctrl->ctrl_class = %04x",
+ ext_ctrl->controls->id,
+ ext_ctrl->ctrl_class);
+
+ if (ext_ctrl->ctrl_class != V4L2_CTRL_CLASS_FM_TX &&
+ ext_ctrl->ctrl_class != V4L2_CTRL_CLASS_USER) {
+ FM_ERR_REPORT("vidioc_get_ext_ctrls: Unsupported "
+ "ctrl_class = %04x", ext_ctrl->ctrl_class);
+ goto error;
+ }
+
+ switch (ext_ctrl->controls->id) {
+ case V4L2_CID_CG2900_RADIO_BANDSCAN_GET_RESULTS:
+ {
+ if (ext_ctrl->ctrl_class != V4L2_CTRL_CLASS_USER) {
+ FM_ERR_REPORT("vidioc_get_ext_ctrls: "
+ "V4L2_CID_CG2900_RADIO_BANDSCAN_GET_RESULTS "
+ "Unsupported ctrl_class = %04x",
+ ext_ctrl->ctrl_class);
+ break;
+ }
+ if (cg2900_device.seekstatus ==
+ FMR_SEEK_IN_PROGRESS) {
+ if (fm_event ==
+ CG2900_EVENT_SCAN_CHANNELS_FOUND) {
+ /* Check to get Scan Result */
+ status =
+ cg2900_fm_get_scan_result
+ (&no_of_scan_freq, scanfreq,
+ scanfreq_rssi_level);
+ if (0 != status) {
+ FM_ERR_REPORT
+ ("vidioc_get_ext_ctrls: "
+ "cg2900_fm_get_scan_"
+ "result: returned %d",
+ status);
+ break;
+ }
+ }
+ }
+ FM_DEBUG_REPORT("vidioc_get_ext_ctrls: "
+ "SeekStatus = %d, GlobalEvent = %d, "
+ "numchannels = %d",
+ cg2900_device.seekstatus,
+ fm_event, no_of_scan_freq);
+
+ if (ext_ctrl->controls->size == 0 &&
+ ext_ctrl->controls->string == NULL) {
+ if (cg2900_device.seekstatus ==
+ FMR_SEEK_IN_PROGRESS &&
+ CG2900_EVENT_SCAN_CHANNELS_FOUND
+ == fm_event) {
+ spin_lock(&fm_spinlock);
+ ext_ctrl->controls->size =
+ no_of_scan_freq;
+ cg2900_device.seekstatus
+ = FMR_SEEK_NONE;
+ fm_event =
+ CG2900_EVENT_NO_EVENT;
+ spin_unlock(&fm_spinlock);
+ return -ENOSPC;
+ }
+ } else if (ext_ctrl->controls->string != NULL) {
+ dest_buffer =
+ (u32 *) ext_ctrl->controls->string;
+ while (index < no_of_scan_freq) {
+ *(dest_buffer + count + 0) =
+ HZ_TO_V4L2(scanfreq[index]);
+ *(dest_buffer + count + 1) =
+ scanfreq_rssi_level[index];
+ count += 2;
+ index++;
+ }
+ ret_val = 0;
+ }
+ break;
+ }
+ case V4L2_CID_CG2900_RADIO_BLOCKSCAN_GET_RESULTS:
+ {
+ if (ext_ctrl->ctrl_class != V4L2_CTRL_CLASS_USER) {
+ FM_ERR_REPORT("vidioc_get_ext_ctrls: "
+ "V4L2_CID_CG2900_RADIO_BLOCKSCAN_GET_RESULTS "
+ "Unsupported ctrl_class = %04x",
+ ext_ctrl->ctrl_class);
+ break;
+ }
+ if (cg2900_device.seekstatus ==
+ FMR_SEEK_IN_PROGRESS) {
+ if (fm_event ==
+ CG2900_EVENT_BLOCK_SCAN_CHANNELS_FOUND) {
+ /* Check to get BlockScan Result */
+ status =
+ cg2900_fm_get_block_scan_result
+ (&no_of_block_scan_freq,
+ block_scan_rssi_level);
+ if (0 != status) {
+ FM_ERR_REPORT
+ ("vidioc_get_ext_ctrls: "
+ "cg2900_fm_get_block_scan_"
+ "result: " "returned %d",
+ status);
+ return ret_val;
+ }
+ }
+ }
+ FM_DEBUG_REPORT("vidioc_get_ext_ctrls: "
+ "SeekStatus = %d, GlobalEvent = %d, "
+ "numchannels = %d",
+ cg2900_device.seekstatus,
+ fm_event, no_of_block_scan_freq);
+ if (ext_ctrl->controls->size == 0 &&
+ ext_ctrl->controls->string == NULL) {
+ if (cg2900_device.seekstatus ==
+ FMR_SEEK_IN_PROGRESS &&
+ CG2900_EVENT_BLOCK_SCAN_CHANNELS_FOUND
+ == fm_event) {
+ spin_lock(&fm_spinlock);
+ ext_ctrl->controls->size =
+ no_of_block_scan_freq;
+ cg2900_device.seekstatus
+ = FMR_SEEK_NONE;
+ fm_event =
+ CG2900_EVENT_NO_EVENT;
+ spin_unlock(&fm_spinlock);
+ return -ENOSPC;
+ }
+ } else if (ext_ctrl->controls->size >=
+ no_of_block_scan_freq &&
+ ext_ctrl->controls->string != NULL) {
+ dest_buffer =
+ (u32 *) ext_ctrl->controls->string;
+ while (index < no_of_block_scan_freq) {
+ *(dest_buffer + index) =
+ block_scan_rssi_level
+ [index];
+ index++;
+ }
+ ret_val = 0;
+ return ret_val;
+ }
+ break;
+ }
+ case V4L2_CID_RDS_TX_DEVIATION:
+ {
+ FM_DEBUG_REPORT("vidioc_get_ext_ctrls: "
+ "V4L2_CID_RDS_TX_DEVIATION");
+ if (V4L2_CTRL_CLASS_FM_TX != ext_ctrl->ctrl_class) {
+ FM_ERR_REPORT("Invalid Ctrl Class = %d",
+ ext_ctrl->ctrl_class);
+ break;
+ }
+ status = cg2900_fm_tx_get_rds_deviation((u16 *) &
+ ext_ctrl->
+ controls->value);
+ if (status == 0)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_PILOT_TONE_ENABLED:
+ {
+ FM_DEBUG_REPORT("vidioc_get_ext_ctrls: "
+ "V4L2_CID_PILOT_TONE_ENABLED");
+ if (V4L2_CTRL_CLASS_FM_TX != ext_ctrl->ctrl_class) {
+ FM_ERR_REPORT("Invalid Ctrl Class = %d",
+ ext_ctrl->ctrl_class);
+ break;
+ }
+ status = cg2900_fm_tx_get_pilot_tone_status(
+ (bool *)&ext_ctrl->controls->value);
+ if (status == 0)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_PILOT_TONE_DEVIATION:
+ {
+ FM_DEBUG_REPORT("vidioc_get_ext_ctrls: "
+ "V4L2_CID_PILOT_TONE_DEVIATION");
+ if (V4L2_CTRL_CLASS_FM_TX != ext_ctrl->ctrl_class) {
+ FM_ERR_REPORT("Invalid Ctrl Class = %d",
+ ext_ctrl->ctrl_class);
+ break;
+ }
+ status = cg2900_fm_tx_get_pilot_deviation(
+ (u16 *)&ext_ctrl->controls->value);
+ if (status == 0)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ {
+ FM_DEBUG_REPORT("vidioc_get_ext_ctrls: "
+ "V4L2_CID_TUNE_PREEMPHASIS");
+ if (V4L2_CTRL_CLASS_FM_TX != ext_ctrl->ctrl_class) {
+ FM_ERR_REPORT("Invalid Ctrl Class = %d",
+ ext_ctrl->ctrl_class);
+ break;
+ }
+ status = cg2900_fm_tx_get_preemphasis(
+ (u8 *)&ext_ctrl->controls->value);
+ if (status == 0)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_TUNE_POWER_LEVEL:
+ {
+ FM_DEBUG_REPORT("vidioc_get_ext_ctrls: "
+ "V4L2_CID_TUNE_POWER_LEVEL");
+ if (V4L2_CTRL_CLASS_FM_TX != ext_ctrl->ctrl_class) {
+ FM_ERR_REPORT("Invalid Ctrl Class = %d",
+ ext_ctrl->ctrl_class);
+ break;
+ }
+ status = cg2900_fm_tx_get_power_level(
+ (u16 *)&ext_ctrl->controls->value);
+ if (status == 0)
+ ret_val = 0;
+ break;
+ }
+ default:
+ {
+ FM_DEBUG_REPORT("vidioc_get_ext_ctrls: "
+ "unsupported (id = %d)",
+ (int)ext_ctrl->controls->id);
+ }
+ }
+
+error:
+ FM_DEBUG_REPORT("vidioc_get_ext_ctrls: returning = %d", ret_val);
+ return ret_val;
+}
+
+/**
+ * vidioc_set_ext_ctrls()- Set the values of a particular control.
+ *
+ * This function is used to set the value of a
+ * particular control on the FM Driver. This is used when the data to
+ * be set is more than 1 paramter. This function is called when the
+ * application issues the IOCTL VIDIOC_S_EXT_CTRLS
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @ext_ctrl: v4l2_ext_controls structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -ENOSPC: when there is no space to copy the data into the buffer provided
+ * by application.
+ * -EINVAL: otherwise
+ */
+static int vidioc_set_ext_ctrls(
+ struct file *file,
+ void *priv,
+ struct v4l2_ext_controls *ext_ctrl
+ )
+{
+ int ret_val = -EINVAL;
+ int status;
+
+ FM_INFO_REPORT("vidioc_set_ext_ctrls: Id = %04x, ctrl_class = %04x",
+ ext_ctrl->controls->id, ext_ctrl->ctrl_class);
+
+ if (ext_ctrl->ctrl_class != V4L2_CTRL_CLASS_FM_TX &&
+ ext_ctrl->ctrl_class != V4L2_CTRL_CLASS_USER) {
+ FM_ERR_REPORT("vidioc_set_ext_ctrls: Unsupported "
+ "ctrl_class = %04x", ext_ctrl->ctrl_class);
+ goto error;
+ }
+
+ switch (ext_ctrl->controls->id) {
+ case V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_START:
+ {
+ u32 af_switch_freq;
+ u16 af_switch_pi;
+ u32 *af_switch_buf;
+
+ if (ext_ctrl->ctrl_class != V4L2_CTRL_CLASS_USER) {
+ FM_ERR_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_START "
+ "Unsupported ctrl_class = %04x",
+ ext_ctrl->ctrl_class);
+ break;
+ }
+
+ if (ext_ctrl->controls->size !=
+ FMR_AF_SWITCH_DATA_SIZE ||
+ ext_ctrl->controls->string == NULL) {
+ FM_ERR_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_START "
+ "Unsupported ctrl_class = %04x",
+ ext_ctrl->ctrl_class);
+ break;
+ }
+
+ af_switch_buf = (u32 *) ext_ctrl->controls->string;
+ af_switch_freq = V4L2_TO_HZ(*af_switch_buf);
+ af_switch_pi = *(af_switch_buf + 1);
+ FM_DEBUG_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_START: "
+ "AF Switch Freq =%d Hz AF Switch PI = %04x",
+ af_switch_freq,
+ af_switch_pi);
+
+ if (af_switch_freq < (FMR_CHINA_LOW_FREQ_IN_MHZ
+ * FMR_HZ_TO_MHZ_CONVERTER) ||
+ af_switch_freq > (FMR_CHINA_HIGH_FREQ_IN_MHZ
+ * FMR_HZ_TO_MHZ_CONVERTER)) {
+ FM_ERR_REPORT("Invalid Freq = %04x",
+ af_switch_freq);
+ break;
+ }
+
+ status = cg2900_fm_af_switch_start(
+ af_switch_freq,
+ af_switch_pi);
+
+ if (0 == status)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_RDS_TX_DEVIATION:
+ {
+ FM_DEBUG_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_RDS_TX_DEVIATION, "
+ "Value = %d",
+ ext_ctrl->controls->value);
+
+ if (ext_ctrl->controls->value <= MIN_RDS_DEVIATION &&
+ ext_ctrl->controls->value > MAX_RDS_DEVIATION) {
+ FM_ERR_REPORT("Invalid RDS Deviation = %02x",
+ ext_ctrl->controls->value);
+ break;
+ }
+
+ status = cg2900_fm_tx_set_rds_deviation(
+ ext_ctrl->controls->value);
+
+ if (0 == status)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_RDS_TX_PI:
+ {
+ FM_DEBUG_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_RDS_TX_PI, PI = %04x",
+ ext_ctrl->controls->value);
+
+ if (ext_ctrl->controls->value <= MIN_PI_VALUE &&
+ ext_ctrl->controls->value > MAX_PI_VALUE) {
+ FM_ERR_REPORT("Invalid PI = %04x",
+ ext_ctrl->controls->value);
+ break;
+ }
+
+ status = cg2900_fm_tx_set_pi_code(
+ ext_ctrl->controls->value);
+
+ if (0 == status)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_RDS_TX_PTY:
+ {
+ FM_DEBUG_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_RDS_TX_PTY, PTY = %d",
+ ext_ctrl->controls->value);
+
+ if (ext_ctrl->controls->value < MIN_PTY_VALUE &&
+ ext_ctrl->controls->value > MAX_PTY_VALUE) {
+ FM_ERR_REPORT("Invalid PTY = %02x",
+ ext_ctrl->controls->value);
+ break;
+ }
+
+ status = cg2900_fm_tx_set_pty_code(
+ ext_ctrl->controls->value);
+
+ if (0 == status)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_RDS_TX_PS_NAME:
+ {
+ if (ext_ctrl->controls->size > MAX_PSN_SIZE
+ || ext_ctrl->controls->string == NULL) {
+ FM_ERR_REPORT("Invalid PSN");
+ break;
+ }
+
+ FM_DEBUG_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_RDS_TX_PS_NAME, "
+ "PSN = %s, Len = %d",
+ ext_ctrl->controls->string,
+ ext_ctrl->controls->size);
+
+ status = cg2900_fm_tx_set_program_station_name(
+ ext_ctrl->controls->string,
+ ext_ctrl->controls->size);
+
+ if (0 == status)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_RDS_TX_RADIO_TEXT:
+ {
+ if (ext_ctrl->controls->size >= MAX_RT_SIZE
+ || ext_ctrl->controls->string == NULL) {
+ FM_ERR_REPORT("Invalid RT");
+ break;
+ }
+
+ FM_DEBUG_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_RDS_TX_RADIO_TEXT, "
+ "RT = %s, Len = %d",
+ ext_ctrl->controls->string,
+ ext_ctrl->controls->size);
+
+ status = cg2900_fm_tx_set_radio_text(
+ ext_ctrl->controls->string,
+ ext_ctrl->controls->size);
+
+ if (0 == status)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_PILOT_TONE_ENABLED:
+ {
+ bool enable;
+ FM_DEBUG_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_PILOT_TONE_ENABLED, "
+ "Value = %d",
+ ext_ctrl->controls->value);
+
+ if (FMD_PILOT_TONE_ENABLED ==
+ ext_ctrl->controls->value)
+ enable = true;
+ else if (FMD_PILOT_TONE_DISABLED ==
+ ext_ctrl->controls->value)
+ enable = false;
+ else {
+ FM_ERR_REPORT("Unsupported Value = %d",
+ ext_ctrl->controls->value);
+ break;
+ }
+ status = cg2900_fm_tx_set_pilot_tone_status(enable);
+ if (0 == status)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_PILOT_TONE_DEVIATION:
+ {
+ FM_DEBUG_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_PILOT_TONE_DEVIATION, "
+ "Value = %d",
+ ext_ctrl->controls->value);
+
+ if (ext_ctrl->controls->value <= MIN_PILOT_DEVIATION &&
+ ext_ctrl->controls->value > MAX_PILOT_DEVIATION) {
+ FM_ERR_REPORT("Invalid Pilot Deviation = %02x",
+ ext_ctrl->controls->value);
+ break;
+ }
+
+ status = cg2900_fm_tx_set_pilot_deviation(
+ ext_ctrl->controls->value);
+
+ if (0 == status)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ {
+ u8 preemphasis;
+ FM_DEBUG_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_TUNE_PREEMPHASIS, "
+ "Value = %d",
+ ext_ctrl->controls->value);
+
+ if ((V4L2_PREEMPHASIS_50_uS >
+ ext_ctrl->controls->value) ||
+ (V4L2_PREEMPHASIS_75_uS <
+ ext_ctrl->controls->value)) {
+ FM_ERR_REPORT("Unsupported Preemphasis = %d",
+ ext_ctrl->controls->value);
+ break;
+ }
+
+ if (V4L2_PREEMPHASIS_50_uS ==
+ ext_ctrl->controls->value) {
+ preemphasis = FMD_EMPHASIS_50US;
+ } else if (V4L2_PREEMPHASIS_75_uS ==
+ ext_ctrl->controls->value) {
+ preemphasis = FMD_EMPHASIS_75US;
+ }
+
+ status = cg2900_fm_tx_set_preemphasis(preemphasis);
+
+ if (0 == status)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_TUNE_POWER_LEVEL:
+ {
+ FM_DEBUG_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_TUNE_POWER_LEVEL, "
+ "Value = %d",
+ ext_ctrl->controls->value);
+ if (ext_ctrl->controls->value < MIN_POWER_LEVEL &&
+ ext_ctrl->controls->value > MAX_POWER_LEVEL) {
+ FM_ERR_REPORT("Invalid Power Level = %02x",
+ ext_ctrl->controls->value);
+ break;
+ }
+
+ status = cg2900_fm_tx_set_power_level(
+ ext_ctrl->controls->value);
+
+ if (0 == status)
+ ret_val = 0;
+ break;
+ }
+ case V4L2_CID_CG2900_RADIO_BLOCKSCAN_START:
+ {
+ u32 start_freq;
+ u32 end_freq;
+ u32 *block_scan_buf;
+ u32 current_grid;
+ u32 low_freq;
+ u32 high_freq;
+ u32 result_freq;
+ u8 no_of_block_scan_channels;
+
+ /* V4L2 Initial check */
+ if (ext_ctrl->ctrl_class != V4L2_CTRL_CLASS_USER) {
+ FM_ERR_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_CG2900_RADIO_BLOCKSCAN_START "
+ "Unsupported ctrl_class = %04x",
+ ext_ctrl->ctrl_class);
+ break;
+ }
+
+ if (ext_ctrl->controls->size !=
+ FMR_BLOCK_SCAN_DATA_SIZE ||
+ ext_ctrl->controls->string == NULL) {
+ FM_ERR_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_CG2900_RADIO_BLOCKSCAN_START "
+ "Invalid Parameters");
+ break;
+ }
+
+ /* Check for current grid */
+ if (grid == CG2900_FM_GRID_50)
+ current_grid = FMR_CHINA_GRID_IN_HZ;
+ else if (grid == CG2900_FM_GRID_100)
+ current_grid = FMR_EUROPE_GRID_IN_HZ;
+ else
+ current_grid = FMR_USA_GRID_IN_HZ;
+
+ /* Check for current band */
+ if (band == CG2900_FM_BAND_US_EU) {
+ low_freq = FMR_EU_US_LOW_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ high_freq = FMR_EU_US_HIGH_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+
+ } else if (band == CG2900_FM_BAND_JAPAN) {
+ low_freq = FMR_JAPAN_LOW_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ high_freq = FMR_JAPAN_HIGH_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+
+ } else {
+ low_freq = FMR_CHINA_LOW_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ high_freq = FMR_CHINA_HIGH_FREQ_IN_MHZ *
+ FMR_HZ_TO_MHZ_CONVERTER;
+ }
+
+ /* V4L2 Extended control */
+
+ block_scan_buf = (u32 *)ext_ctrl->controls->string;
+ start_freq = V4L2_TO_HZ(*block_scan_buf);
+ end_freq = V4L2_TO_HZ(*(block_scan_buf + 1));
+
+ FM_DEBUG_REPORT("vidioc_set_ext_ctrls: "
+ "V4L2_CID_CG2900_RADIO_"
+ "BLOCKSCAN_START: "
+ "Start Freq = %d Hz "
+ "End Freq = %d Hz",
+ start_freq,
+ end_freq);
+
+ result_freq = end_freq - start_freq;
+ no_of_block_scan_channels =
+ (u8)(result_freq / current_grid);
+
+ /* Frequency Check */
+ if (end_freq < start_freq) {
+ FM_ERR_REPORT("Start Freq (%d Hz) "
+ " > End Freq (%d Hz)",
+ start_freq,
+ end_freq);
+ break;
+ }
+
+ if ((start_freq < low_freq) ||
+ (start_freq > high_freq)) {
+ FM_ERR_REPORT("Out of Band Freq: "
+ "Start Freq = %d Hz",
+ start_freq);
+ break;
+ }
+
+ if ((end_freq < low_freq) ||
+ (end_freq > high_freq)) {
+ FM_ERR_REPORT("Out of Band Freq: "
+ "End Freq = %d Hz",
+ end_freq);
+ break;
+ }
+
+ /* Maximum allowed block scan range */
+ if (FMR_MAX_BLOCK_SCAN_CHANNELS <
+ no_of_block_scan_channels) {
+ FM_ERR_REPORT("No of channels (%d)"
+ "exceeds Max Block Scan (%d)",
+ no_of_block_scan_channels,
+ FMR_MAX_BLOCK_SCAN_CHANNELS);
+ break;
+ }
+
+ status = cg2900_fm_start_block_scan(
+ start_freq,
+ end_freq);
+ if (0 == status) {
+ cg2900_device.seekstatus =
+ FMR_SEEK_IN_PROGRESS;
+ ret_val = 0;
+ }
+ break;
+ }
+ default:
+ {
+ FM_ERR_REPORT("vidioc_set_ext_ctrls: "
+ "Unsupported Id = %04x",
+ ext_ctrl->controls->id);
+ }
+ }
+error:
+ return ret_val;
+}
+
+/**
+ * vidioc_set_hw_freq_seek()- seek Up/Down Frequency.
+ *
+ * This function is used to start seek
+ * on the FM Radio. Direction if seek is as inicated by the parameter
+ * inside the v4l2_hw_freq_seek structure. This function is called when the
+ * application issues the IOCTL VIDIOC_S_HW_FREQ_SEEK
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @freq_seek: v4l2_hw_freq_seek structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_set_hw_freq_seek(
+ struct file *file,
+ void *priv,
+ struct v4l2_hw_freq_seek *freq_seek
+ )
+{
+ int status;
+ int ret_val = -EINVAL;
+
+ FM_INFO_REPORT("vidioc_set_hw_freq_seek");
+
+ FM_DEBUG_REPORT("vidioc_set_hw_freq_seek: Status = %d, "
+ "Upwards = %d, Wrap Around = %d",
+ cg2900_device.seekstatus,
+ freq_seek->seek_upward, freq_seek->wrap_around);
+
+ if (cg2900_device.seekstatus == FMR_SEEK_IN_PROGRESS) {
+ FM_ERR_REPORT("vidioc_set_hw_freq_seek: "
+ "VIDIOC_S_HW_FREQ_SEEK, "
+ "freq_seek in progress");
+ goto error;
+ }
+
+ spin_lock(&fm_spinlock);
+ fm_event = CG2900_EVENT_NO_EVENT;
+ no_of_scan_freq = 0;
+ spin_unlock(&fm_spinlock);
+
+ if (CG2900_DIR_UP == freq_seek->seek_upward)
+ status = cg2900_fm_search_up_freq();
+ else if (CG2900_DIR_DOWN == freq_seek->seek_upward)
+ status = cg2900_fm_search_down_freq();
+ else
+ goto error;
+
+ if (0 != status)
+ goto error;
+
+ cg2900_device.seekstatus = FMR_SEEK_IN_PROGRESS;
+ ret_val = 0;
+
+error:
+ FM_DEBUG_REPORT("vidioc_set_hw_freq_seek: returning = %d",
+ ret_val);
+ return ret_val;
+}
+
+/**
+ * vidioc_get_audio()- Get Audio features of FM Driver.
+ *
+ * This function is used to get the audio features of FM Driver.
+ * This function is imlemented as a dumy function.
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @audio: (out) v4l2_audio structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_get_audio(
+ struct file *file,
+ void *priv,
+ struct v4l2_audio *audio
+ )
+{
+ FM_INFO_REPORT("vidioc_get_audio");
+ strcpy(audio->name, "");
+ audio->capability = 0;
+ audio->mode = 0;
+ return 0;
+}
+
+/**
+ * vidioc_set_audio()- Set Audio features of FM Driver.
+ *
+ * This function is used to set the audio features of FM Driver.
+ * This function is imlemented as a dumy function.
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @audio: v4l2_audio structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_set_audio(
+ struct file *file,
+ void *priv,
+ struct v4l2_audio *audio
+ )
+{
+ FM_INFO_REPORT("vidioc_set_audio");
+ if (audio->index != 0)
+ return -EINVAL;
+ return 0;
+}
+
+/**
+ * vidioc_get_input()- Get the Input Value
+ *
+ * This function is used to get the Input.
+ * This function is imlemented as a dumy function.
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @input: (out) Value to be stored.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_get_input(
+ struct file *file,
+ void *priv,
+ unsigned int *input
+ )
+{
+ FM_INFO_REPORT("vidioc_get_input");
+ *input = 0;
+ return 0;
+}
+
+/**
+ * vidioc_set_input()- Set the input value.
+ *
+ * This function is used to set input.
+ * This function is imlemented as a dumy function.
+ *
+ * @file: File structure.
+ * @priv: Previous data of file structure.
+ * @input: Value to set
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int vidioc_set_input(
+ struct file *file,
+ void *priv,
+ unsigned int input
+ )
+{
+ FM_INFO_REPORT("vidioc_set_input");
+ if (input != 0)
+ return -EINVAL;
+ return 0;
+}
+
+/**
+ * cg2900_convert_err_to_v4l2()- Convert Error Bits to V4L2 RDS format.
+ *
+ * This function converts the error bits in RDS Block
+ * as received from Chip into V4L2 RDS data specification.
+ *
+ * @status_byte: The status byte as received in RDS Group for
+ * particular RDS Block
+ * @out_byte: byte to store the modified byte with the err bits
+ * alligned as per V4L2 RDS Specifications.
+ */
+static void cg2900_convert_err_to_v4l2(
+ char status_byte,
+ char *out_byte
+ )
+{
+ if ((status_byte & RDS_ERROR_STATUS_MASK) == RDS_ERROR_STATUS_MASK) {
+ /* Uncorrectable Block */
+ *out_byte = (*out_byte | V4L2_RDS_BLOCK_ERROR);
+ } else if (((status_byte & RDS_UPTO_TWO_BITS_CORRECTED)
+ == RDS_UPTO_TWO_BITS_CORRECTED) ||
+ ((status_byte & RDS_UPTO_FIVE_BITS_CORRECTED)
+ == RDS_UPTO_FIVE_BITS_CORRECTED)) {
+ /* Corrected Bits in Block */
+ *out_byte = (*out_byte | V4L2_RDS_BLOCK_CORRECTED);
+ }
+}
+
+/**
+ * cg2900_open()- This function nitializes and switches on FM.
+ *
+ * This is called when the application opens the character device.
+ *
+ * @file: File structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int cg2900_open(
+ struct file *file
+ )
+{
+ int status;
+ int ret_val = -EINVAL;
+ struct video_device *vdev = video_devdata(file);
+
+ lock_kernel();
+ users++;
+ FM_INFO_REPORT("cg2900_open: users = %d", users);
+
+ if (users > 1) {
+ FM_INFO_REPORT("cg2900_open: FM already switched on!!!");
+ ret_val = 0;
+ /*
+ * No need to perform the initialization and switch on FM
+ * since it is already done during the first open call to
+ * this driver.
+ */
+ goto done;
+ }
+
+ status = cg2900_fm_init();
+ if (0 != status)
+ goto init_error;
+
+ FM_DEBUG_REPORT("cg2900_open: Switching on FM");
+ status = cg2900_fm_switch_on(&(vdev->dev));
+ if (0 != status)
+ goto switch_on_error;
+
+ cg2900_device.state = FMR_SWITCH_ON;
+ cg2900_device.frequency = HZ_TO_V4L2(freq_low);
+ cg2900_device.rx_rds_enabled = false;
+ cg2900_device.muted = false;
+ cg2900_device.audiopath = 0;
+ cg2900_device.seekstatus = FMR_SEEK_NONE;
+ cg2900_device.rssi_threshold = CG2900_FM_DEFAULT_RSSI_THRESHOLD;
+ fm_event = CG2900_EVENT_NO_EVENT;
+ no_of_scan_freq = 0;
+ cg2900_device.fm_mode = CG2900_FM_IDLE_MODE;
+ ret_val = 0;
+ goto done;
+
+switch_on_error:
+ cg2900_fm_deinit();
+init_error:
+ users--;
+done:
+ unlock_kernel();
+ FM_DEBUG_REPORT("cg2900_open: returning %d", ret_val);
+ return ret_val;
+}
+
+/**
+ * cg2900_release()- This function switches off FM.
+ *
+ * This function switches off FM and releases the resources.
+ * This is called when the application closes the character
+ * device.
+ *
+ * @file: File structure.
+ *
+ * Returns:
+ * 0 when no error
+ * -EINVAL: otherwise
+ */
+static int cg2900_release(
+ struct file *file
+ )
+{
+ int status;
+ int ret_val = -EINVAL;
+
+ mutex_lock(&fm_mutex);
+
+ FM_INFO_REPORT("cg2900_release");
+ if (users <= 0) {
+ FM_ERR_REPORT("cg2900_release: No users registered "
+ "with FM Driver");
+ goto done;
+ }
+
+ users--;
+ FM_INFO_REPORT("cg2900_release: users = %d", users);
+
+ if (0 == users) {
+ FM_DEBUG_REPORT("cg2900_release: Switching Off FM");
+ status = cg2900_fm_switch_off();
+ status = cg2900_fm_deinit();
+ if (0 != status)
+ goto done;
+
+ cg2900_device.state = FMR_SWITCH_OFF;
+ cg2900_device.frequency = 0;
+ cg2900_device.rx_rds_enabled = false;
+ cg2900_device.muted = false;
+ cg2900_device.seekstatus = FMR_SEEK_NONE;
+ fm_event = CG2900_EVENT_NO_EVENT;
+ no_of_scan_freq = 0;
+ }
+ ret_val = 0;
+
+done:
+ mutex_unlock(&fm_mutex);
+ FM_DEBUG_REPORT("cg2900_release: returning %d", ret_val);
+ return ret_val;
+}
+
+/**
+ * cg2900_read()- This function is invoked when the application
+ * calls read() to receive RDS Data.
+ *
+ * @file: File structure.
+ * @data: buffer provided by application for receving the data.
+ * @count: Number of bytes that application wants to read from driver
+ * @pos: offset
+ *
+ * Returns:
+ * Number of bytes copied to the user buffer
+ * -EFAULT: If there is problem in copying data to buffer supplied
+ * by application
+ * -EIO: If the number of bytes to be read are not a multiple of
+ * struct v4l2_rds_data.
+ * -EAGAIN: More than 22 blocks requested to be read or read
+ * was called in non blocking mode and no data was available for reading.
+ * -EINTR: If read was interrupted by a signal before data was avaialble.
+ * 0 when no data available for reading.
+ */
+static ssize_t cg2900_read(
+ struct file *file,
+ char __user *data,
+ size_t count, loff_t *pos
+ )
+{
+ int current_rds_grp;
+ int index = 0;
+ int blocks_to_read;
+ int ret;
+ struct v4l2_rds_data rdsbuf[MAX_RDS_GROUPS * NUM_OF_RDS_BLOCKS];
+ struct v4l2_rds_data *rdslocalbuf = rdsbuf;
+
+ FM_INFO_REPORT("cg2900_read");
+
+ blocks_to_read = (count / sizeof(struct v4l2_rds_data));
+
+ if (!cg2900_device.rx_rds_enabled) {
+ FM_INFO_REPORT("cg2900_read: returning 0");
+ return 0;
+ }
+
+ if (count % sizeof(struct v4l2_rds_data) != 0) {
+ FM_ERR_REPORT("cg2900_read: Invalid Number of bytes %d "
+ "requested to read", count);
+ return -EIO;
+ }
+
+ if (blocks_to_read > MAX_RDS_GROUPS * NUM_OF_RDS_BLOCKS) {
+ FM_ERR_REPORT("cg2900_read: Too many blocks(%d) "
+ "requested to be read", blocks_to_read);
+ return -EAGAIN;
+ }
+
+ if (file->f_flags & O_NONBLOCK) {
+ /* Non blocking mode selected by application */
+ if (fm_rds_info.rds_head == fm_rds_info.rds_tail) {
+ FM_DEBUG_REPORT("cg2900_read: Non Blocking mode "
+ "selected by application, returning as "
+ "no RDS data is available");
+ return -EAGAIN;
+ }
+ }
+
+ if (fm_rds_info.rds_head == fm_rds_info.rds_tail) {
+ /*
+ * Blocking mode selected by application
+ * if data is not available block on read queue
+ */
+ FM_DEBUG_REPORT("cg2900_read: Blocking mode "
+ "selected by application, waiting till "
+ "rds data is available");
+ cg2900_device.wait_on_read_queue = true;
+ ret = wait_event_interruptible(cg2900_read_queue,
+ (fm_rds_info.rds_head !=
+ fm_rds_info.rds_tail));
+ cg2900_device.wait_on_read_queue = false;
+ FM_DEBUG_REPORT("cg2900_read: "
+ "wait_event_interruptible returned = %d", ret);
+ if (ret == -ERESTARTSYS)
+ return -EINTR;
+ }
+
+ /*
+ * Check again that in the meantime RDS is not disabled
+ * by the user, If yes, return.
+ */
+ if (!cg2900_device.rx_rds_enabled) {
+ FM_INFO_REPORT("cg2900_read: returning 0");
+ return 0;
+ }
+
+ current_rds_grp = fm_rds_info.rds_group_sent;
+
+ if ((fm_rds_info.rds_head == fm_rds_info.rds_tail) ||
+ (fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].block1 == 0x0000)) {
+ FM_INFO_REPORT("cg2900_read: returning 0");
+ return 0;
+ }
+
+ spin_lock(&fm_spinlock);
+ while (index < blocks_to_read) {
+ /* Check which Block needs to be transferred next */
+ switch (fm_rds_info.rds_block_sent % NUM_OF_RDS_BLOCKS) {
+ case 0:
+ (rdslocalbuf + index)->lsb =
+ fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].block1;
+ (rdslocalbuf + index)->msb =
+ fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].block1 >> 8;
+ (rdslocalbuf + index)->block =
+ (fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].status1
+ & RDS_BLOCK_MASK) >> 2;
+ cg2900_convert_err_to_v4l2(
+ fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].status1,
+ &(rdslocalbuf + index)->block);
+ break;
+ case 1:
+ (rdslocalbuf + index)->lsb =
+ fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].block2;
+ (rdslocalbuf + index)->msb =
+ fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].block2 >> 8;
+ (rdslocalbuf + index)->block =
+ (fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].status2
+ & RDS_BLOCK_MASK) >> 2;
+ cg2900_convert_err_to_v4l2(
+ fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].status2,
+ &(rdslocalbuf + index)->block);
+ break;
+ case 2:
+ (rdslocalbuf + index)->lsb =
+ fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].block3;
+ (rdslocalbuf + index)->msb =
+ fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].block3 >> 8;
+ (rdslocalbuf + index)->block =
+ (fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].status3
+ & RDS_BLOCK_MASK) >> 2;
+ cg2900_convert_err_to_v4l2(
+ fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].status3,
+ &(rdslocalbuf + index)->block);
+ break;
+ case 3:
+ (rdslocalbuf + index)->lsb =
+ fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].block4;
+ (rdslocalbuf + index)->msb =
+ fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].block4 >> 8;
+ (rdslocalbuf + index)->block =
+ (fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].status4
+ & RDS_BLOCK_MASK) >> 2;
+ cg2900_convert_err_to_v4l2(
+ fm_rds_buf[fm_rds_info.rds_tail]
+ [current_rds_grp].status4,
+ &(rdslocalbuf + index)->block);
+ current_rds_grp++;
+ if (current_rds_grp == MAX_RDS_GROUPS) {
+ fm_rds_info.rds_tail++;
+ current_rds_grp = 0;
+ }
+ break;
+ default:
+ FM_ERR_REPORT("Invalid RDS Group!!!");
+ spin_unlock(&fm_spinlock);
+ return 0;
+ }
+ index++;
+ fm_rds_info.rds_block_sent++;
+ if (fm_rds_info.rds_block_sent == NUM_OF_RDS_BLOCKS)
+ fm_rds_info.rds_block_sent = 0;
+
+ if (!cg2900_device.rx_rds_enabled) {
+ FM_INFO_REPORT("cg2900_read: returning 0");
+ spin_unlock(&fm_spinlock);
+ return 0;
+ }
+ }
+ /* Update the RDS Group Count Sent to Application */
+ fm_rds_info.rds_group_sent = current_rds_grp;
+ if (fm_rds_info.rds_tail == MAX_RDS_BUFFER)
+ fm_rds_info.rds_tail = 0;
+
+ if (copy_to_user(data, rdslocalbuf, count)) {
+ spin_unlock(&fm_spinlock);
+ FM_ERR_REPORT("cg2900_read: Error "
+ "in copying, returning");
+ return -EFAULT;
+ }
+ spin_unlock(&fm_spinlock);
+ return count;
+}
+
+/**
+ * cg2900_poll()- Check if the operation is complete or not.
+ *
+ * This function is invoked by application on calling poll() and is used to
+ * wait till the desired operation seek/Band Scan are complete.
+ * Driver blocks till the seek/BandScan Operation is complete. The application
+ * decides to read the results of seek/Band Scan based on the returned value of
+ * this function.
+ *
+ * @file: File structure.
+ * @wait: poll table
+ *
+ * Returns:
+ * POLLRDNORM when Scan Band/Block Scan/Seek station is complete.
+ * POLLHUP when seek station/Band Scan is stopped by user using Stop Scan.
+ */
+static unsigned int cg2900_poll(
+ struct file *file,
+ struct poll_table_struct *wait
+ )
+{
+ int ret_val = 0;
+
+ FM_INFO_REPORT("cg2900_poll");
+
+ poll_wait(file, &cg2900_poll_queue, wait);
+
+ if (cg2900_device.seekstatus == FMR_SEEK_IN_PROGRESS &&
+ ((fm_event == CG2900_EVENT_SCAN_CHANNELS_FOUND) ||
+ (fm_event == CG2900_EVENT_BLOCK_SCAN_CHANNELS_FOUND) ||
+ (fm_event == CG2900_EVENT_SEARCH_CHANNEL_FOUND))) {
+ /* Scan Completed, send event to application */
+ FM_DEBUG_REPORT("poll_wait returning POLLRDNORM");
+ ret_val = POLLRDNORM;
+ goto done;
+ }
+
+ if (fm_event == CG2900_EVENT_SCAN_CANCELLED) {
+ /* Scan/Search cancelled by User */
+ spin_lock(&fm_spinlock);
+ no_of_scan_freq = 0;
+ no_of_block_scan_freq = 0;
+ spin_unlock(&fm_spinlock);
+ cg2900_device.seekstatus = FMR_SEEK_NONE;
+ fm_event = CG2900_EVENT_NO_EVENT;
+ FM_DEBUG_REPORT("cg2900_poll: Cancel operation "
+ "returning POLLHUP");
+ FM_DEBUG_REPORT("poll_wait returning POLLHUP");
+ ret_val = POLLHUP;
+ goto done;
+ }
+
+done:
+ FM_DEBUG_REPORT("poll_wait returning %d", ret_val);
+ return ret_val;
+}
+
+/**
+ * cg2900_init()- This function initializes the FM Driver.
+ *
+ * This Fucntion is called whenever the Driver is loaded from
+ * Video4Linux driver. It registers the FM Driver with Video4Linux
+ * as a character device.
+ *
+ * Returns:
+ * 0 on success
+ * -EINVAL on error
+ */
+static int __init cg2900_init(void)
+{
+ FM_INFO_REPORT(BANNER);
+ radio_nr = 0;
+ grid = CG2900_FM_GRID_100;
+ band = CG2900_FM_BAND_US_EU;
+ FM_INFO_REPORT("cg2900_init: radio_nr= %d.", radio_nr);
+ /* Initialize the parameters */
+ if (video_register_device(
+ &cg2900_video_device,
+ VFL_TYPE_RADIO,
+ radio_nr) == -1) {
+ FM_ERR_REPORT("cg2900_init: video_register_device err");
+ return -EINVAL;
+ }
+ mutex_init(&fm_mutex);
+ spin_lock_init(&fm_spinlock);
+ init_waitqueue_head(&cg2900_poll_queue);
+ users = 0;
+ return 0;
+}
+
+/**
+ * cg2900_exit()- This function exits the FM Driver.
+ *
+ * This function is called whenever the Driver is unloaded from
+ * VideoForLinux driver.
+ */
+static void __exit cg2900_exit(void)
+{
+ FM_INFO_REPORT("cg2900_exit");
+
+ /* Try to Switch Off FM in case it is still switched on */
+ cg2900_fm_switch_off();
+ cg2900_fm_deinit();
+ mutex_destroy(&fm_mutex);
+ video_unregister_device(&cg2900_video_device);
+}
+
+void wake_up_poll_queue(void)
+{
+ FM_INFO_REPORT("wake_up_poll_queue");
+ wake_up_interruptible(&cg2900_poll_queue);
+}
+
+void wake_up_read_queue(void)
+{
+ FM_INFO_REPORT("wake_up_read_queue");
+ if (cg2900_device.wait_on_read_queue)
+ wake_up_interruptible(&cg2900_read_queue);
+}
+
+void cg2900_handle_device_reset(void)
+{
+ FM_INFO_REPORT("cg2900_handle_device_reset");
+ mutex_lock(&fm_mutex);
+ users = 0;
+ cg2900_device.state = FMR_SWITCH_OFF;
+ cg2900_device.frequency = 0;
+ cg2900_device.rx_rds_enabled = false;
+ cg2900_device.muted = false;
+ cg2900_device.seekstatus = FMR_SEEK_NONE;
+ fm_event = CG2900_EVENT_NO_EVENT;
+ no_of_scan_freq = 0;
+ mutex_unlock(&fm_mutex);
+}
+
+module_init(cg2900_init);
+module_exit(cg2900_exit);
+MODULE_AUTHOR("Hemant Gupta");
+MODULE_LICENSE("GPL v2");
+
+module_param(radio_nr, int, S_IRUGO);
+
+module_param(grid, int, S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(grid, "Grid:"
+ "0=50 kHz"
+ "*1=100 kHz*"
+ "2=200 kHz");
+
+module_param(band, int, S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(band, "Band:"
+ "*0=87.5-108 MHz*"
+ "1=76-90 MHz"
+ "2=70-108 MHz");
+
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 83567b898d0..06ad0d3e1dc 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -452,4 +452,20 @@ config RADIO_TIMBERDALE
found behind the Timberdale FPGA on the Russellville board.
Enabling this driver will automatically select the DSP and tuner.
+config RADIO_CG2900
+ tristate "ST-Ericsson CG2900 FM Radio support"
+ depends on MFD_CG2900 && VIDEO_V4L2
+ ---help---
+ Choose Y here if you have one of these FM radio cards. This is a BT,
+ FM and GPS combo chip controlled via HCI.
+
+ In order to control your radio card, you will need to use programs
+ that are compatible with the Video For Linux API. Information on
+ this API and pointers to "v4l" programs may be found at
+ <file:Documentation/video4linux/API.html>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-CG2900.
+
+
endif # RADIO_ADAPTERS
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index f615583b483..2ce9398ddcf 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -26,5 +26,6 @@ obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
+obj-$(CONFIG_RADIO_CG2900) += CG2900/
EXTRA_CFLAGS += -Isound
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 9da0e504bbe..f0cef862ef8 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -177,6 +177,29 @@ config TWL4030_CODEC
select MFD_CORE
default n
+config MFD_STMPE
+ bool "Support STMicroelectronics STMPE"
+ depends on I2C=y && GENERIC_HARDIRQS
+ select MFD_CORE
+ help
+ Support for the STMPE family of I/O Expanders from
+ STMicroelectronics.
+
+ Currently supported devices are:
+
+ STMPE811: GPIO, Touchscreen
+ STMPE1601: GPIO, Keypad
+ STMPE2401: GPIO, Keypad
+ STMPE2403: GPIO, Keypad
+
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the functionality
+ of the device. Currently available sub drivers are:
+
+ GPIO: stmpe-gpio
+ Keypad: stmpe-keypad
+ Touchscreen: stmpe-ts
+
config MFD_TC35892
bool "Support Toshiba TC35892"
depends on I2C=y && GENERIC_HARDIRQS
@@ -213,6 +236,31 @@ config MFD_TC6387XB
help
Support for Toshiba Mobile IO Controller TC6387XB
+config MFD_CG2900
+ tristate "Support ST-Ericsson CG2900 main structure"
+ help
+ Support for ST-Ericsson CG2900 Connectivity Combo controller main structure.
+ Supports multiple functionalities muxed over a Bluetooth HCI H:4 interface.
+ CG2900 support Bluetooth, FM radio, and GPS.
+
+config MFD_CG2900_CHIP
+ tristate "Support CG2900 Connectivity controller"
+ depends on MFD_CG2900
+ help
+ Support for ST-Ericsson CG2900 Connectivity Controller
+
+config MFD_STLC2690_CHIP
+ tristate "Support ST-Ericsson STLC2690 Connectivity controller"
+ depends on MFD_CG2900
+ help
+ Support for ST-Ericsson STLC2690 Connectivity Controller
+
+config MFD_CG2900_AUDIO
+ tristate "Support ST-Ericsson CG2900 audio interface"
+ depends on MFD_CG2900
+ help
+ Support for ST-Ericsson CG2900 Connectivity audio interface
+
config MFD_TC6393XB
bool "Support Toshiba TC6393XB"
depends on GPIOLIB && ARM
@@ -221,6 +269,20 @@ config MFD_TC6393XB
help
Support for Toshiba Mobile IO Controller TC6393XB
+config AB5500_CORE
+ bool "ST-Ericsson AB5500 Mixed Signal Circuit core functions"
+ select MFD_CORE
+ depends on GENERIC_HARDIRQS && ABX500_CORE
+ help
+ Select this to enable the AB5500 Mixed Signal IC core
+ functionality. This connects to a AB5500 chip on the I2C bus via
+ the Power and Reset Management Unit (PRCMU). It exposes a number
+ of symbols needed for dependent devices to read and write
+ registers and subscribe to events from this multi-functional IC.
+ This is needed to use other features of the AB5500 such as
+ battery-backed RTC, charging control, Regulators, LEDs, vibrator,
+ system power and temperature, power management and ALSA sound.
+
config PMIC_DA903X
bool "Dialog Semiconductor DA9030/DA9034 PMIC Support"
depends on I2C=y
@@ -382,7 +444,7 @@ config PCF50633_GPIO
config ABX500_CORE
bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
- default y if ARCH_U300
+ default y if ARCH_U300 || ARCH_U8500
help
Say yes here if you have the ABX500 Mixed Signal IC family
chips. This core driver expose register access functions.
@@ -393,6 +455,7 @@ config ABX500_CORE
config AB3100_CORE
bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
depends on I2C=y && ABX500_CORE
+ select MFD_CORE
default y if ARCH_U300
help
Select this to enable the AB3100 Mixed Signal IC core
@@ -422,14 +485,33 @@ config EZX_PCAP
config AB8500_CORE
bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
- depends on SPI=y && GENERIC_HARDIRQS
+ depends on GENERIC_HARDIRQS && ABX500_CORE && SPI_MASTER && ARCH_U8500
select MFD_CORE
help
Select this option to enable access to AB8500 power management
- chip. This connects to U8500 on the SSP/SPI bus and exports
- read/write functions for the devices to get access to this chip.
+ chip. This connects to U8500 either on the SSP/SPI bus
+ or the I2C bus via PRCMU. It also adds the irq_chip
+ parts for handling the Mixed Signal chip events.
This chip embeds various other multimedia funtionalities as well.
+config AB8500_I2C_CORE
+ bool "AB8500 register access via PRCMU I2C"
+ depends on AB8500_CORE && UX500_SOC_DB8500
+ default y
+ help
+ This enables register access to the AB8500 chip via PRCMU I2C.
+ The AB8500 chip can be accessed via SPI or I2C. On DB8500 hardware
+ the I2C bus is connected to the Power Reset
+ and Mangagement Unit, PRCMU.
+
+config AB8500_DEBUG
+ bool "Enable debug info via debugfs"
+ depends on AB8500_CORE && DEBUG_FS
+ default y if DEBUG_FS
+ help
+ Select this option if you want debug information using the debug
+ filesystem, debugfs.
+
config AB3550_CORE
bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions"
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index fb503e77dc6..c1b532b41f6 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -2,6 +2,7 @@
# Makefile for multifunction miscellaneous devices
#
+obj-$(CONFIG_AB5500_CORE) += ab5500-core.o
88pm860x-objs := 88pm860x-core.o 88pm860x-i2c.o
obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o
obj-$(CONFIG_MFD_SM501) += sm501.o
@@ -15,6 +16,7 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
+obj-$(CONFIG_MFD_STMPE) += stmpe.o
obj-$(CONFIG_MFD_TC35892) += tc35892.o
obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
@@ -51,6 +53,7 @@ obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o
ifeq ($(CONFIG_SA1100_ASSABET),y)
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o
endif
+obj-y += cg2900/
obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o
obj-$(CONFIG_PMIC_DA903X) += da903x.o
@@ -65,7 +68,9 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB3550_CORE) += ab3550-core.o
-obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o
+obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o ab8500-sysctrl.o
+obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
+obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
obj-$(CONFIG_LPC_SCH) += lpc_sch.o
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
index 66379b41390..8e84e783c9e 100644
--- a/drivers/mfd/ab3100-core.c
+++ b/drivers/mfd/ab3100-core.c
@@ -19,6 +19,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
+#include <linux/mfd/core.h>
#include <linux/mfd/abx500.h>
/* These are the only registers inside AB3100 used in this main file */
@@ -146,7 +147,7 @@ static int ab3100_set_test_register_interruptible(struct ab3100 *ab3100,
}
static int ab3100_get_register_interruptible(struct ab3100 *ab3100,
- u8 reg, u8 *regval)
+ u8 reg, u8 *regval)
{
int err;
@@ -202,7 +203,7 @@ static int ab3100_get_register_interruptible(struct ab3100 *ab3100,
}
static int get_register_interruptible(struct device *dev, u8 bank, u8 reg,
- u8 *value)
+ u8 *value)
{
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
@@ -665,7 +666,7 @@ struct ab3100_init_setting {
u8 setting;
};
-static const struct ab3100_init_setting __initconst
+static const struct ab3100_init_setting __devinitconst
ab3100_init_settings[] = {
{
.abreg = AB3100_MCA,
@@ -712,7 +713,7 @@ ab3100_init_settings[] = {
},
};
-static int __init ab3100_setup(struct ab3100 *ab3100)
+static int __devinit ab3100_setup(struct ab3100 *ab3100)
{
int err = 0;
int i;
@@ -742,52 +743,64 @@ static int __init ab3100_setup(struct ab3100 *ab3100)
return err;
}
-/*
- * Here we define all the platform devices that appear
- * as children of the AB3100. These are regular platform
- * devices with the IORESOURCE_IO .start and .end set
- * to correspond to the internal AB3100 register range
- * mapping to the corresponding subdevice.
- */
-
-#define AB3100_DEVICE(devname, devid) \
-static struct platform_device ab3100_##devname##_device = { \
- .name = devid, \
- .id = -1, \
-}
-
-/* This lists all the subdevices */
-AB3100_DEVICE(dac, "ab3100-dac");
-AB3100_DEVICE(leds, "ab3100-leds");
-AB3100_DEVICE(power, "ab3100-power");
-AB3100_DEVICE(regulators, "ab3100-regulators");
-AB3100_DEVICE(sim, "ab3100-sim");
-AB3100_DEVICE(uart, "ab3100-uart");
-AB3100_DEVICE(rtc, "ab3100-rtc");
-AB3100_DEVICE(charger, "ab3100-charger");
-AB3100_DEVICE(boost, "ab3100-boost");
-AB3100_DEVICE(adc, "ab3100-adc");
-AB3100_DEVICE(fuelgauge, "ab3100-fuelgauge");
-AB3100_DEVICE(vibrator, "ab3100-vibrator");
-AB3100_DEVICE(otp, "ab3100-otp");
-AB3100_DEVICE(codec, "ab3100-codec");
-
-static struct platform_device *
-ab3100_platform_devs[] = {
- &ab3100_dac_device,
- &ab3100_leds_device,
- &ab3100_power_device,
- &ab3100_regulators_device,
- &ab3100_sim_device,
- &ab3100_uart_device,
- &ab3100_rtc_device,
- &ab3100_charger_device,
- &ab3100_boost_device,
- &ab3100_adc_device,
- &ab3100_fuelgauge_device,
- &ab3100_vibrator_device,
- &ab3100_otp_device,
- &ab3100_codec_device,
+/* The subdevices of the AB3100 */
+static struct mfd_cell ab3100_devs[] = {
+ {
+ .name = "ab3100-dac",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-leds",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-power",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-regulators",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-sim",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-uart",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-rtc",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-charger",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-boost",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-adc",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-fuelgauge",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-vibrator",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-otp",
+ .id = -1,
+ },
+ {
+ .name = "ab3100-codec",
+ .id = -1,
+ },
};
struct ab_family_id {
@@ -795,7 +808,7 @@ struct ab_family_id {
char *name;
};
-static const struct ab_family_id ids[] __initdata = {
+static const struct ab_family_id ids[] __devinitdata = {
/* AB3100 */
{
.id = 0xc0,
@@ -849,8 +862,8 @@ static const struct ab_family_id ids[] __initdata = {
},
};
-static int __init ab3100_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int __devinit ab3100_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct ab3100 *ab3100;
struct ab3100_platform_data *ab3100_plf_data =
@@ -934,18 +947,14 @@ static int __init ab3100_probe(struct i2c_client *client,
if (err)
goto exit_no_ops;
- /* Set parent and a pointer back to the container in device data */
- for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++) {
- ab3100_platform_devs[i]->dev.parent =
- &client->dev;
- ab3100_platform_devs[i]->dev.platform_data =
- ab3100_plf_data;
- platform_set_drvdata(ab3100_platform_devs[i], ab3100);
+ /* Set up and register the platform devices. */
+ for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) {
+ ab3100_devs[i].platform_data = ab3100_plf_data;
+ ab3100_devs[i].data_size = sizeof(struct ab3100_platform_data);
}
- /* Register the platform devices */
- platform_add_devices(ab3100_platform_devs,
- ARRAY_SIZE(ab3100_platform_devs));
+ err = mfd_add_devices(&client->dev, 0, ab3100_devs,
+ ARRAY_SIZE(ab3100_devs), NULL, 0);
ab3100_setup_debugfs(ab3100);
@@ -961,14 +970,12 @@ static int __init ab3100_probe(struct i2c_client *client,
return err;
}
-static int __exit ab3100_remove(struct i2c_client *client)
+static int __devexit ab3100_remove(struct i2c_client *client)
{
struct ab3100 *ab3100 = i2c_get_clientdata(client);
- int i;
/* Unregister subdevices */
- for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++)
- platform_device_unregister(ab3100_platform_devs[i]);
+ mfd_remove_devices(&client->dev);
ab3100_remove_debugfs();
i2c_unregister_device(ab3100->testreg_client);
@@ -995,7 +1002,7 @@ static struct i2c_driver ab3100_driver = {
},
.id_table = ab3100_id,
.probe = ab3100_probe,
- .remove = __exit_p(ab3100_remove),
+ .remove = __devexit_p(ab3100_remove),
};
static int __init ab3100_i2c_init(void)
diff --git a/drivers/mfd/ab3100-otp.c b/drivers/mfd/ab3100-otp.c
index 63d2b727ddb..8440010eb2b 100644
--- a/drivers/mfd/ab3100-otp.c
+++ b/drivers/mfd/ab3100-otp.c
@@ -199,7 +199,7 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
err = ab3100_otp_read(otp);
if (err)
- return err;
+ goto err_otp_read;
dev_info(&pdev->dev, "AB3100 OTP readout registered\n");
@@ -208,21 +208,21 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
err = device_create_file(&pdev->dev,
&ab3100_otp_attrs[i]);
if (err)
- goto out_no_sysfs;
+ goto err_create_file;
}
/* debugfs entries */
err = ab3100_otp_init_debugfs(&pdev->dev, otp);
if (err)
- goto out_no_debugfs;
+ goto err_init_debugfs;
return 0;
-out_no_sysfs:
- for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++)
- device_remove_file(&pdev->dev,
- &ab3100_otp_attrs[i]);
-out_no_debugfs:
+err_init_debugfs:
+err_create_file:
+ while (--i >= 0)
+ device_remove_file(&pdev->dev, &ab3100_otp_attrs[i]);
+err_otp_read:
kfree(otp);
return err;
}
diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c
index f54ab62e7bc..8a98739e6d9 100644
--- a/drivers/mfd/ab3550-core.c
+++ b/drivers/mfd/ab3550-core.c
@@ -589,16 +589,16 @@ static bool reg_read_allowed(const struct ab3550_reg_ranges *ranges, u8 reg)
}
/*
- * The exported register access functionality.
+ * The register access functionality.
*/
-int ab3550_get_chip_id(struct device *dev)
+static int ab3550_get_chip_id(struct device *dev)
{
struct ab3550 *ab = dev_get_drvdata(dev->parent);
return (int)ab->chip_id;
}
-int ab3550_mask_and_set_register_interruptible(struct device *dev, u8 bank,
- u8 reg, u8 bitmask, u8 bitvalues)
+static int ab3550_mask_and_set_register_interruptible(struct device *dev,
+ u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
{
struct ab3550 *ab;
struct platform_device *pdev = to_platform_device(dev);
@@ -612,15 +612,15 @@ int ab3550_mask_and_set_register_interruptible(struct device *dev, u8 bank,
bitmask, bitvalues);
}
-int ab3550_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
- u8 value)
+static int ab3550_set_register_interruptible(struct device *dev, u8 bank,
+ u8 reg, u8 value)
{
return ab3550_mask_and_set_register_interruptible(dev, bank, reg, 0xFF,
value);
}
-int ab3550_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
- u8 *value)
+static int ab3550_get_register_interruptible(struct device *dev, u8 bank,
+ u8 reg, u8 *value)
{
struct ab3550 *ab;
struct platform_device *pdev = to_platform_device(dev);
@@ -633,7 +633,7 @@ int ab3550_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
return get_register_interruptible(ab, bank, reg, value);
}
-int ab3550_get_register_page_interruptible(struct device *dev, u8 bank,
+static int ab3550_get_register_page_interruptible(struct device *dev, u8 bank,
u8 first_reg, u8 *regvals, u8 numregs)
{
struct ab3550 *ab;
@@ -649,7 +649,8 @@ int ab3550_get_register_page_interruptible(struct device *dev, u8 bank,
numregs);
}
-int ab3550_event_registers_startup_state_get(struct device *dev, u8 *event)
+static int ab3550_event_registers_startup_state_get(struct device *dev,
+ u8 *event)
{
struct ab3550 *ab;
@@ -661,7 +662,7 @@ int ab3550_event_registers_startup_state_get(struct device *dev, u8 *event)
return 0;
}
-int ab3550_startup_irq_enabled(struct device *dev, unsigned int irq)
+static int ab3550_startup_irq_enabled(struct device *dev, unsigned int irq)
{
struct ab3550 *ab;
struct ab3550_platform_data *plf_data;
diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c
new file mode 100755
index 00000000000..b3131768eb6
--- /dev/null
+++ b/drivers/mfd/ab5500-core.c
@@ -0,0 +1,2157 @@
+/*
+ * Copyright (C) 2007-2010 ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ * Low-level core for exclusive access to the AB5500 IC on the I2C bus
+ * and some basic chip-configuration.
+ * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
+ * Author: Mattias Wallin <mattias.wallin@stericsson.com>
+ * Author: Rickard Andersson <rickard.andersson@stericsson.com>
+ * Author: Karl Komierowski <karl.komierowski@stericsson.com>
+ */
+
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/random.h>
+#include <linux/workqueue.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/mfd/abx500.h>
+#include <linux/list.h>
+#include <linux/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/mfd/core.h>
+#include <linux/version.h>
+#include <mach/prcmu-db5500.h>
+
+#define AB5500_NAME_STRING "ab5500"
+#define AB5500_ID_FORMAT_STRING "AB5500 %s"
+#define AB5500_NUM_EVENT_REG 23
+
+/* These are the only registers inside AB5500 used in this main file */
+
+/* Read/write operation values. */
+#define AB5500_PERM_RD (0x01)
+#define AB5500_PERM_WR (0x02)
+
+/* Read/write permissions. */
+#define AB5500_PERM_RO (AB5500_PERM_RD)
+#define AB5500_PERM_RW (AB5500_PERM_RD | AB5500_PERM_WR)
+
+#define AB5500_MASK_BASE (0x60)
+#define AB5500_MASK_END (0x79)
+#define AB5500_CHIP_ID (0x20)
+
+/**
+ * struct ab5500
+ * @access_mutex: lock out concurrent accesses to the AB registers
+ * @dev: a pointer to the device struct for this chip driver
+ * @ab5500_irq: the analog baseband irq
+ * @irq_base: the platform configuration irq base for subdevices
+ * @chip_name: name of this chip variant
+ * @chip_id: 8 bit chip ID for this chip variant
+ * @mask_work: a worker for writing to mask registers
+ * @event_lock: a lock to protect the event_mask
+ * @abb_events: a local bit mask of the prcmu wakeup events
+ * @event_mask: a local copy of the mask event registers
+ * @last_event_mask: a copy of the last event_mask written to hardware
+ * @startup_events: a copy of the first reading of the event registers
+ * @startup_events_read: whether the first events have been read
+ */
+struct ab5500 {
+ struct mutex access_mutex;
+ struct device *dev;
+ unsigned int ab5500_irq;
+ unsigned int irq_base;
+ char chip_name[32];
+ u8 chip_id;
+ struct work_struct mask_work;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
+ struct work_struct irq_work;
+#endif
+ spinlock_t event_lock;
+ u32 abb_events;
+ u8 event_mask[AB5500_NUM_EVENT_REG];
+ u8 last_event_mask[AB5500_NUM_EVENT_REG];
+ u8 startup_events[AB5500_NUM_EVENT_REG];
+ bool startup_events_read;
+#ifdef CONFIG_DEBUG_FS
+ unsigned int debug_bank;
+ unsigned int debug_address;
+#endif
+};
+
+/**
+ * struct ab5500_bank
+ * @slave_addr: I2C slave_addr found in AB5500 specification
+ * @name: Documentation name of the bank. For reference
+ */
+struct ab5500_bank {
+ u8 slave_addr;
+ const char *name;
+};
+
+static const struct ab5500_bank bankinfo[AB5500_NUM_BANKS] = {
+ [AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP] = {0x4A, "VIT_IO_I2C_CLK_TST_OTP"},
+ [AB5500_BANK_VDDDIG_IO_I2C_CLK_TST] = {0x4B, "VDDDIG_IO_I2C_CLK_TST"},
+ [AB5500_BANK_VDENC] = {0x06, "VDENC"},
+ [AB5500_BANK_SIM_USBSIM] = {0x04, "SIM_USBSIM"},
+ [AB5500_BANK_LED] = {0x10, "LED"},
+ [AB5500_BANK_ADC] = {0x0A, "ADC"},
+ [AB5500_BANK_RTC] = {0x0F, "RTC"},
+ [AB5500_BANK_STARTUP] = {0x03, "STARTUP"},
+ [AB5500_BANK_DBI_ECI] = {0x07, "DBI-ECI"},
+ [AB5500_BANK_CHG] = {0x0B, "CHG"},
+ [AB5500_BANK_FG_BATTCOM_ACC] = {0x0C, "FG_BATCOM_ACC"},
+ [AB5500_BANK_USB] = {0x05, "USB"},
+ [AB5500_BANK_IT] = {0x0E, "IT"},
+ [AB5500_BANK_VIBRA] = {0x02, "VIBRA"},
+ [AB5500_BANK_AUDIO_HEADSETUSB] = {0x0D, "AUDIO_HEADSETUSB"},
+};
+
+/**
+ * struct ab5500_reg_range
+ * @first: the first address of the range
+ * @last: the last address of the range
+ * @perm: access permissions for the range
+ */
+struct ab5500_reg_range {
+ u8 first;
+ u8 last;
+ u8 perm;
+};
+
+/**
+ * struct ab5500_i2c_ranges
+ * @count: the number of ranges in the list
+ * @range: the list of register ranges
+ */
+struct ab5500_i2c_ranges {
+ u8 nranges;
+ u8 bankid;
+ const struct ab5500_reg_range *range;
+};
+
+/**
+ * struct ab5500_i2c_banks
+ * @count: the number of ranges in the list
+ * @range: the list of register ranges
+ */
+struct ab5500_i2c_banks {
+ u8 nbanks;
+ const struct ab5500_i2c_ranges *bank;
+};
+
+/*
+ * Permissible register ranges for reading and writing per device and bank.
+ *
+ * The ranges must be listed in increasing address order, and no overlaps are
+ * allowed. It is assumed that write permission implies read permission
+ * (i.e. only RO and RW permissions should be used). Ranges with write
+ * permission must not be split up.
+ */
+
+#define NO_RANGE {.count = 0, .range = NULL,}
+
+static struct ab5500_i2c_banks ab5500_bank_ranges[AB5500_NUM_DEVICES] = {
+ [AB5500_DEVID_ADC] = {
+ .nbanks = 1,
+ .bank = (struct ab5500_i2c_ranges[]) {
+ {
+ .bankid = AB5500_BANK_ADC,
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x20,
+ .last = 0x58,
+ .perm = AB5500_PERM_RW,
+ },
+ },
+ },
+ },
+ },
+ [AB5500_DEVID_LEDS] = {
+ .nbanks = 1,
+ .bank = (struct ab5500_i2c_ranges[]) {
+ {
+ .bankid = AB5500_BANK_LED,
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0C,
+ .perm = AB5500_PERM_RW,
+ },
+ },
+ },
+ },
+ },
+ /* What registers should this device access?*/
+ [AB5500_DEVID_POWER] = {
+ .nbanks = 1,
+ .bank = (struct ab5500_i2c_ranges[]) {
+ {
+ .bankid = AB5500_BANK_CHG,
+ .nranges = 2,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x03,
+ .perm = AB5500_PERM_RW,
+ },
+ {
+ .first = 0x10,
+ .last = 0x30,
+ .perm = AB5500_PERM_RW,
+ },
+ },
+ },
+ },
+ },
+ [AB5500_DEVID_REGULATORS] = {
+ .nbanks = 1,
+ .bank = (struct ab5500_i2c_ranges[]) {
+ {
+ .bankid = AB5500_BANK_STARTUP,
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x50,
+ .last = 0xE0,
+ .perm = AB5500_PERM_RW,
+ },
+ },
+ },
+ },
+ },
+ [AB5500_DEVID_SIM] = {
+ .nbanks = 1,
+ .bank = (struct ab5500_i2c_ranges[]) {
+ {
+ .bankid = AB5500_BANK_SIM_USBSIM,
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x13,
+ .last = 0x19,
+ .perm = AB5500_PERM_RW,
+ },
+ },
+ },
+ },
+ },
+ [AB5500_DEVID_RTC] = {
+ .nbanks = 1,
+ .bank = (struct ab5500_i2c_ranges[]) {
+ {
+ .bankid = AB5500_BANK_LED,
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0C,
+ .perm = AB5500_PERM_RW,
+ },
+ },
+ },
+ },
+ },
+ [AB5500_DEVID_CHARGER] = {
+ .nbanks = 2,
+ .bank = (struct ab5500_i2c_ranges[]) {
+ {
+ .bankid = AB5500_BANK_CHG,
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x10,
+ .last = 0x18,
+ .perm = AB5500_PERM_RW,
+ },
+ },
+ },
+ {
+ .bankid = AB5500_BANK_ADC,
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x1F,
+ .last = 0x58,
+ .perm = AB5500_PERM_RW,
+ },
+ },
+ },
+ },
+ },
+ [AB5500_DEVID_FUELGAUGE] = {
+ .nbanks = 2,
+ .bank = (struct ab5500_i2c_ranges[]) {
+ {
+ .bankid = AB5500_BANK_FG_BATTCOM_ACC,
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x10,
+ .perm = AB5500_PERM_RW,
+ },
+ },
+ },
+ {
+ .bankid = AB5500_BANK_ADC,
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x20,
+ .last = 0x58,
+ .perm = AB5500_PERM_RW,
+ },
+ },
+ },
+ },
+ },
+ [AB5500_DEVID_VIBRATOR] = {
+ .nbanks = 1,
+ .bank = (struct ab5500_i2c_ranges[]) {
+ {
+ .bankid = AB5500_BANK_VIBRA,
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x10,
+ .last = 0x13,
+ .perm = AB5500_PERM_RW,
+ },
+ },
+ },
+ },
+ },
+ [AB5500_DEVID_CODEC] = {
+ .nbanks = 1,
+ .bank = (struct ab5500_i2c_ranges[]) {
+ {
+ .bankid = AB5500_BANK_AUDIO_HEADSETUSB,
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x48,
+ .perm = AB5500_PERM_RW,
+ },
+
+ },
+ },
+ },
+ },
+};
+
+/* I appologize for the resource names beeing a mix of upper case
+ * and lower case but I want them to be exact as the documentation */
+static struct mfd_cell ab5500_devs[AB5500_NUM_DEVICES] = {
+ [AB5500_DEVID_LEDS] = {
+ .name = "ab5500-leds",
+ .id = AB5500_DEVID_LEDS,
+ },
+ [AB5500_DEVID_POWER] = {
+ .name = "ab5500-power",
+ .id = AB5500_DEVID_POWER,
+ },
+ [AB5500_DEVID_REGULATORS] = {
+ .name = "ab5500-regulators",
+ .id = AB5500_DEVID_REGULATORS,
+ },
+ [AB5500_DEVID_SIM] = {
+ .name = "ab5500-sim",
+ .id = AB5500_DEVID_SIM,
+ .num_resources = 1,
+ .resources = (struct resource[]) {
+ {
+ .name = "SIMOFF",
+ .flags = IORESOURCE_IRQ,
+ .start = 16, /*rising*/
+ .end = 17, /*falling*/
+ },
+ },
+ },
+ [AB5500_DEVID_RTC] = {
+ .name = "ab5500-rtc",
+ .id = AB5500_DEVID_RTC,
+ },
+ [AB5500_DEVID_CHARGER] = {
+ .name = "ab5500-charger",
+ .id = AB5500_DEVID_CHARGER,
+ },
+ [AB5500_DEVID_ADC] = {
+ .name = "ab5500-adc",
+ .id = AB5500_DEVID_ADC,
+ .num_resources = 10,
+ .resources = (struct resource[]) {
+ {
+ .name = "TRIGGER-0",
+ .flags = IORESOURCE_IRQ,
+ .start = 0,
+ .end = 0,
+ },
+ {
+ .name = "TRIGGER-1",
+ .flags = IORESOURCE_IRQ,
+ .start = 1,
+ .end = 1,
+ },
+ {
+ .name = "TRIGGER-2",
+ .flags = IORESOURCE_IRQ,
+ .start = 2,
+ .end = 2,
+ },
+ {
+ .name = "TRIGGER-3",
+ .flags = IORESOURCE_IRQ,
+ .start = 3,
+ .end = 3,
+ },
+ {
+ .name = "TRIGGER-4",
+ .flags = IORESOURCE_IRQ,
+ .start = 4,
+ .end = 4,
+ },
+ {
+ .name = "TRIGGER-5",
+ .flags = IORESOURCE_IRQ,
+ .start = 5,
+ .end = 5,
+ },
+ {
+ .name = "TRIGGER-6",
+ .flags = IORESOURCE_IRQ,
+ .start = 6,
+ .end = 6,
+ },
+ {
+ .name = "TRIGGER-7",
+ .flags = IORESOURCE_IRQ,
+ .start = 7,
+ .end = 7,
+ },
+ {
+ .name = "TRIGGER-VBAT-TXON",
+ .flags = IORESOURCE_IRQ,
+ .start = 9,
+ .end = 9,
+ },
+ {
+ .name = "TRIGGER-VBAT",
+ .flags = IORESOURCE_IRQ,
+ .start = 8,
+ .end = 8,
+ },
+ },
+ },
+ [AB5500_DEVID_FUELGAUGE] = {
+ .name = "ab5500-fuelgauge",
+ .id = AB5500_DEVID_FUELGAUGE,
+ .num_resources = 6,
+ .resources = (struct resource[]) {
+ {
+ .name = "Batt_attach",
+ .flags = IORESOURCE_IRQ,
+ .start = 61,
+ .end = 61,
+ },
+ {
+ .name = "Batt_removal",
+ .flags = IORESOURCE_IRQ,
+ .start = 62,
+ .end = 62,
+ },
+ {
+ .name = "UART_framing",
+ .flags = IORESOURCE_IRQ,
+ .start = 63,
+ .end = 63,
+ },
+ {
+ .name = "UART_overrun",
+ .flags = IORESOURCE_IRQ,
+ .start = 64,
+ .end = 64,
+ },
+ {
+ .name = "UART_Rdy_RX",
+ .flags = IORESOURCE_IRQ,
+ .start = 65,
+ .end = 65,
+ },
+ {
+ .name = "UART_Rdy_TX",
+ .flags = IORESOURCE_IRQ,
+ .start = 66,
+ .end = 66,
+ },
+ },
+ },
+ [AB5500_DEVID_VIBRATOR] = {
+ .name = "ab5500-vibrator",
+ .id = AB5500_DEVID_VIBRATOR,
+ },
+ [AB5500_DEVID_CODEC] = {
+ .name = "ab5500-codec",
+ .id = AB5500_DEVID_CODEC,
+ .num_resources = 3,
+ .resources = (struct resource[]) {
+ {
+ .name = "audio_spkr1_ovc",
+ .flags = IORESOURCE_IRQ,
+ .start = 77,
+ .end = 77,
+ },
+ {
+ .name = "audio_plllocked",
+ .flags = IORESOURCE_IRQ,
+ .start = 78,
+ .end = 78,
+ },
+ {
+ .name = "audio_spkr2_ovc",
+ .flags = IORESOURCE_IRQ,
+ .start = 140,
+ .end = 140,
+ },
+ },
+ },
+ [AB5500_DEVID_USB] = {
+ .name = "ab5500-usb",
+ .id = AB5500_DEVID_USB,
+ .num_resources = 35,
+ .resources = (struct resource[]) {
+ {
+ .name = "DCIO",
+ .flags = IORESOURCE_IRQ,
+ .start = 67,
+ .end = 68,
+ },
+ {
+ .name = "VBUS",
+ .flags = IORESOURCE_IRQ,
+ .start = 69,
+ .end = 70,
+ },
+ {
+ .name = "CHGstate_10_PCVBUSchg",
+ .flags = IORESOURCE_IRQ,
+ .start = 71,
+ .end = 71,
+ },
+ {
+ .name = "DCIOreverse_ovc",
+ .flags = IORESOURCE_IRQ,
+ .start = 72,
+ .end = 72,
+ },
+ {
+ .name = "USBCharDetDone",
+ .flags = IORESOURCE_IRQ,
+ .start = 73,
+ .end = 73,
+ },
+ {
+ .name = "DCIO_no_limit",
+ .flags = IORESOURCE_IRQ,
+ .start = 74,
+ .end = 74,
+ },
+ {
+ .name = "USB_suspend",
+ .flags = IORESOURCE_IRQ,
+ .start = 75,
+ .end = 75,
+ },
+ {
+ .name = "DCIOreverse_fwdcurrent",
+ .flags = IORESOURCE_IRQ,
+ .start = 76,
+ .end = 76,
+ },
+ {
+ .name = "Vbus_Imeasmax_change",
+ .flags = IORESOURCE_IRQ,
+ .start = 79,
+ .end = 80,
+ },
+ {
+ .name = "OVV",
+ .flags = IORESOURCE_IRQ,
+ .start = 117,
+ .end = 117,
+ },
+ {
+ .name = "USBcharging_NOTok",
+ .flags = IORESOURCE_IRQ,
+ .start = 123,
+ .end = 123,
+ },
+ {
+ .name = "usb_adp_sensoroff",
+ .flags = IORESOURCE_IRQ,
+ .start = 126,
+ .end = 126,
+ },
+ {
+ .name = "usb_adp_probeplug",
+ .flags = IORESOURCE_IRQ,
+ .start = 127,
+ .end = 127,
+ },
+ {
+ .name = "usb_adp_sinkerror",
+ .flags = IORESOURCE_IRQ,
+ .start = 128,
+ .end = 128,
+ },
+ {
+ .name = "usb_adp_sourceerror",
+ .flags = IORESOURCE_IRQ,
+ .start = 129,
+ .end = 129,
+ },
+ {
+ .name = "usb_idgnd",
+ .flags = IORESOURCE_IRQ,
+ .start = 130,
+ .end = 131,
+ },
+ {
+ .name = "usb_iddetR1",
+ .flags = IORESOURCE_IRQ,
+ .start = 132,
+ .end = 133,
+ },
+ {
+ .name = "usb_iddetR2",
+ .flags = IORESOURCE_IRQ,
+ .start = 134,
+ .end = 135,
+ },
+ {
+ .name = "usb_iddetR3",
+ .flags = IORESOURCE_IRQ,
+ .start = 136,
+ .end = 137,
+ },
+ {
+ .name = "usb_iddetR4",
+ .flags = IORESOURCE_IRQ,
+ .start = 138,
+ .end = 139,
+ },
+ {
+ .name = "CharTempWindowOk",
+ .flags = IORESOURCE_IRQ,
+ .start = 143,
+ .end = 144,
+ },
+ {
+ .name = "USB_SprDetect",
+ .flags = IORESOURCE_IRQ,
+ .start = 145,
+ .end = 145,
+ },
+ {
+ .name = "usb_adp_probe_unplug",
+ .flags = IORESOURCE_IRQ,
+ .start = 146,
+ .end = 146,
+ },
+ {
+ .name = "VBUSChDrop",
+ .flags = IORESOURCE_IRQ,
+ .start = 147,
+ .end = 148,
+ },
+ {
+ .name = "dcio_char_rec_done",
+ .flags = IORESOURCE_IRQ,
+ .start = 149,
+ .end = 149,
+ },
+ {
+ .name = "Charging_stopped_by_temp",
+ .flags = IORESOURCE_IRQ,
+ .start = 150,
+ .end = 150,
+ },
+ {
+ .name = "CHGstate_11_SafeModeVBUS",
+ .flags = IORESOURCE_IRQ,
+ .start = 169,
+ .end = 169,
+ },
+ {
+ .name = "CHGstate_12_comletedVBUS",
+ .flags = IORESOURCE_IRQ,
+ .start = 170,
+ .end = 170,
+ },
+ {
+ .name = "CHGstate_13_completedVBUS",
+ .flags = IORESOURCE_IRQ,
+ .start = 171,
+ .end = 171,
+ },
+ {
+ .name = "CHGstate_14_FullChgDCIO",
+ .flags = IORESOURCE_IRQ,
+ .start = 172,
+ .end = 172,
+ },
+ {
+ .name = "CHGstate_15_SafeModeDCIO",
+ .flags = IORESOURCE_IRQ,
+ .start = 173,
+ .end = 173,
+ },
+ {
+ .name = "CHGstate_16_OFFsuspendDCIO",
+ .flags = IORESOURCE_IRQ,
+ .start = 174,
+ .end = 174,
+ },
+ {
+ .name = "CHGstate_17_completedDCIO",
+ .flags = IORESOURCE_IRQ,
+ .start = 175,
+ .end = 175,
+ },
+ {
+ .name = "o_it_dcio_char_rec_notok",
+ .flags = IORESOURCE_IRQ,
+ .start = 176,
+ .end = 176,
+ },
+ {
+ .name = "usb_link_update",
+ .flags = IORESOURCE_IRQ,
+ .start = 177,
+ .end = 177,
+ },
+ },
+ },
+ [AB5500_DEVID_OTP] = {
+ .name = "ab5500-otp",
+ .id = AB5500_DEVID_OTP,
+ },
+ [AB5500_DEVID_VIDEO] = {
+ .name = "ab5500-video",
+ .id = AB5500_DEVID_VIDEO,
+ .num_resources = 1,
+ .resources = (struct resource[]) {
+ {
+ .name = "plugTVdet",
+ .flags = IORESOURCE_IRQ,
+ .start = 111,
+ .end = 111,
+ },
+ },
+ },
+ [AB5500_DEVID_DBIECI] = {
+ .name = "ab5500-dbieci",
+ .id = AB5500_DEVID_DBIECI,
+ .num_resources = 10,
+ .resources = (struct resource[]) {
+ {
+ .name = "COLL",
+ .flags = IORESOURCE_IRQ,
+ .start = 112,
+ .end = 112,
+ },
+ {
+ .name = "RESERR",
+ .flags = IORESOURCE_IRQ,
+ .start = 113,
+ .end = 113,
+ },
+ {
+ .name = "FRAERR",
+ .flags = IORESOURCE_IRQ,
+ .start = 114,
+ .end = 114,
+ },
+ {
+ .name = "COMERR",
+ .flags = IORESOURCE_IRQ,
+ .start = 115,
+ .end = 115,
+ },
+ {
+ .name = "BSI_indicator",
+ .flags = IORESOURCE_IRQ,
+ .start = 116,
+ .end = 116,
+ },
+ {
+ .name = "SPDSET",
+ .flags = IORESOURCE_IRQ,
+ .start = 118,
+ .end = 118,
+ },
+ {
+ .name = "DSENT",
+ .flags = IORESOURCE_IRQ,
+ .start = 119,
+ .end = 119,
+ },
+ {
+ .name = "DREC",
+ .flags = IORESOURCE_IRQ,
+ .start = 120,
+ .end = 120,
+ },
+ {
+ .name = "ACCINT",
+ .flags = IORESOURCE_IRQ,
+ .start = 121,
+ .end = 121,
+ },
+ {
+ .name = "NOPINT",
+ .flags = IORESOURCE_IRQ,
+ .start = 122,
+ .end = 122,
+ },
+ },
+ },
+};
+
+/*
+ * This stubbed prcmu functionality should be removed when the prcmu driver
+ * implements it.
+ */
+static u8 prcmu_event_buf[AB5500_NUM_EVENT_REG];
+
+void prcmu_get_abb_event_buf(u8 **buf)
+{
+ *buf = prcmu_event_buf;
+}
+
+/*
+ * Functionality for getting/setting register values.
+ */
+static int get_register_interruptible(struct ab5500 *ab, u8 bank, u8 reg,
+ u8 *value)
+{
+ int err;
+
+ if (bank >= AB5500_NUM_BANKS)
+ return -EINVAL;
+
+ err = mutex_lock_interruptible(&ab->access_mutex);
+ if (err)
+ return err;
+ err = prcmu_abb_read(bankinfo[bank].slave_addr, reg, value, 1);
+
+ mutex_unlock(&ab->access_mutex);
+ return err;
+}
+
+static int get_register_page_interruptible(struct ab5500 *ab, u8 bank,
+ u8 first_reg, u8 *regvals, u8 numregs)
+{
+ int err;
+
+ if (bank >= AB5500_NUM_BANKS)
+ return -EINVAL;
+
+ /* The hardware limit for get page is 4 */
+ if (numregs > 4)
+ return -EINVAL;
+
+ err = mutex_lock_interruptible(&ab->access_mutex);
+ if (err)
+ return err;
+
+ err = prcmu_abb_read(bankinfo[bank].slave_addr, first_reg,
+ regvals, numregs);
+
+ mutex_unlock(&ab->access_mutex);
+ return err;
+}
+
+static int mask_and_set_register_interruptible(struct ab5500 *ab, u8 bank,
+ u8 reg, u8 bitmask, u8 bitvalues)
+{
+ int err = 0;
+
+ if (bank >= AB5500_NUM_BANKS)
+ return -EINVAL;
+
+ if (bitmask) {
+ u8 buf;
+
+ err = mutex_lock_interruptible(&ab->access_mutex);
+ if (err)
+ return err;
+
+ if (bitmask == 0xFF) /* No need to read in this case. */
+ buf = bitvalues;
+ else { /* Read and modify the register value. */
+ err = prcmu_abb_read(bankinfo[bank].slave_addr,
+ reg, &buf, 1);
+ if (err)
+ return err;
+
+ buf = ((~bitmask & buf) | (bitmask & bitvalues));
+ }
+ /* Write the new value. */
+ err = prcmu_abb_write(bankinfo[bank].slave_addr, reg, &buf, 1);
+
+ mutex_unlock(&ab->access_mutex);
+ }
+ return err;
+}
+
+/*
+ * Read/write permission checking functions.
+ */
+static const struct ab5500_i2c_ranges *get_bankref(u8 devid, u8 bank)
+{
+ u8 i;
+
+ if (devid < AB5500_NUM_DEVICES) {
+ for (i = 0; i < ab5500_bank_ranges[devid].nbanks; i++) {
+ if (ab5500_bank_ranges[devid].bank[i].bankid == bank)
+ return &ab5500_bank_ranges[devid].bank[i];
+ }
+ }
+ return NULL;
+}
+
+static bool page_write_allowed(u8 devid, u8 bank, u8 first_reg, u8 last_reg)
+{
+ u8 i; /* range loop index */
+ const struct ab5500_i2c_ranges *bankref;
+
+ bankref = get_bankref(devid, bank);
+ if (bankref == NULL || last_reg < first_reg)
+ return false;
+
+ for (i = 0; i < bankref->nranges; i++) {
+ if (first_reg < bankref->range[i].first)
+ break;
+ if ((last_reg <= bankref->range[i].last) &&
+ (bankref->range[i].perm & AB5500_PERM_WR))
+ return true;
+ }
+ return false;
+}
+
+static bool reg_write_allowed(u8 devid, u8 bank, u8 reg)
+{
+ return page_write_allowed(devid, bank, reg, reg);
+}
+
+static bool page_read_allowed(u8 devid, u8 bank, u8 first_reg, u8 last_reg)
+{
+ u8 i;
+ const struct ab5500_i2c_ranges *bankref;
+
+ bankref = get_bankref(devid, bank);
+ if (bankref == NULL || last_reg < first_reg)
+ return false;
+
+
+ /* Find the range (if it exists in the list) that includes first_reg. */
+ for (i = 0; i < bankref->nranges; i++) {
+ if (first_reg < bankref->range[i].first)
+ return false;
+ if (first_reg <= bankref->range[i].last)
+ break;
+ }
+ /* Make sure that the entire range up to and including last_reg is
+ * readable. This may span several of the ranges in the list.
+ */
+ while ((i < bankref->nranges) &&
+ (bankref->range[i].perm & AB5500_PERM_RD)) {
+ if (last_reg <= bankref->range[i].last)
+ return true;
+ if ((++i >= bankref->nranges) ||
+ (bankref->range[i].first !=
+ (bankref->range[i - 1].last + 1))) {
+ break;
+ }
+ }
+ return false;
+}
+
+static bool reg_read_allowed(u8 devid, u8 bank, u8 reg)
+{
+ return page_read_allowed(devid, bank, reg, reg);
+}
+
+
+/*
+ * The exported register access functionality.
+ */
+int ab5500_get_chip_id(struct device *dev)
+{
+ struct ab5500 *ab = dev_get_drvdata(dev->parent);
+
+ return (int)ab->chip_id;
+}
+
+int ab5500_mask_and_set_register_interruptible(struct device *dev, u8 bank,
+ u8 reg, u8 bitmask, u8 bitvalues)
+{
+ struct ab5500 *ab;
+ struct platform_device *pdev = to_platform_device(dev);
+
+ if ((AB5500_NUM_BANKS <= bank) ||
+ !reg_write_allowed(pdev->id, bank, reg))
+ return -EINVAL;
+
+ ab = dev_get_drvdata(dev->parent);
+ return mask_and_set_register_interruptible(ab, bank, reg,
+ bitmask, bitvalues);
+}
+
+int ab5500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
+ u8 value)
+{
+ return ab5500_mask_and_set_register_interruptible(dev, bank, reg, 0xFF,
+ value);
+}
+
+int ab5500_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
+ u8 *value)
+{
+ struct ab5500 *ab;
+ struct platform_device *pdev = to_platform_device(dev);
+
+ if ((AB5500_NUM_BANKS <= bank) ||
+ !reg_read_allowed(pdev->id, bank, reg))
+ return -EINVAL;
+
+ ab = dev_get_drvdata(dev->parent);
+ return get_register_interruptible(ab, bank, reg, value);
+}
+
+int ab5500_get_register_page_interruptible(struct device *dev, u8 bank,
+ u8 first_reg, u8 *regvals, u8 numregs)
+{
+ struct ab5500 *ab;
+ struct platform_device *pdev = to_platform_device(dev);
+
+ if ((AB5500_NUM_BANKS <= bank) ||
+ !page_read_allowed(pdev->id, bank,
+ first_reg, (first_reg + numregs - 1)))
+ return -EINVAL;
+
+ ab = dev_get_drvdata(dev->parent);
+ return get_register_page_interruptible(ab, bank, first_reg, regvals,
+ numregs);
+}
+
+int ab5500_event_registers_startup_state_get(struct device *dev, u8 *event)
+{
+ struct ab5500 *ab;
+
+ ab = dev_get_drvdata(dev->parent);
+ if (!ab->startup_events_read)
+ return -EAGAIN; /* Try again later */
+
+ memcpy(event, ab->startup_events, AB5500_NUM_EVENT_REG);
+ return 0;
+}
+
+int ab5500_startup_irq_enabled(struct device *dev, unsigned int irq)
+{
+ struct ab5500 *ab;
+ bool val;
+
+ ab = get_irq_chip_data(irq);
+ irq -= ab->irq_base;
+ val = ((ab->startup_events[irq / 8] & BIT(irq % 8)) != 0);
+
+ return val;
+}
+
+static struct abx500_ops ab5500_ops = {
+ .get_chip_id = ab5500_get_chip_id,
+ .get_register = ab5500_get_register_interruptible,
+ .set_register = ab5500_set_register_interruptible,
+ .get_register_page = ab5500_get_register_page_interruptible,
+ .set_register_page = NULL,
+ .mask_and_set_register = ab5500_mask_and_set_register_interruptible,
+ .event_registers_startup_state_get =
+ ab5500_event_registers_startup_state_get,
+ .startup_irq_enabled = ab5500_startup_irq_enabled,
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
+static irqreturn_t ab5500_irq_handler(int irq, void *data)
+{
+ struct ab5500 *ab = data;
+
+ /*
+ * Disable the IRQ and dispatch a worker to handle the
+ * event. Since the chip resides on I2C this is slow
+ * stuff and we will re-enable the interrupts once the
+ * worker has finished.
+ */
+ disable_irq_nosync(irq);
+ schedule_work(&ab->irq_work);
+ return IRQ_HANDLED;
+}
+
+static void ab5500_irq_work(struct work_struct *work)
+{
+ struct ab5500 *ab = container_of(work, struct ab5500, irq_work);
+ u8 i;
+ u8 *e = 0;
+ u8 events[AB5500_NUM_EVENT_REG];
+ unsigned long flags;
+
+ prcmu_get_abb_event_buf(&e);
+
+ spin_lock_irqsave(&ab->event_lock, flags);
+ for (i = 0; i < AB5500_NUM_EVENT_REG; i++)
+ events[i] = e[i] & ~ab->event_mask[i];
+ spin_unlock_irqrestore(&ab->event_lock, flags);
+
+ local_irq_disable();
+ for (i = 0; i < AB5500_NUM_EVENT_REG; i++) {
+ u8 bit;
+ u8 event_reg;
+
+ dev_dbg(ab->dev, "IRQ Event[%d]: 0x%2x\n",
+ i, events[i]);
+
+ event_reg = events[i];
+ for (bit = 0; event_reg; bit++, event_reg /= 2) {
+ if (event_reg % 2) {
+ unsigned int irq;
+ struct irq_desc *desc;
+
+ irq = ab->irq_base + (i * 8) + bit;
+ desc = irq_to_desc(irq);
+ if (desc->status & IRQ_DISABLED)
+ note_interrupt(irq, desc, IRQ_NONE);
+ else
+ desc->handle_irq(irq, desc);
+ }
+ }
+ }
+ local_irq_enable();
+ /* By now the IRQ should be acked and deasserted so enable it again */
+ enable_irq(ab->ab5500_irq);
+}
+
+#else
+
+static irqreturn_t ab5500_irq_handler(int irq, void *data)
+{
+ struct ab5500 *ab = data;
+ u8 i;
+ u8 *e = 0;
+ u8 events[AB5500_NUM_EVENT_REG];
+
+ prcmu_get_abb_event_buf(&e);
+
+ spin_lock(&ab->event_lock);
+ for (i = 0; i < AB5500_NUM_EVENT_REG; i++)
+ events[i] = e[i] & ~ab->event_mask[i];
+ spin_unlock(&ab->event_lock);
+
+ for (i = 0; i < AB5500_NUM_EVENT_REG; i++) {
+ u8 bit;
+ u8 event_reg;
+
+ dev_dbg(ab->dev, "IRQ Event[%d]: 0x%2x\n",
+ i, events[i]);
+
+ event_reg = events[i];
+ for (bit = 0; event_reg; bit++, event_reg /= 2) {
+ if (event_reg % 2) {
+ unsigned int irq;
+
+ irq = ab->irq_base + (i * 8) + bit;
+ generic_handle_irq(irq);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static struct ab5500_i2c_ranges debug_ranges[AB5500_NUM_BANKS] = {
+ [AB5500_BANK_LED] = {
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0C,
+ },
+ },
+ },
+ [AB5500_BANK_ADC] = {
+ .nranges = 4,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x1F,
+ .last = 0x24,
+ },
+ {
+ .first = 0x26,
+ .last = 0x2D,
+ },
+ {
+ .first = 0x2F,
+ .last = 0x35,
+ },
+ {
+ .first = 0x37,
+ .last = 0x58,
+ },
+ },
+ },
+ [AB5500_BANK_RTC] = {
+ .nranges = 2,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x04,
+ },
+ {
+ .first = 0x06,
+ .last = 0x0C,
+ },
+ },
+ },
+ [AB5500_BANK_STARTUP] = {
+ .nranges = 12,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x01,
+ },
+ {
+ .first = 0x1F,
+ .last = 0x1F,
+ },
+ {
+ .first = 0x2E,
+ .last = 0x30,
+ },
+ {
+ .first = 0x50,
+ .last = 0x51,
+ },
+ {
+ .first = 0x60,
+ .last = 0x61,
+ },
+ {
+ .first = 0x66,
+ .last = 0x8A,
+ },
+ {
+ .first = 0x8C,
+ .last = 0x96,
+ },
+ {
+ .first = 0xAA,
+ .last = 0xB4,
+ },
+ {
+ .first = 0xB7,
+ .last = 0xBF,
+ },
+ {
+ .first = 0xC1,
+ .last = 0xCA,
+ },
+ {
+ .first = 0xD3,
+ .last = 0xE0,
+ },
+ {
+ .first = 0xF0,
+ .last = 0xF8,
+ },
+ },
+ },
+ [AB5500_BANK_DBI_ECI] = {
+ .nranges = 3,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x07,
+ },
+ {
+ .first = 0x10,
+ .last = 0x10,
+ },
+ {
+ .first = 0x13,
+ .last = 0x13,
+ },
+ },
+ },
+ [AB5500_BANK_CHG] = {
+ .nranges = 1,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x11,
+ .last = 0x1B,
+ },
+ },
+ },
+ [AB5500_BANK_FG_BATTCOM_ACC] = {
+ .nranges = 5,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x10,
+ },
+ {
+ .first = 0x1A,
+ .last = 0x1D,
+ },
+ {
+ .first = 0x20,
+ .last = 0x21,
+ },
+ {
+ .first = 0x23,
+ .last = 0x24,
+ },
+ {
+ .first = 0xFC,
+ .last = 0xFE,
+ },
+ },
+ },
+ [AB5500_BANK_USB] = {
+ .nranges = 13,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x01,
+ .last = 0x01,
+ },
+ {
+ .first = 0x80,
+ .last = 0x83,
+ },
+ {
+ .first = 0x87,
+ .last = 0x8B,
+ },
+ {
+ .first = 0x91,
+ .last = 0x94,
+ },
+ {
+ .first = 0xA8,
+ .last = 0xB0,
+ },
+ {
+ .first = 0xB2,
+ .last = 0xB2,
+ },
+ {
+ .first = 0xB4,
+ .last = 0xBC,
+ },
+ {
+ .first = 0xBF,
+ .last = 0xBF,
+ },
+ {
+ .first = 0xC1,
+ .last = 0xC6,
+ },
+ {
+ .first = 0xCD,
+ .last = 0xCD,
+ },
+ {
+ .first = 0xD6,
+ .last = 0xDA,
+ },
+ {
+ .first = 0xDC,
+ .last = 0xDC,
+ },
+ {
+ .first = 0xE0,
+ .last = 0xE4,
+ },
+ },
+ },
+ [AB5500_BANK_IT] = {
+ .nranges = 4,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x02,
+ },
+ {
+ .first = 0x20,
+ .last = 0x36,
+ },
+ {
+ .first = 0x60,
+ .last = 0x76,
+ },
+ {
+ .first = 0x80,
+ .last = 0x80,
+ },
+ },
+ },
+ [AB5500_BANK_VDDDIG_IO_I2C_CLK_TST] = {
+ .nranges = 7,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x02,
+ .last = 0x02,
+ },
+ {
+ .first = 0x12,
+ .last = 0x12,
+ },
+ {
+ .first = 0x30,
+ .last = 0x34,
+ },
+ {
+ .first = 0x40,
+ .last = 0x44,
+ },
+ {
+ .first = 0x50,
+ .last = 0x54,
+ },
+ {
+ .first = 0x60,
+ .last = 0x64,
+ },
+ {
+ .first = 0x70,
+ .last = 0x74,
+ },
+ },
+ },
+ [AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP] = {
+ .nranges = 12,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x01,
+ .last = 0x02,
+ },
+ {
+ .first = 0x0D,
+ .last = 0x0F,
+ },
+ {
+ .first = 0x1C,
+ .last = 0x1C,
+ },
+ {
+ .first = 0x1E,
+ .last = 0x1E,
+ },
+ {
+ .first = 0x20,
+ .last = 0x21,
+ },
+ {
+ .first = 0x25,
+ .last = 0x25,
+ },
+ {
+ .first = 0x28,
+ .last = 0x2A,
+ },
+ {
+ .first = 0x30,
+ .last = 0x33,
+ },
+ {
+ .first = 0x40,
+ .last = 0x43,
+ },
+ {
+ .first = 0x50,
+ .last = 0x53,
+ },
+ {
+ .first = 0x60,
+ .last = 0x63,
+ },
+ {
+ .first = 0x70,
+ .last = 0x73,
+ },
+ },
+ },
+ [AB5500_BANK_VIBRA] = {
+ .nranges = 2,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x10,
+ .last = 0x13,
+ },
+ {
+ .first = 0xFE,
+ .last = 0xFE,
+ },
+ },
+ },
+ [AB5500_BANK_AUDIO_HEADSETUSB] = {
+ .nranges = 2,
+ .range = (struct ab5500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x48,
+ },
+ {
+ .first = 0xEB,
+ .last = 0xFB,
+ },
+ },
+ },
+};
+
+static int ab5500_registers_print(struct seq_file *s, void *p)
+{
+ struct ab5500 *ab = s->private;
+ unsigned int i;
+ u8 bank = (u8)ab->debug_bank;
+
+ seq_printf(s, AB5500_NAME_STRING " register values:\n");
+
+ seq_printf(s, " bank %u, %s (0x%x):\n", bank,
+ bankinfo[bank].name,
+ bankinfo[bank].slave_addr);
+ for (i = 0; i < debug_ranges[bank].nranges; i++) {
+ u8 reg;
+ int err;
+
+ for (reg = debug_ranges[bank].range[i].first;
+ reg <= debug_ranges[bank].range[i].last;
+ reg++) {
+ u8 value;
+
+ err = get_register_interruptible(ab, bank, reg,
+ &value);
+ if (err < 0) {
+ dev_err(ab->dev, "get_reg failed %d, bank 0x%x"
+ ", reg 0x%x\n", err, bank, reg);
+ return err;
+ }
+
+ err = seq_printf(s, " [%d/0x%02X]: 0x%02X\n", bank,
+ reg, value);
+ if (err < 0) {
+ dev_err(ab->dev, "seq_printf overflow\n");
+ /*
+ * Error is not returned here since
+ * the output is wanted in any case
+ */
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+static int ab5500_registers_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab5500_registers_print, inode->i_private);
+}
+
+static const struct file_operations ab5500_registers_fops = {
+ .open = ab5500_registers_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab5500_bank_print(struct seq_file *s, void *p)
+{
+ struct ab5500 *ab = s->private;
+
+ seq_printf(s, "%d\n", ab->debug_bank);
+ return 0;
+}
+
+static int ab5500_bank_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab5500_bank_print, inode->i_private);
+}
+
+static ssize_t ab5500_bank_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_bank;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_bank);
+ if (err)
+ return -EINVAL;
+
+ if (user_bank >= AB5500_NUM_BANKS) {
+ dev_err(ab->dev,
+ "debugfs error input > number of banks\n");
+ return -EINVAL;
+ }
+
+ ab->debug_bank = user_bank;
+
+ return buf_size;
+}
+
+static int ab5500_address_print(struct seq_file *s, void *p)
+{
+ struct ab5500 *ab = s->private;
+
+ seq_printf(s, "0x%02X\n", ab->debug_address);
+ return 0;
+}
+
+static int ab5500_address_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab5500_address_print, inode->i_private);
+}
+
+static ssize_t ab5500_address_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_address;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_address);
+ if (err)
+ return -EINVAL;
+ if (user_address > 0xff) {
+ dev_err(ab->dev,
+ "debugfs error input > 0xff\n");
+ return -EINVAL;
+ }
+ ab->debug_address = user_address;
+ return buf_size;
+}
+
+static int ab5500_val_print(struct seq_file *s, void *p)
+{
+ struct ab5500 *ab = s->private;
+ int err;
+ u8 regvalue;
+
+ err = get_register_interruptible(ab, (u8)ab->debug_bank,
+ (u8)ab->debug_address, &regvalue);
+ if (err) {
+ dev_err(ab->dev, "get_reg failed %d, bank 0x%x"
+ ", reg 0x%x\n", err, ab->debug_bank,
+ ab->debug_address);
+ return -EINVAL;
+ }
+ seq_printf(s, "0x%02X\n", regvalue);
+
+ return 0;
+}
+
+static int ab5500_val_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab5500_val_print, inode->i_private);
+}
+
+static ssize_t ab5500_val_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_val;
+ int err;
+ u8 regvalue;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_val);
+ if (err)
+ return -EINVAL;
+ if (user_val > 0xff) {
+ dev_err(ab->dev,
+ "debugfs error input > 0xff\n");
+ return -EINVAL;
+ }
+ err = mask_and_set_register_interruptible(
+ ab, (u8)ab->debug_bank,
+ (u8)ab->debug_address, 0xFF, (u8)user_val);
+ if (err)
+ return -EINVAL;
+
+ get_register_interruptible(ab, (u8)ab->debug_bank,
+ (u8)ab->debug_address, &regvalue);
+ if (err)
+ return -EINVAL;
+
+ return buf_size;
+}
+
+static const struct file_operations ab5500_bank_fops = {
+ .open = ab5500_bank_open,
+ .write = ab5500_bank_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab5500_address_fops = {
+ .open = ab5500_address_open,
+ .write = ab5500_address_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab5500_val_fops = {
+ .open = ab5500_val_open,
+ .write = ab5500_val_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static struct dentry *ab5500_dir;
+static struct dentry *ab5500_reg_file;
+static struct dentry *ab5500_bank_file;
+static struct dentry *ab5500_address_file;
+static struct dentry *ab5500_val_file;
+
+static inline void ab5500_setup_debugfs(struct ab5500 *ab)
+{
+ ab->debug_bank = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP;
+ ab->debug_address = AB5500_CHIP_ID;
+
+ ab5500_dir = debugfs_create_dir(AB5500_NAME_STRING, NULL);
+ if (!ab5500_dir)
+ goto exit_no_debugfs;
+
+ ab5500_reg_file = debugfs_create_file("all-bank-registers",
+ S_IRUGO, ab5500_dir, ab, &ab5500_registers_fops);
+ if (!ab5500_reg_file)
+ goto exit_destroy_dir;
+
+ ab5500_bank_file = debugfs_create_file("register-bank",
+ (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_bank_fops);
+ if (!ab5500_bank_file)
+ goto exit_destroy_reg;
+
+ ab5500_address_file = debugfs_create_file("register-address",
+ (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_address_fops);
+ if (!ab5500_address_file)
+ goto exit_destroy_bank;
+
+ ab5500_val_file = debugfs_create_file("register-value",
+ (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_val_fops);
+ if (!ab5500_val_file)
+ goto exit_destroy_address;
+
+ return;
+
+exit_destroy_address:
+ debugfs_remove(ab5500_address_file);
+exit_destroy_bank:
+ debugfs_remove(ab5500_bank_file);
+exit_destroy_reg:
+ debugfs_remove(ab5500_reg_file);
+exit_destroy_dir:
+ debugfs_remove(ab5500_dir);
+exit_no_debugfs:
+ dev_err(ab->dev, "failed to create debugfs entries.\n");
+ return;
+}
+
+static inline void ab5500_remove_debugfs(void)
+{
+ debugfs_remove(ab5500_val_file);
+ debugfs_remove(ab5500_address_file);
+ debugfs_remove(ab5500_bank_file);
+ debugfs_remove(ab5500_reg_file);
+ debugfs_remove(ab5500_dir);
+}
+
+#else /* !CONFIG_DEBUG_FS */
+static inline void ab5500_setup_debugfs(struct ab5500 *ab)
+{
+}
+static inline void ab5500_remove_debugfs(void)
+{
+}
+#endif
+
+/*
+ * Basic set-up, datastructure creation/destruction and I2C interface.
+ * This sets up a default config in the AB5500 chip so that it
+ * will work as expected.
+ */
+static int __init ab5500_setup(struct ab5500 *ab,
+ struct abx500_init_settings *settings, unsigned int size)
+{
+ int err = 0;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ err = mask_and_set_register_interruptible(ab,
+ settings[i].bank,
+ settings[i].reg,
+ 0xFF, settings[i].setting);
+ if (err)
+ goto exit_no_setup;
+
+ /* If event mask register update the event mask in ab5500 */
+ if ((settings[i].bank == AB5500_BANK_IT) &&
+ (AB5500_MASK_BASE <= settings[i].reg) &&
+ (settings[i].reg <= AB5500_MASK_END)) {
+ ab->event_mask[settings[i].reg - AB5500_MASK_BASE] =
+ settings[i].setting;
+ }
+ }
+exit_no_setup:
+ return err;
+}
+
+static void ab5500_mask_work(struct work_struct *work)
+{
+ struct ab5500 *ab = container_of(work, struct ab5500, mask_work);
+ int i;
+ int err;
+ unsigned long flags;
+ u8 mask[AB5500_NUM_EVENT_REG];
+ int call_prcmu_event_readout = 0;
+
+ spin_lock_irqsave(&ab->event_lock, flags);
+ for (i = 0; i < AB5500_NUM_EVENT_REG; i++)
+ mask[i] = ab->event_mask[i];
+ spin_unlock_irqrestore(&ab->event_lock, flags);
+
+ for (i = 0; i < AB5500_NUM_EVENT_REG; i++) {
+ if (mask[i] != ab->last_event_mask[i]) {
+ err = mask_and_set_register_interruptible(ab, 0,
+ (AB5500_MASK_BASE + i), ~0, mask[i]);
+ if (err) {
+ dev_err(ab->dev,
+ "ab5500_mask_work failed 0x%x,0x%x\n",
+ (AB5500_MASK_BASE + i), mask[i]);
+ break;
+ }
+
+ if (mask[i] == 0xFF) {
+ ab->abb_events &= ~BIT(i);
+ call_prcmu_event_readout = 1;
+ } else {
+ ab->abb_events |= BIT(i);
+ if (ab->last_event_mask[i] == 0xFF)
+ call_prcmu_event_readout = 1;
+ }
+
+ ab->last_event_mask[i] = mask[i];
+ }
+ }
+ if (call_prcmu_event_readout) {
+ err = prcmu_config_abb_event_readout(ab->abb_events);
+ if (err)
+ dev_err(ab->dev,
+ "prcmu_config_abb_event_readout failed\n");
+ }
+}
+
+static void ab5500_mask(unsigned int irq)
+{
+ unsigned long flags;
+ struct ab5500 *ab;
+
+ ab = get_irq_chip_data(irq);
+ irq -= ab->irq_base;
+
+ spin_lock_irqsave(&ab->event_lock, flags);
+ ab->event_mask[irq / 8] |= BIT(irq % 8);
+ spin_unlock_irqrestore(&ab->event_lock, flags);
+
+ schedule_work(&ab->mask_work);
+}
+
+static void ab5500_unmask(unsigned int irq)
+{
+ unsigned long flags;
+ struct ab5500 *ab;
+
+ ab = get_irq_chip_data(irq);
+ irq -= ab->irq_base;
+
+ spin_lock_irqsave(&ab->event_lock, flags);
+ ab->event_mask[irq / 8] &= ~BIT(irq % 8);
+ spin_unlock_irqrestore(&ab->event_lock, flags);
+
+ schedule_work(&ab->mask_work);
+}
+
+static void noop(unsigned int irq)
+{
+}
+
+static struct irq_chip ab5500_irq_chip = {
+ .name = "ab5500-core", /* Keep the same name as the request */
+ .startup = NULL, /* defaults to enable */
+ .shutdown = NULL, /* defaults to disable */
+ .enable = NULL, /* defaults to unmask */
+ .disable = ab5500_mask, /* No default to mask in chip.c */
+ .ack = noop,
+ .mask = ab5500_mask,
+ .unmask = ab5500_unmask,
+ .end = NULL,
+};
+
+struct ab_family_id {
+ u8 id;
+ char *name;
+};
+
+static const struct ab_family_id ids[] __initdata = {
+ /* AB5500 */
+ {
+ .id = AB5500_1_0,
+ .name = "1.0"
+ },
+ /* Terminator */
+ {
+ .id = 0x00,
+ }
+};
+
+static int __init ab5500_probe(struct platform_device *pdev)
+{
+ struct ab5500 *ab;
+ struct ab5500_platform_data *ab5500_plf_data =
+ pdev->dev.platform_data;
+ struct resource *res;
+ int err;
+ int i;
+
+ ab = kzalloc(sizeof(struct ab5500), GFP_KERNEL);
+ if (!ab) {
+ dev_err(&pdev->dev,
+ "could not allocate " AB5500_NAME_STRING " device\n");
+ return -ENOMEM;
+ }
+
+ /* Initialize data structure */
+ mutex_init(&ab->access_mutex);
+ spin_lock_init(&ab->event_lock);
+ ab->dev = &pdev->dev;
+ ab->irq_base = ab5500_plf_data->irq.base;
+
+ platform_set_drvdata(pdev, ab);
+
+ /* Read chip ID register */
+ err = get_register_interruptible(ab, AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP,
+ AB5500_CHIP_ID, &ab->chip_id);
+ if (err) {
+ dev_err(&pdev->dev, "could not communicate with the analog "
+ "baseband chip\n");
+ goto exit_no_detect;
+ }
+
+ for (i = 0; ids[i].id != 0x0; i++) {
+ if (ids[i].id == ab->chip_id) {
+ snprintf(&ab->chip_name[0], sizeof(ab->chip_name) - 1,
+ AB5500_ID_FORMAT_STRING, ids[i].name);
+ break;
+ }
+ }
+
+ if (ids[i].id == 0x0) {
+ dev_err(&pdev->dev, "unknown analog baseband chip id: 0x%x\n",
+ ab->chip_id);
+ dev_err(&pdev->dev, "driver not started!\n");
+ goto exit_no_detect;
+ }
+
+ dev_info(&pdev->dev, "detected AB chip: %s\n", &ab->chip_name[0]);
+
+ /* Readout ab->starup_events when prcmu driver is in place */
+ ab->startup_events[0] = 0;
+
+ err = ab5500_setup(ab, ab5500_plf_data->init_settings,
+ ab5500_plf_data->init_settings_sz);
+ if (err) {
+ dev_err(&pdev->dev, "ab5500_setup error\n");
+ goto exit_no_setup;
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
+ INIT_WORK(&ab->irq_work, ab5500_irq_work);
+#endif
+ INIT_WORK(&ab->mask_work, ab5500_mask_work);
+
+ for (i = 0; i < ab5500_plf_data->irq.count; i++) {
+ unsigned int irq;
+
+ irq = ab5500_plf_data->irq.base + i;
+ set_irq_chip_data(irq, ab);
+ set_irq_chip_and_handler(irq, &ab5500_irq_chip,
+ handle_simple_irq);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ set_irq_nested_thread(irq, 1);
+#endif
+ set_irq_flags(irq, IRQF_VALID);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+ if (!res) {
+ dev_err(&pdev->dev, "ab5500_platform_get_resource error\n");
+ goto exit_no_irq;
+ }
+ ab->ab5500_irq = res->start;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
+ /* This really unpredictable IRQ is of course sampled for entropy. */
+ err = request_irq(res->start, ab5500_irq_handler,
+ (IRQF_DISABLED | IRQF_SAMPLE_RANDOM), "ab5500-core", ab);
+ if (err) {
+ dev_err(&pdev->dev, "ab5500_request_irq error\n");
+ goto exit_no_irq;
+ }
+
+ /* We probably already got an irq here, but if not,
+ * we force a first time and save the startup events here.*/
+ disable_irq_nosync(res->start);
+ schedule_work(&ab->irq_work);
+#else
+ err = request_threaded_irq(res->start, ab5500_irq_handler, NULL,
+ IRQF_SAMPLE_RANDOM, "ab5500-core", ab);
+ /* This real unpredictable IRQ is of course sampled for entropy */
+ rand_initialize_irq(res->start);
+
+ if (err) {
+ dev_err(&pdev->dev, "ab5500_request_irq error\n");
+ goto exit_no_irq;
+ }
+#endif
+
+ err = abx500_register_ops(&pdev->dev, &ab5500_ops);
+ if (err) {
+ dev_err(&pdev->dev, "ab5500_register ops error\n");
+ goto exit_no_ops;
+ }
+
+ /* Set up and register the platform devices. */
+ for (i = 0; i < AB5500_NUM_DEVICES; i++) {
+ ab5500_devs[i].platform_data = ab5500_plf_data->dev_data[i];
+ ab5500_devs[i].data_size = ab5500_plf_data->dev_data_sz[i];
+ }
+
+ err = mfd_add_devices(&pdev->dev, 0, ab5500_devs,
+ ARRAY_SIZE(ab5500_devs), NULL,
+ ab5500_plf_data->irq.base);
+ if (err) {
+ dev_err(&pdev->dev, "ab5500_mfd_add_device error\n");
+ goto exit_no_ops;
+ }
+
+ ab5500_setup_debugfs(ab);
+
+ return 0;
+
+exit_no_ops:
+exit_no_irq:
+exit_no_setup:
+exit_no_detect:
+ kfree(ab);
+ return err;
+}
+
+static int __exit ab5500_remove(struct platform_device *pdev)
+{
+ struct ab5500 *ab = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ /*
+ * At this point, all subscribers should have unregistered
+ * their notifiers so deactivate IRQ
+ */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ free_irq(res->start, ab);
+
+ mfd_remove_devices(&pdev->dev);
+ ab5500_remove_debugfs();
+
+ kfree(ab);
+ return 0;
+}
+
+static struct platform_driver ab5500_driver = {
+ .driver = {
+ .name = "ab5500-core",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(ab5500_remove),
+};
+
+static int __init ab5500_core_init(void)
+{
+ return platform_driver_probe(&ab5500_driver, ab5500_probe);
+}
+
+static void __exit ab5500_core_exit(void)
+{
+ platform_driver_unregister(&ab5500_driver);
+}
+
+subsys_initcall(ab5500_core_init);
+module_exit(ab5500_core_exit);
+
+MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
+MODULE_DESCRIPTION("AB5500 core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index f3d26fa9c34..00f55c860a4 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -4,88 +4,82 @@
* License Terms: GNU General Public License v2
* Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
* Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ * Changes: Mattias Wallin <mattias.wallin@stericsson.com>
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/irq.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
+#include <linux/mfd/abx500.h>
#include <linux/mfd/ab8500.h>
+#include <linux/regulator/ab8500.h>
/*
* Interrupt register offsets
* Bank : 0x0E
*/
-#define AB8500_IT_SOURCE1_REG 0x0E00
-#define AB8500_IT_SOURCE2_REG 0x0E01
-#define AB8500_IT_SOURCE3_REG 0x0E02
-#define AB8500_IT_SOURCE4_REG 0x0E03
-#define AB8500_IT_SOURCE5_REG 0x0E04
-#define AB8500_IT_SOURCE6_REG 0x0E05
-#define AB8500_IT_SOURCE7_REG 0x0E06
-#define AB8500_IT_SOURCE8_REG 0x0E07
-#define AB8500_IT_SOURCE19_REG 0x0E12
-#define AB8500_IT_SOURCE20_REG 0x0E13
-#define AB8500_IT_SOURCE21_REG 0x0E14
-#define AB8500_IT_SOURCE22_REG 0x0E15
-#define AB8500_IT_SOURCE23_REG 0x0E16
-#define AB8500_IT_SOURCE24_REG 0x0E17
+#define AB8500_IT_SOURCE1_REG 0x00
+#define AB8500_IT_SOURCE2_REG 0x01
+#define AB8500_IT_SOURCE3_REG 0x02
+#define AB8500_IT_SOURCE4_REG 0x03
+#define AB8500_IT_SOURCE5_REG 0x04
+#define AB8500_IT_SOURCE6_REG 0x05
+#define AB8500_IT_SOURCE7_REG 0x06
+#define AB8500_IT_SOURCE8_REG 0x07
+#define AB8500_IT_SOURCE19_REG 0x12
+#define AB8500_IT_SOURCE20_REG 0x13
+#define AB8500_IT_SOURCE21_REG 0x14
+#define AB8500_IT_SOURCE22_REG 0x15
+#define AB8500_IT_SOURCE23_REG 0x16
+#define AB8500_IT_SOURCE24_REG 0x17
/*
* latch registers
*/
-#define AB8500_IT_LATCH1_REG 0x0E20
-#define AB8500_IT_LATCH2_REG 0x0E21
-#define AB8500_IT_LATCH3_REG 0x0E22
-#define AB8500_IT_LATCH4_REG 0x0E23
-#define AB8500_IT_LATCH5_REG 0x0E24
-#define AB8500_IT_LATCH6_REG 0x0E25
-#define AB8500_IT_LATCH7_REG 0x0E26
-#define AB8500_IT_LATCH8_REG 0x0E27
-#define AB8500_IT_LATCH9_REG 0x0E28
-#define AB8500_IT_LATCH10_REG 0x0E29
-#define AB8500_IT_LATCH19_REG 0x0E32
-#define AB8500_IT_LATCH20_REG 0x0E33
-#define AB8500_IT_LATCH21_REG 0x0E34
-#define AB8500_IT_LATCH22_REG 0x0E35
-#define AB8500_IT_LATCH23_REG 0x0E36
-#define AB8500_IT_LATCH24_REG 0x0E37
+#define AB8500_IT_LATCH1_REG 0x20
+#define AB8500_IT_LATCH2_REG 0x21
+#define AB8500_IT_LATCH3_REG 0x22
+#define AB8500_IT_LATCH4_REG 0x23
+#define AB8500_IT_LATCH5_REG 0x24
+#define AB8500_IT_LATCH6_REG 0x25
+#define AB8500_IT_LATCH7_REG 0x26
+#define AB8500_IT_LATCH8_REG 0x27
+#define AB8500_IT_LATCH9_REG 0x28
+#define AB8500_IT_LATCH10_REG 0x29
+#define AB8500_IT_LATCH12_REG 0x2B
+#define AB8500_IT_LATCH19_REG 0x32
+#define AB8500_IT_LATCH20_REG 0x33
+#define AB8500_IT_LATCH21_REG 0x34
+#define AB8500_IT_LATCH22_REG 0x35
+#define AB8500_IT_LATCH23_REG 0x36
+#define AB8500_IT_LATCH24_REG 0x37
/*
* mask registers
*/
-#define AB8500_IT_MASK1_REG 0x0E40
-#define AB8500_IT_MASK2_REG 0x0E41
-#define AB8500_IT_MASK3_REG 0x0E42
-#define AB8500_IT_MASK4_REG 0x0E43
-#define AB8500_IT_MASK5_REG 0x0E44
-#define AB8500_IT_MASK6_REG 0x0E45
-#define AB8500_IT_MASK7_REG 0x0E46
-#define AB8500_IT_MASK8_REG 0x0E47
-#define AB8500_IT_MASK9_REG 0x0E48
-#define AB8500_IT_MASK10_REG 0x0E49
-#define AB8500_IT_MASK11_REG 0x0E4A
-#define AB8500_IT_MASK12_REG 0x0E4B
-#define AB8500_IT_MASK13_REG 0x0E4C
-#define AB8500_IT_MASK14_REG 0x0E4D
-#define AB8500_IT_MASK15_REG 0x0E4E
-#define AB8500_IT_MASK16_REG 0x0E4F
-#define AB8500_IT_MASK17_REG 0x0E50
-#define AB8500_IT_MASK18_REG 0x0E51
-#define AB8500_IT_MASK19_REG 0x0E52
-#define AB8500_IT_MASK20_REG 0x0E53
-#define AB8500_IT_MASK21_REG 0x0E54
-#define AB8500_IT_MASK22_REG 0x0E55
-#define AB8500_IT_MASK23_REG 0x0E56
-#define AB8500_IT_MASK24_REG 0x0E57
-
-#define AB8500_REV_REG 0x1080
+#define AB8500_IT_MASK1_REG 0x40
+#define AB8500_IT_MASK2_REG 0x41
+#define AB8500_IT_MASK3_REG 0x42
+#define AB8500_IT_MASK4_REG 0x43
+#define AB8500_IT_MASK5_REG 0x44
+#define AB8500_IT_MASK6_REG 0x45
+#define AB8500_IT_MASK7_REG 0x46
+#define AB8500_IT_MASK8_REG 0x47
+#define AB8500_IT_MASK9_REG 0x48
+#define AB8500_IT_MASK10_REG 0x49
+#define AB8500_IT_MASK12_REG 0x4B
+#define AB8500_IT_MASK19_REG 0x52
+#define AB8500_IT_MASK20_REG 0x53
+#define AB8500_IT_MASK21_REG 0x54
+#define AB8500_IT_MASK22_REG 0x55
+
+#define AB8500_REV_REG 0x80
/*
* Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
@@ -98,96 +92,167 @@ static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21,
};
-static int __ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data)
+static int ab8500_get_chip_id(struct device *dev)
+{
+ struct ab8500 *ab8500;
+ if (!dev)
+ return -EINVAL;
+ ab8500 = dev_get_drvdata(dev->parent);
+ return (int)ab8500->chip_id;
+}
+
+static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
+ u8 reg, u8 data)
{
int ret;
+ /*
+ * Put the u8 bank and u8 register together into a an u16.
+ * The bank on higher 8 bits and register in lower 8 bits.
+ * */
+ u16 addr = ((u16)bank) << 8 | reg;
dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
+ ret = mutex_lock_interruptible(&ab8500->lock);
+ if (ret)
+ return ret;
+
ret = ab8500->write(ab8500, addr, data);
if (ret < 0)
dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
addr, ret);
+ mutex_unlock(&ab8500->lock);
return ret;
}
-/**
- * ab8500_write() - write an AB8500 register
- * @ab8500: device to write to
- * @addr: address of the register
- * @data: value to write
- */
-int ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data)
+static int ab8500_set_register(struct device *dev, u8 bank,
+ u8 reg, u8 value)
{
- int ret;
+ struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
- mutex_lock(&ab8500->lock);
- ret = __ab8500_write(ab8500, addr, data);
- mutex_unlock(&ab8500->lock);
-
- return ret;
+ return set_register_interruptible(ab8500, bank, reg, value);
}
-EXPORT_SYMBOL_GPL(ab8500_write);
-static int __ab8500_read(struct ab8500 *ab8500, u16 addr)
+static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
+ u8 reg, u8 *value)
{
int ret;
+ /* put the u8 bank and u8 reg together into a an u16.
+ * bank on higher 8 bits and reg in lower */
+ u16 addr = ((u16)bank) << 8 | reg;
+
+ ret = mutex_lock_interruptible(&ab8500->lock);
+ if (ret)
+ return ret;
ret = ab8500->read(ab8500, addr);
if (ret < 0)
dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
addr, ret);
+ else
+ *value = ret;
+ mutex_unlock(&ab8500->lock);
dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
return ret;
}
-/**
- * ab8500_read() - read an AB8500 register
- * @ab8500: device to read from
- * @addr: address of the register
- */
-int ab8500_read(struct ab8500 *ab8500, u16 addr)
+static int ab8500_get_register(struct device *dev, u8 bank,
+ u8 reg, u8 *value)
{
- int ret;
-
- mutex_lock(&ab8500->lock);
- ret = __ab8500_read(ab8500, addr);
- mutex_unlock(&ab8500->lock);
+ struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
- return ret;
+ return get_register_interruptible(ab8500, bank, reg, value);
}
-EXPORT_SYMBOL_GPL(ab8500_read);
-
-/**
- * ab8500_set_bits() - set a bitfield in an AB8500 register
- * @ab8500: device to read from
- * @addr: address of the register
- * @mask: mask of the bitfield to modify
- * @data: value to set to the bitfield
- */
-int ab8500_set_bits(struct ab8500 *ab8500, u16 addr, u8 mask, u8 data)
+
+static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
+ u8 reg, u8 bitmask, u8 bitvalues)
{
int ret;
+ u8 data;
+ /* put the u8 bank and u8 reg together into a an u16.
+ * bank on higher 8 bits and reg in lower */
+ u16 addr = ((u16)bank) << 8 | reg;
- mutex_lock(&ab8500->lock);
+ ret = mutex_lock_interruptible(&ab8500->lock);
+ if (ret)
+ return ret;
- ret = __ab8500_read(ab8500, addr);
- if (ret < 0)
+ ret = ab8500->read(ab8500, addr);
+ if (ret < 0) {
+ dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
+ addr, ret);
goto out;
+ }
- ret &= ~mask;
- ret |= data;
+ data = (u8)ret;
+ data = (~bitmask & data) | (bitmask & bitvalues);
- ret = __ab8500_write(ab8500, addr, ret);
+ ret = ab8500->write(ab8500, addr, data);
+ if (ret < 0)
+ dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
+ addr, ret);
+ dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, data);
out:
mutex_unlock(&ab8500->lock);
return ret;
}
-EXPORT_SYMBOL_GPL(ab8500_set_bits);
+
+static int ab8500_mask_and_set_register(struct device *dev,
+ u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+
+ return mask_and_set_register_interruptible(ab8500, bank, reg,
+ bitmask, bitvalues);
+
+}
+
+static struct abx500_ops ab8500_ops = {
+ .get_chip_id = ab8500_get_chip_id,
+ .get_register = ab8500_get_register,
+ .set_register = ab8500_set_register,
+ .get_register_page = NULL,
+ .set_register_page = NULL,
+ .mask_and_set_register = ab8500_mask_and_set_register,
+ .event_registers_startup_state_get = NULL,
+ .startup_irq_enabled = NULL,
+};
+
+/* These functions are deprecated and will be removed soon.
+ * They are only here to be backwards compatible during a
+ * change period.
+ */
+struct ab8500 *ab8500_depr;
+
+int __deprecated ab8500_write(u8 block, u32 adr, u8 data)
+{
+ if (!ab8500_depr)
+ return -EINVAL;
+
+ return set_register_interruptible(ab8500_depr, block, adr & 0xFF, data);
+}
+EXPORT_SYMBOL(ab8500_write);
+
+int __deprecated ab8500_read(u8 block, u32 adr)
+{
+ int ret;
+ u8 data;
+
+ if (!ab8500_depr)
+ return -EINVAL;
+
+ ret = get_register_interruptible(ab8500_depr, block, adr & 0xFF,
+ &data);
+ if (ret < 0)
+ return ret;
+ return (int)data;
+}
+EXPORT_SYMBOL(ab8500_read);
+/* End of deprecated functions */
static void ab8500_irq_lock(unsigned int irq)
{
@@ -212,7 +277,18 @@ static void ab8500_irq_sync_unlock(unsigned int irq)
ab8500->oldmask[i] = new;
reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
- ab8500_write(ab8500, reg, new);
+ set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
+ }
+ /* MASK register 12 exist only in v2 */
+ if (ab8500->chip_id >= 0x20) {
+ u8 old = ab8500->oldmask[AB8500_NUM_IRQ_REGS];
+ u8 new = ab8500->mask[AB8500_NUM_IRQ_REGS];
+
+ if (new != old) {
+ ab8500->oldmask[AB8500_NUM_IRQ_REGS] = new;
+ set_register_interruptible(ab8500, AB8500_INTERRUPT,
+ AB8500_IT_MASK12_REG, new);
+ }
}
mutex_unlock(&ab8500->irq_lock);
@@ -256,18 +332,40 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
int regoffset = ab8500_irq_regoffset[i];
int status;
+ u8 value;
- status = ab8500_read(ab8500, AB8500_IT_LATCH1_REG + regoffset);
- if (status <= 0)
+ status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
+ AB8500_IT_LATCH1_REG + regoffset, &value);
+ if (status < 0 || value == 0)
continue;
do {
- int bit = __ffs(status);
+ int bit = __ffs(value);
int line = i * 8 + bit;
handle_nested_irq(ab8500->irq_base + line);
- status &= ~(1 << bit);
- } while (status);
+ value &= ~(1 << bit);
+ } while (value);
+ }
+ /* LATCH register 12 exist only in v2 */
+ if (ab8500->chip_id >= 0x20) {
+ int status;
+ u8 value;
+
+ status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
+ AB8500_IT_LATCH12_REG, &value);
+ if (status < 0) {
+ dev_err(dev, "LATCH12 get reg failed\n");
+ return IRQ_HANDLED;
+ }
+ while (value) {
+ int bit = __ffs(value);
+ int line = AB8500_NUM_IRQ_REGS * 8 + bit;
+
+ handle_nested_irq(ab8500->irq_base + line);
+ value &= ~(1 << bit);
+
+ }
}
return IRQ_HANDLED;
@@ -337,7 +435,209 @@ static struct resource ab8500_rtc_resources[] = {
},
};
+static struct resource ab8500_poweronkey_db_resources[] = {
+ {
+ .name = "ONKEY_DBF",
+ .start = AB8500_INT_PON_KEY1DB_F,
+ .end = AB8500_INT_PON_KEY1DB_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "ONKEY_DBR",
+ .start = AB8500_INT_PON_KEY1DB_R,
+ .end = AB8500_INT_PON_KEY1DB_R,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_bm_resources[] = {
+ {
+ .name = "MAIN_EXT_CH_NOT_OK",
+ .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BATT_OVV",
+ .start = AB8500_INT_BATT_OVV,
+ .end = AB8500_INT_BATT_OVV,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "MAIN_CH_UNPLUG_DET",
+ .start = AB8500_INT_MAIN_CH_UNPLUG_DET,
+ .end = AB8500_INT_MAIN_CH_UNPLUG_DET,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "MAIN_CHARGE_PLUG_DET",
+ .start = AB8500_INT_MAIN_CH_PLUG_DET,
+ .end = AB8500_INT_MAIN_CH_PLUG_DET,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_F",
+ .start = AB8500_INT_VBUS_DET_F,
+ .end = AB8500_INT_VBUS_DET_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_R",
+ .start = AB8500_INT_VBUS_DET_R,
+ .end = AB8500_INT_VBUS_DET_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BAT_CTRL_INDB",
+ .start = AB8500_INT_BAT_CTRL_INDB,
+ .end = AB8500_INT_BAT_CTRL_INDB,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "CH_WD_EXP",
+ .start = AB8500_INT_CH_WD_EXP,
+ .end = AB8500_INT_CH_WD_EXP,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_OVV",
+ .start = AB8500_INT_VBUS_OVV,
+ .end = AB8500_INT_VBUS_OVV,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "NCONV_ACCU",
+ .start = AB8500_INT_CCN_CONV_ACC,
+ .end = AB8500_INT_CCN_CONV_ACC,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "LOW_BAT_F",
+ .start = AB8500_INT_LOW_BAT_F,
+ .end = AB8500_INT_LOW_BAT_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "LOW_BAT_R",
+ .start = AB8500_INT_LOW_BAT_R,
+ .end = AB8500_INT_LOW_BAT_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BTEMP_LOW",
+ .start = AB8500_INT_BTEMP_LOW,
+ .end = AB8500_INT_BTEMP_LOW,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BTEMP_HIGH",
+ .start = AB8500_INT_BTEMP_HIGH,
+ .end = AB8500_INT_BTEMP_HIGH,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CHARGER_NOT_OKR",
+ .start = AB8500_INT_USB_CHARGER_NOT_OK,
+ .end = AB8500_INT_USB_CHARGER_NOT_OK,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CHARGE_DET_DONE",
+ .start = AB8500_INT_USB_CHG_DET_DONE,
+ .end = AB8500_INT_USB_CHG_DET_DONE,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CH_TH_PROT_R",
+ .start = AB8500_INT_USB_CH_TH_PROT_R,
+ .end = AB8500_INT_USB_CH_TH_PROT_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "MAIN_CH_TH_PROT_R",
+ .start = AB8500_INT_MAIN_CH_TH_PROT_R,
+ .end = AB8500_INT_MAIN_CH_TH_PROT_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CHARGER_NOT_OKF",
+ .start = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_debug_resources[] = {
+ {
+ .name = "IRQ_FIRST",
+ .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "IRQ_LAST",
+ .start = AB8500_INT_USB_LINK_STATUS,
+ .end = AB8500_INT_USB_LINK_STATUS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_usb_resources[] = {
+ {
+ .name = "ID_WAKEUP_R",
+ .start = AB8500_INT_ID_WAKEUP_R,
+ .end = AB8500_INT_ID_WAKEUP_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "ID_WAKEUP_F",
+ .start = AB8500_INT_ID_WAKEUP_F,
+ .end = AB8500_INT_ID_WAKEUP_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_F",
+ .start = AB8500_INT_VBUS_DET_F,
+ .end = AB8500_INT_VBUS_DET_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_R",
+ .start = AB8500_INT_VBUS_DET_R,
+ .end = AB8500_INT_VBUS_DET_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_LINK_STATUS",
+ .start = AB8500_INT_USB_LINK_STATUS,
+ .end = AB8500_INT_USB_LINK_STATUS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_temp_resources[] = {
+ {
+ .name = "AB8500_TEMP_WARM",
+ .start = AB8500_INT_TEMP_WARM,
+ .end = AB8500_INT_TEMP_WARM,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct mfd_cell ab8500_devs[] = {
+#ifdef CONFIG_DEBUG_FS
+ {
+ .name = "ab8500-debug",
+ .num_resources = ARRAY_SIZE(ab8500_debug_resources),
+ .resources = ab8500_debug_resources,
+ },
+#endif
+ {
+ .name = "ab8500-sysctrl",
+ },
+ {
+ .name = "ab8500-regulator",
+ },
{
.name = "ab8500-gpadc",
.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
@@ -348,10 +648,43 @@ static struct mfd_cell ab8500_devs[] = {
.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
.resources = ab8500_rtc_resources,
},
- { .name = "ab8500-charger", },
- { .name = "ab8500-audio", },
- { .name = "ab8500-usb", },
- { .name = "ab8500-pwm", },
+ {
+ .name = "ab8500-bm",
+ .num_resources = ARRAY_SIZE(ab8500_bm_resources),
+ .resources = ab8500_bm_resources,
+ },
+ { .name = "ab8500-codec", },
+ {
+ .name = "ab8500-usb",
+ .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+ .resources = ab8500_usb_resources,
+ },
+ {
+ .name = "ab8500-poweron-key",
+ .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+ .resources = ab8500_poweronkey_db_resources,
+ },
+ {
+ .name = "ab8500-pwm",
+ .id = 1,
+ },
+ {
+ .name = "ab8500-pwm",
+ .id = 2,
+ },
+ {
+ .name = "ab8500-pwm",
+ .id = 3,
+ },
+ { .name = "ab8500-leds", },
+ {
+ .name = "ab8500-denc",
+ },
+ {
+ .name = "ab8500-temp",
+ .num_resources = ARRAY_SIZE(ab8500_temp_resources),
+ .resources = ab8500_temp_resources,
+ },
};
int __devinit ab8500_init(struct ab8500 *ab8500)
@@ -359,6 +692,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
int ret;
int i;
+ u8 value;
if (plat)
ab8500->irq_base = plat->irq_base;
@@ -366,7 +700,11 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
mutex_init(&ab8500->lock);
mutex_init(&ab8500->irq_lock);
- ret = ab8500_read(ab8500, AB8500_REV_REG);
+ /* This should be removed when all subdrivers are migrated */
+ ab8500_depr = ab8500;
+
+ ret = get_register_interruptible(ab8500, AB8500_MISC,
+ AB8500_REV_REG, &value);
if (ret < 0)
return ret;
@@ -375,29 +713,43 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
* 0x10 - Cut 1.0
* 0x11 - Cut 1.1
*/
- if (ret == 0x0 || ret == 0x10 || ret == 0x11) {
- ab8500->revision = ret;
- dev_info(ab8500->dev, "detected chip, revision: %#x\n", ret);
+ if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20) {
+ dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
} else {
- dev_err(ab8500->dev, "unknown chip, revision: %#x\n", ret);
+ dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
return -EINVAL;
}
+ ab8500->chip_id = value;
if (plat && plat->init)
plat->init(ab8500);
/* Clear and mask all interrupts */
for (i = 0; i < 10; i++) {
- ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i);
- ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff);
+ get_register_interruptible(ab8500, AB8500_INTERRUPT,
+ AB8500_IT_LATCH1_REG + i, &value);
+ set_register_interruptible(ab8500, AB8500_INTERRUPT,
+ AB8500_IT_MASK1_REG + i, 0xff);
}
-
- for (i = 18; i < 24; i++) {
- ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i);
- ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff);
+ if (ab8500->chip_id >= 0x20) {
+ get_register_interruptible(ab8500, AB8500_INTERRUPT,
+ AB8500_IT_LATCH12_REG, &value);
+ set_register_interruptible(ab8500, AB8500_INTERRUPT,
+ AB8500_IT_MASK12_REG, 0xff);
+ }
+ for (i = 18; i < 22; i++) {
+ get_register_interruptible(ab8500, AB8500_INTERRUPT,
+ AB8500_IT_LATCH1_REG + i, &value);
+ set_register_interruptible(ab8500, AB8500_INTERRUPT,
+ AB8500_IT_MASK1_REG + i, 0xff);
}
- for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
+ ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
+ if (ret)
+ return ret;
+
+ /* Last element is MASK12 */
+ for (i = 0; i < AB8500_NUM_IRQ_REGS + 1; i++)
ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
if (ab8500->irq_base) {
@@ -411,7 +763,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
goto out_removeirq;
}
- ret = mfd_add_devices(ab8500->dev, -1, ab8500_devs,
+ ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
ARRAY_SIZE(ab8500_devs), NULL,
ab8500->irq_base);
if (ret)
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
new file mode 100644
index 00000000000..7345ff99b07
--- /dev/null
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -0,0 +1,845 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson.
+ * License Terms: GNU General Public License v2
+ */
+
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/ab8500.h>
+
+static u32 debug_bank;
+static u32 debug_address;
+
+static int irq_first;
+static int irq_last;
+
+/**
+ * struct ab8500_reg_range
+ * @first: the first address of the range
+ * @last: the last address of the range
+ * @perm: access permissions for the range
+ */
+struct ab8500_reg_range {
+ u8 first;
+ u8 last;
+ u8 perm;
+};
+
+/**
+ * struct ab8500_i2c_ranges
+ * @num_ranges: the number of ranges in the list
+ * @bankid: bank identifier
+ * @range: the list of register ranges
+ */
+struct ab8500_i2c_ranges {
+ u8 num_ranges;
+ u8 bankid;
+ const struct ab8500_reg_range *range;
+};
+
+#define AB8500_NAME_STRING "ab8500"
+#define AB8500_NUM_BANKS 22
+
+#define AB8500_REV_REG 0x80
+
+static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = {
+ [0x0] = {
+ .num_ranges = 0,
+ .range = 0,
+ },
+ [AB8500_SYS_CTRL1_BLOCK] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x02,
+ },
+ {
+ .first = 0x42,
+ .last = 0x42,
+ },
+ {
+ .first = 0x80,
+ .last = 0x81,
+ },
+ },
+ },
+ [AB8500_SYS_CTRL2_BLOCK] = {
+ .num_ranges = 4,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0D,
+ },
+ {
+ .first = 0x0F,
+ .last = 0x17,
+ },
+ {
+ .first = 0x30,
+ .last = 0x30,
+ },
+ {
+ .first = 0x32,
+ .last = 0x33,
+ },
+ },
+ },
+ [AB8500_REGU_CTRL1] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x03,
+ .last = 0x10,
+ },
+ {
+ .first = 0x80,
+ .last = 0x84,
+ },
+ },
+ },
+ [AB8500_REGU_CTRL2] = {
+ .num_ranges = 5,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x15,
+ },
+ {
+ .first = 0x17,
+ .last = 0x19,
+ },
+ {
+ .first = 0x1B,
+ .last = 0x1D,
+ },
+ {
+ .first = 0x1F,
+ .last = 0x22,
+ },
+ {
+ .first = 0x40,
+ .last = 0x44,
+ },
+ /* 0x80-0x8B is SIM registers and should
+ * not be accessed from here */
+ },
+ },
+ [AB8500_USB] = {
+ .num_ranges = 2,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x80,
+ .last = 0x83,
+ },
+ {
+ .first = 0x87,
+ .last = 0x8A,
+ },
+ },
+ },
+ [AB8500_TVOUT] = {
+ .num_ranges = 9,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x12,
+ },
+ {
+ .first = 0x15,
+ .last = 0x17,
+ },
+ {
+ .first = 0x19,
+ .last = 0x21,
+ },
+ {
+ .first = 0x27,
+ .last = 0x2C,
+ },
+ {
+ .first = 0x41,
+ .last = 0x41,
+ },
+ {
+ .first = 0x45,
+ .last = 0x5B,
+ },
+ {
+ .first = 0x5D,
+ .last = 0x5D,
+ },
+ {
+ .first = 0x69,
+ .last = 0x69,
+ },
+ {
+ .first = 0x80,
+ .last = 0x81,
+ },
+ },
+ },
+ [AB8500_DBI] = {
+ .num_ranges = 0,
+ .range = 0,
+ },
+ [AB8500_ECI_AV_ACC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x80,
+ .last = 0x82,
+ },
+ },
+ },
+ [0x9] = {
+ .num_ranges = 0,
+ .range = 0,
+ },
+ [AB8500_GPADC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x08,
+ },
+ },
+ },
+ [AB8500_CHARGER] = {
+ .num_ranges = 8,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x03,
+ },
+ {
+ .first = 0x05,
+ .last = 0x05,
+ },
+ {
+ .first = 0x40,
+ .last = 0x40,
+ },
+ {
+ .first = 0x42,
+ .last = 0x42,
+ },
+ {
+ .first = 0x44,
+ .last = 0x44,
+ },
+ {
+ .first = 0x50,
+ .last = 0x55,
+ },
+ {
+ .first = 0x80,
+ .last = 0x82,
+ },
+ {
+ .first = 0xC0,
+ .last = 0xC2,
+ },
+ },
+ },
+ [AB8500_GAS_GAUGE] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x07,
+ .last = 0x0A,
+ },
+ {
+ .first = 0x10,
+ .last = 0x14,
+ },
+ },
+ },
+ [AB8500_AUDIO] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x6F,
+ },
+ },
+ },
+ [AB8500_INTERRUPT] = {
+ .num_ranges = 0,
+ .range = 0,
+ },
+ [AB8500_RTC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0F,
+ },
+ },
+ },
+ [AB8500_MISC] = {
+ .num_ranges = 8,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x05,
+ },
+ {
+ .first = 0x10,
+ .last = 0x15,
+ },
+ {
+ .first = 0x20,
+ .last = 0x25,
+ },
+ {
+ .first = 0x30,
+ .last = 0x35,
+ },
+ {
+ .first = 0x40,
+ .last = 0x45,
+ },
+ {
+ .first = 0x50,
+ .last = 0x50,
+ },
+ {
+ .first = 0x60,
+ .last = 0x67,
+ },
+ {
+ .first = 0x80,
+ .last = 0x80,
+ },
+ },
+ },
+ [0x11] = {
+ .num_ranges = 0,
+ .range = 0,
+ },
+ [0x12] = {
+ .num_ranges = 0,
+ .range = 0,
+ },
+ [0x13] = {
+ .num_ranges = 0,
+ .range = 0,
+ },
+ [0x14] = {
+ .num_ranges = 0,
+ .range = 0,
+ },
+ [AB8500_OTP_EMUL] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x01,
+ .last = 0x0F,
+ },
+ },
+ },
+};
+
+static irqreturn_t ab8500_debug_handler(int irq, void *data)
+{
+ char buf[16];
+ struct kobject *kobj = (struct kobject *)data;
+
+ /*
+ * This makes it possible to use poll for events (POLLPRI | POLLERR)
+ * from userspace on sysfs file named irq-<nr>
+ */
+ sprintf(buf, "irq-%d", irq);
+ sysfs_notify(kobj, NULL, buf);
+
+ return IRQ_HANDLED;
+}
+
+static int ab8500_registers_print(struct seq_file *s, void *p)
+{
+ struct device *dev = s->private;
+ unsigned int i;
+ u32 bank = debug_bank;
+
+ seq_printf(s, AB8500_NAME_STRING " register values:\n");
+
+ seq_printf(s, " bank %u:\n", bank);
+ for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
+ u32 reg;
+
+ for (reg = debug_ranges[bank].range[i].first;
+ reg <= debug_ranges[bank].range[i].last;
+ reg++) {
+ u8 value;
+ int err;
+
+ err = abx500_get_register_interruptible(dev,
+ (u8)bank, (u8)reg, &value);
+ if (err < 0) {
+ dev_err(dev, "ab->read fail %d\n", err);
+ return err;
+ }
+
+ err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank,
+ reg, value);
+ if (err < 0) {
+ dev_err(dev, "seq_printf overflow\n");
+ /* Error is not returned here since
+ * the output is wanted in any case */
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+static int ab8500_registers_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_registers_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_registers_fops = {
+ .open = ab8500_registers_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_bank_print(struct seq_file *s, void *p)
+{
+ return seq_printf(s, "%d\n", debug_bank);
+}
+
+static int ab8500_bank_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_bank_print, inode->i_private);
+}
+
+static ssize_t ab8500_bank_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_bank;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_bank);
+ if (err)
+ return -EINVAL;
+
+ if (user_bank >= AB8500_NUM_BANKS) {
+ dev_err(dev, "debugfs error input > number of banks\n");
+ return -EINVAL;
+ }
+
+ debug_bank = user_bank;
+
+ return buf_size;
+}
+
+static int ab8500_address_print(struct seq_file *s, void *p)
+{
+ return seq_printf(s, "0x%02X\n", debug_address);
+}
+
+static int ab8500_address_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_address_print, inode->i_private);
+}
+
+static ssize_t ab8500_address_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_address;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_address);
+ if (err)
+ return -EINVAL;
+ if (user_address > 0xff) {
+ dev_err(dev, "debugfs error input > 0xff\n");
+ return -EINVAL;
+ }
+ debug_address = user_address;
+ return buf_size;
+}
+
+static int ab8500_val_print(struct seq_file *s, void *p)
+{
+ struct device *dev = s->private;
+ int ret;
+ u8 regvalue;
+
+ ret = abx500_get_register_interruptible(dev,
+ (u8)debug_bank, (u8)debug_address, &regvalue);
+ if (ret < 0) {
+ dev_err(dev, "abx500_get_reg fail %d, %d\n",
+ ret, __LINE__);
+ return -EINVAL;
+ }
+ seq_printf(s, "0x%02X\n", regvalue);
+
+ return 0;
+}
+
+static int ab8500_val_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_val_print, inode->i_private);
+}
+
+static ssize_t ab8500_val_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_val;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_val);
+ if (err)
+ return -EINVAL;
+ if (user_val > 0xff) {
+ dev_err(dev, "debugfs error input > 0xff\n");
+ return -EINVAL;
+ }
+ err = abx500_set_register_interruptible(dev,
+ (u8)debug_bank, debug_address, (u8)user_val);
+ if (err < 0) {
+ printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
+ return -EINVAL;
+ }
+ return buf_size;
+}
+
+static int ab8500_subscribe_unsubscribe_print(struct seq_file *s, void *p)
+{
+ seq_printf(s, "%d\n", irq_first);
+
+ return 0;
+}
+
+static int ab8500_subscribe_unsubscribe_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_subscribe_unsubscribe_print,
+ inode->i_private);
+}
+
+/*
+ * This function is used for all interrupts and will always print
+ * the same string. It is however this file sysfs_notify called on.
+ * Userspace should read this file and then poll. When an event occur
+ * the blocking poll will be released.
+ */
+static ssize_t show_irq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "irq\n");
+}
+
+static struct device_attribute *dev_attr[AB8500_NR_IRQS];
+static char *event_name[AB8500_NR_IRQS];
+
+static ssize_t ab8500_subscribe_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_val;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_val);
+ if (err)
+ return -EINVAL;
+ if (user_val < irq_first) {
+ dev_err(dev, "debugfs error input < %d\n", irq_first);
+ return -EINVAL;
+ }
+ if (user_val > irq_last) {
+ dev_err(dev, "debugfs error input > %d\n", irq_last);
+ return -EINVAL;
+ }
+
+ /*
+ * This will create a sysfs file named irq-<nr> which userspace can
+ * use to select or poll and get the AB8500 events
+ */
+ dev_attr[user_val] = kmalloc(sizeof(struct device_attribute),
+ GFP_KERNEL);
+ event_name[user_val] = kmalloc(buf_size, GFP_KERNEL);
+ sprintf(event_name[user_val], "irq-%lu", user_val);
+ dev_attr[user_val]->show = show_irq;
+ dev_attr[user_val]->store = NULL;
+ dev_attr[user_val]->attr.name = event_name[user_val];
+ dev_attr[user_val]->attr.mode = S_IRUGO;
+ err = sysfs_create_file(&dev->kobj, &dev_attr[user_val]->attr);
+ if (err < 0) {
+ printk(KERN_ERR "sysfs_create_file failed %d\n", err);
+ return err;
+ }
+
+ err = request_threaded_irq(user_val, NULL, ab8500_debug_handler,
+ 0, "ab8500-debug", &dev->kobj);
+ if (err < 0) {
+ printk(KERN_ERR "request_threaded_irq failed %d, %lu\n",
+ err, user_val);
+ return err;
+ }
+
+ return buf_size;
+}
+
+static ssize_t ab8500_unsubscribe_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_val;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_val);
+ if (err)
+ return -EINVAL;
+ if (user_val < irq_first) {
+ dev_err(dev, "debugfs error input < %d\n", irq_first);
+ return -EINVAL;
+ }
+ if (user_val > irq_last) {
+ dev_err(dev, "debugfs error input > %d\n", irq_last);
+ return -EINVAL;
+ }
+
+ free_irq(user_val, &dev->kobj);
+ kfree(event_name[user_val]);
+ kfree(dev_attr[user_val]);
+
+ if (dev_attr[user_val])
+ sysfs_remove_file(&dev->kobj, &dev_attr[user_val]->attr);
+
+ return buf_size;
+}
+
+static const struct file_operations ab8500_bank_fops = {
+ .open = ab8500_bank_open,
+ .write = ab8500_bank_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_address_fops = {
+ .open = ab8500_address_open,
+ .write = ab8500_address_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_val_fops = {
+ .open = ab8500_val_open,
+ .write = ab8500_val_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_subscribe_fops = {
+ .open = ab8500_subscribe_unsubscribe_open,
+ .write = ab8500_subscribe_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_unsubscribe_fops = {
+ .open = ab8500_subscribe_unsubscribe_open,
+ .write = ab8500_unsubscribe_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static struct dentry *ab8500_dir;
+static struct dentry *ab8500_reg_file;
+static struct dentry *ab8500_bank_file;
+static struct dentry *ab8500_address_file;
+static struct dentry *ab8500_val_file;
+static struct dentry *ab8500_subscribe_file;
+static struct dentry *ab8500_unsubscribe_file;
+
+static int __devinit ab8500_debug_probe(struct platform_device *plf)
+{
+ debug_bank = AB8500_MISC;
+ debug_address = AB8500_REV_REG & 0x00FF;
+
+ irq_first = platform_get_irq_byname(plf, "IRQ_FIRST");
+ if (irq_first < 0) {
+ dev_err(&plf->dev, "First irq not found, err %d\n",
+ irq_first);
+ return irq_first;
+ }
+
+ irq_last = platform_get_irq_byname(plf, "IRQ_LAST");
+ if (irq_last < 0) {
+ dev_err(&plf->dev, "Last irq not found, err %d\n",
+ irq_last);
+ return irq_last;
+ }
+
+ ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
+ if (!ab8500_dir)
+ goto exit_no_debugfs;
+
+ ab8500_reg_file = debugfs_create_file("all-bank-registers",
+ S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
+ if (!ab8500_reg_file)
+ goto exit_destroy_dir;
+
+ ab8500_bank_file = debugfs_create_file("register-bank",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops);
+ if (!ab8500_bank_file)
+ goto exit_destroy_reg;
+
+ ab8500_address_file = debugfs_create_file("register-address",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
+ &ab8500_address_fops);
+ if (!ab8500_address_file)
+ goto exit_destroy_bank;
+
+ ab8500_val_file = debugfs_create_file("register-value",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops);
+ if (!ab8500_val_file)
+ goto exit_destroy_address;
+
+ ab8500_subscribe_file = debugfs_create_file("irq-subscribe",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
+ &ab8500_subscribe_fops);
+ if (!ab8500_subscribe_file)
+ goto exit_destroy_val;
+
+ ab8500_unsubscribe_file = debugfs_create_file("irq-unsubscribe",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
+ &ab8500_unsubscribe_fops);
+ if (!ab8500_unsubscribe_file)
+ goto exit_destroy_subscribe;
+ return 0;
+
+exit_destroy_subscribe:
+ debugfs_remove(ab8500_subscribe_file);
+exit_destroy_val:
+ debugfs_remove(ab8500_val_file);
+exit_destroy_address:
+ debugfs_remove(ab8500_address_file);
+exit_destroy_bank:
+ debugfs_remove(ab8500_bank_file);
+exit_destroy_reg:
+ debugfs_remove(ab8500_reg_file);
+exit_destroy_dir:
+ debugfs_remove(ab8500_dir);
+exit_no_debugfs:
+ dev_err(&plf->dev, "failed to create debugfs entries.\n");
+ return -ENOMEM;
+}
+
+static int __devexit ab8500_debug_remove(struct platform_device *plf)
+{
+ debugfs_remove(ab8500_val_file);
+ debugfs_remove(ab8500_address_file);
+ debugfs_remove(ab8500_bank_file);
+ debugfs_remove(ab8500_reg_file);
+ debugfs_remove(ab8500_dir);
+
+ return 0;
+}
+
+static struct platform_driver ab8500_debug_driver = {
+ .driver = {
+ .name = "ab8500-debug",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_debug_probe,
+ .remove = __devexit_p(ab8500_debug_remove)
+};
+
+static int __init ab8500_debug_init(void)
+{
+ return platform_driver_register(&ab8500_debug_driver);
+}
+
+static void __exit ab8500_debug_exit(void)
+{
+ platform_driver_unregister(&ab8500_debug_driver);
+}
+subsys_initcall(ab8500_debug_init);
+module_exit(ab8500_debug_exit);
+
+MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com");
+MODULE_DESCRIPTION("AB8500 DEBUG");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c
new file mode 100644
index 00000000000..ad2e8928214
--- /dev/null
+++ b/drivers/mfd/ab8500-i2c.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson.
+ * License Terms: GNU General Public License v2
+ * This file was based on drivers/mfd/ab8500-spi.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/ab8500.h>
+
+#include <mach/prcmu-fw-api.h>
+
+static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
+{
+ int ret;
+
+ ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
+ if (ret < 0)
+ dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
+ return ret;
+}
+
+static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
+{
+ int ret;
+ u8 data;
+
+ ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
+ if (ret < 0) {
+ dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
+ return ret;
+ }
+ return (int)data;
+}
+
+static int __devinit ab8500_i2c_probe(struct platform_device *plf)
+{
+ struct ab8500 *ab8500;
+ struct resource *resource;
+ int ret;
+
+ ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
+ if (!ab8500)
+ return -ENOMEM;
+
+ ab8500->dev = &plf->dev;
+
+ resource = platform_get_resource(plf, IORESOURCE_IRQ, 0);
+ if (!resource) {
+ kfree(ab8500);
+ return -ENODEV;
+ }
+
+ ab8500->irq = resource->start;
+
+ ab8500->read = ab8500_i2c_read;
+ ab8500->write = ab8500_i2c_write;
+
+ platform_set_drvdata(plf, ab8500);
+
+ ret = ab8500_init(ab8500);
+ if (ret)
+ kfree(ab8500);
+
+ return ret;
+}
+
+static int __devexit ab8500_i2c_remove(struct platform_device *plf)
+{
+ struct ab8500 *ab8500 = platform_get_drvdata(plf);
+
+ ab8500_exit(ab8500);
+ kfree(ab8500);
+
+ return 0;
+}
+
+static struct platform_driver ab8500_i2c_driver = {
+ .driver = {
+ .name = "ab8500-i2c",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_i2c_probe,
+ .remove = __devexit_p(ab8500_i2c_remove)
+};
+
+static int __init ab8500_i2c_init(void)
+{
+ return platform_driver_register(&ab8500_i2c_driver);
+}
+
+static void __exit ab8500_i2c_exit(void)
+{
+ platform_driver_unregister(&ab8500_i2c_driver);
+}
+subsys_initcall(ab8500_i2c_init);
+module_exit(ab8500_i2c_exit);
+
+MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com");
+MODULE_DESCRIPTION("AB8500 Core access via PRCMU I2C");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/ab8500-spi.c b/drivers/mfd/ab8500-spi.c
index b81d4f768ef..b1653421edb 100644
--- a/drivers/mfd/ab8500-spi.c
+++ b/drivers/mfd/ab8500-spi.c
@@ -68,7 +68,12 @@ static int ab8500_spi_read(struct ab8500 *ab8500, u16 addr)
ret = spi_sync(spi, &msg);
if (!ret)
- ret = ab8500->rx_buf[0];
+ /*
+ * Only the 8 lowermost bytes are
+ * defined with value, the rest may
+ * vary depending on chip/board noise.
+ */
+ ret = ab8500->rx_buf[0] & 0xFFU;
return ret;
}
@@ -78,6 +83,11 @@ static int __devinit ab8500_spi_probe(struct spi_device *spi)
struct ab8500 *ab8500;
int ret;
+ spi->bits_per_word = 24;
+ ret = spi_setup(spi);
+ if (ret < 0)
+ return ret;
+
ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
if (!ab8500)
return -ENOMEM;
@@ -109,7 +119,7 @@ static int __devexit ab8500_spi_remove(struct spi_device *spi)
static struct spi_driver ab8500_spi_driver = {
.driver = {
- .name = "ab8500",
+ .name = "ab8500-spi",
.owner = THIS_MODULE,
},
.probe = ab8500_spi_probe,
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
new file mode 100644
index 00000000000..b1e2fe255db
--- /dev/null
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500.h>
+
+static struct device *sysctrl_dev;
+
+static inline bool valid_bank(u8 bank)
+{
+ return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
+ (bank == AB8500_SYS_CTRL2_BLOCK));
+}
+
+int ab8500_sysctrl_read(u16 reg, u8 *value)
+{
+ u8 bank;
+
+ if (sysctrl_dev == NULL)
+ return -EAGAIN;
+
+ bank = (reg >> 8);
+ if (!valid_bank(bank))
+ return -EINVAL;
+
+ return abx500_get_register_interruptible(sysctrl_dev, bank,
+ (u8)(reg & 0xFF), value);
+}
+
+int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
+{
+ u8 bank;
+
+ if (sysctrl_dev == NULL)
+ return -EAGAIN;
+
+ bank = (reg >> 8);
+ if (!valid_bank(bank))
+ return -EINVAL;
+
+ return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank,
+ (u8)(reg & 0xFF), mask, value);
+}
+
+static int __devinit ab8500_sysctrl_probe(struct platform_device *pdev)
+{
+ sysctrl_dev = &pdev->dev;
+ return 0;
+}
+
+static int __devexit ab8500_sysctrl_remove(struct platform_device *pdev)
+{
+ sysctrl_dev = NULL;
+ return 0;
+}
+
+static struct platform_driver ab8500_sysctrl_driver = {
+ .driver = {
+ .name = "ab8500-sysctrl",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_sysctrl_probe,
+ .remove = __devexit_p(ab8500_sysctrl_remove),
+};
+
+static int __init ab8500_sysctrl_init(void)
+{
+ return platform_driver_register(&ab8500_sysctrl_driver);
+}
+subsys_initcall(ab8500_sysctrl_init);
+
+MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com");
+MODULE_DESCRIPTION("AB8500 system control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/cg2900/Makefile b/drivers/mfd/cg2900/Makefile
new file mode 100644
index 00000000000..8f900b1ac5f
--- /dev/null
+++ b/drivers/mfd/cg2900/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for ST-Ericsson CG2900 connectivity multifunction miscellaneous devices
+#
+#EXTRA_CFLAGS += $(KBUILD_GCOV_FLAGS)
+
+obj-$(CONFIG_MFD_CG2900) += cg2900.o
+cg2900-objs := cg2900_core.o cg2900_uart.o cg2900_char_devices.o
+export-objs := cg2900_core.o
+
+obj-$(CONFIG_MFD_CG2900_AUDIO) += cg2900_audio.o
+
+obj-$(CONFIG_MFD_CG2900_CHIP) += cg2900_chip.o
+obj-$(CONFIG_MFD_STLC2690_CHIP) += stlc2690_chip.o
diff --git a/drivers/mfd/cg2900/cg2900_audio.c b/drivers/mfd/cg2900/cg2900_audio.c
new file mode 100644
index 00000000000..e5713f1dd91
--- /dev/null
+++ b/drivers/mfd/cg2900/cg2900_audio.c
@@ -0,0 +1,2872 @@
+/*
+ * drivers/mfd/cg2900/cg2900_audio.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth Audio Driver for ST-Ericsson CG2900 controller.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/poll.h>
+#include <linux/cdev.h>
+#include <linux/mfd/cg2900.h>
+#include <linux/mfd/cg2900_audio.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/skbuff.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+
+#include "cg2900_debug.h"
+#include "hci_defines.h"
+#include "cg2900_chip.h"
+
+/* Char device op codes */
+#define OP_CODE_SET_DAI_CONF 0x01
+#define OP_CODE_GET_DAI_CONF 0x02
+#define OP_CODE_CONFIGURE_ENDPOINT 0x03
+#define OP_CODE_START_STREAM 0x04
+#define OP_CODE_STOP_STREAM 0x05
+
+/* Device names */
+#define DEVICE_NAME "cg2900_audio"
+
+/* Type of channel used */
+#define BT_CHANNEL_USED 0x00
+#define FM_CHANNEL_USED 0x01
+
+#define MAX_NBR_OF_USERS 10
+#define FIRST_USER 1
+
+#define SET_RESP_STATE(__state_var, __new_state) \
+ CG2900_SET_STATE("resp_state", __state_var, __new_state)
+
+#define DEFAULT_SCO_HANDLE 0x0008
+
+/* Use a timeout of 5 seconds when waiting for a command response */
+#define RESP_TIMEOUT 5000
+
+/* Used to select proper API, ignoring subrevisions etc */
+enum chip_revision {
+ CHIP_REV_PG1,
+ CHIP_REV_PG2
+};
+
+/**
+ * enum chip_resp_state - State when communicating with the CG2900 controller.
+ * @IDLE: No outstanding packets to the controller.
+ * @WAITING: Packet has been sent to the controller. Waiting for
+ * response.
+ * @RESP_RECEIVED: Response from controller has been received but not yet
+ * handled.
+ */
+enum chip_resp_state {
+ IDLE,
+ WAITING,
+ RESP_RECEIVED
+};
+
+/**
+ * enum main_state - Main state for the CG2900 Audio driver.
+ * @OPENED: Audio driver has registered to CG2900 Core.
+ * @CLOSED: Audio driver is not registered to CG2900 Core.
+ * @RESET: A reset of CG2900 Core has occurred and no user has re-opened
+ * the audio driver.
+ */
+enum main_state {
+ OPENED,
+ CLOSED,
+ RESET
+};
+
+/**
+ * struct char_dev_info - CG2900 character device info structure.
+ * @session: Stored session for the char device.
+ * @stored_data: Data returned when executing last command, if any.
+ * @stored_data_len: Length of @stored_data in bytes.
+ * @management_mutex: Mutex for handling access to char dev management.
+ * @rw_mutex: Mutex for handling access to char dev writes and reads.
+ */
+struct char_dev_info {
+ int session;
+ u8 *stored_data;
+ int stored_data_len;
+ struct mutex management_mutex;
+ struct mutex rw_mutex;
+};
+
+/**
+ * struct audio_user - CG2900 audio user info structure.
+ * @session: Stored session for the char device.
+ * @resp_state: State for controller communications.
+ */
+struct audio_user {
+ int session;
+ enum chip_resp_state resp_state;
+};
+
+/**
+ * struct endpoint_list - List for storing endpoint configuration nodes.
+ * @ep_list: Pointer to first node in list.
+ * @management_mutex: Mutex for handling access to list.
+ */
+struct endpoint_list {
+ struct list_head ep_list;
+ struct mutex management_mutex;
+};
+
+/**
+ * struct endpoint_config_node - Node for storing endpoint configuration.
+ * @list: list_head struct.
+ * @endpoint_id: Endpoint ID.
+ * @config: Stored configuration for this endpoint.
+ */
+struct endpoint_config_node {
+ struct list_head list;
+ enum cg2900_audio_endpoint_id endpoint_id;
+ union cg2900_endpoint_config_union config;
+};
+
+/**
+ * struct audio_info - Main CG2900 Audio driver info structure.
+ * @state: Current state of the CG2900 Audio driver.
+ * @revision: Chip revision, used to select API.
+ * @dev: The misc device created by this driver.
+ * @dev_bt: CG2900 Core device registered by this driver for
+ * the BT audio channel.
+ * @dev_fm: CG2900 Core device registered by this driver for
+ * the FM audio channel.
+ * @management_mutex: Mutex for handling access to CG2900 Audio driver
+ * management.
+ * @bt_mutex: Mutex for handling access to BT audio channel.
+ * @fm_mutex: Mutex for handling access to FM audio channel.
+ * @nbr_of_users_active: Number of sessions open in the CG2900 Audio
+ * driver.
+ * @bt_queue: Received BT events.
+ * @fm_queue: Received FM events.
+ * @audio_sessions: Pointers to currently opened sessions (maps
+ * session ID to user info).
+ * @i2s_config: DAI I2S configuration.
+ * @i2s_pcm_config: DAI PCM_I2S configuration.
+ * @i2s_config_known: @true if @i2s_config has been set,
+ * @false otherwise.
+ * @i2s_pcm_config_known: @true if @i2s_pcm_config has been set,
+ * @false otherwise.
+ * @endpoints: List containing the endpoint configurations.
+ * @stream_ids: Bitmask for in-use stream ids (only used with
+ * PG2 chip API).
+ */
+struct audio_info {
+ enum main_state state;
+ enum chip_revision revision;
+ struct miscdevice dev;
+ struct cg2900_device *dev_bt;
+ struct cg2900_device *dev_fm;
+ struct mutex management_mutex;
+ struct mutex bt_mutex;
+ struct mutex fm_mutex;
+ int nbr_of_users_active;
+ struct sk_buff_head bt_queue;
+ struct sk_buff_head fm_queue;
+ struct audio_user *audio_sessions[MAX_NBR_OF_USERS];
+ struct cg2900_dai_conf_i2s i2s_config;
+ struct cg2900_dai_conf_i2s_pcm i2s_pcm_config;
+ bool i2s_config_known;
+ bool i2s_pcm_config_known;
+ struct endpoint_list endpoints;
+ u32 stream_ids;
+};
+
+/**
+ * struct audio_cb_info - Callback info structure registered in @user_data.
+ * @channel: Stores if this device handles BT or FM events.
+ * @user: Audio user currently awaiting data on the channel.
+ */
+struct audio_cb_info {
+ int channel;
+ struct audio_user *user;
+};
+
+/* cg2900_audio wait queues */
+static DECLARE_WAIT_QUEUE_HEAD(wq_bt);
+static DECLARE_WAIT_QUEUE_HEAD(wq_fm);
+
+static struct audio_info *audio_info;
+
+static struct audio_cb_info cb_info_bt = {
+ .channel = BT_CHANNEL_USED,
+ .user = NULL
+};
+static struct audio_cb_info cb_info_fm = {
+ .channel = FM_CHANNEL_USED,
+ .user = NULL
+};
+
+/*
+ * Internal conversion functions
+ *
+ * Since the CG2900 apis uses several different ways to encode the
+ * same parameter in different cases, we have to use translator
+ * functions.
+ */
+
+/**
+ * session_config_sample_rate() - Convert sample rate to format used in VS_Set_SessionConfiguration.
+ * @rate: Sample rate in API encoding.
+ */
+static u8 session_config_sample_rate(enum cg2900_endpoint_sample_rate rate)
+{
+ static const u8 codes[] = {
+ [ENDPOINT_SAMPLE_RATE_8_KHZ] = CG2900_BT_SESSION_RATE_8K,
+ [ENDPOINT_SAMPLE_RATE_16_KHZ] = CG2900_BT_SESSION_RATE_16K,
+ [ENDPOINT_SAMPLE_RATE_44_1_KHZ] = CG2900_BT_SESSION_RATE_44_1K,
+ [ENDPOINT_SAMPLE_RATE_48_KHZ] = CG2900_BT_SESSION_RATE_48K
+ };
+
+ return codes[rate];
+}
+
+/**
+ * mc_i2s_sample_rate() - Convert sample rate to format used in VS_Port_Config for I2S.
+ * @rate: Sample rate in API encoding.
+ */
+static u8 mc_i2s_sample_rate(enum cg2900_dai_sample_rate rate)
+{
+ static const u8 codes[] = {
+ [SAMPLE_RATE_8] = CG2900_MC_I2S_SAMPLE_RATE_8,
+ [SAMPLE_RATE_16] = CG2900_MC_I2S_SAMPLE_RATE_16,
+ [SAMPLE_RATE_44_1] = CG2900_MC_I2S_SAMPLE_RATE_44_1,
+ [SAMPLE_RATE_48] = CG2900_MC_I2S_SAMPLE_RATE_48
+ };
+
+ return codes[rate];
+}
+
+/**
+ * mc_pcm_sample_rate() - Convert sample rate to format used in VS_Port_Config for PCM/I2S.
+ * @rate: Sample rate in API encoding.
+ */
+static u8 mc_pcm_sample_rate(enum cg2900_dai_sample_rate rate)
+{
+ static const u8 codes[] = {
+ [SAMPLE_RATE_8] = CG2900_MC_PCM_SAMPLE_RATE_8,
+ [SAMPLE_RATE_16] = CG2900_MC_PCM_SAMPLE_RATE_16,
+ [SAMPLE_RATE_44_1] = CG2900_MC_PCM_SAMPLE_RATE_44_1,
+ [SAMPLE_RATE_48] = CG2900_MC_PCM_SAMPLE_RATE_48
+ };
+
+ return codes[rate];
+}
+
+/**
+ * mc_i2s_channel_select() - Convert channel selection to format used in VS_Port_Config.
+ * @sel: Channel selection in API encoding.
+ */
+static u8 mc_i2s_channel_select(enum cg2900_dai_channel_sel sel)
+{
+ static const u8 codes[] = {
+ [CHANNEL_SELECTION_RIGHT] = CG2900_MC_I2S_RIGHT_CHANNEL,
+ [CHANNEL_SELECTION_LEFT] = CG2900_MC_I2S_LEFT_CHANNEL,
+ [CHANNEL_SELECTION_BOTH] = CG2900_MC_I2S_BOTH_CHANNELS
+ };
+ return codes[sel];
+}
+
+/**
+ * get_fs_duration() - Convert framesync-enumeration to real value.
+ * @duration: Framsync duration (API encoding).
+ *
+ * Returns:
+ * Duration in bits.
+ */
+static u16 get_fs_duration(enum cg2900_dai_fs_duration duration)
+{
+ static const u16 values[] = {
+ [SYNC_DURATION_8] = 8,
+ [SYNC_DURATION_16] = 16,
+ [SYNC_DURATION_24] = 24,
+ [SYNC_DURATION_32] = 32,
+ [SYNC_DURATION_48] = 48,
+ [SYNC_DURATION_50] = 50,
+ [SYNC_DURATION_64] = 64,
+ [SYNC_DURATION_75] = 75,
+ [SYNC_DURATION_96] = 96,
+ [SYNC_DURATION_125] = 125,
+ [SYNC_DURATION_128] = 128,
+ [SYNC_DURATION_150] = 150,
+ [SYNC_DURATION_192] = 192,
+ [SYNC_DURATION_250] = 250,
+ [SYNC_DURATION_256] = 256,
+ [SYNC_DURATION_300] = 300,
+ [SYNC_DURATION_384] = 384,
+ [SYNC_DURATION_500] = 500,
+ [SYNC_DURATION_512] = 512,
+ [SYNC_DURATION_600] = 600,
+ [SYNC_DURATION_768] = 768
+ };
+ return values[duration];
+}
+
+/**
+ * mc_i2s_role() - Convert master/slave encoding to format for I2S-ports.
+ * @mode: Master/slave in API encoding.
+ */
+static u8 mc_i2s_role(enum cg2900_dai_mode mode)
+{
+ if (mode == DAI_MODE_SLAVE)
+ return CG2900_I2S_MODE_SLAVE;
+ else
+ return CG2900_I2S_MODE_MASTER;
+}
+
+/**
+ * mc_pcm_role() - Convert master/slave encoding to format for PCM/I2S-port.
+ * @mode: Master/slave in API encoding.
+ */
+static u8 mc_pcm_role(enum cg2900_dai_mode mode)
+{
+ if (mode == DAI_MODE_SLAVE)
+ return CG2900_PCM_MODE_SLAVE;
+ else
+ return CG2900_PCM_MODE_MASTER;
+}
+
+/**
+ * fm_get_conversion() - Convert sample rate to convert up/down used in X_Set_Control FM commands.
+ * @srate: Sample rate.
+ */
+static u16 fm_get_conversion(enum cg2900_endpoint_sample_rate srate)
+{
+ if (srate >= ENDPOINT_SAMPLE_RATE_44_1_KHZ)
+ return CG2900_FM_CMD_SET_CTRL_CONV_UP;
+ else
+ return CG2900_FM_CMD_SET_CTRL_CONV_DOWN;
+}
+
+/*
+ * Internal helper functions
+ */
+
+/**
+ * read_cb() - Handle data received from STE connectivity driver.
+ * @dev: Device receiving data.
+ * @skb: Buffer with data coming form device.
+ */
+static void read_cb(struct cg2900_device *dev, struct sk_buff *skb)
+{
+ struct audio_cb_info *cb_info;
+
+ CG2900_INFO("CG2900 Audio: read_cb");
+
+ if (!dev) {
+ CG2900_ERR("NULL supplied as dev");
+ return;
+ }
+
+ if (!skb) {
+ CG2900_ERR("NULL supplied as skb");
+ return;
+ }
+
+ cb_info = (struct audio_cb_info *)dev->user_data;
+ if (!cb_info) {
+ CG2900_ERR("NULL supplied as cb_info");
+ return;
+ }
+ if (!(cb_info->user)) {
+ CG2900_ERR("NULL supplied as cb_info->user");
+ return;
+ }
+
+ /* Mark that packet has been received */
+ SET_RESP_STATE(cb_info->user->resp_state, RESP_RECEIVED);
+
+ /* Handle packet depending on channel */
+ if (cb_info->channel == BT_CHANNEL_USED) {
+ skb_queue_tail(&(audio_info->bt_queue), skb);
+ wake_up_interruptible(&wq_bt);
+ } else if (cb_info->channel == FM_CHANNEL_USED) {
+ skb_queue_tail(&(audio_info->fm_queue), skb);
+ wake_up_interruptible(&wq_fm);
+ } else {
+ /* Unhandled channel; free the packet */
+ CG2900_ERR("Received callback on bad channel %d",
+ cb_info->channel);
+ kfree_skb(skb);
+ }
+}
+
+/**
+ * reset_cb() - Reset callback function.
+ * @dev: CG2900_Core device resetting.
+ */
+static void reset_cb(struct cg2900_device *dev)
+{
+ CG2900_INFO("CG2900 Audio: reset_cb");
+ mutex_lock(&audio_info->management_mutex);
+ audio_info->nbr_of_users_active = 0;
+ audio_info->state = RESET;
+ mutex_unlock(&audio_info->management_mutex);
+}
+
+static struct cg2900_callbacks cg2900_cb = {
+ .read_cb = read_cb,
+ .reset_cb = reset_cb
+};
+
+/**
+ * get_session_user() - Check that supplied session is within valid range.
+ * @session: Session ID.
+ *
+ * Returns:
+ * Audio_user if there is no error.
+ * NULL for bad session ID.
+ */
+static struct audio_user *get_session_user(int session)
+{
+ struct audio_user *audio_user;
+
+ if (session < FIRST_USER || session >= MAX_NBR_OF_USERS) {
+ CG2900_ERR("Calling with invalid session %d", session);
+ return NULL;
+ }
+
+ audio_user = audio_info->audio_sessions[session];
+ if (!audio_user)
+ CG2900_ERR("Calling with non-opened session %d", session);
+ return audio_user;
+}
+
+/**
+ * del_endpoint_private() - Deletes an endpoint from @list.
+ * @endpoint_id: Endpoint ID.
+ * @list: List of endpoints.
+ *
+ * Deletes an endpoint from the supplied endpoint list.
+ * This function is not protected by any semaphore.
+ */
+static void del_endpoint_private(enum cg2900_audio_endpoint_id endpoint_id,
+ struct endpoint_list *list)
+{
+ struct list_head *cursor, *next;
+ struct endpoint_config_node *tmp;
+
+ list_for_each_safe(cursor, next, &(list->ep_list)) {
+ tmp = list_entry(cursor, struct endpoint_config_node, list);
+ if (tmp->endpoint_id == endpoint_id) {
+ list_del(cursor);
+ kfree(tmp);
+ }
+ }
+}
+
+/**
+ * add_endpoint() - Add endpoint node to @list.
+ * @ep_config: Endpoint configuration.
+ * @list: List of endpoints.
+ *
+ * Add endpoint node to the supplied list and copies supplied config to node.
+ * If a node already exists for the supplied endpoint, the old node is removed
+ * and replaced by the new node.
+ */
+static void add_endpoint(struct cg2900_endpoint_config *ep_config,
+ struct endpoint_list *list)
+{
+ struct endpoint_config_node *item;
+
+ item = kzalloc(sizeof(*item), GFP_KERNEL);
+ if (!item) {
+ CG2900_ERR("Failed to alloc memory!");
+ return;
+ }
+
+ /* Store values */
+ item->endpoint_id = ep_config->endpoint_id;
+ memcpy(&(item->config), &(ep_config->config), sizeof(item->config));
+
+ mutex_lock(&(list->management_mutex));
+
+ /*
+ * Check if endpoint ID already exist in list.
+ * If that is the case, remove it.
+ */
+ if (!list_empty(&(list->ep_list)))
+ del_endpoint_private(ep_config->endpoint_id, list);
+
+ list_add_tail(&(item->list), &(list->ep_list));
+
+ mutex_unlock(&(list->management_mutex));
+}
+
+/**
+ * find_endpoint() - Finds endpoint identified by @endpoint_id in @list.
+ * @endpoint_id: Endpoint ID.
+ * @list: List of endpoints.
+ *
+ * Returns:
+ * Endpoint configuration if there is no error.
+ * NULL if no configuration can be found for @endpoint_id.
+ */
+static union cg2900_endpoint_config_union *
+find_endpoint(enum cg2900_audio_endpoint_id endpoint_id,
+ struct endpoint_list *list)
+{
+ struct list_head *cursor, *next;
+ struct endpoint_config_node *tmp;
+ struct endpoint_config_node *ret_ep = NULL;
+
+ mutex_lock(&list->management_mutex);
+ list_for_each_safe(cursor, next, &(list->ep_list)) {
+ tmp = list_entry(cursor, struct endpoint_config_node, list);
+ if (tmp->endpoint_id == endpoint_id) {
+ ret_ep = tmp;
+ break;
+ }
+ }
+ mutex_unlock(&list->management_mutex);
+
+ if (ret_ep)
+ return &(ret_ep->config);
+ else
+ return NULL;
+}
+
+/**
+ * flush_endpoint_list() - Deletes all stored endpoints in @list.
+ * @list: List of endpoints.
+ */
+static void flush_endpoint_list(struct endpoint_list *list)
+{
+ struct list_head *cursor, *next;
+ struct endpoint_config_node *tmp;
+
+ mutex_lock(&list->management_mutex);
+ list_for_each_safe(cursor, next, &(list->ep_list)) {
+ tmp = list_entry(cursor, struct endpoint_config_node, list);
+ list_del(cursor);
+ kfree(tmp);
+ }
+ mutex_unlock(&list->management_mutex);
+}
+
+/**
+ * new_stream_id() - Allocate a new stream id.
+ *
+ * Returns:
+ * 0-127 new valid id.
+ * -ENOMEM if no id is available.
+ */
+static s8 new_stream_id(void)
+{
+ int r;
+
+ mutex_lock(&audio_info->management_mutex);
+
+ r = find_first_zero_bit(&audio_info->stream_ids,
+ 8 * sizeof(audio_info->stream_ids));
+
+ if (r >= 8 * sizeof(audio_info->stream_ids)) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ audio_info->stream_ids |= (0x01u << r);
+
+out:
+ mutex_unlock(&audio_info->management_mutex);
+ return r;
+}
+
+/**
+ * release_stream_id() - Release a stream id.
+ * @id: stream to release.
+ */
+static void release_stream_id(u8 id)
+{
+ if (id >= 8 * sizeof(audio_info->stream_ids))
+ return;
+
+ mutex_lock(&audio_info->management_mutex);
+ audio_info->stream_ids &= ~(0x01u << id);
+ mutex_unlock(&audio_info->management_mutex);
+}
+
+/**
+ * receive_fm_write_response() - Wait for and handle the response to an FM Legacy WriteCommand request.
+ * @audio_user: Audio user to check for.
+ * @command: FM command to wait for.
+ *
+ * This function first waits (up to 5 seconds) for a response to an FM
+ * write command and when one arrives, it checks that it is the one we
+ * are waiting for and also that no error has occurred.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ECOMM if no response was received.
+ * -EIO for other errors.
+ */
+static int receive_fm_write_response(struct audio_user *audio_user,
+ u16 command)
+{
+ int err = 0;
+ struct sk_buff *skb;
+ struct fm_leg_cmd_cmpl *pkt;
+ u16 rsp_cmd;
+
+ /*
+ * Wait for callback to receive command complete and then wake us up
+ * again.
+ */
+ if (0 >= wait_event_interruptible_timeout(wq_fm,
+ audio_user->resp_state == RESP_RECEIVED,
+ msecs_to_jiffies(RESP_TIMEOUT))) {
+ /* We timed out or an error occurred */
+ CG2900_ERR("Error occurred while waiting for return packet.");
+ return -ECOMM;
+ }
+
+ /* OK, now we should have received answer. Let's check it. */
+ skb = skb_dequeue_tail(&audio_info->fm_queue);
+ if (!skb) {
+ CG2900_ERR("No skb in queue when it should be there");
+ return -EIO;
+ }
+
+ pkt = (struct fm_leg_cmd_cmpl *)skb->data;
+
+ /* Check if we received the correct event */
+ if (pkt->opcode != CG2900_FM_GEN_ID_LEGACY) {
+ CG2900_ERR("Received unknown FM packet. 0x%X %X %X %X %X",
+ skb->data[0], skb->data[1], skb->data[2],
+ skb->data[3], skb->data[4]);
+ err = -EIO;
+ goto error_handling_free_skb;
+ }
+
+ /* FM Legacy Command complete event */
+ rsp_cmd = cg2900_get_fm_cmd_id(le16_to_cpu(pkt->response_head));
+
+ if (pkt->fm_function != CG2900_FM_CMD_PARAM_WRITECOMMAND ||
+ rsp_cmd != command) {
+ CG2900_ERR("Received unexpected packet func 0x%X cmd 0x%04X",
+ pkt->fm_function, rsp_cmd);
+ err = -EIO;
+ goto error_handling_free_skb;
+ }
+
+ if (pkt->cmd_status != CG2900_FM_CMD_STATUS_COMMAND_SUCCEEDED) {
+ CG2900_ERR("FM Command failed (%d)", pkt->cmd_status);
+ err = -EIO;
+ goto error_handling_free_skb;
+ }
+ /* Operation succeeded. We are now done */
+
+error_handling_free_skb:
+ kfree_skb(skb);
+ return err;
+}
+
+/**
+ * receive_bt_cmd_complete() - Wait for and handle an BT Command Complete event.
+ * @audio_user: Audio user to check for.
+ * @rsp: Opcode of BT command to wait for.
+ * @data: Pointer to buffer if any received data should be stored (except
+ * status).
+ * @data_len: Length of @data in bytes.
+ *
+ * This function first waits for BT Command Complete event (up to 5 seconds)
+ * and when one arrives, it checks that it is the one we are waiting for and
+ * also that no error has occurred.
+ * If @data is supplied it also copies received data into @data.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ECOMM if no response was received.
+ * -EIO for other errors.
+ */
+static int receive_bt_cmd_complete(struct audio_user *audio_user, u16 rsp,
+ void *data, int data_len)
+{
+ int err = 0;
+ struct sk_buff *skb;
+ struct bt_cmd_cmpl_event *evt;
+ u16 opcode;
+
+ /*
+ * Wait for callback to receive command complete and then wake us up
+ * again.
+ */
+ if (0 >= wait_event_interruptible_timeout(wq_bt,
+ audio_user->resp_state == RESP_RECEIVED,
+ msecs_to_jiffies(RESP_TIMEOUT))) {
+ /* We timed out or an error occurred */
+ CG2900_ERR("Error occurred while waiting for return packet.");
+ return -ECOMM;
+ }
+
+ /* OK, now we should have received answer. Let's check it. */
+ skb = skb_dequeue_tail(&audio_info->bt_queue);
+ if (!skb) {
+ CG2900_ERR("No skb in queue when it should be there");
+ return -EIO;
+ }
+
+ evt = (struct bt_cmd_cmpl_event *)skb->data;
+ if (evt->eventcode != HCI_BT_EVT_CMD_COMPLETE) {
+ CG2900_ERR("We did not receive the event we expected (0x%X)",
+ evt->eventcode);
+ err = -EIO;
+ goto error_handling_free_skb;
+ }
+
+ opcode = le16_to_cpu(evt->opcode);
+ if (opcode != rsp) {
+ CG2900_ERR("Received cmd complete for unexpected command: "
+ "0x%04X", opcode);
+ err = -EIO;
+ goto error_handling_free_skb;
+ }
+
+ if (evt->status != HCI_BT_ERROR_NO_ERROR) {
+ CG2900_ERR("Received command complete with err %d",
+ evt->status);
+ err = -EIO;
+ goto error_handling_free_skb;
+ }
+
+ /* Copy the rest of the parameters if a buffer has been supplied.
+ * The caller must have set the length correctly.
+ */
+ if (data)
+ memcpy(data, evt->data, data_len);
+
+ /* Operation succeeded. We are now done */
+
+error_handling_free_skb:
+ kfree_skb(skb);
+ return err;
+}
+
+/**
+ * send_vs_session_ctrl() - Formats an sends a CG2900_BT_VS_SESSION_CTRL command.
+ * @user: Audio user this command belongs to.
+ * @stream_handle: Handle to stream.
+ * @command: Command to execute on stream, should be one of
+ * CG2900_BT_SESSION_START, CG2900_BT_SESSION_STOP,
+ * CG2900_BT_SESSION_PAUSE, CG2900_BT_SESSION_RESUME.
+ *
+ * Packs and sends a command packet and waits for the response. Must
+ * be called with the bt_mutex held.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ENOMEM if not possible to allocate packet.
+ * -ECOMM if no response was received.
+ * -EIO for other errors.
+ */
+static int send_vs_session_ctrl(struct audio_user *user,
+ u8 stream_handle, u8 command)
+{
+ int err = 0;
+ struct bt_vs_session_ctrl_cmd *pkt;
+ struct sk_buff *skb;
+
+ CG2900_INFO("BT: HCI_VS_Session_Control");
+
+ skb = cg2900_alloc_skb(sizeof(*pkt), GFP_KERNEL);
+ if (!skb) {
+ CG2900_ERR("Could not allocate skb");
+ return -ENOMEM;
+ }
+
+ /* Enter data into the skb */
+ pkt = (struct bt_vs_session_ctrl_cmd *) skb_put(skb, sizeof(*pkt));
+
+ pkt->opcode = cpu_to_le16(CG2900_BT_VS_SESSION_CTRL);
+ pkt->plen = BT_PARAM_LEN(sizeof(*pkt));
+ pkt->id = stream_handle;
+ pkt->control = command; /* Start/stop etc */
+
+ cb_info_bt.user = user;
+ SET_RESP_STATE(user->resp_state, WAITING);
+
+ /* Send packet to controller */
+ err = cg2900_write(audio_info->dev_bt, skb);
+ if (err) {
+ CG2900_ERR("Error occurred while transmitting skb (%d)", err);
+ kfree_skb(skb);
+ goto finished;
+ }
+
+ err = receive_bt_cmd_complete(user, CG2900_BT_VS_SESSION_CTRL,
+ NULL, 0);
+finished:
+ SET_RESP_STATE(user->resp_state, IDLE);
+ return err;
+}
+
+/**
+ * send_vs_session_config() - Formats an sends a CG2900_BT_VS_SESSION_CONFIG command.
+ * @user: Audio user this command belongs to.
+ * @config_stream: Custom function for configuring the stream.
+ * @priv_data: Private data passed to @config_stream untouched.
+ *
+ * Packs and sends a command packet and waits for the response. Must
+ * be called with the bt_mutex held.
+ *
+ * Space is allocated for one stream and a custom function is used to
+ * fill in the stream configuration.
+ *
+ * Returns:
+ * 0-255 stream handle if no error.
+ * -ENOMEM if not possible to allocate packet.
+ * -ECOMM if no response was received.
+ * -EIO for other errors.
+ */
+static int send_vs_session_config(struct audio_user *user,
+ void(*config_stream)(void *, struct session_config_stream *),
+ void *priv_data)
+{
+ int err = 0;
+ struct sk_buff *skb;
+ struct bt_vs_session_config_cmd *pkt;
+ u8 session_id;
+
+ CG2900_INFO("BT: HCI_VS_Set_Session_Configuration");
+
+ skb = cg2900_alloc_skb(sizeof(*pkt), GFP_KERNEL);
+ if (!skb) {
+ CG2900_ERR("Could not allocate skb");
+ return -ENOMEM;
+ }
+
+ pkt = (struct bt_vs_session_config_cmd *)skb_put(skb, sizeof(*pkt));
+ /* zero the packet so we don't have to set all reserved fields */
+ memset(pkt, 0, sizeof(*pkt));
+
+ /* Common parameters */
+ pkt->opcode = cpu_to_le16(CG2900_BT_VS_SET_SESSION_CONFIG);
+ pkt->plen = BT_PARAM_LEN(sizeof(*pkt));
+ pkt->n_streams = 1; /* 1 stream configuration supplied */
+
+ /* Let the custom-function fill in the rest */
+ config_stream(priv_data, &pkt->stream);
+
+ cb_info_bt.user = user;
+ SET_RESP_STATE(user->resp_state, WAITING);
+
+ /* Send packet to controller */
+ err = cg2900_write(audio_info->dev_bt, skb);
+ if (err) {
+ CG2900_ERR("Error occurred while transmitting skb (%d)", err);
+ kfree_skb(skb);
+ goto finished;
+ }
+
+ err = receive_bt_cmd_complete(user,
+ CG2900_BT_VS_SET_SESSION_CONFIG,
+ &session_id, sizeof(session_id));
+ /* Return session id/stream handle if success */
+ if (!err)
+ err = session_id;
+
+finished:
+ SET_RESP_STATE(user->resp_state, IDLE);
+ return err;
+}
+
+/**
+ * send_fm_write_1_param() - Formats and sends an FM legacy write command with one parameter.
+ * @user: Audio user this command belongs to.
+ * @command: Command.
+ * @param: Parameter for command.
+ *
+ * Packs and sends a command packet and waits for the response. Must
+ * be called with the fm_mutex held.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ENOMEM if not possible to allocate packet.
+ * -ECOMM if no response was received.
+ * -EIO for other errors.
+ */
+static int send_fm_write_1_param(struct audio_user *user,
+ u16 command, u16 param)
+{
+ int err = 0;
+ struct sk_buff *skb;
+ struct fm_leg_cmd *cmd;
+ size_t len;
+
+ /* base package + one parameter */
+ len = sizeof(*cmd) + sizeof(cmd->fm_cmd.data[0]);
+
+ skb = cg2900_alloc_skb(len, GFP_KERNEL);
+ if (!skb) {
+ CG2900_ERR("Could not allocate skb");
+ return -ENOMEM;
+ }
+
+ cmd = (struct fm_leg_cmd *)skb_put(skb, len);
+
+ cmd->length = CG2900_FM_CMD_PARAM_LEN(len);
+ cmd->opcode = CG2900_FM_GEN_ID_LEGACY;
+ cmd->read_write = CG2900_FM_CMD_LEG_PARAM_WRITE;
+ cmd->fm_function = CG2900_FM_CMD_PARAM_WRITECOMMAND;
+ /* one parameter - builtin assumption for this function */
+ cmd->fm_cmd.head = cpu_to_le16(cg2900_make_fm_cmd_id(command, 1));
+ cmd->fm_cmd.data[0] = cpu_to_le16(param);
+
+ cb_info_fm.user = user;
+ SET_RESP_STATE(user->resp_state, WAITING);
+
+ /* Send packet to controller */
+ err = cg2900_write(audio_info->dev_fm, skb);
+ if (err) {
+ CG2900_ERR("Error occurred while transmitting skb (%d)", err);
+ kfree_skb(skb);
+ goto finished;
+ }
+
+ err = receive_fm_write_response(user, command);
+finished:
+ SET_RESP_STATE(user->resp_state, IDLE);
+ return err;
+}
+
+/**
+ * send_vs_stream_ctrl() - Formats an sends a CG2900_MC_VS_STREAM_CONTROL command.
+ * @user: Audio user this command belongs to.
+ * @stream: Stream id.
+ * @command: Start/stop etc.
+ *
+ * Packs and sends a command packet and waits for the response. Must
+ * be called with the bt_mutex held.
+ *
+ * While the HCI command allows for multiple streams in one command,
+ * this function only handles one.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ENOMEM if not possible to allocate packet.
+ * -ECOMM if no response was received.
+ * -EIO for other errors.
+ */
+static int send_vs_stream_ctrl(struct audio_user *user, u8 stream, u8 command)
+{
+ int err = 0;
+ struct sk_buff *skb;
+ struct mc_vs_stream_ctrl_cmd *cmd;
+ size_t len;
+ u8 vs_err;
+
+ /* basic length + one stream */
+ len = sizeof(*cmd) + sizeof(cmd->stream[0]);
+
+ skb = cg2900_alloc_skb(len, GFP_KERNEL);
+ if (!skb) {
+ CG2900_ERR("Could not allocate skb");
+ return -ENOMEM;
+ }
+
+ cmd = (struct mc_vs_stream_ctrl_cmd *)skb_put(skb, len);
+
+ cmd->opcode = cpu_to_le16(CG2900_MC_VS_STREAM_CONTROL);
+ cmd->plen = BT_PARAM_LEN(len);
+ cmd->command = command;
+
+ /* one stream */
+ cmd->n_streams = 1;
+ cmd->stream[0] = stream;
+
+ cb_info_bt.user = user;
+ SET_RESP_STATE(user->resp_state, WAITING);
+
+ /* Send packet to controller */
+ err = cg2900_write(audio_info->dev_bt, skb);
+ if (err) {
+ CG2900_ERR("Error occurred while transmitting skb (%d)", err);
+ kfree_skb(skb);
+ goto finished;
+ }
+
+ /* All commands in PG2 API returns one byte with extra status */
+ err = receive_bt_cmd_complete(user,
+ CG2900_MC_VS_STREAM_CONTROL,
+ &vs_err, sizeof(vs_err));
+ if (err)
+ CG2900_DBG("VS_STREAM_CONTROL - failed with error %02x",
+ vs_err);
+
+finished:
+ SET_RESP_STATE(user->resp_state, IDLE);
+ return err;
+}
+
+/**
+ * send_vs_create_stream() - Formats an sends a CG2900_MC_VS_CREATE_STREAM command.
+ * @user: Audio user this command belongs to.
+ * @inport: Stream id.
+ * @outport: Start/stop etc.
+ * @order: Activation order.
+ *
+ * Packs and sends a command packet and waits for the response. Must
+ * be called with the bt_mutex held.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ENOMEM if not possible to allocate packet.
+ * -ECOMM if no response was received.
+ * -EIO for other errors.
+ */
+static int send_vs_create_stream(struct audio_user *user, u8 inport,
+ u8 outport, u8 order)
+{
+ int err = 0;
+ struct sk_buff *skb;
+ struct mc_vs_create_stream_cmd *cmd;
+ s8 id;
+ u8 vs_err;
+
+ id = new_stream_id();
+ if (id < 0) {
+ CG2900_ERR("No free stream id");
+ err = -EIO;
+ goto finished;
+ }
+
+ skb = cg2900_alloc_skb(sizeof(*cmd), GFP_KERNEL);
+ if (!skb) {
+ CG2900_ERR("Could not allocate skb");
+ err = -ENOMEM;
+ goto finished_release_id;
+ }
+
+ cmd = (struct mc_vs_create_stream_cmd *)skb_put(skb, sizeof(*cmd));
+
+ cmd->opcode = cpu_to_le16(CG2900_MC_VS_CREATE_STREAM);
+ cmd->plen = BT_PARAM_LEN(sizeof(*cmd));
+ cmd->id = (u8)id;
+ cmd->inport = inport;
+ cmd->outport = outport;
+ cmd->order = order;
+
+ cb_info_bt.user = user;
+ SET_RESP_STATE(user->resp_state, WAITING);
+
+ /* Send packet to controller */
+ err = cg2900_write(audio_info->dev_bt, skb);
+ if (err) {
+ CG2900_ERR("Error occurred while transmitting skb (%d)", err);
+ kfree_skb(skb);
+ goto finished_release_id;
+ }
+
+ /* All commands in PG2 API returns one byte with extra status */
+ err = receive_bt_cmd_complete(user,
+ CG2900_MC_VS_CREATE_STREAM,
+ &vs_err, sizeof(vs_err));
+ if (err) {
+ CG2900_DBG("VS_CREATE_STREAM - failed with error %02x",
+ vs_err);
+ goto finished_release_id;
+ }
+
+ err = id;
+ goto finished;
+
+finished_release_id:
+ release_stream_id(id);
+finished:
+ SET_RESP_STATE(user->resp_state, IDLE);
+ return err;
+}
+
+/**
+ * send_vs_port_cfg() - Formats an sends a CG2900_MC_VS_PORT_CONFIG command.
+ * @user: Audio user this command belongs to.
+ * @port: Port id to configure.
+ * @cfg: Pointer to specific configuration.
+ * @cfglen: Length of configuration.
+ *
+ * Packs and sends a command packet and waits for the response. Must
+ * be called with the bt_mutex held.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ENOMEM if not possible to allocate packet.
+ * -ECOMM if no response was received.
+ * -EIO for other errors.
+ */
+static int send_vs_port_cfg(struct audio_user *user, u8 port,
+ const void *cfg, size_t cfglen)
+{
+ int err = 0;
+ struct sk_buff *skb;
+ struct mc_vs_port_cfg_cmd *cmd;
+ void *ptr;
+ u8 vs_err;
+
+ skb = cg2900_alloc_skb(sizeof(*cmd) + cfglen, GFP_KERNEL);
+ if (!skb) {
+ CG2900_ERR("Could not allocate skb");
+ return -ENOMEM;
+ }
+
+ /* Fill in common part */
+ cmd = (struct mc_vs_port_cfg_cmd *) skb_put(skb, sizeof(*cmd));
+ cmd->opcode = cpu_to_le16(CG2900_MC_VS_PORT_CONFIG);
+ cmd->plen = BT_PARAM_LEN(sizeof(*cmd) + cfglen);
+ cmd->type = port;
+
+ /* Copy specific configuration */
+ ptr = skb_put(skb, cfglen);
+ memcpy(ptr, cfg, cfglen);
+
+ /* Send */
+ cb_info_bt.user = user;
+ SET_RESP_STATE(user->resp_state, WAITING);
+
+ err = cg2900_write(audio_info->dev_bt, skb);
+ if (err) {
+ CG2900_ERR("Error occurred while transmitting skb (%d)", err);
+ kfree_skb(skb);
+ goto finished;
+ }
+
+ /* All commands in PG2 API returns one byte with extra status */
+ err = receive_bt_cmd_complete(user, CG2900_MC_VS_PORT_CONFIG,
+ &vs_err, sizeof(vs_err));
+ if (err)
+ CG2900_DBG("VS_PORT_CONFIG - failed with error %02x",
+ vs_err);
+
+finished:
+ SET_RESP_STATE(user->resp_state, IDLE);
+ return err;
+}
+
+/**
+ * set_dai_config_pg1() - Internal implementation of @cg2900_audio_set_dai_config for PG1 hardware.
+ * @audio_user: Pointer to audio user struct.
+ * @config: Pointer to the configuration to set.
+ *
+ * Sets the Digital Audio Interface (DAI) configuration for PG1
+ * hardware. This is and internal function and basic
+ * argument-verification should have been done by the caller.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EACCESS if port is not supported.
+ * -ENOMEM if not possible to allocate packet.
+ * -ECOMM if no response was received.
+ * -EIO for other errors.
+ */
+static int set_dai_config_pg1(struct audio_user *audio_user,
+ struct cg2900_dai_config *config)
+{
+ int err = 0;
+ struct cg2900_dai_conf_i2s_pcm *i2s_pcm;
+ struct sk_buff *skb = NULL;
+ struct bt_vs_set_hw_cfg_cmd_i2s *i2s_cmd;
+ struct bt_vs_set_hw_cfg_cmd_pcm *pcm_cmd;
+
+ /*
+ * Use mutex to assure that only ONE command is sent at any time on
+ * each channel.
+ */
+ mutex_lock(&audio_info->bt_mutex);
+
+ /* Allocate the sk_buffer. The length is actually a max length since
+ * length varies depending on logical transport.
+ */
+ skb = cg2900_alloc_skb(CG2900_BT_LEN_VS_SET_HARDWARE_CONFIG,
+ GFP_KERNEL);
+ if (!skb) {
+ CG2900_ERR("Could not allocate skb");
+ err = -ENOMEM;
+ goto finished_unlock_mutex;
+ }
+
+ /* Fill in hci-command according to received configuration */
+ switch (config->port) {
+ case PORT_0_I2S:
+ i2s_cmd = (struct bt_vs_set_hw_cfg_cmd_i2s *)
+ skb_put(skb, sizeof(*i2s_cmd));
+
+ i2s_cmd->opcode = cpu_to_le16(CG2900_BT_VS_SET_HARDWARE_CONFIG);
+ i2s_cmd->plen = BT_PARAM_LEN(sizeof(*i2s_cmd));
+
+ i2s_cmd->vp_type = PORT_PROTOCOL_I2S;
+ i2s_cmd->port_id = 0x00; /* First/only I2S port */
+ i2s_cmd->half_period = config->conf.i2s.half_period;
+
+ i2s_cmd->master_slave = mc_i2s_role(config->conf.i2s.mode);
+
+ /* Store the new configuration */
+ mutex_lock(&audio_info->management_mutex);
+ memcpy(&(audio_info->i2s_config), &(config->conf.i2s),
+ sizeof(config->conf.i2s));
+ audio_info->i2s_config_known = true;
+ mutex_unlock(&audio_info->management_mutex);
+ break;
+
+ case PORT_1_I2S_PCM:
+ pcm_cmd = (struct bt_vs_set_hw_cfg_cmd_pcm *)
+ skb_put(skb, sizeof(*pcm_cmd));
+
+ pcm_cmd->opcode = cpu_to_le16(CG2900_BT_VS_SET_HARDWARE_CONFIG);
+ pcm_cmd->plen = BT_PARAM_LEN(sizeof(*pcm_cmd));
+
+ i2s_pcm = &config->conf.i2s_pcm;
+
+ /*
+ * PG1 chips don't support I2S over the PCM/I2S bus,
+ * and PG2 chips don't use this command
+ */
+ if (i2s_pcm->protocol != PORT_PROTOCOL_PCM) {
+ CG2900_ERR("I2S not supported over the PCM/I2S bus");
+ err = -EACCES;
+ goto error_handling_free_skb;
+ }
+
+ pcm_cmd->vp_type = PORT_PROTOCOL_PCM;
+ pcm_cmd->port_id = 0x00; /* First/only PCM port */
+
+ HWCONFIG_PCM_SET_MODE(pcm_cmd, mc_pcm_role(i2s_pcm->mode));
+
+ HWCONFIG_PCM_SET_DIR(pcm_cmd, 0, i2s_pcm->slot_0_dir);
+ HWCONFIG_PCM_SET_DIR(pcm_cmd, 1, i2s_pcm->slot_1_dir);
+ HWCONFIG_PCM_SET_DIR(pcm_cmd, 2, i2s_pcm->slot_2_dir);
+ HWCONFIG_PCM_SET_DIR(pcm_cmd, 3, i2s_pcm->slot_3_dir);
+
+ pcm_cmd->bit_clock = i2s_pcm->clk;
+ pcm_cmd->frame_len =
+ cpu_to_le16(get_fs_duration(i2s_pcm->duration));
+
+ /* Store the new configuration */
+ mutex_lock(&audio_info->management_mutex);
+ memcpy(&(audio_info->i2s_pcm_config), &(config->conf.i2s_pcm),
+ sizeof(config->conf.i2s_pcm));
+ audio_info->i2s_pcm_config_known = true;
+ mutex_unlock(&audio_info->management_mutex);
+ break;
+
+ default:
+ CG2900_ERR("Unknown port configuration %d", config->port);
+ err = -EACCES;
+ goto error_handling_free_skb;
+ };
+
+ cb_info_bt.user = audio_user;
+ SET_RESP_STATE(audio_user->resp_state, WAITING);
+
+ /* Send packet to controller */
+ err = cg2900_write(audio_info->dev_bt, skb);
+ if (err) {
+ CG2900_ERR("Error occurred while transmitting skb (%d)", err);
+ goto error_handling_free_skb;
+ }
+
+ err = receive_bt_cmd_complete(audio_user,
+ CG2900_BT_VS_SET_HARDWARE_CONFIG,
+ NULL, 0);
+
+ goto finished_unlock_mutex;
+
+error_handling_free_skb:
+ kfree_skb(skb);
+finished_unlock_mutex:
+ SET_RESP_STATE(audio_user->resp_state, IDLE);
+ mutex_unlock(&audio_info->bt_mutex);
+ return err;
+}
+
+/**
+ * set_dai_config_pg2() - Internal implementation of @cg2900_audio_set_dai_config for PG2 hardware.
+ * @audio_user: Pointer to audio user struct.
+ * @config: Pointer to the configuration to set.
+ *
+ * Sets the Digital Audio Interface (DAI) configuration for PG2
+ * hardware. This is an internal function and basic
+ * argument-verification should have been done by the caller.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EACCESS if port is not supported.
+ * -ENOMEM if not possible to allocate packet.
+ * -ECOMM if no response was received.
+ * -EIO for other errors.
+ */
+static int set_dai_config_pg2(struct audio_user *audio_user,
+ struct cg2900_dai_config *config)
+{
+ int err = 0;
+ struct cg2900_dai_conf_i2s *i2s;
+ struct cg2900_dai_conf_i2s_pcm *i2s_pcm;
+
+ struct mc_vs_port_cfg_i2s i2s_cfg;
+ struct mc_vs_port_cfg_pcm_i2s pcm_cfg;
+
+ /*
+ * Use mutex to assure that only ONE command is sent at any time on
+ * each channel.
+ */
+ mutex_lock(&audio_info->bt_mutex);
+
+ switch (config->port) {
+ case PORT_0_I2S:
+ i2s = &config->conf.i2s;
+
+ memset(&i2s_cfg, 0, sizeof(i2s_cfg)); /* just to be safe */
+
+ /* master/slave */
+ PORTCFG_I2S_SET_ROLE(i2s_cfg, mc_i2s_role(i2s->mode));
+
+ PORTCFG_I2S_SET_HALFPERIOD(i2s_cfg, i2s->half_period);
+ PORTCFG_I2S_SET_CHANNELS(i2s_cfg,
+ mc_i2s_channel_select(i2s->channel_sel));
+ PORTCFG_I2S_SET_SRATE(i2s_cfg,
+ mc_i2s_sample_rate(i2s->sample_rate));
+ switch (i2s->word_width) {
+ case WORD_WIDTH_16:
+ PORTCFG_I2S_SET_WORDLEN(i2s_cfg, CG2900_MC_I2S_WORD_16);
+ break;
+ case WORD_WIDTH_32:
+ PORTCFG_I2S_SET_WORDLEN(i2s_cfg, CG2900_MC_I2S_WORD_32);
+ break;
+ }
+
+ /* Store the new configuration */
+ mutex_lock(&audio_info->management_mutex);
+ memcpy(&(audio_info->i2s_config), &(config->conf.i2s),
+ sizeof(config->conf.i2s));
+ audio_info->i2s_config_known = true;
+ mutex_unlock(&audio_info->management_mutex);
+
+ /* Send */
+ err = send_vs_port_cfg(audio_user, CG2900_MC_PORT_I2S,
+ &i2s_cfg, sizeof(i2s_cfg));
+ break;
+
+ case PORT_1_I2S_PCM:
+ i2s_pcm = &config->conf.i2s_pcm;
+
+ memset(&pcm_cfg, 0, sizeof(pcm_cfg)); /* just to be safe */
+
+ /* master/slave */
+ PORTCFG_PCM_SET_ROLE(pcm_cfg, mc_pcm_role(i2s_pcm->mode));
+
+ /* set direction for all 4 slots */
+ PORTCFG_PCM_SET_DIR(pcm_cfg, 0, i2s_pcm->slot_0_dir);
+ PORTCFG_PCM_SET_DIR(pcm_cfg, 1, i2s_pcm->slot_1_dir);
+ PORTCFG_PCM_SET_DIR(pcm_cfg, 2, i2s_pcm->slot_2_dir);
+ PORTCFG_PCM_SET_DIR(pcm_cfg, 3, i2s_pcm->slot_3_dir);
+
+ /* set used SCO slots, other use cases not supported atm */
+ PORTCFG_PCM_SET_SCO_USED(pcm_cfg, 0, i2s_pcm->slot_0_used);
+ PORTCFG_PCM_SET_SCO_USED(pcm_cfg, 1, i2s_pcm->slot_1_used);
+ PORTCFG_PCM_SET_SCO_USED(pcm_cfg, 2, i2s_pcm->slot_2_used);
+ PORTCFG_PCM_SET_SCO_USED(pcm_cfg, 3, i2s_pcm->slot_3_used);
+
+ /* slot starts */
+ pcm_cfg.slot_start[0] = i2s_pcm->slot_0_start;
+ pcm_cfg.slot_start[1] = i2s_pcm->slot_1_start;
+ pcm_cfg.slot_start[2] = i2s_pcm->slot_2_start;
+ pcm_cfg.slot_start[3] = i2s_pcm->slot_3_start;
+
+ /* audio/voice sample-rate ratio */
+ PORTCFG_PCM_SET_RATIO(pcm_cfg, i2s_pcm->ratio);
+
+ /* PCM or I2S mode */
+ PORTCFG_PCM_SET_MODE(pcm_cfg, i2s_pcm->protocol);
+
+ pcm_cfg.frame_len = i2s_pcm->duration;
+
+ PORTCFG_PCM_SET_BITCLK(pcm_cfg, i2s_pcm->clk);
+ PORTCFG_PCM_SET_SRATE(pcm_cfg,
+ mc_pcm_sample_rate(i2s_pcm->sample_rate));
+
+ /* Store the new configuration */
+ mutex_lock(&audio_info->management_mutex);
+ memcpy(&(audio_info->i2s_pcm_config), &(config->conf.i2s_pcm),
+ sizeof(config->conf.i2s_pcm));
+ audio_info->i2s_pcm_config_known = true;
+ mutex_unlock(&audio_info->management_mutex);
+
+ /* Send */
+ err = send_vs_port_cfg(audio_user, CG2900_MC_PORT_PCM_I2S,
+ &pcm_cfg, sizeof(pcm_cfg));
+ break;
+
+ default:
+ CG2900_ERR("Unknown port configuration %d", config->port);
+ err = -EACCES;
+ };
+
+ mutex_unlock(&audio_info->bt_mutex);
+ return err;
+}
+
+/**
+ * struct i2s_fm_stream_config_priv - Helper struct for stream i2s-fm streams.
+ * @fm_config: FM endpoint configuration.
+ * @rx: true for FM-RX, false for FM-TX.
+ */
+struct i2s_fm_stream_config_priv {
+ struct cg2900_endpoint_config_fm *fm_config;
+ bool rx;
+
+};
+
+/**
+ * config_i2s_fm_stream() - Callback for @send_vs_session_config.
+ * @_priv: Pointer to a @i2s_fm_stream_config_priv struct.
+ * @cfg: Pointer to stream config block in command packet.
+ *
+ * Fills in stream configuration for I2S-FM RX/TX.
+ */
+
+static void config_i2s_fm_stream(void *_priv,
+ struct session_config_stream *cfg)
+{
+ struct i2s_fm_stream_config_priv *priv = _priv;
+ struct session_config_vport *fm;
+ struct session_config_vport *i2s;
+
+ cfg->media_type = CG2900_BT_SESSION_MEDIA_TYPE_AUDIO;
+
+ if (audio_info->i2s_config.channel_sel == CHANNEL_SELECTION_BOTH)
+ SESSIONCFG_SET_CHANNELS(cfg, CG2900_BT_MEDIA_CONFIG_STEREO);
+ else
+ SESSIONCFG_SET_CHANNELS(cfg, CG2900_BT_MEDIA_CONFIG_MONO);
+
+ SESSIONCFG_I2S_SET_SRATE(cfg,
+ session_config_sample_rate(priv->fm_config->sample_rate));
+
+ cfg->codec_type = CG2900_CODEC_TYPE_NONE;
+ /* codec mode and parameters not used */
+
+ if (priv->rx) {
+ fm = &cfg->inport; /* FM is input */
+ i2s = &cfg->outport; /* I2S is output */
+ } else {
+ i2s = &cfg->inport; /* I2S is input */
+ fm = &cfg->outport; /* FM is output */
+ }
+
+ fm->type = CG2900_BT_VP_TYPE_FM;
+
+ i2s->type = CG2900_BT_VP_TYPE_I2S;
+ i2s->i2s.index = CG2900_BT_SESSION_I2S_INDEX_I2S;
+ i2s->i2s.channel = audio_info->i2s_config.channel_sel;
+}
+
+/**
+ * conn_start_i2s_to_fm_rx() - Start an audio stream connecting FM RX to I2S.
+ * @audio_user: Audio user to check for.
+ * @stream_handle: [out] Pointer where to store the stream handle.
+ *
+ * This function sets up an FM RX to I2S stream.
+ * It does this by first setting the output mode and then the configuration of
+ * the External Sample Rate Converter.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ECOMM if no response was received.
+ * -ENOMEM upon allocation errors.
+ * -EIO for other errors.
+ */
+static int conn_start_i2s_to_fm_rx(struct audio_user *audio_user,
+ unsigned int *stream_handle)
+{
+ int err = 0;
+ union cg2900_endpoint_config_union *fm_config;
+
+ fm_config = find_endpoint(ENDPOINT_FM_RX,
+ &(audio_info->endpoints));
+ if (!fm_config) {
+ CG2900_ERR("FM RX not configured before stream start");
+ return -EIO;
+ }
+
+ if (!(audio_info->i2s_config_known)) {
+ CG2900_ERR("I2S DAI not configured before stream start");
+ return -EIO;
+ }
+
+ /*
+ * Use mutex to assure that only ONE command is sent at any
+ * time on each channel.
+ */
+ mutex_lock(&audio_info->fm_mutex);
+ mutex_lock(&audio_info->bt_mutex);
+
+ /*
+ * Now set the output mode of the External Sample Rate Converter by
+ * sending HCI_Write command with AUP_EXT_SetMode.
+ */
+ err = send_fm_write_1_param(audio_user,
+ CG2900_FM_CMD_ID_AUP_EXT_SET_MODE,
+ CG2900_FM_CMD_AUP_EXT_SET_MODE_PARALLEL);
+ if (err)
+ goto finished_unlock_mutex;
+
+ /*
+ * Now configure the External Sample Rate Converter by sending
+ * HCI_Write command with AUP_EXT_SetControl.
+ */
+ err = send_fm_write_1_param(
+ audio_user, CG2900_FM_CMD_ID_AUP_EXT_SET_CTRL,
+ fm_get_conversion(fm_config->fm.sample_rate));
+ if (err)
+ goto finished_unlock_mutex;
+
+ /* Set up the stream */
+ if (audio_info->revision == CHIP_REV_PG1) {
+ struct i2s_fm_stream_config_priv stream_priv;
+
+ /* Now send HCI_VS_Set_Session_Configuration command */
+ stream_priv.fm_config = &fm_config->fm;
+ stream_priv.rx = true;
+ err = send_vs_session_config(audio_user, config_i2s_fm_stream,
+ &stream_priv);
+ } else {
+ struct mc_vs_port_cfg_fm fm_cfg;
+
+ /* Configure port FM RX */
+ /* Expects 0-3 - same as user API - so no conversion needed */
+ PORTCFG_FM_SET_SRATE(fm_cfg, (u8)fm_config->fm.sample_rate);
+
+ err = send_vs_port_cfg(audio_user, CG2900_MC_PORT_FM_RX_0,
+ &fm_cfg, sizeof(fm_cfg));
+ if (err)
+ goto finished_unlock_mutex;
+
+ /* CreateStream */
+ err = send_vs_create_stream(audio_user,
+ CG2900_MC_PORT_FM_RX_0,
+ CG2900_MC_PORT_I2S,
+ 0); /* chip doesn't care */
+ }
+
+ if (err < 0)
+ goto finished_unlock_mutex;
+
+ /* Store the stream handle (used for start and stop stream) */
+ *stream_handle = (u8)err;
+ CG2900_DBG("stream_handle set to %d", *stream_handle);
+
+ /* Now start the stream */
+ if (audio_info->revision == CHIP_REV_PG1)
+ err = send_vs_session_ctrl(audio_user, *stream_handle,
+ CG2900_BT_SESSION_START);
+ else
+ err = send_vs_stream_ctrl(audio_user, *stream_handle,
+ CG2900_MC_STREAM_START);
+
+finished_unlock_mutex:
+ SET_RESP_STATE(audio_user->resp_state, IDLE);
+ mutex_unlock(&audio_info->bt_mutex);
+ mutex_unlock(&audio_info->fm_mutex);
+ return err;
+}
+
+/**
+ * conn_start_i2s_to_fm_tx() - Start an audio stream connecting FM TX to I2S.
+ * @audio_user: Audio user to check for.
+ * @stream_handle: [out] Pointer where to store the stream handle.
+ *
+ * This function sets up an I2S to FM TX stream.
+ * It does this by first setting the Audio Input source and then setting the
+ * configuration and input source of BT sample rate converter.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ECOMM if no response was received.
+ * -ENOMEM upon allocation errors.
+ * -EIO for other errors.
+ */
+static int conn_start_i2s_to_fm_tx(struct audio_user *audio_user,
+ unsigned int *stream_handle)
+{
+ int err = 0;
+ union cg2900_endpoint_config_union *fm_config;
+
+ fm_config = find_endpoint(ENDPOINT_FM_TX, &(audio_info->endpoints));
+ if (!fm_config) {
+ CG2900_ERR("FM TX not configured before stream start");
+ return -EIO;
+ }
+
+ if (!(audio_info->i2s_config_known)) {
+ CG2900_ERR("I2S DAI not configured before stream start");
+ return -EIO;
+ }
+
+ /*
+ * Use mutex to assure that only ONE command is sent at any time
+ * on each channel.
+ */
+ mutex_lock(&audio_info->fm_mutex);
+ mutex_lock(&audio_info->bt_mutex);
+
+ /*
+ * Select Audio Input Source by sending HCI_Write command with
+ * AIP_SetMode.
+ */
+ CG2900_DBG("FM: AIP_SetMode");
+ err = send_fm_write_1_param(audio_user, CG2900_FM_CMD_ID_AIP_SET_MODE,
+ CG2900_FM_CMD_AIP_SET_MODE_INPUT_DIG);
+ if (err)
+ goto finished_unlock_mutex;
+
+ /*
+ * Now configure the BT sample rate converter by sending HCI_Write
+ * command with AIP_BT_SetControl.
+ */
+ CG2900_DBG("FM: AIP_BT_SetControl");
+ err = send_fm_write_1_param(
+ audio_user, CG2900_FM_CMD_ID_AIP_BT_SET_CTRL,
+ fm_get_conversion(fm_config->fm.sample_rate));
+ if (err)
+ goto finished_unlock_mutex;
+
+ /*
+ * Now set input of the BT sample rate converter by sending HCI_Write
+ * command with AIP_BT_SetMode.
+ */
+ CG2900_DBG("FM: AIP_BT_SetMode");
+ err = send_fm_write_1_param(audio_user,
+ CG2900_FM_CMD_ID_AIP_BT_SET_MODE,
+ CG2900_FM_CMD_AIP_BT_SET_MODE_INPUT_PAR);
+ if (err)
+ goto finished_unlock_mutex;
+
+ /* Set up the stream */
+ if (audio_info->revision == CHIP_REV_PG1) {
+ struct i2s_fm_stream_config_priv stream_priv;
+
+ /* Now send HCI_VS_Set_Session_Configuration command */
+ stream_priv.fm_config = &fm_config->fm;
+ stream_priv.rx = false;
+ err = send_vs_session_config(audio_user, config_i2s_fm_stream,
+ &stream_priv);
+ } else {
+ struct mc_vs_port_cfg_fm fm_cfg;
+
+ /* Configure port FM TX */
+ /* Expects 0-3 - same as user API - so no conversion needed */
+ PORTCFG_FM_SET_SRATE(fm_cfg, (u8)fm_config->fm.sample_rate);
+
+ err = send_vs_port_cfg(audio_user, CG2900_MC_PORT_FM_TX,
+ &fm_cfg, sizeof(fm_cfg));
+ if (err)
+ goto finished_unlock_mutex;
+
+ /* CreateStream */
+ err = send_vs_create_stream(audio_user,
+ CG2900_MC_PORT_I2S,
+ CG2900_MC_PORT_FM_TX,
+ 0); /* chip doesn't care */
+ }
+
+ if (err < 0)
+ goto finished_unlock_mutex;
+
+ /* Store the stream handle (used for start and stop stream) */
+ *stream_handle = (u8)err;
+ CG2900_DBG("stream_handle set to %d", *stream_handle);
+
+ /* Now start the stream */
+ if (audio_info->revision == CHIP_REV_PG1)
+ err = send_vs_session_ctrl(audio_user, *stream_handle,
+ CG2900_BT_SESSION_START);
+ else
+ err = send_vs_stream_ctrl(audio_user, *stream_handle,
+ CG2900_MC_STREAM_START);
+
+finished_unlock_mutex:
+ SET_RESP_STATE(audio_user->resp_state, IDLE);
+ mutex_unlock(&audio_info->bt_mutex);
+ mutex_unlock(&audio_info->fm_mutex);
+ return err;
+}
+
+/**
+ * config_pcm_sco_stream() - Callback for @send_vs_session_config.
+ * @_priv: Pointer to a @cg2900_endpoint_config_sco_in_out struct.
+ * @cfg: Pointer to stream config block in command packet.
+ *
+ * Fills in stream configuration for PCM-SCO.
+ */
+static void config_pcm_sco_stream(void *_priv,
+ struct session_config_stream *cfg)
+{
+ struct cg2900_endpoint_config_sco_in_out *sco_ep = _priv;
+
+ cfg->media_type = CG2900_BT_SESSION_MEDIA_TYPE_AUDIO;
+
+ SESSIONCFG_SET_CHANNELS(cfg, CG2900_BT_MEDIA_CONFIG_MONO);
+ SESSIONCFG_I2S_SET_SRATE(cfg,
+ session_config_sample_rate(sco_ep->sample_rate));
+
+ cfg->codec_type = CG2900_CODEC_TYPE_NONE;
+ /* codec mode and parameters not used */
+
+ cfg->inport.type = CG2900_BT_VP_TYPE_BT_SCO;
+ cfg->inport.sco.acl_handle = cpu_to_le16(DEFAULT_SCO_HANDLE);
+
+ cfg->outport.type = CG2900_BT_VP_TYPE_PCM;
+ cfg->outport.pcm.index = CG2900_BT_SESSION_PCM_INDEX_PCM_I2S;
+
+ SESSIONCFG_PCM_SET_USED(cfg->outport, 0,
+ audio_info->i2s_pcm_config.slot_0_used);
+ SESSIONCFG_PCM_SET_USED(cfg->outport, 1,
+ audio_info->i2s_pcm_config.slot_1_used);
+ SESSIONCFG_PCM_SET_USED(cfg->outport, 2,
+ audio_info->i2s_pcm_config.slot_2_used);
+ SESSIONCFG_PCM_SET_USED(cfg->outport, 3,
+ audio_info->i2s_pcm_config.slot_3_used);
+
+ cfg->outport.pcm.slot_start[0] =
+ audio_info->i2s_pcm_config.slot_0_start;
+ cfg->outport.pcm.slot_start[1] =
+ audio_info->i2s_pcm_config.slot_1_start;
+ cfg->outport.pcm.slot_start[2] =
+ audio_info->i2s_pcm_config.slot_2_start;
+ cfg->outport.pcm.slot_start[3] =
+ audio_info->i2s_pcm_config.slot_3_start;
+}
+
+/**
+ * conn_start_pcm_to_sco() - Start an audio stream connecting Bluetooth (e)SCO to PCM_I2S.
+ * @audio_user: Audio user to check for.
+ * @stream_handle: [out] Pointer where to store the stream handle.
+ *
+ * This function sets up a BT to_from PCM_I2S stream. It does this by
+ * first setting the Session configuration and then starting the Audio
+ * Stream.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ECOMM if no response was received.
+ * -ENOMEM upon allocation errors.
+ * Errors from @cg2900_write
+ * -EIO for other errors.
+ */
+static int conn_start_pcm_to_sco(struct audio_user *audio_user,
+ unsigned int *stream_handle)
+{
+ int err = 0;
+ union cg2900_endpoint_config_union *bt_config;
+
+ bt_config = find_endpoint(ENDPOINT_BT_SCO_INOUT,
+ &(audio_info->endpoints));
+ if (!bt_config) {
+ CG2900_ERR("BT not configured before stream start");
+ return -EIO;
+ }
+
+ if (!(audio_info->i2s_pcm_config_known)) {
+ CG2900_ERR("I2S_PCM DAI not configured before stream start");
+ return -EIO;
+ }
+
+ /*
+ * Use mutex to assure that only ONE command is sent at any time on each
+ * channel.
+ */
+ mutex_lock(&audio_info->bt_mutex);
+
+ /* Set up the stream */
+ if (audio_info->revision == CHIP_REV_PG1) {
+ err = send_vs_session_config(audio_user, config_pcm_sco_stream,
+ &bt_config->sco);
+ } else {
+ struct mc_vs_port_cfg_sco sco_cfg;
+
+ /* zero codec params etc */
+ memset(&sco_cfg, 0, sizeof(sco_cfg));
+ sco_cfg.acl_id = DEFAULT_SCO_HANDLE;
+ PORTCFG_SCO_SET_WBS(sco_cfg, 0); /* No WBS yet */
+ PORTCFG_SCO_SET_CODEC(sco_cfg, CG2900_CODEC_TYPE_NONE);
+
+ err = send_vs_port_cfg(audio_user, CG2900_MC_PORT_BT_SCO,
+ &sco_cfg, sizeof(sco_cfg));
+ if (err)
+ goto finished_unlock_mutex;
+
+ /* CreateStream */
+ err = send_vs_create_stream(audio_user,
+ CG2900_MC_PORT_PCM_I2S,
+ CG2900_MC_PORT_BT_SCO,
+ 0); /* chip doesn't care */
+ }
+
+ if (err < 0)
+ goto finished_unlock_mutex;
+
+ /* Store the stream handle (used for start and stop stream) */
+ *stream_handle = (u8)err;
+ CG2900_DBG("stream_handle set to %d", *stream_handle);
+
+ /* Now start the stream by sending HCI_VS_Session_Control command */
+ err = send_vs_session_ctrl(audio_user, *stream_handle,
+ CG2900_BT_SESSION_START);
+
+finished_unlock_mutex:
+ SET_RESP_STATE(audio_user->resp_state, IDLE);
+ mutex_unlock(&audio_info->bt_mutex);
+ return err;
+}
+
+/**
+ * conn_stop_stream() - Stops an audio stream defined by @stream_handle.
+ * @audio_user: Audio user to check for.
+ * @stream_handle: Handle of the audio stream.
+ *
+ * This function is used to stop an audio stream defined by a stream
+ * handle. It does this by first stopping the stream and then
+ * resetting the session/stream.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ECOMM if no response was received.
+ * -ENOMEM upon allocation errors.
+ * Errors from @cg2900_write.
+ * -EIO for other errors.
+ */
+static int conn_stop_stream(struct audio_user *audio_user,
+ unsigned int stream_handle)
+{
+ int err = 0;
+ struct sk_buff *skb;
+ u16 opcode;
+
+ /*
+ * Use mutex to assure that only ONE command is sent at any
+ * time on each channel.
+ */
+ mutex_lock(&audio_info->bt_mutex);
+
+ /* Now stop the stream */
+ if (audio_info->revision == CHIP_REV_PG1)
+ err = send_vs_session_ctrl(audio_user, stream_handle,
+ CG2900_BT_SESSION_STOP);
+ else
+ err = send_vs_stream_ctrl(audio_user, stream_handle,
+ CG2900_MC_STREAM_STOP);
+ if (err)
+ goto finished_unlock_mutex;
+
+ /* Now delete the stream - format command... */
+ if (audio_info->revision == CHIP_REV_PG1) {
+ struct bt_vs_reset_session_cfg_cmd *cmd;
+
+ CG2900_DBG("BT: HCI_VS_Reset_Session_Configuration");
+
+ skb = cg2900_alloc_skb(sizeof(*cmd), GFP_KERNEL);
+ if (!skb) {
+ CG2900_ERR("Could not allocate skb");
+ err = -ENOMEM;
+ goto finished_unlock_mutex;
+ }
+
+ cmd = (struct bt_vs_reset_session_cfg_cmd *)
+ skb_put(skb, sizeof(*cmd));
+
+ opcode = CG2900_BT_VS_RESET_SESSION_CONFIG;
+ cmd->opcode = cpu_to_le16(opcode);
+ cmd->plen = BT_PARAM_LEN(sizeof(*cmd));
+ cmd->id = (u8)stream_handle;
+ } else {
+ struct mc_vs_delete_stream_cmd *cmd;
+
+ CG2900_DBG("BT: HCI_VS_Delete_Stream");
+
+ skb = cg2900_alloc_skb(sizeof(*cmd), GFP_KERNEL);
+ if (!skb) {
+ CG2900_ERR("Could not allocate skb");
+ err = -ENOMEM;
+ goto finished_unlock_mutex;
+ }
+
+ cmd = (struct mc_vs_delete_stream_cmd *)
+ skb_put(skb, sizeof(*cmd));
+
+ opcode = CG2900_MC_VS_DELETE_STREAM;
+ cmd->opcode = cpu_to_le16(opcode);
+ cmd->plen = BT_PARAM_LEN(sizeof(*cmd));
+ cmd->stream = (u8)stream_handle;
+ }
+
+ /* ...and send it */
+ cb_info_bt.user = audio_user;
+ SET_RESP_STATE(audio_user->resp_state, WAITING);
+
+ err = cg2900_write(audio_info->dev_bt, skb);
+ if (err) {
+ CG2900_ERR("Error occurred while transmitting skb (%d)", err);
+ goto error_handling_free_skb;
+ }
+
+ /* wait for response */
+ if (audio_info->revision == CHIP_REV_PG1) {
+ err = receive_bt_cmd_complete(audio_user, opcode, NULL, 0);
+ } else {
+ u8 vs_err;
+
+ /* All commands in PG2 API returns one byte extra status */
+ err = receive_bt_cmd_complete(audio_user, opcode,
+ &vs_err, sizeof(vs_err));
+
+ if (err)
+ CG2900_DBG("VS_DELETE_STREAM - failed with error %02x",
+ vs_err);
+ else
+ release_stream_id(stream_handle);
+
+ }
+
+ goto finished_unlock_mutex;
+
+error_handling_free_skb:
+ kfree_skb(skb);
+finished_unlock_mutex:
+ SET_RESP_STATE(audio_user->resp_state, IDLE);
+ mutex_unlock(&audio_info->bt_mutex);
+ return err;
+}
+
+/*
+ * External methods
+ */
+
+int cg2900_audio_open(unsigned int *session)
+{
+ int err = 0;
+ int i;
+
+ CG2900_INFO("cg2900_audio_open");
+
+ if (!session) {
+ CG2900_ERR("NULL supplied as session.");
+ return -EINVAL;
+ }
+
+ mutex_lock(&audio_info->management_mutex);
+
+ *session = 0;
+
+ /*
+ * First find a free session to use and allocate the session structure.
+ */
+ for (i = FIRST_USER;
+ i < MAX_NBR_OF_USERS && audio_info->audio_sessions[i];
+ i++)
+ ; /* Just loop until found or end reached */
+
+ if (i >= MAX_NBR_OF_USERS) {
+ CG2900_ERR("Couldn't find free user");
+ err = -EMFILE;
+ goto finished;
+ }
+
+ audio_info->audio_sessions[i] =
+ kzalloc(sizeof(*(audio_info->audio_sessions[0])),
+ GFP_KERNEL);
+ if (!audio_info->audio_sessions[i]) {
+ CG2900_ERR("Could not allocate user");
+ err = -ENOMEM;
+ goto finished;
+ }
+ CG2900_DBG("Found free session %d", i);
+ *session = i;
+ audio_info->nbr_of_users_active++;
+
+ SET_RESP_STATE(audio_info->audio_sessions[*session]->resp_state, IDLE);
+ audio_info->audio_sessions[*session]->session = *session;
+
+ if (audio_info->nbr_of_users_active == 1) {
+ struct cg2900_rev_data rev_data;
+
+ /*
+ * First user so register to CG2900 Core.
+ * First the BT audio device.
+ */
+ audio_info->dev_bt = cg2900_register_user(CG2900_BT_AUDIO,
+ &cg2900_cb);
+ if (!audio_info->dev_bt) {
+ CG2900_ERR("Failed to register BT audio channel");
+ err = -EIO;
+ goto error_handling;
+ }
+
+ /* Store the callback info structure */
+ audio_info->dev_bt->user_data = &cb_info_bt;
+
+ /* Then the FM audio device */
+ audio_info->dev_fm = cg2900_register_user(CG2900_FM_RADIO_AUDIO,
+ &cg2900_cb);
+ if (!audio_info->dev_fm) {
+ CG2900_ERR("Failed to register FM audio channel");
+ err = -EIO;
+ goto error_handling;
+ }
+
+ /* Store the callback info structure */
+ audio_info->dev_fm->user_data = &cb_info_fm;
+
+ /* Read chip revision data */
+ if (!cg2900_get_local_revision(&rev_data)) {
+ CG2900_ERR("Couldn't retrieve revision data");
+ err = -EIO;
+ goto error_handling;
+ }
+
+ /* Decode revision data */
+ switch (rev_data.revision) {
+ case CG2900_PG1_REV:
+ case CG2900_PG1_SPECIAL_REV:
+ audio_info->revision = CHIP_REV_PG1;
+ break;
+
+ case CG2900_PG2_REV:
+ audio_info->revision = CHIP_REV_PG2;
+ break;
+
+ default:
+ CG2900_ERR("Chip rev 0x%04X sub 0x%04X not supported",
+ rev_data.revision, rev_data.sub_version);
+ err = -EIO;
+ goto error_handling;
+ }
+
+ audio_info->state = OPENED;
+ }
+
+ goto finished;
+
+error_handling:
+ if (audio_info->dev_fm) {
+ cg2900_deregister_user(audio_info->dev_fm);
+ audio_info->dev_fm = NULL;
+ }
+ if (audio_info->dev_bt) {
+ cg2900_deregister_user(audio_info->dev_bt);
+ audio_info->dev_bt = NULL;
+ }
+ audio_info->nbr_of_users_active--;
+ kfree(audio_info->audio_sessions[*session]);
+ audio_info->audio_sessions[*session] = NULL;
+finished:
+ mutex_unlock(&audio_info->management_mutex);
+ return err;
+}
+EXPORT_SYMBOL(cg2900_audio_open);
+
+int cg2900_audio_close(unsigned int *session)
+{
+ int err = 0;
+ struct audio_user *audio_user;
+
+ CG2900_INFO("cg2900_audio_close");
+
+ if (audio_info->state != OPENED) {
+ CG2900_ERR("Audio driver not open");
+ return -EIO;
+ }
+
+ if (!session) {
+ CG2900_ERR("NULL pointer supplied");
+ return -EINVAL;
+ }
+
+ audio_user = get_session_user(*session);
+ if (!audio_user) {
+ CG2900_ERR("Invalid session ID");
+ return -EINVAL;
+ }
+
+ mutex_lock(&audio_info->management_mutex);
+
+ if (!(audio_info->audio_sessions[*session])) {
+ CG2900_ERR("Session %d not opened", *session);
+ err = -EACCES;
+ goto err_unlock_mutex;
+ }
+
+ kfree(audio_info->audio_sessions[*session]);
+ audio_info->audio_sessions[*session] = NULL;
+ audio_info->nbr_of_users_active--;
+
+ if (audio_info->nbr_of_users_active == 0) {
+ /* No more sessions open. Deregister from CG2900 Core */
+ cg2900_deregister_user(audio_info->dev_fm);
+ cg2900_deregister_user(audio_info->dev_bt);
+ audio_info->state = CLOSED;
+ }
+
+ *session = 0;
+
+err_unlock_mutex:
+ mutex_unlock(&audio_info->management_mutex);
+ return err;
+}
+EXPORT_SYMBOL(cg2900_audio_close);
+
+int cg2900_audio_set_dai_config(unsigned int session,
+ struct cg2900_dai_config *config)
+{
+ int err = 0;
+ struct audio_user *audio_user;
+ struct cg2900_rev_data rev_data;
+
+ CG2900_INFO("cg2900_audio_set_dai_config");
+
+ if (audio_info->state != OPENED) {
+ CG2900_ERR("Audio driver not open");
+ return -EIO;
+ }
+
+ audio_user = get_session_user(session);
+ if (!audio_user)
+ return -EINVAL;
+
+ if (!cg2900_get_local_revision(&rev_data)) {
+ CG2900_ERR("Couldn't retrieve revision data");
+ return -EIO;
+ }
+
+ /* Different commands are used for PG1 and PG2 */
+ switch (rev_data.revision) {
+ case CG2900_PG1_REV:
+ case CG2900_PG1_SPECIAL_REV:
+ err = set_dai_config_pg1(audio_user, config);
+ break;
+
+ case CG2900_PG2_REV:
+ err = set_dai_config_pg2(audio_user, config);
+ break;
+
+ default:
+ CG2900_ERR("Chip rev 0x%04X sub 0x%04X not supported",
+ rev_data.revision, rev_data.sub_version);
+ err = -EIO;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(cg2900_audio_set_dai_config);
+
+int cg2900_audio_get_dai_config(unsigned int session,
+ struct cg2900_dai_config *config)
+{
+ int err = 0;
+ struct audio_user *audio_user;
+
+ CG2900_INFO("cg2900_audio_get_dai_config");
+
+ if (audio_info->state != OPENED) {
+ CG2900_ERR("Audio driver not open");
+ return -EIO;
+ }
+
+ if (!config) {
+ CG2900_ERR("NULL supplied as config structure");
+ return -EINVAL;
+ }
+
+ audio_user = get_session_user(session);
+ if (!audio_user)
+ return -EINVAL;
+
+ /*
+ * Return DAI configuration based on the received port.
+ * If port has not been configured return error.
+ */
+ switch (config->port) {
+ case PORT_0_I2S:
+ mutex_lock(&audio_info->management_mutex);
+ if (audio_info->i2s_config_known)
+ memcpy(&(config->conf.i2s),
+ &(audio_info->i2s_config),
+ sizeof(config->conf.i2s));
+ else
+ err = -EIO;
+ mutex_unlock(&audio_info->management_mutex);
+ break;
+
+ case PORT_1_I2S_PCM:
+ mutex_lock(&audio_info->management_mutex);
+ if (audio_info->i2s_pcm_config_known)
+ memcpy(&(config->conf.i2s_pcm),
+ &(audio_info->i2s_pcm_config),
+ sizeof(config->conf.i2s_pcm));
+ else
+ err = -EIO;
+ mutex_unlock(&audio_info->management_mutex);
+ break;
+
+ default:
+ CG2900_ERR("Unknown port configuration %d", config->port);
+ err = -EIO;
+ break;
+ };
+
+ return err;
+}
+EXPORT_SYMBOL(cg2900_audio_get_dai_config);
+
+int cg2900_audio_config_endpoint(unsigned int session,
+ struct cg2900_endpoint_config *config)
+{
+ struct audio_user *audio_user;
+
+ CG2900_INFO("cg2900_audio_config_endpoint");
+
+ if (audio_info->state != OPENED) {
+ CG2900_ERR("Audio driver not open");
+ return -EIO;
+ }
+
+ if (!config) {
+ CG2900_ERR("NULL supplied as configuration structure");
+ return -EINVAL;
+ }
+
+ audio_user = get_session_user(session);
+ if (!audio_user)
+ return -EINVAL;
+
+ switch (config->endpoint_id) {
+ case ENDPOINT_BT_SCO_INOUT:
+ case ENDPOINT_BT_A2DP_SRC:
+ case ENDPOINT_FM_RX:
+ case ENDPOINT_FM_TX:
+ add_endpoint(config, &(audio_info->endpoints));
+ break;
+
+ case ENDPOINT_PORT_0_I2S:
+ case ENDPOINT_PORT_1_I2S_PCM:
+ case ENDPOINT_SLIMBUS_VOICE:
+ case ENDPOINT_SLIMBUS_AUDIO:
+ case ENDPOINT_BT_A2DP_SNK:
+ case ENDPOINT_ANALOG_OUT:
+ case ENDPOINT_DSP_AUDIO_IN:
+ case ENDPOINT_DSP_AUDIO_OUT:
+ case ENDPOINT_DSP_VOICE_IN:
+ case ENDPOINT_DSP_VOICE_OUT:
+ case ENDPOINT_DSP_TONE_IN:
+ case ENDPOINT_BURST_BUFFER_IN:
+ case ENDPOINT_BURST_BUFFER_OUT:
+ case ENDPOINT_MUSIC_DECODER:
+ case ENDPOINT_HCI_AUDIO_IN:
+ default:
+ CG2900_ERR("Unknown endpoint_id %d", config->endpoint_id);
+ return -EACCES;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(cg2900_audio_config_endpoint);
+
+static bool is_dai_port(enum cg2900_audio_endpoint_id ep)
+{
+ /* These are the only supported ones */
+ return (ep == ENDPOINT_PORT_0_I2S) || (ep == ENDPOINT_PORT_1_I2S_PCM);
+}
+
+int cg2900_audio_start_stream(unsigned int session,
+ enum cg2900_audio_endpoint_id ep_1,
+ enum cg2900_audio_endpoint_id ep_2,
+ unsigned int *stream_handle)
+{
+ int err;
+ struct audio_user *audio_user;
+
+ CG2900_INFO("cg2900_audio_start_stream");
+
+ if (audio_info->state != OPENED) {
+ CG2900_ERR("Audio driver not open");
+ return -EIO;
+ }
+
+ audio_user = get_session_user(session);
+ if (!audio_user)
+ return -EINVAL;
+
+ /* put digital interface in ep_1 to simplify comparison below */
+ if (!is_dai_port(ep_1)) {
+ /* Swap endpoints */
+ enum cg2900_audio_endpoint_id t = ep_1;
+ ep_1 = ep_2;
+ ep_2 = t;
+ }
+
+ if (ep_1 == ENDPOINT_PORT_1_I2S_PCM && ep_2 == ENDPOINT_BT_SCO_INOUT) {
+ err = conn_start_pcm_to_sco(audio_user, stream_handle);
+ } else if (ep_1 == ENDPOINT_PORT_0_I2S && ep_2 == ENDPOINT_FM_RX) {
+ err = conn_start_i2s_to_fm_rx(audio_user, stream_handle);
+ } else if (ep_1 == ENDPOINT_PORT_0_I2S && ep_2 == ENDPOINT_FM_TX) {
+ err = conn_start_i2s_to_fm_tx(audio_user, stream_handle);
+ } else {
+ CG2900_ERR("Endpoint config not handled: ep1: %d, "
+ "ep2: %d", ep_1, ep_2);
+ err = -EINVAL;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(cg2900_audio_start_stream);
+
+int cg2900_audio_stop_stream(unsigned int session, unsigned int stream_handle)
+{
+ struct audio_user *audio_user;
+
+ CG2900_INFO("cg2900_audio_stop_stream");
+
+ if (audio_info->state != OPENED) {
+ CG2900_ERR("Audio driver not open");
+ return -EIO;
+ }
+
+ audio_user = get_session_user(session);
+ if (!audio_user)
+ return -EINVAL;
+
+ return conn_stop_stream(audio_user, stream_handle);
+}
+EXPORT_SYMBOL(cg2900_audio_stop_stream);
+
+/*
+ * Character devices for userspace module test
+ */
+
+/**
+ * audio_dev_open() - Open char device.
+ * @inode: Device driver information.
+ * @filp: Pointer to the file struct.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ENOMEM if allocation failed.
+ * Errors from @cg2900_audio_open.
+ */
+static int audio_dev_open(struct inode *inode, struct file *filp)
+{
+ int err;
+ struct char_dev_info *char_dev_info;
+
+ CG2900_INFO("CG2900 Audio: audio_dev_open");
+
+ /*
+ * Allocate the char dev info structure. It will be stored inside
+ * the file pointer and supplied when file_ops are called.
+ * It's free'd in audio_dev_release.
+ */
+ char_dev_info = kzalloc(sizeof(*char_dev_info), GFP_KERNEL);
+ if (!char_dev_info) {
+ CG2900_ERR("Couldn't allocate char_dev_info");
+ return -ENOMEM;
+ }
+ filp->private_data = char_dev_info;
+
+ mutex_init(&char_dev_info->management_mutex);
+ mutex_init(&char_dev_info->rw_mutex);
+
+ mutex_lock(&char_dev_info->management_mutex);
+ err = cg2900_audio_open(&char_dev_info->session);
+ mutex_unlock(&char_dev_info->management_mutex);
+ if (err) {
+ CG2900_ERR("Failed to open CG2900 Audio driver (%d)", err);
+ goto error_handling_free_mem;
+ }
+
+ return 0;
+
+error_handling_free_mem:
+ kfree(char_dev_info);
+ filp->private_data = NULL;
+ return err;
+}
+
+/**
+ * audio_dev_release() - Release char device.
+ * @inode: Device driver information.
+ * @filp: Pointer to the file struct.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EBADF if NULL pointer was supplied in private data.
+ * Errors from @cg2900_audio_close.
+ */
+static int audio_dev_release(struct inode *inode, struct file *filp)
+{
+ int err = 0;
+ struct char_dev_info *dev = (struct char_dev_info *)filp->private_data;
+
+ CG2900_INFO("CG2900 Audio: audio_dev_release");
+
+ if (!dev) {
+ CG2900_ERR("No dev supplied in private data");
+ return -EBADF;
+ }
+
+ mutex_lock(&dev->management_mutex);
+ err = cg2900_audio_close(&dev->session);
+ if (err)
+ /*
+ * Just print the error. Still free the char_dev_info since we
+ * don't know the filp structure is valid after this call
+ */
+ CG2900_ERR("Error when closing CG2900 audio driver (%d)", err);
+
+ mutex_unlock(&dev->management_mutex);
+
+ kfree(dev);
+ filp->private_data = NULL;
+
+ return err;
+}
+
+/**
+ * audio_dev_read() - Return information to the user from last @write call.
+ * @filp: Pointer to the file struct.
+ * @buf: Received buffer.
+ * @count: Size of buffer.
+ * @f_pos: Position in buffer.
+ *
+ * The audio_dev_read() function returns information from
+ * the last @write call to same char device.
+ * The data is in the following format:
+ * * OpCode of command for this data
+ * * Data content (Length of data is determined by the command OpCode, i.e.
+ * fixed for each command)
+ *
+ * Returns:
+ * Bytes successfully read (could be 0).
+ * -EBADF if NULL pointer was supplied in private data.
+ * -EFAULT if copy_to_user fails.
+ * -ENOMEM upon allocation failure.
+ */
+static ssize_t audio_dev_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ struct char_dev_info *dev = (struct char_dev_info *)filp->private_data;
+ unsigned int bytes_to_copy = 0;
+ int err = 0;
+
+ CG2900_INFO("CG2900 Audio: audio_dev_read");
+
+ if (!dev) {
+ CG2900_ERR("No dev supplied in private data");
+ return -EBADF;
+ }
+ mutex_lock(&dev->rw_mutex);
+
+ if (dev->stored_data_len == 0) {
+ /* No data to read */
+ bytes_to_copy = 0;
+ goto finished;
+ }
+
+ bytes_to_copy = min(count, (unsigned int)(dev->stored_data_len));
+ if (bytes_to_copy < dev->stored_data_len)
+ CG2900_ERR("Not enough buffer to store all data. Throwing away "
+ "rest of data.");
+
+ err = copy_to_user(buf, dev->stored_data, bytes_to_copy);
+ /*
+ * Throw away all data, even though not all was copied.
+ * This char device is primarily for testing purposes so we can keep
+ * such a limitation.
+ */
+ kfree(dev->stored_data);
+ dev->stored_data = NULL;
+ dev->stored_data_len = 0;
+
+ if (err) {
+ CG2900_ERR("copy_to_user error %d", err);
+ err = -EFAULT;
+ goto error_handling;
+ }
+
+ goto finished;
+
+error_handling:
+ mutex_unlock(&dev->rw_mutex);
+ return (ssize_t)err;
+finished:
+ mutex_unlock(&dev->rw_mutex);
+ return bytes_to_copy;
+}
+
+/**
+ * audio_dev_write() - Call CG2900 Audio API function.
+ * @filp: Pointer to the file struct.
+ * @buf: Write buffer.
+ * @count: Size of the buffer write.
+ * @f_pos: Position of buffer.
+ *
+ * audio_dev_write() function executes supplied data and
+ * interprets it as if it was a function call to the CG2900 Audio API.
+ * The data is according to:
+ * * OpCode (4 bytes)
+ * * Data according to OpCode (see API). No padding between parameters
+ *
+ * OpCodes are:
+ * * OP_CODE_SET_DAI_CONF 0x00000001
+ * * OP_CODE_GET_DAI_CONF 0x00000002
+ * * OP_CODE_CONFIGURE_ENDPOINT 0x00000003
+ * * OP_CODE_START_STREAM 0x00000004
+ * * OP_CODE_STOP_STREAM 0x00000005
+ *
+ * Returns:
+ * Bytes successfully written (could be 0). Equals input @count if successful.
+ * -EBADF if NULL pointer was supplied in private data.
+ * -EFAULT if copy_from_user fails.
+ * Error codes from all CG2900 Audio API functions.
+ */
+static ssize_t audio_dev_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ u8 *rec_data;
+ struct char_dev_info *dev = (struct char_dev_info *)filp->private_data;
+ int err = 0;
+ int op_code = 0;
+ u8 *curr_data;
+ unsigned int stream_handle;
+ struct cg2900_dai_config dai_config;
+ struct cg2900_endpoint_config ep_config;
+ enum cg2900_audio_endpoint_id ep_1;
+ enum cg2900_audio_endpoint_id ep_2;
+ int bytes_left = count;
+
+ CG2900_INFO("CG2900 Audio: audio_dev_write count %d", count);
+
+ if (!dev) {
+ CG2900_ERR("No dev supplied in private data");
+ return -EBADF;
+ }
+
+ rec_data = kmalloc(count, GFP_KERNEL);
+ if (!rec_data) {
+ CG2900_ERR("kmalloc failed");
+ return -ENOMEM;
+ }
+
+ mutex_lock(&dev->rw_mutex);
+
+ err = copy_from_user(rec_data, buf, count);
+ if (err) {
+ CG2900_ERR("copy_from_user failed (%d)", err);
+ err = -EFAULT;
+ goto finished_mutex_unlock;
+ }
+
+ /* Initialize temporary data pointer used to traverse the packet */
+ curr_data = rec_data;
+
+ op_code = curr_data[0];
+ CG2900_DBG("op_code %d", op_code);
+ /* OpCode is int size to keep data int aligned */
+ curr_data += sizeof(unsigned int);
+ bytes_left -= sizeof(unsigned int);
+
+ switch (op_code) {
+ case OP_CODE_SET_DAI_CONF:
+ CG2900_DBG("OP_CODE_SET_DAI_CONF %d", sizeof(dai_config));
+ if (bytes_left < sizeof(dai_config)) {
+ CG2900_ERR("Not enough data supplied for "
+ "OP_CODE_SET_DAI_CONF");
+ err = -EINVAL;
+ goto finished_mutex_unlock;
+ }
+ memcpy(&dai_config, curr_data, sizeof(dai_config));
+ CG2900_DBG("dai_config.port %d", dai_config.port);
+ err = cg2900_audio_set_dai_config(dev->session, &dai_config);
+ break;
+
+ case OP_CODE_GET_DAI_CONF:
+ CG2900_DBG("OP_CODE_GET_DAI_CONF %d", sizeof(dai_config));
+ if (bytes_left < sizeof(dai_config)) {
+ CG2900_ERR("Not enough data supplied for "
+ "OP_CODE_GET_DAI_CONF");
+ err = -EINVAL;
+ goto finished_mutex_unlock;
+ }
+ /*
+ * Only need to copy the port really, but let's copy
+ * like this for simplicity. It's only test functionality
+ * after all.
+ */
+ memcpy(&dai_config, curr_data, sizeof(dai_config));
+ CG2900_DBG("dai_config.port %d", dai_config.port);
+ err = cg2900_audio_get_dai_config(dev->session, &dai_config);
+ if (!err) {
+ /*
+ * Command succeeded. Store data so it can be returned
+ * when calling read.
+ */
+ if (dev->stored_data) {
+ CG2900_ERR("Data already allocated (%d bytes). "
+ "Throwing it away.",
+ dev->stored_data_len);
+ kfree(dev->stored_data);
+ }
+ dev->stored_data_len = sizeof(op_code) +
+ sizeof(dai_config);
+ dev->stored_data = kmalloc(dev->stored_data_len,
+ GFP_KERNEL);
+ if (dev->stored_data) {
+ memcpy(dev->stored_data, &op_code,
+ sizeof(op_code));
+ memcpy(&(dev->stored_data[sizeof(op_code)]),
+ &dai_config, sizeof(dai_config));
+ }
+ }
+ break;
+
+ case OP_CODE_CONFIGURE_ENDPOINT:
+ CG2900_DBG("OP_CODE_CONFIGURE_ENDPOINT %d", sizeof(ep_config));
+ if (bytes_left < sizeof(ep_config)) {
+ CG2900_ERR("Not enough data supplied for "
+ "OP_CODE_CONFIGURE_ENDPOINT");
+ err = -EINVAL;
+ goto finished_mutex_unlock;
+ }
+ memcpy(&ep_config, curr_data, sizeof(ep_config));
+ CG2900_DBG("ep_config.endpoint_id %d", ep_config.endpoint_id);
+ err = cg2900_audio_config_endpoint(dev->session, &ep_config);
+ break;
+
+ case OP_CODE_START_STREAM:
+ CG2900_DBG("OP_CODE_START_STREAM %d",
+ (sizeof(ep_1) + sizeof(ep_2)));
+ if (bytes_left < (sizeof(ep_1) + sizeof(ep_2))) {
+ CG2900_ERR("Not enough data supplied for "
+ "OP_CODE_START_STREAM");
+ err = -EINVAL;
+ goto finished_mutex_unlock;
+ }
+ memcpy(&ep_1, curr_data, sizeof(ep_1));
+ curr_data += sizeof(ep_1);
+ memcpy(&ep_2, curr_data, sizeof(ep_2));
+ CG2900_DBG("ep_1 %d ep_2 %d", ep_1,
+ ep_2);
+
+ err = cg2900_audio_start_stream(dev->session,
+ ep_1, ep_2, &stream_handle);
+ if (!err) {
+ /*
+ * Command succeeded. Store data so it can be returned
+ * when calling read.
+ */
+ if (dev->stored_data) {
+ CG2900_ERR("Data already allocated (%d bytes). "
+ "Throwing it away.",
+ dev->stored_data_len);
+ kfree(dev->stored_data);
+ }
+ dev->stored_data_len = sizeof(op_code) +
+ sizeof(stream_handle);
+ dev->stored_data = kmalloc(dev->stored_data_len,
+ GFP_KERNEL);
+ if (dev->stored_data) {
+ memcpy(dev->stored_data, &op_code,
+ sizeof(op_code));
+ memcpy(&(dev->stored_data[sizeof(op_code)]),
+ &stream_handle, sizeof(stream_handle));
+ }
+ CG2900_DBG("stream_handle %d", stream_handle);
+ }
+ break;
+
+ case OP_CODE_STOP_STREAM:
+ if (bytes_left < sizeof(stream_handle)) {
+ CG2900_ERR("Not enough data supplied for "
+ "OP_CODE_STOP_STREAM");
+ err = -EINVAL;
+ goto finished_mutex_unlock;
+ }
+ CG2900_DBG("OP_CODE_STOP_STREAM %d", sizeof(stream_handle));
+ memcpy(&stream_handle, curr_data, sizeof(stream_handle));
+ CG2900_DBG("stream_handle %d", stream_handle);
+ err = cg2900_audio_stop_stream(dev->session, stream_handle);
+ break;
+
+ default:
+ CG2900_ERR("Received bad op_code %d", op_code);
+ break;
+ };
+
+finished_mutex_unlock:
+ kfree(rec_data);
+ mutex_unlock(&dev->rw_mutex);
+
+ if (err)
+ return err;
+ else
+ return count;
+}
+
+/**
+ * audio_dev_poll() - Handle POLL call to the interface.
+ * @filp: Pointer to the file struct.
+ * @wait: Poll table supplied to caller.
+ *
+ * This function is used by the User Space application to see if the device is
+ * still open and if there is any data available for reading.
+ *
+ * Returns:
+ * Mask of current set POLL values.
+ */
+static unsigned int audio_dev_poll(struct file *filp, poll_table *wait)
+{
+ struct char_dev_info *dev = (struct char_dev_info *)filp->private_data;
+ unsigned int mask = 0;
+
+ if (!dev) {
+ CG2900_ERR("No dev supplied in private data");
+ return POLLERR | POLLRDHUP;
+ }
+
+ if (RESET == audio_info->state)
+ mask |= POLLERR | POLLRDHUP | POLLPRI;
+ else
+ /* Unless RESET we can transmit */
+ mask |= POLLOUT;
+
+ if (dev->stored_data)
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+static const struct file_operations char_dev_fops = {
+ .open = audio_dev_open,
+ .release = audio_dev_release,
+ .read = audio_dev_read,
+ .write = audio_dev_write,
+ .poll = audio_dev_poll
+};
+
+/*
+ * Module related methods
+ */
+
+/**
+ * cg2900_audio_init() - Initialize module.
+ *
+ * Initialize the module and register misc device.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ENOMEM if allocation fails.
+ * -EEXIST if device has already been started.
+ * Error codes from misc_register.
+ */
+static int __init cg2900_audio_init(void)
+{
+ int err;
+
+ CG2900_INFO("cg2900_audio_init");
+
+ if (audio_info) {
+ CG2900_ERR("ST-Ericsson CG2900 Audio driver already initiated");
+ return -EEXIST;
+ }
+
+ /* Initialize private data. */
+ audio_info = kzalloc(sizeof(*audio_info), GFP_KERNEL);
+ if (!audio_info) {
+ CG2900_ERR("Could not alloc audio_info struct.");
+ return -ENOMEM;
+ }
+
+ /* Initiate the mutexes */
+ mutex_init(&(audio_info->management_mutex));
+ mutex_init(&(audio_info->bt_mutex));
+ mutex_init(&(audio_info->fm_mutex));
+ mutex_init(&(audio_info->endpoints.management_mutex));
+
+ /* Initiate the SKB queues */
+ skb_queue_head_init(&(audio_info->bt_queue));
+ skb_queue_head_init(&(audio_info->fm_queue));
+
+ /* Initiate the endpoint list */
+ INIT_LIST_HEAD(&(audio_info->endpoints.ep_list));
+
+ /* Prepare and register MISC device */
+ audio_info->dev.minor = MISC_DYNAMIC_MINOR;
+ audio_info->dev.name = DEVICE_NAME;
+ audio_info->dev.fops = &char_dev_fops;
+ audio_info->dev.parent = NULL;
+
+ err = misc_register(&(audio_info->dev));
+ if (err) {
+ CG2900_ERR("Error %d registering misc dev!", err);
+ goto error_handling;
+ }
+
+ return 0;
+
+error_handling:
+ mutex_destroy(&audio_info->management_mutex);
+ mutex_destroy(&audio_info->bt_mutex);
+ mutex_destroy(&audio_info->fm_mutex);
+ mutex_destroy(&audio_info->endpoints.management_mutex);
+ kfree(audio_info);
+ audio_info = NULL;
+ return err;
+}
+
+/**
+ * cg2900_audio_exit() - Remove module.
+ *
+ * Remove misc device and free resources.
+ */
+static void __exit cg2900_audio_exit(void)
+{
+ int err;
+
+ CG2900_INFO("cg2900_audio_exit");
+
+ if (!audio_info)
+ return;
+
+ err = misc_deregister(&audio_info->dev);
+ if (err)
+ CG2900_ERR("Error deregistering misc dev (%d)!", err);
+
+ mutex_destroy(&audio_info->management_mutex);
+ mutex_destroy(&audio_info->bt_mutex);
+ mutex_destroy(&audio_info->fm_mutex);
+
+ flush_endpoint_list(&(audio_info->endpoints));
+
+ skb_queue_purge(&(audio_info->bt_queue));
+ skb_queue_purge(&(audio_info->fm_queue));
+
+ mutex_destroy(&audio_info->endpoints.management_mutex);
+
+ kfree(audio_info);
+ audio_info = NULL;
+}
+
+module_init(cg2900_audio_init);
+module_exit(cg2900_audio_exit);
+
+MODULE_AUTHOR("Par-Gunnar Hjalmdahl ST-Ericsson");
+MODULE_AUTHOR("Kjell Andersson ST-Ericsson");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Linux Bluetooth Audio ST-Ericsson controller");
diff --git a/drivers/mfd/cg2900/cg2900_char_devices.c b/drivers/mfd/cg2900/cg2900_char_devices.c
new file mode 100644
index 00000000000..709689bec3a
--- /dev/null
+++ b/drivers/mfd/cg2900/cg2900_char_devices.c
@@ -0,0 +1,709 @@
+/*
+ * drivers/mfd/cg2900/cg2900_char_devices.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth HCI H:4 Driver for ST-Ericsson connectivity controller.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/poll.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+
+#include <linux/mfd/cg2900.h>
+#include <mach/cg2900_devices.h>
+#include "cg2900_core.h"
+#include "cg2900_debug.h"
+
+/* Ioctls */
+#define CG2900_CHAR_DEV_IOCTL_RESET _IOW('U', 210, int)
+#define CG2900_CHAR_DEV_IOCTL_CHECK4RESET _IOR('U', 212, int)
+#define CG2900_CHAR_DEV_IOCTL_GET_REVISION _IOR('U', 213, int)
+#define CG2900_CHAR_DEV_IOCTL_GET_SUB_VER _IOR('U', 214, int)
+
+#define CG2900_CHAR_DEV_IOCTL_EVENT_RESET 1
+#define CG2900_CHAR_DEV_IOCTL_EVENT_CLOSED 2
+
+/* Internal type definitions */
+
+/**
+ * enum char_reset_state - Reset state.
+ * @CG2900_CHAR_IDLE: Idle state.
+ * @CG2900_CHAR_RESET: Reset state.
+ */
+enum char_reset_state {
+ CG2900_CHAR_IDLE,
+ CG2900_CHAR_RESET
+};
+
+/**
+ * struct char_dev_user - Stores device information.
+ * @dev: Registered CG2900 Core device.
+ * @miscdev: Registered device struct.
+ * @name: Name of device.
+ * @rx_queue: Data queue.
+ * @rx_wait_queue: Wait queue.
+ * @reset_wait_queue: Reset Wait queue.
+ * @reset_state: Reset state.
+ * @read_mutex: Read mutex.
+ * @write_mutex: Write mutex.
+ * @list: List header for inserting into device list.
+ */
+struct char_dev_user {
+ struct cg2900_device *dev;
+ struct miscdevice *miscdev;
+ char *name;
+ struct sk_buff_head rx_queue;
+ wait_queue_head_t rx_wait_queue;
+ wait_queue_head_t reset_wait_queue;
+ enum char_reset_state reset_state;
+ struct mutex read_mutex;
+ struct mutex write_mutex;
+ struct list_head list;
+};
+
+/**
+ * struct char_info - Stores all current users.
+ * @open_mutex: Open mutex (used for both open and release).
+ * @dev_users: List of char dev users.
+ */
+struct char_info {
+ struct mutex open_mutex;
+ struct list_head dev_users;
+};
+
+/* Internal variable declarations */
+
+/*
+ * char_info - Main information object for char devices.
+ */
+static struct char_info *char_info;
+
+/* ST-Ericsson CG2900 driver callbacks */
+
+/**
+ * char_dev_read_cb() - Handle data received from controller.
+ * @dev: Device receiving data.
+ * @skb: Buffer with data coming from controller.
+ *
+ * The char_dev_read_cb() function handles data received from STE-CG2900 driver.
+ */
+static void char_dev_read_cb(struct cg2900_device *dev, struct sk_buff *skb)
+{
+ struct char_dev_user *char_dev = (struct char_dev_user *)dev->user_data;
+
+ CG2900_INFO("CharDev: char_dev_read_cb");
+
+ if (!char_dev) {
+ CG2900_ERR("No char dev! Exiting");
+ kfree_skb(skb);
+ return;
+ }
+
+ skb_queue_tail(&char_dev->rx_queue, skb);
+
+ wake_up_interruptible(&char_dev->rx_wait_queue);
+}
+
+/**
+ * char_dev_reset_cb() - Handle reset from controller.
+ * @dev: Device resetting.
+ *
+ * The char_dev_reset_cb() function handles reset from the CG2900 driver.
+ */
+static void char_dev_reset_cb(struct cg2900_device *dev)
+{
+ struct char_dev_user *char_dev = (struct char_dev_user *)dev->user_data;
+
+ CG2900_INFO("CharDev: char_dev_reset_cb");
+
+ if (!char_dev) {
+ CG2900_ERR("char_dev == NULL");
+ return;
+ }
+
+ char_dev->reset_state = CG2900_CHAR_RESET;
+ /*
+ * The device will be freed by CG2900 Core when this function is
+ * finished.
+ */
+ char_dev->dev = NULL;
+
+ wake_up_interruptible(&char_dev->rx_wait_queue);
+ wake_up_interruptible(&char_dev->reset_wait_queue);
+}
+
+/*
+ * struct char_cb - Callback structure for CG2900 user.
+ * @read_cb: Callback function called when data is received from the
+ * CG2900 driver.
+ * @reset_cb: Callback function called when the controller has been reset.
+ */
+static struct cg2900_callbacks char_cb = {
+ .read_cb = char_dev_read_cb,
+ .reset_cb = char_dev_reset_cb
+};
+
+/* File operation functions */
+
+/**
+ * char_dev_open() - Open char device.
+ * @inode: Device driver information.
+ * @filp: Pointer to the file struct.
+ *
+ * The char_dev_open() function opens the char device.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EACCES if device was already registered to driver or if registration
+ * failed.
+ */
+static int char_dev_open(struct inode *inode, struct file *filp)
+{
+ int err = 0;
+ int minor;
+ struct char_dev_user *dev = NULL;
+ struct char_dev_user *tmp;
+ struct list_head *cursor;
+
+ mutex_lock(&char_info->open_mutex);
+
+ minor = iminor(inode);
+
+ /* Find the device for this file */
+ list_for_each(cursor, &char_info->dev_users) {
+ tmp = list_entry(cursor, struct char_dev_user, list);
+ if (tmp->miscdev->minor == minor) {
+ dev = tmp;
+ break;
+ }
+ }
+ if (!dev) {
+ CG2900_ERR("Could not identify device in inode");
+ err = -EINVAL;
+ goto error_handling;
+ }
+
+ filp->private_data = dev;
+
+ CG2900_INFO("CharDev: char_dev_open %s", dev->name);
+
+ if (dev->dev) {
+ CG2900_ERR("Device already registered to CG2900 Driver");
+ err = -EACCES;
+ goto error_handling;
+ }
+ /* First initiate wait queues for this device. */
+ init_waitqueue_head(&dev->rx_wait_queue);
+ init_waitqueue_head(&dev->reset_wait_queue);
+
+ dev->reset_state = CG2900_CHAR_IDLE;
+
+ /* Register to CG2900 Driver */
+ dev->dev = cg2900_register_user(dev->name, &char_cb);
+ if (dev->dev)
+ dev->dev->user_data = dev;
+ else {
+ CG2900_ERR("Couldn't register to CG2900 for H:4 channel %s",
+ dev->name);
+ err = -EACCES;
+ }
+
+error_handling:
+ mutex_unlock(&char_info->open_mutex);
+ return err;
+}
+
+/**
+ * char_dev_release() - Release char device.
+ * @inode: Device driver information.
+ * @filp: Pointer to the file struct.
+ *
+ * The char_dev_release() function release the char device.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EBADF if NULL pointer was supplied in private data.
+ */
+static int char_dev_release(struct inode *inode, struct file *filp)
+{
+ int err = 0;
+ struct char_dev_user *dev = (struct char_dev_user *)filp->private_data;
+
+ CG2900_INFO("CharDev: char_dev_release");
+
+ if (!dev) {
+ CG2900_ERR("Calling with NULL pointer");
+ return -EBADF;
+ }
+
+ mutex_lock(&char_info->open_mutex);
+ mutex_lock(&dev->read_mutex);
+ mutex_lock(&dev->write_mutex);
+
+ if (dev->reset_state == CG2900_CHAR_IDLE)
+ cg2900_deregister_user(dev->dev);
+
+ dev->dev = NULL;
+ filp->private_data = NULL;
+ wake_up_interruptible(&dev->rx_wait_queue);
+ wake_up_interruptible(&dev->reset_wait_queue);
+
+ mutex_unlock(&dev->write_mutex);
+ mutex_unlock(&dev->read_mutex);
+ mutex_unlock(&char_info->open_mutex);
+
+ return err;
+}
+
+/**
+ * char_dev_read() - Queue and copy buffer to user.
+ * @filp: Pointer to the file struct.
+ * @buf: Received buffer.
+ * @count: Size of buffer.
+ * @f_pos: Position in buffer.
+ *
+ * The char_dev_read() function queues and copy the received buffer to
+ * the user space char device. If no data is available this function will block.
+ *
+ * Returns:
+ * Bytes successfully read (could be 0).
+ * -EBADF if NULL pointer was supplied in private data.
+ * -EFAULT if copy_to_user fails.
+ * Error codes from wait_event_interruptible.
+ */
+static ssize_t char_dev_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ struct char_dev_user *dev = (struct char_dev_user *)filp->private_data;
+ struct sk_buff *skb;
+ int bytes_to_copy;
+ int err = 0;
+
+ CG2900_INFO("CharDev: char_dev_read");
+
+ if (!dev) {
+ CG2900_ERR("Calling with NULL pointer");
+ return -EBADF;
+ }
+ mutex_lock(&dev->read_mutex);
+
+ if (skb_queue_empty(&dev->rx_queue)) {
+ err = wait_event_interruptible(dev->rx_wait_queue,
+ (!(skb_queue_empty(&dev->rx_queue))) ||
+ (CG2900_CHAR_RESET == dev->reset_state) ||
+ (dev->dev == NULL));
+ if (err) {
+ CG2900_ERR("Failed to wait for event");
+ goto error_handling;
+ }
+ }
+
+ if (!dev->dev) {
+ CG2900_DBG("dev is empty - return with negative bytes");
+ err = -EBADF;
+ goto error_handling;
+ }
+
+ skb = skb_dequeue(&dev->rx_queue);
+ if (!skb) {
+ CG2900_DBG("skb queue is empty - return with zero bytes");
+ bytes_to_copy = 0;
+ goto finished;
+ }
+
+ bytes_to_copy = min(count, skb->len);
+
+ err = copy_to_user(buf, skb->data, bytes_to_copy);
+ if (err) {
+ skb_queue_head(&dev->rx_queue, skb);
+ err = -EFAULT;
+ goto error_handling;
+ }
+
+ skb_pull(skb, bytes_to_copy);
+
+ if (skb->len > 0)
+ skb_queue_head(&dev->rx_queue, skb);
+ else
+ kfree_skb(skb);
+
+ goto finished;
+
+error_handling:
+ mutex_unlock(&dev->read_mutex);
+ return (ssize_t)err;
+finished:
+ mutex_unlock(&dev->read_mutex);
+ return bytes_to_copy;
+}
+
+/**
+ * char_dev_write() - Copy buffer from user and write to CG2900 driver.
+ * @filp: Pointer to the file struct.
+ * @buf: Write buffer.
+ * @count: Size of the buffer write.
+ * @f_pos: Position of buffer.
+ *
+ * Returns:
+ * Bytes successfully written (could be 0).
+ * -EBADF if NULL pointer was supplied in private data.
+ * -EFAULT if copy_from_user fails.
+ */
+static ssize_t char_dev_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ struct sk_buff *skb;
+ struct char_dev_user *dev = (struct char_dev_user *)filp->private_data;
+ int err = 0;
+
+ CG2900_INFO("CharDev: char_dev_write");
+
+ if (!dev) {
+ CG2900_ERR("Calling with NULL pointer");
+ return -EBADF;
+ }
+ mutex_lock(&dev->write_mutex);
+
+ skb = cg2900_alloc_skb(count, GFP_ATOMIC);
+ if (!skb) {
+ CG2900_ERR("Couldn't allocate sk_buff with length %d", count);
+ goto error_handling;
+ }
+
+ if (copy_from_user(skb_put(skb, count), buf, count)) {
+ kfree_skb(skb);
+ err = -EFAULT;
+ goto error_handling;
+ }
+
+ err = cg2900_write(dev->dev, skb);
+ if (err) {
+ CG2900_ERR("cg2900_write failed (%d)", err);
+ kfree_skb(skb);
+ goto error_handling;
+ }
+
+ mutex_unlock(&dev->write_mutex);
+ return count;
+
+error_handling:
+ mutex_unlock(&dev->write_mutex);
+ return err;
+}
+
+/**
+ * char_dev_unlocked_ioctl() - Handle IOCTL call to the interface.
+ * @filp: Pointer to the file struct.
+ * @cmd: IOCTL command.
+ * @arg: IOCTL argument.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EBADF if NULL pointer was supplied in private data.
+ * -EINVAL if supplied cmd is not supported.
+ * For cmd CG2900_CHAR_DEV_IOCTL_CHECK4RESET 0x01 is returned if device is
+ * reset and 0x02 is returned if device is closed.
+ */
+static long char_dev_unlocked_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct char_dev_user *dev = (struct char_dev_user *)filp->private_data;
+ struct cg2900_rev_data rev_data;
+ int err = 0;
+
+ CG2900_INFO("CharDev: char_dev_unlocked_ioctl cmd %d for %s", cmd,
+ dev->name);
+ CG2900_DBG("DIR: %d, TYPE: %d, NR: %d, SIZE: %d",
+ _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd),
+ _IOC_SIZE(cmd));
+
+ switch (cmd) {
+ case CG2900_CHAR_DEV_IOCTL_RESET:
+ if (!dev) {
+ err = -EBADF;
+ goto error_handling;
+ }
+ CG2900_INFO("ioctl reset command for device %s", dev->name);
+ err = cg2900_reset(dev->dev);
+ break;
+
+ case CG2900_CHAR_DEV_IOCTL_CHECK4RESET:
+ if (!dev) {
+ CG2900_INFO("ioctl check for reset command for device");
+ /* Return positive value if closed */
+ err = CG2900_CHAR_DEV_IOCTL_EVENT_CLOSED;
+ } else if (dev->reset_state == CG2900_CHAR_RESET) {
+ CG2900_INFO("ioctl check for reset command for device "
+ "%s", dev->name);
+ /* Return positive value if reset */
+ err = CG2900_CHAR_DEV_IOCTL_EVENT_RESET;
+ }
+ break;
+
+ case CG2900_CHAR_DEV_IOCTL_GET_REVISION:
+ CG2900_INFO("ioctl check for local revision info");
+ if (cg2900_get_local_revision(&rev_data)) {
+ CG2900_DBG("Read revision data revision %d "
+ "sub_version %d",
+ rev_data.revision, rev_data.sub_version);
+ err = rev_data.revision;
+ } else {
+ CG2900_DBG("No revision data available");
+ err = -EIO;
+ }
+ break;
+
+ case CG2900_CHAR_DEV_IOCTL_GET_SUB_VER:
+ CG2900_INFO("ioctl check for local sub-version info");
+ if (cg2900_get_local_revision(&rev_data)) {
+ CG2900_DBG("Read revision data revision %d "
+ "sub_version %d",
+ rev_data.revision, rev_data.sub_version);
+ err = rev_data.sub_version;
+ } else {
+ CG2900_DBG("No revision data available");
+ err = -EIO;
+ }
+ break;
+
+ default:
+ CG2900_ERR("Unknown ioctl command %08X", cmd);
+ err = -EINVAL;
+ break;
+ };
+
+error_handling:
+ return err;
+}
+
+/**
+ * char_dev_poll() - Handle POLL call to the interface.
+ * @filp: Pointer to the file struct.
+ * @wait: Poll table supplied to caller.
+ *
+ * Returns:
+ * Mask of current set POLL values
+ */
+static unsigned int char_dev_poll(struct file *filp, poll_table *wait)
+{
+ struct char_dev_user *dev = (struct char_dev_user *)filp->private_data;
+ unsigned int mask = 0;
+
+ if (!dev) {
+ CG2900_DBG("Device not open");
+ return POLLERR | POLLRDHUP;
+ }
+
+ poll_wait(filp, &dev->reset_wait_queue, wait);
+ poll_wait(filp, &dev->rx_wait_queue, wait);
+
+ if (!dev->dev)
+ mask |= POLLERR | POLLRDHUP;
+ else
+ mask |= POLLOUT; /* We can TX unless there is an error */
+
+ if (!(skb_queue_empty(&dev->rx_queue)))
+ mask |= POLLIN | POLLRDNORM;
+
+ if (CG2900_CHAR_RESET == dev->reset_state)
+ mask |= POLLPRI;
+
+ return mask;
+}
+
+/*
+ * struct char_dev_fops - Char devices file operations.
+ * @read: Function that reads from the char device.
+ * @write: Function that writes to the char device.
+ * @unlocked_ioctl: Function that performs IO operations with
+ * the char device.
+ * @poll: Function that checks if there are possible operations
+ * with the char device.
+ * @open: Function that opens the char device.
+ * @release: Function that release the char device.
+ */
+static const struct file_operations char_dev_fops = {
+ .read = char_dev_read,
+ .write = char_dev_write,
+ .unlocked_ioctl = char_dev_unlocked_ioctl,
+ .poll = char_dev_poll,
+ .open = char_dev_open,
+ .release = char_dev_release
+};
+
+/**
+ * setup_dev() - Set up the char device structure for device.
+ * @parent: Parent device pointer.
+ * @name: Name of registered device.
+ *
+ * The setup_dev() function sets up the char_dev structure for this device.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL if NULL pointer has been supplied.
+ * Error codes from cdev_add and device_create.
+ */
+static int setup_dev(struct device *parent, char *name)
+{
+ int err = 0;
+ struct char_dev_user *dev_usr;
+
+ CG2900_INFO("CharDev: setup_dev");
+
+ dev_usr = kzalloc(sizeof(*dev_usr), GFP_KERNEL);
+ if (!dev_usr) {
+ CG2900_ERR("Couldn't allocate dev_usr");
+ return -ENOMEM;
+ }
+
+ /* Store device name */
+ dev_usr->name = name;
+
+ dev_usr->miscdev = kzalloc(sizeof(*(dev_usr->miscdev)),
+ GFP_KERNEL);
+ if (!dev_usr->miscdev) {
+ CG2900_ERR("Couldn't allocate char_dev");
+ err = -ENOMEM;
+ goto err_free_usr;
+ }
+
+ /* Prepare miscdevice struct before registering the device */
+ dev_usr->miscdev->minor = MISC_DYNAMIC_MINOR;
+ dev_usr->miscdev->name = name;
+ dev_usr->miscdev->fops = &char_dev_fops;
+ dev_usr->miscdev->parent = parent;
+
+ err = misc_register(dev_usr->miscdev);
+ if (err) {
+ CG2900_ERR("Error %d registering misc dev!", err);
+ goto err_free_dev;
+ }
+
+ CG2900_INFO("Added char device %s with major 0x%X and minor 0x%X",
+ name, MAJOR(dev_usr->miscdev->this_device->devt),
+ MINOR(dev_usr->miscdev->this_device->devt));
+
+ mutex_init(&dev_usr->read_mutex);
+ mutex_init(&dev_usr->write_mutex);
+
+ skb_queue_head_init(&dev_usr->rx_queue);
+
+ list_add_tail(&dev_usr->list, &char_info->dev_users);
+ return 0;
+
+err_free_dev:
+ kfree(dev_usr->miscdev);
+ dev_usr->miscdev = NULL;
+err_free_usr:
+ kfree(dev_usr);
+ return err;
+}
+
+/**
+ * remove_dev() - Remove char device structure for device.
+ * @dev_usr: Char device user.
+ *
+ * The remove_dev() function releases the char_dev structure for this device.
+ */
+static void remove_dev(struct char_dev_user *dev_usr)
+{
+ CG2900_INFO("CharDev: remove_dev");
+
+ if (!dev_usr)
+ return;
+
+ skb_queue_purge(&dev_usr->rx_queue);
+
+ mutex_destroy(&dev_usr->read_mutex);
+ mutex_destroy(&dev_usr->write_mutex);
+
+ /* Remove device node in file system. */
+ misc_deregister(dev_usr->miscdev);
+ kfree(dev_usr->miscdev);
+ dev_usr->miscdev = NULL;
+
+ kfree(dev_usr);
+}
+
+/* External functions */
+
+void cg2900_char_devices_init(struct miscdevice *dev)
+{
+ CG2900_INFO("cg2900_char_devices_init");
+
+ if (!dev) {
+ CG2900_ERR("NULL supplied for dev");
+ return;
+ }
+
+ if (char_info) {
+ CG2900_ERR("Char devices already initiated");
+ return;
+ }
+
+ /* Initialize private data. */
+ char_info = kzalloc(sizeof(*char_info), GFP_ATOMIC);
+ if (!char_info) {
+ CG2900_ERR("Could not alloc char_info struct.");
+ return;
+ }
+
+ mutex_init(&char_info->open_mutex);
+ INIT_LIST_HEAD(&char_info->dev_users);
+
+ setup_dev(dev->this_device, CG2900_BT_CMD);
+ setup_dev(dev->this_device, CG2900_BT_ACL);
+ setup_dev(dev->this_device, CG2900_BT_EVT);
+ setup_dev(dev->this_device, CG2900_FM_RADIO);
+ setup_dev(dev->this_device, CG2900_GNSS);
+ setup_dev(dev->this_device, CG2900_DEBUG);
+ setup_dev(dev->this_device, CG2900_STE_TOOLS);
+ setup_dev(dev->this_device, CG2900_HCI_LOGGER);
+ setup_dev(dev->this_device, CG2900_US_CTRL);
+ setup_dev(dev->this_device, CG2900_BT_AUDIO);
+ setup_dev(dev->this_device, CG2900_FM_RADIO_AUDIO);
+ setup_dev(dev->this_device, CG2900_CORE);
+}
+
+void cg2900_char_devices_exit(void)
+{
+ struct list_head *cursor, *next;
+ struct char_dev_user *tmp;
+
+ CG2900_INFO("cg2900_char_devices_exit");
+
+ if (!char_info)
+ return;
+
+ list_for_each_safe(cursor, next, &char_info->dev_users) {
+ tmp = list_entry(cursor, struct char_dev_user, list);
+ list_del(cursor);
+ remove_dev(tmp);
+ }
+
+ mutex_destroy(&char_info->open_mutex);
+
+ kfree(char_info);
+ char_info = NULL;
+}
+
+MODULE_AUTHOR("Henrik Possung ST-Ericsson");
+MODULE_AUTHOR("Par-Gunnar Hjalmdahl ST-Ericsson");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ST-Ericsson CG2900 Char Devices Driver");
diff --git a/drivers/mfd/cg2900/cg2900_char_devices.h b/drivers/mfd/cg2900/cg2900_char_devices.h
new file mode 100644
index 00000000000..65d2b7f8c35
--- /dev/null
+++ b/drivers/mfd/cg2900/cg2900_char_devices.h
@@ -0,0 +1,36 @@
+/*
+ * drivers/mfd/cg2900/cg2900_char_devices.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth HCI H:4 Driver for ST-Ericsson connectivity controller.
+ */
+
+#ifndef _CG2900_CHAR_DEVICES_H_
+#define _CG2900_CHAR_DEVICES_H_
+
+#include <linux/miscdevice.h>
+
+/**
+ * cg2900_char_devices_init() - Initialize char device module.
+ * @parent: Parent device for the driver.
+ *
+ * Returns:
+ * 0 if success.
+ * Negative value upon error.
+ */
+extern int cg2900_char_devices_init(struct miscdevice *parent);
+
+/**
+ * cg2900_char_devices_exit() - Release the char device module.
+ */
+extern void cg2900_char_devices_exit(void);
+
+#endif /* _CG2900_CHAR_DEVICES_H_ */
diff --git a/drivers/mfd/cg2900/cg2900_chip.c b/drivers/mfd/cg2900/cg2900_chip.c
new file mode 100644
index 00000000000..b39fab57ee9
--- /dev/null
+++ b/drivers/mfd/cg2900/cg2900_chip.c
@@ -0,0 +1,2064 @@
+/*
+ * drivers/mfd/cg2900/cg2900_chip.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth HCI H:4 Driver for ST-Ericsson CG2900 GPS/BT/FM controller.
+ */
+
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include <linux/gfp.h>
+#include <linux/stat.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <asm/byteorder.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/mfd/cg2900.h>
+#include <mach/cg2900_devices.h>
+#include "hci_defines.h"
+#include "cg2900_chip.h"
+#include "cg2900_core.h"
+#include "cg2900_debug.h"
+
+#define LINE_BUFFER_LENGTH 128
+#define FILENAME_MAX 128
+
+#define WQ_NAME "cg2900_chip_wq"
+#define PATCH_INFO_FILE "cg2900_patch_info.fw"
+#define FACTORY_SETTINGS_INFO_FILE "cg2900_settings_info.fw"
+
+/* Size of file chunk ID */
+#define FILE_CHUNK_ID_SIZE 1
+#define FILE_CHUNK_ID_POS 4
+
+/* Times in milliseconds */
+#define POWER_SW_OFF_WAIT 500
+
+/* State setting macros */
+#define SET_BOOT_STATE(__cg2900_new_state) \
+ CG2900_SET_STATE("boot_state", cg2900_info->boot_state, \
+ __cg2900_new_state)
+#define SET_CLOSING_STATE(__cg2900_new_state) \
+ CG2900_SET_STATE("closing_state", cg2900_info->closing_state, \
+ __cg2900_new_state)
+#define SET_FILE_LOAD_STATE(__cg2900_new_state) \
+ CG2900_SET_STATE("file_load_state", cg2900_info->file_load_state, \
+ __cg2900_new_state)
+#define SET_DOWNLOAD_STATE(__cg2900_new_state) \
+ CG2900_SET_STATE("download_state", cg2900_info->download_state, \
+ __cg2900_new_state)
+
+/** CHANNEL_BT_CMD - Bluetooth HCI H:4 channel
+ * for Bluetooth commands in the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_BT_CMD 0x01
+
+/** CHANNEL_BT_ACL - Bluetooth HCI H:4 channel
+ * for Bluetooth ACL data in the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_BT_ACL 0x02
+
+/** CHANNEL_BT_EVT - Bluetooth HCI H:4 channel
+ * for Bluetooth events in the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_BT_EVT 0x04
+
+/** CHANNEL_FM_RADIO - Bluetooth HCI H:4 channel
+ * for FM radio in the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_FM_RADIO 0x08
+
+/** CHANNEL_GNSS - Bluetooth HCI H:4 channel
+ * for GNSS in the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_GNSS 0x09
+
+/** CHANNEL_DEBUG - Bluetooth HCI H:4 channel
+ * for internal debug data in the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_DEBUG 0x0B
+
+/** CHANNEL_STE_TOOLS - Bluetooth HCI H:4 channel
+ * for development tools data in the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_STE_TOOLS 0x0D
+
+/** CHANNEL_HCI_LOGGER - Bluetooth HCI H:4 channel
+ * for logging all transmitted H4 packets (on all channels).
+ */
+#define CHANNEL_HCI_LOGGER 0xFA
+
+/** CHANNEL_US_CTRL - Bluetooth HCI H:4 channel
+ * for user space control of the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_US_CTRL 0xFC
+
+/** CHANNEL_CORE - Bluetooth HCI H:4 channel
+ * for user space control of the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_CORE 0xFD
+
+/**
+ * enum boot_state - BOOT-state for CG2900 chip driver.
+ * @BOOT_NOT_STARTED: Boot has not yet started.
+ * @BOOT_SEND_BD_ADDRESS: VS Store In FS command with BD address
+ * has been sent.
+ * @BOOT_GET_FILES_TO_LOAD: CG2900 chip driver is retrieving file to
+ * load.
+ * @BOOT_DOWNLOAD_PATCH: CG2900 chip driver is downloading
+ * patches.
+ * @BOOT_ACTIVATE_PATCHES_AND_SETTINGS: CG2900 chip driver is activating patches
+ * and settings.
+ * @BOOT_READY: CG2900 chip driver boot is ready.
+ * @BOOT_FAILED: CG2900 chip driver boot failed.
+ */
+enum boot_state {
+ BOOT_NOT_STARTED,
+ BOOT_SEND_BD_ADDRESS,
+ BOOT_GET_FILES_TO_LOAD,
+ BOOT_DOWNLOAD_PATCH,
+ BOOT_ACTIVATE_PATCHES_AND_SETTINGS,
+ BOOT_READY,
+ BOOT_FAILED
+};
+
+/**
+ * enum closing_state - CLOSING-state for CG2900 chip driver.
+ * @CLOSING_RESET: HCI RESET_CMD has been sent.
+ * @CLOSING_POWER_SWITCH_OFF: HCI VS_POWER_SWITCH_OFF command has been sent.
+ * @CLOSING_SHUT_DOWN: We have now shut down the chip.
+ */
+enum closing_state {
+ CLOSING_RESET,
+ CLOSING_POWER_SWITCH_OFF,
+ CLOSING_SHUT_DOWN
+};
+
+/**
+ * enum file_load_state - BOOT_FILE_LOAD-state for CG2900 chip driver.
+ * @FILE_LOAD_GET_PATCH: Loading patches.
+ * @FILE_LOAD_GET_STATIC_SETTINGS: Loading static settings.
+ * @FILE_LOAD_NO_MORE_FILES: No more files to load.
+ * @FILE_LOAD_FAILED: File loading failed.
+ */
+enum file_load_state {
+ FILE_LOAD_GET_PATCH,
+ FILE_LOAD_GET_STATIC_SETTINGS,
+ FILE_LOAD_NO_MORE_FILES,
+ FILE_LOAD_FAILED
+};
+
+/**
+ * enum download_state - BOOT_DOWNLOAD state.
+ * @DOWNLOAD_PENDING: Download in progress.
+ * @DOWNLOAD_SUCCESS: Download successfully finished.
+ * @DOWNLOAD_FAILED: Downloading failed.
+ */
+enum download_state {
+ DOWNLOAD_PENDING,
+ DOWNLOAD_SUCCESS,
+ DOWNLOAD_FAILED
+};
+
+/**
+ * enum fm_radio_mode - FM Radio mode.
+ * It's needed because some FM do-commands generate interrupts only when
+ * the FM driver is in specific mode and we need to know if we should expect
+ * the interrupt.
+ * @FM_RADIO_MODE_IDLE: Radio mode is Idle (default).
+ * @FM_RADIO_MODE_FMT: Radio mode is set to FMT (transmitter).
+ * @FM_RADIO_MODE_FMR: Radio mode is set to FMR (receiver).
+ */
+enum fm_radio_mode {
+ FM_RADIO_MODE_IDLE = 0,
+ FM_RADIO_MODE_FMT = 1,
+ FM_RADIO_MODE_FMR = 2
+};
+
+/**
+ * struct cg2900_device_id - Structure for connecting H4 channel to named user.
+ * @name: Name of device.
+ * @h4_channel: HCI H:4 channel used by this device.
+ */
+struct cg2900_device_id {
+ char *name;
+ int h4_channel;
+};
+
+/**
+ * struct cg2900_skb_data - Structure for storing private data in an sk_buffer.
+ * @dev: CG2900 device for this sk_buffer.
+ */
+struct cg2900_skb_data {
+ struct cg2900_device *dev;
+};
+#define cg2900_skb_data(__skb) ((struct cg2900_skb_data *)((__skb)->cb))
+
+/**
+ * struct cg2900_info - Main info structure for CG2900 chip driver.
+ * @patch_file_name: Stores patch file name.
+ * @settings_file_name: Stores settings file name.
+ * @fw_file: Stores firmware file (patch or settings).
+ * @file_offset: Current read offset in firmware file.
+ * @chunk_id: Stores current chunk ID of write file
+ * operations.
+ * @boot_state: Current BOOT-state of CG2900 chip driver.
+ * @closing_state: Current CLOSING-state of CG2900 chip driver.
+ * @file_load_state: Current BOOT_FILE_LOAD-state of CG2900 chip
+ * driver.
+ * @download_state: Current BOOT_DOWNLOAD-state of CG2900 chip
+ * driver.
+ * @wq: CG2900 chip driver workqueue.
+ * @chip_dev: Chip handler info.
+ * @tx_bt_lock: Spinlock used to protect some global structures
+ * related to internal BT command flow control.
+ * @tx_fm_lock: Spinlock used to protect some global structures
+ * related to internal FM command flow control.
+ * @tx_fm_audio_awaiting_irpt: Indicates if an FM interrupt event related to
+ * audio driver command is expected.
+ * @fm_radio_mode: Current FM radio mode.
+ * @tx_nr_pkts_allowed_bt: Number of packets allowed to send on BT HCI CMD
+ * H4 channel.
+ * @audio_bt_cmd_op: Stores the OpCode of the last sent audio driver
+ * HCI BT CMD.
+ * @audio_fm_cmd_id: Stores the command id of the last sent
+ * HCI FM RADIO command by the fm audio user.
+ * @hci_fm_cmd_func: Stores the command function of the last sent
+ * HCI FM RADIO command by the fm radio user.
+ * @tx_queue_bt: TX queue for HCI BT commands when nr of commands
+ * allowed is 0 (CG2900 internal flow control).
+ * @tx_queue_fm: TX queue for HCI FM commands when nr of commands
+ * allowed is 0 (CG2900 internal flow control).
+ */
+struct cg2900_info {
+ char *patch_file_name;
+ char *settings_file_name;
+ const struct firmware *fw_file;
+ int file_offset;
+ u8 chunk_id;
+ enum boot_state boot_state;
+ enum closing_state closing_state;
+ enum file_load_state file_load_state;
+ enum download_state download_state;
+ struct workqueue_struct *wq;
+ struct cg2900_chip_dev chip_dev;
+ spinlock_t tx_bt_lock;
+ spinlock_t tx_fm_lock;
+ bool tx_fm_audio_awaiting_irpt;
+ enum fm_radio_mode fm_radio_mode;
+ int tx_nr_pkts_allowed_bt;
+ u16 audio_bt_cmd_op;
+ u16 audio_fm_cmd_id;
+ u16 hci_fm_cmd_func;
+ struct sk_buff_head tx_queue_bt;
+ struct sk_buff_head tx_queue_fm;
+};
+
+static struct cg2900_info *cg2900_info;
+
+/*
+ * cg2900_channels() - Array containing available H4 channels for the CG2900
+ * ST-Ericsson Connectivity controller.
+ */
+struct cg2900_device_id cg2900_channels[] = {
+ {CG2900_BT_CMD, CHANNEL_BT_CMD},
+ {CG2900_BT_ACL, CHANNEL_BT_ACL},
+ {CG2900_BT_EVT, CHANNEL_BT_EVT},
+ {CG2900_GNSS, CHANNEL_GNSS},
+ {CG2900_FM_RADIO, CHANNEL_FM_RADIO},
+ {CG2900_DEBUG, CHANNEL_DEBUG},
+ {CG2900_STE_TOOLS, CHANNEL_STE_TOOLS},
+ {CG2900_HCI_LOGGER, CHANNEL_HCI_LOGGER},
+ {CG2900_US_CTRL, CHANNEL_US_CTRL},
+ {CG2900_BT_AUDIO, CHANNEL_BT_CMD},
+ {CG2900_FM_RADIO_AUDIO, CHANNEL_FM_RADIO},
+ {CG2900_CORE, CHANNEL_CORE}
+};
+
+/*
+ * Internal function
+ */
+
+/**
+ * create_and_send_bt_cmd() - Copy and send sk_buffer.
+ * @data: Data to send.
+ * @length: Length in bytes of data.
+ *
+ * The create_and_send_bt_cmd() function allocate sk_buffer, copy supplied data
+ * to it, and send the sk_buffer to controller.
+ */
+static void create_and_send_bt_cmd(void *data, int length)
+{
+ struct sk_buff *skb;
+ struct cg2900_hci_logger_config *logger_config;
+ int err;
+
+ skb = cg2900_alloc_skb(length, GFP_ATOMIC);
+ if (!skb) {
+ CG2900_ERR("Couldn't alloc sk_buff with length %d", length);
+ return;
+ }
+
+ memcpy(skb_put(skb, length), data, length);
+ skb_push(skb, CG2900_SKB_RESERVE);
+ skb->data[0] = CHANNEL_BT_CMD;
+
+ logger_config = cg2900_get_hci_logger_config();
+ if (logger_config)
+ err = cg2900_send_to_chip(skb, logger_config->bt_cmd_enable);
+ else
+ err = cg2900_send_to_chip(skb, false);
+
+ if (err) {
+ CG2900_ERR("Failed to transmit to chip (%d)", err);
+ kfree_skb(skb);
+ }
+}
+
+/**
+ * fm_irpt_expected() - check if this FM command will generate an interrupt.
+ * @cmd_id: command identifier.
+ *
+ * Returns:
+ * true if the command will generate an interrupt.
+ * false if it won't.
+ */
+static bool fm_irpt_expected(u16 cmd_id)
+{
+ bool retval = false;
+
+ switch (cmd_id) {
+ case CG2900_FM_DO_AIP_FADE_START:
+ if (cg2900_info->fm_radio_mode == FM_RADIO_MODE_FMT)
+ retval = true;
+ break;
+
+ case CG2900_FM_DO_AUP_BT_FADE_START:
+ case CG2900_FM_DO_AUP_EXT_FADE_START:
+ case CG2900_FM_DO_AUP_FADE_START:
+ if (cg2900_info->fm_radio_mode == FM_RADIO_MODE_FMR)
+ retval = true;
+ break;
+
+ case CG2900_FM_DO_FMR_SETANTENNA:
+ case CG2900_FM_DO_FMR_SP_AFSWITCH_START:
+ case CG2900_FM_DO_FMR_SP_AFUPDATE_START:
+ case CG2900_FM_DO_FMR_SP_BLOCKSCAN_START:
+ case CG2900_FM_DO_FMR_SP_PRESETPI_START:
+ case CG2900_FM_DO_FMR_SP_SCAN_START:
+ case CG2900_FM_DO_FMR_SP_SEARCH_START:
+ case CG2900_FM_DO_FMR_SP_SEARCHPI_START:
+ case CG2900_FM_DO_FMR_SP_TUNE_SETCHANNEL:
+ case CG2900_FM_DO_FMR_SP_TUNE_STEPCHANNEL:
+ case CG2900_FM_DO_FMT_PA_SETCTRL:
+ case CG2900_FM_DO_FMT_PA_SETMODE:
+ case CG2900_FM_DO_FMT_SP_TUNE_SETCHANNEL:
+ case CG2900_FM_DO_GEN_ANTENNACHECK_START:
+ case CG2900_FM_DO_GEN_GOTOMODE:
+ case CG2900_FM_DO_GEN_POWERSUPPLY_SETMODE:
+ case CG2900_FM_DO_GEN_SELECTREFERENCECLOCK:
+ case CG2900_FM_DO_GEN_SETPROCESSINGCLOCK:
+ case CG2900_FM_DO_GEN_SETREFERENCECLOCKPLL:
+ case CG2900_FM_DO_TST_TX_RAMP_START:
+ retval = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (retval)
+ CG2900_INFO("Following interrupt event expected for this "
+ "Cmd complete evt, cmd_id = 0x%x.", cmd_id);
+
+ return retval;
+}
+
+/**
+ * fm_is_do_cmd_irpt() - Check if irpt_val is one of the FM DO command related interrupts.
+ * @irpt_val: interrupt value.
+ *
+ * Returns:
+ * true if it's do-command related interrupt value.
+ * false if it's not.
+ */
+static bool fm_is_do_cmd_irpt(u16 irpt_val)
+{
+ if ((irpt_val & CG2900_FM_IRPT_OPERATION_SUCCEEDED) ||
+ (irpt_val & CG2900_FM_IRPT_OPERATION_FAILED)) {
+ CG2900_INFO("Irpt evt for FM do-command found, "
+ "irpt_val = 0x%x.", irpt_val);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * create_work_item() - Create work item and add it to the work queue.
+ * @work_func: Work function.
+ *
+ * The create_work_item() function creates work item and add it to
+ * the work queue.
+ */
+static void create_work_item(work_func_t work_func)
+{
+ struct work_struct *new_work;
+ int wq_err;
+
+ new_work = kmalloc(sizeof(*new_work), GFP_ATOMIC);
+ if (!new_work) {
+ CG2900_ERR("Failed to alloc memory for work_struct!");
+ return;
+ }
+
+ INIT_WORK(new_work, work_func);
+
+ wq_err = queue_work(cg2900_info->wq, new_work);
+ if (!wq_err) {
+ CG2900_ERR("Failed to queue work_struct because it's already "
+ "in the queue!");
+ kfree(new_work);
+ }
+}
+
+/**
+ * fm_reset_flow_ctrl - Clears up internal FM flow control.
+ *
+ * Resets outstanding commands and clear FM TX list and set CG2900 FM mode to
+ * idle.
+ */
+static void fm_reset_flow_ctrl(void)
+{
+ CG2900_INFO("fm_reset_flow_ctrl");
+
+ skb_queue_purge(&cg2900_info->tx_queue_fm);
+
+ /* Reset the fm_cmd_id. */
+ cg2900_info->audio_fm_cmd_id = CG2900_FM_CMD_NONE;
+ cg2900_info->hci_fm_cmd_func = CG2900_FM_CMD_PARAM_NONE;
+
+ cg2900_info->fm_radio_mode = FM_RADIO_MODE_IDLE;
+}
+
+
+/**
+ * fm_parse_cmd - Parses a FM command packet.
+ * @data: FM command packet.
+ * @cmd_func: Out: FM legacy command function.
+ * @cmd_id: Out: FM legacy command ID.
+ */
+static void fm_parse_cmd(u8 *data, u8 *cmd_func, u16 *cmd_id)
+{
+ /* Move past H4-header to start of actual package */
+ struct fm_leg_cmd *pkt = (struct fm_leg_cmd *)(data + HCI_H4_SIZE);
+
+ *cmd_func = CG2900_FM_CMD_PARAM_NONE;
+ *cmd_id = CG2900_FM_CMD_NONE;
+
+ if (pkt->opcode != CG2900_FM_GEN_ID_LEGACY) {
+ CG2900_ERR("Not an FM legacy command 0x%X", pkt->opcode);
+ return;
+ }
+
+ *cmd_func = pkt->fm_function;
+ CG2900_DBG("cmd_func 0x%X", *cmd_func);
+ if (*cmd_func == CG2900_FM_CMD_PARAM_WRITECOMMAND) {
+ *cmd_id = cg2900_get_fm_cmd_id(le16_to_cpu(pkt->fm_cmd.head));
+ CG2900_DBG("cmd_id 0x%X", *cmd_id);
+ }
+}
+
+
+/**
+ * fm_parse_event - Parses a FM event packet
+ * @data: FM event packet.
+ * @event: Out: FM event.
+ * @cmd_func: Out: FM legacy command function.
+ * @cmd_id: Out: FM legacy command ID.
+ * @intr_val: Out: FM interrupt value.
+ */
+static void fm_parse_event(u8 *data, u8 *event, u8 *cmd_func, u16 *cmd_id,
+ u16 *intr_val)
+{
+ /* Move past H4-header to start of actual package */
+ union fm_leg_evt_or_irq *pkt =
+ (union fm_leg_evt_or_irq *)(data + HCI_H4_SIZE);
+
+ *cmd_func = CG2900_FM_CMD_PARAM_NONE;
+ *cmd_id = CG2900_FM_CMD_NONE;
+ *intr_val = 0;
+ *event = CG2900_FM_EVENT_UNKNOWN;
+
+ if (pkt->evt.opcode == CG2900_FM_GEN_ID_LEGACY &&
+ pkt->evt.read_write == CG2900_FM_CMD_LEG_PARAM_WRITE) {
+ /* Command complete */
+ *event = CG2900_FM_EVENT_CMD_COMPLETE;
+ *cmd_func = pkt->evt.fm_function;
+ CG2900_DBG("cmd_func 0x%X", *cmd_func);
+ if (*cmd_func == CG2900_FM_CMD_PARAM_WRITECOMMAND) {
+ *cmd_id = cg2900_get_fm_cmd_id(
+ le16_to_cpu(pkt->evt.response_head));
+ CG2900_DBG("cmd_id 0x%X", *cmd_id);
+ }
+ } else if (pkt->irq_v2.opcode == CG2900_FM_GEN_ID_LEGACY &&
+ pkt->irq_v2.event_type == CG2900_FM_CMD_LEG_PARAM_IRQ) {
+ /* Interrupt, PG2 style */
+ *event = CG2900_FM_EVENT_INTERRUPT;
+ *intr_val = le16_to_cpu(pkt->irq_v2.irq);
+ CG2900_DBG("intr_val 0x%X", *intr_val);
+ } else if (pkt->irq_v1.opcode == CG2900_FM_GEN_ID_LEGACY) {
+ /* Interrupt, PG1 style */
+ *event = CG2900_FM_EVENT_INTERRUPT;
+ *intr_val = le16_to_cpu(pkt->irq_v1.irq);
+ CG2900_DBG("intr_val 0x%X", *intr_val);
+ } else {
+ CG2900_ERR("Not an FM legacy command 0x%X %X %X %X ...",
+ data[0], data[1], data[2], data[3]);
+ }
+}
+
+/**
+ * fm_update_mode - Updates the FM mode state machine.
+ * @data: FM command packet.
+ *
+ * Parses a FM command packet and updates the FM mode state machine.
+ */
+static void fm_update_mode(u8 *data)
+{
+ u8 cmd_func;
+ u16 cmd_id;
+
+ fm_parse_cmd(data, &cmd_func, &cmd_id);
+
+ if (cmd_func == CG2900_FM_CMD_PARAM_WRITECOMMAND &&
+ cmd_id == CG2900_FM_DO_GEN_GOTOMODE) {
+ /* Move past H4-header to start of actual package */
+ struct fm_leg_cmd *pkt =
+ (struct fm_leg_cmd *)(data + HCI_H4_SIZE);
+
+ cg2900_info->fm_radio_mode = le16_to_cpu(pkt->fm_cmd.data[0]);
+ CG2900_INFO("FM Radio mode changed to 0x%x",
+ cg2900_info->fm_radio_mode);
+ }
+}
+
+
+/**
+ * transmit_skb_from_tx_queue_bt() - Check flow control info and transmit skb.
+ *
+ * The transmit_skb_from_tx_queue_bt() function checks if there are tickets
+ * available and commands waiting in the TX queue and if so transmits them
+ * to the controller.
+ * It shall always be called within spinlock_bh.
+ */
+static void transmit_skb_from_tx_queue_bt(void)
+{
+ struct cg2900_device *dev;
+ struct sk_buff *skb;
+
+ CG2900_INFO("transmit_skb_from_tx_queue_bt");
+
+ /* Dequeue an skb from the head of the list */
+ skb = skb_dequeue(&cg2900_info->tx_queue_bt);
+ while (skb) {
+ if ((cg2900_info->tx_nr_pkts_allowed_bt) <= 0) {
+ /*
+ * If no more packets allowed just return, we'll get
+ * back here after next Command Complete/Status event.
+ * Put skb back at head of queue.
+ */
+ skb_queue_head(&cg2900_info->tx_queue_bt, skb);
+ return;
+ }
+
+ (cg2900_info->tx_nr_pkts_allowed_bt)--;
+ CG2900_DBG("tx_nr_pkts_allowed_bt = %d",
+ cg2900_info->tx_nr_pkts_allowed_bt);
+
+ dev = cg2900_skb_data(skb)->dev; /* dev is never NULL */
+
+ /*
+ * If it's a command from audio application, store the OpCode,
+ * it'll be used later to decide where to dispatch
+ * the Command Complete event.
+ */
+ if (cg2900_get_bt_audio_dev() == dev) {
+ struct hci_command_hdr *hdr = (struct hci_command_hdr *)
+ (skb->data + HCI_H4_SIZE);
+
+ cg2900_info->audio_bt_cmd_op = le16_to_cpu(hdr->opcode);
+ CG2900_DBG("Sending cmd from audio driver, saving "
+ "OpCode = 0x%X",
+ cg2900_info->audio_bt_cmd_op);
+ }
+
+ cg2900_send_to_chip(skb, dev->logger_enabled);
+
+ /* Dequeue an skb from the head of the list */
+ skb = skb_dequeue(&cg2900_info->tx_queue_bt);
+ }
+}
+
+/**
+ * transmit_skb_from_tx_queue_fm() - Check flow control info and transmit skb.
+ *
+ * The transmit_skb_from_tx_queue_fm() function checks if it possible to
+ * transmit and commands waiting in the TX queue and if so transmits them
+ * to the controller.
+ * It shall always be called within spinlock_bh.
+ */
+static void transmit_skb_from_tx_queue_fm(void)
+{
+ struct cg2900_device *dev;
+ struct sk_buff *skb;
+
+ CG2900_INFO("transmit_skb_from_tx_queue_fm");
+
+ /* Dequeue an skb from the head of the list */
+ skb = skb_dequeue(&cg2900_info->tx_queue_fm);
+ while (skb) {
+ u16 cmd_id;
+ u8 cmd_func;
+ bool do_transmit = false;
+
+ if (cg2900_info->audio_fm_cmd_id != CG2900_FM_CMD_NONE ||
+ cg2900_info->hci_fm_cmd_func != CG2900_FM_CMD_PARAM_NONE) {
+ /*
+ * There are currently outstanding FM commands.
+ * Wait for them to finish. We will get back here later.
+ * Queue back the skb at head of list.
+ */
+ skb_queue_head(&cg2900_info->tx_queue_bt, skb);
+ return;
+ }
+
+ dev = cg2900_skb_data(skb)->dev; /* dev is never NULL */
+
+ fm_parse_cmd(&(skb->data[0]), &cmd_func, &cmd_id);
+
+ /*
+ * Store the FM command function , it'll be used later to decide
+ * where to dispatch the Command Complete event.
+ */
+ if (cg2900_get_fm_audio_dev() == dev) {
+ cg2900_info->audio_fm_cmd_id = cmd_id;
+ CG2900_DBG("audio_fm_cmd_id 0x%X",
+ cg2900_info->audio_fm_cmd_id);
+ do_transmit = true;
+ }
+ if (cg2900_get_fm_radio_dev() == dev) {
+ cg2900_info->hci_fm_cmd_func = cmd_func;
+ fm_update_mode(&(skb->data[0]));
+ CG2900_DBG("hci_fm_cmd_func 0x%X",
+ cg2900_info->hci_fm_cmd_func);
+ do_transmit = true;
+ }
+
+ if (do_transmit) {
+ /*
+ * We have only one ticket on FM. Just return after
+ * sending the skb.
+ */
+ cg2900_send_to_chip(skb, dev->logger_enabled);
+ return;
+ }
+
+ /*
+ * This packet was neither FM or FM audio. That means that
+ * the user that originally sent it has deregistered.
+ * Just throw it away and check the next skb in the queue.
+ */
+ kfree_skb(skb);
+ /* Dequeue an skb from the head of the list */
+ skb = skb_dequeue(&cg2900_info->tx_queue_fm);
+ }
+}
+
+/**
+ * update_flow_ctrl_bt() - Update number of outstanding commands for BT CMD.
+ * @skb: skb with received packet.
+ *
+ * The update_flow_ctrl_bt() checks if incoming data packet is
+ * BT Command Complete/Command Status Event and if so updates number of tickets
+ * and number of outstanding commands. It also calls function to send queued
+ * commands (if the list of queued commands is not empty).
+ */
+static void update_flow_ctrl_bt(const struct sk_buff * const skb)
+{
+ u8 *data = &(skb->data[CG2900_SKB_RESERVE]);
+ u8 event_code = data[0];
+
+ if (HCI_BT_EVT_CMD_COMPLETE == event_code) {
+ /*
+ * If it's HCI Command Complete Event then we might get some
+ * HCI tickets back. Also we can decrease the number outstanding
+ * HCI commands (if it's not NOP command or one of the commands
+ * that generate both Command Status Event and Command Complete
+ * Event).
+ * Check if we have any HCI commands waiting in the TX list and
+ * send them if there are tickets available.
+ */
+ spin_lock_bh(&(cg2900_info->tx_bt_lock));
+ cg2900_info->tx_nr_pkts_allowed_bt =
+ data[HCI_BT_EVT_CMD_COMPL_NR_OF_PKTS_POS];
+ CG2900_DBG("New tx_nr_pkts_allowed_bt = %d",
+ cg2900_info->tx_nr_pkts_allowed_bt);
+
+ if (!skb_queue_empty(&cg2900_info->tx_queue_bt))
+ transmit_skb_from_tx_queue_bt();
+ spin_unlock_bh(&(cg2900_info->tx_bt_lock));
+ } else if (HCI_BT_EVT_CMD_STATUS == event_code) {
+ /*
+ * If it's HCI Command Status Event then we might get some
+ * HCI tickets back. Also we can decrease the number outstanding
+ * HCI commands (if it's not NOP command).
+ * Check if we have any HCI commands waiting in the TX queue and
+ * send them if there are tickets available.
+ */
+ spin_lock_bh(&(cg2900_info->tx_bt_lock));
+ cg2900_info->tx_nr_pkts_allowed_bt =
+ data[HCI_BT_EVT_CMD_STATUS_NR_OF_PKTS_POS];
+ CG2900_DBG("New tx_nr_pkts_allowed_bt = %d",
+ cg2900_info->tx_nr_pkts_allowed_bt);
+
+ if (!skb_queue_empty(&cg2900_info->tx_queue_bt))
+ transmit_skb_from_tx_queue_bt();
+ spin_unlock_bh(&(cg2900_info->tx_bt_lock));
+ }
+}
+
+/**
+ * update_flow_ctrl_fm() - Update packets allowed for FM channel.
+ * @skb: skb with received packet.
+ *
+ * The update_flow_ctrl_fm() checks if incoming data packet is FM packet
+ * indicating that the previous command has been handled and if so update
+ * packets. It also calls function to send queued commands (if the list of
+ * queued commands is not empty).
+ */
+static void update_flow_ctrl_fm(const struct sk_buff * const skb)
+{
+ u8 cmd_func = CG2900_FM_CMD_PARAM_NONE;
+ u16 cmd_id = CG2900_FM_CMD_NONE;
+ u16 irpt_val = 0;
+ u8 event = CG2900_FM_EVENT_UNKNOWN;
+
+ fm_parse_event(&(skb->data[0]), &event, &cmd_func, &cmd_id, &irpt_val);
+
+ if (event == CG2900_FM_EVENT_CMD_COMPLETE) {
+ /* FM legacy command complete event */
+ spin_lock_bh(&(cg2900_info->tx_fm_lock));
+ /*
+ * Check if it's not an write command complete event, because
+ * then it cannot be a DO command.
+ * If it's a write command complete event check that is not a
+ * DO command complete event before setting the outstanding
+ * FM packets to none.
+ */
+ if (cmd_func != CG2900_FM_CMD_PARAM_WRITECOMMAND ||
+ !fm_irpt_expected(cmd_id)) {
+ cg2900_info->hci_fm_cmd_func = CG2900_FM_CMD_PARAM_NONE;
+ cg2900_info->audio_fm_cmd_id = CG2900_FM_CMD_NONE;
+ CG2900_DBG("FM cmd outstanding cmd func 0x%x",
+ cg2900_info->hci_fm_cmd_func);
+ CG2900_DBG("FM cmd Audio outstanding cmd id 0x%x",
+ cg2900_info->audio_fm_cmd_id);
+ transmit_skb_from_tx_queue_fm();
+
+ /*
+ * If there was a write do command complete event check if it is
+ * DO command previously sent by the FM audio user. If that's
+ * the case we need remember that in order to be able to
+ * dispatch the interrupt to the correct user.
+ */
+ } else if (cmd_id == cg2900_info->audio_fm_cmd_id) {
+ cg2900_info->tx_fm_audio_awaiting_irpt = true;
+ CG2900_DBG("FM Audio waiting for interrupt = true.");
+ }
+ spin_unlock_bh(&(cg2900_info->tx_fm_lock));
+ } else if (event == CG2900_FM_EVENT_INTERRUPT) {
+ /* FM legacy interrupt */
+ if (fm_is_do_cmd_irpt(irpt_val)) {
+ /*
+ * If it is an interrupt related to a DO command update
+ * the outstanding flow control and transmit blocked
+ * FM commands.
+ */
+ spin_lock_bh(&(cg2900_info->tx_fm_lock));
+ cg2900_info->hci_fm_cmd_func = CG2900_FM_CMD_PARAM_NONE;
+ cg2900_info->audio_fm_cmd_id = CG2900_FM_CMD_NONE;
+ CG2900_DBG("FM cmd outstanding cmd func 0x%x",
+ cg2900_info->hci_fm_cmd_func);
+ CG2900_DBG("FM cmd Audio outstanding cmd id 0x%x",
+ cg2900_info->audio_fm_cmd_id);
+ cg2900_info->tx_fm_audio_awaiting_irpt = false;
+ CG2900_DBG("FM Audio waiting for interrupt = false.");
+ transmit_skb_from_tx_queue_fm();
+ spin_unlock_bh(&(cg2900_info->tx_fm_lock));
+ }
+ }
+}
+
+/**
+ * send_bd_address() - Send HCI VS command with BD address to the chip.
+ */
+static void send_bd_address(void)
+{
+ struct bt_vs_store_in_fs_cmd *cmd;
+ /*
+ * The '-1' is for the first byte of the data field that's already
+ * there.
+ */
+ u8 plen = sizeof(*cmd) + BT_BDADDR_SIZE - 1;
+
+ cmd = kmalloc(plen, GFP_KERNEL);
+ if (!cmd)
+ return;
+
+ cmd->opcode = cpu_to_le16(CG2900_BT_OP_VS_STORE_IN_FS);
+ cmd->plen = BT_PARAM_LEN(plen);
+ cmd->user_id = CG2900_VS_STORE_IN_FS_USR_ID_BD_ADDR;
+ cmd->len = BT_BDADDR_SIZE;
+ /* Now copy the BD address received from user space control app. */
+ memcpy(&(cmd->data), bd_address, BT_BDADDR_SIZE);
+
+ SET_BOOT_STATE(BOOT_SEND_BD_ADDRESS);
+
+ create_and_send_bt_cmd(cmd, plen);
+
+ kfree(cmd);
+}
+
+/**
+ * get_text_line()- Replacement function for stdio function fgets.
+ * @wr_buffer: Buffer to copy text to.
+ * @max_nbr_of_bytes: Max number of bytes to read, i.e. size of rd_buffer.
+ * @rd_buffer: Data to parse.
+ * @bytes_copied: Number of bytes copied to wr_buffer.
+ *
+ * The get_text_line() function extracts one line of text from input file.
+ *
+ * Returns:
+ * Pointer to next data to read.
+ */
+static char *get_text_line(char *wr_buffer, int max_nbr_of_bytes,
+ char *rd_buffer, int *bytes_copied)
+{
+ char *curr_wr = wr_buffer;
+ char *curr_rd = rd_buffer;
+ char in_byte;
+
+ *bytes_copied = 0;
+
+ do {
+ *curr_wr = *curr_rd;
+ in_byte = *curr_wr;
+ curr_wr++;
+ curr_rd++;
+ (*bytes_copied)++;
+ } while ((*bytes_copied <= max_nbr_of_bytes) && (in_byte != '\0') &&
+ (in_byte != '\n'));
+ *curr_wr = '\0';
+ return curr_rd;
+}
+
+/**
+ * get_file_to_load() - Parse info file and find correct target file.
+ * @fw: Firmware structure containing file data.
+ * @file_name: (out) Pointer to name of requested file.
+ *
+ * Returns:
+ * true, if target file was found,
+ * false, otherwise.
+ */
+static bool get_file_to_load(const struct firmware *fw, char **file_name)
+{
+ char *line_buffer;
+ char *curr_file_buffer;
+ int bytes_left_to_parse = fw->size;
+ int bytes_read = 0;
+ bool file_found = false;
+ u32 hci_rev;
+ u32 lmp_sub;
+
+ curr_file_buffer = (char *)&(fw->data[0]);
+
+ line_buffer = kzalloc(LINE_BUFFER_LENGTH, GFP_ATOMIC);
+ if (!line_buffer) {
+ CG2900_ERR("Failed to allocate line_buffer");
+ return false;
+ }
+
+ while (!file_found) {
+ /* Get one line of text from the file to parse */
+ curr_file_buffer = get_text_line(line_buffer,
+ min(LINE_BUFFER_LENGTH,
+ (int)(fw->size - bytes_read)),
+ curr_file_buffer,
+ &bytes_read);
+
+ bytes_left_to_parse -= bytes_read;
+ if (bytes_left_to_parse <= 0) {
+ /* End of file => Leave while loop */
+ CG2900_ERR("Reached end of file. No file found!");
+ break;
+ }
+
+ /*
+ * Check if the line of text is a comment or not, comments begin
+ * with '#'
+ */
+ if (*line_buffer == '#')
+ continue;
+
+ hci_rev = 0;
+ lmp_sub = 0;
+
+ CG2900_DBG("Found a valid line <%s>", line_buffer);
+
+ /*
+ * Check if we can find the correct HCI revision and
+ * LMP subversion as well as a file name in
+ * the text line.
+ */
+ if (sscanf(line_buffer, "%x%x%s", &hci_rev, &lmp_sub,
+ *file_name) == 3
+ && hci_rev == cg2900_info->chip_dev.chip.hci_revision
+ && lmp_sub == cg2900_info->chip_dev.chip.hci_sub_version) {
+ CG2900_DBG("File found for chip\n"
+ "\tFile name = %s\n"
+ "\tHCI Revision = 0x%X\n"
+ "\tLMP PAL Subversion = 0x%X",
+ *file_name, hci_rev, lmp_sub);
+
+ /*
+ * Name has already been stored above. Nothing more to
+ * do.
+ */
+ file_found = true;
+ } else
+ /* Zero the name buffer so it is clear to next read */
+ memset(*file_name, 0x00, FILENAME_MAX + 1);
+ }
+ kfree(line_buffer);
+
+ return file_found;
+}
+
+/**
+ * read_and_send_file_part() - Transmit a part of the supplied file.
+ *
+ * The read_and_send_file_part() function transmit a part of the supplied file
+ * to the controller.
+ * If nothing more to read, set the correct states.
+ */
+static void read_and_send_file_part(void)
+{
+ int bytes_to_copy;
+ struct sk_buff *skb;
+ struct cg2900_hci_logger_config *logger_config;
+ struct bt_vs_write_file_block_cmd *cmd;
+ int plen;
+
+ /*
+ * Calculate number of bytes to copy;
+ * either max bytes for HCI packet or number of bytes left in file
+ */
+ bytes_to_copy = min((int)HCI_BT_SEND_FILE_MAX_CHUNK_SIZE,
+ (int)(cg2900_info->fw_file->size -
+ cg2900_info->file_offset));
+
+ if (bytes_to_copy <= 0) {
+ /* Nothing more to read in file. */
+ SET_DOWNLOAD_STATE(DOWNLOAD_SUCCESS);
+ cg2900_info->chunk_id = 0;
+ cg2900_info->file_offset = 0;
+ return;
+ }
+
+ /* There is more data to send */
+ logger_config = cg2900_get_hci_logger_config();
+
+ /*
+ * There are bytes to transmit. Allocate a sk_buffer.
+ * When calculating length to alloc the '-1' is because of the first
+ * byte of the data field that is already defined in the struct.
+ */
+ plen = sizeof(*cmd) - 1 + bytes_to_copy;
+ skb = cg2900_alloc_skb(plen, GFP_ATOMIC);
+ if (!skb) {
+ CG2900_ERR("Couldn't allocate sk_buffer");
+ SET_BOOT_STATE(BOOT_FAILED);
+ cg2900_chip_startup_finished(-EIO);
+ return;
+ }
+
+ skb_put(skb, plen);
+
+ cmd = (struct bt_vs_write_file_block_cmd *)skb->data;
+ cmd->opcode = cpu_to_le16(CG2900_BT_OP_VS_WRITE_FILE_BLOCK);
+ cmd->plen = BT_PARAM_LEN(plen);
+ cmd->id = cg2900_info->chunk_id;
+ cg2900_info->chunk_id++;
+
+ /* Copy the data from offset position */
+ memcpy(&(cmd->data),
+ &(cg2900_info->fw_file->data[cg2900_info->file_offset]),
+ bytes_to_copy);
+
+ /* Increase offset with number of bytes copied */
+ cg2900_info->file_offset += bytes_to_copy;
+
+ skb_push(skb, CG2900_SKB_RESERVE);
+ skb->data[0] = CHANNEL_BT_CMD;
+
+ if (logger_config)
+ cg2900_send_to_chip(skb, logger_config->bt_cmd_enable);
+ else
+ cg2900_send_to_chip(skb, false);
+}
+
+/**
+ * send_settings_file() - Transmit settings file.
+ *
+ * The send_settings_file() function transmit settings file.
+ * The file is read in parts to fit in HCI packets. When finished,
+ * close the settings file and send HCI reset to activate settings and patches.
+ */
+static void send_settings_file(void)
+{
+ /* Transmit a file part */
+ read_and_send_file_part();
+
+ if (cg2900_info->download_state != DOWNLOAD_SUCCESS)
+ return;
+
+ /* Settings file finished. Release used resources */
+ CG2900_DBG("Settings file finished, release used resources");
+ if (cg2900_info->fw_file) {
+ release_firmware(cg2900_info->fw_file);
+ cg2900_info->fw_file = NULL;
+ }
+
+ SET_FILE_LOAD_STATE(FILE_LOAD_NO_MORE_FILES);
+
+ /* Create and send HCI VS Store In FS command with bd address. */
+ send_bd_address();
+}
+
+/**
+ * send_patch_file - Transmit patch file.
+ *
+ * The send_patch_file() function transmit patch file.
+ * The file is read in parts to fit in HCI packets. When the complete file is
+ * transmitted, the file is closed.
+ * When finished, continue with settings file.
+ */
+static void send_patch_file(void)
+{
+ int err;
+
+ /*
+ * Transmit a part of the supplied file to the controller.
+ * When nothing more to read, continue to close the patch file.
+ */
+ read_and_send_file_part();
+
+ if (cg2900_info->download_state != DOWNLOAD_SUCCESS)
+ return;
+
+ /* Patch file finished. Release used resources */
+ CG2900_DBG("Patch file finished, release used resources");
+ if (cg2900_info->fw_file) {
+ release_firmware(cg2900_info->fw_file);
+ cg2900_info->fw_file = NULL;
+ }
+ /* Retrieve the settings file */
+ err = request_firmware(&(cg2900_info->fw_file),
+ cg2900_info->settings_file_name,
+ cg2900_info->chip_dev.dev);
+ if (err < 0) {
+ CG2900_ERR("Couldn't get settings file (%d)", err);
+ goto error_handling;
+ }
+ /* Now send the settings file */
+ SET_FILE_LOAD_STATE(FILE_LOAD_GET_STATIC_SETTINGS);
+ SET_DOWNLOAD_STATE(DOWNLOAD_PENDING);
+ send_settings_file();
+ return;
+
+error_handling:
+ SET_BOOT_STATE(BOOT_FAILED);
+ cg2900_chip_startup_finished(err);
+}
+
+/**
+ * work_power_off_chip() - Work item to power off the chip.
+ * @work: Reference to work data.
+ *
+ * The work_power_off_chip() function handles transmission of the HCI command
+ * vs_power_switch_off and then informs the CG2900 Core that this chip driver is
+ * finished and the Core driver can now shut off the chip.
+ */
+static void work_power_off_chip(struct work_struct *work)
+{
+ struct sk_buff *skb;
+ u8 *h4_header;
+ struct cg2900_hci_logger_config *logger_config;
+
+ if (!work) {
+ CG2900_ERR("work == NULL");
+ return;
+ }
+
+ /*
+ * Get the VS Power Switch Off command to use based on connected
+ * connectivity controller
+ */
+ skb = cg2900_devices_get_power_switch_off_cmd(NULL);
+
+ /*
+ * Transmit the received command.
+ * If no command found for the device, just continue
+ */
+ if (!skb) {
+ CG2900_ERR("Could not retrieve PowerSwitchOff command");
+ goto shut_down_chip;
+ }
+
+ logger_config = cg2900_get_hci_logger_config();
+
+ CG2900_DBG("Got power_switch_off command. Add H4 header and transmit");
+
+ /*
+ * Move the data pointer to the H:4 header position and store
+ * the H4 header
+ */
+ h4_header = skb_push(skb, CG2900_SKB_RESERVE);
+ *h4_header = CHANNEL_BT_CMD;
+
+ SET_CLOSING_STATE(CLOSING_POWER_SWITCH_OFF);
+
+ if (logger_config)
+ cg2900_send_to_chip(skb, logger_config->bt_cmd_enable);
+ else
+ cg2900_send_to_chip(skb, false);
+
+ /*
+ * Mandatory to wait 500ms after the power_switch_off command has been
+ * transmitted, in order to make sure that the controller is ready.
+ */
+ schedule_timeout_interruptible(msecs_to_jiffies(POWER_SW_OFF_WAIT));
+
+shut_down_chip:
+ SET_CLOSING_STATE(CLOSING_SHUT_DOWN);
+
+ (void)cg2900_chip_shutdown_finished(0);
+
+ kfree(work);
+}
+
+/**
+ * work_reset_after_error() - Handle reset.
+ * @work: Reference to work data.
+ *
+ * Handle a reset after received Command Complete event.
+ */
+static void work_reset_after_error(struct work_struct *work)
+{
+ if (!work) {
+ CG2900_ERR("work == NULL");
+ return;
+ }
+
+ cg2900_chip_startup_finished(-EIO);
+
+ kfree(work);
+}
+
+/**
+ * work_load_patch_and_settings() - Start loading patches and settings.
+ * @work: Reference to work data.
+ */
+static void work_load_patch_and_settings(struct work_struct *work)
+{
+ int err = 0;
+ bool file_found;
+ const struct firmware *patch_info;
+ const struct firmware *settings_info;
+
+ if (!work) {
+ CG2900_ERR("work == NULL");
+ return;
+ }
+
+ /* Check that we are in the right state */
+ if (cg2900_info->boot_state != BOOT_GET_FILES_TO_LOAD)
+ goto finished;
+
+ /* Open patch info file. */
+ err = request_firmware(&patch_info, PATCH_INFO_FILE,
+ cg2900_info->chip_dev.dev);
+ if (err) {
+ CG2900_ERR("Couldn't get patch info file (%d)", err);
+ goto error_handling;
+ }
+
+ /*
+ * Now we have the patch info file.
+ * See if we can find the right patch file as well
+ */
+ file_found = get_file_to_load(patch_info,
+ &(cg2900_info->patch_file_name));
+
+ /* Now we are finished with the patch info file */
+ release_firmware(patch_info);
+
+ if (!file_found) {
+ CG2900_ERR("Couldn't find patch file! Major error!");
+ goto error_handling;
+ }
+
+ /* Open settings info file. */
+ err = request_firmware(&settings_info,
+ FACTORY_SETTINGS_INFO_FILE,
+ cg2900_info->chip_dev.dev);
+ if (err) {
+ CG2900_ERR("Couldn't get settings info file (%d)", err);
+ goto error_handling;
+ }
+
+ /*
+ * Now we have the settings info file.
+ * See if we can find the right settings file as well.
+ */
+ file_found = get_file_to_load(settings_info,
+ &(cg2900_info->settings_file_name));
+
+ /* Now we are finished with the patch info file */
+ release_firmware(settings_info);
+
+ if (!file_found) {
+ CG2900_ERR("Couldn't find settings file! Major error!");
+ goto error_handling;
+ }
+
+ /* We now all info needed */
+ SET_BOOT_STATE(BOOT_DOWNLOAD_PATCH);
+ SET_DOWNLOAD_STATE(DOWNLOAD_PENDING);
+ SET_FILE_LOAD_STATE(FILE_LOAD_GET_PATCH);
+ cg2900_info->chunk_id = 0;
+ cg2900_info->file_offset = 0;
+ cg2900_info->fw_file = NULL;
+
+ /* OK. Now it is time to download the patches */
+ err = request_firmware(&(cg2900_info->fw_file),
+ cg2900_info->patch_file_name,
+ cg2900_info->chip_dev.dev);
+ if (err < 0) {
+ CG2900_ERR("Couldn't get patch file (%d)", err);
+ goto error_handling;
+ }
+ send_patch_file();
+
+ goto finished;
+
+error_handling:
+ SET_BOOT_STATE(BOOT_FAILED);
+ cg2900_chip_startup_finished(-EIO);
+finished:
+ kfree(work);
+}
+
+/**
+ * work_cont_file_download() - A file block has been written.
+ * @work: Reference to work data.
+ *
+ * Handle a received HCI VS Write File Block Complete event.
+ * Normally this means continue to send files to the controller.
+ */
+static void work_cont_file_download(struct work_struct *work)
+{
+ if (!work) {
+ CG2900_ERR("work == NULL");
+ return;
+ }
+
+ /* Continue to send patches or settings to the controller */
+ if (cg2900_info->file_load_state == FILE_LOAD_GET_PATCH)
+ send_patch_file();
+ else if (cg2900_info->file_load_state == FILE_LOAD_GET_STATIC_SETTINGS)
+ send_settings_file();
+ else
+ CG2900_INFO("No more files to load");
+
+ kfree(work);
+}
+
+/**
+ * handle_reset_cmd_complete() - Handles HCI Reset Command Complete event.
+ * @data: Pointer to received HCI data packet.
+ *
+ * Returns:
+ * true, if packet was handled internally,
+ * false, otherwise.
+ */
+static bool handle_reset_cmd_complete(u8 *data)
+{
+ u8 status = data[0];
+
+ CG2900_INFO("Received Reset complete event with status 0x%X", status);
+
+ if (CLOSING_RESET != cg2900_info->closing_state)
+ return false;
+
+ if (HCI_BT_ERROR_NO_ERROR != status) {
+ /*
+ * Continue in case of error, the chip is going to be shut down
+ * anyway.
+ */
+ CG2900_ERR("Command complete for HciReset received with "
+ "error 0x%X !", status);
+ }
+
+ create_work_item(work_power_off_chip);
+
+ return true;
+}
+
+
+/**
+ * handle_vs_store_in_fs_cmd_complete() - Handles HCI VS StoreInFS Command Complete event.
+ * @data: Pointer to received HCI data packet.
+ *
+ * Returns:
+ * true, if packet was handled internally,
+ * false, otherwise.
+ */
+static bool handle_vs_store_in_fs_cmd_complete(u8 *data)
+{
+ u8 status = data[0];
+
+ CG2900_INFO("Received Store_in_FS complete event with status 0x%X",
+ status);
+
+ if (cg2900_info->boot_state != BOOT_SEND_BD_ADDRESS)
+ return false;
+
+ if (HCI_BT_ERROR_NO_ERROR == status) {
+ struct hci_command_hdr cmd;
+
+ /* Send HCI SystemReset command to activate patches */
+ SET_BOOT_STATE(BOOT_ACTIVATE_PATCHES_AND_SETTINGS);
+
+ cmd.opcode = cpu_to_le16(CG2900_BT_OP_VS_SYSTEM_RESET);
+ cmd.plen = 0; /* No parameters for System Reset */
+ create_and_send_bt_cmd(&cmd, sizeof(cmd));
+ } else {
+ CG2900_ERR("Command complete for StoreInFS received with error "
+ "0x%X", status);
+ SET_BOOT_STATE(BOOT_FAILED);
+ create_work_item(work_reset_after_error);
+ }
+
+ return true;
+}
+
+/**
+ * handle_vs_write_file_block_cmd_complete() - Handles HCI VS WriteFileBlock Command Complete event.
+ * @data: Pointer to received HCI data packet.
+ *
+ * Returns:
+ * true, if packet was handled internally,
+ * false, otherwise.
+ */
+static bool handle_vs_write_file_block_cmd_complete(u8 *data)
+{
+ u8 status = data[0];
+
+ if ((cg2900_info->boot_state != BOOT_DOWNLOAD_PATCH) ||
+ (cg2900_info->download_state != DOWNLOAD_PENDING))
+ return false;
+
+ if (HCI_BT_ERROR_NO_ERROR == status)
+ create_work_item(work_cont_file_download);
+ else {
+ CG2900_ERR("Command complete for WriteFileBlock received with"
+ " error 0x%X", status);
+ SET_DOWNLOAD_STATE(DOWNLOAD_FAILED);
+ SET_BOOT_STATE(BOOT_FAILED);
+ if (cg2900_info->fw_file) {
+ release_firmware(cg2900_info->fw_file);
+ cg2900_info->fw_file = NULL;
+ }
+ create_work_item(work_reset_after_error);
+ }
+
+ return true;
+}
+
+/**
+ * handle_vs_power_switch_off_cmd_complete() - Handles HCI VS PowerSwitchOff Command Complete event.
+ * @data: Pointer to received HCI data packet.
+ *
+ * Returns:
+ * true, if packet was handled internally,
+ * false, otherwise.
+ */
+static bool handle_vs_power_switch_off_cmd_complete(u8 *data)
+{
+ u8 status = data[0];
+
+ if (CLOSING_POWER_SWITCH_OFF != cg2900_info->closing_state)
+ return false;
+
+ /*
+ * We were waiting for this but we don't need to do anything upon
+ * reception except warn for error status
+ */
+ if (HCI_BT_ERROR_NO_ERROR != status)
+ CG2900_ERR("Command Complete for PowerSwitchOff received with "
+ "error 0x%X", status);
+
+ return true;
+}
+
+/**
+ * handle_vs_system_reset_cmd_complete() - Handle HCI VS SystemReset Command Complete event.
+ * @data: Pointer to received HCI data packet.
+ *
+ * Returns:
+ * true, if packet was handled internally,
+ * false, otherwise.
+ */
+static bool handle_vs_system_reset_cmd_complete(u8 *data)
+{
+ u8 status = data[0];
+
+ if (cg2900_info->boot_state != BOOT_ACTIVATE_PATCHES_AND_SETTINGS)
+ return false;
+
+ CG2900_INFO("SYS_CLK_OUT Disabled");
+
+ if (HCI_BT_ERROR_NO_ERROR == status) {
+ /*
+ * The boot sequence is now finished successfully.
+ * Set states and signal to waiting thread.
+ */
+ SET_BOOT_STATE(BOOT_READY);
+ cg2900_chip_startup_finished(0);
+ } else {
+ CG2900_ERR("Received Reset complete event with status 0x%X",
+ status);
+ SET_BOOT_STATE(BOOT_FAILED);
+ cg2900_chip_startup_finished(-EIO);
+ }
+
+ return true;
+}
+
+/**
+ * handle_rx_data_bt_evt() - Check if received data should be handled in CG2900 chip driver.
+ * @skb: Data packet
+ *
+ * The handle_rx_data_bt_evt() function checks if received data should be
+ * handled in CG2900 chip driver. If so handle it correctly.
+ * Received data is always HCI BT Event.
+ *
+ * Returns:
+ * True, if packet was handled internally,
+ * False, otherwise.
+ */
+static bool handle_rx_data_bt_evt(struct sk_buff *skb)
+{
+ bool pkt_handled = false;
+ /* skb cannot be NULL here so it is safe to de-reference */
+ u8 *data = &(skb->data[CG2900_SKB_RESERVE]);
+ struct hci_event_hdr *evt;
+ struct hci_ev_cmd_complete *cmd_complete;
+ u16 op_code;
+
+ evt = (struct hci_event_hdr *)data;
+
+ /* First check the event code. Only handle Command Complete Event */
+ if (HCI_EV_CMD_COMPLETE != evt->evt)
+ return false;
+
+ data += sizeof(*evt);
+ cmd_complete = (struct hci_ev_cmd_complete *)data;
+
+ op_code = le16_to_cpu(cmd_complete->opcode);
+
+ CG2900_DBG_DATA("Received Command Complete: op_code = 0x%04X", op_code);
+ data += sizeof(*cmd_complete); /* Move to first byte after OCF */
+
+ if (op_code == HCI_OP_RESET)
+ pkt_handled = handle_reset_cmd_complete(data);
+ else if (op_code == CG2900_BT_OP_VS_STORE_IN_FS)
+ pkt_handled = handle_vs_store_in_fs_cmd_complete(data);
+ else if (op_code == CG2900_BT_OP_VS_WRITE_FILE_BLOCK)
+ pkt_handled = handle_vs_write_file_block_cmd_complete(data);
+ else if (op_code == CG2900_BT_OP_VS_POWER_SWITCH_OFF)
+ pkt_handled = handle_vs_power_switch_off_cmd_complete(data);
+ else if (op_code == CG2900_BT_OP_VS_SYSTEM_RESET)
+ pkt_handled = handle_vs_system_reset_cmd_complete(data);
+
+ if (pkt_handled)
+ kfree_skb(skb);
+
+ return pkt_handled;
+}
+
+/**
+ * transmit_skb_with_flow_ctrl_bt() - Send the BT skb to the controller if it is allowed or queue it.
+ * @skb: Data packet.
+ * @dev: Pointer to cg2900_device struct.
+ *
+ * The transmit_skb_with_flow_ctrl_bt() function checks if there are
+ * tickets available and if so transmits buffer to controller. Otherwise the skb
+ * and user name is stored in a list for later sending.
+ * If enabled, copy the transmitted data to the HCI logger as well.
+ */
+static void transmit_skb_with_flow_ctrl_bt(struct sk_buff *skb,
+ struct cg2900_device *dev)
+{
+ /*
+ * Because there are more users of some H4 channels (currently audio
+ * application for BT command and FM channel) we need to have an
+ * internal HCI command flow control in CG2900 driver.
+ * So check here how many tickets we have and store skb in a queue if
+ * there are no tickets left. The skb will be sent later when we get
+ * more ticket(s).
+ */
+ spin_lock_bh(&(cg2900_info->tx_bt_lock));
+
+ if ((cg2900_info->tx_nr_pkts_allowed_bt) > 0) {
+ (cg2900_info->tx_nr_pkts_allowed_bt)--;
+ CG2900_DBG("New tx_nr_pkts_allowed_bt = %d",
+ cg2900_info->tx_nr_pkts_allowed_bt);
+
+ /*
+ * If it's command from audio app store the OpCode,
+ * it'll be used later to decide where to dispatch Command
+ * Complete event.
+ */
+ if (cg2900_get_bt_audio_dev() == dev) {
+ struct hci_command_hdr *hdr = (struct hci_command_hdr *)
+ (skb->data + HCI_H4_SIZE);
+
+ cg2900_info->audio_bt_cmd_op = le16_to_cpu(hdr->opcode);
+ CG2900_DBG("Sending cmd from audio driver, saving "
+ "OpCode = 0x%x",
+ cg2900_info->audio_bt_cmd_op);
+ }
+
+ cg2900_send_to_chip(skb, dev->logger_enabled);
+ } else {
+ CG2900_DBG("Not allowed to send cmd to controller, "
+ "storing in TX queue.");
+
+ cg2900_skb_data(skb)->dev = dev;
+ skb_queue_tail(&cg2900_info->tx_queue_bt, skb);
+ }
+ spin_unlock_bh(&(cg2900_info->tx_bt_lock));
+}
+
+/**
+ * transmit_skb_with_flow_ctrl_fm() - Send the FM skb to the controller if it is allowed or queue it.
+ * @skb: Data packet.
+ * @dev: Pointer to cg2900_device struct.
+ *
+ * The transmit_skb_with_flow_ctrl_fm() function checks if chip is available and
+ * if so transmits buffer to controller. Otherwise the skb and user name is
+ * stored in a list for later sending.
+ * Also it updates the FM radio mode if it's FM GOTOMODE command, this is needed
+ * to know how to handle some FM DO commands complete events.
+ * If enabled, copy the transmitted data to the HCI logger as well.
+ */
+static void transmit_skb_with_flow_ctrl_fm(struct sk_buff *skb,
+ struct cg2900_device *dev)
+{
+ u8 cmd_func = CG2900_FM_CMD_PARAM_NONE;
+ u16 cmd_id = CG2900_FM_CMD_NONE;
+
+ fm_parse_cmd(&(skb->data[0]), &cmd_func, &cmd_id);
+
+ /*
+ * If there is an FM IP disable or reset send command and also reset
+ * the flow control and audio user.
+ */
+ if (cmd_func == CG2900_FM_CMD_PARAM_DISABLE ||
+ cmd_func == CG2900_FM_CMD_PARAM_RESET) {
+ spin_lock_bh(&cg2900_info->tx_fm_lock);
+ fm_reset_flow_ctrl();
+ spin_unlock_bh(&cg2900_info->tx_fm_lock);
+ cg2900_send_to_chip(skb, dev->logger_enabled);
+ return;
+ }
+
+ /*
+ * If there is a FM user and no FM audio user command pending just send
+ * FM command. It is up to the user of the FM channel to handle its own
+ * flow control.
+ */
+ spin_lock_bh(&cg2900_info->tx_fm_lock);
+ if (cg2900_get_fm_radio_dev() == dev &&
+ cg2900_info->audio_fm_cmd_id == CG2900_FM_CMD_NONE) {
+ cg2900_info->hci_fm_cmd_func = cmd_func;
+ CG2900_DBG("hci_fm_cmd_func 0x%X",
+ cg2900_info->hci_fm_cmd_func);
+ /* If a GotoMode command update FM mode */
+ fm_update_mode(&(skb->data[0]));
+ cg2900_send_to_chip(skb, dev->logger_enabled);
+ } else if (cg2900_get_fm_audio_dev() == dev &&
+ cg2900_info->hci_fm_cmd_func == CG2900_FM_CMD_PARAM_NONE &&
+ cg2900_info->audio_fm_cmd_id == CG2900_FM_CMD_NONE) {
+ /*
+ * If it's command from fm audio user store the command id.
+ * It'll be used later to decide where to dispatch
+ * command complete event.
+ */
+ cg2900_info->audio_fm_cmd_id = cmd_id;
+ CG2900_DBG("audio_fm_cmd_id 0x%X",
+ cg2900_info->audio_fm_cmd_id);
+ cg2900_send_to_chip(skb, dev->logger_enabled);
+ } else {
+ CG2900_DBG("Not allowed to send cmd to controller, storing in "
+ "TX queue");
+
+ cg2900_skb_data(skb)->dev = dev;
+ skb_queue_tail(&cg2900_info->tx_queue_fm, skb);
+ }
+ spin_unlock_bh(&(cg2900_info->tx_fm_lock));
+}
+
+/**
+ * chip_startup() - Start the chip.
+ * @dev: Chip info.
+ *
+ * The chip_startup() function downloads patches and other needed start
+ * procedures.
+ *
+ * Returns:
+ * 0 if there is no error.
+ */
+static int chip_startup(struct cg2900_chip_dev *dev)
+{
+ /* Start the boot sequence */
+ SET_BOOT_STATE(BOOT_GET_FILES_TO_LOAD);
+ create_work_item(work_load_patch_and_settings);
+
+ return 0;
+}
+
+/**
+ * chip_shutdown() - Shut down the chip.
+ * @dev: Chip info.
+ *
+ * The chip_shutdown() function shuts down the chip by sending PowerSwitchOff
+ * command.
+ *
+ * Returns:
+ * 0 if there is no error.
+ */
+static int chip_shutdown(struct cg2900_chip_dev *dev)
+{
+ struct hci_command_hdr cmd;
+
+ /*
+ * Transmit HCI reset command to ensure the chip is using
+ * the correct transport and to put BT part in reset.
+ */
+ SET_CLOSING_STATE(CLOSING_RESET);
+ cmd.opcode = cpu_to_le16(HCI_OP_RESET);
+ cmd.plen = 0; /* No parameters for HCI reset */
+ create_and_send_bt_cmd(&cmd, sizeof(cmd));
+
+ return 0;
+}
+
+/**
+ * data_to_chip() - Called when data shall be sent to the chip.
+ * @dev: Chip info.
+ * @cg2900_dev: CG2900 user for this packet.
+ * @skb: Packet to transmit.
+ *
+ * The data_to_chip() function updates flow control and itself
+ * transmits packet to controller if packet is BT command or FM radio.
+ *
+ * Returns:
+ * true if packet is handled by this driver.
+ * false otherwise.
+ */
+static bool data_to_chip(struct cg2900_chip_dev *dev,
+ struct cg2900_device *cg2900_dev,
+ struct sk_buff *skb)
+{
+ bool packet_handled = false;
+
+ if (cg2900_dev->h4_channel == CHANNEL_BT_CMD) {
+ transmit_skb_with_flow_ctrl_bt(skb, cg2900_dev);
+ packet_handled = true;
+ } else if (cg2900_dev->h4_channel == CHANNEL_FM_RADIO) {
+ transmit_skb_with_flow_ctrl_fm(skb, cg2900_dev);
+ packet_handled = true;
+ }
+
+ return packet_handled;
+}
+
+/**
+ * data_from_chip() - Called when data shall be sent to the chip.
+ * @dev: Chip info.
+ * @cg2900_dev: CG2900 user for this packet.
+ * @skb: Packet received.
+ *
+ * The data_from_chip() function updates flow control and checks
+ * if packet is a response for a packet it itself has transmitted.
+ *
+ * Returns:
+ * true if packet is handled by this driver.
+ * false otherwise.
+ */
+static bool data_from_chip(struct cg2900_chip_dev *dev,
+ struct cg2900_device *cg2900_dev,
+ struct sk_buff *skb)
+{
+ bool packet_handled;
+ int h4_channel;
+
+ h4_channel = skb->data[0];
+
+ /* First check if we should update flow control */
+ if (h4_channel == CHANNEL_BT_EVT)
+ update_flow_ctrl_bt(skb);
+ else if (h4_channel == CHANNEL_FM_RADIO)
+ update_flow_ctrl_fm(skb);
+
+ /* Then check if this is a response to data we have sent */
+ packet_handled = handle_rx_data_bt_evt(skb);
+
+ return packet_handled;
+}
+
+/**
+ * get_h4_channel() - Returns H:4 channel for the name.
+ * @name: Chip info.
+ * @h4_channel: CG2900 user for this packet.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ENXIO if channel is not found.
+ */
+static int get_h4_channel(char *name, int *h4_channel)
+{
+ int i;
+ int err = -ENXIO;
+
+ *h4_channel = -1;
+
+ for (i = 0; *h4_channel == -1 && i < ARRAY_SIZE(cg2900_channels); i++) {
+ if (0 == strncmp(name, cg2900_channels[i].name,
+ CG2900_MAX_NAME_SIZE)) {
+ /* Device found. Return H4 channel */
+ *h4_channel = cg2900_channels[i].h4_channel;
+ err = 0;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * is_bt_audio_user() - Checks if this packet is for the BT audio user.
+ * @h4_channel: H:4 channel for this packet.
+ * @skb: Packet to check.
+ *
+ * Returns:
+ * true if packet is for BT audio user.
+ * false otherwise.
+ */
+static bool is_bt_audio_user(int h4_channel, const struct sk_buff * const skb)
+{
+ struct hci_event_hdr *hdr = (struct hci_event_hdr *)
+ &(skb->data[CG2900_SKB_RESERVE]);
+ u8 *payload = (u8 *)(hdr + 1); /* follows header */
+ u16 opcode = 0;
+
+ if (h4_channel != CHANNEL_BT_EVT)
+ return false;
+
+ if (HCI_BT_EVT_CMD_COMPLETE == hdr->evt)
+ opcode = le16_to_cpu(
+ ((struct hci_ev_cmd_complete *)payload)->opcode);
+ else if (HCI_BT_EVT_CMD_STATUS == hdr->evt)
+ opcode = le16_to_cpu(
+ ((struct hci_ev_cmd_status *)payload)->opcode);
+
+ if (opcode != 0 && opcode == cg2900_info->audio_bt_cmd_op) {
+ CG2900_DBG("BT OpCode match = 0x%04X", opcode);
+ cg2900_info->audio_bt_cmd_op = CG2900_BT_OPCODE_NONE;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * is_fm_audio_user() - Checks if this packet is for the FM audio user.
+ * @h4_channel: H:4 channel for this packet.
+ * @skb: Packet to check.
+ *
+ * Returns:
+ * true if packet is for BT audio user.
+ * false otherwise.
+ */
+static bool is_fm_audio_user(int h4_channel, const struct sk_buff * const skb)
+{
+ u8 cmd_func = CG2900_FM_CMD_PARAM_NONE;
+ u16 cmd_id = CG2900_FM_CMD_NONE;
+ u16 irpt_val = 0;
+ u8 event = CG2900_FM_EVENT_UNKNOWN;
+ bool bt_audio = false;
+
+ fm_parse_event(&(skb->data[0]), &event, &cmd_func, &cmd_id, &irpt_val);
+
+ if (h4_channel == CHANNEL_FM_RADIO) {
+ /* Check if command complete event FM legacy interface. */
+ if ((event == CG2900_FM_EVENT_CMD_COMPLETE) &&
+ (cmd_func == CG2900_FM_CMD_PARAM_WRITECOMMAND) &&
+ (cmd_id == cg2900_info->audio_fm_cmd_id)) {
+ CG2900_DBG("FM Audio Function Code match = 0x%04X",
+ cmd_id);
+ bt_audio = true;
+ goto finished;
+ }
+
+ /* Check if Interrupt legacy interface. */
+ if ((event == CG2900_FM_EVENT_INTERRUPT) &&
+ (fm_is_do_cmd_irpt(irpt_val)) &&
+ (cg2900_info->tx_fm_audio_awaiting_irpt))
+ bt_audio = true;
+ }
+
+finished:
+ return bt_audio;
+}
+
+/**
+ * last_bt_user_removed() - Called when last BT user is removed.
+ * @dev: Chip handler info.
+ *
+ * Clears out TX queue for BT.
+ */
+static void last_bt_user_removed(struct cg2900_chip_dev *dev)
+{
+ spin_lock_bh(&cg2900_info->tx_bt_lock);
+
+ skb_queue_purge(&cg2900_info->tx_queue_bt);
+
+ /*
+ * Reset number of packets allowed and number of outstanding
+ * BT commands.
+ */
+ cg2900_info->tx_nr_pkts_allowed_bt = 1;
+ /* Reset the audio_bt_cmd_op. */
+ cg2900_info->audio_bt_cmd_op = CG2900_BT_OPCODE_NONE;
+ spin_unlock_bh(&cg2900_info->tx_bt_lock);
+}
+
+/**
+ * last_fm_user_removed() - Called when last FM user is removed.
+ * @dev: Chip handler info.
+ *
+ * Clears out TX queue for BT.
+ */
+static void last_fm_user_removed(struct cg2900_chip_dev *dev)
+{
+ spin_lock_bh(&cg2900_info->tx_fm_lock);
+ fm_reset_flow_ctrl();
+ spin_unlock_bh(&cg2900_info->tx_fm_lock);
+}
+
+/**
+ * check_chip_support() - Checks if connected chip is handled by this driver.
+ * @dev: Chip info structure.
+ *
+ * If supported return true and fill in @callbacks.
+ *
+ * Returns:
+ * true if chip is handled by this driver.
+ * false otherwise.
+ */
+static bool check_chip_support(struct cg2900_chip_dev *dev)
+{
+ CG2900_INFO("CG2900: check_chip_support");
+
+ /*
+ * Check if this is a CG2900 revision.
+ * We do not care about the sub-version at the moment. Change this if
+ * necessary.
+ */
+ if ((dev->chip.manufacturer != CG2900_SUPP_MANUFACTURER) ||
+ (dev->chip.hci_revision != CG2900_PG1_SPECIAL_REV &&
+ (dev->chip.hci_revision < CG2900_SUPP_REVISION_MIN ||
+ dev->chip.hci_revision > CG2900_SUPP_REVISION_MAX))) {
+ CG2900_DBG("Chip not supported by CG2900 driver\n"
+ "\tMan: 0x%02X\n\tRev: 0x%04X\n\tSub: 0x%04X",
+ dev->chip.manufacturer, dev->chip.hci_revision,
+ dev->chip.hci_sub_version);
+ return false;
+ }
+
+ CG2900_INFO("Chip supported by the CG2900 driver");
+ /* Store needed data */
+ dev->user_data = cg2900_info;
+ memcpy(&(cg2900_info->chip_dev), dev, sizeof(*dev));
+ /* Set the callbacks */
+ dev->cb.chip_shutdown = chip_shutdown;
+ dev->cb.chip_startup = chip_startup;
+ dev->cb.data_from_chip = data_from_chip;
+ dev->cb.data_to_chip = data_to_chip;
+ dev->cb.get_h4_channel = get_h4_channel;
+ dev->cb.is_bt_audio_user = is_bt_audio_user;
+ dev->cb.is_fm_audio_user = is_fm_audio_user;
+ dev->cb.last_bt_user_removed = last_bt_user_removed;
+ dev->cb.last_fm_user_removed = last_fm_user_removed;
+
+ return true;
+}
+
+static struct cg2900_id_callbacks chip_support_callbacks = {
+ .check_chip_support = check_chip_support
+};
+
+/**
+ * cg2900_init() - Initialize module.
+ *
+ * The cg2900_init() function initializes the CG2900 driver,
+ * then registers to the CG2900 Core.
+ *
+ * Returns:
+ * 0 if success.
+ * -ENOMEM for failed alloc or structure creation.
+ * Error codes generated by cg2900_register_chip_driver.
+ */
+static int __init cg2900_init(void)
+{
+ int err = 0;
+
+ CG2900_INFO("cg2900_init");
+
+ cg2900_info = kzalloc(sizeof(*cg2900_info), GFP_ATOMIC);
+ if (!cg2900_info) {
+ CG2900_ERR("Couldn't allocate cg2900_info");
+ err = -ENOMEM;
+ goto finished;
+ }
+
+ /*
+ * Initialize linked lists for HCI BT and FM commands
+ * that can't be sent due to internal CG2900 flow control.
+ */
+ skb_queue_head_init(&cg2900_info->tx_queue_bt);
+ skb_queue_head_init(&cg2900_info->tx_queue_fm);
+
+ /* Initialize the spin locks */
+ spin_lock_init(&(cg2900_info->tx_bt_lock));
+ spin_lock_init(&(cg2900_info->tx_fm_lock));
+
+ cg2900_info->tx_nr_pkts_allowed_bt = 1;
+ cg2900_info->audio_bt_cmd_op = CG2900_BT_OPCODE_NONE;
+ cg2900_info->audio_fm_cmd_id = CG2900_FM_CMD_NONE;
+ cg2900_info->hci_fm_cmd_func = CG2900_FM_CMD_PARAM_NONE;
+ cg2900_info->fm_radio_mode = FM_RADIO_MODE_IDLE;
+
+ cg2900_info->wq = create_singlethread_workqueue(WQ_NAME);
+ if (!cg2900_info->wq) {
+ CG2900_ERR("Could not create workqueue");
+ err = -ENOMEM;
+ goto err_handling_free_info;
+ }
+
+ /* Allocate file names that will be used, deallocated in cg2900_exit */
+ cg2900_info->patch_file_name = kzalloc(FILENAME_MAX + 1, GFP_ATOMIC);
+ if (!cg2900_info->patch_file_name) {
+ CG2900_ERR("Couldn't allocate name buffer for patch file.");
+ err = -ENOMEM;
+ goto err_handling_destroy_wq;
+ }
+ /* Allocate file names that will be used, deallocated in cg2900_exit */
+ cg2900_info->settings_file_name = kzalloc(FILENAME_MAX + 1, GFP_ATOMIC);
+ if (!cg2900_info->settings_file_name) {
+ CG2900_ERR("Couldn't allocate name buffers settings file.");
+ err = -ENOMEM;
+ goto err_handling_free_patch_name;
+ }
+
+ err = cg2900_register_chip_driver(&chip_support_callbacks);
+ if (err) {
+ CG2900_ERR("Couldn't register chip driver (%d)", err);
+ goto err_handling_free_settings_name;
+ }
+
+ goto finished;
+
+err_handling_free_settings_name:
+ kfree(cg2900_info->settings_file_name);
+err_handling_free_patch_name:
+ kfree(cg2900_info->patch_file_name);
+err_handling_destroy_wq:
+ destroy_workqueue(cg2900_info->wq);
+err_handling_free_info:
+ kfree(cg2900_info);
+ cg2900_info = NULL;
+finished:
+ return err;
+}
+
+/**
+ * cg2900_exit() - Remove module.
+ */
+static void __exit cg2900_exit(void)
+{
+ CG2900_INFO("cg2900_exit");
+
+ if (!cg2900_info)
+ return;
+
+ kfree(cg2900_info->settings_file_name);
+ kfree(cg2900_info->patch_file_name);
+ destroy_workqueue(cg2900_info->wq);
+ kfree(cg2900_info);
+ cg2900_info = NULL;
+}
+
+module_init(cg2900_init);
+module_exit(cg2900_exit);
+
+MODULE_AUTHOR("Par-Gunnar Hjalmdahl ST-Ericsson");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Linux CG2900 Connectivity Device Driver");
diff --git a/drivers/mfd/cg2900/cg2900_chip.h b/drivers/mfd/cg2900/cg2900_chip.h
new file mode 100644
index 00000000000..d30c5da5d47
--- /dev/null
+++ b/drivers/mfd/cg2900/cg2900_chip.h
@@ -0,0 +1,576 @@
+/*
+ * drivers/mfd/cg2900/cg2900_chip.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth HCI H:4 Driver for ST-Ericsson CG2900 GPS/BT/FM controller.
+ */
+
+#ifndef _CG2900_CHIP_H_
+#define _CG2900_CHIP_H_
+
+#include "hci_defines.h"
+
+/*
+ * Utility
+ */
+
+static inline void set_low_nibble(__u8 *var, __u8 value)
+{
+ *var = (*var & 0xf0) | (value & 0x0f);
+}
+
+static inline void set_high_nibble(__u8 *var, __u8 value)
+{
+ *var = (*var & 0x0f) | (value << 4);
+}
+
+static inline void store_bit(__u8 *var, size_t bit, __u8 value)
+{
+ *var = (*var & ~(1u << bit)) | (value << bit);
+}
+
+/*
+ * General chip defines
+ */
+
+/* Supported chips */
+#define CG2900_SUPP_MANUFACTURER 0x30
+#define CG2900_SUPP_REVISION_MIN 0x0100
+#define CG2900_SUPP_REVISION_MAX 0x0200
+
+/* Specific chip version data */
+#define CG2900_PG1_REV 0x0101
+#define CG2900_PG2_REV 0x0200
+#define CG2900_PG1_SPECIAL_REV 0x0700
+
+/*
+ * Bluetooth
+ */
+
+#define BT_SIZE_OF_HDR (sizeof(__le16) + sizeof(__u8))
+#define BT_PARAM_LEN(__pkt_len) (__pkt_len - BT_SIZE_OF_HDR)
+
+struct bt_cmd_cmpl_event {
+ __u8 eventcode;
+ __u8 plen;
+ __u8 n_commands;
+ __le16 opcode;
+ /*
+ * According to BT-specification what follows is "parameters"
+ * and unique to every command, but all commands start the
+ * parameters with the status field so include it here for
+ * convenience
+ */
+ __u8 status;
+ __u8 data[];
+} __attribute__((packed));
+
+/* BT VS Store In FS command */
+#define CG2900_BT_OP_VS_STORE_IN_FS 0xFC22
+struct bt_vs_store_in_fs_cmd {
+ __le16 opcode;
+ __u8 plen;
+ __u8 user_id;
+ __u8 len;
+ __u8 data; /* Really a data array of variable size */
+} __attribute__((packed));
+
+#define CG2900_VS_STORE_IN_FS_USR_ID_BD_ADDR 0xFE
+
+/* BT VS Write File Block command */
+#define CG2900_BT_OP_VS_WRITE_FILE_BLOCK 0xFC2E
+struct bt_vs_write_file_block_cmd {
+ __le16 opcode;
+ __u8 plen;
+ __u8 id;
+ __u8 data; /* Really a data array of variable size */
+} __attribute__((packed));
+
+/* Bluetooth Vendor Specific Opcodes */
+#define CG2900_BT_OP_VS_POWER_SWITCH_OFF 0xFD40
+#define CG2900_BT_OP_VS_SYSTEM_RESET 0xFF12
+
+#define CG2900_BT_OPCODE_NONE 0xFFFF
+
+/*
+ * Common multimedia
+ */
+
+#define CG2900_CODEC_TYPE_NONE 0x00
+#define CG2900_CODEC_TYPE_SBC 0x01
+
+#define CG2900_PCM_MODE_SLAVE 0x00
+#define CG2900_PCM_MODE_MASTER 0x01
+
+#define CG2900_I2S_MODE_MASTER 0x00
+#define CG2900_I2S_MODE_SLAVE 0x01
+
+/*
+ * CG2900 PG1 multimedia API
+ */
+
+#define CG2900_BT_VP_TYPE_PCM 0x00
+#define CG2900_BT_VP_TYPE_I2S 0x01
+#define CG2900_BT_VP_TYPE_SLIMBUS 0x02
+#define CG2900_BT_VP_TYPE_FM 0x03
+#define CG2900_BT_VP_TYPE_BT_SCO 0x04
+#define CG2900_BT_VP_TYPE_BT_A2DP 0x05
+#define CG2900_BT_VP_TYPE_ANALOG 0x07
+
+#define CG2900_BT_VS_SET_HARDWARE_CONFIG 0xFD54
+/* These don't have the same length, so a union won't work */
+struct bt_vs_set_hw_cfg_cmd_pcm {
+ __le16 opcode;
+ __u8 plen;
+ __u8 vp_type;
+ __u8 port_id;
+ __u8 mode_dir; /* NB: mode is in bit 1 (not 0) */
+ __u8 bit_clock;
+ __le16 frame_len;
+} __attribute__((packed));
+#define HWCONFIG_PCM_SET_MODE(pcfg, mode) \
+ set_low_nibble(&(pcfg)->mode_dir, (mode) << 1)
+#define HWCONFIG_PCM_SET_DIR(pcfg, idx, dir) \
+ store_bit(&(pcfg)->mode_dir, (idx) + 4, (dir))
+
+struct bt_vs_set_hw_cfg_cmd_i2s {
+ __le16 opcode;
+ __u8 plen;
+ __u8 vp_type;
+ __u8 port_id;
+ __u8 half_period;
+ __u8 master_slave;
+} __attribute__((packed));
+
+/* Max length for allocating */
+#define CG2900_BT_LEN_VS_SET_HARDWARE_CONFIG \
+ (sizeof(struct bt_vs_set_hw_cfg_cmd_pcm))
+
+#define CG2900_BT_VS_SET_SESSION_CONFIG 0xFD55
+struct session_config_vport {
+ __u8 type;
+ union {
+ struct {
+ __le16 acl_handle;
+ __u8 reserved[10];
+ } sco;
+ struct {
+ __u8 reserved[12];
+ } fm;
+ struct {
+ __u8 index;
+ __u8 slots_used;
+ __u8 slot_start[4];
+ __u8 reserved[6];
+ } pcm;
+ struct {
+ __u8 index;
+ __u8 channel;
+ __u8 reserved[10];
+ } i2s;
+ };
+} __attribute__((packed));
+#define SESSIONCFG_PCM_SET_USED(port, idx, use) \
+ store_bit(&(port).pcm.slots_used, (idx), (use))
+
+struct session_config_stream {
+ __u8 media_type;
+ __u8 csel_srate;
+ __u8 codec_type;
+ __u8 codec_mode;
+ __u8 codec_params[3];
+ struct session_config_vport inport;
+ struct session_config_vport outport;
+} __attribute__((packed));
+#define SESSIONCFG_SET_CHANNELS(pcfg, chnl) \
+ set_low_nibble(&(pcfg)->csel_srate, (chnl))
+#define SESSIONCFG_I2S_SET_SRATE(pcfg, rate) \
+ set_high_nibble(&(pcfg)->csel_srate, (rate))
+
+struct bt_vs_session_config_cmd {
+ __le16 opcode;
+ __u8 plen;
+ __u8 n_streams; /* we only support one here */
+ struct session_config_stream stream;
+} __attribute__((packed));
+
+#define CG2900_BT_SESSION_MEDIA_TYPE_AUDIO 0x00
+
+#define CG2900_BT_SESSION_RATE_8K 0x01
+#define CG2900_BT_SESSION_RATE_16K 0x02
+#define CG2900_BT_SESSION_RATE_44_1K 0x04
+#define CG2900_BT_SESSION_RATE_48K 0x05
+
+#define CG2900_BT_MEDIA_CONFIG_MONO 0x00
+#define CG2900_BT_MEDIA_CONFIG_STEREO 0x01
+#define CG2900_BT_MEDIA_CONFIG_JOINT_STEREO 0x02
+#define CG2900_BT_MEDIA_CONFIG_DUAL_CHANNEL 0x03
+
+#define CG2900_BT_SESSION_I2S_INDEX_I2S 0x00
+#define CG2900_BT_SESSION_PCM_INDEX_PCM_I2S 0x00
+
+
+#define CG2900_BT_VS_SESSION_CTRL 0xFD57
+struct bt_vs_session_ctrl_cmd {
+ __le16 opcode;
+ __u8 plen;
+ __u8 id;
+ __u8 control;
+} __attribute__((packed));
+
+#define CG2900_BT_SESSION_START 0x00
+#define CG2900_BT_SESSION_STOP 0x01
+#define CG2900_BT_SESSION_PAUSE 0x02
+#define CG2900_BT_SESSION_RESUME 0x03
+
+#define CG2900_BT_VS_RESET_SESSION_CONFIG 0xFD56
+struct bt_vs_reset_session_cfg_cmd {
+ __le16 opcode;
+ __u8 plen;
+ __u8 id;
+} __attribute__((packed));
+
+/*
+ * CG2900 PG2 multimedia API
+ */
+
+#define CG2900_MC_PORT_PCM_I2S 0x00
+#define CG2900_MC_PORT_I2S 0x01
+#define CG2900_MC_PORT_BT_SCO 0x04
+#define CG2900_MC_PORT_FM_RX_0 0x07
+#define CG2900_MC_PORT_FM_TX 0x09
+
+#define CG2900_MC_VS_PORT_CONFIG 0xFD64
+struct mc_vs_port_cfg_cmd {
+ __le16 opcode;
+ __u8 plen;
+ __u8 type;
+ /*
+ * one of the following configuration structs should follow, but they
+ * have different lengths so a union will not work
+ */
+} __attribute__((packed));
+
+struct mc_vs_port_cfg_pcm_i2s {
+ __u8 role_dir;
+ __u8 sco_a2dp_slots_used;
+ __u8 fm_slots_used;
+ __u8 ring_slots_used;
+ __u8 slot_start[4];
+ __u8 ratio_mode;
+ __u8 frame_len;
+ __u8 bitclk_srate;
+} __attribute__((packed));
+#define PORTCFG_PCM_SET_ROLE(cfg, role) \
+ set_low_nibble(&(cfg).role_dir, (role))
+#define PORTCFG_PCM_SET_DIR(cfg, idx, dir) \
+ store_bit(&(cfg).role_dir, (idx) + 4, (dir))
+static inline void portcfg_pcm_set_sco_used(struct mc_vs_port_cfg_pcm_i2s *cfg,
+ size_t index, __u8 use)
+{
+ if (use) {
+ /* clear corresponding slot in all cases */
+ cfg->sco_a2dp_slots_used &= ~(0x11 << index);
+ cfg->fm_slots_used &= ~(0x11 << index);
+ cfg->ring_slots_used &= ~(0x11 << index);
+ /* set for sco */
+ cfg->sco_a2dp_slots_used |= (1u << index);
+ } else {
+ /* only clear for sco */
+ cfg->sco_a2dp_slots_used &= ~(1u << index);
+ }
+}
+#define PORTCFG_PCM_SET_SCO_USED(cfg, idx, use) \
+ portcfg_pcm_set_sco_used(&cfg, idx, use)
+#define PORTCFG_PCM_SET_RATIO(cfg, r) \
+ set_low_nibble(&(cfg).ratio_mode, (r))
+#define PORTCFG_PCM_SET_MODE(cfg, mode) \
+ set_high_nibble(&(cfg).ratio_mode, (mode))
+#define PORTCFG_PCM_SET_BITCLK(cfg, clk) \
+ set_low_nibble(&(cfg).bitclk_srate, (clk))
+#define PORTCFG_PCM_SET_SRATE(cfg, rate) \
+ set_high_nibble(&(cfg).bitclk_srate, (rate))
+
+#define CG2900_MC_PCM_SAMPLE_RATE_8 1
+#define CG2900_MC_PCM_SAMPLE_RATE_16 2
+#define CG2900_MC_PCM_SAMPLE_RATE_44_1 4
+#define CG2900_MC_PCM_SAMPLE_RATE_48 6
+
+struct mc_vs_port_cfg_i2s {
+ __u8 role_hper;
+ __u8 csel_srate;
+ __u8 wordlen;
+};
+#define PORTCFG_I2S_SET_ROLE(cfg, role) \
+ set_low_nibble(&(cfg).role_hper, (role))
+#define PORTCFG_I2S_SET_HALFPERIOD(cfg, hper) \
+ set_high_nibble(&(cfg).role_hper, (hper))
+#define PORTCFG_I2S_SET_CHANNELS(cfg, chnl) \
+ set_low_nibble(&(cfg).csel_srate, (chnl))
+#define PORTCFG_I2S_SET_SRATE(cfg, rate) \
+ set_high_nibble(&(cfg).csel_srate, (rate))
+#define PORTCFG_I2S_SET_WORDLEN(cfg, len) \
+ set_low_nibble(&(cfg).wordlen, len)
+
+#define CG2900_MC_I2S_RIGHT_CHANNEL 1
+#define CG2900_MC_I2S_LEFT_CHANNEL 2
+#define CG2900_MC_I2S_BOTH_CHANNELS 3
+
+#define CG2900_MC_I2S_SAMPLE_RATE_8 0
+#define CG2900_MC_I2S_SAMPLE_RATE_16 1
+#define CG2900_MC_I2S_SAMPLE_RATE_44_1 2
+#define CG2900_MC_I2S_SAMPLE_RATE_48 4
+
+#define CG2900_MC_I2S_WORD_16 1
+#define CG2900_MC_I2S_WORD_32 3
+
+struct mc_vs_port_cfg_fm {
+ __u8 srate; /* NB: value goes in _upper_ nibble! */
+};
+#define PORTCFG_FM_SET_SRATE(cfg, rate) \
+ set_high_nibble(&(cfg).srate, (rate))
+
+struct mc_vs_port_cfg_sco {
+ __le16 acl_id;
+ __u8 wbs_codec;
+ __u8 sbc_params[3]; /* replace when we actually enable WBS... */
+} __attribute__((packed));
+#define PORTCFG_SCO_SET_WBS(cfg, wbs) \
+ set_low_nibble(&(cfg).wbs_codec, (wbs))
+#define PORTCFG_SCO_SET_CODEC(cfg, codec) \
+ set_high_nibble(&(cfg).wbs_codec, (codec))
+
+#define CG2900_MC_VS_CREATE_STREAM 0xFD66
+struct mc_vs_create_stream_cmd {
+ __le16 opcode;
+ __u8 plen;
+ __u8 id;
+ __u8 inport;
+ __u8 outport;
+ __u8 order; /* NB: not used by chip */
+} __attribute__((packed));
+
+#define CG2900_MC_VS_DELETE_STREAM 0xFD67
+struct mc_vs_delete_stream_cmd {
+ __le16 opcode;
+ __u8 plen;
+ __u8 stream;
+} __attribute__((packed));
+
+#define CG2900_MC_VS_STREAM_CONTROL 0xFD68
+struct mc_vs_stream_ctrl_cmd {
+ __le16 opcode;
+ __u8 plen;
+ __u8 command;
+ __u8 n_streams;
+ __u8 stream[];
+} __attribute__((packed));
+
+#define CG2900_MC_STREAM_START 0x00
+#define CG2900_MC_STREAM_STOP 0x01
+#define CG2900_MC_STREAM_STOP_FLUSH 0x02
+
+#define CG2900_MC_VS_SET_FM_START_MODE 0xFD69
+
+/*
+ * FM
+ */
+
+/* FM legacy command packet */
+struct fm_leg_cmd {
+ __u8 length;
+ __u8 opcode;
+ __u8 read_write;
+ __u8 fm_function;
+ union { /* Payload varies with function */
+ __le16 irqmask;
+ struct fm_leg_fm_cmd {
+ __le16 head;
+ __le16 data[];
+ } fm_cmd;
+ };
+} __attribute__((packed));
+
+/* FM legacy command complete packet */
+struct fm_leg_cmd_cmpl {
+ __u8 param_length;
+ __u8 status;
+ __u8 opcode;
+ __u8 read_write;
+ __u8 cmd_status;
+ __u8 fm_function;
+ __le16 response_head;
+ __le16 data[];
+} __attribute__((packed));
+
+/* FM legacy interrupt packet, PG2 style */
+struct fm_leg_irq_v2 {
+ __u8 param_length;
+ __u8 status;
+ __u8 opcode;
+ __u8 event_type;
+ __u8 event_id;
+ __le16 irq;
+} __attribute__((packed));
+
+/* FM legacy interrupt packet, PG1 style */
+struct fm_leg_irq_v1 {
+ __u8 param_length;
+ __u8 opcode;
+ __u8 event_id;
+ __le16 irq;
+} __attribute__((packed));
+
+union fm_leg_evt_or_irq {
+ __u8 param_length;
+ struct fm_leg_cmd_cmpl evt;
+ struct fm_leg_irq_v2 irq_v2;
+ struct fm_leg_irq_v1 irq_v1;
+} __attribute__((packed));
+
+/* FM Opcode generic*/
+#define CG2900_FM_GEN_ID_LEGACY 0xFE
+
+/* FM event*/
+#define CG2900_FM_EVENT_UNKNOWN 0
+#define CG2900_FM_EVENT_CMD_COMPLETE 1
+#define CG2900_FM_EVENT_INTERRUPT 2
+
+/* FM do-command identifiers. */
+#define CG2900_FM_DO_AIP_FADE_START 0x0046
+#define CG2900_FM_DO_AUP_BT_FADE_START 0x01C2
+#define CG2900_FM_DO_AUP_EXT_FADE_START 0x0102
+#define CG2900_FM_DO_AUP_FADE_START 0x00A2
+#define CG2900_FM_DO_FMR_SETANTENNA 0x0663
+#define CG2900_FM_DO_FMR_SP_AFSWITCH_START 0x04A3
+#define CG2900_FM_DO_FMR_SP_AFUPDATE_START 0x0463
+#define CG2900_FM_DO_FMR_SP_BLOCKSCAN_START 0x0683
+#define CG2900_FM_DO_FMR_SP_PRESETPI_START 0x0443
+#define CG2900_FM_DO_FMR_SP_SCAN_START 0x0403
+#define CG2900_FM_DO_FMR_SP_SEARCH_START 0x03E3
+#define CG2900_FM_DO_FMR_SP_SEARCHPI_START 0x0703
+#define CG2900_FM_DO_FMR_SP_TUNE_SETCHANNEL 0x03C3
+#define CG2900_FM_DO_FMR_SP_TUNE_STEPCHANNEL 0x04C3
+#define CG2900_FM_DO_FMT_PA_SETCTRL 0x01A4
+#define CG2900_FM_DO_FMT_PA_SETMODE 0x01E4
+#define CG2900_FM_DO_FMT_SP_TUNE_SETCHANNEL 0x0064
+#define CG2900_FM_DO_GEN_ANTENNACHECK_START 0x02A1
+#define CG2900_FM_DO_GEN_GOTOMODE 0x0041
+#define CG2900_FM_DO_GEN_POWERSUPPLY_SETMODE 0x0221
+#define CG2900_FM_DO_GEN_SELECTREFERENCECLOCK 0x0201
+#define CG2900_FM_DO_GEN_SETPROCESSINGCLOCK 0x0241
+#define CG2900_FM_DO_GEN_SETREFERENCECLOCKPLL 0x01A1
+#define CG2900_FM_DO_TST_TX_RAMP_START 0x0147
+#define CG2900_FM_CMD_NONE 0xFFFF
+#define CG2900_FM_CMD_ID_GEN_GOTO_POWER_DOWN 0x0081
+#define CG2900_FM_CMD_ID_GEN_GOTO_STANDBY 0x0061
+
+/* FM Command IDs */
+#define CG2900_FM_CMD_ID_AUP_EXT_SET_MODE 0x0162
+#define CG2900_FM_CMD_ID_AUP_EXT_SET_CTRL 0x0182
+#define CG2900_FM_CMD_ID_AIP_SET_MODE 0x01C6
+#define CG2900_FM_CMD_ID_AIP_BT_SET_CTRL 0x01A6
+#define CG2900_FM_CMD_ID_AIP_BT_SET_MODE 0x01E6
+
+/* FM Command Parameters. */
+#define CG2900_FM_CMD_PARAM_ENABLE 0x00
+#define CG2900_FM_CMD_PARAM_DISABLE 0x01
+#define CG2900_FM_CMD_PARAM_RESET 0x02
+#define CG2900_FM_CMD_PARAM_WRITECOMMAND 0x10
+#define CG2900_FM_CMD_PARAM_SET_INT_MASK_ALL 0x20
+#define CG2900_FM_CMD_PARAM_GET_INT_MASK_ALL 0x21
+#define CG2900_FM_CMD_PARAM_SET_INT_MASK 0x22
+#define CG2900_FM_CMD_PARAM_GET_INT_MASK 0x23
+#define CG2900_FM_CMD_PARAM_FM_FW_DOWNLOAD 0x30
+#define CG2900_FM_CMD_PARAM_NONE 0xFF
+
+/* FM Legacy Command Parameters */
+#define CG2900_FM_CMD_LEG_PARAM_WRITE 0x00
+#define CG2900_FM_CMD_LEG_PARAM_IRQ 0x01
+
+/* FM Command Status. */
+#define CG2900_FM_CMD_STATUS_COMMAND_SUCCEEDED 0x00
+#define CG2900_FM_CMD_STATUS_HW_FAILURE 0x03
+#define CG2900_FM_CMD_STATUS_INVALID_PARAMS 0x12
+#define CG2900_FM_CMD_STATUS_UNINITILIZED 0x15
+#define CG2900_FM_CMD_STATUS_UNSPECIFIED_ERROR 0x1F
+#define CG2900_FM_CMD_STATUS_COMMAND_DISALLOWED 0x0C
+#define CG2900_FM_CMD_STATUS_FW_WRONG_SEQUENCE_NR 0xF1
+#define CG2900_FM_CMD_STATUS_FW_UNKNOWN_FILE 0xF2
+#define CG2900_FM_CMD_STATUS_FW_FILE_VER_MISMATCH 0xF3
+
+/* FM Interrupts. */
+#define CG2900_FM_IRPT_FIQ 0x0000
+#define CG2900_FM_IRPT_OPERATION_SUCCEEDED 0x0001
+#define CG2900_FM_IRPT_OPERATION_FAILED 0x0002
+#define CG2900_FM_IRPT_BUFFER_FULL 0x0008
+#define CG2900_FM_IRPT_BUFFER_EMPTY 0x0008
+#define CG2900_FM_IRPT_SIGNAL_QUALITY_LOW 0x0010
+#define CG2900_FM_IRPT_MUTE_STATUS_CHANGED 0x0010
+#define CG2900_FM_IRPT_MONO_STEREO_TRANSITION 0x0020
+#define CG2900_FM_IRPT_OVER_MODULATION 0x0020
+#define CG2900_FM_IRPT_RDS_SYNC_FOUND 0x0040
+#define CG2900_FM_IRPT_INPUT_OVERDRIVE 0x0040
+#define CG2900_FM_IRPT_RDS_SYNC_LOST 0x0080
+#define CG2900_FM_IRPT_PI_CODE_CHANGED 0x0100
+#define CG2900_FM_IRPT_REQUEST_BLOCK_AVALIBLE 0x0200
+#define CG2900_FM_IRPT_BUFFER_CLEARED 0x2000
+#define CG2900_FM_IRPT_WARM_BOOT_READY 0x4000
+#define CG2900_FM_IRPT_COLD_BOOT_READY 0x8000
+
+/* FM Legacy Function Command Parameters */
+
+/* AUP_EXT_SetMode Output enum */
+#define CG2900_FM_CMD_AUP_EXT_SET_MODE_DISABLED 0x0000
+#define CG2900_FM_CMD_AUP_EXT_SET_MODE_I2S 0x0001
+#define CG2900_FM_CMD_AUP_EXT_SET_MODE_PARALLEL 0x0002
+
+/* SetControl Conversion enum */
+#define CG2900_FM_CMD_SET_CTRL_CONV_UP 0x0000
+#define CG2900_FM_CMD_SET_CTRL_CONV_DOWN 0x0001
+
+/* AIP_SetMode Input enum */
+#define CG2900_FM_CMD_AIP_SET_MODE_INPUT_ANA 0x0000
+#define CG2900_FM_CMD_AIP_SET_MODE_INPUT_DIG 0x0001
+
+/* AIP_BT_SetMode Input enum */
+#define CG2900_FM_CMD_AIP_BT_SET_MODE_INPUT_RESERVED 0x0000
+#define CG2900_FM_CMD_AIP_BT_SET_MODE_INPUT_I2S 0x0001
+#define CG2900_FM_CMD_AIP_BT_SET_MODE_INPUT_PAR 0x0002
+#define CG2900_FM_CMD_AIP_BT_SET_MODE_INPUT_FIFO 0x0003
+
+/* FM Parameter Lengths = FM command length - length field (1 byte) */
+#define CG2900_FM_CMD_PARAM_LEN(len) (len - 1)
+
+/*
+ * FM Command ID mapped per byte and shifted 3 bits left
+ * Also adds number of parameters at first 3 bits of LSB.
+ */
+static inline __u16 cg2900_get_fm_cmd_id(__u16 opcode)
+{
+ return opcode >> 3;
+}
+
+static inline __u16 cg2900_make_fm_cmd_id(__u16 id, __u8 num_params)
+{
+ return (id << 3) | num_params;
+}
+
+/*
+ * GNSS
+ */
+
+struct gnss_hci_hdr {
+ __u8 op_code;
+ __le16 plen;
+} __attribute__((packed));
+
+#endif /* _CG2900_CHIP_H_ */
diff --git a/drivers/mfd/cg2900/cg2900_core.c b/drivers/mfd/cg2900/cg2900_core.c
new file mode 100644
index 00000000000..8c26202ab24
--- /dev/null
+++ b/drivers/mfd/cg2900/cg2900_core.c
@@ -0,0 +1,2287 @@
+/*
+ * drivers/mfd/cg2900/cg2900_core.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth HCI H:4 Driver for ST-Ericsson CG2900 GPS/BT/FM controller.
+ */
+
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include <linux/gfp.h>
+#include <linux/stat.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <asm/byteorder.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+
+#include <linux/mfd/cg2900.h>
+#include <mach/cg2900_devices.h>
+#include "cg2900_core.h"
+#include "cg2900_char_devices.h"
+#include "cg2900_debug.h"
+#include "hci_defines.h"
+
+/* Device names */
+#define CG2900_CDEV_NAME "cg2900_core_test"
+#define CG2900_CLASS_NAME "cg2900_class"
+#define CG2900_DEVICE_NAME "cg2900_driver"
+#define CORE_WQ_NAME "cg2900_core_wq"
+
+#define SET_MAIN_STATE(__core_new_state) \
+ CG2900_SET_STATE("main_state", core_info->main_state, \
+ __core_new_state)
+#define SET_BOOT_STATE(__core_new_state) \
+ CG2900_SET_STATE("boot_state", core_info->boot_state, __core_new_state)
+#define SET_TRANSPORT_STATE(__core_new_state) \
+ CG2900_SET_STATE("transport_state", core_info->transport_state, \
+ __core_new_state)
+
+#define LOGGER_DIRECTION_TX 0
+#define LOGGER_DIRECTION_RX 1
+
+/* Number of bytes to reserve at start of sk_buffer when receiving packet */
+#define RX_SKB_RESERVE 8
+
+/*
+ * Timeout values
+ */
+#define CHIP_STARTUP_TIMEOUT (15000) /* ms */
+#define CHIP_SHUTDOWN_TIMEOUT (15000) /* ms */
+#define LINE_TOGGLE_DETECT_TIMEOUT (50) /* ms */
+#define CHIP_READY_TIMEOUT (100) /* ms */
+#define REVISION_READOUT_TIMEOUT (500) /* ms */
+
+/*
+ * We can have up to 32 char devs with current bit mask and we also have
+ * the parent device here in the transport so that is 33 devices in total.
+ */
+#define MAX_NBR_OF_DEVS 33
+
+/* Default H4 channels which may change depending on connected controller */
+#define HCI_FM_RADIO_H4_CHANNEL 0x08
+#define HCI_GNSS_H4_CHANNEL 0x09
+
+/*
+ * Internal type definitions
+ */
+
+/**
+ * enum main_state - Main-state for CG2900 Core.
+ * @CORE_INITIALIZING: CG2900 Core initializing.
+ * @CORE_IDLE: No user registered to CG2900 Core.
+ * @CORE_BOOTING: CG2900 Core booting after first user is registered.
+ * @CORE_CLOSING: CG2900 Core closing after last user has deregistered.
+ * @CORE_RESETING: CG2900 Core reset requested.
+ * @CORE_ACTIVE: CG2900 Core up and running with at least one user.
+ */
+enum main_state {
+ CORE_INITIALIZING,
+ CORE_IDLE,
+ CORE_BOOTING,
+ CORE_CLOSING,
+ CORE_RESETING,
+ CORE_ACTIVE
+};
+
+/**
+ * enum boot_state - BOOT-state for CG2900 Core.
+ * @BOOT_NOT_STARTED: Boot has not yet started.
+ * @BOOT_READ_LOCAL_VERSION_INFORMATION: ReadLocalVersionInformation
+ * command has been sent.
+ * @BOOT_READY: CG2900 Core boot is ready.
+ * @BOOT_FAILED: CG2900 Core boot failed.
+ */
+enum boot_state {
+ BOOT_NOT_STARTED,
+ BOOT_READ_LOCAL_VERSION_INFORMATION,
+ BOOT_READY,
+ BOOT_FAILED
+};
+
+/**
+ * enum transport_state - State for the CG2900 transport.
+ * @TRANS_INITIALIZING: Transport initializing.
+ * @TRANS_OPENED: Transport is opened (data can be sent).
+ * @TRANS_CLOSED: Transport is closed (data cannot be sent).
+ */
+enum transport_state {
+ TRANS_INITIALIZING,
+ TRANS_OPENED,
+ TRANS_CLOSED
+};
+
+/**
+ * struct cg2900_users - Stores all current users of CG2900 Core.
+ * @bt_cmd: BT command channel user.
+ * @bt_acl: BT ACL channel user.
+ * @bt_evt: BT event channel user.
+ * @fm_radio: FM radio channel user.
+ * @gnss GNSS: GNSS channel user.
+ * @debug Debug: Internal debug channel user.
+ * @ste_tools: ST-E tools channel user.
+ * @hci_logger: HCI logger channel user.
+ * @us_ctrl: User space control channel user.
+ * @bt_audio: BT audio command channel user.
+ * @fm_radio_audio: FM audio command channel user.
+ * @core: Core command channel user.
+ * @nbr_of_users: Number of users currently registered (not including
+ * the HCI logger).
+ */
+struct cg2900_users {
+ struct cg2900_device *bt_cmd;
+ struct cg2900_device *bt_acl;
+ struct cg2900_device *bt_evt;
+ struct cg2900_device *fm_radio;
+ struct cg2900_device *gnss;
+ struct cg2900_device *debug;
+ struct cg2900_device *ste_tools;
+ struct cg2900_device *hci_logger;
+ struct cg2900_device *us_ctrl;
+ struct cg2900_device *bt_audio;
+ struct cg2900_device *fm_radio_audio;
+ struct cg2900_device *core;
+ unsigned int nbr_of_users;
+};
+
+/**
+ * struct local_chip_info - Stores local controller info.
+ * @version_set: true if version data is valid.
+ * @hci_version: HCI version of local controller.
+ * @hci_revision: HCI revision of local controller.
+ * @lmp_pal_version: LMP/PAL version of local controller.
+ * @manufacturer: Manufacturer of local controller.
+ * @lmp_pal_subversion: LMP/PAL sub-version of local controller.
+ *
+ * According to Bluetooth HCI Read Local Version Information command.
+ */
+struct local_chip_info {
+ bool version_set;
+ u8 hci_version;
+ u16 hci_revision;
+ u8 lmp_pal_version;
+ u16 manufacturer;
+ u16 lmp_pal_subversion;
+};
+
+/**
+ * struct chip_handler_item - Structure to store chip handler cb.
+ * @list: list_head struct.
+ * @cb: Chip handler callback struct.
+ */
+struct chip_handler_item {
+ struct list_head list;
+ struct cg2900_id_callbacks cb;
+};
+
+/**
+ * struct cg2900_work_struct - Work structure for CG2900 Core module.
+ * @work: Work structure.
+ * @data: Pointer to private data.
+ *
+ * This structure is used to pack work for work queue.
+ */
+struct cg2900_work_struct{
+ struct work_struct work;
+ void *data;
+};
+
+/**
+ * struct test_char_dev_info - Stores device information.
+ * @test_miscdev: Registered Misc Device.
+ * @rx_queue: RX data queue.
+ */
+struct test_char_dev_info {
+ struct miscdevice test_miscdev;
+ struct sk_buff_head rx_queue;
+};
+
+/**
+ * struct trans_info - Stores transport information.
+ * @dev: Transport device.
+ * @cb: Transport cb.
+ */
+struct trans_info {
+ struct cg2900_trans_dev dev;
+ struct cg2900_trans_callbacks cb;
+};
+
+/**
+ * struct core_info - Main info structure for CG2900 Core.
+ * @users: Stores all users of CG2900 Core.
+ * @local_chip_info: Stores information of local controller.
+ * @main_state: Current Main-state of CG2900 Core.
+ * @boot_state: Current BOOT-state of CG2900 Core.
+ * @transport_state: Current TRANSPORT-state of CG2900 Core.
+ * @wq: CG2900 Core workqueue.
+ * @hci_logger_config: Stores HCI logger configuration.
+ * @dev: Device structure for STE Connectivity driver.
+ * @chip_dev: Device structure for chip driver.
+ * @h4_channels: HCI H:4 channel used by this device.
+ * @test_char_dev: Stores information of test char dev.
+ * @trans_info: Stores information about current transport.
+ */
+struct core_info {
+ struct cg2900_users users;
+ struct local_chip_info local_chip_info;
+ enum main_state main_state;
+ enum boot_state boot_state;
+ enum transport_state transport_state;
+ struct workqueue_struct *wq;
+ struct cg2900_hci_logger_config hci_logger_config;
+ struct miscdevice *dev;
+ struct cg2900_chip_dev chip_dev;
+ struct cg2900_h4_channels h4_channels;
+ struct test_char_dev_info *test_char_dev;
+ struct trans_info *trans_info;
+};
+
+/*
+ * Internal variable declarations
+ */
+
+/*
+ * core_info - Main information object for CG2900 Core.
+ */
+static struct core_info *core_info;
+
+/* Module parameters */
+int cg2900_debug_level = CG2900_DEFAULT_DEBUG_LEVEL;
+EXPORT_SYMBOL(cg2900_debug_level);
+
+u8 bd_address[] = {0x00, 0xBE, 0xAD, 0xDE, 0x80, 0x00};
+EXPORT_SYMBOL(bd_address);
+int bd_addr_count = BT_BDADDR_SIZE;
+
+/* Setting default values to ST-E CG2900 */
+int default_manufacturer = 0x30;
+EXPORT_SYMBOL(default_manufacturer);
+int default_hci_revision = 0x0700;
+EXPORT_SYMBOL(default_hci_revision);
+int default_sub_version = 0x0011;
+EXPORT_SYMBOL(default_sub_version);
+
+static int sleep_timeout_ms;
+
+/*
+ * chip_handlers - List of the register handlers for different chips.
+ */
+LIST_HEAD(chip_handlers);
+
+/*
+ * main_wait_queue - Main Wait Queue in CG2900 Core.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(main_wait_queue);
+
+/*
+ * main_wait_queue - Char device Wait Queue in CG2900 Core.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(char_wait_queue);
+
+/*
+ * Internal functions
+ */
+
+/**
+ * free_user_dev - Frees user device and also sets it to NULL to inform caller.
+ * @dev: Pointer to user device.
+ */
+static void free_user_dev(struct cg2900_device **dev)
+{
+ if (*dev) {
+ kfree((*dev)->cb);
+ kfree(*dev);
+ *dev = NULL;
+ }
+}
+
+/**
+ * handle_reset_of_user - Calls the reset callback and frees the device.
+ * @dev: Pointer to CG2900 device.
+ */
+static void handle_reset_of_user(struct cg2900_device **dev)
+{
+ if (*dev) {
+ if ((*dev)->cb->reset_cb)
+ (*dev)->cb->reset_cb((*dev));
+ free_user_dev(dev);
+ }
+}
+
+/**
+ * transmit_skb_to_chip() - Transmit buffer to the transport.
+ * @skb: Data packet.
+ * @use_logger: True if HCI logger shall be used, false otherwise.
+ *
+ * The transmit_skb_to_chip() function transmit buffer to the transport.
+ * If enabled, copy the transmitted data to the HCI logger as well.
+ */
+static void transmit_skb_to_chip(struct sk_buff *skb, bool use_logger)
+{
+ int err;
+ struct sk_buff *skb_log;
+ struct trans_info *trans_info = core_info->trans_info;
+ struct cg2900_device *logger;
+
+ CG2900_DBG_DATA("transmit_skb_to_chip %d bytes. First byte 0x%02X",
+ skb->len, *(skb->data));
+
+ if (TRANS_CLOSED == core_info->transport_state) {
+ CG2900_ERR("Trying to write on a closed channel");
+ kfree_skb(skb);
+ return;
+ }
+
+ /*
+ * If HCI logging is enabled for this channel, copy the data to
+ * the HCI logging output.
+ */
+ logger = core_info->users.hci_logger;
+ if (!use_logger || !logger)
+ goto transmit;
+
+ /*
+ * Alloc a new sk_buff and copy the data into it. Then send it to
+ * the HCI logger.
+ */
+ skb_log = alloc_skb(skb->len + 1, GFP_ATOMIC);
+ if (!skb_log) {
+ CG2900_ERR("Couldn't allocate skb_log");
+ goto transmit;
+ }
+
+ memcpy(skb_put(skb_log, skb->len), skb->data, skb->len);
+ skb_log->data[0] = (u8) LOGGER_DIRECTION_TX;
+
+ if (logger->cb->read_cb)
+ logger->cb->read_cb(logger, skb_log);
+
+transmit:
+ CG2900_DBG_DATA_CONTENT("Length: %d Data: %02X %02X %02X %02X %02X "
+ "%02X %02X %02X %02X %02X %02X %02X",
+ skb->len,
+ skb->data[0], skb->data[1], skb->data[2],
+ skb->data[3], skb->data[4], skb->data[5],
+ skb->data[6], skb->data[7], skb->data[8],
+ skb->data[9], skb->data[10], skb->data[11]);
+
+ if (trans_info && trans_info->cb.write) {
+ err = trans_info->cb.write(&trans_info->dev, skb);
+ if (err)
+ CG2900_ERR("Transport write failed (%d)", err);
+ } else {
+ CG2900_ERR("No way to write to chip");
+ err = -EPERM;
+ }
+
+ if (err)
+ kfree_skb(skb);
+}
+
+/**
+ * create_and_send_bt_cmd() - Copy and send sk_buffer.
+ * @data: Data to send.
+ * @length: Length in bytes of data.
+ *
+ * The create_and_send_bt_cmd() function allocates sk_buffer, copy supplied
+ * data to it, and send the sk_buffer to the transport.
+ */
+static void create_and_send_bt_cmd(void *data, int length)
+{
+ struct sk_buff *skb;
+
+ skb = cg2900_alloc_skb(length, GFP_ATOMIC);
+ if (!skb) {
+ CG2900_ERR("Couldn't allocate sk_buff with length %d",
+ length);
+ return;
+ }
+
+ memcpy(skb_put(skb, length), data, length);
+ skb_push(skb, CG2900_SKB_RESERVE);
+ skb->data[0] = HCI_BT_CMD_H4_CHANNEL;
+
+ transmit_skb_to_chip(skb, core_info->hci_logger_config.bt_cmd_enable);
+}
+
+/**
+ * chip_not_detected() - Called when it is not possible to detect the chip.
+ *
+ * This function sets chip information to default values if it is not possible
+ * to read out information from the chip. This is common when running module
+ * tests.
+ */
+static void chip_not_detected(void)
+{
+ struct list_head *cursor;
+ struct chip_handler_item *tmp;
+
+ CG2900_ERR("Could not read out revision from the chip. This is "
+ "typical when running stubbed CG2900.\n"
+ "Switching to default value:\n"
+ "\tman 0x%04X\n"
+ "\trev 0x%04X\n"
+ "\tsub 0x%04X",
+ default_manufacturer,
+ default_hci_revision,
+ default_sub_version);
+
+ core_info->chip_dev.chip.manufacturer = default_manufacturer;
+ core_info->chip_dev.chip.hci_revision = default_hci_revision;
+ core_info->chip_dev.chip.hci_sub_version = default_sub_version;
+
+ memset(&(core_info->chip_dev.cb), 0, sizeof(core_info->chip_dev.cb));
+
+ /* Find the handler for our default chip */
+ list_for_each(cursor, &chip_handlers) {
+ tmp = list_entry(cursor, struct chip_handler_item, list);
+ if (tmp->cb.check_chip_support(&(core_info->chip_dev))) {
+ CG2900_INFO("Chip handler found");
+ SET_BOOT_STATE(BOOT_READY);
+ break;
+ }
+ }
+}
+
+/**
+ * enable_hci_logger() - Enable HCI logger for each device.
+ * @skb: Received sk buffer.
+ *
+ * The enable_hci_logger() change HCI logger configuration for all registered
+ * devices.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EACCES if bad structure was supplied.
+ */
+static int enable_hci_logger(struct sk_buff *skb)
+{
+ struct cg2900_users *users;
+ struct cg2900_hci_logger_config *config;
+
+ if (skb->len != sizeof(*config)) {
+ CG2900_ERR("Trying to configure HCI logger with bad structure");
+ return -EACCES;
+ }
+
+ users = &(core_info->users);
+ config = &(core_info->hci_logger_config);
+
+ /* First store the logger config */
+ memcpy(config, skb->data, sizeof(*config));
+
+ /* Then go through all devices and set the right settings */
+ if (users->bt_cmd)
+ users->bt_cmd->logger_enabled = config->bt_cmd_enable;
+ if (users->bt_audio)
+ users->bt_audio->logger_enabled = config->bt_audio_enable;
+ if (users->bt_acl)
+ users->bt_acl->logger_enabled = config->bt_acl_enable;
+ if (users->bt_evt)
+ users->bt_evt->logger_enabled = config->bt_evt_enable;
+ if (users->fm_radio)
+ users->fm_radio->logger_enabled = config->fm_radio_enable;
+ if (users->fm_radio_audio)
+ users->fm_radio_audio->logger_enabled =
+ config->fm_radio_audio_enable;
+ if (users->gnss)
+ users->gnss->logger_enabled = config->gnss_enable;
+
+ kfree_skb(skb);
+ return 0;
+}
+
+/**
+ * find_bt_audio_user() - Check if data packet is an audio related packet.
+ * @h4_channel: H4 channel.
+ * @dev: Stored CG2900 device.
+ * @skb: skb with received packet.
+ * Returns:
+ * 0 - if no error occurred.
+ * -ENXIO - if cg2900_device not found.
+ */
+static int find_bt_audio_user(int h4_channel, struct cg2900_device **dev,
+ const struct sk_buff * const skb)
+{
+ if (core_info->chip_dev.cb.is_bt_audio_user &&
+ core_info->chip_dev.cb.is_bt_audio_user(h4_channel, skb)) {
+ *dev = core_info->users.bt_audio;
+ if (!(*dev)) {
+ CG2900_ERR("H:4 channel not registered in core_info: "
+ "0x%X", h4_channel);
+ return -ENXIO;
+ }
+ }
+ return 0;
+}
+
+/**
+ * find_fm_audio_user() - Check if data packet is an audio related packet.
+ * @h4_channel: H4 channel.
+ * @dev: Stored CG2900 device.
+ * @skb: skb with received packet.
+ * Returns:
+ * 0 if no error occurred.
+ * -ENXIO if cg2900_device not found.
+ */
+static int find_fm_audio_user(int h4_channel, struct cg2900_device **dev,
+ const struct sk_buff * const skb)
+{
+ if (core_info->chip_dev.cb.is_fm_audio_user &&
+ core_info->chip_dev.cb.is_fm_audio_user(h4_channel, skb)) {
+ *dev = core_info->users.fm_radio_audio;
+ if (!(*dev)) {
+ CG2900_ERR("H:4 channel not registered in core_info: "
+ "0x%X", h4_channel);
+ return -ENXIO;
+ }
+ }
+ return 0;
+}
+
+/**
+ * find_h4_user() - Get H4 user based on supplied H4 channel.
+ * @h4_channel: H4 channel.
+ * @dev: Stored CG2900 device.
+ * @skb: (optional) skb with received packet. Set to NULL if NA.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL if bad channel is supplied or no user was found.
+ * -ENXIO if channel is audio channel but not registered with CG2900.
+ */
+static int find_h4_user(int h4_channel, struct cg2900_device **dev,
+ const struct sk_buff * const skb)
+{
+ int err = 0;
+ struct cg2900_users *users = &(core_info->users);
+ struct cg2900_h4_channels *chan = &(core_info->h4_channels);
+
+ if (h4_channel == chan->bt_cmd_channel) {
+ *dev = users->bt_cmd;
+ } else if (h4_channel == chan->bt_acl_channel) {
+ *dev = users->bt_acl;
+ } else if (h4_channel == chan->bt_evt_channel) {
+ *dev = users->bt_evt;
+ /* Check if it's event generated by previously sent audio user
+ * command. If so then that event should be dispatched to audio
+ * user*/
+ err = find_bt_audio_user(h4_channel, dev, skb);
+ } else if (h4_channel == chan->gnss_channel) {
+ *dev = users->gnss;
+ } else if (h4_channel == chan->fm_radio_channel) {
+ *dev = users->fm_radio;
+ /* Check if it's an event generated by previously sent audio
+ * user command. If so then that event should be dispatched to
+ * audio user */
+ err = find_fm_audio_user(h4_channel, dev, skb);
+ } else if (h4_channel == chan->debug_channel) {
+ *dev = users->debug;
+ } else if (h4_channel == chan->ste_tools_channel) {
+ *dev = users->ste_tools;
+ } else if (h4_channel == chan->hci_logger_channel) {
+ *dev = users->hci_logger;
+ } else if (h4_channel == chan->us_ctrl_channel) {
+ *dev = users->us_ctrl;
+ } else if (h4_channel == chan->core_channel) {
+ *dev = users->core;
+ } else {
+ *dev = NULL;
+ CG2900_ERR("Bad H:4 channel supplied: 0x%X", h4_channel);
+ return -EINVAL;
+ }
+
+ return err;
+}
+
+/**
+ * add_h4_user() - Add H4 user to user storage based on supplied H4 channel.
+ * @dev: Stored CG2900 device.
+ * @name: Device name to identify different devices that are using
+ * the same H4 channel.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL if NULL pointer or bad channel is supplied.
+ * -EBUSY if there already is a user for supplied channel.
+ */
+static int add_h4_user(struct cg2900_device *dev, const char * const name)
+{
+ int err = 0;
+ struct cg2900_users *users = &(core_info->users);
+ struct cg2900_hci_logger_config *config =
+ &(core_info->hci_logger_config);
+ struct cg2900_h4_channels *chan = &(core_info->h4_channels);
+
+ if (!dev) {
+ CG2900_ERR("NULL device supplied");
+ return -EINVAL;
+ }
+
+ if (dev->h4_channel == chan->bt_cmd_channel) {
+ if (!users->bt_cmd &&
+ 0 == strncmp(name, CG2900_BT_CMD, CG2900_MAX_NAME_SIZE)) {
+ users->bt_cmd = dev;
+ users->bt_cmd->logger_enabled = config->bt_cmd_enable;
+ (users->nbr_of_users)++;
+ } else if (!users->bt_audio &&
+ 0 == strncmp(name, CG2900_BT_AUDIO,
+ CG2900_MAX_NAME_SIZE)) {
+ users->bt_audio = dev;
+ users->bt_audio->logger_enabled =
+ config->bt_audio_enable;
+ (users->nbr_of_users)++;
+ } else {
+ err = -EBUSY;
+ CG2900_ERR("name %s bt_cmd 0x%X bt_audio 0x%X",
+ name, (int)users->bt_cmd,
+ (int)users->bt_audio);
+ }
+ } else if (dev->h4_channel == chan->bt_acl_channel) {
+ if (!users->bt_acl) {
+ users->bt_acl = dev;
+ users->bt_acl->logger_enabled = config->bt_acl_enable;
+ (users->nbr_of_users)++;
+ } else {
+ err = -EBUSY;
+ }
+ } else if (dev->h4_channel == chan->bt_evt_channel) {
+ if (!users->bt_evt) {
+ users->bt_evt = dev;
+ users->bt_evt->logger_enabled = config->bt_evt_enable;
+ (users->nbr_of_users)++;
+ } else {
+ err = -EBUSY;
+ }
+ } else if (dev->h4_channel == chan->gnss_channel) {
+ if (!users->gnss) {
+ users->gnss = dev;
+ users->gnss->logger_enabled = config->gnss_enable;
+ (users->nbr_of_users)++;
+ } else {
+ err = -EBUSY;
+ }
+ } else if (dev->h4_channel == chan->fm_radio_channel) {
+ if (!users->fm_radio &&
+ 0 == strncmp(name, CG2900_FM_RADIO,
+ CG2900_MAX_NAME_SIZE)) {
+ users->fm_radio = dev;
+ users->fm_radio->logger_enabled =
+ config->fm_radio_enable;
+ (users->nbr_of_users)++;
+ } else if (!users->fm_radio_audio &&
+ 0 == strncmp(name, CG2900_FM_RADIO_AUDIO,
+ CG2900_MAX_NAME_SIZE)) {
+ users->fm_radio_audio = dev;
+ users->fm_radio_audio->logger_enabled =
+ config->fm_radio_audio_enable;
+ (users->nbr_of_users)++;
+ } else {
+ err = -EBUSY;
+ }
+ } else if (dev->h4_channel == chan->debug_channel) {
+ if (!users->debug)
+ users->debug = dev;
+ else
+ err = -EBUSY;
+ } else if (dev->h4_channel == chan->ste_tools_channel) {
+ if (!users->ste_tools)
+ users->ste_tools = dev;
+ else
+ err = -EBUSY;
+ } else if (dev->h4_channel == chan->hci_logger_channel) {
+ if (!users->hci_logger)
+ users->hci_logger = dev;
+ else
+ err = -EBUSY;
+ } else if (dev->h4_channel == chan->us_ctrl_channel) {
+ if (!users->us_ctrl)
+ users->us_ctrl = dev;
+ else
+ err = -EBUSY;
+ } else if (dev->h4_channel == chan->core_channel) {
+ if (!users->core) {
+ (users->nbr_of_users)++;
+ users->core = dev;
+ } else {
+ err = -EBUSY;
+ }
+ } else {
+ err = -EINVAL;
+ CG2900_ERR("Bad H:4 channel supplied: 0x%X", dev->h4_channel);
+ }
+
+ if (err)
+ CG2900_ERR("H:4 channel 0x%X, not registered (%d)",
+ dev->h4_channel, err);
+
+ return err;
+}
+
+/**
+ * remove_h4_user() - Remove H4 user from user storage.
+ * @dev: Stored CG2900 device.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL if NULL pointer is supplied, bad channel is supplied, or if there
+ * is no user for supplied channel.
+ */
+static int remove_h4_user(struct cg2900_device **dev)
+{
+ int err = 0;
+ struct cg2900_users *users = &(core_info->users);
+ struct cg2900_h4_channels *chan = &(core_info->h4_channels);
+ struct cg2900_chip_callbacks *cb = &(core_info->chip_dev.cb);
+
+ if (!dev || !(*dev)) {
+ CG2900_ERR("NULL device supplied");
+ return -EINVAL;
+ }
+
+ if ((*dev)->h4_channel == chan->bt_cmd_channel) {
+ CG2900_DBG("bt_cmd 0x%X bt_audio 0x%X dev 0x%X",
+ (int)users->bt_cmd,
+ (int)users->bt_audio, (int)*dev);
+
+ if (*dev == users->bt_cmd) {
+ users->bt_cmd = NULL;
+ (users->nbr_of_users)--;
+ } else if (*dev == users->bt_audio) {
+ users->bt_audio = NULL;
+ (users->nbr_of_users)--;
+ } else
+ err = -EINVAL;
+
+ CG2900_DBG("bt_cmd 0x%X bt_audio 0x%X dev 0x%X",
+ (int)users->bt_cmd,
+ (int)users->bt_audio, (int)*dev);
+
+ /*
+ * If both BT Command channel users are de-registered we
+ * inform the chip handler.
+ */
+ if (!users->bt_cmd && !users->bt_audio &&
+ cb->last_bt_user_removed)
+ cb->last_bt_user_removed(&(core_info->chip_dev));
+ } else if ((*dev)->h4_channel == chan->bt_acl_channel) {
+ if (*dev == users->bt_acl) {
+ users->bt_acl = NULL;
+ (users->nbr_of_users)--;
+ } else
+ err = -EINVAL;
+ } else if ((*dev)->h4_channel == chan->bt_evt_channel) {
+ if (*dev == users->bt_evt) {
+ users->bt_evt = NULL;
+ (users->nbr_of_users)--;
+ } else
+ err = -EINVAL;
+ } else if ((*dev)->h4_channel == chan->gnss_channel) {
+ if (*dev == users->gnss) {
+ users->gnss = NULL;
+ (users->nbr_of_users)--;
+ } else
+ err = -EINVAL;
+
+ /*
+ * If the GNSS channel user is de-registered we inform
+ * the chip handler.
+ */
+ if (users->gnss == NULL && cb->last_gnss_user_removed)
+ cb->last_gnss_user_removed(&(core_info->chip_dev));
+ } else if ((*dev)->h4_channel == chan->fm_radio_channel) {
+ if (*dev == users->fm_radio) {
+ users->fm_radio = NULL;
+ (users->nbr_of_users)--;
+ } else if (*dev == users->fm_radio_audio) {
+ users->fm_radio_audio = NULL;
+ (users->nbr_of_users)--;
+ } else
+ err = -EINVAL;
+
+ /*
+ * If both FM Radio channel users are de-registered we inform
+ * the chip handler.
+ */
+ if (!users->fm_radio && !users->fm_radio_audio &&
+ cb->last_fm_user_removed)
+ cb->last_fm_user_removed(&(core_info->chip_dev));
+ } else if ((*dev)->h4_channel == chan->debug_channel) {
+ if (*dev == users->debug)
+ users->debug = NULL;
+ else
+ err = -EINVAL;
+ } else if ((*dev)->h4_channel == chan->ste_tools_channel) {
+ if (*dev == users->ste_tools)
+ users->ste_tools = NULL;
+ else
+ err = -EINVAL;
+ } else if ((*dev)->h4_channel == chan->hci_logger_channel) {
+ if (*dev == users->hci_logger)
+ users->hci_logger = NULL;
+ else
+ err = -EINVAL;
+ } else if ((*dev)->h4_channel == chan->us_ctrl_channel) {
+ if (*dev == users->us_ctrl)
+ users->us_ctrl = NULL;
+ else
+ err = -EINVAL;
+ } else if ((*dev)->h4_channel == chan->core_channel) {
+ if (*dev == users->core) {
+ users->core = NULL;
+ (users->nbr_of_users)--;
+ } else
+ err = -EINVAL;
+ } else {
+ CG2900_ERR("Bad H:4 channel supplied: 0x%X",
+ (*dev)->h4_channel);
+ return -EINVAL;
+ }
+
+ if (err)
+ CG2900_ERR("Trying to remove device that was not registered");
+
+ /*
+ * Free the device even if there is an error with the device.
+ * Also set to NULL to inform caller about the free.
+ */
+ free_user_dev(dev);
+
+ return err;
+}
+
+/**
+ * chip_startup() - Start the connectivity controller and download patches and settings.
+ */
+static void chip_startup(void)
+{
+ struct hci_command_hdr cmd;
+
+ CG2900_INFO("chip_startup");
+
+ SET_MAIN_STATE(CORE_BOOTING);
+ SET_BOOT_STATE(BOOT_NOT_STARTED);
+
+ /*
+ * Transmit HCI reset command to ensure the chip is using
+ * the correct transport
+ */
+ cmd.opcode = cpu_to_le16(HCI_OP_RESET);
+ cmd.plen = 0; /* No parameters for HCI reset */
+ create_and_send_bt_cmd(&cmd, sizeof(cmd));
+}
+
+/**
+ * chip_shutdown() - Reset and power the chip off.
+ */
+static void chip_shutdown(void)
+{
+ int err = 0;
+ struct trans_info *trans_info = core_info->trans_info;
+ struct cg2900_chip_callbacks *cb = &(core_info->chip_dev.cb);
+
+ CG2900_INFO("chip_shutdown");
+
+ /* First do a quick power switch of the chip to assure a good state */
+ if (trans_info && trans_info->cb.set_chip_power)
+ trans_info->cb.set_chip_power(false);
+
+ /*
+ * Wait 50ms before continuing to be sure that the chip detects
+ * chip power off.
+ */
+ schedule_timeout_interruptible(
+ msecs_to_jiffies(LINE_TOGGLE_DETECT_TIMEOUT));
+
+ if (trans_info && trans_info->cb.set_chip_power)
+ trans_info->cb.set_chip_power(true);
+
+ /* Wait 100ms before continuing to be sure that the chip is ready */
+ schedule_timeout_interruptible(msecs_to_jiffies(CHIP_READY_TIMEOUT));
+
+ /*
+ * Let the chip handler finish the reset if any callback is registered.
+ * Otherwise we are finished.
+ */
+ if (!cb->chip_shutdown) {
+ CG2900_DBG("No registered handler. Finishing shutdown.");
+ cg2900_chip_shutdown_finished(err);
+ return;
+ }
+
+ err = cb->chip_shutdown(&(core_info->chip_dev));
+ if (err) {
+ CG2900_ERR("chip_shutdown failed (%d). Finishing shutdown.",
+ err);
+ cg2900_chip_shutdown_finished(err);
+ }
+}
+
+/**
+ * handle_reset_cmd_complete_evt() - Handle a received HCI Command Complete event for a Reset command.
+ * @data: Pointer to received HCI data packet.
+ *
+ * Returns:
+ * True, if packet was handled internally,
+ * False, otherwise.
+ */
+static bool handle_reset_cmd_complete_evt(u8 *data)
+{
+ bool pkt_handled = false;
+ u8 status = data[0];
+ struct hci_command_hdr cmd;
+
+ CG2900_INFO("Received Reset complete event with status 0x%X", status);
+
+ if ((core_info->main_state == CORE_BOOTING ||
+ core_info->main_state == CORE_INITIALIZING) &&
+ core_info->boot_state == BOOT_NOT_STARTED) {
+ /* Transmit HCI Read Local Version Information command */
+ SET_BOOT_STATE(BOOT_READ_LOCAL_VERSION_INFORMATION);
+ cmd.opcode = cpu_to_le16(HCI_OP_READ_LOCAL_VERSION);
+ cmd.plen = 0; /* No parameters for HCI reset */
+ create_and_send_bt_cmd(&cmd, sizeof(cmd));
+
+ pkt_handled = true;
+ }
+
+ return pkt_handled;
+}
+
+/**
+ * handle_read_local_version_info_cmd_complete_evt() - Handle a received HCI Command Complete event for a ReadLocalVersionInformation command.
+ * @data: Pointer to received HCI data packet.
+ *
+ * Returns:
+ * True, if packet was handled internally,
+ * False, otherwise.
+ */
+static bool handle_read_local_version_info_cmd_complete_evt(u8 *data)
+{
+ bool chip_handled = false;
+ struct list_head *cursor;
+ struct chip_handler_item *tmp;
+ struct local_chip_info *chip;
+ struct cg2900_chip_info *chip_info;
+ struct cg2900_chip_callbacks *cb;
+ int err;
+ struct hci_rp_read_local_version *evt;
+
+ /* Check we're in the right state */
+ if ((core_info->main_state != CORE_BOOTING &&
+ core_info->main_state != CORE_INITIALIZING) ||
+ core_info->boot_state != BOOT_READ_LOCAL_VERSION_INFORMATION)
+ return false;
+
+ /* We got an answer for our HCI command. Extract data */
+ evt = (struct hci_rp_read_local_version *)data;
+
+ /* We will handle the packet */
+ if (HCI_BT_ERROR_NO_ERROR != evt->status) {
+ CG2900_ERR("Received Read Local Version Information with "
+ "status 0x%X", evt->status);
+ SET_BOOT_STATE(BOOT_FAILED);
+ cg2900_reset(NULL);
+ return true;
+ }
+
+ /* The command worked. Store the data */
+ chip = &(core_info->local_chip_info);
+ chip->version_set = true;
+ chip->hci_version = evt->hci_ver;
+ chip->hci_revision = le16_to_cpu(evt->hci_rev);
+ chip->lmp_pal_version = evt->lmp_ver;
+ chip->manufacturer = le16_to_cpu(evt->manufacturer);
+ chip->lmp_pal_subversion = le16_to_cpu(evt->lmp_subver);
+ CG2900_DBG("Received Read Local Version Information with:\n"
+ "\thci_version: 0x%X\n"
+ "\thci_revision: 0x%X\n"
+ "\tlmp_pal_version: 0x%X\n"
+ "\tmanufacturer: 0x%X\n"
+ "\tlmp_pal_subversion: 0x%X",
+ chip->hci_version, chip->hci_revision,
+ chip->lmp_pal_version, chip->manufacturer,
+ chip->lmp_pal_subversion);
+
+ cg2900_devices_set_hci_revision(chip->hci_version,
+ chip->hci_revision,
+ chip->lmp_pal_version,
+ chip->lmp_pal_subversion,
+ chip->manufacturer);
+
+ /* Received good confirmation. Find handler for the chip. */
+ chip_info = &(core_info->chip_dev.chip);
+ chip_info->hci_revision = chip->hci_revision;
+ chip_info->hci_sub_version = chip->lmp_pal_subversion;
+ chip_info->manufacturer = chip->manufacturer;
+
+ memset(&(core_info->chip_dev.cb), 0, sizeof(core_info->chip_dev.cb));
+
+ list_for_each(cursor, &chip_handlers) {
+ tmp = list_entry(cursor, struct chip_handler_item, list);
+ chip_handled = tmp->cb.check_chip_support(
+ &(core_info->chip_dev));
+ if (chip_handled) {
+ CG2900_INFO("Chip handler found");
+ break;
+ }
+ }
+
+ if (core_info->main_state == CORE_INITIALIZING) {
+ /*
+ * We are now finished with the start-up during HwRegistered
+ * operation.
+ */
+ SET_BOOT_STATE(BOOT_READY);
+ wake_up_interruptible(&main_wait_queue);
+ } else if (!chip_handled) {
+ CG2900_INFO("No chip handler found. Start-up complete");
+ SET_BOOT_STATE(BOOT_READY);
+ cg2900_chip_startup_finished(0);
+ } else {
+ cb = &(core_info->chip_dev.cb);
+ if (!cb->chip_startup)
+ cg2900_chip_startup_finished(0);
+ else {
+ err = cb->chip_startup(&(core_info->chip_dev));
+ if (err)
+ cg2900_chip_startup_finished(err);
+ }
+ }
+
+ return true;
+}
+
+/**
+ * handle_rx_data_bt_evt() - Check if data should be handled in CG2900 Core.
+ * @skb: Data packet
+ *
+ * The handle_rx_data_bt_evt() function checks if received data should be
+ * handled in CG2900 Core. If so handle it correctly.
+ * Received data is always HCI BT Event.
+ *
+ * Returns:
+ * True, if packet was handled internally,
+ * False, otherwise.
+ */
+static bool handle_rx_data_bt_evt(struct sk_buff *skb)
+{
+ bool pkt_handled = false;
+ u8 *data = &(skb->data[CG2900_SKB_RESERVE]);
+ struct hci_event_hdr *evt;
+ struct hci_ev_cmd_complete *cmd_complete;
+ u16 op_code;
+
+ evt = (struct hci_event_hdr *)data;
+
+ /* First check the event code */
+ if (HCI_EV_CMD_COMPLETE != evt->evt)
+ return false;
+
+ data += sizeof(*evt);
+ cmd_complete = (struct hci_ev_cmd_complete *)data;
+
+ op_code = le16_to_cpu(cmd_complete->opcode);
+
+ CG2900_DBG_DATA("Received Command Complete: op_code = 0x%04X", op_code);
+ data += sizeof(*cmd_complete); /* Move to first byte after OCF */
+
+ if (op_code == HCI_OP_RESET)
+ pkt_handled = handle_reset_cmd_complete_evt(data);
+ else if (op_code == HCI_OP_READ_LOCAL_VERSION)
+ pkt_handled =
+ handle_read_local_version_info_cmd_complete_evt(data);
+
+ if (pkt_handled)
+ kfree_skb(skb);
+
+ return pkt_handled;
+}
+
+/**
+ * test_char_dev_tx_received() - Handle data received from CG2900 Core.
+ * @dev: Current transport device information.
+ * @skb: Buffer with data coming form device.
+ */
+static int test_char_dev_tx_received(struct cg2900_trans_dev *dev,
+ struct sk_buff *skb)
+{
+ skb_queue_tail(&core_info->test_char_dev->rx_queue, skb);
+ wake_up_interruptible(&char_wait_queue);
+ return 0;
+}
+
+/**
+ * test_char_dev_open() - User space char device has been opened.
+ * @inode: Device driver information.
+ * @filp: Pointer to the file struct.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EACCES if transport already exists.
+ * -ENOMEM if allocation fails.
+ * Errors from create_work_item.
+ */
+static int test_char_dev_open(struct inode *inode, struct file *filp)
+{
+ struct cg2900_trans_callbacks cb = {
+ .write = test_char_dev_tx_received,
+ .open = NULL,
+ .close = NULL,
+ .set_chip_power = NULL
+ };
+
+ CG2900_INFO("test_char_dev_open");
+ return cg2900_register_trans_driver(&cb, NULL);
+}
+
+/**
+ * test_char_dev_release() - User space char device has been closed.
+ * @inode: Device driver information.
+ * @filp: Pointer to the file struct.
+ *
+ * Returns:
+ * 0 if there is no error.
+ */
+static int test_char_dev_release(struct inode *inode, struct file *filp)
+{
+ /* Clean the message queue */
+ skb_queue_purge(&core_info->test_char_dev->rx_queue);
+ return cg2900_deregister_trans_driver();
+}
+
+/**
+ * test_char_dev_read() - Queue and copy buffer to user space char device.
+ * @filp: Pointer to the file struct.
+ * @buf: Received buffer.
+ * @count: Count of received data in bytes.
+ * @f_pos: Position in buffer.
+ *
+ * Returns:
+ * >= 0 is number of bytes read.
+ * -EFAULT if copy_to_user fails.
+ */
+static ssize_t test_char_dev_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ struct sk_buff *skb;
+ int bytes_to_copy;
+ int err;
+ struct sk_buff_head *rx_queue = &core_info->test_char_dev->rx_queue;
+
+ CG2900_INFO("test_char_dev_read");
+
+ if (skb_queue_empty(rx_queue))
+ wait_event_interruptible(char_wait_queue,
+ !(skb_queue_empty(rx_queue)));
+
+ skb = skb_dequeue(rx_queue);
+ if (!skb) {
+ CG2900_INFO("skb queue is empty - return with zero bytes");
+ bytes_to_copy = 0;
+ goto finished;
+ }
+
+ bytes_to_copy = min(count, skb->len);
+ err = copy_to_user(buf, skb->data, bytes_to_copy);
+ if (err) {
+ skb_queue_head(rx_queue, skb);
+ return -EFAULT;
+ }
+
+ skb_pull(skb, bytes_to_copy);
+
+ if (skb->len > 0)
+ skb_queue_head(rx_queue, skb);
+ else
+ kfree_skb(skb);
+
+finished:
+ return bytes_to_copy;
+}
+
+/**
+ * test_char_dev_write() - Copy buffer from user and write to CG2900 Core.
+ * @filp: Pointer to the file struct.
+ * @buf: Read buffer.
+ * @count: Size of the buffer write.
+ * @f_pos: Position in buffer.
+ *
+ * Returns:
+ * >= 0 is number of bytes written.
+ * -EFAULT if copy_from_user fails.
+ */
+static ssize_t test_char_dev_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ struct sk_buff *skb;
+
+ CG2900_INFO("test_char_dev_write count %d", count);
+
+ /* Allocate the SKB and reserve space for the header */
+ skb = alloc_skb(count + RX_SKB_RESERVE, GFP_ATOMIC);
+ if (!skb) {
+ CG2900_ERR("Failed to alloc skb");
+ return -ENOMEM;
+ }
+ skb_reserve(skb, RX_SKB_RESERVE);
+
+ if (copy_from_user(skb_put(skb, count), buf, count)) {
+ kfree_skb(skb);
+ return -EFAULT;
+ }
+ cg2900_data_from_chip(skb);
+
+ return count;
+}
+
+/**
+ * test_char_dev_poll() - Handle POLL call to the interface.
+ * @filp: Pointer to the file struct.
+ * @wait: Poll table supplied to caller.
+ *
+ * Returns:
+ * Mask of current set POLL values (0 or (POLLIN | POLLRDNORM))
+ */
+static unsigned int test_char_dev_poll(struct file *filp, poll_table *wait)
+{
+ unsigned int mask = 0;
+
+ poll_wait(filp, &char_wait_queue, wait);
+
+ if (!(skb_queue_empty(&core_info->test_char_dev->rx_queue)))
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+/*
+ * struct test_char_dev_fops - Test char devices file operations.
+ * @read: Function that reads from the char device.
+ * @write: Function that writes to the char device.
+ * @poll: Function that handles poll call to the fd.
+ */
+static const struct file_operations test_char_dev_fops = {
+ .open = test_char_dev_open,
+ .release = test_char_dev_release,
+ .read = test_char_dev_read,
+ .write = test_char_dev_write,
+ .poll = test_char_dev_poll
+};
+
+/**
+ * test_char_dev_create() - Create a char device for testing.
+ *
+ * Creates a separate char device that will interact directly with userspace
+ * test application.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ENOMEM if allocation fails.
+ * -EBUSY if device has already been allocated.
+ * Error codes from misc_register.
+ */
+static int test_char_dev_create(void)
+{
+ int err;
+
+ if (core_info->test_char_dev) {
+ CG2900_ERR("Trying to allocate test_char_dev twice");
+ return -EBUSY;
+ }
+
+ core_info->test_char_dev = kzalloc(sizeof(*(core_info->test_char_dev)),
+ GFP_KERNEL);
+ if (!core_info->test_char_dev) {
+ CG2900_ERR("Couldn't allocate test_char_dev");
+ return -ENOMEM;
+ }
+
+ /* Initialize the RX queue */
+ skb_queue_head_init(&core_info->test_char_dev->rx_queue);
+
+ /* Prepare miscdevice struct before registering the device */
+ core_info->test_char_dev->test_miscdev.minor = MISC_DYNAMIC_MINOR;
+ core_info->test_char_dev->test_miscdev.name = CG2900_CDEV_NAME;
+ core_info->test_char_dev->test_miscdev.fops = &test_char_dev_fops;
+ core_info->test_char_dev->test_miscdev.parent =
+ core_info->dev->this_device;
+
+ err = misc_register(&core_info->test_char_dev->test_miscdev);
+ if (err) {
+ CG2900_ERR("Error %d registering misc dev!", err);
+ kfree(core_info->test_char_dev);
+ core_info->test_char_dev = NULL;
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * test_char_dev_destroy() - Clean up after test_char_dev_create().
+ */
+static void test_char_dev_destroy(void)
+{
+ int err;
+
+ if (!core_info->test_char_dev)
+ return;
+
+ err = misc_deregister(&core_info->test_char_dev->test_miscdev);
+ if (err)
+ CG2900_ERR("Error %d deregistering misc dev!", err);
+
+ /* Clean the message queue */
+ skb_queue_purge(&core_info->test_char_dev->rx_queue);
+
+ kfree(core_info->test_char_dev);
+ core_info->test_char_dev = NULL;
+}
+
+/**
+ * open_transport() - Open the CG2900 transport for data transfers.
+ *
+ * Returns:
+ * 0 if there is no error,
+ * -EACCES if write to transport failed,
+ * -EIO if transport has not been selected or chip did not answer to commands.
+ */
+static int open_transport(void)
+{
+ int err = 0;
+ struct trans_info *trans_info = core_info->trans_info;
+
+ CG2900_INFO("open_transport");
+
+ if (trans_info && trans_info->cb.open) {
+ err = trans_info->cb.open(&trans_info->dev);
+ if (err)
+ CG2900_ERR("Transport open failed (%d)", err);
+ }
+
+ if (!err)
+ SET_TRANSPORT_STATE(TRANS_OPENED);
+
+ return err;
+}
+
+/**
+ * close_transport() - Close the CG2900 transport for data transfers.
+ */
+static void close_transport(void)
+{
+ struct trans_info *trans_info = core_info->trans_info;
+
+ CG2900_INFO("close_transport");
+
+ /* Check so transport has not already been removed */
+ if (TRANS_OPENED == core_info->transport_state)
+ SET_TRANSPORT_STATE(TRANS_CLOSED);
+
+ if (trans_info && trans_info->cb.close) {
+ int err = trans_info->cb.close(&trans_info->dev);
+ if (err)
+ CG2900_ERR("Transport close failed (%d)", err);
+ }
+}
+
+/**
+ * create_work_item() - Create work item and add it to the work queue.
+ * @wq: work queue struct where the work will be added.
+ * @work_func: Work function.
+ * @data: Private data for the work.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EBUSY if not possible to queue work.
+ * -ENOMEM if allocation fails.
+ */
+static int create_work_item(struct workqueue_struct *wq, work_func_t work_func,
+ void *data)
+{
+ struct cg2900_work_struct *new_work;
+ int err;
+
+ new_work = kmalloc(sizeof(*new_work), GFP_ATOMIC);
+ if (!new_work) {
+ CG2900_ERR("Failed to alloc memory for cg2900_work_struct!");
+ return -ENOMEM;
+ }
+
+ new_work->data = data;
+ INIT_WORK(&new_work->work, work_func);
+
+ err = queue_work(wq, &new_work->work);
+ if (!err) {
+ CG2900_ERR("Failed to queue work_struct because it's already "
+ "in the queue!");
+ kfree(new_work);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/**
+ * work_hw_registered() - Called when the interface to HW has been established.
+ * @work: Reference to work data.
+ *
+ * Since there now is a transport identify the connected chip and decide which
+ * chip handler to use.
+ */
+static void work_hw_registered(struct work_struct *work)
+{
+ struct cg2900_work_struct *current_work = NULL;
+ bool run_shutdown = true;
+ struct cg2900_chip_callbacks *cb;
+ struct cg2900_h4_channels *chan;
+ struct trans_info *trans_info = core_info->trans_info;
+ struct hci_command_hdr cmd;
+
+ CG2900_INFO("work_hw_registered");
+
+ if (!work) {
+ CG2900_ERR("work == NULL");
+ return;
+ }
+
+ current_work = container_of(work, struct cg2900_work_struct, work);
+
+ SET_MAIN_STATE(CORE_INITIALIZING);
+ SET_BOOT_STATE(BOOT_NOT_STARTED);
+
+ /*
+ * This might look strange, but we need to read out
+ * the revision info in order to be able to shutdown the chip properly.
+ */
+ if (trans_info && trans_info->cb.set_chip_power)
+ trans_info->cb.set_chip_power(true);
+
+ /* Wait 100ms before continuing to be sure that the chip is ready */
+ schedule_timeout_interruptible(msecs_to_jiffies(CHIP_READY_TIMEOUT));
+
+ /*
+ * Transmit HCI reset command to ensure the chip is using
+ * the correct transport
+ */
+ cmd.opcode = cpu_to_le16(HCI_OP_RESET);
+ cmd.plen = 0; /* No parameters for HCI reset */
+ create_and_send_bt_cmd(&cmd, sizeof(cmd));
+
+ /* Wait up to 500 milliseconds for revision to be read out */
+ CG2900_DBG("Wait up to 500 milliseconds for revision to be read.");
+ wait_event_interruptible_timeout(main_wait_queue,
+ (BOOT_READY == core_info->boot_state),
+ msecs_to_jiffies(REVISION_READOUT_TIMEOUT));
+
+ /*
+ * If we are in BOOT_READY we have a good revision.
+ * Otherwise handle this as an error and switch to default handler.
+ */
+ if (BOOT_READY != core_info->boot_state) {
+ chip_not_detected();
+ run_shutdown = false;
+ }
+
+ /* Read out the channels for connected chip */
+ cb = &(core_info->chip_dev.cb);
+ chan = &(core_info->h4_channels);
+ if (cb->get_h4_channel) {
+ /* Get the H4 channel ID for all channels */
+ cb->get_h4_channel(CG2900_BT_CMD, &(chan->bt_cmd_channel));
+ cb->get_h4_channel(CG2900_BT_ACL, &(chan->bt_acl_channel));
+ cb->get_h4_channel(CG2900_BT_EVT, &(chan->bt_evt_channel));
+ cb->get_h4_channel(CG2900_GNSS, &(chan->gnss_channel));
+ cb->get_h4_channel(CG2900_FM_RADIO, &(chan->fm_radio_channel));
+ cb->get_h4_channel(CG2900_DEBUG, &(chan->debug_channel));
+ cb->get_h4_channel(CG2900_STE_TOOLS,
+ &(chan->ste_tools_channel));
+ cb->get_h4_channel(CG2900_HCI_LOGGER,
+ &(chan->hci_logger_channel));
+ cb->get_h4_channel(CG2900_US_CTRL, &(chan->us_ctrl_channel));
+ cb->get_h4_channel(CG2900_CORE, &(chan->core_channel));
+ }
+
+ /*
+ * Now it is time to shutdown the controller to reduce
+ * power consumption until any users register
+ */
+ if (run_shutdown)
+ chip_shutdown();
+ else
+ cg2900_chip_shutdown_finished(0);
+
+ kfree(current_work);
+}
+
+/*
+ * CG2900 API functions
+ */
+
+struct cg2900_device *cg2900_register_user(char *name,
+ struct cg2900_callbacks *cb)
+{
+ struct cg2900_device *current_dev;
+ int err;
+ struct trans_info *trans_info = core_info->trans_info;
+
+ CG2900_INFO("cg2900_register_user %s", name);
+
+ BUG_ON(!core_info);
+
+ /* Wait for state CORE_IDLE or CORE_ACTIVE. */
+ err = wait_event_interruptible_timeout(main_wait_queue,
+ (CORE_IDLE == core_info->main_state ||
+ CORE_ACTIVE == core_info->main_state),
+ msecs_to_jiffies(LINE_TOGGLE_DETECT_TIMEOUT));
+
+ if (err <= 0) {
+ if (CORE_INITIALIZING == core_info->main_state)
+ CG2900_ERR("Transport not opened");
+ else
+ CG2900_ERR("cg2900_register_user currently busy (0x%X)."
+ " Try again.", core_info->main_state);
+ return NULL;
+ }
+
+ /* Allocate device */
+ current_dev = kzalloc(sizeof(*current_dev), GFP_ATOMIC);
+ if (!current_dev) {
+ CG2900_ERR("Couldn't allocate current dev");
+ goto error_handling;
+ }
+
+ if (!core_info->chip_dev.cb.get_h4_channel) {
+ CG2900_ERR("No channel handler registered");
+ goto error_handling;
+ }
+ err = core_info->chip_dev.cb.get_h4_channel(name,
+ &(current_dev->h4_channel));
+ if (err) {
+ CG2900_ERR("Couldn't find H4 channel for %s", name);
+ goto error_handling;
+ }
+ current_dev->dev = core_info->dev->this_device;
+ current_dev->cb = kmalloc(sizeof(*(current_dev->cb)),
+ GFP_ATOMIC);
+ if (!current_dev->cb) {
+ CG2900_ERR("Couldn't allocate cb ");
+ goto error_handling;
+ }
+ memcpy((char *)current_dev->cb, (char *)cb,
+ sizeof(*(current_dev->cb)));
+
+ /* Retrieve pointer to the correct CG2900 Core user structure */
+ err = add_h4_user(current_dev, name);
+
+ if (!err) {
+ CG2900_DBG("H:4 channel 0x%X registered",
+ current_dev->h4_channel);
+ } else {
+ CG2900_ERR("H:4 channel 0x%X already registered "
+ "or other error (%d)",
+ current_dev->h4_channel, err);
+ goto error_handling;
+ }
+
+ if (CORE_ACTIVE != core_info->main_state &&
+ core_info->users.nbr_of_users == 1) {
+ /* Open transport and start-up the chip */
+ if (trans_info && trans_info->cb.set_chip_power)
+ trans_info->cb.set_chip_power(true);
+
+ /* Wait 100ms to be sure that the chip is ready */
+ schedule_timeout_interruptible(
+ msecs_to_jiffies(CHIP_READY_TIMEOUT));
+
+ err = open_transport();
+ if (err) {
+ /*
+ * Remove the user. If there is no error it will be
+ * freed as well.
+ */
+ remove_h4_user(&current_dev);
+ goto finished;
+ }
+
+ chip_startup();
+
+ /* Wait up to 15 seconds for chip to start */
+ CG2900_DBG("Wait up to 15 seconds for chip to start..");
+ wait_event_interruptible_timeout(main_wait_queue,
+ (CORE_ACTIVE == core_info->main_state ||
+ CORE_IDLE == core_info->main_state),
+ msecs_to_jiffies(CHIP_STARTUP_TIMEOUT));
+ if (CORE_ACTIVE != core_info->main_state) {
+ CG2900_ERR("ST-Ericsson CG2900 driver failed to "
+ "start");
+
+ /* Close the transport and power off the chip */
+ close_transport();
+
+ /*
+ * Remove the user. If there is no error it will be
+ * freed as well.
+ */
+ remove_h4_user(&current_dev);
+
+ /* Chip shut-down finished, set correct state. */
+ SET_MAIN_STATE(CORE_IDLE);
+ }
+ }
+ goto finished;
+
+error_handling:
+ free_user_dev(&current_dev);
+finished:
+ return current_dev;
+}
+EXPORT_SYMBOL(cg2900_register_user);
+
+void cg2900_deregister_user(struct cg2900_device *dev)
+{
+ int h4_channel;
+ int err = 0;
+
+ CG2900_INFO("cg2900_deregister_user");
+
+ BUG_ON(!core_info);
+
+ if (!dev) {
+ CG2900_ERR("Calling with NULL pointer");
+ return;
+ }
+
+ h4_channel = dev->h4_channel;
+
+ /* Remove the user. If there is no error it will be freed as well */
+ err = remove_h4_user(&dev);
+ if (err) {
+ CG2900_ERR("Trying to deregister non-registered "
+ "H:4 channel 0x%X or other error %d",
+ h4_channel, err);
+ return;
+ }
+
+ CG2900_DBG("H:4 channel 0x%X deregistered", h4_channel);
+
+ if (0 != core_info->users.nbr_of_users)
+ /* This was not the last user, we're done. */
+ return;
+
+ if (CORE_IDLE == core_info->main_state)
+ /* Chip has already been shut down. */
+ return;
+
+ SET_MAIN_STATE(CORE_CLOSING);
+ chip_shutdown();
+
+ /* Wait up to 15 seconds for chip to shut-down */
+ CG2900_DBG("Wait up to 15 seconds for chip to shut-down..");
+ wait_event_interruptible_timeout(main_wait_queue,
+ (CORE_IDLE == core_info->main_state),
+ msecs_to_jiffies(CHIP_SHUTDOWN_TIMEOUT));
+
+ /* Force shutdown if we timed out */
+ if (CORE_IDLE != core_info->main_state) {
+ CG2900_ERR("ST-Ericsson CG2900 Core Driver was shut-down with "
+ "problems.");
+
+ /* Close the transport and power off the chip */
+ close_transport();
+
+ /* Chip shut-down finished, set correct state. */
+ SET_MAIN_STATE(CORE_IDLE);
+ }
+}
+EXPORT_SYMBOL(cg2900_deregister_user);
+
+int cg2900_reset(struct cg2900_device *dev)
+{
+ CG2900_INFO("cg2900_reset");
+
+ BUG_ON(!core_info);
+
+ SET_MAIN_STATE(CORE_RESETING);
+
+ /* Shutdown the chip */
+ chip_shutdown();
+
+ /*
+ * Inform all registered users about the reset and free the user devices
+ * Don't send reset for debug and logging channels
+ */
+ handle_reset_of_user(&(core_info->users.bt_cmd));
+ handle_reset_of_user(&(core_info->users.bt_audio));
+ handle_reset_of_user(&(core_info->users.bt_acl));
+ handle_reset_of_user(&(core_info->users.bt_evt));
+ handle_reset_of_user(&(core_info->users.fm_radio));
+ handle_reset_of_user(&(core_info->users.fm_radio_audio));
+ handle_reset_of_user(&(core_info->users.gnss));
+ handle_reset_of_user(&(core_info->users.core));
+
+ core_info->users.nbr_of_users = 0;
+
+ /* Reset finished. We are now idle until first user is registered */
+ SET_MAIN_STATE(CORE_IDLE);
+
+ /*
+ * Send wake-up since this might have been called from a failed boot.
+ * No harm done if it is a CG2900 Core user who called.
+ */
+ wake_up_interruptible(&main_wait_queue);
+
+ return 0;
+}
+EXPORT_SYMBOL(cg2900_reset);
+
+struct sk_buff *cg2900_alloc_skb(unsigned int size, gfp_t priority)
+{
+ struct sk_buff *skb;
+
+ CG2900_INFO("cg2900_alloc_skb");
+ CG2900_DBG("size %d bytes", size);
+
+ /* Allocate the SKB and reserve space for the header */
+ skb = alloc_skb(size + CG2900_SKB_RESERVE, priority);
+ if (skb)
+ skb_reserve(skb, CG2900_SKB_RESERVE);
+
+ return skb;
+}
+EXPORT_SYMBOL(cg2900_alloc_skb);
+
+int cg2900_write(struct cg2900_device *dev, struct sk_buff *skb)
+{
+ int err = 0;
+ u8 *h4_header;
+ struct cg2900_chip_callbacks *cb;
+
+ CG2900_DBG_DATA("cg2900_write");
+
+ BUG_ON(!core_info);
+
+ if (!dev) {
+ CG2900_ERR("cg2900_write with no device");
+ return -EINVAL;
+ }
+
+ if (!skb) {
+ CG2900_ERR("cg2900_write with no sk_buffer");
+ return -EINVAL;
+ }
+
+ CG2900_DBG_DATA("Length %d bytes", skb->len);
+
+ if (core_info->h4_channels.hci_logger_channel == dev->h4_channel) {
+ /*
+ * Treat the HCI logger write differently.
+ * A write can only mean a change of configuration.
+ */
+ err = enable_hci_logger(skb);
+ } else if (core_info->h4_channels.core_channel == dev->h4_channel) {
+ CG2900_ERR("Not possible to write data on core channel, "
+ "it only supports enable / disable chip");
+ err = -EPERM;
+ } else if (CORE_ACTIVE == core_info->main_state) {
+ /*
+ * Move the data pointer to the H:4 header position and
+ * store the H4 header.
+ */
+ h4_header = skb_push(skb, CG2900_SKB_RESERVE);
+ *h4_header = (u8)dev->h4_channel;
+
+ /*
+ * Check if the chip handler wants to handle this packet.
+ * If not, send it to the transport.
+ */
+ cb = &(core_info->chip_dev.cb);
+ if (!cb->data_to_chip ||
+ !(cb->data_to_chip(&(core_info->chip_dev), dev, skb)))
+ transmit_skb_to_chip(skb, dev->logger_enabled);
+ } else {
+ CG2900_ERR("Trying to transmit data when CG2900 Core is not "
+ "active");
+ err = -EACCES;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(cg2900_write);
+
+bool cg2900_get_local_revision(struct cg2900_rev_data *rev_data)
+{
+ BUG_ON(!core_info);
+
+ if (!rev_data) {
+ CG2900_ERR("Calling with rev_data NULL");
+ return false;
+ }
+
+ if (!core_info->local_chip_info.version_set)
+ return false;
+
+ rev_data->revision = core_info->local_chip_info.hci_revision;
+ rev_data->sub_version = core_info->local_chip_info.lmp_pal_subversion;
+
+ return true;
+}
+EXPORT_SYMBOL(cg2900_get_local_revision);
+
+int cg2900_register_chip_driver(struct cg2900_id_callbacks *cb)
+{
+ struct chip_handler_item *item;
+
+ CG2900_INFO("cg2900_register_chip_driver");
+
+ if (!cb) {
+ CG2900_ERR("NULL supplied as cb");
+ return -EINVAL;
+ }
+
+ item = kzalloc(sizeof(*item), GFP_ATOMIC);
+ if (!item) {
+ CG2900_ERR("Failed to alloc memory!");
+ return -ENOMEM;
+ }
+
+ memcpy(&(item->cb), cb, sizeof(cb));
+ list_add_tail(&item->list, &chip_handlers);
+ return 0;
+}
+EXPORT_SYMBOL(cg2900_register_chip_driver);
+
+int cg2900_register_trans_driver(struct cg2900_trans_callbacks *cb, void *data)
+{
+ int err;
+
+ BUG_ON(!core_info);
+
+ CG2900_INFO("cg2900_register_trans_driver");
+
+ if (core_info->trans_info) {
+ CG2900_ERR("trans_info already exists");
+ return -EACCES;
+ }
+
+ core_info->trans_info = kzalloc(sizeof(*(core_info->trans_info)),
+ GFP_KERNEL);
+ if (!core_info->trans_info) {
+ CG2900_ERR("Could not allocate trans_info");
+ return -ENOMEM;
+ }
+
+ memcpy(&(core_info->trans_info->cb), cb, sizeof(*cb));
+ core_info->trans_info->dev.dev = core_info->dev->this_device;
+ core_info->trans_info->dev.user_data = data;
+
+ err = create_work_item(core_info->wq, work_hw_registered, NULL);
+ if (err) {
+ CG2900_ERR("Could not create work item (%d) "
+ "work_hw_registered", err);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(cg2900_register_trans_driver);
+
+int cg2900_deregister_trans_driver(void)
+{
+ BUG_ON(!core_info);
+
+ CG2900_INFO("cg2900_deregister_trans_driver");
+
+ SET_MAIN_STATE(CORE_INITIALIZING);
+ SET_TRANSPORT_STATE(TRANS_INITIALIZING);
+
+ if (!core_info->trans_info)
+ return -EACCES;
+
+ kfree(core_info->trans_info);
+ core_info->trans_info = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(cg2900_deregister_trans_driver);
+
+int cg2900_chip_startup_finished(int err)
+{
+ CG2900_INFO("cg2900_chip_startup_finished (%d)", err);
+
+ if (err)
+ /* Shutdown the chip */
+ chip_shutdown();
+ else
+ SET_MAIN_STATE(CORE_ACTIVE);
+
+ wake_up_interruptible(&main_wait_queue);
+
+ return 0;
+}
+EXPORT_SYMBOL(cg2900_chip_startup_finished);
+
+int cg2900_chip_shutdown_finished(int err)
+{
+ CG2900_INFO("cg2900_chip_shutdown_finished (%d)", err);
+
+ /* Close the transport, which will power off the chip */
+ close_transport();
+
+ /* Chip shut-down finished, set correct state and wake up the chip. */
+ SET_MAIN_STATE(CORE_IDLE);
+ wake_up_interruptible(&main_wait_queue);
+
+ return 0;
+}
+EXPORT_SYMBOL(cg2900_chip_shutdown_finished);
+
+int cg2900_send_to_chip(struct sk_buff *skb, bool use_logger)
+{
+ transmit_skb_to_chip(skb, use_logger);
+ return 0;
+}
+EXPORT_SYMBOL(cg2900_send_to_chip);
+
+struct cg2900_device *cg2900_get_bt_cmd_dev(void)
+{
+ if (core_info)
+ return core_info->users.bt_cmd;
+ else
+ return NULL;
+}
+EXPORT_SYMBOL(cg2900_get_bt_cmd_dev);
+
+struct cg2900_device *cg2900_get_fm_radio_dev(void)
+{
+ if (core_info)
+ return core_info->users.fm_radio;
+ else
+ return NULL;
+}
+EXPORT_SYMBOL(cg2900_get_fm_radio_dev);
+
+struct cg2900_device *cg2900_get_bt_audio_dev(void)
+{
+ if (core_info)
+ return core_info->users.bt_audio;
+ else
+ return NULL;
+}
+EXPORT_SYMBOL(cg2900_get_bt_audio_dev);
+
+struct cg2900_device *cg2900_get_fm_audio_dev(void)
+{
+ if (core_info)
+ return core_info->users.fm_radio_audio;
+ else
+ return NULL;
+}
+EXPORT_SYMBOL(cg2900_get_fm_audio_dev);
+
+struct cg2900_hci_logger_config *cg2900_get_hci_logger_config(void)
+{
+ if (core_info)
+ return &(core_info->hci_logger_config);
+ else
+ return NULL;
+}
+EXPORT_SYMBOL(cg2900_get_hci_logger_config);
+
+unsigned long cg2900_get_sleep_timeout(void)
+{
+ if (CORE_ACTIVE != core_info->main_state || !sleep_timeout_ms)
+ return 0;
+
+ return msecs_to_jiffies(sleep_timeout_ms);
+}
+EXPORT_SYMBOL(cg2900_get_sleep_timeout);
+
+void cg2900_data_from_chip(struct sk_buff *skb)
+{
+ struct cg2900_device *dev = NULL;
+ u8 h4_channel;
+ int err = 0;
+ struct cg2900_chip_callbacks *cb;
+ struct sk_buff *skb_log;
+ struct cg2900_device *logger;
+
+ CG2900_INFO("cg2900_data_from_chip");
+
+ if (!skb) {
+ CG2900_ERR("No data supplied");
+ return;
+ }
+
+ h4_channel = *(skb->data);
+
+ /*
+ * First check if this is the response for something
+ * we have sent internally.
+ */
+ if ((core_info->main_state == CORE_BOOTING ||
+ core_info->main_state == CORE_INITIALIZING) &&
+ (HCI_BT_EVT_H4_CHANNEL == h4_channel) &&
+ handle_rx_data_bt_evt(skb)) {
+ CG2900_DBG("Received packet handled internally");
+ return;
+ }
+
+ /* Find out where to route the data */
+ err = find_h4_user(h4_channel, &dev, skb);
+
+ /* Check if the chip handler wants to deal with the packet. */
+ cb = &(core_info->chip_dev.cb);
+ if (!err && cb->data_from_chip &&
+ cb->data_from_chip(&(core_info->chip_dev), dev, skb))
+ return;
+
+ if (err || !dev) {
+ CG2900_ERR("H:4 channel: 0x%X, does not match device",
+ h4_channel);
+ kfree_skb(skb);
+ return;
+ }
+
+ /*
+ * If HCI logging is enabled for this channel, copy the data to
+ * the HCI logging output.
+ */
+ logger = core_info->users.hci_logger;
+ if (!logger || !dev->logger_enabled)
+ goto transmit;
+
+ /*
+ * Alloc a new sk_buffer and copy the data into it.
+ * Then send it to the HCI logger.
+ */
+ skb_log = alloc_skb(skb->len + 1, GFP_ATOMIC);
+ if (!skb_log) {
+ CG2900_ERR("Couldn't allocate skb_log");
+ goto transmit;
+ }
+
+ memcpy(skb_put(skb_log, skb->len), skb->data, skb->len);
+ skb_log->data[0] = (u8) LOGGER_DIRECTION_RX;
+
+ if (logger->cb->read_cb)
+ logger->cb->read_cb(logger, skb_log);
+
+transmit:
+ /* Remove the H4 header */
+ (void)skb_pull(skb, CG2900_SKB_RESERVE);
+
+ /* Call the Read callback */
+ if (dev->cb->read_cb)
+ dev->cb->read_cb(dev, skb);
+}
+EXPORT_SYMBOL(cg2900_data_from_chip);
+
+/*
+ * Module INIT and EXIT functions
+ */
+
+/**
+ * cg2900_init() - Initialize module.
+ *
+ * The cg2900_init() function initialize the transport and CG2900 Core, then
+ * register to the transport framework.
+ *
+ * Returns:
+ * 0 if success.
+ * -ENOMEM for failed alloc or structure creation.
+ * Error codes generated by cg2900_devices_init, alloc_chrdev_region,
+ * class_create, device_create, core_init, tty_register_ldisc,
+ * create_work_item, cg2900_char_devices_init.
+ */
+static int __init cg2900_init(void)
+{
+ int err;
+
+ CG2900_INFO("cg2900_init");
+
+ err = cg2900_devices_init();
+ if (err) {
+ CG2900_ERR("Couldn't initialize cg2900_devices");
+ return err;
+ }
+
+ core_info = kzalloc(sizeof(*core_info), GFP_KERNEL);
+ if (!core_info) {
+ CG2900_ERR("Couldn't allocate core_info");
+ return -ENOMEM;
+ }
+
+ /* Set the internal states */
+ core_info->main_state = CORE_INITIALIZING;
+ core_info->boot_state = BOOT_NOT_STARTED;
+ core_info->transport_state = TRANS_INITIALIZING;
+
+ /* Get the H4 channel ID for all channels */
+ core_info->h4_channels.bt_cmd_channel = HCI_BT_CMD_H4_CHANNEL;
+ core_info->h4_channels.bt_acl_channel = HCI_BT_ACL_H4_CHANNEL;
+ core_info->h4_channels.bt_evt_channel = HCI_BT_EVT_H4_CHANNEL;
+ core_info->h4_channels.gnss_channel = HCI_FM_RADIO_H4_CHANNEL;
+ core_info->h4_channels.fm_radio_channel = HCI_GNSS_H4_CHANNEL;
+
+ core_info->wq = create_singlethread_workqueue(CORE_WQ_NAME);
+ if (!core_info->wq) {
+ CG2900_ERR("Could not create workqueue");
+ err = -ENOMEM;
+ goto error_handling;
+ }
+
+ core_info->dev = kzalloc(sizeof(*(core_info->dev)), GFP_KERNEL);
+ if (!core_info->dev) {
+ CG2900_ERR("Couldn't allocate main device");
+ err = -ENOMEM;
+ goto error_handling_destroy_wq;
+ }
+
+ /* Prepare miscdevice struct before registering the device */
+ core_info->dev->minor = MISC_DYNAMIC_MINOR;
+ core_info->dev->name = CG2900_DEVICE_NAME;
+
+ err = misc_register(core_info->dev);
+ if (err) {
+ CG2900_ERR("Error %d registering main device!", err);
+ goto error_handling_dev_register;
+ }
+
+ core_info->chip_dev.dev = core_info->dev->this_device;
+
+ /* Create and add test char device. */
+ err = test_char_dev_create();
+ if (err)
+ goto error_handling_deregister;
+
+ /* Initialize the character devices */
+ err = cg2900_char_devices_init(core_info->dev);
+ if (err) {
+ CG2900_ERR("cg2900_char_devices_init failed %d", err);
+ goto error_handling_test_destroy;
+ }
+
+ return 0;
+
+error_handling_test_destroy:
+ test_char_dev_destroy();
+error_handling_deregister:
+ misc_deregister(core_info->dev);
+error_handling_dev_register:
+ kfree(core_info->dev);
+ core_info->dev = NULL;
+error_handling_destroy_wq:
+ destroy_workqueue(core_info->wq);
+error_handling:
+ kfree(core_info);
+ core_info = NULL;
+ return err;
+}
+
+/**
+ * cg2900_exit() - Remove module.
+ */
+static void __exit cg2900_exit(void)
+{
+ CG2900_INFO("cg2900_exit");
+
+ if (!core_info) {
+ CG2900_ERR("CG2900 Core not initiated");
+ return;
+ }
+
+ /* Remove initialized character devices */
+ cg2900_char_devices_exit();
+
+ test_char_dev_destroy();
+
+ /* Free the user devices */
+ free_user_dev(&(core_info->users.bt_cmd));
+ free_user_dev(&(core_info->users.bt_acl));
+ free_user_dev(&(core_info->users.bt_evt));
+ free_user_dev(&(core_info->users.fm_radio));
+ free_user_dev(&(core_info->users.gnss));
+ free_user_dev(&(core_info->users.debug));
+ free_user_dev(&(core_info->users.ste_tools));
+ free_user_dev(&(core_info->users.hci_logger));
+ free_user_dev(&(core_info->users.us_ctrl));
+ free_user_dev(&(core_info->users.core));
+
+ misc_deregister(core_info->dev);
+ kfree(core_info->dev);
+ core_info->dev = NULL;
+
+ destroy_workqueue(core_info->wq);
+
+ kfree(core_info);
+ core_info = NULL;
+
+ cg2900_devices_exit();
+}
+
+module_init(cg2900_init);
+module_exit(cg2900_exit);
+
+module_param(sleep_timeout_ms, int, S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(sleep_timeout_ms,
+ "Sleep timeout for data transmissions:\n"
+ "\t0 = disable <default>\n"
+ "\t>0 = sleep timeout in milliseconds");
+
+module_param(cg2900_debug_level, int, S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(cg2900_debug_level,
+ "Debug level. Default 1. Possible values:\n"
+ "\t0 = No debug\n"
+ "\t1 = Error prints\n"
+ "\t10 = General info, e.g. function entries\n"
+ "\t20 = Debug info, e.g. steps in a functionality\n"
+ "\t25 = Data info, i.e. prints when data is transferred\n"
+ "\t30 = Data content, i.e. contents of the transferred data");
+
+module_param_array(bd_address, byte, &bd_addr_count,
+ S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(bd_address,
+ "Bluetooth Device address. "
+ "Default 0x00 0x80 0xDE 0xAD 0xBE 0xEF. "
+ "Enter as comma separated value.");
+
+module_param(default_hci_revision, int, S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(default_hci_revision,
+ "Default HCI revision according to Bluetooth Assigned "
+ "Numbers.");
+
+module_param(default_manufacturer, int, S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(default_manufacturer,
+ "Default Manufacturer according to Bluetooth Assigned "
+ "Numbers.");
+
+module_param(default_sub_version, int, S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(default_sub_version,
+ "Default HCI sub-version according to Bluetooth Assigned "
+ "Numbers.");
+
+MODULE_AUTHOR("Par-Gunnar Hjalmdahl ST-Ericsson");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Linux Bluetooth HCI H:4 CG2900 Connectivity Device Driver");
diff --git a/drivers/mfd/cg2900/cg2900_core.h b/drivers/mfd/cg2900/cg2900_core.h
new file mode 100644
index 00000000000..dd07305f559
--- /dev/null
+++ b/drivers/mfd/cg2900/cg2900_core.h
@@ -0,0 +1,303 @@
+/*
+ * drivers/mfd/cg2900/cg2900_core.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth HCI H:4 Driver for ST-Ericsson CG2900 GPS/BT/FM controller.
+ */
+
+#ifndef _CG2900_CORE_H_
+#define _CG2900_CORE_H_
+
+#include <linux/skbuff.h>
+#include <linux/device.h>
+
+/* Reserve 1 byte for the HCI H:4 header */
+#define CG2900_SKB_RESERVE 1
+
+#define BT_BDADDR_SIZE 6
+
+struct cg2900_h4_channels {
+ int bt_cmd_channel;
+ int bt_acl_channel;
+ int bt_evt_channel;
+ int gnss_channel;
+ int fm_radio_channel;
+ int debug_channel;
+ int ste_tools_channel;
+ int hci_logger_channel;
+ int us_ctrl_channel;
+ int core_channel;
+};
+
+/**
+ * struct cg2900_hci_logger_config - Configures the HCI logger.
+ * @bt_cmd_enable: Enable BT command logging.
+ * @bt_acl_enable: Enable BT ACL logging.
+ * @bt_evt_enable: Enable BT event logging.
+ * @gnss_enable: Enable GNSS logging.
+ * @fm_radio_enable: Enable FM radio logging.
+ * @bt_audio_enable: Enable BT audio command logging.
+ * @fm_radio_audio_enable: Enable FM radio audio command logging.
+ *
+ * Set using cg2900_write on CHANNEL_HCI_LOGGER H4 channel.
+ */
+struct cg2900_hci_logger_config {
+ bool bt_cmd_enable;
+ bool bt_acl_enable;
+ bool bt_evt_enable;
+ bool gnss_enable;
+ bool fm_radio_enable;
+ bool bt_audio_enable;
+ bool fm_radio_audio_enable;
+};
+
+/**
+ * struct cg2900_chip_info - Chip info structure.
+ * @manufacturer: Chip manufacturer.
+ * @hci_revision: Chip revision, i.e. which chip is this.
+ * @hci_sub_version: Chip sub-version, i.e. which tape-out is this.
+ *
+ * Note that these values match the Bluetooth Assigned Numbers,
+ * see http://www.bluetooth.org/
+ */
+struct cg2900_chip_info {
+ int manufacturer;
+ int hci_revision;
+ int hci_sub_version;
+};
+
+struct cg2900_chip_dev;
+
+/**
+ * struct cg2900_chip_callbacks - Callback functions registered by chip handler.
+ * @chip_startup: Called when chip is started up.
+ * @chip_shutdown: Called when chip is shut down.
+ * @data_to_chip: Called when data shall be transmitted to chip.
+ * Return true when CG2900 Core shall not send it
+ * to chip.
+ * @data_from_chip: Called when data shall be transmitted to user.
+ * Return true when packet is taken care of by
+ * Return chip return handler.
+ * @get_h4_channel: Connects channel name with H:4 channel number.
+ * @is_bt_audio_user: Return true if current packet is for
+ * the BT audio user.
+ * @is_fm_audio_user: Return true if current packet is for
+ * the FM audio user.
+ * @last_bt_user_removed: Last BT channel user has been removed.
+ * @last_fm_user_removed: Last FM channel user has been removed.
+ * @last_gnss_user_removed: Last GNSS channel user has been removed.
+ *
+ * Note that some callbacks may be NULL. They must always be NULL checked before
+ * calling.
+ */
+struct cg2900_chip_callbacks {
+ int (*chip_startup)(struct cg2900_chip_dev *dev);
+ int (*chip_shutdown)(struct cg2900_chip_dev *dev);
+ bool (*data_to_chip)(struct cg2900_chip_dev *dev,
+ struct cg2900_device *cg2900_dev,
+ struct sk_buff *skb);
+ bool (*data_from_chip)(struct cg2900_chip_dev *dev,
+ struct cg2900_device *cg2900_dev,
+ struct sk_buff *skb);
+ int (*get_h4_channel)(char *name, int *h4_channel);
+ bool (*is_bt_audio_user)(int h4_channel,
+ const struct sk_buff * const skb);
+ bool (*is_fm_audio_user)(int h4_channel,
+ const struct sk_buff * const skb);
+ void (*last_bt_user_removed)(struct cg2900_chip_dev *dev);
+ void (*last_fm_user_removed)(struct cg2900_chip_dev *dev);
+ void (*last_gnss_user_removed)(struct cg2900_chip_dev *dev);
+};
+
+/**
+ * struct cg2900_chip_dev - Chip handler info structure.
+ * @dev: Parent device from CG2900 Core.
+ * @chip: Chip info such as manufacturer.
+ * @cb: Callback structure for the chip handler.
+ * @user_data: Arbitrary data set by chip handler.
+ */
+struct cg2900_chip_dev {
+ struct device *dev;
+ struct cg2900_chip_info chip;
+ struct cg2900_chip_callbacks cb;
+ void *user_data;
+};
+
+/**
+ * struct cg2900_id_callbacks - Chip handler identification callbacks.
+ * @check_chip_support: Called when chip is connected. If chip is supported by
+ * driver, return true and fill in @callbacks in @dev.
+ *
+ * Note that the callback may be NULL. It must always be NULL checked before
+ * calling.
+ */
+struct cg2900_id_callbacks {
+ bool (*check_chip_support)(struct cg2900_chip_dev *dev);
+};
+
+/**
+ * struct cg2900_trans_dev - CG2900 transport info structure.
+ * @dev: Parent device from CG2900 Core.
+ * @user_data: Arbitrary data set by chip handler.
+ */
+struct cg2900_trans_dev {
+ struct device *dev;
+ void *user_data;
+};
+
+/**
+ * struct cg2900_trans_callbacks - Callback functions registered by transport.
+ * @open: CG2900 Core needs a transport.
+ * @close: CG2900 Core does not need a transport.
+ * @write: CG2900 Core transmits to the chip.
+ * @set_chip_power: CG2900 Core enables or disables the chip.
+ *
+ * Note that some callbacks may be NULL. They must always be NULL checked before
+ * calling.
+ */
+struct cg2900_trans_callbacks {
+ int (*open)(struct cg2900_trans_dev *dev);
+ int (*close)(struct cg2900_trans_dev *dev);
+ int (*write)(struct cg2900_trans_dev *dev, struct sk_buff *skb);
+ void (*set_chip_power)(bool chip_on);
+};
+
+/**
+ * cg2900_register_chip_driver() - Register a chip handler.
+ * @cb: Callbacks to call when chip is connected.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL if NULL is supplied as @cb.
+ * -ENOMEM if allocation fails or work queue can't be created.
+ */
+extern int cg2900_register_chip_driver(struct cg2900_id_callbacks *cb);
+
+/**
+ * cg2900_register_trans_driver() - Register a transport driver.
+ * @cb: Callbacks to call when chip is connected.
+ * @data: Arbitrary data used by the transport driver.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL if NULL is supplied as @cb.
+ * -ENOMEM if allocation fails or work queue can't be created.
+ */
+extern int cg2900_register_trans_driver(struct cg2900_trans_callbacks *cb,
+ void *data);
+
+/**
+ * cg2900_deregister_trans_driver() - Deregister a transport driver.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL if NULL is supplied as @cb.
+ * -ENOMEM if allocation fails or work queue can't be created.
+ */
+extern int cg2900_deregister_trans_driver(void);
+
+/**
+ * cg2900_chip_startup_finished() - Called from chip handler when start-up is finished.
+ * @err: Result of the start-up.
+ *
+ * Returns:
+ * 0 if there is no error.
+ */
+extern int cg2900_chip_startup_finished(int err);
+
+/**
+ * cg2900_chip_shutdown_finished() - Called from chip handler when shutdown is finished.
+ * @err: Result of the shutdown.
+ *
+ * Returns:
+ * 0 if there is no error.
+ */
+extern int cg2900_chip_shutdown_finished(int err);
+
+/**
+ * cg2900_send_to_chip() - Send data to chip.
+ * @skb: Packet to transmit.
+ * @use_logger: true if hci_logger should copy data content.
+ *
+ * Returns:
+ * 0 if there is no error.
+ */
+extern int cg2900_send_to_chip(struct sk_buff *skb, bool use_logger);
+
+/**
+ * cg2900_get_bt_cmd_dev() - Return user of the BT command H:4 channel.
+ *
+ * Returns:
+ * User of the BT command H:4 channel.
+ * NULL if no user is registered.
+ */
+extern struct cg2900_device *cg2900_get_bt_cmd_dev(void);
+
+/**
+ * cg2900_get_fm_radio_dev() - Return user of the FM radio H:4 channel.
+ *
+ * Returns:
+ * User of the FM radio H:4 channel.
+ * NULL if no user is registered.
+ */
+extern struct cg2900_device *cg2900_get_fm_radio_dev(void);
+
+/**
+ * cg2900_get_bt_audio_dev() - Return user of the BT audio H:4 channel.
+ *
+ * Returns:
+ * User of the BT audio H:4 channel.
+ * NULL if no user is registered.
+ */
+extern struct cg2900_device *cg2900_get_bt_audio_dev(void);
+
+/**
+ * cg2900_get_fm_audio_dev() - Return user of the FM audio H:4 channel.
+ *
+ * Returns:
+ * User of the FM audio H:4 channel.
+ * NULL if no user is registered.
+ */
+extern struct cg2900_device *cg2900_get_fm_audio_dev(void);
+
+/**
+ * cg2900_get_hci_logger_config() - Return HCI Logger configuration.
+ *
+ * Returns:
+ * HCI logger configuration.
+ * NULL if CG2900 Core has not yet been started.
+ */
+extern struct cg2900_hci_logger_config *cg2900_get_hci_logger_config(void);
+
+/**
+ * cg2900_get_sleep_timeout() - Return sleep timeout in jiffies.
+ *
+ * Returns:
+ * Sleep timeout in jiffies. 0 means that sleep timeout shall not be used.
+ */
+extern unsigned long cg2900_get_sleep_timeout(void);
+
+/**
+ * cg2900_data_from_chip() - Data received from connectivity controller.
+ * @skb: Data packet
+ *
+ * The cg2900_data_from_chip() function checks which channel
+ * the data was received on and send to the right user.
+ */
+extern void cg2900_data_from_chip(struct sk_buff *skb);
+
+/* module_param declared in cg2900_core.c */
+extern u8 bd_address[BT_BDADDR_SIZE];
+extern int default_manufacturer;
+extern int default_hci_revision;
+extern int default_sub_version;
+
+#endif /* _CG2900_CORE_H_ */
diff --git a/drivers/mfd/cg2900/cg2900_debug.h b/drivers/mfd/cg2900/cg2900_debug.h
new file mode 100644
index 00000000000..a3aeeaf7a93
--- /dev/null
+++ b/drivers/mfd/cg2900/cg2900_debug.h
@@ -0,0 +1,77 @@
+/*
+ * drivers/mfd/cg2900/cg2900_debug.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Debug functionality for the Linux Bluetooth HCI H:4 Driver for ST-Ericsson
+ * CG2900 connectivity controller.
+ */
+
+#ifndef _CG2900_DEBUG_H_
+#define _CG2900_DEBUG_H_
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#define CG2900_DEFAULT_DEBUG_LEVEL 1
+
+/* module_param declared in cg2900_core.c */
+extern int cg2900_debug_level;
+
+#if defined(NDEBUG) || CG2900_DEFAULT_DEBUG_LEVEL == 0
+ #define CG2900_DBG_DATA_CONTENT(fmt, arg...)
+ #define CG2900_DBG_DATA(fmt, arg...)
+ #define CG2900_DBG(fmt, arg...)
+ #define CG2900_INFO(fmt, arg...)
+ #define CG2900_ERR(fmt, arg...)
+#else
+ #define CG2900_DBG_DATA_CONTENT(fmt, arg...) \
+ do { \
+ if (cg2900_debug_level >= 30) \
+ printk(KERN_DEBUG "CG2900 %s: " fmt "\n" , __func__ , \
+ ## arg); \
+ } while (0)
+
+ #define CG2900_DBG_DATA(fmt, arg...) \
+ do { \
+ if (cg2900_debug_level >= 25) \
+ printk(KERN_DEBUG "CG2900 %s: " fmt "\n" , __func__ , \
+ ## arg); \
+ } while (0)
+
+ #define CG2900_DBG(fmt, arg...) \
+ do { \
+ if (cg2900_debug_level >= 20) \
+ printk(KERN_DEBUG "CG2900 %s: " fmt "\n" , __func__ , \
+ ## arg); \
+ } while (0)
+
+ #define CG2900_INFO(fmt, arg...) \
+ do { \
+ if (cg2900_debug_level >= 10) \
+ printk(KERN_INFO "CG2900: " fmt "\n" , ## arg); \
+ } while (0)
+
+ #define CG2900_ERR(fmt, arg...) \
+ do { \
+ if (cg2900_debug_level >= 1) \
+ printk(KERN_ERR "CG2900 %s: " fmt "\n" , __func__ , \
+ ## arg); \
+ } while (0)
+
+#endif /* NDEBUG */
+
+#define CG2900_SET_STATE(__name, __var, __new_state) \
+do { \
+ CG2900_DBG("New %s: 0x%X", __name, (uint32_t)__new_state); \
+ __var = __new_state; \
+} while (0)
+
+#endif /* _CG2900_DEBUG_H_ */
diff --git a/drivers/mfd/cg2900/cg2900_uart.c b/drivers/mfd/cg2900/cg2900_uart.c
new file mode 100644
index 00000000000..8fe33f0a210
--- /dev/null
+++ b/drivers/mfd/cg2900/cg2900_uart.c
@@ -0,0 +1,1587 @@
+/*
+ * drivers/mfd/cg2900/cg2900_uart.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth UART Driver for ST-Ericsson CG2900 connectivity controller.
+ */
+
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/skbuff.h>
+#include <linux/pm.h>
+#include <linux/gpio.h>
+#include <linux/tty.h>
+#include <linux/tty_ldisc.h>
+#include <linux/poll.h>
+#include <linux/timer.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <asm/byteorder.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+
+#include <linux/mfd/cg2900.h>
+#include <mach/cg2900_devices.h>
+#include "cg2900_core.h"
+#include "cg2900_chip.h"
+#include "cg2900_debug.h"
+#include "hci_defines.h"
+
+/* Workqueues' names */
+#define UART_WQ_NAME "cg2900_uart_wq"
+
+/* Standardized Bluetooth command channels */
+#define HCI_BT_CMD_H4_CHANNEL 0x01
+#define HCI_BT_ACL_H4_CHANNEL 0x02
+#define HCI_BT_EVT_H4_CHANNEL 0x04
+
+/* H4 channels specific for CG2900 */
+#define HCI_FM_RADIO_H4_CHANNEL 0x08
+#define HCI_GNSS_H4_CHANNEL 0x09
+
+/* Timers used in milliseconds */
+#define UART_TX_TIMEOUT 100
+#define UART_RESP_TIMEOUT 1000
+
+/* State-setting defines */
+#define SET_BAUD_STATE(__new_state) \
+ CG2900_SET_STATE("baud_rate_state", uart_info->baud_rate_state, \
+ __new_state)
+#define SET_SLEEP_STATE(__new_state) \
+ CG2900_SET_STATE("sleep_state", uart_info->sleep_state, __new_state)
+
+/* Number of bytes to reserve at start of sk_buffer when receiving packet */
+#define RX_SKB_RESERVE 8
+/* Max size of received packet (not including reserved bytes) */
+#define RX_SKB_MAX_SIZE 1024
+
+/* Max size of bytes we can receive on the UART */
+#define UART_RECEIVE_ROOM 65536
+
+/* Size of the header in the different packets */
+#define HCI_BT_EVT_HDR_SIZE 2
+#define HCI_BT_ACL_HDR_SIZE 4
+#define HCI_FM_RADIO_HDR_SIZE 1
+#define HCI_GNSS_HDR_SIZE 3
+
+/* Position of length field in the different packets */
+#define HCI_EVT_LEN_POS 2
+#define HCI_ACL_LEN_POS 3
+#define FM_RADIO_LEN_POS 1
+#define GNSS_LEN_POS 2
+
+/* Bytes in the command Hci_Cmd_ST_Set_Uart_Baud_Rate */
+#define SET_BAUD_RATE_LSB 0x09
+#define SET_BAUD_RATE_MSB 0xFC
+#define SET_BAUD_RATE_PAYL_LEN 0x01
+#define SET_BAUD_RATE_LEN 0x04
+#define BAUD_RATE_57600 0x03
+#define BAUD_RATE_115200 0x02
+#define BAUD_RATE_230400 0x01
+#define BAUD_RATE_460800 0x00
+#define BAUD_RATE_921600 0x20
+#define BAUD_RATE_2000000 0x25
+#define BAUD_RATE_3000000 0x27
+#define BAUD_RATE_4000000 0x2B
+
+/* Baud rate defines */
+#define ZERO_BAUD_RATE 0
+#define DEFAULT_BAUD_RATE 115200
+#define HIGH_BAUD_RATE 3000000
+
+/* HCI TTY line discipline value */
+#ifndef N_HCI
+#define N_HCI 15
+#endif
+
+/* IOCTLs for UART */
+#define HCIUARTSETPROTO _IOW('U', 200, int)
+#define HCIUARTGETPROTO _IOR('U', 201, int)
+#define HCIUARTGETDEVICE _IOR('U', 202, int)
+#define HCIUARTSETFD _IOW('U', 203, int)
+
+
+/* UART break control parameters */
+#define TTY_BREAK_ON (-1)
+#define TTY_BREAK_OFF (0)
+
+/**
+ * enum uart_rx_state - UART RX-state for UART.
+ * @W4_PACKET_TYPE: Waiting for packet type.
+ * @W4_EVENT_HDR: Waiting for BT event header.
+ * @W4_ACL_HDR: Waiting for BT ACL header.
+ * @W4_FM_RADIO_HDR: Waiting for FM header.
+ * @W4_GNSS_HDR: Waiting for GNSS header.
+ * @W4_DATA: Waiting for data in rest of the packet (after header).
+ */
+enum uart_rx_state {
+ W4_PACKET_TYPE,
+ W4_EVENT_HDR,
+ W4_ACL_HDR,
+ W4_FM_RADIO_HDR,
+ W4_GNSS_HDR,
+ W4_DATA
+};
+
+/**
+ * enum sleep_state - Sleep-state for UART.
+ * @CHIP_AWAKE: Chip is awake.
+ * @CHIP_FALLING_ASLEEP: Chip is falling asleep.
+ * @CHIP_ASLEEP: Chip is asleep.
+ */
+enum sleep_state {
+ CHIP_AWAKE,
+ CHIP_FALLING_ASLEEP,
+ CHIP_ASLEEP
+};
+
+/**
+ * enum baud_rate_change_state - Baud rate-state for UART.
+ * @BAUD_IDLE: No baud rate change is ongoing.
+ * @BAUD_SENDING_RESET: HCI reset has been sent. Waiting for command complete
+ * event.
+ * @BAUD_START: Set baud rate cmd scheduled for sending.
+ * @BAUD_SENDING: Set baud rate cmd sending in progress.
+ * @BAUD_WAITING: Set baud rate cmd sent, waiting for command complete
+ * event.
+ * @BAUD_SUCCESS: Baud rate change has succeeded.
+ * @BAUD_FAIL: Baud rate change has failed.
+ */
+enum baud_rate_change_state {
+ BAUD_IDLE,
+ BAUD_SENDING_RESET,
+ BAUD_START,
+ BAUD_SENDING,
+ BAUD_WAITING,
+ BAUD_SUCCESS,
+ BAUD_FAIL
+};
+
+/**
+ * struct uart_work_struct - Work structure for UART module.
+ * @work: Work structure.
+ * @data: Pointer to private data.
+ *
+ * This structure is used to pack work for work queue.
+ */
+struct uart_work_struct{
+ struct work_struct work;
+ void *data;
+};
+
+/**
+ * struct test_char_dev_info - Main UART info structure.
+ * @wq: UART work queue.
+ * @tx_queue: TX queue for sending data to chip.
+ * @tty: TTY info structure.
+ * @rx_lock: RX spin lock.
+ * @rx_state: Current RX state.
+ * @rx_count: Number of bytes left to receive.
+ * @rx_skb: SK_buffer to store the received data into.
+ * @tx_mutex: TX mutex.
+ * @baud_rate_state: UART baud rate change state.
+ * @baud_rate: Current baud rate setting.
+ * @sleep_state: UART sleep state.
+ * @timer: UART timer (for chip sleep).
+ * @fd: File object to device.
+ * @sleep_state_lock: Used to protect chip state.
+ * @sleep_allowed: Indicate if tty has functions needed for sleep mode.
+ */
+struct uart_info {
+ struct workqueue_struct *wq;
+ struct sk_buff_head tx_queue;
+ struct tty_struct *tty;
+ spinlock_t rx_lock;
+ enum uart_rx_state rx_state;
+ unsigned long rx_count;
+ struct sk_buff *rx_skb;
+ struct mutex tx_mutex;
+ enum baud_rate_change_state baud_rate_state;
+ int baud_rate;
+ enum sleep_state sleep_state;
+ struct timer_list timer;
+ struct file *fd;
+ struct mutex sleep_state_lock;
+ bool sleep_allowed;
+};
+
+static struct uart_info *uart_info;
+
+/* Module parameters */
+static int uart_default_baud = DEFAULT_BAUD_RATE;
+static int uart_high_baud = HIGH_BAUD_RATE;
+
+static DECLARE_WAIT_QUEUE_HEAD(uart_wait_queue);
+
+/**
+ * is_chip_flow_off() - Check if chip has set flow off.
+ * @tty: Pointer to tty.
+ *
+ * Returns:
+ * true - chip flows off.
+ * false - chip flows on.
+ */
+static bool is_chip_flow_off(struct tty_struct *tty)
+{
+ int lines;
+
+ lines = tty->ops->tiocmget(tty, uart_info->fd);
+
+ if (lines & TIOCM_CTS)
+ return false;
+ else
+ return true;
+}
+
+/**
+ * set_tty_baud() - Called to set specific baud in TTY.
+ * @tty: Tty device.
+ * @baud: Baud to set.
+ *
+ * Returns:
+ * true - baudrate set with success.
+ * false - baundrate set failure.
+ */
+static bool set_tty_baud(struct tty_struct *tty, int baud)
+{
+ struct ktermios *old_termios;
+ bool retval = true;
+
+ old_termios = kmalloc(sizeof(*old_termios), GFP_ATOMIC);
+ if (!old_termios) {
+ CG2900_ERR("Could not allocate termios");
+ return false;
+ }
+
+ mutex_lock(&(tty->termios_mutex));
+ /* Start by storing the old termios. */
+ memcpy(old_termios, tty->termios, sizeof(*old_termios));
+
+ /* Let's mark that CG2900 driver uses c_ispeed and c_ospeed fields. */
+ tty->termios->c_cflag |= BOTHER;
+
+ tty_encode_baud_rate(tty, baud, baud);
+
+ /* Finally inform the driver */
+ if (tty->ops->set_termios)
+ tty->ops->set_termios(tty, old_termios);
+ else {
+ CG2900_ERR("Can not set new baudrate.");
+ /* Copy back the old termios to restore old setting. */
+ memcpy(tty->termios, old_termios, sizeof(*old_termios));
+ retval = false;
+ }
+
+ tty->termios->c_cflag &= ~BOTHER;
+
+ mutex_unlock(&(tty->termios_mutex));
+ kfree(old_termios);
+
+ return retval;
+}
+
+/**
+ * update_timer() - Updates or starts the sleep timer.
+ *
+ * Updates or starts the sleep timer used to detect when there are no current
+ * data transmissions.
+ */
+static void update_timer(void)
+{
+ unsigned long timeout_jiffies = cg2900_get_sleep_timeout();
+ struct tty_struct *tty;
+
+ if (!timeout_jiffies || !uart_info->fd || !uart_info->sleep_allowed)
+ return;
+
+ mutex_lock(&(uart_info->sleep_state_lock));
+ /*
+ * This function indicates data is transmitted.
+ * Therefore see to that the chip is awake.
+ */
+ if (CHIP_AWAKE == uart_info->sleep_state)
+ goto finished;
+
+ tty = uart_info->tty;
+
+ if (CHIP_ASLEEP == uart_info->sleep_state) {
+ /* Disable IRQ only when it was enabled. */
+ cg2900_devices_unset_cts_irq();
+ (void)set_tty_baud(tty, uart_info->baud_rate);
+ }
+ /* Set FLOW on. */
+ tty_unthrottle(tty);
+
+ /* Unset BREAK. */
+
+ tty->ops->break_ctl(tty, TTY_BREAK_OFF);
+
+ SET_SLEEP_STATE(CHIP_AWAKE);
+
+finished:
+ mutex_unlock(&(uart_info->sleep_state_lock));
+ /*
+ * If timer is running restart it. If not, start it.
+ * All this is handled by mod_timer().
+ */
+ mod_timer(&(uart_info->timer), jiffies + timeout_jiffies);
+}
+
+/**
+ * sleep_timer_expired() - Called when sleep timer expires.
+ * @data: Value supplied when starting the timer.
+ *
+ * The sleep_timer_expired() function is called if there are no ongoing data
+ * transmissions. It tries to put the chip in sleep mode.
+ *
+ */
+static void sleep_timer_expired(unsigned long data)
+{
+ unsigned long timeout_jiffies = cg2900_get_sleep_timeout();
+ struct tty_struct *tty;
+
+ if (!timeout_jiffies || !uart_info->sleep_allowed || !uart_info->fd)
+ return;
+
+ mutex_lock(&(uart_info->sleep_state_lock));
+
+ tty = uart_info->tty;
+
+ switch (uart_info->sleep_state) {
+ case CHIP_FALLING_ASLEEP:
+ if (!is_chip_flow_off(tty))
+ goto run_timer;
+
+ /* Flow OFF. */
+ tty_throttle(tty);
+
+ /*
+ * Set baud zero.
+ * This cause shut off UART clock as well.
+ */
+ (void)set_tty_baud(tty, ZERO_BAUD_RATE);
+
+ if (cg2900_devices_set_cts_irq() < 0) {
+ CG2900_ERR("Can not set intterupt on CTS.");
+ (void)set_tty_baud(tty, uart_info->baud_rate);
+ tty_unthrottle(tty);
+ SET_SLEEP_STATE(CHIP_AWAKE);
+ goto error;
+ }
+ SET_SLEEP_STATE(CHIP_ASLEEP);
+ break;
+ case CHIP_AWAKE:
+
+ tty->ops->break_ctl(tty, TTY_BREAK_ON);
+
+ SET_SLEEP_STATE(CHIP_FALLING_ASLEEP);
+ goto run_timer;
+
+ case CHIP_ASLEEP: /* Fallthrough. */
+ default:
+ CG2900_ERR("Chip already sleeps.");
+ break;
+ }
+
+ mutex_unlock(&(uart_info->sleep_state_lock));
+
+ return;
+
+run_timer:
+ mutex_unlock(&(uart_info->sleep_state_lock));
+ mod_timer(&(uart_info->timer), jiffies + timeout_jiffies);
+ return;
+error:
+ /* Disable sleep mode.*/
+ CG2900_ERR("Disable sleep mode.");
+ uart_info->sleep_allowed = false;
+ uart_info->fd = NULL;
+ mutex_unlock(&(uart_info->sleep_state_lock));
+}
+
+/**
+ * is_set_baud_rate_cmd() - Checks if data contains set baud rate hci cmd.
+ * @data: Pointer to data array to check.
+ *
+ * Returns:
+ * true - if cmd found;
+ * false - otherwise.
+ */
+static bool is_set_baud_rate_cmd(const char *data)
+{
+ bool cmd_match = false;
+
+ if ((data[0] == HCI_BT_CMD_H4_CHANNEL) &&
+ (data[1] == SET_BAUD_RATE_LSB) &&
+ (data[2] == SET_BAUD_RATE_MSB) &&
+ (data[3] == SET_BAUD_RATE_PAYL_LEN)) {
+ cmd_match = true;
+ }
+ return cmd_match;
+}
+
+/**
+ * is_bt_cmd_complete_no_param() - Checks if data contains command complete event for a certain command.
+ * @skb: sk_buffer containing the data including H:4 header.
+ * @cmd_lsb: Command LSB.
+ * @cmd_msb: Command MSB.
+ *
+ * Returns:
+ * true - If this is the command complete we were looking for;
+ * false - otherwise.
+ */
+static bool is_bt_cmd_complete_no_param(struct sk_buff *skb, u8 cmd_lsb,
+ u8 cmd_msb)
+{
+ if ((HCI_BT_EVT_H4_CHANNEL == skb->data[0]) &&
+ (HCI_BT_EVT_CMD_COMPLETE == skb->data[1]) &&
+ (HCI_BT_CMD_COMPLETE_NO_PARAM_LEN == skb->data[2]) &&
+ (cmd_lsb == skb->data[4]) &&
+ (cmd_msb == skb->data[5]))
+ return true;
+
+ return false;
+}
+
+/**
+ * alloc_rx_skb() - Alloc an sk_buff structure for receiving data from controller.
+ * @size: Size in number of octets.
+ * @priority: Allocation priority, e.g. GFP_KERNEL.
+ *
+ * Returns:
+ * Pointer to sk_buff structure.
+ */
+static struct sk_buff *alloc_rx_skb(unsigned int size, gfp_t priority)
+{
+ struct sk_buff *skb;
+
+ /* Allocate the SKB and reserve space for the header */
+ skb = alloc_skb(size + RX_SKB_RESERVE, priority);
+ if (skb)
+ skb_reserve(skb, RX_SKB_RESERVE);
+
+ return skb;
+}
+
+/**
+ * create_work_item() - Create work item and add it to the work queue.
+ * @wq: work queue struct where the work will be added.
+ * @work_func: Work function.
+ * @data: Private data for the work.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EBUSY if not possible to queue work.
+ * -ENOMEM if allocation fails.
+ */
+static int create_work_item(struct workqueue_struct *wq, work_func_t work_func,
+ void *data)
+{
+ struct uart_work_struct *new_work;
+ int err;
+
+ new_work = kmalloc(sizeof(*new_work), GFP_ATOMIC);
+ if (!new_work) {
+ CG2900_ERR("Failed to alloc memory for uart_work_struct!");
+ return -ENOMEM;
+ }
+
+ new_work->data = data;
+ INIT_WORK(&new_work->work, work_func);
+
+ err = queue_work(wq, &new_work->work);
+ if (!err) {
+ CG2900_ERR("Failed to queue work_struct because it's already "
+ "in the queue!");
+ kfree(new_work);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/**
+ * handle_cts_irq() - Called to interrupt.
+ * @work: work which needs to be done.
+ *
+ * The handle_cts_irq() function is called if interrupt on
+ * CTS occurred.
+ *
+ */
+static void handle_cts_irq(struct work_struct *work)
+{
+ /* Restart timer and disabale interrupt. */
+ update_timer();
+}
+
+/**
+ * cg2900_devices_irq_cb() - Called from ste_conn_devices.
+ *
+ * The cg2900_devices_irq_cb() function is called if interrupt on CTS occurred.
+ *
+ */
+static void cg2900_devices_irq_cb(void)
+{
+ /* Create work and leave irq context. */
+ (void)create_work_item(uart_info->wq, handle_cts_irq, NULL);
+}
+
+/*
+ * struct uart_cg2900_dev_cb - Interrupt callback.
+ * @interrupt_cb: Called when interrupt on CTS occurred.
+ */
+static struct cg2900_devices_cb uart_cg2900_dev_cb = {
+ .interrupt_cb = cg2900_devices_irq_cb
+};
+
+/**
+ * finish_setting_baud_rate() - Handles sending the ste baud rate hci cmd.
+ * @tty: Pointer to a tty_struct used to communicate with tty driver.
+ *
+ * finish_setting_baud_rate() makes sure that the set baud rate cmd has
+ * been really sent out on the wire and then switches the tty driver to new
+ * baud rate.
+ */
+static void finish_setting_baud_rate(struct tty_struct *tty)
+{
+ /*
+ * Give the tty driver time to send data and proceed. If it hasn't
+ * been sent we can't do much about it anyway.
+ */
+ schedule_timeout_interruptible(msecs_to_jiffies(UART_TX_TIMEOUT));
+
+ /*
+ * Now set the termios struct to the new baudrate. Start by storing
+ * the old termios.
+ */
+ if (set_tty_baud(tty, uart_info->baud_rate)) {
+ CG2900_DBG("Setting termios to new baud rate");
+ SET_BAUD_STATE(BAUD_WAITING);
+ } else
+ SET_BAUD_STATE(BAUD_IDLE);
+}
+
+/**
+ * alloc_set_baud_rate_cmd() - Allocates new sk_buff and fills in the change baud rate hci cmd.
+ * @baud: (in/out) Requested new baud rate. Updated to default baud rate
+ * upon invalid value.
+ *
+ * Returns:
+ * Pointer to allocated sk_buff if successful;
+ * NULL otherwise.
+ */
+static struct sk_buff *alloc_set_baud_rate_cmd(int *baud)
+{
+ struct sk_buff *skb;
+ u8 data[SET_BAUD_RATE_LEN];
+ u8 *h4;
+
+ skb = cg2900_alloc_skb(SET_BAUD_RATE_LEN, GFP_ATOMIC);
+ if (!skb) {
+ CG2900_ERR("Failed to alloc skb!");
+ return NULL;
+ }
+
+ /* Create the Hci_Cmd_ST_Set_Uart_Baud_Rate packet */
+ data[0] = SET_BAUD_RATE_LSB;
+ data[1] = SET_BAUD_RATE_MSB;
+ data[2] = SET_BAUD_RATE_PAYL_LEN;
+
+ switch (*baud) {
+ case 57600:
+ data[3] = BAUD_RATE_57600;
+ break;
+ case 115200:
+ data[3] = BAUD_RATE_115200;
+ break;
+ case 230400:
+ data[3] = BAUD_RATE_230400;
+ break;
+ case 460800:
+ data[3] = BAUD_RATE_460800;
+ break;
+ case 921600:
+ data[3] = BAUD_RATE_921600;
+ break;
+ case 2000000:
+ data[3] = BAUD_RATE_2000000;
+ break;
+ case 3000000:
+ data[3] = BAUD_RATE_3000000;
+ break;
+ case 4000000:
+ data[3] = BAUD_RATE_4000000;
+ break;
+ default:
+ CG2900_ERR("Invalid speed requested (%d), using 115200 bps "
+ "instead\n", *baud);
+ data[3] = BAUD_RATE_115200;
+ *baud = 115200;
+ break;
+ };
+
+ memcpy(skb_put(skb, SET_BAUD_RATE_LEN), data, SET_BAUD_RATE_LEN);
+ h4 = skb_push(skb, HCI_H4_SIZE);
+ *h4 = HCI_BT_CMD_H4_CHANNEL;
+
+ return skb;
+}
+
+/**
+ * work_do_transmit() - Transmit data packet to connectivity controller over UART.
+ * @work: Pointer to work info structure. Contains uart_info structure
+ * pointer.
+ */
+static void work_do_transmit(struct work_struct *work)
+{
+ struct sk_buff *skb;
+ struct tty_struct *tty;
+ struct uart_work_struct *current_work;
+
+ if (!work) {
+ CG2900_ERR("work == NULL");
+ return;
+ }
+
+ /* Restart timer. */
+ update_timer();
+
+ current_work = container_of(work, struct uart_work_struct, work);
+
+ if (uart_info->tty)
+ tty = uart_info->tty;
+ else {
+ CG2900_ERR("Important structs not allocated!");
+ goto finished;
+ }
+
+ mutex_lock(&uart_info->tx_mutex);
+
+ /* Retrieve the first packet in the queue */
+ skb = skb_dequeue(&uart_info->tx_queue);
+ while (skb) {
+ int len;
+
+ /*
+ * Tell TTY that there is data waiting and call the write
+ * function.
+ */
+ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ len = tty->ops->write(tty, skb->data, skb->len);
+ CG2900_INFO("Written %d bytes to UART of %d bytes in packet",
+ len, skb->len);
+
+ /*
+ * If it's set baud rate cmd set correct baud state and after
+ * sending is finished inform the tty driver about the new
+ * baud rate.
+ */
+ if ((BAUD_START == uart_info->baud_rate_state) &&
+ (is_set_baud_rate_cmd(skb->data))) {
+ CG2900_INFO("UART set baud rate cmd found.");
+ SET_BAUD_STATE(BAUD_SENDING);
+ }
+
+ /* Remove the bytes written from the sk_buffer */
+ skb_pull(skb, len);
+
+ /*
+ * If there is more data in this sk_buffer, put it at the start
+ * of the list and exit the loop
+ */
+ if (skb->len) {
+ skb_queue_head(&uart_info->tx_queue, skb);
+ break;
+ }
+ /*
+ * No more data in the sk_buffer. Free it and get next packet in
+ * queue.
+ * Check if set baud rate cmd is in sending progress, if so call
+ * proper function to handle that cmd since it requires special
+ * attention.
+ */
+ if (BAUD_SENDING == uart_info->baud_rate_state)
+ finish_setting_baud_rate(tty);
+
+ kfree_skb(skb);
+ skb = skb_dequeue(&uart_info->tx_queue);
+ }
+
+ mutex_unlock(&uart_info->tx_mutex);
+
+finished:
+ kfree(current_work);
+}
+
+/**
+ * work_hw_deregistered() - Handle HW deregistered.
+ * @work: Reference to work data.
+ */
+static void work_hw_deregistered(struct work_struct *work)
+{
+ struct uart_work_struct *current_work;
+ int err;
+
+ if (!work) {
+ CG2900_ERR("work == NULL");
+ return;
+ }
+
+ current_work = container_of(work, struct uart_work_struct, work);
+
+ /* Purge any stored sk_buffers */
+ skb_queue_purge(&uart_info->tx_queue);
+ if (uart_info->rx_skb) {
+ kfree_skb(uart_info->rx_skb);
+ uart_info->rx_skb = NULL;
+ }
+
+ err = cg2900_deregister_trans_driver();
+ if (err)
+ CG2900_ERR("Could not deregister UART from Core (%d)", err);
+
+ kfree(current_work);
+}
+
+/**
+ * set_baud_rate() - Sets new baud rate for the UART.
+ * @baud: New baud rate.
+ *
+ * This function first sends the HCI command
+ * Hci_Cmd_ST_Set_Uart_Baud_Rate. It then changes the baud rate in HW, and
+ * finally it waits for the Command Complete event for the
+ * Hci_Cmd_ST_Set_Uart_Baud_Rate command.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EALREADY if baud rate change is already in progress.
+ * -EFAULT if one or more of the UART related structs is not allocated.
+ * -ENOMEM if skb allocation has failed.
+ * -EPERM if setting the new baud rate has failed.
+ * Error codes generated by create_work_item.
+ */
+static int set_baud_rate(int baud)
+{
+ struct tty_struct *tty = NULL;
+ int err = 0;
+ struct sk_buff *skb;
+ int old_baud_rate;
+
+ CG2900_INFO("set_baud_rate (%d baud)", baud);
+
+ if (uart_info->baud_rate_state != BAUD_IDLE) {
+ CG2900_ERR("Trying to set new baud rate before old setting "
+ "is finished");
+ return -EALREADY;
+ }
+
+ if (uart_info->tty)
+ tty = uart_info->tty;
+ else {
+ CG2900_ERR("Important structs not allocated!");
+ return -EFAULT;
+ }
+
+ /*
+ * Store old baud rate so that we can restore it if something goes
+ * wrong.
+ */
+ old_baud_rate = uart_info->baud_rate;
+
+ skb = alloc_set_baud_rate_cmd(&baud);
+ if (!skb) {
+ CG2900_ERR("alloc_set_baud_rate_cmd failed");
+ return -ENOMEM;
+ }
+
+ SET_BAUD_STATE(BAUD_START);
+ uart_info->baud_rate = baud;
+
+ /* Queue the sk_buffer... */
+ skb_queue_tail(&uart_info->tx_queue, skb);
+
+ /* ... and call the common UART TX function */
+ err = create_work_item(uart_info->wq, work_do_transmit, NULL);
+ if (err) {
+ CG2900_ERR("Failed to send change baud rate cmd, freeing "
+ "skb.");
+ skb = skb_dequeue_tail(&uart_info->tx_queue);
+ SET_BAUD_STATE(BAUD_IDLE);
+ uart_info->baud_rate = old_baud_rate;
+ kfree_skb(skb);
+ return err;
+ }
+
+ CG2900_DBG("Set baud rate cmd scheduled for sending.");
+
+ /*
+ * Now wait for the command complete.
+ * It will come at the new baudrate.
+ */
+ wait_event_interruptible_timeout(uart_wait_queue,
+ ((BAUD_SUCCESS == uart_info->baud_rate_state) ||
+ (BAUD_FAIL == uart_info->baud_rate_state)),
+ msecs_to_jiffies(UART_RESP_TIMEOUT));
+ if (BAUD_SUCCESS == uart_info->baud_rate_state)
+ CG2900_DBG("Baudrate changed to %d baud", baud);
+ else {
+ CG2900_ERR("Failed to set new baudrate (%d)",
+ uart_info->baud_rate_state);
+ err = -EPERM;
+ }
+
+ /* Finally flush the TTY so we are sure that is no bad data there */
+ if (tty->ops->flush_buffer) {
+ CG2900_DBG("Flushing TTY after baud rate change");
+ tty->ops->flush_buffer(tty);
+ }
+
+ /* Finished. Set state to IDLE */
+ SET_BAUD_STATE(BAUD_IDLE);
+
+ return err;
+}
+
+/**
+ * uart_open() - Open the CG2900 UART for data transfers.
+ * @dev: Transport device information.
+ *
+ * Returns:
+ * 0 if there is no error,
+ * -EACCES if write to transport failed,
+ * -EIO if chip did not answer to commands.
+ */
+static int uart_open(struct cg2900_trans_dev *dev)
+{
+ u8 data[HCI_BT_RESET_LEN + HCI_H4_SIZE];
+ struct tty_struct *tty;
+ int bytes_written;
+
+ /*
+ * Chip has just been started up. It has a system to autodetect
+ * exact baud rate and transport to use. There are only a few commands
+ * it will recognize and HCI Reset is one of them.
+ * We therefore start with sending that before actually changing
+ * baud rate.
+ *
+ * Create the Hci_Reset packet
+ */
+ data[0] = HCI_BT_CMD_H4_CHANNEL;
+ data[1] = HCI_BT_RESET_CMD_LSB;
+ data[2] = HCI_BT_RESET_CMD_MSB;
+ data[3] = HCI_BT_RESET_PARAM_LEN;
+
+ /* Get the TTY info and send the packet */
+ tty = uart_info->tty;
+ SET_BAUD_STATE(BAUD_SENDING_RESET);
+ CG2900_DBG("Sending HCI reset before baud rate change");
+ bytes_written = tty->ops->write(tty, data,
+ HCI_BT_RESET_LEN + HCI_H4_SIZE);
+ if (bytes_written != HCI_BT_RESET_LEN + HCI_H4_SIZE) {
+ CG2900_ERR("Only wrote %d bytes", bytes_written);
+ SET_BAUD_STATE(BAUD_IDLE);
+ return -EACCES;
+ }
+
+ /*
+ * Wait for command complete. If error, exit without changing
+ * baud rate.
+ */
+ wait_event_interruptible_timeout(uart_wait_queue,
+ BAUD_IDLE == uart_info->baud_rate_state,
+ msecs_to_jiffies(UART_RESP_TIMEOUT));
+ if (BAUD_IDLE != uart_info->baud_rate_state) {
+ CG2900_ERR("Failed to send HCI Reset");
+ SET_BAUD_STATE(BAUD_IDLE);
+ return -EIO;
+ }
+ /* Register interrupt callback into cg2900_devices.*/
+ cg2900_devices_reg_cb(&uart_cg2900_dev_cb);
+
+ return set_baud_rate(uart_high_baud);;
+}
+
+/**
+ * uart_set_chip_power() - Enable or disable the CG2900.
+ * @chip_on: true if chip shall be enabled, false otherwise.
+ */
+static void uart_set_chip_power(bool chip_on)
+{
+ int uart_baudrate = uart_default_baud;
+ struct tty_struct *tty;
+
+ CG2900_INFO("uart_set_chip_power: %s",
+ (chip_on ? "ENABLE" : "DISABLE"));
+
+ if (uart_info->tty)
+ tty = uart_info->tty;
+ else {
+ CG2900_ERR("Important structs not allocated!");
+ return;
+ }
+
+ if (chip_on)
+ cg2900_devices_enable_chip();
+ else {
+ cg2900_devices_disable_chip();
+ /*
+ * Setting baud rate to 0 will tell UART driver to shut off its
+ * clocks.
+ */
+ uart_baudrate = ZERO_BAUD_RATE;
+ }
+
+ /*
+ * Now we have to set the digital baseband UART
+ * to default baudrate if chip is ON or to zero baudrate if
+ * chip is turning OFF.
+ */
+ (void)set_tty_baud(tty, uart_baudrate);
+}
+
+/**
+ * uart_close() - Close the CG2900 UART for data transfers.
+ * @dev: Transport device information.
+ *
+ * Returns:
+ * 0 if there is no error.
+ */
+static int uart_close(struct cg2900_trans_dev *dev)
+{
+ /* The chip is already shut down. Power off the chip. */
+ uart_set_chip_power(false);
+
+ return 0;
+}
+
+/**
+ * uart_write() - Transmit data to CG2900 over UART.
+ * @dev: Transport device information.
+ * @skb: SK buffer to transmit.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * Errors from create_work_item.
+ */
+static int uart_write(struct cg2900_trans_dev *dev, struct sk_buff *skb)
+{
+ int err;
+
+ /* Delete sleep timer. */
+ (void)del_timer(&uart_info->timer);
+
+ CG2900_DBG_DATA_CONTENT("Length: %d Data: %02X %02X %02X %02X %02X "
+ "%02X %02X %02X %02X %02X %02X %02X",
+ skb->len,
+ skb->data[0], skb->data[1], skb->data[2],
+ skb->data[3], skb->data[4], skb->data[5],
+ skb->data[6], skb->data[7], skb->data[8],
+ skb->data[9], skb->data[10], skb->data[11]);
+
+ /* Queue the sk_buffer... */
+ skb_queue_tail(&uart_info->tx_queue, skb);
+
+ /* ...and start TX operation */
+ err = create_work_item(uart_info->wq, work_do_transmit, NULL);
+ if (err)
+ CG2900_ERR("Failed to create work item (%d) uart_tty_wakeup",
+ err);
+
+ return err;
+}
+
+/**
+ * send_skb_to_core() - Sends packet received from UART to CG2900 Core.
+ * @skb: Received data packet.
+ *
+ * This function checks if UART is waiting for Command complete event,
+ * see set_baud_rate.
+ * If it is waiting it checks if it is the expected packet and the status.
+ * If not is passes the packet to CG2900 Core.
+ */
+static void send_skb_to_core(struct sk_buff *skb)
+{
+ u8 status;
+
+ if (!skb) {
+ CG2900_ERR("Received NULL as skb");
+ return;
+ }
+
+ if (BAUD_WAITING == uart_info->baud_rate_state) {
+ /*
+ * Should only really be one packet received now:
+ * the CmdComplete for the SetBaudrate command
+ * Let's see if this is the packet we are waiting for.
+ */
+ if (!is_bt_cmd_complete_no_param(skb, SET_BAUD_RATE_LSB,
+ SET_BAUD_RATE_MSB)) {
+ /*
+ * Received other event. Should not really happen,
+ * but pass the data to CG2900 Core anyway.
+ */
+ CG2900_DBG_DATA("Sending packet to CG2900 Core while "
+ "waiting for CmdComplete");
+ cg2900_data_from_chip(skb);
+ return;
+ }
+
+ /*
+ * We have received complete event for our baud rate
+ * change command
+ */
+ status = skb->data[HCI_BT_EVT_CMD_COMPL_STATUS_POS +
+ HCI_H4_SIZE];
+ if (HCI_BT_ERROR_NO_ERROR == status) {
+ CG2900_DBG("Received baud rate change complete "
+ "event OK");
+ SET_BAUD_STATE(BAUD_SUCCESS);
+ } else {
+ CG2900_ERR("Received baud rate change complete event "
+ "with status 0x%X", status);
+ SET_BAUD_STATE(BAUD_FAIL);
+ }
+ wake_up_interruptible(&uart_wait_queue);
+ kfree_skb(skb);
+ } else if (BAUD_SENDING_RESET == uart_info->baud_rate_state) {
+ /*
+ * Should only really be one packet received now:
+ * the CmdComplete for the Reset command
+ * Let's see if this is the packet we are waiting for.
+ */
+ if (!is_bt_cmd_complete_no_param(skb, HCI_BT_RESET_CMD_LSB,
+ HCI_BT_RESET_CMD_MSB)) {
+ /*
+ * Received other event. Should not really happen,
+ * but pass the data to CG2900 Core anyway.
+ */
+ CG2900_DBG_DATA("Sending packet to CG2900 Core while "
+ "waiting for CmdComplete");
+ cg2900_data_from_chip(skb);
+ return;
+ }
+
+ /*
+ * We have received complete event for our baud rate
+ * change command
+ */
+ status = skb->data[HCI_BT_EVT_CMD_COMPL_STATUS_POS +
+ HCI_H4_SIZE];
+ if (HCI_BT_ERROR_NO_ERROR == status) {
+ CG2900_DBG("Received HCI reset complete event OK");
+ /*
+ * Go back to BAUD_IDLE since this was not really
+ * baud rate change but just a preparation of the chip
+ * to be ready to receive commands.
+ */
+ SET_BAUD_STATE(BAUD_IDLE);
+ } else {
+ CG2900_ERR("Received HCI reset complete event with "
+ "status 0x%X", status);
+ SET_BAUD_STATE(BAUD_FAIL);
+ }
+ wake_up_interruptible(&uart_wait_queue);
+ kfree_skb(skb);
+ } else {
+ /* Just pass data to CG2900 Core */
+ cg2900_data_from_chip(skb);
+ }
+}
+
+static struct cg2900_trans_callbacks uart_cb = {
+ .open = uart_open,
+ .close = uart_close,
+ .write = uart_write,
+ .set_chip_power = uart_set_chip_power
+};
+
+/**
+ * check_data_len() - Check number of bytes to receive.
+ * @len: Number of bytes left to receive.
+ */
+static void check_data_len(int len)
+{
+ /* First get number of bytes left in the sk_buffer */
+ register int room = skb_tailroom(uart_info->rx_skb);
+
+ if (!len) {
+ /* No data left to receive. Transmit to CG2900 Core */
+ send_skb_to_core(uart_info->rx_skb);
+ } else if (len > room) {
+ CG2900_ERR("Data length is too large (%d > %d)", len, room);
+ kfree_skb(uart_info->rx_skb);
+ } else {
+ /*
+ * "Normal" case. Switch to data receiving state and store
+ * data length.
+ */
+ uart_info->rx_state = W4_DATA;
+ uart_info->rx_count = len;
+ return;
+ }
+
+ uart_info->rx_state = W4_PACKET_TYPE;
+ uart_info->rx_skb = NULL;
+ uart_info->rx_count = 0;
+}
+
+/**
+ * uart_receive_skb() - Handles received UART data.
+ * @data: Data received
+ * @count: Number of bytes received
+ *
+ * The uart_receive_skb() function handles received UART data and puts it
+ * together to one complete packet.
+ *
+ * Returns:
+ * Number of bytes not handled, i.e. 0 = no error.
+ */
+static int uart_receive_skb(const u8 *data, int count)
+{
+ const u8 *r_ptr;
+ u8 *w_ptr;
+ int len;
+ struct hci_event_hdr *evt;
+ struct hci_acl_hdr *acl;
+ union fm_leg_evt_or_irq *fm;
+ struct gnss_hci_hdr *gnss;
+ u8 *tmp;
+
+ r_ptr = data;
+ /* Continue while there is data left to handle */
+ while (count) {
+ /*
+ * If we have already received a packet we know how many bytes
+ * there are left.
+ */
+ if (!uart_info->rx_count)
+ goto check_h4_header;
+
+ /* First copy received data into the skb_rx */
+ len = min_t(unsigned int, uart_info->rx_count, count);
+ memcpy(skb_put(uart_info->rx_skb, len), r_ptr, len);
+ /* Update counters from the length and step the data pointer */
+ uart_info->rx_count -= len;
+ count -= len;
+ r_ptr += len;
+
+ if (uart_info->rx_count)
+ /*
+ * More data to receive to current packet. Break and
+ * wait for next data on the UART.
+ */
+ break;
+
+ /* Handle the different states */
+ tmp = uart_info->rx_skb->data + CG2900_SKB_RESERVE;
+ switch (uart_info->rx_state) {
+ case W4_DATA:
+ /*
+ * Whole data packet has been received.
+ * Transmit it to CG2900 Core.
+ */
+ send_skb_to_core(uart_info->rx_skb);
+
+ uart_info->rx_state = W4_PACKET_TYPE;
+ uart_info->rx_skb = NULL;
+ continue;
+
+ case W4_EVENT_HDR:
+ evt = (struct hci_event_hdr *)tmp;
+ check_data_len(evt->plen);
+ /* Header read. Continue with next bytes */
+ continue;
+
+ case W4_ACL_HDR:
+ acl = (struct hci_acl_hdr *)tmp;
+ check_data_len(le16_to_cpu(acl->dlen));
+ /* Header read. Continue with next bytes */
+ continue;
+
+ case W4_FM_RADIO_HDR:
+ fm = (union fm_leg_evt_or_irq *)tmp;
+ check_data_len(fm->param_length);
+ /* Header read. Continue with next bytes */
+ continue;
+
+ case W4_GNSS_HDR:
+ gnss = (struct gnss_hci_hdr *)tmp;
+ check_data_len(le16_to_cpu(gnss->plen));
+ /* Header read. Continue with next bytes */
+ continue;
+
+ default:
+ CG2900_ERR("Bad state indicating memory overwrite "
+ "(0x%X)", (u8)(uart_info->rx_state));
+ break;
+ }
+
+check_h4_header:
+ /* Check which H:4 packet this is and update RX states */
+ if (*r_ptr == HCI_BT_EVT_H4_CHANNEL) {
+ uart_info->rx_state = W4_EVENT_HDR;
+ uart_info->rx_count = HCI_BT_EVT_HDR_SIZE;
+ } else if (*r_ptr == HCI_BT_ACL_H4_CHANNEL) {
+ uart_info->rx_state = W4_ACL_HDR;
+ uart_info->rx_count = HCI_BT_ACL_HDR_SIZE;
+ } else if (*r_ptr == HCI_FM_RADIO_H4_CHANNEL) {
+ uart_info->rx_state = W4_FM_RADIO_HDR;
+ uart_info->rx_count = HCI_FM_RADIO_HDR_SIZE;
+ } else if (*r_ptr == HCI_GNSS_H4_CHANNEL) {
+ uart_info->rx_state = W4_GNSS_HDR;
+ uart_info->rx_count = HCI_GNSS_HDR_SIZE;
+ } else {
+ CG2900_ERR("Unknown HCI packet type 0x%X", (u8)*r_ptr);
+ r_ptr++;
+ count--;
+ continue;
+ }
+
+ /*
+ * Allocate packet. We do not yet know the size and therefore
+ * allocate max size.
+ */
+ uart_info->rx_skb = alloc_rx_skb(RX_SKB_MAX_SIZE, GFP_ATOMIC);
+ if (!uart_info->rx_skb) {
+ CG2900_ERR("Can't allocate memory for new packet");
+ uart_info->rx_state = W4_PACKET_TYPE;
+ uart_info->rx_count = 0;
+ return 0;
+ }
+
+ /* Write the H:4 header first in the sk_buffer */
+ w_ptr = skb_put(uart_info->rx_skb, 1);
+ *w_ptr = *r_ptr;
+
+ /* First byte (H4 header) read. Goto next byte */
+ r_ptr++;
+ count--;
+ }
+
+ return count;
+}
+
+/**
+ * uart_tty_open() - Called when UART line discipline changed to N_HCI.
+ * @tty: Pointer to associated TTY instance data.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * Errors from cg2900_register_trans_driver.
+ */
+static int uart_tty_open(struct tty_struct *tty)
+{
+ int err;
+
+ CG2900_INFO("uart_tty_open");
+
+ /* Set the structure pointers and set the UART receive room */
+ uart_info->tty = tty;
+ tty->disc_data = NULL;
+ tty->receive_room = UART_RECEIVE_ROOM;
+
+ /*
+ * Flush any pending characters in the driver and line discipline.
+ * Don't use ldisc_ref here as the open path is before the ldisc is
+ * referencable.
+ */
+ if (tty->ldisc->ops->flush_buffer)
+ tty->ldisc->ops->flush_buffer(tty);
+
+ tty_driver_flush_buffer(tty);
+
+ /* Tell CG2900 Core that UART is connected */
+ err = cg2900_register_trans_driver(&uart_cb, NULL);
+ if (err)
+ CG2900_ERR("Could not register transport driver (%d)", err);
+
+ if (tty->ops->tiocmget && tty->ops->break_ctl)
+ uart_info->sleep_allowed = true;
+ else
+ CG2900_DBG("Sleep mode not available.");
+
+ return err;
+
+}
+
+/**
+ * uart_tty_close() - Close UART tty.
+ * @tty: Pointer to associated TTY instance data.
+ *
+ * The uart_tty_close() function is called when the line discipline is changed
+ * to something else, the TTY is closed, or the TTY detects a hangup.
+ */
+static void uart_tty_close(struct tty_struct *tty)
+{
+ int err;
+
+ CG2900_INFO("uart_tty_close");
+
+ BUG_ON(!uart_info);
+ BUG_ON(!uart_info->wq);
+
+ err = create_work_item(uart_info->wq, work_hw_deregistered, NULL);
+ if (err)
+ CG2900_ERR("Failed to create work item (%d) "
+ "work_hw_deregistered", err);
+}
+
+/**
+ * uart_tty_wakeup() - Callback function for transmit wake up.
+ * @tty: Pointer to associated TTY instance data.
+ *
+ * The uart_tty_wakeup() callback function is called when low level
+ * device driver can accept more send data.
+ */
+static void uart_tty_wakeup(struct tty_struct *tty)
+{
+ int err;
+
+ CG2900_INFO("uart_tty_wakeup");
+
+ /*
+ * Clear the TTY_DO_WRITE_WAKEUP bit that is set in
+ * work_do_transmit().
+ */
+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+
+ if (tty != uart_info->tty)
+ return;
+
+ /* Delete sleep timer. */
+ (void)del_timer(&uart_info->timer);
+
+ /* Start TX operation */
+ err = create_work_item(uart_info->wq, work_do_transmit, NULL);
+ if (err)
+ CG2900_ERR("Failed to create work item (%d) uart_tty_wakeup",
+ err);
+}
+
+/**
+ * uart_tty_receive() - Called by TTY low level driver when receive data is available.
+ * @tty: Pointer to TTY instance data
+ * @data: Pointer to received data
+ * @flags: Pointer to flags for data
+ * @count: Count of received data in bytes
+ */
+static void uart_tty_receive(struct tty_struct *tty, const u8 *data,
+ char *flags, int count)
+{
+ CG2900_INFO("uart_tty_receive");
+
+ if (tty != uart_info->tty)
+ return;
+
+ CG2900_DBG_DATA("Received data with length = %d and first byte 0x%02X",
+ count, data[0]);
+ CG2900_DBG_DATA_CONTENT("Data: %02X %02X %02X %02X %02X %02X %02X "
+ "%02X %02X %02X %02X %02X",
+ data[0], data[1], data[2], data[3], data[4],
+ data[5], data[6], data[7], data[8], data[9],
+ data[10], data[11]);
+
+ /* Restart data timer */
+ update_timer();
+ spin_lock(&uart_info->rx_lock);
+ uart_receive_skb(data, count);
+ spin_unlock(&uart_info->rx_lock);
+
+}
+
+/**
+ * uart_tty_ioctl() - Process IOCTL system call for the TTY device.
+ * @tty: Pointer to TTY instance data.
+ * @file: Pointer to open file object for device.
+ * @cmd: IOCTL command code.
+ * @arg: Argument for IOCTL call (cmd dependent).
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EBADF if supplied TTY struct is not correct.
+ * Error codes from n_tty_iotcl_helper.
+ */
+static int uart_tty_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+
+ CG2900_INFO("uart_tty_ioctl cmd %d", cmd);
+ CG2900_DBG("DIR: %d, TYPE: %d, NR: %d, SIZE: %d", _IOC_DIR(cmd),
+ _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
+
+
+
+ switch (cmd) {
+ case HCIUARTSETFD:
+ /* Save file object to device. */
+ if (!uart_info->fd)
+ uart_info->fd = file;
+ else
+ CG2900_DBG("Cannot store file object to device.");
+ break;
+ case HCIUARTSETPROTO: /* Fallthrough */
+ case HCIUARTGETPROTO:
+ case HCIUARTGETDEVICE:
+ /*
+ * We don't do anything special here, but we have to show we
+ * handle it.
+ */
+ break;
+
+ default:
+ err = n_tty_ioctl_helper(tty, file, cmd, arg);
+ break;
+ };
+
+ return err;
+}
+
+/*
+ * We don't provide read/write/poll interface for user space.
+ */
+static ssize_t uart_tty_read(struct tty_struct *tty, struct file *file,
+ unsigned char __user *buf, size_t nr)
+{
+ CG2900_INFO("uart_tty_read");
+ return 0;
+}
+
+static ssize_t uart_tty_write(struct tty_struct *tty, struct file *file,
+ const unsigned char *data, size_t count)
+{
+ CG2900_INFO("uart_tty_write");
+ return count;
+}
+
+static unsigned int uart_tty_poll(struct tty_struct *tty, struct file *filp,
+ poll_table *wait)
+{
+ return 0;
+}
+
+/* Generic functions */
+
+/* The uart_ldisc structure is used when registering to the UART framework. */
+static struct tty_ldisc_ops uart_ldisc = {
+ .magic = TTY_LDISC_MAGIC,
+ .name = "n_hci",
+ .open = uart_tty_open,
+ .close = uart_tty_close,
+ .read = uart_tty_read,
+ .write = uart_tty_write,
+ .ioctl = uart_tty_ioctl,
+ .poll = uart_tty_poll,
+ .receive_buf = uart_tty_receive,
+ .write_wakeup = uart_tty_wakeup,
+ .owner = THIS_MODULE
+};
+
+/**
+ * uart_init() - Initialize module.
+ *
+ * The uart_init() function initializes the module and registers to
+ * the UART framework.
+ *
+ * Returns:
+ * 0 if success.
+ * -ENOMEM for failed alloc or structure creation.
+ * -ECHILD for failed work queue creation.
+ * Error codes generated by tty_register_ldisc.
+ */
+static int __init uart_init(void)
+{
+ int err = 0;
+
+ CG2900_INFO("uart_init");
+
+ uart_info = kzalloc(sizeof(*uart_info), GFP_KERNEL);
+ if (!uart_info) {
+ CG2900_ERR("Couldn't allocate uart_info");
+ return -ENOMEM;
+ }
+
+ uart_info->sleep_state = CHIP_AWAKE;
+ skb_queue_head_init(&uart_info->tx_queue);
+ mutex_init(&uart_info->tx_mutex);
+ spin_lock_init(&uart_info->rx_lock);
+ mutex_init(&(uart_info->sleep_state_lock));
+
+ /* Init UART TX work queue */
+ uart_info->wq = create_singlethread_workqueue(UART_WQ_NAME);
+ if (!uart_info->wq) {
+ CG2900_ERR("Could not create workqueue");
+ err = -ECHILD; /* No child processes */
+ goto error_handling_wq;
+ }
+ init_timer(&uart_info->timer);
+ uart_info->timer.function = sleep_timer_expired;
+ uart_info->timer.expires = jiffies + cg2900_get_sleep_timeout();
+
+ /* Register the tty discipline. We will see what will be used. */
+ err = tty_register_ldisc(N_HCI, &uart_ldisc);
+ if (err) {
+ CG2900_ERR("HCI line discipline registration failed. (0x%X)",
+ err);
+ goto error_handling_register;
+ }
+
+ goto finished;
+
+error_handling_register:
+ destroy_workqueue(uart_info->wq);
+error_handling_wq:
+ mutex_destroy(&uart_info->tx_mutex);
+ kfree(uart_info);
+ uart_info = NULL;
+finished:
+ return err;
+}
+
+/**
+ * uart_exit() - Remove module.
+ */
+static void __exit uart_exit(void)
+{
+ int err;
+
+ CG2900_INFO("uart_exit");
+
+ /* Release tty registration of line discipline */
+ err = tty_unregister_ldisc(N_HCI);
+ if (err)
+ CG2900_ERR("Can't unregister HCI line discipline (%d)", err);
+
+ if (!uart_info)
+ return;
+
+ destroy_workqueue(uart_info->wq);
+ mutex_destroy(&uart_info->tx_mutex);
+
+ kfree(uart_info);
+ uart_info = NULL;
+}
+
+module_init(uart_init);
+module_exit(uart_exit);
+
+module_param(uart_default_baud, int, S_IRUGO);
+MODULE_PARM_DESC(uart_default_baud,
+ "Default UART baud rate, e.g. 115200. If not set 115200 will "
+ "be used.");
+
+module_param(uart_high_baud, int, S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(uart_high_baud,
+ "High speed UART baud rate, e.g. 4000000. If not set 3000000 "
+ "will be used.");
diff --git a/drivers/mfd/cg2900/hci_defines.h b/drivers/mfd/cg2900/hci_defines.h
new file mode 100644
index 00000000000..6210e1bda31
--- /dev/null
+++ b/drivers/mfd/cg2900/hci_defines.h
@@ -0,0 +1,81 @@
+/*
+ * drivers/mfd/cg2900/hci_defines.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth HCI defines for ST-Ericsson CG2900 connectivity controller.
+ */
+
+#ifndef _BLUETOOTH_DEFINES_H_
+#define _BLUETOOTH_DEFINES_H_
+
+#include <linux/types.h>
+
+/* H:4 offset in an HCI packet */
+#define HCI_H4_POS 0
+#define HCI_H4_SIZE 1
+
+/* Standardized Bluetooth H:4 channels */
+#define HCI_BT_CMD_H4_CHANNEL 0x01
+#define HCI_BT_ACL_H4_CHANNEL 0x02
+#define HCI_BT_SCO_H4_CHANNEL 0x03
+#define HCI_BT_EVT_H4_CHANNEL 0x04
+
+/* Bluetooth Opcode Group Field (OGF) */
+#define HCI_BT_OGF_LINK_CTRL 0x01
+#define HCI_BT_OGF_LINK_POLICY 0x02
+#define HCI_BT_OGF_CTRL_BB 0x03
+#define HCI_BT_OGF_LINK_INFO 0x04
+#define HCI_BT_OGF_LINK_STATUS 0x05
+#define HCI_BT_OGF_LINK_TESTING 0x06
+#define HCI_BT_OGF_VS 0x3F
+
+/* Bluetooth Opcode Command Field (OCF) */
+#define HCI_BT_OCF_READ_LOCAL_VERSION_INFO 0x0001
+#define HCI_BT_OCF_RESET 0x0003
+
+/* Bluetooth HCI command OpCodes in LSB/MSB fashion */
+#define HCI_BT_RESET_CMD_LSB 0x03
+#define HCI_BT_RESET_CMD_MSB 0x0C
+#define HCI_BT_READ_LOCAL_VERSION_CMD_LSB 0x01
+#define HCI_BT_READ_LOCAL_VERSION_CMD_MSB 0x10
+
+/* Bluetooth Event OpCodes */
+#define HCI_BT_EVT_CMD_COMPLETE 0x0E
+#define HCI_BT_EVT_CMD_STATUS 0x0F
+
+/* Bluetooth Command offsets */
+#define HCI_BT_CMD_ID_POS 1
+#define HCI_BT_CMD_PARAM_LEN_POS 3
+#define HCI_BT_CMD_PARAM_POS 4
+#define HCI_BT_CMD_HDR_SIZE 4
+
+/* Bluetooth Event offsets for CG2900 users, i.e. not including H:4 channel */
+#define HCI_BT_EVT_ID_POS 0
+#define HCI_BT_EVT_LEN_POS 1
+#define HCI_BT_EVT_CMD_COMPL_ID_POS 3
+#define HCI_BT_EVT_CMD_STATUS_ID_POS 4
+#define HCI_BT_EVT_CMD_COMPL_STATUS_POS 5
+#define HCI_BT_EVT_CMD_STATUS_STATUS_POS 2
+#define HCI_BT_EVT_CMD_COMPL_NR_OF_PKTS_POS 2
+#define HCI_BT_EVT_CMD_STATUS_NR_OF_PKTS_POS 3
+
+/* Bluetooth error codes */
+#define HCI_BT_ERROR_NO_ERROR 0x00
+#define HCI_BT_ERROR_CMD_DISALLOWED 0x0C
+
+/* Bluetooth lengths */
+#define HCI_BT_SEND_FILE_MAX_CHUNK_SIZE 254
+
+#define HCI_BT_RESET_LEN 3
+#define HCI_BT_RESET_PARAM_LEN 0
+#define HCI_BT_CMD_COMPLETE_NO_PARAM_LEN 4
+
+#endif /* _BLUETOOTH_DEFINES_H_ */
diff --git a/drivers/mfd/cg2900/stlc2690_chip.c b/drivers/mfd/cg2900/stlc2690_chip.c
new file mode 100644
index 00000000000..dc2d8025912
--- /dev/null
+++ b/drivers/mfd/cg2900/stlc2690_chip.c
@@ -0,0 +1,1105 @@
+/*
+ * drivers/mfd/cg2900/ste_stlc2690.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth HCI H:4 Driver for ST-Ericsson STLC2690 BT/FM controller.
+ */
+
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include <linux/gfp.h>
+#include <linux/stat.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <asm/byteorder.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+
+#include <linux/mfd/cg2900.h>
+#include <mach/cg2900_devices.h>
+#include "hci_defines.h"
+#include "stlc2690_chip.h"
+#include "cg2900_core.h"
+#include "cg2900_debug.h"
+
+#define LINE_BUFFER_LENGTH 128
+#define FILENAME_MAX 128
+
+#define WQ_NAME "stlc2690_wq"
+#define PATCH_INFO_FILE "cg2900_patch_info.fw"
+#define FACTORY_SETTINGS_INFO_FILE "cg2900_settings_info.fw"
+
+/* Supported chips */
+#define SUPP_MANUFACTURER 0x30
+#define SUPP_REVISION_MIN 0x0500
+#define SUPP_REVISION_MAX 0x06FF
+
+/* Size of file chunk ID */
+#define FILE_CHUNK_ID_SIZE 1
+#define VS_SEND_FILE_CHUNK_ID_POS 4
+#define BT_CMD_LEN_POS 3
+
+/* State setting macros */
+#define SET_BOOT_STATE(__new_state) \
+ CG2900_SET_STATE("boot_state", stlc2690_info->boot_state, __new_state)
+#define SET_FILE_LOAD_STATE(__new_state) \
+ CG2900_SET_STATE("file_load_state", stlc2690_info->file_load_state, \
+ __new_state)
+#define SET_DOWNLOAD_STATE(__new_state) \
+ CG2900_SET_STATE("download_state", stlc2690_info->download_state, \
+ __new_state)
+
+/** CHANNEL_BT_CMD - Bluetooth HCI H:4 channel
+ * for Bluetooth commands in the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_BT_CMD 0x01
+
+/** CHANNEL_BT_ACL - Bluetooth HCI H:4 channel
+ * for Bluetooth ACL data in the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_BT_ACL 0x02
+
+/** CHANNEL_BT_EVT - Bluetooth HCI H:4 channel
+ * for Bluetooth events in the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_BT_EVT 0x04
+
+/** CHANNEL_HCI_LOGGER - Bluetooth HCI H:4 channel
+ * for logging all transmitted H4 packets (on all channels).
+ */
+#define CHANNEL_HCI_LOGGER 0xFA
+
+/** CHANNEL_US_CTRL - Bluetooth HCI H:4 channel
+ * for user space control of the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_US_CTRL 0xFC
+
+/** CHANNEL_CORE - Bluetooth HCI H:4 channel
+ * for user space control of the ST-Ericsson connectivity controller.
+ */
+#define CHANNEL_CORE 0xFD
+
+/**
+ * struct stlc2690_work_struct - Work structure for CG2900 Core module.
+ * @work: Work structure.
+ * @skb: Data packet.
+ * @data: Private data for user.
+ *
+ * This structure is used to pack work for work queue.
+ */
+struct stlc2690_work_struct {
+ struct work_struct work;
+ struct sk_buff *skb;
+ void *data;
+};
+
+/**
+ * enum boot_state - BOOT-state for CG2900 Core.
+ * @BOOT_NOT_STARTED: Boot has not yet started.
+ * @BOOT_SEND_BD_ADDRESS: VS Store In FS command with BD address
+ * has been sent.
+ * @BOOT_GET_FILES_TO_LOAD: CG2900 Core is retreiving file to load.
+ * @BOOT_DOWNLOAD_PATCH: CG2900 Core is downloading patches.
+ * @BOOT_ACTIVATE_PATCHES_AND_SETTINGS: CG2900 Core is activating patches and
+ * settings.
+ * @BOOT_READY: CG2900 Core boot is ready.
+ * @BOOT_FAILED: CG2900 Core boot failed.
+ */
+enum boot_state {
+ BOOT_NOT_STARTED,
+ BOOT_SEND_BD_ADDRESS,
+ BOOT_GET_FILES_TO_LOAD,
+ BOOT_DOWNLOAD_PATCH,
+ BOOT_ACTIVATE_PATCHES_AND_SETTINGS,
+ BOOT_READY,
+ BOOT_FAILED
+};
+
+/**
+ * enum file_load_state - BOOT_FILE_LOAD-state for CG2900 Core.
+ * @FILE_LOAD_GET_PATCH: Loading patches.
+ * @FILE_LOAD_GET_STATIC_SETTINGS: Loading static settings.
+ * @FILE_LOAD_NO_MORE_FILES: No more files to load.
+ * @FILE_LOAD_FAILED: File loading failed.
+ */
+enum file_load_state {
+ FILE_LOAD_GET_PATCH,
+ FILE_LOAD_GET_STATIC_SETTINGS,
+ FILE_LOAD_NO_MORE_FILES,
+ FILE_LOAD_FAILED
+};
+
+/**
+ * enum download_state - BOOT_DOWNLOAD state.
+ * @DOWNLOAD_PENDING: Download in progress.
+ * @DOWNLOAD_SUCCESS: Download successfully finished.
+ * @DOWNLOAD_FAILED: Downloading failed.
+ */
+enum download_state {
+ DOWNLOAD_PENDING,
+ DOWNLOAD_SUCCESS,
+ DOWNLOAD_FAILED
+};
+
+/**
+ * struct stlc2690_device_id - Structure for connecting H4 channel to user.
+ * @name: Name of device.
+ * @h4_channel: HCI H:4 channel used by this device.
+ */
+struct stlc2690_device_id {
+ char *name;
+ int h4_channel;
+};
+
+/**
+ * struct stlc2690_info - Main info structure for STLC2690.
+ * @patch_file_name: Stores patch file name.
+ * @settings_file_name: Stores settings file name.
+ * @fw_file: Stores firmware file (patch or settings).
+ * @file_offset: Current read offset in firmware file.
+ * @chunk_id: Stores current chunk ID of write file operations.
+ * @boot_state: Current BOOT-state of STLC2690.
+ * @file_load_state: Current BOOT_FILE_LOAD-state of STLC2690.
+ * @download_state: Current BOOT_DOWNLOAD-state of STLC2690.
+ * @wq: STLC2690 workqueue.
+ * @chip_dev: Chip info.
+ */
+struct stlc2690_info {
+ char *patch_file_name;
+ char *settings_file_name;
+ const struct firmware *fw_file;
+ int file_offset;
+ u8 chunk_id;
+ enum boot_state boot_state;
+ enum file_load_state file_load_state;
+ enum download_state download_state;
+ struct workqueue_struct *wq;
+ struct cg2900_chip_dev chip_dev;
+};
+
+static struct stlc2690_info *stlc2690_info;
+
+#define NBR_OF_DEVS 6
+
+/*
+ * stlc2690_channels() - Array containing available H4 channels for the STLC2690
+ * ST-Ericsson Connectivity controller.
+ */
+struct stlc2690_device_id stlc2690_channels[NBR_OF_DEVS] = {
+ {CG2900_BT_CMD, CHANNEL_BT_CMD},
+ {CG2900_BT_ACL, CHANNEL_BT_ACL},
+ {CG2900_BT_EVT, CHANNEL_BT_EVT},
+ {CG2900_HCI_LOGGER, CHANNEL_HCI_LOGGER},
+ {CG2900_US_CTRL, CHANNEL_US_CTRL},
+ {CG2900_CORE, CHANNEL_CORE}
+};
+
+/*
+ * Internal functions
+ */
+
+/**
+ * create_and_send_bt_cmd() - Copy and send sk_buffer.
+ * @data: Data to send.
+ * @length: Length in bytes of data.
+ *
+ * The create_and_send_bt_cmd() function allocate sk_buffer, copy supplied data
+ * to it, and send the sk_buffer to CG2900 Core.
+ * Note that the data must contain the H:4 header.
+ */
+static void create_and_send_bt_cmd(void *data, int length)
+{
+ struct sk_buff *skb;
+ struct cg2900_hci_logger_config *logger_config;
+ int err;
+
+ skb = alloc_skb(length, GFP_ATOMIC);
+ if (!skb) {
+ CG2900_ERR("Couldn't allocate sk_buff with length %d", length);
+ return;
+ }
+
+ memcpy(skb_put(skb, length), data, length);
+ skb->data[0] = CHANNEL_BT_CMD;
+
+ logger_config = cg2900_get_hci_logger_config();
+ if (logger_config)
+ err = cg2900_send_to_chip(skb, logger_config->bt_cmd_enable);
+ else
+ err = cg2900_send_to_chip(skb, false);
+ if (err) {
+ CG2900_ERR("Failed to transmit to chip (%d)", err);
+ kfree_skb(skb);
+ }
+}
+
+/**
+ * send_bd_address() - Send HCI VS command with BD address to the chip.
+ */
+static void send_bd_address(void)
+{
+ struct bt_vs_store_in_fs_cmd *cmd;
+ struct hci_command_hdr *hdr;
+ u8 *tmp;
+ u8 *data;
+ u8 plen = sizeof(*cmd) + BT_BDADDR_SIZE - 1;
+
+ data = kmalloc(sizeof(*hdr) + plen, GFP_KERNEL);
+ if (!data)
+ return;
+ tmp = data;
+
+ hdr = (struct hci_command_hdr *)tmp;
+ hdr->opcode = cpu_to_le16(STLC2690_BT_OP_VS_STORE_IN_FS);
+ hdr->plen = plen;
+
+ tmp += sizeof(*hdr);
+ cmd = (struct bt_vs_store_in_fs_cmd *)tmp;
+ cmd->user_id = STLC2690_VS_STORE_IN_FS_USR_ID_BD_ADDR;
+ cmd->len = BT_BDADDR_SIZE;
+ /* Now copy the BD address received from user space control app. */
+ memcpy(&(cmd->data), bd_address, BT_BDADDR_SIZE);
+
+ SET_BOOT_STATE(BOOT_SEND_BD_ADDRESS);
+
+ create_and_send_bt_cmd(data, sizeof(*hdr) + plen);
+
+ kfree(data);
+}
+
+/**
+ * create_work_item() - Create work item and add it to the work queue.
+ * @work_func: Work function.
+ * @skb: Data packet.
+ * @data: Private data for caller.
+ */
+static void create_work_item(work_func_t work_func, struct sk_buff *skb,
+ void *data)
+{
+ struct stlc2690_work_struct *new_work;
+ int wq_err = 1;
+
+ new_work = kmalloc(sizeof(*new_work), GFP_ATOMIC);
+ if (!new_work) {
+ CG2900_ERR("Failed to alloc memory for stlc2690_work_struct!");
+ return;
+ }
+
+ new_work->skb = skb;
+ new_work->data = data;
+ INIT_WORK(&new_work->work, work_func);
+
+ wq_err = queue_work(stlc2690_info->wq, &new_work->work);
+ if (!wq_err) {
+ CG2900_ERR("Failed to queue work_struct because it's already in"
+ " the queue!");
+ kfree(new_work);
+ }
+}
+
+/**
+ * get_text_line()- Replacement function for stdio function fgets.
+ * @wr_buffer: Buffer to copy text to.
+ * @max_nbr_of_bytes: Max number of bytes to read, i.e. size of rd_buffer.
+ * @rd_buffer: Data to parse.
+ * @bytes_copied: Number of bytes copied to wr_buffer.
+ *
+ * The get_text_line() function extracts one line of text from input file.
+ *
+ * Returns:
+ * Pointer to next data to read.
+ */
+static char *get_text_line(char *wr_buffer, int max_nbr_of_bytes,
+ char *rd_buffer, int *bytes_copied)
+{
+ char *curr_wr = wr_buffer;
+ char *curr_rd = rd_buffer;
+ char in_byte;
+
+ *bytes_copied = 0;
+
+ do {
+ *curr_wr = *curr_rd;
+ in_byte = *curr_wr;
+ curr_wr++;
+ curr_rd++;
+ (*bytes_copied)++;
+ } while ((*bytes_copied <= max_nbr_of_bytes) && (in_byte != '\0') &&
+ (in_byte != '\n'));
+ *curr_wr = '\0';
+ return curr_rd;
+}
+
+/**
+ * get_file_to_load() - Parse info file and find correct target file.
+ * @fw: Firmware structure containing file data.
+ * @file_name: (out) Pointer to name of requested file.
+ *
+ * Returns:
+ * True, if target file was found,
+ * False, otherwise.
+ */
+static bool get_file_to_load(const struct firmware *fw, char **file_name)
+{
+ char *line_buffer;
+ char *curr_file_buffer;
+ int bytes_left_to_parse = fw->size;
+ int bytes_read = 0;
+ bool file_found = false;
+ u32 hci_rev;
+ u32 lmp_sub;
+
+ curr_file_buffer = (char *)&(fw->data[0]);
+
+ line_buffer = kzalloc(LINE_BUFFER_LENGTH, GFP_ATOMIC);
+ if (!line_buffer) {
+ CG2900_ERR("Failed to allocate: file_name 0x%X, "
+ "line_buffer 0x%X",
+ (u32)file_name, (u32)line_buffer);
+ goto finished;
+ }
+
+ while (!file_found) {
+ /* Get one line of text from the file to parse */
+ curr_file_buffer = get_text_line(line_buffer,
+ min(LINE_BUFFER_LENGTH,
+ (int)(fw->size - bytes_read)),
+ curr_file_buffer,
+ &bytes_read);
+
+ bytes_left_to_parse -= bytes_read;
+ if (bytes_left_to_parse <= 0) {
+ /* End of file => Leave while loop */
+ CG2900_ERR("Reached end of file. No file found!");
+ break;
+ }
+
+ /*
+ * Check if the line of text is a comment or not,
+ * comments begin with '#'
+ */
+ if (*line_buffer == '#')
+ continue;
+
+ hci_rev = 0;
+ lmp_sub = 0;
+
+ CG2900_DBG("Found a valid line <%s>", line_buffer);
+
+ /*
+ * Check if we can find the correct HCI revision and
+ * LMP subversion as well as a file name in the text line.
+ * Store the filename if the actual file can be found in
+ * the file system.
+ */
+ if (sscanf(line_buffer, "%x%x%s", &hci_rev, &lmp_sub,
+ *file_name) == 3
+ && hci_rev == stlc2690_info->chip_dev.chip.hci_revision
+ && lmp_sub ==
+ stlc2690_info->chip_dev.chip.hci_sub_version) {
+ CG2900_DBG("File matching chip found\n"
+ "\tFile name = %s\n"
+ "\tHCI Revision = 0x%X\n"
+ "\tLMP PAL Subversion = 0x%X",
+ *file_name, hci_rev, lmp_sub);
+
+ /*
+ * Name has already been stored above. Nothing more to
+ * do.
+ */
+ file_found = true;
+ } else {
+ /* Zero the name buffer so it is clear to next read */
+ memset(*file_name, 0x00, FILENAME_MAX + 1);
+ }
+ }
+ kfree(line_buffer);
+
+finished:
+ return file_found;
+}
+
+/**
+ * read_and_send_file_part() - Transmit a part of the supplied file.
+ *
+ * The read_and_send_file_part() function transmit a part of the supplied file
+ * to the controller.
+ * If nothing more to read, set the correct states.
+ */
+static void read_and_send_file_part(void)
+{
+ int bytes_to_copy;
+ struct sk_buff *skb;
+ struct cg2900_hci_logger_config *logger_config;
+ struct hci_command_hdr *hdr;
+ struct bt_vs_write_file_block_cmd *cmd;
+ u8 *data;
+ u8 plen;
+
+ /* Calculate number of bytes to copy;
+ * either max bytes for HCI packet or number of bytes left in file
+ */
+ bytes_to_copy = min((int)HCI_BT_SEND_FILE_MAX_CHUNK_SIZE,
+ (int)(stlc2690_info->fw_file->size -
+ stlc2690_info->file_offset));
+
+ if (bytes_to_copy <= 0) {
+ /* Nothing more to read in file. */
+ SET_DOWNLOAD_STATE(DOWNLOAD_SUCCESS);
+ stlc2690_info->chunk_id = 0;
+ stlc2690_info->file_offset = 0;
+ return;
+ }
+
+ /* There is more data to send */
+ logger_config = cg2900_get_hci_logger_config();
+
+ /* There are bytes to transmit. Allocate a sk_buffer. */
+ plen = sizeof(*cmd) - 1 + bytes_to_copy;
+ skb = cg2900_alloc_skb(sizeof(*hdr) + plen, GFP_ATOMIC);
+ if (!skb) {
+ CG2900_ERR("Couldn't allocate sk_buffer");
+ SET_BOOT_STATE(BOOT_FAILED);
+ cg2900_chip_startup_finished(-EIO);
+ return;
+ }
+
+ skb_put(skb, sizeof(*hdr) + plen);
+
+ data = skb->data;
+ hdr = (struct hci_command_hdr *)data;
+ hdr->opcode = cpu_to_le16(STLC2690_BT_OP_VS_WRITE_FILE_BLOCK);
+ hdr->plen = plen;
+
+ data += sizeof(*hdr);
+ cmd = (struct bt_vs_write_file_block_cmd *)data;
+ cmd->id = stlc2690_info->chunk_id;
+ stlc2690_info->chunk_id++;
+
+ /* Copy the data from offset position */
+ memcpy(&(cmd->data),
+ &(stlc2690_info->fw_file->data[stlc2690_info->file_offset]),
+ bytes_to_copy);
+
+ /* Increase offset with number of bytes copied */
+ stlc2690_info->file_offset += bytes_to_copy;
+
+ skb_push(skb, CG2900_SKB_RESERVE);
+ skb->data[0] = CHANNEL_BT_CMD;
+
+ if (logger_config)
+ cg2900_send_to_chip(skb, logger_config->bt_cmd_enable);
+ else
+ cg2900_send_to_chip(skb, false);
+}
+
+/**
+ * send_settings_file() - Transmit settings file.
+ *
+ * The send_settings_file() function transmit settings file.
+ * The file is read in parts to fit in HCI packets.
+ * When finished, close the settings file and send HCI reset to activate
+ * settings and patches.
+ */
+static void send_settings_file(void)
+{
+ /* Transmit a file part */
+ read_and_send_file_part();
+
+ if (stlc2690_info->download_state != DOWNLOAD_SUCCESS)
+ return;
+
+ /* Settings file finished. Release used resources */
+ CG2900_DBG("Settings file finished, release used resources");
+
+ if (stlc2690_info->fw_file) {
+ release_firmware(stlc2690_info->fw_file);
+ stlc2690_info->fw_file = NULL;
+ }
+
+ SET_FILE_LOAD_STATE(FILE_LOAD_NO_MORE_FILES);
+
+ /* Create and send HCI VS Store In FS command with bd address. */
+ send_bd_address();
+}
+
+/**
+ * send_patch_file - Transmit patch file.
+ *
+ * The send_patch_file() function transmit patch file. The file is read in parts
+ * to fit in HCI packets.
+ * When the complete file is transmitted, the file is closed.
+ * When finished, continue with settings file.
+ */
+static void send_patch_file(void)
+{
+ int err;
+
+ /*
+ * Transmit a part of the supplied file to the controller.
+ * When nothing more to read, continue to close the patch file.
+ */
+ read_and_send_file_part();
+
+ if (stlc2690_info->download_state != DOWNLOAD_SUCCESS)
+ return;
+
+ /* Patch file finished. Release used resources */
+ CG2900_DBG("Patch file finished, release used resources");
+
+ if (stlc2690_info->fw_file) {
+ release_firmware(stlc2690_info->fw_file);
+ stlc2690_info->fw_file = NULL;
+ }
+
+ err = request_firmware(&(stlc2690_info->fw_file),
+ stlc2690_info->settings_file_name,
+ stlc2690_info->chip_dev.dev);
+ if (err < 0) {
+ CG2900_ERR("Couldn't get settings file (%d)", err);
+ goto error_handling;
+ }
+
+ /* Now send the settings file */
+ SET_FILE_LOAD_STATE(FILE_LOAD_GET_STATIC_SETTINGS);
+ SET_DOWNLOAD_STATE(DOWNLOAD_PENDING);
+ send_settings_file();
+ return;
+
+error_handling:
+ SET_BOOT_STATE(BOOT_FAILED);
+ cg2900_chip_startup_finished(err);
+}
+
+/**
+ * work_reset_after_error() - Handle reset.
+ * @work: Reference to work data.
+ *
+ * Handle a reset after received command complete event.
+ */
+static void work_reset_after_error(struct work_struct *work)
+{
+ struct stlc2690_work_struct *current_work = NULL;
+
+ if (!work) {
+ CG2900_ERR("work == NULL");
+ return;
+ }
+
+ current_work = container_of(work, struct stlc2690_work_struct, work);
+
+ cg2900_chip_startup_finished(-EIO);
+
+ kfree(current_work);
+}
+
+/**
+ * work_load_patch_and_settings() - Start loading patches and settings.
+ * @work: Reference to work data.
+ */
+static void work_load_patch_and_settings(struct work_struct *work)
+{
+ struct stlc2690_work_struct *current_work;
+ int err = 0;
+ bool file_found;
+ const struct firmware *patch_info;
+ const struct firmware *settings_info;
+
+ if (!work) {
+ CG2900_ERR("work == NULL");
+ return;
+ }
+
+ current_work = container_of(work, struct stlc2690_work_struct, work);
+
+ /* Check that we are in the right state */
+ if (stlc2690_info->boot_state != BOOT_GET_FILES_TO_LOAD)
+ goto finished;
+
+ /* Open patch info file. */
+ err = request_firmware(&patch_info, PATCH_INFO_FILE,
+ stlc2690_info->chip_dev.dev);
+ if (err) {
+ CG2900_ERR("Couldn't get patch info file (%d)", err);
+ goto error_handling;
+ }
+
+ /*
+ * Now we have the patch info file.
+ * See if we can find the right patch file as well
+ */
+ file_found = get_file_to_load(patch_info,
+ &(stlc2690_info->patch_file_name));
+
+ /* Now we are finished with the patch info file */
+ release_firmware(patch_info);
+
+ if (!file_found) {
+ CG2900_ERR("Couldn't find patch file! Major error!");
+ goto error_handling;
+ }
+
+ /* Open settings info file. */
+ err = request_firmware(&settings_info, FACTORY_SETTINGS_INFO_FILE,
+ stlc2690_info->chip_dev.dev);
+ if (err) {
+ CG2900_ERR("Couldn't get settings info file (%d)", err);
+ goto error_handling;
+ }
+
+ /*
+ * Now we have the settings info file.
+ * See if we can find the right settings file as well
+ */
+ file_found = get_file_to_load(settings_info,
+ &(stlc2690_info->settings_file_name));
+
+ /* Now we are finished with the patch info file */
+ release_firmware(settings_info);
+
+ if (!file_found) {
+ CG2900_ERR("Couldn't find settings file! Major error!");
+ goto error_handling;
+ }
+
+ /* We now all info needed */
+ SET_BOOT_STATE(BOOT_DOWNLOAD_PATCH);
+ SET_DOWNLOAD_STATE(DOWNLOAD_PENDING);
+ SET_FILE_LOAD_STATE(FILE_LOAD_GET_PATCH);
+ stlc2690_info->chunk_id = 0;
+ stlc2690_info->file_offset = 0;
+ stlc2690_info->fw_file = NULL;
+
+ /* OK. Now it is time to download the patches */
+ err = request_firmware(&(stlc2690_info->fw_file),
+ stlc2690_info->patch_file_name,
+ stlc2690_info->chip_dev.dev);
+ if (err < 0) {
+ CG2900_ERR("Couldn't get patch file (%d)", err);
+ goto error_handling;
+ }
+ send_patch_file();
+
+ goto finished;
+
+error_handling:
+ SET_BOOT_STATE(BOOT_FAILED);
+ cg2900_chip_startup_finished(-EIO);
+finished:
+ kfree(current_work);
+}
+
+/**
+ * work_cont_with_file_download() - A file block has been written.
+ * @work: Reference to work data.
+ *
+ * Handle a received HCI VS Write File Block Complete event.
+ * Normally this means continue to send files to the controller.
+ */
+static void work_cont_with_file_download(struct work_struct *work)
+{
+ struct stlc2690_work_struct *current_work;
+
+ if (!work) {
+ CG2900_ERR("work == NULL");
+ return;
+ }
+
+ current_work = container_of(work, struct stlc2690_work_struct, work);
+
+ /* Continue to send patches or settings to the controller */
+ if (stlc2690_info->file_load_state == FILE_LOAD_GET_PATCH)
+ send_patch_file();
+ else if (stlc2690_info->file_load_state ==
+ FILE_LOAD_GET_STATIC_SETTINGS)
+ send_settings_file();
+ else
+ CG2900_INFO("No more files to load");
+
+ kfree(current_work);
+}
+
+/**
+ * handle_reset_cmd_complete() - Handle a received HCI Command Complete event for a Reset command.
+ * @data: Pointer to received HCI data packet.
+ *
+ * Returns:
+ * True, if packet was handled internally,
+ * False, otherwise.
+ */
+static bool handle_reset_cmd_complete(u8 *data)
+{
+ u8 status;
+
+ CG2900_INFO("Received Reset complete event");
+
+ if (stlc2690_info->boot_state != BOOT_ACTIVATE_PATCHES_AND_SETTINGS)
+ return false;
+
+ status = data[0];
+
+ if (HCI_BT_ERROR_NO_ERROR == status) {
+ /*
+ * The boot sequence is now finished successfully.
+ * Set states and signal to waiting thread.
+ */
+ SET_BOOT_STATE(BOOT_READY);
+ cg2900_chip_startup_finished(0);
+ } else {
+ CG2900_ERR("Received Reset complete event with status 0x%X",
+ status);
+ SET_BOOT_STATE(BOOT_FAILED);
+ cg2900_chip_startup_finished(-EIO);
+ }
+ return true;
+}
+
+/**
+ * handle_vs_store_in_fs_cmd_complete() - Handle a received HCI Command Complete event for a VS StoreInFS command.
+ * @data: Pointer to received HCI data packet.
+ *
+ * Returns:
+ * True, if packet was handled internally,
+ * False, otherwise.
+ */
+static bool handle_vs_store_in_fs_cmd_complete(u8 *data)
+{
+ u8 status;
+
+ CG2900_INFO("Received Store_in_FS complete event");
+
+ if (stlc2690_info->boot_state != BOOT_SEND_BD_ADDRESS)
+ return false;
+
+ status = data[0];
+
+ if (HCI_BT_ERROR_NO_ERROR == status) {
+ struct hci_command_hdr cmd;
+
+ /* Send HCI Reset command to activate patches */
+ SET_BOOT_STATE(BOOT_ACTIVATE_PATCHES_AND_SETTINGS);
+ cmd.opcode = cpu_to_le16(HCI_OP_RESET);
+ cmd.plen = 0; /* No parameters for HCI Reset */
+ create_and_send_bt_cmd(&cmd, sizeof(cmd));
+ } else {
+ CG2900_ERR("Command Complete for StoreInFS received with "
+ "error 0x%X", status);
+ SET_BOOT_STATE(BOOT_FAILED);
+ create_work_item(work_reset_after_error, NULL, NULL);
+ }
+ /* We have now handled the packet */
+ return true;
+}
+
+/**
+ * handle_vs_write_file_block_cmd_complete() - Handle a received HCI Command Complete event for a VS WriteFileBlock command.
+ * @data: Pointer to received HCI data packet.
+ *
+ * Returns:
+ * True, if packet was handled internally,
+ * False, otherwise.
+ */
+static bool handle_vs_write_file_block_cmd_complete(u8 *data)
+{
+ u8 status;
+
+ if ((stlc2690_info->boot_state != BOOT_DOWNLOAD_PATCH) ||
+ (stlc2690_info->download_state != DOWNLOAD_PENDING))
+ return false;
+
+ status = data[0];
+ if (HCI_BT_ERROR_NO_ERROR == status) {
+ /* Received good confirmation. Start work to continue. */
+ create_work_item(work_cont_with_file_download, NULL, NULL);
+ } else {
+ CG2900_ERR("Command Complete for WriteFileBlock received with "
+ "error 0x%X", status);
+ SET_DOWNLOAD_STATE(DOWNLOAD_FAILED);
+ SET_BOOT_STATE(BOOT_FAILED);
+ if (stlc2690_info->fw_file) {
+ release_firmware(stlc2690_info->fw_file);
+ stlc2690_info->fw_file = NULL;
+ }
+ create_work_item(work_reset_after_error, NULL, NULL);
+ }
+ /* We have now handled the packet */
+ return true;
+}
+
+/**
+ * handle_rx_data_bt_evt() - Check if received data should be handled.
+ * @skb: Data packet
+ *
+ * The handle_rx_data_bt_evt() function checks if received data should be
+ * handled by STLC2690. If so handle it correctly.
+ * Received data is always HCI BT Event.
+ *
+ * Returns:
+ * True, if packet was handled internally,
+ * False, otherwise.
+ */
+static bool handle_rx_data_bt_evt(struct sk_buff *skb)
+{
+ bool pkt_handled = false;
+ /* skb cannot be NULL here so it is safe to de-reference */
+ u8 *data = &(skb->data[CG2900_SKB_RESERVE]);
+ struct hci_event_hdr *evt;
+ struct hci_ev_cmd_complete *cmd_complete;
+ u16 op_code;
+
+ evt = (struct hci_event_hdr *)data;
+
+ /* First check the event code. Only handle Command Complete Event */
+ if (HCI_EV_CMD_COMPLETE != evt->evt)
+ return false;
+
+ data += sizeof(*evt);
+ cmd_complete = (struct hci_ev_cmd_complete *)data;
+
+ op_code = le16_to_cpu(cmd_complete->opcode);
+
+ CG2900_DBG_DATA("Received Command Complete: op_code = 0x%04X", op_code);
+ data += sizeof(*cmd_complete); /* Move to first byte after OCF */
+
+ if (op_code == HCI_OP_RESET)
+ pkt_handled = handle_reset_cmd_complete(data);
+ else if (op_code == STLC2690_BT_OP_VS_STORE_IN_FS)
+ pkt_handled = handle_vs_store_in_fs_cmd_complete(data);
+ else if (op_code == STLC2690_BT_OP_VS_WRITE_FILE_BLOCK)
+ pkt_handled = handle_vs_write_file_block_cmd_complete(data);
+
+ if (pkt_handled)
+ kfree_skb(skb);
+
+ return pkt_handled;
+}
+
+/**
+ * chip_startup() - Start the chip.
+ * @dev: Chip info.
+ *
+ * The chip_startup() function downloads patches and other needed start
+ * procedures.
+ *
+ * Returns:
+ * 0 if there is no error.
+ */
+static int chip_startup(struct cg2900_chip_dev *dev)
+{
+ /* Start the boot sequence */
+ SET_BOOT_STATE(BOOT_GET_FILES_TO_LOAD);
+ create_work_item(work_load_patch_and_settings, NULL, NULL);
+
+ return 0;
+}
+
+/**
+ * data_from_chip() - Called when data shall be sent to the chip.
+ * @dev: Chip info.
+ * @cg2900_dev: CG2900 user for this packet.
+ * @skb: Packet received.
+ *
+ * The data_from_chip() function checks if packet is a response for a packet it
+ * itself has transmitted.
+ *
+ * Returns:
+ * true if packet is handled by this driver.
+ * false otherwise.
+ */
+static bool data_from_chip(struct cg2900_chip_dev *dev,
+ struct cg2900_device *cg2900_dev,
+ struct sk_buff *skb)
+{
+ /* Then check if this is a response to data we have sent */
+ return handle_rx_data_bt_evt(skb);
+}
+
+/**
+ * get_h4_channel() - Returns H:4 channel for the name.
+ * @name: Chip info.
+ * @h4_channel: CG2900 user for this packet.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -ENXIO if channel is not found.
+ */
+static int get_h4_channel(char *name, int *h4_channel)
+{
+ int i;
+ int err = -ENXIO;
+
+ *h4_channel = -1;
+
+ for (i = 0; *h4_channel == -1 && i < NBR_OF_DEVS; i++) {
+ if (0 == strncmp(name, stlc2690_channels[i].name,
+ CG2900_MAX_NAME_SIZE)) {
+ /* Device found. Return H4 channel */
+ *h4_channel = stlc2690_channels[i].h4_channel;
+ err = 0;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * check_chip_support() - Checks if connected chip is handled by this driver.
+ * @dev: Chip info structure.
+ *
+ * If supported return true and fill in @callbacks.
+ *
+ * Returns:
+ * true if chip is handled by this driver.
+ * false otherwise.
+ */
+static bool check_chip_support(struct cg2900_chip_dev *dev)
+{
+ CG2900_INFO("check_chip_support");
+
+ /*
+ * Check if this is a CG2690 revision. We do not care about
+ * the sub-version at the moment.
+ * Change this if necessary.
+ */
+ if ((dev->chip.manufacturer != SUPP_MANUFACTURER) ||
+ (dev->chip.hci_revision < SUPP_REVISION_MIN) ||
+ (dev->chip.hci_revision > SUPP_REVISION_MAX)) {
+ CG2900_DBG("Chip not supported by STLC2690 driver\n"
+ "\tMan: 0x%02X\n"
+ "\tRev: 0x%04X\n"
+ "\tSub: 0x%04X",
+ dev->chip.manufacturer, dev->chip.hci_revision,
+ dev->chip.hci_sub_version);
+ return false;
+ }
+
+ CG2900_INFO("Chip supported by the STLC2690 driver");
+
+ /* Store needed data */
+ dev->user_data = stlc2690_info;
+ memcpy(&(stlc2690_info->chip_dev), dev, sizeof(*dev));
+ /* Set the callbacks */
+ dev->cb.chip_startup = chip_startup;
+ dev->cb.data_from_chip = data_from_chip;
+ dev->cb.get_h4_channel = get_h4_channel;
+
+ return true;
+}
+
+static struct cg2900_id_callbacks stlc2690_id_callbacks = {
+ .check_chip_support = check_chip_support
+};
+
+/**
+ * stlc2690_init() - Initialize module.
+ *
+ * The stlc2690_init() function initialize the CG2690 driver, then register to
+ * the CG2900 Core.
+ *
+ * Returns:
+ * 0 if success.
+ * -ENOMEM for failed alloc or structure creation.
+ * Error codes generated by cg2900_register_chip_driver.
+ */
+static int __init stlc2690_init(void)
+{
+ int err = 0;
+
+ CG2900_INFO("stlc2690_init");
+
+ stlc2690_info = kzalloc(sizeof(*stlc2690_info), GFP_ATOMIC);
+ if (!stlc2690_info) {
+ CG2900_ERR("Couldn't allocate stlc2690_info");
+ err = -ENOMEM;
+ goto finished;
+ }
+
+ stlc2690_info->wq = create_singlethread_workqueue(WQ_NAME);
+ if (!stlc2690_info->wq) {
+ CG2900_ERR("Could not create workqueue");
+ err = -ENOMEM;
+ goto err_handling_free_info;
+ }
+
+ /*
+ * Allocate file names that will be used, deallocated in stlc2690_exit.
+ */
+ stlc2690_info->patch_file_name = kzalloc(FILENAME_MAX + 1, GFP_ATOMIC);
+ if (!stlc2690_info->patch_file_name) {
+ CG2900_ERR("Couldn't allocate name buffer for patch file.");
+ err = -ENOMEM;
+ goto err_handling_destroy_wq;
+ }
+ /*
+ * Allocate file names that will be used, deallocated in stlc2690_exit.
+ */
+ stlc2690_info->settings_file_name = kzalloc(FILENAME_MAX + 1,
+ GFP_ATOMIC);
+ if (!stlc2690_info->settings_file_name) {
+ CG2900_ERR("Couldn't allocate name buffers settings file.");
+ err = -ENOMEM;
+ goto err_handling_free_patch_name;
+ }
+
+ err = cg2900_register_chip_driver(&stlc2690_id_callbacks);
+ if (err) {
+ CG2900_ERR("Couldn't register chip driver (%d)", err);
+ goto err_handling_free_settings_name;
+ }
+
+ goto finished;
+
+err_handling_free_settings_name:
+ kfree(stlc2690_info->settings_file_name);
+err_handling_free_patch_name:
+ kfree(stlc2690_info->patch_file_name);
+err_handling_destroy_wq:
+ destroy_workqueue(stlc2690_info->wq);
+err_handling_free_info:
+ kfree(stlc2690_info);
+ stlc2690_info = NULL;
+finished:
+ return err;
+}
+
+/**
+ * stlc2690_exit() - Remove module.
+ */
+static void __exit stlc2690_exit(void)
+{
+ CG2900_INFO("stlc2690_exit");
+
+ if (!stlc2690_info)
+ return;
+
+ kfree(stlc2690_info->settings_file_name);
+ kfree(stlc2690_info->patch_file_name);
+ destroy_workqueue(stlc2690_info->wq);
+ kfree(stlc2690_info);
+ stlc2690_info = NULL;
+}
+
+module_init(stlc2690_init);
+module_exit(stlc2690_exit);
+
+MODULE_AUTHOR("Par-Gunnar Hjalmdahl ST-Ericsson");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Linux STLC2690 Connectivity Device Driver");
diff --git a/drivers/mfd/cg2900/stlc2690_chip.h b/drivers/mfd/cg2900/stlc2690_chip.h
new file mode 100644
index 00000000000..deb974d6724
--- /dev/null
+++ b/drivers/mfd/cg2900/stlc2690_chip.h
@@ -0,0 +1,37 @@
+/*
+ * drivers/mfd/cg2900/stlc2690_chip.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth HCI H:4 Driver for ST-Ericsson STLC2690 BT/FM controller.
+ */
+
+#ifndef _STLC2690_CHIP_H_
+#define _STLC2690_CHIP_H_
+
+/* BT VS Store In FS command */
+#define STLC2690_BT_OP_VS_STORE_IN_FS 0xFC22
+struct bt_vs_store_in_fs_cmd {
+ __u8 user_id;
+ __u8 len;
+ __u8 data; /* Really a data array of variable size */
+} __attribute__((packed));
+
+/* BT VS Write File Block command */
+#define STLC2690_BT_OP_VS_WRITE_FILE_BLOCK 0xFC2E
+struct bt_vs_write_file_block_cmd {
+ __u8 id;
+ __u8 data; /* Really a data array of variable size */
+} __attribute__((packed));
+
+/* User ID for storing BD address in chip using Store_In_FS command */
+#define STLC2690_VS_STORE_IN_FS_USR_ID_BD_ADDR 0xFE
+
+#endif /* _STLC2690_CHIP_H_ */
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
new file mode 100644
index 00000000000..b11487f1e1c
--- /dev/null
+++ b/drivers/mfd/stmpe.c
@@ -0,0 +1,1017 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/stmpe.h>
+#include "stmpe.h"
+
+static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
+{
+ return stmpe->variant->enable(stmpe, blocks, true);
+}
+
+static int __stmpe_disable(struct stmpe *stmpe, unsigned int blocks)
+{
+ return stmpe->variant->enable(stmpe, blocks, false);
+}
+
+static int __stmpe_reg_read(struct stmpe *stmpe, u8 reg)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(stmpe->i2c, reg);
+ if (ret < 0)
+ dev_err(stmpe->dev, "failed to read reg %#x: %d\n",
+ reg, ret);
+
+ dev_vdbg(stmpe->dev, "rd: reg %#x => data %#x\n", reg, ret);
+
+ return ret;
+}
+
+static int __stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
+{
+ int ret;
+
+ dev_vdbg(stmpe->dev, "wr: reg %#x <= %#x\n", reg, val);
+
+ ret = i2c_smbus_write_byte_data(stmpe->i2c, reg, val);
+ if (ret < 0)
+ dev_err(stmpe->dev, "failed to write reg %#x: %d\n",
+ reg, ret);
+
+ return ret;
+}
+
+static int __stmpe_set_bits(struct stmpe *stmpe, u8 reg, u8 mask, u8 val)
+{
+ int ret;
+
+ ret = __stmpe_reg_read(stmpe, reg);
+ if (ret < 0)
+ return ret;
+
+ ret &= ~mask;
+ ret |= val;
+
+ return __stmpe_reg_write(stmpe, reg, ret);
+}
+
+static int __stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length,
+ u8 *values)
+{
+ int ret;
+
+ ret = i2c_smbus_read_i2c_block_data(stmpe->i2c, reg, length, values);
+ if (ret < 0)
+ dev_err(stmpe->dev, "failed to read regs %#x: %d\n",
+ reg, ret);
+
+ dev_vdbg(stmpe->dev, "rd: reg %#x (%d) => ret %#x\n", reg, length, ret);
+ stmpe_dump_bytes("stmpe rd: ", values, length);
+
+ return ret;
+}
+
+static int __stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
+ const u8 *values)
+{
+ int ret;
+
+ dev_vdbg(stmpe->dev, "wr: regs %#x (%d)\n", reg, length);
+ stmpe_dump_bytes("stmpe wr: ", values, length);
+
+ ret = i2c_smbus_write_i2c_block_data(stmpe->i2c, reg, length,
+ values);
+ if (ret < 0)
+ dev_err(stmpe->dev, "failed to write regs %#x: %d\n",
+ reg, ret);
+
+ return ret;
+}
+
+/**
+ * stmpe_enable - enable blocks on an STMPE device
+ * @stmpe: Device to work on
+ * @blocks: Mask of blocks (enum stmpe_block values) to enable
+ */
+int stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
+{
+ int ret;
+
+ mutex_lock(&stmpe->lock);
+ ret = __stmpe_enable(stmpe, blocks);
+ mutex_unlock(&stmpe->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_enable);
+
+/**
+ * stmpe_disable - disable blocks on an STMPE device
+ * @stmpe: Device to work on
+ * @blocks: Mask of blocks (enum stmpe_block values) to enable
+ */
+int stmpe_disable(struct stmpe *stmpe, unsigned int blocks)
+{
+ int ret;
+
+ mutex_lock(&stmpe->lock);
+ ret = __stmpe_disable(stmpe, blocks);
+ mutex_unlock(&stmpe->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_disable);
+
+/**
+ * stmpe_reg_read() - read a single STMPE register
+ * @stmpe: Device to read from
+ * @reg: Register to read
+ */
+int stmpe_reg_read(struct stmpe *stmpe, u8 reg)
+{
+ int ret;
+
+ mutex_lock(&stmpe->lock);
+ ret = __stmpe_reg_read(stmpe, reg);
+ mutex_unlock(&stmpe->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_reg_read);
+
+/**
+ * stmpe_reg_write() - write a single STMPE register
+ * @stmpe: Device to write to
+ * @reg: Register to write
+ * @val: Value to write
+ */
+int stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
+{
+ int ret;
+
+ mutex_lock(&stmpe->lock);
+ ret = __stmpe_reg_write(stmpe, reg, val);
+ mutex_unlock(&stmpe->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_reg_write);
+
+/**
+ * stmpe_set_bits() - set the value of a bitfield in a STMPE register
+ * @stmpe: Device to write to
+ * @reg: Register to write
+ * @mask: Mask of bits to set
+ * @val: Value to set
+ */
+int stmpe_set_bits(struct stmpe *stmpe, u8 reg, u8 mask, u8 val)
+{
+ int ret;
+
+ mutex_lock(&stmpe->lock);
+ ret = __stmpe_set_bits(stmpe, reg, mask, val);
+ mutex_unlock(&stmpe->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_set_bits);
+
+/**
+ * stmpe_block_read() - read multiple STMPE registers
+ * @stmpe: Device to read from
+ * @reg: First register
+ * @length: Number of registers
+ * @values: Buffer to write to
+ */
+int stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values)
+{
+ int ret;
+
+ mutex_lock(&stmpe->lock);
+ ret = __stmpe_block_read(stmpe, reg, length, values);
+ mutex_unlock(&stmpe->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_block_read);
+
+/**
+ * stmpe_block_write() - write multiple STMPE registers
+ * @stmpe: Device to write to
+ * @reg: First register
+ * @length: Number of registers
+ * @values: Values to write
+ */
+int stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
+ const u8 *values)
+{
+ int ret;
+
+ mutex_lock(&stmpe->lock);
+ ret = __stmpe_block_write(stmpe, reg, length, values);
+ mutex_unlock(&stmpe->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_block_write);
+
+/**
+ * stmpe_set_altfunc: set the alternate function for STMPE pins
+ * @stmpe: Device to configure
+ * @pins: Bitmask of pins to affect
+ * @block: block to enable alternate functions for
+ *
+ * @pins is assumed to have a bit set for each of the bits whose alternate
+ * function is to be changed, numbered according to the GPIOXY numbers.
+ *
+ * If the GPIO module is not enabled, this function automatically enables it in
+ * order to perform the change.
+ */
+int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins, enum stmpe_block block)
+{
+ struct stmpe_variant_info *variant = stmpe->variant;
+ u8 regaddr = stmpe->regs[STMPE_IDX_GPAFR_U_MSB];
+ int af_bits = variant->af_bits;
+ int numregs = DIV_ROUND_UP(stmpe->num_gpios * af_bits, 8);
+ int afperreg = 8 / af_bits;
+ int mask = (1 << af_bits) - 1;
+ u8 regs[numregs];
+ int af;
+ int ret;
+
+ mutex_lock(&stmpe->lock);
+
+ ret = __stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
+ if (ret < 0)
+ goto out;
+
+ ret = __stmpe_block_read(stmpe, regaddr, numregs, regs);
+ if (ret < 0)
+ goto out;
+
+ af = variant->get_altfunc(stmpe, block);
+
+ while (pins) {
+ int pin = __ffs(pins);
+ int regoffset = numregs - (pin / afperreg) - 1;
+ int pos = (pin % afperreg) * (8 / afperreg);
+
+ regs[regoffset] &= ~(mask << pos);
+ regs[regoffset] |= af << pos;
+
+ pins &= ~(1 << pin);
+ }
+
+ ret = __stmpe_block_write(stmpe, regaddr, numregs, regs);
+
+out:
+ mutex_unlock(&stmpe->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_set_altfunc);
+
+/*
+ * GPIO (all variants)
+ */
+
+static struct resource stmpe_gpio_resources[] = {
+ /* Start and end filled dynamically */
+ {
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell stmpe_gpio_cell = {
+ .name = "stmpe-gpio",
+ .resources = stmpe_gpio_resources,
+ .num_resources = ARRAY_SIZE(stmpe_gpio_resources),
+};
+
+/*
+ * Keypad (1601, 2401, 2403)
+ */
+
+static struct resource stmpe_keypad_resources[] = {
+ {
+ .name = "KEYPAD",
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "KEYPAD_OVER",
+ .start = 1,
+ .end = 1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell stmpe_keypad_cell = {
+ .name = "stmpe-keypad",
+ .resources = stmpe_keypad_resources,
+ .num_resources = ARRAY_SIZE(stmpe_keypad_resources),
+};
+
+/*
+ * Touchscreen (STMPE811)
+ */
+
+static struct resource stmpe_ts_resources[] = {
+ {
+ .name = "TOUCH_DET",
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "FIFO_TH",
+ .start = 1,
+ .end = 1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell stmpe_ts_cell = {
+ .name = "stmpe-ts",
+ .resources = stmpe_ts_resources,
+ .num_resources = ARRAY_SIZE(stmpe_ts_resources),
+};
+
+/*
+ * STMPE811
+ */
+
+static const u8 stmpe811_regs[] = {
+ [STMPE_IDX_CHIP_ID] = STMPE811_REG_CHIP_ID,
+ [STMPE_IDX_ICR_LSB] = STMPE811_REG_INT_CTRL,
+ [STMPE_IDX_IER_LSB] = STMPE811_REG_INT_EN,
+ [STMPE_IDX_ISR_MSB] = STMPE811_REG_INT_STA,
+ [STMPE_IDX_GPMR_LSB] = STMPE811_REG_GPIO_MP_STA,
+ [STMPE_IDX_GPSR_LSB] = STMPE811_REG_GPIO_SET_PIN,
+ [STMPE_IDX_GPCR_LSB] = STMPE811_REG_GPIO_CLR_PIN,
+ [STMPE_IDX_GPDR_LSB] = STMPE811_REG_GPIO_DIR,
+ [STMPE_IDX_GPRER_LSB] = STMPE811_REG_GPIO_RE,
+ [STMPE_IDX_GPFER_LSB] = STMPE811_REG_GPIO_FE,
+ [STMPE_IDX_GPAFR_U_MSB] = STMPE811_REG_GPIO_AF,
+ [STMPE_IDX_IEGPIOR_LSB] = STMPE811_REG_GPIO_INT_EN,
+ [STMPE_IDX_ISGPIOR_MSB] = STMPE811_REG_GPIO_INT_STA,
+ [STMPE_IDX_GPEDR_MSB] = STMPE811_REG_GPIO_ED,
+};
+
+static struct stmpe_variant_block stmpe811_blocks[] = {
+ {
+ .cell = &stmpe_gpio_cell,
+ .irq = STMPE811_IRQ_GPIOC,
+ .block = STMPE_BLOCK_GPIO,
+ },
+ {
+ .cell = &stmpe_ts_cell,
+ .irq = STMPE811_IRQ_TOUCH_DET,
+ .block = STMPE_BLOCK_TOUCHSCREEN,
+ },
+};
+
+static int stmpe811_enable(struct stmpe *stmpe, unsigned int blocks,
+ bool enable)
+{
+ unsigned int mask = 0;
+
+ if (blocks & STMPE_BLOCK_GPIO)
+ mask |= STMPE811_SYS_CTRL2_GPIO_OFF;
+
+ if (blocks & STMPE_BLOCK_ADC)
+ mask |= STMPE811_SYS_CTRL2_ADC_OFF;
+
+ if (blocks & STMPE_BLOCK_TOUCHSCREEN)
+ mask |= STMPE811_SYS_CTRL2_TSC_OFF;
+
+ return __stmpe_set_bits(stmpe, STMPE811_REG_SYS_CTRL2, mask,
+ enable ? 0 : mask);
+}
+
+static int stmpe811_get_altfunc(struct stmpe *stmpe, enum stmpe_block block)
+{
+ /* 0 for touchscreen, 1 for GPIO */
+ return block != STMPE_BLOCK_TOUCHSCREEN;
+}
+
+static struct stmpe_variant_info stmpe811 = {
+ .name = "stmpe811",
+ .id_val = 0x0811,
+ .id_mask = 0xffff,
+ .num_gpios = 8,
+ .af_bits = 1,
+ .regs = stmpe811_regs,
+ .blocks = stmpe811_blocks,
+ .num_blocks = ARRAY_SIZE(stmpe811_blocks),
+ .num_irqs = STMPE811_NR_INTERNAL_IRQS,
+ .enable = stmpe811_enable,
+ .get_altfunc = stmpe811_get_altfunc,
+};
+
+/*
+ * STMPE1601
+ */
+
+static const u8 stmpe1601_regs[] = {
+ [STMPE_IDX_CHIP_ID] = STMPE1601_REG_CHIP_ID,
+ [STMPE_IDX_ICR_LSB] = STMPE1601_REG_ICR_LSB,
+ [STMPE_IDX_IER_LSB] = STMPE1601_REG_IER_LSB,
+ [STMPE_IDX_ISR_MSB] = STMPE1601_REG_ISR_MSB,
+ [STMPE_IDX_GPMR_LSB] = STMPE1601_REG_GPIO_MP_LSB,
+ [STMPE_IDX_GPSR_LSB] = STMPE1601_REG_GPIO_SET_LSB,
+ [STMPE_IDX_GPCR_LSB] = STMPE1601_REG_GPIO_CLR_LSB,
+ [STMPE_IDX_GPDR_LSB] = STMPE1601_REG_GPIO_SET_DIR_LSB,
+ [STMPE_IDX_GPRER_LSB] = STMPE1601_REG_GPIO_RE_LSB,
+ [STMPE_IDX_GPFER_LSB] = STMPE1601_REG_GPIO_FE_LSB,
+ [STMPE_IDX_GPAFR_U_MSB] = STMPE1601_REG_GPIO_AF_U_MSB,
+ [STMPE_IDX_IEGPIOR_LSB] = STMPE1601_REG_INT_EN_GPIO_MASK_LSB,
+ [STMPE_IDX_ISGPIOR_MSB] = STMPE1601_REG_INT_STA_GPIO_MSB,
+ [STMPE_IDX_GPEDR_MSB] = STMPE1601_REG_GPIO_ED_MSB,
+};
+
+static struct stmpe_variant_block stmpe1601_blocks[] = {
+ {
+ .cell = &stmpe_gpio_cell,
+ .irq = STMPE24XX_IRQ_GPIOC,
+ .block = STMPE_BLOCK_GPIO,
+ },
+ {
+ .cell = &stmpe_keypad_cell,
+ .irq = STMPE24XX_IRQ_KEYPAD,
+ .block = STMPE_BLOCK_KEYPAD,
+ },
+};
+
+/* supported autosleep timeout delay (in msecs) */
+static const int stmpe_autosleep_delay[] = {
+ 4, 16, 32, 64, 128, 256, 512, 1024,
+};
+
+static int stmpe_round_timeout(int timeout)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(stmpe_autosleep_delay); i++) {
+ if (stmpe_autosleep_delay[i] >= timeout)
+ return i;
+ }
+
+ /*
+ * requests for delays longer than supported should not return the
+ * longest supported delay
+ */
+ return -EINVAL;
+}
+
+static int stmpe_autosleep(struct stmpe *stmpe, int autosleep_timeout)
+{
+ int ret;
+
+ if (!stmpe->variant->enable_autosleep)
+ return -ENOSYS;
+
+ mutex_lock(&stmpe->lock);
+ ret = stmpe->variant->enable_autosleep(stmpe, autosleep_timeout);
+ mutex_unlock(&stmpe->lock);
+
+ return ret;
+}
+
+/*
+ * Both stmpe 1601/2403 support same layout for autosleep
+ */
+static int stmpe1601_autosleep(struct stmpe *stmpe,
+ int autosleep_timeout)
+{
+ int ret, timeout;
+
+ /* choose the best available timeout */
+ timeout = stmpe_round_timeout(autosleep_timeout);
+ if (timeout < 0) {
+ dev_err(stmpe->dev, "invalid timeout\n");
+ return timeout;
+ }
+
+ ret = __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2,
+ STMPE1601_AUTOSLEEP_TIMEOUT_MASK,
+ timeout);
+ if (ret < 0)
+ return ret;
+
+ return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2,
+ STPME1601_AUTOSLEEP_ENABLE,
+ STPME1601_AUTOSLEEP_ENABLE);
+}
+
+static int stmpe1601_enable(struct stmpe *stmpe, unsigned int blocks,
+ bool enable)
+{
+ unsigned int mask = 0;
+
+ if (blocks & STMPE_BLOCK_GPIO)
+ mask |= STMPE1601_SYS_CTRL_ENABLE_GPIO;
+
+ if (blocks & STMPE_BLOCK_KEYPAD)
+ mask |= STMPE1601_SYS_CTRL_ENABLE_KPC;
+
+ return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL, mask,
+ enable ? mask : 0);
+}
+
+static int stmpe1601_get_altfunc(struct stmpe *stmpe, enum stmpe_block block)
+{
+ switch (block) {
+ case STMPE_BLOCK_PWM:
+ return 2;
+
+ case STMPE_BLOCK_KEYPAD:
+ return 1;
+
+ case STMPE_BLOCK_GPIO:
+ default:
+ return 0;
+ }
+}
+
+static struct stmpe_variant_info stmpe1601 = {
+ .name = "stmpe1601",
+ .id_val = 0x0210,
+ .id_mask = 0xfff0, /* at least 0x0210 and 0x0212 */
+ .num_gpios = 16,
+ .af_bits = 2,
+ .regs = stmpe1601_regs,
+ .blocks = stmpe1601_blocks,
+ .num_blocks = ARRAY_SIZE(stmpe1601_blocks),
+ .num_irqs = STMPE1601_NR_INTERNAL_IRQS,
+ .enable = stmpe1601_enable,
+ .get_altfunc = stmpe1601_get_altfunc,
+ .enable_autosleep = stmpe1601_autosleep,
+};
+
+/*
+ * STMPE24XX
+ */
+
+static const u8 stmpe24xx_regs[] = {
+ [STMPE_IDX_CHIP_ID] = STMPE24XX_REG_CHIP_ID,
+ [STMPE_IDX_ICR_LSB] = STMPE24XX_REG_ICR_LSB,
+ [STMPE_IDX_IER_LSB] = STMPE24XX_REG_IER_LSB,
+ [STMPE_IDX_ISR_MSB] = STMPE24XX_REG_ISR_MSB,
+ [STMPE_IDX_GPMR_LSB] = STMPE24XX_REG_GPMR_LSB,
+ [STMPE_IDX_GPSR_LSB] = STMPE24XX_REG_GPSR_LSB,
+ [STMPE_IDX_GPCR_LSB] = STMPE24XX_REG_GPCR_LSB,
+ [STMPE_IDX_GPDR_LSB] = STMPE24XX_REG_GPDR_LSB,
+ [STMPE_IDX_GPRER_LSB] = STMPE24XX_REG_GPRER_LSB,
+ [STMPE_IDX_GPFER_LSB] = STMPE24XX_REG_GPFER_LSB,
+ [STMPE_IDX_GPAFR_U_MSB] = STMPE24XX_REG_GPAFR_U_MSB,
+ [STMPE_IDX_IEGPIOR_LSB] = STMPE24XX_REG_IEGPIOR_LSB,
+ [STMPE_IDX_ISGPIOR_MSB] = STMPE24XX_REG_ISGPIOR_MSB,
+ [STMPE_IDX_GPEDR_MSB] = STMPE24XX_REG_GPEDR_MSB,
+};
+
+static struct stmpe_variant_block stmpe24xx_blocks[] = {
+ {
+ .cell = &stmpe_gpio_cell,
+ .irq = STMPE24XX_IRQ_GPIOC,
+ .block = STMPE_BLOCK_GPIO,
+ },
+ {
+ .cell = &stmpe_keypad_cell,
+ .irq = STMPE24XX_IRQ_KEYPAD,
+ .block = STMPE_BLOCK_KEYPAD,
+ },
+};
+
+static int stmpe24xx_enable(struct stmpe *stmpe, unsigned int blocks,
+ bool enable)
+{
+ unsigned int mask = 0;
+
+ if (blocks & STMPE_BLOCK_GPIO)
+ mask |= STMPE24XX_SYS_CTRL_ENABLE_GPIO;
+
+ if (blocks & STMPE_BLOCK_KEYPAD)
+ mask |= STMPE24XX_SYS_CTRL_ENABLE_KPC;
+
+ return __stmpe_set_bits(stmpe, STMPE24XX_REG_SYS_CTRL, mask,
+ enable ? mask : 0);
+}
+
+static int stmpe24xx_get_altfunc(struct stmpe *stmpe, enum stmpe_block block)
+{
+ switch (block) {
+ case STMPE_BLOCK_ROTATOR:
+ return 2;
+
+ case STMPE_BLOCK_KEYPAD:
+ return 1;
+
+ case STMPE_BLOCK_GPIO:
+ default:
+ return 0;
+ }
+}
+
+static struct stmpe_variant_info stmpe2401 = {
+ .name = "stmpe2401",
+ .id_val = 0x0101,
+ .id_mask = 0xffff,
+ .num_gpios = 24,
+ .af_bits = 2,
+ .regs = stmpe24xx_regs,
+ .blocks = stmpe24xx_blocks,
+ .num_blocks = ARRAY_SIZE(stmpe24xx_blocks),
+ .num_irqs = STMPE24XX_NR_INTERNAL_IRQS,
+ .enable = stmpe24xx_enable,
+ .get_altfunc = stmpe24xx_get_altfunc,
+};
+
+static struct stmpe_variant_info stmpe2403 = {
+ .name = "stmpe2403",
+ .id_val = 0x0120,
+ .id_mask = 0xffff,
+ .num_gpios = 24,
+ .af_bits = 2,
+ .regs = stmpe24xx_regs,
+ .blocks = stmpe24xx_blocks,
+ .num_blocks = ARRAY_SIZE(stmpe24xx_blocks),
+ .num_irqs = STMPE24XX_NR_INTERNAL_IRQS,
+ .enable = stmpe24xx_enable,
+ .get_altfunc = stmpe24xx_get_altfunc,
+ .enable_autosleep = stmpe1601_autosleep, /* same as stmpe1601 */
+};
+
+static struct stmpe_variant_info *stmpe_variant_info[] = {
+ [STMPE811] = &stmpe811,
+ [STMPE1601] = &stmpe1601,
+ [STMPE2401] = &stmpe2401,
+ [STMPE2403] = &stmpe2403,
+};
+
+static irqreturn_t stmpe_irq(int irq, void *data)
+{
+ struct stmpe *stmpe = data;
+ struct stmpe_variant_info *variant = stmpe->variant;
+ int num = DIV_ROUND_UP(variant->num_irqs, 8);
+ u8 israddr = stmpe->regs[STMPE_IDX_ISR_MSB];
+ u8 isr[num];
+ int ret;
+ int i;
+
+ ret = stmpe_block_read(stmpe, israddr, num, isr);
+ if (ret < 0)
+ return IRQ_NONE;
+
+ for (i = 0; i < num; i++) {
+ int bank = num - i - 1;
+ u8 status = isr[i];
+ u8 clear;
+
+ status &= stmpe->ier[bank];
+ if (!status)
+ continue;
+
+ clear = status;
+ while (status) {
+ int bit = __ffs(status);
+ int line = bank * 8 + bit;
+
+ handle_nested_irq(stmpe->irq_base + line);
+ status &= ~(1 << bit);
+ }
+
+ stmpe_reg_write(stmpe, israddr + i, clear);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void stmpe_irq_lock(unsigned int irq)
+{
+ struct stmpe *stmpe = get_irq_chip_data(irq);
+
+ mutex_lock(&stmpe->irq_lock);
+}
+
+static void stmpe_irq_sync_unlock(unsigned int irq)
+{
+ struct stmpe *stmpe = get_irq_chip_data(irq);
+ struct stmpe_variant_info *variant = stmpe->variant;
+ int num = DIV_ROUND_UP(variant->num_irqs, 8);
+ int i;
+
+ for (i = 0; i < num; i++) {
+ u8 new = stmpe->ier[i];
+ u8 old = stmpe->oldier[i];
+
+ if (new == old)
+ continue;
+
+ stmpe->oldier[i] = new;
+ stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_IER_LSB] - i, new);
+ }
+
+ mutex_unlock(&stmpe->irq_lock);
+}
+
+static void stmpe_irq_mask(unsigned int irq)
+{
+ struct stmpe *stmpe = get_irq_chip_data(irq);
+ int offset = irq - stmpe->irq_base;
+ int regoffset = offset / 8;
+ int mask = 1 << (offset % 8);
+
+ stmpe->ier[regoffset] &= ~mask;
+}
+
+static void stmpe_irq_unmask(unsigned int irq)
+{
+ struct stmpe *stmpe = get_irq_chip_data(irq);
+ int offset = irq - stmpe->irq_base;
+ int regoffset = offset / 8;
+ int mask = 1 << (offset % 8);
+
+ stmpe->ier[regoffset] |= mask;
+}
+
+static struct irq_chip stmpe_irq_chip = {
+ .name = "stmpe",
+ .bus_lock = stmpe_irq_lock,
+ .bus_sync_unlock = stmpe_irq_sync_unlock,
+ .mask = stmpe_irq_mask,
+ .unmask = stmpe_irq_unmask,
+};
+
+static int __devinit stmpe_irq_init(struct stmpe *stmpe)
+{
+ int num_irqs = stmpe->variant->num_irqs;
+ int base = stmpe->irq_base;
+ int irq;
+
+ for (irq = base; irq < base + num_irqs; irq++) {
+ set_irq_chip_data(irq, stmpe);
+ set_irq_chip_and_handler(irq, &stmpe_irq_chip,
+ handle_edge_irq);
+ set_irq_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ set_irq_noprobe(irq);
+#endif
+ }
+
+ return 0;
+}
+
+static void stmpe_irq_remove(struct stmpe *stmpe)
+{
+ int num_irqs = stmpe->variant->num_irqs;
+ int base = stmpe->irq_base;
+ int irq;
+
+ for (irq = base; irq < base + num_irqs; irq++) {
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, 0);
+#endif
+ set_irq_chip_and_handler(irq, NULL, NULL);
+ set_irq_chip_data(irq, NULL);
+ }
+}
+
+static int __devinit stmpe_chip_init(struct stmpe *stmpe)
+{
+ unsigned int irq_trigger = stmpe->pdata->irq_trigger;
+ int autosleep_timeout = stmpe->pdata->autosleep_timeout;
+ struct stmpe_variant_info *variant = stmpe->variant;
+ u8 icr = STMPE_ICR_LSB_GIM;
+ unsigned int id;
+ u8 data[2];
+ int ret;
+
+ ret = stmpe_block_read(stmpe, stmpe->regs[STMPE_IDX_CHIP_ID],
+ ARRAY_SIZE(data), data);
+ if (ret < 0)
+ return ret;
+
+ id = (data[0] << 8) | data[1];
+ if ((id & variant->id_mask) != variant->id_val) {
+ dev_err(stmpe->dev, "unknown chip id: %#x\n", id);
+ return -EINVAL;
+ }
+
+ dev_info(stmpe->dev, "%s detected, chip id: %#x\n", variant->name, id);
+
+ /* Disable all modules -- subdrivers should enable what they need. */
+ ret = stmpe_disable(stmpe, ~0);
+ if (ret)
+ return ret;
+
+ if (irq_trigger == IRQF_TRIGGER_FALLING ||
+ irq_trigger == IRQF_TRIGGER_RISING)
+ icr |= STMPE_ICR_LSB_EDGE;
+
+ if (irq_trigger == IRQF_TRIGGER_RISING ||
+ irq_trigger == IRQF_TRIGGER_HIGH)
+ icr |= STMPE_ICR_LSB_HIGH;
+
+ if (stmpe->pdata->irq_invert_polarity)
+ icr ^= STMPE_ICR_LSB_HIGH;
+
+ if (stmpe->pdata->autosleep) {
+ ret = stmpe_autosleep(stmpe, autosleep_timeout);
+ if (ret)
+ return ret;
+ }
+
+ return stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_ICR_LSB], icr);
+}
+
+static int __devinit stmpe_add_device(struct stmpe *stmpe,
+ struct mfd_cell *cell, int irq)
+{
+ return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1,
+ NULL, stmpe->irq_base + irq);
+}
+
+static int __devinit stmpe_devices_init(struct stmpe *stmpe)
+{
+ struct stmpe_variant_info *variant = stmpe->variant;
+ unsigned int platform_blocks = stmpe->pdata->blocks;
+ int ret = -EINVAL;
+ int i;
+
+ for (i = 0; i < variant->num_blocks; i++) {
+ struct stmpe_variant_block *block = &variant->blocks[i];
+
+ if (!(platform_blocks & block->block))
+ continue;
+
+ platform_blocks &= ~block->block;
+ ret = stmpe_add_device(stmpe, block->cell, block->irq);
+ if (ret)
+ return ret;
+ }
+
+ if (platform_blocks)
+ dev_warn(stmpe->dev,
+ "platform wants blocks (%#x) not present on variant",
+ platform_blocks);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int stmpe_suspend(struct device *dev)
+{
+ struct i2c_client *i2c = to_i2c_client(dev);
+
+ if (device_may_wakeup(&i2c->dev))
+ enable_irq_wake(i2c->irq);
+
+ return 0;
+}
+
+static int stmpe_resume(struct device *dev)
+{
+ struct i2c_client *i2c = to_i2c_client(dev);
+
+ if (device_may_wakeup(&i2c->dev))
+ disable_irq_wake(i2c->irq);
+
+ return 0;
+}
+#endif
+
+static int __devinit stmpe_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct stmpe_platform_data *pdata = i2c->dev.platform_data;
+ struct stmpe *stmpe;
+ int ret;
+
+ if (!pdata)
+ return -EINVAL;
+
+ stmpe = kzalloc(sizeof(struct stmpe), GFP_KERNEL);
+ if (!stmpe)
+ return -ENOMEM;
+
+ mutex_init(&stmpe->irq_lock);
+ mutex_init(&stmpe->lock);
+
+ stmpe->dev = &i2c->dev;
+ stmpe->i2c = i2c;
+
+ stmpe->pdata = pdata;
+ stmpe->irq_base = pdata->irq_base;
+
+ stmpe->partnum = id->driver_data;
+ stmpe->variant = stmpe_variant_info[stmpe->partnum];
+ stmpe->regs = stmpe->variant->regs;
+ stmpe->num_gpios = stmpe->variant->num_gpios;
+
+ i2c_set_clientdata(i2c, stmpe);
+
+ ret = stmpe_chip_init(stmpe);
+ if (ret)
+ goto out_free;
+
+ ret = stmpe_irq_init(stmpe);
+ if (ret)
+ goto out_free;
+
+ ret = request_threaded_irq(stmpe->i2c->irq, NULL, stmpe_irq,
+ pdata->irq_trigger | IRQF_ONESHOT,
+ "stmpe", stmpe);
+ if (ret) {
+ dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
+ goto out_removeirq;
+ }
+
+ ret = stmpe_devices_init(stmpe);
+ if (ret) {
+ dev_err(stmpe->dev, "failed to add children\n");
+ goto out_removedevs;
+ }
+
+ return 0;
+
+out_removedevs:
+ mfd_remove_devices(stmpe->dev);
+ free_irq(stmpe->i2c->irq, stmpe);
+out_removeirq:
+ stmpe_irq_remove(stmpe);
+out_free:
+ kfree(stmpe);
+ return ret;
+}
+
+static int __devexit stmpe_remove(struct i2c_client *client)
+{
+ struct stmpe *stmpe = i2c_get_clientdata(client);
+
+ mfd_remove_devices(stmpe->dev);
+
+ free_irq(stmpe->i2c->irq, stmpe);
+ stmpe_irq_remove(stmpe);
+
+ kfree(stmpe);
+
+ return 0;
+}
+
+static const struct i2c_device_id stmpe_id[] = {
+ { "stmpe811", STMPE811 },
+ { "stmpe1601", STMPE1601 },
+ { "stmpe2401", STMPE2401 },
+ { "stmpe2403", STMPE2403 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, stmpe_id);
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops stmpe_dev_pm_ops = {
+ .suspend = stmpe_suspend,
+ .resume = stmpe_resume,
+};
+#endif
+
+static struct i2c_driver stmpe_driver = {
+ .driver.name = "stmpe",
+ .driver.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .driver.pm = &stmpe_dev_pm_ops,
+#endif
+ .probe = stmpe_probe,
+ .remove = __devexit_p(stmpe_remove),
+ .id_table = stmpe_id,
+};
+
+static int __init stmpe_init(void)
+{
+ return i2c_add_driver(&stmpe_driver);
+}
+subsys_initcall(stmpe_init);
+
+static void __exit stmpe_exit(void)
+{
+ i2c_del_driver(&stmpe_driver);
+}
+module_exit(stmpe_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMPE MFD core driver");
+MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h
new file mode 100644
index 00000000000..0dbdc4e8cd7
--- /dev/null
+++ b/drivers/mfd/stmpe.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ */
+
+#ifndef __STMPE_H
+#define __STMPE_H
+
+#ifdef STMPE_DUMP_BYTES
+static inline void stmpe_dump_bytes(const char *str, const void *buf,
+ size_t len)
+{
+ print_hex_dump_bytes(str, DUMP_PREFIX_OFFSET, buf, len);
+}
+#else
+static inline void stmpe_dump_bytes(const char *str, const void *buf,
+ size_t len)
+{
+}
+#endif
+
+/**
+ * struct stmpe_variant_block - information about block
+ * @cell: base mfd cell
+ * @irq: interrupt number to be added to each IORESOURCE_IRQ
+ * in the cell
+ * @block: block id; used for identification with platform data and for
+ * enable and altfunc callbacks
+ */
+struct stmpe_variant_block {
+ struct mfd_cell *cell;
+ int irq;
+ enum stmpe_block block;
+};
+
+/**
+ * struct stmpe_variant_info - variant-specific information
+ * @name: part name
+ * @id_val: content of CHIPID register
+ * @id_mask: bits valid in CHIPID register for comparison with id_val
+ * @num_gpios: number of GPIOS
+ * @af_bits: number of bits used to specify the alternate function
+ * @blocks: list of blocks present on this device
+ * @num_blocks: number of blocks present on this device
+ * @num_irqs: number of internal IRQs available on this device
+ * @enable: callback to enable the specified blocks.
+ * Called with the I/O lock held.
+ * @get_altfunc: callback to get the alternate function number for the
+ * specific block
+ * @enable_autosleep: callback to configure autosleep with specified timeout
+ */
+struct stmpe_variant_info {
+ const char *name;
+ u16 id_val;
+ u16 id_mask;
+ int num_gpios;
+ int af_bits;
+ const u8 *regs;
+ struct stmpe_variant_block *blocks;
+ int num_blocks;
+ int num_irqs;
+ int (*enable)(struct stmpe *stmpe, unsigned int blocks, bool enable);
+ int (*get_altfunc)(struct stmpe *stmpe, enum stmpe_block block);
+ int (*enable_autosleep)(struct stmpe *stmpe, int autosleep_timeout);
+};
+
+#define STMPE_ICR_LSB_HIGH (1 << 2)
+#define STMPE_ICR_LSB_EDGE (1 << 1)
+#define STMPE_ICR_LSB_GIM (1 << 0)
+
+/*
+ * STMPE811
+ */
+
+#define STMPE811_IRQ_TOUCH_DET 0
+#define STMPE811_IRQ_FIFO_TH 1
+#define STMPE811_IRQ_FIFO_OFLOW 2
+#define STMPE811_IRQ_FIFO_FULL 3
+#define STMPE811_IRQ_FIFO_EMPTY 4
+#define STMPE811_IRQ_TEMP_SENS 5
+#define STMPE811_IRQ_ADC 6
+#define STMPE811_IRQ_GPIOC 7
+#define STMPE811_NR_INTERNAL_IRQS 8
+
+#define STMPE811_REG_CHIP_ID 0x00
+#define STMPE811_REG_SYS_CTRL2 0x04
+#define STMPE811_REG_INT_CTRL 0x09
+#define STMPE811_REG_INT_EN 0x0A
+#define STMPE811_REG_INT_STA 0x0B
+#define STMPE811_REG_GPIO_INT_EN 0x0C
+#define STMPE811_REG_GPIO_INT_STA 0x0D
+#define STMPE811_REG_GPIO_SET_PIN 0x10
+#define STMPE811_REG_GPIO_CLR_PIN 0x11
+#define STMPE811_REG_GPIO_MP_STA 0x12
+#define STMPE811_REG_GPIO_DIR 0x13
+#define STMPE811_REG_GPIO_ED 0x14
+#define STMPE811_REG_GPIO_RE 0x15
+#define STMPE811_REG_GPIO_FE 0x16
+#define STMPE811_REG_GPIO_AF 0x17
+
+#define STMPE811_SYS_CTRL2_ADC_OFF (1 << 0)
+#define STMPE811_SYS_CTRL2_TSC_OFF (1 << 1)
+#define STMPE811_SYS_CTRL2_GPIO_OFF (1 << 2)
+#define STMPE811_SYS_CTRL2_TS_OFF (1 << 3)
+
+/*
+ * STMPE1601
+ */
+
+#define STMPE1601_IRQ_GPIOC 8
+#define STMPE1601_IRQ_PWM3 7
+#define STMPE1601_IRQ_PWM2 6
+#define STMPE1601_IRQ_PWM1 5
+#define STMPE1601_IRQ_PWM0 4
+#define STMPE1601_IRQ_KEYPAD_OVER 2
+#define STMPE1601_IRQ_KEYPAD 1
+#define STMPE1601_IRQ_WAKEUP 0
+#define STMPE1601_NR_INTERNAL_IRQS 9
+
+#define STMPE1601_REG_SYS_CTRL 0x02
+#define STMPE1601_REG_SYS_CTRL2 0x03
+#define STMPE1601_REG_ICR_LSB 0x11
+#define STMPE1601_REG_IER_LSB 0x13
+#define STMPE1601_REG_ISR_MSB 0x14
+#define STMPE1601_REG_CHIP_ID 0x80
+#define STMPE1601_REG_INT_EN_GPIO_MASK_LSB 0x17
+#define STMPE1601_REG_INT_STA_GPIO_MSB 0x18
+#define STMPE1601_REG_GPIO_MP_LSB 0x87
+#define STMPE1601_REG_GPIO_SET_LSB 0x83
+#define STMPE1601_REG_GPIO_CLR_LSB 0x85
+#define STMPE1601_REG_GPIO_SET_DIR_LSB 0x89
+#define STMPE1601_REG_GPIO_ED_MSB 0x8A
+#define STMPE1601_REG_GPIO_RE_LSB 0x8D
+#define STMPE1601_REG_GPIO_FE_LSB 0x8F
+#define STMPE1601_REG_GPIO_AF_U_MSB 0x92
+
+#define STMPE1601_SYS_CTRL_ENABLE_GPIO (1 << 3)
+#define STMPE1601_SYS_CTRL_ENABLE_KPC (1 << 1)
+#define STMPE1601_SYSCON_ENABLE_SPWM (1 << 0)
+
+/* The 1601/2403 share the same masks */
+#define STMPE1601_AUTOSLEEP_TIMEOUT_MASK (0x7)
+#define STPME1601_AUTOSLEEP_ENABLE (1 << 3)
+
+/*
+ * STMPE24xx
+ */
+
+#define STMPE24XX_IRQ_GPIOC 8
+#define STMPE24XX_IRQ_PWM2 7
+#define STMPE24XX_IRQ_PWM1 6
+#define STMPE24XX_IRQ_PWM0 5
+#define STMPE24XX_IRQ_ROT_OVER 4
+#define STMPE24XX_IRQ_ROT 3
+#define STMPE24XX_IRQ_KEYPAD_OVER 2
+#define STMPE24XX_IRQ_KEYPAD 1
+#define STMPE24XX_IRQ_WAKEUP 0
+#define STMPE24XX_NR_INTERNAL_IRQS 9
+
+#define STMPE24XX_REG_SYS_CTRL 0x02
+#define STMPE24XX_REG_ICR_LSB 0x11
+#define STMPE24XX_REG_IER_LSB 0x13
+#define STMPE24XX_REG_ISR_MSB 0x14
+#define STMPE24XX_REG_CHIP_ID 0x80
+#define STMPE24XX_REG_IEGPIOR_LSB 0x18
+#define STMPE24XX_REG_ISGPIOR_MSB 0x19
+#define STMPE24XX_REG_GPMR_LSB 0xA5
+#define STMPE24XX_REG_GPSR_LSB 0x85
+#define STMPE24XX_REG_GPCR_LSB 0x88
+#define STMPE24XX_REG_GPDR_LSB 0x8B
+#define STMPE24XX_REG_GPEDR_MSB 0x8C
+#define STMPE24XX_REG_GPRER_LSB 0x91
+#define STMPE24XX_REG_GPFER_LSB 0x94
+#define STMPE24XX_REG_GPAFR_U_MSB 0x9B
+
+#define STMPE24XX_SYS_CTRL_ENABLE_GPIO (1 << 3)
+#define STMPE24XX_SYSCON_ENABLE_PWM (1 << 2)
+#define STMPE24XX_SYS_CTRL_ENABLE_KPC (1 << 1)
+#define STMPE24XX_SYSCON_ENABLE_ROT (1 << 0)
+
+#endif
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 05f8e3fa61a..5860addef97 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -66,6 +66,15 @@ config ATMEL_PWM
purposes including software controlled power-efficient backlights
on LCD displays, motor control, and waveform generation.
+config AB8500_PWM
+ bool "AB8500 PWM support"
+ depends on AB8500_CORE
+ select HAVE_PWM
+ help
+ This driver exports functions to enable/disble/config/free Pulse
+ Width Modulation in the Analog Baseband Chip AB8500.
+ It is used by led and backlight driver to control the intensity.
+
config ATMEL_TCLIB
bool "Atmel AT32/AT91 Timer/Counter Library"
depends on (AVR32 || ARCH_AT91)
@@ -323,6 +332,16 @@ config SENSORS_AK8975
If you say yes here you get support for Asahi Kasei's
orientation sensor AK8975.
+config SENSORS_BH1780
+ tristate "ROHM BH1780GLI ambient light sensor"
+ depends on I2C && SYSFS
+ help
+ If you say yes here you get support for the ROHM BH1780GLI
+ ambient light sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called bh1780gli.
+
config EP93XX_PWM
tristate "EP93xx PWM support"
depends on ARCH_EP93XX
@@ -399,9 +418,41 @@ config APANIC_PLABEL
If your platform uses a different flash partition label for storing
crashdumps, enter it here.
+config ARM_CHARLCD
+ bool "ARM Ltd. Character LCD Driver"
+ depends on PLAT_VERSATILE
+ help
+ This is a driver for the character LCD found on the ARM Ltd.
+ Versatile and RealView Platform Baseboards. It doesn't do
+ very much more than display the text "ARM Linux" on the first
+ line and the Linux version on the second line, but that's
+ still useful.
+
+config AB8500_GPADC
+ bool "AB8500 GPADC driver"
+ depends on AB8500_CORE
+ default y
+ help
+ AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage
+
+config HWMEM
+ bool "Hardware memory driver"
+ default n
+ help
+ This driver provides a way to allocate contiguous system memory which
+ can be used by hardware. It also enables accessing hwmem allocated
+ memory buffers through a secure id which can be shared across processes.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
source "drivers/misc/iwmc3200top/Kconfig"
+source "drivers/misc/hsi/Kconfig"
+source "drivers/misc/hsi/hsi-legacy/Kconfig"
+source "drivers/misc/i2s/Kconfig"
+source "drivers/misc/msw/Kconfig"
+source "drivers/misc/shrm/Kconfig"
+source "drivers/misc/audio_io_dev/Kconfig"
+source "drivers/misc/ab8500_denc/Kconfig"
endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 19c582a52e4..38a1201e0fa 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
obj-$(CONFIG_PHANTOM) += phantom.o
obj-$(CONFIG_ANDROID_PMEM) += pmem.o
+obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
obj-$(CONFIG_KERNEL_DEBUGGER_CORE) += kernel_debugger.o
@@ -37,3 +38,14 @@ obj-$(CONFIG_VMWARE_BALLOON) += vmware_balloon.o
obj-$(CONFIG_WL127X_RFKILL) += wl127x-rfkill.o
obj-$(CONFIG_APANIC) += apanic.o
obj-$(CONFIG_SENSORS_AK8975) += akm8975.o
+obj-$(CONFIG_HSI) += hsi/
+obj-$(CONFIG_U8500_HSI_LEGACY) += hsi/hsi-legacy/
+obj-$(CONFIG_STM_I2S) += i2s/
+obj-$(CONFIG_AB8500_GPADC) += ab8500_gpadc.o
+obj-$(CONFIG_ISA_HSI_MODEM) += msw/
+obj-$(CONFIG_U8500_SHRM) += shrm/
+obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
+obj-$(CONFIG_AB8500_DENC) += ab8500_denc/
+obj-$(CONFIG_STE_AUDIO_IO_DEV) += audio_io_dev/
+obj-$(CONFIG_HWMEM) += hwmem/
+obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o
diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c
new file mode 100644
index 00000000000..54e3d05b63c
--- /dev/null
+++ b/drivers/misc/ab8500-pwm.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun R Murthy <arun.murthy@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/pwm.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500.h>
+
+/*
+ * PWM Out generators
+ * Bank: 0x10
+ */
+#define AB8500_PWM_OUT_CTRL1_REG 0x60
+#define AB8500_PWM_OUT_CTRL2_REG 0x61
+#define AB8500_PWM_OUT_CTRL7_REG 0x66
+
+/* backlight driver constants */
+#define ENABLE_PWM 1
+#define DISABLE_PWM 0
+
+struct pwm_device {
+ struct device *dev;
+ struct list_head node;
+ const char *label;
+ unsigned int pwm_id;
+};
+
+static LIST_HEAD(pwm_list);
+
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ int ret = 0;
+ unsigned int higher_val, lower_val;
+ u8 reg;
+
+ /*
+ * get the first 8 bits that are be written to
+ * AB8500_PWM_OUT_CTRL1_REG[0:7]
+ */
+ lower_val = duty_ns & 0x00FF;
+ /*
+ * get bits [9:10] that are to be written to
+ * AB8500_PWM_OUT_CTRL2_REG[0:1]
+ */
+ higher_val = ((duty_ns & 0x0300) >> 8);
+
+ reg = AB8500_PWM_OUT_CTRL1_REG + ((pwm->pwm_id - 1) * 2);
+
+ ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
+ reg, (u8)lower_val);
+ if (ret < 0)
+ return ret;
+ ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
+ (reg + 1), (u8)higher_val);
+
+ return ret;
+}
+EXPORT_SYMBOL(pwm_config);
+
+int pwm_enable(struct pwm_device *pwm)
+{
+ int ret;
+
+ ret = abx500_mask_and_set_register_interruptible(pwm->dev,
+ AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
+ 1 << (pwm->pwm_id-1), ENABLE_PWM);
+ if (ret < 0)
+ dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
+ pwm->label, ret);
+ return ret;
+}
+EXPORT_SYMBOL(pwm_enable);
+
+void pwm_disable(struct pwm_device *pwm)
+{
+ int ret;
+
+ ret = abx500_mask_and_set_register_interruptible(pwm->dev,
+ AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
+ 1 << (pwm->pwm_id-1), DISABLE_PWM);
+ if (ret < 0)
+ dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
+ pwm->label, ret);
+ return;
+}
+EXPORT_SYMBOL(pwm_disable);
+
+struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+ struct pwm_device *pwm;
+
+ list_for_each_entry(pwm, &pwm_list, node) {
+ if (pwm->pwm_id == pwm_id) {
+ pwm->label = label;
+ pwm->pwm_id = pwm_id;
+ return pwm;
+ }
+ }
+
+ return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(pwm_request);
+
+void pwm_free(struct pwm_device *pwm)
+{
+ pwm_disable(pwm);
+}
+EXPORT_SYMBOL(pwm_free);
+
+static int __devinit ab8500_pwm_probe(struct platform_device *pdev)
+{
+ struct pwm_device *pwm;
+ /*
+ * Nothing to be done in probe, this is required to get the
+ * device which is required for ab8500 read and write
+ */
+ pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+ if (pwm == NULL) {
+ dev_err(&pdev->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+ pwm->dev = &pdev->dev;
+ pwm->pwm_id = pdev->id;
+ list_add_tail(&pwm->node, &pwm_list);
+ platform_set_drvdata(pdev, pwm);
+ dev_dbg(pwm->dev, "pwm probe successful\n");
+ return 0;
+}
+
+static int __devexit ab8500_pwm_remove(struct platform_device *pdev)
+{
+ struct pwm_device *pwm = platform_get_drvdata(pdev);
+ list_del(&pwm->node);
+ dev_dbg(&pdev->dev, "pwm driver removed\n");
+ kfree(pwm);
+ return 0;
+}
+
+static struct platform_driver ab8500_pwm_driver = {
+ .driver = {
+ .name = "ab8500-pwm",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_pwm_probe,
+ .remove = __devexit_p(ab8500_pwm_remove),
+};
+
+static int __init ab8500_pwm_init(void)
+{
+ return platform_driver_register(&ab8500_pwm_driver);
+}
+
+static void __exit ab8500_pwm_exit(void)
+{
+ platform_driver_unregister(&ab8500_pwm_driver);
+}
+
+subsys_initcall(ab8500_pwm_init);
+module_exit(ab8500_pwm_exit);
+MODULE_AUTHOR("Arun MURTHY <arun.murthy@stericsson.com>");
+MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver");
+MODULE_ALIAS("AB8500 PWM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/ab8500_denc/Kconfig b/drivers/misc/ab8500_denc/Kconfig
new file mode 100644
index 00000000000..46eb02fc2dc
--- /dev/null
+++ b/drivers/misc/ab8500_denc/Kconfig
@@ -0,0 +1,5 @@
+config AB8500_DENC
+ tristate "AB8500_DENC driver support(CVBS)"
+ depends on AB8500_CORE
+ help
+ Please enable this feature if tvout driver support is required.
diff --git a/drivers/misc/ab8500_denc/Makefile b/drivers/misc/ab8500_denc/Makefile
new file mode 100644
index 00000000000..ccd5cc99951
--- /dev/null
+++ b/drivers/misc/ab8500_denc/Makefile
@@ -0,0 +1,4 @@
+# Make file for compiling and loadable module HDMI
+
+obj-$(CONFIG_AB8500_DENC) += ab8500_denc.o
+
diff --git a/drivers/misc/ab8500_denc/ab8500_denc.c b/drivers/misc/ab8500_denc/ab8500_denc.c
new file mode 100644
index 00000000000..acdf9580db6
--- /dev/null
+++ b/drivers/misc/ab8500_denc/ab8500_denc.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * ST-Ericsson AB8500 DENC base driver
+ *
+ * Author: Marcel Tunnissen <marcel.tuennissen@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/uaccess.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500.h>
+
+#include "ab8500_denc_regs.h"
+#include <video/mcde_display-ab8500.h>
+#include <mach/ab8500_denc.h>
+
+#define AB8500_NAME "ab8500"
+#define AB8500_DENC_NAME "ab8500_denc"
+
+static struct platform_device *ab8500_denc_dev;
+
+#define AB8500_REG_BANK_NR(__reg) ((0xff00 & (__reg)) >> 8)
+static inline u8 ab8500_rreg(u32 reg)
+{
+ int ret;
+ u8 val;
+
+ if (!ab8500_denc_dev || !&ab8500_denc_dev->dev)
+ return -ENODEV;
+
+ ret = abx500_get_register_interruptible(&ab8500_denc_dev->dev,
+ AB8500_REG_BANK_NR(reg), reg, &val);
+ if (ret < 0)
+ return ret;
+ else
+ return val;
+}
+static inline void ab8500_wreg(u32 reg, u8 val)
+{
+ if (!ab8500_denc_dev || !&ab8500_denc_dev->dev) {
+ printk(KERN_ERR "AB8500_denc error. No device found.\n");
+ return;
+ }
+
+ abx500_set_register_interruptible(&ab8500_denc_dev->dev,
+ AB8500_REG_BANK_NR(reg), reg, val);
+}
+
+#define ab8500_set_fld(__cur_val, __reg, __fld, __val) \
+ (((__cur_val) & ~__reg##_##__fld##_MASK) |\
+ (((__val) << __reg##_##__fld##_SHIFT) & __reg##_##__fld##_MASK))
+
+#define ab8500_wr_fld(__reg, __fld, __val) \
+ ab8500_wreg(__reg, \
+ ((ab8500_rreg(__reg) & ~__reg##_##__fld##_MASK) |\
+ (((__val) << __reg##_##__fld##_SHIFT) &\
+ __reg##_##__fld##_MASK)))
+
+#define AB8500_DENC_TRACE pr_debug("%s\n", __func__)
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_ab8500_denc_dir;
+static struct dentry *debugfs_ab8500_dump_regs_file;
+static void ab8500_denc_conf_ddr(void);
+static int debugfs_ab8500_open_file(struct inode *inode, struct file *file);
+static ssize_t debugfs_ab8500_dump_regs(struct file *file, char __user *buf,
+ size_t count, loff_t *f_pos);
+static ssize_t debugfs_ab8500_write_file_dummy(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos);
+
+static const struct file_operations debugfs_ab8500_dump_regs_fops = {
+ .owner = THIS_MODULE,
+ .open = debugfs_ab8500_open_file,
+ .read = debugfs_ab8500_dump_regs,
+ .write = debugfs_ab8500_write_file_dummy
+};
+#endif /* CONFIG_DEBUG_FS */
+
+static void setup_27mhz(bool enable);
+static u32 map_tv_std(enum ab8500_denc_TV_std std);
+static u32 map_cr_filter(enum ab8500_denc_cr_filter_bandwidth bw);
+static u32 map_phase_rst_mode(enum ab8500_denc_phase_reset_mode mode);
+static u32 map_plug_time(enum ab8500_denc_plug_time time);
+
+static int __devinit ab8500_denc_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct ab8500_platform_data *ab8500_pdata =
+ dev_get_platdata(pdev->dev.parent);
+ struct ab8500_denc_platform_data *pdata;
+
+ if (ab8500_pdata == NULL) {
+ dev_err(&pdev->dev, "AB8500 platform data missing\n");
+ ret = -EINVAL;
+ goto no_pdata;
+ }
+
+ pdata = ab8500_pdata->denc;
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "Denc platform data missing\n");
+ ret = -EINVAL;
+ goto no_pdata;
+ }
+
+ ab8500_denc_dev = pdev;
+ AB8500_DENC_TRACE; /* note this needs ab8500_denc_dev to be set */
+
+#ifdef CONFIG_DEBUG_FS
+ debugfs_ab8500_denc_dir = debugfs_create_dir(pdev->name, NULL);
+ debugfs_ab8500_dump_regs_file = debugfs_create_file(
+ "dumpregs", S_IRUGO,
+ debugfs_ab8500_denc_dir, 0,
+ &debugfs_ab8500_dump_regs_fops
+ );
+#endif /* CONFIG_DEBUG_FS */
+out:
+ return ret;
+
+no_pdata:
+ goto out;
+}
+
+static void setup_27mhz(bool enable)
+{
+ u8 data = ab8500_rreg(AB8500_SYS_ULP_CLK_CONF);
+
+ AB8500_DENC_TRACE;
+ /* TODO: check if this field needs to be set */
+ data = ab8500_set_fld(data, AB8500_SYS_ULP_CLK_CONF, CLK_27MHZ_PD_ENA,
+ true);
+ data = ab8500_set_fld(data, AB8500_SYS_ULP_CLK_CONF, CLK_27MHZ_BUF_ENA,
+ enable);
+ data = ab8500_set_fld(data, AB8500_SYS_ULP_CLK_CONF, TVOUT_CLK_INV,
+ false);
+ data = ab8500_set_fld(data, AB8500_SYS_ULP_CLK_CONF, TVOUT_CLK_DE_IN,
+ false);
+ data = ab8500_set_fld(data, AB8500_SYS_ULP_CLK_CONF, CLK_27MHZ_STRE,
+ 1);
+ ab8500_wreg(AB8500_SYS_ULP_CLK_CONF, data);
+
+ data = ab8500_rreg(AB8500_SYS_CLK_CTRL);
+ data = ab8500_set_fld(data, AB8500_SYS_CLK_CTRL, TVOUT_CLK_VALID,
+ enable);
+ data = ab8500_set_fld(data, AB8500_SYS_CLK_CTRL, TVOUT_PLL_ENA,
+ enable);
+ ab8500_wreg(AB8500_SYS_CLK_CTRL, data);
+}
+
+static u32 map_tv_std(enum ab8500_denc_TV_std std)
+{
+ switch (std) {
+ case TV_STD_PAL_BDGHI:
+ return AB8500_DENC_CONF0_STD_PAL_BDGHI;
+ case TV_STD_PAL_N:
+ return AB8500_DENC_CONF0_STD_PAL_N;
+ case TV_STD_PAL_M:
+ return AB8500_DENC_CONF0_STD_PAL_M;
+ case TV_STD_NTSC_M:
+ return AB8500_DENC_CONF0_STD_NTSC_M;
+ default:
+ return 0;
+ }
+}
+
+static u32 map_cr_filter(enum ab8500_denc_cr_filter_bandwidth bw)
+{
+ switch (bw) {
+ case TV_CR_NTSC_LOW_DEF_FILTER:
+ return AB8500_DENC_CONF1_FLT_1_1MHZ;
+ case TV_CR_PAL_LOW_DEF_FILTER:
+ return AB8500_DENC_CONF1_FLT_1_3MHZ;
+ case TV_CR_NTSC_HIGH_DEF_FILTER:
+ return AB8500_DENC_CONF1_FLT_1_6MHZ;
+ case TV_CR_PAL_HIGH_DEF_FILTER:
+ return AB8500_DENC_CONF1_FLT_1_9MHZ;
+ default:
+ return 0;
+ }
+}
+
+static u32 map_phase_rst_mode(enum ab8500_denc_phase_reset_mode mode)
+{
+ switch (mode) {
+ case TV_PHASE_RST_MOD_DISABLE:
+ return AB8500_DENC_CONF8_PH_RST_MODE_DISABLED;
+ case TV_PHASE_RST_MOD_FROM_PHASE_BUF:
+ return AB8500_DENC_CONF8_PH_RST_MODE_UPDATE_FROM_PHASE_BUF;
+ case TV_PHASE_RST_MOD_FROM_INC_DFS:
+ return AB8500_DENC_CONF8_PH_RST_MODE_UPDATE_FROM_INC_DFS;
+ case TV_PHASE_RST_MOD_RST:
+ return AB8500_DENC_CONF8_PH_RST_MODE_RESET;
+ default:
+ return 0;
+ }
+}
+
+static u32 map_plug_time(enum ab8500_denc_plug_time time)
+{
+ switch (time) {
+ case TV_PLUG_TIME_0_5S:
+ return AB8500_TVOUT_CTRL_PLUG_TV_TIME_0_5S;
+ case TV_PLUG_TIME_1S:
+ return AB8500_TVOUT_CTRL_PLUG_TV_TIME_1S;
+ case TV_PLUG_TIME_1_5S:
+ return AB8500_TVOUT_CTRL_PLUG_TV_TIME_1_5S;
+ case TV_PLUG_TIME_2S:
+ return AB8500_TVOUT_CTRL_PLUG_TV_TIME_2S;
+ case TV_PLUG_TIME_2_5S:
+ return AB8500_TVOUT_CTRL_PLUG_TV_TIME_2_5S;
+ case TV_PLUG_TIME_3S:
+ return AB8500_TVOUT_CTRL_PLUG_TV_TIME_3S;
+ default:
+ return 0;
+ }
+}
+
+static int __devexit ab8500_denc_remove(struct platform_device *pdev)
+{
+ AB8500_DENC_TRACE;
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove(debugfs_ab8500_dump_regs_file);
+ debugfs_remove(debugfs_ab8500_denc_dir);
+#endif /* CONFIG_DEBUG_FS */
+
+ ab8500_denc_dev = NULL;
+
+ return 0;
+}
+
+static struct platform_driver ab8500_denc_driver = {
+ .probe = ab8500_denc_probe,
+ .remove = ab8500_denc_remove,
+ .driver = {
+ .name = "ab8500-denc",
+ },
+};
+
+void ab8500_denc_reset(bool hard)
+{
+ AB8500_DENC_TRACE;
+ if (hard) {
+ u8 data = ab8500_rreg(AB8500_CTRL3);
+ /* reset start */
+ ab8500_wreg(AB8500_CTRL3,
+ ab8500_set_fld(data, AB8500_CTRL3, RESET_DENC_N, 0)
+ );
+ /* reset done */
+ ab8500_wreg(AB8500_CTRL3,
+ ab8500_set_fld(data, AB8500_CTRL3, RESET_DENC_N, 1)
+ );
+ } else {
+ ab8500_wr_fld(AB8500_DENC_CONF6, SOFT_RESET, 1);
+ mdelay(10);
+ }
+}
+EXPORT_SYMBOL(ab8500_denc_reset);
+
+void ab8500_denc_power_up(void)
+{
+ setup_27mhz(true);
+}
+EXPORT_SYMBOL(ab8500_denc_power_up);
+
+void ab8500_denc_power_down(void)
+{
+ setup_27mhz(false);
+}
+EXPORT_SYMBOL(ab8500_denc_power_down);
+
+void ab8500_denc_regu_setup(bool enable_v_tv, bool enable_lp_mode)
+{
+ u8 data = ab8500_rreg(AB8500_REGU_MISC1);
+
+ AB8500_DENC_TRACE;
+ data = ab8500_set_fld(data, AB8500_REGU_MISC1, V_TVOUT_LP,
+ enable_lp_mode);
+ data = ab8500_set_fld(data, AB8500_REGU_MISC1, V_TVOUT_ENA,
+ enable_v_tv);
+ ab8500_wreg(AB8500_REGU_MISC1, data);
+}
+EXPORT_SYMBOL(ab8500_denc_regu_setup);
+
+void ab8500_denc_conf(struct ab8500_denc_conf *conf)
+{
+ u8 data;
+
+ AB8500_DENC_TRACE;
+
+ ab8500_wreg(AB8500_DENC_CONF0,
+ AB8500_VAL2REG(AB8500_DENC_CONF0, STD, map_tv_std(conf->TV_std))
+ |
+ AB8500_VAL2REG(AB8500_DENC_CONF0, SYNC,
+ conf->test_pattern ? AB8500_DENC_CONF0_SYNC_AUTO_TEST :
+ AB8500_DENC_CONF0_SYNC_F_BASED_SLAVE
+ )
+ );
+ ab8500_wreg(AB8500_DENC_CONF1,
+ AB8500_VAL2REG(AB8500_DENC_CONF1, BLK_LI,
+ !conf->partial_blanking)
+ |
+ AB8500_VAL2REG(AB8500_DENC_CONF1, FLT,
+ map_cr_filter(conf->cr_filter))
+ |
+ AB8500_VAL2REG(AB8500_DENC_CONF1, CO_KI, conf->suppress_col)
+ |
+ AB8500_VAL2REG(AB8500_DENC_CONF1, SETUP_MAIN,
+ conf->black_level_setup)
+ /* TODO: handle cc field: set to 0 now */
+ );
+
+ data = ab8500_rreg(AB8500_DENC_CONF2);
+ data = ab8500_set_fld(data, AB8500_DENC_CONF2, N_INTRL,
+ conf->progressive);
+ ab8500_wreg(AB8500_DENC_CONF2, data);
+
+ ab8500_wreg(AB8500_DENC_CONF8,
+ AB8500_VAL2REG(AB8500_DENC_CONF8, PH_RST_MODE,
+ map_phase_rst_mode(conf->phase_reset_mode))
+ |
+ AB8500_VAL2REG(AB8500_DENC_CONF8, VAL_422_MUX,
+ conf->act_output)
+ |
+ AB8500_VAL2REG(AB8500_DENC_CONF8, BLK_ALL,
+ conf->blank_all)
+ );
+ data = ab8500_rreg(AB8500_TVOUT_CTRL);
+ data = ab8500_set_fld(data, AB8500_TVOUT_CTRL, DAC_CTRL0,
+ conf->dac_enable);
+ data = ab8500_set_fld(data, AB8500_TVOUT_CTRL, DAC_CTRL1,
+ conf->act_dc_output);
+ ab8500_wreg(AB8500_TVOUT_CTRL, data);
+
+ /* no support for DDR in early versions */
+ if (AB8500_REG2VAL(AB8500_REV, FULL_MASK, ab8500_rreg(AB8500_REV)) > 0)
+ ab8500_denc_conf_ddr();
+}
+EXPORT_SYMBOL(ab8500_denc_conf);
+
+void ab8500_denc_conf_plug_detect(bool enable, bool load_RC,
+ enum ab8500_denc_plug_time time)
+{
+ u8 data = ab8500_rreg(AB8500_TVOUT_CTRL);
+
+ AB8500_DENC_TRACE;
+ data = ab8500_set_fld(data, AB8500_TVOUT_CTRL, TV_PLUG_ON, enable);
+ data = ab8500_set_fld(data, AB8500_TVOUT_CTRL, TV_LOAD_RC, load_RC);
+ data = ab8500_set_fld(data, AB8500_TVOUT_CTRL, PLUG_TV_TIME,
+ map_plug_time(time));
+ ab8500_wreg(AB8500_TVOUT_CTRL, data);
+}
+EXPORT_SYMBOL(ab8500_denc_conf_plug_detect);
+
+void ab8500_denc_mask_int_plug_det(bool plug, bool unplug)
+{
+ u8 data = ab8500_rreg(AB8500_IT_MASK1);
+
+ AB8500_DENC_TRACE;
+ data = ab8500_set_fld(data, AB8500_IT_MASK1, PLUG_TV_DET, plug);
+ data = ab8500_set_fld(data, AB8500_IT_MASK1, UNPLUG_TV_DET, unplug);
+ ab8500_wreg(AB8500_IT_MASK1, data);
+}
+EXPORT_SYMBOL(ab8500_denc_mask_int_plug_det);
+
+static void ab8500_denc_conf_ddr(void)
+{
+ struct ab8500_platform_data *ab8500_pdata;
+ struct ab8500_denc_platform_data *pdata;
+
+ AB8500_DENC_TRACE;
+ if (ab8500_denc_dev) {
+ ab8500_pdata = dev_get_platdata(ab8500_denc_dev->dev.parent);
+ pdata = ab8500_pdata->denc;
+ ab8500_wreg(AB8500_TVOUT_CTRL2,
+ AB8500_VAL2REG(AB8500_TVOUT_CTRL2,
+ DENC_DDR, pdata->ddr_enable)
+ |
+ AB8500_VAL2REG(AB8500_TVOUT_CTRL2, SWAP_DDR_DATA_IN,
+ pdata->ddr_little_endian)
+ );
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int debugfs_ab8500_open_file(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static ssize_t debugfs_ab8500_write_file_dummy(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ return count;
+}
+
+#define DEBUG_BUF_SIZE 900
+
+static ssize_t debugfs_ab8500_dump_regs(struct file *file, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ int ret = 0;
+ size_t data_size = 0;
+ char buffer[DEBUG_BUF_SIZE];
+
+ data_size += sprintf(buffer + data_size,
+ "AB8500 DENC registers:\n"
+ "CTRL3 : 0x%04x = 0x%02x\n"
+ "SYSULPCLK_CONF: 0x%04x = 0x%02x\n"
+ "SYSCLK_CTRL : 0x%04x = 0x%02x\n"
+ "REGU_MISC1 : 0x%04x = 0x%02x\n"
+ "VAUX12_REGU : 0x%04x = 0x%02x\n"
+ "VAUX1_SEL1 : 0x%04x = 0x%02x\n"
+ "DENC_CONF0 : 0x%04x = 0x%02x\n"
+ "DENC_CONF1 : 0x%04x = 0x%02x\n"
+ "DENC_CONF2 : 0x%04x = 0x%02x\n"
+ "DENC_CONF6 : 0x%04x = 0x%02x\n"
+ "DENC_CONF8 : 0x%04x = 0x%02x\n"
+ "TVOUT_CTRL : 0x%04x = 0x%02x\n"
+ "TVOUT_CTRL2 : 0x%04x = 0x%02x\n"
+ "IT_MASK1 : 0x%04x = 0x%02x\n"
+ ,
+ AB8500_CTRL3, ab8500_rreg(AB8500_CTRL3),
+ AB8500_SYS_ULP_CLK_CONF, ab8500_rreg(AB8500_SYS_ULP_CLK_CONF),
+ AB8500_SYS_CLK_CTRL, ab8500_rreg(AB8500_SYS_CLK_CTRL),
+ AB8500_REGU_MISC1, ab8500_rreg(AB8500_REGU_MISC1),
+ AB8500_VAUX12_REGU, ab8500_rreg(AB8500_VAUX12_REGU),
+ AB8500_VAUX1_SEL, ab8500_rreg(AB8500_VAUX1_SEL),
+ AB8500_DENC_CONF0, ab8500_rreg(AB8500_DENC_CONF0),
+ AB8500_DENC_CONF1, ab8500_rreg(AB8500_DENC_CONF1),
+ AB8500_DENC_CONF2, ab8500_rreg(AB8500_DENC_CONF2),
+ AB8500_DENC_CONF6, ab8500_rreg(AB8500_DENC_CONF6),
+ AB8500_DENC_CONF8, ab8500_rreg(AB8500_DENC_CONF8),
+ AB8500_TVOUT_CTRL, ab8500_rreg(AB8500_TVOUT_CTRL),
+ AB8500_TVOUT_CTRL2, ab8500_rreg(AB8500_TVOUT_CTRL2),
+ AB8500_IT_MASK1, ab8500_rreg(AB8500_IT_MASK1)
+ );
+ if (data_size >= DEBUG_BUF_SIZE) {
+ printk(KERN_EMERG "AB8500 DENC: Buffer overrun\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* check if read done */
+ if (*f_pos > data_size)
+ goto out;
+
+ if (*f_pos + count > data_size)
+ count = data_size - *f_pos;
+
+ if (copy_to_user(buf, buffer + *f_pos, count))
+ ret = -EINVAL;
+ *f_pos += count;
+ ret = count;
+out:
+ return ret;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+/* Module init */
+static int __init ab8500_denc_init(void)
+{
+ return platform_driver_register(&ab8500_denc_driver);
+}
+module_init(ab8500_denc_init);
+
+static void __exit ab8500_denc_exit(void)
+{
+ platform_driver_unregister(&ab8500_denc_driver);
+}
+module_exit(ab8500_denc_exit);
+
+MODULE_AUTHOR("Marcel Tunnissen <marcel.tuennissen@stericsson.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ST-Ericsson AB8500 DENC driver");
diff --git a/drivers/misc/ab8500_denc/ab8500_denc_regs.h b/drivers/misc/ab8500_denc/ab8500_denc_regs.h
new file mode 100644
index 00000000000..284fb9ec195
--- /dev/null
+++ b/drivers/misc/ab8500_denc/ab8500_denc_regs.h
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson AB8500 DENC related registers
+ *
+ * Author: Marcus Tunnissen <marcel.tuennissen@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#define AB8500_VAL2REG(__reg, __fld, __val) \
+ (((__val) << __reg##_##__fld##_SHIFT) & __reg##_##__fld##_MASK)
+#define AB8500_REG2VAL(__reg, __fld, __val) \
+ (((__val) & __reg##_##__fld##_MASK) >> __reg##_##__fld##_SHIFT)
+
+#define AB8500_CTRL3 0x00000200
+#define AB8500_CTRL3_TH_SD_ENA_SHIFT 3
+#define AB8500_CTRL3_TH_SD_ENA_MASK 0x00000008
+#define AB8500_CTRL3_TH_SD_ENA(__x) \
+ AB8500_VAL2REG(AB8500_CTRL3, TH_SD_ENA, __x)
+#define AB8500_CTRL3_RESET_DENC_N_SHIFT 2
+#define AB8500_CTRL3_RESET_DENC_N_MASK 0x00000004
+#define AB8500_CTRL3_RESET_DENC_N(__x) \
+ AB8500_VAL2REG(AB8500_CTRL3, RESET_DENC_N, __x)
+#define AB8500_CTRL3_RESET_AUD_N_SHIFT 1
+#define AB8500_CTRL3_RESET_AUD_N_MASK 0x00000002
+#define AB8500_CTRL3_RESET_AUD_N(__x) \
+ AB8500_VAL2REG(AB8500_CTRL3, RESET_AUD_N, __x)
+#define AB8500_CTRL3_CLK_32K_OUT2_IS_SHIFT 0
+#define AB8500_CTRL3_CLK_32K_OUT2_IS_MASK 0x00000001
+#define AB8500_CTRL3_CLK_32K_OUT2_IS(__x) \
+ AB8500_VAL2REG(AB8500_CTRL3, CLK_32K_OUT2_IS, __x)
+#define AB8500_SYS_ULP_CLK_CONF 0x0000020A
+#define AB8500_SYS_ULP_CLK_CONF_CLK_27MHZ_PD_ENA_SHIFT 7
+#define AB8500_SYS_ULP_CLK_CONF_CLK_27MHZ_PD_ENA_MASK 0x00000080
+#define AB8500_SYS_ULP_CLK_CONF_CLK_27MHZ_PD_ENA(__x) \
+ AB8500_VAL2REG(AB8500_SYS_ULP_CLK_CONF, CLK_27MHZ_PD_ENA, __x)
+#define AB8500_SYS_ULP_CLK_CONF_CLK_27MHZ_BUF_ENA_SHIFT 6
+#define AB8500_SYS_ULP_CLK_CONF_CLK_27MHZ_BUF_ENA_MASK 0x00000040
+#define AB8500_SYS_ULP_CLK_CONF_CLK_27MHZ_BUF_ENA(__x) \
+ AB8500_VAL2REG(AB8500_SYS_ULP_CLK_CONF, CLK_27MHZ_BUF_ENA, __x)
+#define AB8500_SYS_ULP_CLK_CONF_ULP_CLK_STRE_SHIFT 5
+#define AB8500_SYS_ULP_CLK_CONF_ULP_CLK_STRE_MASK 0x00000020
+#define AB8500_SYS_ULP_CLK_CONF_ULP_CLK_STRE(__x) \
+ AB8500_VAL2REG(AB8500_SYS_ULP_CLK_CONF, ULP_CLK_STRE, __x)
+#define AB8500_SYS_ULP_CLK_CONF_TVOUT_CLK_INV_SHIFT 4
+#define AB8500_SYS_ULP_CLK_CONF_TVOUT_CLK_INV_MASK 0x00000010
+#define AB8500_SYS_ULP_CLK_CONF_TVOUT_CLK_INV(__x) \
+ AB8500_VAL2REG(AB8500_SYS_ULP_CLK_CONF, TVOUT_CLK_INV, __x)
+#define AB8500_SYS_ULP_CLK_CONF_TVOUT_CLK_DE_IN_SHIFT 3
+#define AB8500_SYS_ULP_CLK_CONF_TVOUT_CLK_DE_IN_MASK 0x00000008
+#define AB8500_SYS_ULP_CLK_CONF_TVOUT_CLK_DE_IN(__x) \
+ AB8500_VAL2REG(AB8500_SYS_ULP_CLK_CONF, TVOUT_CLK_DE_IN, __x)
+#define AB8500_SYS_ULP_CLK_CONF_CLK_27MHZ_STRE_SHIFT 2
+#define AB8500_SYS_ULP_CLK_CONF_CLK_27MHZ_STRE_MASK 0x00000004
+#define AB8500_SYS_ULP_CLK_CONF_CLK_27MHZ_STRE(__x) \
+ AB8500_VAL2REG(AB8500_SYS_ULP_CLK_CONF, CLK_27MHZ_STRE, __x)
+#define AB8500_SYS_ULP_CLK_CONF_ULP_CLK_CONF_SHIFT 0
+#define AB8500_SYS_ULP_CLK_CONF_ULP_CLK_CONF_MASK 0x00000003
+#define AB8500_SYS_ULP_CLK_CONF_ULP_CLK_CONF_NO_FUNC 0
+#define AB8500_SYS_ULP_CLK_CONF_ULP_CLK_CONF_AS_OUTPUT 1
+#define AB8500_SYS_ULP_CLK_CONF_ULP_CLK_CONF_AS_INPUT 2
+#define AB8500_SYS_ULP_CLK_CONF_ULP_CLK_CONF(__x) \
+ AB8500_VAL2REG(AB8500_SYS_ULP_CLK_CONF, ULP_CLK_CONF, \
+ AB8500_SYS_ULP_CLK_CONF_ULP_CLK_CONF_##__x)
+#define AB8500_SYS_CLK_CTRL 0x0000020C
+#define AB8500_SYS_CLK_CTRL_USB_CLK_VALID_SHIFT 2
+#define AB8500_SYS_CLK_CTRL_USB_CLK_VALID_MASK 0x00000004
+#define AB8500_SYS_CLK_CTRL_USB_CLK_VALID(__x) \
+ AB8500_VAL2REG(AB8500_SYS_CLK_CTRL, USB_CLK_VALID, __x)
+#define AB8500_SYS_CLK_CTRL_TVOUT_CLK_VALID_SHIFT 1
+#define AB8500_SYS_CLK_CTRL_TVOUT_CLK_VALID_MASK 0x00000002
+#define AB8500_SYS_CLK_CTRL_TVOUT_CLK_VALID(__x) \
+ AB8500_VAL2REG(AB8500_SYS_CLK_CTRL, TVOUT_CLK_VALID, __x)
+#define AB8500_SYS_CLK_CTRL_TVOUT_PLL_ENA_SHIFT 0
+#define AB8500_SYS_CLK_CTRL_TVOUT_PLL_ENA_MASK 0x00000001
+#define AB8500_SYS_CLK_CTRL_TVOUT_PLL_ENA(__x) \
+ AB8500_VAL2REG(AB8500_SYS_CLK_CTRL, TVOUT_PLL_ENA, __x)
+#define AB8500_REGU_MISC1 0x00000380
+#define AB8500_REGU_MISC1_V_TVOUT_LP_SHIFT 7
+#define AB8500_REGU_MISC1_V_TVOUT_LP_MASK 0x00000080
+#define AB8500_REGU_MISC1_V_TVOUT_LP(__x) \
+ AB8500_VAL2REG(AB8500_REGU_MISC1, V_TVOUT_LP, __x)
+#define AB8500_REGU_MISC1_V_INT_CORE_12_LP_SHIFT 6
+#define AB8500_REGU_MISC1_V_INT_CORE_12_LP_MASK 0x00000040
+#define AB8500_REGU_MISC1_V_INT_CORE_12_LP(__x) \
+ AB8500_VAL2REG(AB8500_REGU_MISC1, V_INT_CORE_12_LP, __x)
+#define AB8500_REGU_MISC1_V_INT_CORE_12_SEL_SHIFT 3
+#define AB8500_REGU_MISC1_V_INT_CORE_12_SEL_MASK 0x00000038
+#define AB8500_REGU_MISC1_V_INT_CORE_12_SEL_1_2V 0
+#define AB8500_REGU_MISC1_V_INT_CORE_12_SEL_1_225V 1
+#define AB8500_REGU_MISC1_V_INT_CORE_12_SEL_1_25V 2
+#define AB8500_REGU_MISC1_V_INT_CORE_12_SEL_1_275V 3
+#define AB8500_REGU_MISC1_V_INT_CORE_12_SEL_1_3V 4
+#define AB8500_REGU_MISC1_V_INT_CORE_12_SEL_1_325V 5
+#define AB8500_REGU_MISC1_V_INT_CORE_12_SEL_1_35V 6
+#define AB8500_REGU_MISC1_V_INT_CORE_12_SEL(__x) \
+ AB8500_VAL2REG(AB8500_REGU_MISC1, V_INT_CORE_12_SEL, \
+ AB8500_REGU_MISC1_V_INT_CORE_12_SEL_##__x)
+#define AB8500_REGU_MISC1_V_INT_CORE_12_ENA_SHIFT 2
+#define AB8500_REGU_MISC1_V_INT_CORE_12_ENA_MASK 0x00000004
+#define AB8500_REGU_MISC1_V_INT_CORE_12_ENA(__x) \
+ AB8500_VAL2REG(AB8500_REGU_MISC1, V_INT_CORE_12_ENA, __x)
+#define AB8500_REGU_MISC1_V_TVOUT_ENA_SHIFT 1
+#define AB8500_REGU_MISC1_V_TVOUT_ENA_MASK 0x00000002
+#define AB8500_REGU_MISC1_V_TVOUT_ENA(__x) \
+ AB8500_VAL2REG(AB8500_REGU_MISC1, V_TVOUT_ENA, __x)
+#define AB8500_VAUX12_REGU 0x00000409
+#define AB8500_VAUX12_REGU_VAUX_1_SHIFT 2
+#define AB8500_VAUX12_REGU_VAUX_1_MASK 0x0000000C
+#define AB8500_VAUX12_REGU_VAUX_1_DISABLE 0
+#define AB8500_VAUX12_REGU_VAUX_1_FORCE_HP 1
+#define AB8500_VAUX12_REGU_VAUX_1_BY_CTRL_REG 2
+#define AB8500_VAUX12_REGU_VAUX_1_FORCE_LP 3
+#define AB8500_VAUX12_REGU_VAUX_1(__x) \
+ AB8500_VAL2REG(AB8500_VAUX12_REGU, VAUX_1, \
+ AB8500_VAUX12_REGU_VAUX_1_##__x)
+#define AB8500_VAUX12_REGU_VAUX_2_SHIFT 0
+#define AB8500_VAUX12_REGU_VAUX_2_MASK 0x00000003
+#define AB8500_VAUX12_REGU_VAUX_2_DISABLE 0
+#define AB8500_VAUX12_REGU_VAUX_2_FORCE_HP 1
+#define AB8500_VAUX12_REGU_VAUX_2_BY_CTRL_REG 2
+#define AB8500_VAUX12_REGU_VAUX_2_FORCE_LP 3
+#define AB8500_VAUX12_REGU_VAUX_2(__x) \
+ AB8500_VAL2REG(AB8500_VAUX12_REGU, VAUX_2, \
+ AB8500_VAUX12_REGU_VAUX_2_##__x)
+#define AB8500_VAUX1_SEL 0x0000041F
+#define AB8500_VAUX1_SEL_VAL_SHIFT 0
+#define AB8500_VAUX1_SEL_VAL_MASK 0x0000000F
+#define AB8500_VAUX1_SEL_VAL_1_1V 0
+#define AB8500_VAUX1_SEL_VAL_1_2V 1
+#define AB8500_VAUX1_SEL_VAL_1_3V 2
+#define AB8500_VAUX1_SEL_VAL_1_4V 3
+#define AB8500_VAUX1_SEL_VAL_1_5V 4
+#define AB8500_VAUX1_SEL_VAL_1_8V 5
+#define AB8500_VAUX1_SEL_VAL_1_85V 6
+#define AB8500_VAUX1_SEL_VAL_1_9V 7
+#define AB8500_VAUX1_SEL_VAL_2_5V 8
+#define AB8500_VAUX1_SEL_VAL_2_65V 9
+#define AB8500_VAUX1_SEL_VAL_2_7V 10
+#define AB8500_VAUX1_SEL_VAL_2_75V 11
+#define AB8500_VAUX1_SEL_VAL_2_8V 12
+#define AB8500_VAUX1_SEL_VAL_2_9V 13
+#define AB8500_VAUX1_SEL_VAL_3_0V 14
+#define AB8500_VAUX1_SEL_VAL_3_3V 15
+#define AB8500_VAUX1_SEL_VAL(__x) \
+ AB8500_VAL2REG(AB8500_VAUX1_SEL, VAL, AB8500_VAUX1_SEL_VAL_##__x)
+#define AB8500_DENC_CONF0 0x00000600
+#define AB8500_DENC_CONF0_STD_SHIFT 6
+#define AB8500_DENC_CONF0_STD_MASK 0x000000C0
+#define AB8500_DENC_CONF0_STD_PAL_BDGHI 0
+#define AB8500_DENC_CONF0_STD_PAL_N 1
+#define AB8500_DENC_CONF0_STD_NTSC_M 2
+#define AB8500_DENC_CONF0_STD_PAL_M 3
+#define AB8500_DENC_CONF0_STD(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF0, STD, AB8500_DENC_CONF0_STD_##__x)
+#define AB8500_DENC_CONF0_SYNC_SHIFT 3
+#define AB8500_DENC_CONF0_SYNC_MASK 0x00000038
+#define AB8500_DENC_CONF0_SYNC_F_BASED_SLAVE 1
+#define AB8500_DENC_CONF0_SYNC_AUTO_TEST 7
+#define AB8500_DENC_CONF0_SYNC(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF0, SYNC, AB8500_DENC_CONF0_SYNC_##__x)
+#define AB8500_DENC_CONF1 0x00000601
+#define AB8500_DENC_CONF1_BLK_LI_SHIFT 7
+#define AB8500_DENC_CONF1_BLK_LI_MASK 0x00000080
+#define AB8500_DENC_CONF1_BLK_LI_PARTIAL 0
+#define AB8500_DENC_CONF1_BLK_LI_FULL 1
+#define AB8500_DENC_CONF1_BLK_LI(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF1, BLK_LI, \
+ AB8500_DENC_CONF1_BLK_LI_##__x)
+#define AB8500_DENC_CONF1_FLT_SHIFT 5
+#define AB8500_DENC_CONF1_FLT_MASK 0x00000060
+#define AB8500_DENC_CONF1_FLT_1_1MHZ 0
+#define AB8500_DENC_CONF1_FLT_1_3MHZ 1
+#define AB8500_DENC_CONF1_FLT_1_6MHZ 2
+#define AB8500_DENC_CONF1_FLT_1_9MHZ 3
+#define AB8500_DENC_CONF1_FLT(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF1, FLT, AB8500_DENC_CONF1_FLT_##__x)
+#define AB8500_DENC_CONF1_CO_KI_SHIFT 3
+#define AB8500_DENC_CONF1_CO_KI_MASK 0x00000008
+#define AB8500_DENC_CONF1_CO_KI(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF1, CO_KI, __x)
+#define AB8500_DENC_CONF1_SETUP_MAIN_SHIFT 2
+#define AB8500_DENC_CONF1_SETUP_MAIN_MASK 0x00000004
+#define AB8500_DENC_CONF1_SETUP_MAIN_BLACK_EQ_BLANK 0
+#define AB8500_DENC_CONF1_SETUP_MAIN_BLACK_GT_BLANK 1
+#define AB8500_DENC_CONF1_SETUP_MAIN(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF1, SETUP_MAIN, \
+ AB8500_DENC_CONF1_SETUP_MAIN_##__x)
+#define AB8500_DENC_CONF1_CC_SHIFT 0
+#define AB8500_DENC_CONF1_CC_MASK 0x00000003
+#define AB8500_DENC_CONF1_CC_NONE 0
+#define AB8500_DENC_CONF1_CC_FIELD_1 1
+#define AB8500_DENC_CONF1_CC_FIELD_2 2
+#define AB8500_DENC_CONF1_CC_ALL 3
+#define AB8500_DENC_CONF1_CC(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF1, CC, AB8500_DENC_CONF1_CC_##__x)
+#define AB8500_DENC_CONF2 0x00000602
+#define AB8500_DENC_CONF2_N_INTRL_SHIFT 7
+#define AB8500_DENC_CONF2_N_INTRL_MASK 0x00000080
+#define AB8500_DENC_CONF2_N_INTRL(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF2, N_INTRL, __x)
+#define AB8500_DENC_CONF2_EN_RST_SHIFT 6
+#define AB8500_DENC_CONF2_EN_RST_MASK 0x00000040
+#define AB8500_DENC_CONF2_EN_RST(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF2, EN_RST, __x)
+#define AB8500_DENC_CONF2_BURST_EN_SHIFT 5
+#define AB8500_DENC_CONF2_BURST_EN_MASK 0x00000020
+#define AB8500_DENC_CONF2_BURST_EN(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF2, BURST_EN, __x)
+#define AB8500_DENC_CONF2_SEL_RST_SHIFT 4
+#define AB8500_DENC_CONF2_SEL_RST_MASK 0x00000010
+#define AB8500_DENC_CONF2_SEL_RST_USE_HW_VAL 0
+#define AB8500_DENC_CONF2_SEL_RST_USE_PROG_VAL 1
+#define AB8500_DENC_CONF2_SEL_RST(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF2, SEL_RST, \
+ AB8500_DENC_CONF2_SEL_RST_##__x)
+#define AB8500_DENC_CONF2_RST_OSC_BUF_SHIFT 2
+#define AB8500_DENC_CONF2_RST_OSC_BUF_MASK 0x00000004
+#define AB8500_DENC_CONF2_RST_OSC_BUF(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF2, RST_OSC_BUF, __x)
+#define AB8500_DENC_CONF2_VAL_RST_SHIFT 0
+#define AB8500_DENC_CONF2_VAL_RST_MASK 0x00000003
+#define AB8500_DENC_CONF2_VAL_RST_ALL_LINES 0
+#define AB8500_DENC_CONF2_VAL_RST_EVERY_2ND_FIELD 1
+#define AB8500_DENC_CONF2_VAL_RST_EVERY_4TH_FIELD 2
+#define AB8500_DENC_CONF2_VAL_RST_EVERY_8TH_FIELD 3
+#define AB8500_DENC_CONF2_VAL_RST(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF2, VAL_RST, \
+ AB8500_DENC_CONF2_VAL_RST_##__x)
+#define AB8500_DENC_CONF6 0x00000606
+#define AB8500_DENC_CONF6_SOFT_RESET_SHIFT 7
+#define AB8500_DENC_CONF6_SOFT_RESET_MASK 0x00000080
+#define AB8500_DENC_CONF6_SOFT_RESET(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF6, SOFT_RESET, __x)
+#define AB8500_DENC_CONF6_JUMP_SHIFT 6
+#define AB8500_DENC_CONF6_JUMP_MASK 0x00000040
+#define AB8500_DENC_CONF6_JUMP(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF6, JUMP, __x)
+#define AB8500_DENC_CONF6_DEC_NINC_SHIFT 5
+#define AB8500_DENC_CONF6_DEC_NINC_MASK 0x00000020
+#define AB8500_DENC_CONF6_DEC_NINC(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF6, DEC_NINC, __x)
+#define AB8500_DENC_CONF6_FREE_JUMP_SHIFT 4
+#define AB8500_DENC_CONF6_FREE_JUMP_MASK 0x00000010
+#define AB8500_DENC_CONF6_FREE_JUMP(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF6, FREE_JUMP, __x)
+#define AB8500_DENC_CONF6_MAX_DYN_SHIFT 0
+#define AB8500_DENC_CONF6_MAX_DYN_MASK 0x00000001
+#define AB8500_DENC_CONF6_MAX_DYN(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF6, MAX_DYN, __x)
+#define AB8500_DENC_CONF8 0x00000608
+#define AB8500_DENC_CONF8_PH_RST_MODE_SHIFT 6
+#define AB8500_DENC_CONF8_PH_RST_MODE_MASK 0x000000C0
+#define AB8500_DENC_CONF8_PH_RST_MODE_DISABLED 0
+#define AB8500_DENC_CONF8_PH_RST_MODE_UPDATE_FROM_PHASE_BUF 1
+#define AB8500_DENC_CONF8_PH_RST_MODE_UPDATE_FROM_INC_DFS 2
+#define AB8500_DENC_CONF8_PH_RST_MODE_RESET 3
+#define AB8500_DENC_CONF8_PH_RST_MODE(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF8, PH_RST_MODE, \
+ AB8500_DENC_CONF8_PH_RST_MODE_##__x)
+#define AB8500_DENC_CONF8_VAL_422_MUX_SHIFT 4
+#define AB8500_DENC_CONF8_VAL_422_MUX_MASK 0x00000010
+#define AB8500_DENC_CONF8_VAL_422_MUX_TEST 0
+#define AB8500_DENC_CONF8_VAL_422_MUX_ACTIVE 1
+#define AB8500_DENC_CONF8_VAL_422_MUX(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF8, VAL_422_MUX, \
+ AB8500_DENC_CONF8_VAL_422_MUX_##__x)
+#define AB8500_DENC_CONF8_BLK_ALL_SHIFT 3
+#define AB8500_DENC_CONF8_BLK_ALL_MASK 0x00000008
+#define AB8500_DENC_CONF8_BLK_ALL(__x) \
+ AB8500_VAL2REG(AB8500_DENC_CONF8, BLK_ALL, __x)
+#define AB8500_TVOUT_CTRL 0x00000680
+#define AB8500_TVOUT_CTRL_TV_LOAD_RC_SHIFT 6
+#define AB8500_TVOUT_CTRL_TV_LOAD_RC_MASK 0x00000040
+#define AB8500_TVOUT_CTRL_TV_LOAD_RC(__x) \
+ AB8500_VAL2REG(AB8500_TVOUT_CTRL, TV_LOAD_RC, __x)
+#define AB8500_TVOUT_CTRL_PLUG_TV_TIME_SHIFT 3
+#define AB8500_TVOUT_CTRL_PLUG_TV_TIME_MASK 0x00000038
+#define AB8500_TVOUT_CTRL_PLUG_TV_TIME_0_5S 0
+#define AB8500_TVOUT_CTRL_PLUG_TV_TIME_1S 0
+#define AB8500_TVOUT_CTRL_PLUG_TV_TIME_1_5S 0
+#define AB8500_TVOUT_CTRL_PLUG_TV_TIME_2S 0
+#define AB8500_TVOUT_CTRL_PLUG_TV_TIME_2_5S 0
+#define AB8500_TVOUT_CTRL_PLUG_TV_TIME_3S 0
+#define AB8500_TVOUT_CTRL_PLUG_TV_TIME(__x) \
+ AB8500_VAL2REG(AB8500_TVOUT_CTRL, PLUG_TV_TIME, \
+ AB8500_TVOUT_CTRL_PLUG_TV_TIME_##__x)
+#define AB8500_TVOUT_CTRL_TV_PLUG_ON_SHIFT 2
+#define AB8500_TVOUT_CTRL_TV_PLUG_ON_MASK 0x00000004
+#define AB8500_TVOUT_CTRL_TV_PLUG_ON(__x) \
+ AB8500_VAL2REG(AB8500_TVOUT_CTRL, TV_PLUG_ON, __x)
+#define AB8500_TVOUT_CTRL_DAC_CTRL0_SHIFT 1
+#define AB8500_TVOUT_CTRL_DAC_CTRL0_MASK 0x00000002
+#define AB8500_TVOUT_CTRL_DAC_CTRL0(__x) \
+ AB8500_VAL2REG(AB8500_TVOUT_CTRL, DAC_CTRL0, __x)
+#define AB8500_TVOUT_CTRL_DAC_CTRL1_SHIFT 0
+#define AB8500_TVOUT_CTRL_DAC_CTRL1_MASK 0x00000001
+#define AB8500_TVOUT_CTRL_DAC_CTRL1(__x) \
+ AB8500_VAL2REG(AB8500_TVOUT_CTRL, DAC_CTRL1, __x)
+#define AB8500_TVOUT_CTRL2 0x00000681
+#define AB8500_TVOUT_CTRL2_SWAP_DDR_DATA_IN_SHIFT 1
+#define AB8500_TVOUT_CTRL2_SWAP_DDR_DATA_IN_MASK 0x00000002
+#define AB8500_TVOUT_CTRL2_SWAP_DDR_DATA_IN(__x) \
+ AB8500_VAL2REG(AB8500_TVOUT_CTRL2, SWAP_DDR_DATA_IN, __x)
+#define AB8500_TVOUT_CTRL2_DENC_DDR_SHIFT 0
+#define AB8500_TVOUT_CTRL2_DENC_DDR_MASK 0x00000001
+#define AB8500_TVOUT_CTRL2_DENC_DDR(__x) \
+ AB8500_VAL2REG(AB8500_TVOUT_CTRL2, DENC_DDR, __x)
+#define AB8500_IT_MASK1 0x00000E40
+#define AB8500_IT_MASK1_PON_KEY1_DBR_SHIFT 7
+#define AB8500_IT_MASK1_PON_KEY1_DBR_MASK 0x00000080
+#define AB8500_IT_MASK1_PON_KEY1_DBR(__x) \
+ AB8500_VAL2REG(AB8500_IT_MASK1, PON_KEY1_DBR, __x)
+#define AB8500_IT_MASK1_PON_KEY1_DBF_SHIFT 6
+#define AB8500_IT_MASK1_PON_KEY1_DBF_MASK 0x00000040
+#define AB8500_IT_MASK1_PON_KEY1_DBF(__x) \
+ AB8500_VAL2REG(AB8500_IT_MASK1, PON_KEY1_DBF, __x)
+#define AB8500_IT_MASK1_PON_KEY2_DBR_SHIFT 5
+#define AB8500_IT_MASK1_PON_KEY2_DBR_MASK 0x00000020
+#define AB8500_IT_MASK1_PON_KEY2_DBR(__x) \
+ AB8500_VAL2REG(AB8500_IT_MASK1, PON_KEY2_DBR, __x)
+#define AB8500_IT_MASK1_PON_KEY2_DBF_SHIFT 4
+#define AB8500_IT_MASK1_PON_KEY2_DBF_MASK 0x00000010
+#define AB8500_IT_MASK1_PON_KEY2_DBF(__x) \
+ AB8500_VAL2REG(AB8500_IT_MASK1, PON_KEY2_DBF, __x)
+#define AB8500_IT_MASK1_TEMP_WARN_SHIFT 3
+#define AB8500_IT_MASK1_TEMP_WARN_MASK 0x00000008
+#define AB8500_IT_MASK1_TEMP_WARN(__x) \
+ AB8500_VAL2REG(AB8500_IT_MASK1, TEMP_WARN, __x)
+#define AB8500_IT_MASK1_PLUG_TV_DET_SHIFT 2
+#define AB8500_IT_MASK1_PLUG_TV_DET_MASK 0x00000004
+#define AB8500_IT_MASK1_PLUG_TV_DET(__x) \
+ AB8500_VAL2REG(AB8500_IT_MASK1, PLUG_TV_DET, __x)
+#define AB8500_IT_MASK1_UNPLUG_TV_DET_SHIFT 1
+#define AB8500_IT_MASK1_UNPLUG_TV_DET_MASK 0x00000002
+#define AB8500_IT_MASK1_UNPLUG_TV_DET(__x) \
+ AB8500_VAL2REG(AB8500_IT_MASK1, UNPLUG_TV_DET, __x)
+#define AB8500_IT_MASK1_MAIN_EXT_CH_NOK_SHIFT 0
+#define AB8500_IT_MASK1_MAIN_EXT_CH_NOK_MASK 0x00000001
+#define AB8500_IT_MASK1_MAIN_EXT_CH_NOK(__x) \
+ AB8500_VAL2REG(AB8500_IT_MASK1, MAIN_EXT_CH_NOK, __x)
+#define AB8500_REV 0x00001080
+#define AB8500_REV_FULL_MASK_SHIFT 4
+#define AB8500_REV_FULL_MASK_MASK 0x000000F0
+#define AB8500_REV_FULL_MASK(__x) \
+ AB8500_VAL2REG(AB8500_REV, FULL_MASK, __x)
+#define AB8500_REV_METAL_FIX_SHIFT 0
+#define AB8500_REV_METAL_FIX_MASK 0x0000000F
+#define AB8500_REV_METAL_FIX(__x) \
+ AB8500_VAL2REG(AB8500_REV, METAL_FIX, __x)
diff --git a/drivers/misc/ab8500_gpadc.c b/drivers/misc/ab8500_gpadc.c
new file mode 100644
index 00000000000..94bb8e239fb
--- /dev/null
+++ b/drivers/misc/ab8500_gpadc.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Arun R Murthy <arun.murthy@stericsson.com>
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/ab8500/ab8500-gpadc.h>
+
+/*
+ * GPADC register offsets
+ * Bank : 0x0A
+ */
+#define AB8500_GPADC_CTRL1_REG 0x00
+#define AB8500_GPADC_CTRL2_REG 0x01
+#define AB8500_GPADC_CTRL3_REG 0x02
+#define AB8500_GPADC_AUTO_TIMER_REG 0x03
+#define AB8500_GPADC_STAT_REG 0x04
+#define AB8500_GPADC_MANDATAL_REG 0x05
+#define AB8500_GPADC_MANDATAH_REG 0x06
+#define AB8500_GPADC_AUTODATAL_REG 0x07
+#define AB8500_GPADC_AUTODATAH_REG 0x08
+#define AB8500_GPADC_MUX_CTRL_REG 0x09
+
+/* gpadc constants */
+#define EN_VINTCORE12 0x04
+#define EN_VTVOUT 0x02
+#define EN_GPADC 0x01
+#define DIS_GPADC 0x00
+#define SW_AVG_16 0x60
+#define ADC_SW_CONV 0x04
+#define EN_BUF 0x40
+#define DIS_ZERO 0x00
+
+/**
+ * ab8500_gpadc_convert() - gpadc conversion
+ * @input: analog input to be converted to digital data
+ *
+ * This function converts the selected analog i/p to digital
+ * data. Thereafter calibration has to be made to obtain the
+ * data in the required quantity measurement.
+ */
+int ab8500_gpadc_convert(struct ab8500_gpadc *di, u8 input)
+{
+ int ret, data = 0, looplimit = 0;
+
+ u8 val, low_data, high_data;
+
+ if (!di)
+ return -ENODEV;
+
+ mutex_lock(&di->ab8500_gpadc_lock);
+ /* Enable VTVout LDO this is required for GPADC */
+ regulator_enable(di->regu);
+
+ /* Check if ADC is not busy, lock and proceed */
+ do {
+ ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC,
+ AB8500_GPADC_STAT_REG, &val);
+ if (ret < 0)
+ goto out;
+ msleep(10);
+ } while (val && ++looplimit < 10);
+ if (looplimit >= 10 && val) {
+ dev_err(di->dev, "gpadc_conversion: GPADC was busy after"
+ " %d tries.. ERROR\n", looplimit+1);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Enable GPADC */
+ ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC,
+ AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC);
+ if (ret < 0) {
+ dev_err(di->dev, "gpadc_conversion: enable gpadc failed\n");
+ goto out;
+ }
+ /* Select the input source and set average samples to 16 */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_GPADC,
+ AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16));
+ if (ret < 0) {
+ dev_err(di->dev,
+ "gpadc_conversion: set avg samples failed\n");
+ goto out;
+ }
+ /* Enable ADC, Buffering and select rising edge, start Conversion */
+ ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC,
+ AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
+ if (ret < 0) {
+ dev_err(di->dev,
+ "gpadc_conversion: select falling edge failed\n");
+ goto out;
+ }
+ ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC,
+ AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV);
+ if (ret < 0) {
+ dev_err(di->dev,
+ "gpadc_conversion: start s/w conversion failed\n");
+ goto out;
+ }
+ /* wait for completion of conversion */
+ if (!wait_for_completion_timeout(&di->ab8500_gpadc_complete, HZ)) {
+ dev_err(di->dev,
+ "timeout: didnt recieve GPADC conversion interrupt\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Read the converted RAW data */
+ ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC,
+ AB8500_GPADC_MANDATAL_REG, &low_data);
+ if (ret < 0) {
+ dev_err(di->dev, "gpadc_conversion: read low data failed\n");
+ goto out;
+ }
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC,
+ AB8500_GPADC_MANDATAH_REG, &high_data);
+ if (ret < 0) {
+ dev_err(di->dev, "gpadc_conversion: read high data failed\n");
+ goto out;
+ }
+
+ data = (high_data << 8) | low_data;
+ /* Disable GPADC */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_GPADC,
+ AB8500_GPADC_CTRL1_REG, DIS_GPADC);
+ if (ret < 0) {
+ dev_err(di->dev, "gpadc_conversion: disable gpadc failed\n");
+ goto out;
+ }
+ /* Disable VTVout LDO this is required for GPADC */
+ regulator_disable(di->regu);
+ mutex_unlock(&di->ab8500_gpadc_lock);
+
+ return data;
+
+out:
+ /*
+ * It has shown to be needed to turn off the GPADC if an error occurs,
+ * otherwise we might have problem when waiting for the busy bit in the
+ * GPADC status register to go low. In V1.1 there wait_for_completion
+ * seems to timeout when waiting for an interrupt.. Not seen in V2.0
+ */
+ (void) abx500_set_register_interruptible(di->dev, AB8500_GPADC,
+ AB8500_GPADC_CTRL1_REG, DIS_GPADC);
+ regulator_disable(di->regu);
+ mutex_unlock(&di->ab8500_gpadc_lock);
+ return ret;
+}
+EXPORT_SYMBOL(ab8500_gpadc_convert);
+
+/**
+ * ab8500_bm_gpswadcconvend_handler() - isr for s/w gpadc conversion completion
+ * @irq: irq number
+ * @data: pointer to the data passed during request irq
+ *
+ * This is a interrupt service routine for s/w gpadc conversion completion.
+ * Notifies the gpadc completion is completed and the converted raw value
+ * can be read from the registers.
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_di)
+{
+ struct ab8500_gpadc *di = _di;
+
+ complete(&di->ab8500_gpadc_complete);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit ab8500_gpadc_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct ab8500_gpadc *di;
+
+ di = kzalloc(sizeof(struct ab8500_gpadc), GFP_KERNEL);
+ if (!di) {
+ dev_err(&pdev->dev, "Error: No memory\n");
+ return -ENOMEM;
+ }
+
+ di->parent = dev_get_drvdata(pdev->dev.parent);
+ di->irq = platform_get_irq_byname(pdev, "SW_CONV_END");
+ if (di->irq < 0) {
+ dev_err(di->dev, "failed to get platform irq-%d\n", di->irq);
+ ret = di->irq;
+ goto fail;
+ }
+
+ di->dev = &pdev->dev;
+ mutex_init(&di->ab8500_gpadc_lock);
+
+ /* Initialize completion used to notify completion of conversion */
+ init_completion(&di->ab8500_gpadc_complete);
+
+ /* Register interrupt - SwAdcComplete */
+ ret = request_threaded_irq(di->irq, NULL,
+ ab8500_bm_gpswadcconvend_handler, 0, "ab8500-gpadc", di);
+ if (ret < 0) {
+ dev_err(di->dev, "Failed to register interrupt\n");
+ goto fail;
+ }
+ /* VTVout LDO used to power up ab8500-GPADC */
+ di->regu = regulator_get(&pdev->dev, "ab8500-gpadc");
+ if (IS_ERR(di->regu)) {
+ ret = PTR_ERR(di->regu);
+ dev_err(di->dev, "failed to get vtvout LDO\n");
+ goto fail;
+ }
+ di->parent->gpadc = di;
+ return 0;
+fail:
+ kfree(di);
+ di = NULL;
+ return ret;
+}
+
+static int __devexit ab8500_gpadc_remove(struct platform_device *pdev)
+{
+ struct ab8500_gpadc *di = platform_get_drvdata(pdev);
+
+ /* remove interrupt - completion of Sw ADC conversion */
+ free_irq(di->irq, di);
+ /* disable VTVout LDO that is being used by GPADC */
+ regulator_put(di->regu);
+ kfree(di);
+ di = NULL;
+ return 0;
+}
+
+static struct platform_driver ab8500_gpadc_driver = {
+ .probe = ab8500_gpadc_probe,
+ .remove = __devexit_p(ab8500_gpadc_remove),
+ .driver = {
+ .name = "ab8500-gpadc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ab8500_gpadc_init(void)
+{
+ return platform_driver_register(&ab8500_gpadc_driver);
+}
+
+static void __exit ab8500_gpadc_exit(void)
+{
+ platform_driver_unregister(&ab8500_gpadc_driver);
+}
+
+module_init(ab8500_gpadc_init);
+module_exit(ab8500_gpadc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Arun R Murthy");
+MODULE_ALIAS("platform:ab8500_gpadc");
+MODULE_DESCRIPTION("AB8500 GPADC driver");
diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c
new file mode 100644
index 00000000000..9e3879ef58f
--- /dev/null
+++ b/drivers/misc/arm-charlcd.c
@@ -0,0 +1,396 @@
+/*
+ * Driver for the on-board character LCD found on some ARM reference boards
+ * This is basically an Hitachi HD44780 LCD with a custom IP block to drive it
+ * http://en.wikipedia.org/wiki/HD44780_Character_LCD
+ * Currently it will just display the text "ARM Linux" and the linux version
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Linus Walleij <triad@df.lth.se>
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <generated/utsrelease.h>
+
+#define DRIVERNAME "arm-charlcd"
+#define CHARLCD_TIMEOUT (msecs_to_jiffies(1000))
+
+/* Offsets to registers */
+#define CHAR_COM 0x00U
+#define CHAR_DAT 0x04U
+#define CHAR_RD 0x08U
+#define CHAR_RAW 0x0CU
+#define CHAR_MASK 0x10U
+#define CHAR_STAT 0x14U
+
+#define CHAR_RAW_CLEAR 0x00000000U
+#define CHAR_RAW_VALID 0x00000100U
+
+/* Hitachi HD44780 display commands */
+#define HD_CLEAR 0x01U
+#define HD_HOME 0x02U
+#define HD_ENTRYMODE 0x04U
+#define HD_ENTRYMODE_INCREMENT 0x02U
+#define HD_ENTRYMODE_SHIFT 0x01U
+#define HD_DISPCTRL 0x08U
+#define HD_DISPCTRL_ON 0x04U
+#define HD_DISPCTRL_CURSOR_ON 0x02U
+#define HD_DISPCTRL_CURSOR_BLINK 0x01U
+#define HD_CRSR_SHIFT 0x10U
+#define HD_CRSR_SHIFT_DISPLAY 0x08U
+#define HD_CRSR_SHIFT_DISPLAY_RIGHT 0x04U
+#define HD_FUNCSET 0x20U
+#define HD_FUNCSET_8BIT 0x10U
+#define HD_FUNCSET_2_LINES 0x08U
+#define HD_FUNCSET_FONT_5X10 0x04U
+#define HD_SET_CGRAM 0x40U
+#define HD_SET_DDRAM 0x80U
+#define HD_BUSY_FLAG 0x80U
+
+/**
+ * @dev: a pointer back to containing device
+ * @phybase: the offset to the controller in physical memory
+ * @physize: the size of the physical page
+ * @virtbase: the offset to the controller in virtual memory
+ * @irq: reserved interrupt number
+ * @complete: completion structure for the last LCD command
+ */
+struct charlcd {
+ struct device *dev;
+ u32 phybase;
+ u32 physize;
+ void __iomem *virtbase;
+ int irq;
+ struct completion complete;
+ struct delayed_work init_work;
+};
+
+static irqreturn_t charlcd_interrupt(int irq, void *data)
+{
+ struct charlcd *lcd = data;
+ u8 status;
+
+ status = readl(lcd->virtbase + CHAR_STAT) & 0x01;
+ /* Clear IRQ */
+ writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
+ if (status)
+ complete(&lcd->complete);
+ else
+ dev_info(lcd->dev, "Spurious IRQ (%02x)\n", status);
+ return IRQ_HANDLED;
+}
+
+
+static void charlcd_wait_complete_irq(struct charlcd *lcd)
+{
+ int ret;
+
+ ret = wait_for_completion_interruptible_timeout(&lcd->complete,
+ CHARLCD_TIMEOUT);
+ /* Disable IRQ after completion */
+ writel(0x00, lcd->virtbase + CHAR_MASK);
+
+ if (ret < 0) {
+ dev_err(lcd->dev,
+ "wait_for_completion_interruptible_timeout() "
+ "returned %d waiting for ready\n", ret);
+ return;
+ }
+
+ if (ret == 0) {
+ dev_err(lcd->dev, "charlcd controller timed out "
+ "waiting for ready\n");
+ return;
+ }
+}
+
+static u8 charlcd_4bit_read_char(struct charlcd *lcd)
+{
+ u8 data;
+ u32 val;
+ int i;
+
+ /* If we can, use an IRQ to wait for the data, else poll */
+ if (lcd->irq >= 0)
+ charlcd_wait_complete_irq(lcd);
+ else {
+ i = 0;
+ val = 0;
+ while (!(val & CHAR_RAW_VALID) && i < 10) {
+ udelay(100);
+ val = readl(lcd->virtbase + CHAR_RAW);
+ i++;
+ }
+
+ writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
+ }
+ msleep(1);
+
+ /* Read the 4 high bits of the data */
+ data = readl(lcd->virtbase + CHAR_RD) & 0xf0;
+
+ /*
+ * The second read for the low bits does not trigger an IRQ
+ * so in this case we have to poll for the 4 lower bits
+ */
+ i = 0;
+ val = 0;
+ while (!(val & CHAR_RAW_VALID) && i < 10) {
+ udelay(100);
+ val = readl(lcd->virtbase + CHAR_RAW);
+ i++;
+ }
+ writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
+ msleep(1);
+
+ /* Read the 4 low bits of the data */
+ data |= (readl(lcd->virtbase + CHAR_RD) >> 4) & 0x0f;
+
+ return data;
+}
+
+static bool charlcd_4bit_read_bf(struct charlcd *lcd)
+{
+ if (lcd->irq >= 0) {
+ /*
+ * If we'll use IRQs to wait for the busyflag, clear any
+ * pending flag and enable IRQ
+ */
+ writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
+ init_completion(&lcd->complete);
+ writel(0x01, lcd->virtbase + CHAR_MASK);
+ }
+ readl(lcd->virtbase + CHAR_COM);
+ return charlcd_4bit_read_char(lcd) & HD_BUSY_FLAG ? true : false;
+}
+
+static void charlcd_4bit_wait_busy(struct charlcd *lcd)
+{
+ int retries = 50;
+
+ udelay(100);
+ while (charlcd_4bit_read_bf(lcd) && retries)
+ retries--;
+ if (!retries)
+ dev_err(lcd->dev, "timeout waiting for busyflag\n");
+}
+
+static void charlcd_4bit_command(struct charlcd *lcd, u8 cmd)
+{
+ u32 cmdlo = (cmd << 4) & 0xf0;
+ u32 cmdhi = (cmd & 0xf0);
+
+ writel(cmdhi, lcd->virtbase + CHAR_COM);
+ udelay(10);
+ writel(cmdlo, lcd->virtbase + CHAR_COM);
+ charlcd_4bit_wait_busy(lcd);
+}
+
+static void charlcd_4bit_char(struct charlcd *lcd, u8 ch)
+{
+ u32 chlo = (ch << 4) & 0xf0;
+ u32 chhi = (ch & 0xf0);
+
+ writel(chhi, lcd->virtbase + CHAR_DAT);
+ udelay(10);
+ writel(chlo, lcd->virtbase + CHAR_DAT);
+ charlcd_4bit_wait_busy(lcd);
+}
+
+static void charlcd_4bit_print(struct charlcd *lcd, int line, const char *str)
+{
+ u8 offset;
+ int i;
+
+ /*
+ * We support line 0, 1
+ * Line 1 runs from 0x00..0x27
+ * Line 2 runs from 0x28..0x4f
+ */
+ if (line == 0)
+ offset = 0;
+ else if (line == 1)
+ offset = 0x28;
+ else
+ return;
+
+ /* Set offset */
+ charlcd_4bit_command(lcd, HD_SET_DDRAM | offset);
+
+ /* Send string */
+ for (i = 0; i < strlen(str) && i < 0x28; i++)
+ charlcd_4bit_char(lcd, str[i]);
+}
+
+static void charlcd_4bit_init(struct charlcd *lcd)
+{
+ /* These commands cannot be checked with the busy flag */
+ writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM);
+ msleep(5);
+ writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM);
+ udelay(100);
+ writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM);
+ udelay(100);
+ /* Go to 4bit mode */
+ writel(HD_FUNCSET, lcd->virtbase + CHAR_COM);
+ udelay(100);
+ /*
+ * 4bit mode, 2 lines, 5x8 font, after this the number of lines
+ * and the font cannot be changed until the next initialization sequence
+ */
+ charlcd_4bit_command(lcd, HD_FUNCSET | HD_FUNCSET_2_LINES);
+ charlcd_4bit_command(lcd, HD_DISPCTRL | HD_DISPCTRL_ON);
+ charlcd_4bit_command(lcd, HD_ENTRYMODE | HD_ENTRYMODE_INCREMENT);
+ charlcd_4bit_command(lcd, HD_CLEAR);
+ charlcd_4bit_command(lcd, HD_HOME);
+ /* Put something useful in the display */
+ charlcd_4bit_print(lcd, 0, "ARM Linux");
+ charlcd_4bit_print(lcd, 1, UTS_RELEASE);
+}
+
+static void charlcd_init_work(struct work_struct *work)
+{
+ struct charlcd *lcd =
+ container_of(work, struct charlcd, init_work.work);
+
+ charlcd_4bit_init(lcd);
+}
+
+static int __init charlcd_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct charlcd *lcd;
+ struct resource *res;
+
+ lcd = kzalloc(sizeof(struct charlcd), GFP_KERNEL);
+ if (!lcd)
+ return -ENOMEM;
+
+ lcd->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENOENT;
+ goto out_no_resource;
+ }
+ lcd->phybase = res->start;
+ lcd->physize = resource_size(res);
+
+ if (request_mem_region(lcd->phybase, lcd->physize,
+ DRIVERNAME) == NULL) {
+ ret = -EBUSY;
+ goto out_no_memregion;
+ }
+
+ lcd->virtbase = ioremap(lcd->phybase, lcd->physize);
+ if (!lcd->virtbase) {
+ ret = -ENOMEM;
+ goto out_no_remap;
+ }
+
+ lcd->irq = platform_get_irq(pdev, 0);
+ /* If no IRQ is supplied, we'll survive without it */
+ if (lcd->irq >= 0) {
+ if (request_irq(lcd->irq, charlcd_interrupt, IRQF_DISABLED,
+ DRIVERNAME, lcd)) {
+ ret = -EIO;
+ goto out_no_irq;
+ }
+ }
+
+ platform_set_drvdata(pdev, lcd);
+
+ /*
+ * Initialize the display in a delayed work, because
+ * it is VERY slow and would slow down the boot of the system.
+ */
+ INIT_DELAYED_WORK(&lcd->init_work, charlcd_init_work);
+ schedule_delayed_work(&lcd->init_work, 0);
+
+ dev_info(&pdev->dev, "initalized ARM character LCD at %08x\n",
+ lcd->phybase);
+
+ return 0;
+
+out_no_irq:
+ iounmap(lcd->virtbase);
+out_no_remap:
+ platform_set_drvdata(pdev, NULL);
+out_no_memregion:
+ release_mem_region(lcd->phybase, SZ_4K);
+out_no_resource:
+ kfree(lcd);
+ return ret;
+}
+
+static int __exit charlcd_remove(struct platform_device *pdev)
+{
+ struct charlcd *lcd = platform_get_drvdata(pdev);
+
+ if (lcd) {
+ free_irq(lcd->irq, lcd);
+ iounmap(lcd->virtbase);
+ release_mem_region(lcd->phybase, lcd->physize);
+ platform_set_drvdata(pdev, NULL);
+ kfree(lcd);
+ }
+
+ return 0;
+}
+
+static int charlcd_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct charlcd *lcd = platform_get_drvdata(pdev);
+
+ /* Power the display off */
+ charlcd_4bit_command(lcd, HD_DISPCTRL);
+ return 0;
+}
+
+static int charlcd_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct charlcd *lcd = platform_get_drvdata(pdev);
+
+ /* Turn the display back on */
+ charlcd_4bit_command(lcd, HD_DISPCTRL | HD_DISPCTRL_ON);
+ return 0;
+}
+
+static const struct dev_pm_ops charlcd_pm_ops = {
+ .suspend = charlcd_suspend,
+ .resume = charlcd_resume,
+};
+
+static struct platform_driver charlcd_driver = {
+ .driver = {
+ .name = DRIVERNAME,
+ .owner = THIS_MODULE,
+ .pm = &charlcd_pm_ops,
+ },
+ .remove = __exit_p(charlcd_remove),
+};
+
+static int __init charlcd_init(void)
+{
+ return platform_driver_probe(&charlcd_driver, charlcd_probe);
+}
+
+static void __exit charlcd_exit(void)
+{
+ platform_driver_unregister(&charlcd_driver);
+}
+
+module_init(charlcd_init);
+module_exit(charlcd_exit);
+
+MODULE_AUTHOR("Linus Walleij <triad@df.lth.se>");
+MODULE_DESCRIPTION("ARM Character LCD Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/audio_io_dev/Kconfig b/drivers/misc/audio_io_dev/Kconfig
new file mode 100644
index 00000000000..57bb77172f7
--- /dev/null
+++ b/drivers/misc/audio_io_dev/Kconfig
@@ -0,0 +1,11 @@
+#
+# AB8500 Audio IO Device Driver configuration
+#
+config STE_AUDIO_IO_DEV
+ bool "AB8500 Audio IO device driver"
+ depends on ARCH_U8500 && AB8500_CORE && STM_MSP_I2S
+ default y
+ ---help---
+ If you say Y here, you will enable the AB8500 Audio IO device driver.
+
+ If unsure, say N.
diff --git a/drivers/misc/audio_io_dev/Makefile b/drivers/misc/audio_io_dev/Makefile
new file mode 100644
index 00000000000..44b21fcc573
--- /dev/null
+++ b/drivers/misc/audio_io_dev/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for AB8500 device drivers
+#
+obj-$(CONFIG_STE_AUDIO_IO_DEV) += ste_audio_io.o
+ste_audio_io-objs := ste_audio_io_dev.o\
+ ste_audio_io_core.o\
+ ste_audio_io_func.o\
+ ste_audio_io_hwctrl_common.o
+
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_ab8500_reg_defs.h b/drivers/misc/audio_io_dev/ste_audio_io_ab8500_reg_defs.h
new file mode 100644
index 00000000000..d8bef72697c
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_ab8500_reg_defs.h
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+
+#ifndef _AUDIOIO_REG_DEFS_H_
+#define _AUDIOIO_REG_DEFS_H_
+
+
+ /* Registers */
+#define POWER_UP_CONTROL_REG 0x0D00
+#define SOFTWARE_RESET_REG 0x0D01
+#define DIGITAL_AD_CHANNELS_ENABLE_REG 0x0D02
+#define DIGITAL_DA_CHANNELS_ENABLE_REG 0x0D03
+#define LOW_POWER_HS_EAR_CONF_REG 0x0D04
+#define LINE_IN_MIC_CONF_REG 0x0D05
+#define DMIC_ENABLE_REG 0x0D06
+#define ADC_DAC_ENABLE_REG 0x0D07
+#define ANALOG_OUTPUT_ENABLE_REG 0x0D08
+#define DIGITAL_OUTPUT_ENABLE_REG 0x0D09
+#define MUTE_HS_EAR_REG 0x0D0A
+#define SHORT_CIRCUIT_DISABLE_REG 0x0D0B
+#define NCP_ENABLE_HS_AUTOSTART_REG 0x0D0C
+#define ENVELOPE_THRESHOLD_REG 0x0D0D
+#define ENVELOPE_DECAY_TIME_REG 0x0D0E
+#define VIB_DRIVER_CONF_REG 0x0D0F
+#define PWM_VIBNL_CONF_REG 0x0D10
+#define PWM_VIBPL_CONF_REG 0x0D11
+#define PWM_VIBNR_CONF_REG 0x0D12
+#define PWM_VIBPR_CONF_REG 0x0D13
+#define ANALOG_MIC1_GAIN_REG 0x0D14
+#define ANALOG_MIC2_GAIN_REG 0x0D15
+#define ANALOG_HS_GAIN_REG 0x0D16
+#define ANALOG_LINE_IN_GAIN_REG 0x0D17
+#define LINE_IN_TO_HSL_GAIN_REG 0x0D18
+#define LINE_IN_TO_HSR_GAIN_REG 0x0D19
+#define AD_FILTER_CONF_REG 0x0D1A
+#define IF0_IF1_MASTER_CONF_REG 0x0D1B
+#define IF0_CONF_REG 0x0D1C
+#define TDM_IF_BYPASS_B_FIFO_REG 0x0D1D
+#define IF1_CONF_REG 0x0D1E
+#define AD_ALLOCATION_TO_SLOT0_1_REG 0x0D1F
+#define AD_ALLOCATION_TO_SLOT2_3_REG 0x0D20
+#define AD_ALLOCATION_TO_SLOT4_5_REG 0x0D21
+#define AD_ALLOCATION_TO_SLOT6_7_REG 0x0D22
+#define AD_ALLOCATION_TO_SLOT8_9_REG 0x0D23
+#define AD_ALLOCATION_TO_SLOT10_11_REG 0x0D24
+#define AD_ALLOCATION_TO_SLOT12_13_REG 0x0D25
+#define AD_ALLOCATION_TO_SLOT14_15_REG 0x0D26
+#define AD_ALLOCATION_TO_SLOT16_17_REG 0x0D27
+#define AD_ALLOCATION_TO_SLOT18_19_REG 0x0D28
+#define AD_ALLOCATION_TO_SLOT20_21_REG 0x0D29
+#define AD_ALLOCATION_TO_SLOT22_23_REG 0x0D2A
+#define AD_ALLOCATION_TO_SLOT24_25_REG 0x0D2B
+#define AD_ALLOCATION_TO_SLOT26_27_REG 0x0D2C
+#define AD_ALLOCATION_TO_SLOT28_29_REG 0x0D2D
+#define AD_ALLOCATION_TO_SLOT30_31_REG 0x0D2E
+#define AD_SLOT_0_TO_7_TRISTATE_REG 0x0D2F
+#define AD_SLOT_8_TO_15_TRISTATE_REG 0x0D30
+#define AD_SLOT_16_TO_23_TRISTATE_REG 0x0D31
+#define AD_SLOT_24_TO_31_TRISTATE_REG 0x0D32
+#define SLOT_SELECTION_TO_DA1_REG 0x0D33
+#define SLOT_SELECTION_TO_DA2_REG 0x0D34
+#define SLOT_SELECTION_TO_DA3_REG 0x0D35
+#define SLOT_SELECTION_TO_DA4_REG 0x0D36
+#define SLOT_SELECTION_TO_DA5_REG 0x0D37
+#define SLOT_SELECTION_TO_DA6_REG 0x0D38
+#define SLOT_SELECTION_TO_DA7_REG 0x0D39
+#define SLOT_SELECTION_TO_DA8_REG 0x0D3A
+#define CLASS_D_EMI_PARALLEL_CONF_REG 0x0D3B
+#define CLASS_D_PATH_CONTROL_REG 0x0D3C
+#define CLASS_D_DITHER_CONTROL_REG 0x0D3D
+#define DMIC_DECIMATOR_FILTER_REG 0x0D3E
+#define DIGITAL_MUXES_REG1 0x0D3F
+#define DIGITAL_MUXES_REG2 0x0D40
+#define AD1_DIGITAL_GAIN_REG 0x0D41
+#define AD2_DIGITAL_GAIN_REG 0x0D42
+#define AD3_DIGITAL_GAIN_REG 0x0D43
+#define AD4_DIGITAL_GAIN_REG 0x0D44
+#define AD5_DIGITAL_GAIN_REG 0x0D45
+#define AD6_DIGITAL_GAIN_REG 0x0D46
+#define DA1_DIGITAL_GAIN_REG 0x0D47
+#define DA2_DIGITAL_GAIN_REG 0x0D48
+#define DA3_DIGITAL_GAIN_REG 0x0D49
+#define DA4_DIGITAL_GAIN_REG 0x0D4A
+#define DA5_DIGITAL_GAIN_REG 0x0D4B
+#define DA6_DIGITAL_GAIN_REG 0x0D4C
+#define AD1_TO_HFL_DIGITAL_GAIN_REG 0x0D4D
+#define AD2_TO_HFR_DIGITAL_GAIN_REG 0x0D4E
+#define HSL_EAR_DIGITAL_GAIN_REG 0x0D4F
+#define HSR_DIGITAL_GAIN_REG 0x0D50
+#define SIDETONE_FIR1_GAIN_REG 0x0D51
+#define SIDETONE_FIR2_GAIN_REG 0x0D52
+#define ANC_FILTER_CONTROL_REG 0x0D53
+#define ANC_WARPED_GAIN_REG 0x0D54
+#define ANC_FIR_OUTPUT_GAIN_REG 0x0D55
+#define ANC_IIR_OUTPUT_GAIN_REG 0x0D56
+#define ANC_FIR_COEFF_MSB_REG 0x0D57
+#define ANC_FIR_COEFF_LSB_REG 0x0D58
+#define ANC_IIR_COEFF_MSB_REG 0x0D59
+#define ANC_IIR_COEFF_LSB_REG 0x0D5A
+#define ANC_WARP_DELAY_MSB_REG 0x0D5B
+#define ANC_WARP_DELAY_LSB_REG 0x0D5C
+#define ANC_FIR_PEAK_MSB_REG 0x0D5D
+#define ANC_FIR_PEAK_LSB_REG 0x0D5E
+#define ANC_IIR_PEAK_MSB_REG 0x0D5F
+#define ANC_IIR_PEAK_LSB_REG 0x0D60
+#define SIDETONE_FIR_ADDR_REG 0x0D61
+#define SIDETONE_FIR_COEFF_MSB_REG 0x0D62
+#define SIDETONE_FIR_COEFF_LSB_REG 0x0D63
+#define FILTERS_CONTROL_REG 0x0D64
+#define IRQ_MASK_LSB_REG 0x0D65
+#define IRQ_STATUS_LSB_REG 0x0D66
+#define IRQ_MASK_MSB_REG 0x0D67
+#define IRQ_STATUS_MSB_REG 0x0D68
+#define BURST_FIFO_INT_CONTROL_REG 0x0D69
+#define BURST_FIFO_LENGTH_REG 0x0D6A
+#define BURST_FIFO_CONTROL_REG 0x0D6B
+#define BURST_FIFO_SWITCH_FRAME_REG 0x0D6C
+#define BURST_FIFO_WAKE_UP_DELAY_REG 0x0D6D
+#define BURST_FIFO_SAMPLES_REG 0x0D6E
+#define REVISION_REG 0x0D6F
+
+/* POWER_UP_CONTROL_REG Masks */
+#define DEVICE_POWER_UP 0x80
+#define ANALOG_PARTS_POWER_UP 0x08
+
+/* SOFTWARE_RESET_REG Masks */
+#define SW_RESET 0x80
+
+/* DIGITAL_AD_CHANNELS_ENABLE_REG Masks */
+#define EN_AD1 0x80
+#define EN_AD2 0x80
+#define EN_AD3 0x20
+#define EN_AD4 0x20
+#define EN_AD5 0x08
+#define EN_AD6 0x04
+
+/* DIGITAL_DA_CHANNELS_ENABLE_REG Masks */
+#define EN_DA1 0x80
+#define EN_DA2 0x40
+#define EN_DA3 0x20
+#define EN_DA4 0x10
+#define EN_DA5 0x08
+#define EN_DA6 0x04
+
+/* LOW_POWER_HS_EAR_CONF_REG Masks */
+#define LOW_POWER_HS 0x80
+#define HS_DAC_DRIVER_LP 0x40
+#define HS_DAC_LP 0x20
+#define EAR_DAC_LP 0x10
+
+/* LINE_IN_MIC_CONF_REG Masks */
+#define EN_MIC1 0x80
+#define EN_MIC2 0x40
+#define EN_LIN_IN_L 0x20
+#define EN_LIN_IN_R 0x10
+#define MUT_MIC1 0x08
+#define MUT_MIC2 0x04
+#define MUT_LIN_IN_L 0x02
+#define MUT_LIN_IN_R 0x01
+
+/* DMIC_ENABLE_REG Masks */
+#define EN_DMIC1 0x80
+#define EN_DMIC2 0x40
+#define EN_DMIC3 0x20
+#define EN_DMIC4 0x10
+#define EN_DMIC5 0x08
+#define EN_DMIC6 0x04
+
+/* ADC_DAC_ENABLE_REG Masks */
+#define SEL_MIC1B_CLR_MIC1A 0x80
+#define SEL_LINR_CLR_MIC2 0x40
+#define POWER_UP_HSL_DAC 0x20
+#define POWER_UP_HSR_DAC 0x10
+#define POWER_UP_ADC1 0x04
+#define POWER_UP_ADC3 0x02
+#define POWER_UP_ADC2 0x01
+
+/* ANALOG_OUTPUT_ENABLE_REG and DIGITAL_OUTPUT_ENABLE_REG and
+ MUTE_HS_EAR_REG Masks */
+#define EN_EAR_DAC_MASK 0x04
+#define EN_HSL_DAC_MASK 0x02
+#define EN_HSR_DAC_MASK 0x01
+#define EN_EAR_MASK 0x40
+#define EN_HSL_MASK 0x20
+#define EN_HSR_MASK 0x10
+#define EN_HFL_MASK 0x08
+#define EN_HFR_MASK 0x04
+#define EN_VIBL_MASK 0x02
+#define EN_VIBR_MASK 0x01
+
+/* SHORT_CIRCUIT_DISABLE_REG Masks */
+#define HS_SHORT_DIS 0x20
+#define HS_PULL_DOWN_EN 0x10
+#define HS_OSC_EN 0x04
+#define DIS_HS_FAD 0x02
+#define HS_ZCD_DIS 0x01
+
+/* NCP_ENABLE_HS_AUTOSTART_REG Masks */
+#define EN_NEG_CP 0x80
+#define HS_AUTO_EN 0x01
+
+/* ANALOG_MIC1_GAIN_REG and ANALOG_MIC1_GAIN_REG Masks */
+#define MIC_ANALOG_GAIN_MASK 0x1F
+
+/*ANALOG_HS_GAIN_REG and ANALOG_LINE_IN_GAIN_REG Masks*/
+#define L_ANALOG_GAIN_MASK 0xF0
+#define R_ANALOG_GAIN_MASK 0x0F
+
+/* IF0_IF1_MASTER_CONF_REG Masks */
+#define EN_MASTGEN 0x80
+#define BITCLK_OSR_N_64 0x02
+#define BITCLK_OSR_N_128 0x04
+#define BITCLK_OSR_N_256 0x06
+#define EN_FSYNC_BITCLK 0x01
+#define EN_FSYNC_BITCLK1 0x10
+
+/* IF0_CONF_REG and IF1_CONF_REG Masks */
+#define FSYNC_FALLING_EDGE 0x40
+#define BITCLK_FALLING_EDGE 0x20
+#define IF_DELAYED 0x10
+#define I2S_LEFT_ALIGNED_FORMAT 0x08
+#define TDM_FORMAT 0x04
+#define WORD_LENGTH_32 0x03
+#define WORD_LENGTH_24 0x02
+#define WORD_LENGTH_20 0x01
+#define WORD_LENGTH_16 0x00
+
+/* TDM_IF_BYPASS_B_FIFO_REG Masks */
+#define IF0_BFifoEn 0x01
+#define IF0_MASTER 0x02
+
+#define IF1_MASTER 0x20
+/*
+ * AD_ALLOCATION_TO_SLOT0_1_REG and AD_ALLOCATION_TO_SLOT2_3_REG and
+ * AD_ALLOCATION_TO_SLOT4_5_REG and AD_ALLOCATION_TO_SLOT6_7_REG Masks
+ */
+#define DATA_FROM_AD_OUT1 0x00
+#define DATA_FROM_AD_OUT2 0x01
+#define DATA_FROM_AD_OUT3 0x02
+#define DATA_FROM_AD_OUT4 0x03
+#define DATA_FROM_AD_OUT5 0x04
+#define DATA_FROM_AD_OUT6 0x05
+#define DATA_FROM_AD_OUT7 0x06
+#define DATA_FROM_AD_OUT8 0x07
+#define TRISTATE 0x0C
+
+/*
+ * SLOT_SELECTION_TO_DA1_REG and SLOT_SELECTION_TO_DA2_REG and
+ * SLOT_SELECTION_TO_DA3_REG and SLOT_SELECTION_TO_DA4_REG Masks
+ * SLOT_SELECTION_TO_DA5_REG and SLOT_SELECTION_TO_DA6_REG Masks
+ */
+#define SLOT08_FOR_DA_PATH 0x08
+#define SLOT09_FOR_DA_PATH 0x09
+#define SLOT10_FOR_DA_PATH 0x0A
+#define SLOT11_FOR_DA_PATH 0x0B
+#define SLOT12_FOR_DA_PATH 0x0C
+#define SLOT13_FOR_DA_PATH 0x0D
+#define SLOT14_FOR_DA_PATH 0x0E
+#define SLOT15_FOR_DA_PATH 0x0F
+
+/* DIGITAL_MUXES_REG1 Masks */
+#define DA1_TO_HSL 0x80
+#define DA2_TO_HSR 0x40
+#define SEL_DMIC1_FOR_AD_OUT1 0x20
+#define SEL_DMIC2_FOR_AD_OUT2 0x10
+#define SEL_DMIC3_FOR_AD_OUT3 0x08
+/*#define SEL_DMIC5_FOR_AD_OUT5 0x04*/
+/*#define SEL_DMIC6_FOR_AD_OUT6 0x02*/
+/*#define SEL_DMIC1_FOR_AD_OUT1 0x01*/
+
+/*
+ * AD1_DIGITAL_GAIN_REG and AD2_DIGITAL_GAIN_REG & AD3_DIGITAL_GAIN_REG Masks
+ * AD4_DIGITAL_GAIN_REG and AD5_DIGITAL_GAIN_REG & AD6_DIGITAL_GAIN_REG Masks
+ * DA1_DIGITAL_GAIN_REG and DA2_DIGITAL_GAIN_REG & DA3_DIGITAL_GAIN_REG Masks
+ * DA4_DIGITAL_GAIN_REG and DA5_DIGITAL_GAIN_REG & DA6_DIGITAL_GAIN_REG Masks
+ */
+#define DIS_FADING 0x40
+#define DIGITAL_GAIN_MASK 0x3F
+
+/*
+ * HSL_EAR_DIGITAL_GAIN_REG and HSR_DIGITAL_GAIN_REG Masks
+ */
+#define FADE_SPEED_MASK 0xC0
+#define DIS_DIG_GAIN_FADING 0x10
+#define HS_DIGITAL_GAIN_MASK 0x0F
+
+/* FMRx/FMTx Masks */
+#define SLOT24_FOR_DA_PATH 0x18
+#define SEL_AD_OUT8_FROM_DAIN7 0x20
+#define SLOT25_FOR_DA_PATH 0x19
+#define SEL_AD_OUT6_FROM_DAIN8 0x20
+#define SEL_IF8_FROM_AD_OUT7 0x60
+#define SEL_IF17_FROM_AD_OUT7 0x60
+#define SEL_IF16_FROM_AD_OUT8 0x07
+
+#define SEL_IF6_FROM_AD_OUT5 0x04
+#define SEL_IF7_FROM_AD_OUT6 0x50
+#define SEL_IF17_FROM_AD_OUT6 0x50
+#define SEL_AD_OUT5_FROM_DAIN7 0x20
+
+/* Burst FIFO Control Masks */
+#define WAKEUP_SIGNAL_SAMPLE_COUNT 0x1B
+#define BURST_FIFO_TRANSFER_LENGTH 0xC0
+#define BURST_FIFO_INF_RUNNING 0x01
+#define BURST_FIFO_INF_IN_MASTER_MODE 0x02
+#define PRE_BIT_CLK0_COUNT 0x1C
+#define BURST_FIFO_WAKUP_DEALAY 0x70
+
+/* AB8500 power control Masks */
+#define AB8500_VER_1_0 0x10
+#define AB8500_VER_1_1 0x11
+#define CLK_32K_OUT2_DISABLE 0x01
+#define INACTIVE_RESET_AUDIO 0x02
+#define AB8500_REQ_SYS_CLK 0x08
+#define ENABLE_AUDIO_CLK_TO_AUDIO_BLK 0x10
+#define ENABLE_VINTCORE12_SUPPLY 0x04
+#define VAMIC2_ENABLE 0x10
+#define VAMIC1_ENABLE 0x08
+#define VDMIC_ENABLE 0x04
+#define VAUDIO_ENABLE 0x02
+#define GPIO27_DIR_OUTPUT 0x04
+#define GPIO29_DIR_OUTPUT 0x10
+#define GPIO31_DIR_OUTPUT 0x40
+
+#endif
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_core.c b/drivers/misc/audio_io_dev/ste_audio_io_core.c
new file mode 100644
index 00000000000..b4c07562670
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_core.c
@@ -0,0 +1,1207 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <mach/ste_audio_io_vibrator.h>
+#include "ste_audio_io_core.h"
+#include "ste_audio_io_hwctrl_common.h"
+#include "ste_audio_io_ab8500_reg_defs.h"
+
+static struct audiocodec_context_t *ptr_audio_codec_cnxt;
+
+static struct clk *clk_ptr_msp1;
+static struct clk *clk_ptr_msp3;
+
+static struct regulator *regulator_vdmic;
+static struct regulator *regulator_vaudio;
+static struct regulator *regulator_vamic1;
+static struct regulator *regulator_vamic2;
+
+bool ste_audio_io_core_is_ready_for_suspend()
+{
+ bool err = false;
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+ if ((!ptr_audio_codec_cnxt->power_client) &&
+ (!ptr_audio_codec_cnxt->audio_codec_powerup))
+ err = true;
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+ return err;
+}
+int ste_audio_io_core_api_init_data(struct platform_device *pdev)
+{
+ int status = 0;
+ ptr_audio_codec_cnxt = kmalloc(sizeof(struct audiocodec_context_t),
+ GFP_KERNEL);
+ if (!ptr_audio_codec_cnxt)
+ return -ENOMEM;
+
+ memset(ptr_audio_codec_cnxt, 0, sizeof(*ptr_audio_codec_cnxt));
+ ptr_audio_codec_cnxt->dev = &pdev->dev;
+ mutex_init(&(ptr_audio_codec_cnxt->audio_io_mutex));
+ regulator_vdmic = regulator_get(NULL, "v-dmic");
+ if (IS_ERR(regulator_vdmic)) {
+ status = PTR_ERR(regulator_vdmic);
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Register error for v-dmic=%d", status);
+ goto free_audio_codec_cnxt;
+ }
+ regulator_vamic1 = regulator_get(NULL, "v-amic1");
+ if (IS_ERR(regulator_vamic1)) {
+ status = PTR_ERR(regulator_vamic1);
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Register error for v-amic1=%d", status);
+ goto free_regulator_vdmic;
+ }
+ regulator_vamic2 = regulator_get(NULL, "v-amic2");
+ if (IS_ERR(regulator_vamic2)) {
+ status = PTR_ERR(regulator_vamic2);
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Register error for v-amic2=%d", status);
+ goto free_regulator_vdmic_vamic1;
+ }
+ regulator_vaudio = regulator_get(NULL, "v-audio");
+ if (IS_ERR(regulator_vaudio)) {
+ status = PTR_ERR(regulator_vaudio);
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Register error for v-audio=%d", status);
+ goto free_regulator_vdmic_vamic1_vamic2;
+ }
+ ste_audio_io_init_transducer_cnxt();
+ return 0;
+free_regulator_vdmic_vamic1_vamic2:
+ regulator_put(regulator_vamic2);
+free_regulator_vdmic_vamic1:
+ regulator_put(regulator_vamic1);
+free_regulator_vdmic:
+ regulator_put(regulator_vdmic);
+free_audio_codec_cnxt:
+ kfree(ptr_audio_codec_cnxt);
+ return status;
+}
+
+void ste_audio_io_init_transducer_cnxt(void)
+{
+ struct transducer_context_t *ptr = NULL;
+
+ /* initializing HEADSET properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[HS_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_headset;
+ ptr->pwr_down_func = ste_audio_io_power_down_headset;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = ste_audio_io_set_headset_gain;
+ ptr->get_gain_func = ste_audio_io_get_headset_gain;
+ ptr->mute_func = ste_audio_io_mute_headset;
+ ptr->unmute_func = ste_audio_io_unmute_headset;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = ste_audio_io_enable_fade_headset;
+ ptr->disable_fade_func = ste_audio_io_disable_fade_headset;
+ ptr->switch_to_burst_func = ste_audio_io_switch_to_burst_mode_headset;
+ ptr->switch_to_normal_func = ste_audio_io_switch_to_normal_mode_headset;
+
+ /* initializing EARPIECE properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[EAR_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_earpiece;
+ ptr->pwr_down_func = ste_audio_io_power_down_earpiece;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = ste_audio_io_set_earpiece_gain;
+ ptr->get_gain_func = ste_audio_io_get_earpiece_gain;
+ ptr->mute_func = ste_audio_io_mute_earpiece;
+ ptr->unmute_func = ste_audio_io_unmute_earpiece;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = ste_audio_io_enable_fade_earpiece;
+ ptr->disable_fade_func = ste_audio_io_disable_fade_earpiece;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+
+ /* initializing IHF properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[IHF_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_ihf;
+ ptr->pwr_down_func = ste_audio_io_power_down_ihf;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = ste_audio_io_set_ihf_gain;
+ ptr->get_gain_func = ste_audio_io_get_ihf_gain;
+ ptr->mute_func = ste_audio_io_mute_ihf;
+ ptr->unmute_func = ste_audio_io_unmute_ihf;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = ste_audio_io_enable_fade_ihf;
+ ptr->disable_fade_func = ste_audio_io_disable_fade_ihf;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+
+ /* initializing VIBL properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[VIBL_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_vibl;
+ ptr->pwr_down_func = ste_audio_io_power_down_vibl;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = ste_audio_io_set_vibl_gain;
+ ptr->get_gain_func = ste_audio_io_get_vibl_gain;
+ ptr->mute_func = ste_audio_io_mute_vibl;
+ ptr->unmute_func = ste_audio_io_unmute_vibl;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = ste_audio_io_enable_fade_vibl;
+ ptr->disable_fade_func = ste_audio_io_disable_fade_vibl;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+ /* initializing VIBR properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[VIBR_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_vibr;
+ ptr->pwr_down_func = ste_audio_io_power_down_vibr;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = ste_audio_io_set_vibr_gain;
+ ptr->get_gain_func = ste_audio_io_get_vibr_gain;
+ ptr->mute_func = ste_audio_io_mute_vibr;
+ ptr->unmute_func = ste_audio_io_unmute_vibr;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = ste_audio_io_enable_fade_vibr;
+ ptr->disable_fade_func = ste_audio_io_disable_fade_vibr;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+ /* initializing MIC1A properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[MIC1A_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_mic1a;
+ ptr->pwr_down_func = ste_audio_io_power_down_mic1a;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = ste_audio_io_set_mic1a_gain;
+ ptr->get_gain_func = ste_audio_io_get_mic1a_gain;
+ ptr->mute_func = ste_audio_io_mute_mic1a;
+ ptr->unmute_func = ste_audio_io_unmute_mic1a;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = ste_audio_io_enable_fade_mic1a;
+ ptr->disable_fade_func = ste_audio_io_disable_fade_mic1a;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+
+ /* initializing MIC1B properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[MIC1B_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_mic1b;
+ ptr->pwr_down_func = ste_audio_io_power_down_mic1b;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = ste_audio_io_set_mic1a_gain;
+ ptr->get_gain_func = ste_audio_io_get_mic1a_gain;
+ ptr->mute_func = ste_audio_io_mute_mic1a;
+ ptr->unmute_func = ste_audio_io_unmute_mic1a;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = ste_audio_io_enable_fade_mic1a;
+ ptr->disable_fade_func = ste_audio_io_disable_fade_mic1a;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+ /* initializing MIC2 properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[MIC2_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_mic2;
+ ptr->pwr_down_func = ste_audio_io_power_down_mic2;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = ste_audio_io_set_mic2_gain;
+ ptr->get_gain_func = ste_audio_io_get_mic2_gain;
+ ptr->mute_func = ste_audio_io_mute_mic2;
+ ptr->unmute_func = ste_audio_io_unmute_mic2;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = ste_audio_io_enable_fade_mic2;
+ ptr->disable_fade_func = ste_audio_io_disable_fade_mic2;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+ /* initializing LIN properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[LIN_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_lin;
+ ptr->pwr_down_func = ste_audio_io_power_down_lin;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = ste_audio_io_set_lin_gain;
+ ptr->get_gain_func = ste_audio_io_get_lin_gain;
+ ptr->mute_func = ste_audio_io_mute_lin;
+ ptr->unmute_func = ste_audio_io_unmute_lin;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = ste_audio_io_enable_fade_lin;
+ ptr->disable_fade_func = ste_audio_io_disable_fade_lin;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+ /* initializing DMIC12 properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[DMIC12_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_dmic12;
+ ptr->pwr_down_func = ste_audio_io_power_down_dmic12;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = ste_audio_io_set_dmic12_gain;
+ ptr->get_gain_func = ste_audio_io_get_dmic12_gain;
+ ptr->mute_func = ste_audio_io_mute_dmic12;
+ ptr->unmute_func = ste_audio_io_unmute_dmic12;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = ste_audio_io_enable_fade_dmic12;
+ ptr->disable_fade_func = ste_audio_io_disable_fade_dmic12;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+ /* initializing DMIC34 properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[DMIC34_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_dmic34;
+ ptr->pwr_down_func = ste_audio_io_power_down_dmic34;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = ste_audio_io_set_dmic34_gain;
+ ptr->get_gain_func = ste_audio_io_get_dmic34_gain;
+ ptr->mute_func = ste_audio_io_mute_dmic34;
+ ptr->unmute_func = ste_audio_io_unmute_dmic34;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = ste_audio_io_enable_fade_dmic34;
+ ptr->disable_fade_func = ste_audio_io_disable_fade_dmic34;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+ /* initializing DMIC56 properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[DMIC56_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_dmic56;
+ ptr->pwr_down_func = ste_audio_io_power_down_dmic56;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = ste_audio_io_set_dmic56_gain;
+ ptr->get_gain_func = ste_audio_io_get_dmic56_gain;
+ ptr->mute_func = ste_audio_io_mute_dmic56;
+ ptr->unmute_func = ste_audio_io_unmute_dmic56;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = ste_audio_io_enable_fade_dmic56;
+ ptr->disable_fade_func = ste_audio_io_disable_fade_dmic56;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+
+ /* initializing FMRx properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[FMRX_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_fmrx;
+ ptr->pwr_down_func = ste_audio_io_power_down_fmrx;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = NULL;
+ ptr->get_gain_func = NULL;
+ ptr->mute_func = NULL;
+ ptr->unmute_func = NULL;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = NULL;
+ ptr->disable_fade_func = NULL;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+ /* initializing FMTx properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[FMTX_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_fmtx;
+ ptr->pwr_down_func = ste_audio_io_power_down_fmtx;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = NULL;
+ ptr->get_gain_func = NULL;
+ ptr->mute_func = NULL;
+ ptr->unmute_func = NULL;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = NULL;
+ ptr->disable_fade_func = NULL;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+
+ /* initializing BLUETOOTH properties */
+ ptr = &ptr_audio_codec_cnxt->transducer[BLUETOOTH_CH];
+ ptr->pwr_up_func = ste_audio_io_power_up_bluetooth;
+ ptr->pwr_down_func = ste_audio_io_power_down_bluetooth;
+ ptr->pwr_state_func = NULL;
+ ptr->set_gain_func = NULL;
+ ptr->get_gain_func = NULL;
+ ptr->mute_func = NULL;
+ ptr->unmute_func = NULL;
+ ptr->mute_state_func = NULL;
+ ptr->enable_fade_func = NULL;
+ ptr->disable_fade_func = NULL;
+ ptr->switch_to_burst_func = NULL;
+ ptr->switch_to_normal_func = NULL;
+}
+
+
+void ste_audio_io_core_api_free_data(void)
+{
+ regulator_put(regulator_vdmic);
+ regulator_put(regulator_vamic1);
+ regulator_put(regulator_vamic2);
+ regulator_put(regulator_vaudio);
+ kfree(ptr_audio_codec_cnxt);
+}
+
+int ste_audio_io_core_api_powerup_audiocodec(int power_client)
+{
+ int error = 0;
+ int acodec_device_id;
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ acodec_device_id = abx500_get_chip_id(&ste_audio_io_device->dev);
+
+ /*
+ * If there is no power client registered, power up
+ * common audio blocks for audio and vibrator
+ */
+ if (!ptr_audio_codec_cnxt->power_client) {
+ __u8 data, old_data;
+
+ old_data = HW_REG_READ(AB8500_CTRL3_REG);
+
+ /* Enable 32 Khz clock signal on Clk32KOut2 ball */
+ data = (~CLK_32K_OUT2_DISABLE) & old_data;
+ HW_REG_WRITE(AB8500_CTRL3_REG, data);
+
+ data = INACTIVE_RESET_AUDIO | old_data;
+ HW_REG_WRITE(AB8500_CTRL3_REG, data);
+
+ old_data = HW_REG_READ(AB8500_SYSULPCLK_CTRL1_REG);
+ data = ENABLE_AUDIO_CLK_TO_AUDIO_BLK | old_data;
+
+ HW_REG_WRITE(AB8500_SYSULPCLK_CTRL1_REG, data);
+
+ regulator_enable(regulator_vaudio);
+ regulator_enable(regulator_vdmic);
+ regulator_enable(regulator_vamic1);
+ regulator_enable(regulator_vamic2);
+
+ old_data = HW_REG_READ(AB8500_GPIO_DIR4_REG);
+ data = (GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT |
+ GPIO31_DIR_OUTPUT) | old_data;
+ HW_REG_WRITE(AB8500_GPIO_DIR4_REG, data);
+
+ error = HW_REG_WRITE(SOFTWARE_RESET_REG, SW_RESET);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Software reset error=%d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(POWER_UP_CONTROL_REG,
+ (DEVICE_POWER_UP|ANALOG_PARTS_POWER_UP), 0);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Device Power Up, error=%d", error);
+ goto err_cleanup;
+ }
+ }
+ /* Save information that given client already powered up audio block */
+ ptr_audio_codec_cnxt->power_client |= power_client;
+
+ /* If audio block requested power up, turn on additional audio blocks */
+ if (power_client == STE_AUDIOIO_POWER_AUDIO) {
+ ptr_audio_codec_cnxt->audio_codec_powerup++;
+
+ clk_ptr_msp1 = clk_get_sys("msp1", NULL);
+ if (!IS_ERR(clk_ptr_msp1)) {
+ error = clk_enable(clk_ptr_msp1);
+ if (error)
+ goto err_cleanup;
+ } else {
+ error = -EFAULT;
+ goto err_cleanup;
+ }
+
+ if (AB8500_REV_20 == acodec_device_id) {
+ clk_ptr_msp3 = clk_get_sys("msp3", NULL);
+ if (!IS_ERR(clk_ptr_msp3)) {
+ error = clk_enable(clk_ptr_msp3);
+ if (error)
+ goto err_cleanup;
+ } else {
+ error = -EFAULT;
+ goto err_cleanup;
+ }
+ }
+
+ error = stm_gpio_altfuncenable(GPIO_ALT_MSP_1);
+ if (error)
+ goto err_cleanup;
+
+ error = HW_ACODEC_MODIFY_WRITE(IF0_IF1_MASTER_CONF_REG,
+ EN_MASTGEN, 0);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Enable Master Generator, error=%d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(TDM_IF_BYPASS_B_FIFO_REG,
+ IF0_MASTER, 0);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "IF0: Master Mode, error=%d", error);
+ goto err_cleanup;
+ }
+
+ /* Configuring IF0 */
+
+ error = HW_ACODEC_MODIFY_WRITE(IF0_IF1_MASTER_CONF_REG,
+ BITCLK_OSR_N_256, 0);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "IF0: Enable FsBitClk & FSync error=%d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_REG_WRITE(IF0_CONF_REG, IF_DELAYED | TDM_FORMAT |
+ WORD_LENGTH_20);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "IF0: TDM Format 16 Bits word length, error=%d",
+ error);
+ goto err_cleanup;
+ }
+ }
+err_cleanup:
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return error;
+}
+
+int ste_audio_io_core_api_powerdown_audiocodec(int power_client)
+{
+ int error = 0;
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ /* Update power client status */
+ if (power_client == STE_AUDIOIO_POWER_AUDIO) {
+ ptr_audio_codec_cnxt->audio_codec_powerup--;
+ if (!ptr_audio_codec_cnxt->audio_codec_powerup) {
+ ptr_audio_codec_cnxt->power_client &= ~power_client;
+ clk_disable(clk_ptr_msp1);
+ clk_put(clk_ptr_msp1);
+ if (AB8500_REV_20 == abx500_get_chip_id(
+ &ste_audio_io_device->dev)) {
+ clk_disable(clk_ptr_msp3);
+ clk_put(clk_ptr_msp3);
+ }
+ error = stm_gpio_altfuncdisable(GPIO_ALT_MSP_1);
+ if (error)
+ goto err_cleanup;
+ }
+ } else
+ ptr_audio_codec_cnxt->power_client &= ~power_client;
+
+ /* If no power client registered, power down audio block */
+ if (!ptr_audio_codec_cnxt->power_client) {
+ regulator_disable(regulator_vdmic);
+ regulator_disable(regulator_vamic1);
+ regulator_disable(regulator_vamic2);
+ regulator_disable(regulator_vaudio);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Device Power Down and Analog Parts Power Down error = % d ",
+ error);
+ goto err_cleanup;
+ }
+ }
+
+err_cleanup:
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+ return error;
+}
+/**
+ * @brief Read from AB8500 device
+ * @dev_data Pointer to the structure __audioio_data
+ * @return 0
+ */
+
+int ste_audio_io_core_api_access_read(struct audioio_data_t *dev_data)
+{
+ int reg;
+ if (NULL == dev_data)
+ return -EFAULT;
+ reg = (dev_data->block<<8)|(dev_data->addr&0xff);
+ dev_data->data = HW_REG_READ(reg);
+ return 0;
+}
+/**
+ * @brief Write on AB8500 device
+ * @dev_data Pointer to the structure __audioio_data
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_core_api_access_write(struct audioio_data_t *dev_data)
+{
+ int retval, reg;
+ if (NULL == dev_data)
+ return -EFAULT;
+
+ reg = (dev_data->block<<8)|(dev_data->addr&0xff);
+ retval = HW_REG_WRITE(reg, dev_data->data);
+
+ return retval;
+}
+/**
+ * @brief Store the power and mute status of transducer
+ * @channel_index Channel-index of transducer
+ * @ptr Array storing the status
+ * @value status being stored
+ * @return 0 on success otherwise negative error code
+ */
+
+void ste_audio_io_core_api_store_data(enum AUDIOIO_CH_INDEX channel_index,
+ int *ptr, int value)
+{
+ if (channel_index & e_CHANNEL_1)
+ ptr[0] = value;
+
+ if (channel_index & e_CHANNEL_2)
+ ptr[1] = value;
+
+ if (channel_index & e_CHANNEL_3)
+ ptr[2] = value;
+
+ if (channel_index & e_CHANNEL_4)
+ ptr[3] = value;
+}
+/**
+ * @brief Get power or mute status on a specific channel
+ * @channel_index Channel-index of the transducer
+ * @ptr Pointer to is_power_up array or is_muted array
+ * @return status of control switch
+ */
+enum AUDIOIO_COMMON_SWITCH ste_audio_io_core_api_get_status(
+ enum AUDIOIO_CH_INDEX channel_index, int *ptr)
+{
+ if (channel_index & e_CHANNEL_1) {
+ if (AUDIOIO_TRUE == ptr[0])
+ return AUDIOIO_COMMON_ON;
+ else
+ return AUDIOIO_COMMON_OFF;
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ if (AUDIOIO_TRUE == ptr[1])
+ return AUDIOIO_COMMON_ON;
+ else
+ return AUDIOIO_COMMON_OFF;
+ }
+
+ if (channel_index & e_CHANNEL_3) {
+ if (AUDIOIO_TRUE == ptr[2])
+ return AUDIOIO_COMMON_ON;
+ else
+ return AUDIOIO_COMMON_OFF;
+ }
+
+ if (channel_index & e_CHANNEL_4) {
+ if (AUDIOIO_TRUE == ptr[3])
+ return AUDIOIO_COMMON_ON;
+ else
+ return AUDIOIO_COMMON_OFF;
+ }
+ return 0;
+}
+
+int ste_audio_io_core_api_acodec_power_control(struct audioio_acodec_pwr_ctrl_t
+ *audio_acodec_pwr_ctrl)
+{
+ int error = 0;
+ if (audio_acodec_pwr_ctrl->ctrl_switch == AUDIOIO_COMMON_ON)
+ error = ste_audio_io_core_api_powerup_audiocodec(
+ STE_AUDIOIO_POWER_AUDIO);
+ else
+ error = ste_audio_io_core_api_powerdown_audiocodec(
+ STE_AUDIOIO_POWER_AUDIO);
+
+ return error;
+}
+/**
+ * @brief Control for powering on/off HW components on a specific channel
+ * @pwr_ctrl Pointer to the structure __audioio_pwr_ctrl
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_core_api_power_control_transducer(
+ struct audioio_pwr_ctrl_t *pwr_ctrl)
+{
+ int error = 0;
+ struct transducer_context_t *ptr = NULL;
+ enum AUDIOIO_CH_INDEX channel_index;
+
+ channel_index = pwr_ctrl->channel_index;
+
+ ptr = &ptr_audio_codec_cnxt->transducer[pwr_ctrl->channel_type];
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ if (AUDIOIO_COMMON_ON == pwr_ctrl->ctrl_switch) {
+ if (ptr->pwr_up_func) {
+ error = ptr->pwr_up_func(pwr_ctrl->channel_index,
+ ptr_audio_codec_cnxt->dev);
+ if (0 == error) {
+ ste_audio_io_core_api_store_data(channel_index,
+ ptr->is_power_up, AUDIOIO_TRUE);
+ }
+ }
+ } else {
+ if (ptr->pwr_down_func) {
+ error = ptr->pwr_down_func(pwr_ctrl->channel_index,
+ ptr_audio_codec_cnxt->dev);
+ if (0 == error) {
+ ste_audio_io_core_api_store_data(channel_index,
+ ptr->is_power_up, AUDIOIO_FALSE);
+ }
+ }
+ }
+
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return error;
+}
+/**
+ * @brief Query power state of HW path on specified channel
+ * @pwr_ctrl Pointer to the structure __audioio_pwr_ctrl
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_core_api_power_status_transducer(
+ struct audioio_pwr_ctrl_t *pwr_ctrl)
+{
+
+ struct transducer_context_t *ptr = NULL;
+ enum AUDIOIO_CH_INDEX channel_index;
+
+ channel_index = pwr_ctrl->channel_index;
+
+ ptr = &ptr_audio_codec_cnxt->transducer[pwr_ctrl->channel_type];
+
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+
+ pwr_ctrl->ctrl_switch = ste_audio_io_core_api_get_status(channel_index,
+ ptr->is_power_up);
+
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return 0;
+
+}
+
+int ste_audio_io_core_api_loop_control(struct audioio_loop_ctrl_t *loop_ctrl)
+{
+ return 0;
+}
+
+int ste_audio_io_core_api_loop_status(struct audioio_loop_ctrl_t *loop_ctrl)
+{
+ return 0;
+}
+
+int ste_audio_io_core_api_get_transducer_gain_capability(
+ struct audioio_get_gain_t *get_gain)
+{
+ return 0;
+}
+
+int ste_audio_io_core_api_gain_capabilities_loop(
+ struct audioio_gain_loop_t *gain_loop)
+{
+ return 0;
+}
+
+int ste_audio_io_core_api_supported_loops(
+ struct audioio_support_loop_t *support_loop)
+{
+ return 0;
+}
+
+int ste_audio_io_core_api_gain_descriptor_transducer(
+ struct audioio_gain_desc_trnsdr_t *gdesc_trnsdr)
+{
+ return 0;
+}
+/**
+ * @brief Control for muting a specific channel in HW
+ * @mute_trnsdr Pointer to the structure __audioio_mute_trnsdr
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_core_api_mute_control_transducer(
+ struct audioio_mute_trnsdr_t *mute_trnsdr)
+{
+ int error = 0;
+ struct transducer_context_t *ptr = NULL;
+ enum AUDIOIO_CH_INDEX channel_index;
+
+ channel_index = mute_trnsdr->channel_index;
+
+ ptr = &ptr_audio_codec_cnxt->transducer[mute_trnsdr->channel_type];
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ if (AUDIOIO_COMMON_ON == mute_trnsdr->ctrl_switch) {
+ if (ptr->mute_func) {
+ error = ptr->mute_func(mute_trnsdr->channel_index,
+ ptr_audio_codec_cnxt->dev);
+ if (0 == error) {
+ ste_audio_io_core_api_store_data(channel_index ,
+ ptr->is_muted, AUDIOIO_TRUE);
+ }
+ }
+ } else {
+ if (ptr->unmute_func) {
+ if (0 == ptr->unmute_func(channel_index, ptr->gain,
+ ptr_audio_codec_cnxt->dev)) {
+ ste_audio_io_core_api_store_data(channel_index,
+ ptr->is_muted, AUDIOIO_FALSE);
+ }
+ }
+ }
+
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return error;
+}
+/**
+ * @brief Query state of mute on specified channel
+ * @mute_trnsdr Pointer to the structure __audioio_mute_trnsdr
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_core_api_mute_status_transducer(
+ struct audioio_mute_trnsdr_t *mute_trnsdr)
+{
+ struct transducer_context_t *ptr = NULL;
+ enum AUDIOIO_CH_INDEX channel_index;
+
+ channel_index = mute_trnsdr->channel_index;
+
+ ptr = &ptr_audio_codec_cnxt->transducer[mute_trnsdr->channel_type];
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ mute_trnsdr->ctrl_switch = ste_audio_io_core_api_get_status(
+ channel_index, ptr->is_muted);
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return 0;
+}
+/**
+ * @brief control the fading on the transducer called on.
+ * @fade_ctrl Pointer to the structure __audioio_fade_ctrl
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_core_api_fading_control(struct audioio_fade_ctrl_t *fade_ctrl)
+{
+ int error = 0;
+ struct transducer_context_t *ptr = NULL;
+
+ ptr = &ptr_audio_codec_cnxt->transducer[fade_ctrl->channel_type];
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ if (AUDIOIO_COMMON_ON == fade_ctrl->ctrl_switch)
+ error = ptr->enable_fade_func(ptr_audio_codec_cnxt->dev);
+
+ else
+ error = ptr->disable_fade_func(ptr_audio_codec_cnxt->dev);
+
+
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return error;
+}
+/**
+ * @brief control the low power mode of headset.
+ * @burst_ctrl Pointer to the structure __audioio_burst_ctrl
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_core_api_burstmode_control(
+ struct audioio_burst_ctrl_t *burst_ctrl)
+{
+ int error = 0;
+ struct transducer_context_t *ptr = NULL;
+ int burst_fifo_switch_frame;
+
+ burst_fifo_switch_frame = burst_ctrl->burst_fifo_switch_frame;
+
+
+ ptr = &ptr_audio_codec_cnxt->transducer[burst_ctrl->channel_type];
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ if (AUDIOIO_COMMON_ON == burst_ctrl->ctrl_switch) {
+ if (ptr->switch_to_burst_func)
+ error = ptr->switch_to_burst_func(
+ burst_fifo_switch_frame,
+ ptr_audio_codec_cnxt->dev);
+ } else {
+ if (ptr->switch_to_normal_func)
+ error = ptr->switch_to_normal_func(
+ ptr_audio_codec_cnxt->dev);
+ }
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return error;
+}
+/**
+ * @brief Convert channel index to array index
+ * @channel_index Channel Index of transducer
+ * @return Array index corresponding to the specified channel index
+ */
+
+int convert_channel_index_to_array_index(enum AUDIOIO_CH_INDEX channel_index)
+{
+ if (channel_index & e_CHANNEL_1)
+ return 0;
+ else if (channel_index & e_CHANNEL_2)
+ return 1;
+ else if (channel_index & e_CHANNEL_3)
+ return 2;
+ else
+ return 3;
+}
+
+/**
+ * @brief Set individual gain along the HW path of a specified channel
+ * @gctrl_trnsdr Pointer to the structure __audioio_gain_ctrl_trnsdr
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_core_api_gain_control_transducer(
+ struct audioio_gain_ctrl_trnsdr_t *gctrl_trnsdr)
+{
+ struct transducer_context_t *ptr = NULL;
+ enum AUDIOIO_CH_INDEX channel_index;
+ int ch_array_index;
+ u16 gain_index;
+ int gain_value;
+ u32 linear;
+ int channel_type;
+ int error;
+ int min_gain, max_gain, gain;
+
+ ptr = &ptr_audio_codec_cnxt->transducer[gctrl_trnsdr->channel_type];
+ channel_index = gctrl_trnsdr->channel_index;
+ gain_index = gctrl_trnsdr->gain_index;
+ gain_value = gctrl_trnsdr->gain_value;
+ linear = gctrl_trnsdr->linear;
+ channel_type = gctrl_trnsdr->channel_type;
+
+ ch_array_index = convert_channel_index_to_array_index(channel_index);
+ if (linear) { /* Gain is in the range 0 to 100 */
+ min_gain = gain_descriptor[channel_type]\
+ [ch_array_index][gain_index].min_gain;
+ max_gain = gain_descriptor[channel_type]\
+ [ch_array_index][gain_index].max_gain;
+
+ gain = ((gain_value * (max_gain - min_gain))/100) + min_gain;
+ } else {
+ /* Convert to db */
+ gain = gain_value/100;
+ }
+ gain_value = gain;
+
+#if 1
+ if (gain_index >= transducer_no_of_gains[channel_type])
+ return -EINVAL;
+
+ if (gain_value < gain_descriptor[channel_type]\
+ [ch_array_index][gain_index].min_gain)
+ return -EINVAL;
+
+ if (gain_value > gain_descriptor[channel_type]\
+ [ch_array_index][gain_index].max_gain)
+ return -EINVAL;
+
+#endif
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ error = ptr->set_gain_func(channel_index,
+ gain_index, gain_value, linear,
+ ptr_audio_codec_cnxt->dev);
+ if (0 == error)
+ ste_audio_io_core_api_store_data(channel_index ,
+ ptr->gain, gain_value);
+
+
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return error;
+}
+/**
+ * @brief Get individual gain along the HW path of a specified channel
+ * @gctrl_trnsdr Pointer to the structure __audioio_gain_ctrl_trnsdr
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_core_api_gain_query_transducer(
+ struct audioio_gain_ctrl_trnsdr_t *gctrl_trnsdr)
+{
+ struct transducer_context_t *ptr = NULL;
+ enum AUDIOIO_CH_INDEX channel_index;
+ u16 gain_index;
+ u32 linear;
+ int left_volume, right_volume;
+ int max_gain, min_gain;
+ int ch_array_index;
+
+ ptr = &ptr_audio_codec_cnxt->transducer[gctrl_trnsdr->channel_type];
+ channel_index = gctrl_trnsdr->channel_index;
+ gain_index = gctrl_trnsdr->gain_index;
+ linear = gctrl_trnsdr->linear;
+
+ ptr->get_gain_func(&left_volume, &right_volume, gain_index,
+ ptr_audio_codec_cnxt->dev);
+
+ ch_array_index = convert_channel_index_to_array_index(channel_index);
+ max_gain = gain_descriptor[gctrl_trnsdr->channel_type]\
+ [ch_array_index][gain_index].max_gain;
+ min_gain = gain_descriptor[gctrl_trnsdr->channel_type]\
+ [ch_array_index][gain_index].min_gain;
+
+ switch (channel_index) {
+ case e_CHANNEL_1:
+ gctrl_trnsdr->gain_value = linear ? \
+ min_gain+left_volume*(max_gain-min_gain)/100 : left_volume;
+ break;
+ case e_CHANNEL_2:
+ gctrl_trnsdr->gain_value = linear ? \
+ min_gain+right_volume*(max_gain-min_gain)/100 : right_volume;
+ break;
+ case e_CHANNEL_3:
+ break;
+ case e_CHANNEL_4:
+ break;
+ case e_CHANNEL_ALL:
+ if (left_volume == right_volume) {
+ if (linear)
+ gctrl_trnsdr->gain_value =
+ min_gain+right_volume*(max_gain-min_gain)/100;
+ else
+ gctrl_trnsdr->gain_value = right_volume;
+ }
+ }
+
+ return 0;
+}
+
+
+int ste_audio_io_core_api_fsbitclk_control(
+ struct audioio_fsbitclk_ctrl_t *fsbitclk_ctrl)
+{
+ int error = 0;
+
+ if (AUDIOIO_COMMON_ON == fsbitclk_ctrl->ctrl_switch)
+ error = HW_ACODEC_MODIFY_WRITE(IF0_IF1_MASTER_CONF_REG,
+ EN_FSYNC_BITCLK, 0);
+ else
+ error = HW_ACODEC_MODIFY_WRITE(IF0_IF1_MASTER_CONF_REG, 0,
+ EN_FSYNC_BITCLK);
+
+ return error;
+}
+int ste_audio_io_core_api_pseudoburst_control(
+ struct audioio_pseudoburst_ctrl_t *pseudoburst_ctrl)
+{
+ int error = 0;
+
+ return error;
+}
+int ste_audio_io_core_debug(int x)
+{
+ debug_audioio(x);
+
+return 0;
+}
+
+/**
+ * ste_audioio_vibrator_alloc()
+ * @client: Client id which allocates vibrator
+ * @mask: Mask against which vibrator usage is checked
+ *
+ * This function allocates vibrator.
+ * Mask is added here as audioio driver controls left and right vibrator
+ * separately (can work independently). In case when audioio has allocated
+ * one of its channels (left or right) it should be still able to allocate
+ * the other channel.
+ *
+ * Returns:
+ * 0 - Success
+ * -EBUSY - other client already registered
+ **/
+int ste_audioio_vibrator_alloc(int client, int mask)
+{
+ int error = 0;
+
+ /* Check if other client is already using vibrator */
+ if (ptr_audio_codec_cnxt->vibra_client & ~mask)
+ error = -EBUSY;
+ else
+ ptr_audio_codec_cnxt->vibra_client |= client;
+
+ return error;
+}
+
+/**
+ * ste_audioio_vibrator_release()
+ * @client: Client id which releases vibrator
+ *
+ * This function releases vibrator
+ **/
+void ste_audioio_vibrator_release(int client)
+{
+ ptr_audio_codec_cnxt->vibra_client &= ~client;
+}
+
+/**
+ * ste_audioio_vibrator_pwm_control()
+ * @client: Client id which will use vibrator
+ * @left_speed: Left vibrator speed
+ * @right_speed: Right vibrator speed
+ *
+ * This function controls vibrator using PWM source
+ *
+ * Returns:
+ * 0 - success
+ * -EBUSY - Vibrator already used
+ **/
+int ste_audioio_vibrator_pwm_control(
+ int client,
+ struct ste_vibra_speed left_speed,
+ struct ste_vibra_speed right_speed)
+{
+ int error = 0;
+
+ mutex_lock(&ptr_audio_codec_cnxt->audio_io_mutex);
+
+ /* Try to allocate vibrator for given client */
+ error = ste_audioio_vibrator_alloc(client, client);
+
+ mutex_unlock(&ptr_audio_codec_cnxt->audio_io_mutex);
+
+ if (error)
+ return error;
+
+ /* Duty cycle supported by vibrator's PWM is 0-100 */
+ if (left_speed.positive > STE_AUDIOIO_VIBRATOR_MAX_SPEED)
+ left_speed.positive = STE_AUDIOIO_VIBRATOR_MAX_SPEED;
+
+ if (right_speed.positive > STE_AUDIOIO_VIBRATOR_MAX_SPEED)
+ right_speed.positive = STE_AUDIOIO_VIBRATOR_MAX_SPEED;
+
+ if (left_speed.negative > STE_AUDIOIO_VIBRATOR_MAX_SPEED)
+ left_speed.negative = STE_AUDIOIO_VIBRATOR_MAX_SPEED;
+
+ if (right_speed.negative > STE_AUDIOIO_VIBRATOR_MAX_SPEED)
+ right_speed.negative = STE_AUDIOIO_VIBRATOR_MAX_SPEED;
+
+ if (left_speed.negative || right_speed.negative ||
+ left_speed.positive || right_speed.positive) {
+ /* Power up audio block for vibrator */
+ error = ste_audio_io_core_api_powerup_audiocodec(
+ STE_AUDIOIO_POWER_VIBRA);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Audio power up failed %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ (EN_VIBL_MASK|EN_VIBR_MASK), 0);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Powerup Vibrator Class-D driver %d",
+ error);
+ return error;
+ }
+
+ error = HW_REG_WRITE(VIB_DRIVER_CONF_REG, 0xff);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Enable Vibrator PWM generator %d",
+ error);
+ return error;
+ }
+ }
+
+ error = HW_REG_WRITE(PWM_VIBNL_CONF_REG, left_speed.negative);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Write Left Vibrator negative PWM %d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_REG_WRITE(PWM_VIBPL_CONF_REG, left_speed.positive);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Write Left Vibrator positive PWM %d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_REG_WRITE(PWM_VIBNR_CONF_REG, right_speed.negative);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Write Right Vibrator negative PWM %d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_REG_WRITE(PWM_VIBPR_CONF_REG, right_speed.positive);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Write Right Vibrator positive PWM %d", error);
+ goto err_cleanup;
+ }
+
+ if (!left_speed.negative && !right_speed.negative &&
+ !left_speed.positive && !right_speed.positive) {
+ error = HW_REG_WRITE(VIB_DRIVER_CONF_REG, 0);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Disable PWM Vibrator generator %d",
+ error);
+ goto err_cleanup;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ 0, (EN_VIBL_MASK|EN_VIBR_MASK));
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Power down Vibrator Class-D driver %d",
+ error);
+ goto err_cleanup;
+ }
+
+ /* Power down audio block */
+ error = ste_audio_io_core_api_powerdown_audiocodec(
+ STE_AUDIOIO_POWER_VIBRA);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Audio power down failed %d", error);
+ goto err_cleanup;
+ }
+ }
+
+err_cleanup:
+ /* Release client */
+ if (!left_speed.negative && !right_speed.negative &&
+ !left_speed.positive && !right_speed.positive) {
+ mutex_lock(&ptr_audio_codec_cnxt->audio_io_mutex);
+ ste_audioio_vibrator_release(client);
+ mutex_unlock(&ptr_audio_codec_cnxt->audio_io_mutex);
+ }
+ return error;
+}
+EXPORT_SYMBOL(ste_audioio_vibrator_pwm_control);
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_core.h b/drivers/misc/audio_io_dev/ste_audio_io_core.h
new file mode 100644
index 00000000000..9ccb576c159
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_core.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#ifndef _AUDIOIO_CORE_H_
+#define _AUDIOIO_CORE_H_
+
+#include <mach/ste_audio_io_ioctl.h>
+#include "ste_audio_io_func.h"
+#include "ste_audio_io_hwctrl_common.h"
+
+#define MAX_NO_CHANNELS 4
+
+#define STE_AUDIOIO_POWER_AUDIO 1
+#define STE_AUDIOIO_POWER_VIBRA 2
+
+struct transducer_context_t {
+ /* public variables */
+ int gain[MAX_NO_CHANNELS];
+ int is_muted[MAX_NO_CHANNELS];
+ int is_power_up[MAX_NO_CHANNELS];
+ /* public funcs */
+ int (*pwr_up_func)(enum AUDIOIO_CH_INDEX, struct device *);
+ int (*pwr_down_func)(enum AUDIOIO_CH_INDEX, struct device *);
+ int (*pwr_state_func)(struct device *);
+ int (*set_gain_func)(enum AUDIOIO_CH_INDEX, u16, int, u32,
+ struct device *);
+ int (*get_gain_func)(int *, int *, u16, struct device *);
+ int (*mute_func)(enum AUDIOIO_CH_INDEX, struct device *);
+ int (*unmute_func)(enum AUDIOIO_CH_INDEX, int *, struct device *);
+ int (*mute_state_func)(struct device *);
+ int (*enable_fade_func)(struct device *);
+ int (*disable_fade_func)(struct device *);
+ int (*switch_to_burst_func)(int, struct device *);
+ int (*switch_to_normal_func)(struct device *);
+};
+
+struct audiocodec_context_t {
+ int audio_codec_powerup;
+ int power_client;
+ int vibra_client;
+ struct mutex audio_io_mutex;
+ struct mutex vibrator_mutex;
+ struct transducer_context_t transducer[MAX_NO_TRANSDUCERS];
+ struct device *dev;
+};
+
+
+int ste_audio_io_core_api_access_read(struct audioio_data_t *dev_data);
+
+int ste_audio_io_core_api_access_write(struct audioio_data_t *dev_data);
+
+int ste_audio_io_core_api_power_control_transducer(
+ struct audioio_pwr_ctrl_t *pwr_ctrl);
+
+int ste_audio_io_core_api_power_status_transducer(
+ struct audioio_pwr_ctrl_t *pwr_ctrl);
+
+int ste_audio_io_core_api_loop_control(struct audioio_loop_ctrl_t *loop_ctrl);
+
+int ste_audio_io_core_api_loop_status(struct audioio_loop_ctrl_t *loop_ctrl);
+
+int ste_audio_io_core_api_get_transducer_gain_capability(
+ struct audioio_get_gain_t *get_gain);
+
+int ste_audio_io_core_api_gain_capabilities_loop(
+ struct audioio_gain_loop_t *gain_loop);
+
+int ste_audio_io_core_api_supported_loops(
+ struct audioio_support_loop_t *support_loop);
+
+int ste_audio_io_core_api_gain_descriptor_transducer(
+ struct audioio_gain_desc_trnsdr_t *gdesc_trnsdr);
+
+int ste_audio_io_core_api_gain_control_transducer(
+ struct audioio_gain_ctrl_trnsdr_t *gctrl_trnsdr);
+
+int ste_audio_io_core_api_gain_query_transducer(
+ struct audioio_gain_ctrl_trnsdr_t *gctrl_trnsdr);
+
+int ste_audio_io_core_api_mute_control_transducer(
+ struct audioio_mute_trnsdr_t *mute_trnsdr);
+
+int ste_audio_io_core_api_mute_status_transducer(
+ struct audioio_mute_trnsdr_t *mute_trnsdr);
+
+int ste_audio_io_core_api_fading_control(struct audioio_fade_ctrl_t *fade_ctrl);
+
+int ste_audio_io_core_api_burstmode_control(
+ struct audioio_burst_ctrl_t *burst_ctrl);
+
+int ste_audio_io_core_api_powerup_audiocodec(int power_client);
+
+int ste_audio_io_core_api_powerdown_audiocodec(int power_client);
+
+int ste_audio_io_core_api_init_data(struct platform_device *pdev);
+
+bool ste_audio_io_core_is_ready_for_suspend(void);
+void ste_audio_io_core_api_free_data(void);
+
+void ste_audio_io_init_transducer_cnxt(void);
+
+int ste_audio_io_core_api_fsbitclk_control(
+ struct audioio_fsbitclk_ctrl_t *fsbitclk_ctrl);
+int ste_audio_io_core_api_pseudoburst_control(
+ struct audioio_pseudoburst_ctrl_t *pseudoburst_ctrl);
+
+void ste_audio_io_core_api_store_data(enum AUDIOIO_CH_INDEX channel_index,
+ int *ptr, int value);
+
+int ste_audioio_vibrator_alloc(int client, int mask);
+
+void ste_audioio_vibrator_release(int client);
+
+enum AUDIOIO_COMMON_SWITCH ste_audio_io_core_api_get_status(
+ enum AUDIOIO_CH_INDEX channel_index, int *ptr);
+
+int ste_audio_io_core_api_acodec_power_control(struct audioio_acodec_pwr_ctrl_t
+ *audio_acodec_pwr_ctrl);
+
+int ste_audio_io_core_debug(int x);
+
+#endif /* _AUDIOIO_CORE_H_ */
+
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_dev.c b/drivers/misc/audio_io_dev/ste_audio_io_dev.c
new file mode 100644
index 00000000000..de47fa58956
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_dev.c
@@ -0,0 +1,716 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include "ste_audio_io_dev.h"
+
+#define STR_DEBUG_ON "debug on"
+#define AUDIOIO_DEVNAME "ab8500-codec"
+
+static int ste_audio_io_open(struct inode *inode, struct file *filp);
+static int ste_audio_io_release(struct inode *inode, struct file *filp);
+static long ste_audio_io_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+static int ste_audio_io_cmd_parser(unsigned int cmd, unsigned long arg);
+static ssize_t ste_audio_io_write(struct file *filp,
+ const char __user *buf, size_t count, loff_t *f_pos);
+
+
+/**
+ * @brief Check IOCTL type, command no and access direction
+ * @ inode value corresponding to the file descriptor
+ * @file value corresponding to the file descriptor
+ * @cmd IOCTL command code
+ * @arg Command argument
+ * @return 0 on success otherwise negative error code
+ */
+static long ste_audio_io_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ int err = 0;
+
+ /* Check type and command number */
+ if (_IOC_TYPE(cmd) != AUDIOIO_IOC_MAGIC)
+ return -ENOTTY;
+
+ /* IOC_DIR is from the user perspective, while access_ok is
+ * from the kernel perspective; so they look reversed.
+ */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, (void __user *)arg,
+ _IOC_SIZE(cmd));
+ if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, (void __user *)arg,
+ _IOC_SIZE(cmd));
+ if (err)
+ return -EFAULT;
+
+ retval = ste_audio_io_cmd_parser(cmd, arg);
+
+ return retval;
+}
+/**
+ * @brief IOCTL call to read the value from AB8500 device
+ * @cmd IOCTL command code
+ * @arg Command argument
+ * @return 0 on success otherwise negative error code
+ */
+
+static int process_read_register_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_data_t *audio_dev_data;
+
+ audio_dev_data = (struct audioio_data_t *)&cmd_data;
+
+ if (copy_from_user(audio_dev_data, (void __user *)arg,
+ sizeof(struct audioio_data_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_access_read(audio_dev_data);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_dev_data,
+ sizeof(struct audioio_data_t)))
+ return -EFAULT;
+ return 0;
+}
+/**
+ * @brief IOCTL call to write the given value to the AB8500 device
+ * @cmd IOCTL command code
+ * @arg Command argument
+ * @return 0 on success otherwise negative error code
+ */
+
+static int process_write_register_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_data_t *audio_dev_data;
+
+ audio_dev_data = (struct audioio_data_t *)&cmd_data;
+
+ if (copy_from_user(audio_dev_data, (void __user *)arg,
+ sizeof(struct audioio_data_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_access_write(audio_dev_data);
+
+ return retval;
+}
+/**
+ * @brief IOCTL call to control the power on/off of hardware components
+ * @cmd IOCTL command code
+ * @arg Command argument
+ * @return 0 on success otherwise negative error code
+ */
+
+static int process_pwr_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_pwr_ctrl_t *audio_pwr_ctrl;
+
+ audio_pwr_ctrl = (struct audioio_pwr_ctrl_t *)&cmd_data;
+
+ if (copy_from_user(audio_pwr_ctrl, (void __user *)arg,
+ sizeof(struct audioio_pwr_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_power_control_transducer(audio_pwr_ctrl);
+
+ return retval;
+}
+
+static int process_pwr_sts_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_pwr_ctrl_t *audio_pwr_sts;
+
+ audio_pwr_sts = (struct audioio_pwr_ctrl_t *)&cmd_data;
+
+ if (copy_from_user(audio_pwr_sts, (void __user *)arg,
+ sizeof(struct audioio_pwr_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_power_status_transducer(audio_pwr_sts);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_pwr_sts,
+ sizeof(struct audioio_pwr_ctrl_t)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int process_lp_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_loop_ctrl_t *audio_lp_ctrl;
+
+ audio_lp_ctrl = (struct audioio_loop_ctrl_t *)&cmd_data;
+
+ if (copy_from_user(audio_lp_ctrl, (void __user *)arg,
+ sizeof(struct audioio_loop_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_loop_control(audio_lp_ctrl);
+
+ return retval;
+}
+
+static int process_lp_sts_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_loop_ctrl_t *audio_lp_sts;
+
+ audio_lp_sts = (struct audioio_loop_ctrl_t *)&cmd_data;
+
+
+ if (copy_from_user(audio_lp_sts, (void __user *)arg,
+ sizeof(struct audioio_loop_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_loop_status(audio_lp_sts);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_lp_sts,
+ sizeof(struct audioio_loop_ctrl_t)))
+ return -EFAULT;
+ return 0;
+}
+
+static int process_get_trnsdr_gain_capability_cmd(unsigned int cmd,
+ unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_get_gain_t *audio_trnsdr_gain;
+
+ audio_trnsdr_gain = (struct audioio_get_gain_t *)&cmd_data;
+
+ if (copy_from_user(audio_trnsdr_gain, (void __user *)arg,
+ sizeof(struct audioio_get_gain_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_get_transducer_gain_capability(
+ audio_trnsdr_gain);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_trnsdr_gain,
+ sizeof(struct audioio_get_gain_t)))
+ return -EFAULT;
+ return 0;
+}
+
+static int process_gain_cap_loop_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_gain_loop_t *audio_gain_loop;
+
+ audio_gain_loop = (struct audioio_gain_loop_t *)&cmd_data;
+
+ if (copy_from_user(audio_gain_loop, (void __user *)arg,
+ sizeof(struct audioio_gain_loop_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_gain_capabilities_loop(audio_gain_loop);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_gain_loop,
+ sizeof(struct audioio_gain_loop_t)))
+ return -EFAULT;
+ return 0;
+}
+
+
+static int process_support_loop_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_support_loop_t *audio_spprt_loop;
+
+ audio_spprt_loop = (struct audioio_support_loop_t *)&cmd_data;
+
+ if (copy_from_user(audio_spprt_loop, (void __user *)arg,
+ sizeof(struct audioio_support_loop_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_supported_loops(audio_spprt_loop);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_spprt_loop,
+ sizeof(struct audioio_support_loop_t)))
+ return -EFAULT;
+ return 0;
+}
+
+
+static int process_gain_desc_trnsdr_cmd(unsigned int cmd, unsigned long arg)
+
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_gain_desc_trnsdr_t *audio_gain_desc;
+
+ audio_gain_desc = (struct audioio_gain_desc_trnsdr_t *)&cmd_data;
+
+ if (copy_from_user(audio_gain_desc, (void __user *)arg,
+ sizeof(struct audioio_gain_desc_trnsdr_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_gain_descriptor_transducer(
+ audio_gain_desc);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_gain_desc,
+ sizeof(struct audioio_gain_desc_trnsdr_t)))
+ return -EFAULT;
+ return 0;
+}
+
+
+static int process_gain_ctrl_trnsdr_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_gain_ctrl_trnsdr_t *audio_gain_ctrl;
+
+ audio_gain_ctrl = (struct audioio_gain_ctrl_trnsdr_t *)&cmd_data;
+
+ if (copy_from_user(audio_gain_ctrl, (void __user *)arg,
+ sizeof(struct audioio_gain_ctrl_trnsdr_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_gain_control_transducer(
+ audio_gain_ctrl);
+
+ return retval;
+}
+
+static int process_gain_query_trnsdr_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_gain_ctrl_trnsdr_t *audio_gain_query;
+
+ audio_gain_query = (struct audioio_gain_ctrl_trnsdr_t *)&cmd_data;
+
+ if (copy_from_user(audio_gain_query, (void __user *)arg,
+ sizeof(struct audioio_gain_ctrl_trnsdr_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_gain_query_transducer(audio_gain_query);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_gain_query,
+ sizeof(struct audioio_gain_ctrl_trnsdr_t)))
+ return -EFAULT;
+ return 0;
+}
+
+static int process_mute_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_mute_trnsdr_t *audio_mute_ctrl;
+
+ audio_mute_ctrl = (struct audioio_mute_trnsdr_t *)&cmd_data;
+ if (copy_from_user(audio_mute_ctrl , (void __user *)arg,
+ sizeof(struct audioio_mute_trnsdr_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_mute_control_transducer(
+ audio_mute_ctrl);
+
+ return retval;
+}
+
+static int process_mute_sts_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_mute_trnsdr_t *audio_mute_sts;
+
+ audio_mute_sts = (struct audioio_mute_trnsdr_t *)&cmd_data;
+
+ if (copy_from_user(audio_mute_sts, (void __user *)arg,
+ sizeof(struct audioio_mute_trnsdr_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_mute_status_transducer(audio_mute_sts);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_mute_sts,
+ sizeof(struct audioio_mute_trnsdr_t)))
+ return -EFAULT;
+ return 0;
+}
+
+static int process_fade_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_fade_ctrl_t *audio_fade;
+ audio_fade = (struct audioio_fade_ctrl_t *)&cmd_data;
+
+ if (copy_from_user(audio_fade , (void __user *)arg,
+ sizeof(struct audioio_fade_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_fading_control(audio_fade);
+
+ return retval;
+}
+
+static int process_burst_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_burst_ctrl_t *audio_burst;
+
+ audio_burst = (struct audioio_burst_ctrl_t *)&cmd_data;
+ if (copy_from_user(audio_burst , (void __user *)arg,
+ sizeof(struct audioio_burst_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_burstmode_control(audio_burst);
+
+ return retval;
+
+ return 0;
+}
+
+static int process_fsbitclk_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_fsbitclk_ctrl_t *audio_fsbitclk;
+
+ audio_fsbitclk = (struct audioio_fsbitclk_ctrl_t *)&cmd_data;
+
+ if (copy_from_user(audio_fsbitclk , (void __user *)arg,
+ sizeof(struct audioio_fsbitclk_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_fsbitclk_control(audio_fsbitclk);
+
+ return retval;
+
+ return 0;
+
+}
+
+static int process_pseudoburst_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_pseudoburst_ctrl_t *audio_pseudoburst;
+
+ audio_pseudoburst = (struct audioio_pseudoburst_ctrl_t *)&cmd_data;
+
+ if (copy_from_user(audio_pseudoburst , (void __user *)arg,
+ sizeof(struct audioio_pseudoburst_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_pseudoburst_control(audio_pseudoburst);
+
+ return retval;
+
+ return 0;
+
+}
+static int process_audiocodec_pwr_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_acodec_pwr_ctrl_t *audio_acodec_pwr_ctrl;
+ audio_acodec_pwr_ctrl = (struct audioio_acodec_pwr_ctrl_t *)&cmd_data;
+ if (copy_from_user(audio_acodec_pwr_ctrl, (void __user *)arg,
+ sizeof(struct audioio_acodec_pwr_ctrl_t)))
+ return -EFAULT;
+ retval = ste_audio_io_core_api_acodec_power_control(
+ audio_acodec_pwr_ctrl);
+ return retval;
+}
+
+
+
+static int ste_audio_io_cmd_parser(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+
+ switch (cmd) {
+ case AUDIOIO_READ_REGISTER:
+ retval = process_read_register_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_WRITE_REGISTER:
+ retval = process_write_register_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_PWR_CTRL_TRNSDR:
+ retval = process_pwr_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_PWR_STS_TRNSDR:
+ retval = process_pwr_sts_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_LOOP_CTRL:
+ retval = process_lp_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_LOOP_STS:
+ retval = process_lp_sts_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_GET_TRNSDR_GAIN_CAPABILITY:
+ retval = process_get_trnsdr_gain_capability_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_GAIN_CAP_LOOP:
+ retval = process_gain_cap_loop_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_SUPPORT_LOOP:
+ retval = process_support_loop_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_GAIN_DESC_TRNSDR:
+ retval = process_gain_desc_trnsdr_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_GAIN_CTRL_TRNSDR:
+ retval = process_gain_ctrl_trnsdr_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_GAIN_QUERY_TRNSDR:
+ retval = process_gain_query_trnsdr_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_MUTE_CTRL_TRNSDR:
+ retval = process_mute_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_MUTE_STS_TRNSDR:
+ retval = process_mute_sts_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_FADE_CTRL:
+ retval = process_fade_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_BURST_CTRL:
+ retval = process_burst_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_FSBITCLK_CTRL:
+ retval = process_fsbitclk_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_PSEUDOBURST_CTRL:
+ retval = process_pseudoburst_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_AUDIOCODEC_PWR_CTRL:
+ retval = process_audiocodec_pwr_ctrl_cmd(cmd, arg);
+ break;
+ }
+ return retval;
+}
+
+static int ste_audio_io_open(struct inode *inode, struct file *filp)
+{
+ if (!try_module_get(THIS_MODULE))
+ return -ENODEV;
+ return 0;
+}
+
+static int ste_audio_io_release(struct inode *inode, struct file *filp)
+{
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static ssize_t ste_audio_io_write(struct file *filp,
+ const char __user *buf, size_t count, loff_t *f_pos)
+{
+ char *x = kmalloc(count, GFP_KERNEL);
+ int debug_flag = 0;
+
+ if (copy_from_user(x, buf, count))
+ return -EFAULT;
+
+ if (count >= strlen(STR_DEBUG_ON)) {
+
+ if (!strncmp(STR_DEBUG_ON, x, strlen(STR_DEBUG_ON)))
+ debug_flag = 1;
+ else
+ debug_flag = 0;
+ }
+
+ ste_audio_io_core_debug(debug_flag);
+
+ kfree(x);
+
+ return count;
+}
+
+static const struct file_operations ste_audio_io_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = ste_audio_io_ioctl,
+ .open = ste_audio_io_open,
+ .release = ste_audio_io_release,
+ .write = ste_audio_io_write,
+};
+
+/**
+ * audio_io_misc_dev - Misc device config for audio_io
+ */
+static struct miscdevice audio_io_misc_dev = {
+ MISC_DYNAMIC_MINOR,
+ "audioio",
+ &ste_audio_io_fops
+};
+
+/**
+ * ste_audio_io_probe() - probe the device
+ * @pdev: pointer to the platform device structure
+ *
+ * This funtion is called after the driver is registered to platform
+ * device framework. It does allocate the memory for the internal
+ * data structure and intialized core APIs.
+ */
+static int ste_audio_io_drv_probe(struct platform_device *pdev)
+{
+ int error;
+
+ ste_audio_io_device = pdev;
+
+ dev_dbg(&ste_audio_io_device->dev, "ste_audio_io device probe\n");
+
+ error = misc_register(&audio_io_misc_dev);
+ if (error) {
+ printk(KERN_WARNING "%s: registering misc device failed\n",
+ __func__);
+ return error;
+ }
+
+ error = ste_audio_io_core_api_init_data(ste_audio_io_device);
+ if (error < 0) {
+ dev_err(&ste_audio_io_device->dev,
+ "ste_audioio_core_api_init_data failed err = %d",
+ error);
+ goto ste_audio_io_misc_deregister;
+ }
+ return 0;
+
+ste_audio_io_misc_deregister:
+ misc_deregister(&audio_io_misc_dev);
+ return error;
+}
+
+/**
+ * ste_audio_io_remove() - Removes the device
+ * @pdev: pointer to the platform_device structure
+ *
+ * This function is called when this mnodule is removed using rmmod
+ */
+static int ste_audio_io_drv_remove(struct platform_device *pdev)
+{
+ ste_audio_io_core_api_free_data();
+ misc_deregister(&audio_io_misc_dev);
+ return 0;
+}
+
+/**
+ * ste_audio_io_drv_suspend - suspend audio_io
+ * @pdev: platform data
+ * @state: power down level
+ */
+static int ste_audio_io_drv_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ if (ste_audio_io_core_is_ready_for_suspend())
+ return 0;
+ else
+ return -EINVAL;
+}
+
+/**
+ * ste_audio_io_drv_resume - put back audio_io in the normal state
+ * @pdev: platform data
+ */
+static int ste_audio_io_drv_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+/**
+ * struct audio_io_driver: audio_io platform structure
+ * @probe: The probe funtion to be called
+ * @remove: The remove funtion to be called
+ * @resume: The resume function to be called
+ * @suspend: The suspend function to be called
+ * @driver: The driver data
+ */
+static struct platform_driver ste_audio_io_driver = {
+ .probe = ste_audio_io_drv_probe,
+ .remove = ste_audio_io_drv_remove,
+ .driver = {
+ .name = AUDIOIO_DEVNAME,
+ .owner = THIS_MODULE,
+ },
+ .suspend = ste_audio_io_drv_suspend,
+ .resume = ste_audio_io_drv_resume,
+};
+
+/** Pointer to platform device needed to access abx500 core functions */
+struct platform_device *ste_audio_io_device;
+
+static int __init ste_audio_io_init(void)
+{
+ return platform_driver_register(&ste_audio_io_driver);
+}
+module_init(ste_audio_io_init);
+
+static void __exit ste_audio_io_exit(void)
+{
+ platform_driver_unregister(&ste_audio_io_driver);
+}
+module_exit(ste_audio_io_exit);
+
+MODULE_AUTHOR("Deepak KARDA <deepak.karda@stericsson.com>");
+MODULE_DESCRIPTION("STE_AUDIO_IO");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_dev.h b/drivers/misc/audio_io_dev/ste_audio_io_dev.h
new file mode 100644
index 00000000000..bcb9dce3ad2
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_dev.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#ifndef _AUDIOIO_DEV_H_
+#define _AUDIOIO_DEV_H_
+
+#include <mach/ste_audio_io_ioctl.h>
+#include "ste_audio_io_core.h"
+
+union audioio_cmd_data_t {
+ struct audioio_burst_ctrl_t audioio_burst_ctrl;
+ struct audioio_fade_ctrl_t audioio_fade_ctrl;
+ struct audioio_mute_trnsdr_t audioio_mute_trnsdr;
+ struct audioio_gain_ctrl_trnsdr_t audioio_gain_ctrl_trnsdr;
+ struct audioio_gain_desc_trnsdr_t audioio_gain_desc_trnsdr;
+ struct audioio_support_loop_t audioio_support_loop;
+ struct audioio_gain_loop_t audioio_gain_loop;
+ struct audioio_get_gain_t audioio_get_gain;
+ struct audioio_loop_ctrl_t audioio_loop_ctrl;
+ struct audioio_pwr_ctrl_t audioio_pwr_ctrl;
+ struct audioio_data_t audioio_data;
+ struct audioio_fsbitclk_ctrl_t audioio_fsbitclk_ctrl;
+ struct audioio_acodec_pwr_ctrl_t audioio_acodec_pwr_ctrl;
+ struct audioio_pseudoburst_ctrl_t audioio_pseudoburst_ctrl;
+};
+
+
+#endif /* _AUDIOIO_DEV_H_ */
+
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_func.c b/drivers/misc/audio_io_dev/ste_audio_io_func.c
new file mode 100644
index 00000000000..c793ec9ed6e
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_func.c
@@ -0,0 +1,4044 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <mach/ste_audio_io_vibrator.h>
+#include "ste_audio_io_func.h"
+#include "ste_audio_io_core.h"
+#include "ste_audio_io_ab8500_reg_defs.h"
+#include "ste_audio_io_hwctrl_common.h"
+
+static struct clk *clk_ptr_msp0;
+static int bluetooth_power_up_count;
+static int acodec_reg_dump;
+
+/*
+ * TODO: Use proper register defines instead of home-made generic ones.
+ */
+#define SHIFT_QUARTET0 0
+#define SHIFT_QUARTET1 4
+#define MASK_QUARTET (0xFUL)
+#define MASK_QUARTET1 (MASK_QUARTET << SHIFT_QUARTET1)
+#define MASK_QUARTET0 (MASK_QUARTET << SHIFT_QUARTET0)
+
+/**
+ * @brief Modify the specified register
+ * @reg Register
+ * @mask_set Bit to be set
+ * @mask_clear Bit to be cleared
+ * @return 0 on success otherwise negative error code
+ */
+
+unsigned int ab8500_acodec_modify_write(unsigned int reg, u8 mask_set,
+ u8 mask_clear)
+{
+ u8 value8, retval = 0;
+ value8 = HW_REG_READ(reg);
+ /* clear the specified bit */
+ value8 &= ~mask_clear;
+ /* set the asked bit */
+ value8 |= mask_set;
+ retval = HW_REG_WRITE(reg, value8);
+ return retval;
+}
+
+/**
+ * @brief Power up headset on a specific channel
+ * @channel_index Channel-index of headset
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_headset(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if HS PowerUp request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "HS should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ ste_audio_io_mute_headset(channel_index, dev);
+
+ error = HW_ACODEC_MODIFY_WRITE(NCP_ENABLE_HS_AUTOSTART_REG,
+ HS_AUTO_EN, 0);
+ if (0 != error) {
+ dev_err(dev, "NCP fully controlled with EnCpHs bit % d", error);
+ return error;
+ }
+ error = HW_ACODEC_MODIFY_WRITE(NCP_ENABLE_HS_AUTOSTART_REG,
+ (EN_NEG_CP|HS_AUTO_EN), 0);
+ if (0 != error) {
+ dev_err(dev, "Enable Negative Charge Pump % d", error);
+ return error;
+ }
+
+ mdelay(200);
+
+ /* Enable DA1 for HSL */
+ if (channel_index & e_CHANNEL_1) {
+
+ /* Power Up HSL driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ EN_HSL_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up HSL Driver % d", error);
+ return error;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ if (EN_DA1 & initialVal_DA)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA1_REG,
+ SLOT08_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA1 from Slot 08 % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1,
+ DA1_TO_HSL, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "DA_IN1 path mixed with sidetone FIR % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ EN_DA1, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up HSL % d ", error);
+ return error;
+ }
+
+ /* Power Up HSL DAC driver */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG,
+ POWER_UP_HSL_DAC, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up HSL DAC driver % d", error);
+ return error;
+ }
+
+ /* Power up HSL DAC and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ EN_HSL_MASK, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Power up HSL DAC and digital path % d",
+ error);
+ return error;
+ }
+
+ /*
+ * Disable short detection. Pull Down output to ground,
+ * Use local oscillator, Gain change without zero cross control
+ */
+ error = HW_ACODEC_MODIFY_WRITE(SHORT_CIRCUIT_DISABLE_REG,
+ HS_SHORT_DIS|HS_PULL_DOWN_EN|HS_OSC_EN|HS_ZCD_DIS, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable short detection."
+ "Pull Down output to ground,Use local oscillator,Gain"
+ "change without zero cross control % d", error);
+ return error;
+ }
+ }
+
+ /* Enable DA2 for HSR */
+ if (channel_index & e_CHANNEL_2) {
+
+ /* Power Up HSR driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ EN_HSR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up HSR Driver % d", error);
+ return error;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (EN_DA2 & initialVal_DA)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA2_REG,
+ SLOT09_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA2 from Slot 09 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, DA2_TO_HSR,
+ 0);
+ if (0 != error) {
+ dev_err(dev,
+ "DA_IN2 path mixed with sidetone FIR % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ EN_DA2, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up HSR % d ", error);
+ return error;
+ }
+
+ /* Power Up HSR DAC driver */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG,
+ POWER_UP_HSR_DAC, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up HSR DAC driver % d", error);
+ return error;
+ }
+
+ /* Power up HSR DAC and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ EN_HSR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Power up HSR DAC and digital path % d",
+ error);
+ return error;
+ }
+
+ /*
+ * TEST START .havent cleared the bits in power down.Disable short
+ * detection. Pull Down output to ground, Use local oscillator,
+ * Gain change without zero cross control
+ */
+
+ error = HW_ACODEC_MODIFY_WRITE(SHORT_CIRCUIT_DISABLE_REG,
+ HS_SHORT_DIS|HS_PULL_DOWN_EN|HS_OSC_EN|HS_ZCD_DIS, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable short detection."
+ "Pull Down output to ground, Use local oscillator,"
+ "Gain change without zero cross control % d", error);
+ return error;
+ }
+ /* TEST END */
+ }
+ ste_audio_io_unmute_headset(channel_index, 0, dev);
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+
+/**
+ * @brief Power down headset on a specific channel
+ * @channel_index Channel-index of headset
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_headset(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if HS Power Down request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "HS should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ /* Disable Negative Charge Pump */
+ error = HW_ACODEC_MODIFY_WRITE(NCP_ENABLE_HS_AUTOSTART_REG,
+ (EN_NEG_CP|HS_AUTO_EN), 0);
+ if (0 != error) {
+ dev_err(dev, "NCP not fully controlled with EnCpHs bit % d",
+ error);
+ return error;
+ }
+ error = HW_ACODEC_MODIFY_WRITE(NCP_ENABLE_HS_AUTOSTART_REG, 0,
+ EN_NEG_CP);
+ if (0 != error) {
+ dev_err(dev, "Disable Negative Charge Pump % d", error);
+ return error;
+ }
+
+ mdelay(100);
+
+ if (channel_index & e_CHANNEL_1) {
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (!(initialVal_DA & EN_DA1))
+ return 0;
+
+ /* Power Down HSL driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG, 0,
+ EN_HSL_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power down HSL Driver % d", error);
+ return error;
+ }
+
+ /* Power Down HSL DAC driver */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0,
+ POWER_UP_HSL_DAC);
+ if (0 != error) {
+ dev_err(dev, "Power Up HSL DAC Driver % d", error);
+ return error;
+ }
+
+ /* Power Down HSL DAC and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG, 0,
+ EN_HSL_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power down HSL DAC and digital path % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA1);
+ if (0 != error) {
+ dev_err(dev, "Disable DA1 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1,
+ 0, DA1_TO_HSL);
+ if (0 != error) {
+ dev_err(dev,
+ "Clear DA_IN1 path mixed with sidetone FIR % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA1_REG, 0,
+ SLOT08_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA1 cleared from Slot 08 % d",
+ error);
+ return error;
+ }
+
+
+ }
+ /* Enable DA2 for HSR */
+
+ if (channel_index & e_CHANNEL_2) {
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (!(initialVal_DA & EN_DA2))
+ return 0;
+
+ /* Power Down HSR driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG, 0,
+ EN_HSR_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power down HSR Driver % d", error);
+ return error;
+ }
+
+ /* Power Down HSR DAC driver */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0,
+ POWER_UP_HSR_DAC);
+ if (0 != error) {
+ dev_err(dev, "Power down HSR DAC Driver % d", error);
+ return error;
+ }
+
+ /* Power Down HSR DAC and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG, 0,
+ EN_HSR_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power down HSR DAC and digital path % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA2);
+ if (0 != error) {
+ dev_err(dev, "Disable DA2 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0,
+ DA2_TO_HSR);
+ if (0 != error) {
+ dev_err(dev,
+ "Clear DA_IN2 path mixed with sidetone FIR % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA2_REG, 0,
+ SLOT09_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA2 cleared from Slot 09 % d",
+ error);
+ return error;
+ }
+
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+
+/**
+ * @brief Mute headset on a specific channel
+ * @channel_index Headeset channel-index
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_mute_headset(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ /* Check if HS Mute request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "HS should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Mute HSL */
+ error = HW_ACODEC_MODIFY_WRITE(MUTE_HS_EAR_REG,
+ EN_HSL_MASK | EN_HSL_DAC_MASK,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Mute HSL % d", error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* Mute HSR */
+ error = HW_ACODEC_MODIFY_WRITE(MUTE_HS_EAR_REG,
+ EN_HSR_MASK | EN_HSR_DAC_MASK,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Mute HSR % d", error);
+ return error;
+ }
+ }
+
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+
+/**
+ * @brief Unmute headset on a specific channel
+ * @channel_index Headeset channel-index
+ * @gain Gain index of headset
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_unmute_headset(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+
+ /* Check if HS UnMute request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "HS should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ /* UnMute HSL */
+ error = HW_ACODEC_MODIFY_WRITE(MUTE_HS_EAR_REG, 0,
+ EN_HSL_MASK | EN_HSL_DAC_MASK);
+ if (0 != error) {
+ dev_err(dev, "UnMute HSL % d", error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* UnMute HSR */
+ error = HW_ACODEC_MODIFY_WRITE(MUTE_HS_EAR_REG, 0,
+ EN_HSR_MASK | EN_HSR_DAC_MASK);
+ if (0 != error) {
+ dev_err(dev, "UnMute HSR % d", error);
+ return error;
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+
+/**
+ * @brief Enables fading of headset on a specific channel
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_enable_fade_headset(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(SHORT_CIRCUIT_DISABLE_REG,
+ 0, DIS_HS_FAD);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for HS % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DA1_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for HSL % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(HSL_EAR_DIGITAL_GAIN_REG, 0,
+ DIS_DIG_GAIN_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for Digital Gain of HSL % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DA2_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for HSR % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(HSR_DIGITAL_GAIN_REG, 0,
+ DIS_DIG_GAIN_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for Digital Gain of HSR % d",
+ error);
+ return error;
+ }
+
+ return error;
+}
+/**
+ * @brief Disables fading of headset on a specific channel
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_disable_fade_headset(struct device *dev)
+{
+ int error = 0;
+ error = HW_ACODEC_MODIFY_WRITE(SHORT_CIRCUIT_DISABLE_REG,
+ DIS_HS_FAD, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for HS % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DA1_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for HSL % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(HSL_EAR_DIGITAL_GAIN_REG,
+ DIS_DIG_GAIN_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for Digital Gain of HSL % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DA2_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for HSR % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(HSR_DIGITAL_GAIN_REG,
+ DIS_DIG_GAIN_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for Digital Gain of HSR % d",
+ error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power up earpiece
+ * @channel_index Channel-index
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_up_earpiece(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if Earpiece PowerUp request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "EARPIECE should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if Earpiece is already powered up or DA1 being used by HS */
+ if (EN_DA1 & initialVal_DA)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1,
+ DA1_TO_HSL, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "DA_IN1 path mixed with sidetone FIR % d", error);
+ return error;
+ }
+
+ /* Enable DA1 */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA1_REG,
+ SLOT08_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA1 from Slot 08 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ EN_DA1, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DA1 % d", error);
+ return error;
+ }
+
+ /* Power Up EAR class-AB driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ EN_EAR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up EAR class-AB driver % d", error);
+ return error;
+ }
+
+ /* Power up EAR DAC and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(
+ DIGITAL_OUTPUT_ENABLE_REG, EN_EAR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up EAR DAC and digital path % d", error);
+ return error;
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Power down earpiece
+ * @channel_index Channel-index
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_earpiece(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if Earpiece PowerDown request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "EARPIECE should have mono channel");
+ return -EINVAL;
+ }
+
+ /* Check if Earpiece is already powered down or DA1 being used by HS */
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (!(initialVal_DA & EN_DA1))
+ return 0;
+
+ /* Power Down EAR class-AB driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ 0, EN_EAR_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power Down EAR class-AB driver % d", error);
+ return error;
+ }
+
+ /* Power Down EAR DAC and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ 0, EN_EAR_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power Down EAR DAC and digital path % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0, DA1_TO_HSL);
+ if (0 != error) {
+ dev_err(dev,
+ "Clear DA_IN1 path mixed with sidetone FIR % d",
+ error);
+ return error;
+ }
+
+ /* Disable DA1 */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA1);
+ if (0 != error) {
+ dev_err(dev, "Disable DA1 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA1_REG, 0,
+ SLOT08_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA1 cleared from Slot 08 % d", error);
+ return error;
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Mute earpiece
+ * @channel_index Channel-index
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_mute_earpiece(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+
+ /* Check if Earpiece Mute request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "EARPIECE should have mono channel");
+ return -EINVAL;
+ }
+
+ /* Mute Earpiece */
+ error = HW_ACODEC_MODIFY_WRITE(MUTE_HS_EAR_REG,
+ EN_EAR_MASK | EN_EAR_DAC_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Mute Earpiece % d", error);
+ return error;
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Unmute earpiece
+ * @channel_index Channel-index
+ * @gain Gain index of earpiece
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_unmute_earpiece(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+
+ /* Check if Earpiece UnMute request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "EARPIECE should have mono channel");
+ return -EINVAL;
+ }
+
+ /* UnMute Earpiece */
+ error = HW_ACODEC_MODIFY_WRITE(MUTE_HS_EAR_REG, 0,
+ EN_EAR_MASK | EN_EAR_DAC_MASK);
+ if (0 != error) {
+ dev_err(dev, "UnMute Earpiece % d", error);
+ return error;
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Enables fading of earpiece
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_enable_fade_earpiece(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA1_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for Ear % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(HSL_EAR_DIGITAL_GAIN_REG, 0,
+ DIS_DIG_GAIN_FADING);
+ if (0 != error) {
+ dev_err(dev,
+ "Enable fading for Digital Gain of Ear % d", error);
+ return error;
+ }
+
+ return error;
+}
+/**
+ * @brief Disables fading of earpiece
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_disable_fade_earpiece(struct device *dev)
+{
+ int error = 0;
+ error = HW_ACODEC_MODIFY_WRITE(DA1_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for Ear % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power up IHF on a specific channel
+ * @channel_index Channel-index
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_ihf(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if IHF PowerUp request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "IHF should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (EN_DA3 & initialVal_DA)
+ return 0;
+
+ /* Enable DA3 for IHFL */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA3_REG,
+ SLOT10_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA3 from Slot 10 % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ EN_DA3, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up IHFL % d", error);
+ return error;
+ }
+
+ /* Power Up HFL Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ EN_HFL_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up HFL Class-D Driver % d", error);
+ return error;
+ }
+
+ /* Power up HFL Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ EN_HFL_MASK, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Power up HFL Class D driver & digital path % d",
+ error);
+ return error;
+ }
+ }
+
+ /* Enable DA4 for IHFR */
+ if (channel_index & e_CHANNEL_2) {
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (EN_DA4 & initialVal_DA)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA4_REG,
+ SLOT11_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA4 from Slot 11 % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ EN_DA4, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DA4 % d", error);
+ return error;
+ }
+
+ /* Power Up HFR Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ EN_HFR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up HFR Class-D Driver % d", error);
+ return error;
+ }
+
+ /* Power up HFR Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ EN_HFR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Power up HFR Class D driver and digital path % d",
+ error);
+ return error;
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Power down IHF on a specific channel
+ * @channel_index Channel-index
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_ihf(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if IHF Power Down request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "IHF should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (!(initialVal_DA & EN_DA3))
+ return 0;
+
+ /* Power Down HFL Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG, 0,
+ EN_HFL_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power Down HFL Class-D Driver % d",
+ error);
+ return error;
+ }
+
+ /* Power Down HFL Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG, 0,
+ EN_HFL_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power Down HFL Class D driver & digital path % d",
+ error);
+ return error;
+ }
+
+ /* Disable DA3 for IHFL */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA3);
+ if (0 != error) {
+ dev_err(dev, "Disable DA3 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA3_REG, 0,
+ SLOT10_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA3 cleared from Slot 10 % d",
+ error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if IHF is already powered Down */
+ if (!(initialVal_DA & EN_DA4))
+ return 0;
+
+ /* Power Down HFR Class-D Driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG, 0,
+ EN_HFR_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power Down HFR Class-D Driver % d",
+ error);
+ return error;
+ }
+
+ /* Power Down HFR Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG, 0,
+ EN_HFR_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power Down HFR Class D driver & digital path % d",
+ error);
+ return error;
+ }
+
+ /* Disable DA4 for IHFR */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA4);
+ if (0 != error) {
+ dev_err(dev, "Disable DA4 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA4_REG, 0,
+ SLOT11_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA4 cleared from Slot 11 % d",
+ error);
+ return error;
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Mute IHF on a specific channel
+ * @channel_index Channel-index
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_mute_ihf(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+
+ if ((channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ error = ste_audio_io_set_ihf_gain(channel_index, 0, -63,
+ 0, dev);
+ if (0 != error) {
+ dev_err(dev, "Mute ihf % d", error);
+ return error;
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Unmute IHF on a specific channel
+ * @channel_index Channel-index
+ * @gain Gain index of IHF
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_unmute_ihf(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ error = ste_audio_io_set_ihf_gain(channel_index, 0, gain[0],
+ 0, dev);
+ if (0 != error) {
+ dev_err(dev, "UnMute ihf % d", error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ error = ste_audio_io_set_ihf_gain(channel_index, 0, gain[1],
+ 0, dev);
+ if (0 != error) {
+ dev_err(dev, "UnMute ihf % d", error);
+ return error;
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Enable fading of IHF
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_enable_fade_ihf(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA3_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for HFL % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DA4_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for HFR % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Disable fading of IHF
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_disable_fade_ihf(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA3_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for HFL % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DA4_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for HFR % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power up VIBL
+ * @channel_index Channel-index of VIBL
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_vibl(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if VibL PowerUp request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "VibL should have mono channel");
+ return -EINVAL;
+ }
+
+ /* Try to allocate vibrator for audio left channel */
+ error = ste_audioio_vibrator_alloc(STE_AUDIOIO_CLIENT_AUDIO_L,
+ STE_AUDIOIO_CLIENT_AUDIO_R | STE_AUDIOIO_CLIENT_AUDIO_L);
+ if (error) {
+ dev_err(dev, " Couldn't allocate vibrator %d, client %d",
+ error, STE_AUDIOIO_CLIENT_AUDIO_L);
+ return error;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if VibL is already powered up */
+ if (initialVal_DA & EN_DA5)
+ return 0;
+
+ /* Enable DA5 for vibl */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA5_REG,
+ SLOT12_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA5 from Slot 12 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ EN_DA5, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DA5 for VibL % d", error);
+ return error;
+ }
+
+ /* Power Up VibL Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(
+ ANALOG_OUTPUT_ENABLE_REG, EN_VIBL_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up VibL Class-D Driver % d", error);
+ return error;
+ }
+
+ /* Power up VibL Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ EN_VIBL_MASK, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Power up VibL Class D driver and digital path % d",
+ error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power down VIBL
+ * @channel_index Channel-index of VIBL
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_vibl(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if VibL Power Down request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "VibL should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if VibL is already powered down */
+ if (!(initialVal_DA & EN_DA5))
+ return 0;
+
+
+ /* Power Down VibL Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ 0, EN_VIBL_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power Down VibL Class-D Driver % d", error);
+ return error;
+ }
+
+ /* Power Down VibL Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG, 0,
+ EN_VIBL_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power Down VibL Class D driver & digital path % d",
+ error);
+ return error;
+ }
+
+ /* Disable DA5 for VibL */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA5);
+ if (0 != error) {
+ dev_err(dev, "Disable DA5 for VibL % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA5_REG, 0,
+ SLOT12_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA5 cleared from Slot 12 % d", error);
+ return error;
+ }
+
+ /* Release vibrator */
+ ste_audioio_vibrator_release(STE_AUDIOIO_CLIENT_AUDIO_L);
+
+ return error;
+}
+/**
+ * @brief Enable fading of VIBL
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_enable_fade_vibl(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA5_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for VibL % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Disable fading of VIBL
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_disable_fade_vibl(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA5_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for VibL % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power up VIBR
+ * @channel_index Channel-index of VIBR
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_up_vibr(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if VibR PowerUp request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "VibR should have mono channel");
+ return -EINVAL;
+ }
+
+ /* Try to allocate vibrator for audio right channel */
+ error = ste_audioio_vibrator_alloc(STE_AUDIOIO_CLIENT_AUDIO_R,
+ STE_AUDIOIO_CLIENT_AUDIO_R | STE_AUDIOIO_CLIENT_AUDIO_L);
+ if (error) {
+ dev_err(dev, " Couldn't allocate vibrator %d, client %d",
+ error, STE_AUDIOIO_CLIENT_AUDIO_R);
+ return error;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if VibR is already powered up */
+ if (initialVal_DA & EN_DA6)
+ return 0;
+
+ /* Enable DA6 for vibr */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA6_REG,
+ SLOT13_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA5 from Slot 13 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(
+ DIGITAL_DA_CHANNELS_ENABLE_REG, EN_DA6, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DA6 for VibR % d", error);
+ return error;
+ }
+
+ /* Power Up VibR Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(
+ ANALOG_OUTPUT_ENABLE_REG, EN_VIBR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up VibR Class-D Driver % d", error);
+ return error;
+ }
+
+ /* Power up VibR Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ EN_VIBR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Power up VibR Class D driver & digital path % d",
+ error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power down VIBR
+ * @channel_index Channel-index of VIBR
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_vibr(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if VibR PowerDown request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "VibR should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if VibR is already powered down */
+ if (!(initialVal_DA & EN_DA6))
+ return 0;
+
+
+ /* Power Down VibR Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG, 0,
+ EN_VIBR_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power Down VibR Class-D Driver % d", error);
+ return error;
+ }
+
+ /* Power Down VibR Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG, 0,
+ EN_VIBR_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power Down VibR Class D driver & digital path % d",
+ error);
+ return error;
+ }
+
+ /* Disable DA6 for VibR */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA6);
+ if (0 != error) {
+ dev_err(dev, "Disable DA6 for VibR % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA6_REG, 0,
+ SLOT13_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA5 cleared from Slot 13 % d",
+ error);
+ return error;
+ }
+
+ /* Release vibrator */
+ ste_audioio_vibrator_release(STE_AUDIOIO_CLIENT_AUDIO_R);
+
+ return error;
+}
+/**
+ * @brief Enable fading of VIBR
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_enable_fade_vibr(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA6_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for VibR % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Disable fading of VIBR
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_disable_fade_vibr(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA6_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for VibR % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power up MIC1A
+ * @channel_index Channel-index of MIC1A
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_up_mic1a(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if Mic1 PowerUp request is mono channel */
+
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "MIC1 should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ /* Check if Mic1 is already powered up or used by Dmic3 */
+ if (EN_AD3 & initialVal_AD)
+ return 0;
+
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, DATA_FROM_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev, "Slot 02 outputs data from AD_OUT3 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD3, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD3 for Mic1 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0,
+ SEL_DMIC3_FOR_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev, "Select ADC1 for AD_OUT3 % d", error);
+ return error;
+ }
+
+ /* Select MIC1A */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0,
+ SEL_MIC1B_CLR_MIC1A);
+ if (0 != error) {
+ dev_err(dev, "Select MIC1A % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, EN_MIC1, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up Mic1 % d", error);
+ return error;
+ }
+
+ /* Power Up ADC1 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, POWER_UP_ADC1, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up ADC1 % d", error);
+ return error;
+ }
+
+return error;
+}
+/**
+ * @brief Power down MIC1A
+ * @channel_index Channel-index of MIC1A
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_down_mic1a(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if Mic1 PowerDown request is mono channel */
+
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic1 should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ /* Check if Mic1 is already powered down or used by Dmic3 */
+ if (!(initialVal_AD & EN_AD3))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0, EN_MIC1);
+ if (0 != error) {
+ dev_err(dev, "Power Down Mic1 % d", error);
+ return error;
+ }
+
+ /* Power Down ADC1 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0, POWER_UP_ADC1);
+ if (0 != error) {
+ dev_err(dev, "Power Down ADC1 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD3);
+ if (0 != error) {
+ dev_err(dev, "Disable AD3 for Mic1 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT2_3_REG, 0,
+ DATA_FROM_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev, "Slot 02 outputs data cleared from AD_OUT3 % d",
+ error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Mute MIC1A
+ * @channel_index Channel-index of MIC1A
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_mute_mic1a(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "MIC1 should have mono channel");
+ return -EINVAL;
+ }
+
+ /* Mute mic1 */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, MUT_MIC1, 0);
+ if (0 != error) {
+ dev_err(dev, "Mute Mic1 % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Unmute MIC1A
+ * @channel_index Channel-index of MIC1A
+ * @gain Gain index of MIC1A
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_unmute_mic1a(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic1 should have mono channel");
+ return -EINVAL;
+ }
+ /* UnMute mic1 */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0, MUT_MIC1);
+ if (0 != error) {
+ dev_err(dev, "UnMute Mic1 % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Enable fading of MIC1A
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_enable_fade_mic1a(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD3_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for Mic1 % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Disable fading of MIC1A
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_disable_fade_mic1a(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD3_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for Mic1 % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power up MIC1B
+ * @channel_index Channel-index of MIC1B
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_mic1b(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic1 should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ /* Check if Mic1 is already powered up or used by Dmic3 */
+ if (EN_AD3 & initialVal_AD)
+ return 0;
+
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, DATA_FROM_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev, "Slot 02 outputs data from AD_OUT3 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD3, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD3 for Mic1 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0,
+ SEL_DMIC3_FOR_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev, "Select ADC1 for AD_OUT3 % d", error);
+ return error;
+ }
+
+ /* Select MIC1B */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, SEL_MIC1B_CLR_MIC1A,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Select MIC1B % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, EN_MIC1, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up Mic1 % d", error);
+ return error;
+ }
+
+ /* Power Up ADC1 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, POWER_UP_ADC1, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up ADC1 % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power down MIC1B
+ * @channel_index Channel-index of MIC1B
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_mic1b(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if Mic1 PowerDown request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic1 should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if Mic1 is already powered down or used by Dmic3 */
+ if (!(initialVal_AD & EN_AD3))
+ return 0;
+
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0, EN_MIC1);
+ if (0 != error) {
+ dev_err(dev, "Power Down Mic1 % d", error);
+ return error;
+ }
+
+ /* Power Down ADC1 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0, POWER_UP_ADC1);
+ if (0 != error) {
+ dev_err(dev, "Power Down ADC1 % d", error);
+ return error;
+ }
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG, 0,
+ EN_AD3);
+ if (0 != error) {
+ dev_err(dev, "Disable AD3 for Mic1 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT2_3_REG, 0,
+ DATA_FROM_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev, "Slot 02 outputs data cleared from AD_OUT3 % d",
+ error);
+ return error;
+ }
+
+ return error;
+}
+/**
+ * @brief Power up MIC2
+ * @channel_index Channel-index of MIC2
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_mic2(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if Mic2 PowerUp request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic2 should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if Mic2 is already powered up or used by LINR or Dmic2 */
+ if (EN_AD2 & initialVal_AD)
+ return 0;
+
+
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, DATA_FROM_AD_OUT2);
+ if (0 != error) {
+ dev_err(dev, "Slot 01 outputs data from AD_OUT2 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG, EN_AD2,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD2 for Mic2 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0,
+ SEL_DMIC2_FOR_AD_OUT2);
+ if (0 != error) {
+ dev_err(dev, "Select ADC2 for AD_OUT2 % d", error);
+ return error;
+ }
+
+ /* Select mic2 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0,
+ SEL_LINR_CLR_MIC2);
+ if (0 != error) {
+ dev_err(dev, "Select MIC2 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, EN_MIC2, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up Mic2 % d", error);
+ return error;
+ }
+
+ /* Power Up ADC1 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, POWER_UP_ADC2, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up ADC2 % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power down MIC2
+ * @channel_index Channel-index of MIC2
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_mic2(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if Mic2 PowerDown request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic2 should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if Mic2 is already powered down or used by LINR or Dmic2 */
+ if (!(initialVal_AD & EN_AD2))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0, EN_MIC2);
+ if (0 != error) {
+ dev_err(dev, "Power Down Mic2 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD2);
+ if (0 != error) {
+ dev_err(dev, "Disable AD2 for Mic2 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, 0,
+ (DATA_FROM_AD_OUT2<<4));
+ if (0 != error) {
+ dev_err(dev, "Slot 01 outputs data cleared from AD_OUT2 % d",
+ error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Mute MIC2
+ * @channel_index Channel-index of MIC2
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_mute_mic2(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic2 should have mono channel");
+ return -EINVAL;
+ }
+
+ /* Mute mic2 */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, MUT_MIC2, 0);
+ if (0 != error) {
+ dev_err(dev, "Mute Mic2 % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Unmute MIC2
+ * @channel_index Channel-index of MIC2
+ * @gain Gain index of MIC2
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_unmute_mic2(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic2 should have mono channel");
+ return -EINVAL;
+ }
+ /* UnMute mic2 */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0, MUT_MIC2);
+ if (0 != error) {
+ dev_err(dev, "UnMute Mic2 % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Enable fading of MIC2
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_enable_fade_mic2(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD2_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for Mic2 % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Disable fading of MIC2
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_disable_fade_mic2(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD2_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for Mic2 % d", error);
+ return error;
+ }
+
+ return error;
+}
+/**
+ * @brief Power up LinIn
+ * @channel_index Channel-index of LinIn
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_lin(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if LinIn PowerUp request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "LinIn should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ /* Enable AD1 for LinInL */
+ if (channel_index & e_CHANNEL_1) {
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (initialVal_AD & EN_AD1)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG,
+ DATA_FROM_AD_OUT1, 0);
+ if (0 != error) {
+ dev_err(dev, "Slot 00 outputs data from AD_OUT1 % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD1, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD1 for LinInL % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0,
+ SEL_DMIC1_FOR_AD_OUT1);
+ if (0 != error) {
+ dev_err(dev, "Select ADC3 for AD_OUT1 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(
+ LINE_IN_MIC_CONF_REG, EN_LIN_IN_L, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up LinInL % d", error);
+ return error;
+ }
+
+ /* Power Up ADC3 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG,
+ POWER_UP_ADC3, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up ADC3 % d", error);
+ return error;
+ }
+ }
+ /* Enable AD2 for LinInR */
+
+ if (channel_index & e_CHANNEL_2) {
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (EN_AD2 & initialVal_AD)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG,
+ (DATA_FROM_AD_OUT2<<4), 0);
+ if (0 != error) {
+ dev_err(dev, "Slot 01 outputs data from AD_OUT2 % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD2, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD2 LinInR % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0,
+ SEL_DMIC2_FOR_AD_OUT2);
+ if (0 != error) {
+ dev_err(dev, "Select ADC2 for AD_OUT2 % d", error);
+ return error;
+ }
+
+ /* Select LinInR */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG,
+ SEL_LINR_CLR_MIC2, 0);
+ if (0 != error) {
+ dev_err(dev, "Select LinInR % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG,
+ EN_LIN_IN_R, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up LinInR % d", error);
+ return error;
+ }
+
+ /* Power Up ADC2 */
+ error = HW_ACODEC_MODIFY_WRITE(
+ ADC_DAC_ENABLE_REG, POWER_UP_ADC2, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up ADC2 % d", error);
+ return error;
+ }
+ }
+ return error;
+}
+/**
+ * @brief Power down LinIn
+ * @channel_index Channel-index of LinIn
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_down_lin(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if LinIn PowerDown request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "LinIn should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ /* Enable AD1 for LinInL */
+ if (channel_index & e_CHANNEL_1) {
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (!(initialVal_AD & EN_AD1))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0,
+ EN_LIN_IN_L);
+ if (0 != error) {
+ dev_err(dev, "Power Down LinInL % d", error);
+ return error;
+ }
+
+ /* Power Down ADC3 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0,
+ POWER_UP_ADC3);
+ if (0 != error) {
+ dev_err(dev, "Power Down ADC3 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD1);
+ if (0 != error) {
+ dev_err(dev, "Disable AD1 for LinInL % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, 0,
+ DATA_FROM_AD_OUT1);
+ if (0 != error) {
+ dev_err(dev,
+ "Slot 00 outputs data cleared from AD_OUT1 % d",
+ error);
+ return error;
+ }
+ }
+
+ /* Enable AD2 for LinInR */
+ if (channel_index & e_CHANNEL_2) {
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (!(initialVal_AD & EN_AD2))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0,
+ EN_LIN_IN_R);
+ if (0 != error) {
+ dev_err(dev, "Power Down LinInR % d", error);
+ return error;
+ }
+
+ /* Power Down ADC2 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0,
+ POWER_UP_ADC2);
+ if (0 != error) {
+ dev_err(dev, "Power Down ADC2 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD2);
+ if (0 != error) {
+ dev_err(dev, "Disable AD2 LinInR % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, 0,
+ (DATA_FROM_AD_OUT2<<4));
+ if (0 != error) {
+ dev_err(dev,
+ "Slot01 outputs data cleared from AD_OUT2 % d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+/**
+ * @brief Mute LinIn
+ * @channel_index Channel-index of LinIn
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_mute_lin(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "LinIn should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Mute LinInL */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG,
+ MUT_LIN_IN_L, 0);
+ if (0 != error) {
+ dev_err(dev, "Mute LinInL % d", error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* Mute LinInR */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG,
+ MUT_LIN_IN_R,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Mute LinInR % d", error);
+ return error;
+ }
+ }
+ return error;
+}
+/**
+ * @brief Unmute LinIn
+ * @channel_index Channel-index of LinIn
+ * @gain Gain index of LinIn
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_unmute_lin(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "LinIn should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ /* UnMute LinInL */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0,
+ MUT_LIN_IN_L);
+ if (0 != error) {
+ dev_err(dev, "UnMute LinInL % d", error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* UnMute LinInR */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0,
+ MUT_LIN_IN_R);
+ if (0 != error) {
+ dev_err(dev, "UnMute LinInR % d", error);
+ return error;
+ }
+ }
+ return error;
+}
+/**
+ * @brief Enables fading of LinIn
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_enable_fade_lin(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD1_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for LinInL % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD2_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for LinInR % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Disables fading of LinIn
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_disable_fade_lin(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD1_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for LinInL % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD2_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for LinInR % d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power Up DMIC12 LinIn
+ * @channel_index Channel-index of DMIC12
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_dmic12(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if DMic12 request is mono or Stereo */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "DMic12 does not support more than 2 channels");
+
+ return -EINVAL;
+ }
+
+ /* Setting Direction for GPIO pins on AB8500 */
+ error = HW_REG_WRITE(AB8500_GPIO_DIR4_REG, GPIO27_DIR_OUTPUT);
+ if (0 != error) {
+ dev_err(dev, "Setting Direction for GPIO pins on AB8500 % d",
+ error);
+ return error;
+ }
+
+ /* Enable AD1 for Dmic1 */
+ if (channel_index & e_CHANNEL_1) {
+ /* Check if DMIC1 is already powered up or used by LinInL */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ if (initialVal_AD & EN_AD1)
+ return 0;
+
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG,
+ DATA_FROM_AD_OUT1);
+ if (0 != error) {
+ dev_err(dev, "Slot 00 outputs data from AD_OUT1 % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD1, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD1 for DMIC1 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1,
+ SEL_DMIC1_FOR_AD_OUT1, 0);
+ if (0 != error) {
+ dev_err(dev, "Select DMIC1 for AD_OUT1 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, EN_DMIC1, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC1 % d", error);
+ return error;
+ }
+ }
+ /* Enable AD2 for Dmic2 */
+
+ if (channel_index & e_CHANNEL_2) {
+ /* Check if DMIC2 is already powered up
+ or used by Mic2 or LinInR */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ if (initialVal_AD & EN_AD2)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG,
+ (DATA_FROM_AD_OUT2<<4), 0);
+ if (0 != error) {
+ dev_err(dev, "Slot 01 outputs data from AD_OUT2 % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD2, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD2 for DMIC2 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1,
+ SEL_DMIC2_FOR_AD_OUT2, 0);
+ if (0 != error) {
+ dev_err(dev, "Select DMIC2 for AD_OUT2 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, EN_DMIC2, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC2 % d", error);
+ return error;
+ }
+ }
+
+ return error;
+}
+/**
+ * @brief Power down DMIC12 LinIn
+ * @channel_index Channel-index of DMIC12
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_power_down_dmic12(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if DMic12 request is mono or Stereo or multi channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "DMic12 does not support more than 2 channels");
+
+ return -EINVAL;
+ }
+
+ /* Setting Direction for GPIO pins on AB8500 */
+ error = HW_ACODEC_MODIFY_WRITE(AB8500_GPIO_DIR4_REG, 0,
+ GPIO27_DIR_OUTPUT);
+ if (0 != error) {
+ dev_err(dev, "Clearing Direction for GPIO pins on AB8500 % d",
+ error);
+ return error;
+ }
+ /* Enable AD1 for Dmic1 */
+ if (channel_index & e_CHANNEL_1) {
+ /* Check if DMIC1 is already powered Down or used by LinInL */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ if (!(initialVal_AD & EN_AD1))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, 0, EN_DMIC1);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC1 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD1);
+ if (0 != error) {
+ dev_err(dev, "Disable AD1 for DMIC1 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, 0,
+ DATA_FROM_AD_OUT1);
+ if (0 != error) {
+ dev_err(dev,
+ "Slot 00 outputs data cleared from AD_OUT1 % d",
+ error);
+ return error;
+ }
+ }
+
+ /* Enable AD2 for Dmic2 */
+ if (channel_index & e_CHANNEL_2) {
+ /* MIC2 is already powered Down or used by Mic2 or LinInR */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ if (!(initialVal_AD & EN_AD2))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, 0, EN_DMIC2);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC2 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD2);
+ if (0 != error) {
+ dev_err(dev, "Disable AD2 for DMIC2 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, 0,
+ (DATA_FROM_AD_OUT2<<4));
+ if (0 != error) {
+ dev_err(dev,
+ "Slot 01 outputs data cleared from AD_OUT2 % d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+/**
+ * @brief Get headset gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_get_headset_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ int i = 0;
+ if (gain_index == 0) {
+
+ *left_volume = 0 - HW_REG_READ(DA1_DIGITAL_GAIN_REG);
+ *right_volume = 0 - HW_REG_READ(DA2_DIGITAL_GAIN_REG);
+
+ }
+
+ if (gain_index == 1) {
+ *left_volume = 8 - HW_REG_READ(HSL_EAR_DIGITAL_GAIN_REG);
+ *right_volume = 8 - HW_REG_READ(HSR_DIGITAL_GAIN_REG);
+ }
+
+ if (gain_index == 2) {
+ i = (HW_REG_READ(ANALOG_HS_GAIN_REG)>>4);
+ *left_volume = hs_analog_gain_table[i];
+ i = (HW_REG_READ(ANALOG_HS_GAIN_REG) & MASK_QUARTET0);
+ *right_volume = hs_analog_gain_table[i];
+ }
+ return 0;
+}
+/**
+ * @brief Get earpiece gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_get_earpiece_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ if (0 == gain_index)
+ *left_volume = 0 - HW_REG_READ(DA1_DIGITAL_GAIN_REG);
+ if (1 == gain_index)
+ *left_volume = 8 - HW_REG_READ(HSL_EAR_DIGITAL_GAIN_REG);
+ return 0;
+}
+/**
+ * @brief Get ihf gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_get_ihf_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+
+ *left_volume = 0 - HW_REG_READ(DA3_DIGITAL_GAIN_REG);
+ *right_volume = 0 - HW_REG_READ(DA4_DIGITAL_GAIN_REG);
+ return 0;
+}
+/**
+ * @brief Get vibl gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_get_vibl_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+
+ *left_volume = 0 - HW_REG_READ(DA5_DIGITAL_GAIN_REG);
+
+ return 0;
+}
+/**
+ * @brief Get vibr gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_get_vibr_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+
+ *right_volume = 0 - HW_REG_READ(DA6_DIGITAL_GAIN_REG);
+ return 0;
+}
+/**
+ * @brief Get MIC1A & MIC2A gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_get_mic1a_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ if (gain_index == 0)
+ *left_volume = 31 - HW_REG_READ(AD3_DIGITAL_GAIN_REG);
+ if (gain_index == 1)
+ *left_volume = HW_REG_READ(ANALOG_MIC1_GAIN_REG);
+
+ return 0;
+}
+/**
+ * @brief Get MIC2 gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_get_mic2_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ if (gain_index == 0)
+ *left_volume = 31 - HW_REG_READ(AD2_DIGITAL_GAIN_REG);
+ if (gain_index == 1)
+ *left_volume = HW_REG_READ(ANALOG_MIC2_GAIN_REG);
+
+ return 0;
+}
+/**
+ * @brief Get Lin IN gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_get_lin_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ if (gain_index == 0) {
+ *left_volume = 31 - HW_REG_READ(AD1_DIGITAL_GAIN_REG);
+ *right_volume = 31 - HW_REG_READ(AD2_DIGITAL_GAIN_REG);
+ }
+
+ if (gain_index == 0) {
+ *left_volume = 2 * ((HW_REG_READ(ANALOG_HS_GAIN_REG)>>4) - 5);
+ *right_volume = 2 * (HW_REG_READ(ANALOG_LINE_IN_GAIN_REG) - 5);
+ }
+
+ return 0;
+}
+/**
+ * @brief Get DMIC12 gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_get_dmic12_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+
+ *left_volume = HW_REG_READ(AD1_DIGITAL_GAIN_REG);
+
+ *right_volume = HW_REG_READ(AD2_DIGITAL_GAIN_REG);
+
+ return 0;
+}
+/**
+ * @brief Get DMIC34 gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_get_dmic34_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ *left_volume = HW_REG_READ(AD3_DIGITAL_GAIN_REG);
+ *right_volume = HW_REG_READ(AD4_DIGITAL_GAIN_REG);
+
+ return 0;
+}
+/**
+ * @brief Get DMIC56 gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_get_dmic56_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ *left_volume = HW_REG_READ(AD5_DIGITAL_GAIN_REG);
+
+ *right_volume = HW_REG_READ(AD6_DIGITAL_GAIN_REG);
+ return 0;
+}
+/**
+ * @brief Set gain of headset along a specified channel
+ * @channel_index Channel-index of headset
+ * @gain_index Gain index of headset
+ * @gain_value Gain value of headset
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_set_headset_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+ int i = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA1_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(DA1_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain HSL gainindex = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+
+ if (gain_index == 1) {
+ int gain = 0;
+ gain = 8 - gain_value;
+
+ initial_val = HW_REG_READ(HSL_EAR_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(HSL_EAR_DIGITAL_GAIN_REG,
+ ((initial_val & (~HS_DIGITAL_GAIN_MASK)) | (gain &
+ HS_DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain HSL gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+
+ if (gain_index == 2) {
+ /* Set Analog gain */
+ int gain = -1;
+
+ if (gain_value % 2) {
+ gain_value -= 1;
+ dev_err(dev,
+ "Odd Gain received.Fixing it to 2dB step gain_value = % d",
+ gain_value);
+ }
+ /* Fix for 4dB step gains. Select one lower value */
+ if (gain_value == -22)
+ gain_value = -24;
+
+ if (gain_value == -26)
+ gain_value = -28;
+
+ if (gain_value == -30)
+ gain_value = -32;
+
+ for (i = 0 ; i < 16; i++) {
+ if (hs_analog_gain_table[i] == gain_value) {
+ gain = i<<4;
+ break;
+ }
+ }
+ if (gain == -1)
+ return -1;
+
+ initial_val = HW_REG_READ(ANALOG_HS_GAIN_REG);
+
+ /* Write gain */
+ error = HW_REG_WRITE(ANALOG_HS_GAIN_REG, ((initial_val &
+ (~L_ANALOG_GAIN_MASK)) | (gain & L_ANALOG_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain HSL gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+
+ /* for HSR */
+ if (channel_index & e_CHANNEL_2) {
+ /* Set Gain HSR */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA2_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(DA2_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain HSR gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+
+ if (gain_index == 1) {
+ int gain = 0;
+ gain = 8 - gain_value;
+
+ initial_val = HW_REG_READ(HSR_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(HSR_DIGITAL_GAIN_REG, ((initial_val
+ & (~HS_DIGITAL_GAIN_MASK)) | (gain &
+ HS_DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain HSR gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+
+ }
+
+ if (gain_index == 2) {
+ /* Set Analog gain */
+ int gain = -1;
+
+ if (gain_value % 2) {
+ gain_value -= 1;
+ dev_err(dev,
+ "Odd Gain received.Fixing it to 2dB step gain_value = % d",
+ gain_value);
+ }
+ /* Fix for 4dB step gains. Select one lower value */
+ if (gain_value == -22)
+ gain_value = -24;
+
+ if (gain_value == -26)
+ gain_value = -28;
+
+ if (gain_value == -30)
+ gain_value = -32;
+
+ for (i = 0 ; i < 16 ; i++) {
+ if (hs_analog_gain_table[i] == gain_value) {
+ gain = i;
+ break;
+ }
+ }
+ if (gain == -1)
+ return -1;
+
+ initial_val = HW_REG_READ(ANALOG_HS_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(ANALOG_HS_GAIN_REG, ((initial_val &
+ (~R_ANALOG_GAIN_MASK)) | (gain & R_ANALOG_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain HSR gainindex = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Set gain of earpiece
+ * @channel_index Channel-index of earpiece
+ * @gain_index Gain index of earpiece
+ * @gain_value Gain value of earpiece
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_earpiece_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+ if (channel_index & e_CHANNEL_1) {
+ if (0 == gain_index) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA1_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(DA1_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain Ear gainindex = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+
+ if (gain_index == 1) {
+ int gain = 0;
+ gain = 8 - gain_value;
+
+ initial_val = HW_REG_READ(HSL_EAR_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(HSL_EAR_DIGITAL_GAIN_REG,
+ ((initial_val & (~HS_DIGITAL_GAIN_MASK)) | (gain &
+ HS_DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain Ear gainindex = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Set gain of vibl
+ * @channel_index Channel-index of vibl
+ * @gain_index Gain index of vibl
+ * @gain_value Gain value of vibl
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_vibl_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain vibl */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA5_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(DA5_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain VibL gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ return error;
+}
+/**
+ * @brief Set gain of vibr
+ * @channel_index Channel-index of vibr
+ * @gain_index Gain index of vibr
+ * @gain_value Gain value of vibr
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_set_vibr_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value,
+ u32 linear,
+ struct device *dev)
+{
+
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain vibr */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA6_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(DA6_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain VibR gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ return error;
+}
+/**
+ * @brief Set gain of ihf along a specified channel
+ * @channel_index Channel-index of ihf
+ * @gain_index Gain index of ihf
+ * @gain_value Gain value of ihf
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_ihf_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain IHFL */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA3_DIGITAL_GAIN_REG);
+ error = HW_REG_WRITE(DA3_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain IHFL gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+
+ }
+ }
+ if (channel_index & e_CHANNEL_2) {
+ /* Set Gain IHFR */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA4_DIGITAL_GAIN_REG);
+ error = HW_REG_WRITE(DA4_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain IHFR gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+/**
+ * @brief Set gain of MIC1A & MIC1B
+ * @channel_index Channel-index of MIC1
+ * @gain_index Gain index of MIC1
+ * @gain_value Gain value of MIC1
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_mic1a_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain mic1 */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD3_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(AD3_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain Mic1 gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+
+ }
+
+ if (gain_index == 1) {
+ /* Set Analog gain */
+ initial_val = HW_REG_READ(ANALOG_MIC1_GAIN_REG);
+
+ /* Write gain */
+ error = HW_REG_WRITE(ANALOG_MIC1_GAIN_REG, ((initial_val
+ & (~MIC_ANALOG_GAIN_MASK)) | (gain_value &
+ MIC_ANALOG_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain Mic1 gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ return error;
+}
+/**
+ * @brief Set gain of MIC2
+ * @channel_index Channel-index of MIC2
+ * @gain_index Gain index of MIC2
+ * @gain_value Gain value of MIC2
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_mic2_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value,
+ u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain mic2 */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD2_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(AD2_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain Mic2 gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+
+ }
+
+ if (gain_index == 1) {
+ /* Set Analog gain */
+ initial_val = HW_REG_READ(ANALOG_MIC2_GAIN_REG);
+
+ /* Write gain */
+ error = HW_REG_WRITE(ANALOG_MIC2_GAIN_REG, ((initial_val
+ & (~MIC_ANALOG_GAIN_MASK)) | (gain_value &
+ MIC_ANALOG_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain Mic2 gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ return error;
+}
+/**
+ * @brief Set gain of Lin IN along a specified channel
+ * @channel_index Channel-index of Lin In
+ * @gain_index Gain index of Lin In
+ * @gain_value Gain value of Lin In
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_lin_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD1_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(AD1_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain LinInL gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+
+ }
+
+ if (gain_index == 1) {
+ int gain = 0;
+ /*
+ * Converting -10 to 20 range into 0 - 15
+ * & shifting it left by 4 bits
+ */
+ gain = ((gain_value/2) + 5)<<4;
+
+ initial_val = HW_REG_READ(ANALOG_LINE_IN_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(ANALOG_LINE_IN_GAIN_REG,
+ ((initial_val & (~L_ANALOG_GAIN_MASK)) | (gain &
+ L_ANALOG_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain LinInL gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* Set Gain LinInR */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD2_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(AD2_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain LinInR gain index = % d% d",
+ gain_index, error);
+ return error;
+ }
+ }
+ if (gain_index == 1) {
+ int gain = 0;
+ /* Converting -10 to 20 range into 0 - 15 */
+ gain = ((gain_value/2) + 5);
+
+ initial_val = HW_REG_READ(ANALOG_LINE_IN_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(ANALOG_LINE_IN_GAIN_REG,
+ ((initial_val & (~R_ANALOG_GAIN_MASK)) | (gain &
+ R_ANALOG_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain LinInR gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+/**
+ * @brief Set gain of DMIC12 along a specified channel
+ * @channel_index Channel-index of DMIC12
+ * @gain_index Gain index of DMIC12
+ * @gain_value Gain value of DMIC12
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_dmic12_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain Dmic1 */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD1_DIGITAL_GAIN_REG);
+ error = HW_REG_WRITE(AD1_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain DMic1 gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ if (channel_index & e_CHANNEL_2) {
+ /* Set Gain Dmic2 */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD2_DIGITAL_GAIN_REG);
+ error = HW_REG_WRITE(AD2_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain DMic2 gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ return error;
+}
+
+int ste_audio_io_switch_to_burst_mode_headset(int burst_fifo_switch_frame,
+ struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_INT_CONTROL_REG,
+ WAKEUP_SIGNAL_SAMPLE_COUNT, 0);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_LENGTH_REG,
+ BURST_FIFO_TRANSFER_LENGTH, 0);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_CONTROL_REG,
+ (BURST_FIFO_INF_RUNNING | BURST_FIFO_INF_IN_MASTER_MODE
+ |PRE_BIT_CLK0_COUNT), 0);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_WAKE_UP_DELAY_REG,
+ BURST_FIFO_WAKUP_DEALAY, 0);
+ if (0 != error)
+ return error;
+
+ error = HW_REG_WRITE(BURST_FIFO_SWITCH_FRAME_REG,
+ burst_fifo_switch_frame);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(TDM_IF_BYPASS_B_FIFO_REG,
+ IF0_BFifoEn, 0);
+ if (0 != error)
+ return error;
+
+ return error;
+}
+int ste_audio_io_switch_to_normal_mode_headset(
+ struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(TDM_IF_BYPASS_B_FIFO_REG, 0,
+ IF0_BFifoEn);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_INT_CONTROL_REG,
+ 0, WAKEUP_SIGNAL_SAMPLE_COUNT);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_LENGTH_REG,
+ 0, BURST_FIFO_TRANSFER_LENGTH);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_CONTROL_REG, 0,
+ (BURST_FIFO_INF_RUNNING | BURST_FIFO_INF_IN_MASTER_MODE
+ |PRE_BIT_CLK0_COUNT));
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_WAKE_UP_DELAY_REG,
+ 0, BURST_FIFO_WAKUP_DEALAY);
+ if (0 != error)
+ return error;
+
+ return error;
+}
+
+
+int ste_audio_io_mute_vibl(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_unmute_vibl(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_mute_vibr(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ return 0;
+}
+int ste_audio_io_unmute_vibr(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_mute_dmic12(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ if ((channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ error = ste_audio_io_set_dmic12_gain(channel_index, 0, -32,
+ 0, dev);
+ if (0 != error) {
+ dev_err(dev, "Mute dmic12 % d", error);
+ return error;
+ }
+ }
+
+ return error;
+
+}
+
+int ste_audio_io_unmute_dmic12(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+ if ((channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ error = ste_audio_io_set_dmic12_gain(channel_index,
+ 0, gain[0], 0, dev);
+ if (0 != error) {
+ dev_err(dev, "UnMute dmic12 % d", error);
+ return error;
+ }
+ }
+ return error;
+}
+int ste_audio_io_enable_fade_dmic12(struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_disable_fade_dmic12(struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_power_up_dmic34(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if DMic34 request is mono or Stereo */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "DMic34 does not support more than 2 channels");
+ return -EINVAL;
+ }
+
+ /* Setting Direction for GPIO pins on AB8500 */
+ error = HW_REG_WRITE(AB8500_GPIO_DIR4_REG, GPIO29_DIR_OUTPUT);
+ if (0 != error) {
+ dev_err(dev, "Setting Direction for GPIO pins on AB8500 % d",
+ error);
+ return error;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Check if DMIC3 is already powered up or used by Mic1A
+ or Mic1B */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+
+ if (initialVal_AD & (EN_AD3))
+ return 0;
+
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT2_3_REG,
+ DATA_FROM_AD_OUT3, 0);
+ if (0 != error) {
+ dev_err(dev, "Slot 02 outputs data from AD_OUT3 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG, EN_AD3,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD3 for DMIC3 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1,
+ SEL_DMIC3_FOR_AD_OUT3,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Select DMIC3 for AD_OUT3 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, EN_DMIC3, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC3 % d", error);
+ return error;
+ }
+}
+
+ /* Enable AD4 for Dmic4 */
+ if (channel_index & e_CHANNEL_2) {
+ /* Check if DMIC4 is already powered up */
+ if (initialVal_AD & (EN_AD4))
+ return 0;
+
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT2_3_REG,
+ (DATA_FROM_AD_OUT4<<4), 0);
+ if (0 != error) {
+ dev_err(dev, "Slot 03 outputs data from AD_OUT4 % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD4, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD4 for DMIC4 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, EN_DMIC4, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC4 % d", error);
+ return error;
+ }
+ }
+ return error;
+ }
+
+int ste_audio_io_power_down_dmic34(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "DMic34 does not support more than 2 channels");
+ return -EINVAL;
+ }
+
+ /* Setting Direction for GPIO pins on AB8500 */
+ error = HW_ACODEC_MODIFY_WRITE(AB8500_GPIO_DIR4_REG, 0,
+ GPIO29_DIR_OUTPUT);
+ if (0 != error) {
+ dev_err(dev, "Clearing Direction for GPIO pins on AB8500 % d",
+ error);
+ return error;
+ }
+
+ /* Enable AD1 for Dmic1 */
+ if (channel_index & e_CHANNEL_1) {
+ /* Check if DMIC3 is already powered Down or used by Mic1A
+ or Mic1B */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ if (!(initialVal_AD & EN_AD3))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, 0, EN_DMIC3);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC3 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0,
+ EN_AD3);
+ if (0 != error) {
+ dev_err(dev, "Disable AD3 for DMIC3 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT2_3_REG, 0,
+ DATA_FROM_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev,
+ "Slot 02 outputs data cleared from AD_OUT3 % d",
+ error);
+ return error;
+ }
+ }
+
+ /* Enable AD4 for Dmic4 */
+ if (channel_index & e_CHANNEL_2) {
+ /* Check if DMIC4 is already powered down */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ if (!(initialVal_AD & EN_AD4))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, 0, EN_DMIC4);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC4 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD4);
+ if (0 != error) {
+ dev_err(dev, "Disable AD4 for DMIC4 % d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT2_3_REG, 0,
+ (DATA_FROM_AD_OUT4<<4));
+ if (0 != error) {
+ dev_err(dev,
+ "Slot 03 outputs data cleared from AD_OUT4 % d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+int ste_audio_io_set_dmic34_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain Dmic3 */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD3_DIGITAL_GAIN_REG);
+ error = HW_REG_WRITE(AD3_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain DMic3 gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* Set Gain Dmic4 */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD4_DIGITAL_GAIN_REG);
+ error = HW_REG_WRITE(AD4_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain DMic4 gain index = % d % d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+int ste_audio_io_mute_dmic34(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ if ((channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ error = ste_audio_io_set_dmic34_gain(channel_index, 0, -32,
+ 0, dev);
+ if (0 != error) {
+ dev_err(dev, "Mute dmic34 % d", error);
+ return error;
+ }
+ }
+ return error;
+}
+int ste_audio_io_unmute_dmic34(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+ if ((channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ error = ste_audio_io_set_dmic34_gain(channel_index,
+ 0, gain[0], 0, dev);
+ if (0 != error) {
+ dev_err(dev, "UnMute dmic34 % d", error);
+ return error;
+ }
+ }
+ return error;
+}
+int ste_audio_io_enable_fade_dmic34(struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_disable_fade_dmic34(struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_power_up_dmic56(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ return 0;
+}
+int ste_audio_io_power_down_dmic56(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ return 0;
+}
+int ste_audio_io_set_dmic56_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ return 0;
+}
+int ste_audio_io_mute_dmic56(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ return 0;
+}
+int ste_audio_io_unmute_dmic56(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ return 0;
+}
+int ste_audio_io_enable_fade_dmic56(struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_disable_fade_dmic56(struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_configure_if1(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_REG_WRITE(IF1_CONF_REG, IF_DELAYED |
+ I2S_LEFT_ALIGNED_FORMAT | WORD_LENGTH_16);
+ if (error != 0) {
+ dev_err(dev,
+ "Configure IF1: I2S Format 16 Bits word length error = % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(TDM_IF_BYPASS_B_FIFO_REG, IF1_MASTER, 0);
+ if (error != 0) {
+ dev_err(dev,
+ "Configure IF1: IF1 master error = % d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(IF0_IF1_MASTER_CONF_REG,
+ EN_FSYNC_BITCLK1, 0);
+ if (error != 0) {
+ dev_err(dev,
+ "ConfigIF1 bitclk is 32x48KHz, enable Fsync1 and Bitclk1 error = % d",
+ error);
+ return error;
+ }
+ return error;
+}
+
+int ste_audio_io_power_up_fmrx(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal = 0;
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "FMRX should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ ste_audio_io_configure_if1(dev);
+
+ if (channel_index & e_CHANNEL_1) {
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA7_REG,
+ SLOT24_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA_IN7 from Slot 24 % d",
+ error);
+ return error;
+ }
+ /* DA_IN7 to AD_OUT8 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA5_REG,
+ SEL_AD_OUT8_FROM_DAIN7, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to AD_OUT5 from DA_IN7 % d",
+ error);
+ return error;
+ }
+
+ initialVal = HW_REG_READ(AD_ALLOCATION_TO_SLOT6_7_REG);
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT6_7_REG,
+ ((initialVal & MASK_QUARTET1)|SEL_IF6_FROM_AD_OUT5));
+ if (0 != error) {
+ dev_err(dev, "Data sent to IF slot 6 from AD_OUT5 % d",
+ error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA8_REG,
+ SLOT25_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA_IN8 from Slot 25 % d",
+ error);
+ return error;
+ }
+
+ /* DA_IN7 to AD_OUT8 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA6_REG,
+ SEL_AD_OUT6_FROM_DAIN8, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to AD_OUT6 from DA_IN8 % d",
+ error);
+ return error;
+ }
+
+ initialVal = HW_REG_READ(AD_ALLOCATION_TO_SLOT6_7_REG);
+
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT6_7_REG,
+ (initialVal & MASK_QUARTET0)|SEL_IF7_FROM_AD_OUT6);
+ /* 5x is written */
+ if (0 != error) {
+ dev_err(dev, "Data sent to IF7 from AD_OUT6 % d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+int ste_audio_io_power_down_fmrx(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "FMRX should have mono or stereo channels");
+ return -EINVAL;
+ }
+ if (channel_index & e_CHANNEL_1) {
+ /* data sent to DA7 input of DA filter form IF1 */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA7_REG, 0,
+ SLOT24_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev, "Clearing Data sent to DA_IN7 from Slot 24 % d",
+ error);
+ return error;
+ }
+ /* DA_IN7 to AD_OUT8 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA5_REG, 0,
+ SEL_AD_OUT8_FROM_DAIN7);
+ if (0 != error) {
+ dev_err(dev, "Clearing Data sent to AD_OUT5 from DA_IN7 % d",
+ error);
+ return error;
+ }
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT6_7_REG, 0,
+ SEL_IF6_FROM_AD_OUT5);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to IF slot 6 from AD_OUT5 % d",
+ error);
+ return error;
+ }
+}
+
+ if (channel_index & e_CHANNEL_2) {
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA8_REG, 0,
+ SLOT25_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to DA_IN8 from Slot 25 % d",
+ error);
+ return error;
+ }
+
+ /* DA_IN7 to AD_OUT8 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA6_REG, 0,
+ SEL_AD_OUT6_FROM_DAIN8);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to AD_OUT6 from DA_IN8 % d",
+ error);
+ return error;
+ }
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT6_7_REG, 0,
+ SEL_IF7_FROM_AD_OUT6);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to IF7 from AD_OUT6 % d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+
+int ste_audio_io_power_up_fmtx(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal = 0;
+
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "FMTX should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ ste_audio_io_configure_if1(dev);
+
+ if (channel_index & e_CHANNEL_1) {
+ /* data sent to DA7 input of DA filter form IF1 14 slot */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA7_REG,
+ SLOT14_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA_IN7 from Slot 14 % d", error);
+ return error;
+ }
+ /* DA_IN7 to AD_OUT5 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA5_REG,
+ SEL_AD_OUT5_FROM_DAIN7, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to AD_OUT5 from DA_IN7 % d",
+ error);
+ return error;
+ }
+
+ initialVal = HW_REG_READ(AD_ALLOCATION_TO_SLOT16_17_REG);
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT16_17_REG,
+ (initialVal & MASK_QUARTET1)|SEL_IF6_FROM_AD_OUT5);
+ if (0 != error) {
+ dev_err(dev, "Data sent to IF16 from AD_OUT5 % d",
+ error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* data sent to DA8 input of DA filter */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA8_REG,
+ SLOT15_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA_IN8 from Slot 15 % d",
+ error);
+ return error;
+ }
+
+ /* DA_IN8 to AD_OUT6 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA6_REG,
+ SEL_AD_OUT6_FROM_DAIN8, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to AD_OUT6 from DA_IN8 % d",
+ error);
+ return error;
+ }
+
+ initialVal = HW_REG_READ(AD_ALLOCATION_TO_SLOT16_17_REG);
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT16_17_REG,
+ (initialVal & MASK_QUARTET0)|SEL_IF17_FROM_AD_OUT6);
+ if (0 != error) {
+ dev_err(dev, "Data sent to IF17 from AD_OUT6 % d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+
+int ste_audio_io_power_down_fmtx(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "FMTX should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA7_REG, 0,
+ SLOT14_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to DA_IN7 from Slot 14 % d",
+ error);
+ return error;
+ }
+ /* DA_IN7 to AD_OUT8 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA5_REG, 0,
+ SEL_AD_OUT5_FROM_DAIN7);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to AD_OUT5 from DA_IN7 % d",
+ error);
+ return error;
+ }
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT16_17_REG,
+ SEL_IF6_FROM_AD_OUT5);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to IF16 from AD_OUT8 % d",
+ error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* data sent to DA8 input of DA filter */
+ initialVal_AD = HW_REG_READ(SLOT_SELECTION_TO_DA8_REG);
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA8_REG, 0,
+ SLOT15_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to DA_IN8 from Slot 15 % d",
+ error);
+ return error;
+ }
+
+ /* DA_IN7 to AD_OUT8 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA6_REG, 0,
+ SEL_AD_OUT6_FROM_DAIN8);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to AD_OUT6 from DA_IN8 % d",
+ error);
+ return error;
+ }
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT16_17_REG,
+ SEL_IF17_FROM_AD_OUT6);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to IF17 from AD_OUT6 % d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+int ste_audio_io_power_up_bluetooth(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev)
+{
+ int error = 0;
+ if (bluetooth_power_up_count++)
+ return error;
+
+ error = stm_gpio_altfuncenable(GPIO_ALT_MSP_0);
+ if (error == 0) {
+ clk_ptr_msp0 = clk_get_sys("msp0", NULL);
+ if (!IS_ERR(clk_ptr_msp0)) {
+ error = clk_enable(clk_ptr_msp0);
+ return error;
+ } else
+ return -EFAULT;
+ }
+ return error;
+}
+
+int ste_audio_io_power_down_bluetooth(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev)
+{
+ int error = 0;
+ if (--bluetooth_power_up_count)
+ return error;
+ error = stm_gpio_altfuncdisable(GPIO_ALT_MSP_0);
+
+ if (0 == error) {
+ clk_disable(clk_ptr_msp0);
+ clk_put(clk_ptr_msp0);
+ }
+
+ return error;
+}
+
+int dump_acodec_registers(const char *str, struct device *dev)
+{
+ int reg_count = REVISION_REG & 0xff;
+ if (1 == acodec_reg_dump) {
+ u8 i = 0;
+ dev_err(dev, "\n func : %s\n", str);
+ for (i = 0; i <= reg_count; i++)
+ dev_dbg(dev, "block = 0x0D, adr = %x = %x\n",
+ i, HW_REG_READ((AB8500_AUDIO << 8) | i));
+ }
+ str = str; /* keep compiler happy */
+ return 0;
+}
+
+int debug_audioio(int x)
+{
+
+ if (1 == x)
+ acodec_reg_dump = 1;
+ else
+ acodec_reg_dump = 0;
+ return 0;
+}
+
+
+
+
+
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_func.h b/drivers/misc/audio_io_dev/ste_audio_io_func.h
new file mode 100644
index 00000000000..df1b7283eb2
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_func.h
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#ifndef _AUDIOIO_FUNC_H_
+#define _AUDIOIO_FUNC_H_
+
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <mach/ste_audio_io_ioctl.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500.h>
+
+#define AB8500_REV_10 0x10
+#define AB8500_REV_11 0x11
+#define AB8500_REV_20 0x20
+
+#define AB8500_CTRL3_REG 0x00000200
+#define AB8500_SYSULPCLK_CTRL1_REG 0x0000020B
+#define AB8500_GPIO_DIR4_REG 0x00001013
+
+extern struct platform_device *ste_audio_io_device;
+
+int dump_acodec_registers(const char *, struct device *dev);
+int debug_audioio(int x);
+
+#define AB8500_BLOCK_ADDR(address) ((address >> 8) & 0xff)
+#define AB8500_OFFSET_ADDR(address) (address & 0xff)
+
+static inline unsigned char HW_REG_READ(unsigned short reg)
+{
+ unsigned char ret;
+ int err;
+
+ err = abx500_get_register_interruptible(&ste_audio_io_device->dev,
+ AB8500_BLOCK_ADDR(reg),
+ AB8500_OFFSET_ADDR(reg),
+ &ret);
+ if (err < 0)
+ return err;
+ else
+ return ret;
+}
+
+static inline int HW_REG_WRITE(unsigned short reg, unsigned char data)
+{
+ return abx500_set_register_interruptible(&ste_audio_io_device->dev,
+ AB8500_BLOCK_ADDR(reg),
+ AB8500_OFFSET_ADDR(reg),
+ data);
+}
+
+unsigned int ab8500_acodec_modify_write(unsigned int reg, u8 mask_set,
+ u8 mask_clear);
+
+#define HW_ACODEC_MODIFY_WRITE(reg, mask_set, mask_clear)\
+ ab8500_acodec_modify_write(reg, mask_set, mask_clear)
+
+unsigned int ab8500_modify_write(unsigned int reg, u8 mask_set, u8 mask_clear);
+
+int ste_audio_io_power_up_headset(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_headset(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_headset_query(struct device *dev);
+int ste_audio_io_set_headset_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_headset_gain(int *, int *, u16,
+ struct device *dev);
+int ste_audio_io_mute_headset(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_headset(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_headset_state(struct device *dev);
+int ste_audio_io_enable_fade_headset(struct device *dev);
+int ste_audio_io_disable_fade_headset(struct device *dev);
+int ste_audio_io_switch_to_burst_mode_headset(int burst_fifo_switch_frame,
+ struct device *dev);
+int ste_audio_io_switch_to_normal_mode_headset(
+ struct device *dev);
+
+int ste_audio_io_power_up_earpiece(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_earpiece(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_earpiece_query(struct device *dev);
+int ste_audio_io_set_earpiece_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_earpiece_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_earpiece(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_earpiece(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_earpiece_state(struct device *dev);
+int ste_audio_io_enable_fade_earpiece(struct device *dev);
+int ste_audio_io_disable_fade_earpiece(struct device *dev);
+
+int ste_audio_io_power_up_ihf(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_ihf(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_ihf_query(struct device *dev);
+int ste_audio_io_set_ihf_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_ihf_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_ihf(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_ihf(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_ihf_state(struct device *dev);
+int ste_audio_io_enable_fade_ihf(struct device *dev);
+int ste_audio_io_disable_fade_ihf(struct device *dev);
+
+int ste_audio_io_power_up_vibl(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_vibl(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_vibl_query(struct device *dev);
+int ste_audio_io_set_vibl_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_vibl_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_vibl(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_vibl(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_vibl_state(struct device *dev);
+int ste_audio_io_enable_fade_vibl(struct device *dev);
+int ste_audio_io_disable_fade_vibl(struct device *dev);
+
+int ste_audio_io_power_up_vibr(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_vibr(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_vibr_query(struct device *dev);
+int ste_audio_io_set_vibr_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_vibr_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_vibr(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_vibr(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_vibr_state(struct device *dev);
+int ste_audio_io_enable_fade_vibr(struct device *dev);
+int ste_audio_io_disable_fade_vibr(struct device *dev);
+
+int ste_audio_io_power_up_mic1a(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_mic1a(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_mic1a_query(struct device *dev);
+int ste_audio_io_set_mic1a_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear, struct device *dev);
+int ste_audio_io_get_mic1a_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_mic1a(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_mic1a(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_mic1a_state(struct device *dev);
+int ste_audio_io_enable_fade_mic1a(struct device *dev);
+int ste_audio_io_disable_fade_mic1a(struct device *dev);
+
+int ste_audio_io_power_up_mic1b(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_mic1b(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_mic1b_query(struct device *dev);
+int ste_audio_io_set_mic1b_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear, struct device *dev);
+int ste_audio_io_get_mic1b_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_mic1b(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_mic1b(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_mic1b_state(struct device *dev);
+int ste_audio_io_enable_fade_mic1b(struct device *dev);
+int ste_audio_io_disable_fade_mic1b(struct device *dev);
+
+int ste_audio_io_power_up_mic2(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_mic2(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_mic2_query(struct device *dev);
+int ste_audio_io_set_mic2_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_mic2_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_mic2(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_mic2(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_mic2_state(struct device *dev);
+int ste_audio_io_enable_fade_mic2(struct device *dev);
+int ste_audio_io_disable_fade_mic2(struct device *dev);
+
+int ste_audio_io_power_up_lin(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_lin(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_lin_query(struct device *dev);
+int ste_audio_io_set_lin_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_lin_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_lin(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_lin(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_lin_state(struct device *dev);
+int ste_audio_io_enable_fade_lin(struct device *dev);
+int ste_audio_io_disable_fade_lin(struct device *dev);
+
+int ste_audio_io_power_up_dmic12(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_dmic12(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_dmic12_query(struct device *dev);
+int ste_audio_io_set_dmic12_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_dmic12_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_dmic12(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_dmic12(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_dmic12_state(struct device *dev);
+int ste_audio_io_enable_fade_dmic12(struct device *dev);
+int ste_audio_io_disable_fade_dmic12(struct device *dev);
+
+int ste_audio_io_power_up_dmic34(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_dmic34(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_dmic34_query(struct device *dev);
+int ste_audio_io_set_dmic34_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_dmic34_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_dmic34(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_dmic34(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_dmic34_state(struct device *dev);
+int ste_audio_io_enable_fade_dmic34(struct device *dev);
+int ste_audio_io_disable_fade_dmic34(struct device *dev);
+
+int ste_audio_io_power_up_dmic56(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_dmic56(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_dmic56_query(struct device *dev);
+int ste_audio_io_set_dmic56_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_dmic56_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_dmic56(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_dmic56(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_dmic56_state(struct device *dev);
+int ste_audio_io_enable_fade_dmic56(struct device *dev);
+int ste_audio_io_disable_fade_dmic56(struct device *dev);
+
+int ste_audio_io_power_up_fmrx(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_fmrx(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_fmrx_query(struct device *dev);
+int ste_audio_io_set_fmrx_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_fmrx_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_fmrx(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_fmrx(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_fmrx_state(struct device *dev);
+int ste_audio_io_enable_fade_fmrx(struct device *dev);
+int ste_audio_io_disable_fade_fmrx(struct device *dev);
+
+int ste_audio_io_power_up_fmtx(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_fmtx(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_fmtx_query(struct device *dev);
+int ste_audio_io_set_fmtx_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_fmtx_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_fmtx(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_fmtx(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_fmtx_state(struct device *dev);
+int ste_audio_io_enable_fade_fmtx(struct device *dev);
+int ste_audio_io_disable_fade_fmtx(struct device *dev);
+
+int ste_audio_io_power_up_bluetooth(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_bluetooth(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_bluetooth_query(struct device *dev);
+int ste_audio_io_set_bluetooth_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_bluetooth_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_bluetooth(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_bluetooth(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_bluetooth_state(struct device *dev);
+int ste_audio_io_enable_fade_bluetooth(struct device *dev);
+int ste_audio_io_disable_fade_bluetooth(struct device *dev);
+
+
+#endif
+
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.c b/drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.c
new file mode 100644
index 00000000000..17efef53afc
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+
+#include <linux/types.h>
+#include "ste_audio_io_hwctrl_common.h"
+
+/* Number of channels for each transducer */
+const uint transducer_no_of_channels[MAX_NO_TRANSDUCERS] =
+ {
+ 1, /* Earpiece */
+ 2, /* HS */
+ 2, /* IHF */
+ 1, /* VibL */
+ 1, /* VibR */
+ 1, /* Mic1A */
+ 1, /* Mic1B */
+ 1, /* Mic2 */
+ 2, /* LinIn */
+ 2, /* DMIC12 */
+ 2, /* DMIC34 */
+ 2, /* /DMIC56 */
+ 4 /* MultiMic */
+ };
+
+/* Maximum number of gains in each transducer path
+ (all channels of a specific transducer have same max no of gains) */
+const uint transducer_no_of_gains[MAX_NO_TRANSDUCERS] =
+ {
+ 2, /* Ear g3 and g4 */
+ 3, /* HS g3 and g4 and analog */
+ 1, /* IHF g3 */
+ 1, /* VibL g3 */
+ 1, /* VibR g3 */
+ 2, /* Mic1A g1 and analog */
+ 2, /* Mic1A g1 and analog */
+ 2, /* Mic2 g1 and analog */
+ 2, /* LinIn g1 and analog */
+ 1, /* DMIC12 g1 */
+ 1, /* DMIC34 g1 */
+ 1, /* DMIC56 g1 */
+ 1 /* MultiMic g1 */
+ };
+
+/* Maximum number of supported loops for each transducer */
+const uint transducer_max_no_of_supported_loops[MAX_NO_TRANSDUCERS] =
+ {
+ 0, /* Ear g3 and g4 */
+ 0, /* HS g3 and g4 and analog */
+ 0, /* IHF g3 */
+ 0, /* VibL g3 */
+ 0, /* VibR g3 */
+ 1, /* Mic1A SideTone */
+ 1, /* Mic1A SideTone */
+ 1, /* Mic2 SideTone */
+ 0, /* LinIn */
+ 0, /* DMIC12 ANC */
+ 0, /* DMIC34 ANC */
+ 0, /* DMIC56 */
+ 1 /* MultiMic ANC */
+ };
+
+/* Maximum number of gains supported by loops for each transducer */
+const uint transducer_no_of_loop_gains[MAX_NO_TRANSDUCERS] =
+ {
+ 0, /* Ear g3 and g4 */
+ 0, /* HS g3 and g4 and analog */
+ 0, /* IHF g3 */
+ 0, /* VibL g3 */
+ 0, /* VibR g3 */
+ 1, /* Mic1A SideTone g2 */
+ 1, /* Mic1A SideTone g2 */
+ 1, /* Mic2 SideTone g2 */
+ 0, /* LinIn */
+ 0, /* DMIC12 ANC */
+ 0, /* DMIC34 ANC */
+ 0, /* DMIC56 */
+ 1 /* MultiMic ANC */
+ };
+
+/* Supported Loop Indexes for each transducer */
+const uint transducer_no_of_supported_loops[MAX_NO_TRANSDUCERS] =
+ {
+ 0, /* Ear g3 and g4 */
+ 0, /* HS g3 and g4 and analog */
+ 0, /* IHF g3 */
+ 0, /* VibL g3 */
+ 0, /* VibR g3 */
+ 2, /* Mic1A SideTone g2 */
+ 2, /* Mic1A SideTone g2 */
+ 2, /* Mic2 SideTone g2 */
+ 0, /* LinIn */
+ 0, /* DMIC12 ANC */
+ 0, /* DMIC34 ANC */
+ 0, /* DMIC56 */
+ 1 /* MultiMic ANC */
+ };
+
+
+
+struct gain_descriptor_t gain_descriptor[MAX_NO_TRANSDUCERS]\
+ [MAX_NO_CHANNELS][MAX_NO_GAINS] =
+{
+ /* gainIndex=0 1 2
+ EDestinationEar */
+ {{{-63, 0, 1}, {-1, 8, 1}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* EDestinationHS */
+ {{{-63, 0, 1}, {-1, 8, 1}, {-32, 4, 2} } , /* channelIndex=0 */
+ {{-63, 0, 1}, {-1, 8, 1}, {-32, 4, 2} } , /* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } , /* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } , /* channelIndex=3 */
+
+ /* EDestinationIHF */
+ {{{-63, 0, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{-63, 0, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* EDestinationVibL */
+ {{{-63, 0, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* EDestinationVibR */
+ {{{-63, 0, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceMic1A */
+ {{{-32, 31, 1}, {0, 31, 1}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceMic1B */
+ {{{-32, 31, 1}, {0, 31, 1}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceMic2 */
+ {{{-32, 31, 1}, {0, 31, 1}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceLin */
+ {{{-32, 31, 1}, {-10, 20, 2}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{-32, 31, 1}, {-10, 20, 2}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceDMic12 */
+ {{{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceDMic34 */
+ {{{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceDMic56 */
+ {{{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceMultiMic */
+ {{{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,
+ /* channelIndex=2 */
+ {{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } }
+ /* channelIndex=3 */
+
+};
+
+
+const int hs_analog_gain_table[16] = {4, 2, 0, -2, -4, -6, -8, -10,
+ -12, -14, -16, -18, -20, -24, -28, -32};
+
+
+
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.h b/drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.h
new file mode 100644
index 00000000000..cd07f46947f
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#ifndef __AUDIOIO_HWCTRL_COMMON_H__
+#define __AUDIOIO_HWCTRL_COMMON_H__
+
+#include <linux/types.h>
+#include <mach/ste_audio_io_ioctl.h>
+/*
+ * Defines
+ */
+
+
+#define MAX_GAIN 100
+#define MIN_GAIN 0
+#define MAX_NO_CHANNELS 4
+#define MAX_NO_GAINS 3
+#define MAX_NO_LOOPS 1
+#define MAX_NO_LOOP_GAINS 1
+
+struct gain_descriptor_t {
+ int min_gain;
+ int max_gain;
+ uint gain_step;
+};
+
+
+/* Number of channels for each transducer */
+extern const uint transducer_no_of_channels[MAX_NO_TRANSDUCERS];
+
+/*
+ * Maximum number of gains in each transducer path
+ * all channels of a specific transducer have same max no of gains
+ */
+extern const uint transducer_no_of_gains[MAX_NO_TRANSDUCERS];
+
+/* Maximum number of supported loops for each transducer */
+extern const uint transducer_max_no_of_supported_loops[MAX_NO_TRANSDUCERS];
+
+/* Maximum number of gains supported by loops for each transducer */
+extern const uint transducer_no_of_loop_gains[MAX_NO_TRANSDUCERS];
+
+/* Supported Loop Indexes for each transducer */
+extern const uint transducer_no_of_supported_loops[MAX_NO_TRANSDUCERS];
+
+extern const int hs_analog_gain_table[16] ;
+
+extern struct gain_descriptor_t gain_descriptor[MAX_NO_TRANSDUCERS]\
+ [MAX_NO_CHANNELS][MAX_NO_GAINS];
+
+#endif
+
+/* End of audio_io_hwctrl_common.h */
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c
new file mode 100644
index 00000000000..714c6b48731
--- /dev/null
+++ b/drivers/misc/bh1780gli.c
@@ -0,0 +1,273 @@
+/*
+ * bh1780gli.c
+ * ROHM Ambient Light Sensor Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#define BH1780_REG_CONTROL 0x80
+#define BH1780_REG_PARTID 0x8A
+#define BH1780_REG_MANFID 0x8B
+#define BH1780_REG_DLOW 0x8C
+#define BH1780_REG_DHIGH 0x8D
+
+#define BH1780_REVMASK (0xf)
+#define BH1780_POWMASK (0x3)
+#define BH1780_POFF (0x0)
+#define BH1780_PON (0x3)
+
+/* power on settling time in ms */
+#define BH1780_PON_DELAY 2
+
+struct bh1780_data {
+ struct i2c_client *client;
+ int power_state;
+ /* lock for sysfs operations */
+ struct mutex lock;
+};
+
+static int bh1780_write(struct bh1780_data *ddata, u8 reg, u8 val, char *msg)
+{
+ int ret = i2c_smbus_write_byte_data(ddata->client, reg, val);
+ if (ret < 0)
+ dev_err(&ddata->client->dev,
+ "i2c_smbus_write_byte_data failed error %d\
+ Register (%s)\n", ret, msg);
+ return ret;
+}
+
+static int bh1780_read(struct bh1780_data *ddata, u8 reg, char *msg)
+{
+ int ret = i2c_smbus_read_byte_data(ddata->client, reg);
+ if (ret < 0)
+ dev_err(&ddata->client->dev,
+ "i2c_smbus_read_byte_data failed error %d\
+ Register (%s)\n", ret, msg);
+ return ret;
+}
+
+static ssize_t bh1780_show_lux(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct bh1780_data *ddata = platform_get_drvdata(pdev);
+ int lsb, msb;
+
+ lsb = bh1780_read(ddata, BH1780_REG_DLOW, "DLOW");
+ if (lsb < 0)
+ return lsb;
+
+ msb = bh1780_read(ddata, BH1780_REG_DHIGH, "DHIGH");
+ if (msb < 0)
+ return msb;
+
+ return sprintf(buf, "%d\n", (msb << 8) | lsb);
+}
+
+static ssize_t bh1780_show_power_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct bh1780_data *ddata = platform_get_drvdata(pdev);
+ int state;
+
+ state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL");
+ if (state < 0)
+ return state;
+
+ return sprintf(buf, "%d\n", state & BH1780_POWMASK);
+}
+
+static ssize_t bh1780_store_power_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct bh1780_data *ddata = platform_get_drvdata(pdev);
+ unsigned long val;
+ int error;
+
+ error = strict_strtoul(buf, 0, &val);
+ if (error)
+ return error;
+
+ if (val < BH1780_POFF || val > BH1780_PON)
+ return -EINVAL;
+
+ mutex_lock(&ddata->lock);
+
+ error = bh1780_write(ddata, BH1780_REG_CONTROL, val, "CONTROL");
+ if (error < 0) {
+ mutex_unlock(&ddata->lock);
+ return error;
+ }
+
+ msleep(BH1780_PON_DELAY);
+ ddata->power_state = val;
+ mutex_unlock(&ddata->lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(lux, S_IRUGO, bh1780_show_lux, NULL);
+
+static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
+ bh1780_show_power_state, bh1780_store_power_state);
+
+static struct attribute *bh1780_attributes[] = {
+ &dev_attr_power_state.attr,
+ &dev_attr_lux.attr,
+ NULL
+};
+
+static const struct attribute_group bh1780_attr_group = {
+ .attrs = bh1780_attributes,
+};
+
+static int __devinit bh1780_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct bh1780_data *ddata = NULL;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) {
+ ret = -EIO;
+ goto err_op_failed;
+ }
+
+ ddata = kzalloc(sizeof(struct bh1780_data), GFP_KERNEL);
+ if (ddata == NULL) {
+ ret = -ENOMEM;
+ goto err_op_failed;
+ }
+
+ ddata->client = client;
+ i2c_set_clientdata(client, ddata);
+
+ ret = bh1780_read(ddata, BH1780_REG_PARTID, "PART ID");
+ if (ret < 0)
+ goto err_op_failed;
+
+ dev_info(&client->dev, "Ambient Light Sensor, Rev : %d\n",
+ (ret & BH1780_REVMASK));
+
+ mutex_init(&ddata->lock);
+
+ ret = sysfs_create_group(&client->dev.kobj, &bh1780_attr_group);
+ if (ret)
+ goto err_op_failed;
+
+ return 0;
+
+err_op_failed:
+ kfree(ddata);
+ return ret;
+}
+
+static int __devexit bh1780_remove(struct i2c_client *client)
+{
+ struct bh1780_data *ddata;
+
+ ddata = i2c_get_clientdata(client);
+ sysfs_remove_group(&client->dev.kobj, &bh1780_attr_group);
+ i2c_set_clientdata(client, NULL);
+ kfree(ddata);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bh1780_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct bh1780_data *ddata;
+ int state, ret;
+
+ ddata = i2c_get_clientdata(client);
+ state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL");
+ if (state < 0)
+ return state;
+
+ ddata->power_state = state & BH1780_POWMASK;
+
+ ret = bh1780_write(ddata, BH1780_REG_CONTROL, BH1780_POFF,
+ "CONTROL");
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int bh1780_resume(struct i2c_client *client)
+{
+ struct bh1780_data *ddata;
+ int state, ret;
+
+ ddata = i2c_get_clientdata(client);
+ state = ddata->power_state;
+
+ ret = bh1780_write(ddata, BH1780_REG_CONTROL, state,
+ "CONTROL");
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+#else
+#define bh1780_suspend NULL
+#define bh1780_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id bh1780_id[] = {
+ { "bh1780", 0 },
+ { },
+};
+
+static struct i2c_driver bh1780_driver = {
+ .probe = bh1780_probe,
+ .remove = bh1780_remove,
+ .id_table = bh1780_id,
+ .suspend = bh1780_suspend,
+ .resume = bh1780_resume,
+ .driver = {
+ .name = "bh1780"
+ },
+};
+
+static int __init bh1780_init(void)
+{
+ return i2c_add_driver(&bh1780_driver);
+}
+
+static void __exit bh1780_exit(void)
+{
+ i2c_del_driver(&bh1780_driver);
+}
+
+module_init(bh1780_init)
+module_exit(bh1780_exit)
+
+MODULE_DESCRIPTION("BH1780GLI Ambient Light Sensor Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>");
diff --git a/drivers/misc/hsi/Kconfig b/drivers/misc/hsi/Kconfig
new file mode 100644
index 00000000000..5807cc65085
--- /dev/null
+++ b/drivers/misc/hsi/Kconfig
@@ -0,0 +1,28 @@
+#
+# HSI HW kernel configuration
+#
+#
+
+config HSI
+ boolean "HSI support"
+ depends on ARCH_U8500
+ default n
+
+config U8500_HSI
+ tristate "STN8500 HSI hardware driver"
+ depends on ARCH_U8500 && HSI
+ default y
+ ---help---
+ If you say Y here, you will enable the STN8500 HSI (Rx and Tx) hardware driver.
+
+ If unsure, say N.
+
+config HSIDEV
+ tristate "HSI loopback protocol driver"
+ depends on U8500_HSI
+ default n
+ ---help---
+ If you say Y here, you will enable the test protocol driver used for testing HSI Rx and Tx controllers
+
+ If unsure, say N.
+
diff --git a/drivers/misc/hsi/Makefile b/drivers/misc/hsi/Makefile
new file mode 100644
index 00000000000..aef2f5e83c4
--- /dev/null
+++ b/drivers/misc/hsi/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for HSI drivers
+#
+stmmod_hsi-objs := hsi-stm.o hsi-algo-stm.o
+
+obj-$(CONFIG_HSI) += hsi.o
+obj-$(CONFIG_U8500_HSI) += stmmod_hsi.o
+obj-$(CONFIG_HSIDEV) += hsidev.o
diff --git a/drivers/misc/hsi/hsi-algo-stm.c b/drivers/misc/hsi/hsi-algo-stm.c
new file mode 100644
index 00000000000..ef26fb3f867
--- /dev/null
+++ b/drivers/misc/hsi/hsi-algo-stm.c
@@ -0,0 +1,1471 @@
+/*
+ * Copyright (C) 2007 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/dmaengine.h>
+#include <linux/hsi.h>
+#include <mach/hsi-stm.h>
+#include <mach/debug.h>
+
+/**
+ * hsi_open - open a hsi device channel.
+ * @dev: Reference to the hsi device channel to be openned.
+ *
+ * Returns 0 on success, -EINVAL on bad parameters, -EBUSY if is already opened.
+ */
+static int stm_hsi_open(struct hsi_device *dev)
+{
+ struct hsi_channel *ch;
+ struct hsi_controller *hsi_ctrlr;
+ void __iomem *hsi_base;
+
+ if (!dev || !dev->ch) {
+ stm_dbg(DBG_ST.hsi, "Wrong HSI device %p\n", dev);
+ return -EINVAL;
+ }
+
+ ch = dev->ch;
+ /*if (!ch->ops.read_done && !ch->ops.write_done) {
+ stm_dbg(DBG_ST.hsi,"Trying to open with no callbacks registered\n");
+ return -EINVAL;
+ } */
+ hsi_ctrlr = dev->ctrlr;
+ spin_lock_bh(&ch->hsi_ch_lock);
+ if (ch->flags & HSI_CH_OPEN) {
+ stm_dbg(DBG_ST.hsi,
+ " Controller %d Channel %d already OPENED\n", dev->cid,
+ dev->chid);
+ spin_unlock_bh(&ch->hsi_ch_lock);
+ return -EBUSY;
+ }
+ clk_enable(hsi_ctrlr->clk);
+ ch->flags |= HSI_CH_OPEN;
+ hsi_base = hsi_ctrlr->regbase;
+ if (hsi_ctrlr->dev_type == 0x0) {
+ /** HSI transmit controller
+ * flush the transmit buffer */
+ writel((readl(hsi_base + HSI_TX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),
+ hsi_base + HSI_TX_BUFSTATE);
+ } else {
+ writel((readl(hsi_base + HSI_RX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),
+ hsi_base + HSI_RX_BUFSTATE);
+ }
+ spin_unlock_bh(&ch->hsi_ch_lock);
+
+ return 0;
+}
+
+/**
+ * hsi_write - write data into the hsi device channel
+ * @dev: reference to the hsi device channel to write into.
+ * @data: pointer to a 32-bit word data to be written.
+ * @datawidth: in bits (16bit or 32bit or ....)
+ * @count: total number of bytes to be written.
+ *
+ * Return 0 on sucess, a negative value on failure.
+ * A success values only indicates that the request has been accepted.
+ * Transfer is only completed when the write_done callback is called.
+ *
+ */
+static int stm_hsi_write(struct hsi_device *dev, struct hsi_data *xfer)
+{
+ struct hsi_channel *ch;
+ int err = -EINVAL;
+
+ if (dev->cid != 0x0) {
+ stm_dbg(DBG_ST.hsi, "HSI Controller not enabled for write\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(!dev || !dev->ch || !xfer->data || (xfer->count <= 0))) {
+ stm_dbg(DBG_ST.hsi, "Wrong paramenters "
+ "hsi_device %p data %p count %d", dev, xfer->data,
+ xfer->count);
+ return -EINVAL;
+ }
+
+ if (unlikely(!(dev->ch->flags & HSI_CH_OPEN))) {
+ stm_dbg(DBG_ST.hsi, "HSI device NOT open\n");
+ return -EINVAL;
+ }
+
+ ch = dev->ch;
+ spin_lock_bh(&ch->hsi_ch_lock);
+ ch->write_data = *xfer;
+
+ if (ch->datawidth <= 8) {
+ ch->n_bytes = 1;
+ ch->num_xfer_perintr = ch->watermark * 4;
+ ch->ops.write = hsi_u8_writer;
+ } else if (ch->datawidth <= 16) {
+ ch->n_bytes = 2;
+ ch->num_xfer_perintr = ch->watermark * 2;
+ ch->ops.write = hsi_u16_writer;
+ } else {
+ ch->n_bytes = 4;
+ ch->num_xfer_perintr = ch->watermark * 1;
+ ch->ops.write = hsi_u32_writer;
+ }
+
+ ch->num_xfer_perintr = ch->watermark;
+
+/**
+ * ###Old method of setting modes###
+ * if(dev->curr_mode == HSI_INTERRUPT_MODE)
+ *
+ * err = hsi_write_interrupt_mode(ch);
+ * else if(dev->curr_mode == HSI_DMA_MODE)
+ * err = hsi_write_dma_mode(ch);
+ * else {
+ * stm_dbg(DBG_ST.hsi,"HSI POLLING MODE NOT implemented \n");
+ * err = -EINVAL;
+ * }
+**/
+
+ /**
+ * We need to optimize on DMA setup and teardown overhead
+ * when the number of bytes to be transferred is less than
+ * a minimum value (currently 4). We configure for interrupt
+ * mode in this case.
+ **/
+
+ if (dev->curr_mode == HSI_INTERRUPT_MODE)
+ err = hsi_write_interrupt_mode(ch);
+ else if (dev->curr_mode == HSI_DMA_MODE) {
+ if (xfer->count <= 4)
+ err = hsi_write_interrupt_mode(ch);
+ else
+ err = hsi_write_dma_mode(ch);
+ }
+
+ if (unlikely(err < 0)) {
+ ch->write_data.data = NULL;
+ ch->write_data.count = 0;
+ }
+ spin_unlock_bh(&ch->hsi_ch_lock);
+
+ return err;
+
+}
+
+/**
+ * stm_hsi_read - read data from the hsi device channel
+ * @dev: hsi device channel reference to read data from.
+ * @data: pointer to a 32-bit word data to store the data.
+ * @count: number of 32-bit word to be stored.
+ *
+ * Return 0 on sucess, a negative value on failure.
+ * A success values only indicates that the request has been accepted.
+ * Data is only available in the buffer when the read_done callback is called.
+ *
+ */
+static int stm_hsi_read(struct hsi_device *dev, struct hsi_data *xfer)
+{
+ struct hsi_channel *ch;
+ int err = 0;
+ /** for POLLING MODE **
+ unsigned int loop=0;
+ struct hsi_controller *hsi_ctrlr=NULL ;
+ volatile void __iomem *hsi_base=NULL ;
+ **/
+
+ if (dev->cid != 0x1) {
+ stm_dbg(DBG_ST.hsi, "HSI Controller not enabled for read\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(!dev || !dev->ch || !xfer->data || (xfer->count <= 0))) {
+ stm_dbg(DBG_ST.hsi, "Wrong paramenters "
+ "hsi_device %p data %p count %d", dev, xfer->data,
+ xfer->count);
+ return -EINVAL;
+ }
+ if (unlikely(!(dev->ch->flags & HSI_CH_OPEN))) {
+ stm_dbg(DBG_ST.hsi, "HSI device NOT open\n");
+ return -EINVAL;
+ }
+
+ ch = dev->ch;
+ spin_lock_bh(&ch->hsi_ch_lock);
+ ch->read_data = *xfer;
+
+ if (ch->datawidth <= 8) {
+ ch->n_bytes = 1;
+ ch->num_xfer_perintr = ch->watermark * 4;
+ ch->ops.read = hsi_u8_reader;
+ } else if (ch->datawidth <= 16) {
+ ch->n_bytes = 2;
+ ch->num_xfer_perintr = ch->watermark * 2;
+ ch->ops.read = hsi_u16_reader;
+ } else {
+ ch->n_bytes = 4;
+ ch->num_xfer_perintr = ch->watermark * 1;
+ ch->ops.read = hsi_u32_reader;
+ }
+
+ /**
+ * We need to optimize on DMA setup and teardown overhead
+ * when the number of bytes to be transferred is less than
+ * a minimum value (currently 4). We configure for interrupt
+ * mode in this case.
+ **/
+
+ if (dev->curr_mode == HSI_INTERRUPT_MODE)
+ err = hsi_read_interrupt_mode(ch);
+ else if (dev->curr_mode == HSI_DMA_MODE) {
+ if (xfer->count <= 4)
+ err = hsi_read_interrupt_mode(ch);
+ else
+ err = hsi_read_dma_mode(ch);
+ }
+/**
+*
+* if(dev->curr_mode == HSI_INTERRUPT_MODE)
+* err = hsi_read_interrupt_mode(ch);
+* else if(dev->curr_mode == HSI_DMA_MODE)
+* err = hsi_read_dma_mode(ch);
+* else {
+* ** POLLING mode start**
+* hsi_ctrlr=ch->ctrlr;
+* hsi_base = hsi_ctrlr->regbase;
+* stm_dbg(DBG_ST.hsi,"hsi_read : channel %d regbase 0x%p\n",
+* ch->channel_number,hsi_base);
+* while (!((readl(hsi_base+HSI_RX_BUFSTATE)) &
+* (1<<ch->channel_number) && (loop < 50000)) {
+* loop++;
+* mdelay(1);
+* }
+*
+* if (loop >=50000)
+* stm_dbg(DBG_ST.hsi,"HSI_READ:NO DATA VIA POLL\n");
+* else
+* stm_dbg(DBG_ST.hsi,"HSI_READ:RECEIVED DATA POLL\n");
+* ** POLLING mode end**
+*
+* }
+**/
+ if (unlikely(err < 0)) {
+ ch->read_data.data = NULL;
+ ch->read_data.count = 0;
+ }
+ spin_unlock_bh(&ch->hsi_ch_lock);
+
+ return err;
+}
+
+static void __hsi_write_cancel(struct hsi_channel *ch, int mode)
+{
+ if (mode == HSI_INTERRUPT_MODE)
+ hsi_cancel_write_interrupt_mode(ch);
+ else if (mode == HSI_DMA_MODE)
+ hsi_cancel_write_dma_mode(ch);
+ else
+ stm_dbg(DBG_ST.hsi, "HSI write cancel Incorrect Mode \n");
+ /*FIXME: No Polling Mode Yet */
+}
+
+/**
+ * hsi_write_cancel - Cancel pending write request.
+ * @dev: hsi device channel where to cancel the pending write.
+ *
+ * write_done() callback will not be called after sucess of this function.
+ * This call closes the channel also.
+ */
+static void stm_hsi_write_cancel(struct hsi_device *dev)
+{
+ struct hsi_channel *ch;
+
+ if (dev->cid != 0x0) {
+ stm_dbg(DBG_ST.hsi, "HSI Controller not enabled for write\n");
+ return;
+ }
+
+ if (unlikely(!dev || !dev->ch)) {
+ stm_dbg(DBG_ST.hsi, "Wrong HSI device %p\n", dev);
+ return;
+ }
+ if (unlikely(!(dev->ch->flags & HSI_CH_OPEN))) {
+ stm_dbg(DBG_ST.hsi, "HSI device NOT open\n");
+ return;
+ }
+
+ ch = dev->ch;
+ spin_lock_bh(&ch->hsi_ch_lock);
+ __hsi_write_cancel(ch, dev->curr_mode);
+ dev->ch->flags &= ~HSI_CH_OPEN;
+ spin_unlock_bh(&ch->hsi_ch_lock);
+}
+
+static void __hsi_read_cancel(struct hsi_channel *ch, int mode)
+{
+ if (mode == HSI_INTERRUPT_MODE)
+ hsi_cancel_read_interrupt_mode(ch);
+ else if (mode == HSI_DMA_MODE)
+ hsi_cancel_read_dma_mode(ch);
+ else
+ stm_dbg(DBG_ST.hsi, "HSI read cancel Incorrect Mode \n");
+ /*FIXME: No Polling Mode Yet */
+}
+
+/**
+ * hsi_read_cancel - Cancel pending read request.
+ * @dev: hsi device channel where to cancel the pending read.
+ *
+ * read_done() callback will not be called after sucess of this function.
+ */
+static void stm_hsi_read_cancel(struct hsi_device *dev)
+{
+ struct hsi_channel *ch;
+
+ if (dev->cid != 0x1) {
+ stm_dbg(DBG_ST.hsi, "HSI Controller not enabled for read\n");
+ return;
+ }
+
+ if (unlikely(!dev || !dev->ch)) {
+ stm_dbg(DBG_ST.hsi, "Wrong HSI device %p\n", dev);
+ return;
+ }
+
+ if (unlikely(!(dev->ch->flags & HSI_CH_OPEN))) {
+ stm_dbg(DBG_ST.hsi, "HSI device NOT open\n");
+ return;
+ }
+
+ ch = dev->ch;
+ spin_lock_bh(&ch->hsi_ch_lock);
+ __hsi_read_cancel(dev->ch, dev->curr_mode);
+ dev->ch->flags &= ~HSI_CH_OPEN;
+ spin_unlock_bh(&ch->hsi_ch_lock);
+}
+
+/**
+ * hsi_close - close given hsi device channel
+ * @dev: reference to hsi device channel.
+ */
+static void stm_hsi_close(struct hsi_device *dev)
+{
+ struct hsi_channel *ch;
+ void __iomem *hsi_base;
+ struct hsi_controller *hsi_ctrlr;
+
+ if (!dev || !dev->ch) {
+ stm_dbg(DBG_ST.hsi, "Trying to close wrong HSI device %p\n",
+ dev);
+ return;
+ }
+
+ ch = dev->ch;
+ hsi_ctrlr = dev->ctrlr;
+ hsi_base = hsi_ctrlr->regbase;
+
+ spin_lock_bh(&ch->hsi_ch_lock);
+
+ if (ch->flags & HSI_CH_OPEN) {
+ dev->ch->flags &= ~HSI_CH_OPEN;
+ if (hsi_ctrlr->dev_type == 0x0) {
+ /** HSIT */
+ /** flush the transmit channel buffers */
+ writel((readl(hsi_base + HSI_TX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),
+ hsi_base + HSI_TX_BUFSTATE);
+ } else {
+ /** flush the receive channel buffers */
+ writel((readl(hsi_base + HSI_RX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),
+ hsi_base + HSI_RX_BUFSTATE);
+ }
+
+ clk_disable(hsi_ctrlr->clk);
+ }
+
+ spin_unlock_bh(&ch->hsi_ch_lock);
+}
+
+/**
+ * hsi_dev_set_cb - register read_done() and write_done() callbacks.
+ * @dev: reference to hsi device channel where callbacks are associated.
+ * @r_cb: callback to signal read transfer completed.
+ * @w_cb: callback to signal write transfer completed.
+ */
+static void stm_hsi_dev_set_cb(struct hsi_device *dev,
+ void (*r_cb) (struct hsi_device *dev)
+ , void (*w_cb) (struct hsi_device *dev))
+{
+ struct hsi_channel *ch;
+
+ if (unlikely(!dev || !dev->ch)) {
+ stm_dbg(DBG_ST.hsi, "Wrong HSI device %p\n", dev);
+ return;
+ }
+
+ ch = dev->ch;
+ spin_lock_bh(&ch->hsi_ch_lock);
+ dev->ch->ops.read_done = r_cb;
+ dev->ch->ops.write_done = w_cb;
+ spin_unlock_bh(&ch->hsi_ch_lock);
+}
+
+/**
+ * hsi_ioctl - HSI I/O control
+ * @dev: hsi device channel reference to apply the I/O control
+ * or port associated to it)
+ * @command: HSI I/O control command
+ * @arg: parameter associated to the control command.NULL if no parameter.
+ *
+ * Return 0 on sucess, a negative value on failure.
+**/
+static int stm_hsi_ioctl(struct hsi_device *dev, unsigned int command,
+ void *arg)
+{
+ struct hsi_channel *ch;
+ struct hsi_controller *hsi_ctrlr;
+ void __iomem *hsi_base;
+ int err = 0;
+
+ if (!dev || !dev->ch) {
+ stm_dbg(DBG_ST.hsi, "Wrong HSI device %p\n", dev);
+ return -EINVAL;
+ }
+
+ ch = dev->ch;
+ hsi_ctrlr = ch->ctrlr;
+
+ if (unlikely(!(dev->ch->flags & HSI_CH_OPEN))) {
+ stm_dbg(DBG_ST.hsi, "HSI device NOT open\n");
+ return -EINVAL;
+ }
+
+ spin_lock_bh(&ch->hsi_ch_lock);
+
+ hsi_base = hsi_ctrlr->regbase;
+
+ switch (command) {
+ case HSI_IOC_SET_WATERMARK:
+ /** TODO: check span definition. Manual says (span-1)
+ * is actual span value and the watermark should be less
+ * than span (span -1)
+ **/
+ if (*(u8 *) arg > (ch->span - 2)) {
+ stm_dbg(DBG_ST.hsi,
+ "HSI IOCTL: illegal watermark value > span\n");
+ spin_unlock_bh(&ch->hsi_ch_lock);
+ return -EINVAL;
+ }
+ ch->watermark = *(u8 *) arg;
+ if (hsi_ctrlr->dev_type == 0x0) { /** HSI transmit controller*/
+ writel((0x1f & ((*(u8 *) arg) - 1)), (hsi_base +
+ HSI_TX_WATERMARKX
+ +
+ (0x4 *
+ ch->
+ channel_number)));
+ } else {
+ writel((0x1f & ((*(u8 *) arg) - 1)), (hsi_base +
+ HSI_RX_WATERMARKX
+ +
+ (0x4 *
+ ch->
+ channel_number)));
+ }
+ break;
+ case HSI_IOC_GET_WATERMARK:
+ if (hsi_ctrlr->dev_type == 0x0) {
+ /** HSI transmit controller*/
+ /** add 1 to the value read from register
+ * for actual watermark
+ **/
+ *((u8 *) arg) =
+ (0x1F &
+ (readl
+ (hsi_base + HSI_TX_WATERMARKX +
+ (0x4 * ch->channel_number)))) + 1;
+ } else {
+ *((u8 *) arg) =
+ (0x1F &
+ (readl
+ (hsi_base + HSI_RX_WATERMARKX +
+ (0x4 * ch->channel_number)))) + 1;
+ }
+ break;
+ case HSI_IOC_GET_MODE:
+ *((u8 *) arg) = dev->curr_mode;
+ break;
+ case HSI_IOC_SET_MODE:
+ dev->curr_mode = *((u8 *) arg);
+ break;
+ case HSI_IOC_SEND_BREAK:
+ writel(0x1, hsi_base + HSI_TX_BREAK);
+ break;
+ case HSI_IOC_SET_FRAMELEN:
+ if ((*(u8 *) arg) > HSI_MAX_FRAMELEN) {
+ stm_dbg(DBG_ST.hsi,
+ "HSI IOCTL: Illegal framelen setting \n");
+ spin_unlock_bh(&ch->hsi_ch_lock);
+ return -EINVAL;
+ }
+ if (hsi_ctrlr->dev_type == 0x0) {
+ /** HSI transmit controller*/
+ writel((0x1f & ((*(u8 *) arg) - 1)), (hsi_base +
+ HSI_TX_FRAMELENX +
+ (0x4 *
+ ch->
+ channel_number)));
+ } else {
+ writel((0x1f & ((*(u8 *) arg) - 1)), (hsi_base +
+ HSI_RX_FRAMELENX +
+ (0x4 *
+ ch->
+ channel_number)));
+ }
+ dev->ch->datawidth = (*(u8 *) arg);
+ break;
+ case HSI_IOC_GET_FRAMELEN:
+ if (hsi_ctrlr->dev_type == 0x0) {
+ /** HSI transmit controller*/
+ /** add 1 to the value read from register
+ * for actual framelen */
+ *((u8 *) arg) =
+ (0x1F &
+ (readl
+ (hsi_base + HSI_TX_FRAMELENX +
+ (0x4 * ch->channel_number)))) + 1;
+ } else {
+ *((u8 *) arg) =
+ (0x1F &
+ (readl
+ (hsi_base + HSI_RX_FRAMELENX +
+ (0x4 * ch->channel_number)))) + 1;
+ }
+ break;
+
+ case HSI_IOC_SET_THRESHOLD:
+ writel((0x3f & (*(u32 *) arg)), (hsi_base + HSI_RX_THRESHOLD));
+ break;
+
+ default:
+ err = -ENOIOCTLCMD;
+ break;
+ }
+
+ spin_unlock_bh(&ch->hsi_ch_lock);
+ return err;
+}
+
+/* NOTE: Function called in interrupt context */
+static int stm_hsi_exception_handler(struct device_driver *drv, void *ex_event)
+{
+ struct hsi_ctrlr_excep *event = (struct hsi_ctrlr_excep *)ex_event;
+ struct hsi_device_driver *hsi_drv = to_hsi_device_driver(drv);
+ u8 id = 0;
+
+ if ((hsi_drv->excep_event) &&
+ (test_bit
+ (event->event,
+ (const unsigned long *)&hsi_drv->excep_mask))
+ &&
+ (test_bit
+ (event->ctrlr->dev_type,
+ (const unsigned long *)&hsi_drv->ctrl_mask))
+ && (hsi_drv->ch_mask != 0)) {
+ if (event->priv) {
+ /** channel overrun - we pass the channel id
+ * as private data */
+ id = *(u8 *) event->priv;
+ if (test_bit
+ (id,
+ (const unsigned long *)&hsi_drv->ch_mask))
+ /** callback for channel overrun */
+ (*hsi_drv->excep_event) (event->ctrlr->dev_type,
+ event->event, &id);
+ } else
+ /** callback for everything except
+ * channel overrrun */
+ (*hsi_drv->excep_event) (event->ctrlr->dev_type,
+ event->event, event->priv);
+ }
+
+ return 0;
+}
+
+struct hsi_algorithm hsi_algo = {
+ .open = stm_hsi_open,
+ .read = stm_hsi_read,
+ .write = stm_hsi_write,
+ .ioctl = stm_hsi_ioctl,
+ .cancel_read = stm_hsi_read_cancel,
+ .cancel_write = stm_hsi_write_cancel,
+ .set_cb = stm_hsi_dev_set_cb,
+ .close = stm_hsi_close,
+ .exception_handler = stm_hsi_exception_handler,
+};
+
+static void reset_ch_read(struct hsi_channel *ch)
+{
+ ch->read_data.data = NULL;
+ ch->read_data.dma_addr = (dma_addr_t) NULL;
+ ch->read_data.count = 0;
+}
+
+static void reset_ch_write(struct hsi_channel *ch)
+{
+ ch->write_data.data = NULL;
+ ch->write_data.dma_addr = (dma_addr_t) NULL;
+ ch->write_data.count = 0;
+}
+
+int hsi_write_interrupt_mode(struct hsi_channel *ch)
+{
+ struct hsi_controller *hsi_ctrlr;
+ void __iomem *hsi_base;
+ unsigned int wmark_intrmask;
+
+ stm_dbg(DBG_ST.hsi, "Write int mode\n");
+ hsi_ctrlr = ch->ctrlr;
+ hsi_base = hsi_ctrlr->regbase;
+
+ /** watermark fixed to count-1 entries */
+ /* writel((0x1f & ((ch->write_data.count)-1)),(hsi_base +
+ * HSI_TX_WATERMARKX + (0x4*ch->channel_number))); */
+ /** enable the corresponding channel intr mask */
+ wmark_intrmask = (0xff) & readl(hsi_base + HSI_TX_WATERMARKIM);
+ writel((wmark_intrmask | (1 << ch->channel_number)),
+ hsi_base + HSI_TX_WATERMARKIM);
+
+ return 0;
+}
+
+int hsi_read_interrupt_mode(struct hsi_channel *ch)
+{
+ struct hsi_controller *hsi_ctrlr;
+ void __iomem *hsi_base;
+ unsigned int wmark_intrmask;
+
+ stm_dbg(DBG_ST.hsi, "Read int mode\n");
+ hsi_ctrlr = ch->ctrlr;
+ hsi_base = hsi_ctrlr->regbase;
+
+ /** watermark fixed to count-1 entries -
+ * not required as watermark is fixed
+ * writel((0x1f & ((ch->read_data.count)-1)),(hsi_base+
+ * HSI_RX_WATERMARKX + (0x4*ch->channel_number))); */
+
+ /** enable the corresponding channel intr mask */
+ wmark_intrmask = (0xff) & readl(hsi_base + HSI_RX_WATERMARKIM);
+ writel((wmark_intrmask | (1 << ch->channel_number)),
+ hsi_base + HSI_RX_WATERMARKIM);
+
+ return 0;
+}
+
+void hsi_cancel_write_interrupt_mode(struct hsi_channel *ch)
+{
+
+ struct hsi_controller *hsi_ctrlr;
+ void __iomem *hsi_base;
+ unsigned int wmark_intrmask;
+
+ hsi_ctrlr = ch->ctrlr;
+ hsi_base = hsi_ctrlr->regbase;
+ /** reset watermark to high number,say 4 */
+ /*writel((0x1f & 0x3),(hsi_base+ HSI_TX_WATERMARKX +
+ * (0x4*ch->channel_number)));
+ */
+ /** disable the corresponding channel intr mask */
+ wmark_intrmask = (0xff) & readl(hsi_base + HSI_TX_WATERMARKIM);
+ writel((wmark_intrmask & ~(1 << ch->channel_number)),
+ hsi_base + HSI_TX_WATERMARKIM);
+ /** flush the transmit channel buffers */
+ writel((readl(hsi_base + HSI_TX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),
+ hsi_base + HSI_TX_BUFSTATE);
+
+ reset_ch_write(ch);
+
+}
+
+void hsi_cancel_read_interrupt_mode(struct hsi_channel *ch)
+{
+ struct hsi_controller *hsi_ctrlr;
+ void __iomem *hsi_base;
+ unsigned int wmark_intrmask;
+
+ hsi_ctrlr = ch->ctrlr;
+ hsi_base = hsi_ctrlr->regbase;
+ /** reset watermark to high number,say 4 */
+ /* writel((0x1f & 0x3),(hsi_base+ HSI_RX_WATERMARKX
+ * + (0x4*ch->channel_number)));
+ */
+
+ /** disable the corresponding channel intr mask */
+ wmark_intrmask = (0xff) & readl(hsi_base + HSI_RX_WATERMARKIM);
+ writel((wmark_intrmask & ~(1 << ch->channel_number)),
+ hsi_base + HSI_RX_WATERMARKIM);
+ /** flush the receive channel buffers */
+ writel((readl(hsi_base + HSI_RX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),
+ hsi_base + HSI_RX_BUFSTATE);
+ reset_ch_read(ch);
+}
+
+/**
+ * hsi_u8_writer - Write FIFO data in Data register as a 8 Bit Data
+ *
+ * This function writes data in Tx FIFO till it is not full
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary write ptr tx in drv_data which maintains
+ * current write position in transfer buffer
+ */
+void hsi_u8_writer(struct hsi_channel *ch)
+{
+ struct hsi_controller *hsi_ctrlr = ch->ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ int i = 0;
+
+ spin_lock(&ch->hsi_ch_lock);
+ if (ch->write_data.data) {
+ /*while ((i< (ch->num_xfer_perintr)) &&
+ * (ch->write_data.count)){ */
+ while (!
+ ((readl(hsi_base + HSI_TX_BUFSTATE)) &
+ (1 << ch->channel_number)) && (ch->write_data.count)) {
+ writel(*(u8 *) (ch->write_data.data),
+ hsi_base + HSI_TX_BUFFERX +
+ (4 * ch->channel_number));
+ ch->write_data.data = ch->write_data.data + ch->n_bytes;
+ ch->write_data.count =
+ ch->write_data.count - ch->n_bytes;
+ i++;
+ }
+ if (ch->write_data.count == 0x0)
+ reset_ch_write(ch);
+ }
+ spin_unlock(&ch->hsi_ch_lock);
+}
+
+/**
+ * hsi_u8_reader - Read FIFO data in Data register as a 8 Bit Data
+ *
+ * This function reads data in Rx FIFO till it is not empty
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary Read ptr rx in drv_data which maintains
+ * current read position in transfer buffer
+ */
+void hsi_u8_reader(struct hsi_channel *ch)
+{
+ struct hsi_controller *hsi_ctrlr = ch->ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ int i = 0;
+
+ spin_lock(&ch->hsi_ch_lock);
+ if (ch->read_data.data) {
+ /*while ((i< (ch->num_xfer_perintr)) &&
+ * (ch->read_data.count)){ */
+ while (((readl(hsi_base + HSI_RX_BUFSTATE)) &
+ (1 << ch->channel_number)) && (ch->read_data.count)) {
+ *(u8 *) (ch->read_data.data) =
+ readl(hsi_base + HSI_RX_BUFFERX +
+ (4 * ch->channel_number));
+ /* stm_dbg(DBG_ST.hsi,"HSI RX: data 0x%x arrived \n",
+ * *(u8 *)(ch->read_data.data));
+ **/
+ ch->read_data.data = ch->read_data.data + ch->n_bytes;
+ ch->read_data.count = ch->read_data.count - ch->n_bytes;
+ i++;
+ }
+ if (ch->read_data.count == 0x0)
+ reset_ch_read(ch);
+ }
+ spin_unlock(&ch->hsi_ch_lock);
+}
+
+/**
+ * hsi_u16_writer - Write FIFO data in Data register as a 16 Bit Data
+ *
+ * This function writes data in Tx FIFO till it is not full
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary write ptr tx in drv_data which maintains
+ * current write position in transfer buffer
+ */
+void hsi_u16_writer(struct hsi_channel *ch)
+{
+ struct hsi_controller *hsi_ctrlr = ch->ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ int i = 0;
+
+ spin_lock(&ch->hsi_ch_lock);
+ if (ch->write_data.data) {
+ /*while ((i< (ch->num_xfer_perintr))
+ * && (ch->write_data.count)){ */
+ while (!
+ ((readl(hsi_base + HSI_TX_BUFSTATE)) &
+ (1 << ch->channel_number)) && (ch->write_data.count)) {
+ writel(*(u16 *) (ch->write_data.data),
+ hsi_base + HSI_TX_BUFFERX +
+ (4 * ch->channel_number));
+ ch->write_data.data = ch->write_data.data + ch->n_bytes;
+ ch->write_data.count =
+ ch->write_data.count - ch->n_bytes;
+ i++;
+ }
+ if (ch->write_data.count == 0x0)
+ reset_ch_write(ch);
+ }
+ spin_unlock(&ch->hsi_ch_lock);
+}
+
+/**
+ * hsi_u16_reader - Read FIFO data in Data register as a 16 Bit Data
+ *
+ * This function reads data in Rx FIFO till it is not empty
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary Read ptr rx in drv_data which maintains
+ * current read position in transfer buffer
+ */
+void hsi_u16_reader(struct hsi_channel *ch)
+{
+ struct hsi_controller *hsi_ctrlr = ch->ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ int i = 0;
+
+ spin_lock(&ch->hsi_ch_lock);
+ if (ch->read_data.data) {
+ /*while ((i< (ch->num_xfer_perintr)) &&
+ * (ch->read_data.count)) { */
+ while (((readl(hsi_base + HSI_RX_BUFSTATE)) &
+ (1 << ch->channel_number)) && (ch->read_data.count)) {
+ *(u16 *) (ch->read_data.data) =
+ readl(hsi_base + HSI_RX_BUFFERX +
+ (4 * ch->channel_number));
+ /** stm_dbg(DBG_ST.hsi,"HSI RX: data 0x%x arrived \n",
+ * *(u16 *)(ch->read_data.data));
+ **/
+ ch->read_data.data = ch->read_data.data + ch->n_bytes;
+ ch->read_data.count = ch->read_data.count - ch->n_bytes;
+ i++;
+ }
+ if (ch->read_data.count == 0x0)
+ reset_ch_read(ch);
+ }
+ spin_unlock(&ch->hsi_ch_lock);
+}
+
+/**
+ * hsi_u32_writer - Write FIFO data in Data register as a 32 Bit Data
+ *
+ * This function writes data in Tx FIFO till it is not full
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary write ptr tx in drv_data which maintains
+ * current write position in transfer buffer
+ */
+void hsi_u32_writer(struct hsi_channel *ch)
+{
+ struct hsi_controller *hsi_ctrlr = ch->ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ int i = 0;
+
+ spin_lock(&ch->hsi_ch_lock);
+ if (ch->write_data.data) {
+ /*while (!((readl(hsi_base+HSI_TX_BUFSTATE)) &
+ * (1<<ch->channel_number))
+ * && (ch->write_data.count)) {
+ */
+ while ((i < (ch->num_xfer_perintr)) && (ch->write_data.count)) {
+ writel(*(u32 *) (ch->write_data.data),
+ hsi_base + HSI_TX_BUFFERX +
+ (4 * ch->channel_number));
+ ch->write_data.data = ch->write_data.data + ch->n_bytes;
+ ch->write_data.count =
+ ch->write_data.count - ch->n_bytes;
+ i++;
+ }
+ if (ch->write_data.count == 0x0)
+ reset_ch_write(ch);
+ }
+ spin_unlock(&ch->hsi_ch_lock);
+}
+
+/**
+ * hsi_u32_reader - Read FIFO data in Data register as a 32 Bit Data
+ *
+ * This function reads data in Rx FIFO till it is not empty
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary Read ptr rx in drv_data which maintains
+ * current read position in transfer buffer
+ */
+void hsi_u32_reader(struct hsi_channel *ch)
+{
+ struct hsi_controller *hsi_ctrlr = ch->ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ int i = 0;
+
+ spin_lock(&ch->hsi_ch_lock);
+ if (ch->read_data.data) {
+ /*
+ * while (((readl(hsi_base+HSI_RX_BUFSTATE))
+ * & (1<<ch->channel_number))
+ * && (ch->read_data.count)) {
+ */
+ while ((i < (ch->num_xfer_perintr)) &&
+ (ch->read_data.count)) {
+ *(u32 *) (ch->read_data.data) =
+ readl(hsi_base + HSI_RX_BUFFERX +
+ (4 * ch->channel_number));
+ /** stm_dbg(DBG_ST.hsi,"HSI RX: data 0x%x arrived \n",
+ * *(u32 *)(ch->read_data.data));
+ **/
+ ch->read_data.data = ch->read_data.data + ch->n_bytes;
+ ch->read_data.count = ch->read_data.count - ch->n_bytes;
+ i++;
+ }
+ if (ch->read_data.count == 0x0)
+ reset_ch_read(ch);
+ }
+ spin_unlock(&ch->hsi_ch_lock);
+}
+
+void do_hsi_tx_tasklet(unsigned long ctrlr)
+{
+ struct hsi_controller *hsi_ctrlr = (struct hsi_controller *)ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ unsigned long wmark_intrstatus;
+ unsigned long wmark_intrmask;
+ struct hsi_channel *chnl;
+ unsigned char i;
+
+ stm_dbg(DBG_ST.hsi, "HSI TX tasklet\n");
+ wmark_intrstatus = (0xFF) & readl(hsi_base + HSI_TX_WATERMARKIS);
+
+ for (i = 0; i < HSI_MAX_CHANNELS; i++) {
+ if ((wmark_intrstatus) & (1 << i)) {
+ /** data needs to be transferred for this channel*/
+ chnl = &hsi_ctrlr->hsi_tx_channels[i];
+ /* do_channel_tx(chnl); */
+ (*chnl->ops.write) (chnl);
+ /** FIXME: HSI bug - clearing interrupt disables
+ * delivery of further interrupts
+ **/
+ /* writel((1<<i), hsi_base+HSI_TX_WATERMARKIC);*/
+ /** we have transferred the required number of
+ * bytes user requested, callback
+ **/
+ spin_lock(&chnl->hsi_ch_lock);
+ if ((chnl->write_data.count) <=
+ (chnl->watermark * chnl->n_bytes)) {
+ /** TODO fix watermark on basis of bytes left */
+ writel((0x1f & 0x0),
+ (hsi_base + HSI_TX_WATERMARKX +
+ (0x4 * i)));
+ }
+ if (chnl->write_data.count == 0x0) {
+ /** disable the corresponding watermark
+ * as we are done */
+ wmark_intrmask =
+ (0xff) & readl(hsi_base +
+ HSI_TX_WATERMARKIM);
+ writel((wmark_intrmask &
+ ~(1 << chnl->channel_number)),
+ hsi_base + HSI_TX_WATERMARKIM);
+ /** write the original watermark */
+ writel((0x1f & (chnl->watermark - 1)),
+ (hsi_base + HSI_TX_WATERMARKX +
+ (0x4 * i)));
+ spin_unlock(&chnl->hsi_ch_lock);
+
+ /** callback */
+ (*chnl->ops.write_done) (chnl->dev);
+ } else
+ spin_unlock(&chnl->hsi_ch_lock);
+ }
+ }
+ enable_irq(hsi_ctrlr->irq1);
+}
+
+void do_hsi_rx_tasklet(unsigned long ctrlr)
+{
+ struct hsi_controller *hsi_ctrlr = (struct hsi_controller *)ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ unsigned long wmark_intrstatus;
+ unsigned long wmark_intrmask;
+ struct hsi_channel *chnl;
+ unsigned char i;
+ int gauge;
+
+ stm_dbg(DBG_ST.hsi, "HSI RX tasklet\n");
+ /** enter sleep mode - to negate READY line so that
+ * pipe buf is not overrun
+ * writel((0x3 & 0x0),hsi_base+HSI_RX_MODE);
+ **/
+ wmark_intrstatus = (0xFF) & readl(hsi_base + HSI_RX_WATERMARKIS);
+
+ for (i = 0; i < HSI_MAX_CHANNELS; i++) {
+ if ((wmark_intrstatus) & (1 << i)) {
+ /** data has arrived on this channel */
+ /** stm_dbg(DBG_ST.hsi,"Data arrived
+ * on channel %d\n",i);*/
+ chnl = &hsi_ctrlr->hsi_rx_channels[i];
+ /** gaurd against spurious interrupts */
+ gauge = (0x1F) & (readl(hsi_base + HSI_RX_GAUGEX
+ + (0x4 * chnl->channel_number)));
+ if (!gauge) {
+ /** clear and go away */
+ writel((1<<i), hsi_base+HSI_RX_WATERMARKIC);
+ continue;
+ }
+
+ /* do_channel_rx(chnl); */
+ (*chnl->ops.read) (chnl);
+ spin_lock(&chnl->hsi_ch_lock);
+ writel((1 << i), hsi_base + HSI_RX_WATERMARKIC);
+ if ((chnl->read_data.count) <=
+ (chnl->watermark * chnl->n_bytes))
+ /**TODO fix wmark on basis of bytes left*/
+ writel((0x1f & 0x0),
+ (hsi_base + HSI_RX_WATERMARKX +
+ (0x4 * i)));
+
+ /** we have the required number of bytes
+ * user requested, callback*/
+ if (chnl->read_data.count == 0x0) {
+ /** disable the corresponding watermark
+ * as we are done */
+ wmark_intrmask =
+ (0xff) & readl(hsi_base +
+ HSI_RX_WATERMARKIM);
+ writel((wmark_intrmask &
+ ~(1 << chnl->channel_number)),
+ hsi_base + HSI_RX_WATERMARKIM);
+ /** write the original watermark */
+ writel((0x1f & (chnl->watermark - 1)),
+ (hsi_base + HSI_RX_WATERMARKX +
+ (0x4 * i)));
+ spin_unlock(&chnl->hsi_ch_lock);
+ (*chnl->ops.read_done) (chnl->dev);
+ } else
+ spin_unlock(&chnl->hsi_ch_lock);
+
+ }
+ }
+ enable_irq(hsi_ctrlr->irq1);
+ /** re-enter PIPELINE mode
+ *writel((0x3 & 0x3),hsi_base+HSI_RX_MODE); For MOP
+ **/
+}
+
+void do_hsi_rxexcep_tasklet(unsigned long ctrlr)
+{
+ struct hsi_controller *hsi_ctrlr = (struct hsi_controller *)ctrlr;
+ void __iomem *hsi_base = NULL;
+ u32 exmis = 0x0;
+ u32 ovrmis = 0x0;
+ u8 i;
+ u8 chid = 0x0;
+
+ hsi_base = hsi_ctrlr->regbase;
+ exmis = (0xF) & readl(hsi_base + HSI_RX_EXCEPMIS);
+ ovrmis = (0xFF) & readl(hsi_base + HSI_RX_OVERRUNMIS);
+
+ if (exmis) {
+ for (i = 0; i < 4; i++) {
+ if ((1 << i) & exmis) {
+ switch (i) {
+ case 0x0:
+ stm_dbg(DBG_ST.hsi,
+ "HSIR:TIMEOUT !! \n");
+ hsi_exception(hsi_ctrlr,
+ HSI_EXCEP_TIMEOUT, NULL);
+ break;
+ case 0x1:
+ stm_dbg(DBG_ST.hsi,
+ "HSIR:PIPEBUF OVERRUN !! \n");
+ /** flush pipeline buffers
+ * and ack interrupt */
+ writel(0x1,
+ hsi_base + HSI_RX_PIPEGAUGE);
+ hsi_exception(hsi_ctrlr,
+ HSI_EXCEP_PIPEBUF_OVERRUN,
+ NULL);
+ break;
+ case 0x2:
+ stm_dbg(DBG_ST.hsi,
+ "HSIR:BRK_DETECTED!\n");
+ hsi_exception(hsi_ctrlr,
+ HSI_EXCEP_BREAK_DETECTED,
+ NULL);
+ break;
+ case 0x3:
+ stm_dbg(DBG_ST.hsi,
+ "HSIR:PARITY ERROR !! \n");
+ hsi_exception(hsi_ctrlr,
+ HSI_EXCEP_PARITY_ERROR,
+ NULL);
+ }
+ writel((1 << i), hsi_base + HSI_RX_ACK);
+ }
+ }
+ }
+
+ if (ovrmis) {
+ while (ovrmis) {
+ if (0x1 & ovrmis) {
+ /** channel overrun ..
+ * flush the channel buffer */
+ writel((readl(hsi_base + HSI_RX_BUFSTATE) &
+ ~((unsigned long)(1 << chid))),
+ hsi_base + HSI_RX_BUFSTATE);
+ /** call the exception handler */
+ hsi_exception(hsi_ctrlr,
+ HSI_RXCHANNELS_OVERRUN,
+ &chid);
+ /** set the ack bit */
+ writel((1 << chid),
+ hsi_base + HSI_RX_OVERRUNACK);
+ }
+ ovrmis = ovrmis >> 1;
+ chid++;
+ }
+ }
+
+ enable_irq(hsi_ctrlr->irqexcep);
+}
+
+/** interrupt context : tx handler */
+irqreturn_t hsi_tx_irq_handler(int irq, void *ctrlr)
+{
+ struct hsi_controller *hsi_ctrlr = ctrlr;
+ tasklet_hi_schedule(&hsi_ctrlr->hsi_tx_tasklet);
+ disable_irq_nosync(hsi_ctrlr->irq1);
+
+ return IRQ_HANDLED;
+}
+
+/** interrupt context : rx handler */
+irqreturn_t hsi_rx_irq_handler(int irq, void *ctrlr)
+{
+ struct hsi_controller *hsi_ctrlr = ctrlr;
+
+ tasklet_hi_schedule(&hsi_ctrlr->hsi_rx_tasklet);
+ disable_irq_nosync(hsi_ctrlr->irq1);
+
+ return IRQ_HANDLED;
+}
+
+/** interrupt context : rx exception handler */
+irqreturn_t hsi_rxexcep_irq_handler(int irq, void *ctrlr)
+{
+ int i = 0;
+ struct hsi_controller *hsi_ctrlr = ctrlr;
+ tasklet_hi_schedule(&hsi_ctrlr->hsi_rxexcep_tasklet);
+ disable_irq_nosync(hsi_ctrlr->irqexcep);
+ for (i = 0; i < hsi_ctrlr->max_ch; i++)
+ disable_irq_nosync(hsi_ctrlr->irq_choverrun[i]);
+ return IRQ_HANDLED;
+}
+
+void hsi_dma_write_eot_handler(void *data)
+{
+ struct hsi_channel *ch = (struct hsi_channel *)data;
+ struct hsi_controller *hsi_ctrlr;
+ unsigned int dma_mask;
+ void __iomem *hsi_base;
+
+ hsi_ctrlr = ch->ctrlr;
+ hsi_base = hsi_ctrlr->regbase;
+
+ stm_dbg(DBG_ST.hsi,
+ "Callback:DMA Mem to Periph TC for HSI channel %d \n",
+ ch->channel_number);
+
+ /* For MOP */
+ dma_mask = (0xff) & readl(hsi_base + HSI_TX_DMAEN);
+ writel((dma_mask & (~(1 << ch->channel_number))),
+ hsi_base + HSI_TX_DMAEN);
+
+ /** restore the original watermark */
+ writel((0x1f & (ch->watermark - 1)),
+ (hsi_base + HSI_TX_WATERMARKX + (0x4 * ch->channel_number)));
+
+ ch->write_data.data = NULL;
+ ch->write_data.count = 0;
+ /** disable the corresponding watermark as we are done
+ * wmark_intrmask=(0xff) & readl(hsi_base+HSI_TX_WATERMARKIM);
+ * writel((wmark_intrmask & ~(1<<ch->channel_number)),
+ * hsi_base+HSI_TX_WATERMARKIM);
+ */
+ /** call the application callback in tasklet
+ * (*ch->ops.write_done)(ch->dev);
+ *i*/
+ tasklet_schedule(&ch->hsi_dma_tasklet);
+}
+EXPORT_SYMBOL(hsi_dma_write_eot_handler);
+
+void hsi_dma_read_eot_handler(void *data)
+{
+ struct hsi_channel *ch = (struct hsi_channel *)data;
+ struct hsi_controller *hsi_ctrlr;
+ unsigned int dma_mask;
+ void __iomem *hsi_base;
+
+ hsi_ctrlr = ch->ctrlr;
+ hsi_base = hsi_ctrlr->regbase;
+
+ stm_dbg(DBG_ST.hsi,
+ "DMA Periph to Mem Transfer Completed for HSI channel %d \n",
+ ch->channel_number);
+
+ /* For MOP */
+ dma_mask = (0xff) & readl(hsi_base + HSI_RX_DMAEN);
+ writel((dma_mask & (~(1 << ch->channel_number))),
+ hsi_base + HSI_RX_DMAEN);
+
+ /** restore the original watermark */
+ writel((0x1f & (ch->watermark - 1)),
+ (hsi_base + HSI_RX_WATERMARKX + (0x4 * ch->channel_number)));
+
+ ch->read_data.data = NULL;
+ ch->read_data.count = 0;
+ /** disable the corresponding watermark as we are done
+ * wmark_intrmask=(0xff) & readl(hsi_base+HSI_RX_WATERMARKIM);
+ * writel((wmark_intrmask & ~(1<<ch->channel_number)),
+ * hsi_base+HSI_RX_WATERMARKIM);
+ **/
+
+ /** call the application callback in tasklet
+ *(*ch->ops.read_done)(ch->dev);
+ **/
+ tasklet_schedule(&ch->hsi_dma_tasklet);
+}
+EXPORT_SYMBOL(hsi_dma_read_eot_handler);
+
+int hsi_write_dma_mode(struct hsi_channel *ch)
+{
+ /*We Need to do Mem to Periph DMA */
+ struct hsi_controller *hsi_ctrlr;
+ void __iomem *hsi_base;
+ void *dst_addr = NULL;
+ dma_addr_t src_addr;
+ int count = 0;
+ void *hsi_base_phy = (void *)0x8011C000;
+ unsigned int dma_mask;
+ struct dma_async_tx_descriptor *dmach_desc;
+ struct scatterlist sg;
+
+ stm_dbg(DBG_ST.hsi, "Write dma mode\n");
+ hsi_ctrlr = ch->ctrlr;
+ hsi_base = hsi_ctrlr->regbase;
+
+ if (ch->write_data.is_dma) {
+ src_addr = ch->write_data.dma_addr;
+ } else {
+ src_addr =
+ dma_map_single(NULL, ch->write_data.data,
+ ch->write_data.count, DMA_TO_DEVICE);
+ ch->write_data.dma_addr = src_addr;
+ }
+ dst_addr =
+ (void *)hsi_base_phy + HSI_TX_BUFFERX + (4 * ch->channel_number);
+ count = ch->write_data.count;
+
+ if (ch->watermark <= 0x3) {
+ (void) stedma40_set_psize(ch->dma_chan,
+ STEDMA40_PSIZE_LOG_1,
+ STEDMA40_PSIZE_LOG_1);
+
+ writel((0x1f & 0x0),
+ (hsi_base + HSI_TX_WATERMARKX +
+ (0x4 * (ch->channel_number))));
+ } else {
+ (void) stedma40_set_psize(ch->dma_chan,
+ STEDMA40_PSIZE_LOG_4,
+ STEDMA40_PSIZE_LOG_4);
+
+ writel((0x1f & 0x3),
+ (hsi_base + HSI_TX_WATERMARKX +
+ (0x4 * (ch->channel_number))));
+ }
+
+ sg_init_table(&sg, 1);
+ sg_set_page(&sg, pfn_to_page(PFN_DOWN(src_addr)), count,
+ offset_in_page(src_addr));
+ sg_dma_address(&sg) = src_addr;
+ sg_dma_len(&sg) = count;
+
+ dmach_desc = ch->dma_chan->device->
+ device_prep_slave_sg(ch->dma_chan,
+ &sg, 1,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!dmach_desc)
+ return -ENOMEM;
+
+ dmach_desc->callback = hsi_dma_write_eot_handler;
+ dmach_desc->callback_param = ch;
+ dmach_desc->tx_submit(dmach_desc);
+ dma_async_issue_pending(ch->dma_chan);
+
+ /*Enable DMA bits of HSI controller */
+ dma_mask = (0xff) & readl(hsi_base + HSI_TX_DMAEN);
+ writel((dma_mask | (1 << ch->channel_number)), hsi_base + HSI_TX_DMAEN);
+
+ return 0;
+}
+
+int hsi_read_dma_mode(struct hsi_channel *ch)
+{
+ /*We Need to do Periph to Mem DMA */
+ struct hsi_controller *hsi_ctrlr;
+ void __iomem *hsi_base;
+ dma_addr_t dst_addr;
+ void *src_addr = NULL;
+ int count = 0;
+ unsigned int dma_mask;
+ void *hsi_base_phy = (void *)0x8011B000;
+ struct dma_async_tx_descriptor *dmach_desc;
+ struct scatterlist sg;
+
+ stm_dbg(DBG_ST.hsi, "Read dma mode\n");
+ hsi_ctrlr = ch->ctrlr;
+ hsi_base = hsi_ctrlr->regbase;
+
+ src_addr = hsi_base_phy + HSI_RX_BUFFERX + (4 * ch->channel_number);
+ if (ch->read_data.is_dma) {
+ dst_addr = ch->read_data.dma_addr;
+ } else {
+ dst_addr =
+ dma_map_single(NULL, ch->read_data.data,
+ ch->read_data.count,
+ DMA_FROM_DEVICE);
+ ch->read_data.dma_addr = dst_addr;
+ }
+ count = ch->read_data.count;
+
+ /** sync up the watermark and burst size */
+ if (ch->watermark <= 0x3)
+ (void) stedma40_set_psize(ch->dma_chan,
+ STEDMA40_PSIZE_LOG_1,
+ STEDMA40_PSIZE_LOG_1);
+ else
+ (void) stedma40_set_psize(ch->dma_chan,
+ STEDMA40_PSIZE_LOG_4,
+ STEDMA40_PSIZE_LOG_4);
+
+ sg_init_table(&sg, 1);
+ sg_set_page(&sg, pfn_to_page(PFN_DOWN(dst_addr)), count,
+ offset_in_page(dst_addr));
+ sg_dma_address(&sg) = dst_addr;
+ sg_dma_len(&sg) = count;
+
+ dmach_desc = ch->dma_chan->device->
+ device_prep_slave_sg(ch->dma_chan,
+ &sg, 1,
+ DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!dmach_desc)
+ return -ENOMEM;
+
+ dmach_desc->callback = hsi_dma_read_eot_handler;
+ dmach_desc->callback_param = ch;
+ dmach_desc->tx_submit(dmach_desc);
+ dma_async_issue_pending(ch->dma_chan);
+
+ /*Enable DMA bits of HSI controller */
+ dma_mask = (0xff) & readl(hsi_base + HSI_RX_DMAEN);
+ writel((dma_mask | (1 << ch->channel_number)), hsi_base + HSI_RX_DMAEN);
+
+ return 0;
+}
+
+void hsi_cancel_write_dma_mode(struct hsi_channel *ch)
+{
+ struct hsi_controller *hsi_ctrlr;
+ void __iomem *hsi_base;
+ unsigned int dma_mask;
+
+ hsi_ctrlr = ch->ctrlr;
+ hsi_base = hsi_ctrlr->regbase;
+
+ ch->dma_chan->device->device_control(ch->dma_chan,
+ DMA_TERMINATE_ALL, 0);
+
+ /*Disable DMA nebaling bits of HSI controller */
+ dma_mask = (0xff) & readl(hsi_base + HSI_TX_DMAEN);
+ writel((dma_mask & (~(1 << ch->channel_number))),
+ hsi_base + HSI_TX_DMAEN);
+ /** flush the transmit channel buffers */
+ writel((readl(hsi_base + HSI_TX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),
+ hsi_base + HSI_TX_BUFSTATE);
+ /** restore the original watermark */
+ writel((0x1f & (ch->watermark - 1)),
+ (hsi_base + HSI_TX_WATERMARKX + (0x4 * ch->channel_number)));
+
+ ch->write_data.data = NULL;
+ ch->write_data.dma_addr = (dma_addr_t) NULL;
+ ch->write_data.count = 0;
+}
+
+void hsi_cancel_read_dma_mode(struct hsi_channel *ch)
+{
+ struct hsi_controller *hsi_ctrlr;
+ void __iomem *hsi_base;
+ unsigned int dma_mask;
+
+ hsi_ctrlr = ch->ctrlr;
+ hsi_base = hsi_ctrlr->regbase;
+
+ ch->dma_chan->device->device_control(ch->dma_chan,
+ DMA_TERMINATE_ALL, 0);
+
+ /*Disable DMA nebaling bits of HSI controller */
+ dma_mask = (0xff) & readl(hsi_base + HSI_RX_DMAEN);
+ writel((dma_mask & (~(1 << ch->channel_number))),
+ hsi_base + HSI_RX_DMAEN);
+ /** flush the receive channel buffers */
+ writel((readl(hsi_base + HSI_RX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),
+ hsi_base + HSI_RX_BUFSTATE);
+ /** restore the original watermark */
+ writel((0x1f & (ch->watermark - 1)),
+ (hsi_base + HSI_RX_WATERMARKX + (0x4 * ch->channel_number)));
+
+ ch->read_data.data = NULL;
+ ch->read_data.dma_addr = (dma_addr_t) NULL;
+ ch->read_data.count = 0;
+}
+
+void do_hsi_tx_dma_tasklet(unsigned long param)
+{
+ struct hsi_channel *ch = (struct hsi_channel *)param;
+
+ ch->ops.write_done(ch->dev);
+
+}
+EXPORT_SYMBOL(do_hsi_tx_dma_tasklet);
+
+void do_hsi_rx_dma_tasklet(unsigned long param)
+{
+ struct hsi_channel *ch = (struct hsi_channel *)param;
+
+ ch->ops.read_done(ch->dev);
+
+}
+EXPORT_SYMBOL(do_hsi_rx_dma_tasklet);
+
+/** End of file **/
diff --git a/drivers/misc/hsi/hsi-legacy/Kconfig b/drivers/misc/hsi/hsi-legacy/Kconfig
new file mode 100644
index 00000000000..efe9efcd2ad
--- /dev/null
+++ b/drivers/misc/hsi/hsi-legacy/Kconfig
@@ -0,0 +1,41 @@
+#
+# HSI HW kernel configuration
+#
+if !HSI
+config U8500_HSI_LEGACY
+ tristate "Legacy U8500 HSI hardware driver"
+ depends on ARCH_U8500
+ default n
+ ---help---
+ If you say Y here, you will enable the U8500 HSI (Rx and Tx) hardware driver.
+
+ If unsure, say N.
+
+config U8500_HSI_TEST_PROTOCOL_DRIVER
+ tristate "U8500 HSI test protocol driver"
+ depends on U8500_HSI_LEGACY
+ default n
+ ---help---
+ If you say Y here, you will enable the test protocol driver used for testing HSI Rx and Tx controllers
+
+ If unsure, say N.
+
+choice
+ prompt "HSI transfer mode"
+ depends on U8500_HSI_LEGACY
+ default U8500_HSI_INTERRUPT_MODE
+
+config U8500_HSI_INTERRUPT_MODE
+ bool "Interrupt mode transfer"
+
+config U8500_HSI_DMA_MODE
+ bool "DMA mode transfer"
+
+endchoice
+
+config U8500_HSI_TRANSFER_MODE
+ hex
+ default 0x0 if !U8500_HSI
+ default 0x1 if U8500_HSI_INTERRUPT_MODE
+ default 0x2 if U8500_HSI_DMA_MODE
+endif
diff --git a/drivers/misc/hsi/hsi-legacy/Makefile b/drivers/misc/hsi/hsi-legacy/Makefile
new file mode 100644
index 00000000000..131bc27793e
--- /dev/null
+++ b/drivers/misc/hsi/hsi-legacy/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for HSI drivers
+#
+u8500_hsi-objs := hsi_driver.o hsi_driver_int.o hsi_driver_dma.o \
+ hsi_driver_if.o hsi_driver_bus.o
+
+obj-$(CONFIG_U8500_HSI_LEGACY) += u8500_hsi.o
+
+obj-$(CONFIG_U8500_HSI_TEST_PROTOCOL_DRIVER) += hsi_test_protocol_driver.o
diff --git a/drivers/misc/hsi/hsi-legacy/hsi_driver.c b/drivers/misc/hsi/hsi-legacy/hsi_driver.c
new file mode 100644
index 00000000000..5d461e004bf
--- /dev/null
+++ b/drivers/misc/hsi/hsi-legacy/hsi_driver.c
@@ -0,0 +1,656 @@
+/*----------------------------------------------------------------------------------*/
+/* copyright STMicroelectronics, 2007. */
+/* */
+/* This program is free software; you can redistribute it and/or modify it under */
+/* the terms of the GNU General Public License as published by the Free */
+/* Software Foundation; either version 2.1 of the License, or (at your option) */
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but WITHOUT */
+/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS */
+/* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*----------------------------------------------------------------------------------*/
+
+
+#include <linux/err.h>
+#include "hsi_driver.h"
+#include <linux/dmaengine.h>
+#include <plat/ste_dma40.h>
+
+static void hsi_dev_release(struct device *dev)
+{
+}
+
+static void __exit hsi_close_all_ch(struct hsi_dev *hsi_ctrlr)
+{
+ unsigned int i;
+
+ if (hsi_ctrlr->dev_type==0x0) {
+ for (i=0;i<hsi_ctrlr->max_ch;i++)
+ hsi_close(hsi_ctrlr->hsi_tx_channels[i].dev);
+ }
+ else {
+ for (i=0;i<hsi_ctrlr->max_ch;i++)
+ hsi_close(hsi_ctrlr->hsi_rx_channels[i].dev);
+ }
+}
+
+static void __init start_hsi_controller(struct platform_device* pdev)
+{
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_dev *hsi_ctrlr =NULL;
+ void __iomem *hsi_base;
+ unsigned char n_ch;
+
+ pdata = (struct hsi_plat_data *) pdev->dev.platform_data;
+ hsi_ctrlr = pdata->hsi_ctrlr;
+ n_ch = hsi_ctrlr->max_ch;
+ hsi_base=hsi_ctrlr->regbase;
+
+
+ if (!(pdev->id)) {
+ /** HSI transmit */
+ /** flush all the channel buffers */
+ writel(0x0,hsi_base+HSI_TX_BUFSTATE);
+ /** change mode to FRAME*/
+ writel((0x3 & 0x2),hsi_base+HSI_TX_MODE);
+ /** enable watermark interrupt mask and destination 0*/
+ //writel(((1<<n_ch)-1),hsi_base+HSI_TX_WATERMARKIM);
+ writel(0x0,hsi_base+HSI_TX_WATERMARKID);
+ }
+ else {
+ /** flush the pipeline buffers */
+ writel(0x0,hsi_base+HSI_RX_STATE);
+ writel(0x0,hsi_base+HSI_RX_PIPEGAUGE);
+ writel(0x0,hsi_base+HSI_RX_BUFSTATE);
+
+ /** change mode to FRAME*/
+ writel((0x3 & 0x2),hsi_base+HSI_RX_MODE);
+
+ /** enable watermark interrupt mask and destination 0 */
+ /** ..not done right now, done during data transfer */
+ //writel(((1<<n_ch)-1),hsi_base+HSI_RX_WATERMARKIM);
+ writel(0x0,hsi_base+HSI_RX_WATERMARKID);
+ /** for testing purpose */
+ //writel(0xAAAAAAAA,hsi_base+HSI_RX_BUFFERX);
+ //writel(0xBBBBBBBB,hsi_base+HSI_RX_BUFFERX+0x4);
+ //writel(0xCCCCCCCC,hsi_base+HSI_RX_BUFFERX+0x8);
+
+ /** enable the exeception interrupts - parity,timeout,BREAK,overrun */
+ writel(0xF,hsi_base+HSI_RX_EXCEPIM);
+ /** enable channel overrun interrupt for 4 channels */
+ writel(0xF,hsi_base+HSI_RX_OVERRUNIM);
+ }
+}
+
+static int __init register_hsi_devices(struct platform_device* pdev)
+{
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_dev *hsi_ctrlr =NULL;
+ unsigned int n_ch = 0;
+ int ch = 0;
+ int err = 0;
+ struct hsi_device *dev;
+
+
+ pdata = (struct hsi_plat_data *) pdev->dev.platform_data;
+ hsi_ctrlr = pdata->hsi_ctrlr;
+ n_ch = hsi_ctrlr->max_ch;
+
+
+ if (!(pdev->id)) /** HSI transmit */{
+ for (ch = 0; ((ch < n_ch) && (err >= 0)); ch++)
+ {
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ err= -ENOMEM;
+ break;
+ }
+ dev->ctrlrid = pdev->id;
+ dev->chid = ch;
+ dev->curr_mode = pdata->currmode;
+ dev->ch = &pdata->hsi_ctrlr->hsi_tx_channels[ch];
+ pdata->hsi_ctrlr->hsi_tx_channels[ch].dev = dev;
+ dev->device.bus = &hsi_bus_type;
+ dev->device.parent = &pdev->dev;
+ dev->device.release = hsi_dev_release;
+ snprintf(dev->device.bus_id, sizeof(dev->device.bus_id),
+ "hsitx-ch%u",ch);
+ err = device_register(&dev->device);
+ }
+ }
+ else {
+ for (ch = 0; ((ch < n_ch) && (err >= 0)); ch++)
+ {
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ err= -ENOMEM;
+ break;
+ }
+ dev->ctrlrid = pdev->id;
+ dev->chid = ch;
+ dev->curr_mode = pdata->currmode;
+ dev->ch = &pdata->hsi_ctrlr->hsi_rx_channels[ch];
+ pdata->hsi_ctrlr->hsi_rx_channels[ch].dev = dev;
+ dev->device.bus = &hsi_bus_type;
+ dev->device.parent = &pdev->dev;
+ dev->device.release = hsi_dev_release;
+ snprintf(dev->device.bus_id, sizeof(dev->device.bus_id),
+ "hsirx-ch%u",ch);
+ err = device_register(&dev->device);
+ }
+ }
+ return err;
+}
+
+static void __init hsi_initialise_hw(struct platform_device* pdev)
+{
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_dev *hsi_ctrlr =NULL;
+ struct hsi_channel *txch,*rxch;
+ void __iomem *hsi_base;
+ u8 i;
+ u8 n_ch;
+ volatile u32 partnum0;
+ volatile u32 des0partnum1;
+ volatile u32 revdes1;
+ volatile u32 config;
+
+
+ pdata = (struct hsi_plat_data *) pdev->dev.platform_data;
+ hsi_ctrlr = pdata->hsi_ctrlr;
+ n_ch = hsi_ctrlr->max_ch;
+ hsi_base=hsi_ctrlr->regbase;
+
+ if (!(pdev->id)) {
+ /** HSI transmit */
+ /** channel id and priority */
+ writel((0xf & pdata->channels),hsi_base+HSI_TX_CHANNELS);
+ writel((0xff & pdata->priority),hsi_base+HSI_TX_PRIORITY);
+ /** channels framelen,base and span data */
+ for (i=0;i < n_ch;i++) {
+ writel((0x1f & pdata->framelen),hsi_base+HSI_TX_FRAMELENX + (0x4*i));
+ writel((0x1f & pdata->ch_base_span[i].base),(hsi_base+HSI_TX_BASEX + (0x4*i)));
+ writel((0x1f & pdata->ch_base_span[i].span),(hsi_base+HSI_TX_SPANX + (0x4*i)));
+ }
+
+ /** serial link settings */
+ /** sleep mode for now */
+ writel((0x3 & 0x0),hsi_base+HSI_TX_MODE);
+ writel((0xffffff & pdata->divisor),hsi_base+HSI_TX_DIVISOR);
+ writel((0x3 & pdata->parity),hsi_base+HSI_TX_PARITY);
+ writel((0x3f & pdata->flushbits),hsi_base+HSI_TX_FLUSHBITS);
+ writel((0xffffff & pdata->burstlen),hsi_base+HSI_TX_BURSTLEN);
+ writel((0xffffff & pdata->preamble),hsi_base+HSI_TX_PREAMBLE);
+
+ /** watermark and interrupt settings */
+ for (i=0;i<n_ch;i++) {
+ /** watermark fixed to 4 free entries */
+ txch = &hsi_ctrlr->hsi_tx_channels[i];
+ writel((0x1f & (txch->watermark-1)),(hsi_base+HSI_TX_WATERMARKX + (0x4*i)));
+ }
+
+ /** watermark interrupt mask - mask all interrupts now*/
+ writel(0x0,hsi_base+HSI_TX_WATERMARKIM);
+
+
+ /** Gather info from registers for the driver.(REVISION) */
+ partnum0 = readl(hsi_base+HSI_TX_PERIPHID0);
+ des0partnum1 = readl(hsi_base+HSI_TX_PERIPHID1);
+ revdes1 = readl(hsi_base+HSI_TX_PERIPHID2);
+ config = readl(hsi_base+HSI_TX_PERIPHID3);
+
+ printk("HSIT Hardware VERSION (in hex) %x.%x.%x.%x.%x.%x\n",
+ (partnum0 & 0xff) , (des0partnum1 & 0xf0),(des0partnum1 & 0x0f),
+ (revdes1 & 0xf0),(revdes1 & 0x0f),(config & 0xff));
+
+
+ }
+ else {
+ /** HSI receive*/
+
+ /** channel id and priority */
+ writel((0xf & pdata->channels),hsi_base+HSI_RX_CHANNELS);
+ for (i=0;i<pdata->channels;i++) {
+ /** channels framelen,base and span data */
+ writel((0x1f & pdata->framelen),(hsi_base+HSI_RX_FRAMELENX+ (0x4*i)));
+ writel((0x1f & pdata->ch_base_span[i].base),(hsi_base+HSI_RX_BASEX + (0x4*i)));
+ writel((0x1f & pdata->ch_base_span[i].span),(hsi_base+HSI_RX_SPANX + (0x4*i)));
+ }
+
+ /** serial link settings */
+ /** sleep mode for now */
+ writel((0x3 & 0x0),hsi_base+HSI_RX_MODE);
+ writel((0xffffff & pdata->detector),hsi_base+HSI_RX_DETECTOR);
+ writel((0x3 & pdata->parity),hsi_base+HSI_RX_PARITY);
+ writel((0xffffff & pdata->preamble),hsi_base+HSI_RX_PREAMBLE);
+
+ /** watermark settings */
+ for (i=0;i<pdata->channels;i++) {
+ /** watermark fixed to 1 occupied entries */
+ rxch = &hsi_ctrlr->hsi_rx_channels[i];
+ writel((0x1f & (rxch->watermark-1)),(hsi_base+HSI_RX_WATERMARKX + (0x4*i)));
+ }
+
+ /** watermark interrupt mask - mask all interrupts now*/
+ writel(0x0,hsi_base+HSI_RX_WATERMARKIM);
+ writel(0x0,hsi_base+HSI_RX_OVERRUNIM);
+ writel(0x0,hsi_base+HSI_RX_EXCEPIM);
+
+ /** threshold,realtime and timeout settings */
+ writel((0x3f & pdata->threshold),hsi_base+HSI_RX_THRESHOLD);
+ writel(pdata->realtime,hsi_base+HSI_RX_REALTIME);
+ writel(pdata->timeout,hsi_base+HSI_RX_TIMEOUT);
+
+
+ /** Gather info from registers for the driver.(REVISION) */
+ partnum0 = readl(hsi_base+HSI_RX_PERIPHID0);
+ des0partnum1 = readl(hsi_base+HSI_RX_PERIPHID1);
+ revdes1 = readl(hsi_base+HSI_RX_PERIPHID2);
+ config = readl(hsi_base+HSI_RX_PERIPHID3);
+
+ printk("HSIR Hardware VERSION (in hex) %x.%x.%x.%x.%x.%x\n",
+ (partnum0 & 0xff) , (des0partnum1 & 0xf0),(des0partnum1 & 0x0f),
+ (revdes1 & 0xf0),(revdes1 & 0x0f),(config & 0xff));
+
+
+ }
+}
+
+
+static int __init hsi_initialise_irq(struct hsi_dev* hsi_ctrlr)
+{
+ int err = 0;
+ int i=0,j=0;
+ char irqname[20];
+
+ if (!(hsi_ctrlr->dev_type)) /** tx */ {
+ tasklet_init(&hsi_ctrlr->hsi_tx_tasklet,do_hsi_tx_tasklet,(unsigned long)hsi_ctrlr);
+ err = request_irq(hsi_ctrlr->irq1,hsi_tx_irq_handler,IRQF_DISABLED,"hsi-tx-d0",hsi_ctrlr);
+ if (err < 0) {
+ printk("Unable to allocate HSI tx interrupt line\n");
+ err = -EBUSY;
+ tasklet_disable(&hsi_ctrlr->hsi_tx_tasklet);
+ }
+ }
+ else /** rx */ {
+ tasklet_init(&hsi_ctrlr->hsi_rx_tasklet,do_hsi_rx_tasklet,(unsigned long)hsi_ctrlr);
+ err = request_irq(hsi_ctrlr->irq1,hsi_rx_irq_handler,IRQF_DISABLED,"hsi-rx-d0",hsi_ctrlr);
+ if (err < 0) {
+ printk("Unable to allocate HSI rx interrupt line\n");
+ tasklet_disable(&hsi_ctrlr->hsi_rx_tasklet);
+ err = -EBUSY;
+ return err;
+ }
+
+ tasklet_init(&hsi_ctrlr->hsi_rxexcep_tasklet,do_hsi_rxexcep_tasklet,(unsigned long)hsi_ctrlr);
+ err = request_irq(hsi_ctrlr->irqexcep,hsi_rxexcep_irq_handler,IRQF_DISABLED,"hsi-rx-excep",hsi_ctrlr);
+ if (err < 0) {
+ printk("Unable to allocate HSI rx exception interrupt line\n");
+ err = -EBUSY;
+ tasklet_disable(&hsi_ctrlr->hsi_rx_tasklet);
+ tasklet_disable(&hsi_ctrlr->hsi_rxexcep_tasklet);
+ free_irq(hsi_ctrlr->irq1,hsi_ctrlr);
+ return err;
+ }
+ for (i=0;i<hsi_ctrlr->max_ch;i++) {
+ snprintf(irqname,sizeof(irqname),"hsi-rx-ch%d-ovrn",i);
+ err = request_irq(hsi_ctrlr->irq_choverrun[i],hsi_rxexcep_irq_handler,
+ IRQF_DISABLED,"hsi-rx-overrun",hsi_ctrlr);
+ if (err < 0) {
+ printk("Unable to allocate HSI rx overrun interrupt line\n");
+ err = -EBUSY;
+ tasklet_disable(&hsi_ctrlr->hsi_rx_tasklet);
+ tasklet_disable(&hsi_ctrlr->hsi_rxexcep_tasklet);
+ free_irq(hsi_ctrlr->irq1,hsi_ctrlr);
+ free_irq(hsi_ctrlr->irqexcep,hsi_ctrlr);
+ for (j=0;j<i;j++)
+ free_irq(hsi_ctrlr->irq_choverrun[j],hsi_ctrlr);
+ }
+
+ }
+ }
+
+ return err;
+}
+
+
+static void free_hsi_irq(struct hsi_dev *hsi_ctrlr)
+{
+ int i=0;
+ int j=0;
+
+ if (!(hsi_ctrlr->dev_type)) /** tx */ {
+ tasklet_disable(&hsi_ctrlr->hsi_tx_tasklet);
+ free_irq(hsi_ctrlr->irq1,hsi_ctrlr);
+ }
+ else {
+ tasklet_disable(&hsi_ctrlr->hsi_rx_tasklet);
+ tasklet_disable(&hsi_ctrlr->hsi_rxexcep_tasklet);
+ free_irq(hsi_ctrlr->irq1,hsi_ctrlr);
+ free_irq(hsi_ctrlr->irqexcep,hsi_ctrlr);
+ for (i=0;i<hsi_ctrlr->max_ch;i++)
+ free_irq(hsi_ctrlr->irq_choverrun[i],hsi_ctrlr);
+ }
+
+}
+
+int fill_hsi_dma_info(struct platform_device *pd, struct hsi_channel *ch) {
+
+ struct hsi_dev *hsi_ctrlr;
+ struct hsi_plat_data *pdata;
+ dma_cap_mask_t mask;
+
+ pdata = (struct hsi_plat_data *) pd->dev.platform_data;
+ hsi_ctrlr=pdata->hsi_ctrlr;
+
+ //FIXME can it be made single register
+ if(pd->id)
+ {
+
+ /* find and request free dma chanel */
+ #if 1
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ ch->dma_chan = dma_request_channel(mask, stedma40_filter,
+ ch->hsi_dma_info);
+ if (!ch->dma_chan) {
+ printk("hsi: dma_request_channel for RX failed for channel %d\n",
+ ch->channel_number);
+ return -EBUSY;
+ }
+ #endif
+ tasklet_init(&ch->hsi_dma_tasklet, do_hsi_rx_dma_tasklet,
+ (unsigned long)ch);
+ }
+ else
+ {
+ /* find and request free dma chanel for tx */
+ #if 1
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ ch->dma_chan = dma_request_channel(mask, stedma40_filter,
+ ch->hsi_dma_info);
+ if (!ch->dma_chan) {
+ printk("hsi: dma_request_channel for TX failed for channel %d\n",
+ ch->channel_number);
+ return -EBUSY;
+ }
+ #endif
+ tasklet_init(&ch->hsi_dma_tasklet, do_hsi_tx_dma_tasklet,
+ (unsigned long)ch);
+ }
+ return 0;
+}
+
+
+
+static void __init hsi_initialise_channels(struct platform_device* pdev)
+{
+
+ u8 ch = 0;
+ u8 n_ch = 0;
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_dev *hsi_ctrlr =NULL;
+ struct hsi_channel* txch = NULL; /** temp pointer to populate txchannel array */
+ struct hsi_channel* rxch = NULL; /** temp pointer to populate rxchannel array */
+
+ pdata = (struct hsi_plat_data *) pdev->dev.platform_data;
+ hsi_ctrlr = pdata->hsi_ctrlr;
+ n_ch = hsi_ctrlr->max_ch;
+
+ if (!(pdev->id)) {
+ /** HSI transmit */
+ for (ch=0;ch < n_ch; ch++) {
+ txch = &hsi_ctrlr->hsi_tx_channels[ch];
+ txch->channel_number = ch;
+ txch->span = (pdata->ch_base_span[ch].span)+1;
+ txch->watermark = pdata->watermark;
+ txch->flags = 0;
+ txch->ctrlr = hsi_ctrlr;
+ txch->write_data.addr = NULL;
+ txch->write_data.size = 0;
+ txch->hsi_dma_info = &pdata->hsi_dma_info[ch];
+ txch->n_bytes = 0x1;
+ fill_hsi_dma_info(pdev,txch);
+ spin_lock_init(&txch->hsi_ch_lock);
+ }
+ }
+ else {
+ /** HSI receive */
+ for (ch=0;ch < n_ch; ch++) {
+ rxch = &hsi_ctrlr->hsi_rx_channels[ch];
+ rxch->channel_number = ch;
+ rxch->span = (pdata->ch_base_span[ch].span)+1;
+ rxch->watermark = pdata->watermark;
+ rxch->flags = 0;
+ rxch->ctrlr = hsi_ctrlr;
+ rxch->read_data.addr = NULL;
+ rxch->read_data.size = 0;
+ rxch->hsi_dma_info = &pdata->hsi_dma_info[ch];
+ rxch->n_bytes = 0x1;
+ fill_hsi_dma_info(pdev,rxch);
+ spin_lock_init(&rxch->hsi_ch_lock);
+ }
+
+ }
+}
+
+static void __init hsi_initialise_controller(struct platform_device* pdev)
+{
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_dev *hsi_ctrlr =NULL;
+
+ pdata = (struct hsi_plat_data *) pdev->dev.platform_data;
+
+ hsi_ctrlr=pdata->hsi_ctrlr;
+ hsi_ctrlr->max_ch=pdata->channels;
+ hsi_ctrlr->mode = pdata->mode;
+ hsi_ctrlr->flags = 0;
+ spin_lock_init(&hsi_ctrlr->lock);
+}
+
+
+
+static int __init hsi_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct hsi_dev *hsi_ctrlr = NULL;
+ struct hsi_plat_data *pdata = NULL;
+ unsigned char name[20];
+ int err = 0;
+ int i=0;
+
+ /* FIXME : need to do tis in better way */
+ *((unsigned int *)((void __iomem *)ioremap_nocache(0x8011f000, 32))) = 0x7fff;
+ *((unsigned int *)((void __iomem *)ioremap_nocache(0x8011f008, 32))) = 0x7fff;
+
+ if ((pdev == NULL) || (pdev->dev.platform_data == NULL)) {
+ printk( "No device/platform_data found on HSI device\n");
+ return -ENODEV;
+ }
+
+
+ hsi_ctrlr = kzalloc(sizeof(struct hsi_dev),GFP_KERNEL);
+ if (hsi_ctrlr == NULL) {
+ printk("Could not allocate memory for struct hsi_dev\n");
+ return -ENOMEM;
+ }
+
+ #if 1
+ hsi_ctrlr->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(hsi_ctrlr->clk)) {
+ printk(" DBG_ST.hsi Could not get HSI clock\n");
+ err = PTR_ERR(hsi_ctrlr->clk);
+ goto rollback_alloc;
+ }
+ clk_enable(hsi_ctrlr->clk);
+ #endif
+
+ /** initialise the HSI controller and channels (tx and rx) */
+ hsi_ctrlr->dev_type = pdev->id;
+ pdata = pdev->dev.platform_data;
+ pdata->hsi_ctrlr = hsi_ctrlr;
+
+ err = stm_gpio_altfuncenable(pdata->gpio_alt_func);
+ if (err) {
+ printk("Could not set HSI GPIO alternate function correctly\n");
+ err = -ENODEV;
+ goto rollback_alloc;
+ }
+
+ hsi_initialise_controller(pdev);
+ hsi_initialise_channels(pdev);
+
+ res = platform_get_resource(pdev,IORESOURCE_MEM,0);
+ if (!res) {
+ printk("Could not get HSI IO memory information\n");
+ err = -ENODEV;
+ goto rollback_gpio;
+ }
+
+ hsi_ctrlr->regbase = (void __iomem *)ioremap(res->start,res->end - res->start + 1);
+ if (!(hsi_ctrlr->regbase)) {
+ printk("Unable to map register base \n");
+ err = -EBUSY;
+ goto rollback_gpio;
+ }
+
+ res = platform_get_resource(pdev,IORESOURCE_IRQ,0);
+ if (!res) {
+ printk("Unable to map HSI D0/D1 IRQ base \n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+
+ /** storing D0 and D1 interrupt lines */
+ if (res->end - res->start) {
+ hsi_ctrlr->irq1 = res->start;
+ hsi_ctrlr->irq2 = res->end;
+ }
+
+ /** store the HSIR exception interrupt and channel overrun interrupt line */
+ if (hsi_ctrlr->dev_type == 0x1) /** rx */ {
+ res = platform_get_resource(pdev,IORESOURCE_IRQ,1);
+ if (!res) {
+ printk("Unable to map HSIR EXCEP IRQ base \n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+ hsi_ctrlr->irqexcep = res->start;
+
+ for(i=0;i<hsi_ctrlr->max_ch;i++) {
+ res = platform_get_resource(pdev,IORESOURCE_IRQ,i+2);
+ if (!res) {
+ printk("Unable to map HSIR CHANNEL %d OVERRUN IRQ LINE \n",i);
+ err = -EBUSY;
+ goto rollback_map;
+ }
+ hsi_ctrlr->irq_choverrun[i] = res->start;
+ }
+ }
+
+ /** install handlers and tasklets */
+ if (hsi_initialise_irq(hsi_ctrlr)) {
+ printk("HSI error in interrupt registration \n");
+ goto rollback_map;
+ }
+
+ /** write to hardware but do not start yet*/
+ hsi_initialise_hw(pdev);
+
+ /** register devices on hsi bus */
+ err = register_hsi_devices(pdev);
+ if (err < 0) {
+ printk("HSI error in device registration \n");
+ goto rollback_irq;
+ }
+
+ /** kick start the controller */
+ start_hsi_controller(pdev);
+
+ snprintf(name,sizeof(name),"%s:%d",pdev->name,pdev->id);
+ if (!err) printk("%s probe COMPLETED \n",name);
+
+ return err;
+
+rollback_irq:
+ free_hsi_irq(hsi_ctrlr);
+rollback_map:
+ iounmap(hsi_ctrlr->regbase);
+rollback_gpio:
+ stm_gpio_altfuncdisable(pdata->gpio_alt_func);
+rollback_clock:
+ clk_put(hsi_ctrlr->clk);
+rollback_alloc:
+ pdata->hsi_ctrlr = NULL;
+ kfree(hsi_ctrlr);
+ return err;
+}
+
+static int __exit hsi_remove(struct platform_device *pdev)
+{
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_dev *hsi_ctrlr =NULL;
+
+ pdata = (struct hsi_plat_data *) pdev->dev.platform_data;
+ hsi_ctrlr=pdata->hsi_ctrlr;
+
+ hsi_close_all_ch(hsi_ctrlr);
+ free_hsi_irq(hsi_ctrlr);
+ iounmap(hsi_ctrlr->regbase);
+ clk_put(hsi_ctrlr->clk);
+ pdata->hsi_ctrlr = NULL;
+ kfree(hsi_ctrlr);
+
+ return 0;
+}
+
+static struct platform_driver hsi_driver = {
+ .probe = hsi_probe,
+ .remove = __exit_p(hsi_remove),
+ .driver = {
+ .name = "stm-hsi",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init hsi_driver_init(void)
+{
+ int err = 0;
+
+ err = hsi_bus_init();
+ if (err) {
+ printk("HSI bus initialisation FAILED: %d\n", err);
+ return err;
+ }
+
+ err = platform_driver_probe(&hsi_driver, hsi_probe);
+ if (err < 0) {
+ printk("HSI Platform DRIVER register FAILED: %d\n", err);
+ hsi_bus_exit();
+ return err;
+ }
+
+ return 0;
+}
+
+static void __exit hsi_driver_exit(void)
+{
+ hsi_bus_exit();
+ platform_driver_unregister(&hsi_driver);
+
+ printk("HSI Platform DRIVER removed\n");
+}
+
+module_init(hsi_driver_init);
+module_exit(hsi_driver_exit);
+
+MODULE_AUTHOR(HSI_DRIVER_AUTHOR);
+MODULE_DESCRIPTION(HSI_DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/hsi/hsi-legacy/hsi_driver.h b/drivers/misc/hsi/hsi-legacy/hsi_driver.h
new file mode 100644
index 00000000000..7a61f8deb57
--- /dev/null
+++ b/drivers/misc/hsi/hsi-legacy/hsi_driver.h
@@ -0,0 +1,250 @@
+/*----------------------------------------------------------------------------------*/
+/* copyright STMicroelectronics, 2007. */
+/* */
+/* This program is free software; you can redistribute it and/or modify it under */
+/* the terms of the GNU General Public License as published by the Free */
+/* Software Foundation; either version 2.1 of the License, or (at your option) */
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but WITHOUT */
+/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS */
+/* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*----------------------------------------------------------------------------------*/
+
+
+#ifndef __HSI_DRIVER_H__
+#define __HSI_DRIVER_H__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+
+#include <linux/hsi-legacy.h>
+#include <mach/dma.h>
+
+#define HSI_DRIVER_AUTHOR "STMicroelectronics"
+#define HSI_DRIVER_DESC "High-Speed Synchronous Serial Interface Driver"
+
+#define HSI_DRIVER_NAME "hsi_driver"
+
+#define HSI_DEVICE_NAME "hsi_device"
+#define HSI_TX_PREFIX "hsi_tx:"
+#define HSI_RX_PREFIX "hsi_rx:"
+#define HSI_PREFIX "hsi:"
+
+/** HSIT register offsets */
+#define HSI_TX_ID 0x0
+#define HSI_TX_MODE 0x4
+#define HSI_TX_STATE 0x8
+#define HSI_TX_IOSTATE 0xC
+#define HSI_TX_BUFSTATE 0x10
+#define HSI_TX_DIVISOR 0x14
+#define HSI_TX_PARITY 0x18
+#define HSI_TX_BREAK 0x1C
+#define HSI_TX_CHANNELS 0x20
+#define HSI_TX_FLUSHBITS 0x24
+#define HSI_TX_PRIORITY 0x28
+#define HSI_TX_BURSTLEN 0x2C
+#define HSI_TX_PREAMBLE 0x30
+#define HSI_TX_DATASWAP 0x34
+#define HSI_TX_FRAMELENX 0x80
+#define HSI_TX_BUFFERX 0xC0
+#define HSI_TX_BASEX 0x100
+#define HSI_TX_SPANX 0x140
+#define HSI_TX_GAUGEX 0x180
+#define HSI_TX_WATERMARKX 0x1C0
+#define HSI_TX_DMAEN 0x200
+#define HSI_TX_WATERMARKIS 0x204
+#define HSI_TX_WATERMARKIM 0x208
+#define HSI_TX_WATERMARKIC 0x20C
+#define HSI_TX_WATERMARKID 0x210
+#define HSI_TX_PERIPHID0 0xFE0
+#define HSI_TX_PERIPHID1 0xFE4
+#define HSI_TX_PERIPHID2 0xFE8
+#define HSI_TX_PERIPHID3 0xFEC
+
+
+/** HSIT register offsets */
+#define HSI_RX_ID 0x0
+#define HSI_RX_MODE 0x4
+#define HSI_RX_STATE 0x8
+#define HSI_RX_BUFSTATE 0xC
+#define HSI_RX_THRESHOLD 0x10
+#define HSI_RX_PARITY 0x14
+#define HSI_RX_DETECTOR 0x18
+#define HSI_RX_EXCEP 0x1C
+#define HSI_RX_ACK 0x20
+#define HSI_RX_CHANNELS 0x24
+#define HSI_RX_REALTIME 0x28
+#define HSI_RX_OVERRUN 0x2C
+#define HSI_RX_OVERRUNACK 0x30
+#define HSI_RX_PREAMBLE 0x34
+#define HSI_RX_PIPEGAUGE 0x38
+#define HSI_RX_TIMEOUT 0x3C
+#define HSI_RX_BUFFERX 0x80
+#define HSI_RX_FRAMELENX 0xC0
+#define HSI_RX_BASEX 0x100
+#define HSI_RX_SPANX 0x140
+#define HSI_RX_GAUGEX 0x180
+#define HSI_RX_WATERMARKX 0x1C0
+#define HSI_RX_DMAEN 0x200
+#define HSI_RX_WATERMARKIS 0x204
+#define HSI_RX_WATERMARKIM 0x208
+#define HSI_RX_WATERMARKIC 0x20C
+#define HSI_RX_WATERMARKID 0x210
+#define HSI_RX_OVERRUNMIS 0x214
+#define HSI_RX_OVERRUNIM 0x218
+#define HSI_RX_EXCEPMIS 0x21C
+#define HSI_RX_EXCEPIM 0x220
+#define HSI_RX_PERIPHID0 0xFE0
+#define HSI_RX_PERIPHID1 0xFE4
+#define HSI_RX_PERIPHID2 0xFE8
+#define HSI_RX_PERIPHID3 0xFEC
+
+/*
+ * Callbacks use by the HSI upper layer (HSI protocol) to receive data
+ * from the port channels.
+ */
+struct hsi_channel_ops {
+ void (*write_done) (struct hsi_device *dev);
+ void (*read_done) (struct hsi_device *dev);
+ void (*read)(struct hsi_channel *ch);
+ void (*write)(struct hsi_channel *ch);
+};
+
+struct hsi_data {
+ /* Pointer to the data to be sent/received */
+ void *addr;
+ /*
+ * Number of bytes to be sent or space reserved for data to be
+ * received.
+ */
+ unsigned int size;
+};
+
+#if 0
+struct hsi_tx_channel {
+ struct hsi_channel_ops ops;
+ struct hsi_data write_data;
+ struct hsi_dev *ctrlr;
+ u8 flags;
+ u8 channel_number;
+ spinlock_t hsi_ch_lock;
+ struct hsi_tx_device *dev;
+ void *priv;
+};
+
+struct hsi_rx_channel {
+ struct hsi_channel_ops ops;
+ struct hsi_data read_data;
+ struct hsi_data write_data;
+ struct hsi_dev *ctrlr;
+ u8 flags;
+ u8 channel_number;
+ spinlock_t hsi_ch_lock;
+ struct hsi_rx_device *dev;
+ void *priv;
+};
+#endif
+
+struct dma_chan;
+struct stedma40_chan_cfg;
+
+struct hsi_channel {
+ int id;
+ struct hsi_channel_ops ops;
+ struct hsi_data read_data;
+ struct hsi_data write_data;
+ struct hsi_dev *ctrlr;
+ u8 flags;
+ u8 channel_number;
+ u8 watermark;
+ u8 num_xfer_perintr;
+ struct dma_chan *dma_chan;
+ struct stedma40_chan_cfg *hsi_dma_info;
+ u8 span;
+ u8 n_bytes;
+ spinlock_t hsi_ch_lock;
+ struct hsi_device *dev;
+ struct tasklet_struct hsi_dma_tasklet;
+ void *priv;
+};
+
+
+/*
+ * Struct definition to hold information about hsi controller
+ */
+struct hsi_dev {
+ u8 dev_type; /** tx or rx */
+ u8 flags;
+ u8 max_ch;
+ u8 mode;
+ u8 irq1;
+ u8 irq2;
+ u8 irqexcep;
+ u8 irq_choverrun[HSI_MAX_CHANNELS];
+ void __iomem *regbase;
+ struct clk *clk;
+ spinlock_t lock;
+ u32 tx_wmark_intrstatus;
+ struct tasklet_struct hsi_tx_tasklet;
+ struct tasklet_struct hsi_rx_tasklet;
+ struct tasklet_struct hsi_rxexcep_tasklet;
+ struct hsi_channel hsi_tx_channels[HSI_MAX_CHANNELS];
+ struct hsi_channel hsi_rx_channels[HSI_MAX_CHANNELS];
+};
+
+struct hsi_ctrlr_excep{
+ struct hsi_dev *ctrlr;
+ unsigned int event;
+ void *priv;
+};
+
+int hsi_bus_init(void);
+void hsi_bus_exit(void);
+/* End HSI Bus */
+
+int hsi_read_interrupt_mode(struct hsi_channel *chnl);
+int hsi_write_interrupt_mode(struct hsi_channel *chnl);
+void hsi_cancel_write_interrupt_mode(struct hsi_channel *chnl);
+void hsi_cancel_read_interrupt_mode(struct hsi_channel *chnl);
+
+irqreturn_t hsi_tx_irq_handler(int irq, void *ctrlr);
+irqreturn_t hsi_rx_irq_handler(int irq, void *ctrlr);
+irqreturn_t hsi_rxexcep_irq_handler(int irq, void *ctrlr);
+
+void do_hsi_tx_tasklet(unsigned long ctrlr);
+void do_hsi_rx_tasklet(unsigned long ctrlr);
+void do_hsi_tx_dma_tasklet(unsigned long ctrlr);
+void do_hsi_rx_dma_tasklet(unsigned long ctrlr);
+void do_hsi_rxexcep_tasklet(unsigned long ctrlr);
+void hsi_u8_writer(struct hsi_channel *ch);
+void hsi_u8_reader(struct hsi_channel *ch);
+void hsi_u16_writer(struct hsi_channel *ch);
+void hsi_u16_reader(struct hsi_channel *ch);
+void hsi_u32_writer(struct hsi_channel *ch);
+void hsi_dma_read_eot_handler(void * data);
+void hsi_dma_write_eot_handler(void * data);
+
+void hsi_u32_reader(struct hsi_channel *ch);
+
+
+/*DMA Functions*/
+int hsi_read_dma_mode(struct hsi_channel *chnl);
+int hsi_write_dma_mode(struct hsi_channel *chnl);
+void hsi_cancel_write_dma_mode(struct hsi_channel *chnl);
+void hsi_cancel_read_dma_mode(struct hsi_channel *chnl);
+
+
+
+#endif
diff --git a/drivers/misc/hsi/hsi-legacy/hsi_driver_bus.c b/drivers/misc/hsi/hsi-legacy/hsi_driver_bus.c
new file mode 100644
index 00000000000..2ad781e3dad
--- /dev/null
+++ b/drivers/misc/hsi/hsi-legacy/hsi_driver_bus.c
@@ -0,0 +1,186 @@
+/*----------------------------------------------------------------------------------*/
+/* copyright STMicroelectronics, 2007. */
+/* */
+/* This program is free software; you can redistribute it and/or modify it under */
+/* the terms of the GNU General Public License as published by the Free */
+/* Software Foundation; either version 2.1 of the License, or (at your option) */
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but WITHOUT */
+/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS */
+/* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*----------------------------------------------------------------------------------*/
+
+#include <linux/device.h>
+#include "hsi_driver.h"
+
+/* LDM. defintions for the hsi bus, hsi device, and hsi_device driver */
+struct bus_type hsi_bus_type;
+
+static int modalias_show(struct device *dev, struct device_attribute *a,
+ char *buf)
+{
+ return snprintf(buf, BUS_ID_SIZE + 1, "%s%s\n", HSI_PREFIX,
+ dev->bus_id);
+}
+
+static struct device_attribute hsi_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
+static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ add_uevent_var(env, "MODALIAS=%s%s", HSI_PREFIX, dev->bus_id);
+ return 0;
+}
+
+/* NOTE: Function called in interrupt context */
+static int hsi_ex_handler(struct device_driver *drv, void *ex_event)
+{
+ struct hsi_ctrlr_excep *event = (struct hsi_ctrlr_excep *)ex_event;
+ struct hsi_device_driver *hsi_drv = to_hsi_device_driver(drv);
+ u8 id=0;
+
+ if ((hsi_drv->excep_event) &&
+ (test_bit(event->event, (const volatile unsigned long *)&hsi_drv->excep_mask)) &&
+ (test_bit(event->ctrlr->dev_type, (const volatile unsigned long *)&hsi_drv->ctrl_mask)) &&
+ (hsi_drv->ch_mask != 0)) {
+ if (event->priv) {
+ /** channel overrun - we pass the channel id as private data */
+ id = *(u8 *)event->priv;
+ if (test_bit(id,(const volatile unsigned long *)&hsi_drv->ch_mask))
+ /** callback for channel overrun */
+ (*hsi_drv->excep_event)(event->ctrlr->dev_type,
+ event->event, &id);
+ }
+ else
+ /** callback for everything except channel overrrun */
+ (*hsi_drv->excep_event)(event->ctrlr->dev_type,
+ event->event, event->priv);
+ }
+
+ return 0;
+}
+
+/* NOTE: Function called in interrupt context */
+int hsi_excep_handler(struct hsi_dev *hsi_ctrlr, unsigned int event, void *arg)
+{
+ int err = 0;
+ struct hsi_ctrlr_excep c_ex = {
+ .ctrlr = hsi_ctrlr,
+ .event = event,
+ .priv = arg
+ };
+
+ err = bus_for_each_drv(&hsi_bus_type, NULL, &c_ex, hsi_ex_handler);
+
+ return err;
+}
+
+static int hsi_bus_match(struct device *device, struct device_driver *driver)
+{
+ struct hsi_device *dev = to_hsi_device(device);
+ struct hsi_device_driver *drv = to_hsi_device_driver(driver);
+
+ if (!test_bit(dev->ctrlrid, (const volatile unsigned long *)&drv->ctrl_mask))
+ return 0;
+
+ if (!test_bit(dev->chid, (const volatile unsigned long *)&drv->ch_mask))
+ return 0;
+
+ return 1;
+}
+
+int hsi_bus_unreg_dev(struct device *device, void *p)
+{
+ device->release(device);
+ device_unregister(device);
+
+ return 0;
+}
+
+int __init hsi_bus_init(void)
+{
+ return bus_register(&hsi_bus_type);
+}
+
+void hsi_bus_exit(void)
+{
+ bus_for_each_dev(&hsi_bus_type, NULL, NULL, hsi_bus_unreg_dev);
+ bus_unregister(&hsi_bus_type);
+}
+
+static int hsi_driver_probe(struct device *dev)
+{
+ struct hsi_device_driver *drv = to_hsi_device_driver(dev->driver);
+
+ return drv->probe(to_hsi_device(dev));
+}
+
+static int hsi_driver_remove(struct device *dev)
+{
+ struct hsi_device_driver *drv = to_hsi_device_driver(dev->driver);
+
+ return drv->remove(to_hsi_device(dev));
+}
+
+static int hsi_driver_suspend(struct device *dev, pm_message_t mesg)
+{
+ struct hsi_device_driver *drv = to_hsi_device_driver(dev->driver);
+
+ return drv->suspend(to_hsi_device(dev), mesg);
+}
+
+static int hsi_driver_resume(struct device *dev)
+{
+ struct hsi_device_driver *drv = to_hsi_device_driver(dev->driver);
+
+ return drv->resume(to_hsi_device(dev));
+}
+
+struct bus_type hsi_bus_type = {
+ .name = "hsi",
+ .dev_attrs = hsi_dev_attrs,
+ .match = hsi_bus_match,
+ .uevent = hsi_bus_uevent,
+};
+
+/**
+ * register_hsi_driver - Register HSI device driver
+ * @driver - reference to the HSI device driver.
+ */
+int register_hsi_driver(struct hsi_device_driver *driver)
+{
+ int ret = 0;
+
+ if (driver == NULL) return -ENODEV;
+
+ driver->driver.bus = &hsi_bus_type;
+ if (driver->probe)
+ driver->driver.probe = hsi_driver_probe;
+ if (driver->remove)
+ driver->driver.remove = hsi_driver_remove;
+ if (driver->suspend)
+ driver->driver.suspend = hsi_driver_suspend;
+ if (driver->resume)
+ driver->driver.resume = hsi_driver_resume;
+
+ ret = driver_register(&driver->driver);
+
+ return ret;
+}
+EXPORT_SYMBOL(register_hsi_driver);
+
+/**
+ * unregister_hsi_driver - Unregister HSI device driver
+ * @driver - reference to the HSI device driver.
+ */
+void unregister_hsi_driver(struct hsi_device_driver *driver)
+{
+ if (driver != NULL) driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL(unregister_hsi_driver);
diff --git a/drivers/misc/hsi/hsi-legacy/hsi_driver_dma.c b/drivers/misc/hsi/hsi-legacy/hsi_driver_dma.c
new file mode 100644
index 00000000000..aad65120cdd
--- /dev/null
+++ b/drivers/misc/hsi/hsi-legacy/hsi_driver_dma.c
@@ -0,0 +1,250 @@
+/*----------------------------------------------------------------------------------*/
+/* copyright STMicroelectronics, 2007. */
+/* */
+/* This program is free software; you can redistribute it and/or modify it under */
+/* the terms of the GNU General Public License as published by the Free */
+/* Software Foundation; either version 2.1 of the License, or (at your option) */
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but WITHOUT */
+/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS */
+/* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*----------------------------------------------------------------------------------*/
+#include "hsi_driver.h"
+#include <linux/dmaengine.h>
+#include <linux/pfn.h>
+#include <plat/ste_dma40.h>
+
+void hsi_dma_write_eot_handler(void * data)
+{
+ struct hsi_channel *ch = (struct hsi_channel *)data;
+ struct hsi_dev* hsi_ctrlr;
+ volatile unsigned int dma_mask;
+ void __iomem* hsi_base;
+
+ /*printk("HSI TX dma callback issued ...\n");*/
+ hsi_ctrlr=ch->ctrlr;
+ hsi_base= hsi_ctrlr->regbase;
+
+ dma_mask =(0xff) & readl(hsi_base+HSI_TX_DMAEN);
+ writel((dma_mask & (~(1<<ch->channel_number))), hsi_base+HSI_TX_DMAEN);
+
+ /** restore the original watermark */
+ writel((0x1f & (ch->watermark -1)),(hsi_base+HSI_TX_WATERMARKX + (0x4*ch->channel_number)));
+
+ ch->write_data.addr = NULL;
+ ch->write_data.size = 0;
+
+ /** call the application callback */
+ tasklet_schedule(&ch->hsi_dma_tasklet);
+}
+
+void hsi_dma_read_eot_handler(void * data)
+{
+ struct hsi_channel *ch = (struct hsi_channel *)data;
+ struct hsi_dev* hsi_ctrlr;
+ volatile unsigned int dma_mask;
+ void __iomem* hsi_base;
+
+ /*printk("HSI RX dma callback issued ...\n");*/
+ hsi_ctrlr=ch->ctrlr;
+ hsi_base= hsi_ctrlr->regbase;
+
+ dma_mask =(0xff) & readl(hsi_base+HSI_RX_DMAEN);
+ writel((dma_mask & (~(1<<ch->channel_number))), hsi_base+HSI_RX_DMAEN);
+
+ /** restore the original watermark */
+ writel((0x1f & (ch->watermark -1)),(hsi_base+HSI_RX_WATERMARKX + (0x4*ch->channel_number)));
+
+ ch->read_data.addr = NULL;
+ ch->read_data.size = 0;
+
+ /** call the application callback */
+ tasklet_schedule(&ch->hsi_dma_tasklet);
+}
+
+int hsi_write_dma_mode(struct hsi_channel *ch)
+{
+ /*We Need to do Mem to Periph DMA*/
+ struct hsi_dev *hsi_ctrlr;
+ void __iomem* hsi_base;
+ void * dst_addr = NULL;
+ void * src_addr = NULL;
+ int count = 0;
+ volatile unsigned int dma_mask;
+ void* hsi_base_phy = (void *)0x8011C000;
+ struct dma_async_tx_descriptor *dmach_desc;
+ struct scatterlist sg;
+
+ hsi_ctrlr=ch->ctrlr;
+ hsi_base= hsi_ctrlr->regbase;
+
+ src_addr = ch->write_data.addr;
+ dst_addr = hsi_base_phy+HSI_TX_BUFFERX+(4*ch->channel_number);
+ count = ch->write_data.size;
+
+ if (ch->watermark <= 0x3) {
+ (void) stedma40_set_psize(ch->dma_chan, STEDMA40_PSIZE_LOG_1,
+ STEDMA40_PSIZE_LOG_1);
+
+ writel((0x1f & 0x0),(hsi_base+HSI_TX_WATERMARKX + (0x4*(ch->channel_number))));
+ }
+ else {
+ (void) stedma40_set_psize(ch->dma_chan, STEDMA40_PSIZE_LOG_4,
+ STEDMA40_PSIZE_LOG_4);
+
+ writel((0x1f & 0x3),(hsi_base+HSI_TX_WATERMARKX + (0x4*(ch->channel_number))));
+ }
+
+ sg_init_table(&sg, 1);
+ sg_set_page(&sg, pfn_to_page(PFN_DOWN((dma_addr_t) src_addr)), count,
+ offset_in_page(src_addr));
+ sg_dma_address(&sg) = (dma_addr_t) src_addr;
+ sg_dma_len(&sg) = count;
+
+ dmach_desc = ch->dma_chan->device->
+ device_prep_slave_sg(ch->dma_chan, &sg, 1, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!dmach_desc)
+ return -ENOMEM;
+
+ dmach_desc->callback = hsi_dma_write_eot_handler;
+ dmach_desc->callback_param = ch;
+ dmach_desc->tx_submit(dmach_desc);
+ dma_async_issue_pending(ch->dma_chan);
+
+ /*Enable DMA bits of HSI controller*/
+ dma_mask =(0xff) & readl(hsi_base+HSI_TX_DMAEN);
+ writel((dma_mask | (1<<ch->channel_number)), hsi_base+HSI_TX_DMAEN);
+
+ return 0;
+}
+
+int hsi_read_dma_mode(struct hsi_channel *ch)
+{
+ /*We Need to do Periph to Mem DMA*/
+ struct hsi_dev *hsi_ctrlr;
+ void __iomem* hsi_base;
+ void * dst_addr = NULL;
+ void * src_addr = NULL;
+ int count = 0;
+ volatile unsigned int dma_mask;
+ void *hsi_base_phy=(void *)0x8011B000;
+ struct dma_async_tx_descriptor *dmach_desc;
+ struct scatterlist sg;
+
+ hsi_ctrlr=ch->ctrlr;
+ hsi_base= hsi_ctrlr->regbase;
+
+ src_addr = hsi_base_phy+HSI_RX_BUFFERX+(4*ch->channel_number);
+ dst_addr = ch->read_data.addr;
+ count = ch->read_data.size;
+
+ /** sync up the watermark and burst size */
+ if (ch->watermark <= 0x3) {
+ (void) stedma40_set_psize(ch->dma_chan, STEDMA40_PSIZE_LOG_1,
+ STEDMA40_PSIZE_LOG_1);
+
+ writel((0x1f & 0x0),(hsi_base+HSI_RX_WATERMARKX + (0x4*(ch->channel_number))));
+ }
+ else {
+ (void) stedma40_set_psize(ch->dma_chan, STEDMA40_PSIZE_LOG_4,
+ STEDMA40_PSIZE_LOG_4);
+
+ writel((0x1f & 0x3),(hsi_base+HSI_RX_WATERMARKX + (0x4*(ch->channel_number))));
+ }
+
+ sg_init_table(&sg, 1);
+ sg_set_page(&sg, pfn_to_page(PFN_DOWN((dma_addr_t) dst_addr)), count,
+ offset_in_page(dst_addr));
+ sg_dma_address(&sg) = (dma_addr_t) dst_addr;
+ sg_dma_len(&sg) = count;
+
+ dmach_desc = ch->dma_chan->device->
+ device_prep_slave_sg(ch->dma_chan, &sg, 1, DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!dmach_desc)
+ return -ENOMEM;
+
+ dmach_desc->callback = hsi_dma_read_eot_handler;
+ dmach_desc->callback_param = ch;
+ dmach_desc->tx_submit(dmach_desc);
+ dma_async_issue_pending(ch->dma_chan);
+
+ /*Enable DMA bits of HSI controller*/
+ dma_mask =(0xff) & readl(hsi_base+HSI_RX_DMAEN);
+ writel((dma_mask | (1<<ch->channel_number)), hsi_base+HSI_RX_DMAEN);
+
+ return 0;
+}
+
+void hsi_cancel_write_dma_mode(struct hsi_channel *ch)
+{
+ struct hsi_dev *hsi_ctrlr;
+ void __iomem* hsi_base;
+ volatile unsigned int dma_mask;
+
+ hsi_ctrlr=ch->ctrlr;
+ hsi_base= hsi_ctrlr->regbase;
+
+ ch->dma_chan->device->device_control(ch->dma_chan,
+ DMA_TERMINATE_ALL, 0);
+
+ /*Disable DMA nebaling bits of HSI controller*/
+ dma_mask =(0xff) & readl(hsi_base+HSI_TX_DMAEN);
+ writel((dma_mask & (~(1<<ch->channel_number))), hsi_base+HSI_TX_DMAEN);
+ /** flush the transmit channel buffers */
+ writel((readl(hsi_base+HSI_TX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),hsi_base+HSI_TX_BUFSTATE);
+ /** restore the original watermark */
+ writel((0x1f & (ch->watermark -1)),(hsi_base+HSI_TX_WATERMARKX + (0x4*ch->channel_number)));
+ ch->write_data.addr = NULL;
+ ch->write_data.size = 0;
+}
+
+void hsi_cancel_read_dma_mode(struct hsi_channel *ch)
+{
+ struct hsi_dev *hsi_ctrlr;
+ void __iomem* hsi_base;
+ volatile unsigned int dma_mask;
+
+ hsi_ctrlr=ch->ctrlr;
+ hsi_base= hsi_ctrlr->regbase;
+
+ ch->dma_chan->device->device_control(ch->dma_chan,
+ DMA_TERMINATE_ALL, 0);
+
+ /*Disable DMA nebaling bits of HSI controller*/
+ dma_mask =(0xff) & readl(hsi_base+HSI_RX_DMAEN);
+ writel((dma_mask & (~(1<<ch->channel_number))), hsi_base+HSI_RX_DMAEN);
+ /** flush the receive channel buffers */
+ writel((readl(hsi_base+HSI_RX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),hsi_base+HSI_RX_BUFSTATE);
+ /** restore the original watermark */
+ writel((0x1f & (ch->watermark -1)),(hsi_base+HSI_RX_WATERMARKX + (0x4*ch->channel_number)));
+
+ ch->read_data.addr=NULL;
+ ch->read_data.size=0;
+}
+
+void do_hsi_tx_dma_tasklet(unsigned long param)
+{
+ struct hsi_channel *ch = (struct hsi_channel*)param;
+
+ ch->ops.write_done(ch->dev);
+
+}
+EXPORT_SYMBOL(do_hsi_tx_dma_tasklet);
+
+void do_hsi_rx_dma_tasklet(unsigned long param)
+{
+ struct hsi_channel *ch = (struct hsi_channel*)param;
+
+ ch->ops.read_done(ch->dev);
+
+}
+EXPORT_SYMBOL(do_hsi_rx_dma_tasklet);
+
diff --git a/drivers/misc/hsi/hsi-legacy/hsi_driver_if.c b/drivers/misc/hsi/hsi-legacy/hsi_driver_if.c
new file mode 100644
index 00000000000..722bd66b8cb
--- /dev/null
+++ b/drivers/misc/hsi/hsi-legacy/hsi_driver_if.c
@@ -0,0 +1,503 @@
+/*----------------------------------------------------------------------------------*/
+/* copyright STMicroelectronics, 2007. */
+/* */
+/* This program is free software; you can redistribute it and/or modify it under */
+/* the terms of the GNU General Public License as published by the Free */
+/* Software Foundation; either version 2.1 of the License, or (at your option) */
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but WITHOUT */
+/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS */
+/* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*----------------------------------------------------------------------------------*/
+
+#include "hsi_driver.h"
+#include "linux/delay.h"
+
+//#define HSI_POLLING
+
+/**
+ * hsi_open - open a hsi device channel.
+ * @dev: Reference to the hsi device channel to be openned.
+ *
+ * Returns 0 on success, -EINVAL on bad parameters, -EBUSY if is already opened.
+ */
+int hsi_open(struct hsi_device *dev)
+{
+ struct hsi_channel *ch;
+ struct hsi_dev *hsi_ctrlr;
+ void __iomem *hsi_base;
+
+ if (!dev || !dev->ch) {
+ printk("Wrong HSI device %p\n", dev);
+ return -EINVAL;
+ }
+
+ ch = dev->ch;
+ if (!ch->ops.read_done && !ch->ops.write_done) {
+ printk("Trying to open with no callbacks registered\n");
+ return -EINVAL;
+ }
+ hsi_ctrlr = ch->ctrlr;
+ spin_lock_bh(&ch->hsi_ch_lock);
+ if (ch->flags & HSI_CH_OPEN) {
+ printk(" Controller %d Channel %d already OPENED\n",
+ dev->ctrlrid, dev->chid);
+ spin_unlock_bh(&ch->hsi_ch_lock);
+ return -EBUSY;
+ }
+ clk_enable(hsi_ctrlr->clk);
+ ch->flags |= HSI_CH_OPEN;
+ hsi_base=hsi_ctrlr->regbase;
+ if (hsi_ctrlr->dev_type == 0x0) /** HSI transmit controller*/
+ /** flush the transmit buffer */
+ writel((readl(hsi_base+HSI_TX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),hsi_base+HSI_TX_BUFSTATE);
+ else
+ writel((readl(hsi_base+HSI_RX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),hsi_base+HSI_RX_BUFSTATE);
+
+ spin_unlock_bh(&ch->hsi_ch_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(hsi_open);
+
+/**
+ * hsi_write - write data into the hsi device channel
+ * @dev: reference to the hsi device channel to write into.
+ * @data: pointer to a 32-bit word data to be written.
+ * @datawidth: in bits (16bit or 32bit or ....)
+ * @count: total number of bytes to be written.
+ *
+ * Return 0 on sucess, a negative value on failure.
+ * A success values only indicates that the request has been accepted.
+ * Transfer is only completed when the write_done callback is called.
+ *
+ */
+int hsi_write(struct hsi_device *dev, void *data, u32 datawidth, unsigned int count)
+{
+ struct hsi_channel *ch;
+ int err;
+
+ if (dev->ctrlrid != 0x0) {
+ printk("HSI Controller not enabled for write\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(!dev || !dev->ch || !data || (count <= 0))) {
+ printk( "Wrong paramenters "
+ "hsi_device %p data %p count %d", dev, data, count);
+ return -EINVAL;
+ }
+
+ if (unlikely(!(dev->ch->flags & HSI_CH_OPEN))) {
+ printk("HSI device NOT open\n");
+ return -EINVAL;
+ }
+
+ ch = dev->ch;
+ spin_lock_bh(&ch->hsi_ch_lock);
+ ch->write_data.addr = data;
+ ch->write_data.size = count;
+
+ if (datawidth <=8) {
+ /*printk("HSI: <= 8 bits per word \n");*/
+ ch->n_bytes = 1;
+ ch->ops.write = hsi_u8_writer;
+ } else if (datawidth <= 16) {
+ /*printk("HSI: <= 16 bits per word \n");*/
+ ch->n_bytes = 2;
+ ch->ops.write = hsi_u16_writer;
+ } else {
+ /*printk("HSI: <= 32 bits per word \n");*/
+ ch->n_bytes = 4;
+ ch->ops.write = hsi_u32_writer;
+ }
+
+ ch->num_xfer_perintr = ch->watermark ;
+
+ if(dev->curr_mode == HSI_INTERRUPT_MODE)
+ err = hsi_write_interrupt_mode(ch);
+ else if(dev->curr_mode == HSI_DMA_MODE) {
+ err = hsi_write_dma_mode(ch);
+ }
+ else {
+ printk("HSI POLLING MODE NOT implemented \n");
+ err = -EINVAL;
+ /*FIXME: polling not yet there*/
+ }
+
+ if (unlikely(err < 0)) {
+ ch->write_data.addr = NULL;
+ ch->write_data.size = 0;
+ }
+ spin_unlock_bh(&ch->hsi_ch_lock);
+
+ return err;
+
+}
+EXPORT_SYMBOL(hsi_write);
+
+/**
+ * hsi_read - read data from the hsi device channel
+ * @dev: hsi device channel reference to read data from.
+ * @data: pointer to a 32-bit word data to store the data.
+ * @count: number of 32-bit word to be stored.
+ *
+ * Return 0 on sucess, a negative value on failure.
+ * A success values only indicates that the request has been accepted.
+ * Data is only available in the buffer when the read_done callback is called.
+ *
+ */
+int hsi_read(struct hsi_device *dev, void* data, u32 datawidth, unsigned int count)
+{
+ struct hsi_channel *ch;
+ int err=0;
+ /** for POLLING MODE */
+ unsigned int loop=0;
+ struct hsi_dev *hsi_ctrlr=NULL ;
+ volatile void __iomem *hsi_base=NULL ;
+
+ if (dev->ctrlrid != 0x1) {
+ printk("HSI Controller not enabled for read\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(!dev || !dev->ch || !data || (count <= 0))) {
+ printk("Wrong paramenters "
+ "hsi_device %p data %p count %d", dev, data, count);
+ return -EINVAL;
+ }
+ if (unlikely(!(dev->ch->flags & HSI_CH_OPEN))) {
+ printk("HSI device NOT open\n");
+ return -EINVAL;
+ }
+
+ ch = dev->ch;
+ spin_lock_bh(&ch->hsi_ch_lock);
+ ch->read_data.addr = data;
+ ch->read_data.size = count;
+
+ if (datawidth <=8) {
+ /*printk("HSI: <= 8 bits per word \n");*/
+ ch->n_bytes = 1;
+ ch->ops.read= hsi_u8_reader;
+ } else if (datawidth <= 16) {
+ /*printk("HSI: <= 16 bits per word \n");*/
+ ch->n_bytes = 2;
+ ch->ops.read= hsi_u16_reader;
+ } else {
+ /*printk("HSI: <= 32 bits per word \n");*/
+ ch->n_bytes = 4;
+ ch->ops.read= hsi_u32_reader;
+ }
+
+ ch->num_xfer_perintr = ch->watermark;
+
+ if(dev->curr_mode == HSI_INTERRUPT_MODE)
+ err = hsi_read_interrupt_mode(ch);
+ else if(dev->curr_mode == HSI_DMA_MODE) {
+ err = hsi_read_dma_mode(ch);
+ }
+ else {
+ /** POLLING mode start*/
+ hsi_ctrlr=ch->ctrlr;
+ hsi_base = hsi_ctrlr->regbase;
+ printk("hsi_read : channel %d regbase 0x%p\n",ch->channel_number,hsi_base);
+ while (!((readl(hsi_base+HSI_RX_BUFSTATE)) & (1<<ch->channel_number))
+ && (loop < 50000)) {
+ loop++;
+ mdelay(1);
+ }
+
+ if (loop >=50000)
+ printk("HSI_READ: NO DATA VIA POLLING\n");
+ else
+ printk("HSI_READ: RECEIVED DATA VIA POLLING\n");
+ /** POLLING mode end*/
+
+ }
+
+ if (unlikely(err < 0)) {
+ ch->read_data.addr = NULL;
+ ch->read_data.size = 0;
+ }
+ spin_unlock_bh(&ch->hsi_ch_lock);
+
+ return err;
+}
+EXPORT_SYMBOL(hsi_read);
+
+void __hsi_write_cancel(struct hsi_channel *ch, int mode)
+{
+ if(mode == HSI_INTERRUPT_MODE)
+ hsi_cancel_write_interrupt_mode(ch);
+ else if(mode == HSI_DMA_MODE)
+ hsi_cancel_write_dma_mode(ch);
+ else
+ printk("HSI read cancel Incorrect Mode \n"); /*FIXME: No Polling Mode Yet*/
+}
+
+/**
+ * hsi_write_cancel - Cancel pending write request.
+ * @dev: hsi device channel where to cancel the pending write.
+ *
+ * write_done() callback will not be called after sucess of this function.
+ * This call closes the channel also.
+ */
+void hsi_write_cancel(struct hsi_device *dev)
+{
+ struct hsi_channel *ch;
+
+ if (dev->ctrlrid != 0x0) {
+ printk("HSI Controller not enabled for write\n");
+ return;
+ }
+
+ if (unlikely(!dev || !dev->ch)) {
+ printk("Wrong HSI device %p\n", dev);
+ return;
+ }
+ if (unlikely(!(dev->ch->flags & HSI_CH_OPEN))) {
+ printk("HSI device NOT open\n");
+ return;
+ }
+
+ ch=dev->ch;
+ spin_lock_bh(&ch->hsi_ch_lock);
+ __hsi_write_cancel(ch, dev->curr_mode);
+ dev->ch->flags &= ~HSI_CH_OPEN;
+ spin_unlock_bh(&ch->hsi_ch_lock);
+}
+EXPORT_SYMBOL(hsi_write_cancel);
+
+void __hsi_read_cancel(struct hsi_channel *ch, int mode)
+{
+ if(mode == HSI_INTERRUPT_MODE)
+ hsi_cancel_read_interrupt_mode(ch);
+ else if(mode == HSI_DMA_MODE)
+ hsi_cancel_read_dma_mode(ch);
+ else
+ printk("HSI read cancel Incorrect Mode \n"); /*FIXME: No Polling Mode Yet*/
+}
+
+
+/**
+ * hsi_read_cancel - Cancel pending read request.
+ * @dev: hsi device channel where to cancel the pending read.
+ *
+ * read_done() callback will not be called after sucess of this function.
+ */
+void hsi_read_cancel(struct hsi_device *dev)
+{
+ struct hsi_channel *ch;
+
+ if (dev->ctrlrid != 0x1) {
+ printk("HSI Controller not enabled for read\n");
+ return;
+ }
+
+ if (unlikely(!dev || !dev->ch)) {
+ printk("Wrong HSI device %p\n", dev);
+ return;
+ }
+
+ if (unlikely(!(dev->ch->flags & HSI_CH_OPEN))) {
+ printk("HSI device NOT open\n");
+ return;
+ }
+
+ ch=dev->ch;
+ spin_lock_bh(&ch->hsi_ch_lock);
+ __hsi_read_cancel(dev->ch, dev->curr_mode);
+ dev->ch->flags &= ~HSI_CH_OPEN;
+ spin_unlock_bh(&ch->hsi_ch_lock);
+}
+EXPORT_SYMBOL(hsi_read_cancel);
+
+
+/**
+ * hsi_close - close given hsi device channel
+ * @dev: reference to hsi device channel.
+ */
+void hsi_close(struct hsi_device *dev)
+{
+ struct hsi_channel *ch;
+ void __iomem *hsi_base;
+ struct hsi_dev *hsi_ctrlr;
+
+ if (!dev || !dev->ch) {
+ printk("Trying to close wrong HSI device %p\n", dev);
+ return;
+ }
+
+ ch=dev->ch;
+ hsi_ctrlr=ch->ctrlr;
+ hsi_base=hsi_ctrlr->regbase;
+
+ spin_lock_bh(&ch->hsi_ch_lock);
+
+ if (ch->flags & HSI_CH_OPEN) {
+ dev->ch->flags &= ~HSI_CH_OPEN;
+ if (hsi_ctrlr->dev_type == 0x0) /** HSIT */ {
+ /** flush the transmit channel buffers */
+ writel((readl(hsi_base+HSI_TX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),hsi_base+HSI_TX_BUFSTATE);
+ } else {
+ /** flush the receive channel buffers */
+ writel((readl(hsi_base+HSI_RX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),hsi_base+HSI_RX_BUFSTATE);
+ }
+ clk_disable(hsi_ctrlr->clk);
+ }
+ else
+ printk("Trying to close an unopened HSI device : ctrlr %d chnl %d \n",dev->ctrlrid,dev->chid);
+
+ spin_unlock_bh(&ch->hsi_ch_lock);
+}
+EXPORT_SYMBOL(hsi_close);
+
+/**
+ * hsi_dev_set_cb - register read_done() and write_done() callbacks.
+ * @dev: reference to hsi device channel where callbacks are associated.
+ * @r_cb: callback to signal read transfer completed.
+ * @w_cb: callback to signal write transfer completed.
+ */
+void hsi_dev_set_cb(struct hsi_device *dev, void (*r_cb)(struct hsi_device *dev)
+ , void (*w_cb)(struct hsi_device *dev))
+{
+ struct hsi_channel *ch;
+
+ if (unlikely(!dev || !dev->ch)) {
+ printk("Wrong HSI device %p\n", dev);
+ return;
+ }
+
+ if (unlikely(!r_cb && !w_cb)) {
+ printk("HSI no valid callbacks supplied\n");
+ return;
+ }
+
+ ch=dev->ch;
+ spin_lock_bh(&ch->hsi_ch_lock);
+ dev->ch->ops.read_done = r_cb;
+ dev->ch->ops.write_done = w_cb;
+ spin_unlock_bh(&ch->hsi_ch_lock);
+}
+EXPORT_SYMBOL(hsi_dev_set_cb);
+
+/**
+ * hsi_ioctl - HSI I/O control
+ * @dev: hsi device channel reference to apply the I/O control (or port associated to it)
+ * @command: HSI I/O control command
+ * @arg: parameter associated to the control command. NULL, if no parameter.
+ *
+ * Return 0 on sucess, a negative value on failure.
+ *
+ */
+int hsi_ioctl(struct hsi_device *dev, unsigned int command, void *arg)
+{
+ struct hsi_channel *ch;
+ struct hsi_dev *hsi_ctrlr;
+ void __iomem *hsi_base;
+ int err = 0;
+
+ if (!dev || !dev->ch) {
+ printk("Wrong HSI device %p\n", dev);
+ return -EINVAL;
+ }
+
+ ch = dev->ch;
+ hsi_ctrlr = ch->ctrlr;
+
+ if (unlikely(!(dev->ch->flags & HSI_CH_OPEN))) {
+ printk("HSI device NOT open\n");
+ return -EINVAL;
+ }
+
+ spin_lock_bh(&ch->hsi_ch_lock);
+
+ hsi_base=hsi_ctrlr->regbase;
+
+ switch (command) {
+ case HSI_IOCTL_SET_WATERMARK:
+ /** TODO: check span definition. Manual says (span-1) is actual span value
+ * and the watermark should be less than span (span -1)
+ */
+ if (*(u32*)arg > (ch->span -2)) {
+ printk("HSI IOCTL: illegal watermark value > span\n");
+ spin_unlock_bh(&ch->hsi_ch_lock);
+ return -EINVAL;
+ }
+ ch->watermark = *(u32*)arg;
+ /*printk("HSI IOCTL: setting watermark value \n");*/
+ if (hsi_ctrlr->dev_type == 0x0) /** HSI transmit controller*/
+ writel((0x1f & ((*(u32*)arg)-1)),(hsi_base+
+ HSI_TX_WATERMARKX + (0x4*ch->channel_number)));
+ else
+ writel((0x1f & ((*(u32*)arg)-1)),(hsi_base+
+ HSI_RX_WATERMARKX + (0x4*ch->channel_number)));
+ break;
+ case HSI_IOCTL_GET_WATERMARK:
+ printk("HSI IOCTL: getting watermark value \n");
+ if (hsi_ctrlr->dev_type == 0x0) /** HSI transmit controller*/
+ /** add 1 to the value read from register for actual watermark */
+ *((u32*)arg) = (0x1F & (readl(hsi_base+ HSI_TX_WATERMARKX + (0x4*ch->channel_number))))+1;
+ else
+ *((u32*)arg) = (0x1F & (readl(hsi_base+ HSI_RX_WATERMARKX + (0x4*ch->channel_number))))+1;
+ break;
+ case HSI_IOCTL_GET_CURRMODE:
+ printk("HSI IOCTL: Getting the current mode for transfer\n");
+ *((u32*)arg) = dev->curr_mode;
+ break;
+ case HSI_IOCTL_SET_CURRMODE:
+ /*printk("HSI IOCTL: Setting the current mode \
+ for transfer\n");*/
+ dev->curr_mode = *((u32*)arg);
+ break;
+ case HSI_IOCTL_SEND_BREAK:
+ writel(0x1,hsi_base+HSI_TX_BREAK);
+ break;
+ case HSI_IOCTL_SET_FRAMELEN:
+ if ((*(u32*)arg) > HSI_MAX_FRAMELEN) {
+ printk("HSI IOCTL: Illegal framelen setting \n");
+ spin_unlock_bh(&ch->hsi_ch_lock);
+ return -EINVAL;
+ }
+ /*printk("HSI IOCTL: Setting the framelen for transfer\n");*/
+ if (hsi_ctrlr->dev_type == 0x0) /** HSI transmit controller*/
+ writel((0x1f & ((*(u32*)arg)-1)),(hsi_base+
+ HSI_TX_FRAMELENX + (0x4*ch->channel_number)));
+ else
+ writel((0x1f & ((*(u32*)arg)-1)),(hsi_base+
+ HSI_RX_FRAMELENX + (0x4*ch->channel_number)));
+ break;
+ case HSI_IOCTL_GET_FRAMELEN:
+ printk("HSI IOCTL: getting framelen value \n");
+ if (hsi_ctrlr->dev_type == 0x0) /** HSI transmit controller*/
+ /** add 1 to the value read from register for actual framelen */
+ *((u32*)arg) = (0x1F & (readl(hsi_base+ HSI_TX_FRAMELENX + (0x4*ch->channel_number))))+1;
+ else
+ *((u32*)arg) = (0x1F & (readl(hsi_base+ HSI_RX_FRAMELENX + (0x4*ch->channel_number))))+1;
+ break;
+
+ case HSI_IOCTL_SET_THRESHOLD:
+ printk("HSI IOCTL: Setting threshold for detecting BREAK transmission\n");
+ writel((0x3f & (*(u32*)arg)),(hsi_base+HSI_RX_THRESHOLD));
+ break;
+
+ default:
+ err = -ENOIOCTLCMD;
+ break;
+ }
+
+ spin_unlock_bh(&ch->hsi_ch_lock);
+ return err;
+}
+EXPORT_SYMBOL(hsi_ioctl);
+
+
diff --git a/drivers/misc/hsi/hsi-legacy/hsi_driver_int.c b/drivers/misc/hsi/hsi-legacy/hsi_driver_int.c
new file mode 100644
index 00000000000..3ae93be697a
--- /dev/null
+++ b/drivers/misc/hsi/hsi-legacy/hsi_driver_int.c
@@ -0,0 +1,481 @@
+/*----------------------------------------------------------------------------------*/
+/* copyright STMicroelectronics, 2007. */
+/* */
+/* This program is free software; you can redistribute it and/or modify it under */
+/* the terms of the GNU General Public License as published by the Free */
+/* Software Foundation; either version 2.1 of the License, or (at your option) */
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but WITHOUT */
+/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS */
+/* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*----------------------------------------------------------------------------------*/
+
+#include "hsi_driver.h"
+
+static void reset_ch_read(struct hsi_channel *ch)
+{
+ ch->read_data.addr = NULL;
+ ch->read_data.size = 0;
+}
+
+static void reset_ch_write(struct hsi_channel *ch)
+{
+ ch->write_data.addr = NULL;
+ ch->write_data.size = 0;
+}
+
+int hsi_write_interrupt_mode(struct hsi_channel *ch)
+{
+ struct hsi_dev *hsi_ctrlr;
+ void __iomem* hsi_base;
+ volatile unsigned int wmark_intrmask;
+
+ hsi_ctrlr=ch->ctrlr;
+ hsi_base= hsi_ctrlr->regbase;
+
+ /** watermark fixed to count-1 entries */
+ //writel((0x1f & ((ch->write_data.size)-1)),(hsi_base+ HSI_TX_WATERMARKX + (0x4*ch->channel_number)));
+ /** enable the corresponding channel intr mask */
+ wmark_intrmask=(0xff) & readl(hsi_base+HSI_TX_WATERMARKIM);
+ writel((wmark_intrmask | (1<<ch->channel_number)), hsi_base+HSI_TX_WATERMARKIM);
+
+ return 0;
+}
+
+int hsi_read_interrupt_mode(struct hsi_channel *ch)
+{
+ struct hsi_dev *hsi_ctrlr;
+ void __iomem* hsi_base;
+ volatile unsigned int wmark_intrmask;
+
+ hsi_ctrlr=ch->ctrlr;
+ hsi_base= hsi_ctrlr->regbase;
+
+ /** watermark fixed to count-1 entries - not required as watermark is fixed */
+ // writel((0x1f & ((ch->read_data.size)-1)),(hsi_base+ HSI_RX_WATERMARKX + (0x4*ch->channel_number)));
+
+ /** enable the corresponding channel intr mask */
+ wmark_intrmask=(0xff) & readl(hsi_base+HSI_RX_WATERMARKIM);
+ writel((wmark_intrmask | (1<<ch->channel_number)), hsi_base+HSI_RX_WATERMARKIM);
+
+ return 0;
+}
+
+void hsi_cancel_write_interrupt_mode(struct hsi_channel *ch)
+{
+
+ struct hsi_dev *hsi_ctrlr;
+ void __iomem* hsi_base;
+ volatile unsigned int wmark_intrmask;
+
+ hsi_ctrlr=ch->ctrlr;
+ hsi_base= hsi_ctrlr->regbase;
+ /** reset watermark to high number,say 4 */
+ //writel((0x1f & 0x3),(hsi_base+ HSI_TX_WATERMARKX + (0x4*ch->channel_number)));
+ /** disable the corresponding channel intr mask */
+ wmark_intrmask=(0xff) & readl(hsi_base+HSI_TX_WATERMARKIM);
+ writel((wmark_intrmask & ~(1<<ch->channel_number)), hsi_base+HSI_TX_WATERMARKIM);
+ /** write the original watermark */
+ writel((0x1f & (ch->watermark -1)),(hsi_base+HSI_TX_WATERMARKX + (0x4*ch->channel_number)));
+ /** flush the transmit channel buffers */
+ writel((readl(hsi_base+HSI_TX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),hsi_base+HSI_TX_BUFSTATE);
+
+ reset_ch_write(ch);
+
+}
+
+void hsi_cancel_read_interrupt_mode(struct hsi_channel *ch)
+{
+ struct hsi_dev *hsi_ctrlr;
+ void __iomem* hsi_base;
+ volatile unsigned int wmark_intrmask;
+
+ hsi_ctrlr=ch->ctrlr;
+ hsi_base= hsi_ctrlr->regbase;
+ /** reset watermark to high number,say 4 */
+ //writel((0x1f & 0x3),(hsi_base+ HSI_RX_WATERMARKX + (0x4*ch->channel_number)));
+
+ /** disable the corresponding channel intr mask */
+ wmark_intrmask=(0xff) & readl(hsi_base+HSI_RX_WATERMARKIM);
+ writel((wmark_intrmask & ~(1<<ch->channel_number)), hsi_base+HSI_RX_WATERMARKIM);
+ /** write the original watermark */
+ writel((0x1f & (ch->watermark -1)),(hsi_base+HSI_RX_WATERMARKX + (0x4*ch->channel_number)));
+ /** flush the receive channel buffers */
+ writel((readl(hsi_base+HSI_RX_BUFSTATE) &
+ ~((unsigned long)(1 << ch->channel_number))),hsi_base+HSI_RX_BUFSTATE);
+ reset_ch_read(ch);
+}
+
+/**
+ * hsi_u8_writer - Write FIFO data in Data register as a 8 Bit Data
+ *
+ * This function writes data in Tx FIFO till it is not full
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary write ptr tx in drv_data which maintains
+ * current write position in transfer buffer
+ */
+void hsi_u8_writer(struct hsi_channel *ch)
+{
+ struct hsi_dev *hsi_ctrlr = ch->ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ int i=0;
+
+
+ spin_lock(&ch->hsi_ch_lock);
+ if (ch->write_data.addr) {
+ //while ((i< (ch->num_xfer_perintr)) && (ch->write_data.size)) {
+ while (!((readl(hsi_base+HSI_TX_BUFSTATE)) & (1<<ch->channel_number)) && (ch->write_data.size)) {
+ writel(*(u8 *)(ch->write_data.addr), hsi_base+HSI_TX_BUFFERX+(4*ch->channel_number));
+ ch->write_data.addr = ch->write_data.addr + ch->n_bytes;
+ ch->write_data.size = ch->write_data.size - ch->n_bytes;
+ i++;
+ }
+ if (ch->write_data.size == 0x0)
+ reset_ch_write(ch);
+ }
+ spin_unlock(&ch->hsi_ch_lock);
+}
+
+/**
+ * hsi_u8_reader - Read FIFO data in Data register as a 8 Bit Data
+ *
+ * This function reads data in Rx FIFO till it is not empty
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary Read ptr rx in drv_data which maintains
+ * current read position in transfer buffer
+ */
+void hsi_u8_reader(struct hsi_channel *ch)
+{
+ struct hsi_dev *hsi_ctrlr = ch->ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ int i=0;
+
+
+ spin_lock(&ch->hsi_ch_lock);
+ if (ch->read_data.addr) {
+ //while ((i< (ch->num_xfer_perintr)) && (ch->read_data.size)) {
+ while (((readl(hsi_base+HSI_RX_BUFSTATE)) & (1<<ch->channel_number)) && (ch->read_data.size)) {
+ *(u8 *)(ch->read_data.addr) = readl(hsi_base+HSI_RX_BUFFERX+(4*ch->channel_number));
+ /** printk("HSI RX: data 0x%x arrived \n",*(u8 *)(ch->read_data.addr));*/
+ ch->read_data.addr = ch->read_data.addr + ch->n_bytes;
+ ch->read_data.size = ch->read_data.size - ch->n_bytes;
+ i++;
+ }
+ if (ch->read_data.size == 0x0)
+ reset_ch_read(ch);
+ }
+ spin_unlock(&ch->hsi_ch_lock);
+}
+
+/**
+ * hsi_u16_writer - Write FIFO data in Data register as a 16 Bit Data
+ *
+ * This function writes data in Tx FIFO till it is not full
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary write ptr tx in drv_data which maintains
+ * current write position in transfer buffer
+ */
+void hsi_u16_writer(struct hsi_channel *ch)
+{
+ struct hsi_dev *hsi_ctrlr = ch->ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ int i=0;
+
+
+ spin_lock(&ch->hsi_ch_lock);
+ if (ch->write_data.addr) {
+ //while ((i< (ch->num_xfer_perintr)) && (ch->write_data.size)) {
+ while (!((readl(hsi_base+HSI_TX_BUFSTATE)) & (1<<ch->channel_number)) && (ch->write_data.size)) {
+ writel(*(u16 *)(ch->write_data.addr), hsi_base+HSI_TX_BUFFERX+(4*ch->channel_number));
+ ch->write_data.addr = ch->write_data.addr + ch->n_bytes;
+ ch->write_data.size = ch->write_data.size - ch->n_bytes;
+ i++;
+ }
+ if (ch->write_data.size == 0x0)
+ reset_ch_write(ch);
+ }
+ spin_unlock(&ch->hsi_ch_lock);
+}
+
+
+/**
+ * hsi_u16_reader - Read FIFO data in Data register as a 16 Bit Data
+ *
+ * This function reads data in Rx FIFO till it is not empty
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary Read ptr rx in drv_data which maintains
+ * current read position in transfer buffer
+ */
+void hsi_u16_reader(struct hsi_channel *ch)
+{
+ struct hsi_dev *hsi_ctrlr = ch->ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ int i=0;
+
+
+ spin_lock(&ch->hsi_ch_lock);
+ if (ch->read_data.addr) {
+ //while ((i< (ch->num_xfer_perintr)) && (ch->read_data.size)) {
+ while (((readl(hsi_base+HSI_RX_BUFSTATE)) & (1<<ch->channel_number)) && (ch->read_data.size)) {
+ *(u16 *)(ch->read_data.addr) = readl(hsi_base+HSI_RX_BUFFERX+(4*ch->channel_number));
+ /** printk("HSI RX: data 0x%x arrived \n",*(u16 *)(ch->read_data.addr)); */
+ ch->read_data.addr = ch->read_data.addr + ch->n_bytes;
+ ch->read_data.size = ch->read_data.size - ch->n_bytes;
+ i++;
+ }
+ if (ch->read_data.size == 0x0)
+ reset_ch_read(ch);
+ }
+ spin_unlock(&ch->hsi_ch_lock);
+}
+
+/**
+ * hsi_u32_writer - Write FIFO data in Data register as a 32 Bit Data
+ *
+ * This function writes data in Tx FIFO till it is not full
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary write ptr tx in drv_data which maintains
+ * current write position in transfer buffer
+ */
+void hsi_u32_writer(struct hsi_channel *ch)
+{
+ struct hsi_dev *hsi_ctrlr = ch->ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ int i=0;
+
+
+ spin_lock(&ch->hsi_ch_lock);
+ if (ch->write_data.addr) {
+ while ((i< (ch->num_xfer_perintr)) && (ch->write_data.size)) {
+ //while (!((readl(hsi_base+HSI_TX_BUFSTATE)) & (1<<ch->channel_number)) && (ch->write_data.size)) {
+ writel(*(u32 *)(ch->write_data.addr), hsi_base+HSI_TX_BUFFERX+(4*ch->channel_number));
+ ch->write_data.addr = ch->write_data.addr + ch->n_bytes;
+ ch->write_data.size = ch->write_data.size - ch->n_bytes;
+ i++;
+ }
+ if (ch->write_data.size == 0x0)
+ reset_ch_write(ch);
+ }
+ spin_unlock(&ch->hsi_ch_lock);
+}
+
+
+/**
+ * hsi_u32_reader - Read FIFO data in Data register as a 32 Bit Data
+ *
+ * This function reads data in Rx FIFO till it is not empty
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary Read ptr rx in drv_data which maintains
+ * current read position in transfer buffer
+ */
+void hsi_u32_reader(struct hsi_channel *ch)
+{
+ struct hsi_dev *hsi_ctrlr = ch->ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ int i=0;
+
+
+ spin_lock(&ch->hsi_ch_lock);
+ if (ch->read_data.addr) {
+ while ((i< (ch->num_xfer_perintr)) && (ch->read_data.size)) {
+ //while (((readl(hsi_base+HSI_RX_BUFSTATE)) & (1<<ch->channel_number)) && (ch->read_data.size)) {
+ *(u32 *)(ch->read_data.addr) = readl(hsi_base+HSI_RX_BUFFERX+(4*ch->channel_number));
+ /** printk("HSI RX: data 0x%x arrived \n",*(u32 *)(ch->read_data.addr));*/
+ ch->read_data.addr = ch->read_data.addr + ch->n_bytes;
+ ch->read_data.size = ch->read_data.size - ch->n_bytes;
+ i++;
+ }
+ if (ch->read_data.size == 0x0)
+ reset_ch_read(ch);
+ }
+ spin_unlock(&ch->hsi_ch_lock);
+}
+
+void do_hsi_tx_tasklet(unsigned long ctrlr)
+{
+ struct hsi_dev *hsi_ctrlr=(struct hsi_dev *)ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ volatile unsigned long wmark_intrstatus;
+ volatile unsigned long wmark_intrmask;
+ struct hsi_channel *chnl;
+ unsigned char i;
+
+ wmark_intrstatus = (0xFF) & readl(hsi_base + HSI_TX_WATERMARKIS);
+
+ for (i=0;i<HSI_MAX_CHANNELS;i++) {
+ if ((wmark_intrstatus) & (1<<i)) {
+ /** data needs to be transferred for this channel*/
+ chnl = &hsi_ctrlr->hsi_tx_channels[i];
+ //do_channel_tx(chnl);
+ (*chnl->ops.write)(chnl);
+ /** FIXME: HSI bug - clearing interrupt disables delivery of further interrupts */
+ //writel((1<<i), hsi_base+HSI_TX_WATERMARKIC);
+ spin_lock(&chnl->hsi_ch_lock);
+ if ((chnl->write_data.size) <= (chnl->watermark * chnl->n_bytes))
+ /** TODO fix watermark on basis of bytes left */
+ writel((0x1f & 0x0),(hsi_base+HSI_TX_WATERMARKX + (0x4*i)));
+ /** we have transferred the required number of bytes user requested, callback*/
+ if (chnl->write_data.size == 0x0) {
+ /** disable the corresponding watermark as we are done */
+ wmark_intrmask=(0xff) & readl(hsi_base+HSI_TX_WATERMARKIM);
+ writel((wmark_intrmask & ~(1<<chnl->channel_number)), hsi_base+HSI_TX_WATERMARKIM);
+ /** write the original watermark */
+ writel((0x1f & (chnl->watermark -1)),(hsi_base+HSI_TX_WATERMARKX + (0x4*i)));
+ spin_unlock(&chnl->hsi_ch_lock);
+ /** callback */
+ (*chnl->ops.write_done)(chnl->dev);
+ }
+ else
+ spin_unlock(&chnl->hsi_ch_lock);
+ }
+ }
+ enable_irq(hsi_ctrlr->irq1);
+}
+
+void do_hsi_rx_tasklet(unsigned long ctrlr)
+{
+ struct hsi_dev *hsi_ctrlr=(struct hsi_dev *)ctrlr;
+ void __iomem *hsi_base = hsi_ctrlr->regbase;
+ volatile unsigned long wmark_intrstatus;
+ volatile unsigned long wmark_intrmask;
+ struct hsi_channel *chnl;
+ unsigned char i;
+ volatile unsigned long gauge;
+
+ wmark_intrstatus = (0xFF) & readl(hsi_base + HSI_RX_WATERMARKIS);
+
+ for (i=0;i<HSI_MAX_CHANNELS;i++) {
+ if ((wmark_intrstatus) & (1<<i)) {
+ /** data has arrived on this channel */
+ /** printk("Data arrived on channel %d\n",i);*/
+ chnl = &hsi_ctrlr->hsi_rx_channels[i];
+ /** gaurd against spurious interrupts */
+ gauge = (0x1F) & readl(hsi_base + HSI_RX_GAUGEX+ (0x4 * chnl->channel_number));
+ //do_channel_rx(chnl);
+ if (!gauge) {
+ /** clear and go away */
+ writel((1<<i), hsi_base+HSI_RX_WATERMARKIC);
+ continue;
+ }
+ (*chnl->ops.read)(chnl);
+ spin_lock(&chnl->hsi_ch_lock);
+ writel((1<<i), hsi_base+HSI_RX_WATERMARKIC);
+ if ((chnl->read_data.size) <= (chnl->watermark * chnl->n_bytes))
+ /** TODO fix watermark on basis of bytes left */
+ writel((0x1f & 0x0),(hsi_base+HSI_RX_WATERMARKX + (0x4*i)));
+ /** we have the required number of bytes user requested, callback*/
+ if (chnl->read_data.size == 0x0) {
+ /** disable the corresponding watermark as we are done */
+ wmark_intrmask=(0xff) & readl(hsi_base+HSI_RX_WATERMARKIM);
+ writel((wmark_intrmask & ~(1<<chnl->channel_number)), hsi_base+HSI_RX_WATERMARKIM);
+ /** write the original watermark */
+ writel((0x1f & (chnl->watermark -1)),(hsi_base+HSI_RX_WATERMARKX + (0x4*i)));
+ spin_unlock(&chnl->hsi_ch_lock);
+ (*chnl->ops.read_done)(chnl->dev);
+ }
+ else
+ spin_unlock(&chnl->hsi_ch_lock);
+ }
+ }
+ enable_irq(hsi_ctrlr->irq1);
+}
+
+void do_hsi_rxexcep_tasklet(unsigned long ctrlr)
+{
+ struct hsi_dev *hsi_ctrlr=(struct hsi_dev *)ctrlr;
+ void __iomem *hsi_base=NULL;
+ u32 exmis=0x0;
+ u32 ovrmis=0x0;
+ u8 i;
+ u8 chid=0x0;
+
+ hsi_base=hsi_ctrlr->regbase;
+ exmis = (0xF) & readl(hsi_base+HSI_RX_EXCEPMIS);
+ ovrmis = (0xFF) & readl(hsi_base+HSI_RX_OVERRUNMIS);
+
+
+ if (exmis) {
+ for (i=0;i<4;i++) {
+ if ((1<<i) & exmis) {
+ switch (i) {
+ case 0x0:
+ printk("HSIR:TIMEOUT !! \n");
+ hsi_excep_handler(hsi_ctrlr,HSI_EXCEP_TIMEOUT,NULL);
+ break;
+ case 0x1:
+ printk("HSIR:PIPEBUF OVERRUN !! \n");
+ /** flush pipeline buffers and ack interrupt */
+ writel(0x1,hsi_base+HSI_RX_PIPEGAUGE);
+ hsi_excep_handler(hsi_ctrlr,HSI_EXCEP_PIPEBUF_OVERRUN,NULL);
+ break;
+ case 0x2:
+ printk("HSIR:BREAK_DETECTED !! \n");
+ hsi_excep_handler(hsi_ctrlr,HSI_EXCEP_BREAK_DETECTED,NULL);
+ break;
+ case 0x3:
+ printk("HSIR:PARITY ERROR !! \n");
+ hsi_excep_handler(hsi_ctrlr,HSI_EXCEP_PARITY_ERROR,NULL);
+ }
+ writel((1<<i),hsi_base+HSI_RX_ACK);
+ }
+ }
+ }
+
+ if (ovrmis) {
+ while (ovrmis) {
+ if (0x1 & ovrmis) {
+ /** channel overrun ..flush the channel buffer */
+ writel((readl(hsi_base+HSI_RX_BUFSTATE) &
+ ~((unsigned long)(1 << chid))),hsi_base+HSI_RX_BUFSTATE);
+ /** call the exception handler */
+ hsi_excep_handler(hsi_ctrlr,HSI_RXCHANNELS_OVERRUN,&chid);
+ /** set the ack bit */
+ writel((1<<chid),hsi_base+HSI_RX_OVERRUNACK);
+ }
+ ovrmis=ovrmis >>1;
+ chid++;
+ }
+ }
+
+ enable_irq(hsi_ctrlr->irqexcep);
+}
+
+/** interrupt context : tx handler */
+irqreturn_t hsi_tx_irq_handler(int irq,void *ctrlr)
+{
+ struct hsi_dev *hsi_ctrlr=ctrlr;
+ tasklet_hi_schedule(&hsi_ctrlr->hsi_tx_tasklet);
+ disable_irq_nosync(hsi_ctrlr->irq1);
+
+ return IRQ_HANDLED;
+}
+
+/** interrupt context : rx handler */
+irqreturn_t hsi_rx_irq_handler(int irq,void *ctrlr)
+{
+ struct hsi_dev *hsi_ctrlr=ctrlr;
+
+ tasklet_hi_schedule(&hsi_ctrlr->hsi_rx_tasklet);
+ disable_irq_nosync(hsi_ctrlr->irq1);
+
+ return IRQ_HANDLED;
+}
+
+/** interrupt context : rx exception handler */
+irqreturn_t hsi_rxexcep_irq_handler(int irq,void *ctrlr)
+{
+ int i=0;
+ struct hsi_dev *hsi_ctrlr=ctrlr;
+ tasklet_hi_schedule(&hsi_ctrlr->hsi_rxexcep_tasklet);
+ disable_irq_nosync(hsi_ctrlr->irqexcep);
+ for (i=0;i<hsi_ctrlr->max_ch;i++)
+ disable_irq_nosync(hsi_ctrlr->irq_choverrun[i]);
+ return IRQ_HANDLED;
+}
+
+
diff --git a/drivers/misc/hsi/hsi-legacy/hsi_test_protocol_driver.c b/drivers/misc/hsi/hsi-legacy/hsi_test_protocol_driver.c
new file mode 100644
index 00000000000..0bc07558491
--- /dev/null
+++ b/drivers/misc/hsi/hsi-legacy/hsi_test_protocol_driver.c
@@ -0,0 +1,334 @@
+/*----------------------------------------------------------------------------------*/
+/* copyright STMicroelectronics, 2007. */
+/* */
+/* This program is free software; you can redistribute it and/or modify it under */
+/* the terms of the GNU General Public License as published by the Free */
+/* Software Foundation; either version 2.1 of the License, or (at your option) */
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but WITHOUT */
+/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS */
+/* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*----------------------------------------------------------------------------------*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sysdev.h>
+#include <linux/input.h>
+#include <linux/hsi-legacy.h>
+#include <linux/hsi_test_prot.h>
+
+#include <asm/fcntl.h>
+
+#define HSI_TESTPROT_DRIVER_NAME "HSI_TESTPROT_DRV"
+//#define MAX_CHANNELS_MONITORED 4
+
+
+static struct hsi_device *lp_txdev[MAX_CHANNELS_MONITORED]={NULL,
+ NULL,NULL,NULL}; /** store local pointers to tx channels monitored by this driver */
+static struct hsi_device *lp_rxdev[MAX_CHANNELS_MONITORED]={NULL,
+ NULL,NULL,NULL}; /** store local pointers to rx channels monitored by this driver */
+
+/** shared between protocol driver and its apps */
+struct callback_data cbdata[MAX_CHANNELS_MONITORED*2];
+
+EXPORT_SYMBOL(cbdata);
+
+int hsi_testprot_drv_open(unsigned char flags)
+{
+ int ch = -ENODEV;
+ int i=0;
+
+ if ((flags & O_ACCMODE) == O_WRONLY) {
+ for (i=0;((i<MAX_CHANNELS_MONITORED) && (lp_txdev[i] != NULL));i++)
+ {
+ ch = hsi_open(lp_txdev[i]);
+ if (!(ch)) {
+ ch = i;
+ break; /** found a good channel */
+ }
+ }
+ }
+ else if ((flags & O_ACCMODE) == O_RDONLY) {
+ for (i=0;((i<MAX_CHANNELS_MONITORED) && (lp_rxdev[i] != NULL));i++)
+ {
+ ch = hsi_open(lp_rxdev[i]);
+ if (!(ch)) {
+ ch = i+MAX_CHANNELS_MONITORED; /** to ensure tx and rx channel codes are unique */
+ break;
+ }
+ }
+ }
+
+ printk("hsi_testprot_drv_open: Returned channel number %d \n",ch);
+ return ch;
+}
+EXPORT_SYMBOL(hsi_testprot_drv_open);
+
+/** data - pointer to data buffer
+ * datawidth - in bits i.e 16 - 16bits, 32 - 32bits
+ * count - total number of data bytes to receive (should always be in multiple of words)
+ *
+ * Please refer test applications on how to properly pack the buffer to receive data. Also DMA transfers should
+ * require dma coherent buffers (pls refer test app on how to do this)
+ */
+int hsi_testprot_drv_read(unsigned int ch,void* data,unsigned int datawidth,unsigned int count)
+{
+ int err=-ENODEV;
+ int ch_code = ch - MAX_CHANNELS_MONITORED;
+
+ if (ch_code >= MAX_CHANNELS_MONITORED) return err;
+
+ err = hsi_read(lp_rxdev[ch_code],data,datawidth,count);
+
+ return err;
+}
+EXPORT_SYMBOL(hsi_testprot_drv_read);
+
+/** data - pointer to data
+ * datawidth - in bits i.e 16 - 16bits, 32 - 32bits
+ * count - total number of data bytes to send (should always be in multiple of words)
+ *
+ * Please refer test applications on how to pack the data to be sent. Also DMA transfers should
+ * require dma coherent buffers (pls refer test app on how to do this)
+ */
+
+int hsi_testprot_drv_write(unsigned int ch,void* data,unsigned int datawidth,unsigned int count)
+{
+ int err=-ENODEV;
+
+ if (ch >= MAX_CHANNELS_MONITORED) return err;
+
+ err = hsi_write(lp_txdev[ch],data,datawidth,count);
+
+ return err;
+}
+EXPORT_SYMBOL(hsi_testprot_drv_write);
+
+
+
+int hsi_testprot_drv_write_cancel(unsigned int ch)
+{
+ int err=-ENODEV;
+
+ if (ch >= MAX_CHANNELS_MONITORED) return err;
+
+ hsi_write_cancel(lp_txdev[ch]);
+
+ return 0;
+}
+EXPORT_SYMBOL(hsi_testprot_drv_write_cancel);
+
+int hsi_testprot_drv_read_cancel(unsigned int ch)
+{
+ int err=-ENODEV;
+ int ch_code = ch - MAX_CHANNELS_MONITORED;
+
+ if (ch_code >= MAX_CHANNELS_MONITORED) return err;
+
+ hsi_read_cancel(lp_rxdev[ch_code]);
+
+ return 0;
+}
+EXPORT_SYMBOL(hsi_testprot_drv_read_cancel);
+
+int hsi_testprot_drv_close(unsigned int ch)
+{
+ int err=-ENODEV;
+ int ch_code = ch - MAX_CHANNELS_MONITORED;
+
+ if (ch >= MAX_CHANNELS_MONITORED) {
+ if (!(lp_rxdev[ch_code])) return err;
+ hsi_close(lp_rxdev[ch_code]);
+ } else {
+ if (!(lp_txdev[ch])) return err;
+ hsi_close(lp_txdev[ch]);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(hsi_testprot_drv_close);
+
+/** NOTE: before sending/receiving data the user should set an appropriate
+ * watermark through this ioctl. The watermark determines how often the low
+ * -level HSI driver is interrupted to send/receive data on the link. The user
+ * will be notified through callback only when all the data has been sent or
+ * received
+ */
+
+int hsi_testprot_drv_ioctl(unsigned int ch,unsigned int command,void *arg)
+{
+ int err=-ENODEV;
+
+ if (ch >= MAX_CHANNELS_MONITORED) {
+ if (!(lp_rxdev[ch-MAX_CHANNELS_MONITORED])) return err;
+ err = hsi_ioctl(lp_rxdev[ch-MAX_CHANNELS_MONITORED],command,arg);
+ } else {
+ if (!(lp_txdev[ch])) return err;
+ err = hsi_ioctl(lp_txdev[ch],command,arg);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(hsi_testprot_drv_ioctl);
+
+/** NOTE: the low-level HSI driver executes the read/write callbacks
+ * only when it has received or sent all the data it had been requested
+ * to receive/send through the read/write calls
+ */
+
+void read_callbk(struct hsi_device *dev)
+{
+ int ch=0,i=0;
+
+ for (i=0;i<MAX_CHANNELS_MONITORED;i++) {
+ if (lp_rxdev[i]==dev) {
+ ch = i+MAX_CHANNELS_MONITORED;
+ cbdata[ch].read_done = 0x1;
+ printk("read callback executed for channel %d\n",dev->chid);
+ break;
+ }
+ }
+}
+
+void write_callbk(struct hsi_device *dev)
+{
+ int ch=0,i=0;
+
+ for (i=0;i<MAX_CHANNELS_MONITORED;i++) {
+ if (lp_txdev[i]==dev) {
+ ch = i;
+ cbdata[ch].write_done = 0x1;
+ printk("write callback executed for channel %d\n",dev->chid);
+ break;
+ }
+ }
+}
+
+void hsi_testprot_excep_handler(u32 ctrlr_id,u32 event,void *arg)
+{
+ u8 chid;
+ /** exceptions are received only on HSIR */
+ if (ctrlr_id != HSIR_CTRLR_ID) {
+ printk("HSI test protocol driver:exception on wrong controller\n");
+ return;
+ }
+
+ /** NOTE: an actual protocol driver is expected to do proper
+ * exception handling. This could include flushing its buffers,
+ * cancelling read, informing the TX through a message to
+ * resend/start sending data
+ *
+ * Apart from informing the protocol driver the lowlevel HSI driver
+ * does not perform any operations on receiving an exception,
+ * except when it receives :
+ * HSI_EXCEP_PIPEBUF_OVERRUN, where it flushes HSIR pipeline buffer
+ * HSI_RXCHANNELS_OVERRUN , where it flushes the HSIR channel buffer
+ */
+ switch (event) {
+ case HSI_EXCEP_TIMEOUT:
+ printk("HSI test protocol driver:TIMEOUT received\n");
+ break;
+ case HSI_EXCEP_PIPEBUF_OVERRUN:
+ /** HSI has flushed pipeline buffer...protocol driver MUST take appropriate action */
+ printk("HSI test protocol driver:PIPEBUF OVERRUN received\n");
+ break;
+ case HSI_EXCEP_BREAK_DETECTED:
+ printk("HSI test protocol driver:BREAK DETECT received\n");
+ break;
+ case HSI_EXCEP_PARITY_ERROR:
+ printk("HSI test protocol driver: PARITY ERROR received\n");
+ break;
+ case HSI_RXCHANNELS_OVERRUN:
+ /** HSI has flushed corresponding channel buffer...protocol driver MUST take appropriate action */
+ chid=*(u8 *)arg;
+ printk("HSI test protocol driver: CHANNEL %d OVERRUN \n",chid);
+ break;
+ }
+
+}
+
+static int __init hsi_testprot_drv_probe(struct hsi_device *dev)
+{
+ static int i=0;
+ static int j=0;
+
+ if (!dev) {
+ printk("HSI device not populated \n");
+ return -ENODEV;
+ }
+
+ /** set callbacks for channel read write completion notification */
+ if (dev->ctrlrid == 0x0) {
+ lp_txdev[i++] = dev;
+ hsi_dev_set_cb(dev,NULL,&write_callbk);
+ }
+ else {
+ lp_rxdev[j++] = dev;
+ hsi_dev_set_cb(dev,&read_callbk,NULL);
+ }
+
+ printk("HSI test protocol driver : device %s probed \n",dev->device.bus_id);
+
+ return 0;
+}
+
+static int __exit hsi_testprot_drv_remove(struct hsi_device *dev)
+{
+ hsi_dev_set_cb(dev,NULL,NULL);
+ return 0;
+}
+
+static struct hsi_device_driver hsi_testprot_driver = {
+ /** HSI controller ids to monitor: 0 - transmit and 1 - receive */
+ .ctrl_mask = 0x3,
+ /** HSI channels ids to monitor: 0xF - ch0,ch1,ch2,ch3 */
+ .ch_mask = 0xF,
+ /** HSI exception mask : set exceptions you want to receive
+ * bit 0: link timeout, bit 1: pipebuf overrun, bit2: break detection
+ * bit 3: link parity error, bit 4: rx channels overrun
+ */
+ .excep_mask = 0x1F,
+ .excep_event = hsi_testprot_excep_handler,
+ .probe = hsi_testprot_drv_probe,
+ .remove = __exit_p(hsi_testprot_drv_remove),
+ .driver = {
+ .name = HSI_TESTPROT_DRIVER_NAME,
+ },
+};
+
+static int __init hsi_testprot_init(void)
+{
+ int res;
+
+ res = register_hsi_driver(&hsi_testprot_driver);
+ if (res < 0) {
+ printk("HSI test protocol driver registration failed\n");
+ return res;
+ }
+
+ memset(cbdata,0x0,sizeof(cbdata));
+
+ return 0;
+}
+
+static void __exit hsi_testprot_exit(void)
+{
+ unregister_hsi_driver(&hsi_testprot_driver);
+}
+
+module_init(hsi_testprot_init);
+module_exit(hsi_testprot_exit);
+
+MODULE_AUTHOR("STMicroelectronics");
+MODULE_DESCRIPTION("HSI test protocol driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/hsi/hsi-stm.c b/drivers/misc/hsi/hsi-stm.c
new file mode 100644
index 00000000000..c6aaa29ae5b
--- /dev/null
+++ b/drivers/misc/hsi/hsi-stm.c
@@ -0,0 +1,719 @@
+/*
+ * Copyright (C) 2007 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/hsi.h>
+#include <linux/err.h>
+#include <mach/hsi-stm.h>
+#include <mach/debug.h>
+#include <linux/dmaengine.h>
+
+char hsi_controller_string[] = "HSI-CONTROLLER";
+
+static void __exit hsi_close_all_ch(struct hsi_controller *hsi_ctrlr)
+{
+ unsigned int i;
+
+ if (hsi_ctrlr->dev_type == 0x0) {
+ for (i = 0; i < hsi_ctrlr->max_ch; i++) {
+ dma_release_channel(hsi_ctrlr->hsi_tx_channels[i].
+ dma_chan);
+ hsi_ctrlr->algo->close(hsi_ctrlr->hsi_tx_channels[i].
+ dev);
+ }
+ } else {
+ for (i = 0; i < hsi_ctrlr->max_ch; i++) {
+ dma_release_channel(hsi_ctrlr->hsi_rx_channels[i]
+ .dma_chan);
+ hsi_ctrlr->algo->close(hsi_ctrlr->hsi_rx_channels[i].
+ dev);
+ }
+ }
+}
+
+static void __init start_hsi_controller(struct platform_device *pdev)
+{
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_controller *hsi_ctrlr = NULL;
+ void __iomem *hsi_base;
+ unsigned char n_ch;
+
+ pdata = (struct hsi_plat_data *)pdev->dev.platform_data;
+ hsi_ctrlr = pdata->controller;
+ n_ch = hsi_ctrlr->max_ch;
+ hsi_base = hsi_ctrlr->regbase;
+
+ if (!(pdev->id)) {
+ /** HSI transmit */
+ /** flush all the channel buffers */
+ writel(0x0, hsi_base + HSI_TX_BUFSTATE);
+ /** change mode to FRAME*/
+ writel((0x3 & 0x2), hsi_base + HSI_TX_MODE);
+ /** enable watermark interrupt mask and destination 0
+ writel(((1<<n_ch)-1),hsi_base+HSI_TX_WATERMARKIM);*/
+ writel(0x0, hsi_base + HSI_TX_WATERMARKID);
+ } else {
+ /** flush the pipeline buffers */
+ writel(0x0, hsi_base + HSI_RX_STATE);
+ writel(0x0, hsi_base + HSI_RX_PIPEGAUGE);
+ writel(0x0, hsi_base + HSI_RX_BUFSTATE);
+
+ /** change mode to PIPELINED */
+ /*writel((0x3 & 0x3),hsi_base+HSI_RX_MODE);*/
+
+ /** MOP changes :change mode to FRAME */
+ writel((0x3 & 0x2), hsi_base + HSI_RX_MODE);
+
+ /** enable watermark interrupt mask and destination 0 */
+ /** ..not done right now, done during data transfer /
+ writel(((1<<n_ch)-1),hsi_base+HSI_RX_WATERMARKIM);*/
+ writel(0x0, hsi_base + HSI_RX_WATERMARKID);
+ /** for testing purpose
+ writel(0xAAAAAAAA,hsi_base+HSI_RX_BUFFERX);
+ writel(0xBBBBBBBB,hsi_base+HSI_RX_BUFFERX+0x4);
+ writel(0xCCCCCCCC,
+ hsi_base+HSI_RX_BUFFERX+0x8); */
+
+ /** enable the exeception interrupts -
+ * parity,timeout,BREAK,overrun */
+ writel(0xF, hsi_base + HSI_RX_EXCEPIM);
+ /** enable channel overrun interrupt for 4 channels */
+ writel(0xF, hsi_base + HSI_RX_OVERRUNIM);
+ }
+}
+
+static void __init hsi_initialise_hw(struct platform_device *pdev)
+{
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_controller *hsi_ctrlr = NULL;
+ struct hsi_channel *txch, *rxch;
+ void __iomem *hsi_base;
+ u8 i;
+ u8 n_ch;
+ u32 partnum0;
+ u32 des0partnum1;
+ u32 revdes1;
+ u32 config;
+
+ pdata = (struct hsi_plat_data *)pdev->dev.platform_data;
+ hsi_ctrlr = pdata->controller;
+ n_ch = hsi_ctrlr->max_ch;
+ hsi_base = hsi_ctrlr->regbase;
+
+ if (!(pdev->id)) {
+ /** HSI transmit */
+ /** channel id and priority */
+ writel((0xf & pdata->channels), hsi_base + HSI_TX_CHANNELS);
+ writel((0xff & pdata->priority), hsi_base + HSI_TX_PRIORITY);
+ /** channels framelen,base and span data */
+ for (i = 0; i < n_ch; i++) {
+ writel((0x1f & pdata->framelen),
+ hsi_base + HSI_TX_FRAMELENX + (0x4 * i));
+ writel((0x1f & pdata->ch_base_span[i].base),
+ (hsi_base + HSI_TX_BASEX + (0x4 * i)));
+ writel((0x1f & pdata->ch_base_span[i].span),
+ (hsi_base + HSI_TX_SPANX + (0x4 * i)));
+ }
+
+ /** serial link settings */
+ /** sleep mode for now */
+ writel((0x3 & 0x0), hsi_base + HSI_TX_MODE);
+ writel((0xffffff & pdata->divisor), hsi_base + HSI_TX_DIVISOR);
+ writel((0x3 & pdata->parity), hsi_base + HSI_TX_PARITY);
+ writel((0x3f & pdata->flushbits), hsi_base + HSI_TX_FLUSHBITS);
+ writel((0xffffff & pdata->burstlen),
+ hsi_base + HSI_TX_BURSTLEN);
+ writel((0xffffff & pdata->preamble),
+ hsi_base + HSI_TX_PREAMBLE);
+
+ /** watermark and interrupt settings */
+ for (i = 0; i < n_ch; i++) {
+ /* For MOP */
+ txch = &hsi_ctrlr->hsi_tx_channels[i];
+ writel((0x1f & (txch->watermark - 1)),
+ (hsi_base + HSI_TX_WATERMARKX + (0x4 * i)));
+ }
+
+ /** watermark interrupt mask - mask all interrupts now*/
+ writel(0x0, hsi_base + HSI_TX_WATERMARKIM);
+
+ /** Gather info from registers for the driver.(REVISION) */
+ partnum0 = readl(hsi_base + HSI_TX_PERIPHID0);
+ des0partnum1 = readl(hsi_base + HSI_TX_PERIPHID1);
+ revdes1 = readl(hsi_base + HSI_TX_PERIPHID2);
+ config = readl(hsi_base + HSI_TX_PERIPHID3);
+
+ stm_dbg(DBG_ST.hsi,
+ "HSIT Hardware VERSION (in hex) %x.%x.%x.%x.%x.%x\n",
+ (partnum0 & 0xff), (des0partnum1 & 0xf0),
+ (des0partnum1 & 0x0f), (revdes1 & 0xf0),
+ (revdes1 & 0x0f), (config & 0xff));
+
+ } else {
+ /** HSI receive*/
+
+ /** channel id and priority */
+ writel((0xf & pdata->channels), hsi_base + HSI_RX_CHANNELS);
+ for (i = 0; i < pdata->channels; i++) {
+ /** channels framelen,base and span data */
+ writel((0x1f & pdata->framelen),
+ (hsi_base + HSI_RX_FRAMELENX + (0x4 * i)));
+ writel((0x1f & pdata->ch_base_span[i].base),
+ (hsi_base + HSI_RX_BASEX + (0x4 * i)));
+ writel((0x1f & pdata->ch_base_span[i].span),
+ (hsi_base + HSI_RX_SPANX + (0x4 * i)));
+ }
+
+ /** serial link settings */
+ /** sleep mode for now */
+ writel((0x3 & 0x0), hsi_base + HSI_RX_MODE);
+ writel((0xffffff & pdata->detector),
+ hsi_base + HSI_RX_DETECTOR);
+ writel((0x3 & pdata->parity), hsi_base + HSI_RX_PARITY);
+ writel((0xffffff & pdata->preamble),
+ hsi_base + HSI_RX_PREAMBLE);
+
+ /** watermark settings */
+ for (i = 0; i < pdata->channels; i++) {
+ /* For MOP */
+ rxch = &hsi_ctrlr->hsi_rx_channels[i];
+ writel((0x1f & (rxch->watermark - 1)),
+ (hsi_base + HSI_RX_WATERMARKX + (0x4 * i)));
+ }
+ /** watermark interrupt mask - mask all interrupts now*/
+ writel(0x0, hsi_base + HSI_RX_WATERMARKIM);
+ writel(0x0, hsi_base + HSI_RX_OVERRUNIM);
+ writel(0x0, hsi_base + HSI_RX_EXCEPIM);
+
+ /** threshold,realtime and timeout settings */
+ writel((0x3f & pdata->threshold), hsi_base + HSI_RX_THRESHOLD);
+ writel(pdata->realtime, hsi_base + HSI_RX_REALTIME);
+ writel(pdata->timeout, hsi_base + HSI_RX_TIMEOUT);
+
+ /** Gather info from registers for the driver.(REVISION) */
+ partnum0 = readl(hsi_base + HSI_RX_PERIPHID0);
+ des0partnum1 = readl(hsi_base + HSI_RX_PERIPHID1);
+ revdes1 = readl(hsi_base + HSI_RX_PERIPHID2);
+ config = readl(hsi_base + HSI_RX_PERIPHID3);
+
+ stm_dbg(DBG_ST.hsi,
+ "HSIR Hardware VERSION (in hex) %x.%x.%x.%x.%x.%x\n",
+ (partnum0 & 0xff), (des0partnum1 & 0xf0),
+ (des0partnum1 & 0x0f), (revdes1 & 0xf0),
+ (revdes1 & 0x0f), (config & 0xff));
+
+ }
+}
+
+static int __init hsi_initialise_irq(struct hsi_controller *hsi_ctrlr)
+{
+ int err = 0;
+ int i = 0, j = 0;
+ char irqname[20];
+
+ if (!(hsi_ctrlr->dev_type)) {
+ /** tx */
+ tasklet_init(&hsi_ctrlr->hsi_tx_tasklet, do_hsi_tx_tasklet,
+ (unsigned long)hsi_ctrlr);
+ err =
+ request_irq(hsi_ctrlr->irq1, hsi_tx_irq_handler,
+ IRQF_DISABLED, "hsi-tx-d0", hsi_ctrlr);
+ if (err < 0) {
+ stm_dbg(DBG_ST.hsi,
+ "Unable to allocate HSI tx interrupt line\n");
+ err = -EBUSY;
+ tasklet_disable(&hsi_ctrlr->hsi_tx_tasklet);
+ }
+ } else {
+ /** rx */
+
+ tasklet_init(&hsi_ctrlr->hsi_rx_tasklet, do_hsi_rx_tasklet,
+ (unsigned long)hsi_ctrlr);
+ err =
+ request_irq(hsi_ctrlr->irq1, hsi_rx_irq_handler,
+ IRQF_DISABLED, "hsi-rx-d0", hsi_ctrlr);
+ if (err < 0) {
+ stm_dbg(DBG_ST.hsi,
+ "Unable to allocate HSI rx interrupt line\n");
+ tasklet_disable(&hsi_ctrlr->hsi_rx_tasklet);
+ err = -EBUSY;
+ return err;
+ }
+
+ tasklet_init(&hsi_ctrlr->hsi_rxexcep_tasklet,
+ do_hsi_rxexcep_tasklet, (unsigned long)hsi_ctrlr);
+ err =
+ request_irq(hsi_ctrlr->irqexcep, hsi_rxexcep_irq_handler,
+ IRQF_DISABLED, "hsi-rx-excep", hsi_ctrlr);
+ if (err < 0) {
+ stm_dbg(DBG_ST.hsi, "Unable to allocate HSI rx\
+ exception interrupt line\n");
+ err = -EBUSY;
+ tasklet_disable(&hsi_ctrlr->hsi_rx_tasklet);
+ tasklet_disable(&hsi_ctrlr->hsi_rxexcep_tasklet);
+ free_irq(hsi_ctrlr->irq1, hsi_ctrlr);
+ return err;
+ }
+ for (i = 0; i < hsi_ctrlr->max_ch; i++) {
+ snprintf(irqname, sizeof(irqname), "hsi-rx-ch%d-ovrn",
+ i);
+ err =
+ request_irq(hsi_ctrlr->irq_choverrun[i],
+ hsi_rxexcep_irq_handler, IRQF_DISABLED,
+ "hsi-rx-overrun", hsi_ctrlr);
+ if (err < 0) {
+ stm_dbg(DBG_ST.hsi,
+ "Unable to allocate HSI rx\
+ overrun interrupt line\n");
+ err = -EBUSY;
+ tasklet_disable(&hsi_ctrlr->hsi_rx_tasklet);
+ tasklet_disable(&hsi_ctrlr->
+ hsi_rxexcep_tasklet);
+ free_irq(hsi_ctrlr->irq1, hsi_ctrlr);
+ free_irq(hsi_ctrlr->irqexcep, hsi_ctrlr);
+ for (j = 0; j < i; j++)
+ free_irq(hsi_ctrlr->irq_choverrun[j],
+ hsi_ctrlr);
+ }
+
+ }
+ }
+
+ return err;
+}
+
+static void free_hsi_irq(struct hsi_controller *hsi_ctrlr)
+{
+ int i = 0;
+
+ if (!(hsi_ctrlr->dev_type)) {
+ /** tx */
+ tasklet_disable(&hsi_ctrlr->hsi_tx_tasklet);
+ free_irq(hsi_ctrlr->irq1, hsi_ctrlr);
+ } else {
+ tasklet_disable(&hsi_ctrlr->hsi_rx_tasklet);
+ tasklet_disable(&hsi_ctrlr->hsi_rxexcep_tasklet);
+ free_irq(hsi_ctrlr->irq1, hsi_ctrlr);
+ free_irq(hsi_ctrlr->irqexcep, hsi_ctrlr);
+ for (i = 0; i < hsi_ctrlr->max_ch; i++)
+ free_irq(hsi_ctrlr->irq_choverrun[i], hsi_ctrlr);
+ }
+
+}
+
+int fill_hsi_dma_info(struct platform_device *pd, struct hsi_channel *ch)
+{
+
+ struct hsi_controller *hsi_ctrlr;
+ struct hsi_plat_data *pdata;
+ dma_cap_mask_t mask;
+
+ pdata = (struct hsi_plat_data *)pd->dev.platform_data;
+ hsi_ctrlr = pdata->controller;
+
+ /*FIXME can it be made single register*/
+ if (pd->id) {
+ /* find and request free dma chanel */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ ch->dma_chan = dma_request_channel(mask, stedma40_filter,
+ ch->hsi_dma_info);
+ if (ch->dma_chan == NULL) {
+ stm_error("RX pipe request failed\n");
+ return -EBUSY;
+ }
+ tasklet_init(&ch->hsi_dma_tasklet, do_hsi_rx_dma_tasklet,
+ (unsigned long)ch);
+
+ } else {
+ /* find and request free dma chanel for tx */
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ ch->dma_chan = dma_request_channel(mask, stedma40_filter,
+ ch->hsi_dma_info);
+ if (ch->dma_chan == NULL) {
+ stm_error("RX pipe request failed\n");
+ return -EBUSY;
+ }
+
+ tasklet_init(&ch->hsi_dma_tasklet, do_hsi_tx_dma_tasklet,
+ (unsigned long)ch);
+
+ }
+ return 0;
+}
+
+static void __init hsi_initialise_channels(struct platform_device *pdev)
+{
+
+ u8 ch = 0;
+ u8 n_ch = 0;
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_controller *hsi_ctrlr = NULL;
+ /** temp pointer to populate rxchannel array */
+ struct hsi_channel *txch = NULL;
+ struct hsi_channel *rxch = NULL;
+
+ pdata = (struct hsi_plat_data *)pdev->dev.platform_data;
+ hsi_ctrlr = pdata->controller;
+ n_ch = hsi_ctrlr->max_ch;
+
+ if (!(pdev->id)) {
+ /** HSI transmit */
+ for (ch = 0; ch < n_ch; ch++) {
+ txch = &hsi_ctrlr->hsi_tx_channels[ch];
+ txch->channel_number = ch;
+ txch->span = (pdata->ch_base_span[ch].span) + 1;
+ txch->watermark = pdata->watermark;
+ txch->flags = 0;
+ txch->ctrlr = hsi_ctrlr;
+ txch->write_data.data = NULL;
+ txch->write_data.count = 0;
+ txch->hsi_dma_info = &pdata->hsi_dma_info[ch];
+ txch->n_bytes = 0x1;
+ fill_hsi_dma_info(pdev, txch);
+ spin_lock_init(&txch->hsi_ch_lock);
+ }
+ } else {
+ /** HSI receive */
+ for (ch = 0; ch < n_ch; ch++) {
+ rxch = &hsi_ctrlr->hsi_rx_channels[ch];
+ rxch->channel_number = ch;
+ rxch->span = (pdata->ch_base_span[ch].span) + 1;
+ rxch->watermark = pdata->watermark;
+ rxch->flags = 0;
+ rxch->ctrlr = hsi_ctrlr;
+ rxch->read_data.data = NULL;
+ rxch->read_data.count = 0;
+ rxch->hsi_dma_info = &pdata->hsi_dma_info[ch];
+ rxch->n_bytes = 0x1;
+ fill_hsi_dma_info(pdev, rxch);
+ spin_lock_init(&rxch->hsi_ch_lock);
+ }
+
+ }
+}
+
+static void __init hsi_initialise_controller(struct platform_device *pdev)
+{
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_controller *hsi_ctrlr = NULL;
+
+ pdata = (struct hsi_plat_data *)pdev->dev.platform_data;
+
+ hsi_ctrlr = pdata->controller;
+ hsi_ctrlr->max_ch = pdata->channels;
+ hsi_ctrlr->mode = pdata->mode;
+ hsi_ctrlr->flags = 0;
+ spin_lock_init(&hsi_ctrlr->lock);
+}
+
+static int __init hsi_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct hsi_controller *hsi_ctrlr = NULL;
+ struct hsi_plat_data *pdata = NULL;
+ unsigned char name[20];
+ int err = 0;
+ int i = 0;
+
+ if ((pdev == NULL) || (pdev->dev.platform_data == NULL)) {
+ stm_dbg(DBG_ST.hsi,
+ "No device/platform_data found on HSI device\n");
+ return -ENODEV;
+ }
+
+ hsi_ctrlr = kzalloc(sizeof(struct hsi_controller), GFP_KERNEL);
+ if (hsi_ctrlr == NULL) {
+ stm_dbg(DBG_ST.hsi,
+ "Could not allocate memory for controller struct\n");
+ return -ENOMEM;
+ }
+
+ hsi_ctrlr->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(hsi_ctrlr->clk)) {
+ stm_dbg(DBG_ST.hsi, "Could not get HSI clock\n");
+ err = PTR_ERR(hsi_ctrlr->clk);
+ goto rollback_alloc;
+ }
+
+ /** initialise the HSI controller and channels (tx and rx) */
+ hsi_ctrlr->dev_type = pdev->id;
+ memcpy(hsi_ctrlr->name, hsi_controller_string,
+ strlen(hsi_controller_string)), pdata = pdev->dev.platform_data;
+ pdata->controller = hsi_ctrlr;
+ hsi_ctrlr->dev_type = pdata->dev_type;
+
+ err = stm_gpio_altfuncenable(pdata->gpio_alt_func);
+ if (err) {
+ stm_dbg(DBG_ST.hsi, "Could not set HSI GPIO\
+ alternate function correctly\n");
+ err = -ENODEV;
+ goto rollback_clock;
+ }
+
+ hsi_initialise_controller(pdev);
+ hsi_initialise_channels(pdev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ stm_dbg(DBG_ST.hsi,
+ "Could not get HSI IO memory information\n");
+ err = -ENODEV;
+ goto rollback_gpio;
+ }
+
+ hsi_ctrlr->regbase =
+ (void __iomem *)ioremap(res->start, res->end - res->start + 1);
+ if (!(hsi_ctrlr->regbase)) {
+ stm_dbg(DBG_ST.hsi, "Unable to map register base \n");
+ err = -EBUSY;
+ goto rollback_gpio;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ stm_dbg(DBG_ST.hsi, "Unable to map HSI D0/D1 IRQ base \n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+
+ /** storing D0 and D1 interrupt lines */
+ if (res->end - res->start) {
+ hsi_ctrlr->irq1 = res->start;
+ hsi_ctrlr->irq2 = res->end;
+ }
+
+ /** store the HSIR exception interrupt and channel
+ * overrun interrupt line */
+ if (hsi_ctrlr->dev_type == 0x1) {
+ /** rx */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+ if (!res) {
+ stm_dbg(DBG_ST.hsi,
+ "Unable to map HSIR EXCEP IRQ base \n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+ hsi_ctrlr->irqexcep = res->start;
+
+ for (i = 0; i < hsi_ctrlr->max_ch; i++) {
+ res =
+ platform_get_resource(pdev, IORESOURCE_IRQ, i + 2);
+ if (!res) {
+ stm_dbg(DBG_ST.hsi, "Unable to map HSIR\
+ CHANNEL %d OVERRUN IRQ LINE \n",
+ i);
+ err = -EBUSY;
+ goto rollback_map;
+ }
+ hsi_ctrlr->irq_choverrun[i] = res->start;
+ }
+ }
+
+ /** install handlers and tasklets */
+ if (hsi_initialise_irq(hsi_ctrlr)) {
+ stm_dbg(DBG_ST.hsi, "HSI error in interrupt registration \n");
+ goto rollback_map;
+ }
+
+ /** write to hardware but do not start yet*/
+ hsi_initialise_hw(pdev);
+
+ hsi_ctrlr->algo = &hsi_algo;
+ /** register devices on hsi bus */
+ err = hsi_add_controller(hsi_ctrlr);
+ if (err < 0) {
+ stm_dbg(DBG_ST.hsi, "HSI error in device registration \n");
+ goto rollback_irq;
+ }
+
+ /** kick start the controller */
+ start_hsi_controller(pdev);
+
+ snprintf(name, sizeof(name), "%s:%d", pdev->name, pdev->id);
+ if (!err)
+ printk(KERN_NOTICE"%s probe COMPLETED \n", name);
+
+ return err;
+
+rollback_irq:
+ free_hsi_irq(hsi_ctrlr);
+rollback_map:
+ iounmap(hsi_ctrlr->regbase);
+rollback_gpio:
+ stm_gpio_altfuncdisable(pdata->gpio_alt_func);
+rollback_clock:
+ clk_put(hsi_ctrlr->clk);
+rollback_alloc:
+ pdata->controller = NULL;
+ kfree(hsi_ctrlr);
+ return err;
+}
+
+static int __exit hsi_remove(struct platform_device *pdev)
+{
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_controller *hsi_ctrlr = NULL;
+
+ pdata = (struct hsi_plat_data *)pdev->dev.platform_data;
+ hsi_ctrlr = pdata->controller;
+ hsi_close_all_ch(hsi_ctrlr);
+ hsi_remove_controller(hsi_ctrlr);
+ stm_gpio_altfuncdisable(pdata->gpio_alt_func);
+ free_hsi_irq(hsi_ctrlr);
+ iounmap(hsi_ctrlr->regbase);
+ clk_put(hsi_ctrlr->clk);
+ pdata->controller = NULL;
+ kfree(hsi_ctrlr);
+
+ return 0;
+}
+#ifdef CONFIG_PM
+/**
+ * hsi_suspend - HSI suspend function registered with PM framework.
+ * @pdev: Reference to platform device structure of the device
+ * @state: power mgmt state.
+ *
+ * This function is invoked when the system is going into sleep, called
+ * by the power management framework of the linux kernel.
+ * Nothing is required as controller is configured with every transfer.
+ * It is assumed that no active tranfer is in progress at this time.
+ * Client driver should make sure of this.
+ *
+ */
+
+int hsi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_controller *hsi_ctrlr = NULL;
+ struct hsi_backup_regs *backup_regs;
+ void __iomem *hsi_base;
+ int i;
+
+ pdata = (struct hsi_plat_data *)pdev->dev.platform_data;
+ hsi_ctrlr = pdata->controller;
+ hsi_base = hsi_ctrlr->regbase;
+ backup_regs = &hsi_ctrlr->backup_regs;
+ if(pdev->id) {
+ for(i = 0;i < HSI_MAX_CHANNELS;i++) {
+ backup_regs->framelen[i] =
+ readl(hsi_base + HSI_RX_WATERMARKX + (i*4));
+ backup_regs->watermark[i] =
+ readl(hsi_base + HSI_RX_FRAMELENX + (i*4));
+ }
+ backup_regs->rx_threshold =
+ readl(hsi_base + HSI_RX_THRESHOLD);
+ } else {
+ for(i = 0;i < HSI_MAX_CHANNELS;i++) {
+ backup_regs->watermark[i] =
+ readl(hsi_base + HSI_TX_WATERMARKX + (i*4));
+ backup_regs->framelen[i] =
+ readl(hsi_base + HSI_TX_FRAMELENX + (i*4));
+ }
+ }
+ return 0;
+}
+/**
+ * hsi_resume - HSI Resume function registered with PM framework.
+ * @pdev: Reference to platform device structure of the device
+ *
+ * This function is invoked when the system is coming out of sleep, called
+ * by the power management framework of the linux kernel.
+ * Nothing is required.
+ *
+ */
+
+int hsi_resume(struct platform_device *pdev)
+{
+ struct hsi_plat_data *pdata = NULL;
+ struct hsi_controller *hsi_ctrlr = NULL;
+ struct hsi_backup_regs *backup_regs;
+ void __iomem *hsi_base;
+ int i;
+
+ pdata = (struct hsi_plat_data *)pdev->dev.platform_data;
+ hsi_ctrlr = pdata->controller;
+ backup_regs = &hsi_ctrlr->backup_regs;
+ hsi_base = hsi_ctrlr->regbase;
+ hsi_initialise_hw(pdev);
+ start_hsi_controller(pdev);
+
+ if(pdev->id) {
+ for(i = 0;i < HSI_MAX_CHANNELS;i++) {
+ writel(backup_regs->framelen[i],
+ hsi_base + HSI_RX_WATERMARKX + (i*4));
+ writel(backup_regs->watermark[i],
+ hsi_base + HSI_RX_FRAMELENX + (i*4));
+ }
+ writel(backup_regs->rx_threshold,
+ hsi_base + HSI_RX_THRESHOLD);
+ } else {
+ for(i = 0;i < HSI_MAX_CHANNELS;i++) {
+ writel(backup_regs->watermark[i],
+ hsi_base + HSI_TX_WATERMARKX + (i*4));
+ writel(backup_regs->framelen[i],
+ hsi_base + HSI_TX_FRAMELENX + (i*4));
+ }
+ }
+ return 0;
+
+}
+#else
+#define hsi_suspend NULL
+#define hsi_resume NULL
+#endif
+static struct platform_driver hsi_driver = {
+ .probe = hsi_probe,
+ .remove = __exit_p(hsi_remove),
+ .suspend = hsi_suspend,
+ .resume = hsi_resume,
+ .driver = {
+ .name = "stm-hsi",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init hsi_driver_init(void)
+{
+ int err = 0;
+
+ err = platform_driver_probe(&hsi_driver, hsi_probe);
+ if (err < 0) {
+ stm_dbg(DBG_ST.hsi,
+ "HSI Platform DRIVER register FAILED: %d\n",
+ err);
+ return err;
+ }
+
+ return 0;
+}
+
+static void __exit hsi_driver_exit(void)
+{
+ platform_driver_unregister(&hsi_driver);
+
+ printk(KERN_NOTICE"HSI Platform DRIVER removed\n");
+}
+
+module_init(hsi_driver_init);
+module_exit(hsi_driver_exit);
+
+MODULE_AUTHOR(HSI_DRIVER_AUTHOR);
+MODULE_DESCRIPTION(HSI_DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/hsi/hsi.c b/drivers/misc/hsi/hsi.c
new file mode 100644
index 00000000000..b456da6aa44
--- /dev/null
+++ b/drivers/misc/hsi/hsi.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2007 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/hsi.h>
+#include <mach/hsi-stm.h>
+
+/* LDM. defintions for the hsi bus, hsi device, and hsi_device driver */
+struct bus_type hsi_bus_type;
+static LIST_HEAD(__hsi_board_list);
+static DEFINE_MUTEX(__hsi_board_lock);
+
+static void hsi_controller_device_release(struct device *dev)
+{
+ struct hsi_device *hsi = to_hsi_device(dev);
+
+ kfree(hsi);
+ return;
+}
+
+/** hsi_add_device - instantiate an hsi device and add it to the bus
+ * @dev: The device to instatiate.
+ * This function is called by the kernel automatically on device release
+ * HSI bustype and hsi controller class are registered after board init code
+ * provides the HSI device tables, ensuring that both are present by the
+ * time controller driver registration causes hsi_devices to "enumerate".
+ */
+static void hsidev_release(struct device *dev)
+{
+ struct hsi_device *hsi = to_hsi_device(dev);
+
+ /* TODO: hsi masters may cleanup for released devices */
+ kfree(hsi);
+}
+
+/**
+ * hsi_add_device - instantiate an hsi device and add it to the bus
+ * @info: describes one HSI device with channel and bus information
+ * Context: can sleep
+ *
+ * Create a device to work with a hsi driver, where binding is
+ * handled through driver model probe()/remove() methods.
+ *
+ * This returns the new hsi client, which may be saved for later use with
+ * hsi_unregister_device(); or NULL to indicate an error.
+ */
+struct hsi_device *hsi_add_device(struct hsi_device *dev,
+ struct hsi_board_info const *info)
+{
+ struct hsi_device *client;
+ int status;
+
+ client = kzalloc(sizeof *client, GFP_KERNEL);
+ if (!client) {
+ printk(KERN_ERR"HSI: Device alloc failed\n");
+ return NULL;
+ }
+
+ client->cid = info->controller_id;
+ client->chid = info->chan_num;
+
+ client->ctrlr = dev->ctrlr;
+ client->curr_mode = info->mode;
+ if (!client->cid)
+ client->ch = &dev->ctrlr->hsi_tx_channels[client->chid];
+ else
+ client->ch = &dev->ctrlr->hsi_rx_channels[client->chid];
+
+ client->dev.platform_data = info->platform_data;
+
+ snprintf(client->dev.bus_id, sizeof client->dev.bus_id,
+ "%s.%u.%u", "hsi", info->controller_id, info->chan_num);
+
+ strlcpy(client->name, info->type, sizeof(client->name));
+
+ client->dev.parent = &dev->dev;
+ client->dev.bus = &hsi_bus_type;
+ client->dev.release = hsidev_release;
+ client->ch->dev = client;
+
+ status = device_register(&client->dev);
+ if (status) {
+ printk(KERN_ERR"HSI: Device register failed\n");
+ return NULL;
+ }
+
+ return client;
+}
+EXPORT_SYMBOL_GPL(hsi_add_device);
+
+/**
+ * hsi_open - open a hsi device channel.
+ * @dev: Reference to the hsi device channel to be openned.
+ *
+ * Returns 0 on success, -EINVAL on bad parameters, -EBUSY if is already opened.
+**/
+
+int hsi_open(struct hsi_device *dev)
+{
+ return dev->ctrlr->algo->open(dev);
+}
+EXPORT_SYMBOL_GPL(hsi_open);
+
+/**
+ * hsi_write - write data into the hsi device channel
+ * @dev: reference to the hsi device channel to write into.
+ * @data: pointer to a 32-bit word data to be written.
+ * @datawidth: in bits (16bit or 32bit or ....)
+ * @count: total number of bytes to be written.
+ *
+ * Return 0 on sucess, a negative value on failure.
+ * A success values only indicates that the request has been accepted.
+ * Transfer is only completed when the write_done callback is called.
+ *
+**/
+int hsi_write(struct hsi_device *dev, struct hsi_data *xfer)
+{
+ return dev->ctrlr->algo->write(dev, xfer);
+}
+EXPORT_SYMBOL_GPL(hsi_write);
+
+/**
+ * hsi_read - read data from the hsi device channel
+ * @dev: hsi device channel reference to read data from.
+ * @data: pointer to a 32/16-bit word data to store the data.
+ * @count: number of 32/16-bit word to be stored.
+ *
+ * Return 0 on sucess, a negative value on failure.
+ * A success values only indicates that the request has been accepted.
+ * Data is only available in the buffer when the read_done callback is called.
+ *
+**/
+int hsi_read(struct hsi_device *dev, struct hsi_data *xfer)
+{
+ return dev->ctrlr->algo->read(dev, xfer);
+}
+EXPORT_SYMBOL_GPL(hsi_read);
+
+/**
+ * hsi_write_cancel - Cancel pending write request.
+ * @dev: hsi device channel where to cancel the pending write.
+ *
+ * write_done() callback will not be called after sucess of this function.
+ * This call closes the channel also.
+**/
+void hsi_write_cancel(struct hsi_device *dev)
+{
+ dev->ctrlr->algo->cancel_write(dev);
+ return;
+}
+EXPORT_SYMBOL_GPL(hsi_write_cancel);
+
+/**
+ * hsi_read_cancel - Cancel pending read request.
+ * @dev: hsi device channel where to cancel the pending read.
+ *
+ * read_done() callback will not be called after sucess of this function.
+**/
+void hsi_read_cancel(struct hsi_device *dev)
+{
+ dev->ctrlr->algo->cancel_read(dev);
+ return;
+}
+EXPORT_SYMBOL_GPL(hsi_read_cancel);
+
+/**
+ * hsi_dev_set_cb - register read_done() and write_done() callbacks.
+ * @dev: reference to hsi device channel where callbacks are associated.
+ * @r_cb: callback to signal read transfer completed.
+ * @w_cb: callback to signal write transfer completed.
+ * Context: Can sleep
+**/
+void hsi_set_callback(struct hsi_device *dev,
+ void (*r_cb) (struct hsi_device *dev)
+ , void (*w_cb) (struct hsi_device *dev))
+{
+ dev->ctrlr->algo->set_cb(dev, r_cb, w_cb);
+ return;
+}
+EXPORT_SYMBOL_GPL(hsi_set_callback);
+
+/**
+ * hsi_ioctl - HSI I/O control
+ * @dev: hsi device channel reference to apply the I/O control
+ * (or port associated to it)
+ * @command: HSI I/O control command
+ * @arg: parameter associated to the control command. NULL, if no parameter.
+ * Context: Can sleep
+ *
+ * Return 0 on sucess, a negative value on failure.
+ *
+**/
+int hsi_ioctl(struct hsi_device *dev, unsigned int command, void *arg)
+{
+ return dev->ctrlr->algo->ioctl(dev, command, arg);
+}
+EXPORT_SYMBOL_GPL(hsi_ioctl);
+
+/**
+ * hsi_close - close given hsi device channel
+ * @dev: reference to hsi device channel.
+**/
+void hsi_close(struct hsi_device *dev)
+{
+ dev->ctrlr->algo->close(dev);
+ return;
+}
+EXPORT_SYMBOL_GPL(hsi_close);
+
+static void hsi_scan_static_board_info(struct hsi_device *dev)
+{
+ struct hsi_board_info *boardinfo;
+
+ mutex_lock(&__hsi_board_lock);
+ list_for_each_entry(boardinfo, &__hsi_board_list, list) {
+ if (boardinfo->controller_id == dev->cid
+ && !hsi_add_device(dev, boardinfo))
+ printk(KERN_ERR "hsi-core: can't create hsi%d-%d\n",
+ boardinfo->controller_id, boardinfo->chan_num);
+ }
+ mutex_unlock(&__hsi_board_lock);
+}
+
+int hsi_add_controller(struct hsi_controller *hsi_ctrlr)
+{
+ struct hsi_device *hdev;
+ unsigned int n_ch = 0;
+ int ch = 0;
+ int err = 0;
+
+ n_ch = hsi_ctrlr->max_ch;
+
+ hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
+ if (!hdev) {
+ err = -ENOMEM;
+ return err;
+ }
+ hdev->cid = hsi_ctrlr->dev_type;
+ hdev->ctrlr = hsi_ctrlr;
+ hdev->dev.parent = &platform_bus;
+ hdev->dev.release = hsi_controller_device_release;
+ hsi_ctrlr->dev = &hdev->dev;
+ snprintf(hdev->dev.bus_id, sizeof(hdev->dev.bus_id),
+ hdev->cid ? "hsirx-ch%u" : "hsitx-ch%u", ch);
+ err = device_register(&hdev->dev);
+ if (!err)
+ hsi_scan_static_board_info(hdev);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(hsi_add_controller);
+
+static int __unregister(struct device *dev, void *master_dev)
+{
+ /* note: before about 2.6.14-rc1 this would corrupt memory: */
+ device_unregister(dev);
+ return 0;
+}
+
+/**
+ * hsi_remove_controller - unregister HSI controller
+ * @controller: The controller to be unregistered
+ * Context: can sleep
+ *
+ * This call is used only by HSI controller drivers, which are the
+ * only ones directly touching chip registers.
+ *
+ * This must be called from context that can sleep.
+ */
+void hsi_remove_controller(struct hsi_controller *controller)
+{
+ int dummy;
+
+ dummy = device_for_each_child(controller->dev, controller->dev,
+ __unregister);
+ device_unregister(controller->dev);
+}
+EXPORT_SYMBOL_GPL(hsi_remove_controller);
+
+int hsi_register_board_info(struct hsi_board_info const *info, int len)
+{
+ int status;
+
+ mutex_lock(&__hsi_board_lock);
+
+ for (status = 0; len; len--, info++) {
+ struct hsi_board_info *binfo;
+
+ binfo = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!binfo) {
+ printk(KERN_NOTICE
+ "hsi-core: can't register boardinfo!\n");
+ status = -ENOMEM;
+ break;
+ }
+ memcpy(binfo, info, sizeof *info);
+ list_add_tail(&binfo->list, &__hsi_board_list);
+ }
+
+ mutex_unlock(&__hsi_board_lock);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(hsi_register_board_info);
+
+static int modalias_show(struct device *dev, struct device_attribute *a,
+ char *buf)
+{
+ return snprintf(buf, BUS_ID_SIZE + 1, "%s%s\n", HSI_PREFIX,
+ dev->bus_id);
+}
+
+static struct device_attribute hsi_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
+static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ add_uevent_var(env, "MODALIAS=%s%s", HSI_PREFIX, dev->bus_id);
+ return 0;
+}
+
+static ssize_t
+show_controller_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hsi_device *hdev = to_hsi_device(dev);
+ return sprintf(buf, "%s\n", hdev->ctrlr->name);
+}
+
+static struct device_attribute hsi_controller_attrs[] = {
+ __ATTR(name, S_IRUGO, show_controller_name, NULL),
+ {},
+};
+
+static struct class hsi_controller_class = {
+ .owner = THIS_MODULE,
+ .name = "hsi-controller",
+ .dev_attrs = hsi_controller_attrs,
+};
+
+static int hsi_bus_match(struct device *device, struct device_driver *driver)
+{
+ int error;
+ struct hsi_device *dev = to_hsi_device(device);
+ struct hsi_device_driver *drv = to_hsi_device_driver(driver);
+
+ error = strcmp(dev->name, drv->driver.name);
+ return !error;
+}
+
+int hsi_bus_unreg_dev(struct device *device, void *p)
+{
+ device->release(device);
+ device_unregister(device);
+
+ return 0;
+}
+
+int __init hsi_bus_init(void)
+{
+ int status;
+
+ status = bus_register(&hsi_bus_type);
+ if (status < 0)
+ goto err0;
+
+ status = class_register(&hsi_controller_class);
+ if (status < 0)
+ goto err1;
+
+ printk(KERN_NOTICE"HSI bus initialised\n");
+ return 0;
+err1:
+ bus_unregister(&hsi_bus_type);
+err0:
+ return status;
+
+}
+
+void hsi_bus_exit(void)
+{
+ bus_for_each_dev(&hsi_bus_type, NULL, NULL, hsi_bus_unreg_dev);
+ class_unregister(&hsi_controller_class);
+ bus_unregister(&hsi_bus_type);
+ printk(KERN_NOTICE"HSI bus deinitialised\n");
+}
+
+static int hsi_driver_probe(struct device *dev)
+{
+ struct hsi_device_driver *drv = to_hsi_device_driver(dev->driver);
+
+ return drv->probe(to_hsi_device(dev));
+}
+
+static int hsi_driver_remove(struct device *dev)
+{
+ struct hsi_device_driver *drv = to_hsi_device_driver(dev->driver);
+
+ return drv->remove(to_hsi_device(dev));
+}
+
+static int hsi_driver_suspend(struct device *dev, pm_message_t mesg)
+{
+ struct hsi_device_driver *drv = to_hsi_device_driver(dev->driver);
+
+ return drv->suspend(to_hsi_device(dev), mesg);
+}
+
+static int hsi_driver_resume(struct device *dev)
+{
+ struct hsi_device_driver *drv = to_hsi_device_driver(dev->driver);
+
+ return drv->resume(to_hsi_device(dev));
+}
+
+/* NOTE: Function called in interrupt context */
+int hsi_exception(struct hsi_controller *hsi_ctrlr, unsigned int event,
+ void *arg)
+{
+ int err = 0;
+ struct hsi_ctrlr_excep c_ex = {
+ .ctrlr = hsi_ctrlr,
+ .event = event,
+ .priv = arg
+ };
+
+ err =
+ bus_for_each_drv(&hsi_bus_type, NULL, &c_ex,
+ hsi_ctrlr->algo->exception_handler);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(hsi_exception);
+
+struct bus_type hsi_bus_type = {
+ .name = "hsi",
+ .dev_attrs = hsi_dev_attrs,
+ .match = hsi_bus_match,
+ .uevent = hsi_bus_uevent,
+};
+
+/**
+ * register_hsi_driver - Register HSI device driver
+ * @driver - reference to the HSI device driver.
+ */
+int register_hsi_driver(struct hsi_device_driver *driver)
+{
+ int ret = 0;
+
+ if (driver == NULL)
+ return -ENODEV;
+
+ driver->driver.bus = &hsi_bus_type;
+
+#define HSI_SETFN(fn) { if (!driver->driver.fn) \
+ driver->driver.fn = hsi_driver_##fn; }
+
+ HSI_SETFN(probe);
+ HSI_SETFN(remove);
+ HSI_SETFN(suspend);
+ HSI_SETFN(resume);
+
+ ret = driver_register(&driver->driver);
+ return ret;
+}
+EXPORT_SYMBOL(register_hsi_driver);
+
+/**
+ * unregister_hsi_driver - Unregister HSI device driver
+ * @driver - reference to the HSI device driver.
+ */
+void unregister_hsi_driver(struct hsi_device_driver *driver)
+{
+ if (driver != NULL)
+ driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(unregister_hsi_driver);
+
+/** board_info is normally registered in arch_initcall(),
+ * but even essential drivers wait till later
+ *
+ * REVISIT only boardinfo really needs static linking. the rest (device and
+ * driver registration) _could_ be dynamically linked (modular) ... costs
+ * include needing to have boardinfo data structures be much more public.
+**/
+subsys_initcall(hsi_bus_init);
+
diff --git a/drivers/misc/hsi/hsidev.c b/drivers/misc/hsi/hsidev.c
new file mode 100644
index 00000000000..13f12f55be1
--- /dev/null
+++ b/drivers/misc/hsi/hsidev.c
@@ -0,0 +1,599 @@
+/*
+ * Copyright (C) 2007 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sysdev.h>
+#include <linux/input.h>
+#include <linux/hsi.h>
+#include <linux/hsidev.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+
+#include <linux/fcntl.h>
+
+#define HSI_TESTPROT_DRIVER_NAME "HSI_LOOPBACK"
+
+#define HSIDEV_MAJOR 153 /* assigned */
+#define N_HSI_MINORS 4 /* ... up to 256 */
+static unsigned long tx_minors;
+static unsigned long rx_minors;
+static LIST_HEAD(device_list);
+static DEFINE_MUTEX(device_list_lock);
+
+#define MAX_CHANNELS_MONITORED 4
+
+/** NOTE: the low-level HSI driver executes the read/write callbacks
+ * only when it has received or sent all the data it had been requested
+ * to receive/send through the read/write calls
+ */
+static void transfer_callback(struct hsi_device *dev)
+{
+ struct hsidev_data *hsidev;
+
+ list_for_each_entry(hsidev, &device_list, device_entry) {
+ if (hsidev->hsi->cid == dev->cid &&
+ hsidev->hsi->chid == dev->chid) {
+ hsidev->xfer_done = 1;
+ wake_up_interruptible(&hsidev->wq);
+ stm_dbg(DBG_ST.hsi,
+ "%s callback executed for channel %d\n",
+ dev->cid ? "Read" : "Write", dev->chid);
+ break;
+ }
+ }
+}
+
+int hsidev_open(struct inode *inode, struct file *filp)
+{
+ struct hsidev_data *hsidev;
+ int status = -ENXIO;
+
+ lock_kernel();
+ mutex_lock(&device_list_lock);
+
+ list_for_each_entry(hsidev, &device_list, device_entry) {
+ stm_dbg(DBG_ST.hsi, "%X:%X\n", hsidev->devt,
+ inode->i_rdev);
+ if (hsidev->devt == inode->i_rdev) {
+ status = 0;
+ break;
+ }
+ }
+ if (status == 0) {
+ if (hsidev->users > 0)
+ return -EBUSY;
+ hsidev->users++;
+ filp->private_data = hsidev;
+ nonseekable_open(inode, filp);
+ } else {
+ stm_dbg(DBG_ST.hsi, "hsidev: nothing for minor %d\n",
+ iminor(inode));
+ return status;
+ }
+
+ status = hsi_open(hsidev->hsi);
+ if (!status) {
+ if (iminor(inode) < MAX_CHANNELS_MONITORED)
+ hsi_set_callback(hsidev->hsi, NULL, &transfer_callback);
+ else
+ hsi_set_callback(hsidev->hsi, &transfer_callback, NULL);
+ }
+ mutex_unlock(&device_list_lock);
+ unlock_kernel();
+ return status;
+
+}
+
+void print_data(char *caller, void *tx_buf, int num)
+{
+ int i = 0;
+ for (i = 0; i < num / 4; i++) {
+ stm_dbg(DBG_ST.hsi, "DRV %s:buf[%d]----->%x\n", caller, i,
+ (*(u32 *) tx_buf));
+ tx_buf += 4;
+ }
+}
+
+/** buf - pointer to data buffer
+ * count - total number of data bytes to receive
+ * (should always be in multiple of words)
+ * Please refer test applications on how to properly pack
+ * the buffer to receive data. Also DMA transfers should require
+ * dma coherent buffers (pls refer test app on how to do this).
+ **/
+static ssize_t
+hsidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+ struct hsidev_data *hsidev;
+ ssize_t status = 0;
+ int missing = 0;
+ struct hsi_data *xferdata;
+
+ hsidev = (struct hsidev_data *)filp->private_data;
+ mutex_lock(&hsidev->hsidev_lock);
+
+ if (hsidev->hsi->cid != 1 ||
+ hsidev->hsi->curr_mode == HSI_POLLING_MODE) {
+ mutex_unlock(&hsidev->hsidev_lock);
+ return -EINVAL;
+ }
+
+ if (hsidev->xfer && hsidev->xfer->data) {/* On going transfer */
+ mutex_unlock(&hsidev->hsidev_lock);
+ return -EBUSY;
+ }
+
+ if (!hsidev->xfer) {
+ xferdata = kzalloc(sizeof(struct hsi_data), GFP_KERNEL);
+ if (!xferdata) {
+ mutex_unlock(&hsidev->hsidev_lock);
+ return -ENOMEM;
+ }
+ hsidev->xfer = xferdata;
+ }
+ xferdata = hsidev->xfer;
+ hsidev->xfer_done = 0; /* Reset some fields */
+ xferdata->count = count;
+
+ if (hsidev->hsi->curr_mode == HSI_DMA_MODE) {
+ xferdata->is_dma = 1;
+ xferdata->data = dma_alloc_coherent(NULL, count,
+ &xferdata->dma_addr,
+ GFP_DMA);
+ } else {
+ xferdata->is_dma = 0;
+ xferdata->data = kmalloc(count, GFP_KERNEL);
+ }
+
+ if (!xferdata->data) {
+ mutex_unlock(&hsidev->hsidev_lock);
+ return -ENOMEM;
+ }
+
+ status = hsi_read(hsidev->hsi, xferdata);
+ if (status)
+ goto out_err;
+
+ status = wait_event_interruptible(hsidev->wq, hsidev->xfer_done);
+ /* Check interrupted call, need to abort transfer */
+ if (status)
+ hsi_read_cancel(hsidev->hsi);
+ else {
+ missing = copy_to_user(buf, xferdata->data, count);
+ if (missing)
+ status = -EFAULT;
+ }
+
+out_err:
+ if (xferdata->is_dma)
+ dma_free_coherent(NULL, count,
+ xferdata->data, xferdata->dma_addr);
+ else
+ kfree(xferdata->data);
+
+ xferdata->data = NULL;
+ xferdata->dma_addr = (dma_addr_t) 0;
+ mutex_unlock(&hsidev->hsidev_lock);
+ return status;
+}
+
+/** data - pointer to data
+ * datawidth - in bits i.e 16 - 16bits, 32 - 32bits
+ * count - total number of data bytes to send (should always be in
+ * multiple of words)
+ *
+ * Please refer test applications on how to pack the data to be sent.
+ * Also DMA transfers should require dma coherent buffers (pls refer test
+ * app on how to do this)
+ */
+static ssize_t
+hsidev_write(struct file *filp, const char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ struct hsidev_data *hsidev;
+ ssize_t status = 0;
+ int missing = 0;
+ struct hsi_data *xferdata;
+
+ hsidev = (struct hsidev_data *)filp->private_data;
+ mutex_lock(&hsidev->hsidev_lock);
+
+ if (hsidev->hsi->cid != 0 ||
+ hsidev->hsi->curr_mode == HSI_POLLING_MODE){
+ mutex_unlock(&hsidev->hsidev_lock);
+ return -EINVAL;
+ }
+
+ if (hsidev->xfer && hsidev->xfer->data) { /* On going transfer */
+ mutex_unlock(&hsidev->hsidev_lock);
+ return -EBUSY;
+ }
+
+ if (!hsidev->xfer) {
+ xferdata = kzalloc(sizeof(struct hsi_data), GFP_KERNEL);
+ if (!xferdata) {
+ mutex_unlock(&hsidev->hsidev_lock);
+ return -ENOMEM;
+ }
+ hsidev->xfer = xferdata;
+ }
+ xferdata = hsidev->xfer;
+ hsidev->xfer_done = 0; /* Reset some fields */
+
+ if (hsidev->hsi->curr_mode == HSI_DMA_MODE) {
+ xferdata->is_dma = 1;
+ xferdata->data = dma_alloc_coherent(NULL, count,
+ &xferdata->dma_addr,
+ GFP_DMA);
+ } else {
+ xferdata->is_dma = 0;
+ xferdata->data = kzalloc(count, GFP_KERNEL);
+ }
+
+ if (!xferdata->data) {
+ mutex_unlock(&hsidev->hsidev_lock);
+ return -ENOMEM;
+ }
+
+ missing = copy_from_user(xferdata->data, buf, count);
+ if (missing) {
+ status = -EFAULT;
+ goto out_err;
+ }
+
+ xferdata->count = count;
+ status = hsi_write(hsidev->hsi, xferdata);
+ if (!status)
+ status =
+ wait_event_interruptible(hsidev->wq, hsidev->xfer_done);
+ else
+ goto out_err;
+
+ /* Check interrupted call, need to abort transfer */
+ if (status)
+ hsi_write_cancel(hsidev->hsi);
+
+out_err:
+ if (xferdata->is_dma)
+ dma_free_coherent(NULL, count,
+ xferdata->data, xferdata->dma_addr);
+ else
+ kfree(xferdata->data);
+
+ xferdata->data = NULL;
+ xferdata->dma_addr = (dma_addr_t) 0;
+ mutex_unlock(&hsidev->hsidev_lock);
+ return status;
+}
+
+static int hsidev_release(struct inode *inode, struct file *filp)
+{
+ struct hsidev_data *hsidev;
+ int status = 0;
+
+ mutex_lock(&device_list_lock);
+ hsidev = filp->private_data;
+ hsi_close(hsidev->hsi);
+ filp->private_data = NULL;
+
+ /* last close? */
+ mutex_lock(&hsidev->hsidev_lock);
+ hsidev->users--;
+ if (!hsidev->users) {
+ kfree(hsidev->xfer);
+ hsidev->xfer = NULL;
+ }
+ mutex_unlock(&hsidev->hsidev_lock);
+
+ mutex_unlock(&device_list_lock);
+
+ return status;
+}
+
+/** NOTE: before sending/receiving data the user should set an appropriate
+ * watermark through this ioctl. The watermark determines how often the low
+ * level HSI driver is interrupted to send/receive data on the link. The user
+ * will be notified through callback only when all the data has been sent or
+ * received
+ */
+
+static long hsidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ u32 tmp;
+ int size = 0;
+ struct hsidev_data *hsidev;
+
+ /* Check type and command number */
+ if (_IOC_TYPE(cmd) != HSI_IOC_MAGIC)
+ return -ENOTTY;
+
+ /* Check access direction once here; don't repeat below.
+ * IOC_DIR is from the user perspective, while access_ok is
+ * from the kernel perspective; so they look reversed.
+ */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE,
+ (void __user *)arg, _IOC_SIZE(cmd));
+ if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ,
+ (void __user *)arg, _IOC_SIZE(cmd));
+ if (err)
+ return -EFAULT;
+
+ /* guard against device removal before, or while,
+ * we issue this ioctl.
+ */
+ hsidev = filp->private_data;
+ get_device(&hsidev->hsi->dev);
+
+ /* use the device lock here for triple duty:
+ * - prevent concurrent HSI_IOC_WR_* from morphing
+ * data fields while HSI_IOC_RD_* reads them;
+ * - Prevent changing mode during an ongoing transfer
+ */
+ mutex_lock(&hsidev->hsidev_lock);
+
+ size = _IOC_SIZE(cmd);
+ tmp = 0;
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ err = copy_from_user((void *)&tmp, (void *)arg, size);
+ if (err != 0)
+ goto out_err;
+ }
+ err = hsi_ioctl(hsidev->hsi, cmd, &tmp);
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = copy_to_user((void *)arg, (void *)&tmp, size);
+out_err:
+ mutex_unlock(&hsidev->hsidev_lock);
+ put_device(&hsidev->hsi->dev);
+ return err;
+
+}
+
+void hsi_testprot_excep_handler(u32 ctrlr_id, u32 event, void *arg)
+{
+ u8 chid;
+ /** exceptions are received only on HSIR */
+ if (ctrlr_id != HSIR_CTRLR_ID) {
+ stm_dbg(DBG_ST.hsi, "HSIDEV:excep on wrong ctrlr\n");
+ return;
+ }
+
+ /** NOTE: an actual protocol driver is expected to do proper
+ * exception handling. This could include flushing its buffers,
+ * cancelling read, informing the TX through a message to
+ * resend/start sending data
+ *
+ * Apart from informing the protocol driver the lowlevel HSI driver
+ * does not perform any operations on receiving an exception,
+ * except when it receives :
+ * HSI_EXCEP_PIPEBUF_OVERRUN,
+ * where it flushes HSIR pipeline buffer
+ * HSI_RXCHANNELS_OVERRUN ,
+ * where it flushes the HSIR channel buffer
+ */
+ switch (event) {
+ case HSI_EXCEP_TIMEOUT:
+ stm_dbg(DBG_ST.hsi,
+ "HSI test protocol driver:TIMEOUT received\n");
+ break;
+ case HSI_EXCEP_PIPEBUF_OVERRUN:
+ /** HSI has flushed pipeline buffer... *
+ * protocol driver MUST take appropriate *
+ * action *
+ **/
+ stm_dbg(DBG_ST.hsi,
+ "HSI test protocol driver:PIPEBUF OVERRUN received\n");
+ break;
+ case HSI_EXCEP_BREAK_DETECTED:
+ stm_dbg(DBG_ST.hsi,
+ "HSI test protocol driver:BREAK DETECT received\n");
+ break;
+ case HSI_EXCEP_PARITY_ERROR:
+ stm_dbg(DBG_ST.hsi,
+ "HSI test protocol driver: PARITY ERROR received\n");
+ break;
+ case HSI_RXCHANNELS_OVERRUN:
+ /** HSI has flushed corresponding channel buffer *
+ *...protocol driver MUST take appropriate action *
+ **/
+ chid = *(u8 *) arg;
+ stm_dbg(DBG_ST.hsi,
+ "HSI test protocol driver: CHANNEL %d OVERRUN \n",
+ chid);
+ break;
+ }
+
+}
+
+int hsi_testprot_drv_resume(struct hsi_device *dev)
+{
+ /*TODO: PM */
+ return 0;
+}
+
+int hsi_testprot_drv_suspend(struct hsi_device *dev, pm_message_t state)
+{
+ /*TODO*/ return 0;
+}
+
+static struct class *hsidev_class;
+
+static int __init hsidev_probe(struct hsi_device *dev)
+{
+ int minor;
+ int status = 0;
+ unsigned long *minors;
+ struct device *devc;
+ struct hsidev_data *hsidev;
+
+ stm_dbg(DBG_ST.hsi,
+ "HSI test loopback protocol driver: device %s probed \n",
+ dev->dev.bus_id);
+ /* Allocate driver data */
+ hsidev = kzalloc(sizeof(struct hsidev_data), GFP_KERNEL);
+ if (!hsidev)
+ return -ENOMEM;
+
+ mutex_init(&hsidev->hsidev_lock);
+ /* Initialize the driver data */
+ hsidev->hsi = dev;
+ minors = dev->cid ? &rx_minors : &tx_minors;
+
+ minor = find_first_zero_bit(minors, N_HSI_MINORS);
+ if (minor > 3) {
+ stm_dbg(DBG_ST.hsi, "Minor %d invalid\n", minor);
+ return -EBUSY;
+ }
+
+ mutex_lock(&device_list_lock);
+ if (minor < N_HSI_MINORS) {
+ int minor_t = minor;
+ if (dev->cid == 0x1)
+ minor_t += MAX_CHANNELS_MONITORED;
+
+ hsidev->devt = MKDEV(HSIDEV_MAJOR, minor_t);
+ devc = device_create(hsidev_class, &dev->dev,
+ hsidev->devt, hsidev,
+ "hsidev%d.%d", dev->cid, minor_t);
+ status = IS_ERR(devc) ? PTR_ERR(devc) : 0;
+ } else {
+ dev_dbg(&dev->dev, "no minor number available!\n");
+ status = -ENODEV;
+ }
+ if (status == 0) {
+ set_bit(minor, minors);
+ list_add(&hsidev->device_entry, &device_list);
+ }
+ dev_set_drvdata(&dev->dev, (void *)hsidev);
+ mutex_unlock(&device_list_lock);
+
+ if (status != 0)
+ kfree(hsidev);
+
+ /* Initialize wait queue on which to block */
+ init_waitqueue_head(&hsidev->wq);
+
+ return status;
+}
+
+static int __exit hsidev_remove(struct hsi_device *dev)
+{
+ struct hsidev_data *hsidev = dev_get_drvdata(&dev->dev);
+ unsigned long *minors;
+ /* make sure ops on existing fds can abort cleanly */
+ hsidev->hsi = NULL;
+ dev_set_drvdata(&dev->dev, NULL);
+
+ /* prevent new opens */
+ mutex_lock(&device_list_lock);
+ list_del(&hsidev->device_entry);
+ device_destroy(hsidev_class, hsidev->devt);
+ minors = dev->cid ? &rx_minors : &tx_minors;
+ clear_bit(MINOR(hsidev->devt), minors);
+ if (hsidev->users == 0)
+ kfree(hsidev);
+ hsi_set_callback(dev, NULL, NULL);
+ mutex_unlock(&device_list_lock);
+ return 0;
+}
+
+static struct hsi_device_driver hsidev_driver = {
+ /** HSI controller ids to monitor: 0 - transmit and 1 - receive */
+ .ctrl_mask = 0x3,
+ /** HSI channels ids to monitor: 0xF - ch0,ch1,ch2,ch3 */
+ .ch_mask = 0xF,
+ /** HSI exception mask : set exceptions you want to receive
+ * bit 0: link timeout, bit 1: pipebuf overrun, bit2: break detection
+ * bit 3: link parity error, bit 4: rx channels overrun
+ */
+ .excep_mask = 0x1F,
+ .excep_event = hsi_testprot_excep_handler,
+ .probe = hsidev_probe,
+ .remove = __exit_p(hsidev_remove),
+ .resume = hsi_testprot_drv_resume,
+ .suspend = hsi_testprot_drv_suspend,
+ .driver = {
+ .name = HSI_TESTPROT_DRIVER_NAME,
+ },
+};
+
+/* The main reason to have this class is to make mdev/udev create the
+ * /dev/hsidevB.C character device nodes exposing our userspace API.
+ * It also simplifies memory management.
+ */
+
+static struct file_operations hsidev_fops = {
+ .owner = THIS_MODULE,
+ .write = hsidev_write,
+ .read = hsidev_read,
+ .unlocked_ioctl = hsidev_ioctl,
+ .open = hsidev_open,
+ .release = hsidev_release,
+};
+
+static int __init hsi_testprot_init(void)
+{
+ int status;
+
+ status = register_chrdev(HSIDEV_MAJOR, "hsi", &hsidev_fops);
+ if (status < 0)
+ return status;
+
+ hsidev_class = class_create(THIS_MODULE, "hsidev");
+ if (IS_ERR(hsidev_class)) {
+ unregister_chrdev(HSIDEV_MAJOR, hsidev_driver.driver.name);
+ return PTR_ERR(hsidev_class);
+ }
+
+ status = register_hsi_driver(&hsidev_driver);
+ if (status < 0) {
+ class_destroy(hsidev_class);
+ unregister_chrdev(HSIDEV_MAJOR, hsidev_driver.driver.name);
+ stm_dbg(DBG_ST.hsi,
+ "HSIDEV driver registration failed\n");
+ return status;
+ }
+ printk(KERN_NOTICE"hsidev initialized\n");
+
+ return 0;
+}
+
+static void __exit hsi_testprot_exit(void)
+{
+ unregister_hsi_driver(&hsidev_driver);
+ class_destroy(hsidev_class);
+ unregister_chrdev(HSIDEV_MAJOR, hsidev_driver.driver.name);
+ printk(KERN_NOTICE"hsidev removed\n");
+}
+
+module_init(hsi_testprot_init);
+module_exit(hsi_testprot_exit);
+
+MODULE_AUTHOR("STMicroelectronics");
+MODULE_DESCRIPTION("HSI test protocol driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/hwmem/Makefile b/drivers/misc/hwmem/Makefile
new file mode 100644
index 00000000000..b554fa6d70b
--- /dev/null
+++ b/drivers/misc/hwmem/Makefile
@@ -0,0 +1,3 @@
+hwmem-objs := hwmem-main.o hwmem-ioctl.o hwmem-cache.o hwmem-cache_ux500.o
+
+obj-$(CONFIG_HWMEM) += hwmem.o
diff --git a/drivers/misc/hwmem/hwmem-cache.c b/drivers/misc/hwmem/hwmem-cache.c
new file mode 100644
index 00000000000..de7ef83eb37
--- /dev/null
+++ b/drivers/misc/hwmem/hwmem-cache.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Hardware memory driver, hwmem
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/hwmem.h>
+
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+#include <asm/outercache.h>
+
+#include "hwmem-defs.h"
+
+#include "hwmem-cache.h"
+
+extern void hwmem_drain_cpu_write_buf(void);
+extern void hwmem_clean_cpu_cache(u32 virt_start, u32 virt_end, u32 phys_start,
+ u32 phys_end, enum hwmem_cache_options cache_settings);
+extern void hwmem_flush_cpu_cache(u32 virt_start, u32 virt_end, u32 phys_start,
+ u32 phys_end, enum hwmem_cache_options cache_settings);
+
+static void sync_alloc_cpu(struct hwmem_alloc *alloc, enum hwmem_access access,
+ struct hwmem_region *region);
+
+static void store_alloc_usage_cpu(struct hwmem_alloc *alloc,
+ enum hwmem_access access, struct hwmem_region *region);
+
+static void clean_range(struct hwmem_range *range);
+static void expand_range(struct hwmem_range *range,
+ struct hwmem_range *range_2_add);
+static void expand_range_2_edge(struct hwmem_range *range,
+ struct hwmem_range *encapsulating_range);
+static void shrink_range(struct hwmem_range *range,
+ struct hwmem_range *range_2_remove);
+static bool is_non_empty_range(struct hwmem_range *range);
+static void intersect_range(struct hwmem_range *src_1,
+ struct hwmem_range *src_2, struct hwmem_range *dst);
+static void region_2_range(struct hwmem_region *region, u32 buffer_start,
+ u32 buffer_size, struct hwmem_range *range);
+
+static u32 hwmem_phys_2_virt(u32 phys_addr);
+
+/*
+ * Exported functions
+ */
+
+void __attribute__((weak)) hwmem_set_pgprot_cache_options(
+ struct hwmem_alloc *alloc, pgprot_t *pgprot)
+{
+ if ((alloc->flags & HWMEM_ALLOC_CACHED) == HWMEM_ALLOC_CACHED) {
+ /*
+ * If the alloc is cached we'll use the default setting. We
+ * don't no what this setting is so we have to assume the
+ * worst case, ie "write back, alloc on read and write, inner
+ * and outer".
+ */
+ alloc->cache_settings = HWMEM_CACHE_OPTION_ALLOC_ON_READ |
+ HWMEM_CACHE_OPTION_ALLOC_ON_WRITE |
+ HWMEM_CACHE_OPTION_WRITE_BACK |
+ HWMEM_CACHE_OPTION_INNER_ACTIVE |
+ HWMEM_CACHE_OPTION_OUTER_ACTIVE;
+ } else if ((alloc->flags & HWMEM_ALLOC_BUFFERED) ==
+ HWMEM_ALLOC_BUFFERED) {
+ *pgprot = pgprot_writecombine(*pgprot);
+ } else {
+ *pgprot = pgprot_noncached(*pgprot);
+ }
+}
+
+void hwmem_sync_alloc(struct hwmem_alloc *alloc, enum hwmem_access access,
+ struct hwmem_region *region, enum hwmem_domain domain)
+{
+ switch (domain) {
+ case HWMEM_DOMAIN_SYNC: /* All the domains */
+ sync_alloc_cpu(alloc, access, region);
+
+ break;
+
+ case HWMEM_DOMAIN_CPU:
+ sync_alloc_cpu(alloc, access, region);
+
+ break;
+ }
+}
+
+void clean_alloc_cache_info(struct hwmem_alloc *alloc)
+{
+ alloc->cache_settings = 0;
+ alloc->in_cpu_write_buf = false;
+ clean_range(&alloc->range_in_cpu_cache);
+ clean_range(&alloc->range_dirty_in_cpu_cache);
+}
+
+void hwmem_store_alloc_usage(struct hwmem_alloc *alloc,
+ enum hwmem_access access, struct hwmem_region *region,
+ enum hwmem_domain domain)
+{
+ switch (domain) {
+ case HWMEM_DOMAIN_SYNC:
+ /*
+ * Illegal parameter, will never happen. Case just added to
+ * silence compiler warning.
+ */
+ break;
+
+ case HWMEM_DOMAIN_CPU:
+ store_alloc_usage_cpu(alloc, access, region);
+
+ break;
+ }
+}
+
+/*
+ * Local functions
+ */
+
+static void sync_alloc_cpu(struct hwmem_alloc *alloc, enum hwmem_access access,
+ struct hwmem_region *region)
+{
+ bool write = access & HWMEM_ACCESS_WRITE;
+ bool read = access & HWMEM_ACCESS_READ;
+ struct hwmem_range region_range;
+
+ if (!write && !read)
+ return;
+
+ region_2_range(region, alloc->start, alloc->size, &region_range);
+
+ /*
+ * Order is important here, if read is evaluated before write we risk
+ * doing a clean before flush which is a waste of time.
+ */
+ if (write) {
+ struct hwmem_range intersection = {~0, 0};
+
+ intersect_range(&alloc->range_in_cpu_cache, &region_range,
+ &intersection);
+
+ if (is_non_empty_range(&intersection)) {
+ expand_range_2_edge(&intersection,
+ &alloc->range_in_cpu_cache);
+
+ hwmem_flush_cpu_cache(
+ hwmem_phys_2_virt(intersection.start),
+ hwmem_phys_2_virt(intersection.end),
+ intersection.start, intersection.end,
+ alloc->cache_settings);
+
+ shrink_range(&alloc->range_in_cpu_cache,
+ &intersection);
+ shrink_range(&alloc->range_dirty_in_cpu_cache,
+ &intersection);
+ }
+ }
+ if (read) {
+ struct hwmem_range intersection = {~0, 0};
+
+ intersect_range(&alloc->range_dirty_in_cpu_cache,
+ &region_range, &intersection);
+
+ if (is_non_empty_range(&intersection)) {
+ expand_range_2_edge(&intersection,
+ &alloc->range_dirty_in_cpu_cache);
+
+ hwmem_clean_cpu_cache(
+ hwmem_phys_2_virt(intersection.start),
+ hwmem_phys_2_virt(intersection.end),
+ intersection.start, intersection.end,
+ alloc->cache_settings);
+
+ shrink_range(&alloc->range_dirty_in_cpu_cache,
+ &intersection);
+ }
+ }
+
+ if (alloc->in_cpu_write_buf) {
+ hwmem_drain_cpu_write_buf();
+
+ alloc->in_cpu_write_buf = false;
+ }
+}
+
+static void store_alloc_usage_cpu(struct hwmem_alloc *alloc,
+ enum hwmem_access access, struct hwmem_region *region)
+{
+ bool write = access & HWMEM_ACCESS_WRITE;
+ bool read = access & HWMEM_ACCESS_READ;
+
+ if (!write && !read)
+ return;
+
+ if ((alloc->flags & HWMEM_ALLOC_CACHED) == HWMEM_ALLOC_CACHED) {
+ struct hwmem_range region_range;
+
+ region_2_range(region, alloc->start, alloc->size,
+ &region_range);
+
+ if ((read && (alloc->cache_settings &
+ HWMEM_CACHE_OPTION_ALLOC_ON_READ)) ||
+ (write && (alloc->cache_settings &
+ HWMEM_CACHE_OPTION_ALLOC_ON_WRITE))) {
+ expand_range(&alloc->range_in_cpu_cache,
+ &region_range);
+
+ if (write && ((alloc->cache_settings &
+ HWMEM_CACHE_OPTION_WRITE_BACK) ==
+ HWMEM_CACHE_OPTION_WRITE_BACK))
+ expand_range(&alloc->range_dirty_in_cpu_cache,
+ &region_range);
+ }
+ }
+
+ if (alloc->flags & HWMEM_ALLOC_BUFFERED) {
+ if (write)
+ alloc->in_cpu_write_buf = true;
+ }
+}
+
+static void clean_range(struct hwmem_range *range)
+{
+ range->start = ~0;
+ range->end = 0;
+}
+
+static void expand_range(struct hwmem_range *range,
+ struct hwmem_range *range_2_add)
+{
+ range->start = min(range->start, range_2_add->start);
+ range->end = max(range->end, range_2_add->end);
+}
+
+/*
+ * Expands range to one of enclosing_range's two edges. The function will
+ * choose which of enclosing_range's edges to expand range to in such a
+ * way that the size of range is minimized. range must be located inside
+ * enclosing_range.
+ */
+static void expand_range_2_edge(struct hwmem_range *range,
+ struct hwmem_range *enclosing_range)
+{
+ u32 space_on_low_side = range->start - enclosing_range->start;
+ u32 space_on_high_side = enclosing_range->end - range->end;
+
+ if (space_on_low_side < space_on_high_side)
+ range->start = enclosing_range->start;
+ else
+ range->end = enclosing_range->end;
+}
+
+/* Will always cut on the higher value side if there is a choice. */
+static void shrink_range(struct hwmem_range *range,
+ struct hwmem_range *range_2_remove)
+{
+ if (range_2_remove->start > range->start)
+ range->end = min(range->end, range_2_remove->start);
+ else
+ range->start = max(range->start, range_2_remove->end);
+
+ if (range->start >= range->end) {
+ range->start = ~0;
+ range->end = 0;
+ }
+}
+
+static bool is_non_empty_range(struct hwmem_range *range)
+{
+ return range->end > range->start;
+}
+
+static void intersect_range(struct hwmem_range *src_1,
+ struct hwmem_range *src_2, struct hwmem_range *dst)
+{
+ dst->start = max(src_1->start, src_2->start);
+ dst->end = min(src_1->end, src_2->end);
+}
+
+static void region_2_range(struct hwmem_region *region, u32 buffer_start,
+ u32 buffer_size, struct hwmem_range *range)
+{
+ /*
+ * We don't care about invalid regions, instead we limit the region's
+ * range to the buffer's range. This should work good enough, worst
+ * case we synch the entire buffer when we get an invalid region which
+ * is acceptable.
+ */
+ range->start =
+ max(buffer_start + region->skip * region->size + region->start,
+ buffer_start);
+ range->end = min(buffer_start + (region->skip + region->count) *
+ region->size - (region->size - region->end), buffer_start +
+ buffer_size);
+
+ if (range->start >= range->end) {
+ range->start = ~0;
+ range->end = 0;
+ }
+}
+
+static u32 hwmem_phys_2_virt(u32 phys_addr)
+{
+ return (u32)hwmem_kaddr + (phys_addr - hwmem_start);
+}
diff --git a/drivers/misc/hwmem/hwmem-cache.h b/drivers/misc/hwmem/hwmem-cache.h
new file mode 100644
index 00000000000..87a8a69b2d8
--- /dev/null
+++ b/drivers/misc/hwmem/hwmem-cache.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Hardware memory driver, hwmem
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef _HWMEM_CACHE_H_
+#define _HWMEM_CACHE_H_
+
+#include <linux/types.h>
+
+void hwmem_set_pgprot_cache_options(struct hwmem_alloc *alloc,
+ pgprot_t *pgprot);
+void hwmem_sync_alloc(struct hwmem_alloc *alloc, enum hwmem_access access,
+ struct hwmem_region *region, enum hwmem_domain domain);
+
+void clean_alloc_cache_info(struct hwmem_alloc *alloc);
+void hwmem_store_alloc_usage(struct hwmem_alloc *alloc,
+ enum hwmem_access access, struct hwmem_region *region,
+ enum hwmem_domain domain);
+
+#endif /* _HWMEM_CACHE_H_ */
diff --git a/drivers/misc/hwmem/hwmem-cache_ux500.c b/drivers/misc/hwmem/hwmem-cache_ux500.c
new file mode 100644
index 00000000000..536361ac48c
--- /dev/null
+++ b/drivers/misc/hwmem/hwmem-cache_ux500.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Hardware memory driver, hwmem
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/hwmem.h>
+
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+#include <asm/outercache.h>
+#include <asm/system.h>
+
+#include "hwmem-defs.h"
+
+void hwmem_set_pgprot_cache_options(struct hwmem_alloc *alloc,
+ pgprot_t *pgprot)
+{
+ if ((alloc->flags & HWMEM_ALLOC_CACHED) == HWMEM_ALLOC_CACHED) {
+ int cache_hint = alloc->flags & HWMEM_ALLOC_CACHE_HINT_MASK;
+ if (cache_hint == HWMEM_ALLOC_CACHE_HINT_WT ||
+ cache_hint == HWMEM_ALLOC_CACHE_HINT_WT_INNER) {
+ /* TODO: Add pgprot_cached_wt() to pgtable.h */
+ *pgprot = __pgprot_modify(*pgprot, L_PTE_MT_MASK,
+ L_PTE_MT_WRITETHROUGH);
+
+ alloc->cache_settings =
+ HWMEM_CACHE_OPTION_ALLOC_ON_READ |
+ HWMEM_CACHE_OPTION_WRITE_THROUGH |
+ HWMEM_CACHE_OPTION_INNER_ACTIVE |
+ HWMEM_CACHE_OPTION_OUTER_ACTIVE;
+ } else {
+ /* TODO: Add pgprot_cached_wb() to pgtable.h */
+ *pgprot = __pgprot_modify(*pgprot, L_PTE_MT_MASK,
+ L_PTE_MT_WRITEBACK);
+
+ alloc->cache_settings =
+ HWMEM_CACHE_OPTION_ALLOC_ON_READ |
+ HWMEM_CACHE_OPTION_WRITE_BACK |
+ HWMEM_CACHE_OPTION_INNER_ACTIVE |
+ HWMEM_CACHE_OPTION_OUTER_ACTIVE;
+ }
+ } else if ((alloc->flags & HWMEM_ALLOC_BUFFERED) ==
+ HWMEM_ALLOC_BUFFERED) {
+ *pgprot = pgprot_writecombine(*pgprot);
+ } else {
+ *pgprot = pgprot_noncached(*pgprot);
+ }
+}
+
+void hwmem_drain_cpu_write_buf(void)
+{
+ dsb();
+ outer_sync();
+}
+
+void hwmem_clean_cpu_cache(u32 virt_start, u32 virt_end, u32 phys_start,
+ u32 phys_end, enum hwmem_cache_options cache_settings)
+{
+ if (cache_settings & HWMEM_CACHE_OPTION_INNER_ACTIVE)
+ /* There is no dmac_clean_range() */
+ dmac_flush_range((void *)virt_start, (void *)virt_end);
+ if (cache_settings & HWMEM_CACHE_OPTION_OUTER_ACTIVE)
+ outer_clean_range(phys_start, phys_end);
+}
+
+void hwmem_flush_cpu_cache(u32 virt_start, u32 virt_end, u32 phys_start,
+ u32 phys_end, enum hwmem_cache_options cache_settings)
+{
+ if (cache_settings & HWMEM_CACHE_OPTION_INNER_ACTIVE)
+ dmac_flush_range((void *)virt_start, (void *)virt_end);
+ if (cache_settings & HWMEM_CACHE_OPTION_OUTER_ACTIVE)
+ outer_flush_range(phys_start, phys_end);
+}
diff --git a/drivers/misc/hwmem/hwmem-defs.h b/drivers/misc/hwmem/hwmem-defs.h
new file mode 100644
index 00000000000..a71363bd963
--- /dev/null
+++ b/drivers/misc/hwmem/hwmem-defs.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Hardware memory driver, hwmem
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef _HWMEM_DEFS_H_
+#define _HWMEM_DEFS_H_
+
+#include <linux/types.h>
+#include <linux/hwmem.h>
+#include <linux/pid.h>
+#include <linux/list.h>
+
+extern u32 hwmem_start;
+extern u32 hwmem_size;
+extern void *hwmem_kaddr;
+
+struct hwmem_alloc_threadg_info {
+ struct list_head list;
+
+ struct pid *threadg_pid; /* Ref counted */
+
+ enum hwmem_access access;
+};
+
+enum hwmem_cache_options {
+ HWMEM_CACHE_OPTION_ALLOC_ON_READ = (1 << 0),
+ HWMEM_CACHE_OPTION_ALLOC_ON_WRITE = (1 << 1),
+ HWMEM_CACHE_OPTION_WRITE_THROUGH = (1 << 2),
+ HWMEM_CACHE_OPTION_WRITE_BACK = (2 << 2),
+ HWMEM_CACHE_OPTION_INNER_ACTIVE = (1 << 4),
+ HWMEM_CACHE_OPTION_OUTER_ACTIVE = (1 << 5)
+};
+
+struct hwmem_range {
+ u32 start; /* Inclusive */
+ u32 end; /* Exclusive */
+};
+
+struct hwmem_alloc {
+ struct list_head list;
+
+ atomic_t ref_cnt;
+ enum hwmem_alloc_flags flags;
+ u32 start;
+ u32 size;
+ u32 name;
+
+ /* Access control */
+ enum hwmem_access default_access;
+ struct list_head threadg_info_list;
+
+ /* Caching */
+ enum hwmem_cache_options cache_settings;
+ bool in_cpu_write_buf;
+ struct hwmem_range range_in_cpu_cache;
+ struct hwmem_range range_dirty_in_cpu_cache;
+};
+
+#endif /* _HWMEM_DEFS_H_ */
diff --git a/drivers/misc/hwmem/hwmem-ioctl.c b/drivers/misc/hwmem/hwmem-ioctl.c
new file mode 100644
index 00000000000..b1fc8446949
--- /dev/null
+++ b/drivers/misc/hwmem/hwmem-ioctl.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Hardware memory driver, hwmem
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/mm_types.h>
+#include <linux/hwmem.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+
+/*
+ * TODO:
+ * Count pin unpin at this level to ensure applications can't interfer
+ * with each other.
+ */
+
+static int hwmem_open(struct inode *inode, struct file *file);
+static int hwmem_ioctl_mmap(struct file *file, struct vm_area_struct *vma);
+static int hwmem_release_fop(struct inode *inode, struct file *file);
+static long hwmem_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
+static unsigned long hwmem_get_unmapped_area(struct file *file,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags);
+
+static const struct file_operations hwmem_fops = {
+ .open = hwmem_open,
+ .mmap = hwmem_ioctl_mmap,
+ .unlocked_ioctl = hwmem_ioctl,
+ .release = hwmem_release_fop,
+ .get_unmapped_area = hwmem_get_unmapped_area,
+};
+
+static struct miscdevice hwmem_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "hwmem",
+ .fops = &hwmem_fops,
+};
+
+struct hwmem_file {
+ struct mutex lock;
+ struct idr idr; /* id -> struct hwmem_alloc*, ref counted */
+ struct hwmem_alloc *fd_alloc; /* Ref counted */
+};
+
+static int create_id(struct hwmem_file *hwfile, struct hwmem_alloc *alloc)
+{
+ int id, ret;
+
+ while (true) {
+ if (idr_pre_get(&hwfile->idr, GFP_KERNEL) == 0)
+ return -ENOMEM;
+
+ ret = idr_get_new_above(&hwfile->idr, alloc, 1, &id);
+ if (ret == 0)
+ break;
+ else if (ret != -EAGAIN)
+ return -ENOMEM;
+ }
+
+ /*
+ * TODO: This isn't great as we destroy IDR's ability to reuse freed
+ * IDs. Currently we can use 19 bits for the ID ie 524388 IDs can be
+ * generated by a hwmem file instance before this function starts
+ * failing. This should be enough for most scenarios but the final
+ * solution for this problem is to change IDR so that you can specify
+ * a maximum ID.
+ */
+ if (id >= 1 << (31 - PAGE_SHIFT)) {
+ dev_err(hwmem_device.this_device, "ID overflow!\n");
+ idr_remove(&hwfile->idr, id);
+ return -ENOMSG;
+ }
+
+ return id << PAGE_SHIFT;
+}
+
+static void remove_id(struct hwmem_file *hwfile, int id)
+{
+ idr_remove(&hwfile->idr, id >> PAGE_SHIFT);
+}
+
+static struct hwmem_alloc *resolve_id(struct hwmem_file *hwfile, int id)
+{
+ struct hwmem_alloc *alloc;
+
+ alloc = id ? idr_find(&hwfile->idr, id >> PAGE_SHIFT) :
+ hwfile->fd_alloc;
+ if (alloc == NULL)
+ alloc = ERR_PTR(-EINVAL);
+
+ return alloc;
+}
+
+static int alloc(struct hwmem_file *hwfile, struct hwmem_alloc_request *req)
+{
+ int ret = 0;
+ struct hwmem_alloc *alloc;
+
+ alloc = hwmem_alloc(req->size, req->flags, req->default_access,
+ req->mem_type);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ ret = create_id(hwfile, alloc);
+ if (ret < 0)
+ hwmem_release(alloc);
+
+ return ret;
+}
+
+static int alloc_fd(struct hwmem_file *hwfile, struct hwmem_alloc_request *req)
+{
+ struct hwmem_alloc *alloc;
+
+ if (hwfile->fd_alloc)
+ return -EBUSY;
+
+ alloc = hwmem_alloc(req->size, req->flags, req->default_access,
+ req->mem_type);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ hwfile->fd_alloc = alloc;
+
+ return 0;
+}
+
+static int release(struct hwmem_file *hwfile, s32 id)
+{
+ struct hwmem_alloc *alloc;
+
+ alloc = resolve_id(hwfile, id);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ remove_id(hwfile, id);
+ hwmem_release(alloc);
+
+ return 0;
+}
+
+static int hwmem_ioctl_set_domain(struct hwmem_file *hwfile,
+ struct hwmem_set_domain_request *req)
+{
+ struct hwmem_alloc *alloc;
+
+ alloc = resolve_id(hwfile, req->id);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ return hwmem_set_domain(alloc, req->access, req->domain, &req->region);
+}
+
+static int pin(struct hwmem_file *hwfile, struct hwmem_pin_request *req)
+{
+ struct hwmem_alloc *alloc;
+
+ alloc = resolve_id(hwfile, req->id);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ return hwmem_pin(alloc, &req->phys_addr, req->scattered_addrs);
+}
+
+static int unpin(struct hwmem_file *hwfile, s32 id)
+{
+ struct hwmem_alloc *alloc;
+
+ alloc = resolve_id(hwfile, id);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ hwmem_unpin(alloc);
+
+ return 0;
+}
+
+static int set_access(struct hwmem_file *hwfile,
+ struct hwmem_set_access_request *req)
+{
+ struct hwmem_alloc *alloc;
+
+ alloc = resolve_id(hwfile, req->id);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ return hwmem_set_access(alloc, req->access, req->pid);
+}
+
+static int get_info(struct hwmem_file *hwfile,
+ struct hwmem_get_info_request *req)
+{
+ struct hwmem_alloc *alloc;
+
+ alloc = resolve_id(hwfile, req->id);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ hwmem_get_info(alloc, &req->size, &req->mem_type, &req->access);
+
+ return 0;
+}
+
+static int export(struct hwmem_file *hwfile, s32 id)
+{
+ int ret;
+ struct hwmem_alloc *alloc;
+
+ uint32_t size;
+ enum hwmem_mem_type mem_type;
+ enum hwmem_access access;
+
+ alloc = resolve_id(hwfile, id);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ /*
+ * The user could be about to send the buffer to a driver but
+ * there is a chance the current thread group don't have import rights
+ * if it gained access to the buffer via a inter-process fd transfer
+ * (fork, Android binder), if this is the case the driver will not be
+ * able to resolve the buffer name. To avoid this situation we give the
+ * current thread group import rights. This will not breach the
+ * security as the process already has access to the buffer (otherwise
+ * it would not be able to get here).
+ */
+ hwmem_get_info(alloc, &size, &mem_type, &access);
+
+ ret = hwmem_set_access(alloc, (access | HWMEM_ACCESS_IMPORT),
+ task_tgid_nr(current));
+ if (ret < 0)
+ goto error;
+
+ return hwmem_get_name(alloc);
+
+error:
+ return ret;
+}
+
+static int import(struct hwmem_file *hwfile, s32 name)
+{
+ int ret = 0;
+ struct hwmem_alloc *alloc;
+
+ uint32_t size;
+ enum hwmem_mem_type mem_type;
+ enum hwmem_access access;
+
+ alloc = hwmem_resolve_by_name(name);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ /* Check access permissions for process */
+ hwmem_get_info(alloc, &size, &mem_type, &access);
+
+ if (!(access & HWMEM_ACCESS_IMPORT)) {
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = create_id(hwfile, alloc);
+ if (ret < 0)
+ hwmem_release(alloc);
+
+error:
+ return ret;
+}
+
+static int import_fd(struct hwmem_file *hwfile, s32 name)
+{
+ struct hwmem_alloc *alloc;
+
+ if (hwfile->fd_alloc)
+ return -EBUSY;
+
+ alloc = hwmem_resolve_by_name(name);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ hwfile->fd_alloc = alloc;
+
+ return 0;
+}
+
+static int hwmem_open(struct inode *inode, struct file *file)
+{
+ struct hwmem_file *hwfile;
+
+ hwfile = kzalloc(sizeof(struct hwmem_file), GFP_KERNEL);
+ if (hwfile == NULL)
+ return -ENOMEM;
+
+ idr_init(&hwfile->idr);
+ mutex_init(&hwfile->lock);
+ file->private_data = hwfile;
+
+ return 0;
+}
+
+static int hwmem_ioctl_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct hwmem_file *hwfile = (struct hwmem_file *)file->private_data;
+ struct hwmem_alloc *alloc;
+
+ alloc = resolve_id(hwfile, vma->vm_pgoff << PAGE_SHIFT);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ return hwmem_mmap(alloc, vma);
+}
+
+static int hwmem_release_idr_for_each_wrapper(int id, void *ptr, void *data)
+{
+ hwmem_release((struct hwmem_alloc *)ptr);
+
+ return 0;
+}
+
+static int hwmem_release_fop(struct inode *inode, struct file *file)
+{
+ struct hwmem_file *hwfile = (struct hwmem_file *)file->private_data;
+
+ idr_for_each(&hwfile->idr, hwmem_release_idr_for_each_wrapper, NULL);
+ idr_destroy(&hwfile->idr);
+
+ if (hwfile->fd_alloc)
+ hwmem_release(hwfile->fd_alloc);
+
+ mutex_destroy(&hwfile->lock);
+
+ kfree(hwfile);
+
+ return 0;
+}
+
+static long hwmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret = -ENOSYS;
+ struct hwmem_file *hwfile = (struct hwmem_file *)file->private_data;
+
+ mutex_lock(&hwfile->lock);
+
+ switch (cmd) {
+ case HWMEM_ALLOC_IOC:
+ {
+ struct hwmem_alloc_request req;
+ if (copy_from_user(&req, (void __user *)arg,
+ sizeof(struct hwmem_alloc_request)))
+ ret = -EFAULT;
+ else
+ ret = alloc(hwfile, &req);
+ }
+ break;
+ case HWMEM_ALLOC_FD_IOC:
+ {
+ struct hwmem_alloc_request req;
+ if (copy_from_user(&req, (void __user *)arg,
+ sizeof(struct hwmem_alloc_request)))
+ ret = -EFAULT;
+ else
+ ret = alloc_fd(hwfile, &req);
+ }
+ break;
+ case HWMEM_RELEASE_IOC:
+ ret = release(hwfile, (s32)arg);
+ break;
+ case HWMEM_SET_DOMAIN_IOC:
+ {
+ struct hwmem_set_domain_request req;
+ if (copy_from_user(&req, (void __user *)arg,
+ sizeof(struct hwmem_set_domain_request)))
+ ret = -EFAULT;
+ else
+ ret = hwmem_ioctl_set_domain(hwfile, &req);
+ }
+ break;
+ case HWMEM_PIN_IOC:
+ {
+ struct hwmem_pin_request req;
+ /*
+ * TODO: Validate and copy scattered_addrs. Not a
+ * problem right now as it's never used.
+ */
+ if (copy_from_user(&req, (void __user *)arg,
+ sizeof(struct hwmem_pin_request)))
+ ret = -EFAULT;
+ else
+ ret = pin(hwfile, &req);
+ if (ret == 0 && copy_to_user((void __user *)arg, &req,
+ sizeof(struct hwmem_pin_request)))
+ ret = -EFAULT;
+ }
+ break;
+ case HWMEM_UNPIN_IOC:
+ ret = unpin(hwfile, (s32)arg);
+ break;
+ case HWMEM_SET_ACCESS_IOC:
+ {
+ struct hwmem_set_access_request req;
+ if (copy_from_user(&req, (void __user *)arg,
+ sizeof(struct hwmem_set_access_request)))
+ ret = -EFAULT;
+ else
+ ret = set_access(hwfile, &req);
+ }
+ break;
+ case HWMEM_GET_INFO_IOC:
+ {
+ struct hwmem_get_info_request req;
+ if (copy_from_user(&req, (void __user *)arg,
+ sizeof(struct hwmem_get_info_request)))
+ ret = -EFAULT;
+ else
+ ret = get_info(hwfile, &req);
+ if (ret == 0 && copy_to_user((void __user *)arg, &req,
+ sizeof(struct hwmem_get_info_request)))
+ ret = -EFAULT;
+ }
+ break;
+ case HWMEM_EXPORT_IOC:
+ ret = export(hwfile, (s32)arg);
+ break;
+ case HWMEM_IMPORT_IOC:
+ ret = import(hwfile, (s32)arg);
+ break;
+ case HWMEM_IMPORT_FD_IOC:
+ ret = import_fd(hwfile, (s32)arg);
+ break;
+ }
+
+ mutex_unlock(&hwfile->lock);
+
+ return ret;
+}
+
+static unsigned long hwmem_get_unmapped_area(struct file *file,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ /*
+ * pgoff will not be valid as it contains a buffer id (right shifted
+ * PAGE_SHIFT bits). To not confuse get_unmapped_area we'll not pass
+ * on file or pgoff.
+ */
+ return current->mm->get_unmapped_area(NULL, addr, len, 0, flags);
+}
+
+int __init hwmem_ioctl_init(void)
+{
+ return misc_register(&hwmem_device);
+}
+
+void __exit hwmem_ioctl_exit(void)
+{
+ misc_deregister(&hwmem_device);
+}
diff --git a/drivers/misc/hwmem/hwmem-main.c b/drivers/misc/hwmem/hwmem-main.c
new file mode 100644
index 00000000000..e6fac2fb5fd
--- /dev/null
+++ b/drivers/misc/hwmem/hwmem-main.c
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Hardware memory driver, hwmem
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/pid.h>
+#include <linux/list.h>
+#include <linux/hwmem.h>
+#include "hwmem-defs.h"
+#include "hwmem-cache.h"
+
+static struct platform_device *hwdev;
+
+u32 hwmem_start;
+u32 hwmem_size;
+void *hwmem_kaddr;
+
+static LIST_HEAD(alloc_list);
+static DEFINE_IDR(global_idr);
+static DEFINE_MUTEX(lock);
+
+static void vm_open(struct vm_area_struct *vma);
+static void vm_close(struct vm_area_struct *vma);
+static struct vm_operations_struct vm_ops = {
+ .open = vm_open,
+ .close = vm_close,
+};
+
+/* Helpers */
+
+static void destroy_hwmem_alloc_threadg_info(
+ struct hwmem_alloc_threadg_info *info)
+{
+ if (info->threadg_pid)
+ put_pid(info->threadg_pid);
+
+ kfree(info);
+}
+
+static void clean_hwmem_alloc_threadg_info_list(struct hwmem_alloc *alloc)
+{
+ struct hwmem_alloc_threadg_info *info;
+ struct hwmem_alloc_threadg_info *tmp;
+
+ list_for_each_entry_safe(info, tmp, &(alloc->threadg_info_list), list) {
+ list_del(&info->list);
+ destroy_hwmem_alloc_threadg_info(info);
+ }
+}
+
+static enum hwmem_access get_access(struct hwmem_alloc *alloc)
+{
+ struct hwmem_alloc_threadg_info *info;
+ struct pid *my_pid;
+ bool found = false;
+
+ my_pid = find_get_pid(task_tgid_nr(current));
+ if (!my_pid)
+ return 0;
+
+ list_for_each_entry(info, &(alloc->threadg_info_list), list) {
+ if (info->threadg_pid == my_pid) {
+ found = true;
+ break;
+ }
+ }
+
+ put_pid(my_pid);
+
+ if (found)
+ return info->access;
+ else
+ return alloc->default_access;
+}
+
+static void clear_alloc_mem(struct hwmem_alloc *alloc)
+{
+ u32 offset;
+ void *v_start;
+
+ offset = alloc->start - hwmem_start;
+
+ v_start = (u8 *)hwmem_kaddr + offset;
+
+ memset(v_start, 0, alloc->size);
+}
+
+static void clean_alloc(struct hwmem_alloc *alloc)
+{
+ if (alloc->name) {
+ idr_remove(&global_idr, alloc->name);
+ alloc->name = 0;
+ }
+
+ alloc->flags = 0;
+ clean_alloc_cache_info(alloc);
+
+ clean_hwmem_alloc_threadg_info_list(alloc);
+}
+
+static void destroy_alloc(struct hwmem_alloc *alloc)
+{
+ clean_alloc(alloc);
+
+ kfree(alloc);
+}
+
+static void __hwmem_release(struct hwmem_alloc *alloc)
+{
+ struct hwmem_region alloc_region;
+ struct hwmem_alloc *other;
+
+ alloc_region.skip = 0;
+ alloc_region.count = 0;
+ alloc_region.start = 0;
+ alloc_region.end = alloc->size;
+ alloc_region.size = alloc->size;
+ hwmem_sync_alloc(alloc, HWMEM_ACCESS_READ | HWMEM_ACCESS_WRITE,
+ &alloc_region, HWMEM_DOMAIN_SYNC);
+
+ clean_alloc(alloc);
+
+ other = list_entry(alloc->list.prev, struct hwmem_alloc, list);
+ if ((alloc->list.prev != &alloc_list) &&
+ atomic_read(&other->ref_cnt) == 0) {
+ other->size += alloc->size;
+ list_del(&alloc->list);
+ destroy_alloc(alloc);
+ alloc = other;
+ }
+ other = list_entry(alloc->list.next, struct hwmem_alloc, list);
+ if ((alloc->list.next != &alloc_list) &&
+ atomic_read(&other->ref_cnt) == 0) {
+ alloc->size += other->size;
+ list_del(&other->list);
+ destroy_alloc(other);
+ }
+}
+
+static struct hwmem_alloc *find_free_alloc_bestfit(u32 size)
+{
+ u32 best_diff = ~0;
+ struct hwmem_alloc *alloc = NULL, *i;
+
+ list_for_each_entry(i, &alloc_list, list) {
+ u32 diff = i->size - size;
+ if (atomic_read(&i->ref_cnt) > 0 || i->size < size)
+ continue;
+ if (diff < best_diff) {
+ alloc = i;
+ best_diff = diff;
+ }
+ }
+
+ return alloc != NULL ? alloc : ERR_PTR(-ENOMEM);
+}
+
+static struct hwmem_alloc *split_allocation(struct hwmem_alloc *alloc,
+ u32 new_alloc_size)
+{
+ struct hwmem_alloc *new_alloc;
+
+ new_alloc = kzalloc(sizeof(struct hwmem_alloc), GFP_KERNEL);
+ if (new_alloc == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ atomic_inc(&new_alloc->ref_cnt);
+ INIT_LIST_HEAD(&new_alloc->threadg_info_list);
+ new_alloc->start = alloc->start;
+ new_alloc->size = new_alloc_size;
+ clean_alloc_cache_info(new_alloc);
+ alloc->size -= new_alloc_size;
+ alloc->start += new_alloc_size;
+
+ list_add_tail(&new_alloc->list, &alloc->list);
+
+ return new_alloc;
+}
+
+static int init_alloc_list(void)
+{
+ struct hwmem_alloc *first_alloc;
+
+ first_alloc = kzalloc(sizeof(struct hwmem_alloc), GFP_KERNEL);
+ if (first_alloc == NULL)
+ return -ENOMEM;
+
+ first_alloc->start = hwmem_start;
+ first_alloc->size = hwmem_size;
+ INIT_LIST_HEAD(&first_alloc->threadg_info_list);
+ clean_alloc_cache_info(first_alloc);
+
+ list_add_tail(&first_alloc->list, &alloc_list);
+
+ return 0;
+}
+
+static void clean_alloc_list(void)
+{
+ while (list_empty(&alloc_list) == 0) {
+ struct hwmem_alloc *i = list_first_entry(&alloc_list,
+ struct hwmem_alloc, list);
+
+ list_del(&i->list);
+
+ destroy_alloc(i);
+ }
+}
+
+/* HWMEM API */
+
+struct hwmem_alloc *hwmem_alloc(u32 size, enum hwmem_alloc_flags flags,
+ enum hwmem_access def_access, enum hwmem_mem_type mem_type)
+{
+ struct hwmem_alloc *alloc;
+
+ if (!hwdev) {
+ printk(KERN_ERR "hwmem: Badly configured\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (size == 0)
+ return ERR_PTR(-EINVAL);
+
+ mutex_lock(&lock);
+
+ size = PAGE_ALIGN(size);
+
+ alloc = find_free_alloc_bestfit(size);
+ if (IS_ERR(alloc)) {
+ dev_info(&hwdev->dev, "Allocation failed, no free slot\n");
+ goto no_slot;
+ }
+
+ if (size < alloc->size) {
+ alloc = split_allocation(alloc, size);
+ if (IS_ERR(alloc))
+ goto split_alloc_failed;
+ } else {
+ atomic_inc(&alloc->ref_cnt);
+ }
+
+ clear_alloc_mem(alloc);
+
+ alloc->flags = flags;
+ alloc->default_access = def_access;
+
+ goto out;
+
+split_alloc_failed:
+no_slot:
+out:
+ mutex_unlock(&lock);
+
+ return alloc;
+}
+EXPORT_SYMBOL(hwmem_alloc);
+
+void hwmem_release(struct hwmem_alloc *alloc)
+{
+ mutex_lock(&lock);
+
+ if (atomic_dec_and_test(&alloc->ref_cnt))
+ __hwmem_release(alloc);
+
+ mutex_unlock(&lock);
+}
+EXPORT_SYMBOL(hwmem_release);
+
+int hwmem_set_domain(struct hwmem_alloc *alloc, enum hwmem_access access,
+ enum hwmem_domain domain, struct hwmem_region *region)
+{
+ mutex_lock(&lock);
+
+ switch (domain) {
+ case HWMEM_DOMAIN_SYNC:
+ hwmem_sync_alloc(alloc, access, region, HWMEM_DOMAIN_CPU);
+
+ break;
+
+ case HWMEM_DOMAIN_CPU:
+ hwmem_store_alloc_usage(alloc, access, region,
+ HWMEM_DOMAIN_CPU);
+
+ break;
+ }
+
+ mutex_unlock(&lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(hwmem_set_domain);
+
+int hwmem_pin(struct hwmem_alloc *alloc, uint32_t *phys_addr,
+ uint32_t *scattered_phys_addrs)
+{
+ mutex_lock(&lock);
+
+ *phys_addr = alloc->start;
+
+ mutex_unlock(&lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(hwmem_pin);
+
+void hwmem_unpin(struct hwmem_alloc *alloc)
+{
+}
+EXPORT_SYMBOL(hwmem_unpin);
+
+static void vm_open(struct vm_area_struct *vma)
+{
+ atomic_inc(&((struct hwmem_alloc *)vma->vm_private_data)->ref_cnt);
+}
+
+static void vm_close(struct vm_area_struct *vma)
+{
+ hwmem_release((struct hwmem_alloc *)vma->vm_private_data);
+}
+
+int hwmem_mmap(struct hwmem_alloc *alloc, struct vm_area_struct *vma)
+{
+ int ret = 0;
+ unsigned long vma_size = vma->vm_end - vma->vm_start;
+ enum hwmem_access access;
+ mutex_lock(&lock);
+
+ access = get_access(alloc);
+
+ /* Check permissions */
+ if ((!(access & HWMEM_ACCESS_WRITE) &&
+ (vma->vm_flags & VM_WRITE)) ||
+ (!(access & HWMEM_ACCESS_READ) &&
+ (vma->vm_flags & VM_READ))) {
+ ret = -EPERM;
+ goto illegal_access;
+ }
+
+ if (vma_size > (unsigned long)alloc->size) {
+ ret = -EINVAL;
+ goto illegal_size;
+ }
+
+ /*
+ * We don't want Linux to do anything (merging etc) with our VMAs as
+ * the offset is not necessarily valid
+ */
+ vma->vm_flags |= VM_SPECIAL;
+ hwmem_set_pgprot_cache_options(alloc, &vma->vm_page_prot);
+ vma->vm_private_data = (void *)alloc;
+ atomic_inc(&alloc->ref_cnt);
+ vma->vm_ops = &vm_ops;
+
+ ret = remap_pfn_range(vma, vma->vm_start, alloc->start >> PAGE_SHIFT,
+ min(vma_size, (unsigned long)alloc->size), vma->vm_page_prot);
+ if (ret < 0)
+ goto map_failed;
+
+ goto out;
+
+map_failed:
+ atomic_dec(&alloc->ref_cnt);
+illegal_size:
+illegal_access:
+
+out:
+ mutex_unlock(&lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(hwmem_mmap);
+
+int hwmem_set_access(struct hwmem_alloc *alloc,
+ enum hwmem_access access, pid_t pid_nr)
+{
+ int ret;
+ struct hwmem_alloc_threadg_info *info;
+ struct pid *pid;
+ bool found = false;
+
+ pid = find_get_pid(pid_nr);
+ if (!pid) {
+ ret = -EINVAL;
+ goto error_get_pid;
+ }
+
+ list_for_each_entry(info, &(alloc->threadg_info_list), list) {
+ if (info->threadg_pid == pid) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ ret = -ENOMEM;
+ goto error_alloc_info;
+ }
+
+ info->threadg_pid = pid;
+ info->access = access;
+
+ list_add_tail(&(info->list), &(alloc->threadg_info_list));
+ } else {
+ info->access = access;
+ }
+
+ return 0;
+
+error_alloc_info:
+ put_pid(pid);
+error_get_pid:
+ return ret;
+}
+EXPORT_SYMBOL(hwmem_set_access);
+
+void hwmem_get_info(struct hwmem_alloc *alloc, uint32_t *size,
+ enum hwmem_mem_type *mem_type, enum hwmem_access *access)
+{
+ mutex_lock(&lock);
+
+ *size = alloc->size;
+ *mem_type = HWMEM_MEM_CONTIGUOUS_SYS;
+ *access = get_access(alloc);
+
+ mutex_unlock(&lock);
+}
+EXPORT_SYMBOL(hwmem_get_info);
+
+int hwmem_get_name(struct hwmem_alloc *alloc)
+{
+ int ret = 0, name;
+
+ mutex_lock(&lock);
+
+ if (alloc->name != 0) {
+ ret = alloc->name;
+ goto out;
+ }
+
+ while (true) {
+ if (idr_pre_get(&global_idr, GFP_KERNEL) == 0) {
+ ret = -ENOMEM;
+ goto pre_get_id_failed;
+ }
+
+ ret = idr_get_new_above(&global_idr, alloc, 1, &name);
+ if (ret == 0)
+ break;
+ else if (ret != -EAGAIN)
+ goto get_id_failed;
+ }
+
+ alloc->name = name;
+
+ ret = name;
+ goto out;
+
+get_id_failed:
+pre_get_id_failed:
+
+out:
+ mutex_unlock(&lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(hwmem_get_name);
+
+struct hwmem_alloc *hwmem_resolve_by_name(s32 name)
+{
+ struct hwmem_alloc *alloc;
+
+ mutex_lock(&lock);
+
+ alloc = idr_find(&global_idr, name);
+ if (alloc == NULL) {
+ alloc = ERR_PTR(-EINVAL);
+ goto find_failed;
+ }
+ atomic_inc(&alloc->ref_cnt);
+
+ goto out;
+
+find_failed:
+
+out:
+ mutex_unlock(&lock);
+
+ return alloc;
+}
+EXPORT_SYMBOL(hwmem_resolve_by_name);
+
+/* Module */
+
+extern int hwmem_ioctl_init(void);
+extern void hwmem_ioctl_exit(void);
+
+static int __devinit hwmem_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct hwmem_platform_data *platform_data = pdev->dev.platform_data;
+
+ if (hwdev || platform_data->size == 0) {
+ dev_info(&pdev->dev, "hwdev || platform_data->size == 0\n");
+ return -EINVAL;
+ }
+
+ hwdev = pdev;
+ hwmem_start = platform_data->start;
+ hwmem_size = platform_data->size;
+
+ /*
+ * TODO: This will consume a lot of the kernel's virtual memory space
+ * and is only used when flushing the l1 cache. Investigate if a better
+ * solution exists.
+ */
+ hwmem_kaddr = ioremap(hwmem_start, hwmem_size);
+ if (hwmem_kaddr == NULL) {
+ ret = -ENOMEM;
+ goto ioremap_failed;
+ }
+
+ ret = init_alloc_list();
+ if (ret < 0)
+ goto init_alloc_list_failed;
+
+ ret = hwmem_ioctl_init();
+ if (ret)
+ goto ioctl_init_failed;
+
+ dev_info(&pdev->dev, "Hwmem probed, device contains %#x bytes\n",
+ hwmem_size);
+
+ goto out;
+
+ioctl_init_failed:
+ clean_alloc_list();
+init_alloc_list_failed:
+ iounmap(hwmem_kaddr);
+ioremap_failed:
+ hwdev = NULL;
+
+out:
+ return ret;
+}
+
+static struct platform_driver hwmem_driver = {
+ .probe = hwmem_probe,
+ .driver = {
+ .name = "hwmem",
+ },
+};
+
+static int __init hwmem_init(void)
+{
+ return platform_driver_register(&hwmem_driver);
+}
+subsys_initcall(hwmem_init);
+
+MODULE_AUTHOR("Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Hardware memory driver");
+
diff --git a/drivers/misc/i2s/Kconfig b/drivers/misc/i2s/Kconfig
new file mode 100644
index 00000000000..a2652e9eab3
--- /dev/null
+++ b/drivers/misc/i2s/Kconfig
@@ -0,0 +1,29 @@
+#
+# U8500 I2S HW kernel configuration
+#
+config STM_I2S
+ bool "U8500 I2S hardware driver"
+ depends on ARCH_U8500 && STE_DMA40
+ default y
+ ---help---
+ If you say Y here, you will enable the U8500 I2S hardware driver.
+
+ If unsure, say N.
+config STM_MSP_I2S
+ tristate "U8500 MSP_I2S hardware driver"
+ depends on ARCH_U8500 && STE_DMA40 && STM_I2S
+ default y
+ ---help---
+ If you say Y here, you will enable the U8500 MSP_I2S hardware driver.
+
+ If unsure, say N.
+
+config STM_I2S_TEST_PROTOCOL_DRIVER
+ tristate "U8500 I2S test protocol driver"
+ depends on STM_I2S && STE_DMA40 && STM_MSP_I2S
+ default n
+ ---help---
+ If you say Y here, you will enable the test protocol driver used for testing I2S Rx and Tx controllers
+
+ If unsure, say N.
+
diff --git a/drivers/misc/i2s/Makefile b/drivers/misc/i2s/Makefile
new file mode 100644
index 00000000000..41e9ecd46e7
--- /dev/null
+++ b/drivers/misc/i2s/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for I2S drivers
+#
+
+nmdk_i2s-objs := i2s.o
+obj-$(CONFIG_STM_I2S) += nmdk_i2s.o
+obj-$(CONFIG_STM_MSP_I2S) += msp_i2s.o
+obj-$(CONFIG_STM_I2S_TEST_PROTOCOL_DRIVER) += i2s_test_protocol_driver.o
diff --git a/drivers/misc/i2s/i2s.c b/drivers/misc/i2s/i2s.c
new file mode 100644
index 00000000000..e79c2ec937f
--- /dev/null
+++ b/drivers/misc/i2s/i2s.c
@@ -0,0 +1,564 @@
+/*----------------------------------------------------------------------------*/
+/* copyright STMicroelectronics, 2007. */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the Free */
+/* Software Foundation; either version 2.1 of the License, or (at your option)*/
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY */
+/* or FITNESS */
+/* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more */
+/* details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*----------------------------------------------------------------------------*/
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/cache.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/i2s/i2s.h>
+#include <linux/platform_device.h>
+
+/*******************************************************************************/
+static DEFINE_MUTEX(core_lock);
+
+static void i2sdev_release(struct device *dev)
+{
+ struct i2s_device *i2s = to_i2s_device(dev);
+
+ if (i2s->controller)
+ put_device(&(i2s->controller->dev));
+ kfree(dev);
+}
+static ssize_t
+modalias_show(struct device *dev, struct device_attribute *a, char *buf)
+{
+ const struct i2s_device *i2s = to_i2s_device(dev);
+ return sprintf(buf, "%s\n", i2s->modalias);
+}
+
+static struct device_attribute i2s_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
+/* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
+ * and the sysfs version makes coldplug work too.
+ */
+static const struct i2s_device_id *i2s_match_id(const struct i2s_device_id *id,
+ const struct i2s_device *device)
+{
+ while (id->name[0]) {
+ if (strcmp(device->modalias, id->name) == 0)
+ return id;
+ id++;
+ }
+ return NULL;
+}
+
+static int i2s_match_device(struct device *dev, struct device_driver *drv)
+{
+ const struct i2s_device *device = to_i2s_device(dev);
+ struct i2s_driver *driver = to_i2s_driver(drv);
+ if (driver->id_table)
+ return i2s_match_id(driver->id_table, device) != NULL;
+ return 0;
+}
+
+static int i2s_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ const struct i2s_device *i2s = to_i2s_device(dev);
+
+ add_uevent_var(env, "MODALIAS=%s", i2s->modalias);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2s_suspend(struct device *dev, pm_message_t message)
+{
+ int value = 0;
+ struct i2s_driver *drv = to_i2s_driver(dev->driver);
+
+ /* suspend will stop irqs and dma; no more i/o */
+ if (drv) {
+ if (drv->suspend)
+ value = drv->suspend(to_i2s_device(dev), message);
+ else
+ dev_dbg(dev, "... can't suspend\n");
+ }
+ return value;
+}
+
+static int i2s_resume(struct device *dev)
+{
+ int value = 0;
+ struct i2s_driver *drv = to_i2s_driver(dev->driver);
+
+ /* resume may restart the i/o queue */
+ if (drv) {
+ if (drv->resume)
+ value = drv->resume(to_i2s_device(dev));
+ else
+ dev_dbg(dev, "... can't resume\n");
+ }
+ return value;
+}
+
+#else
+#define i2s_suspend NULL
+#define i2s_resume NULL
+#endif
+
+/*This bus is designed to handle various protocols supported by the MSP- ARM Primecell IP
+ * such as
+ * I2s, PCM, AC97, TDM .... (refer to the data sheet for the complete list.
+ * Current MSP driver has the above ones coded.
+ * */
+struct bus_type i2s_bus_type = {
+ .name = "i2s",
+ .dev_attrs = i2s_dev_attrs,
+ .match = i2s_match_device,
+ .uevent = i2s_uevent,
+ .suspend = i2s_suspend,
+ .resume = i2s_resume,
+};
+
+EXPORT_SYMBOL_GPL(i2s_bus_type);
+
+static int i2s_drv_probe(struct device *dev)
+{
+ const struct i2s_driver *sdrv = to_i2s_driver(dev->driver);
+
+ return sdrv->probe(to_i2s_device(dev));
+}
+
+static int i2s_drv_remove(struct device *dev)
+{
+ const struct i2s_driver *sdrv = to_i2s_driver(dev->driver);
+
+ return sdrv->remove(to_i2s_device(dev));
+}
+
+static void i2s_drv_shutdown(struct device *dev)
+{
+ const struct i2s_driver *sdrv = to_i2s_driver(dev->driver);
+
+ sdrv->shutdown(to_i2s_device(dev));
+}
+
+/**
+ * i2s_register_driver - register a I2S driver
+ * @sdrv: the driver to register
+ * Context: can sleep
+ */
+int i2s_register_driver(struct i2s_driver *sdrv)
+{
+ sdrv->driver.bus = &i2s_bus_type;
+ if (sdrv->probe)
+ sdrv->driver.probe = i2s_drv_probe;
+ if (sdrv->remove)
+ sdrv->driver.remove = i2s_drv_remove;
+ if (sdrv->shutdown)
+ sdrv->driver.shutdown = i2s_drv_shutdown;
+ return driver_register(&sdrv->driver);
+}
+
+EXPORT_SYMBOL_GPL(i2s_register_driver);
+
+/******************************************************************************/
+struct boardinfo {
+ struct list_head list;
+ unsigned n_board_info;
+ struct i2s_board_info board_info[0];
+};
+
+static LIST_HEAD(board_list);
+static DEFINE_MUTEX(board_lock);
+
+/* I2S devices should normally not be created by I2S device drivers; that
+ * would make them board-specific. Similarly with I2S master drivers.
+ * Device registration normally goes into like arch/.../mach.../board-YYY.c
+ * with other readonly (flashable) information about mainboard devices.
+ */
+struct i2s_device *i2s_alloc_device(struct device *device)
+{
+ struct i2s_device *i2s;
+ struct device *dev = device->parent;
+
+ get_device(device);
+ i2s = kzalloc(sizeof *i2s, GFP_KERNEL);
+ if (!i2s) {
+ dev_err(dev, "cannot alloc i2s_device\n");
+ return NULL;
+ }
+
+ i2s->dev.parent = dev;
+ i2s->dev.bus = &i2s_bus_type;
+ i2s->dev.release = i2sdev_release;
+ device_initialize(&i2s->dev);
+ return i2s;
+}
+
+EXPORT_SYMBOL_GPL(i2s_alloc_device);
+
+/**
+ * i2s_add_device - Add i2s_device allocated with i2s_alloc_device
+ * @i2s: i2s_device to register
+ *
+ * Companion function to i2s_alloc_device. Devices allocated with
+ * i2s_alloc_device can be added onto the i2s bus with this function.
+ *
+ * Returns 0 on success; negative errno on failure
+ */
+int i2s_add_device(struct i2s_device *i2s)
+{
+ static DEFINE_MUTEX(i2s_add_lock);
+ struct device *dev = i2s->dev.parent;
+ int status;
+
+ dev_set_name(&i2s->dev, "%s.%u", "i2s", i2s->chip_select);
+
+ mutex_lock(&i2s_add_lock);
+
+ if (bus_find_device_by_name(&i2s_bus_type, NULL, dev_name(&i2s->dev))
+ != NULL) {
+ dev_err(dev, "chipselect %d already in use\n",
+ i2s->chip_select);
+ status = -EBUSY;
+ goto done;
+ }
+
+ /* Device may be bound to an active driver when this returns */
+ status = device_add(&i2s->dev);
+ if (status < 0)
+ dev_err(dev, "can't %s %s, status %d\n",
+ "add", dev_name(&i2s->dev), status);
+ else
+ dev_dbg(dev, "registered child %s\n", dev_name(&i2s->dev));
+
+ done:
+ mutex_unlock(&i2s_add_lock);
+ return status;
+}
+
+EXPORT_SYMBOL_GPL(i2s_add_device);
+
+/**
+ * i2s_new_device - instantiate one new I2S device
+ * @i2s_cont: Controller to which device is connected
+ * @chip: Describes the I2S device
+ * Context: can sleep
+ *
+ * On typical mainboards, this is purely internal; and it's not needed
+ * after board init creates the hard-wired devices. Some development
+ * platforms may not be able to use i2s_register_board_info though, and
+ * this is exported so that driver could add devices (which it would
+ * learn about out-of-band).
+ *
+ * Returns the new device, or NULL.
+ */
+struct i2s_device *i2s_new_device(struct i2s_controller *i2s_cont,
+ struct i2s_board_info *chip)
+{
+ struct i2s_device *proxy;
+ int status;
+
+ /* NOTE: caller did any chip->bus_num checks necessary.
+ *
+ * Also, unless we change the return value convention to use
+ * error-or-pointer (not NULL-or-pointer), troubleshootability
+ * suggests syslogged diagnostics are best here (ugh).
+ */
+
+ proxy = i2s_alloc_device(&i2s_cont->dev);
+ if (!proxy)
+ return NULL;
+
+ WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
+
+ proxy->chip_select = chip->chip_select;
+ strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
+ proxy->dev.platform_data = (void *)chip->platform_data;
+ proxy->controller = i2s_cont;
+
+ status = i2s_add_device(proxy);
+ if (status < 0) {
+ kfree(proxy);
+ return NULL;
+ }
+
+ return proxy;
+}
+
+EXPORT_SYMBOL_GPL(i2s_new_device);
+
+/**
+ * i2s_register_board_info - register I2S devices for a given board
+ * @info: array of chip descriptors
+ * @n: how many descriptors are provided
+ * Context: can sleep
+ *
+ * Board-specific early init code calls this (probably during arch_initcall)
+ * with segments of the I2S device table. Any device nodes are created later,
+ * after the relevant parent I2S controller (id) is defined. We keep
+ * this table of devices forever, so that reloading a controller driver will
+ * not make Linux forget about these hard-wired devices.
+ *
+ */
+int __init
+i2s_register_board_info(struct i2s_board_info const *info, unsigned n)
+{
+ struct boardinfo *bi;
+
+ bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
+ if (!bi)
+ return -ENOMEM;
+ bi->n_board_info = n;
+ memcpy(bi->board_info, info, n * sizeof *info);
+
+ mutex_lock(&board_lock);
+ list_add_tail(&bi->list, &board_list);
+ mutex_unlock(&board_lock);
+ return 0;
+}
+
+/**
+ * scan_boardinfo - Scan, creates and registered new i2s device structure.
+ * @i2s_cont: i2s controller structure
+ * Context: process
+ *
+ * It will scan the device list that may be registered statically using
+ * register_board_info func in arch specific directory and call
+ * i2s_new_device to create and registered i2s device over i2s bus. It is
+ * called by i2s_add_controller function.
+ *
+ * Returns void.
+ */
+static void scan_boardinfo(struct i2s_controller *i2s_cont)
+{
+ struct boardinfo *bi;
+
+ mutex_lock(&board_lock);
+ list_for_each_entry(bi, &board_list, list) {
+ struct i2s_board_info *chip = bi->board_info;
+ unsigned n;
+
+ for (n = bi->n_board_info; n > 0; n--, chip++) {
+ if (chip->id != i2s_cont->id)
+ continue;
+ /* NOTE: this relies on i2s_new_device to
+ * issue diagnostics when given bogus inputs
+ */
+ (void)i2s_new_device(i2s_cont, chip);
+ }
+ }
+ mutex_unlock(&board_lock);
+}
+
+/******************************************************************************/
+/**I2S Controller inittialization*/
+static void i2s_controller_dev_release(struct device *dev)
+{
+ struct i2s_controller *i2s_cont;
+ i2s_cont = container_of(dev, struct i2s_controller, dev);
+ kfree(i2s_cont);
+}
+
+static ssize_t
+show_controller_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2s_controller *cont = to_i2s_controller(dev);
+ return sprintf(buf, "%s\n", cont->name);
+}
+
+static struct device_attribute i2s_controller_attrs[] = {
+ __ATTR(name, S_IRUGO, show_controller_name, NULL),
+ {},
+};
+
+static struct class i2s_controller_class = {
+ .owner = THIS_MODULE,
+ .name = "i2s-controller",
+ .dev_attrs = i2s_controller_attrs,
+};
+
+static int i2s_register_controller(struct i2s_controller *cont)
+{
+ int res = 0;
+ mutex_init(&cont->bus_lock);
+
+ mutex_lock(&core_lock);
+
+ /* Add the controller to the driver core.
+ * If the parent pointer is not set up,
+ * we add this controller to the host bus.
+ */
+ if (cont->dev.parent == NULL) {
+ cont->dev.parent = &platform_bus;
+ pr_debug("I2S controller driver [%s] forgot to specify "
+ "physical device\n", cont->name);
+ }
+ dev_set_name(&cont->dev, "I2Scrlr-%d", cont->id);
+ cont->dev.release = &i2s_controller_dev_release;
+ cont->dev.class = &i2s_controller_class;
+ res = device_register(&cont->dev);
+ if (res)
+ goto out_unlock;
+
+ dev_dbg(&cont->dev, "controller [%s] registered\n", cont->name);
+ scan_boardinfo(cont);
+ out_unlock:
+ mutex_unlock(&core_lock);
+ return res;
+}
+
+/**
+ * i2s_add_controller - declare i2s controller, use dynamic bus number
+ * @controller: the controller to add
+ * Context: can sleep
+ *
+ */
+int i2s_add_controller(struct i2s_controller *controller)
+{
+ return i2s_register_controller(controller);
+}
+
+EXPORT_SYMBOL(i2s_add_controller);
+
+static int __unregister(struct device *dev, void *controller_dev)
+{
+ /* note: before about 2.6.14-rc1 this would corrupt memory: */
+ if (dev != controller_dev)
+ i2s_unregister_device(to_i2s_device(dev));
+ return 0;
+}
+
+/**
+ * i2s_del_controller - unregister I2S controller
+ * @cont: the controller being unregistered
+ * Context: can sleep
+ *
+ * This unregisters an I2S controller which was previously registered
+ * by @i2s_add_controller.
+ */
+int i2s_del_controller(struct i2s_controller *cont)
+{
+ int res = 0;
+ int dummy;
+ mutex_lock(&core_lock);
+
+ dummy = device_for_each_child(cont->dev.parent, &cont->dev,
+ __unregister);
+ device_unregister(&cont->dev);
+ mutex_unlock(&core_lock);
+ return res;
+}
+
+EXPORT_SYMBOL(i2s_del_controller);
+
+/******************************************************************************/
+/*I2S interface apis*/
+
+/**
+ * i2s_transfer - Main i2s transfer function.
+ * @i2s_cont: i2s controller structure passed by client driver.
+ * @message: i2s message structure contains transceive info.
+ * Context: process or interrupt.
+ *
+ * This API is called by client i2s driver as i2s_xfer funtion. It will handle
+ * main i2s transfer over i2s bus. The controller should registered its own
+ * functions using i2s algorithm structure.
+ *
+ * Returns error(-1) in case of failure or success(0).
+ */
+int i2s_transfer(struct i2s_controller *i2s_cont, struct i2s_message *message)
+{
+ return i2s_cont->algo->cont_transfer(i2s_cont, message);
+
+}
+
+EXPORT_SYMBOL(i2s_transfer);
+
+/**
+ * i2s_cleanup - Close the current i2s connection btw controller and client.
+ * @i2s_cont: i2s controller structure
+ * @flag: It indicates the functionality that needs to be disabled.
+ * Context: process
+ *
+ * This API will disable and reset the controller's configuration. Reset the
+ * controller so that i2s client driver can reconfigure with new configuration.
+ * Controller should release all the necessary resources which was acquired
+ * during setup.
+ *
+ * Returns error(-1) in case of failure or success(0).
+ */
+int i2s_cleanup(struct i2s_controller *i2s_cont, i2s_flag flag)
+{
+ int status = 0;
+ status = i2s_cont->algo->cont_cleanup(i2s_cont, flag);
+ if (status)
+ return -1;
+ else
+ return 0;
+}
+
+EXPORT_SYMBOL(i2s_cleanup);
+
+/**
+ * i2s_setup - configures and enables the I2S controller.
+ * @i2s_cont: i2s controller sent by i2s device.
+ * @config: specifies the configuration parameters.
+ *
+ * This function configures the I2S controller with the client configuration.
+ * Controller was already registered on I2S bus by some master controller
+ * driver.
+ *
+ * Returns error(-1) in case of failure else success(0)
+ */
+int i2s_setup(struct i2s_controller *i2s_cont, void *config)
+{
+ return i2s_cont->algo->cont_setup(i2s_cont, config);
+}
+
+EXPORT_SYMBOL(i2s_setup);
+
+/******************************************************************************/
+
+static int __init i2s_init(void)
+{
+ int status;
+
+ status = bus_register(&i2s_bus_type);
+ if (status < 0)
+ goto err0;
+
+ status = class_register(&i2s_controller_class);
+ if (status < 0)
+ goto err1;
+ return 0;
+
+ err1:
+ bus_unregister(&i2s_bus_type);
+ err0:
+ return status;
+}
+
+static void __exit i2s_exit(void)
+{
+ class_unregister(&i2s_controller_class);
+ bus_unregister(&i2s_bus_type);
+}
+
+subsys_initcall(i2s_init);
+module_exit(i2s_exit);
+
+MODULE_AUTHOR("Sandeep Kaushik, <sandeep-mmc.kaushik@st.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/i2s/i2s_test_protocol_driver.c b/drivers/misc/i2s/i2s_test_protocol_driver.c
new file mode 100644
index 00000000000..747409d8722
--- /dev/null
+++ b/drivers/misc/i2s/i2s_test_protocol_driver.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009
+ * Author: Sandeep Kaushik, <sandeep-mmc.kaushik@st.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/i2s/i2s.h>
+#include <linux/i2s/i2s_test_prot.h>
+#include <mach/msp.h>
+
+int i2s_drv_offset = 1;
+
+module_param(i2s_drv_offset, int, 1);
+MODULE_PARM_DESC(i2s_drv_offset, "i2s driver to be opened)=(0/1/2/3/4/5)");
+
+#define MAX_I2S_CLIENTS 6
+
+struct i2sdrv_data {
+ spinlock_t i2s_lock;
+ struct i2s_device *i2s;
+ /* flag to show the device is closed or not */
+ bool device_closed;
+ u32 tx_status;
+ u32 rx_status;
+};
+
+static struct i2sdrv_data *i2sdrv[MAX_I2S_CLIENTS];
+
+/*API Interface */
+int i2s_testprot_drv_open(int i2s_device_num)
+{
+ if (!i2sdrv[i2s_device_num])
+ return -EINVAL;
+
+ spin_lock_irq(&i2sdrv[i2s_device_num]->i2s_lock);
+ if (!i2sdrv[i2s_device_num]->device_closed) {
+ spin_unlock_irq(&i2sdrv[i2s_device_num]->i2s_lock);
+ return -EBUSY;
+ }
+ i2sdrv[i2s_device_num]->device_closed = false;
+ spin_unlock_irq(&i2sdrv[i2s_device_num]->i2s_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(i2s_testprot_drv_open);
+
+int i2s_config_default_protocol(int i2s_device_num,
+ struct test_prot_config *config)
+{
+ return __i2s_testprot_drv_configure(i2s_device_num, config, true);
+}
+EXPORT_SYMBOL(i2s_config_default_protocol);
+
+int i2s_testprot_drv_configure(int i2s_device_num,
+ struct test_prot_config *config)
+{
+ return __i2s_testprot_drv_configure(i2s_device_num, config, false);
+}
+EXPORT_SYMBOL(i2s_testprot_drv_configure);
+
+int __i2s_testprot_drv_configure(int i2s_device_num,
+ struct test_prot_config *config, bool use_default)
+{
+ int error_status = 0;
+ struct i2s_device *i2s_dev;
+ struct msp_config msp_config = {
+ .tx_clock_sel = TX_CLK_SEL_SRG,
+ .rx_clock_sel = 0x0,
+ .tx_frame_sync_sel = TX_SYNC_SRG_AUTO,
+ .rx_frame_sync_sel = 0x0,
+ .input_clock_freq = MSP_INPUT_FREQ_48MHZ,
+ .srg_clock_sel = SRG_CLK_SEL_APB,
+ .rx_frame_sync_pol = RX_FIFO_SYNC_HI,
+ .tx_frame_sync_pol = TX_FIFO_SYNC_HI,
+ .rx_fifo_config = RX_FIFO_ENABLE,
+ .tx_fifo_config = TX_FIFO_ENABLE,
+ .spi_clk_mode = SPI_CLK_MODE_NORMAL,
+ .tx_data_enable = 0x8000,
+ .spi_burst_mode = 0,
+ .loopback_enable = 0x80,
+ };
+
+ msp_config.default_protocol_desc = use_default;
+
+ if (!i2sdrv[i2s_device_num])
+ return -EINVAL;
+
+ i2s_dev = i2sdrv[i2s_device_num]->i2s;
+
+ if (i2sdrv[i2s_device_num]->device_closed)
+ return -EINVAL;
+
+ if (!config)
+ return -EINVAL;
+
+ msp_config.handler = config->handler;
+ msp_config.tx_callback_data = config->tx_callback_data;
+ msp_config.rx_callback_data = config->rx_callback_data;
+ msp_config.frame_freq = config->frame_freq;
+ msp_config.frame_size = config->frame_size;
+ msp_config.data_size = config->data_size;
+ msp_config.direction = config->direction;
+ msp_config.protocol = config->protocol;
+ msp_config.work_mode = config->work_mode;
+
+ msp_config.def_elem_len = use_default;
+
+ msp_config.multichannel_configured = 0;
+ msp_config.protocol_desc = config->protocol_desc;
+
+ msp_config.multichannel_configured = config->multichannel_configured;
+ msp_config.multichannel_config.tx_multichannel_enable =
+ config->multichannel_config.tx_multichannel_enable;
+ /* Channel 1 to 3 */
+ msp_config.multichannel_config.tx_channel_0_enable =
+ config->multichannel_config.tx_channel_0_enable;
+ /* Channel 33 to 64 */
+ msp_config.multichannel_config.tx_channel_1_enable =
+ config->multichannel_config.tx_channel_1_enable;
+ /* Channel 65 to 96 */
+ msp_config.multichannel_config.tx_channel_2_enable =
+ config->multichannel_config.tx_channel_2_enable;
+ /* Channel 97 to 128 */
+ msp_config.multichannel_config.tx_channel_3_enable =
+ config->multichannel_config.tx_channel_3_enable;
+ msp_config.multichannel_config.rx_multichannel_enable =
+ config->multichannel_config.rx_multichannel_enable;
+ /* Channel 1 to 32 */
+ msp_config.multichannel_config.rx_channel_0_enable =
+ config->multichannel_config.rx_channel_0_enable;
+ /* Channel 33 to 64 */
+ msp_config.multichannel_config.rx_channel_1_enable =
+ config->multichannel_config.rx_channel_1_enable;
+ /* Channel 65 to 96 */
+ msp_config.multichannel_config.rx_channel_2_enable =
+ config->multichannel_config.rx_channel_2_enable;
+ /* Channel 97 to 128 */
+ msp_config.multichannel_config.rx_channel_3_enable =
+ config->multichannel_config.rx_channel_3_enable;
+ msp_config.multichannel_config.rx_comparison_enable_mode =
+ config->multichannel_config.rx_comparison_enable_mode;
+ msp_config.multichannel_config.comparison_value =
+ config->multichannel_config.comparison_value;
+ msp_config.multichannel_config.comparison_mask =
+ config->multichannel_config.comparison_mask;
+
+ error_status =
+ i2s_setup(i2s_dev->controller, &msp_config);
+ if (error_status < 0)
+ dev_err(&i2s_dev->dev, "error in msp enable, error_status is %d\n",
+ error_status);
+
+ return error_status;
+
+}
+
+int i2s_testprot_drv_transfer(int i2s_device_num,
+ void *txdata, size_t txbytes, void *rxdata, size_t rxbytes)
+{
+ int bytes_transreceive;
+ struct i2s_device *i2s_dev;
+ struct i2s_message message = {};
+
+ if (!i2sdrv[i2s_device_num])
+ return -EINVAL;
+
+ i2s_dev = i2sdrv[i2s_device_num]->i2s;
+
+ if (i2sdrv[i2s_device_num]->device_closed) {
+ dev_info(&i2s_dev->dev, "msp device not opened yet\n");
+ return -EINVAL;
+ }
+
+ message.txbytes = txbytes;
+ message.txdata = txdata;
+ message.rxbytes = rxbytes;
+ message.rxdata = rxdata;
+ message.dma_flag = 1;
+
+ bytes_transreceive = i2s_transfer(i2s_dev->controller, &message);
+ if (bytes_transreceive < 0) {
+ dev_info(&i2s_dev->dev, "bytes transferred %d\n",
+ bytes_transreceive);
+ return bytes_transreceive;
+ }
+
+ return bytes_transreceive;
+}
+EXPORT_SYMBOL(i2s_testprot_drv_transfer);
+
+int i2s_testprot_drv_inf_loopback(int i2s_device_num, void *txdata,
+ size_t txbytes, void *rxdata, size_t rxbytes)
+{
+ int bytes_transreceive;
+ struct i2s_device *i2s_dev;
+ struct i2s_message message = {};
+
+ if (!i2sdrv[i2s_device_num])
+ return -EINVAL;
+
+ i2s_dev = i2sdrv[i2s_device_num]->i2s;
+
+ if (i2sdrv[i2s_device_num]->device_closed) {
+ dev_info(&i2s_dev->dev, "msp device is not opened yet\n");
+ return -EINVAL;
+ }
+
+ message.txbytes = txbytes;
+ message.txdata = txdata;
+ message.rxbytes = rxbytes;
+ message.rxdata = rxdata;
+ message.dma_flag = 1;
+ message.inf_loopback_xfer = true;
+
+ bytes_transreceive = i2s_transfer(i2s_dev->controller, &message);
+ if (bytes_transreceive < 0) {
+ dev_info(&i2s_dev->dev, "bytes transferred %d\n",
+ bytes_transreceive);
+ return bytes_transreceive;
+ }
+
+ return bytes_transreceive;
+}
+EXPORT_SYMBOL(i2s_testprot_drv_inf_loopback);
+
+int i2s_testprot_drv_close(int i2s_device_num)
+{
+ int status;
+ struct i2s_device *i2s_dev;
+
+ if (!i2sdrv[i2s_device_num])
+ return -EINVAL;
+
+ i2s_dev = i2sdrv[i2s_device_num]->i2s;
+
+ if (i2sdrv[i2s_device_num]->device_closed)
+ return -EINVAL;
+
+ status = i2s_cleanup(i2s_dev->controller, DISABLE_ALL);
+ if (status)
+ return status;
+
+ /* Mark the device as closed */
+ i2sdrv[i2s_device_num]->device_closed = true;
+
+ return 0;
+}
+EXPORT_SYMBOL(i2s_testprot_drv_close);
+
+static int i2sdrv_probe(struct i2s_device *i2s)
+{
+ int status = 0;
+
+ /* Allocate driver data */
+ if (!try_module_get(i2s->controller->dev.parent->driver->owner))
+ return -ENOENT;
+
+ i2sdrv[i2s->chip_select] = kzalloc(sizeof(*i2sdrv[i2s->chip_select]),
+ GFP_KERNEL);
+
+ if (!i2sdrv[i2s->chip_select])
+ return -ENOMEM;
+
+ /* Initialize the driver data */
+ i2sdrv[i2s->chip_select]->i2s = i2s;
+ i2sdrv[i2s->chip_select]->device_closed = true;
+ i2sdrv[i2s->chip_select]->tx_status = 0;
+ i2sdrv[i2s->chip_select]->rx_status = 0;
+ spin_lock_init(&i2sdrv[i2s->chip_select]->i2s_lock);
+
+ i2s_set_drvdata(i2s, (void *)i2sdrv[i2s->chip_select]);
+ return status;
+}
+
+static int i2sdrv_remove(struct i2s_device *i2s)
+{
+ spin_lock_irq(&i2sdrv[i2s->chip_select]->i2s_lock);
+ i2sdrv[i2s->chip_select]->i2s = NULL;
+ i2s_set_drvdata(i2s, NULL);
+ module_put(i2s->controller->dev.parent->driver->owner);
+ spin_unlock_irq(&i2sdrv[i2s->chip_select]->i2s_lock);
+
+ kfree(i2sdrv[i2s->chip_select]);
+
+ return 0;
+}
+
+static const struct i2s_device_id i2s_test_prot_id_table[] = {
+ { "i2s_device.0", 0, 0 },
+ { "i2s_device.1", 0, 0 },
+ { "i2s_device.2", 0, 0 },
+ { "i2s_device.3", 0, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2s, i2s_test_prot_id_table);
+
+static struct i2s_driver i2sdrv_i2s = {
+ .driver = {
+ .name = "i2s_test_protocol_driver",
+ .owner = THIS_MODULE,
+ },
+ .probe = i2sdrv_probe,
+ .remove = __devexit_p(i2sdrv_remove),
+ .id_table = i2s_test_prot_id_table,
+
+ /*
+ * NOTE: suspend/resume methods are not necessary here.
+ */
+};
+
+static int __init i2sdrv_init(void)
+{
+ int status;
+
+ status = i2s_register_driver(&i2sdrv_i2s);
+ if (status < 0)
+ printk(KERN_ERR "Unable to register i2s driver\n");
+
+ return status;
+}
+module_init(i2sdrv_init);
+
+static void __exit i2sdrv_exit(void)
+{
+ i2s_unregister_driver(&i2sdrv_i2s);
+}
+module_exit(i2sdrv_exit);
+
+MODULE_AUTHOR("Sandeep Kaushik, <sandeep-mmc.kaushik@st.com>");
+MODULE_DESCRIPTION("Test Driver module I2S device interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/i2s/msp_i2s.c b/drivers/misc/i2s/msp_i2s.c
new file mode 100644
index 00000000000..484120b5b7f
--- /dev/null
+++ b/drivers/misc/i2s/msp_i2s.c
@@ -0,0 +1,1952 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms:
+ *
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/pfn.h>
+
+#include <linux/regulator/consumer.h>
+#include <mach/hardware.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <linux/dmaengine.h>
+
+#include <mach/hardware.h>
+#include <mach/debug.h>
+#include <mach/irqs.h>
+#include <linux/gpio.h>
+#include <linux/i2s/i2s.h>
+#include <mach/msp.h>
+#include <linux/dma-mapping.h>
+
+#ifdef CONFIG_REGULATOR
+struct regulator *msp_vape_supply;
+#endif
+
+#define STM_MSP_NAME "STM_MSP"
+#define MSP_NAME "msp"
+#define DRIVER_DEBUG_PFX "MSP"
+#define DRIVER_DEBUG CONFIG_STM_MSP_DEBUG
+#define DRIVER_DBG "MSP"
+#define NMDK_DBG /* message level */
+
+
+extern struct driver_debug_st DBG_ST;
+ /* Protocol desciptors */
+static const struct msp_protocol_desc protocol_desc_tab[] = {
+ I2S_PROTOCOL_DESC,
+ PCM_PROTOCOL_DESC,
+ PCM_COMPAND_PROTOCOL_DESC,
+ AC97_PROTOCOL_DESC,
+ SPI_MASTER_PROTOCOL_DESC,
+ SPI_SLAVE_PROTOCOL_DESC,
+};
+
+/* Local static functions */
+static int msp_dma_xfer(struct msp *msp, struct i2s_message *msg);
+static int msp_polling_xfer(struct msp *msp, struct i2s_message *msg);
+static int msp_interrupt_xfer(struct msp *msp, struct i2s_message *msg);
+static int msp_start_dma(struct msp *msp, int transmit, dma_addr_t data,
+ size_t bytes);
+static int configure_protocol(struct msp *msp,
+ struct msp_config *config);
+static int configure_clock(struct msp *msp,
+ struct msp_config *config);
+static int configure_multichannel(struct msp *msp,
+ struct msp_config *config);
+static int stm_msp_configure_enable(struct i2s_controller *i2s_cont,
+ void *configuration);
+static int stm_msp_transceive_data(struct i2s_controller *i2s_cont,
+ struct i2s_message *message);
+
+static int stm_msp_disable(struct msp *msp, int direction,
+ i2s_flag flag);
+static int stm_msp_close(struct i2s_controller *i2s_cont, i2s_flag flag);
+
+#define I2S_DEVICE "i2s_device"
+static struct i2s_algorithm i2s_algo = {
+ .cont_setup = stm_msp_configure_enable,
+ .cont_transfer = stm_msp_transceive_data,
+ .cont_cleanup = stm_msp_close,
+};
+
+/**
+ * stm_msp_write - writel a value to specified register
+ * @value: value
+ * @reg: pointer to register' address
+ * Context: atomic(can be both process and interrupt)
+ * Returns void.
+ */
+static inline void stm_msp_write(u32 value, void __iomem *reg)
+{
+ writel(value, reg);
+}
+
+/**
+ * stm_msp_read - readl a value to specified register
+ * @reg: pointer to register' address
+ * Context: atomic(can be both process and interrupt)
+ * Returns u32 register's value.
+ */
+static inline u32 stm_msp_read(void __iomem *reg)
+{
+ return readl(reg);
+}
+
+static void u8_msp_read(struct trans_data *xfer_data)
+{
+ struct i2s_message *message = &xfer_data->message;
+ while ((message->rx_offset < message->rxbytes) &&
+ !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) &
+ RX_FIFO_EMPTY)) {
+ message->rx_offset += 1;
+ *(u8 *) message->rxdata =
+ (u8) stm_msp_read(xfer_data->msp->registers + MSP_DR);
+ message->rxdata += 1;
+ }
+}
+
+static void u16_msp_read(struct trans_data *xfer_data)
+{
+ struct i2s_message *message = &xfer_data->message;
+ while ((message->rx_offset < message->rxbytes) &&
+ !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) &
+ RX_FIFO_EMPTY)) {
+ message->rx_offset += 2;
+ *(u16 *) message->rxdata =
+ (u16) stm_msp_read(xfer_data->msp->registers + MSP_DR);
+ message->rxdata += 2;
+ }
+}
+
+/**
+ * u32_msp_read - Msp 32bit read function.
+ * @xfer_data: transfer data structure.
+ *
+ * It reads 32bit data from msp receive fifo until it gets empty.
+ *
+ * Returns void.
+ */
+static void u32_msp_read(struct trans_data *xfer_data)
+{
+ struct i2s_message *message = &xfer_data->message;
+ while ((message->rx_offset < message->rxbytes) &&
+ !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) &
+ RX_FIFO_EMPTY)) {
+ *(u32 *) message->rxdata =
+ (u32) stm_msp_read(xfer_data->msp->registers + MSP_DR);
+ message->rx_offset += 4;
+ message->rxdata += 4;
+ }
+}
+static void u8_msp_write(struct trans_data *xfer_data)
+{
+ struct i2s_message *message = &xfer_data->message;
+ while ((message->tx_offset < message->txbytes) &&
+ !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) &
+ TX_FIFO_FULL)) {
+ message->tx_offset += 1;
+ stm_msp_write(*(u8 *) message->txdata,
+ xfer_data->msp->registers + MSP_DR);
+ message->txdata += 1;
+ }
+}
+
+static void u16_msp_write(struct trans_data *xfer_data)
+{
+ struct i2s_message *message = &xfer_data->message;
+ while ((message->tx_offset < message->txbytes) &&
+ !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) &
+ TX_FIFO_FULL)) {
+ message->tx_offset += 2;
+ stm_msp_write(*(u16 *) message->txdata,
+ xfer_data->msp->registers + MSP_DR);
+ message->txdata += 2;
+ }
+}
+
+/**
+ * u32_msp_write - Msp 32bit write function.
+ * @xfer_data: transfer data structure.
+ *
+ * It writes 32bit data to msp transmit fifo until it gets full.
+ *
+ * Returns void.
+ */
+static void u32_msp_write(struct trans_data *xfer_data)
+{
+ struct i2s_message *message = &xfer_data->message;
+ while ((message->tx_offset < message->txbytes) &&
+ !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) &
+ TX_FIFO_FULL)) {
+ message->tx_offset += 4;
+ stm_msp_write(*(u32 *) message->txdata,
+ xfer_data->msp->registers + MSP_DR);
+ message->txdata += 4;
+ }
+}
+
+/**
+ * set_transmit_protocol_descriptor - Set the Transmit Configuration register.
+ * @msp: main msp controller structure.
+ * @protocol_desc: pointer to protocol descriptor structure.
+ * @data_size: Run time configurable element length.
+ *
+ * It will setup transmit configuration register of msp.
+ * Various values related to a particular protocol can be set like, elemnet
+ * length, frame length, endianess etc.
+ *
+ * Returns void.
+ */
+static void set_transmit_protocol_descriptor(struct msp *msp,
+ struct msp_protocol_desc
+ *protocol_desc,
+ enum msp_data_size data_size)
+{
+ u32 temp_reg = 0;
+
+ temp_reg |= MSP_P2_ENABLE_BIT(protocol_desc->tx_phase_mode);
+ temp_reg |= MSP_P2_START_MODE_BIT(protocol_desc->tx_phase2_start_mode);
+ temp_reg |= MSP_P1_FRAME_LEN_BITS(protocol_desc->tx_frame_length_1);
+ temp_reg |= MSP_P2_FRAME_LEN_BITS(protocol_desc->tx_frame_length_2);
+ if (msp->def_elem_len) {
+ temp_reg |=
+ MSP_P1_ELEM_LEN_BITS(protocol_desc->tx_element_length_1);
+ temp_reg |=
+ MSP_P2_ELEM_LEN_BITS(protocol_desc->tx_element_length_2);
+ if (protocol_desc->tx_element_length_1 ==
+ protocol_desc->tx_element_length_2) {
+ msp->actual_data_size =
+ protocol_desc->tx_element_length_1;
+ } else {
+ msp->actual_data_size = data_size;
+ }
+ } else {
+ temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
+ temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
+ msp->actual_data_size = data_size;
+ }
+ temp_reg |= MSP_DATA_DELAY_BITS(protocol_desc->tx_data_delay);
+ temp_reg |=
+ MSP_SET_ENDIANNES_BIT(protocol_desc->tx_bit_transfer_format);
+ temp_reg |= MSP_FRAME_SYNC_POL(protocol_desc->tx_frame_sync_pol);
+ temp_reg |= MSP_DATA_WORD_SWAP(protocol_desc->tx_half_word_swap);
+ temp_reg |= MSP_SET_COMPANDING_MODE(protocol_desc->compression_mode);
+ temp_reg |= MSP_SET_FRAME_SYNC_IGNORE(protocol_desc->frame_sync_ignore);
+
+ stm_msp_write(temp_reg, msp->registers + MSP_TCF);
+}
+
+/**
+ * set_receive_protocol_descriptor - Set the Receive Configuration register.
+ * @msp: main msp controller structure.
+ * @protocol_desc: pointer to protocol descriptor structure.
+ * @data_size: Run time configurable element length.
+ *
+ * It will setup receive configuration register of msp.
+ * Various values related to a particular protocol can be set like, elemnet
+ * length, frame length, endianess etc.
+ *
+ * Returns void.
+ */
+static void set_receive_protocol_descriptor(struct msp *msp,
+ struct msp_protocol_desc
+ *protocol_desc,
+ enum msp_data_size
+ data_size)
+{
+ u32 temp_reg = 0;
+
+ temp_reg |= MSP_P2_ENABLE_BIT(protocol_desc->rx_phase_mode);
+ temp_reg |= MSP_P2_START_MODE_BIT(protocol_desc->rx_phase2_start_mode);
+ temp_reg |= MSP_P1_FRAME_LEN_BITS(protocol_desc->rx_frame_length_1);
+ temp_reg |= MSP_P2_FRAME_LEN_BITS(protocol_desc->rx_frame_length_2);
+ if (msp->def_elem_len) {
+ temp_reg |=
+ MSP_P1_ELEM_LEN_BITS(protocol_desc->rx_element_length_1);
+ temp_reg |=
+ MSP_P2_ELEM_LEN_BITS(protocol_desc->rx_element_length_2);
+ if (protocol_desc->rx_element_length_1 ==
+ protocol_desc->rx_element_length_2) {
+ msp->actual_data_size =
+ protocol_desc->rx_element_length_1;
+ } else {
+ msp->actual_data_size = data_size;
+ }
+ } else {
+ temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
+ temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
+ msp->actual_data_size = data_size;
+ }
+
+ temp_reg |= MSP_DATA_DELAY_BITS(protocol_desc->rx_data_delay);
+ temp_reg |=
+ MSP_SET_ENDIANNES_BIT(protocol_desc->rx_bit_transfer_format);
+ temp_reg |= MSP_FRAME_SYNC_POL(protocol_desc->rx_frame_sync_pol);
+ temp_reg |= MSP_DATA_WORD_SWAP(protocol_desc->rx_half_word_swap);
+ temp_reg |= MSP_SET_COMPANDING_MODE(protocol_desc->expansion_mode);
+ temp_reg |= MSP_SET_FRAME_SYNC_IGNORE(protocol_desc->frame_sync_ignore);
+
+ stm_msp_write(temp_reg, msp->registers + MSP_RCF);
+
+}
+
+/**
+ * configure_protocol - Configures transmit and receive protocol.
+ * @msp: main msp controller structure.
+ * @config: configuration structure passed by client driver
+ *
+ * This will configure transmit and receive protocol decriptors.
+ *
+ * Returns error(-1) on failure else success(0).
+ */
+static int configure_protocol(struct msp *msp,
+ struct msp_config *config)
+{
+ int direction;
+ struct msp_protocol_desc *protocol_desc;
+ enum msp_data_size data_size;
+ u32 temp_reg = 0;
+
+ data_size = config->data_size;
+ msp->def_elem_len = config->def_elem_len;
+ direction = config->direction;
+ if (config->default_protocol_desc == 1) {
+ if (config->protocol >= MSP_INVALID_PROTOCOL) {
+ printk(KERN_ERR
+ "invalid protocol in configure_protocol()\n");
+ return -EINVAL;
+ }
+ protocol_desc =
+ (struct msp_protocol_desc *)&protocol_desc_tab[config->
+ protocol];
+ } else {
+ protocol_desc =
+ (struct msp_protocol_desc *)&config->protocol_desc;
+ }
+
+ if (data_size < MSP_DATA_BITS_DEFAULT
+ || data_size > MSP_DATA_BITS_32) {
+ printk(KERN_ERR
+ "invalid data size requested in configure_protocol()\n");
+ return -EINVAL;
+ }
+
+ switch (direction) {
+ case MSP_TRANSMIT_MODE:
+ set_transmit_protocol_descriptor(msp, protocol_desc, data_size);
+ break;
+ case MSP_RECEIVE_MODE:
+ set_receive_protocol_descriptor(msp, protocol_desc, data_size);
+ break;
+ case MSP_BOTH_T_R_MODE:
+ set_transmit_protocol_descriptor(msp, protocol_desc, data_size);
+ set_receive_protocol_descriptor(msp, protocol_desc, data_size);
+ break;
+ default:
+ printk(KERN_ERR "Invalid direction given\n");
+ return -EINVAL;
+ }
+ /* The below code is needed for both Rx and Tx path can't separate
+ * them.
+ */
+ temp_reg = stm_msp_read(msp->registers + MSP_GCR) & ~TX_CLK_POL_RISING;
+ temp_reg |= MSP_TX_CLKPOL_BIT(protocol_desc->tx_clock_pol);
+ stm_msp_write(temp_reg, msp->registers + MSP_GCR);
+ temp_reg = stm_msp_read(msp->registers + MSP_GCR) & ~RX_CLK_POL_RISING;
+ temp_reg |= MSP_RX_CLKPOL_BIT(protocol_desc->rx_clock_pol);
+ stm_msp_write(temp_reg, msp->registers + MSP_GCR);
+
+ return 0;
+}
+
+/**
+ * configure_clock - Set clock in sample rate generator.
+ * @msp: main msp controller structure.
+ * @config: configuration structure passed by client driver
+ *
+ * This will set the frame width and period. Also enable sample rate generator
+ *
+ * Returns error(-1) on failure else success(0).
+ */
+static int configure_clock(struct msp *msp,
+ struct msp_config *config)
+{
+
+ u32 dummy;
+ u32 frame_per = 0;
+ u32 sck_div = 0;
+ u32 frame_width = 0;
+ u32 temp_reg = 0;
+ u32 bit_clock = 0;
+ struct msp_protocol_desc *protocol_desc = NULL;
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) &
+ (~(SRG_ENABLE))), msp->registers + MSP_GCR);
+
+ if (config->default_protocol_desc) {
+ protocol_desc =
+ (struct msp_protocol_desc *)&protocol_desc_tab[config->
+ protocol];
+ } else {
+ protocol_desc =
+ (struct msp_protocol_desc *)&config->protocol_desc;
+ }
+
+ switch (config->protocol) {
+ case MSP_PCM_PROTOCOL:
+ case MSP_PCM_COMPAND_PROTOCOL:
+ frame_width = protocol_desc->frame_width;
+ sck_div =
+ config->input_clock_freq / (config->frame_freq *
+ (protocol_desc->
+ total_clocks_for_one_frame));
+ frame_per = protocol_desc->frame_period;
+ break;
+ case MSP_I2S_PROTOCOL:
+ frame_width = protocol_desc->frame_width;
+ sck_div =
+ config->input_clock_freq / (config->frame_freq *
+ (protocol_desc->
+ total_clocks_for_one_frame));
+ frame_per = protocol_desc->frame_period;
+
+ break;
+ case MSP_AC97_PROTOCOL:
+/* Not supported */
+ printk(KERN_WARNING "AC97 protocol not supported\n");
+ return -ENOSYS;
+ default:
+ printk(KERN_ERR "Invalid mode attempted for setting clocks\n");
+ return -EINVAL;
+ }
+
+ temp_reg = (sck_div - 1) & SCK_DIV_MASK;
+ temp_reg |= FRAME_WIDTH_BITS(frame_width);
+ temp_reg |= FRAME_PERIOD_BITS(frame_per);
+ stm_msp_write(temp_reg, msp->registers + MSP_SRG);
+
+#ifdef CONFIG_REGULATOR
+ /* Input clock frequency value configured is in MHz/1000 */
+ bit_clock = (config->input_clock_freq * 1000)/(sck_div + 1);
+
+ /* If the bit clock is higher than 19.2MHz, Vape should be run in 100% OPP */
+ if (bit_clock > 19200000) {
+ regulator_set_optimum_mode(msp_vape_supply, 1);
+ msp->vape_opp_constraint = 1;
+ } else {
+ regulator_set_optimum_mode(msp_vape_supply, 0);
+ msp->vape_opp_constraint = 0;
+ }
+#endif
+
+/* Wait a bit */
+ dummy =
+ ((stm_msp_read(msp->registers + MSP_SRG)) >> FRWID_SHIFT) &
+ 0x0000003F;
+
+/* Enable clock */
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | ((SRG_ENABLE))),
+ msp->registers + MSP_GCR);
+
+/* Another wait */
+ dummy =
+ ((stm_msp_read(msp->registers + MSP_SRG)) >> FRWID_SHIFT) &
+ 0x0000003F;
+ return 0;
+}
+
+/**
+ * configure_multichannel - Enable multichannel support for transmit & receive.
+ * @msp: main msp controller structure.
+ * @config: configuration structure passed by client driver
+ *
+ * This will enable multichannel support for transmit and receive.
+ * It will set Receive comparator also if configured.
+ *
+ * Returns error(-1) on failure else success(0).
+ */
+static int configure_multichannel(struct msp *msp,
+ struct msp_config *config)
+{
+ struct msp_protocol_desc *protocol_desc;
+ struct msp_multichannel_config *mult_config;
+ if (config->default_protocol_desc == 1) {
+ if (config->protocol >= MSP_INVALID_PROTOCOL) {
+ printk(KERN_ERR
+ "invalid protocol in configure_protocol()\n");
+ return -EINVAL;
+ }
+ protocol_desc =
+ (struct msp_protocol_desc *)&protocol_desc_tab[config->
+ protocol];
+ } else {
+ protocol_desc =
+ (struct msp_protocol_desc *)&config->protocol_desc;
+ }
+ mult_config = &config->multichannel_config;
+ if (true == mult_config->tx_multichannel_enable) {
+ if (MSP_SINGLE_PHASE == protocol_desc->tx_phase_mode) {
+ stm_msp_write((stm_msp_read(msp->registers + MSP_MCR) |
+ ((mult_config->
+ tx_multichannel_enable << TMCEN_BIT) &
+ (0x0000020))),
+ msp->registers + MSP_MCR);
+ stm_msp_write(mult_config->tx_channel_0_enable,
+ msp->registers + MSP_TCE0);
+ stm_msp_write(mult_config->tx_channel_1_enable,
+ msp->registers + MSP_TCE1);
+ stm_msp_write(mult_config->tx_channel_2_enable,
+ msp->registers + MSP_TCE2);
+ stm_msp_write(mult_config->tx_channel_3_enable,
+ msp->registers + MSP_TCE3);
+ } else {
+ printk(KERN_ERR "Not in authorised mode\n");
+ return -1;
+ }
+ }
+ if (true == mult_config->rx_multichannel_enable) {
+ if (MSP_SINGLE_PHASE == protocol_desc->rx_phase_mode) {
+ stm_msp_write((stm_msp_read(msp->registers + MSP_MCR) |
+ ((mult_config->
+ rx_multichannel_enable << RMCEN_BIT) &
+ (0x0000001))),
+ msp->registers + MSP_MCR);
+ stm_msp_write(mult_config->rx_channel_0_enable,
+ msp->registers + MSP_RCE0);
+ stm_msp_write(mult_config->rx_channel_1_enable,
+ msp->registers + MSP_RCE1);
+ stm_msp_write(mult_config->rx_channel_2_enable,
+ msp->registers + MSP_RCE2);
+ stm_msp_write(mult_config->rx_channel_3_enable,
+ msp->registers + MSP_RCE3);
+ } else {
+ printk(KERN_ERR "Not in authorised mode\n");
+ return -1;
+ }
+ if (mult_config->rx_comparison_enable_mode) {
+ stm_msp_write((stm_msp_read(msp->registers + MSP_MCR) |
+ ((mult_config->
+ rx_comparison_enable_mode << RCMPM_BIT)
+ & (0x0000018))),
+ msp->registers + MSP_MCR);
+
+ stm_msp_write(mult_config->comparison_mask,
+ msp->registers + MSP_RCM);
+ stm_msp_write(mult_config->comparison_value,
+ msp->registers + MSP_RCV);
+
+ }
+ }
+ return 0;
+
+}
+
+/**
+ * configure_dma - configure dma channel for transmit or receive.
+ * @msp: msp structure
+ * @config: configuration structure.
+ * Context: process
+ *
+ * It will configure dma channels and request them in Logical mode for both
+ * transmit and recevie modes.It also register the respective callback handlers
+ * for DMA.
+ *
+ * Returns void.
+ */
+void configure_dma(struct msp *msp, struct msp_config *config)
+{
+ struct stedma40_chan_cfg *rx_dma_info = msp->dma_cfg_rx;
+ struct stedma40_chan_cfg *tx_dma_info = msp->dma_cfg_tx;
+ dma_cap_mask_t mask;
+
+ if (config->direction == MSP_TRANSMIT_MODE
+ || config->direction == MSP_BOTH_T_R_MODE) {
+
+ if (msp->tx_pipeid != NULL) {
+ dma_release_channel(msp->tx_pipeid);
+ msp->tx_pipeid = NULL;
+ }
+
+ if (config->data_size == MSP_DATA_BITS_32)
+ tx_dma_info->src_info.data_width = STEDMA40_WORD_WIDTH;
+ else if (config->data_size == MSP_DATA_BITS_16)
+ tx_dma_info->src_info.data_width
+ = STEDMA40_HALFWORD_WIDTH;
+ else if (config->data_size == MSP_DATA_BITS_8)
+ tx_dma_info->src_info.data_width
+ = STEDMA40_BYTE_WIDTH;
+ else
+ printk(KERN_ERR "Wrong data size\n");
+
+ if (config->data_size == MSP_DATA_BITS_32)
+ tx_dma_info->dst_info.data_width = STEDMA40_WORD_WIDTH;
+ else if (config->data_size == MSP_DATA_BITS_16)
+ tx_dma_info->dst_info.data_width
+ = STEDMA40_HALFWORD_WIDTH;
+ else if (config->data_size == MSP_DATA_BITS_8)
+ tx_dma_info->dst_info.data_width
+ = STEDMA40_BYTE_WIDTH;
+ else
+ printk(KERN_ERR "Wrong data size\n");
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ msp->tx_pipeid = dma_request_channel(mask, stedma40_filter,
+ tx_dma_info);
+ }
+ if (config->direction == MSP_RECEIVE_MODE
+ || config->direction == MSP_BOTH_T_R_MODE) {
+
+ if (msp->rx_pipeid != NULL) {
+ dma_release_channel(msp->rx_pipeid);
+ msp->rx_pipeid = NULL;
+ }
+
+ if (config->data_size == MSP_DATA_BITS_32)
+ rx_dma_info->src_info.data_width = STEDMA40_WORD_WIDTH;
+ else if (config->data_size == MSP_DATA_BITS_16)
+ rx_dma_info->src_info.data_width
+ = STEDMA40_HALFWORD_WIDTH;
+ else if (config->data_size == MSP_DATA_BITS_8)
+ rx_dma_info->src_info.data_width = STEDMA40_BYTE_WIDTH;
+ else
+ printk(KERN_ERR "Wrong data size\n");
+
+ if (config->data_size == MSP_DATA_BITS_32)
+ rx_dma_info->dst_info.data_width = STEDMA40_WORD_WIDTH;
+ else if (config->data_size == MSP_DATA_BITS_16)
+ rx_dma_info->dst_info.data_width
+ = STEDMA40_HALFWORD_WIDTH;
+ else if (config->data_size == MSP_DATA_BITS_8)
+ rx_dma_info->dst_info.data_width = STEDMA40_BYTE_WIDTH;
+ else
+ printk(KERN_ERR "Wrong data size\n");
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ msp->rx_pipeid = dma_request_channel(mask, stedma40_filter,
+ rx_dma_info);
+ }
+
+}
+
+/**
+ * msp_enable - Setup the msp configuration.
+ * @msp: msp data contains main msp structure.
+ * @config: configuration structure sent by i2s client driver.
+ * Context: process
+ *
+ * Main msp configuring functions to configure msp in accordance with msp
+ * protocol descriptor, configuring msp clock,setup transfer mode selected by
+ * user like DMA, interrupt or polling and in the end enable RX and Tx path.
+ *
+ * Returns error(-1) in case of failure or success(0).
+ */
+static int msp_enable(struct msp *msp, struct msp_config *config)
+{
+ int status = 0;
+ int state;
+
+ /* Check msp state whether in RUN or CONFIGURED Mode */
+ state = msp->msp_state;
+ if (state == MSP_STATE_IDLE) {
+ if (msp->plat_init) {
+ status = msp->plat_init(msp->gpio_alt_func);
+ if (status) {
+ printk(KERN_ERR
+ "Error in altfuncenable, status is %d\n",
+ status);
+ return status;
+ }
+ }
+ }
+
+ /* Configure msp with protocol dependent settings */
+ configure_protocol(msp, config);
+ configure_clock(msp, config);
+ if (config->multichannel_configured == 1) {
+ status = configure_multichannel(msp, config);
+ if (status)
+ printk(KERN_ERR "multichannel can't be configured\n");
+ }
+ msp->work_mode = config->work_mode;
+
+ if (msp->work_mode == MSP_DMA_MODE && !msp->dma_cfg_rx) {
+ switch (config->direction) {
+ case MSP_RECEIVE_MODE:
+ case MSP_BOTH_T_R_MODE:
+ dev_err(&msp->i2s_cont->dev, "RX DMA not available");
+ return -EINVAL;
+ }
+ }
+
+ if (msp->work_mode == MSP_DMA_MODE && !msp->dma_cfg_tx) {
+ switch (config->direction) {
+ case MSP_TRANSMIT_MODE:
+ case MSP_BOTH_T_R_MODE:
+ dev_err(&msp->i2s_cont->dev, "TX DMA not available");
+ return -EINVAL;
+ }
+ }
+
+ switch (config->direction) {
+ case MSP_TRANSMIT_MODE:
+ /*Currently they are ignored
+ stm_msp_write((stm_msp_read(msp->registers + MSP_IMSC) |
+ TRANSMIT_UNDERRUN_ERR_INT |
+ TRANSMIT_FRAME_SYNC_ERR_INT),
+ msp->registers + MSP_IMSC); */
+ if (config->work_mode == MSP_DMA_MODE) {
+ stm_msp_write(stm_msp_read(msp->registers + MSP_DMACR) |
+ TX_DMA_ENABLE,
+ msp->registers + MSP_DMACR);
+
+ msp->xfer_data.tx_handler = config->handler;
+ msp->xfer_data.tx_callback_data =
+ config->tx_callback_data;
+ configure_dma(msp, config);
+ }
+ if (config->work_mode == MSP_POLLING_MODE) {
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
+ (TX_ENABLE)), msp->registers + MSP_GCR);
+ }
+ if (msp->work_mode != MSP_DMA_MODE) {
+ switch (msp->actual_data_size) {
+ case MSP_DATA_BITS_8:
+ msp->write = u8_msp_write;
+ break;
+ case MSP_DATA_BITS_10:
+ case MSP_DATA_BITS_12:
+ case MSP_DATA_BITS_14:
+ case MSP_DATA_BITS_16:
+ msp->write = u16_msp_write;
+ break;
+ case MSP_DATA_BITS_20:
+ case MSP_DATA_BITS_24:
+ case MSP_DATA_BITS_32:
+ default:
+ msp->write = u32_msp_write;
+ break;
+ }
+ msp->xfer_data.tx_handler = config->handler;
+ msp->xfer_data.tx_callback_data =
+ config->tx_callback_data;
+ msp->xfer_data.rx_callback_data =
+ config->rx_callback_data;
+ msp->xfer_data.msp = msp;
+ }
+ break;
+ case MSP_RECEIVE_MODE:
+ /*Currently they are ignored
+ stm_msp_write(stm_msp_read(msp->registers + MSP_IMSC) |
+ RECEIVE_OVERRUN_ERROR_INT | RECEIVE_FRAME_SYNC_ERR_INT,
+ msp->registers + MSP_IMSC); */
+ if (config->work_mode == MSP_DMA_MODE) {
+ stm_msp_write(stm_msp_read(msp->registers + MSP_DMACR) |
+ RX_DMA_ENABLE,
+ msp->registers + MSP_DMACR);
+
+ msp->xfer_data.rx_handler = config->handler;
+ msp->xfer_data.rx_callback_data =
+ config->rx_callback_data;
+
+ configure_dma(msp, config);
+ }
+ if (config->work_mode == MSP_POLLING_MODE) {
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
+ (RX_ENABLE)), msp->registers + MSP_GCR);
+ }
+ if (msp->work_mode != MSP_DMA_MODE) {
+ switch (msp->actual_data_size) {
+ case MSP_DATA_BITS_8:
+ msp->read = u8_msp_read;
+ break;
+ case MSP_DATA_BITS_10:
+ case MSP_DATA_BITS_12:
+ case MSP_DATA_BITS_14:
+ case MSP_DATA_BITS_16:
+ msp->read = u16_msp_read;
+ break;
+ case MSP_DATA_BITS_20:
+ case MSP_DATA_BITS_24:
+ case MSP_DATA_BITS_32:
+ default:
+ msp->read = u32_msp_read;
+ break;
+ }
+ msp->xfer_data.rx_handler = config->handler;
+ msp->xfer_data.tx_callback_data =
+ config->tx_callback_data;
+ msp->xfer_data.rx_callback_data =
+ config->rx_callback_data;
+ msp->xfer_data.msp = msp;
+ }
+
+ break;
+ case MSP_BOTH_T_R_MODE:
+ /*Currently they are ignored
+ stm_msp_write(stm_msp_read(msp->registers + MSP_IMSC) |
+ RECEIVE_OVERRUN_ERROR_INT | RECEIVE_FRAME_SYNC_ERR_INT |
+ TRANSMIT_UNDERRUN_ERR_INT | TRANSMIT_FRAME_SYNC_ERR_INT ,
+ msp->registers + MSP_IMSC); */
+ if (config->work_mode == MSP_DMA_MODE) {
+ stm_msp_write(stm_msp_read(msp->registers + MSP_DMACR) |
+ RX_DMA_ENABLE | TX_DMA_ENABLE,
+ msp->registers + MSP_DMACR);
+
+ msp->xfer_data.tx_handler = config->handler;
+ msp->xfer_data.rx_handler = config->handler;
+ msp->xfer_data.tx_callback_data =
+ config->tx_callback_data;
+ msp->xfer_data.rx_callback_data =
+ config->rx_callback_data;
+
+ configure_dma(msp, config);
+ }
+ if (config->work_mode == MSP_POLLING_MODE) {
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
+ (TX_ENABLE)), msp->registers + MSP_GCR);
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
+ (RX_ENABLE)), msp->registers + MSP_GCR);
+ }
+ if (msp->work_mode != MSP_DMA_MODE) {
+ switch (msp->actual_data_size) {
+ case MSP_DATA_BITS_8:
+ msp->read = u8_msp_read;
+ msp->write = u8_msp_write;
+ break;
+ case MSP_DATA_BITS_10:
+ case MSP_DATA_BITS_12:
+ case MSP_DATA_BITS_14:
+ case MSP_DATA_BITS_16:
+ msp->read = u16_msp_read;
+ msp->write = u16_msp_write;
+ break;
+ case MSP_DATA_BITS_20:
+ case MSP_DATA_BITS_24:
+ case MSP_DATA_BITS_32:
+ default:
+ msp->read = u32_msp_read;
+ msp->write = u32_msp_write;
+ break;
+ }
+ msp->xfer_data.tx_handler = config->handler;
+ msp->xfer_data.rx_handler = config->handler;
+ msp->xfer_data.tx_callback_data =
+ config->tx_callback_data;
+ msp->xfer_data.rx_callback_data =
+ config->rx_callback_data;
+ msp->xfer_data.msp = msp;
+ }
+
+ break;
+ default:
+ printk(KERN_ERR "Invalid direction parameter\n");
+ status = -EINVAL;
+ if (msp->plat_exit)
+ msp->plat_exit(msp->gpio_alt_func);
+ return status;
+ }
+
+ switch (config->work_mode) {
+ case MSP_DMA_MODE:
+ msp->transfer = msp_dma_xfer;
+ break;
+ case MSP_POLLING_MODE:
+ msp->transfer = msp_polling_xfer;
+ break;
+ case MSP_INTERRUPT_MODE:
+ msp->transfer = msp_interrupt_xfer;
+ break;
+ default:
+ msp->transfer = NULL;
+ }
+
+ stm_msp_write(config->iodelay, msp->registers + MSP_IODLY);
+
+ /* enable frame generation logic */
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
+ (FRAME_GEN_ENABLE)), msp->registers + MSP_GCR);
+
+ return status;
+}
+
+/**
+ * flush_rx_fifo - Flush Rx fifo MSP controller.
+ * @msp: msp structure.
+ *
+ * This function flush the rx fifo of msp controller.
+ *
+ * Returns error(-1) in case of failure else success(0)
+ */
+static void flush_rx_fifo(struct msp *msp)
+{
+ u32 dummy = 0;
+ u32 limit = 32;
+ u32 cur = stm_msp_read(msp->registers + MSP_GCR);
+ stm_msp_write(cur | RX_ENABLE, msp->registers + MSP_GCR);
+ while (!(stm_msp_read(msp->registers + MSP_FLR) & RX_FIFO_EMPTY)
+ && limit--) {
+ dummy = stm_msp_read(msp->registers + MSP_DR);
+ }
+ stm_msp_write(cur, msp->registers + MSP_GCR);
+}
+
+/**
+ * flush_tx_fifo - Flush Tx fifo MSP controller.
+ * @msp: msp structure.
+ *
+ * This function flush the tx fifo using test intergration register to read data
+ * from tx fifo directly.
+ *
+ * Returns error(-1) in case of failure else success(0)
+ */
+static void flush_tx_fifo(struct msp *msp)
+{
+ u32 dummy = 0;
+ u32 limit = 32;
+ u32 cur = stm_msp_read(msp->registers + MSP_GCR);
+ stm_msp_write(cur | TX_ENABLE, msp->registers + MSP_GCR);
+ stm_msp_write(0x3, msp->registers + MSP_ITCR);
+ while (!(stm_msp_read(msp->registers + MSP_FLR) & TX_FIFO_EMPTY)
+ && limit--) {
+ dummy = stm_msp_read(msp->registers + MSP_TSTDR);
+ }
+ stm_msp_write(0x0, msp->registers + MSP_ITCR);
+ stm_msp_write(cur, msp->registers + MSP_GCR);
+}
+
+/**
+ * stm_msp_configure_enable - configures and enables the MSP controller.
+ * @i2s_cont: i2s controller sent by i2s device.
+ * @configuration: specifies the configuration parameters.
+ *
+ * This function configures the msp controller with the client configuration.
+ *
+ * Returns error(-1) in case of failure else success(0)
+ */
+static int stm_msp_configure_enable(struct i2s_controller *i2s_cont,
+ void *configuration)
+{
+ u32 old_reg;
+ u32 new_reg;
+ u32 mask;
+ struct msp_config *config =
+ (struct msp_config *)configuration;
+ struct msp *msp = (struct msp *)i2s_cont->data;
+
+ if (in_interrupt()) {
+ printk(KERN_ERR
+ "can't call configure_enable in interrupt context\n");
+ return -1;
+ }
+ /* Two simultanous configuring msp is avoidable */
+ down(&msp->lock);
+ switch (msp->users) {
+ case 0:
+ clk_enable(msp->clk);
+ msp->direction = config->direction;
+ break;
+ case 1:
+ if (msp->direction == MSP_BOTH_T_R_MODE ||
+ config->direction == msp->direction ||
+ config->direction == MSP_BOTH_T_R_MODE) {
+ dev_notice(&i2s_cont->dev, "%s: MSP in use in the "
+ "desired direction.\n", __func__);
+ up(&msp->lock);
+ return -EBUSY;
+ }
+ msp->direction = MSP_BOTH_T_R_MODE;
+ break;
+ default:
+ dev_notice(&i2s_cont->dev, "%s: MSP in use in both "
+ "directions.\n", __func__);
+ up(&msp->lock);
+ return -EBUSY;
+ }
+ msp->users++;
+ /* Locks to ensure the parameters won't changes for the current transfer
+ * going on. It may result into hang situation in case of dma.
+ */
+
+ /*down(&msp->tx_lock);
+ down(&msp->rx_lock); */
+
+ /* First do the global config register */
+ mask =
+ RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FRAME_SYNC_MASK |
+ TX_FRAME_SYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK |
+ RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK | SRG_CLK_SEL_MASK |
+ LOOPBACK_MASK | TX_EXTRA_DELAY_MASK;
+
+ new_reg =
+ (config->tx_clock_sel | config->rx_clock_sel | config->
+ rx_frame_sync_pol | config->tx_frame_sync_pol | config->
+ rx_frame_sync_sel | config->tx_frame_sync_sel | config->
+ rx_fifo_config | config->tx_fifo_config | config->
+ srg_clock_sel | config->loopback_enable | config->tx_data_enable);
+
+ old_reg = stm_msp_read(msp->registers + MSP_GCR);
+ old_reg &= ~mask;
+ new_reg |= old_reg;
+ stm_msp_write(new_reg, msp->registers + MSP_GCR);
+
+ if (msp_enable(msp, config) != 0) {
+ printk(KERN_ERR "error enabling MSP\n");
+ return -EBUSY;
+ }
+ if (config->loopback_enable & 0x80)
+ msp->loopback_enable = 1;
+ /*Sometimes FIFO doesn't gets empty hence limit is provided */
+ flush_tx_fifo(msp);
+ /*This has been added in order to fix fifo flush problem
+ When last xfer occurs some data remains in fifo. In order to
+ flush that data delay is needed */
+ msleep(10);
+ /* wait for fifo to flush */
+ flush_rx_fifo(msp);
+
+ /* RX_BUSY take a while to clear */
+ msleep(10);
+
+ msp->msp_state = MSP_STATE_CONFIGURED;
+ up(&msp->lock);
+ return 0;
+}
+
+static int msp_start_dma(struct msp *msp, int transmit, dma_addr_t data,
+ size_t bytes)
+{
+ struct dma_async_tx_descriptor *desc;
+ struct scatterlist sg;
+
+ sg_init_table(&sg, 1);
+ sg_set_page(&sg, pfn_to_page(PFN_DOWN(data)), bytes,
+ offset_in_page(data));
+ sg_dma_address(&sg) = data;
+ sg_dma_len(&sg) = bytes;
+
+ if (transmit) {
+ if (!msp->tx_pipeid)
+ return -EINVAL;
+
+ desc = msp->tx_pipeid->device->
+ device_prep_slave_sg(msp->tx_pipeid,
+ &sg, 1, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT
+ | DMA_CTRL_ACK);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->callback = msp->xfer_data.tx_handler;
+ desc->callback_param = msp->xfer_data.tx_callback_data;
+ desc->tx_submit(desc);
+ dma_async_issue_pending(msp->tx_pipeid);
+ } else {
+ if (!msp->rx_pipeid)
+ return -EINVAL;
+
+ desc = msp->rx_pipeid->device->
+ device_prep_slave_sg(msp->rx_pipeid,
+ &sg, 1, DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT
+ | DMA_CTRL_ACK);
+ if (!desc)
+ return -EBUSY;
+
+ desc->callback = msp->xfer_data.rx_handler;
+ desc->callback_param = msp->xfer_data.rx_callback_data;
+ desc->tx_submit(desc);
+ dma_async_issue_pending(msp->rx_pipeid);
+ }
+
+ return 0;
+}
+
+static void msp_loopback_inf_start_dma(struct msp *msp, dma_addr_t data,
+ size_t bytes)
+{
+ struct stedma40_cyclic_desc *rxcdesc;
+ struct stedma40_cyclic_desc *txcdesc;
+ struct scatterlist rxsg[2];
+ struct scatterlist txsg[2];
+ size_t len = bytes >> 1;
+ int ret;
+
+ sg_init_table(rxsg, ARRAY_SIZE(rxsg));
+ sg_init_table(txsg, ARRAY_SIZE(txsg));
+
+ sg_dma_len(&rxsg[0]) = len;
+ sg_dma_len(&rxsg[1]) = len;
+ sg_dma_len(&txsg[0]) = len;
+ sg_dma_len(&txsg[1]) = len;
+
+ sg_dma_address(&rxsg[0]) = data;
+ sg_dma_address(&rxsg[1]) = data + len;
+
+ sg_dma_address(&txsg[0]) = data + len;
+ sg_dma_address(&txsg[1]) = data;
+
+ rxcdesc = stedma40_cyclic_prep_sg(msp->rx_pipeid,
+ rxsg, ARRAY_SIZE(rxsg),
+ DMA_FROM_DEVICE, 0);
+ if (IS_ERR(rxcdesc))
+ return;
+
+ txcdesc = stedma40_cyclic_prep_sg(msp->tx_pipeid,
+ txsg, ARRAY_SIZE(txsg),
+ DMA_TO_DEVICE, 0);
+ if (IS_ERR(txcdesc))
+ goto free_rx;
+
+ ret = stedma40_cyclic_start(msp->rx_pipeid);
+ if (ret)
+ goto free_tx;
+
+ ret = stedma40_cyclic_start(msp->tx_pipeid);
+ if (ret)
+ goto stop_rx;
+
+ msp->infinite = true;
+
+ return;
+
+stop_rx:
+ stedma40_cyclic_stop(msp->rx_pipeid);
+free_tx:
+ stedma40_cyclic_free(msp->tx_pipeid);
+free_rx:
+ stedma40_cyclic_free(msp->rx_pipeid);
+}
+
+/**
+ * msp_dma_xfer - Handles DMA transfers over i2s bus.
+ * @msp: main msp structure.
+ * @msg: i2s_message contains info about transmit and receive data.
+ * Context: process
+ *
+ * This will first check whether data buffer is dmaable or not.
+ * Call dma_map_single apis etc to make it dmaable dma. Starts the dma transfer
+ * for TX and RX parallely and wait for it to get completed.
+ *
+ * Returns error(-1) in case of failure or success(0).
+ */
+static int msp_dma_xfer(struct msp *msp, struct i2s_message *msg)
+{
+ int status = 0;
+ struct i2s_message *message;
+ if (msg->txbytes) {
+ msp->xfer_data.message.txdata = msg->txdata;
+ msp->xfer_data.message.tx_offset = 0;
+ }
+ if (msg->rxbytes) {
+ msp->xfer_data.message.rxdata = msg->rxdata;
+ msp->xfer_data.message.rx_offset = 0;
+ }
+ msp->xfer_data.message.txbytes = msg->txbytes;
+ msp->xfer_data.message.rxbytes = msg->rxbytes;
+ msp->xfer_data.message.dma_flag = msg->dma_flag;
+ message = &msp->xfer_data.message;
+ if (msg->inf_loopback_xfer == true) {
+ /* Configure loopback dma at msp */
+ msp_loopback_inf_start_dma(msp, (dma_addr_t) message->rxdata,
+ message->rxbytes);
+ /* Enable RX and TX at msp */
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
+ (RX_ENABLE)), msp->registers + MSP_GCR);
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
+ (TX_ENABLE)), msp->registers + MSP_GCR);
+ }
+ else {
+ if (message->rxdata && (message->rxbytes > 0)) {
+ if (!message->dma_flag)
+ message->rxdata =
+ (void *)dma_map_single(NULL, message->rxdata,
+ message->rxbytes,
+ DMA_FROM_DEVICE);
+ status = msp_start_dma(msp, 0, (dma_addr_t) message->rxdata,
+ message->rxbytes);
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
+ (RX_ENABLE)), msp->registers + MSP_GCR);
+ }
+
+ if (message->txdata && (message->txbytes > 0)) {
+ if (!message->dma_flag)
+ message->txdata =
+ (void *)dma_map_single(NULL, message->txdata,
+ message->txbytes,
+ DMA_TO_DEVICE);
+ status = msp_start_dma(msp, 1, (dma_addr_t) message->txdata,
+ message->txbytes);
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
+ (TX_ENABLE)), msp->registers + MSP_GCR);
+ }
+ }
+ return status;
+}
+
+#if 0
+/**
+ * msp_handle_irq - Interrupt handler routine.
+ * @irq: irq no.
+ * @dev_id: device structure registered in request irq.
+ *
+ * Returns error(-1) on failure else success(0).
+ */
+static irqreturn_t msp_handle_irq(int irq, void *dev_id)
+{
+ u32 irq_status;
+ struct msp *msp = (struct msp *)dev_id;
+ struct i2s_message *message = &msp->xfer_data.message;
+ u32 irq_mask = 0;
+ irq_status = stm_msp_read(msp->registers + MSP_MIS);
+ irq_mask = stm_msp_read(msp->registers + MSP_IMSC);
+/* Disable the interrupt to prevent immediate recurrence */
+ stm_msp_write(stm_msp_read(msp->registers + MSP_IMSC) & ~irq_status,
+ msp->registers + MSP_IMSC);
+
+/* Clear the interrupt */
+ stm_msp_write(irq_status, msp->registers + MSP_ICR);
+/* Check for an error condition */
+ msp->msp_io_error = irq_status & (RECEIVE_OVERRUN_ERROR_INT |
+ RECEIVE_FRAME_SYNC_ERR_INT |
+ TRANSMIT_UNDERRUN_ERR_INT |
+ TRANSMIT_FRAME_SYNC_ERR_INT);
+
+ /*Currently they are ignored */
+ if (irq_status & RECEIVE_OVERRUN_ERROR_INT)
+ ;
+ if (irq_status & TRANSMIT_UNDERRUN_ERR_INT)
+ ;
+
+ /* This code has been added basically to support loopback mode
+ * Basically Transmit interrupt is not disabled even after its
+ * completion so that receive fifo gets an additional interrupt
+ */
+ if (irq_mask & (RECEIVE_SERVICE_INT)
+ && (irq_mask & (TRANSMIT_SERVICE_INT)) && (msp->loopback_enable)) {
+ if (msp->read)
+ msp->read(&msp->xfer_data);
+ if (msp->write)
+ msp->write(&msp->xfer_data);
+ if (message->rx_offset >= message->rxbytes) {
+ if (msp->xfer_data.rx_handler)
+ msp->xfer_data.rx_handler(msp->
+ xfer_data.
+ rx_callback_data,
+ message->rx_offset);
+ msp->xfer_data.rx_handler = NULL;
+ return IRQ_HANDLED;
+ }
+
+ if (message->tx_offset >= message->txbytes) {
+ if (msp->xfer_data.tx_handler)
+ msp->xfer_data.tx_handler(msp->xfer_data.
+ tx_callback_data,
+ message->tx_offset);
+ msp->xfer_data.tx_handler = NULL;
+ }
+ stm_msp_write(irq_mask, msp->registers + MSP_IMSC);
+ return IRQ_HANDLED;
+ }
+
+ if (irq_status & RECEIVE_SERVICE_INT) {
+ if (msp->read)
+ msp->read(&msp->xfer_data);
+ if (message->rx_offset >= message->rxbytes) {
+ irq_mask &= ~RECEIVE_SERVICE_INT;
+ stm_msp_write(irq_mask, msp->registers + MSP_IMSC);
+ if (msp->xfer_data.rx_handler)
+ msp->xfer_data.rx_handler(msp->
+ xfer_data.
+ rx_callback_data,
+ message->rx_offset);
+ if (!(irq_status & TRANSMIT_SERVICE_INT))
+ return IRQ_HANDLED;
+ }
+ }
+ if (irq_status & TRANSMIT_SERVICE_INT) {
+ if (msp->write)
+ msp->write(&msp->xfer_data);
+ if (message->tx_offset >= message->txbytes) {
+ irq_mask &= ~TRANSMIT_SERVICE_INT;
+ stm_msp_write(irq_mask, msp->registers + MSP_IMSC);
+ if (msp->xfer_data.tx_handler)
+ msp->xfer_data.tx_handler(msp->xfer_data.
+ tx_callback_data,
+ message->tx_offset);
+ return IRQ_HANDLED;
+ }
+ }
+ stm_msp_write(irq_mask, msp->registers + MSP_IMSC);
+ return IRQ_HANDLED;
+
+}
+#endif
+
+/**
+ * msp_interrupt_xfer - Handles Interrupt transfers over i2s bus.
+ * @msp: main msp structure.
+ * @msg: i2s_message contains info about transmit and receive data.
+ * Context: Process or interrupt.
+ *
+ * This implements transfer and receive functions used in interrupt mode.
+ * This can be used in interrupt context if a callback handler is registered
+ * by client driver. This has been to improve performance in interrupt mode.
+ * Hence can't use sleep in this function.
+ *
+ * Returns error(-1) in case of failure or success(0).
+ */
+static int msp_interrupt_xfer(struct msp *msp, struct i2s_message *msg)
+{
+ struct i2s_message *message;
+ u32 irq_mask = 0;
+ if (msg->txbytes) {
+ msp->xfer_data.message.txbytes = msg->txbytes;
+ msp->xfer_data.message.txdata = msg->txdata;
+ msp->xfer_data.message.tx_offset = 0;
+ }
+ if (msg->rxbytes) {
+ msp->xfer_data.message.rxbytes = msg->rxbytes;
+ msp->xfer_data.message.rxdata = msg->rxdata;
+ msp->xfer_data.message.rx_offset = 0;
+ }
+ message = &msp->xfer_data.message;
+ if ((message->txdata == NULL || message->txbytes == 0)
+ && (message->rxdata == NULL || message->rxbytes == 0)) {
+ printk(KERN_ERR
+ "transmit_receive_data is NULL with bytes > 0\n");
+ return -EINVAL;
+ }
+
+ msp->msp_io_error = 0;
+
+ if (message->tx_offset < message->txbytes) {
+ irq_mask |= TRANSMIT_SERVICE_INT;
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
+ (TX_ENABLE)), msp->registers + MSP_GCR);
+ }
+ if (message->rx_offset < message->rxbytes) {
+ irq_mask |= RECEIVE_SERVICE_INT;
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
+ (RX_ENABLE)), msp->registers + MSP_GCR);
+ }
+ stm_msp_write((stm_msp_read(msp->registers + MSP_IMSC) |
+ irq_mask), msp->registers + MSP_IMSC);
+ return 0;
+}
+
+/**
+ * func_notify_timer - Handles Polling hang issue over i2s bus.
+ * @data: main msp data address
+ * Context: Interrupt.
+ *
+ * This is used to handle error condition in transfer and receive function used
+ * in polling mode.
+ * Sometimes due to passing wrong protocol desc , polling transfer may hang.
+ * To prevent this, timer is added.
+ *
+ * Returns void.
+ */
+static void func_notify_timer(unsigned long data)
+{
+ struct msp *msp = (struct msp *)data;
+ if (msp->polling_flag) {
+ msp->msp_io_error = 1;
+ printk(KERN_ERR
+ "Polling is taking two much time, may be it got hang\n");
+ del_timer(&msp->notify_timer);
+ }
+}
+
+/**
+ * msp_polling_xfer - Handles Polling transfers over i2s bus.
+ * @msp: main msp structure.
+ * @msg: i2s_message contains info about transmit and receive data.
+ * Context: Process.
+ *
+ * This implements transfer and receive functions used in polling mode. This is
+ * blocking fucntion.
+ * It is recommended to use interrupt or dma mode for better performance rather
+ * than the polling mode.
+ *
+ * Returns error(-1) in case of failure or success(0).
+ */
+static int msp_polling_xfer(struct msp *msp, struct i2s_message *msg)
+{
+ struct i2s_message *message;
+ u32 time_expire = 0;
+ u32 tr_ex = 0, rr_ex = 0;
+ u32 msec_jiffies = 0;
+ if (msg->txbytes) {
+ msp->xfer_data.message.txbytes = msg->txbytes;
+ msp->xfer_data.message.txdata = msg->txdata;
+ msp->xfer_data.message.tx_offset = 0;
+ tr_ex = msg->txbytes;
+ }
+ if (msg->rxbytes) {
+ msp->xfer_data.message.rxbytes = msg->rxbytes;
+ msp->xfer_data.message.rxdata = msg->rxdata;
+ msp->xfer_data.message.rx_offset = 0;
+ rr_ex = msg->rxbytes;
+ }
+ message = &msp->xfer_data.message;
+ time_expire = (tr_ex + rr_ex) / 1024;
+ if (!time_expire)
+ msec_jiffies = 500;
+ else
+ msec_jiffies = time_expire * 500;
+ msp->notify_timer.expires = jiffies + msecs_to_jiffies(msec_jiffies);
+ down(&msp->lock);
+ if (message->txdata == NULL && message->txbytes > 0) {
+ printk(KERN_ERR
+ "transmit_receive_data is NULL with bytes > 0\n");
+ return -EINVAL;
+ }
+
+ if (message->rxdata == NULL && message->rxbytes > 0) {
+ printk(KERN_ERR
+ "transmit_receive_data is NULL with bytes > 0\n");
+ return -EINVAL;
+ }
+ msp->msp_io_error = 0;
+ msp->polling_flag = 1;
+ add_timer(&msp->notify_timer);
+ while (message->tx_offset < message->txbytes
+ || message->rx_offset < message->rxbytes) {
+ if (msp->msp_io_error)
+ break;
+ if (msp->read)
+ msp->read(&msp->xfer_data);
+ if (msp->write)
+ msp->write(&msp->xfer_data);
+ }
+ msp->polling_flag = 0;
+ del_timer(&msp->notify_timer);
+ up(&msp->lock);
+ return message->txbytes + message->rxbytes;
+}
+
+/**
+ * stm_msp_transceive_data - Main i2s transfer function.
+ * @i2s_cont: i2s controller structure passed by client driver.
+ * @message: i2s message structure contains transceive info.
+ * Context: process or interrupt.
+ *
+ * This function is registered over i2s_xfer funtions. It will handle main i2s
+ * transfer over i2s bus in various modes.It call msp transfer function on which
+ * suitable transfer function is already registered i.e dma ,interrupt or
+ * polling function.
+ *
+ * Returns error(-1) in case of failure or success(0).
+ */
+static int stm_msp_transceive_data(struct i2s_controller *i2s_cont,
+ struct i2s_message *message)
+{
+ int status = 0;
+ struct msp *msp = (struct msp *)i2s_cont->data;
+
+ if (!message || (msp->msp_state == MSP_STATE_IDLE)) {
+ printk(KERN_ERR "Message is NULL\n");
+ return -EPERM;
+ }
+
+ msp->msp_state = MSP_STATE_RUN;
+ if (msp->transfer)
+ status = msp->transfer(msp, message);
+
+ if (msp->msp_state == MSP_STATE_RUN)
+ msp->msp_state = MSP_STATE_CONFIGURED;
+
+ return status;
+}
+
+/**
+ * msp_disable_receive - Disable receive functionality.
+ * @msp: main msp structure.
+ * Context: process.
+ *
+ * This function will disable msp controller's receive functionality like dma,
+ * interrupt receive data buffer all are disabled.
+ *
+ * Returns void.
+ */
+static void msp_disable_receive(struct msp *msp)
+{
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) &
+ (~RX_ENABLE)), msp->registers + MSP_GCR);
+ stm_msp_write((stm_msp_read(msp->registers + MSP_DMACR) &
+ (~RX_DMA_ENABLE)), msp->registers + MSP_DMACR);
+ stm_msp_write((stm_msp_read(msp->registers + MSP_IMSC) &
+ (~
+ (RECEIVE_SERVICE_INT |
+ RECEIVE_OVERRUN_ERROR_INT))),
+ msp->registers + MSP_IMSC);
+ msp->xfer_data.message.rxbytes = 0;
+ msp->xfer_data.message.rx_offset = 0;
+ msp->xfer_data.message.rxdata = NULL;
+ msp->read = NULL;
+
+}
+
+/**
+ * msp_disable_transmit - Disable transmit functionality.
+ * @msp: main msp structure.
+ * Context: process.
+ *
+ * This function will disable msp controller's transmit functionality like dma,
+ * interrupt transmit data buffer all are disabled.
+ *
+ * Returns void.
+ */
+static void msp_disable_transmit(struct msp *msp)
+{
+
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) &
+ (~TX_ENABLE)), msp->registers + MSP_GCR);
+ stm_msp_write((stm_msp_read(msp->registers + MSP_DMACR) &
+ (~TX_DMA_ENABLE)), msp->registers + MSP_DMACR);
+ stm_msp_write((stm_msp_read(msp->registers + MSP_IMSC) &
+ (~
+ (TRANSMIT_SERVICE_INT |
+ TRANSMIT_UNDERRUN_ERR_INT))),
+ msp->registers + MSP_IMSC);
+ msp->xfer_data.message.txbytes = 0;
+ msp->xfer_data.message.tx_offset = 0;
+ msp->xfer_data.message.txdata = NULL;
+ msp->write = NULL;
+
+}
+
+/**
+ * stm_msp_disable - disable the given msp controller
+ * @msp: specifies the msp contoller data
+ * @direction: specifies the transmit/receive direction
+ * @flag: It indicates the functionality that needs to be disabled.
+ *
+ * Returns error(-1) in case of failure else success(0)
+ */
+static int stm_msp_disable(struct msp *msp, int direction, i2s_flag flag)
+{
+ int limit = 32;
+ u32 dummy = 0;
+ int status = 0;
+ if (!
+ (stm_msp_read(msp->registers + MSP_GCR) &
+ ((TX_ENABLE | RX_ENABLE)))) {
+ return 0;
+ }
+ if (msp->work_mode == MSP_DMA_MODE) {
+ if (flag == DISABLE_ALL || flag == DISABLE_TRANSMIT) {
+ if (msp->tx_pipeid != NULL) {
+ if (msp->infinite) {
+ stedma40_cyclic_stop(msp->tx_pipeid);
+ stedma40_cyclic_free(msp->tx_pipeid);
+ }
+ msp->tx_pipeid->device->
+ device_control(msp->tx_pipeid,
+ DMA_TERMINATE_ALL, 0);
+ dma_release_channel(msp->tx_pipeid);
+ msp->tx_pipeid = NULL;
+ }
+ }
+ if ((flag == DISABLE_ALL || flag == DISABLE_RECEIVE)) {
+ if (msp->rx_pipeid != NULL) {
+ if (msp->infinite) {
+ stedma40_cyclic_stop(msp->rx_pipeid);
+ stedma40_cyclic_free(msp->rx_pipeid);
+ }
+
+ msp->rx_pipeid->device->
+ device_control(msp->rx_pipeid,
+ DMA_TERMINATE_ALL, 0);
+ dma_release_channel(msp->rx_pipeid);
+ msp->rx_pipeid = NULL;
+ }
+ }
+
+ msp->infinite = false;
+ }
+ if (flag == DISABLE_TRANSMIT)
+ msp_disable_transmit(msp);
+ else if (flag == DISABLE_RECEIVE)
+ msp_disable_receive(msp);
+ else {
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
+ (LOOPBACK_MASK)), msp->registers + MSP_GCR);
+ /* Flush Tx fifo */
+ while ((!
+ (stm_msp_read(msp->registers + MSP_FLR) &
+ TX_FIFO_EMPTY)) && limit--)
+ dummy = stm_msp_read(msp->registers + MSP_DR);
+
+ /* Disable Transmit channel */
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) &
+ (~TX_ENABLE)), msp->registers + MSP_GCR);
+ limit = 32;
+ /* Flush Rx Fifo */
+ while ((!
+ (stm_msp_read(msp->registers + MSP_FLR) &
+ RX_FIFO_EMPTY)) && limit--)
+ dummy = stm_msp_read(msp->registers + MSP_DR);
+ /* Disable Loopback and Receive channel */
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) &
+ (~(RX_ENABLE | LOOPBACK_MASK))),
+ msp->registers + MSP_GCR);
+ /*This has been added in order to fix fifo flush problem
+ When last xfer occurs some data remains in fifo. In order to
+ flush that data delay is needed */
+ msleep(10);
+ msp_disable_transmit(msp);
+ msp_disable_receive(msp);
+
+ }
+
+ /* disable sample rate and frame generators */
+ if (flag == DISABLE_ALL) {
+ msp->msp_state = MSP_STATE_IDLE;
+ stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) &
+ (~(FRAME_GEN_ENABLE | SRG_ENABLE))),
+ msp->registers + MSP_GCR);
+ memset(&msp->xfer_data, 0, sizeof(struct trans_data));
+ if (msp->plat_exit) {
+ status = msp->plat_exit(msp->gpio_alt_func);
+ if (status)
+ printk(KERN_ERR "Error in disable\n");
+ }
+ if (msp->work_mode == MSP_POLLING_MODE
+ && msp->msp_state == MSP_STATE_RUN) {
+ up(&msp->lock);
+ }
+ msp->transfer = NULL;
+ stm_msp_write(0, msp->registers + MSP_GCR);
+ stm_msp_write(0, msp->registers + MSP_TCF);
+ stm_msp_write(0, msp->registers + MSP_RCF);
+ stm_msp_write(0, msp->registers + MSP_DMACR);
+ stm_msp_write(0, msp->registers + MSP_SRG);
+ stm_msp_write(0, msp->registers + MSP_MCR);
+ stm_msp_write(0, msp->registers + MSP_RCM);
+ stm_msp_write(0, msp->registers + MSP_RCV);
+ stm_msp_write(0, msp->registers + MSP_TCE0);
+ stm_msp_write(0, msp->registers + MSP_TCE1);
+ stm_msp_write(0, msp->registers + MSP_TCE2);
+ stm_msp_write(0, msp->registers + MSP_TCE3);
+ stm_msp_write(0, msp->registers + MSP_RCE0);
+ stm_msp_write(0, msp->registers + MSP_RCE1);
+ stm_msp_write(0, msp->registers + MSP_RCE2);
+ stm_msp_write(0, msp->registers + MSP_RCE3);
+ }
+ return status;
+}
+
+/**
+ * stm_msp_close - Close the current i2s connection btw controller and client.
+ * @i2s_cont: i2s controller structure
+ * @flag: It indicates the functionality that needs to be disabled.
+ * Context: process
+ *
+ * It will call msp_disable and reset the msp configuration. Disables Rx and Tx
+ * channels, free gpio irqs and interrupt pins.
+ * Called by i2s client driver to indicate the completion of use of i2s bus.
+ * It is registered on i2s_close function.
+ *
+ * Returns error(-1) in case of failure or success(0).
+ */
+static int stm_msp_close(struct i2s_controller *i2s_cont, i2s_flag flag)
+{
+ int status = 0;
+ struct msp *msp = (struct msp *)i2s_cont->data;
+ down(&msp->lock);
+ if(msp->users == 0) {
+ printk("Msp already closed\n");
+ status = -EINVAL;
+ goto end;
+ }
+ dev_dbg(&i2s_cont->dev, "%s: users = %d, flag = %d.\n",
+ __func__, msp->users, flag);
+ /* We need to call it twice for DISABLE_ALL*/
+ msp->users = flag == DISABLE_ALL ? 0 : msp->users - 1;
+ if (msp->users)
+ status = stm_msp_disable(msp, MSP_BOTH_T_R_MODE, flag);
+ else {
+ status = stm_msp_disable(msp, MSP_BOTH_T_R_MODE, DISABLE_ALL);
+ clk_disable(msp->clk);
+ }
+ if (status)
+ goto end;
+ if (msp->users)
+ msp->direction = flag == DISABLE_TRANSMIT ?
+ MSP_RECEIVE_MODE : MSP_TRANSMIT_MODE;
+
+#ifdef CONFIG_REGULATOR
+ if (msp->vape_opp_constraint == 1) {
+ regulator_set_optimum_mode(msp_vape_supply, 0);
+ msp->vape_opp_constraint = 0;
+ }
+#endif
+end:
+ up(&msp->lock);
+ return status;
+
+}
+
+ /*Platform driver's functions */
+/**
+ * msp_probe - Probe function
+ * @pdev: platform device structure.
+ * Context: process
+ *
+ * Probe function of msp platform driver.Handles allocation of memory and irq
+ * resource. It creates i2s_controller and one i2s_device per msp controller.
+ *
+ * Returns error(-1) in case of failure or success(0).
+ */
+int msp_probe(struct platform_device *pdev)
+{
+ int status = 0;
+ struct device *dev;
+ s16 platform_num = 0;
+ struct resource *res = NULL;
+ int irq;
+ struct i2s_controller *i2s_cont;
+/* struct i2s_device *i2s_dev;*/
+ struct msp_i2s_platform_data *platform_data;
+ struct msp *msp;
+
+ if (!pdev)
+ return -EPERM;
+ msp = kzalloc(sizeof(*msp), GFP_KERNEL);
+
+ platform_data = (struct msp_i2s_platform_data *)pdev->dev.platform_data;
+
+ msp->id = platform_data->id;
+ msp->gpio_alt_func = platform_data->gpio_alt_func;
+ msp->plat_init = platform_data->msp_i2s_init;
+ msp->plat_exit = platform_data->msp_i2s_exit;
+
+ msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
+ msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
+
+ dev = &pdev->dev;
+ platform_num = msp->id - 1;
+
+ init_MUTEX(&msp->lock);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ stm_error("probe - MEM resources not defined\n");
+ status = -EINVAL;
+ goto free_msp;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ status = -EINVAL;
+ goto free_msp;
+ }
+ msp->irq = irq;
+
+ msp->registers = ioremap(res->start, (res->end - res->start + 1));
+ if (msp->registers == NULL) {
+ status = -EINVAL;
+ goto free_msp;
+ }
+
+#if 0
+ status =
+ request_irq(msp->irq, msp_handle_irq,
+ IRQF_DISABLED | IRQF_SHARED, MSP_NAME, msp);
+ if (status)
+ goto iounmap;
+#endif
+
+#ifdef CONFIG_REGULATOR
+ msp_vape_supply = regulator_get(NULL, "v-ape");
+ if (IS_ERR(msp_vape_supply)) {
+ status = PTR_ERR(msp_vape_supply);
+ printk(KERN_WARNING "msp i2s : failed to get v-ape supply\n");
+ goto free_irq;
+ }
+#endif
+ msp->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(msp->clk)) {
+ status = PTR_ERR(msp->clk);
+ goto free_irq;
+ }
+
+ init_timer(&msp->notify_timer);
+ msp->notify_timer.expires = jiffies + msecs_to_jiffies(1000);
+ msp->notify_timer.function = func_notify_timer;
+ msp->notify_timer.data = (unsigned long)msp;
+
+ msp->rx_pipeid = NULL;
+ msp->tx_pipeid = NULL;
+ msp->read = NULL;
+ msp->write = NULL;
+ msp->transfer = NULL;
+ msp->msp_state = MSP_STATE_IDLE;
+ msp->loopback_enable = 0;
+
+ dev_set_drvdata(&pdev->dev, msp);
+ /* I2S Controller is allocated and added in
+ * I2S controller class.
+ */
+ i2s_cont =
+ (struct i2s_controller *)kzalloc(sizeof(*i2s_cont), GFP_KERNEL);
+ if (!i2s_cont) {
+ stm_error("i2s controller alloc failed \n");
+ status = -EINVAL;
+ goto del_timer;
+ }
+ i2s_cont->dev.parent = dev;
+ i2s_cont->algo = &i2s_algo;
+ i2s_cont->data = (void *)msp;
+ i2s_cont->id = platform_num;
+ snprintf(i2s_cont->name, sizeof(i2s_cont->name),
+ "MSP_I2S.%04x", platform_num);
+
+ status = i2s_add_controller(i2s_cont);
+ if (status) {
+ stm_error("i2s add controller failed (%d)\n", status);
+ goto free_cont;
+ }
+ msp->i2s_cont = i2s_cont;
+ return status;
+free_cont:
+ kfree(msp->i2s_cont);
+del_timer:
+ del_timer_sync(&msp->notify_timer);
+ clk_put(msp->clk);
+free_irq:
+#if 0
+ free_irq(msp->irq, msp);
+iounmap:
+#endif
+ iounmap(msp->registers);
+free_msp:
+ kfree(msp);
+ return status;
+}
+
+/**
+ * msp_remove - remove function
+ * @pdev: platform device structure.
+ * Context: process
+ *
+ * remove function of msp platform driver.Handles dellocation of memory and irq
+ * resource. It deletes i2s_controller and one i2s_device per msp controller
+ * created in msp_probe.
+ *
+ * Returns error(-1) in case of failure or success(0).
+ */
+static int msp_remove(struct platform_device *pdev)
+{
+ struct msp *msp =
+ (struct msp *)dev_get_drvdata(&pdev->dev);
+ int status = 0;
+ i2s_del_controller(msp->i2s_cont);
+#if 0
+ free_irq(msp->irq, msp);
+#endif
+ del_timer_sync(&msp->notify_timer);
+ clk_put(msp->clk);
+ iounmap(msp->registers);
+#ifdef CONFIG_REGULATOR
+ regulator_put(msp_vape_supply);
+#endif
+ kfree(msp);
+ return status;
+}
+#ifdef CONFIG_PM
+/**
+ * msp_suspend - MSP suspend function registered with PM framework.
+ * @pdev: Reference to platform device structure of the device
+ * @state: power mgmt state.
+ *
+ * This function is invoked when the system is going into sleep, called
+ * by the power management framework of the linux kernel.
+ * Nothing is required as controller is configured with every transfer.
+ * It is assumed that no active tranfer is in progress at this time.
+ * Client driver should make sure of this.
+ *
+ */
+
+int msp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int i;
+ struct msp *msp =
+ (struct msp *)dev_get_drvdata(&pdev->dev);
+ for(i = 0; i < MAX_MSP_BACKUP_REGS;i++)
+ msp->backup_regs[i] = readl(msp->registers + (i * 4));
+ return 0;
+}
+/**
+ * msp_resume - MSP Resume function registered with PM framework.
+ * @pdev: Reference to platform device structure of the device
+ *
+ * This function is invoked when the system is coming out of sleep, called
+ * by the power management framework of the linux kernel.
+ * Nothing is required.
+ *
+ */
+
+int msp_resume(struct platform_device *pdev)
+{
+ int i;
+ struct msp *msp =
+ (struct msp *)dev_get_drvdata(&pdev->dev);
+ for(i = 0; i < MAX_MSP_BACKUP_REGS; i++)
+ writel(msp->backup_regs[i], msp->registers + (i * 4));
+ return 0;
+}
+#else
+#define msp_suspend NULL
+#define msp_resume NULL
+#endif
+
+static struct platform_driver msp_i2s_driver = {
+ .probe = msp_probe,
+ .remove = msp_remove,
+ .suspend = msp_suspend,
+ .resume = msp_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "MSP_I2S",
+ },
+};
+
+static int __init stm_msp_mod_init(void)
+{
+ return platform_driver_register(&msp_i2s_driver);
+}
+
+static void __exit stm_msp_exit(void)
+{
+ platform_driver_unregister(&msp_i2s_driver);
+ return;
+}
+
+module_init(stm_msp_mod_init);
+module_exit(stm_msp_exit);
+
+MODULE_AUTHOR("Sandeep Kaushik");
+MODULE_DESCRIPTION("STM MSP driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/i2s/msp_i2s.h b/drivers/misc/i2s/msp_i2s.h
new file mode 100644
index 00000000000..f6e471f25f8
--- /dev/null
+++ b/drivers/misc/i2s/msp_i2s.h
@@ -0,0 +1,402 @@
+/*----------------------------------------------------------------------------------*/
+/* copyright STMicroelectronics, 2007. */
+/* */
+/* This program is free software; you can redistribute it and/or modify it under */
+/* the terms of the GNU General Public License as published by the Free */
+/* Software Foundation; either version 2.1 of the License, or (at your option) */
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but WITHOUT */
+/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS */
+/* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*----------------------------------------------------------------------------------*/
+
+
+#ifndef STM_MSP_HEADER
+#define STM_MSP_HEADER
+#if 0
+struct msp_register
+{
+ u32 fifo;
+ u32 global_ctrl;
+ u32 tx_config;
+ u32 rx_config;
+ u32 srg_ctrl;
+ u32 status;
+ u32 dma_ctrl;
+ u32 reserved0;
+ u32 irq_mask;
+ u32 raw_irq_status;
+ u32 masked_irq_status;
+ u32 irq_clear;
+ u32 multichannel_ctrl;
+ u32 rx_compare_val;
+ u32 rx_compare_mask;
+ u32 reserved1;
+ u32 tx_enable_ch0;
+ u32 tx_enable_ch1;
+ u32 tx_enable_ch2;
+ u32 tx_enable_ch3;
+ u32 reserved2[4];
+ u32 rx_enable_ch0;
+ u32 rx_enable_ch1;
+ u32 rx_enable_ch2;
+ u32 rx_enable_ch3;
+ u32 reserved3[4];
+ u32 test_ctrl;
+ u32 integration_test_input;
+ u32 integration_test_output;
+ u32 test_data;
+};
+#endif
+
+#define MSP_DR 0x00
+#define MSP_GCR 0x04
+#define MSP_TCF 0x08
+#define MSP_RCF 0x0c
+#define MSP_SRG 0x10
+#define MSP_FLR 0x14
+#define MSP_DMACR 0x18
+
+#define MSP_IMSC 0x20
+#define MSP_RIS 0x24
+#define MSP_MIS 0x28
+#define MSP_ICR 0x2c
+#define MSP_MCR 0x30
+#define MSP_RCV 0x34
+#define MSP_RCM 0x38
+
+#define MSP_TCE0 0x40
+#define MSP_TCE1 0x44
+#define MSP_TCE2 0x48
+#define MSP_TCE3 0x4c
+
+#define MSP_RCE0 0x60
+#define MSP_RCE1 0x64
+#define MSP_RCE2 0x68
+#define MSP_RCE3 0x6c
+
+#define MSP_ITCR 0x80
+#define MSP_ITIP 0x84
+#define MSP_ITOP 0x88
+#define MSP_TSTDR 0x8c
+
+#define MSP_PID0 0xfe0
+#define MSP_PID1 0xfe4
+#define MSP_PID2 0xfe8
+#define MSP_PID3 0xfec
+
+#define MSP_CID0 0xff0
+#define MSP_CID1 0xff4
+#define MSP_CID2 0xff8
+#define MSP_CID3 0xffc
+
+
+/* Single or dual phase mode */
+enum
+{
+ MSP_SINGLE_PHASE,
+ MSP_DUAL_PHASE
+};
+
+
+/* Transmit/Receive shifter status
+-----------------------------------*/
+enum
+{
+ MSP_SxHIFTER_IDLE = 0,
+ MSP_SHIFTER_WORKING = 1
+};
+
+
+/* Transmit/Receive FIFO status
+---------------------------------*/
+enum
+{
+ MSP_FIFO_FULL,
+ MSP_FIFO_PART_FILLED,
+ MSP_FIFO_EMPTY
+};
+
+
+/* Frame length
+------------------*/
+enum
+{
+ MSP_FRAME_LENGTH_1 = 0,
+ MSP_FRAME_LENGTH_2 = 1,
+ MSP_FRAME_LENGTH_4 = 3,
+ MSP_FRAME_LENGTH_8 = 7,
+ MSP_FRAME_LENGTH_12 = 11,
+ MSP_FRAME_LENGTH_16 = 15,
+ MSP_FRAME_LENGTH_20 = 19,
+ MSP_FRAME_LENGTH_32 = 31,
+ MSP_FRAME_LENGTH_48 = 47,
+ MSP_FRAME_LENGTH_64 = 63
+};
+
+/* Element length */
+enum
+{
+ MSP_ELEM_LENGTH_8 = 0,
+ MSP_ELEM_LENGTH_10 = 1,
+ MSP_ELEM_LENGTH_12 = 2,
+ MSP_ELEM_LENGTH_14 = 3,
+ MSP_ELEM_LENGTH_16 = 4,
+ MSP_ELEM_LENGTH_20 = 5,
+ MSP_ELEM_LENGTH_24 = 6,
+ MSP_ELEM_LENGTH_32 = 7
+};
+
+
+/* Data delay (in bit clock cycles)
+---------------------------------------*/
+enum
+{
+ MSP_DELAY_0 = 0,
+ MSP_DELAY_1 = 1,
+ MSP_DELAY_2 = 2,
+ MSP_DELAY_3 = 3
+};
+
+
+/* Configurations of clocks (transmit, receive or sample rate generator)
+-------------------------------------------------------------------------*/
+enum
+{
+ MSP_RISING_EDGE = 0,
+ MSP_FALLING_EDGE = 1
+};
+
+/* Protocol dependant parameters list */
+struct msp_protocol_desc
+{
+ u32 phase_mode;
+ u32 frame_len_1;
+ u32 frame_len_2;
+ u32 element_len_1;
+ u32 element_len_2;
+ u32 data_delay;
+ u32 tx_clock_edge;
+ u32 rx_clock_edge;
+};
+#define RX_ENABLE_MASK 0x00000001
+#define RX_FIFO_ENABLE_MASK 0x00000002
+#define RX_FRAME_SYNC_MASK 0x00000004
+#define DIRECT_COMPANDING_MASK 0x00000008
+#define RX_SYNC_SEL_MASK 0x00000010
+#define RX_CLK_POL_MASK 0x00000020
+#define RX_CLK_SEL_MASK 0x00000040
+#define LOOPBACK_MASK 0x00000080
+#define TX_ENABLE_MASK 0x00000100
+#define TX_FIFO_ENABLE_MASK 0x00000200
+#define TX_FRAME_SYNC_MASK 0x00000400
+#define TX_MSP_TDR_TSR 0x00000800
+#define TX_SYNC_SEL_MASK 0x00001800
+#define TX_CLK_POL_MASK 0x00002000
+#define TX_CLK_SEL_MASK 0x00004000
+#define TX_EXTRA_DELAY_MASK 0x00008000
+#define SRG_ENABLE_MASK 0x00010000
+#define SRG_CLK_POL_MASK 0x00020000
+#define SRG_CLK_SEL_MASK 0x000C0000
+#define FRAME_GEN_EN_MASK 0x00100000
+#define SPI_CLK_MODE_MASK 0x00600000
+#define SPI_BURST_MODE_MASK 0x00800000
+
+#define RXEN_BIT 0
+#define RFFEN_BIT 1
+#define RFSPOL_BIT 2
+#define DCM_BIT 3
+#define RFSSEL_BIT 4
+#define RCKPOL_BIT 5
+#define RCKSEL_BIT 6
+#define LBM_BIT 7
+#define TXEN_BIT 8
+#define TFFEN_BIT 9
+#define TFSPOL_BIT 10
+#define TFSSEL_BIT 11
+#define TCKPOL_BIT 13
+#define TCKSEL_BIT 14
+#define TXDDL_BIT 15
+#define SGEN_BIT 16
+#define SCKPOL_BIT 17
+#define SCKSEL_BIT 18
+#define FGEN_BIT 20
+#define SPICKM_BIT 21
+
+#define msp_rx_clkpol_bit(n) ((n & 1) << RCKPOL_BIT)
+#define msp_tx_clkpol_bit(n) ((n & 1) << TCKPOL_BIT)
+#define msp_spi_clk_mode_bits(n) ((n & 3) << SPICKM_BIT)
+
+
+/* Use this to clear the clock mode bits to non-spi */
+#define MSP_NON_SPI_CLK_MASK 0x00600000
+
+#define P1ELEN_BIT 0
+#define P1FLEN_BIT 3
+#define DTYP_BIT 10
+#define ENDN_BIT 12
+#define DDLY_BIT 13
+#define FSIG_BIT 15
+#define P2ELEN_BIT 16
+#define P2FLEN_BIT 19
+#define P2SM_BIT 26
+#define P2EN_BIT 27
+
+#define msp_p1_elem_len_bits(n) (n & 0x00000007)
+#define msp_p2_elem_len_bits(n) (((n) << P2ELEN_BIT) & 0x00070000)
+#define msp_p1_frame_len_bits(n) (((n) << P1FLEN_BIT) & 0x00000378)
+#define msp_p2_frame_len_bits(n) (((n) << P2FLEN_BIT) & 0x03780000)
+#define msp_data_delay_bits(n) (((n) << DDLY_BIT) & 0x00003000)
+#define msp_data_type_bits(n) (((n) << DTYP_BIT) & 0x00000600)
+#define msp_p2_start_mode_bit(n) (n << P2SM_BIT)
+#define msp_p2_enable_bit(n) (n << P2EN_BIT)
+
+/* Flag register
+--------------------*/
+#define RX_BUSY 0x00000001
+#define RX_FIFO_EMPTY 0x00000002
+#define RX_FIFO_FULL 0x00000004
+#define TX_BUSY 0x00000008
+#define TX_FIFO_EMPTY 0x00000010
+#define TX_FIFO_FULL 0x00000020
+
+#define RBUSY_BIT 0
+#define RFE_BIT 1
+#define RFU_BIT 2
+#define TBUSY_BIT 3
+#define TFE_BIT 4
+#define TFU_BIT 5
+
+/* Multichannel control register
+---------------------------------*/
+#define RMCEN_BIT 0
+#define RMCSF_BIT 1
+#define RCMPM_BIT 3
+#define TMCEN_BIT 5
+#define TNCSF_BIT 6
+
+/* Sample rate generator register
+------------------------------------*/
+#define SCKDIV_BIT 0
+#define FRWID_BIT 10
+#define FRPER_BIT 16
+
+#define SCK_DIV_MASK 0x0000003FF
+#define frame_width_bits(n) (((n) << FRWID_BIT) &0x0000FC00)
+#define frame_period_bits(n) (((n) << FRPER_BIT) &0x1FFF0000)
+
+
+/* DMA controller register
+---------------------------*/
+#define RX_DMA_ENABLE 0x00000001
+#define TX_DMA_ENABLE 0x00000002
+
+#define RDMAE_BIT 0
+#define TDMAE_BIT 1
+
+/*Interrupt Register
+-----------------------------------------*/
+#define RECEIVE_SERVICE_INT 0x00000001
+#define RECEIVE_OVERRUN_ERROR_INT 0x00000002
+#define RECEIVE_FRAME_SYNC_ERR_INT 0x00000004
+#define RECEIVE_FRAME_SYNC_INT 0x00000008
+#define TRANSMIT_SERVICE_INT 0x00000010
+#define TRANSMIT_UNDERRUN_ERR_INT 0x00000020
+#define TRANSMIT_FRAME_SYNC_ERR_INT 0x00000040
+#define TRANSMIT_FRAME_SYNC_INT 0x00000080
+#define ALL_INT 0x000000ff
+
+/* Protocol configuration values
+* I2S: Single phase, 16 bits, 2 words per frame
+-----------------------------------------------*/
+#define I2S_PROTOCOL_DESC \
+{ \
+ MSP_SINGLE_PHASE, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_ELEM_LENGTH_32, \
+ MSP_ELEM_LENGTH_32, \
+ MSP_DELAY_1, \
+ MSP_FALLING_EDGE, \
+ MSP_FALLING_EDGE \
+}
+
+#define PCM_PROTOCOL_DESC \
+{ \
+ MSP_SINGLE_PHASE, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_ELEM_LENGTH_16, \
+ MSP_ELEM_LENGTH_16, \
+ MSP_DATA_DELAY, \
+ MSP_TX_CLOCK_EDGE, \
+ MSP_RX_CLOCK_EDGE \
+}
+
+/* Companded PCM: Single phase, 8 bits, 1 word per frame
+--------------------------------------------------------*/
+#define PCM_COMPAND_PROTOCOL_DESC \
+{ \
+ MSP_SINGLE_PHASE, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_DELAY_0, \
+ MSP_RISING_EDGE, \
+ MSP_FALLING_EDGE \
+}
+
+/* AC97: Double phase, 1 element of 16 bits during first phase,
+* 12 elements of 20 bits in second phase.
+--------------------------------------------------------------*/
+#define AC97_PROTOCOL_DESC \
+{ \
+ MSP_DUAL_PHASE, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_12, \
+ MSP_ELEM_LENGTH_16, \
+ MSP_ELEM_LENGTH_20, \
+ MSP_DELAY_1, \
+ MSP_RISING_EDGE, \
+ MSP_FALLING_EDGE \
+}
+
+#define SPI_MASTER_PROTOCOL_DESC \
+{ \
+ MSP_SINGLE_PHASE, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_DELAY_1, \
+ MSP_FALLING_EDGE, \
+ MSP_RISING_EDGE \
+}
+#define SPI_SLAVE_PROTOCOL_DESC \
+{ \
+ MSP_SINGLE_PHASE, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_FRAME_LENGTH_1, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_ELEM_LENGTH_8, \
+ MSP_DELAY_1, \
+ MSP_FALLING_EDGE, \
+ MSP_RISING_EDGE \
+}
+#define FUNC_MSP0 GPIO_ALT_MSP_0
+#define FUNC_MSP1 GPIO_ALT_MSP_1
+#define FUNC_MSP2 GPIO_ALT_MSP_2
+#define FUNC_MSP3 GPIO_ALT_MSP_3
+#define FUNC_MSP4 GPIO_ALT_MSP_4
+#define FUNC_MSP5 GPIO_ALT_MSP_5
+
+#define MSP_FRAME_PERIOD_IN_MONO_MODE 256
+#define MSP_FRAME_PERIOD_IN_STEREO_MODE 32
+#define MSP_FRAME_WIDTH_IN_STEREO_MODE 16
+#endif
+
diff --git a/drivers/misc/msw/Kconfig b/drivers/misc/msw/Kconfig
new file mode 100644
index 00000000000..f89af4d5664
--- /dev/null
+++ b/drivers/misc/msw/Kconfig
@@ -0,0 +1,28 @@
+#
+# HSI Protocol kernel configuration
+#
+
+config ISA_HSI_MODEM
+ tristate "HSI Protocol driver"
+ depends on U8500_HSI_LEGACY
+ default Y
+ ---help---
+ If you say Y here, you will enable the U8500 HSI Protocol driver.
+
+ If unsure, say N.
+
+choice
+ prompt "HSI Direction"
+ default U8500_HSI_MODEM_EXTERNAL
+
+config U8500_HSI_MODEM_EXTERNAL
+ bool "External"
+config U8500_HSI_MODEM_INTERNAL
+ bool "Internal"
+
+endchoice
+
+config U8500_HSI_MODEM_DIRECTION
+ hex
+ default 0x0 if !U8500_HSI_MODEM_EXTERNAL
+ default 0x1 if U8500_HSI_MODEM_EXTERNAL
diff --git a/drivers/misc/msw/Makefile b/drivers/misc/msw/Makefile
new file mode 100644
index 00000000000..8eeb9dbbfbc
--- /dev/null
+++ b/drivers/misc/msw/Makefile
@@ -0,0 +1,3 @@
+mod_isa-objs := ipc_hsi_protocol.o isa_access.o
+
+obj-$(CONFIG_ISA_HSI_MODEM) += mod_isa.o
diff --git a/drivers/misc/msw/ipc_hsi_protocol.c b/drivers/misc/msw/ipc_hsi_protocol.c
new file mode 100644
index 00000000000..6d466d57296
--- /dev/null
+++ b/drivers/misc/msw/ipc_hsi_protocol.c
@@ -0,0 +1,942 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright ST Ericsson, 2009. */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2.1 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
+/* See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*---------------------------------------------------------------------------*/
+
+/** @file ipc_hsi_protocol.c
+ * @brief This file contains HSI driver protocol interface handling.
+ */
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <linux/hsi-legacy.h>
+#include "ipc_protocol_if.h"
+#include "ipc_hsi_protocol.h"
+
+#define NAME "IPC_HSI"
+#define IPC_HSI_DEBUG 0
+#define dbg_printk(format, arg...) (IPC_HSI_DEBUG & 1) ? \
+ (printk(KERN_ALERT NAME ": " format , ## arg)) : \
+ ({do {} while (0); })
+
+#define HSICTRL 0x80157324
+/** HSI Power management configuration*/
+#define NO_SLEEP_NO_DVFS 0x0
+#define SLEEP_NO_DVFS 0x1
+#define DVFS_NO_SLEEP 0x2
+#define SLEEP_DVFS 0x3
+/** HSI version */
+#define NDK_SSI_VERSION 0x0000
+#define NDK_SSI_CONFIGURATION NO_SLEEP_NO_DVFS
+/** boot state defines */
+#define MODEM_BOOT_INFO_REQ_ID 0x1
+#define MODEM_BOOT_INFO_RESP_ID 0x2
+#define BOOT_INFO_REQ 0x10000000
+#define BOOT_INFO_RESP 0x20000000
+/** Modem States */
+#define MODEM_SSI_BOOT_INIT 0
+#define MODEM_SSI_BOOT_INFO_SYNC 1
+#define MODEM_SSI_BOOT_DONE 2
+
+u8 current_boot_state;
+u8 current_boot_state_audio;
+u32 modem_response;
+u32 host_request,boot_info_resp;
+u32 modem_response_audio;
+u32 rcv_start;
+
+static struct t_l1_desc dev_desc[MAX_CHANNELS_MONITORED];
+
+static int do_modem_boot(void);
+
+static inline int align_4byte(int len)
+{
+ return 4*(int)((len+3)/4);
+}
+
+/**
+ * hsi_msg_send - UL Message Transmission Function
+ *
+ * @addr: message address
+ * @l2_header: l2 header
+ * This function sends the message to the media available(HSI/SSI).
+ * After successful transmission of the message it calls layer-2
+ * provided deallocation function.
+*/
+int hsi_msg_send(void *addr, u8 l2_header, u32 length)
+{
+ u32 st;
+ struct t_data_buf *p_data;
+ struct t_l1_desc *tx_params;
+ u32 hsimode;
+ p_data = (struct t_data_buf *)addr;
+ hsimode = 0;
+ dbg_printk("host_msg_send++\n");
+
+ if (l2_header < 2)
+ tx_params = &dev_desc[3];
+ else
+ tx_params = &dev_desc[2];
+
+ down(&tx_params->tx_mutex);
+
+ if (dlp_ssi_get_boot_state() != MODEM_SSI_BOOT_DONE) {
+ printk(KERN_ALERT NAME ":Modem not Initialized\n");
+ up(&tx_params->tx_mutex);
+ return -1;
+ }
+
+ st = ((l2_header & 0xFF) << 24) |
+ ((tx_params->tx_msg.mapid & 0xF) << 20) |
+ (length & 0xFFFFF);
+
+ *(tx_params->tx_msg.st) = st;
+
+ init_completion(&tx_params->tx_complete);
+ /** set interrupt mode */
+ hsimode = HSI_INTERRUPT_MODE;
+ hsi_ioctl(tx_params->tx_dev, HSI_IOCTL_SET_CURRMODE, &hsimode);
+ /** send start */
+ hsi_write(tx_params->tx_dev, &st, 32, 4);
+ /** wait for start finish */
+ wait_for_completion(&tx_params->tx_complete);
+
+ init_completion(&tx_params->tx_complete);
+ /** set interrupt mode */
+ hsimode = HSI_INTERRUPT_MODE;
+ hsi_ioctl(tx_params->tx_dev, HSI_IOCTL_SET_CURRMODE, &hsimode);
+ /** write data */
+ hsi_write(tx_params->tx_dev, p_data->log_address, \
+ 32, align_4byte(length));
+
+ wait_for_completion(&tx_params->tx_complete);
+
+ tx_params->tx_msg.mapid = (tx_params->tx_msg.mapid + 1) & 0xF;
+
+ dbg_printk("%d byte data transmitted\n", length);
+
+ up(&tx_params->tx_mutex);
+
+ return 0;
+}
+/**
+ * tx_common_data_handler() common data tx completion callback
+ *
+ * This function gets called after any tx completion on common
+ * control channel.
+ */
+static void tx_common_data_handler(void)
+{
+ struct t_l1_desc *tx_params = &dev_desc[3];
+
+ dbg_printk("tx complete on data channel\n");
+ complete(&tx_params->tx_complete);
+}
+
+static void tx_audio_data_handler(void)
+{
+ struct t_l1_desc *tx_params = &dev_desc[2];
+ dbg_printk("tx complete on audio channel\n");
+ complete(&tx_params->tx_complete);
+}
+
+/**
+ * rx_common_data_handler() - Common channel Rx Message handler
+ *
+ * This function handles messages received on common hsi channel.
+ * This callback is registerd while registering client to hsi driver.
+ */
+static void rx_common_data_handler(void)
+{
+ struct t_data_buf *msgptr;
+ u32 pdu_length;
+ u8 l2_header;
+ struct t_l1_desc *rx_params;
+ u32 st;
+ u8 mapid;
+ u32 hsimode = 2;
+
+ rx_params = &dev_desc[3];
+
+ /** start_transmission handler*/
+ if (rx_params->rx_state == L1_RX_WAITING_ST_STATE) {
+ rx_params->rx_state = L1_RX_ST_RECEIVED_STATE;
+
+ if (hsimode != HSI_DMA_MODE)
+ st = rcv_start;
+ else
+ st = *(rx_params->rx_msg.rx_st.log_address);
+
+ pdu_length = st & 0xFFFFF;
+ mapid = (st >> 20) & 0xF;
+ if ((pdu_length <= 0) || \
+ (mapid != rx_params->rx_msg.mapid) || \
+ ((st >> 24) > 1)) {
+ printk(KERN_ALERT "\n False Message..Start searching again");
+ BUG();
+ }
+
+ /** assign correct pointer to the msgptr*/
+ msgptr = &rx_params->rx_msg.msgptr;
+
+ l3alloc(pdu_length, st>>24, (void *)msgptr);
+
+ rx_params->rx_state = L1_RX_BUSY_STATE;
+ rx_params->rx_msg.length = pdu_length;
+
+ hsimode=HSI_DMA_MODE;
+ hsi_ioctl(rx_params->rx_dev, HSI_IOCTL_SET_CURRMODE, \
+ &hsimode);
+ mdelay(1);
+ hsi_read(rx_params->rx_dev, (hsimode == HSI_DMA_MODE) ? \
+ (void *)msgptr->phys_address : \
+ (void *)msgptr->log_address, \
+ 32, align_4byte(pdu_length));
+ }
+ /** data intr/dma eot handler callback*/
+ else if (rx_params->rx_state == L1_RX_BUSY_STATE) {
+
+ msgptr = &rx_params->rx_msg.msgptr;
+ pdu_length = rx_params->rx_msg.length;
+
+ if (hsimode != HSI_DMA_MODE)
+ l2_header = ((rcv_start)>>24) & 0xFF;
+ else
+ l2_header = (*(rx_params->rx_msg.rx_st.log_address) >> \
+ 24) & 0xFF;
+
+ l3receive(msgptr, pdu_length, l2_header);
+
+ /** changing map-id for next message*/
+ rx_params->rx_msg.mapid = (rx_params->rx_msg.mapid+1) & 0xF;
+
+ /** set the state*/
+ rx_params->rx_state = L1_RX_WAITING_ST_STATE;
+ /** start searching for start again */
+ rcv_start = 0;
+ hsimode=HSI_DMA_MODE;
+ hsi_ioctl(rx_params->rx_dev, HSI_IOCTL_SET_CURRMODE, & \
+ hsimode);
+ hsi_read(rx_params->rx_dev, (hsimode != HSI_DMA_MODE) ? \
+ (void *)&rcv_start : \
+ (void *)rx_params->rx_msg.rx_st.phys_address,
+ 32, 4);
+ }
+ /** error case */
+ else {
+ printk(KERN_ALERT "Entering while(1)\n");
+ BUG();
+ }
+}
+
+/**
+ * rx_audio_data_handler - Audio data channel callback handler
+ *
+ * This function handles events on audio data channel.
+ */
+static void rx_audio_data_handler(void)
+{
+ struct t_data_buf *msgptr;
+ u32 pdu_length;
+ u8 l2_header;
+ struct t_l1_desc *rx_params;
+ u32 st;
+ u8 mapid;
+ u32 hsimode = 2;
+
+ dbg_printk("rx_audio_data_handler++ \n");
+
+ rx_params = &dev_desc[2];
+
+ /** start_transmission handler*/
+ if (rx_params->rx_state == L1_RX_WAITING_ST_STATE) {
+ rx_params->rx_state = L1_RX_ST_RECEIVED_STATE;
+
+ if (hsimode != HSI_DMA_MODE)
+ st = rcv_start;
+ else
+ st = *(rx_params->rx_msg.rx_st.log_address);
+
+
+ pdu_length = st & 0xFFFFF;
+ /*message ID*/
+ mapid = (st >> 20) & 0xF;
+
+ if ((pdu_length <= 0) || \
+ (mapid != rx_params->rx_msg.mapid) || \
+ ((st >> 24) != 2)) {
+ printk(KERN_ALERT "False Alert");
+ BUG();
+ }
+
+ /** assign correct pointer to the msgptr*/
+ msgptr = &rx_params->rx_msg.msgptr;
+
+ l3alloc(align_4byte(pdu_length), st>>24, (void *)msgptr);
+
+ rx_params->rx_state = L1_RX_BUSY_STATE;
+ rx_params->rx_msg.length = pdu_length;
+
+ hsimode = HSI_DMA_MODE;
+ hsi_ioctl(rx_params->rx_dev, HSI_IOCTL_SET_CURRMODE, &hsimode);
+ hsi_read(rx_params->rx_dev, \
+ (hsimode == HSI_DMA_MODE) ? \
+ (void *)msgptr->phys_address : \
+ (void *)msgptr->log_address, \
+ 32, align_4byte(pdu_length));
+ }
+ /** data intr/dma eot handler callback*/
+ else if (rx_params->rx_state == L1_RX_BUSY_STATE) {
+
+ msgptr = &rx_params->rx_msg.msgptr;
+ pdu_length = rx_params->rx_msg.length;
+ if (hsimode != HSI_DMA_MODE)
+ l2_header = ((rcv_start) >> 24) & 0xFF;
+ else
+ l2_header = (*(rx_params->rx_msg.rx_st.log_address) >> \
+ 24) & 0xFF;
+
+ l3receive(msgptr, align_4byte(pdu_length), l2_header);
+
+ /** changing map-id for next message*/
+ rx_params->rx_msg.mapid = (rx_params->rx_msg.mapid + 1) & 0xF;
+
+ /** set the state*/
+ rx_params->rx_state = L1_RX_WAITING_ST_STATE;
+ /** start searching for start again */
+ rcv_start = 0;
+ hsimode = HSI_DMA_MODE;
+ hsi_ioctl(rx_params->rx_dev, HSI_IOCTL_SET_CURRMODE, &hsimode);
+ hsi_read(rx_params->rx_dev, \
+ (hsimode != HSI_DMA_MODE) ? \
+ (void *)&rcv_start : \
+ (void *)rx_params->rx_msg.rx_st.phys_address, \
+ 32, 4);
+ } else {
+ printk("Entering while(1)\n");
+ BUG();
+ }
+ dbg_printk("rx_audio_data_handler-- \n");
+}
+
+void state_change_audio(u8 state)
+{
+u32 hsimode = HSI_DMA_MODE;
+static struct t_l1_desc *rx_params;
+rx_params = &dev_desc[2]; /** Common data channel */
+
+if(state==MODEM_SSI_BOOT_DONE){
+
+ rx_params->rx_state = L1_RX_WAITING_ST_STATE;
+ hsimode = HSI_DMA_MODE;
+ hsi_ioctl(rx_params->rx_dev, HSI_IOCTL_SET_CURRMODE, \
+ &hsimode);
+ hsi_read(rx_params->rx_dev, \
+ (hsimode != HSI_DMA_MODE) ? \
+ (void *)&rcv_start : \
+ (void *)rx_params->rx_msg.rx_st.phys_address, \
+ 32, 4);
+ }
+
+}
+
+/**
+ * rx_audio_control_handler - Audio control channel callback handler
+ *
+ * This function handles events on audio control channel.
+ */
+static void rx_audio_control_handler(void)
+{
+ int err=0;
+ static struct t_l1_desc *ch1;
+ u32 hsimode = HSI_INTERRUPT_MODE;
+ u32 rx_command;
+ u8 command_ID,modem_ssi_version,modem_config_info;
+
+ dbg_printk("rx_common_control_handler Read buff %x\n", modem_response);
+
+
+ ch1 = &dev_desc[1];
+
+ rx_command = modem_response;
+
+ command_ID = (rx_command >> 28);
+
+ switch (command_ID) {
+
+ case MODEM_BOOT_INFO_REQ_ID:
+
+
+ modem_ssi_version = (u8)rx_command;
+ if (modem_ssi_version != NDK_SSI_VERSION) {
+ dbg_printk(KERN_ALERT NAME ":Unsup SSI version\n");
+ BUG();
+ }
+
+ host_request = BOOT_INFO_RESP;
+
+
+
+ modem_config_info = (rx_command & \
+ 0x0000ff00) >> 8;
+
+ boot_info_resp = BOOT_INFO_RESP|
+ (NDK_SSI_CONFIGURATION & \
+ modem_config_info) << 8 |
+ modem_ssi_version;
+
+
+
+ hsi_ioctl(ch1->tx_dev, HSI_IOCTL_SET_CURRMODE, &hsimode);
+
+ err = hsi_write(ch1->tx_dev, &boot_info_resp, 32, 4);
+
+ printk(KERN_ALERT NAME ":Audio:SYNC ->DONE!\n");
+
+ current_boot_state_audio = MODEM_SSI_BOOT_DONE;
+
+ /** Start common data channel receive */
+ state_change_audio(current_boot_state_audio);
+
+ break;
+
+ case MODEM_BOOT_INFO_RESP_ID:
+ modem_ssi_version = (u8)rx_command;
+ if (modem_ssi_version != NDK_SSI_VERSION) {
+ dbg_printk(KERN_ALERT NAME ":Unsup SSI version\n");
+ BUG();
+ }
+
+ printk(KERN_ALERT NAME ":Audio:SYNC ->DONE!\n");
+
+ current_boot_state_audio = MODEM_SSI_BOOT_DONE;
+
+ /** Start common data channel receive */
+ state_change_audio(current_boot_state_audio);
+
+ break;
+
+ default:
+
+ dbg_printk(" Error Corrupted response\n");
+
+
+
+ break;
+
+ }
+
+
+}
+
+
+void state_change_common(u8 state)
+{
+u32 hsimode = HSI_DMA_MODE;
+static struct t_l1_desc *rx_params;
+
+rx_params = &dev_desc[3]; /** Common data channel */
+
+if(state==MODEM_SSI_BOOT_DONE){
+
+ rx_params->rx_state = L1_RX_WAITING_ST_STATE;
+ hsimode = HSI_DMA_MODE;
+ hsi_ioctl(rx_params->rx_dev, HSI_IOCTL_SET_CURRMODE, \
+ &hsimode);
+ hsi_read(rx_params->rx_dev, \
+ (hsimode != HSI_DMA_MODE) ? \
+ (void *)&rcv_start : \
+ (void *)rx_params->rx_msg.rx_st.phys_address, \
+ 32, 4);
+ }
+
+}
+
+/**
+ * rx_common_control_handler - Common control channel callback handler
+ * This function handles events on common control channel.
+ */
+static void rx_common_control_handler(void)
+{
+ int err=0;
+ static struct t_l1_desc *ch0;
+ u32 hsimode = HSI_INTERRUPT_MODE;
+ u32 rx_command;
+ u8 command_ID,modem_ssi_version,modem_config_info;
+
+ dbg_printk("rx_common_control_handler Read buff %x\n", modem_response);
+
+
+ ch0 = &dev_desc[0];
+
+ rx_command = modem_response;
+
+ command_ID = (rx_command >> 28);
+
+ switch (command_ID) {
+
+ case MODEM_BOOT_INFO_REQ_ID:
+
+
+ modem_ssi_version = (u8)rx_command;
+ if (modem_ssi_version != NDK_SSI_VERSION) {
+ dbg_printk(KERN_ALERT NAME ":Unsup SSI version\n");
+ BUG();
+ }
+
+ host_request = BOOT_INFO_RESP;
+
+
+
+ modem_config_info = (rx_command & \
+ 0x0000ff00) >> 8;
+
+ boot_info_resp = BOOT_INFO_RESP|
+ (NDK_SSI_CONFIGURATION & \
+ modem_config_info) << 8 |
+ modem_ssi_version;
+
+
+ hsi_ioctl(ch0->tx_dev, HSI_IOCTL_SET_CURRMODE, &hsimode);
+
+ err = hsi_write(ch0->tx_dev, &boot_info_resp, 32, 4);
+
+ printk(KERN_ALERT NAME ":Common:SYNC ->DONE!\n");
+
+ current_boot_state = MODEM_SSI_BOOT_DONE;
+
+ /** Start common data channel receive */
+ state_change_common(current_boot_state);
+
+ break;
+
+ case MODEM_BOOT_INFO_RESP_ID:
+ modem_ssi_version = (u8)rx_command;
+ if (modem_ssi_version != NDK_SSI_VERSION) {
+ dbg_printk(KERN_ALERT NAME ":Unsup SSI version\n");
+ BUG();
+ }
+
+ printk(KERN_ALERT NAME ":Common:SYNC ->DONE!\n");
+
+ current_boot_state = MODEM_SSI_BOOT_DONE;
+
+ /** Start common data channel receive */
+ state_change_common(current_boot_state);
+
+ break;
+
+ default:
+
+ dbg_printk(" Error Corrupted response\n");
+
+
+
+ break;
+
+ }
+
+
+}
+
+
+
+static void tx_common_control_handler(void)
+{
+ dbg_printk("tx_common_control_handler\n");
+}
+
+static void tx_audio_control_handler(void)
+{
+ dbg_printk("tx_common_audio_control_handler\n");
+}
+
+u8 dlp_ssi_get_boot_state(void)
+{
+ return current_boot_state;
+}
+
+
+
+static void read_callbk(struct hsi_device *dev)
+{
+ u8 ch = 0;
+ dbg_printk("read_callbk\n");
+
+ ch = (u8)dev->chid;
+
+ switch (ch) {
+ case CHANNEL_COMMON_CONTROL:
+ rx_common_control_handler();
+ break;
+ case CHANNEL_AUDIO_CONTROL:
+ rx_audio_control_handler();
+ break;
+ case CHANNEL_AUDIO_DATA:
+ rx_audio_data_handler();
+ break;
+ case CHANNEL_COMMON_DATA:
+ rx_common_data_handler();
+ break;
+ default:
+ BUG();
+ };
+}
+
+static void write_callbk(struct hsi_device *dev)
+{
+ int ch = 0;
+ dbg_printk("write_callbk\n");
+
+ ch = dev->chid;
+ switch (ch) {
+ case CHANNEL_COMMON_CONTROL:
+ tx_common_control_handler();
+ break;
+ case CHANNEL_AUDIO_CONTROL:
+ tx_audio_control_handler();
+ break;
+ case CHANNEL_AUDIO_DATA:
+ tx_audio_data_handler();
+ break;
+ case CHANNEL_COMMON_DATA:
+ tx_common_data_handler();
+ break;
+ default:
+ BUG();
+ }
+}
+
+static int __init hsi_l2mux_drv_probe(struct hsi_device *dev)
+{
+ int err = 0;
+ static int chid = -1, no_chn;
+
+ if (!dev) {
+ printk(KERN_ALERT "SSI device not populated \n");
+ return -ENODEV;
+ }
+ dbg_printk("hsi_l2mux_drv_probe++\n");
+ dbg_printk("ctrlrid %d chid %d\n", dev->ctrlrid, dev->chid);
+
+ switch (dev->chid) {
+ case CHANNEL_COMMON_CONTROL:
+ no_chn++; chid = 0;
+ break;
+ case CHANNEL_AUDIO_CONTROL:
+ no_chn++; chid = 1;
+ break;
+ case CHANNEL_AUDIO_DATA:
+ no_chn++; chid = 2;
+ break;
+ case CHANNEL_COMMON_DATA:
+ no_chn++; chid = 3;
+ break;
+ default:
+ break;
+ };
+
+ if (no_chn >= 0) {
+ if (dev->ctrlrid == HSIT_CTRLR_ID) {
+ dev_desc[chid].tx_dev = dev;
+ hsi_dev_set_cb(dev_desc[chid].tx_dev, \
+ NULL, &write_callbk);
+ } else {
+ dev_desc[chid].rx_dev = dev;
+ hsi_dev_set_cb(dev_desc[chid].rx_dev, \
+ &read_callbk, NULL);
+ }
+ }
+
+ return err;
+}
+
+static int __exit hsi_l2mux_drv_remove(struct hsi_device *dev)
+{
+ u8 chid = dev->chid;
+ dbg_printk("hsi_l2mux_drv_remove++\n");
+ dbg_printk("ctrlrid %d chid %d\n", dev->ctrlrid, dev->chid);
+
+ if (dev->ctrlrid == HSIT_CTRLR_ID)
+ dev_desc[chid].tx_dev = NULL;
+ else
+ dev_desc[chid].rx_dev = NULL;
+ return 0;
+}
+
+/**
+ * channel_exception_handler -
+ *
+ * @ctrlr_id: controller id
+ * @event: exception type
+ * @arg:
+ *
+ * NOTE: an actual protocol driver is expected to do proper
+ * exception handling. This could include flushing its buffers,
+ * cancelling read, informing the TX through a message to
+ * resend/start sending data
+ *
+ * Apart from informing the protocol driver the lowlevel HSI driver
+ * does not perform any operations on receiving an exception,
+ * except when it receives :
+ * HSI_EXCEP_PIPEBUF_OVERRUN, where it flushes HSIR
+ * pipeline buffer
+ * HSI_RXCHANNELS_OVERRUN , where it flushes the HSIR channel
+ * buffer
+ */
+static void channel_exception_handler(u32 ctrlr_id, u32 event, void *arg)
+{
+ u8 chid;
+ /** exceptions are received only on HSIR */
+ if (ctrlr_id != HSIR_CTRLR_ID) {
+ printk(KERN_ALERT "HSI test protocol driver:exception on \
+ wrong controller\n");
+ return;
+ }
+
+ switch (event) {
+ case HSI_EXCEP_TIMEOUT:
+ printk(KERN_ALERT "protocol driver:TIMEOUT \n");
+ break;
+ case HSI_EXCEP_PIPEBUF_OVERRUN:
+ /** HSI has flushed pipeline buffer...
+ protocol driver MUST take appropriate action */
+ printk(KERN_ALERT "protocol driver:PIPEBUF OVERRUN \n");
+ break;
+ case HSI_EXCEP_BREAK_DETECTED:
+ printk(KERN_ALERT "protocol driver:BREAK DETECT \n");
+ break;
+ case HSI_EXCEP_PARITY_ERROR:
+ printk(KERN_ALERT "protocol driver: PARITY ERROR \n");
+ break;
+ case HSI_RXCHANNELS_OVERRUN:
+ /** HSI has flushed corresponding channel buffer...
+ protocol driver MUST take appropriate action */
+ chid = *(u8 *)arg;
+ printk(KERN_ALERT "protocol driver: Ch %d OVERRUN \n", chid);
+ break;
+ }
+}
+
+static struct hsi_device_driver ipc_driver = {
+ /** tx and rx controller */
+ .ctrl_mask = 0x3,
+ /** channel 3 and 0*/
+ .ch_mask = 0xf,
+ /** all exceptions */
+ .excep_mask = 0x1F,
+ /** exception handler*/
+ .excep_event = channel_exception_handler,
+ /**probe function*/
+ .probe = hsi_l2mux_drv_probe,
+ /**remove function*/
+ .remove = __exit_p(hsi_l2mux_drv_remove),
+ .driver = {
+ .name = "HSI_IPC_DRIVER",
+ },
+};
+/**
+ * dlp_protocol_init() - HSI Protocol Init
+ *
+ * This function performs following tasks.
+ * Registers to hsi bus driver and waits till all the channels are probed.
+ * It opens common data and common control channel.
+ */
+int dlp_protocol_init(void)
+{
+ int err = 0, no_ch;
+ u32 framelen = 32, watermark = 0x01;
+
+ /*HSI out*/
+ #if (CONFIG_U8500_HSI_MODEM_DIRECTION)
+ *((unsigned int *)((void __iomem *)ioremap_nocache(HSICTRL, 32))) = 2;
+ #endif
+
+ err = register_hsi_driver(&ipc_driver);
+ if (err < 0) {
+ printk(KERN_ALERT "hsi protocol driver registration failed\n");
+ return err;
+ }
+ for (no_ch = 0; no_ch < MAX_CHANNELS_MONITORED; no_ch++) {
+ err = hsi_open(dev_desc[no_ch].tx_dev);
+ if (err < 0) {
+ printk(KERN_ALERT NAME ":Can't open HSIT-%d\n", no_ch);
+ return err;
+ }
+ err = hsi_open(dev_desc[no_ch].rx_dev);
+ if (err < 0) {
+ printk(KERN_ALERT NAME ":Can't open HSIR-%d\n", no_ch);
+ return err;
+ }
+ err = hsi_ioctl(dev_desc[no_ch].tx_dev, \
+ HSI_IOCTL_SET_WATERMARK, \
+ (void *)&watermark);
+ if (err < 0) {
+ printk(KERN_ALERT NAME ":Cannot set frame-length\n");
+ return err;
+ }
+ err = hsi_ioctl(dev_desc[no_ch].rx_dev, \
+ HSI_IOCTL_SET_WATERMARK, \
+ (void *)&watermark);
+ if (err < 0) {
+ printk(KERN_ALERT NAME ":Cannot set frame-length\n");
+ return err;
+ }
+ err = hsi_ioctl(dev_desc[no_ch].tx_dev, \
+ HSI_IOCTL_SET_FRAMELEN, \
+ (void *)&framelen);
+ if (err < 0) {
+ printk(KERN_ALERT NAME ":Cannot set frame-length\n");
+ return err;
+ }
+ err = hsi_ioctl(dev_desc[no_ch].rx_dev, \
+ HSI_IOCTL_SET_FRAMELEN, \
+ (void *)&framelen);
+ if (err < 0) {
+ printk(KERN_ALERT NAME ":Cannot set frame-length\n");
+ return err;
+ }
+ }
+
+ dev_desc[2].tx_msg.st = kmalloc(4, GFP_KERNEL | GFP_ATOMIC);
+ if (dev_desc[2].tx_msg.st == NULL) {
+ printk(KERN_ALERT NAME ":Cannot allocate memory for ST\n");
+ return -ENOMEM;
+ }
+
+ dev_desc[2].rx_msg.rx_st.log_address = dma_alloc_coherent(NULL, 4, \
+ &dev_desc[2].rx_msg.rx_st.phys_address,
+ GFP_DMA | GFP_KERNEL);
+ if (dev_desc[2].rx_msg.rx_st.log_address == NULL) {
+ printk(KERN_ALERT NAME ":Failed to alloc memory\n");
+ BUG();
+ }
+
+ dev_desc[3].tx_msg.st = kmalloc(4, GFP_KERNEL | GFP_ATOMIC);
+ if (dev_desc[3].tx_msg.st == NULL) {
+ printk(KERN_ALERT NAME ":Cannot allocate memory for ST\n");
+ return -ENOMEM;
+ }
+
+ dev_desc[3].rx_msg.rx_st.log_address = dma_alloc_coherent(NULL, 4, \
+ &dev_desc[3].rx_msg.rx_st.phys_address, \
+ GFP_DMA | GFP_KERNEL);
+ if (dev_desc[3].rx_msg.rx_st.log_address == NULL) {
+ printk(KERN_ALERT NAME ":Failed to alloc memory\n");
+ BUG();
+ }
+
+ return err;
+}
+/**
+ * dlp_protocol_deinit() - HSI protocol Uninstall
+ *
+ * This function will close all the hsi channels opened earlier and
+ * unregisters HSI protocol driver client.
+ */
+int dlp_protocol_deinit(void)
+{
+ int no_ch;
+
+ for (no_ch = 0; no_ch < MAX_CHANNELS_MONITORED; no_ch++) {
+ hsi_close(dev_desc[no_ch].tx_dev);
+ kfree(dev_desc[no_ch].tx_msg.st);
+ }
+
+ unregister_hsi_driver(&ipc_driver);
+
+ printk(KERN_ALERT NAME ":unregister_hsi_driver done\n");
+ return 0;
+}
+
+
+static int do_modem_boot(void)
+{
+ int err = 0;
+ struct t_l1_desc *rx_params, *rx_params_audio;
+ u32 hsimode = 1;
+
+ rx_params = &dev_desc[0];
+ rx_params_audio = &dev_desc[1];
+
+ printk(KERN_ALERT "Trying to boot modem\n");
+
+
+ current_boot_state = MODEM_SSI_BOOT_INIT;
+ current_boot_state_audio = MODEM_SSI_BOOT_INIT;
+
+ host_request = BOOT_INFO_REQ;
+ hsimode = HSI_INTERRUPT_MODE;
+
+ printk(KERN_ALERT NAME ":Common: INIT->SYNC!\n");
+ hsi_ioctl(dev_desc[0].tx_dev, HSI_IOCTL_SET_CURRMODE, &hsimode);
+ err = hsi_write(dev_desc[0].tx_dev, &host_request, 32, 4);
+
+
+ hsi_ioctl(rx_params->rx_dev, HSI_IOCTL_SET_CURRMODE, &hsimode);
+ err = hsi_read(rx_params->rx_dev, &modem_response, 32, 4);
+
+ printk(KERN_ALERT NAME ":Audio: INIT->SYNC!\n");
+ err = hsi_write(dev_desc[1].tx_dev, &host_request, 32, 4);
+ err = hsi_read(rx_params_audio->rx_dev, &modem_response_audio, 32, 4);
+
+ return err;
+}
+
+
+
+
+/**
+ * dlp_protocol_start() - HSI Protocol Start
+ *
+ * This function starts HSI protocol by sending boot request on common
+ * control channel.
+ */
+int dlp_protocol_start(u8 l2_header)
+{
+ int err = 0;
+
+ sema_init(&dev_desc[3].tx_mutex, 1);
+ sema_init(&dev_desc[3].rx_mutex, 1);
+ sema_init(&dev_desc[2].tx_mutex, 1);
+ sema_init(&dev_desc[2].rx_mutex, 1);
+
+ *(dev_desc[3].tx_msg.st) = 0;
+ dev_desc[3].tx_msg.mapid = 0;
+ dev_desc[3].tx_msg.length = 0;
+ dev_desc[3].rx_msg.mapid = 0;
+ dev_desc[3].rx_msg.length = 0;
+
+ *(dev_desc[2].tx_msg.st) = 0;
+ dev_desc[2].tx_msg.mapid = 0;
+ dev_desc[2].tx_msg.length = 0;
+ dev_desc[2].rx_msg.mapid = 0;
+ dev_desc[2].rx_msg.length = 0;
+
+ /*delayed modem boot*/
+ do_modem_boot();
+
+ printk(KERN_ALERT NAME ":protocol started\n");
+ return err;
+}
+
+int dlp_protocol_stop(u8 l2_header)
+{
+ return 0;
+}
+
diff --git a/drivers/misc/msw/ipc_hsi_protocol.h b/drivers/misc/msw/ipc_hsi_protocol.h
new file mode 100644
index 00000000000..8f10d0df3cc
--- /dev/null
+++ b/drivers/misc/msw/ipc_hsi_protocol.h
@@ -0,0 +1,71 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright ST Ericsson, 2009. */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2.1 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
+/* See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*---------------------------------------------------------------------------*/
+
+#ifndef __MODEM_SSI_H_INCLUDED
+#define __MODEM_SSI_H_INCLUDED
+
+#define MAX_CHANNELS_MONITORED 4
+
+#define CHANNEL_COMMON_CONTROL 0
+#define CHANNEL_COMMON_DATA 3
+#define CHANNEL_AUDIO_CONTROL 1
+#define CHANNEL_AUDIO_DATA 2
+
+struct t_data_buf {
+ dma_addr_t phys_address;
+ u32 *log_address;
+};
+
+enum t_l1_tx_state {
+ L1_TX_FREE_STATE,
+ L1_TX_ST_SENDING_STATE,
+ L1_TX_ST_DONE_STATE,
+ L1_TX_BUSY_STATE
+};
+
+enum t_l1_rx_state {
+ L1_RX_FREE_STATE,
+ L1_RX_WAITING_ST_STATE,
+ L1_RX_ST_RECEIVED_STATE,
+ L1_RX_BUSY_STATE
+};
+
+struct t_l1_message {
+ u32 *st;
+ struct t_data_buf rx_st;
+ u8 mapid;
+ u32 length;
+ struct t_data_buf msgptr;
+};
+
+struct t_l1_desc {
+ struct t_l1_message tx_msg;
+ struct t_l1_message rx_msg;
+ enum t_l1_tx_state tx_state;
+ enum t_l1_rx_state rx_state;
+ struct semaphore tx_mutex;
+ struct semaphore rx_mutex;
+ struct hsi_device *tx_dev;
+ struct hsi_device *rx_dev;
+ struct completion tx_complete;
+};
+
+void dlp_ssi_boot_state(u8 event);
+void dlp_ssi_boot_state_audio(u8 event);
+u8 dlp_ssi_get_boot_state(void);
+
+#endif /*__MODEM_SSI_H_INCLUDED*/
+
diff --git a/drivers/misc/msw/ipc_protocol_if.h b/drivers/misc/msw/ipc_protocol_if.h
new file mode 100644
index 00000000000..4db6324bef3
--- /dev/null
+++ b/drivers/misc/msw/ipc_protocol_if.h
@@ -0,0 +1,36 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright ST Ericsson, 2009. */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2.1 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
+/* See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*---------------------------------------------------------------------------*/
+
+#ifndef __MODEM_HSI_IF_H
+#define __MODEM_HSI_IF_H
+
+enum t_mapping_identifier {
+ ISI_MESSAGING,
+ RPC_MESSAGING,
+ AUDIO_MESSAGING,
+ SEC_MESSAGING,
+ MAX_MAP_ID
+};
+
+int hsi_msg_send(void *p_data, u8 l2_msg_header, u32 length);
+int dlp_protocol_init(void);
+int dlp_protocol_deinit(void);
+int dlp_protocol_start(u8 l2_header);
+int dlp_protocol_stop(u8 l2_header);
+int l3alloc(u32 n_bytes, u8 l2_msg_header, void *addr);
+void l3receive(void *msg_ptr, u32 length, u8 l2_msg_header);
+
+#endif /*__MODEM_HSI_IF_H*/
diff --git a/drivers/misc/msw/isa_access.c b/drivers/misc/msw/isa_access.c
new file mode 100644
index 00000000000..a5b947a39cf
--- /dev/null
+++ b/drivers/misc/msw/isa_access.c
@@ -0,0 +1,986 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright ST Ericsson, 2009. */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2.1 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
+/* See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*---------------------------------------------------------------------------*/
+
+/** @file isa_access.c
+ * @brief This file contains character driver registrations, character driver
+ * interface to user space and buffer management.
+ *
+ */
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <linux/poll.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <mach/isa_ioctl.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include "ipc_protocol_if.h"
+#include "isa_access.h"
+
+#define ISA_ACCESS_DRIVER_DESC "isa_access"
+#define ISA_ACCESS_DRIVER_AUTHOR "ST_Ericsson"
+#define NAME "IPC_HSI"
+#define ISA_DEVICES 4
+#define CREATE_QUEUES_BOOT_TIME 1
+/**debug functionality*/
+#define ISA_DEBUG 1
+#define dbg_printk(format, arg...) (ISA_DEBUG & 1) ? \
+ (printk(KERN_ALERT NAME ": " format , ## arg)) : \
+ ({do {} while (0); })
+
+/**global data*/
+/**
+This variable is exported to user as module_param to specify
+major number at load time
+*/
+static int major;
+module_param(major, int, 0);
+MODULE_PARM_DESC(major, "Major device number");
+/**global fops mutex*/
+static DEFINE_MUTEX(isa_lock);
+/**global driver context pointer */
+struct t_isa_driver_context *p_isa_context_hsi;
+
+static inline int align_4byte(int len)
+{
+ return 4*((len+3)/4);
+}
+/**
+ * create_queue() - To create FIFO for Tx and Rx message buffering.
+ * @q: message queue.
+ * @n_bytes: queue size in bytes.
+ *
+ * This function creates a FIFO buffer of n_bytes size using
+ * dma_alloc_coherent(). It also initializes all queue handling
+ * locks, queue management pointers. It also initializes message list
+ * which occupies this queue.
+ *
+ * It return -ENOMEM in case of no memory.
+ */
+static int create_queue(struct t_message_queue *q, u32 n_bytes)
+{
+ q->log_address = dma_alloc_coherent(NULL, n_bytes, &q->phy_address, \
+ GFP_DMA|GFP_KERNEL);
+ if (q->log_address == NULL) {
+ printk(KERN_ALERT NAME ":Failed to alloc memory\n");
+ return -ENOMEM;
+ }
+ q->size = n_bytes;
+ q->available_size = q->size;
+ q->readptr = 0;
+ q->writeptr = 0;
+ q->no = 0;
+ spin_lock_init(&q->size_lock);
+ spin_lock_init(&q->read_lock);
+ spin_lock_init(&q->write_lock);
+ spin_lock_init(&q->update_lock);
+ sema_init(&q->tx_mutex, 1);
+ INIT_LIST_HEAD(&q->msg_list);
+ init_waitqueue_head(&q->wq_readable);
+ init_waitqueue_head(&q->wq_writable);
+ atomic_set(&q->q_wp, 1);
+ atomic_set(&q->q_rp, 0);
+ return 0;
+}
+/**
+ * delete_queue() - To delete FIFO and assiciated memory.
+ * @q: message queue
+ *
+ * This function deletes FIFO created using create_queue() function.
+ * It resets queue management pointers.
+ */
+static void delete_queue(struct t_message_queue *q)
+{
+ dma_free_coherent(NULL, q->size, q->log_address, q->phy_address);
+ q->size = 0;
+ q->available_size = 0;
+ q->readptr = 0;
+ q->writeptr = 0;
+}
+/**
+ * allocate_buffer() - To allocate memory inside FIFO
+ *
+ * @q: message queue
+ * @n_bytes: size in bytes
+ *
+ * This function tries to allocate n_bytes of size in FIFO q.
+ * It returns negative number when no memory can be allocated
+ * currently.
+ */
+static int allocate_buffer(struct t_message_queue *q, u32 n_bytes)
+{
+ int readptr, writeptr = -1;
+ int available_size;
+ unsigned long flag;
+
+ dbg_printk("allocate_buffer++\n");
+
+ if (q == NULL) {
+ printk(KERN_ALERT NAME ":q->NULL!\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&q->update_lock, flag);
+ readptr = q->readptr;
+ available_size = q->available_size;
+ spin_unlock_irqrestore(&q->update_lock, flag);
+
+ dbg_printk("curr readptr %d writeptr %d available size %d\n", readptr, \
+ q->writeptr, \
+ available_size);
+
+ if (q->writeptr == readptr) {
+ if (available_size == q->size) {
+ if (q->writeptr + n_bytes < q->size)
+ writeptr = q->writeptr;
+ else
+ writeptr = 0;
+ } else
+ atomic_set(&q->q_wp, 0);
+ } else {
+ if (q->writeptr < readptr) {
+ if (q->writeptr + n_bytes < readptr)
+ writeptr = q->writeptr;
+ else
+ atomic_set(&q->q_wp, 0);
+ } else {
+ if (q->writeptr + n_bytes < q->size)
+ writeptr = q->writeptr;
+ else {
+ if (n_bytes < readptr)
+ writeptr = 0;
+ else
+ atomic_set(&q->q_wp, 0);
+ }
+ }
+ }
+
+ dbg_printk("allocated buffer at offset %d of size %d!\n", \
+ writeptr, n_bytes);
+ dbg_printk("allocate_buffer--\n");
+ return writeptr;
+}
+/**
+ * update_queue() - To update FIFO message list and available size.
+ *
+ * @q: message queue
+ * @op_type: update type (operation completion type)
+ * @size: size in bytes
+ *
+ * This function updates message list associated with message queue q and also
+ * updates available size of FIFO.
+ * If op_type is READ_COMPLETE, then, message is deleted from the list and
+ * available size is increased by size of message. If the message list is empty,
+ * then, event is generated for waiting process to indicate memory availability
+ * inside queue.
+ * If op_type is WRITE_COMPLETE, then, message is added to the list and
+ * available size is reduced by message size. If the message list is empty then,
+ * event is generated for waiting process to indicate new message availability
+ * inside queue.
+ * The message list is FIFO style and message is always added to tail and
+ * removed from
+ * head.
+ */
+static void update_queue(struct t_message_queue *q, \
+ enum t_queue_operation op_type, \
+ u32 size)
+{
+ struct t_queue_element *new_msg = NULL, *old_msg = NULL;
+ struct list_head *msg;
+ dbg_printk("update_queue++\n");
+
+ if (op_type == READ_COMPLETE) {
+ dbg_printk("READ_COMPLETE\n");
+ list_for_each(msg, &q->msg_list) {
+ old_msg = list_entry(msg, \
+ struct t_queue_element, entry);
+ if (old_msg == NULL) {
+ printk(KERN_ALERT NAME ":no message found\n");
+ /*while (1);*/
+ BUG();
+ }
+
+ break;
+ }
+ list_del(msg);
+
+ if (old_msg != NULL) {
+ /** to keep dma buffer alignment */
+ size = align_4byte(old_msg->size);
+ q->readptr = old_msg->offset + size;
+ q->available_size = q->available_size + size;
+ }
+
+ if (q->direction == 0) {
+ if (list_empty(&q->msg_list))
+ atomic_set(&q->q_rp, 0);
+ } else {
+ if (atomic_read(&q->q_wp) == 0) {
+ atomic_set(&q->q_wp, 1);
+ wake_up_interruptible(&q->wq_writable);
+ }
+ }
+ dbg_printk("%s:msg_deleted %d:%d:%d\n", \
+ (q->direction == 1) ? "UL" : "DL", old_msg->no, \
+ old_msg->offset, \
+ old_msg->size);
+ dbg_printk("%s:updating readptr to %d\n", \
+ (q->direction == 1) ? "UL" : "DL", q->readptr);
+ if (old_msg != NULL)
+ kfree(old_msg);
+ }
+
+ if (op_type == WRITE_COMPLETE) {
+ dbg_printk("WRITE_COMPLETE\n");
+ new_msg = kmalloc(sizeof(struct t_queue_element), \
+ GFP_KERNEL|GFP_ATOMIC);
+ if (new_msg == NULL) {
+ printk(KERN_ALERT NAME ":memory overflow\n");
+ /*while (1);*/
+ BUG();
+ }
+
+ new_msg->offset = q->writeptr;
+ new_msg->size = size;
+ new_msg->no = q->no++;
+
+ dbg_printk("%s:msg_added %d:%d:%d\n", \
+ (q->direction == 1) ? "UL" : "DL", new_msg->no, \
+ new_msg->offset, \
+ new_msg->size);
+ /** alignment needed to keep 4-byte boundry of dma buffer */
+ size = align_4byte(size);
+
+ q->writeptr = q->writeptr + size;
+ q->available_size = q->available_size - size;
+
+ if (list_empty(&q->msg_list)) {
+ list_add_tail(&new_msg->entry, &q->msg_list);
+ if (q->direction == 0) {
+ atomic_set(&q->q_rp, 1);
+ wake_up_interruptible(&q->wq_readable);
+ }
+ } else {
+ list_add_tail(&new_msg->entry, &q->msg_list);
+ }
+ }
+ dbg_printk("update_queue--\n");
+}
+/**
+ * get_new_msg() - retrieve new message from message list
+ *
+ * @q: message queue
+ * @msg: message element in list
+ *
+ * This function will retrieve most recent message from the corresponding
+ * queue list. New message is always retrieved from head side.
+ * It returns new message no, offset if FIFO and size.
+ */
+static int get_new_msg(struct t_message_queue *q, struct t_dlp_message *msg)
+{
+ struct t_queue_element *new_msg = NULL;
+ struct list_head *msg_list;
+ unsigned long flag;
+
+ dbg_printk("get_new_message++\n");
+
+ spin_lock_irqsave(&q->update_lock, flag);
+ list_for_each(msg_list, &q->msg_list) {
+ new_msg = list_entry(msg_list, struct t_queue_element, entry);
+ if (new_msg == NULL) {
+ spin_unlock_irqrestore(&q->update_lock, flag);
+ printk(KERN_ALERT NAME ":no message found\n");
+ return -1;
+ }
+ break;
+ }
+ spin_unlock_irqrestore(&q->update_lock, flag);
+
+ msg->offset = new_msg->offset;
+ msg->size = new_msg->size;
+
+ dbg_printk("%s:Message No :%d\n", (q->direction == 1) ? "UL" : "DL", \
+ new_msg->no);
+ dbg_printk("%s:Offset :%d Size :%d\n", \
+ (q->direction == 1) ? "UL" : "DL", \
+ msg->offset, \
+ msg->size);
+ dbg_printk("get_new_message--\n");
+ if (msg->size > 0)
+ return 0;
+ else
+ return -1;
+}
+/**
+ * get_queue_address() - To get logical and physical address from offset
+ *
+ * @q: message queue
+ * @ptr: message pointer pointer
+ * @offset: message offset
+ *
+ * This function returns logical and physical address corresponding to
+ * given offset in queue.
+ */
+static void get_queue_address(struct t_message_queue *q, void *ptr, u32 offset)
+{
+ struct t_data_buf *addr;
+ addr = (struct t_data_buf *)ptr;
+ addr->log_address = q->log_address + offset;
+ addr->phys_address = q->phy_address + offset;
+}
+/**
+ * l3alloc() - Memory allocation callback
+ *
+ * @n_bytes: Required size in bytes
+ * @l2_msg_header: L2 Message Header
+ * @addr: address of allocated memory
+ *
+ * This function allocates required memory in bytes and return corresponding
+ * memory address.
+ */
+int l3alloc(u32 n_bytes, u8 l2_msg_header, void *addr)
+{
+ int offset;
+ unsigned long flag;
+ struct t_message_queue *q;
+ struct t_isadev_context *l3dev;
+
+ l3dev = p_isa_context_hsi->p_isadev[l2_msg_header];
+ q = &l3dev->dl_queue;
+
+ offset = allocate_buffer(q, align_4byte(n_bytes));
+ if (offset < 0) {
+ printk(KERN_ALERT ":%s:Waiting for WP\n", \
+ (q->direction == 1) ? "UL" : "DL");
+ printk(KERN_ALERT "Error:Buffer Full\n");
+ /*while (1)*/
+ BUG();
+ }
+
+ get_queue_address(q, addr, offset);
+ spin_lock_irqsave(&q->update_lock, flag);
+ q->writeptr = offset;
+ spin_unlock_irqrestore(&q->update_lock, flag);
+
+ return 0;
+}
+EXPORT_SYMBOL(l3alloc);
+
+/**
+ * sec_receive() - Rx Completion callback
+ *
+ * @p_data: message pointer
+ * @n_bytes: message size
+ *
+ * This function is a callback to indicate SEC message reception is complete.
+ * It calls update_queue() to update the message list to indicate arrival
+ * of new message.
+ */
+static void sec_receive(void *p_data, u32 n_bytes)
+{
+ struct t_message_queue *q;
+ unsigned long flag;
+ struct t_isadev_context *secdev = p_isa_context_hsi->p_isadev[3];
+ q = &secdev->dl_queue;
+ dbg_printk("rpc_receive++\n");
+ spin_lock_irqsave(&q->update_lock, flag);
+ update_queue(q, WRITE_COMPLETE, n_bytes);
+ spin_unlock_irqrestore(&q->update_lock, flag);
+ dbg_printk("rpc_receive--\n");
+}
+/**
+ * rpc_receive() - Rx Completion callback
+ *
+ * @p_data: message pointer
+ * @n_bytes: message size
+ *
+ * This function is a callback to indicate RPC message reception is complete.
+ * It calls update_queue() to update the message list to indicate arrival
+ * of new message.
+ */
+static void rpc_receive(void *p_data, u32 n_bytes)
+{
+ struct t_message_queue *q;
+ unsigned long flag;
+ struct t_isadev_context *rpcdev = p_isa_context_hsi->p_isadev[1];
+ q = &rpcdev->dl_queue;
+ dbg_printk("rpc_receive++\n");
+ spin_lock_irqsave(&q->update_lock, flag);
+ update_queue(q, WRITE_COMPLETE, n_bytes);
+ spin_unlock_irqrestore(&q->update_lock, flag);
+ dbg_printk("rpc_receive--\n");
+}
+/**
+ * isi_receive() - Rx Completion callback
+ *
+ * @p_data: message pointer
+ * @n_bytes: message size
+ *
+ * This function is a callback to indicate ISI message reception is complete.
+ * It calls update_queue() to update the message list to indicate arrival
+ * of new message.
+ */
+static void isi_receive(void *p_data, u32 n_bytes)
+{
+ struct t_message_queue *q;
+ unsigned long flag;
+ struct t_isadev_context *isidev = p_isa_context_hsi->p_isadev[0];
+ dbg_printk("isi_receive++\n");
+ q = &isidev->dl_queue;
+ spin_lock_irqsave(&q->update_lock, flag);
+ update_queue(q, WRITE_COMPLETE, n_bytes);
+ spin_unlock_irqrestore(&q->update_lock, flag);
+ dbg_printk("isi_receive--\n");
+}
+
+/**
+ * audio_receive() - Rx Completion callback
+ *
+ * @p_data: message pointer
+ * @n_bytes: message size
+ *
+ * This function is a callback to indicate ISI message reception is complete.
+ * It calls update_queue() to update the message list to indicate arrival
+ * of new message.
+ */
+static void audio_receive(void *p_data, u32 n_bytes)
+{
+ struct t_message_queue *q;
+ unsigned long flag;
+ struct t_isadev_context *audiodev = p_isa_context_hsi->p_isadev[2];
+ dbg_printk("isi_receive++\n");
+ q = &audiodev->dl_queue;
+ spin_lock_irqsave(&q->update_lock, flag);
+ update_queue(q, WRITE_COMPLETE, n_bytes);
+ spin_unlock_irqrestore(&q->update_lock, flag);
+ dbg_printk("isi_receive--\n");
+}
+
+/**
+ * l3receive() - Rx Completion callback
+ *
+ * @msg_ptr: message pointer
+ * @length: message size
+ * @l2_msg_header: L2 message header
+ *
+ * This function is a callback to indicate RPC message reception is complete.
+ * It calls update_queue() to update the message list to indicate arrival
+ * of new message.
+ */
+void l3receive(void *msg_ptr, u32 length, u8 l2_msg_header)
+{
+ struct t_isadev_context *l3dev;
+
+ l3dev = p_isa_context_hsi->p_isadev[l2_msg_header];
+
+ if (l3dev->device_id == 0)
+ isi_receive(msg_ptr, length);
+ if (l3dev->device_id == 1)
+ rpc_receive(msg_ptr, length);
+ if (l3dev->device_id == 2)
+ audio_receive(msg_ptr, length);
+ if (l3dev->device_id == 3)
+ sec_receive(msg_ptr, length);
+
+
+}
+EXPORT_SYMBOL(l3receive);
+/**
+ * isa_select() - Select Interface
+ *
+ * @filp: file descriptor pointer
+ * @wait: poll_table_struct pointer
+ *
+ * This function is used to perform non-blocking read operations. It allows
+ * a process to determine whether it can read from one or more open files
+ * without blocking. These calls can also block a process until any of a
+ * given set of file descriptors becomes available for reading.
+ * If a file is ready to read, POLLIN | POLLRDNORM bitmask is returned.
+ * The driver method is called whenever the user-space program performs a
+ * select system call involving a file descriptor associated with the driver.
+ */
+static unsigned int isa_select(struct file *filp, \
+ struct poll_table_struct *wait)
+{
+ struct t_isadev_context *p_isadev;
+ struct t_message_queue *q;
+ unsigned int mask = 0;
+ u32 m = iminor(filp->f_path.dentry->d_inode);
+ dbg_printk("isa_select++\n");
+ p_isadev = (struct t_isadev_context *)filp->private_data;
+
+ if (p_isadev->device_id != m)
+ return -1;
+
+ q = &p_isadev->dl_queue;
+
+ poll_wait(filp, &q->wq_readable, wait);
+
+ if (atomic_read(&q->q_rp) == 1)
+ mask = POLLIN | POLLRDNORM;
+
+ dbg_printk("isa_select--\n");
+ return mask;
+}
+/**
+ * isa_ioctl() - To handle different ioctl commands supported by driver.
+ *
+ * @inode: structure is used by the kernel internally to represent files
+ * @filp: file descriptor pointer
+ * @cmd: ioctl command
+ * @arg: input param
+ *
+ * IOCTL support removed. Use read/write instead.
+ */
+static int isa_ioctl(struct inode *inode, struct file *filp,
+ unsigned cmd, unsigned long arg)
+{
+ int err = 0;
+
+ switch (cmd) {
+ /** DLP_IOC_ALLOCATE_BUFFER - allocate uplink buffer */
+ case DLP_IOC_ALLOCATE_BUFFER: {
+ dbg_printk(" DLP_IOC_ALLOCATE_BUFFER++\n");
+ dbg_printk(" DLP_IOC_ALLOCATE_BUFFER--\n");
+ break;
+ }
+ /** DLP_IOC_PUT_MESSAGE - This ioctl is used to signal
+ that message is copied to the uplink buffer and ready for
+ transmission. */
+ case DLP_IOC_PUT_MESSAGE: {
+ dbg_printk(" DLP_IOC_PUT_MESSAGE++\n");
+ dbg_printk(" DLP_IOC_PUT_MESSAGE--\n");
+ break;
+ }
+ /** DLP_IOC_GET_MESSAGE - This ioctl is used to poll
+ any downlink message */
+ case DLP_IOC_GET_MESSAGE: {
+ dbg_printk(" DLP_IOC_GET_MESSAGE++\n");
+ dbg_printk(" DLP_IOC_GET_MESSAGE--\n");
+ break;
+ }
+ /** DLP_IOC_DEALLOCATE_BUFFER- This ioctl is used to \
+ deallocate buffer reserved for received downlink message */
+ case DLP_IOC_DEALLOCATE_BUFFER: {
+ dbg_printk(" DLP_IOC_DEALLOCATE_BUFFER++\n");
+ dbg_printk(" DLP_IOC_DEALLOCATE_BUFFER--\n");
+ break;
+ }
+ default: {
+ dbg_printk("Unknown IOCTL\n");
+ err = -1;
+ break;
+ }
+ };
+ return err;
+}
+/**
+ * isa_mmap() - Maps kernel queue memory to user space.
+ *
+ * @filp: file descriptor pointer
+ * @vma: virtual area memory structure.
+ *
+ * This function maps kernel FIFO into user space. This function
+ * shall be called twice to map both uplink and downlink buffers.
+ */
+static int isa_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct t_isadev_context *p_isadev;
+ int err = 0;
+ u8 direction;
+ u32 m = iminor(filp->f_path.dentry->d_inode);
+ dbg_printk("isa_mmap %d++\n", m);
+
+ p_isadev = (struct t_isadev_context *)filp->private_data;
+ direction = vma->vm_pgoff;
+ vma->vm_pgoff = 0;
+
+ switch (direction) {
+ case MMAP_DLQUEUE: {
+ dbg_printk(" MMAP_DLQUEUE\n");
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ if (remap_pfn_range(vma, vma->vm_start, \
+ p_isadev->dl_queue.phy_address >> PAGE_SHIFT,\
+ vma->vm_end-vma->vm_start, \
+ vma->vm_page_prot)) {
+ err = -EAGAIN;
+ }
+ }
+ break;
+ case MMAP_ULQUEUE: {
+ dbg_printk(" MMAP_ULQUEUE\n");
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ if (remap_pfn_range(vma, vma->vm_start, \
+ p_isadev->ul_queue.phy_address >> PAGE_SHIFT,
+ vma->vm_end-vma->vm_start, \
+ vma->vm_page_prot)) {
+ err = -EAGAIN;
+ }
+ }
+ break;
+ default: {
+ printk(KERN_ALERT NAME ": unknown mmap called\n");
+ err = -EAGAIN;
+ }
+ };
+ dbg_printk(" isa_mmap--\n");
+ return err;
+}
+/**
+ * isa_read() - Read from device
+ *
+ * @filp: file descriptor
+ * @buf: user buffer pointer
+ * @len: size of requested data transfer
+ * @ppos: not used
+ *
+ * This function is called whenever user calls read() system call.
+ * It reads a oldest message from queue and copies it into user buffer and
+ * returns its size.
+ * If there is no message present in queue, then it blocks until new data is
+ * available.
+ */
+static ssize_t isa_read(struct file *filp, char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ int err = 0;
+ struct t_isadev_context *p_isadev;
+ struct t_message_queue *q;
+ struct t_dlp_message message;
+ void *addr;
+ u32 size;
+ unsigned long flag;
+ dbg_printk("isa_read++\n");
+
+ if (len <= 0 || buf == NULL)
+ return -EFAULT;
+
+ p_isadev = (struct t_isadev_context *)filp->private_data;
+ q = &p_isadev->dl_queue;
+
+ spin_lock_irqsave(&q->update_lock, flag);
+ if (list_empty(&q->msg_list)) {
+ spin_unlock_irqrestore(&q->update_lock, flag);
+ dbg_printk("%s:Waiting for RP\n", \
+ (q->direction == 1) ? "UL" : "DL");
+ if (wait_event_interruptible(q->wq_readable, \
+ atomic_read(&q->q_rp) == 1)) {
+ return -ERESTARTSYS;
+ }
+ } else
+ spin_unlock_irqrestore(&q->update_lock, flag);
+
+ err = get_new_msg(q, &message);
+ if (err < 0) {
+ printk(KERN_ALERT "get_new_msg Failed\n");
+ return -EAGAIN;
+ }
+ size = message.size;
+ addr = q->log_address + message.offset;
+
+ if (copy_to_user(buf, addr, size)) {
+ printk(KERN_ALERT NAME ":copy_to_user failed\n");
+ return -EFAULT;
+ }
+ spin_lock_irqsave(&q->update_lock, flag);
+ update_queue(q, READ_COMPLETE, message.size);
+ spin_unlock_irqrestore(&q->update_lock, flag);
+ dbg_printk("isa_read-- %d\n", size);
+ return size;
+}
+/**
+ * isa_write() - Write to device
+ *
+ * @filp: file descriptor
+ * @buf: user buffer pointer
+ * @len: size of requested data transfer
+ * @ppos: not used
+ *
+ * This function is called whenever user calls write() system call.
+ * It checks if there is space available in queue, and copies the message
+ * inside queue. If there is no space, it blocks until space becomes available.
+ * It also schedules transfer thread to transmit the newly added message.
+ */
+static ssize_t isa_write(struct file *filp, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ struct t_isadev_context *p_isadev;
+ struct t_message_queue *q;
+ int err = 0;
+ struct t_data_buf addr;
+
+ dbg_printk("isa_write++\n");
+
+ if (len <= 0 || (len > 8*1024))
+ return -EFAULT;
+
+ p_isadev = (struct t_isadev_context *)filp->private_data;
+ q = &p_isadev->ul_queue;
+ dbg_printk("%s\n", (p_isadev->device_id == 0) ? "ISI" : "RPC");
+
+ down(&q->tx_mutex);
+
+ /** protection when close happens*/
+ if (atomic_dec_and_test(&p_isa_context_hsi->isOpen[p_isadev->device_id]))
+ return -EFAULT;
+
+ if (copy_from_user((void *)(q->log_address), buf, len)) {
+ printk(KERN_ALERT NAME ":copy_from_user failed\n");
+ up(&q->tx_mutex);
+ return -EFAULT;
+ }
+
+ addr.log_address = q->log_address;
+ addr.phys_address = q->phy_address;
+
+ err = hsi_msg_send((void *)&addr, p_isadev->device_id, \
+ align_4byte(len));
+ if (err < 0)
+ return err;
+
+ dbg_printk("isa_write--\n");
+ up(&q->tx_mutex);
+ return len;
+}
+/**
+ * isa_close() - Close device file
+ *
+ * @inode: structure is used by the kernel internally to represent files
+ * @filp: device file descriptor
+ *
+ * This function deletes structues associated with this file, deletes
+ * queues, flushes and destroys workqueus and closes this file.
+ * It also unregisters itself from l2mux driver.
+ */
+static int isa_close(struct inode *inode, struct file *filp)
+{
+ struct t_isadev_context *p_isadev;
+ u8 m;
+ struct t_message_queue *q;
+ mutex_lock(&isa_lock);
+ m = iminor(filp->f_path.dentry->d_inode);
+ dbg_printk("isa_close %d", m);
+
+ if (atomic_dec_and_test(&p_isa_context_hsi->isOpen[m])) {
+ atomic_inc(&p_isa_context_hsi->isOpen[m]);
+ printk(KERN_ALERT NAME ":Device not opened yet\n");
+ mutex_unlock(&isa_lock);
+ return -ENODEV;
+ }
+ atomic_set(&p_isa_context_hsi->isOpen[m], 1);
+
+ p_isadev = (struct t_isadev_context *)filp->private_data;
+ dbg_printk("p_isadev->device_id %d", p_isadev->device_id);
+ q = &p_isadev->ul_queue;
+ /**unblock any write thread*/
+ up(&q->tx_mutex);
+
+ dbg_printk("Closed %d device\n", m);
+ mutex_unlock(&isa_lock);
+ return 0;
+}
+/**
+ * isa_open() - Open device file
+ *
+ * @inode: structure is used by the kernel internally to represent files
+ * @filp: device file descriptor
+ *
+ * This function performs initialization tasks needed to open HSI channel.
+ * Following tasks are performed.
+ * -return if device is already opened
+ * -create uplink FIFO
+ * -create downlink FIFO
+ * -init delayed workqueue thread
+ * -register to l2mux driver
+ */
+static int isa_open(struct inode *inode, struct file *filp)
+{
+ int err = 0;
+ u8 m;
+ struct t_isadev_context *p_isadev;
+ dbg_printk("isa_open++\n");
+
+ mutex_lock(&isa_lock);
+ m = iminor(inode);
+
+ if ((m != ISI_MESSAGING) && \
+ (m != RPC_MESSAGING) && \
+ (m != AUDIO_MESSAGING) && \
+ (m != SEC_MESSAGING)) {
+ printk(KERN_ALERT NAME ":No such device present\n");
+ mutex_unlock(&isa_lock);
+ return -ENODEV;
+ }
+ if (!atomic_dec_and_test(&p_isa_context_hsi->isOpen[m])) {
+ atomic_inc(&p_isa_context_hsi->isOpen[m]);
+ printk(KERN_ALERT NAME ":Device already opened\n");
+ mutex_unlock(&isa_lock);
+ return -EBUSY;
+ }
+
+ p_isadev = p_isa_context_hsi->p_isadev[m];
+ filp->private_data = p_isadev;
+
+ mutex_unlock(&isa_lock);
+ dbg_printk("isa_open--\n");
+ return err;
+}
+
+const struct file_operations hsi_fops = { \
+ .owner = THIS_MODULE,
+ .open = isa_open,
+ .release = isa_close,
+ .ioctl = isa_ioctl,
+ .mmap = isa_mmap,
+ .read = isa_read,
+ .write = isa_write,
+ .poll = isa_select,
+};
+/**
+ * isa_init() - module insertion function
+ *
+ * This function registers module as a character driver using
+ * register_chrdev_region()
+ * or alloc_chrdev_region. It adds this driver to system using cdev_add() call.
+ * Major number is dynamically allocated using alloc_chrdev_region()
+ * by default or left to user to specify it during load time.
+ * For this variable major is used as module_param
+ *
+ * Nodes to be created using
+ * mknod /dev/isi c $major 0
+ * mknod /dev/rpc c $major 1
+ * mknod /dev/audio c $major 2
+ * mknod /dev/secure c $major 3
+ */
+static int __init isa_init(void)
+{
+ int err = 0;
+ dev_t dev_id;
+ int retval, no_dev;
+ struct t_isadev_context *p_isadev;
+
+ p_isa_context_hsi = kzalloc(sizeof(struct t_isa_driver_context), \
+ GFP_KERNEL);
+ if (p_isa_context_hsi == NULL) {
+ printk(KERN_ALERT NAME ":Failed to alloc memory\n");
+ return -ENOMEM;
+ }
+
+ if (major) {
+ dev_id = MKDEV(major, 0);
+ retval = register_chrdev_region(dev_id, ISA_DEVICES, NAME);
+ } else {
+ retval = alloc_chrdev_region(&dev_id, 0, ISA_DEVICES, NAME);
+ major = MAJOR(dev_id);
+ }
+
+ printk(KERN_ALERT NAME ": major %d\n", major);
+
+ cdev_init(&p_isa_context_hsi->cdev, &hsi_fops);
+ p_isa_context_hsi->cdev.owner = THIS_MODULE;
+ retval = cdev_add(&p_isa_context_hsi->cdev, dev_id, ISA_DEVICES);
+ if (retval) {
+ printk(KERN_ALERT NAME ":Failed to add char device\n");
+ return retval;
+ }
+
+ for (no_dev = 0; no_dev < ISA_DEVICES; no_dev++)
+ atomic_set(&p_isa_context_hsi->isOpen[no_dev], 1);
+
+ for (no_dev = 0; no_dev < ISA_DEVICES; no_dev++) {
+
+ p_isadev = kzalloc(sizeof(struct t_isadev_context), GFP_KERNEL);
+ if (p_isadev == NULL) {
+ printk(KERN_ALERT NAME ":Failed to alloc memory\n");
+ return -ENOMEM;
+ }
+
+ p_isadev->device_id = no_dev;
+
+ retval = create_queue(&p_isadev->ul_queue, 8*1024);
+ if (retval < 0) {
+ printk(KERN_ALERT NAME ":create_queue ul_q failed\n");
+ kfree(p_isadev);
+ return retval;
+ }
+ p_isadev->ul_queue.direction = 1;
+
+ retval = create_queue(&p_isadev->dl_queue, COMMON_BUFFER_SIZE);
+ if (retval < 0) {
+ printk(KERN_ALERT NAME ":create_queue dl_q failed\n");
+ delete_queue(&p_isadev->ul_queue);
+ kfree(p_isadev);
+ return retval;
+ }
+ p_isadev->dl_queue.direction = 0;
+
+ p_isa_context_hsi->p_isadev[p_isadev->device_id] = p_isadev;
+ }
+
+ err = dlp_protocol_init();
+ if (err < 0)
+ return err;
+
+ /** protocol start*/
+ dlp_protocol_start(0);
+
+ printk(KERN_ALERT NAME ": Driver added\n");
+
+ return retval;
+}
+/**
+ * isa_exit() - module removal function
+ *
+ * This function removes this driver from system.
+ */
+static void __exit isa_exit(void)
+{
+ int no_dev;
+ struct t_isadev_context *p_isadev;
+ dev_t dev_id = MKDEV(major, 0);
+
+ for (no_dev = 0; no_dev < ISA_DEVICES; no_dev++) {
+ p_isadev = p_isa_context_hsi->p_isadev[no_dev];
+ delete_queue(&p_isadev->ul_queue);
+ delete_queue(&p_isadev->dl_queue);
+ kfree(p_isadev);
+ }
+
+ cdev_del(&p_isa_context_hsi->cdev);
+ unregister_chrdev_region(dev_id, ISA_DEVICES);
+ kfree(p_isa_context_hsi);
+
+ printk(KERN_ALERT NAME ": Driver removed\n");
+}
+
+module_init(isa_init);
+module_exit(isa_exit);
+
+MODULE_AUTHOR(ISA_ACCESS_DRIVER_AUTHOR);
+MODULE_DESCRIPTION(ISA_ACCESS_DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/msw/isa_access.h b/drivers/misc/msw/isa_access.h
new file mode 100644
index 00000000000..41ea05ad3bf
--- /dev/null
+++ b/drivers/misc/msw/isa_access.h
@@ -0,0 +1,79 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright ST Ericsson, 2009. */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2.1 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
+/* See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*---------------------------------------------------------------------------*/
+
+/** @file isa_access.h
+ * @brief This file contains data structures for ISA access driver.
+ *
+ */
+#ifndef __MODEM_ISA_H
+#define __MODEM_ISA_H
+
+struct t_data_buf {
+ dma_addr_t phys_address;
+ u32 *log_address;
+};
+
+struct t_queue_element {
+ struct list_head entry;
+ u32 offset;
+ u32 size;
+ u32 no;
+};
+
+struct t_message_queue {
+ void *log_address;
+ dma_addr_t phy_address;
+ u32 size;
+ u32 available_size;
+ u32 readptr;
+ u32 writeptr;
+ u32 no;
+ u8 direction;
+ spinlock_t read_lock;
+ spinlock_t write_lock;
+ spinlock_t size_lock;
+ spinlock_t update_lock;
+ struct semaphore tx_mutex;
+ atomic_t q_rp;
+ atomic_t q_wp;
+ wait_queue_head_t wq_readable;
+ wait_queue_head_t wq_writable;
+ struct list_head msg_list;
+};
+
+struct t_isadev_context {
+ struct t_message_queue ul_queue;
+ struct t_message_queue dl_queue;
+ struct delayed_work work;
+ struct workqueue_struct *work_queue;
+ u8 device_id;
+};
+
+struct t_isa_driver_context {
+ u8 modemState;
+ u8 linkState;
+ atomic_t isOpen[4];
+ struct t_isadev_context *p_isadev[4];
+ struct cdev cdev;/* Char device structure */
+ spinlock_t op_lock;
+};
+
+enum t_queue_operation {
+ READ_COMPLETE,
+ WRITE_COMPLETE
+};
+
+#endif/*__MODEM_ISA_H*/
diff --git a/drivers/misc/shrm/Kconfig b/drivers/misc/shrm/Kconfig
new file mode 100644
index 00000000000..d2052671572
--- /dev/null
+++ b/drivers/misc/shrm/Kconfig
@@ -0,0 +1,49 @@
+#
+# SHM HW kernel configuration
+#
+config U8500_SHRM
+ tristate "U8500 SHRM hardware driver"
+ depends on ARCH_U8500
+ default Y
+ ---help---
+ If you say Y here, you will enable the STN8500 SHM hardware driver.
+
+ If unsure, say N.
+choice
+ prompt "Modem Image Version"
+ depends on U8500_SHRM
+ default SHRM_V1_UPDATES_VERSION
+
+ config SHRM_ED_V1_VERSION
+ depends on U8500_SHRM
+ bool "SHRM ED / V1 "
+ help
+ Modem Images with ED/V1 updates
+
+ config SHRM_V1_UPDATES_VERSION
+ depends on U8500_SHRM
+ bool "SHRM V1 UPDATES"
+ help
+ Modem Images with V1 Updates
+
+endchoice
+
+config U8500_SHRM_LOOP_BACK
+ tristate "U8500 SHRM loopback"
+ depends on U8500_SHRM
+ default n
+ ---help---
+ If you say Y here, you will enable the shm loopback
+
+ If unsure, say N.
+
+config U8500_SHRM_MODEM_SILENT_RESET
+ bool "U8500 SHRM Modem Silent Reset"
+ depends on U8500_SHRM
+ default n
+ ---help---
+ If you say Y here, you will enable the modem silent reset feature
+
+ If unsure, say N.
+
+
diff --git a/drivers/misc/shrm/Makefile b/drivers/misc/shrm/Makefile
new file mode 100644
index 00000000000..8115c24920b
--- /dev/null
+++ b/drivers/misc/shrm/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for SHRM drivers
+#
+
+ifdef CONFIG_PHONET
+u8500_shrm-objs := modem_shrm_driver.o shrm_fifo.o shrm_protocol.o
+else
+u8500_shrm-objs := shrm_driver.o shrm_fifo.o shrm_protocol.o
+endif
+
+obj-$(CONFIG_U8500_SHRM) += u8500_shrm.o
diff --git a/drivers/misc/shrm/modem_shrm_driver.c b/drivers/misc/shrm/modem_shrm_driver.c
new file mode 100644
index 00000000000..9fe50acf22d
--- /dev/null
+++ b/drivers/misc/shrm/modem_shrm_driver.c
@@ -0,0 +1,668 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> for ST-Ericsson
+ * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/smp_lock.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/io.h>
+
+#include <mach/isa_ioctl.h>
+#include <mach/shrm_driver.h>
+#include <mach/shrm_private.h>
+#include <mach/shrm_config.h>
+#include <mach/shrm_net.h>
+#include <mach/shrm.h>
+
+#include <linux/skbuff.h>
+#ifdef CONFIG_HIGH_RES_TIMERS
+#include <linux/hrtimer.h>
+static struct hrtimer timer;
+#endif
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/phonet.h>
+
+/* debug functionality */
+#define ISA_DEBUG 0
+
+#define PHONET_TASKLET
+#define MAX_RCV_LEN 2048
+static u8 ph_recv_buf[MAX_RCV_LEN];
+
+void do_phonet_rcv_tasklet(unsigned long unused);
+struct tasklet_struct phonet_rcv_tasklet;
+
+/**
+ * audio_receive() - Receive audio channel completion callback
+ * @shrm: pointer to shrm device information structure
+ * @data: message pointer
+ * @n_bytes: message size
+ * @l2_header: L2 header/device ID 2->audio, 5->audio_loopback
+ *
+ * This fucntion is called from the audio receive handler. Copies the audio
+ * message from the FIFO to the AUDIO queue. The message is later copied from
+ * this queue to the user buffer through the char or net interface read
+ * operation.
+ */
+static int audio_receive(struct shrm_dev *shrm, void *data,
+ u32 n_bytes, u8 l2_header)
+{
+ u32 size = 0;
+ int ret = 0;
+ int idx;
+ u8 *psrc;
+ struct message_queue *q;
+ struct isadev_context *audiodev;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+ idx = shrm_get_cdev_index(l2_header);
+ if (idx < 0) {
+ dev_err(shrm->dev, "failed to get index\n");
+ return idx;
+ }
+ audiodev = &shrm->isa_context->isadev[idx];
+ q = &audiodev->dl_queue;
+ spin_lock(&q->update_lock);
+ /* Memcopy RX data first */
+ if ((q->writeptr+n_bytes) >= q->size) {
+ psrc = (u8 *)data;
+ size = (q->size-q->writeptr);
+ /* Copy First Part of msg */
+ memcpy((q->fifo_base+q->writeptr), psrc, size);
+ psrc += size;
+ /* Copy Second Part of msg at the top of fifo */
+ memcpy(q->fifo_base, psrc, (n_bytes-size));
+ } else {
+ memcpy((q->fifo_base+q->writeptr), data, n_bytes);
+ }
+ ret = add_msg_to_queue(q, n_bytes);
+ spin_unlock(&q->update_lock);
+ if (ret < 0)
+ dev_err(shrm->dev, "Adding a msg to message queue failed");
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return ret;
+}
+
+/**
+ * common_receive() - Receive common channel completion callback
+ * @shrm: pointer to the shrm device information structure
+ * @data: message pointer
+ * @n_bytes: message size
+ * @l2_header: L2 header / device ID
+ *
+ * This function is called from the receive handler to copy the respective
+ * ISI, RPC, SECURITY message to its respective queue. The message is then
+ * copied from queue to the user buffer on char net interface read operation.
+ */
+static int common_receive(struct shrm_dev *shrm, void *data,
+ u32 n_bytes, u8 l2_header)
+{
+ u32 size = 0;
+ int ret = 0;
+ int idx;
+ u8 *psrc;
+ struct message_queue *q;
+ struct isadev_context *isa_dev;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+ idx = shrm_get_cdev_index(l2_header);
+ if (idx < 0) {
+ dev_err(shrm->dev, "failed to get index\n");
+ return idx;
+ }
+ isa_dev = &shrm->isa_context->isadev[idx];
+ q = &isa_dev->dl_queue;
+ spin_lock(&q->update_lock);
+ /* Memcopy RX data first */
+ if ((q->writeptr+n_bytes) >= q->size) {
+ dev_dbg(shrm->dev, "Inside Loop Back\n");
+ psrc = (u8 *)data;
+ size = (q->size-q->writeptr);
+ /* Copy First Part of msg */
+ memcpy((q->fifo_base+q->writeptr), psrc, size);
+ psrc += size;
+ /* Copy Second Part of msg at the top of fifo */
+ memcpy(q->fifo_base, psrc, (n_bytes-size));
+ } else {
+ memcpy((q->fifo_base+q->writeptr), data, n_bytes);
+ }
+ ret = add_msg_to_queue(q, n_bytes);
+ spin_unlock(&q->update_lock);
+ if (ret < 0) {
+ dev_err(shrm->dev, "Adding a msg to message queue failed");
+ return ret;
+ }
+
+
+ if (l2_header == ISI_MESSAGING) {
+ if (shrm->netdev_flag_up) {
+ dev_dbg(shrm->dev,
+ "scheduling the phonet tasklet from %s!\n",
+ __func__);
+ tasklet_schedule(&phonet_rcv_tasklet);
+ }
+ dev_dbg(shrm->dev,
+ "Out of phonet tasklet %s!!!\n", __func__);
+ }
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return ret;
+}
+
+/**
+ * rx_common_l2msg_handler() - common channel receive handler
+ * @l2_header: L2 header
+ * @msg: pointer to the receive buffer
+ * @length: length of the msg to read
+ * @shrm: pointer to shrm device information structure
+ *
+ * This function is called to receive the message from CaMsgPendingNotification
+ * interrupt handler.
+ */
+static void rx_common_l2msg_handler(u8 l2_header,
+ void *msg, u32 length,
+ struct shrm_dev *shrm)
+{
+ int ret = 0;
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ ret = common_receive(shrm, msg, length, l2_header);
+ if (ret < 0)
+ dev_err(shrm->dev,
+ "common receive with l2 header %d failed\n", l2_header);
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+/**
+ * rx_audio_l2msg_handler() - audio channel receive handler
+ * @l2_header: L2 header
+ * @msg: pointer to the receive buffer
+ * @length: length of the msg to read
+ * @shrm: pointer to shrm device information structure
+ *
+ * This function is called to receive the message from CaMsgPendingNotification
+ * interrupt handler.
+ */
+static void rx_audio_l2msg_handler(u8 l2_header,
+ void *msg, u32 length,
+ struct shrm_dev *shrm)
+{
+ int ret = 0;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+ ret = audio_receive(shrm, msg, length, l2_header);
+ if (ret < 0)
+ dev_err(shrm->dev, "audio receive failed\n");
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+static int __init shm_initialise_irq(struct shrm_dev *shrm)
+{
+ int err = 0;
+
+ err = shrm_protocol_init(shrm,
+ rx_common_l2msg_handler, rx_audio_l2msg_handler);
+ if (err < 0) {
+ dev_err(shrm->dev, "SHM Protocol Init Failure\n");
+ return err;
+ }
+
+ err = request_irq(shrm->ca_wake_irq,
+ ca_wake_irq_handler, IRQF_TRIGGER_RISING,
+ "ca_wake-up", shrm);
+ if (err < 0) {
+ dev_err(shrm->dev,
+ "Unable to allocate shm tx interrupt line\n");
+ free_irq(shrm->ca_wake_irq, shrm);
+ return err;
+ }
+
+ err = request_irq(shrm->ac_read_notif_0_irq,
+ ac_read_notif_0_irq_handler, 0,
+ "ac_read_notif_0", shrm);
+
+ if (err < 0) {
+ dev_err(shrm->dev,
+ "error ac_read_notif_0_irq interrupt line\n");
+ goto irq_err1;
+ }
+
+ err = request_irq(shrm->ac_read_notif_1_irq,
+ ac_read_notif_1_irq_handler, 0,
+ "ac_read_notif_1", shrm);
+
+ if (err < 0) {
+ dev_err(shrm->dev,
+ "error ac_read_notif_1_irq interrupt line\n");
+ goto irq_err2;
+ }
+
+ err = request_irq(shrm->ca_msg_pending_notif_0_irq,
+ ca_msg_pending_notif_0_irq_handler, 0,
+ "ca_msg_pending_notif_0", shrm);
+
+ if (err < 0) {
+ dev_err(shrm->dev,
+ "error ca_msg_pending_notif_0_irq line\n");
+ goto irq_err3;
+ }
+
+ err = request_irq(shrm->ca_msg_pending_notif_1_irq,
+ ca_msg_pending_notif_1_irq_handler, 0,
+ "ca_msg_pending_notif_1", shrm);
+
+ if (err < 0) {
+ dev_err(shrm->dev,
+ "error ca_msg_pending_notif_1_irq interrupt line\n");
+ goto irq_err4;
+ }
+ return err;
+irq_err4:
+ free_irq(shrm->ca_msg_pending_notif_0_irq, shrm);
+irq_err3:
+ free_irq(shrm->ac_read_notif_1_irq, shrm);
+irq_err2:
+ free_irq(shrm->ac_read_notif_0_irq, shrm);
+irq_err1:
+ free_irq(shrm->ca_wake_irq, shrm);
+ return err;
+}
+
+static void free_shm_irq(struct shrm_dev *shrm)
+{
+ free_irq(shrm->ca_wake_irq, shrm);
+ free_irq(shrm->ac_read_notif_0_irq, shrm);
+ free_irq(shrm->ac_read_notif_1_irq, shrm);
+ free_irq(shrm->ca_msg_pending_notif_0_irq, shrm);
+ free_irq(shrm->ca_msg_pending_notif_1_irq, shrm);
+}
+
+
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+static enum hrtimer_restart callback(struct hrtimer *timer)
+{
+ return HRTIMER_NORESTART;
+}
+#endif
+
+void do_phonet_rcv_tasklet(unsigned long unused)
+{
+ ssize_t ret;
+ struct shrm_dev *shrm = (struct shrm_dev *)unused;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+ for (;;) {
+ ret = shrm_net_receive(shrm->ndev, ph_recv_buf);
+ if (ret == 0) {
+ dev_dbg(shrm->dev, "len is zero, queue empty\n");
+ break;
+ }
+ if (ret < 0) {
+ dev_err(shrm->dev, "len < 0 !!! error!!!\n");
+ break;
+ }
+ }
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+static int __init shrm_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ struct resource *res;
+ struct shrm_dev *shrm = NULL;
+
+ shrm = kzalloc(sizeof(struct shrm_dev), GFP_KERNEL);
+ if (shrm == NULL) {
+ dev_err(&pdev->dev,
+ "Could not allocate memory for struct shm_dev\n");
+ return -ENOMEM;
+ }
+
+ shrm->dev = &pdev->dev;
+ /* initialise the SHM */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(shrm->dev,
+ "Unable to map Ca Wake up interrupt\n");
+ err = -EBUSY;
+ goto rollback_intr;
+ }
+ shrm->ca_wake_irq = res->start;
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+
+ if (!res) {
+ dev_err(shrm->dev,
+ "Unable to map APE_Read_notif_common IRQ base\n");
+ err = -EBUSY;
+ goto rollback_intr;
+ }
+ shrm->ac_read_notif_0_irq = res->start;
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+
+ if (!res) {
+ dev_err(shrm->dev,
+ "Unable to map APE_Read_notif_audio IRQ base\n");
+ err = -EBUSY;
+ goto rollback_intr;
+ }
+ shrm->ac_read_notif_1_irq = res->start;
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 3);
+
+ if (!res) {
+ dev_err(shrm->dev,
+ "Unable to map Cmt_msg_pending_notif_common IRQ base\n");
+ err = -EBUSY;
+ goto rollback_intr;
+ }
+ shrm->ca_msg_pending_notif_0_irq = res->start;
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 4);
+
+ if (!res) {
+ dev_err(shrm->dev,
+ "Unable to map Cmt_msg_pending_notif_audio IRQ base\n");
+ err = -EBUSY;
+ goto rollback_intr;
+ }
+ shrm->ca_msg_pending_notif_1_irq = res->start;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res) {
+ dev_err(shrm->dev,
+ "Could not get SHM IO memory information\n");
+ err = -ENODEV;
+ goto rollback_intr;
+ }
+ shrm->intr_base = (void __iomem *)ioremap_nocache(res->start,
+ res->end - res->start + 1);
+ if (!(shrm->intr_base)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_intr;
+ }
+ shrm->ape_common_fifo_base_phy =
+ (u32 *)U8500_SHM_FIFO_APE_COMMON_BASE;
+ shrm->ape_common_fifo_base =
+ (void __iomem *)ioremap_nocache(
+ U8500_SHM_FIFO_APE_COMMON_BASE,
+ SHM_FIFO_0_SIZE);
+ shrm->ape_common_fifo_size = (SHM_FIFO_0_SIZE)/4;
+
+ if (!(shrm->ape_common_fifo_base)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_ape_common_fifo_base;
+ }
+ shrm->cmt_common_fifo_base_phy =
+ (u32 *)U8500_SHM_FIFO_CMT_COMMON_BASE;
+ shrm->cmt_common_fifo_base =
+ (void __iomem *)ioremap_nocache(
+ U8500_SHM_FIFO_CMT_COMMON_BASE, SHM_FIFO_0_SIZE);
+ shrm->cmt_common_fifo_size = (SHM_FIFO_0_SIZE)/4;
+
+ if (!(shrm->cmt_common_fifo_base)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_cmt_common_fifo_base;
+ }
+ shrm->ape_audio_fifo_base_phy =
+ (u32 *)U8500_SHM_FIFO_APE_AUDIO_BASE;
+ shrm->ape_audio_fifo_base =
+ (void __iomem *)ioremap_nocache(U8500_SHM_FIFO_APE_AUDIO_BASE,
+ SHM_FIFO_1_SIZE);
+ shrm->ape_audio_fifo_size = (SHM_FIFO_1_SIZE)/4;
+
+ if (!(shrm->ape_audio_fifo_base)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_ape_audio_fifo_base;
+ }
+ shrm->cmt_audio_fifo_base_phy =
+ (u32 *)U8500_SHM_FIFO_CMT_AUDIO_BASE;
+ shrm->cmt_audio_fifo_base =
+ (void __iomem *)ioremap_nocache(U8500_SHM_FIFO_CMT_AUDIO_BASE,
+ SHM_FIFO_1_SIZE);
+ shrm->cmt_audio_fifo_size = (SHM_FIFO_1_SIZE)/4;
+
+ if (!(shrm->cmt_audio_fifo_base)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_cmt_audio_fifo_base;
+ }
+ shrm->ac_common_shared_wptr =
+ (void __iomem *)ioremap(SHM_ACFIFO_0_WRITE_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ac_common_shared_wptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_ac_common_shared_wptr;
+ }
+ shrm->ac_common_shared_rptr =
+ (void __iomem *)ioremap(SHM_ACFIFO_0_READ_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ac_common_shared_rptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+ shrm->ca_common_shared_wptr =
+ (void __iomem *)ioremap(SHM_CAFIFO_0_WRITE_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ca_common_shared_wptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+ shrm->ca_common_shared_rptr =
+ (void __iomem *)ioremap(SHM_CAFIFO_0_READ_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ca_common_shared_rptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+ shrm->ac_audio_shared_wptr =
+ (void __iomem *)ioremap(SHM_ACFIFO_1_WRITE_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ac_audio_shared_wptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+ shrm->ac_audio_shared_rptr =
+ (void __iomem *)ioremap(SHM_ACFIFO_1_READ_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ac_audio_shared_rptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+ shrm->ca_audio_shared_wptr =
+ (void __iomem *)ioremap(SHM_CAFIFO_1_WRITE_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ca_audio_shared_wptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+ shrm->ca_audio_shared_rptr =
+ (void __iomem *)ioremap(SHM_CAFIFO_1_READ_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ca_audio_shared_rptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+
+ if (isa_init(shrm) != 0) {
+ dev_err(shrm->dev, "Driver Initialization Error\n");
+ err = -EBUSY;
+ }
+ /* install handlers and tasklets */
+ if (shm_initialise_irq(shrm)) {
+ dev_err(shrm->dev,
+ "shm error in interrupt registration\n");
+ goto rollback_irq;
+ }
+#ifdef CONFIG_HIGH_RES_TIMERS
+ hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ timer.function = callback;
+ hrtimer_start(&timer, ktime_set(0, 2*NSEC_PER_MSEC), HRTIMER_MODE_REL);
+#endif
+ err = shrm_register_netdev(shrm);
+ if (err < 0)
+ goto rollback_irq;
+
+ tasklet_init(&phonet_rcv_tasklet, do_phonet_rcv_tasklet, 0);
+ phonet_rcv_tasklet.data = (unsigned long)shrm;
+
+ platform_set_drvdata(pdev, shrm);
+
+ return err;
+rollback_irq:
+ free_shm_irq(shrm);
+rollback_map:
+ iounmap(shrm->ac_common_shared_wptr);
+ iounmap(shrm->ac_common_shared_rptr);
+ iounmap(shrm->ca_common_shared_wptr);
+ iounmap(shrm->ca_common_shared_rptr);
+ iounmap(shrm->ac_audio_shared_wptr);
+ iounmap(shrm->ac_audio_shared_rptr);
+ iounmap(shrm->ca_audio_shared_wptr);
+ iounmap(shrm->ca_audio_shared_rptr);
+rollback_ac_common_shared_wptr:
+ iounmap(shrm->cmt_audio_fifo_base);
+rollback_cmt_audio_fifo_base:
+ iounmap(shrm->ape_audio_fifo_base);
+rollback_ape_audio_fifo_base:
+ iounmap(shrm->cmt_common_fifo_base);
+rollback_cmt_common_fifo_base:
+ iounmap(shrm->ape_common_fifo_base);
+rollback_ape_common_fifo_base:
+ iounmap(shrm->intr_base);
+rollback_intr:
+ kfree(shrm);
+ return err;
+}
+
+static int __exit shrm_remove(struct platform_device *pdev)
+{
+ struct shrm_dev *shrm = platform_get_drvdata(pdev);
+
+ free_shm_irq(shrm);
+ iounmap(shrm->intr_base);
+ iounmap(shrm->ape_common_fifo_base);
+ iounmap(shrm->cmt_common_fifo_base);
+ iounmap(shrm->ape_audio_fifo_base);
+ iounmap(shrm->cmt_audio_fifo_base);
+ iounmap(shrm->ac_common_shared_wptr);
+ iounmap(shrm->ac_common_shared_rptr);
+ iounmap(shrm->ca_common_shared_wptr);
+ iounmap(shrm->ca_common_shared_rptr);
+ iounmap(shrm->ac_audio_shared_wptr);
+ iounmap(shrm->ac_audio_shared_rptr);
+ iounmap(shrm->ca_audio_shared_wptr);
+ iounmap(shrm->ca_audio_shared_rptr);
+ shrm_unregister_netdev(shrm);
+ isa_exit(shrm);
+ kfree(shrm);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ * u8500_shrm_suspend() - This routine puts the SHRM in to sustend state.
+ * @dev: pointer to device structure.
+ *
+ * This routine checks the current ongoing communication with Modem by
+ * examining the ca_wake state and prevents suspend if modem communication
+ * is on-going.
+ * If ca_wake = 1 (high), modem comm. is on-going; don't suspend
+ * If ca_wake = 0 (low), no comm. with modem on-going.Allow suspend
+ */
+int u8500_shrm_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct shrm_dev *shrm = platform_get_drvdata(pdev);
+ int err;
+
+ dev_dbg(&pdev->dev, "%s called...\n", __func__);
+ dev_dbg(&pdev->dev, "ca_wake_req_state = %x\n",
+ get_ca_wake_req_state());
+
+ /* if ca_wake_req is high, prevent system suspend */
+ if (!get_ca_wake_req_state()) {
+ err = shrm_suspend_netdev(shrm->ndev);
+ return err;
+ } else
+ return -EBUSY;
+}
+
+/**
+ * u8500_shrm_resume() - This routine resumes the SHRM from suspend state.
+ * @dev: pointer to device structure
+ *
+ * This routine restore back the current state of the SHRM
+ */
+int u8500_shrm_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct shrm_dev *shrm = platform_get_drvdata(pdev);
+ int err;
+
+ dev_dbg(&pdev->dev, "%s called...\n", __func__);
+ err = shrm_resume_netdev(shrm->ndev);
+
+ return err;
+}
+
+static const struct dev_pm_ops shrm_dev_pm_ops = {
+ .suspend = u8500_shrm_suspend,
+ .resume = u8500_shrm_resume,
+};
+#endif
+
+static struct platform_driver shrm_driver = {
+ .probe = shrm_probe,
+ .remove = __exit_p(shrm_remove),
+ .driver = {
+ .name = "u8500_shrm",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &shrm_dev_pm_ops,
+#endif
+ },
+};
+
+static int __init shrm_driver_init(void)
+{
+ return platform_driver_probe(&shrm_driver, shrm_probe);
+}
+
+static void __exit shrm_driver_exit(void)
+{
+ platform_driver_unregister(&shrm_driver);
+}
+
+module_init(shrm_driver_init);
+module_exit(shrm_driver_exit);
+
+MODULE_AUTHOR("Biju Das, Kumar Sanghvi, Arun Murthy");
+MODULE_DESCRIPTION("Shared Memory Modem Driver Interface");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/shrm/shrm_driver.c b/drivers/misc/shrm/shrm_driver.c
new file mode 100644
index 00000000000..d1230301917
--- /dev/null
+++ b/drivers/misc/shrm/shrm_driver.c
@@ -0,0 +1,1440 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> for ST-Ericsson
+ * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#define DEBUG
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/smp_lock.h>
+#include <linux/poll.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <mach/isa_ioctl.h>
+#include <mach/shrm_driver.h>
+#include <mach/shrm_private.h>
+#include <mach/shrm_config.h>
+#include <mach/shrm.h>
+
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+#include <linux/hrtimer.h>
+static struct hrtimer timer;
+#endif
+
+
+#define NAME "IPC_ISA"
+#define ISA_DEVICES 4
+/**debug functionality*/
+#define ISA_DEBUG 0
+
+#define ISI_MESSAGING (0)
+#define RPC_MESSAGING (1)
+#define AUDIO_MESSAGING (2)
+#define SECURITY_MESSAGING (3)
+
+#define SIZE_OF_FIFO (512*1024)
+
+static u8 message_fifo[4][SIZE_OF_FIFO];
+
+static u8 wr_isi_msg[10*1024];
+static u8 wr_rpc_msg[10*1024];
+static u8 wr_sec_msg[10*1024];
+static u8 wr_audio_msg[10*1024];
+
+/* global data */
+/*
+ * int major:This variable is exported to user as module_param to specify
+ * major number at load time
+ */
+static int major;
+module_param(major, int, 0);
+MODULE_PARM_DESC(major, "Major device number");
+/* global fops mutex */
+static DEFINE_MUTEX(isa_lock);
+rx_cb common_rx;
+rx_cb audio_rx;
+
+
+static int isi_receive(struct shrm_dev *shrm, void *data, u32 n_bytes);
+static int rpc_receive(struct shrm_dev *shrm, void *data, u32 n_bytes);
+static int audio_receive(struct shrm_dev *shrm, void *data, u32 n_bytes);
+static int security_receive(struct shrm_dev *shrm,
+ void *data, u32 n_bytes);
+
+static void rx_common_l2msg_handler(u8 l2_header,
+ void *msg, u32 length,
+ struct shrm_dev *shrm)
+{
+ int ret = 0;
+#ifdef CONFIG_U8500_SHRM_LOOP_BACK
+ u8 *pdata;
+#endif
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ switch (l2_header) {
+ case ISI_MESSAGING:
+ ret = isi_receive(shrm, msg, length);
+ if (ret < 0)
+ dev_err(shrm->dev, "isi receive failed\n");
+ break;
+ case RPC_MESSAGING:
+ ret = rpc_receive(shrm, msg, length);
+ if (ret < 0)
+ dev_err(shrm->dev, "rpc receive failed\n");
+ break;
+ case SECURITY_MESSAGING:
+ ret = security_receive(shrm, msg, length);
+ if (ret < 0)
+ dev_err(shrm->dev,
+ "security receive failed\n");
+ break;
+#ifdef CONFIG_U8500_SHRM_LOOP_BACK
+ case COMMMON_LOOPBACK_MESSAGING:
+ pdata = (u8 *)msg;
+ if ((*pdata == 0x50) || (*pdata == 0xAF)) {
+ ret = isi_receive(shrm, msg, length);
+ if (ret < 0)
+ dev_err(shrm->dev, "isi receive failed\n");
+ } else if ((*pdata == 0x0A) || (*pdata == 0xF5)) {
+ ret = rpc_receive(shrm, msg, length);
+ if (ret < 0)
+ dev_err(shrm->dev, "rpc receive failed\n");
+ } else if ((*pdata == 0xFF) || (*pdata == 0x00)) {
+ ret = security_receive(shrm, msg, length);
+ if (ret < 0)
+ dev_err(shrm->dev,
+ "security receive failed\n");
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+static void rx_audio_l2msg_handler(u8 l2_header,
+ void *msg, u32 length,
+ struct shrm_dev *shrm)
+{
+ int ret = 0;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+ audio_receive(shrm, msg, length);
+ if (ret < 0)
+ dev_err(shrm->dev, "audio receive failed\n");
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+static int __init shm_initialise_irq(struct shrm_dev *shrm)
+{
+ int err = 0;
+
+ shrm_protocol_init(shrm,
+ rx_common_l2msg_handler, rx_audio_l2msg_handler);
+
+ err = request_irq(shrm->ca_wake_irq,
+ ca_wake_irq_handler, IRQF_TRIGGER_RISING,
+ "ca_wake-up", shrm);
+ if (err < 0) {
+ dev_err(shrm->dev,
+ "Unable to allocate shm tx interrupt line\n");
+ return err;
+ }
+
+ err = request_irq(shrm->ac_read_notif_0_irq,
+ ac_read_notif_0_irq_handler, 0,
+ "ac_read_notif_0", shrm);
+ if (err < 0) {
+ dev_err(shrm->dev,
+ "error ac_read_notif_0_irq interrupt line\n");
+ goto irq_err1;
+ }
+
+ err = request_irq(shrm->ac_read_notif_1_irq,
+ ac_read_notif_1_irq_handler, 0,
+ "ac_read_notif_1", shrm);
+ if (err < 0) {
+ dev_err(shrm->dev,
+ "error ac_read_notif_1_irq interrupt line\n");
+ goto irq_err2;
+ }
+
+ err = request_irq(shrm->ca_msg_pending_notif_0_irq,
+ ca_msg_pending_notif_0_irq_handler, 0,
+ "ca_msg_pending_notif_0", shrm);
+ if (err < 0) {
+ dev_err(shrm->dev,
+ "error ca_msg_pending_notif_0_irq line\n");
+ goto irq_err3;
+ }
+
+ err = request_irq(shrm->ca_msg_pending_notif_1_irq,
+ ca_msg_pending_notif_1_irq_handler, 0,
+ "ca_msg_pending_notif_1", shrm);
+ if (err < 0) {
+ dev_err(shrm->dev,
+ "error ca_msg_pending_notif_1_irq interrupt line\n");
+ goto irq_err4;
+ }
+
+ return err;
+
+irq_err4:
+ free_irq(shrm->ca_msg_pending_notif_0_irq, shrm);
+irq_err3:
+ free_irq(shrm->ac_read_notif_1_irq, shrm);
+irq_err2:
+ free_irq(shrm->ac_read_notif_0_irq, shrm);
+irq_err1:
+ free_irq(shrm->ca_wake_irq, shrm);
+ return err;
+}
+
+static void free_shm_irq(struct shrm_dev *shrm)
+{
+ free_irq(shrm->ca_wake_irq, shrm);
+ free_irq(shrm->ac_read_notif_0_irq, shrm);
+ free_irq(shrm->ac_read_notif_1_irq, shrm);
+ free_irq(shrm->ca_msg_pending_notif_0_irq, shrm);
+ free_irq(shrm->ca_msg_pending_notif_1_irq, shrm);
+}
+
+/**
+ * create_queue() - To create FIFO for Tx and Rx message buffering.
+ * @q: message queue.
+ * @devicetype: device type 0-isi,1-rpc,2-audio,3-security.
+ *
+ * This function creates a FIFO buffer of n_bytes size using
+ * dma_alloc_coherent(). It also initializes all queue handling
+ * locks, queue management pointers. It also initializes message list
+ * which occupies this queue.
+ *
+ * It return -ENOMEM in case of no memory.
+ */
+static int create_queue(struct message_queue *q, u32 devicetype,
+ struct shrm_dev *shrm)
+{
+ q->fifo_base = (u8 *)&message_fifo[devicetype];
+ q->size = SIZE_OF_FIFO;
+ q->readptr = 0;
+ q->writeptr = 0;
+ q->no = 0;
+ q->shrm = shrm;
+ spin_lock_init(&q->update_lock);
+ INIT_LIST_HEAD(&q->msg_list);
+ init_waitqueue_head(&q->wq_readable);
+ atomic_set(&q->q_rp, 0);
+
+ return 0;
+}
+/**
+ * delete_queue() - To delete FIFO and assiciated memory.
+ * @q: message queue
+ *
+ * This function deletes FIFO created using create_queue() function.
+ * It resets queue management pointers.
+ */
+static void delete_queue(struct message_queue *q)
+{
+ q->size = 0;
+ q->readptr = 0;
+ q->writeptr = 0;
+}
+
+/**
+ * add_msg_to_queue() - Add a message inside inside queue
+ *
+ * @q: message queue
+ * @size: size in bytes
+ *
+ * This function tries to allocate n_bytes of size in FIFO q.
+ * It returns negative number when no memory can be allocated
+ * currently.
+ */
+int add_msg_to_queue(struct message_queue *q, u32 size)
+{
+ struct queue_element *new_msg = NULL;
+ struct shrm_dev *shrm = q->shrm;
+
+ dev_dbg(shrm->dev, "%s IN q->writeptr=%d\n",
+ __func__, q->writeptr);
+ new_msg = kmalloc(sizeof(struct queue_element),
+ GFP_KERNEL|GFP_ATOMIC);
+
+ if (new_msg == NULL) {
+ dev_err(shrm->dev, "memory overflow inside while(1)\n");
+ return -ENOMEM;
+ }
+ new_msg->offset = q->writeptr;
+ new_msg->size = size;
+ new_msg->no = q->no++;
+
+ /* check for overflow condition */
+ if (q->readptr <= q->writeptr) {
+ if (((q->writeptr-q->readptr) + size) >= q->size) {
+ dev_err(shrm->dev, "Buffer overflow !!\n");
+ BUG_ON(((q->writeptr-q->readptr) + size) >= q->size);
+ }
+ } else {
+ if ((q->writeptr + size) >= q->readptr) {
+ dev_err(shrm->dev, "Buffer overflow !!\n");
+ BUG_ON((q->writeptr + size) >= q->readptr);
+ }
+ }
+ q->writeptr = (q->writeptr + size) % q->size;
+ if (list_empty(&q->msg_list)) {
+ list_add_tail(&new_msg->entry, &q->msg_list);
+ /* There can be 2 blocking calls read and another select */
+
+ atomic_set(&q->q_rp, 1);
+ wake_up_interruptible(&q->wq_readable);
+ } else
+ list_add_tail(&new_msg->entry, &q->msg_list);
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return 0;
+}
+
+/**
+ * remove_msg_from_queue() - To remove a message from the msg queue.
+ *
+ * @q: message queue
+ *
+ * This function delets a message from the message list associated with message
+ * queue q and also updates read ptr.
+ * If the message list is empty, then, event is set to block the select and
+ * read calls of the paricular queue.
+ *
+ * The message list is FIFO style and message is always added to tail and
+ * removed from head.
+ */
+
+int remove_msg_from_queue(struct message_queue *q)
+{
+ struct queue_element *old_msg = NULL;
+ struct shrm_dev *shrm = q->shrm;
+ struct list_head *msg;
+
+ dev_dbg(shrm->dev, "%s IN q->readptr %d\n",
+ __func__, q->readptr);
+
+ list_for_each(msg, &q->msg_list) {
+ old_msg = list_entry(msg, struct queue_element, entry);
+ if (old_msg == NULL) {
+ dev_err(shrm->dev, ":no message found\n");
+ return -EFAULT;
+ }
+ break;
+ }
+ list_del(msg);
+ q->readptr = (q->readptr + old_msg->size) % q->size;
+ if (list_empty(&q->msg_list)) {
+ dev_dbg(shrm->dev, "List is empty setting RP= 0\n");
+ atomic_set(&q->q_rp, 0);
+ }
+ kfree(old_msg);
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return 0;
+}
+
+/**
+ * get_size_of_new_msg() - retrieve new message from message list
+ *
+ * @q: message queue
+ *
+ * This function will retrieve most recent message from the corresponding
+ * queue list. New message is always retrieved from head side.
+ * It returns new message no, offset if FIFO and size.
+ */
+int get_size_of_new_msg(struct message_queue *q)
+{
+ struct queue_element *new_msg = NULL;
+ struct list_head *msg_list;
+ struct shrm_dev *shrm = q->shrm;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ spin_lock_bh(&q->update_lock);
+ list_for_each(msg_list, &q->msg_list) {
+ new_msg = list_entry(msg_list, struct queue_element, entry);
+ if (new_msg == NULL) {
+ spin_unlock_bh(&q->update_lock);
+ dev_err(shrm->dev, "no message found\n");
+ return -1;
+ }
+ break;
+ }
+ spin_unlock_bh(&q->update_lock);
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return new_msg->size;
+}
+
+/**
+ * isi_receive() - Rx Completion callback
+ *
+ * @data:message pointer
+ * @n_bytes:message size
+ *
+ * This function is a callback to indicate ISI message reception is complete.
+ * It updates Writeptr of the Fifo
+ */
+static int isi_receive(struct shrm_dev *shrm,
+ void *data, u32 n_bytes)
+{
+ u32 size = 0;
+ int ret = 0;
+ u8 *psrc;
+ struct message_queue *q;
+ struct isadev_context *isidev = &shrm->isa_context->isadev[0];
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+ q = &isidev->dl_queue;
+ spin_lock(&q->update_lock);
+ /* Memcopy RX data first */
+ if ((q->writeptr+n_bytes) >= q->size) {
+ dev_dbg(shrm->dev, "Inside Loop Back\n");
+ psrc = (u8 *)data;
+ size = (q->size-q->writeptr);
+ /* Copy First Part of msg */
+ memcpy((q->fifo_base+q->writeptr), psrc, size);
+ psrc += size;
+ /* Copy Second Part of msg at the top of fifo */
+ memcpy(q->fifo_base, psrc, (n_bytes-size));
+ } else {
+ memcpy((q->fifo_base+q->writeptr), data, n_bytes);
+ }
+ ret = add_msg_to_queue(q, n_bytes);
+ if (ret < 0)
+ dev_err(shrm->dev, "Adding msg to message queue failed\n");
+ spin_unlock(&q->update_lock);
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return ret;
+}
+
+/**
+ * rpc_receive() - Rx Completion callback
+ *
+ * @data:message pointer
+ * @n_bytes:message size
+ *
+ * This function is a callback to indicate RPC message reception is complete.
+ * It updates Writeptr of the Fifo
+ */
+static int rpc_receive(struct shrm_dev *shrm,
+ void *data, u32 n_bytes)
+{
+ u32 size = 0;
+ int ret = 0;
+ u8 *psrc;
+ struct message_queue *q;
+ struct isadev_context *rpcdev = &shrm->isa_context->isadev[1];
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+ q = &rpcdev->dl_queue;
+ spin_lock(&q->update_lock);
+ /* Memcopy RX data first */
+ if ((q->writeptr+n_bytes) >= q->size) {
+ psrc = (u8 *)data;
+ size = (q->size-q->writeptr);
+ /* Copy First Part of msg */
+ memcpy((q->fifo_base+q->writeptr), psrc, size);
+ psrc += size;
+ /* Copy Second Part of msg at the top of fifo */
+ memcpy(q->fifo_base, psrc, (n_bytes-size));
+ } else {
+ memcpy((q->fifo_base+q->writeptr), data, n_bytes);
+ }
+
+ ret = add_msg_to_queue(q, n_bytes);
+ if (ret < 0)
+ dev_err(shrm->dev, "Adding msg to message queue failed\n");
+ spin_unlock(&q->update_lock);
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return ret;
+}
+
+/**
+ * audio_receive() - Rx Completion callback
+ *
+ * @data:message pointer
+ * @n_bytes:message size
+ *
+ * This function is a callback to indicate audio message reception is complete.
+ * It updates Writeptr of the Fifo
+ */
+static int audio_receive(struct shrm_dev *shrm,
+ void *data, u32 n_bytes)
+{
+ u32 size = 0;
+ int ret = 0;
+ u8 *psrc;
+ struct message_queue *q;
+ struct isadev_context *audiodev = &shrm->isa_context->isadev[2];
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+ q = &audiodev->dl_queue;
+ spin_lock(&q->update_lock);
+ /* Memcopy RX data first */
+ if ((q->writeptr+n_bytes) >= q->size) {
+ psrc = (u8 *)data;
+ size = (q->size-q->writeptr);
+ /* Copy First Part of msg */
+ memcpy((q->fifo_base+q->writeptr), psrc, size);
+ psrc += size;
+ /* Copy Second Part of msg at the top of fifo */
+ memcpy(q->fifo_base, psrc, (n_bytes-size));
+ } else {
+ memcpy((q->fifo_base+q->writeptr), data, n_bytes);
+ }
+ ret = add_msg_to_queue(q, n_bytes);
+ if (ret < 0)
+ dev_err(shrm->dev, "Adding msg to message queue failed\n");
+ spin_unlock(&q->update_lock);
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return ret;
+}
+
+/**
+ * security_receive() - Rx Completion callback
+ *
+ * @data:message pointer
+ * @n_bytes: message size
+ *
+ * This function is a callback to indicate security message reception
+ * is complete.It updates Writeptr of the Fifo
+ */
+static int security_receive(struct shrm_dev *shrm,
+ void *data, u32 n_bytes)
+{
+ u32 size = 0;
+ int ret = 0;
+ u8 *psrc;
+ struct message_queue *q;
+ struct isadev_context *secdev = &shrm->isa_context->isadev[3];
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+ q = &secdev->dl_queue;
+ spin_lock(&q->update_lock);
+ /* Memcopy RX data first */
+ if ((q->writeptr+n_bytes) >= q->size) {
+ psrc = (u8 *)data;
+ size = (q->size-q->writeptr);
+ /* Copy First Part of msg */
+ memcpy((q->fifo_base+q->writeptr), psrc, size);
+ psrc += size;
+ /* Copy Second Part of msg at the top of fifo */
+ memcpy(q->fifo_base, psrc, (n_bytes-size));
+ } else {
+ memcpy((q->fifo_base+q->writeptr), data, n_bytes);
+ }
+ ret = add_msg_to_queue(q, n_bytes);
+ if (ret < 0)
+ dev_err(shrm->dev, "Adding msg to message queue failed\n");
+ spin_unlock(&q->update_lock);
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return ret;
+}
+
+
+/**
+ * isa_select() - Select Interface
+ *
+ * @filp:file descriptor pointer
+ * @wait:poll_table_struct pointer
+ *
+ * This function is used to perform non-blocking read operations. It allows
+ * a process to determine whether it can read from one or more open files
+ * without blocking. These calls can also block a process until any of a
+ * given set of file descriptors becomes available for reading.
+ * If a file is ready to read, POLLIN | POLLRDNORM bitmask is returned.
+ * The driver method is called whenever the user-space program performs a select
+ * system call involving a file descriptor associated with the driver.
+ */
+static u32 isa_select(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ struct isadev_context *isadev = filp->private_data;
+ struct shrm_dev *shrm = isadev->dl_queue.shrm;
+ struct message_queue *q;
+ u32 mask = 0;
+ u32 m = iminor(filp->f_path.dentry->d_inode);
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (isadev->device_id != m)
+ return -1;
+ q = &isadev->dl_queue;
+ poll_wait(filp, &q->wq_readable, wait);
+ if (atomic_read(&q->q_rp) == 1)
+ mask = POLLIN | POLLRDNORM;
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return mask;
+}
+
+/**
+ * isa_read() - Read from device
+ *
+ * @filp:file descriptor
+ * @buf:user buffer pointer
+ * @len:size of requested data transfer
+ * @ppos:not used
+ *
+ * This function is called whenever user calls read() system call.
+ * It reads a oldest message from queue and copies it into user buffer and
+ * returns its size.
+ * If there is no message present in queue, then it blocks until new data is
+ * available.
+ */
+ssize_t isa_read(struct file *filp, char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ struct isadev_context *isadev = (struct isadev_context *)
+ filp->private_data;
+ struct shrm_dev *shrm = isadev->dl_queue.shrm;
+ struct message_queue *q;
+ char *psrc;
+ u32 msgsize;
+ u32 size = 0;
+ int ret = 0;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (len <= 0)
+ return -EFAULT;
+ q = &isadev->dl_queue;
+
+ spin_lock_bh(&q->update_lock);
+ if (list_empty(&q->msg_list)) {
+ spin_unlock_bh(&q->update_lock);
+ if (wait_event_interruptible(q->wq_readable,
+ atomic_read(&q->q_rp) == 1)) {
+ return -ERESTARTSYS;
+ }
+ } else
+ spin_unlock_bh(&q->update_lock);
+
+ msgsize = get_size_of_new_msg(q);
+ if ((q->readptr+msgsize) >= q->size) {
+ dev_dbg(shrm->dev, "Inside Loop Back\n");
+ psrc = (char *)buf;
+ size = (q->size-q->readptr);
+ /* Copy First Part of msg */
+ if (copy_to_user(psrc,
+ (u8 *)(q->fifo_base+q->readptr),
+ size)) {
+ dev_err(shrm->dev, "copy_to_user failed\n");
+ return -EFAULT;
+ }
+ psrc += size;
+ /* Copy Second Part of msg at the top of fifo */
+ if (copy_to_user(psrc,
+ (u8 *)(q->fifo_base),
+ (msgsize-size))) {
+ dev_err(shrm->dev, "copy_to_user failed\n");
+ return -EFAULT;
+ }
+ } else {
+ if (copy_to_user(buf,
+ (u8 *)(q->fifo_base+q->readptr),
+ msgsize)) {
+ dev_err(shrm->dev, "copy_to_user failed\n");
+ return -EFAULT;
+ }
+ }
+
+ spin_lock_bh(&q->update_lock);
+ ret = remove_msg_from_queue(q);
+ if (ret < 0) {
+ dev_err(shrm->dev,
+ "Removing msg from message queue failed\n");
+ msgsize = ret;
+ }
+ spin_unlock_bh(&q->update_lock);
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return msgsize;
+}
+/**
+ * isa_write() - Write to device
+ *
+ * @filp:file descriptor
+ * @buf:user buffer pointer
+ * @len:size of requested data transfer
+ * @ppos:not used
+ *
+ * This function is called whenever user calls write() system call.
+ * It checks if there is space available in queue, and copies the message
+ * inside queue. If there is no space, it blocks until space becomes available.
+ * It also schedules transfer thread to transmit the newly added message.
+ */
+static ssize_t isa_write(struct file *filp, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ struct isadev_context *isadev = filp->private_data;
+ struct shrm_dev *shrm = isadev->dl_queue.shrm;
+ struct message_queue *q;
+ int err, ret;
+ void *addr = 0;
+ u8 l2_header = 0;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+ if (len <= 0)
+ return -EFAULT;
+ q = &isadev->dl_queue;
+
+ switch (isadev->device_id) {
+ case ISI_MESSAGING:
+ dev_dbg(shrm->dev, "ISI\n");
+ addr = (void *)wr_isi_msg;
+#ifdef CONFIG_U8500_SHRM_LOOP_BACK
+ dev_dbg(shrm->dev, "Loopback\n");
+ l2_header = COMMON_LOOPBACK_MESSAGING;
+#else
+ l2_header = isadev->device_id;
+#endif
+ break;
+ case RPC_MESSAGING:
+ dev_dbg(shrm->dev, "RPC\n");
+ addr = (void *)wr_rpc_msg;
+#ifdef CONFIG_U8500_SHRM_LOOP_BACK
+ l2_header = COMMON_LOOPBACK_MESSAGING;
+#else
+ l2_header = isadev->device_id;
+#endif
+ break;
+ case AUDIO_MESSAGING:
+ dev_dbg(shrm->dev, "Audio\n");
+ addr = (void *)wr_audio_msg;
+#ifdef CONFIG_U8500_SHRM_LOOP_BACK
+ l2_header = AUDIO_LOOPBACK_MESSAGING;
+#else
+ l2_header = isadev->device_id;
+#endif
+
+ break;
+ case SECURITY_MESSAGING:
+ dev_dbg(shrm->dev, "Security\n");
+ addr = (void *)wr_sec_msg;
+#ifdef CONFIG_U8500_SHRM_LOOP_BACK
+ l2_header = COMMON_LOOPBACK_MESSAGING;
+#else
+ l2_header = isadev->device_id;
+#endif
+ break;
+ default:
+ dev_dbg(shrm->dev, "Wrong device\n");
+ return -EFAULT;
+ }
+
+ if (copy_from_user(addr, buf, len)) {
+ dev_err(shrm->dev, "copy_from_user failed\n");
+ return -EFAULT;
+ }
+
+ /* Write msg to Fifo */
+ if (isadev->device_id == 2) {
+ mutex_lock(&shrm->isa_context->tx_audio_mutex);
+ err = shm_write_msg(shrm, l2_header, addr, len);
+ if (!err)
+ ret = len;
+ else
+ ret = err;
+ mutex_unlock(&shrm->isa_context->tx_audio_mutex);
+ } else {
+ spin_lock_bh(&shrm->isa_context->common_tx);
+ err = shm_write_msg(shrm, l2_header, addr, len);
+ if (!err)
+ ret = len;
+ else
+ ret = err;
+ spin_unlock_bh(&shrm->isa_context->common_tx);
+ }
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return ret;
+}
+
+/**
+ * isa_ioctl() - To handle different ioctl commands supported by driver.
+ *
+ * @inode: structure is used by the kernel internally to represent files
+ * @filp:file descriptor pointer
+ * @cmd:ioctl command
+ * @arg:input param
+ *
+ * Following ioctls are supported by this driver.
+ * DLP_IOCTL_ALLOCATE_BUFFER - To allocate buffer for new uplink message.
+ * This ioctl is called with required message size. It returns offset for
+ * the allocates space in the queue. DLP_IOCTL_PUT_MESSAGE - To indicate
+ * new uplink message available in queuq for transmission. Message is copied
+ * from offset location returned by previous ioctl before calling this ioctl.
+ * DLP_IOCTL_GET_MESSAGE - To check if any downlink message is available in
+ * queue. It returns offset for new message inside queue.
+ * DLP_IOCTL_DEALLOCATE_BUFFER - To deallocate any buffer allocate for
+ * downlink message once the message is copied. Message is copied from offset
+ * location returned by previous ioctl before calling this ioctl.
+ */
+static int isa_ioctl(struct inode *inode, struct file *filp,
+ unsigned cmd, unsigned long arg)
+{
+ int err = 0;
+ struct isadev_context *isadev = filp->private_data;
+ struct shrm_dev *shrm = isadev->dl_queue.shrm;
+ u32 m = iminor(inode);
+
+ if (isadev->device_id != m)
+ return -1;
+
+ switch (cmd) {
+ case DLP_IOC_ALLOCATE_BUFFER:
+ dev_dbg(shrm->dev, "DLP_IOC_ALLOCATE_BUFFER\n");
+ break;
+ case DLP_IOC_PUT_MESSAGE:
+ dev_dbg(shrm->dev, "DLP_IOC_PUT_MESSAGE\n");
+ break;
+ case DLP_IOC_GET_MESSAGE:
+ dev_dbg(shrm->dev, "DLP_IOC_GET_MESSAGE\n");
+ break;
+ case DLP_IOC_DEALLOCATE_BUFFER:
+ dev_dbg(shrm->dev, "DLP_IOC_DEALLOCATE_BUFFER\n");
+ break;
+ default:
+ dev_dbg(shrm->dev, "Unknown IOCTL\n");
+ err = -1;
+ break;
+ }
+ return err;
+}
+/**
+ * isa_mmap() - Maps kernel queue memory to user space.
+ *
+ * @filp:file descriptor pointer
+ * @vma:virtual area memory structure.
+ *
+ * This function maps kernel FIFO into user space. This function
+ * shall be called twice to map both uplink and downlink buffers.
+ */
+static int isa_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct isadev_context *isadev = filp->private_data;
+ struct shrm_dev *shrm = isadev->dl_queue.shrm;
+
+ u32 m = iminor(filp->f_path.dentry->d_inode);
+ dev_dbg(shrm->dev, "%s %dIN\n", __func__, m);
+
+ isadev = (struct isadev_context *)filp->private_data;
+ return 0;
+}
+
+/**
+ * isa_close() - Close device file
+ *
+ * @inode:structure is used by the kernel internally to represent files
+ * @filp:device file descriptor
+ *
+ * This function deletes structues associated with this file, deletes
+ * queues, flushes and destroys workqueus and closes this file.
+ * It also unregisters itself from l2mux driver.
+ */
+static int isa_close(struct inode *inode, struct file *filp)
+{
+ struct isadev_context *isadev = filp->private_data;
+ struct shrm_dev *shrm = isadev->dl_queue.shrm;
+ struct isa_driver_context *isa_context = shrm->isa_context;
+ u8 m;
+
+ mutex_lock(&isa_lock);
+ m = iminor(filp->f_path.dentry->d_inode);
+ dev_dbg(shrm->dev, "%s IN %d", __func__, m);
+
+ if (atomic_dec_and_test(&isa_context->is_open[m])) {
+ atomic_inc(&isa_context->is_open[m]);
+ dev_err(shrm->dev, "Device not opened yet\n");
+ mutex_unlock(&isa_lock);
+ return -ENODEV;
+ }
+ atomic_set(&isa_context->is_open[m], 1);
+
+ dev_dbg(shrm->dev, "isadev->device_id %d", isadev->device_id);
+ dev_dbg(shrm->dev, "Closed %d device\n", m);
+
+ if (m == ISI_MESSAGING)
+ dev_dbg(shrm->dev, "Closed ISI_MESSAGING Device\n");
+ else if (m == RPC_MESSAGING)
+ dev_dbg(shrm->dev, "Closed RPC_MESSAGING Device\n");
+ else if (m == AUDIO_MESSAGING)
+ dev_dbg(shrm->dev, "Closed AUDIO_MESSAGING Device\n");
+ else if (m == SECURITY_MESSAGING)
+ dev_dbg(shrm->dev, "Closed SECURITY_MESSAGING Device\n");
+ else
+ dev_dbg(shrm->dev, NAME ":No such device present\n");
+
+ mutex_unlock(&isa_lock);
+ return 0;
+}
+/**
+ * isa_open() - Open device file
+ *
+ * @inode: structure is used by the kernel internally to represent files
+ * @filp: device file descriptor
+ *
+ * This function performs initialization tasks needed to open SHM channel.
+ * Following tasks are performed.
+ * -return if device is already opened
+ * -create uplink FIFO
+ * -create downlink FIFO
+ * -init delayed workqueue thread
+ * -register to l2mux driver
+ */
+static int isa_open(struct inode *inode, struct file *filp)
+{
+ int err = 0;
+ u8 m;
+ struct isadev_context *isadev;
+ struct isa_driver_context *isa_context = container_of(
+ inode->i_cdev,
+ struct isa_driver_context,
+ cdev);
+ struct shrm_dev *shrm = isa_context->isadev->dl_queue.shrm;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (get_boot_state() != BOOT_DONE) {
+ dev_err(shrm->dev, "Boot is not done\n");
+ return -EBUSY;
+ }
+ mutex_lock(&isa_lock);
+ m = iminor(inode);
+
+ if ((m != ISI_MESSAGING) && (m != RPC_MESSAGING) &&
+ (m != AUDIO_MESSAGING) && (m != SECURITY_MESSAGING)) {
+ dev_err(shrm->dev, "No such device present\n");
+ mutex_unlock(&isa_lock);
+ return -ENODEV;
+ }
+ if (!atomic_dec_and_test(&isa_context->is_open[m])) {
+ atomic_inc(&isa_context->is_open[m]);
+ dev_err(shrm->dev, "Device already opened\n");
+ mutex_unlock(&isa_lock);
+ return -EBUSY;
+ }
+
+ if (m == ISI_MESSAGING)
+ dev_dbg(shrm->dev, "Open ISI_MESSAGING Device\n");
+ else if (m == RPC_MESSAGING)
+ dev_dbg(shrm->dev, "Open RPC_MESSAGING Device\n");
+ else if (m == AUDIO_MESSAGING)
+ dev_dbg(shrm->dev, "Open AUDIO_MESSAGING Device\n");
+ else if (m == SECURITY_MESSAGING)
+ dev_dbg(shrm->dev, "Open SECURITY_MESSAGING Device\n");
+ else
+ dev_dbg(shrm->dev, ":No such device present\n");
+
+ isadev = &isa_context->isadev[m];
+ if (filp != NULL)
+ filp->private_data = isadev;
+
+ mutex_unlock(&isa_lock);
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return err;
+}
+
+const struct file_operations isa_fops = {
+ .owner = THIS_MODULE,
+ .open = isa_open,
+ .release = isa_close,
+ .ioctl = isa_ioctl,
+ .mmap = isa_mmap,
+ .read = isa_read,
+ .write = isa_write,
+ .poll = isa_select,
+};
+
+/**
+ * isa_init() - module insertion function
+ *
+ * This function registers module as a character driver using
+ * register_chrdev_region() or alloc_chrdev_region. It adds this
+ * driver to system using cdev_add() call. Major number is dynamically
+ * allocated using alloc_chrdev_region() by default or left to user to specify
+ * it during load time. For this variable major is used as module_param
+ * Nodes to be created using
+ * mknod /dev/isi c $major 0
+ * mknod /dev/rpc c $major 1
+ * mknod /dev/audio c $major 2
+ * mknod /dev/sec c $major 3
+ */
+int isa_init(struct shrm_dev *shrm)
+{
+ dev_t dev_id;
+ int retval, no_dev;
+ struct isadev_context *isadev;
+ struct isa_driver_context *isa_context;
+
+ isa_context = kzalloc(sizeof(struct isa_driver_context),
+ GFP_KERNEL);
+ shrm->isa_context = isa_context;
+ if (isa_context == NULL) {
+ dev_err(shrm->dev, "Failed to alloc memory\n");
+ return -ENOMEM;
+ }
+
+ if (major) {
+ dev_id = MKDEV(major, 0);
+ retval = register_chrdev_region(dev_id, ISA_DEVICES, NAME);
+ } else {
+ retval = alloc_chrdev_region(&dev_id, 0, ISA_DEVICES, NAME);
+ major = MAJOR(dev_id);
+ }
+
+ dev_dbg(shrm->dev, "major %d\n", major);
+
+ cdev_init(&isa_context->cdev, &isa_fops);
+ isa_context->cdev.owner = THIS_MODULE;
+ retval = cdev_add(&isa_context->cdev, dev_id, ISA_DEVICES);
+ if (retval) {
+ dev_err(shrm->dev, "Failed to add char device\n");
+ return retval;
+ }
+
+ for (no_dev = 0; no_dev < ISA_DEVICES; no_dev++)
+ atomic_set(&isa_context->is_open[no_dev], 1);
+
+ isa_context->isadev = kzalloc(sizeof
+ (struct isadev_context)*ISA_DEVICES,
+ GFP_KERNEL);
+ if (isa_context->isadev == NULL) {
+ dev_err(shrm->dev, "Failed to alloc memory\n");
+ return -ENOMEM;
+ }
+ for (no_dev = 0; no_dev < ISA_DEVICES; no_dev++) {
+ isadev = &isa_context->isadev[no_dev];
+ isadev->device_id = no_dev;
+ retval = create_queue(&isadev->dl_queue,
+ isadev->device_id, shrm);
+ if (retval < 0) {
+ dev_err(shrm->dev, "create dl_queue failed\n");
+ delete_queue(&isadev->dl_queue);
+ kfree(isadev);
+ return retval;
+ }
+ }
+ mutex_init(&isa_context->tx_audio_mutex);
+ spin_lock_init(&isa_context->common_tx);
+
+ dev_err(shrm->dev, "SHRM char driver added\n");
+
+ return retval;
+}
+
+void isa_exit(struct shrm_dev *shrm)
+{
+ int no_dev;
+ struct isadev_context *isadev;
+ struct isa_driver_context *isa_context = shrm->isa_context;
+ dev_t dev_id = MKDEV(major, 0);
+
+ for (no_dev = 0; no_dev < ISA_DEVICES; no_dev++) {
+ isadev = &isa_context->isadev[no_dev];
+ delete_queue(&isadev->dl_queue);
+ kfree(isadev);
+ }
+
+ cdev_del(&isa_context->cdev);
+ unregister_chrdev_region(dev_id, ISA_DEVICES);
+ kfree(isa_context);
+
+ dev_err(shrm->dev, "SHRM char driver removed\n");
+}
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+static enum hrtimer_restart callback(struct hrtimer *timer)
+{
+ return HRTIMER_NORESTART;
+}
+#endif
+
+
+static int __init shrm_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ struct resource *res;
+ struct shrm_dev *shrm = NULL;
+
+ if (pdev == NULL) {
+ dev_err(shrm->dev,
+ "No device/platform_data found on shm device\n");
+ return -ENODEV;
+ }
+
+
+ shrm = kzalloc(sizeof(struct shrm_dev), GFP_KERNEL);
+ if (shrm == NULL) {
+ dev_err(shrm->dev,
+ "Could not allocate memory for struct shm_dev\n");
+ return -ENOMEM;
+ }
+ shrm->dev = &pdev->dev;
+
+ /* initialise the SHM */
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(shrm->dev, "Unable to map Ca Wake up interrupt\n");
+ err = -EBUSY;
+ goto rollback_intr;
+ }
+ shrm->ca_wake_irq = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+ if (!res) {
+ dev_err(shrm->dev,
+ "Unable to map APE_Read_notif_common IRQ base\n");
+ err = -EBUSY;
+ goto rollback_intr;
+ }
+ shrm->ac_read_notif_0_irq = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+ if (!res) {
+ dev_err(shrm->dev,
+ "Unable to map APE_Read_notif_audio IRQ base\n");
+ err = -EBUSY;
+ goto rollback_intr;
+ }
+ shrm->ac_read_notif_1_irq = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 3);
+ if (!res) {
+ dev_err(shrm->dev,
+ "Unable to map Cmt_msg_pending_notif_common IRQ base\n");
+ err = -EBUSY;
+ goto rollback_intr;
+ }
+ shrm->ca_msg_pending_notif_0_irq = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 4);
+ if (!res) {
+ dev_err(shrm->dev,
+ "Unable to map Cmt_msg_pending_notif_audio IRQ base\n");
+ err = -EBUSY;
+ goto rollback_intr;
+ }
+ shrm->ca_msg_pending_notif_1_irq = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(shrm->dev,
+ "Could not get SHM IO memory information\n");
+ err = -ENODEV;
+ goto rollback_intr;
+ }
+
+ shrm->intr_base = (void __iomem *)ioremap_nocache(res->start,
+ res->end - res->start + 1);
+
+ if (!(shrm->intr_base)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_intr;
+ }
+
+ shrm->ape_common_fifo_base_phy =
+ (u32 *)U8500_SHM_FIFO_APE_COMMON_BASE;
+ shrm->ape_common_fifo_base =
+ (void __iomem *)ioremap_nocache(
+ U8500_SHM_FIFO_APE_COMMON_BASE,
+ SHM_FIFO_0_SIZE);
+ shrm->ape_common_fifo_size = (SHM_FIFO_0_SIZE)/4;
+
+ if (!(shrm->ape_common_fifo_base)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_ape_common_fifo_base;
+ }
+
+ shrm->cmt_common_fifo_base_phy =
+ (u32 *)U8500_SHM_FIFO_CMT_COMMON_BASE;
+
+ shrm->cmt_common_fifo_base =
+ (void __iomem *)ioremap_nocache(
+ U8500_SHM_FIFO_CMT_COMMON_BASE, SHM_FIFO_0_SIZE);
+ shrm->cmt_common_fifo_size = (SHM_FIFO_0_SIZE)/4;
+
+ if (!(shrm->cmt_common_fifo_base)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_cmt_common_fifo_base;
+ }
+
+ shrm->ape_audio_fifo_base_phy =
+ (u32 *)U8500_SHM_FIFO_APE_AUDIO_BASE;
+ shrm->ape_audio_fifo_base =
+ (void __iomem *)ioremap_nocache(U8500_SHM_FIFO_APE_AUDIO_BASE,
+ SHM_FIFO_1_SIZE);
+ shrm->ape_audio_fifo_size = (SHM_FIFO_1_SIZE)/4;
+
+ if (!(shrm->ape_audio_fifo_base)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_ape_audio_fifo_base;
+ }
+
+ shrm->cmt_audio_fifo_base_phy =
+ (u32 *)U8500_SHM_FIFO_CMT_AUDIO_BASE;
+ shrm->cmt_audio_fifo_base =
+ (void __iomem *)ioremap_nocache(U8500_SHM_FIFO_CMT_AUDIO_BASE,
+ SHM_FIFO_1_SIZE);
+ shrm->cmt_audio_fifo_size = (SHM_FIFO_1_SIZE)/4;
+
+ if (!(shrm->cmt_audio_fifo_base)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_cmt_audio_fifo_base;
+ }
+
+ shrm->ac_common_shared_wptr =
+ (void __iomem *)ioremap(SHM_ACFIFO_0_WRITE_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ac_common_shared_wptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_ac_common_shared_wptr;
+ }
+
+ shrm->ac_common_shared_rptr =
+ (void __iomem *)ioremap(SHM_ACFIFO_0_READ_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ac_common_shared_rptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+
+
+ shrm->ca_common_shared_wptr =
+ (void __iomem *)ioremap(SHM_CAFIFO_0_WRITE_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ca_common_shared_wptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+
+ shrm->ca_common_shared_rptr =
+ (void __iomem *)ioremap(SHM_CAFIFO_0_READ_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ca_common_shared_rptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+
+
+ shrm->ac_audio_shared_wptr =
+ (void __iomem *)ioremap(SHM_ACFIFO_1_WRITE_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ac_audio_shared_wptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+
+
+ shrm->ac_audio_shared_rptr =
+ (void __iomem *)ioremap(SHM_ACFIFO_1_READ_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ac_audio_shared_rptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+
+
+ shrm->ca_audio_shared_wptr =
+ (void __iomem *)ioremap(SHM_CAFIFO_1_WRITE_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ca_audio_shared_wptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+
+
+ shrm->ca_audio_shared_rptr =
+ (void __iomem *)ioremap(SHM_CAFIFO_1_READ_AMCU, SHM_PTR_SIZE);
+
+ if (!(shrm->ca_audio_shared_rptr)) {
+ dev_err(shrm->dev, "Unable to map register base\n");
+ err = -EBUSY;
+ goto rollback_map;
+ }
+
+
+ if (isa_init(shrm) != 0) {
+ dev_err(shrm->dev, "Driver Initialization Error\n");
+ err = -EBUSY;
+ }
+ /* install handlers and tasklets */
+ if (shm_initialise_irq(shrm)) {
+ dev_err(shrm->dev, "shm error in interrupt registration\n");
+ goto rollback_irq;
+ }
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+ hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ timer.function = callback;
+
+ hrtimer_start(&timer, ktime_set(0, 2*NSEC_PER_MSEC), HRTIMER_MODE_REL);
+#endif
+
+ return err;
+
+rollback_irq:
+ free_shm_irq(shrm);
+rollback_map:
+ iounmap(shrm->ac_common_shared_wptr);
+ iounmap(shrm->ac_common_shared_rptr);
+ iounmap(shrm->ca_common_shared_wptr);
+ iounmap(shrm->ca_common_shared_rptr);
+ iounmap(shrm->ac_audio_shared_wptr);
+ iounmap(shrm->ac_audio_shared_rptr);
+ iounmap(shrm->ca_audio_shared_wptr);
+ iounmap(shrm->ca_audio_shared_rptr);
+rollback_ac_common_shared_wptr:
+ iounmap(shrm->cmt_audio_fifo_base);
+rollback_cmt_audio_fifo_base:
+ iounmap(shrm->ape_audio_fifo_base);
+rollback_ape_audio_fifo_base:
+ iounmap(shrm->cmt_common_fifo_base);
+rollback_cmt_common_fifo_base:
+ iounmap(shrm->ape_common_fifo_base);
+rollback_ape_common_fifo_base:
+ iounmap(shrm->intr_base);
+rollback_intr:
+ kfree(shrm);
+ return err;
+}
+
+static int __exit shrm_remove(struct platform_device *pdev)
+{
+ struct shrm_dev *shrm = platform_get_drvdata(pdev);
+
+ free_shm_irq(shrm);
+ iounmap(shrm->intr_base);
+ iounmap(shrm->ape_common_fifo_base);
+ iounmap(shrm->cmt_common_fifo_base);
+ iounmap(shrm->ape_audio_fifo_base);
+ iounmap(shrm->cmt_audio_fifo_base);
+ iounmap(shrm->ac_common_shared_wptr);
+ iounmap(shrm->ac_common_shared_rptr);
+ iounmap(shrm->ca_common_shared_wptr);
+ iounmap(shrm->ca_common_shared_rptr);
+ iounmap(shrm->ac_audio_shared_wptr);
+ iounmap(shrm->ac_audio_shared_rptr);
+ iounmap(shrm->ca_audio_shared_wptr);
+ iounmap(shrm->ca_audio_shared_rptr);
+ kfree(shrm);
+ isa_exit(shrm);
+
+ return 0;
+}
+#ifdef CONFIG_PM
+
+/**
+ * u8500_shrm_suspend() - This routine puts the SHRM in to sustend state.
+ * @pdev: platform device.
+ *
+ * This routine checks the current ongoing communication with Modem by
+ * examining the ca_wake state and prevents suspend if modem communication
+ * is on-going.
+ * If ca_wake = 1 (high), modem comm. is on-going; don't suspend
+ * If ca_wake = 0 (low), no comm. with modem on-going.Allow suspend
+ */
+int u8500_shrm_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct shrm_dev *shrm = platform_get_drvdata(pdev);
+
+ dev_dbg(shrm->dev, "%s called...\n", __func__);
+ dev_dbg(shrm->dev, "\n ca_wake_req_state = %x\n",
+ get_ca_wake_req_state());
+ /* if ca_wake_req is high, prevent system suspend */
+ if (get_ca_wake_req_state())
+ return -EBUSY;
+ else
+ return 0;
+}
+
+/**
+ * u8500_shrm_resume() - This routine resumes the SHRM from sustend state.
+ * @pdev: platform device.
+ *
+ * This routine restore back the current state of the SHRM
+ */
+int u8500_shrm_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct shrm_dev *shrm = platform_get_drvdata(pdev);
+
+ dev_dbg(shrm->dev, "%s called...\n", __func__);
+ /* TODO:
+ * As of now, no state save takes place in suspend.
+ * So, nothing to restore in resume.
+ * Simply return as of now.
+ * State saved in suspend should be restored here.
+ */
+
+ return 0;
+}
+
+static const struct dev_pm_ops shrm_dev_pm_ops = {
+ .suspend = u8500_shrm_suspend,
+ .resume = u8500_shrm_resume,
+};
+#endif
+
+static struct platform_driver shrm_driver = {
+ .probe = shrm_probe,
+ .remove = __exit_p(shrm_remove),
+ .driver = {
+ .name = "u8500_shrm",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &shrm_dev_pm_ops,
+#endif
+ },
+};
+
+static int __init shrm_driver_init(void)
+{
+ return platform_driver_probe(&shrm_driver, shrm_probe);
+}
+
+static void __exit shrm_driver_exit(void)
+{
+ platform_driver_unregister(&shrm_driver);
+}
+
+module_init(shrm_driver_init);
+module_exit(shrm_driver_exit);
+
+MODULE_AUTHOR("Biju Das");
+MODULE_DESCRIPTION("Shared Memory Modem Driver Interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/shrm/shrm_fifo.c b/drivers/misc/shrm/shrm_fifo.c
new file mode 100644
index 00000000000..c1fbfe088e9
--- /dev/null
+++ b/drivers/misc/shrm/shrm_fifo.c
@@ -0,0 +1,757 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson
+ * Author: Kumar Sanghavi <kumar.sanghvi@stericsson.com> for ST-Ericsson
+ * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <mach/shrm.h>
+#include <mach/shrm_driver.h>
+#include <mach/shrm_private.h>
+
+#define L1_BOOT_INFO_REQ 1
+#define L1_BOOT_INFO_RESP 2
+#define L1_NORMAL_MSG 3
+#define L1_HEADER_MASK 28
+#define L1_MAPID_MASK 0xF0000000
+#define CONFIG_OFFSET 8
+#define COUNTER_OFFSET 20
+#define L2_HEADER_SIZE 4
+#define L2_HEADER_OFFSET 24
+#define MASK_0_15_BIT 0xFF
+#define MASK_16_31_BIT 0xFF00
+#define MASK_0_39_BIT 0xFFFFF
+#define MASK_40_55_BIT 0xFF00000
+
+static u8 msg_audio_counter;
+static u8 msg_common_counter;
+
+struct fifo_write_params ape_shm_fifo_0;
+struct fifo_write_params ape_shm_fifo_1;
+struct fifo_read_params cmt_shm_fifo_0;
+struct fifo_read_params cmt_shm_fifo_1;
+
+
+static u8 cmt_read_notif_0_send;
+static u8 cmt_read_notif_1_send;
+
+void shm_fifo_init(struct shrm_dev *shrm)
+{
+ ape_shm_fifo_0.writer_local_wptr = 0;
+ ape_shm_fifo_0.writer_local_rptr = 0;
+ *((u32 *)shrm->ac_common_shared_wptr) = 0;
+ *((u32 *)shrm->ac_common_shared_rptr) = 0;
+ ape_shm_fifo_0.shared_wptr = 0;
+ ape_shm_fifo_0.shared_rptr = 0;
+ ape_shm_fifo_0.availablesize = shrm->ape_common_fifo_size;
+ ape_shm_fifo_0.end_addr_fifo = shrm->ape_common_fifo_size;
+ ape_shm_fifo_0.fifo_virtual_addr = shrm->ape_common_fifo_base;
+
+
+ cmt_shm_fifo_0.reader_local_rptr = 0;
+ cmt_shm_fifo_0.reader_local_wptr = 0;
+ cmt_shm_fifo_0.shared_wptr =
+ *((u32 *)shrm->ca_common_shared_wptr);
+ cmt_shm_fifo_0.shared_rptr =
+ *((u32 *)shrm->ca_common_shared_rptr);
+ cmt_shm_fifo_0.availablesize = shrm->cmt_common_fifo_size;
+ cmt_shm_fifo_0.end_addr_fifo = shrm->cmt_common_fifo_size;
+ cmt_shm_fifo_0.fifo_virtual_addr = shrm->cmt_common_fifo_base;
+
+ ape_shm_fifo_1.writer_local_wptr = 0;
+ ape_shm_fifo_1.writer_local_rptr = 0;
+ ape_shm_fifo_1.shared_wptr = 0;
+ ape_shm_fifo_1.shared_rptr = 0;
+ *((u32 *)shrm->ac_audio_shared_wptr) = 0;
+ *((u32 *)shrm->ac_audio_shared_rptr) = 0;
+ ape_shm_fifo_1.availablesize = shrm->ape_audio_fifo_size;
+ ape_shm_fifo_1.end_addr_fifo = shrm->ape_audio_fifo_size;
+ ape_shm_fifo_1.fifo_virtual_addr = shrm->ape_audio_fifo_base;
+
+ cmt_shm_fifo_1.reader_local_rptr = 0;
+ cmt_shm_fifo_1.reader_local_wptr = 0;
+ cmt_shm_fifo_1.shared_wptr =
+ *((u32 *)shrm->ca_audio_shared_wptr);
+ cmt_shm_fifo_1.shared_rptr =
+ *((u32 *)shrm->ca_audio_shared_rptr);
+ cmt_shm_fifo_1.availablesize = shrm->cmt_audio_fifo_size;
+ cmt_shm_fifo_1.end_addr_fifo = shrm->cmt_audio_fifo_size;
+ cmt_shm_fifo_1.fifo_virtual_addr = shrm->cmt_audio_fifo_base;
+}
+
+u8 read_boot_info_req(struct shrm_dev *shrm,
+ u32 *config,
+ u32 *version)
+{
+ struct fifo_read_params *fifo = &cmt_shm_fifo_0;
+ u32 *msg;
+ u32 header = 0;
+ u8 msgtype;
+
+ /* Read L1 header read content of reader_local_rptr */
+ msg = (u32 *)
+ (fifo->reader_local_rptr + fifo->fifo_virtual_addr);
+ header = *msg;
+ msgtype = (header & L1_MAPID_MASK) >> L1_MSG_MAPID_OFFSET;
+ if (msgtype != L1_BOOT_INFO_REQ) {
+ dev_err(shrm->dev, "Read_Boot_Info_Req Fatal ERROR\n");
+ BUG();
+ }
+ *config = (header >> CONFIG_OFFSET) & MASK_0_15_BIT;
+ *version = header & MASK_0_15_BIT;
+ fifo->reader_local_rptr += 1;
+
+ return 1;
+}
+
+void write_boot_info_resp(struct shrm_dev *shrm, u32 config,
+ u32 version)
+{
+ struct fifo_write_params *fifo = &ape_shm_fifo_0;
+ u32 *msg;
+
+ /* Read L1 header read content of reader_local_rptr */
+ msg = (u32 *)
+ (fifo->writer_local_wptr+fifo->fifo_virtual_addr);
+
+ *msg = ((L1_BOOT_INFO_RESP<<L1_MSG_MAPID_OFFSET) |
+ ((config << CONFIG_OFFSET) & MASK_16_31_BIT)
+ | (version & MASK_0_15_BIT));
+
+ fifo->writer_local_wptr += 1;
+ fifo->availablesize -= 1;
+
+}
+
+/**
+ * shm_write_msg_to_fifo() - write message to FIFO
+ * @shrm: pointer to shrm device information structure
+ * @channel: audio or common channel
+ * @l2header: L2 header or device ID
+ * @addr: pointer to write buffer address
+ * @length: length of mst to write
+ *
+ * Function Which Writes the data into Fifo in IPC zone
+ * It is called from shm_write_msg. This function will copy the msg
+ * from the kernel buffer to FIFO. There are 4 kernel buffers from where
+ * the data is to copied to FIFO one for each of the messages ISI, RPC,
+ * AUDIO and SECURITY. ISI, RPC and SECURITY messages are pushed to FIFO
+ * in commmon channel and AUDIO message is pushed onto audio channel FIFO.
+ */
+int shm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
+ u8 l2header, void *addr, u32 length)
+{
+ struct fifo_write_params *fifo = NULL;
+ u32 l1_header = 0, l2_header = 0;
+ u32 requiredsize;
+ u32 size = 0;
+ u32 *msg;
+ u8 *src;
+
+ if (channel == COMMON_CHANNEL)
+ fifo = &ape_shm_fifo_0;
+ else if (channel == AUDIO_CHANNEL)
+ fifo = &ape_shm_fifo_1;
+ else {
+ dev_err(shrm->dev, "invalid channel\n");
+ return -EINVAL;
+ }
+
+ /* L2 size in 32b */
+ requiredsize = ((length + 3) / 4);
+ /* Add size of L1 & L2 header */
+ requiredsize += 2;
+
+ /* if availablesize = or < requiredsize then error */
+ if (fifo->availablesize <= requiredsize) {
+ /* Fatal ERROR - should never happens */
+ dev_dbg(shrm->dev, "wr_wptr= %x\n",
+ fifo->writer_local_wptr);
+ dev_dbg(shrm->dev, "wr_rptr= %x\n",
+ fifo->writer_local_rptr);
+ dev_dbg(shrm->dev, "shared_wptr= %x\n",
+ fifo->shared_wptr);
+ dev_dbg(shrm->dev, "shared_rptr= %x\n",
+ fifo->shared_rptr);
+ dev_dbg(shrm->dev, "availsize= %x\n",
+ fifo->availablesize);
+ dev_dbg(shrm->dev, "end__fifo= %x\n",
+ fifo->end_addr_fifo);
+ dev_warn(shrm->dev, "Modem is busy, please wait."
+ " c_cnt = %d; a_cnt = %d\n", msg_common_counter,
+ msg_audio_counter);
+ return -EAGAIN;
+ }
+
+ if (channel == COMMON_CHANNEL) {
+ /* build L1 header */
+ l1_header = ((L1_NORMAL_MSG << L1_MSG_MAPID_OFFSET) |
+ (((msg_common_counter++) << COUNTER_OFFSET)
+ & MASK_40_55_BIT) |
+ ((length + L2_HEADER_SIZE) & MASK_0_39_BIT));
+ } else if (channel == AUDIO_CHANNEL) {
+ /* build L1 header */
+ l1_header = ((L1_NORMAL_MSG << L1_MSG_MAPID_OFFSET) |
+ (((msg_audio_counter++) << COUNTER_OFFSET)
+ & MASK_40_55_BIT) |
+ ((length + L2_HEADER_SIZE) & MASK_0_39_BIT));
+ }
+
+ /*
+ * Need to take care race condition for fifo->availablesize
+ * & fifo->writer_local_rptr with Ac_Read_notification interrupt.
+ * One option could be use stack variable for LocalRptr and recompute
+ * fifo->availablesize,based on flag enabled in the
+ * Ac_read_notification
+ */
+ l2_header = ((l2header << L2_HEADER_OFFSET) |
+ ((length) & MASK_0_39_BIT));
+ /* Check Local Rptr is less than or equal to Local WPtr */
+ if (fifo->writer_local_rptr <= fifo->writer_local_wptr) {
+ msg = (u32 *)
+ (fifo->fifo_virtual_addr+fifo->writer_local_wptr);
+
+ /* check enough place bewteen writer_local_wptr & end of FIFO */
+ if ((fifo->end_addr_fifo-fifo->writer_local_wptr) >=
+ requiredsize) {
+ /* Add L1 header and L2 header */
+ *msg = l1_header;
+ msg++;
+ *msg = l2_header;
+ msg++;
+
+ /* copy the l2 message in 1 memcpy */
+ memcpy((void *)msg, addr, length);
+ /* UpdateWptr */
+ fifo->writer_local_wptr += requiredsize;
+ fifo->availablesize -= requiredsize;
+ fifo->writer_local_wptr %= fifo->end_addr_fifo;
+ } else {
+ /*
+ * message is split between and of FIFO and beg of FIFO
+ * copy first part from writer_local_wptr to end of FIFO
+ */
+ size = fifo->end_addr_fifo-fifo->writer_local_wptr;
+
+ if (size == 1) {
+ /* Add L1 header */
+ *msg = l1_header;
+ msg++;
+ /* UpdateWptr */
+ fifo->writer_local_wptr = 0;
+ fifo->availablesize -= size;
+ /*
+ * copy second part from beg of FIFO
+ * with remaining part of msg
+ */
+ msg = (u32 *)
+ fifo->fifo_virtual_addr;
+ *msg = l2_header;
+ msg++;
+
+ /* copy the l3 message in 1 memcpy */
+ memcpy((void *)msg, addr, length);
+ /* UpdateWptr */
+ fifo->writer_local_wptr +=
+ requiredsize-size;
+ fifo->availablesize -=
+ (requiredsize-size);
+ } else if (size == 2) {
+ /* Add L1 header and L2 header */
+ *msg = l1_header;
+ msg++;
+ *msg = l2_header;
+ msg++;
+
+ /* UpdateWptr */
+ fifo->writer_local_wptr = 0;
+ fifo->availablesize -= size;
+
+ /*
+ * copy second part from beg of FIFO
+ * with remaining part of msg
+ */
+ msg = (u32 *)
+ fifo->fifo_virtual_addr;
+ /* copy the l3 message in 1 memcpy */
+ memcpy((void *)msg, addr, length);
+
+ /* UpdateWptr */
+ fifo->writer_local_wptr +=
+ requiredsize-size;
+ fifo->availablesize -=
+ (requiredsize-size);
+ } else {
+ /* Add L1 header and L2 header */
+ *msg = l1_header;
+ msg++;
+ *msg = l2_header;
+ msg++;
+
+ /* copy the l2 message in 1 memcpy */
+ memcpy((void *)msg, addr, (size-2)*4);
+
+ /* UpdateWptr */
+ fifo->writer_local_wptr = 0;
+ fifo->availablesize -= size;
+
+ /*
+ * copy second part from beg of FIFO
+ * with remaining part of msg
+ */
+ msg = (u32 *)fifo->fifo_virtual_addr;
+ src = (u8 *)addr+((size - 2) * 4);
+ memcpy((void *)msg, src,
+ (length-((size - 2) * 4)));
+
+ /* UpdateWptr */
+ fifo->writer_local_wptr +=
+ requiredsize-size;
+ fifo->availablesize -=
+ (requiredsize-size);
+ }
+
+ }
+ } else {
+ /* writer_local_rptr > writer_local_wptr */
+ msg = (u32 *)
+ (fifo->fifo_virtual_addr+fifo->writer_local_wptr);
+ /* Add L1 header and L2 header */
+ *msg = l1_header;
+ msg++;
+ *msg = l2_header;
+ msg++;
+ /*
+ * copy message possbile between writer_local_wptr up
+ * to writer_local_rptr copy the l3 message in 1 memcpy
+ */
+ memcpy((void *)msg, addr, length);
+ /* UpdateWptr */
+ fifo->writer_local_wptr += requiredsize;
+ fifo->availablesize -= requiredsize;
+
+ }
+ return length;
+}
+
+/**
+ * read_one_l2msg_common() - read message from common channel
+ * @shrm: pointer to shrm device information structure
+ * @l2_msg: pointer to the read L2 message buffer
+ * @len: message length
+ *
+ * This function read one message from the FIFO and returns l2 header type
+ */
+u8 read_one_l2msg_common(struct shrm_dev *shrm,
+ u8 *l2_msg, u32 *len)
+{
+ struct fifo_read_params *fifo = &cmt_shm_fifo_0;
+
+ u32 *msg;
+ u32 l1_header = 0;
+ u32 l2_header = 0;
+ u32 length;
+ u8 msgtype;
+ u32 msg_size;
+ u32 size = 0;
+
+ /* Read L1 header read content of reader_local_rptr */
+ msg = (u32 *)
+ (fifo->reader_local_rptr+fifo->fifo_virtual_addr);
+ l1_header = *msg++;
+ msgtype = (l1_header & 0xF0000000) >> L1_HEADER_MASK;
+
+ if (msgtype != L1_NORMAL_MSG) {
+ /* Fatal ERROR - should never happens */
+ dev_dbg(shrm->dev, "wr_wptr= %x\n",
+ fifo->reader_local_wptr);
+ dev_dbg(shrm->dev, "wr_rptr= %x\n",
+ fifo->reader_local_rptr);
+ dev_dbg(shrm->dev, "shared_wptr= %x\n",
+ fifo->shared_wptr);
+ dev_dbg(shrm->dev, "shared_rptr= %x\n",
+ fifo->shared_rptr);
+ dev_dbg(shrm->dev, "availsize= %x\n",
+ fifo->availablesize);
+ dev_dbg(shrm->dev, "end_fifo= %x\n",
+ fifo->end_addr_fifo);
+ /* Fatal ERROR - should never happens */
+ dev_crit(shrm->dev, "Fatal ERROR - should never happen\n");
+ BUG();
+ }
+ if (fifo->reader_local_rptr == (fifo->end_addr_fifo-1)) {
+ l2_header = (*((u32 *)fifo->fifo_virtual_addr));
+ length = l2_header & MASK_0_39_BIT;
+ } else {
+ /* Read L2 header,Msg size & content of reader_local_rptr */
+ l2_header = *msg;
+ length = l2_header & MASK_0_39_BIT;
+ }
+
+ *len = length;
+ msg_size = ((length + 3) / 4);
+ msg_size += 2;
+
+ if (fifo->reader_local_rptr + msg_size <=
+ fifo->end_addr_fifo) {
+ /* Skip L2 header */
+ msg++;
+
+ /* read msg between reader_local_rptr and end of FIFO */
+ memcpy((void *)l2_msg, (void *)msg, length);
+ /* UpdateLocalRptr */
+ fifo->reader_local_rptr += msg_size;
+ fifo->reader_local_rptr %= fifo->end_addr_fifo;
+ } else {
+ /*
+ * msg split between end of FIFO and beg copy first
+ * part of msg read msg between reader_local_rptr
+ * and end of FIFO
+ */
+ size = fifo->end_addr_fifo-fifo->reader_local_rptr;
+ if (size == 1) {
+ msg = (u32 *)(fifo->fifo_virtual_addr);
+ /* Skip L2 header */
+ msg++;
+ memcpy((void *)l2_msg, (void *)(msg), length);
+ } else if (size == 2) {
+ /* Skip L2 header */
+ msg++;
+ msg = (u32 *)(fifo->fifo_virtual_addr);
+ memcpy((void *)l2_msg,
+ (void *)(msg), length);
+ } else {
+ /* Skip L2 header */
+ msg++;
+ memcpy((void *)l2_msg, (void *)msg, ((size - 2) * 4));
+ /* copy second part of msg */
+ l2_msg += ((size - 2) * 4);
+ msg = (u32 *)(fifo->fifo_virtual_addr);
+ memcpy((void *)l2_msg, (void *)(msg),
+ (length-((size - 2) * 4)));
+ }
+ fifo->reader_local_rptr =
+ (fifo->reader_local_rptr+msg_size) %
+ fifo->end_addr_fifo;
+ }
+ return (l2_header>>L2_HEADER_OFFSET) & MASK_0_15_BIT;
+ }
+
+u8 read_remaining_messages_common()
+{
+ struct fifo_read_params *fifo = &cmt_shm_fifo_0;
+ /*
+ * There won't be any Race condition reader_local_rptr &
+ * fifo->reader_local_wptr with CaMsgpending Notification Interrupt
+ */
+ return ((fifo->reader_local_rptr != fifo->reader_local_wptr) ? 1 : 0);
+}
+
+u8 read_one_l2msg_audio(struct shrm_dev *shrm,
+ u8 *l2_msg, u32 *len)
+{
+ struct fifo_read_params *fifo = &cmt_shm_fifo_1;
+
+ u32 *msg;
+ u32 l1_header = 0;
+ u32 l2_header = 0;
+ u32 length;
+ u8 msgtype;
+ u32 msg_size;
+ u32 size = 0;
+
+ /* Read L1 header read content of reader_local_rptr */
+ msg = (u32 *)
+ (fifo->reader_local_rptr+fifo->fifo_virtual_addr);
+ l1_header = *msg++;
+ msgtype = (l1_header & 0xF0000000) >> L1_HEADER_MASK;
+
+ if (msgtype != L1_NORMAL_MSG) {
+ /* Fatal ERROR - should never happens */
+ dev_dbg(shrm->dev, "wr_local_wptr= %x\n",
+ fifo->reader_local_wptr);
+ dev_dbg(shrm->dev, "wr_local_rptr= %x\n",
+ fifo->reader_local_rptr);
+ dev_dbg(shrm->dev, "shared_wptr= %x\n",
+ fifo->shared_wptr);
+ dev_dbg(shrm->dev, "shared_rptr= %x\n",
+ fifo->shared_rptr);
+ dev_dbg(shrm->dev, "availsize=%x\n",
+ fifo->availablesize);
+ dev_dbg(shrm->dev, "end_fifo= %x\n",
+ fifo->end_addr_fifo);
+ /* Fatal ERROR - should never happens */
+ dev_crit(shrm->dev, "Fatal ERROR - should never happen\n");
+ BUG();
+ }
+ if (fifo->reader_local_rptr == (fifo->end_addr_fifo-1)) {
+ l2_header = (*((u32 *)fifo->fifo_virtual_addr));
+ length = l2_header & MASK_0_39_BIT;
+ } else {
+ /* Read L2 header,Msg size & content of reader_local_rptr */
+ l2_header = *msg;
+ length = l2_header & MASK_0_39_BIT;
+ }
+
+ *len = length;
+ msg_size = ((length + 3) / 4);
+ msg_size += 2;
+
+ if (fifo->reader_local_rptr + msg_size <=
+ fifo->end_addr_fifo) {
+ /* Skip L2 header */
+ msg++;
+ /* read msg between reader_local_rptr and end of FIFO */
+ memcpy((void *)l2_msg, (void *)msg, length);
+ /* UpdateLocalRptr */
+ fifo->reader_local_rptr += msg_size;
+ fifo->reader_local_rptr %= fifo->end_addr_fifo;
+ } else {
+
+ /*
+ * msg split between end of FIFO and beg
+ * copy first part of msg
+ * read msg between reader_local_rptr and end of FIFO
+ */
+ size = fifo->end_addr_fifo-fifo->reader_local_rptr;
+ if (size == 1) {
+ msg = (u32 *)(fifo->fifo_virtual_addr);
+ /* Skip L2 header */
+ msg++;
+ memcpy((void *)l2_msg, (void *)(msg), length);
+ } else if (size == 2) {
+ /* Skip L2 header */
+ msg++;
+ msg = (u32 *)(fifo->fifo_virtual_addr);
+ memcpy((void *)l2_msg, (void *)(msg), length);
+ } else {
+ /* Skip L2 header */
+ msg++;
+ memcpy((void *)l2_msg, (void *)msg, ((size - 2) * 4));
+ /* copy second part of msg */
+ l2_msg += ((size - 2) * 4);
+ msg = (u32 *)(fifo->fifo_virtual_addr);
+ memcpy((void *)l2_msg, (void *)(msg),
+ (length-((size - 2) * 4)));
+ }
+ fifo->reader_local_rptr =
+ (fifo->reader_local_rptr+msg_size) %
+ fifo->end_addr_fifo;
+
+ }
+ return (l2_header>>L2_HEADER_OFFSET) & MASK_0_15_BIT;
+ }
+
+u8 read_remaining_messages_audio()
+{
+ struct fifo_read_params *fifo = &cmt_shm_fifo_1;
+
+ return ((fifo->reader_local_rptr != fifo->reader_local_wptr) ?
+ 1 : 0);
+}
+
+u8 is_the_only_one_unread_message(struct shrm_dev *shrm,
+ u8 channel, u32 length)
+{
+ struct fifo_write_params *fifo = NULL;
+ u32 messagesize = 0;
+ u8 is_only_one_unread_msg = 0;
+
+ if (channel == COMMON_CHANNEL)
+ fifo = &ape_shm_fifo_0;
+ else /* channel = AUDIO_CHANNEL */
+ fifo = &ape_shm_fifo_1;
+
+ /* L3 size in 32b */
+ messagesize = ((length + 3) / 4);
+ /* Add size of L1 & L2 header */
+ messagesize += 2;
+ /*
+ * possibility of race condition with Ac Read notification interrupt.
+ * need to check ?
+ */
+ if (fifo->writer_local_wptr > fifo->writer_local_rptr)
+ is_only_one_unread_msg =
+ ((fifo->writer_local_rptr + messagesize) ==
+ fifo->writer_local_wptr) ? 1 : 0;
+ else
+ /* Msg split between end of fifo and starting of Fifo */
+ is_only_one_unread_msg =
+ (((fifo->writer_local_rptr + messagesize) %
+ fifo->end_addr_fifo) == fifo->writer_local_wptr) ?
+ 1 : 0;
+
+ return is_only_one_unread_msg;
+}
+
+void update_ca_common_reader_local_wptr_with_shared_wptr(
+ struct shrm_dev *shrm)
+{
+ struct fifo_read_params *fifo = &cmt_shm_fifo_0;
+
+ fifo->shared_wptr =
+ (*((u32 *)shrm->ca_common_shared_wptr));
+ fifo->reader_local_wptr = fifo->shared_wptr;
+}
+
+void update_ca_audio_reader_local_wptr_with_shared_wptr(
+ struct shrm_dev *shrm)
+{
+ struct fifo_read_params *fifo = &cmt_shm_fifo_1;
+
+ fifo->shared_wptr =
+ (*((u32 *)shrm->ca_audio_shared_wptr));
+ fifo->reader_local_wptr = fifo->shared_wptr;
+}
+
+void update_ac_common_writer_local_rptr_with_shared_rptr(
+ struct shrm_dev *shrm)
+{
+ struct fifo_write_params *fifo;
+ u32 free_space = 0;
+
+ fifo = &ape_shm_fifo_0;
+
+ fifo->shared_rptr =
+ (*((u32 *)shrm->ac_common_shared_rptr));
+
+ if (fifo->shared_rptr >= fifo->writer_local_rptr)
+ free_space =
+ (fifo->shared_rptr-fifo->writer_local_rptr);
+ else {
+ free_space =
+ (fifo->end_addr_fifo-fifo->writer_local_rptr);
+ free_space += fifo->shared_rptr;
+ }
+
+ /* Chance of race condition of below variables with write_msg */
+ fifo->availablesize += free_space;
+ fifo->writer_local_rptr = fifo->shared_rptr;
+}
+
+void update_ac_audio_writer_local_rptr_with_shared_rptr(
+ struct shrm_dev *shrm)
+{
+ struct fifo_write_params *fifo;
+ u32 free_space = 0;
+
+ fifo = &ape_shm_fifo_1;
+ fifo->shared_rptr =
+ (*((u32 *)shrm->ac_audio_shared_rptr));
+
+ if (fifo->shared_rptr >= fifo->writer_local_rptr)
+ free_space =
+ (fifo->shared_rptr-fifo->writer_local_rptr);
+ else {
+ free_space =
+ (fifo->end_addr_fifo-fifo->writer_local_rptr);
+ free_space += fifo->shared_rptr;
+ }
+
+ /* Chance of race condition of below variables with write_msg */
+ fifo->availablesize += free_space;
+ fifo->writer_local_rptr = fifo->shared_rptr;
+}
+
+void update_ac_common_shared_wptr_with_writer_local_wptr(
+ struct shrm_dev *shrm)
+{
+ struct fifo_write_params *fifo;
+
+ fifo = &ape_shm_fifo_0;
+ /* Update shared pointer fifo offset of the IPC zone */
+ (*((u32 *)shrm->ac_common_shared_wptr)) =
+ fifo->writer_local_wptr;
+
+ fifo->shared_wptr = fifo->writer_local_wptr;
+}
+
+void update_ac_audio_shared_wptr_with_writer_local_wptr(
+ struct shrm_dev *shrm)
+{
+ struct fifo_write_params *fifo;
+
+ fifo = &ape_shm_fifo_1;
+ /* Update shared pointer fifo offset of the IPC zone */
+ (*((u32 *)shrm->ac_audio_shared_wptr)) =
+ fifo->writer_local_wptr;
+ fifo->shared_wptr = fifo->writer_local_wptr;
+}
+
+void update_ca_common_shared_rptr_with_reader_local_rptr(
+ struct shrm_dev *shrm)
+{
+ struct fifo_read_params *fifo;
+
+ fifo = &cmt_shm_fifo_0;
+
+ /* Update shared pointer fifo offset of the IPC zone */
+ (*((u32 *)shrm->ca_common_shared_rptr)) =
+ fifo->reader_local_rptr;
+ fifo->shared_rptr = fifo->reader_local_rptr;
+}
+
+void update_ca_audio_shared_rptr_with_reader_local_rptr(
+ struct shrm_dev *shrm)
+{
+ struct fifo_read_params *fifo;
+
+ fifo = &cmt_shm_fifo_1;
+
+ /* Update shared pointer fifo offset of the IPC zone */
+ (*((u32 *)shrm->ca_audio_shared_rptr)) =
+ fifo->reader_local_rptr;
+ fifo->shared_rptr = fifo->reader_local_rptr;
+}
+
+void get_reader_pointers(u8 channel_type, u32 *reader_local_rptr,
+ u32 *reader_local_wptr, u32 *shared_rptr)
+{
+ struct fifo_read_params *fifo = NULL;
+
+ if (channel_type == COMMON_CHANNEL)
+ fifo = &cmt_shm_fifo_0;
+ else /* channel_type = AUDIO_CHANNEL */
+ fifo = &cmt_shm_fifo_1;
+
+ *reader_local_rptr = fifo->reader_local_rptr;
+ *reader_local_wptr = fifo->reader_local_wptr;
+ *shared_rptr = fifo->shared_rptr;
+}
+
+void get_writer_pointers(u8 channel_type, u32 *writer_local_rptr,
+ u32 *writer_local_wptr, u32 *shared_wptr)
+{
+ struct fifo_write_params *fifo = NULL;
+
+ if (channel_type == COMMON_CHANNEL)
+ fifo = &ape_shm_fifo_0;
+ else /* channel_type = AUDIO_CHANNEL */
+ fifo = &ape_shm_fifo_1;
+
+ *writer_local_rptr = fifo->writer_local_rptr;
+ *writer_local_wptr = fifo->writer_local_wptr;
+ *shared_wptr = fifo->shared_wptr;
+}
+
+void set_ca_msg_0_read_notif_send(u8 val)
+{
+ cmt_read_notif_0_send = val;
+}
+
+u8 get_ca_msg_0_read_notif_send(void)
+{
+ return cmt_read_notif_0_send;
+}
+
+void set_ca_msg_1_read_notif_send(u8 val)
+{
+ cmt_read_notif_1_send = val;
+}
+
+u8 get_ca_msg_1_read_notif_send(void)
+{
+ return cmt_read_notif_1_send;
+}
diff --git a/drivers/misc/shrm/shrm_protocol.c b/drivers/misc/shrm/shrm_protocol.c
new file mode 100644
index 00000000000..f6bf7e47bd5
--- /dev/null
+++ b/drivers/misc/shrm/shrm_protocol.c
@@ -0,0 +1,1157 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson
+ * Author: Kumar Sanghavi <kumar.sanghvi@stericsson.com> for ST-Ericsson
+ * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/netlink.h>
+
+#include <mach/shrm.h>
+#include <mach/shrm_driver.h>
+#include <mach/shrm_private.h>
+#include <mach/shrm_net.h>
+#include <mach/prcmu-fw-api.h>
+#include <mach/prcmu-regs.h>
+
+#define L2_HEADER_ISI 0x0
+#define L2_HEADER_RPC 0x1
+#define L2_HEADER_AUDIO 0x2
+#define L2_HEADER_SECURITY 0x3
+#define L2_HEADER_COMMON_SIMPLE_LOOPBACK 0xC0
+#define L2_HEADER_COMMON_ADVANCED_LOOPBACK 0xC1
+#define L2_HEADER_AUDIO_SIMPLE_LOOPBACK 0x80
+#define L2_HEADER_AUDIO_ADVANCED_LOOPBACK 0x81
+#define MAX_PAYLOAD 1024
+
+static u8 boot_state = BOOT_INIT;
+static u8 recieve_common_msg[8*1024];
+static u8 recieve_audio_msg[8*1024];
+static received_msg_handler rx_common_handler;
+static received_msg_handler rx_audio_handler;
+static struct hrtimer timer;
+static char is_earlydrop;
+static char hr_timer_status;
+struct sock *shrm_nl_sk;
+
+static char shrm_common_tx_state = SHRM_SLEEP_STATE;
+static char shrm_common_rx_state = SHRM_SLEEP_STATE;
+static char shrm_audio_tx_state = SHRM_SLEEP_STATE;
+static char shrm_audio_rx_state = SHRM_SLEEP_STATE;
+
+/*
+ * state of ca_wake_req
+ * ca_wake_req_state = 1 indicates ca_wake_req is high
+ * ca_wake_req_state = 0 indicates ca_wake_req is low
+ */
+static int ca_wake_req_state;
+static struct shrm_dev *shm_dev;
+static int msr_flag;
+
+/* Spin lock and tasklet declaration */
+DECLARE_TASKLET(shm_ca_0_tasklet, shm_ca_msgpending_0_tasklet, 0);
+DECLARE_TASKLET(shm_ca_1_tasklet, shm_ca_msgpending_1_tasklet, 0);
+DECLARE_TASKLET(shm_ac_read_0_tasklet, shm_ac_read_notif_0_tasklet, 0);
+DECLARE_TASKLET(shm_ac_read_1_tasklet, shm_ac_read_notif_1_tasklet, 0);
+DECLARE_TASKLET(shm_ca_wake_tasklet, shm_ca_wake_req_tasklet, 0);
+
+spinlock_t ca_common_lock ;
+spinlock_t ca_audio_lock ;
+spinlock_t ca_wake_req_lock;
+spinlock_t boot_lock;
+
+enum shrm_nl {
+ SHRM_NL_MOD_RESET = 1,
+ SHRM_NL_MOD_QUERY_STATE,
+ SHRM_NL_USER_MOD_RESET,
+ SHRM_NL_STATUS_MOD_ONLINE,
+ SHRM_NL_STATUS_MOD_OFFLINE,
+};
+
+static u32 get_host_accessport_val(void)
+{
+ u32 prcm_hostaccess;
+
+ prcm_hostaccess = readl(PRCM_HOSTACCESS_REQ);
+ wmb();
+ prcm_hostaccess = prcm_hostaccess & 0x01;
+
+ return prcm_hostaccess;
+}
+static enum hrtimer_restart callback(struct hrtimer *timer)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ca_wake_req_lock, flags);
+ if (((shrm_common_rx_state == SHRM_IDLE) ||
+ (shrm_common_rx_state == SHRM_SLEEP_STATE))
+ && ((shrm_common_tx_state == SHRM_IDLE) ||
+ (shrm_common_tx_state == SHRM_SLEEP_STATE))
+ && ((shrm_audio_rx_state == SHRM_IDLE) ||
+ (shrm_audio_rx_state == SHRM_SLEEP_STATE))
+ && ((shrm_audio_tx_state == SHRM_IDLE) ||
+ (shrm_audio_tx_state == SHRM_SLEEP_STATE))) {
+
+ shrm_common_rx_state = SHRM_SLEEP_STATE;
+ shrm_audio_rx_state = SHRM_SLEEP_STATE;
+ shrm_common_tx_state = SHRM_SLEEP_STATE;
+ shrm_audio_tx_state = SHRM_SLEEP_STATE;
+
+ prcmu_ac_sleep_req();
+
+ }
+ hr_timer_status = 0;
+ spin_unlock_irqrestore(&ca_wake_req_lock, flags);
+
+ return HRTIMER_NORESTART;
+}
+
+void shm_ca_wake_req_tasklet(unsigned long tasklet_data)
+{
+ struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+ /* initialize the FIFO Variables */
+ if (boot_state == BOOT_INIT)
+ shm_fifo_init(shrm);
+
+ /* send ca_wake_ack_interrupt to CMU */
+ writel((1<<GOP_CA_WAKE_ACK_BIT),
+ shrm->intr_base+GOP_SET_REGISTER_BASE);
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+int nl_send_multicast_message(int msg)
+{
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh = NULL;
+ int err;
+
+ /* prepare netlink message */
+ skb = alloc_skb(NLMSG_SPACE(MAX_PAYLOAD), GFP_KERNEL);
+ nlh = (struct nlmsghdr *)skb->data;
+ nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
+ dev_dbg(shm_dev->dev, "nlh->nlmsg_len = %d\n", nlh->nlmsg_len);
+
+ nlh->nlmsg_pid = 0; /* from kernel */
+ nlh->nlmsg_flags = 0;
+ *(int *)NLMSG_DATA(nlh) = msg;
+ skb_put(skb, MAX_PAYLOAD);
+ /* sender is in group 1<<0 */
+ NETLINK_CB(skb).pid = 0; /* from kernel */
+ /* to mcast group 1<<0 */
+ NETLINK_CB(skb).dst_group = 1;
+
+ /*multicast the message to all listening processes*/
+ err = netlink_broadcast(shrm_nl_sk, skb, 0, 1, GFP_KERNEL);
+ dev_dbg(shm_dev->dev, "ret val from nl-multicast = %d\n", err);
+
+ return err;
+}
+
+static void nl_send_unicast_message(int dst_pid)
+{
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh = NULL;
+ int err;
+ int bt_state;
+
+ dev_info(shm_dev->dev, "Sending unicast message\n");
+
+ /* prepare the NL message for unicast */
+ skb = alloc_skb(NLMSG_SPACE(MAX_PAYLOAD), GFP_KERNEL);
+ nlh = (struct nlmsghdr *)skb->data;
+ nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
+ dev_dbg(shm_dev->dev, "nlh->nlmsg_len = %d\n", nlh->nlmsg_len);
+
+ nlh->nlmsg_pid = 0; /* from kernel */
+ nlh->nlmsg_flags = 0;
+
+ spin_lock_bh(&boot_lock);
+ bt_state = boot_state;
+ spin_unlock_bh(&boot_lock);
+
+ if (bt_state == BOOT_DONE)
+ *(int *)NLMSG_DATA(nlh) = SHRM_NL_STATUS_MOD_ONLINE;
+ else
+ *(int *)NLMSG_DATA(nlh) = SHRM_NL_STATUS_MOD_OFFLINE;
+
+ skb_put(skb, MAX_PAYLOAD);
+ /* sender is in group 1<<0 */
+ NETLINK_CB(skb).pid = 0; /* from kernel */
+ NETLINK_CB(skb).dst_group = 0;
+
+ /*unicast the message to the querying processes*/
+ err = netlink_unicast(shrm_nl_sk, skb, dst_pid, MSG_DONTWAIT);
+ dev_dbg(shm_dev->dev, "ret val from nl-unicast = %d\n", err);
+}
+
+
+static int check_modem_in_reset(void)
+{
+ u8 bt_state;
+ unsigned long flags;
+
+ spin_lock_irqsave(&boot_lock, flags);
+ bt_state = boot_state;
+ spin_unlock_irqrestore(&boot_lock, flags);
+
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+ if (bt_state != BOOT_UNKNOWN)
+ return 0;
+ else
+ return -ENODEV;
+#else
+ /*
+ * this check won't be applicable and won't work correctly
+ * if modem-silent-feature is not enabled
+ * so, simply return 0
+ */
+ return 0;
+#endif
+}
+
+void shm_ca_msgpending_0_tasklet(unsigned long tasklet_data)
+{
+ struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+ u32 reader_local_rptr;
+ u32 reader_local_wptr;
+ u32 shared_rptr;
+ u32 config = 0, version = 0;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ /* Interprocess locking */
+ spin_lock(&ca_common_lock);
+
+ /* Update_reader_local_wptr with shared_wptr */
+ update_ca_common_reader_local_wptr_with_shared_wptr(shrm);
+ get_reader_pointers(COMMON_CHANNEL, &reader_local_rptr,
+ &reader_local_wptr, &shared_rptr);
+
+ set_ca_msg_0_read_notif_send(0);
+
+ if (boot_state == BOOT_DONE) {
+ shrm_common_rx_state = SHRM_PTR_FREE;
+
+ if (reader_local_rptr != shared_rptr)
+ ca_msg_read_notification_0(shrm);
+ if (reader_local_rptr != reader_local_wptr)
+ receive_messages_common(shrm);
+ get_reader_pointers(COMMON_CHANNEL, &reader_local_rptr,
+ &reader_local_wptr, &shared_rptr);
+ if (reader_local_rptr == reader_local_wptr)
+ shrm_common_rx_state = SHRM_IDLE;
+ } else {
+ /* BOOT phase.only a BOOT_RESP should be in FIFO */
+ if (boot_state != BOOT_INFO_SYNC) {
+ if (!read_boot_info_req(shrm, &config, &version)) {
+ dev_err(shrm->dev,
+ "Unable to read boot state\n");
+ BUG();
+ }
+ /* SendReadNotification */
+ ca_msg_read_notification_0(shrm);
+ /*
+ * Check the version number before
+ * sending Boot info response
+ */
+
+ /* send MsgPending notification */
+ write_boot_info_resp(shrm, config, version);
+ spin_lock_bh(&boot_lock);
+ boot_state = BOOT_INFO_SYNC;
+ spin_unlock_bh(&boot_lock);
+ dev_info(shrm->dev, "BOOT_INFO_SYNC\n");
+ send_ac_msg_pending_notification_0(shrm);
+ } else {
+ ca_msg_read_notification_0(shrm);
+ dev_info(shrm->dev,
+ "BOOT_INFO_SYNC\n");
+ }
+ }
+ /* Interprocess locking */
+ spin_unlock(&ca_common_lock);
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shm_ca_msgpending_1_tasklet(unsigned long tasklet_data)
+{
+ struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+ u32 reader_local_rptr;
+ u32 reader_local_wptr;
+ u32 shared_rptr;
+
+ /*
+ * This function is called when CaMsgPendingNotification Trigerred
+ * by CMU. It means that CMU has wrote a message into Ca Audio FIFO
+ */
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown\n",
+ __func__);
+ return;
+ }
+
+ /* Interprocess locking */
+ spin_lock(&ca_audio_lock);
+
+ /* Update_reader_local_wptr(with shared_wptr) */
+ update_ca_audio_reader_local_wptr_with_shared_wptr(shrm);
+ get_reader_pointers(AUDIO_CHANNEL, &reader_local_rptr,
+ &reader_local_wptr, &shared_rptr);
+
+ set_ca_msg_1_read_notif_send(0);
+
+ if (boot_state != BOOT_DONE) {
+ dev_err(shrm->dev, "Boot Error\n");
+ return;
+ }
+ shrm_audio_rx_state = SHRM_PTR_FREE;
+ /* Check we already read the message */
+ if (reader_local_rptr != shared_rptr)
+ ca_msg_read_notification_1(shrm);
+ if (reader_local_rptr != reader_local_wptr)
+ receive_messages_audio(shrm);
+
+ get_reader_pointers(AUDIO_CHANNEL, &reader_local_rptr,
+ &reader_local_wptr, &shared_rptr);
+ if (reader_local_rptr == reader_local_wptr)
+ shrm_audio_rx_state = SHRM_IDLE;
+
+ /* Interprocess locking */
+ spin_unlock(&ca_audio_lock);
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shm_ac_read_notif_0_tasklet(unsigned long tasklet_data)
+{
+ struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+ u32 writer_local_rptr;
+ u32 writer_local_wptr;
+ u32 shared_wptr;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ /* Update writer_local_rptrwith shared_rptr */
+ update_ac_common_writer_local_rptr_with_shared_rptr(shrm);
+ get_writer_pointers(COMMON_CHANNEL, &writer_local_rptr,
+ &writer_local_wptr, &shared_wptr);
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown\n",
+ __func__);
+ return;
+ }
+
+ if (boot_state == BOOT_INFO_SYNC) {
+ /* BOOT_RESP sent by APE has been received by CMT */
+ spin_lock_bh(&boot_lock);
+ boot_state = BOOT_DONE;
+ spin_unlock_bh(&boot_lock);
+ dev_info(shrm->dev, "IPC_ISA BOOT_DONE\n");
+
+ if (msr_flag) {
+ shrm_start_netdev(shrm->ndev);
+
+ /* multicast that modem is online */
+ nl_send_multicast_message(SHRM_NL_STATUS_MOD_ONLINE);
+ }
+
+ } else if (boot_state == BOOT_DONE) {
+ if (writer_local_rptr != writer_local_wptr) {
+ shrm_common_tx_state = SHRM_PTR_FREE;
+ send_ac_msg_pending_notification_0(shrm);
+ } else {
+ shrm_common_tx_state = SHRM_IDLE;
+ }
+ } else {
+ dev_err(shrm->dev, "Invalid boot state\n");
+ }
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shm_ac_read_notif_1_tasklet(unsigned long tasklet_data)
+{
+ struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+ u32 writer_local_rptr;
+ u32 writer_local_wptr;
+ u32 shared_wptr;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown\n",
+ __func__);
+ return;
+ }
+
+ /* Update writer_local_rptr(with shared_rptr) */
+ update_ac_audio_writer_local_rptr_with_shared_rptr(shrm);
+ get_writer_pointers(AUDIO_CHANNEL, &writer_local_rptr,
+ &writer_local_wptr, &shared_wptr);
+ if (boot_state != BOOT_DONE) {
+ dev_err(shrm->dev, "Error Case in boot state\n");
+ return;
+ }
+ if (writer_local_rptr != writer_local_wptr) {
+ shrm_audio_tx_state = SHRM_PTR_FREE;
+ send_ac_msg_pending_notification_1(shrm);
+ } else
+ shrm_audio_tx_state = SHRM_IDLE;
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+
+static int shrm_modem_reset_sequence(void)
+{
+ int err;
+
+ /*
+ * disable irqs
+ * very much needed for user-space initiated
+ * modem-reset
+ */
+ disable_irq_nosync(shm_dev->ac_read_notif_0_irq);
+ disable_irq_nosync(shm_dev->ac_read_notif_1_irq);
+ disable_irq_nosync(shm_dev->ca_msg_pending_notif_0_irq);
+ disable_irq_nosync(shm_dev->ca_msg_pending_notif_1_irq);
+ disable_irq_nosync(IRQ_PRCMU_CA_WAKE);
+ disable_irq_nosync(IRQ_PRCMU_CA_SLEEP);
+
+
+ /* update the boot_state */
+ spin_lock_bh(&boot_lock);
+ boot_state = BOOT_UNKNOWN;
+
+ /*
+ * put a barrier over here to make sure boot_state is updated
+ * else, it is seen that some of already executing modem
+ * irqs or tasklets fail the protocol checks and will ultimately
+ * try to acces the modem causing system to hang.
+ * This is particularly seen with user-space initiated modem reset
+ */
+ wmb();
+ spin_unlock_bh(&boot_lock);
+
+ hrtimer_cancel(&timer);
+
+ /* stop network queue */
+ shrm_stop_netdev(shm_dev->ndev);
+
+ /* reset char device queues */
+ shrm_char_reset_queues(shm_dev);
+
+ /* reset protocol states */
+ shrm_common_tx_state = SHRM_SLEEP_STATE;
+ shrm_common_rx_state = SHRM_SLEEP_STATE;
+ shrm_audio_tx_state = SHRM_SLEEP_STATE;
+ shrm_audio_rx_state = SHRM_SLEEP_STATE;
+
+ /* set the msr flag */
+ msr_flag = 1;
+
+ /* multicast that modem is going to reset */
+ err = nl_send_multicast_message(SHRM_NL_MOD_RESET);
+
+ /* reset the boot state */
+ spin_lock_bh(&boot_lock);
+ boot_state = BOOT_INIT;
+ spin_unlock_bh(&boot_lock);
+
+ /* re-enable irqs */
+ enable_irq(shm_dev->ac_read_notif_0_irq);
+ enable_irq(shm_dev->ac_read_notif_1_irq);
+ enable_irq(shm_dev->ca_msg_pending_notif_0_irq);
+ enable_irq(shm_dev->ca_msg_pending_notif_1_irq);
+ enable_irq(IRQ_PRCMU_CA_WAKE);
+ enable_irq(IRQ_PRCMU_CA_SLEEP);
+
+ return err;
+}
+
+static void shrm_modem_reset_callback(unsigned long irq)
+{
+ int err;
+ dev_err(shm_dev->dev, "Received mod_reset_req interrupt\n");
+
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+ dev_info(shm_dev->dev, "Initiating Modem silent reset\n");
+ err = shrm_modem_reset_sequence();
+ if (err)
+ dev_err(shm_dev->dev, "Failed multicast of modem reset\n");
+#else
+ dev_info(shm_dev->dev, "Initiating System reset\n");
+ /* Call the PRCMU reset API */
+ prcmu_system_reset();
+#endif
+}
+
+static void shrm_cawake_callback(unsigned long irq)
+{
+ if (shm_dev == NULL)
+ BUG();
+
+ /*
+ * FIXME:
+ * There is a catch here for user-space inited modem reset (the
+ * non-MCE_RESET_REQ case). Before mLoader completes the
+ * modem re-loading, its possible that modem may send CaWakeReq.
+ * Shrm driver will then interpret it as a start of boot sync phase
+ * and ultimately will lead to error situation.
+ * As a solution, a sleep should be put in modem-reset-sequence.
+ * But this can be done only at the integration camp time.
+ */
+
+ if (check_modem_in_reset()) {
+ dev_err(shm_dev->dev, "%s:Modem state reset or unknown\n",
+ __func__);
+ return;
+ }
+
+ switch (irq) {
+ case IRQ_PRCMU_CA_WAKE:
+ dev_dbg(shm_dev->dev, "%s:IRQ_PRCMU_CA_WAKE\n", __func__);
+ /*initialize the FIFO Variables*/
+ if (boot_state == BOOT_INIT)
+ shm_fifo_init(shm_dev);
+ /*
+ * update ca_wake_req_state to prevent system to go into
+ * suspend
+ */
+ prcmu_ac_wake_req();
+
+ /* send ca_wake_ack_interrupt to CMU */
+ if (!get_host_accessport_val())
+ BUG();
+
+ writel((1<<GOP_CA_WAKE_ACK_BIT),
+ shm_dev->intr_base+GOP_SET_REGISTER_BASE);
+ break;
+ case IRQ_PRCMU_CA_SLEEP:
+ dev_dbg(shm_dev->dev, "%s:IRQ_PRCMU_CA_SLEEP\n", __func__);
+ /*
+ * update ca_wake_req_state to allow system to go into
+ * suspend
+ */
+ shrm_common_rx_state = SHRM_IDLE;
+ shrm_audio_rx_state = SHRM_IDLE;
+
+ /*
+ * start timer for X msec before clearing the
+ * prcm_hostport_req
+ */
+ hrtimer_start(&timer, ktime_set(0, 100*NSEC_PER_MSEC),
+ HRTIMER_MODE_REL);
+
+ hr_timer_status = 1;
+ break;
+ default:
+ dev_err(shm_dev->dev, "Unknown IRQ\n");
+ }
+ dev_dbg(shm_dev->dev, "%s OUT\n", __func__);
+}
+
+DECLARE_TASKLET(shrm_ca_sleep_callback, shrm_cawake_callback,
+ IRQ_PRCMU_CA_SLEEP);
+DECLARE_TASKLET(shrm_ca_wake_callback, shrm_cawake_callback,
+ IRQ_PRCMU_CA_WAKE);
+DECLARE_TASKLET(shrm_sw_reset_callback, shrm_modem_reset_callback,
+ IRQ_PRCMU_MODEM_SW_RESET_REQ);
+
+static irqreturn_t shrm_prcmu_irq_handler(int irq, void *data)
+{
+ switch (irq) {
+ case IRQ_PRCMU_CA_WAKE:
+ tasklet_schedule(&shrm_ca_wake_callback);
+ break;
+ case IRQ_PRCMU_CA_SLEEP:
+ tasklet_schedule(&shrm_ca_sleep_callback);
+ break;
+ case IRQ_PRCMU_MODEM_SW_RESET_REQ:
+ tasklet_schedule(&shrm_sw_reset_callback);
+ break;
+ default:
+ return IRQ_NONE;
+ }
+ return IRQ_HANDLED;
+}
+
+
+void shm_nl_receive(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlh = NULL;
+ int msg;
+ int err;
+
+ dev_dbg(shm_dev->dev, "Received NL msg from user-space\n");
+
+ nlh = (struct nlmsghdr *)skb->data;
+ msg = *((int *)(NLMSG_DATA(nlh)));
+ switch (msg) {
+ case SHRM_NL_MOD_QUERY_STATE:
+ dev_info(shm_dev->dev, "mod-query-state from user-space\n");
+ nl_send_unicast_message(nlh->nlmsg_pid);
+ break;
+
+ case SHRM_NL_USER_MOD_RESET:
+ dev_info(shm_dev->dev, "user-space inited mod-reset-req\n");
+ err = shrm_modem_reset_sequence();
+ if (err)
+ dev_err(shm_dev->dev, "User mod-reset mcast fail\n");
+ break;
+
+ default:
+ dev_err(shm_dev->dev, "Invalid NL msg from user-space\n");
+ break;
+ };
+}
+
+int shrm_protocol_init(struct shrm_dev *shrm,
+ received_msg_handler common_rx_handler,
+ received_msg_handler audio_rx_handler)
+{
+ int err;
+
+ shm_dev = shrm;
+ boot_state = BOOT_INIT;
+ dev_info(shrm->dev, "IPC_ISA BOOT_INIT\n");
+ rx_common_handler = common_rx_handler;
+ rx_audio_handler = audio_rx_handler;
+ spin_lock_init(&ca_common_lock);
+ spin_lock_init(&ca_audio_lock);
+ spin_lock_init(&ca_wake_req_lock);
+ spin_lock_init(&boot_lock);
+
+ is_earlydrop = cpu_is_u8500ed();
+ if (is_earlydrop != 0x01) {
+ hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ timer.function = callback;
+ }
+
+ /* enable the PRCM_HostAccess req HIGH as of now */
+ prcmu_ac_wake_req();
+
+ err = request_irq(IRQ_PRCMU_CA_SLEEP, shrm_prcmu_irq_handler, 0,
+ "ca-sleep", NULL);
+ if (err < 0) {
+ dev_err(shm_dev->dev, "Failed alloc IRQ_PRCMU_CA_SLEEP.\n");
+ return err;
+ }
+
+ err = request_irq(IRQ_PRCMU_CA_WAKE, shrm_prcmu_irq_handler, 0,
+ "ca-wake", NULL);
+ if (err < 0) {
+ dev_err(shm_dev->dev, "Failed alloc IRQ_PRCMU_CA_WAKE.\n");
+ goto drop2;
+ }
+
+ err = request_irq(IRQ_PRCMU_MODEM_SW_RESET_REQ, shrm_prcmu_irq_handler,
+ 0, "modem-sw-reset-req", NULL);
+ if (err < 0) {
+ dev_err(shm_dev->dev,
+ "Failed alloc IRQ_PRCMU_MODEM_SW_RESET_REQ.\n");
+ goto drop1;
+ }
+
+ /* set tasklet data */
+ shm_ca_0_tasklet.data = (unsigned long)shrm;
+ shm_ca_1_tasklet.data = (unsigned long)shrm;
+ shm_ca_wake_tasklet.data = (unsigned long)shrm;
+
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+ /* init netlink socket for user-space communication */
+ shrm_nl_sk = netlink_kernel_create(NULL, NETLINK_SHRM, 1,
+ shm_nl_receive, NULL, THIS_MODULE);
+
+ if (!shrm_nl_sk) {
+ dev_err(shm_dev->dev, "netlink socket creation failed\n");
+ goto drop1;
+ }
+#endif
+
+ return 0;
+
+drop1:
+ free_irq(IRQ_PRCMU_CA_WAKE, NULL);
+drop2:
+ free_irq(IRQ_PRCMU_CA_SLEEP, NULL);
+ return err;
+}
+
+int get_ca_wake_req_state(void)
+{
+ return ca_wake_req_state;
+}
+
+irqreturn_t ca_wake_irq_handler(int irq, void *ctrlr)
+{
+ struct shrm_dev *shrm = ctrlr;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+ /* initialize the FIFO Variables */
+ if (boot_state == BOOT_INIT)
+ shm_fifo_init(shrm);
+
+ dev_dbg(shrm->dev, "Inside ca_wake_irq_handler\n");
+
+ /* Clear the interrupt */
+ writel((1<<GOP_CA_WAKE_REQ_BIT),
+ shrm->intr_base+GOP_CLEAR_REGISTER_BASE);
+
+ /* send ca_wake_ack_interrupt to CMU */
+ writel((1<<GOP_CA_WAKE_ACK_BIT),
+ shrm->intr_base+GOP_SET_REGISTER_BASE);
+
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return IRQ_HANDLED;
+}
+
+
+irqreturn_t ac_read_notif_0_irq_handler(int irq, void *ctrlr)
+{
+ struct shrm_dev *shrm = ctrlr;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return IRQ_HANDLED;
+ }
+
+ shm_ac_read_0_tasklet.data = (unsigned long)shrm;
+ tasklet_schedule(&shm_ac_read_0_tasklet);
+
+ prcmu_ac_wake_req();
+
+ if (!get_host_accessport_val())
+ BUG();
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return IRQ_HANDLED;
+ }
+
+ /* Clear the interrupt */
+ writel((1<<GOP_COMMON_AC_READ_NOTIFICATION_BIT),
+ shrm->intr_base+GOP_CLEAR_REGISTER_BASE);
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return IRQ_HANDLED;
+}
+
+irqreturn_t ac_read_notif_1_irq_handler(int irq, void *ctrlr)
+{
+ struct shrm_dev *shrm = ctrlr;
+
+ dev_dbg(shrm->dev, "%s IN+\n", __func__);
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return IRQ_HANDLED;
+ }
+
+ shm_ac_read_1_tasklet.data = (unsigned long)shrm;
+ tasklet_schedule(&shm_ac_read_1_tasklet);
+
+ prcmu_ac_wake_req();
+
+ if (!get_host_accessport_val())
+ BUG();
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return IRQ_HANDLED;
+ }
+
+ /* Clear the interrupt */
+ writel((1<<GOP_AUDIO_AC_READ_NOTIFICATION_BIT),
+ shrm->intr_base+GOP_CLEAR_REGISTER_BASE);
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return IRQ_HANDLED;
+}
+
+irqreturn_t ca_msg_pending_notif_0_irq_handler(int irq, void *ctrlr)
+{
+ struct shrm_dev *shrm = ctrlr;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return IRQ_HANDLED;
+ }
+
+ tasklet_schedule(&shm_ca_0_tasklet);
+ prcmu_ac_wake_req();
+
+ if (!get_host_accessport_val())
+ BUG();
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return IRQ_HANDLED;
+ }
+
+ /* Clear the interrupt */
+ writel((1<<GOP_COMMON_CA_MSG_PENDING_NOTIFICATION_BIT),
+ shrm->intr_base+GOP_CLEAR_REGISTER_BASE);
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return IRQ_HANDLED;
+}
+
+irqreturn_t ca_msg_pending_notif_1_irq_handler(int irq, void *ctrlr)
+{
+ struct shrm_dev *shrm = ctrlr;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return IRQ_HANDLED;
+ }
+
+ tasklet_schedule(&shm_ca_1_tasklet);
+ prcmu_ac_wake_req();
+ if (!get_host_accessport_val())
+ BUG();
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return IRQ_HANDLED;
+ }
+
+ /* Clear the interrupt */
+ writel((1<<GOP_AUDIO_CA_MSG_PENDING_NOTIFICATION_BIT),
+ shrm->intr_base+GOP_CLEAR_REGISTER_BASE);
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return IRQ_HANDLED;
+
+}
+
+/**
+ * shm_write_msg() - write message to shared memory
+ * @shrm: pointer to the shrm device information structure
+ * @l2_header: L2 header
+ * @addr: pointer to the message
+ * @length: length of the message to be written
+ *
+ * This function is called from net or char interface driver write operation.
+ * Prior to calling this function the message is copied from the user space
+ * buffer to the kernel buffer. This function based on the l2 header routes
+ * the message to the respective channel and FIFO. Then makes a call to the
+ * fifo write function where the message is written to the physical device.
+ */
+int shm_write_msg(struct shrm_dev *shrm, u8 l2_header,
+ void *addr, u32 length)
+{
+ u8 channel = 0;
+ int ret;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (boot_state != BOOT_DONE) {
+ dev_err(shrm->dev,
+ "error after boot done call this fn\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if ((l2_header == L2_HEADER_ISI) ||
+ (l2_header == L2_HEADER_RPC) ||
+ (l2_header == L2_HEADER_SECURITY) ||
+ (l2_header == L2_HEADER_COMMON_SIMPLE_LOOPBACK) ||
+ (l2_header == L2_HEADER_COMMON_ADVANCED_LOOPBACK)) {
+ channel = 0;
+ if (shrm_common_tx_state == SHRM_SLEEP_STATE)
+ shrm_common_tx_state = SHRM_PTR_FREE;
+ else if (shrm_common_tx_state == SHRM_IDLE)
+ shrm_common_tx_state = SHRM_PTR_FREE;
+
+ } else if ((l2_header == L2_HEADER_AUDIO) ||
+ (l2_header == L2_HEADER_AUDIO_SIMPLE_LOOPBACK) ||
+ (l2_header == L2_HEADER_AUDIO_ADVANCED_LOOPBACK)) {
+ if (shrm_audio_tx_state == SHRM_SLEEP_STATE)
+ shrm_audio_tx_state = SHRM_PTR_FREE;
+ else if (shrm_audio_tx_state == SHRM_IDLE)
+ shrm_audio_tx_state = SHRM_PTR_FREE;
+
+ channel = 1;
+ } else {
+ ret = -ENODEV;
+ goto out;
+ }
+ ret = shm_write_msg_to_fifo(shrm, channel, l2_header, addr, length);
+ if (ret < 0) {
+ dev_err(shrm->dev, "write message to fifo failed\n");
+ return ret;
+ }
+ /*
+ * notify only if new msg copied is the only unread one
+ * otherwise it means that reading process is ongoing
+ */
+ if (is_the_only_one_unread_message(shrm, channel, length)) {
+
+ /* Send Message Pending Noitication to CMT */
+ if (channel == 0)
+ send_ac_msg_pending_notification_0(shrm);
+ else
+ send_ac_msg_pending_notification_1(shrm);
+
+ }
+
+ /*
+ * cancel the hrtimer running for calling the
+ * prcmu_ac_sleep req
+ */
+ if (hr_timer_status) {
+ ret = hrtimer_cancel(&timer);
+ if (ret)
+ dev_dbg(shrm->dev,
+ "timer_ac_sleep was running\n");
+ hr_timer_status = 0;
+ }
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+ return 0;
+
+out:
+ return ret;
+}
+
+void send_ac_msg_pending_notification_0(struct shrm_dev *shrm)
+{
+ unsigned long flags;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ spin_lock_irqsave(&ca_wake_req_lock, flags);
+ update_ac_common_shared_wptr_with_writer_local_wptr(shrm);
+
+ prcmu_ac_wake_req();
+
+ if (!get_host_accessport_val())
+ BUG();
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return;
+ }
+
+ /* Trigger AcMsgPendingNotification to CMU */
+ writel((1<<GOP_COMMON_AC_MSG_PENDING_NOTIFICATION_BIT),
+ shrm->intr_base+GOP_SET_REGISTER_BASE);
+
+ spin_unlock_irqrestore(&ca_wake_req_lock, flags);
+ if (shrm_common_tx_state == SHRM_PTR_FREE)
+ shrm_common_tx_state = SHRM_PTR_BUSY;
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void send_ac_msg_pending_notification_1(struct shrm_dev *shrm)
+{
+ unsigned long flags;
+
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ spin_lock_irqsave(&ca_wake_req_lock, flags);
+ /* Update shared_wptr with writer_local_wptr) */
+ update_ac_audio_shared_wptr_with_writer_local_wptr(shrm);
+
+ prcmu_ac_wake_req();
+
+ if (!get_host_accessport_val())
+ BUG();
+
+ if (check_modem_in_reset()) {
+ pr_crit("%s:Modem in reset or unknown state.\n", __func__);
+ return;
+ }
+
+ /* Trigger AcMsgPendingNotification to CMU */
+ writel((1<<GOP_AUDIO_AC_MSG_PENDING_NOTIFICATION_BIT),
+ shrm->intr_base+GOP_SET_REGISTER_BASE);
+
+ spin_unlock_irqrestore(&ca_wake_req_lock, flags);
+ if (shrm_audio_tx_state == SHRM_PTR_FREE)
+ shrm_audio_tx_state = SHRM_PTR_BUSY;
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void ca_msg_read_notification_0(struct shrm_dev *shrm)
+{
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (get_ca_msg_0_read_notif_send() == 0) {
+ update_ca_common_shared_rptr_with_reader_local_rptr(shrm);
+
+ prcmu_ac_wake_req();
+ if (!get_host_accessport_val())
+ BUG();
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return;
+ }
+
+ /* Trigger CaMsgReadNotification to CMU */
+ writel((1<<GOP_COMMON_CA_READ_NOTIFICATION_BIT),
+ shrm->intr_base+GOP_SET_REGISTER_BASE);
+ set_ca_msg_0_read_notif_send(1);
+ shrm_common_rx_state = SHRM_PTR_BUSY;
+ }
+
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void ca_msg_read_notification_1(struct shrm_dev *shrm)
+{
+ dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+ if (get_ca_msg_1_read_notif_send() == 0) {
+ update_ca_audio_shared_rptr_with_reader_local_rptr(shrm);
+ prcmu_ac_wake_req();
+ if (!get_host_accessport_val())
+ BUG();
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return;
+ }
+
+ /* Trigger CaMsgReadNotification to CMU */
+ writel((1<<GOP_AUDIO_CA_READ_NOTIFICATION_BIT),
+ shrm->intr_base+GOP_SET_REGISTER_BASE);
+ set_ca_msg_1_read_notif_send(1);
+ shrm_audio_rx_state = SHRM_PTR_BUSY;
+ }
+ dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+/**
+ * receive_messages_common - receive common channnel msg from
+ * CMT(Cellular Mobile Terminal)
+ * @shrm: pointer to shrm device information structure
+ *
+ * The messages sent from CMT to APE are written to the respective FIFO
+ * and an interrupt is triggered by the CMT. This ca message pending
+ * interrupt calls this function. This function sends a read notification
+ * acknowledgement to the CMT and calls the common channel receive handler
+ * where the messsage is copied to the respective(ISI, RPC, SECURIT) queue
+ * based on the message l2 header.
+ */
+void receive_messages_common(struct shrm_dev *shrm)
+{
+ u8 l2_header;
+ u32 len;
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return;
+ }
+
+ l2_header = read_one_l2msg_common(shrm, recieve_common_msg, &len);
+ /* Send Recieve_Call_back to Upper Layer */
+ if (!rx_common_handler) {
+ dev_err(shrm->dev, "common_rx_handler is Null\n");
+ BUG();
+ }
+ (*rx_common_handler)(l2_header, &recieve_common_msg, len,
+ shrm);
+ /* SendReadNotification */
+ ca_msg_read_notification_0(shrm);
+
+ while (read_remaining_messages_common()) {
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return;
+ }
+
+ l2_header = read_one_l2msg_common(shrm, recieve_common_msg,
+ &len);
+ /* Send Recieve_Call_back to Upper Layer */
+ (*rx_common_handler)(l2_header,
+ &recieve_common_msg, len,
+ shrm);
+ }
+}
+
+/**
+ * receive_messages_audio() - receive audio message from CMT
+ * @shrm: pointer to shrm device information structure
+ *
+ * The messages sent from CMT to APE are written to the respective FIFO
+ * and an interrupt is triggered by the CMT. This ca message pending
+ * interrupt calls this function. This function sends a read notification
+ * acknowledgement to the CMT and calls the common channel receive handler
+ * where the messsage is copied to the audio queue.
+ */
+void receive_messages_audio(struct shrm_dev *shrm)
+{
+ u8 l2_header;
+ u32 len;
+
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return;
+ }
+
+ l2_header = read_one_l2msg_audio(shrm, recieve_audio_msg, &len);
+ /* Send Recieve_Call_back to Upper Layer */
+
+ if (!rx_audio_handler) {
+ dev_crit(shrm->dev, "audio_rx_handler is Null\n");
+ BUG();
+ }
+ (*rx_audio_handler)(l2_header, &recieve_audio_msg,
+ len, shrm);
+
+ /* SendReadNotification */
+ ca_msg_read_notification_1(shrm);
+ while (read_remaining_messages_audio()) {
+ if (check_modem_in_reset()) {
+ dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+ __func__);
+ return;
+ }
+
+ l2_header = read_one_l2msg_audio(shrm,
+ recieve_audio_msg, &len);
+ /* Send Recieve_Call_back to Upper Layer */
+ (*rx_audio_handler)(l2_header,
+ &recieve_audio_msg, len,
+ shrm);
+ }
+}
+
+u8 get_boot_state()
+{
+ return boot_state;
+}
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 360dd3ef045..ef06b3f3d10 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -238,33 +238,6 @@ static u32 get_card_status(struct mmc_card *card, struct request *req)
return cmd.resp[0];
}
-static int
-mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
-{
- struct mmc_command cmd;
- int err;
-
- /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
- if (mmc_card_blockaddr(card))
- return 0;
-
- mmc_claim_host(card->host);
- cmd.opcode = MMC_SET_BLOCKLEN;
- cmd.arg = 512;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 5);
- mmc_release_host(card->host);
-
- if (err) {
- printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
- md->disk->disk_name, cmd.arg, err);
- return -EINVAL;
- }
-
- return 0;
-}
-
-
static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
{
struct mmc_blk_data *md = mq->data;
@@ -329,7 +302,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
readcmd = MMC_READ_SINGLE_BLOCK;
writecmd = MMC_WRITE_BLOCK;
}
-
+ if (mmc_card_ddr_mode(card))
+ brq.data.flags |= MMC_DDR_MODE;
if (rq_data_dir(req) == READ) {
brq.cmd.opcode = readcmd;
brq.data.flags |= MMC_DATA_READ;
@@ -596,6 +570,35 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
return ERR_PTR(ret);
}
+static int
+mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
+{
+ struct mmc_command cmd;
+ int err;
+
+ /*
+ * Block-addressed and ddr mode supported cards
+ * ignore MMC_SET_BLOCKLEN.
+ */
+ if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+ return 0;
+
+ mmc_claim_host(card->host);
+ cmd.opcode = MMC_SET_BLOCKLEN;
+ cmd.arg = 512;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ err = mmc_wait_for_cmd(card->host, &cmd, 5);
+ mmc_release_host(card->host);
+
+ if (err) {
+ printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
+ md->disk->disk_name, cmd.arg, err);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 7d0c1f584e2..978b820107a 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -777,8 +777,9 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
/**
* mmc_regulator_set_ocr - set regulator to match host->ios voltage
- * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
+ * @mmc: the host to regulate
* @supply: regulator to use
+ * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
*
* Returns zero on success, else negative errno.
*
@@ -786,15 +787,12 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
* a particular supply voltage. This would normally be called from the
* set_ios() method.
*/
-int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
+int mmc_regulator_set_ocr(struct mmc_host *mmc,
+ struct regulator *supply,
+ unsigned short vdd_bit)
{
int result = 0;
int min_uV, max_uV;
- int enabled;
-
- enabled = regulator_is_enabled(supply);
- if (enabled < 0)
- return enabled;
if (vdd_bit) {
int tmp;
@@ -825,17 +823,25 @@ int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
else
result = 0;
- if (result == 0 && !enabled)
+ if (result == 0 && !mmc->regulator_enabled) {
result = regulator_enable(supply);
- } else if (enabled) {
+ if (!result)
+ mmc->regulator_enabled = true;
+ }
+ } else if (mmc->regulator_enabled) {
result = regulator_disable(supply);
+ if (result == 0)
+ mmc->regulator_enabled = false;
}
+ if (result)
+ dev_err(mmc_dev(mmc),
+ "could not set regulator OCR (%d)\n", result);
return result;
}
EXPORT_SYMBOL(mmc_regulator_set_ocr);
-#endif
+#endif /* CONFIG_REGULATOR */
/*
* Mask off any voltages we don't support and select
@@ -1324,7 +1330,8 @@ int mmc_suspend_host(struct mmc_host *host)
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
- if (host->bus_ops->suspend)
+ if (host->bus_ops->suspend &&
+ (host->bus_resume_flags & MMC_NEEDS_UNSAFE_RESUME))
err = host->bus_ops->suspend(host);
}
mmc_bus_put(host);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index ba684e6d2b6..d037bc1a278 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -139,6 +139,7 @@ int mmc_add_host(struct mmc_host *host)
mmc_start_host(host);
if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
register_pm_notifier(&host->pm_notify);
+ register_pm_notifier(&host->pm_notify);
return 0;
}
@@ -158,6 +159,7 @@ void mmc_remove_host(struct mmc_host *host)
if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
unregister_pm_notifier(&host->pm_notify);
+ unregister_pm_notifier(&host->pm_notify);
mmc_stop_host(host);
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 98cd0e50c89..c006b83e084 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -239,11 +239,29 @@ static int mmc_read_ext_csd(struct mmc_card *card)
/* size is in 256K chunks, i.e. 512 sectors each */
boot_sectors = ext_csd[EXT_CSD_BOOT_SIZE_MULTI] * 512;
card->ext_csd.sectors -= boot_sectors;
+
+ /* Cards with density > 2GiB are sector addressed */
+ if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512)
mmc_card_set_blockaddr(card);
}
}
switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
+ case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
+ EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52;
+ break;
+ case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 |
+ EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V;
+ break;
+ case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 |
+ EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V;
+ break;
case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
card->ext_csd.hs_max_dtr = 52000000;
break;
@@ -461,6 +479,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
mmc_set_clock(host, max_dtr);
/*
+ * Activate DDR50 mode (if supported).
+ */
+ if (mmc_card_highspeed(card)) {
+ if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
+ && (host->caps & (MMC_CAP_1_8V_DDR)))
+ mmc_card_set_ddr_mode(card);
+ else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
+ && (host->caps & (MMC_CAP_1_2V_DDR)))
+ mmc_card_set_ddr_mode(card);
+ }
+
+ /*
* Activate wide bus (if supported).
*/
if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
@@ -468,10 +498,16 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
unsigned ext_csd_bit, bus_width;
if (host->caps & MMC_CAP_8_BIT_DATA) {
- ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
+ if (mmc_card_ddr_mode(card))
+ ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_8;
+ else
+ ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
bus_width = MMC_BUS_WIDTH_8;
} else {
- ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
+ if (mmc_card_ddr_mode(card))
+ ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_4;
+ else
+ ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
bus_width = MMC_BUS_WIDTH_4;
}
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 326447c9ede..91ab05aa1d4 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -202,6 +202,7 @@ int mmc_set_relative_addr(struct mmc_card *card)
{
int err;
struct mmc_command cmd;
+ u32 status;
BUG_ON(!card);
BUG_ON(!card->host);
@@ -216,6 +217,28 @@ int mmc_set_relative_addr(struct mmc_card *card)
if (err)
return err;
+ /* Must check status to be sure of no errors */
+ do {
+ err = mmc_send_status(card, &status);
+ if (err)
+ return err;
+ if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+ break;
+ if (mmc_host_is_spi(card->host))
+ break;
+ } while (R1_CURRENT_STATE(status) == 7);
+
+ if (mmc_host_is_spi(card->host)) {
+ if (status & R1_SPI_ILLEGAL_COMMAND)
+ return -EBADMSG;
+ } else {
+ if (status & 0xFDFFA000)
+ printk(KERN_WARNING "%s: unexpected status %#x after "
+ "switch", mmc_hostname(card->host), status);
+ if (status & R1_SWITCH_ERROR)
+ return -EBADMSG;
+ }
+
return 0;
}
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index 549a3414464..a2767401182 100755
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
@@ -338,6 +338,10 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
while (remainder > 0) {
size = min(remainder, sdio_max_byte_size(func));
+ // Some of host controllers does not support non-power-of-two block sizes
+ if (func->card->host->caps & MMC_CAP_POWER_OF_TWO_BLKSIZE)
+ size = 1 << (fls(size) - 1);
+
ret = mmc_io_rw_extended(func->card, write, func->num, addr,
incr_addr, buf, 1, size);
if (ret)
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index f06d06e7fdf..6f36e1e241f 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -382,6 +382,71 @@ config MMC_TMIO
This provides support for the SD/MMC cell found in TC6393XB,
T7L66XB and also HTC ASIC3
+config MMC_U8500
+ tristate "U8500 MMC Card Interface support"
+ depends on ARM_AMBA && MMC && ARCH_U8500 && STE_DMA40
+ help
+ This selects the U8500 Multimedia card interface.
+ If you have a U8500 platform with a MMC slot, say Y or M here.
+ Depends on U8500/STM DMA driver.
+ If unsure, say N.
+ choice
+ prompt "Driver mode"
+ depends on MMC_U8500
+ default U8500_MMC_DMA
+
+ config U8500_MMC_DMA
+ depends on MMC_U8500
+ bool "DMA mode"
+
+ config U8500_MMC_POLL
+ depends on MMC_U8500
+ bool "Polling mode"
+
+ config U8500_MMC_INTR
+ depends on MMC_U8500
+ bool "Interrupt mode"
+ endchoice
+
+config LEVELSHIFTER_HREF_V1_PLUS
+ bool "configure for HREF+ V1 level shifter"
+ depends on MMC_U8500
+ help
+ This enables the 1V8_3V_SEL command for HREF+.
+
+config U8500_SDIO
+ tristate "Nomadik SDIO Card Interface support"
+ depends on MMC_U8500
+ help
+ This selects the U8500 SDIO card support.
+ If you have a U8500 platform with a SDIO slot, say Y or M here.
+ If unsure, say N.
+ choice
+ prompt "Driver mode"
+ depends on U8500_SDIO
+ default U8500_SDIO_POLL
+
+ config U8500_SDIO_DMA
+ depends on U8500_SDIO
+ bool "SDIO DMA mode"
+
+ config U8500_SDIO_POLL
+ depends on U8500_SDIO
+ bool "SDIO Polling mode"
+
+ config U8500_SDIO_INTR
+ depends on U8500_SDIO
+ bool "SDIO Interrupt mode"
+ endchoice
+
+config U8500_SDIO_CARD_IRQ
+ tristate "SDIO interrupt from card is supported"
+ depends on U8500_SDIO
+ default y
+ help
+ This enables host controller to detect interrupt from
+ SDIO card
+
config MMC_CB710
tristate "ENE CB710 MMC/SD Interface support"
depends on PCI
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index e30c2ee4889..be6b582a89f 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
+obj-$(CONFIG_MMC_U8500) += mmc-u8500.o
obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o
sdhci-of-y := sdhci-of-core.o
diff --git a/drivers/mmc/host/mmc-u8500.c b/drivers/mmc/host/mmc-u8500.c
new file mode 100644
index 00000000000..0fd739610ea
--- /dev/null
+++ b/drivers/mmc/host/mmc-u8500.c
@@ -0,0 +1,1806 @@
+/*
+ * Overview:
+ * SD/EMMC driver for u8500 platform
+ *
+ * Copyright (C) 2009 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*-------------------------------------------------------------------------
+ * SDI controller configuration
+ * Kernel entry point for sdmmc/emmc chip
+ *-------------------------------------------------------------------------
+ * <VERSION>v1.0.0
+ *-------------------------------------------------------------------------
+ */
+
+/** @file mmc-u8500.c
+ * @brief This file contains the sdmmc/emmc chip initialization with default
+ * as DMA mode.Polling/Interrupt mode support could be enabled in the kernel
+ * menuconfig. Read and write function definitions to configure the read and
+ * write functionality was implemented.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/highmem.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/amba/bus.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/completion.h>
+#include <linux/regulator/consumer.h>
+
+#include <asm/cacheflush.h>
+#include <asm/div64.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <asm/sizes.h>
+#include <mach/hardware.h>
+#include <mach/mmc.h>
+#include <asm/bitops.h>
+#include <mach/mmc.h>
+#include <mach/debug.h>
+#include "mmc-u8500.h"
+
+/* Workaround for SDIO Multibyte mode, not suuported in H/W */
+#ifdef SDIO_MULTIBYTE_WORKAROUND
+#undef SDIO_MULTIBYTE_WORKAROUND
+/* Not fully validated, to be enabled from menuconfig later */
+#endif
+
+/*
+ * Global variables
+ */
+
+#define DRIVER_NAME "DRIVER MMC"
+
+#define CONFIG_STM_MMC_DEBUG
+#define DRIVER_DEBUG CONFIG_STM_MMC_DEBUG
+#define DRIVER_DEBUG_PFX DRIVER_NAME
+#define DRIVER_DBG KERN_ERR
+extern struct driver_debug_st DBG_ST;
+#define DMA_SCATERGATHER
+
+#if defined CONFIG_U8500_MMC_POLL
+const int mmc_mode = MCI_POLLINGMODE;
+#elif defined CONFIG_U8500_MMC_INTR
+const int mmc_mode = MCI_INTERRUPTMODE;
+#elif defined CONFIG_U8500_MMC_DMA
+const int mmc_mode = MCI_DMAMODE;
+#endif
+
+#if defined CONFIG_U8500_SDIO_POLL
+const int sdio_mode = MCI_POLLINGMODE;
+#elif defined CONFIG_U8500_SDIO_INTR
+const int sdio_mode = MCI_INTERRUPTMODE;
+#elif defined CONFIG_U8500_SDIO_DMA
+const int sdio_mode = MCI_DMAMODE;
+#else
+const int sdio_mode = 0xFFFF;
+#endif
+
+#if !defined CONFIG_U8500_MMC_INTR
+static unsigned int fmax = MMC_HOST_CLK_MAX;
+#else
+static unsigned int fmax = MMC_HOST_CLK_MAX / 8;
+#endif
+
+static void u8500_mmci_start_command(struct u8500_mmci_host *host,
+ struct mmc_command *cmd);
+
+static void u8500_mmci_data_irq(struct u8500_mmci_host *host,
+ u32 hoststatus);
+
+static void u8500_mmci_cmd_irq(struct u8500_mmci_host *host,
+ u32 hoststatus);
+/*
+ * Pointer to save SDIO host data structure.
+ * Required for sysfs inplementation for card detection
+ */
+static struct u8500_mmci_host *sdio_host_ptr;
+#define CARD_DETECT_DELAY_MSEC (10)
+
+/* For SDIO host DMA mode, min data transfer size in bytes */
+#define MIN_DATA_SIZE_DMA 32
+/* DMA element size in bytes */
+#define DMA_ELEMENT_SZ 4
+/**
+ * u8500_sdio_detect_card() - Initiates card scan for sdio host
+ *
+ * this function will scan for insertion/removal of sdio card.
+ * This is required to initiate card rescan from sdio client device driver.
+ */
+void u8500_sdio_detect_card(void)
+{
+ struct u8500_mmci_host *host = sdio_host_ptr;
+ if (sdio_host_ptr && host->mmc)
+ mmc_detect_change(host->mmc,
+ msecs_to_jiffies(CARD_DETECT_DELAY_MSEC));
+
+ return;
+}
+EXPORT_SYMBOL(u8500_sdio_detect_card);
+
+static ssize_t sdio_detect_card_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned int scan_val;
+
+ if (sscanf(buf, "%u", &scan_val) != 1)
+ return -EINVAL;
+ /*
+ * unsigned integer is valid entry.
+ * mmc_detect_change is called when scan_val == 1.
+ */
+ if (scan_val != 1)
+ return -EINVAL;
+
+ /* call card scan */
+ u8500_sdio_detect_card();
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(detect_card, S_IWUSR, NULL, sdio_detect_card_store);
+
+
+/**
+ * u8500_mmci_init_sg() - initializing the host scatterlist
+ * @host: pointer to the u8500_mmci_host structure
+ * @data: pointer to the mmc_data structure
+ *
+ * this function assigns the scattelist of the mmc_data structure
+ * to the host scatterlist.
+ */
+static inline void
+u8500_mmci_init_sg(struct u8500_mmci_host *host, struct mmc_data *data)
+{
+ /*
+ * Ideally, we want the higher levels to pass us a scatter list
+ */
+ host->sg_len = data->sg_len;
+ host->sg_ptr = data->sg;
+ host->sg_off = 0;
+}
+
+/**
+ * u8500_mmc_clearirqsrc() - Clearing the interrupts of the host
+ * @base: pointer to the base address of the host
+ * @irqsrc: irqsrc number.
+ *
+ * this function clears the corresponding interrupt of the source of the
+ * SD controller by writing to interrupt clear register
+ */
+static inline void u8500_mmc_clearirqsrc(void *base, u32 irqsrc)
+{
+ irqsrc &= ~(MCI_SDIOIT);
+ writel(irqsrc, (base + MMCICLEAR));
+}
+
+/**
+ * u8500_mmc_disableirqsrc() - Disabling the interrupts of the host
+ * @base: pointer to the base address of the host
+ * @irqsrc: irqsrc number.
+ *
+ * this function disables the corresponding interrupt source
+ */
+static inline void u8500_mmc_disableirqsrc(void *base, u32 irqsrc)
+{
+ u32 temp_reg;
+ irqsrc &= ~(MCI_SDIOIT);
+ temp_reg = readl(base + MMCIMASK0);
+ temp_reg &= ~irqsrc;
+ writel(temp_reg, (base + MMCIMASK0));
+}
+
+/**
+ * u8500_mmc_enableirqsrc() - Enabeling the interrupts of the host
+ * @base: pointer to the base address of the host
+ * @irqsrc: irqsrc number
+ *
+ * this function enables the corresponding interrupt source
+ */
+static inline void u8500_mmc_enableirqsrc(void *base, u32 irqsrc)
+{
+ u32 temp_reg;
+ irqsrc &= ~(MCI_SDIOIT);
+ temp_reg = readl(base + MMCIMASK0);
+ temp_reg |= irqsrc;
+ writel(temp_reg, (base + MMCIMASK0));
+}
+
+/**
+ * u8500_mmci_request_end() - Informs the stack regarding the completion of the request
+ * @host: pointer to the u8500_mmci_host structure
+ * @mrq: pointer to the mmc_request structure
+ *
+ * this function will be called after servicing the request sent from the
+ * stack.And this function will inform the stack that the request is done
+ */
+static void
+u8500_mmci_request_end(struct u8500_mmci_host *host,
+ struct mmc_request *mrq)
+{
+ unsigned long flag_lock = 0;
+ spin_lock_irqsave(&host->lock, flag_lock);
+ host->mrq = NULL;
+ host->cmd = NULL;
+ if (mrq->data)
+ mrq->data->bytes_xfered = host->data_xfered;
+ /*
+ * Need to drop the host lock here; mmc_request_done may call
+ * back into the driver...
+ */
+ spin_unlock_irqrestore(&host->lock, flag_lock);
+ mmc_request_done(host->mmc, mrq);
+}
+
+/**
+ * u8500_mmci_stop_data() - clears the data control registers
+ * @host: pointer to the u8500_mmci_host structure
+ *
+ * this function clears the data control register after the end of
+ * data transfer or when an error occured in the data transfer
+ */
+static void u8500_mmci_stop_data(struct u8500_mmci_host *host)
+{
+ unsigned long flag_lock = 0;
+ u32 temp = 0;
+ spin_lock_irqsave(&host->lock, flag_lock);
+ temp = readl(host->base + MMCIDATACTRL) & ~(MCI_DPSM_ENABLE);
+ writel(temp, host->base + MMCIDATACTRL);
+ writel(0, host->base + MMCIMASK1);
+ host->data = NULL;
+ spin_unlock_irqrestore(&host->lock, flag_lock);
+}
+
+/**
+ * u8500_mmc_send_cmd() - configures the cmd and arg control registers
+ * @base: pointer to the base address of the host
+ * @cmd: cmd number to be sent
+ * @arg: arg value need to be paased along with command
+ * @flags: flags need to be set for the cmd
+ * @devicemode: devicemode for the data transfer
+ *
+ * this function will send the cmd to the card by enabling the
+ * command path state machine and writing the cmd number and arg to the
+ * corresponding command and arguement registers
+ */
+static void u8500_mmc_send_cmd(void *base, u32 cmd, u32 arg, u32 flags,
+ int devicemode)
+{
+ u32 c, irqmask;
+ /* stm_dbg2(DBG_ST.mmc,"Sending CMD%d, arg=%08x\n", cmd, arg);*/
+ /* Clear any previous command */
+ if ((readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE)) {
+ writel(0, (base + MMCICOMMAND));
+ udelay(1);
+ }
+ c = cmd | MCI_CPSM_ENABLE;
+ irqmask = MCI_CMDCRCFAIL | MCI_CMDTIMEOUT;
+ if (flags & MMC_RSP_PRESENT) {
+ if (flags & MMC_RSP_136)
+ c |= MCI_CPSM_LONGRSP;
+ c |= MCI_CPSM_RESPONSE;
+ irqmask |= MCI_CMDRESPEND;
+ } else {
+ irqmask |= MCI_CMDSENT;
+ }
+ writel(arg, (base + MMCIARGUMENT));
+ writel(c, (base + MMCICOMMAND));
+
+ if (devicemode != MCI_POLLINGMODE)
+ u8500_mmc_enableirqsrc(base, irqmask);
+}
+
+/**
+ * process_command_end() - read the response for the corresponding cmd sent
+ * @host: pointer to the u8500_mmci_host
+ * @hoststatus: status register value
+ *
+ * this function will read the response of the corresponding command by
+ * reading the response registers
+ */
+static void process_command_end(struct u8500_mmci_host *host, u32 hoststatus)
+{
+ struct mmc_command *cmd;
+ void __iomem *base;
+
+ base = host->base;
+ cmd = host->cmd;
+
+ u8500_mmc_disableirqsrc(base, MCI_CMD_IRQ);
+ u8500_mmc_clearirqsrc(base, MCI_CMD_IRQ);
+
+ cmd->resp[0] = readl(base + MMCIRESPONSE0);
+ cmd->resp[1] = readl(base + MMCIRESPONSE1);
+ cmd->resp[2] = readl(base + MMCIRESPONSE2);
+ cmd->resp[3] = readl(base + MMCIRESPONSE3);
+
+ if ((hoststatus & MCI_CMDTIMEOUT)) {
+ /* printk(KERN_ERR "Command Timeout: %d\n", cmd->opcode); */
+ cmd->error = -ETIMEDOUT;
+ } else if ((hoststatus & MCI_CMDCRCFAIL) && (cmd->flags & MMC_RSP_CRC)) {
+ printk(KERN_ERR "Command CRC Fail\n");
+ cmd->error = -EILSEQ;
+ } else if ((cmd->flags & MMC_RSP_OPCODE) &&
+ readl(base + MMCIRESPCMD) != cmd->opcode) {
+ stm_error("Command failed opcode check");
+ cmd->error = -EILSEQ;
+ } else {
+ cmd->error = MMC_ERR_NONE;
+ }
+ /* stm_dbg2(DBG_ST.mmc,"CMD%d error=%d response:0x%08x 0x%08x 0x%08x 0x%08x\n",
+ cmd->opcode, cmd->error, cmd->resp[0], cmd->resp[1], cmd->resp[2],
+ cmd->resp[3]);
+ */
+}
+
+/**
+ * wait_for_command_end() - waiting for the command completion
+ * @host: pointer to the u8500_mmci_host
+ *
+ * this function will wait for whether the command completion has
+ * happened or any error generated by reading the status register
+ */
+static void wait_for_command_end(struct u8500_mmci_host *host)
+{
+ u32 hoststatus, statusmask;
+ struct mmc_command *cmd;
+ void __iomem *base;
+
+ base = host->base;
+ cmd = host->cmd;
+
+ statusmask = MCI_CMDTIMEOUT | MCI_CMDCRCFAIL;
+ if ((cmd->flags & MMC_RSP_PRESENT)) {
+ statusmask |= MCI_CMDRESPEND;
+ } else {
+ statusmask |= MCI_CMDSENT;
+ }
+ do {
+ hoststatus = readl(base + MMCISTATUS) & statusmask;
+ } while (!hoststatus);
+
+ u8500_mmci_cmd_irq(host, hoststatus);
+}
+
+/**
+ * check_for_data_err() - checks the status register value for the error
+ * @hoststatus: value of the host status register
+ *
+ * this function will read the status register and will return the
+ * error if any generated during the operation
+ */
+static int check_for_data_err(u32 hoststatus)
+{
+ int error = MMC_ERR_NONE;
+ if (hoststatus &
+ (MCI_DATACRCFAIL | MCI_DATATIMEOUT | MCI_TXUNDERRUN | MCI_RXOVERRUN
+ | MCI_STBITERR)) {
+ if ((hoststatus & MCI_DATATIMEOUT)) {
+ stm_error("MMC: data timeout");
+ error = -ETIMEDOUT;
+ } else if (hoststatus & MCI_DATACRCFAIL) {
+ error = -EILSEQ;
+ stm_error("MMC: data CRC fail");
+ } else if (hoststatus & MCI_RXOVERRUN) {
+ error = -EIO;
+ stm_error("MMC: Rx overrun");
+ } else if (hoststatus & MCI_TXUNDERRUN) {
+ stm_error("MMC: Tx underrun");
+ error = -EIO;
+ } else if (hoststatus & MCI_STBITERR) {
+ stm_error("MMC: stbiterr");
+ error = -EILSEQ;
+ }
+ }
+ return error;
+}
+/**
+ * u8500_mmc_dma_transfer_done() - called after the DMA tarnsfer completion
+ * @host: pointer to the u8500_mmci_host
+ *
+ * this function will update the stack with the data read and about
+ * the request completion
+ */
+static void u8500_mmc_dma_transfer_done(struct u8500_mmci_host *host)
+{
+ struct mmc_data *data;
+ struct mmc_host *mmc;
+ void __iomem *base;
+ unsigned long flags;
+ u32 temp_reg;
+ int retry;
+ base = host->base;
+ data = host->data;
+ mmc = host->mmc;
+ host->dma_done = NULL;
+ if (data == NULL) {
+ stm_error("what? data is null, go back");
+ u8500_mmci_request_end(host, host->mrq);
+ return;
+ }
+ /*
+ * Need to wait for end of transfer, i.e.,
+ * DATAEND bit to be set in SDI STATUS register
+ */
+ temp_reg = readl(base + MMCISTATUS);
+ retry = 200*100; /* Max wait for 100 usec */
+ while (!(temp_reg & MCI_DATAEND) && (retry > 0)) {
+ ndelay(5);
+ retry--;
+ temp_reg = readl(host->base + MMCISTATUS);
+ }
+
+#ifndef DMA_SCATERGATHER
+ spin_lock_irqsave(&host->lock, flags);
+ if (!data->error) {
+ if ((data->flags & MMC_DATA_READ)) {
+ u32 *buffer_local, *buffer;
+ u8500_mmci_init_sg(host, data);
+ buffer_local = host->dma_buffer;
+ while (host->sg_len--) {
+ buffer = (u32 *) (page_address(sg_page(host->sg_ptr)) +
+ host->sg_ptr->offset);
+ memcpy(buffer, buffer_local, host->sg_ptr->length);
+ buffer_local += host->sg_ptr->length / 4;
+ host->sg_ptr++;
+ host->sg_off = 0;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+#endif
+ if (data->error) {
+ if (data->flags & MMC_DATA_READ)
+ host->dmach_mmc2mem->device->
+ device_control(host->dmach_mmc2mem,
+ DMA_TERMINATE_ALL, 0);
+ else
+ host->dmach_mem2mmc->device->
+ device_control(host->dmach_mem2mmc,
+ DMA_TERMINATE_ALL, 0);
+#ifdef DMA_SCATERGATHER
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ ((data->flags & MMC_DATA_READ) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE));
+#endif
+ u8500_mmc_clearirqsrc(base, MMCCLRSTATICFLAGS);
+ u8500_mmci_stop_data(host);
+ goto out;
+ }
+ spin_lock_irqsave(&host->lock, flags);
+ host->data_xfered += host->size;
+ spin_unlock_irqrestore(&host->lock, flags);
+ u8500_mmc_clearirqsrc(base, MMCCLRSTATICFLAGS);
+ u8500_mmci_stop_data(host);
+#ifdef DMA_SCATERGATHER
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ ((data->flags & MMC_DATA_READ) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE));
+#endif
+ if (!data->stop)
+ u8500_mmci_request_end(host, data->mrq);
+ else
+ u8500_mmci_start_command(host, data->stop);
+ return;
+out:
+ if (data->error != MMC_ERR_NONE) {
+ if (!data->stop)
+ u8500_mmci_request_end(host, data->mrq);
+ else
+ u8500_mmci_start_command(host, data->stop);
+ }
+}
+/**
+ * u8500_mmc_dmaclbk() - callback handler for DMA
+ * @data: pointer to the host
+ * @event: event value for checking the completion status
+ *
+ * this function is the callback which will be called upon the completion of any DMA
+ * request regarding read/write.
+ */
+void u8500_mmc_dmaclbk(void *data)
+{
+ struct u8500_mmci_host *host = data;
+ if (host->dma_done == NULL) {
+ /* Removing this print */
+ /* stm_info("MMC: host->dma_done is found tobe null ! \n"); */
+ return;
+ }
+ u8500_mmc_dma_transfer_done(host);
+ return;
+}
+
+/**
+ * u8500_mmc_set_dma() - initiates the DMA transfer
+ * @host: pointer to the u8500_mmci_host register
+ *
+ * configures the DMA channel and selects the burst size depending on the
+ * data size and enables the dma transfer for the corresponding device
+ * either sdmmc or emmc
+ */
+static void u8500_mmc_set_dma(struct u8500_mmci_host *host)
+{
+ struct dma_async_tx_descriptor *dmach_desc;
+ struct mmc_data *data;
+#ifndef DMA_SCATERGATHER
+ u32 *buffer, *ptr, *buffer1;
+ unsigned long flag_lock = 0;
+ u32 sg_len;
+#endif
+ enum dma_data_direction direction;
+ data = host->data;
+
+ direction = (data->flags & MMC_DATA_READ)
+ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+#ifdef DMA_SCATERGATHER
+/* #warning " scatter gather is compiled " */
+ data->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len, direction);
+#else
+ spin_lock_irqsave(&host->lock, flag_lock);
+ if (data->flags & MMC_DATA_READ) {
+ buffer = (u32 *)host->dma;
+ } else {
+ ptr = (u32 *) host->dma_buffer;
+ buffer1 = (u32 *) (page_address(sg_page(host->sg_ptr)) +
+ host->sg_ptr->offset) + host->sg_off;
+ memcpy(ptr, buffer1, host->size);
+ buffer = (u32 *)host->dma;
+ }
+ spin_unlock_irqrestore(&host->lock, flag_lock);
+#endif
+
+ if (data->flags & MMC_DATA_READ) {
+ dmach_desc = host->dmach_mmc2mem->device->
+ device_prep_slave_sg(host->dmach_mmc2mem,
+ data->sg, data->sg_len,
+ direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!dmach_desc) {
+ dev_err(mmc_dev(host->mmc),
+ "could not get DMA descriptor");
+ return;
+ }
+
+ dmach_desc->callback = u8500_mmc_dmaclbk;
+ dmach_desc->callback_param = host;
+ dmach_desc->tx_submit(dmach_desc);
+ dma_async_issue_pending(host->dmach_mmc2mem);
+ } else {
+ dmach_desc = host->dmach_mem2mmc->device->
+ device_prep_slave_sg(host->dmach_mem2mmc,
+ data->sg, data->sg_len,
+ direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!dmach_desc) {
+ dev_err(mmc_dev(host->mmc),
+ "could not get DMA descriptor");
+ return;
+ }
+
+ dmach_desc->callback = u8500_mmc_dmaclbk;
+ dmach_desc->callback_param = host;
+ dmach_desc->tx_submit(dmach_desc);
+ dma_async_issue_pending(host->dmach_mem2mmc);
+ }
+}
+/**
+ * u8500_mmci_read() - data read function in polling mode
+ * @host: pointer to the u8500_mmci_host structure
+ * @buffer: pointer to the host buffer
+ * @remain: size of the remaining data to be transferred
+ * @hoststatus: value of the host status register
+ *
+ * the function will read the data from the fifo and copies to the host buffer
+ * in case of polling mode and returns the data transfered
+ */
+static int u8500_mmci_read(struct u8500_mmci_host *host, u32 * buffer,
+ unsigned int remain, u32 hoststatus)
+{
+ void __iomem *base;
+ int count, max_count;
+ unsigned int data_xfered = 0;
+ u8 *char_buf;
+ u16 *word_buf;
+ unsigned int temp;
+ u32 flag = MCI_DATA_IRQ;
+
+ base = host->base;
+ if (host->cmd && host->cmd->opcode == SD_IO_RW_EXTENDED)
+ flag = MCI_DATA_ERR; /* required for SDIO CMD53 */
+
+ while ((remain > 0) && !(hoststatus & flag)) {
+ if ((hoststatus & MCI_RXFIFOHALFFULL) && (remain >= 32))
+ max_count = MCI_FIFOHALFSIZE;
+ else if ((hoststatus & MCI_RXDATAAVLBL) && (remain < 32))
+ max_count = 1;
+ else
+ max_count = 0;
+ for (count = 0; count < max_count; count++) {
+ if (remain == 2) { /* half word aligned, read 16bit half words */
+ word_buf = (u16 *)buffer;
+ *word_buf = readw((u16 *)(base + MMCIFIFO));
+ word_buf++;
+ buffer = (u32 *)word_buf;
+ data_xfered += 2;
+ remain = 0;
+ } else if (remain < 4) {/* not word aligned, read byte by byte */
+ char_buf = (u8 *)buffer;
+ for (temp = 0; temp < remain; temp++) {
+ *char_buf = readb((u8 *)(base + MMCIFIFO));
+ char_buf++;
+ }
+ data_xfered += remain;
+ buffer = (u32 *)char_buf;
+ remain = 0;
+ } else {
+ *buffer = readl(base + MMCIFIFO);
+ buffer++;
+ data_xfered += 4;
+ remain -= 4;
+ }
+ }
+ hoststatus = readl(base + MMCISTATUS);
+ }
+
+ if (remain) {
+ /* stm_dbg2(DBG_ST.mmc,"While READ, Remain is %d, hoststatus is %x, data_xfered is %d\n",
+ * remain, hoststatus, data_xfered);
+ */
+ }
+ return data_xfered;
+}
+/**
+ * u8500_mmci_write() - data write function in polling mode
+ * @host: pointer to the u8500_mmci_host structure
+ * @buffer: pointer to the host buffer
+ * @remain: size of the remaining data to be transfered
+ * @hoststatus: value of the host status register
+ *
+ * the function will write the data from the host buffer to the fifo
+ * in case of polling mode and returns the data transfered
+ */
+static int u8500_mmci_write(struct u8500_mmci_host *host, u32 * buffer,
+ unsigned int remain, u32 hoststatus)
+{
+ void __iomem *base;
+ int count, max_count;
+ unsigned int data_xfered = 0, temp;
+ u16 *buf16;
+ u8 *buf8;
+ u32 flag = MCI_DATA_IRQ;
+
+ base = host->base;
+ if (host->cmd && host->cmd->opcode == SD_IO_RW_EXTENDED)
+ flag = MCI_DATA_ERR; /* required for SDIO CMD53 */
+
+ while ((remain > 0) && !(hoststatus & flag)) {
+ if ((hoststatus & MCI_TXFIFOEMPTY) && (remain >= 64))
+ max_count = MCI_FIFOSIZE;
+ else if ((hoststatus & MCI_TXFIFOHALFEMPTY) && (remain >= 32))
+ max_count = MCI_FIFOHALFSIZE;
+ else if (remain < 32)
+ max_count = 1;
+ else
+ max_count = 0;
+ for (count = 0; count < max_count; count++) {
+ if (remain == 2) { /* half word aligned, read 16bit half words */
+ buf16 = (u16 *)buffer;
+ writew(*buf16, (u16 *)(base + MMCIFIFO));
+ buf16++;
+ buffer = (u32 *)buf16;
+ data_xfered += 2;
+ remain = 0;
+ } else if (remain < 4) /* not word aligned, read byte by byte */ {
+ buf8 = (u8 *)buffer;
+ for (temp = 0; temp < remain; temp++) {
+ writew(*buf8, (u8 *)(base + MMCIFIFO));
+ buf8++;
+ }
+ data_xfered += remain;
+ buffer = (u32 *)buf8;
+ remain = 0;
+ } else {
+ writel(*buffer, (base + MMCIFIFO));
+ buffer++;
+ data_xfered += 4;
+ remain -= 4;
+ }
+ }
+
+ hoststatus = readl(base + MMCISTATUS);
+ }
+ if (remain) {
+ printk(KERN_INFO "While WRITE, Remain is %d, hoststatus is %x, data_xfered is %d\n",
+ remain, hoststatus, data_xfered);
+ }
+ return data_xfered;
+}
+/**
+ * u8500_mmci_read_write() - the function calls corresponding read/write function
+ * @host: pointer to the u8500_mmci_host structure
+ *
+ * this function will call the corresponding read or write function of the polling mode depending
+ * on the flag set in the status register
+ */
+static void u8500_mmci_read_write(struct u8500_mmci_host *host)
+{
+ void __iomem *base;
+ u32 *buffer;
+ u32 hoststatus;
+ struct mmc_data *data;
+ unsigned int remain, len;
+ unsigned long flags = 0;
+
+ u32 temp_flag = MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL;
+ base = host->base;
+ data = host->data;
+
+ hoststatus = readl(base + MMCISTATUS);
+ if (host->cmd && host->cmd->opcode == SD_IO_RW_EXTENDED)
+ temp_flag |= MCI_DATAEND | MCI_DATABLOCKEND; /* Required for SDIO CMD53 */
+
+ while (host->data_xfered < host->size &&
+ (hoststatus & temp_flag)) {
+ /* Do not add any printk or DEBUG at this location */
+ if (data->flags & MMC_DATA_READ) {
+ buffer = host->buffer;
+ remain = host->size;
+ } else {
+ buffer =
+ (u32 *) (page_address(sg_page(host->sg_ptr)) +
+ host->sg_ptr->offset) + host->sg_off;
+ remain = host->sg_ptr->length - host->sg_off;
+ }
+ if (host->devicemode == MCI_POLLINGMODE)
+ local_irq_save(flags);
+ len = 0;
+ if (hoststatus & MCI_RXACTIVE) {
+ len =
+ u8500_mmci_read(host, buffer, remain, hoststatus);
+ } else if (hoststatus & MCI_TXACTIVE) {
+ len =
+ u8500_mmci_write(host, buffer, remain,
+ hoststatus);
+ }
+ if (host->devicemode == MCI_POLLINGMODE)
+ local_irq_restore(flags);
+ spin_lock_irqsave(&host->lock, flags);
+ host->sg_off += len;
+ host->data_xfered += len;
+ remain -= len;
+ if (remain) {
+ printk(KERN_INFO "Remain is %d, hoststatus is %x, host->size is %d, host->data_xfered is %d\n",
+ remain, readl(base + MMCISTATUS), host->size,
+ host->data_xfered);
+ spin_unlock_irqrestore(&host->lock, flags);
+ break;
+ }
+ if ((--host->sg_len) && (data->flags & MMC_DATA_WRITE)) {
+ host->sg_ptr++;
+ host->sg_off = 0;
+ } else {
+ spin_unlock_irqrestore(&host->lock, flags);
+ break;
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ hoststatus = readl(base + MMCISTATUS);
+ }
+
+ if (host->devicemode == MCI_INTERRUPTMODE) {
+ /** If we're nearing the end of the read, switch to
+ * "any data available" mode
+ */
+ if ((hoststatus & MCI_RXACTIVE) &&
+ (host->size - host->data_xfered) < MCI_FIFOSIZE) {
+ u8500_mmc_enableirqsrc(base, MCI_RXDATAAVLBL);
+ }
+ /*
+ * If we run out of data, disable the data IRQs; this
+ * prevents a race where the FIFO becomes empty before
+ * the chip itself has disabled the data path, and
+ * stops us racing with our data end IRQ
+ */
+ if (host->size == host->data_xfered) {
+ u8500_mmc_disableirqsrc(base, MCI_XFER_IRQ_MASK);
+ }
+ } else if (host->devicemode == MCI_POLLINGMODE) {
+
+ u8500_mmci_cmd_irq(host, hoststatus);
+ u8500_mmci_data_irq(host, hoststatus);
+ }
+}
+
+/**
+ * start_data_xfer() - configures the data control registers
+ * @host: pointer to the u8500_mmci_host
+ *
+ * this function configures the data control registers for enabling the data path,
+ * and direction of data transfer and configures the data length register with
+ * the data size to be transfered and configures the data timer register
+ */
+static void start_data_xfer(struct u8500_mmci_host *host)
+{
+ void __iomem *base;
+ struct mmc_data *data;
+ unsigned int size;
+ u32 temp_reg;
+ u32 clk_reg;
+ unsigned int temp;
+ data = host->data;
+ base = host->base;
+ size = host->size;
+
+ BUG_ON(!data);
+ BUG_ON(!(data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)));
+ BUG_ON((data->flags & MMC_DATA_READ) && (data->flags & MMC_DATA_WRITE));
+ BUG_ON(!host->cmd);
+
+ /**
+ * Required for SDIo CMD53, for transfer sizes <8, H/W flow
+ * control should be disabled
+ */
+ if (host->cmd->opcode == SD_IO_RW_EXTENDED) {
+ clk_reg = readl(host->base + MMCICLOCK);
+ if (host->size < 8)
+ clk_reg &= ~(MCI_HWFC_EN);
+ else
+ clk_reg |= (MCI_HWFC_EN);
+ writel(clk_reg, host->base + MMCICLOCK);
+ }
+
+ writel(0x0FFFFFFF, (base + MMCIDATATIMER));
+
+ /**
+ * Work around for SDIO multibyte mode, required for H/W
+ * limitation, as byte mode is not supported in host controller
+ */
+#ifdef SDIO_MULTIBYTE_WORKAROUND
+ if (host->cmd && (host->cmd->opcode == SD_IO_RW_EXTENDED) && !(host->cmd->arg & 0x08000000)) {
+ temp = __fls(host->aligned_blksz);
+ writel(host->aligned_size, (base + MMCIDATALENGTH));
+ } else {
+ writel(size, (base + MMCIDATALENGTH));
+ temp = __fls(data->blksz);
+ /* Get the last set bit position i.e power of two */
+ }
+#else
+ writel(size, (base + MMCIDATALENGTH));
+ temp = __fls(data->blksz); /* Get the last set bit position, i.e., power of two */
+#endif /* End of SDIO_MULTIBYTE_WORKAROUND */
+
+ /*
+ * On DB8500v2, the block size is moved to a different offset, and it
+ * takes the direct value instead of a power of two.
+ */
+ if (cpu_is_u8500v2())
+ temp_reg = MCI_DPSM_ENABLE | (data->blksz << 16);
+ else
+ temp_reg = MCI_DPSM_ENABLE | ((temp & 0xF) << 4);
+
+ if (host->devicemode == MCI_DMAMODE) {
+ /* Enable the DMA mode of the MMC Host Controller */
+ temp_reg |= MCI_DPSM_DMAENABLE;
+ temp_reg |= MCI_DPSM_DMAreqctl;
+ }
+ if ((data->flags & MMC_DATA_READ)) {
+ temp_reg |= MCI_DPSM_DIRECTION;
+ }
+
+ if (host->devicemode == MCI_DMAMODE)
+ u8500_mmc_enableirqsrc(base, MCI_DATA_ERR);
+ else if (host->devicemode == MCI_INTERRUPTMODE) {
+ u8500_mmc_enableirqsrc(base, (MCI_DATA_IRQ | MCI_XFER_IRQ));
+ if (host->size < MCI_FIFOSIZE) {
+ u8500_mmc_enableirqsrc(base, MCI_RXDATAAVLBL);
+ }
+ }
+ /* Required for SDIO CMD53 and SDIO interrupt */
+ if (host->cmd->opcode == SD_IO_RW_EXTENDED)
+ temp_reg |= MCI_SDIO_ENABLE;
+
+ writel(temp_reg, (base + MMCIDATACTRL));
+
+}
+static void u8500_mmci_xfer_irq(struct u8500_mmci_host *host,
+ u32 hoststatus)
+{
+ hoststatus &= MCI_XFER_IRQ_MASK;
+ if (!hoststatus)
+ return;
+ BUG_ON(host->devicemode != MCI_INTERRUPTMODE);
+ u8500_mmci_read_write(host);
+}
+/**
+ * u8500_mmci_cmd_irq() - called to service the command status interrupt
+ * @host: pointer to the u8500_mmci_host
+ * @hoststatus: value of the hoststatus register
+ *
+ * this function processes the command request end in the interrupt mode and will
+ * inform the stack about the request end
+ */
+static void u8500_mmci_cmd_irq(struct u8500_mmci_host *host, u32 hoststatus)
+{
+ void __iomem *base;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ u32 cmdstatusmask;
+ cmd = host->cmd;
+ data = host->data;
+ base = host->base;
+ if (cmd) {
+ cmdstatusmask = MCI_CMDTIMEOUT | MCI_CMDCRCFAIL;
+ if ((cmd->flags & MMC_RSP_PRESENT))
+ cmdstatusmask |= MCI_CMDRESPEND;
+ else
+ cmdstatusmask |= MCI_CMDSENT;
+ } else
+ cmdstatusmask = 0;
+ hoststatus &= cmdstatusmask;
+ if (!hoststatus)
+ return;
+ process_command_end(host, hoststatus);
+
+ if (!cmd->data || cmd->error != MMC_ERR_NONE) {
+ if (cmd->error != MMC_ERR_NONE && data) {
+ /* printk("The COMMCND NUMBER IS : %d status register value is : %d\n",
+ cmd->opcode, hoststatus); */
+ if (host->devicemode == MCI_POLLINGMODE) {
+ u8500_mmci_stop_data(host);
+ if (!data->stop)
+ u8500_mmci_request_end(host, data->mrq);
+ else
+ u8500_mmci_start_command(host, data->stop);
+ } else {
+ data->error = cmd->error;
+ u8500_mmc_dma_transfer_done(host);
+ return;
+ }
+ } else {
+ u8500_mmci_request_end(host, cmd->mrq);
+ }
+ } else if (!(cmd->data->flags & MMC_DATA_READ)) {
+ start_data_xfer(host);
+ }
+ hoststatus &= ~(MCI_SDIOIT);
+ u8500_mmc_clearirqsrc(base, hoststatus);
+}
+/**
+ * u8500_mmci_data_irq() - called to service the data transfer status interrupt
+ * @host: pointer to the u8500_mmci_host
+ * @hoststatus: value of the hoststatus register
+ *
+ * this function processes the command with data request end in the interrupt mode and will
+ * inform the stack about the request end
+ */
+static void u8500_mmci_data_irq(struct u8500_mmci_host *host,
+ u32 hoststatus)
+{
+ struct mmc_data *data;
+ struct mmc_command *cmd;
+ struct mmc_host *mmc;
+ hoststatus &= MCI_DATA_IRQ;
+
+ if (!hoststatus) {
+ return;
+ }
+ cmd = host->cmd;
+ data = host->data;
+ mmc = host->mmc;
+
+ if (!data) {
+ goto clear_data_irq;
+ }
+ data->error = check_for_data_err(hoststatus);
+
+ if (data->error != MMC_ERR_NONE)
+ stm_error("In %d Cmd, data_irq, data->error is %d, data_xfered is %d, hoststatus = %x",
+ cmd->opcode, data->error, host->data_xfered, hoststatus);
+
+ if (host->devicemode == MCI_DMAMODE && data->error != MMC_ERR_NONE) {
+ u8500_mmc_dma_transfer_done(host);
+ return;
+ }
+ if (!data->error) {
+ if ((data->flags & MMC_DATA_READ)
+ && (host->devicemode != MCI_DMAMODE)) {
+ u32 *buffer_local, *buffer;
+ u8500_mmci_init_sg(host, data);
+ buffer_local = host->buffer;
+ while (host->sg_len--) {
+ buffer =
+ (u32 *) (page_address(sg_page(host->sg_ptr)) + host->sg_ptr->offset);
+ memcpy(buffer, buffer_local,
+ host->sg_ptr->length);
+ buffer_local += host->sg_ptr->length / 4;
+ flush_dcache_page(sg_page(host->sg_ptr));
+ host->sg_ptr++;
+ host->sg_off = 0;
+ }
+ }
+ }
+
+ u8500_mmci_stop_data(host);
+
+ if (!data->stop)
+ u8500_mmci_request_end(host, data->mrq);
+ else
+ u8500_mmci_start_command(host, data->stop);
+clear_data_irq:
+ hoststatus &= ~(MCI_SDIOIT);
+ u8500_mmc_clearirqsrc(host->base, hoststatus);
+}
+
+/**
+ * u8500_mmci_irq() - interrupt handler registred for sd controller interrupt
+ * @irq: irq interrupt source number
+ * @dev_id: dev_id pointer to the current device id
+ *
+ * this function is the interrupt handler registered for sdmmc interrupt and this
+ * will be invoked on any interrupt from mmc
+ */
+static irqreturn_t u8500_mmci_irq(int irq, void *dev_id)
+{
+ struct u8500_mmci_host *host = dev_id;
+ void __iomem *base;
+ u32 hoststatus;
+
+ base = host->base;
+
+ hoststatus = readl(base + MMCISTATUS);
+ hoststatus &= readl(base + MMCIMASK0);
+
+ while (hoststatus) {
+ if ((hoststatus & MCI_XFER_IRQ_MASK))
+ u8500_mmci_xfer_irq(host, hoststatus);
+ if ((hoststatus & MCI_CMD_IRQ))
+ u8500_mmci_cmd_irq(host, hoststatus);
+ if ((hoststatus & MCI_DATA_IRQ))
+ u8500_mmci_data_irq(host, hoststatus);
+ if (hoststatus & MCI_SDIOIT) {
+ /* Explicitly clear SDIOIT */
+ writel(MCI_SDIOIT, (base + MMCICLEAR));
+ /* printk("\n START SDIO IRQ handler"); */
+ if (host->mmc->card && host->mmc->card->sdio_func[0] &&
+ host->mmc->card->sdio_func[0]->irq_handler) {
+ struct sdio_func *func = host->mmc->card->sdio_func[0];
+ host->mmc->card->sdio_func[0]->irq_handler(func);
+ /* printk("\n END SDIO IRQ handler"); */
+ }
+ }
+ u8500_mmc_clearirqsrc(base, hoststatus);
+ hoststatus = readl(base + MMCISTATUS);
+ hoststatus &= readl(base + MMCIMASK0);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * u8500_mmci_start_data() - Processes the command with data request recieved from MMC framework
+ * @host: Pointer to the host structure for MMC
+ * @data: Pointer to the mmc data structure
+ * @cmd: Pointer to the mmc comand structure
+ */
+static void u8500_mmci_start_data(struct u8500_mmci_host *host,
+ struct mmc_data *data,
+ struct mmc_command *cmd)
+{
+ DECLARE_COMPLETION_ONSTACK(complete);
+ void __iomem *base;
+ unsigned long flag_lock = 0;
+ unsigned int mem_addr;
+
+ spin_lock_irqsave(&host->lock, flag_lock);
+ host->data = data;
+ host->cmd = cmd;
+ host->size = data->blocks * data->blksz;
+ host->data_xfered = 0;
+ base = host->base;
+
+ spin_unlock_irqrestore(&host->lock, flag_lock);
+
+ u8500_mmci_init_sg(host, data);
+
+ /**
+ * Required for SDIO DMA mode, dynamic switching between polling
+ * and DMA mode, depending on transfer size, and address alignment.
+ * For transfer size < 32 and for element size unaligned address
+ * SDIO host is configured in polling mode.
+ */
+ if ((host->cmd->opcode == SD_IO_RW_EXTENDED) &&
+ (sdio_mode == MCI_DMAMODE)) {
+ mem_addr = (unsigned int)(page_address(sg_page(host->sg_ptr)) +
+ host->sg_ptr->offset) + host->sg_off;
+
+ if ((mem_addr % DMA_ELEMENT_SZ) ||
+ (host->size < MIN_DATA_SIZE_DMA))
+ host->devicemode = MCI_POLLINGMODE;
+ else
+ host->devicemode = MCI_DMAMODE;
+
+ }
+#ifdef SDIO_MULTIBYTE_WORKAROUND
+ /**
+ * Work around for multibyte mode, required for SDIO CMD 53
+ * size alignment required as host controller H/W does not
+ * support byte mode
+ */
+ if (host->cmd && (host->cmd->opcode == SD_IO_RW_EXTENDED) && !(host->cmd->arg & 0x08000000)) {
+ host->aligned_blksz = (1 << __fls(data->blksz));
+ if (host->aligned_blksz < data->blksz) /* If the no. is not power of two, get next power of two */
+ host->aligned_blksz = host->aligned_blksz << 1;
+ if (host->aligned_blksz > 4096) /* Error handling, not sure if this will ever occur */
+ host->aligned_blksz = data->blksz;
+ host->cmd->arg &= ~(0x1FF); /* reset block size in command args to zero */
+ if (host->aligned_blksz < 512)
+ host->cmd->arg |= host->aligned_blksz;
+ host->aligned_size = data->blocks * host->aligned_blksz;
+ /* else blksz in arg will be zero. */
+#if 0
+ else { /* 512 MULTI BYET not working , so always send 512 as block mode */
+ host->cmd->arg |= data->blocks;
+ host->cmd->arg |= 0x08000000;
+ }
+#endif
+ }
+#endif /* End of SDIO_MULTIBYTE_WORKAROUND */
+ cmd->error = MMC_ERR_NONE;
+ data->error = MMC_ERR_NONE;
+
+ if (host->devicemode == MCI_DMAMODE)
+ u8500_mmc_set_dma(host);
+ /**
+ * For a read we need to write to the data ctrl register first, then
+ * send the command. For writes, the order is reversed.
+ */
+ if ((data->flags & MMC_DATA_READ))
+ start_data_xfer(host);
+ if (host->devicemode == MCI_DMAMODE)
+ host->dma_done = &complete;
+ u8500_mmc_send_cmd(base, cmd->opcode, cmd->arg, cmd->flags, host->devicemode);
+
+ /**
+ * Required for SDIO interrupt from card , always enable SDIOIT ,
+ * even if MMC_CAP_SDIO_IRQ is not set
+ */
+ if ((host->is_sdio == 1) /* && (host->mmc->caps & MMC_CAP_SDIO_IRQ) */) {
+ /* Explicitly enable SDIOIT */
+ if (host->sdio_setirq && !(host->sdio_irqstatus)) {
+ /* If nterrupt is not already enabled then enable SDIOIT MASK */
+ writel(MCI_SDIOIT, (base + MMCICLEAR));
+ writel((readl(base + MMCIMASK0) | MCI_SDIOIT), (base + MMCIMASK0));
+ host->sdio_irqstatus = 1;
+ } else if (!(host->sdio_setirq) && (host->sdio_irqstatus)) {
+ /* If SDIO is not already disabled then disable SDIOIT */
+ u32 temp = readl(base + MMCIMASK0);
+ temp &= ~(MCI_SDIOIT);
+ writel(temp, (base + MMCIMASK0));
+ host->sdio_irqstatus = 0;
+ }
+ }
+
+ if (host->devicemode == MCI_POLLINGMODE) {
+ if (!(data->flags & MMC_DATA_READ))
+ wait_for_command_end(host);
+ while (data->error == MMC_ERR_NONE && host->data) {
+ u8500_mmci_read_write(host);
+ schedule();
+ }
+ }
+ return ;
+}
+/**
+ * u8500_mmci_start_command() - Processes the command request recieved from MMC framework
+ * @host: Pointer to the host structure for MMC
+ * @cmd: Pointer to the mmc command structure
+ */
+static void
+u8500_mmci_start_command(struct u8500_mmci_host *host,
+ struct mmc_command *cmd)
+{
+ void __iomem *base = host->base;
+
+ host->cmd = cmd;
+ u8500_mmc_send_cmd(base, cmd->opcode, cmd->arg, cmd->flags, host->devicemode);
+ if (host->devicemode == MCI_POLLINGMODE) {
+ wait_for_command_end(host);
+ }
+ return;
+}
+
+/**
+ * u8500_mmci_request() - Processes the request recieved from MMC framework
+ * @mmc: Pointer to the host structure for MMC
+ * @mrq: Pointer to the mmc request structure
+ */
+static void u8500_mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct u8500_mmci_host *host = mmc_priv(mmc);
+ WARN_ON(host->mrq != NULL);
+ if (host->mrq != NULL) {
+ mrq->cmd->error = -EIO;
+ if (mrq->data)
+ mrq->data->bytes_xfered = 0;
+ return;
+ }
+ host->mrq = mrq;
+ if (mrq->data && mrq->data->flags & (MMC_DATA_READ | MMC_DATA_WRITE))
+ u8500_mmci_start_data(host, mrq->data, mrq->cmd);
+ else
+ u8500_mmci_start_command(host, mrq->cmd);
+}
+
+/**
+ * u8500_mmci_set_ios() - Perform configuration related settings for MMC host
+ * @mmc: the pointer to the host structure for MMC
+ * @ios: pointer to the configuration settings to be done
+ */
+static void u8500_mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct u8500_mmci_host *host = mmc_priv(mmc);
+ u32 clk = 0;
+
+ /**
+ * Make sure we aren't changing the control registers too soon after
+ * writing data.
+ */
+ udelay(10);
+ /* Set the bus and power modes */
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ if (!host->level_shifter) {
+ writel(0x40, host->base + MMCIPOWER);
+ } else {
+ writel(0xBC, host->base + MMCIPOWER);
+ }
+
+ if (host->board->set_power)
+ host->board->set_power(mmc_dev(mmc), 0);
+#ifdef CONFIG_REGULATOR
+ /* we disable the supplies for the SD */
+ if (host->level_shifter) {
+ if (regulator_is_enabled(host->regulator))
+ regulator_disable(host->regulator);
+ }
+#endif
+ break;
+ case MMC_POWER_UP:
+ if (!host->level_shifter) {
+ writel(0x42, host->base + MMCIPOWER);
+ } else {
+ writel(0xBE, host->base + MMCIPOWER);
+ }
+
+ if (host->board->set_power)
+ host->board->set_power(mmc_dev(mmc), 1);
+ if ((host->is_sdio == 1) && (!host->level_shifter))
+ writel(0xBE, host->base + MMCIPOWER);
+#ifdef CONFIG_REGULATOR
+ if (host->level_shifter) {
+ if (!regulator_is_enabled(host->regulator))
+ regulator_enable(host->regulator);
+ }
+#endif
+ break;
+ case MMC_POWER_ON:
+ if (!host->level_shifter)
+ writel(0x43, host->base + MMCIPOWER);
+ else
+ writel(0xBF, host->base + MMCIPOWER);
+ if ((host->is_sdio == 1) && (!host->level_shifter))
+ writel(0x3, host->base + MMCIPOWER);
+ break;
+ }
+ if (ios->clock) {
+ if (ios->clock >= (host->mclk / 2))
+ clk = 0;
+ else {
+ u32 div = host->mclk / ios->clock;
+ if (div > 2) {
+ clk = div - 2;
+ if (clk > 255)
+ clk = 255;
+ } else
+ clk = 0;
+
+ host->cclk = host->mclk / (clk + 2);
+ if (host->cclk > ios->clock) {
+ clk += 1;
+ host->cclk = host->mclk / (clk + 2);
+ }
+ }
+ if ((host->devicemode == MCI_DMAMODE)
+ && !host->is_sdio && !host->level_shifter)
+ clk |= MCI_CLK_PWRSAVE;
+ clk |= (MCI_HWFC_EN | MCI_CLK_ENABLE);
+ writel(clk, host->base + MMCICLOCK);
+ }
+
+ if (!host->level_shifter) {
+ if (ios->bus_mode == MMC_BUSMODE_PUSHPULL)
+ writel(0x03, host->base + MMCIPOWER);
+ }
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_1:
+ break;
+ case MMC_BUS_WIDTH_4:
+ clk = readl(host->base + MMCICLOCK);
+ clk |= MCI_BUS_WIDTH_4;
+ writel(clk, host->base + MMCICLOCK);
+ break;
+ case MMC_BUS_WIDTH_8:
+ clk = readl(host->base + MMCICLOCK);
+ clk |= MCI_BUS_WIDTH_8;
+ writel(clk, host->base + MMCICLOCK);
+ break;
+ default:
+ stm_info("u8500_mmci_setios(): whats going on ??");
+ break;
+ }
+}
+
+static void sdio_enableirq(struct mmc_host *mmc, int enable)
+{
+ struct u8500_mmci_host *host = mmc_priv(mmc);
+ stm_info(" sdio_enableirq= %d", enable);
+ if (host && host->is_sdio)
+ host->sdio_setirq = enable;
+}
+
+static struct mmc_host_ops u8500_mmci_ops = {
+ .request = u8500_mmci_request,
+ .set_ios = u8500_mmci_set_ios,
+ .enable_sdio_irq = sdio_enableirq,
+};
+
+/**
+ * u8500_mmci_check_status() - checks the status of the card on every interval
+ * @data: pointer to the current host
+ *
+ * this function will check the status of the card on every interval
+ * of the time configured and inform the status to the mmc stack
+ */
+static void u8500_mmci_check_status(void *data)
+{
+ struct u8500_mmci_host *host = (struct u8500_mmci_host *) data;
+ mdelay(50);
+ mmc_detect_change(host->mmc, 30);
+ return;
+}
+
+/**
+ * u8500_mmci_probe() - intilaizing the mmc device
+ * @dev: mmc device pointer
+ * @id: bus_id
+ *
+ * this function will use the current mmc device pointer, initialize and configure
+ * the device, allocate the memory for the device,request the memory region with the
+ * device name and scan the device
+ */
+static int u8500_mmci_probe(struct amba_device *dev, struct amba_id *id)
+{
+ struct u8500_mmci_host *host;
+ struct mmc_host *mmc;
+ int ret;
+ int devicemode = mmc_mode;
+ struct mmc_board *board = dev->dev.platform_data;
+ stm_info("MMC: operating mode is set to %d [where 1=dma,2=poll,3=intr]",
+ devicemode);
+ if (!board) {
+ stm_error("mmc: Platform data not set");
+ return -EINVAL;
+ }
+ if (board->is_sdio)
+ devicemode = sdio_mode;
+ else
+ devicemode = mmc_mode;
+
+ if (board->init) {
+ ret = board->init(dev);
+ if (ret) {
+ stm_error("Error in configuring MMC");
+ goto out;
+ }
+ }
+
+ ret = amba_request_regions(dev, DRIVER_NAME);
+ if (ret) {
+ stm_error(" Error in amba_request_region");
+ goto configure_mmc;
+ }
+ mmc = mmc_alloc_host(sizeof(struct u8500_mmci_host), &dev->dev);
+ if (!mmc) {
+ ret = -ENOMEM;
+ goto rel_regions;
+ }
+ host = mmc_priv(mmc);
+ host->oldstat = -1;
+ host->mclk = MMC_HOST_CLK_MAX;
+ host->mmc = mmc;
+ host->board = board;
+ if (board->bus_resume_flags) {
+ host->bus_resume_flags = board->bus_resume_flags;
+ mmc->bus_resume_flags = host->bus_resume_flags;
+ }
+
+ if (board->level_shifter)
+ host->level_shifter = board->level_shifter;
+ /**
+ * For SDIO , as DMA to polling switching happens dynamically , always need to allocate buffer
+ */
+ if (board->is_sdio || (devicemode == MCI_POLLINGMODE)) {
+ host->buffer = vmalloc(MAX_DATA);
+ if (!host->buffer) {
+ ret = -ENOMEM;
+ goto free_mmc;
+ }
+ }
+ host->base = ioremap(dev->res.start, SZ_4K);
+ if (!host->base) {
+ ret = -ENOMEM;
+ goto host_free;
+ }
+ mmc->ops = &u8500_mmci_ops;
+ mmc->f_max = min(host->mclk, fmax);
+ mmc->f_min = MMC_HOST_CLK_MAX / (MMC_CLK_DIV + 2);
+ if (devicemode == MCI_DMAMODE)
+ mmc->caps = host->board->caps;
+
+ host->is_sdio = board->is_sdio;
+ if (host->is_sdio) {
+ if (host->board->caps & MMC_CAP_SDIO_IRQ)
+ host->sdio_setirq = 0;
+ else
+ host->sdio_setirq = 1;
+ /* Make IRQ enable even when SDIO_IRQ is not supported in capability */
+
+ host->sdio_irqstatus = 0;
+ mmc->caps = host->board->caps;
+ }
+
+ host->devicemode = devicemode;
+ /*
+ * We can do SGIO
+ */
+ if (devicemode == MCI_DMAMODE) {
+ /* scatter/gather DMA */
+ mmc->max_hw_segs = MMC_MAX_HW_SEGMENTS;
+ mmc->max_phys_segs = MMC_MAX_PHY_SEGMENTS;
+ } else {
+ mmc->max_hw_segs = 1;
+ mmc->max_phys_segs = 1;
+ }
+ mmc->ocr_avail = OCR_AVAIL;
+ /**
+ * XXX No errors in Tx/Rx but writes garbage data with mmc->max_req_size = 32768;
+ */
+#ifdef DMA_SCATERGATHER
+ mmc->max_req_size = MMC_MAX_REQ_SIZE;
+#else
+ mmc->max_req_size = 4096;
+#endif
+ mmc->max_seg_size = MMC_MAX_SEG_SIZE;
+
+ mmc->max_blk_size = 4096;
+ if (devicemode == MCI_DMAMODE)
+ mmc->max_blk_count = mmc->max_req_size / MMC_HOST_BLK_SIZE;
+ else
+ mmc->max_blk_count = 64;
+ spin_lock_init(&host->lock);
+
+#ifdef CONFIG_REGULATOR
+ /* attach regulator for on board emmc */
+ if (board->supply) {
+ host->regulator = regulator_get(&dev->dev, board->supply);
+ if (IS_ERR(host->regulator)) {
+ ret = PTR_ERR(host->regulator);
+ goto host_free;
+ }
+ regulator_set_voltage(host->regulator,
+ board->min_supply_voltage,
+ board->max_supply_voltage);
+ regulator_enable(host->regulator);
+ }
+#endif
+ host->clk = clk_get(&dev->dev, NULL);
+ if (IS_ERR(host->clk)) {
+ ret = PTR_ERR(host->clk);
+#ifdef CONFIG_REGULATOR
+ goto put_regulator;
+#else
+ goto unmap;
+#endif
+ }
+
+ clk_enable(host->clk);
+ writel(0, host->base + MMCIMASK0);
+ writel(0xfff, host->base + MMCICLEAR);
+ if ((devicemode != MCI_POLLINGMODE) || (host->is_sdio == 1)) {
+ /* interrupt should always be enabled for I/O cards */
+ ret = request_irq(dev->irq[0], u8500_mmci_irq,
+ IRQF_DISABLED/* SA_INTERRUPT */, DRIVER_NAME, host);
+ if (ret)
+ goto put_clk;
+ }
+ amba_set_drvdata(dev, mmc);
+ if (board->card_detect) {
+ board->card_detect(u8500_mmci_check_status, (void *)host);
+ host->card_detect_intr_value = board->card_detect_intr_value;
+ }
+ stm_info("%s: MMCI rev %x cfg %02x at 0x%08x irq %d",
+ mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
+ dev->res.start, dev->irq[0]);
+ if (devicemode == MCI_DMAMODE) {
+ dma_cap_mask_t mask;
+
+#ifndef DMA_SCATERGATHER
+ host->dma_buffer = (u32 *)dma_alloc_coherent(NULL, 4096, &host->dma, (GFP_KERNEL | GFP_DMA));
+#endif
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ host->dmach_mmc2mem
+ = dma_request_channel(mask, host->board->dma_filter,
+ host->board->dma_mmc2mem);
+ if (host->dmach_mmc2mem == NULL) {
+ stm_error("RX pipe request failed");
+ goto irq0_free;
+ }
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ host->dmach_mem2mmc
+ = dma_request_channel(mask, host->board->dma_filter,
+ host->board->dma_mem2mmc);
+ if (host->dmach_mmc2mem == NULL) {
+ stm_error("TX pipe request failed");
+ goto mem2mmc_dmareq_failed;
+ }
+
+ }
+ /*
+ * SDIO host structure is saved into global pointer
+ * Used for sysfs implementation for dynamic detection of I/O cards
+ * Also create sysfs file for detect_card
+ */
+ if (host->is_sdio) {
+ ret = device_create_file(&dev->dev, &dev_attr_detect_card);
+ if (ret < 0) {
+ stm_error("Could not create sysfs file"
+ "for SDIO detect_card");
+ goto create_file_failed;
+ }
+ sdio_host_ptr = host;
+ }
+
+ ret = mmc_add_host(mmc);
+ if (ret)
+ goto add_host_failed;
+
+ return 0;
+add_host_failed:
+ if (host->is_sdio)
+ device_remove_file(&dev->dev, &dev_attr_detect_card);
+create_file_failed:
+ if (host->dmach_mem2mmc)
+ dma_release_channel(host->dmach_mem2mmc);
+mem2mmc_dmareq_failed:
+ if (host->dmach_mmc2mem)
+ dma_release_channel(host->dmach_mmc2mem);
+irq0_free:
+ if (devicemode != MCI_POLLINGMODE || host->is_sdio)
+ free_irq(dev->irq[0], host);
+put_clk:
+ clk_disable(host->clk);
+ clk_put(host->clk);
+#ifdef CONFIG_REGULATOR
+put_regulator:
+ if (host->regulator) {
+ if (regulator_is_enabled(host->regulator))
+ regulator_disable(host->regulator);
+ regulator_put(host->regulator);
+ }
+#else
+unmap:
+#endif
+ iounmap(host->base);
+host_free:
+ vfree(host->buffer);
+free_mmc:
+ mmc_free_host(mmc);
+rel_regions:
+ amba_release_regions(dev);
+configure_mmc:
+ if (board->exit)
+ board->exit(dev);
+out:
+ return ret;
+}
+/**
+ * u8500_mmci_remove() - Remove the mmc by freeing all resources
+ * @dev: current mmc device pointer
+ *
+ * this function will remove the mmc by freeing all resources used by the device by using
+ * the current mmc device pointer
+ */
+static int u8500_mmci_remove(struct amba_device *dev)
+{
+ struct mmc_board *board = dev->dev.platform_data;
+ struct mmc_host *mmc = amba_get_drvdata(dev);
+
+ stm_info("MMC module removed");
+ if (!board)
+ return -EINVAL;
+ amba_set_drvdata(dev, NULL);
+ if (mmc) {
+ struct u8500_mmci_host *host = mmc_priv(mmc);
+
+ /*
+ * global pointer for storing SDIO host structure is cleared
+ * Used for sysfs implementation for dynamic detection of
+ * I/O cards. Also remove sysfs file for detect_card
+ */
+ if (host->is_sdio) {
+ sdio_host_ptr = NULL;
+ device_remove_file(&dev->dev, &dev_attr_detect_card);
+ }
+ mmc_remove_host(mmc);
+ dma_release_channel(host->dmach_mmc2mem);
+ dma_release_channel(host->dmach_mem2mmc);
+ host->dmach_mmc2mem = NULL;
+ host->dmach_mem2mmc = NULL;
+ writel(0, host->base + MMCIMASK0);
+ writel(0, host->base + MMCICOMMAND);
+ writel(0, host->base + MMCIDATACTRL);
+ free_irq(dev->irq[0], host);
+ iounmap(host->base);
+ vfree(host->buffer);
+ mmc_free_host(mmc);
+ amba_release_regions(dev);
+ if (board->exit)
+ board->exit(dev);
+ clk_disable(host->clk);
+ clk_put(host->clk);
+#ifdef CONFIG_REGULATOR
+ if (host->regulator) {
+ if (regulator_is_enabled(host->regulator))
+ regulator_disable(host->regulator);
+ regulator_put(host->regulator);
+ }
+#endif
+ }
+ return 0;
+}
+#ifdef CONFIG_PM
+/**
+ * u8500_mmci_suspend() - Use the current mmc device pointer and called the mmc suspend function
+ * @dev: current mmc device pointer
+ * @state: state suspend state
+ */
+static int u8500_mmci_suspend(struct amba_device *dev, pm_message_t state)
+{
+ struct mmc_host *mmc = amba_get_drvdata(dev);
+ int ret = 0;
+
+ if (mmc) {
+ struct u8500_mmci_host *host = mmc_priv(mmc);
+ ret = mmc_suspend_host(mmc);
+ if (host->level_shifter) {
+ host->board->card_detect_intr_conf(0);
+ clk_disable(host->clk);
+#ifdef CONFIG_REGULATOR
+ if (host->board->supply) {
+ if (!host->level_shifter) {
+ if (regulator_is_enabled(host->regulator))
+ regulator_disable(host->regulator);
+ }
+ }
+#endif
+ }
+ }
+ return ret;
+}
+/**
+ * u8500_mmci_resume() - Use the current mmc device pointer and called the mmc resume function
+ * @dev: mmc device pointer
+ */
+static int u8500_mmci_resume(struct amba_device *dev)
+{
+ struct mmc_host *mmc = amba_get_drvdata(dev);
+ int ret = 0;
+
+ if (mmc) {
+ struct u8500_mmci_host *host = mmc_priv(mmc);
+ if (host->level_shifter)
+ host->board->card_detect_intr_conf(1);
+#ifdef CONFIG_REGULATOR
+ if (host->board->supply) {
+ if (!host->level_shifter) {
+ if (!regulator_is_enabled(host->regulator))
+ regulator_enable(host->regulator);
+ }
+ }
+#endif
+ clk_enable(host->clk);
+ ret = mmc_resume_host(mmc);
+ }
+ return ret;
+}
+#else
+#define u8500_mmci_suspend NULL
+#define u8500_mmci_resume NULL
+#endif
+
+
+static struct amba_id u8500_mmci_ids[] = {
+ {
+ .id = SDI_PER_ID,
+ .mask = SDI_PER_MASK,
+ },
+ {0, 0, 0},
+};
+
+static struct amba_driver u8500_mmci_driver = {
+ .drv = {
+ .name = DRIVER_NAME,
+ },
+ .probe = u8500_mmci_probe,
+ .remove = u8500_mmci_remove,
+ .suspend = u8500_mmci_suspend,
+ .resume = u8500_mmci_resume,
+ .id_table = u8500_mmci_ids,
+};
+/**
+ * u8500_mmci_init() - register the mmc driver as amba driver
+ * @void: No arguments
+ */
+static int __init u8500_mmci_init(void)
+{
+ return amba_driver_register(&u8500_mmci_driver);
+}
+/**
+ * u8500_mmci_exit() - unregister the amba mmc driver
+ * @void: No arguments
+ */
+static void __exit u8500_mmci_exit(void)
+{
+ amba_driver_unregister(&u8500_mmci_driver);
+}
+/**
+ * module_init - register the amba mmc driver to the kernel
+ * @u8500_mmci_init: mmc init function call
+ */
+module_init(u8500_mmci_init);
+/**
+ * module_exit() - unregister the amba mmc driver to the kernel
+ * @u8500_mmci_exit: mmc exit function call
+ */
+module_exit(u8500_mmci_exit);
+
+MODULE_AUTHOR("Hanumath Prasad(hanumath.prasad@stericcson.com)");
+MODULE_DESCRIPTION("ARM PrimeCell PL180 Multimedia Card Interface driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/mmc-u8500.h b/drivers/mmc/host/mmc-u8500.h
new file mode 100644
index 00000000000..ae084288c0b
--- /dev/null
+++ b/drivers/mmc/host/mmc-u8500.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2008 STMicroelectronics
+ *
+ * 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 __MMC_NOMADIK
+#define __MMC_NOMADIK
+
+#define MMC_ERR_NONE 0
+#define MMC_ERR_TIMEOUT 1
+#define MMC_ERR_BADCRC 2
+#define MMC_ERR_FIFO 3
+#define MMC_ERR_FAILED 4
+#define MMC_ERR_INVALID 5
+
+#define MMC_VDD_18_19 0x00000040 /* VDD voltage 1.8 - 1.9 */
+#define MMC_VDD_17_18 0x00000020 /* VDD voltage 1.7 - 1.8 */
+#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
+
+#endif
+
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 2ed435bd4b6..6a911b8ecf6 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -26,7 +26,6 @@
#include <linux/amba/mmci.h>
#include <linux/regulator/consumer.h>
-#include <asm/cacheflush.h>
#include <asm/div64.h>
#include <asm/io.h>
#include <asm/sizes.h>
@@ -37,12 +36,55 @@
static unsigned int fmax = 515633;
+/**
+ * struct variant_data - MMCI variant-specific quirks
+ * @clkreg: default value for MCICLOCK register
+ * @clkreg_enable: enable value for MMCICLOCK register
+ * @datalength_bits: number of bits in the MMCIDATALENGTH register
+ * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
+ * is asserted (likewise for RX)
+ * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
+ * is asserted (likewise for RX)
+ * @singleirq: true if only one IRQ line is available
+ */
+struct variant_data {
+ unsigned int clkreg;
+ unsigned int clkreg_enable;
+ unsigned int datalength_bits;
+ unsigned int fifosize;
+ unsigned int fifohalfsize;
+ bool singleirq;
+};
+
+static struct variant_data variant_arm = {
+ .fifosize = 16 * 4,
+ .fifohalfsize = 8 * 4,
+ .datalength_bits = 16,
+};
+
+static struct variant_data variant_u300 = {
+ .fifosize = 16 * 4,
+ .fifohalfsize = 8 * 4,
+ .clkreg_enable = 1 << 13, /* HWFCEN */
+ .datalength_bits = 16,
+};
+
+static struct variant_data variant_ux500 = {
+ .fifosize = 30 * 4,
+ .fifohalfsize = 8 * 4,
+ .clkreg = MCI_CLK_ENABLE,
+ .clkreg_enable = 1 << 14, /* HWFCEN */
+ .datalength_bits = 24,
+ .singleirq = true,
+};
+
/*
* This must be called with host->lock held
*/
static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
{
- u32 clk = 0;
+ struct variant_data *variant = host->variant;
+ u32 clk = variant->clkreg;
if (desired) {
if (desired >= host->mclk) {
@@ -54,8 +96,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
clk = 255;
host->cclk = host->mclk / (2 * (clk + 1));
}
- if (host->hw_designer == AMBA_VENDOR_ST)
- clk |= MCI_ST_FCEN; /* Bug fix in ST IP block */
+
+ clk |= variant->clkreg_enable;
clk |= MCI_CLK_ENABLE;
/* This hasn't proven to be worthwhile */
/* clk |= MCI_CLK_PWRSAVE; */
@@ -91,15 +133,45 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
spin_lock(&host->lock);
}
+static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
+{
+ struct variant_data *variant = host->variant;
+ void __iomem *base = host->base;
+
+ if (variant->singleirq) {
+ unsigned int mask0 = readl(base + MMCIMASK0);
+
+ mask0 &= ~MCI_IRQ1MASK;
+ mask0 |= mask;
+
+ writel(mask0, base + MMCIMASK0);
+ }
+
+ writel(mask, base + MMCIMASK1);
+}
+
static void mmci_stop_data(struct mmci_host *host)
{
writel(0, host->base + MMCIDATACTRL);
- writel(0, host->base + MMCIMASK1);
+ mmci_set_mask1(host, 0);
host->data = NULL;
}
+static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
+{
+ unsigned int flags = SG_MITER_ATOMIC;
+
+ if (data->flags & MMC_DATA_READ)
+ flags |= SG_MITER_TO_SG;
+ else
+ flags |= SG_MITER_FROM_SG;
+
+ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
+}
+
static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
{
+ struct variant_data *variant = host->variant;
unsigned int datactrl, timeout, irqmask;
unsigned long long clks;
void __iomem *base;
@@ -109,7 +181,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
data->blksz, data->blocks, data->flags);
host->data = data;
- host->size = data->blksz;
+ host->size = data->blksz * data->blocks;
host->data_xfered = 0;
mmci_init_sg(host, data);
@@ -135,7 +207,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
* If we have less than a FIFOSIZE of bytes to transfer,
* trigger a PIO interrupt as soon as any data is available.
*/
- if (host->size < MCI_FIFOSIZE)
+ if (host->size < variant->fifosize)
irqmask |= MCI_RXDATAAVLBLMASK;
} else {
/*
@@ -147,7 +219,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
writel(datactrl, base + MMCIDATACTRL);
writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
- writel(irqmask, base + MMCIMASK1);
+ mmci_set_mask1(host, irqmask);
}
static void
@@ -182,20 +254,7 @@ static void
mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
unsigned int status)
{
- if (status & MCI_DATABLOCKEND) {
- host->data_xfered += data->blksz;
-#ifdef CONFIG_ARCH_U300
- /*
- * On the U300 some signal or other is
- * badly routed so that a data write does
- * not properly terminate with a MCI_DATAEND
- * status flag. This quirk will make writes
- * work again.
- */
- if (data->flags & MMC_DATA_WRITE)
- status |= MCI_DATAEND;
-#endif
- }
+ /* First check for errors */
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status);
if (status & MCI_DATACRCFAIL)
@@ -204,18 +263,78 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
data->error = -ETIMEDOUT;
else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
data->error = -EIO;
- status |= MCI_DATAEND;
+
+ /* Force-complete the transaction */
+ host->blockend = true;
+ host->dataend = true;
/*
* We hit an error condition. Ensure that any data
* partially written to a page is properly coherent.
*/
- if (host->sg_len && data->flags & MMC_DATA_READ)
- flush_dcache_page(sg_page(host->sg_ptr));
+ if (data->flags & MMC_DATA_READ) {
+ struct sg_mapping_iter *sg_miter = &host->sg_miter;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (sg_miter_next(sg_miter)) {
+ flush_dcache_page(sg_miter->page);
+ sg_miter_stop(sg_miter);
+ }
+ local_irq_restore(flags);
+ }
}
- if (status & MCI_DATAEND) {
+
+ /*
+ * On ARM variants in PIO mode, MCI_DATABLOCKEND
+ * is always sent first, and we increase the
+ * transfered number of bytes for that IRQ. Then
+ * MCI_DATEND follows and we conclude the transaction.
+ *
+ * The Ux500 single-IRQ variant only fires the
+ * MCI_DATAEND IRQ at the end of the entire transfer.
+ *
+ * In the U300, the IRQs can arrive out-of-order,
+ * e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND,
+ * so in this case we use the flags "blockend" and
+ * "dataend" to make sure both IRQs have arrived before
+ * concluding the transaction. (This does not apply
+ * to the Ux500 which doesn't fire MCI_DATABLOCKEND
+ * at all.)
+ */
+ if (status & MCI_DATABLOCKEND) {
+ /*
+ * Just being a little over-cautious, we do not
+ * use this progressive update in DMA or single-IRQ
+ * mode.
+ */
+ if (!host->variant->singleirq)
+ host->data_xfered += data->blksz;
+ host->blockend = true;
+ }
+
+ if (status & MCI_DATAEND)
+ host->dataend = true;
+
+ /*
+ * On Ux500 we shall only wait for dataend, on others we must sync
+ * with the blockend signal since they can appear out-of-order.
+ */
+ if (host->dataend && (host->blockend || host->variant->singleirq)) {
mmci_stop_data(host);
+ /* Reset these flags */
+ host->blockend = false;
+ host->dataend = false;
+
+ /*
+ * Single IRQ variants do not transmit MCI_DATABLOCKEND
+ * and in DMA mode this signal need to be synchronized
+ * with MCI_DATEND
+ */
+ if (host->variant->singleirq && !data->error)
+ host->data_xfered += data->blksz * data->blocks;
+
if (!data->stop) {
mmci_request_end(host, data->mrq);
} else {
@@ -285,13 +404,15 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status)
{
+ struct variant_data *variant = host->variant;
void __iomem *base = host->base;
char *ptr = buffer;
do {
unsigned int count, maxcnt;
- maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
+ maxcnt = status & MCI_TXFIFOEMPTY ?
+ variant->fifosize : variant->fifohalfsize;
count = min(remain, maxcnt);
writesl(base + MMCIFIFO, ptr, count >> 2);
@@ -314,15 +435,19 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
{
struct mmci_host *host = dev_id;
+ struct sg_mapping_iter *sg_miter = &host->sg_miter;
+ struct variant_data *variant = host->variant;
void __iomem *base = host->base;
+ unsigned long flags;
u32 status;
status = readl(base + MMCISTATUS);
dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status);
+ local_irq_save(flags);
+
do {
- unsigned long flags;
unsigned int remain, len;
char *buffer;
@@ -336,11 +461,11 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)))
break;
- /*
- * Map the current scatter buffer.
- */
- buffer = mmci_kmap_atomic(host, &flags) + host->sg_off;
- remain = host->sg_ptr->length - host->sg_off;
+ if (!sg_miter_next(sg_miter))
+ break;
+
+ buffer = sg_miter->addr;
+ remain = sg_miter->length;
len = 0;
if (status & MCI_RXACTIVE)
@@ -348,37 +473,30 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
if (status & MCI_TXACTIVE)
len = mmci_pio_write(host, buffer, remain, status);
- /*
- * Unmap the buffer.
- */
- mmci_kunmap_atomic(host, buffer, &flags);
+ sg_miter->consumed = len;
- host->sg_off += len;
host->size -= len;
remain -= len;
if (remain)
break;
- /*
- * If we were reading, and we have completed this
- * page, ensure that the data cache is coherent.
- */
if (status & MCI_RXACTIVE)
- flush_dcache_page(sg_page(host->sg_ptr));
-
- if (!mmci_next_sg(host))
- break;
+ flush_dcache_page(sg_miter->page);
status = readl(base + MMCISTATUS);
} while (1);
+ sg_miter_stop(sg_miter);
+
+ local_irq_restore(flags);
+
/*
* If we're nearing the end of the read, switch to
* "any data available" mode.
*/
- if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE)
- writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
+ if (status & MCI_RXACTIVE && host->size < variant->fifosize)
+ mmci_set_mask1(host, MCI_RXDATAAVLBLMASK);
/*
* If we run out of data, disable the data IRQs; this
@@ -387,7 +505,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
* stops us racing with our data end IRQ.
*/
if (host->size == 0) {
- writel(0, base + MMCIMASK1);
+ mmci_set_mask1(host, 0);
writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0);
}
@@ -400,6 +518,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
static irqreturn_t mmci_irq(int irq, void *dev_id)
{
struct mmci_host *host = dev_id;
+ struct variant_data *variant = host->variant;
u32 status;
int ret = 0;
@@ -410,6 +529,14 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
struct mmc_data *data;
status = readl(host->base + MMCISTATUS);
+
+ if (variant->singleirq) {
+ if (status & readl(host->base + MMCIMASK1))
+ mmci_pio_irq(irq, dev_id);
+
+ status &= ~MCI_IRQ1MASK;
+ }
+
status &= readl(host->base + MMCIMASK0);
writel(status, host->base + MMCICLEAR);
@@ -464,29 +591,30 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct mmci_host *host = mmc_priv(mmc);
u32 pwr = 0;
unsigned long flags;
+ int ret;
switch (ios->power_mode) {
case MMC_POWER_OFF:
- if(host->vcc &&
- regulator_is_enabled(host->vcc))
- regulator_disable(host->vcc);
+ if (host->vcc)
+ ret = mmc_regulator_set_ocr(mmc, host->vcc, 0);
break;
case MMC_POWER_UP:
-#ifdef CONFIG_REGULATOR
- if (host->vcc)
- /* This implicitly enables the regulator */
- mmc_regulator_set_ocr(host->vcc, ios->vdd);
-#endif
- /*
- * The translate_vdd function is not used if you have
- * an external regulator, or your design is really weird.
- * Using it would mean sending in power control BOTH using
- * a regulator AND the 4 MMCIPWR bits. If we don't have
- * a regulator, we might have some other platform specific
- * power control behind this translate function.
- */
- if (!host->vcc && host->plat->translate_vdd)
- pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
+ if (host->vcc) {
+ ret = mmc_regulator_set_ocr(mmc, host->vcc, ios->vdd);
+ if (ret) {
+ dev_err(mmc_dev(mmc), "unable to set OCR\n");
+ /*
+ * The .set_ios() function in the mmc_host_ops
+ * struct return void, and failing to set the
+ * power should be rare so we print an error
+ * and return here.
+ */
+ return;
+ }
+ }
+ if (host->plat->vdd_handler)
+ pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd,
+ ios->power_mode);
/* The ST version does not have this, fall through to POWER_ON */
if (host->hw_designer != AMBA_VENDOR_ST) {
pwr |= MCI_PWR_UP;
@@ -528,18 +656,23 @@ static int mmci_get_ro(struct mmc_host *mmc)
if (host->gpio_wp == -ENOSYS)
return -ENOSYS;
- return gpio_get_value(host->gpio_wp);
+ return gpio_get_value_cansleep(host->gpio_wp);
}
static int mmci_get_cd(struct mmc_host *mmc)
{
struct mmci_host *host = mmc_priv(mmc);
+ struct mmci_platform_data *plat = host->plat;
unsigned int status;
- if (host->gpio_cd == -ENOSYS)
- status = host->plat->status(mmc_dev(host->mmc));
- else
- status = !gpio_get_value(host->gpio_cd);
+ if (host->gpio_cd == -ENOSYS) {
+ if (!plat->status)
+ return 1; /* Assume always present */
+
+ status = plat->status(mmc_dev(host->mmc));
+ } else
+ status = !!gpio_get_value_cansleep(host->gpio_cd)
+ ^ plat->cd_invert;
/*
* Use positive logic throughout - status is zero for no card,
@@ -548,6 +681,15 @@ static int mmci_get_cd(struct mmc_host *mmc)
return status;
}
+static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
+{
+ struct mmci_host *host = dev_id;
+
+ mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+
+ return IRQ_HANDLED;
+}
+
static const struct mmc_host_ops mmci_ops = {
.request = mmci_request,
.set_ios = mmci_set_ios,
@@ -555,23 +697,13 @@ static const struct mmc_host_ops mmci_ops = {
.get_cd = mmci_get_cd,
};
-static void mmci_check_status(unsigned long data)
-{
- struct mmci_host *host = (struct mmci_host *)data;
- unsigned int status = mmci_get_cd(host->mmc);
-
- if (status ^ host->oldstat)
- mmc_detect_change(host->mmc, 0);
-
- host->oldstat = status;
- mod_timer(&host->timer, jiffies + HZ);
-}
-
static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
{
struct mmci_platform_data *plat = dev->dev.platform_data;
+ struct variant_data *variant = id->data;
struct mmci_host *host;
struct mmc_host *mmc;
+ unsigned int mask;
int ret;
/* must have platform data */
@@ -595,6 +727,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
host->gpio_wp = -ENOSYS;
host->gpio_cd = -ENOSYS;
+ host->gpio_cd_irq = -1;
host->hw_designer = amba_manf(dev);
host->hw_revision = amba_rev(dev);
@@ -613,6 +746,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
goto clk_free;
host->plat = plat;
+ host->variant = variant;
host->mclk = clk_get_rate(host->clk);
/*
* According to the spec, mclk is max 100 MHz,
@@ -681,10 +815,11 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
mmc->max_phys_segs = NR_SG;
/*
- * Since we only have a 16-bit data length register, we must
- * ensure that we don't exceed 2^16-1 bytes in a single request.
+ * Since only a certain number of bits are valid in the data length
+ * register, we must ensure that we don't exceed 2^num-1 bytes in a
+ * single request.
*/
- mmc->max_req_size = 65535;
+ mmc->max_req_size = (1 << variant->datalength_bits) - 1;
/*
* Set the maximum segment size. Since we aren't doing DMA
@@ -716,6 +851,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
host->gpio_cd = plat->gpio_cd;
else if (ret != -ENOSYS)
goto err_gpio_cd;
+
+ ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd),
+ mmci_cd_irq, 0,
+ DRIVER_NAME " (cd)", host);
+ if (ret >= 0)
+ host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd);
}
if (gpio_is_valid(plat->gpio_wp)) {
ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)");
@@ -727,18 +868,33 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
goto err_gpio_wp;
}
+ if ((host->plat->status || host->gpio_cd != -ENOSYS)
+ && host->gpio_cd_irq < 0)
+ mmc->caps |= MMC_CAP_NEEDS_POLL;
+
ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
if (ret)
goto unmap;
- ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host);
- if (ret)
- goto irq0_free;
+ if (!variant->singleirq) {
+ ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED,
+ DRIVER_NAME " (pio)", host);
+ if (ret)
+ goto irq0_free;
+ }
+
+ /*
+ * MCI_DATABLOCKEND doesn't seem to immediately clear from the status,
+ * so we can't use it keep count when only one irq is used because the
+ * irq will hit for other reasons.
+ */
+ mask = MCI_IRQENABLE;
+ if (variant->singleirq)
+ mask &= ~MCI_DATABLOCKEND;
- writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+ writel(mask, host->base + MMCIMASK0);
amba_set_drvdata(dev, mmc);
- host->oldstat = mmci_get_cd(host->mmc);
mmc_add_host(mmc);
@@ -746,12 +902,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
(unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
- init_timer(&host->timer);
- host->timer.data = (unsigned long)host;
- host->timer.function = mmci_check_status;
- host->timer.expires = jiffies + HZ;
- add_timer(&host->timer);
-
return 0;
irq0_free:
@@ -760,6 +910,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
if (host->gpio_wp != -ENOSYS)
gpio_free(host->gpio_wp);
err_gpio_wp:
+ if (host->gpio_cd_irq >= 0)
+ free_irq(host->gpio_cd_irq, host);
if (host->gpio_cd != -ENOSYS)
gpio_free(host->gpio_cd);
err_gpio_cd:
@@ -784,8 +936,7 @@ static int __devexit mmci_remove(struct amba_device *dev)
if (mmc) {
struct mmci_host *host = mmc_priv(mmc);
-
- del_timer_sync(&host->timer);
+ struct variant_data *variant = host->variant;
mmc_remove_host(mmc);
@@ -796,10 +947,13 @@ static int __devexit mmci_remove(struct amba_device *dev)
writel(0, host->base + MMCIDATACTRL);
free_irq(dev->irq[0], host);
- free_irq(dev->irq[1], host);
+ if (!variant->singleirq)
+ free_irq(dev->irq[1], host);
if (host->gpio_wp != -ENOSYS)
gpio_free(host->gpio_wp);
+ if (host->gpio_cd_irq >= 0)
+ free_irq(host->gpio_cd_irq, host);
if (host->gpio_cd != -ENOSYS)
gpio_free(host->gpio_cd);
@@ -807,8 +961,8 @@ static int __devexit mmci_remove(struct amba_device *dev)
clk_disable(host->clk);
clk_put(host->clk);
- if (regulator_is_enabled(host->vcc))
- regulator_disable(host->vcc);
+ if (host->vcc)
+ mmc_regulator_set_ocr(mmc, host->vcc, 0);
regulator_put(host->vcc);
mmc_free_host(mmc);
@@ -860,19 +1014,28 @@ static struct amba_id mmci_ids[] = {
{
.id = 0x00041180,
.mask = 0x000fffff,
+ .data = &variant_arm,
},
{
.id = 0x00041181,
.mask = 0x000fffff,
+ .data = &variant_arm,
},
/* ST Micro variants */
{
.id = 0x00180180,
.mask = 0x00ffffff,
+ .data = &variant_u300,
},
{
.id = 0x00280180,
.mask = 0x00ffffff,
+ .data = &variant_u300,
+ },
+ {
+ .id = 0x00480180,
+ .mask = 0x00ffffff,
+ .data = &variant_ux500,
},
{ 0, 0 },
};
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index d77062e5e3a..acac0812060 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -28,8 +28,6 @@
#define MCI_4BIT_BUS (1 << 11)
/* 8bit wide buses supported in ST Micro versions */
#define MCI_ST_8BIT_BUS (1 << 12)
-/* HW flow control on the ST Micro version */
-#define MCI_ST_FCEN (1 << 13)
#define MMCIARGUMENT 0x008
#define MMCICOMMAND 0x00c
@@ -135,16 +133,15 @@
MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
-/*
- * The size of the FIFO in bytes.
- */
-#define MCI_FIFOSIZE (16*4)
-
-#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
+/* These interrupts are directed to IRQ1 when two IRQ lines are available */
+#define MCI_IRQ1MASK \
+ (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
+ MCI_TXFIFOHALFEMPTYMASK)
#define NR_SG 16
struct clk;
+struct variant_data;
struct mmci_host {
void __iomem *base;
@@ -155,6 +152,7 @@ struct mmci_host {
struct clk *clk;
int gpio_cd;
int gpio_wp;
+ int gpio_cd_irq;
unsigned int data_xfered;
@@ -164,6 +162,7 @@ struct mmci_host {
unsigned int cclk;
u32 pwr;
struct mmci_platform_data *plat;
+ struct variant_data *variant;
u8 hw_designer;
u8 hw_revision:4;
@@ -171,42 +170,12 @@ struct mmci_host {
struct timer_list timer;
unsigned int oldstat;
- unsigned int sg_len;
+ bool blockend;
+ bool dataend;
/* pio stuff */
- struct scatterlist *sg_ptr;
- unsigned int sg_off;
+ struct sg_mapping_iter sg_miter;
unsigned int size;
struct regulator *vcc;
};
-static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
-{
- /*
- * Ideally, we want the higher levels to pass us a scatter list.
- */
- host->sg_len = data->sg_len;
- host->sg_ptr = data->sg;
- host->sg_off = 0;
-}
-
-static inline int mmci_next_sg(struct mmci_host *host)
-{
- host->sg_ptr++;
- host->sg_off = 0;
- return --host->sg_len;
-}
-
-static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags)
-{
- struct scatterlist *sg = host->sg_ptr;
-
- local_irq_save(*flags);
- return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
-}
-
-static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags)
-{
- kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
- local_irq_restore(*flags);
-}
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index b032828c612..2e3eff48d43 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -248,9 +248,9 @@ static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
if (power_on)
- ret = mmc_regulator_set_ocr(host->vcc, vdd);
+ ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
else
- ret = mmc_regulator_set_ocr(host->vcc, 0);
+ ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
if (mmc_slot(host).after_set_reg)
mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
@@ -289,18 +289,23 @@ static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
* chips/cards need an interface voltage rail too.
*/
if (power_on) {
- ret = mmc_regulator_set_ocr(host->vcc, vdd);
+ ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
/* Enable interface voltage rail, if needed */
if (ret == 0 && host->vcc_aux) {
ret = regulator_enable(host->vcc_aux);
if (ret < 0)
- ret = mmc_regulator_set_ocr(host->vcc, 0);
+ ret = mmc_regulator_set_ocr(host->mmc,
+ host->vcc, 0);
}
} else {
+ /* Shut down the rail */
if (host->vcc_aux)
ret = regulator_disable(host->vcc_aux);
- if (ret == 0)
- ret = mmc_regulator_set_ocr(host->vcc, 0);
+ if (!ret) {
+ /* Then proceed to shut down the local regulator */
+ ret = mmc_regulator_set_ocr(host->mmc,
+ host->vcc, 0);
+ }
}
if (mmc_slot(host).after_set_reg)
@@ -341,9 +346,9 @@ static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
if (cardsleep) {
/* VCC can be turned off if card is asleep */
if (sleep)
- err = mmc_regulator_set_ocr(host->vcc, 0);
+ err = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
else
- err = mmc_regulator_set_ocr(host->vcc, vdd);
+ err = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
} else
err = regulator_set_mode(host->vcc, mode);
if (err)
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 0a4e43f3714..76093852613 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -99,14 +99,25 @@ static inline void pxamci_init_ocr(struct pxamci_host *host)
}
}
-static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
+static inline int pxamci_set_power(struct pxamci_host *host,
+ unsigned char power_mode,
+ unsigned int vdd)
{
int on;
-#ifdef CONFIG_REGULATOR
- if (host->vcc)
- mmc_regulator_set_ocr(host->vcc, vdd);
-#endif
+ if (host->vcc) {
+ int ret;
+
+ if (power_mode == MMC_POWER_UP) {
+ ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
+ if (ret)
+ return ret;
+ } else if (power_mode == MMC_POWER_OFF) {
+ ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
+ if (ret)
+ return ret;
+ }
+ }
if (!host->vcc && host->pdata &&
gpio_is_valid(host->pdata->gpio_power)) {
on = ((1 << vdd) & host->pdata->ocr_mask);
@@ -115,6 +126,8 @@ static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
}
if (!host->vcc && host->pdata && host->pdata->setpower)
host->pdata->setpower(mmc_dev(host->mmc), vdd);
+
+ return 0;
}
static void pxamci_stop_clock(struct pxamci_host *host)
@@ -490,9 +503,21 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
if (host->power_mode != ios->power_mode) {
+ int ret;
+
host->power_mode = ios->power_mode;
- pxamci_set_power(host, ios->vdd);
+ ret = pxamci_set_power(host, ios->power_mode, ios->vdd);
+ if (ret) {
+ dev_err(mmc_dev(mmc), "unable to set power\n");
+ /*
+ * The .set_ios() function in the mmc_host_ops
+ * struct return void, and failing to set the
+ * power should be rare so we print an error and
+ * return here.
+ */
+ return;
+ }
if (ios->power_mode == MMC_POWER_ON)
host->cmdat |= CMDAT_INIT;
@@ -503,8 +528,8 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
else
host->cmdat &= ~CMDAT_SD_4DAT;
- pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
- host->clkrt, host->cmdat);
+ dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n",
+ host->clkrt, host->cmdat);
}
static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 79bc9ca1458..f38144c2da1 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -297,3 +297,7 @@ obj-$(CONFIG_WIMAX) += wimax/
obj-$(CONFIG_CAIF) += caif/
obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon/
+
+ifdef CONFIG_PHONET
+obj-$(CONFIG_U8500_SHRM) += u8500_shrm.o
+endif
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index 0b28e010769..75bfc3a9d95 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -2,16 +2,32 @@
# CAIF physical drivers
#
-if CAIF
-
comment "CAIF transport drivers"
config CAIF_TTY
tristate "CAIF TTY transport driver"
+ depends on CAIF
default n
---help---
The CAIF TTY transport driver is a Line Discipline (ldisc)
identified as N_CAIF. When this ldisc is opened from user space
it will redirect the TTY's traffic into the CAIF stack.
-endif # CAIF
+config CAIF_SPI_SLAVE
+ tristate "CAIF SPI transport driver for slave interface"
+ depends on CAIF && HAS_DMA
+ default n
+ ---help---
+ The CAIF Link layer SPI Protocol driver for Slave SPI interface.
+ This driver implements a platform driver to accommodate for a
+ platform specific SPI device. A sample CAIF SPI Platform device is
+ provided in Documentation/networking/caif/spi_porting.txt
+
+config CAIF_SPI_SYNC
+ bool "Next command and length in start of frame"
+ depends on CAIF_SPI_SLAVE
+ default n
+ ---help---
+ Putting the next command and length in the start of the frame can
+ help to synchronize to the next transfer in case of over or under-runs.
+ This option also needs to be enabled on the modem.
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index 52b6d1f826f..3a11d619452 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -1,12 +1,10 @@
-ifeq ($(CONFIG_CAIF_DEBUG),1)
-CAIF_DBG_FLAGS := -DDEBUG
+ifeq ($(CONFIG_CAIF_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
endif
-KBUILD_EXTRA_SYMBOLS=net/caif/Module.symvers
-
-ccflags-y := $(CAIF_FLAGS) $(CAIF_DBG_FLAGS)
-clean-dirs:= .tmp_versions
-clean-files:= Module.symvers modules.order *.cmd *~ \
-
# Serial interface
obj-$(CONFIG_CAIF_TTY) += caif_serial.o
+
+# SPI slave physical interfaces module
+cfspi_slave-objs := caif_spi.o caif_spi_slave.o
+obj-$(CONFIG_CAIF_SPI_SLAVE) += cfspi_slave.o
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index 09257ca8f56..2f192fc3d6c 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -396,7 +396,6 @@ static void caifdev_setup(struct net_device *dev)
dev->type = ARPHRD_CAIF;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
dev->mtu = CAIF_MAX_MTU;
- dev->hard_header_len = CAIF_NEEDED_HEADROOM;
dev->tx_queue_len = 0;
dev->destructor = free_netdev;
skb_queue_head_init(&serdev->head);
@@ -410,8 +409,6 @@ static void caifdev_setup(struct net_device *dev)
static int caif_net_open(struct net_device *dev)
{
- struct ser_device *ser;
- ser = netdev_priv(dev);
netif_wake_queue(dev);
return 0;
}
diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c
new file mode 100644
index 00000000000..03049e86e8a
--- /dev/null
+++ b/drivers/net/caif/caif_spi.c
@@ -0,0 +1,847 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/if_arp.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/caif_spi.h>
+
+#ifndef CONFIG_CAIF_SPI_SYNC
+#define FLAVOR "Flavour: Vanilla.\n"
+#else
+#define FLAVOR "Flavour: Master CMD&LEN at start.\n"
+#endif /* CONFIG_CAIF_SPI_SYNC */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
+MODULE_DESCRIPTION("CAIF SPI driver");
+
+static int spi_loop;
+module_param(spi_loop, bool, S_IRUGO);
+MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
+
+/* SPI frame alignment. */
+module_param(spi_frm_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
+
+/* SPI padding options. */
+module_param(spi_up_head_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
+
+module_param(spi_up_tail_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_up_tail_align, "SPI uplink tail alignment.");
+
+module_param(spi_down_head_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_down_head_align, "SPI downlink head alignment.");
+
+module_param(spi_down_tail_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_down_tail_align, "SPI downlink tail alignment.");
+
+#ifdef CONFIG_ARM
+#define BYTE_HEX_FMT "%02X"
+#else
+#define BYTE_HEX_FMT "%02hhX"
+#endif
+
+#define SPI_MAX_PAYLOAD_SIZE 4096
+/*
+ * Threshold values for the SPI packet queue. Flowcontrol will be asserted
+ * when the number of packets exceeds HIGH_WATER_MARK. It will not be
+ * deasserted before the number of packets drops below LOW_WATER_MARK.
+ */
+#define LOW_WATER_MARK 100
+#define HIGH_WATER_MARK (LOW_WATER_MARK*5)
+
+#ifdef CONFIG_UML
+
+/*
+ * We sometimes use UML for debugging, but it cannot handle
+ * dma_alloc_coherent so we have to wrap it.
+ */
+static inline void *dma_alloc(dma_addr_t *daddr)
+{
+ return kmalloc(SPI_DMA_BUF_LEN, GFP_KERNEL);
+}
+
+static inline void dma_free(void *cpu_addr, dma_addr_t handle)
+{
+ kfree(cpu_addr);
+}
+
+#else
+
+static inline void *dma_alloc(dma_addr_t *daddr)
+{
+ return dma_alloc_coherent(NULL, SPI_DMA_BUF_LEN, daddr,
+ GFP_KERNEL);
+}
+
+static inline void dma_free(void *cpu_addr, dma_addr_t handle)
+{
+ dma_free_coherent(NULL, SPI_DMA_BUF_LEN, cpu_addr, handle);
+}
+#endif /* CONFIG_UML */
+
+#ifdef CONFIG_DEBUG_FS
+
+#define DEBUGFS_BUF_SIZE 4096
+
+static struct dentry *dbgfs_root;
+
+static inline void driver_debugfs_create(void)
+{
+ dbgfs_root = debugfs_create_dir(cfspi_spi_driver.driver.name, NULL);
+}
+
+static inline void driver_debugfs_remove(void)
+{
+ debugfs_remove(dbgfs_root);
+}
+
+static inline void dev_debugfs_rem(struct cfspi *cfspi)
+{
+ debugfs_remove(cfspi->dbgfs_frame);
+ debugfs_remove(cfspi->dbgfs_state);
+ debugfs_remove(cfspi->dbgfs_dir);
+}
+
+static int dbgfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t dbgfs_state(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *buf;
+ int len = 0;
+ ssize_t size;
+ struct cfspi *cfspi = (struct cfspi *)file->private_data;
+
+ buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return 0;
+
+ /* Print out debug information. */
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "CAIF SPI debug information:\n");
+
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), FLAVOR);
+
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "STATE: %d\n", cfspi->dbg_state);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Previous CMD: 0x%x\n", cfspi->pcmd);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Current CMD: 0x%x\n", cfspi->cmd);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Previous TX len: %d\n", cfspi->tx_ppck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Previous RX len: %d\n", cfspi->rx_ppck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Current TX len: %d\n", cfspi->tx_cpck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Current RX len: %d\n", cfspi->rx_cpck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Next TX len: %d\n", cfspi->tx_npck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Next RX len: %d\n", cfspi->rx_npck_len);
+
+ size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return size;
+}
+
+static ssize_t print_frame(char *buf, size_t size, char *frm,
+ size_t count, size_t cut)
+{
+ int len = 0;
+ int i;
+ for (i = 0; i < count; i++) {
+ len += snprintf((buf + len), (size - len),
+ "[0x" BYTE_HEX_FMT "]",
+ frm[i]);
+ if ((i == cut) && (count > (cut * 2))) {
+ /* Fast forward. */
+ i = count - cut;
+ len += snprintf((buf + len), (size - len),
+ "--- %u bytes skipped ---\n",
+ (int)(count - (cut * 2)));
+ }
+
+ if ((!(i % 10)) && i) {
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "\n");
+ }
+ }
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), "\n");
+ return len;
+}
+
+static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *buf;
+ int len = 0;
+ ssize_t size;
+ struct cfspi *cfspi;
+
+ cfspi = (struct cfspi *)file->private_data;
+ buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return 0;
+
+ /* Print out debug information. */
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Current frame:\n");
+
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Tx data (Len: %d):\n", cfspi->tx_cpck_len);
+
+ len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
+ cfspi->xfer.va_tx,
+ (cfspi->tx_cpck_len + SPI_CMD_SZ), 100);
+
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Rx data (Len: %d):\n", cfspi->rx_cpck_len);
+
+ len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
+ cfspi->xfer.va_rx,
+ (cfspi->rx_cpck_len + SPI_CMD_SZ), 100);
+
+ size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return size;
+}
+
+static const struct file_operations dbgfs_state_fops = {
+ .open = dbgfs_open,
+ .read = dbgfs_state,
+ .owner = THIS_MODULE
+};
+
+static const struct file_operations dbgfs_frame_fops = {
+ .open = dbgfs_open,
+ .read = dbgfs_frame,
+ .owner = THIS_MODULE
+};
+
+static inline void dev_debugfs_add(struct cfspi *cfspi)
+{
+ cfspi->dbgfs_dir = debugfs_create_dir(cfspi->pdev->name, dbgfs_root);
+ cfspi->dbgfs_state = debugfs_create_file("state", S_IRUGO,
+ cfspi->dbgfs_dir, cfspi,
+ &dbgfs_state_fops);
+ cfspi->dbgfs_frame = debugfs_create_file("frame", S_IRUGO,
+ cfspi->dbgfs_dir, cfspi,
+ &dbgfs_frame_fops);
+}
+
+inline void cfspi_dbg_state(struct cfspi *cfspi, int state)
+{
+ cfspi->dbg_state = state;
+};
+#else
+
+static inline void driver_debugfs_create(void)
+{
+}
+
+static inline void driver_debugfs_remove(void)
+{
+}
+
+static inline void dev_debugfs_add(struct cfspi *cfspi)
+{
+}
+
+static inline void dev_debugfs_rem(struct cfspi *cfspi)
+{
+}
+
+inline void cfspi_dbg_state(struct cfspi *cfspi, int state)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static LIST_HEAD(cfspi_list);
+static spinlock_t cfspi_list_lock;
+
+/* SPI uplink head alignment. */
+static ssize_t show_up_head_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_up_head_align);
+}
+
+static DRIVER_ATTR(up_head_align, S_IRUSR, show_up_head_align, NULL);
+
+/* SPI uplink tail alignment. */
+static ssize_t show_up_tail_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_up_tail_align);
+}
+
+static DRIVER_ATTR(up_tail_align, S_IRUSR, show_up_tail_align, NULL);
+
+/* SPI downlink head alignment. */
+static ssize_t show_down_head_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_down_head_align);
+}
+
+static DRIVER_ATTR(down_head_align, S_IRUSR, show_down_head_align, NULL);
+
+/* SPI downlink tail alignment. */
+static ssize_t show_down_tail_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_down_tail_align);
+}
+
+static DRIVER_ATTR(down_tail_align, S_IRUSR, show_down_tail_align, NULL);
+
+/* SPI frame alignment. */
+static ssize_t show_frame_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_frm_align);
+}
+
+static DRIVER_ATTR(frame_align, S_IRUSR, show_frame_align, NULL);
+
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
+{
+ u8 *dst = buf;
+ caif_assert(buf);
+
+ do {
+ struct sk_buff *skb;
+ struct caif_payload_info *info;
+ int spad = 0;
+ int epad;
+
+ skb = skb_dequeue(&cfspi->chead);
+ if (!skb)
+ break;
+
+ /*
+ * Calculate length of frame including SPI padding.
+ * The payload position is found in the control buffer.
+ */
+ info = (struct caif_payload_info *)&skb->cb;
+
+ /*
+ * Compute head offset i.e. number of bytes to add to
+ * get the start of the payload aligned.
+ */
+ if (spi_up_head_align) {
+ spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+ *dst = (u8)(spad - 1);
+ dst += spad;
+ }
+
+ /* Copy in CAIF frame. */
+ skb_copy_bits(skb, 0, dst, skb->len);
+ dst += skb->len;
+ cfspi->ndev->stats.tx_packets++;
+ cfspi->ndev->stats.tx_bytes += skb->len;
+
+ /*
+ * Compute tail offset i.e. number of bytes to add to
+ * get the complete CAIF frame aligned.
+ */
+ epad = (skb->len + spad) & spi_up_tail_align;
+ dst += epad;
+
+ dev_kfree_skb(skb);
+
+ } while ((dst - buf) < len);
+
+ return dst - buf;
+}
+
+int cfspi_xmitlen(struct cfspi *cfspi)
+{
+ struct sk_buff *skb = NULL;
+ int frm_len = 0;
+ int pkts = 0;
+
+ /*
+ * Decommit previously commited frames.
+ * skb_queue_splice_tail(&cfspi->chead,&cfspi->qhead)
+ */
+ while (skb_peek(&cfspi->chead)) {
+ skb = skb_dequeue_tail(&cfspi->chead);
+ skb_queue_head(&cfspi->qhead, skb);
+ }
+
+ do {
+ struct caif_payload_info *info = NULL;
+ int spad = 0;
+ int epad = 0;
+
+ skb = skb_dequeue(&cfspi->qhead);
+ if (!skb)
+ break;
+
+ /*
+ * Calculate length of frame including SPI padding.
+ * The payload position is found in the control buffer.
+ */
+ info = (struct caif_payload_info *)&skb->cb;
+
+ /*
+ * Compute head offset i.e. number of bytes to add to
+ * get the start of the payload aligned.
+ */
+ if (spi_up_head_align)
+ spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+
+ /*
+ * Compute tail offset i.e. number of bytes to add to
+ * get the complete CAIF frame aligned.
+ */
+ epad = (skb->len + spad) & spi_up_tail_align;
+
+ if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
+ skb_queue_tail(&cfspi->chead, skb);
+ pkts++;
+ frm_len += skb->len + spad + epad;
+ } else {
+ /* Put back packet. */
+ skb_queue_head(&cfspi->qhead, skb);
+ }
+ } while (pkts <= CAIF_MAX_SPI_PKTS);
+
+ /*
+ * Send flow on if previously sent flow off
+ * and now go below the low water mark
+ */
+ if (cfspi->flow_off_sent && cfspi->qhead.qlen < cfspi->qd_low_mark &&
+ cfspi->cfdev.flowctrl) {
+ cfspi->flow_off_sent = 0;
+ cfspi->cfdev.flowctrl(cfspi->ndev, 1);
+ }
+
+ return frm_len;
+}
+
+static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
+{
+ struct cfspi *cfspi = (struct cfspi *)ifc->priv;
+
+ if (!in_interrupt())
+ spin_lock(&cfspi->lock);
+ if (assert) {
+ set_bit(SPI_SS_ON, &cfspi->state);
+ set_bit(SPI_XFER, &cfspi->state);
+ } else {
+ set_bit(SPI_SS_OFF, &cfspi->state);
+ }
+ if (!in_interrupt())
+ spin_unlock(&cfspi->lock);
+
+ /* Wake up the xfer thread. */
+ wake_up_interruptible(&cfspi->wait);
+}
+
+static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
+{
+ struct cfspi *cfspi = (struct cfspi *)ifc->priv;
+
+ /* Transfer done, complete work queue */
+ complete(&cfspi->comp);
+}
+
+static int cfspi_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct cfspi *cfspi = NULL;
+ unsigned long flags;
+ if (!dev)
+ return -EINVAL;
+
+ cfspi = netdev_priv(dev);
+
+ skb_queue_tail(&cfspi->qhead, skb);
+
+ spin_lock_irqsave(&cfspi->lock, flags);
+ if (!test_and_set_bit(SPI_XFER, &cfspi->state)) {
+ /* Wake up xfer thread. */
+ wake_up_interruptible(&cfspi->wait);
+ }
+ spin_unlock_irqrestore(&cfspi->lock, flags);
+
+ /* Send flow off if number of bytes is above high water mark */
+ if (!cfspi->flow_off_sent &&
+ cfspi->qhead.qlen > cfspi->qd_high_mark &&
+ cfspi->cfdev.flowctrl) {
+ cfspi->flow_off_sent = 1;
+ cfspi->cfdev.flowctrl(cfspi->ndev, 0);
+ }
+
+ return 0;
+}
+
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
+{
+ u8 *src = buf;
+
+ caif_assert(buf != NULL);
+
+ do {
+ int res;
+ struct sk_buff *skb = NULL;
+ int spad = 0;
+ int epad = 0;
+ u8 *dst = NULL;
+ int pkt_len = 0;
+
+ /*
+ * Compute head offset i.e. number of bytes added to
+ * get the start of the payload aligned.
+ */
+ if (spi_down_head_align) {
+ spad = 1 + *src;
+ src += spad;
+ }
+
+ /* Read length of CAIF frame (little endian). */
+ pkt_len = *src;
+ pkt_len |= ((*(src+1)) << 8) & 0xFF00;
+ pkt_len += 2; /* Add FCS fields. */
+
+ /* Get a suitable caif packet and copy in data. */
+
+ skb = netdev_alloc_skb(cfspi->ndev, pkt_len + 1);
+ caif_assert(skb != NULL);
+
+ dst = skb_put(skb, pkt_len);
+ memcpy(dst, src, pkt_len);
+ src += pkt_len;
+
+ skb->protocol = htons(ETH_P_CAIF);
+ skb_reset_mac_header(skb);
+ skb->dev = cfspi->ndev;
+
+ /*
+ * Push received packet up the stack.
+ */
+ if (!spi_loop)
+ res = netif_rx_ni(skb);
+ else
+ res = cfspi_xmit(skb, cfspi->ndev);
+
+ if (!res) {
+ cfspi->ndev->stats.rx_packets++;
+ cfspi->ndev->stats.rx_bytes += pkt_len;
+ } else
+ cfspi->ndev->stats.rx_dropped++;
+
+ /*
+ * Compute tail offset i.e. number of bytes added to
+ * get the complete CAIF frame aligned.
+ */
+ epad = (pkt_len + spad) & spi_down_tail_align;
+ src += epad;
+ } while ((src - buf) < len);
+
+ return src - buf;
+}
+
+static int cfspi_open(struct net_device *dev)
+{
+ netif_wake_queue(dev);
+ return 0;
+}
+
+static int cfspi_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ return 0;
+}
+static const struct net_device_ops cfspi_ops = {
+ .ndo_open = cfspi_open,
+ .ndo_stop = cfspi_close,
+ .ndo_start_xmit = cfspi_xmit
+};
+
+static void cfspi_setup(struct net_device *dev)
+{
+ struct cfspi *cfspi = netdev_priv(dev);
+ dev->features = 0;
+ dev->netdev_ops = &cfspi_ops;
+ dev->type = ARPHRD_CAIF;
+ dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+ dev->tx_queue_len = 0;
+ dev->mtu = SPI_MAX_PAYLOAD_SIZE;
+ dev->destructor = free_netdev;
+ skb_queue_head_init(&cfspi->qhead);
+ skb_queue_head_init(&cfspi->chead);
+ cfspi->cfdev.link_select = CAIF_LINK_HIGH_BANDW;
+ cfspi->cfdev.use_frag = false;
+ cfspi->cfdev.use_stx = false;
+ cfspi->cfdev.use_fcs = false;
+ cfspi->ndev = dev;
+}
+
+int cfspi_spi_probe(struct platform_device *pdev)
+{
+ struct cfspi *cfspi = NULL;
+ struct net_device *ndev;
+ struct cfspi_dev *dev;
+ int res;
+ dev = (struct cfspi_dev *)pdev->dev.platform_data;
+
+ ndev = alloc_netdev(sizeof(struct cfspi),
+ "cfspi%d", cfspi_setup);
+ if (!dev)
+ return -ENODEV;
+
+ cfspi = netdev_priv(ndev);
+ netif_stop_queue(ndev);
+ cfspi->ndev = ndev;
+ cfspi->pdev = pdev;
+
+ /* Set flow info */
+ cfspi->flow_off_sent = 0;
+ cfspi->qd_low_mark = LOW_WATER_MARK;
+ cfspi->qd_high_mark = HIGH_WATER_MARK;
+
+ /* Assign the SPI device. */
+ cfspi->dev = dev;
+ /* Assign the device ifc to this SPI interface. */
+ dev->ifc = &cfspi->ifc;
+
+ /* Allocate DMA buffers. */
+ cfspi->xfer.va_tx = dma_alloc(&cfspi->xfer.pa_tx);
+ if (!cfspi->xfer.va_tx) {
+ printk(KERN_WARNING
+ "CFSPI: failed to allocate dma TX buffer.\n");
+ res = -ENODEV;
+ goto err_dma_alloc_tx;
+ }
+
+ cfspi->xfer.va_rx = dma_alloc(&cfspi->xfer.pa_rx);
+
+ if (!cfspi->xfer.va_rx) {
+ printk(KERN_WARNING
+ "CFSPI: failed to allocate dma TX buffer.\n");
+ res = -ENODEV;
+ goto err_dma_alloc_rx;
+ }
+
+ /* Initialize the work queue. */
+ INIT_WORK(&cfspi->work, cfspi_xfer);
+
+ /* Initialize spin locks. */
+ spin_lock_init(&cfspi->lock);
+
+ /* Initialize flow control state. */
+ cfspi->flow_stop = false;
+
+ /* Initialize wait queue. */
+ init_waitqueue_head(&cfspi->wait);
+
+ /* Create work thread. */
+ cfspi->wq = create_singlethread_workqueue(dev->name);
+ if (!cfspi->wq) {
+ printk(KERN_WARNING "CFSPI: failed to create work queue.\n");
+ res = -ENODEV;
+ goto err_create_wq;
+ }
+
+ /* Initialize work queue. */
+ init_completion(&cfspi->comp);
+
+ /* Create debugfs entries. */
+ dev_debugfs_add(cfspi);
+
+ /* Set up the ifc. */
+ cfspi->ifc.ss_cb = cfspi_ss_cb;
+ cfspi->ifc.xfer_done_cb = cfspi_xfer_done_cb;
+ cfspi->ifc.priv = cfspi;
+
+ /* Add CAIF SPI device to list. */
+ spin_lock(&cfspi_list_lock);
+ list_add_tail(&cfspi->list, &cfspi_list);
+ spin_unlock(&cfspi_list_lock);
+
+ /* Schedule the work queue. */
+ queue_work(cfspi->wq, &cfspi->work);
+
+ /* Register network device. */
+ res = register_netdev(ndev);
+ if (res) {
+ printk(KERN_ERR "CFSPI: Reg. error: %d.\n", res);
+ goto err_net_reg;
+ }
+ return res;
+
+ err_net_reg:
+ dev_debugfs_rem(cfspi);
+ set_bit(SPI_TERMINATE, &cfspi->state);
+ wake_up_interruptible(&cfspi->wait);
+ destroy_workqueue(cfspi->wq);
+ err_create_wq:
+ dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
+ err_dma_alloc_rx:
+ dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx);
+ err_dma_alloc_tx:
+ free_netdev(ndev);
+
+ return res;
+}
+
+int cfspi_spi_remove(struct platform_device *pdev)
+{
+ struct list_head *list_node;
+ struct list_head *n;
+ struct cfspi *cfspi = NULL;
+ struct cfspi_dev *dev;
+
+ dev = (struct cfspi_dev *)pdev->dev.platform_data;
+ spin_lock(&cfspi_list_lock);
+ list_for_each_safe(list_node, n, &cfspi_list) {
+ cfspi = list_entry(list_node, struct cfspi, list);
+ /* Find the corresponding device. */
+ if (cfspi->dev == dev) {
+ /* Remove from list. */
+ list_del(list_node);
+ /* Free DMA buffers. */
+ dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
+ dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx);
+ set_bit(SPI_TERMINATE, &cfspi->state);
+ wake_up_interruptible(&cfspi->wait);
+ destroy_workqueue(cfspi->wq);
+ /* Destroy debugfs directory and files. */
+ dev_debugfs_rem(cfspi);
+ unregister_netdev(cfspi->ndev);
+ spin_unlock(&cfspi_list_lock);
+ return 0;
+ }
+ }
+ spin_unlock(&cfspi_list_lock);
+ return -ENODEV;
+}
+
+static void __exit cfspi_exit_module(void)
+{
+ struct list_head *list_node;
+ struct list_head *n;
+ struct cfspi *cfspi = NULL;
+
+ list_for_each_safe(list_node, n, &cfspi_list) {
+ cfspi = list_entry(list_node, struct cfspi, list);
+ platform_device_unregister(cfspi->pdev);
+ }
+
+ /* Destroy sysfs files. */
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_head_align);
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_tail_align);
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_head_align);
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_tail_align);
+ driver_remove_file(&cfspi_spi_driver.driver, &driver_attr_frame_align);
+ /* Unregister platform driver. */
+ platform_driver_unregister(&cfspi_spi_driver);
+ /* Destroy debugfs root directory. */
+ driver_debugfs_remove();
+}
+
+static int __init cfspi_init_module(void)
+{
+ int result;
+
+ /* Initialize spin lock. */
+ spin_lock_init(&cfspi_list_lock);
+
+ /* Register platform driver. */
+ result = platform_driver_register(&cfspi_spi_driver);
+ if (result) {
+ printk(KERN_ERR "Could not register platform SPI driver.\n");
+ goto err_dev_register;
+ }
+
+ /* Create sysfs files. */
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_head_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 1.\n");
+ goto err_create_up_head_align;
+ }
+
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_tail_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 2.\n");
+ goto err_create_up_tail_align;
+ }
+
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_head_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 3.\n");
+ goto err_create_down_head_align;
+ }
+
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_tail_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 4.\n");
+ goto err_create_down_tail_align;
+ }
+
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_frame_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 5.\n");
+ goto err_create_frame_align;
+ }
+ driver_debugfs_create();
+ return result;
+
+ err_create_frame_align:
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_tail_align);
+ err_create_down_tail_align:
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_head_align);
+ err_create_down_head_align:
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_tail_align);
+ err_create_up_tail_align:
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_head_align);
+ err_create_up_head_align:
+ err_dev_register:
+ return result;
+}
+
+module_init(cfspi_init_module);
+module_exit(cfspi_exit_module);
diff --git a/drivers/net/caif/caif_spi_slave.c b/drivers/net/caif/caif_spi_slave.c
new file mode 100644
index 00000000000..2111dbfea6f
--- /dev/null
+++ b/drivers/net/caif/caif_spi_slave.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/semaphore.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <net/caif/caif_spi.h>
+
+#ifndef CONFIG_CAIF_SPI_SYNC
+#define SPI_DATA_POS 0
+static inline int forward_to_spi_cmd(struct cfspi *cfspi)
+{
+ return cfspi->rx_cpck_len;
+}
+#else
+#define SPI_DATA_POS SPI_CMD_SZ
+static inline int forward_to_spi_cmd(struct cfspi *cfspi)
+{
+ return 0;
+}
+#endif
+
+int spi_frm_align = 2;
+int spi_up_head_align = 1;
+int spi_up_tail_align;
+int spi_down_head_align = 3;
+int spi_down_tail_align = 1;
+
+#ifdef CONFIG_DEBUG_FS
+static inline void debugfs_store_prev(struct cfspi *cfspi)
+{
+ /* Store previous command for debugging reasons.*/
+ cfspi->pcmd = cfspi->cmd;
+ /* Store previous transfer. */
+ cfspi->tx_ppck_len = cfspi->tx_cpck_len;
+ cfspi->rx_ppck_len = cfspi->rx_cpck_len;
+}
+#else
+static inline void debugfs_store_prev(struct cfspi *cfspi)
+{
+}
+#endif
+
+void cfspi_xfer(struct work_struct *work)
+{
+ struct cfspi *cfspi;
+ u8 *ptr = NULL;
+ unsigned long flags;
+ int ret;
+ cfspi = container_of(work, struct cfspi, work);
+
+ /* Initialize state. */
+ cfspi->cmd = SPI_CMD_EOT;
+
+ for (;;) {
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_WAITING);
+
+ /* Wait for master talk or transmit event. */
+ wait_event_interruptible(cfspi->wait,
+ test_bit(SPI_XFER, &cfspi->state) ||
+ test_bit(SPI_TERMINATE, &cfspi->state));
+
+ if (test_bit(SPI_TERMINATE, &cfspi->state))
+ return;
+
+#if CFSPI_DBG_PREFILL
+ /* Prefill buffers for easier debugging. */
+ memset(cfspi->xfer.va_tx, 0xFF, SPI_DMA_BUF_LEN);
+ memset(cfspi->xfer.va_rx, 0xFF, SPI_DMA_BUF_LEN);
+#endif /* CFSPI_DBG_PREFILL */
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_AWAKE);
+
+ /* Check whether we have a committed frame. */
+ if (cfspi->tx_cpck_len) {
+ int len;
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_FETCH_PKT);
+
+ /* Copy commited SPI frames after the SPI indication. */
+ ptr = (u8 *) cfspi->xfer.va_tx;
+ ptr += SPI_IND_SZ;
+ len = cfspi_xmitfrm(cfspi, ptr, cfspi->tx_cpck_len);
+ WARN_ON(len != cfspi->tx_cpck_len);
+ }
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_GET_NEXT);
+
+ /* Get length of next frame to commit. */
+ cfspi->tx_npck_len = cfspi_xmitlen(cfspi);
+
+ WARN_ON(cfspi->tx_npck_len > SPI_DMA_BUF_LEN);
+
+ /*
+ * Add indication and length at the beginning of the frame,
+ * using little endian.
+ */
+ ptr = (u8 *) cfspi->xfer.va_tx;
+ *ptr++ = SPI_CMD_IND;
+ *ptr++ = (SPI_CMD_IND & 0xFF00) >> 8;
+ *ptr++ = cfspi->tx_npck_len & 0x00FF;
+ *ptr++ = (cfspi->tx_npck_len & 0xFF00) >> 8;
+
+ /* Calculate length of DMAs. */
+ cfspi->xfer.tx_dma_len = cfspi->tx_cpck_len + SPI_IND_SZ;
+ cfspi->xfer.rx_dma_len = cfspi->rx_cpck_len + SPI_CMD_SZ;
+
+ /* Add SPI TX frame alignment padding, if necessary. */
+ if (cfspi->tx_cpck_len &&
+ (cfspi->xfer.tx_dma_len % spi_frm_align)) {
+
+ cfspi->xfer.tx_dma_len += spi_frm_align -
+ (cfspi->xfer.tx_dma_len % spi_frm_align);
+ }
+
+ /* Add SPI RX frame alignment padding, if necessary. */
+ if (cfspi->rx_cpck_len &&
+ (cfspi->xfer.rx_dma_len % spi_frm_align)) {
+
+ cfspi->xfer.rx_dma_len += spi_frm_align -
+ (cfspi->xfer.rx_dma_len % spi_frm_align);
+ }
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_INIT_XFER);
+
+ /* Start transfer. */
+ ret = cfspi->dev->init_xfer(&cfspi->xfer, cfspi->dev);
+ WARN_ON(ret);
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_ACTIVE);
+
+ /*
+ * TODO: We might be able to make an assumption if this is the
+ * first loop. Make sure that minimum toggle time is respected.
+ */
+ udelay(MIN_TRANSITION_TIME_USEC);
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_ACTIVE);
+
+ /* Signal that we are ready to recieve data. */
+ cfspi->dev->sig_xfer(true, cfspi->dev);
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_XFER_DONE);
+
+ /* Wait for transfer completion. */
+ wait_for_completion(&cfspi->comp);
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_XFER_DONE);
+
+ if (cfspi->cmd == SPI_CMD_EOT) {
+ /*
+ * Clear the master talk bit. A xfer is always at
+ * least two bursts.
+ */
+ clear_bit(SPI_SS_ON, &cfspi->state);
+ }
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_INACTIVE);
+
+ /* Make sure that the minimum toggle time is respected. */
+ if (SPI_XFER_TIME_USEC(cfspi->xfer.tx_dma_len,
+ cfspi->dev->clk_mhz) <
+ MIN_TRANSITION_TIME_USEC) {
+
+ udelay(MIN_TRANSITION_TIME_USEC -
+ SPI_XFER_TIME_USEC
+ (cfspi->xfer.tx_dma_len, cfspi->dev->clk_mhz));
+ }
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_INACTIVE);
+
+ /* De-assert transfer signal. */
+ cfspi->dev->sig_xfer(false, cfspi->dev);
+
+ /* Check whether we received a CAIF packet. */
+ if (cfspi->rx_cpck_len) {
+ int len;
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_DELIVER_PKT);
+
+ /* Parse SPI frame. */
+ ptr = ((u8 *)(cfspi->xfer.va_rx + SPI_DATA_POS));
+
+ len = cfspi_rxfrm(cfspi, ptr, cfspi->rx_cpck_len);
+ WARN_ON(len != cfspi->rx_cpck_len);
+ }
+
+ /* Check the next SPI command and length. */
+ ptr = (u8 *) cfspi->xfer.va_rx;
+
+ ptr += forward_to_spi_cmd(cfspi);
+
+ cfspi->cmd = *ptr++;
+ cfspi->cmd |= ((*ptr++) << 8) & 0xFF00;
+ cfspi->rx_npck_len = *ptr++;
+ cfspi->rx_npck_len |= ((*ptr++) << 8) & 0xFF00;
+
+ WARN_ON(cfspi->rx_npck_len > SPI_DMA_BUF_LEN);
+ WARN_ON(cfspi->cmd > SPI_CMD_EOT);
+
+ debugfs_store_prev(cfspi);
+
+ /* Check whether the master issued an EOT command. */
+ if (cfspi->cmd == SPI_CMD_EOT) {
+ /* Reset state. */
+ cfspi->tx_cpck_len = 0;
+ cfspi->rx_cpck_len = 0;
+ } else {
+ /* Update state. */
+ cfspi->tx_cpck_len = cfspi->tx_npck_len;
+ cfspi->rx_cpck_len = cfspi->rx_npck_len;
+ }
+
+ /*
+ * Check whether we need to clear the xfer bit.
+ * Spin lock needed for packet insertion.
+ * Test and clear of different bits
+ * are not supported.
+ */
+ spin_lock_irqsave(&cfspi->lock, flags);
+ if (cfspi->cmd == SPI_CMD_EOT && !cfspi_xmitlen(cfspi)
+ && !test_bit(SPI_SS_ON, &cfspi->state))
+ clear_bit(SPI_XFER, &cfspi->state);
+
+ spin_unlock_irqrestore(&cfspi->lock, flags);
+ }
+}
+
+struct platform_driver cfspi_spi_driver = {
+ .probe = cfspi_spi_probe,
+ .remove = cfspi_spi_remove,
+ .driver = {
+ .name = "cfspi_sspi",
+ .owner = THIS_MODULE,
+ },
+};
diff --git a/drivers/net/u8500_shrm.c b/drivers/net/u8500_shrm.c
new file mode 100644
index 00000000000..70004ec7d6e
--- /dev/null
+++ b/drivers/net/u8500_shrm.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009
+ *
+ * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> for ST-Ericsson
+ * Author: Arun Murthy <arun.murthy@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/phonet.h>
+#include <linux/if_phonet.h>
+#include <linux/if_arp.h>
+#include <net/sock.h>
+#include <net/phonet/phonet.h>
+#include <net/phonet/pep.h>
+
+#include <mach/shrm_driver.h>
+#include <mach/shrm_private.h>
+#include <mach/shrm_config.h>
+#include <mach/shrm_net.h>
+#include <mach/shrm.h>
+
+static u8 wr_isi_msg[10*1024];
+
+/**
+ * shrm_net_receive() - receive data and copy to user space buffer
+ * @dev: pointer to the network device structure
+ * @data: pointer to the receive buffer
+ *
+ * Copy data from ISI queue to the user space buffer.
+ */
+int shrm_net_receive(struct net_device *dev, u8 *data)
+{
+ struct sk_buff *skb;
+ struct isadev_context *isadev;
+ struct message_queue *q;
+ u32 msgsize;
+ u32 size = 0;
+ struct shrm_net_iface_priv *net_iface_priv =
+ (struct shrm_net_iface_priv *)netdev_priv(dev);
+ struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+ if (data == NULL)
+ goto out;
+
+ isadev = &shrm->isa_context->isadev[ISI_MESSAGING];
+ q = &isadev->dl_queue;
+
+ spin_lock_bh(&q->update_lock);
+ if (list_empty(&q->msg_list)) {
+ spin_unlock_bh(&q->update_lock);
+ dev_dbg(shrm->dev, "Empty Shrm queue\n");
+ return 0;
+ }
+ spin_unlock_bh(&q->update_lock);
+
+ msgsize = get_size_of_new_msg(q);
+ if (msgsize <= 0)
+ return msgsize;
+
+ if ((q->readptr+msgsize) >= q->size) {
+ size = (q->size-q->readptr);
+ /*Copy First Part of msg*/
+ memcpy(data,
+ (u8 *)(q->fifo_base + q->readptr), size);
+ /*Copy Second Part of msg at the top of fifo*/
+ memcpy(data+size,
+ (u8 *)(q->fifo_base), (msgsize - size));
+ } else {
+ memcpy(data,
+ (u8 *)(q->fifo_base+q->readptr), msgsize);
+ }
+
+ spin_lock_bh(&q->update_lock);
+ remove_msg_from_queue(q);
+ spin_unlock_bh(&q->update_lock);
+
+ dev_dbg(shrm->dev, "Data len at shrm_net_receive: %d\n", msgsize);
+
+ /*
+ * The packet has been retrieved from the transmission
+ * medium. Build an skb around it, so upper layers can handle it
+ */
+
+ skb = dev_alloc_skb(msgsize);
+ if (!skb) {
+ if (printk_ratelimit())
+ dev_notice(shrm->dev,
+ "isa rx: low on mem - packet dropped\n");
+ dev->stats.rx_dropped++;
+ goto out;
+ }
+ skb_copy_to_linear_data(skb, data, msgsize);
+ skb_put(skb, msgsize);
+ skb_reset_mac_header(skb);
+ __skb_pull(skb, dev->hard_header_len);
+ /*Write metadata, and then pass to the receive level*/
+ skb->dev = dev;/*kmalloc(sizeof(struct net_device), GFP_ATOMIC);*/
+ skb->protocol = htons(ETH_P_PHONET);
+ skb->priority = 0;
+ skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
+ if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += msgsize;
+ } else
+ dev->stats.rx_dropped++;
+
+ return msgsize;
+out:
+ return -ENOMEM;
+}
+
+static int netdev_isa_open(struct net_device *dev)
+{
+ struct shrm_net_iface_priv *net_iface_priv =
+ (struct shrm_net_iface_priv *)netdev_priv(dev);
+ struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+ shrm->netdev_flag_up = 1;
+ if (!netif_carrier_ok(dev))
+ netif_carrier_on(dev);
+ netif_wake_queue(dev);
+ return 0;
+}
+
+static int netdev_isa_close(struct net_device *dev)
+{
+ struct shrm_net_iface_priv *net_iface_priv =
+ (struct shrm_net_iface_priv *)netdev_priv(dev);
+ struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+ shrm->netdev_flag_up = 0;
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+ return 0;
+}
+
+static int netdev_isa_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct if_phonet_req *req = (struct if_phonet_req *)ifr;
+
+ switch (cmd) {
+ case SIOCPNGAUTOCONF:
+ req->ifr_phonet_autoconf.device = PN_DEV_HOST;
+ return 0;
+ }
+ return -ENOIOCTLCMD;
+}
+
+static struct net_device_stats *netdev_isa_stats(struct net_device *dev)
+{
+ return &dev->stats;
+}
+
+/**
+ * netdev_isa_write() - write through the net interface
+ * @skb: pointer to the socket buffer
+ * @dev: pointer to the network device structure
+ *
+ * Copies data(ISI message) from the user buffer to the kernel buffer and
+ * schedule transfer thread to transmit the message to the modem via FIFO.
+ */
+static netdev_tx_t netdev_isa_write(struct sk_buff *skb, struct net_device *dev)
+{
+ int err;
+ int retval = 0;
+ struct shrm_net_iface_priv *net_iface_priv =
+ (struct shrm_net_iface_priv *)netdev_priv(dev);
+ struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+ /*
+ * FIXME:
+ * U8500 modem requires that Pipe created/enabled Indication should
+ * be sent from the port corresponding to GPRS socket.
+ * Also, the U8500 modem does not implement Pipe controller
+ * which takes care of port manipulations for GPRS traffic.
+ *
+ * Now, APE has GPRS socket and the socket for sending
+ * Indication msgs bound to different ports.
+ * Phonet stack does not allow an indication msg to be sent
+ * from GPRS socket, since Phonet stack assumes the presence
+ * of Pipe controller in modem.
+ *
+ * So, due to lack of Pipe controller implementation in the
+ * U8500 modem, carry out the port manipulation related to
+ * GPRS traffic here.
+ * Ideally, it should be done either by Pipe controller in
+ * modem OR some implementation of Pipe controller on APE side
+ */
+ if (skb->data[RESOURCE_ID_INDEX] == PN_PIPE) {
+ if ((skb->data[MSG_ID_INDEX] == PNS_PIPE_CREATED_IND) ||
+ (skb->data[MSG_ID_INDEX] == PNS_PIPE_ENABLED_IND) ||
+ (skb->data[MSG_ID_INDEX] == PNS_PIPE_DISABLED_IND))
+ skb->data[SRC_OBJ_INDEX] = skb->data[PIPE_HDL_INDEX];
+ }
+
+ if ((void *)wr_isi_msg !=
+ memcpy((void *)wr_isi_msg, skb->data, skb->len)) {
+ dev_err(shrm->dev, "memcpy failed\n");
+ dev_kfree_skb(skb);
+ return -EFAULT;
+ }
+
+ spin_lock_bh(&shrm->isa_context->common_tx);
+ err = shm_write_msg(shrm, ISI_MESSAGING, (void *)wr_isi_msg,
+ skb->len);
+ if (!err) {
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+ retval = NETDEV_TX_OK;
+ } else {
+ dev->stats.tx_dropped++;
+ retval = NETDEV_TX_BUSY;
+ }
+ dev_kfree_skb(skb);
+ spin_unlock_bh(&shrm->isa_context->common_tx);
+
+ return retval;
+}
+
+static const struct net_device_ops shrm_netdev_ops = {
+ .ndo_open = netdev_isa_open,
+ .ndo_stop = netdev_isa_close,
+ .ndo_do_ioctl = netdev_isa_ioctl,
+ .ndo_start_xmit = netdev_isa_write,
+ .ndo_get_stats = netdev_isa_stats,
+};
+
+static void shm_net_init(struct net_device *dev)
+{
+ struct shrm_net_iface_priv *net_iface_priv;
+
+ dev->netdev_ops = &shrm_netdev_ops;
+ dev->header_ops = &phonet_header_ops;
+ dev->type = ARPHRD_PHONET;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ dev->mtu = PHONET_MAX_MTU;
+ dev->hard_header_len = SHRM_HLEN;
+ dev->addr_len = PHONET_ALEN;
+ dev->tx_queue_len = PN_TX_QUEUE_LEN;
+ dev->destructor = free_netdev;
+ dev->dev_addr[0] = PN_LINK_ADDR;
+ net_iface_priv = netdev_priv(dev);
+ memset(net_iface_priv, 0 , sizeof(struct shrm_net_iface_priv));
+}
+
+int shrm_register_netdev(struct shrm_dev *shrm)
+{
+ struct net_device *nw_device;
+ struct shrm_net_iface_priv *net_iface_priv;
+ char *devname = "shrm%d";
+ int err;
+
+ /* allocate the net device */
+ nw_device = shrm->ndev = alloc_netdev(
+ sizeof(struct shrm_net_iface_priv),
+ devname, shm_net_init);
+ if (nw_device == NULL) {
+ dev_err(shrm->dev, "Failed to allocate SHRM Netdev\n");
+ return -ENOMEM;
+ }
+ err = register_netdev(shrm->ndev);
+ if (err) {
+ dev_err(shrm->dev, "Err %i in reg shrm-netdev\n", err);
+ free_netdev(shrm->ndev);
+ return -ENODEV;
+ }
+ dev_info(shrm->dev, "Registered shrm netdev\n");
+
+ net_iface_priv = (struct shrm_net_iface_priv *)netdev_priv(nw_device);
+ net_iface_priv->shrm_device = shrm;
+ net_iface_priv->iface_num = 0;
+
+ return err;
+}
+
+int shrm_stop_netdev(struct net_device *dev)
+{
+ struct shrm_net_iface_priv *net_iface_priv =
+ (struct shrm_net_iface_priv *)netdev_priv(dev);
+ struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+ shrm->netdev_flag_up = 0;
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+ return 0;
+}
+
+int shrm_start_netdev(struct net_device *dev)
+{
+ struct shrm_net_iface_priv *net_iface_priv =
+ (struct shrm_net_iface_priv *)netdev_priv(dev);
+ struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+ if (!netif_carrier_ok(dev))
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
+ shrm->netdev_flag_up = 1;
+ return 0;
+}
+
+int shrm_suspend_netdev(struct net_device *dev)
+{
+ if (netif_running(dev)) {
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+ }
+ netif_device_detach(dev);
+
+ return 0;
+}
+
+int shrm_resume_netdev(struct net_device *dev)
+{
+ netif_device_attach(dev);
+ if (netif_running(dev)) {
+ netif_carrier_on(dev);
+ netif_wake_queue(dev);
+ }
+
+ return 0;
+}
+
+void shrm_unregister_netdev(struct shrm_dev *shrm)
+{
+ unregister_netdev(shrm->ndev);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index c7f56b4aeb8..2a7af4e787b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -3341,7 +3341,7 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
CMD_ASYNC, false);
}
- break;
+ break;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return 0;
else
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 8e9ba177d81..7968f886e49 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -142,4 +142,10 @@ config CHARGER_PCF50633
help
Say Y to include support for NXP PCF50633 Main Battery Charger.
+config AB8500_BM
+ bool "AB8500 Battery Management Driver"
+ depends on AB8500_CORE && AB8500_GPADC && ARCH_U8500
+ help
+ say Y to include support for AB8500 battery management.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 00050809a6c..f042b73af04 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
+obj-$(CONFIG_AB8500_BM) += ab8500_bm.o
diff --git a/drivers/power/ab8500_bm.c b/drivers/power/ab8500_bm.c
new file mode 100644
index 00000000000..8c8837c2037
--- /dev/null
+++ b/drivers/power/ab8500_bm.c
@@ -0,0 +1,4148 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Main and Back-up battery management driver.
+ *
+ * Note: Backup battery management is required in case of Li-Ion battery and not
+ * for capacitive battery. HREF boards have capacitive battery and hence backup
+ * battery management is not used and the supported code is available in this
+ * driver.
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Arun R Murthy <arun.murthy@stericsson.com>
+ * Author: Karl Komierowski <karl.komierowski@stericsson.com>
+ * Author: Johan Palsson <johan.palsson@stericsson.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500.h>
+/*
+ * TODO: The inclusion of this file should be removed once USB has
+ * moved the USB State enum to a machine independant header file
+ */
+#include <mach/stm_musb.h>
+#include <linux/mfd/ab8500/ab8500-bm.h>
+#include <linux/mfd/ab8500/ab8500-gpadc.h>
+
+/*
+ * Charger / status register offfsets
+ * Bank : 0x0B
+ */
+#define AB8500_CH_STATUS1_REG 0x00
+#define AB8500_CH_STATUS2_REG 0x01
+#define AB8500_CH_USBCH_STAT1_REG 0x02
+#define AB8500_CH_USBCH_STAT2_REG 0x03
+#define AB8500_CH_FSM_STAT_REG 0x04
+#define AB8500_CH_STAT_REG 0x05
+
+/*
+ * Charger / control register offfsets
+ * Bank : 0x0B
+ */
+#define AB8500_CH_VOLT_LVL_REG 0x40
+#define AB8500_CH_VOLT_LVL_MAX_REG 0x41 /*Only in Cut2.0*/
+#define AB8500_CH_OPT_CRNTLVL_REG 0x42
+#define AB8500_CH_OPT_CRNTLVL_MAX_REG 0x43 /*Only in Cut2.0*/
+#define AB8500_CH_WD_TIMER_REG 0x50
+#define AB8500_CHARG_WD_CTRL 0x51
+#define AB8500_LED_INDICATOR_PWM_CTRL 0x53
+#define AB8500_LED_INDICATOR_PWM_DUTY 0x54
+#define AB8500_BATT_OVV 0x55
+
+/*
+ * Charger / main control register offsets
+ * Bank : 0x0B
+ */
+#define AB8500_MCH_CTRL1 0x80
+#define AB8500_MCH_CTRL2 0x81
+#define AB8500_MCH_IPT_CURLVL_REG 0x82
+#define AB8500_CH_WD_REG 0x83
+
+/*
+ * OTP register offsets
+ * Bank : 0x15
+ */
+#define AB8500_OTP_CONF_15 0x0E
+
+/* Watchdog kick interval */
+#define CHG_WD_INTERVAL (30*HZ)
+
+/* End-of-charge criteria counter */
+#define EOC_COND_CNT 20
+
+/*
+ * Charger / USB control register offsets
+ * Bank : 0x0B
+ */
+#define AB8500_USBCH_CTRL1_REG 0xC0
+#define AB8500_USBCH_CTRL2_REG 0xC1
+#define AB8500_USBCH_IPT_CRNTLVL_REG 0xC2
+
+/*
+ * Gas Gauge register offsets
+ * Bank : 0x0C
+ */
+#define AB8500_GASG_CC_CTRL_REG 0x00
+#define AB8500_GASG_CC_ACCU1_REG 0x01
+#define AB8500_GASG_CC_ACCU2_REG 0x02
+#define AB8500_GASG_CC_ACCU3_REG 0x03
+#define AB8500_GASG_CC_ACCU4_REG 0x04
+#define AB8500_GASG_CC_SMPL_CNTRL_REG 0x05
+#define AB8500_GASG_CC_SMPL_CNTRH_REG 0x06
+#define AB8500_GASG_CC_SMPL_CNVL_REG 0x07
+#define AB8500_GASG_CC_SMPL_CNVH_REG 0x08
+#define AB8500_GASG_CC_CNTR_AVGOFF_REG 0x09
+#define AB8500_GASG_CC_OFFSET_REG 0x0A
+#define AB8500_GASG_CC_NCOV_ACCU 0x10
+#define AB8500_GASG_CC_NCOV_ACCU_CTRL 0x11
+#define AB8500_GASG_CC_NCOV_ACCU_LOW 0x12
+#define AB8500_GASG_CC_NCOV_ACCU_MED 0x13
+#define AB8500_GASG_CC_NCOV_ACCU_HIGH 0x14
+
+/*
+ * RTC register offsets
+ * Bank: 0x0F
+ */
+#define AB8500_RTC_BACKUP_CHG_REG 0x0C
+#define AB8500_RTC_CC_CONF_REG 0x01
+#define AB8500_RTC_CTRL_REG 0x0B
+
+/* Register bits in RTC CTRL*/
+#define RTC_BUP_CH_ENA 0x10
+
+/* UsbLineStatus register bit masks */
+#define AB8500_USB_LINK_STATUS 0x78
+#define AB8500_STD_HOST_SUSP 0x18
+
+/*
+ * Interrupt register offsets
+ * Bank : 0x0E
+ */
+#define AB8500_IT_SOURCE2_REG 0x01
+#define AB8500_IT_SOURCE21_REG 0x14
+
+/*
+ * USB/ULPI register offsets
+ * Bank : 0x5
+ */
+#define AB8500_USB_LINE_STAT_REG 0x80
+
+/*
+ * System control 2 register offsets.
+ * bank = 0x02
+ */
+#define AB8500_MAIN_WDOG_CTRL_REG 0x01
+#define AB8500_LOW_BAT_REG 0x03
+
+/* Charger constants */
+#define NO_PW_CONN 0
+#define AC_PW_CONN 1
+#define USB_PW_CONN 2
+#define BAT_GAIN 8
+#define BAT_PRESENT 1
+#define BAT_NOT_PRESENT 0
+#define NO_BAT_CONN 1350
+
+#define LOW_BAT_3P1V 0x20
+#define LOW_BAT_2P3V 0x00
+#define LOW_BAT_ENABLE 0x01
+
+/* constants */
+#define AB8500_BM_CHARGING 0x01
+#define AB8500_BM_NOT_CHARGING 0x00
+#define AB8500_BM_AC_PRESENT 0x01
+#define AB8500_BM_AC_NOT_PRESENT 0x00
+#define AB8500_BM_USB_PRESENT 0x01
+#define AB8500_BM_USB_NOT_PRESENT 0x00
+#define STANDARD_HOST 0x04
+
+/* Battery OVV */
+#define AB8500_BM_BATTOVV_4P75 4750000
+#define AB8500_BM_BATTOVV_3P7 3700000
+
+/*
+ * USB completion time
+ * Waiting one second for completion from USB driver
+ * has proven to be sufficient
+ */
+#define USB_COMPL_TIME HZ
+
+/* GPADC constants from AB8500 spec, UM0836 */
+#define ADC_RESOLUTION 1023
+#define ADC_CH_MAIN_MIN 0
+#define ADC_CH_MAIN_MAX 20030
+#define ADC_CH_VBUS_MIN 0
+#define ADC_CH_VBUS_MAX 20030
+#define ADC_CH_VBAT_MIN 2300
+#define ADC_CH_VBAT_MAX 4800
+#define ADC_CH_BKBAT_MIN 0
+#define ADC_CH_BKBAT_MAX 3200
+
+/* Battery constants */
+#define BATT_OVV_TH 0x01
+#define MAIN_CH_ON 0x02
+#define USB_CH_ON 0x04
+#define VBUS_DET_DBNC100 0x02
+#define VBUS_DET_DBNC1 0x01
+#define BATT_OVV_ENA 0x02
+#define BATT_OVV_TH_3P7 0x00
+#define BATT_OVV_TH_4P75 0x01
+#define USB_CH_ENA 0x01
+#define USB_CH_DIS 0x00
+#define MAIN_WDOG_ENA 0x01
+#define MAIN_WDOG_KICK 0x02
+#define MAIN_WDOG_DIS 0x00
+#define CHARG_WD_KICK 0x01
+#define MAIN_CH_ENA 0x01
+#define MAIN_CH_DIS 0x00
+#define MAIN_CH_PLUG_DET 0x08
+#define USB_CHG_DET_DONE 0x40
+#define LED_INDICATOR_PWM_ENA 0x01
+#define LED_INDICATOR_PWM_DIS 0x00
+#define LED_IND_CUR_5MA 0x04
+#define CHARGING_STOP_BY_BTEMP 0x08
+#define LED_INDICATOR_PWM_DUTY_252_256 0xBF
+#define MAIN_CH_CV_ON 0x04
+#define USB_CH_CV_ON 0x08
+#define OTP_ENABLE_WD 0x01
+#define OTP_DISABLE_WD 0xFE
+#define RESET_ACCU 0x02
+#define READ_REQ 0x01
+#define CC_DEEP_SLEEP_ENA 0x02
+#define CC_PWR_UP_ENA 0x01
+#define CC_SAMPLES_40 0x28
+#define RD_NCONV_ACCU_REQ 0x01
+#define MAIN_CH_TH_PROT 0x02
+#define USB_CH_TH_PROT 0x02
+#define VBUS_OVV_TH 0x01
+#define MAIN_CH_NOK 0x01
+#define VBUS_DET 0x80
+
+#define to_ab8500_bm_usb_device_info(x) container_of((x), \
+ struct ab8500_bm, usb);
+#define to_ab8500_bm_ac_device_info(x) container_of((x), \
+ struct ab8500_bm, ac);
+#define to_ab8500_bm_bk_battery_device_info(x) container_of((x), \
+ struct ab8500_bm, bk_bat);
+#define to_ab8500_bm(x) container_of((x), \
+ struct ab8500_bm, bat);
+
+static DEFINE_MUTEX(ab8500_cc_lock);
+
+struct ab8500_suspension_status {
+ bool suspended_change;
+ bool ac_suspended;
+ bool usb_suspended;
+};
+
+enum ab8500_charger_states {
+ AB8500_BM_CHARGER_OFF_INIT,
+ AB8500_BM_CHARGER_OFF,
+ AB8500_BM_CHARGER_HW_TEMP_PROTECT_INIT,
+ AB8500_BM_CHARGER_HW_TEMP_PROTECT,
+ AB8500_BM_CHARGER_NORMAL_INIT,
+ AB8500_BM_CHARGER_NORMAL,
+ AB8500_BM_CHARGER_MAINTENANCE_A_INIT,
+ AB8500_BM_CHARGER_MAINTENANCE_A,
+ AB8500_BM_CHARGER_MAINTENANCE_B_INIT,
+ AB8500_BM_CHARGER_MAINTENANCE_B,
+ AB8500_BM_CHARGER_SAFE,
+ AB8500_BM_CHARGER_TEMP_UNDEROVER_INIT,
+ AB8500_BM_CHARGER_TEMP_UNDEROVER,
+ AB8500_BM_CHARGER_TEMP_LOWHIGH_INIT,
+ AB8500_BM_CHARGER_TEMP_LOWHIGH,
+ AB8500_BM_CHARGER_HANDHELD_INIT,
+ AB8500_BM_CHARGER_HANDHELD,
+ AB8500_BM_CHARGER_SUSPENDED_INIT,
+ AB8500_BM_CHARGER_SUSPENDED,
+ AB8500_BM_CHARGER_OVV_PROTECT_INIT,
+ AB8500_BM_CHARGER_OVV_PROTECT,
+ AB8500_BM_CHARGER_SAFETY_TIMER_EXPIRED_INIT,
+ AB8500_BM_CHARGER_SAFETY_TIMER_EXPIRED,
+};
+
+enum ab8500_charger_CCCV_mode {
+ AB8500_CHARGER_CC,
+ AB8500_CHARGER_CV,
+};
+
+enum ab8500_charger_type {
+ AB8500_CHARGER_OFF,
+ AB8500_CHARGER_DCIO,
+ AB8500_CHARGER_USB,
+} ;
+
+struct ab8500_event_flags {
+ bool mainextchnotok;
+ bool batt_ovv;
+ bool batt_rem;
+ bool btemp_high;
+ bool btemp_medhigh;
+ bool btemp_medlow;
+ bool btemp_low;
+ bool main_thermal_prot;
+ bool usb_thermal_prot;
+ bool vbus_ovv;
+ bool usbchargernotok;
+ bool safety_timer_expired;
+ bool maintenance_timer_expired;
+};
+
+struct ab8500_charger_state_info {
+ int connected_charger_status;
+ int previous_connected_charger_status;
+ enum ab8500_charger_type type;
+ enum ab8500_charger_states state;
+ enum ab8500_charger_CCCV_mode charging_mode;
+};
+
+/**
+ * struct ab8500_bm - ab8500 EM device information
+ * @dev: Pointer to the structure device
+ * @cid Chip ID of the ABB ASIC
+ * @voltage_uV: Battery voltage in uV
+ * @temp_C: Battery temperature in Celcius
+ * @inst_current: Battery instantenous current in mA
+ * @avg_current: Battery average current in mA
+ * @old_avg_current Previous saved average current in mA. Used for
+ * filtering out erroneous samples
+ * @capacity: Battery capacity in percentage
+ * @samples: Num of samples for average current before accumulation
+ * data is stored and can be read.
+ * @prev_capacity: Saved battery capacity in percent since last
+ * time the capacity changed
+ * @charge_status: Charger status(charging, discharging)
+ * @bk_battery_charge_status: Backup battery charger status
+ * @usb_in_cur_lvl: USB charger input current level
+ * @usb_current current that can be drawn, obtained
+ * from usb stack in mA.
+ * @eoc_cond_counter Number of consecutive samples the
+ * end-of-charge criteria must be fulfilled
+ * to consider the battery to be full
+ * @maintenance_chg: flag for enabling/disabling
+ * maintenance charging
+ * @usb_changed flag to indicate that usb stack has
+ * some updates on the usb state
+ * @usb_plug_unplug flag to indicate the event as usb
+ * plug or unplug
+ * @usb_state USB state obtained from the usb stack
+ * @state_info Structure that holds charger state and status
+ * @suspension_status Structure that holds the sysfs suspension
+ * information
+ * @parent: Pointer to the struct ab8500
+ * @pdata: Pointer to the struct
+ * ab8500_bm_platfrom_data
+ * @bat: Structure that holds the battery properties
+ * @bk_bat: Structure that holds the backup battery properties
+ * @ac: Structure that holds the ac/mains properties
+ * @usb: Structure that holds the usb properties
+ * @event_flags Structure that holds information about events triggered
+ * @ab8500_bm_monitor_work: Work to monitor the main battery
+ * @ab8500_bm_watchdog_work: Work to re-kick the watchdog
+ * @ab8500_bm_ac_plug_monitor_work: Work to detect ac charger plugged
+ * @ab8500_bm_ac_unplug_monitor_work: Work to detect ac charger unplugged
+ * @ab8500_bm_usb_en_monitor_work: Work to enable usb charging
+ * @ab8500_bm_usb_dis_monitor_work: Work to disable usb charging
+ * @ab8500_bm_avg_cur_monitor_work: Work to monitor the average current
+ * @ab8500_bm_usb_state_changed_monitor_work
+ * Work to enable/disable usb charging
+ * based on the info from usb stack
+ * @ab8500_bm_instant_monitor_work Work to run the charging algorithm
+ * @ab8500_bm_detect_usb_type_monitor_work
+ * Work to detect the type of the
+ * connected USB charger
+ * @safety_timer Safety timer for charging
+ * @maintenance_timer Timer for maintenance charging
+ * @ab8500_bm_wq: Pointer to work queue-battery mponitor
+ * @ab8500_bm_irq_wq: Pointer to the work queue-
+ * enable/disable chargin from irq
+ * handler
+ * @ab8500_bm_wd_kick_wq: Pointer to work queue-rekick watchdog
+ * @ab8500_bm_usb_completed To get notified when USB negotiations are
+ * @ab8500_bm_kobject structure of type kobject
+ * @ab8500_bm_lock spin lock to lock the usb changed flag
+ */
+ struct ab8500_bm {
+ struct device *dev;
+ u8 cid;
+ int voltage_uV;
+ int temp_C;
+ int inst_current;
+ int avg_current;
+ int old_avg_current;
+ int capacity;
+ int samples;
+ int prev_capacity;
+ int charge_status;
+ int bk_battery_charge_status;
+ int usb_in_cur_lvl;
+ int usb_current;
+ int eoc_cond_counter;
+ bool maintenance_chg;
+ bool usb_changed;
+ bool usb_plug_unplug;
+ enum ab8500_usb_state usb_state;
+ struct ab8500_charger_state_info state_info;
+ struct ab8500_suspension_status suspension_status;
+ struct ab8500 *parent;
+ struct ab8500_bm_platform_data *pdata;
+ struct power_supply bat;
+ struct power_supply bk_bat;
+ struct power_supply ac;
+ struct power_supply usb;
+ struct ab8500_event_flags event_flags;
+ struct delayed_work ab8500_bm_monitor_work;
+ struct delayed_work ab8500_bm_watchdog_work;
+ struct work_struct ab8500_bm_ac_plug_monitor_work;
+ struct work_struct ab8500_bm_ac_unplug_monitor_work;
+ struct work_struct ab8500_bm_usb_en_monitor_work;
+ struct work_struct ab8500_bm_usb_dis_monitor_work;
+ struct work_struct ab8500_bm_avg_cur_monitor_work;
+ struct work_struct ab8500_bm_usb_state_changed_monitor_work;
+ struct work_struct ab8500_bm_instant_monitor_work;
+ struct work_struct ab8500_bm_detect_usb_type_monitor_work;
+ struct timer_list safety_timer;
+ struct timer_list maintenance_timer;
+ struct workqueue_struct *ab8500_bm_wq;
+ struct workqueue_struct *ab8500_bm_irq_wq;
+ struct workqueue_struct *ab8500_bm_wd_kick_wq;
+ struct completion ab8500_bm_usb_completed;
+ struct kobject ab8500_bm_kobject;
+ spinlock_t ab8500_bm_lock;
+};
+
+/**
+ * struct ab8500_bm_capacity - battery capacity based on voltage
+ * @vol_mV: voltage in mV
+ * @capacity capacity corresponding to the voltage in percentage
+ */
+struct ab8500_bm_capacity {
+ int vol_mV;
+ int capacity;
+};
+
+/**
+ * struct ab8500_bm_interrupts - ab8500 em interupts
+ * @name: name of the interrupt
+ * @isr function pointer to the isr
+ */
+struct ab8500_bm_interrupts {
+ char *name;
+ irqreturn_t (*isr)(int irq, void *data);
+};
+
+/* Battery capacity (in percent) based on battery voltage (in mV) */
+static struct ab8500_bm_capacity ab8500_bm_cap[] = {
+ {3100, 5},
+ {3225, 10},
+ {3451, 15},
+ {3525, 20},
+ {3605, 30},
+ {3701, 40},
+ {3800, 50},
+ {3902, 60},
+ {3975, 70},
+ {4050, 80},
+ {4150, 90},
+ {4191, 95},
+ {4195, 97},
+ {4200, 100},
+};
+
+static char *ab8500_bm_supplied_to[] = {
+ "ab8500_bm_battery",
+};
+
+/* Backup battery properties */
+static enum power_supply_property ab8500_bm_bk_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+/* Main battery properties */
+static enum power_supply_property ab8500_bm_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_TEMP,
+};
+
+/* AC/Wall properties */
+static enum power_supply_property ab8500_bm_ac_props[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+/* USB properties */
+static enum power_supply_property ab8500_bm_usb_props[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+/* UsbLineStatus register - usb types */
+enum ab8500_bm_usb_stat{
+ USB_STAT_NOT_CONFIGURED,
+ USB_STAT_STD_HOST_NC,
+ USB_STAT_STD_HOST_C_NS,
+ USB_STAT_STD_HOST_C_S,
+ USB_STAT_HOST_CHG_NM,
+ USB_STAT_HOST_CHG_HS,
+ USB_STAT_HOST_CHG_HS_CHIRP,
+ USB_STAT_DEDICATED_CHG,
+ USB_STAT_ACA_RID_A,
+ USB_STAT_ACA_RID_B,
+ USB_STAT_ACA_RID_C_NM,
+ USB_STAT_ACA_RID_C_HS,
+ USB_STAT_ACA_RID_C_HS_CHIRP,
+ USB_STAT_HM_IDGND,
+ USB_STAT_RESERVED,
+ USB_STAT_NOT_VALID_LINK,
+};
+
+static struct ab8500_bm *ab8500_bm_di;
+
+/* Function prototypes */
+static void ab8500_bm_charging_algorithm(struct ab8500_bm *di);
+
+/* Exposure to the sysfs interface */
+
+/**
+ * ab8500_bm_sysfs_charger() - sysfs store operations
+ * @kobj: pointer to the struct kobject
+ * @attr: pointer to the struct attribute
+ * @buf: buffer that holds the parameter passed from userspace
+ * @length: length of the parameter passed
+ *
+ * Returns length of the buffer(input taken from user space) on success
+ * else error code on failure
+ * The operation to be performed on passing the parameters from the user space.
+ */
+static ssize_t ab8500_bm_sysfs_charger(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t length)
+{
+ struct ab8500_bm *di = container_of(kobj,
+ struct ab8500_bm, ab8500_bm_kobject);
+ long int param;
+ int ac_usb, flag, ret = 0;
+ char entry = *attr->name;
+
+ switch (entry) {
+ case 'c':
+ strict_strtol(buf, 10, &param);
+ ac_usb = param;
+ switch (ac_usb) {
+ case 0:
+ /* Disable charging */
+ di->suspension_status.ac_suspended = true;
+ di->suspension_status.usb_suspended = true;
+ di->suspension_status.suspended_change = true;
+ /* Trigger a state change */
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_instant_monitor_work);
+ break;
+ case 1:
+ /* Enable AC Charging */
+ di->suspension_status.ac_suspended = false;
+ di->suspension_status.suspended_change = true;
+ /* Trigger a state change */
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_instant_monitor_work);
+ break;
+ case 2:
+ /* Enable USB charging */
+ di->suspension_status.usb_suspended = false;
+ di->suspension_status.suspended_change = true;
+ /* Trigger a state change */
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_instant_monitor_work);
+ break;
+ default:
+ dev_info(di->dev, "Wrong input\n"
+ "Enter 0. Disable AC/USB Charging\n"
+ "1. Enable AC charging\n"
+ "2. Enable USB Charging\n");
+ };
+ break;
+ case 'b':
+ strict_strtol(buf, 10, &param);
+ di->capacity = param;
+ break;
+ case 'n':
+ strict_strtol(buf, 10, &param);
+ di->samples = param;
+ /* Stop the CC */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8500_RTC_CC_CONF_REG, 0x01);
+ if (ret) {
+ dev_err(di->dev, "sysfs::cc disable failed\n");
+ return ret;
+ }
+ /* Program the samples */
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_GAS_GAUGE, AB8500_GASG_CC_NCOV_ACCU,
+ di->samples);
+ if (ret) {
+ dev_err(di->dev, "sysfs::cc write sample failed\n");
+ return ret;
+ }
+ /* Start the CC */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8500_RTC_CC_CONF_REG, 0x03);
+ if (ret) {
+ dev_err(di->dev, "sysfs::cc enable failed\n");
+ return ret;
+ }
+ break;
+ case 's':
+ strict_strtol(buf, 10, &param);
+ flag = param;
+ switch (flag) {
+ case 1:
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_RTC, AB8500_RTC_CC_CONF_REG,
+ 0x03);
+ if (ret)
+ dev_err(di->dev, "cc enable failed\n");
+ break;
+ case 0:
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_RTC, AB8500_RTC_CC_CONF_REG,
+ 0x01);
+ if (ret)
+ dev_err(di->dev, "cc disable failed\n");
+ break;
+ }
+ };
+ return strlen(buf);
+}
+
+static struct attribute ab8500_bm_en_charger = \
+{
+ .name = "charger",
+ .mode = S_IWUGO,
+};
+
+static struct attribute ab8500_bm_bat_capacity = \
+{
+ .name = "bat_capacity",
+ .mode = S_IWUGO,
+};
+
+static struct attribute ab8500_bm_num_samples = \
+{
+ .name = "num_samples",
+ .mode = S_IWUGO,
+};
+
+static struct attribute ab8500_bm_gg_status = \
+{
+ .name = "start",
+ .mode = S_IWUGO,
+};
+
+static struct attribute *ab8500_bm_chg[] = {
+ &ab8500_bm_en_charger,
+ &ab8500_bm_bat_capacity,
+ &ab8500_bm_num_samples,
+ &ab8500_bm_gg_status,
+ NULL
+};
+
+const struct sysfs_ops ab8500_bm_sysfs_ops = {
+ .store = ab8500_bm_sysfs_charger,
+};
+
+static struct kobj_type ab8500_bm_ktype = {
+ .sysfs_ops = &ab8500_bm_sysfs_ops,
+ .default_attrs = ab8500_bm_chg,
+};
+
+/**
+ * ab8500_bm_sysfs_exit() - de-init of sysfs entry
+ * @di: pointer to the struct ab8500_bm
+ *
+ * This function removes the entry in sysfs.
+ */
+static void ab8500_bm_sysfs_exit(struct ab8500_bm *di)
+{
+ kobject_del(&di->ab8500_bm_kobject);
+}
+
+/**
+ * ab8500_bm_sysfs_init() - init of sysfs entry
+ * @di: pointer to the struct ab8500_bm
+ *
+ * This function adds an entry in sysfs.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_bm_sysfs_init(struct ab8500_bm *di)
+{
+ int ret = 0;
+
+ ret = kobject_init_and_add(&di->ab8500_bm_kobject, &ab8500_bm_ktype,
+ NULL, "ab8500_charger");
+ if (ret < 0)
+ dev_err(di->dev, "failed to create sysfs entry\n");
+
+ return ret;
+}
+/* Exposure to the sysfs interface <<END>> */
+/**
+ * ab8500_bm_safety_timer_expired() - Expiration of the safety timer
+ * @data: pointer to the ab8500_bm structure
+ *
+ * This function gets called when the safety timer for the charger
+ * expires
+ */
+static void ab8500_bm_safety_timer_expired(unsigned long data)
+{
+ struct ab8500_bm *di = (struct ab8500_bm *) data;
+ dev_dbg(di->dev, "Safety timer expired\n");
+ di->event_flags.safety_timer_expired = true;
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+}
+
+/**
+ * ab8500_bm_maintenance_timer_expired() - Expiration of
+ * the maintenance timer
+ * @data: pointer to the ab8500_bm structure
+ *
+ * This function gets called when the maintenence timer
+ * expires
+ */
+static void ab8500_bm_maintenance_timer_expired(unsigned long data)
+{
+
+ struct ab8500_bm *di = (struct ab8500_bm *) data;
+ dev_dbg(di->dev, "Maintenance timer expired\n");
+ di->event_flags.maintenance_timer_expired = true;
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+}
+
+/**
+ * ab8500_bm_get_usb_cur() - get usb current
+ * @di: pointer to the ab8500_bm structre
+ *
+ * The usb stack provides the i/p current that can be drawn from the standard
+ * usb host. This will be in mA. This function converts current in mA to a
+ * value that can be written to the register.
+ */
+static void ab8500_bm_get_usb_cur(struct ab8500_bm *di)
+{
+ switch (di->usb_current) {
+ case USB_0P1A:
+ di->usb_in_cur_lvl = USB_CH_IP_CUR_LVL_0P09;
+ break;
+ case USB_0P2A:
+ di->usb_in_cur_lvl = USB_CH_IP_CUR_LVL_0P19;
+ break;
+ case USB_0P3A:
+ di->usb_in_cur_lvl = USB_CH_IP_CUR_LVL_0P29;
+ break;
+ case USB_0P4A:
+ di->usb_in_cur_lvl = USB_CH_IP_CUR_LVL_0P38;
+ break;
+ case USB_0P5A:
+ di->usb_in_cur_lvl = USB_CH_IP_CUR_LVL_0P5;
+ break;
+ default:
+ di->usb_in_cur_lvl = USB_CH_IP_CUR_LVL_0P09;
+ break;
+ };
+}
+
+/**
+ * ab8500_bm_usb_state_changed() - get notified with the usb states
+ * @bm_usb_state: USB status(reset, config, high speed)
+ * @mA: current in mA
+ *
+ * USB driver will call this API to notify the change in the USB state
+ * to the battery driver. Based on this information battery driver will
+ * take measurements to enable/disable charging.
+ *
+ */
+void ab8500_bm_usb_state_changed(u8 bm_usb_state, u16 mA)
+{
+
+ /* TODO: Change USB driver so that we get vbus detect */
+/* if (!di->usb_plug_unplug) {
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_dis_monitor_work);
+ return;
+ }
+*/
+ spin_lock(&ab8500_bm_di->ab8500_bm_lock);
+ ab8500_bm_di->usb_changed = true;
+ spin_unlock(&ab8500_bm_di->ab8500_bm_lock);
+
+ ab8500_bm_di->usb_state = bm_usb_state;
+ ab8500_bm_di->usb_current = mA;
+
+ queue_work(ab8500_bm_di->ab8500_bm_wq,
+ &ab8500_bm_di->ab8500_bm_usb_state_changed_monitor_work);
+ return;
+}
+EXPORT_SYMBOL(ab8500_bm_usb_state_changed);
+
+/**
+ * ab8500_bm_usb_state_changed_work() - work to get notified with usb state
+ * @work: Pointer to the work_struct structure
+ *
+ * USB driver will call this API to notify the change in the USB state
+ * to the battery driver. Based on this informatio battery driver will
+ * take measurements to enable/disable charging.
+ *
+ */
+void ab8500_bm_usb_state_changed_work(struct work_struct *work)
+{
+ int cnt, ret;
+ u8 val;
+
+ struct ab8500_bm *di = container_of(work,
+ struct ab8500_bm, ab8500_bm_usb_state_changed_monitor_work);
+
+ /* TODO: Change USB driver so that we get vbus detect */
+ /* if (!di->usb_plug_unplug) {
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_dis_monitor_work);
+ return;
+ }*/
+
+ /*
+ * Before reading the UsbLineStatus register, ITSource 21
+ * register should be read
+ */
+ for (cnt = 0; cnt < 10; cnt++) {
+ msleep(25);
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_INTERRUPT, AB8500_IT_SOURCE21_REG,
+ &val);
+ if (ret < 0)
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_USB, AB8500_USB_LINE_STAT_REG,
+ &val);
+ if (ret < 0)
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+ /*
+ * Until the IT source register is read the UsbLineStatus
+ * register is not updated, hence doing the same
+ * Revisit this:
+ */
+
+ /* get the USB type */
+ val = (val & AB8500_USB_LINK_STATUS) >> 3;
+ if (val)
+ break;
+ }
+
+ spin_lock(&di->ab8500_bm_lock);
+ di->usb_changed = false;
+ spin_unlock(&di->ab8500_bm_lock);
+ /*
+ * wait for some time until you get updates from the usb stack
+ * and negotiations are completed
+ */
+ msleep(250);
+
+ if (di->usb_changed)
+ return;
+
+ ab8500_bm_get_usb_cur(di);
+
+ dev_dbg(di->dev, "%s USB current %d, USB state %d\n",
+ __func__, di->usb_current, di->usb_state);
+
+ if (!di->usb_current) {
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_dis_monitor_work);
+ return;
+ }
+
+ switch (di->usb_state) {
+ case AB8500_BM_USB_STATE_RESET_HS:
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_dis_monitor_work);
+ break;
+ case AB8500_BM_USB_STATE_RESET_FS:
+ /* if cur > 0 enable charging else disable */
+ if (di->usb_current > 0)
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_en_monitor_work);
+ else
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_dis_monitor_work);
+ break;
+ case AB8500_BM_USB_STATE_CONFIGURED:
+ /*
+ * USB is configured, enable charging with the charging
+ * input current obtained from USB driver
+ */
+ if (val == USB_STAT_STD_HOST_C_S) {
+ /*
+ * Host charger, was suspended,
+ * resume first, then charge
+ */
+ ab8500_bm_ulpi_set_char_suspend_mode(
+ AB8500_BM_USB_STATE_RESUME);
+ }
+
+ complete(&di->ab8500_bm_usb_completed);
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_en_monitor_work);
+ break;
+ case AB8500_BM_USB_STATE_SUSPEND:
+ /* USB in suspend state */
+ ab8500_bm_ulpi_set_char_suspend_mode(
+ AB8500_BM_USB_STATE_SUSPEND);
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_dis_monitor_work);
+
+ break;
+ case AB8500_BM_USB_STATE_RESUME:
+ /* USB in resume state */
+ ab8500_bm_ulpi_set_char_suspend_mode(
+ AB8500_BM_USB_STATE_RESUME);
+ /*
+ * when suspend->resume there should be delay
+ * of 1sec for enabling charging
+ */
+ msleep(1000);
+
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_en_monitor_work);
+ break;
+ case AB8500_BM_USB_STATE_MAX:
+ /* USB in max state */
+ break;
+ default:
+ break;
+ };
+ return;
+}
+
+/**
+ * ab8500_bm_detect_usb_type_work() - work to detect USB type
+ * @work: Pointer to the work_struct structure
+ *
+ * Detect the type of USB plugged in and based on the
+ * type set the max current and voltage
+ *
+ */
+void ab8500_bm_detect_usb_type_work(struct work_struct *work)
+{
+ int cnt, ret;
+ u8 val;
+
+ struct ab8500_bm *di = container_of(work,
+ struct ab8500_bm, ab8500_bm_detect_usb_type_monitor_work);
+
+ dev_dbg(di->dev, "%s Trying to detect USB type\n", __func__);
+
+ /*
+ * On getting the VBUS rising edge detect interrupt there
+ * is a 250ms delay after which the register UsbLineStatus
+ * if filled with valid data
+ */
+ for (cnt = 0; cnt < 10; cnt++) {
+ msleep(250);
+
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_INTERRUPT, AB8500_IT_SOURCE21_REG,
+ &val);
+ if (ret < 0)
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+ ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+ AB8500_USB_LINE_STAT_REG, &val);
+ if (ret < 0)
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+
+ /* get the USB type */
+ val = (val & AB8500_USB_LINK_STATUS) >> 3;
+ }
+ if (!val && cnt == 10) {
+ dev_err(di->dev, "%s unable to detect the usb type\n",
+ __func__);
+ return;
+ }
+
+ /* TODO: verify the input current levev for the types of USB */
+ switch (val) {
+ case USB_STAT_NOT_CONFIGURED:
+ dev_dbg(di->dev, "%s USB Type - Not configured\n", __func__);
+ break;
+ case USB_STAT_STD_HOST_NC:
+ if (!wait_for_completion_timeout(&di->ab8500_bm_usb_completed,
+ USB_COMPL_TIME)) {
+ dev_err(di->dev,
+ "%s USB stack didn't update\n", __func__);
+ return;
+ }
+ ab8500_bm_get_usb_cur(di);
+ dev_dbg(di->dev,
+ "%s Standard Host, NC, di->usb_current: %d\n",
+ __func__, di->usb_current);
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_en_monitor_work);
+ break;
+ case USB_STAT_STD_HOST_C_NS:
+ if (!wait_for_completion_timeout(&di->ab8500_bm_usb_completed,
+ USB_COMPL_TIME)) {
+ dev_err(di->dev,
+ "%s USB stack didn't update\n", __func__);
+ return;
+ }
+ ab8500_bm_get_usb_cur(di);
+ dev_dbg(di->dev,
+ "%s Standard Host, charging, not suspended d_mA: %d\n",
+ __func__, di->usb_current);
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_en_monitor_work);
+ break;
+ case USB_STAT_STD_HOST_C_S:
+ if (!wait_for_completion_timeout(&di->ab8500_bm_usb_completed,
+ USB_COMPL_TIME)) {
+ dev_err(di->dev,
+ "%s USB stack didn't update\n", __func__);
+ return;
+ }
+ ab8500_bm_get_usb_cur(di);
+ dev_dbg(di->dev,
+ "%s Standard Host, charging, suspended\n", __func__);
+ break;
+ case USB_STAT_HOST_CHG_HS_CHIRP:
+ case USB_STAT_HOST_CHG_HS:
+ case USB_STAT_HOST_CHG_NM:
+ di->usb_in_cur_lvl = USB_CH_IP_CUR_LVL_0P29;
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_en_monitor_work);
+ dev_dbg(di->dev, "%s Host charger, Mode: %d\n", __func__, val);
+ break;
+ case USB_STAT_DEDICATED_CHG:
+ di->usb_in_cur_lvl = USB_CH_IP_CUR_LVL_1P0;
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_en_monitor_work);
+ dev_dbg(di->dev, "%s Dedicated USB Charger\n", __func__);
+ break;
+ case USB_STAT_ACA_RID_A:
+ case USB_STAT_ACA_RID_B:
+ case USB_STAT_ACA_RID_C_NM:
+ case USB_STAT_ACA_RID_C_HS:
+ case USB_STAT_ACA_RID_C_HS_CHIRP:
+ di->usb_in_cur_lvl = USB_CH_IP_CUR_LVL_0P09;
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_usb_en_monitor_work);
+ dev_dbg(di->dev, "%s ACA RID configuration, Mode: %d\n",
+ __func__, val);
+ break;
+ case USB_STAT_HM_IDGND:
+ dev_dbg(di->dev, "%s Host Mode(IDGND)\n", __func__);
+ break;
+ case USB_STAT_RESERVED:
+ dev_dbg(di->dev, "%s Reserved\n", __func__);
+ break;
+ case USB_STAT_NOT_VALID_LINK:
+ dev_dbg(di->dev, "%s USB link not valid\n", __func__);
+ break;
+ default:
+ dev_err(di->dev, "%s fallback: Error\n", __func__);
+ break;
+ };
+ return;
+}
+
+
+/**
+ * ab8500_bm_cc_enable() - enable coulomb counter
+ * @di: pointer to the ab8500_bm structure
+ * @flag: flag to enable/disable
+ *
+ * Enable/Disable coulomb counter.
+ * On failure returns -ve value.
+ */
+static int ab8500_bm_cc_enable(struct ab8500_bm *di, int flag)
+{
+ int ret = 0;
+ if (flag) {
+ /* Enable CC */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8500_RTC_CC_CONF_REG,
+ (CC_DEEP_SLEEP_ENA | CC_PWR_UP_ENA));
+ if (ret)
+ goto cc_err;
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_GAS_GAUGE, AB8500_GASG_CC_NCOV_ACCU,
+ ab8500_bm_di->samples);
+ if (ret)
+ goto cc_err;
+ } else {
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8500_RTC_CC_CONF_REG, 0);
+ if (ret)
+ goto cc_err;
+ }
+ dev_dbg(di->dev, "%s coulomb counter enabled\n", __func__);
+ return ret;
+cc_err:
+ dev_err(di->dev, "%s Enabling coulomb counter failed\n", __func__);
+ return ret;
+
+}
+
+/**
+ * ab8500_bm_inst_current() - battery instantenous current
+ * @di: pointer to the ab8500_bm structure
+ *
+ * Returns battery instantenous current(on success) else error code
+ */
+static int ab8500_bm_inst_current(struct ab8500_bm *di)
+{
+ int ret = 0;
+ u8 low, high;
+ static int val;
+
+ mutex_lock(&ab8500_cc_lock);
+ /* Reset counter and Read request */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+ AB8500_GASG_CC_CTRL_REG, (RESET_ACCU | READ_REQ));
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ mutex_unlock(&ab8500_cc_lock);
+ return ret;
+ }
+
+ /*
+ * Since there is no interrupt for this, just wait for 250ms
+ * 250ms is one sample conversion time with 32.768 Khz RTC clock
+ */
+ msleep(250);
+ /* Read CC Sample conversion value Low and high */
+ ret = abx500_get_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+ AB8500_GASG_CC_SMPL_CNVL_REG, &low);
+ if (ret < 0) {
+ dev_err(di->dev, "%s read failed\n", __func__);
+ mutex_unlock(&ab8500_cc_lock);
+ return ret;
+ }
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+ AB8500_GASG_CC_SMPL_CNVH_REG, &high);
+ if (ret < 0) {
+ dev_err(di->dev, "%s read failed\n", __func__);
+ mutex_unlock(&ab8500_cc_lock);
+ return ret;
+ }
+
+ /*
+ * negative value for Discharging
+ * convert 2's compliment into decimal
+ */
+ if (high & 0x10)
+ val = (low | (high << 8) | 0xFFFFE000);
+ else
+ val = (low | (high << 8));
+
+ /*
+ * Convert to unit value in mA
+ * Full scale input voltage is
+ * 66.660mV => LSB = 66.660mV/(4096*10) = 1.627mA
+ * resister value is 10 ohms
+ */
+
+ val = ((val * 6666) / 4096);
+
+ mutex_unlock(&ab8500_cc_lock);
+ return val;
+}
+
+/**
+ * ab8500_bm_avg_cur_work() - average battery current
+ * @work: pointer to the work_struct structure
+ *
+ * Updated the average battery current obtained from the
+ * coulomb counter.
+ */
+static void ab8500_bm_avg_cur_work(struct work_struct *work)
+{
+
+ int val;
+ int ret;
+ u8 low, med, high;
+
+ struct ab8500_bm *di = container_of(work,
+ struct ab8500_bm, ab8500_bm_avg_cur_monitor_work);
+
+ mutex_lock(&ab8500_cc_lock);
+ ret = abx500_set_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+ AB8500_GASG_CC_NCOV_ACCU_CTRL, RD_NCONV_ACCU_REQ);
+ if (ret)
+ goto exit;
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+ AB8500_GASG_CC_NCOV_ACCU_LOW, &low);
+ if (ret < 0)
+ goto exit;
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+ AB8500_GASG_CC_NCOV_ACCU_MED, &med);
+ if (ret < 0)
+ goto exit;
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+ AB8500_GASG_CC_NCOV_ACCU_HIGH, &high);
+ if (ret < 0)
+ goto exit;
+
+ /* Check for sign bit in case of negative value, 2's compliment */
+ if (high & 0x10)
+ val = (low | (med << 8) | (high << 16) | 0xFFE00000);
+ else
+ val = (low | (med << 8) | (high << 16));
+
+ /*
+ * CC LSB = 66.66mV/(4096*10mOhm) = 1.627mA
+ * Average Current in mA =
+ * (integrated value * 1627uA) /Number Of samples * 1000)
+ */
+ val = ((val * 1627) / (di->samples * 1000));
+
+ /*
+ * Filter out zero average current, single zero may be because
+ * of read error
+ */
+ if (val == 0) {
+ val = di->old_avg_current;
+ di->old_avg_current = 0;
+ } else
+ di->old_avg_current = val;
+
+ mutex_unlock(&ab8500_cc_lock);
+
+ di->avg_current = val;
+ return;
+exit:
+
+ dev_err(di->dev,
+ "Failed to read or write gas gauge registers\n");
+ mutex_unlock(&ab8500_cc_lock);
+
+ /*
+ * If ab8500 write fails,
+ * update it with previous average value
+ */
+ di->avg_current = di->old_avg_current;
+}
+
+/**
+ * ab8500_bm_ac_plug_work() - work to set AC charger plugged
+ * @work: pointer to the work_struct structure
+ *
+ * Work queue function for setting AC charger plugged
+ */
+static void ab8500_bm_ac_plug_work(struct work_struct *work)
+{
+ struct ab8500_bm *di = container_of(work,
+ struct ab8500_bm, ab8500_bm_ac_plug_monitor_work);
+
+ /* Set AC charger plugged */
+ di->state_info.connected_charger_status |= AC_PW_CONN;
+
+ /* Trigger new update */
+ power_supply_changed(&di->bat);
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+}
+
+/**
+ * ab8500_bm_ac_unplug_work() - work to set AC charger unplugged
+ * @work: pointer to the work_struct structure
+ *
+ * Work queue function for setting AC charger unplugged
+ */
+static void ab8500_bm_ac_unplug_work(struct work_struct *work)
+{
+ struct ab8500_bm *di = container_of(work,
+ struct ab8500_bm, ab8500_bm_ac_unplug_monitor_work);
+
+ /* Set AC charger unplugged */
+ di->state_info.connected_charger_status &= ~AC_PW_CONN;
+
+ /* Trigger new update */
+ power_supply_changed(&di->bat);
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+}
+
+/**
+ * ab8500_bm_usb_en_work() - work to enable usb charging
+ * @work: pointer to the work_struct structure
+ *
+ * Work queue function for enabling USB charging
+ */
+static void ab8500_bm_usb_en_work(struct work_struct *work)
+{
+ struct ab8500_bm *di = container_of(work,
+ struct ab8500_bm, ab8500_bm_usb_en_monitor_work);
+
+ /* Set USB charger ready to use */
+ di->state_info.connected_charger_status |= USB_PW_CONN;
+
+ /* Trigger new update */
+ power_supply_changed(&di->bat);
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+
+}
+
+/**
+ * ab8500_bm_usb_dis_work() - work to disable usb charging
+ * @work: pointer to the work_struct structure
+ *
+ * Work queue function for disabling USB charging
+ */
+static void ab8500_bm_usb_dis_work(struct work_struct *work)
+{
+ struct ab8500_bm *di = container_of(work,
+ struct ab8500_bm, ab8500_bm_usb_dis_monitor_work);
+
+ /* Set USB charger unusable or disconnected */
+ di->state_info.connected_charger_status &= ~USB_PW_CONN;
+
+ /* Trigger new update */
+ power_supply_changed(&di->bat);
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+
+}
+
+/**
+ * ab8500_bm_cc_convend_handler() - isr to get battery avg current.
+ * @irq: interrupt number
+ * @work: pointer to the work_struct structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_cc_convend_handler (int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_avg_cur_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_mainextchnotok_handler() - main charger not OK
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_mainextchnotok_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ dev_info(di->dev, "Main charger NOT OK! Charging cannot proceed\n");
+
+ di->event_flags.mainextchnotok = true;
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_battovv_handler() - battery overvoltage detected
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_battovv_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ /* on occurance of this int charging is stopped by hardware */
+ dev_alert(di->dev,
+ "Battery voltage above threshold voltage, charging stopped\n");
+
+ di->event_flags.batt_ovv = true;
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_mainchunplugdet_handler() - main charge unplug detected
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_mainchunplugdet_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ dev_dbg(di->dev, "%s main charger unplug detected\n", __func__);
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_ac_unplug_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_mainchplugdet_handler() - main charge plug detecte
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_mainchplugdet_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ dev_dbg(di->dev, "%s main charger plug detected\n", __func__);
+ queue_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_ac_plug_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_vbusdetr_handler() - rising edge on vbus detected
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Return IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_vbusdetr_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ di->usb_plug_unplug = true;
+ dev_dbg(di->dev, "%s vbus rising edge detected\n", __func__);
+ queue_work(di->ab8500_bm_irq_wq,
+ &di->ab8500_bm_detect_usb_type_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_vbusdetf_handler() - falling edge on vbus detected
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_vbusdetf_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ di->usb_plug_unplug = false;
+ dev_dbg(di->dev, "%s vbus falling edge detected\n", __func__);
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_usb_dis_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_batctrlindb_handler() - battery removal detected
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_batctrlindb_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+ dev_info(di->dev, "Battery removal detected!\n");
+ di->event_flags.batt_rem = true;
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_chwdexp_handler() - charger watchdog expiration detected
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_chwdexp_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ dev_warn(di->dev, "Watchdog charger expiration detected, "
+ "charging stopped...!\n");
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_vbusovv_handler() - vbus overvoltage detected
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_vbusovv_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ dev_warn(di->dev, "%s VBUS overvoltage detected\n", __func__);
+ /* For protection sw is also disabling charging */
+ switch (di->cid) {
+ case AB8500_CUT1P0:
+ case AB8500_CUT1P1:
+ /*
+ * On cut 1.x we get false VBUS OVV interrupts
+ * when a USB cable is insterted that is stopping
+ * the charging
+ */
+ /* TODO: Handle this in a better way */
+ di->event_flags.vbus_ovv = true;
+
+ break;
+
+ case AB8500_CUT2P0:
+ di->event_flags.vbus_ovv = true;
+ break;
+ }
+
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_lowbatf_handler() - bat voltage goes below LowBat detected
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_lowbatf_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ dev_alert(di->dev, "Battery voltage goes below LowBat voltage\n");
+ /*
+ * send an uevent so that application will get notified with the
+ * battery voltage and take necessary action
+ */
+ power_supply_changed(&di->bat);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_lowbatr_handler() - bat voltage goes above LowBat detected
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_lowbatr_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ dev_alert(di->dev, "Battery voltage goes above LowBat voltage\n");
+ /*
+ * send a uevent so that application will get notified with the
+ * battery voltage and take necessary action
+ */
+ power_supply_changed(&di->bat);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_btemplow_handler() - battery temp lower than 10
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_btemplow_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+ switch (di->cid) {
+ case AB8500_CUT1P0:
+ case AB8500_CUT1P1:
+ case AB8500_CUT2P0:
+ dev_dbg(di->dev, "%s Ignore false btemp low irq"
+ " for ABB cut 1.0, 1.1 and 2.0\n", __func__);
+ break;
+ default:
+ dev_crit(di->dev,
+ "%s Battery temperature lower than -10deg c\n",
+ __func__);
+ di->event_flags.btemp_low = true;
+ break;
+ }
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_btemphigh_handler() - battery temp higher than max temp
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_btemphigh_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ dev_crit(di->dev, "Battery temperature is higher than MAX temp\n");
+ di->event_flags.btemp_high = true;
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_usbchgdetdone_handler() - usb charger plug detected
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_usbchgdetdone_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ dev_dbg(di->dev, "%s usb charger detected\n", __func__);
+ queue_work(di->ab8500_bm_irq_wq,
+ &di->ab8500_bm_detect_usb_type_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_usbchthprotr_handler() - Die temp is above usb charger thermal
+ * protection threshold
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_usbchthprotr_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ dev_warn(di->dev, "Die temp above USB charger thermal protection "
+ "threshold, charging stopped...!\n");
+ di->event_flags.usb_thermal_prot = true;
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_mainchthprotr_handler() - Die temp is above main charger thermal
+ * protection threshold
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_mainchthprotr_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ dev_warn(di->dev,
+ "Die temp above Main chg th prot threshold,charging stopped\n");
+ di->event_flags.main_thermal_prot = true;
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_bm_usbchargernotokf_handler() - usb charger unplug detected
+ * @irq: interrupt number
+ * @_di: void pointer that has to address of ab8500_bm
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_usbchargernotokf_handler(int irq, void *_di)
+{
+ struct ab8500_bm *di = _di;
+
+ power_supply_changed(&di->bat);
+ dev_warn(di->dev, "not allowed USB charger detected...!\n");
+ di->event_flags.usbchargernotok = true;
+ queue_work(di->ab8500_bm_wq, &di->ab8500_bm_instant_monitor_work);
+ return IRQ_HANDLED;
+}
+
+/* ab8500 battery driver interrupts and their respective isr */
+static struct ab8500_bm_interrupts ab8500_bm_irq[] = {
+ {"MAIN_EXT_CH_NOT_OK", ab8500_bm_mainextchnotok_handler},
+ {"BATT_OVV", ab8500_bm_battovv_handler},
+ {"MAIN_CH_UNPLUG_DET", ab8500_bm_mainchunplugdet_handler},
+ {"MAIN_CHARGE_PLUG_DET", ab8500_bm_mainchplugdet_handler},
+ {"VBUS_DET_R", ab8500_bm_vbusdetr_handler},
+ {"VBUS_DET_F", ab8500_bm_vbusdetf_handler},
+ {"BAT_CTRL_INDB", ab8500_bm_batctrlindb_handler},
+ {"CH_WD_EXP", ab8500_bm_chwdexp_handler},
+ {"VBUS_OVV", ab8500_bm_vbusovv_handler},
+ {"LOW_BAT_F", ab8500_bm_lowbatf_handler},
+ {"LOW_BAT_R", ab8500_bm_lowbatr_handler},
+ {"BTEMP_LOW", ab8500_bm_btemplow_handler},
+ {"BTEMP_HIGH", ab8500_bm_btemphigh_handler},
+ {"USB_CHARGE_DET_DONE", ab8500_bm_usbchgdetdone_handler},
+ {"USB_CH_TH_PROT_R", ab8500_bm_usbchthprotr_handler},
+ {"MAIN_CH_TH_PROT_R", ab8500_bm_mainchthprotr_handler},
+ {"USB_CHARGER_NOT_OKF", ab8500_bm_usbchargernotokf_handler},
+ {"NCONV_ACCU", ab8500_bm_cc_convend_handler},
+};
+
+/**
+ * ab8500_bm_ac_voltage() - get ac charger voltage
+ * @di: pointer to the ab8500_bm structure
+ *
+ * Returns ac charger voltage(on success) else error code
+ */
+static int ab8500_bm_ac_voltage(struct ab8500_bm *di)
+{
+ int data;
+ static int prev;
+
+ data = ab8500_gpadc_convert(di->parent->gpadc, MAIN_CHARGER_V);
+ if (data < 0) {
+ dev_err(di->dev,
+ "gpadc conversion failed, using previous value\n");
+ return prev;
+ }
+
+ /*
+ * conversion from RAW val to voltage
+ * MAIN charger range from 0 to 20.03V. The resolution of the ADC
+ * is 10 bits
+ * Figures taken from AB8500 spec, UM0836
+ */
+ data = (ADC_CH_MAIN_MAX * data) / ADC_RESOLUTION;
+ prev = data;
+ return data;
+}
+
+/**
+ * ab8500_bm_usb_voltage() - get vbus voltage
+ * @di: pointer to the ab8500_bm structure
+ *
+ * This function returns the vbus voltage.
+ * Returns vbus voltage(on success) else error code
+ */
+static int ab8500_bm_usb_voltage(struct ab8500_bm *di)
+{
+ int data;
+ static int prev;
+
+ data = ab8500_gpadc_convert(di->parent->gpadc, VBUS_V);
+ if (data < 0) {
+ dev_err(di->dev,
+ "gpadc conversion failed, using previous value\n");
+ return prev;
+ }
+
+ /*
+ * conversion from RAW data to voltage
+ * VBUS range from 0 to 20.03V. The resolution of the ADC
+ * is 10 bits
+ * Figures taken from AB8500 spec, UM0836
+ */
+ data = (ADC_CH_VBUS_MAX * data) / ADC_RESOLUTION;
+ prev = data;
+ return data;
+}
+
+/**
+ * ab8500_bm_voltage() - get battery voltage
+ * @di: pointer to the ab8500_bm structure
+ *
+ * Returns battery voltage(on success) else error code
+ */
+static int ab8500_bm_voltage(struct ab8500_bm *di)
+{
+ int data;
+ static int prev;
+
+ data = ab8500_gpadc_convert(di->parent->gpadc, MAIN_BAT_V);
+ if (data < 0) {
+ dev_err(di->dev,
+ "gpadc conversion failed, using previous value\n");
+ return prev;
+ }
+
+ /*
+ * conversion from RAW value to voltage
+ * VBAT range from 2.3 to 4.8V. The resolution of the ADC
+ * is 10 bits
+ * Figures taken from AB8500 spec, UM0836
+ */
+ data = ADC_CH_VBAT_MIN +
+ (((ADC_CH_VBAT_MAX - ADC_CH_VBAT_MIN) * data) / ADC_RESOLUTION);
+ prev = data;
+ return data;
+}
+
+/**
+ * ab8500_bm_temperature() - get battery temperature
+ * @di: pointer to the ab8500_bm structure
+ *
+ * Returns battery temperature(on success) else error code
+ */
+static int ab8500_bm_temperature(struct ab8500_bm *di)
+{
+ int data, i = 0;
+ int tmp;
+ static int prev;
+ struct temperature {
+ int raw;
+ int uv;
+ int gain_op;
+ int gain_ip;
+ };
+
+ /*
+ * Refer Table-5 in
+ * MontBlanc Energy Management System Software Specification
+ * v1 41 stripped down.pdf
+ */
+
+ /*
+ * Raw Value Kelvin(Unit Value) Gain
+ * 1027 252 100/2075
+ * 636 272 100/1850
+ * 491 280 100/1535
+ * 358 298 100/1175
+ * 257 298 100/875
+ * 190 306 100/625
+ * 126 317 100/400
+ * 87 327 100/300
+ * 67 334 100/200
+ * 42 347 100/100
+ * 20 370 100/45
+ */
+ const struct temperature temp[11] = {
+ {20, 370, 100, 45},
+ {42, 347, 100, 100},
+ {67, 334, 100, 200},
+ {87, 327, 100, 300},
+ {126, 317, 100, 400},
+ {190, 306, 100, 625},
+ {257, 298, 100, 875},
+ {358, 298, 100, 1175},
+ {491, 280, 100, 1535},
+ {636, 272, 100, 1850},
+ {1027, 252, 100, 2075},
+ };
+
+ data = ab8500_gpadc_convert(di->parent->gpadc, BTEMP_BALL);
+ if (data < 0) {
+ dev_err(di->dev,
+ "gpadc conversion failed, using previous value\n");
+ return prev;
+ }
+
+ /*
+ * Conversion function for each sub-range
+ * UV = UV higher + (RAW higher - RAW measured)*Gain
+ */
+ while (data > temp[i].raw)
+ i++;
+ tmp = temp[i].uv + ((((temp[i].raw - data) * temp[i].gain_op * 10000) /
+ temp[i].gain_ip) / 10000);
+ /*
+ * convert kelvin to deg cel.
+ * Tc = Tk - 273.15
+ */
+ tmp = tmp - 273;
+ prev = tmp;
+ return tmp;
+}
+
+/**
+ * ab8500_bm_charger_presence() - check for the presence of charger
+ * @di: pointer to the ab8500 bm device information structure
+ *
+ * Returns an integer value, that means,
+ * NO_PW_CONN no power supply is connected
+ * AC_PW_CONN if the AC power supply is connected
+ * USB_PW_CONN if the USB power supply is connected
+ * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected
+ */
+static int ab8500_bm_charger_presence(struct ab8500_bm *di)
+{
+ return di->state_info.connected_charger_status;
+}
+
+static int simple_ab_read(struct ab8500_bm *di, u8 bank, u8 reg)
+{
+ u8 val;
+ int ret;
+
+ ret = abx500_get_register_interruptible(di->dev, bank, reg, &val);
+ if (ret < 0) {
+ dev_err(di->dev, "Failed to read abb register %s",
+ __func__);
+ return ret;
+ }
+
+ return val;
+}
+
+static void dump_debug_info(struct ab8500_bm *di)
+{
+ static bool firsttime;
+
+ if (firsttime == 0) {
+ firsttime = 1;
+ dev_vdbg(di->dev, "[PLOT_DATA_REG],MCH_CTRL1,MCH_CTRL2,"
+ "MCH_IPT_CURLVL,USBCH_CTRL1,USBCH_CTRL2,"
+ "USBCH_IPT_CRNTLVL,CH_STATUS1,CH_STATUS2,"
+ "CH_USBCH_STAT1,CH_USBCH_STAT2,CH_STAT,CH_VOLT_LVL,"
+ "CH_OPT_CRNTLVL,CH_WD_TIMER,CH_WD_CTRL,"
+ "LED_INDICATOR_PWM_CTRL,LED_INDICATOR_PWM_DUTY,"
+ "BATT_OVV,\n");
+ }
+
+ dev_vdbg(di->dev, "[PLOT_DATA_REG],%02x,%02x,%02x,%02x,%02x,%02x,%02x,"
+ "%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n",
+ simple_ab_read(di, AB8500_CHARGER, AB8500_MCH_CTRL1),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_MCH_CTRL2),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_MCH_IPT_CURLVL_REG),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_USBCH_CTRL1_REG),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_USBCH_CTRL2_REG),
+ simple_ab_read(di, AB8500_CHARGER,
+ AB8500_USBCH_IPT_CRNTLVL_REG),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_CH_STATUS1_REG),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_CH_STATUS2_REG),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_CH_USBCH_STAT1_REG),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_CH_STAT_REG),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_CH_VOLT_LVL_REG),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_REG),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_CH_WD_TIMER_REG),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_CHARG_WD_CTRL),
+ simple_ab_read(di, AB8500_CHARGER,
+ AB8500_LED_INDICATOR_PWM_CTRL),
+ simple_ab_read(di, AB8500_CHARGER,
+ AB8500_LED_INDICATOR_PWM_DUTY),
+ simple_ab_read(di, AB8500_CHARGER, AB8500_BATT_OVV));
+}
+
+/**
+ * ab8500_bm_battery_read_status() - get the battery parameters
+ * @di: pointer to the ab8500_bm structure
+ *
+ * This function is being called from ab8500_bm_charging_algorithm
+ * to get the battery voltage, current and temperature. Ahead to this
+ * it also checks for the condition to terminate charging if chargign
+ * is in progress.
+ */
+static void ab8500_bm_battery_read_status(struct ab8500_bm *di)
+{
+ int val, val_usb, ret;
+ int new_capacity = 0;
+ static bool firsttime;
+
+ di->temp_C = ab8500_bm_temperature(di);
+ di->voltage_uV = ab8500_bm_voltage(di);
+ di->inst_current = ab8500_bm_inst_current(di);
+
+ /*
+ * Capacity might have changed now
+ * if it is changed, then update sysfs
+ */
+ if ((new_capacity != di->prev_capacity) && (new_capacity != 0)) {
+ di->prev_capacity = new_capacity;
+ power_supply_changed(&di->bat);
+ }
+
+ /*
+ * Li-ion batteries gets charged upto 4.2v, hence 4.2v should be
+ * one of the criteria for termination charging.
+ * Another factor to terminate the the charging is the CV method,
+ * on occurance of Constant Voltage charging the termination current
+ * has to be checked.
+ * For this the integrated current has to be in the range of 50-200mA
+ */
+
+ /* Check charging status */
+ ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_CH_STATUS1_REG, (u8 *) &val);
+ if (ret < 0)
+ goto exit;
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_CH_USBCH_STAT1_REG, (u8 *) &val_usb);
+ if (ret < 0)
+ goto exit;
+
+ dump_debug_info(di);
+
+ if (firsttime == 0) {
+ firsttime = 1;
+ dev_dbg(di->dev, "[PLOT_DATA],Vbat, Ibat_inst, Ibat_avg, "
+ "Batt temp,Maintenance,DCIO On,DCIO CV,DCIO pres,"
+ "VBUS On,VBUS CV,VBUS pres,State,Status,VBUS mA\n\n");
+ }
+
+ dev_dbg(di->dev,
+ "[PLOT_DATA],%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
+ di->voltage_uV,
+ di->inst_current,
+ di->avg_current,
+ di->temp_C,
+ di->maintenance_chg,
+ (val >> 1) & 0x01,
+ (val >> 2) & 0x01,
+ ab8500_bm_charger_presence(di) & AC_PW_CONN,
+ (val_usb >> 2) & 0x01,
+ (val_usb >> 3) & 0x01,
+ (ab8500_bm_charger_presence(di) & USB_PW_CONN) >> 1,
+ di->state_info.state,
+ di->charge_status,
+ di->usb_current);
+
+ if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
+ !di->maintenance_chg) {
+ /*
+ * Don't check voltage
+ * let HW decide if we're in CV or CC.
+ */
+ if ((val & MAIN_CH_CV_ON) || (val_usb & USB_CH_CV_ON)) {
+ /* Check for termination current */
+ if (di->inst_current <
+ di->pdata->bat_type[0].termination_curr) {
+ if (++di->eoc_cond_counter >= EOC_COND_CNT) {
+ di->eoc_cond_counter = 0;
+ dev_dbg(di->dev,
+ "%s EOC reached, Ibat < %dmA\n",
+ __func__,
+ di->pdata->bat_type[0].
+ termination_curr);
+
+ di->charge_status =
+ POWER_SUPPLY_STATUS_FULL;
+ di->maintenance_chg = true;
+ dev_dbg(di->dev,
+ "%s Battery full!\n", __func__);
+
+ } else {
+ dev_dbg(di->dev,
+ "%s"
+ " EOC limit reached for the %d"
+ " time, out of %d before EOC\n",
+ __func__,
+ di->eoc_cond_counter,
+ EOC_COND_CNT);
+ }
+ } else {
+ /* Reset the EndOfCharge condition counter */
+ if (di->eoc_cond_counter) {
+ di->eoc_cond_counter = 0;
+ dev_dbg(di->dev, "%s "
+ "Resetting EOC cond counter\n",
+ __func__);
+ }
+ }
+ } else
+ di->eoc_cond_counter = 0;
+ }
+ return;
+
+exit:
+ dev_err(di->dev, "Failed to read charger status registers %s",
+ __func__);
+}
+
+static const char *states[] = {
+ "OFF_INIT",
+ "OFF",
+ "HW_TEMP_PROTECT_INIT",
+ "HW_TEMP_PROTECT",
+ "NORMAL_INIT",
+ "NORMAL",
+ "MAINTENANCE_A_INIT",
+ "MAINTENANCE_A",
+ "MAINTENANCE_B_INIT",
+ "MAINTENANCE_B",
+ "SAFE",
+ "TEMP_UNDEROVER_INIT",
+ "TEMP_UNDEROVER",
+ "TEMP_LOWHIGH_INIT",
+ "TEMP_LOWHIGH",
+ "HANDHELD_INIT",
+ "HANDHELD",
+ "SUSPENDED_INIT",
+ "SUSPENDED",
+ "OVV_PROTECT_INIT",
+ "OVV_PROTECT",
+ "SAFETY_TIMER_EXPIRED_INIT",
+ "SAFETY_TIMER_EXPIRED",
+};
+
+static const char *charge_source[] = {
+ "CHARGER_OFF",
+ "CHARGER_DCIO",
+ "CHARGER_USB",
+};
+
+static void ab8500_bm_change_state_to(struct ab8500_bm *di,
+ enum ab8500_charger_states state)
+{
+ dev_dbg(di->dev,
+ "%s State changed: %s (From state: [%d] %s =to=> [%d] %s )\n",
+ __func__,
+ di->state_info.state == state ? "NO" : "YES",
+ di->state_info.state,
+ states[di->state_info.state],
+ state,
+ states[state]);
+ di->state_info.state = state;
+
+}
+
+static void ab8500_bm_start_safety_timer(struct ab8500_bm *di)
+{
+ unsigned long timer_expiration = 0;
+
+ switch (di->state_info.type) {
+ case AB8500_CHARGER_DCIO:
+ timer_expiration =
+ round_jiffies(jiffies +
+ (di->pdata->main_safety_tmr_h * 3600 * HZ));
+ break;
+
+ case AB8500_CHARGER_USB:
+ timer_expiration =
+ round_jiffies(jiffies +
+ (di->pdata->usb_safety_tmr_h * 3600 * HZ));
+ break;
+
+ default:
+ dev_err(di->dev,
+ "%s Unknown charger to charge from...%d %s\n",
+ __func__,
+ di->state_info.type,
+ charge_source[di->state_info.type]);
+ break;
+ }
+
+ di->event_flags.safety_timer_expired = false;
+ di->safety_timer.expires = timer_expiration;
+ if (!timer_pending(&di->safety_timer))
+ add_timer(&di->safety_timer);
+ else
+ mod_timer(&di->safety_timer, timer_expiration);
+}
+
+static void ab8500_bm_stop_safety_timer(struct ab8500_bm *di)
+{
+ di->event_flags.safety_timer_expired = false;
+ del_timer(&di->safety_timer);
+}
+
+static void ab8500_bm_start_maintenance_timer(struct ab8500_bm *di,
+ int duration)
+{
+ unsigned long timer_expiration;
+
+ /* Convert from hours to jiffies */
+ timer_expiration = round_jiffies(jiffies + (duration * 3600 * HZ));
+
+ di->event_flags.maintenance_timer_expired = false;
+ di->maintenance_timer.expires = timer_expiration;
+ if (!timer_pending(&di->maintenance_timer))
+ add_timer(&di->maintenance_timer);
+ else
+ mod_timer(&di->maintenance_timer, timer_expiration);
+}
+
+static void ab8500_bm_stop_maintenance_timer(struct ab8500_bm *di)
+{
+ di->event_flags.maintenance_timer_expired = false;
+ del_timer(&di->maintenance_timer);
+}
+
+/**
+ * ab8500_bm_get_bat_capacity() - get battery capacity
+ * @di: Pointer to the ab8500_bm structure
+ *
+ * This function returns the battery capacity(in percent) based on voltage.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_bm_get_bat_capacity(struct ab8500_bm *di)
+{
+ int ret = 0, cnt;
+
+ if (di->voltage_uV > di->pdata->bat_type[0].termination_vol)
+ return 100;
+ for (cnt = 0; cnt < ARRAY_SIZE(ab8500_bm_cap); cnt++) {
+ if (di->voltage_uV <= ab8500_bm_cap[cnt].vol_mV) {
+ ret = ab8500_bm_cap[cnt].capacity;
+ break;
+ }
+ };
+ return ret;
+}
+
+/**
+ * ab8500_bm_battery_inst_work() -
+ */
+static void ab8500_bm_battery_inst_work(struct work_struct *work)
+{
+ struct ab8500_bm *di = container_of(work,
+ struct ab8500_bm, ab8500_bm_instant_monitor_work);
+
+ ab8500_bm_charging_algorithm(di);
+}
+
+/**
+ * ab8500_bm_battery_work() - battery monitoring work
+ * @work: pointer to the work_struct structure
+ *
+ * This function is called on probe of the driver and thereafter at
+ * cnnstant interval to time to keep monitoring the battery.
+ */
+static void ab8500_bm_battery_work(struct work_struct *work)
+{
+ struct ab8500_bm *di = container_of(work,
+ struct ab8500_bm, ab8500_bm_monitor_work.work);
+
+ ab8500_bm_charging_algorithm(di);
+
+ /*
+ * If charging is in progress then the battery has to be monitored
+ * very frequently, else the work to monitor can be delayed.
+ */
+ if ((di->charge_status == POWER_SUPPLY_STATUS_CHARGING) ||
+ di->maintenance_chg)
+ queue_delayed_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_monitor_work, HZ);
+ else
+ queue_delayed_work(di->ab8500_bm_wq,
+ &di->ab8500_bm_monitor_work, 20 * HZ);
+}
+
+/**
+ * ab8500_bm_bk_battery_voltage() - backup battery voltage
+ * @di: pointer to the ab8500_bm structure
+ *
+ * This function is called from the ab8500_bm_bk_battery_get_property function
+ * to get the backup battery voltage. It uses GPADC to get the voltage
+ * converted from analog to digital.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_bm_bk_battery_voltage(struct ab8500_bm *di)
+{
+ int data;
+ static int prev;
+
+ data = ab8500_gpadc_convert(di->parent->gpadc, BK_BAT_V);
+ if (data < 0) {
+ dev_err(di->dev,
+ "gpadc conversion failed, using previous value\n");
+ return prev;
+ }
+
+ /*
+ * conversion from RAW value to voltage
+ * Backup bat voltage range from 0 to 3.2V. The resolution of the ADC
+ * is 10 bits
+ * Figures taken from AB8500 spec, UM0836
+ */
+ data = ADC_CH_BKBAT_MIN +
+ (((ADC_CH_BKBAT_MAX - ADC_CH_BKBAT_MIN) * data) /
+ ADC_RESOLUTION);
+ prev = data;
+ return data;
+}
+
+/**
+ * ab8500_bm_watchdog_kick_work() - Re-kick the watchdog
+ * @work: pointer to the work_struct structure
+ *
+ * This function is called on enabling the ac/usb charging to
+ * re-kick the watchdog. Thereafter as delayed work in the workqueue
+ * at contant intervals to keep re-kicking the watchdog until charging
+ * is stopped.
+ */
+static void ab8500_bm_watchdog_kick_work(struct work_struct *work)
+{
+ int ret;
+ struct ab8500_bm *di = container_of(work,
+ struct ab8500_bm, ab8500_bm_watchdog_work.work);
+
+ /* Kickoff main watchdog */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_CHARG_WD_CTRL, CHARG_WD_KICK);
+ if (ret) {
+ dev_err(di->dev, "Failed to kick WD, retrying!\n");
+ queue_delayed_work(di->ab8500_bm_wd_kick_wq,
+ &di->ab8500_bm_watchdog_work, 0);
+ return;
+ }
+
+ queue_delayed_work(di->ab8500_bm_wd_kick_wq,
+ &di->ab8500_bm_watchdog_work, CHG_WD_INTERVAL);
+}
+
+/**
+ * ab8500_bm_led_en() - turn on/off chargign led
+ * @di: pointer to the ab8500_bm structure
+ * @on: flag to turn on/off the chargign led
+ *
+ * Power ON/OFF charging LED indication
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_bm_led_en(struct ab8500_bm *di, int on)
+{
+ int ret;
+
+ if (on) {
+ /* Power ON charging LED indicator, set LED current to 5mA */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_LED_INDICATOR_PWM_CTRL,
+ (LED_IND_CUR_5MA | LED_INDICATOR_PWM_ENA));
+ if (ret) {
+ dev_err(di->dev,
+ "%s power ON LED failed\n", __func__);
+ return ret;
+ }
+ /* LED indicator PWM duty cycle 252/256 */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_LED_INDICATOR_PWM_DUTY,
+ LED_INDICATOR_PWM_DUTY_252_256);
+ if (ret) {
+ dev_err(di->dev, "%s set LED PWM duty cycle failed\n",
+ __func__);
+ return ret;
+ }
+ } else {
+ /* Power off charging LED indicator */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_LED_INDICATOR_PWM_CTRL,
+ LED_INDICATOR_PWM_DIS);
+ if (ret) {
+ dev_err(di->dev,
+ "%s power-off LED failed\n", __func__);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * This array maps the raw hex value to charger voltage used by the AB8500
+ * Values taken from the UM0836
+ */
+static int ab8500_charger_voltage_map[] = {
+ 3500 ,
+ 3525 ,
+ 3550 ,
+ 3575 ,
+ 3600 ,
+ 3625 ,
+ 3650 ,
+ 3675 ,
+ 3700 ,
+ 3725 ,
+ 3750 ,
+ 3775 ,
+ 3800 ,
+ 3825 ,
+ 3850 ,
+ 3875 ,
+ 3900 ,
+ 3925 ,
+ 3950 ,
+ 3975 ,
+ 4000 ,
+ 4025 ,
+ 4050 ,
+ 4060 ,
+ 4070 ,
+ 4080 ,
+ 4090 ,
+ 4100 ,
+ 4110 ,
+ 4120 ,
+ 4130 ,
+ 4140 ,
+ 4150 ,
+ 4160 ,
+ 4170 ,
+ 4180 ,
+ 4190 ,
+ 4200 ,
+ 4210 ,
+ 4220 ,
+ 4230 ,
+ 4240 ,
+ 4250 ,
+ 4260 ,
+ 4270 ,
+ 4280 ,
+ 4290 ,
+ 4300 ,
+ 4310 ,
+ 4320 ,
+ 4330 ,
+ 4340 ,
+ 4350 ,
+ 4360 ,
+ 4370 ,
+ 4380 ,
+ 4390 ,
+ 4400 ,
+ 4410 ,
+ 4420 ,
+ 4430 ,
+ 4440 ,
+ 4450 ,
+ 4460 ,
+ 4470 ,
+ 4480 ,
+ 4490 ,
+ 4500 ,
+ 4510 ,
+ 4520 ,
+ 4530 ,
+ 4540 ,
+ 4550 ,
+ 4560 ,
+ 4570 ,
+ 4580 ,
+ 4590 ,
+ 4600 ,
+ 3390 ,
+ 3500
+};
+
+static int ab8500_regval2voltage(unsigned int regval)
+{
+ if (regval >= ARRAY_SIZE(ab8500_charger_voltage_map))
+ return -EINVAL;
+
+ return ab8500_charger_voltage_map[regval];
+}
+
+/**
+ * ab8500_bm_ac_en() - enable ac charging
+ * @di: pointer to the ab8500_bm structure
+ * @enable: enable/disable flag
+ * @vset: charging voltage
+ * @iset: charging current
+ *
+ * Enable/Disable AC/Mains charging and turns on/off the charging led
+ * respectively.
+ **/
+static int ab8500_bm_ac_en_w_v_i(struct ab8500_bm *di,
+ int enable, int vset, int ich)
+{
+ int ret = 0;
+ if (enable) {
+ /* Check if AC is connected */
+ ret = ab8500_bm_charger_presence(di);
+ if (ret < 0) {
+ dev_err(di->dev, "AC charger presence check failed\n");
+ return ret;
+ }
+ if (!(ret & AC_PW_CONN)) {
+ dev_err(di->dev, "AC charger not connected\n");
+ return -ENXIO;
+ }
+ ret = 0;
+
+ /* Enable AC charging */
+
+ /* ChVoltLevel: max voltage upto which battery can be charged */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_CH_VOLT_LVL_REG, vset);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ /* MainChInputCurr: current that can be drawn from the charger*/
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_MCH_IPT_CURLVL_REG, MAIN_CH_IP_CUR_1P5A);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ /* ChOutputCurentLevel: protected output current */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_CH_OPT_CRNTLVL_REG, ich);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ /* Enable Main Charger */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_MCH_CTRL1, MAIN_CH_ENA);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ /* Enable main watchdog */
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_ENA);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WDOG_CTRL_REG,
+ (MAIN_WDOG_ENA | MAIN_WDOG_KICK));
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ /* Disable main watchdog */
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_DIS);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+
+ /*If success power on charging LED indication */
+ if (ret == 0) {
+ ret = ab8500_bm_led_en(di, true);
+ if (ret < 0)
+ dev_err(di->dev, "failed to enable LED\n");
+ }
+ dev_dbg(di->dev, "%s Enabled AC charging\n", __func__);
+
+ /* Schedule delayed work to re-kick watchdog */
+ /*
+ * TODO: Change the watchdog kickprocedure for cut 1.1
+ * queue_delayed_work(di->ab8500_bm_wd_kick_wq,
+ * &di->ab8500_bm_watchdog_work, CHG_WD_INTERVAL);
+ */
+ } else {
+ /* Disable AC charging */
+
+ switch (di->cid) {
+ case AB8500_CUT1P0:
+ case AB8500_CUT1P1:
+ /*
+ * We can't turn off charging completely
+ * due to a bug in AB8500 cut1.
+ * If we do, charging will not start again.
+ * That is why we set the lowest voltage
+ * and current possible
+ */
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_CHARGER,
+ AB8500_CH_VOLT_LVL_REG, CH_VOL_LVL_3P5);
+ if (ret) {
+ dev_err(di->dev,
+ "%s write failed\n", __func__);
+ return ret;
+ }
+
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_CHARGER,
+ AB8500_CH_VOLT_LVL_REG, CH_OP_CUR_LVL_0P1);
+ if (ret) {
+ dev_err(di->dev,
+ "%s write failed\n", __func__);
+ return ret;
+ }
+ break;
+
+ case AB8500_CUT2P0:
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_CHARGER,
+ AB8500_MCH_CTRL1, MAIN_CH_DIS);
+ if (ret) {
+ dev_err(di->dev,
+ "%s write failed\n", __func__);
+ return ret;
+ }
+ break;
+ }
+
+ /* If success power off charging LED indication */
+ /*
+ * Check if USB charger is presenc if so then dont
+ * turn off the LED, USB charging is taking place
+ */
+ ret = ab8500_bm_charger_presence(di);
+ if (!(ret & USB_PW_CONN)) {
+ /* Schedule delayed work to re-kick watchdog */
+ /*
+ * TODO: Change the watchdog kickprocedure for cut 1.1
+ * cancel_delayed_work
+ * (&di->ab8500_bm_watchdog_work);
+ */
+ ret = ab8500_bm_led_en(di, false);
+ if (ret < 0)
+ dev_err(di->dev,
+ "failed to disable LED\n");
+ }
+ dev_dbg(di->dev, "%s Disabled AC charging\n", __func__);
+ }
+ return ret;
+}
+
+
+static int ab8500_bm_ac_en(struct ab8500_bm *di, int enable)
+{
+ return ab8500_bm_ac_en_w_v_i(di, enable,
+ di->pdata->bat_type[0].normal_ip_vol_lvl,
+ di->pdata->bat_type[0].normal_op_cur_lvl);
+}
+
+/**
+ * ab8500_bm_usb_en_w_v_i() - enable usb charging
+ * @di: pointer to the ab8500_bm structure
+ * @enable: enable/disable flag
+ * @vset: charging voltage
+ * @ich: charger output current
+ *
+ * Enable/Disable USB charging and turns on/off the charging led respectively.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_bm_usb_en_w_v_i(struct ab8500_bm *di,
+ int enable, int vset, int ich)
+{
+ int ret = 0;
+
+ if (enable) {
+ /* Check if USB is connected */
+ ret = ab8500_bm_charger_presence(di);
+ if (ret < 0) {
+ dev_err(di->dev,
+ "USB charger presence check failed\n");
+ return ret;
+ }
+ if ((ret != USB_PW_CONN) &&
+ (ret != (AC_PW_CONN + USB_PW_CONN))) {
+ dev_alert(di->dev, "USB charger not connected\n");
+ return -ENXIO;
+ }
+ /* Enable USB charging */
+
+ /* ChVoltLevel: max voltage upto which battery can be charged */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_CH_VOLT_LVL_REG, vset);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ /* USBChInputCurr: current that can be drawn from the usb */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_USBCH_IPT_CRNTLVL_REG,
+ di->usb_in_cur_lvl);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ /* ChOutputCurentLevel: protected output current */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_CH_OPT_CRNTLVL_REG,
+ ich);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ /* Enable USB Charger */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_USBCH_CTRL1_REG, USB_CH_ENA);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ /* Enable main watchdog */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_ENA);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_MAIN_WDOG_CTRL_REG,
+ (MAIN_WDOG_ENA | MAIN_WDOG_KICK));
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ /* Disable main watchdog */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_DIS);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+ /* If success power on charging LED indication */
+ if (ret == 0) {
+ ret = ab8500_bm_led_en(di, true);
+ if (ret < 0)
+ dev_err(di->dev, "failed to enable LED\n");
+ }
+ dev_dbg(di->dev, "%s Enabled USB charging\n", __func__);
+
+ /* Schedule delayed work to re-kick watchdog */
+ /*
+ * TODO: Change the watchdog kickprocedure for cut 1.1
+ * queue_delayed_work(di->ab8500_bm_wd_kick_wq,
+ * &di->ab8500_bm_watchdog_work, CHG_WD_INTERVAL);
+ */
+ } else {
+ /* Disable USB charging */
+
+ switch (di->cid) {
+ case AB8500_CUT1P0:
+ case AB8500_CUT1P1:
+ /*
+ * We can't turn off charging completely
+ * due to a bug in AB8500 cut1.
+ * If we do, charging will not start again.
+ * That is why we set the lowest voltage
+ * and current possible
+ */
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_CHARGER,
+ AB8500_CH_VOLT_LVL_REG, CH_VOL_LVL_3P5);
+ if (ret) {
+ dev_err(di->dev,
+ "%s write failed\n", __func__);
+ return ret;
+ }
+
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_CHARGER,
+ AB8500_CH_VOLT_LVL_REG, CH_OP_CUR_LVL_0P1);
+ if (ret) {
+ dev_err(di->dev,
+ "%s write failed\n", __func__);
+ return ret;
+ }
+ break;
+
+ case AB8500_CUT2P0:
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_CHARGER,
+ AB8500_USBCH_CTRL1_REG, USB_CH_DIS);
+ if (ret) {
+ dev_err(di->dev,
+ "%s write failed\n", __func__);
+ return ret;
+ }
+ break;
+ }
+
+ /* If successful power off charging LED indication */
+
+ /*
+ * Check if AC charger is present if so then do not
+ * turn off the LED, AC charging is taking place
+ */
+ ret = ab8500_bm_charger_presence(di);
+ if ((ret != AC_PW_CONN) &&
+ (ret != (AC_PW_CONN + USB_PW_CONN))) {
+ /* Schedule delayed work to re-kick watchdog */
+ /*
+ * TODO: Change the watchdog kickprocedure for cut 1.1
+ * cancel_delayed_work
+ * (&di->ab8500_bm_watchdog_work);
+ */
+ ret = ab8500_bm_led_en(di, false);
+ if (ret < 0)
+ dev_err(di->dev,
+ "failed to disable LED\n");
+ }
+ dev_dbg(di->dev, "%s Disabled USB charging\n", __func__);
+ }
+ return ret;
+}
+
+/**
+ * ab8500_bm_usb_en() - enable usb charging
+ * @di: pointer to the ab8500_bm structure
+ * @enable: enable/disable flag
+ *
+ * Enable/Disable USB charging and turns on/off the charging led respectively.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_bm_usb_en(struct ab8500_bm *di, int enable)
+{
+ return ab8500_bm_usb_en_w_v_i(di, enable,
+ di->pdata->bat_type[0].normal_ip_vol_lvl,
+ di->pdata->bat_type[0].normal_op_cur_lvl);
+}
+
+/**
+ * ab8500_bm_status() - battery status
+ * @di: pointer to the ab8500_bm structure
+ *
+ * Returns the type of charge AC/USB
+ * This is called by the battery property "POWER_SUPPLY_PROP_ONLINE"
+ */
+static int ab8500_bm_status(struct ab8500_bm *di)
+{
+ int result = 0;
+ int ret;
+ u8 val;
+
+ /* Check for AC charging */
+ ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_CH_STATUS1_REG, &val);
+ if (ret < 0) {
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+ return ret;
+ }
+
+ if (val & MAIN_CH_ON)
+ result = AC_PW_CONN;
+
+ /* Check for USB charging */
+ ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_CH_USBCH_STAT1_REG, &val);
+ if (ret < 0) {
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+ return ret;
+ }
+
+ switch (di->cid) {
+ case AB8500_CUT1P0:
+ case AB8500_CUT1P1:
+ if (val & (VBUS_DET_DBNC100 | VBUS_DET_DBNC1))
+ result = USB_PW_CONN;
+ break;
+ default: /* This should be valid from cut 2 and on.. */
+ if (val & USB_CH_ON)
+ result = USB_PW_CONN;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * ab8500_bm_get_bat_resis() - get battery resistance
+ * @di: pointer to the ab8500_bm structure
+ *
+ * This function returns the battery resistance that is
+ * read from the GPADC.
+ */
+static int ab8500_bm_get_bat_resis(struct ab8500_bm *di)
+{
+ int data, rbs, vbs;
+ static int prev;
+
+ data = ab8500_gpadc_convert(di->parent->gpadc, BAT_CTRL);
+ if (data < 0) {
+ dev_err(di->dev,
+ "%s gpadc conversion failed, using previous value",
+ __func__);
+ return prev;
+ }
+ /*
+ * The range BAT_CTRL channel of the GPADC is
+ * 0 to 1350mV, and 1 LSB is worth 1.32 mV
+ */
+ vbs = (1350 * data) / 1023;
+
+ switch (ab8500_bm_di->cid) {
+ case AB8500_CUT1P0:
+ case AB8500_CUT1P1:
+ /*
+ * For ABB cut1.0 and 1.1 BAT_CTRL is internally
+ * connected to 1.8V through a 450k resistor
+ */
+ rbs = (450 * vbs) / (1800 - vbs);
+ break;
+ default:
+ /*
+ * For ABB cut2.0 and onwards BAT_CTRL is internally
+ * connected to 1.8V through a 80k resistor
+ */
+ rbs = (80 * vbs) / (1800 - vbs);
+ break;
+ }
+
+ dev_dbg(di->dev, "%s Battery Resistance = %d\n", __func__, rbs);
+ prev = rbs;
+ return rbs;
+}
+
+/**
+ * ab8500_bm_get_battery_property() - get the battery properties
+ * @psy: pointer to the power_supply structure
+ * @psp: pointer to the power_supply_property structure
+ * @val: pointer to the power_supply_propval union
+ *
+ * This function is called when an application tries to get the battery
+ * properties by reading the sysfs interface.
+ * Battery properties include
+ * status: charging/discharging/full/unknown
+ * present: presence of battery
+ * online: who is charging the battery mains/usb
+ * technology: battery type
+ * voltage_max: maximum voltage the battery can withstand
+ * voltage_now: present battery voltage
+ * current_now: instantaneous current of the battery
+ * current_avg: average current of the battery
+ * energy_now: battery energy
+ * capacity: capacity of the battery in percentage
+ * temp: battery temperature in deg cel
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_bm_get_battery_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct ab8500_bm *di;
+ int res = 0;
+ int cnt, ret;
+ u8 status;
+
+ di = to_ab8500_bm(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = di->charge_status;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ /*
+ * No support for reading the battery health, hence
+ * if battery presence is detected health is
+ * assumed to be good.
+ */
+ if (ab8500_bm_get_bat_resis(di) <= (NO_BAT_CONN - BAT_GAIN))
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ else
+ val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ if (ab8500_bm_get_bat_resis(di) <= (NO_BAT_CONN - BAT_GAIN))
+ val->intval = BAT_PRESENT;
+ else
+ val->intval = BAT_NOT_PRESENT;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ status = ab8500_bm_status(di);
+ if (status == AC_PW_CONN)
+ val->intval = POWER_SUPPLY_TYPE_MAINS;
+ else if (status == USB_PW_CONN)
+ val->intval = POWER_SUPPLY_TYPE_USB;
+ else
+ val->intval = POWER_SUPPLY_TYPE_BATTERY;
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ res = ab8500_bm_get_bat_resis(di);
+ val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
+ for (cnt = 0; cnt < SUPPORTED_BATT; cnt++) {
+ if ((res > (di->pdata->bat_type[cnt].resis - BAT_GAIN))
+ && (res < (di->pdata->bat_type[cnt].resis +
+ BAT_GAIN))) {
+ val->intval = di->pdata->bat_type[cnt].name;
+ break;
+ }
+ };
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_BATT_OVV,
+ &status);
+ if (ret < 0) {
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+ return ret;
+ }
+ if ((status | BATT_OVV_TH) == status)
+ val->intval = AB8500_BM_BATTOVV_4P75;
+ else
+ val->intval = AB8500_BM_BATTOVV_3P7;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ /* Voltage is in terms of uV */
+ val->intval = (di->voltage_uV * 1000);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = (di->inst_current * 1000);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ val->intval = (di->avg_current * 1000);
+ break;
+ case POWER_SUPPLY_PROP_ENERGY_NOW:
+ /*
+ * TODO: Need to calculate the present energy and update
+ * the same in uWh from gasguage driver
+ */
+ val->intval = 10000;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ /*
+ * Get the battery capacity from the gas guage
+ * if available else use the voltage based
+ * capacity
+ */
+ if (di->capacity > 0) {
+ val->intval = di->capacity;
+ break;
+ }
+ /* capacity based on voltage */
+ val->intval = ab8500_bm_get_bat_capacity(di);
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ /*
+ * Power supply framework specifies the temperature
+ * in tenths of degree Celsius
+ */
+ val->intval = (di->temp_C * 10);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * ab8500_bm_bk_battery_get_property() - get the backup battery properties
+ * @psy: pointer to the power_supply structure
+ * @psp: pointer to the power_supply_property structure
+ * @val: pointer to the power_supply_propval union
+ *
+ * This function is called when the an application tries to read the backup
+ * battery properties through the sysfs interface.
+ * The properties include status and voltage.
+ * status: charging/discharging/unknown/full
+ * voltage: backup battery voltage
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_bm_bk_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct ab8500_bm *di;
+
+ di = to_ab8500_bm_bk_battery_device_info(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = di->bk_battery_charge_status;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ /* Voltage is measured in terms of uV */
+ val->intval = (ab8500_bm_bk_battery_voltage(di) * 1000);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * ab8500_bm_ac_get_property() - get the ac/mains properties
+ * @psy: pointer to the power_supply structure
+ * @psp: pointer to the power_supply_property structure
+ * @val: pointer to the power_supply_propval union
+ *
+ * This function gets called when an application tries to get the ac/mains
+ * properties by reading the sysfs files.
+ * AC/Mains properties are online, present and voltage.
+ * online: ac/mains charging is in progress or not
+ * present: presence of the ac/mains
+ * voltage: AC/Mains voltage
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_bm_ac_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct ab8500_bm *di;
+ int status = 0;
+
+ di = to_ab8500_bm_ac_device_info(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ if (di->state_info.type == AB8500_CHARGER_DCIO &&
+ di->charge_status == POWER_SUPPLY_STATUS_CHARGING)
+ val->intval = AB8500_BM_CHARGING;
+ else
+ val->intval = AB8500_BM_NOT_CHARGING;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ status = ab8500_bm_charger_presence(di);
+ if (status & AC_PW_CONN)
+ val->intval = AB8500_BM_AC_PRESENT;
+ else
+ val->intval = AB8500_BM_AC_NOT_PRESENT;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ /* Voltage is measured in terms of uV */
+ val->intval = (ab8500_bm_ac_voltage(di) * 1000);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * ab8500_bm_usb_get_property() - get the usb properties
+ * @psy: pointer to the power_supply structure
+ * @psp: pointer to the power_supply_property structure
+ * @val: pointer to the power_supply_propval union
+ *
+ * This function gets called when an application tries to get the usb
+ * properties by reading the sysfs files.
+ * USB properties are online, present and voltage.
+ * online: usb charging is in progress or not
+ * present: presence of the usb
+ * voltage: usb vbus voltage
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_bm_usb_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct ab8500_bm *di;
+ int status = 0;
+
+ di = to_ab8500_bm_usb_device_info(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ status = ab8500_bm_charger_presence(di);
+ if (di->state_info.type == AB8500_CHARGER_USB &&
+ di->charge_status == POWER_SUPPLY_STATUS_CHARGING)
+ val->intval = AB8500_BM_CHARGING;
+ else
+ val->intval = AB8500_BM_NOT_CHARGING;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ status = ab8500_bm_charger_presence(di);
+ if (status & USB_PW_CONN)
+ val->intval = AB8500_BM_USB_PRESENT;
+ else
+ val->intval = AB8500_BM_USB_NOT_PRESENT;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ /* Voltage is measured in terms of uV */
+ val->intval = (ab8500_bm_usb_voltage(di) * 1000);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ab8500_bm_initiate_charging(struct ab8500_bm *di, int vset, int ich)
+{
+ int ret = 0;
+ switch (di->state_info.type) {
+
+ case AB8500_CHARGER_DCIO:
+ dev_dbg(di->dev,
+ "%s DCIO parameters Vset %d, Ich %d\n",
+ __func__, vset, ich);
+ ab8500_bm_usb_en(di, false);
+ ret = ab8500_bm_ac_en_w_v_i(di, true, vset, ich);
+ break;
+
+ case AB8500_CHARGER_USB:
+ dev_dbg(di->dev,
+ "%s VBUS parameters Vset %d, Ich_out %d, Ich_in %d\n",
+ __func__, vset, ich, di->usb_in_cur_lvl);
+ ab8500_bm_ac_en(di, false);
+ ret = ab8500_bm_usb_en_w_v_i(di, true, vset, ich);
+ break;
+
+ default:
+ dev_err(di->dev, "%s Unknown charger to charge from...%d %s\n",
+ __func__, di->state_info.type,
+ charge_source[di->state_info.type]);
+ break;
+ }
+
+ if (ret < 0) {
+ dev_dbg(di->dev,
+ "%s Initiating charging. Enabling charging failed\n",
+ __func__);
+ }
+ return ret;
+}
+
+static int ab8500_bm_check_charger_status(struct ab8500_bm *di)
+{
+ int charger_status;
+
+ charger_status = ab8500_bm_charger_presence(di);
+
+ if (charger_status != di->state_info.previous_connected_charger_status
+ || di->suspension_status.suspended_change) {
+ dev_dbg(di->dev,
+ "%s A change in the charger source was detected\n",
+ __func__);
+ /*
+ * Charger state changed or suspension
+ * has changed since last update
+ */
+ if ((charger_status & AC_PW_CONN) &&
+ !di->suspension_status.ac_suspended) {
+ dev_dbg(di->dev, "%s Charging source is DCIO\n",
+ __func__);
+ if (di->state_info.type != AB8500_CHARGER_DCIO) {
+ di->state_info.type = AB8500_CHARGER_DCIO;
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_NORMAL_INIT);
+ }
+ } else if ((charger_status & USB_PW_CONN) &&
+ !di->suspension_status.usb_suspended) {
+ dev_dbg(di->dev, "%s Charging source is USB\n",
+ __func__);
+ di->state_info.type = AB8500_CHARGER_USB;
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_NORMAL_INIT);
+ } else if (charger_status &&
+ (di->suspension_status.ac_suspended ||
+ di->suspension_status.usb_suspended)) {
+ dev_dbg(di->dev, "%s Charging is suspended\n",
+ __func__);
+ di->state_info.type = AB8500_CHARGER_OFF;
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_SUSPENDED_INIT);
+ } else {
+ dev_dbg(di->dev, "%s Charging source is OFF\n",
+ __func__);
+ di->state_info.type = AB8500_CHARGER_OFF;
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_HANDHELD_INIT);
+ }
+ di->state_info.previous_connected_charger_status =
+ charger_status;
+ di->suspension_status.suspended_change = false;
+ }
+ return charger_status;
+}
+static void ab8500_bm_check_btemp_range(struct ab8500_bm *di)
+{
+ if (di->temp_C > di->pdata->temp_low &&
+ di->temp_C < di->pdata->temp_high) {
+ /*All ok, charge normally */
+
+ switch (di->state_info.state) {
+ case AB8500_BM_CHARGER_TEMP_UNDEROVER:
+ case AB8500_BM_CHARGER_TEMP_LOWHIGH:
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_NORMAL_INIT);
+ break;
+ default:
+ break;
+ }
+ } else {
+ /* Check temp one more time */
+ di->temp_C = ab8500_bm_temperature(di);
+ if (((di->temp_C >= di->pdata->temp_high) &&
+ (di->temp_C < di->pdata->temp_over)) ||
+ ((di->temp_C > di->pdata->temp_under) &&
+ (di->temp_C <= di->pdata->temp_low))) {
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_TEMP_LOWHIGH_INIT);
+ } else if (di->temp_C <= di->pdata->temp_under ||
+ di->temp_C >= di->pdata->temp_over) {
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_TEMP_UNDEROVER_INIT);
+ }
+ }
+}
+
+/**
+ * ab8500_bm_charging_algorithm() - update battery status
+ * @di: pointer to the ab8500_bm structure
+ *
+ * This function is being called by the ab8500_bm_battery_work to update the
+ * battery status i.e charging/discharging/full/unknown.
+ * It also takes care of maintenance charging.
+ */
+static void ab8500_bm_charging_algorithm(struct ab8500_bm *di)
+{
+ int charger_status;
+
+ charger_status = ab8500_bm_check_charger_status(di);
+ /* First check if we have a charger connected */
+ if (!charger_status) {
+ if (di->state_info.state != AB8500_BM_CHARGER_HANDHELD)
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_HANDHELD_INIT);
+ }
+
+ /* Safety timer expiration */
+ else if (di->event_flags.safety_timer_expired) {
+ if (di->state_info.state !=
+ AB8500_BM_CHARGER_SAFETY_TIMER_EXPIRED)
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_SAFETY_TIMER_EXPIRED_INIT);
+ }
+ /*
+ * Check if any interrupts has occured
+ * that will prevent us from charging
+ */
+
+ /* Main charger not ok. */
+ else if (di->event_flags.mainextchnotok) {
+ if (di->state_info.state != AB8500_BM_CHARGER_OFF)
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_OFF_INIT);
+ }
+ /* VBUS or VBAT OVV. */
+ else if (di->event_flags.vbus_ovv || di->event_flags.batt_ovv) {
+ if (di->state_info.state != AB8500_BM_CHARGER_OVV_PROTECT)
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_OVV_PROTECT_INIT);
+ }
+ /* USB Thermal, stop charging */
+ else if (di->event_flags.main_thermal_prot ||
+ di->event_flags.usb_thermal_prot) {
+ if (di->state_info.state != AB8500_BM_CHARGER_HW_TEMP_PROTECT)
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_HW_TEMP_PROTECT_INIT);
+ }
+ /*
+ * USB charger not allowed.
+ * TODO: Add code for handling USB charger not OK interrupt
+ */
+ else if (di->event_flags.usbchargernotok)
+ dev_dbg(di->dev, "%s USB charger not OK\n", __func__);
+
+ /* Battery temp high/low */
+ else if (di->event_flags.btemp_low || di->event_flags.btemp_high) {
+ if (di->state_info.state != AB8500_BM_CHARGER_HW_TEMP_PROTECT)
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_HW_TEMP_PROTECT_INIT);
+ }
+ /*
+ * Battery removed.
+ * TODO How to handle this case?
+ */
+ else if (di->event_flags.batt_rem)
+ dev_dbg(di->dev, "%s Battery removed detected.\n", __func__);
+
+ /* Check temperature manually */
+ else
+ ab8500_bm_check_btemp_range(di);
+
+ dev_dbg(di->dev,
+ "%s Bt: [%d] Status is: [%d] State: [%s], Source: [%s]\n",
+ __func__,
+ di->temp_C,
+ di->charge_status,
+ states[di->state_info.state],
+ charge_source[di->state_info.type]);
+
+ /*
+ * Charging looks like this:
+ * Lower Vset with 50mV.
+ * After 60 hours, lower Vset again with 50mV.
+ * After 200 hours restart a full charging cycle.
+ */
+ switch (di->state_info.state) {
+ case AB8500_BM_CHARGER_SUSPENDED_INIT:
+ if (di->suspension_status.ac_suspended)
+ ab8500_bm_ac_en(di, false);
+ if (di->suspension_status.usb_suspended)
+ ab8500_bm_usb_en(di, false);
+ ab8500_bm_stop_safety_timer(di);
+ ab8500_bm_stop_maintenance_timer(di);
+ di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ di->maintenance_chg = false;
+ ab8500_bm_change_state_to(di, AB8500_BM_CHARGER_SUSPENDED);
+ /* Intentional fallthrough */
+
+ case AB8500_BM_CHARGER_SUSPENDED:
+ /* CHARGING is suspended */
+ break;
+
+ case AB8500_BM_CHARGER_HW_TEMP_PROTECT_INIT:
+ ab8500_bm_ac_en(di, false);
+ ab8500_bm_usb_en(di, false);
+ ab8500_bm_stop_safety_timer(di);
+ ab8500_bm_stop_maintenance_timer(di);
+ di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ di->maintenance_chg = false;
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_HW_TEMP_PROTECT);
+ /* Intentional fallthrough */
+
+ case AB8500_BM_CHARGER_HW_TEMP_PROTECT:
+ {
+ int ret;
+ u8 ch_stat = 0;
+ u8 main_ch_status2 = 0;
+ u8 usb_ch_status2 = 0;
+
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_CH_STAT_REG, &ch_stat);
+ if (ret < 0) {
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+ return;
+ }
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_CH_STATUS2_REG,
+ &main_ch_status2);
+ if (ret < 0) {
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+ return;
+ }
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG,
+ &usb_ch_status2);
+ if (ret < 0) {
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+ return;
+ }
+ if (!(ch_stat & CHARGING_STOP_BY_BTEMP) ||
+ !(main_ch_status2 & MAIN_CH_TH_PROT) ||
+ !(usb_ch_status2 & USB_CH_TH_PROT)) {
+ di->event_flags.btemp_low = false;
+ di->event_flags.btemp_high = false;
+ di->event_flags.main_thermal_prot = false;
+ di->event_flags.usb_thermal_prot = false;
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_NORMAL_INIT);
+ }
+
+ break;
+ }
+ case AB8500_BM_CHARGER_OVV_PROTECT_INIT:
+ ab8500_bm_ac_en(di, false);
+ ab8500_bm_usb_en(di, false);
+ ab8500_bm_stop_safety_timer(di);
+ ab8500_bm_stop_maintenance_timer(di);
+ di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ di->maintenance_chg = false;
+ ab8500_bm_change_state_to(di, AB8500_BM_CHARGER_OVV_PROTECT);
+ /* Intentional fallthrough */
+
+ case AB8500_BM_CHARGER_OVV_PROTECT:
+ {
+ int ret;
+ u8 ch_stat = 0;
+ u8 usb_ch_status2 = 0;
+
+ /* Check if VBUS or VBAT OVV is still active */
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_CH_STAT_REG, &ch_stat);
+ if (ret < 0) {
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+ return;
+ }
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG,
+ &usb_ch_status2);
+ if (ret < 0) {
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+ return;
+ }
+ if (!(ch_stat & BATT_OVV_TH) &&
+ !(usb_ch_status2 & VBUS_OVV_TH)) {
+ di->event_flags.vbus_ovv = false;
+ di->event_flags.batt_ovv = false;
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_NORMAL_INIT);
+ }
+
+ break;
+ }
+ case AB8500_BM_CHARGER_OFF_INIT:
+ ab8500_bm_ac_en(di, false);
+ ab8500_bm_stop_safety_timer(di);
+ ab8500_bm_stop_maintenance_timer(di);
+ di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ di->maintenance_chg = false;
+ ab8500_bm_change_state_to(di, AB8500_BM_CHARGER_OFF);
+ /* Intentional fallthrough */
+
+ case AB8500_BM_CHARGER_OFF:
+ {
+ int ret;
+ u8 ch_status2 = 0;
+
+ /* Check if MainChNOK is still active */
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_CH_STATUS2_REG, &ch_status2);
+ if (ret < 0) {
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+ return;
+ }
+ if (!(ch_status2 & MAIN_CH_NOK)) {
+ di->event_flags.mainextchnotok = false;
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_NORMAL_INIT);
+ }
+
+ break;
+ }
+
+ case AB8500_BM_CHARGER_SAFETY_TIMER_EXPIRED_INIT:
+ ab8500_bm_ac_en(di, false);
+ ab8500_bm_usb_en(di, false);
+ di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ di->maintenance_chg = false;
+ ab8500_bm_stop_safety_timer(di);
+ ab8500_bm_stop_maintenance_timer(di);
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_SAFETY_TIMER_EXPIRED);
+ /* Intentional fallthrough */
+
+ case AB8500_BM_CHARGER_SAFETY_TIMER_EXPIRED:
+ {
+ break;
+ }
+
+ case AB8500_BM_CHARGER_NORMAL_INIT:
+ /*
+ * This state will be used when the 200h
+ * maintenance charging state times out.
+ * Vset needs to be reset to 4200mV.
+ */
+ (void) ab8500_bm_initiate_charging(di,
+ di->pdata->bat_type[0].normal_ip_vol_lvl,
+ di->pdata->bat_type[0].normal_op_cur_lvl);
+ ab8500_bm_change_state_to(di, AB8500_BM_CHARGER_NORMAL);
+ ab8500_bm_start_safety_timer(di);
+ ab8500_bm_stop_maintenance_timer(di);
+ di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
+ di->eoc_cond_counter = 0;
+ di->maintenance_chg = false;
+
+ break;
+
+ case AB8500_BM_CHARGER_NORMAL:
+ /*
+ * No need to turn on charging here.
+ * This is done in the function handling the charger
+ * connect event.. We just wait until
+ * ab8500_bm_battery_read_status() reports that
+ * the battery is full.
+ */
+ if (di->charge_status == POWER_SUPPLY_STATUS_FULL &&
+ di->maintenance_chg) {
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_MAINTENANCE_A_INIT);
+ }
+
+ break;
+
+ case AB8500_BM_CHARGER_MAINTENANCE_A_INIT:
+ dev_dbg(di->dev, "%s Maintenance A %dh charging, Vset = %d\n",
+ __func__,
+ di->pdata->bat_type[0].maint_a_chg_timer_h,
+ ab8500_regval2voltage(
+ di->pdata->bat_type[0].maint_a_ip_vol_lvl));
+ ab8500_bm_stop_safety_timer(di);
+ ab8500_bm_start_maintenance_timer(di,
+ di->pdata->bat_type[0].maint_a_chg_timer_h);
+ (void) ab8500_bm_initiate_charging(di,
+ di->pdata->bat_type[0].maint_a_ip_vol_lvl,
+ di->pdata->bat_type[0].maint_a_op_cur_lvl);
+ ab8500_bm_change_state_to(di, AB8500_BM_CHARGER_MAINTENANCE_A);
+ /* Intentional fallthrough*/
+
+ case AB8500_BM_CHARGER_MAINTENANCE_A:
+ if (di->event_flags.maintenance_timer_expired) {
+ ab8500_bm_stop_maintenance_timer(di);
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_MAINTENANCE_B_INIT);
+ }
+ break;
+
+ case AB8500_BM_CHARGER_MAINTENANCE_B_INIT:
+ dev_dbg(di->dev, "%s Maintenance B %dh charging, Vset = %d\n",
+ __func__,
+ di->pdata->bat_type[0].maint_b_chg_timer_h,
+ ab8500_regval2voltage(
+ di->pdata->bat_type[0].maint_b_ip_vol_lvl));
+ ab8500_bm_start_maintenance_timer(di,
+ di->pdata->bat_type[0].maint_b_chg_timer_h);
+ (void) ab8500_bm_initiate_charging(di,
+ di->pdata->bat_type[0].maint_b_ip_vol_lvl,
+ di->pdata->bat_type[0].maint_b_op_cur_lvl);
+ ab8500_bm_change_state_to(di, AB8500_BM_CHARGER_MAINTENANCE_B);
+ /* Intentional fallthrough*/
+
+ case AB8500_BM_CHARGER_MAINTENANCE_B:
+ if (di->event_flags.maintenance_timer_expired) {
+ ab8500_bm_stop_maintenance_timer(di);
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_NORMAL_INIT);
+ }
+ break;
+
+ case AB8500_BM_CHARGER_SAFE:
+ /* TODO: To use with unknown batteries or something? */
+ break;
+
+ case AB8500_BM_CHARGER_TEMP_LOWHIGH_INIT:
+ (void) ab8500_bm_initiate_charging(di,
+ di->pdata->bat_type[0].low_high_ip_vol_lvl,
+ di->pdata->bat_type[0].low_high_op_cur_lvl);
+ ab8500_bm_stop_maintenance_timer(di);
+ di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
+ ab8500_bm_change_state_to(di, AB8500_BM_CHARGER_TEMP_LOWHIGH);
+ /* Intentional fallthrough */
+
+ case AB8500_BM_CHARGER_TEMP_LOWHIGH:
+ /*
+ * We are here because of that the temperature
+ * is between xll and xlh degrees celsius.
+ * In this mode charging in beeing performed
+ * but with a reduced Ibat (current into the battery.
+ */
+ break;
+
+ case AB8500_BM_CHARGER_TEMP_UNDEROVER_INIT:
+ ab8500_bm_ac_en(di, false);
+ ab8500_bm_usb_en(di, false);
+ ab8500_bm_stop_safety_timer(di);
+ ab8500_bm_stop_maintenance_timer(di);
+ di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ di->maintenance_chg = false;
+ ab8500_bm_change_state_to(di,
+ AB8500_BM_CHARGER_TEMP_UNDEROVER);
+ /* Intentional fallthrough */
+
+ case AB8500_BM_CHARGER_TEMP_UNDEROVER:
+ /*
+ * We are here because of that the temperature is
+ * under the minimum temperature that is allowed for charging.
+ * No charging is performed here until the temperature
+ * is up to a allowed level.
+ */
+ break;
+
+ case AB8500_BM_CHARGER_HANDHELD_INIT:
+ /*
+ * This is the state when no charger is connected,
+ * the unit is beeing "handheld" without
+ * DCIO nor USB charger connected.
+ */
+ ab8500_bm_ac_en(di, false);
+ ab8500_bm_usb_en(di, false);
+ ab8500_bm_stop_safety_timer(di);
+ ab8500_bm_stop_maintenance_timer(di);
+ di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+ di->maintenance_chg = false;
+ ab8500_bm_change_state_to(di, AB8500_BM_CHARGER_HANDHELD);
+ /* Intentional fallthrough */
+
+ case AB8500_BM_CHARGER_HANDHELD:
+ break;
+ }
+
+ ab8500_bm_battery_read_status(di);
+}
+
+#if defined(CONFIG_PM)
+static int ab8500_bm_resume(struct platform_device *pdev)
+{
+ struct ab8500_bm *di = platform_get_drvdata(pdev);
+
+ queue_delayed_work(di->ab8500_bm_wq, &di->ab8500_bm_monitor_work, 0);
+ return 0;
+}
+
+static int ab8500_bm_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ab8500_bm *di = platform_get_drvdata(pdev);
+
+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
+ cancel_delayed_work(&di->ab8500_bm_monitor_work);
+ return 0;
+}
+#else
+#define ab8500_bm_suspend NULL
+#define ab8500_bm_resume NULL
+#endif
+
+static int __devexit ab8500_bm_remove(struct platform_device *pdev)
+{
+ struct ab8500_bm *di = platform_get_drvdata(pdev);
+ int ret = 0, cnt, irq;
+
+ /* Backup battery voltage and current disable */
+ abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, 0);
+ if (ret < 0)
+ dev_err(di->dev, "%s mask and set failed\n", __func__);
+
+ /* Disable coulomb counter */
+ ret = ab8500_bm_cc_enable(di, false);
+ if (ret)
+ dev_err(&pdev->dev, "failed to disable coulomb counter\n");
+
+ /* Disable AC charging */
+ ret = ab8500_bm_ac_en(di, false);
+ if (ret)
+ dev_err(&pdev->dev, "failed to disable AC charging\n");
+
+ /* Disable USB charging */
+ ret = ab8500_bm_usb_en(di, false);
+ if (ret)
+ dev_err(&pdev->dev, "failed to disable USB charging\n");
+
+ /* Disable interrupts */
+ for (cnt = 0; cnt < ARRAY_SIZE(ab8500_bm_irq); cnt++) {
+ irq = platform_get_irq_byname(pdev, ab8500_bm_irq[cnt].name);
+ free_irq(irq, di);
+ }
+
+ /* sysfs interface to enable/disbale charging from user space */
+ ab8500_bm_sysfs_exit(di);
+
+ /* Delete the work queue */
+ destroy_workqueue(di->ab8500_bm_wq);
+ destroy_workqueue(di->ab8500_bm_wd_kick_wq);
+ destroy_workqueue(di->ab8500_bm_irq_wq);
+
+ flush_scheduled_work();
+ power_supply_unregister(&di->ac);
+ power_supply_unregister(&di->usb);
+ power_supply_unregister(&di->bat);
+ platform_set_drvdata(pdev, NULL);
+ kfree(di);
+
+ return ret;
+}
+
+/**
+ * ab8500_bm_external_power_changed() - external_power_changed
+ * @psy: pointer to the structure power_supply
+ *
+ * This function is pointing to the function pointer external_power_changed
+ * of the structure power_supply.
+ * This function gets executed when there is a chage in the external power
+ * supply to tbe battery. It cancels the pending monitor work and starts
+ * the monitor work so as to include the changed power supply parameters.
+ */
+static void ab8500_bm_external_power_changed(struct power_supply *psy)
+{
+ struct ab8500_bm *di = to_ab8500_bm(psy);
+
+ cancel_delayed_work(&di->ab8500_bm_monitor_work);
+ queue_delayed_work(di->ab8500_bm_wq, &di->ab8500_bm_monitor_work, 0);
+}
+
+static int __devinit ab8500_bm_probe(struct platform_device *pdev)
+{
+ int irq = 0, cnt = 0, ret = 0;
+
+ struct ab8500_platform_data *plat;
+ ab8500_bm_di = kzalloc(sizeof(struct ab8500_bm), GFP_KERNEL);
+ if (!ab8500_bm_di)
+ return -ENOMEM;
+ /* get parent data */
+ ab8500_bm_di->dev = &pdev->dev;
+ ab8500_bm_di->parent = dev_get_drvdata(pdev->dev.parent);
+
+ plat = dev_get_platdata(ab8500_bm_di->parent->dev);
+
+ /* initialize lock */
+ spin_lock_init(&ab8500_bm_di->ab8500_bm_lock);
+
+ /* get battery specific platform data */
+ if (!plat->battery) {
+ dev_err(&pdev->dev, "no battery platform data supplied\n");
+ return -EINVAL;
+ }
+ ab8500_bm_di->pdata = plat->battery;
+
+ ab8500_bm_di->maintenance_chg = false;
+ ab8500_bm_di->suspension_status.suspended_change = true;
+ ab8500_bm_di->suspension_status.ac_suspended = false;
+ ab8500_bm_di->suspension_status.usb_suspended = false;
+ /* Main Battery */
+ ab8500_bm_di->bat.name = "ab8500_bm_battery";
+ ab8500_bm_di->bat.supplied_to = ab8500_bm_supplied_to;
+ ab8500_bm_di->bat.num_supplicants =
+ ARRAY_SIZE(ab8500_bm_supplied_to);
+ ab8500_bm_di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+ ab8500_bm_di->bat.properties = ab8500_bm_battery_props;
+ ab8500_bm_di->bat.num_properties =
+ ARRAY_SIZE(ab8500_bm_battery_props);
+ ab8500_bm_di->bat.get_property = ab8500_bm_get_battery_property;
+ ab8500_bm_di->bat.external_power_changed =
+ ab8500_bm_external_power_changed;
+ ab8500_bm_di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
+ ab8500_bm_di->samples = CC_SAMPLES_40;
+ ab8500_bm_di->capacity = 0;
+ ab8500_bm_di->old_avg_current = 0;
+
+ /* Backup Battery */
+ ab8500_bm_di->bk_bat.name = "ab8500_backup_battery";
+ ab8500_bm_di->bk_bat.type = POWER_SUPPLY_TYPE_BATTERY;
+ ab8500_bm_di->bk_bat.properties = ab8500_bm_bk_battery_props;
+ ab8500_bm_di->bk_bat.num_properties =
+ ARRAY_SIZE(ab8500_bm_bk_battery_props);
+ ab8500_bm_di->bk_bat.get_property = ab8500_bm_bk_battery_get_property;
+ ab8500_bm_di->bk_bat.external_power_changed = NULL;
+ ab8500_bm_di->bk_battery_charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
+
+ /* AC supply */
+ ab8500_bm_di->ac.name = "ab8500_ac";
+ ab8500_bm_di->ac.type = POWER_SUPPLY_TYPE_MAINS;
+ ab8500_bm_di->ac.properties = ab8500_bm_ac_props;
+ ab8500_bm_di->ac.num_properties = ARRAY_SIZE(ab8500_bm_ac_props);
+ ab8500_bm_di->ac.get_property = ab8500_bm_ac_get_property;
+ ab8500_bm_di->ac.external_power_changed = NULL;
+
+ /* USB supply */
+ ab8500_bm_di->usb.name = "ab8500_usb";
+ ab8500_bm_di->usb.type = POWER_SUPPLY_TYPE_USB;
+ ab8500_bm_di->usb.properties = ab8500_bm_usb_props;
+ ab8500_bm_di->usb.num_properties = ARRAY_SIZE(ab8500_bm_usb_props);
+ ab8500_bm_di->usb.get_property = ab8500_bm_usb_get_property;
+ ab8500_bm_di->usb.external_power_changed = NULL;
+
+ /* Event flag handling */
+ ab8500_bm_di->event_flags.mainextchnotok = false;
+ ab8500_bm_di->event_flags.batt_ovv = false;
+ ab8500_bm_di->event_flags.batt_rem = false;
+ ab8500_bm_di->event_flags.btemp_high = false;
+ ab8500_bm_di->event_flags.btemp_medhigh = false;
+ ab8500_bm_di->event_flags.btemp_medlow = false;
+ ab8500_bm_di->event_flags.btemp_low = false;
+ ab8500_bm_di->event_flags.main_thermal_prot = false;
+ ab8500_bm_di->event_flags.usb_thermal_prot = false;
+ ab8500_bm_di->event_flags.vbus_ovv = false;
+ ab8500_bm_di->event_flags.usbchargernotok = false;
+ ab8500_bm_di->event_flags.safety_timer_expired = false;
+ ab8500_bm_di->event_flags.maintenance_timer_expired = false;
+
+ ab8500_bm_di->state_info.connected_charger_status = 0;
+ ab8500_bm_di->state_info.previous_connected_charger_status = -1;
+ ab8500_bm_di->state_info.type = 0;
+
+ /* Initilialize safety timer */
+ init_timer(&ab8500_bm_di->safety_timer);
+ ab8500_bm_di->safety_timer.function = ab8500_bm_safety_timer_expired;
+ ab8500_bm_di->safety_timer.data = (unsigned long) ab8500_bm_di;
+
+ /* Initilialize maintenance timer */
+ init_timer(&ab8500_bm_di->maintenance_timer);
+ ab8500_bm_di->maintenance_timer.function =
+ ab8500_bm_maintenance_timer_expired;
+ ab8500_bm_di->maintenance_timer.data = (unsigned long) ab8500_bm_di;
+
+ /* Create a work queue for monitoring the battery */
+ ab8500_bm_di->ab8500_bm_wq =
+ create_singlethread_workqueue("ab8500_bm_wq");
+ if (ab8500_bm_di->ab8500_bm_wq == NULL) {
+ dev_err(&pdev->dev, "failed to create work queue\n");
+ goto free_device_info;
+ }
+
+ /* Create a work queue for en/dis AC/USB from irq handler */
+ ab8500_bm_di->ab8500_bm_irq_wq =
+ create_singlethread_workqueue("ab8500_bm_irq");
+ if (ab8500_bm_di->ab8500_bm_irq_wq == NULL) {
+ dev_err(&pdev->dev, "failed to create work queue\n");
+ goto free_bm_wq;
+ }
+
+ /* Create a work queue for rekicking the watchdog */
+ ab8500_bm_di->ab8500_bm_wd_kick_wq =
+ create_singlethread_workqueue("ab8500_bm_wd_kick_wq");
+ if (ab8500_bm_di->ab8500_bm_wd_kick_wq == NULL) {
+ dev_err(&pdev->dev, "failed to create work queue\n");
+ goto free_bm_irq_wq;
+ }
+
+ /* Work Queue to re-kick the charging watchdog */
+ INIT_DELAYED_WORK_DEFERRABLE(&ab8500_bm_di->ab8500_bm_watchdog_work,
+ ab8500_bm_watchdog_kick_work);
+
+ /* Monitor Main Battery */
+ INIT_DELAYED_WORK_DEFERRABLE(&ab8500_bm_di->ab8500_bm_monitor_work,
+ ab8500_bm_battery_work);
+
+ /* Forced battery monitor work. */
+ INIT_WORK(&ab8500_bm_di->ab8500_bm_instant_monitor_work,
+ ab8500_bm_battery_inst_work);
+
+ /* Init work for enable/desable AC/USB charge */
+ INIT_WORK(&ab8500_bm_di->ab8500_bm_ac_plug_monitor_work,
+ ab8500_bm_ac_plug_work);
+ INIT_WORK(&ab8500_bm_di->ab8500_bm_ac_unplug_monitor_work,
+ ab8500_bm_ac_unplug_work);
+ INIT_WORK(&ab8500_bm_di->ab8500_bm_usb_en_monitor_work,
+ ab8500_bm_usb_en_work);
+ INIT_WORK(&ab8500_bm_di->ab8500_bm_usb_dis_monitor_work,
+ ab8500_bm_usb_dis_work);
+
+ /* Init work for getting the battery average current */
+ INIT_WORK(&ab8500_bm_di->ab8500_bm_avg_cur_monitor_work,
+ ab8500_bm_avg_cur_work);
+
+ /* Init work to handle usb state changed event from USB stack */
+ INIT_WORK(&ab8500_bm_di->ab8500_bm_usb_state_changed_monitor_work,
+ ab8500_bm_usb_state_changed_work);
+
+ /* Init work to handle USB type detection after VBUS rising */
+ INIT_WORK(&ab8500_bm_di->ab8500_bm_detect_usb_type_monitor_work,
+ ab8500_bm_detect_usb_type_work);
+
+ /*
+ * Init completion to get notified when USB negotiations are
+ * done for a standard host
+ */
+ init_completion(&ab8500_bm_di->ab8500_bm_usb_completed);
+
+ /* Enable coulomb counter */
+ ret = ab8500_bm_cc_enable(ab8500_bm_di, true);
+ if (ret)
+ dev_err(&pdev->dev, "failed to enable coulomb counter\n");
+
+ /* Register main battery */
+ ret = power_supply_register(&pdev->dev, &ab8500_bm_di->bat);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register main battery\n");
+ goto free_bm_wd_kick_wq;
+ }
+
+ /* Monitor Main Battery */
+ queue_delayed_work(ab8500_bm_di->ab8500_bm_wq,
+ &ab8500_bm_di->ab8500_bm_monitor_work, 0);
+ /* Register AC charger class */
+ ret = power_supply_register(&pdev->dev, &ab8500_bm_di->ac);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register AC charger\n");
+ goto batt_fail;
+ }
+
+ /* Register USB charger class */
+ ret = power_supply_register(&pdev->dev, &ab8500_bm_di->usb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register USB charger\n");
+ goto ac_fail;
+ }
+
+ /* Get Chip ID of the ABB ASIC */
+ ret = abx500_get_chip_id(ab8500_bm_di->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get chip ID\n");
+ goto ac_fail;
+ }
+
+ ab8500_bm_di->cid = ret;
+ dev_dbg(&pdev->dev, "AB8500 CID is: 0x%02x\n",
+ ab8500_bm_di->cid);
+
+ switch (ab8500_bm_di->cid) {
+ case AB8500_CUT1P0:
+ case AB8500_CUT1P1:
+ break;
+ case AB8500_CUT2P0:
+
+ ret = abx500_set_register_interruptible(ab8500_bm_di->dev,
+ AB8500_CHARGER,
+ AB8500_CH_VOLT_LVL_MAX_REG, CH_VOL_LVL_4P6);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to set CH_VOLT_LVL_MAX_REG\n");
+ goto ac_fail;
+ }
+
+ ret = abx500_set_register_interruptible(ab8500_bm_di->dev,
+ AB8500_CHARGER,
+ AB8500_CH_OPT_CRNTLVL_MAX_REG, CH_OP_CUR_LVL_1P6);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to set CH_OPT_CRNTLVL_MAX_REG\n");
+ goto ac_fail;
+ }
+
+ break;
+ default:
+ goto ac_fail;
+ }
+
+ /* Set initial values */
+
+ /*
+ * BattOVV threshold can take values 3.7 or 4.75
+ * if set to 3.7 charging can be done upto 3.5v
+ * whereas Li-Ion charges of capacity 3.7v charges
+ * upto 4.2v hence
+ * BattOVV threshold = 4.75v
+ */
+ ret = abx500_set_register_interruptible(ab8500_bm_di->dev,
+ AB8500_CHARGER,
+ AB8500_BATT_OVV,
+ (BATT_OVV_ENA | BATT_OVV_TH_4P75));
+ if (ret) {
+ dev_err(&pdev->dev, "failed to set BATT_OVV\n");
+ goto ac_fail;
+ }
+ /*
+ * VBUS OVV set to 6.3V
+ */
+ ret = abx500_set_register_interruptible(ab8500_bm_di->dev,
+ AB8500_CHARGER,
+ AB8500_USBCH_CTRL2_REG, 0x78);
+ if (ret) {
+ dev_err(&pdev->dev, "%s write failed\n", __func__);
+ goto ac_fail;
+ }
+
+ /* Enable main watchdog in OTP */
+ ret = abx500_set_register_interruptible(ab8500_bm_di->dev,
+ AB8500_OTP_EMUL, AB8500_OTP_CONF_15, OTP_ENABLE_WD);
+ if (ret) {
+ dev_err(ab8500_bm_di->dev, "%s write failed\n", __func__);
+ goto ac_fail;
+ }
+
+ /* Low Battery Voltage = 3.1v */
+ ret = abx500_set_register_interruptible(ab8500_bm_di->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_LOW_BAT_REG, LOW_BAT_3P1V | LOW_BAT_ENABLE);
+ if (ret) {
+ dev_err(ab8500_bm_di->dev, "%s write failed\n", __func__);
+ goto ac_fail;
+ }
+
+ /* Backup battery voltage and current */
+ ret = abx500_set_register_interruptible(ab8500_bm_di->dev,
+ AB8500_RTC,
+ AB8500_RTC_BACKUP_CHG_REG,
+ ab8500_bm_di->pdata->bkup_bat_v |
+ ab8500_bm_di->pdata->bkup_bat_i);
+ if (ret) {
+ dev_err(ab8500_bm_di->dev, "%s write failed\n", __func__);
+ goto ac_fail;
+ }
+
+ abx500_mask_and_set_register_interruptible(ab8500_bm_di->dev,
+ AB8500_RTC, AB8500_RTC_CTRL_REG,
+ RTC_BUP_CH_ENA, RTC_BUP_CH_ENA);
+ if (ret < 0)
+ dev_err(ab8500_bm_di->dev, "%s mask and set failed\n",
+ __func__);
+
+ ab8500_bm_di->bk_battery_charge_status = POWER_SUPPLY_STATUS_CHARGING;
+
+ /* Register interrupts */
+ for (cnt = 0; cnt < ARRAY_SIZE(ab8500_bm_irq); cnt++) {
+ irq = platform_get_irq_byname(pdev, ab8500_bm_irq[cnt].name);
+ ret = request_threaded_irq(irq, NULL, ab8500_bm_irq[cnt].isr,
+ IRQF_SHARED, ab8500_bm_irq[cnt].name, ab8500_bm_di);
+
+ if (ret != 0) {
+ dev_err(&pdev->dev, "failed to request %s IRQ %d: %d\n"
+ , ab8500_bm_irq[cnt].name, irq, ret);
+ goto usb_fail;
+ }
+ dev_dbg(&pdev->dev, "Requested %s IRQ %d: %d\n"
+ , ab8500_bm_irq[cnt].name, irq, ret);
+ }
+
+ /* sysfs interface to enable/disbale charging from user space */
+ ret = ab8500_bm_sysfs_init(ab8500_bm_di);
+ if (ret)
+ dev_err(ab8500_bm_di->dev, "failed to create sysfs entry\n");
+ /*
+ * USB driver will send the current to be drawn incase of shandard host
+ * device, hence passing di to ab8500, which can later be used by the
+ * usb driver while calling an API in battery driver.
+ */
+ ab8500_bm_di->parent->battery = ab8500_bm_di;
+
+ queue_delayed_work(ab8500_bm_di->ab8500_bm_wd_kick_wq,
+ &ab8500_bm_di->ab8500_bm_watchdog_work, CHG_WD_INTERVAL);
+
+ return ret;
+
+usb_fail:
+ power_supply_unregister(&ab8500_bm_di->usb);
+ /* We also have to free all successfully registered irqs */
+ for ( ; cnt <= 0; cnt++) {
+ irq = platform_get_irq_byname(pdev, ab8500_bm_irq[cnt].name);
+ free_irq(irq, ab8500_bm_di);
+ }
+ ret = ab8500_bm_ac_en(ab8500_bm_di, false);
+ if (ret)
+ dev_err(&pdev->dev, "failed to disable AC charging\n");
+ ret = ab8500_bm_usb_en(ab8500_bm_di, false);
+ if (ret)
+ dev_err(&pdev->dev, "failed to disable USB charging\n");
+ac_fail:
+ power_supply_unregister(&ab8500_bm_di->ac);
+batt_fail:
+ power_supply_unregister(&ab8500_bm_di->bat);
+free_bm_wd_kick_wq:
+ destroy_workqueue(ab8500_bm_di->ab8500_bm_wd_kick_wq);
+free_bm_irq_wq:
+ destroy_workqueue(ab8500_bm_di->ab8500_bm_irq_wq);
+free_bm_wq:
+ destroy_workqueue(ab8500_bm_di->ab8500_bm_wq);
+free_device_info:
+ kfree(ab8500_bm_di);
+
+ return ret;
+}
+
+static struct platform_driver ab8500_bm_driver = {
+ .probe = ab8500_bm_probe,
+ .remove = __devexit_p(ab8500_bm_remove),
+ .suspend = ab8500_bm_suspend,
+ .resume = ab8500_bm_resume,
+ .driver = {
+ .name = "ab8500-bm",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ab8500_bm_init(void)
+{
+ return platform_driver_register(&ab8500_bm_driver);
+}
+
+static void __exit ab8500_bm_exit(void)
+{
+ platform_driver_unregister(&ab8500_bm_driver);
+}
+
+subsys_initcall(ab8500_bm_init);
+module_exit(ab8500_bm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Arun R Murthy");
+MODULE_AUTHOR("Johan Palsson");
+MODULE_AUTHOR("Karl Komierowski");
+MODULE_ALIAS("platform:ab8500-bm");
+MODULE_DESCRIPTION("AB8500 battery management driver");
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 04f2e085116..33a702b4bba 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -64,6 +64,14 @@ config REGULATOR_USERSPACE_CONSUMER
If unsure, say no.
+config REGULATOR_AB8500
+ bool "ST-Ericsson AB8500 Power Regulators"
+ depends on AB8500_CORE
+ default y if AB8500_CORE
+ help
+ This driver supports the regulators found on the ST-Ericsson mixed
+ signal AB8500 PMIC
+
config REGULATOR_BQ24022
tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC"
help
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 4e7feece22d..0b18070d376 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
+obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_DUMMY) += dummy.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index 11790990277..b349266a43d 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -634,12 +634,9 @@ static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
"%s: failed to register regulator %s err %d\n",
__func__, ab3100_regulator_desc[i].name,
err);
- i--;
/* remove the already registered regulators */
- while (i > 0) {
+ while (--i >= 0)
regulator_unregister(ab3100_regulators[i].rdev);
- i--;
- }
return err;
}
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
new file mode 100644
index 00000000000..00702a65dd3
--- /dev/null
+++ b/drivers/regulator/ab8500.c
@@ -0,0 +1,750 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * AB8500 peripheral regulators
+ *
+ * AB8500 supports the following regulators:
+ * VAUX1/2/3, VINTCORE, VTVOUT, VUSB, VAUDIO, VANAMIC1/2, VDIGMIC, VANA
+ *
+ * For DB8500 cut 1.0 and previous versions of the silicon, all accesses
+ * to registers are done through the DB8500 SPI. Reading registers in bank 4
+ * does not work so special operations are used in this case. In cut 1.1
+ * onwards, these accesses are done through the DB8500 PRCMU I2C.
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/ab8500.h>
+
+/* Used only for detecting old u8500v10 hardware */
+#include <mach/hardware.h>
+
+/**
+ * struct ab8500_regulator_info - ab8500 regulator information
+ * @dev: device pointer
+ * @desc: regulator description
+ * @regulator_dev: regulator device
+ * @max_uV: maximum voltage (for variable voltage supplies)
+ * @min_uV: minimum voltage (for variable voltage supplies)
+ * @fixed_uV: typical voltage (for fixed voltage supplies)
+ * @update_bank: register bank to control on/off
+ * @update_reg: register to control on/off
+ * @mask: mask to enable/disable regulator
+ * @enable: bits to enable the regulator in normal(high power) mode
+ * @voltage_bank: register bank to control regulator voltage
+ * @voltage_reg: register to control regulator voltage
+ * @voltage_mask: mask to control regulator voltage
+ * @supported_voltages: supported voltage table
+ * @voltages_len: number of supported voltages for the regulator
+ * @delay: startup delay in ms
+ * @is_enabled: status of the regulator (only used with v10 ops)
+ * @voltage_regval: status of the voltage register (only used with v10 ops)
+ */
+struct ab8500_regulator_info {
+ struct device *dev;
+ struct regulator_desc desc;
+ struct regulator_dev *regulator;
+ int max_uV;
+ int min_uV;
+ int fixed_uV;
+ int update_bank;
+ int update_reg;
+ int mask;
+ int enable;
+ int voltage_bank;
+ int voltage_reg;
+ int voltage_mask;
+ int const *supported_voltages;
+ int voltages_len;
+ unsigned int delay;
+ bool is_enabled;
+ int voltage_regval;
+};
+
+/* voltage tables for the vauxn/vintcore supplies */
+static const int ldo_vauxn_voltages[] = {
+ 1100000,
+ 1200000,
+ 1300000,
+ 1400000,
+ 1500000,
+ 1800000,
+ 1850000,
+ 1900000,
+ 2500000,
+ 2650000,
+ 2700000,
+ 2750000,
+ 2800000,
+ 2900000,
+ 3000000,
+ 3300000,
+};
+
+static const int ldo_vaux3_voltages[] = {
+ 1200000,
+ 1500000,
+ 1800000,
+ 2100000,
+ 2500000,
+ 2750000,
+ 2790000,
+ 2910000,
+};
+
+static const int ldo_vintcore_voltages[] = {
+ 1200000,
+ 1225000,
+ 1250000,
+ 1275000,
+ 1300000,
+ 1325000,
+ 1350000,
+};
+
+static int ab8500_regulator_enable(struct regulator_dev *rdev)
+{
+ int regulator_id, ret;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ ret = abx500_mask_and_set_register_interruptible(info->dev,
+ info->update_bank, info->update_reg,
+ info->mask, info->enable);
+ if (ret < 0)
+ dev_err(rdev_get_dev(rdev),
+ "couldn't set enable bits for regulator\n");
+
+ msleep(info->delay);
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-enable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->update_bank, info->update_reg,
+ info->mask, info->enable);
+
+ return ret;
+}
+
+static int ab8500_regulator_disable(struct regulator_dev *rdev)
+{
+ int regulator_id, ret;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ ret = abx500_mask_and_set_register_interruptible(info->dev,
+ info->update_bank, info->update_reg,
+ info->mask, 0x0);
+ if (ret < 0)
+ dev_err(rdev_get_dev(rdev),
+ "couldn't set disable bits for regulator\n");
+
+ msleep(info->delay);
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-disable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->update_bank, info->update_reg,
+ info->mask, 0x0);
+
+ return ret;
+}
+
+static int ab8500_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ int regulator_id, ret;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ u8 regval;
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ ret = abx500_get_register_interruptible(info->dev,
+ info->update_bank, info->update_reg, &regval);
+
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't read 0x%x register\n", info->update_reg);
+ return ret;
+ }
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-is_enabled (bank, reg, mask, value): 0x%x, 0x%x, 0x%x,"
+ " 0x%x\n",
+ info->desc.name, info->update_bank, info->update_reg,
+ info->mask, regval);
+
+ if (regval & info->mask)
+ return true;
+ else
+ return false;
+}
+
+static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+ int regulator_id;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ /* return the uV for the fixed regulators */
+ if (info->fixed_uV)
+ return info->fixed_uV;
+
+ if (selector > info->voltages_len)
+ return -EINVAL;
+
+ return info->supported_voltages[selector];
+}
+
+static int ab8500_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ int regulator_id, ret, val;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ u8 regval;
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ ret = abx500_get_register_interruptible(info->dev,
+ info->voltage_bank, info->voltage_reg, &regval);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't read voltage reg for regulator\n");
+ return ret;
+ }
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-get_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x,"
+ " 0x%x\n",
+ info->desc.name, info->voltage_bank, info->voltage_reg,
+ info->voltage_mask, regval);
+
+ /* vintcore has a different layout */
+ val = regval & info->voltage_mask;
+ if (regulator_id == AB8500_LDO_INTCORE)
+ ret = info->supported_voltages[val >> 0x3];
+ else
+ ret = info->supported_voltages[val];
+
+ return ret;
+}
+
+static int ab8500_get_best_voltage_index(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int i;
+
+ /* check the supported voltage */
+ for (i = 0; i < info->voltages_len; i++) {
+ if ((info->supported_voltages[i] >= min_uV) &&
+ (info->supported_voltages[i] <= max_uV))
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int ab8500_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int regulator_id, ret;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ u8 regval;
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ /* get the appropriate voltages within the range */
+ ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't get best voltage for regulator\n");
+ return ret;
+ }
+
+ /* set the registers for the request */
+ regval = (u8)ret;
+ ret = abx500_mask_and_set_register_interruptible(info->dev,
+ info->voltage_bank, info->voltage_reg,
+ info->voltage_mask, regval);
+ if (ret < 0)
+ dev_err(rdev_get_dev(rdev),
+ "couldn't set voltage reg for regulator\n");
+
+ msleep(info->delay);
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-set_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x,"
+ " 0x%x\n",
+ info->desc.name, info->voltage_bank, info->voltage_reg,
+ info->voltage_mask, regval);
+
+ return ret;
+}
+
+static struct ab8500_regulator_info ab8500_regulator_info[];
+
+static int ab8500_v10_regulator_enable(struct regulator_dev *rdev)
+{
+ int regulator_id, ret;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int val;
+
+ regulator_id = rdev_get_id(rdev);
+ switch (regulator_id) {
+ case AB8500_LDO_AUX1:
+ info->is_enabled = true;
+ val = info->enable;
+ if (ab8500_regulator_info[AB8500_LDO_AUX2].is_enabled == true)
+ val |= ab8500_regulator_info[AB8500_LDO_AUX2].enable;
+ break;
+ case AB8500_LDO_AUX2:
+ info->is_enabled = true;
+ val = info->enable;
+ if (ab8500_regulator_info[AB8500_LDO_AUX1].is_enabled == true)
+ val |= ab8500_regulator_info[AB8500_LDO_AUX1].enable;
+ break;
+ case AB8500_LDO_AUX3:
+ info->is_enabled = true;
+ val = info->enable;
+ val |= 0x4; /* put VRF1 in HP mode */
+ break;
+ case AB8500_LDO_ANA:
+ info->is_enabled = true;
+ val = info->enable;
+ val |= 0x1; /* put VPLL in HP mode */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = abx500_set_register_interruptible(info->dev,
+ info->update_bank, info->update_reg,
+ val);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't enable %s\n", info->desc.name);
+ return ret;
+ }
+
+ msleep(info->delay);
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s_v10-enable (bank, reg, value): 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->update_bank, info->update_reg,
+ val);
+
+ return 0;
+}
+
+static int ab8500_v10_regulator_disable(struct regulator_dev *rdev)
+{
+ int regulator_id, ret;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int val;
+
+ regulator_id = rdev_get_id(rdev);
+ switch (regulator_id) {
+ case AB8500_LDO_AUX1:
+ info->is_enabled = false;
+ val = 0x0;
+ if (ab8500_regulator_info[AB8500_LDO_AUX2].is_enabled == true)
+ val |= ab8500_regulator_info[AB8500_LDO_AUX2].enable;
+ break;
+ case AB8500_LDO_AUX2:
+ info->is_enabled = false;
+ val = 0x0;
+ if (ab8500_regulator_info[AB8500_LDO_AUX1].is_enabled == true)
+ val |= ab8500_regulator_info[AB8500_LDO_AUX1].enable;
+ break;
+ case AB8500_LDO_AUX3:
+ info->is_enabled = false;
+ val = 0x4; /* put VRF1 in HP mode */
+ break;
+ case AB8500_LDO_ANA:
+ info->is_enabled = false;
+ val = 0x1; /* put VPLL in HP mode */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = abx500_set_register_interruptible(info->dev,
+ info->update_bank, info->update_reg,
+ val);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't disable %s\n", info->desc.name);
+ return ret;
+ }
+
+ msleep(info->delay);
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s_v10-disable (bank, reg, value): 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->update_bank, info->update_reg,
+ val);
+
+ return 0;
+}
+
+static int ab8500_v10_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ int regulator_id;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ switch (regulator_id) {
+ case AB8500_LDO_AUX1:
+ case AB8500_LDO_AUX2:
+ case AB8500_LDO_AUX3:
+ case AB8500_LDO_ANA:
+ printk(KERN_ALERT "regulator:"
+ "%s_v10-is_enabled (is_enabled): %i\n",
+ info->desc.name, info->is_enabled);
+ return info->is_enabled;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ab8500_v10_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ int regulator_id;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ u8 regval;
+ int voltage;
+
+ regulator_id = rdev_get_id(rdev);
+ switch (regulator_id) {
+ case AB8500_LDO_AUX1:
+ case AB8500_LDO_AUX2:
+ case AB8500_LDO_AUX3:
+ regval = info->voltage_regval & info->voltage_mask;
+ voltage = info->supported_voltages[regval];
+ printk(KERN_ALERT "regulator:"
+ "%s_v10-get_voltage (regval, voltage): 0x%x, %i\n",
+ info->desc.name, regval, voltage);
+ return voltage;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ab8500_v10_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int regulator_id, ret;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ switch (regulator_id) {
+ case AB8500_LDO_AUX1:
+ case AB8500_LDO_AUX2:
+ ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't get best voltage for regulator\n");
+ return ret;
+ }
+ info->voltage_regval = ret;
+ break;
+ case AB8500_LDO_AUX3:
+ ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't get best voltage for regulator\n");
+ return ret;
+ }
+ info->voltage_regval = ret;
+ info->voltage_regval |= 0x20; /* set VRF1 to 2.15 V */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = abx500_set_register_interruptible(info->dev,
+ info->voltage_bank, info->voltage_reg,
+ info->voltage_regval);
+
+ msleep(info->delay);
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s_v10-set_voltage (bank, reg, value): 0x%x, 0x%x, 0x%x",
+ info->desc.name, info->voltage_bank, info->voltage_reg,
+ info->voltage_regval);
+
+ return ret;
+}
+
+static struct regulator_ops ab8500_regulator_ops = {
+ .enable = ab8500_regulator_enable,
+ .disable = ab8500_regulator_disable,
+ .is_enabled = ab8500_regulator_is_enabled,
+ .get_voltage = ab8500_regulator_get_voltage,
+ .set_voltage = ab8500_regulator_set_voltage,
+ .list_voltage = ab8500_list_voltage,
+};
+
+static struct regulator_ops ab8500_v10_regulator_ops = {
+ .enable = ab8500_v10_regulator_enable,
+ .disable = ab8500_v10_regulator_disable,
+ .is_enabled = ab8500_v10_regulator_is_enabled,
+ .get_voltage = ab8500_v10_regulator_get_voltage,
+ .set_voltage = ab8500_v10_regulator_set_voltage,
+ .list_voltage = ab8500_list_voltage,
+};
+
+static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
+{
+ int regulator_id;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ return info->fixed_uV;
+}
+
+static struct regulator_ops ab8500_ldo_fixed_ops = {
+ .enable = ab8500_regulator_enable,
+ .disable = ab8500_regulator_disable,
+ .is_enabled = ab8500_regulator_is_enabled,
+ .get_voltage = ab8500_fixed_get_voltage,
+ .list_voltage = ab8500_list_voltage,
+};
+
+static struct regulator_ops ab8500_v10_ldo_fixed_ops = {
+ .enable = ab8500_v10_regulator_enable,
+ .disable = ab8500_v10_regulator_disable,
+ .is_enabled = ab8500_v10_regulator_is_enabled,
+ .get_voltage = ab8500_fixed_get_voltage,
+ .list_voltage = ab8500_list_voltage,
+};
+
+#define AB8500_LDO(_id, dly, min, max, bank, reg, reg_mask, \
+ reg_enable, volt_bank, volt_reg, volt_mask, \
+ voltages, len_volts) \
+{ \
+ .desc = { \
+ .name = "LDO-" #_id, \
+ .ops = &ab8500_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = AB8500_LDO_##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .delay = dly, \
+ .min_uV = (min) * 1000, \
+ .max_uV = (max) * 1000, \
+ .update_bank = bank, \
+ .update_reg = reg, \
+ .mask = reg_mask, \
+ .enable = reg_enable, \
+ .voltage_bank = volt_bank, \
+ .voltage_reg = volt_reg, \
+ .voltage_mask = volt_mask, \
+ .supported_voltages = voltages, \
+ .voltages_len = len_volts, \
+ .fixed_uV = 0, \
+}
+
+#define AB8500_FIXED_LDO(_id, dly, fixed, bank, reg, reg_mask, \
+ reg_enable) \
+{ \
+ .desc = { \
+ .name = "LDO-" #_id, \
+ .ops = &ab8500_ldo_fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = AB8500_LDO_##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .delay = dly, \
+ .fixed_uV = fixed * 1000, \
+ .update_bank = bank, \
+ .update_reg = reg, \
+ .mask = reg_mask, \
+ .enable = reg_enable, \
+}
+
+static struct ab8500_regulator_info ab8500_regulator_info[] = {
+ /*
+ * Variable Voltage LDOs
+ * name, min uV, max uV, ctrl reg, enable mask, enable value,
+ * volt ctrl reg, volt ctrl mask, volt table, num supported volts
+ */
+ AB8500_LDO(AUX1, 0, 1100, 3300, 0x04, 0x09, 0x03, 0x01,
+ 0x04, 0x1f, 0x0f,
+ ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
+ AB8500_LDO(AUX2, 0, 1100, 3300, 0x04, 0x09, 0x0c, 0x04,
+ 0x04, 0x20, 0x0f,
+ ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
+ AB8500_LDO(AUX3, 0, 1100, 3300, 0x04, 0x0a, 0x03, 0x01,
+ 0x04, 0x21, 0x07,
+ ldo_vaux3_voltages, ARRAY_SIZE(ldo_vaux3_voltages)),
+ AB8500_LDO(INTCORE, 0, 1100, 3300, 0x03, 0x80, 0x44, 0x04,
+ 0x03, 0x80, 0x38,
+ ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)),
+
+ /*
+ * Fixed Voltage LDOs
+ * name, o/p uV, ctrl bank, ctrl reg, enable mask, enable value
+ */
+ AB8500_FIXED_LDO(TVOUT, 10, 2000, 0x03, 0x80, 0x82, 0x02),
+ AB8500_FIXED_LDO(USB, 0, 3300, 0x03, 0x82, 0x03, 0x01),
+ AB8500_FIXED_LDO(AUDIO, 0, 2000, 0x03, 0x83, 0x02, 0x02),
+ AB8500_FIXED_LDO(ANAMIC1, 0, 2050, 0x03, 0x83, 0x08, 0x08),
+ AB8500_FIXED_LDO(ANAMIC2, 0, 2050, 0x03, 0x83, 0x10, 0x10),
+ AB8500_FIXED_LDO(DMIC, 0, 1800, 0x03, 0x83, 0x04, 0x04),
+ AB8500_FIXED_LDO(ANA, 0, 1200, 0x04, 0x06, 0x0c, 0x04),
+};
+
+static inline struct ab8500_regulator_info *find_regulator_info(int id)
+{
+ struct ab8500_regulator_info *info;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+ info = &ab8500_regulator_info[i];
+ if (info->desc.id == id)
+ return info;
+ }
+ return NULL;
+}
+
+static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+ struct ab8500_platform_data *pdata = dev_get_platdata(ab8500->dev);
+ int i, err;
+
+ /* register all regulators */
+ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+ struct ab8500_regulator_info *info = NULL;
+
+ /* assign per-regulator data */
+ info = &ab8500_regulator_info[i];
+ info->dev = &pdev->dev;
+
+ /* fix for hardware before ab8500v2.0 */
+ if (abx500_get_chip_id(info->dev) < 0x20) {
+ if (info->desc.id == AB8500_LDO_AUX3) {
+ info->supported_voltages = ldo_vauxn_voltages;
+ info->voltages_len =
+ ARRAY_SIZE(ldo_vauxn_voltages);
+ info->voltage_mask = 0xf;
+ }
+ }
+
+ /* fix for u8500v1.0 */
+ if (cpu_is_u8500v10()) {
+ switch (info->desc.id) {
+ case AB8500_LDO_AUX1:
+ case AB8500_LDO_AUX2:
+ info->desc.ops = &ab8500_v10_regulator_ops;
+ break;
+ case AB8500_LDO_AUX3:
+ pdata->regulator[i]->constraints.always_on = 1;
+ info->desc.ops = &ab8500_v10_regulator_ops;
+ break;
+ case AB8500_LDO_ANA:
+ info->desc.ops = &ab8500_v10_ldo_fixed_ops;
+ break;
+ }
+ }
+
+ /* register with the regulator framework */
+ info->regulator = regulator_register(&info->desc, &pdev->dev,
+ pdata->regulator[i], info);
+ if (IS_ERR(info->regulator)) {
+ err = PTR_ERR(info->regulator);
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ info->desc.name);
+ /* when we fail, un-register all earlier regulators */
+ i--;
+ while (i > 0) {
+ info = &ab8500_regulator_info[i];
+ regulator_unregister(info->regulator);
+ i--;
+ }
+ return err;
+ }
+
+ dev_vdbg(rdev_get_dev(info->regulator),
+ "%s-probed\n", info->desc.name);
+ }
+
+ return 0;
+}
+
+static __devexit int ab8500_regulator_remove(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+ struct ab8500_regulator_info *info = NULL;
+ info = &ab8500_regulator_info[i];
+
+ dev_vdbg(rdev_get_dev(info->regulator),
+ "%s-removed\n", info->desc.name);
+
+ regulator_unregister(info->regulator);
+ }
+
+ return 0;
+}
+
+static struct platform_driver ab8500_regulator_driver = {
+ .probe = ab8500_regulator_probe,
+ .remove = __devexit_p(ab8500_regulator_remove),
+ .driver = {
+ .name = "ab8500-regulator",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ab8500_regulator_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&ab8500_regulator_driver);
+ if (ret != 0)
+ pr_err("Failed to register ab8500 regulator: %d\n", ret);
+
+ return ret;
+}
+subsys_initcall(ab8500_regulator_init);
+
+static void __exit ab8500_regulator_exit(void)
+{
+ platform_driver_unregister(&ab8500_regulator_driver);
+}
+module_exit(ab8500_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("Regulator Driver for ST-Ericsson AB8500 Mixed-Sig PMIC");
+MODULE_ALIAS("platform:ab8500-regulator");
diff --git a/drivers/rtc/rtc-ab3100.c b/drivers/rtc/rtc-ab3100.c
index d26780ea254..261a07e0fb2 100644
--- a/drivers/rtc/rtc-ab3100.c
+++ b/drivers/rtc/rtc-ab3100.c
@@ -235,6 +235,7 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
err = PTR_ERR(rtc);
return err;
}
+ platform_set_drvdata(pdev, rtc);
return 0;
}
@@ -244,6 +245,7 @@ static int __exit ab3100_rtc_remove(struct platform_device *pdev)
struct rtc_device *rtc = platform_get_drvdata(pdev);
rtc_device_unregister(rtc);
+ platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
index 2fda03125e5..e346705aae9 100644
--- a/drivers/rtc/rtc-ab8500.c
+++ b/drivers/rtc/rtc-ab8500.c
@@ -14,26 +14,26 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
+#include <linux/mfd/abx500.h>
#include <linux/mfd/ab8500.h>
#include <linux/delay.h>
-#define AB8500_RTC_SOFF_STAT_REG 0x0F00
-#define AB8500_RTC_CC_CONF_REG 0x0F01
-#define AB8500_RTC_READ_REQ_REG 0x0F02
-#define AB8500_RTC_WATCH_TSECMID_REG 0x0F03
-#define AB8500_RTC_WATCH_TSECHI_REG 0x0F04
-#define AB8500_RTC_WATCH_TMIN_LOW_REG 0x0F05
-#define AB8500_RTC_WATCH_TMIN_MID_REG 0x0F06
-#define AB8500_RTC_WATCH_TMIN_HI_REG 0x0F07
-#define AB8500_RTC_ALRM_MIN_LOW_REG 0x0F08
-#define AB8500_RTC_ALRM_MIN_MID_REG 0x0F09
-#define AB8500_RTC_ALRM_MIN_HI_REG 0x0F0A
-#define AB8500_RTC_STAT_REG 0x0F0B
-#define AB8500_RTC_BKUP_CHG_REG 0x0F0C
-#define AB8500_RTC_FORCE_BKUP_REG 0x0F0D
-#define AB8500_RTC_CALIB_REG 0x0F0E
-#define AB8500_RTC_SWITCH_STAT_REG 0x0F0F
-#define AB8500_REV_REG 0x1080
+#define AB8500_RTC_SOFF_STAT_REG 0x00
+#define AB8500_RTC_CC_CONF_REG 0x01
+#define AB8500_RTC_READ_REQ_REG 0x02
+#define AB8500_RTC_WATCH_TSECMID_REG 0x03
+#define AB8500_RTC_WATCH_TSECHI_REG 0x04
+#define AB8500_RTC_WATCH_TMIN_LOW_REG 0x05
+#define AB8500_RTC_WATCH_TMIN_MID_REG 0x06
+#define AB8500_RTC_WATCH_TMIN_HI_REG 0x07
+#define AB8500_RTC_ALRM_MIN_LOW_REG 0x08
+#define AB8500_RTC_ALRM_MIN_MID_REG 0x09
+#define AB8500_RTC_ALRM_MIN_HI_REG 0x0A
+#define AB8500_RTC_STAT_REG 0x0B
+#define AB8500_RTC_BKUP_CHG_REG 0x0C
+#define AB8500_RTC_FORCE_BKUP_REG 0x0D
+#define AB8500_RTC_CALIB_REG 0x0E
+#define AB8500_RTC_SWITCH_STAT_REG 0x0F
/* RtcReadRequest bits */
#define RTC_READ_REQUEST 0x01
@@ -46,13 +46,13 @@
#define COUNTS_PER_SEC (0xF000 / 60)
#define AB8500_RTC_EPOCH 2000
-static const unsigned long ab8500_rtc_time_regs[] = {
+static const u8 ab8500_rtc_time_regs[] = {
AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG,
AB8500_RTC_WATCH_TMIN_LOW_REG, AB8500_RTC_WATCH_TSECHI_REG,
AB8500_RTC_WATCH_TSECMID_REG
};
-static const unsigned long ab8500_rtc_alarm_regs[] = {
+static const u8 ab8500_rtc_alarm_regs[] = {
AB8500_RTC_ALRM_MIN_HI_REG, AB8500_RTC_ALRM_MIN_MID_REG,
AB8500_RTC_ALRM_MIN_LOW_REG
};
@@ -76,29 +76,30 @@ static unsigned long get_elapsed_seconds(int year)
static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
unsigned long timeout = jiffies + HZ;
int retval, i;
unsigned long mins, secs;
unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
+ u8 value;
/* Request a data read */
- retval = ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG,
- RTC_READ_REQUEST);
+ retval = abx500_set_register_interruptible(dev,
+ AB8500_RTC, AB8500_RTC_READ_REQ_REG, RTC_READ_REQUEST);
if (retval < 0)
return retval;
/* Early AB8500 chips will not clear the rtc read request bit */
- if (ab8500->revision == 0) {
+ if (abx500_get_chip_id(dev) == 0) {
msleep(1);
} else {
/* Wait for some cycles after enabling the rtc read in ab8500 */
while (time_before(jiffies, timeout)) {
- retval = ab8500_read(ab8500, AB8500_RTC_READ_REQ_REG);
+ retval = abx500_get_register_interruptible(dev,
+ AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value);
if (retval < 0)
return retval;
- if (!(retval & RTC_READ_REQUEST))
+ if (!(value & RTC_READ_REQUEST))
break;
msleep(1);
@@ -107,10 +108,11 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
/* Read the Watchtime registers */
for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
- retval = ab8500_read(ab8500, ab8500_rtc_time_regs[i]);
+ retval = abx500_get_register_interruptible(dev,
+ AB8500_RTC, ab8500_rtc_time_regs[i], &value);
if (retval < 0)
return retval;
- buf[i] = retval;
+ buf[i] = value;
}
mins = (buf[0] << 16) | (buf[1] << 8) | buf[2];
@@ -128,7 +130,6 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
int retval, i;
unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
unsigned long no_secs, no_mins, secs = 0;
@@ -162,27 +163,29 @@ static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
buf[0] = (no_mins >> 16) & 0xFF;
for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
- retval = ab8500_write(ab8500, ab8500_rtc_time_regs[i], buf[i]);
+ retval = abx500_set_register_interruptible(dev, AB8500_RTC,
+ ab8500_rtc_time_regs[i], buf[i]);
if (retval < 0)
return retval;
}
/* Request a data write */
- return ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST);
+ return abx500_set_register_interruptible(dev, AB8500_RTC,
+ AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST);
}
static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
int retval, i;
- int rtc_ctrl;
+ u8 rtc_ctrl, value;
unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
unsigned long secs, mins;
/* Check if the alarm is enabled or not */
- rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG);
- if (rtc_ctrl < 0)
- return rtc_ctrl;
+ retval = abx500_get_register_interruptible(dev, AB8500_RTC,
+ AB8500_RTC_STAT_REG, &rtc_ctrl);
+ if (retval < 0)
+ return retval;
if (rtc_ctrl & RTC_ALARM_ENA)
alarm->enabled = 1;
@@ -192,10 +195,11 @@ static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
alarm->pending = 0;
for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
- retval = ab8500_read(ab8500, ab8500_rtc_alarm_regs[i]);
+ retval = abx500_get_register_interruptible(dev, AB8500_RTC,
+ ab8500_rtc_alarm_regs[i], &value);
if (retval < 0)
return retval;
- buf[i] = retval;
+ buf[i] = value;
}
mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
@@ -211,15 +215,13 @@ static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
static int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled)
{
- struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
-
- return ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_ALARM_ENA,
- enabled ? RTC_ALARM_ENA : 0);
+ return abx500_mask_and_set_register_interruptible(dev, AB8500_RTC,
+ AB8500_RTC_STAT_REG, RTC_ALARM_ENA,
+ enabled ? RTC_ALARM_ENA : 0);
}
static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
int retval, i;
unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
unsigned long mins, secs = 0;
@@ -247,7 +249,8 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
/* Set the alarm time */
for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
- retval = ab8500_write(ab8500, ab8500_rtc_alarm_regs[i], buf[i]);
+ retval = abx500_set_register_interruptible(dev, AB8500_RTC,
+ ab8500_rtc_alarm_regs[i], buf[i]);
if (retval < 0)
return retval;
}
@@ -276,10 +279,9 @@ static const struct rtc_class_ops ab8500_rtc_ops = {
static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
{
- struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
int err;
struct rtc_device *rtc;
- int rtc_ctrl;
+ u8 rtc_ctrl;
int irq;
irq = platform_get_irq_byname(pdev, "ALARM");
@@ -287,17 +289,18 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
return irq;
/* For RTC supply test */
- err = ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_STATUS_DATA,
- RTC_STATUS_DATA);
+ err = abx500_mask_and_set_register_interruptible(&pdev->dev, AB8500_RTC,
+ AB8500_RTC_STAT_REG, RTC_STATUS_DATA, RTC_STATUS_DATA);
if (err < 0)
return err;
/* Wait for reset by the PorRtc */
msleep(1);
- rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG);
- if (rtc_ctrl < 0)
- return rtc_ctrl;
+ err = abx500_get_register_interruptible(&pdev->dev, AB8500_RTC,
+ AB8500_RTC_STAT_REG, &rtc_ctrl);
+ if (err < 0)
+ return err;
/* Check if the RTC Supply fails */
if (!(rtc_ctrl & RTC_STATUS_DATA)) {
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index 3587d9922f2..6b61f5d7c32 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -404,7 +404,7 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)
}
if (request_irq(adev->irq[0], pl031_interrupt,
- IRQF_DISABLED | IRQF_SHARED, "rtc-pl031", ldata)) {
+ IRQF_DISABLED, "rtc-pl031", ldata)) {
ret = -EIO;
goto out_no_irq;
}
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 891e1dd65f2..42a7a4b1001 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -300,6 +300,13 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
+ [PORT_U6_16550A] = {
+ .name = "U6_16550A",
+ .fifo_size = 64,
+ .tx_loadsz = 64,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+ .flags = UART_CAP_FIFO | UART_CAP_AFE,
+ },
};
#if defined (CONFIG_SERIAL_8250_AU1X00)
@@ -1075,6 +1082,15 @@ static void autoconfig_16550a(struct uart_8250_port *up)
DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 ");
}
serial_outp(up, UART_IER, iersave);
+
+ /*
+ * We distinguish between 16550A and U6 16550A by counting
+ * how many bytes are in the FIFO.
+ */
+ if (up->port.type == PORT_16550A && size_fifo(up) == 64) {
+ up->port.type = PORT_U6_16550A;
+ up->capabilities |= UART_CAP_AFE;
+ }
}
/*
@@ -2229,9 +2245,9 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int
return quot;
}
-static void
-serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+void
+serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char cval, fcr = 0;
@@ -2407,6 +2423,17 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
}
+EXPORT_SYMBOL(serial8250_do_set_termios);
+
+static void
+serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ if (port->set_termios)
+ port->set_termios(port, termios, old);
+ else
+ serial8250_do_set_termios(port, termios, old);
+}
static void
serial8250_set_ldisc(struct uart_port *port)
@@ -2994,6 +3021,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
port.type = p->type;
port.serial_in = p->serial_in;
port.serial_out = p->serial_out;
+ port.set_termios = p->set_termios;
port.dev = &dev->dev;
port.irqflags |= irqflag;
ret = serial8250_register_port(&port);
@@ -3157,6 +3185,9 @@ int serial8250_register_port(struct uart_port *port)
uart->port.serial_in = port->serial_in;
if (port->serial_out)
uart->port.serial_out = port->serial_out;
+ /* Possibly override set_termios call */
+ if (port->set_termios)
+ uart->port.set_termios = port->set_termios;
ret = uart_add_one_port(&serial8250_reg, &uart->port);
if (ret == 0)
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 8b23165bc5d..0ad5acd044d 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -331,6 +331,15 @@ config SERIAL_AMBA_PL011_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
+config SERIAL_AMBA_PL011_CLOCK_CONTROL
+ bool "Support for clock control on AMBA serial port"
+ depends on SERIAL_AMBA_PL011
+ select CONSOLE_POLL
+ ---help---
+ Say Y here if you wish to use amba set_termios function to control
+ the pl011 clock. Any positive baudrate passed enables clock,
+ otherwise disables (baudrate = B0 -> hangup)
+
config SERIAL_SB1250_DUART
tristate "BCM1xxx on-chip DUART serial support"
depends on SIBYTE_SB1xxx_SOC=y
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index eb4cb480b93..5406c548229 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -48,6 +48,7 @@
#include <linux/amba/serial.h>
#include <linux/clk.h>
#include <linux/slab.h>
+#include <mach/uart.h>
#include <asm/io.h>
#include <asm/sizes.h>
@@ -63,34 +64,210 @@
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
#define UART_DUMMY_DR_RX (1 << 16)
+
+/* Available amba pl011 port clock states */
+enum pl011_clk_states {
+ PL011_CLK_OFF = 0, /* clock disabled */
+ PL011_CLK_REQUEST_OFF, /* disable after TX flushed */
+ PL011_CLK_ON, /* clock enabled */
+ PL011_PORT_OFF, /* port disabled */
+};
+
/*
* We wrap our port structure around the generic uart_port.
*/
struct uart_amba_port {
struct uart_port port;
struct clk *clk;
- unsigned int im; /* interrupt mask */
+ unsigned int im; /* interrupt mask */
unsigned int old_status;
- unsigned int ifls; /* vendor-specific */
+ unsigned int ifls; /* vendor-specific */
+ unsigned int lcrh_tx; /* vendor-specific */
+ unsigned int lcrh_rx; /* vendor-specific */
+ bool oversampling; /* vendor-specific */
bool autorts;
+#ifdef CONFIG_SERIAL_AMBA_PL011_CLOCK_CONTROL
+ enum pl011_clk_states clk_state; /* actual clock state */
+ struct delayed_work clk_off_work; /* work used for clock off */
+ unsigned int clk_off_delay; /* clock off delay */
+#endif
};
/* There is by now at least one vendor with differing details, so handle it */
struct vendor_data {
unsigned int ifls;
unsigned int fifosize;
+ unsigned int lcrh_tx;
+ unsigned int lcrh_rx;
+ bool oversampling;
};
static struct vendor_data vendor_arm = {
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
.fifosize = 16,
+ .lcrh_tx = UART011_LCRH,
+ .lcrh_rx = UART011_LCRH,
+ .oversampling = false,
};
static struct vendor_data vendor_st = {
.ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
.fifosize = 64,
+ .lcrh_tx = ST_UART011_LCRH_TX,
+ .lcrh_rx = ST_UART011_LCRH_RX,
+ .oversampling = true,
};
+#ifdef CONFIG_SERIAL_AMBA_PL011_CLOCK_CONTROL
+/* Turn clock off if TX buffer is empty, otherwise reschedule */
+static void pl011_clock_off(struct work_struct *work)
+{
+ struct uart_amba_port *uap = container_of(work, struct uart_amba_port,
+ clk_off_work.work);
+ struct uart_port *port = &uap->port;
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (uap->clk_state == PL011_CLK_REQUEST_OFF) {
+ if (uart_circ_empty(xmit)) {
+ clk_disable(uap->clk);
+ uap->clk_state = PL011_CLK_OFF;
+ } else
+ schedule_delayed_work(&uap->clk_off_work,
+ uap->clk_off_delay);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Request to turn off uart clock once pending TX is flushed */
+static void pl011_clock_request_off(struct uart_port *port)
+{
+ unsigned long flags;
+ struct uart_amba_port *uap = (struct uart_amba_port *)(port);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (uap->clk_state == PL011_CLK_ON) {
+ uap->clk_state = PL011_CLK_REQUEST_OFF;
+ /* Turn off later */
+ schedule_delayed_work(&uap->clk_off_work,
+ uap->clk_off_delay);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Request to immediately turn on uart clock */
+static void pl011_clock_on(struct uart_port *port)
+{
+ unsigned long flags;
+ struct uart_amba_port *uap = (struct uart_amba_port *)(port);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ switch (uap->clk_state) {
+ case PL011_CLK_OFF:
+ clk_enable(uap->clk);
+ /* fallthrough */
+ case PL011_CLK_REQUEST_OFF:
+ cancel_delayed_work(&uap->clk_off_work);
+ uap->clk_state = PL011_CLK_ON;
+ break;
+ default:
+ break;
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void pl011_clock_check(struct uart_amba_port *uap)
+{
+ /* Reshedule work during off request */
+ if (uap->clk_state == PL011_CLK_REQUEST_OFF)
+ /* New TX - restart work */
+ if (cancel_delayed_work(&uap->clk_off_work))
+ schedule_delayed_work(&uap->clk_off_work,
+ uap->clk_off_delay);
+}
+
+static int pl011_clock_startup(struct uart_amba_port *uap)
+{
+ int retval = 0;
+
+ if (uap->clk_state == PL011_PORT_OFF) {
+ retval = clk_enable(uap->clk);
+ if (!retval)
+ uap->clk_state = PL011_CLK_ON;
+ else
+ uap->clk_state = PL011_PORT_OFF;
+ }
+
+ return retval;
+}
+
+static void pl011_clock_shutdown(struct uart_amba_port *uap)
+{
+ spin_lock_irq(&uap->port.lock);
+ if (uap->clk_state == PL011_CLK_ON) {
+ clk_disable(uap->clk);
+ uap->clk_state = PL011_PORT_OFF;
+ }
+ spin_unlock_irq(&uap->port.lock);
+}
+
+static void
+pl011_clock_control(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ if (old) {
+ if ((termios->c_cflag & CBAUD) &&
+ (termios->c_ispeed != old->c_ispeed ||
+ termios->c_ospeed != old->c_ospeed)) {
+ if (termios->c_ispeed || termios->c_ospeed)
+ pl011_clock_on(port);
+ else
+ pl011_clock_request_off(port);
+ }
+ }
+}
+
+static void pl011_clock_control_init(struct uart_amba_port *uap)
+{
+ uap->clk_state = PL011_PORT_OFF;
+ INIT_DELAYED_WORK(&uap->clk_off_work, pl011_clock_off);
+ uap->clk_off_delay = HZ / 1000; /* 1 ms */
+}
+
+#else
+/* Blank functions for clock control */
+static inline void pl011_clock_check(struct uart_amba_port *uap)
+{
+}
+
+static inline int pl011_clock_startup(struct uart_amba_port *uap)
+{
+ return clk_enable(uap->clk);
+}
+
+static inline void pl011_clock_shutdown(struct uart_amba_port *uap)
+{
+ clk_disable(uap->clk);
+}
+
+static inline void
+pl011_clock_control(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+}
+
+static inline void pl011_clock_control_init(struct uart_amba_port *uap)
+{
+}
+#endif
+
static void pl011_stop_tx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -200,6 +377,9 @@ static void pl011_tx_chars(struct uart_amba_port *uap)
break;
} while (--count > 0);
+ if (count)
+ pl011_clock_check(uap);
+
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
@@ -327,12 +507,12 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
unsigned int lcr_h;
spin_lock_irqsave(&uap->port.lock, flags);
- lcr_h = readw(uap->port.membase + UART011_LCRH);
+ lcr_h = readw(uap->port.membase + uap->lcrh_tx);
if (break_state == -1)
lcr_h |= UART01x_LCRH_BRK;
else
lcr_h &= ~UART01x_LCRH_BRK;
- writew(lcr_h, uap->port.membase + UART011_LCRH);
+ writew(lcr_h, uap->port.membase + uap->lcrh_tx);
spin_unlock_irqrestore(&uap->port.lock, flags);
}
@@ -371,7 +551,7 @@ static int pl011_startup(struct uart_port *port)
/*
* Try to enable the clock producer.
*/
- retval = clk_enable(uap->clk);
+ retval = pl011_clock_startup(uap);
if (retval)
goto out;
@@ -393,7 +573,17 @@ static int pl011_startup(struct uart_port *port)
writew(cr, uap->port.membase + UART011_CR);
writew(0, uap->port.membase + UART011_FBRD);
writew(1, uap->port.membase + UART011_IBRD);
- writew(0, uap->port.membase + UART011_LCRH);
+ writew(0, uap->port.membase + uap->lcrh_rx);
+ if (uap->lcrh_tx != uap->lcrh_rx) {
+ int i;
+ /*
+ * Wait 10 PCLKs before writing LCRH_TX register,
+ * to get this delay write read only register 10 times
+ */
+ for (i = 0; i < 10; ++i)
+ writew(0xff, uap->port.membase + UART011_MIS);
+ writew(0, uap->port.membase + uap->lcrh_tx);
+ }
writew(0, uap->port.membase + UART01x_DR);
while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
barrier();
@@ -414,18 +604,35 @@ static int pl011_startup(struct uart_port *port)
writew(uap->im, uap->port.membase + UART011_IMSC);
spin_unlock_irq(&uap->port.lock);
+ if (uap->port.dev->platform_data) {
+ struct uart_amba_plat_data *plat;
+
+ plat = uap->port.dev->platform_data;
+ if (plat->init)
+ plat->init();
+ }
+
return 0;
clk_dis:
- clk_disable(uap->clk);
+ pl011_clock_shutdown(uap);
out:
return retval;
}
+static void pl011_shutdown_channel(struct uart_amba_port *uap,
+ unsigned int lcrh)
+{
+ unsigned long val;
+
+ val = readw(uap->port.membase + lcrh);
+ val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
+ writew(val, uap->port.membase + lcrh);
+}
+
static void pl011_shutdown(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
- unsigned long val;
/*
* disable all interrupts
@@ -450,14 +657,22 @@ static void pl011_shutdown(struct uart_port *port)
/*
* disable break condition and fifos
*/
- val = readw(uap->port.membase + UART011_LCRH);
- val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
- writew(val, uap->port.membase + UART011_LCRH);
+ pl011_shutdown_channel(uap, uap->lcrh_rx);
+ if (uap->lcrh_rx != uap->lcrh_tx)
+ pl011_shutdown_channel(uap, uap->lcrh_tx);
/*
* Shut down the clock producer
*/
- clk_disable(uap->clk);
+ pl011_clock_shutdown(uap);
+
+ if (uap->port.dev->platform_data) {
+ struct uart_amba_plat_data *plat;
+
+ plat = uap->port.dev->platform_data;
+ if (plat->exit)
+ plat->exit();
+ }
}
static void
@@ -470,10 +685,22 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned int baud, quot;
/*
+ * Must be before uart_get_baud_rate() call, because
+ * this function changes baudrate to default in case of 0
+ * B0 hangup !!!
+ */
+ pl011_clock_control(port, termios, old);
+
+ /*
* Ask the core to calculate the divisor for us.
*/
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
- quot = port->uartclk * 4 / baud;
+ baud = uart_get_baud_rate(port, termios, old, 0,
+ port->uartclk/(uap->oversampling ? 8 : 16));
+
+ if (baud > port->uartclk/16)
+ quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
+ else
+ quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
switch (termios->c_cflag & CSIZE) {
case CS5:
@@ -552,6 +779,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
uap->autorts = false;
}
+ if (uap->oversampling) {
+ if (baud > port->uartclk/16)
+ old_cr |= ST_UART011_CR_OVSFACT;
+ else
+ old_cr &= ~ST_UART011_CR_OVSFACT;
+ }
+
/* Set baud rate */
writew(quot & 0x3f, port->membase + UART011_FBRD);
writew(quot >> 6, port->membase + UART011_IBRD);
@@ -561,7 +795,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
* NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
* ----------^----------^----------^----------^-----
*/
- writew(lcr_h, port->membase + UART011_LCRH);
+ writew(lcr_h, port->membase + uap->lcrh_rx);
+ if (uap->lcrh_rx != uap->lcrh_tx) {
+ int i;
+ /*
+ * Wait 10 PCLKs before writing LCRH_TX register,
+ * to get this delay write read only register 10 times
+ */
+ for (i = 0; i < 10; ++i)
+ writew(0xff, uap->port.membase + UART011_MIS);
+ writew(lcr_h, port->membase + uap->lcrh_tx);
+ }
writew(old_cr, port->membase + UART011_CR);
spin_unlock_irqrestore(&port->lock, flags);
@@ -688,7 +932,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
unsigned int lcr_h, ibrd, fbrd;
- lcr_h = readw(uap->port.membase + UART011_LCRH);
+ lcr_h = readw(uap->port.membase + uap->lcrh_tx);
*parity = 'n';
if (lcr_h & UART01x_LCRH_PEN) {
@@ -707,6 +951,12 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
fbrd = readw(uap->port.membase + UART011_FBRD);
*baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
+
+ if (uap->oversampling) {
+ if (readw(uap->port.membase + UART011_CR)
+ & ST_UART011_CR_OVSFACT)
+ *baud *= 2;
+ }
}
}
@@ -729,6 +979,14 @@ static int __init pl011_console_setup(struct console *co, char *options)
if (!uap)
return -ENODEV;
+ if (uap->port.dev->platform_data) {
+ struct uart_amba_plat_data *plat;
+
+ plat = uap->port.dev->platform_data;
+ if (plat->init)
+ plat->init();
+ }
+
uap->port.uartclk = clk_get_rate(uap->clk);
if (options)
@@ -800,6 +1058,9 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
}
uap->ifls = vendor->ifls;
+ uap->lcrh_rx = vendor->lcrh_rx;
+ uap->lcrh_tx = vendor->lcrh_tx;
+ uap->oversampling = vendor->oversampling;
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;
@@ -813,6 +1074,9 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
amba_ports[i] = uap;
amba_set_drvdata(dev, uap);
+
+ pl011_clock_control_init(uap);
+
ret = uart_add_one_port(&amba_reg, &uap->port);
if (ret) {
amba_set_drvdata(dev, NULL);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 91c2f4f3af1..caaec2dfb11 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -90,6 +90,18 @@ config SPI_BITBANG
need it. You only need to select this explicitly to support driver
modules that aren't part of this kernel tree.
+config STM_MSP_SPI
+ tristate "STM MSP CONTROLLER (SPI master)"
+ default y
+ help
+ This enables using the STM MSP controller in master
+ mode.
+
+config SPI_WORKQUEUE
+ bool "SPI_WORKQUEUE"
+ depends on STM_SPI
+ default n
+
config SPI_BUTTERFLY
tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)"
depends on PARPORT
@@ -216,8 +228,8 @@ config SPI_ORION
This enables using the SPI master controller on the Orion chips.
config SPI_PL022
- tristate "ARM AMBA PL022 SSP controller (EXPERIMENTAL)"
- depends on ARM_AMBA && EXPERIMENTAL
+ tristate "ARM AMBA PL022 SSP controller"
+ depends on ARM_AMBA
default y if MACH_U300
default y if ARCH_REALVIEW
default y if INTEGRATOR_IMPD1
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index e9cbd18217a..e1771805521 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_SPI_PPC4xx) += spi_ppc4xx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx_hw.o
obj-$(CONFIG_SPI_S3C64XX) += spi_s3c64xx.o
+obj-$(CONFIG_STM_MSP_SPI) += stm_msp.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
obj-$(CONFIG_SPI_XILINX_OF) += xilinx_spi_of.o
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
index f0a1418ce66..403755fefc4 100644
--- a/drivers/spi/amba-pl022.c
+++ b/drivers/spi/amba-pl022.c
@@ -27,7 +27,6 @@
/*
* TODO:
* - add timeout on polled transfers
- * - add generic DMA framework support
*/
#include <linux/init.h>
@@ -45,6 +44,9 @@
#include <linux/amba/pl022.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
/*
* This macro is used to define some register default values.
@@ -381,6 +383,14 @@ struct pl022 {
enum ssp_reading read;
enum ssp_writing write;
u32 exp_fifo_level;
+ /* DMA settings */
+#ifdef CONFIG_DMA_ENGINE
+ struct dma_chan *dma_rx_channel;
+ struct dma_chan *dma_tx_channel;
+ struct sg_table sgt_rx;
+ struct sg_table sgt_tx;
+ char *dummypage;
+#endif
};
/**
@@ -406,7 +416,7 @@ struct chip_data {
u16 dmacr;
u16 cpsr;
u8 n_bytes;
- u8 enable_dma:1;
+ bool enable_dma;
enum ssp_reading read;
enum ssp_writing write;
void (*cs_control) (u32 command);
@@ -762,6 +772,371 @@ static void *next_transfer(struct pl022 *pl022)
}
return STATE_DONE;
}
+
+/*
+ * This DMA functionality is only compiled in if we have
+ * access to the generic DMA devices/DMA engine.
+ */
+#ifdef CONFIG_DMA_ENGINE
+static void unmap_free_dma_scatter(struct pl022 *pl022)
+{
+ /* Unmap and free the SG tables */
+ dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
+ pl022->sgt_tx.nents, DMA_TO_DEVICE);
+ dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
+ pl022->sgt_rx.nents, DMA_FROM_DEVICE);
+ sg_free_table(&pl022->sgt_rx);
+ sg_free_table(&pl022->sgt_tx);
+}
+
+static void dma_callback(void *data)
+{
+ struct pl022 *pl022 = data;
+ struct spi_message *msg = pl022->cur_msg;
+
+ BUG_ON(!pl022->sgt_rx.sgl);
+
+#ifdef VERBOSE_DEBUG
+ /*
+ * Optionally dump out buffers to inspect contents, this is
+ * good if you want to convince yourself that the loopback
+ * read/write contents are the same, when adopting to a new
+ * DMA engine.
+ */
+ {
+ struct scatterlist *sg;
+ unsigned int i;
+
+ dma_sync_sg_for_cpu(&pl022->adev->dev,
+ pl022->sgt_rx.sgl,
+ pl022->sgt_rx.nents,
+ DMA_FROM_DEVICE);
+
+ for_each_sg(pl022->sgt_rx.sgl, sg, pl022->sgt_rx.nents, i) {
+ dev_dbg(&pl022->adev->dev, "SPI RX SG ENTRY: %d", i);
+ print_hex_dump(KERN_ERR, "SPI RX: ",
+ DUMP_PREFIX_OFFSET,
+ 16,
+ 1,
+ sg_virt(sg),
+ sg_dma_len(sg),
+ 1);
+ }
+ for_each_sg(pl022->sgt_tx.sgl, sg, pl022->sgt_tx.nents, i) {
+ dev_dbg(&pl022->adev->dev, "SPI TX SG ENTRY: %d", i);
+ print_hex_dump(KERN_ERR, "SPI TX: ",
+ DUMP_PREFIX_OFFSET,
+ 16,
+ 1,
+ sg_virt(sg),
+ sg_dma_len(sg),
+ 1);
+ }
+ }
+#endif
+
+ unmap_free_dma_scatter(pl022);
+
+ /* Update total bytes transfered */
+ msg->actual_length += pl022->cur_transfer->len;
+ if (pl022->cur_transfer->cs_change)
+ pl022->cur_chip->
+ cs_control(SSP_CHIP_DESELECT);
+
+ /* Move to next transfer */
+ msg->state = next_transfer(pl022);
+ tasklet_schedule(&pl022->pump_transfers);
+}
+
+static void setup_dma_scatter(struct pl022 *pl022,
+ void *buffer,
+ unsigned int length,
+ struct sg_table *sgtab)
+{
+ struct scatterlist *sg;
+ int bytesleft = length;
+ void *bufp = buffer;
+ int mapbytes;
+ int i;
+
+ if (buffer) {
+ for_each_sg(sgtab->sgl, sg, sgtab->nents, i) {
+ /*
+ * If there are less bytes left than what fits
+ * in the current page (plus page alignment offset)
+ * we just feed in this, else we stuff in as much
+ * as we can.
+ */
+ if (bytesleft < (PAGE_SIZE - offset_in_page(bufp)))
+ mapbytes = bytesleft;
+ else
+ mapbytes = PAGE_SIZE - offset_in_page(bufp);
+ sg_set_page(sg, virt_to_page(bufp),
+ mapbytes, offset_in_page(bufp));
+ bufp += mapbytes;
+ bytesleft -= mapbytes;
+ dev_dbg(&pl022->adev->dev,
+ "set RX/TX target page @ %p, %d bytes, %d left\n",
+ bufp, mapbytes, bytesleft);
+ }
+ } else {
+ /* Map the dummy buffer on every page */
+ for_each_sg(sgtab->sgl, sg, sgtab->nents, i) {
+ if (bytesleft < PAGE_SIZE)
+ mapbytes = bytesleft;
+ else
+ mapbytes = PAGE_SIZE;
+ sg_set_page(sg, virt_to_page(pl022->dummypage),
+ mapbytes, 0);
+ bytesleft -= mapbytes;
+ dev_dbg(&pl022->adev->dev,
+ "set RX/TX to dummy page %d bytes, %d left\n",
+ mapbytes, bytesleft);
+
+ }
+ }
+ BUG_ON(bytesleft);
+}
+
+/**
+ * configure_dma - configures the channels for the next transfer
+ * @pl022: SSP driver's private data structure
+ */
+static int configure_dma(struct pl022 *pl022)
+{
+ struct dma_slave_config rx_conf = {
+ .src_addr = SSP_DR(pl022->phybase),
+ .direction = DMA_FROM_DEVICE,
+ .src_maxburst = pl022->vendor->fifodepth >> 1,
+ };
+ struct dma_slave_config tx_conf = {
+ .dst_addr = SSP_DR(pl022->phybase),
+ .direction = DMA_TO_DEVICE,
+ .dst_maxburst = pl022->vendor->fifodepth >> 1,
+ };
+ unsigned int pages;
+ int ret;
+ int sglen;
+ struct dma_chan *rxchan = pl022->dma_rx_channel;
+ struct dma_chan *txchan = pl022->dma_tx_channel;
+ struct dma_async_tx_descriptor *rxdesc;
+ struct dma_async_tx_descriptor *txdesc;
+ dma_cookie_t cookie;
+
+ /* Check that the channels are available */
+ if (!rxchan || !txchan)
+ return -ENODEV;
+
+ switch (pl022->read) {
+ case READING_NULL:
+ /* Use the same as for writing */
+ rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
+ break;
+ case READING_U8:
+ rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ break;
+ case READING_U16:
+ rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ break;
+ case READING_U32:
+ rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ break;
+ }
+
+ switch (pl022->write) {
+ case WRITING_NULL:
+ /* Use the same as for reading */
+ tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
+ break;
+ case WRITING_U8:
+ tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ break;
+ case WRITING_U16:
+ tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ break;
+ case WRITING_U32:
+ tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;;
+ break;
+ }
+
+ /* SPI pecularity: we need to read and write the same width */
+ if (rx_conf.src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+ rx_conf.src_addr_width = tx_conf.dst_addr_width;
+ if (tx_conf.dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+ tx_conf.dst_addr_width = rx_conf.src_addr_width;
+ BUG_ON(rx_conf.src_addr_width != tx_conf.dst_addr_width);
+
+ rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
+ (unsigned long) &rx_conf);
+ txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
+ (unsigned long) &tx_conf);
+
+ /* Create sglists for the transfers */
+ pages = (pl022->cur_transfer->len >> PAGE_SHIFT) + 1;
+ dev_dbg(&pl022->adev->dev, "using %d pages for transfer\n", pages);
+
+ ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_KERNEL);
+ if (ret)
+ goto err_alloc_rx_sg;
+
+ ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_KERNEL);
+ if (ret)
+ goto err_alloc_tx_sg;
+
+ /* Fill in the scatterlists for the RX+TX buffers */
+ setup_dma_scatter(pl022, pl022->rx,
+ pl022->cur_transfer->len, &pl022->sgt_rx);
+ setup_dma_scatter(pl022, pl022->tx,
+ pl022->cur_transfer->len, &pl022->sgt_tx);
+
+ /* Map DMA buffers */
+ sglen = dma_map_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
+ pl022->sgt_rx.nents, DMA_FROM_DEVICE);
+ if (!sglen)
+ goto err_rx_sgmap;
+
+ sglen = dma_map_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
+ pl022->sgt_tx.nents, DMA_TO_DEVICE);
+ if (!sglen)
+ goto err_tx_sgmap;
+
+ /* Send both scatterlists */
+ rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
+ pl022->sgt_rx.sgl,
+ pl022->sgt_rx.nents,
+ DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!rxdesc)
+ goto err_rxdesc;
+
+ txdesc = txchan->device->device_prep_slave_sg(txchan,
+ pl022->sgt_tx.sgl,
+ pl022->sgt_tx.nents,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!txdesc)
+ goto err_txdesc;
+
+ /* Put the callback on the RX transfer only, that should finish last */
+ rxdesc->callback = dma_callback;
+ rxdesc->callback_param = pl022;
+
+ /* Submit and fire RX and TX with TX last so we're ready to read! */
+ cookie = rxdesc->tx_submit(rxdesc);
+ if (dma_submit_error(cookie))
+ goto err_submit_rx;
+ cookie = txdesc->tx_submit(txdesc);
+ if (dma_submit_error(cookie))
+ goto err_submit_tx;
+ rxchan->device->device_issue_pending(rxchan);
+ txchan->device->device_issue_pending(txchan);
+
+ return 0;
+
+err_submit_tx:
+err_submit_rx:
+err_txdesc:
+ txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
+err_rxdesc:
+ rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
+ dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
+ pl022->sgt_tx.nents, DMA_TO_DEVICE);
+err_tx_sgmap:
+ dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
+ pl022->sgt_tx.nents, DMA_FROM_DEVICE);
+err_rx_sgmap:
+ sg_free_table(&pl022->sgt_tx);
+err_alloc_tx_sg:
+ sg_free_table(&pl022->sgt_rx);
+err_alloc_rx_sg:
+ return -ENOMEM;
+}
+
+static int __init pl022_dma_probe(struct pl022 *pl022)
+{
+ dma_cap_mask_t mask;
+
+ /* Try to acquire a generic DMA engine slave channel */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ /*
+ * We need both RX and TX channels to do DMA, else do none
+ * of them.
+ */
+ pl022->dma_rx_channel = dma_request_channel(mask,
+ pl022->master_info->dma_filter,
+ pl022->master_info->dma_rx_param);
+ if (!pl022->dma_rx_channel) {
+ dev_err(&pl022->adev->dev, "no RX DMA channel!\n");
+ goto err_no_rxchan;
+ }
+
+ pl022->dma_tx_channel = dma_request_channel(mask,
+ pl022->master_info->dma_filter,
+ pl022->master_info->dma_tx_param);
+ if (!pl022->dma_tx_channel) {
+ dev_err(&pl022->adev->dev, "no TX DMA channel!\n");
+ goto err_no_txchan;
+ }
+
+ pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!pl022->dummypage) {
+ dev_err(&pl022->adev->dev, "no DMA dummypage!\n");
+ goto err_no_dummypage;
+ }
+
+ dev_info(&pl022->adev->dev, "setup for DMA on RX %s, TX %s\n",
+ dma_chan_name(pl022->dma_rx_channel),
+ dma_chan_name(pl022->dma_tx_channel));
+
+ return 0;
+
+err_no_dummypage:
+ dma_release_channel(pl022->dma_tx_channel);
+err_no_txchan:
+ dma_release_channel(pl022->dma_rx_channel);
+ pl022->dma_rx_channel = NULL;
+err_no_rxchan:
+ return -ENODEV;
+}
+
+static void terminate_dma(struct pl022 *pl022)
+{
+ struct dma_chan *rxchan = pl022->dma_rx_channel;
+ struct dma_chan *txchan = pl022->dma_tx_channel;
+
+ rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
+ txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
+ unmap_free_dma_scatter(pl022);
+}
+
+static void pl022_dma_remove(struct pl022 *pl022)
+{
+ if (pl022->busy)
+ terminate_dma(pl022);
+ if (pl022->dma_tx_channel)
+ dma_release_channel(pl022->dma_tx_channel);
+ if (pl022->dma_rx_channel)
+ dma_release_channel(pl022->dma_rx_channel);
+ kfree(pl022->dummypage);
+}
+
+#else
+static inline int configure_dma(struct pl022 *pl022)
+{
+ return -ENODEV;
+}
+
+static inline int pl022_dma_probe(struct pl022 *pl022)
+{
+ return 0;
+}
+
+static inline void pl022_dma_remove(struct pl022 *pl022)
+{
+}
+#endif
+
/**
* pl022_interrupt_handler - Interrupt handler for SSP controller
*
@@ -793,14 +1168,17 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
if (unlikely(!irq_status))
return IRQ_NONE;
- /* This handles the error code interrupts */
+ /*
+ * This handles the FIFO interrupts, the timeout
+ * interrupts are flatly ignored, they cannot be
+ * trusted.
+ */
if (unlikely(irq_status & SSP_MIS_MASK_RORMIS)) {
/*
* Overrun interrupt - bail out since our Data has been
* corrupted
*/
- dev_err(&pl022->adev->dev,
- "FIFO overrun\n");
+ dev_err(&pl022->adev->dev, "FIFO overrun\n");
if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF)
dev_err(&pl022->adev->dev,
"RXFIFO is full\n");
@@ -895,8 +1273,8 @@ static int set_up_next_transfer(struct pl022 *pl022,
}
/**
- * pump_transfers - Tasklet function which schedules next interrupt transfer
- * when running in interrupt transfer mode.
+ * pump_transfers - Tasklet function which schedules next transfer
+ * when running in interrupt or DMA transfer mode.
* @data: SSP driver private data structure
*
*/
@@ -953,65 +1331,23 @@ static void pump_transfers(unsigned long data)
}
/* Flush the FIFOs and let's go! */
flush(pl022);
- writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
-}
-
-/**
- * NOT IMPLEMENTED
- * configure_dma - It configures the DMA pipes for DMA transfers
- * @data: SSP driver's private data structure
- *
- */
-static int configure_dma(void *data)
-{
- struct pl022 *pl022 = data;
- dev_dbg(&pl022->adev->dev, "configure DMA\n");
- return -ENOTSUPP;
-}
-
-/**
- * do_dma_transfer - It handles transfers of the current message
- * if it is DMA xfer.
- * NOT FULLY IMPLEMENTED
- * @data: SSP driver's private data structure
- */
-static void do_dma_transfer(void *data)
-{
- struct pl022 *pl022 = data;
-
- if (configure_dma(data)) {
- dev_dbg(&pl022->adev->dev, "configuration of DMA Failed!\n");
- goto err_config_dma;
- }
-
- /* TODO: Implememt DMA setup of pipes here */
- /* Enable target chip, set up transfer */
- pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
- if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
- /* Error path */
- pl022->cur_msg->state = STATE_ERROR;
- pl022->cur_msg->status = -EIO;
- giveback(pl022);
+ if (pl022->cur_chip->enable_dma) {
+ if (configure_dma(pl022)) {
+ dev_dbg(&pl022->adev->dev,
+ "configuration of DMA failed, fall back to interrupt mode\n");
+ goto err_config_dma;
+ }
return;
}
- /* Enable SSP */
- writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
- SSP_CR1(pl022->virtbase));
- /* TODO: Enable the DMA transfer here */
- return;
-
- err_config_dma:
- pl022->cur_msg->state = STATE_ERROR;
- pl022->cur_msg->status = -EIO;
- giveback(pl022);
- return;
+err_config_dma:
+ writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
}
-static void do_interrupt_transfer(void *data)
+static void do_interrupt_dma_transfer(struct pl022 *pl022)
{
- struct pl022 *pl022 = data;
+ u32 irqflags = ENABLE_ALL_INTERRUPTS;
/* Enable target chip */
pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
@@ -1022,15 +1358,26 @@ static void do_interrupt_transfer(void *data)
giveback(pl022);
return;
}
+ /* If we're using DMA, set up DMA here */
+ if (pl022->cur_chip->enable_dma) {
+ /* Configure DMA transfer */
+ if (configure_dma(pl022)) {
+ dev_dbg(&pl022->adev->dev,
+ "configuration of DMA failed, fall back to interrupt mode\n");
+ goto err_config_dma;
+ }
+ /* Disable interrupts in DMA mode, IRQ from DMA controller */
+ irqflags = DISABLE_ALL_INTERRUPTS;
+ }
+err_config_dma:
/* Enable SSP, turn on interrupts */
writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
SSP_CR1(pl022->virtbase));
- writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+ writew(irqflags, SSP_IMSC(pl022->virtbase));
}
-static void do_polling_transfer(void *data)
+static void do_polling_transfer(struct pl022 *pl022)
{
- struct pl022 *pl022 = data;
struct spi_message *message = NULL;
struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL;
@@ -1100,7 +1447,7 @@ static void do_polling_transfer(void *data)
*
* This function checks if there is any spi message in the queue that
* needs processing and delegate control to appropriate function
- * do_polling_transfer()/do_interrupt_transfer()/do_dma_transfer()
+ * do_polling_transfer()/do_interrupt_dma_transfer()
* based on the kind of the transfer
*
*/
@@ -1148,10 +1495,8 @@ static void pump_messages(struct work_struct *work)
if (pl022->cur_chip->xfer_type == POLLING_TRANSFER)
do_polling_transfer(pl022);
- else if (pl022->cur_chip->xfer_type == INTERRUPT_TRANSFER)
- do_interrupt_transfer(pl022);
else
- do_dma_transfer(pl022);
+ do_interrupt_dma_transfer(pl022);
}
@@ -1246,100 +1591,56 @@ static int destroy_queue(struct pl022 *pl022)
}
static int verify_controller_parameters(struct pl022 *pl022,
- struct pl022_config_chip *chip_info)
+ struct pl022_config_chip const *chip_info)
{
- if ((chip_info->lbm != LOOPBACK_ENABLED)
- && (chip_info->lbm != LOOPBACK_DISABLED)) {
- dev_err(chip_info->dev,
- "loopback Mode is configured incorrectly\n");
- return -EINVAL;
- }
if ((chip_info->iface < SSP_INTERFACE_MOTOROLA_SPI)
|| (chip_info->iface > SSP_INTERFACE_UNIDIRECTIONAL)) {
- dev_err(chip_info->dev,
+ dev_err(&pl022->adev->dev,
"interface is configured incorrectly\n");
return -EINVAL;
}
if ((chip_info->iface == SSP_INTERFACE_UNIDIRECTIONAL) &&
(!pl022->vendor->unidir)) {
- dev_err(chip_info->dev,
+ dev_err(&pl022->adev->dev,
"unidirectional mode not supported in this "
"hardware version\n");
return -EINVAL;
}
if ((chip_info->hierarchy != SSP_MASTER)
&& (chip_info->hierarchy != SSP_SLAVE)) {
- dev_err(chip_info->dev,
+ dev_err(&pl022->adev->dev,
"hierarchy is configured incorrectly\n");
return -EINVAL;
}
- if (((chip_info->clk_freq).cpsdvsr < CPSDVR_MIN)
- || ((chip_info->clk_freq).cpsdvsr > CPSDVR_MAX)) {
- dev_err(chip_info->dev,
- "cpsdvsr is configured incorrectly\n");
- return -EINVAL;
- }
- if ((chip_info->endian_rx != SSP_RX_MSB)
- && (chip_info->endian_rx != SSP_RX_LSB)) {
- dev_err(chip_info->dev,
- "RX FIFO endianess is configured incorrectly\n");
- return -EINVAL;
- }
- if ((chip_info->endian_tx != SSP_TX_MSB)
- && (chip_info->endian_tx != SSP_TX_LSB)) {
- dev_err(chip_info->dev,
- "TX FIFO endianess is configured incorrectly\n");
- return -EINVAL;
- }
- if ((chip_info->data_size < SSP_DATA_BITS_4)
- || (chip_info->data_size > SSP_DATA_BITS_32)) {
- dev_err(chip_info->dev,
- "DATA Size is configured incorrectly\n");
- return -EINVAL;
- }
if ((chip_info->com_mode != INTERRUPT_TRANSFER)
&& (chip_info->com_mode != DMA_TRANSFER)
&& (chip_info->com_mode != POLLING_TRANSFER)) {
- dev_err(chip_info->dev,
+ dev_err(&pl022->adev->dev,
"Communication mode is configured incorrectly\n");
return -EINVAL;
}
if ((chip_info->rx_lev_trig < SSP_RX_1_OR_MORE_ELEM)
|| (chip_info->rx_lev_trig > SSP_RX_32_OR_MORE_ELEM)) {
- dev_err(chip_info->dev,
+ dev_err(&pl022->adev->dev,
"RX FIFO Trigger Level is configured incorrectly\n");
return -EINVAL;
}
if ((chip_info->tx_lev_trig < SSP_TX_1_OR_MORE_EMPTY_LOC)
|| (chip_info->tx_lev_trig > SSP_TX_32_OR_MORE_EMPTY_LOC)) {
- dev_err(chip_info->dev,
+ dev_err(&pl022->adev->dev,
"TX FIFO Trigger Level is configured incorrectly\n");
return -EINVAL;
}
- if (chip_info->iface == SSP_INTERFACE_MOTOROLA_SPI) {
- if ((chip_info->clk_phase != SSP_CLK_FIRST_EDGE)
- && (chip_info->clk_phase != SSP_CLK_SECOND_EDGE)) {
- dev_err(chip_info->dev,
- "Clock Phase is configured incorrectly\n");
- return -EINVAL;
- }
- if ((chip_info->clk_pol != SSP_CLK_POL_IDLE_LOW)
- && (chip_info->clk_pol != SSP_CLK_POL_IDLE_HIGH)) {
- dev_err(chip_info->dev,
- "Clock Polarity is configured incorrectly\n");
- return -EINVAL;
- }
- }
if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) {
if ((chip_info->ctrl_len < SSP_BITS_4)
|| (chip_info->ctrl_len > SSP_BITS_32)) {
- dev_err(chip_info->dev,
+ dev_err(&pl022->adev->dev,
"CTRL LEN is configured incorrectly\n");
return -EINVAL;
}
if ((chip_info->wait_state != SSP_MWIRE_WAIT_ZERO)
&& (chip_info->wait_state != SSP_MWIRE_WAIT_ONE)) {
- dev_err(chip_info->dev,
+ dev_err(&pl022->adev->dev,
"Wait State is configured incorrectly\n");
return -EINVAL;
}
@@ -1349,23 +1650,18 @@ static int verify_controller_parameters(struct pl022 *pl022,
SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
&& (chip_info->duplex !=
SSP_MICROWIRE_CHANNEL_HALF_DUPLEX))
- dev_err(chip_info->dev,
+ dev_err(&pl022->adev->dev,
"Microwire duplex mode is configured incorrectly\n");
return -EINVAL;
} else {
if (chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
- dev_err(chip_info->dev,
+ dev_err(&pl022->adev->dev,
"Microwire half duplex mode requested,"
" but this is only available in the"
" ST version of PL022\n");
return -EINVAL;
}
}
- if (chip_info->cs_control == NULL) {
- dev_warn(chip_info->dev,
- "Chip Select Function is NULL for this chip\n");
- chip_info->cs_control = null_cs_control;
- }
return 0;
}
@@ -1465,22 +1761,24 @@ static int calculate_effective_freq(struct pl022 *pl022,
return 0;
}
-/**
- * NOT IMPLEMENTED
- * process_dma_info - Processes the DMA info provided by client drivers
- * @chip_info: chip info provided by client device
- * @chip: Runtime state maintained by the SSP controller for each spi device
- *
- * This function processes and stores DMA config provided by client driver
- * into the runtime state maintained by the SSP controller driver
+
+/*
+ * A piece of default chip info unless the platform
+ * supplies it.
*/
-static int process_dma_info(struct pl022_config_chip *chip_info,
- struct chip_data *chip)
-{
- dev_err(chip_info->dev,
- "cannot process DMA info, DMA not implemented!\n");
- return -ENOTSUPP;
-}
+static const struct pl022_config_chip pl022_default_chip_info = {
+ .com_mode = POLLING_TRANSFER,
+ .iface = SSP_INTERFACE_MOTOROLA_SPI,
+ .hierarchy = SSP_SLAVE,
+ .slave_tx_disable = DO_NOT_DRIVE_TX,
+ .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
+ .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
+ .ctrl_len = SSP_BITS_8,
+ .wait_state = SSP_MWIRE_WAIT_ZERO,
+ .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
+ .cs_control = null_cs_control,
+};
+
/**
* pl022_setup - setup function registered to SPI master framework
@@ -1494,23 +1792,15 @@ static int process_dma_info(struct pl022_config_chip *chip_info,
* controller hardware here, that is not done until the actual transfer
* commence.
*/
-
-/* FIXME: JUST GUESSING the spi->mode bits understood by this driver */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
- | SPI_LSB_FIRST | SPI_LOOP)
-
static int pl022_setup(struct spi_device *spi)
{
- struct pl022_config_chip *chip_info;
+ struct pl022_config_chip const *chip_info;
struct chip_data *chip;
+ struct ssp_clock_params clk_freq;
int status = 0;
struct pl022 *pl022 = spi_master_get_devdata(spi->master);
-
- if (spi->mode & ~MODEBITS) {
- dev_dbg(&spi->dev, "unsupported mode bits %x\n",
- spi->mode & ~MODEBITS);
- return -EINVAL;
- }
+ unsigned int bits = spi->bits_per_word;
+ u32 tmp;
if (!spi->max_speed_hz)
return -EINVAL;
@@ -1533,48 +1823,13 @@ static int pl022_setup(struct spi_device *spi)
chip_info = spi->controller_data;
if (chip_info == NULL) {
+ chip_info = &pl022_default_chip_info;
/* spi_board_info.controller_data not is supplied */
dev_dbg(&spi->dev,
"using default controller_data settings\n");
-
- chip_info =
- kzalloc(sizeof(struct pl022_config_chip), GFP_KERNEL);
-
- if (!chip_info) {
- dev_err(&spi->dev,
- "cannot allocate controller data\n");
- status = -ENOMEM;
- goto err_first_setup;
- }
-
- dev_dbg(&spi->dev, "allocated memory for controller data\n");
-
- /* Pointer back to the SPI device */
- chip_info->dev = &spi->dev;
- /*
- * Set controller data default values:
- * Polling is supported by default
- */
- chip_info->lbm = LOOPBACK_DISABLED;
- chip_info->com_mode = POLLING_TRANSFER;
- chip_info->iface = SSP_INTERFACE_MOTOROLA_SPI;
- chip_info->hierarchy = SSP_SLAVE;
- chip_info->slave_tx_disable = DO_NOT_DRIVE_TX;
- chip_info->endian_tx = SSP_TX_LSB;
- chip_info->endian_rx = SSP_RX_LSB;
- chip_info->data_size = SSP_DATA_BITS_12;
- chip_info->rx_lev_trig = SSP_RX_1_OR_MORE_ELEM;
- chip_info->tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC;
- chip_info->clk_phase = SSP_CLK_SECOND_EDGE;
- chip_info->clk_pol = SSP_CLK_POL_IDLE_LOW;
- chip_info->ctrl_len = SSP_BITS_8;
- chip_info->wait_state = SSP_MWIRE_WAIT_ZERO;
- chip_info->duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX;
- chip_info->cs_control = null_cs_control;
- } else {
+ } else
dev_dbg(&spi->dev,
"using user supplied controller_data settings\n");
- }
/*
* We can override with custom divisors, else we use the board
@@ -1584,29 +1839,48 @@ static int pl022_setup(struct spi_device *spi)
&& (0 == chip_info->clk_freq.scr)) {
status = calculate_effective_freq(pl022,
spi->max_speed_hz,
- &chip_info->clk_freq);
+ &clk_freq);
if (status < 0)
goto err_config_params;
} else {
- if ((chip_info->clk_freq.cpsdvsr % 2) != 0)
- chip_info->clk_freq.cpsdvsr =
- chip_info->clk_freq.cpsdvsr - 1;
+ memcpy(&clk_freq, &chip_info->clk_freq, sizeof(clk_freq));
+ if ((clk_freq.cpsdvsr % 2) != 0)
+ clk_freq.cpsdvsr =
+ clk_freq.cpsdvsr - 1;
+ }
+ if ((clk_freq.cpsdvsr < CPSDVR_MIN)
+ || (clk_freq.cpsdvsr > CPSDVR_MAX)) {
+ dev_err(&spi->dev,
+ "cpsdvsr is configured incorrectly\n");
+ goto err_config_params;
}
+
+
status = verify_controller_parameters(pl022, chip_info);
if (status) {
dev_err(&spi->dev, "controller data is incorrect");
goto err_config_params;
}
+
/* Now set controller state based on controller data */
chip->xfer_type = chip_info->com_mode;
- chip->cs_control = chip_info->cs_control;
-
- if (chip_info->data_size <= 8) {
- dev_dbg(&spi->dev, "1 <= n <=8 bits per word\n");
+ if (!chip_info->cs_control) {
+ chip->cs_control = null_cs_control;
+ dev_warn(&spi->dev,
+ "chip select function is NULL for this chip\n");
+ } else
+ chip->cs_control = chip_info->cs_control;
+
+ if (bits <= 3) {
+ /* PL022 doesn't support less than 4-bits */
+ status = -ENOTSUPP;
+ goto err_config_params;
+ } else if (bits <= 8) {
+ dev_dbg(&spi->dev, "4 <= n <=8 bits per word\n");
chip->n_bytes = 1;
chip->read = READING_U8;
chip->write = WRITING_U8;
- } else if (chip_info->data_size <= 16) {
+ } else if (bits <= 16) {
dev_dbg(&spi->dev, "9 <= n <= 16 bits per word\n");
chip->n_bytes = 2;
chip->read = READING_U16;
@@ -1623,6 +1897,7 @@ static int pl022_setup(struct spi_device *spi)
dev_err(&spi->dev,
"a standard pl022 can only handle "
"1 <= n <= 16 bit words\n");
+ status = -ENOTSUPP;
goto err_config_params;
}
}
@@ -1634,9 +1909,8 @@ static int pl022_setup(struct spi_device *spi)
chip->cpsr = 0;
if ((chip_info->com_mode == DMA_TRANSFER)
&& ((pl022->master_info)->enable_dma)) {
- chip->enable_dma = 1;
+ chip->enable_dma = true;
dev_dbg(&spi->dev, "DMA mode set in controller state\n");
- status = process_dma_info(chip_info, chip);
if (status < 0)
goto err_config_params;
SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
@@ -1644,7 +1918,7 @@ static int pl022_setup(struct spi_device *spi)
SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
SSP_DMACR_MASK_TXDMAE, 1);
} else {
- chip->enable_dma = 0;
+ chip->enable_dma = false;
dev_dbg(&spi->dev, "DMA mode NOT set in controller state\n");
SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED,
SSP_DMACR_MASK_RXDMAE, 0);
@@ -1652,10 +1926,12 @@ static int pl022_setup(struct spi_device *spi)
SSP_DMACR_MASK_TXDMAE, 1);
}
- chip->cpsr = chip_info->clk_freq.cpsdvsr;
+ chip->cpsr = clk_freq.cpsdvsr;
/* Special setup for the ST micro extended control registers */
if (pl022->vendor->extended_cr) {
+ u32 etx;
+
if (pl022->vendor->pl023) {
/* These bits are only in the PL023 */
SSP_WRITE_BITS(chip->cr1, chip_info->clkdelay,
@@ -1671,29 +1947,51 @@ static int pl022_setup(struct spi_device *spi)
SSP_WRITE_BITS(chip->cr1, chip_info->wait_state,
SSP_CR1_MASK_MWAIT_ST, 6);
}
- SSP_WRITE_BITS(chip->cr0, chip_info->data_size,
+ SSP_WRITE_BITS(chip->cr0, bits - 1,
SSP_CR0_MASK_DSS_ST, 0);
- SSP_WRITE_BITS(chip->cr1, chip_info->endian_rx,
- SSP_CR1_MASK_RENDN_ST, 4);
- SSP_WRITE_BITS(chip->cr1, chip_info->endian_tx,
- SSP_CR1_MASK_TENDN_ST, 5);
+
+ if (spi->mode & SPI_LSB_FIRST) {
+ tmp = SSP_RX_LSB;
+ etx = SSP_TX_LSB;
+ } else {
+ tmp = SSP_RX_MSB;
+ etx = SSP_TX_MSB;
+ }
+ SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_RENDN_ST, 4);
+ SSP_WRITE_BITS(chip->cr1, etx, SSP_CR1_MASK_TENDN_ST, 5);
SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig,
SSP_CR1_MASK_RXIFLSEL_ST, 7);
SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig,
SSP_CR1_MASK_TXIFLSEL_ST, 10);
} else {
- SSP_WRITE_BITS(chip->cr0, chip_info->data_size,
+ SSP_WRITE_BITS(chip->cr0, bits - 1,
SSP_CR0_MASK_DSS, 0);
SSP_WRITE_BITS(chip->cr0, chip_info->iface,
SSP_CR0_MASK_FRF, 4);
}
+
/* Stuff that is common for all versions */
- SSP_WRITE_BITS(chip->cr0, chip_info->clk_pol, SSP_CR0_MASK_SPO, 6);
- SSP_WRITE_BITS(chip->cr0, chip_info->clk_phase, SSP_CR0_MASK_SPH, 7);
- SSP_WRITE_BITS(chip->cr0, chip_info->clk_freq.scr, SSP_CR0_MASK_SCR, 8);
+ if (spi->mode & SPI_CPOL)
+ tmp = SSP_CLK_POL_IDLE_HIGH;
+ else
+ tmp = SSP_CLK_POL_IDLE_LOW;
+ SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPO, 6);
+
+ if (spi->mode & SPI_CPHA)
+ tmp = SSP_CLK_SECOND_EDGE;
+ else
+ tmp = SSP_CLK_FIRST_EDGE;
+ SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPH, 7);
+
+ SSP_WRITE_BITS(chip->cr0, clk_freq.scr, SSP_CR0_MASK_SCR, 8);
/* Loopback is available on all versions except PL023 */
- if (!pl022->vendor->pl023)
- SSP_WRITE_BITS(chip->cr1, chip_info->lbm, SSP_CR1_MASK_LBM, 0);
+ if (!pl022->vendor->pl023) {
+ if (spi->mode & SPI_LOOP)
+ tmp = LOOPBACK_ENABLED;
+ else
+ tmp = LOOPBACK_DISABLED;
+ SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_LBM, 0);
+ }
SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1);
SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2);
SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3);
@@ -1702,7 +2000,7 @@ static int pl022_setup(struct spi_device *spi)
spi_set_ctldata(spi, chip);
return status;
err_config_params:
- err_first_setup:
+ spi_set_ctldata(spi, NULL);
kfree(chip);
return status;
}
@@ -1723,7 +2021,7 @@ static void pl022_cleanup(struct spi_device *spi)
}
-static int __init
+static int __devinit
pl022_probe(struct amba_device *adev, struct amba_id *id)
{
struct device *dev = &adev->dev;
@@ -1764,12 +2062,21 @@ pl022_probe(struct amba_device *adev, struct amba_id *id)
master->setup = pl022_setup;
master->transfer = pl022_transfer;
+ /*
+ * Supports mode 0-3, loopback, and active low CS. Transfers are
+ * always MS bit first on the original pl022.
+ */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+ if (pl022->vendor->extended_cr)
+ master->mode_bits |= SPI_LSB_FIRST;
+
dev_dbg(&adev->dev, "BUSNO: %d\n", master->bus_num);
status = amba_request_regions(adev, NULL);
if (status)
goto err_no_ioregion;
+ pl022->phybase = adev->res.start;
pl022->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
if (pl022->virtbase == NULL) {
status = -ENOMEM;
@@ -1798,6 +2105,14 @@ pl022_probe(struct amba_device *adev, struct amba_id *id)
dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status);
goto err_no_irq;
}
+
+ /* Get DMA channels */
+ if (platform_info->enable_dma) {
+ status = pl022_dma_probe(pl022);
+ if (status != 0)
+ goto err_no_dma;
+ }
+
/* Initialize and start queue */
status = init_queue(pl022);
if (status != 0) {
@@ -1824,6 +2139,8 @@ pl022_probe(struct amba_device *adev, struct amba_id *id)
err_start_queue:
err_init_queue:
destroy_queue(pl022);
+ pl022_dma_remove(pl022);
+ err_no_dma:
free_irq(adev->irq[0], pl022);
err_no_irq:
clk_put(pl022->clk);
@@ -1838,7 +2155,7 @@ pl022_probe(struct amba_device *adev, struct amba_id *id)
return status;
}
-static int __exit
+static int __devexit
pl022_remove(struct amba_device *adev)
{
struct pl022 *pl022 = amba_get_drvdata(adev);
@@ -1854,6 +2171,7 @@ pl022_remove(struct amba_device *adev)
return status;
}
load_ssp_default_config(pl022);
+ pl022_dma_remove(pl022);
free_irq(adev->irq[0], pl022);
clk_disable(pl022->clk);
clk_put(pl022->clk);
@@ -1970,7 +2288,7 @@ static struct amba_driver pl022_driver = {
},
.id_table = pl022_ids,
.probe = pl022_probe,
- .remove = __exit_p(pl022_remove),
+ .remove = __devexit_p(pl022_remove),
.suspend = pl022_suspend,
.resume = pl022_resume,
};
@@ -1981,7 +2299,7 @@ static int __init pl022_init(void)
return amba_driver_register(&pl022_driver);
}
-module_init(pl022_init);
+subsys_initcall(pl022_init);
static void __exit pl022_exit(void)
{
diff --git a/drivers/spi/stm_msp.c b/drivers/spi/stm_msp.c
new file mode 100644
index 00000000000..07045525d8a
--- /dev/null
+++ b/drivers/spi/stm_msp.c
@@ -0,0 +1,1503 @@
+/*
+ * drivers/spi/stm_msp.c
+ *
+ * Copyright (C) 2006 STMicroelectronics Pvt. Ltd.
+ *
+ * Author: Sachin Verma <sachin.verma@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
+#include <linux/delay.h>
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/debug.h>
+#include <mach/irqs.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/spi/stm_msp.h>
+
+#define STM_MSP_NAME "STM_MSP"
+#define MSP_NAME "msp"
+#define DRIVER_DEBUG_PFX "MSP"
+#define DRIVER_DEBUG 0
+#define DRIVER_DBG "MSP"
+
+#define TRANSFER_TIMEOUT 5000
+
+#define MSP_WBITS(reg, val, mask, sb) \
+ ((reg) = (((reg) & ~(mask)) | (((val)<<(sb)) & (mask))))
+
+/* Queue State */
+#define QUEUE_RUNNING (0)
+#define QUEUE_STOPPED (1)
+
+/* MSP Controller Register Offsets */
+#define MSP_DR(r) (r + 0x000)
+#define MSP_GCR(r) (r + 0x004)
+#define MSP_TCF(r) (r + 0x008)
+#define MSP_RCF(r) (r + 0x00C)
+#define MSP_SRG(r) (r + 0x010)
+#define MSP_FLR(r) (r + 0x014)
+#define MSP_DMACR(r) (r + 0x018)
+#define MSP_IMSC(r) (r + 0x020)
+#define MSP_RIS(r) (r + 0x024)
+#define MSP_MIS(r) (r + 0x028)
+#define MSP_ICR(r) (r + 0x02C)
+#define MSP_MCR(r) (r + 0x030)
+#define MSP_RCV(r) (r + 0x034)
+#define MSP_RCM(r) (r + 0x038)
+#define MSP_TCE0(r) (r + 0x040)
+#define MSP_TCE1(r) (r + 0x044)
+#define MSP_TCE2(r) (r + 0x048)
+#define MSP_TCE3(r) (r + 0x04C)
+#define MSP_RCE0(r) (r + 0x060)
+#define MSP_RCE1(r) (r + 0x064)
+#define MSP_RCE2(r) (r + 0x068)
+#define MSP_RCE3(r) (r + 0x06C)
+#define MSP_PID0(r) (r + 0xFE0)
+#define MSP_PID1(r) (r + 0xFE4)
+#define MSP_PID2(r) (r + 0xFE8)
+#define MSP_PID3(r) (r + 0xFEC)
+
+/**
+ * msp_controller_cmd - To execute controller specific commands for MSP
+ * @drv_data: SPI driver private data structure
+ * @cmd: Command which is to be executed on the controller
+ *
+ *
+ */
+static int msp_controller_cmd(struct driver_data *drv_data, int cmd)
+{
+ int retval = 0;
+ struct msp_regs *msp_regs = NULL;
+
+ switch (cmd) {
+ case DISABLE_CONTROLLER:
+ {
+ stm_dbg2(DBG_ST.msp, ":::: DISABLE_CONTROLLER\n");
+ writel((readl(MSP_GCR(drv_data->regs)) &
+ (~(MSP_GCR_MASK_TXEN | MSP_GCR_MASK_RXEN))),
+ MSP_GCR(drv_data->regs));
+ break;
+ }
+ case ENABLE_CONTROLLER:
+ {
+ stm_dbg2(DBG_ST.msp, ":::: ENABLE_CONTROLLER\n");
+ writel((readl(MSP_GCR(drv_data->regs)) |
+ (MSP_GCR_MASK_TXEN | MSP_GCR_MASK_RXEN)),
+ MSP_GCR(drv_data->regs));
+ break;
+ }
+ case DISABLE_ALL_INTERRUPT:
+ {
+ stm_dbg2(DBG_ST.msp, ":::: DISABLE_ALL_INTERRUPT\n");
+ writel(DISABLE_ALL_MSP_INTERRUPTS,
+ MSP_IMSC(drv_data->regs));
+ break;
+ }
+ case ENABLE_ALL_INTERRUPT:
+ {
+ stm_dbg2(DBG_ST.msp, ":::: ENABLE_ALL_INTERRUPT\n");
+ writel(ENABLE_ALL_MSP_INTERRUPTS,
+ MSP_IMSC(drv_data->regs));
+ break;
+ }
+ case CLEAR_ALL_INTERRUPT:
+ {
+ stm_dbg2(DBG_ST.msp, ":::: CLEAR_ALL_INTERRUPT\n");
+ writel(CLEAR_ALL_MSP_INTERRUPTS,
+ MSP_ICR(drv_data->regs));
+ break;
+ }
+ case FLUSH_FIFO:
+ {
+ unsigned long limit = loops_per_jiffy << 1;
+ stm_dbg2(DBG_ST.msp, ":::: DATA FIFO is flushed\n");
+ do {
+ while (!(readl(MSP_FLR(drv_data->regs))
+ & MSP_FLR_MASK_RFE)) {
+ readl(MSP_DR(drv_data->regs));
+ }
+ } while ((readl(MSP_FLR(drv_data->regs)) &
+ (MSP_FLR_MASK_TBUSY | MSP_FLR_MASK_RBUSY))
+ && limit--);
+ retval = limit;
+ break;
+ }
+ case RESTORE_STATE:
+ {
+ msp_regs =
+ (struct msp_regs *)drv_data->cur_chip->ctr_regs;
+ stm_dbg2(DBG_ST.msp, ":::: RESTORE_STATE\n");
+ writel(msp_regs->gcr, MSP_GCR(drv_data->regs));
+ writel(msp_regs->tcf, MSP_TCF(drv_data->regs));
+ writel(msp_regs->rcf, MSP_RCF(drv_data->regs));
+ writel(msp_regs->srg, MSP_SRG(drv_data->regs));
+ writel(msp_regs->dmacr,
+ MSP_DMACR(drv_data->regs));
+ writel(DISABLE_ALL_MSP_INTERRUPTS,
+ MSP_IMSC(drv_data->regs));
+ writel(CLEAR_ALL_MSP_INTERRUPTS,
+ MSP_ICR(drv_data->regs));
+ break;
+ }
+ case LOAD_DEFAULT_CONFIG:
+ {
+ stm_dbg2(DBG_ST.msp, ":::: LOAD_DEFAULT_CONFIG\n");
+ writel(DEFAULT_MSP_REG_GCR, MSP_GCR(drv_data->regs));
+ writel(DEFAULT_MSP_REG_TCF, MSP_TCF(drv_data->regs));
+ writel(DEFAULT_MSP_REG_RCF, MSP_RCF(drv_data->regs));
+ writel(DEFAULT_MSP_REG_SRG, MSP_SRG(drv_data->regs));
+ writel(DEFAULT_MSP_REG_DMACR,
+ MSP_DMACR(drv_data->regs));
+ writel(DISABLE_ALL_MSP_INTERRUPTS,
+ MSP_IMSC(drv_data->regs));
+ writel(CLEAR_ALL_MSP_INTERRUPTS,
+ MSP_ICR(drv_data->regs));
+ break;
+ }
+ default:
+ {
+ stm_dbg2(DBG_ST.msp, ":::: unknown command\n");
+ retval = -1;
+ break;
+ }
+ }
+ return retval;
+}
+
+/**
+ * giveback - current spi_message is over, schedule next spi_message
+ * @message: current SPI message
+ * @drv_data: spi driver private data structure
+ *
+ * current spi_message is over, schedule next spi_message and call
+ * callback of this msg.
+ */
+static void giveback(struct spi_message *message, struct driver_data *drv_data)
+{
+ struct spi_transfer *last_transfer;
+ unsigned long flags;
+ struct spi_message *msg;
+ void (*curr_cs_control) (u32 command);
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+ msg = drv_data->cur_msg;
+
+ curr_cs_control = drv_data->cur_chip->cs_control;
+ drv_data->cur_msg = NULL;
+ drv_data->cur_transfer = NULL;
+ drv_data->cur_chip = NULL;
+#ifdef CONFIG_SPI_WORKQUEUE
+ queue_work(drv_data->workqueue, &drv_data->spi_work);
+#else
+ schedule_work(&drv_data->spi_work);
+#endif
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ last_transfer = list_entry(msg->transfers.prev,
+ struct spi_transfer, transfer_list);
+ if (!last_transfer->cs_change)
+ curr_cs_control(SPI_CHIP_DESELECT);
+ msg->state = NULL;
+ if (msg->complete)
+ msg->complete(msg->context);
+ msp_controller_cmd(drv_data, DISABLE_CONTROLLER);
+ clk_disable(drv_data->clk);
+}
+
+/**
+ * next_transfer - Move to the Next transfer in the current spi message
+ * @drv_data: spi driver private data structure
+ *
+ * This function moves though the linked list of spi transfers in the
+ * current spi message and returns with the state of current spi
+ * message i.e whether its last transfer is done(DONE_STATE) or
+ * Next transfer is ready(RUNNING_STATE)
+ */
+static void *next_transfer(struct driver_data *drv_data)
+{
+ struct spi_message *msg = drv_data->cur_msg;
+ struct spi_transfer *trans = drv_data->cur_transfer;
+ /* Move to next transfer */
+ if (trans->transfer_list.next != &msg->transfers) {
+ drv_data->cur_transfer =
+ list_entry(trans->transfer_list.next,
+ struct spi_transfer, transfer_list);
+ return RUNNING_STATE;
+ }
+ return DONE_STATE;
+}
+
+static void do_interrupt_transfer(void *data)
+{
+ struct driver_data *drv_data = (struct driver_data *)data;
+
+ drv_data->tx = (void *)drv_data->cur_transfer->tx_buf;
+ drv_data->tx_end = drv_data->tx + drv_data->cur_transfer->len;
+ drv_data->rx = (void *)drv_data->cur_transfer->rx_buf;
+ drv_data->rx_end = drv_data->rx + drv_data->cur_transfer->len;
+
+ drv_data->write = drv_data->tx ?
+ drv_data->cur_chip->write : drv_data->cur_chip->null_write;
+ drv_data->read = drv_data->rx ?
+ drv_data->cur_chip->read : drv_data->cur_chip->null_read;
+
+ drv_data->cur_chip->cs_control(SPI_CHIP_SELECT);
+ msp_controller_cmd(drv_data, ENABLE_ALL_INTERRUPT);
+ msp_controller_cmd(drv_data, ENABLE_CONTROLLER);
+}
+
+static void do_polling_transfer(void *data)
+{
+ struct driver_data *drv_data = (struct driver_data *)data;
+ struct spi_message *message = NULL;
+ struct spi_transfer *transfer = NULL;
+ struct spi_transfer *previous = NULL;
+ struct chip_data *chip;
+ unsigned long limit = 0;
+ u32 timer_expire = 0;
+
+ chip = drv_data->cur_chip;
+ message = drv_data->cur_msg;
+
+ while (message->state != DONE_STATE) {
+ /* Handle for abort */
+ if (message->state == ERROR_STATE)
+ break;
+ transfer = drv_data->cur_transfer;
+
+ /* Delay if requested at end of transfer */
+ if (message->state == RUNNING_STATE) {
+ previous =
+ list_entry(transfer->transfer_list.prev,
+ struct spi_transfer, transfer_list);
+ if (previous->delay_usecs)
+ udelay(previous->delay_usecs);
+ if (previous->cs_change)
+ drv_data->cur_chip->cs_control(SPI_CHIP_SELECT);
+ } else {
+ /* START_STATE */
+ message->state = RUNNING_STATE;
+ drv_data->cur_chip->cs_control(SPI_CHIP_SELECT);
+ }
+
+ /*Configuration Changing Per Transfer */
+ drv_data->tx = (void *)transfer->tx_buf;
+ drv_data->tx_end = drv_data->tx + drv_data->cur_transfer->len;
+ drv_data->rx = (void *)transfer->rx_buf;
+ drv_data->rx_end = drv_data->rx + drv_data->cur_transfer->len;
+
+ drv_data->write = drv_data->tx ?
+ drv_data->cur_chip->write :
+ drv_data->cur_chip->null_write;
+ drv_data->read = drv_data->rx ?
+ drv_data->cur_chip->read :
+ drv_data->cur_chip->null_read;
+ drv_data->delay = drv_data->cur_chip->delay;
+
+ msp_controller_cmd(drv_data, FLUSH_FIFO);
+ msp_controller_cmd(drv_data, ENABLE_CONTROLLER);
+
+ timer_expire = drv_data->cur_transfer->len / 1024;
+ if (!timer_expire)
+ timer_expire = TRANSFER_TIMEOUT;
+ else
+ timer_expire =
+ (drv_data->cur_transfer->len / 1024) * 5000;
+ drv_data->spi_notify_timer.expires =
+ jiffies + msecs_to_jiffies(timer_expire);
+ add_timer(&drv_data->spi_notify_timer);
+
+ stm_dbg(DBG_ST.spi, ":::: POLLING TRANSFER ONGOING ...\n");
+ while (drv_data->tx < drv_data->tx_end) {
+ msp_controller_cmd(drv_data, DISABLE_CONTROLLER);
+ drv_data->read(drv_data);
+ drv_data->write(drv_data);
+ msp_controller_cmd(drv_data, ENABLE_CONTROLLER);
+ if (drv_data->delay)
+ drv_data->delay(drv_data);
+ if (drv_data->spi_io_error == 1)
+ break;
+ }
+
+ del_timer(&drv_data->spi_notify_timer);
+ if (drv_data->spi_io_error == 1)
+ goto out;
+
+ limit = loops_per_jiffy << 1;
+
+ while ((drv_data->rx < drv_data->rx_end) && (limit--))
+ drv_data->read(drv_data);
+
+ /* Update total byte transfered */
+ message->actual_length += drv_data->cur_transfer->len;
+ if (drv_data->cur_transfer->cs_change)
+ drv_data->cur_chip->cs_control(SPI_CHIP_DESELECT);
+ msp_controller_cmd(drv_data, DISABLE_CONTROLLER);
+
+ /* Move to next transfer */
+ message->state = next_transfer(drv_data);
+ }
+
+out:
+ /* Handle end of message */
+ if (message->state == DONE_STATE)
+ message->status = 0;
+ else
+ message->status = -EIO;
+
+ giveback(message, drv_data);
+ drv_data->spi_io_error = 0; /* Reset state for further transfers */
+
+ return;
+}
+
+/**
+ * pump_messages - Workqueue function which processes spi message queue
+ * @data: pointer to private data of spi driver
+ *
+ * This function checks if there is any spi message in the queue that
+ * needs processing and delegate control to appropriate function
+ * do_polling_transfer()/do_interrupt_transfer()/do_dma_transfer()
+ * based on the kind of the transfer
+ *
+ */
+static void pump_messages(struct work_struct *work)
+{
+ struct driver_data *drv_data = container_of(work,
+ struct driver_data, spi_work);
+ unsigned long flags;
+
+ /* Lock queue and check for queue work */
+ spin_lock_irqsave(&drv_data->lock, flags);
+ if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
+ stm_dbg(DBG_ST.spi, ":::: work_queue: Queue Empty\n");
+ drv_data->busy = 0;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return;
+ }
+ /* Make sure we are not already running a message */
+ if (drv_data->cur_msg) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return;
+ }
+
+ clk_enable(drv_data->clk);
+
+ /* Extract head of queue */
+ drv_data->cur_msg =
+ list_entry(drv_data->queue.next, struct spi_message, queue);
+
+ list_del_init(&drv_data->cur_msg->queue);
+ drv_data->busy = 1;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ /* Initial message state */
+ drv_data->cur_msg->state = START_STATE;
+ drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
+ struct spi_transfer, transfer_list);
+
+ /* Setup the SPI using the per chip configuration */
+ drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
+ msp_controller_cmd(drv_data, RESTORE_STATE);
+ msp_controller_cmd(drv_data, FLUSH_FIFO);
+
+ if (drv_data->cur_chip->xfer_type == SPI_POLLING_TRANSFER)
+ do_polling_transfer(drv_data);
+ else if (drv_data->cur_chip->xfer_type == SPI_INTERRUPT_TRANSFER)
+ do_interrupt_transfer(drv_data);
+}
+
+/**
+ * pump_transfers - Tasklet function which schedules next interrupt xfer
+ * @data: spi driver private data structure
+ *
+ */
+static void pump_transfers(unsigned long data)
+{
+ struct driver_data *drv_data = (struct driver_data *)data;
+ struct spi_message *message = NULL;
+ struct spi_transfer *transfer = NULL;
+ struct spi_transfer *previous = NULL;
+
+ message = drv_data->cur_msg;
+ /* Handle for abort */
+ if (message->state == ERROR_STATE) {
+ message->status = -EIO;
+ giveback(message, drv_data);
+ return;
+ }
+ /* Handle end of message */
+ if (message->state == DONE_STATE) {
+ message->status = 0;
+ giveback(message, drv_data);
+ return;
+ }
+ transfer = drv_data->cur_transfer;
+ /* Delay if requested at end of transfer */
+ if (message->state == RUNNING_STATE) {
+ previous =
+ list_entry(transfer->transfer_list.prev,
+ struct spi_transfer, transfer_list);
+ if (previous->delay_usecs)
+ udelay(previous->delay_usecs);
+ if (previous->cs_change)
+ drv_data->cur_chip->cs_control(SPI_CHIP_SELECT);
+ } else {
+ /* START_STATE */
+ message->state = RUNNING_STATE;
+ }
+ drv_data->tx = (void *)transfer->tx_buf;
+ drv_data->tx_end = drv_data->tx + drv_data->cur_transfer->len;
+ drv_data->rx = (void *)transfer->rx_buf;
+ drv_data->rx_end = drv_data->rx + drv_data->cur_transfer->len;
+
+ drv_data->write = drv_data->tx ?
+ drv_data->cur_chip->write : drv_data->cur_chip->null_write;
+ drv_data->read = drv_data->rx ?
+ drv_data->cur_chip->read : drv_data->cur_chip->null_read;
+
+ msp_controller_cmd(drv_data, FLUSH_FIFO);
+ msp_controller_cmd(drv_data, ENABLE_ALL_INTERRUPT);
+}
+
+/**
+ * spi_notify - Handles Polling hang issue over spi bus.
+ * @data: main driver data
+ * Context: Process.
+ *
+ * This is used to handle error condition in transfer and receive function used
+ * in polling mode.
+ * Sometimes due to passing wrong protocol desc , polling transfer may hang.
+ * To prevent this, timer is added.
+ *
+ * Returns void.
+ */
+static void spi_notify(unsigned long data)
+{
+ struct driver_data *dspi = (struct driver_data *)data;
+ dspi->spi_io_error = 1;
+ printk(KERN_ERR
+ "Polling is taking time, maybe device not responding\n");
+ del_timer(&dspi->spi_notify_timer);
+}
+
+/**
+ * stm_msp_transfer - transfer function registered to SPI master framework
+ * @spi: spi device which is requesting transfer
+ * @msg: spi message which is to handled is queued to driver queue
+ *
+ * This function is registered to the SPI framework for this SPI master
+ * controller. It will queue the spi_message in the queue of driver if
+ * the queue is not stopped and return.
+ */
+static int stm_msp_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ unsigned long flags;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ if (drv_data->run == QUEUE_STOPPED) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return -ESHUTDOWN;
+ }
+ stm_dbg(DBG_ST.spi, ":::: Regular request (No infinite DMA ongoing)\n");
+
+ msg->actual_length = 0;
+ msg->status = -EINPROGRESS;
+ msg->state = START_STATE;
+
+ list_add_tail(&msg->queue, &drv_data->queue);
+ if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
+#ifdef CONFIG_SPI_WORKQUEUE
+ queue_work(drv_data->workqueue, &drv_data->spi_work);
+#else
+ schedule_work(&drv_data->spi_work);
+#endif
+
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return 0;
+}
+
+/**
+ * stm_msp_cleanup - cleanup function registered to SPI master framework
+ * @spi: spi device which is requesting cleanup
+ *
+ * This function is registered to the SPI framework for this SPI master
+ * controller. It will free the runtime state of chip.
+ */
+static void stm_msp_cleanup(struct spi_device *spi)
+{
+ struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi);
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ struct spi_master *master;
+ master = drv_data->master;
+
+ if (chip) {
+ kfree(chip->ctr_regs);
+ kfree(chip);
+ spi_set_ctldata(spi, NULL);
+ }
+}
+
+/**
+ * null_cs_control - Dummy chip select function
+ * @command: select/delect the chip
+ *
+ * If no chip select function is provided by client this is used as dummy
+ * chip select
+ */
+static void null_cs_control(u32 command)
+{
+ stm_dbg(DBG_ST.spi, "::::Dummy chip select control\n");
+}
+
+static int init_queue(struct driver_data *drv_data)
+{
+ INIT_LIST_HEAD(&drv_data->queue);
+ spin_lock_init(&drv_data->lock);
+
+ drv_data->run = QUEUE_STOPPED;
+ drv_data->busy = 0;
+
+ tasklet_init(&drv_data->pump_transfers, pump_transfers,
+ (unsigned long)drv_data);
+ INIT_WORK(&drv_data->spi_work, pump_messages);
+#ifdef CONFIG_SPI_WORKQUEUE
+ drv_data->workqueue = create_singlethread_workqueue(
+ dev_name(&drv_data->master->dev));
+
+
+ if (drv_data->workqueue == NULL)
+ return -EBUSY;
+#endif
+ init_timer(&drv_data->spi_notify_timer);
+ drv_data->spi_notify_timer.expires = jiffies + msecs_to_jiffies(1000);
+ drv_data->spi_notify_timer.function = spi_notify;
+ drv_data->spi_notify_timer.data = (unsigned long)drv_data;
+
+ return 0;
+}
+
+static int start_queue(struct driver_data *drv_data)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&drv_data->lock, flags);
+ if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return -EBUSY;
+ }
+ drv_data->run = QUEUE_RUNNING;
+ drv_data->cur_msg = NULL;
+ drv_data->cur_transfer = NULL;
+ drv_data->cur_chip = NULL;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ /*queue_work(drv_data->workqueue, &drv_data->pump_messages);*/
+ /*schedule_work(&drv_data->spi_work);*/
+ return 0;
+}
+
+static int stop_queue(struct driver_data *drv_data)
+{
+ unsigned long flags;
+ unsigned limit = 500;
+ int status = 0;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ /* This is a bit lame, but is optimized for the common execution path.
+ * A wait_queue on the drv_data->busy could be used, but then the common
+ * execution path (pump_messages) would be required to call wake_up or
+ * friends on every SPI message. Do this instead */
+ drv_data->run = QUEUE_STOPPED;
+ while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ msleep(10);
+ spin_lock_irqsave(&drv_data->lock, flags);
+ }
+ if (!list_empty(&drv_data->queue) || drv_data->busy)
+ status = -EBUSY;
+
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ return status;
+}
+
+static int destroy_queue(struct driver_data *drv_data)
+{
+ int status;
+ status = stop_queue(drv_data);
+ if (status != 0)
+ return status;
+#ifdef CONFIG_SPI_WORKQUEUE
+ destroy_workqueue(drv_data->workqueue);
+#endif
+ del_timer_sync(&drv_data->spi_notify_timer);
+ return 0;
+}
+
+/**
+ * msp_null_writer - To Write Dummy Data in Data register
+ * @drv_data: spi driver private data structure
+ *
+ * This function is set as a write function for transfer which have
+ * Tx transfer buffer as NULL. It simply writes '0' in the Data
+ * register
+ */
+static void msp_null_writer(struct driver_data *drv_data)
+{
+ u32 cur_write = 0;
+ u32 status;
+ while (1) {
+ status = readl(MSP_FLR(drv_data->regs));
+ if ((status & MSP_FLR_MASK_TFU) ||
+ (drv_data->tx >= drv_data->tx_end))
+ return;
+ writel(0x0, MSP_DR(drv_data->regs));
+ drv_data->tx += (drv_data->cur_chip->n_bytes);
+ cur_write++;
+ if (cur_write == 8)
+ return;
+ }
+}
+
+/**
+ * msp_null_reader - To read data from Data register and discard it
+ * @drv_data: spi driver private data structure
+ *
+ * This function is set as a reader function for transfer which have
+ * Rx Transfer buffer as null. Read Data is rejected
+ *
+ */
+static void msp_null_reader(struct driver_data *drv_data)
+{
+ u32 status;
+ while (1) {
+ status = readl(MSP_FLR(drv_data->regs));
+ if ((status & MSP_FLR_MASK_RFE) ||
+ (drv_data->rx >= drv_data->rx_end))
+ return;
+ readl(MSP_DR(drv_data->regs));
+ drv_data->rx += (drv_data->cur_chip->n_bytes);
+ }
+}
+
+/**
+ * msp_u8_writer - Write FIFO data in Data register as a 8 Bit Data
+ * @drv_data: spi driver private data structure
+ *
+ * This function writes data in Tx FIFO till it is not full
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary write ptr tx in drv_data which maintains
+ * current write position in transfer buffer. we do not write data more than
+ * FIFO depth
+ */
+void msp_u8_writer(struct driver_data *drv_data)
+{
+ u32 cur_write = 0;
+ u32 status;
+ while (1) {
+ status = readl(MSP_FLR(drv_data->regs));
+ if ((status & MSP_FLR_MASK_TFU)
+ || (drv_data->tx >= drv_data->tx_end))
+ return;
+ writel((u32) (*(u8 *) (drv_data->tx)), MSP_DR(drv_data->regs));
+ drv_data->tx += (drv_data->cur_chip->n_bytes);
+ cur_write++;
+ if (cur_write == MSP_FIFO_DEPTH)
+ return;
+ }
+}
+
+/**
+ * msp_u8_reader - Read FIFO data in Data register as a 8 Bit Data
+ * @drv_data: spi driver private data structure
+ *
+ * This function reads data in Rx FIFO till it is not empty
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary Read ptr rx in drv_data which maintains
+ * current read position in transfer buffer
+ */
+void msp_u8_reader(struct driver_data *drv_data)
+{
+ u32 status;
+ while (1) {
+ status = readl(MSP_FLR(drv_data->regs));
+ if ((status & MSP_FLR_MASK_RFE)
+ || (drv_data->rx >= drv_data->rx_end))
+ return;
+ *(u8 *) (drv_data->rx) = (u8) readl(MSP_DR(drv_data->regs));
+ drv_data->rx += (drv_data->cur_chip->n_bytes);
+ }
+}
+
+/**
+ * msp_u16_writer - Write FIFO data in Data register as a 16 Bit Data
+ * @drv_data: spi driver private data structure
+ *
+ * This function writes data in Tx FIFO till it is not full
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary write ptr tx in drv_data which maintains
+ * current write position in transfer buffer. we do not write data more than
+ * FIFO depth
+ */
+void msp_u16_writer(struct driver_data *drv_data)
+{
+ u32 cur_write = 0;
+ u32 status;
+ while (1) {
+ status = readl(MSP_FLR(drv_data->regs));
+
+ if ((status & MSP_FLR_MASK_TFU)
+ || (drv_data->tx >= drv_data->tx_end))
+ return;
+ writel((u32) (*(u16 *) (drv_data->tx)), MSP_DR(drv_data->regs));
+ drv_data->tx += (drv_data->cur_chip->n_bytes);
+ cur_write++;
+ if (cur_write == MSP_FIFO_DEPTH)
+ return;
+ }
+}
+
+/**
+ * msp_u16_reader - Read FIFO data in Data register as a 16 Bit Data
+ * @drv_data: spi driver private data structure
+ *
+ * This function reads data in Rx FIFO till it is not empty
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary Read ptr rx in drv_data which maintains
+ * current read position in transfer buffer
+ */
+void msp_u16_reader(struct driver_data *drv_data)
+{
+ u32 status;
+ while (1) {
+ status = readl(MSP_FLR(drv_data->regs));
+ if ((status & MSP_FLR_MASK_RFE)
+ || (drv_data->rx >= drv_data->rx_end))
+ return;
+ *(u16 *) (drv_data->rx) = (u16) readl(MSP_DR(drv_data->regs));
+ drv_data->rx += (drv_data->cur_chip->n_bytes);
+ }
+}
+
+/**
+ * msp_u32_writer - Write FIFO data in Data register as a 32 Bit Data
+ * @drv_data: spi driver private data structure
+ *
+ * This function writes data in Tx FIFO till it is not full
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary write ptr tx in drv_data which maintains
+ * current write position in transfer buffer. we do not write data more than
+ * FIFO depth
+ */
+void msp_u32_writer(struct driver_data *drv_data)
+{
+ u32 cur_write = 0;
+ u32 status;
+ while (1) {
+ status = readl(MSP_FLR(drv_data->regs));
+
+ if ((status & MSP_FLR_MASK_TFU)
+ || (drv_data->tx >= drv_data->tx_end))
+ return;
+ /*Write Data to Data Register */
+ writel(*(u32 *) (drv_data->tx), MSP_DR(drv_data->regs));
+ drv_data->tx += (drv_data->cur_chip->n_bytes);
+ cur_write++;
+ if (cur_write == MSP_FIFO_DEPTH)
+ return;
+ }
+}
+
+/**
+ * msp_u32_reader - Read FIFO data in Data register as a 32 Bit Data
+ * @drv_data: spi driver private data structure
+ *
+ * This function reads data in Rx FIFO till it is not empty
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary Read ptr rx in drv_data which maintains
+ * current read position in transfer buffer
+ */
+void msp_u32_reader(struct driver_data *drv_data)
+{
+ u32 status;
+ while (1) {
+ status = readl(MSP_FLR(drv_data->regs));
+ if ((status & MSP_FLR_MASK_RFE)
+ || (drv_data->rx >= drv_data->rx_end))
+ return;
+ *(u32 *) (drv_data->rx) = readl(MSP_DR(drv_data->regs));
+ drv_data->rx += (drv_data->cur_chip->n_bytes);
+ }
+}
+
+static irqreturn_t stm_msp_interrupt_handler(int irq, void *dev_id)
+{
+ struct driver_data *drv_data = (struct driver_data *)dev_id;
+ struct spi_message *msg = drv_data->cur_msg;
+ u32 irq_status = 0;
+ u32 flag = 0;
+ if (!msg) {
+ stm_error("bad message state in interrupt handler");
+ /* Never fail */
+ return IRQ_HANDLED;
+ }
+ /*Read the Interrupt Status Register */
+ irq_status = readl(MSP_MIS(drv_data->regs));
+
+ if (irq_status) {
+ if (irq_status & MSP_MIS_MASK_ROEMIS) { /*Overrun interrupt */
+ /*Bail-out our Data has been corrupted */
+ stm_dbg3(DBG_ST.msp, ":::: Received ROR interrupt\n");
+ msp_controller_cmd(drv_data, DISABLE_ALL_INTERRUPT);
+ msp_controller_cmd(drv_data, CLEAR_ALL_INTERRUPT);
+ msp_controller_cmd(drv_data, DISABLE_CONTROLLER);
+ msg->state = ERROR_STATE;
+ tasklet_schedule(&drv_data->pump_transfers);
+ return IRQ_HANDLED;
+ }
+
+ drv_data->read(drv_data);
+ drv_data->write(drv_data);
+
+ if ((drv_data->tx == drv_data->tx_end) && (flag == 0)) {
+ flag = 1;
+ /*Disable Transmit interrupt */
+ writel(readl(MSP_IMSC(drv_data->regs)) &
+ (~MSP_IMSC_MASK_TXIM) & (~MSP_IMSC_MASK_TFOIM),
+ (drv_data->regs + 0x14));
+ }
+ /*Clearing any Xmit underrun error. overrun already handled */
+ msp_controller_cmd(drv_data, CLEAR_ALL_INTERRUPT);
+
+ if (drv_data->rx == drv_data->rx_end) {
+ msp_controller_cmd(drv_data, DISABLE_ALL_INTERRUPT);
+ msp_controller_cmd(drv_data, CLEAR_ALL_INTERRUPT);
+ stm_dbg3(DBG_ST.msp,
+ ":::: Interrupt transfer Completed...\n");
+ /* Update total bytes transfered */
+ msg->actual_length += drv_data->cur_transfer->len;
+ if (drv_data->cur_transfer->cs_change)
+ drv_data->cur_chip->
+ cs_control(SPI_CHIP_DESELECT);
+ /* Move to next transfer */
+ msg->state = next_transfer(drv_data);
+ tasklet_schedule(&drv_data->pump_transfers);
+ return IRQ_HANDLED;
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static int verify_msp_controller_parameters(struct msp_controller
+ *chip_info)
+{
+ /*FIXME: check clock params */
+ if ((chip_info->lbm != SPI_LOOPBACK_ENABLED)
+ && (chip_info->lbm != SPI_LOOPBACK_DISABLED)) {
+ stm_dbg(DBG_ST.msp,
+ ":::: Loopback Mode is configured incorrectly\n");
+ return -1;
+ }
+ if (chip_info->iface != SPI_INTERFACE_MOTOROLA_SPI) {
+ stm_dbg(DBG_ST.msp,
+ ":::: Interface is configured incorrectly."
+ "This controller supports only MOTOROLA SPI\n");
+ return -1;
+ }
+ if ((chip_info->hierarchy != SPI_MASTER)
+ && (chip_info->hierarchy != SPI_SLAVE)) {
+ stm_dbg(DBG_ST.msp,
+ ":::: hierarchy is configured incorrectly\n");
+ return -1;
+ }
+ if ((chip_info->endian_rx != SPI_FIFO_MSB)
+ && (chip_info->endian_rx != SPI_FIFO_LSB)) {
+ stm_dbg(DBG_ST.msp,
+ ":::: Rx FIFO endianess is configured incorrectly\n");
+ return -1;
+ }
+ if ((chip_info->endian_tx != SPI_FIFO_MSB)
+ && (chip_info->endian_tx != SPI_FIFO_LSB)) {
+ stm_dbg(DBG_ST.msp,
+ ":::: Tx FIFO endianess is configured incorrectly\n");
+ return -1;
+ }
+ if ((chip_info->data_size < MSP_DATA_BITS_8)
+ || (chip_info->data_size > MSP_DATA_BITS_32)) {
+ stm_dbg(DBG_ST.msp,
+ ":::: MSP DATA Size is configured incorrectly\n");
+ return -1;
+ }
+ if ((chip_info->com_mode != SPI_INTERRUPT_TRANSFER)
+ && (chip_info->com_mode != SPI_POLLING_TRANSFER)) {
+ stm_dbg(DBG_ST.msp,
+ ":::: Communication mode is configured incorrectly\n");
+ return -1;
+ }
+ if (chip_info->iface == SPI_INTERFACE_MOTOROLA_SPI) {
+ if (((chip_info->proto_params).moto.clk_phase !=
+ SPI_CLK_ZERO_CYCLE_DELAY)
+ && ((chip_info->proto_params).moto.clk_phase !=
+ SPI_CLK_HALF_CYCLE_DELAY)) {
+ stm_dbg(DBG_ST.msp,
+ ":::: Clock Phase is configured incorrectly\n");
+ return -1;
+ }
+ if (((chip_info->proto_params).moto.clk_pol !=
+ SPI_CLK_POL_IDLE_LOW)
+ && ((chip_info->proto_params).moto.clk_pol !=
+ SPI_CLK_POL_IDLE_HIGH)) {
+ stm_dbg(DBG_ST.msp,
+ ":::: Clk Polarity configured incorrectly\n");
+ return -1;
+ }
+ }
+ if (chip_info->cs_control == NULL) {
+ stm_dbg(DBG_ST.msp,
+ "::::Chip Select Function is NULL for this chip\n");
+ chip_info->cs_control = null_cs_control;
+ }
+ return 0;
+}
+
+static struct msp_controller *allocate_default_msp_chip_cfg(
+ struct spi_device *spi)
+{
+ struct msp_controller *chip_info;
+
+ /* spi_board_info.controller_data not is supplied */
+ chip_info = kzalloc(sizeof(struct msp_controller), GFP_KERNEL);
+ if (!chip_info) {
+ stm_error("setup - cannot allocate controller data");
+ return NULL;
+ }
+ stm_dbg(DBG_ST.msp, ":::: Allocated Memory for controller data\n");
+
+ chip_info->lbm = SPI_LOOPBACK_DISABLED;
+ chip_info->com_mode = SPI_POLLING_TRANSFER;
+ chip_info->iface = SPI_INTERFACE_MOTOROLA_SPI;
+ chip_info->hierarchy = SPI_MASTER;
+ chip_info->endian_tx = SPI_FIFO_LSB;
+ chip_info->endian_rx = SPI_FIFO_LSB;
+ chip_info->data_size = MSP_DATA_BITS_32;
+
+ if (spi->max_speed_hz != 0)
+ chip_info->freq = spi->max_speed_hz;
+ else
+ chip_info->freq = 48000;
+
+ (chip_info->proto_params).moto.clk_phase = SPI_CLK_HALF_CYCLE_DELAY;
+ (chip_info->proto_params).moto.clk_pol = SPI_CLK_POL_IDLE_LOW;
+ chip_info->cs_control = null_cs_control;
+ return chip_info;
+}
+
+static void msp_delay(struct driver_data *drv_data)
+{
+ udelay(15);
+ while (readl(MSP_FLR(drv_data->regs))
+ & (MSP_FLR_MASK_RBUSY | MSP_FLR_MASK_TBUSY))
+ udelay(1);
+}
+
+/**
+ * stm_msp_setup - setup function registered to SPI master framework
+ * @spi: spi device which is requesting setup
+ *
+ * This function is registered to the SPI framework for this SPI master
+ * controller. If it is the first time when setup is called by this device
+ * , this function will initialize the runtime state for this chip and save
+ * the same in the device structure. Else it will update the runtime info
+ * with the updated chip info.
+ */
+static int stm_msp_setup(struct spi_device *spi)
+{
+ struct msp_controller *chip_info;
+ struct chip_data *curr_cfg;
+ struct spi_master *master;
+ int status = 0;
+ u16 sckdiv = 0;
+ s16 bus_num = 0;
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ struct msp_regs *msp_regs;
+ master = drv_data->master;
+ bus_num = master->bus_num - 1;
+
+ /* Get controller data */
+ chip_info = spi->controller_data;
+ /* Get controller_state */
+ curr_cfg = spi_get_ctldata(spi);
+
+ if (curr_cfg == NULL) {
+ curr_cfg = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+ if (!curr_cfg) {
+ stm_error("setup - cannot allocate controller state");
+ return -ENOMEM;
+ }
+ curr_cfg->chip_id = spi->chip_select;
+ curr_cfg->ctr_regs = kzalloc(sizeof(struct msp_regs),
+ GFP_KERNEL);
+ if (curr_cfg->ctr_regs == NULL) {
+ stm_error("setup - cannot allocate mem for regs");
+ goto err_first_setup;
+ }
+ stm_dbg(DBG_ST.msp, ":::: chip Id = %d\n", curr_cfg->chip_id);
+
+ if (chip_info == NULL) {
+ chip_info = allocate_default_msp_chip_cfg(spi);
+ if (!chip_info) {
+ stm_error("setup - cant allocate cntlr data");
+ status = -ENOMEM;
+ goto err_first_setup;
+ }
+ spi->controller_data = chip_info;
+ }
+ }
+
+ if (chip_info->freq == 0) {
+ /*Calculate Specific Freq. */
+ if ((MSP_INTERNAL_CLK ==
+ chip_info->clk_freq.clk_src)
+ || (MSP_EXTERNAL_CLK ==
+ chip_info->clk_freq.clk_src)) {
+ sckdiv = chip_info->clk_freq.sckdiv;
+ } else {
+ status = -1;
+ stm_error("setup - controller clock data is incorrect");
+ goto err_config_params;
+ }
+ } else {
+ /*Calculate Effective Freq. */
+ sckdiv = ((DEFAULT_MSP_CLK) / (chip_info->freq)) - 1;
+ if (sckdiv > MAX_SCKDIV) {
+ stm_dbg(DBG_ST.msp,
+ "SPI: Cannot set frequency less than 48Khz,"
+ "setting lowest(48 Khz)\n");
+ sckdiv = MAX_SCKDIV;
+ }
+ }
+
+ status = verify_msp_controller_parameters(chip_info);
+ if (status) {
+ stm_error("setup - controller data is incorrect");
+ goto err_config_params;
+ }
+
+ /* Now set controller state based on controller data */
+ curr_cfg->xfer_type = chip_info->com_mode;
+ curr_cfg->cs_control = chip_info->cs_control;
+ curr_cfg->delay = msp_delay;
+ curr_cfg->null_write = msp_null_writer;
+ curr_cfg->null_read = msp_null_reader;
+
+ /*FIXME: write all 8 & 16 bit functions */
+ if (chip_info->data_size <= MSP_DATA_BITS_8) {
+ stm_dbg(DBG_ST.msp, ":::: Less than 8 bits per word....\n");
+ curr_cfg->n_bytes = 1;
+ curr_cfg->read = msp_u8_reader;
+ curr_cfg->write = msp_u8_writer;
+ } else if (chip_info->data_size <= MSP_DATA_BITS_16) {
+ stm_dbg(DBG_ST.msp, ":::: Less than 16 bits per word....\n");
+ curr_cfg->n_bytes = 2;
+ curr_cfg->read = msp_u16_reader;
+ curr_cfg->write = msp_u16_writer;
+ } else {
+ stm_dbg(DBG_ST.msp, ":::: Less than 32 bits per word....\n");
+ curr_cfg->n_bytes = 4;
+ curr_cfg->read = msp_u32_reader;
+ curr_cfg->write = msp_u32_writer;
+ }
+
+ /*Now Initialize all register settings reqd. for this chip */
+
+ msp_regs = (struct msp_regs *)(curr_cfg->ctr_regs);
+ msp_regs->gcr = 0x0;
+ msp_regs->tcf = 0x0;
+ msp_regs->rcf = 0x0;
+ msp_regs->srg = 0x0;
+ msp_regs->dmacr = 0x0;
+
+ MSP_WBITS(msp_regs->dmacr, 0x0, MSP_DMACR_MASK_RDMAE, 0);
+ MSP_WBITS(msp_regs->dmacr, 0x0, MSP_DMACR_MASK_TDMAE, 1);
+
+ /**** GCR Reg Config *****/
+
+ MSP_WBITS(msp_regs->gcr,
+ MSP_RECEIVER_DISABLED, MSP_GCR_MASK_RXEN, 0);
+ MSP_WBITS(msp_regs->gcr,
+ MSP_RX_FIFO_ENABLED, MSP_GCR_MASK_RFFEN, 1);
+ MSP_WBITS(msp_regs->gcr,
+ MSP_TRANSMITTER_DISABLED, MSP_GCR_MASK_TXEN, 8);
+ MSP_WBITS(msp_regs->gcr,
+ MSP_TX_FIFO_ENABLED, MSP_GCR_MASK_TFFEN, 9);
+ MSP_WBITS(msp_regs->gcr,
+ MSP_TX_FRAME_SYNC_POL_LOW, MSP_GCR_MASK_TFSPOL, 10);
+ MSP_WBITS(msp_regs->gcr,
+ MSP_TX_FRAME_SYNC_INT, MSP_GCR_MASK_TFSSEL, 11);
+ MSP_WBITS(msp_regs->gcr,
+ MSP_TRANSMIT_DATA_WITH_DELAY, MSP_GCR_MASK_TXDDL, 15);
+ MSP_WBITS(msp_regs->gcr,
+ MSP_SAMPLE_RATE_GEN_ENABLE, MSP_GCR_MASK_SGEN, 16);
+ MSP_WBITS(msp_regs->gcr,
+ MSP_CLOCK_INTERNAL, MSP_GCR_MASK_SCKSEL, 18);
+ MSP_WBITS(msp_regs->gcr,
+ MSP_FRAME_GEN_ENABLE, MSP_GCR_MASK_FGEN, 20);
+ MSP_WBITS(msp_regs->gcr,
+ SPI_BURST_MODE_DISABLE, MSP_GCR_MASK_SPIBME, 23);
+
+ if (chip_info->lbm == SPI_LOOPBACK_ENABLED)
+ MSP_WBITS(msp_regs->gcr,
+ MSP_LOOPBACK_ENABLED, MSP_GCR_MASK_LBM, 7);
+ else
+ MSP_WBITS(msp_regs->gcr,
+ MSP_LOOPBACK_DISABLED, MSP_GCR_MASK_LBM, 7);
+
+ if (chip_info->hierarchy == SPI_MASTER)
+ MSP_WBITS(msp_regs->gcr,
+ MSP_IS_SPI_MASTER, MSP_GCR_MASK_TCKSEL, 14);
+ else
+ MSP_WBITS(msp_regs->gcr,
+ MSP_IS_SPI_SLAVE, MSP_GCR_MASK_TCKSEL, 14);
+
+ if (chip_info->proto_params.moto.clk_phase == SPI_CLK_ZERO_CYCLE_DELAY)
+ MSP_WBITS(msp_regs->gcr,
+ MSP_SPI_PHASE_ZERO_CYCLE_DELAY,
+ MSP_GCR_MASK_SPICKM, 21);
+ else
+ MSP_WBITS(msp_regs->gcr,
+ MSP_SPI_PHASE_HALF_CYCLE_DELAY,
+ MSP_GCR_MASK_SPICKM, 21);
+
+ if (chip_info->proto_params.moto.clk_pol == SPI_CLK_POL_IDLE_HIGH)
+ MSP_WBITS(msp_regs->gcr,
+ MSP_TX_CLOCK_POL_HIGH, MSP_GCR_MASK_TCKPOL, 13);
+ else
+ MSP_WBITS(msp_regs->gcr,
+ MSP_TX_CLOCK_POL_LOW, MSP_GCR_MASK_TCKPOL, 13);
+
+ /**** RCF Reg Config *****/
+ MSP_WBITS(msp_regs->rcf,
+ MSP_IGNORE_RX_FRAME_SYNC_PULSE, MSP_RCF_MASK_RFSIG, 15);
+ MSP_WBITS(msp_regs->rcf,
+ MSP_RX_1BIT_DATA_DELAY, MSP_RCF_MASK_RDDLY, 13);
+ if (chip_info->endian_rx == SPI_FIFO_LSB)
+ MSP_WBITS(msp_regs->rcf,
+ MSP_RX_ENDIANESS_LSB, MSP_RCF_MASK_RENDN, 12);
+ else
+ MSP_WBITS(msp_regs->rcf,
+ MSP_RX_ENDIANESS_MSB, MSP_RCF_MASK_RENDN, 12);
+
+ MSP_WBITS(msp_regs->rcf, chip_info->data_size, MSP_RCF_MASK_RP1ELEN, 0);
+
+ /**** TCF Reg Config *****/
+ MSP_WBITS(msp_regs->tcf,
+ MSP_IGNORE_TX_FRAME_SYNC_PULSE, MSP_TCF_MASK_TFSIG, 15);
+ MSP_WBITS(msp_regs->tcf,
+ MSP_TX_1BIT_DATA_DELAY, MSP_TCF_MASK_TDDLY, 13);
+ if (chip_info->endian_rx == SPI_FIFO_LSB)
+ MSP_WBITS(msp_regs->tcf,
+ MSP_TX_ENDIANESS_LSB, MSP_TCF_MASK_TENDN, 12);
+ else
+ MSP_WBITS(msp_regs->tcf,
+ MSP_TX_ENDIANESS_MSB, MSP_TCF_MASK_TENDN, 12);
+ MSP_WBITS(msp_regs->tcf, chip_info->data_size, MSP_TCF_MASK_TP1ELEN, 0);
+
+ /**** SRG Reg Config *****/
+ MSP_WBITS(msp_regs->srg, sckdiv, MSP_SRG_MASK_SCKDIV, 0);
+
+ /* Save controller_state */
+ spi_set_ctldata(spi, curr_cfg);
+ return status;
+err_config_params:
+err_first_setup:
+ kfree(curr_cfg);
+ return status;
+}
+
+static int stm_msp_probe(struct amba_device *adev, struct amba_id *id)
+{
+ struct device *dev = &adev->dev;
+ struct spi_master_cntlr *platform_info;
+ struct spi_master *master;
+ struct driver_data *drv_data = NULL; /*Data for this driver */
+ struct resource *res;
+ int irq, status = 0;
+
+ platform_info = (struct spi_master_cntlr *)(dev->platform_data);
+ if (platform_info == NULL) {
+ stm_error("probe - no platform data supplied\n");
+ status = -ENODEV;
+ goto err_no_pdata;
+ }
+ /* Allocate master with space for drv_data */
+ master = spi_alloc_master(dev, sizeof(struct driver_data));
+ if (master == NULL) {
+ stm_error("probe - cannot alloc spi_master\n");
+ status = -ENOMEM;
+ goto err_no_mem;
+ }
+
+ drv_data = spi_master_get_devdata(master);
+ drv_data->master = master;
+ drv_data->master_info = platform_info;
+ drv_data->adev = adev;
+
+ drv_data->clk = clk_get(&adev->dev, NULL);
+ if (IS_ERR(drv_data->clk)) {
+ stm_error("probe - cannot find clock\n");
+ status = PTR_ERR(drv_data->clk);
+ goto free_master;
+ }
+
+ /*Fetch the Resources, using platform data */
+ res = &(adev->res);
+ if (res == NULL) {
+ stm_error("probe - MEM resources not defined\n");
+ status = -ENODEV;
+ goto disable_clk;
+ }
+ /*Get Hold of Device Register Area... */
+ drv_data->regs = ioremap(res->start, (res->end - res->start));
+ if (drv_data->regs == NULL) {
+ status = -ENODEV;
+ goto disable_clk;
+ }
+ irq = adev->irq[0];
+ if (irq <= 0) {
+ status = -ENODEV;
+ goto err_no_iores;
+ }
+
+ stm_dbg(DBG_ST.msp, ":::: mSP Controller %d\n", platform_info->id);
+ msp_controller_cmd(drv_data, LOAD_DEFAULT_CONFIG);
+
+ /*Required Info for an SPI controller */
+ /*Bus Number Which Assigned to this SPI controller on this board */
+ master->bus_num = (u16) platform_info->id;
+ master->num_chipselect = platform_info->num_chipselect;
+ master->setup = stm_msp_setup;
+ master->cleanup = (void *)stm_msp_cleanup;
+ master->transfer = stm_msp_transfer;
+
+ stm_dbg(DBG_ST.msp, ":::: BUSNO: %d\n", master->bus_num);
+
+ /* Initialize and start queue */
+ status = init_queue(drv_data);
+ if (status != 0) {
+ stm_error("probe - problem initializing queue\n");
+ goto err_init_queue;
+ }
+ status = start_queue(drv_data);
+ if (status != 0) {
+ stm_error("probe - problem starting queue\n");
+ goto err_start_queue;
+ }
+
+ /* Register with the SPI framework */
+ platform_set_drvdata(adev, drv_data);
+ stm_dbg(DBG_ST.msp, "probe succeded\n");
+ stm_dbg(DBG_ST.msp, "Bus No = %d, IRQ Line = %d, Virtual Addr: %x\n",
+ master->bus_num, irq, (u32) (drv_data->regs));
+
+ status =
+ stm_gpio_altfuncenable(drv_data->master_info->gpio_alt_func);
+ if (status < 0) {
+ stm_error("probe - unable to set GPIO Altfunc, %d\n",
+ drv_data->master_info->gpio_alt_func);
+ status = -ENODEV;
+ goto err_init_queue;
+ }
+ status =
+ request_irq(drv_data->adev->irq[0],
+ stm_msp_interrupt_handler,
+ 0, drv_data->master_info->device_name,
+ drv_data);
+ if (status < 0) {
+ stm_error("probe - cannot get IRQ (%d)\n",
+ status);
+ goto err_irq;
+ }
+
+ status = spi_register_master(master);
+ if (status != 0) {
+ stm_error("probe - problem registering spi master\n");
+ goto err_spi_register;
+ }
+
+ return 0;
+
+err_spi_register:
+ free_irq(drv_data->adev->irq[0], drv_data);
+err_irq:
+ stm_gpio_altfuncdisable(drv_data->master_info->gpio_alt_func);
+err_init_queue:
+err_start_queue:
+ destroy_queue(drv_data);
+err_no_iores:
+ iounmap(drv_data->regs);
+disable_clk:
+ clk_put(drv_data->clk);
+free_master:
+ spi_master_put(master);
+err_no_mem:
+err_no_pdata:
+ return status;
+}
+
+static int msp_remove(struct amba_device *adev)
+{
+ struct driver_data *drv_data = platform_get_drvdata(adev);
+ struct device *dev = &adev->dev;
+ struct spi_master_cntlr *platform_info;
+ int status = 0;
+ if (!drv_data)
+ return 0;
+
+ platform_info = dev->platform_data;
+
+ /* Remove the queue */
+ status = destroy_queue(drv_data);
+ if (status != 0) {
+ stm_error("queue remove failed (%d)\n", status);
+ return status;
+ }
+ msp_controller_cmd(drv_data, LOAD_DEFAULT_CONFIG);
+
+ /* Release map resources */
+ iounmap(drv_data->regs);
+ tasklet_disable(&drv_data->pump_transfers);
+ stm_gpio_altfuncdisable(platform_info->gpio_alt_func);
+ free_irq(drv_data->adev->irq[0], drv_data);
+
+ /* Disconnect from the SPI framework */
+ spi_unregister_master(drv_data->master);
+
+ clk_put(drv_data->clk);
+
+ /* Prevent double remove */
+ platform_set_drvdata(adev, NULL);
+ stm_dbg(DBG_ST.msp, "remove succeded\n");
+ return status;
+}
+
+static struct amba_id msp_ids[] = {
+ {
+ .id = MSP_PER_ID,
+ .mask = MSP_PER_MASK,
+ },
+ {0, 0},
+};
+
+#ifdef CONFIG_PM
+/**
+ * stm_msp_suspend - MSP suspend function registered with PM framework.
+ * @dev: Reference to amba device structure of the device
+ * @state: power mgmt state.
+ *
+ * This function is invoked when the system is going into sleep, called
+ * by the power management framework of the linux kernel.
+ *
+ */
+int stm_msp_suspend(struct amba_device *adev, pm_message_t state)
+{
+ struct driver_data *drv_data = platform_get_drvdata(adev);
+ int status = 0;
+
+ status = stop_queue(drv_data);
+ if (status != 0) {
+ dev_warn(&adev->dev, "suspend cannot stop queue\n");
+ return status;
+ }
+
+ stm_dbg(DBG_ST.msp, "suspended\n");
+ return 0;
+}
+
+/**
+ * stm_msp_resume - MSP Resume function registered with PM framework.
+ * @dev: Reference to amba device structure of the device
+ *
+ * This function is invoked when the system is coming out of sleep, called
+ * by the power management framework of the linux kernel.
+ *
+ */
+int stm_msp_resume(struct amba_device *pdev)
+{
+ struct driver_data *drv_data = platform_get_drvdata(pdev);
+ int status = 0;
+
+ /* Start the queue running */
+ status = start_queue(drv_data);
+ if (status != 0)
+ stm_error("problem starting queue (%d)\n", status);
+ else
+ stm_dbg(DBG_ST.msp, "resumed\n");
+
+ return status;
+}
+
+#else
+#define stm_msp_suspend NULL
+#define stm_msp_resume NULL
+#endif /* CONFIG_PM */
+
+static struct amba_driver msp_driver = {
+ .drv = {
+ .name = "MSP",
+ },
+ .id_table = msp_ids,
+ .probe = stm_msp_probe,
+ .remove = msp_remove,
+ .suspend = stm_msp_suspend,
+ .resume = stm_msp_resume,
+};
+
+static int __init stm_msp_mod_init(void)
+{
+ return amba_driver_register(&msp_driver);
+}
+
+static void __exit stm_msp_exit(void)
+{
+ amba_driver_unregister(&msp_driver);
+ return;
+}
+
+module_init(stm_msp_mod_init);
+module_exit(stm_msp_exit);
+
+MODULE_AUTHOR("Sachin Verma <sachin.verma@st.com>");
+MODULE_DESCRIPTION("STM MSP (SPI protocol) Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig
new file mode 100644
index 00000000000..a452e888d77
--- /dev/null
+++ b/drivers/tee/Kconfig
@@ -0,0 +1,13 @@
+#
+# Copyright (C) ST-Ericsson SA 2010
+# Author: Martin Hovang (martin.xm.hovang@stericsson.com)
+# License terms: GNU General Public License (GPL) version 2
+#
+
+# Trursted Execution Environment Configuration
+config TEE_SUPPORT
+ bool "Trusted Execution Environment Support"
+ default y
+ ---help---
+ This implements the Trusted Execution Environment (TEE) Client
+ API Specification from GlobalPlatform Device Technology.
diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile
new file mode 100644
index 00000000000..b937eb19d72
--- /dev/null
+++ b/drivers/tee/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (C) ST-Ericsson SA 2010
+# Author: Martin Hovang (martin.xm.hovang@stericsson.com)
+# License terms: GNU General Public License (GPL) version 2
+#
+
+obj-$(CONFIG_TEE_SUPPORT) += tee_service.o
+obj-$(CONFIG_TEE_SUPPORT) += tee_driver.o
diff --git a/drivers/tee/tee_driver.c b/drivers/tee/tee_driver.c
new file mode 100644
index 00000000000..551c92cc054
--- /dev/null
+++ b/drivers/tee/tee_driver.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Martin Hovang <martin.xm.hovang@stericsson.com>
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/mutex.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/tee.h>
+#include <linux/slab.h>
+
+#define TEED_NAME "tee"
+
+#define TEED_STATE_OPEN_DEV 0
+#define TEED_STATE_OPEN_SESSION 1
+
+#define TEEC_MEM_INPUT 0x00000001
+#define TEEC_MEM_OUTPUT 0x00000002
+
+static int tee_open(struct inode *inode, struct file *file);
+static int tee_release(struct inode *inode, struct file *file);
+static int tee_read(struct file *filp, char __user *buffer,
+ size_t length, loff_t *offset);
+static int tee_write(struct file *filp, const char __user *buffer,
+ size_t length, loff_t *offset);
+
+static inline void set_emsg(struct tee_session *ts, u32 msg)
+{
+ ts->err = msg;
+ ts->origin = TEED_ORIGIN_DRIVER;
+}
+
+static void reset_session(struct tee_session *ts)
+{
+ ts->state = TEED_STATE_OPEN_DEV;
+ ts->err = TEED_SUCCESS;
+ ts->origin = TEED_ORIGIN_DRIVER;
+ ts->id = 0;
+ ts->ta = NULL;
+ ts->uuid = NULL;
+ ts->cmd = 0;
+ ts->driver_cmd = TEED_OPEN_SESSION;
+ ts->ta_size = 0;
+ ts->op = NULL;
+}
+
+static int copy_ta(struct tee_session *ts,
+ struct tee_session *ku_buffer)
+{
+ ts->ta = kmalloc(ku_buffer->ta_size, GFP_KERNEL);
+ if (ts->ta == NULL) {
+ pr_err("[%s] error, out of memory (ta)\n",
+ __func__);
+ set_emsg(ts, TEED_ERROR_OUT_OF_MEMORY);
+ return -ENOMEM;
+ }
+
+ ts->ta_size = ku_buffer->ta_size;
+
+ memcpy(ts->ta, ku_buffer->ta, ku_buffer->ta_size);
+ return 0;
+}
+
+static int copy_uuid(struct tee_session *ts,
+ struct tee_session *ku_buffer)
+{
+ ts->uuid = kmalloc(sizeof(struct tee_uuid), GFP_KERNEL);
+
+ if (ts->uuid == NULL) {
+ pr_err("[%s] error, out of memory (uuid)\n",
+ __func__);
+ set_emsg(ts, TEED_ERROR_OUT_OF_MEMORY);
+ return -ENOMEM;
+ }
+
+ memcpy(ts->uuid, ku_buffer->uuid, sizeof(struct tee_uuid));
+
+ return 0;
+}
+
+static inline void free_operation(struct tee_session *ts)
+{
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ kfree(ts->op->shm[i].buffer);
+ ts->op->shm[i].buffer = NULL;
+ }
+
+ kfree(ts->op);
+ ts->op = NULL;
+}
+
+static inline void memrefs_phys_to_virt(struct tee_session *ts)
+{
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ if (ts->op->flags & (1 << i)) {
+ ts->op->shm[i].buffer =
+ phys_to_virt((unsigned long)
+ ts->op->shm[i].buffer);
+ }
+ }
+}
+
+static int copy_memref_to_user(struct tee_operation *op,
+ struct tee_operation *ubuf_op,
+ int memref)
+{
+ unsigned long bytes_left;
+
+ bytes_left = copy_to_user(ubuf_op->shm[memref].buffer,
+ op->shm[memref].buffer,
+ op->shm[memref].size);
+
+ if (bytes_left != 0) {
+ pr_err("[%s] Failed to copy result to user space (%lu "
+ "bytes left of buffer).\n", __func__, bytes_left);
+ return bytes_left;
+ }
+
+ bytes_left = put_user(op->shm[memref].size, &ubuf_op->shm[memref].size);
+
+ if (bytes_left != 0) {
+ pr_err("[%s] Failed to copy result to user space (%lu "
+ "bytes left of size).\n", __func__, bytes_left);
+ return -EINVAL;
+ }
+
+ bytes_left = put_user(op->shm[memref].flags,
+ &ubuf_op->shm[memref].flags);
+ if (bytes_left != 0) {
+ pr_err("[%s] Failed to copy result to user space (%lu "
+ "bytes left of flags).\n", __func__, bytes_left);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int copy_memref_to_kernel(struct tee_operation *op,
+ struct tee_operation *kbuf_op,
+ int memref)
+{
+ /* Buffer freed in invoke_command if this function fails */
+ op->shm[memref].buffer = kmalloc(kbuf_op->shm[memref].size, GFP_KERNEL);
+
+ if (!op->shm[memref].buffer) {
+ pr_err("[%s] out of memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ /*
+ * Copy shared memory operations to a local kernel
+ * buffer if they are of type input.
+ */
+ if (kbuf_op->shm[memref].flags & TEEC_MEM_INPUT) {
+ memcpy(op->shm[memref].buffer,
+ kbuf_op->shm[memref].buffer,
+ kbuf_op->shm[memref].size);
+ }
+
+ op->shm[memref].size = kbuf_op->shm[memref].size;
+ op->shm[memref].flags = kbuf_op->shm[memref].flags;
+
+ /* Secure world expects physical addresses. */
+ op->shm[memref].buffer = (void *)virt_to_phys(op->shm[memref].buffer);
+
+ return 0;
+}
+
+static int open_tee_device(struct tee_session *ts,
+ struct tee_session *ku_buffer)
+{
+ int ret;
+
+ if (ku_buffer->driver_cmd != TEED_OPEN_SESSION) {
+ set_emsg(ts, TEED_ERROR_BAD_STATE);
+ return -EINVAL;
+ }
+
+ if (ku_buffer->ta) {
+ ret = copy_ta(ts, ku_buffer);
+ } else if (ku_buffer->uuid) {
+ ret = copy_uuid(ts, ku_buffer);
+ } else {
+ set_emsg(ts, TEED_ERROR_COMMUNICATION);
+ return -EINVAL;
+ }
+
+ ts->id = 0;
+ ts->state = TEED_STATE_OPEN_SESSION;
+ return ret;
+}
+
+static int invoke_command(struct tee_session *ts,
+ struct tee_session *ku_buffer,
+ struct tee_session __user *u_buffer)
+{
+ int i;
+ int ret = 0;
+ struct tee_operation *kbuf_op =
+ (struct tee_operation *)ku_buffer->op;
+
+ ts->op = kmalloc(sizeof(struct tee_operation), GFP_KERNEL);
+
+ if (!ts->op) {
+ if (ts->op == NULL) {
+ pr_err("[%s] error, out of memory "
+ "(op)\n", __func__);
+ set_emsg(ts, TEED_ERROR_OUT_OF_MEMORY);
+ ret = -ENOMEM;
+ goto err;
+ }
+ }
+
+ /* Copy memrefs to kernel space. */
+ ts->op->flags = kbuf_op->flags;
+ ts->cmd = ku_buffer->cmd;
+
+ for (i = 0; i < 4; ++i) {
+ /* We only want to copy memrefs in use. */
+ if (kbuf_op->flags & (1 << i)) {
+ ret = copy_memref_to_kernel(ts->op, kbuf_op, i);
+
+ if (ret)
+ goto err;
+ } else {
+ ts->op->shm[i].buffer = NULL;
+ ts->op->shm[i].size = 0;
+ ts->op->shm[i].flags = 0;
+ }
+ }
+
+ /* To call secure world */
+ if (call_sec_world(ts, TEED_INVOKE)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /*
+ * Convert physical addresses back to virtual address so the
+ * kernel can free the buffers when closing the session.
+ */
+ memrefs_phys_to_virt(ts);
+
+ for (i = 0; i < 4; ++i) {
+ if ((kbuf_op->flags & (1 << i)) &&
+ (kbuf_op->shm[i].flags & TEEC_MEM_OUTPUT)) {
+ struct tee_operation *ubuf_op =
+ (struct tee_operation *)u_buffer->op;
+
+ ret = copy_memref_to_user(ts->op, ubuf_op, i);
+ }
+ }
+err:
+ free_operation(ts);
+
+ return ret;
+}
+
+static int tee_open(struct inode *inode, struct file *filp)
+{
+ struct tee_session *ts;
+
+ filp->private_data = kmalloc(sizeof(struct tee_session),
+ GFP_KERNEL);
+
+ if (filp->private_data == NULL)
+ return -ENOMEM;
+
+ ts = (struct tee_session *) (filp->private_data);
+
+ reset_session(ts);
+
+ ts->sync = kmalloc(sizeof(struct mutex), GFP_KERNEL);
+
+ if (!ts->sync)
+ return -ENOMEM;
+
+ mutex_init(ts->sync);
+
+ return 0;
+}
+
+static int tee_release(struct inode *inode, struct file *filp)
+{
+ struct tee_session *ts;
+ int i;
+
+ ts = (struct tee_session *) (filp->private_data);
+
+ if (ts == NULL)
+ goto no_ts;
+
+ if (ts->op) {
+ for (i = 0; i < 4; ++i) {
+ kfree(ts->op->shm[i].buffer);
+ ts->op->shm[i].buffer = NULL;
+ }
+ }
+
+ kfree(ts->op);
+ ts->op = NULL;
+
+ kfree(ts->sync);
+ ts->sync = NULL;
+
+ kfree(ts->ta);
+ ts->ta = NULL;
+
+no_ts:
+ kfree(filp->private_data);
+ filp->private_data = NULL;
+
+ return 0;
+}
+
+/*
+ * Called when a process, which already opened the dev file, attempts
+ * to read from it. This function gets the current status of the session.
+ */
+static int tee_read(struct file *filp, char __user *buffer,
+ size_t length, loff_t *offset)
+{
+ struct tee_read buf;
+ struct tee_session *ts;
+
+ if (length != sizeof(struct tee_read)) {
+ pr_err("[%s] error, incorrect input length\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ ts = (struct tee_session *) (filp->private_data);
+
+ if (ts == NULL || ts->sync == NULL) {
+ pr_err("[%s] error, private_data not "
+ "initialized\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(ts->sync);
+
+ buf.err = ts->err;
+ buf.origin = ts->origin;
+
+ mutex_unlock(ts->sync);
+
+ if (copy_to_user(buffer, &buf, length)) {
+ pr_err("[%s] error, copy_to_user failed!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ return length;
+}
+
+/*
+ * Called when a process writes to a dev file
+ */
+static int tee_write(struct file *filp, const char __user *buffer,
+ size_t length, loff_t *offset)
+{
+ struct tee_session ku_buffer;
+ struct tee_session *ts;
+ int ret = length;
+
+ if (length != sizeof(struct tee_session)) {
+ pr_err("[%s] error, incorrect input length\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&ku_buffer, buffer, length)) {
+ pr_err("[%s] error, tee_session "
+ "copy_from_user failed\n", __func__);
+ return -EINVAL;
+ }
+
+ ts = (struct tee_session *) (filp->private_data);
+
+ if (ts == NULL || ts->sync == NULL) {
+ pr_err("[%s] error, private_data not "
+ "initialized\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(ts->sync);
+
+ switch (ts->state) {
+ case TEED_STATE_OPEN_DEV:
+ ret = open_tee_device(ts, &ku_buffer);
+ break;
+
+ case TEED_STATE_OPEN_SESSION:
+ switch (ku_buffer.driver_cmd) {
+ case TEED_INVOKE:
+ ret = invoke_command(ts, &ku_buffer,
+ (struct tee_session *)buffer);
+ break;
+
+ case TEED_CLOSE_SESSION:
+ /* no caching implemented yet... */
+ if (call_sec_world(ts, TEED_CLOSE_SESSION))
+ ret = -EINVAL;
+
+ kfree(ts->ta);
+ ts->ta = NULL;
+
+ reset_session(ts);
+ break;
+
+ default:
+ set_emsg(ts, TEED_ERROR_BAD_PARAMETERS);
+ ret = -EINVAL;
+ }
+ break;
+ default:
+ pr_err("[%s] unknown state\n", __func__);
+ set_emsg(ts, TEED_ERROR_BAD_STATE);
+ ret = -EINVAL;
+ }
+
+ /*
+ * We expect that ret has value zero when reaching the end here.
+ * If it has any other value some error must have occured.
+ */
+ if (!ret)
+ ret = length;
+ else
+ ret = -EINVAL;
+
+ mutex_unlock(ts->sync);
+
+ return ret;
+}
+
+static const struct file_operations tee_fops = {
+ .owner = THIS_MODULE,
+ .read = tee_read,
+ .write = tee_write,
+ .open = tee_open,
+ .release = tee_release,
+};
+
+static struct miscdevice tee_dev = {
+ MISC_DYNAMIC_MINOR,
+ TEED_NAME,
+ &tee_fops
+};
+
+static int __init tee_init(void)
+{
+ int err = 0;
+
+ err = misc_register(&tee_dev);
+
+ if (err) {
+ pr_err("[%s] error %d adding character device "
+ "TEE\n", __func__, err);
+ }
+
+ return err;
+}
+
+static void __exit tee_exit(void)
+{
+ misc_deregister(&tee_dev);
+}
+
+module_init(tee_init);
+module_exit(tee_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("Trusted Execution Enviroment driver");
diff --git a/drivers/tee/tee_service.c b/drivers/tee/tee_service.c
new file mode 100644
index 00000000000..b01e9d0ac39
--- /dev/null
+++ b/drivers/tee/tee_service.c
@@ -0,0 +1,17 @@
+/*
+ * TEE service to handle the calls to trusted applications.
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#include <linux/kernel.h>
+#include <linux/tee.h>
+#include <linux/device.h>
+
+int __weak call_sec_world(struct tee_session *ts, int sec_cmd)
+{
+ pr_info("[%s] Generic call_sec_world called!\n", __func__);
+
+ return 0;
+}
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index ffc80e3241e..906abe7a071 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1510,12 +1510,14 @@ static void choose_address(struct usb_device *udev)
* bus->devnum_next. */
devnum = find_next_zero_bit(bus->devmap.devicemap, 128,
bus->devnum_next);
- if (devnum >= 128)
+ /* Due to Hardware bugs we need to reserve a device address
+ * for flushing of endpoints. */
+ if (devnum >= 127)
devnum = find_next_zero_bit(bus->devmap.devicemap,
128, 1);
- bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
+ bus->devnum_next = ( devnum >= 126 ? 1 : devnum + 1);
}
- if (devnum < 128) {
+ if (devnum < 127) {
set_bit(devnum, bus->devmap.devicemap);
udev->devnum = devnum;
}
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index c724e9b5701..99f30df5252 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1157,7 +1157,13 @@ static int composite_bind(struct usb_gadget *gadget)
cdev->bufsiz = USB_BUFSIZ;
cdev->driver = composite;
- usb_gadget_set_selfpowered(gadget);
+ /*
+ * As per USB compliance update, a device that is actively drawing
+ * more than 100mA from USB must report itself as bus-powered in
+ * the GetStatus(DEVICE) call.
+ */
+ if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW)
+ usb_gadget_set_selfpowered(gadget);
/* interface and string IDs start at zero via kzalloc.
* we force endpoints to start unassigned; few controller
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 8a832488ccd..dc2bd3af7d8 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -2,6 +2,7 @@
* epautoconf.c -- endpoint autoconfiguration for usb gadget drivers
*
* Copyright (C) 2004 David Brownell
+ * Copyright (C) 2009 ST Ericsson
*
* 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
@@ -79,6 +80,12 @@ ep_matches (
if (USB_ENDPOINT_XFER_CONTROL == type)
return 0;
+#if defined(CONFIG_ARCH_U8500)
+ /* 512 size endpoints are scarce, so leave them for bulk type */
+ if (ep->maxpacket == 512 && USB_ENDPOINT_XFER_INT == type)
+ return 0;
+#endif
+
/* some other naming convention */
if ('e' != ep->name[0])
return 0;
@@ -287,10 +294,22 @@ struct usb_ep *usb_ep_autoconfig (
/* Second, look at endpoints until an unclaimed one looks usable */
list_for_each_entry (ep, &gadget->ep_list, ep_list) {
- if (ep_matches (gadget, ep, desc))
- return ep;
- }
+#if (defined(CONFIG_ARCH_U8500) && !defined(CONFIG_MUSB_PIO_ONLY))
+ if (!strcmp(((gadget->dev).driver)->name, "g_file_storage")) {
+ if ((strcmp(ep->name, "ep1in") == 0) ||
+ (strcmp(ep->name, "ep1out") == 0)) {
+ if (ep_matches (gadget, ep, desc))
+ return ep;
+ }
+ } else {
+#endif
+ if (ep_matches (gadget, ep, desc))
+ return ep;
+#if (defined(CONFIG_ARCH_U8500) && !defined(CONFIG_MUSB_PIO_ONLY))
+ }
+#endif
+ }
/* Fail */
return NULL;
}
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index e3e5410d922..ddbb98861be 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -112,7 +112,7 @@ acm_iad_descriptor = {
.bInterfaceCount = 2, // control + data
.bFunctionClass = USB_CLASS_COMM,
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
- .bFunctionProtocol = USB_CDC_PROTO_NONE,
+ .bFunctionProtocol = USB_CDC_ACM_PROTO_AT_V25TER,
/* .iFunction = DYNAMIC */
};
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 544257a89ed..94bb2c51f7b 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -215,6 +215,7 @@ static struct usb_endpoint_descriptor fs_ecm_out_desc = {
static struct usb_descriptor_header *ecm_fs_function[] = {
/* CDC ECM control descriptors */
+ (struct usb_descriptor_header *) &ecm_iad_descriptor,
(struct usb_descriptor_header *) &ecm_control_intf,
(struct usb_descriptor_header *) &ecm_header_desc,
(struct usb_descriptor_header *) &ecm_union_desc,
@@ -260,6 +261,7 @@ static struct usb_endpoint_descriptor hs_ecm_out_desc = {
static struct usb_descriptor_header *ecm_hs_function[] = {
/* CDC ECM control descriptors */
+ (struct usb_descriptor_header *) &ecm_iad_descriptor,
(struct usb_descriptor_header *) &ecm_control_intf,
(struct usb_descriptor_header *) &ecm_header_desc,
(struct usb_descriptor_header *) &ecm_union_desc,
@@ -280,6 +282,7 @@ static struct usb_string ecm_string_defs[] = {
[0].s = "CDC Ethernet Control Model (ECM)",
[1].s = NULL /* DYNAMIC */,
[2].s = "CDC Ethernet Data",
+ [3].s = "CDC ECM",
{ } /* end of list */
};
@@ -466,10 +469,10 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
usb_ep_disable(ecm->notify);
} else {
VDBG(cdev, "init ecm ctrl %d\n", intf);
- ecm->notify_desc = ep_choose(cdev->gadget,
- ecm->hs.notify,
- ecm->fs.notify);
}
+ ecm->notify_desc = ep_choose(cdev->gadget,
+ ecm->hs.notify,
+ ecm->fs.notify);
usb_ep_enable(ecm->notify, ecm->notify_desc);
ecm->notify->driver_data = ecm;
@@ -485,11 +488,11 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (!ecm->port.in) {
DBG(cdev, "init ecm\n");
- ecm->port.in = ep_choose(cdev->gadget,
- ecm->hs.in, ecm->fs.in);
- ecm->port.out = ep_choose(cdev->gadget,
- ecm->hs.out, ecm->fs.out);
}
+ ecm->port.in = ep_choose(cdev->gadget,
+ ecm->hs.in, ecm->fs.in);
+ ecm->port.out = ep_choose(cdev->gadget,
+ ecm->hs.out, ecm->fs.out);
/* CDC Ethernet only sends data in non-default altsettings.
* Changing altsettings resets filters, statistics, etc.
@@ -610,6 +613,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
if (status < 0)
goto fail;
ecm->ctrl_id = status;
+ ecm_iad_descriptor.bFirstInterface = status;
ecm_control_intf.bInterfaceNumber = status;
ecm_union_desc.bMasterInterface0 = status;
@@ -795,6 +799,13 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
return status;
ecm_string_defs[1].id = status;
ecm_desc.iMACAddress = status;
+
+ /* IAD label */
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ ecm_string_defs[3].id = status;
+ ecm_iad_descriptor.iFunction = status;
}
/* allocate and initialize one new instance */
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index b49d86e3e45..888f7da3dd1 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1909,6 +1909,18 @@ static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
return -EINTR;
rc = usb_ep_set_halt(fsg->bulk_in);
}
+#ifdef CONFIG_ARCH_U8500
+ /* temporary HACK: There is a problem using mass storage with
+ * the musb driver. The problem is that the status command
+ * wrapper block gets queued in hardware before the clear-stall
+ * is executed. When the clear stall gets executed the status
+ * command wrapper block gets dropped and the USB host OS
+ * starts hanging. We are not sure where the proper place to
+ * fix this bug is. Until further, add a delay here so that
+ * the USB host gets time to execute the clear-stall request.
+ */
+ msleep_interruptible(100); /* temporary HACK */
+#endif
return rc;
}
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index cfd38edfcf9..8d5caddc03e 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -41,6 +41,7 @@ config USB_MUSB_SOC
default y if ARCH_OMAP4
default y if (BF54x && !BF544)
default y if (BF52x && !BF522 && !BF523)
+ default y if ARCH_U8500
comment "DaVinci 35x and 644x USB support"
depends on USB_MUSB_HDRC && ARCH_DAVINCI_DMx
@@ -57,6 +58,17 @@ comment "OMAP 44xx high speed USB support"
comment "Blackfin high speed USB Support"
depends on USB_MUSB_HDRC && ((BF54x && !BF544) || (BF52x && !BF522 && !BF523))
+comment "U8500 USB support"
+ depends on USB_MUSB_HDRC && ARCH_U8500
+
+config U8500_USB_HS_OTG
+ boolean "USB HS-OTG support"
+ depends on USB_MUSB_HDRC && ARCH_U8500
+ default y
+ help
+ Say Y here if you want to enable support for the U8500 USB
+ high speed on-the-go USB interface with external ULPI transceiver.
+
config USB_TUSB6010
boolean "TUSB 6010 support"
depends on USB_MUSB_HDRC && !USB_MUSB_SOC
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 9705f716386..bddb323c3f2 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -26,6 +26,10 @@ ifeq ($(CONFIG_ARCH_OMAP4),y)
musb_hdrc-objs += omap2430.o
endif
+ifeq ($(CONFIG_ARCH_U8500),y)
+ musb_hdrc-objs += stm_musb.o
+endif
+
ifeq ($(CONFIG_BF54x),y)
musb_hdrc-objs += blackfin.o
endif
@@ -67,6 +71,7 @@ ifneq ($(CONFIG_MUSB_PIO_ONLY),y)
endif
endif
endif
+ musb_hdrc-objs += stm_musb_dma.o
endif
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 3b795c56221..ea0ee7bd3fe 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -4,6 +4,7 @@
* Copyright 2005 Mentor Graphics Corporation
* Copyright (C) 2005-2006 by Texas Instruments
* Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2009 ST Ericsson
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -106,12 +107,16 @@
#endif
#include "musb_core.h"
-
+#ifdef CONFIG_ARCH_U8500
+#include "ste_config.h"
+#endif
#ifdef CONFIG_ARCH_DAVINCI
#include "davinci.h"
#endif
+#include <mach/stm_musb.h>
+
#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
@@ -459,6 +464,29 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
DBG(3, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl,
int_usb);
+ /*
+ * XXX The following code has been inserted here as a temporary hack
+ * to get some USB events directly from the USB hardware. This code
+ * and callbacks should eventually be integrated into the generic
+ * USB gadget stack.
+ */
+ if (!(devctl & MUSB_DEVCTL_HM)) {
+ if (int_usb & MUSB_INTR_RESET) {
+ if (power & MUSB_POWER_HSMODE)
+ ab8500_bm_usb_state_changed_wrapper(
+ AB8500_BM_USB_STATE_RESET_HS);
+ else
+ ab8500_bm_usb_state_changed_wrapper(
+ AB8500_BM_USB_STATE_RESET_FS);
+ }
+ if (int_usb & MUSB_INTR_RESUME)
+ ab8500_bm_usb_state_changed_wrapper(
+ AB8500_BM_USB_STATE_RESUME);
+ else if (int_usb & MUSB_INTR_SUSPEND)
+ ab8500_bm_usb_state_changed_wrapper(
+ AB8500_BM_USB_STATE_SUSPEND);
+ }
+
/* in host mode, the peripheral may issue remote wakeup.
* in peripheral mode, the host may resume the link.
* spurious RESUME irqs happen too, paired with SUSPEND.
@@ -1067,7 +1095,11 @@ static void musb_shutdown(struct platform_device *pdev)
|| defined(CONFIG_ARCH_OMAP4)
static ushort __initdata fifo_mode = 4;
#else
+#ifndef CONFIG_ARCH_U8500
static ushort __initdata fifo_mode = 2;
+#else
+static ushort __initdata fifo_mode = 5;
+#endif
#endif
/* "modprobe ... fifo_mode=1" etc */
@@ -1536,7 +1568,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || \
- defined(CONFIG_ARCH_OMAP4)
+ defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500)
static irqreturn_t generic_interrupt(int irq, void *__hci)
{
@@ -1591,6 +1623,14 @@ irqreturn_t musb_interrupt(struct musb *musb)
}
#endif
+ /**
+ * HACK for detecting the AX8817X series Ethernet over USB
+ * Adapters for U8500 platform
+ */
+#if (defined(CONFIG_ARCH_U8500) && defined(CONFIG_USB_NET_AX8817X))
+ mdelay(10);
+#endif
+
/* the core can interrupt us for multiple reasons; docs have
* a generic interrupt flowchart to follow
*/
@@ -2513,10 +2553,18 @@ static int __init musb_init(void)
return platform_driver_probe(&musb_driver, musb_probe);
}
+#ifndef CONFIG_ARCH_U8500
/* make us init after usbcore and i2c (transceivers, regulators, etc)
* and before usb gadget and host-side drivers start to register
*/
fs_initcall(musb_init);
+#else
+/* with fs_initcall the dma controller driver was loaded after mentor IP
+ * driver so when DMA is enabled, it will break as DMA controller driver is
+ * not loaded. This has been done to correct the order
+ */
+module_init(musb_init);
+#endif
static void __exit musb_cleanup(void)
{
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 91d67794e35..82b3fa22adc 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -72,8 +72,6 @@ struct musb_ep;
#include <linux/usb/hcd.h>
#include "musb_host.h"
-
-
#ifdef CONFIG_USB_MUSB_OTG
#define is_peripheral_enabled(musb) ((musb)->board_mode != MUSB_HOST)
@@ -600,7 +598,7 @@ extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode);
#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \
defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
- defined(CONFIG_ARCH_OMAP4)
+ defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500)
extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout);
#else
#define musb_platform_try_idle(x, y) do {} while (0)
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 6fca870e957..fd02192c964 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -5,6 +5,7 @@
* Copyright (C) 2005-2006 by Texas Instruments
* Copyright (C) 2006-2007 Nokia Corporation
* Copyright (C) 2009 MontaVista Software, Inc. <source@mvista.com>
+ * Copyright (C) 2009 ST Ericsson
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -43,10 +44,13 @@
#include <linux/moduleparam.h>
#include <linux/stat.h>
#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
#include <linux/slab.h>
#include "musb_core.h"
-
+#ifdef CONFIG_ARCH_U8500
+#include "ste_config.h"
+#endif
/* MUSB PERIPHERAL status 3-mar-2006:
*
@@ -92,6 +96,23 @@
/* ----------------------------------------------------------------------- */
+#ifdef CONFIG_USB_U8500_DMA
+/*
+ * Check if DMA is to be used for a particular endpoint.
+ *
+ * @param ep end point number
+ */
+static inline bool musb_gadget_use_dma(int ep)
+{
+ /*
+ * Enable DMA only for Endpoint 1 to support mass
+ * storage and disable DMA for other endpoints as
+ * we suspect hardware issues in data tx/rx.
+ */
+ return ep == 1;
+}
+#endif
+
/*
* Immediately complete a request.
*
@@ -119,7 +140,18 @@ __acquires(ep->musb->lock)
ep->busy = 1;
spin_unlock(&musb->lock);
+#ifdef CONFIG_ARM
+ /* If DMA is enabled we need to flush all data we read. */
+ if (ep->hw_ep->musb->controller->dma_mask != 0)
+ dmac_flush_range((const u8 *)req->request.buf,
+ (const u8 *)req->request.buf + req->request.length);
+#endif
+#ifdef CONFIG_USB_U8500_DMA
+ if (is_dma_capable() && !(req->request.actual < ep->packet_sz)
+ && musb_gadget_use_dma(ep->hw_ep->epnum)) {
+#else
if (is_dma_capable()) {
+#endif
if (req->mapped) {
dma_unmap_single(musb->controller,
req->request.dma,
@@ -267,12 +299,17 @@ static void txstate(struct musb *musb, struct musb_request *req)
int use_dma = 0;
musb_ep = req->ep;
-
+#ifdef CONFIG_USB_U8500_DMA
+ if (musb_ep->dma) {
+#endif
/* we shouldn't get here while DMA is active ... but we do ... */
if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
DBG(4, "dma pending...\n");
return;
}
+#ifdef CONFIG_USB_U8500_DMA
+ }
+#endif
/* read TXCSR before */
csr = musb_readw(epio, MUSB_TXCSR);
@@ -298,10 +335,26 @@ static void txstate(struct musb *musb, struct musb_request *req)
csr);
#ifndef CONFIG_MUSB_PIO_ONLY
+#ifdef CONFIG_USB_U8500_DMA
+ if (is_dma_capable() && musb_ep->dma && musb_gadget_use_dma(epnum)) {
+#else
if (is_dma_capable() && musb_ep->dma) {
+#endif
struct dma_controller *c = musb->dma_controller;
use_dma = (request->dma != DMA_ADDR_INVALID);
+#ifdef CONFIG_USB_U8500_DMA
+ if (request->length >= musb_ep->packet_sz) {
+
+ csr |= (MUSB_TXCSR_AUTOSET|
+ MUSB_TXCSR_DMAENAB
+ | MUSB_TXCSR_DMAMODE
+ | MUSB_TXCSR_MODE);
+ csr &= ~MUSB_TXCSR_P_UNDERRUN;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ }
+ use_dma = use_dma && c->channel_program(musb_ep->dma, musb_ep->packet_sz, DMA_MODE_1, request->dma, request->length);
+#endif
/* MUSB_TXCSR_P_ISO is still set correctly */
@@ -422,6 +475,7 @@ void musb_g_tx(struct musb *musb, u8 epnum)
struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_in;
void __iomem *epio = musb->endpoints[epnum].regs;
struct dma_channel *dma;
+ u16 bytes_left = 0;
musb_ep_select(mbase, epnum);
request = next_request(musb_ep);
@@ -464,12 +518,40 @@ void musb_g_tx(struct musb *musb, u8 epnum)
if (dma && (csr & MUSB_TXCSR_DMAENAB)) {
is_dma = 1;
+ int count = 0;
+
+ /* ensure writebuffer is empty */
+ csr = musb_readw(epio, MUSB_TXCSR);
+ bytes_left = request->length
+ -musb_ep->dma->actual_len;
+ for (count = 0; count < MAX_COUNT; count++) {
+ if (!(csr&MUSB_TXCSR_FIFONOTEMPTY))
+ break;
+ csr = musb_readw(epio, MUSB_TXCSR);
+ }
+
csr |= MUSB_TXCSR_P_WZC_BITS;
+#ifdef CONFIG_ARCH_U8500
+ csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_MODE
+ | MUSB_TXCSR_AUTOSET
+ | MUSB_TXCSR_P_UNDERRUN
+ | MUSB_TXCSR_DMAMODE
+ | MUSB_TXCSR_TXPKTRDY);
+#else
csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN |
- MUSB_TXCSR_TXPKTRDY);
+ MUSB_TXCSR_DMAMODE | MUSB_TXCSR_TXPKTRDY);
+#endif
musb_writew(epio, MUSB_TXCSR, csr);
- /* Ensure writebuffer is empty. */
- csr = musb_readw(epio, MUSB_TXCSR);
+ if (bytes_left) {
+ musb_write_fifo(musb_ep->hw_ep,
+ bytes_left,
+ (u8 *) (request->buf +
+ musb_ep->dma->actual_len));
+ musb_writew(epio, MUSB_TXCSR,
+ MUSB_TXCSR_TXPKTRDY);
+ request->actual += bytes_left;
+ }
+
request->actual += musb_ep->dma->actual_len;
DBG(4, "TXCSR%d %04x, DMA off, len %zu, req %p\n",
epnum, csr, musb_ep->dma->actual_len, request);
@@ -513,7 +595,12 @@ void musb_g_tx(struct musb *musb, u8 epnum)
*/
musb_ep_select(mbase, epnum);
csr = musb_readw(epio, MUSB_TXCSR);
+#ifdef CONFIG_ARCH_U8500
+ if ((csr & MUSB_TXCSR_FIFONOTEMPTY) &&
+ !(musb_ep->hw_ep->tx_double_buffered))
+#else
if (csr & MUSB_TXCSR_FIFONOTEMPTY)
+#endif
return;
request = musb_ep->desc ? next_request(musb_ep) : NULL;
@@ -615,6 +702,35 @@ static void rxstate(struct musb *musb, struct musb_request *req)
if (csr & MUSB_RXCSR_RXPKTRDY) {
len = musb_readw(epio, MUSB_RXCOUNT);
+#ifdef CONFIG_USB_U8500_DMA
+ if ((len >= DMA_PACKET_THRESHOLD) && musb_gadget_use_dma(epnum)) {
+
+ if (is_dma_capable() && musb_ep->dma) {
+ struct dma_controller *c;
+ struct dma_channel *channel;
+ int use_dma = 0;
+ use_dma = (request->dma != DMA_ADDR_INVALID);
+ c = musb->dma_controller;
+ channel = musb_ep->dma;
+ csr |= MUSB_RXCSR_AUTOCLEAR;
+ csr |= MUSB_RXCSR_P_WZC_BITS;
+ csr |= MUSB_RXCSR_DMAENAB;
+ musb_writew(epio, MUSB_RXCSR, csr);
+
+ use_dma = c->channel_program(
+ channel,
+ musb_ep->packet_sz,
+ DMA_MODE_0,
+ request->dma+request->actual,
+ request->length-request->actual);
+
+ if (use_dma)
+ return;
+ }
+
+ }
+#endif
+
if (request->actual < request->length) {
#ifdef CONFIG_USB_INVENTRA_DMA
if (is_dma_capable() && musb_ep->dma) {
@@ -743,6 +859,7 @@ void musb_g_rx(struct musb *musb, u8 epnum)
struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out;
void __iomem *epio = musb->endpoints[epnum].regs;
struct dma_channel *dma;
+ u16 bytes_left = 0;
musb_ep_select(mbase, epnum);
@@ -791,13 +908,34 @@ void musb_g_rx(struct musb *musb, u8 epnum)
| MUSB_RXCSR_DMAMODE);
musb_writew(epio, MUSB_RXCSR,
MUSB_RXCSR_P_WZC_BITS | csr);
-
+ csr = musb_readw(epio, MUSB_RXCSR);
+ bytes_left = request->length-musb_ep->dma->actual_len;
+ if (bytes_left) {
+ musb_read_fifo(musb_ep->hw_ep, bytes_left,
+ (u8 *) (request->buf + musb_ep->dma->actual_len));
+ musb_writew(epio, MUSB_RXCSR, csr|~MUSB_RXCSR_RXPKTRDY);
+ request->actual += bytes_left;
+ }
request->actual += musb_ep->dma->actual_len;
DBG(4, "RXCSR%d %04x, dma off, %04x, len %zu, req %p\n",
epnum, csr,
musb_readw(epio, MUSB_RXCSR),
musb_ep->dma->actual_len, request);
+#ifdef CONFIG_USB_U8500_DMA
+ /* Autoclear doesn't clear RxPktRdy for short packets */
+ if ((dma->actual_len & (musb_ep->packet_sz - 1))) {
+ /* ack the read! */
+ csr &= ~MUSB_RXCSR_RXPKTRDY;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
+
+ /* incomplete, and not short? wait for next IN packet */
+ if ((request->actual < request->length)
+ && (musb_ep->dma->actual_len
+ == musb_ep->packet_sz))
+ return;
+#endif
#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
/* Autoclear doesn't clear RxPktRdy for short packets */
@@ -962,7 +1100,12 @@ static int musb_gadget_enable(struct usb_ep *ep,
/* NOTE: all the I/O code _should_ work fine without DMA, in case
* for some reason you run out of channels here.
*/
+#ifndef CONFIG_USB_U8500_DMA
if (is_dma_capable() && musb->dma_controller) {
+#else
+ if (is_dma_capable() && musb->dma_controller &&
+ musb_gadget_use_dma(epnum)) {
+#endif
struct dma_controller *c = musb->dma_controller;
musb_ep->dma = c->channel_alloc(c, hw_ep,
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 877d20b1dff..5490c2bc46a 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -106,24 +106,41 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
{
void __iomem *epio = ep->regs;
+ void __iomem *regs = ep->musb->mregs;
u16 csr;
- u16 lastcsr = 0;
- int retries = 1000;
+ u8 addr;
+ int retries = 3000; /* 3ms */
+ /*
+ * NOTE: We are using a hack here because the FIFO-FLUSH
+ * bit is broken in hardware! The hack consists of changing
+ * the TXFUNCADDR to an unused device address and waiting
+ * for any pending USB packets to hit the 3-strikes and your
+ * gone rule.
+ */
+ addr = musb_readb(regs, MUSB_BUSCTL_OFFSET(ep->epnum, MUSB_TXFUNCADDR));
csr = musb_readw(epio, MUSB_TXCSR);
while (csr & MUSB_TXCSR_FIFONOTEMPTY) {
- if (csr != lastcsr)
- DBG(3, "Host TX FIFONOTEMPTY csr: %02x\n", csr);
- lastcsr = csr;
- csr |= MUSB_TXCSR_FLUSHFIFO;
- musb_writew(epio, MUSB_TXCSR, csr);
+ musb_writeb(regs, MUSB_BUSCTL_OFFSET(ep->epnum,
+ MUSB_TXFUNCADDR), 127);
csr = musb_readw(epio, MUSB_TXCSR);
- if (WARN(retries-- < 1,
- "Could not flush host TX%d fifo: csr: %04x\n",
- ep->epnum, csr))
- return;
- mdelay(1);
+ retries--;
+ if (retries == 0) {
+ /* can happen if the USB clocks are OFF */
+ DBG(3, "Could not flush host TX%d "
+ "fifo: csr=0x%04x\n", ep->epnum, csr);
+ break;
+ }
+ udelay(1);
}
+ /* clear any errors */
+ csr &= ~(MUSB_TXCSR_H_ERROR
+ | MUSB_TXCSR_H_RXSTALL
+ | MUSB_TXCSR_H_NAKTIMEOUT);
+ musb_writew(epio, MUSB_TXCSR, csr);
+
+ /* restore endpoint address */
+ musb_writeb(regs, MUSB_BUSCTL_OFFSET(ep->epnum, MUSB_TXFUNCADDR), addr);
}
static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep)
@@ -1141,7 +1158,9 @@ void musb_host_tx(struct musb *musb, u8 epnum)
DBG(3, "TX 3strikes on ep=%d\n", epnum);
status = -ETIMEDOUT;
-
+ } else if (tx_csr & MUSB_TXCSR_TXPKTRDY) {
+ /* BUSY - can happen during USB transfer cancel */
+ return;
} else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) {
DBG(6, "TX end=%d device not responding\n", epnum);
diff --git a/drivers/usb/musb/ste_config.h b/drivers/usb/musb/ste_config.h
new file mode 100644
index 00000000000..87baf9f0358
--- /dev/null
+++ b/drivers/usb/musb/ste_config.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright (C) 2009 ST-Ericsson SA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __STE_CONFIG_H__
+#define __STE_CONFIG_H__
+
+#if (defined(CONFIG_ARCH_U8500) && !defined(CONFIG_MUSB_PIO_ONLY))
+#define CONFIG_USB_U8500_DMA
+#endif
+#define U8500_DMA_END_POINTS 7
+#define DMA_MODE_0 0
+#define DMA_MODE_1 1
+#define DMA_PACKET_THRESHOLD 512
+#define RX_END_POINT_OFFSET 6
+#define DELAY_IN_MICROSECONDS 10
+#define MAX_COUNT 35000
+
+enum nmdk_dma_tx_rx_channel {
+ TX_CHANNEL_1 = 0,
+ TX_CHANNEL_2,
+ TX_CHANNEL_3,
+ TX_CHANNEL_4,
+ TX_CHANNEL_5,
+ TX_CHANNEL_6,
+ TX_CHANNEL_7,
+ RX_CHANNEL_1,
+ RX_CHANNEL_2,
+ RX_CHANNEL_3,
+ RX_CHANNEL_4,
+ RX_CHANNEL_5,
+ RX_CHANNEL_6,
+ RX_CHANNEL_7
+};
+#endif
+
diff --git a/drivers/usb/musb/stm_musb.c b/drivers/usb/musb/stm_musb.c
new file mode 100644
index 00000000000..12ab9daa370
--- /dev/null
+++ b/drivers/usb/musb/stm_musb.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (C) 2009 STMicroelectronics
+ * Copyright (C) 2009 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/** @file stm_musb.c
+ * @brief This file contains the USB controller and Phy initialization
+ * with default as interrupt mode was implemented
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mfd/ab8500/ab8500-bm.h>
+#include <mach/stm_musb.h>
+#include <mach/musb_db8500.h>
+#include "musb_core.h"
+
+static u8 ulpi_read_register(struct musb *musb, u8 address);
+static u8 ulpi_write_register(struct musb *musb, u8 address, u8 data);
+/* callback argument for AB8500 callback functions */
+static struct musb *musb_status;
+static spinlock_t musb_ulpi_spinlock;
+static unsigned musb_power;
+
+/**
+ * musb_set_session() - Start the USB session
+ *
+ * This function is used to start the USB sessios in USB host mode
+ * once the A cable is plugged in
+ */
+void musb_set_session(void)
+{
+ u8 val;
+ void __iomem *regs;
+
+ if (musb_status == NULL) {
+ printk(KERN_ERR "Error: devctl session cannot be set\n");
+ return;
+ }
+ regs = musb_status->mregs;
+ val = musb_readb(regs, MUSB_DEVCTL);
+ musb_writeb(regs, MUSB_DEVCTL, val | MUSB_DEVCTL_SESSION);
+}
+EXPORT_SYMBOL(musb_set_session);
+
+void
+ab8500_bm_usb_state_changed_wrapper(u8 bm_usb_state)
+{
+ if ((bm_usb_state == AB8500_BM_USB_STATE_RESET_HS) ||
+ (bm_usb_state == AB8500_BM_USB_STATE_RESET_FS)) {
+ musb_power = 0;
+ }
+
+ /*
+ * TODO: Instead of using callbacks, we should be using notify
+ * to tell the battery manager when there is s state change
+ */
+ ab8500_bm_usb_state_changed(bm_usb_state, musb_power);
+}
+
+void
+ab8500_bm_ulpi_set_char_speed_mode(u8 mode)
+{
+ if (musb_status == NULL) {
+ printk(KERN_ALERT "musb_status is NULL. "
+ "Cannot write to ULPI.\n");
+ return;
+ }
+
+ mode &= 3;
+ mode <<= 5;
+ mode |= ulpi_read_register(musb_status, ULPI_ULINKSTAT) &
+ ~ULPI_ULINKSTAT_CHARSPEED_MODE;
+
+ printk(KERN_INFO "Writing 0x%02x to USB char-speed mode bits\n", mode);
+
+ ulpi_write_register(musb_status, ULPI_ULINKSTAT, mode);
+}
+
+void
+ab8500_bm_ulpi_set_char_suspend_mode(u8 suspend)
+{
+ if (musb_status == NULL) {
+ printk(KERN_ALERT "musb_status is NULL. "
+ "Cannot write to ULPI.\n");
+ return;
+ }
+
+ suspend &= 1;
+ suspend <<= 7;
+ suspend |= ulpi_read_register(musb_status, ULPI_ULINKSTAT) &
+ ~ULPI_ULINKSTAT_SUSPEND_MODE;
+
+ printk(KERN_INFO "Writing 0x%02x to USB suspend mode bits\n", suspend);
+
+ ulpi_write_register(musb_status, ULPI_ULINKSTAT, suspend);
+}
+
+/* Sys interfaces */
+static struct kobject *usbstatus_kobj;
+static ssize_t usb_cable_status
+ (struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ u8 is_active = 0;
+
+ if (strcmp(attr->name, "cable_connect") == 0) {
+ is_active = musb_status->is_active;
+ sprintf(buf, "%d\n", is_active);
+ }
+ return strlen(buf);
+}
+
+static struct attribute usb_cable_connect_attribute = \
+ {.name = "cable_connect", .mode = S_IRUGO};
+static struct attribute *usb_status[] = {
+ &usb_cable_connect_attribute,
+ NULL
+};
+
+struct sysfs_ops usb_sysfs_ops = {
+ .show = usb_cable_status,
+};
+
+static struct kobj_type ktype_usbstatus = {
+ .sysfs_ops = &usb_sysfs_ops,
+ .default_attrs = usb_status,
+};
+
+/*
+ * A structure was declared as global for timer in USB host mode
+ */
+static struct timer_list notify_timer;
+
+/**
+ * ulpi_read_register() - Read the usb register from address writing into ULPI
+ * @musb: struct musb pointer.
+ * @address: address for reading from ULPI register of USB
+ *
+ * This function read the value from the specific address in USB host mode.
+ */
+static u8 ulpi_read_register(struct musb *musb, u8 address)
+{
+ void __iomem *mbase = musb->mregs;
+ unsigned long flags;
+ int count = 200;
+ u8 val;
+
+ spin_lock_irqsave(&musb_ulpi_spinlock, flags);
+
+ /* set ULPI register address */
+ musb_writeb(mbase, OTG_UREGADDR, address);
+
+ /* request a read access */
+ val = musb_readb(mbase, OTG_UREGCTRL);
+ val |= OTG_UREGCTRL_URW;
+ musb_writeb(mbase, OTG_UREGCTRL, val);
+
+ /* perform access */
+ val = musb_readb(mbase, OTG_UREGCTRL);
+ val |= OTG_UREGCTRL_REGREQ;
+ musb_writeb(mbase, OTG_UREGCTRL, val);
+
+ /* wait for completion with a time-out */
+ do {
+ udelay(10);
+ val = musb_readb(mbase, OTG_UREGCTRL);
+ count--;
+ } while (!(val & OTG_UREGCTRL_REGCMP) && (count > 0));
+
+ /* check for time-out */
+ if (!(val & OTG_UREGCTRL_REGCMP) && (count == 0)) {
+ spin_unlock_irqrestore(&musb_ulpi_spinlock, flags);
+ if (printk_ratelimit())
+ printk(KERN_ALERT "U8500 USB : ULPI read timed out\n");
+ return 0;
+ }
+
+ /* acknowledge completion */
+ val &= ~OTG_UREGCTRL_REGCMP;
+ musb_writeb(mbase, OTG_UREGCTRL, val);
+
+ /* get data */
+ val = musb_readb(mbase, OTG_UREGDATA);
+ spin_unlock_irqrestore(&musb_ulpi_spinlock, flags);
+
+ return val;
+}
+
+/**
+ * ulpi_write_register() - Write to a usb phy's ULPI register
+ * using the Mentor ULPI wrapper functionality
+ * @musb: struct musb pointer.
+ * @address: address of ULPI register
+ * @data: data for ULPI register
+ * This function writes the value given by data to the specific address
+ */
+static u8 ulpi_write_register(struct musb *musb, u8 address, u8 data)
+{
+ void __iomem *mbase = musb->mregs;
+ unsigned long flags;
+ int count = 200;
+ u8 val;
+
+ spin_lock_irqsave(&musb_ulpi_spinlock, flags);
+
+ /* First write to ULPI wrapper registers */
+ /* set ULPI register address */
+ musb_writeb(mbase, OTG_UREGADDR, address);
+
+ /* request a write access */
+ val = musb_readb(mbase, OTG_UREGCTRL);
+ val &= ~OTG_UREGCTRL_URW;
+ musb_writeb(mbase, OTG_UREGCTRL, val);
+
+ /* Write data to ULPI wrapper data register */
+ musb_writeb(mbase, OTG_UREGDATA, data);
+
+ /* perform access */
+ val = musb_readb(mbase, OTG_UREGCTRL);
+ val |= OTG_UREGCTRL_REGREQ;
+ musb_writeb(mbase, OTG_UREGCTRL, val);
+
+ /* wait for completion with a time-out */
+ do {
+ udelay(10);
+ val = musb_readb(mbase, OTG_UREGCTRL);
+ count--;
+ } while (!(val & OTG_UREGCTRL_REGCMP) && (count > 0));
+
+ /* check for time-out */
+ if (!(val & OTG_UREGCTRL_REGCMP) && (count == 0)) {
+ spin_unlock_irqrestore(&musb_ulpi_spinlock, flags);
+ if (printk_ratelimit())
+ printk(KERN_ALERT "U8500 USB : ULPI write timed out\n");
+ return 0;
+ }
+
+ /* acknowledge completion */
+ val &= ~OTG_UREGCTRL_REGCMP;
+ musb_writeb(mbase, OTG_UREGCTRL, val);
+
+ spin_unlock_irqrestore(&musb_ulpi_spinlock, flags);
+
+ return 0;
+
+}
+
+/**
+ * musb_stm_hs_otg_init() - Initialize the USB for paltform specific.
+ * @musb: struct musb pointer.
+ *
+ * This function initialize the USB with the given musb structure information.
+ */
+int __init musb_stm_hs_otg_init(struct musb *musb)
+{
+ u8 val;
+ int status;
+
+ if (musb->clock)
+ clk_enable(musb->clock);
+ status = stm_gpio_altfuncenable(GPIO_ALT_USB_OTG);
+ if (status) {
+ DBG(1, "U8500 USB : Problem in enabling alternate function\n");
+ return -EBUSY;
+ }
+
+ /* enable ULPI interface */
+ val = musb_readb(musb->mregs, OTG_TOPCTRL);
+ val |= OTG_TOPCTRL_MODE_ULPI;
+ musb_writeb(musb->mregs, OTG_TOPCTRL, val);
+
+ /* do soft reset */
+ val = musb_readb(musb->mregs, 0x7F);
+ val |= 0x2;
+ musb_writeb(musb->mregs, 0x7F, val);
+
+ return 0;
+}
+/**
+ * musb_stm_fs_init() - Initialize the file system for the USB.
+ * @musb: struct musb pointer.
+ *
+ * This function initialize the file system of USB.
+ */
+int __init musb_stm_fs_init(struct musb *musb)
+{
+ return 0;
+}
+/**
+ * musb_platform_enable() - Enable the USB.
+ * @musb: struct musb pointer.
+ *
+ * This function enables the USB.
+ */
+void musb_platform_enable(struct musb *musb)
+{
+}
+/**
+ * musb_platform_disable() - Disable the USB.
+ * @musb: struct musb pointer.
+ *
+ * This function disables the USB.
+ */
+void musb_platform_disable(struct musb *musb)
+{
+}
+
+/**
+ * musb_platform_try_idle() - Check the USB state active or not.
+ * @musb: struct musb pointer.
+ * @timeout: set the timeout to keep the host in idle mode.
+ *
+ * This function keeps the USB host in idle state based on the musb inforamtion.
+ */
+void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+{
+ if (musb->board_mode != MUSB_PERIPHERAL) {
+ unsigned long default_timeout =
+ jiffies + msecs_to_jiffies(1000);
+ static unsigned long last_timer;
+
+ if (timeout == 0)
+ timeout = default_timeout;
+
+ /* Never idle if active, or when VBUS
+ timeout is not set as host */
+ if (musb->is_active || ((musb->a_wait_bcon == 0)
+ && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
+ DBG(4, "%s active, deleting timer\n",
+ otg_state_string(musb));
+ del_timer(&notify_timer);
+ last_timer = jiffies;
+ return;
+ }
+
+ if (time_after(last_timer, timeout)) {
+ if (!timer_pending(&notify_timer))
+ last_timer = timeout;
+ else {
+ DBG(4,
+ "Longer idle timer already pending,ignoring\n");
+ return;
+ }
+ }
+ last_timer = timeout;
+
+ DBG(4, "%s inactive, for idle timer for %lu ms\n",
+ otg_state_string(musb),
+ (unsigned long)jiffies_to_msecs(timeout - jiffies));
+ mod_timer(&notify_timer, timeout);
+ }
+}
+
+/**
+ * set_vbus() - Set the Vbus for the USB.
+ * @musb: struct musb pointer.
+ * @is_on: set Vbus for USB or not.
+ *
+ * This function set the Vbus for USB.
+ */
+static void set_vbus(struct musb *musb, int is_on)
+{
+ u8 devctl;
+ /* HDRC controls CPEN, but beware current surges during device
+ * connect. They can trigger transient overcurrent conditions
+ * that must be ignored.
+ */
+
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+ if (is_on) {
+ musb->is_active = 1;
+ musb->xceiv->default_a = 1;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ devctl |= MUSB_DEVCTL_SESSION;
+
+ MUSB_HST_MODE(musb);
+ } else {
+ musb->is_active = 0;
+
+ /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and
+ * jumping right to B_IDLE...
+ */
+
+ musb->xceiv->default_a = 0;
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ devctl &= ~MUSB_DEVCTL_SESSION;
+
+ MUSB_DEV_MODE(musb);
+ }
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+ DBG(1, "VBUS %s, devctl %02x "
+ /* otg %3x conf %08x prcm %08x */ "\n",
+ otg_state_string(musb),
+ musb_readb(musb->mregs, MUSB_DEVCTL));
+}
+/**
+ * set_power() - Set the power for the USB transceiver.
+ * @x: struct usb_transceiver pointer.
+ * @mA: set mA power for USB.
+ *
+ * This function set the power for the USB.
+ */
+static int set_power(struct otg_transceiver *x, unsigned mA)
+{
+ musb_power = mA;
+ ab8500_bm_usb_state_changed_wrapper(
+ AB8500_BM_USB_STATE_CONFIGURED);
+ return 0;
+}
+/**
+ * musb_platform_set_mode() - Set the mode for the USB driver.
+ * @musb: struct musb pointer.
+ * @musb_mode: usb mode.
+ *
+ * This function set the mode for the USB.
+ */
+int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+{
+ u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+ devctl |= MUSB_DEVCTL_SESSION;
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+ switch (musb_mode) {
+ case MUSB_HOST:
+ otg_set_host(musb->xceiv, musb->xceiv->host);
+ break;
+ case MUSB_PERIPHERAL:
+ otg_set_peripheral(musb->xceiv, musb->xceiv->gadget);
+ break;
+ case MUSB_OTG:
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+/**
+ * funct_host_notify_timer() - Initialize the timer for USB host driver.
+ * @data: usb host data.
+ *
+ * This function runs the timer for the USB host mode.
+ */
+static void funct_host_notify_timer(unsigned long data)
+{
+ /* TODO: Cleanup this timer */
+}
+/**
+ * musb_platform_init() - Initialize the platform USB driver.
+ * @musb: struct musb pointer.
+ *
+ * This function initialize the USB controller and Phy.
+ */
+int __init musb_platform_init(struct musb *musb, void *board_data)
+{
+ int ret;
+
+ usb_nop_xceiv_register();
+
+ musb->xceiv = otg_get_transceiver();
+ if (!musb->xceiv) {
+ pr_err("U8500 USB : no transceiver configured\n");
+ ret = -ENODEV;
+ goto done;
+ }
+
+ ret = musb_stm_hs_otg_init(musb);
+ if (ret < 0)
+ goto done;
+ if (is_host_enabled(musb))
+ musb->board_set_vbus = set_vbus;
+ if (is_peripheral_enabled(musb))
+ musb->xceiv->set_power = set_power;
+
+ ret = musb_phy_en(musb->board_mode);
+ if (ret < 0)
+ goto done;
+
+ if (musb_status == NULL) {
+ musb_status = musb;
+ spin_lock_init(&musb_ulpi_spinlock);
+ }
+
+ /* Registering usb device for sysfs */
+ usbstatus_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
+
+ if (usbstatus_kobj == NULL)
+ ret = -ENOMEM;
+ usbstatus_kobj->ktype = &ktype_usbstatus;
+ kobject_init(usbstatus_kobj, usbstatus_kobj->ktype);
+
+ ret = kobject_set_name(usbstatus_kobj, "usb_status");
+ if (ret)
+ kfree(usbstatus_kobj);
+
+ ret = kobject_add(usbstatus_kobj, NULL, "usb_status");
+ if (ret)
+ kfree(usbstatus_kobj);
+
+ if (musb->board_mode != MUSB_PERIPHERAL) {
+ init_timer(&notify_timer);
+ notify_timer.expires = jiffies + msecs_to_jiffies(1000);
+ notify_timer.function = funct_host_notify_timer;
+ notify_timer.data = (unsigned long)musb;
+ add_timer(&notify_timer);
+ }
+ ret = musb_force_detect(musb->board_mode);
+ if (ret < 0)
+ goto done;
+ return 0;
+
+done:
+ usb_nop_xceiv_unregister();
+ return ret;
+}
+/**
+ * musb_platform_exit() - unregister the platform USB driver.
+ * @musb: struct musb pointer.
+ *
+ * This function unregisters the USB controller.
+ */
+int musb_platform_exit(struct musb *musb)
+{
+ int status = 0;
+ musb->clock = 0;
+ status = stm_gpio_altfuncdisable(GPIO_ALT_USB_OTG);
+ if (status) {
+ DBG(1, "U8500 USB : Problem in disabling alternate function\n");
+ return -EBUSY;
+ }
+ if (musb->board_mode != MUSB_PERIPHERAL)
+ del_timer_sync(&notify_timer);
+
+ usb_nop_xceiv_unregister();
+
+ musb_status = NULL;
+
+ return 0;
+}
diff --git a/drivers/usb/musb/stm_musb_dma.c b/drivers/usb/musb/stm_musb_dma.c
new file mode 100644
index 00000000000..4f829647b2f
--- /dev/null
+++ b/drivers/usb/musb/stm_musb_dma.c
@@ -0,0 +1,740 @@
+/* Copyright (C) 2009 ST-Ericsson SA
+ * Copyright (C) 2009 STMicroelectronics
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/pfn.h>
+#include "musb_core.h"
+#include "ste_config.h"
+#include "stm_musb_dma.h"
+#include <plat/ste_dma40.h>
+#include <mach/ste-dma40-db8500.h>
+
+/**
+ * dma_controller_start() - creates the logical channels pool and registers callbacks
+ * @c: pointer to DMA Controller
+ *
+ * This function requests the logical channels from the DMA driver and creates
+ * logical channels based on event lines and also registers the callbacks which
+ * are invoked after data transfer in the transmit or receive direction.
+*/
+
+static int dma_controller_start(struct dma_controller *c)
+{
+ struct musb_dma_controller *controller = container_of(c,
+ struct musb_dma_controller, controller);
+ struct musb_dma_channel *musb_channel = NULL;
+ struct stedma40_chan_cfg *info;
+ u8 bit;
+ struct dma_channel *channel = NULL;
+ /*bit 0 for receive and bit 1 for transmit*/
+#ifndef CONFIG_USB_U8500_DMA
+ for (bit = 0; bit < 2; bit++) {
+#else
+ for (bit = 0; bit < (U8500_DMA_END_POINTS*2); bit++) {
+#endif
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ musb_channel = &(controller->channel[bit]);
+ info = kzalloc(sizeof(struct stedma40_chan_cfg), GFP_KERNEL);
+ if (!info)
+ ERR("could not allocate dma info structure\n");
+ musb_channel->info = info;
+ musb_channel->controller = controller;
+#ifdef CONFIG_USB_U8500_DMA
+ info->high_priority = true;
+#else
+ info->mode = STEDMA40_MODE_PHYSICAL;
+ info->high_priority = true;
+#endif
+
+#if 1
+#ifndef CONFIG_USB_U8500_DMA
+ if (bit) {
+#else
+ if ((bit >= TX_CHANNEL_1) && (bit <= TX_CHANNEL_7)) {
+#endif
+ int dst_dev_type;
+
+ info->dir = STEDMA40_MEM_TO_PERIPH;
+ info->src_dev_type = STEDMA40_DEV_SRC_MEMORY;
+#ifdef CONFIG_NOMADIK_NDK15
+ info->dst_dev_type = DMA_DEV_USB_OTG_0_TX;
+#endif
+
+#ifdef CONFIG_NOMADIK_NDK20
+ info->dst_dev_type = DMA_DEV_USB_OTG_OEP_2_10;
+#endif
+
+#ifdef CONFIG_USB_U8500_DMA
+ switch (bit) {
+
+ case TX_CHANNEL_1:
+ dst_dev_type = DB8500_DMA_DEV38_USB_OTG_OEP_1_9;
+ break;
+ case TX_CHANNEL_2:
+ dst_dev_type = DB8500_DMA_DEV37_USB_OTG_OEP_2_10;
+ break;
+ case TX_CHANNEL_3:
+ dst_dev_type = DB8500_DMA_DEV36_USB_OTG_OEP_3_11;
+ break;
+ case TX_CHANNEL_4:
+ dst_dev_type = DB8500_DMA_DEV19_USB_OTG_OEP_4_12;
+ break;
+ case TX_CHANNEL_5:
+ dst_dev_type = DB8500_DMA_DEV18_USB_OTG_OEP_5_13;
+ break;
+ case TX_CHANNEL_6:
+ dst_dev_type = DB8500_DMA_DEV17_USB_OTG_OEP_6_14;
+ break;
+ case TX_CHANNEL_7:
+ dst_dev_type = DB8500_DMA_DEV16_USB_OTG_OEP_7_15;
+ break;
+
+ }
+
+ info->dst_dev_type = dst_dev_type;
+#endif
+
+ } else {
+ int src_dev_type;
+
+ info->dir = STEDMA40_PERIPH_TO_MEM;
+#ifdef CONFIG_NOMADIK_NDK15
+ info->src_dev_type = DMA_DEV_USB_OTG_1_RX;
+#endif
+#ifdef CONFIG_NOMADIK_NDK20
+ info->src_dev_type = DMA_DEV_USB_OTG_IEP_1_9;
+#endif
+
+#ifdef CONFIG_USB_U8500_DMA
+ switch (bit) {
+ case RX_CHANNEL_1:
+ src_dev_type = DB8500_DMA_DEV38_USB_OTG_IEP_1_9;
+ break;
+ case RX_CHANNEL_2:
+ src_dev_type =
+ DB8500_DMA_DEV37_USB_OTG_IEP_2_10;
+ break;
+ case RX_CHANNEL_3:
+ src_dev_type =
+ DB8500_DMA_DEV36_USB_OTG_IEP_3_11;
+ break;
+ case RX_CHANNEL_4:
+ src_dev_type =
+ DB8500_DMA_DEV19_USB_OTG_IEP_4_12;
+ break;
+ case RX_CHANNEL_5:
+ src_dev_type =
+ DB8500_DMA_DEV18_USB_OTG_IEP_5_13;
+ break;
+ case RX_CHANNEL_6:
+ src_dev_type =
+ DB8500_DMA_DEV17_USB_OTG_IEP_6_14;
+ break;
+ case RX_CHANNEL_7:
+ src_dev_type =
+ DB8500_DMA_DEV16_USB_OTG_IEP_7_15;
+ break;
+ default:
+ break;
+ }
+
+ info->src_dev_type = src_dev_type;
+#endif
+ info->dst_dev_type = STEDMA40_DEV_DST_MEMORY;
+ }
+ info->src_info.data_width = STEDMA40_WORD_WIDTH;
+ info->src_info.psize = STEDMA40_PSIZE_LOG_16;
+
+ info->dst_info.data_width = STEDMA40_WORD_WIDTH ;
+ info->dst_info.psize = STEDMA40_PSIZE_LOG_16;
+#endif
+ musb_channel->is_pipe_allocated = 1;
+ channel = &(musb_channel->channel);
+ channel->private_data = musb_channel;
+ channel->status = MUSB_DMA_STATUS_FREE;
+ channel->max_len = 0x10000;
+ /* Tx => mode 1; Rx => mode 0 */
+ channel->desired_mode = bit;
+ channel->actual_len = 0;
+
+ musb_channel->dma_chan = dma_request_channel(mask,
+ stedma40_filter,
+ info);
+ if (!musb_channel->dma_chan)
+ ERR("dma pipe can't be allocated\n");
+#ifndef CONFIG_USB_U8500_DMA
+ /* Tx => mode 1; Rx => mode 0 */
+ if (bit) {
+#else
+ if ((bit >= TX_CHANNEL_1) && (bit <= TX_CHANNEL_7)) {
+#endif
+ INIT_WORK(&musb_channel->channel_data_tx,
+ musb_channel_work_tx);
+ DBG(2, "channel allocated for TX, %s\n",
+ dma_chan_name(musb_channel->dma_chan));
+ } else {
+ INIT_WORK(&musb_channel->channel_data_rx,
+ musb_channel_work_rx);
+ DBG(2, "channel allocated for RX, %s\n",
+ dma_chan_name(musb_channel->dma_chan));
+ }
+
+ }
+ return 0;
+}
+
+static void dma_channel_release(struct dma_channel *channel);
+
+/**
+ * dma_controller_stop() - releases all the channels and frees the DMA pipes
+ * @c: pointer to DMA controller
+ *
+ * This function frees all of the logical channels and frees the DMA pipes
+*/
+
+static int dma_controller_stop(struct dma_controller *c)
+{
+ struct musb_dma_controller *controller = container_of(c,
+ struct musb_dma_controller, controller);
+ struct musb *musb = controller->private_data;
+ struct musb_dma_channel *musb_channel;
+ struct dma_channel *channel;
+ u8 bit;
+#ifndef CONFIG_USB_U8500_DMA
+ for (bit = 0; bit < 2; bit++) {
+#else
+ for (bit = 0; bit < (U8500_DMA_END_POINTS*2); bit++) {
+#endif
+ channel = &controller->channel[bit].channel;
+ musb_channel = channel->private_data;
+ dma_channel_release(channel);
+ if (musb_channel->info)
+ {
+ dma_release_channel(musb_channel->dma_chan);
+ kfree(musb_channel->info);
+ musb_channel->info = NULL;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * dma_controller_allocate() - allocates the DMA channels
+ * @c: pointer to DMA controller
+ * @hw_ep: pointer to endpoint
+ * @transmit: transmit or receive direction
+ *
+ * This function allocates the DMA channel and initializes
+ * the channel
+*/
+
+static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
+ struct musb_hw_ep *hw_ep, u8 transmit)
+{
+ struct musb_dma_controller *controller = container_of(c,
+ struct musb_dma_controller, controller);
+ struct musb_dma_channel *musb_channel = NULL;
+ struct dma_channel *channel = NULL;
+ u8 bit;
+
+#ifndef CONFIG_USB_U8500_DMA
+
+ /*bit 0 for receive and bit 1 for transmit*/
+ for (bit = 0; bit < 2; bit++) {
+ if (!(controller->used_channels & (1 << bit))) {
+
+ if ((transmit && !bit))
+ {
+ continue;
+ }
+ if ((!transmit && bit))
+ {
+ break;
+ }
+#else
+ if (hw_ep->epnum > 0 && hw_ep->epnum <= U8500_DMA_END_POINTS) {
+ if (transmit)
+ bit = hw_ep->epnum - 1;
+ else
+ bit = hw_ep->epnum + RX_END_POINT_OFFSET;
+ } else
+ return NULL;
+#endif
+ controller->used_channels |= (1 << bit);
+ musb_channel = &(controller->channel[bit]);
+ musb_channel->idx = bit;
+ musb_channel->epnum = hw_ep->epnum;
+ musb_channel->hw_ep = hw_ep;
+ musb_channel->transmit = transmit;
+ musb_channel->is_pipe_allocated = 1;
+ channel = &(musb_channel->channel);
+#ifndef CONFIG_USB_U8500_DMA
+ break;
+ }
+ }
+#endif
+ return channel;
+}
+
+/**
+ * dma_channel_release() - releases the DMA channel
+ * @channel: channel to be released
+ *
+ * This function releases the DMA channel
+ *
+*/
+
+static void dma_channel_release(struct dma_channel *channel)
+{
+ struct musb_dma_channel *musb_channel = channel->private_data;
+ channel->actual_len = 0;
+ musb_channel->start_addr = 0;
+ musb_channel->len = 0;
+
+ DBG(2, "enter\n");
+ musb_channel->controller->used_channels &=
+ ~(1 << musb_channel->idx);
+
+ channel->status = MUSB_DMA_STATUS_FREE;
+ if (musb_channel->is_pipe_allocated)
+ musb_channel->is_pipe_allocated = 0;
+ DBG(2, "exit\n");
+}
+#ifdef CONFIG_NOMADIK_NDK20
+extern void musb_memcpy(void *dest, void *source, unsigned int len);
+#endif
+
+/**
+ * configure_channel() - configures the source, destination addresses and
+ * starts the transfer
+ * @channel: pointer to DMA channel
+ * @packet_sz: packet size
+ * @mode: Dma mode
+ * @dma_addr: DMA source address for transmit direction
+ * or DMA destination address for receive direction
+ * @len: length
+ * This function configures the source and destination addresses for DMA
+ * operation and initiates the DMA transfer
+*/
+
+static bool configure_channel(struct dma_channel *channel,
+ u16 packet_sz, u8 mode,
+ dma_addr_t dma_addr, u32 len)
+{
+ struct musb_dma_channel *musb_channel = channel->private_data;
+ struct musb_hw_ep *hw_ep = musb_channel->hw_ep;
+ struct musb *musb = hw_ep->musb;
+ void __iomem *mbase = musb->mregs;
+ u32 dma_count;
+#ifdef CONFIG_NOMADIK_NDK15
+ struct stm_dma_pipe_info *info;
+#endif
+ struct dma_chan *dma_chan = musb_channel->dma_chan;
+ struct dma_async_tx_descriptor *dma_desc;
+ enum dma_data_direction direction;
+ struct scatterlist sg;
+
+#ifndef CONFIG_USB_U8500_DMA
+ struct musb_qh *qh;
+ struct urb *urb;
+#endif
+ unsigned int usb_fifo_addr = (unsigned int)(MUSB_FIFO_OFFSET(hw_ep->epnum) + mbase);
+
+#ifndef CONFIG_USB_U8500_DMA
+ if (musb_channel->transmit)
+ qh = hw_ep->out_qh;
+ else
+ qh = hw_ep->in_qh;
+ urb = next_urb(qh);
+#endif
+#ifdef CONFIG_NOMADIK_NDK15
+ info = musb_channel->info;
+
+ /* For High speed devices*/
+ if (urb->dev->speed == USB_SPEED_HIGH)
+ {
+ info->src_info.burst_size = DMA_BURST_SIZE_128;
+ info->dst_info.burst_size = DMA_BURST_SIZE_128;
+ } else
+ {
+ info->src_info.burst_size = DMA_BURST_SIZE_16;
+ info->dst_info.burst_size = DMA_BURST_SIZE_16;
+ }
+ stm_configure_dma_channel(musb_channel->id, info);
+#endif
+
+ dma_count = len - (len % packet_sz);
+ musb_channel->cur_len = dma_count;
+ usb_fifo_addr = U8500_USBOTG_BASE + ((unsigned int)usb_fifo_addr & 0xFFFF);
+
+#ifndef CONFIG_USB_U8500_DMA
+ if (!(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
+ if (musb_channel->transmit)
+ {
+ dma_addr = musb->tx_dma_phy;
+
+#ifdef CONFIG_NOMADIK_NDK15
+ memcpy((void *)musb->tx_dma_log, urb->transfer_buffer, dma_count);
+#endif
+#ifdef CONFIG_NOMADIK_NDK20
+ musb_memcpy((void *)musb->tx_dma_log, urb->transfer_buffer, dma_count);
+#endif
+ } else {
+ dma_addr = musb->rx_dma_phy;
+ }
+ }
+#endif
+
+ stedma40_set_dev_addr(dma_chan, usb_fifo_addr, usb_fifo_addr);
+
+ sg_init_table(&sg, 1);
+ sg_set_page(&sg, pfn_to_page(PFN_DOWN(dma_addr)), dma_count,
+ offset_in_page(dma_addr));
+ sg_dma_address(&sg) = dma_addr;
+ sg_dma_len(&sg) = dma_count;
+
+ direction = musb_channel->transmit ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+ dma_desc = dma_chan->device->
+ device_prep_slave_sg(dma_chan, &sg, 1, direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!dma_desc)
+ return false;
+
+ dma_desc->callback = musb_channel->transmit ?
+ musb_tx_dma_controller_handler :
+ musb_rx_dma_controller_handler;
+ dma_desc->callback_param = channel;
+ dma_desc->tx_submit(dma_desc);
+ dma_async_issue_pending(dma_chan);
+
+#ifdef CONFIG_NOMADIK_NDK15
+ if (musb_channel->transmit)
+ {
+ uint32_t dma_sel = 0;
+
+/* enabling EP2 tx on usb dma channel 0 */
+ dma_sel = musb_readw(musb->mregs, MUSB_O_HDRC_DMASEL);
+ dma_sel &= ~MUSB_TX_DMA_MASK;
+ dma_sel |= MUSB_EP_TX_DMASEL_VAL(2);
+ DBG(2, "dma_sel val for RX = %x\n", dma_sel);
+ musb_writew(musb->mregs, MUSB_O_HDRC_DMASEL, dma_sel);
+ DBG(2, "DMASEL reg = %x\n", musb_readw(musb->mregs, MUSB_O_HDRC_DMASEL));
+ } else
+ {
+ uint32_t dma_sel = 0;
+
+ /* enabling EP1 rx on usb dma channel 1 */
+ dma_sel = musb_readl(musb->mregs, MUSB_O_HDRC_DMASEL);
+ dma_sel &= ~MUSB_RX_DMA_MASK;
+ dma_sel |= MUSB_EP_RX_DMASEL_VAL(1);
+ DBG(2, "dma_sel val for RX = %x\n", dma_sel);
+ musb_writel(musb->mregs, MUSB_O_HDRC_DMASEL, dma_sel);
+ DBG(2, "DMASEL reg = %x\n", musb_readl(musb->mregs, MUSB_O_HDRC_DMASEL));
+ }
+#endif
+
+ //channel->last_xfer = 0;
+ return true;
+}
+
+/**
+ * dma_channel_program() - Configures the channel and initiates transfer
+ * @channel: pointer to DMA channel
+ * @packet_sz: packet size
+ * @mode: mode
+ * @dma_addr: physical address of memory
+ * @len: length
+ *
+ * This function configures the channel and initiates the DMA transfer
+*/
+
+static int dma_channel_program(struct dma_channel *channel,
+ u16 packet_sz, u8 mode,
+ dma_addr_t dma_addr, u32 len)
+{
+ struct musb_dma_channel *musb_channel = channel->private_data;
+ bool ret;
+
+ BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
+ channel->status == MUSB_DMA_STATUS_BUSY);
+ if (len < packet_sz)
+ return false;
+ if (!musb_channel->transmit && len < packet_sz)
+ return false;
+ channel->actual_len = 0;
+ musb_channel->start_addr = dma_addr;
+ musb_channel->len = len;
+ musb_channel->max_packet_sz = packet_sz;
+ channel->status = MUSB_DMA_STATUS_BUSY;
+
+
+ if ((mode == 1) && (len >= packet_sz))
+ ret = configure_channel(channel, packet_sz, 1, dma_addr, len);
+ else
+ ret = configure_channel(channel, packet_sz, 0, dma_addr, len);
+ return ret;
+}
+
+/**
+ * dma_channel_abort() - aborts the DMA transfer
+ * @channel: pointer to DMA channel.
+ *
+ * This function aborts the DMA transfer.
+*/
+
+static int dma_channel_abort(struct dma_channel *channel)
+{
+ struct musb_dma_channel *musb_channel = channel->private_data;
+ void __iomem *mbase = musb_channel->controller->base;
+ u16 csr;
+ if (channel->status == MUSB_DMA_STATUS_BUSY) {
+ if (musb_channel->transmit) {
+
+ csr = musb_readw(mbase,
+ MUSB_EP_OFFSET(musb_channel->epnum,
+ MUSB_TXCSR));
+ csr &= ~(MUSB_TXCSR_AUTOSET |
+ MUSB_TXCSR_DMAENAB |
+ MUSB_TXCSR_DMAMODE);
+ musb_writew(mbase,
+ MUSB_EP_OFFSET(musb_channel->epnum, MUSB_TXCSR),
+ csr);
+ } else {
+ csr = musb_readw(mbase,
+ MUSB_EP_OFFSET(musb_channel->epnum,
+ MUSB_RXCSR));
+ csr &= ~(MUSB_RXCSR_AUTOCLEAR |
+ MUSB_RXCSR_DMAENAB |
+ MUSB_RXCSR_DMAMODE);
+ musb_writew(mbase,
+ MUSB_EP_OFFSET(musb_channel->epnum, MUSB_RXCSR),
+ csr);
+ }
+
+ if (musb_channel->is_pipe_allocated)
+ {
+ musb_channel->dma_chan->device->
+ device_control(musb_channel->dma_chan, DMA_TERMINATE_ALL, 0);
+ channel->status = MUSB_DMA_STATUS_FREE;
+ }
+ }
+ return 0;
+}
+
+/**
+ * musb_rx_dma_controller_handler() - callback invoked when the data is received in the receive direction
+ * @private_data: DMA channel
+ *
+ * This callback is invoked when the DMA transfer is completed in the receive direction.
+*/
+void musb_rx_dma_controller_handler(void *private_data)
+{
+ struct dma_channel *channel = (struct dma_channel *)private_data;
+ struct musb_dma_channel *musb_channel = channel->private_data;
+#ifndef CONFIG_USB_U8500_DMA
+ struct musb_hw_ep *hw_ep = musb_channel->hw_ep;
+ struct musb *musb = hw_ep->musb;
+ void __iomem *mbase = musb->mregs;
+ unsigned long flags, pio;
+ unsigned int rxcsr;
+ struct musb_qh *qh = hw_ep->in_qh;
+ struct urb *urb;
+ spin_lock_irqsave(&musb->lock, flags);
+ urb = next_urb(qh);
+ musb_ep_select(mbase, hw_ep->epnum);
+ channel->actual_len = musb_channel->cur_len;
+ pio = musb_channel->len - channel->actual_len;
+ if (!(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
+ memcpy(urb->transfer_buffer,
+ (void *)musb->rx_dma_log, channel->actual_len);
+ musb_memcpy(urb->transfer_buffer,
+ (void *)musb->rx_dma_log, channel->actual_len);
+ }
+ if (!pio) {
+ channel->status = MUSB_DMA_STATUS_FREE;
+ musb_dma_completion(musb, musb_channel->epnum,
+ musb_channel->transmit);
+ }
+ /*else
+ {
+ channel->last_xfer = 1;
+ }*/
+ spin_unlock_irqrestore(&musb->lock, flags);
+#else
+ schedule_work(&musb_channel->channel_data_rx);
+#endif
+}
+
+/**
+ * musb_tx_dma_controller_handler() - callback invoked on the transmit direction DMA data transfer
+ * @private_data: pointer to DMA channel.
+ *
+ * This callback is invoked when the DMA tranfer is completed in the transmit direction
+*/
+
+void musb_tx_dma_controller_handler(void *private_data)
+{
+ struct dma_channel *channel = (struct dma_channel *)private_data;
+ struct musb_dma_channel *musb_channel = channel->private_data;
+#ifndef CONFIG_USB_U8500_DMA
+ struct musb_hw_ep *hw_ep = musb_channel->hw_ep;
+ struct musb *musb = hw_ep->musb;
+ void __iomem *mbase = musb->mregs;
+ unsigned long flags, pio;
+ unsigned int txcsr;
+ struct musb_qh *qh = hw_ep->out_qh;
+ struct urb *urb;
+ spin_lock_irqsave(&musb->lock, flags);
+ musb_ep_select(mbase, hw_ep->epnum);
+ channel->actual_len = musb_channel->cur_len;
+ pio = musb_channel->len - channel->actual_len;
+ if (!pio)
+ {
+ channel->status = MUSB_DMA_STATUS_FREE;
+ musb_dma_completion(musb, musb_channel->epnum,
+ musb_channel->transmit);
+ }
+ if (pio)
+ {
+ channel->status = MUSB_DMA_STATUS_FREE;
+ urb = next_urb(qh);
+ qh->offset += channel->actual_len;
+ buf = urb->transfer_buffer + qh->offset;
+ musb_write_fifo(hw_ep, pio, buf);
+ qh->segsize = pio;
+ musb_writew(hw_ep->regs, MUSB_TXCSR, MUSB_TXCSR_TXPKTRDY);
+ //channel->last_xfer = 1;
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+#else
+ schedule_work(&musb_channel->channel_data_tx);
+#endif
+}
+
+/**
+ * dma_controller_destroy() - deallocates the DMA controller
+ * @c: pointer to dma controller.
+ *
+ * This function deallocates the DMA controller.
+*/
+
+void dma_controller_destroy(struct dma_controller *c)
+{
+ struct musb_dma_controller *controller = container_of(c,
+ struct musb_dma_controller, controller);
+ struct musb_dma_channel *musb_channel = NULL;
+ u8 bit;
+ if (!controller)
+ return;
+ for (bit = 0; bit < MUSB_HSDMA_CHANNELS; bit++) {
+ musb_channel = &(controller->channel[bit]);
+ }
+ if (controller->irq)
+ free_irq(controller->irq, c);
+
+ kfree(controller);
+}
+
+/**
+ * musb_channel_work_tx() - Invoked by worker thread
+ * @data: worker queue data
+ *
+ * This function is invoked by worker thread when the DMA transfer
+ * is completed in the transmit direction.
+*/
+
+static void musb_channel_work_tx(struct work_struct *data)
+{
+ struct musb_dma_channel *musb_channel = container_of(data,
+ struct musb_dma_channel, channel_data_tx);
+ struct musb_hw_ep *hw_ep = musb_channel->hw_ep;
+ struct musb *musb = hw_ep->musb;
+ unsigned long flags;
+ spin_lock_irqsave(&musb->lock, flags);
+ musb_channel->channel.actual_len = musb_channel->cur_len;
+ musb_channel->channel.status = MUSB_DMA_STATUS_FREE;
+ musb_ep_select(musb->mregs, hw_ep->epnum);
+ musb_dma_completion(musb, musb_channel->epnum,
+ musb_channel->transmit);
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+/**
+ * musb_channel_work_tx() - Invoked by worker thread
+ * @data: worker queue data
+ *
+ * This function is invoked by worker thread when the
+ * DMA transfer is completed in the receive direction.
+*/
+
+static void musb_channel_work_rx(struct work_struct *data)
+{
+ struct musb_dma_channel *musb_channel = container_of(data,
+ struct musb_dma_channel, channel_data_rx);
+ struct musb_hw_ep *hw_ep = musb_channel->hw_ep;
+ struct musb *musb = hw_ep->musb;
+ void __iomem *mbase = musb->mregs;
+ unsigned long flags;
+ spin_lock_irqsave(&musb->lock, flags);
+ musb_channel->channel.actual_len = musb_channel->cur_len;
+ musb_channel->channel.status = MUSB_DMA_STATUS_FREE;
+ musb_ep_select(mbase, hw_ep->epnum);
+ musb_dma_completion(musb, musb_channel->epnum,
+ musb_channel->transmit);
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+/**
+ * dma_controller_create() - creates the dma controller and initializes callbacks
+ *
+ * @musb: pointer to mentor core driver data instance|
+ * @base: base address of musb registers.
+ *
+ * This function creates the DMA controller and initializes the callbacks
+ * that are invoked from the Mentor IP core.
+*/
+
+struct dma_controller *__init
+dma_controller_create(struct musb *musb, void __iomem *base)
+{
+ struct musb_dma_controller *controller;
+
+ controller = kzalloc(sizeof(*controller), GFP_KERNEL);
+ if (!controller)
+ return NULL;
+
+ controller->channel_count = MUSB_HSDMA_CHANNELS;
+ controller->private_data = musb;
+ controller->base = base;
+
+ controller->controller.start = dma_controller_start;
+ controller->controller.stop = dma_controller_stop;
+ controller->controller.channel_alloc = dma_channel_allocate;
+ controller->controller.channel_release = dma_channel_release;
+ controller->controller.channel_program = dma_channel_program;
+ controller->controller.channel_abort = dma_channel_abort;
+
+ return &controller->controller;
+}
diff --git a/drivers/usb/musb/stm_musb_dma.h b/drivers/usb/musb/stm_musb_dma.h
new file mode 100644
index 00000000000..753cf08a882
--- /dev/null
+++ b/drivers/usb/musb/stm_musb_dma.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * Copyright (C) 2009 ST-Ericsson SA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __STM_MUSB_DMA_H__
+#define __STM_MUSB_DMA_H__
+
+#define MUSB_HSDMA_CHANNELS 16
+struct musb_dma_controller;
+struct dma_chan;
+struct stedma40_chan_cfg;
+struct musb_dma_channel {
+ struct dma_channel channel;
+ struct musb_dma_controller *controller;
+ struct stedma40_chan_cfg *info;
+ struct musb_hw_ep *hw_ep;
+ struct work_struct channel_data_tx;
+ struct work_struct channel_data_rx;
+ u32 start_addr;
+ u32 len;
+ u32 is_pipe_allocated;
+ u16 max_packet_sz;
+ u8 idx;
+ struct dma_chan *dma_chan;
+ unsigned int cur_len;
+ u8 epnum;
+ u8 last_xfer;
+ u8 transmit;
+};
+
+struct musb_dma_controller {
+ struct dma_controller controller;
+ struct musb_dma_channel channel[MUSB_HSDMA_CHANNELS];
+ void *private_data;
+ void __iomem *base;
+ u8 channel_count;
+ u8 used_channels;
+ u8 irq;
+};
+void musb_rx_dma_controller_handler(void *private_data);
+void musb_tx_dma_controller_handler(void *private_data);
+static void musb_channel_work_tx(struct work_struct *data);
+static void musb_channel_work_rx(struct work_struct *data);
+#endif
+
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3d94a147172..5ec72c90e5f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -245,6 +245,7 @@ config FB_TILEBLITTING
comment "Frame buffer hardware drivers"
depends on FB
+source "drivers/video/mcde/Kconfig"
config FB_CIRRUS
tristate "Cirrus Logic support"
depends on FB && (ZORRO || PCI)
@@ -304,6 +305,7 @@ config FB_ARMCLCD
inserted into and removed from the running kernel), say M
here and read <file:Documentation/kbuild/modules.txt>. The module
will be called amba-clcd.
+source "drivers/video/b2r2/Kconfig"
choice
@@ -2234,6 +2236,7 @@ source "drivers/video/omap2/Kconfig"
source "drivers/video/backlight/Kconfig"
source "drivers/video/display/Kconfig"
+source "drivers/video/av8100/Kconfig"
if VT
source "drivers/video/console/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ddc2af2ba45..e16c38f2537 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -126,6 +126,9 @@ obj-$(CONFIG_FB_XILINX) += xilinxfb.o
obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
obj-$(CONFIG_FB_OMAP) += omap/
obj-y += omap2/
+obj-$(CONFIG_FB_MCDE) += mcde/
+obj-$(CONFIG_AV8100) += av8100/
+obj-y += b2r2/
obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
obj-$(CONFIG_FB_CARMINE) += carminefb.o
obj-$(CONFIG_FB_MB862XX) += mb862xx/
diff --git a/drivers/video/av8100/Kconfig b/drivers/video/av8100/Kconfig
new file mode 100644
index 00000000000..6fe0f88d9b8
--- /dev/null
+++ b/drivers/video/av8100/Kconfig
@@ -0,0 +1,23 @@
+config AV8100
+ tristate "AV8100 driver support(HDMI/CVBS)"
+ default n
+ help
+ Please enable this feature if hdmi/tvout driver support is required.
+
+config AV8100_HWTRIG_I2SDAT3
+ bool "AV8100 HW trig on I2SDAT3"
+ default n
+ depends on AV8100
+ ---help---
+ If you say Y here AV8100 will use HW triggering
+ from AV8100 I2SDAT3 to MCDE sync1.
+ If you say N here AV8100 will use HW triggering
+ method from AV8100 INT to MCDE sync0.
+
+config HDMI_AV8100_DEBUG
+ bool "HDMI and AV8100 debug messages"
+ default n
+ depends on AV8100
+ ---help---
+ Say Y here if you want the HDMI and AV8100 driver to output debug messages
+
diff --git a/drivers/video/av8100/Makefile b/drivers/video/av8100/Makefile
new file mode 100644
index 00000000000..2d3028b18ca
--- /dev/null
+++ b/drivers/video/av8100/Makefile
@@ -0,0 +1,10 @@
+# Make file for compiling and loadable module HDMI
+
+obj-$(CONFIG_AV8100) += av8100.o hdmi.o
+
+ifdef CONFIG_HDMI_AV8100_DEBUG
+EXTRA_CFLAGS += -DDEBUG
+endif
+
+clean-files := av8100.o hdmi.o built-in.o modules.order
+
diff --git a/drivers/video/av8100/av8100.c b/drivers/video/av8100/av8100.c
new file mode 100644
index 00000000000..6482ad8959c
--- /dev/null
+++ b/drivers/video/av8100/av8100.c
@@ -0,0 +1,3303 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * AV8100 driver
+ *
+ * Author: Per Persson <per.xb.persson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/timer.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include "av8100_regs.h"
+#include <video/av8100.h>
+#include <video/hdmi.h>
+#include "av8100_fw.h"
+#include "av8100v2_fw.h"
+
+#define AV8100_INT_EVENT 0x1
+#define AV8100_TIMER_INT_EVENT 0x2
+
+#define AV8100_TIMER_INTERRUPT_POLLING_TIME 250
+
+#define GPIO_AV8100_RSTN 196
+#define AV8100_MASTER_CLOCK_TIMING 0x3
+#define AV8100_ON_TIME 1
+#define AV8100_DENC_OFF_TIME 3
+#define AV8100_HDMI_OFF_TIME 0
+#define AV8100_COMMAND_OFFSET 0x10
+#define AV8100_COMMAND_MAX_LENGTH 0x81
+#define AV8100_CMD_BUF_OFFSET (AV8100_COMMAND_OFFSET + 1)
+#define AV8100_2ND_RET_BYTE_OFFSET (AV8100_COMMAND_OFFSET + 1)
+#define AV8100_CEC_RET_BUF_OFFSET (AV8100_COMMAND_OFFSET + 4)
+#define AV8100_HDCP_RET_BUF_OFFSET (AV8100_COMMAND_OFFSET + 2)
+#define AV8100_EDID_RET_BUF_OFFSET (AV8100_COMMAND_OFFSET + 1)
+#define AV8100_FUSE_CRC_OFFSET (AV8100_COMMAND_OFFSET + 2)
+#define AV8100_FUSE_PRGD_OFFSET (AV8100_COMMAND_OFFSET + 3)
+
+
+#define AV8100_TE_LINE_NB_14 14
+#define AV8100_TE_LINE_NB_17 17
+#define AV8100_TE_LINE_NB_18 18
+#define AV8100_TE_LINE_NB_21 21
+#define AV8100_TE_LINE_NB_22 22
+#define AV8100_TE_LINE_NB_30 30
+#define AV8100_TE_LINE_NB_38 38
+#define AV8100_TE_LINE_NB_40 40
+#define AV8100_UI_X4_DEFAULT 6
+
+#define HDMI_REQUEST_FOR_REVOCATION_LIST_INPUT 2
+#define HDMI_CEC_MESSAGE_WRITE_BUFFER_SIZE 16
+#define HDMI_HDCP_SEND_KEY_SIZE 7
+#define HDMI_INFOFRAME_DATA_SIZE 28
+#define HDMI_FUSE_AES_KEY_SIZE 16
+#define HDMI_FUSE_AES_KEY_RET_SIZE 2
+
+#define HPDS_INVALID 0xF
+#define CPDS_INVALID 0xF
+#define CECRX_INVALID 0xF
+
+#define REG_16_8_LSB(p) ((u8)(p & 0xFF))
+#define REG_16_8_MSB(p) ((u8)((p & 0xFF00)>>8))
+#define REG_32_8_MSB(p) ((u8)((p & 0xFF000000)>>24))
+#define REG_32_8_MMSB(p) ((u8)((p & 0x00FF0000)>>16))
+#define REG_32_8_MLSB(p) ((u8)((p & 0x0000FF00)>>8))
+#define REG_32_8_LSB(p) ((u8)(p & 0x000000FF))
+#define REG_10_8_MSB(p) ((u8)((p & 0x300)>>8))
+#define REG_12_8_MSB(p) ((u8)((p & 0xf00)>>8))
+
+DEFINE_MUTEX(av8100_hw_mutex);
+#define LOCK_AV8100_HW mutex_lock(&av8100_hw_mutex)
+#define UNLOCK_AV8100_HW mutex_unlock(&av8100_hw_mutex)
+
+#define AV8100_DEBUG_EXTRA
+#define AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS
+#define CEC_ADDR_OFFSET 3
+#define AV8100_POWERON_WAITTIME1_MS 1
+#define AV8100_POWERON_WAITTIME2_MS 1
+
+struct av8100_config_t {
+ struct i2c_client *client;
+ struct i2c_device_id *id;
+ struct av8100_video_input_format_cmd hdmi_video_input_cmd;
+ struct av8100_audio_input_format_cmd hdmi_audio_input_cmd;
+ struct av8100_video_output_format_cmd hdmi_video_output_cmd;
+ struct av8100_video_scaling_format_cmd hdmi_video_scaling_cmd;
+ struct av8100_color_space_conversion_format_cmd
+ hdmi_color_space_conversion_cmd;
+ struct av8100_cec_message_write_format_cmd
+ hdmi_cec_message_write_cmd;
+ struct av8100_cec_message_read_back_format_cmd
+ hdmi_cec_message_read_back_cmd;
+ struct av8100_denc_format_cmd hdmi_denc_cmd;
+ struct av8100_hdmi_cmd hdmi_cmd;
+ struct av8100_hdcp_send_key_format_cmd hdmi_hdcp_send_key_cmd;
+ struct av8100_hdcp_management_format_cmd
+ hdmi_hdcp_management_format_cmd;
+ struct av8100_infoframes_format_cmd hdmi_infoframes_cmd;
+ struct av8100_edid_section_readback_format_cmd
+ hdmi_edid_section_readback_cmd;
+ struct av8100_pattern_generator_format_cmd hdmi_pattern_generator_cmd;
+ struct av8100_fuse_aes_key_format_cmd hdmi_fuse_aes_key_cmd;
+};
+
+struct av8100_globals_t {
+ int denc_off_time;/* 5 volt time */
+ int hdmi_off_time;/* 5 volt time */
+ int on_time;/* 5 volt time */
+ u8 hpdm;/*stby_int_mask*/
+ u8 cpdm;/*stby_int_mask*/
+#ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS
+ u8 hpds_old;
+ u8 cpds_old;
+ u8 cecrx_old;
+ u8 hdcps_old;
+#endif
+ void (*hdmi_ev_cb)(enum av8100_hdmi_event);
+};
+
+/**
+ * struct av8100_cea - CEA(consumer electronic access) standard structure
+ * @cea_id:
+ * @cea_nb:
+ * @vtotale:
+ **/
+
+struct av8100_cea {
+ char cea_id[40];
+ int cea_nb;
+ int vtotale;
+ int vactive;
+ int vsbp;
+ int vslen;
+ int vsfp;
+ char vpol[5];
+ int htotale;
+ int hactive;
+ int hbp;
+ int hslen;
+ int hfp;
+ int frequence;
+ char hpol[5];
+ int reg_line_duration;
+ int blkoel_duration;
+ int uix4;
+ int pll_mult;
+ int pll_div;
+};
+
+enum av8100_command_size {
+ AV8100_COMMAND_VIDEO_INPUT_FORMAT_SIZE = 0x17,
+ AV8100_COMMAND_AUDIO_INPUT_FORMAT_SIZE = 0x8,
+ AV8100_COMMAND_VIDEO_OUTPUT_FORMAT_SIZE = 0x1E,
+ AV8100_COMMAND_VIDEO_SCALING_FORMAT_SIZE = 0x11,
+ AV8100_COMMAND_COLORSPACECONVERSION_SIZE = 0x1D,
+ AV8100_COMMAND_CEC_MESSAGE_WRITE_SIZE = 0x12,
+ AV8100_COMMAND_CEC_MESSAGE_READ_BACK_SIZE = 0x1,
+ AV8100_COMMAND_DENC_SIZE = 0x6,
+ AV8100_COMMAND_HDMI_SIZE = 0x4,
+ AV8100_COMMAND_HDCP_SENDKEY_SIZE = 0xA,
+ AV8100_COMMAND_HDCP_MANAGEMENT_SIZE = 0x4,
+ AV8100_COMMAND_INFOFRAMES_SIZE = 0x21,
+ AV8100_COMMAND_EDID_SECTION_READBACK_SIZE = 0x3,
+ AV8100_COMMAND_PATTERNGENERATOR_SIZE = 0x4,
+ AV8100_COMMAND_FUSE_AES_KEY_SIZE = 0x12,
+ AV8100_COMMAND_FUSE_AES_CHK_SIZE = 0x2,
+};
+
+static void clr_plug_status(enum av8100_plugin_status status);
+static void set_plug_status(enum av8100_plugin_status status);
+static void cec_rx(void);
+static void hdcp_changed(void);
+static int av8100_open(struct inode *inode, struct file *filp);
+static int av8100_release(struct inode *inode, struct file *filp);
+static int av8100_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+static int __devinit av8100_probe(struct i2c_client *i2cClient,
+ const struct i2c_device_id *id);
+static int __devexit av8100_remove(struct i2c_client *i2cClient);
+
+static struct av8100_config_t *av8100_config;
+static struct av8100_status g_av8100_status = {0};
+#ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS
+static struct timer_list av8100_timer;
+#endif
+static wait_queue_head_t av8100_event;
+static int av8100_flag = 0x0;
+static struct av8100_globals_t *av8100_globals;
+static u8 chip_version;
+static char av8100_receivetab[AV8100_FW_SIZE_V2];
+struct device *av8100dev;
+
+static const struct file_operations av8100_fops = {
+ .owner = THIS_MODULE,
+ .open = av8100_open,
+ .release = av8100_release,
+ .ioctl = av8100_ioctl
+};
+
+static struct miscdevice av8100_miscdev = {
+ MISC_DYNAMIC_MINOR,
+ "av8100",
+ &av8100_fops
+};
+
+struct av8100_cea av8100_all_cea[29] = {
+/* cea id
+ * cea_nr vtot vact vsbpp vslen
+ * vsfp vpol htot hact hbp hslen hfp freq
+ * hpol rld bd uix4 pm pd */
+{ "0 CUSTOM ",
+ 0, 0, 0, 0, 0,
+ 0, "-", 800, 640, 16, 96, 10, 25200000,
+ "-", 0, 0, 0, 0, 0},/*Settings to be defined*/
+{ "1 CEA 1 VESA 4 640x480p @ 60 Hz ",
+ 1, 525, 480, 33, 2,
+ 10, "-", 800, 640, 49, 290, 146, 25200000,
+ "-", 2438, 1270, 6, 32, 1},/*RGB888*/
+{ "2 CEA 2 - 3 720x480p @ 60 Hz 4:3 ",
+ 2, 525, 480, 30, 6,
+ 9, "-", 858, 720, 34, 130, 128, 27027000,
+ "-", 1828, 0x3C0, 8, 24, 1},/*RGB565*/
+{ "3 CEA 4 1280x720p @ 60 Hz ",
+ 4, 750, 720, 20, 5,
+ 5, "+", 1650, 1280, 114, 39, 228, 74250000,
+ "+", 1706, 164, 6, 32, 1},/*RGB565*/
+{ "4 CEA 5 1920x1080i @ 60 Hz ",
+ 5, 1125, 540, 20, 5,
+ 0, "+", 2200, 1920, 88, 44, 10, 74250000,
+ "+", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "5 CEA 6-7 480i (NTSC) ",
+ 6, 525, 240, 44, 5,
+ 0, "-", 858, 720, 12, 64, 10, 13513513,
+ "-", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "6 CEA 14-15 480p @ 60 Hz ",
+ 14, 525, 480, 44, 5,
+ 0, "-", 858, 720, 12, 64, 10, 27027000,
+ "-", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "7 CEA 16 1920x1080p @ 60 Hz ",
+ 16, 1125, 1080, 36, 5,
+ 0, "+", 1980, 1280, 440, 40, 10, 133650000,
+ "+", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "8 CEA 17-18 720x576p @ 50 Hz ",
+ 17, 625, 576, 44, 5,
+ 0, "-", 864, 720, 12, 64, 10, 27000000,
+ "-", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "9 CEA 19 1280x720p @ 50 Hz ",
+ 19, 750, 720, 25, 5,
+ 0, "+", 1980, 1280, 440, 40, 10, 74250000,
+ "+", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "10 CEA 20 1920 x 1080i @ 50 Hz ",
+ 20, 1125, 540, 20, 5,
+ 0, "+", 2640, 1920, 528, 44, 10, 74250000,
+ "+", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "11 CEA 21-22 576i (PAL) ",
+ 21, 625, 288, 44, 5,
+ 0, "-", 1728, 1440, 12, 64, 10, 27000000,
+ "-", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "12 CEA 29/30 576p ",
+ 29, 625, 576, 44, 5,
+ 0, "-", 864, 720, 12, 64, 10, 27000000,
+ "-", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "13 CEA 31 1080p 50Hz ",
+ 31, 1125, 1080, 44, 5,
+ 0, "-", 2640, 1920, 12, 64, 10, 148500000,
+ "-", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "14 CEA 32 1920x1080p @ 24 Hz ",
+ 32, 1125, 1080, 36, 5,
+ 4, "+", 2750, 1920, 660, 44, 153, 74250000,
+ "+", 2844, 0x530, 6, 32, 1},/*RGB565*/
+{ "15 CEA 33 1920x1080p @ 25 Hz ",
+ 33, 1125, 1080, 36, 5,
+ 4, "+", 2640, 1920, 528, 44, 10, 74250000,
+ "+", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "16 CEA 34 1920x1080p @ 30Hz ",
+ 34, 1125, 1080, 36, 5,
+ 4, "+", 2200, 1920, 91, 44, 153, 74250000,
+ "+", 2275, 0xAB, 6, 32, 1},/*RGB565*/
+{ "17 CEA 60 1280x720p @ 24 Hz ",
+ 60, 750, 720, 20, 5,
+ 5, "+", 3300, 1280, 284, 50, 2276, 59400000,
+ "+", 4266, 0xAD0, 5, 32, 1},/*RGB565*/
+{ "18 CEA 61 1280x720p @ 25 Hz ",
+ 61, 750, 720, 20, 5,
+ 5, "+", 3960, 1280, 228, 39, 2503, 74250000,
+ "+", 4096, 0x500, 5, 32, 1},/*RGB565*/
+{ "19 CEA 62 1280x720p @ 30 Hz ",
+ 62, 750, 720, 20, 5,
+ 5, "+", 3300, 1280, 228, 39, 1820, 74250000,
+ "+", 3413, 0x770, 5, 32, 1},/*RGB565*/
+{ "20 VESA 9 800x600 @ 60 Hz ",
+ 109, 628, 600, 28, 4,
+ 0, "+", 1056, 800, 40, 128, 10, 20782080,
+ "+", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "21 VESA 14 848x480 @ 60 Hz ",
+ 114, 500, 480, 20, 5,
+ 0, "+", 1056, 848, 24, 80, 10, 31680000,
+ "-", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "22 VESA 16 1024x768 @ 60 Hz ",
+ 116, 806, 768, 38, 6,
+ 0, "-", 1344, 1024, 24, 135, 10, 65000000,
+ "-", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "23 VESA 22 1280x768 @ 60 Hz ",
+ 122, 802, 768, 34, 4,
+ 0, "+", 1688, 1280, 48, 160, 10, 81250000,
+ "-", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "24 VESA 23 1280x768 @ 60 Hz ",
+ 123, 798, 768, 30, 7,
+ 0, "+", 1664, 1280, 64, 128, 10, 79500000,
+ "-", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "25 VESA 27 1280x800 @ 60 Hz ",
+ 127, 823, 800, 23, 6,
+ 0, "+", 1440, 1280, 48, 32, 10, 71000000,
+ "+", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "26 VESA 28 1280x800 @ 60 Hz ",
+ 128, 831, 800, 31, 6,
+ 0, "+", 1680, 1280, 72, 128, 10, 83500000,
+ "-", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "27 VESA 39 1360x768 @ 60 Hz ",
+ 139, 790, 768, 22, 5,
+ 0, "-", 1520, 1360, 48, 32, 10, 72000000,
+ "+", 0, 0, 0, 0, 0},/*Settings to be define*/
+{ "28 VESA 81 1360x768 @ 60 Hz ",
+ 181, 798, 768, 30, 5,
+ 0, "+", 1776, 1360, 72, 136, 10, 84750000,
+ "-", 0, 0, 0, 0, 0} /*Settings to be define*/
+};
+
+const struct av8100_color_space_conversion_format_cmd col_cvt_identity = {
+ .c0 = 0x0100,
+ .c1 = 0x0000,
+ .c2 = 0x0000,
+ .c3 = 0x0000,
+ .c4 = 0x0100,
+ .c5 = 0x0000,
+ .c6 = 0x0000,
+ .c7 = 0x0000,
+ .c8 = 0x0100,
+ .aoffset = 0x0000,
+ .boffset = 0x0000,
+ .coffset = 0x0000,
+ .lmax = 0xff,
+ .lmin = 0x00,
+ .cmax = 0xff,
+ .cmin = 0x00,
+};
+
+const struct av8100_color_space_conversion_format_cmd
+ col_cvt_identity_clamp_yuv = {
+ .c0 = 0x0100,
+ .c1 = 0x0000,
+ .c2 = 0x0000,
+ .c3 = 0x0000,
+ .c4 = 0x0100,
+ .c5 = 0x0000,
+ .c6 = 0x0000,
+ .c7 = 0x0000,
+ .c8 = 0x0100,
+ .aoffset = 0x0000,
+ .boffset = 0x0000,
+ .coffset = 0x0000,
+ .lmax = 0xeb,
+ .lmin = 0x10,
+ .cmax = 0xf0,
+ .cmin = 0x10,
+};
+
+const struct av8100_color_space_conversion_format_cmd col_cvt_yuv422_to_rgb = {
+ .c0 = 0x00ba,
+ .c1 = 0x007d,
+ .c2 = 0x0000,
+ .c3 = 0xffa1,
+ .c4 = 0x007d,
+ .c5 = 0xffd3,
+ .c6 = 0x0000,
+ .c7 = 0x007d,
+ .c8 = 0x00eb,
+ .aoffset = 0xff9b,
+ .boffset = 0x003e,
+ .coffset = 0xff82,
+ .lmax = 0xff,
+ .lmin = 0x00,
+ .cmax = 0xff,
+ .cmin = 0x00,
+};
+
+const struct av8100_color_space_conversion_format_cmd col_cvt_yuv422_to_denc = {
+ .c0 = 0x0000,
+ .c1 = 0x0000,
+ .c2 = 0x0100,
+ .c3 = 0x0000,
+ .c4 = 0x0100,
+ .c5 = 0x0000,
+ .c6 = 0x0100,
+ .c7 = 0x0000,
+ .c8 = 0x0000,
+ .aoffset = 0x0000,
+ .boffset = 0x0000,
+ .coffset = 0x0000,
+ .lmax = 0xeb,
+ .lmin = 0x10,
+ .cmax = 0xf0,
+ .cmin = 0x10,
+};
+
+const struct av8100_color_space_conversion_format_cmd col_cvt_rgb_to_denc = {
+ .c0 = 0xffda,
+ .c1 = 0xffb6,
+ .c2 = 0x0070,
+ .c3 = 0x0042,
+ .c4 = 0x0081,
+ .c5 = 0x0019,
+ .c6 = 0x0070,
+ .c7 = 0xffa2,
+ .c8 = 0xffee,
+ .aoffset = 0x007f,
+ .boffset = 0x0010,
+ .coffset = 0x007f,
+ .lmax = 0xff,
+ .lmin = 0x00,
+ .cmax = 0xff,
+ .cmin = 0x00,
+};
+
+static const struct i2c_device_id av8100_id[] = {
+ { "av8100", 0 },
+ { }
+};
+
+static struct i2c_driver av8100_driver = {
+ .probe = av8100_probe,
+ .remove = av8100_remove,
+ .driver = {
+ .name = "av8100",
+ },
+ .id_table = av8100_id,
+};
+
+#ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS
+static void av8100_timer_int(unsigned long value)
+{
+ av8100_flag |= AV8100_TIMER_INT_EVENT;
+ wake_up_interruptible(&av8100_event);
+
+ if (g_av8100_status.av8100_state >= AV8100_OPMODE_STANDBY) {
+ av8100_timer.expires = jiffies +
+ AV8100_TIMER_INTERRUPT_POLLING_TIME;
+ add_timer(&av8100_timer);
+ }
+}
+#endif
+
+static int av8100_thread(void *p)
+{
+ u8 hpds = 0;
+ u8 cpds = 0;
+ u8 hdcps = 0;
+ int ret = 0;
+#ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS
+ u8 cecrx;
+ u8 *hpds_old;
+ u8 *cpds_old;
+ u8 *cecrx_old;
+ u8 *hdcps_old;
+#else
+ u8 sid = 0;
+ u8 oni = 0;
+ u8 hpdi = 0;
+ u8 cpdi = 0;
+#endif
+
+ while (1) {
+ wait_event_interruptible(av8100_event, (av8100_flag != 0));
+#ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS
+ if ((av8100_flag & AV8100_TIMER_INT_EVENT) &&
+ (g_av8100_status.av8100_state >=
+ AV8100_OPMODE_STANDBY)) {
+ hpds_old = &(av8100_globals->hpds_old);
+ cpds_old = &(av8100_globals->cpds_old);
+ cecrx_old = &(av8100_globals->cecrx_old);
+ hdcps_old = &(av8100_globals->hdcps_old);
+
+ /* STANDBY reg */
+ if (av8100_reg_stby_r(
+ NULL,
+ NULL,
+ &hpds,
+ &cpds,
+ NULL) != 0)
+ dev_dbg(av8100dev, "av8100_reg_"
+ "stby_r fail\n");
+
+ /* TVout plugin change */
+ if ((cpds == 1) && (cpds != *cpds_old)) {
+ *cpds_old = 1;
+
+ set_plug_status(AV8100_CVBS_PLUGIN);
+ } else if ((cpds == 0) && (cpds != *cpds_old)) {
+ *cpds_old = 0;
+
+ clr_plug_status(AV8100_CVBS_PLUGIN);
+ }
+
+ /* HDMI plugin change */
+ if ((hpds == 1) && (hpds != *hpds_old)) {
+ *hpds_old = 1;
+
+ set_plug_status(AV8100_HDMI_PLUGIN);
+ } else if ((hpds == 0) && (hpds != *hpds_old)) {
+ *hpds_old = 0;
+
+ clr_plug_status(AV8100_HDMI_PLUGIN);
+ }
+
+ /* GENERAL_STATUS reg */
+ if (av8100_reg_gen_status_r(
+ &cecrx,
+ NULL,
+ NULL,
+ NULL,
+ &hdcps) != 0)
+ dev_dbg(av8100dev, "av8100_reg_"
+ "gen_status_r fail\n");
+ else {
+ if ((cecrx == 1) && (cecrx != *cecrx_old))
+ /* Report CEC event */
+ cec_rx();
+ *cecrx_old = cecrx;
+
+ if (hdcps != *hdcps_old)
+ /* Report HDCP status change event */
+ hdcp_changed();
+ *hdcps_old = hdcps;
+ }
+ }
+#else
+ /* STANDBY_PENDING_INTERRUPT */
+ ret = av8100_register_standby_pending_interrupt_read(
+ &hpdi,
+ &cpdi,
+ &oni,
+ &sid);
+
+ if (ret)
+ dev_dbg(av8100dev, "av8100_register_standby_"
+ "pending_interrupt_read failed\n");
+
+ if (hpdi | cpdi | oni) {
+ /* STANDBY */
+ ret = av8100_register_standby_read(
+ &cpd,
+ &stby,
+ &hpds,
+ &cpds,
+ &mclkrng);
+ if (ret)
+ dev_dbg(av8100dev, "av8100_register_standby_"
+ "read fail\n");
+ }
+
+ if (cpdi) {
+ /* TVout plugin change */
+ if (cpds)
+ set_plug_status(AV8100_CVBS_PLUGIN);
+ else
+ clr_plug_status(AV8100_CVBS_PLUGIN);
+ } else if (hpdi) {
+ /* HDMI plugin change */
+ if (hpds)
+ set_plug_status(AV8100_HDMI_PLUGIN);
+ else
+ clr_plug_status(AV8100_HDMI_PLUGIN);
+ }
+
+ if (hpdi | cpdi | oni) {
+ /* Clear pending interrupts */
+ ret = av8100_register_standby_pending_interrupt_write(
+ hpdi,
+ cpdi,
+ oni);
+ if (ret)
+ dev_dbg(av8100dev, "av8100_register_standby_"
+ "read fail\n");
+ }
+#endif
+ av8100_flag = 0;
+ }
+
+ return ret;
+}
+
+static irqreturn_t av8100_intr_handler(int irq, void *p)
+{
+ av8100_flag |= AV8100_INT_EVENT;
+ wake_up_interruptible(&av8100_event);
+ return IRQ_HANDLED;
+}
+
+static u16 av8100_get_te_line_nb(
+ enum av8100_output_CEA_VESA output_video_format)
+{
+ u16 retval;
+
+ switch (output_video_format) {
+ case AV8100_CEA1_640X480P_59_94HZ:
+ case AV8100_CEA2_3_720X480P_59_94HZ:
+ retval = AV8100_TE_LINE_NB_30;
+ break;
+
+ case AV8100_CEA5_1920X1080I_60HZ:
+ case AV8100_CEA6_7_NTSC_60HZ:
+ case AV8100_CEA20_1920X1080I_50HZ:
+ retval = AV8100_TE_LINE_NB_18;
+ break;
+
+ case AV8100_CEA4_1280X720P_60HZ:
+ retval = AV8100_TE_LINE_NB_21;
+ break;
+
+ case AV8100_CEA17_18_720X576P_50HZ:
+ retval = AV8100_TE_LINE_NB_40;
+ break;
+
+ case AV8100_CEA19_1280X720P_50HZ:
+ retval = AV8100_TE_LINE_NB_22;
+ break;
+
+ case AV8100_CEA21_22_576I_PAL_50HZ:
+ /* Different values below come from LLD,
+ * TODO: check if this is really needed
+ * if not merge with AV8100_CEA6_7_NTSC_60HZ case
+ */
+#ifdef CONFIG_AV8100_SDTV
+ retval = AV8100_TE_LINE_NB_18;
+#else
+ retval = AV8100_TE_LINE_NB_17;
+#endif
+ break;
+
+ case AV8100_CEA32_1920X1080P_24HZ:
+ case AV8100_CEA33_1920X1080P_25HZ:
+ case AV8100_CEA34_1920X1080P_30HZ:
+ retval = AV8100_TE_LINE_NB_38;
+ break;
+
+ case AV8100_CEA60_1280X720P_24HZ:
+ case AV8100_CEA62_1280X720P_30HZ:
+ retval = AV8100_TE_LINE_NB_21;
+ break;
+
+ case AV8100_CEA14_15_480p_60HZ:
+ case AV8100_VESA14_848X480P_60HZ:
+ case AV8100_CEA61_1280X720P_25HZ:
+ case AV8100_CEA16_1920X1080P_60HZ:
+ case AV8100_CEA31_1920x1080P_50Hz:
+ case AV8100_CEA29_30_576P_50HZ:
+ case AV8100_VESA9_800X600P_60_32HZ:
+ case AV8100_VESA16_1024X768P_60HZ:
+ case AV8100_VESA22_1280X768P_59_99HZ:
+ case AV8100_VESA23_1280X768P_59_87HZ:
+ case AV8100_VESA27_1280X800P_59_91HZ:
+ case AV8100_VESA28_1280X800P_59_81HZ:
+ case AV8100_VESA39_1360X768P_60_02HZ:
+ case AV8100_VESA81_1366X768P_59_79HZ:
+ default:
+ /* TODO */
+ retval = AV8100_TE_LINE_NB_14;
+ break;
+ }
+
+ return retval;
+}
+
+static u16 av8100_get_ui_x4(
+ enum av8100_output_CEA_VESA output_video_format)
+{
+ return AV8100_UI_X4_DEFAULT;
+}
+
+static int av8100_config_video_output_dep(enum av8100_output_CEA_VESA
+ output_format)
+{
+ int retval = 0;
+ union av8100_configuration config;
+
+ /* video input */
+ config.video_input_format.dsi_input_mode =
+ AV8100_HDMI_DSI_COMMAND_MODE;
+ config.video_input_format.input_pixel_format = AV8100_INPUT_PIX_RGB565;
+ config.video_input_format.total_horizontal_pixel =
+ av8100_all_cea[output_format].htotale;
+ config.video_input_format.total_horizontal_active_pixel =
+ av8100_all_cea[output_format].hactive;
+ config.video_input_format.total_vertical_lines =
+ av8100_all_cea[output_format].vtotale;
+ config.video_input_format.total_vertical_active_lines =
+ av8100_all_cea[output_format].vactive;
+
+ switch (output_format) {
+ case AV8100_CEA5_1920X1080I_60HZ:
+ case AV8100_CEA20_1920X1080I_50HZ:
+ case AV8100_CEA21_22_576I_PAL_50HZ:
+ case AV8100_CEA6_7_NTSC_60HZ:
+ config.video_input_format.video_mode =
+ AV8100_VIDEO_INTERLACE;
+ break;
+
+ default:
+ config.video_input_format.video_mode =
+ AV8100_VIDEO_PROGRESSIVE;
+ break;
+ }
+
+ config.video_input_format.nb_data_lane =
+ AV8100_DATA_LANES_USED_2;
+ config.video_input_format.nb_virtual_ch_command_mode = 0;
+ config.video_input_format.nb_virtual_ch_video_mode = 0;
+ config.video_input_format.ui_x4 = av8100_get_ui_x4(output_format);
+ config.video_input_format.TE_line_nb = av8100_get_te_line_nb(
+ output_format);
+#ifdef CONFIG_AV8100_HWTRIG_I2SDAT3
+ config.video_input_format.TE_config = AV8100_TE_GPIO_IT;
+#else
+ config.video_input_format.TE_config = AV8100_TE_IT_LINE;
+#endif
+ config.video_input_format.master_clock_freq = 0;
+
+ retval = av8100_conf_prep(
+ AV8100_COMMAND_VIDEO_INPUT_FORMAT, &config);
+
+ /* DENC */
+ switch (output_format) {
+ case AV8100_CEA21_22_576I_PAL_50HZ:
+ config.denc_format.cvbs_video_format = AV8100_CVBS_625;
+ config.denc_format.standard_selection = AV8100_PAL_BDGHI;
+ break;
+
+ case AV8100_CEA6_7_NTSC_60HZ:
+ config.denc_format.cvbs_video_format = AV8100_CVBS_525;
+ config.denc_format.standard_selection = AV8100_NTSC_M;
+ break;
+
+ default:
+ /* Not supported */
+ break;
+ }
+
+ return retval;
+}
+
+static int av8100_config_init(void)
+{
+ int retval = 0;
+ union av8100_configuration config;
+
+ dev_dbg(av8100dev, "%s\n", __func__);
+
+ av8100_config = kzalloc(sizeof(struct av8100_config_t), GFP_KERNEL);
+ if (!av8100_config) {
+ dev_err(av8100dev, "%s: Failed to allocate config\n", __func__);
+ return AV8100_FAIL;
+ }
+
+ memset(&config, 0, sizeof(union av8100_configuration));
+ memset(av8100_config, 0, sizeof(union av8100_configuration));
+
+ /* Color conversion */
+ config.color_space_conversion_format = col_cvt_identity;
+ retval = av8100_conf_prep(
+ AV8100_COMMAND_COLORSPACECONVERSION, &config);
+ if (retval)
+ return AV8100_FAIL;
+
+ /* DENC */
+ config.denc_format.cvbs_video_format = AV8100_CVBS_625;
+ config.denc_format.standard_selection = AV8100_PAL_BDGHI;
+ config.denc_format.enable = 0;
+ config.denc_format.macrovision_enable = 0;
+ config.denc_format.internal_generator = 0;
+
+ /* Video output */
+ config.video_output_format.video_output_cea_vesa =
+ AV8100_CEA4_1280X720P_60HZ;
+
+ retval = av8100_conf_prep(
+ AV8100_COMMAND_VIDEO_OUTPUT_FORMAT, &config);
+ if (retval)
+ return AV8100_FAIL;
+
+ /* Video input */
+ av8100_config_video_output_dep(
+ config.video_output_format.video_output_cea_vesa);
+
+ /* Pattern generator */
+ config.pattern_generator_format.pattern_audio_mode =
+ AV8100_PATTERN_AUDIO_OFF;
+ config.pattern_generator_format.pattern_type =
+ AV8100_PATTERN_GENERATOR;
+ config.pattern_generator_format.pattern_video_format =
+ AV8100_PATTERN_720P;
+ retval = av8100_conf_prep(AV8100_COMMAND_PATTERNGENERATOR,
+ &config);
+ if (retval)
+ return AV8100_FAIL;
+
+ /* Audio input */
+ config.audio_input_format.audio_input_if_format =
+ AV8100_AUDIO_I2SDELAYED_MODE;
+ config.audio_input_format.i2s_input_nb = 1;
+ config.audio_input_format.sample_audio_freq = AV8100_AUDIO_FREQ_48KHZ;
+ config.audio_input_format.audio_word_lg = AV8100_AUDIO_16BITS;
+ config.audio_input_format.audio_format = AV8100_AUDIO_LPCM_MODE;
+ config.audio_input_format.audio_if_mode = AV8100_AUDIO_MASTER;
+ config.audio_input_format.audio_mute = AV8100_AUDIO_MUTE_DISABLE;
+ retval = av8100_conf_prep(
+ AV8100_COMMAND_AUDIO_INPUT_FORMAT, &config);
+ if (retval)
+ return AV8100_FAIL;
+
+ /* HDMI mode */
+ config.hdmi_format.hdmi_mode = AV8100_HDMI_ON;
+ config.hdmi_format.hdmi_format = AV8100_HDMI;
+ config.hdmi_format.dvi_format = AV8100_DVI_CTRL_CTL0;
+ retval = av8100_conf_prep(AV8100_COMMAND_HDMI, &config);
+ if (retval)
+ return AV8100_FAIL;
+
+ /* EDID section readback */
+ config.edid_section_readback_format.address = 0xA0;
+ config.edid_section_readback_format.block_number = 0;
+ retval = av8100_conf_prep(
+ AV8100_COMMAND_EDID_SECTION_READBACK, &config);
+ if (retval)
+ return AV8100_FAIL;
+
+ return retval;
+}
+
+static void av8100_config_exit(void)
+{
+ dev_dbg(av8100dev, "%s\n", __func__);
+
+ kfree(av8100_config);
+ av8100_config = NULL;
+}
+
+static int av8100_globals_init(void)
+{
+ dev_dbg(av8100dev, "%s\n", __func__);
+
+ av8100_globals = kzalloc(sizeof(struct av8100_globals_t), GFP_KERNEL);
+ if (!av8100_globals) {
+ dev_err(av8100dev, "%s: Alloc failure\n", __func__);
+ return AV8100_FAIL;
+ }
+
+ av8100_globals->denc_off_time = AV8100_DENC_OFF_TIME;
+ av8100_globals->hdmi_off_time = AV8100_HDMI_OFF_TIME;
+ av8100_globals->on_time = AV8100_ON_TIME;
+ av8100_globals->hpdm = AV8100_STANDBY_INTERRUPT_MASK_HPDM_LOW;
+ av8100_globals->cpdm = AV8100_STANDBY_INTERRUPT_MASK_CPDM_LOW;
+#ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS
+ av8100_globals->hpds_old = 0xf;
+ av8100_globals->cpds_old = 0xf;
+ av8100_globals->cecrx_old = 0xf;
+ av8100_globals->hdcps_old = 0xf;
+#endif
+
+ return 0;
+}
+
+static void av8100_globals_exit(void)
+{
+ dev_dbg(av8100dev, "%s\n", __func__);
+
+ kfree(av8100_globals);
+ av8100_globals = NULL;
+}
+
+static void clr_plug_status(enum av8100_plugin_status status)
+{
+ g_av8100_status.av8100_plugin_status &= ~status;
+
+ switch (status) {
+ case AV8100_HDMI_PLUGIN:
+ if (av8100_globals->hdmi_ev_cb)
+ av8100_globals->hdmi_ev_cb(
+ AV8100_HDMI_EVENT_HDMI_PLUGOUT);
+ break;
+
+ case AV8100_CVBS_PLUGIN:
+ /* TODO */
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void set_plug_status(enum av8100_plugin_status status)
+{
+ g_av8100_status.av8100_plugin_status |= status;
+
+ switch (status) {
+ case AV8100_HDMI_PLUGIN:
+ if (av8100_globals->hdmi_ev_cb)
+ av8100_globals->hdmi_ev_cb(
+ AV8100_HDMI_EVENT_HDMI_PLUGIN);
+ break;
+
+ case AV8100_CVBS_PLUGIN:
+ /* TODO */
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void cec_rx(void)
+{
+ if (av8100_globals->hdmi_ev_cb)
+ av8100_globals->hdmi_ev_cb(AV8100_HDMI_EVENT_CEC);
+}
+
+static void hdcp_changed(void)
+{
+ if (av8100_globals->hdmi_ev_cb)
+ av8100_globals->hdmi_ev_cb(AV8100_HDMI_EVENT_HDCP);
+}
+
+static void av8100_set_state(enum av8100_operating_mode state)
+{
+ g_av8100_status.av8100_state = state;
+ if (state <= AV8100_OPMODE_STANDBY) {
+ clr_plug_status(AV8100_HDMI_PLUGIN);
+ clr_plug_status(AV8100_CVBS_PLUGIN);
+ g_av8100_status.hdmi_on = false;
+ }
+}
+
+/**
+ * write_single_byte() - Write a single byte to av8100
+ * through i2c interface.
+ * @client: i2c client structure
+ * @reg: register offset
+ * @data: data byte to be written
+ *
+ * This funtion uses smbus byte write API to write a single byte to av8100
+ **/
+static int write_single_byte(struct i2c_client *client, u8 reg,
+ u8 data)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, reg, data);
+ if (ret < 0)
+ dev_dbg(av8100dev, "i2c smbus write byte failed\n");
+
+ return ret;
+}
+
+/**
+ * read_single_byte() - read single byte from av8100
+ * through i2c interface
+ * @client: i2c client structure
+ * @reg: register offset
+ * @val: register value
+ *
+ * This funtion uses smbus read block API to read single byte from the reg
+ * offset.
+ **/
+static int read_single_byte(struct i2c_client *client, u8 reg, u8 *val)
+{
+ int value;
+
+ value = i2c_smbus_read_byte_data(client, reg);
+ if (value < 0) {
+ dev_dbg(av8100dev, "i2c smbus read byte failed,read data = %x "
+ "from offset:%x\n" , value, reg);
+ return AV8100_FAIL;
+ }
+
+ *val = (u8) value;
+ return 0;
+}
+
+/**
+ * write_multi_byte() - Write a multiple bytes to av8100 through
+ * i2c interface.
+ * @client: i2c client structure
+ * @buf: buffer to be written
+ * @nbytes: nunmber of bytes to be written
+ *
+ * This funtion uses smbus block write API's to write n number of bytes to the
+ * av8100
+ **/
+static int write_multi_byte(struct i2c_client *client, u8 reg,
+ u8 *buf, u8 nbytes)
+{
+ int ret;
+
+ ret = i2c_smbus_write_i2c_block_data(client, reg, nbytes, buf);
+ if (ret < 0)
+ dev_dbg(av8100dev, "i2c smbus write multi byte error\n");
+
+ return ret;
+}
+
+static int configuration_video_input_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = av8100_config->hdmi_video_input_cmd.dsi_input_mode;
+ buffer[1] = av8100_config->hdmi_video_input_cmd.input_pixel_format;
+ buffer[2] = REG_16_8_MSB(av8100_config->hdmi_video_input_cmd.
+ total_horizontal_pixel);
+ buffer[3] = REG_16_8_LSB(av8100_config->hdmi_video_input_cmd.
+ total_horizontal_pixel);
+ buffer[4] = REG_16_8_MSB(av8100_config->hdmi_video_input_cmd.
+ total_horizontal_active_pixel);
+ buffer[5] = REG_16_8_LSB(av8100_config->hdmi_video_input_cmd.
+ total_horizontal_active_pixel);
+ buffer[6] = REG_16_8_MSB(av8100_config->hdmi_video_input_cmd.
+ total_vertical_lines);
+ buffer[7] = REG_16_8_LSB(av8100_config->hdmi_video_input_cmd.
+ total_vertical_lines);
+ buffer[8] = REG_16_8_MSB(av8100_config->hdmi_video_input_cmd.
+ total_vertical_active_lines);
+ buffer[9] = REG_16_8_LSB(av8100_config->hdmi_video_input_cmd.
+ total_vertical_active_lines);
+ buffer[10] = av8100_config->hdmi_video_input_cmd.video_mode;
+ buffer[11] = av8100_config->hdmi_video_input_cmd.nb_data_lane;
+ buffer[12] = av8100_config->hdmi_video_input_cmd.
+ nb_virtual_ch_command_mode;
+ buffer[13] = av8100_config->hdmi_video_input_cmd.
+ nb_virtual_ch_video_mode;
+ buffer[14] = REG_16_8_MSB(av8100_config->hdmi_video_input_cmd.
+ TE_line_nb);
+ buffer[15] = REG_16_8_LSB(av8100_config->hdmi_video_input_cmd.
+ TE_line_nb);
+ buffer[16] = av8100_config->hdmi_video_input_cmd.TE_config;
+ buffer[17] = REG_32_8_MSB(av8100_config->hdmi_video_input_cmd.
+ master_clock_freq);
+ buffer[18] = REG_32_8_MMSB(av8100_config->hdmi_video_input_cmd.
+ master_clock_freq);
+ buffer[19] = REG_32_8_MLSB(av8100_config->hdmi_video_input_cmd.
+ master_clock_freq);
+ buffer[20] = REG_32_8_LSB(av8100_config->hdmi_video_input_cmd.
+ master_clock_freq);
+ buffer[21] = av8100_config->hdmi_video_input_cmd.ui_x4;
+
+ *length = AV8100_COMMAND_VIDEO_INPUT_FORMAT_SIZE - 1;
+ return 0;
+
+}
+
+static int configuration_audio_input_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = av8100_config->hdmi_audio_input_cmd.
+ audio_input_if_format;
+ buffer[1] = av8100_config->hdmi_audio_input_cmd.i2s_input_nb;
+ buffer[2] = av8100_config->hdmi_audio_input_cmd.sample_audio_freq;
+ buffer[3] = av8100_config->hdmi_audio_input_cmd.audio_word_lg;
+ buffer[4] = av8100_config->hdmi_audio_input_cmd.audio_format;
+ buffer[5] = av8100_config->hdmi_audio_input_cmd.audio_if_mode;
+ buffer[6] = av8100_config->hdmi_audio_input_cmd.audio_mute;
+
+ *length = AV8100_COMMAND_AUDIO_INPUT_FORMAT_SIZE - 1;
+ return 0;
+}
+
+static int configuration_video_output_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = av8100_config->hdmi_video_output_cmd.
+ video_output_cea_vesa;
+
+ if (buffer[0] == AV8100_CUSTOM) {
+ buffer[1] = av8100_config->hdmi_video_output_cmd.
+ vsync_polarity;
+ buffer[2] = av8100_config->hdmi_video_output_cmd.
+ hsync_polarity;
+ buffer[3] = REG_16_8_MSB(av8100_config->
+ hdmi_video_output_cmd.total_horizontal_pixel);
+ buffer[4] = REG_16_8_LSB(av8100_config->
+ hdmi_video_output_cmd.total_horizontal_pixel);
+ buffer[5] = REG_16_8_MSB(av8100_config->
+ hdmi_video_output_cmd.total_horizontal_active_pixel);
+ buffer[6] = REG_16_8_LSB(av8100_config->
+ hdmi_video_output_cmd.total_horizontal_active_pixel);
+ buffer[7] = REG_16_8_MSB(av8100_config->
+ hdmi_video_output_cmd.total_vertical_in_half_lines);
+ buffer[8] = REG_16_8_LSB(av8100_config->
+ hdmi_video_output_cmd.total_vertical_in_half_lines);
+ buffer[9] = REG_16_8_MSB(av8100_config->
+ hdmi_video_output_cmd.
+ total_vertical_active_in_half_lines);
+ buffer[10] = REG_16_8_LSB(av8100_config->
+ hdmi_video_output_cmd.
+ total_vertical_active_in_half_lines);
+ buffer[11] = REG_16_8_MSB(av8100_config->
+ hdmi_video_output_cmd.hsync_start_in_pixel);
+ buffer[12] = REG_16_8_LSB(av8100_config->
+ hdmi_video_output_cmd.hsync_start_in_pixel);
+ buffer[13] = REG_16_8_MSB(av8100_config->
+ hdmi_video_output_cmd.hsync_length_in_pixel);
+ buffer[14] = REG_16_8_LSB(av8100_config->
+ hdmi_video_output_cmd.hsync_length_in_pixel);
+ buffer[15] = REG_16_8_MSB(av8100_config->
+ hdmi_video_output_cmd.vsync_start_in_half_line);
+ buffer[16] = REG_16_8_LSB(av8100_config->
+ hdmi_video_output_cmd.vsync_start_in_half_line);
+ buffer[17] = REG_16_8_MSB(av8100_config->
+ hdmi_video_output_cmd.vsync_length_in_half_line);
+ buffer[18] = REG_16_8_LSB(av8100_config->
+ hdmi_video_output_cmd.vsync_length_in_half_line);
+ buffer[19] = REG_16_8_MSB(av8100_config->
+ hdmi_video_output_cmd.hor_video_start_pixel);
+ buffer[20] = REG_16_8_LSB(av8100_config->
+ hdmi_video_output_cmd.hor_video_start_pixel);
+ buffer[21] = REG_16_8_MSB(av8100_config->
+ hdmi_video_output_cmd.vert_video_start_pixel);
+ buffer[22] = REG_16_8_LSB(av8100_config->
+ hdmi_video_output_cmd.vert_video_start_pixel);
+ buffer[23] = av8100_config->
+ hdmi_video_output_cmd.video_type;
+ buffer[24] = av8100_config->
+ hdmi_video_output_cmd.pixel_repeat;
+ buffer[25] = REG_32_8_MSB(av8100_config->
+ hdmi_video_output_cmd.pixel_clock_freq_Hz);
+ buffer[26] = REG_32_8_MMSB(av8100_config->
+ hdmi_video_output_cmd.pixel_clock_freq_Hz);
+ buffer[27] = REG_32_8_MLSB(av8100_config->
+ hdmi_video_output_cmd.pixel_clock_freq_Hz);
+ buffer[28] = REG_32_8_LSB(av8100_config->
+ hdmi_video_output_cmd.pixel_clock_freq_Hz);
+
+ *length = AV8100_COMMAND_VIDEO_OUTPUT_FORMAT_SIZE - 1;
+ } else {
+ *length = 1;
+ }
+
+ return 0;
+}
+
+static int configuration_video_scaling_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd.
+ h_start_in_pixel);
+ buffer[1] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd.
+ h_start_in_pixel);
+ buffer[2] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd.
+ h_stop_in_pixel);
+ buffer[3] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd.
+ h_stop_in_pixel);
+ buffer[4] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd.
+ v_start_in_line);
+ buffer[5] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd.
+ v_start_in_line);
+ buffer[6] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd.
+ v_stop_in_line);
+ buffer[7] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd.
+ v_stop_in_line);
+ buffer[8] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd.
+ h_start_out_pixel);
+ buffer[9] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd
+ .h_start_out_pixel);
+ buffer[10] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd.
+ h_stop_out_pixel);
+ buffer[11] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd.
+ h_stop_out_pixel);
+ buffer[12] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd.
+ v_start_out_line);
+ buffer[13] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd.
+ v_start_out_line);
+ buffer[14] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd.
+ v_stop_out_line);
+ buffer[15] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd.
+ v_stop_out_line);
+
+ *length = AV8100_COMMAND_VIDEO_SCALING_FORMAT_SIZE - 1;
+ return 0;
+}
+
+static int configuration_colorspace_conversion_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = REG_12_8_MSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c0);
+ buffer[1] = REG_16_8_LSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c0);
+ buffer[2] = REG_12_8_MSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c1);
+ buffer[3] = REG_16_8_LSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c1);
+ buffer[4] = REG_12_8_MSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c2);
+ buffer[5] = REG_16_8_LSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c2);
+ buffer[6] = REG_12_8_MSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c3);
+ buffer[7] = REG_16_8_LSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c3);
+ buffer[8] = REG_12_8_MSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c4);
+ buffer[9] = REG_16_8_LSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c4);
+ buffer[10] = REG_12_8_MSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c5);
+ buffer[11] = REG_16_8_LSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c5);
+ buffer[12] = REG_12_8_MSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c6);
+ buffer[13] = REG_16_8_LSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c6);
+ buffer[14] = REG_12_8_MSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c7);
+ buffer[15] = REG_16_8_LSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c7);
+ buffer[16] = REG_12_8_MSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c8);
+ buffer[17] = REG_16_8_LSB(av8100_config->
+ hdmi_color_space_conversion_cmd.c8);
+ buffer[18] = REG_10_8_MSB(av8100_config->
+ hdmi_color_space_conversion_cmd.aoffset);
+ buffer[19] = REG_16_8_LSB(av8100_config->
+ hdmi_color_space_conversion_cmd.aoffset);
+ buffer[20] = REG_10_8_MSB(av8100_config->
+ hdmi_color_space_conversion_cmd.boffset);
+ buffer[21] = REG_16_8_LSB(av8100_config->
+ hdmi_color_space_conversion_cmd.boffset);
+ buffer[22] = REG_10_8_MSB(av8100_config->
+ hdmi_color_space_conversion_cmd.coffset);
+ buffer[23] = REG_16_8_LSB(av8100_config->
+ hdmi_color_space_conversion_cmd.coffset);
+ buffer[24] = av8100_config->hdmi_color_space_conversion_cmd.lmax;
+ buffer[25] = av8100_config->hdmi_color_space_conversion_cmd.lmin;
+ buffer[26] = av8100_config->hdmi_color_space_conversion_cmd.cmax;
+ buffer[27] = av8100_config->hdmi_color_space_conversion_cmd.cmin;
+
+ *length = AV8100_COMMAND_COLORSPACECONVERSION_SIZE - 1;
+ return 0;
+}
+
+static int configuration_cec_message_write_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = av8100_config->hdmi_cec_message_write_cmd.buffer_length;
+ memcpy(&buffer[1], av8100_config->hdmi_cec_message_write_cmd.buffer,
+ HDMI_CEC_MESSAGE_WRITE_BUFFER_SIZE);
+
+ *length = AV8100_COMMAND_CEC_MESSAGE_WRITE_SIZE - 1;
+ return 0;
+}
+
+static int configuration_cec_message_read_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ /* No buffer data */
+ *length = AV8100_COMMAND_CEC_MESSAGE_READ_BACK_SIZE - 1;
+ return 0;
+}
+
+static int configuration_denc_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = av8100_config->hdmi_denc_cmd.cvbs_video_format;
+ buffer[1] = av8100_config->hdmi_denc_cmd.standard_selection;
+ buffer[2] = av8100_config->hdmi_denc_cmd.enable;
+ buffer[3] = av8100_config->hdmi_denc_cmd.macrovision_enable;
+ buffer[4] = av8100_config->hdmi_denc_cmd.internal_generator;
+
+ *length = AV8100_COMMAND_DENC_SIZE - 1;
+ return 0;
+}
+
+static int configuration_hdmi_get(char *buffer, unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = av8100_config->hdmi_cmd.hdmi_mode;
+ buffer[1] = av8100_config->hdmi_cmd.hdmi_format;
+ buffer[2] = av8100_config->hdmi_cmd.dvi_format;
+
+ *length = AV8100_COMMAND_HDMI_SIZE - 1;
+ return 0;
+}
+
+static int configuration_hdcp_sendkey_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = av8100_config->hdmi_hdcp_send_key_cmd.key_number;
+ memcpy(&buffer[1], av8100_config->hdmi_hdcp_send_key_cmd.data,
+ av8100_config->hdmi_hdcp_send_key_cmd.data_len);
+
+ *length = av8100_config->hdmi_hdcp_send_key_cmd.data_len + 1;
+ return 0;
+}
+
+static int configuration_hdcp_management_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = av8100_config->hdmi_hdcp_management_format_cmd.req_type;
+ buffer[1] = av8100_config->hdmi_hdcp_management_format_cmd.req_encr;
+ buffer[2] = av8100_config->hdmi_hdcp_management_format_cmd.encr_use;
+
+ *length = AV8100_COMMAND_HDCP_MANAGEMENT_SIZE - 1;
+ return 0;
+}
+
+static int configuration_infoframe_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = av8100_config->hdmi_infoframes_cmd.type;
+ buffer[1] = av8100_config->hdmi_infoframes_cmd.version;
+ buffer[2] = av8100_config->hdmi_infoframes_cmd.length;
+ buffer[3] = av8100_config->hdmi_infoframes_cmd.crc;
+ memcpy(&buffer[4], av8100_config->hdmi_infoframes_cmd.data,
+ HDMI_INFOFRAME_DATA_SIZE);
+
+ *length = AV8100_COMMAND_INFOFRAMES_SIZE - 1;
+ return 0;
+}
+
+static int av8100_edid_section_readback_get(char *buffer, unsigned int *length)
+{
+ buffer[0] = av8100_config->hdmi_edid_section_readback_cmd.address;
+ buffer[1] = av8100_config->hdmi_edid_section_readback_cmd.
+ block_number;
+
+ *length = AV8100_COMMAND_EDID_SECTION_READBACK_SIZE - 1;
+ return 0;
+}
+
+static int configuration_pattern_generator_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = av8100_config->hdmi_pattern_generator_cmd.pattern_type;
+ buffer[1] = av8100_config->hdmi_pattern_generator_cmd.
+ pattern_video_format;
+ buffer[2] = av8100_config->hdmi_pattern_generator_cmd.
+ pattern_audio_mode;
+
+ *length = AV8100_COMMAND_PATTERNGENERATOR_SIZE - 1;
+ return 0;
+}
+
+static int configuration_fuse_aes_key_get(char *buffer,
+ unsigned int *length)
+{
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ buffer[0] = av8100_config->hdmi_fuse_aes_key_cmd.fuse_operation;
+ if (av8100_config->hdmi_fuse_aes_key_cmd.fuse_operation) {
+ /* Write key command */
+ memcpy(&buffer[1], av8100_config->hdmi_fuse_aes_key_cmd.key,
+ HDMI_FUSE_AES_KEY_SIZE);
+
+ *length = AV8100_COMMAND_FUSE_AES_KEY_SIZE - 1;
+ } else {
+ /* Check key command */
+ *length = AV8100_COMMAND_FUSE_AES_CHK_SIZE - 1;
+ }
+ return 0;
+}
+
+static int get_command_return_data(struct i2c_client *i2c,
+ enum av8100_command_type command_type,
+ u8 *command_buffer,
+ u8 *buffer_length,
+ u8 *buffer)
+{
+ int retval = 0;
+ char val;
+ int index = 0;
+
+ /* Get the first return byte */
+ retval = read_single_byte(i2c, AV8100_COMMAND_OFFSET, &val);
+ if (retval)
+ goto get_command_return_data_fail1r;
+
+ if (val != (0x80 | command_type)) {
+ retval = AV8100_FAIL;
+ goto get_command_return_data_fail1v;
+ }
+
+ switch (command_type) {
+ case AV8100_COMMAND_VIDEO_INPUT_FORMAT:
+ case AV8100_COMMAND_AUDIO_INPUT_FORMAT:
+ case AV8100_COMMAND_VIDEO_OUTPUT_FORMAT:
+ case AV8100_COMMAND_VIDEO_SCALING_FORMAT:
+ case AV8100_COMMAND_COLORSPACECONVERSION:
+ case AV8100_COMMAND_CEC_MESSAGE_WRITE:
+ case AV8100_COMMAND_DENC:
+ case AV8100_COMMAND_HDMI:
+ case AV8100_COMMAND_HDCP_SENDKEY:
+ case AV8100_COMMAND_INFOFRAMES:
+ case AV8100_COMMAND_PATTERNGENERATOR:
+ /* Get the second return byte */
+ retval = read_single_byte(i2c,
+ AV8100_2ND_RET_BYTE_OFFSET, &val);
+ if (retval)
+ goto get_command_return_data_fail2r;
+
+ if (val) {
+ retval = AV8100_FAIL;
+ goto get_command_return_data_fail2v;
+ }
+ break;
+
+ case AV8100_COMMAND_CEC_MESSAGE_READ_BACK:
+ if ((buffer == NULL) || (buffer_length == NULL)) {
+ retval = AV8100_FAIL;
+ goto get_command_return_data_fail;
+ }
+
+ /* Get the return buffer length */
+ retval = read_single_byte(i2c,
+ AV8100_COMMAND_OFFSET + CEC_ADDR_OFFSET, &val);
+ if (retval)
+ goto get_command_return_data_fail;
+
+ /* TODO: buffer_length is always zero */
+ /* *buffer_length = val;*/
+ dev_dbg(av8100dev, "cec buflen:%d\n", val);
+ *buffer_length = val;
+
+ if (*buffer_length >
+ HDMI_CEC_READ_MAXSIZE) {
+ dev_dbg(av8100dev, "CEC size too large %d\n",
+ *buffer_length);
+ *buffer_length = HDMI_CEC_READ_MAXSIZE;
+ }
+
+#ifdef AV8100_DEBUG_EXTRA
+ dev_dbg(av8100dev, "return data: ");
+#endif
+
+ /* Get the return buffer */
+ for (index = 0; index < *buffer_length; ++index) {
+ retval = read_single_byte(i2c,
+ AV8100_CEC_RET_BUF_OFFSET + index, &val);
+ if (retval) {
+ *buffer_length = 0;
+ goto get_command_return_data_fail;
+ } else {
+ *(buffer + index) = val;
+#ifdef AV8100_DEBUG_EXTRA
+ dev_dbg(av8100dev, "%02x ", *(buffer + index));
+#endif
+ }
+ }
+#ifdef AV8100_DEBUG_EXTRA
+ dev_dbg(av8100dev, "\n");
+#endif
+ break;
+
+ case AV8100_COMMAND_HDCP_MANAGEMENT:
+ /* Get the second return byte */
+ retval = read_single_byte(i2c,
+ AV8100_2ND_RET_BYTE_OFFSET, &val);
+ if (retval) {
+ goto get_command_return_data_fail2r;
+ } else {
+ /* Check the second return byte */
+ if (val)
+ goto get_command_return_data_fail2v;
+ }
+
+ if ((buffer == NULL) || (buffer_length == NULL))
+ /* Ignore return data */
+ break;
+
+ /* Get the return buffer length */
+ if (command_buffer[0] ==
+ HDMI_REQUEST_FOR_REVOCATION_LIST_INPUT) {
+ *buffer_length = 0x1F;
+ } else {
+ *buffer_length = 0x0;
+ }
+
+#ifdef AV8100_DEBUG_EXTRA
+ dev_dbg(av8100dev, "return data: ");
+#endif
+ /* Get the return buffer */
+ for (index = 0; index < *buffer_length; ++index) {
+ retval = read_single_byte(i2c,
+ AV8100_HDCP_RET_BUF_OFFSET + index, &val);
+ if (retval) {
+ *buffer_length = 0;
+ goto get_command_return_data_fail;
+ } else {
+ *(buffer + index) = val;
+#ifdef AV8100_DEBUG_EXTRA
+ dev_dbg(av8100dev, "%02x ", *(buffer + index));
+#endif
+ }
+ }
+#ifdef AV8100_DEBUG_EXTRA
+ dev_dbg(av8100dev, "\n");
+#endif
+ break;
+
+ case AV8100_COMMAND_EDID_SECTION_READBACK:
+ if ((buffer == NULL) || (buffer_length == NULL)) {
+ retval = AV8100_FAIL;
+ goto get_command_return_data_fail;
+ }
+
+ /* Return buffer length is fixed */
+ *buffer_length = 0x80;
+
+#ifdef AV8100_DEBUG_EXTRA
+ dev_dbg(av8100dev, "return data: ");
+#endif
+ /* Get the return buffer */
+ for (index = 0; index < *buffer_length; ++index) {
+ retval = read_single_byte(i2c,
+ AV8100_EDID_RET_BUF_OFFSET + index, &val);
+ if (retval) {
+ *buffer_length = 0;
+ goto get_command_return_data_fail;
+ } else {
+ *(buffer + index) = val;
+#ifdef AV8100_DEBUG_EXTRA
+ dev_dbg(av8100dev, "%02x ", *(buffer + index));
+#endif
+ }
+ }
+#ifdef AV8100_DEBUG_EXTRA
+ dev_dbg(av8100dev, "\n");
+#endif
+ break;
+
+ case AV8100_COMMAND_FUSE_AES_KEY:
+ if ((buffer == NULL) || (buffer_length == NULL)) {
+ retval = AV8100_FAIL;
+ goto get_command_return_data_fail;
+ }
+
+ /* Get the second return byte */
+ retval = read_single_byte(i2c,
+ AV8100_2ND_RET_BYTE_OFFSET, &val);
+
+ if (retval)
+ goto get_command_return_data_fail2r;
+
+ /* Check the second return byte */
+ if (val) {
+ retval = AV8100_FAIL;
+ goto get_command_return_data_fail2v;
+ }
+
+ /* Return buffer length is fixed */
+ *buffer_length = HDMI_FUSE_AES_KEY_RET_SIZE;
+
+ /* Get CRC */
+ retval = read_single_byte(i2c,
+ AV8100_FUSE_CRC_OFFSET, &val);
+ if (retval)
+ goto get_command_return_data_fail;
+
+ *buffer = val;
+#ifdef AV8100_DEBUG_EXTRA
+ dev_dbg(av8100dev, "CRC:%02x ", val);
+#endif
+
+ /* Get programmed status */
+ retval = read_single_byte(i2c,
+ AV8100_FUSE_PRGD_OFFSET, &val);
+ if (retval)
+ goto get_command_return_data_fail;
+
+ *(buffer + 1) = val;
+#ifdef AV8100_DEBUG_EXTRA
+ dev_dbg(av8100dev, "programmed:%02x ", val);
+#endif
+ break;
+
+ default:
+ retval = AV8100_INVALID_COMMAND;
+ break;
+ }
+
+ return retval;
+get_command_return_data_fail1r:
+ dev_dbg(av8100dev, "%s Reading first return byte failed\n", __func__);
+ return retval;
+get_command_return_data_fail1v:
+ dev_dbg(av8100dev, "%s First return byte is wrong:%x\n", __func__, val);
+ return retval;
+get_command_return_data_fail2r:
+ dev_dbg(av8100dev, "%s Reading 2nd return byte failed\n", __func__);
+ return retval;
+get_command_return_data_fail2v:
+ dev_dbg(av8100dev, "%s 2nd return byte is wrong:%x\n", __func__, val);
+ return retval;
+get_command_return_data_fail:
+ dev_dbg(av8100dev, "%s FAIL\n", __func__);
+ return retval;
+}
+
+static int av8100_powerup1(void)
+{
+ int retval = 0;
+
+ /* Reset av8100 */
+ gpio_set_value(GPIO_AV8100_RSTN, 1);
+
+ /* Need to wait before proceeding */
+ mdelay(AV8100_POWERON_WAITTIME1_MS);
+
+ av8100_set_state(AV8100_OPMODE_STANDBY);
+
+ /* Get chip version */
+ retval = av8100_reg_stby_pend_int_r(NULL, NULL, NULL, &chip_version);
+ if (retval) {
+ dev_err(av8100dev, "Failed to read chip version\n");
+ return -EFAULT;
+ }
+
+ dev_info(av8100dev, "chip version:%d\n", chip_version);
+
+ switch (chip_version) {
+ case AV8100_CHIPVER_1:
+ case AV8100_CHIPVER_2:
+ break;
+
+ default:
+ dev_err(av8100dev, "Unsupported chip version:%d\n",
+ chip_version);
+ return -EFAULT;
+ break;
+ }
+
+ return retval;
+}
+
+static int av8100_powerup2(void)
+{
+ int retval = 0;
+
+ /* Master clock timing, running, search for plug */
+ retval = av8100_reg_stby_w(AV8100_STANDBY_CPD_HIGH,
+ AV8100_STANDBY_STBY_HIGH, AV8100_MASTER_CLOCK_TIMING);
+ if (retval) {
+ dev_err(av8100dev,
+ "Failed to write the value to av8100 register\n");
+ return -EFAULT;
+ }
+
+ /* ON time & OFF time on 5v HDMI plug detect */
+ retval = av8100_reg_hdmi_5_volt_time_w(
+ av8100_globals->denc_off_time,
+ av8100_globals->hdmi_off_time,
+ av8100_globals->on_time);
+ if (retval) {
+ dev_err(av8100dev,
+ "Failed to write the value to av8100 register\n");
+ return -EFAULT;
+ }
+
+ /* Need to wait before proceeding */
+ mdelay(AV8100_POWERON_WAITTIME2_MS);
+
+ av8100_set_state(AV8100_OPMODE_SCAN);
+
+ return retval;
+}
+
+int av8100_powerup(void)
+{
+ if (av8100_powerup1()) {
+ dev_err(av8100dev, "av8100_powerup1 fail\n");
+ return -EFAULT;
+ }
+
+ return av8100_powerup2();
+}
+
+int av8100_powerdown(void)
+{
+ gpio_set_value(GPIO_AV8100_RSTN, 0);
+ av8100_set_state(AV8100_OPMODE_SHUTDOWN);
+
+ return 0;
+}
+
+int av8100_download_firmware(char *fw_buff, int nbytes,
+ enum interface_type if_type)
+{
+ int retval = 0;
+ int temp = 0x0;
+ int increment = 15;
+ int index = 0;
+ int size = 0x0;
+ int tempnext = 0x0;
+ char val = 0x0;
+ char CheckSum = 0;
+ int cnt = 10;
+ struct i2c_client *i2c;
+ u8 cecrec;
+ u8 cectrx;
+ u8 uc;
+ u8 onuvb;
+ u8 hdcps;
+ u8 fdl;
+ u8 hld;
+ u8 wa;
+ u8 ra;
+
+ if (!av8100_config) {
+ retval = AV8100_FAIL;
+ goto av8100_download_firmware_out;
+ }
+
+ if (fw_buff == NULL) {
+ switch (chip_version) {
+ case AV8100_CHIPVER_1:
+ fw_buff = av8100_fw_buff_v1;
+ nbytes = AV8100_FW_SIZE_V1;
+ break;
+
+ case AV8100_CHIPVER_2:
+ default:
+ fw_buff = av8100_fw_buff_v2;
+ nbytes = AV8100_FW_SIZE_V2;
+ break;
+ }
+ }
+
+ i2c = av8100_config->client;
+
+ /* Enable firmware download */
+ retval = av8100_reg_gen_ctrl_w(
+ AV8100_GENERAL_CONTROL_FDL_HIGH,
+ AV8100_GENERAL_CONTROL_HLD_HIGH,
+ AV8100_GENERAL_CONTROL_WA_LOW,
+ AV8100_GENERAL_CONTROL_RA_LOW);
+ if (retval) {
+ dev_err(av8100dev,
+ "Failed to write the value to av8100 register\n");
+ return -EFAULT;
+ }
+
+ retval = av8100_reg_gen_ctrl_r(&fdl, &hld, &wa, &ra);
+ if (retval) {
+ dev_err(av8100dev,
+ "Failed to read the value from av8100 register\n");
+ return -EFAULT;
+ } else {
+ dev_dbg(av8100dev, "GENERAL_CONTROL_REG register fdl:%d "
+ "hld:%d wa:%d ra:%d\n", fdl, hld, wa, ra);
+ }
+
+ LOCK_AV8100_HW;
+
+ temp = nbytes % increment;
+ for (size = 0; size < (nbytes-temp); size = size + increment,
+ index += increment) {
+ if (if_type == I2C_INTERFACE) {
+ retval = write_multi_byte(i2c,
+ AV8100_FIRMWARE_DOWNLOAD_ENTRY, fw_buff + size,
+ increment);
+ if (retval) {
+ dev_dbg(av8100dev, "Failed to download the "
+ "av8100 firmware\n");
+ retval = -EFAULT;
+ UNLOCK_AV8100_HW;
+ goto av8100_download_firmware_out;
+ }
+ } else if (if_type == DSI_INTERFACE) {
+ dev_dbg(av8100dev,
+ "DSI_INTERFACE is currently not supported\n");
+ UNLOCK_AV8100_HW;
+ goto av8100_download_firmware_out;
+ } else {
+ retval = AV8100_INVALID_INTERFACE;
+ UNLOCK_AV8100_HW;
+ goto av8100_download_firmware_out;
+ }
+
+ for (tempnext = size; tempnext < (increment+size); tempnext++)
+ av8100_receivetab[tempnext] = fw_buff[tempnext];
+ }
+
+ /* Transfer last firmware bytes */
+ if (if_type == I2C_INTERFACE) {
+ retval = write_multi_byte(i2c,
+ AV8100_FIRMWARE_DOWNLOAD_ENTRY, fw_buff + size, temp);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to download the av8100 firmware\n");
+ retval = -EFAULT;
+ UNLOCK_AV8100_HW;
+ goto av8100_download_firmware_out;
+ }
+ } else if (if_type == DSI_INTERFACE) {
+ /* TODO: Add support for DSI firmware download */
+ retval = AV8100_INVALID_INTERFACE;
+ UNLOCK_AV8100_HW;
+ goto av8100_download_firmware_out;
+ } else {
+ retval = AV8100_INVALID_INTERFACE;
+ UNLOCK_AV8100_HW;
+ goto av8100_download_firmware_out;
+ }
+
+ for (tempnext = size; tempnext < (size+temp); tempnext++)
+ av8100_receivetab[tempnext] = fw_buff[tempnext];
+
+ /* check transfer*/
+ for (size = 0; size < nbytes; size++) {
+ CheckSum = CheckSum ^ fw_buff[size];
+ if (av8100_receivetab[size] != fw_buff[size]) {
+ dev_dbg(av8100dev, ">Fw download fail....i=%d\n", size);
+ dev_dbg(av8100dev, "Transm = %x, Receiv = %x\n",
+ fw_buff[size], av8100_receivetab[size]);
+ }
+ }
+
+ UNLOCK_AV8100_HW;
+
+ retval = av8100_reg_fw_dl_entry_r(&val);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to read the value from the av8100 register\n");
+ retval = -EFAULT;
+ goto av8100_download_firmware_out;
+ }
+
+ dev_dbg(av8100dev, "CheckSum:%x,val:%x\n", CheckSum, val);
+
+ if (CheckSum != val) {
+ dev_dbg(av8100dev,
+ ">Fw downloading.... FAIL CheckSum issue\n");
+ dev_dbg(av8100dev, "Checksum = %d\n", CheckSum);
+ dev_dbg(av8100dev, "Checksum read: %d\n", val);
+ retval = AV8100_FWDOWNLOAD_FAIL;
+ goto av8100_download_firmware_out;
+ } else {
+ dev_dbg(av8100dev, ">Fw downloading.... success\n");
+ }
+
+ /* Set to idle mode */
+ av8100_reg_gen_ctrl_w(AV8100_GENERAL_CONTROL_FDL_LOW,
+ AV8100_GENERAL_CONTROL_HLD_LOW, AV8100_GENERAL_CONTROL_WA_LOW,
+ AV8100_GENERAL_CONTROL_RA_LOW);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to write the value to the av8100 register\n");
+ retval = -EFAULT;
+ goto av8100_download_firmware_out;
+ }
+
+ /* Wait Internal Micro controler ready */
+ cnt = 3;
+ retval = av8100_reg_gen_status_r(&cecrec, &cectrx, &uc,
+ &onuvb, &hdcps);
+ while ((retval == 0) && (uc != 0x1) && (cnt-- > 0)) {
+ dev_dbg(av8100dev, "av8100 wait2\n");
+ /* TODO */
+ for (temp = 0; temp < 0xFFFFF; temp++)
+ ;
+
+ retval = av8100_reg_gen_status_r(&cecrec, &cectrx,
+ &uc, &onuvb, &hdcps);
+ }
+
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to read the value from the av8100 register\n");
+ retval = -EFAULT;
+ goto av8100_download_firmware_out;
+ }
+
+ av8100_set_state(AV8100_OPMODE_IDLE);
+
+av8100_download_firmware_out:
+ return retval;
+}
+
+int av8100_disable_interrupt(void)
+{
+ int retval;
+ struct i2c_client *i2c;
+
+ if (!av8100_config) {
+ retval = AV8100_FAIL;
+ goto av8100_disable_interrupt_out;
+ }
+
+ i2c = av8100_config->client;
+
+ retval = av8100_reg_stby_pend_int_w(
+ AV8100_STANDBY_PENDING_INTERRUPT_HPDI_LOW,
+ AV8100_STANDBY_PENDING_INTERRUPT_CPDI_LOW,
+ AV8100_STANDBY_PENDING_INTERRUPT_ONI_LOW);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to write the value to av8100 register\n");
+ retval = -EFAULT;
+ goto av8100_disable_interrupt_out;
+ }
+
+ retval = av8100_reg_gen_int_mask_w(
+ AV8100_GENERAL_INTERRUPT_MASK_EOCM_LOW,
+ AV8100_GENERAL_INTERRUPT_MASK_VSIM_LOW,
+ AV8100_GENERAL_INTERRUPT_MASK_VSOM_LOW,
+ AV8100_GENERAL_INTERRUPT_MASK_CECM_LOW,
+ AV8100_GENERAL_INTERRUPT_MASK_HDCPM_LOW,
+ AV8100_GENERAL_INTERRUPT_MASK_UOVBM_LOW,
+ AV8100_GENERAL_INTERRUPT_MASK_TEM_LOW);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to write the value to av8100 register\n");
+ retval = -EFAULT;
+ goto av8100_disable_interrupt_out;
+ }
+
+ retval = av8100_reg_stby_int_mask_w(
+ AV8100_STANDBY_INTERRUPT_MASK_HPDM_LOW,
+ AV8100_STANDBY_INTERRUPT_MASK_CPDM_LOW,
+ AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_INPUT,
+ AV8100_STANDBY_INTERRUPT_MASK_IPOL_LOW);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to write the value to av8100 register\n");
+ retval = -EFAULT;
+ goto av8100_disable_interrupt_out;
+ }
+
+#ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS
+ del_timer(&av8100_timer);
+
+ if (av8100_globals) {
+ /* Reset to be able to detect changes */
+ av8100_globals->hpds_old = HPDS_INVALID;
+ av8100_globals->cpds_old = CPDS_INVALID;
+ av8100_globals->cecrx_old = CECRX_INVALID;
+ }
+#endif
+
+
+av8100_disable_interrupt_out:
+ return retval;
+}
+
+int av8100_enable_interrupt(void)
+{
+ int retval;
+ struct i2c_client *i2c;
+
+ if (!av8100_config) {
+ retval = AV8100_FAIL;
+ goto av8100_enable_interrupt_out;
+ }
+
+ i2c = av8100_config->client;
+
+ retval = av8100_reg_stby_pend_int_w(
+ AV8100_STANDBY_PENDING_INTERRUPT_HPDI_LOW,
+ AV8100_STANDBY_PENDING_INTERRUPT_CPDI_LOW,
+ AV8100_STANDBY_PENDING_INTERRUPT_ONI_LOW);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to write the value to av8100 register\n");
+ retval = -EFAULT;
+ goto av8100_enable_interrupt_out;
+ }
+
+ retval = av8100_reg_gen_int_mask_w(
+ AV8100_GENERAL_INTERRUPT_MASK_EOCM_LOW,
+ AV8100_GENERAL_INTERRUPT_MASK_VSIM_LOW,
+ AV8100_GENERAL_INTERRUPT_MASK_VSOM_LOW,
+ AV8100_GENERAL_INTERRUPT_MASK_CECM_LOW,
+ AV8100_GENERAL_INTERRUPT_MASK_HDCPM_LOW,
+ AV8100_GENERAL_INTERRUPT_MASK_UOVBM_LOW,
+ AV8100_GENERAL_INTERRUPT_MASK_TEM_HIGH);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to write the value to av8100 register\n");
+ retval = -EFAULT;
+ goto av8100_enable_interrupt_out;
+ }
+
+ retval = av8100_reg_stby_int_mask_w(
+ av8100_globals->hpdm,
+ av8100_globals->cpdm,
+ AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_INPUT,
+ AV8100_STANDBY_INTERRUPT_MASK_IPOL_LOW);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to write the value to av8100 register\n");
+ retval = -EFAULT;
+ goto av8100_enable_interrupt_out;
+ }
+
+#ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS
+ init_timer(&av8100_timer);
+ av8100_timer.expires = jiffies + AV8100_TIMER_INTERRUPT_POLLING_TIME;
+ av8100_timer.function = av8100_timer_int;
+ av8100_timer.data = 0;
+ add_timer(&av8100_timer);
+#endif
+
+av8100_enable_interrupt_out:
+ return retval;
+}
+
+static int register_write_internal(u8 offset, u8 value)
+{
+ int retval;
+ struct i2c_client *i2c;
+
+ if (!av8100_config) {
+ retval = AV8100_FAIL;
+ goto av8100_register_write_out;
+ }
+
+ i2c = av8100_config->client;
+
+ /* Write to register */
+ retval = write_single_byte(i2c, offset, value);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to write the value to av8100 register\n");
+ retval = -EFAULT;
+ }
+
+av8100_register_write_out:
+ return retval;
+}
+
+int av8100_reg_stby_w(
+ u8 cpd, u8 stby, u8 mclkrng)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Set register value */
+ val = AV8100_STANDBY_CPD(cpd) | AV8100_STANDBY_STBY(stby) |
+ AV8100_STANDBY_MCLKRNG(mclkrng);
+
+ /* Write to register */
+ retval = register_write_internal(AV8100_STANDBY, val);
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_hdmi_5_volt_time_w(u8 denc_off, u8 hdmi_off, u8 on)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Set register value.
+ * chip_version == 1 have one common off time
+ * chip_version > 1 support different off time for hdmi and tvout. */
+ if (chip_version == 1)
+ val = AV8100_HDMI_5_VOLT_TIME_OFF_TIME(hdmi_off) |
+ AV8100_HDMI_5_VOLT_TIME_ON_TIME(on);
+ else
+ val = AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME(denc_off) |
+ AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME(hdmi_off) |
+ AV8100_HDMI_5_VOLT_TIME_ON_TIME(on);
+
+ /* Write to register */
+ retval = register_write_internal(AV8100_HDMI_5_VOLT_TIME, val);
+
+ /* Set vars */
+ if (chip_version > 1)
+ av8100_globals->denc_off_time = denc_off;
+
+ av8100_globals->hdmi_off_time = hdmi_off;
+ av8100_globals->on_time = on;
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_stby_int_mask_w(
+ u8 hpdm, u8 cpdm, u8 stbygpiocfg, u8 ipol)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Set register value */
+ val = AV8100_STANDBY_INTERRUPT_MASK_HPDM(hpdm) |
+ AV8100_STANDBY_INTERRUPT_MASK_CPDM(cpdm) |
+ AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG(stbygpiocfg) |
+ AV8100_STANDBY_INTERRUPT_MASK_IPOL(ipol);
+
+ /* Write to register */
+ retval = register_write_internal(AV8100_STANDBY_INTERRUPT_MASK, val);
+
+ av8100_globals->hpdm = hpdm;
+ av8100_globals->cpdm = cpdm;
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_stby_pend_int_w(
+ u8 hpdi, u8 cpdi, u8 oni)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Set register value */
+ val = AV8100_STANDBY_PENDING_INTERRUPT_HPDI(hpdi) |
+ AV8100_STANDBY_PENDING_INTERRUPT_CPDI(cpdi) |
+ AV8100_STANDBY_PENDING_INTERRUPT_ONI(oni);
+
+ /* Write to register */
+ retval = register_write_internal(AV8100_STANDBY_PENDING_INTERRUPT, val);
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_gen_int_mask_w(
+ u8 eocm, u8 vsim, u8 vsom, u8 cecm, u8 hdcpm, u8 uovbm, u8 tem)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Set register value */
+ val = AV8100_GENERAL_INTERRUPT_MASK_EOCM(eocm) |
+ AV8100_GENERAL_INTERRUPT_MASK_VSIM(vsim) |
+ AV8100_GENERAL_INTERRUPT_MASK_VSOM(vsom) |
+ AV8100_GENERAL_INTERRUPT_MASK_CECM(cecm) |
+ AV8100_GENERAL_INTERRUPT_MASK_HDCPM(hdcpm) |
+ AV8100_GENERAL_INTERRUPT_MASK_UOVBM(uovbm) |
+ AV8100_GENERAL_INTERRUPT_MASK_TEM(tem);
+
+ /* Write to register */
+ retval = register_write_internal(AV8100_GENERAL_INTERRUPT_MASK, val);
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_gen_int_w(
+ u8 eoci, u8 vsii, u8 vsoi, u8 ceci, u8 hdcpi, u8 uovbi)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Set register value */
+ val = AV8100_GENERAL_INTERRUPT_EOCI(eoci) |
+ AV8100_GENERAL_INTERRUPT_VSII(vsii) |
+ AV8100_GENERAL_INTERRUPT_VSOI(vsoi) |
+ AV8100_GENERAL_INTERRUPT_CECI(ceci) |
+ AV8100_GENERAL_INTERRUPT_HDCPI(hdcpi) |
+ AV8100_GENERAL_INTERRUPT_UOVBI(uovbi);
+
+ /* Write to register */
+ retval = register_write_internal(AV8100_GENERAL_INTERRUPT, val);
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_gpio_conf_w(
+ u8 dat3dir, u8 dat3val, u8 dat2dir, u8 dat2val, u8 dat1dir,
+ u8 dat1val, u8 ucdbg)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Set register value */
+ val = AV8100_GPIO_CONFIGURATION_DAT3DIR(dat3dir) |
+ AV8100_GPIO_CONFIGURATION_DAT3VAL(dat3val) |
+ AV8100_GPIO_CONFIGURATION_DAT2DIR(dat2dir) |
+ AV8100_GPIO_CONFIGURATION_DAT2VAL(dat2val) |
+ AV8100_GPIO_CONFIGURATION_DAT1DIR(dat1dir) |
+ AV8100_GPIO_CONFIGURATION_DAT1VAL(dat1val) |
+ AV8100_GPIO_CONFIGURATION_UCDBG(ucdbg);
+
+ /* Write to register */
+ retval = register_write_internal(AV8100_GPIO_CONFIGURATION, val);
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_gen_ctrl_w(
+ u8 fdl, u8 hld, u8 wa, u8 ra)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Set register value */
+ val = AV8100_GENERAL_CONTROL_FDL(fdl) |
+ AV8100_GENERAL_CONTROL_HLD(hld) |
+ AV8100_GENERAL_CONTROL_WA(wa) |
+ AV8100_GENERAL_CONTROL_RA(ra);
+
+ /* Write to register */
+ retval = register_write_internal(AV8100_GENERAL_CONTROL, val);
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_fw_dl_entry_w(
+ u8 mbyte_code_entry)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Set register value */
+ val = AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY(
+ mbyte_code_entry);
+
+ /* Write to register */
+ retval = register_write_internal(AV8100_FIRMWARE_DOWNLOAD_ENTRY, val);
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_w(
+ u8 offset, u8 value)
+{
+ int retval = 0;
+ struct i2c_client *i2c;
+
+ LOCK_AV8100_HW;
+
+ if (!av8100_config) {
+ retval = AV8100_FAIL;
+ goto av8100_reg_w_out;
+ }
+
+ i2c = av8100_config->client;
+
+ /* Write to register */
+ retval = write_single_byte(i2c, offset, value);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to write the value to av8100 register\n");
+ retval = -EFAULT;
+ }
+
+av8100_reg_w_out:
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int register_read_internal(u8 offset, u8 *value)
+{
+ int retval = 0;
+ struct i2c_client *i2c;
+
+ if (!av8100_config) {
+ retval = AV8100_FAIL;
+ goto av8100_register_read_out;
+ }
+
+ i2c = av8100_config->client;
+
+ /* Read from register */
+ retval = read_single_byte(i2c, offset, value);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to read the value from av8100 register\n");
+ retval = -EFAULT;
+ goto av8100_register_read_out;
+ }
+
+av8100_register_read_out:
+ return retval;
+}
+
+int av8100_reg_stby_r(
+ u8 *cpd, u8 *stby, u8 *hpds, u8 *cpds, u8 *mclkrng)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Read from register */
+ retval = register_read_internal(AV8100_STANDBY, &val);
+
+ /* Set return params */
+ if (cpd)
+ *cpd = AV8100_STANDBY_CPD_GET(val);
+ if (stby)
+ *stby = AV8100_STANDBY_STBY_GET(val);
+ if (hpds)
+ *hpds = AV8100_STANDBY_HPDS_GET(val);
+ if (cpds)
+ *cpds = AV8100_STANDBY_CPDS_GET(val);
+ if (mclkrng)
+ *mclkrng = AV8100_STANDBY_MCLKRNG_GET(val);
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_hdmi_5_volt_time_r(
+ u8 *denc_off_time, u8 *hdmi_off_time, u8 *on_time)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Read from register */
+ retval = register_read_internal(AV8100_HDMI_5_VOLT_TIME, &val);
+
+ /* Set return params */
+ if (chip_version == 1) {
+ if (denc_off_time)
+ *denc_off_time = 0;
+ if (hdmi_off_time)
+ *hdmi_off_time =
+ AV8100_HDMI_5_VOLT_TIME_OFF_TIME_GET(val);
+ } else {
+ if (denc_off_time)
+ *denc_off_time =
+ AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME_GET(val);
+ if (hdmi_off_time)
+ *hdmi_off_time =
+ AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME_GET(val);
+ }
+
+ if (on_time)
+ *on_time = AV8100_HDMI_5_VOLT_TIME_ON_TIME_GET(val);
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_stby_int_mask_r(
+ u8 *hpdm, u8 *cpdm, u8 *stbygpiocfg, u8 *ipol)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Read from register */
+ retval = register_read_internal(AV8100_STANDBY_INTERRUPT_MASK, &val);
+
+ /* Set return params */
+ if (hpdm)
+ *hpdm = AV8100_STANDBY_INTERRUPT_MASK_HPDM_GET(val);
+ if (cpdm)
+ *cpdm = AV8100_STANDBY_INTERRUPT_MASK_CPDM_GET(val);
+ if (stbygpiocfg)
+ *stbygpiocfg =
+ AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_GET(val);
+ if (ipol)
+ *ipol = AV8100_STANDBY_INTERRUPT_MASK_IPOL_GET(val);
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_stby_pend_int_r(
+ u8 *hpdi, u8 *cpdi, u8 *oni, u8 *sid)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Read from register */
+ retval = register_read_internal(AV8100_STANDBY_PENDING_INTERRUPT,
+ &val);
+
+ /* Set return params */
+ if (hpdi)
+ *hpdi = AV8100_STANDBY_PENDING_INTERRUPT_HPDI_GET(val);
+ if (cpdi)
+ *cpdi = AV8100_STANDBY_PENDING_INTERRUPT_CPDI_GET(val);
+ if (oni)
+ *oni = AV8100_STANDBY_PENDING_INTERRUPT_ONI_GET(val);
+ if (sid)
+ *sid = AV8100_STANDBY_PENDING_INTERRUPT_SID_GET(val);
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_gen_int_mask_r(
+ u8 *eocm,
+ u8 *vsim,
+ u8 *vsom,
+ u8 *cecm,
+ u8 *hdcpm,
+ u8 *uovbm,
+ u8 *tem)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Read from register */
+ retval = register_read_internal(AV8100_GENERAL_INTERRUPT_MASK, &val);
+
+ /* Set return params */
+ if (eocm)
+ *eocm = AV8100_GENERAL_INTERRUPT_MASK_EOCM_GET(val);
+ if (vsim)
+ *vsim = AV8100_GENERAL_INTERRUPT_MASK_VSIM_GET(val);
+ if (vsom)
+ *vsom = AV8100_GENERAL_INTERRUPT_MASK_VSOM_GET(val);
+ if (cecm)
+ *cecm = AV8100_GENERAL_INTERRUPT_MASK_CECM_GET(val);
+ if (hdcpm)
+ *hdcpm = AV8100_GENERAL_INTERRUPT_MASK_HDCPM_GET(val);
+ if (uovbm)
+ *uovbm = AV8100_GENERAL_INTERRUPT_MASK_UOVBM_GET(val);
+ if (tem)
+ *tem = AV8100_GENERAL_INTERRUPT_MASK_TEM_GET(val);
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_gen_int_r(
+ u8 *eoci,
+ u8 *vsii,
+ u8 *vsoi,
+ u8 *ceci,
+ u8 *hdcpi,
+ u8 *uovbi,
+ u8 *tei)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Read from register */
+ retval = register_read_internal(AV8100_GENERAL_INTERRUPT, &val);
+
+ /* Set return params */
+ if (eoci)
+ *eoci = AV8100_GENERAL_INTERRUPT_EOCI_GET(val);
+ if (vsii)
+ *vsii = AV8100_GENERAL_INTERRUPT_VSII_GET(val);
+ if (vsoi)
+ *vsoi = AV8100_GENERAL_INTERRUPT_VSOI_GET(val);
+ if (ceci)
+ *ceci = AV8100_GENERAL_INTERRUPT_CECI_GET(val);
+ if (hdcpi)
+ *hdcpi = AV8100_GENERAL_INTERRUPT_HDCPI_GET(val);
+ if (uovbi)
+ *uovbi = AV8100_GENERAL_INTERRUPT_UOVBI_GET(val);
+ if (tei)
+ *tei = AV8100_GENERAL_INTERRUPT_TEI_GET(val);
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_gen_status_r(
+ u8 *cecrec,
+ u8 *cectrx,
+ u8 *uc,
+ u8 *onuvb,
+ u8 *hdcps)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Read from register */
+ retval = register_read_internal(AV8100_GENERAL_STATUS, &val);
+
+ /* Set return params */
+ if (cecrec)
+ *cecrec = AV8100_GENERAL_STATUS_CECREC_GET(val);
+ if (cectrx)
+ *cectrx = AV8100_GENERAL_STATUS_CECTRX_GET(val);
+ if (uc)
+ *uc = AV8100_GENERAL_STATUS_UC_GET(val);
+ if (onuvb)
+ *onuvb = AV8100_GENERAL_STATUS_ONUVB_GET(val);
+ if (hdcps)
+ *hdcps = AV8100_GENERAL_STATUS_HDCPS_GET(val);
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_gpio_conf_r(
+ u8 *dat3dir,
+ u8 *dat3val,
+ u8 *dat2dir,
+ u8 *dat2val,
+ u8 *dat1dir,
+ u8 *dat1val,
+ u8 *ucdbg)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Read from register */
+ retval = register_read_internal(AV8100_GPIO_CONFIGURATION, &val);
+
+ /* Set return params */
+ if (dat3dir)
+ *dat3dir = AV8100_GPIO_CONFIGURATION_DAT3DIR_GET(val);
+ if (dat3val)
+ *dat3val = AV8100_GPIO_CONFIGURATION_DAT3VAL_GET(val);
+ if (dat2dir)
+ *dat2dir = AV8100_GPIO_CONFIGURATION_DAT2DIR_GET(val);
+ if (dat2val)
+ *dat2val = AV8100_GPIO_CONFIGURATION_DAT2VAL_GET(val);
+ if (dat1dir)
+ *dat1dir = AV8100_GPIO_CONFIGURATION_DAT1DIR_GET(val);
+ if (dat1val)
+ *dat1val = AV8100_GPIO_CONFIGURATION_DAT1VAL_GET(val);
+ if (ucdbg)
+ *ucdbg = AV8100_GPIO_CONFIGURATION_UCDBG_GET(val);
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_gen_ctrl_r(
+ u8 *fdl,
+ u8 *hld,
+ u8 *wa,
+ u8 *ra)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Read from register */
+ retval = register_read_internal(AV8100_GENERAL_CONTROL, &val);
+ /* Set return params */
+ if (fdl)
+ *fdl = AV8100_GENERAL_CONTROL_FDL_GET(val);
+ if (hld)
+ *hld = AV8100_GENERAL_CONTROL_HLD_GET(val);
+ if (wa)
+ *wa = AV8100_GENERAL_CONTROL_WA_GET(val);
+ if (ra)
+ *ra = AV8100_GENERAL_CONTROL_RA_GET(val);
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_fw_dl_entry_r(
+ u8 *mbyte_code_entry)
+{
+ int retval;
+ u8 val;
+
+ LOCK_AV8100_HW;
+
+ /* Read from register */
+ retval = register_read_internal(AV8100_FIRMWARE_DOWNLOAD_ENTRY, &val);
+
+ /* Set return params */
+ if (mbyte_code_entry)
+ *mbyte_code_entry =
+ AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY_GET(val);
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_reg_r(
+ u8 offset,
+ u8 *value)
+{
+ int retval = 0;
+ struct i2c_client *i2c;
+
+ LOCK_AV8100_HW;
+
+ if (!av8100_config) {
+ retval = AV8100_FAIL;
+ goto av8100_register_read_out;
+ }
+
+ i2c = av8100_config->client;
+
+ /* Read from register */
+ retval = read_single_byte(i2c, offset, value);
+ if (retval) {
+ dev_dbg(av8100dev,
+ "Failed to read the value from av8100 register\n");
+ retval = -EFAULT;
+ goto av8100_register_read_out;
+ }
+
+av8100_register_read_out:
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_conf_get(enum av8100_command_type command_type,
+ union av8100_configuration *config)
+{
+ if (!av8100_config || !config)
+ return AV8100_FAIL;
+
+ /* Put configuration data to the corresponding data struct depending
+ * on command type */
+ switch (command_type) {
+ case AV8100_COMMAND_VIDEO_INPUT_FORMAT:
+ memcpy(&config->video_input_format,
+ &av8100_config->hdmi_video_input_cmd,
+ sizeof(struct av8100_video_input_format_cmd));
+ break;
+
+ case AV8100_COMMAND_AUDIO_INPUT_FORMAT:
+ memcpy(&config->audio_input_format,
+ &av8100_config->hdmi_audio_input_cmd,
+ sizeof(struct av8100_audio_input_format_cmd));
+ break;
+
+ case AV8100_COMMAND_VIDEO_OUTPUT_FORMAT:
+ memcpy(&config->video_output_format,
+ &av8100_config->hdmi_video_output_cmd,
+ sizeof(struct av8100_video_output_format_cmd));
+ break;
+
+ case AV8100_COMMAND_VIDEO_SCALING_FORMAT:
+ memcpy(&config->video_scaling_format,
+ &av8100_config->hdmi_video_scaling_cmd,
+ sizeof(struct av8100_video_scaling_format_cmd));
+ break;
+
+ case AV8100_COMMAND_COLORSPACECONVERSION:
+ memcpy(&config->color_space_conversion_format,
+ &av8100_config->hdmi_color_space_conversion_cmd,
+ sizeof(struct
+ av8100_color_space_conversion_format_cmd));
+ break;
+
+ case AV8100_COMMAND_CEC_MESSAGE_WRITE:
+ memcpy(&config->cec_message_write_format,
+ &av8100_config->hdmi_cec_message_write_cmd,
+ sizeof(struct av8100_cec_message_write_format_cmd));
+ break;
+
+ case AV8100_COMMAND_CEC_MESSAGE_READ_BACK:
+ memcpy(&config->cec_message_read_back_format,
+ &av8100_config->hdmi_cec_message_read_back_cmd,
+ sizeof(struct av8100_cec_message_read_back_format_cmd));
+ break;
+
+ case AV8100_COMMAND_DENC:
+ memcpy(&config->denc_format, &av8100_config->hdmi_denc_cmd,
+ sizeof(struct av8100_denc_format_cmd));
+ break;
+
+ case AV8100_COMMAND_HDMI:
+ memcpy(&config->hdmi_format, &av8100_config->hdmi_cmd,
+ sizeof(struct av8100_hdmi_cmd));
+ break;
+
+ case AV8100_COMMAND_HDCP_SENDKEY:
+ memcpy(&config->hdcp_send_key_format,
+ &av8100_config->hdmi_hdcp_send_key_cmd,
+ sizeof(struct av8100_hdcp_send_key_format_cmd));
+ break;
+
+ case AV8100_COMMAND_HDCP_MANAGEMENT:
+ memcpy(&config->hdcp_management_format,
+ &av8100_config->hdmi_hdcp_management_format_cmd,
+ sizeof(struct av8100_hdcp_management_format_cmd));
+ break;
+
+ case AV8100_COMMAND_INFOFRAMES:
+ memcpy(&config->infoframes_format,
+ &av8100_config->hdmi_infoframes_cmd,
+ sizeof(struct av8100_infoframes_format_cmd));
+ break;
+
+ case AV8100_COMMAND_EDID_SECTION_READBACK:
+ memcpy(&config->edid_section_readback_format,
+ &av8100_config->hdmi_edid_section_readback_cmd,
+ sizeof(struct
+ av8100_edid_section_readback_format_cmd));
+ break;
+
+ case AV8100_COMMAND_PATTERNGENERATOR:
+ memcpy(&config->pattern_generator_format,
+ &av8100_config->hdmi_pattern_generator_cmd,
+ sizeof(struct av8100_pattern_generator_format_cmd));
+ break;
+
+ case AV8100_COMMAND_FUSE_AES_KEY:
+ memcpy(&config->fuse_aes_key_format,
+ &av8100_config->hdmi_fuse_aes_key_cmd,
+ sizeof(struct av8100_fuse_aes_key_format_cmd));
+ break;
+
+ default:
+ return AV8100_FAIL;
+ break;
+ }
+
+ return 0;
+}
+
+int av8100_conf_prep(enum av8100_command_type command_type,
+ union av8100_configuration *config)
+{
+ if (!av8100_config || !config)
+ return AV8100_FAIL;
+
+ /* Put configuration data to the corresponding data struct depending
+ * on command type */
+ switch (command_type) {
+ case AV8100_COMMAND_VIDEO_INPUT_FORMAT:
+ memcpy(&av8100_config->hdmi_video_input_cmd,
+ &config->video_input_format,
+ sizeof(struct av8100_video_input_format_cmd));
+ break;
+
+ case AV8100_COMMAND_AUDIO_INPUT_FORMAT:
+ memcpy(&av8100_config->hdmi_audio_input_cmd,
+ &config->audio_input_format,
+ sizeof(struct av8100_audio_input_format_cmd));
+ break;
+
+ case AV8100_COMMAND_VIDEO_OUTPUT_FORMAT:
+ memcpy(&av8100_config->hdmi_video_output_cmd,
+ &config->video_output_format,
+ sizeof(struct av8100_video_output_format_cmd));
+
+ /* Set params that depend on video output */
+ av8100_config_video_output_dep(av8100_config->
+ hdmi_video_output_cmd.video_output_cea_vesa);
+ break;
+
+ case AV8100_COMMAND_VIDEO_SCALING_FORMAT:
+ memcpy(&av8100_config->hdmi_video_scaling_cmd,
+ &config->video_scaling_format,
+ sizeof(struct av8100_video_scaling_format_cmd));
+ break;
+
+ case AV8100_COMMAND_COLORSPACECONVERSION:
+ memcpy(&av8100_config->hdmi_color_space_conversion_cmd,
+ &config->color_space_conversion_format,
+ sizeof(struct
+ av8100_color_space_conversion_format_cmd));
+ break;
+
+ case AV8100_COMMAND_CEC_MESSAGE_WRITE:
+ memcpy(&av8100_config->hdmi_cec_message_write_cmd,
+ &config->cec_message_write_format,
+ sizeof(struct av8100_cec_message_write_format_cmd));
+ break;
+
+ case AV8100_COMMAND_CEC_MESSAGE_READ_BACK:
+ memcpy(&av8100_config->hdmi_cec_message_read_back_cmd,
+ &config->cec_message_read_back_format,
+ sizeof(struct av8100_cec_message_read_back_format_cmd));
+ break;
+
+ case AV8100_COMMAND_DENC:
+ memcpy(&av8100_config->hdmi_denc_cmd, &config->denc_format,
+ sizeof(struct av8100_denc_format_cmd));
+ break;
+
+ case AV8100_COMMAND_HDMI:
+ memcpy(&av8100_config->hdmi_cmd, &config->hdmi_format,
+ sizeof(struct av8100_hdmi_cmd));
+ break;
+
+ case AV8100_COMMAND_HDCP_SENDKEY:
+ memcpy(&av8100_config->hdmi_hdcp_send_key_cmd,
+ &config->hdcp_send_key_format,
+ sizeof(struct av8100_hdcp_send_key_format_cmd));
+ break;
+
+ case AV8100_COMMAND_HDCP_MANAGEMENT:
+ memcpy(&av8100_config->hdmi_hdcp_management_format_cmd,
+ &config->hdcp_management_format,
+ sizeof(struct av8100_hdcp_management_format_cmd));
+ break;
+
+ case AV8100_COMMAND_INFOFRAMES:
+ memcpy(&av8100_config->hdmi_infoframes_cmd,
+ &config->infoframes_format,
+ sizeof(struct av8100_infoframes_format_cmd));
+ break;
+
+ case AV8100_COMMAND_EDID_SECTION_READBACK:
+ memcpy(&av8100_config->hdmi_edid_section_readback_cmd,
+ &config->edid_section_readback_format,
+ sizeof(struct
+ av8100_edid_section_readback_format_cmd));
+ break;
+
+ case AV8100_COMMAND_PATTERNGENERATOR:
+ memcpy(&av8100_config->hdmi_pattern_generator_cmd,
+ &config->pattern_generator_format,
+ sizeof(struct av8100_pattern_generator_format_cmd));
+ break;
+
+ case AV8100_COMMAND_FUSE_AES_KEY:
+ memcpy(&av8100_config->hdmi_fuse_aes_key_cmd,
+ &config->fuse_aes_key_format,
+ sizeof(struct av8100_fuse_aes_key_format_cmd));
+ break;
+
+ default:
+ return AV8100_FAIL;
+ break;
+ }
+
+ return 0;
+}
+
+int av8100_conf_w(enum av8100_command_type command_type,
+ u8 *return_buffer_length,
+ u8 *return_buffer, enum interface_type if_type)
+{
+ int retval = 0;
+ u8 cmd_buffer[AV8100_COMMAND_MAX_LENGTH];
+ u32 cmd_length = 0;
+ struct i2c_client *i2c;
+
+ if (return_buffer_length)
+ *return_buffer_length = 0;
+
+ if (!av8100_config)
+ return AV8100_FAIL;
+
+ i2c = av8100_config->client;
+
+ memset(&cmd_buffer, 0x00, AV8100_COMMAND_MAX_LENGTH);
+
+#ifdef AV8100_DEBUG_EXTRA
+#define PRNK_MODE(_m) dev_dbg(av8100dev, "cmd: " #_m "\n");
+#else
+#define PRNK_MODE(_m)
+#endif
+
+ /* Fill the command buffer with configuration data */
+ switch (command_type) {
+ case AV8100_COMMAND_VIDEO_INPUT_FORMAT:
+ PRNK_MODE(AV8100_COMMAND_VIDEO_INPUT_FORMAT);
+ configuration_video_input_get(cmd_buffer, &cmd_length);
+ break;
+
+ case AV8100_COMMAND_AUDIO_INPUT_FORMAT:
+ PRNK_MODE(AV8100_COMMAND_AUDIO_INPUT_FORMAT);
+ configuration_audio_input_get(cmd_buffer, &cmd_length);
+ break;
+
+ case AV8100_COMMAND_VIDEO_OUTPUT_FORMAT:
+ PRNK_MODE(AV8100_COMMAND_VIDEO_OUTPUT_FORMAT);
+ configuration_video_output_get(cmd_buffer, &cmd_length);
+ break;
+
+ case AV8100_COMMAND_VIDEO_SCALING_FORMAT:
+ PRNK_MODE(AV8100_COMMAND_VIDEO_SCALING_FORMAT);
+ configuration_video_scaling_get(cmd_buffer,
+ &cmd_length);
+ break;
+
+ case AV8100_COMMAND_COLORSPACECONVERSION:
+ PRNK_MODE(AV8100_COMMAND_COLORSPACECONVERSION);
+ configuration_colorspace_conversion_get(cmd_buffer,
+ &cmd_length);
+ break;
+
+ case AV8100_COMMAND_CEC_MESSAGE_WRITE:
+ PRNK_MODE(AV8100_COMMAND_CEC_MESSAGE_WRITE);
+ configuration_cec_message_write_get(cmd_buffer,
+ &cmd_length);
+ break;
+
+ case AV8100_COMMAND_CEC_MESSAGE_READ_BACK:
+ PRNK_MODE(AV8100_COMMAND_CEC_MESSAGE_READ_BACK);
+ configuration_cec_message_read_get(cmd_buffer,
+ &cmd_length);
+ break;
+
+ case AV8100_COMMAND_DENC:
+ PRNK_MODE(AV8100_COMMAND_DENC);
+ configuration_denc_get(cmd_buffer, &cmd_length);
+ break;
+
+ case AV8100_COMMAND_HDMI:
+ PRNK_MODE(AV8100_COMMAND_HDMI);
+ configuration_hdmi_get(cmd_buffer, &cmd_length);
+ break;
+
+ case AV8100_COMMAND_HDCP_SENDKEY:
+ PRNK_MODE(AV8100_COMMAND_HDCP_SENDKEY);
+ configuration_hdcp_sendkey_get(cmd_buffer, &cmd_length);
+ break;
+
+ case AV8100_COMMAND_HDCP_MANAGEMENT:
+ PRNK_MODE(AV8100_COMMAND_HDCP_MANAGEMENT);
+ configuration_hdcp_management_get(cmd_buffer,
+ &cmd_length);
+ break;
+
+ case AV8100_COMMAND_INFOFRAMES:
+ PRNK_MODE(AV8100_COMMAND_INFOFRAMES);
+ configuration_infoframe_get(cmd_buffer, &cmd_length);
+ break;
+
+ case AV8100_COMMAND_EDID_SECTION_READBACK:
+ PRNK_MODE(AV8100_COMMAND_EDID_SECTION_READBACK);
+ av8100_edid_section_readback_get(cmd_buffer, &cmd_length);
+ break;
+
+ case AV8100_COMMAND_PATTERNGENERATOR:
+ PRNK_MODE(AV8100_COMMAND_PATTERNGENERATOR);
+ configuration_pattern_generator_get(cmd_buffer,
+ &cmd_length);
+ break;
+
+ case AV8100_COMMAND_FUSE_AES_KEY:
+ PRNK_MODE(AV8100_COMMAND_FUSE_AES_KEY);
+ configuration_fuse_aes_key_get(cmd_buffer, &cmd_length);
+ break;
+
+ default:
+ dev_dbg(av8100dev, "Invalid command type\n");
+ retval = AV8100_INVALID_COMMAND;
+ break;
+ }
+
+ LOCK_AV8100_HW;
+
+ if (if_type == I2C_INTERFACE) {
+#ifdef AV8100_DEBUG_EXTRA
+ {
+ int cnt = 0;
+ dev_dbg(av8100dev, "av8100_conf_w cmd_type:%02x length:%02x ",
+ command_type, cmd_length);
+ dev_dbg(av8100dev, "buffer: ");
+ while (cnt < cmd_length) {
+ dev_dbg(av8100dev, "%02x ", cmd_buffer[cnt]);
+ cnt++;
+ }
+ dev_dbg(av8100dev, "\n");
+ }
+#endif
+
+ /* Write the command buffer */
+ retval = write_multi_byte(i2c,
+ AV8100_CMD_BUF_OFFSET, cmd_buffer, cmd_length);
+ if (retval) {
+ UNLOCK_AV8100_HW;
+ return retval;
+ }
+
+ /* Write the command */
+ retval = write_single_byte(i2c, AV8100_COMMAND_OFFSET,
+ command_type);
+ if (retval) {
+ UNLOCK_AV8100_HW;
+ return retval;
+ }
+
+ /* TODO */
+ mdelay(100);
+
+ retval = get_command_return_data(i2c, command_type, cmd_buffer,
+ return_buffer_length, return_buffer);
+ } else if (if_type == DSI_INTERFACE) {
+ /* TODO */
+ } else {
+ retval = AV8100_INVALID_INTERFACE;
+ dev_dbg(av8100dev, "Invalid command type\n");
+ }
+
+ if (command_type == AV8100_COMMAND_HDMI) {
+ g_av8100_status.hdmi_on = ((av8100_config->hdmi_cmd.
+ hdmi_mode == AV8100_HDMI_ON) &&
+ (av8100_config->hdmi_cmd.hdmi_format == AV8100_HDMI));
+ }
+
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+int av8100_conf_w_raw(enum av8100_command_type command_type,
+ u8 buffer_length,
+ u8 *buffer,
+ u8 *return_buffer_length,
+ u8 *return_buffer)
+{
+ int retval = 0;
+ struct i2c_client *i2c;
+
+ LOCK_AV8100_HW;
+
+ if (return_buffer_length)
+ *return_buffer_length = 0;
+
+ if (!av8100_config) {
+ retval = AV8100_FAIL;
+ goto av8100_conf_w_raw_out;
+ }
+
+ i2c = av8100_config->client;
+
+ /* Write the command buffer */
+ retval = write_multi_byte(i2c,
+ AV8100_CMD_BUF_OFFSET, buffer, buffer_length);
+ if (retval)
+ goto av8100_conf_w_raw_out;
+
+ /* Write the command */
+ retval = write_single_byte(i2c, AV8100_COMMAND_OFFSET,
+ command_type);
+ if (retval)
+ goto av8100_conf_w_raw_out;
+
+ /* TODO */
+ mdelay(100);
+
+ retval = get_command_return_data(i2c, command_type, buffer,
+ return_buffer_length, return_buffer);
+
+av8100_conf_w_raw_out:
+ UNLOCK_AV8100_HW;
+ return retval;
+}
+
+struct av8100_status av8100_status_get(void)
+{
+ return g_av8100_status;
+}
+
+enum av8100_output_CEA_VESA av8100_video_output_format_get(int xres,
+ int yres,
+ int htot,
+ int vtot,
+ int pixelclk,
+ bool interlaced)
+{
+ enum av8100_output_CEA_VESA index = 1;
+ int yres_div = !interlaced ? 1 : 2;
+ int hres_div = 1;
+ long freq1;
+ long freq2;
+
+ /*
+ * 720_576_I need a divider for hact and htot since
+ * these params need to be twice as large as expected in av8100_all_cea,
+ * which is used as input parameter to video input config.
+ */
+ if ((xres == 720) && (yres == 576) && (interlaced == true))
+ hres_div = 2;
+
+ freq1 = 1000000 / htot * 1000000 / vtot / pixelclk + 1;
+ while (index < sizeof(av8100_all_cea)/sizeof(struct av8100_cea)) {
+ freq2 = av8100_all_cea[index].frequence /
+ av8100_all_cea[index].htotale /
+ av8100_all_cea[index].vtotale;
+
+ dev_dbg(av8100dev, "freq1:%ld freq2:%ld\n", freq1, freq2);
+ if ((xres == av8100_all_cea[index].hactive / hres_div) &&
+ (yres == av8100_all_cea[index].vactive * yres_div) &&
+ (htot == av8100_all_cea[index].htotale / hres_div) &&
+ (vtot == av8100_all_cea[index].vtotale) &&
+ (abs(freq1 - freq2) < 2)) {
+ goto av8100_video_output_format_get_out;
+ }
+ index++;
+ }
+
+av8100_video_output_format_get_out:
+ dev_dbg(av8100dev, "av8100_video_output_format_get %d %d %d %d %d\n",
+ xres, yres, htot, vtot, index);
+ return index;
+}
+
+void av8100_hdmi_event_cb_set(void (*hdmi_ev_cb)(enum av8100_hdmi_event))
+{
+ if (av8100_globals)
+ av8100_globals->hdmi_ev_cb = hdmi_ev_cb;
+}
+
+u8 av8100_ver_get(void)
+{
+ u8 ret;
+
+ LOCK_AV8100_HW;
+ ret = chip_version;
+ UNLOCK_AV8100_HW;
+
+ return ret;
+}
+
+static int av8100_open(struct inode *inode, struct file *filp)
+{
+ dev_dbg(av8100dev, "av8100_open is called\n");
+ return 0;
+}
+
+static int av8100_release(struct inode *inode, struct file *filp)
+{
+ dev_dbg(av8100dev, "av8100_release is called\n");
+ return 0;
+}
+
+static int av8100_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return 0;
+}
+
+static int __devinit av8100_probe(struct i2c_client *i2cClient,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct av8100_platform_data *pdata = i2cClient->dev.platform_data;
+
+ av8100dev = &i2cClient->dev;
+
+ dev_dbg(av8100dev, "%s\n", __func__);
+
+ g_av8100_status.av8100_state = AV8100_OPMODE_SHUTDOWN;
+ g_av8100_status.av8100_plugin_status = AV8100_PLUGIN_NONE;
+ g_av8100_status.hdmi_on = false;
+
+ ret = av8100_config_init();
+ if (ret) {
+ dev_info(av8100dev, "av8100_config_init failed\n");
+ goto err;
+ }
+
+ ret = av8100_globals_init();
+ if (ret) {
+ dev_info(av8100dev, "av8100_globals_init failed\n");
+ goto err;
+ }
+
+ if (!i2c_check_functionality(i2cClient->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+ ret = -ENODEV;
+ dev_info(av8100dev, "av8100 i2c_check_functionality failed\n");
+ goto err;
+ }
+
+ init_waitqueue_head(&av8100_event);
+
+ av8100_config->client = i2cClient;
+ av8100_config->id = (struct i2c_device_id *) id;
+ i2c_set_clientdata(i2cClient, av8100_config);
+
+ kthread_run(av8100_thread, NULL, "av8100_thread");
+
+ ret = request_irq(pdata->irq, av8100_intr_handler,
+ IRQF_TRIGGER_RISING, "av8100", av8100_config);
+ if (ret) {
+ dev_err(av8100dev, "av8100_hw request_irq %d failed %d\n",
+ pdata->irq, ret);
+ gpio_free(pdata->irq);
+ goto err;
+ }
+
+ /* Obtain the chip version */
+ av8100_powerup1();
+ av8100_powerdown();
+
+ return ret;
+err:
+ return ret;
+}
+
+static int __devexit av8100_remove(struct i2c_client *i2cClient)
+{
+ dev_dbg(av8100dev, "%s\n", __func__);
+
+ av8100_config_exit();
+ av8100_globals_exit();
+
+ return 0;
+}
+
+int av8100_init(void)
+{
+ int ret;
+
+ pr_debug("%s\n", __func__);
+
+ ret = i2c_add_driver(&av8100_driver);
+ if (ret) {
+ pr_err("av8100 i2c_add_driver failed\n");
+ goto av8100_init_err;
+ }
+
+ ret = misc_register(&av8100_miscdev);
+ if (ret) {
+ pr_err("av8100 misc_register failed\n");
+ goto av8100_init_err;
+ }
+
+ hdmi_init();
+
+ return ret;
+
+av8100_init_err:
+ return ret;
+}
+module_init(av8100_init);
+
+void av8100_exit(void)
+{
+ pr_debug("%s\n", __func__);
+
+ hdmi_exit();
+
+ misc_deregister(&av8100_miscdev);
+ i2c_del_driver(&av8100_driver);
+}
+module_exit(av8100_exit);
+
+MODULE_AUTHOR("Per Persson <per.xb.persson@stericsson.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ST-Ericsson hdmi display driver");
diff --git a/drivers/video/av8100/av8100_fw.h b/drivers/video/av8100/av8100_fw.h
new file mode 100644
index 00000000000..84575839ba0
--- /dev/null
+++ b/drivers/video/av8100/av8100_fw.h
@@ -0,0 +1,1038 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Author: Per Persson <per.xb.persson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+/* AV8100v1 Firmware version : V4.02 */
+#define AV8100_FW_SIZE_V1 16384
+char av8100_fw_buff_v1[AV8100_FW_SIZE_V1] = {
+0x80,0xfe,0xcb,0xfe,0x11,0xf4,0xc8,0xf5,0xc8,0xf5,0x1e,0xf7,0xc7,0xf4,0x23,0xf7,
+0x6b,0xf8,0x2d,0xfa,0x42,0xfa,0x53,0xfa,0x65,0xfa,0x78,0xfa,0x7d,0xfa,0x82,0xfa,
+0x87,0xfa,0x8c,0xfa,0xa1,0xfa,0xdb,0xfa,0x72,0xfb,0x0b,0xf4,0x0b,0xf4,0x0c,0xf4,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0xea,0xad,0xec,0xad,
+0x38,0x20,0x1b,0x72,0x80,0x81,0x4d,0x51,0x4d,0x51,0x4d,0x51,0x4d,0x51,0x4d,0x51,
+0x4d,0x51,0xb4,0x20,0xf4,0x2a,0x5a,0x90,0x82,0xfe,0xcd,0x80,0x00,0xaf,0x72,0x93,
+0xa3,0x20,0x5f,0x90,0x80,0x80,0x97,0x90,0x8d,0x20,0x0f,0xab,0x01,0xa6,0x88,0x89,
+0x90,0x96,0xad,0x97,0x90,0x9a,0xad,0x8b,0x93,0x9e,0xad,0x97,0x90,0xa2,0xad,0x80,
+0xb7,0xa6,0xad,0x81,0xb7,0xaa,0xad,0x82,0xb7,0xae,0xad,0x26,0x31,0x20,0x08,0x72,
+0x82,0xb7,0x21,0xa6,0x81,0xb7,0xc2,0xa6,0x80,0xb7,0x01,0xa6,0xb4,0x20,0xf5,0x2a,
+0x5a,0x90,0x80,0x00,0xa7,0x72,0x93,0xcc,0xad,0x49,0x27,0x97,0x90,0x5d,0x90,0xd4,
+0xad,0x82,0xb7,0xd8,0xad,0x81,0xb7,0xdc,0xad,0x80,0xb7,0xe0,0xad,0xff,0xae,0x90,
+0x81,0x59,0x29,0xea,0x26,0x5a,0xfb,0x38,0x20,0x07,0x72,0x4d,0x38,0x20,0x1a,0x72,
+0x49,0x00,0x38,0x20,0x05,0x72,0xbc,0xff,0xcd,0x08,0xae,0xf3,0x20,0x79,0x24,0x49,
+0x44,0x24,0x49,0x23,0x24,0x49,0x0b,0xad,0x82,0xfe,0xcd,0x9e,0x82,0xfe,0xcd,0x9f,
+0x5b,0x82,0xfe,0xcd,0x80,0xb6,0x82,0xfe,0xcd,0x81,0xb6,0x82,0xfe,0xcd,0x82,0xb6,
+0x82,0xad,0x9f,0x90,0x86,0xad,0x85,0x90,0x84,0x42,0x8c,0x20,0x9f,0x90,0x01,0xab,
+0x0f,0xa6,0x2a,0x31,0x20,0x08,0x72,0xfb,0x38,0x20,0x07,0x72,0x4d,0x38,0x20,0x1a,
+0x72,0xbc,0xff,0xcd,0xfb,0x38,0x20,0x07,0x72,0x30,0x20,0x10,0x72,0x31,0x20,0x1e,
+0x72,0x30,0x20,0x1c,0x72,0x95,0x05,0xa0,0x9e,0x52,0xc0,0xcc,0x5f,0x90,0x5f,0x4f,
+0x07,0x38,0x20,0x05,0x72,0x0c,0x39,0x20,0x05,0x72,0x81,0x41,0x29,0x38,0x20,0x18,
+0x72,0xd5,0x26,0x5a,0xfb,0x38,0x20,0x07,0x72,0x9d,0x9d,0x4d,0x38,0x20,0x1a,0x72,
+0x4d,0xae,0xff,0xcd,0x4d,0xae,0xff,0xcd,0x38,0x20,0x1b,0x72,0x4d,0x4d,0x4d,0x4d,
+0x4d,0x38,0x20,0x19,0x72,0x04,0x25,0x49,0x38,0x20,0x18,0x72,0x08,0xae,0x34,0x20,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0xa5,0xbe,0x84,0xa3,
+0xb7,0xa4,0xd6,0x92,0x5c,0xa2,0xb7,0xa4,0xd6,0x92,0x5c,0xa1,0xb7,0xa4,0xd6,0x92,
+0x01,0xae,0xa0,0xb7,0xa4,0xc6,0x92,0x88,0xa5,0xbf,0x81,0xa0,0xb7,0xa4,0xc2,0x92,
+0xa0,0xb6,0xa1,0xb7,0xa4,0xd2,0x92,0x5a,0xa1,0xb6,0xa2,0xb7,0xa4,0xd2,0x92,0x5a,
+0xa2,0xb6,0xa3,0xb7,0xa4,0xd0,0x92,0xa3,0xb6,0x03,0xae,0xa5,0xbf,0x81,0xa3,0xb7,
+0xa4,0xda,0x92,0x5c,0xa3,0xb6,0xa2,0xb7,0xa4,0xda,0x92,0x5c,0xa2,0xb6,0xa1,0xb7,
+0xa4,0xda,0x92,0x01,0xae,0xa1,0xb6,0xa0,0xb7,0xa4,0xca,0x92,0xa0,0xb6,0xa5,0xbf,
+0x40,0xfc,0xcc,0x10,0xfd,0xcd,0x81,0xa5,0xbe,0xe9,0x26,0x4a,0xa4,0x00,0x39,0x72,
+0xa4,0x00,0x69,0x72,0x5a,0xa4,0x00,0x69,0x72,0x5a,0xa4,0x00,0x68,0x72,0x03,0xae,
+0xa5,0xbf,0x1b,0x27,0x4d,0x81,0xa0,0xb7,0xa4,0xc9,0x92,0xa0,0xb6,0xa1,0xb7,0xa4,
+0xd9,0x92,0x5a,0xa1,0xb6,0xa2,0xb7,0xa4,0xd9,0x92,0x5a,0xa2,0xb6,0xa3,0xb7,0xa4,
+0xdb,0x92,0xa3,0xb6,0x03,0xae,0xa5,0xbf,0x40,0xfc,0xcc,0xc8,0xfc,0xcd,0x81,0x01,
+0xa6,0x02,0x20,0xff,0xa6,0x04,0x24,0x08,0x27,0xa4,0xd1,0x92,0xa3,0xb6,0xa5,0x3c,
+0x09,0x26,0xa4,0xd1,0x92,0xa2,0xb6,0xa5,0x3c,0x12,0x26,0xa4,0xd1,0x92,0xa1,0xb6,
+0xa5,0x3c,0x23,0x26,0xa4,0xd1,0x92,0xa0,0xb6,0xa5,0x3f,0x81,0xa0,0x3c,0x02,0x24,
+0xa1,0xb7,0xa1,0xb9,0x9f,0xa2,0xb7,0xa2,0xbb,0x42,0x93,0x0f,0x27,0x4d,0x84,0x86,
+0xfc,0xcd,0xa8,0xb6,0x05,0x27,0xa7,0xbe,0xa3,0xb7,0xa2,0xbf,0x42,0x93,0xa8,0xb6,
+0xa1,0xb7,0xa0,0xbf,0x42,0xa7,0xb6,0x89,0xa8,0xb7,0x81,0xa0,0x3f,0xa1,0x3f,0xa2,
+0xbf,0xa3,0xb7,0x81,0xa5,0xbe,0x84,0xa4,0xd7,0x92,0xa3,0xb6,0x5c,0xa4,0xd7,0x92,
+0xa2,0xb6,0x5c,0xa4,0xd7,0x92,0xa1,0xb6,0x01,0xae,0xa4,0xc7,0x92,0xa0,0xb6,0x88,
+0xa5,0xbf,0x81,0xa5,0xbe,0xa4,0xd7,0x92,0xa3,0xb6,0x5c,0xa4,0xd7,0x92,0xa2,0xb6,
+0x5c,0xa4,0xd7,0x92,0xa1,0xb6,0x01,0xae,0xa4,0xc7,0x92,0xa0,0xb6,0xa5,0xbf,0x81,
+0x01,0xa6,0x02,0x27,0x03,0x6d,0x04,0x26,0x02,0x6d,0x08,0x26,0x01,0x6d,0x0e,0x26,
+0x7d,0x81,0x84,0xa3,0xb7,0x03,0xe6,0xa2,0xb7,0x02,0xe6,0xa1,0xb7,0x01,0xe6,0xa0,
+0xb7,0xf6,0x88,0x81,0x01,0xa6,0x02,0x27,0xa3,0x3d,0x04,0x26,0xa2,0x3d,0x08,0x26,
+0xa1,0x3d,0x0e,0x26,0xa0,0x3d,0x81,0xf5,0x26,0x4a,0xa0,0x39,0xa1,0x39,0xa2,0x39,
+0xa3,0x38,0x0b,0x27,0x4d,0x81,0xa0,0x3f,0xa1,0x3f,0x81,0xa0,0xb7,0xa1,0xb7,0xff,
+0xa6,0x07,0x2a,0xa2,0xbf,0xa3,0xb7,0x81,0x41,0xa8,0xbb,0x41,0x52,0x93,0x84,0xa8,
+0xb7,0xa8,0xbb,0x52,0x01,0x7b,0xa7,0xbe,0xa8,0xb7,0x52,0x9f,0x90,0x88,0x81,0xa5,
+0xbe,0xa3,0xb7,0xa4,0xd6,0x92,0x5c,0xa2,0xb7,0xa4,0xd6,0x92,0x5c,0xa1,0xb7,0xa4,
+0xd6,0x92,0x01,0xae,0xa0,0xb7,0xa4,0xc6,0x92,0xa5,0xbf,0x81,0xa0,0x3f,0xa2,0xb7,
+0xa1,0xbf,0x5c,0x01,0x24,0xa2,0xbb,0x42,0x93,0xa0,0xb6,0xa3,0xb7,0xa2,0xbf,0x42,
+0x93,0xa0,0xbf,0x80,0xaa,0x00,0xc7,0x51,0x20,0xc6,0x50,0x20,0x11,0x72,0x80,0x85,
+0x90,0xa6,0x00,0x32,0xa5,0x00,0x32,0xa4,0x00,0x32,0xa9,0x00,0x32,0xa8,0x00,0x32,
+0xa7,0x00,0x32,0x84,0x84,0x84,0x84,0x00,0xc0,0xcd,0x63,0xa6,0x05,0x20,0x6b,0x01,
+0x5a,0x72,0x6a,0x01,0x5a,0x72,0x04,0x26,0x6b,0x01,0xc6,0x0f,0x27,0x6a,0x01,0xca,
+0x6b,0x01,0xc6,0x33,0x01,0x5f,0x72,0x6a,0x01,0x5f,0x72,0x6b,0x01,0x18,0x35,0x08,
+0x25,0x00,0xa2,0x6a,0x01,0xc6,0x19,0xa0,0x6b,0x01,0xc6,0x18,0x20,0x33,0x01,0x01,
+0x35,0x06,0x27,0x10,0xa5,0x04,0x7b,0x01,0x6b,0x10,0x40,0xc6,0x02,0x6b,0x11,0x40,
+0xc6,0x03,0x6b,0x12,0x40,0xc6,0x04,0x6b,0x13,0x40,0xc6,0x67,0xc9,0xcd,0x46,0x20,
+0xc7,0x46,0x20,0xc6,0x41,0x20,0x5f,0x72,0x0a,0x42,0x20,0x0d,0x72,0x88,0x88,0x88,
+0x88,0xa7,0x00,0x3b,0xa8,0x00,0x3b,0xa9,0x00,0x3b,0xa4,0x00,0x3b,0xa5,0x00,0x3b,
+0xa6,0x00,0x3b,0x89,0x90,0x80,0x85,0x90,0xa6,0x00,0x32,0xa5,0x00,0x32,0xa4,0x00,
+0x32,0xa9,0x00,0x32,0xa8,0x00,0x32,0xa7,0x00,0x32,0x00,0xc0,0xcd,0x15,0x20,0x10,
+0x72,0x07,0x27,0x09,0x2b,0x10,0xb6,0x12,0x20,0x01,0x35,0xa7,0x00,0x3b,0xa8,0x00,
+0x3b,0xa9,0x00,0x3b,0xa4,0x00,0x3b,0xa5,0x00,0x3b,0xa6,0x00,0x3b,0x89,0x90,0x80,
+0x0c,0x40,0x00,0x35,0x0d,0x40,0x00,0x35,0x0e,0x40,0x00,0x35,0x0f,0x40,0x04,0x35,
+0x11,0x20,0x80,0x35,0x80,0x11,0x20,0x40,0x35,0x80,0x11,0x20,0x20,0x35,0x80,0x11,
+0x20,0x10,0x35,0x80,0x11,0x20,0x08,0x35,0x80,0x17,0x20,0x14,0x72,0x80,0x17,0x20,
+0x15,0x72,0x05,0x17,0x20,0x05,0x72,0x11,0x20,0x04,0x35,0x80,0x78,0x01,0xc7,0x4a,
+0x05,0x20,0x1a,0x72,0x06,0x20,0x18,0x72,0x11,0x20,0xc7,0x02,0xa6,0x80,0x78,0x01,
+0xc7,0x05,0x20,0x1a,0x72,0x06,0x20,0x19,0x72,0x11,0x20,0xc7,0x01,0xa6,0x80,0x04,
+0x88,0x00,0x35,0x05,0x88,0x30,0x35,0x06,0x88,0x00,0x35,0x07,0x88,0x00,0x35,0x10,
+0x20,0x80,0x35,0x81,0x3e,0xfc,0xcd,0xbc,0xae,0xa4,0x00,0x84,0x35,0x81,0xa4,0xb7,
+0x00,0xa9,0x41,0x01,0xab,0x80,0x85,0x90,0xa6,0x00,0x32,0xa5,0x00,0x32,0xa4,0x00,
+0x32,0xa9,0x00,0x32,0xa8,0x00,0x32,0xa7,0x00,0x32,0xa3,0x00,0x32,0xa2,0x00,0x32,
+0xa1,0x00,0x32,0xa0,0x00,0x32,0x84,0x84,0x84,0x84,0x84,0x84,0x3e,0xfc,0xcd,0xa0,
+0xae,0xa4,0x00,0x84,0x35,0x10,0xfd,0xcd,0x33,0xad,0x5b,0xa0,0x3f,0xa1,0x3f,0xa2,
+0x1f,0x5d,0xfc,0xcd,0x83,0x01,0xce,0x84,0x01,0xc6,0x03,0x6b,0x80,0xa4,0x03,0x7b,
+0x04,0x6b,0x4f,0x01,0x6b,0xa0,0x84,0xc6,0x02,0x6b,0xa1,0x84,0xc6,0x03,0x6b,0xa2,
+0x84,0xc6,0x04,0x6b,0xa3,0x84,0xc6,0x84,0x84,0x83,0x01,0xcf,0x84,0x01,0xc7,0xc0,
+0xc9,0xcd,0xbc,0x00,0xce,0xbd,0x00,0xc6,0x85,0x01,0x3b,0x86,0x01,0x3b,0x0f,0x20,
+0xa4,0xc9,0xcd,0xbc,0x00,0xce,0xbd,0x00,0xc6,0x85,0x01,0x3b,0x86,0x01,0x3b,0x11,
+0x24,0x05,0xe2,0x72,0x85,0x01,0xc6,0x06,0xe0,0x72,0x86,0x01,0xc6,0x1f,0x24,0x05,
+0xe2,0x72,0xbc,0x00,0xc6,0x06,0xe0,0x72,0xbd,0x00,0xc6,0x1c,0x25,0x85,0x01,0xc2,
+0x05,0x7b,0x86,0x01,0xc0,0x06,0x7b,0x0c,0x24,0xbc,0x00,0xc2,0x05,0x7b,0xbd,0x00,
+0xc0,0x06,0x7b,0x5c,0x20,0x83,0x01,0xcf,0xbc,0x00,0xce,0x84,0x01,0xbd,0x00,0x55,
+0x0d,0x26,0x02,0x01,0xc6,0x0d,0x20,0x85,0x01,0xce,0x84,0x01,0xc7,0x86,0x01,0xc6,
+0x0b,0x27,0x4a,0x01,0x01,0xc6,0x07,0x20,0x01,0x35,0x07,0x20,0x03,0x35,0x08,0x26,
+0x04,0xa1,0x05,0x20,0x1d,0x72,0x05,0x20,0x1c,0x72,0x08,0x25,0x02,0xa1,0xbb,0x00,
+0xc6,0x1b,0x26,0xbc,0x00,0xc1,0x05,0x7b,0x22,0x26,0xbd,0x00,0xc1,0x06,0x7b,0x29,
+0x26,0x4a,0x01,0x01,0xc6,0x85,0x01,0x5f,0x72,0x86,0x01,0xc7,0x06,0xa6,0x23,0xfa,
+0xcd,0xa2,0xb7,0x18,0xaa,0xa2,0xb6,0x56,0xfd,0xcd,0x1b,0xfa,0xcd,0x5b,0x12,0x20,
+0x0a,0xa6,0x23,0xfa,0xcd,0xa2,0x18,0x56,0xfd,0xcd,0x1b,0xfa,0xcd,0x5b,0x10,0x24,
+0x00,0xa2,0x05,0x7b,0x0a,0xa0,0x06,0x7b,0x1a,0x25,0x00,0xa2,0x05,0x7b,0x06,0xa0,
+0x06,0x7b,0x03,0x6b,0xc7,0xa4,0x03,0x7b,0x01,0x6b,0xbc,0x84,0xc6,0x02,0x6b,0xbd,
+0x84,0xc6,0x03,0x6b,0xbe,0x84,0xc6,0x04,0x6b,0xbf,0x84,0xc6,0x57,0x27,0x02,0x01,
+0xc6,0x06,0x6b,0xa7,0x83,0xc6,0x05,0x6b,0xa6,0x83,0xc6,0x84,0x01,0x5f,0x72,0x83,
+0x01,0x5f,0x72,0x86,0x01,0x5f,0x72,0x85,0x01,0x5f,0x72,0x10,0x20,0x40,0x35,0x88,
+0x88,0x88,0x88,0x88,0x88,0xa0,0x00,0x3b,0xa1,0x00,0x3b,0xa2,0x00,0x3b,0xa3,0x00,
+0x3b,0xa7,0x00,0x3b,0xa8,0x00,0x3b,0xa9,0x00,0x3b,0xa4,0x00,0x3b,0xa5,0x00,0x3b,
+0xa6,0x00,0x3b,0x89,0x90,0x81,0x48,0x83,0x00,0x35,0x49,0x83,0x00,0x35,0x4a,0x83,
+0x00,0x35,0x4b,0x83,0x0f,0x35,0x80,0x85,0x90,0xa6,0x00,0x32,0xa5,0x00,0x32,0xa4,
+0x00,0x32,0xa9,0x00,0x32,0xa8,0x00,0x32,0xa7,0x00,0x32,0x84,0x84,0x84,0x84,0x79,
+0x01,0x5f,0x72,0xef,0xce,0xcd,0x20,0xad,0x05,0x26,0x4a,0x79,0x01,0xc6,0x0b,0x26,
+0x03,0xa1,0x01,0x01,0xc6,0x7f,0x01,0x5c,0x72,0x04,0x27,0x0f,0xa1,0x7f,0x01,0xc6,
+0x0b,0x20,0x78,0x01,0x01,0x35,0x11,0x26,0x7f,0x01,0x5a,0x72,0x17,0x27,0x7f,0x01,
+0xc6,0x11,0x26,0x03,0xea,0x72,0x04,0x7b,0x07,0x27,0x4c,0x03,0x7b,0x05,0x26,0x4c,
+0x04,0x7b,0x11,0x27,0x03,0x7b,0x04,0x26,0x4a,0x04,0x7b,0x66,0xe3,0xcd,0x03,0xee,
+0x72,0x9f,0x03,0x6b,0x04,0xef,0x72,0x03,0xe2,0x72,0x41,0x04,0xe0,0x72,0x5f,0x01,
+0xa6,0x03,0x6b,0x01,0xe2,0x72,0x03,0x7b,0x04,0x6b,0x02,0xe0,0x72,0x04,0x7b,0x0e,
+0x24,0x03,0xe2,0x72,0x9f,0x04,0xe0,0x72,0x46,0x54,0x01,0xef,0x72,0x02,0x6b,0x46,
+0x54,0xdf,0x00,0xce,0xe0,0x00,0xc6,0x08,0x20,0xdf,0x00,0xce,0xe0,0x00,0xc6,0x08,
+0x26,0x4a,0xd8,0x00,0xc6,0xe3,0x26,0x03,0xe1,0x72,0xa6,0x83,0xc6,0xeb,0x26,0x04,
+0xe1,0x72,0xa7,0x83,0xc6,0x04,0x6b,0xa7,0x83,0xc6,0x03,0x6b,0xa6,0x83,0xc6,0x2b,
+0xf8,0xcc,0x84,0x84,0x84,0x84,0xaf,0x00,0x35,0x35,0xb0,0x00,0x86,0x35,0xb1,0x00,
+0x37,0x35,0xb2,0x00,0xbd,0x35,0x7f,0x01,0x0f,0x35,0x81,0x01,0x01,0x35,0x5a,0xf8,
+0xcd,0xdc,0xc9,0xcd,0xb3,0x00,0x3b,0xb4,0x00,0x3b,0xb5,0x00,0x3b,0xb6,0x00,0x3b,
+0x31,0x26,0x81,0x01,0xc6,0xbd,0xce,0xcd,0x03,0x27,0x7f,0x01,0xc6,0x41,0xf8,0xcc,
+0x03,0x26,0x02,0xa1,0x77,0x01,0xc6,0x2b,0xf8,0xcc,0x03,0x27,0x02,0xa1,0x01,0x01,
+0xc6,0x10,0x20,0x20,0x35,0x88,0x88,0x88,0x88,0xa7,0x00,0x3b,0xa8,0x00,0x3b,0xa9,
+0x00,0x3b,0xa4,0x00,0x3b,0xa5,0x00,0x3b,0xa6,0x00,0x3b,0x89,0x90,0x80,0x10,0x20,
+0x08,0x35,0x81,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x02,0xab,0x80,0x85,0x90,
+0xa6,0x00,0x32,0xa5,0x00,0x32,0xa4,0x00,0x32,0xa9,0x00,0x32,0xa8,0x00,0x32,0xa7,
+0x00,0x32,0xa3,0x00,0x32,0xa2,0x00,0x32,0xa1,0x00,0x32,0xa0,0x00,0x32,0x84,0x84,
+0x84,0x84,0x84,0x7d,0xce,0xcd,0x78,0x01,0x5f,0x72,0x07,0x26,0x4a,0x78,0x01,0xc6,
+0x06,0x27,0x4a,0x01,0x01,0xc6,0x26,0xdb,0xcd,0x7a,0x01,0xc7,0x06,0x26,0x4a,0x7a,
+0x01,0xc6,0x3e,0xfc,0xcd,0xa4,0xbf,0x84,0xae,0xa3,0x1a,0x4e,0xad,0x5b,0x09,0x20,
+0x04,0xae,0xa4,0x00,0x44,0x35,0xa0,0x3f,0x5b,0xad,0x5b,0x02,0x6b,0x08,0x84,0xc6,
+0x03,0x6b,0x09,0x84,0xc6,0x04,0x6b,0x0a,0x84,0xc6,0x05,0x6b,0x0b,0x84,0xc6,0x3e,
+0xfc,0xcd,0xa4,0xbf,0x84,0xae,0xa3,0x1b,0x7b,0xad,0x5b,0x2d,0x27,0x03,0x01,0xc6,
+0x32,0x27,0xbf,0x00,0xc6,0x02,0x6b,0x84,0x84,0xc6,0x03,0x6b,0x85,0x84,0xc6,0x04,
+0x6b,0x86,0x84,0xc6,0x05,0x6b,0x87,0x84,0xc6,0x17,0x01,0x5c,0x72,0x04,0x27,0x4c,
+0x17,0x01,0xc6,0x0a,0x20,0x17,0x01,0x5f,0x72,0x06,0x27,0x7f,0x01,0xc6,0x80,0x01,
+0x5c,0x72,0x04,0x24,0xff,0xa1,0x80,0x01,0xc6,0x79,0x01,0x01,0x35,0x3e,0xfc,0xcd,
+0xa0,0xae,0xa4,0x00,0x84,0x35,0xa0,0x1f,0x13,0xf7,0xcd,0x5b,0x02,0x6b,0xa0,0x84,
+0xc6,0x03,0x6b,0xa1,0x84,0xc6,0x04,0x6b,0xa2,0x84,0xc6,0x05,0x6b,0xa3,0x84,0xc6,
+0x84,0x84,0x84,0x84,0xdc,0xc9,0xcd,0xb3,0x00,0x3b,0xb4,0x00,0x3b,0xb5,0x00,0x3b,
+0xb6,0x00,0x3b,0x81,0x01,0x5f,0x72,0x41,0x25,0x04,0xa1,0x80,0x01,0xc6,0x65,0x27,
+0x4a,0x01,0x01,0xc6,0x3e,0xfc,0xcd,0x9c,0xae,0xa4,0x00,0x83,0x35,0xa0,0xb7,0xa1,
+0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x01,0x6b,0x9f,0x83,0xc6,0x05,0x20,0x14,0x72,0x10,
+0x20,0x06,0x35,0x88,0x88,0x88,0x88,0x88,0xa0,0x00,0x3b,0xa1,0x00,0x3b,0xa2,0x00,
+0x3b,0xa3,0x00,0x3b,0xa7,0x00,0x3b,0xa8,0x00,0x3b,0xa9,0x00,0x3b,0xa4,0x00,0x3b,
+0xa5,0x00,0x3b,0xa6,0x00,0x3b,0x89,0x90,0x81,0xa4,0x00,0x8c,0x35,0xa0,0xb7,0xa1,
+0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x80,0x85,0x90,0xa6,0x00,0x32,0xa5,0x00,0x32,0xa4,
+0x00,0x32,0xa9,0x00,0x32,0xa8,0x00,0x32,0xa7,0x00,0x32,0xa3,0x00,0x32,0xa2,0x00,
+0x32,0xa1,0x00,0x32,0xa0,0x00,0x32,0x84,0x3e,0xfc,0xcd,0x0c,0xae,0x27,0xad,0xf0,
+0xa4,0x01,0x7b,0x18,0x01,0x5f,0x72,0x05,0x20,0x16,0x72,0x06,0x20,0xc7,0x05,0xaa,
+0x06,0x20,0xc6,0x1b,0x27,0x04,0xa5,0x01,0x7b,0x3e,0xfc,0xcd,0x0c,0xae,0x48,0xad,
+0xf0,0xa4,0x05,0x20,0x16,0x72,0x06,0x20,0x14,0x72,0x11,0x20,0x18,0x01,0x5a,0x72,
+0xb5,0xf4,0xcd,0x02,0xa6,0x05,0x26,0x4a,0x05,0x20,0x4f,0x03,0x25,0x02,0xa1,0x18,
+0x01,0xc6,0x3e,0xfc,0xcd,0x10,0xae,0x71,0xad,0x19,0x01,0xd6,0x22,0x27,0x18,0x01,
+0xce,0x59,0x27,0x0f,0xa5,0x01,0x7b,0x3e,0xfc,0xcd,0x0c,0xae,0xba,0xf5,0xcd,0x0f,
+0xa4,0x05,0x20,0x16,0x72,0x06,0x20,0x12,0x72,0x05,0x01,0x01,0x35,0x18,0x27,0x20,
+0xa5,0x01,0x7b,0x98,0xad,0x4f,0x05,0x27,0x80,0xa5,0x01,0x7b,0x07,0x01,0xd7,0x17,
+0x8c,0xc6,0x06,0x01,0x5c,0x72,0x06,0x01,0xce,0x0f,0x27,0x80,0xa5,0x07,0x20,0x06,
+0x01,0xcf,0x06,0x20,0x13,0x72,0x09,0x27,0x10,0xa5,0x20,0x26,0x05,0x01,0xce,0x01,
+0x6b,0x0f,0x8c,0xc6,0x10,0x20,0x10,0x35,0x88,0xa0,0x00,0x3b,0xa1,0x00,0x3b,0xa2,
+0x00,0x3b,0xa3,0x00,0x3b,0xa7,0x00,0x3b,0xa8,0x00,0x3b,0xa9,0x00,0x3b,0xa4,0x00,
+0x3b,0xa5,0x00,0x3b,0xa6,0x00,0x3b,0x89,0x90,0x3e,0xfc,0xcc,0x0c,0xae,0xa4,0x00,
+0x8c,0x35,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x80,0x85,0x90,0xa6,0x00,
+0x32,0xa5,0x00,0x32,0xa4,0x00,0x32,0xa9,0x00,0x32,0xa8,0x00,0x32,0xa7,0x00,0x32,
+0x84,0x84,0x84,0x84,0xa0,0x84,0xc7,0x01,0x7b,0xa1,0x84,0xc7,0x02,0x7b,0xa2,0x84,
+0xc7,0x03,0x7b,0xa3,0x84,0xc7,0x04,0x7b,0x79,0x01,0x01,0x35,0x01,0x6b,0x7f,0xa4,
+0x01,0x7b,0x0a,0x20,0x01,0x6b,0x80,0xaa,0x01,0x7b,0x12,0x27,0x02,0xa1,0x77,0x01,
+0xc6,0x0f,0x26,0x03,0xa1,0x04,0x27,0x02,0xa1,0x01,0x01,0xc6,0x1a,0x27,0x02,0x01,
+0xc6,0x05,0x26,0x03,0x01,0xc6,0x01,0x6b,0xa0,0x84,0xc6,0x02,0x6b,0xa1,0x84,0xc6,
+0x03,0x6b,0xa2,0x84,0xc6,0x04,0x6b,0xa3,0x84,0xc6,0x80,0x01,0x5f,0x72,0x77,0x01,
+0xc7,0x03,0xa4,0x83,0x84,0xc6,0x2a,0xca,0xcd,0x03,0x26,0x4a,0x76,0x01,0xc6,0x05,
+0x20,0x12,0x72,0x10,0x20,0x01,0x35,0x88,0x88,0x88,0x88,0xa7,0x00,0x3b,0xa8,0x00,
+0x3b,0xa9,0x00,0x3b,0xa4,0x00,0x3b,0xa5,0x00,0x3b,0xa6,0x00,0x3b,0x89,0x90,0x80,
+0x12,0x20,0x10,0x35,0x80,0xa1,0xf2,0xcc,0x28,0x4b,0x7a,0xd0,0xcd,0xa5,0xf2,0xcc,
+0xc1,0xa6,0x00,0x4b,0x08,0x4b,0xe5,0xd0,0xcd,0xa5,0xf2,0xcc,0xe0,0xa6,0x01,0x4b,
+0xe0,0x4b,0x26,0xf3,0xcc,0x03,0x26,0x2b,0x01,0x5a,0x72,0x81,0x84,0x84,0x2b,0x01,
+0x02,0x35,0x46,0xf2,0xcd,0xe0,0xa6,0x01,0x4b,0xe0,0x4b,0x10,0x27,0x4d,0xd1,0xd4,
+0xcd,0x28,0x27,0x2d,0x01,0xc5,0x2f,0x01,0xc6,0xa5,0xf2,0xcc,0xc1,0xa6,0x00,0x4b,
+0x28,0x4b,0xa3,0xf2,0xcc,0x01,0x4b,0x90,0x4b,0x7a,0xd0,0xcd,0x0a,0x27,0x2d,0x01,
+0xc5,0x2f,0x01,0xc6,0xc5,0x20,0x28,0x4b,0xa5,0xf2,0xcc,0xe0,0xa6,0x01,0x4b,0x90,
+0x4b,0x40,0xd1,0xcd,0x0c,0x27,0x2d,0x01,0xc5,0x2f,0x01,0xc6,0xdd,0x20,0x08,0x4b,
+0xa5,0xf2,0xcc,0x82,0xa6,0x01,0x4b,0x90,0x4b,0x2c,0x01,0x5a,0x72,0xce,0x27,0x2c,
+0x01,0xc6,0x12,0x26,0x4d,0x45,0xd4,0xcd,0xa5,0xf2,0xcc,0xc0,0xa6,0x00,0x4b,0x50,
+0x4b,0xb7,0x27,0x4d,0xd1,0xd4,0xcd,0xe8,0x26,0x4d,0xf8,0xd1,0xcd,0x03,0xa6,0x26,
+0x20,0x2c,0x01,0x0a,0x35,0xcb,0x27,0x4d,0xd1,0xd4,0xcd,0xd3,0x20,0x60,0x4b,0x04,
+0x27,0x4d,0xf8,0xd1,0xcd,0x83,0xa6,0x18,0x27,0x4d,0x27,0xd4,0xcd,0xa5,0xf2,0xcc,
+0x81,0xa6,0x00,0x4b,0x60,0x4b,0xec,0x26,0x4d,0xf8,0xd1,0xcd,0x02,0xa6,0xa7,0xd3,
+0xcd,0xa5,0xf2,0xcc,0xa0,0xa6,0x00,0x4b,0x08,0x4b,0x09,0x27,0x4d,0xe1,0xd2,0xcd,
+0x06,0x26,0x4d,0xf8,0xd1,0xcd,0x4c,0x8c,0x20,0x80,0xa6,0x88,0x88,0x4f,0x93,0x20,
+0x40,0xa6,0x00,0x4b,0xa0,0x4b,0x08,0x26,0x4d,0x50,0xd2,0xcd,0x03,0xf4,0xcc,0xc7,
+0xf3,0xcc,0x03,0x26,0x1f,0xa0,0xac,0xf3,0xcc,0x03,0x26,0x4a,0x94,0xf3,0xcc,0x03,
+0x26,0x20,0xa0,0xe0,0x27,0x1e,0xa0,0x78,0xf3,0xcc,0x03,0x26,0x4a,0x60,0x27,0x4a,
+0x39,0x27,0x20,0xa0,0xc3,0x27,0x20,0xa0,0x2c,0x27,0x20,0xa0,0x30,0x27,0x20,0xa0,
+0x03,0xf4,0xcc,0x03,0x26,0x39,0x01,0xc6,0xdd,0x20,0x60,0xa6,0x00,0x4b,0x50,0x4b,
+0x7a,0xd0,0xcd,0x03,0x25,0x61,0xa1,0x39,0x01,0xc6,0x12,0x27,0x11,0xa1,0x32,0x01,
+0xc6,0x07,0x27,0x30,0x01,0xc6,0x81,0x84,0x84,0x9f,0xad,0x20,0xa6,0x00,0x4b,0x50,
+0x4b,0x0b,0x26,0x03,0x01,0xc6,0x05,0x27,0x39,0x01,0xc6,0x10,0x20,0x4f,0x00,0x4b,
+0xa0,0x4b,0x7a,0xd0,0xcd,0x03,0x27,0x39,0x01,0xc6,0x0f,0x26,0x33,0x01,0xc6,0x81,
+0x84,0x84,0x84,0x5e,0xc9,0xcd,0x06,0xee,0x72,0x07,0x7b,0x39,0x01,0xc7,0x03,0x7b,
+0x05,0x20,0x18,0x72,0x04,0x27,0x01,0xe1,0x72,0xf0,0xa4,0x39,0x01,0xc6,0x01,0x6b,
+0xf0,0xa4,0x03,0x7b,0x06,0x20,0xc7,0x02,0x6b,0x02,0xea,0x72,0xe0,0xa4,0x03,0x7b,
+0x02,0x6b,0x1f,0xa4,0x06,0x20,0xc6,0x88,0x88,0x88,0xfe,0xce,0x80,0x3d,0xe1,0xb7,
+0x80,0x3d,0xab,0x93,0x80,0x3d,0x25,0x6e,0x9f,0x3d,0x81,0x12,0x00,0xc0,0x84,0x55,
+0x65,0xc0,0xcd,0x11,0xb7,0xeb,0xf0,0xcd,0x65,0xc0,0xcc,0x11,0xb7,0x84,0xef,0xcd,
+0xd6,0x20,0x84,0xef,0xcd,0x05,0x26,0x04,0xa1,0x12,0xb6,0x06,0x27,0x02,0xa1,0x12,
+0xb6,0x11,0x26,0x02,0xa1,0x11,0xb6,0xd2,0x20,0x6f,0xef,0xcd,0x1f,0x20,0x5c,0xee,
+0xcd,0x24,0x20,0xdd,0xed,0xcd,0xe1,0x20,0x11,0xb7,0xdd,0xed,0xcd,0x07,0x26,0x02,
+0xa1,0x11,0xb6,0x36,0x20,0x61,0xec,0xcd,0x3b,0x20,0xc3,0xeb,0xcd,0x40,0x20,0x2f,
+0xe9,0xcd,0x5a,0xc0,0xcc,0x9a,0xe8,0xcd,0x4b,0x20,0xbb,0xe8,0xcd,0x50,0x20,0xc2,
+0xe7,0xcd,0x55,0x20,0x6c,0xe7,0xcd,0x5a,0x20,0x3c,0xe7,0xcd,0x5f,0x20,0xf9,0xe6,
+0xcd,0x64,0x20,0xf4,0xe5,0xcd,0x81,0x88,0x89,0xf1,0xd6,0x88,0x8a,0xf1,0xd6,0x58,
+0x97,0x35,0xf2,0xcc,0x03,0x25,0x0f,0xa1,0x4a,0x28,0xf2,0x09,0xf2,0x04,0xf2,0xff,
+0xf1,0xed,0xf1,0xe8,0xf1,0xe3,0xf1,0xde,0xf1,0xd8,0xf1,0xd3,0xf1,0xce,0xf1,0xc9,
+0xf1,0xc4,0xf1,0xbf,0xf1,0xba,0xf1,0x81,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,
+0x02,0xab,0xf6,0x20,0x01,0xa6,0x81,0x85,0x85,0x85,0x85,0x85,0x06,0x26,0x11,0xbe,
+0x04,0x20,0x4f,0x78,0xc9,0xcd,0x0a,0xa6,0x9a,0x78,0x84,0xc7,0x02,0x7b,0x79,0x84,
+0xc7,0x03,0x7b,0x7a,0x84,0xc7,0x04,0x7b,0x7b,0x84,0xc7,0x05,0x7b,0x3e,0xfc,0xcd,
+0x78,0xae,0xa4,0x00,0x84,0x35,0xa0,0x18,0x36,0xad,0x5b,0x02,0x6b,0x78,0x84,0xc6,
+0x03,0x6b,0x79,0x84,0xc6,0x04,0x6b,0x7a,0x84,0xc6,0x05,0x6b,0x7b,0x84,0xc6,0xe8,
+0xcf,0xcd,0x01,0xa6,0xe8,0xcf,0xcd,0x4f,0x9b,0x49,0x27,0x01,0xe4,0x72,0x4f,0x01,
+0x20,0x4c,0x03,0x26,0x4a,0x11,0xb6,0x01,0x6b,0x4f,0x01,0x20,0x01,0xa6,0x04,0x26,
+0xea,0xfb,0xcd,0xa1,0x3f,0xa2,0x3f,0xa3,0x3f,0x77,0xad,0x5b,0x02,0x6b,0xc0,0x84,
+0xc6,0x03,0x6b,0xc1,0x84,0xc6,0x04,0x6b,0xc2,0x84,0xc6,0x05,0x6b,0xc3,0x84,0xc6,
+0x88,0x88,0x88,0x88,0x88,0x81,0x3e,0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0x81,
+0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,0x85,0x85,0x85,0x85,0x85,
+0x05,0x7b,0x75,0x01,0x01,0x35,0x04,0x27,0x02,0xa1,0x11,0xb6,0x0a,0x26,0x4a,0x13,
+0xb6,0x05,0x6b,0x01,0xa6,0xe1,0x20,0x12,0x00,0x50,0x01,0x55,0x09,0x20,0x64,0xd0,
+0xcd,0x05,0x27,0x85,0x85,0x4d,0xd7,0xc7,0xcd,0x13,0xbe,0x14,0xb6,0x01,0x4b,0x00,
+0x4b,0x1e,0x20,0x4f,0x84,0x84,0xb2,0xc8,0xcd,0x13,0xbe,0x14,0xb6,0x15,0x00,0x3b,
+0x01,0x4b,0x2f,0x20,0x64,0xd0,0xcd,0x34,0x27,0x4d,0x14,0xc9,0xcd,0x3c,0x20,0x9a,
+0x61,0xad,0xa2,0x18,0x5a,0xad,0x5b,0x9b,0x01,0x6b,0xb4,0x84,0xc6,0x02,0x6b,0xb5,
+0x84,0xc6,0x03,0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,0xc6,0x78,0xc9,0xcd,0xfa,
+0xa6,0x9a,0x18,0x84,0x00,0x35,0x19,0x84,0x03,0x35,0x1a,0x84,0x83,0x35,0x1b,0x84,
+0x00,0x35,0x14,0x45,0x00,0x35,0x15,0x45,0x00,0x35,0x16,0x45,0x00,0x35,0x17,0x45,
+0x02,0x35,0xe1,0xf0,0xcd,0xa2,0x16,0xa3,0x12,0xd6,0xf0,0xcd,0x5b,0x9b,0x01,0x6b,
+0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,0x03,0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,
+0x84,0xc6,0xbb,0xf0,0xcc,0x9f,0xf0,0xcc,0x03,0x26,0x4a,0x79,0x27,0x4a,0x71,0x27,
+0x4a,0x0f,0x27,0x4a,0x12,0xb6,0xbb,0xf0,0xcc,0x03,0x27,0x02,0xa1,0x11,0xb6,0xbf,
+0xf0,0xcc,0x79,0x01,0xc7,0x4c,0x9a,0x3e,0xfc,0xcd,0x18,0xae,0xa4,0x00,0x84,0x35,
+0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x12,0xb6,0x9b,0xbf,0xf0,0xcc,0x03,
+0x27,0x03,0xa1,0x01,0x01,0xc6,0x7b,0x01,0x5f,0x72,0x7c,0x01,0xc7,0x02,0xa6,0x02,
+0x20,0x0a,0xa6,0x0d,0x20,0x05,0x6b,0x01,0xa6,0x7d,0x01,0x5f,0x72,0x01,0x01,0x5f,
+0x72,0x12,0x27,0x4a,0x11,0x27,0x4a,0x18,0x27,0x4a,0x7d,0x01,0xc7,0x7f,0xa4,0x12,
+0xb6,0x01,0x01,0x03,0x35,0x56,0x26,0x4a,0x11,0xb6,0x75,0x01,0x5f,0x72,0x9a,0x18,
+0x84,0x00,0x35,0x19,0x84,0x00,0x35,0x1a,0x84,0x00,0x35,0x1b,0x84,0x00,0x35,0x9b,
+0x01,0x01,0x5f,0x72,0x05,0x6b,0x4f,0x88,0x88,0x88,0x88,0x88,0x81,0x4f,0x64,0xd0,
+0xcc,0x03,0x27,0x85,0x85,0x4d,0xd7,0xc7,0xcd,0x11,0xbe,0x12,0xb6,0x80,0x4b,0x00,
+0x4b,0x81,0x9a,0x21,0xfc,0xcd,0xa4,0xb7,0x46,0xa9,0x41,0x81,0xa4,0xb7,0x00,0xa9,
+0x41,0x08,0xab,0x81,0x84,0x8b,0x41,0x00,0xa9,0x41,0x0b,0xab,0x5b,0x0c,0x6b,0x4f,
+0x9a,0x3e,0xfc,0xcd,0x30,0xae,0xa4,0x00,0x42,0x35,0x10,0xfd,0xcd,0xa4,0xb7,0x00,
+0xa9,0x41,0x01,0xab,0x5b,0xdb,0xfb,0xcd,0x06,0x7b,0xa0,0x3f,0xa1,0x3f,0xa2,0x3f,
+0xa3,0x00,0x03,0x35,0x9b,0x01,0x6b,0x30,0x42,0xc6,0x02,0x6b,0x31,0x42,0xc6,0x03,
+0x6b,0x32,0x42,0xc6,0x04,0x6b,0x33,0x42,0xc6,0x06,0x6b,0x04,0xab,0x06,0x7b,0xa0,
+0x24,0x07,0xe1,0x72,0x13,0xb6,0x07,0x6b,0x04,0xab,0x07,0x7b,0x61,0xad,0x04,0xab,
+0x5c,0x01,0x24,0x07,0xeb,0x72,0x52,0x08,0xae,0x06,0x7b,0x56,0xfd,0xcd,0x6b,0xad,
+0x5b,0x9b,0xce,0x25,0x04,0xa1,0x0c,0x6b,0x4c,0x0c,0x7b,0xa4,0xc7,0x92,0x14,0xe6,
+0x90,0xa5,0xbf,0x05,0x6b,0x4c,0x9f,0x90,0x05,0xe6,0x72,0xa4,0x3c,0x02,0x24,0x97,
+0xa5,0xbb,0x0c,0xe0,0x72,0x03,0xa6,0xa5,0xbf,0x5d,0xef,0xcd,0x5b,0x22,0x25,0x05,
+0xe1,0x72,0x13,0xb6,0x0c,0x6b,0x08,0x6b,0x09,0x6b,0x0a,0x6b,0x0b,0x6b,0x4f,0x57,
+0x20,0x05,0x6b,0x4f,0x65,0xef,0xcd,0x00,0xab,0x52,0x08,0xae,0x06,0x7b,0x56,0xfd,
+0xcd,0x5d,0xef,0xcd,0x5b,0x9b,0x08,0x6b,0x4f,0x09,0x6b,0x13,0xb6,0x0a,0x6b,0x12,
+0xb6,0x0b,0x6b,0x11,0xb6,0x06,0x6b,0x10,0xa6,0x02,0x20,0x0c,0xa6,0x06,0x20,0x08,
+0xa6,0x0a,0x20,0x04,0xa6,0x51,0xef,0xcc,0x01,0xa6,0x09,0x27,0x4a,0x08,0x27,0x4a,
+0x17,0x27,0x4a,0x1c,0x27,0x4a,0x19,0x27,0x81,0xa0,0x11,0xb6,0x8b,0x41,0x00,0xa2,
+0x41,0x0c,0xa0,0x5b,0x81,0x85,0x85,0x85,0x85,0x4f,0x2f,0x01,0x01,0x35,0x30,0x01,
+0xc7,0x4c,0x08,0x20,0x17,0xb7,0x0c,0x26,0x31,0x01,0xc6,0x16,0xb7,0x04,0x7b,0x01,
+0x6b,0x02,0x6b,0x03,0x6b,0x4f,0x04,0x6b,0x34,0x01,0xc6,0x15,0xb7,0x01,0x7b,0x14,
+0xb7,0x02,0x7b,0x13,0xb7,0x03,0x7b,0x12,0xb7,0x04,0x7b,0x01,0x6b,0x35,0x01,0xc6,
+0x02,0x6b,0x36,0x01,0xc6,0x03,0x6b,0x37,0x01,0xc6,0x04,0x6b,0x38,0x01,0xc6,0x11,
+0x00,0x30,0x01,0x55,0x4a,0x20,0x2f,0x01,0x5f,0x72,0x30,0x01,0xc7,0x4c,0x54,0x20,
+0x2f,0x01,0x5f,0x72,0x30,0x01,0x5f,0x72,0x56,0x27,0x4a,0x17,0x27,0x4a,0x10,0x27,
+0x4a,0x11,0xb6,0x2e,0x01,0x08,0x35,0x04,0x27,0x12,0x3d,0x2e,0x01,0x5f,0x72,0x88,
+0x88,0x88,0x88,0x81,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,0x10,
+0x4d,0x00,0x35,0x11,0x4d,0x00,0x35,0x12,0x4d,0x00,0x35,0x81,0x04,0x48,0x00,0x35,
+0x05,0x48,0x00,0x35,0x06,0x48,0x00,0x35,0x07,0x48,0x00,0x35,0x3e,0xfc,0xcd,0xb4,
+0xae,0xa4,0x00,0x84,0x35,0xa3,0x1a,0x81,0x85,0x85,0x85,0x85,0x4f,0x9a,0x32,0x01,
+0x18,0x72,0x48,0x01,0x12,0x00,0x55,0x49,0x01,0x13,0x00,0x55,0x4a,0x01,0x14,0x00,
+0x55,0x4b,0x01,0x15,0x00,0x55,0x44,0x01,0x16,0x00,0x55,0x45,0x01,0x17,0x00,0x55,
+0x46,0x01,0x18,0x00,0x55,0x47,0x01,0x19,0x00,0x55,0x2c,0x26,0x28,0xa1,0x11,0xb6,
+0x32,0x20,0x32,0x01,0xc7,0x10,0xa4,0x32,0x01,0xc6,0x3c,0x20,0x32,0x01,0x10,0x72,
+0x06,0x26,0x27,0xa1,0x11,0xb6,0x21,0xfc,0xcd,0xa4,0xb7,0x48,0xa9,0x41,0x44,0xab,
+0x52,0x08,0xae,0x11,0xb6,0xfd,0xfb,0xcd,0x12,0xae,0x21,0xfc,0xcd,0xa4,0xb7,0x48,
+0xa9,0x41,0x40,0xab,0x52,0x08,0xae,0x11,0xb6,0xfd,0xfb,0xcd,0x16,0xae,0xf8,0xd1,
+0xcd,0x01,0xa6,0x7a,0xd0,0xcd,0xa9,0xed,0xcd,0xa1,0x1b,0xd2,0xed,0xcd,0x5b,0x01,
+0x6b,0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,0x03,0x6b,0xb6,0x84,0xc6,0x04,0x6b,
+0xb7,0x84,0xc6,0x25,0x26,0x11,0x3d,0x67,0x24,0x28,0xa1,0x11,0xb6,0xa2,0xed,0xcc,
+0x32,0x01,0x10,0x72,0x6a,0x26,0x91,0xa1,0x11,0xb6,0xc5,0xed,0xcd,0x13,0x4d,0x03,
+0x35,0xc5,0xed,0xcd,0x13,0x4d,0x43,0x35,0x0c,0x4d,0x1e,0x00,0x55,0x0d,0x4d,0x1f,
+0x00,0x55,0x0e,0x4d,0x20,0x00,0x55,0x0f,0x4d,0x21,0x00,0x55,0x08,0x4d,0x1a,0x00,
+0x55,0x09,0x4d,0x1b,0x00,0x55,0x0a,0x4d,0x1c,0x00,0x55,0x0b,0x4d,0x1d,0x00,0x55,
+0x04,0x4d,0x16,0x00,0x55,0x05,0x4d,0x17,0x00,0x55,0x06,0x4d,0x18,0x00,0x55,0x07,
+0x4d,0x19,0x00,0x55,0x00,0x4d,0x12,0x00,0x55,0x01,0x4d,0x13,0x00,0x55,0x02,0x4d,
+0x14,0x00,0x55,0x03,0x4d,0x15,0x00,0x55,0xa9,0xed,0xcd,0xa1,0x1a,0xd2,0xed,0xcd,
+0x5b,0x01,0x6b,0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,0x03,0x6b,0xb6,0x84,0xc6,
+0x04,0x6b,0xb7,0x84,0xc6,0x1d,0x26,0x80,0xa1,0x11,0xb6,0xf7,0x24,0x92,0xa1,0x11,
+0xb6,0x03,0xed,0xcc,0x03,0x24,0x80,0xa1,0x11,0xb6,0x9b,0x88,0x88,0x88,0x88,0x81,
+0x48,0x42,0x00,0x35,0x49,0x42,0x00,0x35,0x4a,0x42,0x00,0x35,0x81,0x85,0x85,0x85,
+0x85,0x4f,0x9a,0x2f,0xcd,0xcd,0x03,0x01,0x01,0x35,0xed,0xc6,0xcd,0x03,0x27,0xbf,
+0x00,0xc6,0x16,0xad,0x4b,0x42,0x05,0x35,0x04,0x20,0x4b,0x42,0x01,0x35,0x06,0x27,
+0x2d,0x01,0xc6,0x9e,0xcb,0xcd,0x3e,0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0xa2,
+0x16,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0x01,0x6b,0xb4,0x84,
+0xc6,0x02,0x6b,0xb5,0x84,0xc6,0x03,0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,0xc6,
+0x0a,0xe0,0xcd,0x50,0x20,0x59,0xad,0x4b,0x42,0x05,0x35,0x04,0x20,0x4b,0x42,0x01,
+0x35,0x06,0x27,0x2d,0x01,0xc6,0x13,0x26,0x4a,0x03,0x01,0xc6,0x69,0x20,0x5e,0xcc,
+0xcd,0x3e,0xcb,0xcd,0x08,0x26,0x11,0x3d,0x9b,0x2d,0x01,0x01,0x35,0x04,0x20,0x2d,
+0x01,0x5f,0x72,0x06,0x26,0x02,0xa1,0x11,0xb6,0x88,0x88,0x88,0x88,0x81,0x3e,0xfc,
+0xcd,0x78,0xae,0xa4,0x00,0x84,0x35,0x81,0x18,0x80,0x00,0x35,0x19,0x80,0x00,0x35,
+0x1a,0x80,0x00,0x35,0x81,0x08,0x80,0x00,0x35,0x09,0x80,0x00,0x35,0x0a,0x80,0x00,
+0x35,0x81,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x03,0xab,0x81,0x04,0x80,0x00,
+0x35,0x05,0x80,0x00,0x35,0x06,0x80,0x00,0x35,0x81,0x85,0x85,0x85,0x85,0x85,0x85,
+0x4f,0x9a,0x5e,0xcc,0xcd,0x02,0x01,0x5f,0x72,0xbc,0x84,0x00,0x35,0xbd,0x84,0x00,
+0x35,0xbe,0x84,0x18,0x35,0xbf,0x84,0x00,0x35,0x45,0xad,0x1b,0x80,0x80,0x35,0x14,
+0x80,0x00,0x35,0x15,0x80,0x00,0x35,0x16,0x80,0x00,0x35,0x17,0x80,0x00,0x35,0x4e,
+0xad,0x0b,0x80,0x00,0x35,0x3c,0xad,0x07,0x80,0x00,0x35,0x00,0x80,0x00,0x35,0x01,
+0x80,0x00,0x35,0x02,0x80,0x00,0x35,0x03,0x80,0x00,0x35,0xb9,0xeb,0xcd,0xa3,0xb7,
+0xf8,0xa4,0xa3,0xb6,0x68,0xad,0x5b,0x03,0x6b,0x78,0x84,0xc6,0x04,0x6b,0x79,0x84,
+0xc6,0x05,0x6b,0x7a,0x84,0xc6,0x06,0x6b,0x7b,0x84,0xc6,0x69,0x20,0x2f,0xcd,0xcd,
+0x02,0x01,0x01,0x35,0xe3,0xde,0xcd,0xbc,0x84,0x00,0x35,0xbd,0x84,0x00,0x35,0xbe,
+0x84,0x1b,0x35,0xbf,0x84,0x40,0x35,0x04,0x20,0xbf,0x84,0x41,0x35,0x06,0x26,0x14,
+0x3d,0xac,0xeb,0xcd,0x1b,0x80,0x81,0x35,0x3e,0xfc,0xcd,0x14,0xae,0xa4,0x00,0x80,
+0x35,0xc9,0xfb,0xcd,0x52,0x80,0xae,0x9f,0xeb,0xcd,0x0b,0x80,0x20,0x35,0x04,0x20,
+0x0b,0x80,0x60,0x35,0x06,0x26,0x6c,0x01,0xc7,0x16,0xb6,0x6d,0x01,0x60,0x20,0x55,
+0x6e,0x01,0x61,0x20,0x55,0x6f,0x01,0x62,0x20,0x55,0x70,0x01,0x63,0x20,0x55,0x68,
+0x20,0x21,0x35,0x64,0x20,0x6d,0x01,0x55,0x65,0x20,0x6e,0x01,0x55,0x66,0x20,0x6f,
+0x01,0x55,0x67,0x20,0x70,0x01,0x55,0x9d,0x9d,0x68,0x20,0x27,0x35,0x68,0x20,0x52,
+0x35,0x64,0x20,0x00,0x35,0x65,0x20,0x0f,0x35,0x66,0x20,0x42,0x35,0x67,0x20,0x40,
+0x35,0x68,0x20,0x22,0x35,0x60,0x20,0xfd,0x00,0x55,0x61,0x20,0xfe,0x00,0x55,0x62,
+0x20,0xff,0x00,0x55,0x63,0x20,0x00,0x01,0x55,0x6d,0x01,0x3a,0xf2,0x55,0x6e,0x01,
+0x3b,0xf2,0x55,0x6f,0x01,0x3c,0xf2,0x55,0x70,0x01,0x3d,0xf2,0x55,0x71,0x01,0xc7,
+0x72,0x01,0x21,0x35,0x73,0x01,0xe6,0x35,0x74,0x01,0xf0,0x35,0x23,0x20,0x6d,0x01,
+0x3e,0xf2,0x55,0x6e,0x01,0x3f,0xf2,0x55,0x6f,0x01,0x40,0xf2,0x55,0x70,0x01,0x41,
+0xf2,0x55,0x71,0x01,0xc7,0x72,0x01,0x21,0x35,0x73,0x01,0xf0,0x35,0x74,0x01,0x7c,
+0x35,0x48,0x20,0x6d,0x01,0x42,0xf2,0x55,0x6e,0x01,0x43,0xf2,0x55,0x6f,0x01,0x44,
+0xf2,0x55,0x70,0x01,0x45,0xf2,0x55,0x71,0x01,0xc7,0x72,0x01,0x21,0x35,0x73,0x01,
+0xf6,0x35,0x74,0x01,0x94,0x35,0x6d,0x20,0x87,0xeb,0xcd,0x07,0x80,0xe0,0x35,0x6d,
+0x01,0x36,0xf2,0x55,0x6e,0x01,0x37,0xf2,0x55,0x6f,0x01,0x38,0xf2,0x55,0x70,0x01,
+0x39,0xf2,0x55,0x71,0x01,0x5f,0x72,0x72,0x01,0x2a,0x35,0x73,0x01,0x09,0x35,0x74,
+0x01,0x8b,0x35,0x77,0x27,0x4a,0x55,0x27,0x4a,0x33,0x27,0x4a,0x12,0xb6,0x10,0x80,
+0x00,0x35,0x11,0x80,0x00,0x35,0x12,0x80,0x00,0x35,0x13,0x80,0x08,0x35,0x87,0xeb,
+0xcd,0x07,0x80,0xc0,0x35,0x3e,0xfc,0xcd,0x5f,0xa4,0x00,0x80,0x35,0xc9,0xfb,0xcd,
+0x06,0xaa,0x41,0x01,0xea,0x72,0x41,0x02,0xea,0x72,0x5f,0x28,0xaa,0xc0,0xa4,0x52,
+0x40,0xae,0x12,0xb6,0x01,0xef,0x72,0x02,0x6b,0x52,0x10,0xae,0x15,0xb6,0xb9,0xeb,
+0xcd,0xa3,0x10,0xa3,0x12,0xa3,0x14,0x94,0xeb,0xcd,0x5b,0x03,0x6b,0x78,0x84,0xc6,
+0x04,0x6b,0x79,0x84,0xc6,0x05,0x6b,0x7a,0x84,0xc6,0x06,0x6b,0x7b,0x84,0xc6,0x3e,
+0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0xa2,0x16,0x94,0xeb,0xcd,0x5b,0x03,0x6b,
+0xb4,0x84,0xc6,0x04,0x6b,0xb5,0x84,0xc6,0x05,0x6b,0xb6,0x84,0xc6,0x06,0x6b,0xb7,
+0x84,0xc6,0x15,0xeb,0xcc,0x03,0x27,0x4a,0x13,0xb6,0x9b,0x88,0x88,0x88,0x88,0x88,
+0x88,0x81,0x85,0x4f,0x18,0x01,0x5a,0x72,0x9a,0x0c,0x8c,0x00,0x35,0x0d,0x8c,0x00,
+0x35,0x0e,0x8c,0x00,0x35,0x0f,0x8c,0x01,0x35,0x04,0x20,0x0f,0x8c,0x03,0x35,0x06,
+0x26,0x4a,0x18,0x01,0xc6,0x3e,0xfc,0xcd,0x10,0xae,0xa4,0x00,0x8c,0x35,0xa0,0xb7,
+0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0x00,0x19,0x01,0x55,0x3e,0xfc,0xcd,0x1c,0xae,0xa4,
+0x00,0x8c,0x35,0xc9,0xfb,0xcd,0x5f,0x0f,0xa4,0x4e,0x19,0x01,0xc6,0x9b,0x06,0x20,
+0xc7,0xfa,0xa4,0x06,0x20,0xc6,0x52,0x27,0x18,0x01,0xc6,0xef,0x25,0x18,0x01,0xc1,
+0x01,0x6b,0x4c,0x9f,0x19,0x01,0xd7,0x12,0xe6,0x01,0xee,0x72,0x0a,0x20,0x4f,0x18,
+0x01,0xc7,0x11,0xb6,0x88,0x81,0x85,0x4f,0x05,0x01,0x5f,0x72,0xef,0x25,0x06,0x01,
+0xc1,0x01,0x6b,0x4c,0x9f,0x14,0xe7,0x07,0x01,0xd6,0x01,0xee,0x72,0x0a,0x20,0x4f,
+0x13,0x00,0x06,0x01,0x55,0x88,0x81,0x4f,0x9a,0xa8,0x84,0x29,0x00,0x55,0xa9,0x84,
+0x2a,0x00,0x55,0xaa,0x84,0x2b,0x00,0x55,0xab,0x84,0x2c,0x00,0x55,0x3e,0xfc,0xcd,
+0x48,0xae,0xa4,0x00,0x84,0x35,0xc9,0xfb,0xcd,0x27,0xbe,0x28,0xb6,0x3e,0xfc,0xcd,
+0x44,0xae,0xa4,0x00,0x84,0x35,0xc9,0xfb,0xcd,0x25,0xbe,0x26,0xb6,0x3e,0xfc,0xcd,
+0x40,0xae,0xa4,0x00,0x84,0x35,0xc9,0xfb,0xcd,0x23,0xbe,0x24,0xb6,0x3e,0xfc,0xcd,
+0x3c,0xae,0xa4,0x00,0x84,0x35,0xc9,0xfb,0xcd,0x21,0xbe,0x22,0xb6,0x3e,0xfc,0xcd,
+0x38,0xae,0xa4,0x00,0x84,0x35,0xc9,0xfb,0xcd,0x1f,0xbe,0x20,0xb6,0x3e,0xfc,0xcd,
+0x34,0xae,0xa4,0x00,0x84,0x35,0xc9,0xfb,0xcd,0x1d,0xbe,0x1e,0xb6,0x3e,0xfc,0xcd,
+0x30,0xae,0xa4,0x00,0x84,0x35,0xc9,0xfb,0xcd,0x1b,0xbe,0x1c,0xb6,0x3e,0xfc,0xcd,
+0x2c,0xae,0xa4,0x00,0x84,0x35,0xc9,0xfb,0xcd,0x19,0xbe,0x1a,0xb6,0x3e,0xfc,0xcd,
+0x28,0xae,0xa4,0x00,0x84,0x35,0xc9,0xfb,0xcd,0x17,0xbe,0x18,0xb6,0x3e,0xfc,0xcd,
+0x24,0xae,0xa4,0x00,0x84,0x35,0xc9,0xfb,0xcd,0x15,0xbe,0x16,0xb6,0x3e,0xfc,0xcd,
+0x20,0xae,0xa4,0x00,0x84,0x35,0xc9,0xfb,0xcd,0x13,0xbe,0x14,0xb6,0x3e,0xfc,0xcd,
+0x1c,0xae,0xa4,0x00,0x84,0x35,0xc9,0xfb,0xcd,0x11,0xbe,0x12,0xb6,0x9b,0x81,0x4f,
+0x7a,0x01,0x01,0x35,0xd6,0x00,0xcf,0x1f,0xbe,0xd7,0x00,0xc7,0x20,0xb6,0xd4,0x00,
+0xcf,0x1d,0xbe,0xd5,0x00,0xc7,0x1e,0xb6,0xd2,0x00,0xcf,0x1b,0xbe,0xd3,0x00,0xc7,
+0x1c,0xb6,0xd0,0x00,0xcf,0x19,0xbe,0xd1,0x00,0xc7,0x1a,0xb6,0xce,0x00,0xcf,0x17,
+0xbe,0xcf,0x00,0xc7,0x18,0xb6,0xcc,0x00,0xcf,0x15,0xbe,0xcd,0x00,0xc7,0x16,0xb6,
+0xca,0x00,0xcf,0x13,0xbe,0xcb,0x00,0xc7,0x14,0xb6,0xc8,0x00,0xcf,0x11,0xbe,0xc9,
+0x00,0xc7,0x12,0xb6,0x81,0x4f,0x9a,0x26,0xdb,0xcd,0x44,0xdc,0xcd,0x84,0x84,0x84,
+0x84,0x84,0x84,0x84,0x84,0x84,0xe0,0xcd,0xfd,0x00,0x3b,0xfe,0x00,0x3b,0xff,0x00,
+0x3b,0x00,0x01,0x3b,0xef,0x00,0x3b,0xf0,0x00,0x3b,0xf1,0x00,0x3b,0xf2,0x00,0x3b,
+0x70,0xd8,0xcd,0x9b,0xc7,0x20,0x9a,0xed,0xc6,0xcd,0x9b,0xce,0x27,0x03,0x01,0xc6,
+0xbf,0x00,0x01,0x35,0x9a,0xcc,0xc2,0xcd,0x9b,0xf1,0x25,0x01,0xe1,0x72,0x02,0x6b,
+0x4c,0x02,0x7b,0x9a,0x64,0xc5,0xcd,0x9b,0x08,0x20,0x4f,0x01,0x6b,0x12,0xb6,0x02,
+0x20,0x04,0xa6,0x04,0x26,0x02,0xa1,0x11,0xb6,0x81,0x85,0x85,0x4f,0xbf,0x00,0x5f,
+0x72,0x08,0x27,0x17,0x3d,0x88,0x88,0x81,0x85,0x85,0x85,0x85,0x85,0x01,0x7b,0x79,
+0x01,0x01,0x35,0x9a,0x3e,0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0xa3,0x1f,0x56,
+0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x02,0xab,0x5b,0xb4,0x84,0xc7,0x02,0x7b,0xb5,
+0x84,0xc7,0x03,0x7b,0xb6,0x84,0xc7,0x04,0x7b,0xb7,0x84,0xc7,0x05,0x7b,0x0a,0xfd,
+0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x02,0xab,0x5b,0xa3,0x1e,0xa0,0x3f,0xa1,0x3f,0xa2,
+0xb7,0x03,0xa4,0xa2,0xb6,0xa3,0x3f,0x66,0xfc,0xcd,0x5f,0x90,0xa7,0x00,0x01,0x35,
+0x5f,0x12,0xb6,0x04,0x6b,0xfc,0xa4,0x04,0x7b,0x02,0x6b,0xb4,0x84,0xc6,0x03,0x6b,
+0xb5,0x84,0xc6,0x04,0x6b,0xb6,0x84,0xc6,0x05,0x6b,0xb7,0x84,0xc6,0x63,0xca,0xcd,
+0x1c,0xbe,0x20,0xa6,0x9b,0xfd,0x00,0x22,0x00,0x55,0xfe,0x00,0x23,0x00,0x55,0xff,
+0x00,0x24,0x00,0x55,0x00,0x01,0x25,0x00,0x55,0x14,0x27,0x0f,0xfc,0xcd,0x22,0xae,
+0xfc,0x00,0xc7,0x12,0xb6,0xbb,0x00,0xc7,0x21,0xb6,0xbc,0x00,0xcf,0x1f,0xbe,0xbd,
+0x00,0xc7,0x20,0xb6,0xf6,0x00,0xcf,0x19,0xbe,0xf7,0x00,0xc7,0x1a,0xb6,0xfa,0x00,
+0xcf,0x17,0xbe,0xfb,0x00,0xc7,0x18,0xb6,0xf4,0x00,0xcf,0x15,0xbe,0xf5,0x00,0xc7,
+0x16,0xb6,0xf8,0x00,0xcf,0x13,0xbe,0xf9,0x00,0xc7,0x14,0xb6,0xf1,0xe6,0xcc,0x76,
+0x01,0xc7,0x4c,0xf1,0xe6,0xcc,0x01,0x6b,0x01,0xa6,0x45,0x27,0x4a,0x11,0x27,0x4a,
+0x0d,0x27,0x4d,0xbb,0x00,0x5f,0x72,0xbd,0x00,0x5f,0x72,0xbc,0x00,0x5f,0x72,0x01,
+0x01,0xc7,0x11,0xb6,0x01,0x6b,0x4f,0x88,0x88,0x88,0x88,0x88,0x00,0x00,0xba,0x42,
+0x00,0x00,0xb8,0x41,0x0a,0xd7,0x23,0x3c,0x00,0x00,0x80,0x3f,0x81,0x56,0xfd,0xcd,
+0xb3,0xae,0xa4,0x00,0x00,0x35,0x81,0xa4,0xb7,0x00,0xa9,0x41,0x17,0xab,0x81,0xa4,
+0x00,0x80,0x35,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x81,0x8b,0x41,0x00,
+0xa9,0x41,0x1c,0xab,0x5b,0x20,0x80,0x00,0x35,0x21,0x80,0x00,0x35,0x22,0x80,0x00,
+0x35,0x23,0x80,0x40,0x35,0x3e,0xfc,0xcd,0x30,0xae,0x1e,0xad,0x16,0x7b,0x3e,0xfc,
+0xcd,0x2c,0xae,0x27,0xad,0x15,0x7b,0x3e,0xfc,0xcd,0x28,0xae,0x30,0xad,0x14,0x7b,
+0xc2,0xfc,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x13,0xab,0x5b,0x56,0xfd,0xcd,0x71,0xae,
+0xa4,0x00,0x01,0x35,0x13,0x6b,0x60,0x20,0xc6,0x14,0x6b,0x61,0x20,0xc6,0x15,0x6b,
+0x62,0x20,0xc6,0x16,0x6b,0x63,0x20,0xc6,0x68,0x20,0x26,0x35,0x68,0x20,0x21,0x35,
+0x68,0x20,0x52,0x35,0x64,0x20,0xc7,0x0d,0x7b,0x65,0x20,0xc7,0x0e,0x7b,0x66,0x20,
+0xc7,0x0f,0x7b,0x67,0x20,0xc7,0x10,0x7b,0x60,0x20,0x6d,0x01,0x55,0x61,0x20,0x6e,
+0x01,0x55,0x62,0x20,0x6f,0x01,0x55,0x63,0x20,0x70,0x01,0x55,0x3e,0xfc,0xcd,0xa4,
+0xb7,0x00,0xa9,0x41,0x0d,0xab,0x5b,0x33,0xfd,0xcd,0xd2,0xe5,0xcd,0x5b,0xda,0xe5,
+0xcd,0xf0,0x27,0x1b,0xea,0x72,0x1c,0x7b,0xf7,0x26,0x4a,0x6c,0x01,0xc6,0xbb,0xe5,
+0xcc,0x03,0x27,0x4a,0x02,0x01,0xc6,0x84,0x84,0x84,0x84,0x01,0xca,0xcd,0x88,0x1a,
+0x7b,0x88,0x1a,0x7b,0x88,0x1a,0x7b,0x88,0x1a,0x7b,0x0f,0x20,0xdc,0xc9,0xcd,0x88,
+0x1a,0x7b,0x88,0x1a,0x7b,0x88,0x1a,0x7b,0x88,0x1a,0x7b,0x11,0x27,0x7f,0x01,0xc6,
+0x81,0x01,0x5f,0x72,0x04,0x20,0xc2,0xfc,0xcd,0xd2,0xe5,0xcd,0x5b,0xda,0xe5,0xcd,
+0x0c,0x2b,0xff,0xa2,0x11,0x7b,0xfd,0xa0,0x12,0x7b,0x0a,0x2b,0x00,0xa2,0x11,0x7b,
+0x04,0xa0,0x12,0x6b,0x18,0x7b,0x11,0x6b,0x17,0x7b,0x17,0x6b,0x60,0x20,0xc6,0x18,
+0x6b,0x61,0x20,0xc6,0x19,0x6b,0x62,0x20,0xc6,0x1a,0x6b,0x63,0x20,0xc6,0x68,0x20,
+0x26,0x35,0x68,0x20,0x24,0x35,0x64,0x20,0xab,0x00,0x55,0x65,0x20,0xac,0x00,0x55,
+0x66,0x20,0xad,0x00,0x55,0x67,0x20,0xae,0x00,0x55,0x68,0x20,0x21,0x35,0x64,0x20,
+0xc7,0x05,0x7b,0x65,0x20,0xc7,0x06,0x7b,0x66,0x20,0xc7,0x07,0x7b,0x67,0x20,0xc7,
+0x08,0x7b,0x60,0x20,0xaf,0x00,0x55,0x61,0x20,0xb0,0x00,0x55,0x62,0x20,0xb1,0x00,
+0x55,0x63,0x20,0xb2,0x00,0x55,0xab,0x00,0x60,0x20,0x55,0xac,0x00,0x61,0x20,0x55,
+0xad,0x00,0x62,0x20,0x55,0xae,0x00,0x63,0x20,0x55,0x68,0x20,0x21,0x35,0x64,0x20,
+0xc7,0x01,0x7b,0x65,0x20,0xc7,0x02,0x7b,0x66,0x20,0xc7,0x03,0x7b,0x67,0x20,0xc7,
+0x04,0x7b,0xaf,0x00,0x64,0x20,0x55,0xb0,0x00,0x65,0x20,0x55,0xb1,0x00,0x66,0x20,
+0x55,0xb2,0x00,0x67,0x20,0x55,0x68,0x20,0x64,0x35,0x64,0x20,0xaf,0x00,0x55,0x65,
+0x20,0xb0,0x00,0x55,0x66,0x20,0xb1,0x00,0x55,0x67,0x20,0xb2,0x00,0x55,0x68,0x20,
+0x21,0x35,0x64,0x20,0xc7,0x09,0x7b,0x65,0x20,0xc7,0x0a,0x7b,0x66,0x20,0xc7,0x0b,
+0x7b,0x67,0x20,0xc7,0x0c,0x7b,0x68,0x20,0x22,0x35,0x3e,0xfc,0xcd,0x60,0xae,0xa4,
+0x00,0x20,0x35,0xc9,0xfb,0xcd,0x1b,0xee,0x72,0x1c,0x7b,0xe0,0xe4,0xcc,0x03,0x26,
+0x1b,0xea,0x72,0x1c,0x7b,0x3e,0xfc,0xcd,0xd2,0xe5,0xcd,0x5b,0xa0,0x3f,0x56,0xfd,
+0xcd,0x5f,0xa4,0x00,0x84,0x35,0x3e,0xfc,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x09,0xab,
+0x5b,0x56,0xfd,0xcd,0xe4,0xae,0xa4,0x00,0xe5,0x35,0x06,0x20,0xe8,0xae,0xa4,0x00,
+0xe5,0x35,0x08,0x26,0x4c,0x17,0x01,0xc6,0x05,0x6b,0xec,0xe5,0xc6,0x06,0x6b,0xed,
+0xe5,0xc6,0x07,0x6b,0xee,0xe5,0xc6,0x08,0x6b,0xef,0xe5,0xc6,0x01,0x6b,0xf0,0xe5,
+0xc6,0x02,0x6b,0xf1,0xe5,0xc6,0x03,0x6b,0xf2,0xe5,0xc6,0x04,0x6b,0xf3,0xe5,0xc6,
+0x8b,0x41,0x00,0xa2,0x41,0x1a,0xa0,0x5b,0x89,0x88,0x81,0xa0,0xb7,0xa1,0xb7,0xa2,
+0xb7,0x4f,0xa3,0xb7,0x81,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,0x84,0x84,0x84,
+0x84,0x3e,0xfc,0xcd,0x10,0xae,0xa4,0x00,0x84,0x35,0xa1,0x1e,0x56,0xfd,0xcd,0x13,
+0xad,0x5b,0x10,0x84,0xc7,0x01,0x7b,0x11,0x84,0xc7,0x02,0x7b,0x12,0x84,0xc7,0x03,
+0x7b,0x13,0x84,0xc7,0x04,0x7b,0x02,0x6b,0x7f,0xa4,0x02,0x7b,0x3e,0xfc,0xcd,0x33,
+0xad,0x5b,0x10,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x07,0xab,0x5b,0xa0,0xb7,0x03,
+0xa4,0xa0,0xb6,0xa1,0x3f,0xa2,0x3f,0xa3,0x3f,0x56,0xfd,0xcd,0x50,0xad,0x5b,0x01,
+0x6b,0x10,0x84,0xc6,0x02,0x6b,0x11,0x84,0xc6,0x03,0x6b,0x12,0x84,0xc6,0x04,0x6b,
+0x13,0x84,0xc6,0x0a,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x07,0xab,0x5b,0xdb,0xfb,
+0xcd,0x14,0xa6,0x5c,0xe3,0xcd,0x0b,0x6b,0x4c,0x01,0x20,0x06,0xa6,0x05,0x20,0x02,
+0xa6,0x09,0x20,0x04,0xa6,0x0d,0x20,0x07,0xa6,0x10,0x27,0x10,0xa0,0x10,0x27,0x08,
+0xa0,0x10,0x27,0x04,0xa0,0x10,0x27,0x02,0xa0,0x21,0x27,0x02,0xa0,0x0b,0x7b,0x07,
+0x6b,0x60,0x20,0xc6,0x08,0x6b,0x61,0x20,0xc6,0x09,0x6b,0x62,0x20,0xc6,0x0a,0x6b,
+0x63,0x20,0xc6,0x68,0x20,0x26,0x35,0x68,0x20,0x21,0x35,0x68,0x20,0x52,0x35,0x64,
+0x20,0x00,0x35,0x65,0x20,0x00,0x35,0x66,0x20,0x80,0x35,0x67,0x20,0x00,0x35,0x9d,
+0x9d,0x68,0x20,0x27,0x35,0x60,0x20,0xb7,0x00,0x55,0x61,0x20,0xb8,0x00,0x55,0x62,
+0x20,0xb9,0x00,0x55,0x63,0x20,0xba,0x00,0x55,0x68,0x20,0x61,0x35,0x68,0x20,0x52,
+0x35,0x3e,0xfc,0xcd,0x64,0xae,0xa4,0x00,0x20,0x35,0x5c,0xe3,0xcd,0x0b,0x7b,0x68,
+0x20,0x22,0x35,0x60,0x20,0xc7,0x07,0x7b,0x61,0x20,0xc7,0x08,0x7b,0x62,0x20,0xc7,
+0x09,0x7b,0x63,0x20,0xc7,0x0a,0x7b,0x88,0x88,0x88,0x88,0x81,0x64,0x20,0x00,0x35,
+0x65,0x20,0x00,0x35,0x66,0x20,0x00,0x35,0x81,0x84,0x3e,0xfc,0xcd,0x10,0xae,0xa4,
+0x00,0x84,0x35,0xa2,0xb7,0x55,0xaa,0xa2,0xb6,0xa3,0xb7,0x55,0xaa,0xa3,0xb6,0xa1,
+0xb7,0x55,0xaa,0xa1,0xb6,0xdb,0xfb,0xcd,0x18,0xa6,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,
+0x4f,0xa3,0xb7,0x01,0x7b,0x3e,0xfc,0xcd,0x14,0xae,0xa4,0x00,0x84,0x35,0xa0,0xb7,
+0x3f,0xa4,0xa0,0xb6,0xa1,0x3f,0xa2,0x3f,0xa3,0x3f,0xdb,0xfb,0xcd,0x18,0xa6,0x56,
+0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x04,0xab,0x5b,0x25,0x24,0x0f,0xa1,0x07,0x7b,
+0x78,0xc9,0xcd,0x64,0xa6,0x84,0x84,0x84,0x84,0xdc,0xc9,0xcd,0xb3,0x00,0x3b,0xb4,
+0x00,0x3b,0xb5,0x00,0x3b,0xb6,0x00,0x3b,0x0f,0x20,0x01,0xca,0xcd,0xb3,0x00,0x3b,
+0xb4,0x00,0x3b,0xb5,0x00,0x3b,0xb6,0x00,0x3b,0x11,0x26,0x4a,0x01,0x01,0xc6,0x14,
+0x84,0x0f,0x35,0x15,0x84,0x00,0x35,0x16,0x84,0x00,0x35,0x17,0x84,0x00,0x35,0x04,
+0x6b,0x60,0x20,0xc6,0x05,0x6b,0x61,0x20,0xc6,0x06,0x6b,0x62,0x20,0xc6,0x07,0x6b,
+0x63,0x20,0xc6,0x68,0x20,0xc7,0x4a,0x9d,0x9d,0x68,0x20,0xc7,0x27,0xa6,0x68,0x20,
+0x52,0x35,0x64,0x20,0x05,0x35,0x65,0x20,0xf5,0x35,0x66,0x20,0xe1,0x35,0x67,0x20,
+0x00,0x35,0x60,0x20,0xb7,0x00,0x55,0x61,0x20,0xb8,0x00,0x55,0x62,0x20,0xb9,0x00,
+0x55,0x63,0x20,0xba,0x00,0x55,0xb3,0x00,0x60,0x20,0x55,0xb4,0x00,0x61,0x20,0x55,
+0xb5,0x00,0x62,0x20,0x55,0xb6,0x00,0x63,0x20,0x55,0x68,0x20,0x26,0x35,0x68,0x20,
+0x21,0x35,0x68,0x20,0x52,0x35,0x64,0x20,0x00,0x35,0x65,0x20,0x00,0x35,0x66,0x20,
+0x80,0x35,0x67,0x20,0x00,0x35,0x68,0x20,0x27,0x35,0xb7,0x00,0x60,0x20,0x55,0xb8,
+0x00,0x61,0x20,0x55,0xb9,0x00,0x62,0x20,0x55,0xba,0x00,0x63,0x20,0x55,0x68,0x20,
+0x52,0x35,0x64,0x20,0xc7,0x04,0x7b,0x65,0x20,0xc7,0x05,0x7b,0x66,0x20,0xc7,0x06,
+0x7b,0x67,0x20,0xc7,0x07,0x7b,0x68,0x20,0xc7,0x4a,0x68,0x20,0xc7,0x22,0xa6,0x60,
+0x20,0xc7,0x08,0x7b,0x61,0x20,0xc7,0x09,0x7b,0x62,0x20,0xc7,0x0a,0x7b,0x63,0x20,
+0xc7,0x0b,0x7b,0x68,0x20,0x52,0x35,0x10,0x84,0x02,0x35,0x11,0x84,0x55,0x35,0x12,
+0x84,0x55,0x35,0x13,0x84,0x55,0x35,0x01,0x6b,0x02,0xa6,0x28,0xe2,0xcd,0x67,0x20,
+0x28,0x35,0x09,0x20,0x01,0xa6,0x28,0xe2,0xcd,0x67,0x20,0x14,0x35,0x0b,0x25,0x02,
+0xa2,0x08,0x7b,0xdd,0xa0,0x09,0x7b,0x1e,0x20,0x4f,0x28,0xe2,0xcd,0x67,0x20,0x0a,
+0x35,0x0a,0x25,0x04,0xa2,0x08,0x7b,0xd9,0xa0,0x09,0x7b,0x88,0x81,0xe3,0x00,0xce,
+0xe4,0x00,0xc6,0x3e,0xfc,0xcd,0x81,0x84,0x84,0x3e,0xfc,0xcd,0x0c,0xae,0xa4,0x00,
+0x41,0x35,0x5d,0xfc,0xcd,0x41,0xdb,0x00,0xc9,0x41,0xdc,0x00,0xcb,0x17,0xad,0x08,
+0xae,0xa4,0x00,0x41,0x35,0x5d,0xfc,0xcd,0x5c,0x01,0x26,0x4c,0x26,0xad,0x04,0xae,
+0xa4,0x00,0x41,0x35,0x5d,0xfc,0xcd,0x41,0xd9,0x00,0xc9,0x41,0xda,0x00,0xcb,0x41,
+0x01,0xe2,0x72,0x41,0x02,0xe0,0x72,0xe1,0x00,0xce,0xe2,0x00,0xc6,0x3e,0xfc,0xcd,
+0x5f,0xa4,0x00,0x41,0x35,0x5d,0xfc,0xcd,0x5c,0x01,0x26,0x4c,0x41,0x01,0xe2,0x72,
+0x41,0x02,0xe0,0x72,0xe1,0x00,0xce,0xe2,0x00,0xc6,0x02,0x6b,0xe6,0x00,0xc6,0x01,
+0x6b,0xe5,0x00,0xc6,0x88,0x88,0x81,0xe9,0x00,0xce,0xea,0x00,0xc6,0x3e,0xfc,0xcd,
+0x81,0x41,0xe5,0x00,0xc9,0x41,0xe6,0x00,0xcb,0x46,0x54,0xdd,0x00,0xce,0xde,0x00,
+0xc6,0x81,0xe5,0x00,0xce,0xe6,0x00,0xc6,0x3e,0xfc,0xcd,0x81,0xdb,0xfb,0xcd,0x10,
+0xa6,0x5d,0xfc,0xcd,0x81,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,0x84,0x84,0x84,
+0x84,0x84,0x84,0x7c,0x83,0x00,0x35,0x7d,0x83,0x00,0x35,0x7e,0x83,0x0f,0x35,0x7f,
+0x83,0xff,0x35,0x3e,0xfc,0xcd,0x6c,0xae,0xa4,0x00,0x83,0x35,0x10,0xfd,0xcd,0x23,
+0xad,0x5b,0x2e,0xad,0x43,0xad,0x3e,0xfc,0xcd,0x2d,0xad,0x5b,0x5d,0xfc,0xcd,0x4e,
+0xad,0x0d,0x20,0x48,0xad,0x39,0xad,0x5b,0x5d,0xfc,0xcd,0xe5,0x00,0xce,0xe6,0x00,
+0xc6,0x10,0x26,0x4a,0xd8,0x00,0xc6,0x3e,0xfc,0xcd,0x68,0xae,0xa4,0x00,0x83,0x35,
+0x10,0xfd,0xcd,0x57,0xad,0x5b,0x62,0xad,0x6d,0xad,0x5e,0xad,0x5b,0x5d,0xfc,0xcd,
+0x75,0xad,0x64,0xae,0xa4,0x00,0x83,0x35,0x10,0xfd,0xcd,0x6f,0xad,0x5b,0x7a,0xad,
+0x41,0xeb,0x00,0xc9,0x41,0xec,0x00,0xcb,0x05,0xee,0x72,0x06,0x7b,0x3e,0xfc,0xcd,
+0xd4,0xdf,0xcd,0x5b,0x5d,0xfc,0xcd,0x05,0xee,0x72,0x06,0x7b,0x3e,0xfc,0xcd,0x60,
+0xae,0xa4,0x00,0x83,0x35,0x10,0xfd,0xcd,0xd4,0xdf,0xcd,0x5b,0xdc,0xdf,0xcd,0x41,
+0xeb,0x00,0xc9,0x41,0xec,0x00,0xcb,0x00,0xe0,0xcd,0xd4,0xdf,0xcd,0x5b,0x5d,0xfc,
+0xcd,0x00,0xe0,0xcd,0x5c,0xae,0xa4,0x00,0x83,0x35,0x5d,0xfc,0xcd,0x46,0x54,0xdd,
+0x00,0xce,0xde,0x00,0xc6,0x05,0xef,0x72,0x06,0x6b,0x4a,0x5a,0x01,0x26,0x4d,0xe9,
+0x00,0xce,0xea,0x00,0xc6,0x10,0x20,0x06,0x6b,0xea,0x00,0xc6,0x05,0x6b,0xe9,0x00,
+0xc6,0x0c,0x26,0x4a,0xd8,0x00,0xc6,0x88,0x88,0x88,0x88,0x88,0x88,0x81,0xe9,0x00,
+0xce,0xea,0x00,0xc6,0x3e,0xfc,0xcd,0x81,0x4d,0x41,0xdb,0x00,0xc9,0x41,0xdc,0x00,
+0xcb,0x81,0x02,0xa0,0x41,0xd9,0x00,0xc9,0x41,0xda,0x00,0xcb,0x81,0x41,0xe5,0x00,
+0xc9,0x41,0xe6,0x00,0xcb,0x46,0x54,0xdd,0x00,0xce,0xde,0x00,0xc6,0x81,0xe1,0x00,
+0xce,0xe2,0x00,0xc6,0x3e,0xfc,0xcd,0x81,0xe5,0x00,0xce,0xe6,0x00,0xc6,0x3e,0xfc,
+0xcd,0x81,0xdb,0xfb,0xcd,0x10,0xa6,0x5d,0xfc,0xcd,0x81,0xa4,0xb7,0x00,0xa9,0x41,
+0x01,0xab,0x81,0x8b,0x41,0x00,0xa9,0x41,0x0e,0xab,0x5b,0x98,0x83,0x00,0x35,0x99,
+0x83,0x00,0x35,0x9a,0x83,0x00,0x35,0x9b,0x83,0x18,0x35,0x3e,0xfc,0xcd,0x3c,0xae,
+0xa4,0x00,0x83,0x35,0x10,0xfd,0xcd,0x25,0xad,0x5b,0x30,0xad,0x4f,0xad,0x3e,0xfc,
+0xcd,0x2f,0xad,0x5b,0x5d,0xfc,0xcd,0x5a,0xad,0x0d,0x20,0x4a,0xad,0x3b,0xad,0x5b,
+0x5d,0xfc,0xcd,0xe5,0x00,0xce,0xe6,0x00,0xc6,0x10,0x26,0x4a,0xd8,0x00,0xc6,0x3e,
+0xfc,0xcd,0x38,0xae,0xa4,0x00,0x83,0x35,0x10,0xfd,0xcd,0x59,0xad,0x5b,0x64,0xad,
+0x6f,0xad,0x60,0xad,0x5b,0x5d,0xfc,0xcd,0x77,0xad,0x34,0xae,0xa4,0x00,0x83,0x35,
+0x10,0xfd,0xcd,0x71,0xad,0x5b,0x7c,0xad,0x41,0xeb,0x00,0xc9,0x41,0xec,0x00,0xcb,
+0x07,0xee,0x72,0x08,0x7b,0x3e,0xfc,0xcd,0x8e,0xde,0xcd,0x5b,0x5d,0xfc,0xcd,0x07,
+0xee,0x72,0x08,0x7b,0x3e,0xfc,0xcd,0x30,0xae,0xa4,0x00,0x83,0x35,0x10,0xfd,0xcd,
+0x8e,0xde,0xcd,0x5b,0x96,0xde,0xcd,0x41,0xeb,0x00,0xc9,0x41,0xec,0x00,0xcb,0xd9,
+0xde,0xcd,0x8e,0xde,0xcd,0x5b,0x5d,0xfc,0xcd,0xd9,0xde,0xcd,0x2c,0xae,0xa4,0x00,
+0x83,0x35,0x10,0xfd,0xcd,0x8e,0xde,0xcd,0x5b,0x96,0xde,0xcd,0x41,0xe7,0x00,0xc9,
+0x41,0xe8,0x00,0xcb,0x9f,0xde,0xcd,0x8e,0xde,0xcd,0x5b,0x5d,0xfc,0xcd,0x9f,0xde,
+0xcd,0x10,0xae,0xa4,0x00,0x83,0x35,0x10,0xfd,0xcd,0x8e,0xde,0xcd,0x5b,0x96,0xde,
+0xcd,0x4a,0x5a,0x01,0x26,0xcf,0xde,0xcd,0x0d,0xee,0x72,0x0e,0x7b,0x3e,0xfc,0xcd,
+0x8e,0xde,0xcd,0x5b,0x5d,0xfc,0xcd,0x5a,0x01,0x24,0xc4,0xde,0xcd,0xa9,0xde,0xcd,
+0x0c,0xae,0xa4,0x00,0x83,0x35,0x10,0xfd,0xcd,0x8e,0xde,0xcd,0x5b,0x96,0xde,0xcd,
+0x0d,0xee,0x72,0x0e,0x7b,0x3e,0xfc,0xcd,0x8e,0xde,0xcd,0x5b,0x5d,0xfc,0xcd,0x4a,
+0x5a,0x01,0x26,0x4d,0xa9,0xde,0xcd,0x08,0xae,0xa4,0x00,0x83,0x35,0x10,0xfd,0xcd,
+0x8e,0xde,0xcd,0x5b,0x96,0xde,0xcd,0x4a,0x5a,0x01,0x26,0xcf,0xde,0xcd,0x0d,0xee,
+0x72,0x0e,0x7b,0x3e,0xfc,0xcd,0x8e,0xde,0xcd,0x5b,0x5d,0xfc,0xcd,0x5a,0x01,0x24,
+0xc4,0xde,0xcd,0xa9,0xde,0xcd,0x04,0xae,0xa4,0x00,0x83,0x35,0x10,0xfd,0xcd,0x8e,
+0xde,0xcd,0x5b,0x96,0xde,0xcd,0x0d,0xee,0x72,0x0e,0x7b,0x3e,0xfc,0xcd,0x8e,0xde,
+0xcd,0x5b,0x5d,0xfc,0xcd,0x4a,0x5a,0x01,0x26,0x4d,0xa9,0xde,0xcd,0x40,0xae,0xa4,
+0x00,0x83,0x35,0xa0,0x3f,0xa1,0x3f,0xa2,0xb7,0x0f,0xa4,0xa2,0xb6,0x5d,0xfc,0xcd,
+0x05,0xee,0x72,0x06,0x7b,0x3e,0xfc,0xcd,0x28,0xae,0xa4,0x00,0x83,0x35,0xa0,0x3f,
+0xa1,0x3f,0xa2,0xb7,0x1f,0xa4,0xa2,0xb6,0x5d,0xfc,0xcd,0xdd,0x00,0xce,0xde,0x00,
+0xc6,0x78,0x84,0xc7,0x09,0x7b,0x79,0x84,0xc7,0x0a,0x7b,0x7a,0x84,0xc7,0x0b,0x7b,
+0x7b,0x84,0xc7,0x0c,0x7b,0x07,0xef,0x72,0x08,0x6b,0x4a,0x5a,0x01,0x26,0x4d,0xe9,
+0x00,0xce,0xea,0x00,0xc6,0x06,0x6b,0xe0,0x00,0xc6,0x05,0x6b,0xdf,0x00,0xc6,0x0a,
+0x6b,0x05,0xaa,0x0a,0x7b,0x20,0x20,0x08,0x6b,0xea,0x00,0xc6,0x07,0x6b,0xe9,0x00,
+0xc6,0x05,0xef,0x72,0x06,0x6b,0x59,0x48,0xdf,0x00,0xce,0xe0,0x00,0xc6,0x0a,0x6b,
+0x01,0xaa,0x0a,0x7b,0x1f,0x26,0x4a,0xd8,0x00,0xc6,0x09,0x6b,0x80,0xaa,0x09,0x7b,
+0x06,0x26,0x04,0xa1,0xfc,0x00,0xc6,0x09,0x6b,0x20,0xa6,0x0a,0x6b,0x0b,0x6b,0x0c,
+0x6b,0x4f,0x0d,0x6b,0x0e,0xef,0x72,0xe9,0x00,0xc9,0x41,0xea,0x00,0xcb,0xe3,0x00,
+0xce,0xe4,0x00,0xc6,0x8b,0x41,0x00,0xa2,0x41,0x0e,0xa0,0x5b,0x81,0x84,0x84,0x84,
+0x84,0x78,0x01,0x01,0x35,0x3e,0xfc,0xcd,0x78,0xae,0xa4,0x00,0x84,0x35,0x10,0xfd,
+0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0xa0,0xb7,0x03,0xa4,0xa0,0xb6,0xa1,
+0xb7,0xc0,0xa4,0xa1,0xb6,0xa2,0x3f,0xa3,0x3f,0xdb,0xfb,0xcd,0x16,0xa6,0xa0,0xb7,
+0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0x00,0xf3,0x00,0x55,0x01,0x6b,0xfc,0xa4,0x01,0x7b,
+0x02,0x6b,0x3f,0xa4,0x02,0x7b,0x01,0x6b,0x78,0x84,0xc6,0x02,0x6b,0x79,0x84,0xc6,
+0x03,0x6b,0x7a,0x84,0xc6,0x04,0x6b,0x7b,0x84,0xc6,0x3e,0xfc,0xcd,0x74,0xae,0xa4,
+0x00,0x84,0x35,0x5d,0xfc,0xcd,0xd6,0x00,0xce,0xd7,0x00,0xc6,0x3e,0xfc,0xcd,0x70,
+0xae,0xa4,0x00,0x84,0x35,0x5d,0xfc,0xcd,0xd4,0x00,0xce,0xd5,0x00,0xc6,0x3e,0xfc,
+0xcd,0x6c,0xae,0xa4,0x00,0x84,0x35,0x5d,0xfc,0xcd,0xd2,0x00,0xce,0xd3,0x00,0xc6,
+0x3e,0xfc,0xcd,0x68,0xae,0xa4,0x00,0x84,0x35,0x5d,0xfc,0xcd,0xd0,0x00,0xce,0xd1,
+0x00,0xc6,0x3e,0xfc,0xcd,0x64,0xae,0xa4,0x00,0x84,0x35,0x5d,0xfc,0xcd,0xce,0x00,
+0xce,0xcf,0x00,0xc6,0x12,0x20,0x64,0x84,0x00,0x35,0x65,0x84,0x00,0x35,0x66,0x84,
+0x02,0x35,0x67,0x84,0xcb,0x35,0x12,0x25,0x02,0xa2,0xce,0x00,0xc6,0xcb,0xa0,0xcf,
+0x00,0xc6,0x1e,0x26,0x02,0xa1,0x7d,0x01,0xc6,0x25,0x26,0x03,0xa1,0x01,0x01,0xc6,
+0x3e,0xfc,0xcd,0x60,0xae,0xa4,0x00,0x84,0x35,0x5d,0xfc,0xcd,0xcc,0x00,0xce,0xcd,
+0x00,0xc6,0x3e,0xfc,0xcd,0x5c,0xae,0xa4,0x00,0x84,0x35,0x5d,0xfc,0xcd,0xca,0x00,
+0xce,0xcb,0x00,0xc6,0x3e,0xfc,0xcd,0x58,0xae,0xa4,0x00,0x84,0x35,0x5d,0xfc,0xcd,
+0xc8,0x00,0xce,0xc9,0x00,0xc6,0x88,0x88,0x88,0x88,0x81,0xa4,0xc6,0x92,0xa5,0xbf,
+0xa4,0xb7,0x81,0xa4,0xd6,0x92,0xa5,0x3f,0xa4,0xb7,0x81,0x84,0xd6,0x00,0xcf,0xce,
+0x00,0xce,0xd7,0x00,0xc7,0xcf,0x00,0xc6,0xce,0x00,0xcf,0xcf,0x00,0xc7,0x4a,0x5a,
+0x01,0x26,0x4d,0x59,0x48,0xf6,0x00,0xce,0xf7,0x00,0xc6,0x0b,0x20,0x0e,0x26,0x4d,
+0xf6,0x00,0xce,0xf7,0x00,0xc6,0x0b,0x26,0x4a,0xd8,0x00,0xc6,0xd4,0x00,0xcf,0xcc,
+0x00,0xce,0xd5,0x00,0xc7,0xcd,0x00,0xc6,0xcd,0x00,0x5f,0x72,0xcc,0x00,0x5f,0x72,
+0xd2,0x00,0xcf,0xca,0x00,0xce,0xd3,0x00,0xc7,0xcb,0x00,0xc6,0xca,0x00,0xcf,0xcb,
+0x00,0xc7,0x4a,0x5a,0x01,0x26,0x4d,0xfa,0x26,0x5a,0x90,0x46,0x54,0x06,0x27,0xf3,
+0x00,0xce,0x90,0xf4,0x00,0xce,0xf5,0x00,0xc6,0xd0,0x00,0xcf,0xc8,0x00,0xce,0xd1,
+0x00,0xc7,0xc9,0x00,0xc6,0xc9,0x00,0x5f,0x72,0xc8,0x00,0x5f,0x72,0xe3,0x00,0x5f,
+0x72,0xe4,0x00,0x23,0x35,0x08,0x26,0x03,0xa1,0x7d,0x01,0xc6,0x0f,0x26,0x03,0xa1,
+0xf6,0x00,0xdb,0x00,0x55,0xf7,0x00,0xdc,0x00,0x55,0xfa,0x00,0xdf,0x00,0x55,0xfb,
+0x00,0xe0,0x00,0x55,0xf4,0x00,0xd9,0x00,0x55,0xf5,0x00,0xda,0x00,0x55,0xf8,0x00,
+0xdd,0x00,0x55,0xf9,0x00,0xde,0x00,0x55,0x09,0xd9,0xcc,0x1e,0xdb,0xcd,0xd5,0xa9,
+0x41,0x7b,0xab,0x52,0x1c,0xae,0x01,0x7b,0x3e,0xfc,0xcd,0xef,0xae,0xa4,0x00,0x00,
+0x35,0x95,0xfb,0xcd,0xa4,0xb7,0xd5,0xa9,0x41,0x77,0xab,0x52,0x1c,0xae,0x01,0x7b,
+0xee,0x00,0xc7,0x1e,0xdb,0xcd,0xd5,0xa9,0x41,0x76,0xab,0x52,0x1c,0xae,0x01,0x7b,
+0xed,0x00,0xc7,0x1e,0xdb,0xcd,0xd5,0xa9,0x41,0x75,0xab,0x52,0x1c,0xae,0x01,0x7b,
+0xec,0x00,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,0xeb,0x00,0xc7,0x16,0xdb,0xcd,0xd5,0xa9,
+0x41,0x73,0xab,0x52,0x1c,0xae,0x01,0x7b,0xe9,0x00,0x5f,0x72,0xea,0x00,0x01,0x35,
+0xe8,0x00,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,0xe7,0x00,0xc7,0x16,0xdb,0xcd,0xd5,0xa9,
+0x41,0x6f,0xab,0x52,0x1c,0xae,0x01,0x7b,0xe6,0x00,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,
+0xe5,0x00,0xc7,0x16,0xdb,0xcd,0xd5,0xa9,0x41,0x6d,0xab,0x52,0x1c,0xae,0x01,0x7b,
+0xe4,0x00,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,0xe3,0x00,0xc7,0x16,0xdb,0xcd,0xd5,0xa9,
+0x41,0x6b,0xab,0x52,0x1c,0xae,0x01,0x7b,0xe2,0x00,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,
+0xe1,0x00,0xc7,0x16,0xdb,0xcd,0xd5,0xa9,0x41,0x69,0xab,0x52,0x1c,0xae,0x01,0x7b,
+0xe0,0x00,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,0xdf,0x00,0xc7,0x16,0xdb,0xcd,0xd5,0xa9,
+0x41,0x67,0xab,0x52,0x1c,0xae,0x01,0x7b,0xde,0x00,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,
+0xdd,0x00,0xc7,0x16,0xdb,0xcd,0xd5,0xa9,0x41,0x65,0xab,0x52,0x1c,0xae,0x01,0x7b,
+0xdc,0x00,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,0xdb,0x00,0xc7,0x16,0xdb,0xcd,0xd5,0xa9,
+0x41,0x63,0xab,0x52,0x1c,0xae,0x01,0x7b,0xda,0x00,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,
+0xd9,0x00,0xc7,0x16,0xdb,0xcd,0xd5,0xa9,0x41,0x61,0xab,0x52,0x1c,0xae,0x01,0x7b,
+0xd8,0x00,0xc7,0x1e,0xdb,0xcd,0xd5,0xa9,0x41,0x60,0xab,0x52,0x1c,0xae,0x01,0x7b,
+0x58,0xda,0xcc,0x80,0xda,0xcc,0x03,0x27,0x02,0xa1,0x58,0xda,0xcc,0x03,0x26,0x03,
+0xa1,0x01,0x01,0xc6,0xf3,0x00,0xc7,0x29,0xb6,0xef,0x00,0x2a,0x00,0x55,0xf0,0x00,
+0x2b,0x00,0x55,0xf1,0x00,0x2c,0x00,0x55,0xf2,0x00,0x2d,0x00,0x55,0xed,0x00,0xc7,
+0x13,0xb6,0x13,0xb6,0xeb,0x00,0xcf,0x22,0xbe,0xec,0x00,0xc7,0x23,0xb6,0xe9,0x00,
+0xcf,0x20,0xbe,0xea,0x00,0xc7,0x21,0xb6,0xe7,0x00,0xcf,0x1e,0xbe,0xe8,0x00,0xc7,
+0x1f,0xb6,0xe5,0x00,0xcf,0x1c,0xbe,0xe6,0x00,0xc7,0x1d,0xb6,0xe3,0x00,0xcf,0x26,
+0xbe,0xe4,0x00,0xc7,0x27,0xb6,0xe1,0x00,0xcf,0x24,0xbe,0xe2,0x00,0xc7,0x25,0xb6,
+0xdf,0x00,0xcf,0x18,0xbe,0xe0,0x00,0xc7,0x19,0xb6,0xdd,0x00,0xcf,0x14,0xbe,0xde,
+0x00,0xc7,0x15,0xb6,0xdb,0x00,0xcf,0x1a,0xbe,0xdc,0x00,0xc7,0x1b,0xb6,0xd9,0x00,
+0xcf,0x16,0xbe,0xda,0x00,0xc7,0x17,0xb6,0xd8,0x00,0xc7,0x28,0xb6,0x20,0xd9,0xcc,
+0x03,0x24,0x1d,0xa1,0x11,0xb6,0x09,0x27,0x11,0x3d,0x01,0x6b,0x4a,0x11,0xb6,0x88,
+0x00,0xf0,0x70,0x1c,0x05,0x01,0x01,0x03,0x00,0x03,0x00,0x8f,0x00,0x46,0x00,0x1b,
+0x00,0xaa,0x01,0x1e,0x03,0x00,0x07,0x00,0x03,0x50,0x05,0x01,0x00,0x60,0xa0,0x18,
+0x05,0x01,0x01,0x06,0x00,0x03,0x00,0x70,0x00,0x40,0x00,0x18,0x00,0xb0,0x01,0x1b,
+0x03,0x00,0x07,0x00,0x03,0x50,0x05,0x01,0x00,0xe0,0x1b,0xfa,0x04,0x01,0x00,0x06,
+0x00,0x03,0x00,0x80,0x00,0x48,0x00,0x1c,0x00,0x90,0x01,0x3f,0x03,0x90,0x06,0x20,
+0x03,0x00,0x05,0x01,0x00,0xc0,0x5f,0x3b,0x04,0x00,0x01,0x06,0x00,0x03,0x00,0x20,
+0x00,0x30,0x00,0x14,0x00,0xa0,0x00,0x37,0x03,0xa0,0x05,0x20,0x03,0x00,0x05,0x01,
+0x00,0xe0,0x12,0xbd,0x04,0x01,0x00,0x07,0x00,0x03,0x00,0x80,0x00,0x40,0x00,0x1b,
+0x00,0x80,0x01,0x1e,0x03,0x80,0x06,0x00,0x03,0x00,0x05,0x01,0x00,0x90,0x69,0x11,
+0x04,0x00,0x01,0x07,0x00,0x03,0x00,0x20,0x00,0x30,0x00,0x13,0x00,0xa0,0x00,0x16,
+0x03,0xa0,0x05,0x00,0x03,0x00,0x05,0x01,0x00,0x40,0xd2,0xdf,0x03,0x00,0x00,0x06,
+0x00,0x03,0x00,0x88,0x00,0x18,0x00,0x23,0x00,0x40,0x01,0x26,0x03,0x40,0x05,0x00,
+0x03,0x00,0x04,0x01,0x00,0xf0,0xfb,0x02,0x02,0x01,0x01,0x08,0x00,0x06,0x00,0x70,
+0x00,0x10,0x00,0x1f,0x00,0xf0,0x00,0x05,0x02,0x40,0x04,0xe0,0x01,0x50,0x03,0x01,
+0x00,0x00,0x5a,0x62,0x02,0x01,0x01,0x04,0x00,0x01,0x00,0x80,0x00,0x28,0x00,0x1b,
+0x00,0x00,0x01,0x74,0x02,0x20,0x04,0x58,0x02,0x20,0x03,0x01,0x00,0x10,0xf7,0x6c,
+0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x28,0x00,0xe0,0x06,0x19,0x00,0xe4,0x07,0xee,
+0x02,0xe4,0x0c,0xd0,0x02,0x00,0x05,0x01,0x00,0x10,0xf7,0x6c,0x04,0x01,0x01,0x05,
+0x00,0x01,0x00,0x28,0x00,0x74,0x09,0x19,0x00,0x78,0x0a,0xee,0x02,0x78,0x0f,0xd0,
+0x02,0x00,0x05,0x01,0x00,0x40,0x5f,0x8a,0x03,0x01,0x01,0x05,0x00,0x01,0x00,0x28,
+0x00,0xe0,0x06,0x19,0x00,0xe4,0x07,0xee,0x02,0xe4,0x0c,0xd0,0x02,0x00,0x05,0x01,
+0x00,0x10,0xf7,0x6c,0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x2c,0x00,0x58,0x00,0x29,
+0x00,0x18,0x01,0x65,0x04,0x98,0x08,0x38,0x04,0x80,0x07,0x01,0x00,0x10,0xf7,0x6c,
+0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x2c,0x00,0x10,0x02,0x29,0x00,0xd0,0x02,0x65,
+0x04,0x50,0x0a,0x38,0x04,0x80,0x07,0x01,0x00,0x10,0xf7,0x6c,0x04,0x01,0x01,0x05,
+0x00,0x01,0x00,0x2c,0x00,0x7e,0x02,0x29,0x00,0x3e,0x03,0x65,0x04,0xbe,0x0a,0x38,
+0x04,0x80,0x07,0x01,0x00,0x20,0xee,0xd9,0x08,0x01,0x01,0x05,0x00,0x01,0x00,0x2c,
+0x00,0x10,0x02,0x29,0x00,0xd0,0x02,0x65,0x04,0x50,0x0a,0x38,0x04,0x80,0x07,0x01,
+0x00,0x80,0xf9,0x37,0x03,0x00,0x00,0x05,0x00,0x01,0x00,0x80,0x00,0x18,0x00,0x2c,
+0x00,0x20,0x01,0x71,0x02,0xc0,0x06,0x40,0x02,0xa0,0x05,0x01,0x01,0xc0,0xfc,0x9b,
+0x01,0x00,0x00,0x03,0x00,0x01,0x00,0x7e,0x00,0x18,0x00,0x16,0x00,0x20,0x01,0x71,
+0x02,0xc0,0x06,0x20,0x01,0xa0,0x05,0x00,0x00,0x10,0xf7,0x6c,0x04,0x01,0x01,0x05,
+0x00,0x01,0x00,0x2c,0x00,0x10,0x02,0x14,0x00,0xd0,0x02,0x65,0x04,0x50,0x0a,0x1c,
+0x02,0x80,0x07,0x00,0x00,0x10,0xf7,0x6c,0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x28,
+0x00,0xb8,0x01,0x19,0x00,0xbc,0x02,0xee,0x02,0xbc,0x07,0xd0,0x02,0x00,0x05,0x01,
+0x00,0xc0,0xfc,0x9b,0x01,0x00,0x00,0x05,0x00,0x01,0x00,0x40,0x00,0x0c,0x00,0x2c,
+0x00,0x90,0x00,0x71,0x02,0x60,0x03,0x40,0x02,0xd0,0x02,0x01,0x00,0x20,0xee,0xd9,
+0x08,0x01,0x01,0x05,0x00,0x01,0x00,0x2c,0x00,0x58,0x00,0x29,0x00,0x18,0x01,0x65,
+0x04,0x98,0x08,0x38,0x04,0x80,0x07,0x01,0x00,0x80,0xf9,0x37,0x03,0x00,0x00,0x06,
+0x00,0x07,0x00,0x7c,0x00,0x20,0x00,0x24,0x00,0x14,0x01,0x0d,0x02,0xb4,0x06,0xe0,
+0x01,0xa0,0x05,0x01,0x01,0xc0,0xfc,0x9b,0x01,0x00,0x00,0x03,0x00,0x04,0x00,0x7c,
+0x00,0x26,0x00,0x12,0x00,0x14,0x01,0x0d,0x02,0xb4,0x06,0xf0,0x00,0xa0,0x05,0x00,
+0x00,0x10,0xf7,0x6c,0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x2c,0x00,0x58,0x00,0x14,
+0x00,0x18,0x01,0x65,0x04,0x98,0x08,0x1c,0x02,0x80,0x07,0x00,0x00,0x10,0xf7,0x6c,
+0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x28,0x00,0x6e,0x00,0x19,0x00,0x72,0x01,0xee,
+0x02,0x72,0x06,0xd0,0x02,0x00,0x05,0x01,0x00,0xc0,0xfc,0x9b,0x01,0x00,0x00,0x06,
+0x00,0x07,0x00,0x3e,0x00,0x10,0x00,0x24,0x00,0x8a,0x00,0x0d,0x02,0x5a,0x03,0xe0,
+0x01,0xd0,0x02,0x01,0x00,0x80,0x85,0x80,0x01,0x00,0x00,0x02,0x00,0x01,0x00,0x60,
+0x00,0x10,0x00,0x23,0x00,0xa0,0x00,0x0d,0x02,0x20,0x03,0xe0,0x01,0x80,0x02,0x01,
+0x81,0x84,0x8b,0x41,0x00,0xa9,0x41,0x08,0xab,0x5b,0x09,0x6b,0x01,0x6b,0x4f,0x01,
+0x20,0x01,0xa6,0x04,0x26,0x50,0x01,0xc1,0x05,0x7b,0x0b,0x26,0x04,0xe1,0x72,0x51,
+0x01,0xc6,0x08,0x27,0x50,0x01,0xc6,0xb7,0x26,0x95,0xfc,0xcd,0xa4,0xb7,0x00,0xa9,
+0x41,0x02,0xab,0x5b,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x06,0xab,0x5b,0x06,
+0x6b,0x30,0x48,0xc6,0x07,0x6b,0x31,0x48,0xc6,0x08,0x6b,0x32,0x48,0xc6,0x09,0x6b,
+0x33,0x48,0xc6,0x84,0x84,0xd7,0xc7,0xcd,0x74,0xae,0x08,0xa6,0x02,0x4b,0x00,0x4b,
+0x02,0x6b,0x06,0x7b,0x03,0x6b,0x07,0x7b,0x04,0x6b,0x08,0x7b,0x05,0x6b,0x09,0x7b,
+0x06,0x6b,0x30,0x48,0xc6,0x07,0x6b,0x31,0x48,0xc6,0x08,0x6b,0x32,0x48,0xc6,0x09,
+0x6b,0x33,0x48,0xc6,0x01,0x6b,0x4f,0x8b,0x41,0x00,0xa2,0x41,0x09,0xa0,0x5b,0xab,
+0x20,0x80,0xaa,0x17,0xb7,0x02,0x7b,0x84,0x84,0xd7,0xc7,0xcd,0x74,0xae,0x20,0xa6,
+0x14,0x4b,0x88,0x07,0xab,0x01,0x7b,0xf0,0x25,0x05,0xa1,0x03,0x6b,0x4c,0x9f,0x18,
+0xe7,0x50,0x01,0xd6,0x03,0xee,0x72,0x03,0x6b,0x12,0x26,0x4a,0x02,0x7b,0x84,0x84,
+0xd7,0xc7,0xcd,0x74,0xae,0x43,0xa6,0x88,0x02,0x7b,0x07,0x4b,0x10,0x27,0x02,0x7b,
+0x01,0x6b,0x52,0x05,0xae,0x05,0x24,0x14,0xa1,0x02,0x6b,0x7f,0xa4,0x50,0x01,0xc6,
+0x81,0x85,0x85,0x85,0x4f,0x05,0x51,0x01,0x07,0x72,0x05,0x20,0x02,0x50,0x01,0x0f,
+0x72,0x84,0x84,0xd7,0xc7,0xcd,0x74,0xae,0x41,0xa6,0x02,0x4b,0x00,0x4b,0x19,0x26,
+0x60,0xa1,0x60,0xa4,0x50,0x01,0xc6,0x84,0x84,0xd7,0xc7,0xcd,0x74,0xae,0x40,0xa6,
+0x01,0x4b,0x00,0x4b,0x01,0x6b,0x64,0xa6,0x88,0x88,0x88,0x81,0x31,0x01,0xc6,0x31,
+0x01,0x01,0x35,0x04,0x50,0x01,0x0d,0x72,0x84,0x84,0xd7,0xc7,0xcd,0x74,0xae,0x40,
+0xa6,0x01,0x4b,0x00,0x4b,0x31,0x01,0x5f,0x72,0x81,0x85,0x9a,0x3e,0xfc,0xcd,0x14,
+0xae,0xa4,0x00,0x48,0x35,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0x00,0x34,0x01,
+0x55,0x10,0x48,0x35,0x01,0x55,0x11,0x48,0x36,0x01,0x55,0x12,0x48,0x37,0x01,0x55,
+0x13,0x48,0x38,0x01,0x55,0x9b,0xcd,0x25,0x05,0xa1,0x01,0x6b,0x4c,0x01,0x7b,0x0a,
+0xfd,0xcd,0x35,0xae,0xa4,0x00,0x01,0x35,0xdb,0xfb,0xcd,0x48,0x48,0x48,0x9f,0xa0,
+0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x50,0x01,0xd6,0x01,0xee,0x72,0x1f,0x20,
+0x34,0x01,0x54,0x01,0x55,0x07,0x26,0x04,0xa1,0x01,0x6b,0x4f,0x84,0x84,0x35,0x01,
+0x5f,0x72,0x36,0x01,0x5f,0x72,0x37,0x01,0x5f,0x72,0x38,0x01,0x5f,0x72,0xd7,0xc7,
+0xcd,0x74,0xae,0x4f,0x05,0x4b,0x00,0x4b,0x88,0x81,0x84,0x8b,0x41,0x00,0xa9,0x41,
+0x08,0xab,0x5b,0x09,0x6b,0x01,0x6b,0x85,0x85,0xb2,0xc8,0xcd,0x74,0xae,0x10,0xa6,
+0x00,0x4b,0x05,0x4b,0x54,0x01,0xc7,0x05,0x7b,0x02,0x6b,0x48,0x01,0xc6,0x03,0x6b,
+0x49,0x01,0xc6,0x04,0x6b,0x4a,0x01,0xc6,0x05,0x6b,0x4b,0x01,0xc6,0x53,0x01,0xc7,
+0x02,0x7b,0x52,0x01,0xc7,0x03,0x7b,0x51,0x01,0xc7,0x04,0x7b,0x50,0x01,0xc7,0x05,
+0x7b,0x02,0x6b,0x44,0x01,0xc6,0x03,0x6b,0x45,0x01,0xc6,0x04,0x6b,0x46,0x01,0xc6,
+0x05,0x6b,0x47,0x01,0xc6,0x01,0x6b,0x85,0x85,0xb2,0xc8,0xcd,0x74,0xae,0x18,0xa6,
+0x00,0x4b,0x08,0x4b,0x57,0x01,0xc7,0x06,0x7b,0x56,0x01,0xc7,0x07,0x7b,0x55,0x01,
+0xc7,0x08,0x7b,0x54,0x01,0xc7,0x09,0x7b,0x06,0x6b,0x1c,0x48,0xc6,0x07,0x6b,0x1d,
+0x48,0xc6,0x08,0x6b,0x1e,0x48,0xc6,0x09,0x6b,0x1f,0x48,0xc6,0x53,0x01,0xc7,0x06,
+0x7b,0x52,0x01,0xc7,0x07,0x7b,0x51,0x01,0xc7,0x08,0x7b,0x50,0x01,0xc7,0x09,0x7b,
+0x06,0x6b,0x18,0x48,0xc6,0x07,0x6b,0x19,0x48,0xc6,0x08,0x6b,0x1a,0x48,0xc6,0x09,
+0x6b,0x1b,0x48,0xc6,0x01,0x6b,0x4f,0x8b,0x41,0x00,0xa2,0x41,0x09,0xa0,0x5b,0x81,
+0x85,0x85,0x85,0x85,0x85,0x01,0x7b,0x01,0x6b,0x01,0xa6,0x04,0x26,0x14,0xa1,0x02,
+0x7b,0x0a,0x26,0x14,0xa1,0x03,0x7b,0xd1,0x25,0x05,0xa1,0x05,0x6b,0x4c,0x05,0x7b,
+0xdd,0x25,0x08,0xa1,0x04,0x6b,0x4c,0x04,0x7b,0x50,0x01,0x44,0x72,0x02,0x6b,0x4c,
+0x02,0x7b,0x05,0x20,0x03,0x6b,0x4c,0x03,0x7b,0x07,0x26,0x01,0xa4,0x50,0x01,0xd6,
+0x05,0xee,0x72,0x04,0x6b,0x4f,0x05,0x6b,0x4f,0x44,0x20,0x4f,0x03,0x27,0x85,0x85,
+0x4d,0xd7,0xc7,0xcd,0x74,0xae,0x05,0x4b,0x00,0x4b,0x9a,0x14,0x48,0x48,0x01,0x55,
+0x15,0x48,0x49,0x01,0x55,0x16,0x48,0x4a,0x01,0x55,0x17,0x48,0x4b,0x01,0x55,0x10,
+0x48,0x44,0x01,0x55,0x11,0x48,0x45,0x01,0x55,0x12,0x48,0x46,0x01,0x55,0x13,0x48,
+0x47,0x01,0x55,0x9b,0x03,0x6b,0x02,0x6b,0x01,0x6b,0x4f,0x88,0x88,0x88,0x88,0x88,
+0x81,0xa4,0x00,0x48,0x35,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x81,0x85,
+0x85,0x85,0x85,0x01,0x7b,0x9a,0x3e,0xfc,0xcd,0x0c,0xae,0x0d,0xad,0x03,0x7b,0x9b,
+0x01,0x6b,0x01,0xa6,0x04,0x26,0x02,0x7b,0x04,0x26,0x4a,0x03,0x7b,0xee,0x26,0x02,
+0x7b,0x06,0x26,0x03,0x7b,0x02,0x6b,0x4a,0x02,0x7b,0x03,0x6b,0x0f,0x48,0xc6,0x0a,
+0x20,0x9a,0x3e,0xfc,0xcd,0x5f,0x38,0xad,0x04,0x7b,0x9b,0x02,0x6b,0x32,0xa6,0x01,
+0x6b,0x03,0x6b,0x4f,0x88,0x88,0x88,0x88,0x81,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,
+0x41,0x05,0xab,0x81,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x9a,0x3e,0xfc,0xcd,
+0x04,0xae,0xa4,0x00,0x48,0x35,0xa3,0x15,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,
+0xb7,0x03,0xaa,0x3f,0xa4,0x08,0x7b,0x9b,0x05,0x6b,0x04,0x48,0xc6,0x06,0x6b,0x05,
+0x48,0xc6,0x07,0x6b,0x06,0x48,0xc6,0x08,0x6b,0x07,0x48,0xc6,0x9a,0x3e,0xfc,0xcd,
+0x5f,0xa4,0x00,0x40,0x35,0x10,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,
+0xa3,0x14,0x4f,0xad,0x5b,0x3e,0xfc,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,
+0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0x00,0x2e,0x01,0x55,0x9b,0x05,0x6b,0x00,
+0x40,0xc6,0x06,0x6b,0x01,0x40,0xc6,0x07,0x6b,0x02,0x40,0xc6,0x08,0x6b,0x03,0x40,
+0xc6,0x9a,0x3e,0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0xa3,0x1a,0xa3,0x19,0xed,
+0xd1,0xcd,0x5b,0x9b,0x05,0x6b,0xb4,0x84,0xc6,0x06,0x6b,0xb5,0x84,0xc6,0x07,0x6b,
+0xb6,0x84,0xc6,0x08,0x6b,0xb7,0x84,0xc6,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
+0x81,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,0x84,0x84,0x84,0x84,
+0x9a,0x3e,0xfc,0xcd,0x04,0xae,0xa4,0x00,0x48,0x35,0xa3,0x14,0x11,0xad,0x5b,0x9b,
+0x01,0x6b,0x04,0x48,0xc6,0x02,0x6b,0x05,0x48,0xc6,0x03,0x6b,0x06,0x48,0xc6,0x04,
+0x6b,0x07,0x48,0xc6,0x9a,0x3e,0xfc,0xcd,0x5f,0xa4,0x00,0x40,0x35,0xa3,0x15,0x34,
+0xad,0x5b,0x9b,0x01,0x6b,0x00,0x40,0xc6,0x02,0x6b,0x01,0x40,0xc6,0x03,0x6b,0x02,
+0x40,0xc6,0x04,0x6b,0x03,0x40,0xc6,0x88,0x88,0x88,0x88,0x81,0x85,0x85,0x85,0x85,
+0x4f,0x9a,0x3e,0xfc,0xcd,0x04,0xae,0xa4,0x00,0x48,0x35,0xa0,0x3f,0xa1,0x3f,0xa2,
+0x3f,0xa3,0xb7,0x30,0xa4,0xa3,0xb6,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,
+0x04,0x7b,0x9b,0x01,0x6b,0x04,0x48,0xc6,0x02,0x6b,0x05,0x48,0xc6,0x03,0x6b,0x06,
+0x48,0xc6,0x04,0x6b,0x07,0x48,0xc6,0x9a,0x3e,0xfc,0xcd,0x5f,0xa4,0x00,0x40,0x35,
+0xa3,0x15,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0x9b,0x01,0x6b,
+0x00,0x40,0xc6,0x02,0x6b,0x01,0x40,0xc6,0x03,0x6b,0x02,0x40,0xc6,0x04,0x6b,0x03,
+0x40,0xc6,0x88,0x88,0x88,0x88,0x81,0x01,0xa6,0x15,0x00,0xde,0x35,0x14,0x00,0xc0,
+0x35,0x13,0x00,0xad,0x35,0x12,0x00,0xde,0x35,0x65,0xc0,0xcd,0x81,0x84,0x84,0x84,
+0x84,0x84,0x25,0xcf,0xcd,0xac,0x25,0x10,0xa1,0x04,0x6b,0x4c,0x04,0x7b,0xc2,0x25,
+0x08,0xa1,0x05,0x6b,0x4c,0x05,0x7b,0x6d,0xcf,0xcd,0x03,0x27,0x5d,0x03,0x26,0x4d,
+0x41,0x01,0xe4,0x72,0x41,0x02,0xe4,0x72,0xfa,0x26,0x5a,0x90,0x59,0x48,0x06,0x27,
+0x05,0xe6,0x72,0x01,0xa6,0x01,0xef,0x72,0x02,0x6b,0x5f,0x03,0x7b,0x92,0xcf,0xcd,
+0x03,0x20,0x9a,0xad,0x04,0x26,0x05,0x7b,0x08,0x26,0x04,0x7b,0x05,0x6b,0x4f,0x03,
+0x6b,0x12,0xe6,0x97,0x04,0xe0,0x72,0x0f,0xa6,0x04,0x6b,0x4f,0xf5,0x25,0x10,0xa1,
+0x04,0x6b,0x4c,0x04,0x7b,0x97,0xad,0x04,0x6b,0x4f,0x6d,0xcf,0xcd,0x25,0xcf,0xcd,
+0x4f,0xcf,0xcd,0x88,0x88,0x88,0x88,0x88,0x81,0xb3,0x84,0x00,0x35,0xb0,0x84,0x00,
+0x35,0xb1,0x84,0x00,0x35,0x81,0xb0,0x84,0x00,0x35,0xb1,0x84,0x00,0x35,0xb2,0x84,
+0x00,0x35,0x0d,0xad,0xb2,0x84,0x03,0x35,0x13,0xad,0xb2,0x84,0x02,0x35,0x19,0xad,
+0xb2,0x84,0x00,0x35,0xb3,0x84,0x00,0x35,0x81,0xb0,0x84,0x00,0x35,0xb1,0x84,0x00,
+0x35,0xb2,0x84,0x00,0x35,0xb3,0x84,0x00,0x35,0x81,0x01,0xad,0xb0,0x84,0x00,0x35,
+0xb1,0x84,0x00,0x35,0xb2,0x84,0x01,0x35,0xb3,0x84,0x00,0x35,0x13,0xad,0x81,0x64,
+0xa6,0xb0,0x84,0x00,0x35,0xb1,0x84,0x00,0x35,0x78,0xc9,0xcc,0x03,0xad,0xb2,0x84,
+0x00,0x35,0xb3,0x84,0x00,0x35,0x78,0xc9,0xcd,0x10,0xad,0xb2,0x84,0x04,0x35,0xb3,
+0x84,0x00,0x35,0x81,0xad,0x84,0x00,0x35,0xae,0x84,0x00,0x35,0xaf,0x84,0x00,0x35,
+0x81,0xac,0x84,0x00,0x35,0x05,0xad,0x81,0xac,0x84,0x80,0x35,0x0c,0xad,0x07,0x27,
+0x4d,0x78,0xc9,0xcc,0x64,0xa6,0xb0,0x84,0x00,0x35,0xb1,0x84,0x00,0x35,0xb2,0x84,
+0x00,0x35,0xb3,0x84,0x00,0x35,0x78,0xc9,0xcd,0x0a,0xa6,0xb0,0x84,0x00,0x35,0xb1,
+0x84,0x00,0x35,0xb2,0x84,0x10,0x35,0xb3,0x84,0x00,0x35,0x81,0x84,0x84,0x84,0x84,
+0x78,0x01,0x01,0x35,0x3e,0xfc,0xcd,0x5f,0xa4,0x00,0x84,0x35,0xa0,0x1a,0x56,0xfd,
+0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0x01,0x6b,0x00,0x84,0xc6,0x02,0x6b,
+0x01,0x84,0xc6,0x03,0x6b,0x02,0x84,0xc6,0x04,0x6b,0x03,0x84,0xc6,0x88,0x88,0x88,
+0x88,0x81,0x84,0x84,0x84,0x84,0x3e,0xfc,0xcd,0x5f,0xa4,0x00,0x84,0x35,0xa0,0x1b,
+0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0x01,0x6b,0x00,0x84,0xc6,
+0x02,0x6b,0x01,0x84,0xc6,0x03,0x6b,0x02,0x84,0xc6,0x04,0x6b,0x03,0x84,0xc6,0x88,
+0x88,0x88,0x88,0x81,0x3e,0xfc,0xcd,0x78,0xae,0xa4,0x00,0x84,0x35,0x81,0x56,0xfd,
+0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,0x84,0x84,0x84,0x84,0x10,0xad,0xa3,
+0x1d,0x09,0xad,0x5b,0x17,0xad,0xa3,0x1c,0x10,0xad,0x5b,0x01,0x6b,0x78,0x84,0xc6,
+0x02,0x6b,0x79,0x84,0xc6,0x03,0x6b,0x7a,0x84,0xc6,0x04,0x6b,0x7b,0x84,0xc6,0x88,
+0x88,0x88,0x88,0x81,0x5d,0xfc,0xcd,0xbc,0x00,0xce,0xbd,0x00,0xc6,0x81,0x84,0x84,
+0x84,0x84,0xa0,0x84,0xc7,0x01,0x7b,0xa1,0x84,0xc7,0x02,0x7b,0xa2,0x84,0xc7,0x03,
+0x7b,0xa3,0x84,0xc7,0x04,0x7b,0x03,0x6b,0x80,0xaa,0x03,0x7b,0x04,0x6b,0x06,0xaa,
+0x04,0x7b,0x0c,0x20,0x0a,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0xa2,
+0x1e,0x34,0xad,0x11,0x24,0x00,0xa2,0xbc,0x00,0xc6,0x06,0xa0,0xbd,0x00,0xc6,0x0c,
+0x27,0x02,0x01,0xc6,0x22,0x25,0x02,0xa1,0xbb,0x00,0xc6,0x29,0x26,0x4a,0x01,0x01,
+0xc6,0x03,0x6b,0x80,0xa4,0x03,0x7b,0x04,0x6b,0x4f,0x01,0x6b,0xa0,0x84,0xc6,0x02,
+0x6b,0xa1,0x84,0xc6,0x03,0x6b,0xa2,0x84,0xc6,0x04,0x6b,0xa3,0x84,0xc6,0x6c,0x25,
+0x02,0xa1,0xbb,0x00,0xc6,0x73,0x26,0x4a,0x01,0x01,0xc6,0x0d,0x27,0x4a,0x02,0x01,
+0xc6,0x3e,0xfc,0xcd,0x78,0xae,0xa4,0x00,0x84,0x35,0xa0,0x1c,0x56,0xfd,0xcd,0xa4,
+0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0x01,0x6b,0x78,0x84,0xc6,0x02,0x6b,0x79,0x84,
+0xc6,0x03,0x6b,0x7a,0x84,0xc6,0x04,0x6b,0x7b,0x84,0xc6,0x48,0x83,0x00,0x35,0x49,
+0x83,0x00,0x35,0x4a,0x83,0x00,0x35,0x4b,0x83,0x0f,0x35,0x10,0x26,0x4a,0x24,0x83,
+0x00,0x35,0x25,0x83,0x00,0x35,0x26,0x83,0x00,0x35,0x27,0x83,0x00,0x35,0x4d,0x27,
+0x01,0x01,0xc6,0x3e,0xfc,0xcd,0xa4,0xae,0xa4,0x00,0x84,0x35,0xa2,0x1e,0xa0,0x3f,
+0xa1,0x3f,0xa2,0x1f,0x73,0xce,0xcd,0x14,0x26,0x03,0xa1,0x04,0x27,0x01,0xa1,0xbb,
+0x00,0xc6,0x1f,0x26,0x4a,0x01,0x01,0xc6,0x3e,0xfc,0xcd,0xa0,0xae,0xa4,0x00,0x84,
+0x35,0xa0,0x1f,0xa2,0x3f,0xa3,0x3f,0xdb,0xfb,0xcd,0x10,0xa6,0x5d,0xfc,0xcd,0x5c,
+0x01,0x24,0x02,0xab,0xe9,0x00,0xce,0xea,0x00,0xc6,0x0b,0x20,0x7b,0x01,0xce,0x7c,
+0x01,0xc6,0x2a,0x26,0x4a,0x0b,0x27,0x02,0xa0,0x01,0x01,0xc6,0x81,0x01,0x5f,0x72,
+0xef,0xcd,0xcc,0x03,0x27,0x03,0x01,0xc6,0x08,0x27,0x02,0x01,0xc6,0x88,0x88,0x88,
+0x88,0x81,0x84,0x84,0x84,0x84,0xa0,0x84,0xc7,0x01,0x7b,0xa1,0x84,0xc7,0x02,0x7b,
+0xa2,0x84,0xc7,0x03,0x7b,0xa3,0x84,0xc7,0x04,0x7b,0x0a,0xfd,0xcd,0xa4,0xb7,0x00,
+0xa9,0x41,0x01,0xab,0x5b,0xa2,0x1e,0x5d,0xfc,0xcd,0xbc,0x00,0xce,0xbd,0x00,0xc6,
+0x03,0x6b,0x80,0xa4,0x03,0x7b,0x04,0x6b,0x4f,0x1f,0x25,0x02,0xa1,0xbb,0x00,0xc6,
+0x26,0x26,0x4a,0x01,0x01,0xc6,0x03,0x6b,0x7f,0xa4,0x03,0x7b,0x01,0x6b,0xa0,0x84,
+0xc6,0x02,0x6b,0xa1,0x84,0xc6,0x03,0x6b,0xa2,0x84,0xc6,0x04,0x6b,0xa3,0x84,0xc6,
+0x5a,0x26,0x02,0x01,0xc6,0x5f,0x20,0x24,0x83,0x00,0x35,0x25,0x83,0x00,0x35,0x26,
+0x83,0x02,0x35,0x27,0x83,0x00,0x35,0xa0,0x84,0x00,0x35,0xa1,0x84,0x00,0x35,0xa2,
+0x84,0x00,0x35,0xa3,0x84,0x00,0x35,0xa4,0x84,0x00,0x35,0xa5,0x84,0x00,0x35,0xa6,
+0x84,0x00,0x35,0xa7,0x84,0x00,0x35,0x3e,0xfc,0xcd,0x78,0xae,0xa4,0x00,0x84,0x35,
+0xa0,0x1d,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0x01,0x6b,0x78,
+0x84,0xc6,0x02,0x6b,0x79,0x84,0xc6,0x03,0x6b,0x7a,0x84,0xc6,0x04,0x6b,0x7b,0x84,
+0xc6,0x81,0x01,0xc7,0x5f,0x26,0x02,0x01,0xce,0x64,0x26,0x03,0x01,0xc6,0x88,0x88,
+0x88,0x88,0x81,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,0x84,0x84,
+0x84,0x84,0x00,0x40,0xc7,0x01,0x7b,0x01,0x40,0xc7,0x02,0x7b,0x02,0x40,0xc7,0x03,
+0x7b,0x03,0x40,0xc7,0x04,0x7b,0x3e,0xfc,0xcd,0x5f,0xa4,0x00,0x40,0x35,0xa0,0x1e,
+0x23,0xad,0x5b,0x3e,0xfc,0xcd,0x1c,0xae,0xa4,0x00,0x40,0x35,0xa0,0xb7,0xa1,0xb7,
+0xa2,0xb7,0x4f,0xa3,0xb7,0x13,0xb6,0x14,0x20,0x1c,0x40,0x00,0x35,0x1d,0x40,0x00,
+0x35,0x1e,0x40,0x00,0x35,0x1f,0x40,0x00,0x35,0x04,0x6b,0x02,0xaa,0x04,0x7b,0x18,
+0x26,0x12,0x3d,0x04,0x6b,0x40,0xaa,0x04,0x7b,0x06,0x26,0xee,0x00,0xc6,0x04,0x6b,
+0x10,0xaa,0x04,0x7b,0x06,0x26,0xed,0x00,0xc6,0x01,0x6b,0x02,0x6b,0x03,0x6b,0x4f,
+0x04,0x6b,0x01,0xa6,0x3e,0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0xa3,0x18,0xa2,
+0x18,0x53,0xcc,0xcd,0x5b,0x01,0x6b,0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,0x03,
+0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,0xc6,0x78,0xc9,0xcd,0xfa,0xa6,0x14,0x45,
+0x00,0x35,0x15,0x45,0x00,0x35,0x16,0x45,0x00,0x35,0x17,0x45,0x02,0x35,0x88,0x88,
+0x88,0x88,0x81,0x01,0x40,0x00,0x35,0x02,0x40,0x00,0x35,0x03,0x40,0x00,0x35,0x81,
+0x84,0x84,0x84,0x84,0x03,0x01,0x5f,0x72,0x3e,0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,
+0x35,0xa2,0x19,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0x01,0x6b,
+0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,0x03,0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,
+0x84,0xc6,0x14,0x45,0x00,0x35,0x15,0x45,0x00,0x35,0x16,0x45,0x00,0x35,0x17,0x45,
+0x01,0x35,0x00,0x40,0x00,0x35,0x47,0xad,0x00,0x40,0x80,0x35,0x4d,0xad,0x88,0x88,
+0x88,0x88,0x81,0x00,0x88,0x00,0x35,0x01,0x88,0x00,0x35,0x02,0x88,0x00,0x35,0x81,
+0xa2,0x14,0xa3,0x14,0xa0,0x3f,0xa1,0x3f,0xa2,0xb7,0x01,0xa4,0xa2,0xb6,0xa3,0xb7,
+0xf8,0xa4,0xa3,0xb6,0x7d,0xfb,0xcd,0x08,0xae,0x90,0x5f,0x26,0xb6,0x81,0x84,0x84,
+0x21,0xad,0x03,0x88,0x01,0x35,0x08,0x88,0x00,0x35,0x09,0x88,0x30,0x35,0x0a,0x88,
+0x00,0x35,0x0b,0x88,0x00,0x35,0x3e,0xfc,0xcd,0x0c,0xae,0xa4,0x00,0x88,0x35,0xa3,
+0x1e,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x07,0xa4,0x01,0x7b,0x18,0x88,
+0x00,0x35,0x19,0x88,0x00,0x35,0x1a,0x88,0xff,0x35,0x1b,0x88,0xff,0x35,0x14,0x88,
+0x00,0x35,0x15,0x88,0x00,0x35,0x16,0x88,0xff,0x35,0x17,0x88,0xff,0x35,0x10,0x88,
+0x00,0x35,0x11,0x88,0x5f,0x35,0x12,0x88,0xff,0x35,0x13,0x88,0xff,0x35,0x31,0xcb,
+0xcd,0x03,0x88,0x00,0x35,0xac,0x84,0x00,0x35,0xad,0x84,0x00,0x35,0xae,0x84,0x00,
+0x35,0xaf,0x84,0x20,0x35,0x3e,0xfc,0xcd,0x7c,0xae,0xa4,0x00,0x84,0x35,0xa0,0x14,
+0xa1,0x1a,0xa1,0x10,0x13,0xcb,0xcd,0x09,0x20,0xa1,0x1a,0xa1,0x10,0x13,0xcb,0xcd,
+0x12,0x20,0xa1,0x10,0x13,0xcb,0xcd,0x19,0x20,0x13,0xcb,0xcd,0x27,0x20,0x17,0x27,
+0x4a,0x11,0x27,0x4a,0x0d,0x27,0x4a,0x0b,0x27,0x4a,0x9f,0x89,0x88,0x81,0xac,0x84,
+0x00,0x35,0xad,0x84,0x00,0x35,0xae,0x84,0x00,0x35,0xaf,0x84,0x00,0x35,0x7c,0x84,
+0x00,0x35,0x7d,0x84,0x00,0x35,0x7e,0x84,0x00,0x35,0x7f,0x84,0x00,0x35,0x00,0x88,
+0x00,0x35,0x01,0x88,0x00,0x35,0x02,0x88,0x00,0x35,0x03,0x88,0x00,0x35,0x01,0x01,
+0x5f,0x72,0x76,0x01,0x5f,0x72,0x81,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x03,
+0xab,0x3e,0xfc,0xcc,0x5f,0xa4,0x00,0x84,0x35,0xa0,0x00,0x30,0x35,0x0c,0xad,0x5b,
+0x3e,0xfc,0xcd,0x5f,0xa4,0x00,0x84,0x35,0xa0,0x1a,0xa0,0x3f,0x1b,0xad,0x5b,0x81,
+0xa0,0x3f,0x56,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x03,0xab,0x3e,0xfc,0xcc,0x5f,
+0xa4,0x00,0x84,0x35,0xa0,0x18,0x0a,0xad,0x5b,0x3e,0xfc,0xcd,0x5f,0xa4,0x00,0x84,
+0x35,0x15,0xad,0x5b,0x81,0x85,0x90,0x85,0x90,0x01,0xee,0x72,0x02,0x7b,0x05,0x20,
+0x05,0xee,0x72,0x06,0x7b,0x07,0x24,0x05,0xe2,0x72,0x9f,0x06,0xe0,0x72,0x89,0x88,
+0x81,0x85,0x90,0x85,0x90,0x05,0xee,0x72,0x06,0x7b,0x05,0x20,0x01,0xee,0x72,0x02,
+0x7b,0x07,0x24,0x05,0xe2,0x72,0x9f,0x06,0xe0,0x72,0x89,0x88,0x81,0x84,0x84,0xe9,
+0x26,0xa4,0xb6,0xed,0x26,0x5d,0x01,0x6b,0x00,0xa2,0xa4,0xb7,0x01,0x7b,0x02,0x6b,
+0x01,0xa0,0x97,0x02,0x7b,0x9d,0x01,0x20,0x01,0xef,0x72,0x02,0x6b,0xb2,0xfb,0xcd,
+0x03,0xae,0x90,0xa7,0x3f,0x5f,0x88,0x88,0x81,0x41,0x20,0x40,0x35,0x48,0x20,0x5f,
+0x72,0x46,0x20,0x5f,0x72,0x45,0x20,0xd8,0x35,0x81,0x9a,0x6a,0x01,0xcf,0x6b,0x01,
+0xc7,0x9b,0x81,0x4f,0x13,0xb7,0x53,0x20,0xc6,0x50,0x20,0x12,0x72,0x81,0x01,0xa6,
+0x03,0x27,0x4d,0x5e,0xc7,0xcd,0x88,0xa6,0x12,0xb7,0x53,0x20,0xc6,0x50,0x20,0x15,
+0x72,0x81,0x01,0xa6,0x03,0x27,0x4d,0x5e,0xc7,0xcd,0x88,0xa6,0x81,0x01,0xa6,0x03,
+0x27,0x4d,0xbb,0xc7,0xcd,0x41,0xa6,0x81,0x01,0xa6,0x03,0x27,0x4d,0xa6,0xc7,0xcd,
+0xaa,0x00,0x5f,0x72,0x50,0x20,0x20,0x35,0x52,0x20,0x09,0x35,0x81,0x4d,0x5e,0xc7,
+0xcd,0x88,0xa6,0x50,0x20,0x20,0x35,0x53,0x20,0xc7,0xcb,0x20,0x4f,0x50,0x20,0x12,
+0x72,0xec,0x25,0x07,0xe1,0x72,0x01,0x6b,0x4c,0x01,0x7b,0xda,0x26,0x13,0xad,0x50,
+0x01,0xd6,0x01,0xee,0x72,0x0d,0x20,0x4f,0x78,0xc9,0xcd,0x05,0xa6,0xec,0x26,0x25,
+0xad,0x03,0x7b,0xf2,0x26,0x4d,0x5e,0xc7,0xcd,0x88,0xa6,0x81,0x85,0x85,0x85,0x01,
+0xa6,0x06,0x27,0x4d,0xbb,0xc7,0xcd,0x02,0x7b,0x08,0x26,0x4d,0xa6,0xc7,0xcd,0xaa,
+0x00,0x5f,0x72,0x50,0x20,0x20,0x35,0x52,0x20,0x09,0x35,0x88,0x89,0x88,0x81,0x4d,
+0x5e,0xc7,0xcd,0x88,0xa6,0xf7,0xc7,0xcc,0x4f,0x78,0xc9,0xcd,0x05,0xa6,0x95,0x25,
+0x06,0xe1,0x72,0x01,0x7b,0x50,0x01,0xd7,0x53,0x20,0xc6,0x01,0x6b,0x4c,0x9f,0x01,
+0xee,0x72,0x0d,0x20,0x11,0xe7,0x53,0x20,0xc6,0x97,0x07,0xeb,0x72,0x4a,0x01,0x6b,
+0x4c,0x01,0x7b,0x11,0x25,0x09,0xa1,0x06,0x7b,0x50,0x20,0x22,0x35,0x04,0x26,0xa8,
+0xb1,0xa8,0xbf,0x90,0x0b,0x26,0xa7,0xb3,0xa7,0x3f,0x01,0xe6,0x72,0x4a,0x5a,0x01,
+0x26,0x4d,0x5f,0x06,0x7b,0x50,0x20,0x15,0x72,0x04,0x26,0xa8,0xb1,0xa8,0xbf,0x90,
+0x0b,0x26,0xa7,0xb3,0xa7,0x3f,0x01,0xe6,0x72,0x5a,0x01,0x24,0x02,0xa0,0x5f,0x1a,
+0x25,0x02,0xa1,0x06,0x7b,0xba,0x26,0x72,0xad,0x50,0x20,0x15,0x72,0x04,0x26,0x4a,
+0x06,0x7b,0xc7,0x26,0x4d,0x90,0xad,0x01,0xaa,0x02,0x7b,0xd0,0x26,0x4d,0x84,0xad,
+0x78,0xc9,0xcd,0x05,0xa6,0xda,0x26,0xab,0xc8,0xcd,0x50,0x20,0x20,0x35,0x53,0x20,
+0xc7,0x03,0x7b,0x02,0x20,0x52,0x80,0xae,0x03,0x7b,0x07,0x26,0x80,0xa1,0x06,0x7b,
+0xf5,0x26,0xab,0xc8,0xcd,0x81,0x85,0x85,0x85,0x01,0xa6,0x06,0x27,0x4d,0xc9,0xad,
+0x02,0x7b,0x07,0x26,0x4d,0xbb,0xad,0xaa,0x00,0x5f,0x72,0x01,0x6b,0x4f,0x50,0x20,
+0x20,0x35,0x52,0x20,0x09,0x35,0x88,0x89,0x88,0x81,0x4f,0x50,0x20,0x24,0x35,0x78,
+0xc9,0xcd,0x05,0xa6,0x81,0x01,0xa6,0x03,0x27,0x4d,0xb7,0xad,0x82,0xa6,0x50,0x20,
+0x21,0x35,0x53,0x20,0xc7,0x81,0x4f,0x78,0xc9,0xcd,0x05,0xa6,0x81,0x01,0xa6,0x03,
+0x27,0x4d,0xcf,0xad,0x81,0xa6,0x50,0x20,0x29,0x35,0x81,0x85,0x4f,0xaa,0x00,0x5f,
+0x72,0x81,0x85,0x01,0xa6,0xaa,0x00,0x5f,0x72,0x50,0x20,0x22,0x35,0x0c,0xaa,0x00,
+0x0d,0x72,0x05,0x26,0x01,0xe1,0x72,0x01,0xe4,0x72,0xfa,0x27,0xaa,0x00,0xc6,0x8f,
+0x01,0x20,0x88,0x81,0x85,0x4f,0x81,0x85,0x01,0xa6,0x50,0x20,0x05,0x35,0x08,0x27,
+0x01,0xe1,0x72,0x01,0xe4,0x72,0x51,0x20,0xc6,0xfa,0x51,0x20,0x0f,0x72,0x9d,0x01,
+0x20,0x88,0x81,0x44,0x42,0x00,0x35,0x45,0x42,0x00,0x35,0x46,0x42,0x00,0x35,0x47,
+0x42,0x00,0x35,0x00,0x42,0x00,0x35,0x01,0x42,0x00,0x35,0x02,0x42,0x01,0x35,0x03,
+0x42,0x01,0x35,0x10,0x20,0x00,0x42,0x08,0x35,0x01,0x42,0x00,0x35,0x02,0x42,0x01,
+0x35,0x03,0x42,0x00,0x35,0x12,0x26,0x4a,0xbe,0x00,0xc6,0x20,0x40,0x00,0x35,0x21,
+0x40,0x00,0x35,0x22,0x40,0x00,0x35,0x23,0x40,0x01,0x35,0x04,0x44,0xc0,0x00,0x55,
+0x05,0x44,0xc1,0x00,0x55,0x06,0x44,0xc2,0x00,0x55,0x07,0x44,0xc3,0x00,0x55,0x00,
+0x44,0xc4,0x00,0x55,0x01,0x44,0xc5,0x00,0x55,0x02,0x44,0xc6,0x00,0x55,0x03,0x44,
+0xc7,0x00,0x55,0x81,0x21,0xfc,0xcd,0xa0,0x3f,0xa1,0x3f,0xa2,0x3f,0x81,0x21,0xfc,
+0xcd,0xa4,0xb7,0x01,0xaa,0x41,0x81,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,
+0x81,0xa4,0xc6,0x92,0xa5,0xbf,0xa4,0xb7,0x81,0x1c,0xad,0xa3,0x3f,0xa4,0xb7,0x01,
+0xaa,0x81,0x84,0x84,0x84,0xdf,0x26,0x03,0xe1,0x72,0x12,0xad,0x02,0xaa,0x41,0x03,
+0xaa,0x01,0xee,0x72,0x02,0x7b,0x21,0xfc,0xcd,0xa4,0xb7,0x02,0xaa,0x01,0x7b,0x02,
+0xee,0x72,0x32,0xad,0x03,0x7b,0x10,0x20,0x03,0x6b,0x03,0xa6,0x02,0x20,0x83,0xa6,
+0x04,0x26,0x02,0xa1,0x11,0xb6,0x59,0xad,0xa3,0x00,0x3d,0x35,0x02,0xee,0x72,0xa4,
+0xb7,0x01,0x7b,0x66,0xad,0xa3,0x00,0x08,0x35,0xa4,0xb7,0x02,0xaa,0x41,0x24,0xaa,
+0x01,0xee,0x72,0x02,0x7b,0x54,0xad,0x41,0x1c,0xaa,0x01,0xee,0x72,0x02,0x7b,0x5e,
+0xad,0x41,0x18,0xaa,0x01,0xee,0x72,0x02,0x7b,0x68,0xad,0x41,0x14,0xaa,0x01,0xee,
+0x72,0x02,0x7b,0xdf,0x26,0x03,0xe1,0x72,0xc8,0xc6,0xcd,0x01,0xaa,0x41,0x13,0xaa,
+0x01,0xee,0x72,0x02,0x7b,0xda,0xc6,0xcd,0x10,0xaa,0x01,0xee,0x72,0x02,0x7b,0xd0,
+0xc6,0xcd,0x03,0x7b,0x0f,0x20,0x03,0x6b,0xcf,0xa6,0x02,0x20,0x0f,0xa6,0x06,0x20,
+0x0c,0xa6,0x08,0x20,0x06,0x27,0x4a,0x05,0x27,0x14,0xb6,0xda,0x26,0x03,0xe1,0x72,
+0xc8,0xc6,0xcd,0x01,0xaa,0x41,0x0d,0xaa,0x01,0xee,0x72,0x02,0x7b,0xda,0xc6,0xcd,
+0x0c,0xaa,0x01,0xee,0x72,0x02,0x7b,0xdb,0xfb,0xcd,0x10,0xa6,0xd0,0xc6,0xcd,0x03,
+0x7b,0x14,0x20,0x03,0x6b,0xfc,0xa6,0x02,0x20,0xf0,0xa6,0x06,0x20,0xcc,0xa6,0x0a,
+0x20,0xc0,0xa6,0x0e,0x20,0x0c,0xa6,0x12,0x20,0x0f,0xa6,0x04,0x20,0x16,0x27,0x4a,
+0x15,0x27,0x4a,0x14,0x27,0x4a,0x13,0x27,0x4a,0x12,0x27,0x4a,0x27,0x27,0x4a,0x14,
+0x27,0x13,0xb6,0xd1,0x26,0x03,0xe1,0x72,0xc8,0xc6,0xcd,0x01,0xaa,0x41,0x0b,0xaa,
+0x01,0xee,0x72,0x02,0x7b,0xda,0xc6,0xcd,0x08,0xaa,0x01,0xee,0x72,0x02,0x7b,0xa0,
+0xb7,0x03,0xaa,0xa0,0xb6,0xa1,0xb7,0xc3,0xaa,0xa0,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,
+0x03,0x7b,0x1d,0x20,0x03,0x6b,0x4f,0x01,0x20,0x0c,0xa6,0x04,0x27,0x15,0x3d,0xbf,
+0xc6,0xcd,0x41,0x04,0xaa,0x01,0xee,0x72,0x02,0x7b,0xbf,0xc6,0xcd,0x01,0x6b,0x02,
+0xef,0x72,0x50,0xaa,0x41,0x4f,0x58,0x58,0x97,0x88,0x88,0x88,0x81,0x56,0xfd,0xcd,
+0xc4,0xae,0xa4,0x00,0x00,0x35,0x81,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,
+0x81,0x4d,0x5f,0x12,0xb6,0x81,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,0xa0,0xb7,
+0x03,0xa4,0xa0,0xb6,0xa1,0x3f,0xa2,0x3f,0xa3,0x3f,0xdb,0xfb,0xcd,0x18,0xa6,0xc9,
+0xfb,0xcd,0x4a,0x81,0xa4,0xb7,0x00,0xa9,0x41,0x07,0xab,0x81,0xc4,0x00,0x00,0x35,
+0xc5,0x00,0x00,0x35,0xc6,0x00,0x18,0x35,0x81,0xa0,0x3f,0xa1,0xb7,0x3e,0xa4,0xa1,
+0xb6,0xa2,0x3f,0xa3,0x3f,0xdb,0xfb,0xcd,0x11,0xa6,0x4a,0xad,0x81,0x4d,0xad,0x18,
+0xa4,0x48,0x48,0x48,0x4a,0x12,0xb6,0x3e,0xfc,0xcd,0x4d,0xad,0x81,0x8b,0x41,0x00,
+0xa9,0x41,0x0a,0xab,0x5b,0x3e,0xfc,0xcd,0x0c,0xae,0xa4,0x00,0x84,0x35,0xa3,0x36,
+0xa2,0x36,0xa1,0x36,0xa0,0x34,0x5a,0xc5,0xcd,0x0b,0x20,0xa0,0x39,0xa1,0x39,0xa2,
+0x39,0xa3,0x38,0x5a,0xc5,0xcd,0x0d,0x26,0x02,0xa1,0x11,0xb6,0x84,0x84,0x84,0x84,
+0x84,0x35,0xe2,0xcd,0x88,0x0b,0x7b,0x88,0x0b,0x7b,0x88,0x0b,0x7b,0x88,0x0b,0x7b,
+0x88,0x06,0x7b,0x06,0x6b,0x44,0x44,0x06,0x7b,0xeb,0xfc,0xcd,0x02,0xa6,0x25,0xc5,
+0xcd,0x5b,0x0f,0x26,0x02,0xa1,0x11,0xb6,0x06,0x6b,0x08,0xa6,0x07,0x6b,0x4f,0x08,
+0x6b,0xbb,0xa6,0x09,0x6b,0x80,0xa6,0x0a,0x6b,0xc4,0x00,0x00,0x35,0xc5,0x00,0x00,
+0x35,0xc6,0x00,0x60,0x35,0xc7,0x00,0x00,0x35,0x18,0x20,0xac,0xa6,0x09,0x6b,0x44,
+0xa6,0x0a,0x6b,0xc4,0x00,0x00,0x35,0xc5,0x00,0x00,0x35,0xc6,0x00,0x62,0x35,0xc7,
+0x00,0x00,0x35,0x39,0x20,0x10,0xa6,0x07,0x6b,0x4f,0x08,0x6b,0x5d,0xa6,0x09,0x6b,
+0xc0,0xa6,0x0a,0x6b,0xc4,0x00,0x00,0x35,0xc5,0x00,0x00,0x35,0xc6,0x00,0x30,0x35,
+0xc7,0x00,0x00,0x35,0x18,0x20,0x56,0xa6,0x09,0x6b,0x22,0xa6,0x0a,0x6b,0xc4,0x00,
+0x00,0x35,0xc5,0x00,0x00,0x35,0xc6,0x00,0x31,0x35,0xc7,0x00,0x00,0x35,0x74,0x20,
+0x20,0xa6,0x07,0x6b,0x4f,0x08,0x6b,0x2e,0xa6,0x09,0x6b,0xe0,0xa6,0x0a,0x6b,0x18,
+0xc5,0xcd,0xc7,0x00,0x00,0x35,0x96,0xc4,0xcc,0x20,0xa6,0x07,0x6b,0x4f,0x08,0x6b,
+0x2b,0xa6,0x09,0x6b,0x11,0xa6,0x0a,0x6b,0x18,0xc5,0xcd,0xc7,0x00,0x80,0x35,0x96,
+0xc4,0xcc,0x20,0xa6,0x07,0x6b,0x4f,0x08,0x6b,0x1f,0xa6,0x09,0x6b,0x40,0xa6,0x0a,
+0x6b,0xc4,0x00,0x00,0x35,0xc5,0x00,0x00,0x35,0xc6,0x00,0x10,0x35,0xc7,0x00,0x00,
+0x35,0x96,0xc4,0xcc,0x20,0xa6,0x07,0x6b,0x4f,0x08,0x6b,0x2e,0xa6,0x09,0x6b,0xe0,
+0xa6,0x0a,0x6b,0x4f,0x18,0xc5,0xcd,0xc7,0x00,0x00,0x35,0x77,0xc4,0xcc,0x03,0x26,
+0x4a,0x5d,0xc4,0xcc,0x03,0x26,0x4a,0x3c,0xc4,0xcc,0x03,0x26,0x4a,0x22,0xc4,0xcc,
+0x03,0x26,0x4a,0x6d,0x27,0x4a,0x57,0x27,0x4a,0x38,0x27,0x13,0xb6,0x3e,0xfc,0xcd,
+0xa4,0xbf,0x84,0xae,0xa3,0x1a,0x56,0xfd,0xcd,0x25,0xc5,0xcd,0x5b,0x0a,0xfd,0xcd,
+0x25,0xc5,0xcd,0x5b,0x10,0xfd,0xcd,0x43,0xc5,0xcd,0x5b,0xf4,0xc4,0xcd,0x5b,0x2d,
+0xc5,0xcd,0x5a,0x01,0x26,0x4b,0xc5,0xcd,0x14,0x20,0xa3,0x10,0x10,0xfd,0xcd,0x43,
+0xc5,0xcd,0x5b,0xf4,0xc4,0xcd,0x5b,0x2d,0xc5,0xcd,0x5a,0x01,0x26,0x4b,0xc5,0xcd,
+0x18,0x26,0x4a,0x11,0xb6,0x38,0x20,0x08,0x6b,0x40,0xaa,0x08,0x7b,0x0a,0x6b,0x02,
+0xaa,0x0a,0x7b,0x0e,0x26,0x02,0xa1,0x11,0xb6,0x36,0x20,0x39,0x26,0x4b,0xc5,0xcd,
+0x25,0x20,0x28,0x26,0x4b,0xc5,0xcd,0x07,0x26,0x4a,0x11,0xb6,0x19,0x27,0x02,0xa1,
+0x11,0xb6,0x0a,0x6b,0x04,0xaa,0x0a,0x7b,0x1f,0x27,0x16,0x3d,0x3e,0xfc,0xcd,0x25,
+0xc5,0xcd,0x5b,0xa2,0x1e,0x04,0xc5,0xcd,0x05,0x7b,0x05,0x20,0xa0,0x14,0x04,0xc5,
+0xcd,0x05,0x7b,0x09,0x27,0x75,0x01,0xc6,0xbe,0x00,0xc7,0x12,0xb6,0x02,0x20,0x04,
+0xa6,0x04,0x26,0x02,0xa1,0x11,0xb6,0x05,0x6b,0x18,0xa6,0x02,0x20,0x14,0xa6,0x06,
+0x20,0x10,0xa6,0x08,0x20,0x06,0x27,0x4a,0x05,0x27,0x14,0xb6,0x8b,0x41,0x00,0xa2,
+0x41,0x0a,0xa0,0x5b,0xe0,0x20,0x8f,0xe3,0x26,0x01,0x7b,0x81,0xf2,0xcd,0x03,0x26,
+0x6a,0x01,0xca,0x6b,0x01,0xc6,0xa7,0xf1,0xcd,0x03,0x24,0x20,0xa1,0x12,0x27,0x01,
+0x6b,0x28,0xc0,0xcd,0x79,0xc0,0xcd,0x88,0x81,0x84,0x06,0x20,0x08,0x35,0x9a,0x1a,
+0x20,0x10,0x72,0x15,0x20,0xc7,0xee,0xa4,0x15,0x20,0xc6,0x14,0x20,0xc7,0x7c,0xa4,
+0x14,0x20,0xc6,0x13,0x20,0xc7,0x08,0xa4,0x13,0x20,0xc6,0x67,0xc9,0xcd,0x84,0x84,
+0x84,0x84,0x84,0x84,0x84,0x84,0x84,0xe0,0xcd,0xfd,0x00,0x3b,0xfe,0x00,0x3b,0xff,
+0x00,0x3b,0x00,0x01,0x3b,0x01,0x4b,0x80,0x4b,0x85,0x4b,0x80,0x4b,0xb0,0x84,0x00,
+0x35,0xb1,0x84,0x00,0x35,0xb2,0x84,0x00,0x35,0xb3,0x84,0x15,0x35,0xa4,0x84,0x00,
+0x35,0xa5,0x84,0x00,0x35,0xa6,0x84,0x00,0x35,0xa7,0x84,0x00,0x35,0xa0,0x84,0x00,
+0x35,0xa1,0x84,0x00,0x35,0xa2,0x84,0x00,0x35,0xa3,0x84,0x00,0x35,0x0c,0x8c,0x00,
+0x35,0x0d,0x8c,0x00,0x35,0x0e,0x8c,0x00,0x35,0x0f,0x8c,0x00,0x35,0x18,0x8c,0x00,
+0x35,0x19,0x8c,0x00,0x35,0x1a,0x8c,0x00,0x35,0x1b,0x8c,0x03,0x35,0x04,0x8c,0x00,
+0x35,0x05,0x8c,0x00,0x35,0x06,0x8c,0x00,0x35,0x07,0x8c,0x0a,0x35,0x00,0x8c,0x00,
+0x35,0x01,0x8c,0x00,0x35,0x02,0x8c,0x00,0x35,0x03,0x8c,0x00,0x35,0x1c,0x8c,0x00,
+0x35,0x1d,0x8c,0x00,0x35,0x1e,0x8c,0x00,0x35,0x1f,0x8c,0x04,0x35,0x2a,0xca,0xcd,
+0x3e,0xcb,0xcd,0x24,0x83,0x00,0x35,0x25,0x83,0x00,0x35,0x26,0x83,0x02,0x35,0x27,
+0x83,0x00,0x35,0x84,0x84,0x00,0x35,0x85,0x84,0x00,0x35,0x86,0x84,0x00,0x35,0x87,
+0x84,0x20,0x35,0xb4,0x84,0x00,0x35,0xb5,0x84,0x00,0x35,0xb6,0x84,0x00,0x35,0xb7,
+0x84,0x80,0x35,0x18,0x84,0x00,0x35,0x19,0x84,0x00,0x35,0x1a,0x84,0x00,0x35,0x1b,
+0x84,0x00,0x35,0x78,0x84,0x00,0x35,0x79,0x84,0x00,0x35,0x7a,0x84,0x00,0x35,0x7b,
+0x84,0x00,0x35,0x3f,0x20,0x01,0x35,0x3d,0x20,0xc7,0xff,0xa6,0x3c,0x20,0xc7,0x04,
+0xa6,0x3e,0x20,0xfe,0x35,0xfd,0x00,0x02,0x35,0xfe,0x00,0x49,0x35,0xff,0x00,0xf0,
+0x35,0x00,0x01,0xc7,0x0f,0x20,0xfd,0x00,0x01,0x35,0xfe,0x00,0x9b,0x35,0xff,0x00,
+0xfc,0x35,0x00,0x01,0xc0,0x35,0x0c,0x20,0xfe,0x00,0x8c,0x35,0xff,0x00,0xba,0x35,
+0x00,0x01,0x80,0x35,0x1a,0x20,0xfe,0x00,0x24,0x35,0xff,0x00,0xf8,0x35,0x00,0x01,
+0xc7,0x3c,0x20,0xfd,0x00,0x5f,0x72,0xfe,0x00,0x5f,0x72,0xff,0x00,0x5f,0x72,0x00,
+0x01,0x5f,0x72,0x3f,0x27,0x4a,0x30,0x27,0x4a,0x25,0x27,0x4a,0x1b,0x27,0x0f,0xa4,
+0x08,0x20,0xc6,0x82,0x01,0xc7,0x0f,0xa4,0x4e,0x03,0x20,0xc6,0xf2,0x25,0x10,0xa1,
+0x01,0x6b,0x4c,0x5a,0x01,0x4f,0x72,0x01,0xee,0x72,0x01,0x6b,0x4f,0x75,0x01,0x5f,
+0x72,0xbb,0x00,0x5f,0x72,0xbd,0x00,0x5f,0x72,0xbc,0x00,0x5f,0x72,0x6b,0x01,0x5f,
+0x72,0x6a,0x01,0x5f,0x72,0x2c,0x01,0x0a,0x35,0x2f,0x01,0x5f,0x72,0x30,0x01,0x5f,
+0x72,0x3a,0x01,0x5f,0x72,0x31,0x01,0x5f,0x72,0x32,0x01,0x5f,0x72,0x33,0x01,0x5f,
+0x72,0x17,0x01,0x5f,0x72,0x7a,0x01,0x5f,0x72,0x7d,0x01,0x5f,0x72,0x02,0x01,0x5f,
+0x72,0x03,0x01,0x5f,0x72,0xaa,0x00,0x5f,0x72,0x05,0x01,0x5f,0x72,0x18,0x01,0x5f,
+0x72,0x06,0x01,0x5f,0x72,0xbe,0x00,0x5f,0x72,0xbf,0x00,0x5f,0x72,0x01,0x01,0x5f,
+0x72,0x11,0x3f,0x10,0x3f,0x04,0x01,0x5f,0x72,0x58,0x01,0x5f,0x72,0x59,0x01,0x5f,
+0x72,0x7e,0x01,0x5f,0x72,0x7f,0x01,0xff,0x35,0x81,0x01,0x5f,0x72,0x79,0x01,0x5f,
+0x72,0x9b,0x06,0x20,0x5f,0x72,0x88,0x81,0x84,0xe3,0xad,0xf4,0x25,0x40,0xa1,0x01,
+0x6b,0x4c,0x12,0x6f,0x01,0xee,0x72,0x01,0x6b,0x4f,0x88,0x81,0x05,0x20,0x10,0x72,
+0x15,0x20,0x11,0x72,0x10,0x1e,0xa8,0xc2,0xcc,0x8b,0xff,0xa6,0x04,0xae,0x81,0x85,
+0x01,0x7b,0x9a,0x58,0x01,0xc7,0x0f,0xa4,0x58,0x01,0xc6,0x5a,0x01,0x4f,0x72,0x58,
+0x01,0x5c,0x72,0x01,0x6b,0x5a,0x01,0xd6,0x58,0x01,0xce,0x18,0x27,0x58,0x01,0xc1,
+0x59,0x01,0xc6,0x9b,0x01,0x6b,0x4f,0x88,0x81,0x84,0x9a,0x59,0x01,0xc7,0x0f,0xa4,
+0x59,0x01,0xc6,0x5a,0x01,0xd7,0x59,0x01,0x5c,0x72,0x59,0x01,0xce,0x01,0x7b,0x14,
+0x27,0x01,0xe1,0x72,0x5a,0x01,0xd6,0x97,0x0f,0xa4,0x4a,0x59,0x01,0xc6,0x9b,0x88,
+};
+
diff --git a/drivers/video/av8100/av8100_regs.h b/drivers/video/av8100/av8100_regs.h
new file mode 100644
index 00000000000..704a99a3a4e
--- /dev/null
+++ b/drivers/video/av8100/av8100_regs.h
@@ -0,0 +1,346 @@
+
+#define AV8100_VAL2REG(__reg, __fld, __val) \
+ (((__val) << __reg##_##__fld##_SHIFT) & __reg##_##__fld##_MASK)
+#define AV8100_REG2VAL(__reg, __fld, __val) \
+ (((__val) & __reg##_##__fld##_MASK) >> __reg##_##__fld##_SHIFT)
+
+#define AV8100_STANDBY 0x00000000
+#define AV8100_STANDBY_CPD_SHIFT 0
+#define AV8100_STANDBY_CPD_MASK 0x00000001
+#define AV8100_STANDBY_CPD_HIGH 1
+#define AV8100_STANDBY_CPD_LOW 0
+#define AV8100_STANDBY_CPD(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY, CPD, __x)
+#define AV8100_STANDBY_CPD_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY, CPD, __x)
+#define AV8100_STANDBY_STBY_SHIFT 1
+#define AV8100_STANDBY_STBY_MASK 0x00000002
+#define AV8100_STANDBY_STBY_HIGH 1
+#define AV8100_STANDBY_STBY_LOW 0
+#define AV8100_STANDBY_STBY(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY, STBY, __x)
+#define AV8100_STANDBY_STBY_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY, STBY, __x)
+#define AV8100_STANDBY_HPDS_SHIFT 2
+#define AV8100_STANDBY_HPDS_MASK 0x00000004
+#define AV8100_STANDBY_HPDS(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY, HPDS, __x)
+#define AV8100_STANDBY_HPDS_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY, HPDS, __x)
+#define AV8100_STANDBY_CPDS_SHIFT 3
+#define AV8100_STANDBY_CPDS_MASK 0x00000008
+#define AV8100_STANDBY_CPDS(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY, CPDS, __x)
+#define AV8100_STANDBY_CPDS_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY, CPDS, __x)
+#define AV8100_STANDBY_MCLKRNG_SHIFT 4
+#define AV8100_STANDBY_MCLKRNG_MASK 0x000000F0
+#define AV8100_STANDBY_MCLKRNG(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY, MCLKRNG, __x)
+#define AV8100_STANDBY_MCLKRNG_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY, MCLKRNG, __x)
+#define AV8100_HDMI_5_VOLT_TIME 0x00000001
+#define AV8100_HDMI_5_VOLT_TIME_OFF_TIME_SHIFT 0
+#define AV8100_HDMI_5_VOLT_TIME_OFF_TIME_MASK 0x0000001F
+#define AV8100_HDMI_5_VOLT_TIME_OFF_TIME(__x) \
+ AV8100_VAL2REG(AV8100_HDMI_5_VOLT_TIME, OFF_TIME, __x)
+#define AV8100_HDMI_5_VOLT_TIME_OFF_TIME_GET(__x) \
+ AV8100_REG2VAL(AV8100_HDMI_5_VOLT_TIME, OFF_TIME, __x)
+#define AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME_SHIFT 0
+#define AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME_MASK 0x00000003
+#define AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME(__x) \
+ AV8100_VAL2REG(AV8100_HDMI_5_VOLT_TIME, DAC_OFF_TIME, __x)
+#define AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME_GET(__x) \
+ AV8100_REG2VAL(AV8100_HDMI_5_VOLT_TIME, DAC_OFF_TIME, __x)
+#define AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME_SHIFT 2
+#define AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME_MASK 0x0000001C
+#define AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME(__x) \
+ AV8100_VAL2REG(AV8100_HDMI_5_VOLT_TIME, SU_OFF_TIME, __x)
+#define AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME_GET(__x) \
+ AV8100_REG2VAL(AV8100_HDMI_5_VOLT_TIME, SU_OFF_TIME, __x)
+#define AV8100_HDMI_5_VOLT_TIME_ON_TIME_SHIFT 5
+#define AV8100_HDMI_5_VOLT_TIME_ON_TIME_MASK 0x000000E0
+#define AV8100_HDMI_5_VOLT_TIME_ON_TIME(__x) \
+ AV8100_VAL2REG(AV8100_HDMI_5_VOLT_TIME, ON_TIME, __x)
+#define AV8100_HDMI_5_VOLT_TIME_ON_TIME_GET(__x) \
+ AV8100_REG2VAL(AV8100_HDMI_5_VOLT_TIME, ON_TIME, __x)
+#define AV8100_STANDBY_INTERRUPT_MASK 0x00000002
+#define AV8100_STANDBY_INTERRUPT_MASK_HPDM_SHIFT 0
+#define AV8100_STANDBY_INTERRUPT_MASK_HPDM_MASK 0x00000001
+#define AV8100_STANDBY_INTERRUPT_MASK_HPDM_HIGH 1
+#define AV8100_STANDBY_INTERRUPT_MASK_HPDM_LOW 0
+#define AV8100_STANDBY_INTERRUPT_MASK_HPDM(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY_INTERRUPT_MASK, HPDM, __x)
+#define AV8100_STANDBY_INTERRUPT_MASK_HPDM_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY_INTERRUPT_MASK, HPDM, __x)
+#define AV8100_STANDBY_INTERRUPT_MASK_CPDM_SHIFT 1
+#define AV8100_STANDBY_INTERRUPT_MASK_CPDM_MASK 0x00000002
+#define AV8100_STANDBY_INTERRUPT_MASK_CPDM_HIGH 1
+#define AV8100_STANDBY_INTERRUPT_MASK_CPDM_LOW 0
+#define AV8100_STANDBY_INTERRUPT_MASK_CPDM(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY_INTERRUPT_MASK, CPDM, __x)
+#define AV8100_STANDBY_INTERRUPT_MASK_CPDM_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY_INTERRUPT_MASK, CPDM, __x)
+#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_SHIFT 2
+#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_MASK 0x0000000C
+#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_INPUT 0x00
+#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_ALT 0x01
+#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_OUTPUT0 0x02
+#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_OUTPUT1 0x03
+#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY_INTERRUPT_MASK, STBYGPIOCFG, __x)
+#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY_INTERRUPT_MASK, STBYGPIOCFG, __x)
+#define AV8100_STANDBY_INTERRUPT_MASK_IPOL_SHIFT 7
+#define AV8100_STANDBY_INTERRUPT_MASK_IPOL_MASK 0x00000080
+#define AV8100_STANDBY_INTERRUPT_MASK_IPOL_HIGH 1
+#define AV8100_STANDBY_INTERRUPT_MASK_IPOL_LOW 0
+#define AV8100_STANDBY_INTERRUPT_MASK_IPOL(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY_INTERRUPT_MASK, IPOL, __x)
+#define AV8100_STANDBY_INTERRUPT_MASK_IPOL_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY_INTERRUPT_MASK, IPOL, __x)
+#define AV8100_STANDBY_PENDING_INTERRUPT 0x00000003
+#define AV8100_STANDBY_PENDING_INTERRUPT_HPDI_SHIFT 0
+#define AV8100_STANDBY_PENDING_INTERRUPT_HPDI_MASK 0x00000001
+#define AV8100_STANDBY_PENDING_INTERRUPT_HPDI_HIGH 1
+#define AV8100_STANDBY_PENDING_INTERRUPT_HPDI_LOW 0
+#define AV8100_STANDBY_PENDING_INTERRUPT_HPDI(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY_PENDING_INTERRUPT, HPDI, __x)
+#define AV8100_STANDBY_PENDING_INTERRUPT_HPDI_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY_PENDING_INTERRUPT, HPDI, __x)
+#define AV8100_STANDBY_PENDING_INTERRUPT_CPDI_SHIFT 1
+#define AV8100_STANDBY_PENDING_INTERRUPT_CPDI_MASK 0x00000002
+#define AV8100_STANDBY_PENDING_INTERRUPT_CPDI_HIGH 1
+#define AV8100_STANDBY_PENDING_INTERRUPT_CPDI_LOW 0
+#define AV8100_STANDBY_PENDING_INTERRUPT_CPDI(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY_PENDING_INTERRUPT, CPDI, __x)
+#define AV8100_STANDBY_PENDING_INTERRUPT_CPDI_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY_PENDING_INTERRUPT, CPDI, __x)
+#define AV8100_STANDBY_PENDING_INTERRUPT_ONI_SHIFT 2
+#define AV8100_STANDBY_PENDING_INTERRUPT_ONI_MASK 0x00000004
+#define AV8100_STANDBY_PENDING_INTERRUPT_ONI_HIGH 1
+#define AV8100_STANDBY_PENDING_INTERRUPT_ONI_LOW 0
+#define AV8100_STANDBY_PENDING_INTERRUPT_ONI(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY_PENDING_INTERRUPT, ONI, __x)
+#define AV8100_STANDBY_PENDING_INTERRUPT_ONI_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY_PENDING_INTERRUPT, ONI, __x)
+#define AV8100_STANDBY_PENDING_INTERRUPT_SID_SHIFT 4
+#define AV8100_STANDBY_PENDING_INTERRUPT_SID_MASK 0x000000F0
+#define AV8100_STANDBY_PENDING_INTERRUPT_SID(__x) \
+ AV8100_VAL2REG(AV8100_STANDBY_PENDING_INTERRUPT, SID, __x)
+#define AV8100_STANDBY_PENDING_INTERRUPT_SID_GET(__x) \
+ AV8100_REG2VAL(AV8100_STANDBY_PENDING_INTERRUPT, SID, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK 0x00000004
+#define AV8100_GENERAL_INTERRUPT_MASK_EOCM_SHIFT 0
+#define AV8100_GENERAL_INTERRUPT_MASK_EOCM_MASK 0x00000001
+#define AV8100_GENERAL_INTERRUPT_MASK_EOCM_HIGH 1
+#define AV8100_GENERAL_INTERRUPT_MASK_EOCM_LOW 0
+#define AV8100_GENERAL_INTERRUPT_MASK_EOCM(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, EOCM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_EOCM_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, EOCM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_VSIM_SHIFT 1
+#define AV8100_GENERAL_INTERRUPT_MASK_VSIM_MASK 0x00000002
+#define AV8100_GENERAL_INTERRUPT_MASK_VSIM_HIGH 1
+#define AV8100_GENERAL_INTERRUPT_MASK_VSIM_LOW 0
+#define AV8100_GENERAL_INTERRUPT_MASK_VSIM(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, VSIM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_VSIM_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, VSIM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_VSOM_SHIFT 2
+#define AV8100_GENERAL_INTERRUPT_MASK_VSOM_MASK 0x00000004
+#define AV8100_GENERAL_INTERRUPT_MASK_VSOM_HIGH 1
+#define AV8100_GENERAL_INTERRUPT_MASK_VSOM_LOW 0
+#define AV8100_GENERAL_INTERRUPT_MASK_VSOM(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, VSOM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_VSOM_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, VSOM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_CECM_SHIFT 3
+#define AV8100_GENERAL_INTERRUPT_MASK_CECM_MASK 0x00000008
+#define AV8100_GENERAL_INTERRUPT_MASK_CECM_HIGH 1
+#define AV8100_GENERAL_INTERRUPT_MASK_CECM_LOW 0
+#define AV8100_GENERAL_INTERRUPT_MASK_CECM(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, CECM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_CECM_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, CECM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_HDCPM_SHIFT 4
+#define AV8100_GENERAL_INTERRUPT_MASK_HDCPM_MASK 0x00000010
+#define AV8100_GENERAL_INTERRUPT_MASK_HDCPM_HIGH 1
+#define AV8100_GENERAL_INTERRUPT_MASK_HDCPM_LOW 0
+#define AV8100_GENERAL_INTERRUPT_MASK_HDCPM(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, HDCPM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_HDCPM_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, HDCPM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_UOVBM_SHIFT 5
+#define AV8100_GENERAL_INTERRUPT_MASK_UOVBM_MASK 0x00000020
+#define AV8100_GENERAL_INTERRUPT_MASK_UOVBM_HIGH 1
+#define AV8100_GENERAL_INTERRUPT_MASK_UOVBM_LOW 0
+#define AV8100_GENERAL_INTERRUPT_MASK_UOVBM(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, UOVBM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_UOVBM_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, UOVBM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_TEM_SHIFT 6
+#define AV8100_GENERAL_INTERRUPT_MASK_TEM_MASK 0x00000040
+#define AV8100_GENERAL_INTERRUPT_MASK_TEM_HIGH 1
+#define AV8100_GENERAL_INTERRUPT_MASK_TEM_LOW 0
+#define AV8100_GENERAL_INTERRUPT_MASK_TEM(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, TEM, __x)
+#define AV8100_GENERAL_INTERRUPT_MASK_TEM_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, TEM, __x)
+#define AV8100_GENERAL_INTERRUPT 0x00000005
+#define AV8100_GENERAL_INTERRUPT_EOCI_SHIFT 0
+#define AV8100_GENERAL_INTERRUPT_EOCI_MASK 0x00000001
+#define AV8100_GENERAL_INTERRUPT_EOCI(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, EOCI, __x)
+#define AV8100_GENERAL_INTERRUPT_EOCI_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, EOCI, __x)
+#define AV8100_GENERAL_INTERRUPT_VSII_SHIFT 1
+#define AV8100_GENERAL_INTERRUPT_VSII_MASK 0x00000002
+#define AV8100_GENERAL_INTERRUPT_VSII(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, VSII, __x)
+#define AV8100_GENERAL_INTERRUPT_VSII_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, VSII, __x)
+#define AV8100_GENERAL_INTERRUPT_VSOI_SHIFT 2
+#define AV8100_GENERAL_INTERRUPT_VSOI_MASK 0x00000004
+#define AV8100_GENERAL_INTERRUPT_VSOI(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, VSOI, __x)
+#define AV8100_GENERAL_INTERRUPT_VSOI_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, VSOI, __x)
+#define AV8100_GENERAL_INTERRUPT_CECI_SHIFT 3
+#define AV8100_GENERAL_INTERRUPT_CECI_MASK 0x00000008
+#define AV8100_GENERAL_INTERRUPT_CECI(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, CECI, __x)
+#define AV8100_GENERAL_INTERRUPT_CECI_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, CECI, __x)
+#define AV8100_GENERAL_INTERRUPT_HDCPI_SHIFT 4
+#define AV8100_GENERAL_INTERRUPT_HDCPI_MASK 0x00000010
+#define AV8100_GENERAL_INTERRUPT_HDCPI(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, HDCPI, __x)
+#define AV8100_GENERAL_INTERRUPT_HDCPI_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, HDCPI, __x)
+#define AV8100_GENERAL_INTERRUPT_UOVBI_SHIFT 5
+#define AV8100_GENERAL_INTERRUPT_UOVBI_MASK 0x00000020
+#define AV8100_GENERAL_INTERRUPT_UOVBI(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, UOVBI, __x)
+#define AV8100_GENERAL_INTERRUPT_UOVBI_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, UOVBI, __x)
+#define AV8100_GENERAL_INTERRUPT_TEI_SHIFT 6
+#define AV8100_GENERAL_INTERRUPT_TEI_MASK 0x00000040
+#define AV8100_GENERAL_INTERRUPT_TEI(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, TEI, __x)
+#define AV8100_GENERAL_INTERRUPT_TEI_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, TEI, __x)
+#define AV8100_GENERAL_STATUS 0x00000006
+#define AV8100_GENERAL_STATUS_CECREC_SHIFT 1
+#define AV8100_GENERAL_STATUS_CECREC_MASK 0x00000002
+#define AV8100_GENERAL_STATUS_CECREC(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_STATUS, CECREC, __x)
+#define AV8100_GENERAL_STATUS_CECREC_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_STATUS, CECREC, __x)
+#define AV8100_GENERAL_STATUS_CECTRX_SHIFT 2
+#define AV8100_GENERAL_STATUS_CECTRX_MASK 0x00000004
+#define AV8100_GENERAL_STATUS_CECTRX(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_STATUS, CECTRX, __x)
+#define AV8100_GENERAL_STATUS_CECTRX_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_STATUS, CECTRX, __x)
+#define AV8100_GENERAL_STATUS_UC_SHIFT 3
+#define AV8100_GENERAL_STATUS_UC_MASK 0x00000008
+#define AV8100_GENERAL_STATUS_UC(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_STATUS, UC, __x)
+#define AV8100_GENERAL_STATUS_UC_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_STATUS, UC, __x)
+#define AV8100_GENERAL_STATUS_ONUVB_SHIFT 4
+#define AV8100_GENERAL_STATUS_ONUVB_MASK 0x00000010
+#define AV8100_GENERAL_STATUS_ONUVB(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_STATUS, ONUVB, __x)
+#define AV8100_GENERAL_STATUS_ONUVB_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_STATUS, ONUVB, __x)
+#define AV8100_GENERAL_STATUS_HDCPS_SHIFT 5
+#define AV8100_GENERAL_STATUS_HDCPS_MASK 0x000000E0
+#define AV8100_GENERAL_STATUS_HDCPS(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_STATUS, HDCPS, __x)
+#define AV8100_GENERAL_STATUS_HDCPS_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_STATUS, HDCPS, __x)
+#define AV8100_GPIO_CONFIGURATION 0x00000007
+#define AV8100_GPIO_CONFIGURATION_DAT3DIR_SHIFT 0
+#define AV8100_GPIO_CONFIGURATION_DAT3DIR_MASK 0x00000001
+#define AV8100_GPIO_CONFIGURATION_DAT3DIR(__x) \
+ AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, DAT3DIR, __x)
+#define AV8100_GPIO_CONFIGURATION_DAT3DIR_GET(__x) \
+ AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, DAT3DIR, __x)
+#define AV8100_GPIO_CONFIGURATION_DAT3VAL_SHIFT 1
+#define AV8100_GPIO_CONFIGURATION_DAT3VAL_MASK 0x00000002
+#define AV8100_GPIO_CONFIGURATION_DAT3VAL(__x) \
+ AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, DAT3VAL, __x)
+#define AV8100_GPIO_CONFIGURATION_DAT3VAL_GET(__x) \
+ AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, DAT3VAL, __x)
+#define AV8100_GPIO_CONFIGURATION_DAT2DIR_SHIFT 2
+#define AV8100_GPIO_CONFIGURATION_DAT2DIR_MASK 0x00000004
+#define AV8100_GPIO_CONFIGURATION_DAT2DIR(__x) \
+ AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, DAT2DIR, __x)
+#define AV8100_GPIO_CONFIGURATION_DAT2DIR_GET(__x) \
+ AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, DAT2DIR, __x)
+#define AV8100_GPIO_CONFIGURATION_DAT2VAL_SHIFT 3
+#define AV8100_GPIO_CONFIGURATION_DAT2VAL_MASK 0x00000008
+#define AV8100_GPIO_CONFIGURATION_DAT2VAL(__x) \
+ AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, DAT2VAL, __x)
+#define AV8100_GPIO_CONFIGURATION_DAT2VAL_GET(__x) \
+ AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, DAT2VAL, __x)
+#define AV8100_GPIO_CONFIGURATION_DAT1DIR_SHIFT 4
+#define AV8100_GPIO_CONFIGURATION_DAT1DIR_MASK 0x00000010
+#define AV8100_GPIO_CONFIGURATION_DAT1DIR(__x) \
+ AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, DAT1DIR, __x)
+#define AV8100_GPIO_CONFIGURATION_DAT1DIR_GET(__x) \
+ AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, DAT1DIR, __x)
+#define AV8100_GPIO_CONFIGURATION_DAT1VAL_SHIFT 5
+#define AV8100_GPIO_CONFIGURATION_DAT1VAL_MASK 0x00000020
+#define AV8100_GPIO_CONFIGURATION_DAT1VAL(__x) \
+ AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, DAT1VAL, __x)
+#define AV8100_GPIO_CONFIGURATION_DAT1VAL_GET(__x) \
+ AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, DAT1VAL, __x)
+#define AV8100_GPIO_CONFIGURATION_UCDBG_SHIFT 6
+#define AV8100_GPIO_CONFIGURATION_UCDBG_MASK 0x00000040
+#define AV8100_GPIO_CONFIGURATION_UCDBG(__x) \
+ AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, UCDBG, __x)
+#define AV8100_GPIO_CONFIGURATION_UCDBG_GET(__x) \
+ AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, UCDBG, __x)
+#define AV8100_GENERAL_CONTROL 0x00000008
+#define AV8100_GENERAL_CONTROL_FDL_SHIFT 4
+#define AV8100_GENERAL_CONTROL_FDL_MASK 0x00000010
+#define AV8100_GENERAL_CONTROL_FDL_HIGH 1
+#define AV8100_GENERAL_CONTROL_FDL_LOW 0
+#define AV8100_GENERAL_CONTROL_FDL(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_CONTROL, FDL, __x)
+#define AV8100_GENERAL_CONTROL_FDL_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_CONTROL, FDL, __x)
+#define AV8100_GENERAL_CONTROL_HLD_SHIFT 5
+#define AV8100_GENERAL_CONTROL_HLD_MASK 0x00000020
+#define AV8100_GENERAL_CONTROL_HLD_HIGH 1
+#define AV8100_GENERAL_CONTROL_HLD_LOW 0
+#define AV8100_GENERAL_CONTROL_HLD(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_CONTROL, HLD, __x)
+#define AV8100_GENERAL_CONTROL_HLD_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_CONTROL, HLD, __x)
+#define AV8100_GENERAL_CONTROL_WA_SHIFT 6
+#define AV8100_GENERAL_CONTROL_WA_MASK 0x00000040
+#define AV8100_GENERAL_CONTROL_WA_HIGH 1
+#define AV8100_GENERAL_CONTROL_WA_LOW 0
+#define AV8100_GENERAL_CONTROL_WA(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_CONTROL, WA, __x)
+#define AV8100_GENERAL_CONTROL_WA_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_CONTROL, WA, __x)
+#define AV8100_GENERAL_CONTROL_RA_SHIFT 7
+#define AV8100_GENERAL_CONTROL_RA_MASK 0x00000080
+#define AV8100_GENERAL_CONTROL_RA_HIGH 1
+#define AV8100_GENERAL_CONTROL_RA_LOW 0
+#define AV8100_GENERAL_CONTROL_RA(__x) \
+ AV8100_VAL2REG(AV8100_GENERAL_CONTROL, RA, __x)
+#define AV8100_GENERAL_CONTROL_RA_GET(__x) \
+ AV8100_REG2VAL(AV8100_GENERAL_CONTROL, RA, __x)
+#define AV8100_FIRMWARE_DOWNLOAD_ENTRY 0x0000000F
+#define AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY_SHIFT 0
+#define AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY_MASK 0x000000FF
+#define AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY(__x) \
+ AV8100_VAL2REG(AV8100_FIRMWARE_DOWNLOAD_ENTRY, MBYTE_CODE_ENTRY, __x)
+#define AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY_GET(__x) \
+ AV8100_REG2VAL(AV8100_FIRMWARE_DOWNLOAD_ENTRY, MBYTE_CODE_ENTRY, __x)
diff --git a/drivers/video/av8100/av8100v2_fw.h b/drivers/video/av8100/av8100v2_fw.h
new file mode 100644
index 00000000000..2f43fc37c4d
--- /dev/null
+++ b/drivers/video/av8100/av8100v2_fw.h
@@ -0,0 +1,1165 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Author: Per Persson <per.xb.persson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+/* AV8100v2 Firmware version : V1.03 */
+#define AV8100_FW_SIZE_V2 18432
+char av8100_fw_buff_v2[AV8100_FW_SIZE_V2] = {
+0x80,0xfe,0xcb,0xfe,0x73,0xf4,0x2a,0xf6,0x2a,0xf6,0xc1,0xf7,0x29,0xf5,0xc6,0xf7,
+0x0e,0xf9,0xd0,0xfa,0xe5,0xfa,0xf6,0xfa,0x08,0xfb,0x1b,0xfb,0x20,0xfb,0x25,0xfb,
+0x2a,0xfb,0x2f,0xfb,0x44,0xfb,0x7e,0xfb,0x23,0xfc,0x6d,0xf4,0x6d,0xf4,0x6e,0xf4,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0xea,0xad,0xec,0xad,
+0x38,0x20,0x1b,0x72,0x80,0x81,0x4d,0x51,0x4d,0x51,0x4d,0x51,0x4d,0x51,0x4d,0x51,
+0x4d,0x51,0xb4,0x20,0xf4,0x2a,0x5a,0x90,0x82,0xfe,0xcd,0x80,0x00,0xaf,0x72,0x93,
+0xa3,0x20,0x5f,0x90,0x80,0x80,0x97,0x90,0x8d,0x20,0x0f,0xab,0x01,0xa6,0x88,0x89,
+0x90,0x96,0xad,0x97,0x90,0x9a,0xad,0x8b,0x93,0x9e,0xad,0x97,0x90,0xa2,0xad,0x80,
+0xb7,0xa6,0xad,0x81,0xb7,0xaa,0xad,0x82,0xb7,0xae,0xad,0x26,0x31,0x20,0x08,0x72,
+0x82,0xb7,0x21,0xa6,0x81,0xb7,0xc2,0xa6,0x80,0xb7,0x01,0xa6,0xb4,0x20,0xf5,0x2a,
+0x5a,0x90,0x80,0x00,0xa7,0x72,0x93,0xcc,0xad,0x49,0x27,0x97,0x90,0x5d,0x90,0xd4,
+0xad,0x82,0xb7,0xd8,0xad,0x81,0xb7,0xdc,0xad,0x80,0xb7,0xe0,0xad,0xff,0xae,0x90,
+0x81,0x59,0x29,0xea,0x26,0x5a,0xfb,0x38,0x20,0x07,0x72,0x4d,0x38,0x20,0x1a,0x72,
+0x49,0x00,0x38,0x20,0x05,0x72,0xbc,0xff,0xcd,0x08,0xae,0xf3,0x20,0x79,0x24,0x49,
+0x44,0x24,0x49,0x23,0x24,0x49,0x0b,0xad,0x82,0xfe,0xcd,0x9e,0x82,0xfe,0xcd,0x9f,
+0x5b,0x82,0xfe,0xcd,0x80,0xb6,0x82,0xfe,0xcd,0x81,0xb6,0x82,0xfe,0xcd,0x82,0xb6,
+0x82,0xad,0x9f,0x90,0x86,0xad,0x85,0x90,0x84,0x42,0x8c,0x20,0x9f,0x90,0x01,0xab,
+0x0f,0xa6,0x2a,0x31,0x20,0x08,0x72,0xfb,0x38,0x20,0x07,0x72,0x4d,0x38,0x20,0x1a,
+0x72,0xbc,0xff,0xcd,0xfb,0x38,0x20,0x07,0x72,0x30,0x20,0x10,0x72,0x31,0x20,0x1e,
+0x72,0x30,0x20,0x1c,0x72,0x95,0x05,0xa0,0x9e,0x3d,0x18,0xcc,0x5f,0x90,0x5f,0x4f,
+0x07,0x38,0x20,0x05,0x72,0x0c,0x39,0x20,0x05,0x72,0x81,0x41,0x29,0x38,0x20,0x18,
+0x72,0xd5,0x26,0x5a,0xfb,0x38,0x20,0x07,0x72,0x9d,0x9d,0x4d,0x38,0x20,0x1a,0x72,
+0x4d,0xae,0xff,0xcd,0x4d,0xae,0xff,0xcd,0x38,0x20,0x1b,0x72,0x4d,0x4d,0x4d,0x4d,
+0x4d,0x38,0x20,0x19,0x72,0x04,0x25,0x49,0x38,0x20,0x18,0x72,0x08,0xae,0x34,0x20,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0xa5,0xbe,0x84,0xa3,0xb7,
+0xa4,0xd6,0x92,0x5c,0xa2,0xb7,0xa4,0xd6,0x92,0x5c,0xa1,0xb7,0xa4,0xd6,0x92,0x01,
+0xae,0xa0,0xb7,0xa4,0xc6,0x92,0x88,0xa5,0xbf,0x81,0xa0,0xb7,0xa4,0xc2,0x92,0xa0,
+0xb6,0xa1,0xb7,0xa4,0xd2,0x92,0x5a,0xa1,0xb6,0xa2,0xb7,0xa4,0xd2,0x92,0x5a,0xa2,
+0xb6,0xa3,0xb7,0xa4,0xd0,0x92,0xa3,0xb6,0x03,0xae,0xa5,0xbf,0x81,0xa3,0xb7,0xa4,
+0xda,0x92,0x5c,0xa3,0xb6,0xa2,0xb7,0xa4,0xda,0x92,0x5c,0xa2,0xb6,0xa1,0xb7,0xa4,
+0xda,0x92,0x01,0xae,0xa1,0xb6,0xa0,0xb7,0xa4,0xca,0x92,0xa0,0xb6,0xa5,0xbf,0xf1,
+0xfc,0xcc,0xc1,0xfd,0xcd,0x81,0xa5,0xbe,0xe9,0x26,0x4a,0xa4,0x00,0x39,0x72,0xa4,
+0x00,0x69,0x72,0x5a,0xa4,0x00,0x69,0x72,0x5a,0xa4,0x00,0x68,0x72,0x03,0xae,0xa5,
+0xbf,0x1b,0x27,0x4d,0x81,0xa0,0xb7,0xa4,0xc9,0x92,0xa0,0xb6,0xa1,0xb7,0xa4,0xd9,
+0x92,0x5a,0xa1,0xb6,0xa2,0xb7,0xa4,0xd9,0x92,0x5a,0xa2,0xb6,0xa3,0xb7,0xa4,0xdb,
+0x92,0xa3,0xb6,0x03,0xae,0xa5,0xbf,0xf1,0xfc,0xcc,0x79,0xfd,0xcd,0x81,0x01,0xa6,
+0x02,0x20,0xff,0xa6,0x04,0x24,0x08,0x27,0xa4,0xd1,0x92,0xa3,0xb6,0xa5,0x3c,0x09,
+0x26,0xa4,0xd1,0x92,0xa2,0xb6,0xa5,0x3c,0x12,0x26,0xa4,0xd1,0x92,0xa1,0xb6,0xa5,
+0x3c,0x23,0x26,0xa4,0xd1,0x92,0xa0,0xb6,0xa5,0x3f,0x81,0xa0,0x3c,0x02,0x24,0xa1,
+0xb7,0xa1,0xb9,0x9f,0xa2,0xb7,0xa2,0xbb,0x42,0x93,0x0f,0x27,0x4d,0x84,0x37,0xfd,
+0xcd,0xa8,0xb6,0x05,0x27,0xa7,0xbe,0xa3,0xb7,0xa2,0xbf,0x42,0x93,0xa8,0xb6,0xa1,
+0xb7,0xa0,0xbf,0x42,0xa7,0xb6,0x89,0xa8,0xb7,0x81,0xa0,0x3f,0xa1,0x3f,0xa2,0xbf,
+0xa3,0xb7,0x81,0xa5,0xbe,0x84,0xa4,0xd7,0x92,0xa3,0xb6,0x5c,0xa4,0xd7,0x92,0xa2,
+0xb6,0x5c,0xa4,0xd7,0x92,0xa1,0xb6,0x01,0xae,0xa4,0xc7,0x92,0xa0,0xb6,0x88,0xa5,
+0xbf,0x81,0xa5,0xbe,0xa4,0xd7,0x92,0xa3,0xb6,0x5c,0xa4,0xd7,0x92,0xa2,0xb6,0x5c,
+0xa4,0xd7,0x92,0xa1,0xb6,0x01,0xae,0xa4,0xc7,0x92,0xa0,0xb6,0xa5,0xbf,0x81,0x01,
+0xa6,0x02,0x27,0x03,0x6d,0x04,0x26,0x02,0x6d,0x08,0x26,0x01,0x6d,0x0e,0x26,0x7d,
+0x81,0x84,0xa3,0xb7,0x03,0xe6,0xa2,0xb7,0x02,0xe6,0xa1,0xb7,0x01,0xe6,0xa0,0xb7,
+0xf6,0x88,0x81,0x01,0xa6,0x02,0x27,0xa3,0x3d,0x04,0x26,0xa2,0x3d,0x08,0x26,0xa1,
+0x3d,0x0e,0x26,0xa0,0x3d,0x81,0xf5,0x26,0x4a,0xa0,0x39,0xa1,0x39,0xa2,0x39,0xa3,
+0x38,0x0b,0x27,0x4d,0x81,0xa0,0x3f,0xa1,0x3f,0x81,0xa0,0xb7,0xa1,0xb7,0xff,0xa6,
+0x07,0x2a,0xa2,0xbf,0xa3,0xb7,0x81,0x41,0xa8,0xbb,0x41,0x52,0x93,0x84,0xa8,0xb7,
+0xa8,0xbb,0x52,0x01,0x7b,0xa7,0xbe,0xa8,0xb7,0x52,0x9f,0x90,0x88,0x81,0xa5,0xbe,
+0xa3,0xb7,0xa4,0xd6,0x92,0x5c,0xa2,0xb7,0xa4,0xd6,0x92,0x5c,0xa1,0xb7,0xa4,0xd6,
+0x92,0x01,0xae,0xa0,0xb7,0xa4,0xc6,0x92,0xa5,0xbf,0x81,0xa0,0x3f,0xa2,0xb7,0xa1,
+0xbf,0x5c,0x01,0x24,0xa2,0xbb,0x42,0x93,0xa0,0xb6,0xa3,0xb7,0xa2,0xbf,0x42,0x93,
+0xa0,0xbf,0x80,0xaa,0x00,0xc7,0x51,0x20,0xc6,0x50,0x20,0x11,0x72,0x80,0x85,0x90,
+0xa6,0x00,0x32,0xa5,0x00,0x32,0xa4,0x00,0x32,0xa9,0x00,0x32,0xa8,0x00,0x32,0xa7,
+0x00,0x32,0x84,0x84,0x84,0x84,0x00,0x18,0xcd,0x63,0xa6,0x05,0x20,0xd9,0x01,0x5a,
+0x72,0xd8,0x01,0x5a,0x72,0x04,0x26,0xd9,0x01,0xc6,0x0f,0x27,0xd8,0x01,0xca,0xd9,
+0x01,0xc6,0x00,0x18,0xcd,0x12,0xa6,0xc0,0x00,0x5f,0x72,0x09,0x27,0xc0,0x00,0xc6,
+0xa1,0x01,0x5f,0x72,0xd8,0x01,0x5f,0x72,0xd9,0x01,0x18,0x35,0x08,0x25,0x00,0xa2,
+0xd8,0x01,0xc6,0x19,0xa0,0xd9,0x01,0xc6,0x18,0x20,0xa1,0x01,0x01,0x35,0x06,0x27,
+0x10,0xa5,0x04,0x7b,0x01,0x6b,0x10,0x40,0xc6,0x02,0x6b,0x11,0x40,0xc6,0x03,0x6b,
+0x12,0x40,0xc6,0x04,0x6b,0x13,0x40,0xc6,0xdc,0xc6,0xcd,0x46,0x20,0xc7,0x46,0x20,
+0xc6,0x41,0x20,0x5f,0x72,0x0a,0x42,0x20,0x0d,0x72,0x88,0x88,0x88,0x88,0xa7,0x00,
+0x3b,0xa8,0x00,0x3b,0xa9,0x00,0x3b,0xa4,0x00,0x3b,0xa5,0x00,0x3b,0xa6,0x00,0x3b,
+0x89,0x90,0x80,0x85,0x90,0xa6,0x00,0x32,0xa5,0x00,0x32,0xa4,0x00,0x32,0xa9,0x00,
+0x32,0xa8,0x00,0x32,0xa7,0x00,0x32,0x00,0x18,0xcd,0x15,0x20,0x10,0x72,0x07,0x27,
+0x09,0x2b,0x10,0xb6,0x12,0x20,0x01,0x35,0xa7,0x00,0x3b,0xa8,0x00,0x3b,0xa9,0x00,
+0x3b,0xa4,0x00,0x3b,0xa5,0x00,0x3b,0xa6,0x00,0x3b,0x89,0x90,0x80,0x0c,0x40,0x00,
+0x35,0x0d,0x40,0x00,0x35,0x0e,0x40,0x00,0x35,0x0f,0x40,0x04,0x35,0x11,0x20,0x80,
+0x35,0x80,0x11,0x20,0x40,0x35,0x80,0x11,0x20,0x20,0x35,0x80,0x11,0x20,0x10,0x35,
+0x80,0x11,0x20,0x08,0x35,0x80,0x17,0x20,0x14,0x72,0x80,0x17,0x20,0x15,0x72,0x05,
+0x17,0x20,0x05,0x72,0x11,0x20,0x04,0x35,0x80,0xe6,0x01,0xc7,0x4a,0x05,0x20,0x1a,
+0x72,0x06,0x20,0x18,0x72,0x11,0x20,0xc7,0x02,0xa6,0x80,0xe6,0x01,0xc7,0x05,0x20,
+0x1a,0x72,0x06,0x20,0x19,0x72,0x11,0x20,0xc7,0x01,0xa6,0x80,0x04,0x88,0x00,0x35,
+0x05,0x88,0x30,0x35,0x06,0x88,0x00,0x35,0x07,0x88,0x00,0x35,0x10,0x20,0x80,0x35,
+0x81,0xef,0xfc,0xcd,0xbc,0xae,0xa4,0x00,0x84,0x35,0x81,0xa4,0xb7,0x00,0xa9,0x41,
+0x01,0xab,0x80,0x85,0x90,0xa6,0x00,0x32,0xa5,0x00,0x32,0xa4,0x00,0x32,0xa9,0x00,
+0x32,0xa8,0x00,0x32,0xa7,0x00,0x32,0xa3,0x00,0x32,0xa2,0x00,0x32,0xa1,0x00,0x32,
+0xa0,0x00,0x32,0x84,0x84,0x84,0x84,0x84,0x84,0xef,0xfc,0xcd,0xa0,0xae,0xa4,0x00,
+0x84,0x35,0xc1,0xfd,0xcd,0x33,0xad,0x5b,0xa0,0x3f,0xa1,0x3f,0xa2,0x1f,0x0e,0xfd,
+0xcd,0xf1,0x01,0xce,0xf2,0x01,0xc6,0x03,0x6b,0x80,0xa4,0x03,0x7b,0x04,0x6b,0x4f,
+0x01,0x6b,0xa0,0x84,0xc6,0x02,0x6b,0xa1,0x84,0xc6,0x03,0x6b,0xa2,0x84,0xc6,0x04,
+0x6b,0xa3,0x84,0xc6,0x84,0x84,0xf1,0x01,0xcf,0xf2,0x01,0xc7,0x35,0xc7,0xcd,0xbc,
+0x00,0xce,0xbd,0x00,0xc6,0xf3,0x01,0x3b,0xf4,0x01,0x3b,0x0f,0x20,0x19,0xc7,0xcd,
+0xbc,0x00,0xce,0xbd,0x00,0xc6,0xf3,0x01,0x3b,0xf4,0x01,0x3b,0x11,0x24,0x05,0xe2,
+0x72,0xf3,0x01,0xc6,0x06,0xe0,0x72,0xf4,0x01,0xc6,0x1f,0x24,0x05,0xe2,0x72,0xbc,
+0x00,0xc6,0x06,0xe0,0x72,0xbd,0x00,0xc6,0x1c,0x25,0xf3,0x01,0xc2,0x05,0x7b,0xf4,
+0x01,0xc0,0x06,0x7b,0x0c,0x24,0xbc,0x00,0xc2,0x05,0x7b,0xbd,0x00,0xc0,0x06,0x7b,
+0x5c,0x20,0xf1,0x01,0xcf,0xbc,0x00,0xce,0xf2,0x01,0xbd,0x00,0x55,0x0d,0x26,0x70,
+0x01,0xc6,0x0d,0x20,0xf3,0x01,0xce,0xf2,0x01,0xc7,0xf4,0x01,0xc6,0x0b,0x27,0x4a,
+0x6f,0x01,0xc6,0x07,0x20,0x01,0x35,0x07,0x20,0x03,0x35,0x08,0x26,0x04,0xa1,0x05,
+0x20,0x1d,0x72,0x05,0x20,0x1c,0x72,0x08,0x25,0x02,0xa1,0xbb,0x00,0xc6,0x1b,0x26,
+0xbc,0x00,0xc1,0x05,0x7b,0x22,0x26,0xbd,0x00,0xc1,0x06,0x7b,0x29,0x26,0x4a,0x6f,
+0x01,0xc6,0xf3,0x01,0x5f,0x72,0xf4,0x01,0xc7,0x06,0xa6,0xc6,0xfa,0xcd,0xa2,0xb7,
+0x18,0xaa,0xa2,0xb6,0x07,0xfe,0xcd,0xbe,0xfa,0xcd,0x5b,0x12,0x20,0x0a,0xa6,0xc6,
+0xfa,0xcd,0xa2,0x18,0x07,0xfe,0xcd,0xbe,0xfa,0xcd,0x5b,0x10,0x24,0x00,0xa2,0x05,
+0x7b,0x0a,0xa0,0x06,0x7b,0x1a,0x25,0x00,0xa2,0x05,0x7b,0x06,0xa0,0x06,0x7b,0x03,
+0x6b,0xc7,0xa4,0x03,0x7b,0x01,0x6b,0xbc,0x84,0xc6,0x02,0x6b,0xbd,0x84,0xc6,0x03,
+0x6b,0xbe,0x84,0xc6,0x04,0x6b,0xbf,0x84,0xc6,0x57,0x27,0x70,0x01,0xc6,0x06,0x6b,
+0xa7,0x83,0xc6,0x05,0x6b,0xa6,0x83,0xc6,0xf2,0x01,0x5f,0x72,0xf1,0x01,0x5f,0x72,
+0xf4,0x01,0x5f,0x72,0xf3,0x01,0x5f,0x72,0x10,0x20,0x40,0x35,0x88,0x88,0x88,0x88,
+0x88,0x88,0xa0,0x00,0x3b,0xa1,0x00,0x3b,0xa2,0x00,0x3b,0xa3,0x00,0x3b,0xa7,0x00,
+0x3b,0xa8,0x00,0x3b,0xa9,0x00,0x3b,0xa4,0x00,0x3b,0xa5,0x00,0x3b,0xa6,0x00,0x3b,
+0x89,0x90,0x81,0x48,0x83,0x00,0x35,0x49,0x83,0x00,0x35,0x4a,0x83,0x00,0x35,0x4b,
+0x83,0x0f,0x35,0x80,0x85,0x90,0xa6,0x00,0x32,0xa5,0x00,0x32,0xa4,0x00,0x32,0xa9,
+0x00,0x32,0xa8,0x00,0x32,0xa7,0x00,0x32,0x84,0x84,0x84,0x84,0xe7,0x01,0x5f,0x72,
+0x07,0xcd,0xcd,0x20,0xad,0x05,0x26,0x4a,0xe7,0x01,0xc6,0x0b,0x26,0x03,0xa1,0x6f,
+0x01,0xc6,0xed,0x01,0x5c,0x72,0x04,0x27,0x0f,0xa1,0xed,0x01,0xc6,0x0b,0x20,0xe6,
+0x01,0x01,0x35,0x11,0x26,0xed,0x01,0x5a,0x72,0x17,0x27,0xed,0x01,0xc6,0x11,0x26,
+0x03,0xea,0x72,0x04,0x7b,0x07,0x27,0x4c,0x03,0x7b,0x05,0x26,0x4c,0x04,0x7b,0x11,
+0x27,0x03,0x7b,0x04,0x26,0x4a,0x04,0x7b,0xac,0xe2,0xcd,0x03,0xee,0x72,0x9f,0x03,
+0x6b,0x04,0xef,0x72,0x03,0xe2,0x72,0x41,0x04,0xe0,0x72,0x5f,0x01,0xa6,0x03,0x6b,
+0x01,0xe2,0x72,0x03,0x7b,0x04,0x6b,0x02,0xe0,0x72,0x04,0x7b,0x0e,0x24,0x03,0xe2,
+0x72,0x9f,0x04,0xe0,0x72,0x46,0x54,0x01,0xef,0x72,0x02,0x6b,0x46,0x54,0x4d,0x01,
+0xce,0x4e,0x01,0xc6,0x08,0x20,0x4d,0x01,0xce,0x4e,0x01,0xc6,0x08,0x26,0x4a,0x46,
+0x01,0xc6,0xe3,0x26,0x03,0xe1,0x72,0xa6,0x83,0xc6,0xeb,0x26,0x04,0xe1,0x72,0xa7,
+0x83,0xc6,0x04,0x6b,0xa7,0x83,0xc6,0x03,0x6b,0xa6,0x83,0xc6,0xce,0xf8,0xcc,0x84,
+0x84,0x84,0x84,0xaf,0x00,0x35,0x35,0xb0,0x00,0x86,0x35,0xb1,0x00,0x37,0x35,0xb2,
+0x00,0xbd,0x35,0xed,0x01,0x0f,0x35,0xef,0x01,0x01,0x35,0xfd,0xf8,0xcd,0x51,0xc7,
+0xcd,0xb3,0x00,0x3b,0xb4,0x00,0x3b,0xb5,0x00,0x3b,0xb6,0x00,0x3b,0x31,0x26,0xef,
+0x01,0xc6,0xd5,0xcc,0xcd,0x03,0x27,0xed,0x01,0xc6,0xe4,0xf8,0xcc,0x03,0x26,0x02,
+0xa1,0xe5,0x01,0xc6,0xce,0xf8,0xcc,0x03,0x27,0x02,0xa1,0x6f,0x01,0xc6,0x10,0x20,
+0x20,0x35,0x88,0x88,0x88,0x88,0xa7,0x00,0x3b,0xa8,0x00,0x3b,0xa9,0x00,0x3b,0xa4,
+0x00,0x3b,0xa5,0x00,0x3b,0xa6,0x00,0x3b,0x89,0x90,0x80,0x10,0x20,0x08,0x35,0x81,
+0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x02,0xab,0x80,0x85,0x90,0xa6,0x00,0x32,
+0xa5,0x00,0x32,0xa4,0x00,0x32,0xa9,0x00,0x32,0xa8,0x00,0x32,0xa7,0x00,0x32,0xa3,
+0x00,0x32,0xa2,0x00,0x32,0xa1,0x00,0x32,0xa0,0x00,0x32,0x84,0x84,0x84,0x84,0x84,
+0xef,0xfc,0xcd,0xa4,0xbf,0x84,0xae,0xa3,0x1a,0x2f,0xad,0x5b,0x09,0x20,0x04,0xae,
+0xa4,0x00,0x44,0x35,0xa0,0x3f,0x3c,0xad,0x5b,0x02,0x6b,0x08,0x84,0xc6,0x03,0x6b,
+0x09,0x84,0xc6,0x04,0x6b,0x0a,0x84,0xc6,0x05,0x6b,0x0b,0x84,0xc6,0xef,0xfc,0xcd,
+0xa4,0xbf,0x84,0xae,0xa3,0x1b,0x5c,0xad,0x5b,0x2d,0x27,0x71,0x01,0xc6,0x32,0x27,
+0xc1,0x00,0xc6,0x02,0x6b,0x84,0x84,0xc6,0x03,0x6b,0x85,0x84,0xc6,0x04,0x6b,0x86,
+0x84,0xc6,0x05,0x6b,0x87,0x84,0xc6,0x84,0x84,0x84,0x92,0xce,0xcd,0x41,0x00,0xa9,
+0x41,0xd3,0xab,0x5f,0x52,0x21,0xae,0xd1,0x00,0xc6,0x02,0x4b,0x10,0x4b,0x00,0x4b,
+0xd1,0x00,0x5c,0x72,0x04,0x20,0xd1,0x00,0x5f,0x72,0x06,0x26,0xa8,0xb1,0xa8,0xbf,
+0x90,0x0d,0x26,0xa7,0xb3,0xa7,0x3f,0xd1,0x00,0xce,0x90,0x4a,0x5a,0x01,0x26,0x4d,
+0x5f,0x3a,0x25,0x02,0xa1,0xd2,0x00,0xc6,0x95,0xcc,0xcd,0xe6,0x01,0x5f,0x72,0x07,
+0x26,0x4a,0xe6,0x01,0xc6,0x06,0x27,0x4a,0x6f,0x01,0xc6,0x6e,0xda,0xcd,0xe8,0x01,
+0xc7,0x06,0x26,0x4a,0xe8,0x01,0xc6,0x85,0x01,0x5c,0x72,0x04,0x27,0x4c,0x85,0x01,
+0xc6,0x0a,0x20,0x85,0x01,0x5f,0x72,0x06,0x27,0xed,0x01,0xc6,0xee,0x01,0x5c,0x72,
+0x04,0x24,0xff,0xa1,0xee,0x01,0xc6,0xe7,0x01,0x01,0x35,0xef,0xfc,0xcd,0xa0,0xae,
+0xa4,0x00,0x84,0x35,0xa0,0x1f,0xb6,0xf7,0xcd,0x5b,0x02,0x6b,0xa0,0x84,0xc6,0x03,
+0x6b,0xa1,0x84,0xc6,0x04,0x6b,0xa2,0x84,0xc6,0x05,0x6b,0xa3,0x84,0xc6,0x84,0x84,
+0x84,0x84,0x51,0xc7,0xcd,0xb3,0x00,0x3b,0xb4,0x00,0x3b,0xb5,0x00,0x3b,0xb6,0x00,
+0x3b,0xef,0x01,0x5f,0x72,0x41,0x25,0x04,0xa1,0xee,0x01,0xc6,0x65,0x27,0x4a,0x6f,
+0x01,0xc6,0xef,0xfc,0xcd,0x9c,0xae,0xa4,0x00,0x83,0x35,0xa0,0xb7,0xa1,0xb7,0xa2,
+0xb7,0x4f,0xa3,0xb7,0x01,0x6b,0x9f,0x83,0xc6,0x05,0x20,0x14,0x72,0x10,0x20,0x06,
+0x35,0x88,0x88,0x88,0x88,0x88,0xa0,0x00,0x3b,0xa1,0x00,0x3b,0xa2,0x00,0x3b,0xa3,
+0x00,0x3b,0xa7,0x00,0x3b,0xa8,0x00,0x3b,0xa9,0x00,0x3b,0xa4,0x00,0x3b,0xa5,0x00,
+0x3b,0xa6,0x00,0x3b,0x89,0x90,0x81,0xa4,0x00,0x8c,0x35,0xa0,0xb7,0xa1,0xb7,0xa2,
+0xb7,0x4f,0xa3,0xb7,0x80,0x85,0x90,0xa6,0x00,0x32,0xa5,0x00,0x32,0xa4,0x00,0x32,
+0xa9,0x00,0x32,0xa8,0x00,0x32,0xa7,0x00,0x32,0xa3,0x00,0x32,0xa2,0x00,0x32,0xa1,
+0x00,0x32,0xa0,0x00,0x32,0x84,0xef,0xfc,0xcd,0x0c,0xae,0x27,0xad,0xf0,0xa4,0x01,
+0x7b,0x86,0x01,0x5f,0x72,0x05,0x20,0x16,0x72,0x06,0x20,0xc7,0x05,0xaa,0x06,0x20,
+0xc6,0x1b,0x27,0x04,0xa5,0x01,0x7b,0xef,0xfc,0xcd,0x0c,0xae,0x48,0xad,0xf0,0xa4,
+0x05,0x20,0x16,0x72,0x06,0x20,0x14,0x72,0x11,0x20,0x86,0x01,0x5a,0x72,0x17,0xf5,
+0xcd,0x02,0xa6,0x05,0x26,0x4a,0x05,0x20,0x4f,0x03,0x25,0x02,0xa1,0x86,0x01,0xc6,
+0xef,0xfc,0xcd,0x10,0xae,0x71,0xad,0x87,0x01,0xd6,0x22,0x27,0x86,0x01,0xce,0x59,
+0x27,0x0f,0xa5,0x01,0x7b,0xef,0xfc,0xcd,0x0c,0xae,0x1c,0xf6,0xcd,0x0f,0xa4,0x05,
+0x20,0x16,0x72,0x06,0x20,0x12,0x72,0x73,0x01,0x01,0x35,0x18,0x27,0x20,0xa5,0x01,
+0x7b,0x98,0xad,0x4f,0x05,0x27,0x80,0xa5,0x01,0x7b,0x75,0x01,0xd7,0x17,0x8c,0xc6,
+0x74,0x01,0x5c,0x72,0x74,0x01,0xce,0x0f,0x27,0x80,0xa5,0x07,0x20,0x74,0x01,0xcf,
+0x06,0x20,0x13,0x72,0x09,0x27,0x10,0xa5,0x20,0x26,0x73,0x01,0xce,0x01,0x6b,0x0f,
+0x8c,0xc6,0x10,0x20,0x10,0x35,0x88,0xa0,0x00,0x3b,0xa1,0x00,0x3b,0xa2,0x00,0x3b,
+0xa3,0x00,0x3b,0xa7,0x00,0x3b,0xa8,0x00,0x3b,0xa9,0x00,0x3b,0xa4,0x00,0x3b,0xa5,
+0x00,0x3b,0xa6,0x00,0x3b,0x89,0x90,0xef,0xfc,0xcc,0x0c,0xae,0xa4,0x00,0x8c,0x35,
+0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x80,0x85,0x90,0xa6,0x00,0x32,0xa5,
+0x00,0x32,0xa4,0x00,0x32,0xa9,0x00,0x32,0xa8,0x00,0x32,0xa7,0x00,0x32,0x84,0x84,
+0x84,0x84,0xa0,0x84,0xc7,0x01,0x7b,0xa1,0x84,0xc7,0x02,0x7b,0xa2,0x84,0xc7,0x03,
+0x7b,0xa3,0x84,0xc7,0x04,0x7b,0xe7,0x01,0x01,0x35,0x01,0x6b,0x7f,0xa4,0x01,0x7b,
+0x0a,0x20,0x01,0x6b,0x80,0xaa,0x01,0x7b,0x12,0x27,0x02,0xa1,0xe5,0x01,0xc6,0x0f,
+0x26,0x03,0xa1,0x04,0x27,0x02,0xa1,0x6f,0x01,0xc6,0x1a,0x27,0x70,0x01,0xc6,0x05,
+0x26,0x71,0x01,0xc6,0x01,0x6b,0xa0,0x84,0xc6,0x02,0x6b,0xa1,0x84,0xc6,0x03,0x6b,
+0xa2,0x84,0xc6,0x04,0x6b,0xa3,0x84,0xc6,0xee,0x01,0x5f,0x72,0xe5,0x01,0xc7,0x03,
+0xa4,0x83,0x84,0xc6,0xe6,0xc7,0xcd,0x03,0x26,0x4a,0xe4,0x01,0xc6,0x05,0x20,0x12,
+0x72,0x10,0x20,0x01,0x35,0x88,0x88,0x88,0x88,0xa7,0x00,0x3b,0xa8,0x00,0x3b,0xa9,
+0x00,0x3b,0xa4,0x00,0x3b,0xa5,0x00,0x3b,0xa6,0x00,0x3b,0x89,0x90,0x80,0x12,0x20,
+0x10,0x35,0x80,0x03,0xf3,0xcc,0x28,0x4b,0xc6,0xcf,0xcd,0x07,0xf3,0xcc,0xc1,0xa6,
+0x00,0x4b,0x08,0x4b,0x31,0xd0,0xcd,0x07,0xf3,0xcc,0xe0,0xa6,0x01,0x4b,0xe0,0x4b,
+0x88,0xf3,0xcc,0x03,0x26,0x99,0x01,0x5a,0x72,0x81,0x84,0x84,0x99,0x01,0x02,0x35,
+0xa8,0xf2,0xcd,0xe0,0xa6,0x01,0x4b,0xe0,0x4b,0x10,0x27,0x4d,0x1d,0xd4,0xcd,0x28,
+0x27,0x9b,0x01,0xc5,0x9d,0x01,0xc6,0x07,0xf3,0xcc,0xc1,0xa6,0x00,0x4b,0x28,0x4b,
+0x05,0xf3,0xcc,0x01,0x4b,0x90,0x4b,0xc6,0xcf,0xcd,0x0a,0x27,0x9b,0x01,0xc5,0x9d,
+0x01,0xc6,0xc5,0x20,0x28,0x4b,0x07,0xf3,0xcc,0xe0,0xa6,0x01,0x4b,0x90,0x4b,0x8c,
+0xd0,0xcd,0x0c,0x27,0x9b,0x01,0xc5,0x9d,0x01,0xc6,0xdd,0x20,0x08,0x4b,0x07,0xf3,
+0xcc,0x82,0xa6,0x01,0x4b,0x90,0x4b,0x9a,0x01,0x5a,0x72,0xce,0x27,0x9a,0x01,0xc6,
+0x12,0x26,0x4d,0x91,0xd3,0xcd,0x07,0xf3,0xcc,0xc0,0xa6,0x00,0x4b,0x50,0x4b,0xb7,
+0x27,0x4d,0x1d,0xd4,0xcd,0xe8,0x26,0x4d,0x44,0xd1,0xcd,0x03,0xa6,0x26,0x20,0x9a,
+0x01,0x0a,0x35,0xcb,0x27,0x4d,0x1d,0xd4,0xcd,0xd3,0x20,0x60,0x4b,0x04,0x27,0x4d,
+0x44,0xd1,0xcd,0x83,0xa6,0x18,0x27,0x4d,0x73,0xd3,0xcd,0x07,0xf3,0xcc,0x81,0xa6,
+0x00,0x4b,0x60,0x4b,0xec,0x26,0x4d,0x44,0xd1,0xcd,0x02,0xa6,0xf3,0xd2,0xcd,0x07,
+0xf3,0xcc,0xa0,0xa6,0x00,0x4b,0x08,0x4b,0x09,0x27,0x4d,0x2d,0xd2,0xcd,0x06,0x26,
+0x4d,0x44,0xd1,0xcd,0x4c,0x8c,0x20,0x80,0xa6,0x88,0x88,0x4f,0x93,0x20,0x40,0xa6,
+0x00,0x4b,0xa0,0x4b,0x08,0x26,0x4d,0x9c,0xd1,0xcd,0x65,0xf4,0xcc,0x29,0xf4,0xcc,
+0x03,0x26,0x1f,0xa0,0x0e,0xf4,0xcc,0x03,0x26,0x4a,0xf6,0xf3,0xcc,0x03,0x26,0x20,
+0xa0,0xe0,0x27,0x1e,0xa0,0xda,0xf3,0xcc,0x03,0x26,0x4a,0x60,0x27,0x4a,0x39,0x27,
+0x20,0xa0,0xc3,0x27,0x20,0xa0,0x2c,0x27,0x20,0xa0,0x30,0x27,0x20,0xa0,0x65,0xf4,
+0xcc,0x03,0x26,0xa7,0x01,0xc6,0xdd,0x20,0x60,0xa6,0x00,0x4b,0x50,0x4b,0xc6,0xcf,
+0xcd,0x03,0x25,0x61,0xa1,0xa7,0x01,0xc6,0x12,0x27,0x11,0xa1,0xa0,0x01,0xc6,0x07,
+0x27,0x9e,0x01,0xc6,0x81,0x84,0x84,0x9f,0xad,0x20,0xa6,0x00,0x4b,0x50,0x4b,0x0b,
+0x26,0x71,0x01,0xc6,0x05,0x27,0xa7,0x01,0xc6,0x10,0x20,0x4f,0x00,0x4b,0xa0,0x4b,
+0xc6,0xcf,0xcd,0x03,0x27,0xa7,0x01,0xc6,0x0f,0x26,0xa1,0x01,0xc6,0x81,0x84,0x84,
+0x84,0xd3,0xc6,0xcd,0x06,0xee,0x72,0x07,0x7b,0xa7,0x01,0xc7,0x03,0x7b,0x05,0x20,
+0x18,0x72,0x04,0x27,0x01,0xe1,0x72,0xf0,0xa4,0xa7,0x01,0xc6,0x01,0x6b,0xf0,0xa4,
+0x03,0x7b,0x06,0x20,0xc7,0x02,0x6b,0x02,0xea,0x72,0xe0,0xa4,0x03,0x7b,0x02,0x6b,
+0x1f,0xa4,0x06,0x20,0xc6,0x88,0x88,0x88,0xfe,0xce,0x80,0x3d,0xe1,0xb7,0x80,0x3d,
+0xab,0x93,0x80,0x3d,0x25,0x6e,0x9f,0x3d,0x81,0x13,0x00,0x01,0x35,0x04,0x27,0x12,
+0xb7,0xc0,0x84,0xc6,0x50,0x18,0xcd,0x11,0xb7,0x2f,0xf1,0xcd,0x50,0x18,0xcc,0x11,
+0xb7,0xa5,0xef,0xcd,0xd6,0x20,0xa5,0xef,0xcd,0x05,0x26,0x04,0xa1,0x12,0xb6,0x06,
+0x27,0x02,0xa1,0x12,0xb6,0x11,0x26,0x02,0xa1,0x11,0xb6,0xba,0x20,0x90,0xef,0xcd,
+0x1f,0x20,0xd9,0xee,0xcd,0x24,0x20,0x5a,0xee,0xcd,0xc9,0x20,0x11,0xb7,0x5a,0xee,
+0xcd,0x07,0x26,0x02,0xa1,0x11,0xb6,0x81,0x12,0x00,0x18,0x4d,0x55,0x13,0x00,0x19,
+0x4d,0x55,0x14,0x00,0x1a,0x4d,0x55,0x15,0x00,0x1b,0x4d,0x55,0x50,0x18,0xcd,0x11,
+0xb7,0x1e,0xec,0xcd,0x53,0x20,0x80,0xeb,0xcd,0x58,0x20,0xec,0xe8,0xcd,0x45,0x18,
+0xcc,0x57,0xe8,0xcd,0x63,0x20,0x78,0xe8,0xcd,0x68,0x20,0x7f,0xe7,0xcd,0x6d,0x20,
+0x29,0xe7,0xcd,0x72,0x20,0xe9,0xe6,0xcd,0x77,0x20,0x3f,0xe6,0xcd,0x7c,0x20,0x3a,
+0xe5,0xcd,0x81,0x88,0xcd,0xf1,0xd6,0x88,0xce,0xf1,0xd6,0x58,0x97,0x97,0xf2,0xcc,
+0x03,0x25,0x0f,0xa1,0x4a,0x84,0xf2,0x65,0xf2,0x60,0xf2,0x5b,0xf2,0x49,0xf2,0x2c,
+0xf2,0x27,0xf2,0x22,0xf2,0x1c,0xf2,0x17,0xf2,0x12,0xf2,0x0d,0xf2,0x08,0xf2,0x03,
+0xf2,0xfe,0xf1,0x81,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x02,0xab,0xf6,0x20,
+0x01,0xa6,0x81,0x85,0x85,0x85,0x85,0x85,0x06,0x26,0x11,0xbe,0x04,0x20,0x4f,0xed,
+0xc6,0xcd,0x0a,0xa6,0x9a,0x78,0x84,0xc7,0x02,0x7b,0x79,0x84,0xc7,0x03,0x7b,0x7a,
+0x84,0xc7,0x04,0x7b,0x7b,0x84,0xc7,0x05,0x7b,0xef,0xfc,0xcd,0x78,0xae,0xa4,0x00,
+0x84,0x35,0xa0,0x18,0x36,0xad,0x5b,0x02,0x6b,0x78,0x84,0xc6,0x03,0x6b,0x79,0x84,
+0xc6,0x04,0x6b,0x7a,0x84,0xc6,0x05,0x6b,0x7b,0x84,0xc6,0x00,0xce,0xcd,0x01,0xa6,
+0x00,0xce,0xcd,0x4f,0x9b,0x49,0x27,0x01,0xe4,0x72,0x4f,0x01,0x20,0x4c,0x03,0x26,
+0x4a,0x11,0xb6,0x01,0x6b,0x4f,0x01,0x20,0x01,0xa6,0x04,0x26,0x9b,0xfc,0xcd,0xa1,
+0x3f,0xa2,0x3f,0xa3,0x3f,0x77,0xad,0x5b,0x02,0x6b,0xc0,0x84,0xc6,0x03,0x6b,0xc1,
+0x84,0xc6,0x04,0x6b,0xc2,0x84,0xc6,0x05,0x6b,0xc3,0x84,0xc6,0x88,0x88,0x88,0x88,
+0x88,0x81,0xef,0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0x81,0x07,0xfe,0xcd,0xa4,
+0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,0x85,0x85,0x85,0x85,0x85,0x05,0x7b,0xe3,0x01,
+0x01,0x35,0x04,0x27,0x02,0xa1,0x11,0xb6,0x0a,0x26,0x4a,0x13,0xb6,0x05,0x6b,0x01,
+0xa6,0xe1,0x20,0x12,0x00,0xbe,0x01,0x55,0x09,0x20,0x7c,0xce,0xcd,0x05,0x27,0x85,
+0x85,0x4d,0x79,0xc0,0xcd,0x13,0xbe,0x14,0xb6,0x01,0x4b,0x00,0x4b,0x1e,0x20,0x4f,
+0x84,0x84,0x54,0xc1,0xcd,0x13,0xbe,0x14,0xb6,0x15,0x00,0x3b,0x01,0x4b,0x2f,0x20,
+0x7c,0xce,0xcd,0x34,0x27,0x4d,0xb6,0xc1,0xcd,0x3c,0x20,0x9a,0x61,0xad,0xa2,0x18,
+0x5a,0xad,0x5b,0x9b,0x01,0x6b,0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,0x03,0x6b,
+0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,0xc6,0xed,0xc6,0xcd,0xfa,0xa6,0x9a,0x18,0x84,
+0x00,0x35,0x19,0x84,0x03,0x35,0x1a,0x84,0x83,0x35,0x1b,0x84,0x00,0x35,0x14,0x45,
+0x00,0x35,0x15,0x45,0x00,0x35,0x16,0x45,0x00,0x35,0x17,0x45,0x02,0x35,0x25,0xf1,
+0xcd,0xa2,0x16,0xa3,0x12,0x1a,0xf1,0xcd,0x5b,0x9b,0x01,0x6b,0xb4,0x84,0xc6,0x02,
+0x6b,0xb5,0x84,0xc6,0x03,0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,0xc6,0x84,0x84,
+0x84,0x84,0x84,0x84,0x84,0x84,0xd0,0xdf,0xcd,0x6b,0x01,0x3b,0x6c,0x01,0x3b,0x6d,
+0x01,0x3b,0x6e,0x01,0x3b,0x04,0x4b,0xc4,0x4b,0xb4,0x4b,0x00,0x4b,0xff,0xf0,0xcc,
+0xe3,0xf0,0xcc,0x03,0x26,0x4a,0xd2,0xf0,0xcc,0x03,0x26,0x4a,0xc7,0xf0,0xcc,0x03,
+0x26,0x4a,0x15,0x27,0x4a,0x12,0xb6,0xff,0xf0,0xcc,0x03,0x27,0x02,0xa1,0x11,0xb6,
+0x03,0xf1,0xcc,0xe7,0x01,0xc7,0x4c,0x9a,0xef,0xfc,0xcd,0x18,0xae,0xa4,0x00,0x84,
+0x35,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x12,0xb6,0x9b,0x03,0xf1,0xcc,
+0x03,0x27,0x03,0xa1,0x6f,0x01,0xc6,0xe9,0x01,0x5f,0x72,0xea,0x01,0xc7,0x4c,0x08,
+0x20,0x05,0x6b,0x01,0xa6,0xeb,0x01,0x5f,0x72,0x6f,0x01,0x5f,0x72,0x0e,0x27,0x4a,
+0x11,0x27,0x4a,0x14,0x27,0x4a,0x17,0x27,0x4a,0xeb,0x01,0xc7,0x7f,0xa4,0x12,0xb6,
+0x6f,0x01,0x03,0x35,0x54,0x26,0x4a,0x11,0xb6,0xe3,0x01,0x5f,0x72,0x9a,0x18,0x84,
+0x00,0x35,0x19,0x84,0x00,0x35,0x1a,0x84,0x00,0x35,0x1b,0x84,0x00,0x35,0x9b,0x6f,
+0x01,0x5f,0x72,0x05,0x6b,0x4f,0x88,0x88,0x88,0x88,0x88,0x81,0x4f,0x7c,0xce,0xcc,
+0x03,0x27,0x85,0x85,0x4d,0x79,0xc0,0xcd,0x11,0xbe,0x12,0xb6,0x80,0x4b,0x00,0x4b,
+0x81,0xd3,0x00,0xd7,0x11,0xb6,0x97,0x52,0x21,0xae,0x81,0x85,0x85,0x85,0x85,0x85,
+0x4f,0x84,0x84,0x84,0x92,0xce,0xcd,0x00,0xae,0x11,0xa6,0x88,0x04,0x7b,0x88,0x04,
+0x7b,0x88,0x01,0x7b,0xd2,0x00,0x5c,0x72,0x04,0x24,0x03,0xa1,0x08,0x26,0xd2,0x00,
+0xc1,0x04,0x7b,0xe2,0x22,0x05,0xe1,0x72,0x13,0xb6,0x05,0x6b,0x4c,0x9f,0x90,0xd6,
+0x00,0xd7,0x14,0xe6,0x90,0x05,0xe6,0x72,0x97,0x05,0xeb,0x72,0x52,0x21,0xae,0x04,
+0x7b,0x15,0x20,0x4f,0xd5,0x00,0xd7,0x13,0xb6,0xd4,0x00,0xd7,0x12,0xb6,0x54,0xad,
+0x3c,0x24,0x03,0xa1,0x04,0x7b,0xef,0x25,0x03,0xa1,0x05,0x6b,0x4c,0x05,0x7b,0x04,
+0x6b,0x05,0x7b,0x04,0x27,0x6b,0xad,0x05,0x6b,0x4f,0x04,0x6b,0xd2,0x00,0xc6,0x03,
+0x6b,0x10,0xa6,0x02,0x6b,0x02,0xa6,0x63,0x20,0x02,0x6b,0x03,0xef,0x72,0x06,0xa9,
+0x41,0x00,0xab,0x59,0x48,0x59,0x48,0x59,0x48,0x59,0x48,0x59,0x48,0x4a,0x5a,0x01,
+0x26,0x4d,0x5f,0x01,0x6b,0x0f,0xa4,0x11,0xb6,0x22,0x25,0x81,0xa1,0x11,0xb6,0x01,
+0x6b,0x4f,0x88,0x88,0x88,0x88,0x88,0x81,0x85,0x85,0x85,0x85,0x4f,0x9d,0x01,0x01,
+0x35,0x9e,0x01,0xc7,0x4c,0x08,0x20,0x17,0xb7,0x0c,0x26,0x9f,0x01,0xc6,0x16,0xb7,
+0x04,0x7b,0x01,0x6b,0x02,0x6b,0x03,0x6b,0x4f,0x04,0x6b,0xa2,0x01,0xc6,0x15,0xb7,
+0x01,0x7b,0x14,0xb7,0x02,0x7b,0x13,0xb7,0x03,0x7b,0x12,0xb7,0x04,0x7b,0x01,0x6b,
+0xa3,0x01,0xc6,0x02,0x6b,0xa4,0x01,0xc6,0x03,0x6b,0xa5,0x01,0xc6,0x04,0x6b,0xa6,
+0x01,0xc6,0x11,0x00,0x9e,0x01,0x55,0x4a,0x20,0x9d,0x01,0x5f,0x72,0x9e,0x01,0xc7,
+0x4c,0x54,0x20,0x9d,0x01,0x5f,0x72,0x9e,0x01,0x5f,0x72,0x56,0x27,0x4a,0x17,0x27,
+0x4a,0x10,0x27,0x4a,0x11,0xb6,0x9c,0x01,0x08,0x35,0x04,0x27,0x12,0x3d,0x9c,0x01,
+0x5f,0x72,0x88,0x88,0x88,0x88,0x81,0xef,0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,
+0x81,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,0x10,0x4d,0x00,0x35,
+0x11,0x4d,0x00,0x35,0x12,0x4d,0x00,0x35,0x81,0x44,0xd1,0xcd,0x01,0xa6,0xc6,0xcf,
+0xcd,0x04,0x48,0x00,0x35,0x05,0x48,0x00,0x35,0x06,0x48,0x00,0x35,0x07,0x48,0x00,
+0x35,0x31,0xad,0xa3,0x1a,0x81,0x85,0x85,0x85,0x85,0x4f,0x9a,0xa0,0x01,0x18,0x72,
+0xae,0x01,0x1e,0x00,0x55,0xaf,0x01,0x1f,0x00,0x55,0xb0,0x01,0x20,0x00,0x55,0xb1,
+0x01,0x21,0x00,0x55,0xaa,0x01,0x1a,0x00,0x55,0xab,0x01,0x1b,0x00,0x55,0xac,0x01,
+0x1c,0x00,0x55,0xad,0x01,0x1d,0x00,0x55,0xb6,0x01,0x12,0x00,0x55,0xb7,0x01,0x13,
+0x00,0x55,0xb8,0x01,0x14,0x00,0x55,0xb9,0x01,0x15,0x00,0x55,0xb2,0x01,0x16,0x00,
+0x55,0xb3,0x01,0x17,0x00,0x55,0xb4,0x01,0x18,0x00,0x55,0xb5,0x01,0x19,0x00,0x55,
+0x54,0x26,0x28,0xa1,0x11,0xb6,0x5a,0x20,0xa0,0x01,0xc7,0x10,0xa4,0xa0,0x01,0xc6,
+0x64,0x20,0xa0,0x01,0x10,0x72,0x06,0x26,0x27,0xa1,0x11,0xb6,0xd2,0xfc,0xcd,0xa4,
+0xb7,0x48,0xa9,0x41,0x44,0xab,0x52,0x08,0xae,0x11,0xb6,0xae,0xfc,0xcd,0x12,0xae,
+0xd2,0xfc,0xcd,0xa4,0xb7,0x48,0xa9,0x41,0x40,0xab,0x52,0x08,0xae,0x11,0xb6,0xae,
+0xfc,0xcd,0x16,0xae,0x14,0x48,0xae,0x01,0x55,0x15,0x48,0xaf,0x01,0x55,0x16,0x48,
+0xb0,0x01,0x55,0x17,0x48,0xb1,0x01,0x55,0x10,0x48,0xaa,0x01,0x55,0x11,0x48,0xab,
+0x01,0x55,0x12,0x48,0xac,0x01,0x55,0x13,0x48,0xad,0x01,0x55,0x1b,0xee,0xcd,0xa1,
+0x1b,0x45,0xee,0xcd,0x5b,0x01,0x6b,0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,0x03,
+0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,0xc6,0x45,0x26,0x11,0x3d,0xba,0xed,0xcc,
+0x03,0x25,0x28,0xa1,0x11,0xb6,0x14,0xee,0xcc,0x50,0xee,0xcd,0xa1,0x1b,0x45,0xee,
+0xcd,0x5b,0xed,0xc6,0xcd,0x0a,0xa6,0x01,0x6b,0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,
+0xc6,0x03,0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,0xc6,0xa0,0x01,0x10,0x72,0xb0,
+0xed,0xcc,0x03,0x27,0x91,0xa1,0x11,0xb6,0x38,0xee,0xcd,0x13,0x4d,0x03,0x35,0x38,
+0xee,0xcd,0x13,0x4d,0x43,0x35,0x0c,0x4d,0x1e,0x00,0x55,0x0d,0x4d,0x1f,0x00,0x55,
+0x0e,0x4d,0x20,0x00,0x55,0x0f,0x4d,0x21,0x00,0x55,0x08,0x4d,0x1a,0x00,0x55,0x09,
+0x4d,0x1b,0x00,0x55,0x0a,0x4d,0x1c,0x00,0x55,0x0b,0x4d,0x1d,0x00,0x55,0x04,0x4d,
+0x16,0x00,0x55,0x05,0x4d,0x17,0x00,0x55,0x06,0x4d,0x18,0x00,0x55,0x07,0x4d,0x19,
+0x00,0x55,0x00,0x4d,0x12,0x00,0x55,0x01,0x4d,0x13,0x00,0x55,0x02,0x4d,0x14,0x00,
+0x55,0x03,0x4d,0x15,0x00,0x55,0xc4,0x27,0x9b,0xfc,0xcd,0xa0,0x3f,0xa1,0xb7,0x06,
+0xa4,0xa1,0xb6,0xa2,0x3f,0xa3,0x3f,0x45,0xee,0xcd,0x5b,0x01,0x6b,0x14,0x4d,0xc6,
+0x02,0x6b,0x15,0x4d,0xc6,0x03,0x6b,0x16,0x4d,0xc6,0x04,0x6b,0x17,0x4d,0xc6,0xed,
+0xc6,0xcd,0x0f,0xa6,0x38,0xee,0xcd,0x13,0x4d,0x03,0x35,0x38,0xee,0xcd,0x13,0x4d,
+0xc3,0x35,0x25,0x20,0x02,0x6b,0x03,0x6b,0x04,0x6b,0x4f,0x1b,0xee,0xcd,0xa1,0x1a,
+0x45,0xee,0xcd,0x5b,0x01,0x6b,0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,0x03,0x6b,
+0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,0xc6,0x62,0x26,0x80,0xa1,0x11,0xb6,0xf7,0x24,
+0x92,0xa1,0x11,0xb6,0x2a,0xed,0xcc,0x03,0x24,0x80,0xa1,0x11,0xb6,0x9b,0x88,0x88,
+0x88,0x88,0x81,0x48,0x42,0x00,0x35,0x49,0x42,0x00,0x35,0x4a,0x42,0x00,0x35,0x81,
+0x85,0x85,0x85,0x85,0x4f,0x9a,0x47,0xcb,0xcd,0x71,0x01,0x01,0x35,0x62,0xc6,0xcd,
+0x03,0x27,0xc1,0x00,0xc6,0x16,0xad,0x4b,0x42,0x05,0x35,0x04,0x20,0x4b,0x42,0x01,
+0x35,0x06,0x27,0x9b,0x01,0xc6,0xb6,0xc9,0xcd,0xef,0xfc,0xcd,0xb4,0xae,0xa4,0x00,
+0x84,0x35,0xa2,0x16,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0x01,
+0x6b,0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,0x03,0x6b,0xb6,0x84,0xc6,0x04,0x6b,
+0xb7,0x84,0xc6,0x56,0xdf,0xcd,0x50,0x20,0x59,0xad,0x4b,0x42,0x05,0x35,0x04,0x20,
+0x4b,0x42,0x01,0x35,0x06,0x27,0x9b,0x01,0xc6,0x13,0x26,0x4a,0x71,0x01,0xc6,0x69,
+0x20,0x76,0xca,0xcd,0x56,0xc9,0xcd,0x08,0x26,0x11,0x3d,0x9b,0x9b,0x01,0x01,0x35,
+0x04,0x20,0x9b,0x01,0x5f,0x72,0x06,0x26,0x02,0xa1,0x11,0xb6,0x88,0x88,0x88,0x88,
+0x81,0xef,0xfc,0xcd,0x78,0xae,0xa4,0x00,0x84,0x35,0x81,0x18,0x80,0x00,0x35,0x19,
+0x80,0x00,0x35,0x1a,0x80,0x00,0x35,0x81,0x08,0x80,0x00,0x35,0x09,0x80,0x00,0x35,
+0x0a,0x80,0x00,0x35,0x81,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x03,0xab,0x81,
+0x04,0x80,0x00,0x35,0x05,0x80,0x00,0x35,0x06,0x80,0x00,0x35,0x81,0x85,0x85,0x85,
+0x85,0x85,0x85,0x4f,0x9a,0x76,0xca,0xcd,0x70,0x01,0x5f,0x72,0xbc,0x84,0x00,0x35,
+0xbd,0x84,0x00,0x35,0xbe,0x84,0x18,0x35,0xbf,0x84,0x00,0x35,0x45,0xad,0x1b,0x80,
+0x80,0x35,0x14,0x80,0x00,0x35,0x15,0x80,0x00,0x35,0x16,0x80,0x00,0x35,0x17,0x80,
+0x00,0x35,0x4e,0xad,0x0b,0x80,0x00,0x35,0x3c,0xad,0x07,0x80,0x00,0x35,0x00,0x80,
+0x00,0x35,0x01,0x80,0x00,0x35,0x02,0x80,0x00,0x35,0x03,0x80,0x00,0x35,0x76,0xeb,
+0xcd,0xa3,0xb7,0xf8,0xa4,0xa3,0xb6,0x68,0xad,0x5b,0x03,0x6b,0x78,0x84,0xc6,0x04,
+0x6b,0x79,0x84,0xc6,0x05,0x6b,0x7a,0x84,0xc6,0x06,0x6b,0x7b,0x84,0xc6,0x69,0x20,
+0x47,0xcb,0xcd,0x70,0x01,0x01,0x35,0x2f,0xde,0xcd,0xbc,0x84,0x00,0x35,0xbd,0x84,
+0x00,0x35,0xbe,0x84,0x1b,0x35,0xbf,0x84,0x40,0x35,0x04,0x20,0xbf,0x84,0x41,0x35,
+0x06,0x26,0x14,0x3d,0x69,0xeb,0xcd,0x1b,0x80,0x81,0x35,0xef,0xfc,0xcd,0x14,0xae,
+0xa4,0x00,0x80,0x35,0x7a,0xfc,0xcd,0x52,0x80,0xae,0x5c,0xeb,0xcd,0x0b,0x80,0x20,
+0x35,0x04,0x20,0x0b,0x80,0x60,0x35,0x06,0x26,0xda,0x01,0xc7,0x16,0xb6,0xdb,0x01,
+0x60,0x20,0x55,0xdc,0x01,0x61,0x20,0x55,0xdd,0x01,0x62,0x20,0x55,0xde,0x01,0x63,
+0x20,0x55,0x68,0x20,0x21,0x35,0x64,0x20,0xdb,0x01,0x55,0x65,0x20,0xdc,0x01,0x55,
+0x66,0x20,0xdd,0x01,0x55,0x67,0x20,0xde,0x01,0x55,0x9d,0x9d,0x68,0x20,0x27,0x35,
+0x68,0x20,0x52,0x35,0x64,0x20,0x00,0x35,0x65,0x20,0x0f,0x35,0x66,0x20,0x42,0x35,
+0x67,0x20,0x40,0x35,0x68,0x20,0x22,0x35,0x60,0x20,0x6b,0x01,0x55,0x61,0x20,0x6c,
+0x01,0x55,0x62,0x20,0x6d,0x01,0x55,0x63,0x20,0x6e,0x01,0x55,0xdb,0x01,0x9c,0xf2,
+0x55,0xdc,0x01,0x9d,0xf2,0x55,0xdd,0x01,0x9e,0xf2,0x55,0xde,0x01,0x9f,0xf2,0x55,
+0xdf,0x01,0xc7,0xe0,0x01,0x21,0x35,0xe1,0x01,0xe6,0x35,0xe2,0x01,0xf0,0x35,0x23,
+0x20,0xdb,0x01,0xa0,0xf2,0x55,0xdc,0x01,0xa1,0xf2,0x55,0xdd,0x01,0xa2,0xf2,0x55,
+0xde,0x01,0xa3,0xf2,0x55,0xdf,0x01,0xc7,0xe0,0x01,0x21,0x35,0xe1,0x01,0xf0,0x35,
+0xe2,0x01,0x7c,0x35,0x48,0x20,0xdb,0x01,0xa4,0xf2,0x55,0xdc,0x01,0xa5,0xf2,0x55,
+0xdd,0x01,0xa6,0xf2,0x55,0xde,0x01,0xa7,0xf2,0x55,0xdf,0x01,0xc7,0xe0,0x01,0x21,
+0x35,0xe1,0x01,0xf6,0x35,0xe2,0x01,0x94,0x35,0x6d,0x20,0x44,0xeb,0xcd,0x07,0x80,
+0xe0,0x35,0xdb,0x01,0x98,0xf2,0x55,0xdc,0x01,0x99,0xf2,0x55,0xdd,0x01,0x9a,0xf2,
+0x55,0xde,0x01,0x9b,0xf2,0x55,0xdf,0x01,0x5f,0x72,0xe0,0x01,0x2a,0x35,0xe1,0x01,
+0x09,0x35,0xe2,0x01,0x8b,0x35,0x77,0x27,0x4a,0x55,0x27,0x4a,0x33,0x27,0x4a,0x12,
+0xb6,0x10,0x80,0x00,0x35,0x11,0x80,0x00,0x35,0x12,0x80,0x00,0x35,0x13,0x80,0x08,
+0x35,0x44,0xeb,0xcd,0x07,0x80,0xc0,0x35,0xef,0xfc,0xcd,0x5f,0xa4,0x00,0x80,0x35,
+0x7a,0xfc,0xcd,0x06,0xaa,0x41,0x01,0xea,0x72,0x41,0x02,0xea,0x72,0x5f,0x28,0xaa,
+0xc0,0xa4,0x52,0x40,0xae,0x12,0xb6,0x01,0xef,0x72,0x02,0x6b,0x52,0x10,0xae,0x15,
+0xb6,0x76,0xeb,0xcd,0xa3,0x10,0xa3,0x12,0xa3,0x14,0x51,0xeb,0xcd,0x5b,0x03,0x6b,
+0x78,0x84,0xc6,0x04,0x6b,0x79,0x84,0xc6,0x05,0x6b,0x7a,0x84,0xc6,0x06,0x6b,0x7b,
+0x84,0xc6,0xef,0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0xa2,0x16,0x51,0xeb,0xcd,
+0x5b,0x03,0x6b,0xb4,0x84,0xc6,0x04,0x6b,0xb5,0x84,0xc6,0x05,0x6b,0xb6,0x84,0xc6,
+0x06,0x6b,0xb7,0x84,0xc6,0xd2,0xea,0xcc,0x03,0x27,0x4a,0x13,0xb6,0x9b,0x88,0x88,
+0x88,0x88,0x88,0x88,0x81,0x85,0x4f,0x86,0x01,0x5a,0x72,0x9a,0x0c,0x8c,0x00,0x35,
+0x0d,0x8c,0x00,0x35,0x0e,0x8c,0x00,0x35,0x0f,0x8c,0x01,0x35,0x04,0x20,0x0f,0x8c,
+0x03,0x35,0x06,0x26,0x4a,0x86,0x01,0xc6,0xef,0xfc,0xcd,0x10,0xae,0xa4,0x00,0x8c,
+0x35,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0x00,0x87,0x01,0x55,0xef,0xfc,0xcd,
+0x1c,0xae,0xa4,0x00,0x8c,0x35,0x7a,0xfc,0xcd,0x5f,0x0f,0xa4,0x4e,0x87,0x01,0xc6,
+0x9b,0x06,0x20,0xc7,0xfa,0xa4,0x06,0x20,0xc6,0x52,0x27,0x86,0x01,0xc6,0xef,0x25,
+0x86,0x01,0xc1,0x01,0x6b,0x4c,0x9f,0x87,0x01,0xd7,0x12,0xe6,0x01,0xee,0x72,0x0a,
+0x20,0x4f,0x86,0x01,0xc7,0x11,0xb6,0x88,0x81,0x85,0x4f,0x73,0x01,0x5f,0x72,0xef,
+0x25,0x74,0x01,0xc1,0x01,0x6b,0x4c,0x9f,0x14,0xe7,0x75,0x01,0xd6,0x01,0xee,0x72,
+0x0a,0x20,0x4f,0x13,0x00,0x74,0x01,0x55,0x88,0x81,0x4f,0x9a,0xa8,0x84,0x29,0x00,
+0x55,0xa9,0x84,0x2a,0x00,0x55,0xaa,0x84,0x2b,0x00,0x55,0xab,0x84,0x2c,0x00,0x55,
+0xef,0xfc,0xcd,0x48,0xae,0xa4,0x00,0x84,0x35,0x7a,0xfc,0xcd,0x27,0xbe,0x28,0xb6,
+0xef,0xfc,0xcd,0x44,0xae,0xa4,0x00,0x84,0x35,0x7a,0xfc,0xcd,0x25,0xbe,0x26,0xb6,
+0xef,0xfc,0xcd,0x40,0xae,0xa4,0x00,0x84,0x35,0x7a,0xfc,0xcd,0x23,0xbe,0x24,0xb6,
+0xef,0xfc,0xcd,0x3c,0xae,0xa4,0x00,0x84,0x35,0x7a,0xfc,0xcd,0x21,0xbe,0x22,0xb6,
+0xef,0xfc,0xcd,0x38,0xae,0xa4,0x00,0x84,0x35,0x7a,0xfc,0xcd,0x1f,0xbe,0x20,0xb6,
+0xef,0xfc,0xcd,0x34,0xae,0xa4,0x00,0x84,0x35,0x7a,0xfc,0xcd,0x1d,0xbe,0x1e,0xb6,
+0xef,0xfc,0xcd,0x30,0xae,0xa4,0x00,0x84,0x35,0x7a,0xfc,0xcd,0x1b,0xbe,0x1c,0xb6,
+0xef,0xfc,0xcd,0x2c,0xae,0xa4,0x00,0x84,0x35,0x7a,0xfc,0xcd,0x19,0xbe,0x1a,0xb6,
+0xef,0xfc,0xcd,0x28,0xae,0xa4,0x00,0x84,0x35,0x7a,0xfc,0xcd,0x17,0xbe,0x18,0xb6,
+0xef,0xfc,0xcd,0x24,0xae,0xa4,0x00,0x84,0x35,0x7a,0xfc,0xcd,0x15,0xbe,0x16,0xb6,
+0xef,0xfc,0xcd,0x20,0xae,0xa4,0x00,0x84,0x35,0x7a,0xfc,0xcd,0x13,0xbe,0x14,0xb6,
+0xef,0xfc,0xcd,0x1c,0xae,0xa4,0x00,0x84,0x35,0x7a,0xfc,0xcd,0x11,0xbe,0x12,0xb6,
+0x9b,0x81,0x4f,0xe8,0x01,0x01,0x35,0x44,0x01,0xcf,0x1f,0xbe,0x45,0x01,0xc7,0x20,
+0xb6,0x42,0x01,0xcf,0x1d,0xbe,0x43,0x01,0xc7,0x1e,0xb6,0x40,0x01,0xcf,0x1b,0xbe,
+0x41,0x01,0xc7,0x1c,0xb6,0x3e,0x01,0xcf,0x19,0xbe,0x3f,0x01,0xc7,0x1a,0xb6,0x3c,
+0x01,0xcf,0x17,0xbe,0x3d,0x01,0xc7,0x18,0xb6,0x3a,0x01,0xcf,0x15,0xbe,0x3b,0x01,
+0xc7,0x16,0xb6,0x38,0x01,0xcf,0x13,0xbe,0x39,0x01,0xc7,0x14,0xb6,0x36,0x01,0xcf,
+0x11,0xbe,0x37,0x01,0xc7,0x12,0xb6,0x81,0x4f,0x9a,0x30,0x42,0x00,0x35,0x31,0x42,
+0x00,0x35,0x32,0x42,0x00,0x35,0x33,0x42,0x00,0x35,0x6e,0xda,0xcd,0x90,0xdb,0xcd,
+0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0xd0,0xdf,0xcd,0x6b,0x01,0x3b,0x6c,0x01,
+0x3b,0x6d,0x01,0x3b,0x6e,0x01,0x3b,0x5d,0x01,0x3b,0x5e,0x01,0x3b,0x5f,0x01,0x3b,
+0x60,0x01,0x3b,0xbc,0xd7,0xcd,0x9b,0x81,0x85,0x85,0x85,0x85,0x85,0x4f,0xc1,0x00,
+0x01,0x35,0x9a,0x84,0x84,0xc7,0x02,0x7b,0x85,0x84,0xc7,0x03,0x7b,0x86,0x84,0xc7,
+0x04,0x7b,0x87,0x84,0xc7,0x9b,0x05,0x6b,0xfb,0xa4,0x05,0x7b,0x04,0x20,0x04,0xaa,
+0x05,0x7b,0x06,0x27,0x01,0x7b,0x02,0x6b,0x84,0x84,0xc6,0x03,0x6b,0x85,0x84,0xc6,
+0x04,0x6b,0x86,0x84,0xc6,0x05,0x6b,0x87,0x84,0xc6,0x9a,0x62,0xc6,0xcd,0x9b,0x05,
+0x27,0x71,0x01,0xc6,0x00,0xc2,0xcd,0x4e,0xc6,0xcd,0xbf,0x00,0xc7,0x12,0xb6,0x02,
+0x20,0x04,0xa6,0x04,0x26,0x02,0xa1,0x11,0xb6,0x9a,0xef,0xfc,0xcd,0xa4,0xbf,0x84,
+0xae,0xa3,0x1b,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x02,0xab,0x5b,0x9b,0x05,
+0x6b,0x04,0xaa,0x05,0x7b,0x02,0x6b,0x84,0x84,0xc6,0x03,0x6b,0x85,0x84,0xc6,0x04,
+0x6b,0x86,0x84,0xc6,0x05,0x6b,0x87,0x84,0xc6,0x16,0x00,0x01,0x35,0x01,0x6b,0x16,
+0xb6,0xe2,0xe6,0xcc,0xc1,0x00,0x5f,0x72,0x07,0x27,0x17,0x3d,0x88,0x88,0x88,0x88,
+0x88,0x81,0x85,0x85,0x85,0x85,0x85,0x01,0x7b,0xe7,0x01,0x01,0x35,0x9a,0xef,0xfc,
+0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0xa3,0x1f,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,
+0x41,0x02,0xab,0x5b,0xb4,0x84,0xc7,0x02,0x7b,0xb5,0x84,0xc7,0x03,0x7b,0xb6,0x84,
+0xc7,0x04,0x7b,0xb7,0x84,0xc7,0x05,0x7b,0xbb,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,
+0x02,0xab,0x5b,0xa3,0x1e,0xa0,0x3f,0xa1,0x3f,0xa2,0xb7,0x03,0xa4,0xa2,0xb6,0xa3,
+0x3f,0x17,0xfd,0xcd,0x5f,0x90,0xa7,0x00,0x01,0x35,0x5f,0x12,0xb6,0x04,0x6b,0xfc,
+0xa4,0x04,0x7b,0x02,0x6b,0xb4,0x84,0xc6,0x03,0x6b,0xb5,0x84,0xc6,0x04,0x6b,0xb6,
+0x84,0xc6,0x05,0x6b,0xb7,0x84,0xc6,0x21,0xc8,0xcd,0x1c,0xbe,0x20,0xa6,0x9b,0x6b,
+0x01,0x22,0x00,0x55,0x6c,0x01,0x23,0x00,0x55,0x6d,0x01,0x24,0x00,0x55,0x6e,0x01,
+0x25,0x00,0x55,0x14,0x27,0xc0,0xfc,0xcd,0x22,0xae,0x6a,0x01,0xc7,0x12,0xb6,0xbb,
+0x00,0xc7,0x21,0xb6,0xbc,0x00,0xcf,0x1f,0xbe,0xbd,0x00,0xc7,0x20,0xb6,0x64,0x01,
+0xcf,0x19,0xbe,0x65,0x01,0xc7,0x1a,0xb6,0x68,0x01,0xcf,0x17,0xbe,0x69,0x01,0xc7,
+0x18,0xb6,0x62,0x01,0xcf,0x15,0xbe,0x63,0x01,0xc7,0x16,0xb6,0x66,0x01,0xcf,0x13,
+0xbe,0x67,0x01,0xc7,0x14,0xb6,0x37,0xe6,0xcc,0xe4,0x01,0xc7,0x4c,0x37,0xe6,0xcc,
+0x01,0x6b,0x01,0xa6,0x45,0x27,0x4a,0x11,0x27,0x4a,0x0d,0x27,0x4d,0xbb,0x00,0x5f,
+0x72,0xbd,0x00,0x5f,0x72,0xbc,0x00,0x5f,0x72,0x6f,0x01,0xc7,0x11,0xb6,0x01,0x6b,
+0x4f,0x88,0x88,0x88,0x88,0x88,0x00,0x00,0xba,0x42,0x00,0x00,0xb8,0x41,0x0a,0xd7,
+0x23,0x3c,0x00,0x00,0x80,0x3f,0x81,0x07,0xfe,0xcd,0xb3,0xae,0xa4,0x00,0x00,0x35,
+0x81,0xa4,0xb7,0x00,0xa9,0x41,0x17,0xab,0x81,0xa4,0x00,0x80,0x35,0xa0,0xb7,0xa1,
+0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x81,0x8b,0x41,0x00,0xa9,0x41,0x1c,0xab,0x5b,0x20,
+0x80,0x00,0x35,0x21,0x80,0x00,0x35,0x22,0x80,0x00,0x35,0x23,0x80,0x40,0x35,0xef,
+0xfc,0xcd,0x30,0xae,0x1e,0xad,0x16,0x7b,0xef,0xfc,0xcd,0x2c,0xae,0x27,0xad,0x15,
+0x7b,0xef,0xfc,0xcd,0x28,0xae,0x30,0xad,0x14,0x7b,0x73,0xfd,0xcd,0xa4,0xb7,0x00,
+0xa9,0x41,0x13,0xab,0x5b,0x07,0xfe,0xcd,0xdf,0xae,0xa4,0x00,0x01,0x35,0x13,0x6b,
+0x60,0x20,0xc6,0x14,0x6b,0x61,0x20,0xc6,0x15,0x6b,0x62,0x20,0xc6,0x16,0x6b,0x63,
+0x20,0xc6,0x68,0x20,0x26,0x35,0x68,0x20,0x21,0x35,0x68,0x20,0x52,0x35,0x64,0x20,
+0xc7,0x0d,0x7b,0x65,0x20,0xc7,0x0e,0x7b,0x66,0x20,0xc7,0x0f,0x7b,0x67,0x20,0xc7,
+0x10,0x7b,0x60,0x20,0xdb,0x01,0x55,0x61,0x20,0xdc,0x01,0x55,0x62,0x20,0xdd,0x01,
+0x55,0x63,0x20,0xde,0x01,0x55,0xef,0xfc,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x0d,0xab,
+0x5b,0xe4,0xfd,0xcd,0x18,0xe5,0xcd,0x5b,0x20,0xe5,0xcd,0xf0,0x27,0x1b,0xea,0x72,
+0x1c,0x7b,0xf7,0x26,0x4a,0xda,0x01,0xc6,0x01,0xe5,0xcc,0x03,0x27,0x4a,0x70,0x01,
+0xc6,0x84,0x84,0x84,0x84,0x76,0xc7,0xcd,0x88,0x1a,0x7b,0x88,0x1a,0x7b,0x88,0x1a,
+0x7b,0x88,0x1a,0x7b,0x0f,0x20,0x51,0xc7,0xcd,0x88,0x1a,0x7b,0x88,0x1a,0x7b,0x88,
+0x1a,0x7b,0x88,0x1a,0x7b,0x11,0x27,0xed,0x01,0xc6,0xef,0x01,0x5f,0x72,0x04,0x20,
+0x73,0xfd,0xcd,0x18,0xe5,0xcd,0x5b,0x20,0xe5,0xcd,0x0c,0x2b,0xff,0xa2,0x11,0x7b,
+0xfd,0xa0,0x12,0x7b,0x0a,0x2b,0x00,0xa2,0x11,0x7b,0x04,0xa0,0x12,0x6b,0x18,0x7b,
+0x11,0x6b,0x17,0x7b,0x17,0x6b,0x60,0x20,0xc6,0x18,0x6b,0x61,0x20,0xc6,0x19,0x6b,
+0x62,0x20,0xc6,0x1a,0x6b,0x63,0x20,0xc6,0x68,0x20,0x26,0x35,0x68,0x20,0x24,0x35,
+0x64,0x20,0xab,0x00,0x55,0x65,0x20,0xac,0x00,0x55,0x66,0x20,0xad,0x00,0x55,0x67,
+0x20,0xae,0x00,0x55,0x68,0x20,0x21,0x35,0x64,0x20,0xc7,0x05,0x7b,0x65,0x20,0xc7,
+0x06,0x7b,0x66,0x20,0xc7,0x07,0x7b,0x67,0x20,0xc7,0x08,0x7b,0x60,0x20,0xaf,0x00,
+0x55,0x61,0x20,0xb0,0x00,0x55,0x62,0x20,0xb1,0x00,0x55,0x63,0x20,0xb2,0x00,0x55,
+0xab,0x00,0x60,0x20,0x55,0xac,0x00,0x61,0x20,0x55,0xad,0x00,0x62,0x20,0x55,0xae,
+0x00,0x63,0x20,0x55,0x68,0x20,0x21,0x35,0x64,0x20,0xc7,0x01,0x7b,0x65,0x20,0xc7,
+0x02,0x7b,0x66,0x20,0xc7,0x03,0x7b,0x67,0x20,0xc7,0x04,0x7b,0xaf,0x00,0x64,0x20,
+0x55,0xb0,0x00,0x65,0x20,0x55,0xb1,0x00,0x66,0x20,0x55,0xb2,0x00,0x67,0x20,0x55,
+0x68,0x20,0x64,0x35,0x64,0x20,0xaf,0x00,0x55,0x65,0x20,0xb0,0x00,0x55,0x66,0x20,
+0xb1,0x00,0x55,0x67,0x20,0xb2,0x00,0x55,0x68,0x20,0x21,0x35,0x64,0x20,0xc7,0x09,
+0x7b,0x65,0x20,0xc7,0x0a,0x7b,0x66,0x20,0xc7,0x0b,0x7b,0x67,0x20,0xc7,0x0c,0x7b,
+0x68,0x20,0x22,0x35,0xef,0xfc,0xcd,0x60,0xae,0xa4,0x00,0x20,0x35,0x7a,0xfc,0xcd,
+0x1b,0xee,0x72,0x1c,0x7b,0x26,0xe4,0xcc,0x03,0x26,0x1b,0xea,0x72,0x1c,0x7b,0xef,
+0xfc,0xcd,0x18,0xe5,0xcd,0x5b,0xa0,0x3f,0x07,0xfe,0xcd,0x5f,0xa4,0x00,0x84,0x35,
+0xef,0xfc,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x09,0xab,0x5b,0x07,0xfe,0xcd,0x2a,0xae,
+0xa4,0x00,0xe5,0x35,0x06,0x20,0x2e,0xae,0xa4,0x00,0xe5,0x35,0x08,0x26,0x4c,0x85,
+0x01,0xc6,0x05,0x6b,0x32,0xe5,0xc6,0x06,0x6b,0x33,0xe5,0xc6,0x07,0x6b,0x34,0xe5,
+0xc6,0x08,0x6b,0x35,0xe5,0xc6,0x01,0x6b,0x36,0xe5,0xc6,0x02,0x6b,0x37,0xe5,0xc6,
+0x03,0x6b,0x38,0xe5,0xc6,0x04,0x6b,0x39,0xe5,0xc6,0x8b,0x41,0x00,0xa2,0x41,0x1a,
+0xa0,0x5b,0x89,0x88,0x81,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x81,0xa4,
+0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,0x84,0x84,0x84,0x84,0xef,0xfc,0xcd,0x10,0xae,
+0xa4,0x00,0x84,0x35,0xa1,0x1e,0x07,0xfe,0xcd,0x13,0xad,0x5b,0x10,0x84,0xc7,0x01,
+0x7b,0x11,0x84,0xc7,0x02,0x7b,0x12,0x84,0xc7,0x03,0x7b,0x13,0x84,0xc7,0x04,0x7b,
+0x02,0x6b,0x7f,0xa4,0x02,0x7b,0xef,0xfc,0xcd,0x33,0xad,0x5b,0xc1,0xfd,0xcd,0xa4,
+0xb7,0x00,0xa9,0x41,0x07,0xab,0x5b,0xa0,0xb7,0x03,0xa4,0xa0,0xb6,0xa1,0x3f,0xa2,
+0x3f,0xa3,0x3f,0x07,0xfe,0xcd,0x50,0xad,0x5b,0x01,0x6b,0x10,0x84,0xc6,0x02,0x6b,
+0x11,0x84,0xc6,0x03,0x6b,0x12,0x84,0xc6,0x04,0x6b,0x13,0x84,0xc6,0xbb,0xfd,0xcd,
+0xa4,0xb7,0x00,0xa9,0x41,0x07,0xab,0x5b,0x8c,0xfc,0xcd,0x14,0xa6,0xa2,0xe2,0xcd,
+0x0b,0x6b,0x04,0xa6,0x02,0x20,0x03,0xa6,0x06,0x20,0x02,0xa6,0x0a,0x20,0x4c,0x0b,
+0x20,0x09,0x27,0x08,0xa0,0x09,0x27,0x04,0xa0,0x0a,0x27,0x02,0xa0,0x1b,0x27,0x02,
+0xa0,0x0b,0x7b,0x07,0x6b,0x60,0x20,0xc6,0x08,0x6b,0x61,0x20,0xc6,0x09,0x6b,0x62,
+0x20,0xc6,0x0a,0x6b,0x63,0x20,0xc6,0x68,0x20,0x26,0x35,0x68,0x20,0x21,0x35,0x68,
+0x20,0x52,0x35,0x64,0x20,0x00,0x35,0x65,0x20,0x00,0x35,0x66,0x20,0x80,0x35,0x67,
+0x20,0x00,0x35,0x9d,0x9d,0x68,0x20,0x27,0x35,0x60,0x20,0xb7,0x00,0x55,0x61,0x20,
+0xb8,0x00,0x55,0x62,0x20,0xb9,0x00,0x55,0x63,0x20,0xba,0x00,0x55,0x68,0x20,0x61,
+0x35,0x68,0x20,0x52,0x35,0xef,0xfc,0xcd,0x64,0xae,0xa4,0x00,0x20,0x35,0xa2,0xe2,
+0xcd,0x0b,0x7b,0x68,0x20,0x22,0x35,0x60,0x20,0xc7,0x07,0x7b,0x61,0x20,0xc7,0x08,
+0x7b,0x62,0x20,0xc7,0x09,0x7b,0x63,0x20,0xc7,0x0a,0x7b,0x88,0x88,0x88,0x88,0x81,
+0x64,0x20,0x00,0x35,0x65,0x20,0x00,0x35,0x66,0x20,0x00,0x35,0x81,0x84,0xef,0xfc,
+0xcd,0x10,0xae,0xa4,0x00,0x84,0x35,0xa2,0xb7,0x55,0xaa,0xa2,0xb6,0xa3,0xb7,0x55,
+0xaa,0xa3,0xb6,0xa1,0xb7,0x55,0xaa,0xa1,0xb6,0x8c,0xfc,0xcd,0x18,0xa6,0xa0,0xb7,
+0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x01,0x7b,0xef,0xfc,0xcd,0x14,0xae,0xa4,0x00,
+0x84,0x35,0xa0,0xb7,0x3f,0xa4,0xa0,0xb6,0xa1,0x3f,0xa2,0x3f,0xa3,0x3f,0x8c,0xfc,
+0xcd,0x18,0xa6,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x04,0xab,0x5b,0x25,0x24,
+0x0f,0xa1,0x07,0x7b,0xed,0xc6,0xcd,0x64,0xa6,0x84,0x84,0x84,0x84,0x51,0xc7,0xcd,
+0xb3,0x00,0x3b,0xb4,0x00,0x3b,0xb5,0x00,0x3b,0xb6,0x00,0x3b,0x0f,0x20,0x76,0xc7,
+0xcd,0xb3,0x00,0x3b,0xb4,0x00,0x3b,0xb5,0x00,0x3b,0xb6,0x00,0x3b,0x11,0x26,0x4a,
+0x6f,0x01,0xc6,0x14,0x84,0x0f,0x35,0x15,0x84,0x00,0x35,0x16,0x84,0x00,0x35,0x17,
+0x84,0x00,0x35,0x04,0x6b,0x60,0x20,0xc6,0x05,0x6b,0x61,0x20,0xc6,0x06,0x6b,0x62,
+0x20,0xc6,0x07,0x6b,0x63,0x20,0xc6,0x68,0x20,0xc7,0x4a,0x9d,0x9d,0x68,0x20,0xc7,
+0x27,0xa6,0x68,0x20,0x52,0x35,0x64,0x20,0x05,0x35,0x65,0x20,0xf5,0x35,0x66,0x20,
+0xe1,0x35,0x67,0x20,0x00,0x35,0x60,0x20,0xb7,0x00,0x55,0x61,0x20,0xb8,0x00,0x55,
+0x62,0x20,0xb9,0x00,0x55,0x63,0x20,0xba,0x00,0x55,0xb3,0x00,0x60,0x20,0x55,0xb4,
+0x00,0x61,0x20,0x55,0xb5,0x00,0x62,0x20,0x55,0xb6,0x00,0x63,0x20,0x55,0x68,0x20,
+0x26,0x35,0x68,0x20,0x21,0x35,0x68,0x20,0x52,0x35,0x64,0x20,0x00,0x35,0x65,0x20,
+0x00,0x35,0x66,0x20,0x80,0x35,0x67,0x20,0x00,0x35,0x68,0x20,0x27,0x35,0xb7,0x00,
+0x60,0x20,0x55,0xb8,0x00,0x61,0x20,0x55,0xb9,0x00,0x62,0x20,0x55,0xba,0x00,0x63,
+0x20,0x55,0x68,0x20,0x52,0x35,0x64,0x20,0xc7,0x04,0x7b,0x65,0x20,0xc7,0x05,0x7b,
+0x66,0x20,0xc7,0x06,0x7b,0x67,0x20,0xc7,0x07,0x7b,0x68,0x20,0xc7,0x4a,0x68,0x20,
+0xc7,0x22,0xa6,0x60,0x20,0xc7,0x08,0x7b,0x61,0x20,0xc7,0x09,0x7b,0x62,0x20,0xc7,
+0x0a,0x7b,0x63,0x20,0xc7,0x0b,0x7b,0x68,0x20,0x52,0x35,0x10,0x84,0x02,0x35,0x11,
+0x84,0x55,0x35,0x12,0x84,0x55,0x35,0x13,0x84,0x55,0x35,0x01,0x6b,0x02,0xa6,0x74,
+0xe1,0xcd,0x67,0x20,0x28,0x35,0x09,0x20,0x01,0xa6,0x74,0xe1,0xcd,0x67,0x20,0x14,
+0x35,0x0b,0x25,0x02,0xa2,0x08,0x7b,0xdd,0xa0,0x09,0x7b,0x1e,0x20,0x4f,0x74,0xe1,
+0xcd,0x67,0x20,0x0a,0x35,0x0a,0x25,0x04,0xa2,0x08,0x7b,0xd9,0xa0,0x09,0x7b,0x88,
+0x81,0x51,0x01,0xce,0x52,0x01,0xc6,0xef,0xfc,0xcd,0x81,0x84,0x84,0xef,0xfc,0xcd,
+0x0c,0xae,0xa4,0x00,0x41,0x35,0x0e,0xfd,0xcd,0x41,0x49,0x01,0xc9,0x41,0x4a,0x01,
+0xcb,0x17,0xad,0x08,0xae,0xa4,0x00,0x41,0x35,0x0e,0xfd,0xcd,0x5c,0x01,0x26,0x4c,
+0x26,0xad,0x04,0xae,0xa4,0x00,0x41,0x35,0x0e,0xfd,0xcd,0x41,0x47,0x01,0xc9,0x41,
+0x48,0x01,0xcb,0x41,0x01,0xe2,0x72,0x41,0x02,0xe0,0x72,0x4f,0x01,0xce,0x50,0x01,
+0xc6,0xef,0xfc,0xcd,0x5f,0xa4,0x00,0x41,0x35,0x0e,0xfd,0xcd,0x5c,0x01,0x26,0x4c,
+0x41,0x01,0xe2,0x72,0x41,0x02,0xe0,0x72,0x4f,0x01,0xce,0x50,0x01,0xc6,0x02,0x6b,
+0x54,0x01,0xc6,0x01,0x6b,0x53,0x01,0xc6,0x88,0x88,0x81,0x57,0x01,0xce,0x58,0x01,
+0xc6,0xef,0xfc,0xcd,0x81,0x41,0x53,0x01,0xc9,0x41,0x54,0x01,0xcb,0x46,0x54,0x4b,
+0x01,0xce,0x4c,0x01,0xc6,0x81,0x53,0x01,0xce,0x54,0x01,0xc6,0xef,0xfc,0xcd,0x81,
+0x8c,0xfc,0xcd,0x10,0xa6,0x0e,0xfd,0xcd,0x81,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,
+0x81,0x84,0x84,0x84,0x84,0x84,0x84,0x7c,0x83,0x00,0x35,0x7d,0x83,0x00,0x35,0x7e,
+0x83,0x0f,0x35,0x7f,0x83,0xff,0x35,0xef,0xfc,0xcd,0x6c,0xae,0xa4,0x00,0x83,0x35,
+0xc1,0xfd,0xcd,0x23,0xad,0x5b,0x2e,0xad,0x43,0xad,0xef,0xfc,0xcd,0x2d,0xad,0x5b,
+0x0e,0xfd,0xcd,0x4e,0xad,0x0d,0x20,0x48,0xad,0x39,0xad,0x5b,0x0e,0xfd,0xcd,0x53,
+0x01,0xce,0x54,0x01,0xc6,0x10,0x26,0x4a,0x46,0x01,0xc6,0xef,0xfc,0xcd,0x68,0xae,
+0xa4,0x00,0x83,0x35,0xc1,0xfd,0xcd,0x57,0xad,0x5b,0x62,0xad,0x6d,0xad,0x5e,0xad,
+0x5b,0x0e,0xfd,0xcd,0x75,0xad,0x64,0xae,0xa4,0x00,0x83,0x35,0xc1,0xfd,0xcd,0x6f,
+0xad,0x5b,0x7a,0xad,0x41,0x59,0x01,0xc9,0x41,0x5a,0x01,0xcb,0x05,0xee,0x72,0x06,
+0x7b,0xef,0xfc,0xcd,0x20,0xdf,0xcd,0x5b,0x0e,0xfd,0xcd,0x05,0xee,0x72,0x06,0x7b,
+0xef,0xfc,0xcd,0x60,0xae,0xa4,0x00,0x83,0x35,0xc1,0xfd,0xcd,0x20,0xdf,0xcd,0x5b,
+0x28,0xdf,0xcd,0x41,0x59,0x01,0xc9,0x41,0x5a,0x01,0xcb,0x4c,0xdf,0xcd,0x20,0xdf,
+0xcd,0x5b,0x0e,0xfd,0xcd,0x4c,0xdf,0xcd,0x5c,0xae,0xa4,0x00,0x83,0x35,0x0e,0xfd,
+0xcd,0x46,0x54,0x4b,0x01,0xce,0x4c,0x01,0xc6,0x05,0xef,0x72,0x06,0x6b,0x4a,0x5a,
+0x01,0x26,0x4d,0x57,0x01,0xce,0x58,0x01,0xc6,0x10,0x20,0x06,0x6b,0x58,0x01,0xc6,
+0x05,0x6b,0x57,0x01,0xc6,0x0c,0x26,0x4a,0x46,0x01,0xc6,0x88,0x88,0x88,0x88,0x88,
+0x88,0x81,0x57,0x01,0xce,0x58,0x01,0xc6,0xef,0xfc,0xcd,0x81,0x4d,0x41,0x49,0x01,
+0xc9,0x41,0x4a,0x01,0xcb,0x81,0x04,0xa0,0x41,0x47,0x01,0xc9,0x41,0x48,0x01,0xcb,
+0x81,0x41,0x53,0x01,0xc9,0x41,0x54,0x01,0xcb,0x46,0x54,0x4b,0x01,0xce,0x4c,0x01,
+0xc6,0x81,0x4f,0x01,0xce,0x50,0x01,0xc6,0xef,0xfc,0xcd,0x81,0x53,0x01,0xce,0x54,
+0x01,0xc6,0xef,0xfc,0xcd,0x81,0x8c,0xfc,0xcd,0x10,0xa6,0x0e,0xfd,0xcd,0x81,0xa4,
+0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,0x8b,0x41,0x00,0xa9,0x41,0x0e,0xab,0x5b,0x98,
+0x83,0x00,0x35,0x99,0x83,0x00,0x35,0x9a,0x83,0x00,0x35,0x9b,0x83,0x18,0x35,0xef,
+0xfc,0xcd,0x3c,0xae,0xa4,0x00,0x83,0x35,0xc1,0xfd,0xcd,0x25,0xad,0x5b,0x30,0xad,
+0x4f,0xad,0xef,0xfc,0xcd,0x2f,0xad,0x5b,0x0e,0xfd,0xcd,0x5a,0xad,0x0d,0x20,0x4a,
+0xad,0x3b,0xad,0x5b,0x0e,0xfd,0xcd,0x53,0x01,0xce,0x54,0x01,0xc6,0x10,0x26,0x4a,
+0x46,0x01,0xc6,0xef,0xfc,0xcd,0x38,0xae,0xa4,0x00,0x83,0x35,0xc1,0xfd,0xcd,0x59,
+0xad,0x5b,0x64,0xad,0x6f,0xad,0x60,0xad,0x5b,0x0e,0xfd,0xcd,0x77,0xad,0x34,0xae,
+0xa4,0x00,0x83,0x35,0xc1,0xfd,0xcd,0x71,0xad,0x5b,0x7c,0xad,0x41,0x59,0x01,0xc9,
+0x41,0x5a,0x01,0xcb,0x07,0xee,0x72,0x08,0x7b,0xef,0xfc,0xcd,0xda,0xdd,0xcd,0x5b,
+0x0e,0xfd,0xcd,0x07,0xee,0x72,0x08,0x7b,0xef,0xfc,0xcd,0x30,0xae,0xa4,0x00,0x83,
+0x35,0xc1,0xfd,0xcd,0xda,0xdd,0xcd,0x5b,0xe2,0xdd,0xcd,0x41,0x59,0x01,0xc9,0x41,
+0x5a,0x01,0xcb,0x25,0xde,0xcd,0xda,0xdd,0xcd,0x5b,0x0e,0xfd,0xcd,0x25,0xde,0xcd,
+0x2c,0xae,0xa4,0x00,0x83,0x35,0xc1,0xfd,0xcd,0xda,0xdd,0xcd,0x5b,0xe2,0xdd,0xcd,
+0x41,0x55,0x01,0xc9,0x41,0x56,0x01,0xcb,0xeb,0xdd,0xcd,0xda,0xdd,0xcd,0x5b,0x0e,
+0xfd,0xcd,0xeb,0xdd,0xcd,0x10,0xae,0xa4,0x00,0x83,0x35,0xc1,0xfd,0xcd,0xda,0xdd,
+0xcd,0x5b,0xe2,0xdd,0xcd,0x4a,0x5a,0x01,0x26,0x1b,0xde,0xcd,0x0d,0xee,0x72,0x0e,
+0x7b,0xef,0xfc,0xcd,0xda,0xdd,0xcd,0x5b,0x0e,0xfd,0xcd,0x5a,0x01,0x24,0x10,0xde,
+0xcd,0xf5,0xdd,0xcd,0x0c,0xae,0xa4,0x00,0x83,0x35,0xc1,0xfd,0xcd,0xda,0xdd,0xcd,
+0x5b,0xe2,0xdd,0xcd,0x0d,0xee,0x72,0x0e,0x7b,0xef,0xfc,0xcd,0xda,0xdd,0xcd,0x5b,
+0x0e,0xfd,0xcd,0x5a,0x01,0x24,0x03,0xa0,0xf5,0xdd,0xcd,0x08,0xae,0xa4,0x00,0x83,
+0x35,0xc1,0xfd,0xcd,0xda,0xdd,0xcd,0x5b,0xe2,0xdd,0xcd,0x4a,0x5a,0x01,0x26,0x1b,
+0xde,0xcd,0x0d,0xee,0x72,0x0e,0x7b,0xef,0xfc,0xcd,0xda,0xdd,0xcd,0x5b,0x0e,0xfd,
+0xcd,0x5a,0x01,0x24,0x10,0xde,0xcd,0xf5,0xdd,0xcd,0x04,0xae,0xa4,0x00,0x83,0x35,
+0xc1,0xfd,0xcd,0xda,0xdd,0xcd,0x5b,0xe2,0xdd,0xcd,0x0d,0xee,0x72,0x0e,0x7b,0xef,
+0xfc,0xcd,0xda,0xdd,0xcd,0x5b,0x0e,0xfd,0xcd,0x5a,0x01,0x24,0x03,0xa0,0xf5,0xdd,
+0xcd,0x40,0xae,0xa4,0x00,0x83,0x35,0xa0,0x3f,0xa1,0x3f,0xa2,0xb7,0x0f,0xa4,0xa2,
+0xb6,0x0e,0xfd,0xcd,0x05,0xee,0x72,0x06,0x7b,0xef,0xfc,0xcd,0x28,0xae,0xa4,0x00,
+0x83,0x35,0xa0,0x3f,0xa1,0x3f,0xa2,0xb7,0x1f,0xa4,0xa2,0xb6,0x0e,0xfd,0xcd,0x4b,
+0x01,0xce,0x4c,0x01,0xc6,0x78,0x84,0xc7,0x09,0x7b,0x79,0x84,0xc7,0x0a,0x7b,0x7a,
+0x84,0xc7,0x0b,0x7b,0x7b,0x84,0xc7,0x0c,0x7b,0x07,0xef,0x72,0x08,0x6b,0x4a,0x5a,
+0x01,0x26,0x4d,0x57,0x01,0xce,0x58,0x01,0xc6,0x06,0x6b,0x4e,0x01,0xc6,0x05,0x6b,
+0x4d,0x01,0xc6,0x0a,0x6b,0x05,0xaa,0x0a,0x7b,0x20,0x20,0x08,0x6b,0x58,0x01,0xc6,
+0x07,0x6b,0x57,0x01,0xc6,0x05,0xef,0x72,0x06,0x6b,0x59,0x48,0x4d,0x01,0xce,0x4e,
+0x01,0xc6,0x0a,0x6b,0x01,0xaa,0x0a,0x7b,0x1f,0x26,0x4a,0x46,0x01,0xc6,0x09,0x6b,
+0x80,0xaa,0x09,0x7b,0x06,0x26,0x04,0xa1,0x6a,0x01,0xc6,0x09,0x6b,0x20,0xa6,0x0a,
+0x6b,0x0b,0x6b,0x0c,0x6b,0x4f,0x0d,0x6b,0x0e,0xef,0x72,0x57,0x01,0xc9,0x41,0x58,
+0x01,0xcb,0x51,0x01,0xce,0x52,0x01,0xc6,0x8b,0x41,0x00,0xa2,0x41,0x0e,0xa0,0x5b,
+0x81,0x84,0x84,0x84,0x84,0xe6,0x01,0x01,0x35,0xef,0xfc,0xcd,0xb4,0xae,0xa4,0x00,
+0x84,0x35,0xa0,0x16,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0x01,
+0x6b,0xe3,0xa4,0x01,0x7b,0x01,0x6b,0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,0x03,
+0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,0xc6,0xef,0xfc,0xcd,0x78,0xae,0xa4,0x00,
+0x84,0x35,0xc1,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0xa0,0xb7,0x03,
+0xa4,0xa0,0xb6,0xa1,0xb7,0xc0,0xa4,0xa1,0xb6,0xa2,0x3f,0xa3,0x3f,0x8c,0xfc,0xcd,
+0x16,0xa6,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0x00,0x61,0x01,0x55,0x01,0x6b,
+0xfc,0xa4,0x01,0x7b,0x02,0x6b,0x3f,0xa4,0x02,0x7b,0x01,0x6b,0x78,0x84,0xc6,0x02,
+0x6b,0x79,0x84,0xc6,0x03,0x6b,0x7a,0x84,0xc6,0x04,0x6b,0x7b,0x84,0xc6,0xef,0xfc,
+0xcd,0x74,0xae,0xa4,0x00,0x84,0x35,0x0e,0xfd,0xcd,0x44,0x01,0xce,0x45,0x01,0xc6,
+0xef,0xfc,0xcd,0x70,0xae,0xa4,0x00,0x84,0x35,0x0e,0xfd,0xcd,0x42,0x01,0xce,0x43,
+0x01,0xc6,0xef,0xfc,0xcd,0x6c,0xae,0xa4,0x00,0x84,0x35,0x0e,0xfd,0xcd,0x40,0x01,
+0xce,0x41,0x01,0xc6,0xef,0xfc,0xcd,0x68,0xae,0xa4,0x00,0x84,0x35,0x0e,0xfd,0xcd,
+0x3e,0x01,0xce,0x3f,0x01,0xc6,0xef,0xfc,0xcd,0x64,0xae,0xa4,0x00,0x84,0x35,0x0e,
+0xfd,0xcd,0x3c,0x01,0xce,0x3d,0x01,0xc6,0xef,0xfc,0xcd,0x60,0xae,0xa4,0x00,0x84,
+0x35,0x0e,0xfd,0xcd,0x3a,0x01,0xce,0x3b,0x01,0xc6,0xef,0xfc,0xcd,0x5c,0xae,0xa4,
+0x00,0x84,0x35,0x0e,0xfd,0xcd,0x38,0x01,0xce,0x39,0x01,0xc6,0xef,0xfc,0xcd,0x58,
+0xae,0xa4,0x00,0x84,0x35,0x0e,0xfd,0xcd,0x36,0x01,0xce,0x37,0x01,0xc6,0x88,0x88,
+0x88,0x88,0x81,0xa4,0xc6,0x92,0xa5,0xbf,0xa4,0xb7,0x81,0xa4,0xd6,0x92,0xa5,0x3f,
+0xa4,0xb7,0x81,0x84,0x44,0x01,0xcf,0x3c,0x01,0xce,0x45,0x01,0xc7,0x3d,0x01,0xc6,
+0x3c,0x01,0xcf,0x3d,0x01,0xc7,0x4a,0x5a,0x01,0x26,0x4d,0x59,0x48,0x64,0x01,0xce,
+0x65,0x01,0xc6,0x0b,0x20,0x0e,0x26,0x4d,0x64,0x01,0xce,0x65,0x01,0xc6,0x0b,0x26,
+0x4a,0x46,0x01,0xc6,0x42,0x01,0xcf,0x3a,0x01,0xce,0x43,0x01,0xc7,0x3b,0x01,0xc6,
+0x3b,0x01,0x5f,0x72,0x3a,0x01,0x5f,0x72,0x40,0x01,0xcf,0x38,0x01,0xce,0x41,0x01,
+0xc7,0x39,0x01,0xc6,0x38,0x01,0xcf,0x39,0x01,0xc7,0x4a,0x5a,0x01,0x26,0x4d,0xfa,
+0x26,0x5a,0x90,0x46,0x54,0x06,0x27,0x61,0x01,0xce,0x90,0x62,0x01,0xce,0x63,0x01,
+0xc6,0x3e,0x01,0xcf,0x36,0x01,0xce,0x3f,0x01,0xc7,0x37,0x01,0xc6,0x37,0x01,0x5f,
+0x72,0x36,0x01,0x5f,0x72,0x61,0x01,0x5f,0x72,0x04,0x26,0x04,0xa1,0xeb,0x01,0xc6,
+0x0b,0x26,0x03,0xa1,0x64,0x01,0x49,0x01,0x55,0x65,0x01,0x4a,0x01,0x55,0x68,0x01,
+0x4d,0x01,0x55,0x69,0x01,0x4e,0x01,0x55,0x62,0x01,0x47,0x01,0x55,0x63,0x01,0x48,
+0x01,0x55,0x66,0x01,0x4b,0x01,0x55,0x67,0x01,0x4c,0x01,0x55,0x55,0xd8,0xcc,0x66,
+0xda,0xcd,0xd4,0xa9,0x41,0xc7,0xab,0x52,0x1c,0xae,0x01,0x7b,0xef,0xfc,0xcd,0x5d,
+0xae,0xa4,0x00,0x01,0x35,0x46,0xfc,0xcd,0xa4,0xb7,0xd4,0xa9,0x41,0xc3,0xab,0x52,
+0x1c,0xae,0x01,0x7b,0x5c,0x01,0xc7,0x66,0xda,0xcd,0xd4,0xa9,0x41,0xc2,0xab,0x52,
+0x1c,0xae,0x01,0x7b,0x5b,0x01,0xc7,0x66,0xda,0xcd,0xd4,0xa9,0x41,0xc1,0xab,0x52,
+0x1c,0xae,0x01,0x7b,0x5a,0x01,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,0x59,0x01,0xc7,0x5e,
+0xda,0xcd,0xd4,0xa9,0x41,0xbf,0xab,0x52,0x1c,0xae,0x01,0x7b,0x57,0x01,0x5f,0x72,
+0x58,0x01,0x01,0x35,0x56,0x01,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,0x55,0x01,0xc7,0x5e,
+0xda,0xcd,0xd4,0xa9,0x41,0xbb,0xab,0x52,0x1c,0xae,0x01,0x7b,0x54,0x01,0xc7,0xa4,
+0xd6,0x92,0xa5,0x3c,0x53,0x01,0xc7,0x5e,0xda,0xcd,0xd4,0xa9,0x41,0xb9,0xab,0x52,
+0x1c,0xae,0x01,0x7b,0x52,0x01,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,0x51,0x01,0xc7,0x5e,
+0xda,0xcd,0xd4,0xa9,0x41,0xb7,0xab,0x52,0x1c,0xae,0x01,0x7b,0x50,0x01,0xc7,0xa4,
+0xd6,0x92,0xa5,0x3c,0x4f,0x01,0xc7,0x5e,0xda,0xcd,0xd4,0xa9,0x41,0xb5,0xab,0x52,
+0x1c,0xae,0x01,0x7b,0x4e,0x01,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,0x4d,0x01,0xc7,0x5e,
+0xda,0xcd,0xd4,0xa9,0x41,0xb3,0xab,0x52,0x1c,0xae,0x01,0x7b,0x4c,0x01,0xc7,0xa4,
+0xd6,0x92,0xa5,0x3c,0x4b,0x01,0xc7,0x5e,0xda,0xcd,0xd4,0xa9,0x41,0xb1,0xab,0x52,
+0x1c,0xae,0x01,0x7b,0x4a,0x01,0xc7,0xa4,0xd6,0x92,0xa5,0x3c,0x49,0x01,0xc7,0x5e,
+0xda,0xcd,0xd4,0xa9,0x41,0xaf,0xab,0x52,0x1c,0xae,0x01,0x7b,0x48,0x01,0xc7,0xa4,
+0xd6,0x92,0xa5,0x3c,0x47,0x01,0xc7,0x5e,0xda,0xcd,0xd4,0xa9,0x41,0xad,0xab,0x52,
+0x1c,0xae,0x01,0x7b,0x46,0x01,0xc7,0x66,0xda,0xcd,0xd4,0xa9,0x41,0xac,0xab,0x52,
+0x1c,0xae,0x01,0x7b,0xa4,0xd9,0xcc,0xcc,0xd9,0xcc,0x03,0x27,0x02,0xa1,0xa4,0xd9,
+0xcc,0x03,0x26,0x03,0xa1,0x6f,0x01,0xc6,0x61,0x01,0xc7,0x29,0xb6,0x5d,0x01,0x2a,
+0x00,0x55,0x5e,0x01,0x2b,0x00,0x55,0x5f,0x01,0x2c,0x00,0x55,0x60,0x01,0x2d,0x00,
+0x55,0x5b,0x01,0xc7,0x13,0xb6,0x13,0xb6,0x59,0x01,0xcf,0x22,0xbe,0x5a,0x01,0xc7,
+0x23,0xb6,0x57,0x01,0xcf,0x20,0xbe,0x58,0x01,0xc7,0x21,0xb6,0x55,0x01,0xcf,0x1e,
+0xbe,0x56,0x01,0xc7,0x1f,0xb6,0x53,0x01,0xcf,0x1c,0xbe,0x54,0x01,0xc7,0x1d,0xb6,
+0x51,0x01,0xcf,0x26,0xbe,0x52,0x01,0xc7,0x27,0xb6,0x4f,0x01,0xcf,0x24,0xbe,0x50,
+0x01,0xc7,0x25,0xb6,0x4d,0x01,0xcf,0x18,0xbe,0x4e,0x01,0xc7,0x19,0xb6,0x4b,0x01,
+0xcf,0x14,0xbe,0x4c,0x01,0xc7,0x15,0xb6,0x49,0x01,0xcf,0x1a,0xbe,0x4a,0x01,0xc7,
+0x1b,0xb6,0x47,0x01,0xcf,0x16,0xbe,0x48,0x01,0xc7,0x17,0xb6,0x46,0x01,0xc7,0x28,
+0xb6,0x6c,0xd8,0xcc,0x03,0x24,0x1d,0xa1,0x11,0xb6,0x09,0x27,0x11,0x3d,0x01,0x6b,
+0x4a,0x11,0xb6,0x88,0x00,0xf0,0x70,0x1c,0x05,0x01,0x01,0x03,0x00,0x03,0x00,0x8f,
+0x00,0x46,0x00,0x1b,0x00,0xaa,0x01,0x1e,0x03,0x00,0x07,0x00,0x03,0x50,0x05,0x01,
+0x00,0x60,0xa0,0x18,0x05,0x01,0x01,0x06,0x00,0x03,0x00,0x70,0x00,0x40,0x00,0x18,
+0x00,0xb0,0x01,0x1b,0x03,0x00,0x07,0x00,0x03,0x50,0x05,0x01,0x00,0xe0,0x1b,0xfa,
+0x04,0x01,0x00,0x06,0x00,0x03,0x00,0x80,0x00,0x48,0x00,0x1c,0x00,0x90,0x01,0x3f,
+0x03,0x90,0x06,0x20,0x03,0x00,0x05,0x01,0x00,0xc0,0x5f,0x3b,0x04,0x00,0x01,0x06,
+0x00,0x03,0x00,0x20,0x00,0x30,0x00,0x14,0x00,0xa0,0x00,0x37,0x03,0xa0,0x05,0x20,
+0x03,0x00,0x05,0x01,0x00,0xe0,0x12,0xbd,0x04,0x01,0x00,0x07,0x00,0x03,0x00,0x80,
+0x00,0x40,0x00,0x1b,0x00,0x80,0x01,0x1e,0x03,0x80,0x06,0x00,0x03,0x00,0x05,0x01,
+0x00,0x90,0x69,0x11,0x04,0x00,0x01,0x07,0x00,0x03,0x00,0x20,0x00,0x30,0x00,0x13,
+0x00,0xa0,0x00,0x16,0x03,0xa0,0x05,0x00,0x03,0x00,0x05,0x01,0x00,0x40,0xd2,0xdf,
+0x03,0x00,0x00,0x06,0x00,0x03,0x00,0x88,0x00,0x18,0x00,0x23,0x00,0x40,0x01,0x26,
+0x03,0x40,0x05,0x00,0x03,0x00,0x04,0x01,0x00,0xf0,0xfb,0x02,0x02,0x01,0x01,0x08,
+0x00,0x06,0x00,0x70,0x00,0x10,0x00,0x1f,0x00,0xf0,0x00,0x05,0x02,0x40,0x04,0xe0,
+0x01,0x50,0x03,0x01,0x00,0x00,0x5a,0x62,0x02,0x01,0x01,0x04,0x00,0x01,0x00,0x80,
+0x00,0x28,0x00,0x1b,0x00,0x00,0x01,0x74,0x02,0x20,0x04,0x58,0x02,0x20,0x03,0x01,
+0x00,0x10,0xf7,0x6c,0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x28,0x00,0xe0,0x06,0x19,
+0x00,0xe4,0x07,0xee,0x02,0xe4,0x0c,0xd0,0x02,0x00,0x05,0x01,0x00,0x10,0xf7,0x6c,
+0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x28,0x00,0x74,0x09,0x19,0x00,0x78,0x0a,0xee,
+0x02,0x78,0x0f,0xd0,0x02,0x00,0x05,0x01,0x00,0x40,0x5f,0x8a,0x03,0x01,0x01,0x05,
+0x00,0x01,0x00,0x28,0x00,0xe0,0x06,0x19,0x00,0xe4,0x07,0xee,0x02,0xe4,0x0c,0xd0,
+0x02,0x00,0x05,0x01,0x00,0x10,0xf7,0x6c,0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x2c,
+0x00,0x58,0x00,0x29,0x00,0x18,0x01,0x65,0x04,0x98,0x08,0x38,0x04,0x80,0x07,0x01,
+0x00,0x10,0xf7,0x6c,0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x2c,0x00,0x10,0x02,0x29,
+0x00,0xd0,0x02,0x65,0x04,0x50,0x0a,0x38,0x04,0x80,0x07,0x01,0x00,0x10,0xf7,0x6c,
+0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x2c,0x00,0x7e,0x02,0x29,0x00,0x3e,0x03,0x65,
+0x04,0xbe,0x0a,0x38,0x04,0x80,0x07,0x01,0x00,0x20,0xee,0xd9,0x08,0x01,0x01,0x05,
+0x00,0x01,0x00,0x2c,0x00,0x10,0x02,0x29,0x00,0xd0,0x02,0x65,0x04,0x50,0x0a,0x38,
+0x04,0x80,0x07,0x01,0x00,0x80,0xf9,0x37,0x03,0x00,0x00,0x05,0x00,0x01,0x00,0x80,
+0x00,0x18,0x00,0x2c,0x00,0x20,0x01,0x71,0x02,0xc0,0x06,0x40,0x02,0xa0,0x05,0x01,
+0x01,0xc0,0xfc,0x9b,0x01,0x00,0x00,0x03,0x00,0x01,0x00,0x7e,0x00,0x18,0x00,0x16,
+0x00,0x20,0x01,0x71,0x02,0xc0,0x06,0x20,0x01,0xa0,0x05,0x00,0x00,0x10,0xf7,0x6c,
+0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x2c,0x00,0x10,0x02,0x14,0x00,0xd0,0x02,0x65,
+0x04,0x50,0x0a,0x1c,0x02,0x80,0x07,0x00,0x00,0x10,0xf7,0x6c,0x04,0x01,0x01,0x05,
+0x00,0x01,0x00,0x28,0x00,0xb8,0x01,0x19,0x00,0xbc,0x02,0xee,0x02,0xbc,0x07,0xd0,
+0x02,0x00,0x05,0x01,0x00,0xc0,0xfc,0x9b,0x01,0x00,0x00,0x05,0x00,0x01,0x00,0x40,
+0x00,0x0c,0x00,0x2c,0x00,0x90,0x00,0x71,0x02,0x60,0x03,0x40,0x02,0xd0,0x02,0x01,
+0x00,0x20,0xee,0xd9,0x08,0x01,0x01,0x05,0x00,0x01,0x00,0x2c,0x00,0x58,0x00,0x29,
+0x00,0x18,0x01,0x65,0x04,0x98,0x08,0x38,0x04,0x80,0x07,0x01,0x00,0x80,0xf9,0x37,
+0x03,0x00,0x00,0x06,0x00,0x07,0x00,0x7c,0x00,0x20,0x00,0x24,0x00,0x14,0x01,0x0d,
+0x02,0xb4,0x06,0xe0,0x01,0xa0,0x05,0x01,0x01,0xc0,0xfc,0x9b,0x01,0x00,0x00,0x03,
+0x00,0x04,0x00,0x7c,0x00,0x26,0x00,0x12,0x00,0x14,0x01,0x0d,0x02,0xb4,0x06,0xf0,
+0x00,0xa0,0x05,0x00,0x00,0x10,0xf7,0x6c,0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x2c,
+0x00,0x58,0x00,0x14,0x00,0x18,0x01,0x65,0x04,0x98,0x08,0x1c,0x02,0x80,0x07,0x00,
+0x00,0x10,0xf7,0x6c,0x04,0x01,0x01,0x05,0x00,0x01,0x00,0x28,0x00,0x6e,0x00,0x19,
+0x00,0x72,0x01,0xee,0x02,0x72,0x06,0xd0,0x02,0x00,0x05,0x01,0x00,0xc0,0xfc,0x9b,
+0x01,0x00,0x00,0x06,0x00,0x07,0x00,0x3e,0x00,0x10,0x00,0x24,0x00,0x8a,0x00,0x0d,
+0x02,0x5a,0x03,0xe0,0x01,0xd0,0x02,0x01,0x00,0x80,0x85,0x80,0x01,0x00,0x00,0x02,
+0x00,0x01,0x00,0x60,0x00,0x10,0x00,0x23,0x00,0xa0,0x00,0x0d,0x02,0x20,0x03,0xe0,
+0x01,0x80,0x02,0x01,0x81,0x84,0x8b,0x41,0x00,0xa9,0x41,0x08,0xab,0x5b,0x09,0x6b,
+0x01,0x6b,0x4f,0x01,0x20,0x01,0xa6,0x04,0x26,0xbe,0x01,0xc1,0x05,0x7b,0x0b,0x26,
+0x04,0xe1,0x72,0xbf,0x01,0xc6,0x08,0x27,0xbe,0x01,0xc6,0xb7,0x26,0x46,0xfd,0xcd,
+0xa4,0xb7,0x00,0xa9,0x41,0x02,0xab,0x5b,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,
+0x06,0xab,0x5b,0x06,0x6b,0x30,0x48,0xc6,0x07,0x6b,0x31,0x48,0xc6,0x08,0x6b,0x32,
+0x48,0xc6,0x09,0x6b,0x33,0x48,0xc6,0x84,0x84,0x79,0xc0,0xcd,0x74,0xae,0x08,0xa6,
+0x02,0x4b,0x00,0x4b,0x02,0x6b,0x06,0x7b,0x03,0x6b,0x07,0x7b,0x04,0x6b,0x08,0x7b,
+0x05,0x6b,0x09,0x7b,0x06,0x6b,0x30,0x48,0xc6,0x07,0x6b,0x31,0x48,0xc6,0x08,0x6b,
+0x32,0x48,0xc6,0x09,0x6b,0x33,0x48,0xc6,0x01,0x6b,0x4f,0x8b,0x41,0x00,0xa2,0x41,
+0x09,0xa0,0x5b,0xab,0x20,0x80,0xaa,0x17,0xb7,0x02,0x7b,0x84,0x84,0x79,0xc0,0xcd,
+0x74,0xae,0x20,0xa6,0x14,0x4b,0x88,0x07,0xab,0x01,0x7b,0xf0,0x25,0x05,0xa1,0x03,
+0x6b,0x4c,0x9f,0x18,0xe7,0xbe,0x01,0xd6,0x03,0xee,0x72,0x03,0x6b,0x12,0x26,0x4a,
+0x02,0x7b,0x84,0x84,0x79,0xc0,0xcd,0x74,0xae,0x43,0xa6,0x88,0x02,0x7b,0x07,0x4b,
+0x10,0x27,0x02,0x7b,0x01,0x6b,0x52,0x05,0xae,0x05,0x24,0x14,0xa1,0x02,0x6b,0x7f,
+0xa4,0xbe,0x01,0xc6,0x81,0x85,0x85,0x85,0x4f,0x05,0xbf,0x01,0x07,0x72,0x05,0x20,
+0x02,0xbe,0x01,0x0f,0x72,0x84,0x84,0x79,0xc0,0xcd,0x74,0xae,0x41,0xa6,0x02,0x4b,
+0x00,0x4b,0x19,0x26,0x60,0xa1,0x60,0xa4,0xbe,0x01,0xc6,0x84,0x84,0x79,0xc0,0xcd,
+0x74,0xae,0x40,0xa6,0x01,0x4b,0x00,0x4b,0x01,0x6b,0x64,0xa6,0x88,0x88,0x88,0x81,
+0x9f,0x01,0xc6,0x9f,0x01,0x01,0x35,0x04,0xbe,0x01,0x0d,0x72,0x84,0x84,0x79,0xc0,
+0xcd,0x74,0xae,0x40,0xa6,0x01,0x4b,0x00,0x4b,0x9f,0x01,0x5f,0x72,0x81,0x85,0x9a,
+0xef,0xfc,0xcd,0x14,0xae,0xa4,0x00,0x48,0x35,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,
+0xa3,0x00,0xa2,0x01,0x55,0x10,0x48,0xa3,0x01,0x55,0x11,0x48,0xa4,0x01,0x55,0x12,
+0x48,0xa5,0x01,0x55,0x13,0x48,0xa6,0x01,0x55,0x9b,0xcd,0x25,0x05,0xa1,0x01,0x6b,
+0x4c,0x01,0x7b,0xbb,0xfd,0xcd,0xa3,0xae,0xa4,0x00,0x01,0x35,0x8c,0xfc,0xcd,0x48,
+0x48,0x48,0x9f,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0xbe,0x01,0xd6,0x01,
+0xee,0x72,0x1f,0x20,0xa2,0x01,0xc2,0x01,0x55,0x07,0x26,0x04,0xa1,0x01,0x6b,0x4f,
+0x84,0x84,0xa3,0x01,0x5f,0x72,0xa4,0x01,0x5f,0x72,0xa5,0x01,0x5f,0x72,0xa6,0x01,
+0x5f,0x72,0x79,0xc0,0xcd,0x74,0xae,0x4f,0x05,0x4b,0x00,0x4b,0x88,0x81,0x84,0x8b,
+0x41,0x00,0xa9,0x41,0x08,0xab,0x5b,0x09,0x6b,0x01,0x6b,0x85,0x85,0x54,0xc1,0xcd,
+0x74,0xae,0x10,0xa6,0x00,0x4b,0x05,0x4b,0xc2,0x01,0xc7,0x05,0x7b,0x02,0x6b,0xb6,
+0x01,0xc6,0x03,0x6b,0xb7,0x01,0xc6,0x04,0x6b,0xb8,0x01,0xc6,0x05,0x6b,0xb9,0x01,
+0xc6,0xc1,0x01,0xc7,0x02,0x7b,0xc0,0x01,0xc7,0x03,0x7b,0xbf,0x01,0xc7,0x04,0x7b,
+0xbe,0x01,0xc7,0x05,0x7b,0x02,0x6b,0xb2,0x01,0xc6,0x03,0x6b,0xb3,0x01,0xc6,0x04,
+0x6b,0xb4,0x01,0xc6,0x05,0x6b,0xb5,0x01,0xc6,0x01,0x6b,0x85,0x85,0x54,0xc1,0xcd,
+0x74,0xae,0x18,0xa6,0x00,0x4b,0x08,0x4b,0xc5,0x01,0xc7,0x06,0x7b,0xc4,0x01,0xc7,
+0x07,0x7b,0xc3,0x01,0xc7,0x08,0x7b,0xc2,0x01,0xc7,0x09,0x7b,0x06,0x6b,0x1c,0x48,
+0xc6,0x07,0x6b,0x1d,0x48,0xc6,0x08,0x6b,0x1e,0x48,0xc6,0x09,0x6b,0x1f,0x48,0xc6,
+0xc1,0x01,0xc7,0x06,0x7b,0xc0,0x01,0xc7,0x07,0x7b,0xbf,0x01,0xc7,0x08,0x7b,0xbe,
+0x01,0xc7,0x09,0x7b,0x06,0x6b,0x18,0x48,0xc6,0x07,0x6b,0x19,0x48,0xc6,0x08,0x6b,
+0x1a,0x48,0xc6,0x09,0x6b,0x1b,0x48,0xc6,0x01,0x6b,0x4f,0x8b,0x41,0x00,0xa2,0x41,
+0x09,0xa0,0x5b,0x81,0x85,0x85,0x85,0x85,0x85,0x01,0x7b,0x01,0x6b,0x01,0xa6,0x04,
+0x26,0x14,0xa1,0x02,0x7b,0x0a,0x26,0x14,0xa1,0x03,0x7b,0xd1,0x25,0x05,0xa1,0x05,
+0x6b,0x4c,0x05,0x7b,0xdd,0x25,0x08,0xa1,0x04,0x6b,0x4c,0x04,0x7b,0xbe,0x01,0x44,
+0x72,0x02,0x6b,0x4c,0x02,0x7b,0x05,0x20,0x03,0x6b,0x4c,0x03,0x7b,0x07,0x26,0x01,
+0xa4,0xbe,0x01,0xd6,0x05,0xee,0x72,0x04,0x6b,0x4f,0x05,0x6b,0x4f,0x44,0x20,0x4f,
+0x03,0x27,0x85,0x85,0x4d,0x79,0xc0,0xcd,0x74,0xae,0x05,0x4b,0x00,0x4b,0x9a,0x14,
+0x48,0xb6,0x01,0x55,0x15,0x48,0xb7,0x01,0x55,0x16,0x48,0xb8,0x01,0x55,0x17,0x48,
+0xb9,0x01,0x55,0x10,0x48,0xb2,0x01,0x55,0x11,0x48,0xb3,0x01,0x55,0x12,0x48,0xb4,
+0x01,0x55,0x13,0x48,0xb5,0x01,0x55,0x9b,0x03,0x6b,0x02,0x6b,0x01,0x6b,0x4f,0x88,
+0x88,0x88,0x88,0x88,0x81,0xa4,0x00,0x48,0x35,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,
+0xa3,0xb7,0x81,0x85,0x85,0x85,0x85,0x01,0x7b,0x9a,0xef,0xfc,0xcd,0x0c,0xae,0x0d,
+0xad,0x03,0x7b,0x9b,0x01,0x6b,0x01,0xa6,0x04,0x26,0x02,0x7b,0x04,0x26,0x4a,0x03,
+0x7b,0xee,0x26,0x02,0x7b,0x06,0x26,0x03,0x7b,0x02,0x6b,0x4a,0x02,0x7b,0x03,0x6b,
+0x0f,0x48,0xc6,0x0a,0x20,0x9a,0xef,0xfc,0xcd,0x5f,0x38,0xad,0x04,0x7b,0x9b,0x02,
+0x6b,0x32,0xa6,0x01,0x6b,0x03,0x6b,0x4f,0x88,0x88,0x88,0x88,0x81,0x07,0xfe,0xcd,
+0xa4,0xb7,0x00,0xa9,0x41,0x05,0xab,0x81,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+0x9a,0xef,0xfc,0xcd,0x04,0xae,0xa4,0x00,0x48,0x35,0xa3,0x15,0xa0,0xb7,0xa1,0xb7,
+0xa2,0xb7,0x4f,0xa3,0xb7,0x03,0xaa,0x3f,0xa4,0x08,0x7b,0x9b,0x05,0x6b,0x04,0x48,
+0xc6,0x06,0x6b,0x05,0x48,0xc6,0x07,0x6b,0x06,0x48,0xc6,0x08,0x6b,0x07,0x48,0xc6,
+0x9a,0xef,0xfc,0xcd,0x5f,0xa4,0x00,0x40,0x35,0xc1,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,
+0x41,0x01,0xab,0x5b,0xa3,0x14,0x4f,0xad,0x5b,0xef,0xfc,0xcd,0xa4,0xb7,0x00,0xa9,
+0x41,0x01,0xab,0x5b,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0x00,0x9c,0x01,0x55,
+0x9b,0x05,0x6b,0x00,0x40,0xc6,0x06,0x6b,0x01,0x40,0xc6,0x07,0x6b,0x02,0x40,0xc6,
+0x08,0x6b,0x03,0x40,0xc6,0x9a,0xef,0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0xa3,
+0x1a,0xa3,0x19,0x39,0xd1,0xcd,0x5b,0x9b,0x05,0x6b,0xb4,0x84,0xc6,0x06,0x6b,0xb5,
+0x84,0xc6,0x07,0x6b,0xb6,0x84,0xc6,0x08,0x6b,0xb7,0x84,0xc6,0x88,0x88,0x88,0x88,
+0x88,0x88,0x88,0x88,0x81,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x81,
+0x84,0x84,0x84,0x84,0x9a,0xef,0xfc,0xcd,0x04,0xae,0xa4,0x00,0x48,0x35,0xa3,0x14,
+0x11,0xad,0x5b,0x9b,0x01,0x6b,0x04,0x48,0xc6,0x02,0x6b,0x05,0x48,0xc6,0x03,0x6b,
+0x06,0x48,0xc6,0x04,0x6b,0x07,0x48,0xc6,0x9a,0xef,0xfc,0xcd,0x5f,0xa4,0x00,0x40,
+0x35,0xa3,0x15,0x34,0xad,0x5b,0x9b,0x01,0x6b,0x00,0x40,0xc6,0x02,0x6b,0x01,0x40,
+0xc6,0x03,0x6b,0x02,0x40,0xc6,0x04,0x6b,0x03,0x40,0xc6,0x88,0x88,0x88,0x88,0x81,
+0x85,0x85,0x85,0x85,0x4f,0x9a,0xef,0xfc,0xcd,0x04,0xae,0xa4,0x00,0x48,0x35,0xa0,
+0x3f,0xa1,0x3f,0xa2,0x3f,0xa3,0xb7,0x30,0xa4,0xa3,0xb6,0xa0,0xb7,0xa1,0xb7,0xa2,
+0xb7,0x4f,0xa3,0xb7,0x04,0x7b,0x9b,0x01,0x6b,0x04,0x48,0xc6,0x02,0x6b,0x05,0x48,
+0xc6,0x03,0x6b,0x06,0x48,0xc6,0x04,0x6b,0x07,0x48,0xc6,0x9a,0xef,0xfc,0xcd,0x5f,
+0xa4,0x00,0x40,0x35,0xa3,0x15,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,
+0x5b,0x9b,0x01,0x6b,0x00,0x40,0xc6,0x02,0x6b,0x01,0x40,0xc6,0x03,0x6b,0x02,0x40,
+0xc6,0x04,0x6b,0x03,0x40,0xc6,0x88,0x88,0x88,0x88,0x81,0x9a,0xd2,0xfc,0xcd,0xa4,
+0xb7,0x40,0xa9,0x41,0x00,0xab,0x81,0xa4,0xb7,0x00,0xa9,0x41,0x07,0xab,0x81,0x8b,
+0x41,0x00,0xa9,0x41,0x0d,0xab,0x5b,0x9a,0xef,0xfc,0xcd,0x30,0xae,0xa4,0x00,0x42,
+0x35,0xc1,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0x8c,0xfc,0xcd,0x48,
+0x48,0x12,0x7b,0xa0,0x3f,0xa1,0x3f,0xa2,0x3f,0xa3,0x00,0x03,0x35,0x9b,0x01,0x6b,
+0x30,0x42,0xc6,0x02,0x6b,0x31,0x42,0xc6,0x03,0x6b,0x32,0x42,0xc6,0x04,0x6b,0x33,
+0x42,0xc6,0xe3,0xce,0xcc,0x03,0x25,0x06,0xe1,0x72,0xa4,0xd6,0x92,0x02,0xae,0xa5,
+0xb7,0x0d,0x7b,0xa4,0xb7,0x0c,0x7b,0x06,0x6b,0x04,0xab,0x06,0x7b,0x67,0xad,0x5c,
+0x01,0x24,0x06,0xeb,0x72,0x10,0xee,0x72,0x11,0x7b,0x07,0xfe,0xcd,0x6f,0xad,0x5b,
+0x9b,0xaf,0x25,0x04,0xa1,0x0b,0x6b,0x4c,0x0b,0x7b,0xa4,0xc7,0x92,0xa5,0xbf,0x85,
+0xa4,0x00,0x32,0xa4,0xd6,0x92,0x03,0xae,0xa5,0xbf,0xa4,0xb7,0x0e,0xe9,0x72,0x41,
+0x0f,0xeb,0x72,0x5f,0x4a,0x07,0x6b,0x4c,0x07,0x7b,0xa4,0x00,0x3b,0x89,0xa4,0x3c,
+0x02,0x24,0x97,0xa5,0xbb,0x0b,0xe0,0x72,0x03,0xa6,0xa5,0xbf,0xb2,0xcf,0xcd,0x5b,
+0x36,0x25,0x05,0xe1,0x72,0xa4,0xd6,0x92,0x02,0xae,0xa5,0xb7,0x0d,0x7b,0xa4,0xb7,
+0x0c,0x7b,0x0b,0x6b,0x07,0x6b,0x08,0x6b,0x09,0x6b,0x0a,0x6b,0x4f,0x74,0x20,0x05,
+0x6b,0x4f,0x10,0x6b,0x00,0xa9,0x10,0x7b,0x11,0x6b,0x04,0xab,0x11,0x7b,0xba,0xcf,
+0xcd,0x10,0xee,0x72,0x11,0x7b,0x07,0xfe,0xcd,0xb2,0xcf,0xcd,0x5b,0x9b,0x07,0x6b,
+0x4f,0x08,0x6b,0xa4,0xd6,0x92,0x5c,0x09,0x6b,0xa4,0xd6,0x92,0x01,0xae,0xa5,0xb7,
+0x0d,0x7b,0xa4,0xb7,0x0c,0x7b,0x0a,0x6b,0xa4,0xc6,0x92,0xa5,0xb7,0x0d,0x7b,0xa4,
+0xbf,0x0c,0xee,0x72,0x8b,0x41,0x00,0xa2,0x41,0x0b,0xa0,0x5b,0x89,0x88,0x81,0x01,
+0xa6,0x15,0x00,0xde,0x35,0x14,0x00,0xc0,0x35,0x13,0x00,0xad,0x35,0x12,0x00,0xde,
+0x35,0x50,0x18,0xcd,0x81,0x84,0x84,0x84,0x84,0x84,0x3d,0xcd,0xcd,0xac,0x25,0x10,
+0xa1,0x04,0x6b,0x4c,0x04,0x7b,0xc2,0x25,0x08,0xa1,0x05,0x6b,0x4c,0x05,0x7b,0x85,
+0xcd,0xcd,0x03,0x27,0x5d,0x03,0x26,0x4d,0x41,0x01,0xe4,0x72,0x41,0x02,0xe4,0x72,
+0xfa,0x26,0x5a,0x90,0x59,0x48,0x06,0x27,0x05,0xe6,0x72,0x01,0xa6,0x01,0xef,0x72,
+0x02,0x6b,0x5f,0x03,0x7b,0xaa,0xcd,0xcd,0x03,0x20,0x9a,0xad,0x04,0x26,0x05,0x7b,
+0x08,0x26,0x04,0x7b,0x05,0x6b,0x4f,0x03,0x6b,0x12,0xe6,0x97,0x04,0xe0,0x72,0x0f,
+0xa6,0x04,0x6b,0x4f,0xf5,0x25,0x10,0xa1,0x04,0x6b,0x4c,0x04,0x7b,0x97,0xad,0x04,
+0x6b,0x4f,0x85,0xcd,0xcd,0x3d,0xcd,0xcd,0x67,0xcd,0xcd,0x88,0x88,0x88,0x88,0x88,
+0x81,0xb3,0x84,0x00,0x35,0xb0,0x84,0x00,0x35,0xb1,0x84,0x00,0x35,0x81,0xb0,0x84,
+0x00,0x35,0xb1,0x84,0x00,0x35,0xb2,0x84,0x00,0x35,0x0d,0xad,0xb2,0x84,0x03,0x35,
+0x13,0xad,0xb2,0x84,0x02,0x35,0x19,0xad,0xb2,0x84,0x00,0x35,0xb3,0x84,0x00,0x35,
+0x81,0xb0,0x84,0x00,0x35,0xb1,0x84,0x00,0x35,0xb2,0x84,0x00,0x35,0xb3,0x84,0x00,
+0x35,0x81,0x01,0xad,0xb0,0x84,0x00,0x35,0xb1,0x84,0x00,0x35,0xb2,0x84,0x01,0x35,
+0xb3,0x84,0x00,0x35,0x13,0xad,0x81,0x64,0xa6,0xb0,0x84,0x00,0x35,0xb1,0x84,0x00,
+0x35,0xed,0xc6,0xcc,0x03,0xad,0xb2,0x84,0x00,0x35,0xb3,0x84,0x00,0x35,0xed,0xc6,
+0xcd,0x10,0xad,0xb2,0x84,0x04,0x35,0xb3,0x84,0x00,0x35,0x81,0xad,0x84,0x00,0x35,
+0xae,0x84,0x00,0x35,0xaf,0x84,0x00,0x35,0x81,0xac,0x84,0x00,0x35,0x05,0xad,0x81,
+0xac,0x84,0x80,0x35,0x0c,0xad,0x07,0x27,0x4d,0xed,0xc6,0xcc,0x64,0xa6,0xb0,0x84,
+0x00,0x35,0xb1,0x84,0x00,0x35,0xb2,0x84,0x00,0x35,0xb3,0x84,0x00,0x35,0xed,0xc6,
+0xcd,0x0a,0xa6,0xb0,0x84,0x00,0x35,0xb1,0x84,0x00,0x35,0xb2,0x84,0x10,0x35,0xb3,
+0x84,0x00,0x35,0x81,0x84,0x84,0x84,0x84,0xe6,0x01,0x01,0x35,0xef,0xfc,0xcd,0x5f,
+0xa4,0x00,0x84,0x35,0xa0,0x1a,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,
+0x5b,0x01,0x6b,0x00,0x84,0xc6,0x02,0x6b,0x01,0x84,0xc6,0x03,0x6b,0x02,0x84,0xc6,
+0x04,0x6b,0x03,0x84,0xc6,0x88,0x88,0x88,0x88,0x81,0x84,0x84,0x84,0x84,0xef,0xfc,
+0xcd,0x5f,0xa4,0x00,0x84,0x35,0xa0,0x1b,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,
+0x01,0xab,0x5b,0x01,0x6b,0x00,0x84,0xc6,0x02,0x6b,0x01,0x84,0xc6,0x03,0x6b,0x02,
+0x84,0xc6,0x04,0x6b,0x03,0x84,0xc6,0x88,0x88,0x88,0x88,0x81,0xef,0xfc,0xcd,0x78,
+0xae,0xa4,0x00,0x84,0x35,0x81,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,
+0x81,0x84,0x84,0x84,0x84,0x10,0xad,0xa3,0x1d,0x09,0xad,0x5b,0x17,0xad,0xa3,0x1c,
+0x10,0xad,0x5b,0x01,0x6b,0x78,0x84,0xc6,0x02,0x6b,0x79,0x84,0xc6,0x03,0x6b,0x7a,
+0x84,0xc6,0x04,0x6b,0x7b,0x84,0xc6,0x88,0x88,0x88,0x88,0x81,0x0e,0xfd,0xcd,0xbc,
+0x00,0xce,0xbd,0x00,0xc6,0x81,0x84,0x84,0x84,0x84,0xa0,0x84,0xc7,0x01,0x7b,0xa1,
+0x84,0xc7,0x02,0x7b,0xa2,0x84,0xc7,0x03,0x7b,0xa3,0x84,0xc7,0x04,0x7b,0x03,0x6b,
+0x80,0xaa,0x03,0x7b,0x04,0x6b,0x06,0xaa,0x04,0x7b,0x0c,0x20,0xbb,0xfd,0xcd,0xa4,
+0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0xa2,0x1e,0x34,0xad,0x11,0x24,0x00,0xa2,0xbc,
+0x00,0xc6,0x06,0xa0,0xbd,0x00,0xc6,0x0c,0x27,0x70,0x01,0xc6,0x22,0x25,0x02,0xa1,
+0xbb,0x00,0xc6,0x29,0x26,0x4a,0x6f,0x01,0xc6,0x03,0x6b,0x80,0xa4,0x03,0x7b,0x04,
+0x6b,0x4f,0x01,0x6b,0xa0,0x84,0xc6,0x02,0x6b,0xa1,0x84,0xc6,0x03,0x6b,0xa2,0x84,
+0xc6,0x04,0x6b,0xa3,0x84,0xc6,0x6c,0x25,0x02,0xa1,0xbb,0x00,0xc6,0x73,0x26,0x4a,
+0x6f,0x01,0xc6,0x0d,0x27,0x4a,0x70,0x01,0xc6,0xef,0xfc,0xcd,0x78,0xae,0xa4,0x00,
+0x84,0x35,0xa0,0x1c,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0x01,
+0x6b,0x78,0x84,0xc6,0x02,0x6b,0x79,0x84,0xc6,0x03,0x6b,0x7a,0x84,0xc6,0x04,0x6b,
+0x7b,0x84,0xc6,0x48,0x83,0x00,0x35,0x49,0x83,0x00,0x35,0x4a,0x83,0x00,0x35,0x4b,
+0x83,0x0f,0x35,0x10,0x26,0x4a,0x24,0x83,0x00,0x35,0x25,0x83,0x00,0x35,0x26,0x83,
+0x00,0x35,0x27,0x83,0x00,0x35,0x4d,0x27,0x6f,0x01,0xc6,0xef,0xfc,0xcd,0xa4,0xae,
+0xa4,0x00,0x84,0x35,0xa2,0x1e,0xa0,0x3f,0xa1,0x3f,0xa2,0x1f,0x8b,0xcc,0xcd,0x14,
+0x26,0x03,0xa1,0x04,0x27,0x01,0xa1,0xbb,0x00,0xc6,0x1f,0x26,0x4a,0x6f,0x01,0xc6,
+0xef,0xfc,0xcd,0xa0,0xae,0xa4,0x00,0x84,0x35,0xa0,0x1f,0xa2,0x3f,0xa3,0x3f,0x8c,
+0xfc,0xcd,0x10,0xa6,0x0e,0xfd,0xcd,0x5c,0x01,0x24,0x02,0xab,0x57,0x01,0xce,0x58,
+0x01,0xc6,0x0b,0x20,0xe9,0x01,0xce,0xea,0x01,0xc6,0x2a,0x26,0x4a,0x0b,0x27,0x02,
+0xa0,0x6f,0x01,0xc6,0xef,0x01,0x5f,0x72,0x07,0xcc,0xcc,0x03,0x27,0x71,0x01,0xc6,
+0x08,0x27,0x70,0x01,0xc6,0x88,0x88,0x88,0x88,0x81,0x84,0x84,0x84,0x84,0xa0,0x84,
+0xc7,0x01,0x7b,0xa1,0x84,0xc7,0x02,0x7b,0xa2,0x84,0xc7,0x03,0x7b,0xa3,0x84,0xc7,
+0x04,0x7b,0xbb,0xfd,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0xa2,0x1e,0x0e,
+0xfd,0xcd,0xbc,0x00,0xce,0xbd,0x00,0xc6,0x03,0x6b,0x80,0xa4,0x03,0x7b,0x04,0x6b,
+0x4f,0x1f,0x25,0x02,0xa1,0xbb,0x00,0xc6,0x26,0x26,0x4a,0x6f,0x01,0xc6,0x03,0x6b,
+0x7f,0xa4,0x03,0x7b,0x01,0x6b,0xa0,0x84,0xc6,0x02,0x6b,0xa1,0x84,0xc6,0x03,0x6b,
+0xa2,0x84,0xc6,0x04,0x6b,0xa3,0x84,0xc6,0x5a,0x26,0x70,0x01,0xc6,0x5f,0x20,0x24,
+0x83,0x00,0x35,0x25,0x83,0x00,0x35,0x26,0x83,0x02,0x35,0x27,0x83,0x00,0x35,0xa0,
+0x84,0x00,0x35,0xa1,0x84,0x00,0x35,0xa2,0x84,0x00,0x35,0xa3,0x84,0x00,0x35,0xa4,
+0x84,0x00,0x35,0xa5,0x84,0x00,0x35,0xa6,0x84,0x00,0x35,0xa7,0x84,0x00,0x35,0xef,
+0xfc,0xcd,0x78,0xae,0xa4,0x00,0x84,0x35,0xa0,0x1d,0x07,0xfe,0xcd,0xa4,0xb7,0x00,
+0xa9,0x41,0x01,0xab,0x5b,0x01,0x6b,0x78,0x84,0xc6,0x02,0x6b,0x79,0x84,0xc6,0x03,
+0x6b,0x7a,0x84,0xc6,0x04,0x6b,0x7b,0x84,0xc6,0xef,0x01,0xc7,0x5f,0x26,0x70,0x01,
+0xce,0x64,0x26,0x71,0x01,0xc6,0x88,0x88,0x88,0x88,0x81,0x07,0xfe,0xcd,0xa4,0xb7,
+0x00,0xa9,0x41,0x01,0xab,0x81,0x84,0x84,0x84,0x84,0x00,0x40,0xc7,0x01,0x7b,0x01,
+0x40,0xc7,0x02,0x7b,0x02,0x40,0xc7,0x03,0x7b,0x03,0x40,0xc7,0x04,0x7b,0xef,0xfc,
+0xcd,0x5f,0xa4,0x00,0x40,0x35,0xa0,0x1e,0x23,0xad,0x5b,0xef,0xfc,0xcd,0x1c,0xae,
+0xa4,0x00,0x40,0x35,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x13,0xb6,0x14,
+0x20,0x1c,0x40,0x00,0x35,0x1d,0x40,0x00,0x35,0x1e,0x40,0x00,0x35,0x1f,0x40,0x00,
+0x35,0x04,0x6b,0x02,0xaa,0x04,0x7b,0x18,0x26,0x12,0x3d,0x04,0x6b,0x40,0xaa,0x04,
+0x7b,0x06,0x26,0x5c,0x01,0xc6,0x04,0x6b,0x10,0xaa,0x04,0x7b,0x06,0x26,0x5b,0x01,
+0xc6,0x01,0x6b,0x02,0x6b,0x03,0x6b,0x4f,0x04,0x6b,0x01,0xa6,0xef,0xfc,0xcd,0xb4,
+0xae,0xa4,0x00,0x84,0x35,0xa3,0x18,0xa2,0x18,0x6b,0xca,0xcd,0x5b,0x01,0x6b,0xb4,
+0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,0x03,0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,
+0xc6,0xed,0xc6,0xcd,0xfa,0xa6,0x14,0x45,0x00,0x35,0x15,0x45,0x00,0x35,0x16,0x45,
+0x00,0x35,0x17,0x45,0x02,0x35,0x88,0x88,0x88,0x88,0x81,0x01,0x40,0x00,0x35,0x02,
+0x40,0x00,0x35,0x03,0x40,0x00,0x35,0x81,0x84,0x84,0x84,0x84,0x71,0x01,0x5f,0x72,
+0xef,0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0xa2,0x19,0x07,0xfe,0xcd,0xa4,0xb7,
+0x00,0xa9,0x41,0x01,0xab,0x5b,0x01,0x6b,0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,
+0x03,0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,0xc6,0x14,0x45,0x00,0x35,0x15,0x45,
+0x00,0x35,0x16,0x45,0x00,0x35,0x17,0x45,0x01,0x35,0x00,0x40,0x00,0x35,0x47,0xad,
+0x00,0x40,0x80,0x35,0x4d,0xad,0x88,0x88,0x88,0x88,0x81,0xac,0x84,0x00,0x35,0xad,
+0x84,0x00,0x35,0xae,0x84,0x00,0x35,0x81,0x00,0x88,0x00,0x35,0x01,0x88,0x00,0x35,
+0x02,0x88,0x00,0x35,0x81,0xa2,0x14,0xa3,0x14,0xa0,0x3f,0xa1,0x3f,0xa2,0xb7,0x01,
+0xa4,0xa2,0xb6,0xa3,0xb7,0xf8,0xa4,0xa3,0xb6,0x2e,0xfc,0xcd,0x08,0xae,0x90,0x5f,
+0x26,0xb6,0x81,0x84,0x84,0x84,0x84,0x84,0x84,0x25,0xad,0x03,0x88,0x01,0x35,0x08,
+0x88,0x00,0x35,0x09,0x88,0x30,0x35,0x0a,0x88,0x00,0x35,0x0b,0x88,0x00,0x35,0xef,
+0xfc,0xcd,0x0c,0xae,0xa4,0x00,0x88,0x35,0xa3,0x1e,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,
+0x4f,0xa3,0xb7,0x07,0xa4,0x05,0x7b,0x18,0x88,0x00,0x35,0x19,0x88,0x00,0x35,0x1a,
+0x88,0xff,0x35,0x1b,0x88,0xff,0x35,0x14,0x88,0x00,0x35,0x15,0x88,0x00,0x35,0x16,
+0x88,0xff,0x35,0x17,0x88,0xff,0x35,0x10,0x88,0x00,0x35,0x11,0x88,0x5f,0x35,0x12,
+0x88,0xff,0x35,0x13,0x88,0xff,0x35,0x3c,0xc9,0xcd,0x03,0x88,0x00,0x35,0xef,0xfc,
+0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0xa2,0x1e,0xa0,0x1e,0x07,0xfe,0xcd,0xa4,0xb7,
+0x00,0xa9,0x41,0x01,0xab,0x5b,0x01,0x6b,0xb4,0x84,0xc6,0x02,0x6b,0xb5,0x84,0xc6,
+0x03,0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,0xc6,0x49,0xc9,0xcd,0xaf,0x84,0x20,
+0x35,0xef,0xfc,0xcd,0x7c,0xae,0xa4,0x00,0x84,0x35,0xa0,0x14,0xa1,0x1a,0xa1,0x10,
+0x1e,0xc9,0xcd,0x09,0x20,0xa1,0x1a,0xa1,0x10,0x1e,0xc9,0xcd,0x12,0x20,0xa1,0x10,
+0x1e,0xc9,0xcd,0x19,0x20,0x1e,0xc9,0xcd,0x27,0x20,0x17,0x27,0x4a,0x11,0x27,0x4a,
+0x0d,0x27,0x4a,0x0b,0x27,0x4a,0x05,0x7b,0x49,0xc9,0xcd,0xaf,0x84,0x00,0x35,0x7c,
+0x84,0x00,0x35,0x7d,0x84,0x00,0x35,0x7e,0x84,0x00,0x35,0x7f,0x84,0x00,0x35,0x3c,
+0xc9,0xcd,0x03,0x88,0x00,0x35,0x9f,0xc7,0xcd,0x88,0x88,0x88,0x88,0x89,0x88,0x81,
+0xac,0x84,0x00,0x35,0xad,0x84,0x00,0x35,0xae,0x84,0x00,0x35,0xaf,0x84,0x00,0x35,
+0x7c,0x84,0x00,0x35,0x7d,0x84,0x00,0x35,0x7e,0x84,0x00,0x35,0x7f,0x84,0x00,0x35,
+0x00,0x88,0x00,0x35,0x01,0x88,0x00,0x35,0x02,0x88,0x00,0x35,0x03,0x88,0x00,0x35,
+0xaf,0xad,0x6f,0x01,0x5f,0x72,0xe4,0x01,0x5f,0x72,0x81,0x84,0x84,0x84,0x84,0xb4,
+0x84,0xc7,0x01,0x7b,0xb5,0x84,0xc7,0x02,0x7b,0xb6,0x84,0xc7,0x03,0x7b,0xb7,0x84,
+0xc7,0x04,0x7b,0xef,0xfc,0xcd,0xb4,0xae,0xa4,0x00,0x84,0x35,0xa1,0x1c,0x07,0xfe,
+0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x01,0xab,0x5b,0x01,0x6b,0xb4,0x84,0xc6,0x02,0x6b,
+0xb5,0x84,0xc6,0x03,0x6b,0xb6,0x84,0xc6,0x04,0x6b,0xb7,0x84,0xc6,0x88,0x88,0x88,
+0x88,0x81,0x07,0xfe,0xcd,0xa4,0xb7,0x00,0xa9,0x41,0x03,0xab,0xef,0xfc,0xcc,0x5f,
+0xa4,0x00,0x84,0x35,0xa0,0x00,0x30,0x35,0x0c,0xad,0x5b,0xef,0xfc,0xcd,0x5f,0xa4,
+0x00,0x84,0x35,0xa0,0x1a,0xa0,0x3f,0x1b,0xad,0x5b,0x81,0xa0,0x3f,0x07,0xfe,0xcd,
+0xa4,0xb7,0x00,0xa9,0x41,0x03,0xab,0xef,0xfc,0xcc,0x5f,0xa4,0x00,0x84,0x35,0xa0,
+0x18,0x0a,0xad,0x5b,0xef,0xfc,0xcd,0x5f,0xa4,0x00,0x84,0x35,0x15,0xad,0x5b,0x81,
+0x85,0x90,0x85,0x90,0x01,0xee,0x72,0x02,0x7b,0x05,0x20,0x05,0xee,0x72,0x06,0x7b,
+0x07,0x24,0x05,0xe2,0x72,0x9f,0x06,0xe0,0x72,0x89,0x88,0x81,0x85,0x90,0x85,0x90,
+0x05,0xee,0x72,0x06,0x7b,0x05,0x20,0x01,0xee,0x72,0x02,0x7b,0x07,0x24,0x05,0xe2,
+0x72,0x9f,0x06,0xe0,0x72,0x89,0x88,0x81,0x84,0x84,0xe9,0x26,0xa4,0xb6,0xed,0x26,
+0x5d,0x01,0x6b,0x00,0xa2,0xa4,0xb7,0x01,0x7b,0x02,0x6b,0x01,0xa0,0x97,0x02,0x7b,
+0x9d,0x01,0x20,0x01,0xef,0x72,0x02,0x6b,0x63,0xfc,0xcd,0x03,0xae,0x90,0xa7,0x3f,
+0x5f,0x88,0x88,0x81,0x41,0x20,0x40,0x35,0x48,0x20,0x5f,0x72,0x46,0x20,0x5f,0x72,
+0x45,0x20,0x01,0x35,0x81,0x9a,0xd8,0x01,0xcf,0xd9,0x01,0xc7,0x9b,0x81,0x44,0x42,
+0x00,0x35,0x45,0x42,0x00,0x35,0x46,0x42,0x00,0x35,0x47,0x42,0x00,0x35,0x00,0x42,
+0x00,0x35,0x01,0x42,0x00,0x35,0x02,0x42,0x01,0x35,0x03,0x42,0x01,0x35,0x10,0x20,
+0x00,0x42,0x08,0x35,0x01,0x42,0x00,0x35,0x02,0x42,0x01,0x35,0x03,0x42,0x00,0x35,
+0x12,0x26,0x4a,0xbf,0x00,0xc6,0x20,0x40,0x00,0x35,0x21,0x40,0x00,0x35,0x22,0x40,
+0x00,0x35,0x23,0x40,0x01,0x35,0x04,0x44,0xc2,0x00,0x55,0x05,0x44,0xc3,0x00,0x55,
+0x06,0x44,0xc4,0x00,0x55,0x07,0x44,0xc5,0x00,0x55,0x00,0x44,0xc6,0x00,0x55,0x01,
+0x44,0xc7,0x00,0x55,0x02,0x44,0xc8,0x00,0x55,0x03,0x44,0xc9,0x00,0x55,0x81,0x85,
+0x4f,0xf3,0x25,0xbf,0x00,0xc1,0x01,0x6b,0x4c,0x01,0x7b,0x7e,0xc4,0xcd,0x06,0x20,
+0x4f,0x88,0x81,0x9a,0xd2,0xfc,0xcd,0xa0,0x3f,0xa1,0x3f,0xa2,0x3f,0x81,0xa0,0xb7,
+0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x81,0x9a,0xd2,0xfc,0xcd,0xa4,0xb7,0x01,0xaa,
+0x41,0x81,0xa4,0xc6,0x92,0xa5,0xbf,0xa4,0xb7,0x81,0x1d,0xad,0xa3,0x3f,0xa4,0xb7,
+0x01,0xaa,0x3b,0xc5,0xcc,0x4f,0x29,0xad,0xa3,0x00,0x3d,0x35,0x03,0xee,0x72,0xa4,
+0xb7,0x02,0x7b,0x9b,0x37,0xad,0xa3,0x00,0x08,0x35,0xa4,0xb7,0x02,0xaa,0x41,0x24,
+0xaa,0x02,0xee,0x72,0x03,0x7b,0x9b,0xd3,0x26,0x04,0xe1,0x72,0x33,0xad,0x02,0xaa,
+0x41,0x03,0xaa,0x02,0xee,0x72,0x03,0x7b,0x3a,0xc5,0xcc,0x03,0x26,0x01,0x6b,0x4a,
+0x01,0x7b,0x9a,0xd2,0xfc,0xcd,0xa4,0xb7,0x02,0xaa,0x02,0x7b,0x03,0xee,0x72,0x68,
+0xad,0x04,0x7b,0x9b,0x1c,0x20,0x01,0x6b,0xff,0xa6,0x04,0x6b,0x03,0xa6,0x02,0x20,
+0x83,0xa6,0x04,0x26,0x04,0xa1,0xbf,0x00,0xc6,0x67,0xad,0x41,0x1c,0xaa,0x02,0xee,
+0x72,0x03,0x7b,0x9b,0x72,0xad,0x41,0x18,0xaa,0x02,0xee,0x72,0x03,0x7b,0x9b,0x7d,
+0xad,0x41,0x14,0xaa,0x02,0xee,0x72,0x03,0x7b,0x9b,0xd7,0x26,0x04,0xe1,0x72,0x27,
+0xc6,0xcd,0x01,0xaa,0x41,0x13,0xaa,0x02,0xee,0x72,0x03,0x7b,0xb6,0x27,0x01,0x6b,
+0x4a,0x01,0x7b,0x2f,0xc6,0xcd,0x10,0xaa,0x02,0xee,0x72,0x03,0x7b,0x39,0xc6,0xcd,
+0x04,0x7b,0x9b,0x17,0x20,0x01,0x6b,0xff,0xa6,0x04,0x6b,0xcf,0xa6,0x02,0x20,0x0f,
+0xa6,0x06,0x20,0x0c,0xa6,0x08,0x20,0x06,0x27,0x4a,0x05,0x27,0x14,0xb6,0xcc,0x26,
+0x04,0xe1,0x72,0x27,0xc6,0xcd,0x01,0xaa,0x41,0x0d,0xaa,0x02,0xee,0x72,0x03,0x7b,
+0x81,0x85,0x85,0x85,0x85,0x4c,0x06,0x26,0x01,0x6b,0x4a,0x01,0x7b,0x2f,0xc6,0xcd,
+0x0c,0xaa,0x02,0xee,0x72,0x03,0x7b,0x8c,0xfc,0xcd,0x10,0xa6,0x39,0xc6,0xcd,0x04,
+0x7b,0x9b,0x22,0x20,0x01,0x6b,0xff,0xa6,0x04,0x6b,0xfc,0xa6,0x02,0x20,0xf0,0xa6,
+0x06,0x20,0xcc,0xa6,0x0a,0x20,0xc0,0xa6,0x0e,0x20,0x0c,0xa6,0x12,0x20,0x0f,0xa6,
+0x16,0x20,0x0c,0xa6,0x18,0x27,0x4a,0x17,0x27,0x4a,0x16,0x27,0x4a,0x15,0x27,0x4a,
+0x14,0x27,0x4a,0x29,0x27,0x4a,0x16,0x27,0x13,0xb6,0xc9,0x26,0x04,0xe1,0x72,0x27,
+0xc6,0xcd,0x01,0xaa,0x41,0x0b,0xaa,0x02,0xee,0x72,0x03,0x7b,0x66,0x27,0x01,0x6b,
+0x4a,0x01,0x7b,0x2f,0xc6,0xcd,0x08,0xaa,0x02,0xee,0x72,0x03,0x7b,0xa0,0xb7,0x03,
+0xaa,0xa0,0xb6,0xa1,0xb7,0xc3,0xaa,0xa0,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x04,0x7b,
+0x9b,0x25,0x20,0x01,0x6b,0xff,0xa6,0x04,0x6b,0x4f,0x01,0x20,0x0c,0xa6,0x04,0x27,
+0x15,0x3d,0x1e,0xc6,0xcd,0x41,0x04,0xaa,0x02,0xee,0x72,0x03,0x7b,0x9b,0x1e,0xc6,
+0xcd,0x9b,0x02,0x6b,0x03,0xef,0x72,0x50,0xaa,0x41,0x4f,0x58,0x58,0x97,0x88,0x88,
+0x88,0x88,0x81,0x07,0xfe,0xcd,0xc6,0xae,0xa4,0x00,0x00,0x35,0x9b,0x81,0xa4,0xb7,
+0x00,0xa9,0x41,0x01,0xab,0x81,0xa0,0xb7,0xa1,0xb7,0xa2,0xb7,0x4f,0xa3,0xb7,0x81,
+0xa0,0xb7,0x03,0xa4,0xa0,0xb6,0xa1,0x3f,0xa2,0x3f,0xa3,0x3f,0x8c,0xfc,0xcd,0x18,
+0xa6,0x7a,0xfc,0xcd,0x4a,0x81,0xa4,0xb7,0x00,0xa9,0x41,0x07,0xab,0x81,0xc6,0x00,
+0x00,0x35,0xc7,0x00,0x00,0x35,0xc8,0x00,0x18,0x35,0x81,0x2c,0xad,0x18,0xa4,0x48,
+0x48,0x48,0x4a,0x12,0xb6,0xef,0xfc,0xcd,0x43,0xad,0x81,0x8b,0x41,0x00,0xa9,0x41,
+0x0a,0xab,0x5b,0x9a,0xef,0xfc,0xcd,0x0c,0xae,0xa4,0x00,0x84,0x35,0xa3,0x36,0xa2,
+0x36,0xa1,0x36,0xa0,0x34,0x68,0xad,0x0a,0x20,0xa0,0x39,0xa1,0x39,0xa2,0x39,0xa3,
+0x38,0x74,0xad,0x0c,0x26,0x04,0xa1,0xbf,0x00,0xc6,0x84,0x84,0x84,0x84,0x84,0x81,
+0xe1,0xcd,0x88,0x0b,0x7b,0x88,0x0b,0x7b,0x88,0x0b,0x7b,0x88,0x0b,0x7b,0x88,0x06,
+0x7b,0x06,0x6b,0x44,0x44,0x06,0x7b,0x9c,0xfd,0xcd,0x02,0xa6,0x6f,0xad,0x5b,0x0e,
+0x26,0x04,0xa1,0xbf,0x00,0xc6,0x2c,0x27,0x16,0x3d,0x06,0x6b,0x08,0xa6,0x07,0x6b,
+0x4f,0x08,0x6b,0xbb,0xa6,0x09,0x6b,0x80,0xa6,0x0a,0x6b,0xc6,0x00,0x00,0x35,0xc7,
+0x00,0x00,0x35,0xc8,0x00,0x60,0x35,0xc9,0x00,0x00,0x35,0x18,0x20,0xac,0xa6,0x09,
+0x6b,0x44,0xa6,0x0a,0x6b,0xc6,0x00,0x00,0x35,0xc7,0x00,0x00,0x35,0xc8,0x00,0x62,
+0x35,0xc9,0x00,0x00,0x35,0x39,0x20,0x10,0xa6,0x07,0x6b,0x4f,0x08,0x6b,0x5d,0xa6,
+0x09,0x6b,0xc0,0xa6,0x0a,0x6b,0xc6,0x00,0x00,0x35,0xc7,0x00,0x00,0x35,0xc8,0x00,
+0x30,0x35,0xc9,0x00,0x00,0x35,0x18,0x20,0x56,0xa6,0x09,0x6b,0x22,0xa6,0x0a,0x6b,
+0xc6,0x00,0x00,0x35,0xc7,0x00,0x00,0x35,0xc8,0x00,0x31,0x35,0xc9,0x00,0x00,0x35,
+0x74,0x20,0x20,0xa6,0x07,0x6b,0x4f,0x08,0x6b,0x2e,0xa6,0x09,0x6b,0xe0,0xa6,0x0a,
+0x6b,0x36,0xc4,0xcd,0xc9,0x00,0x00,0x35,0xc4,0xc3,0xcc,0x20,0xa6,0x07,0x6b,0x4f,
+0x08,0x6b,0x2b,0xa6,0x09,0x6b,0x11,0xa6,0x0a,0x6b,0x36,0xc4,0xcd,0xc9,0x00,0x80,
+0x35,0xc4,0xc3,0xcc,0x20,0xa6,0x07,0x6b,0x4f,0x08,0x6b,0x1f,0xa6,0x09,0x6b,0x40,
+0xa6,0x0a,0x6b,0xc6,0x00,0x00,0x35,0xc7,0x00,0x00,0x35,0xc8,0x00,0x10,0x35,0xc9,
+0x00,0x00,0x35,0xc4,0xc3,0xcc,0x20,0xa6,0x07,0x6b,0x4f,0x08,0x6b,0x2e,0xa6,0x09,
+0x6b,0xe0,0xa6,0x0a,0x6b,0x4f,0x36,0xc4,0xcd,0xc9,0x00,0x00,0x35,0xa5,0xc3,0xcc,
+0x03,0x26,0x4a,0x8b,0xc3,0xcc,0x03,0x26,0x4a,0x6a,0xc3,0xcc,0x03,0x26,0x4a,0x50,
+0xc3,0xcc,0x03,0x26,0x4a,0x6d,0x27,0x4a,0x57,0x27,0x4a,0x38,0x27,0x13,0xb6,0x9a,
+0xef,0xfc,0xcd,0xa4,0xbf,0x84,0xae,0xa3,0x1a,0x07,0xfe,0xcd,0x43,0xc4,0xcd,0x5b,
+0x9b,0xbb,0xfd,0xcd,0x43,0xc4,0xcd,0x5b,0xc1,0xfd,0xcd,0x6b,0xc4,0xcd,0x5b,0x26,
+0xc4,0xcd,0x5b,0x4b,0xc4,0xcd,0x5a,0x01,0x26,0x4d,0x5f,0x12,0xb6,0x15,0x20,0xa3,
+0x10,0xc1,0xfd,0xcd,0x6b,0xc4,0xcd,0x5b,0x26,0xc4,0xcd,0x5b,0x4b,0xc4,0xcd,0x5a,
+0x01,0x26,0x4d,0x5f,0x12,0xb6,0x19,0x26,0x4a,0x11,0xb6,0x3a,0x20,0x08,0x6b,0x40,
+0xaa,0x08,0x7b,0x0a,0x6b,0x02,0xaa,0x0a,0x7b,0x0e,0x26,0x02,0xa1,0x11,0xb6,0x0a,
+0x6b,0x04,0xaa,0x0a,0x7b,0x06,0x27,0x16,0x3d,0xef,0xfc,0xcd,0x43,0xc4,0xcd,0x5b,
+0xa2,0x1e,0xa0,0xbf,0xa1,0xb7,0x3e,0xa4,0xa1,0xb6,0xa2,0xbf,0xa3,0xbf,0x8c,0xfc,
+0xcd,0x11,0xa6,0x61,0xc4,0xcd,0x14,0x20,0xa0,0x14,0xa0,0x3f,0xa1,0xb7,0x3e,0xa4,
+0xa1,0xb6,0xa2,0x3f,0xa3,0x3f,0x8c,0xfc,0xcd,0x11,0xa6,0x61,0xc4,0xcd,0x18,0x27,
+0xe3,0x01,0xce,0x05,0x6b,0x18,0xa6,0x02,0x20,0x14,0xa6,0x06,0x20,0x10,0xa6,0x08,
+0x20,0x06,0x27,0x4a,0x05,0x27,0x14,0xb6,0x8b,0x41,0x00,0xa2,0x41,0x0a,0xa0,0x5b,
+0x81,0x4f,0x13,0xb7,0x53,0x20,0xc6,0x50,0x20,0x12,0x72,0x81,0x01,0xa6,0x03,0x27,
+0x4d,0x00,0xc0,0xcd,0x88,0xa6,0x12,0xb7,0x53,0x20,0xc6,0x50,0x20,0x15,0x72,0x81,
+0x01,0xa6,0x03,0x27,0x4d,0x00,0xc0,0xcd,0x88,0xa6,0x81,0x01,0xa6,0x03,0x27,0x4d,
+0x5d,0xc0,0xcd,0x41,0xa6,0x81,0x01,0xa6,0x03,0x27,0x4d,0x48,0xc0,0xcd,0xaa,0x00,
+0x5f,0x72,0x50,0x20,0x20,0x35,0x52,0x20,0x09,0x35,0x81,0x4d,0x00,0xc0,0xcd,0x88,
+0xa6,0x50,0x20,0x20,0x35,0x53,0x20,0xc7,0xcb,0x20,0x4f,0x50,0x20,0x12,0x72,0xec,
+0x25,0x07,0xe1,0x72,0x01,0x6b,0x4c,0x01,0x7b,0xda,0x26,0x13,0xad,0xbe,0x01,0xd6,
+0x01,0xee,0x72,0x0d,0x20,0x4f,0xed,0xc6,0xcd,0x05,0xa6,0xec,0x26,0x25,0xad,0x03,
+0x7b,0xf2,0x26,0x4d,0x00,0xc0,0xcd,0x88,0xa6,0x81,0x85,0x85,0x85,0x01,0xa6,0x06,
+0x27,0x4d,0x5d,0xc0,0xcd,0x02,0x7b,0x08,0x26,0x4d,0x48,0xc0,0xcd,0xaa,0x00,0x5f,
+0x72,0x50,0x20,0x20,0x35,0x52,0x20,0x09,0x35,0x88,0x89,0x88,0x81,0x4d,0x00,0xc0,
+0xcd,0x88,0xa6,0x99,0xc0,0xcc,0x4f,0xed,0xc6,0xcd,0x05,0xa6,0x95,0x25,0x06,0xe1,
+0x72,0x01,0x7b,0xbe,0x01,0xd7,0x53,0x20,0xc6,0x01,0x6b,0x4c,0x9f,0x01,0xee,0x72,
+0x0d,0x20,0x11,0xe7,0x53,0x20,0xc6,0x97,0x07,0xeb,0x72,0x4a,0x01,0x6b,0x4c,0x01,
+0x7b,0x11,0x25,0x09,0xa1,0x06,0x7b,0x50,0x20,0x22,0x35,0x04,0x26,0xa8,0xb1,0xa8,
+0xbf,0x90,0x0b,0x26,0xa7,0xb3,0xa7,0x3f,0x01,0xe6,0x72,0x4a,0x5a,0x01,0x26,0x4d,
+0x5f,0x06,0x7b,0x50,0x20,0x15,0x72,0x04,0x26,0xa8,0xb1,0xa8,0xbf,0x90,0x0b,0x26,
+0xa7,0xb3,0xa7,0x3f,0x01,0xe6,0x72,0x5a,0x01,0x24,0x02,0xa0,0x5f,0x1a,0x25,0x02,
+0xa1,0x06,0x7b,0xba,0x26,0x72,0xad,0x50,0x20,0x15,0x72,0x04,0x26,0x4a,0x06,0x7b,
+0xc7,0x26,0x4d,0x90,0xad,0x01,0xaa,0x02,0x7b,0xd0,0x26,0x4d,0x84,0xad,0xed,0xc6,
+0xcd,0x05,0xa6,0xda,0x26,0x4d,0xc1,0xcd,0x50,0x20,0x20,0x35,0x53,0x20,0xc7,0x03,
+0x7b,0x02,0x20,0x52,0x80,0xae,0x03,0x7b,0x07,0x26,0x80,0xa1,0x06,0x7b,0xf5,0x26,
+0x4d,0xc1,0xcd,0x81,0x85,0x85,0x85,0x01,0xa6,0x06,0x27,0x4d,0xc9,0xad,0x02,0x7b,
+0x07,0x26,0x4d,0xbb,0xad,0xaa,0x00,0x5f,0x72,0x01,0x6b,0x4f,0x50,0x20,0x20,0x35,
+0x52,0x20,0x09,0x35,0x88,0x89,0x88,0x81,0x4f,0x50,0x20,0x24,0x35,0xed,0xc6,0xcd,
+0x05,0xa6,0x81,0x01,0xa6,0x03,0x27,0x4d,0xb7,0xad,0x82,0xa6,0x50,0x20,0x21,0x35,
+0x53,0x20,0xc7,0x81,0x4f,0xed,0xc6,0xcd,0x05,0xa6,0x81,0x01,0xa6,0x03,0x27,0x4d,
+0xcf,0xad,0x81,0xa6,0x50,0x20,0x29,0x35,0x81,0x85,0x4f,0xaa,0x00,0x5f,0x72,0x81,
+0x85,0x01,0xa6,0xaa,0x00,0x5f,0x72,0x50,0x20,0x22,0x35,0x0c,0xaa,0x00,0x0d,0x72,
+0x05,0x26,0x01,0xe1,0x72,0x01,0xe4,0x72,0xfa,0x27,0xaa,0x00,0xc6,0x8f,0x01,0x20,
+0x88,0x81,0x85,0x4f,0x81,0x85,0x01,0xa6,0x50,0x20,0x05,0x35,0x08,0x27,0x01,0xe1,
+0x72,0x01,0xe4,0x72,0x51,0x20,0xc6,0xfa,0x51,0x20,0x0f,0x72,0x9d,0x01,0x20,0x88,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x20,0x8f,
+0xe3,0x26,0x01,0x7b,0xe3,0xf2,0xcd,0x03,0x26,0xd8,0x01,0xca,0xd9,0x01,0xc6,0xeb,
+0xf1,0xcd,0x03,0x24,0x20,0xa1,0x12,0x27,0x01,0x6b,0x13,0x18,0xcd,0x64,0x18,0xcd,
+0x88,0x81,0x84,0x06,0x20,0x08,0x35,0x9a,0x1a,0x20,0x10,0x72,0x15,0x20,0xc7,0xee,
+0xa4,0x15,0x20,0xc6,0x14,0x20,0xc7,0x7c,0xa4,0x14,0x20,0xc6,0x13,0x20,0xc7,0x08,
+0xa4,0x13,0x20,0xc6,0xdc,0xc6,0xcd,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0xd0,
+0xdf,0xcd,0x6b,0x01,0x3b,0x6c,0x01,0x3b,0x6d,0x01,0x3b,0x6e,0x01,0x3b,0x01,0x4b,
+0x80,0x4b,0x85,0x4b,0x80,0x4b,0xb0,0x84,0x00,0x35,0xb1,0x84,0x00,0x35,0xb2,0x84,
+0x00,0x35,0xb3,0x84,0x15,0x35,0xa4,0x84,0x00,0x35,0xa5,0x84,0x00,0x35,0xa6,0x84,
+0x00,0x35,0xa7,0x84,0x00,0x35,0xa0,0x84,0x00,0x35,0xa1,0x84,0x00,0x35,0xa2,0x84,
+0x00,0x35,0xa3,0x84,0x00,0x35,0x0c,0x8c,0x00,0x35,0x0d,0x8c,0x00,0x35,0x0e,0x8c,
+0x00,0x35,0x0f,0x8c,0x00,0x35,0x18,0x8c,0x00,0x35,0x19,0x8c,0x00,0x35,0x1a,0x8c,
+0x00,0x35,0x1b,0x8c,0x03,0x35,0x04,0x8c,0x00,0x35,0x05,0x8c,0x00,0x35,0x06,0x8c,
+0x00,0x35,0x07,0x8c,0x0a,0x35,0x00,0x8c,0x00,0x35,0x01,0x8c,0x00,0x35,0x02,0x8c,
+0x00,0x35,0x03,0x8c,0x00,0x35,0x1c,0x8c,0x00,0x35,0x1d,0x8c,0x00,0x35,0x1e,0x8c,
+0x00,0x35,0x1f,0x8c,0x04,0x35,0xe6,0xc7,0xcd,0x56,0xc9,0xcd,0x24,0x83,0x00,0x35,
+0x25,0x83,0x00,0x35,0x26,0x83,0x02,0x35,0x27,0x83,0x00,0x35,0x84,0x84,0x00,0x35,
+0x85,0x84,0x00,0x35,0x86,0x84,0x00,0x35,0x87,0x84,0x20,0x35,0xb4,0x84,0x00,0x35,
+0xb5,0x84,0x20,0x35,0xb6,0x84,0x00,0x35,0xb7,0x84,0xa0,0x35,0x18,0x84,0x00,0x35,
+0x19,0x84,0x00,0x35,0x1a,0x84,0x00,0x35,0x1b,0x84,0x00,0x35,0x78,0x84,0x00,0x35,
+0x79,0x84,0x00,0x35,0x7a,0x84,0x00,0x35,0x7b,0x84,0x00,0x35,0x3f,0x20,0x01,0x35,
+0x3d,0x20,0xc7,0xff,0xa6,0x3c,0x20,0xc7,0x04,0xa6,0x3e,0x20,0x20,0x35,0x6b,0x01,
+0x02,0x35,0x6c,0x01,0x49,0x35,0x6d,0x01,0xf0,0x35,0x6e,0x01,0xc7,0x0f,0x20,0x6b,
+0x01,0x01,0x35,0x6c,0x01,0x9b,0x35,0x6d,0x01,0xfc,0x35,0x6e,0x01,0xc0,0x35,0x0c,
+0x20,0x6c,0x01,0x8c,0x35,0x6d,0x01,0xba,0x35,0x6e,0x01,0x80,0x35,0x1a,0x20,0x6c,
+0x01,0x24,0x35,0x6d,0x01,0xf8,0x35,0x6e,0x01,0xc7,0x3c,0x20,0x6b,0x01,0x5f,0x72,
+0x6c,0x01,0x5f,0x72,0x6d,0x01,0x5f,0x72,0x6e,0x01,0x5f,0x72,0x3f,0x27,0x4a,0x30,
+0x27,0x4a,0x25,0x27,0x4a,0x1b,0x27,0x0f,0xa4,0x08,0x20,0xc6,0xf0,0x01,0xc7,0x0f,
+0xa4,0x4e,0x03,0x20,0xc6,0xf2,0x25,0x10,0xa1,0x01,0x6b,0x4c,0xc8,0x01,0x4f,0x72,
+0x01,0xee,0x72,0x01,0x6b,0x4f,0xd1,0x00,0x5f,0x72,0xd2,0x00,0x5f,0x72,0xe3,0x01,
+0x5f,0x72,0xbb,0x00,0x5f,0x72,0xbd,0x00,0x5f,0x72,0xbc,0x00,0x5f,0x72,0xd9,0x01,
+0x5f,0x72,0xd8,0x01,0x5f,0x72,0x9a,0x01,0x0a,0x35,0x9d,0x01,0x5f,0x72,0x9e,0x01,
+0x5f,0x72,0xa8,0x01,0x5f,0x72,0x9f,0x01,0x5f,0x72,0xa0,0x01,0x5f,0x72,0xa1,0x01,
+0x5f,0x72,0x85,0x01,0x5f,0x72,0xe8,0x01,0x5f,0x72,0xeb,0x01,0x5f,0x72,0x70,0x01,
+0x5f,0x72,0x71,0x01,0x5f,0x72,0xaa,0x00,0x5f,0x72,0x73,0x01,0x5f,0x72,0x86,0x01,
+0x5f,0x72,0x74,0x01,0x5f,0x72,0xbf,0x00,0x5f,0x72,0xc0,0x00,0x5f,0x72,0xc1,0x00,
+0x5f,0x72,0x6f,0x01,0x5f,0x72,0x11,0x3f,0x10,0x3f,0x72,0x01,0x5f,0x72,0xc6,0x01,
+0x5f,0x72,0xc7,0x01,0x5f,0x72,0xec,0x01,0x5f,0x72,0xed,0x01,0xff,0x35,0xef,0x01,
+0x5f,0x72,0xe7,0x01,0x5f,0x72,0x9b,0x06,0x20,0x5f,0x72,0x88,0x81,0x84,0xe3,0xad,
+0xf4,0x25,0x40,0xa1,0x01,0x6b,0x4c,0x12,0x6f,0x01,0xee,0x72,0x01,0x6b,0x4f,0x88,
+0x81,0x05,0x20,0x10,0x72,0x15,0x20,0x11,0x72,0x10,0x1e,0x9f,0x1a,0xcc,0x8b,0xff,
+0xa6,0x04,0xae,0x81,0x85,0x01,0x7b,0x9a,0xc6,0x01,0xc7,0x0f,0xa4,0xc6,0x01,0xc6,
+0xc8,0x01,0x4f,0x72,0xc6,0x01,0x5c,0x72,0x01,0x6b,0xc8,0x01,0xd6,0xc6,0x01,0xce,
+0x18,0x27,0xc6,0x01,0xc1,0xc7,0x01,0xc6,0x9b,0x01,0x6b,0x4f,0x88,0x81,0xc7,0x01,
+0xc7,0x0f,0xa4,0xc7,0x01,0xc6,0xc8,0x01,0xd7,0xc7,0x01,0x5c,0x72,0xc7,0x01,0xce,
+};
diff --git a/drivers/video/av8100/hdmi.c b/drivers/video/av8100/hdmi.c
new file mode 100644
index 00000000000..c7a3970b37d
--- /dev/null
+++ b/drivers/video/av8100/hdmi.c
@@ -0,0 +1,1977 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * ST-Ericsson HDMI driver
+ *
+ * Author: Per Persson <per.xb.persson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/uaccess.h>
+#include <video/av8100.h>
+#include <video/hdmi.h>
+#include <linux/poll.h>
+#include <linux/mutex.h>
+#include <linux/ctype.h>
+#include "hdmi_loc.h"
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#define SYSFS_EVENT_FILENAME "evread"
+
+DEFINE_MUTEX(hdmi_events_mutex);
+#define LOCK_HDMI_EVENTS mutex_lock(&hdmi_events_mutex)
+#define UNLOCK_HDMI_EVENTS mutex_unlock(&hdmi_events_mutex)
+#define EVENTS_MASK 0xFF
+
+static int device_open;
+static int events;
+static int events_mask;
+static bool events_received;
+static wait_queue_head_t hdmi_event_wq;
+struct device *hdmidev;
+
+static ssize_t store_storeastext(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t store_plugdeten(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t store_edidread(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t show_edidread(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static ssize_t store_ceceven(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t show_cecread(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static ssize_t store_cecsend(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t store_infofrsend(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t store_hdcpeven(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t show_hdcpchkaesotp(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t store_hdcpfuseaes(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t show_hdcpfuseaes(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t store_hdcploadaes(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t show_hdcploadaes(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t store_hdcpauthencr(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t show_hdcpstateget(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t show_evread(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static ssize_t store_evclr(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t store_audiocfg(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t show_plugstatus(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static DEVICE_ATTR(storeastext, S_IWUSR, NULL, store_storeastext);
+static DEVICE_ATTR(plugdeten, S_IWUSR, NULL, store_plugdeten);
+static DEVICE_ATTR(edidread, S_IRUGO | S_IWUSR, show_edidread, store_edidread);
+static DEVICE_ATTR(ceceven, S_IWUSR, NULL, store_ceceven);
+static DEVICE_ATTR(cecread, S_IRUGO, show_cecread, NULL);
+static DEVICE_ATTR(cecsend, S_IWUSR, NULL, store_cecsend);
+static DEVICE_ATTR(infofrsend, S_IWUSR, NULL, store_infofrsend);
+static DEVICE_ATTR(hdcpeven, S_IWUSR, NULL, store_hdcpeven);
+static DEVICE_ATTR(hdcpchkaesotp, S_IRUGO, show_hdcpchkaesotp, NULL);
+static DEVICE_ATTR(hdcpfuseaes, S_IRUGO | S_IWUSR, show_hdcpfuseaes,
+ store_hdcpfuseaes);
+static DEVICE_ATTR(hdcploadaes, S_IRUGO | S_IWUSR, show_hdcploadaes,
+ store_hdcploadaes);
+static DEVICE_ATTR(hdcpauthencr, S_IWUSR, NULL, store_hdcpauthencr);
+static DEVICE_ATTR(hdcpstateget, S_IRUGO, show_hdcpstateget, NULL);
+static DEVICE_ATTR(evread, S_IRUGO, show_evread, NULL);
+static DEVICE_ATTR(evclr, S_IWUSR, NULL, store_evclr);
+static DEVICE_ATTR(audiocfg, S_IWUSR, NULL, store_audiocfg);
+static DEVICE_ATTR(plugstatus, S_IRUGO, show_plugstatus, NULL);
+
+/* Hex to int conversion */
+static unsigned int htoi(const char *ptr)
+{
+ unsigned int value = 0;
+ char ch = *ptr;
+
+ if (!ptr)
+ return 0;
+
+ if (isdigit(ch))
+ value = ch - '0';
+ else
+ value = toupper(ch) - 'A' + 10;
+
+ value <<= 4;
+ ch = *(++ptr);
+
+ if (isdigit(ch))
+ value += ch - '0';
+ else
+ value += toupper(ch) - 'A' + 10;
+
+ return value;
+}
+
+static int event_enable(bool enable, enum hdmi_event ev)
+{
+ dev_dbg(hdmidev, "enable_event %d %02x\n", enable, ev);
+ if (enable)
+ events_mask |= ev;
+ else
+ events_mask &= ~ev;
+
+ return 0;
+}
+
+static int plugdeten(struct plug_detect *pldet)
+{
+ struct av8100_status status;
+ u8 denc_off_time = 0;
+ int retval;
+
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_STANDBY) {
+ if (av8100_powerup() != 0) {
+ dev_err(hdmidev, "av8100_powerup failed\n");
+ return -EINVAL;
+ }
+ }
+
+ av8100_reg_hdmi_5_volt_time_r(&denc_off_time, NULL, NULL);
+
+ retval = av8100_reg_hdmi_5_volt_time_w(
+ denc_off_time,
+ pldet->hdmi_off_time,
+ pldet->on_time);
+
+ if (retval) {
+ dev_err(hdmidev, "Failed to write the value to av8100 "
+ "register\n");
+ return -EFAULT;
+ }
+
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_IDLE) {
+ av8100_disable_interrupt();
+ av8100_enable_interrupt();
+ }
+
+ event_enable(pldet->hdmi_detect_enable != 0,
+ HDMI_EVENT_HDMI_PLUGIN);
+ event_enable(pldet->hdmi_detect_enable != 0,
+ HDMI_EVENT_HDMI_PLUGOUT);
+
+ return retval;
+}
+
+static int edidread(struct edid_read *edidread, u8 *len, u8 *data)
+{
+ union av8100_configuration config;
+ struct av8100_status status;
+
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_STANDBY) {
+ if (av8100_powerup() != 0) {
+ dev_err(hdmidev, "av8100_powerup failed\n");
+ return -EINVAL;
+ }
+ }
+
+ if (status.av8100_state < AV8100_OPMODE_INIT) {
+ if (av8100_download_firmware(NULL, 0, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100 dl fw FAIL\n");
+ return -EINVAL;
+ }
+ }
+
+ config.edid_section_readback_format.address = edidread->address;
+ config.edid_section_readback_format.block_number = edidread->block_nr;
+
+ dev_dbg(hdmidev, "addr:%0x blnr:%0x",
+ config.edid_section_readback_format.address,
+ config.edid_section_readback_format.block_number);
+
+ if (av8100_conf_prep(AV8100_COMMAND_EDID_SECTION_READBACK,
+ &config) != 0) {
+ dev_err(hdmidev, "av8100_conf_prep FAIL\n");
+ return -EINVAL;
+ }
+
+ if (av8100_conf_w(AV8100_COMMAND_EDID_SECTION_READBACK,
+ len,
+ data, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100_conf_w FAIL\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(hdmidev, "len:%0x\n", *len);
+
+ return 0;
+}
+
+static int cecread(u8 *src, u8 *dest, u8 *data_len, u8 *data)
+{
+ union av8100_configuration config;
+ struct av8100_status status;
+ u8 buf_len;
+ u8 buff[HDMI_CEC_READ_MAXSIZE];
+
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_STANDBY) {
+ if (av8100_powerup() != 0) {
+ dev_err(hdmidev, "av8100_powerup failed\n");
+ return -EINVAL;
+ }
+ }
+
+ if (status.av8100_state < AV8100_OPMODE_INIT) {
+ if (av8100_download_firmware(NULL, 0, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100 dl fw FAIL\n");
+ return -EINVAL;
+ }
+ }
+
+ if (av8100_conf_prep(AV8100_COMMAND_CEC_MESSAGE_READ_BACK,
+ &config) != 0) {
+ dev_err(hdmidev, "av8100_conf_prep FAIL\n");
+ return -EINVAL;
+ }
+
+ if (av8100_conf_w(AV8100_COMMAND_CEC_MESSAGE_READ_BACK,
+ &buf_len, buff, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100_conf_w FAIL\n");
+ return -EINVAL;
+ }
+
+ if (buf_len > 0) {
+ *src = (buff[0] & 0xF0) >> 4;
+ *dest = buff[0] & 0x0F;
+ *data_len = buf_len - 1;
+ memcpy(data, &buff[1], buf_len - 1);
+ } else
+ *data_len = 0;
+
+ return 0;
+}
+
+static int cecsend(u8 src, u8 dest, u8 data_len, u8 *data)
+{
+ union av8100_configuration config;
+ struct av8100_status status;
+
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_STANDBY) {
+ if (av8100_powerup() != 0) {
+ dev_err(hdmidev, "av8100_powerup failed\n");
+ return -EINVAL;
+ }
+ }
+
+ if (status.av8100_state < AV8100_OPMODE_INIT) {
+ if (av8100_download_firmware(NULL, 0, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100 dl fw FAIL\n");
+ return -EINVAL;
+ }
+ }
+
+ if (data_len < 1)
+ return -EINVAL;
+
+ config.cec_message_write_format.buffer[0] = ((src & 0x0F) << 4) +
+ (dest & 0x0F);
+ config.cec_message_write_format.buffer_length = data_len + 1;
+ memcpy(&config.cec_message_write_format.buffer[1], data, data_len - 1);
+
+ if (av8100_conf_prep(AV8100_COMMAND_CEC_MESSAGE_WRITE,
+ &config) != 0) {
+ dev_err(hdmidev, "av8100_conf_prep FAIL\n");
+ return -EINVAL;
+ }
+
+ if (av8100_conf_w(AV8100_COMMAND_CEC_MESSAGE_WRITE,
+ NULL, NULL, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100_conf_w FAIL\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int infofrsend(u8 type, u8 version, u8 crc, u8 data_len, u8 *data)
+{
+ union av8100_configuration config;
+ struct av8100_status status;
+
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_STANDBY) {
+ if (av8100_powerup() != 0) {
+ dev_err(hdmidev, "av8100_powerup failed\n");
+ return -EINVAL;
+ }
+ }
+
+ if (status.av8100_state < AV8100_OPMODE_INIT) {
+ if (av8100_download_firmware(NULL, 0, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100 dl fw FAIL\n");
+ return -EINVAL;
+ }
+ }
+
+ if ((data_len < 1) || (data_len > HDMI_INFOFRAME_MAX_SIZE))
+ return -EINVAL;
+
+ config.infoframes_format.type = type;
+ config.infoframes_format.version = version;
+ config.infoframes_format.crc = crc;
+ config.infoframes_format.length = data_len;
+ memcpy(&config.infoframes_format.data, data, data_len);
+
+ if (av8100_conf_prep(AV8100_COMMAND_INFOFRAMES,
+ &config) != 0) {
+ dev_err(hdmidev, "av8100_conf_prep FAIL\n");
+ return -EINVAL;
+ }
+
+ if (av8100_conf_w(AV8100_COMMAND_INFOFRAMES,
+ NULL, NULL, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100_conf_w FAIL\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hdcpchkaesotp(u8 *crc, u8 *progged)
+{
+ union av8100_configuration config;
+ struct av8100_status status;
+ u8 buf_len;
+ u8 buf[2];
+
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_STANDBY) {
+ if (av8100_powerup() != 0) {
+ dev_err(hdmidev, "av8100_powerup failed\n");
+ return -EINVAL;
+ }
+ }
+
+ if (status.av8100_state < AV8100_OPMODE_INIT) {
+ if (av8100_download_firmware(NULL, 0, I2C_INTERFACE) !=
+ 0) {
+ dev_err(hdmidev, "av8100 dl fw FAIL\n");
+ return -EINVAL;
+ }
+ }
+
+ config.fuse_aes_key_format.fuse_operation = AV8100_FUSE_READ;
+ memset(config.fuse_aes_key_format.key, 0, AV8100_FUSE_KEY_SIZE);
+ if (av8100_conf_prep(AV8100_COMMAND_FUSE_AES_KEY,
+ &config) != 0) {
+ dev_err(hdmidev, "av8100_conf_prep FAIL\n");
+ return -EINVAL;
+ }
+
+ if (av8100_conf_w(AV8100_COMMAND_FUSE_AES_KEY,
+ &buf_len, buf, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100_conf_w FAIL\n");
+ return -EINVAL;
+ }
+
+ if (buf_len == 2) {
+ *crc = buf[0];
+ *progged = buf[1];
+ }
+
+ return 0;
+}
+
+static int hdcpfuseaes(u8 *key, u8 crc, u8 *result)
+{
+ union av8100_configuration config;
+ struct av8100_status status;
+ u8 buf_len;
+ u8 buf[2];
+
+ /* Default not OK */
+ *result = 1;
+
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_STANDBY) {
+ if (av8100_powerup() != 0) {
+ dev_err(hdmidev, "av8100_powerup failed\n");
+ return -EINVAL;
+ }
+ }
+
+ if (status.av8100_state < AV8100_OPMODE_INIT) {
+ if (av8100_download_firmware(NULL, 0, I2C_INTERFACE) !=
+ 0) {
+ dev_err(hdmidev, "av8100 dl fw FAIL\n");
+ return -EINVAL;
+ }
+ }
+
+ config.fuse_aes_key_format.fuse_operation = AV8100_FUSE_WRITE;
+ memcpy(config.fuse_aes_key_format.key, key, AV8100_FUSE_KEY_SIZE);
+ if (av8100_conf_prep(AV8100_COMMAND_FUSE_AES_KEY,
+ &config) != 0) {
+ dev_err(hdmidev, "av8100_conf_prep FAIL\n");
+ return -EINVAL;
+ }
+
+ if (av8100_conf_w(AV8100_COMMAND_FUSE_AES_KEY,
+ &buf_len, buf, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100_conf_w FAIL\n");
+ return -EINVAL;
+ }
+
+ if (buf_len == 2) {
+ dev_dbg(hdmidev, "buf[0]:%02x buf[1]:%02x\n", buf[0], buf[1]);
+ if ((crc == buf[0]) && (buf[1] == 1))
+ /* OK */
+ *result = 0;
+ }
+
+ return 0;
+}
+
+static int hdcploadaes(u8 block, u8 key_len, u8 *key, u8 *result)
+{
+ union av8100_configuration config;
+ struct av8100_status status;
+
+ /* Default not OK */
+ *result = 1;
+
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_STANDBY) {
+ if (av8100_powerup() != 0) {
+ dev_err(hdmidev, "av8100_powerup failed\n");
+ return -EINVAL;
+ }
+ }
+
+ if (status.av8100_state < AV8100_OPMODE_INIT) {
+ if (av8100_download_firmware(NULL, 0, I2C_INTERFACE) !=
+ 0) {
+ dev_err(hdmidev, "av8100 dl fw FAIL\n");
+ return -EINVAL;
+ }
+ }
+
+ config.hdcp_send_key_format.key_number = block;
+ config.hdcp_send_key_format.data_len = key_len;
+ memcpy(config.hdcp_send_key_format.data, key, key_len);
+ if (av8100_conf_prep(AV8100_COMMAND_HDCP_SENDKEY, &config) != 0) {
+ dev_err(hdmidev, "av8100_conf_prep FAIL\n");
+ return -EINVAL;
+ }
+
+ if (av8100_conf_w(AV8100_COMMAND_HDCP_SENDKEY,
+ NULL, NULL, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100_conf_w FAIL\n");
+ return -EINVAL;
+ }
+
+ *result = 0;
+
+ return 0;
+}
+
+static int hdcpauthencr(u8 auth_type, u8 encr_type)
+{
+ union av8100_configuration config;
+ struct av8100_status status;
+
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_STANDBY) {
+ if (av8100_powerup() != 0) {
+ dev_err(hdmidev, "av8100_powerup failed\n");
+ return -EINVAL;
+ }
+ }
+
+ if (status.av8100_state < AV8100_OPMODE_INIT) {
+ if (av8100_download_firmware(NULL, 0, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100 dl fw FAIL\n");
+ return -EINVAL;
+ }
+ }
+
+ switch (auth_type) {
+ case HDMI_HDCP_AUTH_OFF:
+ default:
+ config.hdcp_management_format.req_type =
+ AV8100_HDCP_AUTH_REQ_OFF;
+ break;
+
+ case HDMI_HDCP_AUTH_START:
+ config.hdcp_management_format.req_type =
+ AV8100_HDCP_AUTH_REQ_ON;
+ break;
+
+ case HDMI_HDCP_AUTH_CONT:
+ config.hdcp_management_format.req_type =
+ AV8100_HDCP_AUTH_CONT;
+ break;
+ }
+
+ switch (encr_type) {
+ case HDMI_HDCP_ENCR_OFF:
+ config.hdcp_management_format.req_encr =
+ AV8100_HDCP_ENCR_REQ_OFF;
+ config.hdcp_management_format.encr_use =
+ AV8100_HDCP_ENCR_USE_OESS;
+ break;
+
+ case HDMI_HDCP_ENCR_OESS:
+ config.hdcp_management_format.req_encr =
+ AV8100_HDCP_ENCR_REQ_ON;
+ config.hdcp_management_format.encr_use =
+ AV8100_HDCP_ENCR_USE_OESS;
+ break;
+
+ case HDMI_HDCP_ENCR_EESS:
+ config.hdcp_management_format.req_encr =
+ AV8100_HDCP_ENCR_REQ_ON;
+ config.hdcp_management_format.encr_use =
+ AV8100_HDCP_ENCR_USE_EESS;
+ break;
+ }
+
+ if (av8100_conf_prep(AV8100_COMMAND_HDCP_MANAGEMENT,
+ &config) != 0) {
+ dev_err(hdmidev, "av8100_conf_prep FAIL\n");
+ return -EINVAL;
+ }
+
+ if (av8100_conf_w(AV8100_COMMAND_HDCP_MANAGEMENT,
+ NULL, NULL, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100_conf_w FAIL\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static u8 events_read(void)
+{
+ int ret;
+
+ LOCK_HDMI_EVENTS;
+ ret = events;
+ dev_dbg(hdmidev, "%s %02x\n", __func__, events);
+ UNLOCK_HDMI_EVENTS;
+
+ return ret;
+}
+
+static int events_clear(u8 ev)
+{
+ dev_dbg(hdmidev, "%s %02x\n", __func__, ev);
+
+ LOCK_HDMI_EVENTS;
+ events &= ~ev & EVENTS_MASK;
+ UNLOCK_HDMI_EVENTS;
+
+ return 0;
+}
+
+static int audiocfg(struct audio_cfg *cfg)
+{
+ union av8100_configuration config;
+ struct av8100_status status;
+
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_STANDBY) {
+ if (av8100_powerup() != 0) {
+ dev_err(hdmidev, "av8100_powerup failed\n");
+ return -EINVAL;
+ }
+ }
+
+ if (status.av8100_state < AV8100_OPMODE_INIT) {
+ if (av8100_download_firmware(NULL, 0, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100 dl fw FAIL\n");
+ return -EINVAL;
+ }
+ }
+
+ config.audio_input_format.audio_input_if_format = cfg->if_format;
+ config.audio_input_format.i2s_input_nb = cfg->i2s_entries;
+ config.audio_input_format.sample_audio_freq = cfg->freq;
+ config.audio_input_format.audio_word_lg = cfg->word_length;
+ config.audio_input_format.audio_format = cfg->format;
+ config.audio_input_format.audio_if_mode = cfg->if_mode;
+ config.audio_input_format.audio_mute = cfg->mute;
+
+ if (av8100_conf_prep(AV8100_COMMAND_AUDIO_INPUT_FORMAT,
+ &config) != 0) {
+ dev_err(hdmidev, "av8100_conf_prep FAIL\n");
+ return -EINVAL;
+ }
+
+ if (av8100_conf_w(AV8100_COMMAND_AUDIO_INPUT_FORMAT,
+ NULL, NULL, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100_conf_w FAIL\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* sysfs */
+static ssize_t store_storeastext(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if ((count != HDMI_STOREASTEXT_BIN_SIZE) &&
+ (count != HDMI_STOREASTEXT_TEXT_SIZE) &&
+ (count != HDMI_STOREASTEXT_TEXT_SIZE + 1))
+ return -EINVAL;
+
+ if ((count == HDMI_STOREASTEXT_BIN_SIZE) && (*buf == 0x1))
+ hdmi_driver_data->store_as_hextext = true;
+ else if (((count == HDMI_STOREASTEXT_TEXT_SIZE) ||
+ (count == HDMI_STOREASTEXT_TEXT_SIZE + 1)) && (*buf == '0') &&
+ (*(buf + 1) == '1'))
+ hdmi_driver_data->store_as_hextext = true;
+
+ dev_dbg(hdmidev, "store_as_hextext:%0d\n",
+ hdmi_driver_data->store_as_hextext);
+
+ return count;
+}
+
+static ssize_t store_plugdeten(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ struct plug_detect plug_detect;
+ int index = 0;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdmi_driver_data->store_as_hextext) {
+ if ((count != HDMI_PLUGDETEN_TEXT_SIZE) &&
+ (count != HDMI_PLUGDETEN_TEXT_SIZE + 1))
+ return -EINVAL;
+ plug_detect.hdmi_detect_enable = htoi(buf + index);
+ index += 2;
+ plug_detect.on_time = htoi(buf + index);
+ index += 2;
+ plug_detect.hdmi_off_time = htoi(buf + index);
+ index += 2;
+ } else {
+ if (count != HDMI_PLUGDETEN_BIN_SIZE)
+ return -EINVAL;
+ plug_detect.hdmi_detect_enable = *(buf + index++);
+ plug_detect.on_time = *(buf + index++);
+ plug_detect.hdmi_off_time = *(buf + index++);
+ }
+
+ if (plugdeten(&plug_detect))
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t store_edidread(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ struct edid_read edid_read;
+ int index = 0;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+ dev_dbg(hdmidev, "count:%d\n", count);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdmi_driver_data->store_as_hextext) {
+ if ((count != HDMI_EDIDREAD_TEXT_SIZE) &&
+ (count != HDMI_EDIDREAD_TEXT_SIZE + 1))
+ return -EINVAL;
+ edid_read.address = htoi(buf + index);
+ index += 2;
+ edid_read.block_nr = htoi(buf + index);
+ index += 2;
+ } else {
+ if (count != HDMI_EDIDREAD_BIN_SIZE)
+ return -EINVAL;
+ edid_read.address = *(buf + index++);
+ edid_read.block_nr = *(buf + index++);
+ }
+
+ if (edidread(&edid_read, &hdmi_driver_data->edid_data.buf_len,
+ hdmi_driver_data->edid_data.buf))
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t show_edidread(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ int len;
+ int index = 0;
+ int cnt;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ len = hdmi_driver_data->edid_data.buf_len;
+
+ if (hdmi_driver_data->store_as_hextext) {
+ snprintf(buf + index, 3, "%02x", len);
+ index += 2;
+ } else
+ *(buf + index++) = len;
+
+ dev_dbg(hdmidev, "len:%02x\n", len);
+
+ cnt = 0;
+ while (cnt < len) {
+ if (hdmi_driver_data->store_as_hextext) {
+ snprintf(buf + index, 3, "%02x",
+ hdmi_driver_data->edid_data.buf[cnt]);
+ index += 2;
+ } else
+ *(buf + index++) =
+ hdmi_driver_data->edid_data.buf[cnt];
+
+ dev_dbg(hdmidev, "%02x ",
+ hdmi_driver_data->edid_data.buf[cnt]);
+
+ cnt++;
+ }
+
+ if (hdmi_driver_data->store_as_hextext)
+ index++;
+
+ return index;
+}
+
+static ssize_t store_ceceven(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ bool enable = false;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdmi_driver_data->store_as_hextext) {
+ if ((count != HDMI_CECEVEN_TEXT_SIZE) &&
+ (count != HDMI_CECEVEN_TEXT_SIZE + 1))
+ return -EINVAL;
+ if ((*buf == '0') && (*(buf + 1) == '1'))
+ enable = true;
+ } else {
+ if (count != HDMI_CECEVEN_BIN_SIZE)
+ return -EINVAL;
+ if (*buf == 0x01)
+ enable = true;
+ }
+
+ event_enable(enable, HDMI_EVENT_CEC);
+
+ return count;
+}
+
+static ssize_t show_cecread(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ struct cec_rw cec_read;
+ int index = 0;
+ int cnt;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (cecread(&cec_read.src, &cec_read.dest, &cec_read.length,
+ cec_read.data))
+ return -EINVAL;
+
+ if (hdmi_driver_data->store_as_hextext) {
+ snprintf(buf + index, 3, "%02x", cec_read.src);
+ index += 2;
+ snprintf(buf + index, 3, "%02x", cec_read.dest);
+ index += 2;
+ snprintf(buf + index, 3, "%02x", cec_read.length);
+ index += 2;
+ } else {
+ *(buf + index++) = cec_read.src;
+ *(buf + index++) = cec_read.dest;
+ *(buf + index++) = cec_read.length;
+ }
+
+ dev_dbg(hdmidev, "len:%02x\n", cec_read.length);
+
+ cnt = 0;
+ while (cnt < cec_read.length) {
+ if (hdmi_driver_data->store_as_hextext) {
+ snprintf(buf + index, 3, "%02x", cec_read.data[cnt]);
+ index += 2;
+ } else
+ *(buf + index++) = cec_read.data[cnt];
+
+ dev_dbg(hdmidev, "%02x ", cec_read.data[cnt]);
+
+ cnt++;
+ }
+
+ if (hdmi_driver_data->store_as_hextext)
+ index++;
+
+ return index;
+}
+
+static ssize_t store_cecsend(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ struct cec_rw cec_w;
+ int index = 0;
+ int cnt;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdmi_driver_data->store_as_hextext) {
+ if ((count < HDMI_CECSEND_TEXT_SIZE_MIN) ||
+ (count > HDMI_CECSEND_TEXT_SIZE_MAX))
+ return -EINVAL;
+
+ cec_w.src = htoi(buf + index);
+ index += 2;
+ cec_w.dest = htoi(buf + index);
+ index += 2;
+ cec_w.length = htoi(buf + index);
+ index += 2;
+ if (cec_w.length > HDMI_CEC_WRITE_MAXSIZE)
+ return -EINVAL;
+ cnt = 0;
+ while (cnt < cec_w.length) {
+ cec_w.data[cnt] = htoi(buf + index);
+ index += 2;
+ dev_dbg(hdmidev, "%02x ", cec_w.data[cnt]);
+ cnt++;
+ }
+ } else {
+ if ((count < HDMI_CECSEND_BIN_SIZE_MIN) ||
+ (count > HDMI_CECSEND_BIN_SIZE_MAX))
+ return -EINVAL;
+
+ cec_w.src = *(buf + index++);
+ cec_w.dest = *(buf + index++);
+ cec_w.length = *(buf + index++);
+ if (cec_w.length > HDMI_CEC_WRITE_MAXSIZE)
+ return -EINVAL;
+ memcpy(cec_w.data, buf + index, cec_w.length);
+ }
+
+ if (cecsend(cec_w.src,
+ cec_w.dest,
+ cec_w.length,
+ cec_w.data))
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t store_infofrsend(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ struct info_fr info_fr;
+ int index = 0;
+ int cnt;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdmi_driver_data->store_as_hextext) {
+ if ((count < HDMI_INFOFRSEND_TEXT_SIZE_MIN) ||
+ (count > HDMI_INFOFRSEND_TEXT_SIZE_MAX))
+ return -EINVAL;
+
+ info_fr.type = htoi(&buf[index]);
+ index += 2;
+ info_fr.ver = htoi(&buf[index]);
+ index += 2;
+ info_fr.crc = htoi(&buf[index]);
+ index += 2;
+ info_fr.length = htoi(&buf[index]);
+ index += 2;
+
+ if (info_fr.length > HDMI_INFOFRAME_MAX_SIZE)
+ return -EINVAL;
+ cnt = 0;
+ while (cnt < info_fr.length) {
+ info_fr.data[cnt] = htoi(buf + index);
+ index += 2;
+ dev_dbg(hdmidev, "%02x ", info_fr.data[cnt]);
+ cnt++;
+ }
+ } else {
+ if ((count < HDMI_INFOFRSEND_BIN_SIZE_MIN) ||
+ (count > HDMI_INFOFRSEND_BIN_SIZE_MAX))
+ return -EINVAL;
+
+ info_fr.type = *(buf + index++);
+ info_fr.ver = *(buf + index++);
+ info_fr.crc = *(buf + index++);
+ info_fr.length = *(buf + index++);
+
+ if (info_fr.length > HDMI_INFOFRAME_MAX_SIZE)
+ return -EINVAL;
+ memcpy(info_fr.data, buf + index, info_fr.length);
+ }
+
+ if (infofrsend(info_fr.type, info_fr.ver, info_fr.crc,
+ info_fr.length, info_fr.data))
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t store_hdcpeven(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ bool enable = false;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdmi_driver_data->store_as_hextext) {
+ if ((count != HDMI_HDCPEVEN_TEXT_SIZE) &&
+ (count != HDMI_HDCPEVEN_TEXT_SIZE + 1))
+ return -EINVAL;
+ if ((*buf == '0') && (*(buf + 1) == '1'))
+ enable = true;
+ } else {
+ if (count != HDMI_HDCPEVEN_BIN_SIZE)
+ return -EINVAL;
+ if (*buf == 0x01)
+ enable = true;
+ }
+
+ event_enable(enable, HDMI_EVENT_HDCP);
+
+ return count;
+}
+
+static ssize_t show_hdcpchkaesotp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ u8 crc;
+ u8 status;
+ int index = 0;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdcpchkaesotp(&crc, &status))
+ return -EINVAL;
+
+ if (hdmi_driver_data->store_as_hextext) {
+ snprintf(buf + index, 3, "%02x", status);
+ index += 2;
+ } else {
+ *(buf + index++) = status;
+ }
+
+ dev_dbg(hdmidev, "status:%02x\n", status);
+
+ if (hdmi_driver_data->store_as_hextext)
+ index++;
+
+ return index;
+}
+
+static ssize_t store_hdcpfuseaes(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ struct hdcp_fuseaes hdcp_fuseaes;
+ int index = 0;
+ int cnt;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdmi_driver_data->store_as_hextext) {
+ if ((count != HDMI_HDCP_FUSEAES_TEXT_SIZE) &&
+ (count != HDMI_HDCP_FUSEAES_TEXT_SIZE + 1))
+ return -EINVAL;
+
+ cnt = 0;
+ while (cnt < HDMI_HDCP_FUSEAES_KEYSIZE) {
+ hdcp_fuseaes.key[cnt] = htoi(buf + index);
+ index += 2;
+ dev_dbg(hdmidev, "%02x ", hdcp_fuseaes.key[cnt]);
+ cnt++;
+ }
+ hdcp_fuseaes.crc = htoi(&buf[index]);
+ index += 2;
+ dev_dbg(hdmidev, "%02x ", hdcp_fuseaes.crc);
+ } else {
+ if (count != HDMI_HDCP_FUSEAES_BIN_SIZE)
+ return -EINVAL;
+
+ memcpy(hdcp_fuseaes.key, buf + index,
+ HDMI_HDCP_FUSEAES_KEYSIZE);
+ index += HDMI_HDCP_FUSEAES_KEYSIZE;
+ hdcp_fuseaes.crc = *(buf + index++);
+ }
+
+ if (hdcpfuseaes(hdcp_fuseaes.key, hdcp_fuseaes.crc,
+ &hdcp_fuseaes.result))
+ return -EINVAL;
+
+ dev_dbg(hdmidev, "fuseresult:%02x ", hdcp_fuseaes.result);
+
+ hdmi_driver_data->fuse_result = hdcp_fuseaes.result;
+
+ return count;
+}
+
+static ssize_t show_hdcpfuseaes(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ int index = 0;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdmi_driver_data->store_as_hextext) {
+ snprintf(buf + index, 3, "%02x",
+ hdmi_driver_data->fuse_result);
+ index += 2;
+ } else
+ *(buf + index++) = hdmi_driver_data->fuse_result;
+
+ dev_dbg(hdmidev, "status:%02x\n", hdmi_driver_data->fuse_result);
+
+ if (hdmi_driver_data->store_as_hextext)
+ index++;
+
+ return index;
+}
+
+static ssize_t store_hdcploadaes(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ struct hdcp_loadaesone hdcp_loadaes;
+ int index = 0;
+ int block_cnt;
+ int cnt;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ /* Default not OK */
+ hdmi_driver_data->loadaes_result = 1;
+
+ if (hdmi_driver_data->store_as_hextext) {
+ if ((count != HDMI_HDCP_LOADAES_TEXT_SIZE) &&
+ (count != HDMI_HDCP_LOADAES_TEXT_SIZE + 1))
+ return -EINVAL;
+
+ /* AES */
+ block_cnt = 0;
+ while (block_cnt < HDMI_HDCP_AES_NR_OF_BLOCKS) {
+ cnt = 0;
+ while (cnt < HDMI_HDCP_AES_KEYSIZE) {
+ hdcp_loadaes.key[cnt] = htoi(buf + index);
+ index += 2;
+ dev_dbg(hdmidev, "%02x ",
+ hdcp_loadaes.key[cnt]);
+ cnt++;
+ }
+
+ if (hdcploadaes(block_cnt + HDMI_HDCP_AES_BLOCK_START,
+ HDMI_HDCP_AES_KEYSIZE,
+ hdcp_loadaes.key,
+ &hdcp_loadaes.result))
+ return -EINVAL;
+ if (hdcp_loadaes.result)
+ return -EINVAL;
+
+ block_cnt++;
+ }
+
+ /* KSV */
+ memset(hdcp_loadaes.key, 0, HDMI_HDCP_AES_KSVZEROESSIZE);
+ cnt = HDMI_HDCP_AES_KSVZEROESSIZE;
+ while (cnt < HDMI_HDCP_AES_KSVSIZE +
+ HDMI_HDCP_AES_KSVZEROESSIZE) {
+ hdcp_loadaes.key[cnt] =
+ htoi(&buf[index]);
+ index += 2;
+ dev_dbg(hdmidev, "%02x ", hdcp_loadaes.key[cnt]);
+ cnt++;
+ }
+
+ if (hdcploadaes(HDMI_HDCP_KSV_BLOCK,
+ HDMI_HDCP_AES_KSVSIZE +
+ HDMI_HDCP_AES_KSVZEROESSIZE,
+ hdcp_loadaes.key,
+ &hdcp_loadaes.result))
+ return -EINVAL;
+
+ if (hdcp_loadaes.result)
+ return -EINVAL;
+ } else {
+ if (count != HDMI_HDCP_LOADAES_BIN_SIZE)
+ return -EINVAL;
+
+ /* AES */
+ block_cnt = 0;
+ while (block_cnt < HDMI_HDCP_AES_NR_OF_BLOCKS) {
+ memcpy(hdcp_loadaes.key, buf + index,
+ HDMI_HDCP_AES_KEYSIZE);
+ index += HDMI_HDCP_AES_KEYSIZE;
+
+ if (hdcploadaes(block_cnt + HDMI_HDCP_AES_BLOCK_START,
+ HDMI_HDCP_AES_KEYSIZE,
+ hdcp_loadaes.key,
+ &hdcp_loadaes.result))
+ return -EINVAL;
+
+ if (hdcp_loadaes.result)
+ return -EINVAL;
+ }
+
+ /* KSV */
+ memset(hdcp_loadaes.key, 0, HDMI_HDCP_AES_KSVZEROESSIZE);
+ memcpy(hdcp_loadaes.key + HDMI_HDCP_AES_KSVZEROESSIZE,
+ buf + index,
+ HDMI_HDCP_AES_KSVSIZE);
+ index += HDMI_HDCP_AES_KSVSIZE;
+
+ if (hdcploadaes(HDMI_HDCP_KSV_BLOCK,
+ HDMI_HDCP_AES_KSVSIZE +
+ HDMI_HDCP_AES_KSVZEROESSIZE,
+ hdcp_loadaes.key,
+ &hdcp_loadaes.result))
+ return -EINVAL;
+
+ if (hdcp_loadaes.result)
+ return -EINVAL;
+ }
+
+ hdmi_driver_data->loadaes_result = hdcp_loadaes.result;
+
+ return count;
+}
+
+static ssize_t show_hdcploadaes(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ int index = 0;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdmi_driver_data->store_as_hextext) {
+ snprintf(buf + index, 3, "%02x",
+ hdmi_driver_data->loadaes_result);
+ index += 2;
+ } else
+ *(buf + index++) = hdmi_driver_data->loadaes_result;
+
+ dev_dbg(hdmidev, "status:%02x\n", hdmi_driver_data->loadaes_result);
+
+ if (hdmi_driver_data->store_as_hextext)
+ index++;
+
+ return index;
+}
+
+static ssize_t store_hdcpauthencr(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ struct hdcp_authencr hdcp_authencr;
+ int index = 0;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdmi_driver_data->store_as_hextext) {
+ if ((count != HDMI_HDCPAUTHENCR_TEXT_SIZE) &&
+ (count != HDMI_HDCPAUTHENCR_TEXT_SIZE + 1))
+ return -EINVAL;
+
+ hdcp_authencr.auth_type = htoi(buf + index);
+ index += 2;
+ hdcp_authencr.encr_type = htoi(buf + index);
+ index += 2;
+ } else {
+ if (count != HDMI_HDCPAUTHENCR_BIN_SIZE)
+ return -EINVAL;
+
+ hdcp_authencr.auth_type = *(buf + index++);
+ hdcp_authencr.encr_type = *(buf + index++);
+ }
+
+ if (hdcpauthencr(hdcp_authencr.auth_type, hdcp_authencr.encr_type))
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t show_hdcpstateget(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ u8 hdcp_state;
+ int index = 0;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (av8100_reg_gen_status_r(NULL, NULL, NULL, NULL, &hdcp_state))
+ return -EINVAL;
+
+ if (hdmi_driver_data->store_as_hextext) {
+ snprintf(buf + index, 3, "%02x", hdcp_state);
+ index += 2;
+ } else
+ *(buf + index++) = hdcp_state;
+
+ dev_dbg(hdmidev, "status:%02x\n", hdcp_state);
+
+ if (hdmi_driver_data->store_as_hextext)
+ index++;
+
+ return index;
+}
+
+static ssize_t show_evread(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ int index = 0;
+ u8 ev;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ ev = events_read();
+
+ if (hdmi_driver_data->store_as_hextext) {
+ snprintf(buf + index, 3, "%02x", ev);
+ index += 2;
+ } else
+ *(buf + index++) = ev;
+
+ if (hdmi_driver_data->store_as_hextext)
+ index++;
+
+ /* Events are read: clear events */
+ events_clear(EVENTS_MASK);
+
+ return index;
+}
+
+static ssize_t store_evclr(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ u8 ev;
+ int index = 0;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdmi_driver_data->store_as_hextext) {
+ if ((count != HDMI_EVCLR_TEXT_SIZE) &&
+ (count != HDMI_EVCLR_TEXT_SIZE + 1))
+ return -EINVAL;
+
+ ev = htoi(&buf[index]);
+ index += 2;
+ } else {
+ if (count != HDMI_EVCLR_BIN_SIZE)
+ return -EINVAL;
+
+ ev = *(buf + index++);
+ }
+
+ events_clear(ev);
+
+ return count;
+}
+
+static ssize_t store_audiocfg(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ struct audio_cfg audio_cfg;
+ int index = 0;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ if (hdmi_driver_data->store_as_hextext) {
+ if ((count != HDMI_AUDIOCFG_TEXT_SIZE) &&
+ (count != HDMI_AUDIOCFG_TEXT_SIZE + 1))
+ return -EINVAL;
+
+ audio_cfg.if_format = htoi(&buf[index]);
+ index += 2;
+ audio_cfg.i2s_entries = htoi(&buf[index]);
+ index += 2;
+ audio_cfg.freq = htoi(&buf[index]);
+ index += 2;
+ audio_cfg.word_length = htoi(&buf[index]);
+ index += 2;
+ audio_cfg.format = htoi(&buf[index]);
+ index += 2;
+ audio_cfg.if_mode = htoi(&buf[index]);
+ index += 2;
+ audio_cfg.mute = htoi(&buf[index]);
+ index += 2;
+ } else {
+ if (count != HDMI_AUDIOCFG_BIN_SIZE)
+ return -EINVAL;
+
+ audio_cfg.if_format = *(buf + index++);
+ audio_cfg.i2s_entries = *(buf + index++);
+ audio_cfg.freq = *(buf + index++);
+ audio_cfg.word_length = *(buf + index++);
+ audio_cfg.format = *(buf + index++);
+ audio_cfg.if_mode = *(buf + index++);
+ audio_cfg.mute = *(buf + index++);
+ }
+
+ audiocfg(&audio_cfg);
+
+ return count;
+}
+
+static ssize_t show_plugstatus(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+ int index = 0;
+ struct av8100_status av8100_status;
+ u8 plstat;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ hdmi_driver_data = dev_get_drvdata(dev);
+
+ av8100_status = av8100_status_get();
+ plstat = av8100_status.av8100_plugin_status == AV8100_HDMI_PLUGIN;
+
+ if (hdmi_driver_data->store_as_hextext) {
+ snprintf(buf + index, 3, "%02x", plstat);
+ index += 2;
+ } else
+ *(buf + index++) = plstat;
+
+ if (hdmi_driver_data->store_as_hextext)
+ index++;
+
+ return index;
+}
+
+static int hdmi_open(struct inode *inode, struct file *filp)
+{
+ if (device_open)
+ return -EBUSY;
+
+ device_open++;
+
+ return 0;
+}
+
+static int hdmi_release(struct inode *inode, struct file *filp)
+{
+ if (device_open)
+ device_open--;
+
+ return 0;
+}
+
+/* ioctl */
+static int hdmi_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ u8 value = 0;
+ struct plug_detect plug_detect;
+ struct edid_read edid_read;
+ struct cec_rw cec_read;
+ struct cec_rw cec_send;
+ struct info_fr info_fr;
+ struct hdcp_fuseaes hdcp_fuseaes;
+ struct hdcp_loadaesall hdcp_loadaesall;
+ int block_cnt;
+ struct hdcp_loadaesone hdcp_loadaesone;
+ struct hdcp_authencr hdcp_authencr;
+ struct audio_cfg audio_cfg;
+ union av8100_configuration config;
+ struct hdmi_register reg;
+ struct hdmi_command_register command_reg;
+ struct av8100_status status;
+ u8 aes_status;
+
+ switch (cmd) {
+
+ case IOC_PLUG_DETECT_ENABLE:
+ if (copy_from_user(&plug_detect, (void *)arg,
+ sizeof(struct plug_detect)))
+ return -EINVAL;
+
+ if (plugdeten(&plug_detect))
+ return -EINVAL;
+ break;
+
+ case IOC_EDID_READ:
+ if (copy_from_user(&edid_read, (void *)arg,
+ sizeof(struct edid_read)))
+ return -EINVAL;
+
+ if (edidread(&edid_read, &edid_read.data_length,
+ edid_read.data))
+ return -EINVAL;
+
+ if (copy_to_user((void *)arg, (void *)&edid_read,
+ sizeof(struct edid_read))) {
+ return -EINVAL;
+ }
+ break;
+
+ case IOC_CEC_EVENT_ENABLE:
+ if (copy_from_user(&value, (void *)arg, sizeof(u8)))
+ return -EINVAL;
+
+ event_enable(value != 0, HDMI_EVENT_CEC);
+ break;
+
+ case IOC_CEC_READ:
+ if (cecread(&cec_read.src, &cec_read.dest, &cec_read.length,
+ cec_read.data))
+ return -EINVAL;
+
+ if (copy_to_user((void *)arg, (void *)&cec_read,
+ sizeof(struct cec_rw))) {
+ return -EINVAL;
+ }
+ break;
+
+ case IOC_CEC_SEND:
+ if (copy_from_user(&cec_send, (void *)arg,
+ sizeof(struct cec_rw)))
+ return -EINVAL;
+
+ if (cecsend(cec_send.src,
+ cec_send.dest,
+ cec_send.length,
+ cec_send.data))
+ return -EINVAL;
+ break;
+
+ case IOC_INFOFRAME_SEND:
+ if (copy_from_user(&info_fr, (void *)arg,
+ sizeof(struct info_fr)))
+ return -EINVAL;
+
+ if (infofrsend(info_fr.type, info_fr.ver, info_fr.crc,
+ info_fr.length, info_fr.data))
+ return -EINVAL;
+ break;
+
+ case IOC_HDCP_EVENT_ENABLE:
+ if (copy_from_user(&value, (void *)arg, sizeof(u8)))
+ return -EINVAL;
+
+ event_enable(value != 0, HDMI_EVENT_HDCP);
+ break;
+
+ case IOC_HDCP_CHKAESOTP:
+ if (hdcpchkaesotp(&value, &aes_status))
+ return -EINVAL;
+
+ if (copy_to_user((void *)arg, (void *)&aes_status,
+ sizeof(u8))) {
+ return -EINVAL;
+ }
+ break;
+
+ case IOC_HDCP_FUSEAES:
+ if (copy_from_user(&hdcp_fuseaes, (void *)arg,
+ sizeof(struct hdcp_fuseaes)))
+ return -EINVAL;
+
+ if (hdcpfuseaes(hdcp_fuseaes.key, hdcp_fuseaes.crc,
+ &hdcp_fuseaes.result))
+ return -EINVAL;
+
+ if (copy_to_user((void *)arg, (void *)&hdcp_fuseaes,
+ sizeof(struct hdcp_fuseaes))) {
+ return -EINVAL;
+ }
+ break;
+
+ case IOC_HDCP_LOADAES:
+ if (copy_from_user(&hdcp_loadaesall, (void *)arg,
+ sizeof(struct hdcp_loadaesall)))
+ return -EINVAL;
+
+ /* AES */
+ block_cnt = 0;
+ while (block_cnt < HDMI_HDCP_AES_NR_OF_BLOCKS) {
+ memcpy(hdcp_loadaesone.key, hdcp_loadaesall.key +
+ block_cnt * HDMI_HDCP_AES_KEYSIZE,
+ HDMI_HDCP_AES_KEYSIZE);
+
+ if (hdcploadaes(block_cnt + HDMI_HDCP_AES_BLOCK_START,
+ HDMI_HDCP_AES_KEYSIZE,
+ hdcp_loadaesone.key,
+ &hdcp_loadaesone.result))
+ return -EINVAL;
+
+ if (hdcp_loadaesone.result)
+ return -EINVAL;
+ }
+
+ /* KSV */
+ memset(hdcp_loadaesone.key, 0, HDMI_HDCP_AES_KSVZEROESSIZE);
+ memcpy(hdcp_loadaesone.key + HDMI_HDCP_AES_KSVZEROESSIZE,
+ hdcp_loadaesall.ksv, HDMI_HDCP_AES_KSVSIZE);
+
+ if (hdcploadaes(HDMI_HDCP_KSV_BLOCK,
+ HDMI_HDCP_AES_KSVSIZE +
+ HDMI_HDCP_AES_KSVZEROESSIZE,
+ hdcp_loadaesone.key,
+ &hdcp_loadaesone.result))
+ return -EINVAL;
+
+ if (hdcp_loadaesone.result)
+ return -EINVAL;
+
+ hdcp_loadaesall.result = hdcp_loadaesone.result;
+
+ if (copy_to_user((void *)arg, (void *)&hdcp_loadaesall,
+ sizeof(struct hdcp_loadaesall))) {
+ return -EINVAL;
+ }
+ break;
+
+ case IOC_HDCP_AUTHENCR_REQ:
+ if (copy_from_user(&hdcp_authencr, (void *)arg,
+ sizeof(struct hdcp_authencr)))
+ return -EINVAL;
+
+ if (hdcpauthencr(hdcp_authencr.auth_type,
+ hdcp_authencr.encr_type))
+ return -EINVAL;
+ break;
+
+ case IOC_HDCP_STATE_GET:
+ if (av8100_reg_gen_status_r(NULL, NULL, NULL, NULL,
+ &value))
+ return -EINVAL;
+
+ if (copy_to_user((void *)arg, (void *)&value,
+ sizeof(u8))) {
+ return -EINVAL;
+ }
+ break;
+
+ case IOC_EVENTS_READ:
+ value = events_read();
+
+ if (copy_to_user((void *)arg, (void *)&value,
+ sizeof(u8))) {
+ return -EINVAL;
+ }
+
+ /* Events are read: clear events */
+ events_clear(EVENTS_MASK);
+ break;
+
+ case IOC_EVENTS_CLEAR:
+ if (copy_from_user(&value, (void *)arg, sizeof(u8)))
+ return -EINVAL;
+
+ events_clear(value);
+ break;
+
+ case IOC_AUDIO_CFG:
+ if (copy_from_user(&audio_cfg, (void *)arg,
+ sizeof(struct audio_cfg)))
+ return -EINVAL;
+
+ audiocfg(&audio_cfg);
+ break;
+
+ case IOC_PLUG_STATUS:
+ status = av8100_status_get();
+ value = status.av8100_plugin_status == AV8100_HDMI_PLUGIN;
+
+ if (copy_to_user((void *)arg, (void *)&value,
+ sizeof(u8))) {
+ return -EINVAL;
+ }
+ break;
+
+ /* Internal */
+ case IOC_HDMI_POWER:
+ /* Get desired power state on or off */
+ if (copy_from_user(&value, (void *)arg, sizeof(u8)))
+ return -EINVAL;
+
+ if (value == 0) {
+ if (av8100_powerdown() != 0) {
+ dev_err(hdmidev, "av8100_powerdown FAIL\n");
+ return -EINVAL;
+ }
+ } else {
+ if (av8100_powerup() != 0) {
+ dev_err(hdmidev, "av8100_powerup FAIL\n");
+ return -EINVAL;
+ }
+ }
+ break;
+
+ case IOC_HDMI_ENABLE_INTERRUPTS:
+ av8100_disable_interrupt();
+ if (av8100_enable_interrupt() != 0) {
+ dev_err(hdmidev, "av8100_conf_get FAIL\n");
+ return -EINVAL;
+ }
+ break;
+
+ case IOC_HDMI_DOWNLOAD_FW:
+ if (av8100_download_firmware(NULL, 0, I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100 dl fw FAIL\n");
+ return -EINVAL;
+ }
+ break;
+
+ case IOC_HDMI_ONOFF:
+ /* Get desired HDMI mode on or off */
+ if (copy_from_user(&value, (void *)arg, sizeof(u8)))
+ return -EFAULT;
+
+ if (av8100_conf_get(AV8100_COMMAND_HDMI, &config) != 0) {
+ dev_err(hdmidev, "av8100_conf_get FAIL\n");
+ return -EINVAL;
+ }
+ if (value == 0)
+ config.hdmi_format.hdmi_mode = AV8100_HDMI_OFF;
+ else
+ config.hdmi_format.hdmi_mode = AV8100_HDMI_ON;
+
+ if (av8100_conf_prep(AV8100_COMMAND_HDMI, &config) != 0) {
+ dev_err(hdmidev, "av8100_conf_prep FAIL\n");
+ return -EINVAL;
+ }
+ if (av8100_conf_w(AV8100_COMMAND_HDMI, NULL, NULL,
+ I2C_INTERFACE) != 0) {
+ dev_err(hdmidev, "av8100_conf_w FAIL\n");
+ return -EINVAL;
+ }
+ break;
+
+ case IOC_HDMI_REGISTER_WRITE:
+ if (copy_from_user(&reg, (void *)arg,
+ sizeof(struct hdmi_register))) {
+ return -EINVAL;
+ }
+
+ if (av8100_reg_w(reg.offset, reg.value) != 0) {
+ dev_err(hdmidev, "hdmi_register_write FAIL\n");
+ return -EINVAL;
+ }
+ break;
+
+ case IOC_HDMI_REGISTER_READ:
+ if (copy_from_user(&reg, (void *)arg,
+ sizeof(struct hdmi_register))) {
+ return -EINVAL;
+ }
+
+ if (av8100_reg_r(reg.offset, &reg.value) != 0) {
+ dev_err(hdmidev, "hdmi_register_write FAIL\n");
+ return -EINVAL;
+ }
+
+ if (copy_to_user((void *)arg, (void *)&reg,
+ sizeof(struct hdmi_register))) {
+ return -EINVAL;
+ }
+ break;
+
+ case IOC_HDMI_STATUS_GET:
+ status = av8100_status_get();
+
+ if (copy_to_user((void *)arg, (void *)&status,
+ sizeof(struct av8100_status))) {
+ return -EINVAL;
+ }
+ break;
+
+ case IOC_HDMI_CONFIGURATION_WRITE:
+ if (copy_from_user(&command_reg, (void *)arg,
+ sizeof(struct hdmi_command_register)) != 0) {
+ dev_err(hdmidev, "IOC_HDMI_CONFIGURATION_WRITE "
+ "fail 1\n");
+ command_reg.return_status = EINVAL;
+ } else {
+ if (av8100_conf_w_raw(command_reg.cmd_id,
+ command_reg.buf_len,
+ command_reg.buf,
+ &(command_reg.buf_len),
+ command_reg.buf) != 0) {
+ dev_err(hdmidev, "IOC_HDMI_CONFIGURATION_WRITE "
+ "fail 2\n");
+ command_reg.return_status = EINVAL;
+ }
+ }
+
+ if (copy_to_user((void *)arg, (void *)&command_reg,
+ sizeof(struct hdmi_command_register)) != 0) {
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static unsigned int
+hdmi_poll(struct file *filp, poll_table *wait)
+{
+ unsigned int mask = 0;
+
+ dev_dbg(hdmidev, "%s\n", __func__);
+
+ poll_wait(filp, &hdmi_event_wq , wait);
+
+ LOCK_HDMI_EVENTS;
+ if (events_received == true) {
+ events_received = false;
+ mask = POLLIN | POLLRDNORM;
+ }
+ UNLOCK_HDMI_EVENTS;
+
+ return mask;
+}
+
+static const struct file_operations hdmi_fops = {
+ .owner = THIS_MODULE,
+ .open = hdmi_open,
+ .release = hdmi_release,
+ .ioctl = hdmi_ioctl,
+ .poll = hdmi_poll
+};
+
+static struct miscdevice hdmi_miscdev = {
+ MISC_DYNAMIC_MINOR,
+ "hdmi",
+ &hdmi_fops
+};
+
+/* Event callback function called by hw driver */
+void hdmi_event(enum av8100_hdmi_event ev)
+{
+ int events_old;
+ int events_new;
+ struct kobject *kobj = &hdmidev->kobj;
+
+ dev_dbg(hdmidev, "hdmi_event %02x\n", ev);
+
+ LOCK_HDMI_EVENTS;
+
+ events_old = events;
+
+ /* Set event */
+ switch (ev) {
+ case AV8100_HDMI_EVENT_HDMI_PLUGIN:
+ events |= events_mask & HDMI_EVENT_HDMI_PLUGIN;
+ break;
+
+ case AV8100_HDMI_EVENT_HDMI_PLUGOUT:
+ events |= events_mask & HDMI_EVENT_HDMI_PLUGOUT;
+ break;
+
+ case AV8100_HDMI_EVENT_CEC:
+ events |= events_mask & HDMI_EVENT_CEC;
+ break;
+
+ case AV8100_HDMI_EVENT_HDCP:
+ events |= events_mask & HDMI_EVENT_HDCP;
+ break;
+
+ default:
+ break;
+ }
+
+ events_new = events;
+
+ UNLOCK_HDMI_EVENTS;
+
+ dev_dbg(hdmidev, "hdmi events:%02x, events_old:%02x mask:%02x\n",
+ events_new, events_old, events_mask);
+
+ if (events_new != events_old) {
+ /* Wake up application waiting for event via call to poll() */
+ sysfs_notify(kobj, NULL, SYSFS_EVENT_FILENAME);
+
+ LOCK_HDMI_EVENTS;
+ events_received = true;
+ UNLOCK_HDMI_EVENTS;
+
+ wake_up_interruptible(&hdmi_event_wq);
+ }
+}
+
+int __init hdmi_init(void)
+{
+ int ret;
+ struct hdmi_driver_data *hdmi_driver_data;
+
+ ret = misc_register(&hdmi_miscdev);
+ if (ret)
+ goto hdmi_init_out;
+
+ hdmidev = hdmi_miscdev.this_device;
+
+ hdmi_driver_data =
+ kzalloc(sizeof(struct hdmi_driver_data), GFP_KERNEL);
+
+ if (!hdmi_driver_data)
+ return -ENOMEM;
+
+ dev_set_drvdata(hdmidev, hdmi_driver_data);
+
+ /* Default sysfs file format is hextext */
+ hdmi_driver_data->store_as_hextext = true;
+
+ init_waitqueue_head(&hdmi_event_wq);
+
+ if (device_create_file(hdmidev, &dev_attr_storeastext))
+ dev_info(hdmidev, "Unable to create storeastext attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_plugdeten))
+ dev_info(hdmidev, "Unable to create plugdeten attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_edidread))
+ dev_info(hdmidev, "Unable to create edidread attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_ceceven))
+ dev_info(hdmidev, "Unable to create ceceven attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_cecread))
+ dev_info(hdmidev, "Unable to create cecread attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_cecsend))
+ dev_info(hdmidev, "Unable to create cecsend attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_infofrsend))
+ dev_info(hdmidev, "Unable to create infofrsend attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_hdcpeven))
+ dev_info(hdmidev, "Unable to create hdcpeven attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_hdcpchkaesotp))
+ dev_info(hdmidev, "Unable to create hdcpchkaesotp attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_hdcpfuseaes))
+ dev_info(hdmidev, "Unable to create hdcpfuseaes attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_hdcploadaes))
+ dev_info(hdmidev, "Unable to create hdcploadaes attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_hdcpauthencr))
+ dev_info(hdmidev, "Unable to create hdcpauthreq attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_hdcpstateget))
+ dev_info(hdmidev, "Unable to create hdcpstateget attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_evread))
+ dev_info(hdmidev, "Unable to create evread attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_evclr))
+ dev_info(hdmidev, "Unable to create evclr attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_audiocfg))
+ dev_info(hdmidev, "Unable to create audiocfg attribute\n");
+ if (device_create_file(hdmidev, &dev_attr_plugstatus))
+ dev_info(hdmidev, "Unable to create plugstatus attribute\n");
+
+ /* Register event callback */
+ av8100_hdmi_event_cb_set(hdmi_event);
+
+hdmi_init_out:
+ return ret;
+}
+
+void hdmi_exit(void)
+{
+ struct hdmi_driver_data *hdmi_driver_data;
+
+ /* Deregister event callback */
+ av8100_hdmi_event_cb_set(NULL);
+
+ device_remove_file(hdmidev, &dev_attr_storeastext);
+ device_remove_file(hdmidev, &dev_attr_plugdeten);
+ device_remove_file(hdmidev, &dev_attr_edidread);
+ device_remove_file(hdmidev, &dev_attr_ceceven);
+ device_remove_file(hdmidev, &dev_attr_cecread);
+ device_remove_file(hdmidev, &dev_attr_cecsend);
+ device_remove_file(hdmidev, &dev_attr_infofrsend);
+ device_remove_file(hdmidev, &dev_attr_hdcpeven);
+ device_remove_file(hdmidev, &dev_attr_hdcpchkaesotp);
+ device_remove_file(hdmidev, &dev_attr_hdcpfuseaes);
+ device_remove_file(hdmidev, &dev_attr_hdcploadaes);
+ device_remove_file(hdmidev, &dev_attr_hdcpauthencr);
+ device_remove_file(hdmidev, &dev_attr_hdcpstateget);
+ device_remove_file(hdmidev, &dev_attr_evread);
+ device_remove_file(hdmidev, &dev_attr_evclr);
+ device_remove_file(hdmidev, &dev_attr_audiocfg);
+ device_remove_file(hdmidev, &dev_attr_plugstatus);
+
+ hdmi_driver_data = dev_get_drvdata(hdmidev);
+ kfree(hdmi_driver_data);
+
+ misc_deregister(&hdmi_miscdev);
+}
diff --git a/drivers/video/av8100/hdmi_loc.h b/drivers/video/av8100/hdmi_loc.h
new file mode 100644
index 00000000000..8cd83f874bd
--- /dev/null
+++ b/drivers/video/av8100/hdmi_loc.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Author: Per Persson <per.xb.persson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __HDMI_LOC__H__
+#define __HDMI_LOC__H__
+
+#define EDID_BUF_LEN 128
+#define COMMAND_BUF_LEN 128
+
+struct edid_data {
+ u8 buf_len;
+ u8 buf[EDID_BUF_LEN];
+};
+
+struct hdmi_register {
+ unsigned char value;
+ unsigned char offset;
+};
+
+struct hdcp_loadaesone {
+ u8 key[16];
+ u8 result;
+};
+
+struct hdmi_driver_data {
+ bool store_as_hextext;
+ struct plug_detect plug_detect;
+ bool enable_cec_event;
+ struct edid_data edid_data;
+ struct cec_rw cec_read;
+ bool fuse_result;
+ bool loadaes_result;
+};
+
+struct hdmi_command_register {
+ unsigned char cmd_id; /* input */
+ unsigned char buf_len; /* input, output */
+ unsigned char buf[COMMAND_BUF_LEN]; /* input, output */
+ unsigned char return_status; /* output */
+};
+
+/* Internal */
+#define IOC_HDMI_POWER _IOWR(HDMI_IOC_MAGIC, 31, int)
+#define IOC_HDMI_ENABLE_INTERRUPTS _IOWR(HDMI_IOC_MAGIC, 32, int)
+#define IOC_HDMI_DOWNLOAD_FW _IOWR(HDMI_IOC_MAGIC, 33, int)
+#define IOC_HDMI_ONOFF _IOWR(HDMI_IOC_MAGIC, 34, int)
+#define IOC_HDMI_REGISTER_WRITE _IOWR(HDMI_IOC_MAGIC, 35, int)
+#define IOC_HDMI_REGISTER_READ _IOWR(HDMI_IOC_MAGIC, 36, int)
+#define IOC_HDMI_STATUS_GET _IOWR(HDMI_IOC_MAGIC, 37, int)
+#define IOC_HDMI_CONFIGURATION_WRITE _IOWR(HDMI_IOC_MAGIC, 38, int)
+
+#endif /* __HDMI_LOC__H__ */
diff --git a/drivers/video/b2r2/Kconfig b/drivers/video/b2r2/Kconfig
new file mode 100644
index 00000000000..4c9ebda87c3
--- /dev/null
+++ b/drivers/video/b2r2/Kconfig
@@ -0,0 +1,6 @@
+config FB_B2R2
+ tristate "B2R2 engine support"
+ default y
+ help
+ B2R2 engine does various bit-blitting operations,post-processor operations
+ and various compositions.
diff --git a/drivers/video/b2r2/Makefile b/drivers/video/b2r2/Makefile
new file mode 100644
index 00000000000..4ebbccf6bbb
--- /dev/null
+++ b/drivers/video/b2r2/Makefile
@@ -0,0 +1,25 @@
+# Make file for compiling and loadable module B2R2
+
+# TODO: This should be moved to Kconfig
+CONFIG_B2R2_DEBUG := y
+
+# Fix for hardware bug requiring rectangles to be a multiple of 16 high
+EXTRA_CFLAGS += -DB2R2_ROTATION_HEIGHT_BUGFIX
+
+# Enable fallback to generic
+EXTRA_CFLAGS += -DB2R2_GEN_OPT_MIX
+
+obj-$(CONFIG_FB_B2R2) += b2r2.o
+
+b2r2-objs = b2r2_blt_main.o b2r2_core.o b2r2_mem_alloc.o b2r2_generic.o b2r2_node_gen.o b2r2_node_split.o b2r2_profiler_socket.o b2r2_timing.o b2r2_filters.o b2r2_utils.o b2r2_input_validation.o
+
+ifdef CONFIG_B2R2_DEBUG
+EXTRA_CFLAGS += -DCONFIG_B2R2_DEBUG -DDEBUG
+b2r2-objs += b2r2_debug.o
+endif
+
+ifeq ($(CONFIG_FB_B2R2),m)
+obj-y += b2r2_kernel_if.o
+endif
+
+clean-files := b2r2.o b2r2_blt_main.o b2r2_core.o b2r2_mem_alloc.o b2r2_generic.o b2r2_node_gen.o b2r2_node_split.o b2r2_profiler_socket.o b2r2_timing.o b2r2_debug.o modules.order built-in.o
diff --git a/drivers/video/b2r2/b2r2_blt_main.c b/drivers/video/b2r2/b2r2_blt_main.c
new file mode 100644
index 00000000000..b2aeb6678cb
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_blt_main.c
@@ -0,0 +1,3326 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 Blitter module
+ *
+ * Author: Robert Fekete <robert.fekete@stericsson.com>
+ * Author: Paul Wannback
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#ifdef CONFIG_ANDROID_PMEM
+#include <linux/android_pmem.h>
+#endif
+#include <linux/fb.h>
+#include <linux/uaccess.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#endif
+#include <asm/cacheflush.h>
+#include <linux/smp.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/hwmem.h>
+
+#include "b2r2_internal.h"
+#include "b2r2_node_split.h"
+#include "b2r2_generic.h"
+#include "b2r2_mem_alloc.h"
+#include "b2r2_profiler_socket.h"
+#include "b2r2_timing.h"
+#include "b2r2_debug.h"
+#include "b2r2_utils.h"
+#include "b2r2_input_validation.h"
+
+#define B2R2_HEAP_SIZE (4 * PAGE_SIZE)
+static u32 b2r2_heap_size = 31 * PAGE_SIZE;
+
+/*
+ * TODO:
+ * Implementation of query cap
+ * Support for user space virtual pointer to physically consecutive memory
+ * Support for user space virtual pointer to physically scattered memory
+ * Callback reads lagging behind in blt_api_stress app
+ * Store smaller items in the report list instead of the whole request
+ * Support read of many report records at once.
+ */
+
+/**
+ * b2r2_blt_dev - Our device, /dev/b2r2_blt
+ */
+static struct miscdevice *b2r2_blt_dev;
+
+/* Statistics */
+
+/**
+ * stat_lock - Spin lock protecting the statistics
+ */
+static spinlock_t stat_lock;
+/**
+ * stat_n_jobs_added - Number of jobs added to b2r2_core
+ */
+static unsigned long stat_n_jobs_added;
+/**
+ * stat_n_jobs_released - Number of jobs released (job_release called)
+ */
+static unsigned long stat_n_jobs_released;
+/**
+ * stat_n_jobs_in_report_list - Number of jobs currently in the report list
+ */
+static unsigned long stat_n_jobs_in_report_list;
+/**
+ * stat_n_in_blt - Number of client threads currently exec inside b2r2_blt()
+ */
+static unsigned long stat_n_in_blt;
+/**
+ * stat_n_in_blt_synch - Nunmber of client threads currently waiting for synch
+ */
+static unsigned long stat_n_in_blt_synch;
+/**
+ * stat_n_in_blt_add - Number of client threads currenlty adding in b2r2_blt
+ */
+static unsigned long stat_n_in_blt_add;
+/**
+ * stat_n_in_blt_wait - Number of client threads currently waiting in b2r2_blt
+ */
+static unsigned long stat_n_in_blt_wait;
+/**
+ * stat_n_in_sync_0 - Number of client threads currently in b2r2_blt_sync
+ * waiting for all client jobs to finish
+ */
+static unsigned long stat_n_in_synch_0;
+/**
+ * stat_n_in_sync_job - Number of client threads currently in b2r2_blt_sync
+ * waiting specific job to finish
+ */
+static unsigned long stat_n_in_synch_job;
+/**
+ * stat_n_in_query_cap - Number of clients currently in query cap
+ */
+static unsigned long stat_n_in_query_cap;
+/**
+ * stat_n_in_open - Number of clients currently in b2r2_blt_open
+ */
+static unsigned long stat_n_in_open;
+/**
+ * stat_n_in_release - Number of clients currently in b2r2_blt_release
+ */
+static unsigned long stat_n_in_release;
+
+/* Debug file system support */
+#ifdef CONFIG_DEBUG_FS
+/**
+ * debugfs_latest_request - Copy of the latest request issued
+ */
+struct b2r2_blt_request debugfs_latest_request;
+/**
+ * debugfs_latest_first_node - Copy of the first B2R2 node of
+ * latest request issued
+ */
+struct b2r2_node debugfs_latest_first_node;
+/**
+ * debugfs_root_dir - The debugfs root directory, i.e. /debugfs/b2r2
+ */
+static struct dentry *debugfs_root_dir;
+
+static int sprintf_req(struct b2r2_blt_request *request, char *buf, int size);
+#endif
+
+/* Local functions */
+static void inc_stat(unsigned long *stat);
+static void dec_stat(unsigned long *stat);
+static int b2r2_blt(struct b2r2_blt_instance *instance,
+ struct b2r2_blt_request *request);
+static int b2r2_generic_blt(struct b2r2_blt_instance *instance,
+ struct b2r2_blt_request *request);
+static int b2r2_blt_synch(struct b2r2_blt_instance *instance,
+ int request_id);
+static int b2r2_blt_query_cap(struct b2r2_blt_instance *instance,
+ struct b2r2_blt_query_cap *query_cap);
+
+static void job_callback(struct b2r2_core_job *job);
+static void job_release(struct b2r2_core_job *job);
+static int job_acquire_resources(struct b2r2_core_job *job, bool atomic);
+static void job_release_resources(struct b2r2_core_job *job, bool atomic);
+
+static void job_callback_gen(struct b2r2_core_job *job);
+static void job_release_gen(struct b2r2_core_job *job);
+static int job_acquire_resources_gen(struct b2r2_core_job *job, bool atomic);
+static void job_release_resources_gen(struct b2r2_core_job *job, bool atomic);
+static void tile_job_callback_gen(struct b2r2_core_job *job);
+static void tile_job_release_gen(struct b2r2_core_job *job);
+static int resolve_buf(struct b2r2_blt_img *img,
+ struct b2r2_blt_rect *rect_2b_used,
+ bool is_dst,
+ struct b2r2_resolved_buf *resolved);
+static void unresolve_buf(struct b2r2_blt_buf *buf,
+ struct b2r2_resolved_buf *resolved);
+static void sync_buf(struct b2r2_blt_img *img,
+ struct b2r2_resolved_buf *resolved,
+ bool is_dst,
+ struct b2r2_blt_rect *rect);
+static bool is_report_list_empty(struct b2r2_blt_instance *instance);
+static bool is_synching(struct b2r2_blt_instance *instance);
+static void get_actual_dst_rect(struct b2r2_blt_req *req,
+ struct b2r2_blt_rect *actual_dst_rect);
+static void set_up_hwmem_region(struct b2r2_blt_img *img,
+ struct b2r2_blt_rect *rect, struct hwmem_region *region);
+static int resolve_hwmem(struct b2r2_blt_img *img,
+ struct b2r2_blt_rect *rect_2b_used, bool is_dst,
+ struct b2r2_resolved_buf *resolved_buf);
+static void unresolve_hwmem(struct b2r2_resolved_buf *resolved_buf);
+
+/**
+ * struct sync_args - Data for clean/flush
+ *
+ * @start: Virtual start address
+ * @end: Virtual end address
+ */
+struct sync_args {
+ unsigned long start;
+ unsigned long end;
+};
+/**
+ * flush_l1_cache_range_curr_cpu() - Cleans and invalidates L1 cache on the current CPU
+ *
+ * @arg: Pointer to sync_args structure
+ */
+static inline void flush_l1_cache_range_curr_cpu(void *arg)
+{
+ struct sync_args *sa = (struct sync_args *)arg;
+
+ dmac_flush_range((void *)sa->start, (void *)sa->end);
+}
+
+#ifdef CONFIG_SMP
+/**
+ * inv_l1_cache_range_all_cpus() - Cleans and invalidates L1 cache on all CPU:s
+ *
+ * @sa: Pointer to sync_args structure
+ */
+static void flush_l1_cache_range_all_cpus(struct sync_args *sa)
+{
+ on_each_cpu(flush_l1_cache_range_curr_cpu, sa, 1);
+}
+#endif
+
+/**
+ * clean_l1_cache_range_curr_cpu() - Cleans L1 cache on current CPU
+ *
+ * Ensures that data is written out from the CPU:s L1 cache,
+ * it will still be in the cache.
+ *
+ * @arg: Pointer to sync_args structure
+ */
+static inline void clean_l1_cache_range_curr_cpu(void *arg)
+{
+ struct sync_args *sa = (struct sync_args *)arg;
+
+ dmac_map_area((void *)sa->start,
+ (void *)sa->end - (void *)sa->start,
+ DMA_TO_DEVICE);
+}
+
+#ifdef CONFIG_SMP
+/**
+ * clean_l1_cache_range_all_cpus() - Cleans L1 cache on all CPU:s
+ *
+ * Ensures that data is written out from all CPU:s L1 cache,
+ * it will still be in the cache.
+ *
+ * @sa: Pointer to sync_args structure
+ */
+static void clean_l1_cache_range_all_cpus(struct sync_args *sa)
+{
+ on_each_cpu(clean_l1_cache_range_curr_cpu, sa, 1);
+}
+#endif
+
+/**
+ * b2r2_blt_open - Implements file open on the b2r2_blt device
+ *
+ * @inode: File system inode
+ * @filp: File pointer
+ *
+ * A B2R2 BLT instance is created and stored in the file structure.
+ */
+static int b2r2_blt_open(struct inode *inode, struct file *filp)
+{
+ int ret = 0;
+ struct b2r2_blt_instance *instance;
+
+ b2r2_log_info("%s\n", __func__);
+
+ inc_stat(&stat_n_in_open);
+
+ /* Allocate and initialize the instance */
+ instance = (struct b2r2_blt_instance *)
+ kmalloc(sizeof(*instance), GFP_KERNEL);
+ if (!instance) {
+ b2r2_log_err("%s: Failed to alloc\n", __func__);
+ goto instance_alloc_failed;
+ }
+ memset(instance, 0, sizeof(*instance));
+ INIT_LIST_HEAD(&instance->report_list);
+ spin_lock_init(&instance->lock);
+ init_waitqueue_head(&instance->report_list_waitq);
+ init_waitqueue_head(&instance->synch_done_waitq);
+
+ /*
+ * Remember the instance so that we can retrieve it in
+ * other functions
+ */
+ filp->private_data = instance;
+ goto out;
+
+instance_alloc_failed:
+out:
+ dec_stat(&stat_n_in_open);
+
+ return ret;
+}
+
+/**
+ * b2r2_blt_release - Implements last close on an instance of
+ * the b2r2_blt device
+ *
+ * @inode: File system inode
+ * @filp: File pointer
+ *
+ * All active jobs are finished or cancelled and allocated data
+ * is released.
+ */
+static int b2r2_blt_release(struct inode *inode, struct file *filp)
+{
+ int ret;
+ struct b2r2_blt_instance *instance;
+
+ b2r2_log_info("%s\n", __func__);
+
+ inc_stat(&stat_n_in_release);
+
+ instance = (struct b2r2_blt_instance *) filp->private_data;
+
+ /* Finish all outstanding requests */
+ ret = b2r2_blt_synch(instance, 0);
+ if (ret < 0)
+ b2r2_log_warn(
+ "%s: b2r2_blt_sync failed with %d\n", __func__, ret);
+
+ /* Now cancel any remaining outstanding request */
+ if (instance->no_of_active_requests) {
+ struct b2r2_core_job *job;
+
+ b2r2_log_warn("%s: %d active requests\n",
+ __func__, instance->no_of_active_requests);
+
+ /* Find and cancel all jobs belonging to us */
+ job = b2r2_core_job_find_first_with_tag((int) instance);
+ while (job) {
+ b2r2_core_job_cancel(job);
+ /* This release matches addref in b2r2_core_job_find... */
+ b2r2_core_job_release(job, __func__);
+ job = b2r2_core_job_find_first_with_tag((int) instance);
+ }
+
+ b2r2_log_warn(
+ "%s: %d active requests after cancel\n",
+ __func__, instance->no_of_active_requests);
+ }
+
+ /* Release jobs in report list */
+ spin_lock(&instance->lock);
+ while (!list_empty(&instance->report_list)) {
+ struct b2r2_blt_request *request = list_first_entry(
+ &instance->report_list,
+ struct b2r2_blt_request,
+ list);
+ list_del_init(&request->list);
+ spin_unlock(&instance->lock);
+ /*
+ * This release matches the addref when the job was put into
+ * the report list
+ */
+ b2r2_core_job_release(&request->job, __func__);
+ spin_lock(&instance->lock);
+ }
+ spin_unlock(&instance->lock);
+
+ /* Release our instance */
+ kfree(instance);
+
+ dec_stat(&stat_n_in_release);
+
+ return 0;
+}
+
+/**
+ * b2r2_blt_ioctl - This routine implements b2r2_blt ioctl interface
+ *
+ * @inode: inode pointer.
+ * @file: file pointer.
+ * @cmd :ioctl command.
+ * @arg: input argument for ioctl.
+ *
+ * Returns 0 if OK else negative error code
+ */
+static int b2r2_blt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ struct b2r2_blt_instance *instance;
+
+ /** Process actual ioctl */
+
+ b2r2_log_info("%s\n", __func__);
+
+ /* Get the instance from the file structure */
+ instance = (struct b2r2_blt_instance *) file->private_data;
+
+ switch (cmd) {
+ case B2R2_BLT_IOC: {
+ /* This is the "blit" command */
+
+ /* arg is user pointer to struct b2r2_blt_request */
+ struct b2r2_blt_request *request =
+ kmalloc(sizeof(*request), GFP_KERNEL);
+ if (!request) {
+ b2r2_log_err("%s: Failed to alloc mem\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ /* Initialize the structure */
+ memset(request, 0, sizeof(*request));
+ INIT_LIST_HEAD(&request->list);
+ request->instance = instance;
+
+ /*
+ * The user request is a sub structure of the
+ * kernel request structure.
+ */
+
+ /* Get the user data */
+ if (copy_from_user(&request->user_req, (void *)arg,
+ sizeof(request->user_req))) {
+ b2r2_log_err(
+ "%s: copy_from_user failed\n",
+ __func__);
+ kfree(request);
+ return -EFAULT;
+ }
+
+ if (!b2r2_validate_user_req(&request->user_req)) {
+ kfree(request);
+ return -EINVAL;
+ }
+
+ request->profile = is_profiler_registered_approx();
+
+ /*
+ * If the user specified a color look-up table,
+ * make a copy that the HW can use.
+ */
+ if ((request->user_req.flags &
+ B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) != 0) {
+ request->clut = dma_alloc_coherent(b2r2_blt_device(),
+ CLUT_SIZE, &(request->clut_phys_addr),
+ GFP_DMA | GFP_KERNEL);
+ if (request->clut == NULL) {
+ b2r2_log_err("%s CLUT allocation failed.\n",
+ __func__);
+ kfree(request);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(request->clut,
+ request->user_req.clut, CLUT_SIZE)) {
+ b2r2_log_err("%s: CLUT copy_from_user failed\n",
+ __func__);
+ dma_free_coherent(b2r2_blt_device(), CLUT_SIZE,
+ request->clut, request->clut_phys_addr);
+ request->clut = NULL;
+ request->clut_phys_addr = 0;
+ kfree(request);
+ return -EFAULT;
+ }
+ }
+
+ /* Perform the blit */
+#ifdef B2R2_GENERIC_BLT
+ ret = b2r2_generic_blt(instance, request);
+#elif defined(B2R2_OPT_BLT)
+ ret = b2r2_blt(instance, request);
+#elif defined(B2R2_GEN_OPT_MIX)
+ ret = b2r2_blt(instance, request);
+ if (ret == -ENOSYS) {
+ struct b2r2_blt_request *request_gen;
+ b2r2_log_info("b2r2_blt=%d Going generic.\n", ret);
+ request_gen = kmalloc(sizeof(*request_gen), GFP_KERNEL);
+ if (!request_gen) {
+ b2r2_log_err(
+ "%s: Failed to alloc mem for request_gen\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* Initialize the structure */
+ memset(request_gen, 0, sizeof(*request_gen));
+ INIT_LIST_HEAD(&request_gen->list);
+ request_gen->instance = instance;
+
+ /*
+ * The user request is a sub structure of the
+ * kernel request structure.
+ */
+
+ /* Get the user data */
+ if (copy_from_user(&request_gen->user_req, (void *)arg,
+ sizeof(request_gen->user_req))) {
+ b2r2_log_err(
+ "%s: copy_from_user failed\n",
+ __func__);
+ kfree(request_gen);
+ return -EFAULT;
+ }
+
+ /*
+ * If the user specified a color look-up table,
+ * make a copy that the HW can use.
+ */
+ if ((request_gen->user_req.flags &
+ B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) != 0) {
+ request_gen->clut = dma_alloc_coherent(b2r2_blt_device(),
+ CLUT_SIZE, &(request_gen->clut_phys_addr),
+ GFP_DMA | GFP_KERNEL);
+ if (request_gen->clut == NULL) {
+ b2r2_log_err("%s CLUT allocation failed.\n", __func__);
+ kfree(request_gen);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(request_gen->clut, request_gen->user_req.clut, CLUT_SIZE)) {
+ b2r2_log_err("%s: CLUT copy_from_user failed\n", __func__);
+ dma_free_coherent(b2r2_blt_device(), CLUT_SIZE, request_gen->clut,
+ request_gen->clut_phys_addr);
+ request_gen->clut = NULL;
+ request_gen->clut_phys_addr = 0;
+ kfree(request_gen);
+ return -EFAULT;
+ }
+ }
+
+ request_gen->profile = is_profiler_registered_approx();
+
+ ret = b2r2_generic_blt(instance, request_gen);
+ b2r2_log_info("\nb2r2_generic_blt=%d Generic done.\n", ret);
+ }
+#endif
+ break;
+ }
+
+ case B2R2_BLT_SYNCH_IOC:
+ /* This is the "synch" command */
+
+ /* arg is request_id */
+ ret = b2r2_blt_synch(instance, (int) arg);
+ break;
+
+ case B2R2_BLT_QUERY_CAP_IOC:
+ {
+ /* This is the "query capabilities" command */
+
+ /* Arg is struct b2r2_blt_query_cap */
+ struct b2r2_blt_query_cap query_cap;
+
+ /* Get the user data */
+ if (copy_from_user(&query_cap, (void *)arg,
+ sizeof(query_cap))) {
+ b2r2_log_err(
+ "%s: copy_from_user failed\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ /* Fill in our capabilities */
+ ret = b2r2_blt_query_cap(instance, &query_cap);
+
+ /* Return data to user */
+ if (copy_to_user((void *)arg, &query_cap,
+ sizeof(query_cap))) {
+ b2r2_log_err("%s: copy_to_user failed\n",
+ __func__);
+ return -EFAULT;
+ }
+ break;
+ }
+
+ default:
+ /* Unknown command */
+ b2r2_log_err(
+ "%s: Unknown cmd %d\n", __func__, cmd);
+ ret = -EINVAL;
+ break;
+
+ }
+
+ if (ret < 0)
+ b2r2_log_err("EC %d OK!\n", -ret);
+
+ return ret;
+}
+
+/**
+ * b2r2_blt_poll - Support for user-space poll, select & epoll.
+ * Used for user-space callback
+ *
+ * @filp: File to poll on
+ * @wait: Poll table to wait on
+ *
+ * This function checks if there are anything to read
+ */
+static unsigned b2r2_blt_poll(struct file *filp, poll_table *wait)
+{
+ struct b2r2_blt_instance *instance;
+ unsigned int mask = 0;
+
+ b2r2_log_info("%s\n", __func__);
+
+ /* Get the instance from the file structure */
+ instance = (struct b2r2_blt_instance *) filp->private_data;
+
+ poll_wait(filp, &instance->report_list_waitq, wait);
+ spin_lock(&instance->lock);
+ if (!list_empty(&instance->report_list))
+ mask |= POLLIN | POLLRDNORM;
+ spin_unlock(&instance->lock);
+
+ return mask;
+}
+
+/**
+ * b2r2_blt_read - Read report data, user for user-space callback
+ *
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to read
+ * @f_pos: File position
+ *
+ * Returns number of bytes read or negative error code
+ */
+static ssize_t b2r2_blt_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ int ret = 0;
+ struct b2r2_blt_instance *instance;
+ struct b2r2_blt_request *request;
+ struct b2r2_blt_report report;
+
+ b2r2_log_info("%s\n", __func__);
+
+ /* Get the instance from the file structure */
+ instance = (struct b2r2_blt_instance *) filp->private_data;
+
+ /*
+ * We return only complete report records, one at a time.
+ * Might be more efficient to support read of many.
+ */
+ count = (count / sizeof(struct b2r2_blt_report)) *
+ sizeof(struct b2r2_blt_report);
+ if (count > sizeof(struct b2r2_blt_report))
+ count = sizeof(struct b2r2_blt_report);
+ if (count == 0)
+ return count;
+
+ /*
+ * Loop and wait here until we have anything to return or
+ * until interrupted
+ */
+ spin_lock(&instance->lock);
+ while (list_empty(&instance->report_list)) {
+ spin_unlock(&instance->lock);
+
+ /* Return if non blocking read */
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ b2r2_log_info("%s - Going to sleep\n", __func__);
+ if (wait_event_interruptible(
+ instance->report_list_waitq,
+ !is_report_list_empty(instance)))
+ /* signal: tell the fs layer to handle it */
+ return -ERESTARTSYS;
+
+ /* Otherwise loop, but first reaquire the lock */
+ spin_lock(&instance->lock);
+ }
+
+ /* Ok, we have something to return */
+
+ /* Return */
+ request = NULL;
+ if (!list_empty(&instance->report_list))
+ request = list_first_entry(
+ &instance->report_list, struct b2r2_blt_request, list);
+
+ if (request) {
+ /* Remove from list to avoid reading twice */
+ list_del_init(&request->list);
+
+ report.request_id = request->request_id;
+ report.report1 = request->user_req.report1;
+ report.report2 = request->user_req.report2;
+ report.usec_elapsed = 0; /* TBD */
+
+ spin_unlock(&instance->lock);
+ if (copy_to_user(buf,
+ &report,
+ sizeof(report)))
+ ret = -EFAULT;
+ spin_lock(&instance->lock);
+
+ if (ret) {
+ /* copy to user failed, re-insert into list */
+ list_add(&request->list,
+ &request->instance->report_list);
+ request = NULL;
+ }
+ }
+ spin_unlock(&instance->lock);
+
+ if (request)
+ /*
+ * Release matching the addref when the job was put into
+ * the report list
+ */
+ b2r2_core_job_release(&request->job, __func__);
+
+ return count;
+}
+
+/**
+ * b2r2_blt_fops - File operations for b2r2_blt
+ */
+static const struct file_operations b2r2_blt_fops = {
+ .owner = THIS_MODULE,
+ .open = b2r2_blt_open,
+ .release = b2r2_blt_release,
+ .ioctl = b2r2_blt_ioctl,
+ .poll = b2r2_blt_poll,
+ .read = b2r2_blt_read,
+};
+
+/**
+ * b2r2_blt_misc_dev - Misc device config for b2r2_blt
+ */
+static struct miscdevice b2r2_blt_misc_dev = {
+ MISC_DYNAMIC_MINOR,
+ "b2r2_blt",
+ &b2r2_blt_fops
+};
+
+/**
+ * b2r2_blt - Implementation of the B2R2 blit request
+ *
+ * @instance: The B2R2 BLT instance
+ * @request; The request to perform
+ */
+static int b2r2_blt(struct b2r2_blt_instance *instance,
+ struct b2r2_blt_request *request)
+{
+ int ret = 0;
+ struct b2r2_blt_rect actual_dst_rect;
+ int request_id = 0;
+ struct b2r2_node *last_node = request->first_node;
+ int node_count;
+
+ u32 thread_runtime_at_start = 0;
+
+ if (request->profile) {
+ request->start_time_nsec = b2r2_get_curr_nsec();
+ thread_runtime_at_start = (u32)task_sched_runtime(current);
+ }
+
+ b2r2_log_info("%s\n", __func__);
+
+ inc_stat(&stat_n_in_blt);
+
+ /* Debug prints of incoming request */
+ b2r2_log_info(
+ "src.fmt=%#010x src.buf={%d,%d,%d} "
+ "src.w,h={%d,%d} src.rect={%d,%d,%d,%d}\n",
+ request->user_req.src_img.fmt,
+ request->user_req.src_img.buf.type,
+ request->user_req.src_img.buf.fd,
+ request->user_req.src_img.buf.offset,
+ request->user_req.src_img.width,
+ request->user_req.src_img.height,
+ request->user_req.src_rect.x,
+ request->user_req.src_rect.y,
+ request->user_req.src_rect.width,
+ request->user_req.src_rect.height);
+ b2r2_log_info(
+ "dst.fmt=%#010x dst.buf={%d,%d,%d} "
+ "dst.w,h={%d,%d} dst.rect={%d,%d,%d,%d}\n",
+ request->user_req.dst_img.fmt,
+ request->user_req.dst_img.buf.type,
+ request->user_req.dst_img.buf.fd,
+ request->user_req.dst_img.buf.offset,
+ request->user_req.dst_img.width,
+ request->user_req.dst_img.height,
+ request->user_req.dst_rect.x,
+ request->user_req.dst_rect.y,
+ request->user_req.dst_rect.width,
+ request->user_req.dst_rect.height);
+
+ inc_stat(&stat_n_in_blt_synch);
+
+ /* Wait here if synch is ongoing */
+ ret = wait_event_interruptible(instance->synch_done_waitq,
+ !is_synching(instance));
+ if (ret) {
+ b2r2_log_warn(
+ "%s: Sync wait interrupted, %d\n",
+ __func__, ret);
+ ret = -EAGAIN;
+ dec_stat(&stat_n_in_blt_synch);
+ goto synch_interrupted;
+ }
+
+ dec_stat(&stat_n_in_blt_synch);
+
+ /* Resolve the buffers */
+
+ /* Source buffer */
+ ret = resolve_buf(&request->user_req.src_img,
+ &request->user_req.src_rect, false, &request->src_resolved);
+ if (ret < 0) {
+ b2r2_log_warn(
+ "%s: Resolve src buf failed, %d\n",
+ __func__, ret);
+ ret = -EAGAIN;
+ goto resolve_src_buf_failed;
+ }
+
+ /* Source mask buffer */
+ ret = resolve_buf(&request->user_req.src_mask,
+ &request->user_req.src_rect, false,
+ &request->src_mask_resolved);
+ if (ret < 0) {
+ b2r2_log_warn(
+ "%s: Resolve src mask buf failed, %d\n",
+ __func__, ret);
+ ret = -EAGAIN;
+ goto resolve_src_mask_buf_failed;
+ }
+
+ /* Destination buffer */
+ get_actual_dst_rect(&request->user_req, &actual_dst_rect);
+ ret = resolve_buf(&request->user_req.dst_img, &actual_dst_rect,
+ true, &request->dst_resolved);
+ if (ret < 0) {
+ b2r2_log_warn(
+ "%s: Resolve dst buf failed, %d\n",
+ __func__, ret);
+ ret = -EAGAIN;
+ goto resolve_dst_buf_failed;
+ }
+
+ /* Debug prints of resolved buffers */
+ b2r2_log_info("src.rbuf={%X,%p,%d} {%p,%X,%X,%d}\n",
+ request->src_resolved.physical_address,
+ request->src_resolved.virtual_address,
+ request->src_resolved.is_pmem,
+ request->src_resolved.filep,
+ request->src_resolved.file_physical_start,
+ request->src_resolved.file_virtual_start,
+ request->src_resolved.file_len);
+
+ b2r2_log_info("dst.rbuf={%X,%p,%d} {%p,%X,%X,%d}\n",
+ request->dst_resolved.physical_address,
+ request->dst_resolved.virtual_address,
+ request->dst_resolved.is_pmem,
+ request->dst_resolved.filep,
+ request->dst_resolved.file_physical_start,
+ request->dst_resolved.file_virtual_start,
+ request->dst_resolved.file_len);
+
+ /* Calculate the number of nodes (and resources) needed for this job */
+ ret = b2r2_node_split_analyze(request, b2r2_heap_size,
+ &node_count, &request->bufs, &request->buf_count,
+ &request->node_split_job);
+ if (ret == -ENOSYS) {
+ /* There was no optimized path for this request */
+ b2r2_log_info(
+ "%s: No optimized path for request\n", __func__);
+ goto no_optimized_path;
+
+ } else if (ret < 0) {
+ b2r2_log_warn(
+ "%s: Failed to analyze request, ret = %d\n",
+ __func__, ret);
+#ifdef CONFIG_DEBUG_FS
+ {
+ /* Failed, dump job to dmesg */
+ char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+
+ b2r2_log_info(
+ "%s: Analyze failed for:\n", __func__);
+ if (Buf != NULL) {
+ sprintf_req(request, Buf, sizeof(char) * 4096);
+ b2r2_log_info("%s", Buf);
+ kfree(Buf);
+ } else {
+ b2r2_log_info("Unable to print the request. "
+ "Message buffer allocation failed.\n");
+ }
+ }
+#endif
+ goto generate_nodes_failed;
+ }
+
+ /* Allocate the nodes needed */
+#ifdef B2R2_USE_NODE_GEN
+ request->first_node = b2r2_blt_alloc_nodes(node_count);
+ if (request->first_node == NULL) {
+ b2r2_log_warn(
+ "%s: Failed to allocate nodes, ret = %d\n",
+ __func__, ret);
+ goto generate_nodes_failed;
+ }
+#else
+ ret = b2r2_node_alloc(node_count, &(request->first_node));
+ if (ret < 0 || request->first_node == NULL) {
+ b2r2_log_warn(
+ "%s: Failed to allocate nodes, ret = %d\n",
+ __func__, ret);
+ goto generate_nodes_failed;
+ }
+#endif
+
+ /* Build the B2R2 node list */
+ ret = b2r2_node_split_configure(&request->node_split_job,
+ request->first_node);
+
+ if (ret < 0) {
+ b2r2_log_warn(
+ "%s: Failed to perform node split, ret = %d\n",
+ __func__, ret);
+ goto generate_nodes_failed;
+ }
+
+ /* Exit here if dry run */
+ if (request->user_req.flags & B2R2_BLT_FLAG_DRY_RUN)
+ goto exit_dry_run;
+
+ /* Configure the request */
+ last_node = request->first_node;
+ while (last_node && last_node->next)
+ last_node = last_node->next;
+
+ request->job.tag = (int) instance;
+ request->job.prio = request->user_req.prio;
+ request->job.first_node_address =
+ request->first_node->physical_address;
+ request->job.last_node_address =
+ last_node->physical_address;
+ request->job.callback = job_callback;
+ request->job.release = job_release;
+ request->job.acquire_resources = job_acquire_resources;
+ request->job.release_resources = job_release_resources;
+
+ /* Synchronize memory occupied by the buffers */
+
+ /* Source buffer */
+ if (!(request->user_req.flags &
+ B2R2_BLT_FLAG_SRC_NO_CACHE_FLUSH) &&
+ (request->user_req.src_img.buf.type !=
+ B2R2_BLT_PTR_PHYSICAL) &&
+ !b2r2_is_mb_fmt(request->user_req.src_img.fmt))
+ /* MB formats are never touched by SW */
+ sync_buf(&request->user_req.src_img,
+ &request->src_resolved,
+ false, /*is_dst*/
+ &request->user_req.src_rect);
+
+ /* Source mask buffer */
+ if (!(request->user_req.flags &
+ B2R2_BLT_FLAG_SRC_MASK_NO_CACHE_FLUSH) &&
+ (request->user_req.src_mask.buf.type !=
+ B2R2_BLT_PTR_PHYSICAL) &&
+ !b2r2_is_mb_fmt(request->user_req.src_mask.fmt))
+ /* MB formats are never touched by SW */
+ sync_buf(&request->user_req.src_mask,
+ &request->src_mask_resolved,
+ false, /*is_dst*/
+ NULL);
+
+ /* Destination buffer */
+ if (!(request->user_req.flags &
+ B2R2_BLT_FLAG_DST_NO_CACHE_FLUSH) &&
+ (request->user_req.dst_img.buf.type !=
+ B2R2_BLT_PTR_PHYSICAL) &&
+ !b2r2_is_mb_fmt(request->user_req.dst_img.fmt))
+ /* MB formats are never touched by SW */
+ sync_buf(&request->user_req.dst_img,
+ &request->dst_resolved,
+ true, /*is_dst*/
+ &request->user_req.dst_rect);
+
+#ifdef CONFIG_DEBUG_FS
+ /* Remember latest request and first node for debugfs */
+ debugfs_latest_request = *request;
+ debugfs_latest_first_node = *request->first_node;
+#endif
+
+ /* Submit the job */
+ b2r2_log_info("%s: Submitting job\n", __func__);
+
+ inc_stat(&stat_n_in_blt_add);
+
+ if (request->profile)
+ request->nsec_active_in_cpu =
+ (s32)((u32)task_sched_runtime(current) -
+ thread_runtime_at_start);
+
+ spin_lock(&instance->lock);
+
+ /* Add the job to b2r2_core */
+ request_id = b2r2_core_job_add(&request->job);
+ request->request_id = request_id;
+
+ dec_stat(&stat_n_in_blt_add);
+
+ if (request_id < 0) {
+ b2r2_log_warn("%s: Failed to add job, ret = %d\n",
+ __func__, request_id);
+ ret = request_id;
+ spin_unlock(&instance->lock);
+ goto job_add_failed;
+ }
+
+ inc_stat(&stat_n_jobs_added);
+
+ instance->no_of_active_requests++;
+ spin_unlock(&instance->lock);
+
+ /* Wait for the job to be done if synchronous */
+ if ((request->user_req.flags & B2R2_BLT_FLAG_ASYNCH) == 0) {
+ b2r2_log_info("%s: Synchronous, waiting\n",
+ __func__);
+
+ inc_stat(&stat_n_in_blt_wait);
+
+ ret = b2r2_core_job_wait(&request->job);
+
+ dec_stat(&stat_n_in_blt_wait);
+
+ if (ret < 0 && ret != -ENOENT)
+ b2r2_log_warn(
+ "%s: Failed to wait job, ret = %d\n",
+ __func__, ret);
+ else
+ b2r2_log_info(
+ "%s: Synchronous wait done\n", __func__);
+ ret = 0;
+ }
+
+ /*
+ * Release matching the addref in b2r2_core_job_add,
+ * the request must not be accessed after this call
+ */
+ b2r2_core_job_release(&request->job, __func__);
+
+ dec_stat(&stat_n_in_blt);
+
+ return ret >= 0 ? request_id : ret;
+
+job_add_failed:
+exit_dry_run:
+no_optimized_path:
+generate_nodes_failed:
+ unresolve_buf(&request->user_req.dst_img.buf,
+ &request->dst_resolved);
+resolve_dst_buf_failed:
+ unresolve_buf(&request->user_req.src_mask.buf,
+ &request->src_mask_resolved);
+resolve_src_mask_buf_failed:
+ unresolve_buf(&request->user_req.src_img.buf,
+ &request->src_resolved);
+resolve_src_buf_failed:
+synch_interrupted:
+ job_release(&request->job);
+ dec_stat(&stat_n_jobs_released);
+ if ((request->user_req.flags & B2R2_BLT_FLAG_DRY_RUN) == 0 || ret)
+ b2r2_log_warn(
+ "%s returns with error %d\n", __func__, ret);
+
+ dec_stat(&stat_n_in_blt);
+
+ return ret;
+}
+
+/**
+ * Called when job for one tile is done or cancelled
+ * in the generic path.
+ *
+ * @job: The job
+ */
+static void tile_job_callback_gen(struct b2r2_core_job *job)
+{
+ if (b2r2_blt_device())
+ b2r2_log_info("%s\n", __func__);
+
+ /* Local addref / release within this func */
+ b2r2_core_job_addref(job, __func__);
+
+#ifdef CONFIG_DEBUG_FS
+ /* Notify if a tile job is cancelled */
+ if (job->job_state == B2R2_CORE_JOB_CANCELED) {
+ b2r2_log_info("%s: Tile job cancelled:\n", __func__);
+ }
+#endif
+
+ /* Local addref / release within this func */
+ b2r2_core_job_release(job, __func__);
+}
+
+/**
+ * Called when job is done or cancelled.
+ * Used for the last tile in the generic path
+ * to notify waiting clients.
+ *
+ * @job: The job
+ */
+static void job_callback_gen(struct b2r2_core_job *job)
+{
+ struct b2r2_blt_request *request =
+ container_of(job, struct b2r2_blt_request, job);
+
+ if (b2r2_blt_device())
+ b2r2_log_info("%s\n", __func__);
+
+ /* Local addref / release within this func */
+ b2r2_core_job_addref(job, __func__);
+
+ /* Move to report list if the job shall be reported */
+ /* FIXME: Use a smaller struct? */
+ spin_lock(&request->instance->lock);
+
+ if (request->user_req.flags & B2R2_BLT_FLAG_REPORT_WHEN_DONE) {
+ /* Move job to report list */
+ list_add_tail(&request->list,
+ &request->instance->report_list);
+ inc_stat(&stat_n_jobs_in_report_list);
+
+ /* Wake up poll */
+ wake_up_interruptible(
+ &request->instance->report_list_waitq);
+
+ /*
+ * Add a reference because we put the
+ * job in the report list
+ */
+ b2r2_core_job_addref(job, __func__);
+ }
+
+ /*
+ * Decrease number of active requests and wake up
+ * synching threads if active requests reaches zero
+ */
+ BUG_ON(request->instance->no_of_active_requests == 0);
+ request->instance->no_of_active_requests--;
+ if (request->instance->synching &&
+ request->instance->no_of_active_requests == 0) {
+ request->instance->synching = false;
+ /* Wake up all syncing */
+
+ wake_up_interruptible_all(
+ &request->instance->synch_done_waitq);
+ }
+ spin_unlock(&request->instance->lock);
+
+#ifdef CONFIG_DEBUG_FS
+ /* Dump job if cancelled */
+ if (job->job_state == B2R2_CORE_JOB_CANCELED) {
+ char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+
+ b2r2_log_info("%s: Job cancelled:\n", __func__);
+ if (Buf != NULL) {
+ sprintf_req(request, Buf, sizeof(char) * 4096);
+ b2r2_log_info("%s", Buf);
+ kfree(Buf);
+ } else {
+ b2r2_log_info("Unable to print the request. "
+ "Message buffer allocation failed.\n");
+ }
+ }
+#endif
+
+ /* Local addref / release within this func */
+ b2r2_core_job_release(job, __func__);
+}
+
+/**
+ * Called when tile job should be released (free memory etc.)
+ * Should be used only for tile jobs. Tile jobs should only be used
+ * by b2r2_core, thus making ref_count trigger their release.
+ *
+ * @job: The job
+ */
+
+static void tile_job_release_gen(struct b2r2_core_job *job)
+{
+ inc_stat(&stat_n_jobs_released);
+
+ b2r2_log_info("%s, first_node_address=0x%.8x, ref_count=%d\n",
+ __func__, job->first_node_address, job->ref_count);
+
+ /* Release memory for the job */
+ kfree(job);
+}
+
+/**
+ * Called when job should be released (free memory etc.)
+ *
+ * @job: The job
+ */
+
+static void job_release_gen(struct b2r2_core_job *job)
+{
+ struct b2r2_blt_request *request =
+ container_of(job, struct b2r2_blt_request, job);
+
+ inc_stat(&stat_n_jobs_released);
+
+ b2r2_log_info("%s, first_node=%p, ref_count=%d\n",
+ __func__, request->first_node, request->job.ref_count);
+
+ /* Free nodes */
+#ifdef B2R2_USE_NODE_GEN
+ if (request->first_node)
+ b2r2_blt_free_nodes(request->first_node);
+#else
+ if (request->first_node)
+ b2r2_node_free(request->first_node);
+#endif
+
+ /* Release memory for the request */
+ if (request->clut != NULL) {
+ dma_free_coherent(b2r2_blt_device(), CLUT_SIZE, request->clut,
+ request->clut_phys_addr);
+ request->clut = NULL;
+ request->clut_phys_addr = 0;
+ }
+ kfree(request);
+}
+
+static int job_acquire_resources_gen(struct b2r2_core_job *job, bool atomic)
+{
+ /* Nothing so far. Temporary buffers are pre-allocated */
+ return 0;
+}
+static void job_release_resources_gen(struct b2r2_core_job *job, bool atomic)
+{
+ /* Nothing so far. Temporary buffers are pre-allocated */
+}
+
+/**
+ * b2r2_generic_blt - Generic implementation of the B2R2 blit request
+ *
+ * @instance: The B2R2 BLT instance
+ * @request; The request to perform
+ */
+static int b2r2_generic_blt(struct b2r2_blt_instance *instance,
+ struct b2r2_blt_request *request)
+{
+ int ret = 0;
+ struct b2r2_blt_rect actual_dst_rect;
+ int request_id = 0;
+ struct b2r2_node *last_node = request->first_node;
+ int node_count;
+ s32 tmp_buf_width = 0;
+ s32 tmp_buf_height = 0;
+ u32 tmp_buf_count = 0;
+ s32 x;
+ s32 y;
+ const struct b2r2_blt_rect *dst_rect = &(request->user_req.dst_rect);
+ const s32 dst_img_width = request->user_req.dst_img.width;
+ const s32 dst_img_height = request->user_req.dst_img.height;
+ const enum b2r2_blt_flag flags = request->user_req.flags;
+ /* Descriptors for the temporary buffers */
+ struct b2r2_work_buf work_bufs[4];
+ struct b2r2_blt_rect dst_rect_tile;
+ int i;
+
+ u32 thread_runtime_at_start = 0;
+ s32 nsec_active_in_b2r2 = 0;
+
+ /*
+ * Early exit if zero blt.
+ * dst_rect outside of dst_img or
+ * dst_clip_rect outside of dst_img.
+ */
+ if (dst_rect->x + dst_rect->width <= 0 ||
+ dst_rect->y + dst_rect->height <= 0 ||
+ dst_img_width <= dst_rect->x ||
+ dst_img_height <= dst_rect->y ||
+ ((flags & B2R2_BLT_FLAG_DESTINATION_CLIP) != 0 &&
+ (dst_img_width <= request->user_req.dst_clip_rect.x ||
+ dst_img_height <= request->user_req.dst_clip_rect.y ||
+ request->user_req.dst_clip_rect.x +
+ request->user_req.dst_clip_rect.width <= 0 ||
+ request->user_req.dst_clip_rect.y +
+ request->user_req.dst_clip_rect.height <= 0))) {
+ goto zero_blt;
+ }
+
+ if (request->profile) {
+ request->start_time_nsec = b2r2_get_curr_nsec();
+ thread_runtime_at_start = (u32)task_sched_runtime(current);
+ }
+
+ memset(work_bufs, 0, sizeof(work_bufs));
+
+ b2r2_log_info("%s\n", __func__);
+
+ inc_stat(&stat_n_in_blt);
+
+ /* Debug prints of incoming request */
+ b2r2_log_info(
+ "src.fmt=%#010x flags=0x%.8x src.buf={%d,%d,0x%.8x}\n"
+ "src.w,h={%d,%d} src.rect={%d,%d,%d,%d}\n",
+ request->user_req.src_img.fmt,
+ request->user_req.flags,
+ request->user_req.src_img.buf.type,
+ request->user_req.src_img.buf.fd,
+ request->user_req.src_img.buf.offset,
+ request->user_req.src_img.width,
+ request->user_req.src_img.height,
+ request->user_req.src_rect.x,
+ request->user_req.src_rect.y,
+ request->user_req.src_rect.width,
+ request->user_req.src_rect.height);
+ b2r2_log_info(
+ "dst.fmt=%#010x dst.buf={%d,%d,0x%.8x}\n"
+ "dst.w,h={%d,%d} dst.rect={%d,%d,%d,%d}\n"
+ "dst_clip_rect={%d,%d,%d,%d}\n",
+ request->user_req.dst_img.fmt,
+ request->user_req.dst_img.buf.type,
+ request->user_req.dst_img.buf.fd,
+ request->user_req.dst_img.buf.offset,
+ request->user_req.dst_img.width,
+ request->user_req.dst_img.height,
+ request->user_req.dst_rect.x,
+ request->user_req.dst_rect.y,
+ request->user_req.dst_rect.width,
+ request->user_req.dst_rect.height,
+ request->user_req.dst_clip_rect.x,
+ request->user_req.dst_clip_rect.y,
+ request->user_req.dst_clip_rect.width,
+ request->user_req.dst_clip_rect.height);
+
+ inc_stat(&stat_n_in_blt_synch);
+
+ /* Wait here if synch is ongoing */
+ ret = wait_event_interruptible(instance->synch_done_waitq,
+ !is_synching(instance));
+ if (ret) {
+ b2r2_log_warn(
+ "%s: Sync wait interrupted, %d\n",
+ __func__, ret);
+ ret = -EAGAIN;
+ dec_stat(&stat_n_in_blt_synch);
+ goto synch_interrupted;
+ }
+
+ dec_stat(&stat_n_in_blt_synch);
+
+ /* Resolve the buffers */
+
+ /* Source buffer */
+ ret = resolve_buf(&request->user_req.src_img,
+ &request->user_req.src_rect, false, &request->src_resolved);
+ if (ret < 0) {
+ b2r2_log_warn(
+ "%s: Resolve src buf failed, %d\n",
+ __func__, ret);
+ ret = -EAGAIN;
+ goto resolve_src_buf_failed;
+ }
+
+ /* Source mask buffer */
+ ret = resolve_buf(&request->user_req.src_mask,
+ &request->user_req.src_rect, false,
+ &request->src_mask_resolved);
+ if (ret < 0) {
+ b2r2_log_warn(
+ "%s: Resolve src mask buf failed, %d\n",
+ __func__, ret);
+ ret = -EAGAIN;
+ goto resolve_src_mask_buf_failed;
+ }
+
+ /* Destination buffer */
+ get_actual_dst_rect(&request->user_req, &actual_dst_rect);
+ ret = resolve_buf(&request->user_req.dst_img, &actual_dst_rect,
+ true, &request->dst_resolved);
+ if (ret < 0) {
+ b2r2_log_warn(
+ "%s: Resolve dst buf failed, %d\n",
+ __func__, ret);
+ ret = -EAGAIN;
+ goto resolve_dst_buf_failed;
+ }
+
+ /* Debug prints of resolved buffers */
+ b2r2_log_info("src.rbuf={%X,%p,%d} {%p,%X,%X,%d}\n",
+ request->src_resolved.physical_address,
+ request->src_resolved.virtual_address,
+ request->src_resolved.is_pmem,
+ request->src_resolved.filep,
+ request->src_resolved.file_physical_start,
+ request->src_resolved.file_virtual_start,
+ request->src_resolved.file_len);
+
+ b2r2_log_info("dst.rbuf={%X,%p,%d} {%p,%X,%X,%d}\n",
+ request->dst_resolved.physical_address,
+ request->dst_resolved.virtual_address,
+ request->dst_resolved.is_pmem,
+ request->dst_resolved.filep,
+ request->dst_resolved.file_physical_start,
+ request->dst_resolved.file_virtual_start,
+ request->dst_resolved.file_len);
+
+ /* Calculate the number of nodes (and resources) needed for this job */
+ ret = b2r2_generic_analyze(request, &tmp_buf_width,
+ &tmp_buf_height, &tmp_buf_count, &node_count);
+ if (ret < 0) {
+ b2r2_log_warn(
+ "%s: Failed to analyze request, ret = %d\n",
+ __func__, ret);
+#ifdef CONFIG_DEBUG_FS
+ {
+ /* Failed, dump job to dmesg */
+ char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+
+ b2r2_log_info(
+ "%s: Analyze failed for:\n", __func__);
+ if (Buf != NULL) {
+ sprintf_req(request, Buf, sizeof(char) * 4096);
+ b2r2_log_info("%s", Buf);
+ kfree(Buf);
+ } else {
+ b2r2_log_info("Unable to print the request. "
+ "Message buffer allocation failed.\n");
+ }
+ }
+#endif
+ goto generate_nodes_failed;
+ }
+
+ /* Allocate the nodes needed */
+#ifdef B2R2_USE_NODE_GEN
+ request->first_node = b2r2_blt_alloc_nodes(node_count);
+ if (request->first_node == NULL) {
+ b2r2_log_warn(
+ "%s: Failed to allocate nodes, ret = %d\n",
+ __func__, ret);
+ goto generate_nodes_failed;
+ }
+#else
+ ret = b2r2_node_alloc(node_count, &(request->first_node));
+ if (ret < 0 || request->first_node == NULL) {
+ b2r2_log_warn(
+ "%s: Failed to allocate nodes, ret = %d\n",
+ __func__, ret);
+ goto generate_nodes_failed;
+ }
+#endif
+
+ /* Allocate the temporary buffers */
+ for (i = 0; i < tmp_buf_count; i++) {
+ void *virt;
+ work_bufs[i].size = tmp_buf_width * tmp_buf_height * 4;
+
+ virt = dma_alloc_coherent(b2r2_blt_device(),
+ work_bufs[i].size,
+ &(work_bufs[i].phys_addr),
+ GFP_DMA | GFP_KERNEL);
+ if (virt == NULL) {
+ ret = -ENOMEM;
+ goto alloc_work_bufs_failed;
+ }
+
+ work_bufs[i].virt_addr = virt;
+ memset(work_bufs[i].virt_addr, 0xff, work_bufs[i].size);
+ }
+ ret = b2r2_generic_configure(request,
+ request->first_node, &work_bufs[0], tmp_buf_count);
+
+ if (ret < 0) {
+ b2r2_log_warn(
+ "%s: Failed to perform generic configure, ret = %d\n",
+ __func__, ret);
+ goto generic_conf_failed;
+ }
+
+ /* Exit here if dry run */
+ if (flags & B2R2_BLT_FLAG_DRY_RUN)
+ goto exit_dry_run;
+
+ /*
+ * Configure the request and make sure
+ * that its job is run only for the LAST tile.
+ * This is when the request is complete
+ * and waiting clients should be notified.
+ */
+ last_node = request->first_node;
+ while (last_node && last_node->next)
+ last_node = last_node->next;
+
+ request->job.tag = (int) instance;
+ request->job.prio = request->user_req.prio;
+ request->job.first_node_address =
+ request->first_node->physical_address;
+ request->job.last_node_address =
+ last_node->physical_address;
+ request->job.callback = job_callback_gen;
+ request->job.release = job_release_gen;
+ /* Work buffers and nodes are pre-allocated */
+ request->job.acquire_resources = job_acquire_resources_gen;
+ request->job.release_resources = job_release_resources_gen;
+
+ /* Flush the L1/L2 cache for the buffers */
+
+ /* Source buffer */
+ if (!(flags & B2R2_BLT_FLAG_SRC_NO_CACHE_FLUSH) &&
+ (request->user_req.src_img.buf.type !=
+ B2R2_BLT_PTR_PHYSICAL) &&
+ !b2r2_is_mb_fmt(request->user_req.src_img.fmt))
+ /* MB formats are never touched by SW */
+ sync_buf(&request->user_req.src_img,
+ &request->src_resolved,
+ false, /*is_dst*/
+ &request->user_req.src_rect);
+
+ /* Source mask buffer */
+ if (!(flags & B2R2_BLT_FLAG_SRC_MASK_NO_CACHE_FLUSH) &&
+ (request->user_req.src_mask.buf.type !=
+ B2R2_BLT_PTR_PHYSICAL) &&
+ !b2r2_is_mb_fmt(request->user_req.src_mask.fmt))
+ /* MB formats are never touched by SW */
+ sync_buf(&request->user_req.src_mask,
+ &request->src_mask_resolved,
+ false, /*is_dst*/
+ NULL);
+
+ /* Destination buffer */
+ if (!(flags & B2R2_BLT_FLAG_DST_NO_CACHE_FLUSH) &&
+ (request->user_req.dst_img.buf.type !=
+ B2R2_BLT_PTR_PHYSICAL) &&
+ !b2r2_is_mb_fmt(request->user_req.dst_img.fmt))
+ /* MB formats are never touched by SW */
+ sync_buf(&request->user_req.dst_img,
+ &request->dst_resolved,
+ true, /*is_dst*/
+ &request->user_req.dst_rect);
+
+#ifdef CONFIG_DEBUG_FS
+ /* Remember latest request and first node for debugfs */
+ debugfs_latest_request = *request;
+ debugfs_latest_first_node = *request->first_node;
+#endif
+
+ /*
+ * Same nodes are reused for all the jobs needed to complete the blit.
+ * Nodes are NOT released together with associated job,
+ * as is the case with optimized b2r2_blt() path.
+ */
+ spin_lock(&instance->lock);
+ instance->no_of_active_requests++;
+ spin_unlock(&instance->lock);
+ /*
+ * Process all but the last row in the destination rectangle.
+ * Consider only the tiles that will actually end up inside
+ * the destination image.
+ * dst_rect->height - tmp_buf_height being <=0 is allright.
+ * The loop will not be entered since y will always be equal to or
+ * greater than zero.
+ * Early exit check at the beginning handles the cases when nothing
+ * at all should be processed.
+ */
+ y = 0;
+ if (dst_rect->y < 0)
+ y = -dst_rect->y;
+
+ for (; y < dst_rect->height - tmp_buf_height &&
+ y + dst_rect->y < dst_img_height - tmp_buf_height;
+ y += tmp_buf_height) {
+ /* Tile in the destination rectangle being processed */
+ struct b2r2_blt_rect dst_rect_tile;
+ dst_rect_tile.y = y;
+ dst_rect_tile.width = tmp_buf_width;
+ dst_rect_tile.height = tmp_buf_height;
+
+ x = 0;
+ if (dst_rect->x < 0)
+ x = -dst_rect->x;
+
+ for (; x < dst_rect->width &&
+ x + dst_rect->x < dst_img_width; x += tmp_buf_width) {
+ /*
+ * Tile jobs are freed by the supplied release function
+ * when ref_count on a tile_job reaches zero.
+ */
+ struct b2r2_core_job *tile_job = kmalloc(sizeof(*tile_job), GFP_KERNEL);
+ if (tile_job == NULL) {
+ /*
+ * Skip this tile. Do not abort, just hope for better luck
+ * with rest of the tiles. Memory might become available.
+ */
+ b2r2_log_info("%s: Failed to alloc job. "
+ "Skipping tile at (x, y)=(%d, %d)\n", __func__, x, y);
+ continue;
+ }
+ tile_job->tag = request->job.tag;
+ tile_job->prio = request->job.prio;
+ tile_job->first_node_address =
+ request->job.first_node_address;
+ tile_job->last_node_address =
+ request->job.last_node_address;
+ tile_job->callback = tile_job_callback_gen;
+ tile_job->release = tile_job_release_gen;
+ /* Work buffers and nodes are pre-allocated */
+ tile_job->acquire_resources = job_acquire_resources_gen;
+ tile_job->release_resources = job_release_resources_gen;
+
+ dst_rect_tile.x = x;
+ if (x + dst_rect->x + tmp_buf_width > dst_img_width) {
+ /*
+ * Only a part of the tile can be written.
+ * Limit imposed by buffer size.
+ */
+ dst_rect_tile.width = dst_img_width - (x + dst_rect->x);
+ } else if (x + tmp_buf_width > dst_rect->width) {
+ /*
+ * Only a part of the tile can be written.
+ * In this case limit imposed by dst_rect size.
+ */
+ dst_rect_tile.width = dst_rect->width - x;
+ } else {
+ /* Whole tile can be written. */
+ dst_rect_tile.width = tmp_buf_width;
+ }
+ /*
+ * Where applicable, calculate area in src buffer that is needed
+ * to generate the specified part of destination rectangle.
+ */
+ b2r2_generic_set_areas(request, request->first_node, &dst_rect_tile);
+ /* Submit the job */
+ b2r2_log_info("%s: Submitting job\n", __func__);
+
+ inc_stat(&stat_n_in_blt_add);
+
+ spin_lock(&instance->lock);
+
+ request_id = b2r2_core_job_add(tile_job);
+
+ dec_stat(&stat_n_in_blt_add);
+
+ if (request_id < 0) {
+ b2r2_log_warn("%s: "
+ "Failed to add tile job, ret = %d\n",
+ __func__, request_id);
+ ret = request_id;
+ spin_unlock(&instance->lock);
+ goto job_add_failed;
+ }
+
+ inc_stat(&stat_n_jobs_added);
+
+ spin_unlock(&instance->lock);
+
+ /* Wait for the job to be done */
+ b2r2_log_info("%s: Synchronous, waiting\n",
+ __func__);
+
+ inc_stat(&stat_n_in_blt_wait);
+
+ ret = b2r2_core_job_wait(tile_job);
+
+ dec_stat(&stat_n_in_blt_wait);
+
+ if (ret < 0 && ret != -ENOENT)
+ b2r2_log_warn(
+ "%s: Failed to wait job, ret = %d\n",
+ __func__, ret);
+ else {
+ b2r2_log_info(
+ "%s: Synchronous wait done\n",
+ __func__);
+
+ nsec_active_in_b2r2 +=
+ tile_job->nsec_active_in_hw;
+ }
+ /* Release matching the addref in b2r2_core_job_add */
+ b2r2_core_job_release(tile_job, __func__);
+ }
+ }
+
+ x = 0;
+ if (dst_rect->x < 0)
+ x = -dst_rect->x;
+
+ for (; x < dst_rect->width &&
+ x + dst_rect->x < dst_img_width; x += tmp_buf_width) {
+ struct b2r2_core_job *tile_job = NULL;
+ if (x + tmp_buf_width < dst_rect->width &&
+ x + dst_rect->x + tmp_buf_width < dst_img_width) {
+ /*
+ * Tile jobs are freed by the supplied release function
+ * when ref_count on a tile_job reaches zero.
+ * Do NOT allocate a tile_job for the last tile.
+ * Send the job from the request. This way clients
+ * will be notified when the whole blit is complete
+ * and not just part of it.
+ */
+ tile_job = kmalloc(sizeof(*tile_job), GFP_KERNEL);
+ if (tile_job == NULL) {
+ b2r2_log_info("%s: Failed to alloc job. "
+ "Skipping tile at (x, y)=(%d, %d)\n",
+ __func__, x, y);
+ continue;
+ }
+ tile_job->tag = request->job.tag;
+ tile_job->prio = request->job.prio;
+ tile_job->first_node_address =
+ request->job.first_node_address;
+ tile_job->last_node_address =
+ request->job.last_node_address;
+ tile_job->callback = tile_job_callback_gen;
+ tile_job->release = tile_job_release_gen;
+ tile_job->acquire_resources = job_acquire_resources_gen;
+ tile_job->release_resources = job_release_resources_gen;
+ }
+
+ dst_rect_tile.x = x;
+ if (x + dst_rect->x + tmp_buf_width > dst_img_width) {
+ /*
+ * Only a part of the tile can be written.
+ * Limit imposed by buffer size.
+ */
+ dst_rect_tile.width = dst_img_width - (x + dst_rect->x);
+ } else if (x + tmp_buf_width > dst_rect->width) {
+ /*
+ * Only a part of the tile can be written.
+ * In this case limit imposed by dst_rect size.
+ */
+ dst_rect_tile.width = dst_rect->width - x;
+ } else {
+ /* Whole tile can be written. */
+ dst_rect_tile.width = tmp_buf_width;
+ }
+ /*
+ * y is now the last row. Either because the whole dst_rect
+ * has been processed, or because the last row that will be written
+ * to dst_img has been reached. Limits imposed in the same way
+ * as for width.
+ */
+ dst_rect_tile.y = y;
+ if (y + dst_rect->y + tmp_buf_height > dst_img_height)
+ dst_rect_tile.height = dst_img_height - (y + dst_rect->y);
+ else if (y + tmp_buf_height > dst_rect->height)
+ dst_rect_tile.height = dst_rect->height - y;
+ else
+ dst_rect_tile.height = tmp_buf_height;
+
+ b2r2_generic_set_areas(request, request->first_node, &dst_rect_tile);
+
+ b2r2_log_info("%s: Submitting job\n", __func__);
+ inc_stat(&stat_n_in_blt_add);
+
+ spin_lock(&instance->lock);
+ if (x + tmp_buf_width < dst_rect->width &&
+ x + dst_rect->x + tmp_buf_width < dst_img_width) {
+ request_id = b2r2_core_job_add(tile_job);
+ } else {
+ /*
+ * Last tile. Send the job-struct from the request.
+ * Clients will be notified once it completes.
+ */
+ request_id = b2r2_core_job_add(&request->job);
+ }
+
+ dec_stat(&stat_n_in_blt_add);
+
+ if (request_id < 0) {
+ b2r2_log_warn("%s: Failed to add tile job, ret = %d\n",
+ __func__, request_id);
+ ret = request_id;
+ spin_unlock(&instance->lock);
+ if (tile_job != NULL)
+ kfree(tile_job);
+ goto job_add_failed;
+ }
+
+ inc_stat(&stat_n_jobs_added);
+ spin_unlock(&instance->lock);
+
+ b2r2_log_info("%s: Synchronous, waiting\n",
+ __func__);
+
+ inc_stat(&stat_n_in_blt_wait);
+ if (x + tmp_buf_width < dst_rect->width &&
+ x + dst_rect->x + tmp_buf_width < dst_img_width) {
+ ret = b2r2_core_job_wait(tile_job);
+ } else {
+ /*
+ * This is the last tile. Wait for the job-struct from
+ * the request.
+ */
+ ret = b2r2_core_job_wait(&request->job);
+ }
+ dec_stat(&stat_n_in_blt_wait);
+
+ if (ret < 0 && ret != -ENOENT)
+ b2r2_log_warn(
+ "%s: Failed to wait job, ret = %d\n",
+ __func__, ret);
+ else {
+ b2r2_log_info(
+ "%s: Synchronous wait done\n", __func__);
+
+ if (x + tmp_buf_width < dst_rect->width &&
+ x + dst_rect->x + tmp_buf_width < dst_img_width)
+ nsec_active_in_b2r2 += tile_job->nsec_active_in_hw;
+ else
+ nsec_active_in_b2r2 +=
+ request->job.nsec_active_in_hw;
+ }
+
+ /*
+ * Release matching the addref in b2r2_core_job_add.
+ * Make sure that the correct job-struct is released
+ * when the last tile is processed.
+ */
+ if (x + tmp_buf_width < dst_rect->width &&
+ x + dst_rect->x + tmp_buf_width < dst_img_width) {
+ b2r2_core_job_release(tile_job, __func__);
+ } else {
+ b2r2_core_job_release(&request->job, __func__);
+ }
+ }
+
+
+ ret = 0;
+
+
+ /* Unresolve the buffers */
+ unresolve_buf(&request->user_req.src_img.buf,
+ &request->src_resolved);
+ unresolve_buf(&request->user_req.src_mask.buf,
+ &request->src_mask_resolved);
+ unresolve_buf(&request->user_req.dst_img.buf,
+ &request->dst_resolved);
+
+ dec_stat(&stat_n_in_blt);
+
+ for (i = 0; i < tmp_buf_count; i++) {
+ dma_free_coherent(b2r2_blt_device(),
+ work_bufs[i].size,
+ work_bufs[i].virt_addr,
+ work_bufs[i].phys_addr);
+ memset(&(work_bufs[i]), 0, sizeof(work_bufs[i]));
+ }
+
+ if (request->profile) {
+ request->nsec_active_in_cpu =
+ (s32)((u32)task_sched_runtime(current) - thread_runtime_at_start);
+ request->total_time_nsec =
+ (s32)(b2r2_get_curr_nsec() - request->start_time_nsec);
+ request->job.nsec_active_in_hw = nsec_active_in_b2r2;
+
+ b2r2_call_profiler_blt_done(request);
+ }
+
+ return ret >= 0 ? request_id : ret;
+
+job_add_failed:
+exit_dry_run:
+generic_conf_failed:
+alloc_work_bufs_failed:
+ for (i = 0; i < 4; i++) {
+ if (work_bufs[i].virt_addr != 0) {
+ dma_free_coherent(b2r2_blt_device(),
+ work_bufs[i].size,
+ work_bufs[i].virt_addr,
+ work_bufs[i].phys_addr);
+ memset(&(work_bufs[i]), 0, sizeof(work_bufs[i]));
+ }
+ }
+
+generate_nodes_failed:
+ unresolve_buf(&request->user_req.dst_img.buf,
+ &request->dst_resolved);
+resolve_dst_buf_failed:
+ unresolve_buf(&request->user_req.src_mask.buf,
+ &request->src_mask_resolved);
+resolve_src_mask_buf_failed:
+ unresolve_buf(&request->user_req.src_img.buf,
+ &request->src_resolved);
+resolve_src_buf_failed:
+synch_interrupted:
+zero_blt:
+ job_release_gen(&request->job);
+ dec_stat(&stat_n_jobs_released);
+ dec_stat(&stat_n_in_blt);
+
+ b2r2_log_info("b2r2:%s ret=%d", __func__, ret);
+ return ret;
+}
+
+/**
+ * b2r2_blt_synch - Implements wait for all or a specified job
+ *
+ * @instance: The B2R2 BLT instance
+ * @request_id: If 0, wait for all requests on this instance to finish.
+ * Else wait for request with given request id to finish.
+ */
+static int b2r2_blt_synch(struct b2r2_blt_instance *instance,
+ int request_id)
+{
+ int ret = 0;
+ b2r2_log_info("%s, request_id=%d\n", __func__, request_id);
+
+ if (request_id == 0) {
+ /* Wait for all requests */
+ inc_stat(&stat_n_in_synch_0);
+
+ /* Enter state "synching" if we have any active request */
+ spin_lock(&instance->lock);
+ if (instance->no_of_active_requests)
+ instance->synching = true;
+ spin_unlock(&instance->lock);
+
+ /* Wait until no longer in state synching */
+ ret = wait_event_interruptible(instance->synch_done_waitq,
+ !is_synching(instance));
+ dec_stat(&stat_n_in_synch_0);
+ } else {
+ struct b2r2_core_job *job;
+
+ inc_stat(&stat_n_in_synch_job);
+
+ /* Wait for specific job */
+ job = b2r2_core_job_find(request_id);
+ if (job) {
+ /* Wait on find job */
+ ret = b2r2_core_job_wait(job);
+ /* Release matching the addref in b2r2_core_job_find */
+ b2r2_core_job_release(job, __func__);
+ }
+
+ /* If job not found we assume that is has been run */
+
+ dec_stat(&stat_n_in_synch_job);
+ }
+
+ b2r2_log_info(
+ "%s, request_id=%d, returns %d\n", __func__, request_id, ret);
+
+ return ret;
+}
+
+/**
+ * Query B2R2 capabilities
+ *
+ * @instance: The B2R2 BLT instance
+ * @query_cap: The structure receiving the capabilities
+ */
+static int b2r2_blt_query_cap(struct b2r2_blt_instance *instance,
+ struct b2r2_blt_query_cap *query_cap)
+{
+ /* FIXME: Not implemented yet */
+ return -ENOSYS;
+}
+
+/**
+ * Called when job is done or cancelled
+ *
+ * @job: The job
+ */
+static void job_callback(struct b2r2_core_job *job)
+{
+ struct b2r2_blt_request *request =
+ container_of(job, struct b2r2_blt_request, job);
+
+ if (b2r2_blt_device())
+ b2r2_log_info("%s\n", __func__);
+
+ /* Local addref / release within this func */
+ b2r2_core_job_addref(job, __func__);
+
+ /* Unresolve the buffers */
+ unresolve_buf(&request->user_req.src_img.buf,
+ &request->src_resolved);
+ unresolve_buf(&request->user_req.src_mask.buf,
+ &request->src_mask_resolved);
+ unresolve_buf(&request->user_req.dst_img.buf,
+ &request->dst_resolved);
+
+ /* Move to report list if the job shall be reported */
+ /* FIXME: Use a smaller struct? */
+ spin_lock(&request->instance->lock);
+ if (request->user_req.flags & B2R2_BLT_FLAG_REPORT_WHEN_DONE) {
+ /* Move job to report list */
+ list_add_tail(&request->list,
+ &request->instance->report_list);
+ inc_stat(&stat_n_jobs_in_report_list);
+
+ /* Wake up poll */
+ wake_up_interruptible(
+ &request->instance->report_list_waitq);
+
+ /* Add a reference because we put the job in the report list */
+ b2r2_core_job_addref(job, __func__);
+ }
+
+ /*
+ * Decrease number of active requests and wake up
+ * synching threads if active requests reaches zero
+ */
+ BUG_ON(request->instance->no_of_active_requests == 0);
+ request->instance->no_of_active_requests--;
+ if (request->instance->synching &&
+ request->instance->no_of_active_requests == 0) {
+ request->instance->synching = false;
+ /* Wake up all syncing */
+
+ wake_up_interruptible_all(
+ &request->instance->synch_done_waitq);
+ }
+ spin_unlock(&request->instance->lock);
+
+#ifdef CONFIG_DEBUG_FS
+ /* Dump job if cancelled */
+ if (job->job_state == B2R2_CORE_JOB_CANCELED) {
+ char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+
+ b2r2_log_info("%s: Job cancelled:\n", __func__);
+ if (Buf != NULL) {
+ sprintf_req(request, Buf, sizeof(char) * 4096);
+ b2r2_log_info("%s", Buf);
+ kfree(Buf);
+ } else {
+ b2r2_log_info("Unable to print the request. "
+ "Message buffer allocation failed.\n");
+ }
+ }
+#endif
+
+ if (request->profile) {
+ request->total_time_nsec =
+ (s32)(b2r2_get_curr_nsec() - request->start_time_nsec);
+ b2r2_call_profiler_blt_done(request);
+ }
+
+ /* Local addref / release within this func */
+ b2r2_core_job_release(job, __func__);
+}
+
+/**
+ * Called when job should be released (free memory etc.)
+ *
+ * @job: The job
+ */
+static void job_release(struct b2r2_core_job *job)
+{
+ struct b2r2_blt_request *request =
+ container_of(job, struct b2r2_blt_request, job);
+
+ inc_stat(&stat_n_jobs_released);
+
+ b2r2_log_info("%s, first_node=%p, ref_count=%d\n",
+ __func__, request->first_node, request->job.ref_count);
+
+ b2r2_node_split_cancel(&request->node_split_job);
+
+ /* Free nodes */
+#ifdef B2R2_USE_NODE_GEN
+ if (request->first_node)
+ b2r2_blt_free_nodes(request->first_node);
+#else
+ if (request->first_node)
+ b2r2_node_free(request->first_node);
+#endif
+
+ /* Release memory for the request */
+ if (request->clut != NULL) {
+ dma_free_coherent(b2r2_blt_device(), CLUT_SIZE, request->clut,
+ request->clut_phys_addr);
+ request->clut = NULL;
+ request->clut_phys_addr = 0;
+ }
+ kfree(request);
+}
+
+/**
+ * Tells the job to try to allocate the resources needed to execute the job.
+ * Called just before execution of a job.
+ *
+ * @job: The job
+ * @atomic: true if called from atomic (i.e. interrupt) context. If function
+ * can't allocate in atomic context it should return error, it
+ * will then be called later from non-atomic context.
+ */
+static int job_acquire_resources(struct b2r2_core_job *job, bool atomic)
+{
+ struct b2r2_blt_request *request =
+ container_of(job, struct b2r2_blt_request, job);
+ int ret;
+ int i;
+
+ b2r2_log_info("%s\n", __func__);
+
+ /* We do not support atomic allocations (I think...) */
+ if (atomic)
+ return -EAGAIN;
+
+ for (i = 0; i < request->buf_count; i++) {
+ void *virt;
+
+ b2r2_log_info("%s: allocating %d bytes\n",
+ __func__, request->bufs[i].size);
+
+ virt = dma_alloc_coherent(b2r2_blt_device(),
+ request->bufs[i].size,
+ &request->bufs[i].phys_addr,
+ GFP_DMA);
+ if (virt == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ request->bufs[i].virt_addr = virt;
+
+ b2r2_log_info("%s: phys=%p, virt=%p\n",
+ __func__, (void *)request->bufs[i].phys_addr,
+ request->bufs[i].virt_addr);
+
+ ret = b2r2_node_split_assign_buffers(&request->node_split_job,
+ request->first_node, request->bufs,
+ request->buf_count);
+ if (ret < 0)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ return ret;
+}
+
+/**
+ * Tells the job to free the resources needed to execute the job.
+ * Called after execution of a job.
+ *
+ * @job: The job
+ * @atomic: true if called from atomic (i.e. interrupt) context. If function
+ * can't allocate in atomic context it should return error, it
+ * will then be called later from non-atomic context.
+ */
+static void job_release_resources(struct b2r2_core_job *job, bool atomic)
+{
+ struct b2r2_blt_request *request =
+ container_of(job, struct b2r2_blt_request, job);
+
+ b2r2_log_info("%s\n", __func__);
+
+ /*
+ * Early release of nodes
+ * FIXME: If nodes are to be reused we don't want to release here
+ */
+ if (!atomic && request->first_node) {
+ int i;
+
+#ifdef B2R2_USE_NODE_GEN
+ b2r2_blt_free_nodes(request->first_node);
+#else
+ b2r2_node_free(request->first_node);
+#endif
+ request->first_node = NULL;
+
+ /* Free any temporary buffers */
+ for (i = 0; i < request->buf_count; i++) {
+
+ b2r2_log_info("%s: freeing %d bytes\n",
+ __func__, request->bufs[i].size);
+ dma_free_coherent(b2r2_blt_device(),
+ request->bufs[i].size,
+ request->bufs[i].virt_addr,
+ request->bufs[i].phys_addr);
+ memset(&request->bufs[i], 0, sizeof(request->bufs[i]));
+ }
+ request->buf_count = 0;
+ }
+}
+
+static void get_actual_dst_rect(struct b2r2_blt_req *req,
+ struct b2r2_blt_rect *actual_dst_rect)
+{
+ struct b2r2_blt_rect dst_img_bounds;
+
+ b2r2_get_img_bounding_rect(&req->dst_img, &dst_img_bounds);
+
+ b2r2_intersect_rects(&req->dst_rect, &dst_img_bounds, actual_dst_rect);
+
+ if (req->flags & B2R2_BLT_FLAG_DESTINATION_CLIP)
+ b2r2_intersect_rects(actual_dst_rect, &req->dst_clip_rect,
+ actual_dst_rect);
+}
+
+static void set_up_hwmem_region(struct b2r2_blt_img *img,
+ struct b2r2_blt_rect *rect, struct hwmem_region *region)
+{
+ s32 img_size;
+
+ if (b2r2_is_zero_area_rect(rect)) {
+ region->skip = 0;
+ region->count = 0;
+ region->start = 0;
+ region->end = 0;
+ region->size = 0;
+
+ return;
+ }
+
+ img_size = b2r2_get_img_size(img);
+
+ if (b2r2_is_single_plane_fmt(img->fmt) &&
+ b2r2_is_independent_pixel_fmt(img->fmt)) {
+ int img_fmt_bpp;
+
+ img_fmt_bpp = b2r2_get_fmt_bpp(img->fmt);
+
+ region->skip = (uint32_t)(img->height *
+ (img->buf.offset / img_size) + rect->y);
+ region->count = (uint32_t)rect->height;
+ region->start = (uint32_t)((rect->x * img_fmt_bpp) / 8);
+ region->end = (uint32_t)b2r2_div_round_up(
+ (rect->x + rect->width) * img_fmt_bpp, 8);
+ region->size = b2r2_get_img_pitch(img);
+ } else {
+ /*
+ * TODO: Locking entire buffer as a quick safe solution. In the
+ * future we should lock less to avoid unecessary cache
+ * synching. Pixel interleaved YCbCr formats should be quite
+ * easy, just align start and stop points on 2.
+ */
+ region->skip = (uint32_t)(img->buf.offset / img_size);
+ region->count = 1;
+ region->start = 0;
+ region->end = (uint32_t)img_size;
+ region->size = (uint32_t)img_size;
+ }
+}
+
+static int resolve_hwmem(struct b2r2_blt_img *img,
+ struct b2r2_blt_rect *rect_2b_used,
+ bool is_dst,
+ struct b2r2_resolved_buf *resolved_buf)
+{
+ int return_value = 0;
+ enum hwmem_mem_type mem_type;
+ enum hwmem_access access;
+ enum hwmem_access required_access;
+ struct hwmem_region region;
+
+ resolved_buf->hwmem_alloc =
+ hwmem_resolve_by_name(img->buf.hwmem_buf_name);
+ if (IS_ERR(resolved_buf->hwmem_alloc)) {
+ return_value = PTR_ERR(resolved_buf->hwmem_alloc);
+ b2r2_log_info("%s: hwmem_resolve_by_name failed, "
+ "error code: %i\n", __func__, return_value);
+ goto resolve_failed;
+ }
+
+ hwmem_get_info(resolved_buf->hwmem_alloc, &resolved_buf->file_len,
+ &mem_type, &access);
+
+ required_access = (is_dst ? HWMEM_ACCESS_WRITE : HWMEM_ACCESS_READ) |
+ HWMEM_ACCESS_IMPORT;
+ if ((required_access & access) != required_access) {
+ b2r2_log_info("%s: Insufficient access to hwmem buffer.\n",
+ __func__);
+ return_value = -EACCES;
+ goto access_check_failed;
+ }
+
+ if (mem_type != HWMEM_MEM_CONTIGUOUS_SYS) {
+ b2r2_log_info("%s: Hwmem buffer is scattered.\n", __func__);
+ return_value = -EINVAL;
+ goto buf_scattered;
+ }
+
+ if (resolved_buf->file_len <
+ img->buf.offset + (__u32)b2r2_get_img_size(img)) {
+ b2r2_log_info("%s: Hwmem buffer too small.\n", __func__);
+ return_value = -EINVAL;
+ goto size_check_failed;
+ }
+
+ return_value = hwmem_pin(resolved_buf->hwmem_alloc,
+ &resolved_buf->file_physical_start, NULL);
+ if (return_value < 0) {
+ b2r2_log_info("%s: hwmem_pin failed, "
+ "error code: %i\n", __func__, return_value);
+ goto pin_failed;
+ }
+
+ set_up_hwmem_region(img, rect_2b_used, &region);
+ return_value = hwmem_set_domain(resolved_buf->hwmem_alloc,
+ required_access, HWMEM_DOMAIN_SYNC, &region);
+ if (return_value < 0) {
+ b2r2_log_info("%s: hwmem_set_domain failed, "
+ "error code: %i\n", __func__, return_value);
+ goto set_domain_failed;
+ }
+
+ resolved_buf->physical_address =
+ resolved_buf->file_physical_start + img->buf.offset;
+
+ goto out;
+
+set_domain_failed:
+ hwmem_unpin(resolved_buf->hwmem_alloc);
+pin_failed:
+size_check_failed:
+buf_scattered:
+access_check_failed:
+ hwmem_release(resolved_buf->hwmem_alloc);
+resolve_failed:
+
+out:
+ return return_value;
+}
+
+static void unresolve_hwmem(struct b2r2_resolved_buf *resolved_buf)
+{
+ hwmem_unpin(resolved_buf->hwmem_alloc);
+ hwmem_release(resolved_buf->hwmem_alloc);
+}
+
+/**
+ * unresolve_buf() - Must be called after resolve_buf
+ *
+ * @buf: The buffer specification as supplied from user space
+ * @resolved: Gathered information about the buffer
+ *
+ * Returns 0 if OK else negative error code
+ */
+static void unresolve_buf(struct b2r2_blt_buf *buf,
+ struct b2r2_resolved_buf *resolved)
+{
+#ifdef CONFIG_ANDROID_PMEM
+ if (resolved->is_pmem && resolved->filep)
+ put_pmem_file(resolved->filep);
+#endif
+ if (resolved->hwmem_alloc != NULL)
+ unresolve_hwmem(resolved);
+}
+
+/**
+ * resolve_buf() - Returns the physical & virtual addresses of a B2R2 blt buffer
+ *
+ * @img: The image specification as supplied from user space
+ * @rect_2b_used: The part of the image b2r2 will use.
+ * @usage: Specifies how the buffer will be used.
+ * @resolved: Gathered information about the buffer
+ *
+ * Returns 0 if OK else negative error code
+ */
+static int resolve_buf(struct b2r2_blt_img *img,
+ struct b2r2_blt_rect *rect_2b_used,
+ bool is_dst,
+ struct b2r2_resolved_buf *resolved)
+{
+ int ret = 0;
+
+ memset(resolved, 0, sizeof(*resolved));
+
+ switch (img->buf.type) {
+ case B2R2_BLT_PTR_NONE:
+ break;
+
+ case B2R2_BLT_PTR_PHYSICAL:
+ resolved->physical_address = img->buf.offset;
+ resolved->file_len = img->buf.len;
+ break;
+
+ /* FD + OFFSET type */
+ case B2R2_BLT_PTR_FD_OFFSET: {
+ /*
+ * TODO: Do we need to check if the process is allowed to
+ * read/write (depending on if it's dst or src) to the file?
+ */
+ struct file *file;
+ int put_needed;
+ int i;
+
+#ifdef CONFIG_ANDROID_PMEM
+ if (!get_pmem_file(
+ img->buf.fd,
+ (unsigned long *) &resolved->file_physical_start,
+ (unsigned long *) &resolved->file_virtual_start,
+ (unsigned long *) &resolved->file_len,
+ &resolved->filep)) {
+ resolved->physical_address =
+ resolved->file_physical_start +
+ img->buf.offset;
+ resolved->virtual_address = (void *)
+ (resolved->file_virtual_start +
+ img->buf.offset);
+ resolved->is_pmem = true;
+ } else
+#endif
+ {
+ /* Will be set to 0 if a matching dev is found */
+ ret = -EINVAL;
+
+ file = fget_light(img->buf.fd, &put_needed);
+ if (file == NULL)
+ return -EINVAL;
+#ifdef CONFIG_FB
+ if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
+ /*
+ * This is a frame buffer device, find fb_info
+ * (OK to do it like this, no locking???)
+ */
+
+ for (i = 0; i < num_registered_fb; i++) {
+ struct fb_info *info = registered_fb[i];
+
+ if (info && info->dev &&
+ MINOR(info->dev->devt) ==
+ MINOR(file->f_dentry->d_inode->i_rdev)) {
+ resolved->file_physical_start =
+ info->fix.smem_start;
+ resolved->file_virtual_start =
+ (u32)info->screen_base;
+ resolved->file_len =
+ info->fix.smem_len;
+
+ resolved->physical_address =
+ resolved->file_physical_start +
+ img->buf.offset;
+ resolved->virtual_address =
+ (void *)(resolved->file_virtual_start +
+ img->buf.offset);
+
+ ret = 0;
+ break;
+ }
+ }
+ }
+#endif
+
+ fput_light(file, put_needed);
+ }
+
+ /* Check bounds */
+ if (ret >= 0 && img->buf.offset + img->buf.len >
+ resolved->file_len) {
+ ret = -ESPIPE;
+ unresolve_buf(&img->buf, resolved);
+ }
+
+ break;
+ }
+
+ case B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET:
+ ret = resolve_hwmem(img, rect_2b_used, is_dst, resolved);
+ break;
+
+ default:
+ b2r2_log_warn(
+ "%s: Failed to resolve buf type %d\n",
+ __func__, img->buf.type);
+
+ ret = -EINVAL;
+ break;
+
+ }
+
+ return ret;
+}
+
+/**
+ * sync_buf - Synchronizes the memory occupied by an image buffer.
+ *
+ * @buf: User buffer specification
+ * @resolved_buf: Gathered info (physical address etc.) about buffer
+ * @is_dst: true if the buffer is a destination buffer, false if the buffer is a
+ * source buffer.
+ * @rect: rectangle in the image buffer that should be synced. NULL the buffer is a source mask.
+ * @img_width: width of the complete image buffer
+ * @fmt: buffer format
+*/
+static void sync_buf(struct b2r2_blt_img *img,
+ struct b2r2_resolved_buf *resolved,
+ bool is_dst,
+ struct b2r2_blt_rect *rect)
+{
+ struct sync_args sa;
+ u32 start_phys, end_phys;
+
+ if (B2R2_BLT_PTR_NONE == img->buf.type ||
+ B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET == img->buf.type)
+ return;
+
+ start_phys = resolved->physical_address;
+ end_phys = resolved->physical_address + img->buf.len;
+
+ /*
+ * TODO: Very ugly. We should find out whether the memory is coherent in
+ * some generic way but cache handling will be rewritten soon so there
+ * is no use spending time on it. In the new design this will probably
+ * not be a problem.
+ */
+ /* Frame buffer is coherent, at least now. */
+ if (!resolved->is_pmem) {
+ /*
+ * Drain the write buffers as they are not always part of the
+ * coherent concept.
+ */
+ wmb();
+
+ return;
+ }
+
+ /*
+ * src_mask does not have rect.
+ * Also flush full buffer for planar and semiplanar YUV formats
+ */
+ if (rect == NULL ||
+ (img->fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR) ||
+ (img->fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR) ||
+ (img->fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR) ||
+ (img->fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR) ||
+ (img->fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR) ||
+ (img->fmt ==
+ B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE) ||
+ (img->fmt ==
+ B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE)) {
+ sa.start = (unsigned long)resolved->virtual_address;
+ sa.end = (unsigned long)resolved->virtual_address + img->buf.len;
+ start_phys = resolved->physical_address;
+ end_phys = resolved->physical_address + img->buf.len;
+ } else {
+ /* buffer is not a src_mask so make use of rect when clean & flush caches*/
+ u32 bpp; /* Bits per pixel */
+ u32 pitch;
+
+ switch (img->fmt) {
+ case B2R2_BLT_FMT_16_BIT_ARGB4444: /* Fall through */
+ case B2R2_BLT_FMT_16_BIT_ARGB1555: /* Fall through */
+ case B2R2_BLT_FMT_16_BIT_RGB565: /* Fall through */
+ case B2R2_BLT_FMT_Y_CB_Y_CR: /* Fall through */
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ bpp = 16;
+ break;
+ case B2R2_BLT_FMT_24_BIT_RGB888: /* Fall through */
+ case B2R2_BLT_FMT_24_BIT_ARGB8565: /* Fall through */
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ bpp = 24;
+ break;
+ case B2R2_BLT_FMT_32_BIT_ARGB8888: /* Fall through */
+ case B2R2_BLT_FMT_32_BIT_ABGR8888: /* Fall through */
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ bpp = 32;
+ break;
+ default:
+ bpp = 12;
+ }
+ if (img->pitch == 0)
+ pitch = (img->width * bpp) / 8;
+ else
+ pitch = img->pitch;
+
+ /*
+ * For 422I formats 2 horizontal pixels share color data.
+ * Thus, the x position must be aligned down to closest even
+ * number and width must be aligned up.
+ */
+ {
+ s32 x;
+ s32 width;
+
+ switch (img->fmt) {
+ case B2R2_BLT_FMT_Y_CB_Y_CR: /* Fall through */
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ x = (rect->x / 2) * 2;
+ width = ((rect->width + 1) / 2) * 2;
+ break;
+ default:
+ x = rect->x;
+ width = rect->width;
+ break;
+ }
+
+ sa.start = (unsigned long)resolved->virtual_address +
+ rect->y * pitch + (x * bpp) / 8;
+ sa.end = (unsigned long)sa.start +
+ (rect->height - 1) * pitch +
+ (width * bpp) / 8;
+
+ start_phys = resolved->physical_address +
+ rect->y * pitch + (x * bpp) / 8;
+ end_phys = start_phys +
+ (rect->height - 1) * pitch +
+ (width * bpp) / 8;
+ }
+ }
+
+ /*
+ * The virtual address to a pmem buffer is retrieved from ioremap, not
+ * sure if it's ok to use such an address as a kernel virtual address.
+ * When doing it at a higher level such as dma_map_single it triggers an
+ * error but at lower levels such as dmac_clean_range it seems to work,
+ * hence the low level stuff.
+ */
+
+ if (is_dst) {
+ /*
+ * According to ARM's docs you must clean before invalidating
+ * (ie flush) to avoid loosing data.
+ */
+
+ /* Flush L1 cache */
+#ifdef CONFIG_SMP
+ flush_l1_cache_range_all_cpus(&sa);
+#else
+ flush_l1_cache_range_curr_cpu(&sa);
+#endif
+
+ /* Flush L2 cache */
+ outer_flush_range(start_phys, end_phys);
+ } else {
+ /* Clean L1 cache */
+#ifdef CONFIG_SMP
+ clean_l1_cache_range_all_cpus(&sa);
+#else
+ clean_l1_cache_range_curr_cpu(&sa);
+#endif
+
+ /* Clean L2 cache */
+ outer_clean_range(start_phys, end_phys);
+ }
+}
+
+/**
+ * is_report_list_empty() - Spin lock protected check of report list
+ *
+ * @instance: The B2R2 BLT instance
+ */
+static bool is_report_list_empty(struct b2r2_blt_instance *instance)
+{
+ bool is_empty;
+
+ spin_lock(&instance->lock);
+ is_empty = list_empty(&instance->report_list);
+ spin_unlock(&instance->lock);
+
+ return is_empty;
+}
+
+/**
+ * is_synching() - Spin lock protected check if synching
+ *
+ * @instance: The B2R2 BLT instance
+ */
+static bool is_synching(struct b2r2_blt_instance *instance)
+{
+ bool is_synching;
+
+ spin_lock(&instance->lock);
+ is_synching = instance->synching;
+ spin_unlock(&instance->lock);
+
+ return is_synching;
+}
+
+/**
+ * b2r2_blt_devide() - Returns the B2R2 blt device for logging
+ */
+struct device *b2r2_blt_device(void)
+{
+ return b2r2_blt_dev ? b2r2_blt_dev->this_device : NULL;
+}
+
+/**
+ * inc_stat() - Spin lock protected increment of statistics variable
+ *
+ * @stat: Pointer to statistics variable that should be incremented
+ */
+static void inc_stat(unsigned long *stat)
+{
+ spin_lock(&stat_lock);
+ (*stat)++;
+ spin_unlock(&stat_lock);
+}
+
+/**
+ * inc_stat() - Spin lock protected decrement of statistics variable
+ *
+ * @stat: Pointer to statistics variable that should be decremented
+ */
+static void dec_stat(unsigned long *stat)
+{
+ spin_lock(&stat_lock);
+ (*stat)--;
+ spin_unlock(&stat_lock);
+}
+
+
+#ifdef CONFIG_DEBUG_FS
+/**
+ * sprintf_req() - Builds a string representing the request, for debug
+ *
+ * @request:Request that should be encoded into a string
+ * @buf: Receiving buffer
+ * @size: Size of receiving buffer
+ *
+ * Returns number of characters in string, excluding null terminator
+ */
+static int sprintf_req(struct b2r2_blt_request *request, char *buf, int size)
+{
+ size_t dev_size = 0;
+
+ dev_size += sprintf(buf + dev_size,
+ "instance: %p\n\n",
+ request->instance);
+
+ dev_size += sprintf(buf + dev_size,
+ "size: %d bytes\n",
+ request->user_req.size);
+ dev_size += sprintf(buf + dev_size,
+ "flags: %8lX\n",
+ (unsigned long) request->user_req.flags);
+ dev_size += sprintf(buf + dev_size,
+ "transform: %3lX\n",
+ (unsigned long) request->user_req.transform);
+ dev_size += sprintf(buf + dev_size,
+ "prio: %d\n",
+ request->user_req.transform);
+ dev_size += sprintf(buf + dev_size,
+ "src_img.fmt: %#010x\n",
+ request->user_req.src_img.fmt);
+ dev_size += sprintf(buf + dev_size,
+ "src_img.buf: {type=%d,hwmem_buf_name=%d,fd=%d,"
+ "offset=%d,len=%d}\n",
+ request->user_req.src_img.buf.type,
+ request->user_req.src_img.buf.hwmem_buf_name,
+ request->user_req.src_img.buf.fd,
+ request->user_req.src_img.buf.offset,
+ request->user_req.src_img.buf.len);
+ dev_size += sprintf(buf + dev_size,
+ "src_img.{width=%d,height=%d,pitch=%d}\n",
+ request->user_req.src_img.width,
+ request->user_req.src_img.height,
+ request->user_req.src_img.pitch);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask.fmt: %#010x\n",
+ request->user_req.src_mask.fmt);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask.buf: {type=%d,hwmem_buf_name=%d,fd=%d,"
+ "offset=%d,len=%d}\n",
+ request->user_req.src_mask.buf.type,
+ request->user_req.src_mask.buf.hwmem_buf_name,
+ request->user_req.src_mask.buf.fd,
+ request->user_req.src_mask.buf.offset,
+ request->user_req.src_mask.buf.len);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask.{width=%d,height=%d,pitch=%d}\n",
+ request->user_req.src_mask.width,
+ request->user_req.src_mask.height,
+ request->user_req.src_mask.pitch);
+ dev_size += sprintf(buf + dev_size,
+ "src_rect.{x=%d,y=%d,width=%d,height=%d}\n",
+ request->user_req.src_rect.x,
+ request->user_req.src_rect.y,
+ request->user_req.src_rect.width,
+ request->user_req.src_rect.height);
+ dev_size += sprintf(buf + dev_size,
+ "src_color=%08lX\n",
+ (unsigned long) request->user_req.src_color);
+
+ dev_size += sprintf(buf + dev_size,
+ "dst_img.fmt: %#010x\n",
+ request->user_req.dst_img.fmt);
+ dev_size += sprintf(buf + dev_size,
+ "dst_img.buf: {type=%d,hwmem_buf_name=%d,fd=%d,"
+ "offset=%d,len=%d}\n",
+ request->user_req.dst_img.buf.type,
+ request->user_req.dst_img.buf.hwmem_buf_name,
+ request->user_req.dst_img.buf.fd,
+ request->user_req.dst_img.buf.offset,
+ request->user_req.dst_img.buf.len);
+ dev_size += sprintf(buf + dev_size,
+ "dst_img.{width=%d,height=%d,pitch=%d}\n",
+ request->user_req.dst_img.width,
+ request->user_req.dst_img.height,
+ request->user_req.dst_img.pitch);
+ dev_size += sprintf(buf + dev_size,
+ "dst_rect.{x=%d,y=%d,width=%d,height=%d}\n",
+ request->user_req.dst_rect.x,
+ request->user_req.dst_rect.y,
+ request->user_req.dst_rect.width,
+ request->user_req.dst_rect.height);
+ dev_size += sprintf(buf + dev_size,
+ "dst_clip_rect.{x=%d,y=%d,width=%d,height=%d}\n",
+ request->user_req.dst_clip_rect.x,
+ request->user_req.dst_clip_rect.y,
+ request->user_req.dst_clip_rect.width,
+ request->user_req.dst_clip_rect.height);
+ dev_size += sprintf(buf + dev_size,
+ "dst_color=%08lX\n",
+ (unsigned long) request->user_req.dst_color);
+ dev_size += sprintf(buf + dev_size,
+ "global_alpha=%d\n",
+ (int) request->user_req.global_alpha);
+ dev_size += sprintf(buf + dev_size,
+ "report1=%08lX\n",
+ (unsigned long) request->user_req.report1);
+ dev_size += sprintf(buf + dev_size,
+ "report2=%08lX\n",
+ (unsigned long) request->user_req.report2);
+
+ dev_size += sprintf(buf + dev_size,
+ "request_id: %d\n",
+ request->request_id);
+
+ dev_size += sprintf(buf + dev_size,
+ "src_resolved.physical: %lX\n",
+ (unsigned long) request->src_resolved.
+ physical_address);
+ dev_size += sprintf(buf + dev_size,
+ "src_resolved.virtual: %p\n",
+ request->src_resolved.virtual_address);
+ dev_size += sprintf(buf + dev_size,
+ "src_resolved.filep: %p\n",
+ request->src_resolved.filep);
+ dev_size += sprintf(buf + dev_size,
+ "src_resolved.filep_physical_start: %lX\n",
+ (unsigned long) request->src_resolved.
+ file_physical_start);
+ dev_size += sprintf(buf + dev_size,
+ "src_resolved.filep_virtual_start: %p\n",
+ (void *) request->src_resolved.file_virtual_start);
+ dev_size += sprintf(buf + dev_size,
+ "src_resolved.file_len: %d\n",
+ request->src_resolved.file_len);
+
+ dev_size += sprintf(buf + dev_size,
+ "src_mask_resolved.physical: %lX\n",
+ (unsigned long) request->src_mask_resolved.
+ physical_address);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask_resolved.virtual: %p\n",
+ request->src_mask_resolved.virtual_address);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask_resolved.filep: %p\n",
+ request->src_mask_resolved.filep);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask_resolved.filep_physical_start: %lX\n",
+ (unsigned long) request->src_mask_resolved.
+ file_physical_start);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask_resolved.filep_virtual_start: %p\n",
+ (void *) request->src_mask_resolved.
+ file_virtual_start);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask_resolved.file_len: %d\n",
+ request->src_mask_resolved.file_len);
+
+ dev_size += sprintf(buf + dev_size,
+ "dst_resolved.physical: %lX\n",
+ (unsigned long) request->dst_resolved.
+ physical_address);
+ dev_size += sprintf(buf + dev_size,
+ "dst_resolved.virtual: %p\n",
+ request->dst_resolved.virtual_address);
+ dev_size += sprintf(buf + dev_size,
+ "dst_resolved.filep: %p\n",
+ request->dst_resolved.filep);
+ dev_size += sprintf(buf + dev_size,
+ "dst_resolved.filep_physical_start: %lX\n",
+ (unsigned long) request->dst_resolved.
+ file_physical_start);
+ dev_size += sprintf(buf + dev_size,
+ "dst_resolved.filep_virtual_start: %p\n",
+ (void *) request->dst_resolved.file_virtual_start);
+ dev_size += sprintf(buf + dev_size,
+ "dst_resolved.file_len: %d\n",
+ request->dst_resolved.file_len);
+
+ return dev_size;
+}
+
+/**
+ * debugfs_b2r2_blt_request_read() - Implements debugfs read for B2R2 register
+ *
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to read
+ * @f_pos: File position
+ *
+ * Returns number of bytes read or negative error code
+ */
+static int debugfs_b2r2_blt_request_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ size_t dev_size = 0;
+ int ret = 0;
+ char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+
+ if (Buf == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ dev_size = sprintf_req(&debugfs_latest_request, Buf, sizeof(char) * 4096);
+
+ /* No more to read if offset != 0 */
+ if (*f_pos > dev_size)
+ goto out;
+
+ if (*f_pos + count > dev_size)
+ count = dev_size - *f_pos;
+
+ if (copy_to_user(buf, Buf, count))
+ ret = -EINVAL;
+ *f_pos += count;
+ ret = count;
+
+out:
+ if (Buf != NULL)
+ kfree(Buf);
+ return ret;
+}
+
+/**
+ * debugfs_b2r2_blt_request_fops - File operations for B2R2 request debugfs
+ */
+static const struct file_operations debugfs_b2r2_blt_request_fops = {
+ .owner = THIS_MODULE,
+ .read = debugfs_b2r2_blt_request_read,
+};
+
+/**
+ * struct debugfs_reg - Represents a B2R2 node "register"
+ *
+ * @name: Register name
+ * @offset: Offset within the node
+ */
+struct debugfs_reg {
+ const char name[30];
+ u32 offset;
+};
+
+/**
+ * debugfs_node_regs - Array with all the registers in a B2R2 node, for debug
+ */
+static const struct debugfs_reg debugfs_node_regs[] = {
+ {"GROUP0.B2R2_NIP", offsetof(struct b2r2_link_list, GROUP0.B2R2_NIP)},
+ {"GROUP0.B2R2_CIC", offsetof(struct b2r2_link_list, GROUP0.B2R2_CIC)},
+ {"GROUP0.B2R2_INS", offsetof(struct b2r2_link_list, GROUP0.B2R2_INS)},
+ {"GROUP0.B2R2_ACK", offsetof(struct b2r2_link_list, GROUP0.B2R2_ACK)},
+
+ {"GROUP1.B2R2_TBA", offsetof(struct b2r2_link_list, GROUP1.B2R2_TBA)},
+ {"GROUP1.B2R2_TTY", offsetof(struct b2r2_link_list, GROUP1.B2R2_TTY)},
+ {"GROUP1.B2R2_TXY", offsetof(struct b2r2_link_list, GROUP1.B2R2_TXY)},
+ {"GROUP1.B2R2_TSZ", offsetof(struct b2r2_link_list, GROUP1.B2R2_TSZ)},
+
+ {"GROUP2.B2R2_S1CF", offsetof(struct b2r2_link_list, GROUP2.B2R2_S1CF)},
+ {"GROUP2.B2R2_S2CF", offsetof(struct b2r2_link_list, GROUP2.B2R2_S2CF)},
+
+ {"GROUP3.B2R2_SBA", offsetof(struct b2r2_link_list, GROUP3.B2R2_SBA)},
+ {"GROUP3.B2R2_STY", offsetof(struct b2r2_link_list, GROUP3.B2R2_STY)},
+ {"GROUP3.B2R2_SXY", offsetof(struct b2r2_link_list, GROUP3.B2R2_SXY)},
+ {"GROUP3.B2R2_SSZ", offsetof(struct b2r2_link_list, GROUP3.B2R2_SSZ)},
+
+ {"GROUP4.B2R2_SBA", offsetof(struct b2r2_link_list, GROUP4.B2R2_SBA)},
+ {"GROUP4.B2R2_STY", offsetof(struct b2r2_link_list, GROUP4.B2R2_STY)},
+ {"GROUP4.B2R2_SXY", offsetof(struct b2r2_link_list, GROUP4.B2R2_SXY)},
+ {"GROUP4.B2R2_SSZ", offsetof(struct b2r2_link_list, GROUP4.B2R2_SSZ)},
+
+ {"GROUP5.B2R2_SBA", offsetof(struct b2r2_link_list, GROUP5.B2R2_SBA)},
+ {"GROUP5.B2R2_STY", offsetof(struct b2r2_link_list, GROUP5.B2R2_STY)},
+ {"GROUP5.B2R2_SXY", offsetof(struct b2r2_link_list, GROUP5.B2R2_SXY)},
+ {"GROUP5.B2R2_SSZ", offsetof(struct b2r2_link_list, GROUP5.B2R2_SSZ)},
+
+ {"GROUP6.B2R2_CWO", offsetof(struct b2r2_link_list, GROUP6.B2R2_CWO)},
+ {"GROUP6.B2R2_CWS", offsetof(struct b2r2_link_list, GROUP6.B2R2_CWS)},
+
+ {"GROUP7.B2R2_CCO", offsetof(struct b2r2_link_list, GROUP7.B2R2_CCO)},
+ {"GROUP7.B2R2_CML", offsetof(struct b2r2_link_list, GROUP7.B2R2_CML)},
+
+ {"GROUP8.B2R2_FCTL", offsetof(struct b2r2_link_list, GROUP8.B2R2_FCTL)},
+ {"GROUP8.B2R2_PMK", offsetof(struct b2r2_link_list, GROUP8.B2R2_PMK)},
+
+ {"GROUP9.B2R2_RSF", offsetof(struct b2r2_link_list, GROUP9.B2R2_RSF)},
+ {"GROUP9.B2R2_RZI", offsetof(struct b2r2_link_list, GROUP9.B2R2_RZI)},
+ {"GROUP9.B2R2_HFP", offsetof(struct b2r2_link_list, GROUP9.B2R2_HFP)},
+ {"GROUP9.B2R2_VFP", offsetof(struct b2r2_link_list, GROUP9.B2R2_VFP)},
+
+ {"GROUP10.B2R2_RSF", offsetof(struct b2r2_link_list, GROUP10.B2R2_RSF)},
+ {"GROUP10.B2R2_RZI", offsetof(struct b2r2_link_list, GROUP10.B2R2_RZI)},
+ {"GROUP10.B2R2_HFP", offsetof(struct b2r2_link_list, GROUP10.B2R2_HFP)},
+ {"GROUP10.B2R2_VFP", offsetof(struct b2r2_link_list, GROUP10.B2R2_VFP)},
+
+ {"GROUP11.B2R2_Coeff0", offsetof(struct b2r2_link_list,
+ GROUP11.B2R2_Coeff0)},
+ {"GROUP11.B2R2_Coeff1", offsetof(struct b2r2_link_list,
+ GROUP11.B2R2_Coeff1)},
+ {"GROUP11.B2R2_Coeff2", offsetof(struct b2r2_link_list,
+ GROUP11.B2R2_Coeff2)},
+ {"GROUP11.B2R2_Coeff3", offsetof(struct b2r2_link_list,
+ GROUP11.B2R2_Coeff3)},
+
+ {"GROUP12.B2R2_KEY1", offsetof(struct b2r2_link_list,
+ GROUP12.B2R2_KEY1)},
+ {"GROUP12.B2R2_KEY2", offsetof(struct b2r2_link_list,
+ GROUP12.B2R2_KEY2)},
+
+ {"GROUP13.B2R2_XYL", offsetof(struct b2r2_link_list, GROUP13.B2R2_XYL)},
+ {"GROUP13.B2R2_XYP", offsetof(struct b2r2_link_list, GROUP13.B2R2_XYP)},
+
+ {"GROUP14.B2R2_SAR", offsetof(struct b2r2_link_list, GROUP14.B2R2_SAR)},
+ {"GROUP14.B2R2_USR", offsetof(struct b2r2_link_list, GROUP14.B2R2_USR)},
+
+ {"GROUP15.B2R2_VMX0", offsetof(struct b2r2_link_list,
+ GROUP15.B2R2_VMX0)},
+ {"GROUP15.B2R2_VMX1", offsetof(struct b2r2_link_list,
+ GROUP15.B2R2_VMX1)},
+ {"GROUP15.B2R2_VMX2", offsetof(struct b2r2_link_list,
+ GROUP15.B2R2_VMX2)},
+ {"GROUP15.B2R2_VMX3", offsetof(struct b2r2_link_list,
+ GROUP15.B2R2_VMX3)},
+
+ {"GROUP16.B2R2_VMX0", offsetof(struct b2r2_link_list,
+ GROUP16.B2R2_VMX0)},
+ {"GROUP16.B2R2_VMX1", offsetof(struct b2r2_link_list,
+ GROUP16.B2R2_VMX1)},
+ {"GROUP16.B2R2_VMX2", offsetof(struct b2r2_link_list,
+ GROUP16.B2R2_VMX2)},
+ {"GROUP16.B2R2_VMX3", offsetof(struct b2r2_link_list,
+ GROUP16.B2R2_VMX3)},
+};
+
+/**
+ * sprintf_node() - Encodes a B2R2 node into a string
+ *
+ * @node: The node to convert to a string
+ * @buf: Receiving buffer
+ * @size: Size of receiving buffer
+ */
+static int sprintf_node(struct b2r2_link_list *node, char *buf, int size)
+{
+ size_t dev_size = 0;
+ int i;
+
+ /* Handle null node */
+ if (!node) {
+ dev_size = sprintf(buf + dev_size,
+ "{null}\n");
+ return dev_size;
+ }
+
+ /* Loop over all registers */
+ for (i = 0; i < ARRAY_SIZE(debugfs_node_regs); i++) {
+ unsigned long value =
+ *((unsigned long *) (((u8 *) node) +
+ debugfs_node_regs[i].offset));
+ dev_size += sprintf(buf + dev_size, "%s: %08lX\n",
+ debugfs_node_regs[i].name,
+ value);
+ }
+
+ return dev_size;
+}
+
+/**
+ * debugfs_b2r2_blt_first_node_read() - Implements debugfs read for
+ * B2R2 BLT request first node
+ *
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to read
+ * @f_pos: File position
+ *
+ * Returns number of bytes read or negative error code
+ */
+static int debugfs_b2r2_blt_first_node_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ size_t dev_size = 0;
+ int ret = 0;
+ char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+
+ if (Buf == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ dev_size = sprintf_node(&debugfs_latest_first_node.node,
+ Buf, sizeof(char) * 4096);
+
+ /* No more to read if offset != 0 */
+ if (*f_pos > dev_size)
+ goto out;
+
+ if (*f_pos + count > dev_size)
+ count = dev_size - *f_pos;
+
+ if (copy_to_user(buf, Buf, count))
+ ret = -EINVAL;
+ *f_pos += count;
+ ret = count;
+
+out:
+ if (Buf != NULL)
+ kfree(Buf);
+ return ret;
+}
+
+/**
+ * debugfs_b2r2_blt_first_node_fops() - File operations for first node
+ */
+static const struct file_operations debugfs_b2r2_blt_first_node_fops = {
+ .owner = THIS_MODULE,
+ .read = debugfs_b2r2_blt_first_node_read,
+};
+
+
+/**
+ * debugfs_b2r2_blt_stat_read() - Implements debugfs read for B2R2 BLT
+ * statistics
+ *
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to read
+ * @f_pos: File position
+ *
+ * Returns number of bytes read or negative error code
+ */
+static int debugfs_b2r2_blt_stat_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ size_t dev_size = 0;
+ int ret = 0;
+ char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+
+ if (Buf == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ spin_lock(&stat_lock);
+ dev_size += sprintf(Buf + dev_size, "Added jobs: %lu\n",
+ stat_n_jobs_added);
+ dev_size += sprintf(Buf + dev_size, "Released jobs: %lu\n",
+ stat_n_jobs_released);
+ dev_size += sprintf(Buf + dev_size, "Jobs in report list: %lu\n",
+ stat_n_jobs_in_report_list);
+ dev_size += sprintf(Buf + dev_size, "Clients in open: %lu\n",
+ stat_n_in_open);
+ dev_size += sprintf(Buf + dev_size, "Clients in release: %lu\n",
+ stat_n_in_release);
+ dev_size += sprintf(Buf + dev_size, "Clients in blt: %lu\n",
+ stat_n_in_blt);
+ dev_size += sprintf(Buf + dev_size, " synch: %lu\n",
+ stat_n_in_blt_synch);
+ dev_size += sprintf(Buf + dev_size, " add: %lu\n",
+ stat_n_in_blt_add);
+ dev_size += sprintf(Buf + dev_size, " wait: %lu\n",
+ stat_n_in_blt_wait);
+ dev_size += sprintf(Buf + dev_size, "Clients in synch 0: %lu\n",
+ stat_n_in_synch_0);
+ dev_size += sprintf(Buf + dev_size, "Clients in synch job: %lu\n",
+ stat_n_in_synch_job);
+ dev_size += sprintf(Buf + dev_size, "Clients in query_cap: %lu\n",
+ stat_n_in_query_cap);
+ spin_unlock(&stat_lock);
+
+ /* No more to read if offset != 0 */
+ if (*f_pos > dev_size)
+ goto out;
+
+ if (*f_pos + count > dev_size)
+ count = dev_size - *f_pos;
+
+ if (copy_to_user(buf, Buf, count))
+ ret = -EINVAL;
+ *f_pos += count;
+ ret = count;
+
+out:
+ if (Buf != NULL)
+ kfree(Buf);
+ return ret;
+}
+
+/**
+ * debugfs_b2r2_blt_stat_fops() - File operations for B2R2 BLT
+ * statistics debugfs
+ */
+static const struct file_operations debugfs_b2r2_blt_stat_fops = {
+ .owner = THIS_MODULE,
+ .read = debugfs_b2r2_blt_stat_read,
+};
+#endif
+
+/**
+ * b2r2_blt_module_init() - Module init function
+ *
+ * Returns 0 if OK else negative error code
+ */
+int b2r2_blt_module_init(void)
+{
+ int ret;
+
+ spin_lock_init(&stat_lock);
+
+#ifdef B2R2_GENERIC_BLT
+ /* Initialize generic path */
+ b2r2_generic_init();
+#elif defined(B2R2_OPT_BLT)
+ /* Initialize node splitter */
+ ret = b2r2_node_split_init();
+ if (ret) {
+ printk(KERN_WARNING "%s: node split init fails\n",
+ __func__);
+ goto b2r2_node_split_init_fail;
+ }
+#elif defined(B2R2_GEN_OPT_MIX)
+ /* Initialize generic path */
+ b2r2_generic_init();
+ /* Initialize node splitter */
+ ret = b2r2_node_split_init();
+ if (ret) {
+ printk(KERN_WARNING "%s: node split init fails\n",
+ __func__);
+ goto b2r2_node_split_init_fail;
+ }
+#endif
+
+ /* Register b2r2 driver */
+ ret = misc_register(&b2r2_blt_misc_dev);
+ if (ret) {
+ printk(KERN_WARNING "%s: registering misc device fails\n",
+ __func__);
+ goto b2r2_misc_register_fail;
+ }
+
+ b2r2_blt_misc_dev.this_device->coherent_dma_mask = 0xFFFFFFFF;
+ b2r2_blt_dev = &b2r2_blt_misc_dev;
+ b2r2_log_info("%s\n", __func__);
+
+ /* Initialize memory allocator */
+ /*
+ * FIXME: Should be before misc_register,
+ * someone might issue requests on /dev/b2r2_blt
+ */
+ ret = b2r2_mem_init(b2r2_blt_device(), B2R2_HEAP_SIZE,
+ 4, sizeof(struct b2r2_node));
+ if (ret) {
+ printk(KERN_WARNING "%s: initializing B2R2 memhandler fails\n",
+ __func__);
+ goto b2r2_mem_init_fail;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ /* Register debug fs */
+ if (!debugfs_root_dir) {
+ debugfs_root_dir = debugfs_create_dir("b2r2_blt", NULL);
+ debugfs_create_file("latest_request",
+ 0666, debugfs_root_dir,
+ 0,
+ &debugfs_b2r2_blt_request_fops);
+ debugfs_create_file("first_node",
+ 0666, debugfs_root_dir,
+ 0,
+ &debugfs_b2r2_blt_first_node_fops);
+ debugfs_create_file("stat",
+ 0666, debugfs_root_dir,
+ 0,
+ &debugfs_b2r2_blt_stat_fops);
+
+ debugfs_create_u32("b2r2_heap_size",
+ 0666, debugfs_root_dir,
+ &b2r2_heap_size);
+ }
+#endif
+ goto out;
+
+b2r2_misc_register_fail:
+b2r2_mem_init_fail:
+#ifdef B2R2_GENERIC_BLT
+ b2r2_generic_exit();
+#elif defined(B2R2_OPT_BLT)
+ b2r2_node_split_exit();
+b2r2_node_split_init_fail:
+#elif defined(B2R2_GEN_OPT_MIX)
+ b2r2_node_split_exit();
+b2r2_node_split_init_fail:
+ /*
+ * Safe to call regardless of whether or not b2r2_generic_init()
+ * actually succeeded.
+ */
+ b2r2_generic_exit();
+#endif
+out:
+ return ret;
+}
+
+/**
+ * b2r2_module_exit() - Module exit function
+ */
+void b2r2_blt_module_exit(void)
+{
+#ifdef CONFIG_DEBUG_FS
+ if (debugfs_root_dir) {
+ debugfs_remove_recursive(debugfs_root_dir);
+ debugfs_root_dir = NULL;
+ }
+#endif
+ if (b2r2_blt_dev) {
+ b2r2_log_info("%s\n", __func__);
+ b2r2_mem_exit();
+ b2r2_blt_dev = NULL;
+ misc_deregister(&b2r2_blt_misc_dev);
+ }
+
+ b2r2_node_split_exit();
+
+#if defined(B2R2_GENERIC_BLT) || defined(B2R2_GEN_OPT_MIX)
+ b2r2_generic_exit();
+#endif
+}
+
+MODULE_AUTHOR("Robert Fekete <robert.fekete@stericsson.com>");
+MODULE_DESCRIPTION("ST-Ericsson B2R2 Blitter module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/b2r2/b2r2_core.c b/drivers/video/b2r2/b2r2_core.c
new file mode 100644
index 00000000000..f11ddab917d
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_core.c
@@ -0,0 +1,2613 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 core driver
+ *
+ * Author: Robert Fekete <robert.fekete@stericsson.com>
+ * Author: Paul Wannback
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+/*
+ * TODO: Clock address from platform data
+ * Platform data should have string id instead of numbers
+ * b2r2_remove, some type of runtime problem when kernel hacking
+ * debug features on
+ *
+ * Is there already a priority list in kernel?
+ * Is it possible to handle clock using clock framework?
+ * uTimeOut, use mdelay instead?
+ * Measure performance
+ *
+ * Exchange our home-cooked ref count with kernel kref? See
+ * http://lwn.net/Articles/336224/
+ *
+ * B2R2:
+ * Source fill 2 bug
+ * Check with Symbian?
+ */
+
+/* include file */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#endif
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+
+#include "b2r2_core.h"
+#include "b2r2_global.h"
+#include "b2r2_structures.h"
+#include "b2r2_internal.h"
+#include "b2r2_profiler_api.h"
+#include "b2r2_timing.h"
+#include "b2r2_debug.h"
+
+#include <mach/prcmu-fw-api.h>
+
+/**
+ * B2R2_DRIVER_TIMEOUT_VALUE - Busy loop timeout after soft reset
+ */
+#define B2R2_DRIVER_TIMEOUT_VALUE (1500)
+
+/**
+ * B2R2_CLK_FLAG - Value to write into clock reg to turn clock on
+ */
+#define B2R2_CLK_FLAG (0x125)
+
+/**
+ * DEBUG_CHECK_ADDREF_RELEASE - Define this to enable addref / release debug
+ */
+#define DEBUG_CHECK_ADDREF_RELEASE 1
+
+#ifdef CONFIG_DEBUG_FS
+/**
+ * HANDLE_TIMEOUTED_JOBS - Define this to check jobs for timeout and cancel them
+ */
+#define HANDLE_TIMEOUTED_JOBS 1
+#endif
+
+/**
+ * B2R2_CLOCK_ALWAYS_ON - Define this to disable power save clock turn off
+ */
+/* #define B2R2_CLOCK_ALWAYS_ON 1 */
+
+/**
+ * START_SENTINEL - Watch guard to detect job overwrites
+ */
+#define START_SENTINEL 0xBABEDEEA
+
+/**
+ * STOP_SENTINEL - Watch guard to detect job overwrites
+ */
+#define END_SENTINEL 0xDADBDCDD
+
+/**
+ * B2R2_CORE_LOWEST_PRIO - Lowest prio allowed
+ */
+#define B2R2_CORE_LOWEST_PRIO -19
+/**
+ * B2R2_CORE_HIGHEST_PRIO - Highest prio allowed
+ */
+#define B2R2_CORE_HIGHEST_PRIO 20
+
+
+/**
+ * B2R2 Hardware defines below
+ */
+
+/* - BLT_AQ_CTL */
+#define B2R2_AQ_Enab (0x80000000)
+#define B2R2_AQ_PRIOR_0 (0x0)
+#define B2R2_AQ_PRIOR_1 (0x1)
+#define B2R2_AQ_PRIOR_2 (0x2)
+#define B2R2_AQ_PRIOR_3 (0x3)
+#define B2R2_AQ_NODE_REPEAT_INT (0x100000)
+#define B2R2_AQ_STOP_INT (0x200000)
+#define B2R2_AQ_LNA_REACH_INT (0x400000)
+#define B2R2_AQ_COMPLETED_INT (0x800000)
+
+/* - BLT_CTL */
+#define B2R2BLT_CTLGLOBAL_soft_reset (0x80000000)
+#define B2R2BLT_CTLStep_By_Step (0x20000000)
+#define B2R2BLT_CTLBig_not_little (0x10000000)
+#define B2R2BLT_CTLMask (0xb0000000)
+#define B2R2BLT_CTLTestMask (0xb0000000)
+#define B2R2BLT_CTLInitialValue (0x0)
+#define B2R2BLT_CTLAccessType (INITIAL_TEST)
+#define B2R2BLT_CTL (0xa00)
+
+/* - BLT_ITS */
+#define B2R2BLT_ITSRLD_ERROR (0x80000000)
+#define B2R2BLT_ITSAQ4_Node_Notif (0x8000000)
+#define B2R2BLT_ITSAQ4_Node_repeat (0x4000000)
+#define B2R2BLT_ITSAQ4_Stopped (0x2000000)
+#define B2R2BLT_ITSAQ4_LNA_Reached (0x1000000)
+#define B2R2BLT_ITSAQ3_Node_Notif (0x800000)
+#define B2R2BLT_ITSAQ3_Node_repeat (0x400000)
+#define B2R2BLT_ITSAQ3_Stopped (0x200000)
+#define B2R2BLT_ITSAQ3_LNA_Reached (0x100000)
+#define B2R2BLT_ITSAQ2_Node_Notif (0x80000)
+#define B2R2BLT_ITSAQ2_Node_repeat (0x40000)
+#define B2R2BLT_ITSAQ2_Stopped (0x20000)
+#define B2R2BLT_ITSAQ2_LNA_Reached (0x10000)
+#define B2R2BLT_ITSAQ1_Node_Notif (0x8000)
+#define B2R2BLT_ITSAQ1_Node_repeat (0x4000)
+#define B2R2BLT_ITSAQ1_Stopped (0x2000)
+#define B2R2BLT_ITSAQ1_LNA_Reached (0x1000)
+#define B2R2BLT_ITSCQ2_Repaced (0x80)
+#define B2R2BLT_ITSCQ2_Node_Notif (0x40)
+#define B2R2BLT_ITSCQ2_retriggered (0x20)
+#define B2R2BLT_ITSCQ2_completed (0x10)
+#define B2R2BLT_ITSCQ1_Repaced (0x8)
+#define B2R2BLT_ITSCQ1_Node_Notif (0x4)
+#define B2R2BLT_ITSCQ1_retriggered (0x2)
+#define B2R2BLT_ITSCQ1_completed (0x1)
+#define B2R2BLT_ITSMask (0x8ffff0ff)
+#define B2R2BLT_ITSTestMask (0x8ffff0ff)
+#define B2R2BLT_ITSInitialValue (0x0)
+#define B2R2BLT_ITSAccessType (INITIAL_TEST)
+#define B2R2BLT_ITS (0xa04)
+
+/* - BLT_STA1 */
+#define B2R2BLT_STA1BDISP_IDLE (0x1)
+#define B2R2BLT_STA1Mask (0x1)
+#define B2R2BLT_STA1TestMask (0x1)
+#define B2R2BLT_STA1InitialValue (0x1)
+#define B2R2BLT_STA1AccessType (INITIAL_TEST)
+#define B2R2BLT_STA1 (0xa08)
+
+
+#ifdef DEBUG_CHECK_ADDREF_RELEASE
+
+/**
+ * struct addref_release - Represents one addref or release. Used
+ * to debug addref / release problems
+ *
+ * @addref: true if this represents an addref else it represents
+ * a release.
+ * @job: The job that was referenced
+ * @caller: The caller of the addref or release
+ * @ref_count: The job reference count after addref / release
+ */
+struct addref_release {
+ bool addref;
+ struct b2r2_core_job *job;
+ const char *caller;
+ int ref_count;
+};
+
+#endif
+
+/**
+ * struct b2r2_core - Administration data for B2R2 core
+ *
+ * @lock: Spin lock protecting the b2r2_core structure and the B2R2 HW
+ * @hw: B2R2 registers memory mapped
+ * @pmu_b2r2_clock: Control of B2R2 clock
+ * @log_dev: Device used for logging via dev_... functions
+ *
+ * @prio_queue: Queue of jobs sorted in priority order
+ * @active_jobs: Array containing pointer to zero or one job per queue
+ * @n_active_jobs: Number of active jobs
+ * @jiffies_last_active: jiffie value when adding last active job
+ * @jiffies_last_irq: jiffie value when last irq occured
+ * @timeout_work: Work structure for timeout work
+ *
+ * @next_job_id: Contains the job id that will be assigned to the next
+ * added job.
+ *
+ * @clock_request_count: When non-zero, clock is on
+ * @clock_off_timer: Kernel timer to handle delayed turn off of clock
+ *
+ * @work_queue: Work queue to handle done jobs (callbacks) and timeouts in
+ * non-interrupt context.
+ *
+ * @stat_n_irq: Number of interrupts (statistics)
+ * @stat_n_jobs_added: Number of jobs added (statistics)
+ * @stat_n_jobs_removed: Number of jobs removed (statistics)
+ * @stat_n_jobs_in_prio_list: Number of jobs in prio list (statistics)
+ *
+ * @debugfs_root_dir: Root directory for B2R2 debugfs
+ *
+ * @ar: Circular array of addref / release debug structs
+ * @ar_write: Where next write will occur
+ * @ar_read: First valid place to read. When ar_read == ar_write then
+ * the array is empty.
+ */
+struct b2r2_core {
+ spinlock_t lock;
+
+ struct b2r2_memory_map *hw;
+
+ struct clk *b2r2_clock;
+
+ bool b2r2_clock_on;
+
+ struct device *log_dev;
+
+ struct list_head prio_queue;
+
+ struct b2r2_core_job *active_jobs[B2R2_CORE_QUEUE_NO_OF];
+ unsigned long n_active_jobs;
+
+ unsigned long jiffies_last_active;
+ unsigned long jiffies_last_irq;
+#ifdef HANDLE_TIMEOUTED_JOBS
+ struct delayed_work timeout_work;
+#endif
+ int next_job_id;
+
+ unsigned long clock_request_count;
+ struct timer_list clock_off_timer;
+
+ struct workqueue_struct *work_queue;
+
+ /* Statistics */
+ unsigned long stat_n_irq;
+ unsigned long stat_n_jobs_added;
+ unsigned long stat_n_jobs_removed;
+
+ unsigned long stat_n_jobs_in_prio_list;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_root_dir;
+#endif
+
+#ifdef DEBUG_CHECK_ADDREF_RELEASE
+ /* Tracking release bug...*/
+ struct addref_release ar[100];
+ int ar_write;
+ int ar_read;
+#endif
+};
+
+/**
+ * b2r2_core - Administration data for B2R2 core (singleton)
+ */
+static struct b2r2_core b2r2_core;
+
+/* Local functions */
+static void check_prio_list(bool atomic);
+static void clear_interrupts(void);
+static void trigger_job(struct b2r2_core_job *job);
+static void exit_job_list(struct list_head *job_list);
+static int get_next_job_id(void);
+static void job_work_function(struct work_struct *ptr);
+static void init_job(struct b2r2_core_job *job);
+static void insert_into_prio_list(struct b2r2_core_job *job);
+static struct b2r2_core_job *find_job_in_list(
+ int job_id,
+ struct list_head *list);
+static struct b2r2_core_job *find_job_in_active_jobs(int job_id);
+static struct b2r2_core_job *find_tag_in_list(
+ int tag,
+ struct list_head *list);
+static struct b2r2_core_job *find_tag_in_active_jobs(int tag);
+static void clock_off_timer_function(unsigned long arg);
+static void clock_enable(void);
+static void clock_disable(void);
+static void turn_on_clock(void);
+static void turn_off_clock(void);
+static void stop_queue(enum b2r2_core_queue queue);
+
+#ifdef HANDLE_TIMEOUTED_JOBS
+static void printk_regs(void);
+static int hw_reset(void);
+static void timeout_work_function(struct work_struct *ptr);
+#endif
+
+static void reset_hw_timer(struct b2r2_core_job *job);
+static void start_hw_timer(struct b2r2_core_job *job);
+static void stop_hw_timer(struct b2r2_core_job *job);
+
+
+/* Tracking release bug... */
+#ifdef DEBUG_CHECK_ADDREF_RELEASE
+/**
+ * ar_add() - Adds an addref or a release to the array
+ *
+ * @job: The job that has been referenced
+ * @caller: The caller of addref / release
+ * @addref: true if it is an addref else false for release
+ */
+void ar_add(struct b2r2_core_job *job, const char *caller, bool addref)
+{
+ b2r2_core.ar[b2r2_core.ar_write].addref = addref;
+ b2r2_core.ar[b2r2_core.ar_write].job = job;
+ b2r2_core.ar[b2r2_core.ar_write].caller = caller;
+ b2r2_core.ar[b2r2_core.ar_write].ref_count = job->ref_count;
+ b2r2_core.ar_write = (b2r2_core.ar_write + 1) %
+ ARRAY_SIZE(b2r2_core.ar);
+ if (b2r2_core.ar_write == b2r2_core.ar_read)
+ b2r2_core.ar_read = (b2r2_core.ar_read + 1) %
+ ARRAY_SIZE(b2r2_core.ar);
+}
+
+/**
+ * sprintf_ar() - Writes all addref / release to a string buffer
+ *
+ * @buf: Receiving character bufefr
+ * @job: Which job to write or NULL for all
+ *
+ * NOTE! No buffer size check!!
+ */
+char *sprintf_ar(char *buf, struct b2r2_core_job *job)
+{
+ int i;
+ int size = 0;
+
+ for (i = b2r2_core.ar_read;
+ i != b2r2_core.ar_write;
+ i = (i + 1) % ARRAY_SIZE(b2r2_core.ar)) {
+ struct addref_release *ar = &b2r2_core.ar[i];
+ if (!job || job == ar->job)
+ size += sprintf(buf + size,
+ "%s on %p from %s, ref = %d\n",
+ ar->addref ? "addref" : "release",
+ ar->job, ar->caller, ar->ref_count);
+ }
+
+ return buf;
+}
+
+/**
+ * printk_ar() - Writes all addref / release using dev_info
+ *
+ * @job: Which job to write or NULL for all
+ */
+void printk_ar(struct b2r2_core_job *job)
+{
+ int i;
+
+ for (i = b2r2_core.ar_read;
+ i != b2r2_core.ar_write;
+ i = (i + 1) % ARRAY_SIZE(b2r2_core.ar)) {
+ struct addref_release *ar = &b2r2_core.ar[i];
+ if (!job || job == ar->job)
+ b2r2_log_info("%s on %p from %s,"
+ " ref = %d\n",
+ ar->addref ? "addref" : "release",
+ ar->job, ar->caller, ar->ref_count);
+ }
+}
+#endif
+
+/**
+ * internal_job_addref() - Increments the reference count for a job
+ *
+ * @job: Which job to increment reference count for
+ * @caller: Name of function calling addref (for debug)
+ *
+ * Note that b2r2_core.lock _must_ be held
+ */
+static void internal_job_addref(struct b2r2_core_job *job, const char *caller)
+{
+ u32 ref_count;
+
+ b2r2_log_info("%s (%p) (from %s)\n",
+ __func__, job, caller);
+
+ /* Sanity checks */
+ BUG_ON(job == NULL);
+
+ if (job->start_sentinel != START_SENTINEL ||
+ job->end_sentinel != END_SENTINEL ||
+ job->ref_count == 0 || job->ref_count > 10) {
+ b2r2_log_info(
+ "%s: (%p) start=%X end=%X ref_count=%d\n",
+ __func__, job, job->start_sentinel,
+ job->end_sentinel, job->ref_count);
+
+ /* Something is wrong, print the addref / release array */
+#ifdef DEBUG_CHECK_ADDREF_RELEASE
+ printk_ar(NULL);
+#endif
+ }
+
+
+ BUG_ON(job->start_sentinel != START_SENTINEL);
+ BUG_ON(job->end_sentinel != END_SENTINEL);
+
+ /* Do the actual reference count increment */
+ ref_count = ++job->ref_count;
+
+#ifdef DEBUG_CHECK_ADDREF_RELEASE
+ /* Keep track of addref / release */
+ ar_add(job, caller, true);
+#endif
+
+ b2r2_log_info("%s called from %s (%p): Ref Count is %d\n",
+ __func__, caller, job, job->ref_count);
+}
+
+/**
+ * internal_job_release() - Decrements the reference count for a job
+ *
+ * @job: Which job to decrement reference count for
+ * @caller: Name of function calling release (for debug)
+ *
+ * Returns true if job_release should be called by caller
+ * (reference count reached zero).
+ *
+ * Note that b2r2_core.lock _must_ be held
+ */
+bool internal_job_release(struct b2r2_core_job *job, const char *caller)
+{
+ u32 ref_count;
+ bool call_release = false;
+
+ b2r2_log_info("%s (%p) (from %s)\n",
+ __func__, job, caller);
+
+ /* Sanity checks */
+ BUG_ON(job == NULL);
+
+ if (job->start_sentinel != START_SENTINEL ||
+ job->end_sentinel != END_SENTINEL ||
+ job->ref_count == 0 || job->ref_count > 10) {
+ b2r2_log_info(
+ "%s: (%p) start=%X end=%X ref_count=%d\n",
+ __func__, job, job->start_sentinel,
+ job->end_sentinel, job->ref_count);
+
+#ifdef DEBUG_CHECK_ADDREF_RELEASE
+ printk_ar(NULL);
+#endif
+ }
+
+
+ BUG_ON(job->start_sentinel != START_SENTINEL);
+ BUG_ON(job->end_sentinel != END_SENTINEL);
+
+ BUG_ON(job->ref_count == 0 || job->ref_count > 10);
+
+ /* Do the actual decrement */
+ ref_count = --job->ref_count;
+#ifdef DEBUG_CHECK_ADDREF_RELEASE
+ ar_add(job, caller, false);
+#endif
+ b2r2_log_info("%s called from %s (%p) Ref Count is %d\n",
+ __func__, caller, job, ref_count);
+
+ if (!ref_count && job->release) {
+ call_release = true;
+ /* Job will now cease to exist */
+ job->start_sentinel = 0xFFFFFFFF;
+ job->end_sentinel = 0xFFFFFFFF;
+ }
+ return call_release;
+}
+
+
+
+/* Exported functions */
+
+/* b2r2_core.lock _must_ _NOT_ be held when calling this function */
+void b2r2_core_job_addref(struct b2r2_core_job *job, const char *caller)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+ internal_job_addref(job, caller);
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+}
+
+/* b2r2_core.lock _must_ _NOT_ be held when calling this function */
+void b2r2_core_job_release(struct b2r2_core_job *job, const char *caller)
+{
+ unsigned long flags;
+ bool call_release = false;
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+ call_release = internal_job_release(job, caller);
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+
+ if (call_release)
+ job->release(job);
+}
+
+/* b2r2_core.lock _must_ _NOT_ be held when calling this function */
+int b2r2_core_job_add(struct b2r2_core_job *job)
+{
+ unsigned long flags;
+
+ b2r2_log_info("%s (%p)\n", __func__, job);
+
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+ b2r2_core.stat_n_jobs_added++;
+
+ /* Initialise internal job data */
+ init_job(job);
+
+ /* Initial reference, should be released by caller of this function */
+ job->ref_count = 1;
+
+ /* Insert job into prio list */
+ insert_into_prio_list(job);
+
+ /* Check if we can dispatch job */
+ check_prio_list(false);
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+
+ return 0;
+}
+
+/* b2r2_core.lock _must_ _NOT_ be held when calling this function */
+struct b2r2_core_job *b2r2_core_job_find(int job_id)
+{
+ unsigned long flags;
+ struct b2r2_core_job *job;
+
+ b2r2_log_info("%s (%d)\n", __func__, job_id);
+
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+ /* Look through prio queue */
+ job = find_job_in_list(job_id, &b2r2_core.prio_queue);
+
+ if (!job)
+ job = find_job_in_active_jobs(job_id);
+
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+
+ return job;
+}
+
+/* b2r2_core.lock _must_ _NOT_ be held when calling this function */
+struct b2r2_core_job *b2r2_core_job_find_first_with_tag(int tag)
+{
+ unsigned long flags;
+ struct b2r2_core_job *job;
+
+ b2r2_log_info("%s (%d)\n", __func__, tag);
+
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+ /* Look through prio queue */
+ job = find_tag_in_list(tag, &b2r2_core.prio_queue);
+
+ if (!job)
+ job = find_tag_in_active_jobs(tag);
+
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+
+ return job;
+}
+
+/**
+ * is_job_done() - Spin lock protected check if job is done
+ *
+ * @job: Job to check
+ *
+ * Returns true if job is done or cancelled
+ *
+ * b2r2_core.lock must _NOT_ be held when calling this function
+ */
+static bool is_job_done(struct b2r2_core_job *job)
+{
+ unsigned long flags;
+ bool job_is_done;
+
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+ job_is_done =
+ job->job_state != B2R2_CORE_JOB_QUEUED &&
+ job->job_state != B2R2_CORE_JOB_RUNNING;
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+
+ return job_is_done;
+}
+
+/* b2r2_core.lock _must_ _NOT_ be held when calling this function */
+int b2r2_core_job_wait(struct b2r2_core_job *job)
+{
+ int ret = 0;
+
+ b2r2_log_info("%s (%p)\n", __func__, job);
+ /* Check that we have the job */
+ if (job->job_state == B2R2_CORE_JOB_IDLE) {
+ /* Never or not queued */
+ b2r2_log_info("%s: Job not queued\n", __func__);
+ return -ENOENT;
+ }
+
+ /* Wait for the job to be done */
+ ret = wait_event_interruptible(
+ job->event,
+ is_job_done(job));
+
+ if (ret)
+ b2r2_log_warn(
+ "%s: wait_event_interruptible returns %d, state is %d",
+ __func__, ret, job->job_state);
+ return ret;
+}
+
+/**
+ * cancel_job() - Cancels a job (removes it from prio list or active jobs) and
+ * calls the job callback
+ *
+ * @job: Job to cancel
+ *
+ * Returns true if the job was found and cancelled
+ *
+ * b2r2_core.lock must be held when calling this function
+ */
+static bool cancel_job(struct b2r2_core_job *job)
+{
+ bool found_job = false;
+ bool job_was_active = false;
+
+ /* Remove from prio list */
+ if (job->job_state == B2R2_CORE_JOB_QUEUED) {
+ list_del_init(&job->list);
+ found_job = true;
+ }
+
+ /* Remove from active jobs */
+ if (!found_job) {
+ if (b2r2_core.n_active_jobs > 0) {
+ int i;
+
+ /* Look for timeout:ed jobs and put them in tmp list */
+ for (i = 0;
+ i < ARRAY_SIZE(b2r2_core.active_jobs);
+ i++) {
+ if (b2r2_core.active_jobs[i] == job) {
+ stop_queue((enum b2r2_core_queue)i);
+ stop_hw_timer(job);
+ b2r2_core.active_jobs[i] = NULL;
+ b2r2_core.n_active_jobs--;
+ clock_disable();
+ found_job = true;
+ job_was_active = true;
+ }
+ }
+ }
+ }
+
+
+ /* Handle done list & callback */
+ if (found_job) {
+ /* Job is canceled */
+ job->job_state = B2R2_CORE_JOB_CANCELED;
+
+ queue_work(b2r2_core.work_queue, &job->work);
+
+ /* Statistics */
+ if (!job_was_active)
+ b2r2_core.stat_n_jobs_in_prio_list--;
+
+ }
+
+ return found_job;
+}
+
+/* b2r2_core.lock _must_ _NOT_ be held when calling this function */
+int b2r2_core_job_cancel(struct b2r2_core_job *job)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ b2r2_log_info("%s (%p) (%d)\n", __func__,
+ job, job->job_state);
+ /* Check that we have the job */
+ if (job->job_state == B2R2_CORE_JOB_IDLE) {
+ /* Never or not queued */
+ b2r2_log_info("%s: Job not queued\n", __func__);
+ return -ENOENT;
+ }
+
+ /* Remove from prio list */
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+ cancel_job(job);
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+
+ return ret;
+}
+
+/* LOCAL FUNCTIONS BELOW */
+
+static void turn_on_clock(void)
+{
+ if (!b2r2_core.b2r2_clock_on) {
+ clk_enable(b2r2_core.b2r2_clock);
+ b2r2_core.b2r2_clock_on = true;
+ }
+}
+
+static void turn_off_clock(void)
+{
+ if (b2r2_core.b2r2_clock_on) {
+ clk_disable(b2r2_core.b2r2_clock);
+ b2r2_core.b2r2_clock_on = false;
+ }
+}
+
+ /**
+ * clock_off_timer_function() - Checks if the B2R2 clock should be turned off
+ *
+ * @arg: Timer function argument (not used)
+ */
+static void clock_off_timer_function(unsigned long arg)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+ if (b2r2_core.clock_request_count == 0) {
+ unsigned long j = jiffies;
+#ifndef B2R2_CLOCK_ALWAYS_ON
+ if (time_after_eq(j, b2r2_core.clock_off_timer.expires)) {
+ turn_off_clock();
+ b2r2_log_debug("B2R2 disable clock: disable b2r2 = %X\n",
+ (int)b2r2_core.b2r2_clock);
+ }
+#endif
+ }
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+}
+
+
+
+
+/**
+ * clock_enable() - Turns on the B2R2 clock.
+ *
+ * b2r2_core.lock must be held
+ *
+ * The clock is reference counted. When reference count goes from
+ * 0 to 1, the HW clock is turned on.
+ */
+static void clock_enable(void)
+{
+ b2r2_core.clock_request_count++;
+ if (b2r2_core.clock_request_count == 1) {
+ turn_on_clock();
+ b2r2_log_info("core: enable clock: enable b2r2 = %X\n",
+ (int)b2r2_core.b2r2_clock);
+ }
+}
+
+
+/**
+ * clock_disable() - Turns off the B2R2 clock.
+ *
+ * b2r2_core.lock must be held
+ *
+ * The clock is reference counted. When reference count goes from
+ * 1 to 0, the HW clock is turned off (via a delay timer).
+ */
+static void clock_disable(void)
+{
+ BUG_ON(b2r2_core.clock_request_count == 0);
+ b2r2_core.clock_request_count--;
+
+ if (b2r2_core.clock_request_count == 0) {
+ /* Delayed clock turn off
+ (10 ms but at least 2 jiffie increments) */
+ mod_timer(&b2r2_core.clock_off_timer,
+ jiffies + min(HZ / 100, 2));
+ }
+}
+
+/**
+ * stop_queue() - Stops the specified queue.
+ */
+static void stop_queue(enum b2r2_core_queue queue)
+{
+ /* TODO: Implement! If this function is not implemented canceled jobs will
+ use b2r2 which is a waste of resources. Not stopping jobs will also screw up
+ the hardware timing, the job the canceled job intrerrupted (if any) will be
+ billed for the time between the point where the job is cancelled and when it
+ stops. */
+}
+
+/**
+ * exit_job_list() - Empties a job queue by canceling the jobs
+ *
+ * b2r2_core.lock _must_ be held when calling this function
+ */
+static void exit_job_list(struct list_head *job_queue)
+{
+ while (!list_empty(job_queue)) {
+ struct b2r2_core_job *job =
+ list_entry(job_queue->next,
+ struct b2r2_core_job,
+ list);
+ /* Add reference to prevent job from disappearing
+ in the middle of our work, released below */
+ internal_job_addref(job, __func__);
+
+ cancel_job(job);
+
+ /* Matching release to addref above */
+ internal_job_release(job, __func__);
+
+ }
+}
+
+/**
+ * get_next_job_id() - Return a new job id.
+ */
+static int get_next_job_id(void)
+{
+ int job_id;
+
+ if (b2r2_core.next_job_id < 1)
+ b2r2_core.next_job_id = 1;
+ job_id = b2r2_core.next_job_id++;
+
+ return job_id;
+}
+
+/**
+ * job_work_function() - Work queue function that calls callback(s) and
+ * checks if B2R2 can accept a new job
+ *
+ * @ptr: Pointer to work struct (embedded in struct b2r2_core_job)
+ */
+static void job_work_function(struct work_struct *ptr)
+{
+ unsigned long flags;
+ struct b2r2_core_job *job = container_of(
+ ptr, struct b2r2_core_job, work);
+
+ /* Release resources */
+ if (job->release_resources)
+ job->release_resources(job, false);
+
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+
+ /* Dispatch a new job if possible */
+ check_prio_list(false);
+
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+
+ /* Tell the client */
+ if (job->callback)
+ job->callback(job);
+
+ /* Drop our reference, matches the
+ addref in handle_queue_event or b2r2_core_job_cancel */
+ b2r2_core_job_release(job, __func__);
+}
+
+#ifdef HANDLE_TIMEOUTED_JOBS
+/**
+ * timeout_work_function() - Work queue function that checks for
+ * timeout:ed jobs. B2R2 might silently refuse
+ * to execute some jobs, i.e. SRC2 fill
+ *
+ * @ptr: Pointer to work struct (embedded in struct b2r2_core)
+ *
+ */
+static void timeout_work_function(struct work_struct *ptr)
+{
+ unsigned long flags;
+ struct list_head job_list;
+
+ INIT_LIST_HEAD(&job_list);
+
+ /* Cancel all jobs if too long time since last irq */
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+ if (b2r2_core.n_active_jobs > 0) {
+ unsigned long diff =
+ (long) jiffies - (long) b2r2_core.jiffies_last_irq;
+ if (diff > HZ/2) {
+ /* Active jobs and more than a second since last irq! */
+ int i;
+
+ /* Look for timeout:ed jobs and put them in tmp list. It's
+ important that the application queues are killed in order
+ of decreasing priority */
+ for (i = 0;
+ i < ARRAY_SIZE(b2r2_core.active_jobs);
+ i++) {
+ struct b2r2_core_job *job =
+ b2r2_core.active_jobs[i];
+
+ if (job) {
+ stop_hw_timer(job);
+
+ b2r2_core.active_jobs[i] = NULL;
+ b2r2_core.n_active_jobs--;
+ clock_disable();
+ list_add_tail(&job->list,
+ &job_list);
+ }
+ }
+
+ /* Print the B2R2 register and reset B2R2 */
+ printk_regs();
+ hw_reset();
+ }
+ }
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+
+ /* Handle timeout:ed jobs */
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+ while (!list_empty(&job_list)) {
+ struct b2r2_core_job *job =
+ list_entry(job_list.next,
+ struct b2r2_core_job,
+ list);
+
+ b2r2_log_warn("%s: Job timeout\n", __func__);
+
+ list_del_init(&job->list);
+
+ /* Job is cancelled */
+ job->job_state = B2R2_CORE_JOB_CANCELED;
+
+ /* Handle done */
+ wake_up_interruptible(&job->event);
+
+ /* Job callbacks handled via work queue */
+ queue_work(b2r2_core.work_queue, &job->work);
+ }
+
+ /* Requeue delayed work */
+ if (b2r2_core.n_active_jobs)
+ queue_delayed_work(
+ b2r2_core.work_queue,
+ &b2r2_core.timeout_work, HZ/2);
+
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+}
+#endif
+
+/**
+ * reset_hw_timer() - Resets a job's hardware timer. Must be called before
+ * the timer is used.
+ *
+ * @job: Pointer to job struct
+ *
+ * b2r2_core.lock _must_ be held when calling this function
+ */
+static void reset_hw_timer(struct b2r2_core_job *job)
+{
+ job->nsec_active_in_hw = 0;
+}
+
+/**
+ * start_hw_timer() - Times how long a job spends in hardware (active).
+ * Should be called immediatly before starting the
+ * hardware.
+ *
+ * @job: Pointer to job struct
+ *
+ * b2r2_core.lock _must_ be held when calling this function
+ */
+static void start_hw_timer(struct b2r2_core_job *job)
+{
+ job->hw_start_time = b2r2_get_curr_nsec();
+}
+
+/**
+ * stop_hw_timer() - Times how long a job spends in hardware (active).
+ * Should be called immediatly after the hardware has
+ * finished.
+ *
+ * @job: Pointer to job struct
+ *
+ * b2r2_core.lock _must_ be held when calling this function
+ */
+static void stop_hw_timer(struct b2r2_core_job *job)
+{
+ /* Assumes only app queues are used, which is the case right now. */
+ /* Not 100% accurate. When a higher prio job interrupts a lower prio job it does
+ so after the current node of the low prio job has finished. Currently we can not
+ sense when the actual switch takes place so the time reported for a job that
+ interrupts a lower prio job will on average contain the time it takes to process
+ half a node in the lower prio job in addition to the time it takes to process the
+ job's own nodes. This could possibly be solved by adding node notifications but
+ that would involve a significant amount of work and consume system resources due
+ to the extra interrupts. */
+ /* If a job takes more than ~2s (absolute time, including idleing in the hardware)
+ the state of the hardware timer will be corrupted and it will not report valid
+ values until b2r2 becomes idle (no active jobs on any queues). The maximum length
+ can possibly be increased by using 64 bit integers. */
+
+ int i;
+
+ u32 stop_time_raw = b2r2_get_curr_nsec();
+ /* We'll add an offset to all positions in time to make the current time equal to
+ 0xFFFFFFFF. This way we can compare positions in time to each other without having
+ to wory about wrapping (so long as all positions in time are in the past). */
+ u32 stop_time = 0xFFFFFFFF;
+ u32 time_pos_offset = 0xFFFFFFFF - stop_time_raw;
+ u32 nsec_in_hw = stop_time - (job->hw_start_time + time_pos_offset);
+ job->nsec_active_in_hw += (s32)nsec_in_hw;
+
+ /* Check if we have delayed the start of higher prio jobs. Can happen as queue
+ switching only can be done between nodes. */
+ for (i = (int)job->queue - 1; i >= (int)B2R2_CORE_QUEUE_AQ1; i--) {
+ struct b2r2_core_job *queue_active_job = b2r2_core.active_jobs[i];
+ if (NULL == queue_active_job)
+ continue;
+
+ queue_active_job->hw_start_time = stop_time_raw;
+ }
+
+ /* Check if the job has stolen time from lower prio jobs */
+ for (i = (int)job->queue + 1; i < B2R2_NUM_APPLICATIONS_QUEUES; i++) {
+ struct b2r2_core_job *queue_active_job = b2r2_core.active_jobs[i];
+ u32 queue_active_job_hw_start_time;
+
+ if (NULL == queue_active_job)
+ continue;
+
+ queue_active_job_hw_start_time = queue_active_job->hw_start_time + time_pos_offset;
+
+ if (queue_active_job_hw_start_time < stop_time) {
+ u32 queue_active_job_nsec_in_hw = stop_time - queue_active_job_hw_start_time;
+ u32 num_stolen_nsec = min(queue_active_job_nsec_in_hw, nsec_in_hw);
+
+ queue_active_job->nsec_active_in_hw -= (s32)num_stolen_nsec;
+
+ nsec_in_hw -= num_stolen_nsec;
+ stop_time -= num_stolen_nsec;
+ }
+
+ if (0 == nsec_in_hw)
+ break;
+ }
+}
+
+/**
+ * init_job() - Initializes a job structure from filled in client data.
+ * Reference count will be set to 1
+ *
+ * @job: Job to initialize
+ */
+static void init_job(struct b2r2_core_job *job)
+{
+ job->start_sentinel = START_SENTINEL;
+ job->end_sentinel = END_SENTINEL;
+
+ /* Get a job id*/
+ job->job_id = get_next_job_id();
+
+ /* Job is idle, never queued */
+ job->job_state = B2R2_CORE_JOB_IDLE;
+
+ /* Initialize internal data */
+ INIT_LIST_HEAD(&job->list);
+ init_waitqueue_head(&job->event);
+ INIT_WORK(&job->work, job_work_function);
+
+ /* Map given prio to B2R2 queues */
+ if (job->prio < B2R2_CORE_LOWEST_PRIO)
+ job->prio = B2R2_CORE_LOWEST_PRIO;
+ else if (job->prio > B2R2_CORE_HIGHEST_PRIO)
+ job->prio = B2R2_CORE_HIGHEST_PRIO;
+
+ if (job->prio > 10) {
+ job->queue = B2R2_CORE_QUEUE_AQ1;
+ job->interrupt_context =
+ (B2R2BLT_ITSAQ1_LNA_Reached);
+ job->control = (B2R2_AQ_Enab | B2R2_AQ_PRIOR_3);
+ } else if (job->prio > 0) {
+ job->queue = B2R2_CORE_QUEUE_AQ2;
+ job->interrupt_context =
+ (B2R2BLT_ITSAQ2_LNA_Reached);
+ job->control = (B2R2_AQ_Enab | B2R2_AQ_PRIOR_2);
+ } else if (job->prio > -10) {
+ job->queue = B2R2_CORE_QUEUE_AQ3;
+ job->interrupt_context =
+ (B2R2BLT_ITSAQ3_LNA_Reached);
+ job->control = (B2R2_AQ_Enab | B2R2_AQ_PRIOR_1);
+ } else {
+ job->queue = B2R2_CORE_QUEUE_AQ4;
+ job->interrupt_context =
+ (B2R2BLT_ITSAQ4_LNA_Reached);
+ job->control = (B2R2_AQ_Enab | B2R2_AQ_PRIOR_0);
+ }
+}
+
+/**
+ * clear_interrupts() - Disables all interrupts
+ *
+ * b2r2_core.lock must be held
+ */
+static void clear_interrupts(void)
+{
+ writel(0x0, &b2r2_core.hw->BLT_ITM0);
+ writel(0x0, &b2r2_core.hw->BLT_ITM1);
+ writel(0x0, &b2r2_core.hw->BLT_ITM2);
+ writel(0x0, &b2r2_core.hw->BLT_ITM3);
+}
+
+/**
+ * insert_into_prio_list() - Inserts the job into the sorted list of jobs.
+ * The list is sorted by priority.
+ *
+ * @job: Job to insert
+ *
+ * b2r2_core.lock must be held
+ */
+static void insert_into_prio_list(struct b2r2_core_job *job)
+{
+ /* Ref count is increased when job put in list,
+ should be released when job is removed from list */
+ internal_job_addref(job, __func__);
+
+ b2r2_core.stat_n_jobs_in_prio_list++;
+
+ /* Sort in the job */
+ if (list_empty(&b2r2_core.prio_queue))
+ list_add_tail(&job->list, &b2r2_core.prio_queue);
+ else {
+ struct b2r2_core_job *first_job =
+ list_entry(b2r2_core.prio_queue.next,
+ struct b2r2_core_job, list);
+ struct b2r2_core_job *last_job =
+ list_entry(b2r2_core.prio_queue.prev,
+ struct b2r2_core_job, list);
+
+ /* High prio job? */
+ if (job->prio > first_job->prio)
+ /* Insert first */
+ list_add(&job->list, &b2r2_core.prio_queue);
+ else if (job->prio <= last_job->prio)
+ /* Insert last */
+ list_add_tail(&job->list, &b2r2_core.prio_queue);
+ else {
+ /* We need to find where to put it */
+ struct list_head *ptr;
+
+ list_for_each(ptr, &b2r2_core.prio_queue) {
+ struct b2r2_core_job *list_job =
+ list_entry(ptr, struct b2r2_core_job,
+ list);
+ if (job->prio > list_job->prio) {
+ /* Add before */
+ list_add_tail(&job->list,
+ &list_job->list);
+ break;
+ }
+ }
+ }
+ }
+ /* The job is now queued */
+ job->job_state = B2R2_CORE_JOB_QUEUED;
+}
+
+/**
+ * check_prio_list() - Checks if the first job(s) in the prio list can
+ * be dispatched to B2R2
+ *
+ * @atomic: true if in atomic context (i.e. interrupt context)
+ *
+ * b2r2_core.lock must be held
+ */
+static void check_prio_list(bool atomic)
+{
+ bool dispatched_job;
+ int n_dispatched = 0;
+
+ /* Do we have anything in our prio list? */
+ do {
+ dispatched_job = false;
+ if (!list_empty(&b2r2_core.prio_queue)) {
+ /* The first job waiting */
+ struct b2r2_core_job *job =
+ list_first_entry(&b2r2_core.prio_queue,
+ struct b2r2_core_job,
+ list);
+
+ /* Is the B2R2 queue available? */
+ if (b2r2_core.active_jobs[job->queue] == NULL) {
+ /* Can we acquire resources? */
+ if (!job->acquire_resources ||
+ job->acquire_resources(job, atomic) == 0) {
+ /* Ok to dispatch job */
+
+ /* Remove from list */
+ list_del_init(&job->list);
+
+ /* The job is now active */
+ b2r2_core.active_jobs[job->queue] = job;
+ b2r2_core.n_active_jobs++;
+ clock_enable();
+ job->jiffies = jiffies;
+ b2r2_core.jiffies_last_active =
+ jiffies;
+
+ /* Kick off B2R2 */
+ trigger_job(job);
+
+ dispatched_job = true;
+ n_dispatched++;
+
+#ifdef HANDLE_TIMEOUTED_JOBS
+ /* Check in one half second
+ if it hangs */
+ queue_delayed_work(
+ b2r2_core.work_queue,
+ &b2r2_core.timeout_work,
+ HZ/2);
+#endif
+ } else {
+ /* No resources */
+ if (!atomic &&
+ b2r2_core.n_active_jobs == 0) {
+ b2r2_log_warn(
+ "%s: No resource",
+ __func__);
+ cancel_job(job);
+ }
+ }
+ }
+ }
+ } while (dispatched_job);
+
+ b2r2_core.stat_n_jobs_in_prio_list -= n_dispatched;
+}
+
+/**
+ * find_job_in_list() - Finds job with job_id in list
+ *
+ * @jobid: Job id to find
+ * @list: List to find job id in
+ *
+ * Reference count will be incremented for found job.
+ *
+ * b2r2_core.lock must be held
+ */
+static struct b2r2_core_job *find_job_in_list(int job_id,
+ struct list_head *list)
+{
+ struct list_head *ptr;
+
+ list_for_each(ptr, list) {
+ struct b2r2_core_job *job =
+ list_entry(ptr, struct b2r2_core_job, list);
+ if (job->job_id == job_id) {
+ /* Increase reference count, should be released by
+ the caller of b2r2_core_job_find */
+ internal_job_addref(job, __func__);
+ return job;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * find_job_in_active_jobs() - Finds job in active job queues
+ *
+ * @jobid: Job id to find
+ *
+ * Reference count will be incremented for found job.
+ *
+ * b2r2_core.lock must be held
+ */
+static struct b2r2_core_job *find_job_in_active_jobs(int job_id)
+{
+ int i;
+ struct b2r2_core_job *found_job = NULL;
+
+ if (b2r2_core.n_active_jobs) {
+ for (i = 0; i < ARRAY_SIZE(b2r2_core.active_jobs); i++) {
+ struct b2r2_core_job *job = b2r2_core.active_jobs[i];
+
+ if (job && job->job_id == job_id) {
+ internal_job_addref(job, __func__);
+ found_job = job;
+ break;
+ }
+ }
+ }
+ return found_job;
+}
+
+/**
+ * find_tag_in_list() - Finds first job with tag in list
+ *
+ * @tag: Tag to find
+ * @list: List to find job id in
+ *
+ * Reference count will be incremented for found job.
+ *
+ * b2r2_core.lock must be held
+ */
+static struct b2r2_core_job *find_tag_in_list(int tag, struct list_head *list)
+{
+ struct list_head *ptr;
+
+ list_for_each(ptr, list) {
+ struct b2r2_core_job *job =
+ list_entry(ptr, struct b2r2_core_job, list);
+ if (job->tag == tag) {
+ /* Increase reference count, should be released by
+ the caller of b2r2_core_job_find */
+ internal_job_addref(job, __func__);
+ return job;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * find_tag_in_active_jobs() - Finds job with tag in active job queues
+ *
+ * @tag: Tag to find
+ *
+ * Reference count will be incremented for found job.
+ *
+ * b2r2_core.lock must be held
+ */
+static struct b2r2_core_job *find_tag_in_active_jobs(int tag)
+{
+ int i;
+ struct b2r2_core_job *found_job = NULL;
+
+ if (b2r2_core.n_active_jobs) {
+ for (i = 0; i < ARRAY_SIZE(b2r2_core.active_jobs); i++) {
+ struct b2r2_core_job *job = b2r2_core.active_jobs[i];
+
+ if (job && job->tag == tag) {
+ internal_job_addref(job, __func__);
+ found_job = job;
+ break;
+ }
+ }
+ }
+ return found_job;
+}
+
+
+#ifdef HANDLE_TIMEOUTED_JOBS
+/**
+ * hw_reset() - Resets B2R2 hardware
+ *
+ * b2r2_core.lock must be held
+ */
+static int hw_reset(void)
+{
+ u32 uTimeOut = B2R2_DRIVER_TIMEOUT_VALUE;
+ clock_enable();
+
+ /* Tell B2R2 to reset */
+ writel(readl(&b2r2_core.hw->BLT_CTL) | B2R2BLT_CTLGLOBAL_soft_reset,
+ &b2r2_core.hw->BLT_CTL);
+ writel(0x00000000, &b2r2_core.hw->BLT_CTL);
+
+ b2r2_log_info("wait for B2R2 to be idle..\n");
+
+ /** Wait for B2R2 to be idle (on a timeout rather than while loop) */
+ while ((uTimeOut > 0) &&
+ ((readl(&b2r2_core.hw->BLT_STA1) &
+ B2R2BLT_STA1BDISP_IDLE) == 0x0))
+ uTimeOut--;
+
+ clock_disable();
+
+ if (uTimeOut == 0) {
+ b2r2_log_warn(
+ "error-> after software reset B2R2 is not idle\n");
+ return -EAGAIN;
+ }
+
+ return 0;
+
+}
+#endif
+
+/**
+ * trigger_job() - Put job in B2R2 HW queue
+ *
+ * @job: Job to trigger
+ *
+ * b2r2_core.lock must be held
+ */
+static void trigger_job(struct b2r2_core_job *job)
+{
+ /* Debug prints */
+ b2r2_log_info("queue 0x%x \n", job->queue);
+ b2r2_log_info("BLT TRIG_IP 0x%x (first node)\n",
+ job->first_node_address);
+ b2r2_log_info("BLT LNA_CTL 0x%x (last node)\n",
+ job->last_node_address);
+ b2r2_log_info("BLT TRIG_CTL 0x%x \n", job->control);
+ b2r2_log_info("BLT PACE_CTL 0x%x \n", job->pace_control);
+
+ reset_hw_timer(job);
+ job->job_state = B2R2_CORE_JOB_RUNNING;
+
+ /* Enable interrupt */
+ writel(readl(&b2r2_core.hw->BLT_ITM0) | job->interrupt_context,
+ &b2r2_core.hw->BLT_ITM0);
+
+ /* B2R2 kicks off when LNA is written, LNA write must be last! */
+ switch (job->queue) {
+ case B2R2_CORE_QUEUE_CQ1:
+ writel(job->first_node_address, &b2r2_core.hw->BLT_CQ1_TRIG_IP);
+ writel(job->control, &b2r2_core.hw->BLT_CQ1_TRIG_CTL);
+ writel(job->pace_control, &b2r2_core.hw->BLT_CQ1_PACE_CTL);
+ break;
+
+ case B2R2_CORE_QUEUE_CQ2:
+ writel(job->first_node_address, &b2r2_core.hw->BLT_CQ2_TRIG_IP);
+ writel(job->control, &b2r2_core.hw->BLT_CQ2_TRIG_CTL);
+ writel(job->pace_control, &b2r2_core.hw->BLT_CQ2_PACE_CTL);
+ break;
+
+ case B2R2_CORE_QUEUE_AQ1:
+ writel(job->control, &b2r2_core.hw->BLT_AQ1_CTL);
+ writel(job->first_node_address, &b2r2_core.hw->BLT_AQ1_IP);
+ wmb();
+ start_hw_timer(job);
+ writel(job->last_node_address, &b2r2_core.hw->BLT_AQ1_LNA);
+ break;
+
+ case B2R2_CORE_QUEUE_AQ2:
+ writel(job->control, &b2r2_core.hw->BLT_AQ2_CTL);
+ writel(job->first_node_address, &b2r2_core.hw->BLT_AQ2_IP);
+ wmb();
+ start_hw_timer(job);
+ writel(job->last_node_address, &b2r2_core.hw->BLT_AQ2_LNA);
+ break;
+
+ case B2R2_CORE_QUEUE_AQ3:
+ writel(job->control, &b2r2_core.hw->BLT_AQ3_CTL);
+ writel(job->first_node_address, &b2r2_core.hw->BLT_AQ3_IP);
+ wmb();
+ start_hw_timer(job);
+ writel(job->last_node_address, &b2r2_core.hw->BLT_AQ3_LNA);
+ break;
+
+ case B2R2_CORE_QUEUE_AQ4:
+ writel(job->control, &b2r2_core.hw->BLT_AQ4_CTL);
+ writel(job->first_node_address, &b2r2_core.hw->BLT_AQ4_IP);
+ wmb();
+ start_hw_timer(job);
+ writel(job->last_node_address, &b2r2_core.hw->BLT_AQ4_LNA);
+ break;
+
+ /** Handle the default case */
+ default:
+ break;
+
+ } /* end switch */
+
+}
+
+/**
+ * handle_queue_event() - Handles interrupt event for specified B2R2 queue
+ *
+ * @queue: Queue to handle event for
+ *
+ * b2r2_core.lock must be held
+ */
+static void handle_queue_event(enum b2r2_core_queue queue)
+{
+ struct b2r2_core_job *job;
+
+ job = b2r2_core.active_jobs[queue];
+ if (job) {
+ if (job->job_state != B2R2_CORE_JOB_RUNNING)
+ /* Should be running
+ Severe error. TBD */
+ b2r2_log_warn(
+ "%s: Job is not running", __func__);
+
+ stop_hw_timer(job);
+
+ /* Remove from queue */
+ BUG_ON(b2r2_core.n_active_jobs == 0);
+ b2r2_core.active_jobs[queue] = NULL;
+ b2r2_core.n_active_jobs--;
+ }
+
+ if (!job) {
+ /* No job, error? */
+ b2r2_log_warn("%s: No job", __func__);
+ return;
+ }
+
+
+ clock_disable();
+
+ /* Atomic context release resources, release resources will
+ be called again later from process context (work queue) */
+ if (job->release_resources)
+ job->release_resources(job, true);
+
+ /* Job is done */
+ job->job_state = B2R2_CORE_JOB_DONE;
+
+ /* Handle done */
+ wake_up_interruptible(&job->event);
+
+ /* Dispatch to work queue to handle callbacks */
+ queue_work(b2r2_core.work_queue, &job->work);
+}
+
+/**
+ * process_events() - Handles interrupt events
+ *
+ * @status: Contents of the B2R2 ITS register
+ */
+static void process_events(u32 status)
+{
+ u32 mask = 0xF;
+ u32 disable_itm_mask = 0;
+
+ b2r2_log_info("Enters process_events \n");
+ b2r2_log_info("status 0x%x \n", status);
+
+ /* Composition queue 1 */
+ if (status & mask) {
+ handle_queue_event(B2R2_CORE_QUEUE_CQ1);
+ disable_itm_mask |= mask;
+ }
+ mask <<= 4;
+
+ /* Composition queue 2 */
+ if (status & mask) {
+ handle_queue_event(B2R2_CORE_QUEUE_CQ2);
+ disable_itm_mask |= mask;
+ }
+ mask <<= 8;
+
+ /* Application queue 1 */
+ if (status & mask) {
+ handle_queue_event(B2R2_CORE_QUEUE_AQ1);
+ disable_itm_mask |= mask;
+ }
+ mask <<= 4;
+
+ /* Application queue 2 */
+ if (status & mask) {
+ handle_queue_event(B2R2_CORE_QUEUE_AQ2);
+ disable_itm_mask |= mask;
+ }
+ mask <<= 4;
+
+ /* Application queue 3 */
+ if (status & mask) {
+ handle_queue_event(B2R2_CORE_QUEUE_AQ3);
+ disable_itm_mask |= mask;
+ }
+ mask <<= 4;
+
+ /* Application queue 4 */
+ if (status & mask) {
+ handle_queue_event(B2R2_CORE_QUEUE_AQ4);
+ disable_itm_mask |= mask;
+ }
+
+ /* Clear received interrupt flags */
+ writel(status, &b2r2_core.hw->BLT_ITS);
+ /* Disable handled interrupts */
+ writel(readl(&b2r2_core.hw->BLT_ITM0) & ~disable_itm_mask,
+ &b2r2_core.hw->BLT_ITM0);
+
+ b2r2_log_info("Returns process_events \n");
+}
+
+/**
+ * b2r2_irq_handler() - B2R2 interrupt handler
+ *
+ * @irq: Interrupt number (not used)
+ * @x: ??? (Not used)
+ */
+static irqreturn_t b2r2_irq_handler(int irq, void *x)
+{
+ unsigned long flags;
+
+ /* Spin lock is need in irq handler (SMP) */
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+
+ /* Make sure that we have a clock */
+ clock_enable();
+
+ /* Remember time for last irq (for timeout mgmt) */
+ b2r2_core.jiffies_last_irq = jiffies;
+ b2r2_core.stat_n_irq++;
+
+ /* Handle the interrupt(s) */
+ process_events(readl(&b2r2_core.hw->BLT_ITS));
+
+ /* Check if we can dispatch new jobs */
+ check_prio_list(true);
+
+ clock_disable();
+
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+
+#ifdef CONFIG_DEBUG_FS
+/**
+ * struct debugfs_reg - Represents one B2R2 register in debugfs
+ *
+ * @name: Register name
+ * @offset: Byte offset in B2R2 for register
+ */
+struct debugfs_reg {
+ const char name[30];
+ u32 offset;
+};
+
+/**
+ * debugfs_regs - Array of B2R2 debugfs registers
+ */
+static const struct debugfs_reg debugfs_regs[] = {
+ {"BLT_SSBA17", offsetof(struct b2r2_memory_map, BLT_SSBA17)},
+ {"BLT_SSBA18", offsetof(struct b2r2_memory_map, BLT_SSBA18)},
+ {"BLT_SSBA19", offsetof(struct b2r2_memory_map, BLT_SSBA19)},
+ {"BLT_SSBA20", offsetof(struct b2r2_memory_map, BLT_SSBA20)},
+ {"BLT_SSBA21", offsetof(struct b2r2_memory_map, BLT_SSBA21)},
+ {"BLT_SSBA22", offsetof(struct b2r2_memory_map, BLT_SSBA22)},
+ {"BLT_SSBA23", offsetof(struct b2r2_memory_map, BLT_SSBA23)},
+ {"BLT_SSBA24", offsetof(struct b2r2_memory_map, BLT_SSBA24)},
+ {"BLT_STBA5", offsetof(struct b2r2_memory_map, BLT_STBA5)},
+ {"BLT_STBA6", offsetof(struct b2r2_memory_map, BLT_STBA6)},
+ {"BLT_STBA7", offsetof(struct b2r2_memory_map, BLT_STBA7)},
+ {"BLT_STBA8", offsetof(struct b2r2_memory_map, BLT_STBA8)},
+ {"BLT_CTL", offsetof(struct b2r2_memory_map, BLT_CTL)},
+ {"BLT_ITS", offsetof(struct b2r2_memory_map, BLT_ITS)},
+ {"BLT_STA1", offsetof(struct b2r2_memory_map, BLT_STA1)},
+ {"BLT_SSBA1", offsetof(struct b2r2_memory_map, BLT_SSBA1)},
+ {"BLT_SSBA2", offsetof(struct b2r2_memory_map, BLT_SSBA2)},
+ {"BLT_SSBA3", offsetof(struct b2r2_memory_map, BLT_SSBA3)},
+ {"BLT_SSBA4", offsetof(struct b2r2_memory_map, BLT_SSBA4)},
+ {"BLT_SSBA5", offsetof(struct b2r2_memory_map, BLT_SSBA5)},
+ {"BLT_SSBA6", offsetof(struct b2r2_memory_map, BLT_SSBA6)},
+ {"BLT_SSBA7", offsetof(struct b2r2_memory_map, BLT_SSBA7)},
+ {"BLT_SSBA8", offsetof(struct b2r2_memory_map, BLT_SSBA8)},
+ {"BLT_STBA1", offsetof(struct b2r2_memory_map, BLT_STBA1)},
+ {"BLT_STBA2", offsetof(struct b2r2_memory_map, BLT_STBA2)},
+ {"BLT_STBA3", offsetof(struct b2r2_memory_map, BLT_STBA3)},
+ {"BLT_STBA4", offsetof(struct b2r2_memory_map, BLT_STBA4)},
+ {"BLT_CQ1_TRIG_IP", offsetof(struct b2r2_memory_map, BLT_CQ1_TRIG_IP)},
+ {"BLT_CQ1_TRIG_CTL", offsetof(struct b2r2_memory_map,
+ BLT_CQ1_TRIG_CTL)},
+ {"BLT_CQ1_PACE_CTL", offsetof(struct b2r2_memory_map,
+ BLT_CQ1_PACE_CTL)},
+ {"BLT_CQ1_IP", offsetof(struct b2r2_memory_map, BLT_CQ1_IP)},
+ {"BLT_CQ2_TRIG_IP", offsetof(struct b2r2_memory_map, BLT_CQ2_TRIG_IP)},
+ {"BLT_CQ2_TRIG_CTL", offsetof(struct b2r2_memory_map,
+ BLT_CQ2_TRIG_CTL)},
+ {"BLT_CQ2_PACE_CTL", offsetof(struct b2r2_memory_map,
+ BLT_CQ2_PACE_CTL)},
+ {"BLT_CQ2_IP", offsetof(struct b2r2_memory_map, BLT_CQ2_IP)},
+ {"BLT_AQ1_CTL", offsetof(struct b2r2_memory_map, BLT_AQ1_CTL)},
+ {"BLT_AQ1_IP", offsetof(struct b2r2_memory_map, BLT_AQ1_IP)},
+ {"BLT_AQ1_LNA", offsetof(struct b2r2_memory_map, BLT_AQ1_LNA)},
+ {"BLT_AQ1_STA", offsetof(struct b2r2_memory_map, BLT_AQ1_STA)},
+ {"BLT_AQ2_CTL", offsetof(struct b2r2_memory_map, BLT_AQ2_CTL)},
+ {"BLT_AQ2_IP", offsetof(struct b2r2_memory_map, BLT_AQ2_IP)},
+ {"BLT_AQ2_LNA", offsetof(struct b2r2_memory_map, BLT_AQ2_LNA)},
+ {"BLT_AQ2_STA", offsetof(struct b2r2_memory_map, BLT_AQ2_STA)},
+ {"BLT_AQ3_CTL", offsetof(struct b2r2_memory_map, BLT_AQ3_CTL)},
+ {"BLT_AQ3_IP", offsetof(struct b2r2_memory_map, BLT_AQ3_IP)},
+ {"BLT_AQ3_LNA", offsetof(struct b2r2_memory_map, BLT_AQ3_LNA)},
+ {"BLT_AQ3_STA", offsetof(struct b2r2_memory_map, BLT_AQ3_STA)},
+ {"BLT_AQ4_CTL", offsetof(struct b2r2_memory_map, BLT_AQ4_CTL)},
+ {"BLT_AQ4_IP", offsetof(struct b2r2_memory_map, BLT_AQ4_IP)},
+ {"BLT_AQ4_LNA", offsetof(struct b2r2_memory_map, BLT_AQ4_LNA)},
+ {"BLT_AQ4_STA", offsetof(struct b2r2_memory_map, BLT_AQ4_STA)},
+ {"BLT_SSBA9", offsetof(struct b2r2_memory_map, BLT_SSBA9)},
+ {"BLT_SSBA10", offsetof(struct b2r2_memory_map, BLT_SSBA10)},
+ {"BLT_SSBA11", offsetof(struct b2r2_memory_map, BLT_SSBA11)},
+ {"BLT_SSBA12", offsetof(struct b2r2_memory_map, BLT_SSBA12)},
+ {"BLT_SSBA13", offsetof(struct b2r2_memory_map, BLT_SSBA13)},
+ {"BLT_SSBA14", offsetof(struct b2r2_memory_map, BLT_SSBA14)},
+ {"BLT_SSBA15", offsetof(struct b2r2_memory_map, BLT_SSBA15)},
+ {"BLT_SSBA16", offsetof(struct b2r2_memory_map, BLT_SSBA16)},
+ {"BLT_SGA1", offsetof(struct b2r2_memory_map, BLT_SGA1)},
+ {"BLT_SGA2", offsetof(struct b2r2_memory_map, BLT_SGA2)},
+ {"BLT_ITM0", offsetof(struct b2r2_memory_map, BLT_ITM0)},
+ {"BLT_ITM1", offsetof(struct b2r2_memory_map, BLT_ITM1)},
+ {"BLT_ITM2", offsetof(struct b2r2_memory_map, BLT_ITM2)},
+ {"BLT_ITM3", offsetof(struct b2r2_memory_map, BLT_ITM3)},
+ {"BLT_DFV2", offsetof(struct b2r2_memory_map, BLT_DFV2)},
+ {"BLT_DFV1", offsetof(struct b2r2_memory_map, BLT_DFV1)},
+ {"BLT_PRI", offsetof(struct b2r2_memory_map, BLT_PRI)},
+ {"PLUGS1_OP2", offsetof(struct b2r2_memory_map, PLUGS1_OP2)},
+ {"PLUGS1_CHZ", offsetof(struct b2r2_memory_map, PLUGS1_CHZ)},
+ {"PLUGS1_MSZ", offsetof(struct b2r2_memory_map, PLUGS1_MSZ)},
+ {"PLUGS1_PGZ", offsetof(struct b2r2_memory_map, PLUGS1_PGZ)},
+ {"PLUGS2_OP2", offsetof(struct b2r2_memory_map, PLUGS2_OP2)},
+ {"PLUGS2_CHZ", offsetof(struct b2r2_memory_map, PLUGS2_CHZ)},
+ {"PLUGS2_MSZ", offsetof(struct b2r2_memory_map, PLUGS2_MSZ)},
+ {"PLUGS2_PGZ", offsetof(struct b2r2_memory_map, PLUGS2_PGZ)},
+ {"PLUGS3_OP2", offsetof(struct b2r2_memory_map, PLUGS3_OP2)},
+ {"PLUGS3_CHZ", offsetof(struct b2r2_memory_map, PLUGS3_CHZ)},
+ {"PLUGS3_MSZ", offsetof(struct b2r2_memory_map, PLUGS3_MSZ)},
+ {"PLUGS3_PGZ", offsetof(struct b2r2_memory_map, PLUGS3_PGZ)},
+ {"PLUGT_OP2", offsetof(struct b2r2_memory_map, PLUGT_OP2)},
+ {"PLUGT_CHZ", offsetof(struct b2r2_memory_map, PLUGT_CHZ)},
+ {"PLUGT_MSZ", offsetof(struct b2r2_memory_map, PLUGT_MSZ)},
+ {"PLUGT_PGZ", offsetof(struct b2r2_memory_map, PLUGT_PGZ)},
+ {"BLT_NIP", offsetof(struct b2r2_memory_map, BLT_NIP)},
+ {"BLT_CIC", offsetof(struct b2r2_memory_map, BLT_CIC)},
+ {"BLT_INS", offsetof(struct b2r2_memory_map, BLT_INS)},
+ {"BLT_ACK", offsetof(struct b2r2_memory_map, BLT_ACK)},
+ {"BLT_TBA", offsetof(struct b2r2_memory_map, BLT_TBA)},
+ {"BLT_TTY", offsetof(struct b2r2_memory_map, BLT_TTY)},
+ {"BLT_TXY", offsetof(struct b2r2_memory_map, BLT_TXY)},
+ {"BLT_TSZ", offsetof(struct b2r2_memory_map, BLT_TSZ)},
+ {"BLT_S1CF", offsetof(struct b2r2_memory_map, BLT_S1CF)},
+ {"BLT_S2CF", offsetof(struct b2r2_memory_map, BLT_S2CF)},
+ {"BLT_S1BA", offsetof(struct b2r2_memory_map, BLT_S1BA)},
+ {"BLT_S1TY", offsetof(struct b2r2_memory_map, BLT_S1TY)},
+ {"BLT_S1XY", offsetof(struct b2r2_memory_map, BLT_S1XY)},
+ {"BLT_S2BA", offsetof(struct b2r2_memory_map, BLT_S2BA)},
+ {"BLT_S2TY", offsetof(struct b2r2_memory_map, BLT_S2TY)},
+ {"BLT_S2XY", offsetof(struct b2r2_memory_map, BLT_S2XY)},
+ {"BLT_S2SZ", offsetof(struct b2r2_memory_map, BLT_S2SZ)},
+ {"BLT_S3BA", offsetof(struct b2r2_memory_map, BLT_S3BA)},
+ {"BLT_S3TY", offsetof(struct b2r2_memory_map, BLT_S3TY)},
+ {"BLT_S3XY", offsetof(struct b2r2_memory_map, BLT_S3XY)},
+ {"BLT_S3SZ", offsetof(struct b2r2_memory_map, BLT_S3SZ)},
+ {"BLT_CWO", offsetof(struct b2r2_memory_map, BLT_CWO)},
+ {"BLT_CWS", offsetof(struct b2r2_memory_map, BLT_CWS)},
+ {"BLT_CCO", offsetof(struct b2r2_memory_map, BLT_CCO)},
+ {"BLT_CML", offsetof(struct b2r2_memory_map, BLT_CML)},
+ {"BLT_FCTL", offsetof(struct b2r2_memory_map, BLT_FCTL)},
+ {"BLT_PMK", offsetof(struct b2r2_memory_map, BLT_PMK)},
+ {"BLT_RSF", offsetof(struct b2r2_memory_map, BLT_RSF)},
+ {"BLT_RZI", offsetof(struct b2r2_memory_map, BLT_RZI)},
+ {"BLT_HFP", offsetof(struct b2r2_memory_map, BLT_HFP)},
+ {"BLT_VFP", offsetof(struct b2r2_memory_map, BLT_VFP)},
+ {"BLT_Y_RSF", offsetof(struct b2r2_memory_map, BLT_Y_RSF)},
+ {"BLT_Y_RZI", offsetof(struct b2r2_memory_map, BLT_Y_RZI)},
+ {"BLT_Y_HFP", offsetof(struct b2r2_memory_map, BLT_Y_HFP)},
+ {"BLT_Y_VFP", offsetof(struct b2r2_memory_map, BLT_Y_VFP)},
+ {"BLT_KEY1", offsetof(struct b2r2_memory_map, BLT_KEY1)},
+ {"BLT_KEY2", offsetof(struct b2r2_memory_map, BLT_KEY2)},
+ {"BLT_SAR", offsetof(struct b2r2_memory_map, BLT_SAR)},
+ {"BLT_USR", offsetof(struct b2r2_memory_map, BLT_USR)},
+ {"BLT_IVMX0", offsetof(struct b2r2_memory_map, BLT_IVMX0)},
+ {"BLT_IVMX1", offsetof(struct b2r2_memory_map, BLT_IVMX1)},
+ {"BLT_IVMX2", offsetof(struct b2r2_memory_map, BLT_IVMX2)},
+ {"BLT_IVMX3", offsetof(struct b2r2_memory_map, BLT_IVMX3)},
+ {"BLT_OVMX0", offsetof(struct b2r2_memory_map, BLT_OVMX0)},
+ {"BLT_OVMX1", offsetof(struct b2r2_memory_map, BLT_OVMX1)},
+ {"BLT_OVMX2", offsetof(struct b2r2_memory_map, BLT_OVMX2)},
+ {"BLT_OVMX3", offsetof(struct b2r2_memory_map, BLT_OVMX3)},
+ {"BLT_VC1R", offsetof(struct b2r2_memory_map, BLT_VC1R)},
+ {"BLT_Y_HFC0", offsetof(struct b2r2_memory_map, BLT_Y_HFC0)},
+ {"BLT_Y_HFC1", offsetof(struct b2r2_memory_map, BLT_Y_HFC1)},
+ {"BLT_Y_HFC2", offsetof(struct b2r2_memory_map, BLT_Y_HFC2)},
+ {"BLT_Y_HFC3", offsetof(struct b2r2_memory_map, BLT_Y_HFC3)},
+ {"BLT_Y_HFC4", offsetof(struct b2r2_memory_map, BLT_Y_HFC4)},
+ {"BLT_Y_HFC5", offsetof(struct b2r2_memory_map, BLT_Y_HFC5)},
+ {"BLT_Y_HFC6", offsetof(struct b2r2_memory_map, BLT_Y_HFC6)},
+ {"BLT_Y_HFC7", offsetof(struct b2r2_memory_map, BLT_Y_HFC7)},
+ {"BLT_Y_HFC8", offsetof(struct b2r2_memory_map, BLT_Y_HFC8)},
+ {"BLT_Y_HFC9", offsetof(struct b2r2_memory_map, BLT_Y_HFC9)},
+ {"BLT_Y_HFC10", offsetof(struct b2r2_memory_map, BLT_Y_HFC10)},
+ {"BLT_Y_HFC11", offsetof(struct b2r2_memory_map, BLT_Y_HFC11)},
+ {"BLT_Y_HFC12", offsetof(struct b2r2_memory_map, BLT_Y_HFC12)},
+ {"BLT_Y_HFC13", offsetof(struct b2r2_memory_map, BLT_Y_HFC13)},
+ {"BLT_Y_HFC14", offsetof(struct b2r2_memory_map, BLT_Y_HFC14)},
+ {"BLT_Y_HFC15", offsetof(struct b2r2_memory_map, BLT_Y_HFC15)},
+ {"BLT_Y_VFC0", offsetof(struct b2r2_memory_map, BLT_Y_VFC0)},
+ {"BLT_Y_VFC1", offsetof(struct b2r2_memory_map, BLT_Y_VFC1)},
+ {"BLT_Y_VFC2", offsetof(struct b2r2_memory_map, BLT_Y_VFC2)},
+ {"BLT_Y_VFC3", offsetof(struct b2r2_memory_map, BLT_Y_VFC3)},
+ {"BLT_Y_VFC4", offsetof(struct b2r2_memory_map, BLT_Y_VFC4)},
+ {"BLT_Y_VFC5", offsetof(struct b2r2_memory_map, BLT_Y_VFC5)},
+ {"BLT_Y_VFC6", offsetof(struct b2r2_memory_map, BLT_Y_VFC6)},
+ {"BLT_Y_VFC7", offsetof(struct b2r2_memory_map, BLT_Y_VFC7)},
+ {"BLT_Y_VFC8", offsetof(struct b2r2_memory_map, BLT_Y_VFC8)},
+ {"BLT_Y_VFC9", offsetof(struct b2r2_memory_map, BLT_Y_VFC9)},
+ {"BLT_HFC0", offsetof(struct b2r2_memory_map, BLT_HFC0)},
+ {"BLT_HFC1", offsetof(struct b2r2_memory_map, BLT_HFC1)},
+ {"BLT_HFC2", offsetof(struct b2r2_memory_map, BLT_HFC2)},
+ {"BLT_HFC3", offsetof(struct b2r2_memory_map, BLT_HFC3)},
+ {"BLT_HFC4", offsetof(struct b2r2_memory_map, BLT_HFC4)},
+ {"BLT_HFC5", offsetof(struct b2r2_memory_map, BLT_HFC5)},
+ {"BLT_HFC6", offsetof(struct b2r2_memory_map, BLT_HFC6)},
+ {"BLT_HFC7", offsetof(struct b2r2_memory_map, BLT_HFC7)},
+ {"BLT_HFC8", offsetof(struct b2r2_memory_map, BLT_HFC8)},
+ {"BLT_HFC9", offsetof(struct b2r2_memory_map, BLT_HFC9)},
+ {"BLT_HFC10", offsetof(struct b2r2_memory_map, BLT_HFC10)},
+ {"BLT_HFC11", offsetof(struct b2r2_memory_map, BLT_HFC11)},
+ {"BLT_HFC12", offsetof(struct b2r2_memory_map, BLT_HFC12)},
+ {"BLT_HFC13", offsetof(struct b2r2_memory_map, BLT_HFC13)},
+ {"BLT_HFC14", offsetof(struct b2r2_memory_map, BLT_HFC14)},
+ {"BLT_HFC15", offsetof(struct b2r2_memory_map, BLT_HFC15)},
+ {"BLT_VFC0", offsetof(struct b2r2_memory_map, BLT_VFC0)},
+ {"BLT_VFC1", offsetof(struct b2r2_memory_map, BLT_VFC1)},
+ {"BLT_VFC2", offsetof(struct b2r2_memory_map, BLT_VFC2)},
+ {"BLT_VFC3", offsetof(struct b2r2_memory_map, BLT_VFC3)},
+ {"BLT_VFC4", offsetof(struct b2r2_memory_map, BLT_VFC4)},
+ {"BLT_VFC5", offsetof(struct b2r2_memory_map, BLT_VFC5)},
+ {"BLT_VFC6", offsetof(struct b2r2_memory_map, BLT_VFC6)},
+ {"BLT_VFC7", offsetof(struct b2r2_memory_map, BLT_VFC7)},
+ {"BLT_VFC8", offsetof(struct b2r2_memory_map, BLT_VFC8)},
+ {"BLT_VFC9", offsetof(struct b2r2_memory_map, BLT_VFC9)},
+};
+
+#ifdef HANDLE_TIMEOUTED_JOBS
+/**
+ * printk_regs() - Print B2R2 registers to printk
+ */
+static void printk_regs(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) {
+ unsigned long value = readl(
+ (unsigned long *) (((u8 *) b2r2_core.hw) +
+ debugfs_regs[i].offset));
+ b2r2_log_regdump("%s: %08lX\n",
+ debugfs_regs[i].name,
+ value);
+ }
+}
+#endif
+
+/**
+ * debugfs_b2r2_reg_read() - Implements debugfs read for B2R2 register
+ *
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to read
+ * @f_pos: File position
+ *
+ * Returns number of bytes read or negative error code
+ */
+static int debugfs_b2r2_reg_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ size_t dev_size;
+ int ret = 0;
+
+ unsigned long value;
+ char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+
+ if (Buf == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* We need a clock when reading from B2R2 */
+ clock_enable();
+
+ /* Read from B2R2 */
+ value = readl((unsigned long *) (((u8 *) b2r2_core.hw) +
+ (u32) filp->f_dentry->
+ d_inode->i_private));
+ clock_disable();
+
+ /* Build the string */
+ dev_size = sprintf(Buf, "%8lX\n", value);
+
+ /* No more to read if offset != 0 */
+ if (*f_pos > dev_size)
+ goto out;
+
+ if (*f_pos + count > dev_size)
+ count = dev_size - *f_pos;
+
+ /* Return it to user space */
+ if (copy_to_user(buf, Buf, count))
+ ret = -EINVAL;
+ *f_pos += count;
+ ret = count;
+
+out:
+ if (Buf != NULL)
+ kfree(Buf);
+ return ret;
+}
+
+/**
+ * debugfs_b2r2_reg_write() - Implements debugfs write for B2R2 register
+ *
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to write
+ * @f_pos: File position
+ *
+ * Returns number of bytes written or negative error code
+ */
+static int debugfs_b2r2_reg_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ char Buf[80];
+ u32 reg_value;
+ int ret = 0;
+
+ /* Adjust count */
+ if (count >= sizeof(Buf))
+ count = sizeof(Buf) - 1;
+ /* Get it from user space */
+ if (copy_from_user(Buf, buf, count))
+ return -EINVAL;
+ Buf[count] = 0;
+ /* Convert from hex string */
+ if (sscanf(Buf, "%8lX", (unsigned long *) &reg_value) != 1)
+ return -EINVAL;
+
+ /* Turn on clock, write to B2R2, turn off clock */
+ clock_enable();
+ writel(reg_value, (u32 *) (((u8 *) b2r2_core.hw) +
+ (u32) filp->f_dentry->d_inode->i_private));
+
+ clock_disable();
+ *f_pos += count;
+ ret = count;
+
+ return ret;
+}
+
+/**
+ * debugfs_b2r2_reg_fops() - File operations for B2R2 register debugfs
+ */
+static const struct file_operations debugfs_b2r2_reg_fops = {
+ .owner = THIS_MODULE,
+ .read = debugfs_b2r2_reg_read,
+ .write = debugfs_b2r2_reg_write,
+};
+
+/**
+ * debugfs_b2r2_regs_read() - Implements debugfs read for B2R2 register dump
+ *
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to read
+ * @f_pos: File position
+ *
+ * Returns number of bytes written or negative error code
+ */
+static int debugfs_b2r2_regs_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ size_t dev_size = 0;
+ int ret = 0;
+ int i;
+ char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+
+ if (Buf == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Build a giant string containing all registers */
+ clock_enable();
+ for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) {
+ unsigned long value =
+ readl((unsigned long *) (((u8 *) b2r2_core.hw) +
+ debugfs_regs[i].offset));
+ dev_size += sprintf(Buf + dev_size, "%s: %08lX\n",
+ debugfs_regs[i].name,
+ value);
+ }
+ clock_disable();
+
+ /* No more to read if offset != 0 */
+ if (*f_pos > dev_size)
+ goto out;
+
+ if (*f_pos + count > dev_size)
+ count = dev_size - *f_pos;
+
+ if (copy_to_user(buf, Buf, count))
+ ret = -EINVAL;
+ *f_pos += count;
+ ret = count;
+
+out:
+ if (Buf != NULL)
+ kfree(Buf);
+ return ret;
+}
+
+/**
+ * debugfs_b2r2_regs_fops() - File operations for B2R2 register dump debugfs
+ */
+static const struct file_operations debugfs_b2r2_regs_fops = {
+ .owner = THIS_MODULE,
+ .read = debugfs_b2r2_regs_read,
+};
+
+/**
+ * debugfs_b2r2_stat_read() - Implements debugfs read for B2R2 statistics
+ *
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to read
+ * @f_pos: File position
+ *
+ * Returns number of bytes read or negative error code
+ */
+static int debugfs_b2r2_stat_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ size_t dev_size = 0;
+ int ret = 0;
+ int i = 0;
+ char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+
+ if (Buf == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Build a string containing all statistics */
+ dev_size += sprintf(Buf + dev_size, "Interrupts: %lu\n",
+ b2r2_core.stat_n_irq);
+ dev_size += sprintf(Buf + dev_size, "Added jobs: %lu\n",
+ b2r2_core.stat_n_jobs_added);
+ dev_size += sprintf(Buf + dev_size, "Removed jobs: %lu\n",
+ b2r2_core.stat_n_jobs_removed);
+ dev_size += sprintf(Buf + dev_size, "Jobs in prio list: %lu\n",
+ b2r2_core.stat_n_jobs_in_prio_list);
+ dev_size += sprintf(Buf + dev_size, "Active jobs: %lu\n",
+ b2r2_core.n_active_jobs);
+ for (i = 0; i < ARRAY_SIZE(b2r2_core.active_jobs); i++)
+ dev_size += sprintf(Buf + dev_size, "Job in queue %d: %p\n",
+ i, b2r2_core.active_jobs[i]);
+ dev_size += sprintf(Buf + dev_size, "Clock requests: %lu\n",
+ b2r2_core.clock_request_count);
+
+ /* No more to read if offset != 0 */
+ if (*f_pos > dev_size)
+ goto out;
+
+ if (*f_pos + count > dev_size)
+ count = dev_size - *f_pos;
+
+ if (copy_to_user(buf, Buf, count))
+ ret = -EINVAL;
+ *f_pos += count;
+ ret = count;
+
+out:
+ if (Buf != NULL)
+ kfree(Buf);
+ return ret;
+}
+
+/**
+ * debugfs_b2r2_stat_fops() - File operations for B2R2 statistics debugfs
+ */
+static const struct file_operations debugfs_b2r2_stat_fops = {
+ .owner = THIS_MODULE,
+ .read = debugfs_b2r2_stat_read,
+};
+
+
+/**
+ * debugfs_b2r2_clock_read() - Implements debugfs read for
+ * PMU B2R2 clock register
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to read
+ * @f_pos: File position
+ *
+ * Returns number of bytes read or negative error code
+ */
+static int debugfs_b2r2_clock_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ /* 10 characters hex number + newline + string terminator; */
+ char Buf[10+2];
+ size_t dev_size;
+ int ret = 0;
+
+ unsigned long value = clk_get_rate(b2r2_core.b2r2_clock);
+
+ dev_size = sprintf(Buf, "%#010lX\n", value);
+
+ /* No more to read if offset != 0 */
+ if (*f_pos > dev_size)
+ goto out;
+
+ if (*f_pos + count > dev_size)
+ count = dev_size - *f_pos;
+
+ if (copy_to_user(buf, Buf, count))
+ ret = -EINVAL;
+ *f_pos += count;
+ ret = count;
+
+out:
+ return ret;
+}
+
+/**
+ * debugfs_b2r2_clock_write() - Implements debugfs write for
+ * PMU B2R2 clock register
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to write
+ * @f_pos: File position
+ *
+ * Returns number of bytes written or negative error code
+ */
+static int debugfs_b2r2_clock_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ char Buf[80];
+ u32 reg_value;
+ int ret = 0;
+
+ if (count >= sizeof(Buf))
+ count = sizeof(Buf) - 1;
+ if (copy_from_user(Buf, buf, count))
+ return -EINVAL;
+ Buf[count] = 0;
+ if (sscanf(Buf, "%8lX", (unsigned long *) &reg_value) != 1)
+ return -EINVAL;
+
+ /*not working yet*/
+ /*clk_set_rate(b2r2_core.b2r2_clock, (unsigned long) reg_value);*/
+
+ *f_pos += count;
+ ret = count;
+
+ return ret;
+}
+
+/**
+ * debugfs_b2r2_clock_fops() - File operations for PMU B2R2 clock debugfs
+ */
+static const struct file_operations debugfs_b2r2_clock_fops = {
+ .owner = THIS_MODULE,
+ .read = debugfs_b2r2_clock_read,
+ .write = debugfs_b2r2_clock_write,
+};
+
+#endif
+
+
+/**
+ *
+ * init_hw() - B2R2 Hardware reset & initiliaze
+ *
+ * @pdev: B2R2 platform device
+ *
+ * 1)Register interrupt handler
+ *
+ * 2)B2R2 Register map
+ *
+ * 3)For resetting B2R2 hardware,write to B2R2 Control register the
+ * B2R2BLT_CTLGLOBAL_soft_reset and then polling for on
+ * B2R2 status register for B2R2BLT_STA1BDISP_IDLE flag.
+ *
+ * 4)Wait for B2R2 hardware to be idle (on a timeout rather than while loop)
+ *
+ * 5)Driver status reset
+ *
+ * 6)Recover from any error without any leaks.
+ *
+ */
+static int init_hw(struct platform_device *pdev)
+{
+ int result = 0;
+ struct resource *res;
+ u32 uTimeOut = B2R2_DRIVER_TIMEOUT_VALUE;
+
+ b2r2_log_info("%s started..\n", __func__);
+ b2r2_log_info("Map B2R2 registers...\n");
+
+ (void)prcmu_set_hwacc(HW_ACC_B2R2, HW_ON);
+
+ /* Map B2R2 into kernel virtual memory space */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL)
+ goto b2r2_init_no_res;
+
+ b2r2_core.hw = (struct b2r2_memory_map *) ioremap(res->start,
+ res->end - res->start + 1);
+ if (b2r2_core.hw == NULL) {
+
+ b2r2_log_info("%s: ioremap failed\n", __func__);
+ result = -ENOMEM;
+ goto b2r2_init_ioremap_failed;
+ }
+
+ dev_dbg(b2r2_core.log_dev,
+ "b2r2 structure address %p \n",
+ b2r2_core.hw);
+
+ /* Make sure we have a clock during initialization */
+ clock_enable();
+
+ /* Put B2R2 into reset */
+ clear_interrupts();
+ writel(readl(&b2r2_core.hw->BLT_CTL) | B2R2BLT_CTLGLOBAL_soft_reset,
+ &b2r2_core.hw->BLT_CTL);
+
+ b2r2_log_info("register interrupt handler..\n");
+
+ /* Set up interrupt handler */
+ result = request_irq(IRQ_B2R2, b2r2_irq_handler, 0,
+ "b2r2-interrupt", 0);
+ if (result) {
+
+ dev_dbg(b2r2_core.log_dev,
+ "%s: failed to register IRQ for B2R2\n", __func__);
+ goto b2r2_init_request_irq_failed;
+ }
+
+ b2r2_log_info("do a global reset..\n");
+
+ /* Release reset */
+ writel(0x00000000, &b2r2_core.hw->BLT_CTL);
+
+ b2r2_log_info("wait for B2R2 to be idle..\n");
+
+ /** Wait for B2R2 to be idle (on a timeout rather than while loop) */
+ while ((uTimeOut > 0) &&
+ ((readl(&b2r2_core.hw->BLT_STA1) &
+ B2R2BLT_STA1BDISP_IDLE) == 0x0))
+ uTimeOut--;
+ if (uTimeOut == 0) {
+ b2r2_log_warn(
+ "%s: B2R2 not idle after SW reset\n", __func__);
+ result = -EAGAIN;
+ goto b2r2_core_init_hw_timeout;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ /* Register debug fs */
+ if (!b2r2_core.debugfs_root_dir) {
+ int i;
+
+ b2r2_core.debugfs_root_dir = debugfs_create_dir("b2r2", NULL);
+ debugfs_create_file("regs",
+ 0666, b2r2_core.debugfs_root_dir,
+ 0,
+ &debugfs_b2r2_regs_fops);
+ debugfs_create_file("stat",
+ 0666, b2r2_core.debugfs_root_dir,
+ 0,
+ &debugfs_b2r2_stat_fops);
+ debugfs_create_file("clock",
+ 0666, b2r2_core.debugfs_root_dir,
+ 0,
+ &debugfs_b2r2_clock_fops);
+ /* Create debugfs entries for all static registers */
+ for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++)
+ debugfs_create_file(debugfs_regs[i].name,
+ 0666, b2r2_core.debugfs_root_dir,
+ (void *) debugfs_regs[i].offset,
+ &debugfs_b2r2_reg_fops);
+ }
+#endif
+
+ clock_disable();
+ b2r2_log_info("%s ended..\n", __func__);
+ return result;
+
+/** Recover from any error without any leaks */
+
+b2r2_core_init_hw_timeout:
+
+ /** Free B2R2 interrupt handler */
+
+ free_irq(IRQ_B2R2, 0);
+
+b2r2_init_request_irq_failed:
+ /** Unmap B2R2 registers */
+
+ clock_disable();
+ if (b2r2_core.hw)
+ iounmap(b2r2_core.hw);
+ b2r2_core.hw = NULL;
+
+b2r2_init_no_res:
+b2r2_init_ioremap_failed:
+
+ return result;
+
+}
+
+
+/**
+ * exit_hw() - B2R2 Hardware exit
+ *
+ * b2r2_core.lock _must_ NOT be held
+ */
+static void exit_hw(void)
+{
+ unsigned long flags;
+
+ b2r2_log_info("%s started..\n", __func__);
+
+#ifdef CONFIG_DEBUG_FS
+ /* Unregister our debugfs entries */
+ if (b2r2_core.debugfs_root_dir) {
+ debugfs_remove_recursive(b2r2_core.debugfs_root_dir);
+ b2r2_core.debugfs_root_dir = NULL;
+ }
+#endif
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+
+ /* Cancel all pending jobs */
+ exit_job_list(&b2r2_core.prio_queue);
+
+ /* Soft reset B2R2 (Close all DMA,
+ reset all state to idle, reset regs)*/
+ clock_enable();
+
+ writel(readl(&b2r2_core.hw->BLT_CTL) | B2R2BLT_CTLGLOBAL_soft_reset,
+ &b2r2_core.hw->BLT_CTL);
+ clear_interrupts();
+
+ /** Free B2R2 interrupt handler */
+ b2r2_log_info("free interrupt handler..\n");
+ free_irq(IRQ_B2R2, 0);
+
+ /** Unmap B2R2 registers */
+ b2r2_log_info("unmap b2r2 registers..\n");
+ if (b2r2_core.hw) {
+ iounmap(b2r2_core.hw);
+
+ b2r2_core.hw = NULL;
+ }
+
+ clock_disable();
+
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+
+ (void)prcmu_set_hwacc(HW_ACC_B2R2, HW_OFF);
+
+ b2r2_log_info("%s ended...\n", __func__);
+}
+
+/**
+ * b2r2_probe() - This routine loads the B2R2 core driver
+ *
+ * @pdev: platform device.
+ */
+static int __init b2r2_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct resource *res;
+
+ BUG_ON(pdev == NULL);
+
+ ret = b2r2_debug_init(&pdev->dev);
+ if (ret < 0) {
+ dev_err(b2r2_core.log_dev, "b2r2_debug_init failed\n");
+ goto b2r2_probe_debug_init_failed;
+ }
+
+ b2r2_core.log_dev = &pdev->dev;
+ b2r2_log_info("init started.\n");
+
+ /* Init spin locks */
+ spin_lock_init(&b2r2_core.lock);
+
+ /* Init job queues */
+ INIT_LIST_HEAD(&b2r2_core.prio_queue);
+
+#ifdef HANDLE_TIMEOUTED_JOBS
+ /* Create work queue for callbacks & timeout */
+ INIT_DELAYED_WORK(&b2r2_core.timeout_work, timeout_work_function);
+#endif
+
+ /* Timer used when B2R2 clock is turned off */
+ init_timer(&b2r2_core.clock_off_timer);
+ b2r2_core.clock_off_timer.function = clock_off_timer_function;
+
+
+ /* Work queue for callbacks and timeout management */
+ b2r2_core.work_queue = create_workqueue("B2R2");
+ if (!b2r2_core.work_queue) {
+ ret = -ENOMEM;
+ goto b2r2_probe_no_work_queue;
+ }
+
+ /* Get the clock for B2R2*/
+ b2r2_core.b2r2_clock = clk_get(&pdev->dev, "b2r2");
+ if (IS_ERR(b2r2_core.b2r2_clock)) {
+ ret = PTR_ERR(b2r2_core.b2r2_clock);
+ b2r2_log_err("clk_get b2r2 failed\n");
+ goto b2r2_probe_no_clk;
+ }
+
+ /** Enable B2R2 power domain & check it.*/
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res == NULL) {
+ ret = -EINVAL;
+ goto b2r2_probe_no_pmu_b2r2_res;
+ }
+
+ /** Init B2R2 hardware */
+ ret = init_hw(pdev);
+ if (ret < 0) {
+ b2r2_log_err("init_hw() returns %d\n", ret);
+ goto b2r2_probe_init_hw_fail;
+ }
+
+ /* Initialize b2r2_blt module. FIXME: Module of it's own
+ or perhaps a dedicated module init c file? */
+ ret = b2r2_blt_module_init();
+ if (ret < 0) {
+ b2r2_log_err("b2r2_blt_module_init failed\n");
+ goto b2r2_probe_blt_init_fail;
+ }
+
+ b2r2_log_info("init done.\n");
+
+ return ret;
+
+/** Recover from any error if something fails */
+b2r2_probe_blt_init_fail:
+ exit_hw();
+b2r2_probe_init_hw_fail:
+ clock_disable();
+b2r2_probe_no_pmu_b2r2_res:
+b2r2_probe_no_clk:
+ destroy_workqueue(b2r2_core.work_queue);
+ b2r2_core.work_queue = NULL;
+b2r2_probe_no_work_queue:
+
+ b2r2_log_info("init done with errors.\n");
+b2r2_probe_debug_init_failed:
+
+ return ret;
+
+}
+
+
+
+/**
+ * b2r2_remove - This routine unloads b2r2 driver
+ *
+ * @pdev: platform device.
+ */
+static int b2r2_remove(struct platform_device *pdev)
+{
+ unsigned long flags;
+
+ BUG_ON(pdev == NULL);
+
+ b2r2_log_info("%s started\n", __func__);
+
+ /* Flush B2R2 work queue (call all callbacks) */
+ flush_workqueue(b2r2_core.work_queue);
+
+ /* Exit b2r2 blt module */
+ b2r2_blt_module_exit();
+
+#ifdef HANDLE_TIMEOUTED_JOBS
+ cancel_delayed_work(&b2r2_core.timeout_work);
+#endif
+
+ /* Flush B2R2 work queue (call all callbacks for
+ cancelled jobs) */
+ flush_workqueue(b2r2_core.work_queue);
+
+ /** Exit B2R2 hardware */
+ exit_hw();
+
+ destroy_workqueue(b2r2_core.work_queue);
+
+ spin_lock_irqsave(&b2r2_core.lock, flags);
+ b2r2_core.work_queue = NULL;
+ spin_unlock_irqrestore(&b2r2_core.lock, flags);
+
+ /* Wait for delayed timer to execute
+ TODO: Can't we just use timer_del()? */
+ while (timer_pending(&b2r2_core.clock_off_timer))
+ mdelay(10);
+
+ /* Return the clock */
+ clk_put(b2r2_core.b2r2_clock);
+
+ b2r2_log_info("%s ended\n", __func__);
+
+ b2r2_core.log_dev = NULL;
+
+ b2r2_debug_exit();
+
+ return 0;
+
+}
+/**
+ * b2r2_suspend() - This routine puts the B2R2 device in to sustend state.
+ * @pdev: platform device.
+ *
+ * This routine stores the current state of the b2r2 device and puts in to suspend state.
+ *
+ */
+int b2r2_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ b2r2_log_info("%s\n", __func__);
+
+ /* Flush B2R2 work queue (call all callbacks) */
+ flush_workqueue(b2r2_core.work_queue);
+
+#ifdef HANDLE_TIMEOUTED_JOBS
+ cancel_delayed_work(&b2r2_core.timeout_work);
+#endif
+
+ /* Flush B2R2 work queue (call all callbacks for
+ cancelled jobs) */
+ flush_workqueue(b2r2_core.work_queue);
+
+ /** Exit B2R2 hardware */
+ exit_hw();
+
+ /* Wait for delayed timer to execute */
+ while (timer_pending(&b2r2_core.clock_off_timer))
+ mdelay(10);
+
+ return 0;
+}
+
+
+/**
+ * b2r2_resume() - This routine resumes the B2R2 device from sustend state.
+ * @pdev: platform device.
+ *
+ * This routine restore back the current state of the b2r2 device resumes.
+ *
+ */
+int b2r2_resume(struct platform_device *pdev)
+{
+ b2r2_log_info("%s\n", __func__);
+
+ return init_hw(pdev);
+}
+
+/**
+ * struct platform_b2r2_driver - Platform driver configuration for the
+ * B2R2 core driver
+ */
+static struct platform_driver platform_b2r2_driver = {
+ .probe = b2r2_probe,
+ .remove = b2r2_remove,
+ .driver = {
+ .name = "U8500-B2R2",
+ },
+ /** TODO implement power mgmt functions */
+ .suspend = b2r2_suspend,
+ .resume = b2r2_resume,
+};
+
+
+/**
+ * b2r2_init() - Module init function for the B2R2 core module
+ */
+static int __init b2r2_init(void)
+{
+ printk(KERN_INFO "%s\n", __func__);
+ return platform_driver_register(&platform_b2r2_driver);
+}
+module_init(b2r2_init);
+
+/**
+ * b2r2_exit() - Module exit function for the B2R2 core module
+ */
+static void __exit b2r2_exit(void)
+{
+ printk(KERN_INFO "%s\n", __func__);
+ platform_driver_unregister(&platform_b2r2_driver);
+ return;
+}
+module_exit(b2r2_exit);
+
+
+/** Module is having GPL license */
+
+MODULE_LICENSE("GPL");
+
+/** Module author & discription */
+
+MODULE_AUTHOR("Robert Fekete (robert.fekete@stericsson.com)");
+MODULE_DESCRIPTION("B2R2 Core driver");
diff --git a/drivers/video/b2r2/b2r2_core.h b/drivers/video/b2r2/b2r2_core.h
new file mode 100644
index 00000000000..2f958751694
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_core.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 core driver
+ *
+ * Author: Robert Fekete <robert.fekete@stericsson.com>
+ * Author: Paul Wannback
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __B2R2_CORE_H__
+#define __B2R2_CORE_H__
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+/**
+ * enum b2r2_core_queue - Indicates the B2R2 queue that the job belongs to
+ *
+ * @B2R2_CORE_QUEUE_AQ1: Application queue 1
+ * @B2R2_CORE_QUEUE_AQ2: Application queue 2
+ * @B2R2_CORE_QUEUE_AQ3: Application queue 3
+ * @B2R2_CORE_QUEUE_AQ4: Application queue 4
+ * @B2R2_CORE_QUEUE_CQ1: Composition queue 1
+ * @B2R2_CORE_QUEUE_CQ2: Composition queue 2
+ * @B2R2_CORE_QUEUE_NO_OF: Number of queues
+ */
+enum b2r2_core_queue {
+ B2R2_CORE_QUEUE_AQ1 = 0,
+ B2R2_CORE_QUEUE_AQ2,
+ B2R2_CORE_QUEUE_AQ3,
+ B2R2_CORE_QUEUE_AQ4,
+ B2R2_CORE_QUEUE_CQ1,
+ B2R2_CORE_QUEUE_CQ2,
+ B2R2_CORE_QUEUE_NO_OF,
+};
+
+#define B2R2_NUM_APPLICATIONS_QUEUES 4
+
+/**
+ * enum b2r2_core_job_state - Indicates the current state of the job
+ *
+ * @B2R2_CORE_JOB_IDLE: Never queued
+ * @B2R2_CORE_JOB_QUEUED: In queue but not started yet
+ * @B2R2_CORE_JOB_RUNNING: Running, executed by B2R2
+ * @B2R2_CORE_JOB_DONE: Completed
+ * @B2R2_CORE_JOB_CANCELED: Canceled
+ */
+enum b2r2_core_job_state {
+ B2R2_CORE_JOB_IDLE = 0,
+ B2R2_CORE_JOB_QUEUED,
+ B2R2_CORE_JOB_RUNNING,
+ B2R2_CORE_JOB_DONE,
+ B2R2_CORE_JOB_CANCELED,
+};
+
+/**
+ * struct b2r2_core_job - Represents a B2R2 core job
+ *
+ * @start_sentinel: Memory overwrite guard
+ *
+ * @tag: Client value. Used by b2r2_core_job_find_first_with_tag().
+ * @prio: Job priority, from -19 up to 20. Mapped to the
+ * B2R2 application queues. Filled in by the client.
+ * @first_node_address: Physical address of the first node. Filled
+ * in by the client.
+ * @last_node_address: Physical address of the last node. Filled
+ * in by the client.
+ *
+ * @callback: Function that will be called when the job is done.
+ * @acquire_resources: Function that allocates the resources needed
+ * to execute the job (i.e. SRAM alloc). Must not
+ * sleep if atomic, should fail with negative error code
+ * if resources not available.
+ * @release_resources: Function that releases the resources previously
+ * allocated by acquire_resources (i.e. SRAM alloc).
+ * @release: Function that will be called when the reference count reaches
+ * zero.
+ *
+ * @job_id: Unique id for this job, assigned by B2R2 core
+ * @job_state: The current state of the job
+ * @jiffies: Number of jiffies needed for this request
+ *
+ * @list: List entry element for internal list management
+ * @event: Wait queue event to wait for job done
+ * @work: Work queue structure, for callback implementation
+ *
+ * @queue: The queue that this job shall be submitted to
+ * @control: B2R2 Queue control
+ * @pace_control: For composition queue only
+ * @interrupt_context: Context for interrupt
+ *
+ * @end_sentinel: Memory overwrite guard
+ */
+struct b2r2_core_job {
+ u32 start_sentinel;
+
+ /* Data to be filled in by client */
+ int tag;
+ int prio;
+ u32 first_node_address;
+ u32 last_node_address;
+ void (*callback)(struct b2r2_core_job *);
+ int (*acquire_resources)(struct b2r2_core_job *,
+ bool atomic);
+ void (*release_resources)(struct b2r2_core_job *,
+ bool atomic);
+ void (*release)(struct b2r2_core_job *);
+
+ /* Output data, do not modify */
+ int job_id;
+ enum b2r2_core_job_state job_state;
+ unsigned long jiffies;
+
+ /* Data below is internal to b2r2_core, do not modify */
+
+ /* Reference counting */
+ u32 ref_count;
+
+ /* Internal data */
+ struct list_head list;
+ wait_queue_head_t event;
+ struct work_struct work;
+
+ /* B2R2 HW data */
+ enum b2r2_core_queue queue;
+ u32 control;
+ u32 pace_control;
+ u32 interrupt_context;
+
+ /* Timing data */
+ u32 hw_start_time;
+ s32 nsec_active_in_hw;
+
+ u32 end_sentinel;
+};
+
+/**
+ * b2r2_core_job_add() - Adds a job to B2R2 job queues
+ *
+ * The job reference count will be increased after this function
+ * has been called and b2r2_core_job_release() must be called to
+ * release the reference. The job callback function will be always
+ * be called after the job is done or cancelled.
+ *
+ * @job: Job to be added
+ *
+ * Returns 0 if OK else negative error code
+ *
+ */
+int b2r2_core_job_add(struct b2r2_core_job *job);
+
+/**
+ * b2r2_core_job_wait() - Waits for an added job to be done.
+ *
+ * @job: Job to wait for
+ *
+ * Returns 0 if job done else negative error code
+ *
+ */
+int b2r2_core_job_wait(struct b2r2_core_job *job);
+
+/**
+ * b2r2_core_job_cancel() - Cancel an already added job.
+ *
+ * @job: Job to cancel
+ *
+ * Returns 0 if job cancelled or done else negative error code
+ *
+ */
+int b2r2_core_job_cancel(struct b2r2_core_job *job);
+
+/**
+ * b2r2_core_job_find() - Finds job with given job id
+ *
+ * Reference count will be increased for the found job
+ *
+ * @job_id: Job id to find
+ *
+ * Returns job if found, else NULL
+ *
+ */
+struct b2r2_core_job *b2r2_core_job_find(int job_id);
+
+/**
+ * b2r2_core_job_find_first_with_tag() - Finds first job with given tag
+ *
+ * Reference count will be increased for the found job.
+ * This function can be used to find all jobs for a client, i.e.
+ * when cancelling all jobs for a client.
+ *
+ * @tag: Tag to find
+ *
+ * Returns job if found, else NULL
+ *
+ */
+struct b2r2_core_job *b2r2_core_job_find_first_with_tag(int tag);
+
+/**
+ * b2r2_core_job_addref() - Increase the job reference count.
+ *
+ * @job: Job to increase reference count for.
+ * @caller: The function calling this function (for debug)
+ */
+void b2r2_core_job_addref(struct b2r2_core_job *job, const char *caller);
+
+/**
+ * b2r2_core_job_release() - Decrease the job reference count. The
+ * job will be released (the release() function
+ * will be called) when the reference count
+ * reaches zero.
+ *
+ * @job: Job to decrease reference count for.
+ * @caller: The function calling this function (for debug)
+ */
+void b2r2_core_job_release(struct b2r2_core_job *job, const char *caller);
+
+#endif /* !defined(__B2R2_CORE_JOB_H__) */
diff --git a/drivers/video/b2r2/b2r2_debug.c b/drivers/video/b2r2/b2r2_debug.c
new file mode 100644
index 00000000000..c9f9caeef68
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_debug.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 dynamic debug
+ *
+ * Author: Fredrik Allansson <fredrik.allansson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include "b2r2_debug.h"
+#include <linux/debugfs.h>
+
+int b2r2_log_levels[B2R2_LOG_LEVEL_COUNT];
+struct device *b2r2_log_dev;
+
+static struct dentry *root_dir;
+static struct dentry *log_lvl_dir;
+
+int b2r2_debug_init(struct device *log_dev)
+{
+ int i;
+ int init_val = 0;
+
+ b2r2_log_dev = log_dev;
+
+#ifdef CONFIG_DYNAMIC_DEBUG
+ /*
+ * We want all prints to be enabled by default when using dynamic
+ * debug
+ */
+ init_val = 1;
+#endif
+
+ for (i = 0; i < B2R2_LOG_LEVEL_COUNT; i++)
+ b2r2_log_levels[i] = init_val;
+
+#if !defined(CONFIG_DYNAMIC_DEBUG) && defined(CONFIG_DEBUG_FS)
+ /*
+ * If dynamic debug is disabled we need some other way to control the
+ * log prints
+ */
+ root_dir = debugfs_create_dir("b2r2_debug", NULL);
+ log_lvl_dir = debugfs_create_dir("logs", root_dir);
+
+ /* No need to save the files, they will be removed recursively */
+ (void)debugfs_create_bool("warnings", 0644, log_lvl_dir,
+ &b2r2_log_levels[B2R2_LOG_LEVEL_WARN]);
+ (void)debugfs_create_bool("info", 0644, log_lvl_dir,
+ &b2r2_log_levels[B2R2_LOG_LEVEL_INFO]);
+ (void)debugfs_create_bool("debug", 0644, log_lvl_dir,
+ &b2r2_log_levels[B2R2_LOG_LEVEL_DEBUG]);
+ (void)debugfs_create_bool("regdumps", 0644, log_lvl_dir,
+ &b2r2_log_levels[B2R2_LOG_LEVEL_REGDUMP]);
+#endif
+
+ return 0;
+}
+
+void b2r2_debug_exit(void)
+{
+#if !defined(CONFIG_DYNAMIC_DEBUG) && defined(CONFIG_DEBUG_FS)
+ if (root_dir)
+ debugfs_remove_recursive(root_dir);
+#endif
+}
diff --git a/drivers/video/b2r2/b2r2_debug.h b/drivers/video/b2r2/b2r2_debug.h
new file mode 100644
index 00000000000..e03a913f43c
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_debug.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 dynamic debug
+ *
+ * Author: Fredrik Allansson <fredrik.allansson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef _LINUX_DRIVERS_VIDEO_B2R2_DEBUG_H_
+#define _LINUX_DRIVERS_VIDEO_B2R2_DEBUG_H_
+
+#include <linux/device.h>
+
+#ifdef CONFIG_B2R2_DEBUG
+
+/* Log macros */
+enum b2r2_log_levels {
+ B2R2_LOG_LEVEL_WARN,
+ B2R2_LOG_LEVEL_INFO,
+ B2R2_LOG_LEVEL_DEBUG,
+ B2R2_LOG_LEVEL_REGDUMP,
+ B2R2_LOG_LEVEL_COUNT,
+};
+
+/*
+ * Booleans controlling the different log levels. The different log levels are
+ * enabled separately (i.e. you can have info prints without the warn prints).
+ */
+extern int b2r2_log_levels[B2R2_LOG_LEVEL_COUNT];
+
+extern struct device *b2r2_log_dev;
+
+#define b2r2_log_err(...) \
+ do { \
+ dev_err(b2r2_log_dev, __VA_ARGS__); \
+ } while (0)
+
+#define b2r2_log_warn(...) \
+ do { \
+ if (b2r2_log_levels[B2R2_LOG_LEVEL_WARN]) \
+ dev_dbg(b2r2_log_dev, "WARN " __VA_ARGS__); \
+ } while (0)
+
+#define b2r2_log_info(...) \
+ do { \
+ if (b2r2_log_levels[B2R2_LOG_LEVEL_INFO]) \
+ dev_dbg(b2r2_log_dev, "INFO " __VA_ARGS__); \
+ } while (0)
+
+#define b2r2_log_debug(...) \
+ do { \
+ if (b2r2_log_levels[B2R2_LOG_LEVEL_DEBUG]) \
+ dev_dbg(b2r2_log_dev, "DEBUG " __VA_ARGS__); \
+ } while (0)
+
+#define b2r2_log_regdump(...) \
+ do { \
+ if (b2r2_log_levels[B2R2_LOG_LEVEL_REGDUMP]) \
+ dev_dbg(b2r2_log_dev, "REGD " __VA_ARGS__); \
+ } while (0)
+
+int b2r2_debug_init(struct device *log_dev);
+void b2r2_debug_exit(void);
+
+#else
+
+#define b2r2_log_err(...)
+#define b2r2_log_warn(...)
+#define b2r2_log_info(...)
+#define b2r2_log_regdump(...)
+
+static inline int b2r2_debug_init(struct device *log_dev)
+{
+ return 0;
+}
+static inline void b2r2_debug_exit(void)
+{
+ return;
+}
+
+#endif
+
+#endif
diff --git a/drivers/video/b2r2/b2r2_filters.c b/drivers/video/b2r2/b2r2_filters.c
new file mode 100644
index 00000000000..208cdcd286e
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_filters.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 filters.
+ *
+ * Author: Fredrik Allansson <fredrik.allansson@stericsson.com> for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/dma-mapping.h>
+
+#include "b2r2_filters.h"
+#include "b2r2_internal.h"
+
+/**
+ * struct b2r2_filter_spec filters[] - Filter lookup table
+ *
+ * Lookup table for filters for different scale factors. A filter
+ * will be selected according to "min < scale_factor <= max".
+ */
+static struct b2r2_filter_spec filters[] = {
+ {
+ .min = 1024,
+ .max = 1433,
+ .h_coeffs = {
+ 0xfc, 0x06, 0xf9, 0x09, 0x34, 0x09, 0xf9, 0x06,
+ 0xfd, 0x07, 0xf7, 0x10, 0x32, 0x02, 0xfc, 0x05,
+ 0xfe, 0x07, 0xf6, 0x17, 0x2f, 0xfc, 0xff, 0x04,
+ 0xff, 0x06, 0xf5, 0x20, 0x2a, 0xf9, 0x01, 0x02,
+ 0x00, 0x04, 0xf6, 0x27, 0x25, 0xf6, 0x04, 0x00,
+ 0x02, 0x01, 0xf9, 0x2d, 0x1d, 0xf5, 0x06, 0xff,
+ 0x04, 0xff, 0xfd, 0x31, 0x15, 0xf5, 0x07, 0xfe,
+ 0x05, 0xfc, 0x02, 0x35, 0x0d, 0xf7, 0x07, 0xfd
+ },
+ .v_coeffs = {
+ 0xf8, 0x0a, 0x3c, 0x0a, 0xf8,
+ 0xf6, 0x12, 0x3b, 0x02, 0xfb,
+ 0xf4, 0x1b, 0x35, 0xfd, 0xff,
+ 0xf4, 0x23, 0x30, 0xf8, 0x01,
+ 0xf6, 0x29, 0x27, 0xf6, 0x04,
+ 0xf9, 0x2e, 0x1e, 0xf5, 0x06,
+ 0xfd, 0x31, 0x16, 0xf6, 0x06,
+ 0x02, 0x32, 0x0d, 0xf8, 0x07
+ },
+ },
+ {
+ .min = 1433,
+ .max = 1536,
+ .h_coeffs = {
+ 0xfe, 0x06, 0xf8, 0x0b, 0x30, 0x0b, 0xf8, 0x06,
+ 0xff, 0x06, 0xf7, 0x12, 0x2d, 0x05, 0xfa, 0x06,
+ 0x00, 0x04, 0xf6, 0x18, 0x2c, 0x00, 0xfc, 0x06,
+ 0x01, 0x02, 0xf7, 0x1f, 0x27, 0xfd, 0xff, 0x04,
+ 0x03, 0x00, 0xf9, 0x24, 0x24, 0xf9, 0x00, 0x03,
+ 0x04, 0xff, 0xfd, 0x29, 0x1d, 0xf7, 0x02, 0x01,
+ 0x06, 0xfc, 0x00, 0x2d, 0x17, 0xf6, 0x04, 0x00,
+ 0x06, 0xfa, 0x05, 0x30, 0x0f, 0xf7, 0x06, 0xff
+ },
+ .v_coeffs = {
+ 0xf6, 0x0e, 0x38, 0x0e, 0xf6,
+ 0xf5, 0x15, 0x38, 0x06, 0xf8,
+ 0xf5, 0x1d, 0x33, 0x00, 0xfb,
+ 0xf6, 0x23, 0x2d, 0xfc, 0xfe,
+ 0xf9, 0x28, 0x26, 0xf9, 0x00,
+ 0xfc, 0x2c, 0x1e, 0xf7, 0x03,
+ 0x00, 0x2e, 0x18, 0xf6, 0x04,
+ 0x05, 0x2e, 0x11, 0xf7, 0x05
+ },
+ },
+ {
+ .min = 1536,
+ .max = 3072,
+ .h_coeffs = {
+ 0xfc, 0xfd, 0x06, 0x13, 0x18, 0x13, 0x06, 0xfd,
+ 0xfc, 0xfe, 0x08, 0x15, 0x17, 0x12, 0x04, 0xfc,
+ 0xfb, 0xfe, 0x0a, 0x16, 0x18, 0x10, 0x03, 0xfc,
+ 0xfb, 0x00, 0x0b, 0x18, 0x17, 0x0f, 0x01, 0xfb,
+ 0xfb, 0x00, 0x0d, 0x19, 0x17, 0x0d, 0x00, 0xfb,
+ 0xfb, 0x01, 0x0f, 0x19, 0x16, 0x0b, 0x00, 0xfb,
+ 0xfc, 0x03, 0x11, 0x19, 0x15, 0x09, 0xfe, 0xfb,
+ 0xfc, 0x04, 0x12, 0x1a, 0x12, 0x08, 0xfe, 0xfc
+ },
+ .v_coeffs = {
+ 0x05, 0x10, 0x16, 0x10, 0x05,
+ 0x06, 0x11, 0x16, 0x0f, 0x04,
+ 0x08, 0x13, 0x15, 0x0e, 0x02,
+ 0x09, 0x14, 0x16, 0x0c, 0x01,
+ 0x0b, 0x15, 0x15, 0x0b, 0x00,
+ 0x0d, 0x16, 0x13, 0x0a, 0x00,
+ 0x0f, 0x17, 0x13, 0x08, 0xff,
+ 0x11, 0x18, 0x12, 0x07, 0xfe
+ },
+ },
+ {
+ .min = 3072,
+ .max = 4096,
+ .h_coeffs = {
+ 0xfe, 0x02, 0x09, 0x0f, 0x0e, 0x0f, 0x09, 0x02,
+ 0xff, 0x02, 0x09, 0x0f, 0x10, 0x0e, 0x08, 0x01,
+ 0xff, 0x03, 0x0a, 0x10, 0x10, 0x0d, 0x07, 0x00,
+ 0x00, 0x04, 0x0b, 0x10, 0x0f, 0x0c, 0x06, 0x00,
+ 0x00, 0x05, 0x0c, 0x10, 0x0e, 0x0c, 0x05, 0x00,
+ 0x00, 0x06, 0x0c, 0x11, 0x0e, 0x0b, 0x04, 0x00,
+ 0x00, 0x07, 0x0d, 0x11, 0x0f, 0x0a, 0x03, 0xff,
+ 0x01, 0x08, 0x0e, 0x11, 0x0e, 0x09, 0x02, 0xff
+ },
+ .v_coeffs = {
+ 0x09, 0x0f, 0x10, 0x0f, 0x09,
+ 0x09, 0x0f, 0x12, 0x0e, 0x08,
+ 0x0a, 0x10, 0x11, 0x0e, 0x07,
+ 0x0b, 0x11, 0x11, 0x0d, 0x06,
+ 0x0c, 0x11, 0x12, 0x0c, 0x05,
+ 0x0d, 0x12, 0x11, 0x0c, 0x04,
+ 0x0e, 0x12, 0x11, 0x0b, 0x04,
+ 0x0f, 0x13, 0x11, 0x0a, 0x03
+ },
+ },
+ {
+ .min = 4096,
+ .max = 5120,
+ .h_coeffs = {
+ 0x00, 0x04, 0x09, 0x0c, 0x0e, 0x0c, 0x09, 0x04,
+ 0x01, 0x05, 0x09, 0x0c, 0x0d, 0x0c, 0x08, 0x04,
+ 0x01, 0x05, 0x0a, 0x0c, 0x0e, 0x0b, 0x08, 0x03,
+ 0x02, 0x06, 0x0a, 0x0d, 0x0c, 0x0b, 0x07, 0x03,
+ 0x02, 0x07, 0x0a, 0x0d, 0x0d, 0x0a, 0x07, 0x02,
+ 0x03, 0x07, 0x0b, 0x0d, 0x0c, 0x0a, 0x06, 0x02,
+ 0x03, 0x08, 0x0b, 0x0d, 0x0d, 0x0a, 0x05, 0x01,
+ 0x04, 0x08, 0x0c, 0x0d, 0x0c, 0x09, 0x05, 0x01
+ },
+ .v_coeffs = {
+ 0x0a, 0x0e, 0x10, 0x0e, 0x0a,
+ 0x0b, 0x0e, 0x0f, 0x0e, 0x0a,
+ 0x0b, 0x0f, 0x10, 0x0d, 0x09,
+ 0x0c, 0x0f, 0x10, 0x0d, 0x08,
+ 0x0d, 0x0f, 0x0f, 0x0d, 0x08,
+ 0x0d, 0x10, 0x10, 0x0c, 0x07,
+ 0x0e, 0x10, 0x0f, 0x0c, 0x07,
+ 0x0f, 0x10, 0x10, 0x0b, 0x06
+ },
+ },
+};
+static const size_t filters_size = sizeof(filters)/sizeof(filters[0]);
+
+/**
+ * struct b2r2_filter_spec bilinear_filter - A bilinear filter
+ *
+ * The bilinear filter will be used if no custom filters are specified, or
+ * for upscales not matching any filter in the lookup table.
+ */
+static struct b2r2_filter_spec bilinear_filter = {
+ .min = 0,
+ .max = 0xffff,
+ .h_coeffs = {
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
+ 0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
+ 0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
+ 0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
+ 0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
+ 0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
+ 0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
+ },
+ .v_coeffs = {
+ 0x00, 0x00, 0x40, 0x00, 0x00,
+ 0xfd, 0x09, 0x3c, 0xfa, 0x04,
+ 0xf9, 0x13, 0x39, 0xf5, 0x06,
+ 0xf5, 0x1f, 0x31, 0xf3, 0x08,
+ 0xf3, 0x2a, 0x28, 0xf3, 0x08,
+ 0xf3, 0x34, 0x1d, 0xf5, 0x07,
+ 0xf5, 0x3b, 0x12, 0xf9, 0x05,
+ 0xfa, 0x3f, 0x07, 0xfd, 0x03
+ },
+};
+
+/**
+ * struct b2r2_filter_spec default_downscale_filter - Default filter for downscale
+ *
+ * The default downscale filter will be used for downscales not matching any
+ * filter in the lookup table.
+ */
+static struct b2r2_filter_spec default_downscale_filter = {
+ .min = 1 << 10,
+ .max = 0xffff,
+ .h_coeffs = {
+ 0x03, 0x06, 0x09, 0x0b, 0x09, 0x0b, 0x09, 0x06,
+ 0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05,
+ 0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05,
+ 0x04, 0x07, 0x09, 0x0b, 0x0b, 0x0a, 0x08, 0x04,
+ 0x04, 0x07, 0x0a, 0x0b, 0x0b, 0x0a, 0x07, 0x04,
+ 0x04, 0x08, 0x0a, 0x0b, 0x0b, 0x09, 0x07, 0x04,
+ 0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03,
+ 0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03
+ },
+ .v_coeffs = {
+ 0x0b, 0x0e, 0x0e, 0x0e, 0x0b,
+ 0x0b, 0x0e, 0x0f, 0x0d, 0x0b,
+ 0x0c, 0x0e, 0x0f, 0x0d, 0x0a,
+ 0x0c, 0x0e, 0x0f, 0x0d, 0x0a,
+ 0x0d, 0x0f, 0x0e, 0x0d, 0x09,
+ 0x0d, 0x0f, 0x0f, 0x0c, 0x09,
+ 0x0e, 0x0f, 0x0e, 0x0c, 0x09,
+ 0x0e, 0x0f, 0x0f, 0x0c, 0x08
+ },
+};
+
+/**
+ * struct b2r2_filter_spec blur_filter - Blur filter
+ *
+ * Filter for blurring an image.
+ */
+static struct b2r2_filter_spec blur_filter = {
+ .min = 0,
+ .max = 0xffff,
+ .h_coeffs = {
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
+ },
+ .v_coeffs = {
+ 0x0c, 0x0c, 0x10, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x10, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x10, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x10, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x10, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x10, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x10, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x10, 0x0c, 0x0c
+ },
+};
+
+/* Private function declarations */
+static int alloc_filter_coeffs(struct b2r2_filter_spec *filter);
+static void free_filter_coeffs(struct b2r2_filter_spec *filter);
+
+/* Public functions */
+
+static int filters_initialized;
+
+int b2r2_filters_init()
+{
+ int i;
+
+ if (filters_initialized)
+ return 0;
+
+ for (i = 0; i < filters_size; i++) {
+ alloc_filter_coeffs(&filters[i]);
+ }
+
+ alloc_filter_coeffs(&bilinear_filter);
+ alloc_filter_coeffs(&default_downscale_filter);
+ alloc_filter_coeffs(&blur_filter);
+
+ filters_initialized = 1;
+
+ return 0;
+}
+
+void b2r2_filters_exit()
+{
+ int i;
+
+ if (!filters_initialized)
+ return;
+
+ for (i = 0; i < filters_size; i++) {
+ free_filter_coeffs(&filters[i]);
+ }
+
+ free_filter_coeffs(&bilinear_filter);
+ free_filter_coeffs(&default_downscale_filter);
+ free_filter_coeffs(&blur_filter);
+
+ filters_initialized = 0;
+}
+
+struct b2r2_filter_spec *b2r2_filter_find(u16 scale_factor)
+{
+ int i;
+ struct b2r2_filter_spec *filter = NULL;
+
+ for (i = 0; i < filters_size; i++) {
+ if ((filters[i].min < scale_factor) &&
+ (scale_factor <= filters[i].max) &&
+ filters[i].h_coeffs_dma_addr &&
+ filters[i].v_coeffs_dma_addr) {
+ filter = &filters[i];
+ break;
+ }
+ }
+
+ if (filter == NULL) {
+ /*
+ * No suitable filter has been found. Use default filters,
+ * bilinear for any upscale.
+ */
+ if (scale_factor < (1 << 10))
+ filter = &bilinear_filter;
+ else
+ filter = &default_downscale_filter;
+ }
+
+ /*
+ * Check so that the coefficients were successfully allocated for this
+ * filter.
+ */
+ if (!filter->h_coeffs_dma_addr || !filter->v_coeffs_dma_addr)
+ return NULL;
+ else
+ return filter;
+}
+
+struct b2r2_filter_spec *b2r2_filter_blur()
+{
+ return &blur_filter;
+}
+
+/* Private functions */
+static int alloc_filter_coeffs(struct b2r2_filter_spec *filter)
+{
+ int ret;
+
+ filter->h_coeffs_dma_addr = dma_alloc_coherent(b2r2_blt_device(),
+ B2R2_HF_TABLE_SIZE, &(filter->h_coeffs_phys_addr),
+ GFP_DMA | GFP_KERNEL);
+ if (filter->h_coeffs_dma_addr == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ filter->v_coeffs_dma_addr = dma_alloc_coherent(b2r2_blt_device(),
+ B2R2_VF_TABLE_SIZE, &(filter->v_coeffs_phys_addr),
+ GFP_DMA | GFP_KERNEL);
+ if (filter->v_coeffs_dma_addr == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ memcpy(filter->h_coeffs_dma_addr, filter->h_coeffs, B2R2_HF_TABLE_SIZE);
+ memcpy(filter->v_coeffs_dma_addr, filter->v_coeffs, B2R2_VF_TABLE_SIZE);
+
+ return 0;
+
+error:
+ free_filter_coeffs(filter);
+ return ret;
+
+}
+
+static void free_filter_coeffs(struct b2r2_filter_spec *filter)
+{
+ if (filter->h_coeffs_dma_addr != NULL)
+ dma_free_coherent(b2r2_blt_device(), B2R2_HF_TABLE_SIZE,
+ filter->h_coeffs_dma_addr,
+ filter->h_coeffs_phys_addr);
+ if (filter->v_coeffs_dma_addr != NULL)
+ dma_free_coherent(b2r2_blt_device(), B2R2_VF_TABLE_SIZE,
+ filter->v_coeffs_dma_addr,
+ filter->v_coeffs_phys_addr);
+
+ filter->h_coeffs_dma_addr = NULL;
+ filter->h_coeffs_phys_addr = 0;
+ filter->v_coeffs_dma_addr = NULL;
+ filter->v_coeffs_phys_addr = 0;
+}
diff --git a/drivers/video/b2r2/b2r2_filters.h b/drivers/video/b2r2/b2r2_filters.h
new file mode 100644
index 00000000000..0eeefc6b0e0
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_filters.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 filters.
+ *
+ * Author: Fredrik Allansson <fredrik.allansson@stericsson.com> for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef _LINUX_VIDEO_B2R2_FILTERS_H
+#define _LINUX_VIDEO_B2R2_FILTERS_H
+
+#include <linux/kernel.h>
+
+#define B2R2_HF_TABLE_SIZE 64
+#define B2R2_VF_TABLE_SIZE 40
+
+/**
+ * @struct b2r2_filter_spec - Filter specification structure
+ *
+ * @param min - Minimum scale factor for this filter (in 6.10 fixed point)
+ * @param max - Maximum scale factor for this filter (in 6.10 fixed point)
+ * @param h_coeffs - Horizontal filter coefficients
+ * @param v_coeffs - Vertical filter coefficients
+ * @param h_coeffs_dma_addr - Virtual DMA address for horizontal coefficients
+ * @param v_coeffs_dma_addr - Virtual DMA address for vertical coefficients
+ * @param h_coeffs_phys_addr - Physical address for horizontal coefficients
+ * @param v_coeffs_phys_addr - Physical address for vertical coefficients
+ */
+struct b2r2_filter_spec {
+ const u16 min;
+ const u16 max;
+
+ const u8 h_coeffs[B2R2_HF_TABLE_SIZE];
+ const u8 v_coeffs[B2R2_VF_TABLE_SIZE];
+
+ void *h_coeffs_dma_addr;
+ u32 h_coeffs_phys_addr;
+
+ void *v_coeffs_dma_addr;
+ u32 v_coeffs_phys_addr;
+};
+
+/**
+ * b2r2_filters_init() - Initilizes the B2R2 filters
+ */
+int b2r2_filters_init(void);
+
+/**
+ * b2r2_filters_init() - De-initilizes the B2R2 filters
+ */
+void b2r2_filters_exit(void);
+
+/**
+ * b2r2_filter_find() - Find a filter matching the given scale factor
+ *
+ * @param scale_factor - Scale factor to find a filter for
+ *
+ * Returns NULL if no filter could be found.
+ */
+struct b2r2_filter_spec *b2r2_filter_find(u16 scale_factor);
+
+/**
+ * b2r2_filter_blur() - Returns the blur filter
+ *
+ * Returns NULL if no blur filter is available.
+ */
+struct b2r2_filter_spec *b2r2_filter_blur(void);
+
+#endif /* _LINUX_VIDEO_B2R2_FILTERS_H */
diff --git a/drivers/video/b2r2/b2r2_generic.c b/drivers/video/b2r2/b2r2_generic.c
new file mode 100644
index 00000000000..533de169409
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_generic.c
@@ -0,0 +1,2839 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 generic. Full coverage of user interface but
+ * non optimized implementation. For Fallback purposes.
+ *
+ * Author: Maciej Socha <maciej.socha@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+
+#include "b2r2_generic.h"
+#include "b2r2_internal.h"
+#include "b2r2_global.h"
+#include "b2r2_debug.h"
+#include "b2r2_filters.h"
+
+/*
+ * Debug printing
+ */
+#define B2R2_GENERIC_DEBUG_AREAS 0
+#define B2R2_GENERIC_DEBUG
+
+#define B2R2_GENERIC_WORK_BUF_WIDTH 16
+#define B2R2_GENERIC_WORK_BUF_HEIGHT 16
+#define B2R2_GENERIC_WORK_BUF_PITCH (16 * 4)
+#define B2R2_GENERIC_WORK_BUF_FMT B2R2_NATIVE_ARGB8888
+
+/*
+ * Private functions
+ */
+
+/**
+ * reset_nodes() - clears the node list
+ */
+static void reset_nodes(struct b2r2_node *node)
+{
+ b2r2_log_info("%s ENTRY\n", __func__);
+
+ while (node != NULL) {
+ memset(&(node->node), 0, sizeof(node->node));
+
+ /* TODO: Implement support for short linked lists */
+ node->node.GROUP0.B2R2_CIC = 0x7fffc;
+
+ if (node->next != NULL)
+ node->node.GROUP0.B2R2_NIP = node->next->physical_address;
+
+ node = node->next;
+ }
+ b2r2_log_info("%s DONE\n", __func__);
+}
+
+/**
+ * dump_nodes() - prints the node list
+ */
+static void dump_nodes(struct b2r2_node *first, bool dump_all)
+{
+ struct b2r2_node *node = first;
+ b2r2_log_info("%s ENTRY\n", __func__);
+ do {
+ b2r2_log_debug("\nNODE START:\n=============\n");
+ b2r2_log_debug("B2R2_ACK: \t0x%.8x\n",
+ node->node.GROUP0.B2R2_ACK);
+ b2r2_log_debug("B2R2_INS: \t0x%.8x\n",
+ node->node.GROUP0.B2R2_INS);
+ b2r2_log_debug("B2R2_CIC: \t0x%.8x\n",
+ node->node.GROUP0.B2R2_CIC);
+ b2r2_log_debug("B2R2_NIP: \t0x%.8x\n",
+ node->node.GROUP0.B2R2_NIP);
+
+ b2r2_log_debug("B2R2_TSZ: \t0x%.8x\n",
+ node->node.GROUP1.B2R2_TSZ);
+ b2r2_log_debug("B2R2_TXY: \t0x%.8x\n",
+ node->node.GROUP1.B2R2_TXY);
+ b2r2_log_debug("B2R2_TTY: \t0x%.8x\n",
+ node->node.GROUP1.B2R2_TTY);
+ b2r2_log_debug("B2R2_TBA: \t0x%.8x\n",
+ node->node.GROUP1.B2R2_TBA);
+
+ b2r2_log_debug("B2R2_S2CF: \t0x%.8x\n",
+ node->node.GROUP2.B2R2_S2CF);
+ b2r2_log_debug("B2R2_S1CF: \t0x%.8x\n",
+ node->node.GROUP2.B2R2_S1CF);
+
+ b2r2_log_debug("B2R2_S1SZ: \t0x%.8x\n",
+ node->node.GROUP3.B2R2_SSZ);
+ b2r2_log_debug("B2R2_S1XY: \t0x%.8x\n",
+ node->node.GROUP3.B2R2_SXY);
+ b2r2_log_debug("B2R2_S1TY: \t0x%.8x\n",
+ node->node.GROUP3.B2R2_STY);
+ b2r2_log_debug("B2R2_S1BA: \t0x%.8x\n",
+ node->node.GROUP3.B2R2_SBA);
+
+ b2r2_log_debug("B2R2_S2SZ: \t0x%.8x\n",
+ node->node.GROUP4.B2R2_SSZ);
+ b2r2_log_debug("B2R2_S2XY: \t0x%.8x\n",
+ node->node.GROUP4.B2R2_SXY);
+ b2r2_log_debug("B2R2_S2TY: \t0x%.8x\n",
+ node->node.GROUP4.B2R2_STY);
+ b2r2_log_debug("B2R2_S2BA: \t0x%.8x\n",
+ node->node.GROUP4.B2R2_SBA);
+
+ b2r2_log_debug("B2R2_S3SZ: \t0x%.8x\n",
+ node->node.GROUP5.B2R2_SSZ);
+ b2r2_log_debug("B2R2_S3XY: \t0x%.8x\n",
+ node->node.GROUP5.B2R2_SXY);
+ b2r2_log_debug("B2R2_S3TY: \t0x%.8x\n",
+ node->node.GROUP5.B2R2_STY);
+ b2r2_log_debug("B2R2_S3BA: \t0x%.8x\n",
+ node->node.GROUP5.B2R2_SBA);
+
+ b2r2_log_debug("B2R2_CWS: \t0x%.8x\n",
+ node->node.GROUP6.B2R2_CWS);
+ b2r2_log_debug("B2R2_CWO: \t0x%.8x\n",
+ node->node.GROUP6.B2R2_CWO);
+
+ b2r2_log_debug("B2R2_FCTL: \t0x%.8x\n",
+ node->node.GROUP8.B2R2_FCTL);
+ b2r2_log_debug("B2R2_RSF: \t0x%.8x\n",
+ node->node.GROUP9.B2R2_RSF);
+ b2r2_log_debug("B2R2_RZI: \t0x%.8x\n",
+ node->node.GROUP9.B2R2_RZI);
+ b2r2_log_debug("B2R2_HFP: \t0x%.8x\n",
+ node->node.GROUP9.B2R2_HFP);
+ b2r2_log_debug("B2R2_VFP: \t0x%.8x\n",
+ node->node.GROUP9.B2R2_VFP);
+ b2r2_log_debug("B2R2_LUMA_RSF: \t0x%.8x\n",
+ node->node.GROUP10.B2R2_RSF);
+ b2r2_log_debug("B2R2_LUMA_RZI: \t0x%.8x\n",
+ node->node.GROUP10.B2R2_RZI);
+ b2r2_log_debug("B2R2_LUMA_HFP: \t0x%.8x\n",
+ node->node.GROUP10.B2R2_HFP);
+ b2r2_log_debug("B2R2_LUMA_VFP: \t0x%.8x\n",
+ node->node.GROUP10.B2R2_VFP);
+
+
+ b2r2_log_debug("B2R2_IVMX0: \t0x%.8x\n",
+ node->node.GROUP15.B2R2_VMX0);
+ b2r2_log_debug("B2R2_IVMX1: \t0x%.8x\n",
+ node->node.GROUP15.B2R2_VMX1);
+ b2r2_log_debug("B2R2_IVMX2: \t0x%.8x\n",
+ node->node.GROUP15.B2R2_VMX2);
+ b2r2_log_debug("B2R2_IVMX3: \t0x%.8x\n",
+ node->node.GROUP15.B2R2_VMX3);
+ b2r2_log_debug("\n=============\nNODE END\n");
+
+ node = node->next;
+ } while (node != NULL && dump_all);
+
+ b2r2_log_info("%s DONE\n", __func__);
+}
+
+/**
+ * to_native_fmt() - returns the native B2R2 format
+ */
+static inline enum b2r2_native_fmt to_native_fmt(enum b2r2_blt_fmt fmt)
+{
+
+ switch (fmt) {
+ case B2R2_BLT_FMT_UNUSED:
+ return B2R2_NATIVE_RGB565;
+ case B2R2_BLT_FMT_1_BIT_A1:
+ return B2R2_NATIVE_A1;
+ case B2R2_BLT_FMT_8_BIT_A8:
+ return B2R2_NATIVE_A8;
+ case B2R2_BLT_FMT_16_BIT_RGB565:
+ return B2R2_NATIVE_RGB565;
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ return B2R2_NATIVE_ARGB4444;
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ return B2R2_NATIVE_ARGB1555;
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ return B2R2_NATIVE_ARGB8565;
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ return B2R2_NATIVE_RGB888;
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ return B2R2_NATIVE_YCBCR888;
+ case B2R2_BLT_FMT_32_BIT_ABGR8888: /* Not actually supported by HW */
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ return B2R2_NATIVE_ARGB8888;
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ return B2R2_NATIVE_AYCBCR8888;
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ return B2R2_NATIVE_YCBCR422R;
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ return B2R2_NATIVE_YCBCR422R;
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ return B2R2_NATIVE_YCBCR42X_R2B;
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ return B2R2_NATIVE_YCBCR42X_MBN;
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ return B2R2_NATIVE_YUV;
+ default:
+ /* Should never ever happen */
+ return B2R2_NATIVE_BYTE;
+ }
+}
+
+/**
+ * get_alpha_range() - returns the alpha range of the given format
+ */
+static inline enum b2r2_ty get_alpha_range(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ case B2R2_BLT_FMT_8_BIT_A8:
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ return B2R2_TY_ALPHA_RANGE_255; /* 0 - 255 */
+ break;
+ default:
+ break;
+ }
+
+ return B2R2_TY_ALPHA_RANGE_128; /* 0 - 128 */
+}
+
+static unsigned int get_pitch(enum b2r2_blt_fmt format, u32 width)
+{
+ switch (format) {
+ case B2R2_BLT_FMT_1_BIT_A1: {
+ int pitch = width >> 3;
+ /* Check for remainder */
+ if (width & 7)
+ pitch++;
+ return pitch;
+ break;
+ }
+ case B2R2_BLT_FMT_8_BIT_A8:
+ return width;
+ break;
+ case B2R2_BLT_FMT_16_BIT_RGB565: /* all 16 bits/pixel RGB formats */
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ return width * 2;
+ break;
+ case B2R2_BLT_FMT_24_BIT_RGB888: /* all 24 bits/pixel RGB formats */
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ return width * 3;
+ break;
+ case B2R2_BLT_FMT_32_BIT_ARGB8888: /* all 32 bits/pixel RGB formats */
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ return width * 4;
+ break;
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ return width * 4;
+ break;
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ /* width of the buffer must be a multiple of 4 */
+ if (width & 3) {
+ b2r2_log_warn("%s: Illegal width "
+ "for fmt=%#010x width=%d\n", __func__,
+ format, width);
+ return 0;
+ }
+ return width * 2;
+ break;
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ return width;
+ break;
+ /* fall through, same pitch and pointers */
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ /* width of the buffer must be a multiple of 2 */
+ if (width & 1) {
+ b2r2_log_warn("%s: Illegal width "
+ "for fmt=%#010x width=%d\n", __func__,
+ format, width);
+ return 0;
+ }
+ /*
+ * return pitch of the Y-buffer.
+ * U and V pitch can be derived from it.
+ */
+ return width;
+ break;
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ /* width of the buffer must be a multiple of 16. */
+ if (width & 15) {
+ b2r2_log_warn("%s: Illegal width "
+ "for fmt=%#010x width=%d\n", __func__,
+ format, width);
+ return 0;
+ }
+ /*
+ * return pitch of the Y-buffer.
+ * U and V pitch can be derived from it.
+ */
+ return width;
+ break;
+ default:
+ b2r2_log_warn("%s: Unable to determine pitch "
+ "for fmt=%#010x width=%d\n", __func__,
+ format, width);
+ return 0;
+ }
+}
+
+static s32 validate_buf(const struct b2r2_blt_img *image,
+ const struct b2r2_resolved_buf *buf)
+{
+ u32 expect_buf_size;
+ u32 pitch;
+
+ if (image->width <= 0 || image->height <= 0) {
+ b2r2_log_warn("%s: width=%d or height=%d negative.\n", __func__,
+ image->width, image->height);
+ return -EINVAL;
+ }
+
+ if (image->pitch == 0) {
+ /* autodetect pitch based on format and width */
+ pitch = get_pitch(image->fmt, image->width);
+ } else
+ pitch = image->pitch;
+
+ expect_buf_size = pitch * image->height;
+
+ if (pitch == 0) {
+ b2r2_log_warn("%s: Unable to detect pitch. "
+ "fmt=%#010x, width=%d\n",
+ __func__,
+ image->fmt, image->width);
+ return -EINVAL;
+ }
+
+ /* format specific adjustments */
+ switch (image->fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ /*
+ * Use ceil(height/2) in case buffer height
+ * is not divisible by 2.
+ */
+ expect_buf_size +=
+ (pitch >> 1) * ((image->height + 1) >> 1) * 2;
+ break;
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ expect_buf_size += (pitch >> 1) * image->height * 2;
+ break;
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ expect_buf_size += pitch * image->height * 2;
+ break;
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ /*
+ * include space occupied by U and V data.
+ * U and V interleaved, half resolution, which makes
+ * the UV pitch equal to luma pitch.
+ * Use ceil(height/2) in case buffer height
+ * is not divisible by 2.
+ */
+ expect_buf_size += pitch * ((image->height + 1) >> 1);
+ break;
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ /*
+ * include space occupied by U and V data.
+ * U and V interleaved, half resolution, which makes
+ * the UV pitch equal to luma pitch.
+ */
+ expect_buf_size += pitch * image->height;
+ break;
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ /* Height must be a multiple of 16 for macro-block format.*/
+ if (image->height & 15) {
+ b2r2_log_warn("%s: Illegal height "
+ "for fmt=%#010x height=%d\n", __func__,
+ image->fmt, image->height);
+ return -EINVAL;
+ }
+ expect_buf_size += pitch * (image->height >> 1);
+ break;
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ /* Height must be a multiple of 16 for macro-block format.*/
+ if (image->height & 15) {
+ b2r2_log_warn("%s: Illegal height "
+ "for fmt=%#010x height=%d\n", __func__,
+ image->fmt, image->height);
+ return -EINVAL;
+ }
+ expect_buf_size += pitch * image->height;
+ break;
+ default:
+ break;
+ }
+
+ if (buf->file_len < expect_buf_size) {
+ b2r2_log_warn("%s: Invalid buffer size:\n"
+ "fmt=%#010x w=%d h=%d buf.len=%d expect_buf_size=%d\n",
+ __func__,
+ image->fmt, image->width, image->height, buf->file_len,
+ expect_buf_size);
+ return -EINVAL;
+ }
+
+ if (image->buf.type == B2R2_BLT_PTR_VIRTUAL) {
+ b2r2_log_warn("%s: Virtual pointers not supported yet.\n",
+ __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * Bit-expand the color from fmt to RGB888 with blue at LSB.
+ * Copy MSBs into missing LSBs.
+ */
+static u32 to_RGB888(u32 color, const enum b2r2_blt_fmt fmt)
+{
+ u32 out_color = 0;
+ u32 r = 0;
+ u32 g = 0;
+ u32 b = 0;
+ switch (fmt) {
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ r = ((color & 0xf00) << 12) | ((color & 0xf00) << 8);
+ g = ((color & 0xf0) << 8) | ((color & 0xf0) << 4);
+ b = ((color & 0xf) << 4) | (color & 0xf);
+ out_color = r | g | b;
+ break;
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ r = ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
+ g = ((color & 0x3e0) << 6) | ((color & 0x380) << 1);
+ b = ((color & 0x1f) << 3) | ((color & 0x1c) >> 2);
+ out_color = r | g | b;
+ break;
+ case B2R2_BLT_FMT_16_BIT_RGB565:
+ r = ((color & 0xf800) << 8) | ((color & 0xe000) << 3);
+ g = ((color & 0x7e0) << 5) | ((color & 0x600) >> 1);
+ b = ((color & 0x1f) << 3) | ((color & 0x1c) >> 2);
+ out_color = r | g | b;
+ break;
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ out_color = color & 0xffffff;
+ break;
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ r = (color & 0xff) << 16;
+ g = color & 0xff00;
+ b = (color & 0xff0000) >> 16;
+ out_color = r | g | b;
+ break;
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ r = ((color & 0xf800) << 8) | ((color & 0xe000) << 3);
+ g = ((color & 0x7e0) << 5) | ((color & 0x600) >> 1);
+ b = ((color & 0x1f) << 3) | ((color & 0x1c) >> 2);
+ out_color = r | g | b;
+ break;
+ default:
+ break;
+ }
+
+ return out_color;
+}
+
+static void setup_input_stage(const struct b2r2_blt_request *req,
+ struct b2r2_node *node,
+ struct b2r2_work_buf *out_buf)
+{
+ /* Horizontal and vertical scaling factors in 6.10 fixed point format */
+ s32 h_scf = 1 << 10;
+ s32 v_scf = 1 << 10;
+ const struct b2r2_blt_rect *src_rect = &(req->user_req.src_rect);
+ const struct b2r2_blt_rect *dst_rect = &(req->user_req.dst_rect);
+ const struct b2r2_blt_img *src_img = &(req->user_req.src_img);
+ const struct b2r2_blt_img *dst_img = &(req->user_req.dst_img);
+ u32 src_pitch = 0;
+ /* horizontal and vertical scan order for out_buf */
+ enum b2r2_ty dst_hso = B2R2_TY_HSO_LEFT_TO_RIGHT;
+ enum b2r2_ty dst_vso = B2R2_TY_VSO_TOP_TO_BOTTOM;
+ u32 fctl = 0;
+ u32 rsf = 0;
+ u32 rzi = 0;
+ bool yuv_semi_planar =
+ src_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR ||
+ src_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR ||
+ src_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE ||
+ src_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE;
+
+ bool yuv_planar =
+ src_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR ||
+ src_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR ||
+ src_img->fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR;
+
+ struct b2r2_filter_spec *hf;
+ struct b2r2_filter_spec *vf;
+
+ bool use_h_filter = false;
+ bool use_v_filter = false;
+
+ b2r2_log_info("%s ENTRY\n", __func__);
+
+ if ((req->user_req.flags &
+ (B2R2_BLT_FLAG_SOURCE_FILL | B2R2_BLT_FLAG_SOURCE_FILL_RAW)) != 0) {
+ enum b2r2_native_fmt fill_fmt = 0;
+ u32 src_color = req->user_req.src_color;
+
+ /* Determine format in src_color */
+ switch (dst_img->fmt) {
+ /* ARGB formats */
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ case B2R2_BLT_FMT_16_BIT_RGB565:
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_1_BIT_A1:
+ case B2R2_BLT_FMT_8_BIT_A8:
+ if ((req->user_req.flags & B2R2_BLT_FLAG_SOURCE_FILL) != 0) {
+ fill_fmt = B2R2_NATIVE_ARGB8888;
+ } else {
+ /* SOURCE_FILL_RAW */
+ fill_fmt = to_native_fmt(dst_img->fmt);
+ if (dst_img->fmt == B2R2_BLT_FMT_32_BIT_ABGR8888) {
+ /*
+ * Color is read from a register,
+ * where it is stored in ABGR format.
+ * Set up IVMX.
+ */
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_IVMX_ENABLED;
+ node->node.GROUP0.B2R2_CIC |=
+ B2R2_CIC_IVMX;
+ node->node.GROUP15.B2R2_VMX0 =
+ B2R2_VMX0_RGB_TO_BGR;
+ node->node.GROUP15.B2R2_VMX1 =
+ B2R2_VMX1_RGB_TO_BGR;
+ node->node.GROUP15.B2R2_VMX2 =
+ B2R2_VMX2_RGB_TO_BGR;
+ node->node.GROUP15.B2R2_VMX3 =
+ B2R2_VMX3_RGB_TO_BGR;
+ }
+ }
+ break;
+ /* YUV formats */
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ /*
+ * Set up IVMX
+ * The destination format is in fact YUV,
+ * but the input stage stores the data in
+ * an intermediate buffer which is RGB.
+ * Hence the conversion from YUV to RGB.
+ */
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX;
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_YUV_TO_RGB_601_VIDEO;
+
+ if ((req->user_req.flags & B2R2_BLT_FLAG_SOURCE_FILL) != 0) {
+ fill_fmt = B2R2_NATIVE_AYCBCR8888;
+ } else {
+ /* SOURCE_FILL_RAW */
+ bool dst_yuv_planar =
+ dst_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR ||
+ dst_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR ||
+ dst_img->fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR;
+
+ bool dst_yuv_semi_planar =
+ dst_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR ||
+ dst_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR ||
+ dst_img->fmt ==
+ B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE ||
+ dst_img->fmt ==
+ B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE;
+
+ if (dst_yuv_planar || dst_yuv_semi_planar) {
+ /*
+ * SOURCE_FILL_RAW cannot be supported
+ * with multi-buffer formats.
+ * Force a legal format to prevent B2R2
+ * from misbehaving.
+ */
+ fill_fmt = B2R2_NATIVE_AYCBCR8888;
+ } else {
+ fill_fmt = to_native_fmt(dst_img->fmt);
+ }
+
+ if (dst_img->fmt == B2R2_BLT_FMT_Y_CB_Y_CR) {
+ /*
+ * Setup input VMX to convert YVU to
+ * RGB 601 VIDEO
+ * Chroma components are swapped so
+ * it is YVU and not YUV.
+ */
+ node->node.GROUP15.B2R2_VMX0 =
+ B2R2_VMX0_YVU_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 =
+ B2R2_VMX1_YVU_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 =
+ B2R2_VMX2_YVU_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 =
+ B2R2_VMX3_YVU_TO_RGB_601_VIDEO;
+ }
+ }
+ break;
+ default:
+ src_color = 0;
+ fill_fmt = B2R2_NATIVE_ARGB8888;
+ break;
+ }
+
+ node->node.GROUP1.B2R2_TBA = out_buf->phys_addr;
+ node->node.GROUP1.B2R2_TTY =
+ (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ B2R2_GENERIC_WORK_BUF_FMT |
+ B2R2_TY_ALPHA_RANGE_255 |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+ /* Set color fill on SRC2 channel */
+ node->node.GROUP4.B2R2_SBA = 0;
+ node->node.GROUP4.B2R2_STY =
+ (0 << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ fill_fmt |
+ get_alpha_range(dst_img->fmt) |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_SOURCE_2_COLOR_FILL_REGISTER;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_COLOR_FILL;
+ node->node.GROUP2.B2R2_S2CF = src_color;
+
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3;
+
+ b2r2_log_info("%s DONE\n", __func__);
+ return;
+ }
+
+ if (src_img->pitch == 0) {
+ /* Determine pitch based on format and width of the image. */
+ src_pitch = get_pitch(src_img->fmt, src_img->width);
+ } else {
+ src_pitch = src_img->pitch;
+ }
+
+ b2r2_log_info("%s transform=%#010x\n",
+ __func__, req->user_req.transform);
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) {
+ h_scf = (src_rect->width << 10) / dst_rect->height;
+ v_scf = (src_rect->height << 10) / dst_rect->width;
+ } else {
+ h_scf = (src_rect->width << 10) / dst_rect->width;
+ v_scf = (src_rect->height << 10) / dst_rect->height;
+ }
+
+ hf = b2r2_filter_find(h_scf);
+ vf = b2r2_filter_find(v_scf);
+
+ use_h_filter = h_scf != (1 << 10);
+ use_v_filter = v_scf != (1 << 10);
+
+ /* B2R2_BLT_FLAG_BLUR overrides any scaling filter. */
+ if (req->user_req.flags & B2R2_BLT_FLAG_BLUR) {
+ use_h_filter = true;
+ use_v_filter = true;
+ hf = b2r2_filter_blur();
+ vf = b2r2_filter_blur();
+ }
+
+ /* Configure horizontal rescale */
+ if (h_scf != (1 << 10)) {
+ b2r2_log_info("%s: Scaling horizontally by 0x%.8x"
+ "\ns(%d, %d)->d(%d, %d)\n", __func__,
+ h_scf, src_rect->width, src_rect->height,
+ dst_rect->width, dst_rect->height);
+ }
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER;
+ rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT);
+ rsf |= h_scf << B2R2_RSF_HSRC_INC_SHIFT;
+ rzi |= B2R2_RZI_DEFAULT_HNB_REPEAT;
+
+ /* Configure vertical rescale */
+ if (v_scf != (1 << 10)) {
+ b2r2_log_info("%s: Scaling vertically by 0x%.8x"
+ "\ns(%d, %d)->d(%d, %d)\n", __func__,
+ v_scf, src_rect->width, src_rect->height,
+ dst_rect->width, dst_rect->height);
+ }
+ fctl |= B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER;
+ rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT);
+ rsf |= v_scf << B2R2_RSF_VSRC_INC_SHIFT;
+ rzi |= 2 << B2R2_RZI_VNB_REPEAT_SHIFT;
+
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_RESCALE2D_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_RESIZE_CHROMA;
+
+ /* Adjustments that depend on the source format */
+ switch (src_img->fmt) {
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ /* Set up IVMX */
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX;
+
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_RGB_TO_BGR;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_RGB_TO_BGR;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_RGB_TO_BGR;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_BGR;
+ break;
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ /* Set up IVMX */
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX;
+ if (src_img->fmt == B2R2_BLT_FMT_Y_CB_Y_CR) {
+ /*
+ * Setup input VMX to convert YVU to RGB 601 VIDEO
+ * Chroma components are swapped so it is YVU and not YUV.
+ */
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_YVU_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_YVU_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_YVU_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_YVU_TO_RGB_601_VIDEO;
+ } else {
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_YUV_TO_RGB_601_VIDEO;
+ }
+ break;
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: {
+ /*
+ * Luma handled in the same way
+ * for all YUV multi-buffer formats.
+ * Set luma rescale registers.
+ */
+ u32 rsf_luma = 0;
+ u32 rzi_luma = 0;
+
+ /* Set up IVMX */
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_IVMX_ENABLED | B2R2_INS_RESCALE2D_ENABLED;
+ node->node.GROUP0.B2R2_CIC |=
+ B2R2_CIC_IVMX | B2R2_CIC_RESIZE_LUMA;
+
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_YUV_TO_RGB_601_VIDEO;
+
+ fctl |= B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_RESIZER |
+ B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_RESIZER;
+
+ if (use_h_filter && hf) {
+ fctl |= B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_FILTER;
+ node->node.GROUP10.B2R2_HFP = hf->h_coeffs_phys_addr;
+ }
+
+ if (use_v_filter && vf) {
+ fctl |= B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_FILTER;
+ node->node.GROUP10.B2R2_VFP = vf->v_coeffs_phys_addr;
+ }
+
+ rsf_luma |= h_scf << B2R2_RSF_HSRC_INC_SHIFT;
+ rzi_luma |= B2R2_RZI_DEFAULT_HNB_REPEAT;
+
+ rsf_luma |= v_scf << B2R2_RSF_VSRC_INC_SHIFT;
+ rzi_luma |= 2 << B2R2_RZI_VNB_REPEAT_SHIFT;
+
+ node->node.GROUP10.B2R2_RSF = rsf_luma;
+ node->node.GROUP10.B2R2_RZI = rzi_luma;
+
+ switch (src_img->fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ /*
+ * Chrominance is always half the luminance size
+ * so chrominance resizer is always active.
+ */
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER |
+ B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER;
+
+ rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT);
+ rsf |= (h_scf >> 1) << B2R2_RSF_HSRC_INC_SHIFT;
+ rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT);
+ rsf |= (v_scf >> 1) << B2R2_RSF_VSRC_INC_SHIFT;
+ /* Select suitable filter for chroma */
+ hf = b2r2_filter_find(h_scf >> 1);
+ vf = b2r2_filter_find(v_scf >> 1);
+ use_h_filter = true;
+ use_v_filter = true;
+ break;
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ /*
+ * Chrominance is always half the luminance size
+ * only in horizontal direction.
+ */
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER |
+ B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER;
+
+ rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT);
+ rsf |= (h_scf >> 1) << B2R2_RSF_HSRC_INC_SHIFT;
+ rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT);
+ rsf |= v_scf << B2R2_RSF_VSRC_INC_SHIFT;
+ /* Select suitable filter for chroma */
+ hf = b2r2_filter_find(h_scf >> 1);
+ use_h_filter = true;
+ break;
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ /* Chrominance is the same size as luminance.*/
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER |
+ B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER;
+
+ rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT);
+ rsf |= h_scf << B2R2_RSF_HSRC_INC_SHIFT;
+ rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT);
+ rsf |= v_scf << B2R2_RSF_VSRC_INC_SHIFT;
+ /* Select suitable filter for chroma */
+ hf = b2r2_filter_find(h_scf);
+ vf = b2r2_filter_find(v_scf);
+ use_h_filter = true;
+ use_v_filter = true;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ /*
+ * Set the filter control and rescale registers.
+ * GROUP9 registers are used for all single-buffer formats
+ * or for chroma in case of multi-buffer YUV formats.
+ * h/v_filter is now appropriately selected for chroma scaling,
+ * be it YUV multi-buffer, or single-buffer raster format.
+ * B2R2_BLT_FLAG_BLUR overrides any scaling filter.
+ */
+ if (req->user_req.flags & B2R2_BLT_FLAG_BLUR) {
+ use_h_filter = true;
+ use_v_filter = true;
+ hf = b2r2_filter_blur();
+ vf = b2r2_filter_blur();
+ }
+
+ if (use_h_filter && hf) {
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_COLOR_CHANNEL_FILTER;
+ node->node.GROUP9.B2R2_HFP = hf->h_coeffs_phys_addr;
+ }
+
+ if (use_v_filter && vf) {
+ fctl |= B2R2_FCTL_VF2D_MODE_ENABLE_COLOR_CHANNEL_FILTER;
+ node->node.GROUP9.B2R2_VFP = vf->v_coeffs_phys_addr;
+ }
+
+ node->node.GROUP8.B2R2_FCTL |= fctl;
+ node->node.GROUP9.B2R2_RSF |= rsf;
+ node->node.GROUP9.B2R2_RZI |= rzi;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_FILTER_CONTROL;
+
+ /*
+ * Flip transform is done before potential rotation.
+ * This can be achieved with appropriate scan order.
+ * Transform stage will only do rotation.
+ */
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_H)
+ dst_hso = B2R2_TY_HSO_RIGHT_TO_LEFT;
+
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_V)
+ dst_vso = B2R2_TY_VSO_BOTTOM_TO_TOP;
+
+ /* Set target buffer */
+ node->node.GROUP1.B2R2_TBA = out_buf->phys_addr;
+ node->node.GROUP1.B2R2_TTY =
+ (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ B2R2_GENERIC_WORK_BUF_FMT |
+ B2R2_TY_ALPHA_RANGE_255 |
+ dst_hso | dst_vso;
+
+ if (yuv_planar) {
+ /*
+ * Set up chrominance buffers on source 1 and 2,
+ * luminance on source 3.
+ * src_pitch and physical_address apply to luminance,
+ * corresponding chrominance values have to be derived.
+ */
+ u32 cb_addr = req->src_resolved.physical_address +
+ src_pitch * src_img->height;
+ u32 cr_addr = 0;
+ u32 chroma_pitch = 0;
+ enum b2r2_native_fmt src_fmt = to_native_fmt(src_img->fmt);
+
+ switch (src_img->fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ chroma_pitch = src_pitch >> 1;
+ cr_addr =
+ cb_addr + chroma_pitch * (src_img->height >> 1);
+ break;
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ chroma_pitch = src_pitch >> 1;
+ cr_addr =
+ cb_addr + chroma_pitch * src_img->height;
+ break;
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ /* Chrominance has full resolution, same as luminance.*/
+ chroma_pitch = src_pitch;
+ cr_addr =
+ cb_addr + chroma_pitch * src_img->height;
+ break;
+ default:
+ break;
+ }
+
+ node->node.GROUP3.B2R2_SBA = cr_addr;
+ node->node.GROUP3.B2R2_STY =
+ (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ src_fmt |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP4.B2R2_SBA = cb_addr;
+ node->node.GROUP4.B2R2_STY = node->node.GROUP3.B2R2_STY;
+
+ node->node.GROUP5.B2R2_SBA = req->src_resolved.physical_address;
+ node->node.GROUP5.B2R2_STY =
+ (src_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ src_fmt |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_SOURCE_1_FETCH_FROM_MEM |
+ B2R2_INS_SOURCE_2_FETCH_FROM_MEM |
+ B2R2_INS_SOURCE_3_FETCH_FROM_MEM;
+ node->node.GROUP0.B2R2_CIC |=
+ B2R2_CIC_SOURCE_1 | B2R2_CIC_SOURCE_2 | B2R2_CIC_SOURCE_3;
+ } else if (yuv_semi_planar) {
+ /*
+ * Set up chrominance buffer on source 2, luminance on source 3.
+ * src_pitch and physical_address apply to luminance,
+ * corresponding chrominance values have to be derived.
+ * U and V are interleaved at half the luminance resolution,
+ * which makes the pitch of the UV plane equal
+ * to luminance pitch.
+ */
+ u32 chroma_addr = req->src_resolved.physical_address +
+ src_pitch * src_img->height;
+ u32 chroma_pitch = src_pitch;
+
+ enum b2r2_native_fmt src_fmt = to_native_fmt(src_img->fmt);
+
+ node->node.GROUP4.B2R2_SBA = chroma_addr;
+ node->node.GROUP4.B2R2_STY =
+ (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ src_fmt |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP5.B2R2_SBA = req->src_resolved.physical_address;
+ node->node.GROUP5.B2R2_STY =
+ (src_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ src_fmt |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_SOURCE_2_FETCH_FROM_MEM |
+ B2R2_INS_SOURCE_3_FETCH_FROM_MEM;
+ node->node.GROUP0.B2R2_CIC |=
+ B2R2_CIC_SOURCE_2 | B2R2_CIC_SOURCE_3;
+ } else {
+ /* single buffer format */
+ node->node.GROUP4.B2R2_SBA = req->src_resolved.physical_address;
+ node->node.GROUP4.B2R2_STY =
+ (src_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ to_native_fmt(src_img->fmt) |
+ get_alpha_range(src_img->fmt) |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_2_FETCH_FROM_MEM;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2;
+ }
+
+ if ((req->user_req.flags &
+ B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) != 0) {
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_CLUTOP_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_CLUT;
+ node->node.GROUP7.B2R2_CCO = B2R2_CCO_CLUT_COLOR_CORRECTION |
+ B2R2_CCO_CLUT_UPDATE;
+ node->node.GROUP7.B2R2_CML = req->clut_phys_addr;
+ }
+
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3;
+
+ b2r2_log_info("%s DONE\n", __func__);
+}
+
+static void setup_transform_stage(const struct b2r2_blt_request *req,
+ struct b2r2_node *node,
+ struct b2r2_work_buf *out_buf,
+ struct b2r2_work_buf *in_buf)
+{
+ /* vertical scan order for out_buf */
+ enum b2r2_ty dst_vso = B2R2_TY_VSO_TOP_TO_BOTTOM;
+ enum b2r2_blt_transform transform = req->user_req.transform;
+
+ b2r2_log_info("%s ENTRY\n", __func__);
+
+ if (transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) {
+ /*
+ * Scan order must be flipped otherwise contents will
+ * be mirrored vertically. Leftmost column of in_buf
+ * would become top instead of bottom row of out_buf.
+ */
+ dst_vso = B2R2_TY_VSO_BOTTOM_TO_TOP;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_ROTATION_ENABLED;
+ }
+
+ /* Set target buffer */
+ node->node.GROUP1.B2R2_TBA = out_buf->phys_addr;
+ node->node.GROUP1.B2R2_TTY =
+ (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ B2R2_GENERIC_WORK_BUF_FMT |
+ B2R2_TY_ALPHA_RANGE_255 |
+ B2R2_TY_HSO_LEFT_TO_RIGHT | dst_vso;
+
+ /* Set source buffer on SRC2 channel */
+ node->node.GROUP4.B2R2_SBA = in_buf->phys_addr;
+ node->node.GROUP4.B2R2_STY =
+ (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ B2R2_GENERIC_WORK_BUF_FMT |
+ B2R2_TY_ALPHA_RANGE_255 |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_2_FETCH_FROM_MEM;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2;
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3;
+
+ b2r2_log_info("%s DONE\n", __func__);
+}
+
+/*
+static void setup_mask_stage(const struct b2r2_blt_request req,
+ struct b2r2_node *node,
+ struct b2r2_work_buf *out_buf,
+ struct b2r2_work_buf *in_buf);
+*/
+
+static void setup_dst_read_stage(const struct b2r2_blt_request *req,
+ struct b2r2_node *node,
+ struct b2r2_work_buf *out_buf)
+{
+ const struct b2r2_blt_img *dst_img = &(req->user_req.dst_img);
+ u32 fctl = 0;
+ u32 rsf = 0;
+ bool yuv_semi_planar =
+ dst_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR ||
+ dst_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR ||
+ dst_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE ||
+ dst_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE;
+
+ bool yuv_planar =
+ dst_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR ||
+ dst_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR ||
+ dst_img->fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR;
+
+ u32 dst_pitch = 0;
+ if (dst_img->pitch == 0) {
+ /* Determine pitch based on format and width of the image. */
+ dst_pitch = get_pitch(dst_img->fmt, dst_img->width);
+ } else {
+ dst_pitch = dst_img->pitch;
+ }
+
+ b2r2_log_info("%s ENTRY\n", __func__);
+
+ /* Adjustments that depend on the destination format */
+ switch (dst_img->fmt) {
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ /* Set up IVMX */
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX;
+
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_RGB_TO_BGR;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_RGB_TO_BGR;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_RGB_TO_BGR;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_BGR;
+ break;
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ /* Set up IVMX */
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX;
+ if (dst_img->fmt == B2R2_BLT_FMT_Y_CB_Y_CR) {
+ /*
+ * Setup input VMX to convert YVU to RGB 601 VIDEO
+ * Chroma components are swapped
+ * so it is YVU and not YUV.
+ */
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_YVU_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_YVU_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_YVU_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_YVU_TO_RGB_601_VIDEO;
+ } else {
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_YUV_TO_RGB_601_VIDEO;
+ }
+ break;
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: {
+ /* Set up IVMX */
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX;
+
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_YUV_TO_RGB_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_YUV_TO_RGB_601_VIDEO;
+
+ switch (dst_img->fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ /*
+ * Chrominance is always half the luminance size
+ * so chrominance resizer is always active.
+ */
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER |
+ B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER;
+
+ rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT);
+ rsf |= (1 << 9) << B2R2_RSF_HSRC_INC_SHIFT;
+ rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT);
+ rsf |= (1 << 9) << B2R2_RSF_VSRC_INC_SHIFT;
+ break;
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ /*
+ * Chrominance is always half the luminance size
+ * only in horizontal direction.
+ */
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER;
+
+ rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT);
+ rsf |= (1 << 9) << B2R2_RSF_HSRC_INC_SHIFT;
+ rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT);
+ rsf |= (1 << 10) << B2R2_RSF_VSRC_INC_SHIFT;
+ break;
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ /* Chrominance is the same size as luminance.*/
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER |
+ B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER;
+
+ rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT);
+ rsf |= (1 << 10) << B2R2_RSF_HSRC_INC_SHIFT;
+ rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT);
+ rsf |= (1 << 10) << B2R2_RSF_VSRC_INC_SHIFT;
+ break;
+ default:
+ break;
+ }
+ /* Set the filter control and rescale registers for chroma */
+ node->node.GROUP8.B2R2_FCTL |= fctl;
+ node->node.GROUP9.B2R2_RSF |= rsf;
+ node->node.GROUP9.B2R2_RZI =
+ B2R2_RZI_DEFAULT_HNB_REPEAT |
+ (2 << B2R2_RZI_VNB_REPEAT_SHIFT);
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_RESCALE2D_ENABLED;
+ node->node.GROUP0.B2R2_CIC |=
+ B2R2_CIC_FILTER_CONTROL | B2R2_CIC_RESIZE_CHROMA;
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Set target buffer */
+ node->node.GROUP1.B2R2_TBA = out_buf->phys_addr;
+ node->node.GROUP1.B2R2_TTY =
+ (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ B2R2_GENERIC_WORK_BUF_FMT |
+ B2R2_TY_ALPHA_RANGE_255 |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ if (yuv_planar) {
+ /*
+ * Set up chrominance buffers on source 1 and 2,
+ * luminance on source 3.
+ * dst_pitch and physical_address apply to luminance,
+ * corresponding chrominance values have to be derived.
+ */
+ u32 cb_addr = req->dst_resolved.physical_address +
+ dst_pitch * dst_img->height;
+ u32 cr_addr = 0;
+ u32 chroma_pitch = 0;
+ enum b2r2_native_fmt dst_native_fmt =
+ to_native_fmt(dst_img->fmt);
+
+ switch (dst_img->fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ chroma_pitch = dst_pitch >> 1;
+ cr_addr =
+ cb_addr + chroma_pitch * (dst_img->height >> 1);
+ break;
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ chroma_pitch = dst_pitch >> 1;
+ cr_addr =
+ cb_addr + chroma_pitch * dst_img->height;
+ break;
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ chroma_pitch = dst_pitch;
+ cr_addr =
+ cb_addr + chroma_pitch * dst_img->height;
+ break;
+ default:
+ break;
+ }
+
+ node->node.GROUP3.B2R2_SBA = cr_addr;
+ node->node.GROUP3.B2R2_STY =
+ (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ dst_native_fmt |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP4.B2R2_SBA = cb_addr;
+ node->node.GROUP4.B2R2_STY = node->node.GROUP3.B2R2_STY;
+
+ node->node.GROUP5.B2R2_SBA = req->dst_resolved.physical_address;
+ node->node.GROUP5.B2R2_STY =
+ (dst_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ dst_native_fmt |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_SOURCE_1_FETCH_FROM_MEM |
+ B2R2_INS_SOURCE_2_FETCH_FROM_MEM |
+ B2R2_INS_SOURCE_3_FETCH_FROM_MEM;
+ node->node.GROUP0.B2R2_CIC |=
+ B2R2_CIC_SOURCE_1 | B2R2_CIC_SOURCE_2 | B2R2_CIC_SOURCE_3;
+ } else if (yuv_semi_planar) {
+ /*
+ * Set up chrominance buffer on source 2, luminance on source 3.
+ * dst_pitch and physical_address apply to luminance,
+ * corresponding chrominance values have to be derived.
+ * U and V are interleaved at half the luminance resolution,
+ * which makes the pitch of the UV plane equal
+ * to luminance pitch.
+ */
+ u32 chroma_addr = req->dst_resolved.physical_address +
+ dst_pitch * dst_img->height;
+ u32 chroma_pitch = dst_pitch;
+
+ enum b2r2_native_fmt dst_native_fmt =
+ to_native_fmt(dst_img->fmt);
+
+ node->node.GROUP4.B2R2_SBA = chroma_addr;
+ node->node.GROUP4.B2R2_STY =
+ (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ dst_native_fmt |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP5.B2R2_SBA = req->dst_resolved.physical_address;
+ node->node.GROUP5.B2R2_STY =
+ (dst_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ dst_native_fmt |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_SOURCE_2_FETCH_FROM_MEM |
+ B2R2_INS_SOURCE_3_FETCH_FROM_MEM;
+ node->node.GROUP0.B2R2_CIC |=
+ B2R2_CIC_SOURCE_2 | B2R2_CIC_SOURCE_3;
+ } else {
+ /* single buffer format */
+ node->node.GROUP4.B2R2_SBA = req->dst_resolved.physical_address;
+ node->node.GROUP4.B2R2_STY =
+ (dst_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ to_native_fmt(dst_img->fmt) |
+ get_alpha_range(dst_img->fmt) |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_SOURCE_2_FETCH_FROM_MEM;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2;
+ }
+
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3;
+
+ b2r2_log_info("%s DONE\n", __func__);
+}
+
+static void setup_blend_stage(const struct b2r2_blt_request *req,
+ struct b2r2_node *node,
+ struct b2r2_work_buf *bg_buf,
+ struct b2r2_work_buf *fg_buf)
+{
+ u32 global_alpha = req->user_req.global_alpha;
+ b2r2_log_info("%s ENTRY\n", __func__);
+
+ node->node.GROUP0.B2R2_ACK = 0;
+
+ if (req->user_req.flags &
+ (B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND |
+ B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND)) {
+ /* Some kind of blending needs to be done. */
+ if ((req->user_req.flags & B2R2_BLT_FLAG_SRC_IS_NOT_PREMULT) != 0)
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BLEND_NOT_PREMULT;
+ else
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BLEND_PREMULT;
+
+ /*
+ * global_alpha register accepts 0..128 range,
+ * global_alpha in the request is 0..255, remap needed.
+ */
+ if ((req->user_req.flags & B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND) != 0) {
+ if (global_alpha == 255)
+ global_alpha = 128;
+ else
+ global_alpha >>= 1;
+ } else {
+ /*
+ * Use solid global_alpha
+ * if global alpha blending is not set.
+ */
+ global_alpha = 128;
+ }
+
+ node->node.GROUP0.B2R2_ACK |=
+ global_alpha << (B2R2_ACK_GALPHA_ROPID_SHIFT);
+
+ /* Set background on SRC1 channel */
+ node->node.GROUP3.B2R2_SBA = bg_buf->phys_addr;
+ node->node.GROUP3.B2R2_STY =
+ (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ B2R2_GENERIC_WORK_BUF_FMT |
+ B2R2_TY_ALPHA_RANGE_255 |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ /* Set foreground on SRC2 channel */
+ node->node.GROUP4.B2R2_SBA = fg_buf->phys_addr;
+ node->node.GROUP4.B2R2_STY =
+ (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ B2R2_GENERIC_WORK_BUF_FMT |
+ B2R2_TY_ALPHA_RANGE_255 |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ /* Set target buffer */
+ node->node.GROUP1.B2R2_TBA = bg_buf->phys_addr;
+ node->node.GROUP1.B2R2_TTY =
+ (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ B2R2_GENERIC_WORK_BUF_FMT |
+ B2R2_TY_ALPHA_RANGE_255 |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_SOURCE_1_FETCH_FROM_MEM |
+ B2R2_INS_SOURCE_2_FETCH_FROM_MEM;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_1 | B2R2_CIC_SOURCE_2;
+ } else {
+ /*
+ * No blending, foreground goes on SRC2. No global alpha.
+ * EMACSOC TODO: The blending stage should be skipped altogether
+ * if no blending is to be done. Probably could go directly from
+ * transform to writeback.
+ */
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3;
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_SOURCE_2_FETCH_FROM_MEM;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2;
+
+ node->node.GROUP4.B2R2_SBA = fg_buf->phys_addr;
+ node->node.GROUP4.B2R2_STY =
+ (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ B2R2_GENERIC_WORK_BUF_FMT |
+ B2R2_TY_ALPHA_RANGE_255 |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ node->node.GROUP1.B2R2_TBA = bg_buf->phys_addr;
+ node->node.GROUP1.B2R2_TTY =
+ (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ B2R2_GENERIC_WORK_BUF_FMT |
+ B2R2_TY_ALPHA_RANGE_255 |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+ }
+
+ b2r2_log_info("%s DONE\n", __func__);
+}
+
+static void setup_writeback_stage(const struct b2r2_blt_request *req,
+ struct b2r2_node *node,
+ struct b2r2_work_buf *in_buf)
+{
+ const struct b2r2_blt_img *dst_img = &(req->user_req.dst_img);
+ const enum b2r2_blt_fmt dst_fmt = dst_img->fmt;
+ const bool yuv_planar_dst =
+ dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR;
+
+ const bool yuv_semi_planar_dst =
+ dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE ||
+ dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE;
+
+ const u32 group4_b2r2_sty =
+ (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ B2R2_GENERIC_WORK_BUF_FMT |
+ B2R2_TY_ALPHA_RANGE_255 |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM;
+
+ u32 dst_dither = 0;
+ u32 dst_pitch = 0;
+
+ b2r2_log_info("%s ENTRY\n", __func__);
+
+ if (dst_img->pitch == 0) {
+ /* Determine pitch based on format and width of the image. */
+ dst_pitch = get_pitch(dst_img->fmt, dst_img->width);
+ } else
+ dst_pitch = dst_img->pitch;
+
+ if ((req->user_req.flags & B2R2_BLT_FLAG_DITHER) != 0)
+ dst_dither = B2R2_TTY_RGB_ROUND_DITHER;
+
+ /* Set target buffer(s) */
+ if (yuv_planar_dst) {
+ /*
+ * three nodes required to write the output.
+ * Luma, blue chroma and red chroma.
+ */
+ u32 fctl = 0;
+ u32 rsf = 0;
+ const u32 group0_b2r2_ins =
+ B2R2_INS_SOURCE_2_FETCH_FROM_MEM |
+ B2R2_INS_RECT_CLIP_ENABLED |
+ B2R2_INS_IVMX_ENABLED;
+ const u32 group0_b2r2_cic =
+ B2R2_CIC_SOURCE_2 |
+ B2R2_CIC_CLIP_WINDOW |
+ B2R2_CIC_IVMX;
+
+ u32 cb_addr = req->dst_resolved.physical_address +
+ dst_pitch * dst_img->height;
+ u32 cr_addr = 0;
+ u32 chroma_pitch = 0;
+ enum b2r2_native_fmt dst_native_fmt =
+ to_native_fmt(dst_img->fmt);
+ enum b2r2_ty alpha_range = get_alpha_range(dst_img->fmt);
+
+ switch (dst_fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ chroma_pitch = dst_pitch >> 1;
+ cr_addr =
+ cb_addr + chroma_pitch * (dst_img->height >> 1);
+ /*
+ * Chrominance is always half the luminance size
+ * so chrominance resizer is always active.
+ */
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER |
+ B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER;
+
+ rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT);
+ rsf |= (2 << 10) << B2R2_RSF_HSRC_INC_SHIFT;
+ rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT);
+ rsf |= (2 << 10) << B2R2_RSF_VSRC_INC_SHIFT;
+ break;
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ chroma_pitch = dst_pitch >> 1;
+ cr_addr =
+ cb_addr + chroma_pitch * dst_img->height;
+ /*
+ * YUV422
+ * Chrominance is always half the luminance size
+ * only in horizontal direction.
+ */
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER;
+
+ rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT);
+ rsf |= (2 << 10) << B2R2_RSF_HSRC_INC_SHIFT;
+ rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT);
+ rsf |= (1 << 10) << B2R2_RSF_VSRC_INC_SHIFT;
+ break;
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ chroma_pitch = dst_pitch;
+ cr_addr =
+ cb_addr + chroma_pitch * dst_img->height;
+ /*
+ * No scaling required since
+ * chrominance is not subsampled.
+ */
+ default:
+ break;
+ }
+
+ /* Luma (Y-component) */
+ node->node.GROUP1.B2R2_TBA = req->dst_resolved.physical_address;
+ node->node.GROUP1.B2R2_TTY =
+ (dst_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ dst_native_fmt | alpha_range |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM |
+ dst_dither;
+
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_YUV_601_VIDEO;
+
+ /* bypass ALU, no blending here. Handled in its own stage. */
+ node->node.GROUP0.B2R2_ACK = B2R2_ACK_MODE_BYPASS_S2_S3;
+ node->node.GROUP0.B2R2_INS = group0_b2r2_ins;
+ node->node.GROUP0.B2R2_CIC |= group0_b2r2_cic;
+
+ /* Set source buffer on SRC2 channel */
+ node->node.GROUP4.B2R2_SBA = in_buf->phys_addr;
+ node->node.GROUP4.B2R2_STY = group4_b2r2_sty;
+
+ /* Blue chroma (U-component)*/
+ node = node->next;
+ node->node.GROUP1.B2R2_TBA = cb_addr;
+ node->node.GROUP1.B2R2_TTY =
+ (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ dst_native_fmt | alpha_range |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM |
+ dst_dither |
+ B2R2_TTY_CHROMA_NOT_LUMA;
+
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_YUV_601_VIDEO;
+
+ node->node.GROUP0.B2R2_ACK = B2R2_ACK_MODE_BYPASS_S2_S3;
+ node->node.GROUP0.B2R2_INS = group0_b2r2_ins;
+ node->node.GROUP0.B2R2_CIC |= group0_b2r2_cic;
+ if (dst_fmt != B2R2_BLT_FMT_YUV444_PACKED_PLANAR) {
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_RESCALE2D_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_FILTER_CONTROL |
+ B2R2_CIC_RESIZE_CHROMA;
+ /* Set the filter control and rescale registers */
+ node->node.GROUP8.B2R2_FCTL = fctl;
+ node->node.GROUP9.B2R2_RSF = rsf;
+ node->node.GROUP9.B2R2_RZI =
+ B2R2_RZI_DEFAULT_HNB_REPEAT |
+ (2 << B2R2_RZI_VNB_REPEAT_SHIFT);
+ }
+
+ node->node.GROUP4.B2R2_SBA = in_buf->phys_addr;
+ node->node.GROUP4.B2R2_STY = group4_b2r2_sty;
+
+
+ /*
+ * Red chroma (V-component)
+ * The flag B2R2_TTY_CB_NOT_CR actually works
+ * the other way around, i.e. as if it was
+ * CR_NOT_CB.
+ */
+ node = node->next;
+ node->node.GROUP1.B2R2_TBA = cr_addr;
+ node->node.GROUP1.B2R2_TTY =
+ (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ dst_native_fmt | alpha_range |
+ B2R2_TTY_CB_NOT_CR |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM |
+ dst_dither |
+ B2R2_TTY_CHROMA_NOT_LUMA;
+
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_YUV_601_VIDEO;
+
+ node->node.GROUP0.B2R2_ACK = B2R2_ACK_MODE_BYPASS_S2_S3;
+ node->node.GROUP0.B2R2_INS = group0_b2r2_ins;
+ node->node.GROUP0.B2R2_CIC |= group0_b2r2_cic;
+ if (dst_fmt != B2R2_BLT_FMT_YUV444_PACKED_PLANAR) {
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_RESCALE2D_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_FILTER_CONTROL |
+ B2R2_CIC_RESIZE_CHROMA;
+ /* Set the filter control and rescale registers */
+ node->node.GROUP8.B2R2_FCTL = fctl;
+ node->node.GROUP9.B2R2_RSF = rsf;
+ node->node.GROUP9.B2R2_RZI =
+ B2R2_RZI_DEFAULT_HNB_REPEAT |
+ (2 << B2R2_RZI_VNB_REPEAT_SHIFT);
+ }
+
+ node->node.GROUP4.B2R2_SBA = in_buf->phys_addr;
+ node->node.GROUP4.B2R2_STY = group4_b2r2_sty;
+ } else if (yuv_semi_planar_dst) {
+ /*
+ * two nodes required to write the output.
+ * One node for luma and one for interleaved chroma
+ * components.
+ */
+ u32 fctl = 0;
+ u32 rsf = 0;
+ const u32 group0_b2r2_ins =
+ B2R2_INS_SOURCE_2_FETCH_FROM_MEM |
+ B2R2_INS_RECT_CLIP_ENABLED |
+ B2R2_INS_IVMX_ENABLED;
+ const u32 group0_b2r2_cic =
+ B2R2_CIC_SOURCE_2 |
+ B2R2_CIC_CLIP_WINDOW |
+ B2R2_CIC_IVMX;
+
+ u32 chroma_addr = req->dst_resolved.physical_address +
+ dst_pitch * dst_img->height;
+ u32 chroma_pitch = dst_pitch;
+ enum b2r2_native_fmt dst_native_fmt =
+ to_native_fmt(dst_img->fmt);
+ enum b2r2_ty alpha_range = get_alpha_range(dst_img->fmt);
+
+ if (dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE) {
+ /*
+ * Chrominance is always half the luminance size
+ * so chrominance resizer is always active.
+ */
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER |
+ B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER;
+
+ rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT);
+ rsf |= (2 << 10) << B2R2_RSF_HSRC_INC_SHIFT;
+ rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT);
+ rsf |= (2 << 10) << B2R2_RSF_VSRC_INC_SHIFT;
+ } else {
+ /*
+ * YUV422
+ * Chrominance is always half the luminance size
+ * only in horizontal direction.
+ */
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER;
+
+ rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT);
+ rsf |= (2 << 10) << B2R2_RSF_HSRC_INC_SHIFT;
+ rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT);
+ rsf |= (1 << 10) << B2R2_RSF_VSRC_INC_SHIFT;
+ }
+
+ /* Luma (Y-component) */
+ node->node.GROUP1.B2R2_TBA = req->dst_resolved.physical_address;
+ node->node.GROUP1.B2R2_TTY =
+ (dst_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ dst_native_fmt | alpha_range |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM |
+ dst_dither;
+
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_YUV_601_VIDEO;
+
+ /* bypass ALU, no blending here. Handled in its own stage. */
+ node->node.GROUP0.B2R2_ACK = B2R2_ACK_MODE_BYPASS_S2_S3;
+ node->node.GROUP0.B2R2_INS = group0_b2r2_ins;
+ node->node.GROUP0.B2R2_CIC |= group0_b2r2_cic;
+
+ /* Set source buffer on SRC2 channel */
+ node->node.GROUP4.B2R2_SBA = in_buf->phys_addr;
+ node->node.GROUP4.B2R2_STY = group4_b2r2_sty;
+
+ /* Chroma (UV-components)*/
+ node = node->next;
+ node->node.GROUP1.B2R2_TBA = chroma_addr;
+ node->node.GROUP1.B2R2_TTY =
+ (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ dst_native_fmt | alpha_range |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM |
+ dst_dither |
+ B2R2_TTY_CHROMA_NOT_LUMA;
+
+ node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_YUV_601_VIDEO;
+
+ node->node.GROUP0.B2R2_ACK = B2R2_ACK_MODE_BYPASS_S2_S3;
+ node->node.GROUP0.B2R2_INS =
+ group0_b2r2_ins | B2R2_INS_RESCALE2D_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= group0_b2r2_cic |
+ B2R2_CIC_FILTER_CONTROL |
+ B2R2_CIC_RESIZE_CHROMA;
+
+ /* Set the filter control and rescale registers */
+ node->node.GROUP8.B2R2_FCTL = fctl;
+ node->node.GROUP9.B2R2_RSF = rsf;
+ node->node.GROUP9.B2R2_RZI =
+ B2R2_RZI_DEFAULT_HNB_REPEAT |
+ (2 << B2R2_RZI_VNB_REPEAT_SHIFT);
+
+ node->node.GROUP4.B2R2_SBA = in_buf->phys_addr;
+ node->node.GROUP4.B2R2_STY = group4_b2r2_sty;
+ } else {
+ /* single buffer target */
+
+ /* Set up OVMX */
+ switch (dst_fmt) {
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_OVMX_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_OVMX;
+ node->node.GROUP16.B2R2_VMX0 = B2R2_VMX0_RGB_TO_BGR;
+ node->node.GROUP16.B2R2_VMX1 = B2R2_VMX1_RGB_TO_BGR;
+ node->node.GROUP16.B2R2_VMX2 = B2R2_VMX2_RGB_TO_BGR;
+ node->node.GROUP16.B2R2_VMX3 = B2R2_VMX3_RGB_TO_BGR;
+ break;
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_OVMX_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_OVMX;
+ node->node.GROUP16.B2R2_VMX0 = B2R2_VMX0_RGB_TO_YVU_601_VIDEO;
+ node->node.GROUP16.B2R2_VMX1 = B2R2_VMX1_RGB_TO_YVU_601_VIDEO;
+ node->node.GROUP16.B2R2_VMX2 = B2R2_VMX2_RGB_TO_YVU_601_VIDEO;
+ node->node.GROUP16.B2R2_VMX3 = B2R2_VMX3_RGB_TO_YVU_601_VIDEO;
+ break;
+ case B2R2_BLT_FMT_24_BIT_YUV888: /* fall through */
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_OVMX_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_OVMX;
+ node->node.GROUP16.B2R2_VMX0 = B2R2_VMX0_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP16.B2R2_VMX1 = B2R2_VMX1_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP16.B2R2_VMX2 = B2R2_VMX2_RGB_TO_YUV_601_VIDEO;
+ node->node.GROUP16.B2R2_VMX3 = B2R2_VMX3_RGB_TO_YUV_601_VIDEO;
+ break;
+ default:
+ break;
+ }
+
+ node->node.GROUP1.B2R2_TBA = req->dst_resolved.physical_address;
+ node->node.GROUP1.B2R2_TTY =
+ (dst_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) |
+ to_native_fmt(dst_img->fmt) |
+ get_alpha_range(dst_img->fmt) |
+ B2R2_TY_HSO_LEFT_TO_RIGHT |
+ B2R2_TY_VSO_TOP_TO_BOTTOM |
+ dst_dither;
+
+ node->node.GROUP0.B2R2_ACK = B2R2_ACK_MODE_BYPASS_S2_S3;
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_SOURCE_2_FETCH_FROM_MEM |
+ B2R2_INS_RECT_CLIP_ENABLED;
+ node->node.GROUP0.B2R2_CIC |=
+ B2R2_CIC_SOURCE_2 | B2R2_CIC_CLIP_WINDOW;
+
+ if (req->user_req.flags & B2R2_BLT_FLAG_SOURCE_COLOR_KEY) {
+ u32 key_color = 0;
+
+ node->node.GROUP0.B2R2_ACK |=
+ B2R2_ACK_CKEY_SEL_SRC_AFTER_CLUT |
+ B2R2_ACK_CKEY_RED_MATCH_IF_BETWEEN |
+ B2R2_ACK_CKEY_GREEN_MATCH_IF_BETWEEN |
+ B2R2_ACK_CKEY_BLUE_MATCH_IF_BETWEEN;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_CKEY_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_COLOR_KEY;
+
+ key_color = to_RGB888(req->user_req.src_color,
+ req->user_req.src_img.fmt);
+ node->node.GROUP12.B2R2_KEY1 = key_color;
+ node->node.GROUP12.B2R2_KEY2 = key_color;
+ }
+
+ /* Set source buffer on SRC2 channel */
+ node->node.GROUP4.B2R2_SBA = in_buf->phys_addr;
+ node->node.GROUP4.B2R2_STY = group4_b2r2_sty;
+ }
+ /*
+ * Writeback is the last stage. Terminate the program chain
+ * to prevent out-of-control B2R2 execution.
+ */
+ node->node.GROUP0.B2R2_NIP = 0;
+
+ b2r2_log_info("%s DONE\n", __func__);
+}
+
+/*
+ * Public functions
+ */
+void b2r2_generic_init()
+{
+ b2r2_filters_init();
+}
+
+void b2r2_generic_exit(void)
+{
+ b2r2_filters_exit();
+}
+
+int b2r2_generic_analyze(const struct b2r2_blt_request *req,
+ s32 *work_buf_width,
+ s32 *work_buf_height,
+ u32 *work_buf_count,
+ u32 *node_count)
+{
+ /*
+ * Need at least 4 nodes, read or fill input, read dst, blend
+ * and write back the result */
+ u32 n_nodes = 4;
+ /* Need at least 2 bufs, 1 for blend output and 1 for input */
+ u32 n_work_bufs = 2;
+ /* Horizontal and vertical scaling factors in 6.10 fixed point format */
+ s32 h_scf = 1 << 10;
+ s32 v_scf = 1 << 10;
+ enum b2r2_blt_fmt dst_fmt = 0;
+ bool is_src_fill = false;
+ bool yuv_planar_dst;
+ bool yuv_semi_planar_dst;
+
+ struct b2r2_blt_rect src_rect;
+ struct b2r2_blt_rect dst_rect;
+
+ if (req == NULL || work_buf_width == NULL || work_buf_height == NULL ||
+ work_buf_count == NULL || node_count == NULL) {
+ b2r2_log_warn("%s: Invalid in or out pointers:\n"
+ "req=0x%p\n"
+ "work_buf_width=0x%p work_buf_height=0x%p "
+ "work_buf_count=0x%p\n"
+ "node_count=0x%p.\n",
+ __func__,
+ req,
+ work_buf_width, work_buf_height,
+ work_buf_count,
+ node_count);
+ return -EINVAL;
+ }
+
+ dst_fmt = req->user_req.dst_img.fmt;
+
+ is_src_fill = (req->user_req.flags &
+ (B2R2_BLT_FLAG_SOURCE_FILL | B2R2_BLT_FLAG_SOURCE_FILL_RAW)) != 0;
+
+ yuv_planar_dst =
+ dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR;
+ yuv_semi_planar_dst =
+ dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE ||
+ dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE;
+
+ *node_count = 0;
+ *work_buf_width = 0;
+ *work_buf_height = 0;
+ *work_buf_count = 0;
+
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) {
+ n_nodes++;
+ n_work_bufs++;
+ }
+
+ if ((yuv_planar_dst || yuv_semi_planar_dst) &&
+ (req->user_req.flags & B2R2_BLT_FLAG_SOURCE_FILL_RAW) != 0) {
+ b2r2_log_warn("%s: Invalid combination: source_fill_raw"
+ " and multi-buffer destination.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if ((req->user_req.flags & B2R2_BLT_FLAG_SOURCE_COLOR_KEY) != 0 &&
+ (req->user_req.flags & B2R2_BLT_FLAG_DEST_COLOR_KEY) != 0) {
+ b2r2_log_warn("%s: Invalid combination: source and "
+ "destination color keying.\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((req->user_req.flags &
+ (B2R2_BLT_FLAG_SOURCE_FILL |
+ B2R2_BLT_FLAG_SOURCE_FILL_RAW)) &&
+ (req->user_req.flags &
+ (B2R2_BLT_FLAG_SOURCE_COLOR_KEY |
+ B2R2_BLT_FLAG_DEST_COLOR_KEY))) {
+ b2r2_log_warn("%s: Invalid combination: "
+ "source_fill and color keying.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if ((req->user_req.flags &
+ (B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND |
+ B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND)) &&
+ (req->user_req.flags &
+ (B2R2_BLT_FLAG_DEST_COLOR_KEY |
+ B2R2_BLT_FLAG_SOURCE_COLOR_KEY))) {
+ b2r2_log_warn("%s: Invalid combination: "
+ "blending and color keying.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if ((req->user_req.flags & B2R2_BLT_FLAG_SOURCE_MASK) &&
+ (req->user_req.flags &
+ (B2R2_BLT_FLAG_DEST_COLOR_KEY |
+ B2R2_BLT_FLAG_SOURCE_COLOR_KEY))) {
+ b2r2_log_warn("%s: Invalid combination: source mask and "
+ "color keying.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (req->user_req.flags &
+ (B2R2_BLT_FLAG_DEST_COLOR_KEY |
+ B2R2_BLT_FLAG_SOURCE_MASK)) {
+ b2r2_log_warn("%s: Unsupported: source mask, "
+ "destination color keying.\n",
+ __func__);
+ return -ENOSYS;
+ }
+
+ if ((req->user_req.flags & B2R2_BLT_FLAG_SOURCE_MASK)) {
+ enum b2r2_blt_fmt src_fmt = req->user_req.src_img.fmt;
+ bool yuv_src =
+ src_fmt == B2R2_BLT_FMT_Y_CB_Y_CR ||
+ src_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR ||
+ src_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR ||
+ src_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR ||
+ src_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR ||
+ src_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR ||
+ src_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE ||
+ src_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE;
+ if (yuv_src || src_fmt == B2R2_BLT_FMT_1_BIT_A1 ||
+ src_fmt == B2R2_BLT_FMT_8_BIT_A8) {
+ b2r2_log_warn("%s: Unsupported: source color keying "
+ "with YUV or pure alpha formats.\n",
+ __func__);
+ return -ENOSYS;
+ }
+ }
+
+ /* Check for invalid dimensions that would hinder scale calculations */
+ src_rect = req->user_req.src_rect;
+ dst_rect = req->user_req.dst_rect;
+ /* Check for invalid src_rect unless src_fill is enabled */
+ if (!is_src_fill && (src_rect.x < 0 || src_rect.y < 0 ||
+ src_rect.x + src_rect.width > req->user_req.src_img.width ||
+ src_rect.y + src_rect.height > req->user_req.src_img.height)) {
+ b2r2_log_warn("%s: src_rect outside src_img:\n"
+ "src(x,y,w,h)=(%d, %d, %d, %d) src_img(w,h)=(%d, %d).\n",
+ __func__,
+ src_rect.x, src_rect.y, src_rect.width, src_rect.height,
+ req->user_req.src_img.width, req->user_req.src_img.height);
+ return -EINVAL;
+ }
+
+ if (!is_src_fill && (src_rect.width <= 0 || src_rect.height <= 0)) {
+ b2r2_log_warn("%s: Invalid source dimensions:\n"
+ "src(w,h)=(%d, %d).\n",
+ __func__,
+ src_rect.width, src_rect.height);
+ return -EINVAL;
+ }
+
+ if (dst_rect.width <= 0 || dst_rect.height <= 0) {
+ b2r2_log_warn("%s: Invalid dest dimensions:\n"
+ "dst(w,h)=(%d, %d).\n",
+ __func__,
+ dst_rect.width, dst_rect.height);
+ return -EINVAL;
+ }
+
+ if ((req->user_req.flags & B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) &&
+ req->user_req.clut == NULL) {
+ b2r2_log_warn("%s: Invalid request: no table specified "
+ "for CLUT color correction.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* Check for invalid image params */
+ if (!is_src_fill && validate_buf(&(req->user_req.src_img),
+ &(req->src_resolved)))
+ return -EINVAL;
+
+ if (validate_buf(&(req->user_req.dst_img), &(req->dst_resolved)))
+ return -EINVAL;
+
+ if (is_src_fill) {
+ /*
+ * Params correct for a source fill operation.
+ * No need for further checking.
+ */
+ if (yuv_planar_dst)
+ n_nodes += 2;
+ else if (yuv_semi_planar_dst)
+ n_nodes++;
+
+ *work_buf_width = B2R2_GENERIC_WORK_BUF_WIDTH;
+ *work_buf_height = B2R2_GENERIC_WORK_BUF_HEIGHT;
+ *work_buf_count = n_work_bufs;
+ *node_count = n_nodes;
+ b2r2_log_info("%s DONE buf_w=%d buf_h=%d buf_count=%d "
+ "node_count=%d\n",
+ __func__,
+ *work_buf_width, *work_buf_height,
+ *work_buf_count, *node_count);
+ return 0;
+ }
+
+ /*
+ * Calculate scaling factors, all transform enum values
+ * that include rotation have the CCW_ROT_90 bit set.
+ */
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) {
+ h_scf = (src_rect.width << 10) / dst_rect.height;
+ v_scf = (src_rect.height << 10) / dst_rect.width;
+ } else {
+ h_scf = (src_rect.width << 10) / dst_rect.width;
+ v_scf = (src_rect.height << 10) / dst_rect.height;
+ }
+
+ /* Check for degenerate/out_of_range scaling factors. */
+ if (h_scf <= 0 || v_scf <= 0 || h_scf > 0x7C00 || v_scf > 0x7C00) {
+ b2r2_log_warn("%s: Dimensions result in degenerate or "
+ "out of range scaling:\n"
+ "src(w,h)=(%d, %d) "
+ "dst(w,h)=(%d,%d).\n"
+ "h_scf=0x%.8x, v_scf=0x%.8x\n",
+ __func__,
+ src_rect.width, src_rect.height,
+ dst_rect.width, dst_rect.height,
+ h_scf, v_scf);
+ return -EINVAL;
+ }
+
+ if (yuv_planar_dst)
+ n_nodes += 2;
+ else if (yuv_semi_planar_dst)
+ n_nodes++;
+
+ *work_buf_width = B2R2_GENERIC_WORK_BUF_WIDTH;
+ *work_buf_height = B2R2_GENERIC_WORK_BUF_HEIGHT;
+ *work_buf_count = n_work_bufs;
+ *node_count = n_nodes;
+ b2r2_log_info("%s DONE buf_w=%d buf_h=%d buf_count=%d node_count=%d\n",
+ __func__,
+ *work_buf_width, *work_buf_height, *work_buf_count,
+ *node_count);
+ return 0;
+}
+
+/*
+ *
+ */
+int b2r2_generic_configure(const struct b2r2_blt_request *req,
+ struct b2r2_node *first,
+ struct b2r2_work_buf *tmp_bufs,
+ u32 buf_count)
+{
+ struct b2r2_node *node = NULL;
+ struct b2r2_work_buf *in_buf = NULL;
+ struct b2r2_work_buf *out_buf = NULL;
+ struct b2r2_work_buf *empty_buf = NULL;
+
+#ifdef B2R2_GENERIC_DEBUG
+ u32 needed_bufs = 0;
+ u32 needed_nodes = 0;
+ s32 work_buf_width = 0;
+ s32 work_buf_height = 0;
+ u32 n_nodes = 0;
+ int invalid_req = b2r2_generic_analyze(req, &work_buf_width,
+ &work_buf_height, &needed_bufs,
+ &needed_nodes);
+ if (invalid_req < 0) {
+ b2r2_log_warn("%s: Invalid request supplied, ec=%d\n",
+ __func__, invalid_req);
+ return -EINVAL;
+ }
+
+ node = first;
+
+ while (node != NULL) {
+ n_nodes++;
+ node = node->next;
+ }
+ if (n_nodes < needed_nodes) {
+ b2r2_log_warn("%s: Not enough nodes %d < %d.\n",
+ __func__, n_nodes, needed_nodes);
+ return -EINVAL;
+ }
+
+ if (buf_count < needed_bufs) {
+ b2r2_log_warn("%s: Not enough buffers %d < %d.\n",
+ __func__, buf_count, needed_bufs);
+ return -EINVAL;
+ }
+
+#endif
+
+ reset_nodes(first);
+ node = first;
+ empty_buf = tmp_bufs;
+ out_buf = empty_buf;
+ empty_buf++;
+ /* Prepare input tile. Color_fill or read from src */
+ setup_input_stage(req, node, out_buf);
+ in_buf = out_buf;
+ out_buf = empty_buf;
+ empty_buf++;
+ node = node->next;
+
+ if ((req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) != 0) {
+ setup_transform_stage(req, node, out_buf, in_buf);
+ node = node->next;
+ in_buf = out_buf;
+ out_buf = empty_buf++;
+ }
+ /* EMACSOC TODO: mask */
+ /*
+ if (req->user_req.flags & B2R2_BLT_FLAG_SOURCE_MASK) {
+ setup_mask_stage(req, node, out_buf, in_buf);
+ node = node->next;
+ in_buf = out_buf;
+ out_buf = empty_buf++;
+ }
+ */
+ /* Read the part of destination that will be updated */
+ setup_dst_read_stage(req, node, out_buf);
+ node = node->next;
+ setup_blend_stage(req, node, out_buf, in_buf);
+ node = node->next;
+ in_buf = out_buf;
+ setup_writeback_stage(req, node, in_buf);
+ return 0;
+}
+
+void b2r2_generic_set_areas(const struct b2r2_blt_request *req,
+ struct b2r2_node *first,
+ struct b2r2_blt_rect *dst_rect_area)
+{
+ /*
+ * Nodes come in the following order: <input stage>, [transform],
+ * [src_mask], <dst_read>, <blend>, <writeback>
+ */
+ struct b2r2_node *node = first;
+ const struct b2r2_blt_rect *dst_rect = &(req->user_req.dst_rect);
+ const struct b2r2_blt_rect *src_rect = &(req->user_req.src_rect);
+ const enum b2r2_blt_fmt src_fmt = req->user_req.src_img.fmt;
+ bool yuv_multi_buffer_src =
+ src_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR ||
+ src_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR ||
+ src_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR ||
+ src_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR ||
+ src_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR ||
+ src_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE ||
+ src_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE;
+ const enum b2r2_blt_fmt dst_fmt = req->user_req.dst_img.fmt;
+ const bool yuv_multi_buffer_dst =
+ dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE ||
+ dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE;
+ s32 h_scf = 1 << 10;
+ s32 v_scf = 1 << 10;
+ s32 src_x = 0;
+ s32 src_y = 0;
+ s32 src_w = 0;
+ s32 src_h = 0;
+ u32 b2r2_rzi = 0;
+ s32 clip_top = 0;
+ s32 clip_left = 0;
+ s32 clip_bottom = req->user_req.dst_img.height - 1;
+ s32 clip_right = req->user_req.dst_img.width - 1;
+ /* Dst coords inside the dst_rect, not the buffer */
+ s32 dst_x = dst_rect_area->x;
+ s32 dst_y = dst_rect_area->y;
+
+ b2r2_log_info("%s ENTRY\n", __func__);
+
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) {
+ h_scf = (src_rect->width << 10) / dst_rect->height;
+ v_scf = (src_rect->height << 10) / dst_rect->width;
+ } else {
+ h_scf = (src_rect->width << 10) / dst_rect->width;
+ v_scf = (src_rect->height << 10) / dst_rect->height;
+ }
+
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) {
+ /*
+ * Normally the inverse transform for 90 degree rotation is given by
+ * | 0 1| |x| | y|
+ * | | X | | = | |
+ * |-1 0| |y| |-x|
+ * but screen coordinates are flipped in y direction
+ * (compared to usual Cartesian coordinates), hence the offsets.
+ */
+ src_x = (dst_rect->height - dst_y - dst_rect_area->height) * h_scf;
+ src_y = dst_x * v_scf;
+ src_w = dst_rect_area->height * h_scf;
+ src_h = dst_rect_area->width * v_scf;
+ } else {
+ src_x = dst_x * h_scf;
+ src_y = dst_y * v_scf;
+ src_w = dst_rect_area->width * h_scf;
+ src_h = dst_rect_area->height * v_scf;
+ }
+
+ b2r2_rzi |= ((src_x & 0x3ff) << B2R2_RZI_HSRC_INIT_SHIFT) |
+ ((src_y & 0x3ff) << B2R2_RZI_VSRC_INIT_SHIFT);
+
+ /*
+ * src_w must contain all the pixels that contribute
+ * to a particular tile.
+ * ((x + 0x3ff) >> 10) is equivalent to ceiling(x),
+ * expressed in 6.10 fixed point format.
+ * Every destination tile, maps to a certain area in the source
+ * rectangle. The area in source will most likely not be a rectangle
+ * with exact integer dimensions whenever arbitrary scaling is involved.
+ * Consider the following example.
+ * Suppose, that width of the current destination tile maps
+ * to 1.7 pixels in source, starting at x == 5.4, as calculated
+ * using the scaling factor.
+ * This means that while the destination tile is written,
+ * the source should be read from x == 5.4 up to x == 5.4 + 1.7 == 7.1
+ * Consequently, color from 3 pixels (x == 5, 6 and 7)
+ * needs to be read from source.
+ * The formula below the comment yields:
+ * ceil(0.4 + 1.7) == ceil(2.1) == 3
+ * (src_x & 0x3ff) is the fractional part of src_x,
+ * which is expressed in 6.10 fixed point format.
+ * Thus, width of the source area should be 3 pixels wide,
+ * starting at x == 5.
+ * However, the reading should not start at x == 5.0
+ * but a bit inside, namely x == 5.4
+ * The B2R2_RZI register is used to instruct the HW to do so.
+ * It contains the fractional part that will be added to
+ * the first pixel coordinate, before incrementing the current source
+ * coordinate with the step specified in B2R2_RSF register.
+ * The same applies to scaling in vertical direction.
+ */
+ src_w = ((src_x & 0x3ff) + src_w + 0x3ff) >> 10;
+ src_h = ((src_y & 0x3ff) + src_h + 0x3ff) >> 10;
+
+ /*
+ * EMACSOC TODO: Remove this debug clamp, once tile size
+ * is taken into account in generic_analyze()
+ */
+ if (src_w > 128)
+ src_w = 128;
+
+ src_x >>= 10;
+ src_y >>= 10;
+
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_H)
+ src_x = src_rect->width - src_x - src_w;
+
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_V)
+ src_y = src_rect->height - src_y - src_h;
+
+ /*
+ * Translate the src/dst_rect coordinates into true
+ * src/dst_buffer coordinates
+ */
+ src_x += src_rect->x;
+ src_y += src_rect->y;
+
+ dst_x += dst_rect->x;
+ dst_y += dst_rect->y;
+
+ /*
+ * Clamp the src coords to buffer dimensions
+ * to prevent illegal reads.
+ */
+ if (src_x < 0)
+ src_x = 0;
+
+ if (src_y < 0)
+ src_y = 0;
+
+ if ((src_x + src_w) > req->user_req.src_img.width)
+ src_w = req->user_req.src_img.width - src_x;
+
+ if ((src_y + src_h) > req->user_req.src_img.height)
+ src_h = req->user_req.src_img.height - src_y;
+
+
+ /* The input node */
+ if (yuv_multi_buffer_src) {
+ /* Luma on SRC3 */
+ node->node.GROUP5.B2R2_SXY =
+ ((src_x & 0xffff) << B2R2_XY_X_SHIFT) |
+ ((src_y & 0xffff) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP5.B2R2_SSZ =
+ ((src_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((src_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+
+ /* Clear and set only the SRC_INIT bits */
+ node->node.GROUP10.B2R2_RZI &=
+ ~((0x3ff << B2R2_RZI_HSRC_INIT_SHIFT) |
+ (0x3ff << B2R2_RZI_VSRC_INIT_SHIFT));
+ node->node.GROUP10.B2R2_RZI |= b2r2_rzi;
+
+ node->node.GROUP9.B2R2_RZI &=
+ ~((0x3ff << B2R2_RZI_HSRC_INIT_SHIFT) |
+ (0x3ff << B2R2_RZI_VSRC_INIT_SHIFT));
+ switch (src_fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ /*
+ * Chroma goes on SRC2 and potentially on SRC1.
+ * Chroma is half the size of luma. Must round up
+ * the chroma size to handle cases when luma size is not
+ * divisible by 2.
+ * E.g. luma width==7 requires chroma width==4.
+ * Chroma width==7/2==3 is only enough
+ * for luma width==6.
+ */
+ node->node.GROUP4.B2R2_SXY =
+ (((src_x & 0xffff) >> 1) << B2R2_XY_X_SHIFT) |
+ (((src_y & 0xffff) >> 1) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP4.B2R2_SSZ =
+ ((((src_w + 1) & 0xfff) >> 1) << B2R2_SZ_WIDTH_SHIFT) |
+ ((((src_h + 1) & 0xfff) >> 1) << B2R2_SZ_HEIGHT_SHIFT);
+ if (src_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR) {
+ node->node.GROUP3.B2R2_SXY = node->node.GROUP4.B2R2_SXY;
+ node->node.GROUP3.B2R2_SSZ = node->node.GROUP4.B2R2_SSZ;
+ }
+ node->node.GROUP9.B2R2_RZI |= (b2r2_rzi >> 1) &
+ ((0x3ff << B2R2_RZI_HSRC_INIT_SHIFT) |
+ (0x3ff << B2R2_RZI_VSRC_INIT_SHIFT));
+ break;
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ /*
+ * Chroma goes on SRC2 and potentially on SRC1.
+ * Now chroma is half the size of luma
+ * only in horizontal direction.
+ * Same rounding applies as for 420 formats above,
+ * except it is only done horizontally.
+ */
+ node->node.GROUP4.B2R2_SXY =
+ (((src_x & 0xffff) >> 1) << B2R2_XY_X_SHIFT) |
+ ((src_y & 0xffff) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP4.B2R2_SSZ =
+ ((((src_w + 1) & 0xfff) >> 1) << B2R2_SZ_WIDTH_SHIFT) |
+ ((src_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ if (src_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR) {
+ node->node.GROUP3.B2R2_SXY = node->node.GROUP4.B2R2_SXY;
+ node->node.GROUP3.B2R2_SSZ = node->node.GROUP4.B2R2_SSZ;
+ }
+ node->node.GROUP9.B2R2_RZI |=
+ (((src_x & 0x3ff) >> 1) << B2R2_RZI_HSRC_INIT_SHIFT) |
+ ((src_y & 0x3ff) << B2R2_RZI_VSRC_INIT_SHIFT);
+ break;
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ /*
+ * Chroma goes on SRC2 and SRC1.
+ * It is the same size as luma.
+ */
+ node->node.GROUP4.B2R2_SXY =
+ ((src_x & 0xffff) << B2R2_XY_X_SHIFT) |
+ ((src_y & 0xffff) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP4.B2R2_SSZ =
+ ((src_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((src_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ node->node.GROUP3.B2R2_SXY = node->node.GROUP4.B2R2_SXY;
+ node->node.GROUP3.B2R2_SSZ = node->node.GROUP4.B2R2_SSZ;
+
+ /* Clear and set only the SRC_INIT bits */
+ node->node.GROUP9.B2R2_RZI &=
+ ~((0x3ff << B2R2_RZI_HSRC_INIT_SHIFT) |
+ (0x3ff << B2R2_RZI_VSRC_INIT_SHIFT));
+ node->node.GROUP9.B2R2_RZI |= b2r2_rzi;
+ break;
+ default:
+ break;
+ }
+ } else {
+ node->node.GROUP4.B2R2_SXY =
+ ((src_x & 0xffff) << B2R2_XY_X_SHIFT) |
+ ((src_y & 0xffff) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP4.B2R2_SSZ =
+ ((src_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((src_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+
+ /* Clear and set only the SRC_INIT bits */
+ node->node.GROUP9.B2R2_RZI &=
+ ~((0x3ff << B2R2_RZI_HSRC_INIT_SHIFT) |
+ (0x3ff << B2R2_RZI_VSRC_INIT_SHIFT));
+ node->node.GROUP9.B2R2_RZI |= b2r2_rzi;
+ }
+
+ node->node.GROUP1.B2R2_TXY = 0;
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) {
+ /*
+ * dst_rect_area coordinates are specified
+ * after potential rotation.
+ * Input is read before rotation, hence the width and height
+ * need to be swapped.
+ * Horizontal and vertical flips are accomplished with
+ * suitable scanning order while writing
+ * to the temporary buffer.
+ */
+ if ((req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_H) != 0) {
+ node->node.GROUP1.B2R2_TXY |=
+ ((dst_rect_area->height - 1) & 0xffff) << B2R2_XY_X_SHIFT;
+ }
+
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_V) {
+ node->node.GROUP1.B2R2_TXY |=
+ ((dst_rect_area->width - 1) & 0xffff) << B2R2_XY_Y_SHIFT;
+ }
+
+ node->node.GROUP1.B2R2_TSZ =
+ ((dst_rect_area->height & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_rect_area->width & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ } else {
+ if ((req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_H) != 0) {
+ node->node.GROUP1.B2R2_TXY |=
+ ((dst_rect_area->width - 1) & 0xffff) << B2R2_XY_X_SHIFT;
+ }
+
+ if ((req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_V) != 0) {
+ node->node.GROUP1.B2R2_TXY |=
+ ((dst_rect_area->height - 1) & 0xffff) << B2R2_XY_Y_SHIFT;
+ }
+
+ node->node.GROUP1.B2R2_TSZ =
+ ((dst_rect_area->width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_rect_area->height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ }
+
+ if (req->user_req.flags &
+ (B2R2_BLT_FLAG_SOURCE_FILL | B2R2_BLT_FLAG_SOURCE_FILL_RAW)) {
+ /*
+ * Scan order for source fill should always be left-to-right
+ * and top-to-bottom. Fill the input tile from top left.
+ */
+ node->node.GROUP1.B2R2_TXY = 0;
+ node->node.GROUP4.B2R2_SSZ = node->node.GROUP1.B2R2_TSZ;
+ }
+
+ if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 &&
+ dst_rect_area->y == 0) {
+ dump_nodes(node, false);
+ b2r2_log_debug("%s Input node done.\n", __func__);
+ }
+
+ /* Transform */
+ if ((req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) != 0) {
+ /*
+ * Transform node operates on temporary buffers.
+ * Content always at top left, but scanning order
+ * has to be flipped during rotation.
+ * Width and height need to be considered as well, since
+ * a tile may not necessarily be filled completely.
+ * dst_rect_area dimensions are specified
+ * after potential rotation.
+ * Input is read before rotation, hence the width and height
+ * need to be swapped on src.
+ */
+ node = node->next;
+
+ node->node.GROUP4.B2R2_SXY = 0;
+ node->node.GROUP4.B2R2_SSZ =
+ ((dst_rect_area->height & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_rect_area->width & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ /* Bottom line written first */
+ node->node.GROUP1.B2R2_TXY =
+ ((dst_rect_area->height - 1) & 0xffff) << B2R2_XY_Y_SHIFT;
+
+ node->node.GROUP1.B2R2_TSZ =
+ ((dst_rect_area->width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_rect_area->height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+
+ if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 &&
+ dst_rect_area->y == 0) {
+ dump_nodes(node, false);
+ b2r2_log_debug("%s Tranform node done.\n", __func__);
+ }
+ }
+
+ /* Source mask */
+ if (req->user_req.flags & B2R2_BLT_FLAG_SOURCE_MASK) {
+ node = node->next;
+ /*
+ * Same coords for mask as for the input stage.
+ * Should the mask be transformed together with source?
+ * EMACSOC TODO: Apply mask before any
+ * transform/scaling is done.
+ * Otherwise it will be dst_ not src_mask.
+ */
+ if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 &&
+ dst_rect_area->y == 0) {
+ dump_nodes(node, false);
+ b2r2_log_debug("%s Source mask node done.\n", __func__);
+ }
+ }
+
+ /* dst_read */
+ if (yuv_multi_buffer_dst) {
+ s32 dst_w = dst_rect_area->width;
+ s32 dst_h = dst_rect_area->height;
+ node = node->next;
+ /* Luma on SRC3 */
+ node->node.GROUP5.B2R2_SXY =
+ ((dst_x & 0xffff) << B2R2_XY_X_SHIFT) |
+ ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP5.B2R2_SSZ =
+ ((dst_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+
+ if (dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE) {
+ /*
+ * Chroma goes on SRC2 and potentially on SRC1.
+ * Chroma is half the size of luma. Must round up
+ * the chroma size to handle cases when luma size is not
+ * divisible by 2.
+ * E.g. luma width==7 requires chroma width==4.
+ * Chroma width==7/2==3 is only enough
+ * for luma width==6.
+ */
+ node->node.GROUP4.B2R2_SXY =
+ (((dst_x & 0xffff) >> 1) << B2R2_XY_X_SHIFT) |
+ (((dst_y & 0xffff) >> 1) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP4.B2R2_SSZ =
+ ((((dst_w + 1) & 0xfff) >> 1) << B2R2_SZ_WIDTH_SHIFT) |
+ ((((dst_h + 1) & 0xfff) >> 1) << B2R2_SZ_HEIGHT_SHIFT);
+
+ if (dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR) {
+ node->node.GROUP3.B2R2_SXY = node->node.GROUP4.B2R2_SXY;
+ node->node.GROUP3.B2R2_SSZ = node->node.GROUP4.B2R2_SSZ;
+ }
+ } else if (dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE) {
+ /*
+ * Chroma goes on SRC2 and potentially on SRC1.
+ * Now chroma is half the size of luma
+ * only in horizontal direction.
+ * Same rounding applies as for 420 formats above,
+ * except it is only done horizontally.
+ */
+ node->node.GROUP4.B2R2_SXY =
+ (((dst_x & 0xffff) >> 1) << B2R2_XY_X_SHIFT) |
+ ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP4.B2R2_SSZ =
+ ((((dst_w + 1) & 0xfff) >> 1) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+
+ if (dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR) {
+ node->node.GROUP3.B2R2_SXY = node->node.GROUP4.B2R2_SXY;
+ node->node.GROUP3.B2R2_SSZ = node->node.GROUP4.B2R2_SSZ;
+ }
+ } else if (dst_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR) {
+ /*
+ * Chroma goes on SRC2 and SRC1.
+ * It is the same size as luma.
+ */
+ node->node.GROUP4.B2R2_SXY = node->node.GROUP5.B2R2_SXY;
+ node->node.GROUP4.B2R2_SSZ = node->node.GROUP5.B2R2_SSZ;
+ node->node.GROUP3.B2R2_SXY = node->node.GROUP5.B2R2_SXY;
+ node->node.GROUP3.B2R2_SSZ = node->node.GROUP5.B2R2_SSZ;
+ }
+
+ node->node.GROUP1.B2R2_TXY = 0;
+ node->node.GROUP1.B2R2_TSZ =
+ ((dst_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ } else {
+ node = node->next;
+ node->node.GROUP4.B2R2_SXY =
+ ((dst_x & 0xffff) << B2R2_XY_X_SHIFT) |
+ ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP4.B2R2_SSZ =
+ ((dst_rect_area->width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_rect_area->height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ node->node.GROUP1.B2R2_TXY = 0;
+ node->node.GROUP1.B2R2_TSZ =
+ ((dst_rect_area->width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_rect_area->height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ }
+
+ if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 &&
+ dst_rect_area->y == 0) {
+ dump_nodes(node, false);
+ b2r2_log_debug("%s dst_read node done.\n", __func__);
+ }
+
+ /* blend */
+ node = node->next;
+ node->node.GROUP3.B2R2_SXY = 0;
+ node->node.GROUP3.B2R2_SSZ =
+ ((dst_rect_area->width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_rect_area->height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ /* contents of the foreground temporary buffer always at top left */
+ node->node.GROUP4.B2R2_SXY = 0;
+ node->node.GROUP4.B2R2_SSZ =
+ ((dst_rect_area->width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_rect_area->height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+
+ node->node.GROUP1.B2R2_TXY = 0;
+ node->node.GROUP1.B2R2_TSZ =
+ ((dst_rect_area->width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_rect_area->height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+
+ if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 &&
+ dst_rect_area->y == 0) {
+ dump_nodes(node, false);
+ b2r2_log_debug("%s Blend node done.\n", __func__);
+ }
+
+ /* writeback */
+ node = node->next;
+ if ((req->user_req.flags & B2R2_BLT_FLAG_DESTINATION_CLIP) != 0) {
+ clip_left = req->user_req.dst_clip_rect.x;
+ clip_top = req->user_req.dst_clip_rect.y;
+ clip_right = clip_left + req->user_req.dst_clip_rect.width - 1;
+ clip_bottom = clip_top + req->user_req.dst_clip_rect.height - 1;
+ }
+ /*
+ * Clamp the dst clip rectangle to buffer dimensions to prevent
+ * illegal writes. An illegal clip rectangle, e.g. outside the
+ * buffer will be ignored, resulting in nothing being clipped.
+ */
+ if (clip_left < 0 || req->user_req.dst_img.width <= clip_left)
+ clip_left = 0;
+
+ if (clip_top < 0 || req->user_req.dst_img.height <= clip_top)
+ clip_top = 0;
+
+ if (clip_right < 0 || req->user_req.dst_img.width <= clip_right)
+ clip_right = req->user_req.dst_img.width - 1;
+
+ if (clip_bottom < 0 || req->user_req.dst_img.height <= clip_bottom)
+ clip_bottom = req->user_req.dst_img.height - 1;
+
+ /*
+ * Only allow writing inside the clip rect.
+ * INTNL bit in B2R2_CWO should be zero.
+ */
+ node->node.GROUP6.B2R2_CWO =
+ ((clip_top & 0x7fff) << B2R2_CWO_Y_SHIFT) |
+ ((clip_left & 0x7fff) << B2R2_CWO_X_SHIFT);
+ node->node.GROUP6.B2R2_CWS =
+ ((clip_bottom & 0x7fff) << B2R2_CWS_Y_SHIFT) |
+ ((clip_right & 0x7fff) << B2R2_CWS_X_SHIFT);
+
+ if (yuv_multi_buffer_dst) {
+ const s32 dst_w = dst_rect_area->width;
+ const s32 dst_h = dst_rect_area->height;
+ int i = 0;
+ /* Number of nodes required to write chroma output */
+ int n_nodes = 1;
+ if (dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR ||
+ dst_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR)
+ n_nodes = 2;
+
+ node->node.GROUP4.B2R2_SXY = 0;
+ node->node.GROUP4.B2R2_SSZ =
+ ((dst_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+
+ /* Luma (Y-component) */
+ node->node.GROUP1.B2R2_TXY =
+ ((dst_x & 0xffff) << B2R2_XY_X_SHIFT) |
+ ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP1.B2R2_TSZ =
+ ((dst_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+
+ node->node.GROUP6.B2R2_CWO =
+ ((clip_top & 0x7fff) << B2R2_CWO_Y_SHIFT) |
+ ((clip_left & 0x7fff) << B2R2_CWO_X_SHIFT);
+ node->node.GROUP6.B2R2_CWS =
+ ((clip_bottom & 0x7fff) << B2R2_CWS_Y_SHIFT) |
+ ((clip_right & 0x7fff) << B2R2_CWS_X_SHIFT);
+
+ if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 &&
+ dst_rect_area->y == 0) {
+ dump_nodes(node, false);
+ b2r2_log_debug("%s Writeback luma node done.\n",
+ __func__);
+ }
+
+ node = node->next;
+
+ /*
+ * Chroma components. 1 or 2 nodes
+ * for semi-planar or planar buffer respectively.
+ */
+ for (i = 0; i < n_nodes && node != NULL; ++i) {
+
+ node->node.GROUP4.B2R2_SXY = 0;
+ node->node.GROUP4.B2R2_SSZ =
+ ((dst_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+
+ switch (dst_fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ /*
+ * Chroma is half the size of luma.
+ * Must round up the chroma size to handle
+ * cases when luma size is not divisible by 2.
+ * E.g. luma_width==7 requires chroma_width==4.
+ * Chroma_width==7/2==3 is only enough
+ * for luma_width==6.
+ */
+ node->node.GROUP1.B2R2_TXY =
+ (((dst_x & 0xffff) >> 1) << B2R2_XY_X_SHIFT) |
+ (((dst_y & 0xffff) >> 1) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP1.B2R2_TSZ =
+ ((((dst_w + 1) & 0xfff) >> 1) << B2R2_SZ_WIDTH_SHIFT) |
+ ((((dst_h + 1) & 0xfff) >> 1) << B2R2_SZ_HEIGHT_SHIFT);
+ break;
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ /*
+ * Now chroma is half the size of luma only
+ * in horizontal direction.
+ * Same rounding applies as
+ * for 420 formats above, except it is only
+ * done horizontally.
+ */
+ node->node.GROUP1.B2R2_TXY =
+ (((dst_x & 0xffff) >> 1) << B2R2_XY_X_SHIFT) |
+ ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP1.B2R2_TSZ =
+ ((((dst_w + 1) & 0xfff) >> 1) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ break;
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ /*
+ * Chroma has the same resolution as luma.
+ */
+ node->node.GROUP1.B2R2_TXY =
+ ((dst_x & 0xffff) << B2R2_XY_X_SHIFT) |
+ ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP1.B2R2_TSZ =
+ ((dst_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ break;
+ default:
+ break;
+ }
+
+ node->node.GROUP6.B2R2_CWO =
+ ((clip_top & 0x7fff) << B2R2_CWO_Y_SHIFT) |
+ ((clip_left & 0x7fff) << B2R2_CWO_X_SHIFT);
+ node->node.GROUP6.B2R2_CWS =
+ ((clip_bottom & 0x7fff) << B2R2_CWS_Y_SHIFT) |
+ ((clip_right & 0x7fff) << B2R2_CWS_X_SHIFT);
+
+ if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 &&
+ dst_rect_area->y == 0) {
+ dump_nodes(node, false);
+ b2r2_log_debug("%s Writeback chroma node "
+ "%d of %d done.\n",
+ __func__, i + 1, n_nodes);
+ }
+
+ node = node->next;
+ }
+ } else {
+ node->node.GROUP4.B2R2_SXY = 0;
+ node->node.GROUP4.B2R2_SSZ =
+ ((dst_rect_area->width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_rect_area->height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ node->node.GROUP1.B2R2_TXY =
+ ((dst_x & 0xffff) << B2R2_XY_X_SHIFT) |
+ ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT);
+ node->node.GROUP1.B2R2_TSZ =
+ ((dst_rect_area->width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((dst_rect_area->height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+
+ if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 &&
+ dst_rect_area->y == 0) {
+ dump_nodes(node, false);
+ b2r2_log_debug("%s Writeback node done.\n", __func__);
+ }
+ }
+
+ b2r2_log_info("%s DONE\n", __func__);
+}
diff --git a/drivers/video/b2r2/b2r2_generic.h b/drivers/video/b2r2/b2r2_generic.h
new file mode 100644
index 00000000000..d3dbd00ef1e
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_generic.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 generic. Full coverage of user interface but
+ * non optimized implementation. For Fallback purposes.
+ *
+ * Author: Maciej Socha <maciej.socha@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef _LINUX_VIDEO_B2R2_GENERIC_H
+#define _LINUX_VIDEO_B2R2_GENERIC_H
+
+#include <video/b2r2_blt.h>
+
+#include "b2r2_internal.h"
+
+/**
+ * b2r2_generic_init()
+ */
+void b2r2_generic_init(void);
+
+/**
+ * b2r2_generic_exit()
+ */
+void b2r2_generic_exit(void);
+
+/**
+ * b2r2_generic_analyze()
+ */
+int b2r2_generic_analyze(const struct b2r2_blt_request *req,
+ s32 *work_buf_width,
+ s32 *work_buf_height,
+ u32 *work_buf_count,
+ u32 *node_count);
+/**
+ * b2r2_generic_configure()
+ */
+int b2r2_generic_configure(const struct b2r2_blt_request *req,
+ struct b2r2_node *first,
+ struct b2r2_work_buf *tmp_bufs,
+ u32 buf_count);
+/**
+ * b2r2_generic_set_areas()
+ */
+void b2r2_generic_set_areas(const struct b2r2_blt_request *req,
+ struct b2r2_node *first,
+ struct b2r2_blt_rect *dst_rect_area);
+#endif
diff --git a/drivers/video/b2r2/b2r2_global.h b/drivers/video/b2r2/b2r2_global.h
new file mode 100644
index 00000000000..e4b1358024f
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_global.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 global definitions
+ *
+ * Author: Robert Fekete <robert.fekete@stericsson.com>
+ * Author: Paul Wannback
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __B2R2_GLOBAL_H
+#define __B2R2_GLOBAL_H
+
+/** Sources involved */
+
+struct b2r2_system {
+ unsigned int B2R2_NIP;
+ unsigned int B2R2_CIC;
+ unsigned int B2R2_INS;
+ unsigned int B2R2_ACK;
+};
+
+struct b2r2_target {
+ unsigned int B2R2_TBA;
+ unsigned int B2R2_TTY;
+ unsigned int B2R2_TXY;
+ unsigned int B2R2_TSZ;
+};
+
+struct b2r2_color_fill {
+ unsigned int B2R2_S1CF;
+ unsigned int B2R2_S2CF;
+};
+
+struct b2r2_src_config {
+ unsigned int B2R2_SBA;
+ unsigned int B2R2_STY;
+ unsigned int B2R2_SXY;
+ unsigned int B2R2_SSZ;
+};
+
+struct b2r2_clip {
+ unsigned int B2R2_CWO;
+ unsigned int B2R2_CWS;
+};
+
+struct b2r2_color_key {
+ unsigned int B2R2_KEY1;
+ unsigned int B2R2_KEY2;
+};
+
+struct b2r2_clut {
+ unsigned int B2R2_CCO;
+ unsigned int B2R2_CML;
+};
+
+struct b2r2_rsz_pl_mask {
+ unsigned int B2R2_FCTL;
+ unsigned int B2R2_PMK;
+};
+
+struct b2r2_Cr_luma_rsz {
+ unsigned int B2R2_RSF;
+ unsigned int B2R2_RZI;
+ unsigned int B2R2_HFP;
+ unsigned int B2R2_VFP;
+};
+
+struct b2r2_flikr_filter {
+ unsigned int B2R2_Coeff0;
+ unsigned int B2R2_Coeff1;
+ unsigned int B2R2_Coeff2;
+ unsigned int B2R2_Coeff3;
+};
+
+struct b2r2_xyl {
+ unsigned int B2R2_XYL;
+ unsigned int B2R2_XYP;
+};
+
+struct b2r2_sau {
+ unsigned int B2R2_SAR;
+ unsigned int B2R2_USR;
+};
+
+struct b2r2_vm {
+ unsigned int B2R2_VMX0;
+ unsigned int B2R2_VMX1;
+ unsigned int B2R2_VMX2;
+ unsigned int B2R2_VMX3;
+};
+
+struct b2r2_link_list {
+
+ struct b2r2_system GROUP0;
+ struct b2r2_target GROUP1;
+ struct b2r2_color_fill GROUP2;
+ struct b2r2_src_config GROUP3;
+ struct b2r2_src_config GROUP4;
+ struct b2r2_src_config GROUP5;
+ struct b2r2_clip GROUP6;
+ struct b2r2_clut GROUP7;
+ struct b2r2_rsz_pl_mask GROUP8;
+ struct b2r2_Cr_luma_rsz GROUP9;
+ struct b2r2_Cr_luma_rsz GROUP10;
+ struct b2r2_flikr_filter GROUP11;
+ struct b2r2_color_key GROUP12;
+ struct b2r2_xyl GROUP13;
+ struct b2r2_sau GROUP14;
+ struct b2r2_vm GROUP15;
+ struct b2r2_vm GROUP16;
+
+ unsigned int B2R2_RESERVED[2];
+};
+
+
+#endif /* !defined(__B2R2_GLOBAL_H) */
diff --git a/drivers/video/b2r2/b2r2_hw.h b/drivers/video/b2r2/b2r2_hw.h
new file mode 100644
index 00000000000..3a3239c1e5d
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_hw.h
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 hw definitions
+ *
+ * Author: Fredrik Allansson <fredrik.allansson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef B2R2_HW_H__
+#define B2R2_HW_H__
+
+#include <linux/bitops.h>
+
+/* Scaling works in strips 128 pixels wide */
+#define B2R2_RESCALE_MAX_WIDTH 128
+
+/* Rotation works in strips 16 pixels wide */
+#define B2R2_ROTATE_MAX_WIDTH 16
+
+/* B2R2 color formats */
+#define B2R2_COLOR_FORMAT_SHIFT 16
+enum b2r2_native_fmt {
+ /* RGB formats */
+ B2R2_NATIVE_RGB565 = 0x00 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_RGB888 = 0x01 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_ARGB8565 = 0x04 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_ARGB8888 = 0x05 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_ARGB1555 = 0x06 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_ARGB4444 = 0x07 << B2R2_COLOR_FORMAT_SHIFT,
+
+ /* YCbCr formats */
+ B2R2_NATIVE_YCBCR888 = 0x10 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_YCBCR422R = 0x12 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_AYCBCR8888 = 0x15 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_YCBCR42X_MB = 0x14 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_YCBCR42X_R2B = 0x16 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_YCBCR42X_MBN = 0x0e << B2R2_COLOR_FORMAT_SHIFT,
+
+ /* CLUT formats */
+ B2R2_NATIVE_CLUT2 = 0x09 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_CLUT8 = 0x0b << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_ACLUT44 = 0x0c << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_ACLUT88 = 0x0d << B2R2_COLOR_FORMAT_SHIFT,
+
+ /* Misc. formats */
+ B2R2_NATIVE_A1 = 0x18 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_A8 = 0x19 << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_YUV = 0x1e << B2R2_COLOR_FORMAT_SHIFT,
+ B2R2_NATIVE_BYTE = 0x1f << B2R2_COLOR_FORMAT_SHIFT,
+};
+
+/* B2R2_CIC register values */
+enum b2r2_cic {
+ B2R2_CIC_COLOR_FILL = BIT(1),/*0x00000002*/
+ B2R2_CIC_SOURCE_1 = BIT(2),/*0x00000004*/
+ B2R2_CIC_SOURCE_2 = BIT(3),/*0x00000008*/
+ B2R2_CIC_SOURCE_3 = BIT(4),/*0x00000010*/
+ B2R2_CIC_CLIP_WINDOW = BIT(5),/*0x00000020*/
+ B2R2_CIC_CLUT = BIT(6),/*0x00000040*/
+ B2R2_CIC_FILTER_CONTROL = BIT(7),/*0x00000080*/
+ B2R2_CIC_RESIZE_CHROMA = BIT(8),/*0x00000100*/
+ B2R2_CIC_RESIZE_LUMA = BIT(9),/*0x00000200*/
+ B2R2_CIC_FLICKER_COEFF = BIT(10),/*0x00000400*/
+ B2R2_CIC_COLOR_KEY = BIT(11),/*0x00000800*/
+ B2R2_CIC_XYL = BIT(12),/*0x00001000*/
+ B2R2_CIC_SAU = BIT(13),/*0x00002000*/
+ B2R2_CIC_IVMX = BIT(14),/*0x00004000*/
+ B2R2_CIC_OVMX = BIT(15),/*0x00008000*/
+ B2R2_CIC_PACEDOT = BIT(16),/*0x00010000*/
+ B2R2_CIC_VC1 = BIT(17)/*0x00020000*/
+};
+
+/* B2R2_INS register values */
+#define B2R2_INS_SOURCE_1_SHIFT 0
+#define B2R2_INS_SOURCE_2_SHIFT 3
+#define B2R2_INS_SOURCE_3_SHIFT 5
+#define B2R2_INS_IVMX_SHIFT 6
+#define B2R2_INS_CLUTOP_SHIFT 7
+#define B2R2_INS_RESCALE2D_SHIFT 8
+#define B2R2_INS_FLICK_FILT_SHIFT 9
+#define B2R2_INS_RECT_CLIP_SHIFT 10
+#define B2R2_INS_CKEY_SHIFT 11
+#define B2R2_INS_OVMX_SHIFT 12
+#define B2R2_INS_DEI_SHIFT 13
+#define B2R2_INS_PLANE_MASK_SHIFT 14
+#define B2R2_INS_XYL_SHIFT 15
+#define B2R2_INS_DOT_SHIFT 16
+#define B2R2_INS_VC1R_SHIFT 17
+#define B2R2_INS_ROTATION_SHIFT 18
+#define B2R2_INS_PACE_DOWN_SHIFT 30
+#define B2R2_INS_BLITCOMPIRQ_SHIFT 31
+enum b2r2_ins {
+ /* Source 1 config */
+ B2R2_INS_SOURCE_1_FETCH_FROM_MEM = 0x1 << B2R2_INS_SOURCE_1_SHIFT,
+ B2R2_INS_SOURCE_1_COLOR_FILL_REGISTER = 0x3 << B2R2_INS_SOURCE_1_SHIFT,
+ B2R2_INS_SOURCE_1_DIRECT_COPY = 0x4 << B2R2_INS_SOURCE_1_SHIFT,
+ B2R2_INS_SOURCE_1_DIRECT_FILL = 0x7 << B2R2_INS_SOURCE_1_SHIFT,
+
+ /* Source 2 config */
+ B2R2_INS_SOURCE_2_FETCH_FROM_MEM = 0x1 << B2R2_INS_SOURCE_2_SHIFT,
+ B2R2_INS_SOURCE_2_COLOR_FILL_REGISTER = 0x3 << B2R2_INS_SOURCE_2_SHIFT,
+
+ /* Source 3 config */
+ B2R2_INS_SOURCE_3_FETCH_FROM_MEM = 0x1 << B2R2_INS_SOURCE_3_SHIFT,
+
+ /* Other configs */
+ B2R2_INS_IVMX_ENABLED = 0x1 << B2R2_INS_IVMX_SHIFT,
+ B2R2_INS_CLUTOP_ENABLED = 0x1 << B2R2_INS_CLUTOP_SHIFT,
+ B2R2_INS_RESCALE2D_ENABLED = 0x1 << B2R2_INS_RESCALE2D_SHIFT,
+ B2R2_INS_FLICK_FILT_ENABLED = 0x1 << B2R2_INS_FLICK_FILT_SHIFT,
+ B2R2_INS_RECT_CLIP_ENABLED = 0x1 << B2R2_INS_RECT_CLIP_SHIFT,
+ B2R2_INS_CKEY_ENABLED = 0x1 << B2R2_INS_CKEY_SHIFT,
+ B2R2_INS_OVMX_ENABLED = 0x1 << B2R2_INS_OVMX_SHIFT,
+ B2R2_INS_DEI_ENABLED = 0x1 << B2R2_INS_DEI_SHIFT,
+ B2R2_INS_PLANE_MASK_ENABLED = 0x1 << B2R2_INS_PLANE_MASK_SHIFT,
+ B2R2_INS_XYL_ENABLED = 0x1 << B2R2_INS_XYL_SHIFT,
+ B2R2_INS_DOT_ENABLED = 0x1 << B2R2_INS_DOT_SHIFT,
+ B2R2_INS_VC1R_ENABLED = 0x1 << B2R2_INS_VC1R_SHIFT,
+ B2R2_INS_ROTATION_ENABLED = 0x1 << B2R2_INS_ROTATION_SHIFT,
+ B2R2_INS_PACE_DOWN_ENABLED = 0x1 << B2R2_INS_PACE_DOWN_SHIFT,
+ B2R2_INS_BLITCOMPIRQ_ENABLED = 0x1 << B2R2_INS_BLITCOMPIRQ_SHIFT,
+
+};
+
+/* B2R2_ACK register values */
+#define B2R2_ACK_MODE_SHIFT 0
+#define B2R2_ACK_SWAP_FG_BG_SHIFT 4
+#define B2R2_ACK_GALPHA_ROPID_SHIFT 8
+#define B2R2_ACK_CKEY_BLUE_SHIFT 16
+#define B2R2_ACK_CKEY_GREEN_SHIFT 18
+#define B2R2_ACK_CKEY_RED_SHIFT 20
+#define B2R2_ACK_CKEY_SEL_SHIFT 22
+enum b2r2_ack {
+ /* ALU operation modes */
+ B2R2_ACK_MODE_LOGICAL_OPERATION = 0x1 << B2R2_ACK_MODE_SHIFT,
+ B2R2_ACK_MODE_BLEND_NOT_PREMULT = 0x2 << B2R2_ACK_MODE_SHIFT,
+ B2R2_ACK_MODE_BLEND_PREMULT = 0x3 << B2R2_ACK_MODE_SHIFT,
+ B2R2_ACK_MODE_CLIPMASK_LOGICAL_FIRST_PASS = 0x4 << B2R2_ACK_MODE_SHIFT,
+ B2R2_ACK_MODE_CLIPMASK_BLEND = 0x5 << B2R2_ACK_MODE_SHIFT,
+ B2R2_ACK_MODE_BYPASS_S2_S3 = 0x7 << B2R2_ACK_MODE_SHIFT,
+ B2R2_ACK_MODE_CLIPMASK_LOGICAL_SECOND_PASS = 0x8 << B2R2_ACK_MODE_SHIFT,
+ B2R2_ACK_MODE_CLIPMASK_XYL_LOGICAL = 0x9 << B2R2_ACK_MODE_SHIFT,
+ B2R2_ACK_MODE_CLIPMASK_XYL_BLEND_NOT_PREMULT = 0xa << B2R2_ACK_MODE_SHIFT,
+ B2R2_ACK_MODE_CLIPMASK_XYL_BLEND_PREMULT = 0xb << B2R2_ACK_MODE_SHIFT,
+
+ /* ALU channel selection */
+ B2R2_ACK_SWAP_FG_BG = 0x1 << B2R2_ACK_SWAP_FG_BG_SHIFT,
+
+ /* Global alpha and ROP IDs */
+ B2R2_ACK_ROP_CLEAR = 0x0 << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_AND = 0x1 << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_AND_REV = 0x2 << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_COPY = 0x3 << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_AND_INV = 0x4 << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_NOOP = 0x5 << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_XOR = 0x6 << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_OR = 0x7 << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_NOR = 0x8 << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_EQUIV = 0x9 << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_INVERT = 0xa << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_OR_REV = 0xb << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_COPY_INV = 0xc << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_OR_INV = 0xd << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_NAND = 0xe << B2R2_ACK_GALPHA_ROPID_SHIFT,
+ B2R2_ACK_ROP_SET = 0xf << B2R2_ACK_GALPHA_ROPID_SHIFT,
+
+ /* Color key configuration bits */
+ B2R2_ACK_CKEY_BLUE_MATCH_IF_BETWEEN = 0x1 << B2R2_ACK_CKEY_BLUE_SHIFT,
+ B2R2_ACK_CKEY_BLUE_MATCH_IF_LT_OR_GT = 0x2 << B2R2_ACK_CKEY_BLUE_SHIFT,
+ B2R2_ACK_CKEY_RED_MATCH_IF_BETWEEN = 0x1 << B2R2_ACK_CKEY_GREEN_SHIFT,
+ B2R2_ACK_CKEY_RED_MATCH_IF_LT_OR_GT = 0x2 << B2R2_ACK_CKEY_GREEN_SHIFT,
+ B2R2_ACK_CKEY_GREEN_MATCH_IF_BETWEEN = 0x1 << B2R2_ACK_CKEY_RED_SHIFT,
+ B2R2_ACK_CKEY_GREEN_MATCH_IF_LT_OR_GT = 0x2 << B2R2_ACK_CKEY_RED_SHIFT,
+
+ /* Color key input selection */
+ B2R2_ACK_CKEY_SEL_DEST = 0x0 << B2R2_ACK_CKEY_SEL_SHIFT,
+ B2R2_ACK_CKEY_SEL_SRC_BEFORE_CLUT = 0x1 << B2R2_ACK_CKEY_SEL_SHIFT,
+ B2R2_ACK_CKEY_SEL_SRC_AFTER_CLUT = 0x2 << B2R2_ACK_CKEY_SEL_SHIFT,
+ B2R2_ACK_CKEY_SEL_BLANKING_S2_ALPHA = 0x3 << B2R2_ACK_CKEY_SEL_SHIFT,
+};
+
+/* Common <S/T>TY defines */
+#define B2R2_TY_BITMAP_PITCH_SHIFT 0
+#define B2R2_TY_COLOR_FORM_SHIFT 16
+#define B2R2_TY_ALPHA_RANGE_SHIFT 21
+#define B2R2_TY_MB_ACCESS_MODE_SHIFT 23
+#define B2R2_TY_HSO_SHIFT 24
+#define B2R2_TY_VSO_SHIFT 25
+#define B2R2_TY_SUBBYTE_SHIFT 28
+#define B2R2_TY_ENDIAN_SHIFT 30
+#define B2R2_TY_SECURE_SHIFT 31
+
+/* Dummy enum for generalization of <S/T>TY registers */
+enum b2r2_ty {
+ /* Alpha range */
+ B2R2_TY_ALPHA_RANGE_128 = 0x0 << B2R2_TY_ALPHA_RANGE_SHIFT,
+ B2R2_TY_ALPHA_RANGE_255 = 0x1 << B2R2_TY_ALPHA_RANGE_SHIFT,
+
+ /* Access mode in macro-block organized frame buffers */
+ B2R2_TY_MB_ACCESS_MODE_FRAME = 0x0 << B2R2_TY_MB_ACCESS_MODE_SHIFT,
+ B2R2_TY_MB_ACCESS_MODE_FIELD = 0x1 << B2R2_TY_MB_ACCESS_MODE_SHIFT,
+
+ /* Horizontal scan order */
+ B2R2_TY_HSO_LEFT_TO_RIGHT = 0x0 << B2R2_TY_HSO_SHIFT,
+ B2R2_TY_HSO_RIGHT_TO_LEFT = 0x1 << B2R2_TY_HSO_SHIFT,
+
+ /* Vertical scan order */
+ B2R2_TY_VSO_TOP_TO_BOTTOM = 0x0 << B2R2_TY_VSO_SHIFT,
+ B2R2_TY_VSO_BOTTOM_TO_TOP = 0x1 << B2R2_TY_VSO_SHIFT,
+
+ /* Pixel ordering for sub-byte formats (position of right-most pixel) */
+ B2R2_TY_SUBBYTE_MSB = 0x0 << B2R2_TY_SUBBYTE_SHIFT,
+ B2R2_TY_SUBBYTE_LSB = 0x1 << B2R2_TY_SUBBYTE_SHIFT,
+
+ /* Bitmap endianess */
+ B2R2_TY_ENDIAN_BIG_NOT_LITTLE = 0x1 << B2R2_TY_ENDIAN_SHIFT,
+
+ /* Secureness of the target memory region */
+ B2R2_TY_SECURE_UNSECURE = 0x0 << B2R2_TY_SECURE_SHIFT,
+ B2R2_TY_SECURE_SECURE = 0x1 << B2R2_TY_SECURE_SHIFT,
+
+ /* Dummy to make sure the data type is large enough */
+ B2R2_TY_DUMMY = 0xffffffff,
+};
+
+/* B2R2_TTY register values */
+#define B2R2_TTY_CB_NOT_CR_SHIFT 22
+#define B2R2_TTY_RGB_ROUND_SHIFT 26
+#define B2R2_TTY_CHROMA_NOT_LUMA_SHIFT 27
+enum b2r2_tty {
+
+ /* Chroma component selection */
+ B2R2_TTY_CB_NOT_CR = 0x1 << B2R2_TTY_CB_NOT_CR_SHIFT,
+
+ /* RGB rounding mode */
+ B2R2_TTY_RGB_ROUND_NORMAL = 0x0 << B2R2_TTY_RGB_ROUND_SHIFT,
+ B2R2_TTY_RGB_ROUND_DITHER = 0x1 << B2R2_TTY_RGB_ROUND_SHIFT,
+
+ /* Component selection for splitted frame buffer formats */
+ B2R2_TTY_CHROMA_NOT_LUMA = 0x1 << B2R2_TTY_CHROMA_NOT_LUMA_SHIFT,
+};
+
+/* B2R2_S1TY register values */
+#define B2R2_S1TY_A1_SUBST_SHIFT 22
+#define B2R2_S1TY_ROTATION_SHIFT 27
+#define B2R2_S1TY_RGB_EXPANSION_SHIFT 29
+enum b2r2_s1ty {
+
+ /* Alpha bit substitution mode for ARGB1555 */
+ B2R2_S1TY_A1_SUBST_KEY_MODE = 0x1 << B2R2_S1TY_A1_SUBST_SHIFT,
+
+ /* Input rectangle rotation (NOT YET IMPLEMENTED) */
+ B2R2_S1TY_ENABLE_ROTATION = 0x1 << B2R2_S1TY_ROTATION_SHIFT,
+
+ /* RGB expansion mode */
+ B2R2_S1TY_RGB_EXPANSION_MSB_DUP = 0x0 << B2R2_S1TY_RGB_EXPANSION_SHIFT,
+ B2R2_S1TY_RGB_EXPANSION_LSP_ZERO = 0x1 << B2R2_S1TY_RGB_EXPANSION_SHIFT,
+};
+
+/* B2R2_S1TY register values */
+#define B2R2_S2TY_A1_SUBST_SHIFT 22
+#define B2R2_S2TY_CHROMA_LEFT_SHIFT 26
+#define B2R2_S2TY_RGB_EXPANSION_SHIFT 29
+enum b2r2_s2ty {
+
+ /* Alpha bit substitution mode for ARGB1555 */
+ B2R2_S2TY_A1_SUBST_KEY_MODE = 0x1 << B2R2_S2TY_A1_SUBST_SHIFT,
+
+ /* Chroma left extension */
+ B2R2_S2TY_CHROMA_LEFT_EXT_FOLLOWING_PIXEL = 0x0
+ << B2R2_S2TY_CHROMA_LEFT_SHIFT,
+ B2R2_S2TY_CHROMA_LEFT_EXT_AVERAGE = 0x1 << B2R2_S2TY_CHROMA_LEFT_SHIFT,
+
+ /* RGB expansion mode */
+ B2R2_S2TY_RGB_EXPANSION_MSB_DUP = 0x0 << B2R2_S2TY_RGB_EXPANSION_SHIFT,
+ B2R2_S2TY_RGB_EXPANSION_LSP_ZERO = 0x1 << B2R2_S2TY_RGB_EXPANSION_SHIFT,
+};
+
+/* B2R2_S1TY register values */
+#define B2R2_S3TY_BLANK_ACC_SHIFT 26
+enum b2r2_s3ty {
+ /* Enables "blank" access on this source (nothing will be fetched from
+ memory) */
+ B2R2_S3TY_ENABLE_BLANK_ACCESS = 0x1 << B2R2_S3TY_BLANK_ACC_SHIFT,
+};
+
+/* B2R2_<S or T>XY register values */
+#define B2R2_XY_X_SHIFT 0
+#define B2R2_XY_Y_SHIFT 16
+
+/* B2R2_<S or T>SZ register values */
+#define B2R2_SZ_WIDTH_SHIFT 0
+#define B2R2_SZ_HEIGHT_SHIFT 16
+
+/* Clip window offset (top left coordinates) */
+#define B2R2_CWO_X_SHIFT 0
+#define B2R2_CWO_Y_SHIFT 16
+
+/* Clip window stop (bottom right coordinates) */
+#define B2R2_CWS_X_SHIFT 0
+#define B2R2_CWS_Y_SHIFT 16
+
+/* Color look-up table */
+enum b2r2_cco {
+ B2R2_CCO_CLUT_COLOR_CORRECTION = (1 << 16),
+ B2R2_CCO_CLUT_UPDATE = (1 << 18),
+ B2R2_CCO_CLUT_ON_S1 = (1 << 15)
+};
+
+/* Filter control (2D resize control) */
+enum b2r2_fctl {
+ /* Horizontal 2D filter mode */
+ B2R2_FCTL_HF2D_MODE_ENABLE_COLOR_CHANNEL_FILTER = BIT(0),
+ B2R2_FCTL_HF2D_MODE_ENABLE_ALPHA_CHANNEL_FILTER = BIT(1),
+ B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER = BIT(2),
+
+ /* Vertical 2D filter mode */
+ B2R2_FCTL_VF2D_MODE_ENABLE_COLOR_CHANNEL_FILTER = BIT(4),
+ B2R2_FCTL_VF2D_MODE_ENABLE_ALPHA_CHANNEL_FILTER = BIT(5),
+ B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER = BIT(6),
+
+ /* Alpha borders */
+ B2R2_FCTL_ENABLE_ALPHA_BORDER_RIGHT = BIT(12),
+ B2R2_FCTL_ENABLE_ALPHA_BORDER_LEFT = BIT(13),
+ B2R2_FCTL_ENABLE_ALPHA_BORDER_BOTTOM = BIT(14),
+ B2R2_FCTL_ENABLE_ALPHA_BORDER_TOP = BIT(15),
+
+ /* Luma path horizontal 2D filter mode */
+ B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_FILTER = BIT(24),
+ B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_RESIZER = BIT(25),
+
+ /* Luma path vertical 2D filter mode */
+ B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_FILTER = BIT(28),
+ B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_RESIZER = BIT(29),
+};
+
+/* Resize scaling factor */
+#define B2R2_RSF_HSRC_INC_SHIFT 0
+#define B2R2_RSF_VSRC_INC_SHIFT 16
+
+/* Resizer initialization */
+#define B2R2_RZI_HSRC_INIT_SHIFT 0
+#define B2R2_RZI_HNB_REPEAT_SHIFT 12
+#define B2R2_RZI_VSRC_INIT_SHIFT 16
+#define B2R2_RZI_VNB_REPEAT_SHIFT 28
+
+/* Default values for the resizer */
+#define B2R2_RZI_DEFAULT_HNB_REPEAT (3 << B2R2_RZI_HNB_REPEAT_SHIFT)
+#define B2R2_RZI_DEFAULT_VNB_REPEAT (3 << B2R2_RZI_VNB_REPEAT_SHIFT)
+
+/* VMX register values for RGB to YUV color conversion */
+/* Magic numbers from 27.11 in DB8500_DesignSpecification_v2.5.pdf */
+
+/* 601 Video Matrix (standard 601 conversion) */
+#define B2R2_VMX0_RGB_TO_YUV_601_VIDEO 0x107e4beb
+#define B2R2_VMX1_RGB_TO_YUV_601_VIDEO 0x0982581d
+#define B2R2_VMX2_RGB_TO_YUV_601_VIDEO 0xfa9ea483
+#define B2R2_VMX3_RGB_TO_YUV_601_VIDEO 0x08000080
+
+/* 601 Gfx Matrix (full range conversion) */
+#define B2R2_VMX0_RGB_TO_YUV_601_GFX 0x0e1e8bee
+#define B2R2_VMX1_RGB_TO_YUV_601_GFX 0x08420419
+#define B2R2_VMX2_RGB_TO_YUV_601_GFX 0xfb5ed471
+#define B2R2_VMX3_RGB_TO_YUV_601_GFX 0x08004080
+
+/* 709 Video Matrix (standard 709 conversion) */
+#define B2R2_VMX0_RGB_TO_YUV_709_VIDEO 0x107e27f4
+#define B2R2_VMX1_RGB_TO_YUV_709_VIDEO 0x06e2dc13
+#define B2R2_VMX2_RGB_TO_YUV_709_VIDEO 0xfc5e6c83
+#define B2R2_VMX3_RGB_TO_YUV_709_VIDEO 0x08000080
+
+/* 709 Gfx Matrix (standard 709 conversion) */
+#define B2R2_VMX0_RGB_TO_YUV_709_GFX 0x0e3e6bf5
+#define B2R2_VMX1_RGB_TO_YUV_709_GFX 0x05e27410
+#define B2R2_VMX2_RGB_TO_YUV_709_GFX 0xfcdea471
+#define B2R2_VMX3_RGB_TO_YUV_709_GFX 0x08004080
+
+/* VMX register values for YUV to RGB color conversion */
+
+/* 601 Video Matrix (standard 601 conversion) */
+#define B2R2_VMX0_YUV_TO_RGB_601_VIDEO 0x2c440000
+#define B2R2_VMX1_YUV_TO_RGB_601_VIDEO 0xe9a403aa
+#define B2R2_VMX2_YUV_TO_RGB_601_VIDEO 0x0004013f
+#define B2R2_VMX3_YUV_TO_RGB_601_VIDEO 0x34f21322
+
+/* 601 Gfx Matrix (full range conversion) */
+#define B2R2_VMX0_YUV_TO_RGB_601_GFX 0x3324a800
+#define B2R2_VMX1_YUV_TO_RGB_601_GFX 0xe604ab9c
+#define B2R2_VMX2_YUV_TO_RGB_601_GFX 0x0004a957
+#define B2R2_VMX3_YUV_TO_RGB_601_GFX 0x32121eeb
+
+/* 709 Video Matrix (standard 709 conversion) */
+#define B2R2_VMX0_YUV_TO_RGB_709_VIDEO 0x31440000
+#define B2R2_VMX1_YUV_TO_RGB_709_VIDEO 0xf16403d1
+#define B2R2_VMX2_YUV_TO_RGB_709_VIDEO 0x00040145
+#define B2R2_VMX3_YUV_TO_RGB_709_VIDEO 0x33b14b18
+
+/* 709 Gfx Matrix (standard 709 conversion) */
+#define B2R2_VMX0_YUV_TO_RGB_709_GFX 0x3964a800
+#define B2R2_VMX1_YUV_TO_RGB_709_GFX 0xef04abc9
+#define B2R2_VMX2_YUV_TO_RGB_709_GFX 0x0004a95f
+#define B2R2_VMX3_YUV_TO_RGB_709_GFX 0x307132df
+
+/* VMX register values for RGB to BGR conversion */
+#define B2R2_VMX0_RGB_TO_BGR 0x00000100
+#define B2R2_VMX1_RGB_TO_BGR 0x00040000
+#define B2R2_VMX2_RGB_TO_BGR 0x20000000
+#define B2R2_VMX3_RGB_TO_BGR 0x00000000
+
+/* VMX register values for BGR to YUV color conversion */
+/* Note: All BGR -> YUV values are calculated by multiplying
+ * the RGB -> YUV matrices [A], with [S] to form [A]x[S] where
+ * |0 0 1|
+ * S = |0 1 0|
+ * |1 0 0|
+ * Essentially swapping first and third columns in
+ * the matrices (VMX0, VMX1 and VMX2 values).
+ * The offset vector VMX3 remains untouched.
+ * Put another way, the value of bits 0 through 9
+ * is swapped with the value of
+ * bits 20 through 31 in VMX0, VMX1 and VMX2,
+ * taking into consideration the compression
+ * that is used on bits 0 through 9. Bit 0 being LSB.
+ */
+
+/* 601 Video Matrix (standard 601 conversion) */
+#define B2R2_VMX0_BGR_TO_YUV_601_VIDEO 0xfd7e4883
+#define B2R2_VMX1_BGR_TO_YUV_601_VIDEO 0x03a2584c
+#define B2R2_VMX2_BGR_TO_YUV_601_VIDEO 0x107ea7d4
+#define B2R2_VMX3_BGR_TO_YUV_601_VIDEO 0x08000080
+
+/* 601 Gfx Matrix (full range conversion) */
+#define B2R2_VMX0_BGR_TO_YUV_601_GFX 0xfdde8870
+#define B2R2_VMX1_BGR_TO_YUV_601_GFX 0x03220442
+#define B2R2_VMX2_BGR_TO_YUV_601_GFX 0x0e3ed7da
+#define B2R2_VMX3_BGR_TO_YUV_601_GFX 0x08004080
+
+/* 709 Video Matrix (standard 709 conversion) */
+#define B2R2_VMX0_BGR_TO_YUV_709_VIDEO 0xfe9e2483
+#define B2R2_VMX1_BGR_TO_YUV_709_VIDEO 0x0262dc37
+#define B2R2_VMX2_BGR_TO_YUV_709_VIDEO 0x107e6fe2
+#define B2R2_VMX3_BGR_TO_YUV_709_VIDEO 0x08000080
+
+/* 709 Gfx Matrix (standard 709 conversion) */
+#define B2R2_VMX0_BGR_TO_YUV_709_GFX 0xfebe6871
+#define B2R2_VMX1_BGR_TO_YUV_709_GFX 0x0202742f
+#define B2R2_VMX2_BGR_TO_YUV_709_GFX 0x0e3ea7e6
+#define B2R2_VMX3_BGR_TO_YUV_709_GFX 0x08004080
+
+
+/* VMX register values for YUV to BGR conversion */
+/* Note: All YUV -> BGR values are constructed
+ * from the YUV -> RGB ones, by swapping
+ * first and third rows in the matrix
+ * (VMX0 and VMX2 values). Further, the first and
+ * third values in the offset vector need to be
+ * swapped as well, i.e. bits 0 through 9 are swapped
+ * with bits 20 through 29 in the VMX3 value.
+ * Bit 0 being LSB.
+ */
+
+/* 601 Video Matrix (standard 601 conversion) */
+#define B2R2_VMX0_YUV_TO_BGR_601_VIDEO 0x0004013f
+#define B2R2_VMX1_YUV_TO_BGR_601_VIDEO 0xe9a403aa
+#define B2R2_VMX2_YUV_TO_BGR_601_VIDEO 0x2c440000
+#define B2R2_VMX3_YUV_TO_BGR_601_VIDEO 0x3222134f
+
+/* 601 Gfx Matrix (full range conversion) */
+#define B2R2_VMX0_YUV_TO_BGR_601_GFX 0x0004a957
+#define B2R2_VMX1_YUV_TO_BGR_601_GFX 0xe604ab9c
+#define B2R2_VMX2_YUV_TO_BGR_601_GFX 0x3324a800
+#define B2R2_VMX3_YUV_TO_BGR_601_GFX 0x2eb21f21
+
+/* 709 Video Matrix (standard 709 conversion) */
+#define B2R2_VMX0_YUV_TO_BGR_709_VIDEO 0x00040145
+#define B2R2_VMX1_YUV_TO_BGR_709_VIDEO 0xf16403d1
+#define B2R2_VMX2_YUV_TO_BGR_709_VIDEO 0x31440000
+#define B2R2_VMX3_YUV_TO_BGR_709_VIDEO 0x31814b3b
+
+/* 709 Gfx Matrix (standard 709 conversion) */
+#define B2R2_VMX0_YUV_TO_BGR_709_GFX 0x0004a95f
+#define B2R2_VMX1_YUV_TO_BGR_709_GFX 0xef04abc9
+#define B2R2_VMX2_YUV_TO_BGR_709_GFX 0x3964a800
+#define B2R2_VMX3_YUV_TO_BGR_709_GFX 0x2df13307
+
+
+/* VMX register values for YVU to RGB conversion */
+
+/* 601 Video Matrix (standard 601 conversion) */
+#define B2R2_VMX0_YVU_TO_RGB_601_VIDEO 0x00040120
+#define B2R2_VMX1_YVU_TO_RGB_601_VIDEO 0xF544034D
+#define B2R2_VMX2_YVU_TO_RGB_601_VIDEO 0x37840000
+#define B2R2_VMX3_YVU_TO_RGB_601_VIDEO 0x34f21322
+
+/* VMX register values for RGB to YVU conversion */
+
+/* 601 Video Matrix (standard 601 conversion) */
+#define B2R2_VMX0_RGB_TO_YVU_601_VIDEO 0xfa9ea483
+#define B2R2_VMX1_RGB_TO_YVU_601_VIDEO 0x0982581d
+#define B2R2_VMX2_RGB_TO_YVU_601_VIDEO 0x107e4beb
+#define B2R2_VMX3_RGB_TO_YVU_601_VIDEO 0x08000080
+
+/* VMX register values for YVU to BGR conversion */
+
+/* 601 Video Matrix (standard 601 conversion) */
+#define B2R2_VMX0_YVU_TO_BGR_601_VIDEO 0x37840000
+#define B2R2_VMX1_YVU_TO_BGR_601_VIDEO 0xF544034D
+#define B2R2_VMX2_YVU_TO_BGR_601_VIDEO 0x00040120
+#define B2R2_VMX3_YVU_TO_BGR_601_VIDEO 0x3222134F
+
+/* VMX register values for BGR to YVU conversion */
+
+/* 601 Video Matrix (standard 601 conversion) */
+#define B2R2_VMX0_BGR_TO_YVU_601_VIDEO 0x107ea7d4
+#define B2R2_VMX1_BGR_TO_YVU_601_VIDEO 0x03a2584c
+#define B2R2_VMX2_BGR_TO_YVU_601_VIDEO 0xfd7e4883
+#define B2R2_VMX3_BGR_TO_YVU_601_VIDEO 0x08000080
+
+/* VMX register values for YVU to YUV conversion */
+
+/* 601 Video Matrix (standard 601 conversion) */
+/* Internally, the components are in fact stored
+ * with luma in the middle, i.e. UYV, which is why
+ * the values are just like for RGB->BGR conversion.
+ */
+#define B2R2_VMX0_YVU_TO_YUV_601_VIDEO 0x00000100
+#define B2R2_VMX1_YVU_TO_YUV_601_VIDEO 0x00040000
+#define B2R2_VMX2_YVU_TO_YUV_601_VIDEO 0x20000000
+#define B2R2_VMX3_YVU_TO_YUV_601_VIDEO 0x00000000
+
+#endif /* B2R2_HW_H__ */
diff --git a/drivers/video/b2r2/b2r2_input_validation.c b/drivers/video/b2r2/b2r2_input_validation.c
new file mode 100644
index 00000000000..96bab5dfd17
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_input_validation.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> for ST-Ericsson
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "b2r2_input_validation.h"
+
+#include "b2r2_debug.h"
+#include "b2r2_utils.h"
+
+#include <video/b2r2_blt.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+
+static bool is_valid_format(enum b2r2_blt_fmt fmt);
+
+static bool is_valid_pitch_for_fmt(u32 pitch, s32 width,
+ enum b2r2_blt_fmt fmt);
+
+static bool is_aligned_width_for_fmt(s32 width, enum b2r2_blt_fmt fmt);
+static s32 width_2_complete_width(s32 width, enum b2r2_blt_fmt fmt);
+static bool is_complete_width_for_fmt(s32 width, enum b2r2_blt_fmt fmt);
+static bool is_valid_height_for_fmt(s32 height, enum b2r2_blt_fmt fmt);
+
+static bool validate_img(struct b2r2_blt_img *img);
+static bool validate_rect(struct b2r2_blt_rect *rect);
+
+
+static bool is_valid_format(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_1_BIT_A1:
+ case B2R2_BLT_FMT_8_BIT_A8:
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ case B2R2_BLT_FMT_16_BIT_RGB565:
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+
+static bool is_valid_pitch_for_fmt(u32 pitch, s32 width, enum b2r2_blt_fmt fmt)
+{
+ s32 complete_width;
+ u32 pitch_derived_from_width;
+
+ complete_width = width_2_complete_width(width, fmt);
+
+ pitch_derived_from_width =
+ b2r2_calc_pitch_from_width(complete_width, fmt);
+
+ if (pitch < pitch_derived_from_width)
+ return false;
+
+ switch (fmt) {
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ case B2R2_BLT_FMT_16_BIT_RGB565:
+ if (!b2r2_is_aligned(pitch, 2))
+ return false;
+
+ break;
+
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ if (!b2r2_is_aligned(pitch, 4))
+ return false;
+
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+
+static bool is_aligned_width_for_fmt(s32 width, enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ if (!b2r2_is_aligned(width, 4))
+ return false;
+
+ break;
+
+ case B2R2_BLT_FMT_1_BIT_A1:
+ if (!b2r2_is_aligned(width, 8))
+ return false;
+
+ break;
+
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ if (!b2r2_is_aligned(width, 2))
+ return false;
+
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static s32 width_2_complete_width(s32 width, enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ return b2r2_align_up(width, 2);
+
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ return b2r2_align_up(width, 16);
+
+ default:
+ return width;
+ }
+}
+
+static bool is_complete_width_for_fmt(s32 width, enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ if (!b2r2_is_aligned(width, 2))
+ return false;
+
+ break;
+
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ if (!b2r2_is_aligned(width, 16))
+ return false;
+
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static bool is_valid_height_for_fmt(s32 height, enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ if (!b2r2_is_aligned(height, 2))
+ return false;
+
+ break;
+
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ if (!b2r2_is_aligned(height, 16))
+ return false;
+
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static bool validate_img(struct b2r2_blt_img *img)
+{
+ /*
+ * So that we always can do width * height * bpp without overflowing a
+ * 32 bit signed integer. isqrt(s32_max / max_bpp) was used to
+ * calculate the value.
+ */
+ static const s32 max_img_width_height = 8191;
+
+ s32 img_size;
+
+ if (!is_valid_format(img->fmt)) {
+ b2r2_log_info("Validation Error: !is_valid_format(img->fmt)\n");
+ return false;
+ }
+
+ if (img->width < 0 || img->width > max_img_width_height ||
+ img->height < 0 || img->height > max_img_width_height) {
+ b2r2_log_info("Validation Error: "
+ "img->width < 0 || "
+ "img->width > max_img_width_height || "
+ "img->height < 0 || "
+ "img->height > max_img_width_height\n");
+ return false;
+ }
+
+ if (b2r2_is_mb_fmt(img->fmt)) {
+ if (!is_complete_width_for_fmt(img->width, img->fmt)) {
+ b2r2_log_info("Validation Error: "
+ "!is_complete_width_for_fmt(img->width, "
+ "img->fmt)\n");
+ return false;
+ }
+ } else {
+ if (img->pitch < 0) {
+ b2r2_log_info("Validation Error: img->pitch < 0\n");
+ return false;
+ }
+
+ if (0 == img->pitch &&
+ (!is_aligned_width_for_fmt(img->width, img->fmt) ||
+ !is_complete_width_for_fmt(img->width, img->fmt))) {
+ b2r2_log_info("Validation Error: "
+ "0 == img->pitch && "
+ "(!is_aligned_width_for_fmt(img->width, img->fmt) || "
+ "!is_complete_width_for_fmt(img->width, "
+ "img->fmt))\n");
+ return false;
+ }
+
+ if (img->pitch != 0 &&
+ !is_valid_pitch_for_fmt(img->pitch, img->width, img->fmt)) {
+ b2r2_log_info("Validation Error: "
+ "img->pitch != 0 && "
+ "!is_valid_pitch_for_fmt(img->pitch, img->width, "
+ "img->fmt)\n");
+ return false;
+ }
+ }
+
+ if (!is_valid_height_for_fmt(img->width, img->fmt)) {
+ b2r2_log_info("Validation Error: "
+ "!is_valid_height_for_fmt(img->width, img->fmt)\n");
+ return false;
+ }
+
+ img_size = b2r2_get_img_size(img);
+
+ /*
+ * To keep the entire image inside s32 range.
+ */
+ if ((B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET == img->buf.type ||
+ B2R2_BLT_PTR_FD_OFFSET == img->buf.type) &&
+ img->buf.offset > (u32)b2r2_s32_max - (u32)img_size) {
+ b2r2_log_info("Validation Error: "
+ "(B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET == "
+ "img->buf.type || B2R2_BLT_PTR_FD_OFFSET == "
+ "img->buf.type) && img->buf.offset > "
+ "(u32)B2R2_MAX_S32 - (u32)img_size\n");
+ return false;
+ }
+
+ if (B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET == img->buf.type &&
+ img->buf.offset % (u32)img_size != 0) {
+ b2r2_log_info("Validation Error: "
+ "B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET == "
+ "img->buf.type && img->buf.offset && "
+ "(u32)b2r2_get_img_size(img) != 0\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool validate_rect(struct b2r2_blt_rect *rect)
+{
+ if (rect->width < 0 || rect->height < 0) {
+ b2r2_log_info("Validation Error: "
+ "rect->width < 0 || rect->height < 0\n");
+ return false;
+ }
+
+ return true;
+}
+
+bool b2r2_validate_user_req(struct b2r2_blt_req *req)
+{
+ bool is_src_img_used;
+ bool is_src_mask_used;
+ bool is_dst_clip_rect_used;
+
+ if (req->size != sizeof(struct b2r2_blt_req)) {
+ b2r2_log_err("Validation Error: "
+ "req->size != sizeof(struct b2r2_blt_req)\n");
+ return false;
+ }
+
+ is_src_img_used = !(req->flags & B2R2_BLT_FLAG_SOURCE_FILL ||
+ req->flags & B2R2_BLT_FLAG_SOURCE_FILL_RAW);
+ is_src_mask_used = req->flags & B2R2_BLT_FLAG_SOURCE_MASK;
+ is_dst_clip_rect_used = req->flags & B2R2_BLT_FLAG_DESTINATION_CLIP;
+
+ if (is_src_img_used || is_src_mask_used) {
+ if (!validate_rect(&req->src_rect)) {
+ b2r2_log_info("Validation Error: "
+ "!validate_rect(&req->src_rect)\n");
+ return false;
+ }
+ }
+
+ if (!validate_rect(&req->dst_rect)) {
+ b2r2_log_info("Validation Error: "
+ "!validate_rect(&req->dst_rect)\n");
+ return false;
+ }
+
+ if (is_dst_clip_rect_used) {
+ if (!validate_rect(&req->dst_clip_rect)) {
+ b2r2_log_info("Validation Error: "
+ "!validate_rect(&req->dst_clip_rect)\n");
+ return false;
+ }
+ }
+
+ if (is_src_img_used) {
+ struct b2r2_blt_rect src_img_bounding_rect;
+
+ if (!validate_img(&req->src_img)) {
+ b2r2_log_info("Validation Error: "
+ "!validate_img(&req->src_img)\n");
+ return false;
+ }
+
+ b2r2_get_img_bounding_rect(&req->src_img,
+ &src_img_bounding_rect);
+ if (!b2r2_is_rect_inside_rect(&req->src_rect,
+ &src_img_bounding_rect)) {
+ b2r2_log_info("Validation Error: "
+ "!b2r2_is_rect_inside_rect(&req->src_rect, "
+ "&src_img_bounding_rect)\n");
+ return false;
+ }
+ }
+
+ if (is_src_mask_used) {
+ struct b2r2_blt_rect src_mask_bounding_rect;
+
+ if (!validate_img(&req->src_mask)) {
+ b2r2_log_info("Validation Error: "
+ "!validate_img(&req->src_mask)\n");
+ return false;
+ }
+
+ b2r2_get_img_bounding_rect(&req->src_mask,
+ &src_mask_bounding_rect);
+ if (!b2r2_is_rect_inside_rect(&req->src_rect,
+ &src_mask_bounding_rect)) {
+ b2r2_log_info("Validation Error: "
+ "!b2r2_is_rect_inside_rect(&req->src_rect, "
+ "&src_mask_bounding_rect)\n");
+ return false;
+ }
+ }
+
+ if (!validate_img(&req->dst_img)) {
+ b2r2_log_info("Validation Error: "
+ "!validate_img(&req->dst_img)\n");
+ return false;
+ }
+
+ return true;
+}
diff --git a/drivers/video/b2r2/b2r2_input_validation.h b/drivers/video/b2r2/b2r2_input_validation.h
new file mode 100644
index 00000000000..9a736343e06
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_input_validation.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> for ST-Ericsson
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _LINUX_DRIVERS_VIDEO_B2R2_INPUT_VALIDATION_H_
+#define _LINUX_DRIVERS_VIDEO_B2R2_INPUT_VALIDATION_H_
+
+#include <video/b2r2_blt.h>
+
+bool b2r2_validate_user_req(struct b2r2_blt_req *req);
+
+#endif
diff --git a/drivers/video/b2r2/b2r2_internal.h b/drivers/video/b2r2/b2r2_internal.h
new file mode 100644
index 00000000000..9bda2e8255d
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_internal.h
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 internal definitions
+ *
+ * Author: Robert Fekete <robert.fekete@stericsson.com>
+ * Author: Paul Wannback
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef _LINUX_DRIVERS_VIDEO_B2R2_INTERNAL_H_
+#define _LINUX_DRIVERS_VIDEO_B2R2_INTERNAL_H_
+
+
+#include <video/b2r2_blt.h>
+
+#include "b2r2_core.h"
+#include "b2r2_global.h"
+
+#include "b2r2_hw.h"
+
+/* The maximum possible number of temporary buffers needed */
+#define MAX_TMP_BUFS_NEEDED 2
+
+/* Size of the color look-up table */
+#define CLUT_SIZE 1024
+
+/**
+ * b2r2_blt_device() - Returns the device associated with B2R2 BLT.
+ * Mainly for debugging with dev_... functions.
+ *
+ * Returns the device pointer or NULL
+ */
+struct device *b2r2_blt_device(void);
+
+/**
+ * struct b2r2_blt_instance - Represents the B2R2 instance (one per open)
+ *
+ * @lock: Lock to protect the instance
+ *
+ * @report_list: Ready requests that should be reported,
+ * @report_list_waitq: Wait queue for report list
+ * @no_of_active_requests: Number of requests added but not reported
+ * in callback.
+ * @synching: true if any client is waiting for b2r2_blt_synch(0)
+ * @synch_done_waitq: Wait queue to handle synching on request_id 0
+ */
+struct b2r2_blt_instance {
+ spinlock_t lock;
+
+ /* Requests to be reported */
+ struct list_head report_list;
+ wait_queue_head_t report_list_waitq;
+
+ /* Below for synching */
+ u32 no_of_active_requests;
+ bool synching;
+ wait_queue_head_t synch_done_waitq;
+};
+
+/**
+ * struct b2r2_node - Represents a B2R2 node with reqister values, executed
+ * by B2R2. Should be allocated non-cached.
+ *
+ * @next: Next node
+ * @physical_address: Physical address to be given to B2R2
+ * (physical address of "node" member below)
+ * @node: The B2R2 node with register settings. This is the data
+ * that B2R2 will use.
+ *
+ */
+struct b2r2_node {
+ struct b2r2_node *next;
+ u32 physical_address;
+
+ int src_tmp_index;
+ int dst_tmp_index;
+
+ int src_index;
+
+ /* B2R2 regs comes here */
+ struct b2r2_link_list node;
+};
+
+/**
+ * struct b2r2_resolved_buf - Contains calculated information about
+ * image buffers.
+ *
+ * @physical_address: Physical address of the buffer
+ * @virtual_address: Virtual address of the buffer
+ * @is_pmem: true if buffer is from pmem
+ * @hwmem_session: Hwmem session
+ * @hwmem_alloc: Hwmem alloc
+ * @filep: File pointer of mapped file (like pmem device, frame buffer device)
+ * @file_physical_start: Physical address of file start
+ * @file_virtual_start: Virtual address of file start
+ * @file_len: File len
+ *
+ */
+struct b2r2_resolved_buf {
+ u32 physical_address;
+ void *virtual_address;
+ bool is_pmem;
+ struct hwmem_alloc *hwmem_alloc;
+ /* Data for validation below */
+ struct file *filep;
+ u32 file_physical_start;
+ u32 file_virtual_start;
+ u32 file_len;
+};
+
+
+/**
+ * b2r2_work_buf - specification for a temporary work buffer
+ *
+ * @size - the size of the buffer (set by b2r2_node_split)
+ * @phys_addr - the physical address of the buffer (set by b2r2_blt_main)
+ */
+struct b2r2_work_buf {
+ u32 size;
+ u32 phys_addr;
+ void *virt_addr;
+ u32 mem_handle;
+};
+
+
+/**
+ * b2r2_op_type - the type of B2R2 operation to configure
+ */
+enum b2r2_op_type {
+ B2R2_DIRECT_COPY,
+ B2R2_DIRECT_FILL,
+ B2R2_COPY,
+ B2R2_FILL,
+ B2R2_SCALE,
+ B2R2_ROTATE,
+ B2R2_SCALE_AND_ROTATE,
+ B2R2_FLIP,
+};
+
+/**
+ * b2r2_fmt_type - the type of buffer for a given format
+ */
+enum b2r2_fmt_type {
+ B2R2_FMT_TYPE_RASTER,
+ B2R2_FMT_TYPE_SEMI_PLANAR,
+ B2R2_FMT_TYPE_PLANAR,
+};
+
+/**
+ * b2r2_fmt_conv - the type of format conversion to do
+ */
+enum b2r2_fmt_conv {
+ B2R2_FMT_CONV_NONE,
+ B2R2_FMT_CONV_RGB_TO_YUV,
+ B2R2_FMT_CONV_YUV_TO_RGB,
+ B2R2_FMT_CONV_YUV_TO_YUV,
+ B2R2_FMT_CONV_RGB_TO_BGR,
+ B2R2_FMT_CONV_BGR_TO_RGB,
+ B2R2_FMT_CONV_YUV_TO_BGR,
+ B2R2_FMT_CONV_BGR_TO_YUV,
+};
+
+/**
+ * b2r2_node_split_buf - information about a source or destination buffer
+ *
+ * @addr - the physical base address
+ * @chroma_addr - the physical address of the chroma plane
+ * @chroma_cr_addr - the physical address of the Cr chroma plane
+ * @fmt - the buffer format
+ * @fmt_type - the buffer format type
+ * @rect - the rectangle of the buffer to use
+ * @color - the color value to use is case of a fill operation
+ * @pitch - the pixmap byte pitch
+ * @height - the pixmap height
+ * @alpha_range - the alpha range of the buffer (0-128 or 0-255)
+ * @hso - the horizontal scan order
+ * @vso - the vertical scan order
+ * @endian - the endianess of the buffer
+ * @plane_selection - the plane to write if buffer is planar or semi-planar
+ */
+struct b2r2_node_split_buf {
+ u32 addr;
+ u32 chroma_addr;
+ u32 chroma_cr_addr;
+
+ enum b2r2_blt_fmt fmt;
+ enum b2r2_fmt_type type;
+
+ struct b2r2_blt_rect rect;
+ struct b2r2_blt_rect window;
+
+ s32 dx;
+ s32 dy;
+
+ u32 color;
+ u16 pitch;
+ u16 width;
+ u16 height;
+
+ enum b2r2_ty alpha_range;
+ enum b2r2_ty hso;
+ enum b2r2_ty vso;
+ enum b2r2_ty endian;
+ enum b2r2_tty dither;
+
+ /* Plane selection (used when writing to a multibuffer format) */
+ enum b2r2_tty plane_selection;
+
+ /* Chroma plane selection (used when writing planar formats) */
+ enum b2r2_tty chroma_selection;
+
+ int tmp_buf_index;
+};
+
+/**
+ * b2r2_node_split_job - an instance of a node split job
+ *
+ * @type - the type of operation
+ * @ivmx - the ivmx matrix to use for color conversion
+ * @blend - determines if blending is enabled
+ * @clip - determines if destination clipping is enabled
+ * @swap_fg_bg - determines if FG and BG should be swapped when blending
+ * @flags - the flags passed in the blt request
+ * @flag_param - parameter required by certain flags,
+ * e.g. color for source color keying.
+ * @transform - the transforms passed in the blt request
+ * @global_alpha - the global alpha
+ * @clip_rect - the clipping rectangle to use
+ * @horiz_rescale - determmines if horizontal rescaling is enabled
+ * @horiz_sf - the horizontal scale factor
+ * @vert_rescale - determines if vertical rescale is enabled
+ * @vert_sf - the vertical scale factor
+ * @src - the incoming source buffer
+ * @dst - the outgoing destination buffer
+ * @work_bufs - work buffer specifications
+ * @tmp_bufs - temporary buffers
+ * @buf_count - the number of temporary buffers used for the job
+ * @node_count - the number of nodes used for the job
+ * @max_buf_size - the maximum size of temporary buffers
+ * @nbr_rows - the number of tile rows in the blit operation
+ * @nbr_cols - the number of time columns in the blit operation
+ */
+struct b2r2_node_split_job {
+ enum b2r2_op_type type;
+
+ const u32 *ivmx;
+
+ bool blend;
+ bool clip;
+ bool rotation;
+
+ bool swap_fg_bg;
+
+ u32 flags;
+ u32 flag_param;
+ u32 transform;
+ u32 global_alpha;
+
+ struct b2r2_blt_rect clip_rect;
+
+ bool horiz_rescale;
+ u16 horiz_sf;
+
+ bool vert_rescale;
+ u16 vert_sf;
+
+ struct b2r2_node_split_buf src;
+ struct b2r2_node_split_buf dst;
+
+ struct b2r2_work_buf work_bufs[MAX_TMP_BUFS_NEEDED];
+ struct b2r2_node_split_buf tmp_bufs[MAX_TMP_BUFS_NEEDED];
+
+ u32 buf_count;
+ u32 node_count;
+ u32 max_buf_size;
+
+ u32 nbr_rows;
+ u32 nbr_cols;
+ u32 nbr_sub_rows;
+ u32 nbr_sub_cols;
+};
+
+/**
+ * struct b2r2_blt_request - Represents one B2R2 blit request
+ *
+ * @instance: Back pointer to the instance structure
+ * @list: List item to keep track of requests per instance
+ * @user_req: The request received from userspace
+ * @job: The administration structure for the B2R2 job,
+ * consisting of one or more nodes
+ * @node_split_job: The administration structure for the B2R2 node split job
+ * @first_node: Pointer to the first B2R2 node
+ * @request_id: Request id for this job
+ * @node_split_handle: Handle of the node split
+ * @src_resolved: Calculated info about the source buffer
+ * @src_mask_resolved: Calculated info about the source mask buffer
+ * @dst_resolved: Calculated info about the destination buffer
+ * @profile: True if the blit shall be profiled, false otherwise
+ */
+struct b2r2_blt_request {
+ struct b2r2_blt_instance *instance;
+ struct list_head list;
+ struct b2r2_blt_req user_req;
+ struct b2r2_core_job job;
+ struct b2r2_node_split_job node_split_job;
+ struct b2r2_node *first_node;
+ int request_id;
+
+ /* Resolved buffer addresses */
+ struct b2r2_resolved_buf src_resolved;
+ struct b2r2_resolved_buf src_mask_resolved;
+ struct b2r2_resolved_buf dst_resolved;
+
+ /* TBD: Info about SRAM usage & needs */
+ struct b2r2_work_buf *bufs;
+ u32 buf_count;
+
+ /* color look-up table */
+ void *clut;
+ u32 clut_phys_addr;
+
+ /* Profiling stuff */
+ bool profile;
+
+ s32 nsec_active_in_cpu;
+
+ u32 start_time_nsec;
+ s32 total_time_nsec;
+};
+
+/* FIXME: The functions below should be removed when we are
+ switching to the new Robert Lind allocator */
+
+/**
+ * b2r2_blt_alloc_nodes() - Allocate nodes
+ *
+ * @node_count: Number of nodes to allocate
+ *
+ * Return:
+ * Returns a pointer to the first node in the node list.
+ */
+struct b2r2_node *b2r2_blt_alloc_nodes(int node_count);
+
+/**
+ * b2r2_blt_free_nodes() - Release nodes previously allocated via
+ * b2r2_generate_nodes
+ *
+ * @first_node: First node in linked list of nodes
+ */
+void b2r2_blt_free_nodes(struct b2r2_node *first_node);
+
+/**
+ * b2r2_blt_module_init() - Initialize the B2R2 blt module
+ */
+int b2r2_blt_module_init(void);
+
+/**
+ * b2r2_blt_module_exit() - Un-initialize the B2R2 blt module
+ */
+void b2r2_blt_module_exit(void);
+
+#endif
diff --git a/drivers/video/b2r2/b2r2_kernel_if.c b/drivers/video/b2r2/b2r2_kernel_if.c
new file mode 100644
index 00000000000..373311ccca5
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_kernel_if.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 kernel interface for beeing a separate module
+ *
+ * Author: Robert Fekete <robert.fekete@stericsson.com>
+ * Author: Paul Wannback
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#ifdef CONFIG_ANDROID_PMEM
+#include <linux/android_pmem.h>
+#endif
+#include <linux/fb.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <asm/cacheflush.h>
+
+EXPORT_SYMBOL(fget_light);
+EXPORT_SYMBOL(fput_light);
+EXPORT_SYMBOL(flush_cache_range);
+EXPORT_SYMBOL(task_sched_runtime);
+#ifdef CONFIG_ANDROID_PMEM
+EXPORT_SYMBOL(get_pmem_file);
+EXPORT_SYMBOL(put_pmem_file);
+EXPORT_SYMBOL(flush_pmem_file);
+#endif
diff --git a/drivers/video/b2r2/b2r2_mem_alloc.c b/drivers/video/b2r2/b2r2_mem_alloc.c
new file mode 100644
index 00000000000..0dcd9b6a55e
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_mem_alloc.c
@@ -0,0 +1,726 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 internal Memory allocator
+ *
+ * Author: Robert Lind <robert.lind@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+
+#include "b2r2_internal.h"
+#include "b2r2_mem_alloc.h"
+
+
+/* Represents one block of b2r2 physical memory, free or allocated */
+struct b2r2_mem_block {
+ struct list_head list; /* For membership in list */
+
+ u32 offset; /* Offset in b2r2 physical memory area (aligned) */
+ u32 size; /* Size of the object (requested size if busy,
+ else actual) */
+ bool free; /* True if the block is free */
+
+ u32 lock_count; /* Lock count */
+
+#ifdef CONFIG_DEBUG_FS
+ char debugfs_fname[80]; /* debugfs file name */
+ struct dentry *debugfs_block; /* debugfs dir entry for the block */
+#endif
+};
+
+/* The memory heap */
+struct b2r2_mem_heap {
+ struct device *dev; /* Device pointer for memory allocation */
+ dma_addr_t start_phys_addr;/* Physical memory start address */
+ void *start_virt_ptr; /* Virtual pointer to start */
+ u32 size; /* Memory size */
+ u32 align; /* Alignment */
+
+ struct list_head blocks; /* List of all blocks */
+
+ spinlock_t heap_lock; /* Protection for the heap */
+
+ u32 node_size; /* Size of each B2R2 node */
+ struct dma_pool *node_heap;/* Heap for B2R2 node allocations */
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_sub_root_dir; /* debugfs: B2R2 MEM root dir */
+ struct dentry *debugfs_heap_stats; /* debugfs: B2R2 memory status */
+ struct dentry *debugfs_dir_blocks; /* debugfs: Free blocks dir */
+#endif
+};
+
+static struct b2r2_mem_heap *mem_heap;
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_root_dir; /* debugfs: B2R2 MEM root dir */
+#endif
+
+/* Forward declarations */
+static struct b2r2_mem_block *b2r2_mem_block_alloc(
+ u32 offset, u32 size, bool free);
+static void b2r2_mem_block_free(struct b2r2_mem_block *mem_block);
+
+/* Align value down to specified alignment */
+static inline u32 align_down(u32 align, u32 value)
+{
+ return value & ~(align - 1);
+}
+
+/* Align value up to specified alignment */
+static inline u32 align_up(u32 align, u32 value)
+{
+ return (value + align - 1) & ~(align - 1);
+}
+
+
+#ifdef CONFIG_DEBUG_FS
+/* About debugfs:
+ * debugfs is a mountable debug file system.
+ *
+ * Mount like this:
+ * mkdir /debug
+ * mount -t debugfs none /debug
+ * ls /debug/b2r2_mem
+ *
+ * ls -al /debug/b2r2_mem/blocks
+ * cat /debug/b2r2_mem/stats
+ */
+
+
+/* Create string containing memory heap status */
+static char *get_b2r2_mem_stats(struct b2r2_mem_heap *mem_heap, char *buf)
+{
+ struct b2r2_mem_heap_status mem_heap_status;
+
+ if (b2r2_mem_heap_status(&mem_heap_status) != 0) {
+ strcpy(buf, "Error, failed to get status\n");
+ return buf;
+ }
+
+ sprintf(buf,
+ "Handle : 0x%lX\n"
+ "Physical start address : 0x%lX\n"
+ "Size : %lu\n"
+ "Align : %lu\n"
+ "No of blocks allocated : %lu\n"
+ "Allocated size : %lu\n"
+ "No of free blocks : %lu\n"
+ "Free size : %lu\n"
+ "No of locks : %lu\n"
+ "No of locked : %lu\n"
+ "No of nodes : %lu\n",
+ (unsigned long) mem_heap,
+ (unsigned long) mem_heap_status.start_phys_addr,
+ (unsigned long) mem_heap_status.size,
+ (unsigned long) mem_heap_status.align,
+ (unsigned long) mem_heap_status.num_alloc,
+ (unsigned long) mem_heap_status.allocated_size,
+ (unsigned long) mem_heap_status.num_free,
+ (unsigned long) mem_heap_status.free_size,
+ (unsigned long) mem_heap_status.num_locks,
+ (unsigned long) mem_heap_status.num_locked,
+ (unsigned long) mem_heap_status.num_nodes);
+
+ return buf;
+}
+
+/*
+ * Print memory heap status on file
+ * (Use like "cat /debug/b2r2_mem/igram/stats")
+ */
+static int debugfs_b2r2_mem_stats_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ struct b2r2_mem_heap *mem_heap = filp->f_dentry->d_inode->i_private;
+ char Buf[400];
+ size_t dev_size;
+ int ret = 0;
+
+ get_b2r2_mem_stats(mem_heap, Buf);
+ dev_size = strlen(Buf);
+
+ /* No more to read if offset != 0 */
+ if (*f_pos > dev_size)
+ goto out;
+
+ if (*f_pos + count > dev_size)
+ count = dev_size - *f_pos;
+
+ if (copy_to_user(buf, Buf, count))
+ ret = -EINVAL;
+ *f_pos += count;
+ ret = count;
+
+out:
+ return ret;
+}
+
+/* debugfs file operations for the "stats" file */
+static const struct file_operations debugfs_b2r2_mem_stats_fops = {
+ .owner = THIS_MODULE,
+ .read = debugfs_b2r2_mem_stats_read,
+};
+
+/* read function for file in the "blocks" sub directory */
+static int debugfs_b2r2_mem_block_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ struct b2r2_mem_block *mem_block = filp->f_dentry->d_inode->i_private;
+ char Buf[200];
+ size_t dev_size;
+ int ret = 0;
+
+ dev_size = sprintf(Buf, "offset: %08lX %s size: %8d "
+ "lock_count: %2d\n",
+ (unsigned long) mem_block->offset,
+ mem_block->free ? "free" : "allc",
+ mem_block->size,
+ mem_block->lock_count);
+
+ /* No more to read if offset != 0 */
+ if (*f_pos > dev_size)
+ goto out;
+
+ if (*f_pos + count > dev_size)
+ count = dev_size - *f_pos;
+
+ if (copy_to_user(buf, Buf, count))
+ ret = -EINVAL;
+ *f_pos += count;
+ ret = count;
+
+out:
+ return ret;
+}
+
+/* debugfs file operations for files in the "blocks" directory */
+static const struct file_operations debugfs_b2r2_mem_block_fops = {
+ .owner = THIS_MODULE,
+ .read = debugfs_b2r2_mem_block_read,
+};
+
+/*
+ * Create or update the debugfs directory entry for a file in the
+ * "blocks" directory (a memory allocation)
+ */
+void debugfs_create_mem_block_entry(struct b2r2_mem_block *mem_block,
+ struct dentry *parent)
+{
+ struct timespec tm = current_kernel_time();
+ struct timespec atime = tm;
+ struct timespec mtime = tm;
+ struct timespec ctime = tm;
+
+ if (mem_block->debugfs_block) {
+ atime = mem_block->debugfs_block->d_inode->i_atime;
+ ctime = mem_block->debugfs_block->d_inode->i_ctime;
+ debugfs_remove(mem_block->debugfs_block);
+ }
+
+ /* Add the block in debugfs */
+ if (mem_block->free)
+ sprintf(mem_block->debugfs_fname, "%08lX free",
+ (unsigned long) mem_block->offset);
+ else {
+ sprintf(mem_block->debugfs_fname, "%08lX allc h:%08lX "
+ "lck:%d ",
+ (unsigned long) mem_block->offset,
+ (unsigned long) mem_block,
+ mem_block->lock_count);
+ }
+
+ mem_block->debugfs_block = debugfs_create_file(
+ mem_block->debugfs_fname,
+ 0444, parent, mem_block,
+ &debugfs_b2r2_mem_block_fops);
+ if (mem_block->debugfs_block) {
+ mem_block->debugfs_block->d_inode->i_size = mem_block->size;
+ mem_block->debugfs_block->d_inode->i_atime = atime;
+ mem_block->debugfs_block->d_inode->i_mtime = mtime;
+ mem_block->debugfs_block->d_inode->i_ctime = ctime;
+ }
+}
+#endif /* CONFIG_DEBUG_FS */
+
+/* Module initialization function */
+int b2r2_mem_init(struct device *dev, u32 heap_size, u32 align, u32 node_size)
+{
+ struct b2r2_mem_block *mem_block;
+ u32 aligned_size;
+
+ printk(KERN_INFO "B2R2_MEM: Creating heap for size %d bytes\n",
+ (int) heap_size);
+
+ /* Align size */
+ aligned_size = align_down(align, heap_size);
+ if (aligned_size == 0)
+ return -EINVAL;
+
+ mem_heap = kcalloc(sizeof(struct b2r2_mem_heap), 1, GFP_KERNEL);
+ if (!mem_heap)
+ return -ENOMEM;
+
+ mem_heap->start_virt_ptr = dma_alloc_coherent(dev,
+ aligned_size, &(mem_heap->start_phys_addr), GFP_KERNEL);
+ if (!mem_heap->start_phys_addr || !mem_heap->start_virt_ptr) {
+ printk(KERN_ERR "B2R2_MEM: Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ /* Initialize the heap */
+ mem_heap->dev = dev;
+ mem_heap->size = aligned_size;
+ mem_heap->align = align;
+
+ INIT_LIST_HEAD(&mem_heap->blocks);
+
+#ifdef CONFIG_DEBUG_FS
+ /* Register debugfs */
+
+ debugfs_root_dir = debugfs_create_dir("b2r2_mem", NULL);
+
+ mem_heap->debugfs_sub_root_dir = debugfs_create_dir("b2r2_mem",
+ debugfs_root_dir);
+ mem_heap->debugfs_heap_stats = debugfs_create_file(
+ "stats", 0444, mem_heap->debugfs_sub_root_dir, mem_heap,
+ &debugfs_b2r2_mem_stats_fops);
+ mem_heap->debugfs_dir_blocks = debugfs_create_dir(
+ "blocks", mem_heap->debugfs_sub_root_dir);
+#endif
+
+ /* Create the first _free_ memory block */
+ mem_block = b2r2_mem_block_alloc(0, aligned_size, true);
+ if (!mem_block) {
+ dma_free_coherent(dev, aligned_size,
+ mem_heap->start_virt_ptr,
+ mem_heap->start_phys_addr);
+ kfree(mem_heap);
+ printk(KERN_ERR "B2R2_MEM: Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ /* Add the free block to the blocks list */
+ list_add(&mem_block->list, &mem_heap->blocks);
+
+ /* Allocate separate heap for B2R2 nodes */
+ mem_heap->node_size = node_size;
+ mem_heap->node_heap = dma_pool_create("b2r2_node_cache",
+ dev, node_size, align, 4096);
+ if (!mem_heap->node_heap) {
+ b2r2_mem_block_free(mem_block);
+ dma_free_coherent(dev, aligned_size,
+ mem_heap->start_virt_ptr,
+ mem_heap->start_phys_addr);
+ kfree(mem_heap);
+ printk(KERN_ERR "B2R2_MEM: Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(b2r2_mem_init);
+
+/* Module exit function */
+void b2r2_mem_exit(void)
+{
+ struct list_head *ptr;
+
+ /* Free B2R2 node heap */
+ dma_pool_destroy(mem_heap->node_heap);
+
+#ifdef CONFIG_DEBUG_FS
+ /* debugfs root dir */
+ if (debugfs_root_dir) {
+ debugfs_remove_recursive(debugfs_root_dir);
+ debugfs_root_dir = NULL;
+ }
+#endif
+
+ list_for_each(ptr, &mem_heap->blocks) {
+ struct b2r2_mem_block *mem_block =
+ list_entry(ptr, struct b2r2_mem_block, list);
+
+ b2r2_mem_block_free(mem_block);
+ }
+
+ dma_free_coherent(mem_heap->dev, mem_heap->size,
+ mem_heap->start_virt_ptr,
+ mem_heap->start_phys_addr);
+ kfree(mem_heap);
+}
+EXPORT_SYMBOL(b2r2_mem_exit);
+
+/* Return status of the heap */
+int b2r2_mem_heap_status(struct b2r2_mem_heap_status *mem_heap_status)
+{
+ struct list_head *ptr;
+
+ if (!mem_heap || !mem_heap_status)
+ return -EINVAL;
+ memset(mem_heap_status, 0, sizeof(*mem_heap_status));
+
+ /* Lock the heap */
+ spin_lock(&mem_heap->heap_lock);
+
+ /* Fill in static info */
+ mem_heap_status->start_phys_addr = mem_heap->start_phys_addr;
+ mem_heap_status->size = mem_heap->size;
+ mem_heap_status->align = mem_heap->align;
+
+ list_for_each(ptr, &mem_heap->blocks) {
+ struct b2r2_mem_block *mem_block =
+ list_entry(ptr, struct b2r2_mem_block, list);
+
+ if (mem_block->free) {
+ mem_heap_status->num_free++;
+ mem_heap_status->free_size += mem_block->size;
+ } else {
+ if (mem_block->lock_count) {
+ mem_heap_status->num_locked++;
+ mem_heap_status->num_locks +=
+ mem_block->lock_count;
+ }
+ mem_heap_status->num_alloc++;
+ mem_heap_status->allocated_size += mem_block->size;
+ }
+ }
+
+ spin_unlock(&mem_heap->heap_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(b2r2_mem_heap_status);
+
+/* Internal: Allocate a housekeeping structure
+ * for an allocated or free memory block
+ */
+static struct b2r2_mem_block *b2r2_mem_block_alloc(
+ u32 offset, u32 size, bool free)
+{
+ struct b2r2_mem_block *mem_block = kmalloc(
+ sizeof(struct b2r2_mem_block), GFP_KERNEL);
+
+ if (mem_block) {
+ mem_block->offset = offset;
+ mem_block->size = size;
+ mem_block->free = free;
+ mem_block->lock_count = 0;
+
+ INIT_LIST_HEAD(&mem_block->list);
+
+#ifdef CONFIG_DEBUG_FS
+ mem_block->debugfs_block = NULL;
+ /* Add the block in debugfs */
+ debugfs_create_mem_block_entry(mem_block,
+ mem_heap->debugfs_dir_blocks);
+#endif
+ }
+
+ return mem_block;
+}
+
+/* Internal: Release housekeeping structure */
+static void b2r2_mem_block_free(struct b2r2_mem_block *mem_block)
+{
+ if (mem_block) {
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove(mem_block->debugfs_block);
+#endif
+ kfree(mem_block);
+ }
+}
+
+/* Allocate a block from the heap */
+int b2r2_mem_alloc(u32 requested_size, u32 *returned_size, u32 *mem_handle)
+{
+ int ret = 0;
+ struct list_head *ptr;
+ struct b2r2_mem_block *found_mem_block = NULL;
+ u32 aligned_size;
+
+ if (!mem_handle)
+ return -EINVAL;
+
+ printk(KERN_INFO "%s: size=%d\n", __func__, requested_size);
+
+ *mem_handle = 0;
+ if (!mem_heap)
+ return -EINVAL;
+
+ /* Lock the heap */
+ spin_lock(&mem_heap->heap_lock);
+
+ aligned_size = align_up(mem_heap->align, requested_size);
+ /* Try to find the best matching free block of suitable size */
+ list_for_each(ptr, &mem_heap->blocks) {
+ struct b2r2_mem_block *mem_block =
+ list_entry(ptr, struct b2r2_mem_block, list);
+
+ if (mem_block->free && mem_block->size >= aligned_size &&
+ (!found_mem_block ||
+ mem_block->size < found_mem_block->size)) {
+ found_mem_block = mem_block;
+ if (found_mem_block->size == aligned_size)
+ break;
+ }
+ }
+
+ if (found_mem_block) {
+ struct b2r2_mem_block *new_block
+ = b2r2_mem_block_alloc(found_mem_block->offset,
+ requested_size, false);
+
+ if (new_block) {
+ /* Insert the new block before the found block */
+ list_add_tail(&new_block->list,
+ &found_mem_block->list);
+
+ /* Split the free block */
+ found_mem_block->offset += aligned_size;
+ found_mem_block->size -= aligned_size;
+
+ if (found_mem_block->size == 0)
+ b2r2_mem_block_free(found_mem_block);
+ else {
+#ifdef CONFIG_DEBUG_FS
+ debugfs_create_mem_block_entry(
+ found_mem_block,
+ mem_heap->debugfs_dir_blocks);
+#endif
+ }
+
+ *mem_handle = (u32) new_block;
+ *returned_size = aligned_size;
+ } else {
+ ret = -ENOMEM;
+ }
+ } else
+ ret = -ENOMEM;
+
+ if (ret != 0) {
+ *returned_size = 0;
+ *mem_handle = (u32) 0;
+ }
+
+ /* Unlock */
+ spin_unlock(&mem_heap->heap_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(b2r2_mem_alloc);
+
+/* Free the allocated block */
+int b2r2_mem_free(u32 mem_handle)
+{
+ int ret = 0;
+ struct b2r2_mem_block *mem_block = (struct b2r2_mem_block *) mem_handle;
+
+ if (!mem_block)
+ return -EINVAL;
+
+ /* Lock the heap */
+ spin_lock(&mem_heap->heap_lock);
+
+ if (!ret && mem_block->free)
+ ret = -EINVAL;
+
+ if (!ret) {
+ printk(KERN_INFO "%s: freeing block 0x%p\n", __func__, mem_block);
+ /* Release the block */
+
+ mem_block->free = true;
+ mem_block->size = align_up(mem_heap->align,
+ mem_block->size);
+
+ /* Join with previous block if possible */
+ if (mem_block->list.prev != &mem_heap->blocks) {
+ struct b2r2_mem_block *prev_block =
+ list_entry(mem_block->list.prev,
+ struct b2r2_mem_block, list);
+
+ if (prev_block->free &&
+ (prev_block->offset + prev_block->size) ==
+ mem_block->offset) {
+ mem_block->offset = prev_block->offset;
+ mem_block->size += prev_block->size;
+
+ b2r2_mem_block_free(prev_block);
+ }
+ }
+
+ /* Join with next block if possible */
+ if (mem_block->list.next != &mem_heap->blocks) {
+ struct b2r2_mem_block *next_block
+ = list_entry(mem_block->list.next,
+ struct b2r2_mem_block,
+ list);
+
+ if (next_block->free &&
+ (mem_block->offset + mem_block->size) ==
+ next_block->offset) {
+ mem_block->size += next_block->size;
+
+ b2r2_mem_block_free(next_block);
+ }
+ }
+#ifdef CONFIG_DEBUG_FS
+ debugfs_create_mem_block_entry(mem_block,
+ mem_heap->debugfs_dir_blocks);
+#endif
+ }
+
+ /* Unlock */
+ spin_unlock(&mem_heap->heap_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(b2r2_mem_free);
+
+/* Lock the allocated block in memory */
+int b2r2_mem_lock(u32 mem_handle, u32 *phys_addr, void **virt_ptr, u32 *size)
+{
+ struct b2r2_mem_block *mem_block =
+ (struct b2r2_mem_block *) mem_handle;
+
+ if (!mem_block)
+ return -EINVAL;
+
+ /* Lock the heap */
+ spin_lock(&mem_heap->heap_lock);
+
+ mem_block->lock_count++;
+
+ if (phys_addr)
+ *phys_addr = mem_heap->start_phys_addr + mem_block->offset;
+ if (virt_ptr)
+ *virt_ptr = (char *) mem_heap->start_virt_ptr +
+ mem_block->offset;
+ if (size)
+ *size = align_up(mem_heap->align, mem_block->size);
+#ifdef CONFIG_DEBUG_FS
+ debugfs_create_mem_block_entry(mem_block,
+ mem_heap->debugfs_dir_blocks);
+#endif
+
+ spin_unlock(&mem_heap->heap_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(b2r2_mem_lock);
+
+/* Unlock the allocated block in memory */
+int b2r2_mem_unlock(u32 mem_handle)
+{
+ struct b2r2_mem_block *mem_block =
+ (struct b2r2_mem_block *) mem_handle;
+
+ if (!mem_block)
+ return -EINVAL;
+
+ /* Lock the heap */
+ spin_lock(&mem_heap->heap_lock);
+
+ mem_block->lock_count--;
+
+ spin_unlock(&mem_heap->heap_lock);
+
+ /* debugfs will be updated in release */
+ return 0;
+/* return b2r2_mem_free(mem_handle);*/
+}
+EXPORT_SYMBOL(b2r2_mem_unlock);
+
+/* Allocate one or more b2r2 nodes from DMA pool */
+int b2r2_node_alloc(u32 num_nodes, struct b2r2_node **first_node)
+{
+ int i;
+ int ret = 0;
+ u32 physical_address;
+ struct b2r2_node *first_node_ptr;
+ struct b2r2_node *node_ptr;
+
+ /* Check input parameters */
+ if ((num_nodes <= 0) || !first_node) {
+ printk(KERN_ERR
+ "B2R2_MEM: Invalid parameter for b2r2_node_alloc, "
+ "num_nodes=%d, first_node=%ld\n",
+ (int) num_nodes, (long) first_node);
+ return -EINVAL;
+ }
+
+ /* Allocate the first node */
+ first_node_ptr = dma_pool_alloc(mem_heap->node_heap,
+ GFP_DMA | GFP_KERNEL, &physical_address);
+ if (first_node_ptr) {
+ /* Initialize first node */
+ first_node_ptr->next = NULL;
+ first_node_ptr->physical_address = physical_address +
+ offsetof(struct b2r2_node, node);
+
+ /* Allocate and initialize remaining nodes, */
+ /* and link them into a list */
+ for (i = 1, node_ptr = first_node_ptr; i < num_nodes; i++) {
+ node_ptr->next = dma_pool_alloc(mem_heap->node_heap,
+ GFP_DMA | GFP_KERNEL, &physical_address);
+ if (node_ptr->next) {
+ node_ptr = node_ptr->next;
+ node_ptr->next = NULL;
+ node_ptr->physical_address = physical_address +
+ offsetof(struct b2r2_node, node);
+ } else {
+ printk(KERN_ERR "B2R2_MEM: Failed to allocate memory for node\n");
+ ret = -ENOMEM;
+ break;
+ }
+ }
+
+ /* If all nodes were allocated successfully, */
+ /* return the first node */
+ if (!ret)
+ *first_node = first_node_ptr;
+ else
+ b2r2_node_free(first_node_ptr);
+ } else {
+ printk(KERN_ERR "B2R2_MEM: Failed to allocate memory for node\n");
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(b2r2_node_alloc);
+
+/* Free a linked list of b2r2 nodes */
+void b2r2_node_free(struct b2r2_node *first_node)
+{
+ struct b2r2_node *current_node = first_node;
+ struct b2r2_node *next_node = NULL;
+
+ /* Traverse the linked list and free the nodes */
+ while (current_node != NULL) {
+ next_node = current_node->next;
+ dma_pool_free(mem_heap->node_heap, current_node,
+ current_node->physical_address -
+ offsetof(struct b2r2_node, node));
+ current_node = next_node;
+ }
+}
+EXPORT_SYMBOL(b2r2_node_free);
+
+MODULE_AUTHOR("Robert Lind <robert.lind@ericsson.com");
+MODULE_DESCRIPTION("Ericsson AB B2R2 physical memory driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/b2r2/b2r2_mem_alloc.h b/drivers/video/b2r2/b2r2_mem_alloc.h
new file mode 100644
index 00000000000..33309c972f5
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_mem_alloc.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 internal Memory allocator
+ *
+ * Author: Robert Lind <robert.lind@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __B2R2_MEM_ALLOC_H
+#define __B2R2_MEM_ALLOC_H
+
+#include "b2r2_internal.h"
+
+
+/**
+ * struct b2r2_mem_heap_status - Information about current state of the heap
+ * @start_phys_addr: Physical address of the the memory area
+ * @size: Size of the memory area
+ * @align: Alignment of start and allocation sizes (in bytes).
+ * @num_alloc: Number of memory allocations
+ * @allocated_size: Size allocated (sum of requested sizes)
+ * @num_free: Number of free blocks (fragments)
+ * @free_size: Free size available for allocation
+ * @num_locks: Sum of number of number of locks on memory allocations
+ * @num_locked: Number of locked memory allocations
+ * @num_nodes: Number of node allocations
+ *
+ **/
+struct b2r2_mem_heap_status {
+ u32 start_phys_addr;
+ u32 size;
+ u32 align;
+ u32 num_alloc;
+ u32 allocated_size;
+ u32 num_free;
+ u32 free_size;
+ u32 num_locks;
+ u32 num_locked;
+ u32 num_nodes;
+};
+
+
+/* B2R2 memory API (kernel) */
+
+/**
+ * b2r2_mem_init() - Initializes the B2R2 memory manager
+ * @dev: Pointer to device to use for allocating the memory heap
+ * @heap_size: Size of the heap (in bytes)
+ * @align: Alignment to use for memory allocations on heap (in bytes)
+ * @node_size: Size of each B2R2 node (in bytes)
+ *
+ * Returns 0 if success, else negative error code
+ **/
+int b2r2_mem_init(struct device *dev, u32 heap_size, u32 align, u32 node_size);
+
+/**
+ * b2r2_mem_exit() - Cleans up the B2R2 memory manager
+ *
+ **/
+void b2r2_mem_exit(void);
+
+/**
+ * b2r2_mem_heap_status() - Get information about the current heap state
+ * @mem_heap_status: Struct containing status info on succesful return
+ *
+ * Returns 0 if success, else negative error code
+ **/
+int b2r2_mem_heap_status(struct b2r2_mem_heap_status *mem_heap_status);
+
+/**
+ * b2r2_mem_alloc() - Allocates memory block from physical memory heap
+ * @requested_size: Requested size
+ * @returned_size: Actual size of memory block. Might be adjusted due to
+ * alignment but is always >= requested size if function
+ * succeeds
+ * @mem_handle: Returned memory handle
+ *
+ * All memory allocations are movable when not locked.
+ * Returns 0 if OK else negative error value
+ **/
+int b2r2_mem_alloc(u32 requested_size, u32 *returned_size, u32 *mem_handle);
+
+/**
+ * b2r2_mem_free() - Frees an allocation
+ * @mem_handle: Memory handle
+ *
+ * Returns 0 if OK else negative error value
+ **/
+int b2r2_mem_free(u32 mem_handle);
+
+/**
+ * b2r2_mem_lock() - Lock memory in memory and return physical address
+ * @mem_handle: Memory handle
+ * @phys_addr: Returned physical address to start of memory allocation.
+ * May be NULL.
+ * @virt_ptr: Returned virtual address pointer to start of memory allocation.
+ * May be NULL.
+ * @size: Returned size of memory allocation. May be NULL.
+ *
+ * The adress of the memory allocation is locked and the physical address
+ * is returned.
+ * The lock count is incremented by one.
+ * You need to call b2r2_mem_unlock once for each call to
+ * b2r2_mem_lock.
+ * Returns 0 if OK else negative error value
+ **/
+int b2r2_mem_lock(u32 mem_handle, u32 *phys_addr, void **virt_ptr, u32 *size);
+
+/**
+ * b2r2_mem_unlock() - Unlock previously locked memory
+ * @mem_handle: Memory handle
+ *
+ * Decrements lock count. When lock count reaches 0 the
+ * memory area is movable again.
+ * Returns 0 if OK else negative error value
+ **/
+int b2r2_mem_unlock(u32 mem_handle);
+
+/**
+ * b2r2_node_alloc() - Allocates B2R2 node from physical memory heap
+ * @num_nodes: Number of linked nodes to allocate
+ * @first_node: Returned pointer to first node in linked list
+ *
+ * Returns 0 if OK else negative error value
+ **/
+int b2r2_node_alloc(u32 num_nodes, struct b2r2_node **first_node);
+
+/**
+ * b2r2_node_free() - Frees a linked list of allocated B2R2 nodes
+ * @first_node: Pointer to first node in linked list
+ *
+ * Returns 0 if OK else negative error value
+ **/
+void b2r2_node_free(struct b2r2_node *first_node);
+
+
+#endif /* __B2R2_MEM_ALLOC_H */
diff --git a/drivers/video/b2r2/b2r2_node_gen.c b/drivers/video/b2r2/b2r2_node_gen.c
new file mode 100644
index 00000000000..f452a4b11df
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_node_gen.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 node generator
+ *
+ * Author: Robert Fekete <robert.fekete@stericsson.com>
+ * Author: Paul Wannback
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma-mapping.h>
+#include "b2r2_internal.h"
+
+static void free_nodes(struct b2r2_node *first_node)
+{
+ struct b2r2_node *node = first_node;
+ int no_of_nodes = 0;
+
+ while (node) {
+ no_of_nodes++;
+ node = node->next;
+ }
+
+ dma_free_coherent(b2r2_blt_device(),
+ no_of_nodes * sizeof(struct b2r2_node),
+ first_node,
+ first_node->physical_address -
+ offsetof(struct b2r2_node, node));
+}
+
+struct b2r2_node *b2r2_blt_alloc_nodes(int no_of_nodes)
+{
+ u32 physical_address;
+ struct b2r2_node *nodes;
+ struct b2r2_node *tmpnode;
+
+ if (no_of_nodes <= 0) {
+ dev_err(b2r2_blt_device(), "%s: Wrong number of nodes (%d)",
+ __func__, no_of_nodes);
+ return NULL;
+ }
+
+ /* Allocate the memory */
+ nodes = (struct b2r2_node *) dma_alloc_coherent(b2r2_blt_device(),
+ no_of_nodes * sizeof(struct b2r2_node),
+ &physical_address, GFP_DMA | GFP_KERNEL);
+
+ if (nodes == NULL) {
+ dev_err(b2r2_blt_device(),
+ "%s: Failed to alloc memory for nodes",
+ __func__);
+ return NULL;
+ }
+
+ /* Build the linked list */
+ tmpnode = nodes;
+ physical_address += offsetof(struct b2r2_node, node);
+ while (no_of_nodes--) {
+ tmpnode->physical_address = physical_address;
+ if (no_of_nodes)
+ tmpnode->next = tmpnode + 1;
+ else
+ tmpnode->next = NULL;
+
+ tmpnode++;
+ physical_address += sizeof(struct b2r2_node);
+ }
+
+ return nodes;
+}
+
+void b2r2_blt_free_nodes(struct b2r2_node *first_node)
+{
+ free_nodes(first_node);
+}
+
diff --git a/drivers/video/b2r2/b2r2_node_split.c b/drivers/video/b2r2/b2r2_node_split.c
new file mode 100644
index 00000000000..c3c3226b679
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_node_split.c
@@ -0,0 +1,3599 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 node splitter
+ *
+ * Author: Fredrik Allansson <fredrik.allansson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+
+#include "b2r2_node_split.h"
+#include "b2r2_internal.h"
+#include "b2r2_hw.h"
+#include "b2r2_debug.h"
+#include "b2r2_filters.h"
+
+/*
+ * Debug printing
+ */
+static u32 verbose;
+
+
+#define pverbose(...) \
+ do { \
+ if (verbose) \
+ printk(__VA_ARGS__); \
+ } while (false)
+
+#define PTRACE_ENTRY() pverbose(KERN_INFO LOG_TAG "::%s\n", __func__)
+
+#define LOG_TAG "b2r2_node_split"
+
+
+/*
+ * Macros and constants
+ */
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+#define INSTANCES_DEFAULT_SIZE 10
+#define INSTANCES_GROW_SIZE 5
+
+/*
+ * Internal types
+ */
+
+
+/*
+ * Global variables
+ */
+
+/**
+ * VMX values for different color space conversions
+ */
+static const u32 vmx_rgb_to_yuv[] = {
+ B2R2_VMX0_RGB_TO_YUV_601_VIDEO,
+ B2R2_VMX1_RGB_TO_YUV_601_VIDEO,
+ B2R2_VMX2_RGB_TO_YUV_601_VIDEO,
+ B2R2_VMX3_RGB_TO_YUV_601_VIDEO,
+};
+
+static const u32 vmx_yuv_to_rgb[] = {
+ B2R2_VMX0_YUV_TO_RGB_601_VIDEO,
+ B2R2_VMX1_YUV_TO_RGB_601_VIDEO,
+ B2R2_VMX2_YUV_TO_RGB_601_VIDEO,
+ B2R2_VMX3_YUV_TO_RGB_601_VIDEO,
+};
+
+static const u32 vmx_yvu_to_rgb[] = {
+ B2R2_VMX0_YVU_TO_RGB_601_VIDEO,
+ B2R2_VMX1_YVU_TO_RGB_601_VIDEO,
+ B2R2_VMX2_YVU_TO_RGB_601_VIDEO,
+ B2R2_VMX3_YVU_TO_RGB_601_VIDEO,
+};
+
+static const u32 vmx_rgb_to_yvu[] = {
+ B2R2_VMX0_RGB_TO_YVU_601_VIDEO,
+ B2R2_VMX1_RGB_TO_YVU_601_VIDEO,
+ B2R2_VMX2_RGB_TO_YVU_601_VIDEO,
+ B2R2_VMX3_RGB_TO_YVU_601_VIDEO,
+};
+
+static const u32 vmx_rgb_to_bgr[] = {
+ B2R2_VMX0_RGB_TO_BGR,
+ B2R2_VMX1_RGB_TO_BGR,
+ B2R2_VMX2_RGB_TO_BGR,
+ B2R2_VMX3_RGB_TO_BGR,
+};
+
+static const u32 vmx_bgr_to_yuv[] = {
+ B2R2_VMX0_BGR_TO_YUV_601_VIDEO,
+ B2R2_VMX1_BGR_TO_YUV_601_VIDEO,
+ B2R2_VMX2_BGR_TO_YUV_601_VIDEO,
+ B2R2_VMX3_BGR_TO_YUV_601_VIDEO,
+};
+
+static const u32 vmx_yuv_to_bgr[] = {
+ B2R2_VMX0_YUV_TO_BGR_601_VIDEO,
+ B2R2_VMX1_YUV_TO_BGR_601_VIDEO,
+ B2R2_VMX2_YUV_TO_BGR_601_VIDEO,
+ B2R2_VMX3_YUV_TO_BGR_601_VIDEO,
+};
+
+static const u32 vmx_bgr_to_yvu[] = {
+ B2R2_VMX0_BGR_TO_YVU_601_VIDEO,
+ B2R2_VMX1_BGR_TO_YVU_601_VIDEO,
+ B2R2_VMX2_BGR_TO_YVU_601_VIDEO,
+ B2R2_VMX3_BGR_TO_YVU_601_VIDEO,
+};
+
+static const u32 vmx_yvu_to_bgr[] = {
+ B2R2_VMX0_YVU_TO_BGR_601_VIDEO,
+ B2R2_VMX1_YVU_TO_BGR_601_VIDEO,
+ B2R2_VMX2_YVU_TO_BGR_601_VIDEO,
+ B2R2_VMX3_YVU_TO_BGR_601_VIDEO,
+};
+
+static const u32 vmx_yvu_to_yuv[] = {
+ B2R2_VMX0_YVU_TO_YUV_601_VIDEO,
+ B2R2_VMX1_YVU_TO_YUV_601_VIDEO,
+ B2R2_VMX2_YVU_TO_YUV_601_VIDEO,
+ B2R2_VMX3_YVU_TO_YUV_601_VIDEO,
+};
+
+/*
+ * Forward declaration of private functions
+ */
+
+static int analyze_fmt_conv(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count);
+static int analyze_color_fill(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count);
+static int analyze_copy(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count,
+ u32 *buf_count);
+static int analyze_scaling(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count,
+ u32 *buf_count);
+static int analyze_rotation(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count,
+ u32 *buf_count);
+static int analyze_transform(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count,
+ u32 *buf_count);
+static int analyze_rot_scale(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count,
+ u32 *buf_count);
+static int analyze_scale_factors(struct b2r2_node_split_job *this);
+
+static int calculate_rot_scale_node_count(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req);
+static int rot_node_count(s32 width, s32 height);
+
+static void configure_src(struct b2r2_node *node,
+ struct b2r2_node_split_buf *src, const u32 *ivmx);
+static int configure_dst(struct b2r2_node *node,
+ struct b2r2_node_split_buf *dst, const u32 *ivmx,
+ struct b2r2_node **next);
+static void configure_blend(struct b2r2_node *node, u32 flags, u32 global_alpha,
+ bool swap_fg_bg);
+static void configure_clip(struct b2r2_node *node,
+ struct b2r2_blt_rect *clip_rect);
+
+static int configure_tile(struct b2r2_node_split_job *this,
+ struct b2r2_node *node, struct b2r2_node **next);
+static void configure_direct_fill(struct b2r2_node *node, u32 color,
+ struct b2r2_node_split_buf *dst, struct b2r2_node **next);
+static int configure_fill(struct b2r2_node *node, u32 color,
+ enum b2r2_blt_fmt fmt, struct b2r2_node_split_buf *dst,
+ const u32 *ivmx, struct b2r2_node **next);
+static void configure_direct_copy(struct b2r2_node *node,
+ struct b2r2_node_split_buf *src,
+ struct b2r2_node_split_buf *dst, struct b2r2_node **next);
+static int configure_copy(struct b2r2_node *node,
+ struct b2r2_node_split_buf *src,
+ struct b2r2_node_split_buf *dst, const u32 *ivmx,
+ struct b2r2_node **next,
+ struct b2r2_node_split_job *this);
+static int configure_rotate(struct b2r2_node *node,
+ struct b2r2_node_split_buf *src,
+ struct b2r2_node_split_buf *dst, const u32 *ivmx,
+ struct b2r2_node **next,
+ struct b2r2_node_split_job *this);
+static int configure_scale(struct b2r2_node *node,
+ struct b2r2_node_split_buf *src,
+ struct b2r2_node_split_buf *dst, u16 h_rsf, u16 v_rsf,
+ const u32 *ivmx, struct b2r2_node **next,
+ struct b2r2_node_split_job *this);
+static void configure_tmp_buf(struct b2r2_node_split_buf *this, int index,
+ struct b2r2_blt_rect *window);
+static int configure_rot_scale(struct b2r2_node_split_job *this,
+ struct b2r2_node *node, struct b2r2_node **next);
+
+static int check_rect(const struct b2r2_blt_img *img,
+ const struct b2r2_blt_rect *rect,
+ const struct b2r2_blt_rect *clip);
+static void set_buf(struct b2r2_node_split_buf *buf, u32 addr,
+ const struct b2r2_blt_img *img,
+ const struct b2r2_blt_rect *rect, bool color_fill, u32 color);
+static int constrain_window(struct b2r2_blt_rect *window,
+ enum b2r2_blt_fmt fmt, u32 max_size);
+static int setup_tmp_buf(struct b2r2_node_split_buf *this, u32 max_size,
+ enum b2r2_blt_fmt pref_fmt, u32 pref_width, u32 pref_height);
+
+static enum b2r2_ty get_alpha_range(enum b2r2_blt_fmt fmt);
+static u32 set_alpha(enum b2r2_blt_fmt fmt, u8 alpha, u32 color);
+static u8 get_alpha(enum b2r2_blt_fmt fmt, u32 pixel);
+static bool fmt_has_alpha(enum b2r2_blt_fmt fmt);
+static bool is_rgb_fmt(enum b2r2_blt_fmt fmt);
+static bool is_bgr_fmt(enum b2r2_blt_fmt fmt);
+static bool is_yuv_fmt(enum b2r2_blt_fmt fmt);
+static bool is_yuv420_fmt(enum b2r2_blt_fmt fmt);
+static int fmt_byte_pitch(enum b2r2_blt_fmt fmt, u32 width);
+static enum b2r2_native_fmt to_native_fmt(enum b2r2_blt_fmt fmt);
+static u32 to_RGB888(u32 color, const enum b2r2_blt_fmt fmt);
+static enum b2r2_fmt_type get_fmt_type(enum b2r2_blt_fmt fmt);
+static char *type2str(enum b2r2_op_type type);
+
+static bool is_transform(const struct b2r2_blt_request *req);
+static int calculate_scale_factor(u32 from, u32 to, u16 *sf_out);
+static s32 rescale(s32 dim, u16 sf);
+static s32 inv_rescale(s32 dim, u16 sf);
+
+static void set_target(struct b2r2_node *node, u32 addr,
+ struct b2r2_node_split_buf *buf);
+static void set_src(struct b2r2_src_config *src, u32 addr,
+ struct b2r2_node_split_buf *buf);
+static void set_src_1(struct b2r2_node *node, u32 addr,
+ struct b2r2_node_split_buf *buf);
+static void set_src_2(struct b2r2_node *node, u32 addr,
+ struct b2r2_node_split_buf *buf);
+static void set_src_3(struct b2r2_node *node, u32 addr,
+ struct b2r2_node_split_buf *buf);
+static void set_ivmx(struct b2r2_node *node, const u32 *vmx_values);
+
+static void reset_nodes(struct b2r2_node *node);
+
+/*
+ * Public functions
+ */
+
+/**
+ * b2r2_node_split_analyze() - analyzes the request
+ */
+int b2r2_node_split_analyze(const struct b2r2_blt_request *req,
+ u32 max_buf_size, u32 *node_count, struct b2r2_work_buf **bufs,
+ u32 *buf_count, struct b2r2_node_split_job *this)
+{
+ int ret;
+ bool color_fill;
+
+ PTRACE_ENTRY();
+
+ memset(this, 0, sizeof(*this));
+
+ /* Copy parameters */
+ this->flags = req->user_req.flags;
+ this->transform = req->user_req.transform;
+ this->max_buf_size = max_buf_size;
+ this->global_alpha = req->user_req.global_alpha;
+ this->buf_count = 0;
+ this->node_count = 0;
+
+ if (this->flags & B2R2_BLT_FLAG_BLUR) {
+ ret = -ENOSYS;
+ goto unsupported;
+ }
+
+ if ((this->flags & B2R2_BLT_FLAG_SOURCE_COLOR_KEY) &&
+ (is_yuv_fmt(req->user_req.src_img.fmt) ||
+ req->user_req.src_img.fmt == B2R2_BLT_FMT_1_BIT_A1 ||
+ req->user_req.src_img.fmt == B2R2_BLT_FMT_8_BIT_A8)) {
+ b2r2_log_warn("%s: Unsupported: source color keying with "
+ "YUV or pure alpha formats.\n",
+ __func__);
+ ret = -ENOSYS;
+ goto unsupported;
+ }
+
+ if (this->flags & (B2R2_BLT_FLAG_DEST_COLOR_KEY |
+ B2R2_BLT_FLAG_SOURCE_MASK)) {
+ b2r2_log_warn("%s: Unsupported: source mask, "
+ "destination color keying.\n",
+ __func__);
+ ret = -ENOSYS;
+ goto unsupported;
+ }
+
+ if (req->user_req.src_img.fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR) {
+ b2r2_log_warn("%s: Unsupported "
+ "format B2R2_BLT_FMT_YUV444_PACKED_PLANAR "
+ "on source\n", __func__);
+ ret = -ENOSYS;
+ goto unsupported;
+ }
+
+ if (req->user_req.dst_img.fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR) {
+ b2r2_log_warn("%s: Unsupported "
+ "format B2R2_BLT_FMT_YUV444_PACKED_PLANAR "
+ "on destination\n", __func__);
+ ret = -ENOSYS;
+ goto unsupported;
+ }
+
+ if ((req->user_req.flags & B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) &&
+ req->user_req.clut == NULL) {
+ b2r2_log_warn("%s: Invalid request: no table specified "
+ "for CLUT color correction.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* Check for color fill */
+ color_fill = (this->flags & (B2R2_BLT_FLAG_SOURCE_FILL |
+ B2R2_BLT_FLAG_SOURCE_FILL_RAW)) != 0;
+
+ /* Configure the source and destination buffers */
+ set_buf(&this->src, req->src_resolved.physical_address,
+ &req->user_req.src_img, &req->user_req.src_rect,
+ color_fill, req->user_req.src_color);
+
+ set_buf(&this->dst, req->dst_resolved.physical_address,
+ &req->user_req.dst_img, &req->user_req.dst_rect, false,
+ 0);
+
+ b2r2_log_info("%s:\n"
+ "\t\tsrc.rect=(%4d, %4d, %4d, %4d)\t"
+ "dst.rect=(%4d, %4d, %4d, %4d)\n", __func__, this->src.rect.x,
+ this->src.rect.y, this->src.rect.width, this->src.rect.height,
+ this->dst.rect.x, this->dst.rect.y, this->dst.rect.width,
+ this->dst.rect.height);
+
+ if (this->flags & B2R2_BLT_FLAG_DITHER)
+ this->dst.dither = B2R2_TTY_RGB_ROUND_DITHER;
+
+ if (this->flags & B2R2_BLT_FLAG_SOURCE_COLOR_KEY) {
+ this->flag_param = req->user_req.src_color;
+ }
+
+ /* Check for blending */
+ if (this->flags & B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND)
+ this->blend = true;
+ else if (this->flags & B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND)
+ this->blend = fmt_has_alpha(this->src.fmt) ||
+ fmt_has_alpha(this->dst.fmt);
+
+ /* Check for clipping */
+ this->clip = (this->flags &
+ B2R2_BLT_FLAG_DESTINATION_CLIP) != 0;
+ if (this->clip) {
+ s32 l = req->user_req.dst_clip_rect.x;
+ s32 r = l + req->user_req.dst_clip_rect.width;
+ s32 t = req->user_req.dst_clip_rect.y;
+ s32 b = t + req->user_req.dst_clip_rect.height;
+
+ /* Intersect the clip and buffer rects */
+ if (l < 0)
+ l = 0;
+ if (r > req->user_req.dst_img.width)
+ r = req->user_req.dst_img.width;
+ if (t < 0)
+ t = 0;
+ if (b > req->user_req.dst_img.height)
+ b = req->user_req.dst_img.height;
+
+ this->clip_rect.x = l;
+ this->clip_rect.y = t;
+ this->clip_rect.width = r - l;
+ this->clip_rect.height = b - t;
+ } else {
+ /* Set the clip rectangle to the buffer bounds */
+ this->clip_rect.x = 0;
+ this->clip_rect.y = 0;
+ this->clip_rect.width = req->user_req.dst_img.width;
+ this->clip_rect.height = req->user_req.dst_img.height;
+ }
+
+ /* Validate the destination */
+ ret = check_rect(&req->user_req.dst_img, &req->user_req.dst_rect,
+ &this->clip_rect);
+ if (ret < 0)
+ goto error;
+
+ /* Validate the source (if not color fill) */
+ if (!color_fill) {
+ ret = check_rect(&req->user_req.src_img,
+ &req->user_req.src_rect, NULL);
+ if (ret < 0)
+ goto error;
+ }
+
+ /* Do the analysis depending on the type of operation */
+ if (color_fill) {
+ ret = analyze_color_fill(this, req, &this->node_count);
+ } else {
+
+ if (is_transform(req) ||
+ (this->src.type == B2R2_FMT_TYPE_SEMI_PLANAR) ||
+ (this->src.type == B2R2_FMT_TYPE_PLANAR) ||
+ (this->dst.type == B2R2_FMT_TYPE_SEMI_PLANAR) ||
+ (this->dst.type == B2R2_FMT_TYPE_PLANAR)) {
+ ret = analyze_transform(this, req, &this->node_count,
+ &this->buf_count);
+ } else {
+ ret = analyze_copy(this, req, &this->node_count,
+ &this->buf_count);
+ }
+ }
+
+ if (ret == -ENOSYS) {
+ goto unsupported;
+ } else if (ret < 0) {
+ b2r2_log_warn("%s: Analysis failed!\n", __func__);
+ goto error;
+ }
+
+ *buf_count = this->buf_count;
+ *node_count = this->node_count;
+
+ if (this->buf_count > 0)
+ *bufs = &this->work_bufs[0];
+
+ pverbose(KERN_INFO "%s: src=%d dst=%d\n"
+ "\t\tsrc.rect=(%4d, %4d, %4d, %4d)\td_src=(%4d, %4d)\n"
+ "\t\tdst.rect=(%4d, %4d, %4d, %4d)\td_dst=(%4d, %4d)\n",
+ __func__, req->user_req.src_img.buf.fd,
+ req->user_req.dst_img.buf.fd,
+ this->src.rect.x, this->src.rect.y,
+ this->src.rect.width, this->src.rect.height,
+ this->src.dx, this->src.dy,
+ this->dst.rect.x, this->dst.rect.y,
+ this->dst.rect.width, this->dst.rect.height,
+ this->dst.dx, this->dst.dy);
+ pverbose(KERN_INFO "%s:\n"
+ "\t\tsrc.window=(%4d, %4d, %4d, %4d)\td_src=(%d, %d)\n"
+ "\t\tdst.window=(%4d, %4d, %4d, %4d)\td_dst=(%d, %d)\n",
+ __func__, this->src.window.x, this->src.window.y,
+ this->src.window.width, this->src.window.height,
+ this->src.dx, this->src.dy,
+ this->dst.window.x, this->dst.window.y,
+ this->dst.window.width, this->dst.window.height,
+ this->dst.dx, this->dst.dy);
+
+ pverbose(KERN_INFO "\t\t\tnode_count=%d, buf_count=%d, type=%s\n",
+ *node_count, *buf_count, type2str(this->type));
+ pverbose(KERN_INFO "\t\t\tblend=%d, clip=%d, color_fill=%d\n",
+ this->blend, this->clip, color_fill);
+
+ return 0;
+
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+unsupported:
+ return ret;
+}
+
+/**
+ * b2r2_node_split_configure() - configures the node list
+ */
+int b2r2_node_split_configure(struct b2r2_node_split_job *this,
+ struct b2r2_node *first)
+{
+ int ret;
+ struct b2r2_node *node = first;
+ struct b2r2_node *last = first;
+
+ bool last_row = false;
+ bool last_col = false;
+
+ s32 src_win_width;
+ s32 src_win_height;
+ s32 dst_win_width;
+ s32 dst_win_height;
+
+ pverbose(KERN_INFO "%s: src_rect=(%d, %d, %d, %d), "
+ "dst_rect=(%d, %d, %d, %d)\n", __func__,
+ this->src.rect.x, this->src.rect.y,
+ this->src.rect.width, this->src.rect.height,
+ this->dst.rect.x, this->dst.rect.y,
+ this->dst.rect.width,
+ this->dst.rect.height);
+
+ pverbose(KERN_INFO "%s: d_src=(%d, %d) d_dst=(%d, %d)\n",
+ __func__, this->src.dx, this->src.dy, this->dst.dx,
+ this->dst.dy);
+
+ reset_nodes(node);
+
+ /* Save these so we can do restore them when moving to a new row */
+ src_win_width = this->src.window.width;
+ src_win_height = this->src.window.height;
+ dst_win_width = this->dst.window.width;
+ dst_win_height = this->dst.window.height;
+
+ do {
+ if (node == NULL) {
+ /* DOH! This is an internal error (to few nodes
+ allocated) */
+ b2r2_log_warn("%s: "
+ "Internal error! Out of nodes!\n",
+ __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ last_col = ABS(this->src.window.x + this->src.dx -
+ this->src.rect.x) >=
+ this->src.rect.width;
+ last_row = ABS(this->src.window.y + this->src.dy -
+ this->src.rect.y) >=
+ this->src.rect.height;
+
+ if (last_col) {
+ pverbose(KERN_INFO "%s: last col\n", __func__);
+ this->src.window.width = this->src.rect.width -
+ ABS(this->src.rect.x - this->src.window.x);
+ if (this->src.window.width != src_win_width) { /* To not introduce precision issues on "normal" tiles */
+ s32 new_dst_width =
+ this->horiz_rescale ? rescale(this->src.window.width, this->horiz_sf) : this->src.window.width;
+ if (this->rotation)
+ this->dst.window.height = new_dst_width;
+ else
+ this->dst.window.width = new_dst_width;
+ }
+ }
+
+ if (last_row) {
+ pverbose(KERN_INFO "%s: last row\n", __func__);
+ this->src.window.height = this->src.rect.height -
+ ABS(this->src.rect.y - this->src.window.y);
+ if (this->src.window.height != src_win_height) { /* To not introduce precision issues on "normal" tiles */
+ s32 new_dst_height =
+ this->vert_rescale ? rescale(this->src.window.height, this->vert_sf) : this->src.window.height;
+ if (this->rotation)
+ this->dst.window.width = new_dst_height;
+ else
+ this->dst.window.height = new_dst_height;
+ }
+ }
+
+ pverbose(KERN_INFO "%s: src=(%d, %d, %d, %d), "
+ "dst=(%d, %d, %d, %d)\n", __func__,
+ this->src.window.x, this->src.window.y,
+ this->src.window.width, this->src.window.height,
+ this->dst.window.x, this->dst.window.y,
+ this->dst.window.width,
+ this->dst.window.height);
+
+ ret = configure_tile(this, node, &last);
+ if (ret < 0)
+ goto error;
+
+ this->src.window.x += this->src.dx;
+ if (this->rotation)
+ this->dst.window.y += this->dst.dy;
+ else
+ this->dst.window.x += this->dst.dx;
+
+ if (last_col) {
+ /* Reset the window and slide vertically */
+ this->src.window.x = this->src.rect.x;
+ this->src.window.width = src_win_width;
+
+ this->src.window.y += this->src.dy;
+
+ if (this->rotation) {
+ this->dst.window.y = this->dst.rect.y;
+ this->dst.window.height = dst_win_height;
+
+ this->dst.window.x += this->dst.dx;
+ } else {
+ this->dst.window.x = this->dst.rect.x;
+ this->dst.window.width = dst_win_width;
+
+ this->dst.window.y += this->dst.dy;
+ }
+ }
+
+ node = last;
+
+ } while (!(last_row && last_col));
+
+ return 0;
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+
+ {
+ int nbr_nodes = 0;
+ while (first != NULL) {
+ nbr_nodes++;
+ first = first->next;
+ }
+
+ b2r2_log_warn("%s: Asked for %d nodes, got %d\n",
+ __func__, this->node_count, nbr_nodes);
+ b2r2_log_warn("%s: src.rect=(%4d, %4d, %4d, %4d)\t"
+ "dst.rect=(%4d, %4d, %4d, %4d)\n", __func__,
+ this->src.rect.x, this->src.rect.y,
+ this->src.rect.width, this->src.rect.height,
+ this->dst.rect.x, this->dst.rect.y,
+ this->dst.rect.width, this->dst.rect.height);
+ }
+
+ return ret;
+}
+
+/**
+ * b2r2_node_split_assign_buffers() - assigns temporary buffers to the node list
+ */
+int b2r2_node_split_assign_buffers(struct b2r2_node_split_job *this,
+ struct b2r2_node *first, struct b2r2_work_buf *bufs,
+ u32 buf_count)
+{
+ struct b2r2_node *node = first;
+
+ while (node != NULL) {
+ /* The indices are offset by one */
+ if (node->dst_tmp_index) {
+ u32 addr = bufs[node->dst_tmp_index - 1].phys_addr;
+
+ BUG_ON(node->dst_tmp_index > buf_count);
+
+ node->node.GROUP1.B2R2_TBA =
+ bufs[node->dst_tmp_index - 1].phys_addr;
+ pverbose(KERN_INFO LOG_TAG "::%s: "
+ "%p Assigning %p as destination\n", __func__,
+ node, (void *)addr);
+ }
+ if (node->src_tmp_index) {
+ u32 addr = bufs[node->src_tmp_index - 1].phys_addr;
+
+ b2r2_log_info("%s: "
+ "%p Assigning %p as source ", __func__,
+ node, (void *)addr);
+
+ BUG_ON(node->src_tmp_index > buf_count);
+
+ switch (node->src_index) {
+ case 1:
+ b2r2_log_info("1\n");
+ node->node.GROUP3.B2R2_SBA = addr;
+ break;
+ case 2:
+ b2r2_log_info("2\n");
+ node->node.GROUP4.B2R2_SBA = addr;
+ break;
+ case 3:
+ b2r2_log_info("3\n");
+ node->node.GROUP5.B2R2_SBA = addr;
+ break;
+ default:
+ BUG_ON(1);
+ break;
+ }
+ }
+
+ b2r2_log_info("%s: tba=%p\tsba=%p\n", __func__,
+ (void *)node->node.GROUP1.B2R2_TBA,
+ (void *)node->node.GROUP4.B2R2_SBA);
+
+ node = node->next;
+ }
+
+ return 0;
+}
+
+/**
+ * b2r2_node_split_unassign_buffers() - releases temporary buffers
+ */
+void b2r2_node_split_unassign_buffers(struct b2r2_node_split_job *this,
+ struct b2r2_node *first)
+{
+ return;
+}
+
+/**
+ * b2r2_node_split_cancel() - cancels and releases a job instance
+ */
+void b2r2_node_split_cancel(struct b2r2_node_split_job *this)
+{
+ pverbose("%s: Releasing job\n", __func__);
+
+ memset(this, 0, sizeof(*this));
+
+ return;
+}
+
+/*
+ * Private functions
+ */
+
+static int check_rect(const struct b2r2_blt_img *img,
+ const struct b2r2_blt_rect *rect,
+ const struct b2r2_blt_rect *clip)
+{
+ int ret;
+
+ s32 l, r, b, t;
+
+ /* Check rectangle dimensions*/
+ if ((rect->width <= 0) || (rect->height <= 0)) {
+ b2r2_log_warn("%s: "
+ "Illegal rect (%d, %d, %d, %d)\n",
+ __func__, rect->x, rect->y, rect->width, rect->height);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* If we are using clip we should only look at the intersection of the
+ rects */
+ if (clip) {
+ l = MAX(rect->x, clip->x);
+ t = MAX(rect->y, clip->y);
+ r = MIN(rect->x + rect->width, clip->x + clip->width);
+ b = MIN(rect->y + rect->height, clip->y + clip->height);
+ } else {
+ l = rect->x;
+ t = rect->y;
+ r = rect->x + rect->width;
+ b = rect->y + rect->height;
+ }
+
+ /* Check so that the rect isn't outside the buffer */
+ if ((l < 0) || (t < 0) || (l >= img->width) || (t >= img->height)) {
+ b2r2_log_warn("%s: "
+ "rect origin outside buffer\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if ((r > img->width) || (b > img->height)) {
+ b2r2_log_warn("%s: "
+ "rect ends outside buffer\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Check so the intersected rectangle isn't empty */
+ if ((l == r) || (t == b)) {
+ b2r2_log_warn("%s: "
+ "rect is empty (width or height zero)\n",
+ __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ return 0;
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * analyze_fmt_conv() - analyze the format conversions needed for a job
+ */
+static int analyze_fmt_conv(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count)
+{
+ pverbose(KERN_INFO LOG_TAG "::%s: Analyzing fmt conv...\n", __func__);
+
+ if (is_rgb_fmt(this->src.fmt)) {
+ if (is_yuv_fmt(this->dst.fmt)) {
+ if (this->dst.fmt == B2R2_BLT_FMT_Y_CB_Y_CR)
+ this->ivmx = &vmx_rgb_to_yvu[0];
+ else
+ this->ivmx = &vmx_rgb_to_yuv[0];
+ } else if (is_bgr_fmt(this->dst.fmt)) {
+ this->ivmx = &vmx_rgb_to_bgr[0];
+ }
+ } else if (is_yuv_fmt(this->src.fmt)) {
+ if (this->src.fmt == B2R2_BLT_FMT_Y_CB_Y_CR) {
+ if (is_rgb_fmt(this->dst.fmt))
+ this->ivmx = &vmx_yvu_to_rgb[0];
+ else if (is_bgr_fmt(this->dst.fmt))
+ this->ivmx = &vmx_yvu_to_bgr[0];
+ else if (this->dst.fmt != B2R2_BLT_FMT_Y_CB_Y_CR)
+ this->ivmx = &vmx_yvu_to_yuv[0];
+ } else {
+ if (is_rgb_fmt(this->dst.fmt))
+ this->ivmx = &vmx_yuv_to_rgb[0];
+ else if (is_bgr_fmt(this->dst.fmt))
+ this->ivmx = &vmx_yuv_to_bgr[0];
+ else if (this->dst.fmt == B2R2_BLT_FMT_Y_CB_Y_CR)
+ this->ivmx = &vmx_yvu_to_yuv[0];
+ }
+ } else if (is_bgr_fmt(this->src.fmt)) {
+ if (is_rgb_fmt(this->dst.fmt))
+ this->ivmx = &vmx_rgb_to_bgr[0];
+ else if (is_yuv_fmt(this->dst.fmt)) {
+ if (this->dst.fmt == B2R2_BLT_FMT_Y_CB_Y_CR)
+ this->ivmx = &vmx_bgr_to_yvu[0];
+ else
+ this->ivmx = &vmx_bgr_to_yuv[0];
+ }
+ }
+
+ if (this->dst.type == B2R2_FMT_TYPE_RASTER) {
+ pverbose(KERN_INFO LOG_TAG "::%s: --> RASTER\n", __func__);
+ *node_count = 1;
+ } else if (this->dst.type == B2R2_FMT_TYPE_SEMI_PLANAR) {
+ pverbose(KERN_INFO LOG_TAG "::%s: --> SEMI PLANAR\n", __func__);
+ *node_count = 2;
+ } else if (this->dst.type == B2R2_FMT_TYPE_PLANAR) {
+ pverbose(KERN_INFO LOG_TAG "::%s: --> PLANAR\n", __func__);
+ *node_count = 3;
+ } else {
+ /* That's strange... */
+ BUG_ON(1);
+ }
+
+ return 0;
+}
+
+/**
+ * analyze_color_fill() - analyze a color fill operation
+ */
+static int analyze_color_fill(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count)
+{
+ int ret;
+ pverbose(KERN_INFO LOG_TAG "::%s: Analyzing color fill...\n", __func__);
+
+ /* Destination must be raster for raw fill to work */
+ if ((this->flags & B2R2_BLT_FLAG_SOURCE_FILL_RAW) &&
+ (this->dst.type != B2R2_FMT_TYPE_RASTER)) {
+ b2r2_log_warn("%s: Raw fill requires raster destination\n",
+ __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* We will try to fill the entire rectangle in one go */
+ memcpy(&this->dst.window, &this->dst.rect, sizeof(this->dst.window));
+
+ /* Check if this is a direct fill */
+ if ((!this->blend) && ((this->flags & B2R2_BLT_FLAG_SOURCE_FILL_RAW) ||
+ (this->dst.fmt == B2R2_BLT_FMT_32_BIT_ARGB8888) ||
+ (this->dst.fmt == B2R2_BLT_FMT_32_BIT_ABGR8888) ||
+ (this->dst.fmt == B2R2_BLT_FMT_32_BIT_AYUV8888))) {
+ pverbose(KERN_INFO LOG_TAG "::%s: Direct fill!\n", __func__);
+ this->type = B2R2_DIRECT_FILL;
+
+ /* The color format will be the same as the dst fmt */
+ this->src.fmt = this->dst.fmt;
+
+ /* The entire destination rectangle will be */
+ memcpy(&this->dst.window, &this->dst.rect,
+ sizeof(this->dst.window));
+ *node_count = 1;
+ } else {
+ pverbose(KERN_INFO LOG_TAG "::%s: Normal fill!\n", __func__);
+ this->type = B2R2_FILL;
+
+ /* Determine the fill color format */
+ if (this->flags & B2R2_BLT_FLAG_SOURCE_FILL_RAW) {
+ /* The color format will be the same as the dst fmt */
+ this->src.fmt = this->dst.fmt;
+ } else {
+ /* If the dst fmt is YUV the fill fmt will be as well */
+ if (is_yuv_fmt(this->dst.fmt)) {
+ this->src.fmt = B2R2_BLT_FMT_32_BIT_AYUV8888;
+ } else if (is_rgb_fmt(this->dst.fmt)) {
+ this->src.fmt = B2R2_BLT_FMT_32_BIT_ARGB8888;
+ } else if (is_bgr_fmt(this->dst.fmt)) {
+ /* Color will still be ARGB, we will translate
+ using IVMX (configured later) */
+ this->src.fmt = B2R2_BLT_FMT_32_BIT_ARGB8888;
+ } else {
+ /* Wait, what? */
+ b2r2_log_warn("%s: "
+ "Illegal destination format for fill",
+ __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ /* If the destination is a multibuffer format, the operation
+ must be treated like a scale operation (multiple nodes).
+ Hence the need for src and dst windows */
+ if (this->dst.type != B2R2_FMT_TYPE_RASTER) {
+ memcpy(&this->dst.window, &this->dst.rect,
+ sizeof(this->dst.window));
+ this->dst.window.width = MIN(this->dst.window.width,
+ B2R2_RESCALE_MAX_WIDTH);
+
+ /* We need a rectangle and a window for the source */
+ memcpy(&this->src.rect, &this->dst.rect,
+ sizeof(this->src.rect));
+ memcpy(&this->src.window, &this->dst.window,
+ sizeof(this->src.window));
+ }
+
+ /* Also, B2R2 seems to ignore the pixel alpha value */
+ if (((this->flags & B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND)
+ != 0) &&
+ ((this->flags & B2R2_BLT_FLAG_SOURCE_FILL_RAW)
+ == 0) && fmt_has_alpha(this->src.fmt)) {
+ u8 pixel_alpha = get_alpha(this->src.fmt,
+ this->src.color);
+ u32 new_global = pixel_alpha * this->global_alpha / 255;
+
+ this->global_alpha = (u8)new_global;
+
+ /* Set the pixel alpha to full opaque so we don't get
+ any nasty suprises */
+ this->src.color = set_alpha(this->src.fmt, 0xFF,
+ this->src.color);
+ }
+
+ ret = analyze_fmt_conv(this, req, node_count);
+ if (ret < 0)
+ goto error;
+ }
+
+ this->dst.dx = this->dst.window.width;
+ this->dst.dy = this->dst.window.height;
+
+ return 0;
+
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+
+}
+
+/**
+ * analyze_transform() - analyze a transform operation (rescale, rotate, etc.)
+ */
+static int analyze_transform(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count,
+ u32 *buf_count)
+{
+ int ret;
+
+ bool is_scaling;
+
+ /* The transform enum is defined so that all rotation transforms are
+ masked with the rotation flag */
+ this->rotation = (this->transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) != 0;
+
+ pverbose(KERN_INFO LOG_TAG "::%s: Analyzing transform...\n", __func__);
+
+ /* Check for scaling */
+ if (this->rotation) {
+ is_scaling = (this->src.rect.width != this->dst.rect.height) ||
+ (this->src.rect.height != this->dst.rect.width);
+ } else {
+ is_scaling = (this->src.rect.width != this->dst.rect.width) ||
+ (this->src.rect.height != this->dst.rect.height);
+ }
+
+ /* Plane separated formats must be treated as scaling */
+ is_scaling = is_scaling ||
+ (this->src.type == B2R2_FMT_TYPE_SEMI_PLANAR) ||
+ (this->src.type == B2R2_FMT_TYPE_PLANAR) ||
+ (this->dst.type == B2R2_FMT_TYPE_SEMI_PLANAR) ||
+ (this->dst.type == B2R2_FMT_TYPE_PLANAR);
+
+ if (is_scaling && this->rotation && this->blend) {
+ /* TODO: This is unsupported. Fix it! */
+ printk(KERN_DEBUG LOG_TAG "::%s: Unsupported operation\n",
+ __func__);
+ ret = -ENOSYS;
+ goto unsupported;
+ }
+
+ /* Check which type of transform */
+ if (is_scaling && this->rotation) {
+ ret = analyze_rot_scale(this, req, node_count, buf_count);
+ if (ret < 0)
+ goto error;
+ } else if (is_scaling) {
+ ret = analyze_scaling(this, req, node_count, buf_count);
+ if (ret < 0)
+ goto error;
+ } else if (this->rotation) {
+ ret = analyze_rotation(this, req, node_count, buf_count);
+ if (ret < 0)
+ goto error;
+ } else {
+ /* No additional nodes are required for a flip */
+ ret = analyze_copy(this, req, node_count, buf_count);
+ if (ret < 0)
+ goto error;
+ this->type = B2R2_FLIP;
+ }
+
+ /* Modify the horizontal and vertical scan order if FLIP (the enum
+ values are set up so all flip combination values are masked with a
+ flip flag) */
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_H) {
+ this->src.hso = B2R2_TY_HSO_RIGHT_TO_LEFT;
+ this->src.rect.x += this->src.rect.width - 1;
+ this->src.window.x = this->src.rect.x;
+ this->src.dx = -this->src.window.width;
+ } else {
+ this->src.dx = this->src.window.width;
+ }
+ if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_V) {
+ this->src.vso = B2R2_TY_VSO_BOTTOM_TO_TOP;
+ this->src.rect.y += this->src.rect.height - 1;
+ this->src.window.y = this->src.rect.y;
+ this->src.dy = -this->src.window.height;
+ } else {
+ this->src.dy = this->src.window.height;
+ }
+
+ /* Set the dx and dy of the destination as well */
+ if (this->dst.hso == B2R2_TY_HSO_RIGHT_TO_LEFT)
+ this->dst.dx = -this->dst.window.width;
+ else
+ this->dst.dx = this->dst.window.width;
+ if (this->dst.vso == B2R2_TY_VSO_BOTTOM_TO_TOP)
+ this->dst.dy = -this->dst.window.height;
+ else
+ this->dst.dy = this->dst.window.height;
+
+ return 0;
+
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+unsupported:
+ return ret;
+}
+
+/**
+ * analyze_copy() - analyze a copy operation
+ */
+static int analyze_copy(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count,
+ u32 *buf_count)
+{
+ int ret;
+
+ pverbose(KERN_INFO LOG_TAG "::%s: Analyzing copy...\n", __func__);
+
+ memcpy(&this->src.window, &this->src.rect, sizeof(this->src.window));
+ memcpy(&this->dst.window, &this->dst.rect, sizeof(this->dst.window));
+
+ if (!this->blend && !(this->flags & B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) &&
+ (this->src.fmt == this->dst.fmt) &&
+ (this->src.type == B2R2_FMT_TYPE_RASTER) &&
+ (this->dst.rect.x >= this->clip_rect.x) &&
+ (this->dst.rect.y >= this->clip_rect.y) &&
+ (this->dst.rect.x + this->dst.rect.width <=
+ this->clip_rect.x + this->clip_rect.width) &&
+ (this->dst.rect.y + this->dst.rect.height <=
+ this->clip_rect.y + this->clip_rect.height)) {
+ this->type = B2R2_DIRECT_COPY;
+ *node_count = 1;
+ } else {
+ u32 copy_count = 0;
+ u32 nbr_rows = 0;
+ u32 nbr_cols = 0;
+
+ this->type = B2R2_COPY;
+
+ ret = analyze_fmt_conv(this, req, &copy_count);
+ if (ret < 0)
+ goto error;
+
+ if (this->buf_count > 0) {
+ setup_tmp_buf(&this->tmp_bufs[0], this->max_buf_size,
+ this->dst.fmt, this->dst.rect.width,
+ this->dst.rect.height);
+
+ this->work_bufs[0].size = this->tmp_bufs[0].pitch *
+ this->tmp_bufs[0].height;
+
+ ret = constrain_window(&this->src.window,
+ this->tmp_bufs[0].fmt,
+ this->work_bufs[0].size);
+ if (ret < 0)
+ goto error;
+
+ this->dst.window.width = this->src.window.width;
+ this->dst.window.height = this->src.window.height;
+
+ /* Each copy will require an additional node */
+ copy_count++;
+ }
+
+ /* Calculate how many rows and columns this will result in */
+ nbr_cols = this->src.rect.width / this->src.window.width;
+ if (this->src.rect.width % this->src.window.width)
+ nbr_cols++;
+
+ nbr_rows = this->src.rect.height / this->src.window.height;
+ if (this->src.rect.height % this->src.window.height)
+ nbr_rows++;
+
+ /* Finally, calculate the node count */
+ *node_count = copy_count * nbr_rows * nbr_cols;
+ }
+
+ this->src.dx = this->src.window.width;
+ this->src.dy = this->src.window.height;
+ this->dst.dx = this->dst.window.width;
+ this->dst.dy = this->dst.window.height;
+
+ return 0;
+
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * analyze_rot_scaling() - analyzes a combined rotation and scaling op
+ */
+static int analyze_rot_scale(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count,
+ u32 *buf_count)
+{
+ int ret;
+
+ struct b2r2_node_split_buf *tmp;
+
+ s32 tmp_width;
+ s32 tmp_height;
+
+ /* We will always need one tmp buffer */
+ this->buf_count = 1;
+ tmp = &this->tmp_bufs[0];
+
+ ret = analyze_scale_factors(this);
+ if (ret < 0)
+ goto error;
+
+ /* All rotations are written from the bottom up */
+ this->dst.vso = B2R2_TY_VSO_BOTTOM_TO_TOP;
+ this->dst.rect.y += this->dst.rect.height - 1;
+
+ /* We will try to to the entire rectangle at once */
+ memcpy(&this->src.window, &this->src.rect, sizeof(this->src.window));
+ memcpy(&this->dst.window, &this->dst.rect, sizeof(this->dst.window));
+
+ /* The source width will be limited by the rescale max width */
+ this->src.window.width = MIN(this->src.window.width,
+ B2R2_RESCALE_MAX_WIDTH);
+
+ tmp_width = rescale(this->src.window.width, this->horiz_sf);
+ tmp_height = rescale(this->src.window.height, this->vert_sf);
+
+ /* Setup the tmp buf from the source window */
+ ret = setup_tmp_buf(tmp, this->max_buf_size, this->dst.fmt, tmp_width,
+ tmp_height);
+ if (ret < 0)
+ goto error;
+
+ b2r2_log_info("%s: tmp_width=%d\ttmp_height=%d\n",
+ __func__, tmp_width, tmp_height);
+ b2r2_log_info("%s: "
+ "tmp.rect.width=%d\ttmp.rect.height=%d\n", __func__,
+ tmp->rect.width, tmp->rect.height);
+ b2r2_log_info("%s: hsf=%d\tvsf=%d\n",
+ __func__, this->horiz_sf, this->vert_sf);
+
+ this->work_bufs[0].size = tmp->pitch * tmp->height;
+ tmp->tmp_buf_index = 1;
+
+ /* If the entire source window couldn't fit into the tmp buf we need
+ to modify it */
+ if (tmp_width != tmp->rect.width)
+ this->src.window.width = inv_rescale(tmp->rect.width,
+ this->horiz_sf);
+ if (tmp_height != tmp->rect.height)
+ this->src.window.height = inv_rescale(tmp->rect.height,
+ this->vert_sf);
+
+ /* The source window will slide normally */
+ this->src.dx = this->src.window.width;
+ this->src.dy = this->src.window.height;
+
+ /* Setup the destination window (also make sure it is never larger
+ than the rectangle) */
+ this->dst.window.width = MIN(this->dst.rect.width, tmp->rect.height);
+ this->dst.window.height = MIN(this->dst.rect.height, tmp->rect.width);
+
+ /* The destination will slide upwards because of the rotation */
+ this->dst.dx = this->dst.window.width;
+ this->dst.dy = -this->dst.window.height;
+
+ /* Calculate the number of nodes needed */
+ ret = calculate_rot_scale_node_count(this, req);
+ if (ret < 0)
+ goto error;
+
+ this->type = B2R2_SCALE_AND_ROTATE;
+
+ b2r2_log_info("%s: Rot scale:\n", __func__);
+ b2r2_log_info("%s: node_count=%d\n", __func__,
+ this->node_count);
+
+ return 0;
+
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * calculate_rot_scale_node_count() - calculates the number of nodes required
+ * for a combined rotation and scaling
+ */
+static int calculate_rot_scale_node_count(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req)
+{
+ int ret;
+
+ u32 copy_count;
+ u32 rot_count;
+ u32 tile_rots;
+ u32 scale_count;
+
+ s32 src_right_width;
+ s32 src_bottom_height;
+ s32 dst_right_width;
+ s32 dst_bottom_height;
+
+ int nbr_full_rows;
+ int nbr_full_cols;
+
+ /* First check how many nodes we need for a simple copy */
+ ret = analyze_fmt_conv(this, req, &copy_count);
+ if (ret < 0)
+ goto error;
+
+ /* The number of rotation nodes per tile will vary depending on whether
+ it is an "inner" tile or an "edge" tile, since they may have
+ different sizes. */
+ nbr_full_cols = this->src.rect.width / this->src.window.width;
+ nbr_full_rows = this->src.rect.height / this->src.window.height;
+
+ src_right_width = this->src.rect.width % this->src.window.width;
+ if (src_right_width)
+ dst_right_width =
+ this->horiz_rescale ? rescale(src_right_width, this->horiz_sf) : src_right_width;
+ else
+ dst_right_width = 0;
+
+ src_bottom_height = this->src.rect.height % this->src.window.height;
+ if (src_bottom_height)
+ dst_bottom_height =
+ this->horiz_rescale ? rescale(src_bottom_height, this->vert_sf) : src_bottom_height;
+ else
+ dst_bottom_height = 0;
+
+ b2r2_log_info("dst.window=\t(%4d, %4d, %4d, %4d)\n",
+ this->dst.window.x, this->dst.window.y, this->dst.window.width,
+ this->dst.window.height);
+ b2r2_log_info("src.window=\t(%4d, %4d, %4d, %4d)\n",
+ this->src.window.x, this->src.window.y, this->src.window.width,
+ this->src.window.height);
+ b2r2_log_info("right_width=%d, bottom_height=%d\n", dst_right_width,
+ dst_bottom_height);
+
+ /* Update the rot_count and scale_count with all the "inner" tiles */
+ tile_rots = rot_node_count(this->dst.window.height,
+ this->dst.window.width);
+ rot_count = tile_rots * nbr_full_cols * nbr_full_rows;
+ scale_count = nbr_full_cols * nbr_full_rows;
+
+ b2r2_log_info("%s: inner=%d\n", __func__,
+ tile_rots);
+
+ /* Update with "right tile" rotations (one tile per row) */
+ if (dst_right_width) {
+ tile_rots = rot_node_count(dst_right_width, this->dst.window.width);
+ rot_count += tile_rots * nbr_full_rows;
+ scale_count += nbr_full_rows;
+
+ b2r2_log_info("%s: right=%d\n", __func__,
+ tile_rots);
+ }
+
+ /* Update with "bottom tile" rotations (one tile per col) */
+ if (dst_bottom_height) {
+ tile_rots = rot_node_count(this->dst.window.height,
+ dst_bottom_height);
+ rot_count += tile_rots * nbr_full_cols;
+ scale_count += nbr_full_cols;
+
+ b2r2_log_info("%s: bottom=%d\n", __func__,
+ tile_rots);
+ }
+
+ /* Update with "bottom right tile" rotations (ever only one tile) */
+ if (dst_right_width && dst_bottom_height) {
+ tile_rots = rot_node_count(dst_right_width, dst_bottom_height);
+ rot_count += tile_rots;
+ scale_count++;
+
+ b2r2_log_info("%s: bottom_right=%d\n", __func__,
+ tile_rots);
+ }
+
+ /* Finally calculate the total node count */
+ this->node_count = (scale_count + rot_count) * copy_count;
+
+ b2r2_log_info("%s: nbr_full_cols=%d, nbr_full_rows=%d\n",
+ __func__, nbr_full_cols, nbr_full_rows);
+
+ b2r2_log_info("%s: node_count=%d\n", __func__,
+ this->node_count);
+
+ return 0;
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+static int rot_node_count(s32 width, s32 height)
+{
+ u32 node_count;
+
+ node_count = width / B2R2_ROTATE_MAX_WIDTH;
+ if (width % B2R2_ROTATE_MAX_WIDTH)
+ node_count++;
+#ifdef B2R2_ROTATION_HEIGHT_BUGFIX
+ if ((height > 16) && (height % 16))
+ node_count *= 2;
+#endif
+
+ return node_count;
+}
+
+/**
+ * analyze_scaling() - analyze a rescale operation
+ */
+static int analyze_scaling(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count,
+ u32 *buf_count)
+{
+ int ret;
+ u32 copy_count;
+ u32 nbr_rows;
+ u32 nbr_cols;
+
+ pverbose(KERN_INFO LOG_TAG "::%s: Analyzing scaling...\n", __func__);
+
+ ret = analyze_scale_factors(this);
+ if (ret < 0)
+ goto error;
+
+ /* Find out how many nodes a simple copy would require */
+ ret = analyze_fmt_conv(this, req, &copy_count);
+ if (ret < 0)
+ goto error;
+
+
+ memcpy(&this->src.window, &this->src.rect, sizeof(this->src.window));
+ memcpy(&this->dst.window, &this->dst.rect, sizeof(this->dst.window));
+
+ this->src.window.width = MIN(this->src.window.width,
+ B2R2_RESCALE_MAX_WIDTH);
+ if (this->horiz_rescale)
+ this->dst.window.width = rescale(this->src.window.width,
+ this->horiz_sf);
+ else
+ this->dst.window.width = this->src.window.width;
+
+ /* Check if dest is a temp buffer */
+ if (*buf_count > 0) {
+ s32 old_width = this->dst.window.width;
+ s32 old_height = this->dst.window.height;
+
+ /* The operation will require one more node (to copy to tmp) */
+ copy_count++;
+
+ ret = setup_tmp_buf(&this->tmp_bufs[0], this->max_buf_size,
+ this->dst.fmt, this->dst.rect.width,
+ this->dst.rect.height);
+ if (ret < 0)
+ goto error;
+ this->work_bufs[0].size = this->tmp_bufs[0].pitch *
+ this->tmp_bufs[0].height;
+ this->tmp_bufs[0].tmp_buf_index = 1;
+
+ ret = constrain_window(&this->dst.window, this->tmp_bufs[0].fmt,
+ this->work_bufs[0].size);
+ if (ret < 0)
+ goto error;
+
+ /* The dimensions might have changed */
+ if (this->dst.window.width != old_width) {
+ if (this->horiz_rescale)
+ this->src.window.width =
+ inv_rescale(this->dst.window.width,
+ this->horiz_sf);
+ else
+ this->src.window.width =
+ this->dst.window.width;
+ }
+ if (this->dst.window.height != old_height) {
+ if (this->vert_rescale)
+ this->src.window.height =
+ inv_rescale(this->dst.window.height,
+ this->vert_sf);
+ else
+ this->src.window.height =
+ this->dst.window.height;
+ }
+ }
+
+ nbr_cols = this->src.rect.width / this->src.window.width;
+ if (this->src.rect.width % this->src.window.width)
+ nbr_cols++;
+
+ nbr_rows = this->src.rect.height / this->src.window.height;
+ if (this->src.rect.height % this->src.window.height)
+ nbr_rows++;
+
+ pverbose(KERN_INFO LOG_TAG "::%s: Each stripe will require %d nodes\n",
+ __func__, copy_count);
+
+ *node_count = copy_count * nbr_rows * nbr_cols;
+
+ this->type = B2R2_SCALE;
+
+ return 0;
+
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+
+}
+
+/**
+ * analyze_rotation() - analyze a rotate operation
+ */
+static int analyze_rotation(struct b2r2_node_split_job *this,
+ const struct b2r2_blt_request *req, u32 *node_count,
+ u32 *buf_count)
+{
+ int ret;
+
+ u32 copy_count;
+ u32 nbr_rows;
+ u32 nbr_cols;
+
+ pverbose(KERN_INFO LOG_TAG "::%s: Analyzing rotation...\n", __func__);
+
+ /* Find out how many nodes a simple copy would require */
+ ret = analyze_fmt_conv(this, req, &copy_count);
+ if (ret < 0)
+ goto error;
+
+ this->type = B2R2_ROTATE;
+
+ /* Blending cannot be combined with rotation */
+ if (this->blend)
+ this->buf_count = 1;
+
+ /* The vertical scan order of the destination must be flipped */
+ if (this->dst.vso == B2R2_TY_VSO_TOP_TO_BOTTOM) {
+ this->dst.rect.y += (this->dst.rect.height - 1);
+ this->dst.vso = B2R2_TY_VSO_BOTTOM_TO_TOP;
+ } else {
+ this->dst.rect.y -= (this->dst.rect.height - 1);
+ this->dst.vso = B2R2_TY_VSO_TOP_TO_BOTTOM;
+ }
+
+ memcpy(&this->src.window, &this->src.rect, sizeof(this->src.window));
+ memcpy(&this->dst.window, &this->dst.rect, sizeof(this->dst.window));
+
+ this->src.window.width = B2R2_ROTATE_MAX_WIDTH;
+
+ if (this->buf_count > 0) {
+ struct b2r2_node_split_buf *tmp = &this->tmp_bufs[0];
+
+ /* One more node to copy to the tmp buf */
+ copy_count++;
+
+ ret = setup_tmp_buf(tmp, this->max_buf_size, this->dst.fmt,
+ this->src.window.height, this->src.window.width);
+ if (ret < 0)
+ goto error;
+
+ this->work_bufs[0].size = tmp->pitch * tmp->height;
+ tmp->tmp_buf_index = 1;
+
+ /* The temporary buffer will be written bottom up */
+ tmp->vso = B2R2_TY_VSO_BOTTOM_TO_TOP;
+
+ if (this->src.window.width > tmp->rect.height)
+ this->src.window.width = tmp->rect.height;
+ if (this->src.window.height > tmp->rect.width)
+ this->src.window.height = tmp->rect.width;
+ }
+
+#ifdef B2R2_ROTATION_HEIGHT_BUGFIX
+ /*
+ * Because of a possible bug in the hardware, B2R2 cannot handle
+ * stripes that are not a multiple of 16 high. We need one extra node
+ * per stripe.
+ */
+ if ((this->src.window.height > 16) && (this->src.window.height % 16))
+ this->src.window.height -= this->src.window.height % 16;
+#endif
+
+ /* Set the size of the destination window */
+ this->dst.window.width = this->src.window.height;
+ this->dst.window.height = this->src.window.width;
+
+ /* Calculate how many rows and columns this will result in */
+ nbr_cols = this->src.rect.width / this->src.window.width;
+ if (this->src.rect.width % this->src.window.width)
+ nbr_cols++;
+
+ nbr_rows = this->src.rect.height / this->src.window.height;
+ if (this->src.rect.height % this->src.window.height)
+ nbr_rows++;
+
+ /* Finally, calculate the node count */
+ *node_count = copy_count * nbr_rows * nbr_cols;
+
+ return 0;
+
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * analyze_scale_factors() - determines the scale factors for the op
+ */
+static int analyze_scale_factors(struct b2r2_node_split_job *this)
+{
+ int ret;
+
+ u16 hsf;
+ u16 vsf;
+
+ if (this->rotation) {
+ ret = calculate_scale_factor(this->src.rect.width,
+ this->dst.rect.height, &hsf);
+ if (ret < 0)
+ goto error;
+
+ ret = calculate_scale_factor(this->src.rect.height,
+ this->dst.rect.width, &vsf);
+ if (ret < 0)
+ goto error;
+ } else {
+ ret = calculate_scale_factor(this->src.rect.width,
+ this->dst.rect.width, &hsf);
+ if (ret < 0)
+ goto error;
+
+ ret = calculate_scale_factor(this->src.rect.height,
+ this->dst.rect.height, &vsf);
+ if (ret < 0)
+ goto error;
+ }
+
+ this->horiz_rescale = hsf != (1 << 10);
+ this->vert_rescale = vsf != (1 << 10);
+
+ this->horiz_sf = hsf;
+ this->vert_sf = vsf;
+
+ return 0;
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * configure_tile() - configures one tile of a blit operation
+ */
+static int configure_tile(struct b2r2_node_split_job *this,
+ struct b2r2_node *node, struct b2r2_node **next)
+{
+ int ret;
+ struct b2r2_node *last;
+ struct b2r2_node_split_buf *src = &this->src;
+ struct b2r2_node_split_buf *dst = &this->dst;
+
+ /* Do the configuration depending on operation type */
+ switch (this->type) {
+ case B2R2_DIRECT_FILL:
+ configure_direct_fill(node, this->src.color, dst, &last);
+
+ break;
+ case B2R2_DIRECT_COPY:
+ configure_direct_copy(node, &this->src, dst, &last);
+
+ break;
+ case B2R2_FILL:
+ ret = configure_fill(node, this->src.color, this->src.fmt,
+ dst, this->ivmx, &last);
+ if (ret < 0)
+ goto error;
+
+ break;
+ case B2R2_FLIP: /* FLIP is just a copy with different VSO/HSO */
+ case B2R2_COPY:
+ if (this->buf_count > 0) {
+ /* First do a copy to the tmp buf */
+ configure_tmp_buf(&this->tmp_bufs[0], 1, &src->window);
+
+ ret = configure_copy(node, src, &this->tmp_bufs[0],
+ this->ivmx, &node, NULL);
+ if (ret < 0)
+ goto error;
+
+ /* Then set the source as the tmp buf */
+ src = &this->tmp_bufs[0];
+
+ /* We will not need the iVMX now */
+ this->ivmx = NULL;
+ }
+
+ ret = configure_copy(node, src, dst, this->ivmx, &last, this);
+ if (ret < 0)
+ goto error;
+
+ break;
+ case B2R2_ROTATE:
+ if (this->buf_count > 0) {
+ struct b2r2_node_split_buf *tmp = &this->tmp_bufs[0];
+
+ memcpy(&tmp->window, &dst->window, sizeof(tmp->window));
+
+ tmp->window.x = 0;
+ tmp->window.y = tmp->window.height - 1;
+
+ /* Rotate to the temp buf */
+ ret = configure_rotate(node, src, tmp, this->ivmx, &node, NULL);
+ if (ret < 0)
+ goto error;
+
+ /* Then do a copy to the destination */
+ ret = configure_copy(node, tmp, dst, NULL, &last, this);
+ if (ret < 0)
+ goto error;
+
+ } else {
+ /* Just do a rotation */
+ ret = configure_rotate(node, src, dst, this->ivmx, &last, this);
+ if (ret < 0)
+ goto error;
+
+ }
+
+ break;
+ case B2R2_SCALE:
+ if (this->buf_count > 0) {
+ /* Scaling will be done first */
+ configure_tmp_buf(&this->tmp_bufs[0], 1, &dst->window);
+
+ dst = &this->tmp_bufs[0];
+ }
+
+ ret = configure_scale(node, src, dst, this->horiz_sf, this->vert_sf,
+ this->ivmx, &last, this);
+ if (ret < 0)
+ goto error;
+
+ if (this->buf_count > 0) {
+ /* Then copy the tmp buf to the destination */
+ node = last;
+ src = dst;
+ dst = &this->dst;
+ ret = configure_copy(node, src, dst, NULL, &last, NULL);
+ if (ret < 0)
+ goto error;
+ }
+ break;
+ case B2R2_SCALE_AND_ROTATE:
+ ret = configure_rot_scale(this, node, &last);
+ if (ret < 0)
+ goto error;
+ break;
+ default:
+ b2r2_log_warn("%s: Unsupported request\n", __func__);
+ ret = -ENOSYS;
+ goto error;
+
+ break;
+ }
+
+ /* Scale and rotate will configure its own blending and clipping */
+ if (this->type != B2R2_SCALE_AND_ROTATE) {
+
+ /* Configure blending and clipping */
+ do {
+ if (node == NULL) {
+ b2r2_log_warn("%s: "
+ "Internal error! Out of nodes!\n",
+ __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ if (this->blend)
+ configure_blend(node, this->flags,
+ this->global_alpha,
+ this->swap_fg_bg);
+ if (this->clip)
+ configure_clip(node, &this->clip_rect);
+
+ node = node->next;
+
+ } while (node != last);
+ }
+
+ /* Consume the nodes */
+ *next = last;
+
+ return 0;
+
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * configure_rot_scale() - configures a combined rotation and scaling op
+ */
+static int configure_rot_scale(struct b2r2_node_split_job *this,
+ struct b2r2_node *node, struct b2r2_node **next)
+{
+ int ret;
+
+ bool last_row;
+ bool last_col;
+
+ struct b2r2_node *rot_start;
+ struct b2r2_node *last;
+
+ struct b2r2_node_split_buf *tmp = &this->tmp_bufs[0];
+ struct b2r2_blt_rect dst_win;
+
+ if (node == NULL) {
+ b2r2_log_warn("%s: Out of nodes!\n",
+ __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ memcpy(&dst_win, &this->dst.window, sizeof(dst_win));
+
+ tmp->rect.x = 0;
+ tmp->rect.y = 0;
+ tmp->rect.width = this->dst.window.height;
+ tmp->rect.height = this->dst.window.width;
+
+ memcpy(&tmp->window, &tmp->rect, sizeof(tmp->window));
+ b2r2_log_info("%s:Rot rescale:\n", __func__);
+ b2r2_log_info("%s:\tsrc=(%4d, %4d, %4d, %4d)\t"
+ "tmp=(%4d, %4d, %4d, %4d)\n", __func__, this->src.window.x,
+ this->src.window.y, this->src.window.width,
+ this->src.window.height, tmp->window.x, tmp->window.y,
+ tmp->window.width, tmp->window.height);
+
+ configure_scale(node, &this->src, tmp, this->horiz_sf,
+ this->vert_sf, this->ivmx, &node, this);
+
+ tmp->window.width = MIN(tmp->rect.width, B2R2_ROTATE_MAX_WIDTH);
+#ifdef B2R2_ROTATION_HEIGHT_BUGFIX
+ if ((tmp->window.height > 16) && (tmp->window.height % 16))
+ tmp->window.height -= tmp->window.height % 16;
+#endif
+
+ tmp->dx = tmp->window.width;
+ tmp->dy = tmp->window.height;
+
+ this->dst.window.width = tmp->window.height;
+ this->dst.window.height = tmp->window.width;
+
+ rot_start = node;
+
+ b2r2_log_info("%s: tmp_rect=(%d, %d, %d, %d)\n", __func__,
+ tmp->rect.x, tmp->rect.y, tmp->rect.width, tmp->rect.height);
+ do {
+
+ last_col = tmp->window.x + tmp->dx >= tmp->rect.width;
+ last_row = tmp->window.y + tmp->dy >= tmp->rect.height;
+
+ if (node == NULL) {
+ b2r2_log_warn("%s: Out of nodes!\n",
+ __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ if (last_col) {
+ tmp->window.width = tmp->rect.width - tmp->window.x;
+ this->dst.window.height = tmp->window.width;
+ }
+
+ if (last_row) {
+ tmp->window.height = tmp->rect.height - tmp->window.y;
+ this->dst.window.width = tmp->window.height;
+ }
+
+ b2r2_log_info("%s: \ttmp=(%4d, %4d, %4d, %4d) "
+ "\tdst=(%4d, %4d, %4d, %4d)\n", __func__, tmp->window.x,
+ tmp->window.y, tmp->window.width, tmp->window.height,
+ this->dst.window.x, this->dst.window.y,
+ this->dst.window.width, this->dst.window.height);
+
+ configure_rotate(node, tmp, &this->dst, NULL, &last, NULL);
+
+ tmp->window.x += tmp->dx;
+ this->dst.window.y -= tmp->dx;
+
+ /* Slide vertically if we reached the end of the row */
+ if (last_col) {
+ tmp->window.x = 0;
+ tmp->window.y += tmp->dy;
+ this->dst.window.x += tmp->dy;
+ this->dst.window.y = dst_win.y;
+ }
+
+ /* Consume the nodes */
+ node = last;
+
+ } while (!(last_row && last_col));
+
+
+
+ /* Configure blending and clipping for the rotation nodes */
+ node = rot_start;
+ b2r2_log_info("%s: "
+ "Configuring clipping and blending. rot_start=%p, last=%p\n",
+ __func__, rot_start, last);
+ do {
+ if (node == NULL) {
+ b2r2_log_warn("%s: Out of nodes!\n",
+ __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ if (this->blend) {
+ configure_blend(node, this->flags,
+ this->global_alpha, false);
+ }
+ if (this->clip)
+ configure_clip(node, &this->clip_rect);
+
+ node = node->next;
+ } while (node != last);
+
+ memcpy(&this->dst.window, &dst_win, sizeof(this->dst.window));
+
+ *next = node;
+
+ return 0;
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * configure_direct_fill() - configures the given node for direct fill
+ *
+ * @node - the node to configure
+ * @color - the fill color
+ * @dst - the destination buffer
+ * @next - the next empty node in the node list
+ *
+ * This operation will always consume one node only.
+ */
+static void configure_direct_fill(struct b2r2_node *node, u32 color,
+ struct b2r2_node_split_buf *dst, struct b2r2_node **next)
+{
+ PTRACE_ENTRY();
+
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_COLOR_FILL | B2R2_CIC_SOURCE_1;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_1_DIRECT_FILL;
+
+ /* Target setup */
+ set_target(node, dst->addr, dst);
+
+ /* Source setup */
+
+ /* It seems B2R2 checks so that source and dest has the same format */
+ node->node.GROUP3.B2R2_STY = to_native_fmt(dst->fmt);
+ node->node.GROUP2.B2R2_S1CF = color;
+ node->node.GROUP2.B2R2_S2CF = 0;
+
+ /* Consume the node */
+ *next = node->next;
+}
+
+/**
+ * configure_direct_copy() - configures the node for direct copy
+ *
+ * @node - the node to configure
+ * @src - the source buffer
+ * @dst - the destination buffer
+ * @next - the next empty node in the node list
+ *
+ * This operation will always consume one node only.
+ */
+static void configure_direct_copy(struct b2r2_node *node,
+ struct b2r2_node_split_buf *src,
+ struct b2r2_node_split_buf *dst, struct b2r2_node **next)
+{
+ PTRACE_ENTRY();
+
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_1;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_1_DIRECT_COPY;
+
+ /* Source setup, use the base function to avoid altering the INS */
+ set_src(&node->node.GROUP3, src->addr, src);
+
+ /* Target setup */
+ set_target(node, dst->addr, dst);
+
+ /* Consume the node */
+ *next = node->next;
+}
+
+/**
+ * configure_fill() - configures the given node for color fill
+ *
+ * @node - the node to configure
+ * @color - the fill color
+ * @fmt - the source color format
+ * @dst - the destination buffer
+ * @next - the next empty node in the node list
+ *
+ * A normal fill operation can be combined with any other per pixel operations
+ * such as blend.
+ *
+ * This operation will consume as many nodes as are required to write to the
+ * destination format.
+ */
+static int configure_fill(struct b2r2_node *node, u32 color,
+ enum b2r2_blt_fmt fmt, struct b2r2_node_split_buf *dst,
+ const u32 *ivmx, struct b2r2_node **next)
+{
+ int ret;
+ struct b2r2_node *last;
+
+ PTRACE_ENTRY();
+
+ /* Configure the destination */
+ ret = configure_dst(node, dst, ivmx, &last);
+ if (ret < 0)
+ goto error;
+
+ do {
+ if (node == NULL) {
+ b2r2_log_warn("%s: "
+ "Internal error! Out of nodes!\n", __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2 |
+ B2R2_CIC_COLOR_FILL;
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_SOURCE_2_COLOR_FILL_REGISTER;
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3;
+
+ /* B2R2 has a bug that disables color fill from S2. As a
+ workaround we use S1 for the color. */
+ node->node.GROUP2.B2R2_S1CF = 0;
+ node->node.GROUP2.B2R2_S2CF = color;
+
+ /* TO BE REMOVED: */
+ set_src_2(node, dst->addr, dst);
+ node->node.GROUP4.B2R2_STY = to_native_fmt(fmt);
+
+ /* Setup the iVMX for color conversion */
+ if (ivmx != NULL)
+ set_ivmx(node, ivmx);
+
+ if ((dst->type == B2R2_FMT_TYPE_PLANAR) ||
+ (dst->type == B2R2_FMT_TYPE_SEMI_PLANAR)) {
+
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_RESCALE2D_ENABLED;
+ node->node.GROUP8.B2R2_FCTL =
+ B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER |
+ B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_RESIZER;
+ node->node.GROUP9.B2R2_RSF =
+ (1 << (B2R2_RSF_HSRC_INC_SHIFT + 10)) |
+ (1 << (B2R2_RSF_VSRC_INC_SHIFT + 10));
+ node->node.GROUP9.B2R2_RZI =
+ B2R2_RZI_DEFAULT_HNB_REPEAT |
+ B2R2_RZI_DEFAULT_VNB_REPEAT;
+
+ node->node.GROUP10.B2R2_RSF =
+ (1 << (B2R2_RSF_HSRC_INC_SHIFT + 10)) |
+ (1 << (B2R2_RSF_VSRC_INC_SHIFT + 10));
+ node->node.GROUP10.B2R2_RZI =
+ B2R2_RZI_DEFAULT_HNB_REPEAT |
+ B2R2_RZI_DEFAULT_VNB_REPEAT;
+ }
+
+ node = node->next;
+
+ } while (node != last);
+
+ /* Consume the nodes */
+ *next = node;
+
+ return 0;
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * configure_copy() - configures the given node for a copy operation
+ *
+ * @node - the node to configure
+ * @src - the source buffer
+ * @dst - the destination buffer
+ * @ivmx - the iVMX to use for color conversion
+ * @next - the next empty node in the node list
+ *
+ * This operation will consume as many nodes as are required to write to the
+ * destination format.
+ */
+static int configure_copy(struct b2r2_node *node,
+ struct b2r2_node_split_buf *src,
+ struct b2r2_node_split_buf *dst, const u32 *ivmx,
+ struct b2r2_node **next,
+ struct b2r2_node_split_job *this)
+{
+ int ret;
+
+ struct b2r2_node *last;
+
+ PTRACE_ENTRY();
+
+ pverbose(KERN_INFO LOG_TAG "::%s:\n", __func__);
+ pverbose(KERN_INFO "\tsrc=(%4d, %4d, %4d, %4d)\n"
+ "\tdst=(%4d, %4d, %4d, %4d)\n", src->window.x,
+ src->window.y, src->window.width, src->window.height,
+ dst->window.x, dst->window.y, dst->window.width,
+ dst->window.height);
+
+ ret = configure_dst(node, dst, ivmx, &last);
+ if (ret < 0)
+ goto error;
+
+ /* Configure the source for each node */
+ do {
+ if (node == NULL) {
+ b2r2_log_warn("%s: "
+ " Internal error! Out of nodes!\n", __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3;
+ if (this != NULL &&
+ (this->flags & B2R2_BLT_FLAG_SOURCE_COLOR_KEY) != 0) {
+ u32 key_color = 0;
+
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_CKEY_SEL_SRC_AFTER_CLUT |
+ B2R2_ACK_CKEY_RED_MATCH_IF_BETWEEN |
+ B2R2_ACK_CKEY_GREEN_MATCH_IF_BETWEEN |
+ B2R2_ACK_CKEY_BLUE_MATCH_IF_BETWEEN;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_CKEY_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_COLOR_KEY;
+
+ key_color = to_RGB888(this->flag_param, src->fmt);
+ node->node.GROUP12.B2R2_KEY1 = key_color;
+ node->node.GROUP12.B2R2_KEY2 = key_color;
+ }
+
+ if (this != NULL &&
+ (this->flags & B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) != 0) {
+ struct b2r2_blt_request *request =
+ container_of(this, struct b2r2_blt_request,
+ node_split_job);
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_CLUTOP_ENABLED;
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_CLUT;
+ node->node.GROUP7.B2R2_CCO = B2R2_CCO_CLUT_COLOR_CORRECTION |
+ B2R2_CCO_CLUT_UPDATE;
+ node->node.GROUP7.B2R2_CML = request->clut_phys_addr;
+ }
+ /* Configure the source(s) */
+ configure_src(node, src, ivmx);
+
+ node = node->next;
+ } while (node != last);
+
+ /* Consume the nodes */
+ *next = node;
+
+ return 0;
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * configure_rotate() - configures the given node for rotation
+ *
+ * @node - the node to configure
+ * @src - the source buffer
+ * @dst - the destination buffer
+ * @ivmx - the iVMX to use for color conversion
+ * @next - the next empty node in the node list
+ *
+ * This operation will consume as many nodes are are required by the combination
+ * of rotating and writing the destination format.
+ */
+static int configure_rotate(struct b2r2_node *node,
+ struct b2r2_node_split_buf *src,
+ struct b2r2_node_split_buf *dst, const u32 *ivmx,
+ struct b2r2_node **next,
+ struct b2r2_node_split_job *this)
+{
+ int ret;
+
+ struct b2r2_node *last;
+
+ ret = configure_copy(node, src, dst, ivmx, &last, this);
+ if (ret < 0)
+ goto error;
+
+ do {
+ if (node == NULL) {
+ b2r2_log_warn("%s: "
+ "Internal error! Out of nodes!\n", __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_ROTATION_ENABLED;
+
+ node = node->next;
+
+ } while (node != last);
+
+ /* Consume the nodes */
+ *next = node;
+
+ return 0;
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * configure_scale() - configures the given node for scaling
+ *
+ * @node - the node to configure
+ * @src - the source buffer
+ * @dst - the destination buffer
+ * @h_rsf - the horizontal rescale factor
+ * @v_rsf - the vertical rescale factor
+ * @ivmx - the iVMX to use for color conversion
+ * @next - the next empty node in the node list
+ */
+static int configure_scale(struct b2r2_node *node,
+ struct b2r2_node_split_buf *src,
+ struct b2r2_node_split_buf *dst, u16 h_rsf, u16 v_rsf,
+ const u32 *ivmx, struct b2r2_node **next,
+ struct b2r2_node_split_job *this)
+{
+ int ret;
+
+ struct b2r2_node *last;
+
+ u32 fctl = 0;
+ u32 rsf = 0;
+ u32 rzi = 0;
+
+ struct b2r2_filter_spec *hf;
+ struct b2r2_filter_spec *vf;
+
+ hf = b2r2_filter_find(h_rsf);
+ vf = b2r2_filter_find(v_rsf);
+
+ b2r2_log_info("%s:\n"
+ "\t\tsrc=(%4d, %4d, %4d, %4d)\tdst=(%4d, %4d, %4d, %4d)\n",
+ __func__, src->window.x, src->window.y, src->window.width,
+ src->window.height, dst->window.x, dst->window.y,
+ dst->window.width, dst->window.height);
+
+ /* Configure horizontal rescale */
+ fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER |
+ B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_RESIZER;
+ rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT);
+ rsf |= h_rsf << B2R2_RSF_HSRC_INC_SHIFT;
+ rzi |= B2R2_RZI_DEFAULT_HNB_REPEAT;
+
+ /* Configure vertical rescale */
+ fctl |= B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER |
+ B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_RESIZER;
+ rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT);
+ rsf |= v_rsf << B2R2_RSF_VSRC_INC_SHIFT;
+ rzi |= B2R2_RZI_DEFAULT_VNB_REPEAT;
+
+ ret = configure_copy(node, src, dst, ivmx, &last, this);
+ if (ret < 0)
+ goto error;
+
+ do {
+ if (node == NULL) {
+ b2r2_log_warn("%s: "
+ "Internal error! Out of nodes!\n", __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_FILTER_CONTROL |
+ B2R2_CIC_RESIZE_LUMA |
+ B2R2_CIC_RESIZE_CHROMA;
+ node->node.GROUP0.B2R2_INS |=
+ B2R2_INS_RESCALE2D_ENABLED;
+
+ /* Set the filter control and rescale registers */
+ node->node.GROUP8.B2R2_FCTL |= fctl;
+ if ((src->type == B2R2_FMT_TYPE_SEMI_PLANAR) ||
+ (src->type == B2R2_FMT_TYPE_PLANAR)) {
+ u16 chroma_vsf = v_rsf;
+ u16 chroma_hsf = h_rsf;
+
+ struct b2r2_filter_spec *luma_hf = hf;
+ struct b2r2_filter_spec *luma_vf = vf;
+
+ if ((dst->type != B2R2_FMT_TYPE_SEMI_PLANAR) &&
+ (dst->type != B2R2_FMT_TYPE_PLANAR))
+ chroma_hsf = h_rsf / 2;
+
+ /* YUV420 needs to be vertically upsampled */
+ if (is_yuv420_fmt(src->fmt)) {
+ if (!is_yuv420_fmt(dst->fmt))
+ chroma_vsf /= 2;
+ } else if (is_yuv420_fmt(dst->fmt)) {
+ if (!is_yuv420_fmt(src->fmt))
+ chroma_vsf *= 2;
+ }
+
+ node->node.GROUP9.B2R2_RSF =
+ chroma_hsf << B2R2_RSF_HSRC_INC_SHIFT |
+ chroma_vsf << B2R2_RSF_VSRC_INC_SHIFT;
+
+ /* Find new filters for the chroma scale factor */
+ hf = b2r2_filter_find(chroma_hsf);
+ vf = b2r2_filter_find(chroma_vsf);
+
+ /* Set the Luma rescale registers as well */
+ node->node.GROUP10.B2R2_RSF |= rsf;
+ node->node.GROUP10.B2R2_RZI |= rzi;
+
+
+ if (luma_hf) {
+ node->node.GROUP8.B2R2_FCTL |=
+ B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_FILTER;
+ node->node.GROUP10.B2R2_HFP =
+ luma_hf->h_coeffs_phys_addr;
+ }
+
+ if (luma_vf) {
+ node->node.GROUP8.B2R2_FCTL |=
+ B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_FILTER;
+ node->node.GROUP10.B2R2_VFP =
+ luma_vf->v_coeffs_phys_addr;
+ }
+
+ } else {
+ if ((node->node.GROUP1.B2R2_TTY & B2R2_TTY_CHROMA_NOT_LUMA) != 0) {
+ u32 chroma_rsf = (h_rsf << 1) << B2R2_RSF_HSRC_INC_SHIFT;
+ if (is_yuv420_fmt(dst->fmt)) {
+ chroma_rsf |= (v_rsf << 1) << B2R2_RSF_VSRC_INC_SHIFT;
+ } else {
+ chroma_rsf |= v_rsf << B2R2_RSF_VSRC_INC_SHIFT;
+ }
+ node->node.GROUP9.B2R2_RSF = chroma_rsf;
+ } else {
+ node->node.GROUP9.B2R2_RSF = rsf;
+ }
+ }
+
+
+ if (hf) {
+ node->node.GROUP8.B2R2_FCTL |=
+ B2R2_FCTL_HF2D_MODE_ENABLE_COLOR_CHANNEL_FILTER;
+ node->node.GROUP9.B2R2_HFP =
+ hf->h_coeffs_phys_addr;
+ }
+
+ if (vf) {
+ node->node.GROUP8.B2R2_FCTL |=
+ B2R2_FCTL_VF2D_MODE_ENABLE_COLOR_CHANNEL_FILTER;
+ node->node.GROUP9.B2R2_VFP =
+ vf->v_coeffs_phys_addr;
+ }
+
+ node->node.GROUP9.B2R2_RZI |= rzi;
+
+ node = node->next;
+
+ } while (node != last);
+
+ /* Consume the nodes */
+ *next = node;
+
+ return 0;
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * configure_src() - configures the source registers and the iVMX
+ *
+ * @node - the node to configure
+ * @src - the source buffer
+ * @ivmx - the iVMX to use for color conversion
+ *
+ * This operation will not consume any nodes
+ */
+static void configure_src(struct b2r2_node *node,
+ struct b2r2_node_split_buf *src, const u32 *ivmx)
+{
+ struct b2r2_node_split_buf tmp_buf;
+
+ PTRACE_ENTRY();
+
+ /* Configure S1 - S3 */
+ switch (src->type) {
+ case B2R2_FMT_TYPE_RASTER:
+ set_src_2(node, src->addr, src);
+ break;
+ case B2R2_FMT_TYPE_SEMI_PLANAR:
+ memcpy(&tmp_buf, src, sizeof(tmp_buf));
+
+ /* Horizontal resolution is half */
+ tmp_buf.window.x >>= 1;
+ tmp_buf.window.width >>= 1;
+
+ /* If the buffer is in YUV420 format, the vertical resolution
+ is half as well */
+ if (is_yuv420_fmt(src->fmt)) {
+ tmp_buf.window.height >>= 1;
+ tmp_buf.window.y >>= 1;
+ }
+
+ set_src_3(node, src->addr, src);
+ set_src_2(node, tmp_buf.chroma_addr, &tmp_buf);
+ break;
+ case B2R2_FMT_TYPE_PLANAR:
+ memcpy(&tmp_buf, src, sizeof(tmp_buf));
+
+ /* Each chroma buffer will have half as many values per line as
+ the luma buffer */
+ tmp_buf.pitch >>= 1;
+
+ /* Horizontal resolution is half */
+ tmp_buf.window.x >>= 1;
+ tmp_buf.window.width >>= 1;
+
+ /* If the buffer is in YUV420 format, the vertical resolution
+ is half as well */
+ if (is_yuv420_fmt(src->fmt)) {
+ tmp_buf.window.height >>= 1;
+ tmp_buf.window.y >>= 1;
+ }
+
+ set_src_3(node, src->addr, src); /* Y */
+ set_src_2(node, tmp_buf.chroma_addr, &tmp_buf); /* U */
+ set_src_1(node, tmp_buf.chroma_cr_addr, &tmp_buf); /* V */
+
+ break;
+ default:
+ /* Should never, ever happen */
+ BUG_ON(1);
+ break;
+ }
+
+ /* Configure the iVMX for color space conversions */
+ if (ivmx != NULL)
+ set_ivmx(node, ivmx);
+}
+
+/**
+ * configure_dst() - configures the destination registers of the given node
+ *
+ * @node - the node to configure
+ * @ivmx - the iVMX to use for color conversion
+ * @dst - the destination buffer
+ *
+ * This operation will consume as many nodes as are required to write the
+ * destination format.
+ */
+static int configure_dst(struct b2r2_node *node,
+ struct b2r2_node_split_buf *dst, const u32 *ivmx,
+ struct b2r2_node **next)
+{
+ int ret;
+ int nbr_planes = 1;
+ int i;
+
+ struct b2r2_node_split_buf dst_planes[3];
+
+ PTRACE_ENTRY();
+
+ memcpy(&dst_planes[0], dst, sizeof(dst_planes[0]));
+
+ if (dst->type != B2R2_FMT_TYPE_RASTER) {
+ /* There will be at least 2 planes */
+ nbr_planes = 2;
+
+ memcpy(&dst_planes[1], dst, sizeof(dst_planes[1]));
+
+ dst_planes[1].addr = dst->chroma_addr;
+ dst_planes[1].plane_selection = B2R2_TTY_CHROMA_NOT_LUMA;
+
+ /* Horizontal resolution is half */
+ dst_planes[1].window.x >>= 1;
+ /*
+ * Must round up the chroma size to handle cases when luma size is not
+ * divisible by 2. E.g. luma width==7 requires chroma width==4.
+ * Chroma width==7/2==3 is only enough for luma width==6.
+ */
+ dst_planes[1].window.width = (dst_planes[1].window.width + 1) >> 1;
+
+ /*
+ * If the buffer is in YUV420 format, the vertical resolution
+ * is half as well. Height must be rounded in the same way
+ * as is done for width.
+ */
+ if (is_yuv420_fmt(dst->fmt)) {
+ dst_planes[1].window.y >>= 1;
+ dst_planes[1].window.height =
+ (dst_planes[1].window.height + 1) >> 1;
+ }
+
+ if (dst->type == B2R2_FMT_TYPE_PLANAR) {
+ /* There will be a third plane as well */
+ nbr_planes = 3;
+
+ /* The chroma planes have half the luma pitch */
+ dst_planes[1].pitch >>= 1;
+
+ memcpy(&dst_planes[2], &dst_planes[1],
+ sizeof(dst_planes[2]));
+ dst_planes[2].addr = dst->chroma_cr_addr;
+
+ /*
+ * The third plane will be Cr.
+ * The flag B2R2_TTY_CB_NOT_CR actually works
+ * the other way around, i.e. as if it was
+ * B2R2_TTY_CR_NOT_CB.
+ */
+ dst_planes[2].chroma_selection = B2R2_TTY_CB_NOT_CR;
+ }
+
+ }
+
+ /* Configure one node for each plane */
+ for (i = 0; i < nbr_planes; i++) {
+
+ if (node == NULL) {
+ b2r2_log_warn("%s: "
+ "Internal error! Out of nodes!\n", __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ set_target(node, dst_planes[i].addr, &dst_planes[i]);
+
+ node = node->next;
+ }
+
+ pverbose(KERN_INFO LOG_TAG "::%s: %d nodes consumed\n", __func__,
+ nbr_planes);
+
+ /* Consume the nodes */
+ *next = node;
+
+ return 0;
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+
+}
+
+/**
+ * configure_blend() - configures the given node for alpha blending
+ *
+ * @node - the node to configure
+ * @flags - the flags passed in the blt_request
+ * @global_alpha - the global alpha to use (if enabled in flags)
+ * @swap_fg_bg - if true, fg will be on s1 instead of s2
+ *
+ * This operation will not consume any nodes.
+ *
+ * NOTE: This method should be called _AFTER_ the destination has been
+ * configured.
+ *
+ * WARNING: Take care when using this with semi-planar or planar sources since
+ * either S1 or S2 will be overwritten!
+ */
+static void configure_blend(struct b2r2_node *node, u32 flags, u32 global_alpha,
+ bool swap_fg_bg)
+{
+ PTRACE_ENTRY();
+
+ node->node.GROUP0.B2R2_ACK &= ~(B2R2_ACK_MODE_BYPASS_S2_S3);
+
+ /* Check if the foreground is premultiplied */
+ if ((flags & B2R2_BLT_FLAG_SRC_IS_NOT_PREMULT) != 0)
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BLEND_NOT_PREMULT;
+ else
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BLEND_PREMULT;
+
+
+ /* Check if global alpha blend should be enabled */
+ if ((flags & B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND) != 0) {
+
+ /* B2R2 expects the global alpha to be in 0...128 range */
+ global_alpha = (global_alpha*128)/255;
+
+ node->node.GROUP0.B2R2_ACK |=
+ global_alpha << B2R2_ACK_GALPHA_ROPID_SHIFT;
+ } else {
+ node->node.GROUP0.B2R2_ACK |=
+ (128 << B2R2_ACK_GALPHA_ROPID_SHIFT);
+ }
+
+ /* Copy the destination config to the appropriate source and clear any
+ clashing flags */
+ if (swap_fg_bg) {
+ /* S1 will be foreground, S2 background */
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_2_FETCH_FROM_MEM;
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_SWAP_FG_BG;
+
+ node->node.GROUP4.B2R2_SBA = node->node.GROUP1.B2R2_TBA;
+ node->node.GROUP4.B2R2_STY = node->node.GROUP1.B2R2_TTY;
+ node->node.GROUP4.B2R2_SXY = node->node.GROUP1.B2R2_TXY;
+ node->node.GROUP4.B2R2_SSZ = node->node.GROUP1.B2R2_TSZ;
+
+ node->node.GROUP4.B2R2_STY &= ~(B2R2_S2TY_A1_SUBST_KEY_MODE |
+ B2R2_S2TY_CHROMA_LEFT_EXT_AVERAGE);
+ } else {
+ /* S1 will be background, S2 foreground */
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_1;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_1_FETCH_FROM_MEM;
+
+ node->node.GROUP3.B2R2_SBA = node->node.GROUP1.B2R2_TBA;
+ node->node.GROUP3.B2R2_STY |= node->node.GROUP1.B2R2_TTY;
+ node->node.GROUP3.B2R2_SXY = node->node.GROUP1.B2R2_TXY;
+
+ node->node.GROUP3.B2R2_STY &= ~(B2R2_S1TY_A1_SUBST_KEY_MODE);
+
+ }
+}
+
+/**
+ * configure_clip() - configures destination clipping for the given node
+ *
+ * @node - the node to configure
+ * @clip_rect - the clip rectangle
+ *
+ * This operation does not consume any nodes.
+ */
+static void configure_clip(struct b2r2_node *node,
+ struct b2r2_blt_rect *clip_rect)
+{
+ s32 l = clip_rect->x;
+ s32 r = clip_rect->x + clip_rect->width - 1;
+ s32 t = clip_rect->y;
+ s32 b = clip_rect->y + clip_rect->height - 1;
+
+ PTRACE_ENTRY();
+
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_CLIP_WINDOW;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_RECT_CLIP_ENABLED;
+
+ /* Clip window setup */
+ node->node.GROUP6.B2R2_CWO =
+ ((t & 0x7FFF) << B2R2_CWO_Y_SHIFT) |
+ ((l & 0x7FFF) << B2R2_CWO_X_SHIFT);
+ node->node.GROUP6.B2R2_CWS =
+ ((b & 0x7FFF) << B2R2_CWO_Y_SHIFT) |
+ ((r & 0x7FFF) << B2R2_CWO_X_SHIFT);
+}
+
+/**
+ * configure_tmp_buf() - configures a temporary buffer
+ */
+static void configure_tmp_buf(struct b2r2_node_split_buf *this, int index,
+ struct b2r2_blt_rect *window)
+{
+ memcpy(&this->window, window, sizeof(this->window));
+
+ this->pitch = fmt_byte_pitch(this->fmt, this->window.width);
+ this->width = this->window.width;
+ this->height = this->window.height;
+ this->tmp_buf_index = index;
+
+ /* Temporary buffers rects are always positioned in origo */
+ this->window.x = 0;
+ this->window.y = 0;
+}
+
+/**
+ * set_buf() - configures the given buffer with the provided values
+ *
+ * @addr - the physical base address
+ * @img - the blt image to base the buffer on
+ * @rect - the rectangle to use
+ * @color_fill - determines whether the buffer should be used for color fill
+ * @color - the color to use in case of color fill
+ */
+static void set_buf(struct b2r2_node_split_buf *buf, u32 addr,
+ const struct b2r2_blt_img *img,
+ const struct b2r2_blt_rect *rect, bool color_fill, u32 color)
+{
+ memset(buf, 0, sizeof(*buf));
+
+ buf->fmt = img->fmt;
+ buf->type = get_fmt_type(img->fmt);
+
+ if (color_fill) {
+ buf->type = B2R2_FMT_TYPE_RASTER;
+ buf->color = color;
+ } else {
+ buf->addr = addr;
+
+ buf->alpha_range = get_alpha_range(img->fmt);
+
+ if (img->pitch == 0)
+ buf->pitch = fmt_byte_pitch(img->fmt, img->width);
+ else
+ buf->pitch = img->pitch;
+
+ buf->height = img->height;
+ buf->width = img->width;
+
+ switch (buf->type) {
+ case B2R2_FMT_TYPE_SEMI_PLANAR:
+ buf->chroma_addr = (u32)(((u8 *)addr) +
+ buf->pitch * buf->height);
+ break;
+ case B2R2_FMT_TYPE_PLANAR:
+ buf->chroma_addr = (u32)(((u8 *)addr) +
+ buf->pitch * buf->height);
+ if (is_yuv420_fmt(buf->fmt)) {
+ /*
+ * Use ceil(height/2) in case
+ * buffer height is not divisible by 2.
+ */
+ buf->chroma_cr_addr = (u32)(((u8 *)buf->chroma_addr) +
+ (buf->pitch >> 1) * ((buf->height + 1) >> 1));
+ } else {
+ buf->chroma_cr_addr = (u32)(((u8 *)buf->chroma_addr) +
+ (buf->pitch >> 1) * buf->height);
+ }
+ break;
+ default:
+ break;
+ }
+
+ memcpy(&buf->rect, rect, sizeof(buf->rect));
+ }
+}
+
+/**
+ * constrain_window() - resizes a window to fit the given size restraints
+ *
+ * NOTE: Width will be kept constant.
+ */
+static int constrain_window(struct b2r2_blt_rect *window,
+ enum b2r2_blt_fmt fmt, u32 max_size)
+{
+ int ret;
+
+ u32 current_size;
+ u32 pitch;
+
+ pitch = fmt_byte_pitch(fmt, window->width);
+ current_size = pitch * window->height;
+
+ if (current_size > max_size) {
+ window->width = MIN(window->width, B2R2_RESCALE_MAX_WIDTH);
+ pitch = fmt_byte_pitch(fmt, window->width);
+ window->height = MIN(window->height, max_size / pitch);
+
+ if (window->height == 0) {
+ b2r2_log_warn("%s: Not enough tmp mem\n",
+ __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+ }
+
+ return 0;
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * setup_tmp_buf() - configure a temporary buffer
+ */
+static int setup_tmp_buf(struct b2r2_node_split_buf *tmp, u32 max_size,
+ enum b2r2_blt_fmt pref_fmt, u32 pref_width, u32 pref_height)
+{
+ int ret;
+
+ enum b2r2_blt_fmt fmt;
+
+ u32 width;
+ u32 height;
+ u32 pitch;
+ u32 size;
+
+ /* Determine what format we should use for the tmp buf */
+ if (is_rgb_fmt(pref_fmt)) {
+ fmt = B2R2_BLT_FMT_32_BIT_ARGB8888;
+ } else if (is_bgr_fmt(pref_fmt)) {
+ fmt = B2R2_BLT_FMT_32_BIT_ABGR8888;
+ } else if (is_yuv_fmt(pref_fmt)) {
+ fmt = B2R2_BLT_FMT_32_BIT_AYUV8888;
+ } else {
+ /* Wait, what? */
+ b2r2_log_warn("%s: "
+ "Cannot create tmp buf from this fmt (%d)\n", __func__,
+ pref_fmt);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* See if we can fit the entire preferred rectangle */
+ width = pref_width;
+ height = pref_height;
+ pitch = fmt_byte_pitch(fmt, width);
+ size = pitch * height;
+
+ if (size > max_size) {
+ /* We need to limit the size, so we choose a different width */
+ width = MIN(width, B2R2_RESCALE_MAX_WIDTH);
+ pitch = fmt_byte_pitch(fmt, width);
+ height = MIN(height, max_size / pitch);
+ size = pitch * height;
+ }
+
+ /* We should at least have enough room for one scanline */
+ if (height == 0) {
+ b2r2_log_warn("%s: Not enough tmp mem!\n",
+ __func__);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ memset(tmp, 0, sizeof(*tmp));
+
+ tmp->fmt = fmt;
+ tmp->type = B2R2_FMT_TYPE_RASTER;
+ tmp->height = height;
+ tmp->width = width;
+ tmp->pitch = pitch;
+
+ tmp->rect.width = width;
+ tmp->rect.height = tmp->height;
+ tmp->alpha_range = B2R2_TY_ALPHA_RANGE_255;
+
+ return 0;
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+
+}
+
+/**
+ * get_alpha_range() - returns the alpha range of the given format
+ */
+static enum b2r2_ty get_alpha_range(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ case B2R2_BLT_FMT_8_BIT_A8:
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ return B2R2_TY_ALPHA_RANGE_255; /* 0 - 255 */
+ default:
+ return B2R2_TY_ALPHA_RANGE_128; /* 0 - 128 */
+ }
+}
+
+/**
+ * get_alpha() - returns the pixel alpha in 0...255 range
+ */
+static u8 get_alpha(enum b2r2_blt_fmt fmt, u32 pixel)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ return (pixel >> 24) & 0xff;
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ return (pixel & 0xfff) >> 16;
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ return (((pixel >> 12) & 0xf) * 255) / 15;
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ return (pixel >> 15) * 255;
+ case B2R2_BLT_FMT_1_BIT_A1:
+ return pixel * 255;
+ case B2R2_BLT_FMT_8_BIT_A8:
+ return pixel;
+ default:
+ return 255;
+ }
+}
+
+/**
+ * set_alpha() - returns a color value with the alpha component set
+ */
+static u32 set_alpha(enum b2r2_blt_fmt fmt, u8 alpha, u32 color)
+{
+ u32 alpha_mask;
+
+ switch (fmt) {
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ color &= 0x00ffffff;
+ alpha_mask = alpha << 24;
+ break;
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ color &= 0x00ffff;
+ alpha_mask = alpha << 16;
+ break;
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ color &= 0x0fff;
+ alpha_mask = (alpha << 8) & 0xF000;
+ break;
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ color &= 0x7fff;
+ alpha_mask = (alpha / 255) << 15 ;
+ break;
+ case B2R2_BLT_FMT_1_BIT_A1:
+ color = 0;
+ alpha_mask = (alpha / 255);
+ break;
+ case B2R2_BLT_FMT_8_BIT_A8:
+ color = 0;
+ alpha_mask = alpha;
+ break;
+ default:
+ alpha_mask = 0;
+ }
+
+ return color | alpha_mask;
+}
+
+/**
+ * fmt_has_alpha() - returns whether the given format carries an alpha value
+ */
+static bool fmt_has_alpha(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ case B2R2_BLT_FMT_1_BIT_A1:
+ case B2R2_BLT_FMT_8_BIT_A8:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * is_rgb_fmt() - returns whether the given format is a rgb format
+ */
+static bool is_rgb_fmt(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ case B2R2_BLT_FMT_16_BIT_RGB565:
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_1_BIT_A1:
+ case B2R2_BLT_FMT_8_BIT_A8:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * is_bgr_fmt() - returns whether the given format is a bgr format
+ */
+static bool is_bgr_fmt(enum b2r2_blt_fmt fmt)
+{
+ return (fmt == B2R2_BLT_FMT_32_BIT_ABGR8888);
+}
+
+/**
+ * is_yuv_fmt() - returns whether the given format is a yuv format
+ */
+static bool is_yuv_fmt(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * is_yuv420_fmt() - returns whether the given format is a yuv420 format
+ */
+static bool is_yuv420_fmt(enum b2r2_blt_fmt fmt)
+{
+
+ switch (fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * get_fmt_byte_pitch() - returns the pitch of a pixmap with the given width
+ */
+static int fmt_byte_pitch(enum b2r2_blt_fmt fmt, u32 width)
+{
+ int pitch;
+
+ switch (fmt) {
+
+ case B2R2_BLT_FMT_1_BIT_A1:
+ pitch = width >> 3; /* Shift is faster than division */
+ if ((width & 0x3) != 0) /* Check for remainder */
+ pitch++;
+ return pitch;
+
+ case B2R2_BLT_FMT_8_BIT_A8: /* Fall through */
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: /* Fall through */
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: /* Fall through */
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: /* Fall through */
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: /* Fall through */
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: /* Fall through */
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ return width;
+
+ case B2R2_BLT_FMT_16_BIT_ARGB4444: /* Fall through */
+ case B2R2_BLT_FMT_16_BIT_ARGB1555: /* Fall through */
+ case B2R2_BLT_FMT_16_BIT_RGB565: /* Fall through */
+ case B2R2_BLT_FMT_Y_CB_Y_CR: /* Fall through */
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ return width << 1;
+
+ case B2R2_BLT_FMT_24_BIT_RGB888: /* Fall through */
+ case B2R2_BLT_FMT_24_BIT_ARGB8565: /* Fall through */
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ return width * 3;
+
+ case B2R2_BLT_FMT_32_BIT_ARGB8888: /* Fall through */
+ case B2R2_BLT_FMT_32_BIT_ABGR8888: /* Fall through */
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ return width << 2;
+
+ default:
+ /* Should never, ever happen */
+ BUG_ON(1);
+ return 0;
+ }
+}
+
+/**
+ * to_native_fmt() - returns the native B2R2 format
+ */
+static enum b2r2_native_fmt to_native_fmt(enum b2r2_blt_fmt fmt)
+{
+
+ switch (fmt) {
+ case B2R2_BLT_FMT_UNUSED:
+ return B2R2_NATIVE_RGB565;
+ case B2R2_BLT_FMT_1_BIT_A1:
+ return B2R2_NATIVE_A1;
+ case B2R2_BLT_FMT_8_BIT_A8:
+ return B2R2_NATIVE_A8;
+ case B2R2_BLT_FMT_16_BIT_RGB565:
+ return B2R2_NATIVE_RGB565;
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ return B2R2_NATIVE_ARGB4444;
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ return B2R2_NATIVE_ARGB1555;
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ return B2R2_NATIVE_ARGB8565;
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ return B2R2_NATIVE_RGB888;
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ return B2R2_NATIVE_YCBCR888;
+ case B2R2_BLT_FMT_32_BIT_ABGR8888: /* Not actually supported by HW */
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ return B2R2_NATIVE_ARGB8888;
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ return B2R2_NATIVE_AYCBCR8888;
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ return B2R2_NATIVE_YCBCR422R;
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ return B2R2_NATIVE_YCBCR422R;
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ return B2R2_NATIVE_YCBCR42X_R2B;
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ return B2R2_NATIVE_YCBCR42X_MBN;
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ return B2R2_NATIVE_YUV;
+ default:
+ /* Should never ever happen */
+ return B2R2_NATIVE_BYTE;
+ }
+}
+
+/**
+ * Bit-expand the color from fmt to RGB888 with blue at LSB.
+ * Copy MSBs into missing LSBs.
+ */
+static u32 to_RGB888(u32 color, const enum b2r2_blt_fmt fmt)
+{
+ u32 out_color = 0;
+ u32 r = 0;
+ u32 g = 0;
+ u32 b = 0;
+ switch (fmt) {
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ r = ((color & 0xf00) << 12) | ((color & 0xf00) << 8);
+ g = ((color & 0xf0) << 8) | ((color & 0xf0) << 4);
+ b = ((color & 0xf) << 4) | (color & 0xf);
+ out_color = r | g | b;
+ break;
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ r = ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
+ g = ((color & 0x3e0) << 6) | ((color & 0x380) << 1);
+ b = ((color & 0x1f) << 3) | ((color & 0x1c) >> 2);
+ out_color = r | g | b;
+ break;
+ case B2R2_BLT_FMT_16_BIT_RGB565:
+ r = ((color & 0xf800) << 8) | ((color & 0xe000) << 3);
+ g = ((color & 0x7e0) << 5) | ((color & 0x600) >> 1);
+ b = ((color & 0x1f) << 3) | ((color & 0x1c) >> 2);
+ out_color = r | g | b;
+ break;
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ out_color = color & 0xffffff;
+ break;
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ r = (color & 0xff) << 16;
+ g = color & 0xff00;
+ b = (color & 0xff0000) >> 16;
+ out_color = r | g | b;
+ break;
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ r = ((color & 0xf800) << 8) | ((color & 0xe000) << 3);
+ g = ((color & 0x7e0) << 5) | ((color & 0x600) >> 1);
+ b = ((color & 0x1f) << 3) | ((color & 0x1c) >> 2);
+ out_color = r | g | b;
+ break;
+ default:
+ break;
+ }
+
+ return out_color;
+}
+
+/**
+ * get_fmt_type() - returns the type of the given format (raster, planar, etc.)
+ */
+static enum b2r2_fmt_type get_fmt_type(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ case B2R2_BLT_FMT_16_BIT_RGB565:
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ case B2R2_BLT_FMT_1_BIT_A1:
+ case B2R2_BLT_FMT_8_BIT_A8:
+ return B2R2_FMT_TYPE_RASTER;
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ return B2R2_FMT_TYPE_PLANAR;
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ return B2R2_FMT_TYPE_SEMI_PLANAR;
+ default:
+ return B2R2_FMT_TYPE_RASTER;
+ }
+}
+
+/**
+ * type2str() - returns a string representation of the type (for debug prints)
+ */
+static char *type2str(enum b2r2_op_type type)
+{
+ switch (type) {
+ case B2R2_DIRECT_COPY:
+ return "B2R2_DIRECT COPY";
+ case B2R2_DIRECT_FILL:
+ return "B2R2_DIRECT_FILL";
+ case B2R2_COPY:
+ return "B2R2_COPY";
+ case B2R2_FILL:
+ return "B2R2_FILL";
+ case B2R2_SCALE:
+ return "B2R2_SCALE";
+ case B2R2_ROTATE:
+ return "B2R2_ROTATE";
+ case B2R2_SCALE_AND_ROTATE:
+ return "B2R2_SCALE_AND_ROTATE";
+ case B2R2_FLIP:
+ return "B2R2_FLIP";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+/**
+ * is_transform() - returns whether the given request is a transform operation
+ */
+static bool is_transform(const struct b2r2_blt_request *req)
+{
+ return (req->user_req.transform != B2R2_BLT_TRANSFORM_NONE) ||
+ (req->user_req.src_rect.width !=
+ req->user_req.dst_rect.width) ||
+ (req->user_req.src_rect.height !=
+ req->user_req.dst_rect.height);
+}
+
+/**
+ * calculate_scale_factor() - calculates the scale factor between the given
+ * values
+ */
+static int calculate_scale_factor(u32 from, u32 to, u16 *sf_out)
+{
+ int ret;
+ u32 sf;
+
+ /*
+ * Assume normal nearest neighbor scaling:
+ *
+ * sf = (src - min_step) / (dst - 1)
+ */
+ if (to > 1)
+ sf = ((from << 10) - 1) / (to - 1);
+ else
+ sf = (from << 10);
+
+ if ((sf & 0xffff0000) != 0) {
+ /* Overflow error */
+ b2r2_log_warn("%s: "
+ "Scale factor too large\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ } else if (sf == 0) {
+ b2r2_log_warn("%s: "
+ "Scale factor too small\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ *sf_out = (u16)sf;
+
+ return 0;
+
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return ret;
+}
+
+/**
+ * rescale() - rescales the given dimension
+ */
+static s32 rescale(s32 dim, u16 sf)
+{
+ s32 tmp = dim << 10;
+
+ tmp = (tmp - 1) / sf + 1;
+
+ return tmp;
+}
+
+/**
+ * inv_rescale() - does an inverted rescale of the given dimension
+ */
+static s32 inv_rescale(s32 dim, u16 sf)
+{
+ s32 tmp;
+
+ if (dim == 1)
+ tmp = sf;
+ else
+ tmp = (dim - 1) * (s32)sf + 1;
+
+ if (tmp & 0x3FF)
+ tmp += (1 << 10);
+
+ return tmp >> 10;
+}
+
+/**
+ * set_target() - sets the target registers of the given node
+ */
+static void set_target(struct b2r2_node *node, u32 addr,
+ struct b2r2_node_split_buf *buf)
+{
+ s32 l;
+ s32 r;
+ s32 t;
+ s32 b;
+
+ PTRACE_ENTRY();
+
+ if (buf->tmp_buf_index) {
+ pverbose(KERN_INFO LOG_TAG "::%s: %p target is tmp\n", __func__,
+ node);
+ node->dst_tmp_index = buf->tmp_buf_index;
+ }
+
+ node->node.GROUP1.B2R2_TBA = addr;
+ node->node.GROUP1.B2R2_TTY = buf->pitch | to_native_fmt(buf->fmt) |
+ buf->alpha_range | buf->chroma_selection | buf->hso |
+ buf->vso | buf->dither | buf->plane_selection;
+ node->node.GROUP1.B2R2_TSZ =
+ ((buf->window.width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((buf->window.height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ node->node.GROUP1.B2R2_TXY =
+ ((buf->window.x & 0xffff) << B2R2_XY_X_SHIFT) |
+ ((buf->window.y & 0xffff) << B2R2_XY_Y_SHIFT);
+
+ /* Check if the rectangle is outside the buffer */
+ if (buf->vso == B2R2_TY_VSO_BOTTOM_TO_TOP)
+ t = buf->window.y - (buf->window.height - 1);
+ else
+ t = buf->window.y;
+
+ if (buf->hso == B2R2_TY_HSO_RIGHT_TO_LEFT)
+ l = buf->window.x - (buf->window.width - 1);
+ else
+ l = buf->window.x;
+
+ r = l + buf->window.width;
+ b = t + buf->window.height;
+
+ /* Clip to the destination buffer to prevent memory overwrites */
+ if ((l < 0) || (r > buf->width) || (t < 0) || (b > buf->height)) {
+ pverbose(KERN_INFO LOG_TAG "::%s: "
+ "Window outside buffer. Clipping...\n", __func__);
+
+ /* The clip rectangle is including the borders */
+ l = MAX(l, 0);
+ r = MIN(r, buf->width) - 1;
+ t = MAX(t, 0);
+ b = MIN(b, buf->height) - 1;
+
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_CLIP_WINDOW;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_RECT_CLIP_ENABLED;
+ node->node.GROUP6.B2R2_CWO =
+ ((l & 0x7FFF) << B2R2_CWS_X_SHIFT) |
+ ((t & 0x7FFF) << B2R2_CWS_Y_SHIFT);
+ node->node.GROUP6.B2R2_CWS =
+ ((r & 0x7FFF) << B2R2_CWO_X_SHIFT) |
+ ((b & 0x7FFF) << B2R2_CWO_Y_SHIFT);
+ }
+
+ pverbose(KERN_INFO LOG_TAG "::%s: addr=%p, rect=(%d, %d, %d, %d), "
+ "pitch=%d\n", __func__, (void *)addr, buf->window.x,
+ buf->window.y, buf->window.width, buf->window.height,
+ buf->pitch);
+}
+
+/**
+ * set_src() - configures the given source register with the given values
+ */
+static void set_src(struct b2r2_src_config *src, u32 addr,
+ struct b2r2_node_split_buf *buf)
+{
+ PTRACE_ENTRY();
+
+ src->B2R2_SBA = addr;
+ src->B2R2_STY = buf->pitch | to_native_fmt(buf->fmt) |
+ buf->alpha_range | buf->hso | buf->vso;
+ src->B2R2_SSZ = ((buf->window.width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) |
+ ((buf->window.height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT);
+ src->B2R2_SXY = ((buf->window.x & 0xffff) << B2R2_XY_X_SHIFT) |
+ ((buf->window.y & 0xffff) << B2R2_XY_Y_SHIFT);
+
+}
+
+/**
+ * set_src_1() - sets the source 1 registers of the given node
+ */
+static void set_src_1(struct b2r2_node *node, u32 addr,
+ struct b2r2_node_split_buf *buf)
+{
+ PTRACE_ENTRY();
+
+ if (buf->tmp_buf_index) {
+ pverbose(KERN_INFO LOG_TAG "::%s: %p src1 is tmp\n", __func__,
+ node);
+ node->src_tmp_index = buf->tmp_buf_index;
+ }
+
+ node->src_index = 1;
+
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_1;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_1_FETCH_FROM_MEM;
+
+ pverbose(KERN_INFO LOG_TAG "::%s: addr=%p, rect=(%d, %d, %d, %d), "
+ "pitch=%d\n", __func__, (void *)addr, buf->window.x,
+ buf->window.y, buf->window.width, buf->window.height,
+ buf->pitch);
+
+ node->node.GROUP3.B2R2_SBA = addr;
+ node->node.GROUP3.B2R2_STY = buf->pitch | to_native_fmt(buf->fmt) |
+ buf->alpha_range | buf->hso | buf->vso;
+ node->node.GROUP3.B2R2_SXY =
+ ((buf->window.x & 0xffff) << B2R2_XY_X_SHIFT) |
+ ((buf->window.y & 0xffff) << B2R2_XY_Y_SHIFT);
+
+ /* Source 1 has no size register */
+}
+
+/**
+ * set_src_2() - sets the source 2 registers of the given node
+ */
+static void set_src_2(struct b2r2_node *node, u32 addr,
+ struct b2r2_node_split_buf *buf)
+{
+ PTRACE_ENTRY();
+
+ if (buf->tmp_buf_index) {
+ pverbose(KERN_INFO LOG_TAG "::%s: %p src2 is tmp\n", __func__,
+ node);
+ node->src_tmp_index = buf->tmp_buf_index;
+ }
+
+ node->src_index = 2;
+
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_2_FETCH_FROM_MEM;
+
+ pverbose(KERN_INFO LOG_TAG "::%s: addr=%p, rect=(%d, %d, %d, %d), "
+ "pitch=%d\n", __func__, (void *)addr, buf->window.x,
+ buf->window.y, buf->window.width, buf->window.height,
+ buf->pitch);
+
+ set_src(&node->node.GROUP4, addr, buf);
+}
+
+/**
+ * set_src_3() - sets the source 3 registers of the given node
+ */
+static void set_src_3(struct b2r2_node *node, u32 addr,
+ struct b2r2_node_split_buf *buf)
+{
+ PTRACE_ENTRY();
+
+ if (buf->tmp_buf_index) {
+ pverbose(KERN_INFO LOG_TAG "::%s: %p src3 is tmp\n", __func__,
+ node);
+ node->src_tmp_index = buf->tmp_buf_index;
+ }
+
+ node->src_index = 3;
+
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_3;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_3_FETCH_FROM_MEM;
+
+ pverbose(KERN_INFO LOG_TAG "::%s: addr=%p, rect=(%d, %d, %d, %d), "
+ "pitch=%d\n", __func__, (void *)addr, buf->window.x,
+ buf->window.y, buf->window.width, buf->window.height,
+ buf->pitch);
+
+ set_src(&node->node.GROUP5, addr, buf);
+}
+
+/**
+ * set_ivmx() - configures the iVMX registers with the given values
+ */
+static void set_ivmx(struct b2r2_node *node, const u32 *vmx_values)
+{
+ PTRACE_ENTRY();
+
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED;
+
+ node->node.GROUP15.B2R2_VMX0 = vmx_values[0];
+ node->node.GROUP15.B2R2_VMX1 = vmx_values[1];
+ node->node.GROUP15.B2R2_VMX2 = vmx_values[2];
+ node->node.GROUP15.B2R2_VMX3 = vmx_values[3];
+}
+
+/**
+ * reset_nodes() - clears the node list
+ */
+static void reset_nodes(struct b2r2_node *node)
+{
+ PTRACE_ENTRY();
+
+ while (node != NULL) {
+ memset(&node->node, 0, sizeof(node->node));
+
+ node->src_tmp_index = 0;
+ node->dst_tmp_index = 0;
+
+ /* TODO: Implement support for short linked lists */
+ node->node.GROUP0.B2R2_CIC = 0x7ffff;
+
+ if (node->next != NULL)
+ node->node.GROUP0.B2R2_NIP =
+ node->next->physical_address;
+ node = node->next;
+ }
+}
+
+/* Commented for now, will be useful later... */
+#if 0
+/**
+ * dump_nodes() - prints the node list
+ */
+static void dump_nodes(struct b2r2_node *first)
+{
+ struct b2r2_node *node = first;
+ while (node != NULL) {
+ pverbose(KERN_INFO "\nNEW NODE:\n=============\n");
+ pverbose(KERN_INFO "B2R2_ACK: \t%#010x\n",
+ node->node.GROUP0.B2R2_ACK);
+ pverbose(KERN_INFO "B2R2_INS: \t%#010x\n",
+ node->node.GROUP0.B2R2_INS);
+ pverbose(KERN_INFO "B2R2_CIC: \t%#010x\n",
+ node->node.GROUP0.B2R2_CIC);
+ pverbose(KERN_INFO "B2R2_NIP: \t%#010x\n",
+ node->node.GROUP0.B2R2_NIP);
+
+ pverbose(KERN_INFO "B2R2_TSZ: \t%#010x\n",
+ node->node.GROUP1.B2R2_TSZ);
+ pverbose(KERN_INFO "B2R2_TXY: \t%#010x\n",
+ node->node.GROUP1.B2R2_TXY);
+ pverbose(KERN_INFO "B2R2_TTY: \t%#010x\n",
+ node->node.GROUP1.B2R2_TTY);
+ pverbose(KERN_INFO "B2R2_TBA: \t%#010x\n",
+ node->node.GROUP1.B2R2_TBA);
+
+ pverbose(KERN_INFO "B2R2_S2CF: \t%#010x\n",
+ node->node.GROUP2.B2R2_S2CF);
+ pverbose(KERN_INFO "B2R2_S1CF: \t%#010x\n",
+ node->node.GROUP2.B2R2_S1CF);
+
+ pverbose(KERN_INFO "B2R2_S1SZ: \t%#010x\n",
+ node->node.GROUP3.B2R2_SSZ);
+ pverbose(KERN_INFO "B2R2_S1XY: \t%#010x\n",
+ node->node.GROUP3.B2R2_SXY);
+ pverbose(KERN_INFO "B2R2_S1TY: \t%#010x\n",
+ node->node.GROUP3.B2R2_STY);
+ pverbose(KERN_INFO "B2R2_S1BA: \t%#010x\n",
+ node->node.GROUP3.B2R2_SBA);
+
+ pverbose(KERN_INFO "B2R2_S2SZ: \t%#010x\n",
+ node->node.GROUP4.B2R2_SSZ);
+ pverbose(KERN_INFO "B2R2_S2XY: \t%#010x\n",
+ node->node.GROUP4.B2R2_SXY);
+ pverbose(KERN_INFO "B2R2_S2TY: \t%#010x\n",
+ node->node.GROUP4.B2R2_STY);
+ pverbose(KERN_INFO "B2R2_S2BA: \t%#010x\n",
+ node->node.GROUP4.B2R2_SBA);
+
+ pverbose(KERN_INFO "B2R2_S3SZ: \t%#010x\n",
+ node->node.GROUP5.B2R2_SSZ);
+ pverbose(KERN_INFO "B2R2_S3XY: \t%#010x\n",
+ node->node.GROUP5.B2R2_SXY);
+ pverbose(KERN_INFO "B2R2_S3TY: \t%#010x\n",
+ node->node.GROUP5.B2R2_STY);
+ pverbose(KERN_INFO "B2R2_S3BA: \t%#010x\n",
+ node->node.GROUP5.B2R2_SBA);
+
+ pverbose(KERN_INFO "B2R2_CWS: \t%#010x\n",
+ node->node.GROUP6.B2R2_CWS);
+ pverbose(KERN_INFO "B2R2_CWO: \t%#010x\n",
+ node->node.GROUP6.B2R2_CWO);
+
+ pverbose(KERN_INFO "B2R2_FCTL: \t%#010x\n",
+ node->node.GROUP8.B2R2_FCTL);
+ pverbose(KERN_INFO "B2R2_RSF: \t%#010x\n",
+ node->node.GROUP9.B2R2_RSF);
+ pverbose(KERN_INFO "B2R2_RZI: \t%#010x\n",
+ node->node.GROUP9.B2R2_RZI);
+ pverbose(KERN_INFO "B2R2_LUMA_RSF: \t%#010x\n",
+ node->node.GROUP10.B2R2_RSF);
+ pverbose(KERN_INFO "B2R2_LUMA_RZI: \t%#010x\n",
+ node->node.GROUP10.B2R2_RZI);
+
+
+ pverbose(KERN_INFO "B2R2_IVMX0: \t%#010x\n",
+ node->node.GROUP15.B2R2_VMX0);
+ pverbose(KERN_INFO "B2R2_IVMX1: \t%#010x\n",
+ node->node.GROUP15.B2R2_VMX1);
+ pverbose(KERN_INFO "B2R2_IVMX2: \t%#010x\n",
+ node->node.GROUP15.B2R2_VMX2);
+ pverbose(KERN_INFO "B2R2_IVMX3: \t%#010x\n",
+ node->node.GROUP15.B2R2_VMX3);
+
+ node = node->next;
+ }
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *dir;
+static struct dentry *verbose_file;
+
+static int init_debugfs(void)
+{
+ dir = debugfs_create_dir("b2r2_node_split", NULL);
+ if (dir == NULL)
+ goto error;
+
+ verbose_file = debugfs_create_bool("verbose", 644, dir, &verbose);
+ if (verbose_file == NULL)
+ goto error_free_dir;
+
+ return 0;
+
+error_free_dir:
+ debugfs_remove(dir);
+error:
+ b2r2_log_warn("%s: Exit...\n", __func__);
+ return -1;
+}
+
+static void exit_debugfs(void)
+{
+ if (verbose_file != NULL)
+ debugfs_remove(verbose_file);
+ if (dir != NULL)
+ debugfs_remove(dir);
+
+ verbose_file = NULL;
+ dir = NULL;
+}
+
+#else
+static int init_debugfs(void) { return 0; }
+static void exit_debugfs(void) {}
+#endif
+
+int b2r2_node_split_init(void)
+{
+ b2r2_filters_init();
+
+ return init_debugfs();
+}
+
+void b2r2_node_split_exit(void)
+{
+ b2r2_filters_exit();
+
+ exit_debugfs();
+}
diff --git a/drivers/video/b2r2/b2r2_node_split.h b/drivers/video/b2r2/b2r2_node_split.h
new file mode 100644
index 00000000000..5bceac28488
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_node_split.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 node splitter
+ *
+ * Author: Fredrik Allansson <fredrik.allansson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __B2R2_NODE_SPLIT_H_
+#define __B2R2_NODE_SPLIT_H_
+
+#include "b2r2_internal.h"
+#include "b2r2_hw.h"
+
+/**
+ * b2r2_node_split_analyze() - Analyzes a B2R2 request
+ *
+ * @req - The request to analyze
+ * @max_buf_size - The largest size allowed for intermediate buffers
+ * @node_count - Number of nodes required for the job
+ * @buf_count - Number of intermediate buffers required for the job
+ * @bufs - An array of buffers needed for intermediate buffers
+ *
+ * Analyzes the request and determines how many nodes and intermediate buffers
+ * are required.
+ *
+ * It is the responsibility of the caller to allocate memory and assign the
+ * physical addresses. After that b2r2_node_split_assign_buffers should be
+ * called to assign the buffers to the right nodes.
+ *
+ * Returns:
+ * A handle identifing the analyzed request if successful, a negative
+ * value otherwise.
+ */
+int b2r2_node_split_analyze(const struct b2r2_blt_request *req, u32 max_buf_size,
+ u32 *node_count, struct b2r2_work_buf **bufs, u32* buf_count,
+ struct b2r2_node_split_job *job);
+
+/**
+ * b2r2_node_split_configure() - Performs a node split
+ *
+ * @handle - A handle for the analyzed request
+ * @first - The first node in the list of nodes to use
+ *
+ * Fills the supplied list of nodes with the parameters acquired by analyzing
+ * the request.
+ *
+ * All pointers to intermediate buffers are represented by integers to be used
+ * in the array returned by b2r2_node_split_analyze.
+ *
+ * Returns:
+ * A negative value if an error occurred, 0 otherwise.
+ */
+int b2r2_node_split_configure(struct b2r2_node_split_job *job,
+ struct b2r2_node *first);
+
+/**
+ * b2r2_node_split_assign_buffers() - Assignes physical addresses
+ *
+ * @handle - The handle for the job
+ * @first - The first node in the node list
+ * @bufs - Buffers with assigned physical addresses
+ * @buf_count - Number of physical addresses
+ *
+ * Assigns the physical addresses where intermediate buffers are required in
+ * the node list.
+ *
+ * The order of the elements of 'bufs' must be maintained from the call to
+ * b2r2_node_split_analyze.
+ *
+ * Returns:
+ * A negative value if an error occurred, 0 otherwise.
+ */
+int b2r2_node_split_assign_buffers(struct b2r2_node_split_job *job,
+ struct b2r2_node *first, struct b2r2_work_buf *bufs,
+ u32 buf_count);
+
+/**
+ * b2r2_node_split_unassign_buffers() - Removes all physical addresses
+ *
+ * @handle - The handle associated with the job
+ * @first - The first node in the node list
+ *
+ * Removes all references to intermediate buffers from the node list.
+ *
+ * This makes it possible to reuse the node list with new buffers by calling
+ * b2r2_node_split_assign_buffers again. Useful for caching node lists.
+ */
+void b2r2_node_split_unassign_buffers(struct b2r2_node_split_job *job,
+ struct b2r2_node *first);
+
+/**
+ * b2r2_node_split_release() - Releases all resources for a job
+ *
+ * @handle - The handle identifying the job. This will be set to 0.
+ *
+ * Releases all resources associated with a job.
+ *
+ * This should always be called once b2r2_node_split_analyze has been called
+ * in order to release any resources allocated while analyzing.
+ */
+void b2r2_node_split_cancel(struct b2r2_node_split_job *job);
+
+/**
+ * b2r2_node_split_init() - Initializes the node split module
+ *
+ * Initializes the node split module and creates debugfs files.
+ */
+int b2r2_node_split_init(void);
+
+/**
+ * b2r2_node_split_exit() - Deinitializes the node split module
+ *
+ * Releases all resources for the node split module.
+ */
+void b2r2_node_split_exit(void);
+
+#endif
diff --git a/drivers/video/b2r2/b2r2_profiler/Makefile b/drivers/video/b2r2/b2r2_profiler/Makefile
new file mode 100644
index 00000000000..06886618883
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_profiler/Makefile
@@ -0,0 +1,3 @@
+# Make file for loadable module B2R2 Profiler
+
+obj-m := b2r2_profiler.o
diff --git a/drivers/video/b2r2/b2r2_profiler/b2r2_profiler.c b/drivers/video/b2r2/b2r2_profiler/b2r2_profiler.c
new file mode 100644
index 00000000000..6fcca3f77d2
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_profiler/b2r2_profiler.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * ST-Ericsson B2R2 profiler implementation
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/jiffies.h>
+
+#include "../b2r2_blt.h"
+#include "../b2r2_profiler_api.h"
+
+
+#define S32_MAX 2147483647
+
+
+static int src_format_filter_on = false;
+module_param(src_format_filter_on, bool, S_IRUGO | S_IWUSR);
+static unsigned int src_format_filter;
+module_param(src_format_filter, uint, S_IRUGO | S_IWUSR);
+
+static int print_blts_on = 0;
+module_param(print_blts_on, bool, S_IRUGO | S_IWUSR);
+static int use_mpix_per_second_in_print_blts = 1;
+module_param(use_mpix_per_second_in_print_blts, bool, S_IRUGO | S_IWUSR);
+
+static int min_avg_max_mpix_per_second_on = 1;
+module_param(min_avg_max_mpix_per_second_on, bool, S_IRUGO | S_IWUSR);
+
+static const unsigned int min_avg_max_mpix_per_second_num_blts_used = 400;
+static struct {
+ unsigned long sampling_start_time_jiffies;
+
+ s32 min_mpix_per_second;
+ struct b2r2_blt_req min_blt_request;
+ struct b2r2_blt_profiling_info min_blt_profiling_info;
+
+ s32 max_mpix_per_second;
+ struct b2r2_blt_req max_blt_request;
+ struct b2r2_blt_profiling_info max_blt_profiling_info;
+
+ s32 accumulated_num_pixels;
+ s32 accumulated_num_usecs;
+
+ u32 num_blts_done;
+} min_avg_max_mpix_per_second_state;
+
+
+static s32 nsec_2_usec(const s32 nsec);
+
+static int is_scale_blt(const struct b2r2_blt_req * const request);
+static s32 get_blt_mpix_per_second(const struct b2r2_blt_req * const request, const struct b2r2_blt_profiling_info * const blt_profiling_info);
+static void print_blt(const struct b2r2_blt_req * const request, const struct b2r2_blt_profiling_info * const blt_profiling_info);
+
+static s32 get_num_pixels_in_blt(const struct b2r2_blt_req * const request);
+static s32 get_mpix_per_second(const s32 num_pixels, const s32 num_usecs);
+static void print_min_avg_max_mpix_per_second_state(void);
+static void reset_min_avg_max_mpix_per_second_state(void);
+static void do_min_avg_max_mpix_per_second(const struct b2r2_blt_req * const request, const struct b2r2_blt_profiling_info * const blt_profiling_info);
+
+static void blt_done(const struct b2r2_blt_req * const blt, const s32 request_id, const struct b2r2_blt_profiling_info * const blt_profiling_info);
+
+
+static struct b2r2_profiler this = {
+ .blt_done = blt_done,
+};
+
+
+static s32 nsec_2_usec(const s32 nsec)
+{
+ return nsec / 1000;
+}
+
+
+static int is_scale_blt(const struct b2r2_blt_req * const request)
+{
+ if ((request->transform & B2R2_BLT_TRANSFORM_CCW_ROT_90 &&
+ (request->src_rect.width != request->dst_rect.height ||
+ request->src_rect.height != request->dst_rect.width)) ||
+ (!(request->transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) &&
+ (request->src_rect.width != request->dst_rect.width ||
+ request->src_rect.height != request->dst_rect.height)))
+ return 1;
+ else
+ return 0;
+}
+
+static s32 get_blt_mpix_per_second(const struct b2r2_blt_req * const request, const struct b2r2_blt_profiling_info * const blt_profiling_info)
+{
+ return get_mpix_per_second(get_num_pixels_in_blt(request),
+ nsec_2_usec(blt_profiling_info->nsec_active_in_cpu + blt_profiling_info->nsec_active_in_b2r2));
+}
+
+static void print_blt(const struct b2r2_blt_req * const request, const struct b2r2_blt_profiling_info * const blt_profiling_info)
+{
+ char tmp_str[128];
+ sprintf(tmp_str, "SF: %#10x, DF: %#10x, F: %#10x, T: %#3x, S: %1i, P: %7i",
+ request->src_img.fmt,
+ request->dst_img.fmt,
+ request->flags,
+ request->transform,
+ is_scale_blt(request),
+ get_num_pixels_in_blt(request));
+ if (use_mpix_per_second_in_print_blts)
+ printk(KERN_ALERT "%s, MPix/s: %3i\n",
+ tmp_str,
+ get_blt_mpix_per_second(request, blt_profiling_info));
+ else
+ printk(KERN_ALERT "%s, CPU: %10i, B2R2: %10i, Tot: %10i ns\n",
+ tmp_str,
+ blt_profiling_info->nsec_active_in_cpu,
+ blt_profiling_info->nsec_active_in_b2r2,
+ blt_profiling_info->total_time_nsec);
+}
+
+
+static s32 get_num_pixels_in_blt(const struct b2r2_blt_req * const request)
+{
+ s32 num_pixels_in_src = request->src_rect.width * request->src_rect.height;
+ s32 num_pixels_in_dst = request->dst_rect.width * request->dst_rect.height;
+ return (num_pixels_in_src + num_pixels_in_dst) / 2;
+}
+
+static s32 get_mpix_per_second(const s32 num_pixels, const s32 num_usecs)
+{
+ s32 num_pixels_scale_factor = num_pixels != 0 ? S32_MAX / num_pixels : S32_MAX;
+ s32 num_usecs_scale_factor = num_usecs != 0 ? S32_MAX / num_usecs : S32_MAX;
+ s32 scale_factor = min(num_pixels_scale_factor, num_usecs_scale_factor);
+
+ s32 num_pixels_scaled = num_pixels * scale_factor;
+ s32 num_usecs_scaled = num_usecs * scale_factor;
+
+ if (num_usecs_scaled < 1000000)
+ return 0;
+
+ return (num_pixels_scaled / 1000000) / (num_usecs_scaled / 1000000);
+}
+
+static void print_min_avg_max_mpix_per_second_state(void)
+{
+ printk(KERN_ALERT "Min: %3i, Avg: %3i, Max: %3i MPix/s\n",
+ min_avg_max_mpix_per_second_state.min_mpix_per_second,
+ get_mpix_per_second(min_avg_max_mpix_per_second_state.accumulated_num_pixels,
+ min_avg_max_mpix_per_second_state.accumulated_num_usecs),
+ min_avg_max_mpix_per_second_state.max_mpix_per_second);
+ printk(KERN_ALERT "Min blit:\n");
+ print_blt(&min_avg_max_mpix_per_second_state.min_blt_request,
+ &min_avg_max_mpix_per_second_state.min_blt_profiling_info);
+ printk(KERN_ALERT "Max blit:\n");
+ print_blt(&min_avg_max_mpix_per_second_state.max_blt_request,
+ &min_avg_max_mpix_per_second_state.max_blt_profiling_info);
+}
+
+static void reset_min_avg_max_mpix_per_second_state(void)
+{
+ min_avg_max_mpix_per_second_state.sampling_start_time_jiffies =
+ jiffies;
+ min_avg_max_mpix_per_second_state.min_mpix_per_second = S32_MAX;
+ min_avg_max_mpix_per_second_state.max_mpix_per_second = 0;
+ min_avg_max_mpix_per_second_state.accumulated_num_pixels = 0;
+ min_avg_max_mpix_per_second_state.accumulated_num_usecs = 0;
+ min_avg_max_mpix_per_second_state.num_blts_done = 0;
+}
+
+static void do_min_avg_max_mpix_per_second(const struct b2r2_blt_req * const request, const struct b2r2_blt_profiling_info * const blt_profiling_info)
+{
+ s32 num_pixels_in_blt;
+ s32 num_usec_blt_took;
+ s32 blt_mpix_per_second;
+
+ if (time_before(jiffies, min_avg_max_mpix_per_second_state.sampling_start_time_jiffies))
+ return;
+
+ num_pixels_in_blt = get_num_pixels_in_blt(request);
+ num_usec_blt_took = nsec_2_usec(blt_profiling_info->nsec_active_in_cpu + blt_profiling_info->nsec_active_in_b2r2);
+ blt_mpix_per_second = get_mpix_per_second(num_pixels_in_blt,
+ num_usec_blt_took);
+
+ if (blt_mpix_per_second <= min_avg_max_mpix_per_second_state.min_mpix_per_second) {
+ min_avg_max_mpix_per_second_state.min_mpix_per_second =
+ blt_mpix_per_second;
+ memcpy(&min_avg_max_mpix_per_second_state.min_blt_request,
+ request, sizeof(struct b2r2_blt_req));
+ memcpy(&min_avg_max_mpix_per_second_state.min_blt_profiling_info,
+ blt_profiling_info, sizeof(struct b2r2_blt_profiling_info));
+ }
+
+ if (blt_mpix_per_second >= min_avg_max_mpix_per_second_state.max_mpix_per_second) {
+ min_avg_max_mpix_per_second_state.max_mpix_per_second =
+ blt_mpix_per_second;
+ memcpy(&min_avg_max_mpix_per_second_state.max_blt_request,
+ request, sizeof(struct b2r2_blt_req));
+ memcpy(&min_avg_max_mpix_per_second_state.max_blt_profiling_info,
+ blt_profiling_info, sizeof(struct b2r2_blt_profiling_info));
+ }
+
+ min_avg_max_mpix_per_second_state.accumulated_num_pixels +=
+ num_pixels_in_blt;
+ min_avg_max_mpix_per_second_state.accumulated_num_usecs +=
+ num_usec_blt_took;
+
+ min_avg_max_mpix_per_second_state.num_blts_done++;
+
+ if (min_avg_max_mpix_per_second_state.num_blts_done >= min_avg_max_mpix_per_second_num_blts_used) {
+ print_min_avg_max_mpix_per_second_state();
+ reset_min_avg_max_mpix_per_second_state();
+ /* The printouts initiated above can disturb the next measurement
+ so we delay it two seconds to give the printouts a chance to finish. */
+ min_avg_max_mpix_per_second_state.sampling_start_time_jiffies =
+ jiffies + (2 * HZ);
+ }
+}
+
+static void blt_done(const struct b2r2_blt_req * const request, const s32 request_id, const struct b2r2_blt_profiling_info * const blt_profiling_info)
+{
+ /* Filters */
+ if (src_format_filter_on && request->src_img.fmt != src_format_filter)
+ return;
+
+ /* Processors */
+ if (print_blts_on)
+ print_blt(request, blt_profiling_info);
+
+ if (min_avg_max_mpix_per_second_on)
+ do_min_avg_max_mpix_per_second(request, blt_profiling_info);
+}
+
+
+static int __init b2r2_profiler_init(void)
+{
+ reset_min_avg_max_mpix_per_second_state();
+
+ return b2r2_register_profiler(&this);
+}
+module_init(b2r2_profiler_init);
+
+static void __exit b2r2_profiler_exit(void)
+{
+ b2r2_unregister_profiler(&this);
+}
+module_exit(b2r2_profiler_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Johan Mossberg (johan.xx.mossberg@stericsson.com)");
+MODULE_DESCRIPTION("B2R2 Profiler");
diff --git a/drivers/video/b2r2/b2r2_profiler_api.h b/drivers/video/b2r2/b2r2_profiler_api.h
new file mode 100644
index 00000000000..5f1f9abbe49
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_profiler_api.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 profiling API
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+
+#ifndef _LINUX_VIDEO_B2R2_PROFILER_API_H
+#define _LINUX_VIDEO_B2R2_PROFILER_API_H
+
+#include <video/b2r2_blt.h>
+
+/**
+ * struct b2r2_blt_profiling_info - Profiling information for a blit
+ *
+ * @nsec_active_in_cpu: The number of nanoseconds the job was active in the CPU.
+ * This is an approximate value, check out the code for more
+ * info.
+ * @nsec_active_in_b2r2: The number of nanoseconds the job was active in B2R2. This
+ * is an approximate value, check out the code for more info.
+ * @total_time_nsec: The total time the job took in nano seconds. Includes ideling.
+ */
+struct b2r2_blt_profiling_info {
+ s32 nsec_active_in_cpu;
+ s32 nsec_active_in_b2r2;
+ s32 total_time_nsec;
+};
+
+/**
+ * struct b2r2_profiler - B2R2 profiler.
+ *
+ * The callbacks are never run concurrently. No heavy stuff must be done in the
+ * callbacks as this might adversely affect the B2R2 driver. The callbacks must
+ * not call the B2R2 profiler API as this will cause a deadlock. If the callbacks
+ * call into the B2R2 driver care must be taken as deadlock situations can arise.
+ *
+ * @blt_done: Called when a blit has finished, timed out or been canceled.
+ */
+struct b2r2_profiler {
+ void (*blt_done)(const struct b2r2_blt_req * const request, const s32 request_id, const struct b2r2_blt_profiling_info * const blt_profiling_info);
+};
+
+/**
+ * b2r2_register_profiler() - Registers a profiler.
+ *
+ * Currently only one profiler can be registered at any given time.
+ *
+ * @profiler: The profiler
+ *
+ * Returns 0 on success, negative error code on failure
+ */
+int b2r2_register_profiler(const struct b2r2_profiler * const profiler);
+
+/**
+ * b2r2_unregister_profiler() - Unregisters a profiler.
+ *
+ * @profiler: The profiler
+ */
+void b2r2_unregister_profiler(const struct b2r2_profiler * const profiler);
+
+#endif /* #ifdef _LINUX_VIDEO_B2R2_PROFILER_API_H */
diff --git a/drivers/video/b2r2/b2r2_profiler_socket.c b/drivers/video/b2r2/b2r2_profiler_socket.c
new file mode 100644
index 00000000000..5631a730d4e
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_profiler_socket.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 profiler socket communication
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/semaphore.h>
+#include <asm/errno.h>
+
+#include "b2r2_profiler_api.h"
+#include "b2r2_internal.h"
+
+
+/*
+ * TODO: Call the profiler in a seperate thread and have a circular buffer
+ * between the B2R2 driver and that thread. That way the profiler can not slow
+ * down or kill the B2R2 driver. Seems a bit overkill right now as there is
+ * only one B2R2 profiler and we have full control over it but the situation
+ * may be different in the future.
+ */
+
+
+static const struct b2r2_profiler *b2r2_profiler;
+static DECLARE_MUTEX(b2r2_profiler_lock);
+
+
+int b2r2_register_profiler(const struct b2r2_profiler * const profiler)
+{
+ int return_value;
+
+ return_value = down_interruptible(&b2r2_profiler_lock);
+ if (return_value != 0)
+ return return_value;
+
+ if (b2r2_profiler != NULL) {
+ return_value = -EUSERS;
+
+ goto cleanup;
+ }
+
+ b2r2_profiler = profiler;
+
+ return_value = 0;
+
+cleanup:
+ up(&b2r2_profiler_lock);
+
+ return return_value;
+}
+EXPORT_SYMBOL(b2r2_register_profiler);
+
+void b2r2_unregister_profiler(const struct b2r2_profiler * const profiler)
+{
+ down(&b2r2_profiler_lock);
+
+ if (profiler == b2r2_profiler)
+ b2r2_profiler = NULL;
+
+ up(&b2r2_profiler_lock);
+}
+EXPORT_SYMBOL(b2r2_unregister_profiler);
+
+
+bool is_profiler_registered_approx(void)
+{
+ /* No locking by design, to make it fast, hence the approx */
+ if (b2r2_profiler != NULL)
+ return true;
+ else
+ return false;
+}
+
+void b2r2_call_profiler_blt_done(const struct b2r2_blt_request * const request)
+{
+ int return_value;
+ struct b2r2_blt_profiling_info blt_profiling_info;
+
+ return_value = down_interruptible(&b2r2_profiler_lock);
+ if (return_value != 0) {
+ dev_err(b2r2_blt_device(),
+ "%s: Failed to acquire semaphore, ret=%i. Lost profiler call!\n",
+ __func__, return_value);
+
+ return;
+ }
+
+ if (NULL == b2r2_profiler)
+ goto cleanup;
+
+ blt_profiling_info.nsec_active_in_cpu = request->nsec_active_in_cpu;
+ blt_profiling_info.nsec_active_in_b2r2 = request->job.nsec_active_in_hw;
+ blt_profiling_info.total_time_nsec = request->total_time_nsec;
+
+ b2r2_profiler->blt_done(&request->user_req, request->request_id, &blt_profiling_info);
+
+cleanup:
+ up(&b2r2_profiler_lock);
+}
diff --git a/drivers/video/b2r2/b2r2_profiler_socket.h b/drivers/video/b2r2/b2r2_profiler_socket.h
new file mode 100644
index 00000000000..80b2c20293f
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_profiler_socket.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 profiler socket communication
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef _LINUX_VIDEO_B2R2_PROFILER_SOCKET_H
+#define _LINUX_VIDEO_B2R2_PROFILER_SOCKET_H
+
+#include "b2r2_internal.h"
+
+/* Will give a correct result most of the time but can be wrong */
+bool is_profiler_registered_approx(void);
+
+void b2r2_call_profiler_blt_done(const struct b2r2_blt_request * const request);
+
+#endif /* _LINUX_VIDEO_B2R2_PROFILER_SOCKET_H */
diff --git a/drivers/video/b2r2/b2r2_structures.h b/drivers/video/b2r2/b2r2_structures.h
new file mode 100644
index 00000000000..99fa7f047d3
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_structures.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 register struct
+ *
+ * Author: Robert Fekete <robert.fekete@stericsson.com>
+ * Author: Paul Wannback
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+
+#ifndef __B2R2_STRUCTURES_H
+#define __B2R2_STRUCTURES_H
+
+/* C struct view */
+struct b2r2_memory_map {
+ unsigned char fill0[2304];
+ unsigned int BLT_SSBA17; /* @2304 */
+ unsigned int BLT_SSBA18; /* @2308 */
+ unsigned int BLT_SSBA19; /* @2312 */
+ unsigned int BLT_SSBA20; /* @2316 */
+ unsigned int BLT_SSBA21; /* @2320 */
+ unsigned int BLT_SSBA22; /* @2324 */
+ unsigned int BLT_SSBA23; /* @2328 */
+ unsigned int BLT_SSBA24; /* @2332 */
+ unsigned char fill1[32];
+ unsigned int BLT_STBA5; /* @2368 */
+ unsigned int BLT_STBA6; /* @2372 */
+ unsigned int BLT_STBA7; /* @2376 */
+ unsigned int BLT_STBA8; /* @2380 */
+ unsigned char fill2[176];
+ unsigned int BLT_CTL; /* @2560 */
+ unsigned int BLT_ITS; /* @2564 */
+ unsigned int BLT_STA1; /* @2568 */
+ unsigned char fill3[4];
+ unsigned int BLT_SSBA1; /* @2576 */
+ unsigned int BLT_SSBA2; /* @2580 */
+ unsigned int BLT_SSBA3; /* @2584 */
+ unsigned int BLT_SSBA4; /* @2588 */
+ unsigned int BLT_SSBA5; /* @2592 */
+ unsigned int BLT_SSBA6; /* @2596 */
+ unsigned int BLT_SSBA7; /* @2600 */
+ unsigned int BLT_SSBA8; /* @2604 */
+ unsigned int BLT_STBA1; /* @2608 */
+ unsigned int BLT_STBA2; /* @2612 */
+ unsigned int BLT_STBA3; /* @2616 */
+ unsigned int BLT_STBA4; /* @2620 */
+ unsigned int BLT_CQ1_TRIG_IP; /* @2624 */
+ unsigned int BLT_CQ1_TRIG_CTL; /* @2628 */
+ unsigned int BLT_CQ1_PACE_CTL; /* @2632 */
+ unsigned int BLT_CQ1_IP; /* @2636 */
+ unsigned int BLT_CQ2_TRIG_IP; /* @2640 */
+ unsigned int BLT_CQ2_TRIG_CTL; /* @2644 */
+ unsigned int BLT_CQ2_PACE_CTL; /* @2648 */
+ unsigned int BLT_CQ2_IP; /* @2652 */
+ unsigned int BLT_AQ1_CTL; /* @2656 */
+ unsigned int BLT_AQ1_IP; /* @2660 */
+ unsigned int BLT_AQ1_LNA; /* @2664 */
+ unsigned int BLT_AQ1_STA; /* @2668 */
+ unsigned int BLT_AQ2_CTL; /* @2672 */
+ unsigned int BLT_AQ2_IP; /* @2676 */
+ unsigned int BLT_AQ2_LNA; /* @2680 */
+ unsigned int BLT_AQ2_STA; /* @2684 */
+ unsigned int BLT_AQ3_CTL; /* @2688 */
+ unsigned int BLT_AQ3_IP; /* @2692 */
+ unsigned int BLT_AQ3_LNA; /* @2696 */
+ unsigned int BLT_AQ3_STA; /* @2700 */
+ unsigned int BLT_AQ4_CTL; /* @2704 */
+ unsigned int BLT_AQ4_IP; /* @2708 */
+ unsigned int BLT_AQ4_LNA; /* @2712 */
+ unsigned int BLT_AQ4_STA; /* @2716 */
+ unsigned int BLT_SSBA9; /* @2720 */
+ unsigned int BLT_SSBA10; /* @2724 */
+ unsigned int BLT_SSBA11; /* @2728 */
+ unsigned int BLT_SSBA12; /* @2732 */
+ unsigned int BLT_SSBA13; /* @2736 */
+ unsigned int BLT_SSBA14; /* @2740 */
+ unsigned int BLT_SSBA15; /* @2744 */
+ unsigned int BLT_SSBA16; /* @2748 */
+ unsigned int BLT_SGA1; /* @2752 */
+ unsigned int BLT_SGA2; /* @2756 */
+ unsigned char fill4[8];
+ unsigned int BLT_ITM0; /* @2768 */
+ unsigned int BLT_ITM1; /* @2772 */
+ unsigned int BLT_ITM2; /* @2776 */
+ unsigned int BLT_ITM3; /* @2780 */
+ unsigned char fill5[16];
+ unsigned int BLT_DFV2; /* @2800 */
+ unsigned int BLT_DFV1; /* @2804 */
+ unsigned int BLT_PRI; /* @2808 */
+ unsigned char fill6[8];
+ unsigned int PLUGS1_OP2; /* @2820 */
+ unsigned int PLUGS1_CHZ; /* @2824 */
+ unsigned int PLUGS1_MSZ; /* @2828 */
+ unsigned int PLUGS1_PGZ; /* @2832 */
+ unsigned char fill7[16];
+ unsigned int PLUGS2_OP2; /* @2852 */
+ unsigned int PLUGS2_CHZ; /* @2856 */
+ unsigned int PLUGS2_MSZ; /* @2860 */
+ unsigned int PLUGS2_PGZ; /* @2864 */
+ unsigned char fill8[16];
+ unsigned int PLUGS3_OP2; /* @2884 */
+ unsigned int PLUGS3_CHZ; /* @2888 */
+ unsigned int PLUGS3_MSZ; /* @2892 */
+ unsigned int PLUGS3_PGZ; /* @2896 */
+ unsigned char fill9[48];
+ unsigned int PLUGT_OP2; /* @2948 */
+ unsigned int PLUGT_CHZ; /* @2952 */
+ unsigned int PLUGT_MSZ; /* @2956 */
+ unsigned int PLUGT_PGZ; /* @2960 */
+ unsigned char fill10[108];
+ unsigned int BLT_NIP; /* @3072 */
+ unsigned int BLT_CIC; /* @3076 */
+ unsigned int BLT_INS; /* @3080 */
+ unsigned int BLT_ACK; /* @3084 */
+ unsigned int BLT_TBA; /* @3088 */
+ unsigned int BLT_TTY; /* @3092 */
+ unsigned int BLT_TXY; /* @3096 */
+ unsigned int BLT_TSZ; /* @3100 */
+ unsigned int BLT_S1CF; /* @3104 */
+ unsigned int BLT_S2CF; /* @3108 */
+ unsigned int BLT_S1BA; /* @3112 */
+ unsigned int BLT_S1TY; /* @3116 */
+ unsigned int BLT_S1XY; /* @3120 */
+ unsigned char fill11[4];
+ unsigned int BLT_S2BA; /* @3128 */
+ unsigned int BLT_S2TY; /* @3132 */
+ unsigned int BLT_S2XY; /* @3136 */
+ unsigned int BLT_S2SZ; /* @3140 */
+ unsigned int BLT_S3BA; /* @3144 */
+ unsigned int BLT_S3TY; /* @3148 */
+ unsigned int BLT_S3XY; /* @3152 */
+ unsigned int BLT_S3SZ; /* @3156 */
+ unsigned int BLT_CWO; /* @3160 */
+ unsigned int BLT_CWS; /* @3164 */
+ unsigned int BLT_CCO; /* @3168 */
+ unsigned int BLT_CML; /* @3172 */
+ unsigned int BLT_FCTL; /* @3176 */
+ unsigned int BLT_PMK; /* @3180 */
+ unsigned int BLT_RSF; /* @3184 */
+ unsigned int BLT_RZI; /* @3188 */
+ unsigned int BLT_HFP; /* @3192 */
+ unsigned int BLT_VFP; /* @3196 */
+ unsigned int BLT_Y_RSF; /* @3200 */
+ unsigned int BLT_Y_RZI; /* @3204 */
+ unsigned int BLT_Y_HFP; /* @3208 */
+ unsigned int BLT_Y_VFP; /* @3212 */
+ unsigned char fill12[16];
+ unsigned int BLT_KEY1; /* @3232 */
+ unsigned int BLT_KEY2; /* @3236 */
+ unsigned char fill13[8];
+ unsigned int BLT_SAR; /* @3248 */
+ unsigned int BLT_USR; /* @3252 */
+ unsigned char fill14[8];
+ unsigned int BLT_IVMX0; /* @3264 */
+ unsigned int BLT_IVMX1; /* @3268 */
+ unsigned int BLT_IVMX2; /* @3272 */
+ unsigned int BLT_IVMX3; /* @3276 */
+ unsigned int BLT_OVMX0; /* @3280 */
+ unsigned int BLT_OVMX1; /* @3284 */
+ unsigned int BLT_OVMX2; /* @3288 */
+ unsigned int BLT_OVMX3; /* @3292 */
+ unsigned char fill15[8];
+ unsigned int BLT_VC1R; /* @3304 */
+ unsigned char fill16[20];
+ unsigned int BLT_Y_HFC0; /* @3328 */
+ unsigned int BLT_Y_HFC1; /* @3332 */
+ unsigned int BLT_Y_HFC2; /* @3336 */
+ unsigned int BLT_Y_HFC3; /* @3340 */
+ unsigned int BLT_Y_HFC4; /* @3344 */
+ unsigned int BLT_Y_HFC5; /* @3348 */
+ unsigned int BLT_Y_HFC6; /* @3352 */
+ unsigned int BLT_Y_HFC7; /* @3356 */
+ unsigned int BLT_Y_HFC8; /* @3360 */
+ unsigned int BLT_Y_HFC9; /* @3364 */
+ unsigned int BLT_Y_HFC10; /* @3368 */
+ unsigned int BLT_Y_HFC11; /* @3372 */
+ unsigned int BLT_Y_HFC12; /* @3376 */
+ unsigned int BLT_Y_HFC13; /* @3380 */
+ unsigned int BLT_Y_HFC14; /* @3384 */
+ unsigned int BLT_Y_HFC15; /* @3388 */
+ unsigned char fill17[80];
+ unsigned int BLT_Y_VFC0; /* @3472 */
+ unsigned int BLT_Y_VFC1; /* @3476 */
+ unsigned int BLT_Y_VFC2; /* @3480 */
+ unsigned int BLT_Y_VFC3; /* @3484 */
+ unsigned int BLT_Y_VFC4; /* @3488 */
+ unsigned int BLT_Y_VFC5; /* @3492 */
+ unsigned int BLT_Y_VFC6; /* @3496 */
+ unsigned int BLT_Y_VFC7; /* @3500 */
+ unsigned int BLT_Y_VFC8; /* @3504 */
+ unsigned int BLT_Y_VFC9; /* @3508 */
+ unsigned char fill18[72];
+ unsigned int BLT_HFC0; /* @3584 */
+ unsigned int BLT_HFC1; /* @3588 */
+ unsigned int BLT_HFC2; /* @3592 */
+ unsigned int BLT_HFC3; /* @3596 */
+ unsigned int BLT_HFC4; /* @3600 */
+ unsigned int BLT_HFC5; /* @3604 */
+ unsigned int BLT_HFC6; /* @3608 */
+ unsigned int BLT_HFC7; /* @3612 */
+ unsigned int BLT_HFC8; /* @3616 */
+ unsigned int BLT_HFC9; /* @3620 */
+ unsigned int BLT_HFC10; /* @3624 */
+ unsigned int BLT_HFC11; /* @3628 */
+ unsigned int BLT_HFC12; /* @3632 */
+ unsigned int BLT_HFC13; /* @3636 */
+ unsigned int BLT_HFC14; /* @3640 */
+ unsigned int BLT_HFC15; /* @3644 */
+ unsigned char fill19[80];
+ unsigned int BLT_VFC0; /* @3728 */
+ unsigned int BLT_VFC1; /* @3732 */
+ unsigned int BLT_VFC2; /* @3736 */
+ unsigned int BLT_VFC3; /* @3740 */
+ unsigned int BLT_VFC4; /* @3744 */
+ unsigned int BLT_VFC5; /* @3748 */
+ unsigned int BLT_VFC6; /* @3752 */
+ unsigned int BLT_VFC7; /* @3756 */
+ unsigned int BLT_VFC8; /* @3760 */
+ unsigned int BLT_VFC9; /* @3764 */
+};
+
+#endif /* !defined(__B2R2_STRUCTURES_H) */
+
diff --git a/drivers/video/b2r2/b2r2_timing.c b/drivers/video/b2r2/b2r2_timing.c
new file mode 100644
index 00000000000..4f3e2b8b042
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_timing.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 timing
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/time.h>
+
+
+u32 b2r2_get_curr_nsec(void)
+{
+ struct timespec ts;
+
+ getrawmonotonic(&ts);
+
+ return (u32)timespec_to_ns(&ts);
+}
diff --git a/drivers/video/b2r2/b2r2_timing.h b/drivers/video/b2r2/b2r2_timing.h
new file mode 100644
index 00000000000..e87113c0ec9
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_timing.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 timing
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef _LINUX_DRIVERS_VIDEO_B2R2_TIMING_H_
+#define _LINUX_DRIVERS_VIDEO_B2R2_TIMING_H_
+
+/**
+ * b2r2_get_curr_nsec() - Return the current nanosecond. Notice that the value
+ * wraps when the u32 limit is reached.
+ *
+ */
+u32 b2r2_get_curr_nsec(void);
+
+#endif /* _LINUX_DRIVERS_VIDEO_B2R2_TIMING_H_ */
diff --git a/drivers/video/b2r2/b2r2_utils.c b/drivers/video/b2r2/b2r2_utils.c
new file mode 100644
index 00000000000..3c7fc9f9f42
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_utils.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 utils
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include "b2r2_utils.h"
+
+#include "b2r2_debug.h"
+
+#include <video/b2r2_blt.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+
+const s32 b2r2_s32_max = 2147483647;
+
+
+void b2r2_get_img_bounding_rect(struct b2r2_blt_img *img,
+ struct b2r2_blt_rect *bounding_rect)
+{
+ bounding_rect->x = 0;
+ bounding_rect->y = 0;
+ bounding_rect->width = img->width;
+ bounding_rect->height = img->height;
+}
+
+
+bool b2r2_is_zero_area_rect(struct b2r2_blt_rect *rect)
+{
+ return rect->width == 0 || rect->height == 0;
+}
+
+bool b2r2_is_rect_inside_rect(struct b2r2_blt_rect *rect1,
+ struct b2r2_blt_rect *rect2)
+{
+ return rect1->x >= rect2->x &&
+ rect1->y >= rect2->y &&
+ rect1->x + rect1->width <= rect2->x + rect2->width &&
+ rect1->y + rect1->height <= rect2->y + rect2->height;
+}
+
+void b2r2_intersect_rects(struct b2r2_blt_rect *rect1,
+ struct b2r2_blt_rect *rect2, struct b2r2_blt_rect *intersection)
+{
+ struct b2r2_blt_rect tmp_rect;
+
+ tmp_rect.x = max(rect1->x, rect2->x);
+ tmp_rect.y = max(rect1->y, rect2->y);
+ tmp_rect.width = min(rect1->x + rect1->width, rect2->x + rect2->width)
+ - tmp_rect.x;
+ if (tmp_rect.width < 0)
+ tmp_rect.width = 0;
+ tmp_rect.height =
+ min(rect1->y + rect1->height, rect2->y + rect2->height) -
+ tmp_rect.y;
+ if (tmp_rect.height < 0)
+ tmp_rect.height = 0;
+
+ *intersection = tmp_rect;
+}
+
+
+int b2r2_get_fmt_bpp(enum b2r2_blt_fmt fmt)
+{
+ /*
+ * Currently this function is not used that often but if that changes a
+ * lookup table could make it a lot faster.
+ */
+ switch (fmt) {
+ case B2R2_BLT_FMT_1_BIT_A1:
+ return 1;
+
+ case B2R2_BLT_FMT_8_BIT_A8:
+ return 8;
+
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ return 12;
+
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ case B2R2_BLT_FMT_16_BIT_RGB565:
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ return 16;
+
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ return 24;
+
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ return 32;
+
+ default:
+ b2r2_log_err("%s: Internal error! Format %#x not recognized.\n", __func__, fmt);
+ return 32;
+ }
+}
+
+int b2r2_get_fmt_y_bpp(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ return 8;
+
+ default:
+ b2r2_log_err("%s: Internal error! Non YCbCr format supplied.\n", __func__);
+ return 8;
+ }
+}
+
+
+bool b2r2_is_single_plane_fmt(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_1_BIT_A1:
+ case B2R2_BLT_FMT_8_BIT_A8:
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ case B2R2_BLT_FMT_16_BIT_RGB565:
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool b2r2_is_independent_pixel_fmt(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_1_BIT_A1:
+ case B2R2_BLT_FMT_8_BIT_A8:
+ case B2R2_BLT_FMT_16_BIT_ARGB4444:
+ case B2R2_BLT_FMT_16_BIT_ARGB1555:
+ case B2R2_BLT_FMT_16_BIT_RGB565:
+ case B2R2_BLT_FMT_24_BIT_RGB888:
+ case B2R2_BLT_FMT_24_BIT_ARGB8565:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_32_BIT_ARGB8888:
+ case B2R2_BLT_FMT_32_BIT_ABGR8888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool b2r2_is_ycbcri_fmt(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool b2r2_is_ycbcrsp_fmt(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool b2r2_is_ycbcrp_fmt(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool b2r2_is_ycbcr420_fmt(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool b2r2_is_ycbcr422_fmt(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_Y_CB_Y_CR:
+ case B2R2_BLT_FMT_CB_Y_CR_Y:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool b2r2_is_mb_fmt(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+u32 b2r2_calc_pitch_from_width(s32 width, enum b2r2_blt_fmt fmt)
+{
+ if (b2r2_is_single_plane_fmt(fmt)) {
+ return (u32)b2r2_div_round_up(width *
+ b2r2_get_fmt_bpp(fmt), 8);
+ } else if (b2r2_is_ycbcrsp_fmt(fmt) || b2r2_is_ycbcrp_fmt(fmt)) {
+ return (u32)b2r2_div_round_up(width *
+ b2r2_get_fmt_y_bpp(fmt), 8);
+ } else {
+ b2r2_log_err("%s: Internal error! "
+ "Pitchless format supplied.\n",
+ __func__);
+ return 0;
+ }
+}
+
+u32 b2r2_get_img_pitch(struct b2r2_blt_img *img)
+{
+ if (img->pitch != 0)
+ return img->pitch;
+ else
+ return b2r2_calc_pitch_from_width(img->width, img->fmt);
+}
+
+s32 b2r2_get_img_size(struct b2r2_blt_img *img)
+{
+ if (b2r2_is_single_plane_fmt(img->fmt)) {
+ return (s32)b2r2_get_img_pitch(img) * img->height;
+ } else if (b2r2_is_ycbcrsp_fmt(img->fmt) ||
+ b2r2_is_ycbcrp_fmt(img->fmt)) {
+ s32 y_plane_size;
+
+ y_plane_size = (s32)b2r2_get_img_pitch(img) * img->height;
+
+ if (b2r2_is_ycbcr420_fmt(img->fmt)) {
+ return y_plane_size + y_plane_size / 2;
+ } else if (b2r2_is_ycbcr422_fmt(img->fmt)) {
+ return y_plane_size * 2;
+ } else {
+ b2r2_log_err("%s: Internal error! "
+ "Format %#x not recognized.\n",
+ __func__, img->fmt);
+ return 0;
+ }
+ } else if (b2r2_is_mb_fmt(img->fmt)) {
+ return (img->width * img->height *
+ b2r2_get_fmt_bpp(img->fmt)) / 8;
+ } else {
+ b2r2_log_err("%s: Internal error! "
+ "Format %#x not recognized.\n",
+ __func__, img->fmt);
+ return 0;
+ }
+}
+
+
+s32 b2r2_div_round_up(s32 dividend, s32 divisor)
+{
+ s32 quotient = dividend / divisor;
+ if (dividend % divisor != 0)
+ quotient++;
+
+ return quotient;
+}
+
+bool b2r2_is_aligned(s32 value, s32 alignment)
+{
+ return value % alignment == 0;
+}
+
+s32 b2r2_align_up(s32 value, s32 alignment)
+{
+ s32 remainder = abs(value) % abs(alignment);
+ s32 value_to_add;
+
+ if (remainder > 0) {
+ if (value >= 0)
+ value_to_add = alignment - remainder;
+ else
+ value_to_add = remainder;
+ } else {
+ value_to_add = 0;
+ }
+
+ return value + value_to_add;
+}
diff --git a/drivers/video/b2r2/b2r2_utils.h b/drivers/video/b2r2/b2r2_utils.h
new file mode 100644
index 00000000000..df1a65da644
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_utils.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 utils
+ *
+ * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef _LINUX_DRIVERS_VIDEO_B2R2_UTILS_H_
+#define _LINUX_DRIVERS_VIDEO_B2R2_UTILS_H_
+
+#include <video/b2r2_blt.h>
+
+extern const s32 b2r2_s32_max;
+
+void b2r2_get_img_bounding_rect(struct b2r2_blt_img *img,
+ struct b2r2_blt_rect *bounding_rect);
+
+bool b2r2_is_zero_area_rect(struct b2r2_blt_rect *rect);
+bool b2r2_is_rect_inside_rect(struct b2r2_blt_rect *rect1,
+ struct b2r2_blt_rect *rect2);
+void b2r2_intersect_rects(struct b2r2_blt_rect *rect1,
+ struct b2r2_blt_rect *rect2, struct b2r2_blt_rect *intersection);
+
+int b2r2_get_fmt_bpp(enum b2r2_blt_fmt fmt);
+int b2r2_get_fmt_y_bpp(enum b2r2_blt_fmt fmt);
+
+bool b2r2_is_single_plane_fmt(enum b2r2_blt_fmt fmt);
+bool b2r2_is_independent_pixel_fmt(enum b2r2_blt_fmt fmt);
+bool b2r2_is_ycbcri_fmt(enum b2r2_blt_fmt fmt);
+bool b2r2_is_ycbcrsp_fmt(enum b2r2_blt_fmt fmt);
+bool b2r2_is_ycbcrp_fmt(enum b2r2_blt_fmt fmt);
+bool b2r2_is_ycbcr420_fmt(enum b2r2_blt_fmt fmt);
+bool b2r2_is_ycbcr422_fmt(enum b2r2_blt_fmt fmt);
+bool b2r2_is_mb_fmt(enum b2r2_blt_fmt fmt);
+
+/*
+ * Rounds up if an invalid width causes the pitch to be non byte aligned.
+ */
+u32 b2r2_calc_pitch_from_width(s32 width, enum b2r2_blt_fmt fmt);
+u32 b2r2_get_img_pitch(struct b2r2_blt_img *img);
+s32 b2r2_get_img_size(struct b2r2_blt_img *img);
+
+s32 b2r2_div_round_up(s32 dividend, s32 divisor);
+bool b2r2_is_aligned(s32 value, s32 alignment);
+s32 b2r2_align_up(s32 value, s32 alignment);
+
+#endif
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 55044351889..16fe812724f 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -25,6 +25,7 @@ struct pwm_bl_data {
struct pwm_device *pwm;
struct device *dev;
unsigned int period;
+ unsigned int lth_brightness;
int (*notify)(struct device *,
int brightness);
};
@@ -48,7 +49,9 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
pwm_config(pb->pwm, 0, pb->period);
pwm_disable(pb->pwm);
} else {
- pwm_config(pb->pwm, brightness * pb->period / max, pb->period);
+ brightness = pb->lth_brightness + (brightness *
+ (pb->period - pb->lth_brightness) / max);
+ pwm_config(pb->pwm, brightness, pb->period);
pwm_enable(pb->pwm);
}
return 0;
@@ -92,6 +95,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->period = data->pwm_period_ns;
pb->notify = data->notify;
+ pb->lth_brightness = data->lth_brightness *
+ (data->pwm_period_ns / data->max_brightness);
pb->dev = &pdev->dev;
pb->pwm = pwm_request(data->pwm_id, "backlight");
diff --git a/drivers/video/mcde/Kconfig b/drivers/video/mcde/Kconfig
new file mode 100644
index 00000000000..47a315eb033
--- /dev/null
+++ b/drivers/video/mcde/Kconfig
@@ -0,0 +1,76 @@
+config FB_MCDE
+ tristate "MCDE support"
+ depends on FB
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_SYS_FOPS
+ select HWMEM
+ ---help---
+ This enables support for MCDE based frame buffer driver.
+
+ Please read the file <file:Documentation/fb/mcde.txt>
+
+config MCDE_DISPLAY_GENERIC_DSI
+ tristate "Generic DSI display driver"
+ depends on FB_MCDE
+ depends on MACH_U8500_MOP
+
+config MCDE_DISPLAY_SONY_SY35560_DSI
+ tristate "Sony sy35560 display driver"
+ depends on FB_MCDE
+ depends on MACH_U8500_PDP
+
+config MCDE_DISPLAY_DPI
+ bool "Support for DPI displays within MCDE"
+ depends on FB_MCDE
+ default n
+ ---help---
+ Add this option to choose which DPI display driver for MCDE to include
+
+ DPI (Display Pixel Interface) is a MIPI Alliance standard used for
+ active-matrix LCDs. The DPI uses parallel data lines.
+
+menu "MCDE DPI displays"
+ depends on MCDE_DISPLAY_DPI
+
+config MCDE_DISPLAY_VUIB500_DPI
+ tristate "DPI display driver for the VUIB500 board"
+ ---help---
+ The VUIB500 is an ST-Ericsson user interface board.
+
+endmenu
+
+config MCDE_DISPLAY_AV8100
+ tristate "AV8100 HDMI/CVBS display driver"
+ depends on FB_MCDE
+ select AV8100
+
+config MCDE_DISPLAY_AB8500_DENC
+ tristate "AB8500 CVBS display driver"
+ depends on FB_MCDE
+ select AB8500_DENC
+
+config FB_MCDE_DEBUG
+ bool "MCDE debug messages"
+ depends on FB_MCDE
+ ---help---
+ Say Y here if you want the MCDE driver to output debug messages
+
+config FB_MCDE_VDEBUG
+ bool "MCDE verbose debug messages"
+ depends on FB_MCDE_DEBUG
+ ---help---
+ Say Y here if you want the MCDE driver to output more debug messages
+
+config MCDE_FB_AVOID_REALLOC
+ bool "MCDE early allocate framebuffer"
+ default n
+ depends on FB_MCDE
+ ---help---
+ If you say Y here maximum frame buffer size is allocated and
+ used for all resolutions. If you say N here, the frame buffer is
+ reallocated when resolution is changed. This reallocation might
+ fail because of fragmented memory. Note that this memory will
+ never be deallocated, while the MCDE framebuffer is used.
+
diff --git a/drivers/video/mcde/Makefile b/drivers/video/mcde/Makefile
new file mode 100644
index 00000000000..93097f8961e
--- /dev/null
+++ b/drivers/video/mcde/Makefile
@@ -0,0 +1,16 @@
+
+mcde-objs := mcde_mod.o mcde_hw.o mcde_dss.o mcde_display.o mcde_bus.o mcde_fb.o
+obj-$(CONFIG_FB_MCDE) += mcde.o
+
+obj-$(CONFIG_MCDE_DISPLAY_GENERIC_DSI) += display-generic_dsi.o
+obj-$(CONFIG_MCDE_DISPLAY_SONY_SY35560_DSI) += display-sony_sy35560_dsi.o
+obj-$(CONFIG_MCDE_DISPLAY_VUIB500_DPI) += display-vuib500-dpi.o
+obj-$(CONFIG_MCDE_DISPLAY_AB8500_DENC) += display-ab8500.o
+obj-$(CONFIG_MCDE_DISPLAY_AV8100) += display-av8100.o
+
+ifdef CONFIG_FB_MCDE_DEBUG
+EXTRA_CFLAGS += -DDEBUG
+endif
+ifdef CONFIG_FB_MCDE_VDEBUG
+EXTRA_CFLAGS += -DVERBOSE_DEBUG
+endif
diff --git a/drivers/video/mcde/display-ab8500.c b/drivers/video/mcde/display-ab8500.c
new file mode 100644
index 00000000000..2943976c01d
--- /dev/null
+++ b/drivers/video/mcde/display-ab8500.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * AB8500 display driver
+ *
+ * Author: Marcel Tunnissen <marcel.tuennissen@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <video/mcde_display.h>
+#include <video/mcde_display-ab8500.h>
+#include <mach/ab8500_denc.h>
+
+
+#define AB8500_DISP_TRACE dev_dbg(&ddev->dev, "%s\n", __func__)
+
+static int try_video_mode(struct mcde_display_device *ddev,
+ struct mcde_video_mode *video_mode);
+static int set_video_mode(struct mcde_display_device *ddev,
+ struct mcde_video_mode *video_mode);
+static int set_power_mode(struct mcde_display_device *ddev,
+ enum mcde_display_power_mode power_mode);
+static int on_first_update(struct mcde_display_device *ddev);
+static int display_update(struct mcde_display_device *ddev);
+
+static int __devinit ab8500_probe(struct mcde_display_device *ddev)
+{
+ int ret = 0;
+ struct ab8500_display_platform_data *pdata = ddev->dev.platform_data;
+ struct ab8500_denc_conf *driver_data;
+ AB8500_DISP_TRACE;
+
+ if (pdata == NULL) {
+ dev_err(&ddev->dev, "%s:Platform data missing\n", __func__);
+ return -EINVAL;
+ }
+ if (ddev->port->type != MCDE_PORTTYPE_DPI) {
+ dev_err(&ddev->dev, "%s:Invalid port type %d\n", __func__,
+ ddev->port->type);
+ return -EINVAL;
+ }
+
+ driver_data =
+ kzalloc(sizeof(struct ab8500_denc_conf), GFP_KERNEL);
+
+ if (!driver_data) {
+ dev_err(&ddev->dev, "Failed to allocate driver data\n");
+ return -ENOMEM;
+ }
+
+ dev_set_drvdata(&ddev->dev, driver_data);
+
+ memset(driver_data, 0, sizeof(struct ab8500_denc_conf));
+
+ /* initialise the device */
+ if (pdata->regulator_id) {
+ pdata->regulator = regulator_get(&ddev->dev,
+ pdata->regulator_id);
+ if (IS_ERR(pdata->regulator)) {
+ ret = PTR_ERR(pdata->regulator);
+ dev_warn(&ddev->dev,
+ "%s:Failed to get regulator '%s'\n",
+ __func__, pdata->regulator_id);
+ pdata->regulator = NULL;
+ goto regulator_get_failed;
+ }
+ ret = regulator_enable(pdata->regulator);
+ if (ret < 0) {
+ dev_err(&ddev->dev, "%s:Failed to enable regulator\n",
+ __func__);
+ goto regu_failed;
+ }
+ } else {
+ /* TODO remove as soon as we use a kernel with support
+ * for ab8500 supports regulators */
+ /* enable tv voltage, no lp mode */
+ ab8500_denc_regu_setup(true, false);
+ }
+
+ ddev->try_video_mode = try_video_mode;
+ ddev->set_video_mode = set_video_mode;
+ ddev->set_power_mode = set_power_mode;
+ ddev->on_first_update = on_first_update;
+ ddev->update = display_update;
+ ddev->prepare_for_update = NULL;
+
+ return 0;
+
+regu_failed:
+regulator_get_failed:
+ kfree(driver_data);
+ return ret;
+}
+
+static int __devexit ab8500_remove(struct mcde_display_device *ddev)
+{
+ struct ab8500_display_platform_data *pdata = ddev->dev.platform_data;
+ struct ab8500_denc_conf *driver_data;
+ AB8500_DISP_TRACE;
+
+ if (pdata->regulator)
+ regulator_put(pdata->regulator);
+ driver_data = dev_get_drvdata(&ddev->dev);
+ kfree(driver_data);
+ return 0;
+}
+
+static int ab8500_resume(struct mcde_display_device *ddev)
+{
+ int res;
+ struct ab8500_display_platform_data *pdata = ddev->dev.platform_data;
+ AB8500_DISP_TRACE;
+
+ if (pdata->regulator) {
+ res = regulator_enable(pdata->regulator);
+ if (res < 0) {
+ dev_err(&ddev->dev, "%s:Failed to enable regulator\n",
+ __func__);
+ return res;
+ }
+ } else {
+ /* TODO remove as soon as we use a kernel with support
+ * for ab8500 supports regulators */
+ /* enable tv voltage, no lp mode */
+ ab8500_denc_regu_setup(true, false);
+ }
+
+ ab8500_denc_power_up();
+ ab8500_denc_reset(/* hard = */ true);
+
+ return 0;
+}
+
+static int ab8500_suspend(struct mcde_display_device *ddev, pm_message_t state)
+{
+ int res = 0;
+ struct ab8500_display_platform_data *pdata = ddev->dev.platform_data;
+ AB8500_DISP_TRACE;
+
+ if (pdata->regulator) {
+ res = regulator_disable(pdata->regulator);
+ if (res != 0) {
+ dev_err(&ddev->dev, "%s:Failed to disable regulator\n",
+ __func__);
+ return res;
+ }
+ }
+ ab8500_denc_power_down();
+
+ return 0;
+}
+
+
+static struct mcde_display_driver ab8500_driver = {
+ .probe = ab8500_probe,
+ .remove = ab8500_remove,
+ .suspend = ab8500_suspend,
+ .resume = ab8500_resume,
+ .driver = {
+ .name = "mcde_tv_ab8500",
+ },
+};
+
+static void print_vmode(struct mcde_video_mode *vmode)
+{
+ pr_debug("resolution: %dx%d\n", vmode->xres, vmode->yres);
+ pr_debug(" pixclock: %d\n", vmode->pixclock);
+ pr_debug(" hbp: %d\n", vmode->hbp);
+ pr_debug(" hfp: %d\n", vmode->hfp);
+ pr_debug(" vbp1: %d\n", vmode->vbp1);
+ pr_debug(" vfp1: %d\n", vmode->vfp1);
+ pr_debug(" vbp2: %d\n", vmode->vbp2);
+ pr_debug(" vfp2: %d\n", vmode->vfp2);
+ pr_debug("interlaced: %s\n", vmode->interlaced ? "true" : "false");
+}
+
+static int try_video_mode(
+ struct mcde_display_device *ddev, struct mcde_video_mode *video_mode)
+{
+ AB8500_DISP_TRACE;
+
+ if (ddev == NULL || video_mode == NULL) {
+ dev_warn(&ddev->dev, "%s:ddev = NULL or video_mode = NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (video_mode->xres != 720) {
+ dev_warn(&ddev->dev,
+ "%s:Failed to find video mode x=%d, y=%d\n",
+ __func__, video_mode->xres, video_mode->yres);
+ return -EINVAL;
+ }
+
+
+ /* TODO: move this part to MCDE: mcde_dss_try_video_mode? */
+ /* check for PAL */
+ switch (video_mode->yres) {
+ case 576:
+ /* set including SAV/EAV: */
+ video_mode->hbp = 132;
+ video_mode->hfp = 12;
+ /*
+ * Total nr of active lines: 576
+ * Total nr of blanking lines: 49
+ */
+ video_mode->vbp1 = 22;
+ video_mode->vfp1 = 2;
+ video_mode->vbp2 = 23;
+ video_mode->vfp2 = 2;
+ /* currently only support interlaced */
+ video_mode->interlaced = true;
+ video_mode->pixclock = 37037;
+ break;
+ case 480:
+ /* set including SAV/EAV */
+ video_mode->hbp = 122;
+ video_mode->hfp = 16;
+ /*
+ * Total nr of active lines: 486.
+ * Total nr of blanking lines: 39.
+ */
+ /* Why does the following work? As far as I know the
+ * total nr of vertical blanking lines between the
+ * fields equals to 19 or 20, of which 3 are vfp.
+ */
+ video_mode->vbp1 = 19;
+ video_mode->vfp1 = 3;
+ video_mode->vbp2 = 20;
+ video_mode->vfp2 = 3;
+ /* currently only support interlaced */
+ video_mode->interlaced = true;
+ video_mode->pixclock = 37037;
+ break;
+ default:
+ dev_warn(&ddev->dev,
+ "%s:Failed to find video mode x=%d, y=%d\n",
+ __func__, video_mode->xres, video_mode->yres);
+ return -EINVAL;
+ }
+
+ print_vmode(video_mode);
+
+ return 0;
+
+}
+
+static int set_video_mode(
+ struct mcde_display_device *ddev, struct mcde_video_mode *video_mode)
+{
+ int res;
+ struct ab8500_display_platform_data *pdata = ddev->dev.platform_data;
+ struct ab8500_denc_conf *driver_data =
+ (struct ab8500_denc_conf *)dev_get_drvdata(&ddev->dev);
+ AB8500_DISP_TRACE;
+
+ if (ddev == NULL || video_mode == NULL) {
+ dev_warn(&ddev->dev, "%s:ddev = NULL or video_mode = NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+ ddev->video_mode = *video_mode;
+
+ if (video_mode->xres != 720) {
+ dev_warn(&ddev->dev, "%s:Failed to set video mode x=%d, y=%d\n",
+ __func__, video_mode->xres, video_mode->yres);
+ return -EINVAL;
+ }
+
+ /* check for PAL BDGHI and N */
+ switch (video_mode->yres) {
+ case 576:
+ driver_data->TV_std = TV_STD_PAL_BDGHI;
+ /* TODO: how to choose LOW DEF FILTER */
+ driver_data->cr_filter = TV_CR_PAL_HIGH_DEF_FILTER;
+ /* TODO: PAL N (e.g. uses a setup of 7.5 IRE) */
+ driver_data->black_level_setup = false;
+ break;
+ case 480: /* NTSC, PAL M */
+ /* TODO: PAL M */
+ driver_data->TV_std = TV_STD_NTSC_M;
+ /* TODO: how to choose LOW DEF FILTER */
+ driver_data->cr_filter = TV_CR_NTSC_HIGH_DEF_FILTER;
+ driver_data->black_level_setup = true;
+ break;
+ default:
+ dev_warn(&ddev->dev, "%s:Failed to set video mode x=%d, y=%d\n",
+ __func__, video_mode->xres, video_mode->yres);
+ return -EINVAL;
+ }
+
+
+ driver_data->progressive = !video_mode->interlaced;
+ driver_data->act_output = true;
+ driver_data->test_pattern = false;
+ driver_data->partial_blanking = true;
+ driver_data->blank_all = false;
+ driver_data->suppress_col = false;
+ driver_data->phase_reset_mode = TV_PHASE_RST_MOD_DISABLE;
+ driver_data->dac_enable = false;
+ driver_data->act_dc_output = true;
+
+ set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY);
+ mcde_chnl_set_col_convert(ddev->chnl_state,
+ &pdata->rgb_2_yCbCr_convert);
+ mcde_chnl_stop_flow(ddev->chnl_state);
+ res = mcde_chnl_set_video_mode(ddev->chnl_state, &ddev->video_mode);
+ if (res < 0) {
+ dev_warn(&ddev->dev, "%s:Failed to set video mode on channel\n",
+ __func__);
+
+ return res;
+ }
+ ddev->update_flags |= UPDATE_FLAG_VIDEO_MODE;
+
+ return 0;
+}
+
+static int set_power_mode(struct mcde_display_device *ddev,
+ enum mcde_display_power_mode power_mode)
+{
+ int ret;
+ AB8500_DISP_TRACE;
+
+ /* OFF -> STANDBY */
+ if (ddev->power_mode == MCDE_DISPLAY_PM_OFF &&
+ power_mode != MCDE_DISPLAY_PM_OFF) {
+ dev_vdbg(&ddev->dev, "/* OFF -> STANDBY */\n");
+ if (ddev->platform_enable) {
+ ret = ddev->platform_enable(ddev);
+ if (ret)
+ return ret;
+ }
+ ab8500_denc_power_up();
+ ab8500_denc_reset(/* hard = */ true);
+ ddev->power_mode = MCDE_DISPLAY_PM_STANDBY;
+ }
+ /* STANDBY -> ON */
+ if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY &&
+ power_mode == MCDE_DISPLAY_PM_ON) {
+ dev_vdbg(&ddev->dev, "/* STANDBY -> ON */\n");
+ ddev->power_mode = MCDE_DISPLAY_PM_ON;
+ }
+ /* ON -> STANDBY */
+ if (ddev->power_mode == MCDE_DISPLAY_PM_ON &&
+ power_mode <= MCDE_DISPLAY_PM_STANDBY) {
+ dev_vdbg(&ddev->dev, "/* ON -> STANDBY */\n");
+ ab8500_denc_reset(/* hard = */ false);
+ ddev->power_mode = MCDE_DISPLAY_PM_STANDBY;
+ }
+ /* STANDBY -> OFF */
+ if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY &&
+ power_mode == MCDE_DISPLAY_PM_OFF) {
+ dev_vdbg(&ddev->dev, "/* STANDBY -> OFF */\n");
+ if (ddev->platform_disable) {
+ ret = ddev->platform_disable(ddev);
+ if (ret)
+ return ret;
+ }
+
+ ab8500_denc_power_down();
+ ddev->power_mode = MCDE_DISPLAY_PM_OFF;
+ }
+
+ return 0;
+}
+
+static int on_first_update(struct mcde_display_device *ddev)
+{
+ struct ab8500_denc_conf *driver_data = dev_get_drvdata(&ddev->dev);
+
+ ab8500_denc_conf((struct ab8500_denc_conf *) driver_data);
+ ab8500_denc_conf_plug_detect(true, false, TV_PLUG_TIME_2S);
+ ab8500_denc_mask_int_plug_det(false, false);
+ ddev->first_update = false;
+ return 0;
+}
+
+static int display_update(struct mcde_display_device *ddev)
+{
+ int ret;
+
+ if (ddev->first_update)
+ on_first_update(ddev);
+ if (ddev->power_mode != MCDE_DISPLAY_PM_ON && ddev->set_power_mode) {
+ ret = set_power_mode(ddev, MCDE_DISPLAY_PM_ON);
+ if (ret < 0)
+ goto error;
+ }
+ ret = mcde_chnl_update(ddev->chnl_state, &ddev->update_area);
+ if (ret < 0)
+ goto error;
+out:
+ return ret;
+error:
+ dev_warn(&ddev->dev, "%s:Failed to set power mode to on\n", __func__);
+ goto out;
+}
+
+/* Module init */
+static int __init mcde_display_tvout_ab8500_init(void)
+{
+ pr_debug("%s\n", __func__);
+
+ return mcde_display_driver_register(&ab8500_driver);
+}
+late_initcall(mcde_display_tvout_ab8500_init);
+
+static void __exit mcde_display_tvout_ab8500_exit(void)
+{
+ pr_debug("%s\n", __func__);
+
+ mcde_display_driver_unregister(&ab8500_driver);
+}
+module_exit(mcde_display_tvout_ab8500_exit);
+
+MODULE_AUTHOR("Marcel Tunnissen <marcel.tuennissen@stericsson.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ST-Ericsson MCDE TVout through AB8500 display driver");
diff --git a/drivers/video/mcde/display-av8100.c b/drivers/video/mcde/display-av8100.c
new file mode 100644
index 00000000000..b60dcd2f794
--- /dev/null
+++ b/drivers/video/mcde/display-av8100.c
@@ -0,0 +1,718 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson HDMI display driver
+ *
+ * Author: Per Persson <per-xb-persson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <video/mcde_display.h>
+#include <video/mcde_display-av8100.h>
+#include <video/av8100.h>
+#include <video/hdmi.h>
+
+static int hdmi_try_video_mode(
+ struct mcde_display_device *ddev, struct mcde_video_mode *video_mode);
+static int hdmi_set_video_mode(
+ struct mcde_display_device *ddev, struct mcde_video_mode *video_mode);
+
+static struct mcde_video_mode video_modes_supp[] =
+{
+#ifndef CONFIG_AV8100_SDTV
+ /* 640_480_60_P */
+ {
+ .xres = 640, .yres = 480,
+ .pixclock = 39682,
+ .hbp = 112, .hfp = 48,
+ .vbp1 = 33, .vfp1 = 12
+ },
+ /* 720_480_60_P */
+ {
+ .xres = 720, .yres = 480,
+ .pixclock = 37000,
+ .hbp = 104, .hfp = 34,
+ .vbp1 = 30, .vfp1 = 15
+ },
+ /* 720_576_50_P */
+ {
+ .xres = 720, .yres = 576,
+ .pixclock = 37037,
+ .hbp = 132, .hfp = 12,
+ .vbp1 = 44, .vfp1 = 5
+ },
+ /* 1280_720_60_P */
+ {
+ .xres = 1280, .yres = 720,
+ .pixclock = 13468,
+ .hbp = 256, .hfp = 114,
+ .vbp1 = 20, .vfp1 = 10
+ },
+ /* 1280_720_50_P */
+ {
+ .xres = 1280, .yres = 720,
+ .pixclock = 13468,
+ .hbp = 260, .hfp = 440,
+ .vbp1 = 25, .vfp1 = 5
+ },
+ /* 1920_1080_30_P */
+ {
+ .xres = 1920, .yres = 1080,
+ .pixclock = 13468,
+ .hbp = 189, .hfp = 91,
+ .vbp1 = 36, .vfp1 = 9
+ },
+ /* 1920_1080_24_P */
+ {
+ .xres = 1920, .yres = 1080,
+ .pixclock = 13468,
+ .hbp = 170, .hfp = 660,
+ .vbp1 = 36, .vfp1 = 9
+ },
+ /* 1920_1080_25_P */
+ {
+ .xres = 1920, .yres = 1080,
+ .pixclock = 13468,
+ .hbp = 192, .hfp = 528,
+ .vbp1 = 36, .vfp1 = 9
+ },
+#endif /* CONFIG_AV8100_SDTV */
+ /* 720_480_60_I) */
+ {
+ .xres = 720, .yres = 480,
+ .pixclock = 74074,
+ .hbp = 126, .hfp = 12,
+ .vbp1 = 44, .vfp1 = 1,
+ .interlaced = true,
+ },
+ /* 720_576_50_I) */
+ {
+ .xres = 720, .yres = 576,
+ .pixclock = 74074,
+ .hbp = 132, .hfp = 12,
+ .vbp1 = 44, .vfp1 = 5,
+ .interlaced = true,
+ },
+#ifndef CONFIG_AV8100_SDTV
+ /* 1920_1080_50_I) */
+ {
+ .xres = 1920, .yres = 1080,
+ .pixclock = 13468,
+ .hbp = 192, .hfp = 528,
+ .vbp1 = 20, .vfp1 = 25,
+ .interlaced = true,
+ },
+ /* 1920_1080_60_I) */
+ {
+ .xres = 1920, .yres = 1080,
+ .pixclock = 13468,
+ .hbp = 192, .hfp = 88,
+ .vbp1 = 20, .vfp1 = 25,
+ .interlaced = true,
+ },
+#endif /* CONFIG_AV8100_SDTV */
+};
+
+#define AV8100_MAX_LEVEL 255
+
+static int hdmi_try_video_mode(
+ struct mcde_display_device *ddev, struct mcde_video_mode *video_mode)
+{
+ int index = 0;
+ int match_level = AV8100_MAX_LEVEL;
+ int found_index = -1;
+
+ if (ddev == NULL || video_mode == NULL) {
+ pr_warning("%s:ddev = NULL or video_mode = NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_vdbg(&ddev->dev, "%s\n", __func__);
+
+#ifdef CONFIG_AV8100_SDTV
+ video_mode->interlaced = true;
+#endif /* CONFIG_AV8100_SDTV */
+
+ while (index < ARRAY_SIZE(video_modes_supp)) {
+ /* 1. Check if all parameters match */
+ if (memcmp(video_mode, &video_modes_supp[index],
+ sizeof(struct mcde_video_mode)) == 0) {
+ match_level = 1;
+ found_index = index;
+ break;
+ }
+
+ /* 2. Check if xres,yres,htot,vtot,interlaced match */
+ if ((match_level > 2) &&
+ (video_mode->xres == video_modes_supp[index].xres) &&
+ (video_mode->yres == video_modes_supp[index].yres) &&
+ ((video_mode->xres + video_mode->hbp +
+ video_mode->hfp) ==
+ (video_modes_supp[index].xres +
+ video_modes_supp[index].hbp +
+ video_modes_supp[index].hfp)) &&
+ ((video_mode->yres + video_mode->vbp1 +
+ video_mode->vbp2 + video_mode->vfp1 +
+ video_mode->vfp2) ==
+ (video_modes_supp[index].yres +
+ video_modes_supp[index].vbp1 +
+ video_modes_supp[index].vbp2 +
+ video_modes_supp[index].vfp1 +
+ video_modes_supp[index].vfp2)) &&
+ (video_mode->interlaced ==
+ video_modes_supp[index].interlaced)) {
+ match_level = 2;
+ found_index = index;
+ }
+
+ /* 3. Check if xres,yres,pixelclock,interlaced match */
+ if ((match_level > 3) &&
+ (video_mode->xres == video_modes_supp[index].xres) &&
+ (video_mode->yres == video_modes_supp[index].yres) &&
+ (video_mode->interlaced ==
+ video_modes_supp[index].interlaced) &&
+ (video_mode->pixclock ==
+ video_modes_supp[index].pixclock)) {
+ match_level = 3;
+ found_index = index;
+ }
+
+ /* 4. Check if xres,yres,interlaced match */
+ if ((match_level > 4) &&
+ (video_mode->xres == video_modes_supp[index].xres) &&
+ (video_mode->yres == video_modes_supp[index].yres) &&
+ (video_mode->interlaced ==
+ video_modes_supp[index].interlaced)) {
+ match_level = 4;
+ found_index = index;
+ }
+
+ index++;
+ }
+
+ if (found_index == -1) {
+ dev_dbg(&ddev->dev, "video_mode not accepted\n");
+ dev_dbg(&ddev->dev, "xres:%d yres:%d pixclock:%d hbp:%d hfp:%d "
+ "vfp1:%d vfp2:%d vbp1:%d vbp2:%d intlcd:%d\n",
+ video_mode->xres, video_mode->yres,
+ video_mode->pixclock, video_mode->hbp,
+ video_mode->hfp, video_mode->vfp1, video_mode->vfp2,
+ video_mode->vbp1, video_mode->vbp2,
+ video_mode->interlaced);
+ return -EINVAL;
+ }
+
+ memset(video_mode, 0, sizeof(struct mcde_video_mode));
+ memcpy(video_mode, &video_modes_supp[found_index],
+ sizeof(struct mcde_video_mode));
+
+ dev_dbg(&ddev->dev, "%s:HDMI video_mode %d chosen. Level:%d\n",
+ __func__, found_index, match_level);
+
+ return 0;
+}
+
+static int hdmi_set_video_mode(
+ struct mcde_display_device *dev, struct mcde_video_mode *video_mode)
+{
+ int ret;
+ bool update = 0;
+ union av8100_configuration av8100_config;
+ struct mcde_display_hdmi_platform_data *pdata = dev->dev.platform_data;
+ struct av8100_status status;
+
+ /* TODO check video_mode_params */
+ if (dev == NULL || video_mode == NULL) {
+ pr_warning("%s:ddev = NULL or video_mode = NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_vdbg(&dev->dev, "%s:\n", __func__);
+ dev_vdbg(&dev->dev, "%s:xres:%d yres:%d hbp:%d hfp:%d vbp1:%d vfp1:%d "
+ "vbp2:%d vfp2:%d interlaced:%d\n", __func__,
+ video_mode->xres,
+ video_mode->yres,
+ video_mode->hbp,
+ video_mode->hfp,
+ video_mode->vbp1,
+ video_mode->vfp1,
+ video_mode->vbp2,
+ video_mode->vfp2,
+ video_mode->interlaced);
+
+ memset(&(dev->video_mode), 0, sizeof(struct mcde_video_mode));
+ memcpy(&(dev->video_mode), video_mode, sizeof(struct mcde_video_mode));
+
+ if (dev->port->pixel_format == MCDE_PORTPIXFMT_DSI_YCBCR422)
+ mcde_chnl_set_col_convert(dev->chnl_state,
+ &pdata->rgb_2_yCbCr_convert);
+ mcde_chnl_stop_flow(dev->chnl_state);
+
+ ret = mcde_chnl_set_video_mode(dev->chnl_state, &dev->video_mode);
+ if (ret < 0) {
+ dev_warn(&dev->dev, "Failed to set video mode\n");
+ return ret;
+ }
+
+ /* TODO: We shouldn't need to shutdown */
+ status = av8100_status_get();
+ if (status.av8100_state >= AV8100_OPMODE_STANDBY) {
+ /* Disable interrupts */
+ ret = av8100_disable_interrupt();
+ if (ret) {
+ dev_err(&dev->dev,
+ "%s:av8100_disable_interrupt failed\n",
+ __func__);
+ return ret;
+ }
+
+ ret = av8100_powerdown();
+ if (ret) {
+ dev_err(&dev->dev, "av8100_powerdown failed\n");
+ return ret;
+ }
+
+ /* TODO: What delay is needed here */
+ msleep(10);
+ }
+
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_STANDBY) {
+ ret = av8100_powerup();
+ if (ret) {
+ dev_err(&dev->dev, "av8100_powerup failed\n");
+ return ret;
+ }
+
+ ret = av8100_download_firmware(NULL, 0, I2C_INTERFACE);
+ if (ret) {
+ dev_err(&dev->dev, "av8100_download_firmware failed\n");
+ return ret;
+ }
+ }
+
+ /* Get current av8100 video output format */
+ ret = av8100_conf_get(AV8100_COMMAND_VIDEO_OUTPUT_FORMAT,
+ &av8100_config);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_get "
+ "AV8100_COMMAND_VIDEO_OUTPUT_FORMAT failed\n",
+ __func__);
+ return ret;
+ }
+
+ av8100_config.video_output_format.video_output_cea_vesa =
+/* TODO: Remove #ifdefs in driver code. This is a dynamic property! */
+#ifdef CONFIG_AV8100_SDTV
+ dev->video_mode.yres == 576 ? AV8100_CEA21_22_576I_PAL_50HZ
+ : AV8100_CEA6_7_NTSC_60HZ;
+#else
+ av8100_video_output_format_get(
+ dev->video_mode.xres,
+ dev->video_mode.yres,
+ dev->video_mode.xres +
+ dev->video_mode.hbp + dev->video_mode.hfp,
+ dev->video_mode.yres +
+ dev->video_mode.vbp1 + dev->video_mode.vfp1 +
+ dev->video_mode.vbp2 + dev->video_mode.vfp2,
+ dev->video_mode.pixclock,
+ dev->video_mode.interlaced);
+#endif
+ if (AV8100_VIDEO_OUTPUT_CEA_VESA_MAX ==
+ av8100_config.video_output_format.video_output_cea_vesa) {
+ dev_err(&dev->dev, "%s:video output format not found "
+ "\n", __func__);
+ return ret;
+ }
+
+ ret = av8100_conf_prep(AV8100_COMMAND_VIDEO_OUTPUT_FORMAT,
+ &av8100_config);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_prep "
+ "AV8100_COMMAND_VIDEO_OUTPUT_FORMAT failed\n",
+ __func__);
+ return ret;
+ }
+
+ /* Get current av8100 video input format */
+ ret = av8100_conf_get(AV8100_COMMAND_VIDEO_INPUT_FORMAT,
+ &av8100_config);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_get "
+ "AV8100_COMMAND_VIDEO_INPUT_FORMAT failed\n",
+ __func__);
+ return ret;
+ }
+
+ /* Set correct av8100 video input pixel format */
+ switch (dev->port->pixel_format) {
+ case MCDE_PORTPIXFMT_DSI_16BPP:
+ default:
+ av8100_config.video_input_format.input_pixel_format =
+ AV8100_INPUT_PIX_RGB565;
+ break;
+ case MCDE_PORTPIXFMT_DSI_18BPP:
+ av8100_config.video_input_format.input_pixel_format =
+ AV8100_INPUT_PIX_RGB666;
+ break;
+ case MCDE_PORTPIXFMT_DSI_18BPP_PACKED:
+ av8100_config.video_input_format.input_pixel_format =
+ AV8100_INPUT_PIX_RGB666P;
+ break;
+ case MCDE_PORTPIXFMT_DSI_24BPP:
+ av8100_config.video_input_format.input_pixel_format =
+ AV8100_INPUT_PIX_RGB888;
+ break;
+ case MCDE_PORTPIXFMT_DSI_YCBCR422:
+ av8100_config.video_input_format.input_pixel_format =
+ /*
+ * The following is expected:
+ * AV8100_INPUT_PIX_YCBCR422;
+ * However 565 is used for now and the colour converter
+ * is used to transform the correct colour.
+ */
+ AV8100_INPUT_PIX_RGB565;
+ break;
+ }
+
+ /* Set ui_x4 */
+ av8100_config.video_input_format.ui_x4 = dev->port->phy.dsi.ui;
+
+ ret = av8100_conf_prep(AV8100_COMMAND_VIDEO_INPUT_FORMAT,
+ &av8100_config);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_prep "
+ "AV8100_COMMAND_VIDEO_INPUT_FORMAT failed\n",
+ __func__);
+ return ret;
+ }
+
+ ret = av8100_conf_w(AV8100_COMMAND_VIDEO_INPUT_FORMAT,
+ NULL, NULL, I2C_INTERFACE);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_w "
+ "AV8100_COMMAND_VIDEO_INPUT_FORMAT failed\n",
+ __func__);
+ return ret;
+ }
+
+/* TODO: Remove #ifdefs in driver code. This is a dynamic property! */
+#ifdef CONFIG_AV8100_SDTV
+ if (dev->port->pixel_format != MCDE_PORTPIXFMT_DSI_YCBCR422) {
+ av8100_config.color_space_conversion_format =
+ col_cvt_rgb_to_denc;
+ } else {
+ av8100_config.color_space_conversion_format =
+ col_cvt_yuv422_to_denc;
+ }
+#else
+ if (dev->port->pixel_format == MCDE_PORTPIXFMT_DSI_YCBCR422) {
+ av8100_config.color_space_conversion_format =
+ col_cvt_yuv422_to_rgb;
+ } else {
+ av8100_config.color_space_conversion_format =
+ col_cvt_identity;
+ }
+#endif
+
+ ret = av8100_conf_prep(
+ AV8100_COMMAND_COLORSPACECONVERSION,
+ &av8100_config);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_configuration_prepare "
+ "AV8100_COMMAND_COLORSPACECONVERSION failed\n",
+ __func__);
+ return ret;
+ }
+
+ ret = av8100_conf_w(
+ AV8100_COMMAND_COLORSPACECONVERSION,
+ NULL, NULL, I2C_INTERFACE);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_w "
+ "AV8100_COMMAND_COLORSPACECONVERSION failed\n",
+ __func__);
+ return ret;
+ }
+
+ /* Set video output format */
+ ret = av8100_conf_w(AV8100_COMMAND_VIDEO_OUTPUT_FORMAT,
+ NULL, NULL, I2C_INTERFACE);
+ if (ret) {
+ dev_err(&dev->dev, "av8100_conf_w failed\n");
+ return ret;
+ }
+
+ /* Set audio input format */
+ ret = av8100_conf_w(AV8100_COMMAND_AUDIO_INPUT_FORMAT,
+ NULL, NULL, I2C_INTERFACE);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_w "
+ "AV8100_COMMAND_AUDIO_INPUT_FORMAT failed\n",
+ __func__);
+ return ret;
+ }
+
+ /* Get current av8100 video denc settings format */
+ ret = av8100_conf_get(AV8100_COMMAND_DENC,
+ &av8100_config);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_get "
+ "AV8100_COMMAND_DENC failed\n", __func__);
+ return ret;
+ }
+#ifdef CONFIG_AV8100_SDTV
+ update = true;
+ if (dev->video_mode.yres == 576) {
+ av8100_config.denc_format.standard_selection = AV8100_PAL_BDGHI;
+ av8100_config.denc_format.cvbs_video_format = AV8100_CVBS_625;
+ } else {
+ av8100_config.denc_format.standard_selection = AV8100_NTSC_M;
+ av8100_config.denc_format.cvbs_video_format = AV8100_CVBS_525;
+ }
+#else
+ update = (av8100_config.denc_format.enable != 0);
+#endif
+
+ if (update) {
+#ifdef CONFIG_AV8100_SDTV
+ av8100_config.denc_format.enable = 1;
+#else
+ av8100_config.denc_format.enable = 0;
+#endif
+ ret = av8100_conf_prep(AV8100_COMMAND_DENC,
+ &av8100_config);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_prep "
+ "AV8100_COMMAND_DENC failed\n", __func__);
+ return ret;
+ }
+
+ /* TODO: prepare depending on OUT fmt */
+ ret = av8100_conf_w(AV8100_COMMAND_DENC,
+ NULL, NULL, I2C_INTERFACE);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_w "
+ "AV8100_COMMAND_DENC failed\n", __func__);
+ return ret;
+ }
+ }
+
+ dev->update_flags |= UPDATE_FLAG_VIDEO_MODE;
+ dev->first_update = true;
+
+ return 0;
+}
+
+static int hdmi_set_pixel_format(
+ struct mcde_display_device *ddev, enum mcde_ovly_pix_fmt format)
+{
+ int ret;
+
+ ddev->pixel_format = format;
+ mcde_chnl_stop_flow(ddev->chnl_state);
+ ret = mcde_chnl_set_pixel_format(ddev->chnl_state,
+ ddev->port->pixel_format);
+ if (ret < 0) {
+ dev_warn(&ddev->dev, "%s:Failed to set pixel format = %d\n",
+ __func__, format);
+ return ret;
+ }
+
+ ddev->update_flags |= UPDATE_FLAG_PIXEL_FORMAT;
+
+ return 0;
+}
+
+static int hdmi_apply_config(struct mcde_display_device *ddev)
+{
+ int ret;
+
+ if (!ddev->update_flags)
+ return 0;
+
+ ret = mcde_chnl_apply(ddev->chnl_state);
+ if (ret < 0) {
+ dev_warn(&ddev->dev, "%s:Failed to apply to channel\n",
+ __func__);
+ return ret;
+ }
+ ddev->update_flags = 0;
+
+ return 0;
+}
+
+static int hdmi_on_first_update(struct mcde_display_device *dev)
+{
+ int ret;
+ union av8100_configuration av8100_config;
+
+ dev->first_update = false;
+
+ /* Get current av8100 video denc settings format */
+ ret = av8100_conf_get(AV8100_COMMAND_DENC,
+ &av8100_config);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_get "
+ "AV8100_COMMAND_DENC failed\n", __func__);
+ return ret;
+ }
+
+ /*
+ * Avoid simultaneous output of DENC and HDMI.
+ * Only one of them should be enabled.
+ */
+ if (av8100_config.denc_format.enable)
+ av8100_config.hdmi_format.hdmi_mode = AV8100_HDMI_OFF;
+ else
+ av8100_config.hdmi_format.hdmi_mode = AV8100_HDMI_ON;
+
+ av8100_config.hdmi_format.hdmi_format = AV8100_HDMI;
+ av8100_config.hdmi_format.dvi_format = AV8100_DVI_CTRL_CTL0;
+
+ ret = av8100_conf_prep(AV8100_COMMAND_HDMI,
+ &av8100_config);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_prep "
+ "AV8100_COMMAND_HDMI failed\n", __func__);
+ return ret;
+ }
+
+ /* Enable interrupts */
+ ret = av8100_enable_interrupt();
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_enable_interrupt failed\n",
+ __func__);
+ return ret;
+ }
+
+ ret = av8100_conf_w(AV8100_COMMAND_HDMI, NULL,
+ NULL, I2C_INTERFACE);
+ if (ret) {
+ dev_err(&dev->dev, "%s:av8100_conf_w "
+ "AV8100_COMMAND_HDMI failed\n", __func__);
+ }
+
+ return ret;
+}
+
+static int __devinit hdmi_probe(struct mcde_display_device *dev)
+{
+ struct mcde_display_hdmi_platform_data *pdata =
+ dev->dev.platform_data;
+
+ if (pdata == NULL) {
+ dev_err(&dev->dev, "%s:Platform data missing\n", __func__);
+ return -EINVAL;
+ }
+
+ if (dev->port->type != MCDE_PORTTYPE_DSI) {
+ dev_err(&dev->dev, "%s:Invalid port type %d\n",
+ __func__, dev->port->type);
+ return -EINVAL;
+ }
+
+ /* DSI use clock continous mode if AV8100_CHIPVER_1 > 1 */
+ if (av8100_ver_get() > AV8100_CHIPVER_1)
+ dev->port->phy.dsi.clk_cont = true;
+
+ dev->prepare_for_update = NULL;
+ dev->on_first_update = hdmi_on_first_update;
+ dev->try_video_mode = hdmi_try_video_mode;
+ dev->set_video_mode = hdmi_set_video_mode;
+ dev->apply_config = hdmi_apply_config;
+ dev->set_pixel_format = hdmi_set_pixel_format;
+
+ dev_info(&dev->dev, "HDMI display probed\n");
+
+ return 0;
+}
+
+static int __devexit hdmi_remove(struct mcde_display_device *dev)
+{
+ struct mcde_display_hdmi_platform_data *pdata =
+ dev->dev.platform_data;
+
+ dev->set_power_mode(dev, MCDE_DISPLAY_PM_OFF);
+
+ if (pdata->hdmi_platform_enable) {
+ if (pdata->regulator)
+ regulator_put(pdata->regulator);
+ if (pdata->reset_gpio) {
+ gpio_direction_input(pdata->reset_gpio);
+ gpio_free(pdata->reset_gpio);
+ }
+ }
+
+ return 0;
+}
+
+static int hdmi_resume(struct mcde_display_device *ddev)
+{
+ int ret;
+
+ ret = av8100_powerup();
+ if (ret) {
+ dev_err(&ddev->dev, "%s:av8100_powerup failed\n", __func__);
+ return ret;
+ }
+
+ ret = av8100_download_firmware(NULL, 0, I2C_INTERFACE);
+ if (ret) {
+ dev_err(&ddev->dev, "%s:av8100_download_firmware failed\n",
+ __func__);
+ }
+
+ return ret;
+}
+
+static int hdmi_suspend(struct mcde_display_device *ddev, pm_message_t state)
+{
+ int ret;
+
+ ret = av8100_powerdown();
+ if (ret)
+ dev_err(&ddev->dev, "%s:av8100_powerdown failed\n", __func__);
+
+ return ret;
+}
+
+static struct mcde_display_driver hdmi_driver = {
+ .probe = hdmi_probe,
+ .remove = hdmi_remove,
+ .suspend = hdmi_suspend,
+ .resume = hdmi_resume,
+ .driver = {
+ .name = "av8100_hdmi",
+ },
+};
+
+/* Module init */
+static int __init mcde_display_hdmi_init(void)
+{
+ pr_info("%s\n", __func__);
+
+ return mcde_display_driver_register(&hdmi_driver);
+
+}
+late_initcall(mcde_display_hdmi_init);
+
+static void __exit mcde_display_hdmi_exit(void)
+{
+ pr_info("%s\n", __func__);
+
+ mcde_display_driver_unregister(&hdmi_driver);
+}
+module_exit(mcde_display_hdmi_exit);
+
+MODULE_AUTHOR("Per Persson <per.xb.persson@stericsson.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ST-Ericsson hdmi display driver");
diff --git a/drivers/video/mcde/display-generic_dsi.c b/drivers/video/mcde/display-generic_dsi.c
new file mode 100644
index 00000000000..c42cb85d395
--- /dev/null
+++ b/drivers/video/mcde/display-generic_dsi.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson MCDE generic DCS display driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+
+#include <video/mcde_display.h>
+#include <video/mcde_display-generic_dsi.h>
+
+static int generic_platform_enable(struct mcde_display_device *dev)
+{
+ struct mcde_display_generic_platform_data *pdata =
+ dev->dev.platform_data;
+
+ dev_dbg(&dev->dev, "%s: Reset & power on generic display\n", __func__);
+
+ if (pdata->regulator) {
+ if (regulator_enable(pdata->regulator) < 0) {
+ dev_err(&dev->dev, "%s:Failed to enable regulator\n"
+ , __func__);
+ return -EINVAL;
+ }
+ }
+ if (pdata->reset_gpio)
+ gpio_set_value(pdata->reset_gpio, pdata->reset_high);
+ mdelay(pdata->reset_delay);
+ if (pdata->reset_gpio)
+ gpio_set_value(pdata->reset_gpio, !pdata->reset_high);
+
+ return 0;
+}
+
+static int generic_platform_disable(struct mcde_display_device *dev)
+{
+ struct mcde_display_generic_platform_data *pdata =
+ dev->dev.platform_data;
+
+ dev_dbg(&dev->dev, "%s:Reset & power off generic display\n", __func__);
+
+ if (pdata->regulator) {
+ if (regulator_disable(pdata->regulator) < 0) {
+ dev_err(&dev->dev, "%s:Failed to disable regulator\n"
+ , __func__);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int __devinit generic_probe(struct mcde_display_device *dev)
+{
+ int ret = 0;
+ struct mcde_display_generic_platform_data *pdata =
+ dev->dev.platform_data;
+
+ if (pdata == NULL) {
+ dev_err(&dev->dev, "%s:Platform data missing\n", __func__);
+ return -EINVAL;
+ }
+
+ if (dev->port->type != MCDE_PORTTYPE_DSI) {
+ dev_err(&dev->dev,
+ "%s:Invalid port type %d\n",
+ __func__, dev->port->type);
+ return -EINVAL;
+ }
+
+ if (!dev->platform_enable && !dev->platform_disable) {
+ pdata->generic_platform_enable = true;
+ if (pdata->reset_gpio) {
+ ret = gpio_request(pdata->reset_gpio, NULL);
+ if (ret) {
+ dev_warn(&dev->dev,
+ "%s:Failed to request gpio %d\n",
+ __func__, pdata->reset_gpio);
+ goto gpio_request_failed;
+ }
+ gpio_direction_output(pdata->reset_gpio,
+ !pdata->reset_high);
+ }
+ if (pdata->regulator_id) {
+ pdata->regulator = regulator_get(NULL,
+ pdata->regulator_id);
+ if (IS_ERR(pdata->regulator)) {
+ ret = PTR_ERR(pdata->regulator);
+ dev_warn(&dev->dev,
+ "%s:Failed to get regulator '%s'\n",
+ __func__, pdata->regulator_id);
+ pdata->regulator = NULL;
+ goto regulator_get_failed;
+ }
+ regulator_set_voltage(pdata->regulator,
+ pdata->min_supply_voltage,
+ pdata->max_supply_voltage);
+ /*
+ * When u-boot has display a startup screen.
+ * U-boot has turned on display power however the
+ * regulator framework does not know about that
+ * This is the case here, the display driver has to
+ * enable the regulator for the display.
+ */
+ if (dev->power_mode == MCDE_DISPLAY_PM_STANDBY) {
+ ret = regulator_enable(pdata->regulator);
+ if (ret < 0) {
+ dev_err(&dev->dev,
+ "%s:Failed to enable regulator\n"
+ , __func__);
+ goto regulator_enable_failed;
+ }
+ }
+ }
+ }
+
+ /* TODO: Remove when DSI send command uses interrupts */
+ dev->prepare_for_update = NULL;
+ dev->platform_enable = generic_platform_enable,
+ dev->platform_disable = generic_platform_disable,
+
+ dev_info(&dev->dev, "Generic display probed\n");
+
+ goto out;
+regulator_enable_failed:
+regulator_get_failed:
+ if (pdata->generic_platform_enable && pdata->reset_gpio)
+ gpio_free(pdata->reset_gpio);
+gpio_request_failed:
+out:
+ return ret;
+}
+
+static int __devexit generic_remove(struct mcde_display_device *dev)
+{
+ struct mcde_display_generic_platform_data *pdata =
+ dev->dev.platform_data;
+
+ dev->set_power_mode(dev, MCDE_DISPLAY_PM_OFF);
+
+ if (!pdata->generic_platform_enable)
+ return 0;
+
+ if (pdata->regulator)
+ regulator_put(pdata->regulator);
+ if (pdata->reset_gpio) {
+ gpio_direction_input(pdata->reset_gpio);
+ gpio_free(pdata->reset_gpio);
+ }
+
+ return 0;
+}
+
+static int generic_resume(struct mcde_display_device *ddev)
+{
+ int ret;
+
+ /* set_power_mode will handle call platform_enable */
+ ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY);
+ if (ret < 0)
+ dev_warn(&ddev->dev, "%s:Failed to resume display\n"
+ , __func__);
+ return ret;
+}
+
+static int generic_suspend(struct mcde_display_device *ddev, pm_message_t state)
+{
+ int ret;
+
+ /* set_power_mode will handle call platform_disable */
+ ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF);
+ if (ret < 0)
+ dev_warn(&ddev->dev, "%s:Failed to suspend display\n"
+ , __func__);
+ return ret;
+}
+
+static struct mcde_display_driver generic_driver = {
+ .probe = generic_probe,
+ .remove = generic_remove,
+ .suspend = generic_suspend,
+ .resume = generic_resume,
+ .driver = {
+ .name = "mcde_disp_generic",
+ },
+};
+
+/* Module init */
+static int __init mcde_display_generic_init(void)
+{
+ pr_info("%s\n", __func__);
+
+ return mcde_display_driver_register(&generic_driver);
+}
+module_init(mcde_display_generic_init);
+
+static void __exit mcde_display_generic_exit(void)
+{
+ pr_info("%s\n", __func__);
+
+ mcde_display_driver_unregister(&generic_driver);
+}
+module_exit(mcde_display_generic_exit);
+
+MODULE_AUTHOR("Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ST-Ericsson MCDE generic DCS display driver");
diff --git a/drivers/video/mcde/display-sony_sy35560_dsi.c b/drivers/video/mcde/display-sony_sy35560_dsi.c
new file mode 100644
index 00000000000..28a36b98c77
--- /dev/null
+++ b/drivers/video/mcde/display-sony_sy35560_dsi.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * ST-Ericsson MCDE Sony sy35560 DCS display driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+
+#include <video/mcde_dss.h>
+#include <video/mcde_display.h>
+#include <video/mcde_display-sony_sy35560_dsi.h>
+
+static int counter = 1;
+
+/*
+ * Work queue function for ESD check
+ *
+ * read display registers and perform power off/on/init sequence
+ * if register value indicate HW failure
+ */
+static void sony_sy35560_esd_work_fn(struct work_struct *work)
+{
+ u8 value;
+ struct sony_sy35560_device *dev = container_of(work,
+ struct sony_sy35560_device,
+ esd_work.work);
+
+
+ mcde_dsi_dcs_write(((struct mcde_display_device *)dev)->chnl_state,
+ 0x00, &value, 1);
+ pr_info("%s: %d) Read register 0x00, value 0x%.2X\n",
+ __func__, counter, value);
+
+ /* for now there are no registers available for ESD status check
+ * just perform power off/on/init every 4th work queue task
+ */
+
+ if (counter % 4 == 0) {
+ bool vsync_enabled;
+
+ pr_info("%s:Resetting display....", __func__);
+
+ /* get current display state */
+ vsync_enabled = ((struct mcde_display_device *)dev)->
+ get_synchronized_update(
+ (struct mcde_display_device *)dev);
+
+ /* wait a while to make sure finish refresh before resetting */
+ mdelay(10);
+
+ ((struct mcde_display_device *)dev)->set_power_mode(
+ (struct mcde_display_device *)dev,
+ MCDE_DISPLAY_PM_OFF);
+ ((struct mcde_display_device *)dev)->set_power_mode(
+ (struct mcde_display_device *)dev,
+ MCDE_DISPLAY_PM_STANDBY);
+
+ if (vsync_enabled) {
+ u8 m = 0;
+ mcde_dsi_dcs_write(
+ ((struct mcde_display_device *)dev)->chnl_state,
+ DCS_CMD_SET_TEAR_ON, &m, 1);
+ mcde_dss_set_synchronized_update(
+ (struct mcde_display_device *)dev, 0);
+
+ /* refresh display */
+ ((struct mcde_display_device *)dev)->update(
+ (struct mcde_display_device *)dev);
+
+ mcde_dss_set_synchronized_update(
+ (struct mcde_display_device *)dev, 1);
+ } else {
+ /* need to wait a while before turning on the display */
+ mdelay(5);
+
+ ((struct mcde_display_device *)dev)->set_power_mode(
+ (struct mcde_display_device *)dev,
+ MCDE_DISPLAY_PM_ON);
+ }
+ }
+ counter++;
+
+ queue_delayed_work(((struct sony_sy35560_device *)dev)->esd_wq,
+ &(((struct sony_sy35560_device *)dev)->esd_work),
+ SONY_SY35560_ESD_CHECK_PERIOD);
+}
+
+static int __devinit sony_sy35560_probe(struct mcde_display_device *dev)
+{
+ struct mcde_chnl_state *chnl;
+
+ u32 id;
+ u8 id1, id2, id3;
+ int len = 1;
+ int ret = 0;
+ int readret = 0;
+
+ /* create a workqueue for ESD status check */
+ ((struct sony_sy35560_device *)dev)->esd_wq =
+ create_singlethread_workqueue("sony_esd");
+ if (((struct sony_sy35560_device *)dev)->esd_wq == NULL) {
+ dev_warn(&dev->dev, "can't create ESD workqueue\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ INIT_DELAYED_WORK(&(((struct sony_sy35560_device *)dev)->esd_work),
+ sony_sy35560_esd_work_fn);
+
+ /* Acquire MCDE resources */
+ chnl = mcde_chnl_get(dev->chnl_id, dev->fifo, dev->port);
+ if (IS_ERR(chnl)) {
+ ret = PTR_ERR(chnl);
+ dev_warn(&dev->dev, "Failed to acquire MCDE channel\n");
+ goto out;
+ }
+
+ /* plugnplay: use registers DAh, DBh and DCh to detect display */
+ readret = mcde_dsi_dcs_read(chnl, 0xDA, &id1, &len);
+ if (!readret)
+ readret = mcde_dsi_dcs_read(chnl, 0xDB, &id2, &len);
+ if (!readret)
+ readret = mcde_dsi_dcs_read(chnl, 0xDC, &id3, &len);
+
+ if (readret) {
+ dev_info(&dev->dev,
+ "mcde_dsi_dcs_read failed to read display ID\n");
+ goto read_fail;
+ }
+
+ id = (id3 << 16) | (id2 << 8) | id1;
+
+ switch (id) {
+ case 0x018101:
+ dev_info(&dev->dev,
+ "Cygnus Cut1 display (ID 0x%.6X) probed\n", id);
+ /* add display specific initialization here */
+ break;
+
+ case 0x028101:
+ dev_info(&dev->dev,
+ "Cygnus Cut2 display (ID 0x%.6X) probed\n", id);
+ /* add display specific initialization here */
+ break;
+
+ default:
+ dev_info(&dev->dev,
+ "Display with id 0x%.6X probed\n", id);
+ break;
+ }
+
+read_fail:
+ /* close MCDE channel */
+ mcde_chnl_put(chnl);
+ chnl = NULL;
+out:
+ return ret;
+}
+
+static int __devexit sony_sy35560_remove(struct mcde_display_device *dev)
+{
+ dev->set_power_mode(dev, MCDE_DISPLAY_PM_OFF);
+
+ cancel_delayed_work(&(((struct sony_sy35560_device *)dev)->esd_work));
+ destroy_workqueue(((struct sony_sy35560_device *)dev)->esd_wq);
+ return 0;
+}
+
+static int sony_sy35560_resume(struct mcde_display_device *ddev)
+{
+ int ret;
+ /* set_power_mode will handle call platform_enable */
+ ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY);
+ if (ret < 0)
+ dev_warn(&ddev->dev, "%s:Failed to resume display\n"
+ , __func__);
+
+ queue_delayed_work(((struct sony_sy35560_device *)ddev)->esd_wq,
+ &(((struct sony_sy35560_device *)ddev)->esd_work),
+ SONY_SY35560_ESD_CHECK_PERIOD);
+
+ return ret;
+}
+
+static int sony_sy35560_suspend(struct mcde_display_device *ddev,
+ pm_message_t state)
+{
+ int ret;
+ /* set_power_mode will handle call platform_disable */
+ ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF);
+ if (ret < 0)
+ dev_warn(&ddev->dev, "%s:Failed to suspend display\n"
+ , __func__);
+
+ cancel_delayed_work(&(((struct sony_sy35560_device *)ddev)->esd_work));
+
+ return ret;
+}
+
+static struct mcde_display_driver sony_sy35560_driver = {
+ .probe = sony_sy35560_probe,
+ .remove = sony_sy35560_remove,
+ .suspend = sony_sy35560_suspend,
+ .resume = sony_sy35560_resume,
+ .driver = {
+ .name = "mcde_disp_sony",
+ },
+};
+
+/* Module init */
+
+static int __init mcde_display_sony_sy35560_init(void)
+{
+ pr_info("%s\n", __func__);
+
+ return mcde_display_driver_register(&sony_sy35560_driver);
+}
+module_init(mcde_display_sony_sy35560_init);
+
+static void __exit mcde_display_sony_sy35560_exit(void)
+{
+ pr_info("%s\n", __func__);
+
+ mcde_display_driver_unregister(&sony_sy35560_driver);
+}
+module_exit(mcde_display_sony_sy35560_exit);
+
+MODULE_AUTHOR("Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ST-Ericsson MCDE Sony sy35560 DCS display driver");
+
diff --git a/drivers/video/mcde/display-vuib500-dpi.c b/drivers/video/mcde/display-vuib500-dpi.c
new file mode 100644
index 00000000000..211c04e5070
--- /dev/null
+++ b/drivers/video/mcde/display-vuib500-dpi.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson MCDE DPI display driver
+ * The VUIB500 is an user interface board the can be attached to an HREF. It
+ * supports the DPI pixel interface and converts this to an analog VGA signal,
+ * which can be connected to a monitor using a DSUB connector. The VUIB board
+ * uses an external power supply of 5V.
+ *
+ * Author: Marcel Tunnissen <marcel.tuennissen@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <video/mcde_display.h>
+#include <video/mcde_display-vuib500-dpi.h>
+
+#define DPI_DISP_TRACE dev_dbg(&ddev->dev, "%s\n", __func__)
+
+static int try_video_mode(struct mcde_display_device *ddev,
+ struct mcde_video_mode *video_mode);
+static int set_video_mode(struct mcde_display_device *ddev,
+ struct mcde_video_mode *video_mode);
+
+static int __devinit dpi_display_probe(struct mcde_display_device *ddev)
+{
+ int ret = 0;
+ struct mcde_display_dpi_platform_data *pdata = ddev->dev.platform_data;
+ DPI_DISP_TRACE;
+
+ if (pdata == NULL) {
+ dev_err(&ddev->dev, "%s:Platform data missing\n", __func__);
+ ret = -EINVAL;
+ goto no_pdata;
+ }
+
+ if (ddev->port->type != MCDE_PORTTYPE_DPI) {
+ dev_err(&ddev->dev,
+ "%s:Invalid port type %d\n",
+ __func__, ddev->port->type);
+ ret = -EINVAL;
+ goto invalid_port_type;
+ }
+
+ ddev->try_video_mode = try_video_mode;
+ ddev->set_video_mode = set_video_mode;
+ ddev->prepare_for_update = NULL;
+ dev_info(&ddev->dev, "DPI display probed\n");
+
+ goto out;
+invalid_port_type:
+no_pdata:
+out:
+ return ret;
+}
+
+static int __devexit dpi_display_remove(struct mcde_display_device *ddev)
+{
+ DPI_DISP_TRACE;
+
+ ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF);
+
+ return 0;
+}
+
+static int dpi_display_resume(struct mcde_display_device *ddev)
+{
+ int ret;
+ DPI_DISP_TRACE;
+
+ /* set_power_mode will handle call platform_enable */
+ ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY);
+ if (ret < 0)
+ dev_warn(&ddev->dev, "%s:Failed to resume display\n"
+ , __func__);
+ return ret;
+}
+
+static int dpi_display_suspend(struct mcde_display_device *ddev,
+ pm_message_t state)
+{
+ int ret;
+ DPI_DISP_TRACE;
+
+ /* set_power_mode will handle call platform_disable */
+ ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF);
+ if (ret < 0)
+ dev_warn(&ddev->dev, "%s:Failed to suspend display\n"
+ , __func__);
+ return ret;
+}
+
+static void print_vmode(struct mcde_video_mode *vmode)
+{
+ pr_debug("resolution: %dx%d\n", vmode->xres, vmode->yres);
+ pr_debug(" pixclock: %d\n", vmode->pixclock);
+ pr_debug(" hbp: %d\n", vmode->hbp);
+ pr_debug(" hfp: %d\n", vmode->hfp);
+ pr_debug(" hsw: %d\n", vmode->hsw);
+ pr_debug(" vbp: %d\n", vmode->vbp1);
+ pr_debug(" vfp: %d\n", vmode->vfp1);
+ pr_debug(" vsw: %d\n", vmode->vsw);
+ pr_debug("interlaced: %s\n", vmode->interlaced ? "true" : "false");
+}
+
+/* Taken from the programmed value of the LCD clock in PRCMU */
+#define PIX_CLK_FREQ 25000000
+#define VMODE_XRES 640
+#define VMODE_YRES 480
+
+static int try_video_mode(
+ struct mcde_display_device *ddev, struct mcde_video_mode *video_mode)
+{
+ int res = -EINVAL;
+ DPI_DISP_TRACE;
+
+ if (ddev == NULL || video_mode == NULL) {
+ dev_warn(&ddev->dev, "%s:ddev = NULL or video_mode = NULL\n",
+ __func__);
+ return res;
+ }
+
+ if (video_mode->xres == VMODE_XRES && video_mode->yres == VMODE_YRES) {
+ video_mode->hbp = 40;
+ video_mode->hfp = 8;
+ video_mode->hsw = 96;
+ video_mode->vbp1 = 25;
+ video_mode->vfp1 = 2;
+ video_mode->vbp2 = 0;
+ video_mode->vfp2 = 0;
+ video_mode->vsw = 2;
+ /*
+ * The pixclock setting is not used within MCDE. The clock is
+ * setup elsewhere. But the pixclock value is visible in user
+ * space.
+ */
+ video_mode->pixclock = (int) (1e+12 * (1.0 / PIX_CLK_FREQ));
+ res = 0;
+ } /* TODO: add more supported resolutions here */
+ video_mode->interlaced = false;
+
+ if (res == 0)
+ print_vmode(video_mode);
+ else
+ dev_warn(&ddev->dev,
+ "%s:Failed to find video mode x=%d, y=%d\n",
+ __func__, video_mode->xres, video_mode->yres);
+
+ return res;
+
+}
+
+static int set_video_mode(
+ struct mcde_display_device *ddev, struct mcde_video_mode *video_mode)
+{
+ int res;
+ DPI_DISP_TRACE;
+
+ if (ddev == NULL || video_mode == NULL) {
+ dev_warn(&ddev->dev, "%s:ddev = NULL or video_mode = NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (video_mode->xres != VMODE_XRES || video_mode->yres != VMODE_YRES) {
+ dev_warn(&ddev->dev, "%s:Failed to set video mode x=%d, y=%d\n",
+ __func__, video_mode->xres, video_mode->yres);
+ return -EINVAL;
+ }
+ ddev->video_mode = *video_mode;
+ print_vmode(video_mode);
+
+ res = mcde_chnl_set_video_mode(ddev->chnl_state, &ddev->video_mode);
+ if (res < 0) {
+ dev_warn(&ddev->dev, "%s:Failed to set video mode on channel\n",
+ __func__);
+
+ }
+ /* notify mcde display driver about updated video mode */
+ ddev->update_flags |= UPDATE_FLAG_VIDEO_MODE;
+ return res;
+}
+
+static struct mcde_display_driver dpi_display_driver = {
+ .probe = dpi_display_probe,
+ .remove = dpi_display_remove,
+ .suspend = dpi_display_suspend,
+ .resume = dpi_display_resume,
+ .driver = {
+ .name = "mcde_display_dpi",
+ },
+};
+
+/* Module init */
+static int __init mcde_dpi_display_init(void)
+{
+ pr_info("%s\n", __func__);
+
+ return mcde_display_driver_register(&dpi_display_driver);
+}
+module_init(mcde_dpi_display_init);
+
+static void __exit mcde_dpi_display_exit(void)
+{
+ pr_info("%s\n", __func__);
+
+ mcde_display_driver_unregister(&dpi_display_driver);
+}
+module_exit(mcde_dpi_display_exit);
+
+MODULE_AUTHOR("Marcel Tunnissen <marcel.tuennissen@stericsson.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ST-Ericsson MCDE DPI display driver fro VUIB500 display");
diff --git a/drivers/video/mcde/dsilink_regs.h b/drivers/video/mcde/dsilink_regs.h
new file mode 100644
index 00000000000..b5d5bd952eb
--- /dev/null
+++ b/drivers/video/mcde/dsilink_regs.h
@@ -0,0 +1,2024 @@
+
+#define DSI_VAL2REG(__reg, __fld, __val) \
+ (((__val) << __reg##_##__fld##_SHIFT) & __reg##_##__fld##_MASK)
+#define DSI_REG2VAL(__reg, __fld, __val) \
+ (((__val) & __reg##_##__fld##_MASK) >> __reg##_##__fld##_SHIFT)
+
+#define DSI_MCTL_INTEGRATION_MODE 0x00000000
+#define DSI_MCTL_INTEGRATION_MODE_INT_MODE_EN_SHIFT 0
+#define DSI_MCTL_INTEGRATION_MODE_INT_MODE_EN_MASK 0x00000001
+#define DSI_MCTL_INTEGRATION_MODE_INT_MODE_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_INTEGRATION_MODE, INT_MODE_EN, __x)
+#define DSI_MCTL_MAIN_DATA_CTL 0x00000004
+#define DSI_MCTL_MAIN_DATA_CTL_LINK_EN_SHIFT 0
+#define DSI_MCTL_MAIN_DATA_CTL_LINK_EN_MASK 0x00000001
+#define DSI_MCTL_MAIN_DATA_CTL_LINK_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, LINK_EN, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE_SHIFT 1
+#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE_MASK 0x00000002
+#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE_CMD 0
+#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE_VID 1
+#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE_ENUM(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, IF1_MODE, \
+ DSI_MCTL_MAIN_DATA_CTL_IF1_MODE_##__x)
+#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, IF1_MODE, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_VID_EN_SHIFT 2
+#define DSI_MCTL_MAIN_DATA_CTL_VID_EN_MASK 0x00000004
+#define DSI_MCTL_MAIN_DATA_CTL_VID_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, VID_EN, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_TVG_SEL_SHIFT 3
+#define DSI_MCTL_MAIN_DATA_CTL_TVG_SEL_MASK 0x00000008
+#define DSI_MCTL_MAIN_DATA_CTL_TVG_SEL(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, TVG_SEL, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_TBG_SEL_SHIFT 4
+#define DSI_MCTL_MAIN_DATA_CTL_TBG_SEL_MASK 0x00000010
+#define DSI_MCTL_MAIN_DATA_CTL_TBG_SEL(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, TBG_SEL, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_IF1_TE_EN_SHIFT 5
+#define DSI_MCTL_MAIN_DATA_CTL_IF1_TE_EN_MASK 0x00000020
+#define DSI_MCTL_MAIN_DATA_CTL_IF1_TE_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, IF1_TE_EN, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_IF2_TE_EN_SHIFT 6
+#define DSI_MCTL_MAIN_DATA_CTL_IF2_TE_EN_MASK 0x00000040
+#define DSI_MCTL_MAIN_DATA_CTL_IF2_TE_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, IF2_TE_EN, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_REG_TE_EN_SHIFT 7
+#define DSI_MCTL_MAIN_DATA_CTL_REG_TE_EN_MASK 0x00000080
+#define DSI_MCTL_MAIN_DATA_CTL_REG_TE_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, REG_TE_EN, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_READ_EN_SHIFT 8
+#define DSI_MCTL_MAIN_DATA_CTL_READ_EN_MASK 0x00000100
+#define DSI_MCTL_MAIN_DATA_CTL_READ_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, READ_EN, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_BTA_EN_SHIFT 9
+#define DSI_MCTL_MAIN_DATA_CTL_BTA_EN_MASK 0x00000200
+#define DSI_MCTL_MAIN_DATA_CTL_BTA_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, BTA_EN, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_ECC_SHIFT 10
+#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_ECC_MASK 0x00000400
+#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_ECC(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, DISP_GEN_ECC, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_CHECKSUM_SHIFT 11
+#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_CHECKSUM_MASK 0x00000800
+#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_CHECKSUM(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, DISP_GEN_CHECKSUM, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_HOST_EOT_GEN_SHIFT 12
+#define DSI_MCTL_MAIN_DATA_CTL_HOST_EOT_GEN_MASK 0x00001000
+#define DSI_MCTL_MAIN_DATA_CTL_HOST_EOT_GEN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, HOST_EOT_GEN, __x)
+#define DSI_MCTL_MAIN_DATA_CTL_DISP_EOT_GEN_SHIFT 13
+#define DSI_MCTL_MAIN_DATA_CTL_DISP_EOT_GEN_MASK 0x00002000
+#define DSI_MCTL_MAIN_DATA_CTL_DISP_EOT_GEN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, DISP_EOT_GEN, __x)
+#define DSI_MCTL_MAIN_PHY_CTL 0x00000008
+#define DSI_MCTL_MAIN_PHY_CTL_LANE2_EN_SHIFT 0
+#define DSI_MCTL_MAIN_PHY_CTL_LANE2_EN_MASK 0x00000001
+#define DSI_MCTL_MAIN_PHY_CTL_LANE2_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, LANE2_EN, __x)
+#define DSI_MCTL_MAIN_PHY_CTL_FORCE_STOP_MODE_SHIFT 1
+#define DSI_MCTL_MAIN_PHY_CTL_FORCE_STOP_MODE_MASK 0x00000002
+#define DSI_MCTL_MAIN_PHY_CTL_FORCE_STOP_MODE(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, FORCE_STOP_MODE, __x)
+#define DSI_MCTL_MAIN_PHY_CTL_CLK_CONTINUOUS_SHIFT 2
+#define DSI_MCTL_MAIN_PHY_CTL_CLK_CONTINUOUS_MASK 0x00000004
+#define DSI_MCTL_MAIN_PHY_CTL_CLK_CONTINUOUS(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, CLK_CONTINUOUS, __x)
+#define DSI_MCTL_MAIN_PHY_CTL_CLK_ULPM_EN_SHIFT 3
+#define DSI_MCTL_MAIN_PHY_CTL_CLK_ULPM_EN_MASK 0x00000008
+#define DSI_MCTL_MAIN_PHY_CTL_CLK_ULPM_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, CLK_ULPM_EN, __x)
+#define DSI_MCTL_MAIN_PHY_CTL_DAT1_ULPM_EN_SHIFT 4
+#define DSI_MCTL_MAIN_PHY_CTL_DAT1_ULPM_EN_MASK 0x00000010
+#define DSI_MCTL_MAIN_PHY_CTL_DAT1_ULPM_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, DAT1_ULPM_EN, __x)
+#define DSI_MCTL_MAIN_PHY_CTL_DAT2_ULPM_EN_SHIFT 5
+#define DSI_MCTL_MAIN_PHY_CTL_DAT2_ULPM_EN_MASK 0x00000020
+#define DSI_MCTL_MAIN_PHY_CTL_DAT2_ULPM_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, DAT2_ULPM_EN, __x)
+#define DSI_MCTL_MAIN_PHY_CTL_WAIT_BURST_TIME_SHIFT 6
+#define DSI_MCTL_MAIN_PHY_CTL_WAIT_BURST_TIME_MASK 0x000003C0
+#define DSI_MCTL_MAIN_PHY_CTL_WAIT_BURST_TIME(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, WAIT_BURST_TIME, __x)
+#define DSI_MCTL_PLL_CTL 0x0000000C
+#define DSI_MCTL_PLL_CTL_PLL_MULT_SHIFT 0
+#define DSI_MCTL_PLL_CTL_PLL_MULT_MASK 0x000000FF
+#define DSI_MCTL_PLL_CTL_PLL_MULT(__x) \
+ DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_MULT, __x)
+#define DSI_MCTL_PLL_CTL_PLL_OUT_DIV_SHIFT 8
+#define DSI_MCTL_PLL_CTL_PLL_OUT_DIV_MASK 0x00003F00
+#define DSI_MCTL_PLL_CTL_PLL_OUT_DIV(__x) \
+ DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_OUT_DIV, __x)
+#define DSI_MCTL_PLL_CTL_PLL_IN_DIV_SHIFT 14
+#define DSI_MCTL_PLL_CTL_PLL_IN_DIV_MASK 0x0001C000
+#define DSI_MCTL_PLL_CTL_PLL_IN_DIV(__x) \
+ DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_IN_DIV, __x)
+#define DSI_MCTL_PLL_CTL_PLL_SEL_DIV2_SHIFT 17
+#define DSI_MCTL_PLL_CTL_PLL_SEL_DIV2_MASK 0x00020000
+#define DSI_MCTL_PLL_CTL_PLL_SEL_DIV2(__x) \
+ DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_SEL_DIV2, __x)
+#define DSI_MCTL_PLL_CTL_PLL_OUT_SEL_SHIFT 18
+#define DSI_MCTL_PLL_CTL_PLL_OUT_SEL_MASK 0x00040000
+#define DSI_MCTL_PLL_CTL_PLL_OUT_SEL_INT_PLL 0
+#define DSI_MCTL_PLL_CTL_PLL_OUT_SEL_SYS_PLL 1
+#define DSI_MCTL_PLL_CTL_PLL_OUT_SEL_ENUM(__x) \
+ DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_OUT_SEL, \
+ DSI_MCTL_PLL_CTL_PLL_OUT_SEL_##__x)
+#define DSI_MCTL_PLL_CTL_PLL_OUT_SEL(__x) \
+ DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_OUT_SEL, __x)
+#define DSI_MCTL_PLL_CTL_PLL_MASTER_SHIFT 31
+#define DSI_MCTL_PLL_CTL_PLL_MASTER_MASK 0x80000000
+#define DSI_MCTL_PLL_CTL_PLL_MASTER(__x) \
+ DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_MASTER, __x)
+#define DSI_MCTL_LANE_STS 0x00000010
+#define DSI_MCTL_LANE_STS_CLKLANE_STATE_SHIFT 0
+#define DSI_MCTL_LANE_STS_CLKLANE_STATE_MASK 0x00000003
+#define DSI_MCTL_LANE_STS_CLKLANE_STATE_START 0
+#define DSI_MCTL_LANE_STS_CLKLANE_STATE_IDLE 1
+#define DSI_MCTL_LANE_STS_CLKLANE_STATE_HS 2
+#define DSI_MCTL_LANE_STS_CLKLANE_STATE_ULPM 3
+#define DSI_MCTL_LANE_STS_CLKLANE_STATE_ENUM(__x) \
+ DSI_VAL2REG(DSI_MCTL_LANE_STS, CLKLANE_STATE, \
+ DSI_MCTL_LANE_STS_CLKLANE_STATE_##__x)
+#define DSI_MCTL_LANE_STS_CLKLANE_STATE(__x) \
+ DSI_VAL2REG(DSI_MCTL_LANE_STS, CLKLANE_STATE, __x)
+#define DSI_MCTL_LANE_STS_DATLANE1_STATE_SHIFT 2
+#define DSI_MCTL_LANE_STS_DATLANE1_STATE_MASK 0x0000001C
+#define DSI_MCTL_LANE_STS_DATLANE1_STATE_START 0
+#define DSI_MCTL_LANE_STS_DATLANE1_STATE_IDLE 1
+#define DSI_MCTL_LANE_STS_DATLANE1_STATE_WRITE 2
+#define DSI_MCTL_LANE_STS_DATLANE1_STATE_ULPM 3
+#define DSI_MCTL_LANE_STS_DATLANE1_STATE_READ 4
+#define DSI_MCTL_LANE_STS_DATLANE1_STATE_ENUM(__x) \
+ DSI_VAL2REG(DSI_MCTL_LANE_STS, DATLANE1_STATE, \
+ DSI_MCTL_LANE_STS_DATLANE1_STATE_##__x)
+#define DSI_MCTL_LANE_STS_DATLANE1_STATE(__x) \
+ DSI_VAL2REG(DSI_MCTL_LANE_STS, DATLANE1_STATE, __x)
+#define DSI_MCTL_LANE_STS_DATLANE2_STATE_SHIFT 5
+#define DSI_MCTL_LANE_STS_DATLANE2_STATE_MASK 0x00000060
+#define DSI_MCTL_LANE_STS_DATLANE2_STATE_START 0
+#define DSI_MCTL_LANE_STS_DATLANE2_STATE_IDLE 1
+#define DSI_MCTL_LANE_STS_DATLANE2_STATE_WRITE 2
+#define DSI_MCTL_LANE_STS_DATLANE2_STATE_ULPM 3
+#define DSI_MCTL_LANE_STS_DATLANE2_STATE_ENUM(__x) \
+ DSI_VAL2REG(DSI_MCTL_LANE_STS, DATLANE2_STATE, \
+ DSI_MCTL_LANE_STS_DATLANE2_STATE_##__x)
+#define DSI_MCTL_LANE_STS_DATLANE2_STATE(__x) \
+ DSI_VAL2REG(DSI_MCTL_LANE_STS, DATLANE2_STATE, __x)
+#define DSI_MCTL_DPHY_TIMEOUT 0x00000014
+#define DSI_MCTL_DPHY_TIMEOUT_CLK_DIV_SHIFT 0
+#define DSI_MCTL_DPHY_TIMEOUT_CLK_DIV_MASK 0x0000000F
+#define DSI_MCTL_DPHY_TIMEOUT_CLK_DIV(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_TIMEOUT, CLK_DIV, __x)
+#define DSI_MCTL_DPHY_TIMEOUT_HSTX_TO_VAL_SHIFT 4
+#define DSI_MCTL_DPHY_TIMEOUT_HSTX_TO_VAL_MASK 0x0003FFF0
+#define DSI_MCTL_DPHY_TIMEOUT_HSTX_TO_VAL(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_TIMEOUT, HSTX_TO_VAL, __x)
+#define DSI_MCTL_DPHY_TIMEOUT_LPRX_TO_VAL_SHIFT 18
+#define DSI_MCTL_DPHY_TIMEOUT_LPRX_TO_VAL_MASK 0xFFFC0000
+#define DSI_MCTL_DPHY_TIMEOUT_LPRX_TO_VAL(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_TIMEOUT, LPRX_TO_VAL, __x)
+#define DSI_MCTL_ULPOUT_TIME 0x00000018
+#define DSI_MCTL_ULPOUT_TIME_CKLANE_ULPOUT_TIME_SHIFT 0
+#define DSI_MCTL_ULPOUT_TIME_CKLANE_ULPOUT_TIME_MASK 0x000001FF
+#define DSI_MCTL_ULPOUT_TIME_CKLANE_ULPOUT_TIME(__x) \
+ DSI_VAL2REG(DSI_MCTL_ULPOUT_TIME, CKLANE_ULPOUT_TIME, __x)
+#define DSI_MCTL_ULPOUT_TIME_DATA_ULPOUT_TIME_SHIFT 9
+#define DSI_MCTL_ULPOUT_TIME_DATA_ULPOUT_TIME_MASK 0x0003FE00
+#define DSI_MCTL_ULPOUT_TIME_DATA_ULPOUT_TIME(__x) \
+ DSI_VAL2REG(DSI_MCTL_ULPOUT_TIME, DATA_ULPOUT_TIME, __x)
+#define DSI_MCTL_DPHY_STATIC 0x0000001C
+#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_CLK_SHIFT 0
+#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_CLK_MASK 0x00000001
+#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_CLK(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, SWAP_PINS_CLK, __x)
+#define DSI_MCTL_DPHY_STATIC_HS_INVERT_CLK_SHIFT 1
+#define DSI_MCTL_DPHY_STATIC_HS_INVERT_CLK_MASK 0x00000002
+#define DSI_MCTL_DPHY_STATIC_HS_INVERT_CLK(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, HS_INVERT_CLK, __x)
+#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT1_SHIFT 2
+#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT1_MASK 0x00000004
+#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT1(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, SWAP_PINS_DAT1, __x)
+#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT1_SHIFT 3
+#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT1_MASK 0x00000008
+#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT1(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, HS_INVERT_DAT1, __x)
+#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT2_SHIFT 4
+#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT2_MASK 0x00000010
+#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT2(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, SWAP_PINS_DAT2, __x)
+#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT2_SHIFT 5
+#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT2_MASK 0x00000020
+#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT2(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, HS_INVERT_DAT2, __x)
+#define DSI_MCTL_DPHY_STATIC_UI_X4_SHIFT 6
+#define DSI_MCTL_DPHY_STATIC_UI_X4_MASK 0x00000FC0
+#define DSI_MCTL_DPHY_STATIC_UI_X4(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, UI_X4, __x)
+#define DSI_MCTL_MAIN_EN 0x00000020
+#define DSI_MCTL_MAIN_EN_PLL_START_SHIFT 0
+#define DSI_MCTL_MAIN_EN_PLL_START_MASK 0x00000001
+#define DSI_MCTL_MAIN_EN_PLL_START(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_EN, PLL_START, __x)
+#define DSI_MCTL_MAIN_EN_CKLANE_EN_SHIFT 3
+#define DSI_MCTL_MAIN_EN_CKLANE_EN_MASK 0x00000008
+#define DSI_MCTL_MAIN_EN_CKLANE_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_EN, CKLANE_EN, __x)
+#define DSI_MCTL_MAIN_EN_DAT1_EN_SHIFT 4
+#define DSI_MCTL_MAIN_EN_DAT1_EN_MASK 0x00000010
+#define DSI_MCTL_MAIN_EN_DAT1_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_EN, DAT1_EN, __x)
+#define DSI_MCTL_MAIN_EN_DAT2_EN_SHIFT 5
+#define DSI_MCTL_MAIN_EN_DAT2_EN_MASK 0x00000020
+#define DSI_MCTL_MAIN_EN_DAT2_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_EN, DAT2_EN, __x)
+#define DSI_MCTL_MAIN_EN_CLKLANE_ULPM_REQ_SHIFT 6
+#define DSI_MCTL_MAIN_EN_CLKLANE_ULPM_REQ_MASK 0x00000040
+#define DSI_MCTL_MAIN_EN_CLKLANE_ULPM_REQ(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_EN, CLKLANE_ULPM_REQ, __x)
+#define DSI_MCTL_MAIN_EN_DAT1_ULPM_REQ_SHIFT 7
+#define DSI_MCTL_MAIN_EN_DAT1_ULPM_REQ_MASK 0x00000080
+#define DSI_MCTL_MAIN_EN_DAT1_ULPM_REQ(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_EN, DAT1_ULPM_REQ, __x)
+#define DSI_MCTL_MAIN_EN_DAT2_ULPM_REQ_SHIFT 8
+#define DSI_MCTL_MAIN_EN_DAT2_ULPM_REQ_MASK 0x00000100
+#define DSI_MCTL_MAIN_EN_DAT2_ULPM_REQ(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_EN, DAT2_ULPM_REQ, __x)
+#define DSI_MCTL_MAIN_EN_IF1_EN_SHIFT 9
+#define DSI_MCTL_MAIN_EN_IF1_EN_MASK 0x00000200
+#define DSI_MCTL_MAIN_EN_IF1_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_EN, IF1_EN, __x)
+#define DSI_MCTL_MAIN_EN_IF2_EN_SHIFT 10
+#define DSI_MCTL_MAIN_EN_IF2_EN_MASK 0x00000400
+#define DSI_MCTL_MAIN_EN_IF2_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_EN, IF2_EN, __x)
+#define DSI_MCTL_MAIN_STS 0x00000024
+#define DSI_MCTL_MAIN_STS_PLL_LOCK_SHIFT 0
+#define DSI_MCTL_MAIN_STS_PLL_LOCK_MASK 0x00000001
+#define DSI_MCTL_MAIN_STS_PLL_LOCK(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS, PLL_LOCK, __x)
+#define DSI_MCTL_MAIN_STS_CLKLANE_READY_SHIFT 1
+#define DSI_MCTL_MAIN_STS_CLKLANE_READY_MASK 0x00000002
+#define DSI_MCTL_MAIN_STS_CLKLANE_READY(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS, CLKLANE_READY, __x)
+#define DSI_MCTL_MAIN_STS_DAT1_READY_SHIFT 2
+#define DSI_MCTL_MAIN_STS_DAT1_READY_MASK 0x00000004
+#define DSI_MCTL_MAIN_STS_DAT1_READY(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS, DAT1_READY, __x)
+#define DSI_MCTL_MAIN_STS_DAT2_READY_SHIFT 3
+#define DSI_MCTL_MAIN_STS_DAT2_READY_MASK 0x00000008
+#define DSI_MCTL_MAIN_STS_DAT2_READY(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS, DAT2_READY, __x)
+#define DSI_MCTL_MAIN_STS_HSTX_TO_ERR_SHIFT 4
+#define DSI_MCTL_MAIN_STS_HSTX_TO_ERR_MASK 0x00000010
+#define DSI_MCTL_MAIN_STS_HSTX_TO_ERR(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS, HSTX_TO_ERR, __x)
+#define DSI_MCTL_MAIN_STS_LPRX_TO_ERR_SHIFT 5
+#define DSI_MCTL_MAIN_STS_LPRX_TO_ERR_MASK 0x00000020
+#define DSI_MCTL_MAIN_STS_LPRX_TO_ERR(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS, LPRX_TO_ERR, __x)
+#define DSI_MCTL_MAIN_STS_CRS_UNTERM_PCK_SHIFT 6
+#define DSI_MCTL_MAIN_STS_CRS_UNTERM_PCK_MASK 0x00000040
+#define DSI_MCTL_MAIN_STS_CRS_UNTERM_PCK(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS, CRS_UNTERM_PCK, __x)
+#define DSI_MCTL_MAIN_STS_VRS_UNTERM_PCK_SHIFT 7
+#define DSI_MCTL_MAIN_STS_VRS_UNTERM_PCK_MASK 0x00000080
+#define DSI_MCTL_MAIN_STS_VRS_UNTERM_PCK(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS, VRS_UNTERM_PCK, __x)
+#define DSI_MCTL_DPHY_ERR 0x00000028
+#define DSI_MCTL_DPHY_ERR_ERR_ESC_1_SHIFT 6
+#define DSI_MCTL_DPHY_ERR_ERR_ESC_1_MASK 0x00000040
+#define DSI_MCTL_DPHY_ERR_ERR_ESC_1(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_ESC_1, __x)
+#define DSI_MCTL_DPHY_ERR_ERR_ESC_2_SHIFT 7
+#define DSI_MCTL_DPHY_ERR_ERR_ESC_2_MASK 0x00000080
+#define DSI_MCTL_DPHY_ERR_ERR_ESC_2(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_ESC_2, __x)
+#define DSI_MCTL_DPHY_ERR_ERR_SYNCESC_1_SHIFT 8
+#define DSI_MCTL_DPHY_ERR_ERR_SYNCESC_1_MASK 0x00000100
+#define DSI_MCTL_DPHY_ERR_ERR_SYNCESC_1(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_SYNCESC_1, __x)
+#define DSI_MCTL_DPHY_ERR_ERR_SYNCESC_2_SHIFT 9
+#define DSI_MCTL_DPHY_ERR_ERR_SYNCESC_2_MASK 0x00000200
+#define DSI_MCTL_DPHY_ERR_ERR_SYNCESC_2(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_SYNCESC_2, __x)
+#define DSI_MCTL_DPHY_ERR_ERR_CONTROL_1_SHIFT 10
+#define DSI_MCTL_DPHY_ERR_ERR_CONTROL_1_MASK 0x00000400
+#define DSI_MCTL_DPHY_ERR_ERR_CONTROL_1(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_CONTROL_1, __x)
+#define DSI_MCTL_DPHY_ERR_ERR_CONTROL_2_SHIFT 11
+#define DSI_MCTL_DPHY_ERR_ERR_CONTROL_2_MASK 0x00000800
+#define DSI_MCTL_DPHY_ERR_ERR_CONTROL_2(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_CONTROL_2, __x)
+#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP0_1_SHIFT 12
+#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP0_1_MASK 0x00001000
+#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP0_1(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_CONT_LP0_1, __x)
+#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP0_2_SHIFT 13
+#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP0_2_MASK 0x00002000
+#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP0_2(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_CONT_LP0_2, __x)
+#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP1_1_SHIFT 14
+#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP1_1_MASK 0x00004000
+#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP1_1(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_CONT_LP1_1, __x)
+#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP1_2_SHIFT 15
+#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP1_2_MASK 0x00008000
+#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP1_2(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_CONT_LP1_2, __x)
+#define DSI_INT_VID_RDDATA 0x00000030
+#define DSI_INT_VID_RDDATA_IF_DATA_SHIFT 0
+#define DSI_INT_VID_RDDATA_IF_DATA_MASK 0x0000FFFF
+#define DSI_INT_VID_RDDATA_IF_DATA(__x) \
+ DSI_VAL2REG(DSI_INT_VID_RDDATA, IF_DATA, __x)
+#define DSI_INT_VID_RDDATA_IF_VALID_SHIFT 16
+#define DSI_INT_VID_RDDATA_IF_VALID_MASK 0x00010000
+#define DSI_INT_VID_RDDATA_IF_VALID(__x) \
+ DSI_VAL2REG(DSI_INT_VID_RDDATA, IF_VALID, __x)
+#define DSI_INT_VID_RDDATA_IF_START_SHIFT 17
+#define DSI_INT_VID_RDDATA_IF_START_MASK 0x00020000
+#define DSI_INT_VID_RDDATA_IF_START(__x) \
+ DSI_VAL2REG(DSI_INT_VID_RDDATA, IF_START, __x)
+#define DSI_INT_VID_RDDATA_IF_FRAME_SYNC_SHIFT 18
+#define DSI_INT_VID_RDDATA_IF_FRAME_SYNC_MASK 0x00040000
+#define DSI_INT_VID_RDDATA_IF_FRAME_SYNC(__x) \
+ DSI_VAL2REG(DSI_INT_VID_RDDATA, IF_FRAME_SYNC, __x)
+#define DSI_INT_VID_GNT 0x00000034
+#define DSI_INT_VID_GNT_IF_STALL_SHIFT 0
+#define DSI_INT_VID_GNT_IF_STALL_MASK 0x00000001
+#define DSI_INT_VID_GNT_IF_STALL(__x) \
+ DSI_VAL2REG(DSI_INT_VID_GNT, IF_STALL, __x)
+#define DSI_INT_CMD_RDDATA 0x00000038
+#define DSI_INT_CMD_RDDATA_IF_DATA_SHIFT 0
+#define DSI_INT_CMD_RDDATA_IF_DATA_MASK 0x0000FFFF
+#define DSI_INT_CMD_RDDATA_IF_DATA(__x) \
+ DSI_VAL2REG(DSI_INT_CMD_RDDATA, IF_DATA, __x)
+#define DSI_INT_CMD_RDDATA_IF_VALID_SHIFT 16
+#define DSI_INT_CMD_RDDATA_IF_VALID_MASK 0x00010000
+#define DSI_INT_CMD_RDDATA_IF_VALID(__x) \
+ DSI_VAL2REG(DSI_INT_CMD_RDDATA, IF_VALID, __x)
+#define DSI_INT_CMD_RDDATA_IF_START_SHIFT 17
+#define DSI_INT_CMD_RDDATA_IF_START_MASK 0x00020000
+#define DSI_INT_CMD_RDDATA_IF_START(__x) \
+ DSI_VAL2REG(DSI_INT_CMD_RDDATA, IF_START, __x)
+#define DSI_INT_CMD_RDDATA_IF_FRAME_SYNC_SHIFT 18
+#define DSI_INT_CMD_RDDATA_IF_FRAME_SYNC_MASK 0x00040000
+#define DSI_INT_CMD_RDDATA_IF_FRAME_SYNC(__x) \
+ DSI_VAL2REG(DSI_INT_CMD_RDDATA, IF_FRAME_SYNC, __x)
+#define DSI_INT_CMD_GNT 0x0000003C
+#define DSI_INT_CMD_GNT_IF_STALL_SHIFT 0
+#define DSI_INT_CMD_GNT_IF_STALL_MASK 0x00000001
+#define DSI_INT_CMD_GNT_IF_STALL(__x) \
+ DSI_VAL2REG(DSI_INT_CMD_GNT, IF_STALL, __x)
+#define DSI_INT_INTERRUPT_CTL 0x00000040
+#define DSI_INT_INTERRUPT_CTL_INT_VAL_SHIFT 0
+#define DSI_INT_INTERRUPT_CTL_INT_VAL_MASK 0x00000001
+#define DSI_INT_INTERRUPT_CTL_INT_VAL(__x) \
+ DSI_VAL2REG(DSI_INT_INTERRUPT_CTL, INT_VAL, __x)
+#define DSI_CMD_MODE_CTL 0x00000050
+#define DSI_CMD_MODE_CTL_IF1_ID_SHIFT 0
+#define DSI_CMD_MODE_CTL_IF1_ID_MASK 0x00000003
+#define DSI_CMD_MODE_CTL_IF1_ID(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_CTL, IF1_ID, __x)
+#define DSI_CMD_MODE_CTL_IF2_ID_SHIFT 2
+#define DSI_CMD_MODE_CTL_IF2_ID_MASK 0x0000000C
+#define DSI_CMD_MODE_CTL_IF2_ID(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_CTL, IF2_ID, __x)
+#define DSI_CMD_MODE_CTL_IF1_LP_EN_SHIFT 4
+#define DSI_CMD_MODE_CTL_IF1_LP_EN_MASK 0x00000010
+#define DSI_CMD_MODE_CTL_IF1_LP_EN(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_CTL, IF1_LP_EN, __x)
+#define DSI_CMD_MODE_CTL_IF2_LP_EN_SHIFT 5
+#define DSI_CMD_MODE_CTL_IF2_LP_EN_MASK 0x00000020
+#define DSI_CMD_MODE_CTL_IF2_LP_EN(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_CTL, IF2_LP_EN, __x)
+#define DSI_CMD_MODE_CTL_ARB_MODE_SHIFT 6
+#define DSI_CMD_MODE_CTL_ARB_MODE_MASK 0x00000040
+#define DSI_CMD_MODE_CTL_ARB_MODE(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_CTL, ARB_MODE, __x)
+#define DSI_CMD_MODE_CTL_ARB_PRI_SHIFT 7
+#define DSI_CMD_MODE_CTL_ARB_PRI_MASK 0x00000080
+#define DSI_CMD_MODE_CTL_ARB_PRI(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_CTL, ARB_PRI, __x)
+#define DSI_CMD_MODE_CTL_FIL_VALUE_SHIFT 8
+#define DSI_CMD_MODE_CTL_FIL_VALUE_MASK 0x0000FF00
+#define DSI_CMD_MODE_CTL_FIL_VALUE(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_CTL, FIL_VALUE, __x)
+#define DSI_CMD_MODE_CTL_TE_TIMEOUT_SHIFT 16
+#define DSI_CMD_MODE_CTL_TE_TIMEOUT_MASK 0x03FF0000
+#define DSI_CMD_MODE_CTL_TE_TIMEOUT(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_CTL, TE_TIMEOUT, __x)
+#define DSI_CMD_MODE_STS 0x00000054
+#define DSI_CMD_MODE_STS_ERR_NO_TE_SHIFT 0
+#define DSI_CMD_MODE_STS_ERR_NO_TE_MASK 0x00000001
+#define DSI_CMD_MODE_STS_ERR_NO_TE(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS, ERR_NO_TE, __x)
+#define DSI_CMD_MODE_STS_ERR_TE_MISS_SHIFT 1
+#define DSI_CMD_MODE_STS_ERR_TE_MISS_MASK 0x00000002
+#define DSI_CMD_MODE_STS_ERR_TE_MISS(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS, ERR_TE_MISS, __x)
+#define DSI_CMD_MODE_STS_ERR_SDI1_UNDERRUN_SHIFT 2
+#define DSI_CMD_MODE_STS_ERR_SDI1_UNDERRUN_MASK 0x00000004
+#define DSI_CMD_MODE_STS_ERR_SDI1_UNDERRUN(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS, ERR_SDI1_UNDERRUN, __x)
+#define DSI_CMD_MODE_STS_ERR_SDI2_UNDERRUN_SHIFT 3
+#define DSI_CMD_MODE_STS_ERR_SDI2_UNDERRUN_MASK 0x00000008
+#define DSI_CMD_MODE_STS_ERR_SDI2_UNDERRUN(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS, ERR_SDI2_UNDERRUN, __x)
+#define DSI_CMD_MODE_STS_ERR_UNWANTED_RD_SHIFT 4
+#define DSI_CMD_MODE_STS_ERR_UNWANTED_RD_MASK 0x00000010
+#define DSI_CMD_MODE_STS_ERR_UNWANTED_RD(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS, ERR_UNWANTED_RD, __x)
+#define DSI_CMD_MODE_STS_CSM_RUNNING_SHIFT 5
+#define DSI_CMD_MODE_STS_CSM_RUNNING_MASK 0x00000020
+#define DSI_CMD_MODE_STS_CSM_RUNNING(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS, CSM_RUNNING, __x)
+#define DSI_DIRECT_CMD_SEND 0x00000060
+#define DSI_DIRECT_CMD_SEND_START_SHIFT 0
+#define DSI_DIRECT_CMD_SEND_START_MASK 0xFFFFFFFF
+#define DSI_DIRECT_CMD_SEND_START(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_SEND, START, __x)
+#define DSI_DIRECT_CMD_MAIN_SETTINGS 0x00000064
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_SHIFT 0
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_MASK 0x00000007
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_WRITE 0
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_READ 1
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_TE_REQ 4
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_TRIG_REQ 5
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_BTA_REQ 6
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_ENUM(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_NAT, \
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_##__x)
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_NAT, __x)
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT_SHIFT 3
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT_MASK 0x00000008
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_LONGNOTSHORT, __x)
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT 8
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_MASK 0x00003F00
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_SHORT_WRITE_0 5
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_SHORT_WRITE_1 21
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_LONG_WRITE 57
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_READ 6
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_HEAD, \
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_##__x)
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_HEAD, __x)
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT 14
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_MASK 0x0000C000
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_ID, __x)
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT 16
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_MASK 0x001F0000
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_SIZE, __x)
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN_SHIFT 21
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN_MASK 0x00200000
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_LP_EN, __x)
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_TRIGGER_VAL_SHIFT 24
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_TRIGGER_VAL_MASK 0x0F000000
+#define DSI_DIRECT_CMD_MAIN_SETTINGS_TRIGGER_VAL(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, TRIGGER_VAL, __x)
+#define DSI_DIRECT_CMD_STS 0x00000068
+#define DSI_DIRECT_CMD_STS_CMD_TRANSMISSION_SHIFT 0
+#define DSI_DIRECT_CMD_STS_CMD_TRANSMISSION_MASK 0x00000001
+#define DSI_DIRECT_CMD_STS_CMD_TRANSMISSION(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, CMD_TRANSMISSION, __x)
+#define DSI_DIRECT_CMD_STS_WRITE_COMPLETED_SHIFT 1
+#define DSI_DIRECT_CMD_STS_WRITE_COMPLETED_MASK 0x00000002
+#define DSI_DIRECT_CMD_STS_WRITE_COMPLETED(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, WRITE_COMPLETED, __x)
+#define DSI_DIRECT_CMD_STS_TRIGGER_COMPLETED_SHIFT 2
+#define DSI_DIRECT_CMD_STS_TRIGGER_COMPLETED_MASK 0x00000004
+#define DSI_DIRECT_CMD_STS_TRIGGER_COMPLETED(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, TRIGGER_COMPLETED, __x)
+#define DSI_DIRECT_CMD_STS_READ_COMPLETED_SHIFT 3
+#define DSI_DIRECT_CMD_STS_READ_COMPLETED_MASK 0x00000008
+#define DSI_DIRECT_CMD_STS_READ_COMPLETED(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, READ_COMPLETED, __x)
+#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_RECEIVED_SHIFT 4
+#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_RECEIVED_MASK 0x00000010
+#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_RECEIVED(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, ACKNOWLEDGE_RECEIVED, __x)
+#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_WITH_ERR_RECEIVED_SHIFT 5
+#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_WITH_ERR_RECEIVED_MASK 0x00000020
+#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_WITH_ERR_RECEIVED(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, ACKNOWLEDGE_WITH_ERR_RECEIVED, __x)
+#define DSI_DIRECT_CMD_STS_TRIGGER_RECEIVED_SHIFT 6
+#define DSI_DIRECT_CMD_STS_TRIGGER_RECEIVED_MASK 0x00000040
+#define DSI_DIRECT_CMD_STS_TRIGGER_RECEIVED(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, TRIGGER_RECEIVED, __x)
+#define DSI_DIRECT_CMD_STS_TE_RECEIVED_SHIFT 7
+#define DSI_DIRECT_CMD_STS_TE_RECEIVED_MASK 0x00000080
+#define DSI_DIRECT_CMD_STS_TE_RECEIVED(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, TE_RECEIVED, __x)
+#define DSI_DIRECT_CMD_STS_BTA_COMPLETED_SHIFT 8
+#define DSI_DIRECT_CMD_STS_BTA_COMPLETED_MASK 0x00000100
+#define DSI_DIRECT_CMD_STS_BTA_COMPLETED(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, BTA_COMPLETED, __x)
+#define DSI_DIRECT_CMD_STS_BTA_FINISHED_SHIFT 9
+#define DSI_DIRECT_CMD_STS_BTA_FINISHED_MASK 0x00000200
+#define DSI_DIRECT_CMD_STS_BTA_FINISHED(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, BTA_FINISHED, __x)
+#define DSI_DIRECT_CMD_STS_READ_COMPLETED_WITH_ERR_SHIFT 10
+#define DSI_DIRECT_CMD_STS_READ_COMPLETED_WITH_ERR_MASK 0x00000400
+#define DSI_DIRECT_CMD_STS_READ_COMPLETED_WITH_ERR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, READ_COMPLETED_WITH_ERR, __x)
+#define DSI_DIRECT_CMD_STS_TRIGGER_VAL_SHIFT 11
+#define DSI_DIRECT_CMD_STS_TRIGGER_VAL_MASK 0x00007800
+#define DSI_DIRECT_CMD_STS_TRIGGER_VAL(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, TRIGGER_VAL, __x)
+#define DSI_DIRECT_CMD_STS_ACK_VAL_SHIFT 16
+#define DSI_DIRECT_CMD_STS_ACK_VAL_MASK 0xFFFF0000
+#define DSI_DIRECT_CMD_STS_ACK_VAL(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS, ACK_VAL, __x)
+#define DSI_DIRECT_CMD_RD_INIT 0x0000006C
+#define DSI_DIRECT_CMD_RD_INIT_RESET_SHIFT 0
+#define DSI_DIRECT_CMD_RD_INIT_RESET_MASK 0xFFFFFFFF
+#define DSI_DIRECT_CMD_RD_INIT_RESET(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_INIT, RESET, __x)
+#define DSI_DIRECT_CMD_WRDAT0 0x00000070
+#define DSI_DIRECT_CMD_WRDAT0_WRDAT0_SHIFT 0
+#define DSI_DIRECT_CMD_WRDAT0_WRDAT0_MASK 0x000000FF
+#define DSI_DIRECT_CMD_WRDAT0_WRDAT0(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT0, WRDAT0, __x)
+#define DSI_DIRECT_CMD_WRDAT0_WRDAT1_SHIFT 8
+#define DSI_DIRECT_CMD_WRDAT0_WRDAT1_MASK 0x0000FF00
+#define DSI_DIRECT_CMD_WRDAT0_WRDAT1(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT0, WRDAT1, __x)
+#define DSI_DIRECT_CMD_WRDAT0_WRDAT2_SHIFT 16
+#define DSI_DIRECT_CMD_WRDAT0_WRDAT2_MASK 0x00FF0000
+#define DSI_DIRECT_CMD_WRDAT0_WRDAT2(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT0, WRDAT2, __x)
+#define DSI_DIRECT_CMD_WRDAT0_WRDAT3_SHIFT 24
+#define DSI_DIRECT_CMD_WRDAT0_WRDAT3_MASK 0xFF000000
+#define DSI_DIRECT_CMD_WRDAT0_WRDAT3(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT0, WRDAT3, __x)
+#define DSI_DIRECT_CMD_WRDAT1 0x00000074
+#define DSI_DIRECT_CMD_WRDAT1_WRDAT4_SHIFT 0
+#define DSI_DIRECT_CMD_WRDAT1_WRDAT4_MASK 0x000000FF
+#define DSI_DIRECT_CMD_WRDAT1_WRDAT4(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT1, WRDAT4, __x)
+#define DSI_DIRECT_CMD_WRDAT1_WRDAT5_SHIFT 8
+#define DSI_DIRECT_CMD_WRDAT1_WRDAT5_MASK 0x0000FF00
+#define DSI_DIRECT_CMD_WRDAT1_WRDAT5(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT1, WRDAT5, __x)
+#define DSI_DIRECT_CMD_WRDAT1_WRDAT6_SHIFT 16
+#define DSI_DIRECT_CMD_WRDAT1_WRDAT6_MASK 0x00FF0000
+#define DSI_DIRECT_CMD_WRDAT1_WRDAT6(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT1, WRDAT6, __x)
+#define DSI_DIRECT_CMD_WRDAT1_WRDAT7_SHIFT 24
+#define DSI_DIRECT_CMD_WRDAT1_WRDAT7_MASK 0xFF000000
+#define DSI_DIRECT_CMD_WRDAT1_WRDAT7(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT1, WRDAT7, __x)
+#define DSI_DIRECT_CMD_WRDAT2 0x00000078
+#define DSI_DIRECT_CMD_WRDAT2_WRDAT8_SHIFT 0
+#define DSI_DIRECT_CMD_WRDAT2_WRDAT8_MASK 0x000000FF
+#define DSI_DIRECT_CMD_WRDAT2_WRDAT8(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT2, WRDAT8, __x)
+#define DSI_DIRECT_CMD_WRDAT2_WRDAT9_SHIFT 8
+#define DSI_DIRECT_CMD_WRDAT2_WRDAT9_MASK 0x0000FF00
+#define DSI_DIRECT_CMD_WRDAT2_WRDAT9(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT2, WRDAT9, __x)
+#define DSI_DIRECT_CMD_WRDAT2_WRDAT10_SHIFT 16
+#define DSI_DIRECT_CMD_WRDAT2_WRDAT10_MASK 0x00FF0000
+#define DSI_DIRECT_CMD_WRDAT2_WRDAT10(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT2, WRDAT10, __x)
+#define DSI_DIRECT_CMD_WRDAT2_WRDAT11_SHIFT 24
+#define DSI_DIRECT_CMD_WRDAT2_WRDAT11_MASK 0xFF000000
+#define DSI_DIRECT_CMD_WRDAT2_WRDAT11(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT2, WRDAT11, __x)
+#define DSI_DIRECT_CMD_WRDAT3 0x0000007C
+#define DSI_DIRECT_CMD_WRDAT3_WRDAT12_SHIFT 0
+#define DSI_DIRECT_CMD_WRDAT3_WRDAT12_MASK 0x000000FF
+#define DSI_DIRECT_CMD_WRDAT3_WRDAT12(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT3, WRDAT12, __x)
+#define DSI_DIRECT_CMD_WRDAT3_WRDAT13_SHIFT 8
+#define DSI_DIRECT_CMD_WRDAT3_WRDAT13_MASK 0x0000FF00
+#define DSI_DIRECT_CMD_WRDAT3_WRDAT13(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT3, WRDAT13, __x)
+#define DSI_DIRECT_CMD_WRDAT3_WRDAT14_SHIFT 16
+#define DSI_DIRECT_CMD_WRDAT3_WRDAT14_MASK 0x00FF0000
+#define DSI_DIRECT_CMD_WRDAT3_WRDAT14(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT3, WRDAT14, __x)
+#define DSI_DIRECT_CMD_WRDAT3_WRDAT15_SHIFT 24
+#define DSI_DIRECT_CMD_WRDAT3_WRDAT15_MASK 0xFF000000
+#define DSI_DIRECT_CMD_WRDAT3_WRDAT15(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT3, WRDAT15, __x)
+#define DSI_DIRECT_CMD_RDDAT 0x00000080
+#define DSI_DIRECT_CMD_RDDAT_RDDAT0_SHIFT 0
+#define DSI_DIRECT_CMD_RDDAT_RDDAT0_MASK 0x000000FF
+#define DSI_DIRECT_CMD_RDDAT_RDDAT0(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RDDAT, RDDAT0, __x)
+#define DSI_DIRECT_CMD_RDDAT_RDDAT1_SHIFT 8
+#define DSI_DIRECT_CMD_RDDAT_RDDAT1_MASK 0x0000FF00
+#define DSI_DIRECT_CMD_RDDAT_RDDAT1(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RDDAT, RDDAT1, __x)
+#define DSI_DIRECT_CMD_RDDAT_RDDAT2_SHIFT 16
+#define DSI_DIRECT_CMD_RDDAT_RDDAT2_MASK 0x00FF0000
+#define DSI_DIRECT_CMD_RDDAT_RDDAT2(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RDDAT, RDDAT2, __x)
+#define DSI_DIRECT_CMD_RDDAT_RDDAT3_SHIFT 24
+#define DSI_DIRECT_CMD_RDDAT_RDDAT3_MASK 0xFF000000
+#define DSI_DIRECT_CMD_RDDAT_RDDAT3(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RDDAT, RDDAT3, __x)
+#define DSI_DIRECT_CMD_RD_PROPERTY 0x00000084
+#define DSI_DIRECT_CMD_RD_PROPERTY_RD_SIZE_SHIFT 0
+#define DSI_DIRECT_CMD_RD_PROPERTY_RD_SIZE_MASK 0x0000FFFF
+#define DSI_DIRECT_CMD_RD_PROPERTY_RD_SIZE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_PROPERTY, RD_SIZE, __x)
+#define DSI_DIRECT_CMD_RD_PROPERTY_RD_ID_SHIFT 16
+#define DSI_DIRECT_CMD_RD_PROPERTY_RD_ID_MASK 0x00030000
+#define DSI_DIRECT_CMD_RD_PROPERTY_RD_ID(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_PROPERTY, RD_ID, __x)
+#define DSI_DIRECT_CMD_RD_PROPERTY_RD_DCSNOTGENERIC_SHIFT 18
+#define DSI_DIRECT_CMD_RD_PROPERTY_RD_DCSNOTGENERIC_MASK 0x00040000
+#define DSI_DIRECT_CMD_RD_PROPERTY_RD_DCSNOTGENERIC(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_PROPERTY, RD_DCSNOTGENERIC, __x)
+#define DSI_DIRECT_CMD_RD_STS 0x00000088
+#define DSI_DIRECT_CMD_RD_STS_ERR_FIXED_SHIFT 0
+#define DSI_DIRECT_CMD_RD_STS_ERR_FIXED_MASK 0x00000001
+#define DSI_DIRECT_CMD_RD_STS_ERR_FIXED(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_FIXED, __x)
+#define DSI_DIRECT_CMD_RD_STS_ERR_UNCORRECTABLE_SHIFT 1
+#define DSI_DIRECT_CMD_RD_STS_ERR_UNCORRECTABLE_MASK 0x00000002
+#define DSI_DIRECT_CMD_RD_STS_ERR_UNCORRECTABLE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_UNCORRECTABLE, __x)
+#define DSI_DIRECT_CMD_RD_STS_ERR_CHECKSUM_SHIFT 2
+#define DSI_DIRECT_CMD_RD_STS_ERR_CHECKSUM_MASK 0x00000004
+#define DSI_DIRECT_CMD_RD_STS_ERR_CHECKSUM(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_CHECKSUM, __x)
+#define DSI_DIRECT_CMD_RD_STS_ERR_UNDECODABLE_SHIFT 3
+#define DSI_DIRECT_CMD_RD_STS_ERR_UNDECODABLE_MASK 0x00000008
+#define DSI_DIRECT_CMD_RD_STS_ERR_UNDECODABLE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_UNDECODABLE, __x)
+#define DSI_DIRECT_CMD_RD_STS_ERR_RECEIVE_SHIFT 4
+#define DSI_DIRECT_CMD_RD_STS_ERR_RECEIVE_MASK 0x00000010
+#define DSI_DIRECT_CMD_RD_STS_ERR_RECEIVE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_RECEIVE, __x)
+#define DSI_DIRECT_CMD_RD_STS_ERR_OVERSIZE_SHIFT 5
+#define DSI_DIRECT_CMD_RD_STS_ERR_OVERSIZE_MASK 0x00000020
+#define DSI_DIRECT_CMD_RD_STS_ERR_OVERSIZE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_OVERSIZE, __x)
+#define DSI_DIRECT_CMD_RD_STS_ERR_WRONG_LENGTH_SHIFT 6
+#define DSI_DIRECT_CMD_RD_STS_ERR_WRONG_LENGTH_MASK 0x00000040
+#define DSI_DIRECT_CMD_RD_STS_ERR_WRONG_LENGTH(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_WRONG_LENGTH, __x)
+#define DSI_DIRECT_CMD_RD_STS_ERR_MISSING_EOT_SHIFT 7
+#define DSI_DIRECT_CMD_RD_STS_ERR_MISSING_EOT_MASK 0x00000080
+#define DSI_DIRECT_CMD_RD_STS_ERR_MISSING_EOT(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_MISSING_EOT, __x)
+#define DSI_DIRECT_CMD_RD_STS_ERR_EOT_WITH_ERR_SHIFT 8
+#define DSI_DIRECT_CMD_RD_STS_ERR_EOT_WITH_ERR_MASK 0x00000100
+#define DSI_DIRECT_CMD_RD_STS_ERR_EOT_WITH_ERR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_EOT_WITH_ERR, __x)
+#define DSI_VID_MAIN_CTL 0x00000090
+#define DSI_VID_MAIN_CTL_START_MODE_SHIFT 0
+#define DSI_VID_MAIN_CTL_START_MODE_MASK 0x00000003
+#define DSI_VID_MAIN_CTL_START_MODE(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, START_MODE, __x)
+#define DSI_VID_MAIN_CTL_STOP_MODE_SHIFT 2
+#define DSI_VID_MAIN_CTL_STOP_MODE_MASK 0x0000000C
+#define DSI_VID_MAIN_CTL_STOP_MODE(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, STOP_MODE, __x)
+#define DSI_VID_MAIN_CTL_VID_ID_SHIFT 4
+#define DSI_VID_MAIN_CTL_VID_ID_MASK 0x00000030
+#define DSI_VID_MAIN_CTL_VID_ID(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, VID_ID, __x)
+#define DSI_VID_MAIN_CTL_HEADER_SHIFT 6
+#define DSI_VID_MAIN_CTL_HEADER_MASK 0x00000FC0
+#define DSI_VID_MAIN_CTL_HEADER(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, HEADER, __x)
+#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_SHIFT 12
+#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_MASK 0x00003000
+#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_16BITS 0
+#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_18BITS 1
+#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_18BITS_LOOSE 2
+#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_24BITS 3
+#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_ENUM(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, VID_PIXEL_MODE, \
+ DSI_VID_MAIN_CTL_VID_PIXEL_MODE_##__x)
+#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, VID_PIXEL_MODE, __x)
+#define DSI_VID_MAIN_CTL_BURST_MODE_SHIFT 14
+#define DSI_VID_MAIN_CTL_BURST_MODE_MASK 0x00004000
+#define DSI_VID_MAIN_CTL_BURST_MODE(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, BURST_MODE, __x)
+#define DSI_VID_MAIN_CTL_SYNC_PULSE_ACTIVE_SHIFT 15
+#define DSI_VID_MAIN_CTL_SYNC_PULSE_ACTIVE_MASK 0x00008000
+#define DSI_VID_MAIN_CTL_SYNC_PULSE_ACTIVE(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, SYNC_PULSE_ACTIVE, __x)
+#define DSI_VID_MAIN_CTL_SYNC_PULSE_HORIZONTAL_SHIFT 16
+#define DSI_VID_MAIN_CTL_SYNC_PULSE_HORIZONTAL_MASK 0x00010000
+#define DSI_VID_MAIN_CTL_SYNC_PULSE_HORIZONTAL(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, SYNC_PULSE_HORIZONTAL, __x)
+#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_SHIFT 17
+#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_MASK 0x00060000
+#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_NULL 0
+#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_BLANKING 1
+#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_LP_0 2
+#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_LP_1 3
+#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_ENUM(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, REG_BLKLINE_MODE, \
+ DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_##__x)
+#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, REG_BLKLINE_MODE, __x)
+#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_SHIFT 19
+#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_MASK 0x00180000
+#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_NULL 0
+#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_BLANKING 1
+#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0 2
+#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_1 3
+#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_ENUM(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, REG_BLKEOL_MODE, \
+ DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_##__x)
+#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, REG_BLKEOL_MODE, __x)
+#define DSI_VID_MAIN_CTL_RECOVERY_MODE_SHIFT 21
+#define DSI_VID_MAIN_CTL_RECOVERY_MODE_MASK 0x00600000
+#define DSI_VID_MAIN_CTL_RECOVERY_MODE(__x) \
+ DSI_VAL2REG(DSI_VID_MAIN_CTL, RECOVERY_MODE, __x)
+#define DSI_VID_VSIZE 0x00000094
+#define DSI_VID_VSIZE_VSA_LENGTH_SHIFT 0
+#define DSI_VID_VSIZE_VSA_LENGTH_MASK 0x0000003F
+#define DSI_VID_VSIZE_VSA_LENGTH(__x) \
+ DSI_VAL2REG(DSI_VID_VSIZE, VSA_LENGTH, __x)
+#define DSI_VID_VSIZE_VBP_LENGTH_SHIFT 6
+#define DSI_VID_VSIZE_VBP_LENGTH_MASK 0x00000FC0
+#define DSI_VID_VSIZE_VBP_LENGTH(__x) \
+ DSI_VAL2REG(DSI_VID_VSIZE, VBP_LENGTH, __x)
+#define DSI_VID_VSIZE_VFP_LENGTH_SHIFT 12
+#define DSI_VID_VSIZE_VFP_LENGTH_MASK 0x000FF000
+#define DSI_VID_VSIZE_VFP_LENGTH(__x) \
+ DSI_VAL2REG(DSI_VID_VSIZE, VFP_LENGTH, __x)
+#define DSI_VID_VSIZE_VACT_LENGTH_SHIFT 20
+#define DSI_VID_VSIZE_VACT_LENGTH_MASK 0x7FF00000
+#define DSI_VID_VSIZE_VACT_LENGTH(__x) \
+ DSI_VAL2REG(DSI_VID_VSIZE, VACT_LENGTH, __x)
+#define DSI_VID_HSIZE1 0x00000098
+#define DSI_VID_HSIZE1_HSA_LENGTH_SHIFT 0
+#define DSI_VID_HSIZE1_HSA_LENGTH_MASK 0x000003FF
+#define DSI_VID_HSIZE1_HSA_LENGTH(__x) \
+ DSI_VAL2REG(DSI_VID_HSIZE1, HSA_LENGTH, __x)
+#define DSI_VID_HSIZE1_HBP_LENGTH_SHIFT 10
+#define DSI_VID_HSIZE1_HBP_LENGTH_MASK 0x000FFC00
+#define DSI_VID_HSIZE1_HBP_LENGTH(__x) \
+ DSI_VAL2REG(DSI_VID_HSIZE1, HBP_LENGTH, __x)
+#define DSI_VID_HSIZE1_HFP_LENGTH_SHIFT 20
+#define DSI_VID_HSIZE1_HFP_LENGTH_MASK 0x7FF00000
+#define DSI_VID_HSIZE1_HFP_LENGTH(__x) \
+ DSI_VAL2REG(DSI_VID_HSIZE1, HFP_LENGTH, __x)
+#define DSI_VID_HSIZE2 0x0000009C
+#define DSI_VID_HSIZE2_RGB_SIZE_SHIFT 0
+#define DSI_VID_HSIZE2_RGB_SIZE_MASK 0x00001FFF
+#define DSI_VID_HSIZE2_RGB_SIZE(__x) \
+ DSI_VAL2REG(DSI_VID_HSIZE2, RGB_SIZE, __x)
+#define DSI_VID_BLKSIZE1 0x000000A0
+#define DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_SHIFT 0
+#define DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_MASK 0x00001FFF
+#define DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK(__x) \
+ DSI_VAL2REG(DSI_VID_BLKSIZE1, BLKLINE_EVENT_PCK, __x)
+#define DSI_VID_BLKSIZE1_BLKEOL_PCK_SHIFT 13
+#define DSI_VID_BLKSIZE1_BLKEOL_PCK_MASK 0x03FFE000
+#define DSI_VID_BLKSIZE1_BLKEOL_PCK(__x) \
+ DSI_VAL2REG(DSI_VID_BLKSIZE1, BLKEOL_PCK, __x)
+#define DSI_VID_BLKSIZE2 0x000000A4
+#define DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK_SHIFT 0
+#define DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK_MASK 0x00001FFF
+#define DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK(__x) \
+ DSI_VAL2REG(DSI_VID_BLKSIZE2, BLKLINE_PULSE_PCK, __x)
+#define DSI_VID_PCK_TIME 0x000000A8
+#define DSI_VID_PCK_TIME_BLKEOL_DURATION_SHIFT 0
+#define DSI_VID_PCK_TIME_BLKEOL_DURATION_MASK 0x00001FFF
+#define DSI_VID_PCK_TIME_BLKEOL_DURATION(__x) \
+ DSI_VAL2REG(DSI_VID_PCK_TIME, BLKEOL_DURATION, __x)
+#define DSI_VID_DPHY_TIME 0x000000AC
+#define DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT 0
+#define DSI_VID_DPHY_TIME_REG_LINE_DURATION_MASK 0x00001FFF
+#define DSI_VID_DPHY_TIME_REG_LINE_DURATION(__x) \
+ DSI_VAL2REG(DSI_VID_DPHY_TIME, REG_LINE_DURATION, __x)
+#define DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_SHIFT 13
+#define DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_MASK 0x00FFE000
+#define DSI_VID_DPHY_TIME_REG_WAKEUP_TIME(__x) \
+ DSI_VAL2REG(DSI_VID_DPHY_TIME, REG_WAKEUP_TIME, __x)
+#define DSI_VID_ERR_COLOR 0x000000B0
+#define DSI_VID_ERR_COLOR_COL_RED_SHIFT 0
+#define DSI_VID_ERR_COLOR_COL_RED_MASK 0x000000FF
+#define DSI_VID_ERR_COLOR_COL_RED(__x) \
+ DSI_VAL2REG(DSI_VID_ERR_COLOR, COL_RED, __x)
+#define DSI_VID_ERR_COLOR_COL_GREEN_SHIFT 8
+#define DSI_VID_ERR_COLOR_COL_GREEN_MASK 0x0000FF00
+#define DSI_VID_ERR_COLOR_COL_GREEN(__x) \
+ DSI_VAL2REG(DSI_VID_ERR_COLOR, COL_GREEN, __x)
+#define DSI_VID_ERR_COLOR_COL_BLUE_SHIFT 16
+#define DSI_VID_ERR_COLOR_COL_BLUE_MASK 0x00FF0000
+#define DSI_VID_ERR_COLOR_COL_BLUE(__x) \
+ DSI_VAL2REG(DSI_VID_ERR_COLOR, COL_BLUE, __x)
+#define DSI_VID_ERR_COLOR_PAD_VAL_SHIFT 24
+#define DSI_VID_ERR_COLOR_PAD_VAL_MASK 0xFF000000
+#define DSI_VID_ERR_COLOR_PAD_VAL(__x) \
+ DSI_VAL2REG(DSI_VID_ERR_COLOR, PAD_VAL, __x)
+#define DSI_VID_VPOS 0x000000B4
+#define DSI_VID_VPOS_LINE_POS_SHIFT 0
+#define DSI_VID_VPOS_LINE_POS_MASK 0x00000003
+#define DSI_VID_VPOS_LINE_POS(__x) \
+ DSI_VAL2REG(DSI_VID_VPOS, LINE_POS, __x)
+#define DSI_VID_VPOS_LINE_VAL_SHIFT 2
+#define DSI_VID_VPOS_LINE_VAL_MASK 0x00001FFC
+#define DSI_VID_VPOS_LINE_VAL(__x) \
+ DSI_VAL2REG(DSI_VID_VPOS, LINE_VAL, __x)
+#define DSI_VID_HPOS 0x000000B8
+#define DSI_VID_HPOS_HORIZONTAL_POS_SHIFT 0
+#define DSI_VID_HPOS_HORIZONTAL_POS_MASK 0x00000007
+#define DSI_VID_HPOS_HORIZONTAL_POS(__x) \
+ DSI_VAL2REG(DSI_VID_HPOS, HORIZONTAL_POS, __x)
+#define DSI_VID_HPOS_HORIZONTAL_VAL_SHIFT 3
+#define DSI_VID_HPOS_HORIZONTAL_VAL_MASK 0x0000FFF8
+#define DSI_VID_HPOS_HORIZONTAL_VAL(__x) \
+ DSI_VAL2REG(DSI_VID_HPOS, HORIZONTAL_VAL, __x)
+#define DSI_VID_MODE_STS 0x000000BC
+#define DSI_VID_MODE_STS_VSG_RUNNING_SHIFT 0
+#define DSI_VID_MODE_STS_VSG_RUNNING_MASK 0x00000001
+#define DSI_VID_MODE_STS_VSG_RUNNING(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS, VSG_RUNNING, __x)
+#define DSI_VID_MODE_STS_ERR_MISSING_DATA_SHIFT 1
+#define DSI_VID_MODE_STS_ERR_MISSING_DATA_MASK 0x00000002
+#define DSI_VID_MODE_STS_ERR_MISSING_DATA(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS, ERR_MISSING_DATA, __x)
+#define DSI_VID_MODE_STS_ERR_MISSING_HSYNC_SHIFT 2
+#define DSI_VID_MODE_STS_ERR_MISSING_HSYNC_MASK 0x00000004
+#define DSI_VID_MODE_STS_ERR_MISSING_HSYNC(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS, ERR_MISSING_HSYNC, __x)
+#define DSI_VID_MODE_STS_ERR_MISSING_VSYNC_SHIFT 3
+#define DSI_VID_MODE_STS_ERR_MISSING_VSYNC_MASK 0x00000008
+#define DSI_VID_MODE_STS_ERR_MISSING_VSYNC(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS, ERR_MISSING_VSYNC, __x)
+#define DSI_VID_MODE_STS_REG_ERR_SMALL_LENGTH_SHIFT 4
+#define DSI_VID_MODE_STS_REG_ERR_SMALL_LENGTH_MASK 0x00000010
+#define DSI_VID_MODE_STS_REG_ERR_SMALL_LENGTH(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS, REG_ERR_SMALL_LENGTH, __x)
+#define DSI_VID_MODE_STS_REG_ERR_SMALL_HEIGHT_SHIFT 5
+#define DSI_VID_MODE_STS_REG_ERR_SMALL_HEIGHT_MASK 0x00000020
+#define DSI_VID_MODE_STS_REG_ERR_SMALL_HEIGHT(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS, REG_ERR_SMALL_HEIGHT, __x)
+#define DSI_VID_MODE_STS_ERR_BURSTWRITE_SHIFT 6
+#define DSI_VID_MODE_STS_ERR_BURSTWRITE_MASK 0x00000040
+#define DSI_VID_MODE_STS_ERR_BURSTWRITE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS, ERR_BURSTWRITE, __x)
+#define DSI_VID_MODE_STS_ERR_LONGWRITE_SHIFT 7
+#define DSI_VID_MODE_STS_ERR_LONGWRITE_MASK 0x00000080
+#define DSI_VID_MODE_STS_ERR_LONGWRITE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS, ERR_LONGWRITE, __x)
+#define DSI_VID_MODE_STS_ERR_LONGREAD_SHIFT 8
+#define DSI_VID_MODE_STS_ERR_LONGREAD_MASK 0x00000100
+#define DSI_VID_MODE_STS_ERR_LONGREAD(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS, ERR_LONGREAD, __x)
+#define DSI_VID_MODE_STS_ERR_VRS_WRONG_LENGTH_SHIFT 9
+#define DSI_VID_MODE_STS_ERR_VRS_WRONG_LENGTH_MASK 0x00000200
+#define DSI_VID_MODE_STS_ERR_VRS_WRONG_LENGTH(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS, ERR_VRS_WRONG_LENGTH, __x)
+#define DSI_VID_MODE_STS_VSG_RECOVERY_SHIFT 10
+#define DSI_VID_MODE_STS_VSG_RECOVERY_MASK 0x00000400
+#define DSI_VID_MODE_STS_VSG_RECOVERY(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS, VSG_RECOVERY, __x)
+#define DSI_VID_VCA_SETTING1 0x000000C0
+#define DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_SHIFT 0
+#define DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_MASK 0x0000FFFF
+#define DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT(__x) \
+ DSI_VAL2REG(DSI_VID_VCA_SETTING1, MAX_BURST_LIMIT, __x)
+#define DSI_VID_VCA_SETTING1_BURST_LP_SHIFT 16
+#define DSI_VID_VCA_SETTING1_BURST_LP_MASK 0x00010000
+#define DSI_VID_VCA_SETTING1_BURST_LP(__x) \
+ DSI_VAL2REG(DSI_VID_VCA_SETTING1, BURST_LP, __x)
+#define DSI_VID_VCA_SETTING2 0x000000C4
+#define DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT 0
+#define DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_MASK 0x0000FFFF
+#define DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT(__x) \
+ DSI_VAL2REG(DSI_VID_VCA_SETTING2, EXACT_BURST_LIMIT, __x)
+#define DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_SHIFT 16
+#define DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_MASK 0xFFFF0000
+#define DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT(__x) \
+ DSI_VAL2REG(DSI_VID_VCA_SETTING2, MAX_LINE_LIMIT, __x)
+#define DSI_TVG_CTL 0x000000C8
+#define DSI_TVG_CTL_TVG_RUN_SHIFT 0
+#define DSI_TVG_CTL_TVG_RUN_MASK 0x00000001
+#define DSI_TVG_CTL_TVG_RUN(__x) \
+ DSI_VAL2REG(DSI_TVG_CTL, TVG_RUN, __x)
+#define DSI_TVG_CTL_TVG_STOPMODE_SHIFT 1
+#define DSI_TVG_CTL_TVG_STOPMODE_MASK 0x00000006
+#define DSI_TVG_CTL_TVG_STOPMODE(__x) \
+ DSI_VAL2REG(DSI_TVG_CTL, TVG_STOPMODE, __x)
+#define DSI_TVG_CTL_TVG_MODE_SHIFT 3
+#define DSI_TVG_CTL_TVG_MODE_MASK 0x00000018
+#define DSI_TVG_CTL_TVG_MODE(__x) \
+ DSI_VAL2REG(DSI_TVG_CTL, TVG_MODE, __x)
+#define DSI_TVG_CTL_TVG_STRIPE_SIZE_SHIFT 5
+#define DSI_TVG_CTL_TVG_STRIPE_SIZE_MASK 0x000000E0
+#define DSI_TVG_CTL_TVG_STRIPE_SIZE(__x) \
+ DSI_VAL2REG(DSI_TVG_CTL, TVG_STRIPE_SIZE, __x)
+#define DSI_TVG_IMG_SIZE 0x000000CC
+#define DSI_TVG_IMG_SIZE_TVG_LINE_SIZE_SHIFT 0
+#define DSI_TVG_IMG_SIZE_TVG_LINE_SIZE_MASK 0x00001FFF
+#define DSI_TVG_IMG_SIZE_TVG_LINE_SIZE(__x) \
+ DSI_VAL2REG(DSI_TVG_IMG_SIZE, TVG_LINE_SIZE, __x)
+#define DSI_TVG_IMG_SIZE_TVG_NBLINE_SHIFT 16
+#define DSI_TVG_IMG_SIZE_TVG_NBLINE_MASK 0x07FF0000
+#define DSI_TVG_IMG_SIZE_TVG_NBLINE(__x) \
+ DSI_VAL2REG(DSI_TVG_IMG_SIZE, TVG_NBLINE, __x)
+#define DSI_TVG_COLOR1 0x000000D0
+#define DSI_TVG_COLOR1_COL1_RED_SHIFT 0
+#define DSI_TVG_COLOR1_COL1_RED_MASK 0x000000FF
+#define DSI_TVG_COLOR1_COL1_RED(__x) \
+ DSI_VAL2REG(DSI_TVG_COLOR1, COL1_RED, __x)
+#define DSI_TVG_COLOR1_COL1_GREEN_SHIFT 8
+#define DSI_TVG_COLOR1_COL1_GREEN_MASK 0x0000FF00
+#define DSI_TVG_COLOR1_COL1_GREEN(__x) \
+ DSI_VAL2REG(DSI_TVG_COLOR1, COL1_GREEN, __x)
+#define DSI_TVG_COLOR1_COL1_BLUE_SHIFT 16
+#define DSI_TVG_COLOR1_COL1_BLUE_MASK 0x00FF0000
+#define DSI_TVG_COLOR1_COL1_BLUE(__x) \
+ DSI_VAL2REG(DSI_TVG_COLOR1, COL1_BLUE, __x)
+#define DSI_TVG_COLOR2 0x000000D4
+#define DSI_TVG_COLOR2_COL2_RED_SHIFT 0
+#define DSI_TVG_COLOR2_COL2_RED_MASK 0x000000FF
+#define DSI_TVG_COLOR2_COL2_RED(__x) \
+ DSI_VAL2REG(DSI_TVG_COLOR2, COL2_RED, __x)
+#define DSI_TVG_COLOR2_COL2_GREEN_SHIFT 8
+#define DSI_TVG_COLOR2_COL2_GREEN_MASK 0x0000FF00
+#define DSI_TVG_COLOR2_COL2_GREEN(__x) \
+ DSI_VAL2REG(DSI_TVG_COLOR2, COL2_GREEN, __x)
+#define DSI_TVG_COLOR2_COL2_BLUE_SHIFT 16
+#define DSI_TVG_COLOR2_COL2_BLUE_MASK 0x00FF0000
+#define DSI_TVG_COLOR2_COL2_BLUE(__x) \
+ DSI_VAL2REG(DSI_TVG_COLOR2, COL2_BLUE, __x)
+#define DSI_TVG_STS 0x000000D8
+#define DSI_TVG_STS_TVG_RUNNING_SHIFT 0
+#define DSI_TVG_STS_TVG_RUNNING_MASK 0x00000001
+#define DSI_TVG_STS_TVG_RUNNING(__x) \
+ DSI_VAL2REG(DSI_TVG_STS, TVG_RUNNING, __x)
+#define DSI_TBG_CTL 0x000000E0
+#define DSI_TBG_CTL_TBG_START_SHIFT 0
+#define DSI_TBG_CTL_TBG_START_MASK 0x00000001
+#define DSI_TBG_CTL_TBG_START(__x) \
+ DSI_VAL2REG(DSI_TBG_CTL, TBG_START, __x)
+#define DSI_TBG_CTL_TBG_HS_REQ_SHIFT 1
+#define DSI_TBG_CTL_TBG_HS_REQ_MASK 0x00000002
+#define DSI_TBG_CTL_TBG_HS_REQ(__x) \
+ DSI_VAL2REG(DSI_TBG_CTL, TBG_HS_REQ, __x)
+#define DSI_TBG_CTL_TBG_DATA_SEL_SHIFT 2
+#define DSI_TBG_CTL_TBG_DATA_SEL_MASK 0x00000004
+#define DSI_TBG_CTL_TBG_DATA_SEL(__x) \
+ DSI_VAL2REG(DSI_TBG_CTL, TBG_DATA_SEL, __x)
+#define DSI_TBG_CTL_TBG_MODE_SHIFT 3
+#define DSI_TBG_CTL_TBG_MODE_MASK 0x00000018
+#define DSI_TBG_CTL_TBG_MODE_1BYTE 0
+#define DSI_TBG_CTL_TBG_MODE_2BYTE 1
+#define DSI_TBG_CTL_TBG_MODE_BURST_COUNTER 2
+#define DSI_TBG_CTL_TBG_MODE_BURST 3
+#define DSI_TBG_CTL_TBG_MODE_ENUM(__x) \
+ DSI_VAL2REG(DSI_TBG_CTL, TBG_MODE, DSI_TBG_CTL_TBG_MODE_##__x)
+#define DSI_TBG_CTL_TBG_MODE(__x) \
+ DSI_VAL2REG(DSI_TBG_CTL, TBG_MODE, __x)
+#define DSI_TBG_SETTING 0x000000E4
+#define DSI_TBG_SETTING_TBG_DATA_SHIFT 0
+#define DSI_TBG_SETTING_TBG_DATA_MASK 0x0000FFFF
+#define DSI_TBG_SETTING_TBG_DATA(__x) \
+ DSI_VAL2REG(DSI_TBG_SETTING, TBG_DATA, __x)
+#define DSI_TBG_SETTING_TBG_CPT_SHIFT 16
+#define DSI_TBG_SETTING_TBG_CPT_MASK 0x0FFF0000
+#define DSI_TBG_SETTING_TBG_CPT(__x) \
+ DSI_VAL2REG(DSI_TBG_SETTING, TBG_CPT, __x)
+#define DSI_TBG_STS 0x000000E8
+#define DSI_TBG_STS_TBG_STATUS_SHIFT 0
+#define DSI_TBG_STS_TBG_STATUS_MASK 0x00000001
+#define DSI_TBG_STS_TBG_STATUS(__x) \
+ DSI_VAL2REG(DSI_TBG_STS, TBG_STATUS, __x)
+#define DSI_MCTL_MAIN_STS_CTL 0x000000F0
+#define DSI_MCTL_MAIN_STS_CTL_PLL_LOCK_EN_SHIFT 0
+#define DSI_MCTL_MAIN_STS_CTL_PLL_LOCK_EN_MASK 0x00000001
+#define DSI_MCTL_MAIN_STS_CTL_PLL_LOCK_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, PLL_LOCK_EN, __x)
+#define DSI_MCTL_MAIN_STS_CTL_CLKLANE_READY_EN_SHIFT 1
+#define DSI_MCTL_MAIN_STS_CTL_CLKLANE_READY_EN_MASK 0x00000002
+#define DSI_MCTL_MAIN_STS_CTL_CLKLANE_READY_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, CLKLANE_READY_EN, __x)
+#define DSI_MCTL_MAIN_STS_CTL_DAT1_READY_EN_SHIFT 2
+#define DSI_MCTL_MAIN_STS_CTL_DAT1_READY_EN_MASK 0x00000004
+#define DSI_MCTL_MAIN_STS_CTL_DAT1_READY_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, DAT1_READY_EN, __x)
+#define DSI_MCTL_MAIN_STS_CTL_DAT2_READY_EN_SHIFT 3
+#define DSI_MCTL_MAIN_STS_CTL_DAT2_READY_EN_MASK 0x00000008
+#define DSI_MCTL_MAIN_STS_CTL_DAT2_READY_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, DAT2_READY_EN, __x)
+#define DSI_MCTL_MAIN_STS_CTL_HSTX_TO_ERR_EN_SHIFT 4
+#define DSI_MCTL_MAIN_STS_CTL_HSTX_TO_ERR_EN_MASK 0x00000010
+#define DSI_MCTL_MAIN_STS_CTL_HSTX_TO_ERR_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, HSTX_TO_ERR_EN, __x)
+#define DSI_MCTL_MAIN_STS_CTL_LPRX_TO_ERR_EN_SHIFT 5
+#define DSI_MCTL_MAIN_STS_CTL_LPRX_TO_ERR_EN_MASK 0x00000020
+#define DSI_MCTL_MAIN_STS_CTL_LPRX_TO_ERR_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, LPRX_TO_ERR_EN, __x)
+#define DSI_MCTL_MAIN_STS_CTL_CRS_UNTERM_PCK_ERR_EN_SHIFT 6
+#define DSI_MCTL_MAIN_STS_CTL_CRS_UNTERM_PCK_ERR_EN_MASK 0x00000040
+#define DSI_MCTL_MAIN_STS_CTL_CRS_UNTERM_PCK_ERR_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, CRS_UNTERM_PCK_ERR_EN, __x)
+#define DSI_MCTL_MAIN_STS_CTL_VRS_UNTERM_PCK_ERR_EN_SHIFT 7
+#define DSI_MCTL_MAIN_STS_CTL_VRS_UNTERM_PCK_ERR_EN_MASK 0x00000080
+#define DSI_MCTL_MAIN_STS_CTL_VRS_UNTERM_PCK_ERR_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, VRS_UNTERM_PCK_ERR_EN, __x)
+#define DSI_MCTL_MAIN_STS_CTL_PLL_LOCK_EDGE_SHIFT 16
+#define DSI_MCTL_MAIN_STS_CTL_PLL_LOCK_EDGE_MASK 0x00010000
+#define DSI_MCTL_MAIN_STS_CTL_PLL_LOCK_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, PLL_LOCK_EDGE, __x)
+#define DSI_MCTL_MAIN_STS_CTL_CLKLANE_READY_EDGE_SHIFT 17
+#define DSI_MCTL_MAIN_STS_CTL_CLKLANE_READY_EDGE_MASK 0x00020000
+#define DSI_MCTL_MAIN_STS_CTL_CLKLANE_READY_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, CLKLANE_READY_EDGE, __x)
+#define DSI_MCTL_MAIN_STS_CTL_DAT1_READY_EDGE_SHIFT 18
+#define DSI_MCTL_MAIN_STS_CTL_DAT1_READY_EDGE_MASK 0x00040000
+#define DSI_MCTL_MAIN_STS_CTL_DAT1_READY_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, DAT1_READY_EDGE, __x)
+#define DSI_MCTL_MAIN_STS_CTL_DAT2_READY_EDGE_SHIFT 19
+#define DSI_MCTL_MAIN_STS_CTL_DAT2_READY_EDGE_MASK 0x00080000
+#define DSI_MCTL_MAIN_STS_CTL_DAT2_READY_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, DAT2_READY_EDGE, __x)
+#define DSI_MCTL_MAIN_STS_CTL_HSTX_TO_ERR_EDGE_SHIFT 20
+#define DSI_MCTL_MAIN_STS_CTL_HSTX_TO_ERR_EDGE_MASK 0x00100000
+#define DSI_MCTL_MAIN_STS_CTL_HSTX_TO_ERR_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, HSTX_TO_ERR_EDGE, __x)
+#define DSI_MCTL_MAIN_STS_CTL_LPRX_TO_ERR_EDGE_SHIFT 21
+#define DSI_MCTL_MAIN_STS_CTL_LPRX_TO_ERR_EDGE_MASK 0x00200000
+#define DSI_MCTL_MAIN_STS_CTL_LPRX_TO_ERR_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, LPRX_TO_ERR_EDGE, __x)
+#define DSI_MCTL_MAIN_STS_CTL_CRS_UNTERM_PCK_ERR_EDGE_SHIFT 22
+#define DSI_MCTL_MAIN_STS_CTL_CRS_UNTERM_PCK_ERR_EDGE_MASK 0x00400000
+#define DSI_MCTL_MAIN_STS_CTL_CRS_UNTERM_PCK_ERR_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, CRS_UNTERM_PCK_ERR_EDGE, __x)
+#define DSI_MCTL_MAIN_STS_CTL_VRS_UNTERM_PCK_ERR_EDGE_SHIFT 23
+#define DSI_MCTL_MAIN_STS_CTL_VRS_UNTERM_PCK_ERR_EDGE_MASK 0x00800000
+#define DSI_MCTL_MAIN_STS_CTL_VRS_UNTERM_PCK_ERR_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, VRS_UNTERM_PCK_ERR_EDGE, __x)
+#define DSI_CMD_MODE_STS_CTL 0x000000F4
+#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EN_SHIFT 0
+#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EN_MASK 0x00000001
+#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EN(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_NO_TE_EN, __x)
+#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EN_SHIFT 1
+#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EN_MASK 0x00000002
+#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EN(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_TE_MISS_EN, __x)
+#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EN_SHIFT 2
+#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EN_MASK 0x00000004
+#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EN(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_SDI1_UNDERRUN_EN, __x)
+#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EN_SHIFT 3
+#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EN_MASK 0x00000008
+#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EN(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_SDI2_UNDERRUN_EN, __x)
+#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EN_SHIFT 4
+#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EN_MASK 0x00000010
+#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EN(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_UNWANTED_RD_EN, __x)
+#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EN_SHIFT 5
+#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EN_MASK 0x00000020
+#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EN(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, CSM_RUNNING_EN, __x)
+#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EDGE_SHIFT 16
+#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EDGE_MASK 0x00010000
+#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EDGE(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_NO_TE_EDGE, __x)
+#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EDGE_SHIFT 17
+#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EDGE_MASK 0x00020000
+#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EDGE(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_TE_MISS_EDGE, __x)
+#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EDGE_SHIFT 18
+#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EDGE_MASK 0x00040000
+#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EDGE(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_SDI1_UNDERRUN_EDGE, __x)
+#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EDGE_SHIFT 19
+#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EDGE_MASK 0x00080000
+#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EDGE(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_SDI2_UNDERRUN_EDGE, __x)
+#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EDGE_SHIFT 20
+#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EDGE_MASK 0x00100000
+#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EDGE(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_UNWANTED_RD_EDGE, __x)
+#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EDGE_SHIFT 21
+#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EDGE_MASK 0x00200000
+#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EDGE(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, CSM_RUNNING_EDGE, __x)
+#define DSI_DIRECT_CMD_STS_CTL 0x000000F8
+#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EN_SHIFT 0
+#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EN_MASK 0x00000001
+#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, CMD_TRANSMISSION_EN, __x)
+#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EN_SHIFT 1
+#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EN_MASK 0x00000002
+#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, WRITE_COMPLETED_EN, __x)
+#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EN_SHIFT 2
+#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EN_MASK 0x00000004
+#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, TRIGGER_COMPLETED_EN, __x)
+#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EN_SHIFT 3
+#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EN_MASK 0x00000008
+#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, READ_COMPLETED_EN, __x)
+#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EN_SHIFT 4
+#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EN_MASK 0x00000010
+#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, ACKNOWLEDGE_RECEIVED_EN, __x)
+#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EN_SHIFT 5
+#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EN_MASK 0x00000020
+#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, ACKNOWLEDGE_WITH_ERR_EN, __x)
+#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EN_SHIFT 6
+#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EN_MASK 0x00000040
+#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, TRIGGER_RECEIVED_EN, __x)
+#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EN_SHIFT 7
+#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EN_MASK 0x00000080
+#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, TE_RECEIVED_EN, __x)
+#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EN_SHIFT 8
+#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EN_MASK 0x00000100
+#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, BTA_COMPLETED_EN, __x)
+#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EN_SHIFT 9
+#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EN_MASK 0x00000200
+#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, BTA_FINISHED_EN, __x)
+#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EN_SHIFT 10
+#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EN_MASK 0x00000400
+#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, READ_COMPLETED_WITH_ERR_EN, __x)
+#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EDGE_SHIFT 16
+#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EDGE_MASK 0x00010000
+#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, CMD_TRANSMISSION_EDGE, __x)
+#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EDGE_SHIFT 17
+#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EDGE_MASK 0x00020000
+#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, WRITE_COMPLETED_EDGE, __x)
+#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EDGE_SHIFT 18
+#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EDGE_MASK 0x00040000
+#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, TRIGGER_COMPLETED_EDGE, __x)
+#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EDGE_SHIFT 19
+#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EDGE_MASK 0x00080000
+#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, READ_COMPLETED_EDGE, __x)
+#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EDGE_SHIFT 20
+#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EDGE_MASK 0x00100000
+#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, ACKNOWLEDGE_RECEIVED_EDGE, __x)
+#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EDGE_SHIFT 21
+#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EDGE_MASK 0x00200000
+#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, ACKNOWLEDGE_WITH_ERR_EDGE, __x)
+#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EDGE_SHIFT 22
+#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EDGE_MASK 0x00400000
+#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, TRIGGER_RECEIVED_EDGE, __x)
+#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EDGE_SHIFT 23
+#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EDGE_MASK 0x00800000
+#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, TE_RECEIVED_EDGE, __x)
+#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EDGE_SHIFT 24
+#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EDGE_MASK 0x01000000
+#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, BTA_COMPLETED_EDGE, __x)
+#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EDGE_SHIFT 25
+#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EDGE_MASK 0x02000000
+#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, BTA_FINISHED_EDGE, __x)
+#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EDGE_SHIFT 26
+#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EDGE_MASK 0x04000000
+#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, READ_COMPLETED_WITH_ERR_EDGE, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL 0x000000FC
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_FIXED_EN_SHIFT 0
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_FIXED_EN_MASK 0x00000001
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_FIXED_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_FIXED_EN, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNCORRECTABLE_EN_SHIFT 1
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNCORRECTABLE_EN_MASK 0x00000002
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNCORRECTABLE_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_UNCORRECTABLE_EN, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_CHECKSUM_EN_SHIFT 2
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_CHECKSUM_EN_MASK 0x00000004
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_CHECKSUM_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_CHECKSUM_EN, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNDECODABLE_EN_SHIFT 3
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNDECODABLE_EN_MASK 0x00000008
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNDECODABLE_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_UNDECODABLE_EN, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_RECEIVE_EN_SHIFT 4
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_RECEIVE_EN_MASK 0x00000010
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_RECEIVE_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_RECEIVE_EN, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_OVERSIZE_EN_SHIFT 5
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_OVERSIZE_EN_MASK 0x00000020
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_OVERSIZE_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_OVERSIZE_EN, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_WRONG_LENGTH_EN_SHIFT 6
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_WRONG_LENGTH_EN_MASK 0x00000040
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_WRONG_LENGTH_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_WRONG_LENGTH_EN, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_MISSING_EOT_EN_SHIFT 7
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_MISSING_EOT_EN_MASK 0x00000080
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_MISSING_EOT_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_MISSING_EOT_EN, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_EOT_WITH_ERR_EN_SHIFT 8
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_EOT_WITH_ERR_EN_MASK 0x00000100
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_EOT_WITH_ERR_EN(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_EOT_WITH_ERR_EN, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_FIXED_EDGE_SHIFT 16
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_FIXED_EDGE_MASK 0x00010000
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_FIXED_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_FIXED_EDGE, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNCORRECTABLE_EDGE_SHIFT 17
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNCORRECTABLE_EDGE_MASK 0x00020000
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNCORRECTABLE_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_UNCORRECTABLE_EDGE, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_CHECKSUM_EDGE_SHIFT 18
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_CHECKSUM_EDGE_MASK 0x00040000
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_CHECKSUM_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_CHECKSUM_EDGE, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNDECODABLE_EDGE_SHIFT 19
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNDECODABLE_EDGE_MASK 0x00080000
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNDECODABLE_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_UNDECODABLE_EDGE, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_RECEIVE_EDGE_SHIFT 20
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_RECEIVE_EDGE_MASK 0x00100000
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_RECEIVE_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_RECEIVE_EDGE, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_OVERSIZE_EDGE_SHIFT 21
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_OVERSIZE_EDGE_MASK 0x00200000
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_OVERSIZE_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_OVERSIZE_EDGE, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_WRONG_LENGTH_EDGE_SHIFT 22
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_WRONG_LENGTH_EDGE_MASK 0x00400000
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_WRONG_LENGTH_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_WRONG_LENGTH_EDGE, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_MISSING_EOT_EDGE_SHIFT 23
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_MISSING_EOT_EDGE_MASK 0x00800000
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_MISSING_EOT_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_MISSING_EOT_EDGE, __x)
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_EOT_WITH_ERR_EDGE_SHIFT 24
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_EOT_WITH_ERR_EDGE_MASK 0x01000000
+#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_EOT_WITH_ERR_EDGE(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_EOT_WITH_ERR_EDGE, __x)
+#define DSI_VID_MODE_STS_CTL 0x00000100
+#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EN_SHIFT 0
+#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EN_MASK 0x00000001
+#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EN(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, VSG_RUNNING_EN, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EN_SHIFT 1
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EN_MASK 0x00000002
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EN(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_MISSING_DATA_EN, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EN_SHIFT 2
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EN_MASK 0x00000004
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EN(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_MISSING_HSYNC_EN, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EN_SHIFT 3
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EN_MASK 0x00000008
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EN(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_MISSING_VSYNC_EN, __x)
+#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EN_SHIFT 4
+#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EN_MASK 0x00000010
+#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EN(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, REG_ERR_SMALL_LENGTH_EN, __x)
+#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EN_SHIFT 5
+#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EN_MASK 0x00000020
+#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EN(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, REG_ERR_SMALL_HEIGHT_EN, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EN_SHIFT 6
+#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EN_MASK 0x00000040
+#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EN(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_BURSTWRITE_EN, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EN_SHIFT 7
+#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EN_MASK 0x00000080
+#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EN(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_LONGWRITE_EN, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EN_SHIFT 8
+#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EN_MASK 0x00000100
+#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EN(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_LONGREAD_EN, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EN_SHIFT 9
+#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EN_MASK 0x00000200
+#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EN(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_VRS_WRONG_LENGTH_EN, __x)
+#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EDGE_SHIFT 16
+#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EDGE_MASK 0x00010000
+#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EDGE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, VSG_RUNNING_EDGE, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EDGE_SHIFT 17
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EDGE_MASK 0x00020000
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EDGE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_MISSING_DATA_EDGE, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EDGE_SHIFT 18
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EDGE_MASK 0x00040000
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EDGE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_MISSING_HSYNC_EDGE, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EDGE_SHIFT 19
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EDGE_MASK 0x00080000
+#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EDGE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_MISSING_VSYNC_EDGE, __x)
+#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EDGE_SHIFT 20
+#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EDGE_MASK 0x00100000
+#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EDGE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, REG_ERR_SMALL_LENGTH_EDGE, __x)
+#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EDGE_SHIFT 21
+#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EDGE_MASK 0x00200000
+#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EDGE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, REG_ERR_SMALL_HEIGHT_EDGE, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EDGE_SHIFT 22
+#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EDGE_MASK 0x00400000
+#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EDGE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_BURSTWRITE_EDGE, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EDGE_SHIFT 23
+#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EDGE_MASK 0x00800000
+#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EDGE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_LONGWRITE_EDGE, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EDGE_SHIFT 24
+#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EDGE_MASK 0x01000000
+#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EDGE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_LONGREAD_EDGE, __x)
+#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EDGE_SHIFT 25
+#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EDGE_MASK 0x02000000
+#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EDGE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_VRS_WRONG_LENGTH_EDGE, __x)
+#define DSI_VID_MODE_STS_CTL_VSG_RECOVERY_EDGE_SHIFT 26
+#define DSI_VID_MODE_STS_CTL_VSG_RECOVERY_EDGE_MASK 0x04000000
+#define DSI_VID_MODE_STS_CTL_VSG_RECOVERY_EDGE(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CTL, VSG_RECOVERY_EDGE, __x)
+#define DSI_TG_STS_CTL 0x00000104
+#define DSI_TG_STS_CTL_TVG_STS_EN_SHIFT 0
+#define DSI_TG_STS_CTL_TVG_STS_EN_MASK 0x00000001
+#define DSI_TG_STS_CTL_TVG_STS_EN(__x) \
+ DSI_VAL2REG(DSI_TG_STS_CTL, TVG_STS_EN, __x)
+#define DSI_TG_STS_CTL_TBG_STS_EN_SHIFT 1
+#define DSI_TG_STS_CTL_TBG_STS_EN_MASK 0x00000002
+#define DSI_TG_STS_CTL_TBG_STS_EN(__x) \
+ DSI_VAL2REG(DSI_TG_STS_CTL, TBG_STS_EN, __x)
+#define DSI_TG_STS_CTL_TVG_STS_EDGE_SHIFT 16
+#define DSI_TG_STS_CTL_TVG_STS_EDGE_MASK 0x00010000
+#define DSI_TG_STS_CTL_TVG_STS_EDGE(__x) \
+ DSI_VAL2REG(DSI_TG_STS_CTL, TVG_STS_EDGE, __x)
+#define DSI_TG_STS_CTL_TBG_STS_EDGE_SHIFT 17
+#define DSI_TG_STS_CTL_TBG_STS_EDGE_MASK 0x00020000
+#define DSI_TG_STS_CTL_TBG_STS_EDGE(__x) \
+ DSI_VAL2REG(DSI_TG_STS_CTL, TBG_STS_EDGE, __x)
+#define DSI_MCTL_DHPY_ERR_CTL 0x00000108
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_1_EN_SHIFT 6
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_1_EN_MASK 0x00000040
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_1_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_ESC_1_EN, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_2_EN_SHIFT 7
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_2_EN_MASK 0x00000080
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_2_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_ESC_2_EN, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_1_EN_SHIFT 8
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_1_EN_MASK 0x00000100
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_1_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_SYNCESC_1_EN, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_2_EN_SHIFT 9
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_2_EN_MASK 0x00000200
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_2_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_SYNCESC_2_EN, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_1_EN_SHIFT 10
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_1_EN_MASK 0x00000400
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_1_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONTROL_1_EN, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_2_EN_SHIFT 11
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_2_EN_MASK 0x00000800
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_2_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONTROL_2_EN, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_1_EN_SHIFT 12
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_1_EN_MASK 0x00001000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_1_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP0_1_EN, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_2_EN_SHIFT 13
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_2_EN_MASK 0x00002000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_2_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP0_2_EN, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_1_EN_SHIFT 14
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_1_EN_MASK 0x00004000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_1_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP1_1_EN, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_2_EN_SHIFT 15
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_2_EN_MASK 0x00008000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_2_EN(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP1_2_EN, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_1_EDGE_SHIFT 22
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_1_EDGE_MASK 0x00400000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_1_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_ESC_1_EDGE, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_2_EDGE_SHIFT 23
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_2_EDGE_MASK 0x00800000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_2_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_ESC_2_EDGE, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_1_EDGE_SHIFT 24
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_1_EDGE_MASK 0x01000000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_1_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_SYNCESC_1_EDGE, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_2_EDGE_SHIFT 25
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_2_EDGE_MASK 0x02000000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_2_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_SYNCESC_2_EDGE, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_1_EDGE_SHIFT 26
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_1_EDGE_MASK 0x04000000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_1_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONTROL_1_EDGE, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_2_EDGE_SHIFT 27
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_2_EDGE_MASK 0x08000000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_2_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONTROL_2_EDGE, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_1_EDGE_SHIFT 28
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_1_EDGE_MASK 0x10000000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_1_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP0_1_EDGE, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_2_EDGE_SHIFT 29
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_2_EDGE_MASK 0x20000000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_2_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP0_2_EDGE, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_1_EDGE_SHIFT 30
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_1_EDGE_MASK 0x40000000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_1_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP1_1_EDGE, __x)
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_2_EDGE_SHIFT 31
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_2_EDGE_MASK 0x80000000
+#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_2_EDGE(__x) \
+ DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP1_2_EDGE, __x)
+#define DSI_MCTL_MAIN_STS_CLR 0x00000110
+#define DSI_MCTL_MAIN_STS_CLR_PLL_LOCK_CLR_SHIFT 0
+#define DSI_MCTL_MAIN_STS_CLR_PLL_LOCK_CLR_MASK 0x00000001
+#define DSI_MCTL_MAIN_STS_CLR_PLL_LOCK_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, PLL_LOCK_CLR, __x)
+#define DSI_MCTL_MAIN_STS_CLR_CLKLANE_READY_CLR_SHIFT 1
+#define DSI_MCTL_MAIN_STS_CLR_CLKLANE_READY_CLR_MASK 0x00000002
+#define DSI_MCTL_MAIN_STS_CLR_CLKLANE_READY_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, CLKLANE_READY_CLR, __x)
+#define DSI_MCTL_MAIN_STS_CLR_DAT1_READY_CLR_SHIFT 2
+#define DSI_MCTL_MAIN_STS_CLR_DAT1_READY_CLR_MASK 0x00000004
+#define DSI_MCTL_MAIN_STS_CLR_DAT1_READY_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, DAT1_READY_CLR, __x)
+#define DSI_MCTL_MAIN_STS_CLR_DAT2_READY_CLR_SHIFT 3
+#define DSI_MCTL_MAIN_STS_CLR_DAT2_READY_CLR_MASK 0x00000008
+#define DSI_MCTL_MAIN_STS_CLR_DAT2_READY_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, DAT2_READY_CLR, __x)
+#define DSI_MCTL_MAIN_STS_CLR_HSTX_TO_ERR_CLR_SHIFT 4
+#define DSI_MCTL_MAIN_STS_CLR_HSTX_TO_ERR_CLR_MASK 0x00000010
+#define DSI_MCTL_MAIN_STS_CLR_HSTX_TO_ERR_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, HSTX_TO_ERR_CLR, __x)
+#define DSI_MCTL_MAIN_STS_CLR_LPRX_TO_ERR_CLR_SHIFT 5
+#define DSI_MCTL_MAIN_STS_CLR_LPRX_TO_ERR_CLR_MASK 0x00000020
+#define DSI_MCTL_MAIN_STS_CLR_LPRX_TO_ERR_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, LPRX_TO_ERR_CLR, __x)
+#define DSI_MCTL_MAIN_STS_CLR_CRS_UNTERM_PCK_CLR_SHIFT 6
+#define DSI_MCTL_MAIN_STS_CLR_CRS_UNTERM_PCK_CLR_MASK 0x00000040
+#define DSI_MCTL_MAIN_STS_CLR_CRS_UNTERM_PCK_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, CRS_UNTERM_PCK_CLR, __x)
+#define DSI_MCTL_MAIN_STS_CLR_VRS_UNTERM_PCK_CLR_SHIFT 7
+#define DSI_MCTL_MAIN_STS_CLR_VRS_UNTERM_PCK_CLR_MASK 0x00000080
+#define DSI_MCTL_MAIN_STS_CLR_VRS_UNTERM_PCK_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, VRS_UNTERM_PCK_CLR, __x)
+#define DSI_CMD_MODE_STS_CLR 0x00000114
+#define DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR_SHIFT 0
+#define DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR_MASK 0x00000001
+#define DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CLR, ERR_NO_TE_CLR, __x)
+#define DSI_CMD_MODE_STS_CLR_ERR_TE_MISS_CLR_SHIFT 1
+#define DSI_CMD_MODE_STS_CLR_ERR_TE_MISS_CLR_MASK 0x00000002
+#define DSI_CMD_MODE_STS_CLR_ERR_TE_MISS_CLR(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CLR, ERR_TE_MISS_CLR, __x)
+#define DSI_CMD_MODE_STS_CLR_ERR_SDI1_UNDERRUN_CLR_SHIFT 2
+#define DSI_CMD_MODE_STS_CLR_ERR_SDI1_UNDERRUN_CLR_MASK 0x00000004
+#define DSI_CMD_MODE_STS_CLR_ERR_SDI1_UNDERRUN_CLR(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CLR, ERR_SDI1_UNDERRUN_CLR, __x)
+#define DSI_CMD_MODE_STS_CLR_ERR_SDI2_UNDERRUN_CLR_SHIFT 3
+#define DSI_CMD_MODE_STS_CLR_ERR_SDI2_UNDERRUN_CLR_MASK 0x00000008
+#define DSI_CMD_MODE_STS_CLR_ERR_SDI2_UNDERRUN_CLR(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CLR, ERR_SDI2_UNDERRUN_CLR, __x)
+#define DSI_CMD_MODE_STS_CLR_ERR_UNWANTED_RD_CLR_SHIFT 4
+#define DSI_CMD_MODE_STS_CLR_ERR_UNWANTED_RD_CLR_MASK 0x00000010
+#define DSI_CMD_MODE_STS_CLR_ERR_UNWANTED_RD_CLR(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CLR, ERR_UNWANTED_RD_CLR, __x)
+#define DSI_CMD_MODE_STS_CLR_CSM_RUNNING_CLR_SHIFT 5
+#define DSI_CMD_MODE_STS_CLR_CSM_RUNNING_CLR_MASK 0x00000020
+#define DSI_CMD_MODE_STS_CLR_CSM_RUNNING_CLR(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_CLR, CSM_RUNNING_CLR, __x)
+#define DSI_DIRECT_CMD_STS_CLR 0x00000118
+#define DSI_DIRECT_CMD_STS_CLR_CMD_TRANSMISSION_CLR_SHIFT 0
+#define DSI_DIRECT_CMD_STS_CLR_CMD_TRANSMISSION_CLR_MASK 0x00000001
+#define DSI_DIRECT_CMD_STS_CLR_CMD_TRANSMISSION_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, CMD_TRANSMISSION_CLR, __x)
+#define DSI_DIRECT_CMD_STS_CLR_WRITE_COMPLETED_CLR_SHIFT 1
+#define DSI_DIRECT_CMD_STS_CLR_WRITE_COMPLETED_CLR_MASK 0x00000002
+#define DSI_DIRECT_CMD_STS_CLR_WRITE_COMPLETED_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, WRITE_COMPLETED_CLR, __x)
+#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_COMPLETED_CLR_SHIFT 2
+#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_COMPLETED_CLR_MASK 0x00000004
+#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_COMPLETED_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, TRIGGER_COMPLETED_CLR, __x)
+#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_CLR_SHIFT 3
+#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_CLR_MASK 0x00000008
+#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, READ_COMPLETED_CLR, __x)
+#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_RECEIVED_CLR_SHIFT 4
+#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_RECEIVED_CLR_MASK 0x00000010
+#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_RECEIVED_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, ACKNOWLEDGE_RECEIVED_CLR, __x)
+#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_WITH_ERR_RECEIVED_CLR_SHIFT 5
+#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_WITH_ERR_RECEIVED_CLR_MASK 0x00000020
+#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_WITH_ERR_RECEIVED_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, ACKNOWLEDGE_WITH_ERR_RECEIVED_CLR, __x)
+#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_RECEIVED_CLR_SHIFT 6
+#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_RECEIVED_CLR_MASK 0x00000040
+#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_RECEIVED_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, TRIGGER_RECEIVED_CLR, __x)
+#define DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR_SHIFT 7
+#define DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR_MASK 0x00000080
+#define DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, TE_RECEIVED_CLR, __x)
+#define DSI_DIRECT_CMD_STS_CLR_BTA_COMPLETED_CLR_SHIFT 8
+#define DSI_DIRECT_CMD_STS_CLR_BTA_COMPLETED_CLR_MASK 0x00000100
+#define DSI_DIRECT_CMD_STS_CLR_BTA_COMPLETED_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, BTA_COMPLETED_CLR, __x)
+#define DSI_DIRECT_CMD_STS_CLR_BTA_FINISHED_CLR_SHIFT 9
+#define DSI_DIRECT_CMD_STS_CLR_BTA_FINISHED_CLR_MASK 0x00000200
+#define DSI_DIRECT_CMD_STS_CLR_BTA_FINISHED_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, BTA_FINISHED_CLR, __x)
+#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_WITH_ERR_CLR_SHIFT 10
+#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_WITH_ERR_CLR_MASK 0x00000400
+#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_WITH_ERR_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, READ_COMPLETED_WITH_ERR_CLR, __x)
+#define DSI_DIRECT_CMD_RD_STS_CLR 0x0000011C
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_FIXED_CLR_SHIFT 0
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_FIXED_CLR_MASK 0x00000001
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_FIXED_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_FIXED_CLR, __x)
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_UNCORRECTABLE_CLR_SHIFT 1
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_UNCORRECTABLE_CLR_MASK 0x00000002
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_UNCORRECTABLE_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_UNCORRECTABLE_CLR, __x)
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_CHECKSUM_CLR_SHIFT 2
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_CHECKSUM_CLR_MASK 0x00000004
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_CHECKSUM_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_CHECKSUM_CLR, __x)
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_UNDECODABLE_CLR_SHIFT 3
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_UNDECODABLE_CLR_MASK 0x00000008
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_UNDECODABLE_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_UNDECODABLE_CLR, __x)
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_RECEIVE_CLR_SHIFT 4
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_RECEIVE_CLR_MASK 0x00000010
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_RECEIVE_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_RECEIVE_CLR, __x)
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_OVERSIZE_CLR_SHIFT 5
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_OVERSIZE_CLR_MASK 0x00000020
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_OVERSIZE_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_OVERSIZE_CLR, __x)
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_WRONG_LENGTH_CLR_SHIFT 6
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_WRONG_LENGTH_CLR_MASK 0x00000040
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_WRONG_LENGTH_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_WRONG_LENGTH_CLR, __x)
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_MISSING_EOT_CLR_SHIFT 7
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_MISSING_EOT_CLR_MASK 0x00000080
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_MISSING_EOT_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_MISSING_EOT_CLR, __x)
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_EOT_WITH_ERR_CLR_SHIFT 8
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_EOT_WITH_ERR_CLR_MASK 0x00000100
+#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_EOT_WITH_ERR_CLR(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_EOT_WITH_ERR_CLR, __x)
+#define DSI_VID_MODE_STS_CLR 0x00000120
+#define DSI_VID_MODE_STS_CLR_VSG_STS_CLR_SHIFT 0
+#define DSI_VID_MODE_STS_CLR_VSG_STS_CLR_MASK 0x00000001
+#define DSI_VID_MODE_STS_CLR_VSG_STS_CLR(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CLR, VSG_STS_CLR, __x)
+#define DSI_VID_MODE_STS_CLR_ERR_MISSING_DATA_CLR_SHIFT 1
+#define DSI_VID_MODE_STS_CLR_ERR_MISSING_DATA_CLR_MASK 0x00000002
+#define DSI_VID_MODE_STS_CLR_ERR_MISSING_DATA_CLR(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_MISSING_DATA_CLR, __x)
+#define DSI_VID_MODE_STS_CLR_ERR_MISSING_HSYNC_CLR_SHIFT 2
+#define DSI_VID_MODE_STS_CLR_ERR_MISSING_HSYNC_CLR_MASK 0x00000004
+#define DSI_VID_MODE_STS_CLR_ERR_MISSING_HSYNC_CLR(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_MISSING_HSYNC_CLR, __x)
+#define DSI_VID_MODE_STS_CLR_ERR_MISSING_VSYNC_CLR_SHIFT 3
+#define DSI_VID_MODE_STS_CLR_ERR_MISSING_VSYNC_CLR_MASK 0x00000008
+#define DSI_VID_MODE_STS_CLR_ERR_MISSING_VSYNC_CLR(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_MISSING_VSYNC_CLR, __x)
+#define DSI_VID_MODE_STS_CLR_REG_ERR_SMALL_LENGTH_CLR_SHIFT 4
+#define DSI_VID_MODE_STS_CLR_REG_ERR_SMALL_LENGTH_CLR_MASK 0x00000010
+#define DSI_VID_MODE_STS_CLR_REG_ERR_SMALL_LENGTH_CLR(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CLR, REG_ERR_SMALL_LENGTH_CLR, __x)
+#define DSI_VID_MODE_STS_CLR_REG_ERR_SMALL_HEIGHT_CLR_SHIFT 5
+#define DSI_VID_MODE_STS_CLR_REG_ERR_SMALL_HEIGHT_CLR_MASK 0x00000020
+#define DSI_VID_MODE_STS_CLR_REG_ERR_SMALL_HEIGHT_CLR(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CLR, REG_ERR_SMALL_HEIGHT_CLR, __x)
+#define DSI_VID_MODE_STS_CLR_ERR_BURSTWRITE_CLR_SHIFT 6
+#define DSI_VID_MODE_STS_CLR_ERR_BURSTWRITE_CLR_MASK 0x00000040
+#define DSI_VID_MODE_STS_CLR_ERR_BURSTWRITE_CLR(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_BURSTWRITE_CLR, __x)
+#define DSI_VID_MODE_STS_CLR_ERR_LONGWRITE_CLR_SHIFT 7
+#define DSI_VID_MODE_STS_CLR_ERR_LONGWRITE_CLR_MASK 0x00000080
+#define DSI_VID_MODE_STS_CLR_ERR_LONGWRITE_CLR(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_LONGWRITE_CLR, __x)
+#define DSI_VID_MODE_STS_CLR_ERR_LONGREAD_CLR_SHIFT 8
+#define DSI_VID_MODE_STS_CLR_ERR_LONGREAD_CLR_MASK 0x00000100
+#define DSI_VID_MODE_STS_CLR_ERR_LONGREAD_CLR(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_LONGREAD_CLR, __x)
+#define DSI_VID_MODE_STS_CLR_ERR_VRS_WRONG_LENGTH_CLR_SHIFT 9
+#define DSI_VID_MODE_STS_CLR_ERR_VRS_WRONG_LENGTH_CLR_MASK 0x00000200
+#define DSI_VID_MODE_STS_CLR_ERR_VRS_WRONG_LENGTH_CLR(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_VRS_WRONG_LENGTH_CLR, __x)
+#define DSI_VID_MODE_STS_CLR_VSG_RECOVERY_CLR_SHIFT 10
+#define DSI_VID_MODE_STS_CLR_VSG_RECOVERY_CLR_MASK 0x00000400
+#define DSI_VID_MODE_STS_CLR_VSG_RECOVERY_CLR(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_CLR, VSG_RECOVERY_CLR, __x)
+#define DSI_TG_STS_CLR 0x00000124
+#define DSI_TG_STS_CLR_TVG_STS_CLR_SHIFT 0
+#define DSI_TG_STS_CLR_TVG_STS_CLR_MASK 0x00000001
+#define DSI_TG_STS_CLR_TVG_STS_CLR(__x) \
+ DSI_VAL2REG(DSI_TG_STS_CLR, TVG_STS_CLR, __x)
+#define DSI_TG_STS_CLR_TBG_STS_CLR_SHIFT 1
+#define DSI_TG_STS_CLR_TBG_STS_CLR_MASK 0x00000002
+#define DSI_TG_STS_CLR_TBG_STS_CLR(__x) \
+ DSI_VAL2REG(DSI_TG_STS_CLR, TBG_STS_CLR, __x)
+#define DSI_MCTL_DPHY_ERR_CLR 0x00000128
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_ESC_1_CLR_SHIFT 6
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_ESC_1_CLR_MASK 0x00000040
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_ESC_1_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_ESC_1_CLR, __x)
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_ESC_2_CLR_SHIFT 7
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_ESC_2_CLR_MASK 0x00000080
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_ESC_2_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_ESC_2_CLR, __x)
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_SYNCESC_1_CLR_SHIFT 8
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_SYNCESC_1_CLR_MASK 0x00000100
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_SYNCESC_1_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_SYNCESC_1_CLR, __x)
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_SYNCESC_2_CLR_SHIFT 9
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_SYNCESC_2_CLR_MASK 0x00000200
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_SYNCESC_2_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_SYNCESC_2_CLR, __x)
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONTROL_1_CLR_SHIFT 10
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONTROL_1_CLR_MASK 0x00000400
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONTROL_1_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_CONTROL_1_CLR, __x)
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONTROL_2_CLR_SHIFT 11
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONTROL_2_CLR_MASK 0x00000800
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONTROL_2_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_CONTROL_2_CLR, __x)
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP0_1_CLR_SHIFT 12
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP0_1_CLR_MASK 0x00001000
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP0_1_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_CONT_LP0_1_CLR, __x)
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP0_2_CLR_SHIFT 13
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP0_2_CLR_MASK 0x00002000
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP0_2_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_CONT_LP0_2_CLR, __x)
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP1_1_CLR_SHIFT 14
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP1_1_CLR_MASK 0x00004000
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP1_1_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_CONT_LP1_1_CLR, __x)
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP1_2_CLR_SHIFT 15
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP1_2_CLR_MASK 0x00008000
+#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP1_2_CLR(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_CONT_LP1_2_CLR, __x)
+#define DSI_MCTL_MAIN_STS_FLAG 0x00000130
+#define DSI_MCTL_MAIN_STS_FLAG_PLL_LOCK_FLAG_SHIFT 0
+#define DSI_MCTL_MAIN_STS_FLAG_PLL_LOCK_FLAG_MASK 0x00000001
+#define DSI_MCTL_MAIN_STS_FLAG_PLL_LOCK_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, PLL_LOCK_FLAG, __x)
+#define DSI_MCTL_MAIN_STS_FLAG_CLKLANE_READY_FLAG_SHIFT 1
+#define DSI_MCTL_MAIN_STS_FLAG_CLKLANE_READY_FLAG_MASK 0x00000002
+#define DSI_MCTL_MAIN_STS_FLAG_CLKLANE_READY_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, CLKLANE_READY_FLAG, __x)
+#define DSI_MCTL_MAIN_STS_FLAG_DAT1_READY_FLAG_SHIFT 2
+#define DSI_MCTL_MAIN_STS_FLAG_DAT1_READY_FLAG_MASK 0x00000004
+#define DSI_MCTL_MAIN_STS_FLAG_DAT1_READY_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, DAT1_READY_FLAG, __x)
+#define DSI_MCTL_MAIN_STS_FLAG_DAT2_READY_FLAG_SHIFT 3
+#define DSI_MCTL_MAIN_STS_FLAG_DAT2_READY_FLAG_MASK 0x00000008
+#define DSI_MCTL_MAIN_STS_FLAG_DAT2_READY_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, DAT2_READY_FLAG, __x)
+#define DSI_MCTL_MAIN_STS_FLAG_HSTX_TO_ERR_FLAG_SHIFT 4
+#define DSI_MCTL_MAIN_STS_FLAG_HSTX_TO_ERR_FLAG_MASK 0x00000010
+#define DSI_MCTL_MAIN_STS_FLAG_HSTX_TO_ERR_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, HSTX_TO_ERR_FLAG, __x)
+#define DSI_MCTL_MAIN_STS_FLAG_LPRX_TO_ERR_FLAG_SHIFT 5
+#define DSI_MCTL_MAIN_STS_FLAG_LPRX_TO_ERR_FLAG_MASK 0x00000020
+#define DSI_MCTL_MAIN_STS_FLAG_LPRX_TO_ERR_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, LPRX_TO_ERR_FLAG, __x)
+#define DSI_MCTL_MAIN_STS_FLAG_CRS_UNTERM_PCK_FLAG_SHIFT 6
+#define DSI_MCTL_MAIN_STS_FLAG_CRS_UNTERM_PCK_FLAG_MASK 0x00000040
+#define DSI_MCTL_MAIN_STS_FLAG_CRS_UNTERM_PCK_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, CRS_UNTERM_PCK_FLAG, __x)
+#define DSI_MCTL_MAIN_STS_FLAG_VRS_UNTERM_PCK_FLAG_SHIFT 7
+#define DSI_MCTL_MAIN_STS_FLAG_VRS_UNTERM_PCK_FLAG_MASK 0x00000080
+#define DSI_MCTL_MAIN_STS_FLAG_VRS_UNTERM_PCK_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, VRS_UNTERM_PCK_FLAG, __x)
+#define DSI_CMD_MODE_STS_FLAG 0x00000134
+#define DSI_CMD_MODE_STS_FLAG_ERR_NO_TE_FLAG_SHIFT 0
+#define DSI_CMD_MODE_STS_FLAG_ERR_NO_TE_FLAG_MASK 0x00000001
+#define DSI_CMD_MODE_STS_FLAG_ERR_NO_TE_FLAG(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_FLAG, ERR_NO_TE_FLAG, __x)
+#define DSI_CMD_MODE_STS_FLAG_ERR_TE_MISS_FLAG_SHIFT 1
+#define DSI_CMD_MODE_STS_FLAG_ERR_TE_MISS_FLAG_MASK 0x00000002
+#define DSI_CMD_MODE_STS_FLAG_ERR_TE_MISS_FLAG(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_FLAG, ERR_TE_MISS_FLAG, __x)
+#define DSI_CMD_MODE_STS_FLAG_ERR_SDI1_UNDERRUN_FLAG_SHIFT 2
+#define DSI_CMD_MODE_STS_FLAG_ERR_SDI1_UNDERRUN_FLAG_MASK 0x00000004
+#define DSI_CMD_MODE_STS_FLAG_ERR_SDI1_UNDERRUN_FLAG(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_FLAG, ERR_SDI1_UNDERRUN_FLAG, __x)
+#define DSI_CMD_MODE_STS_FLAG_ERR_SDI2_UNDERRUN_FLAG_SHIFT 3
+#define DSI_CMD_MODE_STS_FLAG_ERR_SDI2_UNDERRUN_FLAG_MASK 0x00000008
+#define DSI_CMD_MODE_STS_FLAG_ERR_SDI2_UNDERRUN_FLAG(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_FLAG, ERR_SDI2_UNDERRUN_FLAG, __x)
+#define DSI_CMD_MODE_STS_FLAG_ERR_UNWANTED_RD_FLAG_SHIFT 4
+#define DSI_CMD_MODE_STS_FLAG_ERR_UNWANTED_RD_FLAG_MASK 0x00000010
+#define DSI_CMD_MODE_STS_FLAG_ERR_UNWANTED_RD_FLAG(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_FLAG, ERR_UNWANTED_RD_FLAG, __x)
+#define DSI_CMD_MODE_STS_FLAG_CSM_RUNNING_FLAG_SHIFT 5
+#define DSI_CMD_MODE_STS_FLAG_CSM_RUNNING_FLAG_MASK 0x00000020
+#define DSI_CMD_MODE_STS_FLAG_CSM_RUNNING_FLAG(__x) \
+ DSI_VAL2REG(DSI_CMD_MODE_STS_FLAG, CSM_RUNNING_FLAG, __x)
+#define DSI_DIRECT_CMD_STS_FLAG 0x00000138
+#define DSI_DIRECT_CMD_STS_FLAG_CMD_TRANSMISSION_FLAG_SHIFT 0
+#define DSI_DIRECT_CMD_STS_FLAG_CMD_TRANSMISSION_FLAG_MASK 0x00000001
+#define DSI_DIRECT_CMD_STS_FLAG_CMD_TRANSMISSION_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, CMD_TRANSMISSION_FLAG, __x)
+#define DSI_DIRECT_CMD_STS_FLAG_WRITE_COMPLETED_FLAG_SHIFT 1
+#define DSI_DIRECT_CMD_STS_FLAG_WRITE_COMPLETED_FLAG_MASK 0x00000002
+#define DSI_DIRECT_CMD_STS_FLAG_WRITE_COMPLETED_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, WRITE_COMPLETED_FLAG, __x)
+#define DSI_DIRECT_CMD_STS_FLAG_TRIGGER_COMPLETED_FLAG_SHIFT 2
+#define DSI_DIRECT_CMD_STS_FLAG_TRIGGER_COMPLETED_FLAG_MASK 0x00000004
+#define DSI_DIRECT_CMD_STS_FLAG_TRIGGER_COMPLETED_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, TRIGGER_COMPLETED_FLAG, __x)
+#define DSI_DIRECT_CMD_STS_FLAG_READ_COMPLETED_FLAG_SHIFT 3
+#define DSI_DIRECT_CMD_STS_FLAG_READ_COMPLETED_FLAG_MASK 0x00000008
+#define DSI_DIRECT_CMD_STS_FLAG_READ_COMPLETED_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, READ_COMPLETED_FLAG, __x)
+#define DSI_DIRECT_CMD_STS_FLAG_ACKNOWLEDGE_RECEIVED_FLAG_SHIFT 4
+#define DSI_DIRECT_CMD_STS_FLAG_ACKNOWLEDGE_RECEIVED_FLAG_MASK 0x00000010
+#define DSI_DIRECT_CMD_STS_FLAG_ACKNOWLEDGE_RECEIVED_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, ACKNOWLEDGE_RECEIVED_FLAG, __x)
+#define DSI_DIRECT_CMD_STS_FLAG_ACKNOWLEDGE_WITH_ERR_RECEIVED_FLAG_SHIFT 5
+#define DSI_DIRECT_CMD_STS_FLAG_ACKNOWLEDGE_WITH_ERR_RECEIVED_FLAG_MASK 0x00000020
+#define DSI_DIRECT_CMD_STS_FLAG_ACKNOWLEDGE_WITH_ERR_RECEIVED_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, ACKNOWLEDGE_WITH_ERR_RECEIVED_FLAG, __x)
+#define DSI_DIRECT_CMD_STS_FLAG_TRIGGER_RECEIVED_FLAG_SHIFT 6
+#define DSI_DIRECT_CMD_STS_FLAG_TRIGGER_RECEIVED_FLAG_MASK 0x00000040
+#define DSI_DIRECT_CMD_STS_FLAG_TRIGGER_RECEIVED_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, TRIGGER_RECEIVED_FLAG, __x)
+#define DSI_DIRECT_CMD_STS_FLAG_TE_RECEIVED_FLAG_SHIFT 7
+#define DSI_DIRECT_CMD_STS_FLAG_TE_RECEIVED_FLAG_MASK 0x00000080
+#define DSI_DIRECT_CMD_STS_FLAG_TE_RECEIVED_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, TE_RECEIVED_FLAG, __x)
+#define DSI_DIRECT_CMD_STS_FLAG_BTA_COMPLETED_FLAG_SHIFT 8
+#define DSI_DIRECT_CMD_STS_FLAG_BTA_COMPLETED_FLAG_MASK 0x00000100
+#define DSI_DIRECT_CMD_STS_FLAG_BTA_COMPLETED_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, BTA_COMPLETED_FLAG, __x)
+#define DSI_DIRECT_CMD_STS_FLAG_BTA_FINISHED_FLAG_SHIFT 9
+#define DSI_DIRECT_CMD_STS_FLAG_BTA_FINISHED_FLAG_MASK 0x00000200
+#define DSI_DIRECT_CMD_STS_FLAG_BTA_FINISHED_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, BTA_FINISHED_FLAG, __x)
+#define DSI_DIRECT_CMD_STS_FLAG_READ_COMPLETED_WITH_ERR_FLAG_SHIFT 10
+#define DSI_DIRECT_CMD_STS_FLAG_READ_COMPLETED_WITH_ERR_FLAG_MASK 0x00000400
+#define DSI_DIRECT_CMD_STS_FLAG_READ_COMPLETED_WITH_ERR_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, READ_COMPLETED_WITH_ERR_FLAG, __x)
+#define DSI_DIRECT_CMD_RD_STS_FLAG 0x0000013C
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_FIXED_FLAG_SHIFT 0
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_FIXED_FLAG_MASK 0x00000001
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_FIXED_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_FIXED_FLAG, __x)
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_UNCORRECTABLE_FLAG_SHIFT 1
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_UNCORRECTABLE_FLAG_MASK 0x00000002
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_UNCORRECTABLE_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_UNCORRECTABLE_FLAG, __x)
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_CHECKSUM_FLAG_SHIFT 2
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_CHECKSUM_FLAG_MASK 0x00000004
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_CHECKSUM_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_CHECKSUM_FLAG, __x)
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_UNDECODABLE_FLAG_SHIFT 3
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_UNDECODABLE_FLAG_MASK 0x00000008
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_UNDECODABLE_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_UNDECODABLE_FLAG, __x)
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_RECEIVE_FLAG_SHIFT 4
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_RECEIVE_FLAG_MASK 0x00000010
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_RECEIVE_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_RECEIVE_FLAG, __x)
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_OVERSIZE_FLAG_SHIFT 5
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_OVERSIZE_FLAG_MASK 0x00000020
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_OVERSIZE_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_OVERSIZE_FLAG, __x)
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_WRONG_LENGTH_FLAG_SHIFT 6
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_WRONG_LENGTH_FLAG_MASK 0x00000040
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_WRONG_LENGTH_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_WRONG_LENGTH_FLAG, __x)
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_MISSING_EOT_FLAG_SHIFT 7
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_MISSING_EOT_FLAG_MASK 0x00000080
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_MISSING_EOT_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_MISSING_EOT_FLAG, __x)
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_EOT_WITH_ERR_FLAG_SHIFT 8
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_EOT_WITH_ERR_FLAG_MASK 0x00000100
+#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_EOT_WITH_ERR_FLAG(__x) \
+ DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_EOT_WITH_ERR_FLAG, __x)
+#define DSI_VID_MODE_STS_FLAG 0x00000140
+#define DSI_VID_MODE_STS_FLAG_VSG_STS_FLAG_SHIFT 0
+#define DSI_VID_MODE_STS_FLAG_VSG_STS_FLAG_MASK 0x00000001
+#define DSI_VID_MODE_STS_FLAG_VSG_STS_FLAG(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, VSG_STS_FLAG, __x)
+#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_DATA_FLAG_SHIFT 1
+#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_DATA_FLAG_MASK 0x00000002
+#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_DATA_FLAG(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_MISSING_DATA_FLAG, __x)
+#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_HSYNC_FLAG_SHIFT 2
+#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_HSYNC_FLAG_MASK 0x00000004
+#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_HSYNC_FLAG(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_MISSING_HSYNC_FLAG, __x)
+#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_VSYNC_FLAG_SHIFT 3
+#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_VSYNC_FLAG_MASK 0x00000008
+#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_VSYNC_FLAG(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_MISSING_VSYNC_FLAG, __x)
+#define DSI_VID_MODE_STS_FLAG_REG_ERR_SMALL_LENGTH_FLAG_SHIFT 4
+#define DSI_VID_MODE_STS_FLAG_REG_ERR_SMALL_LENGTH_FLAG_MASK 0x00000010
+#define DSI_VID_MODE_STS_FLAG_REG_ERR_SMALL_LENGTH_FLAG(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, REG_ERR_SMALL_LENGTH_FLAG, __x)
+#define DSI_VID_MODE_STS_FLAG_REG_ERR_SMALL_HEIGHT_FLAG_SHIFT 5
+#define DSI_VID_MODE_STS_FLAG_REG_ERR_SMALL_HEIGHT_FLAG_MASK 0x00000020
+#define DSI_VID_MODE_STS_FLAG_REG_ERR_SMALL_HEIGHT_FLAG(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, REG_ERR_SMALL_HEIGHT_FLAG, __x)
+#define DSI_VID_MODE_STS_FLAG_ERR_BURSTWRITE_FLAG_SHIFT 6
+#define DSI_VID_MODE_STS_FLAG_ERR_BURSTWRITE_FLAG_MASK 0x00000040
+#define DSI_VID_MODE_STS_FLAG_ERR_BURSTWRITE_FLAG(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_BURSTWRITE_FLAG, __x)
+#define DSI_VID_MODE_STS_FLAG_ERR_LONGWRITE_FLAG_SHIFT 7
+#define DSI_VID_MODE_STS_FLAG_ERR_LONGWRITE_FLAG_MASK 0x00000080
+#define DSI_VID_MODE_STS_FLAG_ERR_LONGWRITE_FLAG(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_LONGWRITE_FLAG, __x)
+#define DSI_VID_MODE_STS_FLAG_ERR_LONGREAD_FLAG_SHIFT 8
+#define DSI_VID_MODE_STS_FLAG_ERR_LONGREAD_FLAG_MASK 0x00000100
+#define DSI_VID_MODE_STS_FLAG_ERR_LONGREAD_FLAG(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_LONGREAD_FLAG, __x)
+#define DSI_VID_MODE_STS_FLAG_ERR_VRS_WRONG_LENGTH_FLAG_SHIFT 9
+#define DSI_VID_MODE_STS_FLAG_ERR_VRS_WRONG_LENGTH_FLAG_MASK 0x00000200
+#define DSI_VID_MODE_STS_FLAG_ERR_VRS_WRONG_LENGTH_FLAG(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_VRS_WRONG_LENGTH_FLAG, __x)
+#define DSI_VID_MODE_STS_FLAG_VSG_RECOVERY_FLAG_SHIFT 10
+#define DSI_VID_MODE_STS_FLAG_VSG_RECOVERY_FLAG_MASK 0x00000400
+#define DSI_VID_MODE_STS_FLAG_VSG_RECOVERY_FLAG(__x) \
+ DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, VSG_RECOVERY_FLAG, __x)
+#define DSI_TG_STS_FLAG 0x00000144
+#define DSI_TG_STS_FLAG_TVG_STS_FLAG_SHIFT 0
+#define DSI_TG_STS_FLAG_TVG_STS_FLAG_MASK 0x00000001
+#define DSI_TG_STS_FLAG_TVG_STS_FLAG(__x) \
+ DSI_VAL2REG(DSI_TG_STS_FLAG, TVG_STS_FLAG, __x)
+#define DSI_TG_STS_FLAG_TBG_STS_FLAG_SHIFT 1
+#define DSI_TG_STS_FLAG_TBG_STS_FLAG_MASK 0x00000002
+#define DSI_TG_STS_FLAG_TBG_STS_FLAG(__x) \
+ DSI_VAL2REG(DSI_TG_STS_FLAG, TBG_STS_FLAG, __x)
+#define DSI_MCTL_DPHY_ERR_FLAG 0x00000148
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_ESC_1_FLAG_SHIFT 6
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_ESC_1_FLAG_MASK 0x00000040
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_ESC_1_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_ESC_1_FLAG, __x)
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_ESC_2_FLAG_SHIFT 7
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_ESC_2_FLAG_MASK 0x00000080
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_ESC_2_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_ESC_2_FLAG, __x)
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_SYNCESC_1_FLAG_SHIFT 8
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_SYNCESC_1_FLAG_MASK 0x00000100
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_SYNCESC_1_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_SYNCESC_1_FLAG, __x)
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_SYNCESC_2_FLAG_SHIFT 9
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_SYNCESC_2_FLAG_MASK 0x00000200
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_SYNCESC_2_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_SYNCESC_2_FLAG, __x)
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONTROL_1_FLAG_SHIFT 10
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONTROL_1_FLAG_MASK 0x00000400
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONTROL_1_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_CONTROL_1_FLAG, __x)
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONTROL_2_FLAG_SHIFT 11
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONTROL_2_FLAG_MASK 0x00000800
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONTROL_2_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_CONTROL_2_FLAG, __x)
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP0_1_FLAG_SHIFT 12
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP0_1_FLAG_MASK 0x00001000
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP0_1_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_CONT_LP0_1_FLAG, __x)
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP0_2_FLAG_SHIFT 13
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP0_2_FLAG_MASK 0x00002000
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP0_2_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_CONT_LP0_2_FLAG, __x)
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP1_1_FLAG_SHIFT 14
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP1_1_FLAG_MASK 0x00004000
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP1_1_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_CONT_LP1_1_FLAG, __x)
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP1_2_FLAG_SHIFT 15
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP1_2_FLAG_MASK 0x00008000
+#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP1_2_FLAG(__x) \
+ DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_CONT_LP1_2_FLAG, __x)
+#define DSI_DPHY_LANES_TRIM 0x00000150
+#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT1_SHIFT 0
+#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT1_MASK 0x00000003
+#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT1(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_SKEW_DAT1, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_CD_OFF_DAT1_SHIFT 2
+#define DSI_DPHY_LANES_TRIM_DPHY_CD_OFF_DAT1_MASK 0x00000004
+#define DSI_DPHY_LANES_TRIM_DPHY_CD_OFF_DAT1(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_CD_OFF_DAT1, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT1_SHIFT 3
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT1_MASK 0x00000008
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT1(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_HSTX_SLEWRATE_UP_DAT1, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT1_SHIFT 4
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT1_MASK 0x00000010
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT1(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_HSTX_SLEWRATE_DOWN_DAT1, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT1_SHIFT 5
+#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT1_MASK 0x00000020
+#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT1(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_TEST_RESERVED_1_DAT1, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_CLK_SHIFT 6
+#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_CLK_MASK 0x000000C0
+#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_CLK(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_SKEW_CLK, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_LP_RX_VIL_CLK_SHIFT 8
+#define DSI_DPHY_LANES_TRIM_DPHY_LP_RX_VIL_CLK_MASK 0x00000300
+#define DSI_DPHY_LANES_TRIM_DPHY_LP_RX_VIL_CLK(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_LP_RX_VIL_CLK, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_LP_TX_SLEWRATE_CLK_SHIFT 10
+#define DSI_DPHY_LANES_TRIM_DPHY_LP_TX_SLEWRATE_CLK_MASK 0x00000C00
+#define DSI_DPHY_LANES_TRIM_DPHY_LP_TX_SLEWRATE_CLK(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_LP_TX_SLEWRATE_CLK, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_SHIFT 12
+#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_MASK 0x00001000
+#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_0_81 0
+#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_0_90 1
+#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_ENUM(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_SPECS_90_81B, \
+ DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_##__x)
+#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_SPECS_90_81B, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_CLK_SHIFT 13
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_CLK_MASK 0x00002000
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_CLK(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_HSTX_SLEWRATE_UP_CLK, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_CLK_SHIFT 14
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_CLK_MASK 0x00004000
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_CLK(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_HSTX_SLEWRATE_DOWN_CLK, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_CLK_SHIFT 15
+#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_CLK_MASK 0x00008000
+#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_CLK(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_TEST_RESERVED_1_CLK, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT2_SHIFT 16
+#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT2_MASK 0x00030000
+#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT2(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_SKEW_DAT2, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT2_SHIFT 18
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT2_MASK 0x00040000
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT2(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_HSTX_SLEWRATE_UP_DAT2, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT2_SHIFT 19
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT2_MASK 0x00080000
+#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT2(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_HSTX_SLEWRATE_DOWN_DAT2, __x)
+#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT2_SHIFT 20
+#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT2_MASK 0x00100000
+#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT2(__x) \
+ DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_TEST_RESERVED_1_DAT2, __x)
+#define DSI_ID_REG 0x00000FF0
+#define DSI_ID_REG_Y_SHIFT 0
+#define DSI_ID_REG_Y_MASK 0x0000000F
+#define DSI_ID_REG_Y(__x) \
+ DSI_VAL2REG(DSI_ID_REG, Y, __x)
+#define DSI_ID_REG_X_SHIFT 4
+#define DSI_ID_REG_X_MASK 0x000000F0
+#define DSI_ID_REG_X(__x) \
+ DSI_VAL2REG(DSI_ID_REG, X, __x)
+#define DSI_ID_REG_H_SHIFT 8
+#define DSI_ID_REG_H_MASK 0x00000300
+#define DSI_ID_REG_H(__x) \
+ DSI_VAL2REG(DSI_ID_REG, H, __x)
+#define DSI_ID_REG_PRODUCT_ID_SHIFT 10
+#define DSI_ID_REG_PRODUCT_ID_MASK 0x0003FC00
+#define DSI_ID_REG_PRODUCT_ID(__x) \
+ DSI_VAL2REG(DSI_ID_REG, PRODUCT_ID, __x)
+#define DSI_ID_REG_VENDOR_ID_SHIFT 18
+#define DSI_ID_REG_VENDOR_ID_MASK 0xFFFC0000
+#define DSI_ID_REG_VENDOR_ID(__x) \
+ DSI_VAL2REG(DSI_ID_REG, VENDOR_ID, __x)
+#define DSI_IP_CONF 0x00000FF4
+#define DSI_IP_CONF_FIFO_SIZE_SHIFT 0
+#define DSI_IP_CONF_FIFO_SIZE_MASK 0x0000003F
+#define DSI_IP_CONF_FIFO_SIZE(__x) \
+ DSI_VAL2REG(DSI_IP_CONF, FIFO_SIZE, __x)
diff --git a/drivers/video/mcde/mcde_bus.c b/drivers/video/mcde/mcde_bus.c
new file mode 100644
index 00000000000..63c6079a879
--- /dev/null
+++ b/drivers/video/mcde/mcde_bus.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * ST-Ericsson MCDE display bus driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/notifier.h>
+
+#include <video/mcde_display.h>
+#include <video/mcde_dss.h>
+
+#define to_mcde_display_driver(__drv) \
+ container_of((__drv), struct mcde_display_driver, driver)
+
+static BLOCKING_NOTIFIER_HEAD(bus_notifier_list);
+
+static int mcde_drv_suspend(struct device *_dev, pm_message_t state);
+static int mcde_drv_resume(struct device *_dev);
+struct bus_type mcde_bus_type;
+
+static int mcde_suspend_device(struct device *dev, void *data)
+{
+ pm_message_t* state = (pm_message_t *) data;
+ if (dev->driver->suspend)
+ return dev->driver->suspend(dev, *state);
+ return 0;
+}
+
+static int mcde_resume_device(struct device *dev, void *data)
+{
+ if (dev->driver->resume)
+ return dev->driver->resume(dev);
+ return 0;
+}
+
+/* Bus driver */
+
+static int mcde_bus_match(struct device *_dev, struct device_driver *driver)
+{
+ pr_debug("Matching device %s with driver %s\n",
+ dev_name(_dev), driver->name);
+
+ return strncmp(dev_name(_dev), driver->name, strlen(driver->name)) == 0;
+}
+
+static int mcde_bus_suspend(struct device *_dev, pm_message_t state)
+{
+ int ret;
+ ret = bus_for_each_dev(&mcde_bus_type, NULL, &state,
+ mcde_suspend_device);
+ if (ret) {
+ /* TODO Resume all suspended devices */
+ /* mcde_bus_resume(dev); */
+ return ret;
+ }
+ return 0;
+}
+
+static int mcde_bus_resume(struct device *_dev)
+{
+ return bus_for_each_dev(&mcde_bus_type, NULL, NULL, mcde_resume_device);
+}
+
+struct bus_type mcde_bus_type = {
+ .name = "mcde_bus",
+ .match = mcde_bus_match,
+ .suspend = mcde_bus_suspend,
+ .resume = mcde_bus_resume,
+};
+
+static int mcde_drv_probe(struct device *_dev)
+{
+ struct mcde_display_driver *drv = to_mcde_display_driver(_dev->driver);
+ struct mcde_display_device *dev = to_mcde_display_device(_dev);
+
+ return drv->probe(dev);
+}
+
+static int mcde_drv_remove(struct device *_dev)
+{
+ struct mcde_display_driver *drv = to_mcde_display_driver(_dev->driver);
+ struct mcde_display_device *dev = to_mcde_display_device(_dev);
+
+ return drv->remove(dev);
+}
+
+static void mcde_drv_shutdown(struct device *_dev)
+{
+ struct mcde_display_driver *drv = to_mcde_display_driver(_dev->driver);
+ struct mcde_display_device *dev = to_mcde_display_device(_dev);
+
+ drv->shutdown(dev);
+}
+
+static int mcde_drv_suspend(struct device *_dev, pm_message_t state)
+{
+ struct mcde_display_driver *drv = to_mcde_display_driver(_dev->driver);
+ struct mcde_display_device *dev = to_mcde_display_device(_dev);
+
+ return drv->suspend(dev, state);
+}
+
+static int mcde_drv_resume(struct device *_dev)
+{
+ struct mcde_display_driver *drv = to_mcde_display_driver(_dev->driver);
+ struct mcde_display_device *dev = to_mcde_display_device(_dev);
+
+ return drv->resume(dev);
+}
+
+/* Bus device */
+
+static void mcde_bus_release(struct device *dev)
+{
+}
+
+struct device mcde_bus = {
+ .init_name = "mcde_bus",
+ .release = mcde_bus_release
+};
+
+/* Public bus API */
+
+int mcde_display_driver_register(struct mcde_display_driver *drv)
+{
+ drv->driver.bus = &mcde_bus_type;
+ if (drv->probe)
+ drv->driver.probe = mcde_drv_probe;
+ if (drv->remove)
+ drv->driver.remove = mcde_drv_remove;
+ if (drv->shutdown)
+ drv->driver.shutdown = mcde_drv_shutdown;
+ if (drv->suspend)
+ drv->driver.suspend = mcde_drv_suspend;
+ if (drv->resume)
+ drv->driver.resume = mcde_drv_resume;
+
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL(mcde_display_driver_register);
+
+void mcde_display_driver_unregister(struct mcde_display_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(mcde_display_driver_unregister);
+
+static void mcde_display_dev_release(struct device *dev)
+{
+ /* Do nothing */
+}
+
+int mcde_display_device_register(struct mcde_display_device *dev)
+{
+ /* Setup device */
+ if (!dev)
+ return -EINVAL;
+ dev->dev.coherent_dma_mask = DMA_32BIT_MASK;
+ dev->dev.bus = &mcde_bus_type;
+ if (dev->dev.parent != NULL)
+ dev->dev.parent = &mcde_bus;
+ dev->dev.release = mcde_display_dev_release;
+ if (dev->id != -1)
+ dev_set_name(&dev->dev, "%s.%d", dev->name, dev->id);
+ else
+ dev_set_name(&dev->dev, dev->name);
+
+ mcde_display_init_device(dev);
+
+ return device_register(&dev->dev);
+}
+EXPORT_SYMBOL(mcde_display_device_register);
+
+void mcde_display_device_unregister(struct mcde_display_device *dev)
+{
+ device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL(mcde_display_device_unregister);
+
+/* Notifications */
+int mcde_dss_register_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&bus_notifier_list, nb);
+}
+EXPORT_SYMBOL(mcde_dss_register_notifier);
+
+int mcde_dss_unregister_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&bus_notifier_list, nb);
+}
+EXPORT_SYMBOL(mcde_dss_unregister_notifier);
+
+static int bus_notify_callback(struct notifier_block *nb,
+ unsigned long event, void *dev)
+{
+ struct mcde_display_device *ddev = to_mcde_display_device(dev);
+
+ if (event == BUS_NOTIFY_BOUND_DRIVER) {
+ ddev->initialized = true;
+ blocking_notifier_call_chain(&bus_notifier_list,
+ MCDE_DSS_EVENT_DISPLAY_REGISTERED, ddev);
+ } else if (event == BUS_NOTIFY_UNBIND_DRIVER) {
+ ddev->initialized = false;
+ blocking_notifier_call_chain(&bus_notifier_list,
+ MCDE_DSS_EVENT_DISPLAY_UNREGISTERED, ddev);
+ }
+ return 0;
+}
+
+struct notifier_block bus_nb = {
+ .notifier_call = bus_notify_callback,
+};
+
+/* Driver init/exit */
+
+int __init mcde_display_init(void)
+{
+ int ret;
+
+ ret = bus_register(&mcde_bus_type);
+ if (ret) {
+ pr_warning("Unable to register bus type\n");
+ goto no_bus_registration;
+ }
+ ret = device_register(&mcde_bus);
+ if (ret) {
+ pr_warning("Unable to register bus device\n");
+ goto no_device_registration;
+ }
+ ret = bus_register_notifier(&mcde_bus_type, &bus_nb);
+ if (ret) {
+ pr_warning("Unable to register bus notifier\n");
+ goto no_bus_notifier;
+ }
+
+ goto out;
+
+no_bus_notifier:
+ device_unregister(&mcde_bus);
+no_device_registration:
+ bus_unregister(&mcde_bus_type);
+no_bus_registration:
+out:
+ return ret;
+}
+
+void mcde_display_exit(void)
+{
+ bus_unregister_notifier(&mcde_bus_type, &bus_nb);
+ device_unregister(&mcde_bus);
+ bus_unregister(&mcde_bus_type);
+}
diff --git a/drivers/video/mcde/mcde_display.c b/drivers/video/mcde/mcde_display.c
new file mode 100644
index 00000000000..84545297481
--- /dev/null
+++ b/drivers/video/mcde/mcde_display.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson MCDE display driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+#include <video/mcde_display.h>
+
+/*temp*/
+#include <linux/delay.h>
+
+static void mcde_display_get_native_resolution_default(
+ struct mcde_display_device *ddev, u16 *x_res, u16 *y_res)
+{
+ if (x_res)
+ *x_res = ddev->native_x_res;
+ if (y_res)
+ *y_res = ddev->native_y_res;
+}
+
+static enum mcde_ovly_pix_fmt mcde_display_get_default_pixel_format_default(
+ struct mcde_display_device *ddev)
+{
+ return ddev->default_pixel_format;
+}
+
+static void mcde_display_get_physical_size_default(
+ struct mcde_display_device *ddev, u16 *width, u16 *height)
+{
+ if (width)
+ *width = ddev->physical_width;
+ if (height)
+ *height = ddev->physical_height;
+}
+
+static int mcde_display_set_power_mode_default(struct mcde_display_device *ddev,
+ enum mcde_display_power_mode power_mode)
+{
+ int ret;
+
+ /* OFF -> STANDBY */
+ if (ddev->power_mode == MCDE_DISPLAY_PM_OFF &&
+ power_mode != MCDE_DISPLAY_PM_OFF) {
+ if (ddev->platform_enable) {
+ ret = ddev->platform_enable(ddev);
+ if (ret)
+ return ret;
+ }
+ ddev->power_mode = MCDE_DISPLAY_PM_STANDBY;
+ }
+
+ if (ddev->port->type == MCDE_PORTTYPE_DSI) {
+ /* STANDBY -> ON */
+ if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY &&
+ power_mode == MCDE_DISPLAY_PM_ON) {
+ ret = mcde_dsi_dcs_write(ddev->chnl_state,
+ DCS_CMD_EXIT_SLEEP_MODE, NULL, 0);
+ if (ret)
+ return ret;
+
+ ret = mcde_dsi_dcs_write(ddev->chnl_state,
+ DCS_CMD_SET_DISPLAY_ON, NULL, 0);
+ if (ret)
+ return ret;
+
+ ddev->power_mode = MCDE_DISPLAY_PM_ON;
+ goto set_power_and_exit;
+ }
+ /* ON -> STANDBY */
+ else if (ddev->power_mode == MCDE_DISPLAY_PM_ON &&
+ power_mode <= MCDE_DISPLAY_PM_STANDBY) {
+ ret = mcde_dsi_dcs_write(ddev->chnl_state,
+ DCS_CMD_SET_DISPLAY_OFF, NULL, 0);
+ if (ret)
+ return ret;
+
+ ret = mcde_dsi_dcs_write(ddev->chnl_state,
+ DCS_CMD_ENTER_SLEEP_MODE, NULL, 0);
+ if (ret)
+ return ret;
+
+ ddev->power_mode = MCDE_DISPLAY_PM_STANDBY;
+ goto set_power_and_exit;
+ }
+ } else if (ddev->port->type == MCDE_PORTTYPE_DPI)
+ ddev->power_mode = power_mode;
+ else if (ddev->power_mode != power_mode)
+ return -EINVAL;
+
+ /* SLEEP -> OFF */
+ if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY &&
+ power_mode == MCDE_DISPLAY_PM_OFF) {
+ if (ddev->platform_disable) {
+ ret = ddev->platform_disable(ddev);
+ if (ret)
+ return ret;
+ }
+ ddev->power_mode = MCDE_DISPLAY_PM_OFF;
+ }
+
+set_power_and_exit:
+ mcde_chnl_set_power_mode(ddev->chnl_state, ddev->power_mode);
+
+ return ret;
+}
+
+static inline enum mcde_display_power_mode mcde_display_get_power_mode_default(
+ struct mcde_display_device *ddev)
+{
+ return ddev->power_mode;
+}
+
+static inline int mcde_display_try_video_mode_default(
+ struct mcde_display_device *ddev,
+ struct mcde_video_mode *video_mode)
+{
+ /* TODO Check if inside native_xres and native_yres */
+ return 0;
+}
+
+static int mcde_display_set_video_mode_default(struct mcde_display_device *ddev,
+ struct mcde_video_mode *video_mode)
+{
+ int ret;
+ struct mcde_video_mode channel_video_mode;
+
+ if (!video_mode)
+ return -EINVAL;
+
+ ddev->video_mode = *video_mode;
+ channel_video_mode = ddev->video_mode;
+ /* Dependant on if display should rotate or MCDE should rotate */
+ if (ddev->rotation == MCDE_DISPLAY_ROT_90_CCW ||
+ ddev->rotation == MCDE_DISPLAY_ROT_90_CW) {
+ channel_video_mode.xres = ddev->native_x_res;
+ channel_video_mode.yres = ddev->native_y_res;
+ }
+ ret = mcde_chnl_set_video_mode(ddev->chnl_state, &channel_video_mode);
+ if (ret < 0) {
+ dev_warn(&ddev->dev, "%s:Failed to set video mode\n", __func__);
+ return ret;
+ }
+
+ ddev->update_flags |= UPDATE_FLAG_VIDEO_MODE;
+
+ return 0;
+}
+
+static inline void mcde_display_get_video_mode_default(
+ struct mcde_display_device *ddev, struct mcde_video_mode *video_mode)
+{
+ if (video_mode)
+ *video_mode = ddev->video_mode;
+}
+
+static int mcde_display_set_pixel_format_default(
+ struct mcde_display_device *ddev, enum mcde_ovly_pix_fmt format)
+{
+ int ret;
+
+ ddev->pixel_format = format;
+ ret = mcde_chnl_set_pixel_format(ddev->chnl_state,
+ ddev->port->pixel_format);
+ if (ret < 0) {
+ dev_warn(&ddev->dev, "%s:Failed to set pixel format = %d\n",
+ __func__, format);
+ return ret;
+ }
+
+ ddev->update_flags |= UPDATE_FLAG_PIXEL_FORMAT;
+
+ return 0;
+}
+
+static inline enum mcde_ovly_pix_fmt mcde_display_get_pixel_format_default(
+ struct mcde_display_device *ddev)
+{
+ return ddev->pixel_format;
+}
+
+static inline enum mcde_port_pix_fmt mcde_display_get_port_pixel_format_default(
+ struct mcde_display_device *ddev)
+{
+ return ddev->port->pixel_format;
+}
+
+static int mcde_display_set_rotation_default(struct mcde_display_device *ddev,
+ enum mcde_display_rotation rotation)
+{
+ int ret;
+
+ ret = mcde_chnl_set_rotation(ddev->chnl_state, rotation,
+ ddev->rotbuf1, ddev->rotbuf2);
+ if (ret < 0) {
+ dev_warn(&ddev->dev, "%s:Failed to set rotation = %d\n",
+ __func__, rotation);
+ return ret;
+ }
+
+ ddev->rotation = rotation;
+ ddev->update_flags |= UPDATE_FLAG_ROTATION;
+
+ return 0;
+}
+
+static inline enum mcde_display_rotation mcde_display_get_rotation_default(
+ struct mcde_display_device *ddev)
+{
+ return ddev->rotation;
+}
+
+static int mcde_display_set_synchronized_update_default(
+ struct mcde_display_device *ddev, bool enable)
+{
+ if (ddev->port->type == MCDE_PORTTYPE_DSI && enable) {
+ int ret;
+ u8 m = 0;
+
+ if (ddev->port->sync_src == MCDE_SYNCSRC_OFF)
+ return -EINVAL;
+
+ ret = mcde_dsi_dcs_write(ddev->chnl_state,
+ DCS_CMD_SET_TEAR_ON, &m, 1);
+ if (ret < 0) {
+ dev_warn(&ddev->dev,
+ "%s:Failed to set synchornized update = %d\n",
+ __func__, enable);
+ return ret;
+ }
+ }
+ ddev->synchronized_update = enable;
+ return 0;
+}
+
+static inline bool mcde_display_get_synchronized_update_default(
+ struct mcde_display_device *ddev)
+{
+ return ddev->synchronized_update;
+}
+
+static int mcde_display_apply_config_default(struct mcde_display_device *ddev)
+{
+ int ret;
+
+ ret = mcde_chnl_enable_synchronized_update(ddev->chnl_state,
+ ddev->synchronized_update);
+
+ if (ret < 0) {
+ dev_warn(&ddev->dev,
+ "%s:Failed to enable synchronized update\n",
+ __func__);
+ return ret;
+ }
+
+ if (!ddev->update_flags)
+ return 0;
+
+ if ((ddev->update_flags & UPDATE_FLAG_VIDEO_MODE) ||
+ (ddev->update_flags & UPDATE_FLAG_PIXEL_FORMAT))
+ mcde_chnl_stop_flow(ddev->chnl_state);
+
+ ret = mcde_chnl_apply(ddev->chnl_state);
+ if (ret < 0) {
+ dev_warn(&ddev->dev, "%s:Failed to apply to channel\n",
+ __func__);
+ return ret;
+ }
+ ddev->update_flags = 0;
+ ddev->first_update = true;
+
+ return 0;
+}
+
+static int mcde_display_invalidate_area_default(
+ struct mcde_display_device *ddev,
+ struct mcde_rectangle *area)
+{
+ dev_vdbg(&ddev->dev, "%s\n", __func__);
+ if (area) {
+ /* take union of rects */
+ u16 t;
+ t = min(ddev->update_area.x, area->x);
+ /* note should be > 0 */
+ ddev->update_area.w = max(ddev->update_area.x +
+ ddev->update_area.w,
+ area->x + area->w) - t;
+ ddev->update_area.x = t;
+ t = min(ddev->update_area.y, area->y);
+ ddev->update_area.h = max(ddev->update_area.y +
+ ddev->update_area.h,
+ area->y + area->h) - t;
+ ddev->update_area.y = t;
+ /* TODO: Implement real clipping when partial refresh is
+ activated.*/
+ ddev->update_area.w = min((u16) ddev->video_mode.xres,
+ (u16) ddev->update_area.w);
+ ddev->update_area.h = min((u16) ddev->video_mode.yres,
+ (u16) ddev->update_area.h);
+ } else {
+ ddev->update_area.x = 0;
+ ddev->update_area.y = 0;
+ ddev->update_area.w = ddev->video_mode.xres;
+ ddev->update_area.h = ddev->video_mode.yres;
+ /* Invalidate_area(ddev, NULL) means reset area to empty
+ * rectangle really. After that the rectangle should grow by
+ * taking an union (above). This means that the code should
+ * really look like below, however the code above is a temp fix
+ * for rotation.
+ * TODO: fix
+ * ddev->update_area.x = ddev->video_mode.xres;
+ * ddev->update_area.y = ddev->video_mode.yres;
+ * ddev->update_area.w = 0;
+ * ddev->update_area.h = 0;
+ */
+ }
+
+ return 0;
+}
+
+static int mcde_display_update_default(struct mcde_display_device *ddev)
+{
+ int ret;
+
+ /* TODO: Dirty */
+ if (ddev->prepare_for_update) {
+ /* TODO: Send dirty rectangle */
+ ret = ddev->prepare_for_update(ddev, 0, 0,
+ ddev->native_x_res, ddev->native_y_res);
+ if (ret < 0) {
+ dev_warn(&ddev->dev,
+ "%s:Failed to prepare for update\n", __func__);
+ return ret;
+ }
+ }
+ /* TODO: Calculate & set update rect */
+ ret = mcde_chnl_update(ddev->chnl_state, &ddev->update_area);
+ if (ret < 0) {
+ dev_warn(&ddev->dev, "%s:Failed to update channel\n", __func__);
+ return ret;
+ }
+ if (ddev->first_update && ddev->on_first_update)
+ ddev->on_first_update(ddev);
+
+ if (ddev->power_mode != MCDE_DISPLAY_PM_ON && ddev->set_power_mode) {
+ ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_ON);
+ if (ret < 0) {
+ dev_warn(&ddev->dev,
+ "%s:Failed to set power mode to on\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ dev_vdbg(&ddev->dev, "Overlay updated, chnl=%d\n", ddev->chnl_id);
+
+ return 0;
+}
+
+static int mcde_display_prepare_for_update_default(
+ struct mcde_display_device *ddev,
+ u16 x, u16 y, u16 w, u16 h)
+{
+ int ret;
+ u8 params[8] = { x >> 8, x & 0xff,
+ (x + w - 1) >> 8, (x + w - 1) & 0xff,
+ y >> 8, y & 0xff,
+ (y + h - 1) >> 8, (y + h - 1) & 0xff };
+
+ if (ddev->port->type != MCDE_PORTTYPE_DSI)
+ return -EINVAL;
+
+ ret = mcde_dsi_dcs_write(ddev->chnl_state,
+ DCS_CMD_SET_COLUMN_ADDRESS, &params[0], 4);
+ if (ret)
+ return ret;
+
+ ret = mcde_dsi_dcs_write(ddev->chnl_state,
+ DCS_CMD_SET_PAGE_ADDRESS, &params[4], 4);
+
+ return ret;
+}
+
+static inline int mcde_display_on_first_update_default(
+ struct mcde_display_device *ddev)
+{
+ ddev->first_update = false;
+ return 0;
+}
+
+void mcde_display_init_device(struct mcde_display_device *ddev)
+{
+ /* Setup default callbacks */
+ ddev->get_native_resolution =
+ mcde_display_get_native_resolution_default;
+ ddev->get_default_pixel_format =
+ mcde_display_get_default_pixel_format_default;
+ ddev->get_physical_size = mcde_display_get_physical_size_default;
+ ddev->set_power_mode = mcde_display_set_power_mode_default;
+ ddev->get_power_mode = mcde_display_get_power_mode_default;
+ ddev->try_video_mode = mcde_display_try_video_mode_default;
+ ddev->set_video_mode = mcde_display_set_video_mode_default;
+ ddev->get_video_mode = mcde_display_get_video_mode_default;
+ ddev->set_pixel_format = mcde_display_set_pixel_format_default;
+ ddev->get_pixel_format = mcde_display_get_pixel_format_default;
+ ddev->get_port_pixel_format =
+ mcde_display_get_port_pixel_format_default;
+ ddev->set_rotation = mcde_display_set_rotation_default;
+ ddev->get_rotation = mcde_display_get_rotation_default;
+ ddev->set_synchronized_update =
+ mcde_display_set_synchronized_update_default;
+ ddev->get_synchronized_update =
+ mcde_display_get_synchronized_update_default;
+ ddev->apply_config = mcde_display_apply_config_default;
+ ddev->invalidate_area = mcde_display_invalidate_area_default;
+ ddev->update = mcde_display_update_default;
+ ddev->prepare_for_update = mcde_display_prepare_for_update_default;
+ ddev->on_first_update = mcde_display_on_first_update_default;
+}
+
diff --git a/drivers/video/mcde/mcde_dss.c b/drivers/video/mcde/mcde_dss.c
new file mode 100644
index 00000000000..846d7c33e33
--- /dev/null
+++ b/drivers/video/mcde/mcde_dss.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * ST-Ericsson MCDE display sub system driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include <video/mcde_dss.h>
+
+#define to_overlay(x) container_of(x, struct mcde_overlay, kobj)
+
+void overlay_release(struct kobject *kobj)
+{
+ struct mcde_overlay *ovly = to_overlay(kobj);
+
+ kfree(ovly);
+}
+
+struct kobj_type ovly_type = {
+ .release = overlay_release,
+};
+
+static int apply_overlay(struct mcde_overlay *ovly,
+ struct mcde_overlay_info *info, bool force)
+{
+ int ret = 0;
+ if (ovly->ddev->invalidate_area) {
+ /* TODO: transform ovly coord to screen coords (vmode):
+ * add offset
+ */
+ struct mcde_rectangle dirty = info->dirty;
+ ret = ovly->ddev->invalidate_area(ovly->ddev, &dirty);
+ }
+
+ if (ovly->info.paddr != info->paddr || force)
+ mcde_ovly_set_source_buf(ovly->state, info->paddr);
+
+ if (ovly->info.stride != info->stride || ovly->info.fmt != info->fmt ||
+ force)
+ mcde_ovly_set_source_info(ovly->state, info->stride, info->fmt);
+ if (ovly->info.src_x != info->src_x ||
+ ovly->info.src_y != info->src_y ||
+ ovly->info.w != info->w ||
+ ovly->info.h != info->h || force)
+ mcde_ovly_set_source_area(ovly->state,
+ info->src_x, info->src_y, info->w, info->h);
+ if (ovly->info.dst_x != info->dst_x || ovly->info.dst_y != info->dst_y
+ || ovly->info.dst_z != info->dst_z ||
+ force)
+ mcde_ovly_set_dest_pos(ovly->state,
+ info->dst_x, info->dst_y, info->dst_z);
+
+ mcde_ovly_apply(ovly->state);
+ ovly->info = *info;
+
+ return ret;
+}
+
+/* MCDE DSS operations */
+
+int mcde_dss_enable_display(struct mcde_display_device *ddev)
+{
+ int ret;
+ struct mcde_chnl_state *chnl;
+
+ if (ddev->enabled)
+ return 0;
+
+ /* Acquire MCDE resources */
+ chnl = mcde_chnl_get(ddev->chnl_id, ddev->fifo, ddev->port);
+ if (IS_ERR(chnl)) {
+ ret = PTR_ERR(chnl);
+ dev_warn(&ddev->dev, "Failed to acquire MCDE channel\n");
+ goto get_chnl_failed;
+ }
+ ddev->chnl_state = chnl;
+ /* Initiate display communication */
+ ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY);
+ if (ret < 0) {
+ dev_warn(&ddev->dev, "Failed to initialize display\n");
+ goto display_failed;
+ }
+
+ ret = ddev->set_synchronized_update(ddev, ddev->synchronized_update);
+ if (ret < 0)
+ dev_warn(&ddev->dev, "Failed to set sync\n");
+ /* TODO: call driver for all defaults like sync_update above */
+
+ dev_dbg(&ddev->dev, "Display enabled, chnl=%d\n",
+ ddev->chnl_id);
+ ddev->enabled = true;
+out:
+ return ret;
+
+display_failed:
+ mcde_chnl_put(ddev->chnl_state);
+ ddev->chnl_state = NULL;
+get_chnl_failed:
+ goto out;
+}
+
+void mcde_dss_disable_display(struct mcde_display_device *ddev)
+{
+ if (!ddev->enabled)
+ return;
+
+ /* TODO: Disable overlays */
+
+ (void)ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF);
+ mcde_chnl_put(ddev->chnl_state);
+ ddev->chnl_state = NULL;
+
+ ddev->enabled = false;
+
+ dev_dbg(&ddev->dev, "Display disabled, chnl=%d\n", ddev->chnl_id);
+}
+
+int mcde_dss_apply_channel(struct mcde_display_device *ddev)
+{
+ if (ddev->apply_config)
+ return ddev->apply_config(ddev);
+ else
+ return -EINVAL;
+}
+
+struct mcde_overlay *mcde_dss_create_overlay(struct mcde_display_device *ddev,
+ struct mcde_overlay_info *info)
+{
+ struct mcde_overlay *ovly;
+
+ ovly = kzalloc(sizeof(struct mcde_overlay), GFP_KERNEL);
+ if (!ovly)
+ return NULL;
+
+ kobject_init(&ovly->kobj, &ovly_type); /* Local ref */
+ kobject_get(&ovly->kobj); /* Creator ref */
+ INIT_LIST_HEAD(&ovly->list);
+ list_add(&ddev->ovlys, &ovly->list);
+ ovly->info = *info;
+ ovly->ddev = ddev;
+
+ return ovly;
+}
+
+void mcde_dss_destroy_overlay(struct mcde_overlay *ovly)
+{
+ list_del(&ovly->list);
+ if (ovly->state)
+ mcde_dss_disable_overlay(ovly);
+ kobject_put(&ovly->kobj);
+}
+
+int mcde_dss_enable_overlay(struct mcde_overlay *ovly)
+{
+ int ret = 0;
+
+ if (!ovly->ddev->chnl_state)
+ return -EINVAL;
+
+ if (!ovly->state) {
+ struct mcde_ovly_state *state;
+ state = mcde_ovly_get(ovly->ddev->chnl_state);
+ if (IS_ERR(state)) {
+ ret = PTR_ERR(state);
+ dev_warn(&ovly->ddev->dev,
+ "Failed to acquire overlay\n");
+ goto get_ovly_failed;
+ }
+ ovly->state = state;
+ }
+
+ apply_overlay(ovly, &ovly->info, true);
+
+ dev_vdbg(&ovly->ddev->dev, "Overlay enabled, chnl=%d\n",
+ ovly->ddev->chnl_id);
+
+ goto out;
+get_ovly_failed:
+out:
+ return ret;
+}
+
+int mcde_dss_apply_overlay(struct mcde_overlay *ovly,
+ struct mcde_overlay_info *info)
+{
+ if (info == NULL)
+ info = &ovly->info;
+ return apply_overlay(ovly, info, false);
+}
+
+void mcde_dss_disable_overlay(struct mcde_overlay *ovly)
+{
+ if (!ovly->state)
+ return;
+
+ mcde_ovly_put(ovly->state);
+
+ dev_dbg(&ovly->ddev->dev, "Overlay disabled, chnl=%d\n",
+ ovly->ddev->chnl_id);
+
+ ovly->state = NULL;
+}
+
+int mcde_dss_update_overlay(struct mcde_overlay *ovly)
+{
+ int ret = 0;
+
+ dev_vdbg(&ovly->ddev->dev, "Overlay update, chnl=%d\n",
+ ovly->ddev->chnl_id);
+
+ if (!ovly->state || !ovly->ddev->update || !ovly->ddev->invalidate_area)
+ return -EINVAL;
+
+ ret = ovly->ddev->update(ovly->ddev);
+ if (ret)
+ goto out;
+ ret = ovly->ddev->invalidate_area(ovly->ddev, NULL);
+
+out:
+ return ret;
+}
+
+void mcde_dss_get_native_resolution(struct mcde_display_device *ddev,
+ u16 *x_res, u16 *y_res)
+{
+ ddev->get_native_resolution(ddev, x_res, y_res);
+}
+
+enum mcde_ovly_pix_fmt mcde_dss_get_default_pixel_format(
+ struct mcde_display_device *ddev)
+{
+ return ddev->get_default_pixel_format(ddev);
+}
+
+void mcde_dss_get_physical_size(struct mcde_display_device *ddev,
+ u16 *physical_width, u16 *physical_height)
+{
+ ddev->get_physical_size(ddev, physical_width, physical_height);
+}
+
+int mcde_dss_try_video_mode(struct mcde_display_device *ddev,
+ struct mcde_video_mode *video_mode)
+{
+ return ddev->try_video_mode(ddev, video_mode);
+}
+
+int mcde_dss_set_video_mode(struct mcde_display_device *ddev,
+ struct mcde_video_mode *vmode)
+{
+ int ret;
+ struct mcde_video_mode old_vmode;
+
+ ddev->get_video_mode(ddev, &old_vmode);
+ if (memcmp(vmode, &old_vmode, sizeof(old_vmode)) == 0)
+ return 0;
+
+ ret = ddev->set_video_mode(ddev, vmode);
+ if (ret)
+ return ret;
+
+ return ddev->invalidate_area(ddev, NULL);
+}
+
+void mcde_dss_get_video_mode(struct mcde_display_device *ddev,
+ struct mcde_video_mode *video_mode)
+{
+ ddev->get_video_mode(ddev, video_mode);
+}
+
+int mcde_dss_set_pixel_format(struct mcde_display_device *ddev,
+ enum mcde_ovly_pix_fmt pix_fmt)
+{
+ enum mcde_ovly_pix_fmt old_pix_fmt;
+
+ old_pix_fmt = ddev->get_pixel_format(ddev);
+ if (old_pix_fmt == pix_fmt)
+ return 0;
+
+ return ddev->set_pixel_format(ddev, pix_fmt);
+}
+
+int mcde_dss_get_pixel_format(struct mcde_display_device *ddev)
+{
+ return ddev->get_pixel_format(ddev);
+}
+
+int mcde_dss_set_rotation(struct mcde_display_device *ddev,
+ enum mcde_display_rotation rotation)
+{
+ enum mcde_display_rotation old_rotation;
+
+ old_rotation = ddev->get_rotation(ddev);
+ if (old_rotation == rotation)
+ return 0;
+
+ return ddev->set_rotation(ddev, rotation);
+}
+
+enum mcde_display_rotation mcde_dss_get_rotation(
+ struct mcde_display_device *ddev)
+{
+ return ddev->get_rotation(ddev);
+}
+
+int mcde_dss_set_synchronized_update(struct mcde_display_device *ddev,
+ bool enable)
+{
+ int ret;
+ ret = ddev->set_synchronized_update(ddev, enable);
+ if (ret)
+ return ret;
+ if (ddev->chnl_state)
+ mcde_chnl_enable_synchronized_update(ddev->chnl_state, enable);
+ return 0;
+}
+
+bool mcde_dss_get_synchronized_update(struct mcde_display_device *ddev)
+{
+ return ddev->get_synchronized_update(ddev);
+}
+
+int __init mcde_dss_init(void)
+{
+ return 0;
+}
+
+void mcde_dss_exit(void)
+{
+}
+
diff --git a/drivers/video/mcde/mcde_fb.c b/drivers/video/mcde/mcde_fb.c
new file mode 100644
index 00000000000..ac8f7264ede
--- /dev/null
+++ b/drivers/video/mcde/mcde_fb.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * ST-Ericsson MCDE frame buffer driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/hwmem.h>
+#include <linux/io.h>
+
+#include <video/mcde_fb.h>
+
+#define MCDE_FB_BPP_MAX 16
+#define MCDE_FB_VXRES_MAX 1920
+#define MCDE_FB_VYRES_MAX 2160
+
+static struct fb_ops fb_ops;
+
+struct pix_fmt_info {
+ enum mcde_ovly_pix_fmt pix_fmt;
+
+ u32 bpp;
+ struct fb_bitfield r;
+ struct fb_bitfield g;
+ struct fb_bitfield b;
+ struct fb_bitfield a;
+ u32 nonstd;
+};
+
+struct pix_fmt_info pix_fmt_map[] = {
+ {
+ .pix_fmt = MCDE_OVLYPIXFMT_RGB565,
+ .bpp = 16,
+ .r = { .offset = 11, .length = 5 },
+ .g = { .offset = 5, .length = 6 },
+ .b = { .offset = 0, .length = 5 },
+ }, {
+ .pix_fmt = MCDE_OVLYPIXFMT_RGBA5551,
+ .bpp = 16,
+ .r = { .offset = 11, .length = 5 },
+ .g = { .offset = 6, .length = 5 },
+ .b = { .offset = 1, .length = 5 },
+ .a = { .offset = 0, .length = 1 },
+ }, {
+ .pix_fmt = MCDE_OVLYPIXFMT_RGBA4444,
+ .bpp = 16,
+ .r = { .offset = 12, .length = 4 },
+ .g = { .offset = 8, .length = 4 },
+ .b = { .offset = 4, .length = 4 },
+ .a = { .offset = 0, .length = 4 },
+ }, {
+ .pix_fmt = MCDE_OVLYPIXFMT_YCbCr422,
+ .bpp = 16,
+ .nonstd = MCDE_OVLYPIXFMT_YCbCr422,
+ }, {
+ .pix_fmt = MCDE_OVLYPIXFMT_RGB888,
+ .bpp = 24,
+ .r = { .offset = 16, .length = 8 },
+ .g = { .offset = 8, .length = 8 },
+ .b = { .offset = 0, .length = 8 },
+ }, {
+ .pix_fmt = MCDE_OVLYPIXFMT_RGBA8888,
+ .bpp = 32,
+ .r = { .offset = 16, .length = 8 },
+ .g = { .offset = 8, .length = 8 },
+ .b = { .offset = 0, .length = 8 },
+ .a = { .offset = 24, .length = 8 },
+ }, {
+ .pix_fmt = MCDE_OVLYPIXFMT_RGBX8888,
+ .bpp = 32,
+ .r = { .offset = 16, .length = 8 },
+ .g = { .offset = 8, .length = 8 },
+ .b = { .offset = 0, .length = 8 },
+ }
+
+};
+
+static struct platform_device mcde_fb_device = {
+ .name = "mcde_fb",
+ .id = -1,
+};
+
+/* Helpers */
+
+static struct pix_fmt_info *find_pix_fmt_info(enum mcde_ovly_pix_fmt pix_fmt)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pix_fmt_map); i++) {
+ if (pix_fmt_map[i].pix_fmt == pix_fmt)
+ return &pix_fmt_map[i];
+ }
+ return NULL;
+}
+
+static bool bitfield_cmp(struct fb_bitfield *bf1, struct fb_bitfield *bf2)
+{
+ return bf1->offset == bf2->offset &&
+ bf1->length == bf2->length &&
+ bf1->msb_right == bf2->msb_right;
+}
+
+static struct pix_fmt_info *var_to_pix_fmt_info(struct fb_var_screeninfo *var)
+{
+ int i;
+ struct pix_fmt_info *info;
+
+ if (var->nonstd)
+ return find_pix_fmt_info(var->nonstd);
+
+ for (i = 0; i < ARRAY_SIZE(pix_fmt_map); i++) {
+ info = &pix_fmt_map[i];
+ if (info->bpp == var->bits_per_pixel &&
+ bitfield_cmp(&info->r, &var->red) &&
+ bitfield_cmp(&info->g, &var->green) &&
+ bitfield_cmp(&info->b, &var->blue) &&
+ bitfield_cmp(&info->a, &var->transp))
+ return info;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pix_fmt_map); i++) {
+ info = &pix_fmt_map[i];
+ if (var->bits_per_pixel == info->bpp)
+ return info;
+ }
+
+ return NULL;
+}
+
+static void pix_fmt_info_to_var(struct pix_fmt_info *pix_fmt_info,
+ struct fb_var_screeninfo *var)
+{
+ var->bits_per_pixel = pix_fmt_info->bpp;
+ var->nonstd = pix_fmt_info->nonstd;
+ var->red = pix_fmt_info->r;
+ var->green = pix_fmt_info->g;
+ var->blue = pix_fmt_info->b;
+ var->transp = pix_fmt_info->a;
+}
+
+static int init_var_fmt(struct fb_var_screeninfo *var,
+ u16 w, u16 h, u16 vw, u16 vh, enum mcde_ovly_pix_fmt pix_fmt,
+ u32 rotate)
+{
+ struct pix_fmt_info *info;
+
+ info = find_pix_fmt_info(pix_fmt);
+ if (!info)
+ return -EINVAL;
+
+ var->bits_per_pixel = info->bpp;
+ var->nonstd = info->nonstd;
+ var->red = info->r;
+ var->green = info->g;
+ var->blue = info->b;
+ var->transp = info->a;
+ var->grayscale = false;
+
+ var->xres = w;
+ var->yres = h;
+ var->xres_virtual = vw;
+ var->yres_virtual = vh;
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->activate = FB_ACTIVATE_NOW;
+ var->rotate = rotate;
+ return 0;
+};
+
+static int reallocate_fb_mem(struct fb_info *fbi, u32 size)
+{
+ struct mcde_fb *mfb = to_mcde_fb(fbi);
+ dma_addr_t paddr;
+ void __iomem *vaddr;
+ struct hwmem_alloc *alloc;
+ int name;
+
+ size = PAGE_ALIGN(size);
+
+ if (size == fbi->screen_size)
+ return 0;
+
+/* TODO: Remove once hwmem has support for defragmentation */
+#ifdef CONFIG_MCDE_FB_AVOID_REALLOC
+ if (!mfb->alloc) {
+ u32 old_size = size;
+
+ size = MCDE_FB_BPP_MAX / 8 * MCDE_FB_VXRES_MAX *
+ MCDE_FB_VYRES_MAX;
+#endif
+
+ alloc = hwmem_alloc(size, HWMEM_ALLOC_BUFFERED,
+ (HWMEM_ACCESS_READ | HWMEM_ACCESS_WRITE |
+ HWMEM_ACCESS_IMPORT),
+ HWMEM_MEM_CONTIGUOUS_SYS);
+ if (IS_ERR(alloc))
+ return PTR_ERR(alloc);
+
+ name = hwmem_get_name(alloc);
+ if (name < 0) {
+ hwmem_release(alloc);
+ return name;
+ }
+
+ if (mfb->alloc) {
+ hwmem_unpin(mfb->alloc);
+ hwmem_release(mfb->alloc);
+ }
+
+ (void)hwmem_pin(alloc, &paddr, NULL);
+
+ vaddr = ioremap(paddr, size);
+
+ mfb->alloc = alloc;
+ mfb->alloc_name = name;
+
+ fbi->screen_base = vaddr;
+ fbi->fix.smem_start = paddr;
+
+#ifdef CONFIG_MCDE_FB_AVOID_REALLOC
+ size = old_size;
+ }
+#endif
+
+ fbi->screen_size = size;
+ fbi->fix.smem_len = size;
+
+ return 0;
+}
+
+static void free_fb_mem(struct fb_info *fbi)
+{
+ struct mcde_fb *mfb = to_mcde_fb(fbi);
+
+ if (mfb->alloc) {
+ hwmem_unpin(mfb->alloc);
+ hwmem_release(mfb->alloc);
+ mfb->alloc = NULL;
+ mfb->alloc_name = 0;
+
+ fbi->fix.smem_start = 0;
+ fbi->fix.smem_len = 0;
+ fbi->screen_base = 0;
+ fbi->screen_size = 0;
+ }
+}
+
+static void init_fb(struct fb_info *fbi)
+{
+ struct mcde_fb *mfb = to_mcde_fb(fbi);
+
+ strlcpy(fbi->fix.id, "mcde_fb", sizeof(fbi->fix.id));
+ fbi->fix.type = FB_TYPE_PACKED_PIXELS;
+ fbi->fix.visual = FB_VISUAL_TRUECOLOR;
+ fbi->fix.xpanstep = 1;
+ fbi->fix.ypanstep = 1;
+ fbi->flags = FBINFO_HWACCEL_DISABLED;
+ fbi->fbops = &fb_ops;
+ fbi->pseudo_palette = &mfb->pseudo_palette[0];
+}
+
+static void get_ovly_info(struct fb_info *fbi, struct mcde_overlay *ovly,
+ struct mcde_overlay_info *info)
+{
+ struct mcde_fb *mfb = to_mcde_fb(fbi);
+
+ memset(info, 0, sizeof(*info));
+ info->paddr = fbi->fix.smem_start +
+ fbi->fix.line_length * fbi->var.yoffset;
+ /* TODO: move mem check to check_var/pan_display */
+ if (info->paddr + fbi->fix.line_length * fbi->var.yres >
+ fbi->fix.smem_start + fbi->fix.smem_len)
+ info->paddr = fbi->fix.smem_start;
+ info->fmt = mfb->pix_fmt;
+ info->stride = fbi->fix.line_length;
+ if (ovly) {
+ info->src_x = ovly->info.src_x;
+ info->src_y = ovly->info.src_y;
+ info->dst_x = ovly->info.dst_x;
+ info->dst_y = ovly->info.dst_y;
+ info->dst_z = ovly->info.dst_z;
+ } else {
+ info->src_x = 0;
+ info->src_y = 0;
+ info->dst_x = 0;
+ info->dst_y = 0;
+ info->dst_z = 0;
+ }
+ info->w = fbi->var.xres;
+ info->h = fbi->var.yres;
+ info->dirty.x = 0;
+ info->dirty.y = 0;
+ info->dirty.w = fbi->var.xres;
+ info->dirty.h = fbi->var.yres;
+}
+
+void vmode_to_var(struct mcde_video_mode *video_mode,
+ struct fb_var_screeninfo *var)
+{
+ /* TODO: use only 1 vbp and 1 vfp */
+ var->xres = video_mode->xres;
+ var->yres = video_mode->yres;
+ var->pixclock = video_mode->pixclock;
+ var->upper_margin = video_mode->vbp1 + video_mode->vbp2;
+ var->lower_margin = video_mode->vfp1 + video_mode->vfp2;
+ var->vsync_len = video_mode->vsw;
+ var->left_margin = video_mode->hbp;
+ var->right_margin = video_mode->hfp;
+ var->hsync_len = video_mode->hsw;
+ var->vmode &= ~FB_VMODE_INTERLACED;
+ var->vmode |= video_mode->interlaced ?
+ FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
+}
+
+void var_to_vmode(struct fb_var_screeninfo *var,
+ struct mcde_video_mode *video_mode)
+{
+ video_mode->xres = var->xres;
+ video_mode->yres = var->yres;
+ video_mode->pixclock = var->pixclock;
+ video_mode->vbp1 = var->upper_margin / 2;
+ video_mode->vfp1 = var->lower_margin / 2;
+ video_mode->vbp2 = video_mode->vbp1 + var->upper_margin % 2;
+ video_mode->vfp2 = video_mode->vfp1 + var->lower_margin % 2;
+ video_mode->vsw = var->vsync_len;
+ video_mode->hbp = var->left_margin;
+ video_mode->hfp = var->right_margin;
+ video_mode->hsw = var->hsync_len;
+ video_mode->interlaced = (var->vmode & FB_VMODE_INTERLACED) ==
+ FB_VMODE_INTERLACED;
+}
+
+enum mcde_display_rotation var_to_rotation(struct fb_var_screeninfo *var)
+{
+ enum mcde_display_rotation rot;
+
+ switch (var->rotate) {
+ case FB_ROTATE_UR:
+ rot = MCDE_DISPLAY_ROT_0;
+ break;
+ case FB_ROTATE_CW:
+ rot = MCDE_DISPLAY_ROT_90_CW;
+ break;
+ case FB_ROTATE_UD:
+ rot = MCDE_DISPLAY_ROT_180_CW;
+ break;
+ case FB_ROTATE_CCW:
+ rot = MCDE_DISPLAY_ROT_90_CCW;
+ break;
+ default:
+ rot = MCDE_DISPLAY_ROT_0;
+ break;
+ }
+ dev_vdbg(&mcde_fb_device.dev, "var_rot: %d -> mcde_rot: %d\n",
+ var->rotate, rot);
+ return rot;
+}
+
+static struct mcde_display_device *fb_to_display(struct fb_info *fbi)
+{
+ int i;
+ struct mcde_fb *mfb = to_mcde_fb(fbi);
+
+ for (i = 0; i < mfb->num_ovlys; i++) {
+ if (mfb->ovlys[i])
+ return mfb->ovlys[i]->ddev;
+ }
+ return NULL;
+}
+
+static int check_var(struct fb_var_screeninfo *var, struct fb_info *fbi,
+ struct mcde_display_device *ddev)
+{
+ int ret;
+ u16 w = -1, h = -1;
+ struct mcde_video_mode vmode;
+ struct pix_fmt_info *fmtinfo;
+
+ /* TODO: check sizes/offsets/memory validity */
+
+ /* Device physical size */
+ mcde_dss_get_physical_size(ddev, &w, &h);
+ var->width = w;
+ var->height = h;
+
+ /* Rotation */
+ if (var->rotate > 3) {
+ dev_info(&(ddev->dev), "check_var failed var->rotate\n");
+ return -EINVAL;
+ }
+
+ /* Video mode */
+ var_to_vmode(var, &vmode);
+ ret = mcde_dss_try_video_mode(ddev, &vmode);
+ if (ret < 0) {
+ dev_vdbg(&(ddev->dev), "check_var failed "
+ "mcde_dss_try_video_mode with size = %x\n", ret);
+ return ret;
+ }
+ vmode_to_var(&vmode, var);
+
+ /* Pixel format */
+ fmtinfo = var_to_pix_fmt_info(var);
+ if (!fmtinfo) {
+ dev_vdbg(&(ddev->dev), "check_var failed fmtinfo\n");
+ return -EINVAL;
+ }
+ pix_fmt_info_to_var(fmtinfo, var);
+
+ /* Not used */
+ var->grayscale = 0;
+ var->sync = 0;
+
+ return 0;
+}
+
+static int apply_var(struct fb_info *fbi, struct mcde_display_device *ddev)
+{
+ int ret, i;
+ struct mcde_fb *mfb = to_mcde_fb(fbi);
+ struct fb_var_screeninfo *var;
+ struct mcde_video_mode vmode;
+ struct pix_fmt_info *fmt;
+ u32 line_len, size;
+
+ dev_vdbg(&(ddev->dev), "%s\n", __func__);
+
+ var = &fbi->var;
+
+ /* Reallocate memory */
+ line_len = (fbi->var.bits_per_pixel * var->xres_virtual) / 8;
+ line_len = ALIGN(line_len, MCDE_BUF_LINE_ALIGMENT);
+ size = line_len * var->yres_virtual;
+ ret = reallocate_fb_mem(fbi, size);
+ if (ret) {
+ dev_vdbg(&(ddev->dev), "apply_var failed with"
+ "reallocate mem with size = %d\n", size);
+ return ret;
+ }
+ fbi->fix.line_length = line_len;
+
+ if (ddev) {
+ /* Apply pixel format */
+ fmt = var_to_pix_fmt_info(var);
+ mfb->pix_fmt = fmt->pix_fmt;
+ mcde_dss_set_pixel_format(ddev, mfb->pix_fmt);
+
+ /* Apply rotation */
+ mcde_dss_set_rotation(ddev, var_to_rotation(var));
+ /* Apply video mode */
+ memset(&vmode, 0, sizeof(struct mcde_video_mode));
+ var_to_vmode(var, &vmode);
+ mcde_dss_set_video_mode(ddev, &vmode);
+ mcde_dss_apply_channel(ddev);
+ }
+
+ /* Apply overlay info */
+ for (i = 0; i < mfb->num_ovlys; i++) {
+ struct mcde_overlay *ovly = mfb->ovlys[i];
+ struct mcde_overlay_info info;
+
+ get_ovly_info(fbi, ovly, &info);
+ (void) mcde_dss_apply_overlay(ovly, &info);
+ ret = mcde_dss_update_overlay(ovly);
+ }
+
+ return 0;
+}
+
+/* FB ops */
+
+static int mcde_fb_open(struct fb_info *fbi, int user)
+{
+ dev_vdbg(fbi->dev, "%s\n", __func__);
+ return 0;
+}
+
+static int mcde_fb_release(struct fb_info *fbi, int user)
+{
+ dev_vdbg(fbi->dev, "%s\n", __func__);
+ return 0;
+}
+
+static int mcde_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
+{
+ struct mcde_display_device *ddev = fb_to_display(fbi);
+
+ dev_vdbg(fbi->dev, "%s\n", __func__);
+
+ if (!ddev) {
+ printk(KERN_ERR "mcde_fb_check_var failed !ddev\n");
+ return -ENODEV;
+ }
+
+ return check_var(var, fbi, ddev);
+}
+
+static int mcde_fb_set_par(struct fb_info *fbi)
+{
+ dev_vdbg(fbi->dev, "%s\n", __func__);
+
+ return apply_var(fbi, fb_to_display(fbi));
+}
+
+static int mcde_fb_blank(int blank, struct fb_info *fbi)
+{
+ dev_vdbg(fbi->dev, "%s\n", __func__);
+ /* REVIEW: is this supposed to be empty? */
+ return 0;
+}
+
+static int mcde_fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *fbi)
+{
+ dev_vdbg(fbi->dev, "%s\n", __func__);
+
+ if (var->xoffset == fbi->var.xoffset &&
+ var->yoffset == fbi->var.yoffset)
+ return 0;
+
+ fbi->var.xoffset = var->xoffset;
+ fbi->var.yoffset = var->yoffset;
+ return apply_var(fbi, fb_to_display(fbi));
+}
+
+static void mcde_fb_rotate(struct fb_info *fbi, int rotate)
+{
+ dev_vdbg(fbi->dev, "%s\n", __func__);
+}
+
+static int mcde_fb_ioctl(struct fb_info *fbi, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mcde_fb *mfb = to_mcde_fb(fbi);
+
+ if (cmd == MCDE_GET_BUFFER_NAME_IOC)
+ return mfb->alloc_name;
+
+ return -EINVAL;
+}
+
+static struct fb_ops fb_ops = {
+ /* creg, cmap */
+ .owner = THIS_MODULE,
+ .fb_open = mcde_fb_open,
+ .fb_release = mcde_fb_release,
+ .fb_read = fb_sys_read,
+ .fb_write = fb_sys_write,
+ .fb_fillrect = sys_fillrect,
+ .fb_copyarea = sys_copyarea,
+ .fb_imageblit = sys_imageblit,
+ .fb_check_var = mcde_fb_check_var,
+ .fb_set_par = mcde_fb_set_par,
+ .fb_blank = mcde_fb_blank,
+ .fb_pan_display = mcde_fb_pan_display,
+ .fb_rotate = mcde_fb_rotate,
+ .fb_ioctl = mcde_fb_ioctl,
+};
+
+/* FB driver */
+
+struct fb_info *mcde_fb_create(struct mcde_display_device *ddev,
+ u16 w, u16 h, u16 vw, u16 vh, enum mcde_ovly_pix_fmt pix_fmt,
+ u32 rotate)
+{
+ int ret = 0;
+ struct fb_info *fbi;
+ struct mcde_fb *mfb;
+ struct mcde_overlay *ovly = NULL;
+ struct mcde_overlay_info ovly_info;
+
+ dev_vdbg(&ddev->dev, "%s\n", __func__);
+ if (!ddev->initialized) {
+ dev_warn(&ddev->dev, "%s: Device not initialized\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* Init fb */
+ fbi = framebuffer_alloc(sizeof(struct mcde_fb), &mcde_fb_device.dev);
+ if (fbi == NULL) {
+ ret = -ENOMEM;
+ goto fb_alloc_failed;
+ }
+ init_fb(fbi);
+ mfb = to_mcde_fb(fbi);
+
+ ret = mcde_dss_enable_display(ddev);
+ if (ret)
+ goto display_enable_failed;
+
+ /* Prepare var and allocate frame buffer memory */
+ init_var_fmt(&fbi->var, w, h, vw, vh, pix_fmt, rotate);
+ check_var(&fbi->var, fbi, ddev);
+ ret = apply_var(fbi, ddev);
+ if (ret)
+ goto apply_var_failed;
+
+ /* Setup overlay */
+ get_ovly_info(fbi, NULL, &ovly_info);
+ ovly = mcde_dss_create_overlay(ddev, &ovly_info);
+ if (!ovly) {
+ ret = PTR_ERR(ovly);
+ goto ovly_alloc_failed;
+ }
+ mfb->ovlys[0] = ovly;
+ mfb->num_ovlys = 1;
+
+ ret = mcde_dss_enable_overlay(ovly);
+ if (ret)
+ goto ovly_enable_failed;
+
+ mfb->id = ddev->id;
+
+ /* Register framebuffer */
+ ret = register_framebuffer(fbi);
+ if (ret)
+ goto fb_register_failed;
+
+ goto out;
+fb_register_failed:
+ mcde_dss_disable_overlay(ovly);
+ovly_enable_failed:
+ mcde_dss_destroy_overlay(ovly);
+ovly_alloc_failed:
+ free_fb_mem(fbi);
+apply_var_failed:
+ mcde_dss_disable_display(ddev);
+display_enable_failed:
+ framebuffer_release(fbi);
+ fbi = NULL;
+fb_alloc_failed:
+out:
+ return ret ? ERR_PTR(ret) : fbi;
+}
+EXPORT_SYMBOL(mcde_fb_create);
+
+int mcde_fb_attach_overlay(struct fb_info *fb_info, struct mcde_overlay *ovl)
+{
+ /* TODO: Attach extra overlay targets */
+ return -EINVAL;
+}
+
+void mcde_fb_destroy(struct fb_info *fb_info)
+{
+ /* TODO: clean up */
+}
+
+/* Overlay fbs' platform device */
+static int mcde_fb_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int mcde_fb_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver mcde_fb_driver = {
+ .probe = mcde_fb_probe,
+ .remove = mcde_fb_remove,
+ .driver = {
+ .name = "mcde_fb",
+ .owner = THIS_MODULE,
+ },
+};
+
+/* MCDE fb init */
+
+int __init mcde_fb_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&mcde_fb_driver);
+ if (ret)
+ goto fb_driver_failed;
+ ret = platform_device_register(&mcde_fb_device);
+ if (ret)
+ goto fb_device_failed;
+
+ goto out;
+fb_device_failed:
+ platform_driver_unregister(&mcde_fb_driver);
+fb_driver_failed:
+out:
+ return ret;
+}
+
+void mcde_fb_exit(void)
+{
+ platform_device_unregister(&mcde_fb_device);
+ platform_driver_unregister(&mcde_fb_driver);
+}
+
diff --git a/drivers/video/mcde/mcde_hw.c b/drivers/video/mcde/mcde_hw.c
new file mode 100644
index 00000000000..d78f54b2a12
--- /dev/null
+++ b/drivers/video/mcde/mcde_hw.c
@@ -0,0 +1,2484 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * ST-Ericsson MCDE base driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include "dsilink_regs.h"
+#include "mcde_regs.h"
+#include <video/mcde.h>
+
+#include <mach/prcmu-fw-api.h>
+
+static void disable_channel(struct mcde_chnl_state *chnl);
+static void watchdog_auto_sync_timer_function(unsigned long arg);
+
+#define OVLY_TIMEOUT 500
+#define CHNL_TIMEOUT 500
+
+u8 *mcdeio;
+u8 **dsiio;
+DEFINE_SPINLOCK(mcde_lock); /* REVIEW: Remove or use */
+struct platform_device *mcde_dev;
+u8 num_dsilinks;
+static u8 hardware_version;
+
+static struct regulator *regulator;
+static struct clk *clock_dpi;
+static struct clk *clock_dsi;
+static struct clk *clock_mcde;
+static struct clk *clock_dsi_lp;
+
+static inline u32 dsi_rreg(int i, u32 reg)
+{
+ return readl(dsiio[i] + reg);
+}
+static inline void dsi_wreg(int i, u32 reg, u32 val)
+{
+ writel(val, dsiio[i] + reg);
+}
+#define dsi_rfld(__i, __reg, __fld) \
+ ((dsi_rreg(__i, __reg) & __reg##_##__fld##_MASK) >> \
+ __reg##_##__fld##_SHIFT)
+#define dsi_wfld(__i, __reg, __fld, __val) \
+ dsi_wreg(__i, __reg, (dsi_rreg(__i, __reg) & \
+ ~__reg##_##__fld##_MASK) | (((__val) << __reg##_##__fld##_SHIFT) & \
+ __reg##_##__fld##_MASK))
+
+static inline u32 mcde_rreg(u32 reg)
+{
+ return readl(mcdeio + reg);
+}
+static inline void mcde_wreg(u32 reg, u32 val)
+{
+ writel(val, mcdeio + reg);
+}
+#define mcde_rfld(__reg, __fld) \
+ ((mcde_rreg(__reg) & __reg##_##__fld##_MASK) >> \
+ __reg##_##__fld##_SHIFT)
+#define mcde_wfld(__reg, __fld, __val) \
+ mcde_wreg(__reg, (mcde_rreg(__reg) & \
+ ~__reg##_##__fld##_MASK) | (((__val) << __reg##_##__fld##_SHIFT) & \
+ __reg##_##__fld##_MASK))
+
+struct ovly_regs {
+ u8 ch_id;
+ bool enabled;
+ u32 baseaddress0;
+ u32 baseaddress1;
+ bool reset_buf_id;
+ u8 bits_per_pixel;
+ u8 bpp;
+ bool bgr;
+ bool bebo;
+ bool opq;
+ u8 col_conv;
+ u8 pixoff;
+ u16 ppl;
+ u16 lpf;
+ u16 cropx;
+ u16 cropy;
+ u16 xpos;
+ u16 ypos;
+ u8 z;
+};
+
+struct mcde_ovly_state {
+ bool inuse;
+ u8 idx; /* MCDE overlay index */
+ struct mcde_chnl_state *chnl; /* Owner channel */
+ u32 transactionid; /* Apply time stamp */
+ u32 transactionid_regs; /* Register update time stamp */
+ u32 transactionid_hw; /* HW completed time stamp */
+ wait_queue_head_t waitq_hw; /* Waitq for transactionid_hw */
+
+ /* Staged settings */
+ u32 paddr;
+ u16 stride;
+ enum mcde_ovly_pix_fmt pix_fmt;
+
+ u16 src_x;
+ u16 src_y;
+ u16 dst_x;
+ u16 dst_y;
+ u16 dst_z;
+ u16 w;
+ u16 h;
+
+ /* Applied settings */
+ struct ovly_regs regs;
+};
+static struct mcde_ovly_state overlays[] = {
+ { .idx = 0 },
+ { .idx = 1 },
+ { .idx = 2 },
+ { .idx = 3 },
+ { .idx = 4 },
+ { .idx = 5 },
+};
+
+struct chnl_regs {
+ bool floen;
+ u16 x;
+ u16 y;
+ u16 ppl;
+ u16 lpf;
+ u8 bpp;
+ bool internal_clk; /* CLKTYPE field */
+ u16 pcd;
+ u8 clksel;
+ u8 cdwin;
+ bool bcd;
+ bool synchronized_update;
+ bool roten;
+ u8 rotdir;
+ u32 rotbuf1; /* TODO: Replace with eSRAM alloc */
+ u32 rotbuf2; /* TODO: Replace with eSRAM alloc */
+
+ /* DSI */
+ u8 dsipacking;
+};
+
+struct col_regs {
+ u16 y_red;
+ u16 y_green;
+ u16 y_blue;
+ u16 cb_red;
+ u16 cb_green;
+ u16 cb_blue;
+ u16 cr_red;
+ u16 cr_green;
+ u16 cr_blue;
+ u16 off_red;
+ u16 off_green;
+ u16 off_blue;
+};
+
+struct tv_regs {
+ u16 dho; /* TV mode: left border width; destination horizontal offset */
+ /* LCD MODE: horizontal back porch */
+ u16 alw; /* TV mode: right border width */
+ /* LCD mode: horizontal front porch */
+ u16 hsw; /* horizontal synch width */
+ u16 dvo; /* TV mode: top border width; destination horizontal offset */
+ /* LCD MODE: vertical back porch */
+ u16 bsl; /* TV mode: bottom border width; blanking start line */
+ /* LCD MODE: vertical front porch */
+ /* field 1 */
+ u16 bel1; /* TV mode: field total vertical blanking lines */
+ /* LCD mode: vertical sync width */
+ u16 fsl1; /* field vbp */
+ /* field 2 */
+ u16 bel2;
+ u16 fsl2;
+ u8 tv_mode;
+ bool sel_mode_tv;
+ bool interlaced_en;
+ u32 lcdtim1;
+};
+
+struct mcde_chnl_state {
+ bool inuse;
+ enum mcde_chnl id;
+ enum mcde_fifo fifo;
+ struct mcde_port port;
+ struct mcde_ovly_state *ovly0;
+ struct mcde_ovly_state *ovly1;
+ const struct chnl_config *cfg;
+ u32 transactionid;
+ u32 transactionid_regs;
+ u32 transactionid_hw;
+ wait_queue_head_t waitq_hw; /* Waitq for transactionid_hw */
+ /* Used as watchdog timer for auto sync feature */
+ struct timer_list auto_sync_timer;
+
+ enum mcde_display_power_mode power_mode;
+
+ /* Staged settings */
+ bool synchronized_update;
+ enum mcde_port_pix_fmt pix_fmt;
+ struct mcde_video_mode vmode;
+ enum mcde_display_rotation rotation;
+ u32 rotbuf1;
+ u32 rotbuf2;
+
+ /* Applied settings */
+ struct chnl_regs regs;
+ struct col_regs col_regs;
+ struct tv_regs tv_regs;
+
+ bool continous_running;
+};
+
+static struct mcde_chnl_state channels[] = {
+ {
+ .id = MCDE_CHNL_A,
+ .ovly0 = &overlays[0],
+ .ovly1 = &overlays[1],
+ },
+ {
+ .id = MCDE_CHNL_B,
+ .ovly0 = &overlays[2],
+ .ovly1 = &overlays[3],
+ },
+ {
+ .id = MCDE_CHNL_C0,
+ .ovly0 = &overlays[4],
+ .ovly1 = NULL,
+ },
+ {
+ .id = MCDE_CHNL_C1,
+ .ovly0 = &overlays[5],
+ .ovly1 = NULL,
+ }
+};
+
+struct chnl_config {
+ /* Key */
+ enum mcde_chnl_path path;
+
+ /* Value */
+ bool swap_a_c0;
+ bool swap_a_c0_set;
+ bool swap_b_c1;
+ bool swap_b_c1_set;
+ bool fabmux;
+ bool fabmux_set;
+ bool f01mux;
+ bool f01mux_set;
+};
+
+static /* TODO: const, compiler bug? */ struct chnl_config chnl_configs[] = {
+ /* Channel A */
+ { .path = MCDE_CHNLPATH_CHNLA_FIFOA_DPI_0,
+ .swap_a_c0 = false, .swap_a_c0_set = true },
+ { .path = MCDE_CHNLPATH_CHNLA_FIFOA_DSI_IFC0_0,
+ .swap_a_c0 = false, .swap_a_c0_set = true,
+ .fabmux = false, .fabmux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLA_FIFOA_DSI_IFC0_1,
+ .swap_a_c0 = false, .swap_a_c0_set = true,
+ .fabmux = true, .fabmux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLA_FIFOC0_DSI_IFC0_2,
+ .swap_a_c0 = true, .swap_a_c0_set = true,
+ .f01mux = false, .f01mux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLA_FIFOC0_DSI_IFC1_0,
+ .swap_a_c0 = true, .swap_a_c0_set = true,
+ .f01mux = false, .f01mux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLA_FIFOC0_DSI_IFC1_1,
+ .swap_a_c0 = true, .swap_a_c0_set = true,
+ .f01mux = true, .f01mux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLA_FIFOA_DSI_IFC1_2,
+ .swap_a_c0 = false, .swap_a_c0_set = true,
+ .fabmux = false, .fabmux_set = true },
+ /* Channel B */
+ { .path = MCDE_CHNLPATH_CHNLB_FIFOB_DPI_1,
+ .swap_b_c1 = false, .swap_b_c1_set = true },
+ { .path = MCDE_CHNLPATH_CHNLB_FIFOB_DSI_IFC0_0,
+ .swap_b_c1 = false, .swap_b_c1_set = true,
+ .fabmux = true, .fabmux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLB_FIFOB_DSI_IFC0_1,
+ .swap_b_c1 = false, .swap_b_c1_set = true,
+ .fabmux = false, .fabmux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLB_FIFOC1_DSI_IFC0_2,
+ .swap_b_c1 = true, .swap_b_c1_set = true,
+ .f01mux = true, .f01mux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLB_FIFOC1_DSI_IFC1_0,
+ .swap_b_c1 = true, .swap_b_c1_set = true,
+ .f01mux = true, .f01mux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLB_FIFOC1_DSI_IFC1_1,
+ .swap_b_c1 = true, .swap_b_c1_set = true,
+ .f01mux = false, .f01mux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLB_FIFOB_DSI_IFC1_2,
+ .swap_b_c1 = false, .swap_b_c1_set = true,
+ .fabmux = true, .fabmux_set = true },
+ /* Channel C0 */
+ { .path = MCDE_CHNLPATH_CHNLC0_FIFOA_DSI_IFC0_0,
+ .swap_a_c0 = true, .swap_a_c0_set = true,
+ .fabmux = false, .fabmux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLC0_FIFOA_DSI_IFC0_1,
+ .swap_a_c0 = true, .swap_a_c0_set = true,
+ .fabmux = true, .fabmux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLC0_FIFOC0_DSI_IFC0_2,
+ .swap_a_c0 = false, .swap_a_c0_set = true,
+ .f01mux = false, .f01mux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLC0_FIFOC0_DSI_IFC1_0,
+ .swap_a_c0 = false, .swap_a_c0_set = true,
+ .f01mux = false, .f01mux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLC0_FIFOC0_DSI_IFC1_1,
+ .swap_a_c0 = false, .swap_a_c0_set = true,
+ .f01mux = true, .f01mux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLC0_FIFOA_DSI_IFC1_2,
+ .swap_a_c0 = true, .swap_a_c0_set = true,
+ .fabmux = false, .fabmux_set = true },
+ /* Channel C1 */
+ { .path = MCDE_CHNLPATH_CHNLC1_FIFOB_DSI_IFC0_0,
+ .swap_b_c1 = true, .swap_b_c1_set = true,
+ .fabmux = true, .fabmux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLC1_FIFOB_DSI_IFC0_1,
+ .swap_b_c1 = true, .swap_b_c1_set = true,
+ .fabmux = false, .fabmux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLC1_FIFOC1_DSI_IFC0_2,
+ .swap_b_c1 = false, .swap_b_c1_set = true,
+ .f01mux = true, .f01mux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLC1_FIFOC1_DSI_IFC1_0,
+ .swap_b_c1 = false, .swap_b_c1_set = true,
+ .f01mux = true, .f01mux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLC1_FIFOC1_DSI_IFC1_1,
+ .swap_b_c1 = false, .swap_b_c1_set = true,
+ .f01mux = false, .f01mux_set = true },
+ { .path = MCDE_CHNLPATH_CHNLC1_FIFOB_DSI_IFC1_2,
+ .swap_b_c1 = true, .swap_b_c1_set = true,
+ .fabmux = true, .fabmux_set = true },
+};
+
+int mcde_chnl_set_video_mode(struct mcde_chnl_state *chnl,
+ struct mcde_video_mode *vmode)
+{
+ if (chnl == NULL || vmode == NULL)
+ return -EINVAL;
+
+ chnl->vmode = *vmode;
+
+ return 0;
+}
+EXPORT_SYMBOL(mcde_chnl_set_video_mode);
+
+static void dpi_video_mode_apply(struct mcde_chnl_state *chnl)
+{
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
+ chnl->tv_regs.interlaced_en = chnl->vmode.interlaced;
+
+ chnl->tv_regs.sel_mode_tv = chnl->port.phy.dpi.tv_mode;
+ if (chnl->tv_regs.sel_mode_tv) {
+ /* TV mode */
+ u32 bel = chnl->vmode.vbp1 + chnl->vmode.vfp1
+ + chnl->vmode.vbp2 + chnl->vmode.vfp2;
+ /* -4 since hsw is excluding SAV/EAV, 2 bytes each */
+ chnl->tv_regs.hsw = chnl->vmode.hbp + chnl->vmode.hfp - 4;
+ chnl->tv_regs.dho = MCDE_CONFIG_TVOUT_HBORDER;
+ chnl->tv_regs.alw = MCDE_CONFIG_TVOUT_HBORDER;
+ /* in TV mode: bel1 = bel2 + 1 */
+ chnl->tv_regs.bel2 = bel / 2;
+ chnl->tv_regs.bel1 = bel - chnl->tv_regs.bel2;
+ chnl->tv_regs.dvo = MCDE_CONFIG_TVOUT_VBORDER;
+ chnl->tv_regs.bsl = MCDE_CONFIG_TVOUT_VBORDER;
+ chnl->tv_regs.fsl1 = chnl->vmode.vbp1;
+ chnl->tv_regs.fsl2 = chnl->vmode.vbp2;
+ if (chnl->port.phy.dpi.bus_width == 4)
+ chnl->tv_regs.tv_mode = MCDE_TVCRA_TVMODE_SDTV_656P_BE;
+ else
+ chnl->tv_regs.tv_mode = MCDE_TVCRA_TVMODE_SDTV_656P;
+ } else {
+ /* LCD mode */
+ u32 polarity;
+ chnl->tv_regs.hsw = chnl->vmode.hsw;
+ chnl->tv_regs.dho = chnl->vmode.hbp;
+ chnl->tv_regs.alw = chnl->vmode.hfp;
+ chnl->tv_regs.bel1 = chnl->vmode.vsw;
+ chnl->tv_regs.bel2 = chnl->tv_regs.bel1;
+ chnl->tv_regs.dvo = chnl->vmode.vbp1 + chnl->vmode.vbp2;
+ chnl->tv_regs.bsl = chnl->vmode.vfp1 + chnl->vmode.vfp2;
+ chnl->tv_regs.fsl1 = 0;
+ chnl->tv_regs.fsl2 = 0;
+ polarity = chnl->port.phy.dpi.polarity;
+ chnl->tv_regs.lcdtim1 |= MCDE_LCDTIM1A_IPC(
+ (polarity & DPI_ACT_ON_FALLING_EDGE) != 0);
+ chnl->tv_regs.lcdtim1 = MCDE_LCDTIM1A_IHS(
+ (polarity & DPI_ACT_LOW_HSYNC) != 0);
+ chnl->tv_regs.lcdtim1 |= MCDE_LCDTIM1A_IVS(
+ (polarity & DPI_ACT_LOW_VSYNC) != 0);
+ chnl->tv_regs.lcdtim1 |= MCDE_LCDTIM1A_IOE(
+ (polarity & DPI_ACT_LOW_DATA_ENABLE) != 0);
+ }
+}
+
+static void update_dpi_registers(enum mcde_chnl chnl_id, struct tv_regs *regs)
+{
+ u8 idx = chnl_id;
+
+ dev_dbg(&mcde_dev->dev, "%s\n", __func__);
+ mcde_wreg(MCDE_TVCRA + idx * MCDE_TVCRA_GROUPOFFSET,
+ MCDE_TVCRA_SEL_MOD(regs->sel_mode_tv) |
+ MCDE_TVCRA_INTEREN(regs->interlaced_en) |
+ MCDE_TVCRA_IFIELD(1) |
+ MCDE_TVCRA_TVMODE(regs->tv_mode) |
+ MCDE_TVCRA_SDTVMODE(MCDE_TVCRA_SDTVMODE_Y0CBY1CR) |
+ MCDE_TVCRA_AVRGEN(0));
+ mcde_wreg(MCDE_TVBLUA + idx * MCDE_TVBLUA_GROUPOFFSET,
+ MCDE_TVBLUA_TVBLU(MCDE_CONFIG_TVOUT_BACKGROUND_LUMINANCE) |
+ MCDE_TVBLUA_TVBCB(MCDE_CONFIG_TVOUT_BACKGROUND_CHROMINANCE_CB)|
+ MCDE_TVBLUA_TVBCR(MCDE_CONFIG_TVOUT_BACKGROUND_CHROMINANCE_CR));
+
+ /* Vertical timing registers */
+ mcde_wreg(MCDE_TVDVOA + idx * MCDE_TVDVOA_GROUPOFFSET,
+ MCDE_TVDVOA_DVO1(regs->dvo) |
+ MCDE_TVDVOA_DVO2(regs->dvo));
+ mcde_wreg(MCDE_TVBL1A + idx * MCDE_TVBL1A_GROUPOFFSET,
+ MCDE_TVBL1A_BEL1(regs->bel1) |
+ MCDE_TVBL1A_BSL1(regs->bsl));
+ mcde_wreg(MCDE_TVBL2A + idx * MCDE_TVBL1A_GROUPOFFSET,
+ MCDE_TVBL2A_BEL2(regs->bel2) |
+ MCDE_TVBL2A_BSL2(regs->bsl));
+ mcde_wreg(MCDE_TVISLA + idx * MCDE_TVISLA_GROUPOFFSET,
+ MCDE_TVISLA_FSL1(regs->fsl1) |
+ MCDE_TVISLA_FSL2(regs->fsl2));
+
+ /* Horizontal timing registers */
+ if (!regs->sel_mode_tv ||
+ hardware_version == MCDE_CHIP_VERSION_3_0_8) {
+ mcde_wreg(MCDE_TVLBALWA + idx * MCDE_TVLBALWA_GROUPOFFSET,
+ MCDE_TVLBALWA_LBW(regs->hsw) |
+ MCDE_TVLBALWA_ALW(regs->alw));
+ mcde_wreg(MCDE_TVTIM1A + idx * MCDE_TVTIM1A_GROUPOFFSET,
+ MCDE_TVTIM1A_DHO(regs->dho));
+ } else {
+ /* in earlier versions the LBW and DHO fields are swapped
+ * TV mode only
+ */
+ mcde_wreg(MCDE_TVLBALWA + idx * MCDE_TVLBALWA_GROUPOFFSET,
+ MCDE_TVLBALWA_LBW(regs->dho) |
+ MCDE_TVLBALWA_ALW(regs->alw));
+ mcde_wreg(MCDE_TVTIM1A + idx * MCDE_TVTIM1A_GROUPOFFSET,
+ MCDE_TVTIM1A_DHO(regs->hsw));
+ }
+ if (!regs->sel_mode_tv)
+ mcde_wreg(MCDE_LCDTIM1A + idx * MCDE_LCDTIM1A_GROUPOFFSET,
+ regs->lcdtim1);
+}
+
+static void update_col_registers(enum mcde_chnl chnl_id, struct col_regs *regs)
+{
+ u8 idx = chnl_id;
+
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
+ mcde_wreg(MCDE_RGBCONV1A + idx * MCDE_RGBCONV1A_GROUPOFFSET,
+ MCDE_RGBCONV1A_YR_RED(regs->y_red) |
+ MCDE_RGBCONV1A_YR_GREEN(regs->y_green));
+ mcde_wreg(MCDE_RGBCONV2A + idx * MCDE_RGBCONV2A_GROUPOFFSET,
+ MCDE_RGBCONV2A_YR_BLUE(regs->y_blue) |
+ MCDE_RGBCONV2A_CR_RED(regs->cr_red));
+ mcde_wreg(MCDE_RGBCONV3A + idx * MCDE_RGBCONV3A_GROUPOFFSET,
+ MCDE_RGBCONV3A_CR_GREEN(regs->cr_green) |
+ MCDE_RGBCONV3A_CR_BLUE(regs->cr_blue));
+ mcde_wreg(MCDE_RGBCONV4A + idx * MCDE_RGBCONV4A_GROUPOFFSET,
+ MCDE_RGBCONV4A_CB_RED(regs->cb_red) |
+ MCDE_RGBCONV4A_CB_GREEN(regs->cb_green));
+ mcde_wreg(MCDE_RGBCONV5A + idx * MCDE_RGBCONV5A_GROUPOFFSET,
+ MCDE_RGBCONV5A_CB_BLUE(regs->cb_blue) |
+ MCDE_RGBCONV5A_OFF_RED(regs->off_red));
+ mcde_wreg(MCDE_RGBCONV6A + idx * MCDE_RGBCONV6A_GROUPOFFSET,
+ MCDE_RGBCONV6A_OFF_GREEN(regs->off_green) |
+ MCDE_RGBCONV6A_OFF_BLUE(regs->off_blue));
+}
+
+/* MCDE internal helpers */
+static u8 portfmt2dsipacking(enum mcde_port_pix_fmt pix_fmt)
+{
+ switch (pix_fmt) {
+ case MCDE_PORTPIXFMT_DSI_16BPP:
+ return MCDE_DSIVID0CONF0_PACKING_RGB565;
+ case MCDE_PORTPIXFMT_DSI_18BPP_PACKED:
+ return MCDE_DSIVID0CONF0_PACKING_RGB666;
+ case MCDE_PORTPIXFMT_DSI_18BPP:
+ case MCDE_PORTPIXFMT_DSI_24BPP:
+ default:
+ return MCDE_DSIVID0CONF0_PACKING_RGB888;
+ case MCDE_PORTPIXFMT_DSI_YCBCR422:
+ return MCDE_DSIVID0CONF0_PACKING_HDTV;
+ }
+}
+
+static u8 portfmt2bpp(enum mcde_port_pix_fmt pix_fmt)
+{
+ /* TODO: Check DPI spec *//* REVIEW: Remove or check */
+ switch (pix_fmt) {
+ case MCDE_PORTPIXFMT_DPI_16BPP_C1:
+ case MCDE_PORTPIXFMT_DPI_16BPP_C2:
+ case MCDE_PORTPIXFMT_DPI_16BPP_C3:
+ case MCDE_PORTPIXFMT_DSI_16BPP:
+ case MCDE_PORTPIXFMT_DSI_YCBCR422:
+ return 16;
+ case MCDE_PORTPIXFMT_DPI_18BPP_C1:
+ case MCDE_PORTPIXFMT_DPI_18BPP_C2:
+ case MCDE_PORTPIXFMT_DSI_18BPP_PACKED:
+ return 18;
+ case MCDE_PORTPIXFMT_DSI_18BPP:
+ case MCDE_PORTPIXFMT_DPI_24BPP:
+ case MCDE_PORTPIXFMT_DSI_24BPP:
+ return 24;
+ default:
+ return 1;
+ }
+}
+
+static u8 bpp2outbpp(u8 bpp)
+{
+ switch (bpp) {
+ case 16:
+ return MCDE_CRA1_OUTBPP_16BPP;
+ case 18:
+ return MCDE_CRA1_OUTBPP_18BPP;
+ case 24:
+ return MCDE_CRA1_OUTBPP_24BPP;
+ default:
+ return 0;
+ }
+}
+
+static u8 portfmt2cdwin(enum mcde_port_pix_fmt pix_fmt)
+{
+ switch (pix_fmt) {
+ case MCDE_PORTPIXFMT_DPI_16BPP_C1:
+ return MCDE_CRA1_CDWIN_16BBP_C1;
+ case MCDE_PORTPIXFMT_DPI_16BPP_C2:
+ return MCDE_CRA1_CDWIN_16BBP_C2;
+ case MCDE_PORTPIXFMT_DPI_18BPP_C1:
+ return MCDE_CRA1_CDWIN_18BBP_C1;
+ case MCDE_PORTPIXFMT_DPI_18BPP_C2:
+ return MCDE_CRA1_CDWIN_18BBP_C2;
+ case MCDE_PORTPIXFMT_DPI_24BPP:
+ return MCDE_CRA1_CDWIN_24BBP;
+
+ case MCDE_PORTPIXFMT_DPI_16BPP_C3:
+ /* 16 BPP C3 not supported by HW */
+ dev_warn(&mcde_dev->dev, "DPI 16 BPP C3 not supported\n");
+ /* intentional fall through */
+ default:
+ /* only DPI formats are relevant */
+ return 0;
+ }
+}
+
+static u32 get_output_fifo_size(enum mcde_fifo fifo)
+{
+ u32 ret = 1; /* Avoid div by zero */
+
+ switch (fifo) {
+ case MCDE_FIFO_A:
+ case MCDE_FIFO_B:
+ ret = MCDE_FIFO_AB_SIZE;
+ break;
+ case MCDE_FIFO_C0:
+ case MCDE_FIFO_C1:
+ ret = MCDE_FIFO_C0C1_SIZE;
+ break;
+ default:
+ dev_vdbg(&mcde_dev->dev, "Unsupported fifo");
+ break;
+ }
+ return ret;
+}
+
+static u8 get_dsi_formid(const struct mcde_port *port)
+{
+ if (port->ifc == DSI_VIDEO_MODE && port->link == 0)
+ return MCDE_CTRLA_FORMID_DSI0VID;
+ else if (port->ifc == DSI_VIDEO_MODE && port->link == 1)
+ return MCDE_CTRLA_FORMID_DSI1VID;
+ else if (port->ifc == DSI_VIDEO_MODE && port->link == 2)
+ return MCDE_CTRLA_FORMID_DSI2VID;
+ else if (port->ifc == DSI_CMD_MODE && port->link == 0)
+ return MCDE_CTRLA_FORMID_DSI0CMD;
+ else if (port->ifc == DSI_CMD_MODE && port->link == 1)
+ return MCDE_CTRLA_FORMID_DSI1CMD;
+ else if (port->ifc == DSI_CMD_MODE && port->link == 2)
+ return MCDE_CTRLA_FORMID_DSI2CMD;
+ return 0;
+}
+
+static struct mcde_chnl_state *find_channel_by_dsilink(int link)
+{
+ struct mcde_chnl_state *chnl = &channels[0];
+ for (; chnl < &channels[ARRAY_SIZE(channels)]; chnl++)
+ if (chnl->inuse && chnl->port.link == link &&
+ chnl->port.type == MCDE_PORTTYPE_DSI)
+ return chnl;
+ return NULL;
+}
+
+static irqreturn_t mcde_irq_handler(int irq, void *dev)
+{
+ int i;
+ u32 irq_status;
+ bool trig = false;
+ struct mcde_chnl_state *chnl;
+
+ /* Handle overlay irqs */
+ irq_status = mcde_rfld(MCDE_RISOVL, OVLFDRIS);
+ for (i = 0; i < ARRAY_SIZE(overlays); i++) {
+ if (irq_status & (1 << i)) {
+ struct mcde_ovly_state *ovly = &overlays[i];
+ ovly->transactionid_hw = ovly->transactionid_regs;
+ wake_up(&ovly->waitq_hw);
+ }
+ }
+ mcde_wfld(MCDE_RISOVL, OVLFDRIS, irq_status);
+
+ /* Handle channel irqs */
+ irq_status = mcde_rreg(MCDE_RISPP);
+ if (irq_status & MCDE_RISPP_VCMPARIS_MASK) {
+ chnl = &channels[MCDE_CHNL_A];
+ chnl->transactionid_hw = chnl->transactionid_regs;
+ wake_up(&chnl->waitq_hw);
+ mcde_wfld(MCDE_RISPP, VCMPARIS, 1);
+ if (chnl->port.update_auto_trig &&
+ chnl->port.sync_src == MCDE_SYNCSRC_OFF &&
+ chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->continous_running) {
+ mcde_wreg(MCDE_CHNL0SYNCHSW +
+ chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ MCDE_CHNL0SYNCHSW_SW_TRIG(true));
+ mod_timer(&chnl->auto_sync_timer,
+ jiffies +
+ msecs_to_jiffies(MCDE_AUTO_SYNC_WATCHDOG
+ * 1000));
+ }
+ }
+ if (irq_status & MCDE_RISPP_VCMPBRIS_MASK) {
+ chnl = &channels[MCDE_CHNL_B];
+ chnl->transactionid_hw = chnl->transactionid_regs;
+ wake_up(&chnl->waitq_hw);
+ mcde_wfld(MCDE_RISPP, VCMPBRIS, 1);
+ if (chnl->port.update_auto_trig &&
+ chnl->port.sync_src == MCDE_SYNCSRC_OFF &&
+ chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->continous_running) {
+ mcde_wreg(MCDE_CHNL0SYNCHSW +
+ chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ MCDE_CHNL0SYNCHSW_SW_TRIG(true));
+ mod_timer(&chnl->auto_sync_timer,
+ jiffies +
+ msecs_to_jiffies(MCDE_AUTO_SYNC_WATCHDOG
+ * 1000));
+ }
+ }
+ if (irq_status & MCDE_RISPP_VCMPC0RIS_MASK) {
+ chnl = &channels[MCDE_CHNL_C0];
+ chnl->transactionid_hw = chnl->transactionid_regs;
+ wake_up(&chnl->waitq_hw);
+ mcde_wfld(MCDE_RISPP, VCMPC0RIS, 1);
+ if (chnl->port.update_auto_trig &&
+ chnl->port.sync_src == MCDE_SYNCSRC_OFF &&
+ chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->continous_running) {
+ mcde_wreg(MCDE_CHNL0SYNCHSW +
+ chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ MCDE_CHNL0SYNCHSW_SW_TRIG(true));
+ mod_timer(&chnl->auto_sync_timer,
+ jiffies +
+ msecs_to_jiffies(MCDE_AUTO_SYNC_WATCHDOG
+ * 1000));
+ }
+ }
+ if (irq_status & MCDE_RISPP_VCMPC1RIS_MASK) {
+ chnl = &channels[MCDE_CHNL_C1];
+ chnl->transactionid_hw = chnl->transactionid_regs;
+ wake_up(&chnl->waitq_hw);
+ mcde_wfld(MCDE_RISPP, VCMPC1RIS, 1);
+ if (chnl->port.update_auto_trig &&
+ chnl->port.sync_src == MCDE_SYNCSRC_OFF &&
+ chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->continous_running) {
+ mcde_wreg(MCDE_CHNL0SYNCHSW +
+ chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ MCDE_CHNL0SYNCHSW_SW_TRIG(true));
+ mod_timer(&chnl->auto_sync_timer,
+ jiffies +
+ msecs_to_jiffies(MCDE_AUTO_SYNC_WATCHDOG
+ * 1000));
+ }
+ }
+ for (i = 0; i < num_dsilinks; i++) {
+ struct mcde_chnl_state *chnl_from_dsi;
+
+ trig = false;
+ irq_status = dsi_rfld(i, DSI_DIRECT_CMD_STS_FLAG,
+ TE_RECEIVED_FLAG);
+ if (irq_status) {
+ trig = true;
+ dsi_wreg(i, DSI_DIRECT_CMD_STS_CLR,
+ DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR(true));
+ dev_vdbg(&mcde_dev->dev, "BTA TE DSI%d\n", i);
+ }
+ irq_status = dsi_rfld(i, DSI_CMD_MODE_STS_FLAG, ERR_NO_TE_FLAG);
+ if (irq_status) {
+ dsi_wreg(i, DSI_CMD_MODE_STS_CLR,
+ DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR(true));
+ dev_info(&mcde_dev->dev, "NO_TE DSI%d\n", i);
+ }
+ if (!trig)
+ continue;
+ chnl_from_dsi = find_channel_by_dsilink(i);
+ if (chnl_from_dsi) {
+ mcde_wreg(MCDE_CHNL0SYNCHSW +
+ chnl_from_dsi->id *
+ MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ MCDE_CHNL0SYNCHSW_SW_TRIG(true));
+ dev_vdbg(&mcde_dev->dev, "SW TRIG DSI%d, chnl=%d\n", i,
+ chnl_from_dsi->id);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+void wait_for_overlay(struct mcde_ovly_state *ovly)
+{
+ int ret;
+
+ ret = wait_event_timeout(ovly->waitq_hw,
+ ovly->transactionid_hw == ovly->transactionid_regs,
+ msecs_to_jiffies(OVLY_TIMEOUT));
+ if (!ret)
+ dev_warn(&mcde_dev->dev,
+ "Wait for overlay timeout (ovly=%d,%d<%d)!\n",
+ ovly->idx, ovly->transactionid_hw,
+ ovly->transactionid_regs);
+}
+
+void wait_for_channel(struct mcde_chnl_state *chnl)
+{
+ int ret;
+
+ ret = wait_event_timeout(chnl->waitq_hw,
+ chnl->transactionid_hw == chnl->transactionid_regs,
+ msecs_to_jiffies(CHNL_TIMEOUT));
+ if (!ret)
+ dev_warn(&mcde_dev->dev,
+ "Wait for channel timeout (chnl=%d,%d<%d)!\n",
+ chnl->id, chnl->transactionid_hw,
+ chnl->transactionid_regs);
+}
+
+static int update_channel_static_registers(struct mcde_chnl_state *chnl)
+{
+ const struct chnl_config *cfg = chnl->cfg;
+ const struct mcde_port *port = &chnl->port;
+
+ if (hardware_version == MCDE_CHIP_VERSION_3_0_5) {
+ /* Fifo & muxing */
+ if (cfg->swap_a_c0_set)
+ mcde_wfld(MCDE_CONF0, SWAP_A_C0_V1, cfg->swap_a_c0);
+ if (cfg->swap_b_c1_set)
+ mcde_wfld(MCDE_CONF0, SWAP_B_C1_V1, cfg->swap_b_c1);
+ if (cfg->fabmux_set)
+ mcde_wfld(MCDE_CR, FABMUX_V1, cfg->fabmux);
+ if (cfg->f01mux_set)
+ mcde_wfld(MCDE_CR, F01MUX_V1, cfg->f01mux);
+
+ if (port->type == MCDE_PORTTYPE_DPI) {
+ if (port->link == 0)
+ mcde_wfld(MCDE_CR, DPIA_EN_V1, true);
+ else if (port->link == 1)
+ mcde_wfld(MCDE_CR, DPIB_EN_V1, true);
+ } else if (port->type == MCDE_PORTTYPE_DSI) {
+ if (port->ifc == DSI_VIDEO_MODE && port->link == 0)
+ mcde_wfld(MCDE_CR, DSIVID0_EN_V1, true);
+ else if (port->ifc == DSI_VIDEO_MODE && port->link == 1)
+ mcde_wfld(MCDE_CR, DSIVID1_EN_V1, true);
+ else if (port->ifc == DSI_VIDEO_MODE && port->link == 2)
+ mcde_wfld(MCDE_CR, DSIVID2_EN_V1, true);
+ else if (port->ifc == DSI_CMD_MODE && port->link == 0)
+ mcde_wfld(MCDE_CR, DSICMD0_EN_V1, true);
+ else if (port->ifc == DSI_CMD_MODE && port->link == 1)
+ mcde_wfld(MCDE_CR, DSICMD1_EN_V1, true);
+ else if (port->ifc == DSI_CMD_MODE && port->link == 2)
+ mcde_wfld(MCDE_CR, DSICMD2_EN_V1, true);
+ }
+
+ if (chnl->fifo == MCDE_FIFO_C0)
+ mcde_wreg(MCDE_CTRLC0, MCDE_CTRLC0_FIFOWTRMRK(
+ get_output_fifo_size(MCDE_FIFO_C0)));
+ else if (chnl->fifo == MCDE_FIFO_C1)
+ mcde_wreg(MCDE_CTRLC1, MCDE_CTRLC1_FIFOWTRMRK(
+ get_output_fifo_size(MCDE_FIFO_C1)));
+ else if (port->update_auto_trig &&
+ (port->sync_src == MCDE_SYNCSRC_TE0))
+ mcde_wreg(MCDE_CTRLC0, MCDE_CTRLC0_FIFOWTRMRK(
+ get_output_fifo_size(MCDE_FIFO_C0)));
+ else if (port->update_auto_trig &&
+ (port->sync_src == MCDE_SYNCSRC_TE1))
+ mcde_wreg(MCDE_CTRLC1, MCDE_CTRLC1_FIFOWTRMRK(
+ get_output_fifo_size(MCDE_FIFO_C1)));
+ } else {
+
+ switch (chnl->fifo) {
+ case MCDE_FIFO_A:
+ mcde_wreg(MCDE_CHNL0MUXING_V2 + chnl->id *
+ MCDE_CHNL0MUXING_V2_GROUPOFFSET,
+ MCDE_CHNL0MUXING_V2_FIFO_ID_ENUM(FIFO_A));
+ if (port->type == MCDE_PORTTYPE_DPI) {
+ mcde_wfld(MCDE_CTRLA, FORMTYPE,
+ MCDE_CTRLA_FORMTYPE_DPITV);
+ mcde_wfld(MCDE_CTRLA, FORMID, port->link);
+ mcde_wfld(MCDE_CTRLA, FIFOWTRMRK,
+ get_output_fifo_size(MCDE_FIFO_A));
+ } else if (port->type == MCDE_PORTTYPE_DSI) {
+ mcde_wfld(MCDE_CTRLA, FORMTYPE,
+ MCDE_CTRLA_FORMTYPE_DSI);
+ mcde_wfld(MCDE_CTRLA, FORMID,
+ get_dsi_formid(port));
+ mcde_wfld(MCDE_CTRLA, FIFOWTRMRK,
+ get_output_fifo_size(MCDE_FIFO_A));
+ }
+ break;
+ case MCDE_FIFO_B:
+ mcde_wreg(MCDE_CHNL0MUXING_V2 + chnl->id *
+ MCDE_CHNL0MUXING_V2_GROUPOFFSET,
+ MCDE_CHNL0MUXING_V2_FIFO_ID_ENUM(FIFO_B));
+ if (port->type == MCDE_PORTTYPE_DPI) {
+ mcde_wfld(MCDE_CTRLB, FORMTYPE,
+ MCDE_CTRLB_FORMTYPE_DPITV);
+ mcde_wfld(MCDE_CTRLB, FORMID, port->link);
+ mcde_wfld(MCDE_CTRLB, FIFOWTRMRK,
+ get_output_fifo_size(MCDE_FIFO_B));
+ } else if (port->type == MCDE_PORTTYPE_DSI) {
+ mcde_wfld(MCDE_CTRLB, FORMTYPE,
+ MCDE_CTRLB_FORMTYPE_DSI);
+ mcde_wfld(MCDE_CTRLB, FORMID,
+ get_dsi_formid(port));
+ mcde_wfld(MCDE_CTRLB, FIFOWTRMRK,
+ get_output_fifo_size(MCDE_FIFO_B));
+ }
+
+ break;
+ case MCDE_FIFO_C0:
+ mcde_wreg(MCDE_CHNL0MUXING_V2 + chnl->id *
+ MCDE_CHNL0MUXING_V2_GROUPOFFSET,
+ MCDE_CHNL0MUXING_V2_FIFO_ID_ENUM(FIFO_C0));
+ if (port->type == MCDE_PORTTYPE_DPI)
+ return -EINVAL;
+ mcde_wfld(MCDE_CTRLC0, FORMTYPE,
+ MCDE_CTRLC0_FORMTYPE_DSI);
+ mcde_wfld(MCDE_CTRLC0, FORMID, get_dsi_formid(port));
+ mcde_wfld(MCDE_CTRLC0, FIFOWTRMRK,
+ get_output_fifo_size(MCDE_FIFO_C0));
+ break;
+ case MCDE_FIFO_C1:
+ mcde_wreg(MCDE_CHNL0MUXING_V2 + chnl->id *
+ MCDE_CHNL0MUXING_V2_GROUPOFFSET,
+ MCDE_CHNL0MUXING_V2_FIFO_ID_ENUM(FIFO_C1));
+ if (port->type == MCDE_PORTTYPE_DPI)
+ return -EINVAL;
+ mcde_wfld(MCDE_CTRLC1, FORMTYPE,
+ MCDE_CTRLC1_FORMTYPE_DSI);
+ mcde_wfld(MCDE_CTRLC1, FORMID, get_dsi_formid(port));
+ mcde_wfld(MCDE_CTRLC1, FIFOWTRMRK,
+ get_output_fifo_size(MCDE_FIFO_C1));
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ /* Formatter */
+ if (port->type == MCDE_PORTTYPE_DSI) {
+ int i = 0;
+ u8 idx = 2 * port->link + port->ifc;
+ u8 lnk = port->link;
+
+ dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, LINK_EN, true);
+ dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, BTA_EN, true);
+ dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, READ_EN, true);
+ dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, REG_TE_EN, true);
+ dsi_wreg(lnk, DSI_MCTL_DPHY_STATIC,
+ DSI_MCTL_DPHY_STATIC_UI_X4(port->phy.dsi.ui));
+ dsi_wreg(lnk, DSI_DPHY_LANES_TRIM,
+ DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_ENUM(0_90));
+ dsi_wreg(lnk, DSI_MCTL_DPHY_TIMEOUT,
+ DSI_MCTL_DPHY_TIMEOUT_CLK_DIV(0xf) |
+ DSI_MCTL_DPHY_TIMEOUT_HSTX_TO_VAL(0x3fff) |
+ DSI_MCTL_DPHY_TIMEOUT_LPRX_TO_VAL(0x3fff));
+ dsi_wreg(lnk, DSI_MCTL_MAIN_PHY_CTL,
+ DSI_MCTL_MAIN_PHY_CTL_WAIT_BURST_TIME(0xf) |
+ DSI_MCTL_MAIN_PHY_CTL_LANE2_EN(true) |
+ DSI_MCTL_MAIN_PHY_CTL_CLK_CONTINUOUS(
+ port->phy.dsi.clk_cont));
+ dsi_wreg(lnk, DSI_MCTL_ULPOUT_TIME,
+ DSI_MCTL_ULPOUT_TIME_CKLANE_ULPOUT_TIME(1) |
+ DSI_MCTL_ULPOUT_TIME_DATA_ULPOUT_TIME(1));
+ /* TODO: make enum */
+ dsi_wfld(lnk, DSI_CMD_MODE_CTL, ARB_MODE, false);
+ /* TODO: make enum */
+ dsi_wfld(lnk, DSI_CMD_MODE_CTL, ARB_PRI, port->ifc == 1);
+ dsi_wreg(lnk, DSI_MCTL_MAIN_EN,
+ DSI_MCTL_MAIN_EN_PLL_START(true) |
+ DSI_MCTL_MAIN_EN_CKLANE_EN(true) |
+ DSI_MCTL_MAIN_EN_DAT1_EN(true) |
+ DSI_MCTL_MAIN_EN_DAT2_EN(port->phy.dsi.num_data_lanes
+ == 2) |
+ DSI_MCTL_MAIN_EN_IF1_EN(port->ifc == 0) |
+ DSI_MCTL_MAIN_EN_IF2_EN(port->ifc == 1));
+ while (dsi_rfld(lnk, DSI_MCTL_MAIN_STS, CLKLANE_READY) == 0 ||
+ dsi_rfld(lnk, DSI_MCTL_MAIN_STS, DAT1_READY) == 0 ||
+ dsi_rfld(lnk, DSI_MCTL_MAIN_STS, DAT2_READY) == 0) {
+ mdelay(1);
+ if (i++ == 10) {
+ dev_warn(&mcde_dev->dev,
+ "DSI lane not ready (link=%d)!\n", lnk);
+ return -EINVAL;
+ }
+ }
+
+ mcde_wreg(MCDE_DSIVID0CONF0 +
+ idx * MCDE_DSIVID0CONF0_GROUPOFFSET,
+ MCDE_DSIVID0CONF0_BLANKING(0) |
+ MCDE_DSIVID0CONF0_VID_MODE(
+ port->mode == MCDE_PORTMODE_VID) |
+ MCDE_DSIVID0CONF0_CMD8(true) |
+ MCDE_DSIVID0CONF0_BIT_SWAP(false) |
+ MCDE_DSIVID0CONF0_BYTE_SWAP(false) |
+ MCDE_DSIVID0CONF0_DCSVID_NOTGEN(true));
+
+ if (port->mode == MCDE_PORTMODE_CMD) {
+ if (port->ifc == DSI_VIDEO_MODE)
+ dsi_wfld(port->link, DSI_CMD_MODE_CTL, IF1_ID,
+ port->phy.dsi.virt_id);
+ else if (port->ifc == DSI_CMD_MODE)
+ dsi_wfld(port->link, DSI_CMD_MODE_CTL, IF2_ID,
+ port->phy.dsi.virt_id);
+ }
+ }
+
+ mcde_wfld(MCDE_CR, MCDEEN, true);
+
+ dev_vdbg(&mcde_dev->dev, "Static registers setup, chnl=%d\n", chnl->id);
+
+ return 0;
+}
+
+/* REVIEW: Make update_* an mcde_rectangle? */
+static void update_overlay_registers(u8 idx, struct ovly_regs *regs,
+ struct mcde_port *port, enum mcde_fifo fifo,
+ u16 update_x, u16 update_y, u16 update_w,
+ u16 update_h, u16 stride, bool interlaced)
+{
+ /* TODO: fix clipping for small overlay */
+ u32 lmrgn = (regs->cropx + update_x) * regs->bits_per_pixel;
+ u32 tmrgn = (regs->cropy + update_y) * stride;
+ u32 ppl = regs->ppl - update_x;
+ u32 lpf = regs->lpf - update_y;
+ u32 ljinc = stride;
+ u32 pixelfetchwtrmrklevel;
+ u8 nr_of_bufs = 1;
+ u32 fifo_size;
+
+ /* TODO: disable if everything clipped */
+ if (!regs->enabled) {
+ u32 temp;
+ temp = mcde_rreg(MCDE_OVL0CR + idx * MCDE_OVL0CR_GROUPOFFSET);
+ mcde_wreg(MCDE_OVL0CR + idx * MCDE_OVL0CR_GROUPOFFSET,
+ (temp & ~MCDE_OVL0CR_OVLEN_MASK) |
+ MCDE_OVL0CR_OVLEN(false));
+ return;
+ }
+
+ /*
+ * TODO: Preferably most of this is done in some apply function instead
+ * of every update. Problem is however that at overlay apply
+ * there is no port type info available (and the question is
+ * whether it is appropriate to add a port type there).
+ * Note that lpf has a dependency on update_y.
+ */
+ if (port->type == MCDE_PORTTYPE_DPI && port->phy.dpi.tv_mode)
+ /* REVIEW: Why not for DSI? enable in regs? */
+ regs->col_conv = MCDE_OVL0CR_COLCCTRL_ENABLED_NO_SAT;
+ else if (port->type == MCDE_PORTTYPE_DSI) {
+ if (port->pixel_format == MCDE_PORTPIXFMT_DSI_YCBCR422)
+ regs->col_conv = MCDE_OVL0CR_COLCCTRL_ENABLED_NO_SAT;
+ else
+ regs->col_conv = MCDE_OVL0CR_COLCCTRL_DISABLED;
+ if (interlaced) {
+ nr_of_bufs = 2;
+ lpf = lpf / 2;
+ ljinc *= 2;
+ }
+ }
+
+ fifo_size = get_output_fifo_size(fifo);
+#ifdef CONFIG_AV8100_SDTV
+ /* TODO: check if these watermark levels work for HDMI as well. */
+ pixelfetchwtrmrklevel = MCDE_PIXFETCH_SMALL_WTRMRKLVL;
+#else
+ if ((fifo == MCDE_FIFO_A || fifo == MCDE_FIFO_B) &&
+ regs->ppl >= fifo_size * 2)
+ pixelfetchwtrmrklevel = MCDE_PIXFETCH_LARGE_WTRMRKLVL;
+ else
+ pixelfetchwtrmrklevel = MCDE_PIXFETCH_MEDIUM_WTRMRKLVL;
+#endif /* CONFIG_AV8100_SDTV */
+
+ if (regs->reset_buf_id) {
+ u32 sel_mod = MCDE_EXTSRC0CR_SEL_MOD_SOFTWARE_SEL;
+ if (port->update_auto_trig && port->type == MCDE_PORTTYPE_DSI) {
+ switch (port->sync_src) {
+ case MCDE_SYNCSRC_OFF:
+ sel_mod = MCDE_EXTSRC0CR_SEL_MOD_SOFTWARE_SEL;
+ break;
+ case MCDE_SYNCSRC_TE0:
+ case MCDE_SYNCSRC_TE1:
+ default:
+ sel_mod = MCDE_EXTSRC0CR_SEL_MOD_AUTO_TOGGLE;
+ }
+ } else if (port->type == MCDE_PORTTYPE_DPI) {
+ sel_mod = port->update_auto_trig ?
+ MCDE_EXTSRC0CR_SEL_MOD_AUTO_TOGGLE :
+ MCDE_EXTSRC0CR_SEL_MOD_SOFTWARE_SEL;
+ }
+
+ regs->reset_buf_id = false;
+ mcde_wreg(MCDE_EXTSRC0CONF + idx * MCDE_EXTSRC0CONF_GROUPOFFSET,
+ MCDE_EXTSRC0CONF_BUF_ID(0) |
+ MCDE_EXTSRC0CONF_BUF_NB(nr_of_bufs) |
+ MCDE_EXTSRC0CONF_PRI_OVLID(idx) |
+ MCDE_EXTSRC0CONF_BPP(regs->bpp) |
+ MCDE_EXTSRC0CONF_BGR(regs->bgr) |
+ MCDE_EXTSRC0CONF_BEBO(regs->bebo) |
+ MCDE_EXTSRC0CONF_BEPO(false));
+ mcde_wreg(MCDE_EXTSRC0CR + idx * MCDE_EXTSRC0CR_GROUPOFFSET,
+ MCDE_EXTSRC0CR_SEL_MOD(sel_mod) |
+ MCDE_EXTSRC0CR_MULTIOVL_CTRL_ENUM(PRIMARY) |
+ MCDE_EXTSRC0CR_FS_DIV_DISABLE(false) |
+ MCDE_EXTSRC0CR_FORCE_FS_DIV(false));
+ mcde_wreg(MCDE_OVL0CR + idx * MCDE_OVL0CR_GROUPOFFSET,
+ MCDE_OVL0CR_OVLEN(true) |
+ MCDE_OVL0CR_COLCCTRL(regs->col_conv) |
+ MCDE_OVL0CR_CKEYGEN(false) |
+ MCDE_OVL0CR_ALPHAPMEN(true) |
+ MCDE_OVL0CR_OVLF(false) |
+ MCDE_OVL0CR_OVLR(false) |
+ MCDE_OVL0CR_OVLB(false) |
+ MCDE_OVL0CR_FETCH_ROPC(0) |
+ MCDE_OVL0CR_STBPRIO(0) |
+ MCDE_OVL0CR_BURSTSIZE_ENUM(HW_8W) |
+ /* TODO: enum, get from ovly */
+ MCDE_OVL0CR_MAXOUTSTANDING_ENUM(4_REQ) |
+ /* TODO: _HW_8W, calculate? */
+ MCDE_OVL0CR_ROTBURSTSIZE_ENUM(HW_8W));
+ mcde_wreg(MCDE_OVL0CONF + idx * MCDE_OVL0CONF_GROUPOFFSET,
+ MCDE_OVL0CONF_PPL(ppl) |
+ MCDE_OVL0CONF_EXTSRC_ID(idx) |
+ MCDE_OVL0CONF_LPF(lpf));
+ mcde_wreg(MCDE_OVL0CONF2 + idx * MCDE_OVL0CONF2_GROUPOFFSET,
+ MCDE_OVL0CONF2_BP_ENUM(PER_PIXEL_ALPHA) |
+ /* TODO: Allow setting? */
+ MCDE_OVL0CONF2_ALPHAVALUE(0xff) |
+ MCDE_OVL0CONF2_OPQ(regs->opq) |
+ MCDE_OVL0CONF2_PIXOFF(lmrgn & 63) |
+ MCDE_OVL0CONF2_PIXELFETCHERWATERMARKLEVEL(
+ pixelfetchwtrmrklevel));
+ mcde_wreg(MCDE_OVL0LJINC + idx * MCDE_OVL0LJINC_GROUPOFFSET,
+ ljinc);
+ mcde_wreg(MCDE_OVL0CROP + idx * MCDE_OVL0CROP_GROUPOFFSET,
+ MCDE_OVL0CROP_TMRGN(tmrgn) |
+ MCDE_OVL0CROP_LMRGN(lmrgn >> 6));
+ mcde_wreg(MCDE_OVL0COMP + idx * MCDE_OVL0COMP_GROUPOFFSET,
+ MCDE_OVL0COMP_XPOS(regs->xpos) |
+ MCDE_OVL0COMP_CH_ID(regs->ch_id) |
+ MCDE_OVL0COMP_YPOS(regs->ypos) |
+ MCDE_OVL0COMP_Z(regs->z));
+ }
+
+ dev_vdbg(&mcde_dev->dev, "Overlay registers setup, idx=%d\n", idx);
+}
+
+static void update_overlay_address_registers(u8 idx, struct ovly_regs *regs)
+{
+ mcde_wreg(MCDE_EXTSRC0A0 + idx * MCDE_EXTSRC0A0_GROUPOFFSET,
+ regs->baseaddress0);
+ mcde_wreg(MCDE_EXTSRC0A1 + idx * MCDE_EXTSRC0A1_GROUPOFFSET,
+ regs->baseaddress1);
+}
+
+#define MCDE_FLOWEN_MAX_TRIAL 6
+
+static void disable_channel(struct mcde_chnl_state *chnl)
+{
+ int i;
+ const struct mcde_port *port = &chnl->port;
+
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
+
+ if (port->type == MCDE_PORTTYPE_DSI)
+ dsi_wfld(port->link, DSI_MCTL_MAIN_PHY_CTL, CLK_CONTINUOUS,
+ false);
+
+ switch (chnl->id) {
+ case MCDE_CHNL_A:
+ mcde_wfld(MCDE_CRA0, FLOEN, false);
+ wait_for_channel(chnl);
+ for (i = 0; i < MCDE_FLOWEN_MAX_TRIAL; i++) {
+ msleep(1);
+ if (!mcde_rfld(MCDE_CRA0, FLOEN)) {
+ dev_vdbg(&mcde_dev->dev,
+ "Flow (A) disable after >= %d ms\n", i);
+ goto break_switch;
+ }
+ }
+ dev_warn(&mcde_dev->dev, "%s: channel A timeout\n", __func__);
+ break;
+ case MCDE_CHNL_B:
+ mcde_wfld(MCDE_CRB0, FLOEN, false);
+ wait_for_channel(chnl);
+ for (i = 0; i < MCDE_FLOWEN_MAX_TRIAL; i++) {
+ msleep(1);
+ if (!mcde_rfld(MCDE_CRB0, FLOEN)) {
+ dev_vdbg(&mcde_dev->dev,
+ "Flow (B) disable after >= %d ms\n", i);
+ goto break_switch;
+ }
+ }
+ dev_warn(&mcde_dev->dev, "%s: channel B timeout\n", __func__);
+ break;
+ case MCDE_CHNL_C0:
+ mcde_wfld(MCDE_CRC, C1EN, false);
+ if (!mcde_rfld(MCDE_CRC, C2EN))
+ mcde_wfld(MCDE_CRC, FLOEN, false);
+ wait_for_channel(chnl);
+ break;
+ case MCDE_CHNL_C1:
+ mcde_wfld(MCDE_CRC, C2EN, false);
+ if (!mcde_rfld(MCDE_CRC, C1EN))
+ mcde_wfld(MCDE_CRC, FLOEN, false);
+ wait_for_channel(chnl);
+ break;
+ }
+break_switch:
+ chnl->continous_running = false;
+#undef MCDE_FLOWEN_MAX_TRIAL
+}
+
+static void enable_channel(struct mcde_chnl_state *chnl)
+{
+ const struct mcde_port *port = &chnl->port;
+
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
+
+ if (port->type == MCDE_PORTTYPE_DSI)
+ dsi_wfld(port->link, DSI_MCTL_MAIN_PHY_CTL, CLK_CONTINUOUS,
+ port->phy.dsi.clk_cont);
+
+ switch (chnl->id) {
+ case MCDE_CHNL_A:
+ mcde_wfld(MCDE_CRA0, FLOEN, true);
+ break;
+ case MCDE_CHNL_B:
+ mcde_wfld(MCDE_CRB0, FLOEN, true);
+ break;
+ case MCDE_CHNL_C0:
+ mcde_wfld(MCDE_CRC, POWEREN, true);
+ mcde_wfld(MCDE_CRC, FLOEN, true);
+ mcde_wfld(MCDE_CRC, C1EN, true);
+ break;
+ case MCDE_CHNL_C1:
+ mcde_wfld(MCDE_CRC, POWEREN, true);
+ mcde_wfld(MCDE_CRC, FLOEN, true);
+ mcde_wfld(MCDE_CRC, C2EN, true);
+ break;
+ }
+}
+
+static int is_channel_enabled(struct mcde_chnl_state *chnl)
+{
+ switch (chnl->id) {
+ case MCDE_CHNL_A:
+ return mcde_rfld(MCDE_CRA0, FLOEN);
+ case MCDE_CHNL_B:
+ return mcde_rfld(MCDE_CRB0, FLOEN);
+ case MCDE_CHNL_C0:
+ return mcde_rfld(MCDE_CRC, FLOEN);
+ case MCDE_CHNL_C1:
+ return mcde_rfld(MCDE_CRC, FLOEN);
+ }
+ return 0;
+}
+
+static void watchdog_auto_sync_timer_function(unsigned long arg)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(channels); i++) {
+ struct mcde_chnl_state *chnl = &channels[i];
+ if (chnl->port.update_auto_trig &&
+ chnl->port.sync_src == MCDE_SYNCSRC_OFF &&
+ chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->continous_running) {
+ mcde_wreg(MCDE_CHNL0SYNCHSW +
+ chnl->id
+ * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ MCDE_CHNL0SYNCHSW_SW_TRIG(true));
+ mod_timer(&chnl->auto_sync_timer,
+ jiffies +
+ msecs_to_jiffies(MCDE_AUTO_SYNC_WATCHDOG
+ * 1000));
+ }
+ }
+}
+
+/* TODO get from register */
+#define MCDE_CLK_FREQ_MHZ 160
+
+void update_channel_registers(enum mcde_chnl chnl_id, struct chnl_regs *regs,
+ struct mcde_port *port, enum mcde_fifo fifo,
+ struct mcde_video_mode *video_mode)
+{
+ u8 idx = chnl_id;
+ u32 out_synch_src = MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_FORMATTER;
+ u32 src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE;
+
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
+ /* Channel */
+ if (port->update_auto_trig && port->type == MCDE_PORTTYPE_DSI) {
+ switch (port->sync_src) {
+ case MCDE_SYNCSRC_TE0:
+ out_synch_src = MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_VSYNC0;
+ src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_OUTPUT;
+ break;
+ case MCDE_SYNCSRC_OFF:
+ src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE;
+ break;
+ case MCDE_SYNCSRC_TE1:
+ default:
+ out_synch_src = MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_VSYNC1;
+ src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_OUTPUT;
+ }
+ } else if (port->type == MCDE_PORTTYPE_DPI) {
+ src_synch = port->update_auto_trig ?
+ MCDE_CHNL0SYNCHMOD_SRC_SYNCH_OUTPUT :
+ MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE;
+ }
+
+ mcde_wreg(MCDE_CHNL0CONF + idx * MCDE_CHNL0CONF_GROUPOFFSET,
+ MCDE_CHNL0CONF_PPL(regs->ppl-1) |
+ MCDE_CHNL0CONF_LPF(regs->lpf-1));
+ mcde_wreg(MCDE_CHNL0STAT + idx * MCDE_CHNL0STAT_GROUPOFFSET,
+ MCDE_CHNL0STAT_CHNLBLBCKGND_EN(false) |
+ MCDE_CHNL0STAT_CHNLRD(true));
+ mcde_wreg(MCDE_CHNL0SYNCHMOD +
+ idx * MCDE_CHNL0SYNCHMOD_GROUPOFFSET,
+ MCDE_CHNL0SYNCHMOD_SRC_SYNCH(src_synch) |
+ MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC(out_synch_src));
+ mcde_wreg(MCDE_CHNL0BCKGNDCOL + idx * MCDE_CHNL0BCKGNDCOL_GROUPOFFSET,
+ MCDE_CHNL0BCKGNDCOL_B(0) |
+ MCDE_CHNL0BCKGNDCOL_G(0) |
+ MCDE_CHNL0BCKGNDCOL_R(0));
+
+ switch (chnl_id) {
+ case MCDE_CHNL_A:
+ mcde_wfld(MCDE_CRA0, ROTEN, regs->roten);
+ mcde_wreg(MCDE_CRA1,
+ MCDE_CRA1_PCD(regs->pcd) |
+ MCDE_CRA1_CLKSEL(regs->clksel) |
+ MCDE_CRA1_CDWIN(regs->cdwin) |
+ MCDE_CRA1_OUTBPP(bpp2outbpp(regs->bpp)) |
+ MCDE_CRA1_BCD(regs->bcd) |
+ MCDE_CRA1_CLKTYPE(regs->internal_clk)
+ );
+ break;
+ case MCDE_CHNL_B:
+ mcde_wfld(MCDE_CRB0, ROTEN, regs->roten);
+ mcde_wreg(MCDE_CRB1,
+ MCDE_CRB1_PCD(regs->pcd) |
+ MCDE_CRB1_CLKSEL(regs->clksel) |
+ MCDE_CRB1_CDWIN(regs->cdwin) |
+ MCDE_CRB1_OUTBPP(bpp2outbpp(regs->bpp)) |
+ MCDE_CRB1_BCD(regs->bcd) |
+ MCDE_CRB1_CLKTYPE(regs->internal_clk)
+ );
+ break;
+ default:
+ break;
+ }
+
+ /* Formatter */
+ if (port->type == MCDE_PORTTYPE_DSI) {
+ u8 fidx = 2 * port->link + port->ifc;
+ u32 temp, packet;
+ /* pkt_div is used to avoid underflow in output fifo for
+ * large packets */
+ u32 pkt_div = 1;
+ u32 dsi_delay0 = 0;
+ u32 screen_ppl, screen_lpf;
+
+ screen_ppl = video_mode->xres;
+ screen_lpf = video_mode->yres;
+
+ pkt_div = screen_ppl / (get_output_fifo_size(fifo) * 2) + 1;
+
+ if (video_mode->interlaced)
+ screen_lpf /= 2;
+
+ /* pkt_delay_progressive = pixelclock * htot /
+ * (1E12 / 160E6) / pkt_div */
+ dsi_delay0 = (video_mode->pixclock + 1) *
+ (video_mode->xres + video_mode->hbp +
+ video_mode->hfp) /
+ (1000000 / MCDE_CLK_FREQ_MHZ) / pkt_div;
+ temp = mcde_rreg(MCDE_DSIVID0CONF0 +
+ fidx * MCDE_DSIVID0CONF0_GROUPOFFSET);
+ mcde_wreg(MCDE_DSIVID0CONF0 +
+ fidx * MCDE_DSIVID0CONF0_GROUPOFFSET,
+ (temp & ~MCDE_DSIVID0CONF0_PACKING_MASK) |
+ MCDE_DSIVID0CONF0_PACKING(regs->dsipacking));
+ /* 1==CMD8 */
+ packet = ((screen_ppl / pkt_div * regs->bpp) >> 3) + 1;
+ mcde_wreg(MCDE_DSIVID0FRAME +
+ fidx * MCDE_DSIVID0FRAME_GROUPOFFSET,
+ MCDE_DSIVID0FRAME_FRAME(packet * pkt_div * screen_lpf));
+ mcde_wreg(MCDE_DSIVID0PKT + fidx * MCDE_DSIVID0PKT_GROUPOFFSET,
+ MCDE_DSIVID0PKT_PACKET(packet));
+ mcde_wreg(MCDE_DSIVID0SYNC +
+ fidx * MCDE_DSIVID0SYNC_GROUPOFFSET,
+ MCDE_DSIVID0SYNC_SW(0) |
+ MCDE_DSIVID0SYNC_DMA(0));
+ mcde_wreg(MCDE_DSIVID0CMDW +
+ fidx * MCDE_DSIVID0CMDW_GROUPOFFSET,
+ MCDE_DSIVID0CMDW_CMDW_START(DCS_CMD_WRITE_START) |
+ MCDE_DSIVID0CMDW_CMDW_CONTINUE(DCS_CMD_WRITE_CONTINUE));
+ mcde_wreg(MCDE_DSIVID0DELAY0 +
+ fidx * MCDE_DSIVID0DELAY0_GROUPOFFSET,
+ MCDE_DSIVID0DELAY0_INTPKTDEL(dsi_delay0));
+ mcde_wreg(MCDE_DSIVID0DELAY1 +
+ fidx * MCDE_DSIVID0DELAY1_GROUPOFFSET,
+ MCDE_DSIVID0DELAY1_TEREQDEL(0) |
+ MCDE_DSIVID0DELAY1_FRAMESTARTDEL(0));
+ }
+
+ if (regs->roten) {
+ /* TODO: Allocate memory in ESRAM instead of
+ static allocations. */
+ mcde_wreg(MCDE_ROTADD0A + chnl_id * MCDE_ROTADD0A_GROUPOFFSET,
+ regs->rotbuf1);
+ mcde_wreg(MCDE_ROTADD1A + chnl_id * MCDE_ROTADD1A_GROUPOFFSET,
+ regs->rotbuf2);
+
+ mcde_wreg(MCDE_ROTACONF + chnl_id * MCDE_ROTACONF_GROUPOFFSET,
+ MCDE_ROTACONF_ROTBURSTSIZE_ENUM(8W) |
+ MCDE_ROTACONF_ROTBURSTSIZE_HW(1) |
+ MCDE_ROTACONF_ROTDIR(regs->rotdir) |
+ MCDE_ROTACONF_STRIP_WIDTH_ENUM(16PIX) |
+ MCDE_ROTACONF_RD_MAXOUT_ENUM(4_REQ) |
+ MCDE_ROTACONF_WR_MAXOUT_ENUM(8_REQ));
+ }
+
+ dev_vdbg(&mcde_dev->dev, "Channel registers setup, chnl=%d\n", chnl_id);
+}
+
+/* DSI */
+
+int mcde_dsi_dcs_write(struct mcde_chnl_state *chnl, u8 cmd, u8* data, int len)
+{
+ int i;
+ u32 wrdat[4] = { 0, 0, 0, 0 };
+ u32 settings;
+ u8 link = chnl->port.link;
+ u8 virt_id = chnl->port.phy.dsi.virt_id;
+
+ /* REVIEW: One command at a time */
+ /* REVIEW: Allow read/write on unreserved ports */
+ if (len > MCDE_MAX_DCS_WRITE || chnl->port.type != MCDE_PORTTYPE_DSI)
+ return -EINVAL;
+
+ wrdat[0] = cmd;
+ for (i = 1; i <= len; i++)
+ wrdat[i>>2] |= ((u32)data[i-1] << ((i & 3) * 8));
+
+ settings = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_ENUM(WRITE) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT(len > 1) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID(virt_id) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE(len+1) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN(true);
+ if (len == 0)
+ settings |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM(
+ DCS_SHORT_WRITE_0);
+ else if (len == 1)
+ settings |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM(
+ DCS_SHORT_WRITE_1);
+ else
+ settings |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM(
+ DCS_LONG_WRITE);
+
+ dsi_wreg(link, DSI_DIRECT_CMD_MAIN_SETTINGS, settings);
+ dsi_wreg(link, DSI_DIRECT_CMD_WRDAT0, wrdat[0]);
+ if (len > 3)
+ dsi_wreg(link, DSI_DIRECT_CMD_WRDAT1, wrdat[1]);
+ if (len > 7)
+ dsi_wreg(link, DSI_DIRECT_CMD_WRDAT2, wrdat[2]);
+ if (len > 11)
+ dsi_wreg(link, DSI_DIRECT_CMD_WRDAT3, wrdat[3]);
+ dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR, ~0);
+ dsi_wreg(link, DSI_DIRECT_CMD_SEND, true);
+
+ /* TODO: irq wait and error check */
+ mdelay(10);
+ dsi_wreg(link, DSI_CMD_MODE_STS_CLR, ~0);
+ dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR, ~0);
+
+ return 0;
+}
+
+int mcde_dsi_dcs_read(struct mcde_chnl_state *chnl, u8 cmd, u8* data, int *len)
+{
+ int ret = 0;
+ u8 link = chnl->port.link;
+ u8 virt_id = chnl->port.phy.dsi.virt_id;
+ u32 settings;
+ int wait = 100;
+ bool error, ok;
+
+ if (*len > MCDE_MAX_DCS_READ || chnl->port.type != MCDE_PORTTYPE_DSI)
+ return -EINVAL;
+
+ dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, BTA_EN, true);
+ dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, READ_EN, true);
+ settings = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_ENUM(READ) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT(false) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID(virt_id) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE(1) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN(true) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM(DCS_READ);
+ dsi_wreg(link, DSI_DIRECT_CMD_MAIN_SETTINGS, settings);
+ dsi_wreg(link, DSI_DIRECT_CMD_WRDAT0, cmd);
+ dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR, ~0);
+ dsi_wreg(link, DSI_DIRECT_CMD_RD_STS_CLR, ~0);
+ dsi_wreg(link, DSI_DIRECT_CMD_SEND, true);
+
+ /* TODO */
+ while (wait-- && !(error = dsi_rfld(link, DSI_DIRECT_CMD_STS,
+ READ_COMPLETED_WITH_ERR)) && !(ok = dsi_rfld(link,
+ DSI_DIRECT_CMD_STS, READ_COMPLETED)))
+ mdelay(10);
+
+ if (ok) {
+ int rdsize;
+ u32 rddat;
+
+ rdsize = dsi_rfld(link, DSI_DIRECT_CMD_RD_PROPERTY, RD_SIZE);
+ rddat = dsi_rreg(link, DSI_DIRECT_CMD_RDDAT);
+ if (rdsize < *len)
+ pr_debug("DCS incomplete read %d<%d (%.8X)\n",
+ rdsize, *len, rddat);/* REVIEW: dev_dbg */
+ *len = min(*len, rdsize);
+ memcpy(data, &rddat, *len);
+ } else {
+ pr_err("DCS read failed, err=%d, sts=%X\n",
+ error, dsi_rreg(link, DSI_DIRECT_CMD_STS));
+ ret = -EIO;
+ }
+
+ dsi_wreg(link, DSI_CMD_MODE_STS_CLR, ~0);
+ dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR, ~0);
+
+ return ret;
+}
+
+static void dsi_te_request(struct mcde_chnl_state *chnl)
+{
+ u8 link = chnl->port.link;
+ u8 virt_id = chnl->port.phy.dsi.virt_id;
+ u32 settings;
+
+ dev_vdbg(&mcde_dev->dev, "Request BTA TE, chnl=%d\n",
+ chnl->id);
+
+ dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, BTA_EN, true);
+ dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, REG_TE_EN, true);
+ dsi_wfld(link, DSI_CMD_MODE_CTL, TE_TIMEOUT, 0x3FF);
+ settings = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_ENUM(TE_REQ) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT(false) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID(virt_id) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE(2) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN(true) |
+ DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM(DCS_SHORT_WRITE_1);
+ dsi_wreg(link, DSI_DIRECT_CMD_MAIN_SETTINGS, settings);
+ dsi_wreg(link, DSI_DIRECT_CMD_WRDAT0, DCS_CMD_SET_TEAR_ON);
+ dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR,
+ DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR(true));
+ dsi_wfld(link, DSI_DIRECT_CMD_STS_CTL, TE_RECEIVED_EN, true);
+ dsi_wreg(link, DSI_CMD_MODE_STS_CLR,
+ DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR(true));
+ dsi_wfld(link, DSI_CMD_MODE_STS_CTL, ERR_NO_TE_EN, true);
+ dsi_wreg(link, DSI_DIRECT_CMD_SEND, true);
+}
+
+/* MCDE channels */
+struct mcde_chnl_state *mcde_chnl_get(enum mcde_chnl chnl_id,
+ enum mcde_fifo fifo, const struct mcde_port *port)
+{
+ int i;
+ struct mcde_chnl_state *chnl = NULL;
+ enum mcde_chnl_path path;
+ const struct chnl_config *cfg = NULL;
+
+ /* Allocate channel */
+ for (i = 0; i < ARRAY_SIZE(channels); i++) {
+ if (chnl_id == channels[i].id)
+ chnl = &channels[i];
+ }
+ if (!chnl) {
+ dev_dbg(&mcde_dev->dev, "Invalid channel, chnl=%d\n", chnl_id);
+ return ERR_PTR(-EINVAL);
+ }
+ if (chnl->inuse) {
+ dev_dbg(&mcde_dev->dev, "Channel in use, chnl=%d\n", chnl_id);
+ return ERR_PTR(-EBUSY);
+ }
+
+ path = MCDE_CHNLPATH(chnl->id, fifo, port->type, port->ifc, port->link);
+ for (i = 0; i < ARRAY_SIZE(chnl_configs); i++)
+ if (chnl_configs[i].path == path) {
+ cfg = &chnl_configs[i];
+ break;
+ }
+ if (cfg == NULL) {
+ dev_dbg(&mcde_dev->dev, "Invalid config, chnl=%d,"
+ " path=0x%.8X\n", chnl_id, path);
+ return ERR_PTR(-EINVAL);
+ } else
+ dev_info(&mcde_dev->dev, "Config, chnl=%d,"
+ " path=0x%.8X\n", chnl_id, path);
+
+ /* TODO: verify that cfg is ok to activate (check other chnl cfgs) */
+
+ chnl->cfg = cfg;
+ chnl->port = *port;
+ chnl->fifo = fifo;
+
+ if (update_channel_static_registers(chnl) < 0)
+ return ERR_PTR(-EINVAL);
+
+ chnl->synchronized_update = true;
+ chnl->pix_fmt = port->pixel_format;
+ mcde_chnl_apply(chnl);
+ chnl->inuse = true;
+
+ return chnl;
+}
+
+int mcde_chnl_set_pixel_format(struct mcde_chnl_state *chnl,
+ enum mcde_port_pix_fmt pix_fmt)
+{
+ if (!chnl->inuse)
+ return -EINVAL;
+ chnl->pix_fmt = pix_fmt;
+ return 0;
+}
+
+void mcde_chnl_set_col_convert(struct mcde_chnl_state *chnl,
+ struct mcde_col_convert *col_convert)
+{
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
+ chnl->col_regs.y_red = col_convert->matrix[0][0];
+ chnl->col_regs.y_green = col_convert->matrix[0][1];
+ chnl->col_regs.y_blue = col_convert->matrix[0][2];
+ chnl->col_regs.cb_red = col_convert->matrix[1][0];
+ chnl->col_regs.cb_green = col_convert->matrix[1][1];
+ chnl->col_regs.cb_blue = col_convert->matrix[1][2];
+ chnl->col_regs.cr_red = col_convert->matrix[2][0];
+ chnl->col_regs.cr_green = col_convert->matrix[2][1];
+ chnl->col_regs.cr_blue = col_convert->matrix[2][2];
+ chnl->col_regs.off_red = col_convert->offset[0];
+ chnl->col_regs.off_green = col_convert->offset[1];
+ chnl->col_regs.off_blue = col_convert->offset[2];
+}
+
+int mcde_chnl_set_rotation(struct mcde_chnl_state *chnl,
+ enum mcde_display_rotation rotation, u32 rotbuf1, u32 rotbuf2)
+{
+ if (!chnl->inuse)
+ return -EINVAL;
+
+ /* TODO: Fix 180 degrees rotation */
+ if (rotation == MCDE_DISPLAY_ROT_180_CCW ||
+ (chnl->id != MCDE_CHNL_A && chnl->id != MCDE_CHNL_B))
+ return -EINVAL;
+
+ chnl->rotation = rotation;
+ chnl->rotbuf1 = rotbuf1;
+ chnl->rotbuf2 = rotbuf2;
+
+ return 0;
+}
+
+int mcde_chnl_enable_synchronized_update(struct mcde_chnl_state *chnl,
+ bool enable)
+{
+ if (!chnl->inuse)
+ return -EINVAL;
+ chnl->synchronized_update = enable;
+ return 0;
+}
+
+int mcde_chnl_set_power_mode(struct mcde_chnl_state *chnl,
+ enum mcde_display_power_mode power_mode)
+{
+ if (!chnl->inuse)
+ return -EINVAL;
+
+ chnl->power_mode = power_mode;
+ return 0;
+}
+
+int mcde_chnl_apply(struct mcde_chnl_state *chnl)
+{
+ /* TODO: lock *//* REVIEW: MCDE locking! */
+ bool roten = false;
+ u8 rotdir = 0;
+
+ if (!chnl->inuse)
+ return -EINVAL;
+
+ if (chnl->rotation == MCDE_DISPLAY_ROT_90_CCW) {
+ roten = true;
+ rotdir = MCDE_ROTACONF_ROTDIR_CCW;
+ } else if (chnl->rotation == MCDE_DISPLAY_ROT_90_CW) {
+ roten = true;
+ rotdir = MCDE_ROTACONF_ROTDIR_CW;
+ }
+ /* REVIEW: 180 deg? */
+
+ chnl->regs.bpp = portfmt2bpp(chnl->pix_fmt);
+ chnl->regs.synchronized_update = chnl->synchronized_update;
+ chnl->regs.roten = roten;
+ chnl->regs.rotdir = rotdir;
+ chnl->regs.rotbuf1 = chnl->rotbuf1;
+ chnl->regs.rotbuf2 = chnl->rotbuf2;
+ if (chnl->port.type == MCDE_PORTTYPE_DSI) {
+ chnl->regs.clksel = MCDE_CRA1_CLKSEL_166MHZ;
+ chnl->regs.dsipacking = portfmt2dsipacking(chnl->pix_fmt);
+ } else if (chnl->port.type == MCDE_PORTTYPE_DPI) {
+ if (chnl->port.phy.dpi.tv_mode) {
+ chnl->regs.internal_clk = false;
+ if (chnl->id == MCDE_CHNL_A)
+ chnl->regs.clksel = MCDE_CRA1_CLKSEL_EXT_TV1;
+ else
+ chnl->regs.clksel = MCDE_CRA1_CLKSEL_EXT_TV2;
+ } else {
+ chnl->regs.internal_clk = true;
+ chnl->regs.clksel = MCDE_CRA1_CLKSEL_LCD;
+ chnl->regs.cdwin = portfmt2cdwin(chnl->pix_fmt);
+ chnl->regs.bcd = (chnl->port.phy.dpi.clock_div < 2);
+ if (!chnl->regs.bcd)
+ chnl->regs.pcd =
+ chnl->port.phy.dpi.clock_div - 2;
+ }
+ dpi_video_mode_apply(chnl);
+ }
+ chnl->transactionid++;
+
+ dev_vdbg(&mcde_dev->dev, "Channel applied, chnl=%d\n", chnl->id);
+ return 0;
+}
+
+static void chnl_update_registers(struct mcde_chnl_state *chnl)
+{
+ /* REVIEW: Move content to update_channel_register */
+ /* and remove this one */
+ if (chnl->port.type == MCDE_PORTTYPE_DPI)
+ update_dpi_registers(chnl->id, &chnl->tv_regs);
+ if (chnl->id == MCDE_CHNL_A || chnl->id == MCDE_CHNL_B)
+ update_col_registers(chnl->id, &chnl->col_regs);
+ update_channel_registers(chnl->id, &chnl->regs, &chnl->port,
+ chnl->fifo, &chnl->vmode);
+
+ chnl->transactionid_regs = chnl->transactionid;
+}
+
+static void chnl_update_continous(struct mcde_chnl_state *chnl)
+{
+ if (!chnl->continous_running) {
+ if (chnl->transactionid_regs < chnl->transactionid)
+ chnl_update_registers(chnl);
+ if (chnl->port.sync_src == MCDE_SYNCSRC_TE0)
+ mcde_wfld(MCDE_CRC, SYCEN0, true);
+ else if (chnl->port.sync_src == MCDE_SYNCSRC_TE1)
+ mcde_wfld(MCDE_CRC, SYCEN1, true);
+ chnl->continous_running = true;
+ /*
+ * For main and secondary display,
+ * FLOWEN has to be set before a SOFTWARE TRIG
+ * Otherwise not overlay interrupt is triggerd
+ */
+ enable_channel(chnl);
+ if (chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->port.sync_src == MCDE_SYNCSRC_OFF) {
+ mod_timer(&chnl->auto_sync_timer,
+ jiffies +
+ msecs_to_jiffies(MCDE_AUTO_SYNC_WATCHDOG * 1000));
+ }
+ }
+}
+
+static void chnl_update_non_continous(struct mcde_chnl_state *chnl)
+{
+ /* Commit settings to registers */
+ wait_for_channel(chnl);
+ if (chnl->transactionid_regs < chnl->transactionid)
+ chnl_update_registers(chnl);
+
+ /*
+ * For main and secondary display,
+ * FLOWEN has to be set before a SOFTWARE TRIG
+ * Otherwise not overlay interrupt is triggerd
+ * However FLOWEN must not be triggered before SOFTWARE TRIG
+ * if rotation is enabled
+ */
+ if (chnl->power_mode == MCDE_DISPLAY_PM_STANDBY ||
+ (!is_channel_enabled(chnl) && !chnl->regs.roten))
+ enable_channel(chnl);
+
+
+ /* TODO: look at port sync source and synched_update */
+ if (chnl->regs.synchronized_update &&
+ chnl->power_mode == MCDE_DISPLAY_PM_ON) {
+ if (chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->port.sync_src == MCDE_SYNCSRC_BTA) {
+ while (dsi_rfld(chnl->port.link, DSI_CMD_MODE_STS,
+ CSM_RUNNING))
+ udelay(100);
+ dsi_te_request(chnl);
+ }
+ } else {
+ mcde_wreg(MCDE_CHNL0SYNCHSW +
+ chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ MCDE_CHNL0SYNCHSW_SW_TRIG(true));
+ dev_vdbg(&mcde_dev->dev, "Channel update (no sync), chnl=%d\n",
+ chnl->id);
+ }
+ if (chnl->power_mode == MCDE_DISPLAY_PM_ON)
+ enable_channel(chnl);
+}
+
+static void chnl_update_overlay(struct mcde_chnl_state *chnl,
+ struct mcde_ovly_state *ovly)
+{
+ if (!ovly || (ovly->transactionid_regs >= ovly->transactionid &&
+ chnl->transactionid_regs >= chnl->transactionid))
+ return;
+
+ update_overlay_address_registers(ovly->idx, &ovly->regs);
+ if (ovly->regs.reset_buf_id) {
+ if (!chnl->continous_running)
+ wait_for_overlay(ovly);
+
+ update_overlay_registers(ovly->idx, &ovly->regs, &chnl->port,
+ chnl->fifo, chnl->regs.x, chnl->regs.y,
+ chnl->regs.ppl, chnl->regs.lpf, ovly->stride,
+ chnl->vmode.interlaced);
+ ovly->transactionid_regs = ovly->transactionid;
+ } else if (chnl->continous_running) {
+ ovly->transactionid_regs = ovly->transactionid;
+ wait_for_overlay(ovly);
+ }
+}
+
+int mcde_chnl_update(struct mcde_chnl_state *chnl,
+ struct mcde_rectangle *update_area)
+{
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
+
+ /* TODO: lock & make wait->trig async */
+ if (!chnl->inuse || !update_area
+ || (update_area->w == 0 && update_area->h == 0)) {
+ return -EINVAL;
+ }
+
+ chnl->regs.x = update_area->x;
+ chnl->regs.y = update_area->y;
+ /* TODO Crop against video_mode.xres and video_mode.yres */
+ chnl->regs.ppl = update_area->w;
+ chnl->regs.lpf = update_area->h;
+ if (chnl->port.type == MCDE_PORTTYPE_DPI &&
+ chnl->port.phy.dpi.tv_mode) {
+ chnl->regs.ppl -= 2 * MCDE_CONFIG_TVOUT_HBORDER;
+ /* subtract double borders, ie. per field */
+ chnl->regs.lpf -= 4 * MCDE_CONFIG_TVOUT_VBORDER;
+ } else if (chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->vmode.interlaced)
+ chnl->regs.lpf /= 2;
+
+ chnl_update_overlay(chnl, chnl->ovly0);
+ chnl_update_overlay(chnl, chnl->ovly1);
+
+ if (chnl->port.update_auto_trig)
+ chnl_update_continous(chnl);
+ else
+ chnl_update_non_continous(chnl);
+
+ dev_vdbg(&mcde_dev->dev, "Channel updated, chnl=%d\n", chnl->id);
+ return 0;
+}
+
+void mcde_chnl_put(struct mcde_chnl_state *chnl)
+{
+ /* TODO: If last channel, shutdown MCDE */
+ /* TODO: Release formatter MCDE_CR.DPI/DSI_EN */
+ if (!chnl->inuse)
+ return;
+
+ mcde_chnl_apply(chnl);
+ chnl->inuse = false;
+ (void)update_channel_static_registers(chnl);
+}
+
+void mcde_chnl_stop_flow(struct mcde_chnl_state *chnl)
+{
+ disable_channel(chnl);
+}
+
+/* MCDE overlays */
+struct mcde_ovly_state *mcde_ovly_get(struct mcde_chnl_state *chnl)
+{
+ struct mcde_ovly_state *ovly;
+
+ if (!chnl->inuse)
+ return ERR_PTR(-EINVAL);
+
+ if (!chnl->ovly0->inuse)
+ ovly = chnl->ovly0;
+ else if (chnl->ovly1 && !chnl->ovly1->inuse)
+ ovly = chnl->ovly1;
+ else
+ ovly = ERR_PTR(-EBUSY);
+
+ if (!IS_ERR(ovly)) {
+ ovly->inuse = true;
+ ovly->paddr = 0;
+ ovly->stride = 0;
+ ovly->pix_fmt = MCDE_OVLYPIXFMT_RGB565;
+ ovly->src_x = 0;
+ ovly->src_y = 0;
+ ovly->dst_x = 0;
+ ovly->dst_y = 0;
+ ovly->dst_z = 0;
+ ovly->w = 0;
+ ovly->h = 0;
+ mcde_ovly_apply(ovly);
+ }
+
+ return ovly;
+}
+
+void mcde_ovly_put(struct mcde_ovly_state *ovly)
+{
+ if (!ovly->inuse)
+ return;
+ if (ovly->regs.enabled) {
+ ovly->paddr = 0;
+ mcde_ovly_apply(ovly);/* REVIEW: API call calling API call! */
+ }
+ ovly->inuse = false;
+}
+
+void mcde_ovly_set_source_buf(struct mcde_ovly_state *ovly, u32 paddr)
+{
+ if (!ovly->inuse)
+ return;
+
+ ovly->paddr = paddr;
+}
+
+void mcde_ovly_set_source_info(struct mcde_ovly_state *ovly,
+ u32 stride, enum mcde_ovly_pix_fmt pix_fmt)
+{
+ if (!ovly->inuse)
+ return;
+
+ ovly->stride = stride;
+ ovly->pix_fmt = pix_fmt;
+}
+
+void mcde_ovly_set_source_area(struct mcde_ovly_state *ovly,
+ u16 x, u16 y, u16 w, u16 h)
+{
+ if (!ovly->inuse)
+ return;
+
+ ovly->src_x = x;
+ ovly->src_y = y;
+ ovly->w = w;
+ ovly->h = h;
+}
+
+void mcde_ovly_set_dest_pos(struct mcde_ovly_state *ovly, u16 x, u16 y, u8 z)
+{
+ if (!ovly->inuse)
+ return;
+
+ ovly->dst_x = x;
+ ovly->dst_y = y;
+ ovly->dst_z = z;
+}
+
+void mcde_ovly_apply(struct mcde_ovly_state *ovly)
+{
+ if (!ovly->inuse)
+ return;
+
+ /* TODO: lock */
+
+ ovly->regs.ch_id = ovly->chnl->id;
+ ovly->regs.enabled = ovly->paddr != 0;
+ ovly->regs.baseaddress0 = ovly->paddr;
+ ovly->regs.baseaddress1 = ovly->paddr + ovly->stride;
+ /*TODO set to true if interlaced *//* REVIEW: Video mode interlaced? */
+ ovly->regs.reset_buf_id = !ovly->chnl->continous_running;
+ switch (ovly->pix_fmt) {/* REVIEW: Extract to table */
+ case MCDE_OVLYPIXFMT_RGB565:
+ ovly->regs.bits_per_pixel = 16;
+ ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_RGB565;
+ ovly->regs.bgr = false;
+ ovly->regs.bebo = false;
+ ovly->regs.opq = true;
+ break;
+ case MCDE_OVLYPIXFMT_RGBA5551:
+ ovly->regs.bits_per_pixel = 16;
+ ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_IRGB1555;
+ ovly->regs.bgr = false;
+ ovly->regs.bebo = false;
+ ovly->regs.opq = false;
+ break;
+ case MCDE_OVLYPIXFMT_RGBA4444:
+ ovly->regs.bits_per_pixel = 16;
+ ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_ARGB4444;
+ ovly->regs.bgr = false;
+ ovly->regs.bebo = false;
+ ovly->regs.opq = false;
+ break;
+ case MCDE_OVLYPIXFMT_RGB888:
+ ovly->regs.bits_per_pixel = 24;
+ ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_RGB888;
+ ovly->regs.bgr = false;
+ ovly->regs.bebo = false;
+ ovly->regs.opq = true;
+ break;
+ case MCDE_OVLYPIXFMT_RGBX8888:
+ ovly->regs.bits_per_pixel = 32;
+ ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_XRGB8888;
+ ovly->regs.bgr = false;
+ ovly->regs.bebo = true;
+ ovly->regs.opq = true;
+ break;
+ case MCDE_OVLYPIXFMT_RGBA8888:
+ ovly->regs.bits_per_pixel = 32;
+ ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_ARGB8888;
+ ovly->regs.bgr = false;
+ ovly->regs.bebo = true;
+ ovly->regs.opq = false;
+ break;
+ case MCDE_OVLYPIXFMT_YCbCr422:
+ ovly->regs.bits_per_pixel = 16;
+ ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_YCBCR422;
+ ovly->regs.bgr = false;
+ ovly->regs.bebo = false;
+ ovly->regs.opq = true;
+ break;
+ default:
+ break;
+ }
+
+ ovly->regs.ppl = ovly->w;
+ ovly->regs.lpf = ovly->h;
+ ovly->regs.cropx = ovly->src_x;
+ ovly->regs.cropy = ovly->src_y;
+ ovly->regs.xpos = ovly->dst_x;
+ ovly->regs.ypos = ovly->dst_y;
+ ovly->regs.z = ovly->dst_z > 0; /* 0 or 1 */
+ ovly->regs.col_conv = MCDE_OVL0CR_COLCCTRL_DISABLED;
+
+ ovly->transactionid = ++ovly->chnl->transactionid;
+
+ dev_vdbg(&mcde_dev->dev, "Overlay applied, chnl=%d\n", ovly->chnl->id);
+}
+
+static int init_clocks_and_power(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct mcde_platform_data *pdata = pdev->dev.platform_data;
+ if (pdata->regulator_id) {
+ regulator = regulator_get(&pdev->dev,
+ pdata->regulator_id);
+ if (IS_ERR(regulator)) {
+ ret = PTR_ERR(regulator);
+ dev_warn(&pdev->dev,
+ "%s: Failed to get regulator '%s'\n",
+ __func__, pdata->regulator_id);
+ regulator = NULL;
+ goto regulator_err;
+ }
+ } else {
+ dev_dbg(&pdev->dev, "%s: No regulator id supplied \n",
+ __func__);
+ regulator = NULL;
+ }
+ clock_dsi = clk_get(&pdev->dev, pdata->clock_dsi_id);
+ if (IS_ERR(clock_dsi)) {
+ ret = PTR_ERR(clock_dsi);
+ dev_warn(&pdev->dev, "%s: Failed to get clock '%s'\n",
+ __func__, pdata->clock_dsi_id);
+ goto clk_dsi_err;
+ }
+
+ clock_dsi_lp = clk_get(&pdev->dev, pdata->clock_dsi_lp_id);
+ if (IS_ERR(clock_dsi_lp)) {
+ ret = PTR_ERR(clock_dsi_lp);
+ dev_warn(&pdev->dev, "%s: Failed to get clock '%s'\n",
+ __func__, pdata->clock_dsi_lp_id);
+ goto clk_dsi_lp_err;
+ }
+
+ clock_dpi = clk_get(&pdev->dev, pdata->clock_dpi_id);
+ if (IS_ERR(clock_dpi)) {
+ ret = PTR_ERR(clock_dpi);
+ dev_warn(&pdev->dev, "%s: Failed to get clock '%s'\n",
+ __func__, pdata->clock_dpi_id);
+ goto clk_dpi_err;
+ }
+
+ clock_mcde = clk_get(&pdev->dev, pdata->clock_mcde_id);
+ if (IS_ERR(clock_mcde)) {
+ ret = PTR_ERR(clock_mcde);
+ dev_warn(&pdev->dev, "%s: Failed to get clock '%s'\n",
+ __func__, pdata->clock_mcde_id);
+ goto clk_mcde_err;
+ }
+
+ return ret;
+
+clk_mcde_err:
+ clk_put(clock_dpi);
+clk_dpi_err:
+ clk_put(clock_dsi_lp);
+clk_dsi_lp_err:
+ clk_put(clock_dsi);
+clk_dsi_err:
+ if (regulator)
+ regulator_put(regulator);
+regulator_err:
+ return ret;
+}
+
+static void remove_clocks_and_power(struct platform_device *pdev)
+{
+ /* REVIEW: Release only if exist */
+ /* REVIEW: Remove make sure MCDE is done */
+ clk_put(clock_dpi);
+ clk_put(clock_dsi_lp);
+ clk_put(clock_dsi);
+ clk_put(clock_mcde);
+ if (regulator)
+ regulator_put(regulator);
+}
+
+static int enable_clocks_and_power(struct platform_device *pdev)
+{
+ int ret = 0;
+ if (regulator) {
+ ret = regulator_enable(regulator);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "%s: regulator_enable failed\n",
+ __func__);
+ goto regulator_err;
+ }
+ } else {
+ dev_dbg(&pdev->dev, "%s: No regulator id supplied \n"
+ , __func__);
+ }
+
+ ret = prcmu_set_hwacc(HW_ACC_ESRAM4, HW_ON);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "%s: prcmu_set_hwacc ESRAM 4 failed"
+ " ret = %d\n", __func__, ret);
+ goto prcmu_set_err;
+ }
+ ret = prcmu_set_hwacc(HW_ACC_MCDE, HW_ON);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "%s: "
+ "prcmu_set_hwacc MCDE failed ret = %d\n",
+ __func__, ret);
+ goto prcmu_set_err;
+ }
+
+ ret = clk_enable(clock_dsi);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "%s: "
+ "clk_enable dsi failed ret = %d\n", __func__, ret);
+ goto clk_dsi_err;
+ }
+ ret = clk_enable(clock_dsi_lp);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "%s: "
+ "clk_enable dsi_lp failed ret = %d\n", __func__, ret);
+ goto clk_dsi_lp_err;
+ }
+ ret = clk_enable(clock_dpi);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "%s: "
+ "clk_enable dpi failed ret = %d\n", __func__, ret);
+ goto clk_dpi_err;
+ }
+ ret = clk_enable(clock_mcde);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "%s: "
+ "clk_enable mcde failed ret = %d\n", __func__, ret);
+ goto clk_mcde_err;
+ }
+
+ ret = prcmu_enable_mcde();
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "%s: "
+ "prcmu_enable_mcde failed ret = %d\n", __func__, ret);
+ goto prcmu_err;
+ }
+
+ return ret;
+
+prcmu_err:
+clk_mcde_err:
+ clk_disable(clock_dpi);
+clk_dpi_err:
+ clk_disable(clock_dsi_lp);
+clk_dsi_lp_err:
+ clk_disable(clock_dsi);
+clk_dsi_err:
+ if (regulator)
+ regulator_disable(regulator);
+regulator_err:
+ (void)prcmu_set_hwacc(HW_ACC_MCDE, HW_OFF);
+prcmu_set_err:
+
+ return ret;
+}
+
+static int disable_clocks_and_power(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ clk_disable(clock_dpi);
+ clk_disable(clock_dsi_lp);
+ clk_disable(clock_dsi);
+ clk_disable(clock_mcde);
+ if (regulator) {
+ ret = regulator_disable(regulator);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "%s: regulator_disable failed\n"
+ , __func__);
+ goto regulator_err;
+ }
+ } else {
+ dev_dbg(&pdev->dev, "%s: No regulator id supplied \n"
+ , __func__);
+ }
+
+ (void)prcmu_set_hwacc(HW_ACC_MCDE, HW_OFF);
+
+ return ret;
+regulator_err:
+ clk_enable(clock_mcde);
+ clk_enable(clock_dsi);
+ clk_enable(clock_dsi_lp);
+ clk_enable(clock_dpi);
+ return ret;
+}
+
+static void update_mcde_registers(void)
+{
+ struct mcde_platform_data *pdata = mcde_dev->dev.platform_data;
+
+ /* Setup output muxing */
+ mcde_wreg(MCDE_CONF0,
+ MCDE_CONF0_IFIFOCTRLWTRMRKLVL(7) |
+ MCDE_CONF0_OUTMUX0(pdata->outmux[0]) |
+ MCDE_CONF0_OUTMUX1(pdata->outmux[1]) |
+ MCDE_CONF0_OUTMUX2(pdata->outmux[2]) |
+ MCDE_CONF0_OUTMUX3(pdata->outmux[3]) |
+ MCDE_CONF0_OUTMUX4(pdata->outmux[4]) |
+ pdata->syncmux);
+
+ /* Enable channel VCMP interrupts */
+ mcde_wreg(MCDE_IMSCPP,
+ MCDE_IMSCPP_VCMPAIM(true) |
+ MCDE_IMSCPP_VCMPBIM(true) |
+ MCDE_IMSCPP_VCMPC0IM(true) |
+ MCDE_IMSCPP_VCMPC1IM(true));
+
+ /* Enable overlay fetch done interrupts */
+ mcde_wfld(MCDE_IMSCOVL, OVLFDIM, 0x3f);
+
+ /* Setup sync pulse length */
+ mcde_wreg(MCDE_VSCRC0,
+ MCDE_VSCRC0_VSPMIN(1) |
+ MCDE_VSCRC0_VSPMAX(0xff));
+ mcde_wreg(MCDE_VSCRC1,
+ MCDE_VSCRC1_VSPMIN(1) |
+ MCDE_VSCRC1_VSPMAX(0xff));
+}
+
+static int __devinit mcde_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ int i, irq;
+ struct resource *res;
+ struct mcde_platform_data *pdata = pdev->dev.platform_data;
+ u8 major_version;
+ u8 minor_version;
+ u8 development_version;
+
+ if (!pdata) {
+ dev_dbg(&pdev->dev, "No platform data\n");
+ return -EINVAL;
+ }
+
+ num_dsilinks = pdata->num_dsilinks;
+ mcde_dev = pdev;
+
+ dsiio = kzalloc(num_dsilinks * sizeof(*dsiio), GFP_KERNEL);
+ if (!dsiio) {
+ ret = -ENOMEM;
+ goto failed_dsi_alloc;
+ }
+
+ /* Hook up irq */
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_dbg(&pdev->dev, "No irq defined\n");
+ ret = -EINVAL;
+ goto failed_irq_get;
+ }
+ ret = request_irq(irq, mcde_irq_handler, 0, "mcde", &pdev->dev);
+ if (ret) {
+ dev_dbg(&pdev->dev, "Failed to request irq (irq=%d)\n", irq);
+ goto failed_request_irq;
+ }
+
+ /* Map I/O */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "No MCDE io defined\n");
+ ret = -EINVAL;
+ goto failed_get_mcde_io;
+ }
+ mcdeio = ioremap(res->start, res->end - res->start + 1);
+ if (!mcdeio) {
+ dev_dbg(&pdev->dev, "MCDE iomap failed\n");
+ ret = -EINVAL;
+ goto failed_map_mcde_io;
+ }
+ dev_info(&pdev->dev, "MCDE iomap: 0x%.8X->0x%.8X\n",
+ (u32)res->start, (u32)mcdeio);
+ for (i = 0; i < num_dsilinks; i++) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1+i);
+ if (!res) {
+ dev_dbg(&pdev->dev, "No DSI%d io defined\n", i);
+ ret = -EINVAL;
+ goto failed_get_dsi_io;
+ }
+ dsiio[i] = ioremap(res->start, res->end - res->start + 1);
+ if (!dsiio[i]) {
+ dev_dbg(&pdev->dev, "MCDE DSI%d iomap failed\n", i);
+ ret = -EINVAL;
+ goto failed_map_dsi_io;
+ }
+ dev_info(&pdev->dev, "MCDE DSI%d iomap: 0x%.8X->0x%.8X\n",
+ i, (u32)res->start, (u32)dsiio[i]);
+ }
+
+ ret = init_clocks_and_power(pdev);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "%s: init_clocks_and_power failed\n"
+ , __func__);
+ goto failed_init_clocks;
+ }
+ ret = enable_clocks_and_power(pdev);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "%s: enable_clocks_and_power failed\n"
+ , __func__);
+ goto failed_enable_clocks;
+ }
+ update_mcde_registers();
+
+ major_version = MCDE_REG2VAL(MCDE_PID, MAJOR_VERSION,
+ mcde_rreg(MCDE_PID));
+ minor_version = MCDE_REG2VAL(MCDE_PID, MINOR_VERSION,
+ mcde_rreg(MCDE_PID));
+ development_version = MCDE_REG2VAL(MCDE_PID, DEVELOPMENT_VERSION,
+ mcde_rreg(MCDE_PID));
+
+ dev_info(&mcde_dev->dev, "MCDE HW revision %u.%u.%u.%u\n",
+ major_version, minor_version, development_version,
+ mcde_rfld(MCDE_PID, METALFIX_VERSION));
+
+ if (major_version == 3 && minor_version == 0 &&
+ development_version >= 8) {
+ hardware_version = MCDE_CHIP_VERSION_3_0_8;
+ dev_info(&mcde_dev->dev, "V2 HW\n");
+ } else if (major_version == 3 && minor_version == 0 &&
+ development_version >= 5) {
+ hardware_version = MCDE_CHIP_VERSION_3_0_5;
+ dev_info(&mcde_dev->dev, "V1 HW\n");
+ } else {
+ dev_err(&mcde_dev->dev, "Unsupported HW version\n");
+ ret = -ENOTSUPP;
+ goto failed_hardware_version;
+ }
+
+ return 0;
+
+failed_hardware_version:
+ disable_clocks_and_power(pdev);
+failed_enable_clocks:
+ remove_clocks_and_power(pdev);
+failed_init_clocks:
+failed_map_dsi_io:
+failed_get_dsi_io:
+ for (i = 0; i < num_dsilinks; i++) {
+ if (dsiio[i])
+ iounmap(dsiio[i]);
+ }
+ iounmap(mcdeio);
+failed_map_mcde_io:
+failed_get_mcde_io:
+ free_irq(irq, &pdev->dev);
+failed_request_irq:
+failed_irq_get:
+ kfree(dsiio);
+ dsiio = NULL;
+failed_dsi_alloc:
+ return ret;
+}
+
+
+static int __devexit mcde_remove(struct platform_device *pdev)
+{
+ struct mcde_chnl_state *chnl = &channels[0];
+
+ for (; chnl < &channels[ARRAY_SIZE(channels)]; chnl++) {
+ if (del_timer(&chnl->auto_sync_timer))
+ dev_vdbg(&mcde_dev->dev,
+ "%s timer could not be stopped\n"
+ , __func__);
+ }
+ remove_clocks_and_power(pdev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mcde_resume(struct platform_device *pdev)
+{
+ int ret;
+ struct mcde_chnl_state *chnl = &channels[0];
+
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
+ ret = enable_clocks_and_power(pdev);
+ if (ret < 0) {
+ dev_dbg(&pdev->dev, "%s: Enable clocks and power failed\n"
+ , __func__);
+ goto clock_err;
+ }
+ update_mcde_registers();
+
+ for (; chnl < &channels[ARRAY_SIZE(channels)]; chnl++) {
+ if (chnl->inuse) {
+ (void)update_channel_static_registers(chnl);
+ update_channel_registers(chnl->id, &chnl->regs,
+ &chnl->port, chnl->fifo,
+ &chnl->vmode);
+ if (chnl->ovly0)
+ update_overlay_registers(chnl->ovly0->idx,
+ &chnl->ovly0->regs,
+ &chnl->port, chnl->fifo,
+ chnl->regs.x, chnl->regs.y,
+ chnl->regs.ppl, chnl->regs.lpf,
+ chnl->ovly0->stride,
+ chnl->vmode.interlaced);
+ if (chnl->ovly1)
+ update_overlay_registers(chnl->ovly1->idx,
+ &chnl->ovly1->regs,
+ &chnl->port, chnl->fifo,
+ chnl->regs.x, chnl->regs.y,
+ chnl->regs.ppl, chnl->regs.lpf,
+ chnl->ovly1->stride,
+ chnl->vmode.interlaced);
+ }
+ }
+clock_err:
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int mcde_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct mcde_chnl_state *chnl = &channels[0];
+
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
+
+ /* This is added because of the auto sync feature */
+ for (; chnl < &channels[ARRAY_SIZE(channels)]; chnl++) {
+ mcde_chnl_stop_flow(chnl);
+ if (del_timer(&chnl->auto_sync_timer))
+ dev_vdbg(&mcde_dev->dev,
+ "%s timer could not be stopped\n"
+ , __func__);
+ }
+ return disable_clocks_and_power(pdev);
+}
+#endif
+
+static struct platform_driver mcde_driver = {
+ .probe = mcde_probe,
+ .remove = mcde_remove,
+#ifdef CONFIG_PM
+ .suspend = mcde_suspend,
+ .resume = mcde_resume,
+#else
+ .suspend = NULL,
+ .resume = NULL,
+#endif
+ .driver = {
+ .name = "mcde",
+ },
+};
+
+int __init mcde_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(channels); i++) {
+ channels[i].ovly0->chnl = &channels[i];
+ if (channels[i].ovly1)
+ channels[i].ovly1->chnl = &channels[i];
+ init_waitqueue_head(&channels[i].waitq_hw);
+ init_timer(&channels[i].auto_sync_timer);
+ channels[i].auto_sync_timer.function =
+ watchdog_auto_sync_timer_function;
+ }
+ for (i = 0; i < ARRAY_SIZE(overlays); i++)
+ init_waitqueue_head(&overlays[i].waitq_hw);
+
+ return platform_driver_register(&mcde_driver);
+}
+
+void mcde_exit(void)
+{
+ /* REVIEW: shutdown MCDE? */
+ platform_driver_unregister(&mcde_driver);
+}
diff --git a/drivers/video/mcde/mcde_mod.c b/drivers/video/mcde/mcde_mod.c
new file mode 100644
index 00000000000..60df0d4965f
--- /dev/null
+++ b/drivers/video/mcde/mcde_mod.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * ST-Ericsson MCDE driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <video/mcde.h>
+#include <video/mcde_fb.h>
+#include <video/mcde_dss.h>
+#include <video/mcde_display.h>
+
+/* Module init */
+
+static int __init mcde_subsystem_init(void)
+{
+ int ret;
+ pr_info("MCDE subsystem init begin\n");
+
+ /* MCDE module init sequence */
+ ret = mcde_init();
+ if (ret)
+ goto mcde_failed;
+ ret = mcde_display_init();
+ if (ret)
+ goto mcde_display_failed;
+ ret = mcde_dss_init();
+ if (ret)
+ goto mcde_dss_failed;
+ ret = mcde_fb_init();
+ if (ret)
+ goto mcde_fb_failed;
+ pr_info("MCDE subsystem init done\n");
+
+ goto done;
+mcde_fb_failed:
+ mcde_dss_exit();
+mcde_dss_failed:
+ mcde_display_exit();
+mcde_display_failed:
+ mcde_exit();
+mcde_failed:
+done:
+ return ret;
+}
+#ifdef MODULE
+module_init(mcde_subsystem_init);
+#else
+fs_initcall(mcde_subsystem_init);
+#endif
+
+static void __exit mcde_module_exit(void)
+{
+ mcde_exit();
+ mcde_display_exit();
+ mcde_dss_exit();
+}
+module_exit(mcde_module_exit);
+
+MODULE_AUTHOR("Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ST-Ericsson MCDE driver");
+
diff --git a/drivers/video/mcde/mcde_regs.h b/drivers/video/mcde/mcde_regs.h
new file mode 100644
index 00000000000..95b4c75a0dd
--- /dev/null
+++ b/drivers/video/mcde/mcde_regs.h
@@ -0,0 +1,5297 @@
+
+#define MCDE_VAL2REG(__reg, __fld, __val) \
+ (((__val) << __reg##_##__fld##_SHIFT) & __reg##_##__fld##_MASK)
+#define MCDE_REG2VAL(__reg, __fld, __val) \
+ (((__val) & __reg##_##__fld##_MASK) >> __reg##_##__fld##_SHIFT)
+
+#define MCDE_CR 0x00000000
+#define MCDE_CR_DSICMD2_EN_V1_SHIFT 0
+#define MCDE_CR_DSICMD2_EN_V1_MASK 0x00000001
+#define MCDE_CR_DSICMD2_EN_V1(__x) \
+ MCDE_VAL2REG(MCDE_CR, DSICMD2_EN_V1, __x)
+#define MCDE_CR_DSICMD1_EN_V1_SHIFT 1
+#define MCDE_CR_DSICMD1_EN_V1_MASK 0x00000002
+#define MCDE_CR_DSICMD1_EN_V1(__x) \
+ MCDE_VAL2REG(MCDE_CR, DSICMD1_EN_V1, __x)
+#define MCDE_CR_DSICMD0_EN_V1_SHIFT 2
+#define MCDE_CR_DSICMD0_EN_V1_MASK 0x00000004
+#define MCDE_CR_DSICMD0_EN_V1(__x) \
+ MCDE_VAL2REG(MCDE_CR, DSICMD0_EN_V1, __x)
+#define MCDE_CR_DSIVID2_EN_V1_SHIFT 3
+#define MCDE_CR_DSIVID2_EN_V1_MASK 0x00000008
+#define MCDE_CR_DSIVID2_EN_V1(__x) \
+ MCDE_VAL2REG(MCDE_CR, DSIVID2_EN_V1, __x)
+#define MCDE_CR_DSIVID1_EN_V1_SHIFT 4
+#define MCDE_CR_DSIVID1_EN_V1_MASK 0x00000010
+#define MCDE_CR_DSIVID1_EN_V1(__x) \
+ MCDE_VAL2REG(MCDE_CR, DSIVID1_EN_V1, __x)
+#define MCDE_CR_DSIVID0_EN_V1_SHIFT 5
+#define MCDE_CR_DSIVID0_EN_V1_MASK 0x00000020
+#define MCDE_CR_DSIVID0_EN_V1(__x) \
+ MCDE_VAL2REG(MCDE_CR, DSIVID0_EN_V1, __x)
+#define MCDE_CR_DBIC1_EN_V1_SHIFT 6
+#define MCDE_CR_DBIC1_EN_V1_MASK 0x00000040
+#define MCDE_CR_DBIC1_EN_V1(__x) \
+ MCDE_VAL2REG(MCDE_CR, DBIC1_EN_V1, __x)
+#define MCDE_CR_DBIC0_EN_V1_SHIFT 7
+#define MCDE_CR_DBIC0_EN_V1_MASK 0x00000080
+#define MCDE_CR_DBIC0_EN_V1(__x) \
+ MCDE_VAL2REG(MCDE_CR, DBIC0_EN_V1, __x)
+#define MCDE_CR_DPIB_EN_V1_SHIFT 8
+#define MCDE_CR_DPIB_EN_V1_MASK 0x00000100
+#define MCDE_CR_DPIB_EN_V1(__x) \
+ MCDE_VAL2REG(MCDE_CR, DPIB_EN_V1, __x)
+#define MCDE_CR_DPIA_EN_V1_SHIFT 9
+#define MCDE_CR_DPIA_EN_V1_MASK 0x00000200
+#define MCDE_CR_DPIA_EN_V1(__x) \
+ MCDE_VAL2REG(MCDE_CR, DPIA_EN_V1, __x)
+#define MCDE_CR_IFIFOCTRLEN_SHIFT 15
+#define MCDE_CR_IFIFOCTRLEN_MASK 0x00008000
+#define MCDE_CR_IFIFOCTRLEN(__x) \
+ MCDE_VAL2REG(MCDE_CR, IFIFOCTRLEN, __x)
+#define MCDE_CR_F01MUX_V1_SHIFT 16
+#define MCDE_CR_F01MUX_V1_MASK 0x00010000
+#define MCDE_CR_F01MUX_V1(__x) \
+ MCDE_VAL2REG(MCDE_CR, F01MUX_V1, __x)
+#define MCDE_CR_FABMUX_V1_SHIFT 17
+#define MCDE_CR_FABMUX_V1_MASK 0x00020000
+#define MCDE_CR_FABMUX_V1(__x) \
+ MCDE_VAL2REG(MCDE_CR, FABMUX_V1, __x)
+#define MCDE_CR_AUTOCLKG_EN_SHIFT 30
+#define MCDE_CR_AUTOCLKG_EN_MASK 0x40000000
+#define MCDE_CR_AUTOCLKG_EN(__x) \
+ MCDE_VAL2REG(MCDE_CR, AUTOCLKG_EN, __x)
+#define MCDE_CR_MCDEEN_SHIFT 31
+#define MCDE_CR_MCDEEN_MASK 0x80000000
+#define MCDE_CR_MCDEEN(__x) \
+ MCDE_VAL2REG(MCDE_CR, MCDEEN, __x)
+#define MCDE_CONF0 0x00000004
+#define MCDE_CONF0_SYNCMUX0_SHIFT 0
+#define MCDE_CONF0_SYNCMUX0_MASK 0x00000001
+#define MCDE_CONF0_SYNCMUX0(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, SYNCMUX0, __x)
+#define MCDE_CONF0_SYNCMUX1_SHIFT 1
+#define MCDE_CONF0_SYNCMUX1_MASK 0x00000002
+#define MCDE_CONF0_SYNCMUX1(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, SYNCMUX1, __x)
+#define MCDE_CONF0_SYNCMUX2_SHIFT 2
+#define MCDE_CONF0_SYNCMUX2_MASK 0x00000004
+#define MCDE_CONF0_SYNCMUX2(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, SYNCMUX2, __x)
+#define MCDE_CONF0_SYNCMUX3_SHIFT 3
+#define MCDE_CONF0_SYNCMUX3_MASK 0x00000008
+#define MCDE_CONF0_SYNCMUX3(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, SYNCMUX3, __x)
+#define MCDE_CONF0_SYNCMUX4_SHIFT 4
+#define MCDE_CONF0_SYNCMUX4_MASK 0x00000010
+#define MCDE_CONF0_SYNCMUX4(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, SYNCMUX4, __x)
+#define MCDE_CONF0_SYNCMUX5_SHIFT 5
+#define MCDE_CONF0_SYNCMUX5_MASK 0x00000020
+#define MCDE_CONF0_SYNCMUX5(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, SYNCMUX5, __x)
+#define MCDE_CONF0_SYNCMUX6_SHIFT 6
+#define MCDE_CONF0_SYNCMUX6_MASK 0x00000040
+#define MCDE_CONF0_SYNCMUX6(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, SYNCMUX6, __x)
+#define MCDE_CONF0_SYNCMUX7_SHIFT 7
+#define MCDE_CONF0_SYNCMUX7_MASK 0x00000080
+#define MCDE_CONF0_SYNCMUX7(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, SYNCMUX7, __x)
+#define MCDE_CONF0_SWAP_A_C0_V1_SHIFT 8
+#define MCDE_CONF0_SWAP_A_C0_V1_MASK 0x00000100
+#define MCDE_CONF0_SWAP_A_C0_V1(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, SWAP_A_C0_V1, __x)
+#define MCDE_CONF0_SWAP_B_C1_V1_SHIFT 9
+#define MCDE_CONF0_SWAP_B_C1_V1_MASK 0x00000200
+#define MCDE_CONF0_SWAP_B_C1_V1(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, SWAP_B_C1_V1, __x)
+#define MCDE_CONF0_FSYNCTRLA_V1_SHIFT 10
+#define MCDE_CONF0_FSYNCTRLA_V1_MASK 0x00000400
+#define MCDE_CONF0_FSYNCTRLA_V1(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, FSYNCTRLA_V1, __x)
+#define MCDE_CONF0_FSYNCTRLB_V1_SHIFT 11
+#define MCDE_CONF0_FSYNCTRLB_V1_MASK 0x00000800
+#define MCDE_CONF0_FSYNCTRLB_V1(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, FSYNCTRLB_V1, __x)
+#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT 12
+#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_MASK 0x00007000
+#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, IFIFOCTRLWTRMRKLVL, __x)
+#define MCDE_CONF0_OUTMUX0_SHIFT 16
+#define MCDE_CONF0_OUTMUX0_MASK 0x00070000
+#define MCDE_CONF0_OUTMUX0(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, OUTMUX0, __x)
+#define MCDE_CONF0_OUTMUX1_SHIFT 19
+#define MCDE_CONF0_OUTMUX1_MASK 0x00380000
+#define MCDE_CONF0_OUTMUX1(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, OUTMUX1, __x)
+#define MCDE_CONF0_OUTMUX2_SHIFT 22
+#define MCDE_CONF0_OUTMUX2_MASK 0x01C00000
+#define MCDE_CONF0_OUTMUX2(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, OUTMUX2, __x)
+#define MCDE_CONF0_OUTMUX3_SHIFT 25
+#define MCDE_CONF0_OUTMUX3_MASK 0x0E000000
+#define MCDE_CONF0_OUTMUX3(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, OUTMUX3, __x)
+#define MCDE_CONF0_OUTMUX4_SHIFT 28
+#define MCDE_CONF0_OUTMUX4_MASK 0x70000000
+#define MCDE_CONF0_OUTMUX4(__x) \
+ MCDE_VAL2REG(MCDE_CONF0, OUTMUX4, __x)
+#define MCDE_SSP 0x00000008
+#define MCDE_SSP_SSPDATA_SHIFT 0
+#define MCDE_SSP_SSPDATA_MASK 0x000000FF
+#define MCDE_SSP_SSPDATA(__x) \
+ MCDE_VAL2REG(MCDE_SSP, SSPDATA, __x)
+#define MCDE_SSP_SSPCMD_SHIFT 8
+#define MCDE_SSP_SSPCMD_MASK 0x00000100
+#define MCDE_SSP_SSPCMD_DATA 0
+#define MCDE_SSP_SSPCMD_COMMAND 1
+#define MCDE_SSP_SSPCMD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_SSP, SSPCMD, MCDE_SSP_SSPCMD_##__x)
+#define MCDE_SSP_SSPCMD(__x) \
+ MCDE_VAL2REG(MCDE_SSP, SSPCMD, __x)
+#define MCDE_SSP_SSPEN_SHIFT 16
+#define MCDE_SSP_SSPEN_MASK 0x00010000
+#define MCDE_SSP_SSPEN(__x) \
+ MCDE_VAL2REG(MCDE_SSP, SSPEN, __x)
+#define MCDE_AIS 0x00000100
+#define MCDE_AIS_MCDEPPI_SHIFT 0
+#define MCDE_AIS_MCDEPPI_MASK 0x00000001
+#define MCDE_AIS_MCDEPPI(__x) \
+ MCDE_VAL2REG(MCDE_AIS, MCDEPPI, __x)
+#define MCDE_AIS_MCDEOVLI_SHIFT 1
+#define MCDE_AIS_MCDEOVLI_MASK 0x00000002
+#define MCDE_AIS_MCDEOVLI(__x) \
+ MCDE_VAL2REG(MCDE_AIS, MCDEOVLI, __x)
+#define MCDE_AIS_MCDECHNLI_SHIFT 2
+#define MCDE_AIS_MCDECHNLI_MASK 0x00000004
+#define MCDE_AIS_MCDECHNLI(__x) \
+ MCDE_VAL2REG(MCDE_AIS, MCDECHNLI, __x)
+#define MCDE_AIS_MCDEERRI_SHIFT 3
+#define MCDE_AIS_MCDEERRI_MASK 0x00000008
+#define MCDE_AIS_MCDEERRI(__x) \
+ MCDE_VAL2REG(MCDE_AIS, MCDEERRI, __x)
+#define MCDE_AIS_DSI0AI_SHIFT 4
+#define MCDE_AIS_DSI0AI_MASK 0x00000010
+#define MCDE_AIS_DSI0AI(__x) \
+ MCDE_VAL2REG(MCDE_AIS, DSI0AI, __x)
+#define MCDE_AIS_DSI1AI_SHIFT 5
+#define MCDE_AIS_DSI1AI_MASK 0x00000020
+#define MCDE_AIS_DSI1AI(__x) \
+ MCDE_VAL2REG(MCDE_AIS, DSI1AI, __x)
+#define MCDE_AIS_DSI2AI_SHIFT 6
+#define MCDE_AIS_DSI2AI_MASK 0x00000040
+#define MCDE_AIS_DSI2AI(__x) \
+ MCDE_VAL2REG(MCDE_AIS, DSI2AI, __x)
+#define MCDE_IMSCPP 0x00000104
+#define MCDE_IMSCPP_VCMPAIM_SHIFT 0
+#define MCDE_IMSCPP_VCMPAIM_MASK 0x00000001
+#define MCDE_IMSCPP_VCMPAIM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCPP, VCMPAIM, __x)
+#define MCDE_IMSCPP_VCMPBIM_SHIFT 1
+#define MCDE_IMSCPP_VCMPBIM_MASK 0x00000002
+#define MCDE_IMSCPP_VCMPBIM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCPP, VCMPBIM, __x)
+#define MCDE_IMSCPP_VSCC0IM_SHIFT 2
+#define MCDE_IMSCPP_VSCC0IM_MASK 0x00000004
+#define MCDE_IMSCPP_VSCC0IM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCPP, VSCC0IM, __x)
+#define MCDE_IMSCPP_VSCC1IM_SHIFT 3
+#define MCDE_IMSCPP_VSCC1IM_MASK 0x00000008
+#define MCDE_IMSCPP_VSCC1IM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCPP, VSCC1IM, __x)
+#define MCDE_IMSCPP_VCMPC0IM_SHIFT 4
+#define MCDE_IMSCPP_VCMPC0IM_MASK 0x00000010
+#define MCDE_IMSCPP_VCMPC0IM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCPP, VCMPC0IM, __x)
+#define MCDE_IMSCPP_VCMPC1IM_SHIFT 5
+#define MCDE_IMSCPP_VCMPC1IM_MASK 0x00000020
+#define MCDE_IMSCPP_VCMPC1IM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCPP, VCMPC1IM, __x)
+#define MCDE_IMSCPP_ROTFDIM_B_SHIFT 6
+#define MCDE_IMSCPP_ROTFDIM_B_MASK 0x00000040
+#define MCDE_IMSCPP_ROTFDIM_B(__x) \
+ MCDE_VAL2REG(MCDE_IMSCPP, ROTFDIM_B, __x)
+#define MCDE_IMSCPP_ROTFDIM_A_SHIFT 7
+#define MCDE_IMSCPP_ROTFDIM_A_MASK 0x00000080
+#define MCDE_IMSCPP_ROTFDIM_A(__x) \
+ MCDE_VAL2REG(MCDE_IMSCPP, ROTFDIM_A, __x)
+#define MCDE_IMSCOVL 0x00000108
+#define MCDE_IMSCOVL_OVLRDIM_SHIFT 0
+#define MCDE_IMSCOVL_OVLRDIM_MASK 0x0000FFFF
+#define MCDE_IMSCOVL_OVLRDIM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCOVL, OVLRDIM, __x)
+#define MCDE_IMSCOVL_OVLFDIM_SHIFT 16
+#define MCDE_IMSCOVL_OVLFDIM_MASK 0xFFFF0000
+#define MCDE_IMSCOVL_OVLFDIM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCOVL, OVLFDIM, __x)
+#define MCDE_IMSCCHNL 0x0000010C
+#define MCDE_IMSCCHNL_CHNLRDIM_SHIFT 0
+#define MCDE_IMSCCHNL_CHNLRDIM_MASK 0x0000FFFF
+#define MCDE_IMSCCHNL_CHNLRDIM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCCHNL, CHNLRDIM, __x)
+#define MCDE_IMSCCHNL_CHNLAIM_SHIFT 16
+#define MCDE_IMSCCHNL_CHNLAIM_MASK 0xFFFF0000
+#define MCDE_IMSCCHNL_CHNLAIM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCCHNL, CHNLAIM, __x)
+#define MCDE_IMSCERR 0x00000110
+#define MCDE_IMSCERR_FUAIM_SHIFT 0
+#define MCDE_IMSCERR_FUAIM_MASK 0x00000001
+#define MCDE_IMSCERR_FUAIM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCERR, FUAIM, __x)
+#define MCDE_IMSCERR_FUBIM_SHIFT 1
+#define MCDE_IMSCERR_FUBIM_MASK 0x00000002
+#define MCDE_IMSCERR_FUBIM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCERR, FUBIM, __x)
+#define MCDE_IMSCERR_SCHBLCKDIM_SHIFT 2
+#define MCDE_IMSCERR_SCHBLCKDIM_MASK 0x00000004
+#define MCDE_IMSCERR_SCHBLCKDIM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCERR, SCHBLCKDIM, __x)
+#define MCDE_IMSCERR_ROTAFEIM_WRITE_SHIFT 3
+#define MCDE_IMSCERR_ROTAFEIM_WRITE_MASK 0x00000008
+#define MCDE_IMSCERR_ROTAFEIM_WRITE(__x) \
+ MCDE_VAL2REG(MCDE_IMSCERR, ROTAFEIM_WRITE, __x)
+#define MCDE_IMSCERR_ROTAFEIM_READ_SHIFT 4
+#define MCDE_IMSCERR_ROTAFEIM_READ_MASK 0x00000010
+#define MCDE_IMSCERR_ROTAFEIM_READ(__x) \
+ MCDE_VAL2REG(MCDE_IMSCERR, ROTAFEIM_READ, __x)
+#define MCDE_IMSCERR_ROTBFEIM_WRITE_SHIFT 5
+#define MCDE_IMSCERR_ROTBFEIM_WRITE_MASK 0x00000020
+#define MCDE_IMSCERR_ROTBFEIM_WRITE(__x) \
+ MCDE_VAL2REG(MCDE_IMSCERR, ROTBFEIM_WRITE, __x)
+#define MCDE_IMSCERR_ROTBFEIM_READ_SHIFT 6
+#define MCDE_IMSCERR_ROTBFEIM_READ_MASK 0x00000040
+#define MCDE_IMSCERR_ROTBFEIM_READ(__x) \
+ MCDE_VAL2REG(MCDE_IMSCERR, ROTBFEIM_READ, __x)
+#define MCDE_IMSCERR_FUC0IM_SHIFT 7
+#define MCDE_IMSCERR_FUC0IM_MASK 0x00000080
+#define MCDE_IMSCERR_FUC0IM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCERR, FUC0IM, __x)
+#define MCDE_IMSCERR_FUC1IM_SHIFT 8
+#define MCDE_IMSCERR_FUC1IM_MASK 0x00000100
+#define MCDE_IMSCERR_FUC1IM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCERR, FUC1IM, __x)
+#define MCDE_IMSCERR_OVLFERRIM_SHIFT 16
+#define MCDE_IMSCERR_OVLFERRIM_MASK 0xFFFF0000
+#define MCDE_IMSCERR_OVLFERRIM(__x) \
+ MCDE_VAL2REG(MCDE_IMSCERR, OVLFERRIM, __x)
+#define MCDE_RISPP 0x00000114
+#define MCDE_RISPP_VCMPARIS_SHIFT 0
+#define MCDE_RISPP_VCMPARIS_MASK 0x00000001
+#define MCDE_RISPP_VCMPARIS(__x) \
+ MCDE_VAL2REG(MCDE_RISPP, VCMPARIS, __x)
+#define MCDE_RISPP_VCMPBRIS_SHIFT 1
+#define MCDE_RISPP_VCMPBRIS_MASK 0x00000002
+#define MCDE_RISPP_VCMPBRIS(__x) \
+ MCDE_VAL2REG(MCDE_RISPP, VCMPBRIS, __x)
+#define MCDE_RISPP_VSCC0RIS_SHIFT 2
+#define MCDE_RISPP_VSCC0RIS_MASK 0x00000004
+#define MCDE_RISPP_VSCC0RIS(__x) \
+ MCDE_VAL2REG(MCDE_RISPP, VSCC0RIS, __x)
+#define MCDE_RISPP_VSCC1RIS_SHIFT 3
+#define MCDE_RISPP_VSCC1RIS_MASK 0x00000008
+#define MCDE_RISPP_VSCC1RIS(__x) \
+ MCDE_VAL2REG(MCDE_RISPP, VSCC1RIS, __x)
+#define MCDE_RISPP_VCMPC0RIS_SHIFT 4
+#define MCDE_RISPP_VCMPC0RIS_MASK 0x00000010
+#define MCDE_RISPP_VCMPC0RIS(__x) \
+ MCDE_VAL2REG(MCDE_RISPP, VCMPC0RIS, __x)
+#define MCDE_RISPP_VCMPC1RIS_SHIFT 5
+#define MCDE_RISPP_VCMPC1RIS_MASK 0x00000020
+#define MCDE_RISPP_VCMPC1RIS(__x) \
+ MCDE_VAL2REG(MCDE_RISPP, VCMPC1RIS, __x)
+#define MCDE_RISPP_ROTFDRIS_B_SHIFT 6
+#define MCDE_RISPP_ROTFDRIS_B_MASK 0x00000040
+#define MCDE_RISPP_ROTFDRIS_B(__x) \
+ MCDE_VAL2REG(MCDE_RISPP, ROTFDRIS_B, __x)
+#define MCDE_RISPP_ROTFDRIS_A_SHIFT 7
+#define MCDE_RISPP_ROTFDRIS_A_MASK 0x00000080
+#define MCDE_RISPP_ROTFDRIS_A(__x) \
+ MCDE_VAL2REG(MCDE_RISPP, ROTFDRIS_A, __x)
+#define MCDE_RISOVL 0x00000118
+#define MCDE_RISOVL_OVLRDRIS_SHIFT 0
+#define MCDE_RISOVL_OVLRDRIS_MASK 0x0000FFFF
+#define MCDE_RISOVL_OVLRDRIS(__x) \
+ MCDE_VAL2REG(MCDE_RISOVL, OVLRDRIS, __x)
+#define MCDE_RISOVL_OVLFDRIS_SHIFT 16
+#define MCDE_RISOVL_OVLFDRIS_MASK 0xFFFF0000
+#define MCDE_RISOVL_OVLFDRIS(__x) \
+ MCDE_VAL2REG(MCDE_RISOVL, OVLFDRIS, __x)
+#define MCDE_RISCHNL 0x0000011C
+#define MCDE_RISCHNL_CHNLRDRIS_SHIFT 0
+#define MCDE_RISCHNL_CHNLRDRIS_MASK 0x0000FFFF
+#define MCDE_RISCHNL_CHNLRDRIS(__x) \
+ MCDE_VAL2REG(MCDE_RISCHNL, CHNLRDRIS, __x)
+#define MCDE_RISCHNL_CHNLARIS_SHIFT 16
+#define MCDE_RISCHNL_CHNLARIS_MASK 0xFFFF0000
+#define MCDE_RISCHNL_CHNLARIS(__x) \
+ MCDE_VAL2REG(MCDE_RISCHNL, CHNLARIS, __x)
+#define MCDE_RISERR 0x00000120
+#define MCDE_RISERR_FUARIS_SHIFT 0
+#define MCDE_RISERR_FUARIS_MASK 0x00000001
+#define MCDE_RISERR_FUARIS(__x) \
+ MCDE_VAL2REG(MCDE_RISERR, FUARIS, __x)
+#define MCDE_RISERR_FUBRIS_SHIFT 1
+#define MCDE_RISERR_FUBRIS_MASK 0x00000002
+#define MCDE_RISERR_FUBRIS(__x) \
+ MCDE_VAL2REG(MCDE_RISERR, FUBRIS, __x)
+#define MCDE_RISERR_SCHBLCKDRIS_SHIFT 2
+#define MCDE_RISERR_SCHBLCKDRIS_MASK 0x00000004
+#define MCDE_RISERR_SCHBLCKDRIS(__x) \
+ MCDE_VAL2REG(MCDE_RISERR, SCHBLCKDRIS, __x)
+#define MCDE_RISERR_ROTAFERIS_WRITE_SHIFT 3
+#define MCDE_RISERR_ROTAFERIS_WRITE_MASK 0x00000008
+#define MCDE_RISERR_ROTAFERIS_WRITE(__x) \
+ MCDE_VAL2REG(MCDE_RISERR, ROTAFERIS_WRITE, __x)
+#define MCDE_RISERR_ROTAFERIS_READ_SHIFT 4
+#define MCDE_RISERR_ROTAFERIS_READ_MASK 0x00000010
+#define MCDE_RISERR_ROTAFERIS_READ(__x) \
+ MCDE_VAL2REG(MCDE_RISERR, ROTAFERIS_READ, __x)
+#define MCDE_RISERR_ROTBFERIS_WRITE_SHIFT 5
+#define MCDE_RISERR_ROTBFERIS_WRITE_MASK 0x00000020
+#define MCDE_RISERR_ROTBFERIS_WRITE(__x) \
+ MCDE_VAL2REG(MCDE_RISERR, ROTBFERIS_WRITE, __x)
+#define MCDE_RISERR_ROTBFERIS_READ_SHIFT 6
+#define MCDE_RISERR_ROTBFERIS_READ_MASK 0x00000040
+#define MCDE_RISERR_ROTBFERIS_READ(__x) \
+ MCDE_VAL2REG(MCDE_RISERR, ROTBFERIS_READ, __x)
+#define MCDE_RISERR_FUC0RIS_SHIFT 7
+#define MCDE_RISERR_FUC0RIS_MASK 0x00000080
+#define MCDE_RISERR_FUC0RIS(__x) \
+ MCDE_VAL2REG(MCDE_RISERR, FUC0RIS, __x)
+#define MCDE_RISERR_FUC1RIS_SHIFT 8
+#define MCDE_RISERR_FUC1RIS_MASK 0x00000100
+#define MCDE_RISERR_FUC1RIS(__x) \
+ MCDE_VAL2REG(MCDE_RISERR, FUC1RIS, __x)
+#define MCDE_RISERR_OVLFERRRIS_SHIFT 16
+#define MCDE_RISERR_OVLFERRRIS_MASK 0xFFFF0000
+#define MCDE_RISERR_OVLFERRRIS(__x) \
+ MCDE_VAL2REG(MCDE_RISERR, OVLFERRRIS, __x)
+#define MCDE_MISPP 0x00000124
+#define MCDE_MISPP_VCMPAMIS_SHIFT 0
+#define MCDE_MISPP_VCMPAMIS_MASK 0x00000001
+#define MCDE_MISPP_VCMPAMIS(__x) \
+ MCDE_VAL2REG(MCDE_MISPP, VCMPAMIS, __x)
+#define MCDE_MISPP_VCMPBMIS_SHIFT 1
+#define MCDE_MISPP_VCMPBMIS_MASK 0x00000002
+#define MCDE_MISPP_VCMPBMIS(__x) \
+ MCDE_VAL2REG(MCDE_MISPP, VCMPBMIS, __x)
+#define MCDE_MISPP_VSCC0MIS_SHIFT 2
+#define MCDE_MISPP_VSCC0MIS_MASK 0x00000004
+#define MCDE_MISPP_VSCC0MIS(__x) \
+ MCDE_VAL2REG(MCDE_MISPP, VSCC0MIS, __x)
+#define MCDE_MISPP_VSCC1MIS_SHIFT 3
+#define MCDE_MISPP_VSCC1MIS_MASK 0x00000008
+#define MCDE_MISPP_VSCC1MIS(__x) \
+ MCDE_VAL2REG(MCDE_MISPP, VSCC1MIS, __x)
+#define MCDE_MISPP_VCMPC0MIS_SHIFT 4
+#define MCDE_MISPP_VCMPC0MIS_MASK 0x00000010
+#define MCDE_MISPP_VCMPC0MIS(__x) \
+ MCDE_VAL2REG(MCDE_MISPP, VCMPC0MIS, __x)
+#define MCDE_MISPP_VCMPC1MIS_SHIFT 5
+#define MCDE_MISPP_VCMPC1MIS_MASK 0x00000020
+#define MCDE_MISPP_VCMPC1MIS(__x) \
+ MCDE_VAL2REG(MCDE_MISPP, VCMPC1MIS, __x)
+#define MCDE_MISPP_ROTFDMIS_A_SHIFT 6
+#define MCDE_MISPP_ROTFDMIS_A_MASK 0x00000040
+#define MCDE_MISPP_ROTFDMIS_A(__x) \
+ MCDE_VAL2REG(MCDE_MISPP, ROTFDMIS_A, __x)
+#define MCDE_MISPP_ROTFDMIS_B_SHIFT 7
+#define MCDE_MISPP_ROTFDMIS_B_MASK 0x00000080
+#define MCDE_MISPP_ROTFDMIS_B(__x) \
+ MCDE_VAL2REG(MCDE_MISPP, ROTFDMIS_B, __x)
+#define MCDE_MISOVL 0x00000128
+#define MCDE_MISOVL_OVLRDMIS_SHIFT 0
+#define MCDE_MISOVL_OVLRDMIS_MASK 0x0000FFFF
+#define MCDE_MISOVL_OVLRDMIS(__x) \
+ MCDE_VAL2REG(MCDE_MISOVL, OVLRDMIS, __x)
+#define MCDE_MISOVL_OVLFDMIS_SHIFT 16
+#define MCDE_MISOVL_OVLFDMIS_MASK 0xFFFF0000
+#define MCDE_MISOVL_OVLFDMIS(__x) \
+ MCDE_VAL2REG(MCDE_MISOVL, OVLFDMIS, __x)
+#define MCDE_MISCHNL 0x0000012C
+#define MCDE_MISCHNL_CHNLRDMIS_SHIFT 0
+#define MCDE_MISCHNL_CHNLRDMIS_MASK 0x0000FFFF
+#define MCDE_MISCHNL_CHNLRDMIS(__x) \
+ MCDE_VAL2REG(MCDE_MISCHNL, CHNLRDMIS, __x)
+#define MCDE_MISCHNL_CHNLAMIS_SHIFT 16
+#define MCDE_MISCHNL_CHNLAMIS_MASK 0xFFFF0000
+#define MCDE_MISCHNL_CHNLAMIS(__x) \
+ MCDE_VAL2REG(MCDE_MISCHNL, CHNLAMIS, __x)
+#define MCDE_MISERR 0x00000130
+#define MCDE_MISERR_FUAMIS_SHIFT 0
+#define MCDE_MISERR_FUAMIS_MASK 0x00000001
+#define MCDE_MISERR_FUAMIS(__x) \
+ MCDE_VAL2REG(MCDE_MISERR, FUAMIS, __x)
+#define MCDE_MISERR_FUBMIS_SHIFT 1
+#define MCDE_MISERR_FUBMIS_MASK 0x00000002
+#define MCDE_MISERR_FUBMIS(__x) \
+ MCDE_VAL2REG(MCDE_MISERR, FUBMIS, __x)
+#define MCDE_MISERR_SCHBLCKDMIS_SHIFT 2
+#define MCDE_MISERR_SCHBLCKDMIS_MASK 0x00000004
+#define MCDE_MISERR_SCHBLCKDMIS(__x) \
+ MCDE_VAL2REG(MCDE_MISERR, SCHBLCKDMIS, __x)
+#define MCDE_MISERR_ROTAFEMIS_WRITE_SHIFT 3
+#define MCDE_MISERR_ROTAFEMIS_WRITE_MASK 0x00000008
+#define MCDE_MISERR_ROTAFEMIS_WRITE(__x) \
+ MCDE_VAL2REG(MCDE_MISERR, ROTAFEMIS_WRITE, __x)
+#define MCDE_MISERR_ROTAFEMIS_READ_SHIFT 4
+#define MCDE_MISERR_ROTAFEMIS_READ_MASK 0x00000010
+#define MCDE_MISERR_ROTAFEMIS_READ(__x) \
+ MCDE_VAL2REG(MCDE_MISERR, ROTAFEMIS_READ, __x)
+#define MCDE_MISERR_ROTBFEMIS_WRITE_SHIFT 5
+#define MCDE_MISERR_ROTBFEMIS_WRITE_MASK 0x00000020
+#define MCDE_MISERR_ROTBFEMIS_WRITE(__x) \
+ MCDE_VAL2REG(MCDE_MISERR, ROTBFEMIS_WRITE, __x)
+#define MCDE_MISERR_ROTBFEMIS_READ_SHIFT 6
+#define MCDE_MISERR_ROTBFEMIS_READ_MASK 0x00000040
+#define MCDE_MISERR_ROTBFEMIS_READ(__x) \
+ MCDE_VAL2REG(MCDE_MISERR, ROTBFEMIS_READ, __x)
+#define MCDE_MISERR_FUC0MIS_SHIFT 7
+#define MCDE_MISERR_FUC0MIS_MASK 0x00000080
+#define MCDE_MISERR_FUC0MIS(__x) \
+ MCDE_VAL2REG(MCDE_MISERR, FUC0MIS, __x)
+#define MCDE_MISERR_FUC1MIS_SHIFT 8
+#define MCDE_MISERR_FUC1MIS_MASK 0x00000100
+#define MCDE_MISERR_FUC1MIS(__x) \
+ MCDE_VAL2REG(MCDE_MISERR, FUC1MIS, __x)
+#define MCDE_MISERR_OVLFERMIS_SHIFT 16
+#define MCDE_MISERR_OVLFERMIS_MASK 0xFFFF0000
+#define MCDE_MISERR_OVLFERMIS(__x) \
+ MCDE_VAL2REG(MCDE_MISERR, OVLFERMIS, __x)
+#define MCDE_SISPP 0x00000134
+#define MCDE_SISPP_VCMPASIS_SHIFT 0
+#define MCDE_SISPP_VCMPASIS_MASK 0x00000001
+#define MCDE_SISPP_VCMPASIS(__x) \
+ MCDE_VAL2REG(MCDE_SISPP, VCMPASIS, __x)
+#define MCDE_SISPP_VCMPBSIS_SHIFT 1
+#define MCDE_SISPP_VCMPBSIS_MASK 0x00000002
+#define MCDE_SISPP_VCMPBSIS(__x) \
+ MCDE_VAL2REG(MCDE_SISPP, VCMPBSIS, __x)
+#define MCDE_SISPP_VSCC0SIS_SHIFT 2
+#define MCDE_SISPP_VSCC0SIS_MASK 0x00000004
+#define MCDE_SISPP_VSCC0SIS(__x) \
+ MCDE_VAL2REG(MCDE_SISPP, VSCC0SIS, __x)
+#define MCDE_SISPP_VSCC1SIS_SHIFT 3
+#define MCDE_SISPP_VSCC1SIS_MASK 0x00000008
+#define MCDE_SISPP_VSCC1SIS(__x) \
+ MCDE_VAL2REG(MCDE_SISPP, VSCC1SIS, __x)
+#define MCDE_SISPP_VCMPC0SIS_SHIFT 4
+#define MCDE_SISPP_VCMPC0SIS_MASK 0x00000010
+#define MCDE_SISPP_VCMPC0SIS(__x) \
+ MCDE_VAL2REG(MCDE_SISPP, VCMPC0SIS, __x)
+#define MCDE_SISPP_VCMPC1SIS_SHIFT 5
+#define MCDE_SISPP_VCMPC1SIS_MASK 0x00000020
+#define MCDE_SISPP_VCMPC1SIS(__x) \
+ MCDE_VAL2REG(MCDE_SISPP, VCMPC1SIS, __x)
+#define MCDE_SISPP_ROTFDSIS_A_SHIFT 6
+#define MCDE_SISPP_ROTFDSIS_A_MASK 0x00000040
+#define MCDE_SISPP_ROTFDSIS_A(__x) \
+ MCDE_VAL2REG(MCDE_SISPP, ROTFDSIS_A, __x)
+#define MCDE_SISPP_ROTFDSIS_B_SHIFT 7
+#define MCDE_SISPP_ROTFDSIS_B_MASK 0x00000080
+#define MCDE_SISPP_ROTFDSIS_B(__x) \
+ MCDE_VAL2REG(MCDE_SISPP, ROTFDSIS_B, __x)
+#define MCDE_SISOVL 0x00000138
+#define MCDE_SISOVL_OVLRDSIS_SHIFT 0
+#define MCDE_SISOVL_OVLRDSIS_MASK 0x0000FFFF
+#define MCDE_SISOVL_OVLRDSIS(__x) \
+ MCDE_VAL2REG(MCDE_SISOVL, OVLRDSIS, __x)
+#define MCDE_SISOVL_OVLFDSIS_SHIFT 16
+#define MCDE_SISOVL_OVLFDSIS_MASK 0xFFFF0000
+#define MCDE_SISOVL_OVLFDSIS(__x) \
+ MCDE_VAL2REG(MCDE_SISOVL, OVLFDSIS, __x)
+#define MCDE_SISCHNL 0x0000013C
+#define MCDE_SISCHNL_CHNLRDSIS_SHIFT 0
+#define MCDE_SISCHNL_CHNLRDSIS_MASK 0x0000FFFF
+#define MCDE_SISCHNL_CHNLRDSIS(__x) \
+ MCDE_VAL2REG(MCDE_SISCHNL, CHNLRDSIS, __x)
+#define MCDE_SISCHNL_CHNLASIS_SHIFT 16
+#define MCDE_SISCHNL_CHNLASIS_MASK 0xFFFF0000
+#define MCDE_SISCHNL_CHNLASIS(__x) \
+ MCDE_VAL2REG(MCDE_SISCHNL, CHNLASIS, __x)
+#define MCDE_SISERR 0x00000140
+#define MCDE_SISERR_FUASIS_SHIFT 0
+#define MCDE_SISERR_FUASIS_MASK 0x00000001
+#define MCDE_SISERR_FUASIS(__x) \
+ MCDE_VAL2REG(MCDE_SISERR, FUASIS, __x)
+#define MCDE_SISERR_FUBSIS_SHIFT 1
+#define MCDE_SISERR_FUBSIS_MASK 0x00000002
+#define MCDE_SISERR_FUBSIS(__x) \
+ MCDE_VAL2REG(MCDE_SISERR, FUBSIS, __x)
+#define MCDE_SISERR_SCHBLCKDSIS_SHIFT 2
+#define MCDE_SISERR_SCHBLCKDSIS_MASK 0x00000004
+#define MCDE_SISERR_SCHBLCKDSIS(__x) \
+ MCDE_VAL2REG(MCDE_SISERR, SCHBLCKDSIS, __x)
+#define MCDE_SISERR_ROTAFESIS_WRITE_SHIFT 3
+#define MCDE_SISERR_ROTAFESIS_WRITE_MASK 0x00000008
+#define MCDE_SISERR_ROTAFESIS_WRITE(__x) \
+ MCDE_VAL2REG(MCDE_SISERR, ROTAFESIS_WRITE, __x)
+#define MCDE_SISERR_ROTAFESIS_READ_SHIFT 4
+#define MCDE_SISERR_ROTAFESIS_READ_MASK 0x00000010
+#define MCDE_SISERR_ROTAFESIS_READ(__x) \
+ MCDE_VAL2REG(MCDE_SISERR, ROTAFESIS_READ, __x)
+#define MCDE_SISERR_ROTBFESIS_WRITE_SHIFT 5
+#define MCDE_SISERR_ROTBFESIS_WRITE_MASK 0x00000020
+#define MCDE_SISERR_ROTBFESIS_WRITE(__x) \
+ MCDE_VAL2REG(MCDE_SISERR, ROTBFESIS_WRITE, __x)
+#define MCDE_SISERR_ROTBFESIS_READ_SHIFT 6
+#define MCDE_SISERR_ROTBFESIS_READ_MASK 0x00000040
+#define MCDE_SISERR_ROTBFESIS_READ(__x) \
+ MCDE_VAL2REG(MCDE_SISERR, ROTBFESIS_READ, __x)
+#define MCDE_SISERR_FUC0SIS_SHIFT 7
+#define MCDE_SISERR_FUC0SIS_MASK 0x00000080
+#define MCDE_SISERR_FUC0SIS(__x) \
+ MCDE_VAL2REG(MCDE_SISERR, FUC0SIS, __x)
+#define MCDE_SISERR_FUC1SIS_SHIFT 8
+#define MCDE_SISERR_FUC1SIS_MASK 0x00000100
+#define MCDE_SISERR_FUC1SIS(__x) \
+ MCDE_VAL2REG(MCDE_SISERR, FUC1SIS, __x)
+#define MCDE_SISERR_OVLFERSIS_SHIFT 16
+#define MCDE_SISERR_OVLFERSIS_MASK 0xFFFF0000
+#define MCDE_SISERR_OVLFERSIS(__x) \
+ MCDE_VAL2REG(MCDE_SISERR, OVLFERSIS, __x)
+#define MCDE_PID 0x000001FC
+#define MCDE_PID_METALFIX_VERSION_SHIFT 0
+#define MCDE_PID_METALFIX_VERSION_MASK 0x000000FF
+#define MCDE_PID_METALFIX_VERSION(__x) \
+ MCDE_VAL2REG(MCDE_PID, METALFIX_VERSION, __x)
+#define MCDE_PID_DEVELOPMENT_VERSION_SHIFT 8
+#define MCDE_PID_DEVELOPMENT_VERSION_MASK 0x0000FF00
+#define MCDE_PID_DEVELOPMENT_VERSION(__x) \
+ MCDE_VAL2REG(MCDE_PID, DEVELOPMENT_VERSION, __x)
+#define MCDE_PID_MINOR_VERSION_SHIFT 16
+#define MCDE_PID_MINOR_VERSION_MASK 0x00FF0000
+#define MCDE_PID_MINOR_VERSION(__x) \
+ MCDE_VAL2REG(MCDE_PID, MINOR_VERSION, __x)
+#define MCDE_PID_MAJOR_VERSION_SHIFT 24
+#define MCDE_PID_MAJOR_VERSION_MASK 0xFF000000
+#define MCDE_PID_MAJOR_VERSION(__x) \
+ MCDE_VAL2REG(MCDE_PID, MAJOR_VERSION, __x)
+#define MCDE_EXTSRC0A0 0x00000200
+#define MCDE_EXTSRC0A0_GROUPOFFSET 0x20
+#define MCDE_EXTSRC0A0_BASEADDRESS0_SHIFT 3
+#define MCDE_EXTSRC0A0_BASEADDRESS0_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC0A0_BASEADDRESS0(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0A0, BASEADDRESS0, __x)
+#define MCDE_EXTSRC1A0 0x00000220
+#define MCDE_EXTSRC1A0_BASEADDRESS0_SHIFT 3
+#define MCDE_EXTSRC1A0_BASEADDRESS0_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC1A0_BASEADDRESS0(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1A0, BASEADDRESS0, __x)
+#define MCDE_EXTSRC2A0 0x00000240
+#define MCDE_EXTSRC2A0_BASEADDRESS0_SHIFT 3
+#define MCDE_EXTSRC2A0_BASEADDRESS0_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC2A0_BASEADDRESS0(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2A0, BASEADDRESS0, __x)
+#define MCDE_EXTSRC3A0 0x00000260
+#define MCDE_EXTSRC3A0_BASEADDRESS0_SHIFT 3
+#define MCDE_EXTSRC3A0_BASEADDRESS0_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC3A0_BASEADDRESS0(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3A0, BASEADDRESS0, __x)
+#define MCDE_EXTSRC4A0 0x00000280
+#define MCDE_EXTSRC4A0_BASEADDRESS0_SHIFT 3
+#define MCDE_EXTSRC4A0_BASEADDRESS0_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC4A0_BASEADDRESS0(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4A0, BASEADDRESS0, __x)
+#define MCDE_EXTSRC5A0 0x000002A0
+#define MCDE_EXTSRC5A0_BASEADDRESS0_SHIFT 3
+#define MCDE_EXTSRC5A0_BASEADDRESS0_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC5A0_BASEADDRESS0(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5A0, BASEADDRESS0, __x)
+#define MCDE_EXTSRC6A0 0x000002C0
+#define MCDE_EXTSRC6A0_BASEADDRESS0_SHIFT 3
+#define MCDE_EXTSRC6A0_BASEADDRESS0_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC6A0_BASEADDRESS0(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6A0, BASEADDRESS0, __x)
+#define MCDE_EXTSRC7A0 0x000002E0
+#define MCDE_EXTSRC7A0_BASEADDRESS0_SHIFT 3
+#define MCDE_EXTSRC7A0_BASEADDRESS0_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC7A0_BASEADDRESS0(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7A0, BASEADDRESS0, __x)
+#define MCDE_EXTSRC8A0 0x00000300
+#define MCDE_EXTSRC8A0_BASEADDRESS0_SHIFT 3
+#define MCDE_EXTSRC8A0_BASEADDRESS0_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC8A0_BASEADDRESS0(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8A0, BASEADDRESS0, __x)
+#define MCDE_EXTSRC9A0 0x00000320
+#define MCDE_EXTSRC9A0_BASEADDRESS0_SHIFT 3
+#define MCDE_EXTSRC9A0_BASEADDRESS0_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC9A0_BASEADDRESS0(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9A0, BASEADDRESS0, __x)
+#define MCDE_EXTSRC0A1 0x00000204
+#define MCDE_EXTSRC0A1_GROUPOFFSET 0x20
+#define MCDE_EXTSRC0A1_BASEADDRESS1_SHIFT 3
+#define MCDE_EXTSRC0A1_BASEADDRESS1_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC0A1_BASEADDRESS1(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0A1, BASEADDRESS1, __x)
+#define MCDE_EXTSRC1A1 0x00000224
+#define MCDE_EXTSRC1A1_BASEADDRESS1_SHIFT 3
+#define MCDE_EXTSRC1A1_BASEADDRESS1_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC1A1_BASEADDRESS1(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1A1, BASEADDRESS1, __x)
+#define MCDE_EXTSRC2A1 0x00000244
+#define MCDE_EXTSRC2A1_BASEADDRESS1_SHIFT 3
+#define MCDE_EXTSRC2A1_BASEADDRESS1_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC2A1_BASEADDRESS1(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2A1, BASEADDRESS1, __x)
+#define MCDE_EXTSRC3A1 0x00000264
+#define MCDE_EXTSRC3A1_BASEADDRESS1_SHIFT 3
+#define MCDE_EXTSRC3A1_BASEADDRESS1_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC3A1_BASEADDRESS1(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3A1, BASEADDRESS1, __x)
+#define MCDE_EXTSRC4A1 0x00000284
+#define MCDE_EXTSRC4A1_BASEADDRESS1_SHIFT 3
+#define MCDE_EXTSRC4A1_BASEADDRESS1_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC4A1_BASEADDRESS1(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4A1, BASEADDRESS1, __x)
+#define MCDE_EXTSRC5A1 0x000002A4
+#define MCDE_EXTSRC5A1_BASEADDRESS1_SHIFT 3
+#define MCDE_EXTSRC5A1_BASEADDRESS1_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC5A1_BASEADDRESS1(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5A1, BASEADDRESS1, __x)
+#define MCDE_EXTSRC6A1 0x000002C4
+#define MCDE_EXTSRC6A1_BASEADDRESS1_SHIFT 3
+#define MCDE_EXTSRC6A1_BASEADDRESS1_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC6A1_BASEADDRESS1(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6A1, BASEADDRESS1, __x)
+#define MCDE_EXTSRC7A1 0x000002E4
+#define MCDE_EXTSRC7A1_BASEADDRESS1_SHIFT 3
+#define MCDE_EXTSRC7A1_BASEADDRESS1_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC7A1_BASEADDRESS1(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7A1, BASEADDRESS1, __x)
+#define MCDE_EXTSRC8A1 0x00000304
+#define MCDE_EXTSRC8A1_BASEADDRESS1_SHIFT 3
+#define MCDE_EXTSRC8A1_BASEADDRESS1_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC8A1_BASEADDRESS1(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8A1, BASEADDRESS1, __x)
+#define MCDE_EXTSRC9A1 0x00000324
+#define MCDE_EXTSRC9A1_BASEADDRESS1_SHIFT 3
+#define MCDE_EXTSRC9A1_BASEADDRESS1_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC9A1_BASEADDRESS1(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9A1, BASEADDRESS1, __x)
+#define MCDE_EXTSRC6A2 0x000002C8
+#define MCDE_EXTSRC6A2_BASEADDRESS2_SHIFT 3
+#define MCDE_EXTSRC6A2_BASEADDRESS2_MASK 0xFFFFFFF8
+#define MCDE_EXTSRC6A2_BASEADDRESS2(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6A2, BASEADDRESS2, __x)
+#define MCDE_EXTSRC0CONF 0x0000020C
+#define MCDE_EXTSRC0CONF_GROUPOFFSET 0x20
+#define MCDE_EXTSRC0CONF_BUF_ID_SHIFT 0
+#define MCDE_EXTSRC0CONF_BUF_ID_MASK 0x00000003
+#define MCDE_EXTSRC0CONF_BUF_ID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CONF, BUF_ID, __x)
+#define MCDE_EXTSRC0CONF_BUF_NB_SHIFT 2
+#define MCDE_EXTSRC0CONF_BUF_NB_MASK 0x0000000C
+#define MCDE_EXTSRC0CONF_BUF_NB(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CONF, BUF_NB, __x)
+#define MCDE_EXTSRC0CONF_PRI_OVLID_SHIFT 4
+#define MCDE_EXTSRC0CONF_PRI_OVLID_MASK 0x000000F0
+#define MCDE_EXTSRC0CONF_PRI_OVLID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CONF, PRI_OVLID, __x)
+#define MCDE_EXTSRC0CONF_BPP_SHIFT 8
+#define MCDE_EXTSRC0CONF_BPP_MASK 0x00000F00
+#define MCDE_EXTSRC0CONF_BPP_1BPP_PAL 0
+#define MCDE_EXTSRC0CONF_BPP_2BPP_PAL 1
+#define MCDE_EXTSRC0CONF_BPP_4BPP_PAL 2
+#define MCDE_EXTSRC0CONF_BPP_8BPP_PAL 3
+#define MCDE_EXTSRC0CONF_BPP_RGB444 4
+#define MCDE_EXTSRC0CONF_BPP_ARGB4444 5
+#define MCDE_EXTSRC0CONF_BPP_IRGB1555 6
+#define MCDE_EXTSRC0CONF_BPP_RGB565 7
+#define MCDE_EXTSRC0CONF_BPP_RGB888 8
+#define MCDE_EXTSRC0CONF_BPP_XRGB8888 9
+#define MCDE_EXTSRC0CONF_BPP_ARGB8888 10
+#define MCDE_EXTSRC0CONF_BPP_YCBCR422 11
+#define MCDE_EXTSRC0CONF_BPP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CONF, BPP, MCDE_EXTSRC0CONF_BPP_##__x)
+#define MCDE_EXTSRC0CONF_BPP(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CONF, BPP, __x)
+#define MCDE_EXTSRC0CONF_BGR_SHIFT 12
+#define MCDE_EXTSRC0CONF_BGR_MASK 0x00001000
+#define MCDE_EXTSRC0CONF_BGR_RGB 0
+#define MCDE_EXTSRC0CONF_BGR_BGR 1
+#define MCDE_EXTSRC0CONF_BGR_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CONF, BGR, MCDE_EXTSRC0CONF_BGR_##__x)
+#define MCDE_EXTSRC0CONF_BGR(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CONF, BGR, __x)
+#define MCDE_EXTSRC0CONF_BEBO_SHIFT 13
+#define MCDE_EXTSRC0CONF_BEBO_MASK 0x00002000
+#define MCDE_EXTSRC0CONF_BEBO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC0CONF_BEBO_BIG_ENDIAN 1
+#define MCDE_EXTSRC0CONF_BEBO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CONF, BEBO, MCDE_EXTSRC0CONF_BEBO_##__x)
+#define MCDE_EXTSRC0CONF_BEBO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CONF, BEBO, __x)
+#define MCDE_EXTSRC0CONF_BEPO_SHIFT 14
+#define MCDE_EXTSRC0CONF_BEPO_MASK 0x00004000
+#define MCDE_EXTSRC0CONF_BEPO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC0CONF_BEPO_BIG_ENDIAN 1
+#define MCDE_EXTSRC0CONF_BEPO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CONF, BEPO, MCDE_EXTSRC0CONF_BEPO_##__x)
+#define MCDE_EXTSRC0CONF_BEPO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CONF, BEPO, __x)
+#define MCDE_EXTSRC1CONF 0x0000022C
+#define MCDE_EXTSRC1CONF_BUF_ID_SHIFT 0
+#define MCDE_EXTSRC1CONF_BUF_ID_MASK 0x00000003
+#define MCDE_EXTSRC1CONF_BUF_ID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CONF, BUF_ID, __x)
+#define MCDE_EXTSRC1CONF_BUF_NB_SHIFT 2
+#define MCDE_EXTSRC1CONF_BUF_NB_MASK 0x0000000C
+#define MCDE_EXTSRC1CONF_BUF_NB(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CONF, BUF_NB, __x)
+#define MCDE_EXTSRC1CONF_PRI_OVLID_SHIFT 4
+#define MCDE_EXTSRC1CONF_PRI_OVLID_MASK 0x000000F0
+#define MCDE_EXTSRC1CONF_PRI_OVLID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CONF, PRI_OVLID, __x)
+#define MCDE_EXTSRC1CONF_BPP_SHIFT 8
+#define MCDE_EXTSRC1CONF_BPP_MASK 0x00000F00
+#define MCDE_EXTSRC1CONF_BPP_1BPP_PAL 0
+#define MCDE_EXTSRC1CONF_BPP_2BPP_PAL 1
+#define MCDE_EXTSRC1CONF_BPP_4BPP_PAL 2
+#define MCDE_EXTSRC1CONF_BPP_8BPP_PAL 3
+#define MCDE_EXTSRC1CONF_BPP_RGB444 4
+#define MCDE_EXTSRC1CONF_BPP_ARGB4444 5
+#define MCDE_EXTSRC1CONF_BPP_IRGB1555 6
+#define MCDE_EXTSRC1CONF_BPP_RGB565 7
+#define MCDE_EXTSRC1CONF_BPP_RGB888 8
+#define MCDE_EXTSRC1CONF_BPP_XRGB8888 9
+#define MCDE_EXTSRC1CONF_BPP_ARGB8888 10
+#define MCDE_EXTSRC1CONF_BPP_YCBCR422 11
+#define MCDE_EXTSRC1CONF_BPP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CONF, BPP, MCDE_EXTSRC1CONF_BPP_##__x)
+#define MCDE_EXTSRC1CONF_BPP(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CONF, BPP, __x)
+#define MCDE_EXTSRC1CONF_BGR_SHIFT 12
+#define MCDE_EXTSRC1CONF_BGR_MASK 0x00001000
+#define MCDE_EXTSRC1CONF_BGR_RGB 0
+#define MCDE_EXTSRC1CONF_BGR_BGR 1
+#define MCDE_EXTSRC1CONF_BGR_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CONF, BGR, MCDE_EXTSRC1CONF_BGR_##__x)
+#define MCDE_EXTSRC1CONF_BGR(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CONF, BGR, __x)
+#define MCDE_EXTSRC1CONF_BEBO_SHIFT 13
+#define MCDE_EXTSRC1CONF_BEBO_MASK 0x00002000
+#define MCDE_EXTSRC1CONF_BEBO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC1CONF_BEBO_BIG_ENDIAN 1
+#define MCDE_EXTSRC1CONF_BEBO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CONF, BEBO, MCDE_EXTSRC1CONF_BEBO_##__x)
+#define MCDE_EXTSRC1CONF_BEBO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CONF, BEBO, __x)
+#define MCDE_EXTSRC1CONF_BEPO_SHIFT 14
+#define MCDE_EXTSRC1CONF_BEPO_MASK 0x00004000
+#define MCDE_EXTSRC1CONF_BEPO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC1CONF_BEPO_BIG_ENDIAN 1
+#define MCDE_EXTSRC1CONF_BEPO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CONF, BEPO, MCDE_EXTSRC1CONF_BEPO_##__x)
+#define MCDE_EXTSRC1CONF_BEPO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CONF, BEPO, __x)
+#define MCDE_EXTSRC2CONF 0x0000024C
+#define MCDE_EXTSRC2CONF_BUF_ID_SHIFT 0
+#define MCDE_EXTSRC2CONF_BUF_ID_MASK 0x00000003
+#define MCDE_EXTSRC2CONF_BUF_ID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CONF, BUF_ID, __x)
+#define MCDE_EXTSRC2CONF_BUF_NB_SHIFT 2
+#define MCDE_EXTSRC2CONF_BUF_NB_MASK 0x0000000C
+#define MCDE_EXTSRC2CONF_BUF_NB(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CONF, BUF_NB, __x)
+#define MCDE_EXTSRC2CONF_PRI_OVLID_SHIFT 4
+#define MCDE_EXTSRC2CONF_PRI_OVLID_MASK 0x000000F0
+#define MCDE_EXTSRC2CONF_PRI_OVLID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CONF, PRI_OVLID, __x)
+#define MCDE_EXTSRC2CONF_BPP_SHIFT 8
+#define MCDE_EXTSRC2CONF_BPP_MASK 0x00000F00
+#define MCDE_EXTSRC2CONF_BPP_1BPP_PAL 0
+#define MCDE_EXTSRC2CONF_BPP_2BPP_PAL 1
+#define MCDE_EXTSRC2CONF_BPP_4BPP_PAL 2
+#define MCDE_EXTSRC2CONF_BPP_8BPP_PAL 3
+#define MCDE_EXTSRC2CONF_BPP_RGB444 4
+#define MCDE_EXTSRC2CONF_BPP_ARGB4444 5
+#define MCDE_EXTSRC2CONF_BPP_IRGB1555 6
+#define MCDE_EXTSRC2CONF_BPP_RGB565 7
+#define MCDE_EXTSRC2CONF_BPP_RGB888 8
+#define MCDE_EXTSRC2CONF_BPP_XRGB8888 9
+#define MCDE_EXTSRC2CONF_BPP_ARGB8888 10
+#define MCDE_EXTSRC2CONF_BPP_YCBCR422 11
+#define MCDE_EXTSRC2CONF_BPP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CONF, BPP, MCDE_EXTSRC2CONF_BPP_##__x)
+#define MCDE_EXTSRC2CONF_BPP(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CONF, BPP, __x)
+#define MCDE_EXTSRC2CONF_BGR_SHIFT 12
+#define MCDE_EXTSRC2CONF_BGR_MASK 0x00001000
+#define MCDE_EXTSRC2CONF_BGR_RGB 0
+#define MCDE_EXTSRC2CONF_BGR_BGR 1
+#define MCDE_EXTSRC2CONF_BGR_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CONF, BGR, MCDE_EXTSRC2CONF_BGR_##__x)
+#define MCDE_EXTSRC2CONF_BGR(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CONF, BGR, __x)
+#define MCDE_EXTSRC2CONF_BEBO_SHIFT 13
+#define MCDE_EXTSRC2CONF_BEBO_MASK 0x00002000
+#define MCDE_EXTSRC2CONF_BEBO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC2CONF_BEBO_BIG_ENDIAN 1
+#define MCDE_EXTSRC2CONF_BEBO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CONF, BEBO, MCDE_EXTSRC2CONF_BEBO_##__x)
+#define MCDE_EXTSRC2CONF_BEBO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CONF, BEBO, __x)
+#define MCDE_EXTSRC2CONF_BEPO_SHIFT 14
+#define MCDE_EXTSRC2CONF_BEPO_MASK 0x00004000
+#define MCDE_EXTSRC2CONF_BEPO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC2CONF_BEPO_BIG_ENDIAN 1
+#define MCDE_EXTSRC2CONF_BEPO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CONF, BEPO, MCDE_EXTSRC2CONF_BEPO_##__x)
+#define MCDE_EXTSRC2CONF_BEPO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CONF, BEPO, __x)
+#define MCDE_EXTSRC3CONF 0x0000026C
+#define MCDE_EXTSRC3CONF_BUF_ID_SHIFT 0
+#define MCDE_EXTSRC3CONF_BUF_ID_MASK 0x00000003
+#define MCDE_EXTSRC3CONF_BUF_ID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CONF, BUF_ID, __x)
+#define MCDE_EXTSRC3CONF_BUF_NB_SHIFT 2
+#define MCDE_EXTSRC3CONF_BUF_NB_MASK 0x0000000C
+#define MCDE_EXTSRC3CONF_BUF_NB(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CONF, BUF_NB, __x)
+#define MCDE_EXTSRC3CONF_PRI_OVLID_SHIFT 4
+#define MCDE_EXTSRC3CONF_PRI_OVLID_MASK 0x000000F0
+#define MCDE_EXTSRC3CONF_PRI_OVLID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CONF, PRI_OVLID, __x)
+#define MCDE_EXTSRC3CONF_BPP_SHIFT 8
+#define MCDE_EXTSRC3CONF_BPP_MASK 0x00000F00
+#define MCDE_EXTSRC3CONF_BPP_1BPP_PAL 0
+#define MCDE_EXTSRC3CONF_BPP_2BPP_PAL 1
+#define MCDE_EXTSRC3CONF_BPP_4BPP_PAL 2
+#define MCDE_EXTSRC3CONF_BPP_8BPP_PAL 3
+#define MCDE_EXTSRC3CONF_BPP_RGB444 4
+#define MCDE_EXTSRC3CONF_BPP_ARGB4444 5
+#define MCDE_EXTSRC3CONF_BPP_IRGB1555 6
+#define MCDE_EXTSRC3CONF_BPP_RGB565 7
+#define MCDE_EXTSRC3CONF_BPP_RGB888 8
+#define MCDE_EXTSRC3CONF_BPP_XRGB8888 9
+#define MCDE_EXTSRC3CONF_BPP_ARGB8888 10
+#define MCDE_EXTSRC3CONF_BPP_YCBCR422 11
+#define MCDE_EXTSRC3CONF_BPP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CONF, BPP, MCDE_EXTSRC3CONF_BPP_##__x)
+#define MCDE_EXTSRC3CONF_BPP(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CONF, BPP, __x)
+#define MCDE_EXTSRC3CONF_BGR_SHIFT 12
+#define MCDE_EXTSRC3CONF_BGR_MASK 0x00001000
+#define MCDE_EXTSRC3CONF_BGR_RGB 0
+#define MCDE_EXTSRC3CONF_BGR_BGR 1
+#define MCDE_EXTSRC3CONF_BGR_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CONF, BGR, MCDE_EXTSRC3CONF_BGR_##__x)
+#define MCDE_EXTSRC3CONF_BGR(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CONF, BGR, __x)
+#define MCDE_EXTSRC3CONF_BEBO_SHIFT 13
+#define MCDE_EXTSRC3CONF_BEBO_MASK 0x00002000
+#define MCDE_EXTSRC3CONF_BEBO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC3CONF_BEBO_BIG_ENDIAN 1
+#define MCDE_EXTSRC3CONF_BEBO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CONF, BEBO, MCDE_EXTSRC3CONF_BEBO_##__x)
+#define MCDE_EXTSRC3CONF_BEBO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CONF, BEBO, __x)
+#define MCDE_EXTSRC3CONF_BEPO_SHIFT 14
+#define MCDE_EXTSRC3CONF_BEPO_MASK 0x00004000
+#define MCDE_EXTSRC3CONF_BEPO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC3CONF_BEPO_BIG_ENDIAN 1
+#define MCDE_EXTSRC3CONF_BEPO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CONF, BEPO, MCDE_EXTSRC3CONF_BEPO_##__x)
+#define MCDE_EXTSRC3CONF_BEPO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CONF, BEPO, __x)
+#define MCDE_EXTSRC4CONF 0x0000028C
+#define MCDE_EXTSRC4CONF_BUF_ID_SHIFT 0
+#define MCDE_EXTSRC4CONF_BUF_ID_MASK 0x00000003
+#define MCDE_EXTSRC4CONF_BUF_ID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CONF, BUF_ID, __x)
+#define MCDE_EXTSRC4CONF_BUF_NB_SHIFT 2
+#define MCDE_EXTSRC4CONF_BUF_NB_MASK 0x0000000C
+#define MCDE_EXTSRC4CONF_BUF_NB(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CONF, BUF_NB, __x)
+#define MCDE_EXTSRC4CONF_PRI_OVLID_SHIFT 4
+#define MCDE_EXTSRC4CONF_PRI_OVLID_MASK 0x000000F0
+#define MCDE_EXTSRC4CONF_PRI_OVLID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CONF, PRI_OVLID, __x)
+#define MCDE_EXTSRC4CONF_BPP_SHIFT 8
+#define MCDE_EXTSRC4CONF_BPP_MASK 0x00000F00
+#define MCDE_EXTSRC4CONF_BPP_1BPP_PAL 0
+#define MCDE_EXTSRC4CONF_BPP_2BPP_PAL 1
+#define MCDE_EXTSRC4CONF_BPP_4BPP_PAL 2
+#define MCDE_EXTSRC4CONF_BPP_8BPP_PAL 3
+#define MCDE_EXTSRC4CONF_BPP_RGB444 4
+#define MCDE_EXTSRC4CONF_BPP_ARGB4444 5
+#define MCDE_EXTSRC4CONF_BPP_IRGB1555 6
+#define MCDE_EXTSRC4CONF_BPP_RGB565 7
+#define MCDE_EXTSRC4CONF_BPP_RGB888 8
+#define MCDE_EXTSRC4CONF_BPP_XRGB8888 9
+#define MCDE_EXTSRC4CONF_BPP_ARGB8888 10
+#define MCDE_EXTSRC4CONF_BPP_YCBCR422 11
+#define MCDE_EXTSRC4CONF_BPP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CONF, BPP, MCDE_EXTSRC4CONF_BPP_##__x)
+#define MCDE_EXTSRC4CONF_BPP(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CONF, BPP, __x)
+#define MCDE_EXTSRC4CONF_BGR_SHIFT 12
+#define MCDE_EXTSRC4CONF_BGR_MASK 0x00001000
+#define MCDE_EXTSRC4CONF_BGR_RGB 0
+#define MCDE_EXTSRC4CONF_BGR_BGR 1
+#define MCDE_EXTSRC4CONF_BGR_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CONF, BGR, MCDE_EXTSRC4CONF_BGR_##__x)
+#define MCDE_EXTSRC4CONF_BGR(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CONF, BGR, __x)
+#define MCDE_EXTSRC4CONF_BEBO_SHIFT 13
+#define MCDE_EXTSRC4CONF_BEBO_MASK 0x00002000
+#define MCDE_EXTSRC4CONF_BEBO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC4CONF_BEBO_BIG_ENDIAN 1
+#define MCDE_EXTSRC4CONF_BEBO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CONF, BEBO, MCDE_EXTSRC4CONF_BEBO_##__x)
+#define MCDE_EXTSRC4CONF_BEBO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CONF, BEBO, __x)
+#define MCDE_EXTSRC4CONF_BEPO_SHIFT 14
+#define MCDE_EXTSRC4CONF_BEPO_MASK 0x00004000
+#define MCDE_EXTSRC4CONF_BEPO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC4CONF_BEPO_BIG_ENDIAN 1
+#define MCDE_EXTSRC4CONF_BEPO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CONF, BEPO, MCDE_EXTSRC4CONF_BEPO_##__x)
+#define MCDE_EXTSRC4CONF_BEPO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CONF, BEPO, __x)
+#define MCDE_EXTSRC5CONF 0x000002AC
+#define MCDE_EXTSRC5CONF_BUF_ID_SHIFT 0
+#define MCDE_EXTSRC5CONF_BUF_ID_MASK 0x00000003
+#define MCDE_EXTSRC5CONF_BUF_ID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CONF, BUF_ID, __x)
+#define MCDE_EXTSRC5CONF_BUF_NB_SHIFT 2
+#define MCDE_EXTSRC5CONF_BUF_NB_MASK 0x0000000C
+#define MCDE_EXTSRC5CONF_BUF_NB(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CONF, BUF_NB, __x)
+#define MCDE_EXTSRC5CONF_PRI_OVLID_SHIFT 4
+#define MCDE_EXTSRC5CONF_PRI_OVLID_MASK 0x000000F0
+#define MCDE_EXTSRC5CONF_PRI_OVLID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CONF, PRI_OVLID, __x)
+#define MCDE_EXTSRC5CONF_BPP_SHIFT 8
+#define MCDE_EXTSRC5CONF_BPP_MASK 0x00000F00
+#define MCDE_EXTSRC5CONF_BPP_1BPP_PAL 0
+#define MCDE_EXTSRC5CONF_BPP_2BPP_PAL 1
+#define MCDE_EXTSRC5CONF_BPP_4BPP_PAL 2
+#define MCDE_EXTSRC5CONF_BPP_8BPP_PAL 3
+#define MCDE_EXTSRC5CONF_BPP_RGB444 4
+#define MCDE_EXTSRC5CONF_BPP_ARGB4444 5
+#define MCDE_EXTSRC5CONF_BPP_IRGB1555 6
+#define MCDE_EXTSRC5CONF_BPP_RGB565 7
+#define MCDE_EXTSRC5CONF_BPP_RGB888 8
+#define MCDE_EXTSRC5CONF_BPP_XRGB8888 9
+#define MCDE_EXTSRC5CONF_BPP_ARGB8888 10
+#define MCDE_EXTSRC5CONF_BPP_YCBCR422 11
+#define MCDE_EXTSRC5CONF_BPP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CONF, BPP, MCDE_EXTSRC5CONF_BPP_##__x)
+#define MCDE_EXTSRC5CONF_BPP(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CONF, BPP, __x)
+#define MCDE_EXTSRC5CONF_BGR_SHIFT 12
+#define MCDE_EXTSRC5CONF_BGR_MASK 0x00001000
+#define MCDE_EXTSRC5CONF_BGR_RGB 0
+#define MCDE_EXTSRC5CONF_BGR_BGR 1
+#define MCDE_EXTSRC5CONF_BGR_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CONF, BGR, MCDE_EXTSRC5CONF_BGR_##__x)
+#define MCDE_EXTSRC5CONF_BGR(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CONF, BGR, __x)
+#define MCDE_EXTSRC5CONF_BEBO_SHIFT 13
+#define MCDE_EXTSRC5CONF_BEBO_MASK 0x00002000
+#define MCDE_EXTSRC5CONF_BEBO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC5CONF_BEBO_BIG_ENDIAN 1
+#define MCDE_EXTSRC5CONF_BEBO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CONF, BEBO, MCDE_EXTSRC5CONF_BEBO_##__x)
+#define MCDE_EXTSRC5CONF_BEBO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CONF, BEBO, __x)
+#define MCDE_EXTSRC5CONF_BEPO_SHIFT 14
+#define MCDE_EXTSRC5CONF_BEPO_MASK 0x00004000
+#define MCDE_EXTSRC5CONF_BEPO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC5CONF_BEPO_BIG_ENDIAN 1
+#define MCDE_EXTSRC5CONF_BEPO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CONF, BEPO, MCDE_EXTSRC5CONF_BEPO_##__x)
+#define MCDE_EXTSRC5CONF_BEPO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CONF, BEPO, __x)
+#define MCDE_EXTSRC6CONF 0x000002CC
+#define MCDE_EXTSRC6CONF_BUF_ID_SHIFT 0
+#define MCDE_EXTSRC6CONF_BUF_ID_MASK 0x00000003
+#define MCDE_EXTSRC6CONF_BUF_ID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CONF, BUF_ID, __x)
+#define MCDE_EXTSRC6CONF_BUF_NB_SHIFT 2
+#define MCDE_EXTSRC6CONF_BUF_NB_MASK 0x0000000C
+#define MCDE_EXTSRC6CONF_BUF_NB(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CONF, BUF_NB, __x)
+#define MCDE_EXTSRC6CONF_PRI_OVLID_SHIFT 4
+#define MCDE_EXTSRC6CONF_PRI_OVLID_MASK 0x000000F0
+#define MCDE_EXTSRC6CONF_PRI_OVLID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CONF, PRI_OVLID, __x)
+#define MCDE_EXTSRC6CONF_BPP_SHIFT 8
+#define MCDE_EXTSRC6CONF_BPP_MASK 0x00000F00
+#define MCDE_EXTSRC6CONF_BPP_1BPP_PAL 0
+#define MCDE_EXTSRC6CONF_BPP_2BPP_PAL 1
+#define MCDE_EXTSRC6CONF_BPP_4BPP_PAL 2
+#define MCDE_EXTSRC6CONF_BPP_8BPP_PAL 3
+#define MCDE_EXTSRC6CONF_BPP_RGB444 4
+#define MCDE_EXTSRC6CONF_BPP_ARGB4444 5
+#define MCDE_EXTSRC6CONF_BPP_IRGB1555 6
+#define MCDE_EXTSRC6CONF_BPP_RGB565 7
+#define MCDE_EXTSRC6CONF_BPP_RGB888 8
+#define MCDE_EXTSRC6CONF_BPP_XRGB8888 9
+#define MCDE_EXTSRC6CONF_BPP_ARGB8888 10
+#define MCDE_EXTSRC6CONF_BPP_YCBCR422 11
+#define MCDE_EXTSRC6CONF_BPP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CONF, BPP, MCDE_EXTSRC6CONF_BPP_##__x)
+#define MCDE_EXTSRC6CONF_BPP(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CONF, BPP, __x)
+#define MCDE_EXTSRC6CONF_BGR_SHIFT 12
+#define MCDE_EXTSRC6CONF_BGR_MASK 0x00001000
+#define MCDE_EXTSRC6CONF_BGR_RGB 0
+#define MCDE_EXTSRC6CONF_BGR_BGR 1
+#define MCDE_EXTSRC6CONF_BGR_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CONF, BGR, MCDE_EXTSRC6CONF_BGR_##__x)
+#define MCDE_EXTSRC6CONF_BGR(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CONF, BGR, __x)
+#define MCDE_EXTSRC6CONF_BEBO_SHIFT 13
+#define MCDE_EXTSRC6CONF_BEBO_MASK 0x00002000
+#define MCDE_EXTSRC6CONF_BEBO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC6CONF_BEBO_BIG_ENDIAN 1
+#define MCDE_EXTSRC6CONF_BEBO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CONF, BEBO, MCDE_EXTSRC6CONF_BEBO_##__x)
+#define MCDE_EXTSRC6CONF_BEBO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CONF, BEBO, __x)
+#define MCDE_EXTSRC6CONF_BEPO_SHIFT 14
+#define MCDE_EXTSRC6CONF_BEPO_MASK 0x00004000
+#define MCDE_EXTSRC6CONF_BEPO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC6CONF_BEPO_BIG_ENDIAN 1
+#define MCDE_EXTSRC6CONF_BEPO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CONF, BEPO, MCDE_EXTSRC6CONF_BEPO_##__x)
+#define MCDE_EXTSRC6CONF_BEPO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CONF, BEPO, __x)
+#define MCDE_EXTSRC7CONF 0x000002EC
+#define MCDE_EXTSRC7CONF_BUF_ID_SHIFT 0
+#define MCDE_EXTSRC7CONF_BUF_ID_MASK 0x00000003
+#define MCDE_EXTSRC7CONF_BUF_ID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CONF, BUF_ID, __x)
+#define MCDE_EXTSRC7CONF_BUF_NB_SHIFT 2
+#define MCDE_EXTSRC7CONF_BUF_NB_MASK 0x0000000C
+#define MCDE_EXTSRC7CONF_BUF_NB(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CONF, BUF_NB, __x)
+#define MCDE_EXTSRC7CONF_PRI_OVLID_SHIFT 4
+#define MCDE_EXTSRC7CONF_PRI_OVLID_MASK 0x000000F0
+#define MCDE_EXTSRC7CONF_PRI_OVLID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CONF, PRI_OVLID, __x)
+#define MCDE_EXTSRC7CONF_BPP_SHIFT 8
+#define MCDE_EXTSRC7CONF_BPP_MASK 0x00000F00
+#define MCDE_EXTSRC7CONF_BPP_1BPP_PAL 0
+#define MCDE_EXTSRC7CONF_BPP_2BPP_PAL 1
+#define MCDE_EXTSRC7CONF_BPP_4BPP_PAL 2
+#define MCDE_EXTSRC7CONF_BPP_8BPP_PAL 3
+#define MCDE_EXTSRC7CONF_BPP_RGB444 4
+#define MCDE_EXTSRC7CONF_BPP_ARGB4444 5
+#define MCDE_EXTSRC7CONF_BPP_IRGB1555 6
+#define MCDE_EXTSRC7CONF_BPP_RGB565 7
+#define MCDE_EXTSRC7CONF_BPP_RGB888 8
+#define MCDE_EXTSRC7CONF_BPP_XRGB8888 9
+#define MCDE_EXTSRC7CONF_BPP_ARGB8888 10
+#define MCDE_EXTSRC7CONF_BPP_YCBCR422 11
+#define MCDE_EXTSRC7CONF_BPP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CONF, BPP, MCDE_EXTSRC7CONF_BPP_##__x)
+#define MCDE_EXTSRC7CONF_BPP(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CONF, BPP, __x)
+#define MCDE_EXTSRC7CONF_BGR_SHIFT 12
+#define MCDE_EXTSRC7CONF_BGR_MASK 0x00001000
+#define MCDE_EXTSRC7CONF_BGR_RGB 0
+#define MCDE_EXTSRC7CONF_BGR_BGR 1
+#define MCDE_EXTSRC7CONF_BGR_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CONF, BGR, MCDE_EXTSRC7CONF_BGR_##__x)
+#define MCDE_EXTSRC7CONF_BGR(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CONF, BGR, __x)
+#define MCDE_EXTSRC7CONF_BEBO_SHIFT 13
+#define MCDE_EXTSRC7CONF_BEBO_MASK 0x00002000
+#define MCDE_EXTSRC7CONF_BEBO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC7CONF_BEBO_BIG_ENDIAN 1
+#define MCDE_EXTSRC7CONF_BEBO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CONF, BEBO, MCDE_EXTSRC7CONF_BEBO_##__x)
+#define MCDE_EXTSRC7CONF_BEBO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CONF, BEBO, __x)
+#define MCDE_EXTSRC7CONF_BEPO_SHIFT 14
+#define MCDE_EXTSRC7CONF_BEPO_MASK 0x00004000
+#define MCDE_EXTSRC7CONF_BEPO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC7CONF_BEPO_BIG_ENDIAN 1
+#define MCDE_EXTSRC7CONF_BEPO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CONF, BEPO, MCDE_EXTSRC7CONF_BEPO_##__x)
+#define MCDE_EXTSRC7CONF_BEPO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CONF, BEPO, __x)
+#define MCDE_EXTSRC8CONF 0x0000030C
+#define MCDE_EXTSRC8CONF_BUF_ID_SHIFT 0
+#define MCDE_EXTSRC8CONF_BUF_ID_MASK 0x00000003
+#define MCDE_EXTSRC8CONF_BUF_ID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CONF, BUF_ID, __x)
+#define MCDE_EXTSRC8CONF_BUF_NB_SHIFT 2
+#define MCDE_EXTSRC8CONF_BUF_NB_MASK 0x0000000C
+#define MCDE_EXTSRC8CONF_BUF_NB(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CONF, BUF_NB, __x)
+#define MCDE_EXTSRC8CONF_PRI_OVLID_SHIFT 4
+#define MCDE_EXTSRC8CONF_PRI_OVLID_MASK 0x000000F0
+#define MCDE_EXTSRC8CONF_PRI_OVLID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CONF, PRI_OVLID, __x)
+#define MCDE_EXTSRC8CONF_BPP_SHIFT 8
+#define MCDE_EXTSRC8CONF_BPP_MASK 0x00000F00
+#define MCDE_EXTSRC8CONF_BPP_1BPP_PAL 0
+#define MCDE_EXTSRC8CONF_BPP_2BPP_PAL 1
+#define MCDE_EXTSRC8CONF_BPP_4BPP_PAL 2
+#define MCDE_EXTSRC8CONF_BPP_8BPP_PAL 3
+#define MCDE_EXTSRC8CONF_BPP_RGB444 4
+#define MCDE_EXTSRC8CONF_BPP_ARGB4444 5
+#define MCDE_EXTSRC8CONF_BPP_IRGB1555 6
+#define MCDE_EXTSRC8CONF_BPP_RGB565 7
+#define MCDE_EXTSRC8CONF_BPP_RGB888 8
+#define MCDE_EXTSRC8CONF_BPP_XRGB8888 9
+#define MCDE_EXTSRC8CONF_BPP_ARGB8888 10
+#define MCDE_EXTSRC8CONF_BPP_YCBCR422 11
+#define MCDE_EXTSRC8CONF_BPP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CONF, BPP, MCDE_EXTSRC8CONF_BPP_##__x)
+#define MCDE_EXTSRC8CONF_BPP(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CONF, BPP, __x)
+#define MCDE_EXTSRC8CONF_BGR_SHIFT 12
+#define MCDE_EXTSRC8CONF_BGR_MASK 0x00001000
+#define MCDE_EXTSRC8CONF_BGR_RGB 0
+#define MCDE_EXTSRC8CONF_BGR_BGR 1
+#define MCDE_EXTSRC8CONF_BGR_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CONF, BGR, MCDE_EXTSRC8CONF_BGR_##__x)
+#define MCDE_EXTSRC8CONF_BGR(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CONF, BGR, __x)
+#define MCDE_EXTSRC8CONF_BEBO_SHIFT 13
+#define MCDE_EXTSRC8CONF_BEBO_MASK 0x00002000
+#define MCDE_EXTSRC8CONF_BEBO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC8CONF_BEBO_BIG_ENDIAN 1
+#define MCDE_EXTSRC8CONF_BEBO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CONF, BEBO, MCDE_EXTSRC8CONF_BEBO_##__x)
+#define MCDE_EXTSRC8CONF_BEBO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CONF, BEBO, __x)
+#define MCDE_EXTSRC8CONF_BEPO_SHIFT 14
+#define MCDE_EXTSRC8CONF_BEPO_MASK 0x00004000
+#define MCDE_EXTSRC8CONF_BEPO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC8CONF_BEPO_BIG_ENDIAN 1
+#define MCDE_EXTSRC8CONF_BEPO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CONF, BEPO, MCDE_EXTSRC8CONF_BEPO_##__x)
+#define MCDE_EXTSRC8CONF_BEPO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CONF, BEPO, __x)
+#define MCDE_EXTSRC9CONF 0x0000032C
+#define MCDE_EXTSRC9CONF_BUF_ID_SHIFT 0
+#define MCDE_EXTSRC9CONF_BUF_ID_MASK 0x00000003
+#define MCDE_EXTSRC9CONF_BUF_ID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CONF, BUF_ID, __x)
+#define MCDE_EXTSRC9CONF_BUF_NB_SHIFT 2
+#define MCDE_EXTSRC9CONF_BUF_NB_MASK 0x0000000C
+#define MCDE_EXTSRC9CONF_BUF_NB(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CONF, BUF_NB, __x)
+#define MCDE_EXTSRC9CONF_PRI_OVLID_SHIFT 4
+#define MCDE_EXTSRC9CONF_PRI_OVLID_MASK 0x000000F0
+#define MCDE_EXTSRC9CONF_PRI_OVLID(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CONF, PRI_OVLID, __x)
+#define MCDE_EXTSRC9CONF_BPP_SHIFT 8
+#define MCDE_EXTSRC9CONF_BPP_MASK 0x00000F00
+#define MCDE_EXTSRC9CONF_BPP_1BPP_PAL 0
+#define MCDE_EXTSRC9CONF_BPP_2BPP_PAL 1
+#define MCDE_EXTSRC9CONF_BPP_4BPP_PAL 2
+#define MCDE_EXTSRC9CONF_BPP_8BPP_PAL 3
+#define MCDE_EXTSRC9CONF_BPP_RGB444 4
+#define MCDE_EXTSRC9CONF_BPP_ARGB4444 5
+#define MCDE_EXTSRC9CONF_BPP_IRGB1555 6
+#define MCDE_EXTSRC9CONF_BPP_RGB565 7
+#define MCDE_EXTSRC9CONF_BPP_RGB888 8
+#define MCDE_EXTSRC9CONF_BPP_XRGB8888 9
+#define MCDE_EXTSRC9CONF_BPP_ARGB8888 10
+#define MCDE_EXTSRC9CONF_BPP_YCBCR422 11
+#define MCDE_EXTSRC9CONF_BPP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CONF, BPP, MCDE_EXTSRC9CONF_BPP_##__x)
+#define MCDE_EXTSRC9CONF_BPP(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CONF, BPP, __x)
+#define MCDE_EXTSRC9CONF_BGR_SHIFT 12
+#define MCDE_EXTSRC9CONF_BGR_MASK 0x00001000
+#define MCDE_EXTSRC9CONF_BGR_RGB 0
+#define MCDE_EXTSRC9CONF_BGR_BGR 1
+#define MCDE_EXTSRC9CONF_BGR_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CONF, BGR, MCDE_EXTSRC9CONF_BGR_##__x)
+#define MCDE_EXTSRC9CONF_BGR(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CONF, BGR, __x)
+#define MCDE_EXTSRC9CONF_BEBO_SHIFT 13
+#define MCDE_EXTSRC9CONF_BEBO_MASK 0x00002000
+#define MCDE_EXTSRC9CONF_BEBO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC9CONF_BEBO_BIG_ENDIAN 1
+#define MCDE_EXTSRC9CONF_BEBO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CONF, BEBO, MCDE_EXTSRC9CONF_BEBO_##__x)
+#define MCDE_EXTSRC9CONF_BEBO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CONF, BEBO, __x)
+#define MCDE_EXTSRC9CONF_BEPO_SHIFT 14
+#define MCDE_EXTSRC9CONF_BEPO_MASK 0x00004000
+#define MCDE_EXTSRC9CONF_BEPO_LITTLE_ENDIAN 0
+#define MCDE_EXTSRC9CONF_BEPO_BIG_ENDIAN 1
+#define MCDE_EXTSRC9CONF_BEPO_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CONF, BEPO, MCDE_EXTSRC9CONF_BEPO_##__x)
+#define MCDE_EXTSRC9CONF_BEPO(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CONF, BEPO, __x)
+#define MCDE_EXTSRC0CR 0x00000210
+#define MCDE_EXTSRC0CR_GROUPOFFSET 0x20
+#define MCDE_EXTSRC0CR_SEL_MOD_SHIFT 0
+#define MCDE_EXTSRC0CR_SEL_MOD_MASK 0x00000003
+#define MCDE_EXTSRC0CR_SEL_MOD_EXTERNAL_SEL 0
+#define MCDE_EXTSRC0CR_SEL_MOD_AUTO_TOGGLE 1
+#define MCDE_EXTSRC0CR_SEL_MOD_SOFTWARE_SEL 2
+#define MCDE_EXTSRC0CR_SEL_MOD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CR, SEL_MOD, MCDE_EXTSRC0CR_SEL_MOD_##__x)
+#define MCDE_EXTSRC0CR_SEL_MOD(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CR, SEL_MOD, __x)
+#define MCDE_EXTSRC0CR_MULTIOVL_CTRL_SHIFT 2
+#define MCDE_EXTSRC0CR_MULTIOVL_CTRL_MASK 0x00000004
+#define MCDE_EXTSRC0CR_MULTIOVL_CTRL_ALL 0
+#define MCDE_EXTSRC0CR_MULTIOVL_CTRL_PRIMARY 1
+#define MCDE_EXTSRC0CR_MULTIOVL_CTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CR, MULTIOVL_CTRL, \
+ MCDE_EXTSRC0CR_MULTIOVL_CTRL_##__x)
+#define MCDE_EXTSRC0CR_MULTIOVL_CTRL(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CR, MULTIOVL_CTRL, __x)
+#define MCDE_EXTSRC0CR_FS_DIV_DISABLE_SHIFT 3
+#define MCDE_EXTSRC0CR_FS_DIV_DISABLE_MASK 0x00000008
+#define MCDE_EXTSRC0CR_FS_DIV_DISABLE(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CR, FS_DIV_DISABLE, __x)
+#define MCDE_EXTSRC0CR_FORCE_FS_DIV_SHIFT 4
+#define MCDE_EXTSRC0CR_FORCE_FS_DIV_MASK 0x00000010
+#define MCDE_EXTSRC0CR_FORCE_FS_DIV(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC0CR, FORCE_FS_DIV, __x)
+#define MCDE_EXTSRC1CR 0x00000230
+#define MCDE_EXTSRC1CR_SEL_MOD_SHIFT 0
+#define MCDE_EXTSRC1CR_SEL_MOD_MASK 0x00000003
+#define MCDE_EXTSRC1CR_SEL_MOD_EXTERNAL_SEL 0
+#define MCDE_EXTSRC1CR_SEL_MOD_AUTO_TOGGLE 1
+#define MCDE_EXTSRC1CR_SEL_MOD_SOFTWARE_SEL 2
+#define MCDE_EXTSRC1CR_SEL_MOD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CR, SEL_MOD, MCDE_EXTSRC1CR_SEL_MOD_##__x)
+#define MCDE_EXTSRC1CR_SEL_MOD(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CR, SEL_MOD, __x)
+#define MCDE_EXTSRC1CR_MULTIOVL_CTRL_SHIFT 2
+#define MCDE_EXTSRC1CR_MULTIOVL_CTRL_MASK 0x00000004
+#define MCDE_EXTSRC1CR_MULTIOVL_CTRL_ALL 0
+#define MCDE_EXTSRC1CR_MULTIOVL_CTRL_PRIMARY 1
+#define MCDE_EXTSRC1CR_MULTIOVL_CTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CR, MULTIOVL_CTRL, \
+ MCDE_EXTSRC1CR_MULTIOVL_CTRL_##__x)
+#define MCDE_EXTSRC1CR_MULTIOVL_CTRL(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CR, MULTIOVL_CTRL, __x)
+#define MCDE_EXTSRC1CR_FS_DIV_DISABLE_SHIFT 3
+#define MCDE_EXTSRC1CR_FS_DIV_DISABLE_MASK 0x00000008
+#define MCDE_EXTSRC1CR_FS_DIV_DISABLE(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CR, FS_DIV_DISABLE, __x)
+#define MCDE_EXTSRC1CR_FORCE_FS_DIV_SHIFT 4
+#define MCDE_EXTSRC1CR_FORCE_FS_DIV_MASK 0x00000010
+#define MCDE_EXTSRC1CR_FORCE_FS_DIV(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC1CR, FORCE_FS_DIV, __x)
+#define MCDE_EXTSRC2CR 0x00000250
+#define MCDE_EXTSRC2CR_SEL_MOD_SHIFT 0
+#define MCDE_EXTSRC2CR_SEL_MOD_MASK 0x00000003
+#define MCDE_EXTSRC2CR_SEL_MOD_EXTERNAL_SEL 0
+#define MCDE_EXTSRC2CR_SEL_MOD_AUTO_TOGGLE 1
+#define MCDE_EXTSRC2CR_SEL_MOD_SOFTWARE_SEL 2
+#define MCDE_EXTSRC2CR_SEL_MOD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CR, SEL_MOD, MCDE_EXTSRC2CR_SEL_MOD_##__x)
+#define MCDE_EXTSRC2CR_SEL_MOD(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CR, SEL_MOD, __x)
+#define MCDE_EXTSRC2CR_MULTIOVL_CTRL_SHIFT 2
+#define MCDE_EXTSRC2CR_MULTIOVL_CTRL_MASK 0x00000004
+#define MCDE_EXTSRC2CR_MULTIOVL_CTRL_ALL 0
+#define MCDE_EXTSRC2CR_MULTIOVL_CTRL_PRIMARY 1
+#define MCDE_EXTSRC2CR_MULTIOVL_CTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CR, MULTIOVL_CTRL, \
+ MCDE_EXTSRC2CR_MULTIOVL_CTRL_##__x)
+#define MCDE_EXTSRC2CR_MULTIOVL_CTRL(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CR, MULTIOVL_CTRL, __x)
+#define MCDE_EXTSRC2CR_FS_DIV_DISABLE_SHIFT 3
+#define MCDE_EXTSRC2CR_FS_DIV_DISABLE_MASK 0x00000008
+#define MCDE_EXTSRC2CR_FS_DIV_DISABLE(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CR, FS_DIV_DISABLE, __x)
+#define MCDE_EXTSRC2CR_FORCE_FS_DIV_SHIFT 4
+#define MCDE_EXTSRC2CR_FORCE_FS_DIV_MASK 0x00000010
+#define MCDE_EXTSRC2CR_FORCE_FS_DIV(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC2CR, FORCE_FS_DIV, __x)
+#define MCDE_EXTSRC3CR 0x00000270
+#define MCDE_EXTSRC3CR_SEL_MOD_SHIFT 0
+#define MCDE_EXTSRC3CR_SEL_MOD_MASK 0x00000003
+#define MCDE_EXTSRC3CR_SEL_MOD_EXTERNAL_SEL 0
+#define MCDE_EXTSRC3CR_SEL_MOD_AUTO_TOGGLE 1
+#define MCDE_EXTSRC3CR_SEL_MOD_SOFTWARE_SEL 2
+#define MCDE_EXTSRC3CR_SEL_MOD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CR, SEL_MOD, MCDE_EXTSRC3CR_SEL_MOD_##__x)
+#define MCDE_EXTSRC3CR_SEL_MOD(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CR, SEL_MOD, __x)
+#define MCDE_EXTSRC3CR_MULTIOVL_CTRL_SHIFT 2
+#define MCDE_EXTSRC3CR_MULTIOVL_CTRL_MASK 0x00000004
+#define MCDE_EXTSRC3CR_MULTIOVL_CTRL_ALL 0
+#define MCDE_EXTSRC3CR_MULTIOVL_CTRL_PRIMARY 1
+#define MCDE_EXTSRC3CR_MULTIOVL_CTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CR, MULTIOVL_CTRL, \
+ MCDE_EXTSRC3CR_MULTIOVL_CTRL_##__x)
+#define MCDE_EXTSRC3CR_MULTIOVL_CTRL(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CR, MULTIOVL_CTRL, __x)
+#define MCDE_EXTSRC3CR_FS_DIV_DISABLE_SHIFT 3
+#define MCDE_EXTSRC3CR_FS_DIV_DISABLE_MASK 0x00000008
+#define MCDE_EXTSRC3CR_FS_DIV_DISABLE(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CR, FS_DIV_DISABLE, __x)
+#define MCDE_EXTSRC3CR_FORCE_FS_DIV_SHIFT 4
+#define MCDE_EXTSRC3CR_FORCE_FS_DIV_MASK 0x00000010
+#define MCDE_EXTSRC3CR_FORCE_FS_DIV(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC3CR, FORCE_FS_DIV, __x)
+#define MCDE_EXTSRC4CR 0x00000290
+#define MCDE_EXTSRC4CR_SEL_MOD_SHIFT 0
+#define MCDE_EXTSRC4CR_SEL_MOD_MASK 0x00000003
+#define MCDE_EXTSRC4CR_SEL_MOD_EXTERNAL_SEL 0
+#define MCDE_EXTSRC4CR_SEL_MOD_AUTO_TOGGLE 1
+#define MCDE_EXTSRC4CR_SEL_MOD_SOFTWARE_SEL 2
+#define MCDE_EXTSRC4CR_SEL_MOD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CR, SEL_MOD, MCDE_EXTSRC4CR_SEL_MOD_##__x)
+#define MCDE_EXTSRC4CR_SEL_MOD(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CR, SEL_MOD, __x)
+#define MCDE_EXTSRC4CR_MULTIOVL_CTRL_SHIFT 2
+#define MCDE_EXTSRC4CR_MULTIOVL_CTRL_MASK 0x00000004
+#define MCDE_EXTSRC4CR_MULTIOVL_CTRL_ALL 0
+#define MCDE_EXTSRC4CR_MULTIOVL_CTRL_PRIMARY 1
+#define MCDE_EXTSRC4CR_MULTIOVL_CTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CR, MULTIOVL_CTRL, \
+ MCDE_EXTSRC4CR_MULTIOVL_CTRL_##__x)
+#define MCDE_EXTSRC4CR_MULTIOVL_CTRL(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CR, MULTIOVL_CTRL, __x)
+#define MCDE_EXTSRC4CR_FS_DIV_DISABLE_SHIFT 3
+#define MCDE_EXTSRC4CR_FS_DIV_DISABLE_MASK 0x00000008
+#define MCDE_EXTSRC4CR_FS_DIV_DISABLE(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CR, FS_DIV_DISABLE, __x)
+#define MCDE_EXTSRC4CR_FORCE_FS_DIV_SHIFT 4
+#define MCDE_EXTSRC4CR_FORCE_FS_DIV_MASK 0x00000010
+#define MCDE_EXTSRC4CR_FORCE_FS_DIV(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC4CR, FORCE_FS_DIV, __x)
+#define MCDE_EXTSRC5CR 0x000002B0
+#define MCDE_EXTSRC5CR_SEL_MOD_SHIFT 0
+#define MCDE_EXTSRC5CR_SEL_MOD_MASK 0x00000003
+#define MCDE_EXTSRC5CR_SEL_MOD_EXTERNAL_SEL 0
+#define MCDE_EXTSRC5CR_SEL_MOD_AUTO_TOGGLE 1
+#define MCDE_EXTSRC5CR_SEL_MOD_SOFTWARE_SEL 2
+#define MCDE_EXTSRC5CR_SEL_MOD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CR, SEL_MOD, MCDE_EXTSRC5CR_SEL_MOD_##__x)
+#define MCDE_EXTSRC5CR_SEL_MOD(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CR, SEL_MOD, __x)
+#define MCDE_EXTSRC5CR_MULTIOVL_CTRL_SHIFT 2
+#define MCDE_EXTSRC5CR_MULTIOVL_CTRL_MASK 0x00000004
+#define MCDE_EXTSRC5CR_MULTIOVL_CTRL_ALL 0
+#define MCDE_EXTSRC5CR_MULTIOVL_CTRL_PRIMARY 1
+#define MCDE_EXTSRC5CR_MULTIOVL_CTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CR, MULTIOVL_CTRL, \
+ MCDE_EXTSRC5CR_MULTIOVL_CTRL_##__x)
+#define MCDE_EXTSRC5CR_MULTIOVL_CTRL(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CR, MULTIOVL_CTRL, __x)
+#define MCDE_EXTSRC5CR_FS_DIV_DISABLE_SHIFT 3
+#define MCDE_EXTSRC5CR_FS_DIV_DISABLE_MASK 0x00000008
+#define MCDE_EXTSRC5CR_FS_DIV_DISABLE(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CR, FS_DIV_DISABLE, __x)
+#define MCDE_EXTSRC5CR_FORCE_FS_DIV_SHIFT 4
+#define MCDE_EXTSRC5CR_FORCE_FS_DIV_MASK 0x00000010
+#define MCDE_EXTSRC5CR_FORCE_FS_DIV(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC5CR, FORCE_FS_DIV, __x)
+#define MCDE_EXTSRC6CR 0x000002D0
+#define MCDE_EXTSRC6CR_SEL_MOD_SHIFT 0
+#define MCDE_EXTSRC6CR_SEL_MOD_MASK 0x00000003
+#define MCDE_EXTSRC6CR_SEL_MOD_EXTERNAL_SEL 0
+#define MCDE_EXTSRC6CR_SEL_MOD_AUTO_TOGGLE 1
+#define MCDE_EXTSRC6CR_SEL_MOD_SOFTWARE_SEL 2
+#define MCDE_EXTSRC6CR_SEL_MOD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CR, SEL_MOD, MCDE_EXTSRC6CR_SEL_MOD_##__x)
+#define MCDE_EXTSRC6CR_SEL_MOD(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CR, SEL_MOD, __x)
+#define MCDE_EXTSRC6CR_MULTIOVL_CTRL_SHIFT 2
+#define MCDE_EXTSRC6CR_MULTIOVL_CTRL_MASK 0x00000004
+#define MCDE_EXTSRC6CR_MULTIOVL_CTRL_ALL 0
+#define MCDE_EXTSRC6CR_MULTIOVL_CTRL_PRIMARY 1
+#define MCDE_EXTSRC6CR_MULTIOVL_CTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CR, MULTIOVL_CTRL, \
+ MCDE_EXTSRC6CR_MULTIOVL_CTRL_##__x)
+#define MCDE_EXTSRC6CR_MULTIOVL_CTRL(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CR, MULTIOVL_CTRL, __x)
+#define MCDE_EXTSRC6CR_FS_DIV_DISABLE_SHIFT 3
+#define MCDE_EXTSRC6CR_FS_DIV_DISABLE_MASK 0x00000008
+#define MCDE_EXTSRC6CR_FS_DIV_DISABLE(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CR, FS_DIV_DISABLE, __x)
+#define MCDE_EXTSRC6CR_FORCE_FS_DIV_SHIFT 4
+#define MCDE_EXTSRC6CR_FORCE_FS_DIV_MASK 0x00000010
+#define MCDE_EXTSRC6CR_FORCE_FS_DIV(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC6CR, FORCE_FS_DIV, __x)
+#define MCDE_EXTSRC7CR 0x000002F0
+#define MCDE_EXTSRC7CR_SEL_MOD_SHIFT 0
+#define MCDE_EXTSRC7CR_SEL_MOD_MASK 0x00000003
+#define MCDE_EXTSRC7CR_SEL_MOD_EXTERNAL_SEL 0
+#define MCDE_EXTSRC7CR_SEL_MOD_AUTO_TOGGLE 1
+#define MCDE_EXTSRC7CR_SEL_MOD_SOFTWARE_SEL 2
+#define MCDE_EXTSRC7CR_SEL_MOD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CR, SEL_MOD, MCDE_EXTSRC7CR_SEL_MOD_##__x)
+#define MCDE_EXTSRC7CR_SEL_MOD(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CR, SEL_MOD, __x)
+#define MCDE_EXTSRC7CR_MULTIOVL_CTRL_SHIFT 2
+#define MCDE_EXTSRC7CR_MULTIOVL_CTRL_MASK 0x00000004
+#define MCDE_EXTSRC7CR_MULTIOVL_CTRL_ALL 0
+#define MCDE_EXTSRC7CR_MULTIOVL_CTRL_PRIMARY 1
+#define MCDE_EXTSRC7CR_MULTIOVL_CTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CR, MULTIOVL_CTRL, \
+ MCDE_EXTSRC7CR_MULTIOVL_CTRL_##__x)
+#define MCDE_EXTSRC7CR_MULTIOVL_CTRL(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CR, MULTIOVL_CTRL, __x)
+#define MCDE_EXTSRC7CR_FS_DIV_DISABLE_SHIFT 3
+#define MCDE_EXTSRC7CR_FS_DIV_DISABLE_MASK 0x00000008
+#define MCDE_EXTSRC7CR_FS_DIV_DISABLE(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CR, FS_DIV_DISABLE, __x)
+#define MCDE_EXTSRC7CR_FORCE_FS_DIV_SHIFT 4
+#define MCDE_EXTSRC7CR_FORCE_FS_DIV_MASK 0x00000010
+#define MCDE_EXTSRC7CR_FORCE_FS_DIV(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC7CR, FORCE_FS_DIV, __x)
+#define MCDE_EXTSRC8CR 0x00000310
+#define MCDE_EXTSRC8CR_SEL_MOD_SHIFT 0
+#define MCDE_EXTSRC8CR_SEL_MOD_MASK 0x00000003
+#define MCDE_EXTSRC8CR_SEL_MOD_EXTERNAL_SEL 0
+#define MCDE_EXTSRC8CR_SEL_MOD_AUTO_TOGGLE 1
+#define MCDE_EXTSRC8CR_SEL_MOD_SOFTWARE_SEL 2
+#define MCDE_EXTSRC8CR_SEL_MOD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CR, SEL_MOD, MCDE_EXTSRC8CR_SEL_MOD_##__x)
+#define MCDE_EXTSRC8CR_SEL_MOD(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CR, SEL_MOD, __x)
+#define MCDE_EXTSRC8CR_MULTIOVL_CTRL_SHIFT 2
+#define MCDE_EXTSRC8CR_MULTIOVL_CTRL_MASK 0x00000004
+#define MCDE_EXTSRC8CR_MULTIOVL_CTRL_ALL 0
+#define MCDE_EXTSRC8CR_MULTIOVL_CTRL_PRIMARY 1
+#define MCDE_EXTSRC8CR_MULTIOVL_CTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CR, MULTIOVL_CTRL, \
+ MCDE_EXTSRC8CR_MULTIOVL_CTRL_##__x)
+#define MCDE_EXTSRC8CR_MULTIOVL_CTRL(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CR, MULTIOVL_CTRL, __x)
+#define MCDE_EXTSRC8CR_FS_DIV_DISABLE_SHIFT 3
+#define MCDE_EXTSRC8CR_FS_DIV_DISABLE_MASK 0x00000008
+#define MCDE_EXTSRC8CR_FS_DIV_DISABLE(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CR, FS_DIV_DISABLE, __x)
+#define MCDE_EXTSRC8CR_FORCE_FS_DIV_SHIFT 4
+#define MCDE_EXTSRC8CR_FORCE_FS_DIV_MASK 0x00000010
+#define MCDE_EXTSRC8CR_FORCE_FS_DIV(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC8CR, FORCE_FS_DIV, __x)
+#define MCDE_EXTSRC9CR 0x00000330
+#define MCDE_EXTSRC9CR_SEL_MOD_SHIFT 0
+#define MCDE_EXTSRC9CR_SEL_MOD_MASK 0x00000003
+#define MCDE_EXTSRC9CR_SEL_MOD_EXTERNAL_SEL 0
+#define MCDE_EXTSRC9CR_SEL_MOD_AUTO_TOGGLE 1
+#define MCDE_EXTSRC9CR_SEL_MOD_SOFTWARE_SEL 2
+#define MCDE_EXTSRC9CR_SEL_MOD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CR, SEL_MOD, MCDE_EXTSRC9CR_SEL_MOD_##__x)
+#define MCDE_EXTSRC9CR_SEL_MOD(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CR, SEL_MOD, __x)
+#define MCDE_EXTSRC9CR_MULTIOVL_CTRL_SHIFT 2
+#define MCDE_EXTSRC9CR_MULTIOVL_CTRL_MASK 0x00000004
+#define MCDE_EXTSRC9CR_MULTIOVL_CTRL_ALL 0
+#define MCDE_EXTSRC9CR_MULTIOVL_CTRL_PRIMARY 1
+#define MCDE_EXTSRC9CR_MULTIOVL_CTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CR, MULTIOVL_CTRL, \
+ MCDE_EXTSRC9CR_MULTIOVL_CTRL_##__x)
+#define MCDE_EXTSRC9CR_MULTIOVL_CTRL(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CR, MULTIOVL_CTRL, __x)
+#define MCDE_EXTSRC9CR_FS_DIV_DISABLE_SHIFT 3
+#define MCDE_EXTSRC9CR_FS_DIV_DISABLE_MASK 0x00000008
+#define MCDE_EXTSRC9CR_FS_DIV_DISABLE(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CR, FS_DIV_DISABLE, __x)
+#define MCDE_EXTSRC9CR_FORCE_FS_DIV_SHIFT 4
+#define MCDE_EXTSRC9CR_FORCE_FS_DIV_MASK 0x00000010
+#define MCDE_EXTSRC9CR_FORCE_FS_DIV(__x) \
+ MCDE_VAL2REG(MCDE_EXTSRC9CR, FORCE_FS_DIV, __x)
+#define MCDE_OVL0CR 0x00000400
+#define MCDE_OVL0CR_GROUPOFFSET 0x20
+#define MCDE_OVL0CR_OVLEN_SHIFT 0
+#define MCDE_OVL0CR_OVLEN_MASK 0x00000001
+#define MCDE_OVL0CR_OVLEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, OVLEN, __x)
+#define MCDE_OVL0CR_COLCCTRL_SHIFT 1
+#define MCDE_OVL0CR_COLCCTRL_MASK 0x00000006
+#define MCDE_OVL0CR_COLCCTRL_DISABLED 0
+#define MCDE_OVL0CR_COLCCTRL_ENABLED_NO_SAT 1
+#define MCDE_OVL0CR_COLCCTRL_ENABLED_SAT 2
+#define MCDE_OVL0CR_COLCCTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, COLCCTRL, MCDE_OVL0CR_COLCCTRL_##__x)
+#define MCDE_OVL0CR_COLCCTRL(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, COLCCTRL, __x)
+#define MCDE_OVL0CR_CKEYGEN_SHIFT 3
+#define MCDE_OVL0CR_CKEYGEN_MASK 0x00000008
+#define MCDE_OVL0CR_CKEYGEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, CKEYGEN, __x)
+#define MCDE_OVL0CR_ALPHAPMEN_SHIFT 4
+#define MCDE_OVL0CR_ALPHAPMEN_MASK 0x00000010
+#define MCDE_OVL0CR_ALPHAPMEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, ALPHAPMEN, __x)
+#define MCDE_OVL0CR_OVLF_SHIFT 5
+#define MCDE_OVL0CR_OVLF_MASK 0x00000020
+#define MCDE_OVL0CR_OVLF(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, OVLF, __x)
+#define MCDE_OVL0CR_OVLR_SHIFT 6
+#define MCDE_OVL0CR_OVLR_MASK 0x00000040
+#define MCDE_OVL0CR_OVLR(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, OVLR, __x)
+#define MCDE_OVL0CR_OVLB_SHIFT 7
+#define MCDE_OVL0CR_OVLB_MASK 0x00000080
+#define MCDE_OVL0CR_OVLB(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, OVLB, __x)
+#define MCDE_OVL0CR_FETCH_ROPC_SHIFT 8
+#define MCDE_OVL0CR_FETCH_ROPC_MASK 0x0000FF00
+#define MCDE_OVL0CR_FETCH_ROPC(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, FETCH_ROPC, __x)
+#define MCDE_OVL0CR_STBPRIO_SHIFT 16
+#define MCDE_OVL0CR_STBPRIO_MASK 0x000F0000
+#define MCDE_OVL0CR_STBPRIO(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, STBPRIO, __x)
+#define MCDE_OVL0CR_BURSTSIZE_SHIFT 20
+#define MCDE_OVL0CR_BURSTSIZE_MASK 0x00F00000
+#define MCDE_OVL0CR_BURSTSIZE_1W 0
+#define MCDE_OVL0CR_BURSTSIZE_2W 1
+#define MCDE_OVL0CR_BURSTSIZE_4W 2
+#define MCDE_OVL0CR_BURSTSIZE_8W 3
+#define MCDE_OVL0CR_BURSTSIZE_16W 4
+#define MCDE_OVL0CR_BURSTSIZE_HW_1W 8
+#define MCDE_OVL0CR_BURSTSIZE_HW_2W 9
+#define MCDE_OVL0CR_BURSTSIZE_HW_4W 10
+#define MCDE_OVL0CR_BURSTSIZE_HW_8W 11
+#define MCDE_OVL0CR_BURSTSIZE_HW_16W 12
+#define MCDE_OVL0CR_BURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, BURSTSIZE, MCDE_OVL0CR_BURSTSIZE_##__x)
+#define MCDE_OVL0CR_BURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, BURSTSIZE, __x)
+#define MCDE_OVL0CR_MAXOUTSTANDING_SHIFT 24
+#define MCDE_OVL0CR_MAXOUTSTANDING_MASK 0x0F000000
+#define MCDE_OVL0CR_MAXOUTSTANDING_1_REQ 0
+#define MCDE_OVL0CR_MAXOUTSTANDING_2_REQ 1
+#define MCDE_OVL0CR_MAXOUTSTANDING_4_REQ 2
+#define MCDE_OVL0CR_MAXOUTSTANDING_8_REQ 3
+#define MCDE_OVL0CR_MAXOUTSTANDING_16_REQ 4
+#define MCDE_OVL0CR_MAXOUTSTANDING_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, MAXOUTSTANDING, \
+ MCDE_OVL0CR_MAXOUTSTANDING_##__x)
+#define MCDE_OVL0CR_MAXOUTSTANDING(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, MAXOUTSTANDING, __x)
+#define MCDE_OVL0CR_ROTBURSTSIZE_SHIFT 28
+#define MCDE_OVL0CR_ROTBURSTSIZE_MASK 0xF0000000
+#define MCDE_OVL0CR_ROTBURSTSIZE_1W 0
+#define MCDE_OVL0CR_ROTBURSTSIZE_2W 1
+#define MCDE_OVL0CR_ROTBURSTSIZE_4W 2
+#define MCDE_OVL0CR_ROTBURSTSIZE_8W 3
+#define MCDE_OVL0CR_ROTBURSTSIZE_16W 4
+#define MCDE_OVL0CR_ROTBURSTSIZE_HW_1W 8
+#define MCDE_OVL0CR_ROTBURSTSIZE_HW_2W 9
+#define MCDE_OVL0CR_ROTBURSTSIZE_HW_4W 10
+#define MCDE_OVL0CR_ROTBURSTSIZE_HW_8W 11
+#define MCDE_OVL0CR_ROTBURSTSIZE_HW_16W 12
+#define MCDE_OVL0CR_ROTBURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, ROTBURSTSIZE, MCDE_OVL0CR_ROTBURSTSIZE_##__x)
+#define MCDE_OVL0CR_ROTBURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CR, ROTBURSTSIZE, __x)
+#define MCDE_OVL1CR 0x00000420
+#define MCDE_OVL1CR_OVLEN_SHIFT 0
+#define MCDE_OVL1CR_OVLEN_MASK 0x00000001
+#define MCDE_OVL1CR_OVLEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, OVLEN, __x)
+#define MCDE_OVL1CR_COLCCTRL_SHIFT 1
+#define MCDE_OVL1CR_COLCCTRL_MASK 0x00000006
+#define MCDE_OVL1CR_COLCCTRL_DISABLED 0
+#define MCDE_OVL1CR_COLCCTRL_ENABLED_NO_SAT 1
+#define MCDE_OVL1CR_COLCCTRL_ENABLED_SAT 2
+#define MCDE_OVL1CR_COLCCTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, COLCCTRL, MCDE_OVL1CR_COLCCTRL_##__x)
+#define MCDE_OVL1CR_COLCCTRL(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, COLCCTRL, __x)
+#define MCDE_OVL1CR_CKEYGEN_SHIFT 3
+#define MCDE_OVL1CR_CKEYGEN_MASK 0x00000008
+#define MCDE_OVL1CR_CKEYGEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, CKEYGEN, __x)
+#define MCDE_OVL1CR_ALPHAPMEN_SHIFT 4
+#define MCDE_OVL1CR_ALPHAPMEN_MASK 0x00000010
+#define MCDE_OVL1CR_ALPHAPMEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, ALPHAPMEN, __x)
+#define MCDE_OVL1CR_OVLF_SHIFT 5
+#define MCDE_OVL1CR_OVLF_MASK 0x00000020
+#define MCDE_OVL1CR_OVLF(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, OVLF, __x)
+#define MCDE_OVL1CR_OVLR_SHIFT 6
+#define MCDE_OVL1CR_OVLR_MASK 0x00000040
+#define MCDE_OVL1CR_OVLR(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, OVLR, __x)
+#define MCDE_OVL1CR_OVLB_SHIFT 7
+#define MCDE_OVL1CR_OVLB_MASK 0x00000080
+#define MCDE_OVL1CR_OVLB(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, OVLB, __x)
+#define MCDE_OVL1CR_FETCH_ROPC_SHIFT 8
+#define MCDE_OVL1CR_FETCH_ROPC_MASK 0x0000FF00
+#define MCDE_OVL1CR_FETCH_ROPC(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, FETCH_ROPC, __x)
+#define MCDE_OVL1CR_STBPRIO_SHIFT 16
+#define MCDE_OVL1CR_STBPRIO_MASK 0x000F0000
+#define MCDE_OVL1CR_STBPRIO(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, STBPRIO, __x)
+#define MCDE_OVL1CR_BURSTSIZE_SHIFT 20
+#define MCDE_OVL1CR_BURSTSIZE_MASK 0x00F00000
+#define MCDE_OVL1CR_BURSTSIZE_1W 0
+#define MCDE_OVL1CR_BURSTSIZE_2W 1
+#define MCDE_OVL1CR_BURSTSIZE_4W 2
+#define MCDE_OVL1CR_BURSTSIZE_8W 3
+#define MCDE_OVL1CR_BURSTSIZE_16W 4
+#define MCDE_OVL1CR_BURSTSIZE_HW_1W 8
+#define MCDE_OVL1CR_BURSTSIZE_HW_2W 9
+#define MCDE_OVL1CR_BURSTSIZE_HW_4W 10
+#define MCDE_OVL1CR_BURSTSIZE_HW_8W 11
+#define MCDE_OVL1CR_BURSTSIZE_HW_16W 12
+#define MCDE_OVL1CR_BURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, BURSTSIZE, MCDE_OVL1CR_BURSTSIZE_##__x)
+#define MCDE_OVL1CR_BURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, BURSTSIZE, __x)
+#define MCDE_OVL1CR_MAXOUTSTANDING_SHIFT 24
+#define MCDE_OVL1CR_MAXOUTSTANDING_MASK 0x0F000000
+#define MCDE_OVL1CR_MAXOUTSTANDING_1_REQ 0
+#define MCDE_OVL1CR_MAXOUTSTANDING_2_REQ 1
+#define MCDE_OVL1CR_MAXOUTSTANDING_4_REQ 2
+#define MCDE_OVL1CR_MAXOUTSTANDING_8_REQ 3
+#define MCDE_OVL1CR_MAXOUTSTANDING_16_REQ 4
+#define MCDE_OVL1CR_MAXOUTSTANDING_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, MAXOUTSTANDING, \
+ MCDE_OVL1CR_MAXOUTSTANDING_##__x)
+#define MCDE_OVL1CR_MAXOUTSTANDING(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, MAXOUTSTANDING, __x)
+#define MCDE_OVL1CR_ROTBURSTSIZE_SHIFT 28
+#define MCDE_OVL1CR_ROTBURSTSIZE_MASK 0xF0000000
+#define MCDE_OVL1CR_ROTBURSTSIZE_1W 0
+#define MCDE_OVL1CR_ROTBURSTSIZE_2W 1
+#define MCDE_OVL1CR_ROTBURSTSIZE_4W 2
+#define MCDE_OVL1CR_ROTBURSTSIZE_8W 3
+#define MCDE_OVL1CR_ROTBURSTSIZE_16W 4
+#define MCDE_OVL1CR_ROTBURSTSIZE_HW_1W 8
+#define MCDE_OVL1CR_ROTBURSTSIZE_HW_2W 9
+#define MCDE_OVL1CR_ROTBURSTSIZE_HW_4W 10
+#define MCDE_OVL1CR_ROTBURSTSIZE_HW_8W 11
+#define MCDE_OVL1CR_ROTBURSTSIZE_HW_16W 12
+#define MCDE_OVL1CR_ROTBURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, ROTBURSTSIZE, MCDE_OVL1CR_ROTBURSTSIZE_##__x)
+#define MCDE_OVL1CR_ROTBURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CR, ROTBURSTSIZE, __x)
+#define MCDE_OVL2CR 0x00000440
+#define MCDE_OVL2CR_OVLEN_SHIFT 0
+#define MCDE_OVL2CR_OVLEN_MASK 0x00000001
+#define MCDE_OVL2CR_OVLEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, OVLEN, __x)
+#define MCDE_OVL2CR_COLCCTRL_SHIFT 1
+#define MCDE_OVL2CR_COLCCTRL_MASK 0x00000006
+#define MCDE_OVL2CR_COLCCTRL_DISABLED 0
+#define MCDE_OVL2CR_COLCCTRL_ENABLED_NO_SAT 1
+#define MCDE_OVL2CR_COLCCTRL_ENABLED_SAT 2
+#define MCDE_OVL2CR_COLCCTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, COLCCTRL, MCDE_OVL2CR_COLCCTRL_##__x)
+#define MCDE_OVL2CR_COLCCTRL(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, COLCCTRL, __x)
+#define MCDE_OVL2CR_CKEYGEN_SHIFT 3
+#define MCDE_OVL2CR_CKEYGEN_MASK 0x00000008
+#define MCDE_OVL2CR_CKEYGEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, CKEYGEN, __x)
+#define MCDE_OVL2CR_ALPHAPMEN_SHIFT 4
+#define MCDE_OVL2CR_ALPHAPMEN_MASK 0x00000010
+#define MCDE_OVL2CR_ALPHAPMEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, ALPHAPMEN, __x)
+#define MCDE_OVL2CR_OVLF_SHIFT 5
+#define MCDE_OVL2CR_OVLF_MASK 0x00000020
+#define MCDE_OVL2CR_OVLF(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, OVLF, __x)
+#define MCDE_OVL2CR_OVLR_SHIFT 6
+#define MCDE_OVL2CR_OVLR_MASK 0x00000040
+#define MCDE_OVL2CR_OVLR(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, OVLR, __x)
+#define MCDE_OVL2CR_OVLB_SHIFT 7
+#define MCDE_OVL2CR_OVLB_MASK 0x00000080
+#define MCDE_OVL2CR_OVLB(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, OVLB, __x)
+#define MCDE_OVL2CR_FETCH_ROPC_SHIFT 8
+#define MCDE_OVL2CR_FETCH_ROPC_MASK 0x0000FF00
+#define MCDE_OVL2CR_FETCH_ROPC(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, FETCH_ROPC, __x)
+#define MCDE_OVL2CR_STBPRIO_SHIFT 16
+#define MCDE_OVL2CR_STBPRIO_MASK 0x000F0000
+#define MCDE_OVL2CR_STBPRIO(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, STBPRIO, __x)
+#define MCDE_OVL2CR_BURSTSIZE_SHIFT 20
+#define MCDE_OVL2CR_BURSTSIZE_MASK 0x00F00000
+#define MCDE_OVL2CR_BURSTSIZE_1W 0
+#define MCDE_OVL2CR_BURSTSIZE_2W 1
+#define MCDE_OVL2CR_BURSTSIZE_4W 2
+#define MCDE_OVL2CR_BURSTSIZE_8W 3
+#define MCDE_OVL2CR_BURSTSIZE_16W 4
+#define MCDE_OVL2CR_BURSTSIZE_HW_1W 8
+#define MCDE_OVL2CR_BURSTSIZE_HW_2W 9
+#define MCDE_OVL2CR_BURSTSIZE_HW_4W 10
+#define MCDE_OVL2CR_BURSTSIZE_HW_8W 11
+#define MCDE_OVL2CR_BURSTSIZE_HW_16W 12
+#define MCDE_OVL2CR_BURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, BURSTSIZE, MCDE_OVL2CR_BURSTSIZE_##__x)
+#define MCDE_OVL2CR_BURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, BURSTSIZE, __x)
+#define MCDE_OVL2CR_MAXOUTSTANDING_SHIFT 24
+#define MCDE_OVL2CR_MAXOUTSTANDING_MASK 0x0F000000
+#define MCDE_OVL2CR_MAXOUTSTANDING_1_REQ 0
+#define MCDE_OVL2CR_MAXOUTSTANDING_2_REQ 1
+#define MCDE_OVL2CR_MAXOUTSTANDING_4_REQ 2
+#define MCDE_OVL2CR_MAXOUTSTANDING_8_REQ 3
+#define MCDE_OVL2CR_MAXOUTSTANDING_16_REQ 4
+#define MCDE_OVL2CR_MAXOUTSTANDING_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, MAXOUTSTANDING, \
+ MCDE_OVL2CR_MAXOUTSTANDING_##__x)
+#define MCDE_OVL2CR_MAXOUTSTANDING(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, MAXOUTSTANDING, __x)
+#define MCDE_OVL2CR_ROTBURSTSIZE_SHIFT 28
+#define MCDE_OVL2CR_ROTBURSTSIZE_MASK 0xF0000000
+#define MCDE_OVL2CR_ROTBURSTSIZE_1W 0
+#define MCDE_OVL2CR_ROTBURSTSIZE_2W 1
+#define MCDE_OVL2CR_ROTBURSTSIZE_4W 2
+#define MCDE_OVL2CR_ROTBURSTSIZE_8W 3
+#define MCDE_OVL2CR_ROTBURSTSIZE_16W 4
+#define MCDE_OVL2CR_ROTBURSTSIZE_HW_1W 8
+#define MCDE_OVL2CR_ROTBURSTSIZE_HW_2W 9
+#define MCDE_OVL2CR_ROTBURSTSIZE_HW_4W 10
+#define MCDE_OVL2CR_ROTBURSTSIZE_HW_8W 11
+#define MCDE_OVL2CR_ROTBURSTSIZE_HW_16W 12
+#define MCDE_OVL2CR_ROTBURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, ROTBURSTSIZE, MCDE_OVL2CR_ROTBURSTSIZE_##__x)
+#define MCDE_OVL2CR_ROTBURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CR, ROTBURSTSIZE, __x)
+#define MCDE_OVL3CR 0x00000460
+#define MCDE_OVL3CR_OVLEN_SHIFT 0
+#define MCDE_OVL3CR_OVLEN_MASK 0x00000001
+#define MCDE_OVL3CR_OVLEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, OVLEN, __x)
+#define MCDE_OVL3CR_COLCCTRL_SHIFT 1
+#define MCDE_OVL3CR_COLCCTRL_MASK 0x00000006
+#define MCDE_OVL3CR_COLCCTRL_DISABLED 0
+#define MCDE_OVL3CR_COLCCTRL_ENABLED_NO_SAT 1
+#define MCDE_OVL3CR_COLCCTRL_ENABLED_SAT 2
+#define MCDE_OVL3CR_COLCCTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, COLCCTRL, MCDE_OVL3CR_COLCCTRL_##__x)
+#define MCDE_OVL3CR_COLCCTRL(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, COLCCTRL, __x)
+#define MCDE_OVL3CR_CKEYGEN_SHIFT 3
+#define MCDE_OVL3CR_CKEYGEN_MASK 0x00000008
+#define MCDE_OVL3CR_CKEYGEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, CKEYGEN, __x)
+#define MCDE_OVL3CR_ALPHAPMEN_SHIFT 4
+#define MCDE_OVL3CR_ALPHAPMEN_MASK 0x00000010
+#define MCDE_OVL3CR_ALPHAPMEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, ALPHAPMEN, __x)
+#define MCDE_OVL3CR_OVLF_SHIFT 5
+#define MCDE_OVL3CR_OVLF_MASK 0x00000020
+#define MCDE_OVL3CR_OVLF(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, OVLF, __x)
+#define MCDE_OVL3CR_OVLR_SHIFT 6
+#define MCDE_OVL3CR_OVLR_MASK 0x00000040
+#define MCDE_OVL3CR_OVLR(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, OVLR, __x)
+#define MCDE_OVL3CR_OVLB_SHIFT 7
+#define MCDE_OVL3CR_OVLB_MASK 0x00000080
+#define MCDE_OVL3CR_OVLB(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, OVLB, __x)
+#define MCDE_OVL3CR_FETCH_ROPC_SHIFT 8
+#define MCDE_OVL3CR_FETCH_ROPC_MASK 0x0000FF00
+#define MCDE_OVL3CR_FETCH_ROPC(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, FETCH_ROPC, __x)
+#define MCDE_OVL3CR_STBPRIO_SHIFT 16
+#define MCDE_OVL3CR_STBPRIO_MASK 0x000F0000
+#define MCDE_OVL3CR_STBPRIO(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, STBPRIO, __x)
+#define MCDE_OVL3CR_BURSTSIZE_SHIFT 20
+#define MCDE_OVL3CR_BURSTSIZE_MASK 0x00F00000
+#define MCDE_OVL3CR_BURSTSIZE_1W 0
+#define MCDE_OVL3CR_BURSTSIZE_2W 1
+#define MCDE_OVL3CR_BURSTSIZE_4W 2
+#define MCDE_OVL3CR_BURSTSIZE_8W 3
+#define MCDE_OVL3CR_BURSTSIZE_16W 4
+#define MCDE_OVL3CR_BURSTSIZE_HW_1W 8
+#define MCDE_OVL3CR_BURSTSIZE_HW_2W 9
+#define MCDE_OVL3CR_BURSTSIZE_HW_4W 10
+#define MCDE_OVL3CR_BURSTSIZE_HW_8W 11
+#define MCDE_OVL3CR_BURSTSIZE_HW_16W 12
+#define MCDE_OVL3CR_BURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, BURSTSIZE, MCDE_OVL3CR_BURSTSIZE_##__x)
+#define MCDE_OVL3CR_BURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, BURSTSIZE, __x)
+#define MCDE_OVL3CR_MAXOUTSTANDING_SHIFT 24
+#define MCDE_OVL3CR_MAXOUTSTANDING_MASK 0x0F000000
+#define MCDE_OVL3CR_MAXOUTSTANDING_1_REQ 0
+#define MCDE_OVL3CR_MAXOUTSTANDING_2_REQ 1
+#define MCDE_OVL3CR_MAXOUTSTANDING_4_REQ 2
+#define MCDE_OVL3CR_MAXOUTSTANDING_8_REQ 3
+#define MCDE_OVL3CR_MAXOUTSTANDING_16_REQ 4
+#define MCDE_OVL3CR_MAXOUTSTANDING_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, MAXOUTSTANDING, \
+ MCDE_OVL3CR_MAXOUTSTANDING_##__x)
+#define MCDE_OVL3CR_MAXOUTSTANDING(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, MAXOUTSTANDING, __x)
+#define MCDE_OVL3CR_ROTBURSTSIZE_SHIFT 28
+#define MCDE_OVL3CR_ROTBURSTSIZE_MASK 0xF0000000
+#define MCDE_OVL3CR_ROTBURSTSIZE_1W 0
+#define MCDE_OVL3CR_ROTBURSTSIZE_2W 1
+#define MCDE_OVL3CR_ROTBURSTSIZE_4W 2
+#define MCDE_OVL3CR_ROTBURSTSIZE_8W 3
+#define MCDE_OVL3CR_ROTBURSTSIZE_16W 4
+#define MCDE_OVL3CR_ROTBURSTSIZE_HW_1W 8
+#define MCDE_OVL3CR_ROTBURSTSIZE_HW_2W 9
+#define MCDE_OVL3CR_ROTBURSTSIZE_HW_4W 10
+#define MCDE_OVL3CR_ROTBURSTSIZE_HW_8W 11
+#define MCDE_OVL3CR_ROTBURSTSIZE_HW_16W 12
+#define MCDE_OVL3CR_ROTBURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, ROTBURSTSIZE, MCDE_OVL3CR_ROTBURSTSIZE_##__x)
+#define MCDE_OVL3CR_ROTBURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CR, ROTBURSTSIZE, __x)
+#define MCDE_OVL4CR 0x00000480
+#define MCDE_OVL4CR_OVLEN_SHIFT 0
+#define MCDE_OVL4CR_OVLEN_MASK 0x00000001
+#define MCDE_OVL4CR_OVLEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, OVLEN, __x)
+#define MCDE_OVL4CR_COLCCTRL_SHIFT 1
+#define MCDE_OVL4CR_COLCCTRL_MASK 0x00000006
+#define MCDE_OVL4CR_COLCCTRL_DISABLED 0
+#define MCDE_OVL4CR_COLCCTRL_ENABLED_NO_SAT 1
+#define MCDE_OVL4CR_COLCCTRL_ENABLED_SAT 2
+#define MCDE_OVL4CR_COLCCTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, COLCCTRL, MCDE_OVL4CR_COLCCTRL_##__x)
+#define MCDE_OVL4CR_COLCCTRL(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, COLCCTRL, __x)
+#define MCDE_OVL4CR_CKEYGEN_SHIFT 3
+#define MCDE_OVL4CR_CKEYGEN_MASK 0x00000008
+#define MCDE_OVL4CR_CKEYGEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, CKEYGEN, __x)
+#define MCDE_OVL4CR_ALPHAPMEN_SHIFT 4
+#define MCDE_OVL4CR_ALPHAPMEN_MASK 0x00000010
+#define MCDE_OVL4CR_ALPHAPMEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, ALPHAPMEN, __x)
+#define MCDE_OVL4CR_OVLF_SHIFT 5
+#define MCDE_OVL4CR_OVLF_MASK 0x00000020
+#define MCDE_OVL4CR_OVLF(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, OVLF, __x)
+#define MCDE_OVL4CR_OVLR_SHIFT 6
+#define MCDE_OVL4CR_OVLR_MASK 0x00000040
+#define MCDE_OVL4CR_OVLR(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, OVLR, __x)
+#define MCDE_OVL4CR_OVLB_SHIFT 7
+#define MCDE_OVL4CR_OVLB_MASK 0x00000080
+#define MCDE_OVL4CR_OVLB(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, OVLB, __x)
+#define MCDE_OVL4CR_FETCH_ROPC_SHIFT 8
+#define MCDE_OVL4CR_FETCH_ROPC_MASK 0x0000FF00
+#define MCDE_OVL4CR_FETCH_ROPC(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, FETCH_ROPC, __x)
+#define MCDE_OVL4CR_STBPRIO_SHIFT 16
+#define MCDE_OVL4CR_STBPRIO_MASK 0x000F0000
+#define MCDE_OVL4CR_STBPRIO(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, STBPRIO, __x)
+#define MCDE_OVL4CR_BURSTSIZE_SHIFT 20
+#define MCDE_OVL4CR_BURSTSIZE_MASK 0x00F00000
+#define MCDE_OVL4CR_BURSTSIZE_1W 0
+#define MCDE_OVL4CR_BURSTSIZE_2W 1
+#define MCDE_OVL4CR_BURSTSIZE_4W 2
+#define MCDE_OVL4CR_BURSTSIZE_8W 3
+#define MCDE_OVL4CR_BURSTSIZE_16W 4
+#define MCDE_OVL4CR_BURSTSIZE_HW_1W 8
+#define MCDE_OVL4CR_BURSTSIZE_HW_2W 9
+#define MCDE_OVL4CR_BURSTSIZE_HW_4W 10
+#define MCDE_OVL4CR_BURSTSIZE_HW_8W 11
+#define MCDE_OVL4CR_BURSTSIZE_HW_16W 12
+#define MCDE_OVL4CR_BURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, BURSTSIZE, MCDE_OVL4CR_BURSTSIZE_##__x)
+#define MCDE_OVL4CR_BURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, BURSTSIZE, __x)
+#define MCDE_OVL4CR_MAXOUTSTANDING_SHIFT 24
+#define MCDE_OVL4CR_MAXOUTSTANDING_MASK 0x0F000000
+#define MCDE_OVL4CR_MAXOUTSTANDING_1_REQ 0
+#define MCDE_OVL4CR_MAXOUTSTANDING_2_REQ 1
+#define MCDE_OVL4CR_MAXOUTSTANDING_4_REQ 2
+#define MCDE_OVL4CR_MAXOUTSTANDING_8_REQ 3
+#define MCDE_OVL4CR_MAXOUTSTANDING_16_REQ 4
+#define MCDE_OVL4CR_MAXOUTSTANDING_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, MAXOUTSTANDING, \
+ MCDE_OVL4CR_MAXOUTSTANDING_##__x)
+#define MCDE_OVL4CR_MAXOUTSTANDING(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, MAXOUTSTANDING, __x)
+#define MCDE_OVL4CR_ROTBURSTSIZE_SHIFT 28
+#define MCDE_OVL4CR_ROTBURSTSIZE_MASK 0xF0000000
+#define MCDE_OVL4CR_ROTBURSTSIZE_1W 0
+#define MCDE_OVL4CR_ROTBURSTSIZE_2W 1
+#define MCDE_OVL4CR_ROTBURSTSIZE_4W 2
+#define MCDE_OVL4CR_ROTBURSTSIZE_8W 3
+#define MCDE_OVL4CR_ROTBURSTSIZE_16W 4
+#define MCDE_OVL4CR_ROTBURSTSIZE_HW_1W 8
+#define MCDE_OVL4CR_ROTBURSTSIZE_HW_2W 9
+#define MCDE_OVL4CR_ROTBURSTSIZE_HW_4W 10
+#define MCDE_OVL4CR_ROTBURSTSIZE_HW_8W 11
+#define MCDE_OVL4CR_ROTBURSTSIZE_HW_16W 12
+#define MCDE_OVL4CR_ROTBURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, ROTBURSTSIZE, MCDE_OVL4CR_ROTBURSTSIZE_##__x)
+#define MCDE_OVL4CR_ROTBURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CR, ROTBURSTSIZE, __x)
+#define MCDE_OVL5CR 0x000004A0
+#define MCDE_OVL5CR_OVLEN_SHIFT 0
+#define MCDE_OVL5CR_OVLEN_MASK 0x00000001
+#define MCDE_OVL5CR_OVLEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, OVLEN, __x)
+#define MCDE_OVL5CR_COLCCTRL_SHIFT 1
+#define MCDE_OVL5CR_COLCCTRL_MASK 0x00000006
+#define MCDE_OVL5CR_COLCCTRL_DISABLED 0
+#define MCDE_OVL5CR_COLCCTRL_ENABLED_NO_SAT 1
+#define MCDE_OVL5CR_COLCCTRL_ENABLED_SAT 2
+#define MCDE_OVL5CR_COLCCTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, COLCCTRL, MCDE_OVL5CR_COLCCTRL_##__x)
+#define MCDE_OVL5CR_COLCCTRL(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, COLCCTRL, __x)
+#define MCDE_OVL5CR_CKEYGEN_SHIFT 3
+#define MCDE_OVL5CR_CKEYGEN_MASK 0x00000008
+#define MCDE_OVL5CR_CKEYGEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, CKEYGEN, __x)
+#define MCDE_OVL5CR_ALPHAPMEN_SHIFT 4
+#define MCDE_OVL5CR_ALPHAPMEN_MASK 0x00000010
+#define MCDE_OVL5CR_ALPHAPMEN(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, ALPHAPMEN, __x)
+#define MCDE_OVL5CR_OVLF_SHIFT 5
+#define MCDE_OVL5CR_OVLF_MASK 0x00000020
+#define MCDE_OVL5CR_OVLF(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, OVLF, __x)
+#define MCDE_OVL5CR_OVLR_SHIFT 6
+#define MCDE_OVL5CR_OVLR_MASK 0x00000040
+#define MCDE_OVL5CR_OVLR(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, OVLR, __x)
+#define MCDE_OVL5CR_OVLB_SHIFT 7
+#define MCDE_OVL5CR_OVLB_MASK 0x00000080
+#define MCDE_OVL5CR_OVLB(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, OVLB, __x)
+#define MCDE_OVL5CR_FETCH_ROPC_SHIFT 8
+#define MCDE_OVL5CR_FETCH_ROPC_MASK 0x0000FF00
+#define MCDE_OVL5CR_FETCH_ROPC(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, FETCH_ROPC, __x)
+#define MCDE_OVL5CR_STBPRIO_SHIFT 16
+#define MCDE_OVL5CR_STBPRIO_MASK 0x000F0000
+#define MCDE_OVL5CR_STBPRIO(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, STBPRIO, __x)
+#define MCDE_OVL5CR_BURSTSIZE_SHIFT 20
+#define MCDE_OVL5CR_BURSTSIZE_MASK 0x00F00000
+#define MCDE_OVL5CR_BURSTSIZE_1W 0
+#define MCDE_OVL5CR_BURSTSIZE_2W 1
+#define MCDE_OVL5CR_BURSTSIZE_4W 2
+#define MCDE_OVL5CR_BURSTSIZE_8W 3
+#define MCDE_OVL5CR_BURSTSIZE_16W 4
+#define MCDE_OVL5CR_BURSTSIZE_HW_1W 8
+#define MCDE_OVL5CR_BURSTSIZE_HW_2W 9
+#define MCDE_OVL5CR_BURSTSIZE_HW_4W 10
+#define MCDE_OVL5CR_BURSTSIZE_HW_8W 11
+#define MCDE_OVL5CR_BURSTSIZE_HW_16W 12
+#define MCDE_OVL5CR_BURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, BURSTSIZE, MCDE_OVL5CR_BURSTSIZE_##__x)
+#define MCDE_OVL5CR_BURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, BURSTSIZE, __x)
+#define MCDE_OVL5CR_MAXOUTSTANDING_SHIFT 24
+#define MCDE_OVL5CR_MAXOUTSTANDING_MASK 0x0F000000
+#define MCDE_OVL5CR_MAXOUTSTANDING_1_REQ 0
+#define MCDE_OVL5CR_MAXOUTSTANDING_2_REQ 1
+#define MCDE_OVL5CR_MAXOUTSTANDING_4_REQ 2
+#define MCDE_OVL5CR_MAXOUTSTANDING_8_REQ 3
+#define MCDE_OVL5CR_MAXOUTSTANDING_16_REQ 4
+#define MCDE_OVL5CR_MAXOUTSTANDING_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, MAXOUTSTANDING, \
+ MCDE_OVL5CR_MAXOUTSTANDING_##__x)
+#define MCDE_OVL5CR_MAXOUTSTANDING(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, MAXOUTSTANDING, __x)
+#define MCDE_OVL5CR_ROTBURSTSIZE_SHIFT 28
+#define MCDE_OVL5CR_ROTBURSTSIZE_MASK 0xF0000000
+#define MCDE_OVL5CR_ROTBURSTSIZE_1W 0
+#define MCDE_OVL5CR_ROTBURSTSIZE_2W 1
+#define MCDE_OVL5CR_ROTBURSTSIZE_4W 2
+#define MCDE_OVL5CR_ROTBURSTSIZE_8W 3
+#define MCDE_OVL5CR_ROTBURSTSIZE_16W 4
+#define MCDE_OVL5CR_ROTBURSTSIZE_HW_1W 8
+#define MCDE_OVL5CR_ROTBURSTSIZE_HW_2W 9
+#define MCDE_OVL5CR_ROTBURSTSIZE_HW_4W 10
+#define MCDE_OVL5CR_ROTBURSTSIZE_HW_8W 11
+#define MCDE_OVL5CR_ROTBURSTSIZE_HW_16W 12
+#define MCDE_OVL5CR_ROTBURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, ROTBURSTSIZE, MCDE_OVL5CR_ROTBURSTSIZE_##__x)
+#define MCDE_OVL5CR_ROTBURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CR, ROTBURSTSIZE, __x)
+#define MCDE_OVL0CONF 0x00000404
+#define MCDE_OVL0CONF_GROUPOFFSET 0x20
+#define MCDE_OVL0CONF_PPL_SHIFT 0
+#define MCDE_OVL0CONF_PPL_MASK 0x000007FF
+#define MCDE_OVL0CONF_PPL(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CONF, PPL, __x)
+#define MCDE_OVL0CONF_EXTSRC_ID_SHIFT 11
+#define MCDE_OVL0CONF_EXTSRC_ID_MASK 0x00007800
+#define MCDE_OVL0CONF_EXTSRC_ID(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CONF, EXTSRC_ID, __x)
+#define MCDE_OVL0CONF_LPF_SHIFT 16
+#define MCDE_OVL0CONF_LPF_MASK 0x07FF0000
+#define MCDE_OVL0CONF_LPF(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CONF, LPF, __x)
+#define MCDE_OVL1CONF 0x00000424
+#define MCDE_OVL1CONF_PPL_SHIFT 0
+#define MCDE_OVL1CONF_PPL_MASK 0x000007FF
+#define MCDE_OVL1CONF_PPL(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CONF, PPL, __x)
+#define MCDE_OVL1CONF_EXTSRC_ID_SHIFT 11
+#define MCDE_OVL1CONF_EXTSRC_ID_MASK 0x00007800
+#define MCDE_OVL1CONF_EXTSRC_ID(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CONF, EXTSRC_ID, __x)
+#define MCDE_OVL1CONF_LPF_SHIFT 16
+#define MCDE_OVL1CONF_LPF_MASK 0x07FF0000
+#define MCDE_OVL1CONF_LPF(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CONF, LPF, __x)
+#define MCDE_OVL2CONF 0x00000444
+#define MCDE_OVL2CONF_PPL_SHIFT 0
+#define MCDE_OVL2CONF_PPL_MASK 0x000007FF
+#define MCDE_OVL2CONF_PPL(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CONF, PPL, __x)
+#define MCDE_OVL2CONF_EXTSRC_ID_SHIFT 11
+#define MCDE_OVL2CONF_EXTSRC_ID_MASK 0x00007800
+#define MCDE_OVL2CONF_EXTSRC_ID(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CONF, EXTSRC_ID, __x)
+#define MCDE_OVL2CONF_LPF_SHIFT 16
+#define MCDE_OVL2CONF_LPF_MASK 0x07FF0000
+#define MCDE_OVL2CONF_LPF(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CONF, LPF, __x)
+#define MCDE_OVL3CONF 0x00000464
+#define MCDE_OVL3CONF_PPL_SHIFT 0
+#define MCDE_OVL3CONF_PPL_MASK 0x000007FF
+#define MCDE_OVL3CONF_PPL(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CONF, PPL, __x)
+#define MCDE_OVL3CONF_EXTSRC_ID_SHIFT 11
+#define MCDE_OVL3CONF_EXTSRC_ID_MASK 0x00007800
+#define MCDE_OVL3CONF_EXTSRC_ID(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CONF, EXTSRC_ID, __x)
+#define MCDE_OVL3CONF_LPF_SHIFT 16
+#define MCDE_OVL3CONF_LPF_MASK 0x07FF0000
+#define MCDE_OVL3CONF_LPF(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CONF, LPF, __x)
+#define MCDE_OVL4CONF 0x00000484
+#define MCDE_OVL4CONF_PPL_SHIFT 0
+#define MCDE_OVL4CONF_PPL_MASK 0x000007FF
+#define MCDE_OVL4CONF_PPL(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CONF, PPL, __x)
+#define MCDE_OVL4CONF_EXTSRC_ID_SHIFT 11
+#define MCDE_OVL4CONF_EXTSRC_ID_MASK 0x00007800
+#define MCDE_OVL4CONF_EXTSRC_ID(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CONF, EXTSRC_ID, __x)
+#define MCDE_OVL4CONF_LPF_SHIFT 16
+#define MCDE_OVL4CONF_LPF_MASK 0x07FF0000
+#define MCDE_OVL4CONF_LPF(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CONF, LPF, __x)
+#define MCDE_OVL5CONF 0x000004A4
+#define MCDE_OVL5CONF_PPL_SHIFT 0
+#define MCDE_OVL5CONF_PPL_MASK 0x000007FF
+#define MCDE_OVL5CONF_PPL(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CONF, PPL, __x)
+#define MCDE_OVL5CONF_EXTSRC_ID_SHIFT 11
+#define MCDE_OVL5CONF_EXTSRC_ID_MASK 0x00007800
+#define MCDE_OVL5CONF_EXTSRC_ID(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CONF, EXTSRC_ID, __x)
+#define MCDE_OVL5CONF_LPF_SHIFT 16
+#define MCDE_OVL5CONF_LPF_MASK 0x07FF0000
+#define MCDE_OVL5CONF_LPF(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CONF, LPF, __x)
+#define MCDE_OVL0CONF2 0x00000408
+#define MCDE_OVL0CONF2_GROUPOFFSET 0x20
+#define MCDE_OVL0CONF2_BP_SHIFT 0
+#define MCDE_OVL0CONF2_BP_MASK 0x00000001
+#define MCDE_OVL0CONF2_BP_PER_PIXEL_ALPHA 0
+#define MCDE_OVL0CONF2_BP_CONSTANT_ALPHA 1
+#define MCDE_OVL0CONF2_BP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CONF2, BP, MCDE_OVL0CONF2_BP_##__x)
+#define MCDE_OVL0CONF2_BP(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CONF2, BP, __x)
+#define MCDE_OVL0CONF2_ALPHAVALUE_SHIFT 1
+#define MCDE_OVL0CONF2_ALPHAVALUE_MASK 0x000001FE
+#define MCDE_OVL0CONF2_ALPHAVALUE(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CONF2, ALPHAVALUE, __x)
+#define MCDE_OVL0CONF2_OPQ_SHIFT 9
+#define MCDE_OVL0CONF2_OPQ_MASK 0x00000200
+#define MCDE_OVL0CONF2_OPQ(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CONF2, OPQ, __x)
+#define MCDE_OVL0CONF2_PIXOFF_SHIFT 10
+#define MCDE_OVL0CONF2_PIXOFF_MASK 0x0000FC00
+#define MCDE_OVL0CONF2_PIXOFF(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CONF2, PIXOFF, __x)
+#define MCDE_OVL0CONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16
+#define MCDE_OVL0CONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000
+#define MCDE_OVL0CONF2_PIXELFETCHERWATERMARKLEVEL(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CONF2, PIXELFETCHERWATERMARKLEVEL, __x)
+#define MCDE_OVL1CONF2 0x00000428
+#define MCDE_OVL1CONF2_BP_SHIFT 0
+#define MCDE_OVL1CONF2_BP_MASK 0x00000001
+#define MCDE_OVL1CONF2_BP_PER_PIXEL_ALPHA 0
+#define MCDE_OVL1CONF2_BP_CONSTANT_ALPHA 1
+#define MCDE_OVL1CONF2_BP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CONF2, BP, MCDE_OVL1CONF2_BP_##__x)
+#define MCDE_OVL1CONF2_BP(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CONF2, BP, __x)
+#define MCDE_OVL1CONF2_ALPHAVALUE_SHIFT 1
+#define MCDE_OVL1CONF2_ALPHAVALUE_MASK 0x000001FE
+#define MCDE_OVL1CONF2_ALPHAVALUE(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CONF2, ALPHAVALUE, __x)
+#define MCDE_OVL1CONF2_OPQ_SHIFT 9
+#define MCDE_OVL1CONF2_OPQ_MASK 0x00000200
+#define MCDE_OVL1CONF2_OPQ(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CONF2, OPQ, __x)
+#define MCDE_OVL1CONF2_PIXOFF_SHIFT 10
+#define MCDE_OVL1CONF2_PIXOFF_MASK 0x0000FC00
+#define MCDE_OVL1CONF2_PIXOFF(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CONF2, PIXOFF, __x)
+#define MCDE_OVL1CONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16
+#define MCDE_OVL1CONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000
+#define MCDE_OVL1CONF2_PIXELFETCHERWATERMARKLEVEL(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CONF2, PIXELFETCHERWATERMARKLEVEL, __x)
+#define MCDE_OVL2CONF2 0x00000448
+#define MCDE_OVL2CONF2_BP_SHIFT 0
+#define MCDE_OVL2CONF2_BP_MASK 0x00000001
+#define MCDE_OVL2CONF2_BP_PER_PIXEL_ALPHA 0
+#define MCDE_OVL2CONF2_BP_CONSTANT_ALPHA 1
+#define MCDE_OVL2CONF2_BP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CONF2, BP, MCDE_OVL2CONF2_BP_##__x)
+#define MCDE_OVL2CONF2_BP(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CONF2, BP, __x)
+#define MCDE_OVL2CONF2_ALPHAVALUE_SHIFT 1
+#define MCDE_OVL2CONF2_ALPHAVALUE_MASK 0x000001FE
+#define MCDE_OVL2CONF2_ALPHAVALUE(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CONF2, ALPHAVALUE, __x)
+#define MCDE_OVL2CONF2_OPQ_SHIFT 9
+#define MCDE_OVL2CONF2_OPQ_MASK 0x00000200
+#define MCDE_OVL2CONF2_OPQ(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CONF2, OPQ, __x)
+#define MCDE_OVL2CONF2_PIXOFF_SHIFT 10
+#define MCDE_OVL2CONF2_PIXOFF_MASK 0x0000FC00
+#define MCDE_OVL2CONF2_PIXOFF(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CONF2, PIXOFF, __x)
+#define MCDE_OVL2CONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16
+#define MCDE_OVL2CONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000
+#define MCDE_OVL2CONF2_PIXELFETCHERWATERMARKLEVEL(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CONF2, PIXELFETCHERWATERMARKLEVEL, __x)
+#define MCDE_OVL3CONF2 0x00000468
+#define MCDE_OVL3CONF2_BP_SHIFT 0
+#define MCDE_OVL3CONF2_BP_MASK 0x00000001
+#define MCDE_OVL3CONF2_BP_PER_PIXEL_ALPHA 0
+#define MCDE_OVL3CONF2_BP_CONSTANT_ALPHA 1
+#define MCDE_OVL3CONF2_BP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CONF2, BP, MCDE_OVL3CONF2_BP_##__x)
+#define MCDE_OVL3CONF2_BP(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CONF2, BP, __x)
+#define MCDE_OVL3CONF2_ALPHAVALUE_SHIFT 1
+#define MCDE_OVL3CONF2_ALPHAVALUE_MASK 0x000001FE
+#define MCDE_OVL3CONF2_ALPHAVALUE(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CONF2, ALPHAVALUE, __x)
+#define MCDE_OVL3CONF2_OPQ_SHIFT 9
+#define MCDE_OVL3CONF2_OPQ_MASK 0x00000200
+#define MCDE_OVL3CONF2_OPQ(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CONF2, OPQ, __x)
+#define MCDE_OVL3CONF2_PIXOFF_SHIFT 10
+#define MCDE_OVL3CONF2_PIXOFF_MASK 0x0000FC00
+#define MCDE_OVL3CONF2_PIXOFF(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CONF2, PIXOFF, __x)
+#define MCDE_OVL3CONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16
+#define MCDE_OVL3CONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000
+#define MCDE_OVL3CONF2_PIXELFETCHERWATERMARKLEVEL(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CONF2, PIXELFETCHERWATERMARKLEVEL, __x)
+#define MCDE_OVL4CONF2 0x00000488
+#define MCDE_OVL4CONF2_BP_SHIFT 0
+#define MCDE_OVL4CONF2_BP_MASK 0x00000001
+#define MCDE_OVL4CONF2_BP_PER_PIXEL_ALPHA 0
+#define MCDE_OVL4CONF2_BP_CONSTANT_ALPHA 1
+#define MCDE_OVL4CONF2_BP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CONF2, BP, MCDE_OVL4CONF2_BP_##__x)
+#define MCDE_OVL4CONF2_BP(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CONF2, BP, __x)
+#define MCDE_OVL4CONF2_ALPHAVALUE_SHIFT 1
+#define MCDE_OVL4CONF2_ALPHAVALUE_MASK 0x000001FE
+#define MCDE_OVL4CONF2_ALPHAVALUE(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CONF2, ALPHAVALUE, __x)
+#define MCDE_OVL4CONF2_OPQ_SHIFT 9
+#define MCDE_OVL4CONF2_OPQ_MASK 0x00000200
+#define MCDE_OVL4CONF2_OPQ(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CONF2, OPQ, __x)
+#define MCDE_OVL4CONF2_PIXOFF_SHIFT 10
+#define MCDE_OVL4CONF2_PIXOFF_MASK 0x0000FC00
+#define MCDE_OVL4CONF2_PIXOFF(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CONF2, PIXOFF, __x)
+#define MCDE_OVL4CONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16
+#define MCDE_OVL4CONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000
+#define MCDE_OVL4CONF2_PIXELFETCHERWATERMARKLEVEL(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CONF2, PIXELFETCHERWATERMARKLEVEL, __x)
+#define MCDE_OVL5CONF2 0x000004A8
+#define MCDE_OVL5CONF2_BP_SHIFT 0
+#define MCDE_OVL5CONF2_BP_MASK 0x00000001
+#define MCDE_OVL5CONF2_BP_PER_PIXEL_ALPHA 0
+#define MCDE_OVL5CONF2_BP_CONSTANT_ALPHA 1
+#define MCDE_OVL5CONF2_BP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CONF2, BP, MCDE_OVL5CONF2_BP_##__x)
+#define MCDE_OVL5CONF2_BP(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CONF2, BP, __x)
+#define MCDE_OVL5CONF2_ALPHAVALUE_SHIFT 1
+#define MCDE_OVL5CONF2_ALPHAVALUE_MASK 0x000001FE
+#define MCDE_OVL5CONF2_ALPHAVALUE(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CONF2, ALPHAVALUE, __x)
+#define MCDE_OVL5CONF2_OPQ_SHIFT 9
+#define MCDE_OVL5CONF2_OPQ_MASK 0x00000200
+#define MCDE_OVL5CONF2_OPQ(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CONF2, OPQ, __x)
+#define MCDE_OVL5CONF2_PIXOFF_SHIFT 10
+#define MCDE_OVL5CONF2_PIXOFF_MASK 0x0000FC00
+#define MCDE_OVL5CONF2_PIXOFF(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CONF2, PIXOFF, __x)
+#define MCDE_OVL5CONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16
+#define MCDE_OVL5CONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000
+#define MCDE_OVL5CONF2_PIXELFETCHERWATERMARKLEVEL(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CONF2, PIXELFETCHERWATERMARKLEVEL, __x)
+#define MCDE_OVL0LJINC 0x0000040C
+#define MCDE_OVL0LJINC_GROUPOFFSET 0x20
+#define MCDE_OVL0LJINC_LJINC_SHIFT 0
+#define MCDE_OVL0LJINC_LJINC_MASK 0xFFFFFFFF
+#define MCDE_OVL0LJINC_LJINC(__x) \
+ MCDE_VAL2REG(MCDE_OVL0LJINC, LJINC, __x)
+#define MCDE_OVL1LJINC 0x0000042C
+#define MCDE_OVL1LJINC_LJINC_SHIFT 0
+#define MCDE_OVL1LJINC_LJINC_MASK 0xFFFFFFFF
+#define MCDE_OVL1LJINC_LJINC(__x) \
+ MCDE_VAL2REG(MCDE_OVL1LJINC, LJINC, __x)
+#define MCDE_OVL2LJINC 0x0000044C
+#define MCDE_OVL2LJINC_LJINC_SHIFT 0
+#define MCDE_OVL2LJINC_LJINC_MASK 0xFFFFFFFF
+#define MCDE_OVL2LJINC_LJINC(__x) \
+ MCDE_VAL2REG(MCDE_OVL2LJINC, LJINC, __x)
+#define MCDE_OVL3LJINC 0x0000046C
+#define MCDE_OVL3LJINC_LJINC_SHIFT 0
+#define MCDE_OVL3LJINC_LJINC_MASK 0xFFFFFFFF
+#define MCDE_OVL3LJINC_LJINC(__x) \
+ MCDE_VAL2REG(MCDE_OVL3LJINC, LJINC, __x)
+#define MCDE_OVL4LJINC 0x0000048C
+#define MCDE_OVL4LJINC_LJINC_SHIFT 0
+#define MCDE_OVL4LJINC_LJINC_MASK 0xFFFFFFFF
+#define MCDE_OVL4LJINC_LJINC(__x) \
+ MCDE_VAL2REG(MCDE_OVL4LJINC, LJINC, __x)
+#define MCDE_OVL5LJINC 0x000004AC
+#define MCDE_OVL5LJINC_LJINC_SHIFT 0
+#define MCDE_OVL5LJINC_LJINC_MASK 0xFFFFFFFF
+#define MCDE_OVL5LJINC_LJINC(__x) \
+ MCDE_VAL2REG(MCDE_OVL5LJINC, LJINC, __x)
+#define MCDE_OVL0CROP 0x00000410
+#define MCDE_OVL0CROP_GROUPOFFSET 0x20
+#define MCDE_OVL0CROP_TMRGN_SHIFT 0
+#define MCDE_OVL0CROP_TMRGN_MASK 0x003FFFFF
+#define MCDE_OVL0CROP_TMRGN(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CROP, TMRGN, __x)
+#define MCDE_OVL0CROP_LMRGN_SHIFT 22
+#define MCDE_OVL0CROP_LMRGN_MASK 0xFFC00000
+#define MCDE_OVL0CROP_LMRGN(__x) \
+ MCDE_VAL2REG(MCDE_OVL0CROP, LMRGN, __x)
+#define MCDE_OVL1CROP 0x00000430
+#define MCDE_OVL1CROP_TMRGN_SHIFT 0
+#define MCDE_OVL1CROP_TMRGN_MASK 0x003FFFFF
+#define MCDE_OVL1CROP_TMRGN(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CROP, TMRGN, __x)
+#define MCDE_OVL1CROP_LMRGN_SHIFT 22
+#define MCDE_OVL1CROP_LMRGN_MASK 0xFFC00000
+#define MCDE_OVL1CROP_LMRGN(__x) \
+ MCDE_VAL2REG(MCDE_OVL1CROP, LMRGN, __x)
+#define MCDE_OVL2CROP 0x00000450
+#define MCDE_OVL2CROP_TMRGN_SHIFT 0
+#define MCDE_OVL2CROP_TMRGN_MASK 0x003FFFFF
+#define MCDE_OVL2CROP_TMRGN(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CROP, TMRGN, __x)
+#define MCDE_OVL2CROP_LMRGN_SHIFT 22
+#define MCDE_OVL2CROP_LMRGN_MASK 0xFFC00000
+#define MCDE_OVL2CROP_LMRGN(__x) \
+ MCDE_VAL2REG(MCDE_OVL2CROP, LMRGN, __x)
+#define MCDE_OVL3CROP 0x00000470
+#define MCDE_OVL3CROP_TMRGN_SHIFT 0
+#define MCDE_OVL3CROP_TMRGN_MASK 0x003FFFFF
+#define MCDE_OVL3CROP_TMRGN(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CROP, TMRGN, __x)
+#define MCDE_OVL3CROP_LMRGN_SHIFT 22
+#define MCDE_OVL3CROP_LMRGN_MASK 0xFFC00000
+#define MCDE_OVL3CROP_LMRGN(__x) \
+ MCDE_VAL2REG(MCDE_OVL3CROP, LMRGN, __x)
+#define MCDE_OVL4CROP 0x00000490
+#define MCDE_OVL4CROP_TMRGN_SHIFT 0
+#define MCDE_OVL4CROP_TMRGN_MASK 0x003FFFFF
+#define MCDE_OVL4CROP_TMRGN(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CROP, TMRGN, __x)
+#define MCDE_OVL4CROP_LMRGN_SHIFT 22
+#define MCDE_OVL4CROP_LMRGN_MASK 0xFFC00000
+#define MCDE_OVL4CROP_LMRGN(__x) \
+ MCDE_VAL2REG(MCDE_OVL4CROP, LMRGN, __x)
+#define MCDE_OVL5CROP 0x000004B0
+#define MCDE_OVL5CROP_TMRGN_SHIFT 0
+#define MCDE_OVL5CROP_TMRGN_MASK 0x003FFFFF
+#define MCDE_OVL5CROP_TMRGN(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CROP, TMRGN, __x)
+#define MCDE_OVL5CROP_LMRGN_SHIFT 22
+#define MCDE_OVL5CROP_LMRGN_MASK 0xFFC00000
+#define MCDE_OVL5CROP_LMRGN(__x) \
+ MCDE_VAL2REG(MCDE_OVL5CROP, LMRGN, __x)
+#define MCDE_OVL0COMP 0x00000414
+#define MCDE_OVL0COMP_GROUPOFFSET 0x20
+#define MCDE_OVL0COMP_XPOS_SHIFT 0
+#define MCDE_OVL0COMP_XPOS_MASK 0x000007FF
+#define MCDE_OVL0COMP_XPOS(__x) \
+ MCDE_VAL2REG(MCDE_OVL0COMP, XPOS, __x)
+#define MCDE_OVL0COMP_CH_ID_SHIFT 11
+#define MCDE_OVL0COMP_CH_ID_MASK 0x00007800
+#define MCDE_OVL0COMP_CH_ID(__x) \
+ MCDE_VAL2REG(MCDE_OVL0COMP, CH_ID, __x)
+#define MCDE_OVL0COMP_YPOS_SHIFT 16
+#define MCDE_OVL0COMP_YPOS_MASK 0x07FF0000
+#define MCDE_OVL0COMP_YPOS(__x) \
+ MCDE_VAL2REG(MCDE_OVL0COMP, YPOS, __x)
+#define MCDE_OVL0COMP_Z_SHIFT 27
+#define MCDE_OVL0COMP_Z_MASK 0x78000000
+#define MCDE_OVL0COMP_Z(__x) \
+ MCDE_VAL2REG(MCDE_OVL0COMP, Z, __x)
+#define MCDE_OVL1COMP 0x00000434
+#define MCDE_OVL1COMP_XPOS_SHIFT 0
+#define MCDE_OVL1COMP_XPOS_MASK 0x000007FF
+#define MCDE_OVL1COMP_XPOS(__x) \
+ MCDE_VAL2REG(MCDE_OVL1COMP, XPOS, __x)
+#define MCDE_OVL1COMP_CH_ID_SHIFT 11
+#define MCDE_OVL1COMP_CH_ID_MASK 0x00007800
+#define MCDE_OVL1COMP_CH_ID(__x) \
+ MCDE_VAL2REG(MCDE_OVL1COMP, CH_ID, __x)
+#define MCDE_OVL1COMP_YPOS_SHIFT 16
+#define MCDE_OVL1COMP_YPOS_MASK 0x07FF0000
+#define MCDE_OVL1COMP_YPOS(__x) \
+ MCDE_VAL2REG(MCDE_OVL1COMP, YPOS, __x)
+#define MCDE_OVL1COMP_Z_SHIFT 27
+#define MCDE_OVL1COMP_Z_MASK 0x78000000
+#define MCDE_OVL1COMP_Z(__x) \
+ MCDE_VAL2REG(MCDE_OVL1COMP, Z, __x)
+#define MCDE_OVL2COMP 0x00000454
+#define MCDE_OVL2COMP_XPOS_SHIFT 0
+#define MCDE_OVL2COMP_XPOS_MASK 0x000007FF
+#define MCDE_OVL2COMP_XPOS(__x) \
+ MCDE_VAL2REG(MCDE_OVL2COMP, XPOS, __x)
+#define MCDE_OVL2COMP_CH_ID_SHIFT 11
+#define MCDE_OVL2COMP_CH_ID_MASK 0x00007800
+#define MCDE_OVL2COMP_CH_ID(__x) \
+ MCDE_VAL2REG(MCDE_OVL2COMP, CH_ID, __x)
+#define MCDE_OVL2COMP_YPOS_SHIFT 16
+#define MCDE_OVL2COMP_YPOS_MASK 0x07FF0000
+#define MCDE_OVL2COMP_YPOS(__x) \
+ MCDE_VAL2REG(MCDE_OVL2COMP, YPOS, __x)
+#define MCDE_OVL2COMP_Z_SHIFT 27
+#define MCDE_OVL2COMP_Z_MASK 0x78000000
+#define MCDE_OVL2COMP_Z(__x) \
+ MCDE_VAL2REG(MCDE_OVL2COMP, Z, __x)
+#define MCDE_OVL3COMP 0x00000474
+#define MCDE_OVL3COMP_XPOS_SHIFT 0
+#define MCDE_OVL3COMP_XPOS_MASK 0x000007FF
+#define MCDE_OVL3COMP_XPOS(__x) \
+ MCDE_VAL2REG(MCDE_OVL3COMP, XPOS, __x)
+#define MCDE_OVL3COMP_CH_ID_SHIFT 11
+#define MCDE_OVL3COMP_CH_ID_MASK 0x00007800
+#define MCDE_OVL3COMP_CH_ID(__x) \
+ MCDE_VAL2REG(MCDE_OVL3COMP, CH_ID, __x)
+#define MCDE_OVL3COMP_YPOS_SHIFT 16
+#define MCDE_OVL3COMP_YPOS_MASK 0x07FF0000
+#define MCDE_OVL3COMP_YPOS(__x) \
+ MCDE_VAL2REG(MCDE_OVL3COMP, YPOS, __x)
+#define MCDE_OVL3COMP_Z_SHIFT 27
+#define MCDE_OVL3COMP_Z_MASK 0x78000000
+#define MCDE_OVL3COMP_Z(__x) \
+ MCDE_VAL2REG(MCDE_OVL3COMP, Z, __x)
+#define MCDE_OVL4COMP 0x00000494
+#define MCDE_OVL4COMP_XPOS_SHIFT 0
+#define MCDE_OVL4COMP_XPOS_MASK 0x000007FF
+#define MCDE_OVL4COMP_XPOS(__x) \
+ MCDE_VAL2REG(MCDE_OVL4COMP, XPOS, __x)
+#define MCDE_OVL4COMP_CH_ID_SHIFT 11
+#define MCDE_OVL4COMP_CH_ID_MASK 0x00007800
+#define MCDE_OVL4COMP_CH_ID(__x) \
+ MCDE_VAL2REG(MCDE_OVL4COMP, CH_ID, __x)
+#define MCDE_OVL4COMP_YPOS_SHIFT 16
+#define MCDE_OVL4COMP_YPOS_MASK 0x07FF0000
+#define MCDE_OVL4COMP_YPOS(__x) \
+ MCDE_VAL2REG(MCDE_OVL4COMP, YPOS, __x)
+#define MCDE_OVL4COMP_Z_SHIFT 27
+#define MCDE_OVL4COMP_Z_MASK 0x78000000
+#define MCDE_OVL4COMP_Z(__x) \
+ MCDE_VAL2REG(MCDE_OVL4COMP, Z, __x)
+#define MCDE_OVL5COMP 0x000004B4
+#define MCDE_OVL5COMP_XPOS_SHIFT 0
+#define MCDE_OVL5COMP_XPOS_MASK 0x000007FF
+#define MCDE_OVL5COMP_XPOS(__x) \
+ MCDE_VAL2REG(MCDE_OVL5COMP, XPOS, __x)
+#define MCDE_OVL5COMP_CH_ID_SHIFT 11
+#define MCDE_OVL5COMP_CH_ID_MASK 0x00007800
+#define MCDE_OVL5COMP_CH_ID(__x) \
+ MCDE_VAL2REG(MCDE_OVL5COMP, CH_ID, __x)
+#define MCDE_OVL5COMP_YPOS_SHIFT 16
+#define MCDE_OVL5COMP_YPOS_MASK 0x07FF0000
+#define MCDE_OVL5COMP_YPOS(__x) \
+ MCDE_VAL2REG(MCDE_OVL5COMP, YPOS, __x)
+#define MCDE_OVL5COMP_Z_SHIFT 27
+#define MCDE_OVL5COMP_Z_MASK 0x78000000
+#define MCDE_OVL5COMP_Z(__x) \
+ MCDE_VAL2REG(MCDE_OVL5COMP, Z, __x)
+#define MCDE_CHNL0CONF 0x00000600
+#define MCDE_CHNL0CONF_GROUPOFFSET 0x20
+#define MCDE_CHNL0CONF_PPL_SHIFT 0
+#define MCDE_CHNL0CONF_PPL_MASK 0x000007FF
+#define MCDE_CHNL0CONF_PPL(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0CONF, PPL, __x)
+#define MCDE_CHNL0CONF_LPF_SHIFT 16
+#define MCDE_CHNL0CONF_LPF_MASK 0x07FF0000
+#define MCDE_CHNL0CONF_LPF(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0CONF, LPF, __x)
+#define MCDE_CHNL1CONF 0x00000620
+#define MCDE_CHNL1CONF_PPL_SHIFT 0
+#define MCDE_CHNL1CONF_PPL_MASK 0x000007FF
+#define MCDE_CHNL1CONF_PPL(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1CONF, PPL, __x)
+#define MCDE_CHNL1CONF_LPF_SHIFT 16
+#define MCDE_CHNL1CONF_LPF_MASK 0x07FF0000
+#define MCDE_CHNL1CONF_LPF(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1CONF, LPF, __x)
+#define MCDE_CHNL2CONF 0x00000640
+#define MCDE_CHNL2CONF_PPL_SHIFT 0
+#define MCDE_CHNL2CONF_PPL_MASK 0x000007FF
+#define MCDE_CHNL2CONF_PPL(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2CONF, PPL, __x)
+#define MCDE_CHNL2CONF_LPF_SHIFT 16
+#define MCDE_CHNL2CONF_LPF_MASK 0x07FF0000
+#define MCDE_CHNL2CONF_LPF(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2CONF, LPF, __x)
+#define MCDE_CHNL3CONF 0x00000660
+#define MCDE_CHNL3CONF_PPL_SHIFT 0
+#define MCDE_CHNL3CONF_PPL_MASK 0x000007FF
+#define MCDE_CHNL3CONF_PPL(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3CONF, PPL, __x)
+#define MCDE_CHNL3CONF_LPF_SHIFT 16
+#define MCDE_CHNL3CONF_LPF_MASK 0x07FF0000
+#define MCDE_CHNL3CONF_LPF(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3CONF, LPF, __x)
+#define MCDE_CHNL0STAT 0x00000604
+#define MCDE_CHNL0STAT_GROUPOFFSET 0x20
+#define MCDE_CHNL0STAT_CHNLRD_SHIFT 0
+#define MCDE_CHNL0STAT_CHNLRD_MASK 0x00000001
+#define MCDE_CHNL0STAT_CHNLRD(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0STAT, CHNLRD, __x)
+#define MCDE_CHNL0STAT_CHNLA_SHIFT 1
+#define MCDE_CHNL0STAT_CHNLA_MASK 0x00000002
+#define MCDE_CHNL0STAT_CHNLA(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0STAT, CHNLA, __x)
+#define MCDE_CHNL0STAT_CHNLBLBCKGND_EN_SHIFT 16
+#define MCDE_CHNL0STAT_CHNLBLBCKGND_EN_MASK 0x00010000
+#define MCDE_CHNL0STAT_CHNLBLBCKGND_EN(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0STAT, CHNLBLBCKGND_EN, __x)
+#define MCDE_CHNL1STAT 0x00000624
+#define MCDE_CHNL1STAT_CHNLRD_SHIFT 0
+#define MCDE_CHNL1STAT_CHNLRD_MASK 0x00000001
+#define MCDE_CHNL1STAT_CHNLRD(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1STAT, CHNLRD, __x)
+#define MCDE_CHNL1STAT_CHNLA_SHIFT 1
+#define MCDE_CHNL1STAT_CHNLA_MASK 0x00000002
+#define MCDE_CHNL1STAT_CHNLA(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1STAT, CHNLA, __x)
+#define MCDE_CHNL1STAT_CHNLBLBCKGND_EN_SHIFT 16
+#define MCDE_CHNL1STAT_CHNLBLBCKGND_EN_MASK 0x00010000
+#define MCDE_CHNL1STAT_CHNLBLBCKGND_EN(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1STAT, CHNLBLBCKGND_EN, __x)
+#define MCDE_CHNL2STAT 0x00000644
+#define MCDE_CHNL2STAT_CHNLRD_SHIFT 0
+#define MCDE_CHNL2STAT_CHNLRD_MASK 0x00000001
+#define MCDE_CHNL2STAT_CHNLRD(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2STAT, CHNLRD, __x)
+#define MCDE_CHNL2STAT_CHNLA_SHIFT 1
+#define MCDE_CHNL2STAT_CHNLA_MASK 0x00000002
+#define MCDE_CHNL2STAT_CHNLA(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2STAT, CHNLA, __x)
+#define MCDE_CHNL2STAT_CHNLBLBCKGND_EN_SHIFT 16
+#define MCDE_CHNL2STAT_CHNLBLBCKGND_EN_MASK 0x00010000
+#define MCDE_CHNL2STAT_CHNLBLBCKGND_EN(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2STAT, CHNLBLBCKGND_EN, __x)
+#define MCDE_CHNL3STAT 0x00000664
+#define MCDE_CHNL3STAT_CHNLRD_SHIFT 0
+#define MCDE_CHNL3STAT_CHNLRD_MASK 0x00000001
+#define MCDE_CHNL3STAT_CHNLRD(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3STAT, CHNLRD, __x)
+#define MCDE_CHNL3STAT_CHNLA_SHIFT 1
+#define MCDE_CHNL3STAT_CHNLA_MASK 0x00000002
+#define MCDE_CHNL3STAT_CHNLA(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3STAT, CHNLA, __x)
+#define MCDE_CHNL3STAT_CHNLBLBCKGND_EN_SHIFT 16
+#define MCDE_CHNL3STAT_CHNLBLBCKGND_EN_MASK 0x00010000
+#define MCDE_CHNL3STAT_CHNLBLBCKGND_EN(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3STAT, CHNLBLBCKGND_EN, __x)
+#define MCDE_CHNL0SYNCHMOD 0x00000608
+#define MCDE_CHNL0SYNCHMOD_GROUPOFFSET 0x20
+#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SHIFT 0
+#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_MASK 0x00000003
+#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_OUTPUT 0
+#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_AUTO 1
+#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE 2
+#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_EXTERNAL 3
+#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0SYNCHMOD, SRC_SYNCH, \
+ MCDE_CHNL0SYNCHMOD_SRC_SYNCH_##__x)
+#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0SYNCHMOD, SRC_SYNCH, __x)
+#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_SHIFT 2
+#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_MASK 0x0000001C
+#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_FORMATTER 0
+#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_VSYNC0 1
+#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_VSYNC1 2
+#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0SYNCHMOD, OUT_SYNCH_SRC, \
+ MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_##__x)
+#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0SYNCHMOD, OUT_SYNCH_SRC, __x)
+#define MCDE_CHNL1SYNCHMOD 0x00000628
+#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_SHIFT 0
+#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_MASK 0x00000003
+#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_OUTPUT 0
+#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_AUTO 1
+#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_SOFTWARE 2
+#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_EXTERNAL 3
+#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1SYNCHMOD, SRC_SYNCH, \
+ MCDE_CHNL1SYNCHMOD_SRC_SYNCH_##__x)
+#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1SYNCHMOD, SRC_SYNCH, __x)
+#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_SHIFT 2
+#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_MASK 0x0000001C
+#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_FORMATTER 0
+#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_VSYNC0 1
+#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_VSYNC1 2
+#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1SYNCHMOD, OUT_SYNCH_SRC, \
+ MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_##__x)
+#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1SYNCHMOD, OUT_SYNCH_SRC, __x)
+#define MCDE_CHNL2SYNCHMOD 0x00000648
+#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_SHIFT 0
+#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_MASK 0x00000003
+#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_OUTPUT 0
+#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_AUTO 1
+#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_SOFTWARE 2
+#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_EXTERNAL 3
+#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2SYNCHMOD, SRC_SYNCH, \
+ MCDE_CHNL2SYNCHMOD_SRC_SYNCH_##__x)
+#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2SYNCHMOD, SRC_SYNCH, __x)
+#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_SHIFT 2
+#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_MASK 0x0000001C
+#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_FORMATTER 0
+#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_VSYNC0 1
+#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_VSYNC1 2
+#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2SYNCHMOD, OUT_SYNCH_SRC, \
+ MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_##__x)
+#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2SYNCHMOD, OUT_SYNCH_SRC, __x)
+#define MCDE_CHNL3SYNCHMOD 0x00000668
+#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_SHIFT 0
+#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_MASK 0x00000003
+#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_OUTPUT 0
+#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_AUTO 1
+#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_SOFTWARE 2
+#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_EXTERNAL 3
+#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3SYNCHMOD, SRC_SYNCH, \
+ MCDE_CHNL3SYNCHMOD_SRC_SYNCH_##__x)
+#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3SYNCHMOD, SRC_SYNCH, __x)
+#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_SHIFT 2
+#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_MASK 0x0000001C
+#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_FORMATTER 0
+#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_VSYNC0 1
+#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_VSYNC1 2
+#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3SYNCHMOD, OUT_SYNCH_SRC, \
+ MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_##__x)
+#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3SYNCHMOD, OUT_SYNCH_SRC, __x)
+#define MCDE_CHNL0SYNCHSW 0x0000060C
+#define MCDE_CHNL0SYNCHSW_GROUPOFFSET 0x20
+#define MCDE_CHNL0SYNCHSW_SW_TRIG_SHIFT 0
+#define MCDE_CHNL0SYNCHSW_SW_TRIG_MASK 0x00000001
+#define MCDE_CHNL0SYNCHSW_SW_TRIG(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0SYNCHSW, SW_TRIG, __x)
+#define MCDE_CHNL1SYNCHSW 0x0000062C
+#define MCDE_CHNL1SYNCHSW_SW_TRIG_SHIFT 0
+#define MCDE_CHNL1SYNCHSW_SW_TRIG_MASK 0x00000001
+#define MCDE_CHNL1SYNCHSW_SW_TRIG(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1SYNCHSW, SW_TRIG, __x)
+#define MCDE_CHNL2SYNCHSW 0x0000064C
+#define MCDE_CHNL2SYNCHSW_SW_TRIG_SHIFT 0
+#define MCDE_CHNL2SYNCHSW_SW_TRIG_MASK 0x00000001
+#define MCDE_CHNL2SYNCHSW_SW_TRIG(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2SYNCHSW, SW_TRIG, __x)
+#define MCDE_CHNL3SYNCHSW 0x0000066C
+#define MCDE_CHNL3SYNCHSW_SW_TRIG_SHIFT 0
+#define MCDE_CHNL3SYNCHSW_SW_TRIG_MASK 0x00000001
+#define MCDE_CHNL3SYNCHSW_SW_TRIG(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3SYNCHSW, SW_TRIG, __x)
+#define MCDE_CHNL0BCKGNDCOL 0x00000610
+#define MCDE_CHNL0BCKGNDCOL_GROUPOFFSET 0x20
+#define MCDE_CHNL0BCKGNDCOL_B_SHIFT 0
+#define MCDE_CHNL0BCKGNDCOL_B_MASK 0x000000FF
+#define MCDE_CHNL0BCKGNDCOL_B(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0BCKGNDCOL, B, __x)
+#define MCDE_CHNL0BCKGNDCOL_G_SHIFT 8
+#define MCDE_CHNL0BCKGNDCOL_G_MASK 0x0000FF00
+#define MCDE_CHNL0BCKGNDCOL_G(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0BCKGNDCOL, G, __x)
+#define MCDE_CHNL0BCKGNDCOL_R_SHIFT 16
+#define MCDE_CHNL0BCKGNDCOL_R_MASK 0x00FF0000
+#define MCDE_CHNL0BCKGNDCOL_R(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0BCKGNDCOL, R, __x)
+#define MCDE_CHNL1BCKGNDCOL 0x00000630
+#define MCDE_CHNL1BCKGNDCOL_B_SHIFT 0
+#define MCDE_CHNL1BCKGNDCOL_B_MASK 0x000000FF
+#define MCDE_CHNL1BCKGNDCOL_B(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1BCKGNDCOL, B, __x)
+#define MCDE_CHNL1BCKGNDCOL_G_SHIFT 8
+#define MCDE_CHNL1BCKGNDCOL_G_MASK 0x0000FF00
+#define MCDE_CHNL1BCKGNDCOL_G(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1BCKGNDCOL, G, __x)
+#define MCDE_CHNL1BCKGNDCOL_R_SHIFT 16
+#define MCDE_CHNL1BCKGNDCOL_R_MASK 0x00FF0000
+#define MCDE_CHNL1BCKGNDCOL_R(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1BCKGNDCOL, R, __x)
+#define MCDE_CHNL2BCKGNDCOL 0x00000650
+#define MCDE_CHNL2BCKGNDCOL_B_SHIFT 0
+#define MCDE_CHNL2BCKGNDCOL_B_MASK 0x000000FF
+#define MCDE_CHNL2BCKGNDCOL_B(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2BCKGNDCOL, B, __x)
+#define MCDE_CHNL2BCKGNDCOL_G_SHIFT 8
+#define MCDE_CHNL2BCKGNDCOL_G_MASK 0x0000FF00
+#define MCDE_CHNL2BCKGNDCOL_G(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2BCKGNDCOL, G, __x)
+#define MCDE_CHNL2BCKGNDCOL_R_SHIFT 16
+#define MCDE_CHNL2BCKGNDCOL_R_MASK 0x00FF0000
+#define MCDE_CHNL2BCKGNDCOL_R(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2BCKGNDCOL, R, __x)
+#define MCDE_CHNL3BCKGNDCOL 0x00000670
+#define MCDE_CHNL3BCKGNDCOL_B_SHIFT 0
+#define MCDE_CHNL3BCKGNDCOL_B_MASK 0x000000FF
+#define MCDE_CHNL3BCKGNDCOL_B(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3BCKGNDCOL, B, __x)
+#define MCDE_CHNL3BCKGNDCOL_G_SHIFT 8
+#define MCDE_CHNL3BCKGNDCOL_G_MASK 0x0000FF00
+#define MCDE_CHNL3BCKGNDCOL_G(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3BCKGNDCOL, G, __x)
+#define MCDE_CHNL3BCKGNDCOL_R_SHIFT 16
+#define MCDE_CHNL3BCKGNDCOL_R_MASK 0x00FF0000
+#define MCDE_CHNL3BCKGNDCOL_R(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3BCKGNDCOL, R, __x)
+#define MCDE_CHNL0PRIO_V1 0x00000614
+#define MCDE_CHNL0PRIO_V1_GROUPOFFSET 0x20
+#define MCDE_CHNL0PRIO_V1_CHNLPRIO_SHIFT 0
+#define MCDE_CHNL0PRIO_V1_CHNLPRIO_MASK 0x0000000F
+#define MCDE_CHNL0PRIO_V1_CHNLPRIO(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0PRIO_V1, CHNLPRIO, __x)
+#define MCDE_CHNL1PRIO_V1 0x00000634
+#define MCDE_CHNL1PRIO_V1_CHNLPRIO_SHIFT 0
+#define MCDE_CHNL1PRIO_V1_CHNLPRIO_MASK 0x0000000F
+#define MCDE_CHNL1PRIO_V1_CHNLPRIO(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1PRIO_V1, CHNLPRIO, __x)
+#define MCDE_CHNL2PRIO_V1 0x00000654
+#define MCDE_CHNL2PRIO_V1_CHNLPRIO_SHIFT 0
+#define MCDE_CHNL2PRIO_V1_CHNLPRIO_MASK 0x0000000F
+#define MCDE_CHNL2PRIO_V1_CHNLPRIO(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2PRIO_V1, CHNLPRIO, __x)
+#define MCDE_CHNL3PRIO_V1 0x00000674
+#define MCDE_CHNL3PRIO_V1_CHNLPRIO_SHIFT 0
+#define MCDE_CHNL3PRIO_V1_CHNLPRIO_MASK 0x0000000F
+#define MCDE_CHNL3PRIO_V1_CHNLPRIO(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3PRIO_V1, CHNLPRIO, __x)
+#define MCDE_CHNL0MUXING_V2 0x00000614
+#define MCDE_CHNL0MUXING_V2_GROUPOFFSET 0x20
+#define MCDE_CHNL0MUXING_V2_FIFO_ID_SHIFT 0
+#define MCDE_CHNL0MUXING_V2_FIFO_ID_MASK 0x00000007
+#define MCDE_CHNL0MUXING_V2_FIFO_ID_FIFO_A 0
+#define MCDE_CHNL0MUXING_V2_FIFO_ID_FIFO_B 1
+#define MCDE_CHNL0MUXING_V2_FIFO_ID_FIFO_C0 2
+#define MCDE_CHNL0MUXING_V2_FIFO_ID_FIFO_C1 3
+#define MCDE_CHNL0MUXING_V2_FIFO_ID_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0MUXING_V2, FIFO_ID, \
+ MCDE_CHNL0MUXING_V2_FIFO_ID_##__x)
+#define MCDE_CHNL0MUXING_V2_FIFO_ID(__x) \
+ MCDE_VAL2REG(MCDE_CHNL0MUXING_V2, FIFO_ID, __x)
+#define MCDE_CHNL1MUXING_V2 0x00000634
+#define MCDE_CHNL1MUXING_V2_FIFO_ID_SHIFT 0
+#define MCDE_CHNL1MUXING_V2_FIFO_ID_MASK 0x00000007
+#define MCDE_CHNL1MUXING_V2_FIFO_ID_FIFO_A 0
+#define MCDE_CHNL1MUXING_V2_FIFO_ID_FIFO_B 1
+#define MCDE_CHNL1MUXING_V2_FIFO_ID_FIFO_C0 2
+#define MCDE_CHNL1MUXING_V2_FIFO_ID_FIFO_C1 3
+#define MCDE_CHNL1MUXING_V2_FIFO_ID_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1MUXING_V2, FIFO_ID, \
+ MCDE_CHNL1MUXING_V2_FIFO_ID_##__x)
+#define MCDE_CHNL1MUXING_V2_FIFO_ID(__x) \
+ MCDE_VAL2REG(MCDE_CHNL1MUXING_V2, FIFO_ID, __x)
+#define MCDE_CHNL2MUXING_V2 0x00000654
+#define MCDE_CHNL2MUXING_V2_FIFO_ID_SHIFT 0
+#define MCDE_CHNL2MUXING_V2_FIFO_ID_MASK 0x00000007
+#define MCDE_CHNL2MUXING_V2_FIFO_ID_FIFO_A 0
+#define MCDE_CHNL2MUXING_V2_FIFO_ID_FIFO_B 1
+#define MCDE_CHNL2MUXING_V2_FIFO_ID_FIFO_C0 2
+#define MCDE_CHNL2MUXING_V2_FIFO_ID_FIFO_C1 3
+#define MCDE_CHNL2MUXING_V2_FIFO_ID_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2MUXING_V2, FIFO_ID, \
+ MCDE_CHNL2MUXING_V2_FIFO_ID_##__x)
+#define MCDE_CHNL2MUXING_V2_FIFO_ID(__x) \
+ MCDE_VAL2REG(MCDE_CHNL2MUXING_V2, FIFO_ID, __x)
+#define MCDE_CHNL3MUXING_V2 0x00000674
+#define MCDE_CHNL3MUXING_V2_FIFO_ID_SHIFT 0
+#define MCDE_CHNL3MUXING_V2_FIFO_ID_MASK 0x00000007
+#define MCDE_CHNL3MUXING_V2_FIFO_ID_FIFO_A 0
+#define MCDE_CHNL3MUXING_V2_FIFO_ID_FIFO_B 1
+#define MCDE_CHNL3MUXING_V2_FIFO_ID_FIFO_C0 2
+#define MCDE_CHNL3MUXING_V2_FIFO_ID_FIFO_C1 3
+#define MCDE_CHNL3MUXING_V2_FIFO_ID_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3MUXING_V2, FIFO_ID, \
+ MCDE_CHNL3MUXING_V2_FIFO_ID_##__x)
+#define MCDE_CHNL3MUXING_V2_FIFO_ID(__x) \
+ MCDE_VAL2REG(MCDE_CHNL3MUXING_V2, FIFO_ID, __x)
+#define MCDE_CRA0 0x00000800
+#define MCDE_CRA0_GROUPOFFSET 0x200
+#define MCDE_CRA0_FLOEN_SHIFT 0
+#define MCDE_CRA0_FLOEN_MASK 0x00000001
+#define MCDE_CRA0_FLOEN(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, FLOEN, __x)
+#define MCDE_CRA0_POWEREN_SHIFT 1
+#define MCDE_CRA0_POWEREN_MASK 0x00000002
+#define MCDE_CRA0_POWEREN(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, POWEREN, __x)
+#define MCDE_CRA0_BLENDEN_SHIFT 2
+#define MCDE_CRA0_BLENDEN_MASK 0x00000004
+#define MCDE_CRA0_BLENDEN(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, BLENDEN, __x)
+#define MCDE_CRA0_AFLICKEN_SHIFT 3
+#define MCDE_CRA0_AFLICKEN_MASK 0x00000008
+#define MCDE_CRA0_AFLICKEN(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, AFLICKEN, __x)
+#define MCDE_CRA0_PALEN_SHIFT 4
+#define MCDE_CRA0_PALEN_MASK 0x00000010
+#define MCDE_CRA0_PALEN(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, PALEN, __x)
+#define MCDE_CRA0_DITHEN_SHIFT 5
+#define MCDE_CRA0_DITHEN_MASK 0x00000020
+#define MCDE_CRA0_DITHEN(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, DITHEN, __x)
+#define MCDE_CRA0_GAMEN_SHIFT 6
+#define MCDE_CRA0_GAMEN_MASK 0x00000040
+#define MCDE_CRA0_GAMEN(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, GAMEN, __x)
+#define MCDE_CRA0_KEYCTRL_SHIFT 7
+#define MCDE_CRA0_KEYCTRL_MASK 0x00000380
+#define MCDE_CRA0_KEYCTRL_OFF 0
+#define MCDE_CRA0_KEYCTRL_ALPHA_RGB 1
+#define MCDE_CRA0_KEYCTRL_RGB 2
+#define MCDE_CRA0_KEYCTRL_FALPHA_FRGB 4
+#define MCDE_CRA0_KEYCTRL_FRGB 5
+#define MCDE_CRA0_KEYCTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, KEYCTRL, MCDE_CRA0_KEYCTRL_##__x)
+#define MCDE_CRA0_KEYCTRL(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, KEYCTRL, __x)
+#define MCDE_CRA0_BLENDCTRL_SHIFT 10
+#define MCDE_CRA0_BLENDCTRL_MASK 0x00000400
+#define MCDE_CRA0_BLENDCTRL_SOURCE 0
+#define MCDE_CRA0_BLENDCTRL_CONSTANT 1
+#define MCDE_CRA0_BLENDCTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, BLENDCTRL, MCDE_CRA0_BLENDCTRL_##__x)
+#define MCDE_CRA0_BLENDCTRL(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, BLENDCTRL, __x)
+#define MCDE_CRA0_FLICKMODE_SHIFT 11
+#define MCDE_CRA0_FLICKMODE_MASK 0x00001800
+#define MCDE_CRA0_FLICKMODE_FORCE_FILTER_0 0
+#define MCDE_CRA0_FLICKMODE_ADAPTIVE 1
+#define MCDE_CRA0_FLICKMODE_TEST_MODE 2
+#define MCDE_CRA0_FLICKMODE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, FLICKMODE, MCDE_CRA0_FLICKMODE_##__x)
+#define MCDE_CRA0_FLICKMODE(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, FLICKMODE, __x)
+#define MCDE_CRA0_FLOCKFORMAT_SHIFT 13
+#define MCDE_CRA0_FLOCKFORMAT_MASK 0x00002000
+#define MCDE_CRA0_FLOCKFORMAT_YCBCR 0
+#define MCDE_CRA0_FLOCKFORMAT_RGB 1
+#define MCDE_CRA0_FLOCKFORMAT_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, FLOCKFORMAT, MCDE_CRA0_FLOCKFORMAT_##__x)
+#define MCDE_CRA0_FLOCKFORMAT(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, FLOCKFORMAT, __x)
+#define MCDE_CRA0_PALMODE_SHIFT 14
+#define MCDE_CRA0_PALMODE_MASK 0x00004000
+#define MCDE_CRA0_PALMODE_PALETTE 0
+#define MCDE_CRA0_PALMODE_GAMMA 1
+#define MCDE_CRA0_PALMODE(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, PALMODE, __x)
+#define MCDE_CRA0_OLEDEN_SHIFT 15
+#define MCDE_CRA0_OLEDEN_MASK 0x00008000
+#define MCDE_CRA0_OLEDEN(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, OLEDEN, __x)
+#define MCDE_CRA0_ALPHABLEND_SHIFT 16
+#define MCDE_CRA0_ALPHABLEND_MASK 0x00FF0000
+#define MCDE_CRA0_ALPHABLEND(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, ALPHABLEND, __x)
+#define MCDE_CRA0_ROTEN_SHIFT 24
+#define MCDE_CRA0_ROTEN_MASK 0x01000000
+#define MCDE_CRA0_ROTEN(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, ROTEN, __x)
+#define MCDE_CRA0_ROTBURSTSIZE_V1_SHIFT 25
+#define MCDE_CRA0_ROTBURSTSIZE_V1_MASK 0x0E000000
+#define MCDE_CRA0_ROTBURSTSIZE_V1_1W 0
+#define MCDE_CRA0_ROTBURSTSIZE_V1_2W 1
+#define MCDE_CRA0_ROTBURSTSIZE_V1_4W 2
+#define MCDE_CRA0_ROTBURSTSIZE_V1_8W 3
+#define MCDE_CRA0_ROTBURSTSIZE_V1_16W 4
+#define MCDE_CRA0_ROTBURSTSIZE_V1_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, ROTBURSTSIZE_V1, \
+ MCDE_CRA0_ROTBURSTSIZE_V1_##__x)
+#define MCDE_CRA0_ROTBURSTSIZE_V1(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, ROTBURSTSIZE_V1, __x)
+#define MCDE_CRA0_ROTBURSTSIZE_HW_V1_SHIFT 28
+#define MCDE_CRA0_ROTBURSTSIZE_HW_V1_MASK 0x10000000
+#define MCDE_CRA0_ROTBURSTSIZE_HW_V1(__x) \
+ MCDE_VAL2REG(MCDE_CRA0, ROTBURSTSIZE_HW_V1, __x)
+#define MCDE_CRB0 0x00000A00
+#define MCDE_CRB0_FLOEN_SHIFT 0
+#define MCDE_CRB0_FLOEN_MASK 0x00000001
+#define MCDE_CRB0_FLOEN(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, FLOEN, __x)
+#define MCDE_CRB0_POWEREN_SHIFT 1
+#define MCDE_CRB0_POWEREN_MASK 0x00000002
+#define MCDE_CRB0_POWEREN(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, POWEREN, __x)
+#define MCDE_CRB0_BLENDEN_SHIFT 2
+#define MCDE_CRB0_BLENDEN_MASK 0x00000004
+#define MCDE_CRB0_BLENDEN(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, BLENDEN, __x)
+#define MCDE_CRB0_AFLICKEN_SHIFT 3
+#define MCDE_CRB0_AFLICKEN_MASK 0x00000008
+#define MCDE_CRB0_AFLICKEN(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, AFLICKEN, __x)
+#define MCDE_CRB0_PALEN_SHIFT 4
+#define MCDE_CRB0_PALEN_MASK 0x00000010
+#define MCDE_CRB0_PALEN(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, PALEN, __x)
+#define MCDE_CRB0_DITHEN_SHIFT 5
+#define MCDE_CRB0_DITHEN_MASK 0x00000020
+#define MCDE_CRB0_DITHEN(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, DITHEN, __x)
+#define MCDE_CRB0_GAMEN_SHIFT 6
+#define MCDE_CRB0_GAMEN_MASK 0x00000040
+#define MCDE_CRB0_GAMEN(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, GAMEN, __x)
+#define MCDE_CRB0_KEYCTRL_SHIFT 7
+#define MCDE_CRB0_KEYCTRL_MASK 0x00000380
+#define MCDE_CRB0_KEYCTRL_OFF 0
+#define MCDE_CRB0_KEYCTRL_ALPHA_RGB 1
+#define MCDE_CRB0_KEYCTRL_RGB 2
+#define MCDE_CRB0_KEYCTRL_FALPHA_FRGB 4
+#define MCDE_CRB0_KEYCTRL_FRGB 5
+#define MCDE_CRB0_KEYCTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, KEYCTRL, MCDE_CRB0_KEYCTRL_##__x)
+#define MCDE_CRB0_KEYCTRL(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, KEYCTRL, __x)
+#define MCDE_CRB0_BLENDCTRL_SHIFT 10
+#define MCDE_CRB0_BLENDCTRL_MASK 0x00000400
+#define MCDE_CRB0_BLENDCTRL_SOURCE 0
+#define MCDE_CRB0_BLENDCTRL_CONSTANT 1
+#define MCDE_CRB0_BLENDCTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, BLENDCTRL, MCDE_CRB0_BLENDCTRL_##__x)
+#define MCDE_CRB0_BLENDCTRL(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, BLENDCTRL, __x)
+#define MCDE_CRB0_FLICKMODE_SHIFT 11
+#define MCDE_CRB0_FLICKMODE_MASK 0x00001800
+#define MCDE_CRB0_FLICKMODE_FORCE_FILTER_0 0
+#define MCDE_CRB0_FLICKMODE_ADAPTIVE 1
+#define MCDE_CRB0_FLICKMODE_TEST_MODE 2
+#define MCDE_CRB0_FLICKMODE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, FLICKMODE, MCDE_CRB0_FLICKMODE_##__x)
+#define MCDE_CRB0_FLICKMODE(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, FLICKMODE, __x)
+#define MCDE_CRB0_FLOCKFORMAT_SHIFT 13
+#define MCDE_CRB0_FLOCKFORMAT_MASK 0x00002000
+#define MCDE_CRB0_FLOCKFORMAT_YCBCR 0
+#define MCDE_CRB0_FLOCKFORMAT_RGB 1
+#define MCDE_CRB0_FLOCKFORMAT_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, FLOCKFORMAT, MCDE_CRB0_FLOCKFORMAT_##__x)
+#define MCDE_CRB0_FLOCKFORMAT(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, FLOCKFORMAT, __x)
+#define MCDE_CRB0_PALMODE_SHIFT 14
+#define MCDE_CRB0_PALMODE_MASK 0x00004000
+#define MCDE_CRB0_PALMODE_PALETTE 0
+#define MCDE_CRB0_PALMODE_GAMMA 1
+#define MCDE_CRB0_PALMODE(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, PALMODE, __x)
+#define MCDE_CRB0_OLEDEN_SHIFT 15
+#define MCDE_CRB0_OLEDEN_MASK 0x00008000
+#define MCDE_CRB0_OLEDEN(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, OLEDEN, __x)
+#define MCDE_CRB0_ALPHABLEND_SHIFT 16
+#define MCDE_CRB0_ALPHABLEND_MASK 0x00FF0000
+#define MCDE_CRB0_ALPHABLEND(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, ALPHABLEND, __x)
+#define MCDE_CRB0_ROTEN_SHIFT 24
+#define MCDE_CRB0_ROTEN_MASK 0x01000000
+#define MCDE_CRB0_ROTEN(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, ROTEN, __x)
+#define MCDE_CRB0_ROTBURSTSIZE_V1_SHIFT 25
+#define MCDE_CRB0_ROTBURSTSIZE_V1_MASK 0x0E000000
+#define MCDE_CRB0_ROTBURSTSIZE_V1_1W 0
+#define MCDE_CRB0_ROTBURSTSIZE_V1_2W 1
+#define MCDE_CRB0_ROTBURSTSIZE_V1_4W 2
+#define MCDE_CRB0_ROTBURSTSIZE_V1_8W 3
+#define MCDE_CRB0_ROTBURSTSIZE_V1_16W 4
+#define MCDE_CRB0_ROTBURSTSIZE_V1_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, ROTBURSTSIZE_V1, \
+ MCDE_CRB0_ROTBURSTSIZE_V1_##__x)
+#define MCDE_CRB0_ROTBURSTSIZE_V1(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, ROTBURSTSIZE_V1, __x)
+#define MCDE_CRB0_ROTBURSTSIZE_HW_V1_SHIFT 28
+#define MCDE_CRB0_ROTBURSTSIZE_HW_V1_MASK 0x10000000
+#define MCDE_CRB0_ROTBURSTSIZE_HW_V1(__x) \
+ MCDE_VAL2REG(MCDE_CRB0, ROTBURSTSIZE_HW_V1, __x)
+#define MCDE_CRA1 0x00000804
+#define MCDE_CRA1_GROUPOFFSET 0x200
+#define MCDE_CRA1_PCD_SHIFT 0
+#define MCDE_CRA1_PCD_MASK 0x000003FF
+#define MCDE_CRA1_PCD(__x) \
+ MCDE_VAL2REG(MCDE_CRA1, PCD, __x)
+#define MCDE_CRA1_CLKSEL_SHIFT 10
+#define MCDE_CRA1_CLKSEL_MASK 0x00001C00
+#define MCDE_CRA1_CLKSEL_LCD 0
+#define MCDE_CRA1_CLKSEL_HDMI 1
+#define MCDE_CRA1_CLKSEL_TV 2
+#define MCDE_CRA1_CLKSEL_EXT_TV1 3
+#define MCDE_CRA1_CLKSEL_EXT_TV2 4
+#define MCDE_CRA1_CLKSEL_166MHZ 5
+#define MCDE_CRA1_CLKSEL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRA1, CLKSEL, MCDE_CRA1_CLKSEL_##__x)
+#define MCDE_CRA1_CLKSEL(__x) \
+ MCDE_VAL2REG(MCDE_CRA1, CLKSEL, __x)
+#define MCDE_CRA1_CDWIN_SHIFT 13
+#define MCDE_CRA1_CDWIN_MASK 0x0001E000
+#define MCDE_CRA1_CDWIN_8BBP_C1 0
+#define MCDE_CRA1_CDWIN_12BBP_C1 1
+#define MCDE_CRA1_CDWIN_12BBP_C2 2
+#define MCDE_CRA1_CDWIN_16BBP_C1 3
+#define MCDE_CRA1_CDWIN_16BBP_C2 4
+#define MCDE_CRA1_CDWIN_18BBP_C1 5
+#define MCDE_CRA1_CDWIN_18BBP_C2 6
+#define MCDE_CRA1_CDWIN_24BBP 7
+#define MCDE_CRA1_CDWIN_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRA1, CDWIN, MCDE_CRA1_CDWIN_##__x)
+#define MCDE_CRA1_CDWIN(__x) \
+ MCDE_VAL2REG(MCDE_CRA1, CDWIN, __x)
+#define MCDE_CRA1_OUTBPP_SHIFT 25
+#define MCDE_CRA1_OUTBPP_MASK 0x1E000000
+#define MCDE_CRA1_OUTBPP_MONO1 0
+#define MCDE_CRA1_OUTBPP_MONO2 1
+#define MCDE_CRA1_OUTBPP_MONO4 2
+#define MCDE_CRA1_OUTBPP_MONO8 3
+#define MCDE_CRA1_OUTBPP_8BPP 4
+#define MCDE_CRA1_OUTBPP_12BPP 5
+#define MCDE_CRA1_OUTBPP_15BPP 6
+#define MCDE_CRA1_OUTBPP_16BPP 7
+#define MCDE_CRA1_OUTBPP_18BPP 8
+#define MCDE_CRA1_OUTBPP_24BPP 9
+#define MCDE_CRA1_OUTBPP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRA1, OUTBPP, MCDE_CRA1_OUTBPP_##__x)
+#define MCDE_CRA1_OUTBPP(__x) \
+ MCDE_VAL2REG(MCDE_CRA1, OUTBPP, __x)
+#define MCDE_CRA1_BCD_SHIFT 29
+#define MCDE_CRA1_BCD_MASK 0x20000000
+#define MCDE_CRA1_BCD(__x) \
+ MCDE_VAL2REG(MCDE_CRA1, BCD, __x)
+#define MCDE_CRA1_CLKTYPE_SHIFT 30
+#define MCDE_CRA1_CLKTYPE_MASK 0x40000000
+#define MCDE_CRA1_CLKTYPE_EXTERNAL 0
+#define MCDE_CRA1_CLKTYPE_INTERNAL 1
+#define MCDE_CRA1_CLKTYPE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRA1, CLKTYPE, MCDE_CRA1_CLKTYPE_##__x)
+#define MCDE_CRA1_CLKTYPE(__x) \
+ MCDE_VAL2REG(MCDE_CRA1, CLKTYPE, __x)
+#define MCDE_CRA1_TEFFECTEN_V1_SHIFT 31
+#define MCDE_CRA1_TEFFECTEN_V1_MASK 0x80000000
+#define MCDE_CRA1_TEFFECTEN_V1(__x) \
+ MCDE_VAL2REG(MCDE_CRA1, TEFFECTEN_V1, __x)
+#define MCDE_CRB1 0x00000A04
+#define MCDE_CRB1_PCD_SHIFT 0
+#define MCDE_CRB1_PCD_MASK 0x000003FF
+#define MCDE_CRB1_PCD(__x) \
+ MCDE_VAL2REG(MCDE_CRB1, PCD, __x)
+#define MCDE_CRB1_CLKSEL_SHIFT 10
+#define MCDE_CRB1_CLKSEL_MASK 0x00001C00
+#define MCDE_CRB1_CLKSEL_LCD 0
+#define MCDE_CRB1_CLKSEL_HDMI 1
+#define MCDE_CRB1_CLKSEL_TV 2
+#define MCDE_CRB1_CLKSEL_EXT_TV1 3
+#define MCDE_CRB1_CLKSEL_EXT_TV2 4
+#define MCDE_CRB1_CLKSEL_166MHZ 5
+#define MCDE_CRB1_CLKSEL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRB1, CLKSEL, MCDE_CRB1_CLKSEL_##__x)
+#define MCDE_CRB1_CLKSEL(__x) \
+ MCDE_VAL2REG(MCDE_CRB1, CLKSEL, __x)
+#define MCDE_CRB1_CDWIN_SHIFT 13
+#define MCDE_CRB1_CDWIN_MASK 0x0001E000
+#define MCDE_CRB1_CDWIN_8BBP_C1 0
+#define MCDE_CRB1_CDWIN_12BBP_C1 1
+#define MCDE_CRB1_CDWIN_12BBP_C2 2
+#define MCDE_CRB1_CDWIN_16BBP_C1 3
+#define MCDE_CRB1_CDWIN_16BBP_C2 4
+#define MCDE_CRB1_CDWIN_18BBP_C1 5
+#define MCDE_CRB1_CDWIN_18BBP_C2 6
+#define MCDE_CRB1_CDWIN_24BBP 7
+#define MCDE_CRB1_CDWIN_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRB1, CDWIN, MCDE_CRB1_CDWIN_##__x)
+#define MCDE_CRB1_CDWIN(__x) \
+ MCDE_VAL2REG(MCDE_CRB1, CDWIN, __x)
+#define MCDE_CRB1_OUTBPP_SHIFT 25
+#define MCDE_CRB1_OUTBPP_MASK 0x1E000000
+#define MCDE_CRB1_OUTBPP_MONO1 0
+#define MCDE_CRB1_OUTBPP_MONO2 1
+#define MCDE_CRB1_OUTBPP_MONO4 2
+#define MCDE_CRB1_OUTBPP_MONO8 3
+#define MCDE_CRB1_OUTBPP_8BPP 4
+#define MCDE_CRB1_OUTBPP_12BPP 5
+#define MCDE_CRB1_OUTBPP_15BPP 6
+#define MCDE_CRB1_OUTBPP_16BPP 7
+#define MCDE_CRB1_OUTBPP_18BPP 8
+#define MCDE_CRB1_OUTBPP_24BPP 9
+#define MCDE_CRB1_OUTBPP_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRB1, OUTBPP, MCDE_CRB1_OUTBPP_##__x)
+#define MCDE_CRB1_OUTBPP(__x) \
+ MCDE_VAL2REG(MCDE_CRB1, OUTBPP, __x)
+#define MCDE_CRB1_BCD_SHIFT 29
+#define MCDE_CRB1_BCD_MASK 0x20000000
+#define MCDE_CRB1_BCD(__x) \
+ MCDE_VAL2REG(MCDE_CRB1, BCD, __x)
+#define MCDE_CRB1_CLKTYPE_SHIFT 30
+#define MCDE_CRB1_CLKTYPE_MASK 0x40000000
+#define MCDE_CRB1_CLKTYPE_EXTERNAL 0
+#define MCDE_CRB1_CLKTYPE_INTERNAL 1
+#define MCDE_CRB1_CLKTYPE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRB1, CLKTYPE, MCDE_CRB1_CLKTYPE_##__x)
+#define MCDE_CRB1_CLKTYPE(__x) \
+ MCDE_VAL2REG(MCDE_CRB1, CLKTYPE, __x)
+#define MCDE_CRB1_TEFFECTEN_V1_SHIFT 31
+#define MCDE_CRB1_TEFFECTEN_V1_MASK 0x80000000
+#define MCDE_CRB1_TEFFECTEN_V1(__x) \
+ MCDE_VAL2REG(MCDE_CRB1, TEFFECTEN_V1, __x)
+#define MCDE_COLKEYA 0x00000808
+#define MCDE_COLKEYA_GROUPOFFSET 0x200
+#define MCDE_COLKEYA_KEYB_SHIFT 0
+#define MCDE_COLKEYA_KEYB_MASK 0x000000FF
+#define MCDE_COLKEYA_KEYB(__x) \
+ MCDE_VAL2REG(MCDE_COLKEYA, KEYB, __x)
+#define MCDE_COLKEYA_KEYG_SHIFT 8
+#define MCDE_COLKEYA_KEYG_MASK 0x0000FF00
+#define MCDE_COLKEYA_KEYG(__x) \
+ MCDE_VAL2REG(MCDE_COLKEYA, KEYG, __x)
+#define MCDE_COLKEYA_KEYR_SHIFT 16
+#define MCDE_COLKEYA_KEYR_MASK 0x00FF0000
+#define MCDE_COLKEYA_KEYR(__x) \
+ MCDE_VAL2REG(MCDE_COLKEYA, KEYR, __x)
+#define MCDE_COLKEYA_KEYA_SHIFT 24
+#define MCDE_COLKEYA_KEYA_MASK 0xFF000000
+#define MCDE_COLKEYA_KEYA(__x) \
+ MCDE_VAL2REG(MCDE_COLKEYA, KEYA, __x)
+#define MCDE_COLKEYB 0x00000A08
+#define MCDE_COLKEYB_KEYB_SHIFT 0
+#define MCDE_COLKEYB_KEYB_MASK 0x000000FF
+#define MCDE_COLKEYB_KEYB(__x) \
+ MCDE_VAL2REG(MCDE_COLKEYB, KEYB, __x)
+#define MCDE_COLKEYB_KEYG_SHIFT 8
+#define MCDE_COLKEYB_KEYG_MASK 0x0000FF00
+#define MCDE_COLKEYB_KEYG(__x) \
+ MCDE_VAL2REG(MCDE_COLKEYB, KEYG, __x)
+#define MCDE_COLKEYB_KEYR_SHIFT 16
+#define MCDE_COLKEYB_KEYR_MASK 0x00FF0000
+#define MCDE_COLKEYB_KEYR(__x) \
+ MCDE_VAL2REG(MCDE_COLKEYB, KEYR, __x)
+#define MCDE_COLKEYB_KEYA_SHIFT 24
+#define MCDE_COLKEYB_KEYA_MASK 0xFF000000
+#define MCDE_COLKEYB_KEYA(__x) \
+ MCDE_VAL2REG(MCDE_COLKEYB, KEYA, __x)
+#define MCDE_FCOLKEYA 0x0000080C
+#define MCDE_FCOLKEYA_GROUPOFFSET 0x200
+#define MCDE_FCOLKEYA_FKEYB_SHIFT 0
+#define MCDE_FCOLKEYA_FKEYB_MASK 0x000000FF
+#define MCDE_FCOLKEYA_FKEYB(__x) \
+ MCDE_VAL2REG(MCDE_FCOLKEYA, FKEYB, __x)
+#define MCDE_FCOLKEYA_FKEYG_SHIFT 8
+#define MCDE_FCOLKEYA_FKEYG_MASK 0x0000FF00
+#define MCDE_FCOLKEYA_FKEYG(__x) \
+ MCDE_VAL2REG(MCDE_FCOLKEYA, FKEYG, __x)
+#define MCDE_FCOLKEYA_FKEYR_SHIFT 16
+#define MCDE_FCOLKEYA_FKEYR_MASK 0x00FF0000
+#define MCDE_FCOLKEYA_FKEYR(__x) \
+ MCDE_VAL2REG(MCDE_FCOLKEYA, FKEYR, __x)
+#define MCDE_FCOLKEYA_FKEYA_SHIFT 24
+#define MCDE_FCOLKEYA_FKEYA_MASK 0xFF000000
+#define MCDE_FCOLKEYA_FKEYA(__x) \
+ MCDE_VAL2REG(MCDE_FCOLKEYA, FKEYA, __x)
+#define MCDE_FCOLKEYB 0x00000A0C
+#define MCDE_FCOLKEYB_FKEYB_SHIFT 0
+#define MCDE_FCOLKEYB_FKEYB_MASK 0x000000FF
+#define MCDE_FCOLKEYB_FKEYB(__x) \
+ MCDE_VAL2REG(MCDE_FCOLKEYB, FKEYB, __x)
+#define MCDE_FCOLKEYB_FKEYG_SHIFT 8
+#define MCDE_FCOLKEYB_FKEYG_MASK 0x0000FF00
+#define MCDE_FCOLKEYB_FKEYG(__x) \
+ MCDE_VAL2REG(MCDE_FCOLKEYB, FKEYG, __x)
+#define MCDE_FCOLKEYB_FKEYR_SHIFT 16
+#define MCDE_FCOLKEYB_FKEYR_MASK 0x00FF0000
+#define MCDE_FCOLKEYB_FKEYR(__x) \
+ MCDE_VAL2REG(MCDE_FCOLKEYB, FKEYR, __x)
+#define MCDE_FCOLKEYB_FKEYA_SHIFT 24
+#define MCDE_FCOLKEYB_FKEYA_MASK 0xFF000000
+#define MCDE_FCOLKEYB_FKEYA(__x) \
+ MCDE_VAL2REG(MCDE_FCOLKEYB, FKEYA, __x)
+#define MCDE_RGBCONV1A 0x00000810
+#define MCDE_RGBCONV1A_GROUPOFFSET 0x200
+#define MCDE_RGBCONV1A_YR_GREEN_SHIFT 0
+#define MCDE_RGBCONV1A_YR_GREEN_MASK 0x000007FF
+#define MCDE_RGBCONV1A_YR_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV1A, YR_GREEN, __x)
+#define MCDE_RGBCONV1A_YR_RED_SHIFT 16
+#define MCDE_RGBCONV1A_YR_RED_MASK 0x07FF0000
+#define MCDE_RGBCONV1A_YR_RED(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV1A, YR_RED, __x)
+#define MCDE_RGBCONV1B 0x00000A10
+#define MCDE_RGBCONV1B_YR_GREEN_SHIFT 0
+#define MCDE_RGBCONV1B_YR_GREEN_MASK 0x000007FF
+#define MCDE_RGBCONV1B_YR_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV1B, YR_GREEN, __x)
+#define MCDE_RGBCONV1B_YR_RED_SHIFT 16
+#define MCDE_RGBCONV1B_YR_RED_MASK 0x07FF0000
+#define MCDE_RGBCONV1B_YR_RED(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV1B, YR_RED, __x)
+#define MCDE_RGBCONV2A 0x00000814
+#define MCDE_RGBCONV2A_GROUPOFFSET 0x200
+#define MCDE_RGBCONV2A_CR_RED_SHIFT 0
+#define MCDE_RGBCONV2A_CR_RED_MASK 0x000007FF
+#define MCDE_RGBCONV2A_CR_RED(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV2A, CR_RED, __x)
+#define MCDE_RGBCONV2A_YR_BLUE_SHIFT 16
+#define MCDE_RGBCONV2A_YR_BLUE_MASK 0x07FF0000
+#define MCDE_RGBCONV2A_YR_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV2A, YR_BLUE, __x)
+#define MCDE_RGBCONV2B 0x00000A14
+#define MCDE_RGBCONV2B_CR_RED_SHIFT 0
+#define MCDE_RGBCONV2B_CR_RED_MASK 0x000007FF
+#define MCDE_RGBCONV2B_CR_RED(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV2B, CR_RED, __x)
+#define MCDE_RGBCONV2B_YR_BLUE_SHIFT 16
+#define MCDE_RGBCONV2B_YR_BLUE_MASK 0x07FF0000
+#define MCDE_RGBCONV2B_YR_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV2B, YR_BLUE, __x)
+#define MCDE_RGBCONV3A 0x00000818
+#define MCDE_RGBCONV3A_GROUPOFFSET 0x200
+#define MCDE_RGBCONV3A_CR_BLUE_SHIFT 0
+#define MCDE_RGBCONV3A_CR_BLUE_MASK 0x000007FF
+#define MCDE_RGBCONV3A_CR_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV3A, CR_BLUE, __x)
+#define MCDE_RGBCONV3A_CR_GREEN_SHIFT 16
+#define MCDE_RGBCONV3A_CR_GREEN_MASK 0x07FF0000
+#define MCDE_RGBCONV3A_CR_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV3A, CR_GREEN, __x)
+#define MCDE_RGBCONV3B 0x00000A18
+#define MCDE_RGBCONV3B_CR_BLUE_SHIFT 0
+#define MCDE_RGBCONV3B_CR_BLUE_MASK 0x000007FF
+#define MCDE_RGBCONV3B_CR_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV3B, CR_BLUE, __x)
+#define MCDE_RGBCONV3B_CR_GREEN_SHIFT 16
+#define MCDE_RGBCONV3B_CR_GREEN_MASK 0x07FF0000
+#define MCDE_RGBCONV3B_CR_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV3B, CR_GREEN, __x)
+#define MCDE_RGBCONV4A 0x0000081C
+#define MCDE_RGBCONV4A_GROUPOFFSET 0x200
+#define MCDE_RGBCONV4A_CB_GREEN_SHIFT 0
+#define MCDE_RGBCONV4A_CB_GREEN_MASK 0x000007FF
+#define MCDE_RGBCONV4A_CB_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV4A, CB_GREEN, __x)
+#define MCDE_RGBCONV4A_CB_RED_SHIFT 16
+#define MCDE_RGBCONV4A_CB_RED_MASK 0x07FF0000
+#define MCDE_RGBCONV4A_CB_RED(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV4A, CB_RED, __x)
+#define MCDE_RGBCONV4B 0x00000A1C
+#define MCDE_RGBCONV4B_CB_GREEN_SHIFT 0
+#define MCDE_RGBCONV4B_CB_GREEN_MASK 0x000007FF
+#define MCDE_RGBCONV4B_CB_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV4B, CB_GREEN, __x)
+#define MCDE_RGBCONV4B_CB_RED_SHIFT 16
+#define MCDE_RGBCONV4B_CB_RED_MASK 0x07FF0000
+#define MCDE_RGBCONV4B_CB_RED(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV4B, CB_RED, __x)
+#define MCDE_RGBCONV5A 0x00000820
+#define MCDE_RGBCONV5A_GROUPOFFSET 0x200
+#define MCDE_RGBCONV5A_OFF_RED_SHIFT 0
+#define MCDE_RGBCONV5A_OFF_RED_MASK 0x000007FF
+#define MCDE_RGBCONV5A_OFF_RED(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV5A, OFF_RED, __x)
+#define MCDE_RGBCONV5A_CB_BLUE_SHIFT 16
+#define MCDE_RGBCONV5A_CB_BLUE_MASK 0x07FF0000
+#define MCDE_RGBCONV5A_CB_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV5A, CB_BLUE, __x)
+#define MCDE_RGBCONV5B 0x00000A20
+#define MCDE_RGBCONV5B_OFF_RED_SHIFT 0
+#define MCDE_RGBCONV5B_OFF_RED_MASK 0x000007FF
+#define MCDE_RGBCONV5B_OFF_RED(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV5B, OFF_RED, __x)
+#define MCDE_RGBCONV5B_CB_BLUE_SHIFT 16
+#define MCDE_RGBCONV5B_CB_BLUE_MASK 0x07FF0000
+#define MCDE_RGBCONV5B_CB_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV5B, CB_BLUE, __x)
+#define MCDE_RGBCONV6A 0x00000824
+#define MCDE_RGBCONV6A_GROUPOFFSET 0x200
+#define MCDE_RGBCONV6A_OFF_BLUE_SHIFT 0
+#define MCDE_RGBCONV6A_OFF_BLUE_MASK 0x000007FF
+#define MCDE_RGBCONV6A_OFF_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV6A, OFF_BLUE, __x)
+#define MCDE_RGBCONV6A_OFF_GREEN_SHIFT 16
+#define MCDE_RGBCONV6A_OFF_GREEN_MASK 0x07FF0000
+#define MCDE_RGBCONV6A_OFF_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV6A, OFF_GREEN, __x)
+#define MCDE_RGBCONV6B 0x00000A24
+#define MCDE_RGBCONV6B_OFF_BLUE_SHIFT 0
+#define MCDE_RGBCONV6B_OFF_BLUE_MASK 0x000007FF
+#define MCDE_RGBCONV6B_OFF_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV6B, OFF_BLUE, __x)
+#define MCDE_RGBCONV6B_OFF_GREEN_SHIFT 16
+#define MCDE_RGBCONV6B_OFF_GREEN_MASK 0x07FF0000
+#define MCDE_RGBCONV6B_OFF_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_RGBCONV6B, OFF_GREEN, __x)
+#define MCDE_FFCOEF0 0x00000828
+#define MCDE_FFCOEF0_COEFF0_N1_SHIFT 0
+#define MCDE_FFCOEF0_COEFF0_N1_MASK 0x000000FF
+#define MCDE_FFCOEF0_COEFF0_N1(__x) \
+ MCDE_VAL2REG(MCDE_FFCOEF0, COEFF0_N1, __x)
+#define MCDE_FFCOEF0_COEFF0_N2_SHIFT 8
+#define MCDE_FFCOEF0_COEFF0_N2_MASK 0x0000FF00
+#define MCDE_FFCOEF0_COEFF0_N2(__x) \
+ MCDE_VAL2REG(MCDE_FFCOEF0, COEFF0_N2, __x)
+#define MCDE_FFCOEF0_COEFF0_N3_SHIFT 16
+#define MCDE_FFCOEF0_COEFF0_N3_MASK 0x00FF0000
+#define MCDE_FFCOEF0_COEFF0_N3(__x) \
+ MCDE_VAL2REG(MCDE_FFCOEF0, COEFF0_N3, __x)
+#define MCDE_FFCOEF0_T0_SHIFT 24
+#define MCDE_FFCOEF0_T0_MASK 0x0F000000
+#define MCDE_FFCOEF0_T0(__x) \
+ MCDE_VAL2REG(MCDE_FFCOEF0, T0, __x)
+#define MCDE_FFCOEF1 0x0000082C
+#define MCDE_FFCOEF1_COEFF1_N1_SHIFT 0
+#define MCDE_FFCOEF1_COEFF1_N1_MASK 0x000000FF
+#define MCDE_FFCOEF1_COEFF1_N1(__x) \
+ MCDE_VAL2REG(MCDE_FFCOEF1, COEFF1_N1, __x)
+#define MCDE_FFCOEF1_COEFF1_N2_SHIFT 8
+#define MCDE_FFCOEF1_COEFF1_N2_MASK 0x0000FF00
+#define MCDE_FFCOEF1_COEFF1_N2(__x) \
+ MCDE_VAL2REG(MCDE_FFCOEF1, COEFF1_N2, __x)
+#define MCDE_FFCOEF1_COEFF1_N3_SHIFT 16
+#define MCDE_FFCOEF1_COEFF1_N3_MASK 0x00FF0000
+#define MCDE_FFCOEF1_COEFF1_N3(__x) \
+ MCDE_VAL2REG(MCDE_FFCOEF1, COEFF1_N3, __x)
+#define MCDE_FFCOEF1_T1_SHIFT 24
+#define MCDE_FFCOEF1_T1_MASK 0x0F000000
+#define MCDE_FFCOEF1_T1(__x) \
+ MCDE_VAL2REG(MCDE_FFCOEF1, T1, __x)
+#define MCDE_FFCOEF2 0x00000830
+#define MCDE_FFCOEF2_COEFF2_N1_SHIFT 0
+#define MCDE_FFCOEF2_COEFF2_N1_MASK 0x000000FF
+#define MCDE_FFCOEF2_COEFF2_N1(__x) \
+ MCDE_VAL2REG(MCDE_FFCOEF2, COEFF2_N1, __x)
+#define MCDE_FFCOEF2_COEFF2_N2_SHIFT 8
+#define MCDE_FFCOEF2_COEFF2_N2_MASK 0x0000FF00
+#define MCDE_FFCOEF2_COEFF2_N2(__x) \
+ MCDE_VAL2REG(MCDE_FFCOEF2, COEFF2_N2, __x)
+#define MCDE_FFCOEF2_COEFF2_N3_SHIFT 16
+#define MCDE_FFCOEF2_COEFF2_N3_MASK 0x00FF0000
+#define MCDE_FFCOEF2_COEFF2_N3(__x) \
+ MCDE_VAL2REG(MCDE_FFCOEF2, COEFF2_N3, __x)
+#define MCDE_FFCOEF2_T2_SHIFT 24
+#define MCDE_FFCOEF2_T2_MASK 0x0F000000
+#define MCDE_FFCOEF2_T2(__x) \
+ MCDE_VAL2REG(MCDE_FFCOEF2, T2, __x)
+#define MCDE_MCDE_WDATAA_V2 0x00000834
+#define MCDE_MCDE_WDATAA_V2_GROUPOFFSET 0x200
+#define MCDE_MCDE_WDATAA_V2_DC_SHIFT 24
+#define MCDE_MCDE_WDATAA_V2_DC_MASK 0x01000000
+#define MCDE_MCDE_WDATAA_V2_DC(__x) \
+ MCDE_VAL2REG(MCDE_MCDE_WDATAA_V2, DC, __x)
+#define MCDE_MCDE_WDATAA_V2_DATAVALUE_SHIFT 0
+#define MCDE_MCDE_WDATAA_V2_DATAVALUE_MASK 0x00FFFFFF
+#define MCDE_MCDE_WDATAA_V2_DATAVALUE(__x) \
+ MCDE_VAL2REG(MCDE_MCDE_WDATAA_V2, DATAVALUE, __x)
+#define MCDE_MCDE_WDATAB_V2 0x00000A34
+#define MCDE_MCDE_WDATAB_V2_DC_SHIFT 24
+#define MCDE_MCDE_WDATAB_V2_DC_MASK 0x01000000
+#define MCDE_MCDE_WDATAB_V2_DC(__x) \
+ MCDE_VAL2REG(MCDE_MCDE_WDATAB_V2, DC, __x)
+#define MCDE_MCDE_WDATAB_V2_DATAVALUE_SHIFT 0
+#define MCDE_MCDE_WDATAB_V2_DATAVALUE_MASK 0x00FFFFFF
+#define MCDE_MCDE_WDATAB_V2_DATAVALUE(__x) \
+ MCDE_VAL2REG(MCDE_MCDE_WDATAB_V2, DATAVALUE, __x)
+#define MCDE_TVCRA 0x00000838
+#define MCDE_TVCRA_GROUPOFFSET 0x200
+#define MCDE_TVCRA_SEL_MOD_SHIFT 0
+#define MCDE_TVCRA_SEL_MOD_MASK 0x00000001
+#define MCDE_TVCRA_SEL_MOD_LCD 0
+#define MCDE_TVCRA_SEL_MOD_TV 1
+#define MCDE_TVCRA_SEL_MOD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_TVCRA, SEL_MOD, MCDE_TVCRA_SEL_MOD_##__x)
+#define MCDE_TVCRA_SEL_MOD(__x) \
+ MCDE_VAL2REG(MCDE_TVCRA, SEL_MOD, __x)
+#define MCDE_TVCRA_INTEREN_SHIFT 1
+#define MCDE_TVCRA_INTEREN_MASK 0x00000002
+#define MCDE_TVCRA_INTEREN(__x) \
+ MCDE_VAL2REG(MCDE_TVCRA, INTEREN, __x)
+#define MCDE_TVCRA_IFIELD_SHIFT 2
+#define MCDE_TVCRA_IFIELD_MASK 0x00000004
+#define MCDE_TVCRA_IFIELD(__x) \
+ MCDE_VAL2REG(MCDE_TVCRA, IFIELD, __x)
+#define MCDE_TVCRA_TVMODE_SHIFT 3
+#define MCDE_TVCRA_TVMODE_MASK 0x00000038
+#define MCDE_TVCRA_TVMODE_SDTV_656P 0
+#define MCDE_TVCRA_TVMODE_HDTV_480P 1
+#define MCDE_TVCRA_TVMODE_HDTV_720P 2
+#define MCDE_TVCRA_TVMODE_SDTV_656P_LE 3
+#define MCDE_TVCRA_TVMODE_SDTV_656P_BE 4
+#define MCDE_TVCRA_TVMODE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_TVCRA, TVMODE, MCDE_TVCRA_TVMODE_##__x)
+#define MCDE_TVCRA_TVMODE(__x) \
+ MCDE_VAL2REG(MCDE_TVCRA, TVMODE, __x)
+#define MCDE_TVCRA_SDTVMODE_SHIFT 6
+#define MCDE_TVCRA_SDTVMODE_MASK 0x000000C0
+#define MCDE_TVCRA_SDTVMODE_Y0CBY1CR 0
+#define MCDE_TVCRA_SDTVMODE_CBY0CRY1 1
+#define MCDE_TVCRA_SDTVMODE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_TVCRA, SDTVMODE, MCDE_TVCRA_SDTVMODE_##__x)
+#define MCDE_TVCRA_SDTVMODE(__x) \
+ MCDE_VAL2REG(MCDE_TVCRA, SDTVMODE, __x)
+#define MCDE_TVCRA_AVRGEN_SHIFT 8
+#define MCDE_TVCRA_AVRGEN_MASK 0x00000100
+#define MCDE_TVCRA_AVRGEN(__x) \
+ MCDE_VAL2REG(MCDE_TVCRA, AVRGEN, __x)
+#define MCDE_TVCRA_CKINV_SHIFT 9
+#define MCDE_TVCRA_CKINV_MASK 0x00000200
+#define MCDE_TVCRA_CKINV(__x) \
+ MCDE_VAL2REG(MCDE_TVCRA, CKINV, __x)
+#define MCDE_TVCRB 0x00000A38
+#define MCDE_TVCRB_SEL_MOD_SHIFT 0
+#define MCDE_TVCRB_SEL_MOD_MASK 0x00000001
+#define MCDE_TVCRB_SEL_MOD_LCD 0
+#define MCDE_TVCRB_SEL_MOD_TV 1
+#define MCDE_TVCRB_SEL_MOD_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_TVCRB, SEL_MOD, MCDE_TVCRB_SEL_MOD_##__x)
+#define MCDE_TVCRB_SEL_MOD(__x) \
+ MCDE_VAL2REG(MCDE_TVCRB, SEL_MOD, __x)
+#define MCDE_TVCRB_INTEREN_SHIFT 1
+#define MCDE_TVCRB_INTEREN_MASK 0x00000002
+#define MCDE_TVCRB_INTEREN(__x) \
+ MCDE_VAL2REG(MCDE_TVCRB, INTEREN, __x)
+#define MCDE_TVCRB_IFIELD_SHIFT 2
+#define MCDE_TVCRB_IFIELD_MASK 0x00000004
+#define MCDE_TVCRB_IFIELD(__x) \
+ MCDE_VAL2REG(MCDE_TVCRB, IFIELD, __x)
+#define MCDE_TVCRB_TVMODE_SHIFT 3
+#define MCDE_TVCRB_TVMODE_MASK 0x00000038
+#define MCDE_TVCRB_TVMODE_SDTV_656P 0
+#define MCDE_TVCRB_TVMODE_HDTV_480P 1
+#define MCDE_TVCRB_TVMODE_HDTV_720P 2
+#define MCDE_TVCRB_TVMODE_SDTV_656P_LE 3
+#define MCDE_TVCRB_TVMODE_SDTV_656P_BE 4
+#define MCDE_TVCRB_TVMODE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_TVCRB, TVMODE, MCDE_TVCRB_TVMODE_##__x)
+#define MCDE_TVCRB_TVMODE(__x) \
+ MCDE_VAL2REG(MCDE_TVCRB, TVMODE, __x)
+#define MCDE_TVCRB_SDTVMODE_SHIFT 6
+#define MCDE_TVCRB_SDTVMODE_MASK 0x000000C0
+#define MCDE_TVCRB_SDTVMODE_Y0CBY1CR 0
+#define MCDE_TVCRB_SDTVMODE_CBY0CRY1 1
+#define MCDE_TVCRB_SDTVMODE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_TVCRB, SDTVMODE, MCDE_TVCRB_SDTVMODE_##__x)
+#define MCDE_TVCRB_SDTVMODE(__x) \
+ MCDE_VAL2REG(MCDE_TVCRB, SDTVMODE, __x)
+#define MCDE_TVCRB_AVRGEN_SHIFT 8
+#define MCDE_TVCRB_AVRGEN_MASK 0x00000100
+#define MCDE_TVCRB_AVRGEN(__x) \
+ MCDE_VAL2REG(MCDE_TVCRB, AVRGEN, __x)
+#define MCDE_TVCRB_CKINV_SHIFT 9
+#define MCDE_TVCRB_CKINV_MASK 0x00000200
+#define MCDE_TVCRB_CKINV(__x) \
+ MCDE_VAL2REG(MCDE_TVCRB, CKINV, __x)
+#define MCDE_TVBL1A 0x0000083C
+#define MCDE_TVBL1A_GROUPOFFSET 0x200
+#define MCDE_TVBL1A_BEL1_SHIFT 0
+#define MCDE_TVBL1A_BEL1_MASK 0x000007FF
+#define MCDE_TVBL1A_BEL1(__x) \
+ MCDE_VAL2REG(MCDE_TVBL1A, BEL1, __x)
+#define MCDE_TVBL1A_BSL1_SHIFT 16
+#define MCDE_TVBL1A_BSL1_MASK 0x07FF0000
+#define MCDE_TVBL1A_BSL1(__x) \
+ MCDE_VAL2REG(MCDE_TVBL1A, BSL1, __x)
+#define MCDE_TVBL1B 0x00000A3C
+#define MCDE_TVBL1B_BEL1_SHIFT 0
+#define MCDE_TVBL1B_BEL1_MASK 0x000007FF
+#define MCDE_TVBL1B_BEL1(__x) \
+ MCDE_VAL2REG(MCDE_TVBL1B, BEL1, __x)
+#define MCDE_TVBL1B_BSL1_SHIFT 16
+#define MCDE_TVBL1B_BSL1_MASK 0x07FF0000
+#define MCDE_TVBL1B_BSL1(__x) \
+ MCDE_VAL2REG(MCDE_TVBL1B, BSL1, __x)
+#define MCDE_TVISLA 0x00000840
+#define MCDE_TVISLA_GROUPOFFSET 0x200
+#define MCDE_TVISLA_FSL1_SHIFT 0
+#define MCDE_TVISLA_FSL1_MASK 0x000007FF
+#define MCDE_TVISLA_FSL1(__x) \
+ MCDE_VAL2REG(MCDE_TVISLA, FSL1, __x)
+#define MCDE_TVISLA_FSL2_SHIFT 16
+#define MCDE_TVISLA_FSL2_MASK 0x07FF0000
+#define MCDE_TVISLA_FSL2(__x) \
+ MCDE_VAL2REG(MCDE_TVISLA, FSL2, __x)
+#define MCDE_TVISLB 0x00000A40
+#define MCDE_TVISLB_FSL1_SHIFT 0
+#define MCDE_TVISLB_FSL1_MASK 0x000007FF
+#define MCDE_TVISLB_FSL1(__x) \
+ MCDE_VAL2REG(MCDE_TVISLB, FSL1, __x)
+#define MCDE_TVISLB_FSL2_SHIFT 16
+#define MCDE_TVISLB_FSL2_MASK 0x07FF0000
+#define MCDE_TVISLB_FSL2(__x) \
+ MCDE_VAL2REG(MCDE_TVISLB, FSL2, __x)
+#define MCDE_TVDVOA 0x00000844
+#define MCDE_TVDVOA_GROUPOFFSET 0x200
+#define MCDE_TVDVOA_DVO1_SHIFT 0
+#define MCDE_TVDVOA_DVO1_MASK 0x000007FF
+#define MCDE_TVDVOA_DVO1(__x) \
+ MCDE_VAL2REG(MCDE_TVDVOA, DVO1, __x)
+#define MCDE_TVDVOA_DVO2_SHIFT 16
+#define MCDE_TVDVOA_DVO2_MASK 0x07FF0000
+#define MCDE_TVDVOA_DVO2(__x) \
+ MCDE_VAL2REG(MCDE_TVDVOA, DVO2, __x)
+#define MCDE_TVDVOB 0x00000A44
+#define MCDE_TVDVOB_DVO1_SHIFT 0
+#define MCDE_TVDVOB_DVO1_MASK 0x000007FF
+#define MCDE_TVDVOB_DVO1(__x) \
+ MCDE_VAL2REG(MCDE_TVDVOB, DVO1, __x)
+#define MCDE_TVDVOB_DVO2_SHIFT 16
+#define MCDE_TVDVOB_DVO2_MASK 0x07FF0000
+#define MCDE_TVDVOB_DVO2(__x) \
+ MCDE_VAL2REG(MCDE_TVDVOB, DVO2, __x)
+#define MCDE_TVTIM1A 0x0000084C
+#define MCDE_TVTIM1A_GROUPOFFSET 0x200
+#define MCDE_TVTIM1A_DHO_SHIFT 0
+#define MCDE_TVTIM1A_DHO_MASK 0x000007FF
+#define MCDE_TVTIM1A_DHO(__x) \
+ MCDE_VAL2REG(MCDE_TVTIM1A, DHO, __x)
+#define MCDE_TVTIM1B 0x00000A4C
+#define MCDE_TVTIM1B_DHO_SHIFT 0
+#define MCDE_TVTIM1B_DHO_MASK 0x000007FF
+#define MCDE_TVTIM1B_DHO(__x) \
+ MCDE_VAL2REG(MCDE_TVTIM1B, DHO, __x)
+#define MCDE_TVLBALWA 0x00000850
+#define MCDE_TVLBALWA_GROUPOFFSET 0x200
+#define MCDE_TVLBALWA_LBW_SHIFT 0
+#define MCDE_TVLBALWA_LBW_MASK 0x000007FF
+#define MCDE_TVLBALWA_LBW(__x) \
+ MCDE_VAL2REG(MCDE_TVLBALWA, LBW, __x)
+#define MCDE_TVLBALWA_ALW_SHIFT 16
+#define MCDE_TVLBALWA_ALW_MASK 0x07FF0000
+#define MCDE_TVLBALWA_ALW(__x) \
+ MCDE_VAL2REG(MCDE_TVLBALWA, ALW, __x)
+#define MCDE_TVLBALWB 0x00000A50
+#define MCDE_TVLBALWB_LBW_SHIFT 0
+#define MCDE_TVLBALWB_LBW_MASK 0x000007FF
+#define MCDE_TVLBALWB_LBW(__x) \
+ MCDE_VAL2REG(MCDE_TVLBALWB, LBW, __x)
+#define MCDE_TVLBALWB_ALW_SHIFT 16
+#define MCDE_TVLBALWB_ALW_MASK 0x07FF0000
+#define MCDE_TVLBALWB_ALW(__x) \
+ MCDE_VAL2REG(MCDE_TVLBALWB, ALW, __x)
+#define MCDE_TVBL2A 0x00000854
+#define MCDE_TVBL2A_GROUPOFFSET 0x200
+#define MCDE_TVBL2A_BEL2_SHIFT 0
+#define MCDE_TVBL2A_BEL2_MASK 0x000007FF
+#define MCDE_TVBL2A_BEL2(__x) \
+ MCDE_VAL2REG(MCDE_TVBL2A, BEL2, __x)
+#define MCDE_TVBL2A_BSL2_SHIFT 16
+#define MCDE_TVBL2A_BSL2_MASK 0x07FF0000
+#define MCDE_TVBL2A_BSL2(__x) \
+ MCDE_VAL2REG(MCDE_TVBL2A, BSL2, __x)
+#define MCDE_TVBL2B 0x00000A54
+#define MCDE_TVBL2B_BEL2_SHIFT 0
+#define MCDE_TVBL2B_BEL2_MASK 0x000007FF
+#define MCDE_TVBL2B_BEL2(__x) \
+ MCDE_VAL2REG(MCDE_TVBL2B, BEL2, __x)
+#define MCDE_TVBL2B_BSL2_SHIFT 16
+#define MCDE_TVBL2B_BSL2_MASK 0x07FF0000
+#define MCDE_TVBL2B_BSL2(__x) \
+ MCDE_VAL2REG(MCDE_TVBL2B, BSL2, __x)
+#define MCDE_TVBLUA 0x00000858
+#define MCDE_TVBLUA_GROUPOFFSET 0x200
+#define MCDE_TVBLUA_TVBLU_SHIFT 0
+#define MCDE_TVBLUA_TVBLU_MASK 0x000000FF
+#define MCDE_TVBLUA_TVBLU(__x) \
+ MCDE_VAL2REG(MCDE_TVBLUA, TVBLU, __x)
+#define MCDE_TVBLUA_TVBCB_SHIFT 8
+#define MCDE_TVBLUA_TVBCB_MASK 0x0000FF00
+#define MCDE_TVBLUA_TVBCB(__x) \
+ MCDE_VAL2REG(MCDE_TVBLUA, TVBCB, __x)
+#define MCDE_TVBLUA_TVBCR_SHIFT 16
+#define MCDE_TVBLUA_TVBCR_MASK 0x00FF0000
+#define MCDE_TVBLUA_TVBCR(__x) \
+ MCDE_VAL2REG(MCDE_TVBLUA, TVBCR, __x)
+#define MCDE_TVBLUB 0x00000A58
+#define MCDE_TVBLUB_TVBLU_SHIFT 0
+#define MCDE_TVBLUB_TVBLU_MASK 0x000000FF
+#define MCDE_TVBLUB_TVBLU(__x) \
+ MCDE_VAL2REG(MCDE_TVBLUB, TVBLU, __x)
+#define MCDE_TVBLUB_TVBCB_SHIFT 8
+#define MCDE_TVBLUB_TVBCB_MASK 0x0000FF00
+#define MCDE_TVBLUB_TVBCB(__x) \
+ MCDE_VAL2REG(MCDE_TVBLUB, TVBCB, __x)
+#define MCDE_TVBLUB_TVBCR_SHIFT 16
+#define MCDE_TVBLUB_TVBCR_MASK 0x00FF0000
+#define MCDE_TVBLUB_TVBCR(__x) \
+ MCDE_VAL2REG(MCDE_TVBLUB, TVBCR, __x)
+#define MCDE_LCDTIM1A 0x00000860
+#define MCDE_LCDTIM1A_GROUPOFFSET 0x200
+#define MCDE_LCDTIM1A_IVP_SHIFT 19
+#define MCDE_LCDTIM1A_IVP_MASK 0x00080000
+#define MCDE_LCDTIM1A_IVP(__x) \
+ MCDE_VAL2REG(MCDE_LCDTIM1A, IVP, __x)
+#define MCDE_LCDTIM1A_IVS_SHIFT 20
+#define MCDE_LCDTIM1A_IVS_MASK 0x00100000
+#define MCDE_LCDTIM1A_IVS(__x) \
+ MCDE_VAL2REG(MCDE_LCDTIM1A, IVS, __x)
+#define MCDE_LCDTIM1A_IHS_SHIFT 21
+#define MCDE_LCDTIM1A_IHS_MASK 0x00200000
+#define MCDE_LCDTIM1A_IHS(__x) \
+ MCDE_VAL2REG(MCDE_LCDTIM1A, IHS, __x)
+#define MCDE_LCDTIM1A_IPC_SHIFT 22
+#define MCDE_LCDTIM1A_IPC_MASK 0x00400000
+#define MCDE_LCDTIM1A_IPC(__x) \
+ MCDE_VAL2REG(MCDE_LCDTIM1A, IPC, __x)
+#define MCDE_LCDTIM1A_IOE_SHIFT 23
+#define MCDE_LCDTIM1A_IOE_MASK 0x00800000
+#define MCDE_LCDTIM1A_IOE(__x) \
+ MCDE_VAL2REG(MCDE_LCDTIM1A, IOE, __x)
+#define MCDE_LCDTIM1B 0x00000A60
+#define MCDE_LCDTIM1B_IVP_SHIFT 19
+#define MCDE_LCDTIM1B_IVP_MASK 0x00080000
+#define MCDE_LCDTIM1B_IVP(__x) \
+ MCDE_VAL2REG(MCDE_LCDTIM1B, IVP, __x)
+#define MCDE_LCDTIM1B_IVS_SHIFT 20
+#define MCDE_LCDTIM1B_IVS_MASK 0x00100000
+#define MCDE_LCDTIM1B_IVS(__x) \
+ MCDE_VAL2REG(MCDE_LCDTIM1B, IVS, __x)
+#define MCDE_LCDTIM1B_IHS_SHIFT 21
+#define MCDE_LCDTIM1B_IHS_MASK 0x00200000
+#define MCDE_LCDTIM1B_IHS(__x) \
+ MCDE_VAL2REG(MCDE_LCDTIM1B, IHS, __x)
+#define MCDE_LCDTIM1B_IPC_SHIFT 22
+#define MCDE_LCDTIM1B_IPC_MASK 0x00400000
+#define MCDE_LCDTIM1B_IPC(__x) \
+ MCDE_VAL2REG(MCDE_LCDTIM1B, IPC, __x)
+#define MCDE_LCDTIM1B_IOE_SHIFT 23
+#define MCDE_LCDTIM1B_IOE_MASK 0x00800000
+#define MCDE_LCDTIM1B_IOE(__x) \
+ MCDE_VAL2REG(MCDE_LCDTIM1B, IOE, __x)
+#define MCDE_DITCTRLA 0x00000864
+#define MCDE_DITCTRLA_GROUPOFFSET 0x200
+#define MCDE_DITCTRLA_TEMP_SHIFT 0
+#define MCDE_DITCTRLA_TEMP_MASK 0x00000001
+#define MCDE_DITCTRLA_TEMP(__x) \
+ MCDE_VAL2REG(MCDE_DITCTRLA, TEMP, __x)
+#define MCDE_DITCTRLA_COMP_SHIFT 1
+#define MCDE_DITCTRLA_COMP_MASK 0x00000002
+#define MCDE_DITCTRLA_COMP(__x) \
+ MCDE_VAL2REG(MCDE_DITCTRLA, COMP, __x)
+#define MCDE_DITCTRLA_MASK_SHIFT 4
+#define MCDE_DITCTRLA_MASK_MASK 0x00000010
+#define MCDE_DITCTRLA_MASK(__x) \
+ MCDE_VAL2REG(MCDE_DITCTRLA, MASK, __x)
+#define MCDE_DITCTRLA_FOFFX_SHIFT 5
+#define MCDE_DITCTRLA_FOFFX_MASK 0x000003E0
+#define MCDE_DITCTRLA_FOFFX(__x) \
+ MCDE_VAL2REG(MCDE_DITCTRLA, FOFFX, __x)
+#define MCDE_DITCTRLA_FOFFY_SHIFT 10
+#define MCDE_DITCTRLA_FOFFY_MASK 0x00007C00
+#define MCDE_DITCTRLA_FOFFY(__x) \
+ MCDE_VAL2REG(MCDE_DITCTRLA, FOFFY, __x)
+#define MCDE_DITCTRLB 0x00000A64
+#define MCDE_DITCTRLB_TEMP_SHIFT 0
+#define MCDE_DITCTRLB_TEMP_MASK 0x00000001
+#define MCDE_DITCTRLB_TEMP(__x) \
+ MCDE_VAL2REG(MCDE_DITCTRLB, TEMP, __x)
+#define MCDE_DITCTRLB_COMP_SHIFT 1
+#define MCDE_DITCTRLB_COMP_MASK 0x00000002
+#define MCDE_DITCTRLB_COMP(__x) \
+ MCDE_VAL2REG(MCDE_DITCTRLB, COMP, __x)
+#define MCDE_DITCTRLB_MASK_SHIFT 4
+#define MCDE_DITCTRLB_MASK_MASK 0x00000010
+#define MCDE_DITCTRLB_MASK(__x) \
+ MCDE_VAL2REG(MCDE_DITCTRLB, MASK, __x)
+#define MCDE_DITCTRLB_FOFFX_SHIFT 5
+#define MCDE_DITCTRLB_FOFFX_MASK 0x000003E0
+#define MCDE_DITCTRLB_FOFFX(__x) \
+ MCDE_VAL2REG(MCDE_DITCTRLB, FOFFX, __x)
+#define MCDE_DITCTRLB_FOFFY_SHIFT 10
+#define MCDE_DITCTRLB_FOFFY_MASK 0x00007C00
+#define MCDE_DITCTRLB_FOFFY(__x) \
+ MCDE_VAL2REG(MCDE_DITCTRLB, FOFFY, __x)
+#define MCDE_DITOFFA 0x00000868
+#define MCDE_DITOFFA_GROUPOFFSET 0x200
+#define MCDE_DITOFFA_XG_SHIFT 0
+#define MCDE_DITOFFA_XG_MASK 0x0000001F
+#define MCDE_DITOFFA_XG(__x) \
+ MCDE_VAL2REG(MCDE_DITOFFA, XG, __x)
+#define MCDE_DITOFFA_YG_SHIFT 8
+#define MCDE_DITOFFA_YG_MASK 0x00001F00
+#define MCDE_DITOFFA_YG(__x) \
+ MCDE_VAL2REG(MCDE_DITOFFA, YG, __x)
+#define MCDE_DITOFFA_XB_SHIFT 16
+#define MCDE_DITOFFA_XB_MASK 0x001F0000
+#define MCDE_DITOFFA_XB(__x) \
+ MCDE_VAL2REG(MCDE_DITOFFA, XB, __x)
+#define MCDE_DITOFFA_YB_SHIFT 24
+#define MCDE_DITOFFA_YB_MASK 0x1F000000
+#define MCDE_DITOFFA_YB(__x) \
+ MCDE_VAL2REG(MCDE_DITOFFA, YB, __x)
+#define MCDE_DITOFFB 0x00000A68
+#define MCDE_DITOFFB_XG_SHIFT 0
+#define MCDE_DITOFFB_XG_MASK 0x0000001F
+#define MCDE_DITOFFB_XG(__x) \
+ MCDE_VAL2REG(MCDE_DITOFFB, XG, __x)
+#define MCDE_DITOFFB_YG_SHIFT 8
+#define MCDE_DITOFFB_YG_MASK 0x00001F00
+#define MCDE_DITOFFB_YG(__x) \
+ MCDE_VAL2REG(MCDE_DITOFFB, YG, __x)
+#define MCDE_DITOFFB_XB_SHIFT 16
+#define MCDE_DITOFFB_XB_MASK 0x001F0000
+#define MCDE_DITOFFB_XB(__x) \
+ MCDE_VAL2REG(MCDE_DITOFFB, XB, __x)
+#define MCDE_DITOFFB_YB_SHIFT 24
+#define MCDE_DITOFFB_YB_MASK 0x1F000000
+#define MCDE_DITOFFB_YB(__x) \
+ MCDE_VAL2REG(MCDE_DITOFFB, YB, __x)
+#define MCDE_PAL0A 0x0000086C
+#define MCDE_PAL0A_GROUPOFFSET 0x200
+#define MCDE_PAL0A_BLUE_SHIFT 0
+#define MCDE_PAL0A_BLUE_MASK 0x00000FFF
+#define MCDE_PAL0A_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_PAL0A, BLUE, __x)
+#define MCDE_PAL0A_GREEN_SHIFT 16
+#define MCDE_PAL0A_GREEN_MASK 0x0FFF0000
+#define MCDE_PAL0A_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_PAL0A, GREEN, __x)
+#define MCDE_PAL0B 0x00000A6C
+#define MCDE_PAL0B_BLUE_SHIFT 0
+#define MCDE_PAL0B_BLUE_MASK 0x00000FFF
+#define MCDE_PAL0B_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_PAL0B, BLUE, __x)
+#define MCDE_PAL0B_GREEN_SHIFT 16
+#define MCDE_PAL0B_GREEN_MASK 0x0FFF0000
+#define MCDE_PAL0B_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_PAL0B, GREEN, __x)
+#define MCDE_PAL1A 0x00000870
+#define MCDE_PAL1A_GROUPOFFSET 0x200
+#define MCDE_PAL1A_RED_SHIFT 0
+#define MCDE_PAL1A_RED_MASK 0x00000FFF
+#define MCDE_PAL1A_RED(__x) \
+ MCDE_VAL2REG(MCDE_PAL1A, RED, __x)
+#define MCDE_PAL1B 0x00000A70
+#define MCDE_PAL1B_RED_SHIFT 0
+#define MCDE_PAL1B_RED_MASK 0x00000FFF
+#define MCDE_PAL1B_RED(__x) \
+ MCDE_VAL2REG(MCDE_PAL1B, RED, __x)
+#define MCDE_ROTADD0A 0x00000874
+#define MCDE_ROTADD0A_GROUPOFFSET 0x200
+#define MCDE_ROTADD0A_ROTADD0_SHIFT 3
+#define MCDE_ROTADD0A_ROTADD0_MASK 0xFFFFFFF8
+#define MCDE_ROTADD0A_ROTADD0(__x) \
+ MCDE_VAL2REG(MCDE_ROTADD0A, ROTADD0, __x)
+#define MCDE_ROTADD0B 0x00000A74
+#define MCDE_ROTADD0B_ROTADD0_SHIFT 3
+#define MCDE_ROTADD0B_ROTADD0_MASK 0xFFFFFFF8
+#define MCDE_ROTADD0B_ROTADD0(__x) \
+ MCDE_VAL2REG(MCDE_ROTADD0B, ROTADD0, __x)
+#define MCDE_ROTADD1A 0x00000878
+#define MCDE_ROTADD1A_GROUPOFFSET 0x200
+#define MCDE_ROTADD1A_ROTADD1_SHIFT 3
+#define MCDE_ROTADD1A_ROTADD1_MASK 0xFFFFFFF8
+#define MCDE_ROTADD1A_ROTADD1(__x) \
+ MCDE_VAL2REG(MCDE_ROTADD1A, ROTADD1, __x)
+#define MCDE_ROTADD1B 0x00000A78
+#define MCDE_ROTADD1B_ROTADD1_SHIFT 3
+#define MCDE_ROTADD1B_ROTADD1_MASK 0xFFFFFFF8
+#define MCDE_ROTADD1B_ROTADD1(__x) \
+ MCDE_VAL2REG(MCDE_ROTADD1B, ROTADD1, __x)
+#define MCDE_ROTACONF 0x0000087C
+#define MCDE_ROTACONF_GROUPOFFSET 0x200
+#define MCDE_ROTACONF_ROTBURSTSIZE_SHIFT 0
+#define MCDE_ROTACONF_ROTBURSTSIZE_MASK 0x00000003
+#define MCDE_ROTACONF_ROTBURSTSIZE_1W 0
+#define MCDE_ROTACONF_ROTBURSTSIZE_2W 1
+#define MCDE_ROTACONF_ROTBURSTSIZE_4W 2
+#define MCDE_ROTACONF_ROTBURSTSIZE_8W 3
+#define MCDE_ROTACONF_ROTBURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, ROTBURSTSIZE, \
+ MCDE_ROTACONF_ROTBURSTSIZE_##__x)
+#define MCDE_ROTACONF_ROTBURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, ROTBURSTSIZE, __x)
+#define MCDE_ROTACONF_ROTBURSTSIZE_HW_SHIFT 2
+#define MCDE_ROTACONF_ROTBURSTSIZE_HW_MASK 0x00000004
+#define MCDE_ROTACONF_ROTBURSTSIZE_HW(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, ROTBURSTSIZE_HW, __x)
+#define MCDE_ROTACONF_ROTDIR_SHIFT 3
+#define MCDE_ROTACONF_ROTDIR_MASK 0x00000008
+#define MCDE_ROTACONF_ROTDIR_CCW 0
+#define MCDE_ROTACONF_ROTDIR_CW 1
+#define MCDE_ROTACONF_ROTDIR_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, ROTDIR, MCDE_ROTACONF_ROTDIR_##__x)
+#define MCDE_ROTACONF_ROTDIR(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, ROTDIR, __x)
+#define MCDE_ROTACONF_WR_MAXOUT_SHIFT 4
+#define MCDE_ROTACONF_WR_MAXOUT_MASK 0x00000030
+#define MCDE_ROTACONF_WR_MAXOUT_1_REQ 0
+#define MCDE_ROTACONF_WR_MAXOUT_2_REQ 1
+#define MCDE_ROTACONF_WR_MAXOUT_4_REQ 2
+#define MCDE_ROTACONF_WR_MAXOUT_8_REQ 3
+#define MCDE_ROTACONF_WR_MAXOUT_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, WR_MAXOUT, MCDE_ROTACONF_WR_MAXOUT_##__x)
+#define MCDE_ROTACONF_WR_MAXOUT(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, WR_MAXOUT, __x)
+#define MCDE_ROTACONF_RD_MAXOUT_SHIFT 6
+#define MCDE_ROTACONF_RD_MAXOUT_MASK 0x000000C0
+#define MCDE_ROTACONF_RD_MAXOUT_1_REQ 0
+#define MCDE_ROTACONF_RD_MAXOUT_2_REQ 1
+#define MCDE_ROTACONF_RD_MAXOUT_4_REQ 2
+#define MCDE_ROTACONF_RD_MAXOUT_8_REQ 3
+#define MCDE_ROTACONF_RD_MAXOUT_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, RD_MAXOUT, MCDE_ROTACONF_RD_MAXOUT_##__x)
+#define MCDE_ROTACONF_RD_MAXOUT(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, RD_MAXOUT, __x)
+#define MCDE_ROTACONF_STRIP_WIDTH_SHIFT 8
+#define MCDE_ROTACONF_STRIP_WIDTH_MASK 0x00007F00
+#define MCDE_ROTACONF_STRIP_WIDTH_2PIX 0
+#define MCDE_ROTACONF_STRIP_WIDTH_4PIX 1
+#define MCDE_ROTACONF_STRIP_WIDTH_8PIX 2
+#define MCDE_ROTACONF_STRIP_WIDTH_16PIX 3
+#define MCDE_ROTACONF_STRIP_WIDTH_32PIX 4
+#define MCDE_ROTACONF_STRIP_WIDTH_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, STRIP_WIDTH, \
+ MCDE_ROTACONF_STRIP_WIDTH_##__x)
+#define MCDE_ROTACONF_STRIP_WIDTH(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, STRIP_WIDTH, __x)
+#define MCDE_ROTACONF_SINGLE_BUF_SHIFT 15
+#define MCDE_ROTACONF_SINGLE_BUF_MASK 0x00008000
+#define MCDE_ROTACONF_SINGLE_BUF(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, SINGLE_BUF, __x)
+#define MCDE_ROTACONF_WR_ROPC_SHIFT 16
+#define MCDE_ROTACONF_WR_ROPC_MASK 0x00FF0000
+#define MCDE_ROTACONF_WR_ROPC(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, WR_ROPC, __x)
+#define MCDE_ROTACONF_RD_ROPC_SHIFT 24
+#define MCDE_ROTACONF_RD_ROPC_MASK 0xFF000000
+#define MCDE_ROTACONF_RD_ROPC(__x) \
+ MCDE_VAL2REG(MCDE_ROTACONF, RD_ROPC, __x)
+#define MCDE_ROTBCONF 0x00000A7C
+#define MCDE_ROTBCONF_ROTBURSTSIZE_SHIFT 0
+#define MCDE_ROTBCONF_ROTBURSTSIZE_MASK 0x00000003
+#define MCDE_ROTBCONF_ROTBURSTSIZE_1W 0
+#define MCDE_ROTBCONF_ROTBURSTSIZE_2W 1
+#define MCDE_ROTBCONF_ROTBURSTSIZE_4W 2
+#define MCDE_ROTBCONF_ROTBURSTSIZE_8W 3
+#define MCDE_ROTBCONF_ROTBURSTSIZE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, ROTBURSTSIZE, \
+ MCDE_ROTBCONF_ROTBURSTSIZE_##__x)
+#define MCDE_ROTBCONF_ROTBURSTSIZE(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, ROTBURSTSIZE, __x)
+#define MCDE_ROTBCONF_ROTBURSTSIZE_HW_SHIFT 2
+#define MCDE_ROTBCONF_ROTBURSTSIZE_HW_MASK 0x00000004
+#define MCDE_ROTBCONF_ROTBURSTSIZE_HW(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, ROTBURSTSIZE_HW, __x)
+#define MCDE_ROTBCONF_ROTDIR_SHIFT 3
+#define MCDE_ROTBCONF_ROTDIR_MASK 0x00000008
+#define MCDE_ROTBCONF_ROTDIR_CCW 0
+#define MCDE_ROTBCONF_ROTDIR_CW 1
+#define MCDE_ROTBCONF_ROTDIR_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, ROTDIR, MCDE_ROTBCONF_ROTDIR_##__x)
+#define MCDE_ROTBCONF_ROTDIR(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, ROTDIR, __x)
+#define MCDE_ROTBCONF_WR_MAXOUT_SHIFT 4
+#define MCDE_ROTBCONF_WR_MAXOUT_MASK 0x00000030
+#define MCDE_ROTBCONF_WR_MAXOUT_1_REQ 0
+#define MCDE_ROTBCONF_WR_MAXOUT_2_REQ 1
+#define MCDE_ROTBCONF_WR_MAXOUT_4_REQ 2
+#define MCDE_ROTBCONF_WR_MAXOUT_8_REQ 3
+#define MCDE_ROTBCONF_WR_MAXOUT_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, WR_MAXOUT, MCDE_ROTBCONF_WR_MAXOUT_##__x)
+#define MCDE_ROTBCONF_WR_MAXOUT(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, WR_MAXOUT, __x)
+#define MCDE_ROTBCONF_RD_MAXOUT_SHIFT 6
+#define MCDE_ROTBCONF_RD_MAXOUT_MASK 0x000000C0
+#define MCDE_ROTBCONF_RD_MAXOUT_1_REQ 0
+#define MCDE_ROTBCONF_RD_MAXOUT_2_REQ 1
+#define MCDE_ROTBCONF_RD_MAXOUT_4_REQ 2
+#define MCDE_ROTBCONF_RD_MAXOUT_8_REQ 3
+#define MCDE_ROTBCONF_RD_MAXOUT_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, RD_MAXOUT, MCDE_ROTBCONF_RD_MAXOUT_##__x)
+#define MCDE_ROTBCONF_RD_MAXOUT(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, RD_MAXOUT, __x)
+#define MCDE_ROTBCONF_STRIP_WIDTH_SHIFT 8
+#define MCDE_ROTBCONF_STRIP_WIDTH_MASK 0x00007F00
+#define MCDE_ROTBCONF_STRIP_WIDTH_2PIX 0
+#define MCDE_ROTBCONF_STRIP_WIDTH_4PIX 1
+#define MCDE_ROTBCONF_STRIP_WIDTH_8PIX 2
+#define MCDE_ROTBCONF_STRIP_WIDTH_16PIX 3
+#define MCDE_ROTBCONF_STRIP_WIDTH_32PIX 4
+#define MCDE_ROTBCONF_STRIP_WIDTH_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, STRIP_WIDTH, \
+ MCDE_ROTBCONF_STRIP_WIDTH_##__x)
+#define MCDE_ROTBCONF_STRIP_WIDTH(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, STRIP_WIDTH, __x)
+#define MCDE_ROTBCONF_SINGLE_BUF_SHIFT 15
+#define MCDE_ROTBCONF_SINGLE_BUF_MASK 0x00008000
+#define MCDE_ROTBCONF_SINGLE_BUF(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, SINGLE_BUF, __x)
+#define MCDE_ROTBCONF_WR_ROPC_SHIFT 16
+#define MCDE_ROTBCONF_WR_ROPC_MASK 0x00FF0000
+#define MCDE_ROTBCONF_WR_ROPC(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, WR_ROPC, __x)
+#define MCDE_ROTBCONF_RD_ROPC_SHIFT 24
+#define MCDE_ROTBCONF_RD_ROPC_MASK 0xFF000000
+#define MCDE_ROTBCONF_RD_ROPC(__x) \
+ MCDE_VAL2REG(MCDE_ROTBCONF, RD_ROPC, __x)
+#define MCDE_SYNCHCONFA 0x00000880
+#define MCDE_SYNCHCONFA_GROUPOFFSET 0x200
+#define MCDE_SYNCHCONFA_HWREQVEVENT_SHIFT 0
+#define MCDE_SYNCHCONFA_HWREQVEVENT_MASK 0x00000003
+#define MCDE_SYNCHCONFA_HWREQVEVENT_VSYNC 0
+#define MCDE_SYNCHCONFA_HWREQVEVENT_BACK_PORCH 1
+#define MCDE_SYNCHCONFA_HWREQVEVENT_ACTIVE_VIDEO 2
+#define MCDE_SYNCHCONFA_HWREQVEVENT_FRONT_PORCH 3
+#define MCDE_SYNCHCONFA_HWREQVEVENT_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_SYNCHCONFA, HWREQVEVENT, \
+ MCDE_SYNCHCONFA_HWREQVEVENT_##__x)
+#define MCDE_SYNCHCONFA_HWREQVEVENT(__x) \
+ MCDE_VAL2REG(MCDE_SYNCHCONFA, HWREQVEVENT, __x)
+#define MCDE_SYNCHCONFA_HWREQVCNT_SHIFT 2
+#define MCDE_SYNCHCONFA_HWREQVCNT_MASK 0x0000FFFC
+#define MCDE_SYNCHCONFA_HWREQVCNT(__x) \
+ MCDE_VAL2REG(MCDE_SYNCHCONFA, HWREQVCNT, __x)
+#define MCDE_SYNCHCONFA_SWINTVEVENT_SHIFT 16
+#define MCDE_SYNCHCONFA_SWINTVEVENT_MASK 0x00030000
+#define MCDE_SYNCHCONFA_SWINTVEVENT_VSYNC 0
+#define MCDE_SYNCHCONFA_SWINTVEVENT_BACK_PORCH 1
+#define MCDE_SYNCHCONFA_SWINTVEVENT_ACTIVE_VIDEO 2
+#define MCDE_SYNCHCONFA_SWINTVEVENT_FRONT_PORCH 3
+#define MCDE_SYNCHCONFA_SWINTVEVENT_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_SYNCHCONFA, SWINTVEVENT, \
+ MCDE_SYNCHCONFA_SWINTVEVENT_##__x)
+#define MCDE_SYNCHCONFA_SWINTVEVENT(__x) \
+ MCDE_VAL2REG(MCDE_SYNCHCONFA, SWINTVEVENT, __x)
+#define MCDE_SYNCHCONFA_SWINTVCNT_SHIFT 18
+#define MCDE_SYNCHCONFA_SWINTVCNT_MASK 0xFFFC0000
+#define MCDE_SYNCHCONFA_SWINTVCNT(__x) \
+ MCDE_VAL2REG(MCDE_SYNCHCONFA, SWINTVCNT, __x)
+#define MCDE_SYNCHCONFB 0x00000A80
+#define MCDE_SYNCHCONFB_HWREQVEVENT_SHIFT 0
+#define MCDE_SYNCHCONFB_HWREQVEVENT_MASK 0x00000003
+#define MCDE_SYNCHCONFB_HWREQVEVENT_VSYNC 0
+#define MCDE_SYNCHCONFB_HWREQVEVENT_BACK_PORCH 1
+#define MCDE_SYNCHCONFB_HWREQVEVENT_ACTIVE_VIDEO 2
+#define MCDE_SYNCHCONFB_HWREQVEVENT_FRONT_PORCH 3
+#define MCDE_SYNCHCONFB_HWREQVEVENT_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_SYNCHCONFB, HWREQVEVENT, \
+ MCDE_SYNCHCONFB_HWREQVEVENT_##__x)
+#define MCDE_SYNCHCONFB_HWREQVEVENT(__x) \
+ MCDE_VAL2REG(MCDE_SYNCHCONFB, HWREQVEVENT, __x)
+#define MCDE_SYNCHCONFB_HWREQVCNT_SHIFT 2
+#define MCDE_SYNCHCONFB_HWREQVCNT_MASK 0x0000FFFC
+#define MCDE_SYNCHCONFB_HWREQVCNT(__x) \
+ MCDE_VAL2REG(MCDE_SYNCHCONFB, HWREQVCNT, __x)
+#define MCDE_SYNCHCONFB_SWINTVEVENT_SHIFT 16
+#define MCDE_SYNCHCONFB_SWINTVEVENT_MASK 0x00030000
+#define MCDE_SYNCHCONFB_SWINTVEVENT_VSYNC 0
+#define MCDE_SYNCHCONFB_SWINTVEVENT_BACK_PORCH 1
+#define MCDE_SYNCHCONFB_SWINTVEVENT_ACTIVE_VIDEO 2
+#define MCDE_SYNCHCONFB_SWINTVEVENT_FRONT_PORCH 3
+#define MCDE_SYNCHCONFB_SWINTVEVENT_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_SYNCHCONFB, SWINTVEVENT, \
+ MCDE_SYNCHCONFB_SWINTVEVENT_##__x)
+#define MCDE_SYNCHCONFB_SWINTVEVENT(__x) \
+ MCDE_VAL2REG(MCDE_SYNCHCONFB, SWINTVEVENT, __x)
+#define MCDE_SYNCHCONFB_SWINTVCNT_SHIFT 18
+#define MCDE_SYNCHCONFB_SWINTVCNT_MASK 0xFFFC0000
+#define MCDE_SYNCHCONFB_SWINTVCNT(__x) \
+ MCDE_VAL2REG(MCDE_SYNCHCONFB, SWINTVCNT, __x)
+#define MCDE_CTRLA 0x00000884
+#define MCDE_CTRLA_GROUPOFFSET 0x200
+#define MCDE_CTRLA_FIFOWTRMRK_SHIFT 0
+#define MCDE_CTRLA_FIFOWTRMRK_MASK 0x000003FF
+#define MCDE_CTRLA_FIFOWTRMRK(__x) \
+ MCDE_VAL2REG(MCDE_CTRLA, FIFOWTRMRK, __x)
+#define MCDE_CTRLA_FIFOEMPTY_SHIFT 12
+#define MCDE_CTRLA_FIFOEMPTY_MASK 0x00001000
+#define MCDE_CTRLA_FIFOEMPTY(__x) \
+ MCDE_VAL2REG(MCDE_CTRLA, FIFOEMPTY, __x)
+#define MCDE_CTRLA_FIFOFULL_SHIFT 13
+#define MCDE_CTRLA_FIFOFULL_MASK 0x00002000
+#define MCDE_CTRLA_FIFOFULL(__x) \
+ MCDE_VAL2REG(MCDE_CTRLA, FIFOFULL, __x)
+#define MCDE_CTRLA_FORMID_SHIFT 16
+#define MCDE_CTRLA_FORMID_MASK 0x00070000
+#define MCDE_CTRLA_FORMID_DSI0VID 0
+#define MCDE_CTRLA_FORMID_DSI0CMD 1
+#define MCDE_CTRLA_FORMID_DSI1VID 2
+#define MCDE_CTRLA_FORMID_DSI1CMD 0
+#define MCDE_CTRLA_FORMID_DSI2VID 1
+#define MCDE_CTRLA_FORMID_DSI2CMD 2
+#define MCDE_CTRLA_FORMID_DPIA 0
+#define MCDE_CTRLA_FORMID_DPIB 1
+#define MCDE_CTRLA_FORMID_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CTRLA, FORMID, MCDE_CTRLA_FORMID_##__x)
+#define MCDE_CTRLA_FORMID(__x) \
+ MCDE_VAL2REG(MCDE_CTRLA, FORMID, __x)
+#define MCDE_CTRLA_FORMTYPE_SHIFT 20
+#define MCDE_CTRLA_FORMTYPE_MASK 0x00700000
+#define MCDE_CTRLA_FORMTYPE_DPITV 0
+#define MCDE_CTRLA_FORMTYPE_DBI 1
+#define MCDE_CTRLA_FORMTYPE_DSI 2
+#define MCDE_CTRLA_FORMTYPE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CTRLA, FORMTYPE, MCDE_CTRLA_FORMTYPE_##__x)
+#define MCDE_CTRLA_FORMTYPE(__x) \
+ MCDE_VAL2REG(MCDE_CTRLA, FORMTYPE, __x)
+#define MCDE_CTRLB 0x00000A84
+#define MCDE_CTRLB_FIFOWTRMRK_SHIFT 0
+#define MCDE_CTRLB_FIFOWTRMRK_MASK 0x000003FF
+#define MCDE_CTRLB_FIFOWTRMRK(__x) \
+ MCDE_VAL2REG(MCDE_CTRLB, FIFOWTRMRK, __x)
+#define MCDE_CTRLB_FIFOEMPTY_SHIFT 12
+#define MCDE_CTRLB_FIFOEMPTY_MASK 0x00001000
+#define MCDE_CTRLB_FIFOEMPTY(__x) \
+ MCDE_VAL2REG(MCDE_CTRLB, FIFOEMPTY, __x)
+#define MCDE_CTRLB_FIFOFULL_SHIFT 13
+#define MCDE_CTRLB_FIFOFULL_MASK 0x00002000
+#define MCDE_CTRLB_FIFOFULL(__x) \
+ MCDE_VAL2REG(MCDE_CTRLB, FIFOFULL, __x)
+#define MCDE_CTRLB_FORMID_SHIFT 16
+#define MCDE_CTRLB_FORMID_MASK 0x00070000
+#define MCDE_CTRLB_FORMID_DSI0VID 0
+#define MCDE_CTRLB_FORMID_DSI0CMD 1
+#define MCDE_CTRLB_FORMID_DSI1VID 2
+#define MCDE_CTRLB_FORMID_DSI1CMD 0
+#define MCDE_CTRLB_FORMID_DSI2VID 1
+#define MCDE_CTRLB_FORMID_DSI2CMD 2
+#define MCDE_CTRLB_FORMID_DPIA 0
+#define MCDE_CTRLB_FORMID_DPIB 1
+#define MCDE_CTRLB_FORMID_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CTRLB, FORMID, MCDE_CTRLB_FORMID_##__x)
+#define MCDE_CTRLB_FORMID(__x) \
+ MCDE_VAL2REG(MCDE_CTRLB, FORMID, __x)
+#define MCDE_CTRLB_FORMTYPE_SHIFT 20
+#define MCDE_CTRLB_FORMTYPE_MASK 0x00700000
+#define MCDE_CTRLB_FORMTYPE_DPITV 0
+#define MCDE_CTRLB_FORMTYPE_DBI 1
+#define MCDE_CTRLB_FORMTYPE_DSI 2
+#define MCDE_CTRLB_FORMTYPE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CTRLB, FORMTYPE, MCDE_CTRLB_FORMTYPE_##__x)
+#define MCDE_CTRLB_FORMTYPE(__x) \
+ MCDE_VAL2REG(MCDE_CTRLB, FORMTYPE, __x)
+#define MCDE_GAM0A 0x00000888
+#define MCDE_GAM0A_GROUPOFFSET 0x200
+#define MCDE_GAM0A_BLUE_SHIFT 0
+#define MCDE_GAM0A_BLUE_MASK 0x00FFFFFF
+#define MCDE_GAM0A_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_GAM0A, BLUE, __x)
+#define MCDE_GAM0B 0x00000A88
+#define MCDE_GAM0B_BLUE_SHIFT 0
+#define MCDE_GAM0B_BLUE_MASK 0x00FFFFFF
+#define MCDE_GAM0B_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_GAM0B, BLUE, __x)
+#define MCDE_GAM1A 0x0000088C
+#define MCDE_GAM1A_GROUPOFFSET 0x200
+#define MCDE_GAM1A_GREEN_SHIFT 0
+#define MCDE_GAM1A_GREEN_MASK 0x00FFFFFF
+#define MCDE_GAM1A_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_GAM1A, GREEN, __x)
+#define MCDE_GAM1B 0x00000A8C
+#define MCDE_GAM1B_GREEN_SHIFT 0
+#define MCDE_GAM1B_GREEN_MASK 0x00FFFFFF
+#define MCDE_GAM1B_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_GAM1B, GREEN, __x)
+#define MCDE_GAM2A 0x00000890
+#define MCDE_GAM2A_GROUPOFFSET 0x200
+#define MCDE_GAM2A_RED_SHIFT 0
+#define MCDE_GAM2A_RED_MASK 0x00FFFFFF
+#define MCDE_GAM2A_RED(__x) \
+ MCDE_VAL2REG(MCDE_GAM2A, RED, __x)
+#define MCDE_GAM2B 0x00000A90
+#define MCDE_GAM2B_RED_SHIFT 0
+#define MCDE_GAM2B_RED_MASK 0x00FFFFFF
+#define MCDE_GAM2B_RED(__x) \
+ MCDE_VAL2REG(MCDE_GAM2B, RED, __x)
+#define MCDE_OLEDCONV1A 0x00000894
+#define MCDE_OLEDCONV1A_GROUPOFFSET 0x200
+#define MCDE_OLEDCONV1A_ALPHA_RED_SHIFT 0
+#define MCDE_OLEDCONV1A_ALPHA_RED_MASK 0x00003FFF
+#define MCDE_OLEDCONV1A_ALPHA_RED(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV1A, ALPHA_RED, __x)
+#define MCDE_OLEDCONV1A_ALPHA_GREEN_SHIFT 16
+#define MCDE_OLEDCONV1A_ALPHA_GREEN_MASK 0x3FFF0000
+#define MCDE_OLEDCONV1A_ALPHA_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV1A, ALPHA_GREEN, __x)
+#define MCDE_OLEDCONV1B 0x00000A94
+#define MCDE_OLEDCONV1B_ALPHA_RED_SHIFT 0
+#define MCDE_OLEDCONV1B_ALPHA_RED_MASK 0x00003FFF
+#define MCDE_OLEDCONV1B_ALPHA_RED(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV1B, ALPHA_RED, __x)
+#define MCDE_OLEDCONV1B_ALPHA_GREEN_SHIFT 16
+#define MCDE_OLEDCONV1B_ALPHA_GREEN_MASK 0x3FFF0000
+#define MCDE_OLEDCONV1B_ALPHA_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV1B, ALPHA_GREEN, __x)
+#define MCDE_OLEDCONV2A 0x00000898
+#define MCDE_OLEDCONV2A_GROUPOFFSET 0x200
+#define MCDE_OLEDCONV2A_ALPHA_BLUE_SHIFT 0
+#define MCDE_OLEDCONV2A_ALPHA_BLUE_MASK 0x00003FFF
+#define MCDE_OLEDCONV2A_ALPHA_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV2A, ALPHA_BLUE, __x)
+#define MCDE_OLEDCONV2A_BETA_RED_SHIFT 16
+#define MCDE_OLEDCONV2A_BETA_RED_MASK 0x3FFF0000
+#define MCDE_OLEDCONV2A_BETA_RED(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV2A, BETA_RED, __x)
+#define MCDE_OLEDCONV2B 0x00000A98
+#define MCDE_OLEDCONV2B_ALPHA_BLUE_SHIFT 0
+#define MCDE_OLEDCONV2B_ALPHA_BLUE_MASK 0x00003FFF
+#define MCDE_OLEDCONV2B_ALPHA_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV2B, ALPHA_BLUE, __x)
+#define MCDE_OLEDCONV2B_BETA_RED_SHIFT 16
+#define MCDE_OLEDCONV2B_BETA_RED_MASK 0x3FFF0000
+#define MCDE_OLEDCONV2B_BETA_RED(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV2B, BETA_RED, __x)
+#define MCDE_OLEDCONV3A 0x0000089C
+#define MCDE_OLEDCONV3A_GROUPOFFSET 0x200
+#define MCDE_OLEDCONV3A_BETA_GREEN_SHIFT 0
+#define MCDE_OLEDCONV3A_BETA_GREEN_MASK 0x00003FFF
+#define MCDE_OLEDCONV3A_BETA_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV3A, BETA_GREEN, __x)
+#define MCDE_OLEDCONV3A_BETA_BLUE_SHIFT 16
+#define MCDE_OLEDCONV3A_BETA_BLUE_MASK 0x3FFF0000
+#define MCDE_OLEDCONV3A_BETA_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV3A, BETA_BLUE, __x)
+#define MCDE_OLEDCONV3B 0x00000A9C
+#define MCDE_OLEDCONV3B_BETA_GREEN_SHIFT 0
+#define MCDE_OLEDCONV3B_BETA_GREEN_MASK 0x00003FFF
+#define MCDE_OLEDCONV3B_BETA_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV3B, BETA_GREEN, __x)
+#define MCDE_OLEDCONV3B_BETA_BLUE_SHIFT 16
+#define MCDE_OLEDCONV3B_BETA_BLUE_MASK 0x3FFF0000
+#define MCDE_OLEDCONV3B_BETA_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV3B, BETA_BLUE, __x)
+#define MCDE_OLEDCONV4A 0x000008A0
+#define MCDE_OLEDCONV4A_GROUPOFFSET 0x200
+#define MCDE_OLEDCONV4A_GAMMA_RED_SHIFT 0
+#define MCDE_OLEDCONV4A_GAMMA_RED_MASK 0x00003FFF
+#define MCDE_OLEDCONV4A_GAMMA_RED(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV4A, GAMMA_RED, __x)
+#define MCDE_OLEDCONV4A_GAMMA_GREEN_SHIFT 16
+#define MCDE_OLEDCONV4A_GAMMA_GREEN_MASK 0x3FFF0000
+#define MCDE_OLEDCONV4A_GAMMA_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV4A, GAMMA_GREEN, __x)
+#define MCDE_OLEDCONV4B 0x00000AA0
+#define MCDE_OLEDCONV4B_GAMMA_RED_SHIFT 0
+#define MCDE_OLEDCONV4B_GAMMA_RED_MASK 0x00003FFF
+#define MCDE_OLEDCONV4B_GAMMA_RED(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV4B, GAMMA_RED, __x)
+#define MCDE_OLEDCONV4B_GAMMA_GREEN_SHIFT 16
+#define MCDE_OLEDCONV4B_GAMMA_GREEN_MASK 0x3FFF0000
+#define MCDE_OLEDCONV4B_GAMMA_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV4B, GAMMA_GREEN, __x)
+#define MCDE_OLEDCONV5A 0x000008A4
+#define MCDE_OLEDCONV5A_GROUPOFFSET 0x200
+#define MCDE_OLEDCONV5A_GAMMA_BLUE_SHIFT 0
+#define MCDE_OLEDCONV5A_GAMMA_BLUE_MASK 0x00003FFF
+#define MCDE_OLEDCONV5A_GAMMA_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV5A, GAMMA_BLUE, __x)
+#define MCDE_OLEDCONV5A_OFF_RED_SHIFT 16
+#define MCDE_OLEDCONV5A_OFF_RED_MASK 0x3FFF0000
+#define MCDE_OLEDCONV5A_OFF_RED(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV5A, OFF_RED, __x)
+#define MCDE_OLEDCONV5B 0x00000AA4
+#define MCDE_OLEDCONV5B_GAMMA_BLUE_SHIFT 0
+#define MCDE_OLEDCONV5B_GAMMA_BLUE_MASK 0x00003FFF
+#define MCDE_OLEDCONV5B_GAMMA_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV5B, GAMMA_BLUE, __x)
+#define MCDE_OLEDCONV5B_OFF_RED_SHIFT 16
+#define MCDE_OLEDCONV5B_OFF_RED_MASK 0x3FFF0000
+#define MCDE_OLEDCONV5B_OFF_RED(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV5B, OFF_RED, __x)
+#define MCDE_OLEDCONV6A 0x000008A8
+#define MCDE_OLEDCONV6A_GROUPOFFSET 0x200
+#define MCDE_OLEDCONV6A_OFF_GREEN_SHIFT 0
+#define MCDE_OLEDCONV6A_OFF_GREEN_MASK 0x00003FFF
+#define MCDE_OLEDCONV6A_OFF_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV6A, OFF_GREEN, __x)
+#define MCDE_OLEDCONV6A_OFF_BLUE_SHIFT 16
+#define MCDE_OLEDCONV6A_OFF_BLUE_MASK 0x3FFF0000
+#define MCDE_OLEDCONV6A_OFF_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV6A, OFF_BLUE, __x)
+#define MCDE_OLEDCONV6B 0x00000AA8
+#define MCDE_OLEDCONV6B_OFF_GREEN_SHIFT 0
+#define MCDE_OLEDCONV6B_OFF_GREEN_MASK 0x00003FFF
+#define MCDE_OLEDCONV6B_OFF_GREEN(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV6B, OFF_GREEN, __x)
+#define MCDE_OLEDCONV6B_OFF_BLUE_SHIFT 16
+#define MCDE_OLEDCONV6B_OFF_BLUE_MASK 0x3FFF0000
+#define MCDE_OLEDCONV6B_OFF_BLUE(__x) \
+ MCDE_VAL2REG(MCDE_OLEDCONV6B, OFF_BLUE, __x)
+#define MCDE_CRC 0x00000C00
+#define MCDE_CRC_FLOEN_SHIFT 0
+#define MCDE_CRC_FLOEN_MASK 0x00000001
+#define MCDE_CRC_FLOEN(__x) \
+ MCDE_VAL2REG(MCDE_CRC, FLOEN, __x)
+#define MCDE_CRC_POWEREN_SHIFT 1
+#define MCDE_CRC_POWEREN_MASK 0x00000002
+#define MCDE_CRC_POWEREN(__x) \
+ MCDE_VAL2REG(MCDE_CRC, POWEREN, __x)
+#define MCDE_CRC_C1EN_SHIFT 2
+#define MCDE_CRC_C1EN_MASK 0x00000004
+#define MCDE_CRC_C1EN(__x) \
+ MCDE_VAL2REG(MCDE_CRC, C1EN, __x)
+#define MCDE_CRC_C2EN_SHIFT 3
+#define MCDE_CRC_C2EN_MASK 0x00000008
+#define MCDE_CRC_C2EN(__x) \
+ MCDE_VAL2REG(MCDE_CRC, C2EN, __x)
+#define MCDE_CRC_WMLVL1_SHIFT 4
+#define MCDE_CRC_WMLVL1_MASK 0x00000010
+#define MCDE_CRC_WMLVL1(__x) \
+ MCDE_VAL2REG(MCDE_CRC, WMLVL1, __x)
+#define MCDE_CRC_WMLVL2_SHIFT 5
+#define MCDE_CRC_WMLVL2_MASK 0x00000020
+#define MCDE_CRC_WMLVL2(__x) \
+ MCDE_VAL2REG(MCDE_CRC, WMLVL2, __x)
+#define MCDE_CRC_SYNCSEL_SHIFT 6
+#define MCDE_CRC_SYNCSEL_MASK 0x00000040
+#define MCDE_CRC_SYNCSEL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, SYNCSEL, __x)
+#define MCDE_CRC_SYCEN0_SHIFT 7
+#define MCDE_CRC_SYCEN0_MASK 0x00000080
+#define MCDE_CRC_SYCEN0(__x) \
+ MCDE_VAL2REG(MCDE_CRC, SYCEN0, __x)
+#define MCDE_CRC_SYCEN1_SHIFT 8
+#define MCDE_CRC_SYCEN1_MASK 0x00000100
+#define MCDE_CRC_SYCEN1(__x) \
+ MCDE_VAL2REG(MCDE_CRC, SYCEN1, __x)
+#define MCDE_CRC_SIZE1_SHIFT 9
+#define MCDE_CRC_SIZE1_MASK 0x00000200
+#define MCDE_CRC_SIZE1(__x) \
+ MCDE_VAL2REG(MCDE_CRC, SIZE1, __x)
+#define MCDE_CRC_SIZE2_SHIFT 10
+#define MCDE_CRC_SIZE2_MASK 0x00000400
+#define MCDE_CRC_SIZE2(__x) \
+ MCDE_VAL2REG(MCDE_CRC, SIZE2, __x)
+#define MCDE_CRC_INBAND1_SHIFT 11
+#define MCDE_CRC_INBAND1_MASK 0x00000800
+#define MCDE_CRC_INBAND1(__x) \
+ MCDE_VAL2REG(MCDE_CRC, INBAND1, __x)
+#define MCDE_CRC_INBAND2_SHIFT 12
+#define MCDE_CRC_INBAND2_MASK 0x00001000
+#define MCDE_CRC_INBAND2(__x) \
+ MCDE_VAL2REG(MCDE_CRC, INBAND2, __x)
+#define MCDE_CRC_CLKSEL_SHIFT 13
+#define MCDE_CRC_CLKSEL_MASK 0x00006000
+#define MCDE_CRC_CLKSEL_166MHz 0
+#define MCDE_CRC_CLKSEL_48MHz 1
+#define MCDE_CRC_CLKSEL_LCD 2
+#define MCDE_CRC_CLKSEL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRC, CLKSEL, MCDE_CRC_CLKSEL_##__x)
+#define MCDE_CRC_CLKSEL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, CLKSEL, __x)
+#define MCDE_CRC_YUVCONVC1EN_SHIFT 15
+#define MCDE_CRC_YUVCONVC1EN_MASK 0x00008000
+#define MCDE_CRC_YUVCONVC1EN(__x) \
+ MCDE_VAL2REG(MCDE_CRC, YUVCONVC1EN, __x)
+#define MCDE_CRC_CS1EN_SHIFT 16
+#define MCDE_CRC_CS1EN_MASK 0x00010000
+#define MCDE_CRC_CS1EN(__x) \
+ MCDE_VAL2REG(MCDE_CRC, CS1EN, __x)
+#define MCDE_CRC_CS2EN_SHIFT 17
+#define MCDE_CRC_CS2EN_MASK 0x00020000
+#define MCDE_CRC_CS2EN(__x) \
+ MCDE_VAL2REG(MCDE_CRC, CS2EN, __x)
+#define MCDE_CRC_RESEN_SHIFT 18
+#define MCDE_CRC_RESEN_MASK 0x00040000
+#define MCDE_CRC_RESEN(__x) \
+ MCDE_VAL2REG(MCDE_CRC, RESEN, __x)
+#define MCDE_CRC_CS1POL_SHIFT 19
+#define MCDE_CRC_CS1POL_MASK 0x00080000
+#define MCDE_CRC_CS1POL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, CS1POL, __x)
+#define MCDE_CRC_CS2POL_SHIFT 20
+#define MCDE_CRC_CS2POL_MASK 0x00100000
+#define MCDE_CRC_CS2POL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, CS2POL, __x)
+#define MCDE_CRC_CD1POL_SHIFT 21
+#define MCDE_CRC_CD1POL_MASK 0x00200000
+#define MCDE_CRC_CD1POL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, CD1POL, __x)
+#define MCDE_CRC_CD2POL_SHIFT 22
+#define MCDE_CRC_CD2POL_MASK 0x00400000
+#define MCDE_CRC_CD2POL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, CD2POL, __x)
+#define MCDE_CRC_WR1POL_SHIFT 23
+#define MCDE_CRC_WR1POL_MASK 0x00800000
+#define MCDE_CRC_WR1POL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, WR1POL, __x)
+#define MCDE_CRC_WR2POL_SHIFT 24
+#define MCDE_CRC_WR2POL_MASK 0x01000000
+#define MCDE_CRC_WR2POL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, WR2POL, __x)
+#define MCDE_CRC_RD1POL_SHIFT 25
+#define MCDE_CRC_RD1POL_MASK 0x02000000
+#define MCDE_CRC_RD1POL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, RD1POL, __x)
+#define MCDE_CRC_RD2POL_SHIFT 26
+#define MCDE_CRC_RD2POL_MASK 0x04000000
+#define MCDE_CRC_RD2POL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, RD2POL, __x)
+#define MCDE_CRC_RES1POL_SHIFT 27
+#define MCDE_CRC_RES1POL_MASK 0x08000000
+#define MCDE_CRC_RES1POL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, RES1POL, __x)
+#define MCDE_CRC_RES2POL_SHIFT 28
+#define MCDE_CRC_RES2POL_MASK 0x10000000
+#define MCDE_CRC_RES2POL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, RES2POL, __x)
+#define MCDE_CRC_SYNCCTRL_SHIFT 29
+#define MCDE_CRC_SYNCCTRL_MASK 0x60000000
+#define MCDE_CRC_SYNCCTRL_OFF 0
+#define MCDE_CRC_SYNCCTRL_C0 1
+#define MCDE_CRC_SYNCCTRL_C1 2
+#define MCDE_CRC_SYNCCTRL_PING_PONG 3
+#define MCDE_CRC_SYNCCTRL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CRC, SYNCCTRL, MCDE_CRC_SYNCCTRL_##__x)
+#define MCDE_CRC_SYNCCTRL(__x) \
+ MCDE_VAL2REG(MCDE_CRC, SYNCCTRL, __x)
+#define MCDE_CRC_CLAMPC1EN_SHIFT 31
+#define MCDE_CRC_CLAMPC1EN_MASK 0x80000000
+#define MCDE_CRC_CLAMPC1EN(__x) \
+ MCDE_VAL2REG(MCDE_CRC, CLAMPC1EN, __x)
+#define MCDE_PBCCRC0 0x00000C04
+#define MCDE_PBCCRC0_GROUPOFFSET 0x4
+#define MCDE_PBCCRC0_BSCM_SHIFT 0
+#define MCDE_PBCCRC0_BSCM_MASK 0x00000007
+#define MCDE_PBCCRC0_BSCM_1_8BIT 0
+#define MCDE_PBCCRC0_BSCM_2_8BIT 1
+#define MCDE_PBCCRC0_BSCM_3_8BIT 2
+#define MCDE_PBCCRC0_BSCM_1_16BIT 3
+#define MCDE_PBCCRC0_BSCM_2_16BIT 4
+#define MCDE_PBCCRC0_BSCM_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC0, BSCM, MCDE_PBCCRC0_BSCM_##__x)
+#define MCDE_PBCCRC0_BSCM(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC0, BSCM, __x)
+#define MCDE_PBCCRC0_BSDM_SHIFT 3
+#define MCDE_PBCCRC0_BSDM_MASK 0x00000038
+#define MCDE_PBCCRC0_BSDM_1_8BIT 0
+#define MCDE_PBCCRC0_BSDM_2_8BIT 1
+#define MCDE_PBCCRC0_BSDM_3_8BIT 2
+#define MCDE_PBCCRC0_BSDM_1_16BIT 3
+#define MCDE_PBCCRC0_BSDM_2_16BIT 4
+#define MCDE_PBCCRC0_BSDM_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC0, BSDM, MCDE_PBCCRC0_BSDM_##__x)
+#define MCDE_PBCCRC0_BSDM(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC0, BSDM, __x)
+#define MCDE_PBCCRC0_PDM_SHIFT 6
+#define MCDE_PBCCRC0_PDM_MASK 0x000000C0
+#define MCDE_PBCCRC0_PDM_NORMAL 0
+#define MCDE_PBCCRC0_PDM_16_TO_32 1
+#define MCDE_PBCCRC0_PDM_24_TO_32_RIGHT 2
+#define MCDE_PBCCRC0_PDM_24_TO_32_LEFT 3
+#define MCDE_PBCCRC0_PDM_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC0, PDM, MCDE_PBCCRC0_PDM_##__x)
+#define MCDE_PBCCRC0_PDM(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC0, PDM, __x)
+#define MCDE_PBCCRC0_PDCTRL_SHIFT 12
+#define MCDE_PBCCRC0_PDCTRL_MASK 0x00001000
+#define MCDE_PBCCRC0_PDCTRL(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC0, PDCTRL, __x)
+#define MCDE_PBCCRC0_BPP_SHIFT 13
+#define MCDE_PBCCRC0_BPP_MASK 0x0000E000
+#define MCDE_PBCCRC0_BPP_8BPP 0
+#define MCDE_PBCCRC0_BPP_12BPP 1
+#define MCDE_PBCCRC0_BPP_15BPP 2
+#define MCDE_PBCCRC0_BPP_16BPP 3
+#define MCDE_PBCCRC0_BPP_18BPP 4
+#define MCDE_PBCCRC0_BPP_24BPP 5
+#define MCDE_PBCCRC0_BPP(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC0, BPP, __x)
+#define MCDE_PBCCRC1 0x00000C08
+#define MCDE_PBCCRC1_BSCM_SHIFT 0
+#define MCDE_PBCCRC1_BSCM_MASK 0x00000007
+#define MCDE_PBCCRC1_BSCM_1_8BIT 0
+#define MCDE_PBCCRC1_BSCM_2_8BIT 1
+#define MCDE_PBCCRC1_BSCM_3_8BIT 2
+#define MCDE_PBCCRC1_BSCM_1_16BIT 3
+#define MCDE_PBCCRC1_BSCM_2_16BIT 4
+#define MCDE_PBCCRC1_BSCM_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC1, BSCM, MCDE_PBCCRC1_BSCM_##__x)
+#define MCDE_PBCCRC1_BSCM(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC1, BSCM, __x)
+#define MCDE_PBCCRC1_BSDM_SHIFT 3
+#define MCDE_PBCCRC1_BSDM_MASK 0x00000038
+#define MCDE_PBCCRC1_BSDM_1_8BIT 0
+#define MCDE_PBCCRC1_BSDM_2_8BIT 1
+#define MCDE_PBCCRC1_BSDM_3_8BIT 2
+#define MCDE_PBCCRC1_BSDM_1_16BIT 3
+#define MCDE_PBCCRC1_BSDM_2_16BIT 4
+#define MCDE_PBCCRC1_BSDM_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC1, BSDM, MCDE_PBCCRC1_BSDM_##__x)
+#define MCDE_PBCCRC1_BSDM(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC1, BSDM, __x)
+#define MCDE_PBCCRC1_PDM_SHIFT 6
+#define MCDE_PBCCRC1_PDM_MASK 0x000000C0
+#define MCDE_PBCCRC1_PDM_NORMAL 0
+#define MCDE_PBCCRC1_PDM_16_TO_32 1
+#define MCDE_PBCCRC1_PDM_24_TO_32_RIGHT 2
+#define MCDE_PBCCRC1_PDM_24_TO_32_LEFT 3
+#define MCDE_PBCCRC1_PDM_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC1, PDM, MCDE_PBCCRC1_PDM_##__x)
+#define MCDE_PBCCRC1_PDM(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC1, PDM, __x)
+#define MCDE_PBCCRC1_PDCTRL_SHIFT 12
+#define MCDE_PBCCRC1_PDCTRL_MASK 0x00001000
+#define MCDE_PBCCRC1_PDCTRL(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC1, PDCTRL, __x)
+#define MCDE_PBCCRC1_BPP_SHIFT 13
+#define MCDE_PBCCRC1_BPP_MASK 0x0000E000
+#define MCDE_PBCCRC1_BPP_8BPP 0
+#define MCDE_PBCCRC1_BPP_12BPP 1
+#define MCDE_PBCCRC1_BPP_15BPP 2
+#define MCDE_PBCCRC1_BPP_16BPP 3
+#define MCDE_PBCCRC1_BPP_18BPP 4
+#define MCDE_PBCCRC1_BPP_24BPP 5
+#define MCDE_PBCCRC1_BPP(__x) \
+ MCDE_VAL2REG(MCDE_PBCCRC1, BPP, __x)
+#define MCDE_PBCBMRC00 0x00000C0C
+#define MCDE_PBCBMRC00_GROUPOFFSET 0x4
+#define MCDE_PBCBMRC00_MUXI_SHIFT 0
+#define MCDE_PBCBMRC00_MUXI_MASK 0xFFFFFFFF
+#define MCDE_PBCBMRC00_MUXI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBMRC00, MUXI, __x)
+#define MCDE_PBCBMRC01 0x00000C10
+#define MCDE_PBCBMRC01_MUXI_SHIFT 0
+#define MCDE_PBCBMRC01_MUXI_MASK 0xFFFFFFFF
+#define MCDE_PBCBMRC01_MUXI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBMRC01, MUXI, __x)
+#define MCDE_PBCBMRC02 0x00000C14
+#define MCDE_PBCBMRC02_MUXI_SHIFT 0
+#define MCDE_PBCBMRC02_MUXI_MASK 0xFFFFFFFF
+#define MCDE_PBCBMRC02_MUXI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBMRC02, MUXI, __x)
+#define MCDE_PBCBMRC03 0x00000C18
+#define MCDE_PBCBMRC03_MUXI_SHIFT 0
+#define MCDE_PBCBMRC03_MUXI_MASK 0xFFFFFFFF
+#define MCDE_PBCBMRC03_MUXI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBMRC03, MUXI, __x)
+#define MCDE_PBCBMRC04 0x00000C1C
+#define MCDE_PBCBMRC04_MUXI_SHIFT 0
+#define MCDE_PBCBMRC04_MUXI_MASK 0xFFFFFFFF
+#define MCDE_PBCBMRC04_MUXI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBMRC04, MUXI, __x)
+#define MCDE_PBCBMRC10 0x00000C20
+#define MCDE_PBCBMRC10_MUXI_SHIFT 0
+#define MCDE_PBCBMRC10_MUXI_MASK 0xFFFFFFFF
+#define MCDE_PBCBMRC10_MUXI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBMRC10, MUXI, __x)
+#define MCDE_PBCBMRC11 0x00000C24
+#define MCDE_PBCBMRC11_MUXI_SHIFT 0
+#define MCDE_PBCBMRC11_MUXI_MASK 0xFFFFFFFF
+#define MCDE_PBCBMRC11_MUXI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBMRC11, MUXI, __x)
+#define MCDE_PBCBMRC12 0x00000C28
+#define MCDE_PBCBMRC12_MUXI_SHIFT 0
+#define MCDE_PBCBMRC12_MUXI_MASK 0xFFFFFFFF
+#define MCDE_PBCBMRC12_MUXI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBMRC12, MUXI, __x)
+#define MCDE_PBCBMRC13 0x00000C2C
+#define MCDE_PBCBMRC13_MUXI_SHIFT 0
+#define MCDE_PBCBMRC13_MUXI_MASK 0xFFFFFFFF
+#define MCDE_PBCBMRC13_MUXI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBMRC13, MUXI, __x)
+#define MCDE_PBCBMRC14 0x00000C30
+#define MCDE_PBCBMRC14_MUXI_SHIFT 0
+#define MCDE_PBCBMRC14_MUXI_MASK 0xFFFFFFFF
+#define MCDE_PBCBMRC14_MUXI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBMRC14, MUXI, __x)
+#define MCDE_PBCBCRC00 0x00000C34
+#define MCDE_PBCBCRC00_GROUPOFFSET 0x4
+#define MCDE_PBCBCRC00_CTLI_SHIFT 0
+#define MCDE_PBCBCRC00_CTLI_MASK 0xFFFFFFFF
+#define MCDE_PBCBCRC00_CTLI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBCRC00, CTLI, __x)
+#define MCDE_PBCBCRC10 0x00000C38
+#define MCDE_PBCBCRC10_CTLI_SHIFT 0
+#define MCDE_PBCBCRC10_CTLI_MASK 0xFFFFFFFF
+#define MCDE_PBCBCRC10_CTLI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBCRC10, CTLI, __x)
+#define MCDE_PBCBCRC01 0x00000C48
+#define MCDE_PBCBCRC01_GROUPOFFSET 0x4
+#define MCDE_PBCBCRC01_CTLI_SHIFT 0
+#define MCDE_PBCBCRC01_CTLI_MASK 0xFFFFFFFF
+#define MCDE_PBCBCRC01_CTLI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBCRC01, CTLI, __x)
+#define MCDE_PBCBCRC11 0x00000C4C
+#define MCDE_PBCBCRC11_CTLI_SHIFT 0
+#define MCDE_PBCBCRC11_CTLI_MASK 0xFFFFFFFF
+#define MCDE_PBCBCRC11_CTLI(__x) \
+ MCDE_VAL2REG(MCDE_PBCBCRC11, CTLI, __x)
+#define MCDE_VSCRC0 0x00000C5C
+#define MCDE_VSCRC0_GROUPOFFSET 0x4
+#define MCDE_VSCRC0_VSPMIN_SHIFT 0
+#define MCDE_VSCRC0_VSPMIN_MASK 0x00000FFF
+#define MCDE_VSCRC0_VSPMIN(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC0, VSPMIN, __x)
+#define MCDE_VSCRC0_VSPMAX_SHIFT 12
+#define MCDE_VSCRC0_VSPMAX_MASK 0x00FFF000
+#define MCDE_VSCRC0_VSPMAX(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC0, VSPMAX, __x)
+#define MCDE_VSCRC0_VSPDIV_SHIFT 24
+#define MCDE_VSCRC0_VSPDIV_MASK 0x07000000
+#define MCDE_VSCRC0_VSPDIV(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC0, VSPDIV, __x)
+#define MCDE_VSCRC0_VSPOL_SHIFT 27
+#define MCDE_VSCRC0_VSPOL_MASK 0x08000000
+#define MCDE_VSCRC0_VSPOL_ACTIVE_HIGH 0
+#define MCDE_VSCRC0_VSPOL_ACTIVE_LOW 1
+#define MCDE_VSCRC0_VSPOL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC0, VSPOL, MCDE_VSCRC0_VSPOL_##__x)
+#define MCDE_VSCRC0_VSPOL(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC0, VSPOL, __x)
+#define MCDE_VSCRC0_VSSEL_SHIFT 28
+#define MCDE_VSCRC0_VSSEL_MASK 0x10000000
+#define MCDE_VSCRC0_VSSEL_VSYNC 0
+#define MCDE_VSCRC0_VSSEL_HSYNC 1
+#define MCDE_VSCRC0_VSSEL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC0, VSSEL, MCDE_VSCRC0_VSSEL_##__x)
+#define MCDE_VSCRC0_VSSEL(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC0, VSSEL, __x)
+#define MCDE_VSCRC0_VSDBL_SHIFT 29
+#define MCDE_VSCRC0_VSDBL_MASK 0xE0000000
+#define MCDE_VSCRC0_VSDBL(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC0, VSDBL, __x)
+#define MCDE_VSCRC1 0x00000C60
+#define MCDE_VSCRC1_VSPMIN_SHIFT 0
+#define MCDE_VSCRC1_VSPMIN_MASK 0x00000FFF
+#define MCDE_VSCRC1_VSPMIN(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC1, VSPMIN, __x)
+#define MCDE_VSCRC1_VSPMAX_SHIFT 12
+#define MCDE_VSCRC1_VSPMAX_MASK 0x00FFF000
+#define MCDE_VSCRC1_VSPMAX(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC1, VSPMAX, __x)
+#define MCDE_VSCRC1_VSPDIV_SHIFT 24
+#define MCDE_VSCRC1_VSPDIV_MASK 0x07000000
+#define MCDE_VSCRC1_VSPDIV(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC1, VSPDIV, __x)
+#define MCDE_VSCRC1_VSPOL_SHIFT 27
+#define MCDE_VSCRC1_VSPOL_MASK 0x08000000
+#define MCDE_VSCRC1_VSPOL_ACTIVE_HIGH 0
+#define MCDE_VSCRC1_VSPOL_ACTIVE_LOW 1
+#define MCDE_VSCRC1_VSPOL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC1, VSPOL, MCDE_VSCRC1_VSPOL_##__x)
+#define MCDE_VSCRC1_VSPOL(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC1, VSPOL, __x)
+#define MCDE_VSCRC1_VSSEL_SHIFT 28
+#define MCDE_VSCRC1_VSSEL_MASK 0x10000000
+#define MCDE_VSCRC1_VSSEL_VSYNC 0
+#define MCDE_VSCRC1_VSSEL_HSYNC 1
+#define MCDE_VSCRC1_VSSEL_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC1, VSSEL, MCDE_VSCRC1_VSSEL_##__x)
+#define MCDE_VSCRC1_VSSEL(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC1, VSSEL, __x)
+#define MCDE_VSCRC1_VSDBL_SHIFT 29
+#define MCDE_VSCRC1_VSDBL_MASK 0xE0000000
+#define MCDE_VSCRC1_VSDBL(__x) \
+ MCDE_VAL2REG(MCDE_VSCRC1, VSDBL, __x)
+#define MCDE_SCTRC 0x00000C64
+#define MCDE_SCTRC_SYNCDELC0_SHIFT 0
+#define MCDE_SCTRC_SYNCDELC0_MASK 0x000000FF
+#define MCDE_SCTRC_SYNCDELC0(__x) \
+ MCDE_VAL2REG(MCDE_SCTRC, SYNCDELC0, __x)
+#define MCDE_SCTRC_SYNCDELC1_SHIFT 8
+#define MCDE_SCTRC_SYNCDELC1_MASK 0x0000FF00
+#define MCDE_SCTRC_SYNCDELC1(__x) \
+ MCDE_VAL2REG(MCDE_SCTRC, SYNCDELC1, __x)
+#define MCDE_SCTRC_TRDELC_SHIFT 16
+#define MCDE_SCTRC_TRDELC_MASK 0x0FFF0000
+#define MCDE_SCTRC_TRDELC(__x) \
+ MCDE_VAL2REG(MCDE_SCTRC, TRDELC, __x)
+#define MCDE_SCSRC 0x00000C68
+#define MCDE_SCSRC_VSTAC0_SHIFT 0
+#define MCDE_SCSRC_VSTAC0_MASK 0x00000001
+#define MCDE_SCSRC_VSTAC0(__x) \
+ MCDE_VAL2REG(MCDE_SCSRC, VSTAC0, __x)
+#define MCDE_SCSRC_VSTAC1_SHIFT 1
+#define MCDE_SCSRC_VSTAC1_MASK 0x00000002
+#define MCDE_SCSRC_VSTAC1(__x) \
+ MCDE_VAL2REG(MCDE_SCSRC, VSTAC1, __x)
+#define MCDE_BCNR0 0x00000C6C
+#define MCDE_BCNR0_GROUPOFFSET 0x4
+#define MCDE_BCNR0_BCN_SHIFT 0
+#define MCDE_BCNR0_BCN_MASK 0x000000FF
+#define MCDE_BCNR0_BCN(__x) \
+ MCDE_VAL2REG(MCDE_BCNR0, BCN, __x)
+#define MCDE_BCNR1 0x00000C70
+#define MCDE_BCNR1_BCN_SHIFT 0
+#define MCDE_BCNR1_BCN_MASK 0x000000FF
+#define MCDE_BCNR1_BCN(__x) \
+ MCDE_VAL2REG(MCDE_BCNR1, BCN, __x)
+#define MCDE_CSCDTR0 0x00000C74
+#define MCDE_CSCDTR0_GROUPOFFSET 0x4
+#define MCDE_CSCDTR0_CSACT_SHIFT 0
+#define MCDE_CSCDTR0_CSACT_MASK 0x000000FF
+#define MCDE_CSCDTR0_CSACT(__x) \
+ MCDE_VAL2REG(MCDE_CSCDTR0, CSACT, __x)
+#define MCDE_CSCDTR0_CSDEACT_SHIFT 8
+#define MCDE_CSCDTR0_CSDEACT_MASK 0x0000FF00
+#define MCDE_CSCDTR0_CSDEACT(__x) \
+ MCDE_VAL2REG(MCDE_CSCDTR0, CSDEACT, __x)
+#define MCDE_CSCDTR0_CDACT_SHIFT 16
+#define MCDE_CSCDTR0_CDACT_MASK 0x00FF0000
+#define MCDE_CSCDTR0_CDACT(__x) \
+ MCDE_VAL2REG(MCDE_CSCDTR0, CDACT, __x)
+#define MCDE_CSCDTR0_CDDEACT_SHIFT 24
+#define MCDE_CSCDTR0_CDDEACT_MASK 0xFF000000
+#define MCDE_CSCDTR0_CDDEACT(__x) \
+ MCDE_VAL2REG(MCDE_CSCDTR0, CDDEACT, __x)
+#define MCDE_CSCDTR1 0x00000C78
+#define MCDE_CSCDTR1_CSACT_SHIFT 0
+#define MCDE_CSCDTR1_CSACT_MASK 0x000000FF
+#define MCDE_CSCDTR1_CSACT(__x) \
+ MCDE_VAL2REG(MCDE_CSCDTR1, CSACT, __x)
+#define MCDE_CSCDTR1_CSDEACT_SHIFT 8
+#define MCDE_CSCDTR1_CSDEACT_MASK 0x0000FF00
+#define MCDE_CSCDTR1_CSDEACT(__x) \
+ MCDE_VAL2REG(MCDE_CSCDTR1, CSDEACT, __x)
+#define MCDE_CSCDTR1_CDACT_SHIFT 16
+#define MCDE_CSCDTR1_CDACT_MASK 0x00FF0000
+#define MCDE_CSCDTR1_CDACT(__x) \
+ MCDE_VAL2REG(MCDE_CSCDTR1, CDACT, __x)
+#define MCDE_CSCDTR1_CDDEACT_SHIFT 24
+#define MCDE_CSCDTR1_CDDEACT_MASK 0xFF000000
+#define MCDE_CSCDTR1_CDDEACT(__x) \
+ MCDE_VAL2REG(MCDE_CSCDTR1, CDDEACT, __x)
+#define MCDE_RDWRTR0 0x00000C7C
+#define MCDE_RDWRTR0_GROUPOFFSET 0x4
+#define MCDE_RDWRTR0_RWACT_SHIFT 0
+#define MCDE_RDWRTR0_RWACT_MASK 0x000000FF
+#define MCDE_RDWRTR0_RWACT(__x) \
+ MCDE_VAL2REG(MCDE_RDWRTR0, RWACT, __x)
+#define MCDE_RDWRTR0_RWDEACT_SHIFT 8
+#define MCDE_RDWRTR0_RWDEACT_MASK 0x0000FF00
+#define MCDE_RDWRTR0_RWDEACT(__x) \
+ MCDE_VAL2REG(MCDE_RDWRTR0, RWDEACT, __x)
+#define MCDE_RDWRTR0_MOTINT_SHIFT 16
+#define MCDE_RDWRTR0_MOTINT_MASK 0x00010000
+#define MCDE_RDWRTR0_MOTINT(__x) \
+ MCDE_VAL2REG(MCDE_RDWRTR0, MOTINT, __x)
+#define MCDE_RDWRTR1 0x00000C80
+#define MCDE_RDWRTR1_RWACT_SHIFT 0
+#define MCDE_RDWRTR1_RWACT_MASK 0x000000FF
+#define MCDE_RDWRTR1_RWACT(__x) \
+ MCDE_VAL2REG(MCDE_RDWRTR1, RWACT, __x)
+#define MCDE_RDWRTR1_RWDEACT_SHIFT 8
+#define MCDE_RDWRTR1_RWDEACT_MASK 0x0000FF00
+#define MCDE_RDWRTR1_RWDEACT(__x) \
+ MCDE_VAL2REG(MCDE_RDWRTR1, RWDEACT, __x)
+#define MCDE_RDWRTR1_MOTINT_SHIFT 16
+#define MCDE_RDWRTR1_MOTINT_MASK 0x00010000
+#define MCDE_RDWRTR1_MOTINT(__x) \
+ MCDE_VAL2REG(MCDE_RDWRTR1, MOTINT, __x)
+#define MCDE_DOTR0 0x00000C84
+#define MCDE_DOTR0_GROUPOFFSET 0x4
+#define MCDE_DOTR0_DOACT_SHIFT 0
+#define MCDE_DOTR0_DOACT_MASK 0x000000FF
+#define MCDE_DOTR0_DOACT(__x) \
+ MCDE_VAL2REG(MCDE_DOTR0, DOACT, __x)
+#define MCDE_DOTR0_DODEACT_SHIFT 8
+#define MCDE_DOTR0_DODEACT_MASK 0x0000FF00
+#define MCDE_DOTR0_DODEACT(__x) \
+ MCDE_VAL2REG(MCDE_DOTR0, DODEACT, __x)
+#define MCDE_DOTR1 0x00000C88
+#define MCDE_DOTR1_DOACT_SHIFT 0
+#define MCDE_DOTR1_DOACT_MASK 0x000000FF
+#define MCDE_DOTR1_DOACT(__x) \
+ MCDE_VAL2REG(MCDE_DOTR1, DOACT, __x)
+#define MCDE_DOTR1_DODEACT_SHIFT 8
+#define MCDE_DOTR1_DODEACT_MASK 0x0000FF00
+#define MCDE_DOTR1_DODEACT(__x) \
+ MCDE_VAL2REG(MCDE_DOTR1, DODEACT, __x)
+#define MCDE_WCMDC0_V1 0x00000C8C
+#define MCDE_WCMDC0_V1_GROUPOFFSET 0x4
+#define MCDE_WCMDC0_V1_COMMANDVALUE_SHIFT 0
+#define MCDE_WCMDC0_V1_COMMANDVALUE_MASK 0x00FFFFFF
+#define MCDE_WCMDC0_V1_COMMANDVALUE(__x) \
+ MCDE_VAL2REG(MCDE_WCMDC0_V1, COMMANDVALUE, __x)
+#define MCDE_WCMDC1_V1 0x00000C90
+#define MCDE_WCMDC1_V1_COMMANDVALUE_SHIFT 0
+#define MCDE_WCMDC1_V1_COMMANDVALUE_MASK 0x00FFFFFF
+#define MCDE_WCMDC1_V1_COMMANDVALUE(__x) \
+ MCDE_VAL2REG(MCDE_WCMDC1_V1, COMMANDVALUE, __x)
+#define MCDE_WDATADC0 0x00000C94
+#define MCDE_WDATADC0_GROUPOFFSET 0x4
+#define MCDE_WDATADC0_DATAVALUE_SHIFT 0
+#define MCDE_WDATADC0_DATAVALUE_MASK 0x00FFFFFF
+#define MCDE_WDATADC0_DATAVALUE(__x) \
+ MCDE_VAL2REG(MCDE_WDATADC0, DATAVALUE, __x)
+#define MCDE_WDATADC1 0x00000C98
+#define MCDE_WDATADC1_DATAVALUE_SHIFT 0
+#define MCDE_WDATADC1_DATAVALUE_MASK 0x00FFFFFF
+#define MCDE_WDATADC1_DATAVALUE(__x) \
+ MCDE_VAL2REG(MCDE_WDATADC1, DATAVALUE, __x)
+#define MCDE_RDATADC0 0x00000C9C
+#define MCDE_RDATADC0_GROUPOFFSET 0x4
+#define MCDE_RDATADC0_DATAREADFROMDISPLAYMODULE_SHIFT 0
+#define MCDE_RDATADC0_DATAREADFROMDISPLAYMODULE_MASK 0x0000FFFF
+#define MCDE_RDATADC0_DATAREADFROMDISPLAYMODULE(__x) \
+ MCDE_VAL2REG(MCDE_RDATADC0, DATAREADFROMDISPLAYMODULE, __x)
+#define MCDE_RDATADC0_STARTREAD_SHIFT 16
+#define MCDE_RDATADC0_STARTREAD_MASK 0x00010000
+#define MCDE_RDATADC0_STARTREAD(__x) \
+ MCDE_VAL2REG(MCDE_RDATADC0, STARTREAD, __x)
+#define MCDE_RDATADC1 0x00000CA0
+#define MCDE_RDATADC1_DATAREADFROMDISPLAYMODULE_SHIFT 0
+#define MCDE_RDATADC1_DATAREADFROMDISPLAYMODULE_MASK 0x0000FFFF
+#define MCDE_RDATADC1_DATAREADFROMDISPLAYMODULE(__x) \
+ MCDE_VAL2REG(MCDE_RDATADC1, DATAREADFROMDISPLAYMODULE, __x)
+#define MCDE_RDATADC1_STARTREAD_SHIFT 16
+#define MCDE_RDATADC1_STARTREAD_MASK 0x00010000
+#define MCDE_RDATADC1_STARTREAD(__x) \
+ MCDE_VAL2REG(MCDE_RDATADC1, STARTREAD, __x)
+#define MCDE_STATC_V1 0x00000CA4
+#define MCDE_STATC_V1_STATBUSY0_SHIFT 0
+#define MCDE_STATC_V1_STATBUSY0_MASK 0x00000001
+#define MCDE_STATC_V1_STATBUSY0(__x) \
+ MCDE_VAL2REG(MCDE_STATC_V1, STATBUSY0, __x)
+#define MCDE_STATC_V1_FIFOEMPTY0_SHIFT 1
+#define MCDE_STATC_V1_FIFOEMPTY0_MASK 0x00000002
+#define MCDE_STATC_V1_FIFOEMPTY0(__x) \
+ MCDE_VAL2REG(MCDE_STATC_V1, FIFOEMPTY0, __x)
+#define MCDE_STATC_V1_FIFOFULL0_SHIFT 2
+#define MCDE_STATC_V1_FIFOFULL0_MASK 0x00000004
+#define MCDE_STATC_V1_FIFOFULL0(__x) \
+ MCDE_VAL2REG(MCDE_STATC_V1, FIFOFULL0, __x)
+#define MCDE_STATC_V1_FIFOCMDEMPTY0_SHIFT 3
+#define MCDE_STATC_V1_FIFOCMDEMPTY0_MASK 0x00000008
+#define MCDE_STATC_V1_FIFOCMDEMPTY0(__x) \
+ MCDE_VAL2REG(MCDE_STATC_V1, FIFOCMDEMPTY0, __x)
+#define MCDE_STATC_V1_FIFOCMDFULL0_SHIFT 4
+#define MCDE_STATC_V1_FIFOCMDFULL0_MASK 0x00000010
+#define MCDE_STATC_V1_FIFOCMDFULL0(__x) \
+ MCDE_VAL2REG(MCDE_STATC_V1, FIFOCMDFULL0, __x)
+#define MCDE_STATC_V1_STATBUSY1_SHIFT 5
+#define MCDE_STATC_V1_STATBUSY1_MASK 0x00000020
+#define MCDE_STATC_V1_STATBUSY1(__x) \
+ MCDE_VAL2REG(MCDE_STATC_V1, STATBUSY1, __x)
+#define MCDE_STATC_V1_FIFOEMPTY1_SHIFT 6
+#define MCDE_STATC_V1_FIFOEMPTY1_MASK 0x00000040
+#define MCDE_STATC_V1_FIFOEMPTY1(__x) \
+ MCDE_VAL2REG(MCDE_STATC_V1, FIFOEMPTY1, __x)
+#define MCDE_STATC_V1_FIFOFULL1_SHIFT 7
+#define MCDE_STATC_V1_FIFOFULL1_MASK 0x00000080
+#define MCDE_STATC_V1_FIFOFULL1(__x) \
+ MCDE_VAL2REG(MCDE_STATC_V1, FIFOFULL1, __x)
+#define MCDE_STATC_V1_FIFOCMDEMPTY1_SHIFT 8
+#define MCDE_STATC_V1_FIFOCMDEMPTY1_MASK 0x00000100
+#define MCDE_STATC_V1_FIFOCMDEMPTY1(__x) \
+ MCDE_VAL2REG(MCDE_STATC_V1, FIFOCMDEMPTY1, __x)
+#define MCDE_STATC_V1_FIFOCMDFULL1_SHIFT 9
+#define MCDE_STATC_V1_FIFOCMDFULL1_MASK 0x00000200
+#define MCDE_STATC_V1_FIFOCMDFULL1(__x) \
+ MCDE_VAL2REG(MCDE_STATC_V1, FIFOCMDFULL1, __x)
+#define MCDE_CTRLC0 0x00000CA8
+#define MCDE_CTRLC0_GROUPOFFSET 0x4
+#define MCDE_CTRLC0_FIFOWTRMRK_SHIFT 0
+#define MCDE_CTRLC0_FIFOWTRMRK_MASK 0x000000FF
+#define MCDE_CTRLC0_FIFOWTRMRK(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC0, FIFOWTRMRK, __x)
+#define MCDE_CTRLC0_FIFOEMPTY_SHIFT 12
+#define MCDE_CTRLC0_FIFOEMPTY_MASK 0x00001000
+#define MCDE_CTRLC0_FIFOEMPTY(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC0, FIFOEMPTY, __x)
+#define MCDE_CTRLC0_FIFOFULL_SHIFT 13
+#define MCDE_CTRLC0_FIFOFULL_MASK 0x00002000
+#define MCDE_CTRLC0_FIFOFULL(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC0, FIFOFULL, __x)
+#define MCDE_CTRLC0_FORMID_SHIFT 16
+#define MCDE_CTRLC0_FORMID_MASK 0x00070000
+#define MCDE_CTRLC0_FORMID_DSI0VID 0
+#define MCDE_CTRLC0_FORMID_DSI0CMD 1
+#define MCDE_CTRLC0_FORMID_DSI1VID 2
+#define MCDE_CTRLC0_FORMID_DSI1CMD 0
+#define MCDE_CTRLC0_FORMID_DSI2VID 1
+#define MCDE_CTRLC0_FORMID_DSI2CMD 2
+#define MCDE_CTRLC0_FORMID_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC0, FORMID, MCDE_CTRLC0_FORMID_##__x)
+#define MCDE_CTRLC0_FORMID(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC0, FORMID, __x)
+#define MCDE_CTRLC0_FORMTYPE_SHIFT 20
+#define MCDE_CTRLC0_FORMTYPE_MASK 0x00700000
+#define MCDE_CTRLC0_FORMTYPE_DPITV 0
+#define MCDE_CTRLC0_FORMTYPE_DBI 1
+#define MCDE_CTRLC0_FORMTYPE_DSI 2
+#define MCDE_CTRLC0_FORMTYPE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC0, FORMTYPE, MCDE_CTRLC0_FORMTYPE_##__x)
+#define MCDE_CTRLC0_FORMTYPE(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC0, FORMTYPE, __x)
+#define MCDE_CTRLC1 0x00000CAC
+#define MCDE_CTRLC1_FIFOWTRMRK_SHIFT 0
+#define MCDE_CTRLC1_FIFOWTRMRK_MASK 0x000000FF
+#define MCDE_CTRLC1_FIFOWTRMRK(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC1, FIFOWTRMRK, __x)
+#define MCDE_CTRLC1_FIFOEMPTY_SHIFT 12
+#define MCDE_CTRLC1_FIFOEMPTY_MASK 0x00001000
+#define MCDE_CTRLC1_FIFOEMPTY(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC1, FIFOEMPTY, __x)
+#define MCDE_CTRLC1_FIFOFULL_SHIFT 13
+#define MCDE_CTRLC1_FIFOFULL_MASK 0x00002000
+#define MCDE_CTRLC1_FIFOFULL(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC1, FIFOFULL, __x)
+#define MCDE_CTRLC1_FORMID_SHIFT 16
+#define MCDE_CTRLC1_FORMID_MASK 0x00070000
+#define MCDE_CTRLC1_FORMID_DSI0VID 0
+#define MCDE_CTRLC1_FORMID_DSI0CMD 1
+#define MCDE_CTRLC1_FORMID_DSI1VID 2
+#define MCDE_CTRLC1_FORMID_DSI1CMD 0
+#define MCDE_CTRLC1_FORMID_DSI2VID 1
+#define MCDE_CTRLC1_FORMID_DSI2CMD 2
+#define MCDE_CTRLC1_FORMID_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC1, FORMID, MCDE_CTRLC1_FORMID_##__x)
+#define MCDE_CTRLC1_FORMID(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC1, FORMID, __x)
+#define MCDE_CTRLC1_FORMTYPE_SHIFT 20
+#define MCDE_CTRLC1_FORMTYPE_MASK 0x00700000
+#define MCDE_CTRLC1_FORMTYPE_DPITV 0
+#define MCDE_CTRLC1_FORMTYPE_DBI 1
+#define MCDE_CTRLC1_FORMTYPE_DSI 2
+#define MCDE_CTRLC1_FORMTYPE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC1, FORMTYPE, MCDE_CTRLC1_FORMTYPE_##__x)
+#define MCDE_CTRLC1_FORMTYPE(__x) \
+ MCDE_VAL2REG(MCDE_CTRLC1, FORMTYPE, __x)
+#define MCDE_DSIVID0CONF0 0x00000E00
+#define MCDE_DSIVID0CONF0_GROUPOFFSET 0x20
+#define MCDE_DSIVID0CONF0_BLANKING_SHIFT 0
+#define MCDE_DSIVID0CONF0_BLANKING_MASK 0x000000FF
+#define MCDE_DSIVID0CONF0_BLANKING(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0CONF0, BLANKING, __x)
+#define MCDE_DSIVID0CONF0_VID_MODE_SHIFT 12
+#define MCDE_DSIVID0CONF0_VID_MODE_MASK 0x00001000
+#define MCDE_DSIVID0CONF0_VID_MODE_CMD 0
+#define MCDE_DSIVID0CONF0_VID_MODE_VID 1
+#define MCDE_DSIVID0CONF0_VID_MODE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0CONF0, VID_MODE, \
+ MCDE_DSIVID0CONF0_VID_MODE_##__x)
+#define MCDE_DSIVID0CONF0_VID_MODE(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0CONF0, VID_MODE, __x)
+#define MCDE_DSIVID0CONF0_CMD8_SHIFT 13
+#define MCDE_DSIVID0CONF0_CMD8_MASK 0x00002000
+#define MCDE_DSIVID0CONF0_CMD8(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0CONF0, CMD8, __x)
+#define MCDE_DSIVID0CONF0_BIT_SWAP_SHIFT 16
+#define MCDE_DSIVID0CONF0_BIT_SWAP_MASK 0x00010000
+#define MCDE_DSIVID0CONF0_BIT_SWAP(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0CONF0, BIT_SWAP, __x)
+#define MCDE_DSIVID0CONF0_BYTE_SWAP_SHIFT 17
+#define MCDE_DSIVID0CONF0_BYTE_SWAP_MASK 0x00020000
+#define MCDE_DSIVID0CONF0_BYTE_SWAP(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0CONF0, BYTE_SWAP, __x)
+#define MCDE_DSIVID0CONF0_DCSVID_NOTGEN_SHIFT 18
+#define MCDE_DSIVID0CONF0_DCSVID_NOTGEN_MASK 0x00040000
+#define MCDE_DSIVID0CONF0_DCSVID_NOTGEN(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0CONF0, DCSVID_NOTGEN, __x)
+#define MCDE_DSIVID0CONF0_PACKING_SHIFT 20
+#define MCDE_DSIVID0CONF0_PACKING_MASK 0x00700000
+#define MCDE_DSIVID0CONF0_PACKING_RGB565 0
+#define MCDE_DSIVID0CONF0_PACKING_RGB666 1
+#define MCDE_DSIVID0CONF0_PACKING_RGB888 2
+#define MCDE_DSIVID0CONF0_PACKING_BGR888 3
+#define MCDE_DSIVID0CONF0_PACKING_HDTV 7
+#define MCDE_DSIVID0CONF0_PACKING_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0CONF0, PACKING, \
+ MCDE_DSIVID0CONF0_PACKING_##__x)
+#define MCDE_DSIVID0CONF0_PACKING(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0CONF0, PACKING, __x)
+#define MCDE_DSICMD0CONF0 0x00000E20
+#define MCDE_DSICMD0CONF0_BLANKING_SHIFT 0
+#define MCDE_DSICMD0CONF0_BLANKING_MASK 0x000000FF
+#define MCDE_DSICMD0CONF0_BLANKING(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0CONF0, BLANKING, __x)
+#define MCDE_DSICMD0CONF0_VID_MODE_SHIFT 12
+#define MCDE_DSICMD0CONF0_VID_MODE_MASK 0x00001000
+#define MCDE_DSICMD0CONF0_VID_MODE_CMD 0
+#define MCDE_DSICMD0CONF0_VID_MODE_VID 1
+#define MCDE_DSICMD0CONF0_VID_MODE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0CONF0, VID_MODE, \
+ MCDE_DSICMD0CONF0_VID_MODE_##__x)
+#define MCDE_DSICMD0CONF0_VID_MODE(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0CONF0, VID_MODE, __x)
+#define MCDE_DSICMD0CONF0_CMD8_SHIFT 13
+#define MCDE_DSICMD0CONF0_CMD8_MASK 0x00002000
+#define MCDE_DSICMD0CONF0_CMD8(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0CONF0, CMD8, __x)
+#define MCDE_DSICMD0CONF0_BIT_SWAP_SHIFT 16
+#define MCDE_DSICMD0CONF0_BIT_SWAP_MASK 0x00010000
+#define MCDE_DSICMD0CONF0_BIT_SWAP(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0CONF0, BIT_SWAP, __x)
+#define MCDE_DSICMD0CONF0_BYTE_SWAP_SHIFT 17
+#define MCDE_DSICMD0CONF0_BYTE_SWAP_MASK 0x00020000
+#define MCDE_DSICMD0CONF0_BYTE_SWAP(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0CONF0, BYTE_SWAP, __x)
+#define MCDE_DSICMD0CONF0_DCSVID_NOTGEN_SHIFT 18
+#define MCDE_DSICMD0CONF0_DCSVID_NOTGEN_MASK 0x00040000
+#define MCDE_DSICMD0CONF0_DCSVID_NOTGEN(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0CONF0, DCSVID_NOTGEN, __x)
+#define MCDE_DSICMD0CONF0_PACKING_SHIFT 20
+#define MCDE_DSICMD0CONF0_PACKING_MASK 0x00700000
+#define MCDE_DSICMD0CONF0_PACKING_RGB565 0
+#define MCDE_DSICMD0CONF0_PACKING_RGB666 1
+#define MCDE_DSICMD0CONF0_PACKING_RGB888 2
+#define MCDE_DSICMD0CONF0_PACKING_BGR888 3
+#define MCDE_DSICMD0CONF0_PACKING_HDTV 7
+#define MCDE_DSICMD0CONF0_PACKING_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0CONF0, PACKING, \
+ MCDE_DSICMD0CONF0_PACKING_##__x)
+#define MCDE_DSICMD0CONF0_PACKING(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0CONF0, PACKING, __x)
+#define MCDE_DSIVID1CONF0 0x00000E40
+#define MCDE_DSIVID1CONF0_BLANKING_SHIFT 0
+#define MCDE_DSIVID1CONF0_BLANKING_MASK 0x000000FF
+#define MCDE_DSIVID1CONF0_BLANKING(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1CONF0, BLANKING, __x)
+#define MCDE_DSIVID1CONF0_VID_MODE_SHIFT 12
+#define MCDE_DSIVID1CONF0_VID_MODE_MASK 0x00001000
+#define MCDE_DSIVID1CONF0_VID_MODE_CMD 0
+#define MCDE_DSIVID1CONF0_VID_MODE_VID 1
+#define MCDE_DSIVID1CONF0_VID_MODE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1CONF0, VID_MODE, \
+ MCDE_DSIVID1CONF0_VID_MODE_##__x)
+#define MCDE_DSIVID1CONF0_VID_MODE(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1CONF0, VID_MODE, __x)
+#define MCDE_DSIVID1CONF0_CMD8_SHIFT 13
+#define MCDE_DSIVID1CONF0_CMD8_MASK 0x00002000
+#define MCDE_DSIVID1CONF0_CMD8(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1CONF0, CMD8, __x)
+#define MCDE_DSIVID1CONF0_BIT_SWAP_SHIFT 16
+#define MCDE_DSIVID1CONF0_BIT_SWAP_MASK 0x00010000
+#define MCDE_DSIVID1CONF0_BIT_SWAP(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1CONF0, BIT_SWAP, __x)
+#define MCDE_DSIVID1CONF0_BYTE_SWAP_SHIFT 17
+#define MCDE_DSIVID1CONF0_BYTE_SWAP_MASK 0x00020000
+#define MCDE_DSIVID1CONF0_BYTE_SWAP(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1CONF0, BYTE_SWAP, __x)
+#define MCDE_DSIVID1CONF0_DCSVID_NOTGEN_SHIFT 18
+#define MCDE_DSIVID1CONF0_DCSVID_NOTGEN_MASK 0x00040000
+#define MCDE_DSIVID1CONF0_DCSVID_NOTGEN(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1CONF0, DCSVID_NOTGEN, __x)
+#define MCDE_DSIVID1CONF0_PACKING_SHIFT 20
+#define MCDE_DSIVID1CONF0_PACKING_MASK 0x00700000
+#define MCDE_DSIVID1CONF0_PACKING_RGB565 0
+#define MCDE_DSIVID1CONF0_PACKING_RGB666 1
+#define MCDE_DSIVID1CONF0_PACKING_RGB888 2
+#define MCDE_DSIVID1CONF0_PACKING_BGR888 3
+#define MCDE_DSIVID1CONF0_PACKING_HDTV 7
+#define MCDE_DSIVID1CONF0_PACKING_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1CONF0, PACKING, \
+ MCDE_DSIVID1CONF0_PACKING_##__x)
+#define MCDE_DSIVID1CONF0_PACKING(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1CONF0, PACKING, __x)
+#define MCDE_DSICMD1CONF0 0x00000E60
+#define MCDE_DSICMD1CONF0_BLANKING_SHIFT 0
+#define MCDE_DSICMD1CONF0_BLANKING_MASK 0x000000FF
+#define MCDE_DSICMD1CONF0_BLANKING(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1CONF0, BLANKING, __x)
+#define MCDE_DSICMD1CONF0_VID_MODE_SHIFT 12
+#define MCDE_DSICMD1CONF0_VID_MODE_MASK 0x00001000
+#define MCDE_DSICMD1CONF0_VID_MODE_CMD 0
+#define MCDE_DSICMD1CONF0_VID_MODE_VID 1
+#define MCDE_DSICMD1CONF0_VID_MODE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1CONF0, VID_MODE, \
+ MCDE_DSICMD1CONF0_VID_MODE_##__x)
+#define MCDE_DSICMD1CONF0_VID_MODE(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1CONF0, VID_MODE, __x)
+#define MCDE_DSICMD1CONF0_CMD8_SHIFT 13
+#define MCDE_DSICMD1CONF0_CMD8_MASK 0x00002000
+#define MCDE_DSICMD1CONF0_CMD8(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1CONF0, CMD8, __x)
+#define MCDE_DSICMD1CONF0_BIT_SWAP_SHIFT 16
+#define MCDE_DSICMD1CONF0_BIT_SWAP_MASK 0x00010000
+#define MCDE_DSICMD1CONF0_BIT_SWAP(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1CONF0, BIT_SWAP, __x)
+#define MCDE_DSICMD1CONF0_BYTE_SWAP_SHIFT 17
+#define MCDE_DSICMD1CONF0_BYTE_SWAP_MASK 0x00020000
+#define MCDE_DSICMD1CONF0_BYTE_SWAP(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1CONF0, BYTE_SWAP, __x)
+#define MCDE_DSICMD1CONF0_DCSVID_NOTGEN_SHIFT 18
+#define MCDE_DSICMD1CONF0_DCSVID_NOTGEN_MASK 0x00040000
+#define MCDE_DSICMD1CONF0_DCSVID_NOTGEN(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1CONF0, DCSVID_NOTGEN, __x)
+#define MCDE_DSICMD1CONF0_PACKING_SHIFT 20
+#define MCDE_DSICMD1CONF0_PACKING_MASK 0x00700000
+#define MCDE_DSICMD1CONF0_PACKING_RGB565 0
+#define MCDE_DSICMD1CONF0_PACKING_RGB666 1
+#define MCDE_DSICMD1CONF0_PACKING_RGB888 2
+#define MCDE_DSICMD1CONF0_PACKING_BGR888 3
+#define MCDE_DSICMD1CONF0_PACKING_HDTV 7
+#define MCDE_DSICMD1CONF0_PACKING_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1CONF0, PACKING, \
+ MCDE_DSICMD1CONF0_PACKING_##__x)
+#define MCDE_DSICMD1CONF0_PACKING(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1CONF0, PACKING, __x)
+#define MCDE_DSIVID2CONF0 0x00000E80
+#define MCDE_DSIVID2CONF0_BLANKING_SHIFT 0
+#define MCDE_DSIVID2CONF0_BLANKING_MASK 0x000000FF
+#define MCDE_DSIVID2CONF0_BLANKING(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2CONF0, BLANKING, __x)
+#define MCDE_DSIVID2CONF0_VID_MODE_SHIFT 12
+#define MCDE_DSIVID2CONF0_VID_MODE_MASK 0x00001000
+#define MCDE_DSIVID2CONF0_VID_MODE_CMD 0
+#define MCDE_DSIVID2CONF0_VID_MODE_VID 1
+#define MCDE_DSIVID2CONF0_VID_MODE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2CONF0, VID_MODE, \
+ MCDE_DSIVID2CONF0_VID_MODE_##__x)
+#define MCDE_DSIVID2CONF0_VID_MODE(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2CONF0, VID_MODE, __x)
+#define MCDE_DSIVID2CONF0_CMD8_SHIFT 13
+#define MCDE_DSIVID2CONF0_CMD8_MASK 0x00002000
+#define MCDE_DSIVID2CONF0_CMD8(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2CONF0, CMD8, __x)
+#define MCDE_DSIVID2CONF0_BIT_SWAP_SHIFT 16
+#define MCDE_DSIVID2CONF0_BIT_SWAP_MASK 0x00010000
+#define MCDE_DSIVID2CONF0_BIT_SWAP(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2CONF0, BIT_SWAP, __x)
+#define MCDE_DSIVID2CONF0_BYTE_SWAP_SHIFT 17
+#define MCDE_DSIVID2CONF0_BYTE_SWAP_MASK 0x00020000
+#define MCDE_DSIVID2CONF0_BYTE_SWAP(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2CONF0, BYTE_SWAP, __x)
+#define MCDE_DSIVID2CONF0_DCSVID_NOTGEN_SHIFT 18
+#define MCDE_DSIVID2CONF0_DCSVID_NOTGEN_MASK 0x00040000
+#define MCDE_DSIVID2CONF0_DCSVID_NOTGEN(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2CONF0, DCSVID_NOTGEN, __x)
+#define MCDE_DSIVID2CONF0_PACKING_SHIFT 20
+#define MCDE_DSIVID2CONF0_PACKING_MASK 0x00700000
+#define MCDE_DSIVID2CONF0_PACKING_RGB565 0
+#define MCDE_DSIVID2CONF0_PACKING_RGB666 1
+#define MCDE_DSIVID2CONF0_PACKING_RGB888 2
+#define MCDE_DSIVID2CONF0_PACKING_BGR888 3
+#define MCDE_DSIVID2CONF0_PACKING_HDTV 7
+#define MCDE_DSIVID2CONF0_PACKING_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2CONF0, PACKING, \
+ MCDE_DSIVID2CONF0_PACKING_##__x)
+#define MCDE_DSIVID2CONF0_PACKING(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2CONF0, PACKING, __x)
+#define MCDE_DSICMD2CONF0 0x00000EA0
+#define MCDE_DSICMD2CONF0_BLANKING_SHIFT 0
+#define MCDE_DSICMD2CONF0_BLANKING_MASK 0x000000FF
+#define MCDE_DSICMD2CONF0_BLANKING(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2CONF0, BLANKING, __x)
+#define MCDE_DSICMD2CONF0_VID_MODE_SHIFT 12
+#define MCDE_DSICMD2CONF0_VID_MODE_MASK 0x00001000
+#define MCDE_DSICMD2CONF0_VID_MODE_CMD 0
+#define MCDE_DSICMD2CONF0_VID_MODE_VID 1
+#define MCDE_DSICMD2CONF0_VID_MODE_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2CONF0, VID_MODE, \
+ MCDE_DSICMD2CONF0_VID_MODE_##__x)
+#define MCDE_DSICMD2CONF0_VID_MODE(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2CONF0, VID_MODE, __x)
+#define MCDE_DSICMD2CONF0_CMD8_SHIFT 13
+#define MCDE_DSICMD2CONF0_CMD8_MASK 0x00002000
+#define MCDE_DSICMD2CONF0_CMD8(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2CONF0, CMD8, __x)
+#define MCDE_DSICMD2CONF0_BIT_SWAP_SHIFT 16
+#define MCDE_DSICMD2CONF0_BIT_SWAP_MASK 0x00010000
+#define MCDE_DSICMD2CONF0_BIT_SWAP(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2CONF0, BIT_SWAP, __x)
+#define MCDE_DSICMD2CONF0_BYTE_SWAP_SHIFT 17
+#define MCDE_DSICMD2CONF0_BYTE_SWAP_MASK 0x00020000
+#define MCDE_DSICMD2CONF0_BYTE_SWAP(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2CONF0, BYTE_SWAP, __x)
+#define MCDE_DSICMD2CONF0_DCSVID_NOTGEN_SHIFT 18
+#define MCDE_DSICMD2CONF0_DCSVID_NOTGEN_MASK 0x00040000
+#define MCDE_DSICMD2CONF0_DCSVID_NOTGEN(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2CONF0, DCSVID_NOTGEN, __x)
+#define MCDE_DSICMD2CONF0_PACKING_SHIFT 20
+#define MCDE_DSICMD2CONF0_PACKING_MASK 0x00700000
+#define MCDE_DSICMD2CONF0_PACKING_RGB565 0
+#define MCDE_DSICMD2CONF0_PACKING_RGB666 1
+#define MCDE_DSICMD2CONF0_PACKING_RGB888 2
+#define MCDE_DSICMD2CONF0_PACKING_BGR888 3
+#define MCDE_DSICMD2CONF0_PACKING_HDTV 7
+#define MCDE_DSICMD2CONF0_PACKING_ENUM(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2CONF0, PACKING, \
+ MCDE_DSICMD2CONF0_PACKING_##__x)
+#define MCDE_DSICMD2CONF0_PACKING(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2CONF0, PACKING, __x)
+#define MCDE_DSIVID0FRAME 0x00000E04
+#define MCDE_DSIVID0FRAME_GROUPOFFSET 0x20
+#define MCDE_DSIVID0FRAME_FRAME_SHIFT 0
+#define MCDE_DSIVID0FRAME_FRAME_MASK 0x00FFFFFF
+#define MCDE_DSIVID0FRAME_FRAME(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0FRAME, FRAME, __x)
+#define MCDE_DSICMD0FRAME 0x00000E24
+#define MCDE_DSICMD0FRAME_FRAME_SHIFT 0
+#define MCDE_DSICMD0FRAME_FRAME_MASK 0x00FFFFFF
+#define MCDE_DSICMD0FRAME_FRAME(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0FRAME, FRAME, __x)
+#define MCDE_DSIVID1FRAME 0x00000E44
+#define MCDE_DSIVID1FRAME_FRAME_SHIFT 0
+#define MCDE_DSIVID1FRAME_FRAME_MASK 0x00FFFFFF
+#define MCDE_DSIVID1FRAME_FRAME(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1FRAME, FRAME, __x)
+#define MCDE_DSICMD1FRAME 0x00000E64
+#define MCDE_DSICMD1FRAME_FRAME_SHIFT 0
+#define MCDE_DSICMD1FRAME_FRAME_MASK 0x00FFFFFF
+#define MCDE_DSICMD1FRAME_FRAME(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1FRAME, FRAME, __x)
+#define MCDE_DSIVID2FRAME 0x00000E84
+#define MCDE_DSIVID2FRAME_FRAME_SHIFT 0
+#define MCDE_DSIVID2FRAME_FRAME_MASK 0x00FFFFFF
+#define MCDE_DSIVID2FRAME_FRAME(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2FRAME, FRAME, __x)
+#define MCDE_DSICMD2FRAME 0x00000EA4
+#define MCDE_DSICMD2FRAME_FRAME_SHIFT 0
+#define MCDE_DSICMD2FRAME_FRAME_MASK 0x00FFFFFF
+#define MCDE_DSICMD2FRAME_FRAME(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2FRAME, FRAME, __x)
+#define MCDE_DSIVID0PKT 0x00000E08
+#define MCDE_DSIVID0PKT_GROUPOFFSET 0x20
+#define MCDE_DSIVID0PKT_PACKET_SHIFT 0
+#define MCDE_DSIVID0PKT_PACKET_MASK 0x0000FFFF
+#define MCDE_DSIVID0PKT_PACKET(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0PKT, PACKET, __x)
+#define MCDE_DSICMD0PKT 0x00000E28
+#define MCDE_DSICMD0PKT_PACKET_SHIFT 0
+#define MCDE_DSICMD0PKT_PACKET_MASK 0x0000FFFF
+#define MCDE_DSICMD0PKT_PACKET(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0PKT, PACKET, __x)
+#define MCDE_DSIVID1PKT 0x00000E48
+#define MCDE_DSIVID1PKT_PACKET_SHIFT 0
+#define MCDE_DSIVID1PKT_PACKET_MASK 0x0000FFFF
+#define MCDE_DSIVID1PKT_PACKET(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1PKT, PACKET, __x)
+#define MCDE_DSICMD1PKT 0x00000E68
+#define MCDE_DSICMD1PKT_PACKET_SHIFT 0
+#define MCDE_DSICMD1PKT_PACKET_MASK 0x0000FFFF
+#define MCDE_DSICMD1PKT_PACKET(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1PKT, PACKET, __x)
+#define MCDE_DSIVID2PKT 0x00000E88
+#define MCDE_DSIVID2PKT_PACKET_SHIFT 0
+#define MCDE_DSIVID2PKT_PACKET_MASK 0x0000FFFF
+#define MCDE_DSIVID2PKT_PACKET(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2PKT, PACKET, __x)
+#define MCDE_DSICMD2PKT 0x00000EA8
+#define MCDE_DSICMD2PKT_PACKET_SHIFT 0
+#define MCDE_DSICMD2PKT_PACKET_MASK 0x0000FFFF
+#define MCDE_DSICMD2PKT_PACKET(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2PKT, PACKET, __x)
+#define MCDE_DSIVID0SYNC 0x00000E0C
+#define MCDE_DSIVID0SYNC_GROUPOFFSET 0x20
+#define MCDE_DSIVID0SYNC_DMA_SHIFT 0
+#define MCDE_DSIVID0SYNC_DMA_MASK 0x00000FFF
+#define MCDE_DSIVID0SYNC_DMA(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0SYNC, DMA, __x)
+#define MCDE_DSIVID0SYNC_SW_SHIFT 16
+#define MCDE_DSIVID0SYNC_SW_MASK 0x0FFF0000
+#define MCDE_DSIVID0SYNC_SW(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0SYNC, SW, __x)
+#define MCDE_DSICMD0SYNC 0x00000E2C
+#define MCDE_DSICMD0SYNC_DMA_SHIFT 0
+#define MCDE_DSICMD0SYNC_DMA_MASK 0x00000FFF
+#define MCDE_DSICMD0SYNC_DMA(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0SYNC, DMA, __x)
+#define MCDE_DSICMD0SYNC_SW_SHIFT 16
+#define MCDE_DSICMD0SYNC_SW_MASK 0x0FFF0000
+#define MCDE_DSICMD0SYNC_SW(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0SYNC, SW, __x)
+#define MCDE_DSIVID1SYNC 0x00000E4C
+#define MCDE_DSIVID1SYNC_DMA_SHIFT 0
+#define MCDE_DSIVID1SYNC_DMA_MASK 0x00000FFF
+#define MCDE_DSIVID1SYNC_DMA(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1SYNC, DMA, __x)
+#define MCDE_DSIVID1SYNC_SW_SHIFT 16
+#define MCDE_DSIVID1SYNC_SW_MASK 0x0FFF0000
+#define MCDE_DSIVID1SYNC_SW(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1SYNC, SW, __x)
+#define MCDE_DSICMD1SYNC 0x00000E6C
+#define MCDE_DSICMD1SYNC_DMA_SHIFT 0
+#define MCDE_DSICMD1SYNC_DMA_MASK 0x00000FFF
+#define MCDE_DSICMD1SYNC_DMA(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1SYNC, DMA, __x)
+#define MCDE_DSICMD1SYNC_SW_SHIFT 16
+#define MCDE_DSICMD1SYNC_SW_MASK 0x0FFF0000
+#define MCDE_DSICMD1SYNC_SW(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1SYNC, SW, __x)
+#define MCDE_DSIVID2SYNC 0x00000E8C
+#define MCDE_DSIVID2SYNC_DMA_SHIFT 0
+#define MCDE_DSIVID2SYNC_DMA_MASK 0x00000FFF
+#define MCDE_DSIVID2SYNC_DMA(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2SYNC, DMA, __x)
+#define MCDE_DSIVID2SYNC_SW_SHIFT 16
+#define MCDE_DSIVID2SYNC_SW_MASK 0x0FFF0000
+#define MCDE_DSIVID2SYNC_SW(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2SYNC, SW, __x)
+#define MCDE_DSICMD2SYNC 0x00000EAC
+#define MCDE_DSICMD2SYNC_DMA_SHIFT 0
+#define MCDE_DSICMD2SYNC_DMA_MASK 0x00000FFF
+#define MCDE_DSICMD2SYNC_DMA(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2SYNC, DMA, __x)
+#define MCDE_DSICMD2SYNC_SW_SHIFT 16
+#define MCDE_DSICMD2SYNC_SW_MASK 0x0FFF0000
+#define MCDE_DSICMD2SYNC_SW(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2SYNC, SW, __x)
+#define MCDE_DSIVID0CMDW 0x00000E10
+#define MCDE_DSIVID0CMDW_GROUPOFFSET 0x20
+#define MCDE_DSIVID0CMDW_CMDW_CONTINUE_SHIFT 0
+#define MCDE_DSIVID0CMDW_CMDW_CONTINUE_MASK 0x0000FFFF
+#define MCDE_DSIVID0CMDW_CMDW_CONTINUE(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0CMDW, CMDW_CONTINUE, __x)
+#define MCDE_DSIVID0CMDW_CMDW_START_SHIFT 16
+#define MCDE_DSIVID0CMDW_CMDW_START_MASK 0xFFFF0000
+#define MCDE_DSIVID0CMDW_CMDW_START(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0CMDW, CMDW_START, __x)
+#define MCDE_DSICMD0CMDW 0x00000E30
+#define MCDE_DSICMD0CMDW_CMDW_CONTINUE_SHIFT 0
+#define MCDE_DSICMD0CMDW_CMDW_CONTINUE_MASK 0x0000FFFF
+#define MCDE_DSICMD0CMDW_CMDW_CONTINUE(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0CMDW, CMDW_CONTINUE, __x)
+#define MCDE_DSICMD0CMDW_CMDW_START_SHIFT 16
+#define MCDE_DSICMD0CMDW_CMDW_START_MASK 0xFFFF0000
+#define MCDE_DSICMD0CMDW_CMDW_START(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0CMDW, CMDW_START, __x)
+#define MCDE_DSIVID1CMDW 0x00000E50
+#define MCDE_DSIVID1CMDW_CMDW_CONTINUE_SHIFT 0
+#define MCDE_DSIVID1CMDW_CMDW_CONTINUE_MASK 0x0000FFFF
+#define MCDE_DSIVID1CMDW_CMDW_CONTINUE(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1CMDW, CMDW_CONTINUE, __x)
+#define MCDE_DSIVID1CMDW_CMDW_START_SHIFT 16
+#define MCDE_DSIVID1CMDW_CMDW_START_MASK 0xFFFF0000
+#define MCDE_DSIVID1CMDW_CMDW_START(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1CMDW, CMDW_START, __x)
+#define MCDE_DSICMD1CMDW 0x00000E70
+#define MCDE_DSICMD1CMDW_CMDW_CONTINUE_SHIFT 0
+#define MCDE_DSICMD1CMDW_CMDW_CONTINUE_MASK 0x0000FFFF
+#define MCDE_DSICMD1CMDW_CMDW_CONTINUE(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1CMDW, CMDW_CONTINUE, __x)
+#define MCDE_DSICMD1CMDW_CMDW_START_SHIFT 16
+#define MCDE_DSICMD1CMDW_CMDW_START_MASK 0xFFFF0000
+#define MCDE_DSICMD1CMDW_CMDW_START(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1CMDW, CMDW_START, __x)
+#define MCDE_DSIVID2CMDW 0x00000E90
+#define MCDE_DSIVID2CMDW_CMDW_CONTINUE_SHIFT 0
+#define MCDE_DSIVID2CMDW_CMDW_CONTINUE_MASK 0x0000FFFF
+#define MCDE_DSIVID2CMDW_CMDW_CONTINUE(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2CMDW, CMDW_CONTINUE, __x)
+#define MCDE_DSIVID2CMDW_CMDW_START_SHIFT 16
+#define MCDE_DSIVID2CMDW_CMDW_START_MASK 0xFFFF0000
+#define MCDE_DSIVID2CMDW_CMDW_START(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2CMDW, CMDW_START, __x)
+#define MCDE_DSICMD2CMDW 0x00000EB0
+#define MCDE_DSICMD2CMDW_CMDW_CONTINUE_SHIFT 0
+#define MCDE_DSICMD2CMDW_CMDW_CONTINUE_MASK 0x0000FFFF
+#define MCDE_DSICMD2CMDW_CMDW_CONTINUE(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2CMDW, CMDW_CONTINUE, __x)
+#define MCDE_DSICMD2CMDW_CMDW_START_SHIFT 16
+#define MCDE_DSICMD2CMDW_CMDW_START_MASK 0xFFFF0000
+#define MCDE_DSICMD2CMDW_CMDW_START(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2CMDW, CMDW_START, __x)
+#define MCDE_DSIVID0DELAY0 0x00000E14
+#define MCDE_DSIVID0DELAY0_GROUPOFFSET 0x20
+#define MCDE_DSIVID0DELAY0_INTPKTDEL_SHIFT 0
+#define MCDE_DSIVID0DELAY0_INTPKTDEL_MASK 0x0000FFFF
+#define MCDE_DSIVID0DELAY0_INTPKTDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0DELAY0, INTPKTDEL, __x)
+#define MCDE_DSICMD0DELAY0 0x00000E34
+#define MCDE_DSICMD0DELAY0_INTPKTDEL_SHIFT 0
+#define MCDE_DSICMD0DELAY0_INTPKTDEL_MASK 0x0000FFFF
+#define MCDE_DSICMD0DELAY0_INTPKTDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0DELAY0, INTPKTDEL, __x)
+#define MCDE_DSIVID1DELAY0 0x00000E54
+#define MCDE_DSIVID1DELAY0_INTPKTDEL_SHIFT 0
+#define MCDE_DSIVID1DELAY0_INTPKTDEL_MASK 0x0000FFFF
+#define MCDE_DSIVID1DELAY0_INTPKTDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1DELAY0, INTPKTDEL, __x)
+#define MCDE_DSICMD1DELAY0 0x00000E74
+#define MCDE_DSICMD1DELAY0_INTPKTDEL_SHIFT 0
+#define MCDE_DSICMD1DELAY0_INTPKTDEL_MASK 0x0000FFFF
+#define MCDE_DSICMD1DELAY0_INTPKTDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1DELAY0, INTPKTDEL, __x)
+#define MCDE_DSIVID2DELAY0 0x00000E94
+#define MCDE_DSIVID2DELAY0_INTPKTDEL_SHIFT 0
+#define MCDE_DSIVID2DELAY0_INTPKTDEL_MASK 0x0000FFFF
+#define MCDE_DSIVID2DELAY0_INTPKTDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2DELAY0, INTPKTDEL, __x)
+#define MCDE_DSICMD2DELAY0 0x00000EB4
+#define MCDE_DSICMD2DELAY0_INTPKTDEL_SHIFT 0
+#define MCDE_DSICMD2DELAY0_INTPKTDEL_MASK 0x0000FFFF
+#define MCDE_DSICMD2DELAY0_INTPKTDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2DELAY0, INTPKTDEL, __x)
+#define MCDE_DSIVID0DELAY1 0x00000E18
+#define MCDE_DSIVID0DELAY1_GROUPOFFSET 0x20
+#define MCDE_DSIVID0DELAY1_TEREQDEL_SHIFT 0
+#define MCDE_DSIVID0DELAY1_TEREQDEL_MASK 0x00000FFF
+#define MCDE_DSIVID0DELAY1_TEREQDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0DELAY1, TEREQDEL, __x)
+#define MCDE_DSIVID0DELAY1_FRAMESTARTDEL_SHIFT 16
+#define MCDE_DSIVID0DELAY1_FRAMESTARTDEL_MASK 0x00FF0000
+#define MCDE_DSIVID0DELAY1_FRAMESTARTDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID0DELAY1, FRAMESTARTDEL, __x)
+#define MCDE_DSICMD0DELAY1 0x00000E38
+#define MCDE_DSICMD0DELAY1_TEREQDEL_SHIFT 0
+#define MCDE_DSICMD0DELAY1_TEREQDEL_MASK 0x00000FFF
+#define MCDE_DSICMD0DELAY1_TEREQDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0DELAY1, TEREQDEL, __x)
+#define MCDE_DSICMD0DELAY1_FRAMESTARTDEL_SHIFT 16
+#define MCDE_DSICMD0DELAY1_FRAMESTARTDEL_MASK 0x00FF0000
+#define MCDE_DSICMD0DELAY1_FRAMESTARTDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD0DELAY1, FRAMESTARTDEL, __x)
+#define MCDE_DSIVID1DELAY1 0x00000E58
+#define MCDE_DSIVID1DELAY1_TEREQDEL_SHIFT 0
+#define MCDE_DSIVID1DELAY1_TEREQDEL_MASK 0x00000FFF
+#define MCDE_DSIVID1DELAY1_TEREQDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1DELAY1, TEREQDEL, __x)
+#define MCDE_DSIVID1DELAY1_FRAMESTARTDEL_SHIFT 16
+#define MCDE_DSIVID1DELAY1_FRAMESTARTDEL_MASK 0x00FF0000
+#define MCDE_DSIVID1DELAY1_FRAMESTARTDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID1DELAY1, FRAMESTARTDEL, __x)
+#define MCDE_DSICMD1DELAY1 0x00000E78
+#define MCDE_DSICMD1DELAY1_TEREQDEL_SHIFT 0
+#define MCDE_DSICMD1DELAY1_TEREQDEL_MASK 0x00000FFF
+#define MCDE_DSICMD1DELAY1_TEREQDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1DELAY1, TEREQDEL, __x)
+#define MCDE_DSICMD1DELAY1_FRAMESTARTDEL_SHIFT 16
+#define MCDE_DSICMD1DELAY1_FRAMESTARTDEL_MASK 0x00FF0000
+#define MCDE_DSICMD1DELAY1_FRAMESTARTDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD1DELAY1, FRAMESTARTDEL, __x)
+#define MCDE_DSIVID2DELAY1 0x00000E98
+#define MCDE_DSIVID2DELAY1_TEREQDEL_SHIFT 0
+#define MCDE_DSIVID2DELAY1_TEREQDEL_MASK 0x00000FFF
+#define MCDE_DSIVID2DELAY1_TEREQDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2DELAY1, TEREQDEL, __x)
+#define MCDE_DSIVID2DELAY1_FRAMESTARTDEL_SHIFT 16
+#define MCDE_DSIVID2DELAY1_FRAMESTARTDEL_MASK 0x00FF0000
+#define MCDE_DSIVID2DELAY1_FRAMESTARTDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSIVID2DELAY1, FRAMESTARTDEL, __x)
+#define MCDE_DSICMD2DELAY1 0x00000EB8
+#define MCDE_DSICMD2DELAY1_TEREQDEL_SHIFT 0
+#define MCDE_DSICMD2DELAY1_TEREQDEL_MASK 0x00000FFF
+#define MCDE_DSICMD2DELAY1_TEREQDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2DELAY1, TEREQDEL, __x)
+#define MCDE_DSICMD2DELAY1_FRAMESTARTDEL_SHIFT 16
+#define MCDE_DSICMD2DELAY1_FRAMESTARTDEL_MASK 0x00FF0000
+#define MCDE_DSICMD2DELAY1_FRAMESTARTDEL(__x) \
+ MCDE_VAL2REG(MCDE_DSICMD2DELAY1, FRAMESTARTDEL, __x)
diff --git a/firmware/BT_src_coeff_1.1.fw.ihex b/firmware/BT_src_coeff_1.1.fw.ihex
new file mode 100644
index 00000000000..9922c736cd1
--- /dev/null
+++ b/firmware/BT_src_coeff_1.1.fw.ihex
@@ -0,0 +1,130 @@
+:10000000080046B304080000F9FFFCFF2A007E0048
+:10001000A1004400B3FFA3FF34008600FAFF55FFA0
+:10002000BEFFBB00A20059FFF0FE610079011F0076
+:100030003AFE27FFDA01C30167FE38FDE600C6037A
+:1000400053006EFBDAFDF304A3045FFB11F82803F1
+:10005000730C790032ECCCF51529A45CA45C15294D
+:10006000CCF532EC7900730C280311F85FFBA30484
+:10007000F304DAFD6EFB5300C603E60038FD67FEAD
+:10008000C301DA0127FF3AFE1F0079016100F0FE8B
+:1000900059FFA200BB00BEFF55FFFAFF86003400E7
+:1000A000A3FFB3FF4400A1007E002A00FCFFF9FF7C
+:1000B0000000000000000000000000000000000040
+:1000C0000000000000000000000000000000000030
+:1000D0000000000000000000000000000000000020
+:1000E0000000000000000000000000000000000010
+:1000F0000000000000000000000000000000000000
+:1001000000000000000000000000000000000000EF
+:1001100000000000000000000000000000000000DF
+:1001200000000000000000000000000000000000CF
+:1001300000000000000000000000000000000000BF
+:1001400000000000000000000000000000000000AF
+:10015000000000000000000000000000000000009F
+:10016000000000000000000000000000000000008F
+:10017000000000000000000000000000000000007F
+:10018000000000000000000000000000000000006F
+:10019000000000000000000000000000000000005F
+:1001A000000000000000000000000000000000004F
+:1001B000000000000000000000000000000000003F
+:1001C000000000000000000000000000000000002F
+:1001D000000000000000000000000000000000001F
+:1001E000000000000000000000000000000000000F
+:1001F00000000000000000000000000000000000FF
+:1002000000000000000000000000000000000000EE
+:1002100000000000000000000000000000000000DE
+:1002200000000000000000000000000000000000CE
+:1002300000000000000000000000000000000000BE
+:1002400000000000000000000000000000000000AE
+:10025000000000000000000000000000000000009E
+:10026000000000000000000000000000000000008E
+:10027000000000000000000000000000000000007E
+:10028000000000000000000000000000000000006E
+:10029000000000000000000000000000000000005E
+:1002A000000000000000000000000000000000004E
+:1002B000000000000000000000000000000000003E
+:1002C000000000000000000000000000000000002E
+:1002D000000000000000000000000000000000001E
+:1002E000000000000000000000000000000000000E
+:1002F00000000000000000000000000000000000FE
+:1003000000000000000000000000000000000000ED
+:1003100000000000000000000000000000000000DD
+:1003200000000000000000000000000000000000CD
+:1003300000000000000000000000000000000000BD
+:1003400000000000000000000000000000000000AD
+:10035000000000000000000000000000000000009D
+:10036000000000000000000000000000000000008D
+:10037000000000000000000000000000000000007D
+:10038000000000000000000000000000000000006D
+:10039000000000000000000000000000000000005D
+:1003A000000000000000000000000000000000004D
+:1003B000000000000000000000000000000000003D
+:1003C000000000000000000000000000000000002D
+:1003D000000000000000000000000000000000001D
+:1003E000000000000000000000000000000000000D
+:1003F00000000000000000000000000000000000FD
+:1004000000000000000000001100060007000900C5
+:100410000A000C000D000F00110013001500180059
+:100420001B001D002000240027002B002F0033009C
+:1004300037003C00410046004C00510057005D0071
+:1004400064006A0071007800800087008F009700C8
+:10045000A000A800B100BA00C300CC00D500DE00A7
+:10046000E800F100FB0005010E01180121012A013D
+:1004700033013C0145014E0156015E0165016C01ED
+:10048000730179017E01830187018B018D018F0149
+:10049000900190018F018D01890185017F01790112
+:1004A000700167015C014F014101310120010D0123
+:1004B000F800E200CA00AF00930075005500340058
+:1004C0001000EAFFC2FF98FF6CFF3EFF0FFFDDFE4A
+:1004D000A9FE73FE3BFE02FEC6FD89FD4AFD09FD35
+:1004E000C6FC82FC3DFCF6FBAEFB65FB1AFBCFFABB
+:1004F00083FA36FAE8F99BF94CF9FEF8B0F861F89E
+:1005000014F8C6F77AF72EF7E4F69BF653F60DF6D5
+:10051000CAF588F549F50DF5D3F49DF46AF43BF47A
+:100520000FF4E8F3C5F3A7F38EF37AF36BF363F3F9
+:100530005FF363F36CF37CF393F3B1F3D7F304F459
+:1005400039F476F4BBF408F55EF5BDF524F695F6BE
+:100550000FF793F71FF8B6F856F900FAB4FA71FBE3
+:1005600039FC0BFDE7FDCDFEBDFFB700BB01C902A5
+:10057000E10302052E066207A108E809390B930C76
+:10058000F50D600FD3104E12D1135B15ED168518C3
+:10059000241AC91B741D241FDA2094225224142605
+:1005A000DA27A3296E2B3B2D092FD930A9327A34B3
+:1005B0004A361938E739B23B7C3D423F0541C342D8
+:1005C0007E443346E2478C492F4BCA4C5E4EEA4F7D
+:1005D0006D51E8525854BF551B576C58B259EC5ADC
+:1005E0001A5C3B5D505E575F50603C611962E86287
+:1005F000A7635864FA648C650E668066E2663467A9
+:100600007667A867C967D967D967C967A867766732
+:100610003467E26680660E668C65FA645864A76388
+:10062000E86219623C615060575F505E3B5D1A5C46
+:10063000EC5AB2596C581B57BF555854E8526D517B
+:10064000EA4F5E4ECA4C2F4B8C49E24733467E44FC
+:10065000C3420541423F7C3DB23BE73919384A3637
+:100660007A34A932D930092F3B2D6E2BA329DA27F2
+:10067000142652249422DA20241F741DC91B241A24
+:100680008518ED165B15D1134E12D310600FF50DC2
+:10069000930C390BE809A10862072E060205E10355
+:1006A000C902BB01B700BDFFCDFEE7FD0BFD39FC64
+:1006B00071FBB4FA00FA56F9B6F81FF893F70FF782
+:1006C00095F624F6BDF55EF508F5BBF476F439F43D
+:1006D00004F4D7F3B1F393F37CF36CF363F35FF3B8
+:1006E00063F36BF37AF38EF3A7F3C5F3E8F30FF438
+:1006F0003BF46AF49DF4D3F40DF549F588F5CAF599
+:100700000DF653F69BF6E4F62EF77AF7C6F714F8D3
+:1007100061F8B0F8FEF84CF99BF9E8F936FA83FA7B
+:10072000CFFA1AFB65FBAEFBF6FB3DFC82FCC6FC78
+:1007300009FD4AFD89FDC6FD02FE3BFE73FEA9FED2
+:10074000DDFE0FFF3EFF6CFF98FFC2FFEAFF1000C7
+:100750003400550075009300AF00CA00E200F800B5
+:100760000D012001310141014F015C016701700160
+:1007700079017F01850189018D018F01900190012F
+:100780008F018D018B01870183017E017901730146
+:100790006C0165015E0156014E0145013C013301CA
+:1007A0002A01210118010E010501FB00F100E800FA
+:1007B000DE00D500CC00C300BA00B100A800A00044
+:1007C00097008F0087008000780071006A00640045
+:1007D0005D00570051004C00460041003C003700CE
+:1007E00033002F002B002700240020001D001B00D9
+:1007F00018001500130011000F000D000C000A0076
+:080800000900070006001100C9
+:00000001FF
diff --git a/firmware/CG2900_1_05_SOC_generic_V11_mod.fw.ihex b/firmware/CG2900_1_05_SOC_generic_V11_mod.fw.ihex
new file mode 100644
index 00000000000..df51b3e0984
--- /dev/null
+++ b/firmware/CG2900_1_05_SOC_generic_V11_mod.fw.ihex
@@ -0,0 +1,61 @@
+:10000000010002B303DC0A0007000000000000004A
+:10001000000994766227A063272E0628763A0628E0
+:10002000769A86D989A18600008B00FA0E700F1A85
+:1000300008000852085008AADA010038FE01008EB4
+:10004000130300002803002A2E0100012001009C58
+:1000500003010087F200003D40474C00941100006E
+:10006000C0AF000601260150016901FEFF00010238
+:10007000140D3C27000000000000000000000000FC
+:1000800000200000101010101000001000250100CA
+:10009000000000F60AE70000000000000000000079
+:1000A000000000000000000A0291060D0A6009002D
+:1000B000010000020002040E01021206010000000D
+:1000C00000001A080406050C10000A0C1C08FFFFAB
+:1000D000FFFFFFFFFFFF2E04400000003201003B46
+:1000E00001473C0C85920F38DA54000000000B43A6
+:1000F00046023C00473F7662270055550100B21387
+:10010000FFFF99000212000D0F00CF1B02CF1A0251
+:10011000CF2A00CFD1034FC1034BC003CF2A00CF5A
+:10012000D1034FC1034BC0030000000000000005D5
+:100130001C000380804C0217064D024A404E01010C
+:100140005501005601005701015F22080006000713
+:1001500000EC000246F200B406F800B006FE00AC67
+:10016000060400A8060A00C0060D002017640C0251
+:100170000100010001000078000032650101660104
+:1001800001670102680819000000000000006F1EEE
+:10019000070000000600EC000246F200B406F8007A
+:1001A000B006FE00AC060400A8060A00C0068108DE
+:1001B000FFEE8DFE9BFF59878575170015DD04DD69
+:1001C0000416801E801E24661200C0260000100443
+:1001D00010102510253DFF01000071283028305FE8
+:1001E00055A5280075200020005D00000A00500081
+:1001F000A8001A590A630A0E4D8A00000070F8011F
+:10020000F80139270027002E57545754339128916D
+:1002100028308B018B012F7E867E8629C002E2C3A7
+:100220002A000400004A0E1200BA79EFBD07318699
+:10023000E32D005E040902D05E040903D05E0409C8
+:1002400002D05E020912D05E020913D05E020912CA
+:10025000D05E022D22D05E022D23D05E022D22D050
+:100260005E072932D05E072933D05E072932D05E7F
+:10027000062942D05E062943D05E062942D05E029E
+:100280006E52D05E026E53D05E026E52D05E0E6A27
+:1002900062D05E0E6A63D05E0E6A62D05E136A72CE
+:1002A000D05E136A73D05E136A72D05E156282D01C
+:1002B0005E156283D05E156282D05E216F92D05E41
+:1002C000216F93D05E216F92D05E0E6BA2D05E0E36
+:1002D0006BA3D05E0E6BA2D05E136BB2D05E136BBD
+:1002E000B3D05E136BB2D05E1563C2D05E1563C32C
+:1002F000D05E1563C2D05E214CD2D05E214CD3D0EB
+:100300005E214CD2D05E1548E2D05E1548E3D05E47
+:100310001548E2D08A01018D02000894010C950174
+:100320000D96010D980108990108DD7016005E1CFC
+:1003300048F2D05E1C48F3D05E1C48F2D05E215CCF
+:1003400002D15E215C03D15E215C02D15E2150129C
+:10035000D15E215013D15E215012D15E265422D19C
+:100360005E265423D15E265422D15E015832D15EDE
+:10037000015833D15E015832D15E015842D15E013D
+:100380005843D15E015842D15E015852D15E0158A6
+:1003900053D15E015852D155001A0000E6140000F6
+:1003A000C7060000C7060000C7060000C706000019
+:0303B000C706FF7E
+:00000001FF
diff --git a/firmware/CG2900_1_0C4_1C5.fw.ihex b/firmware/CG2900_1_0C4_1C5.fw.ihex
new file mode 100644
index 00000000000..3096ba77723
--- /dev/null
+++ b/firmware/CG2900_1_0C4_1C5.fw.ihex
@@ -0,0 +1,682 @@
+:100000000000A0E10000A0E10C0000EBCD1F00000B
+:10001000110000EF7C260000880300000A000000A9
+:100020007856012000000000003001204247423293
+:1000300039302052372E30202020202031433520E7
+:100040002031363034323031302031313A35303AA7
+:1000500033344CE230209CE5010C12E334C09C1593
+:1000600000C08C0001C08CE00000A0E3000053E35E
+:100070000EF0A0D104008CE404305302E11400001F
+:1000800010B502F00FF9FE490220087010BDFC49BE
+:100090000A7812B1896801220A7002F008B910B515
+:1000A00002F00AF9F6490878002801D0401E0870CD
+:1000B00010BD10B502F005F90020F24BF24AF34CE6
+:1000C000014600BF23F8101022F8101024F8101079
+:1000D000401C80B20A28F5D310BD2DE9F041E84E4E
+:1000E0000446F068EA4D0079002879D002F0EEF875
+:1000F000F0684179002975D1A17941716278016870
+:100100000068496862F3451141600121052002F051
+:10011000E2F8F06801680268496821F01001516056
+:1001200001680268096821F0100111600168026825
+:10013000496821F00401516001680268096821F0F2
+:100140000401116001680268496941F00041516190
+:1001500022790168496862F30101026851602279DD
+:100160000168096862F3010102681160016827787B
+:100170004A68316947F6C07331F817C06FF47E17CB
+:100180009A4307EA8C1C42EA0C02D0F800C0CCF873
+:100190000420026812689A43237831F8131007EAA2
+:1001A00081110A4301680A6001680068096821F446
+:1001B000803101606078B8BBE178207801EB4101C3
+:1001C00006F14C0202EB8101415C002002F088F84C
+:1001D000F168E07888710021084602F086F826E090
+:1001E00027E0FFE7032922D0227803685B68C3F386
+:1001F00088139A4219D1627803685B68C3F340138D
+:100200009A4212D1E27883799A420ED12279036818
+:100210005B6803F003039A4207D16279012A04D193
+:10022000A27900251143417101E0994D6D1C02F046
+:1002300061F82846BDE8F0812DE9F04389B04FF020
+:10024000000806AB0093934DCDF82080CDF81C80BC
+:10025000CDF818800B462D68444607AA08A9A84780
+:1002600001287ED19DF818008B4E854FC0076BD0BA
+:10027000B86990F86C00002866D1BDF82000874D61
+:10028000C00703D02968012088470446BDF8200034
+:100290004FF00109800707D5787828B987F80190D1
+:1002A0002968022088470443BDF82000400703D591
+:1002B0002968042088470443BDF82000000703D5BF
+:1002C0002968082088470443BDF82000C00603D5EC
+:1002D0002968102088470443BDF82000800603D514
+:1002E0002968202088470443BDF82000400603D534
+:1002F0002968402088470443012C07D1B869018848
+:10030000BDF820008843316888470024BDF82000EC
+:10031000800719D578698178B1B9C178A1B980F819
+:100320000190B969B1F87C10417180F806808DF8B0
+:10033000048041F61800ADF8060001F0E0FF584ACD
+:100340000146126801A890479DF81800800748D51B
+:10035000B86990F86C00012843D1BDF81C00C007B3
+:1003600000E03EE04F4D03D0296801208847044655
+:10037000BDF81C00800703D5296802208847044384
+:10038000BDF81C00400703D52968042088470443B2
+:10039000BDF81C00C00603D5296810208847044317
+:1003A000BDF81C00800603D5296820208847044337
+:1003B000BDF81C0040060BD529684020884704433F
+:1003C000BDF81C00400603D5296840208847044337
+:1003D000012C06D1B8694188BDF81C0088433168FA
+:1003E000884709B0BDE8F0832DE9F0470025089C57
+:1003F000C60725700D80158040F2C33740F2E33CFC
+:1004000040F2A34E40F2434840F283695AD0BB42C7
+:1004100003D0634501D0734503D10D8845F0010534
+:1004200006E0A3F58066633E07D10D8845F0100510
+:100430000D80257845F0010543E0434503D10D8843
+:1004400045F01105F4E7642B05D1012515802578C9
+:1004500045F0020535E0B3F5F27F25D1DFF820A0A5
+:10046000DAF81C603678012E2CD102261680267808
+:1004700046F002062670DAF81C60357022E00000B3
+:10048000E45501202CAA002040AA002054AA0020F4
+:1004900001483188C42A0120BC160120542B0120B8
+:1004A000082B0120582B01204B450BD10D8845F01E
+:1004B00020050D80158845F004051580257845F048
+:1004C00003052570850723D5BB4205D0634503D0BE
+:1004D000434501D0734507D10A8842F001020A80E2
+:1004E000227842F0010212E0642B07D1138843F016
+:1004F00001031380227842F0020208E04B4507D145
+:10050000138843F004031380227842F00302227020
+:10051000020707D50A8842F002020A80227842F0D8
+:1005200001022270020607D50A8842F004020A80FE
+:10053000227842F001022270C20607D50A8842F0F2
+:1005400008020A80227842F001022270800607D554
+:10055000088840F040000880207840F001002070BA
+:100560002078002800D00120BDE8F087F0B5418850
+:10057000FD4DC908A1F54071DFF8F0C3FC4E87B00E
+:10058000033941F618024FF00004FA4F7B6935D069
+:10059000202909D0402905D100222C68F6A3114654
+:1005A0001220A04707B0F0BD808810F0FF005871FE
+:1005B0009C7114D19878012808D19C7000230121E6
+:1005C00000931A461020DCF8005005E0D878012886
+:1005D000E8D1DC701C70AEE0A8477C70E2E715281B
+:1005E00001D9152058718DF80840ADF80A2001F0A6
+:1005F00086FE0146326802A89047D3E7D9780029E1
+:100600006FD193F806E081880EEB4E0E090A03EBDA
+:100610008E0E8EF8071093F806E081880EEB4E0ED2
+:1006200003EB8E0E8EF8081093F806E081890EEB2E
+:100630004E0E090A03EB8E0E8EF8091093F806E0B1
+:10064000C1880EEB4E0E090A03EB8E0E8EF80A10CF
+:1006500093F806E0C1880EEB4E0E03EB8E0E8EF87B
+:100660000B1093F806E081890EEB4E0E03EB8E0E15
+:100670008EF80C1093F806E001890EEB4E0E090A75
+:1006800003EB8E0E8EF80D1093F806E001890EEB49
+:100690004E0E03EB8E0E8EF80E1093F806E0C18915
+:1006A0000EEB4E0E090A03EB8E0E8EF80F1093F828
+:1006B00006E041890EEB4E0E090A03EB8E0E8EF812
+:1006C000101093F806E041890EEB4E0E03EB8E0EF0
+:1006D0008EF811109979C08901EB410103EB81017A
+:1006E00088749879401CC1B2997158798142FFF49D
+:1006F0007AAF9978012902D01979012915D1DB1D2A
+:100700000C2148430093C3B200220121DCF80050C1
+:100710001020A8477C7078690470847001790129E1
+:100720007FF45CAF047144703CE7D87801280DD1A8
+:10073000DC701C705C71B869002201888EA321F006
+:1007400002010180012111202D6845E75878012818
+:10075000EAD118705C7025E7F0B5864D0246017845
+:1007600001230024824E686987B041F618171029CA
+:1007700008D0112926D012290BD110467F4A012119
+:1007800012681DE05178012903D14178012901D176
+:10079000037107E70178012910D1C31D0093407947
+:1007A0000C214843714EC3B200220121366810204B
+:1007B000B0476C70686904708470F3E6837015E06C
+:1007C0009047EFE6417801290FD104704471A86980
+:1007D000654E0188002221F0020101800121366866
+:1007E00065A31120B0476C70DCE6C3708DF808403B
+:1007F000ADF80A7001F083FD014602A83268DFE718
+:100800005C490020487001F07FBD7FB55C495620EF
+:1008100008805C48006880475B4C00205B4D20707E
+:1008200001212B686A463B2098479DF80000C007CD
+:100830001CD00C212B6801AA3C20984730B1BDF890
+:10084000080000F43640B0F5A05F0FD101212B68FD
+:100850006A468A2098479DF80000C00701D1012010
+:1008600003E04B4800688047022020707FBDF0B550
+:100870004949404D474E0B8816281AD140491A392C
+:100880000988090514D400210827A97101240DE065
+:10089000C1EBC10206EB021292F841C0BCF1050F98
+:1008A00002D182F84170AC71491C89B29942EFD9EA
+:1008B000F0BD1728FCD1A9790029F9D00021052421
+:1008C0000CE000BFC1EBC10206EB021292F84150EE
+:1008D000082D01D182F84140491C89B29942F1D9D1
+:1008E000F0BD10B501F0DEFC22490120887010BD7A
+:1008F00070B501F00EFD1F4CA07868B120481A3881
+:100900000088000508D4254D0121286801F006FD66
+:100910000621286801F007FD0020A07070BD204965
+:10092000012008601F4981F86E0E70472DE9F843D9
+:1009300091461F46C27800230C46072598461106AB
+:1009400022F0800670D5811C0422184601F0F0FCCC
+:100950004A46214601F0ECFC397881426ED10025EF
+:100960000A2E6AD220E00000C0160120C416012021
+:10097000082B0120E455012000000000BC2A0120C2
+:10098000728C0040341501207E6800204421012033
+:100990003815012060A50020D26E00201C700020B8
+:1009A0004406304200600020DFE806F047050F48AB
+:1009B00034274747082FDFF8288447E0607800F0A5
+:1009C0000101172001F087FC40E0A07800F00F0043
+:1009D00001F0B3FCE078010938D000F00F000428E2
+:1009E0002CD2DFE800F002020406002002E0022020
+:1009F00000E0032001F0A6FC28E0FA4A2078126803
+:100A0000617820F08000904738E0F74900200968BD
+:100A1000884733E02078062810D2DFE800F003038F
+:100A2000060A0F0C002001E02CE0022001F08AFCF5
+:100A300024E00320FAE70820F8E70325052E1DD05F
+:100A4000092E1BD0042E19D0032D17D0E7490226FA
+:100A5000096830468847814600952078E4A200F076
+:100A60007F033146484601F072FC00233246E14ED6
+:100A700000933668434649461720B047204601F0A8
+:100A80006BFC04E04946204601F06BFC00251FB1D9
+:100A90007878C22800D007252846BDE8F88310B52D
+:100AA0000021062001F062FC0221042001F063FC19
+:100AB0000021072001F05AFC0121BDE8104005206B
+:100AC00001F054BC10B50021084601F04FFC002194
+:100AD000012001F04BFC002001F052FC022140F209
+:100AE000DC5001F048FC0021052001F03FFC012111
+:100AF000062001F03BFC0121072001F037FC00211A
+:100B0000042001F033FC0021032001F02FFC002120
+:100B1000022001F03AFC012001F03CFC002010BD55
+:100B200010B5B548006A007AF8B1B44906200870DB
+:100B30000121042001F01AFC0021032001F016FC21
+:100B40000121052001F012FC012001F019FC022115
+:100B50005D2001F010FC0121002001F007FC0121C3
+:100B6000084601F003FC002010BD052010BD70B543
+:100B7000044615460E4601F073F92A4631462046D2
+:100B8000BDE8704001F00BBC70B5DDE90424002520
+:100B900001461E461570284601F006FC8320207091
+:100BA0009748657090F8C500C00703D00021072062
+:100BB00001F0FFFB0220307070BD70B58E4DA86A49
+:100BC0000178012901D1042415E00121017001F00F
+:100BD000F5FB002001F0D4FB8A490420096888470E
+:100BE000040005D1884800688047032001F0EBFB32
+:100BF000A96A00200870204670BD2DE9F04F044618
+:100C0000DFF8FC81DFF804927B4E8BB0800B4FF055
+:100C100001074FF0000A42D07849032008704FF4D2
+:100C200084707B4AADF81A00126801A906A89047A3
+:100C3000BDF80800022802D0002001F0A1FB754891
+:100C4000006890F8F700C00704D1012177710846C9
+:100C500001F0BEFBB8F8260440F2E241484301F03F
+:100C6000BCFB01F0BFFB6C490968884798F87B031F
+:100C7000800704D56949706B0968007888470121AD
+:100C8000022001F082FB002001F084FB6448007820
+:100C9000002852D000215DE00021204652E0306B58
+:100CA000A10740884FEAD00542D0DFF878B1412D46
+:100CB00010D0A5F50070213834D101F020FB316B44
+:100CC0004A6990422ED1888820BB012001F08FFB19
+:100CD000242020E09BF80000012807D0032821D120
+:100CE000002001F04DFB8BF800A01BE041F20A1040
+:100CF000ADF81A00ADF81C707B20ADF81E0001F0B5
+:100D0000FEFA494A0146126806A89047232001F0DE
+:100D100073FB07E0232001F06FFB02208BF800003B
+:100D200024F00304414800688047F06A80F800A07E
+:100D30004CB198F8FB0001280BD0306A4268002AB9
+:100D4000AAD100E090473A48006880470BB0BDE860
+:100D5000F08F29462046D9F80020F3E7284991F87A
+:100D6000FB10012901D101F04CBB70472DE9F04780
+:100D7000224E304FDFF8C080DFF8C0900546337850
+:100D800000243868D8F80010D9F80020082B1AD2AF
+:100D9000DFE803F004041B58637C7C7C012D6DD0DC
+:100DA000022D05D0032D0CD0042D0CD1012466E0BA
+:100DB00023480068804702213E2001F0DCFA3868B1
+:100DC00068E004245BE0032459E0012D05D0022DE6
+:100DD00060D0032D47D190474CE088474AE000009F
+:100DE000C1E7050008170120A42B01205C2B01207E
+:100DF00062620000702B0120E4550120F1680020A0
+:100E00001C0F01208816012094160120F82A0120C9
+:100E1000D4160120A46C0020242B0120C816012028
+:100E200005730020F2680020082B0120B81601206D
+:100E3000B4160120A016012098160120A816012042
+:100E40009C160120012DC8D0022D23D0032D16D0D1
+:100E5000042DB8D1FF4800680BE0012D06D0022D0B
+:100E600018D0032D0ED0042DADD1AAE79047D8F8A5
+:100E700000008047040002D1032D00D035702046C9
+:100E8000BDE8F0878047D9F80000F2E7012DA4D033
+:100E9000022D96D18047F1E7F8B506460D46144677
+:100EA00003EBD1010422684601F0B0FA05F0070017
+:100EB000009DC4F12001C5404FF0FF3727FA01F033
+:100EC00005407209009516F01F0104D0C1F1200001
+:100ED00027FA00F300E00023DF488D400E19806BF5
+:100EE000202E08D8B74050F822101F43394029431C
+:100EF00040F82210F8BD50F82260C1F120011E40D8
+:100F00002E43631A40F822609F40009BCB40521C46
+:100F100091B250F821203A401A4340F82120F8BD00
+:100F20002DE9F0410446CD480D4690F80D041646D3
+:100F3000000662D5CA4B07221F46002140F20A3044
+:100F4000FFF7AAFF3B46102208218A20FFF7A4FFE3
+:100F50003B4610221821C820FFF79EFF3B460B227C
+:100F600028214FF46070FFF797FF3B46052233219D
+:100F7000D820FFF791FF3B4606223821EF20FFF7EC
+:100F80008BFF3B4606223E21F520FFF785FF3B46BF
+:100F90000422442140F20D10FFF77EFF3B46082259
+:100FA0004821B820FFF778FF3B4608225021C02097
+:100FB000FFF772FF3B46052258218020FFF76CFFA8
+:100FC0003B4605225D218520FFF766FF3B46052253
+:100FD00062214FF47E70FFF75FFF3B4607226821D6
+:100FE000B120FFF759FF3B4607226F219A20FFF7F8
+:100FF00053FF99490120C96B08709B4999480860C3
+:10100000324629462046BDE8F04101F004BA10B549
+:101010000446807A88B3E07A78BB06229349201D83
+:1010200001F0FEF910BB914808388178F1B990F8C9
+:101030002800032803D0022801D0042816D18C49A7
+:101040008C4A09781278114303D103280ED0022864
+:101050000CD0894A0D21126813209047D4E901234E
+:101060000021BDE81040084601F0DFB9D4E90112C3
+:10107000BDE81040002001F0DDB92046BDE8104079
+:1010800001F0DDB91CB57A480178012916D100219B
+:10109000017001F0D9F9784A0221126816209047B0
+:1010A00006227249684601F0B1F9704800210838FB
+:1010B0008078DDE9002301F0B8F91CBDBDE81C40D3
+:1010C00001F0C2B92DE9FC4105460F461646012A3A
+:1010D00025D101F0BEF92D206849684301EB800459
+:1010E0007434A6750020E075284601F0B7F906466D
+:1010F000284601F0B8F962A2CDE9002641F27F73DB
+:1011000001220021284601F0B3F92770284601F09A
+:10111000B4F92846BDE8FC410F2101F0B3B93246CD
+:101120003946284602B0BDE8F04101F0B0B97CB5BF
+:1011300001F0B2F904460068042811D101F0DFF88B
+:101140000C280DD12079022801D00D2808D14D4D51
+:10115000611D284601F0A5F9611D284601F0A6F998
+:101160002068A0F54061153916D101F0C8F80328B0
+:1011700012D1A08800EB0011434800EBC105A87B09
+:1011800050B1A86C40B1A87830B105F148000421F5
+:1011900001F091F90020A8642068A0F5406193391E
+:1011A0001BD101F0ACF8022817D13849A088096892
+:1011B00088470D2811D101AA6946E01D01F080F988
+:1011C000BDF80000A0F500517F3906D13048006815
+:1011D00030F86A1F41F08001018020467CBD10B5C7
+:1011E00001F073F92B4C6088EE2802D001F072F9FF
+:1011F00020B9608801F073F9002816D0264C94F8C5
+:10120000A600800705D5254AB4F8A400126801217C
+:10121000904794F8A600400704D52149B4F8A400EB
+:1012200009688847002084F8A60010BD10B5044660
+:1012300001F05AF901283AD1628840F2E111B1EB8C
+:10124000D20F34D10448006A006802800222A11C37
+:1012500028E00000A4160120E45501201C0F012005
+:1012600029130120AFB80000D82B0120C491002021
+:10127000186D0020196D00200016012094AE00208A
+:1012800069000000AC020120F8930020541A0120EC
+:10129000807000204CBB00209CB50020F829012064
+:1012A0006420012041F6580001F023F9002010BD10
+:1012B00010B586B001A9001DFF4A12689047BDF81D
+:1012C0000600BDF80A40C108A1F5807200F00700D1
+:1012D000E13A12D1022810D1A4F5AF60B0F53E7FFB
+:1012E0000BD8082001F00AF941F6CB1100900160FB
+:1012F00084800921684601F0DEF806B010BD10B503
+:10130000044601F000F9022C09D10021042001F06B
+:101310002DF80021BDE81040032001F027B810BDD2
+:10132000E64800686630818B01F47C4141F4E67147
+:101330008183018801F47F4141F00D010180018822
+:10134000C9B241F400610180C18B01F47C4101F21A
+:101350006A21C183018D01F47F4141F01E010185A5
+:10136000704710B501F0D4F8BDE81040D8E710B5CB
+:1013700001F0D3F8BDE81040D2E710B501F0D2F883
+:10138000BDE81040CCE710B501F0D1F8CC49002001
+:10139000C870CC48B0F86E2C520608D5B0F8580C7E
+:1013A00000F49040B0F5804F01D10120C87010BD0D
+:1013B00010B501F0C1F8C248C07801280BD101F086
+:1013C000C0F8C1480068C18C21F04001C184BDE86B
+:1013D000104001F0BBB810BDB948C078002801D159
+:1013E00001F0B9B8704770B5B54C05466079012871
+:1013F00004D1002100F0ECFF002060712846BDE818
+:10140000704001F0ADB82DE9F043B04E01243168D1
+:1014100087B020468847AE4F05463868ADA290F8A1
+:1014200003312146284600F092FF29460023AA4DA9
+:10143000224600932C680220A047022431682046EF
+:101440008847804600F0CEFF0346A4A221464046CE
+:1014500000F07DFF00230093D5F800C022464146EE
+:101460000420E0473168204688478046A3039BA2BA
+:10147000214600F06CFF0023224600932C68414671
+:101480000520A0474FF009083168404688473C686E
+:10149000814604F27C44E08863882288217A8DE8C2
+:1014A0000F00A3888EA24146484600F050FF00235B
+:1014B00000932C68424649460B20A047012431681E
+:1014C000204688478046386882A290F875342146C5
+:1014D000404600F03CFF0023224600932C68414622
+:1014E0001D20A0474FF005083168404688473C68FA
+:1014F000814604F2764460782379E278A1788DE819
+:101500000F00237878A24146484600F020FF0023D0
+:1015100000932C68424649461E20A0474FF0080819
+:101520003168404688473C68064604F266442079A4
+:10153000E379A279617902AF0FC7E378A278CDE9A8
+:10154000002323886AA24146304600F000FF5C4F2A
+:101550004246386C31460369009300232C680C2006
+:10156000A0470446062804D0386C016909B1002060
+:101570008847204607B0BDE8F0832DE9F04100F030
+:10158000F4FF5D480026006846710E21C1705B4F74
+:101590000121386800F0C2FE0421386800F0EAFF3B
+:1015A0005FF00104386804EB440500EB45000121BD
+:1015B00000F0B4FE3868002100EB450000F0DAFFCF
+:1015C000641C0E2CEEDB00F0DAFF4D4C40F2E247DB
+:1015D0002579E80713D004F1CC011C2201F1500059
+:1015E00000F0D2FF5C3460887843E06784F888605C
+:1015F0002188206F08442067C4E91D065C3CA807C9
+:1016000013D53F491C22B03101F1500000F0BCFF5E
+:10161000403460887843E06784F888602188206FD0
+:1016200008442067C4E91D06403C002000F0B1FFDB
+:10163000401CC4F8F000B4F83801401C0004000C51
+:10164000A4F8380104D1A4F83A610120A4F83801C3
+:101650000220EE34A0712B4806702B4821780268D6
+:10166000002000F09BFF29480078C00709D02848D7
+:101670000188144811F4C06F05D049F6FF71A0F835
+:101680005E1CBDE8F081A0F85E6CFAE72DE9F84F2A
+:101690008946418806464FEAD10A04250027DFF82B
+:1016A00020B0AAF54070833804D1DBF83000417EC9
+:1016B000002971D100242DE0D41601208070002073
+:1016C000E455012000800040287000205C2B0120A0
+:1016D000A46C002062000000702B01206800000054
+:1016E000686862686800000062626262620000000E
+:1016F0006862626262626200147000201C700020E6
+:1017000008A400206E6E00205C160120636E00208D
+:10171000066F00204FF00108FB49C4EBC40B086BB7
+:1017200000EB8B004288002A6FD10D461222314611
+:1017300000F06CFE286B40F2412200EB8B00AAF215
+:101740004121C0F81490924552D026DC40F2471255
+:10175000AAF24711924547D011DCBAF1620F4AD084
+:1017600006DCBAF1410F3FD0BAF1460F54D13FE049
+:10177000BAF1640F38D0BAF1A20F4DD138E09D29EB
+:1017800036D004DC5A2933D05D2945D130E0BA295E
+:101790002ED0DA2940D12BE05CE040F26223A1F2A6
+:1017A0006222994220D011DCB1F5E17F19D006DC2C
+:1017B000B1F5C17F18D0B1F5D17F2DD111E0A1F5E0
+:1017C0000071023910D0202926D10DE0202A0BD03B
+:1017D000B2F5E07F0CD0B2F5F07F02D0B2F5187F01
+:1017E0001AD180F8198000E0477680F81A8007E067
+:1017F0004776877604E047768776F188012902D11B
+:1018000080F8188000E007760625641CE4B2082CF6
+:1018100005D2062D80D118E047768776F3E7042DB0
+:1018200013D1B9F1000F10D0182000F067FE41F677
+:101830004401009001607088494620F007007080E4
+:1018400000988580684600F036FEB0480068804702
+:10185000BDE8F88F1222314600F0D8FDDBF83000E9
+:10186000C0F814904776DBF82C100220087018207E
+:1018700000F044FEA64A0090811D1268DBF830009B
+:101880009047009941F644020A608880DBF83000F6
+:101890004169684611B100F00EFED9E700F083FE01
+:1018A000D6E770B59B4C05462068418BB0F8862082
+:1018B000C1EBC2010C3101F0070141830021A0F806
+:1018C000861000F075FE216848832846BDE8704008
+:1018D00000F073BEFEB505460E4627208E496843CC
+:1018E00001EB800404F112003B2100F06BFEC0B15B
+:1018F000227C8AA18DE8460041F67F7400222346AF
+:101900001146284600F0B4FD8549284609688847F5
+:101910000423009323462A4640F6184100F057FE60
+:10192000FEBD0023227C7DA18DE80E000EB9202390
+:1019300000E01F2300220121284600F099FDFEBD92
+:10194000F8B527251F465543734E0024069B06EB2A
+:101950008505252903D16E7C0E2E00D1012400932C
+:101960003B4600F039FE012C01D10E206874F8BD11
+:1019700010B500F036FE0221092000F029FD0021FB
+:10198000082000F033FE0021BDE81040082000F0E0
+:101990001FBD10B500F02FFE0221BDE81040092048
+:1019A00000F016BD5F480088802805D35E480078A7
+:1019B000032801D100F024BE70470E20704730B4D8
+:1019C0005A4C00EB400304EBC3039B7B012B02D179
+:1019D000012A00D1002230BC00F017BEF8B5544DEA
+:1019E000544E287030780024A8B9287800284FF089
+:1019F000040005D000F082FD40F6A751009004E0FD
+:101A000000F07CFD4FF4E271009001600C2168460B
+:101A100000F051FD2DE000203F4B272200FB02F19A
+:101A200013F8211001B10124401C80B20A2802D20F
+:101A3000002CF3D003E014B900F0ECFD00B101205C
+:101A400010B900F0ECFD00B1012010B900F0ECFD80
+:101A500008B1012400E00024384F00223F68364BD3
+:101A60004FF6FF714920B84735480078044300D04D
+:101A700001243078002817D0BCB128780C24002825
+:101A80004FF0080005D000F039FD40F6A651009057
+:101A900004E000F033FD40F2C311009001600471D6
+:101AA0000C21684600F007FDF8BD0021012000F080
+:101AB0006CFC042000F022FD40F6AB510090016068
+:101AC0000821EEE708B51B48007800284FF0040015
+:101AD00005D000F013FD40F2C711009004E000F0C3
+:101AE0000DFD40F6A851009001600C21684600F001
+:101AF000E2FC08BD10B50446124800688047204645
+:101B0000BDE8104000F095BDE4550120B416012059
+:101B1000D4160120807000204C89002069620000EA
+:101B20005C1A0120D4750020D1750020CC900020D3
+:101B3000B66C0020A86C00202FC60100EC19012013
+:101B4000B56C0020342C01202DE9F0474FF000083F
+:101B5000D94C4309646CC44604EB830E474600F03D
+:101B60001F00C14682F80080454643464FF0010AF7
+:101B7000BCF1000F03D000200EF1040E84461FB10B
+:101B8000002502F8019F2F46C0F12004E6B2C5F1FE
+:101B90000804E4B2B14205D8A1420AD84FF00108C6
+:101BA0000B4608E0A64202D84FF0010C3346B4427F
+:101BB00001D8012723460AFA03F6761EDEF8004014
+:101BC00086403440C440AC401678C91A344314707F
+:101BD000EC181844C0B2E5B2C9B2B8F1000FC7D0D2
+:101BE000BDE8F08710B500F029FDB548B34900689D
+:101BF000B1F89C23C36A62F38B23C362026CB1F811
+:101C00009E1322F0FF02C9B20A430264AA4890F967
+:101C10000400FF2805D0AB4909684A6E60F31852EA
+:101C20004A6610BDF0B587B000F00DFDA64B0D2142
+:101C30001B6803AA4A209847002875D0A34D0521A8
+:101C40002B6802AA8520984705ACA71C002303A88F
+:101C50001E2606AA11E0A04201D138460CE0017808
+:101C60009DF808C0614449B20170002901DA03708F
+:101C700002E01E2900DD0670401C9042EBD98E4820
+:101C80009DF80D108F4E01713068426E61F318524D
+:101C900042669DF80C20016E62F38E2101669DF86C
+:101CA0000E20416E62F3D33141669DF80F20416EE4
+:101CB00062F38E2141669DF81020416E62F3491156
+:101CC00041669DF81120416E62F3040141669DF862
+:101CD0001220016E62F3491101669DF81320016E16
+:101CE00062F3040101669DF81720416E62F35D61A5
+:101CF000416677489DF818200068816D62F34D2198
+:101D000081652B6801AA05214FF47E7098479DF9E3
+:101D10000400C10602D540F0F00001906FF00E0102
+:101D20000F230DF115020EE01CE020789DF8045001
+:101D3000284440B22070884201DA217002E00F2866
+:101D400000DD2370641C9442EFD930689DF81420A4
+:101D5000016E62F3185101669DF81520016E62F361
+:101D6000D331016607B0F0BD10B500F071FC5248E8
+:101D7000406A0078032801D0062814D1554C206809
+:101D8000816A41F0800181624E480068816D21F0D6
+:101D9000FE01816502210A2000F0EDFA2068816AC7
+:101DA00021F08001816210BD70B50D464A4904469C
+:101DB000096888470D2806D14848006830F86A1F2E
+:101DC00021F08001018029462046BDE8704000F0E6
+:101DD00044BCF0B5002487B04148019400883B4FD3
+:101DE00025462646B0F5977F1AD83B6802AA0721F8
+:101DF00040F20A3098479DF90800410602D540F0AC
+:101E0000800002902D499DF9080091F90924824231
+:101E100001DD022404E091F90814814200DD01246F
+:101E2000294B0D211B6803AA4A20984708B19DF948
+:101E3000125005213B6801AA852098479DF80400AF
+:101E40002844204441B21C480029806C017000DA0B
+:101E5000067090F900101E2984DD1E21017081E7B3
+:101E600010B52048007800280CD01348416A154866
+:101E700009780068062906D1816D21F0FE0141F044
+:101E80001401816510BD0329FCD1124C21688A6AB6
+:101E900042F080028A62816D21F0FE0141F01E0154
+:101EA000816502210A2000F066FA2068816A21F02B
+:101EB0008001816210BD0000E45501201C0F01204B
+:101EC000206C0020286C002044210120D82B012008
+:101ED0001C6C0020246C0020541A0120807000200B
+:101EE0001274002008740020744A73481060754A08
+:101EF00073481060754A74481060764A74481060E0
+:101F0000764A75481060774A75481060774A764877
+:101F10001060784A76481060784A77481060794AAD
+:101F200077481060794A78486249106078480860BC
+:101F30007949784808607A49784808607A49794848
+:101F400008607B49794808607B497A4808607C4989
+:101F50007A4808607C497B4808607D497B48086076
+:101F60007D497C4808607E497C4808607E497D4800
+:101F700008607F497D4808607F497E480860804945
+:101F80007E48086080497F48086081497F48086032
+:101F900081498048086082498048086082498148B8
+:101FA0000860834981480860834982480860844901
+:101FB00082480860844983480860854983480860EE
+:101FC0008549844808608649844808608649854870
+:101FD00008608749854808608749864808608849BD
+:101FE00086480860884987480860894987480860AA
+:101FF0008949884808608A49884808608A49894828
+:1020000008608A490E2008808A49894808608B49FF
+:10201000894808608B498A4808608C498A4808606A
+:102020008C498B4808608D498B4808608D498C48E5
+:1020300008608E498C4808608E498D4808608F4939
+:102040008D4808608F498E480860704710B500F0D1
+:1020500078FA8D498D4B99420BD08D48820800202B
+:1020600005E000BF51F8204043F82040401C90425A
+:10207000F8D38848884A81080020034603E000BF5F
+:1020800042F82030401C8842FAD3FFF72DFF8348E6
+:1020900083490370486880F4805048600020401CE9
+:1020A0000528FCDB486880F48050486000F04EFA58
+:1020B000002010BDB82901200F300120C8240120C4
+:1020C0001F3001208C2901205B300120AC2B012026
+:1020D0003330012054240120B9310120F82A012095
+:1020E00069330120C42A0120ED3401200C2B01208A
+:1020F000D9360120C02A012081370120142B01206C
+:102100008B3701203C280120EF370120882901204E
+:10211000633801207138012034160120AD380120C8
+:102120000C1701201F3A01209C160120453A01207E
+:1021300098160120A13A0120A8160120EF3A0120AB
+:10214000982A0120093B0120942101203B3B0120DA
+:102150004C2B01207B3B0120F02A0120DD3C01209B
+:10216000EC2A0120ED3C012088160120A13E01202F
+:10217000D82B01208F3F012034230120054001206E
+:10218000841B01204540012084290120AF4001200B
+:10219000302801205F410120201F0120AD41012096
+:1021A000D81601207F420120D02A01209F3801202B
+:1021B000801E0120E3420120AC1C0120EF420120DF
+:1021C000901C0120FB4201208C1C012007430120B0
+:1021D00028260120314301209C240120594301205D
+:1021E0009C1E012067430120202B012087430120F2
+:1021F000842B0120FB440120581601200D460120AC
+:10220000082B012023480120842401205548012067
+:10221000D01A0120C148012008210120F1480120E5
+:10222000D015012013490120B42A0120C68800409E
+:102230003B490120401E01203F490120D4210120BB
+:102240005D49012064230120454A012068230120C3
+:10225000754A0120002C0120C94A0120A821012033
+:10226000654B0120342C0120A54B01207022012058
+:10227000E94C012068220120294D0120DC1D0120AC
+:10228000534D0120EC2B01200030012000300120B3
+:10229000782600000000000078560120E955012052
+:1022A000004001404BF6FB2CC0F2030C604749F69E
+:1022B0008B6CC0F2030C604749F66B5CC0F2030CF8
+:1022C00060474EF2290CC0F2030C60474FF67F3C8A
+:1022D000C0F2000C604740F2775CC0F2010C60472E
+:1022E0004FF6654CC0F2000C60474FF6873CC0F2D9
+:1022F000000C60474FF6833CC0F2000C604748F684
+:10230000173CC0F2000C60474EF21B2CC0F2050CCB
+:10231000604745F6891CC0F2030C604745F2514CFA
+:10232000C0F2030C604745F25D4CC0F2030C6047FD
+:1023300047F28B4CC0F2060C60474AF6430CC0F2E1
+:10234000000C60474AF25D6CC0F2000C60474EF230
+:10235000E95CC0F2050C60474FF61B7CC0F2050C2F
+:1023600060474AF6D52CC0F2000C60474EF2511C73
+:10237000C0F2000C604740F24F5CC0F2010C6047B5
+:102380004BF23F4CC0F2000C60474FF2817CC0F230
+:10239000050C604745F2830CC0F2060C60474BF217
+:1023A000850CC0F2000C604741F6FF1CC0F2000C27
+:1023B00060474EF2715CC0F2000C60474EF6AF2CE5
+:1023C000C0F2000C60474EF20B5CC0F2000C60479C
+:1023D0004EF2D17CC0F2000C60474EF69D2CC0F24C
+:1023E000000C60474EF6031CC0F2000C60474BF235
+:1023F000534CC0F2000C60474FF6D14CC0F2000CB9
+:1024000060474DF2EB6CC0F2050C60474DF23B0C9F
+:10241000C0F2060C60474BF6AF0CC0F2000C6047F0
+:102420004CF6DD6CC0F2060C604742F6B17CC0F29F
+:10243000020C604743F6371CC0F2020C604743F6BB
+:10244000AF1CC0F2020C604742F6EB7CC0F2020CFB
+:10245000604744F6E94CC0F2010C604742F6E93CA3
+:10246000C0F2040C604747F6776CC0F2010C60477D
+:1024700048F2E77CC0F2060C604749F29F7CC0F24C
+:10248000010C604743F2B15CC0F2040C604749F2B2
+:10249000BF5CC0F2040C604748F6973CC0F2000CE9
+:1024A000604741F65D7CC0F2000C604741F6EB7C72
+:1024B000C0F2000C604748F61F3CC0F2000C6047B9
+:1024C00048F2894CC0F2060C604749F6570CC0F23E
+:1024D000040C604747F6137CC0F2010C604743F2DE
+:1024E000D10CC0F2020C604749F6E97CC0F2000C46
+:1024F000604743F2B13CC0F2010C604748F6F32C50
+:10250000C0F2000C60474AF2734CC0F2000C604706
+:1025100046F2451CC0F2050C604746F2173CC0F27B
+:10252000050C604746F26D3CC0F2050C604744F66E
+:10253000C53CC0F2030C60474DF6196CC0F2030CA9
+:10254000604748F6793CC0F2000C604748F6573CBB
+:10255000C0F2000C604740F62D6CC0F2040C6047DE
+:102560004AF2E75CC0F2000C60474FF2235CC0F215
+:10257000040C604745F2914CC0F2030C60474FF2E7
+:10258000335CC0F2040C60474CF6837CC0F2060C4E
+:1025900060474FF2495CC0F2040C604740F6716C32
+:1025A000C0F2000C604748F6073CC0F2000C6047E0
+:1025B00041F6DB6CC0F2010C60474BF2AD5CC0F23F
+:1025C000020C604744F66D2CC0F2020C60474AF2E0
+:1025D0009F4CC0F2040C60474DF2096CC0F2040C31
+:1025E00060474BF6B75CC0F2050C60474EF6911C95
+:1025F000C0F2000C60474CF2FB4CC0F2050C604787
+:102600004EF2D74CC0F2000C604742F2CB1CC0F235
+:10261000020C604744F2C11CC0F2030C60474CF24C
+:10262000D91CC0F2040C604743F2472CC0F2020CE4
+:10263000604741F6C50CC0F2060C604746F2E76CF5
+:10264000C0F2060C604741F6E17CC0F2010C604725
+:1026500040F2094CC0F2060C60474AF6656CC0F2C5
+:10266000040C604700000000FF000000B36E002073
+:102670003469002040D2060088C90020147300206D
+:10268000007300205482002010740020F4680020A1
+:10269000F068002074810020F168002094820020FE
+:1026A0000869002068820020948200208074002045
+:1026B00000010C0C0203040C0608090B0102030CB8
+:1026C000040608090B0C0C0C0C050C0C0A0C0C0C69
+:1026D0000C0C0C0C0C060C090B0C0C0C0C0C0C0C44
+:1026E000EC750020ED750020F4750020EE750020DB
+:1026F000180F0120EF750020DDCCBBAA0000CB0035
+:10270000700001000100B50064A103000200DD01BA
+:1027100074FB000003002B0234A2060004006902CF
+:1027200058A1060005007F0220C7050006005100E1
+:1027300088F3020007006900CCF302000800B5022C
+:1027400038BF05000900EB02388E00000FF20500CB
+:1027500000F024B807B500F026F8BDE807400022D5
+:102760000C4C20470FF2050000F018B807B500F038
+:102770001AF8BDE80740054A17680122BA71044AF1
+:10278000176800221000DFF810C06047B8F402009C
+:10279000BCF402008DF30200D1F3020040F2ED4CD4
+:1027A000C0F2000C604740F2DD4CC0F2000C604704
+:1027B0000FF20500FFF7F2BF07B5FFF7F4FFBDE822
+:1027C0000740904A10470FF20700FFF7E7BF07B531
+:1027D000FFF7E9FFBDE807402DE9F04F002799B06A
+:1027E00005463846BB464FEA0D0949F820B0401C63
+:1027F0001928FAD3FFF7A7FE834850F82540002C8C
+:102800005BD0DFF808A2284600F014F9E06849F828
+:1028100027001AF8051020466469491E0AF80510B9
+:102820009AF804107F1C491E8AF80410D0F808801A
+:10283000C0F80CB00126C0F808B00421C0F804B0FC
+:10284000017480F800B0724900E011464A69824282
+:1028500002D0002AF9D103E012B14069486101E0D9
+:10286000C0F814B0284600F0EAF854B1A1688045D9
+:1028700004D2814204D2414503D801E0814200D311
+:1028800000261AF8050008B1002EBCD05E4E46F8AE
+:1028900025401CB12846A16800F0D6F81AF80500BA
+:1028A00058B946F825B0284600F0D3F8284600F07D
+:1028B000D5F80021284600F0D6F8FFF749FE00249D
+:1028C00003E08047641C192C03D259F82400002827
+:1028D000F7D119B0BDE8F08F0FF20500FFF75EBF2A
+:1028E00007B5FFF760FFBDE807404A490A8822F4B0
+:1028F000FC72032802D0042804D00DE042F4B47224
+:102900000A800CE042F4D4720A808A8822F03802ED
+:1029100042F020028A8002E03F4800F0A9F8BDE8BA
+:102920001040BDE8F0810FF20700FFF737BF07B591
+:10293000FFF739FFBDE8074006EB0401069B181BB3
+:102940000ED0012802D1FF2D0AD002E0BA1C90421D
+:1029500006DAC2B28AF80120DAF80800FFF758FD5B
+:102960002E4A10470FF20500FFF718BF07B5FFF713
+:102970001AFFBDE807402A4800470FF20700FFF79B
+:102980000DBF07B5FFF70FFFBDE807400EB440F2DB
+:10299000E1118C4202D1FEF78DFC06E00EBC03294A
+:1029A00001D020480047204800470EBC1F48004780
+:1029B0000FF20500FFF7F2BE07B5FFF7F4FEBDE822
+:1029C000074000F05AF860684078800709D402B4E4
+:1029D0004FF00001606820F8521F8170C1700171D2
+:1029E00002BC134800470FF20700FFF7D7BE07B538
+:1029F000FFF7D9FEBDE80740FEF7D6FF48F63D6079
+:102A00000047000075A103004C870020F56B0020F3
+:102A10002C840020B0C601400004A1AA15A3060022
+:102A200061A1060025C70500B5C70500F3C905006B
+:102A30003DBF050040F2EB7CC0F2010C60474EF652
+:102A40009D6CC0F2000C60474EF6A96CC0F2000C01
+:102A5000604740F2DF7CC0F2010C60474FF6F17C2A
+:102A6000C0F2000C604740F2C37CC0F2010C60472A
+:102A700043F2792CC0F2010C60474BF6A97CC0F2FE
+:042A8000050C60479A
+:00000001FF
diff --git a/firmware/Cobra_FM_SOC1_coef.fw.ihex b/firmware/Cobra_FM_SOC1_coef.fw.ihex
new file mode 100644
index 00000000000..b67325acdc0
--- /dev/null
+++ b/firmware/Cobra_FM_SOC1_coef.fw.ihex
@@ -0,0 +1,195 @@
+:1000000005009F23140C0000E8FFA6FF2FFF91FEC0
+:100010002EFE91FE5000D803E6089D0EAD139D16EE
+:100020009D16AD139D0EE608D803500091FE2EFEDE
+:1000300091FE2FFFA6FFE8FF0504F60B0014F11B4D
+:10004000F11B0014F60B0504B601DF03C2054407DB
+:10005000530890095E0ADF0ADF0A5E0A9009530816
+:100060004407C205DF03B6012F00D900630245052E
+:100070006209210E7C12021502157C12210E620902
+:1000800045056302D9002F0048FAF0E197BED5A3D9
+:1000900008A404BF43E25FFAA105BD1DFC40F85B64
+:1000A0002B5C6941101EB805B3FACCFC0FFA47FF70
+:1000B000CD064E11A61CFD21FD21A61C4E11CD061C
+:1000C00047FF0FFACCFCB3FA87108101F801B801A1
+:1000D000EA000502020000000000FF7F70177017A1
+:1000E000FF7FFF7F1F001F00E40016022100210098
+:1000F000200020002F02D8015A0000000004000454
+:10010000A6FF000400000000C264020001006F4569
+:10011000020000000100C264C2642C43030002001C
+:1001200002009D104D0121020100A91AAA3C010004
+:1001300010016A07C20027005206DD00CE04FF7FCF
+:10014000FF7FC70AE1251400860140051517280026
+:10015000C300A902650E4E004E0010016A07C200DE
+:100160002700CE10A3018202000084035A00A400DD
+:1001700092027245FF7F0000FF7FA4009B02FC6695
+:10018000FF7F0000FF7FA400A402FC66FF7F000049
+:10019000FF7F4700AD02A202A302AB02AC029902AC
+:1001A0009A02FFFFFFFF180007080B280D0812082E
+:1001B000134814082228264829282A282B482D28A5
+:1001C0003548372839083B283D48404842484428AC
+:1001D00045084B084F4852280F00700855285728EB
+:1001E00059285B285D285F8861086428662868288C
+:1001F00070086A286C286E281000712873287548CA
+:10020000772879287B287D287F28812883288528BE
+:10021000872889288B288D288F28380096689B2866
+:100220009D089F08A128A328A528A728A928AB488E
+:10023000AD48AF48B048B128B388B528B768B928E9
+:10024000BB88BD08BF28C728C828CA08CD08CF2842
+:10025000D128D308D508D728E048E348E628E8881D
+:10026000ED28F208F4A8DC28F90800290629082955
+:100270000A290C290E09100912091409160918492E
+:100280001C2922492F293129332935C91C003869F5
+:100290003D293F2944097409472949494B894D297A
+:1002A0004F295129530957295A495C296109642961
+:1002B00066A968296A296C296E49702972A974098E
+:1002C0007529740977290B008229844986C989090F
+:1002D0008DE9910993E99429952996A99B092849C3
+:1002E0000000084800000C7800200D600000F42693
+:1002F00000500C7800280C7800280D7800000D784C
+:1003000000200C7800200C7800000C41000436011D
+:1003100000041E5100041C5100040C590004E56245
+:10032000C6207013A40D5D0A3C08B9069705B304F6
+:10033000FC036403E40278021B02CB01850148013F
+:100340001401E600BF009D008000670052004000DD
+:10035000310025001B0013000D0008000500E262BB
+:10036000BE206213920D460A1F0898067105890483
+:10037000CD033103AE023F02DF018C0144010601CF
+:10038000D100A2007B00C31141007C007B00CA1198
+:1003900084001A03F6FF0060A4000300E0110400CB
+:1003A00039030C6080408240770404003E032C60D7
+:1003B000A040A240780401004303CC6004005B032A
+:1003C000B800B00161044503B51222004504006085
+:1003D0000035880072030E0003000A000E00E513CA
+:1003E000007018000F0028007F030003000C000EAF
+:1003F0000060010000600001002028008803380030
+:1004000040030000FF7F0100FF7F00010010280073
+:1004100091030004000A0000FF7F0100FF7F000439
+:10042000002028009A030000C000001800600100AE
+:100430000060800000082800A3030C003800004082
+:10044000FF7F0100FF7F000200102800AC030000C6
+:100450000004000400780100006000040010150092
+:10046000B5030001000880000004000400208000A3
+:1004700000024000000100010010200000010008FF
+:10048000100040000001000A800010001500CA039F
+:100490000010002000400040004000020004004026
+:1004A0000008007000010040000200080040000148
+:1004B000FF7F00200020001000046600E103000818
+:1004C000100099597900BFE040002500EF03870430
+:1004D000EC0316012C02BD0A4400F5035C04ED0395
+:1004E00033033D0A0600FB037003EE03D83B2549A6
+:1004F000BE0ABE0A6A000104FF7F008000000000FF
+:100500000000800200000000000E00206A000E04BF
+:10051000FF7F0080000000000000000B00000000D2
+:10052000000600206A001B04FF7F00FC00000000A2
+:100530000000000800000000000100204B0028041B
+:10054000FF7F00FF8003000000000014800800000F
+:100550006000002080032C003504FF7F80F700102E
+:100560000080000000020000001200020018001DC0
+:10057000001855859FFF009041FFAB9ABDFE55A521
+:1005800008FE00B013FDABBACCFB55C510FA00D085
+:10059000A2F7ABDAFDF355E5C6ED00F0F8DFABFAF4
+:1005A0005B9DF8FFE8FFC9FF9BFF5FFF1CFFDEFEBE
+:1005B000BDFED0FE36FF0600530120035F05F107A4
+:1005C000A30A3B0D760F1A11F81103000000F6FF85
+:1005D000D9FFA6FF59FFF9FE95FE4CFE46FEB3FE7D
+:1005E000BBFF7A01F20307077A0AF30D0A115D13C4
+:1005F0009D14090018002E003F003E001700BBFFAD
+:1006000025FF6AFEB7FD59FDA3FDE9FE5A01F4047A
+:1006100070094B0ED71260164F18030011002F00FF
+:100620005F009100B00094001F0042FF19FEF3FC30
+:100630004FFCBBFCB5FE7102BC07F20D1314001990
+:10064000BE1BFAFFF7FFFBFF19005400A600EA00EB
+:10065000EA006B0052FFC6FD47FC9CFB9FFCEBFFD2
+:100660009105E70C9F14121BBE1EF7FFE3FFC7FFA7
+:10067000B7FFD3FF2F00C7005F019401F80060FFB0
+:100680001DFD1BFBA5FAF8FCA6022B0BDC14581D64
+:100690004C220200F9FFE0FFB3FF8FFFA1FF15001E
+:1006A000E700C10104021301C9FED9FBD6F9ADFA76
+:1006B000BEFFF8088014231F86250C001C002400B0
+:1006C0000400B2FF50FF36FFBEFFF1003F029D0263
+:1006D0001C01C2FD13FAC0F865FCE9057913DB20A3
+:1006E0002C2907001D003C00460010008FFF03FF6F
+:1006F000F9FEE2FF97010403A802AFFF1EFBFCF71F
+:1007000000FA3C033A12F021002CFBFFFFFF170018
+:1007100048006200250078FFC4FED6FE3C006B0254
+:100720009A03DF0117FD1EF8DAF71F006310D622C7
+:10073000182FF7FFE8FFE7FF16006E009D0031005D
+:1007400026FF4AFED6FE2901BB03B90376FF09F94D
+:100750003FF600FD350E7B232C320200F3FFD5FF60
+:10076000C8FF0A009500E1003900B9FECEFD2BFF5D
+:100770009302E60468022DFB4FF570F9240BD82391
+:10078000CA350E001800FFFFB6FF8EFFFAFFE0002B
+:100790003601FBFFE1FD77FD7E00C304E10407FEA7
+:1007A0006FF54FF6C807D02349390B002B003E00E8
+:1007B000030080FF58FF2B0069014A0100FFC8FCBD
+:1007C00043FE6A035D0614018AF6D4F34D045923EF
+:1007D0007D3CF6FF02003B006E00190049FF1AFF46
+:1007E0007100FC01070199FD3DFCA900A1069F04D1
+:1007F00006F9BCF1F6FF5A224940FAFFD5FFBEFFC9
+:100800001000A400760033FFAAFE9200B002C600DA
+:1008100023FC7EFC2D04370817FEA2F0BFF90B2045
+:1008200082450D001A002F00450064008C00BE00B8
+:10083000F60034017A01C50114026102AD02F5022D
+:1008400037036E039903B703C703B703B8F38617DB
+:1008500053E0AD1F7AE8480C49FC531427004804C4
+:10086000ECA90001000A0700FFFF3002002005008C
+:1008700072042000200080001000000003008404A7
+:1008800000012000FFFF03008D0466086608FFFFDB
+:10089000240096048404FF7F0000FF7F43009B0434
+:1008A00000101900FFFF0200A40463AC01006614ED
+:1008B0004200C204E04000410300C604E840602159
+:1008C000AD040300C90408417021AC040200CC044B
+:1008D0008021B5040000000C5B030100000C4008FF
+:1008E00021018C066F14D4FFF700B8FCC50826EA76
+:1008F000914F914F26EAC508B8FCF700D4FF0700D6
+:10090000EDFF2B00ADFF920010FF7601CEFD360308
+:1009100061FB9F0659F6D20EC0E52D512D51C0E561
+:10092000D20E59F69F0661FB3603CEFD760110FF0D
+:100930009200ADFF2B00EDFF07007EFFA301BFF982
+:1009400039413DFF74029EF6D56165FF75011AFDC0
+:10095000FB09781700E03EE0902120612A613661B2
+:10096000A021A521AB2140804E805D80400801057B
+:10097000BA4D721C0E01B604F90011474CF5C3754F
+:100980000000030001000100DD14A106C714A50644
+:10099000FF7FFF7F000000200040006000A000807B
+:1009A00000A00080E80900804D460080E909008031
+:1009B00058200080EA090080696D0080EF090080FE
+:1009C00020740000960C0C1944251E317F3C4847CA
+:1009D0006151AF5A1C63936A02715B768F7A957D81
+:1009E000677FFF7F677F957D8F7A5B760271936A61
+:1009F0001C63AF5A615148477F3C1E3144250C1996
+:100A0000960C00006AF3F4E6BCDAE2CE81C3B8B813
+:100A10009FAE51A5E49C6D95FE8EA58971856B8274
+:100A20009980018099806B827185A589FE8E6D9574
+:100A3000E49C51A59FAEB8B881C3E2CEBCDAF4E61F
+:100A40006AF30000060DE11964266832C63D5A4873
+:100A50000652AF5A3F62A868DF6DE071AE745176FE
+:100A6000D6765276DA748D72896FF06BE967976388
+:100A7000225FAF5A61565C52BE4EA14B1F49484798
+:100A80002A46CD452A4648471F49A14BBE4E5C52D7
+:100A90006156AF5A225F9763E967F06B896F8D7279
+:100AA000DA745276D6765176AE74E071DF6DA8684E
+:100AB0003F62AF5A06525A48C63D68326426E11971
+:100AC000060D0000FF7FDD141D15540690082D490A
+:100AD000C208C003E4080000420900004109000008
+:100AE0007909000055090009D9080000E808839039
+:100AF00091083D0070090000A4081100A408370007
+:100B000090082D79C208C003E408000042090000E3
+:100B10004109BA075309430655090009D9080000DD
+:100B2000E80883907009000091083D00A4087E0049
+:100B300096080040970800409008BC99C208C10B75
+:100B4000E40800404209C3004109000053090106BE
+:100B500055090109D908000070090400E8088790C8
+:100B6000BE1588007207D6064E0062000000020023
+:100B70009A019A010100A5008A0700007F00FF0189
+:100B8000C8327F00D6069A01F00518017805F802F0
+:100B900020062706020028062F060100A907B10734
+:100BA0000200B207BB070100B107D6061E068C057E
+:100BB000E803F3073A078106C805E8039264005882
+:100BC000394E6646004024490040E33833338B2ECB
+:100BD000E61B6A18B3158813C111A3502A5CAE67CF
+:100BE0003373B87E4009FF934309070347097F0E1B
+:100BF00048091DA8490902004A09880790082D499B
+:100C0000E40800005E0901005C09901A5009080020
+:080C10007E0900932109080090
+:00000001FF
diff --git a/firmware/Cobra_FM_SOC1_prog.fw.ihex b/firmware/Cobra_FM_SOC1_prog.fw.ihex
new file mode 100644
index 00000000000..ee70c7a36e0
--- /dev/null
+++ b/firmware/Cobra_FM_SOC1_prog.fw.ihex
@@ -0,0 +1,3060 @@
+:100000000400EF6726BF000000F0831F80D200F0DD
+:100010000070149000F0300A80D200F07C1F80D273
+:1000200000F0007022A000F0D01A80D200F0021F71
+:1000300080D200F0241B80D200F02A0280D200F08F
+:100040004D1580D200F0091680D200F0A60780D2AC
+:1000500000F0601380D200F0480D80D200F0C50699
+:1000600080D200F0230B80D200F0A01480D200F0E8
+:100070008B1380D200F02A0080D200F0E31480D2EB
+:1000800000F0CA0A80D200F00070108000F0731FE8
+:1000900080D200F000700FA000F0211B80D200F091
+:1000A0003F0280D200F0511580D200F0261680D297
+:1000B00000F0AA0780D200F0621380D200F04F0D4A
+:1000C00080D200F0C80680D200F0310B80D200F060
+:1000D000A01480D200F0931380D200F02D0080D2C3
+:1000E00000F0EC1480D200F0CC0A80D200F0591558
+:1000F00080D000F0F31A80D200F0970A80D200F08E
+:100100009E0980D000F06010086000F0B31F80D21C
+:1001100000F000708AA10082F20108601B020960F1
+:1001200006C01440001000F00602086006C000F08F
+:10013000101000F08434F801096000F0007034A160
+:1001400000F0143600F000F094333DA100F0DB071E
+:100150000A6000F0E801096000F027200280E80151
+:1001600009607CA1113F00700080112F88090A608E
+:10017000F09F42090C60834F222C09D40082442056
+:10018000754E9AC2010806604190932B00F02CC373
+:10019000912E069000F0263200F0AA90132E00F067
+:1001A0004190443015409290A330C0E0932D8409D3
+:1001B000066000F0223C05801B88A0308141DBD026
+:1001C000223C00F0CBC2007000F01CC5A6080660FF
+:1001D00000F0443006A08E91963F00F01630F301F7
+:1001E0000E60B683933004C000F0661000F000F09B
+:1001F0001531E1A000F000706681152F834162A1E6
+:100200004591991B80D21CC3142C09D4C0D703403C
+:10021000059020A0007000F000A8952C00F000CC04
+:10022000007000F04583007000F00BAE007000F02D
+:1002300000F0153100F000F0933008D0E8010960BB
+:1002400057A1913B0070DB8FE801096055A1913EF9
+:100250000070D98FE801096053A1113E0070D78F5B
+:1002600000F087100E60709EE8010960789EEC70C7
+:1002700000E2102F6C7000E200F0650100F000F069
+:10028000662000F00090153C00F000F0963C09D488
+:1002900000F00070CE8F0AA2007000F05382F13996
+:1002A000019800F0733908D05380713900F000F0E4
+:1002B000F33908D0E8010F6043A14090F12A00F023
+:1002C00000F0703BF88FE8010F6040A100F0702B48
+:1002D00000F000F0F13AF58FF09FE8010F6000F0B8
+:1002E00012400394419070283BA100887235C0E011
+:1002F00000F0703A08D00082FF7F02604190703AAF
+:1003000000F09282703540E000F0F23708D0E8014A
+:100310000F6034A100F0F13808D000F0F82F00F0A1
+:1003200000F0792000F000F0F32000F000F0002051
+:1003300000F000F0112000F018A0742100F058B077
+:10034000732400F008AF7824074209BFF42400F0BA
+:10035000C390F92400F00491002000E600F0112081
+:1003600000E638A0722600F078B0E07F06601586BF
+:10037000F32500F010821540029CF3A20070039850
+:1003800000F000580280F3A20070019C00F0FF7F93
+:10039000006059A1007000F0B1A0742700F003A81C
+:1003A000FF7F0560F3A8733600F0EDC2F32600F07E
+:1003B0006586F53500F061821540029CF3A200705D
+:1003C000039800F001580280F3A20070019C00F035
+:1003D000FF7F016059B1007000F031B1007000F092
+:1003E00003B8FF7F0560F3B8733700F0EBC2F7285E
+:1003F00000F000F0F33600F0FF9F742900F000F0E9
+:10040000F5290598FF9F007002900190007040E070
+:100410004090007002800884007000F0019000702D
+:1004200000F020A0007000F068B0007000F050AA4A
+:10043000742A00F051BAF32700F065DC772500F04C
+:10044000E382007000F0FF9F0070029C00F077359F
+:1004500000E2EBD7B30A80D318A2F33700F059A219
+:10046000F03100F000F0713208D00689007000F021
+:100470000F8913231440BE8D952200F018A100703F
+:1004800000F0AE83007000F09220122040EF00F0E8
+:10049000FF7F076091A1007000F006A8007000F0D7
+:1004A000AE81122200F0F3A8963200F0FBC2007079
+:1004B00000F08290133300F000F0132409D0068975
+:1004C000952300F018A1132500F0AE83922100F0CF
+:1004D00018B1122100EE0C89007000F091A100709B
+:1004E00000F006A8007000F0AE81952400F000F046
+:1004F000963300F02C83922100F0F6A8122100EE32
+:10050000BEC3007000F011B1007000F004B81634E2
+:1005100000F02C81007000F0F4B8943400F03CC37B
+:10052000007000F000F0143508D000F006020860FA
+:1005300000F0662400F000F0642500F000F0E524EF
+:1005400000F0A2A3007000F0AA80E52000F093A3C1
+:10055000E62200F01B83E23400F075A3672300F06D
+:10056000AAA2633500F0F383E42300F000F07528BD
+:10057000079000F0E235039CAE83007000F0BE8D62
+:10058000007000F000F0E6320E80AE81007000F0E6
+:10059000C691007040E100F0E6320B8000F0632667
+:1005A00000F03C9FE23500F0FB9E00700894C7917C
+:1005B00000700594E321632140E6C791FF7F02604C
+:1005C000E38C024000E6C390007000F000F062335C
+:1005D00000E6E38C007000F063367201046000F006
+:1005E000822300F000F0E43300F000F0862200F0F7
+:1005F000B29E072300F000F0E02500E2F383E1253E
+:1006000000E200F08225059000F00070029CAE83AD
+:10061000007000F0BE8D00700280AE81007000F0AE
+:10062000C691007040E130A2842400F071A28632AD
+:1006300000F000F0003700F000F0813700F0049186
+:10064000842F00F0BA9E032509D4349F823509D443
+:10065000C3909422119400F08520069000F0832628
+:1006600000F02C8F022000F0FB9E8321C0E200F0FE
+:100670000422054000F0833600F0C3900436078062
+:1006800000F0052100F000F0032600F0648FF24135
+:1006900000F0FB9E0322C0E200F08421154000F030
+:1006A000033600F0C390843600F00240023400E2CA
+:1006B00000F0053500E2FF83023340E283237C0033
+:1006C0000D60042472010260F683552100F0E68279
+:1006D000823509D44591842F09D0B683007009D0A2
+:1006E000349F007000F00041991F80D37C000D60A2
+:1006F0008FA0532100704BA0C390007000F000F059
+:100700000070069000F0100B80D228C6007000F038
+:1007100000F00070039041915D0280D24790080B79
+:1007200080D20040771A80D20602086085A0002798
+:10073000E8010F608127007008D02109086000F0EF
+:1007400000F0902B824200F00120F44DB683152D6D
+:1007500000F061C2923300F0F29F132F04427A9F9F
+:1007600016330394C29000700294029000700194BA
+:1007700061C40070C0E000F0013008D000F0F02B40
+:1007800000F0722D21090860732FC0000660BA9E28
+:10079000F42300F0C390752309D40090007009D4AD
+:1007A0000491022009D04591F3220B94B2C200704B
+:1007B00008948F02026009D000F0991B80D2C0D744
+:1007C000007000F010A2007000F018A0007000F09F
+:1007D000F5A9007000F0F4A875330044F433991FB4
+:1007E00080D07D9F007000F000F0753300F03C9FDA
+:1007F000007000F000F0F43308D000F0E801096068
+:10080000A2459B1B80D280A242090A6000F01038EA
+:1008100000F000F02420FBAEF8010E603B80E80100
+:1008200009605CA000F0113DD88FE80109605AA072
+:100830000082913200F000F0903300F000F01033AD
+:1008400008D016020E6056A000F0E12300F000F080
+:10085000E22408D016020E6053A00082613200F03C
+:1008600000F0E03300F000F0E03400F000F060341D
+:1008700000F000F0603508D01140832F06A0FB9EE9
+:10088000813500F0F3410320C0E2013516020A6011
+:100890004982033400F000F0A13200F000F021336F
+:1008A00008D000F0002200F000F0822100F000F0FB
+:1008B000003600F000F0823608D00602086042A040
+:1008C00000F00424064000F0F8010E600591FF7F5F
+:1008D00007603D9F84330990359F0070099000F0B8
+:1008E000007001901540073308D000F062223AA052
+:1008F0008290652100F000F0E52100E2FF830733DC
+:10090000C0E000F0653600F01540673308D00540C0
+:10091000063308D01540063308D040900602086020
+:10092000F241007040E000F0813F00F000F0023042
+:10093000E1AF00F000709E8F060208602DA000F06D
+:10094000813000F000F0023100F000F0833100F05F
+:1009500000F00432E28FF8010E6028A000F0E130D0
+:1009600000F000F0623000F000F0E33100F01140E0
+:10097000643100F000F0653200F000F06136008074
+:1009800000F0460B056062209B1B80D217405E4B37
+:100990000660A8A0E53400F0B9A1007000F065AAD7
+:1009A000007000F045A30040076092D7E12000F0FE
+:1009B000D783653400F079A2007000F000F0613553
+:1009C00008D00602086016A04190822F00F000F0C7
+:1009D0000120CD93BA9E007000F041900070CB973B
+:1009E00000F00140CA9700F0F241DD8F0602086076
+:1009F0000FA000F0803408D006020C600DA0C62FB6
+:100A0000100B80D20190C5230240B69F007000F009
+:100A10004D99007009D41240224040E600F0007069
+:100A200008D000F0E8010F6000F000708DAF00F01A
+:100A30000070D1AE1602096008AFF8010E6027AF52
+:100A400000F0421480D200F00070398000F0007095
+:100A500008D000F08D10086000F0B31F80D000F0C7
+:100A600028020860B683FF7F076000F0063700F0B9
+:100A700000F0873200F000F0863500F0BE9F872F2F
+:100A800000F000F0863400F000F0073300F000F0D2
+:100A9000072E00F000F0063400F000F0873308D095
+:100AA00028020E60F1AF4190E32F00F000F0E13C2E
+:100AB00009D000F0633308D000F0280208600090ED
+:100AC000007000F000F00035EE9300F0007008D0E8
+:100AD00000F028020E6000F0D148066049D0613D68
+:100AE00000F000F0623E00F070A0E23300F011AAC6
+:100AF000007000F000F0E13D08D089D39D10076040
+:100B000009D528020E607980CE04066092D3E137C1
+:100B100000F012D5E52F00F0BA80ED2700F000F0CC
+:100B2000E23700F000F0542100F000F0D220EC2772
+:100B3000A6815120E43FA681C221623F6583E13E48
+:100B400000F000F0643300E600F0623000F000F0E6
+:100B5000E63008D000F0642500F000F0E52100F058
+:100B60000491E42000F000F0EC210894648F6523E8
+:100B700000F0CE040C6000E27D9F007000F00040A9
+:100B80004020C0EB00F0401000F065334120C0EB86
+:100B900001404110C0E100F0EC3108D001400040BC
+:100BA00008D0028928020E600B89007000F09A8C30
+:100BB000E62DC4AF928DE42500F0938FE52C00F074
+:100BC0001C81623600F04591E43500F000F0E32628
+:100BD00009D000F06727EAAFD48E652400F000F05A
+:100BE000E03704908390E02E00F0FC82E52F00F0C7
+:100BF00000A3007000F000F0E03400F07D9F64205E
+:100C000000F000F0E0240198055865340480B887AE
+:100C1000FFFF056020A2007000F0288A007000F03D
+:100C2000C391E0340558C781E33600F07F9F007020
+:100C300040E1DF8B602F00F0BD8F673703583DCC5C
+:100C4000E2220194FD9E66370B807FC1B786046067
+:100C500076C1A3B50360E5A3007000F05D811B8041
+:100C60000360ECA3007000F0E482007000F028A1A3
+:100C7000007000F014AA007000F030A1FF7F036044
+:100C800015AA007000F0C590007040E155836532F0
+:100C900000F02DA2E02700F05581007000F028A29E
+:100CA000E53200F069A2007008D0008228020F60CF
+:100CB00000F064060E6000F0712100F000F0F323F4
+:100CC00000F0799EE22200F0FB9E713109DC00F019
+:100CD0007231029800F0F03500F000F0F33308D0E4
+:100CE00000F0F42500F0399E732E00F0049100709E
+:100CF00000F0FB9EF13309D000F0F33300F0F03543
+:100D0000BB0A80D0A1406902086096000260E4A19D
+:100D10008130444651A301306B0209602233A54063
+:100D200000F02434A64000F0A533FF7F076026368C
+:100D3000C8000060A732014500F04032024000F0D8
+:100D4000C132007000F02237E8030360A237670267
+:100D5000086093309001046013308116096084307C
+:100D600008000560023066080660D532007000F0A9
+:100D70008F90963000F0B733163000F000F0323725
+:100D800008D069020860D0A100F0731580D26B0210
+:100D9000086000F000F0731580D0690208603EA37F
+:100DA0008230771580D0690209603CA300F0902062
+:100DB0003BA300F0003008D000F0791580D0450248
+:100DC0000A6000F0690208602BA300F0202A00F0FE
+:100DD00000F0022000F000F0A12900F082906A15D6
+:100DE00080D06B02086000F0D41B006000F000F0BF
+:100DF000022000F08303016000F082906A1580D029
+:100E000000F01B1E80D245020A6034A200F0007080
+:100E100056A2000400606FA200F00070B7815B0969
+:100E2000086020A3801608602183801608601EA336
+:100E300000F000701E82439045020A60008000604E
+:100E400000F000F0C70480D3C190007008D04502C4
+:100E50000A6000F0008000605FA2DF02026009D03B
+:100E60004F02036000F000F0A23900F000F0233AD6
+:100E700008D01140361680D20090007000F04090EB
+:100E80000070C0E00090007008D000F08A160E607C
+:100E90000082007000F000F0603100F000F060327D
+:100EA00000F000F0E03100F0F400006000F04502D6
+:100EB0000A60B9A1213C10401BA274020060D48FCB
+:100EC00045020A600DA300F0202CC7A100F0A13C50
+:100ED0000CA278020060D08F45020A603DA2720227
+:100EE0000B603DA24040FF0402601340214055A228
+:100EF0007D020060CB8F00F00070F0A1A02F8A1659
+:100F00000E6000F0212000F000F0E03200F000F070
+:100F1000613300F0830200607A8345020A60FEA21A
+:100F2000A02F8A160E602120007000F000F06030C3
+:100F300000F000F0E13000F089020060788300F0FA
+:100F40001B1E80D200F00070FFA1D41B0560F2A22E
+:100F50000008006037A200F0A02EEDA100F06902A9
+:100F60000860A539731580D200F0B40A80D28205DA
+:100F70000060B68F00F000707DA100F00070FC8F63
+:100F80000004016000F053020860E4A208C200708F
+:100F900000F0088E007008D000F0361680D2009065
+:100FA00045020A60F400006009D40004006028A231
+:100FB00000F0681380D2F400006000F000F00070D0
+:100FC0008CA100F0213CE3A1A1020060A78F4502A3
+:100FD0000A60E0A200F0202C9AA100F0701B80D2E1
+:100FE0000090A70202600988007040E18090A13C57
+:100FF000A18F00F07B1380D245020A6009D000F077
+:101000006E1380D272020B600CA28040FF0402605B
+:101010001340114024A2F802006000F04702016072
+:10102000358200F0721380D2B1020060978F4502C2
+:101030000A60D8A100F0771380D20004006013A2E8
+:1010400082050060938F00F08A160E6000820070A7
+:1010500000F000F0603100F000F0603200F000F0CD
+:10106000E03100F000F00070F5A1045431000060A0
+:1010700045020A6088A10091A13CD8A100F020405F
+:101080008DA200F03040A5A2C1020060878F044607
+:10109000CFFF006045020A6082A10091213DE4A1DA
+:1010A000C5020060838F87900060E1A145020A605D
+:1010B000F0A100820070F8A14040130502600340D7
+:1010C000114007A2CB0200607D8F00F00070A2A14A
+:1010D000A02F8A160E6000F0212000F000F0E03210
+:1010E00000F000F0613300F0D10200602D83450272
+:1010F0000A60B0A2A02F8A160E602120007000F0B6
+:1011000000F0603000F000F0E13000F0D702006045
+:101110002B8300F01B1E80D200F045020A600008FD
+:101120000060EDA100400060ECA100800060E8A13B
+:1011300000F0A02E9EA100F0B40A80D282050060CB
+:10114000698F45020A60D0A12026DA0F80D2E20220
+:101150000060668F00F045020A6000F09D1B80D29F
+:1011600000F0A03C00F00041F70402600340114091
+:10117000EAA100F0E902006047020160FB8145023C
+:101180000A6098A200F0A02209A000F0222396A2F3
+:10119000878EA32700F0580300605A930040006038
+:1011A000D3A1C39000700290550300605797004090
+:1011B0000060D5A140000060D4A1FB020060548F04
+:1011C00000F021218DA20882007000F000890070DB
+:1011D00000F000F0203508D045020A6089A2FF7FA8
+:1011E0000060FAAF00F00070F78F8D1608607EA2E5
+:1011F000089000707FA200F05B09086000F04502D3
+:101200000A6000F0002000F0B683A12600F0F74746
+:10121000252500F00880A03400F0328C80000660A4
+:10122000BA8AA53500F086C3023000F000F0090349
+:10123000006047020160DC91120300603F8F4502AD
+:101240000A6000F000080060B7A1FF7F006000E6C0
+:1012500000F0A02200E200F0212174A208820070B8
+:1012600000F00089007000F000F0203500F012035B
+:101270000060368F45020A606FA2222500080060D8
+:1012800000F0A325ADA100F0A52609909F8EA42310
+:101290006BA2A78E00700390AF0200602F974000F2
+:1012A0000060ADA1FB0200602D8F40000060A6A190
+:1012B0002D8800700D9000F000700FA0AF0200604C
+:1012C000298F9F8E242462A2A78E0070039055035D
+:1012D0000060269740000060A4A1FB020060248FFC
+:1012E000400000609DA12D8800700490F40103600F
+:1012F00006A000F0A33700F0004000609BA155035A
+:1013000000601E8F00F0A53602A04000006098A18A
+:10131000FB0200601B8F00F045020A6000F05B09D1
+:10132000086000F0A02400F000F0A12500F000F01B
+:10133000003000F000F0213508D000F000704AA223
+:1013400000F04130378245020A604CA22026DA0FB5
+:1013500080D238030060108FCFFF006000F045029C
+:101360000A60F1A00082213C85A13C0300600C8F43
+:1013700045020A6045A200F0202CFFA0A13C0040DD
+:101380004FA100F0007043A141030060078F00F0FF
+:1013900045020A600041FF040260034011408DA134
+:1013A00000F046030060580201609E8100F01B1EA1
+:1013B00080D200F0007042A100F0007023A200F083
+:1013C000402010A200F0204001A200F000544AA1E9
+:1013D0004F03006035A200F0A03A00F05A0300600D
+:1013E000F98EDF0200602EA2A0396902086000F0C9
+:1013F000007062A100F0731580D200F0B60A80D2AE
+:1014000082050060F38E5A03006028A25803016031
+:101410002BA200F0A13AF08E45020A605BA1202ABF
+:10142000791580D045020A6000F0800300606BA14E
+:101430005D030060EB8E45020A6000F00041F70496
+:1014400002600340114071A100F062030060570286
+:101450000160828100F000701BA200F0C12000F04A
+:1014600000F042211DA2538220251CA21B89A03519
+:1014700000F000F02335BD8200F03040E3A100F021
+:10148000F040FBA1FF7F00602BA1839000603BA197
+:1014900000F0A04700F000F00070E1A000F0701B29
+:1014A00080D20090007000F00988007040E1409008
+:1014B00000704EA140D800700BA20040A03C28A1B3
+:1014C00000F0007028A176030060D28E45020A6009
+:1014D00040A10042F70402601340114058A17A0372
+:1014E00000600A8300F01B1E80D2004000601AA139
+:1014F000879000602AA14F02006000A2203A0240BB
+:1015000000F0014069020860D231731580D200F00A
+:10151000B50A80D282050060C58E00F09D1B80D286
+:1015200040D80070F9A100F0A03C2AA1839000608F
+:1015300020A1F040DA0F80D200F0F704026000F042
+:10154000800000601340114046A15F02016000F07E
+:101550008D030060578100F00070F0A191030460DA
+:1015600003A30091910680D593030060B78E5E02BD
+:101570000160ECA19303006051818790006013A18A
+:1015800000F000701FA1D41B0060B28E00F000704C
+:1015900019A100F00070D6A000F0A02F00F000F01C
+:1015A0002120E8A108840070E0A09C030060AC8EBC
+:1015B000839000600AA100F02040AEA100F0F0404E
+:1015C000C6A100F0007017A1A1030060A78E00F073
+:1015D0009D1B80D201900070DBA10082A13C1CA168
+:1015E00008900070A1A100F0405002A100F0F0406E
+:1015F00000F000F001407CA080400905026013402B
+:10160000114027A1AC03006000F06702016038813F
+:101610000082007099A100F0007006A100F0BC0AE1
+:1016200080D282050060988E67020860D1A100F028
+:10163000002000F000F08120CFA1408E007008D083
+:1016400072020B60CDA100F0B123CCA14190450204
+:101650000A60389E00700B9000F000700594F34013
+:10166000007068A0C090014069A00010006008A14F
+:1016700000F01040D1A0C70300608A8E00F0007017
+:1016800063A00082014064A00010006006A100F089
+:101690000040CCA0C7030060858E0140FF7F006042
+:1016A00000F0660D80D200F0690D80D200F000706D
+:1016B0001F80F400006000F045020A6060A04090C6
+:1016C000213C73A01040A13CC7A0CC0300607C8EDD
+:1016D0000040DA0F80D245020A60B5A072020B60AA
+:1016E00000F00082FF0402602340114000A1D203F9
+:1016F0000060768E45020A6000F000100060EEA0E7
+:101700001040007002907B02016000F0DA0300607C
+:101710000D8100F000706EA17D02016000F0DC031D
+:1017200000600A8131010260A3A100F0B0240380AF
+:101730000082007069A1A4040260A0A100F0B0259D
+:10174000008000F0007071A000F0660D80D200F003
+:1017500000707FA000F0690D80D200F00070A6A09C
+:1017600000F000703BA000F01B1E80D200F0BC0A0D
+:1017700080D282050060608E00F0007095A100F0BC
+:10178000302400F000F0B1247CA000F0303600F0EE
+:1017900000F0B13600F000F0302500F000F0B12587
+:1017A00078A000F0303700F000F0B13708D0029098
+:1017B000007006A0BA9EF206046031253124C0E212
+:1017C0001E41046000E632273226C0E2B327B3266A
+:1017D000C0E200F00070598000F08C1B80D20190B4
+:1017E000941B80D209807805006000F072020B60C3
+:1017F0004082007008D000F00070FAAF00F0312491
+:1018000000F000F0322600F000F0B3266080800285
+:10181000086078A10090007008D0720208607EA174
+:1018200000F0802400F000F0812500F000F000348A
+:1018300000F000F0013508D000F0007000F0A03B8F
+:101840000B04006000F0213B3D8E45020A6076A14A
+:1018500000F0A12B75A1799E202B00F000F0A13B98
+:1018600009D400F00070388E00F045020A60D41BE5
+:10187000006070A100F0A03900F000F0203A08D01C
+:10188000E54F41090860399E5509096042402240F0
+:10189000C0E20320F9FF016016400640C0E2CBC25F
+:1018A000142000F0D3C4007000F02CC3007000F0CE
+:1018B00034C5033000F000F0143008D000F00070A0
+:1018C00003A000F00070008050405509086000F04F
+:1018D0000070A88050405509086000F00070A98091
+:1018E00002D15309086008FF03601DA118C20070EF
+:1018F00000F010C4007000F008C400706080039015
+:10190000007000F0008200700180039000700BA056
+:101910000289991B80D29A80007000F012894008D9
+:10192000086016CC0209016092C1007000F080D7F7
+:10193000023000F000F0803000F000F0813112C081
+:1019400000F0007000F0969D01214CA189C100704B
+:1019500008D000F0441E80D278A0007000F031A0C2
+:10196000411E80D27AA0007000F032A0007000F01A
+:1019700070AA0070458101524008086003CC02093A
+:101980000260C0C0813000F000F0003000F000F0D4
+:10199000823112C000F0007000F0FB9C01213EA1DA
+:1019A000C9C0007008D002900070F1AF1280991B7E
+:1019B00080D2D2D04008086080D7007000F000F0DC
+:1019C0000209016000F0823000F000F0003000F009
+:1019D00000F0813112C000F0007000F000F0012131
+:1019E0003381C2D8991B80D240080860F78F400825
+:1019F00008600CA000F04008086005CC007000F002
+:101A000040C9007000F026CC007000F0A2C9007040
+:101A100000F0818E007000F000F000700294D2DFC0
+:101A2000007000F0BE9F007000F000F00070EDAF9D
+:101A30004090007000F07183007008D010A000701A
+:101A400000F0C8AE007000F00880007008D0B849FF
+:101A50000460FCAF20A0534000F000A8007000F02C
+:101A600000CC007000F0C182007000F008AE007081
+:101A700008D063403C5602604082007000F010A025
+:101A8000007000F000A8007000F000CC007000F0C2
+:101A9000C182007000F008AE007008D062408C1B5C
+:101AA00080D20190941B80D208808360016080D72F
+:101AB000208F036014403402056045020A6008A0CC
+:101AC0002630B35901605240059803600440F40089
+:101AD000056000F0374004A0B881A63F00F0A03DAB
+:101AE00072020B6000F0203E08D05B0908600C8099
+:101AF00000A0007000F08EAE007000F08EA30070A9
+:101B000000F018A0007000F009AF007000F08E81A6
+:101B1000007000F0AE81007008D0A040500908604D
+:101B200000F0007045A000407009086000F00070EF
+:101B300043805A09086000F000F0007000F000F0E7
+:101B4000003008D0A0405009086000F0007041A0AB
+:101B500000407009086000F000703F8000F07009DC
+:101B60000860389E0100006000F00070399000F0BD
+:101B700000703B8000F070090860389E0200006031
+:101B800000F00070359000F0007037809608086013
+:101B9000F1AF97080860F0AF98080860EFAF9908B8
+:101BA0000860EE8F96080860E7A000F00020E6804D
+:101BB0009A08086001809B080860008041D00258A4
+:101BC000A4A0C9D7007000F010C2007000F008C4D3
+:101BD0000070E78F9A08086001809B080860008009
+:101BE00000F000709EA040D0007000F0C0DF0070D8
+:101BF00008D0E8080860E08F9C080860DFAF9D0807
+:101C00000860DE8F00F09208086000F0004021A01C
+:101C100000F0F0401D8000F09208086000F0F040F5
+:101C20001EA000F000401A80BC070060D1A041094E
+:101C30000860D6AF0000006061AF2740C60780D0C3
+:101C40000082007000F041090860D28F0041D90F76
+:101C500080D00041DA0F80D000F0B12FC9A04290AF
+:101C6000007000F07A9E0070039000F00070039006
+:101C700000F0007001A0008800700180C3080860B7
+:101C8000C98FC7080860C88F93080860C78F950878
+:101C90000860C68F00F02127BFA041C2007008D0A5
+:101CA00000F02127BDA041C4007000F000F02137F2
+:101CB00008D000F0007000F000CA2127B9A041C28E
+:101CC0000070FC8F12400120B7A012C0007000F01D
+:101CD00050C40070BC8F12400120B4A012C000702C
+:101CE00000F012CA007000F050C20070B88F72028B
+:101CF0000B60B0A000F0B03D00F000F0B13F00F08C
+:101D000000F0B23100F000F0333008D0928233207E
+:101D1000ABA0C090FF7F01608116096008B4F09EFF
+:101D2000323E00F000F0B23E029000F0323F00F090
+:101D300000F0B13008D092313C000060113444050D
+:101D4000016010310020006000F09132E68F00F059
+:101D50009B1B80D2C0D7007000F04182007008D079
+:101D600072020B6000F000F00070008000F0B22101
+:101D70009BA000F0007000F000F0007020D0720214
+:101D80000B6098A030314802016000F0202E8FAF28
+:101D9000ED040060F98F4902016090A000F0232E4D
+:101DA00000F000F0A42092A0E08200708AAFF2045C
+:101DB0000060F48F470201608BA000F0232E00F03A
+:101DC00000F0A4208DA0E080322185AF80900070CB
+:101DD000EF8F3032FB04046000F0B132DDAF00F071
+:101DE000A02CBEAF019160400D8F72020B602AA043
+:101DF0000190B82209D000F0302200F000F001304C
+:101E0000498D00F0303200F000F0B132D5AF00F073
+:101E1000A02CB6AF00F0202C84AF0505016000F0C7
+:101E200000F03040038F72020B6020A000F0B92256
+:101E300009D00490302200F000F014303F8D00F003
+:101E4000303200F000F0B132CBAF00F0A02CB5AFD3
+:101E500000F0A02CABAF00F000709CAF0F0501604C
+:101E60000A8072020B6016A00490B92209D000F01B
+:101E700033229BAFC0901430358D00F0303200F02B
+:101E800000F0B132C1AF00F0A02CABAF00F0A02C3D
+:101E9000A1AF00F0007092AF1A05016000F00600DB
+:101EA0000060EE8E72020B600BA00490B92209D084
+:101EB00000F0202DA4AF00F0202D9AAF00F01430D8
+:101EC000B7AF20050160F98F72020B6005A0049086
+:101ED000B92209D000F033228AAF00F010205EA0B2
+:101EE0002484007000F0C0901430228D45020A60F6
+:101EF00012A0759F78020960811608600D9008A2F3
+:101F0000B32E174010A0342E0558D9A1362F00F05B
+:101F100062A1B72D00F08E91FF7F0560BE83363F32
+:101F200000F003A800700390F4A8333E00F02CC327
+:101F3000007000F09282B43E08D039CC124000F01C
+:101F400048AE007000F08290007008D03033720FFD
+:101F500080D2002000608AAF00F0802108D02240AB
+:101F6000B32F48A0C490B12000F0FC9E352004900F
+:101F700000F00070049000F0007002A00390007068
+:101F800002A01884007008D0E30808600180EB0804
+:101F90000860008000F0007000F000F000203E803B
+:101FA00000F045020A60002000607E8F0190420927
+:101FB0000860FFFE0260FBAF10C2125000F04190BB
+:101FC000007000F010C40070C0E000F000703D8FA1
+:101FD0005C09086035A000F0012034A089D70070AA
+:101FE00000F089D0007000F008C4007000F000F02C
+:101FF000003008D05C0908602FA000F000202EA05F
+:1020000080D3007000F080D4007008D000F0007021
+:10201000FBAF08900070F48F00F00070F9AF389EAD
+:102020000070F28F00F0414600F0DB82124000F0B9
+:102030000982A14600F083903240C0E10982014745
+:1020400000F083907240C0E10982614700F0839004
+:10205000F240C0E10982007000F083900070C0E19E
+:10206000C090007000805D090860228F5D090860E3
+:10207000DB8F5D090860DAAF40D0007000F0089097
+:1020800000701E8F5D090860D7AFC0D700701C8F2D
+:102090003642007011A0C0211157076041205555EC
+:1020A00005603882007000F07182007000F048A175
+:1020B000007000F092AA007000F08280007000F0C2
+:1020C00000F0A23200F000F0C23008D000F0A027EB
+:1020D0000BA0389E007000F000F0A03700EE00F07A
+:1020E000007008D000F0007000F000F000200680C2
+:1020F00000F0007000F000F0003008D045020A60E7
+:1021000000F072020B6000F055020C6000F05B0200
+:102110000D60008000F0007008D045020A60FEAF3C
+:102120008A160E60FDAF00F06221FCAF8A90632238
+:10213000FBAFCB9010403AAF63326231C0E200F0A7
+:10214000222200F0A3218305076000F0242F69A05C
+:102150004090007068A000900070059C0EC4007054
+:1021600004980E8000701B9000F00070259800F01D
+:102170000070599000F000702D800E80007000F00B
+:1021800000F00070029000F00070059800F0007000
+:102190000C8000F0007059A04190007000F000F039
+:1021A0000070039800F000700A8000F0007055A0E5
+:1021B0000188007000F08A80A13600F09A8CA1217D
+:1021C00000F08082242200F0188C2131DAAEA43194
+:1021D00049020160C091223E418F00F000704DA085
+:1021E0000190007000F08A80A13600F0A28AA1213F
+:1021F00000F08080232100F0208A2132D2AEA3316A
+:1022000047020160C091223E398FA2260070D6AFEE
+:102210008290007000F000F0222E049800F023203D
+:10222000D3AF9A82007000F000F00070F29B00F0D3
+:1022300000701E8000F0A32FCFAFD282007000F09C
+:1022400000F00070E69B00F0007011804040222EEC
+:102250000DAF223020400AAFB89EA32F049400F0A7
+:102260000070E19F00F0104007AF00F00070019493
+:1022700000F000700A8000F0007000F09A84007096
+:1022800000F000F0A23E34802040232E03AFA33F95
+:10229000404000AFF89E2220FA9700F00070DF9FC8
+:1022A00000F01040FDAE00F00070F79700F00070F5
+:1022B000098000F0007029A000F04040F9AEB89EFF
+:1022C0000070049400F08040F9AE00F00041F6AEDA
+:1022D00000F0A52F179000F000700B8000F0222076
+:1022E000CC9F00F0A33FED8F00F0007020A000F025
+:1022F0002040F0AEA0820070049400F00041F0AEE7
+:1023000000F08040EDAE00F0A52F0E9000F00070C0
+:1023100002800291A32FCB9B00F02230E48F00F0CB
+:10232000262000F04591007000F0A6830070039411
+:1023300000F000700294A52D0042E6AE00F0A53E2C
+:102340001580A5208040E7AE24300041E6AE00F0C5
+:10235000A33F00F0A536007000F0C091253E058F28
+:10236000A2261040DDAE8290007003941288A52D45
+:1023700000F0A236007000F0C091253E008F00F002
+:102380000070B99B00F00070B08F00F0007005A0E5
+:102390008182A23E00F0CB8C007000F08180A33FD0
+:1023A00000F0648A007000F000F0243003800340E5
+:1023B000A02000F0F447A12600F000F0222E8E8F1E
+:1023C00000F0A02A538CD582014000F02E890070C5
+:1023D00000F03683007000F0D5820070029C799E78
+:1023E000007001985190007000F0C290007000F0F1
+:1023F0007E9E232108D014000260018096000260B6
+:10240000008000F0A03A1EA083050060E88E0A005C
+:102410000260018005000260008000F0A03A1FA069
+:1024200000F0A02F00F000F021207CAF4282A52E0A
+:1024300000F0A39E0070039000F00070039800F07D
+:10244000253E00F083050060DE8E00F0A03EE88FA0
+:102450001080223100F000F002406DAEA231460241
+:10246000016010060060D48E45020A6071AF00F072
+:10247000242100F000F0A62F00F000F0A22000F0D0
+:10248000A581A3216DAFD08E007000F000F0A231C5
+:1024900000E63C9F253200E600F024310398A0813D
+:1024A000007061AE00F04602016010060060C88E48
+:1024B00000F0252265AF00F0A53ED68F00F0304039
+:1024C00000F000F0223F00F000F0A03000F000F03B
+:1024D000A03600F03F000060A48E00F01040FBAF7B
+:1024E000104000709F8E8F8E442200F000F0C522B5
+:1024F0001490E78E007000F0CD7C06600A94800096
+:10250000006098AECD7C0660089400F0007026AFA5
+:102510002F9E007039AF0F9CA4252C98CD7C0660AF
+:10252000389800F000706AAE3782007000F0A54E57
+:102530000660439800F000705080EF8E007066AE29
+:10254000378200704D94A54E06603F9800F00070F1
+:102550001BAF2F9E00702EAF0F9C0070479400F0B1
+:102560000070469400F000704880E78E007000F024
+:10257000330306600A948000006084AE3303066073
+:1025800008946D83007012AF478F007025AF478F9E
+:10259000A4250D9433030660209400F0007056AE1D
+:1025A000878F007000F0A54E0660259400F0007043
+:1025B0003C80EF8E007052AE878F00703994A54E2C
+:1025C0000660219400F0007007AF079000701AAF0A
+:1025D00007900070339400F00070329400F00070A7
+:1025E00034800002006072AEE78E0070049000F04C
+:1025F000007006B38000006071AE0003006073AE2F
+:1026000000F00070038000F0007002AF0001006075
+:102610006DAE00F00070008000F000543DAE5D0330
+:102620000060EE8B0001006067AEE78E00700490E2
+:1026300000F00070F9B28000006066AE0003006038
+:1026400068AE00F00070F88F00F00070F5AE000288
+:10265000006062AE00F00070F58F00F0007006AF11
+:1026600000F02040E7AE0001006061AE00F00070B5
+:10267000F18F00F00070FFAE00F01040E3AE0002FA
+:1026800000605DAE00F00070ED8F00F05501076056
+:10269000000100605AAEDB8B007000F0F0A000700B
+:1026A00000F043AA00702AAEC3A23303066018826A
+:1026B000007000F0808D007023AE8000006050AE8E
+:1026C0005D030060D38B00F05501076000020060DD
+:1026D00050AEDB8B007000F0F0A0007000F043AA59
+:1026E000007020AEC3A2FF7F06601880007000F06B
+:1026F0008091007040E100F0007018AE8000006032
+:1027000045AE5D030060C88B8000006046AE00F0FF
+:102710000070D68F0040006044AE00F0A02AC48B49
+:102720009A08086000F0A03A8706006000F0414176
+:1027300010804141890600609B0808600E80A1401E
+:102740008B0600609A0808600C80A1408D0600602E
+:102750009B0808600A8031408F0600609A08086074
+:1027600008809B080860EEAE3140A02A068000F089
+:10277000A03AF78F00F0512200F000F0D221EEAE27
+:102780008982D32200F00989007000F0C88E0070A1
+:1027900008D000F00070E6AED0359C0603605130E2
+:1027A0006402016000F0D83009AEC0905031488E0C
+:1027B00045020A601FA01080007022A000F0610294
+:1027C0000160A0060060448E45020A601BA01082D2
+:1027D00000701EA000F062020160A4060060408E3E
+:1027E00000F0007017A0F44FD12300F0168253239D
+:1027F000DBAE5D82007000F000F000700298C190C6
+:10280000144000F01680007000F000F0513400F029
+:1028100080915435F1AD5B020D60D4AE00F0D8204C
+:10282000F5ADD124FF3F0560045C5224D1AE89820E
+:10283000532000F000F05125059CD23445020A6077
+:1028400000F000700DA000F000700AA063020160AB
+:1028500000F0AD0600602C8E00F0007000F00988DA
+:10286000007008A000F0007005A000F0D0258C8B4F
+:102870005B020D60C5AE502100C004605220FF3FD6
+:10288000056000F0D82008D0208C007000F0288A65
+:102890000070DC8D4190007000F01B88007040E1FA
+:1028A0001880007008D000F0AD10086000F0B31F71
+:1028B00080D200F0007081A0008292020B60820240
+:1028C000096008A010329B020B60DB07086006A0BD
+:1028D0009032A4020B60072088090A608802086011
+:1028E00097A0C8090A6002A08D02086095A000F0B8
+:1028F0001120028000F0B03300F000F0303408D036
+:10290000845182020960FB9F410908600240113036
+:1029100009D47B9E002000F0739E324000E26B9E43
+:10292000224000E224CA124000E220C279090A6073
+:10293000D3D2007000F018C4223000F000F0003054
+:1029400008D092020A60C5A0A13000706B809B0283
+:102950000A60C3A0A1300070698092020A60C1A021
+:102960002131007067809B020A60BFA02131007096
+:102970006580A4020A60BDA02131007063809202CC
+:102980000A600280A4020A6001809B020A60008043
+:102990004190124000F001401140C0E200F0007090
+:1029A0000780BD9F92020A609282007040E000F0B2
+:1029B000007004809282A4020A6000F0007002801D
+:1029C00092829B020A6000F00070008000F0820298
+:1029D0000860FE9F007000F082908321059406211C
+:1029E0008620C0E2D3C4007000F04190007000F077
+:1029F00036888331C0E000F0263208D09282FF7F13
+:102A000006604190223200F0B6838231C0E000F0CF
+:102A1000A63108D000F0820208609202096008A086
+:102A20009B02096007A0A402096006A000F08521AE
+:102A300010A09202096014A09B02096013A0A402D6
+:102A4000096012A00082007009D08031B30A80D0E2
+:102A500000F0032200F000F0922100F000F0942238
+:102A600000F09EA2172300F034A3007000F0F7A33B
+:102A7000862200F020A0007000F014AA007000F080
+:102A800078B0943300F014BA007000F000F0143401
+:102A900008D0F380FF7F04600082033209DC869156
+:102AA000803200F000910070C0E10032B20A80D0A4
+:102AB0000082FF7F046000F0172287A0C791922157
+:102AC00086A0BA8000700590C7910070039C0191A8
+:102AD0000070C0E14982103240E14591913108D047
+:102AE0006D83923108D04591007008D08202096050
+:102AF0007EA000F0962000F000F09B1B80D286A301
+:102B0000007000F000F0963208D08202096079A0CF
+:102B100000F01621FB8F8202096077A000F096205A
+:102B200000F000F0007000F036880070F78F82022D
+:102B3000096073A000F01621FC8F840306600180F9
+:102B40005A00066000F0820208606FA000F00631B3
+:102B500008D0AD020C606DA04822A6080A60C92208
+:102B6000A7080B600020007000F01120007000F03A
+:102B7000C223007000F0432488090D6080C84423FC
+:102B800000F0C9C8482000F00083C92000F0098384
+:102B9000203000F000F0313002A04821007000F039
+:102BA000C921C8090D6000F0002000F000F01120DC
+:102BB00000F000F0503D00F000F0D13D08D092024E
+:102BC0000A6002A0A4020A6001A09B020A600080C1
+:102BD00000F09B1B80D22121018004602220007024
+:102BE00000F0618CA32000F082A2007000F08E90B3
+:102BF000007000F08F90007000F051A2007000F0A3
+:102C00008E830070C0E19EA3007000F04190A63258
+:102C100000F0CF81007040E1DFA3007000F000F011
+:102C2000273308D000F08802086000F088090A60A5
+:102C300001300070098000F08802086000F0880907
+:102C40000A6081300070068000F08D02086000F09C
+:102C5000C8090A6001300070038000F08D0208602E
+:102C600000F0C8090A60813000700080F49F222CB7
+:102C7000844F00F0032009D0A2C2842000F0C3904A
+:102C8000010801608A900070C0E00491213200F0D8
+:102C90009290A330C0E000F0223C08D017400070B2
+:102CA000008088090E6000F0C8090F6000F000F095
+:102CB000E73F00F000F0F73F08D007400070FB8FBF
+:102CC00088090F6000F08A02096000A000F07723F5
+:102CD00000F000F0F62300F000F0752400F017314A
+:102CE000C8090F6000F0963000F01C72153008D053
+:102CF0008A02096000F088090F6001A0C8090F600E
+:102D000000F000F0172100F01440962000F01C7233
+:102D1000152000F077D7773300F06ED3F6330351E8
+:102D2000F5C5753406525F83034100F0758300706A
+:102D3000019853408340C0EB00F0007000F0DBD1FD
+:102D4000007000F0E3C4007000F000F0733208D0AF
+:102D500088090F6018A00740762100F01440F52183
+:102D6000F3AFC8090F6015A00740762100F01440AA
+:102D7000F521F08F1740602C12A038C2007008D0E7
+:102D800000F088090E6000F0007002A0069000704C
+:102D900001A0318C007008D000F0E521F9AF459119
+:102DA0000070C0E020400070C0E0C8090E6008D08C
+:102DB00088090E6008A000F0E62CF4AF8091007046
+:102DC000019000F0007009D0C8090E6004A000F066
+:102DD000E62CF0AF80910070019000F0007008D0F8
+:102DE000C091007008D000F0007008D0124001407F
+:102DF00003A000F0113100F000F0123000F000F0FC
+:102E0000923008D000826B0008606800096003C03F
+:102E100000F0001000F000F0007008D068000960B9
+:102E200028A01032941B80D24180923100F000F033
+:102E3000102100F000F0913200F0009013090960B9
+:102E400000F0007009D000F0123008D0224040405D
+:102E500020A040C26800096080D7711B80D250C298
+:102E6000124000F0C0D7C00F80D250C2007000F0F6
+:102E700000F0103108D06C00096019A009090A603F
+:102E800082C800F0100017A000F0201000F000F041
+:102E9000007008D06800096014A000F011300280B2
+:102EA0006800096012A000F091300080E24B4109F7
+:102EB0000B60F34B42090C603620007000F0452097
+:102EC000007000F096C3680009605DC3007000F0F8
+:102ED000C49113201240FC9F00700790D3C2007071
+:102EE00002909BD1007000F05DC5007004809420BA
+:102EF000361680D20491134000F0049000700190C7
+:102F00009EC5007040E000F0363000F000F0453023
+:102F100008D000F0007008D0CE1009602D80CF10CE
+:102F200009602C80F81009602B80091109602A8043
+:102F3000421109602980CE1009602880E8100960DC
+:102F400027805F11096026800809086025A0F540E8
+:102F5000062500F000F0022C00F0AEC3D807036095
+:102F6000BE9F007009D014D60070F74150D7007092
+:102F7000159038C2D1070A60C38000701390019E7B
+:102F8000007000F000F00070119C00F0007030D272
+:102F900000F0293000F000F0112000F02020007037
+:102FA00017A02080007000F06182203015A000F092
+:102FB00029200A9800F0812C00F01020FF1F0760E4
+:102FC000022DDB070A6038C2832D00F000F02720B5
+:102FD0000FA000F0042E00D200F008090860009055
+:102FE000007000F000F0003000E600F0007008D043
+:102FF00000F00980006000F08230FA8F0809086054
+:1030000007A08030007000F002310B7F006081313A
+:103010000070F68F00F01240FB8F00F0022C00F0E1
+:103020000980006000F000F0823008D000F00070ED
+:1030300008D0DB070960FEAF11200901006000F035
+:10304000007000F000F0813008D000F0FF1980D24D
+:103050000802006008D000F08E1F80D24982040B65
+:1030600080D200F040090A604982B91F80D200F086
+:10307000213008D000F00070FB8F00F00070EF8F5F
+:10308000A808096000F07F090A6000F000F0040160
+:10309000016000F001800460922014F205601320AA
+:1030A0000800066081300F06006027200D000160D7
+:1030B00000F0023100F000F0043200F03FD285321F
+:1030C00000F0FBC4063300F000F0833100F000F0A4
+:1030D000813308D000F0892CE3AF00F0112000F01C
+:1030E00000F00907006000F0813008D000F0892C62
+:1030F00000F000F00808006000F0123008D000F086
+:103100000070D98F00F00070D88F8090981B80D20B
+:10311000080B006008D04190007000F000F00070D3
+:10312000039000F0330780D200F0DC1580D2080C49
+:10313000006008D000F0340780D200F0DD1580D2A6
+:10314000080C006008D000F0401680D2080D006026
+:1031500008D000F0B60780D2080E006008D000F05A
+:10316000BD0780D20A0F006008D000F0421680D25E
+:103170000810006008D000F01A0B80D200F01E0B7F
+:1031800080D20811006008D000F0471680D20812E3
+:10319000006008D000F0C91F80D20813006008D07A
+:1031A0000814006008D0C091007000F000F00070BA
+:1031B000029400F00B1A80D20815006008D020405D
+:1031C000991F80D20815006008D05B090960BAAF6A
+:1031D00000F01120B9AF00F0813000F00916006056
+:1031E00008D04190007000F000F0430280D308172F
+:1031F000006008D041900C7000F000F0450280D3D0
+:103200000918006008D000F0780080D23002006019
+:1032100008D000F0750080D23003006008D000F0C4
+:10322000720080D23004006008D000F05E0080D2CE
+:103230003005006008D000F0640080D230060060E5
+:1032400008D000F0620180D23007006008D000F0A2
+:103250005F0180D281303208006000F0023108D076
+:1032600000F0590180D23009006008D000F08100E0
+:1032700080D2300A006008D000F05B0180D2300BB1
+:10328000006008D000F0600080D2300D006008D0EF
+:1032900000F0390080D2300E006008D000F06200EB
+:1032A00080D2300F006008D000F00070928F00F0E4
+:1032B000DF0680D21001006008D000F0E30680D263
+:1032C0001002006008D000F0EF0680D2100300600A
+:1032D00008D000F0D40680D21004006008D000F0BE
+:1032E000E90680D21005006008D000F05A0780D2AD
+:1032F0001006006008D000F05D0780D21007006063
+:1033000008D000F0EA0680D21008006008D000F073
+:10331000E10680D21009006008D000F0E50680D2F6
+:10332000100A006008D000F0600780D2100B006027
+:1033300008D000F0630780D2100C006008D000F0C5
+:10334000F40680D2100D006008D000F0EB0680D2A9
+:10335000100E006008D000F0F20680D2100F00605E
+:1033600008D000F0E70680D21010006008D001906D
+:10337000007000F00809086073AF00F0813000F0C1
+:1033800000F0023100F0C091833108D000F0391B09
+:1033900080D200F0007002900140C51680D2180162
+:1033A000006008D018010060638F00F0541B80D2C9
+:1033B0001802006008D000F0770D80D21A03076071
+:1033C000F38F00F0590D80D219040760F08F00F0E0
+:1033D0008C0F80D21805006008D000F06F0D80D2ED
+:1033E0001806006008D000F0910F80D21807006026
+:1033F00008D000F0930F80D21808006008D000F0C9
+:10340000960F80D21809006008D000F0A90F80D272
+:10341000180A006008D000F0AF0F80D2180B0060CF
+:1034200008D000F00070538F00F00070528F00F051
+:10343000B20F80D2180E006008D000F0B40F80D216
+:10344000180F006008D000F0C20F80D21810006082
+:1034500008D000F0C40F80D21811006008D000F02E
+:10346000C60F80D21812006008D000F0C80F80D2BA
+:103470001813006008D000F04A0B80D219140760BE
+:10348000D38F729E007000F000F00070039C00F07B
+:103490004C0B80D200F0691280D21815006008D061
+:1034A00000F04C0B80D200F0651280D2181500603D
+:1034B00008D000F000703B8F00F0500B80D218173E
+:1034C000006008D000F0350B80D2181801603AAFC8
+:1034D0000880007008D000F0440B80D219190760F2
+:1034E000C38F00F0460B80D2181A006008D000F09D
+:1034F0004E0B80D2181B006008D000F0531A80D207
+:10350000181C006008D000F08C1B80D2191D0760C9
+:10351000BA8F00F08D1B80D2181E0060299300F036
+:10352000C51680D200F04B1A80D2181E006008D059
+:103530004090AB1B80D20190C51680D200F04B1A90
+:1035400080D21826006008D000F0551780D200F015
+:103550004D1A80D2181F006008D000F0131880D2D6
+:1035600000F04E1A80D21820006008D000F0B01A87
+:1035700080D21F21006008D000F08D1B80D218225D
+:103580000060189300F0E81880D200F0511A80D241
+:103590001822006008D000F08D1B80D21823006034
+:1035A000139300F0381880D200F04F1A80D21823FD
+:1035B000006008D000F0361880D2192407609D8F73
+:1035C00000F08D1B80D2182500600C93852E6418A6
+:1035D00080D200F0501A80D21825006008D000F088
+:1035E00008090F6000F08C1B80D2F030590D80D29A
+:1035F0007031770D80D200F04A0B80D2F2311C2757
+:10360000006000F0713208D04190007000F000F0CE
+:103610000070029000F0840F80D21828006008D05B
+:1036200000F0880F80D21828006008D000F0C6167D
+:1036300080D21829006008D000F0520B80D2182ADE
+:10364000006008D000F0371880D2182B006008D036
+:1036500000F0590B80D2182C006008D000F05B0BF2
+:1036600080D21A2D0760828F00F0810B80D2182E35
+:10367000006008D000F09A0B80D21E2F006008D0A6
+:1036800000F06D1880D21B3007607C8F00F0ED18C1
+:1036900080D21B3107607A8F08090F60EDAEF12CE4
+:1036A0009E0D80D2F12D970D80D21832006008D087
+:1036B000FE9F311680D200F0007002901040991FDA
+:1036C00080D21833006008D000F04B1A80D2183333
+:1036D000006008D084908D1B80D2469012400A90E2
+:1036E00001918D1B80D230832240089000F0007041
+:1036F0000798C190E54FDEAEE8C2007000F000F020
+:10370000324004948191007000F00291EC1980D253
+:1037100000F0231A80D21834006008D018340060FA
+:10372000CF8E00F0C41A80D21F35006008D000F0A0
+:10373000480B80D21836006008D000F0C40780D251
+:103740001837006008D000F0611780D200F04D1AE1
+:1037500080D21838006008D000F03A1B80D200F008
+:10376000007002900140E51980D22001006008D06D
+:1037700020010060C18E00F0551B80D22002006045
+:1037800008D000F08D1B80D220030060C19200F0B1
+:10379000E51980D200F0751A80D22003006008D0AD
+:1037A00000F0A80180D281302204006000F00231D4
+:1037B00008D000F03C1480D22006006008D000F051
+:1037C000830180D22007006008D000F0880180D2F9
+:1037D0002008006008D000F0C40180D220090060F9
+:1037E00008D000F0E61980D2200A006008D000F06E
+:1037F000A91380D2200B006008D000F008090F60E8
+:1038000000F08C1B80D200F0F03000F0210C006042
+:1038100008D000F0140B80D200F01E0B80D2200DD7
+:10382000006008D000F0CC0180D2200E006008D0EB
+:103830004190007000F00040C80180D700F0040BF8
+:1038400080D200F01E0B80D2200F006008D000F064
+:10385000F71480D200F0813000F02110006008D011
+:1038600000F0FF1480D22011006008D0852E0815CA
+:1038700080D22012006008D000F0051580D22013FD
+:10388000006008D000F0031580D22014006008D03A
+:1038900000F0AE1380D22015006008D000F0D301F4
+:1038A00080D22016006008D000F0C20780D2201716
+:1038B000006008D0852E8D0180D22018006008D0CD
+:1038C00000F000708E8E00F0B01380D2201A0060DD
+:1038D00008D043908C1B80D219808D1B80D2201C75
+:1038E000006007901989007000F0629E00700390DC
+:1038F000529E007004987A9A0070039000F0007055
+:10390000029CC190F01980D2201C006008D0C190A8
+:103910000070808E00F00C1F80D23801006008D04B
+:1039200000F0211F80D23802006008D000F0852E00
+:1039300000F0062F191F80D23803006008D000F075
+:103940009B1B80D2080908607BAE00F0803000F03D
+:103950003904006008D000F0852E00F000F0062F3A
+:1039600000F0872FD41A80D23805006008D000F00C
+:10397000DB1A80D23806006008D03807006008D013
+:103980003808006008D03809006008D000F08D1BAE
+:1039900080D2380A00606A92852EE71980D200F042
+:1039A000761A80D2380A006008D0380B00606AAE00
+:1039B0000030C31F80D20000006008D00082007079
+:1039C00000F00990E9020A60E802086004A000F033
+:1039D000213000F0EB02086002A0EC02086001A0B8
+:1039E00000F0EA02086000F0007000F000F0003023
+:1039F00008D0EA020860BFA049820020BEA0009063
+:103A0000013000F000F0007009D000F0007000D02C
+:103A100000F0D8020F6000F0EA02086000F07026A3
+:103A2000B8A00090AC09096000F07020019000F08F
+:103A3000093000F000F0F12000F000F0722100F0F9
+:103A400000F0F32100F000F0742200F000F0F52205
+:103A500000F000F0762300F000F0F72500F000F011
+:103A6000782400F000F0F92400F000F07F2500F049
+:103A700000F0F72300F000F0007070D0EB02086057
+:103A8000A8A000F00020A7A00890007000F000F0AF
+:103A9000003008D0B6020F60A4A000F0742000F03F
+:103AA0001740F82000F03C9FF32200F000F00020C7
+:103AB00000F0D8A1F12100F00089722140E03C9F84
+:103AC000007000F000A2007040E00882FF7F0760F5
+:103AD00011A0703200F000A8EA020E600880C2094E
+:103AE0000660F3A8F03100F0FBC2663000F000F091
+:103AF000F33208D0BC020F6094A07020EA020E607E
+:103B0000F120D2090D6000F0722100F00BA270319B
+:103B100000F0D4DFF52100F0E382762200F0DB80B4
+:103B2000007000F0EBA2733000F0F3806D3000F015
+:103B300000F0F33208D0C3020F6089A0F22FEA022E
+:103B40000E607320007000F07923007000F0F821FF
+:103B5000007000F07934007000F000F0F42300F001
+:103B600000F0723500F000F0712100F000F000204C
+:103B700000F0F234EF090D604782DD090C6000F0BF
+:103B80006D3000E204916C3000E6D3826D3000E2CB
+:103B9000CB90007000F000F0F33000F000F0F33252
+:103BA00008D0C3020F6077A0F523FD090C607824CC
+:103BB000EA020E60F924007000F0F622007000F0B6
+:103BC0004591772200F00000000840E6BE9F00709B
+:103BD00000F0FF9F1010039045910070FC97F9349E
+:103BE000EF090C6078340070C0E000F0F63200F0AD
+:103BF00000F06C3008D0C3020F6069A0F12F0640BE
+:103C000000F07220007000F07325007000F0F526BF
+:103C1000EA020E60F027FD090D60CC90F63500F049
+:103C2000CF8E763600F09F8E743515940040066076
+:103C300014945784007000F00090007000F0CC9055
+:103C4000007008903C83F72000F02489007000F099
+:103C5000FFD7007000F03C83007000F024890070F2
+:103C600000F03C9F007000F0A4D1007000F000F064
+:103C7000743700F000F0782500F000F0F63500F021
+:103C8000812F0080026003A0007000F08AA0007005
+:103C900000F00090007000F060A00070C0E049AF3C
+:103CA000007000F000F0713600F000F06D3008D0C8
+:103CB000D3020F604AA078201C0A0D607921EA0225
+:103CC0000E6000F0082000F000F0192000F07222D1
+:103CD0000D7C00F06D301D7C00F000F0002000F045
+:103CE00000F0112000F080C8007000F089C8F030AA
+:103CF00000F000F0F13108D0E5020F603EA078201E
+:103D0000280A0760F920EA020F60002089080A608B
+:103D10001120007000F000F0A03000F000F0213120
+:103D200000F000F0773008D01350ADDE006000F0F6
+:103D3000000008600008026005A000F0801608601E
+:103D40008001026003A01350007031A000F00070E9
+:103D500000F200F0007008D0C390BEBA0160BA9EB5
+:103D60000070FBB3FB9E0010FE9700F0813F08D06F
+:103D700000F06308086000F0E702096000206108B5
+:103D80000B609120E9020D60103000040260478E44
+:103D9000332000F000F0903000E69F8E552000F0B8
+:103DA000FFFF006009D04591933000F000F00070F3
+:103DB00009D400F0A61F80D01640EC02096000F084
+:103DC0007808086000F01630008000F0063008D057
+:103DD0000640EC02096000F07808086000F0163038
+:103DE000FC8F16407908086000F00070FA8F0640DA
+:103DF0007908086000F00070F88F16407A080860B3
+:103E000000F00070F68F06407A08086000F000703D
+:103E1000F48F92827B0808608A90007000F010C2D4
+:103E2000012000F08A90007000F051C2007000F094
+:103E300008C4007000F000F0003008D016407B0885
+:103E4000086000F00070EB8F06407B08086000F00F
+:103E50000070E98FEC02096004A01740162003A04F
+:103E6000BE9F78080860C691007040E100F01630EF
+:103E7000E48F00F0007008D000F0551680D000F0FC
+:103E8000551680D000F0551680D000F0551680D021
+:103E90000041991F80D00042991F80D000F0551634
+:103EA00080D000F0007057800044991F80D00040FF
+:103EB0001B1A80D08040991F80D000F0551680D00A
+:103EC0001040991F80D000F02A1680D000F05516BF
+:103ED00080D01050991F80D000F0551680D020500F
+:103EE000991F80D000F0551680D00042991F80D0D5
+:103EF00000826E000E605620007000F0D520603108
+:103F000000F000F0E63100F000F0603200F000F068
+:103F1000E53200F000F0E03008D06E000C6045A003
+:103F200000F0472044A0C783007008D06E000E60E8
+:103F300042A0E020680A0560DB82662100F0389E1E
+:103F4000E72100F000F0633009D800F0612200F0B2
+:103F5000BFC3E22213403CCCE030039452C2770A44
+:103F6000056014CCEC7009D0469000700341658167
+:103F70006E000D60E180FF3F03602488513000F047
+:103F80001BC1007000F09AC3007000F000F06231B5
+:103F900050D06B110D60E48F6D110D60E38F6F11C8
+:103FA0000D60E28F71110D60E18F73110D60E08F74
+:103FB00075110D60DF8F77110D60DE8F79110D6047
+:103FC000DD8F7B110D60DC8F7D110D60DB8F7F112C
+:103FD0000D60DA8F81110D60D98F83110D60D88F3C
+:103FE00085110D60D78F87110D60D68F89110D60F7
+:103FF000D58F70000E60008000F0007000F000F0BF
+:1040000067201FA0BEC5007000F000F0663000F011
+:104010006E000E601CA000F0E6201BA08E910070C8
+:1040200000F000F0E63008D072000E60F78F00401C
+:104030000660F58F00200660F48F04000660F38FA1
+:1040400000100660F28F00100660F18F001006600D
+:10405000F08F20000660EF8F02000660EE8F0800F0
+:104060000660ED8F00010660EC8F00040660F48F9F
+:1040700000080660EA8F00040660E98F000206600F
+:10408000E88F80000660E78F40000660E68F00083A
+:104090000660EE8F00400660ED8F10000660E38F33
+:1040A00001000660E28F00200660EA8F00100660C3
+:1040B000E98F00F08000006000F0991F80D000F0D0
+:1040C000007008D000F0007003A000F00070338092
+:1040D00000F0007001A000F00070358000F000706A
+:1040E00008D000F0007008D000F07B1480D200F0FF
+:1040F000BB1480D200F03B1580D200F0AF0180D21B
+:1041000000F0A11380D200F01B0280D200F00070FA
+:1041100008D0F02074000E6072208B1101606031B5
+:1041200040000060E130193A0160603078000D60B5
+:10413000E131AB110060523128000160D030A63B64
+:1041400000605130007000F0D031007008D077204E
+:10415000D1070960762101050460FFD7FE2000F039
+:10416000BA81E34F00F000F0123000F0F1219B1B08
+:1041700080D2BA9E1D2000F000F01230E6AF0AA2F5
+:104180001C2000F09AC2035400F000F040080960BF
+:10419000D3A2610000F000F0133100F0D3801130A1
+:1041A00000F06100943114C000F0962000F0FF9FF1
+:1041B000133100F0D380113000F06100943100F031
+:1041C00000F0133100F076D0113000F0D38056109B
+:1041D00000F000F046140DC000F0007000F0FF9FEA
+:1041E000007000F000F09620F89700F0007000F0EA
+:1041F00076D0007000F000F0561000F000F0461489
+:1042000008D000F0BF11086000F0B31F80D27C001E
+:104210000960CDAF00F0112011A000F0007008D0AF
+:104220007C000F60CAAF4790713102A000F05D02C0
+:1042300080D200F09F0180D000F042090F603FD291
+:10424000DB070A607620FFFE05602220007000F088
+:10425000AEC3007000F0B59E007000F0BEC50070E7
+:1042600040E000F0763008D042090F60BEAF00F0A9
+:104270007020BDAFC0D1007000F040D4007008D0F5
+:104280007C000960BAAF00F0922000F000F011301D
+:1042900000F08290007000F0518A0070C0E000F0E1
+:1042A000330380D041907C00096092820070C0E0AE
+:1042B00000F0112000F000F09230F68FDB070A606A
+:1042C000B0AF00F02020AFAF309E007000F0104083
+:1042D000991F80D51040771A80D02240FD020960D6
+:1042E0000082114000F01238624100F090310070FD
+:1042F00000F01132007000F09132007000F01033C5
+:10430000007000F0123E00080360123F544000F0BD
+:104310009334A54100F09435A64000F015370070A5
+:1043200000F09636007000F0913700700080008237
+:10433000FD02086000F0007000F08033007000F0B3
+:10434000003B007064810C70FD020F6000F02917C3
+:10435000026000F0F72E00F0F92D007000F0C79118
+:10436000007000F0FF9F004009D000F0F73E00F021
+:10437000F62D007000F000F0100000F096831000A1
+:1043800004C00010100000F00010AB160A6000100E
+:10439000007000F0F93DFA3DC0E200F0604008D046
+:1043A000FD0208605BA000F0812E08D0FD020860CD
+:1043B00059A000F0013E5181FD02086057A000F0B5
+:1043C000013F08D0FD02096055A09123007008D07C
+:1043D000FD02096053A0113800701080FD020960D1
+:1043E00051A09131007008D0FD0209604FA0113238
+:1043F000007008D0FD0209604DA09132007008D015
+:10440000FD0208604BA000F0822F00F00BC200708C
+:1044100000F08CC2007000F0E782007008D0FD024E
+:10442000096046A0113B007008D0FD02096044A05D
+:10443000912B007000F0122C007008D00082FD0259
+:10444000086000F0007000F08033007038A100F0C8
+:1044500000703F8025030E603DA0E72CFD020F6039
+:104460000082662E00F0C791F52900F08691742A2B
+:1044700042944591632D2F950491F0394995C3904D
+:10448000703A889500F0603DE09400F0007008D02C
+:10449000008214030A6000F0FD02086000F0212091
+:1044A00000F000F0003600F000F0803300F049909A
+:1044B000803F00F0003000700EB02130BF0A80D085
+:1044C000C741FD02086000F00070004000F00629BE
+:1044D000114000F0803C2240BEC381333340A79F8F
+:1044E000007000F0879F833A00E2A79D803A00E2C7
+:1044F000879D813A00E2A79B813A00E200F0823A70
+:1045000000E200F0C10A80D200F0C00A80D000F0C2
+:1045100014030B60FF83007005C000F0371000F03B
+:1045200000F0371008D014030A601AA000F026210A
+:1045300000F000F0A02000F0BE81A72200F008905B
+:10454000263100F000F0A030F69388D3262209A08F
+:1045500000F0A531F49390D3007007A000F0A531CE
+:10456000F29398D3007005A000F0A531F093A0D38A
+:10457000007003A000F0A531EE9300F0263200F0A9
+:1045800000F0A73208D040D0A521019CCF91007047
+:1045900008D000F00070019C8E91007008D04D9101
+:1045A000007008D000F014030A6000F009090B60E5
+:1045B00000F0200085C800F0200000F000F030106E
+:1045C00000F000F0301008D000F0007008D001407A
+:1045D0005C08086000010060FDAF8031A008026047
+:1045E0000131007006C000F0007000F082310070F0
+:1045F00000F00131C411086000F0A81F80D025032D
+:104600000A60F6AF00F0A52CF5AF7D9F50080B6057
+:104610006D83224040E100F0A53C09D400F0B230A7
+:10462000B18007585C080860865125030A60802025
+:10463000FD020960812167040D603FC2C54121264A
+:1046400073C2022048905BD500707EA0EB9E36407E
+:104650002740CB90C5411790CB9014260C9000F0CA
+:104660000070019000F0007032800C91007000F03A
+:104670002BC21800076000F014363390FB820070E4
+:1046800000F000F00070319091160F6001A000F072
+:1046900000703080248300701AC000F0741000F0A5
+:1046A00000F0007008D000F0952603400C91172709
+:1046B00000F02D8F143600F036C200700390BE9FBC
+:1046C00000702B9000F00070299000F000702180A5
+:1046D000E78F0070289000F000701E9400F00070CA
+:1046E000258000F0252600F0FF83112400F0459F6F
+:1046F000132500F036C294250A94719E1521089066
+:10470000CB900070079C4591952000F000F0007060
+:1047100002904291007000F0E091007000F01C8F58
+:10472000133500F000F000701D9000F00070128052
+:1047300000F017351B8000F0942700F000F0A12650
+:1047400036400491C54100F036C2242F17902DC287
+:1047500000700494679D007000F0479D00701490F5
+:10476000479B0070139000F0007012900291A425F6
+:1047700000F04090E3FF056020C4007000F0049159
+:10478000007000F028C20070C0E000F000700C80E3
+:1047900000F0133600F0A00804600C80F7411640CA
+:1047A00042A000F000707CAFA00804600980A0085F
+:1047B0000460088029C2007041A0201004600680B7
+:1047C000201004600580F74116403BA000F013352F
+:1047D0007DAF201804600280F741164038A02018F1
+:1047E0000460008000F05C08086000F067040D6061
+:1047F000843125030A6000F09116076000F0A62EB0
+:1048000000F04982007094418E8D007000F0A68BFC
+:10481000D1070F60F781812100F000F0773000F0C0
+:1048200000F0D32000F049D57F2000F0799E55207C
+:1048300000F09BD876200B901B88972400F0F38221
+:10484000007000F0FBA2112400F09B81242600F0F0
+:10485000719E007000F0249F0070059C00F00070B5
+:104860000494C590733000F000F035030F602F887A
+:10487000007000F000F0773000F000F050080B609E
+:104880000082972700F06DD4A12E00F0C79105316A
+:1048900000F04790007017907F984640029400F017
+:1048A000203700F07F98A03700F0479CD02001947B
+:1048B00000F0A63C00F000F000700998469C222011
+:1048C000255036880070F34FADC1007000F0AAC2C9
+:1048D000007000F018C6A427C0E00790007000F038
+:1048E0002CC50070019800F0A43700F000F00070B3
+:1048F00005800790055800F00E8824270398ADC165
+:10490000007000F02CC5007000F000F0243700F0BB
+:1049100000F0844043404190303000F0B430B33078
+:10492000C0E24990007000F000F0A13E08D000F015
+:10493000923800F03FC2963900F000F0173908D0E5
+:10494000B683A136A740C9D73A0C0560C98B8450FD
+:1049500000F04D81A63E00F0A4C2007000F000F00F
+:10496000007050D000F0007000F000F0007000F017
+:1049700000F000708140980105600B8000F000702D
+:10498000C14000F00070068000F000704141B401A9
+:104990000560078000F000704141B40105600580AA
+:1049A00000F000704140FC00056003800491680144
+:1049B000056000F0014100E65003056000E600F0EC
+:1049C000213600F000F0253008D02503096054AFEF
+:1049D0001140902D53AF088C40080E6007CC142274
+:1049E00000F0CD9101400260C0C115310154108C1E
+:1049F000972D00F060300209066000F00070E13091
+:104A000000F0E6310AC02489932216403C83922BA1
+:104A100000F098A1007000F011A1007000F004A84F
+:104A2000007000F03C81FF7F0560F3A8007000F08B
+:104A3000EBC2943D00F000F0933200F000F06021F2
+:104A400041AF00F0903108D0008225030960914108
+:104A5000007000F000F0903500F000F0103300F02E
+:104A600000F0903300F000F0103400F000F0113E40
+:104A700008D025030A6038AF272E50080B6000F0DD
+:104A8000007000F0C791262500F0F899B12109D0F7
+:104A9000B6D2A327069400F0302100F05DC622278D
+:104AA00000F0ADC5203F00F014C6253500F000F041
+:104AB000A43400F00558A13F0280F09D265005580F
+:104AC000FC9D22250398FF99A22400F0EDC10070FF
+:104AD00000F0AAC20070028036C1007000F0B2C2BD
+:104AE000007000F01140A02325AF0090007000F08E
+:104AF000829020230294A1332134C0E200F00070A0
+:104B00000B8045502325069400F0242400F0EBC2CE
+:104B1000354000F004910070029000F000700194A4
+:104B200000F02134018000F0A5350280089000706B
+:104B300000F000F0203300F00082007000F000F080
+:104B4000A03300F000F0202E15AF389E007000F06A
+:104B50000090203E00F01440A02309D435402325C6
+:104B600000F00090212300F0E3C2262C029049902F
+:104B700000700194799EA53500F000F0007000F0FF
+:104B80008F8F213300F000F0007009D000F0A535C0
+:104B900008D000F00070CFAF00F00070CE8F4982D7
+:104BA000AB16096081390D030A6000F0893D00F001
+:104BB00000F0093D00F000F0013A00F000F0813E05
+:104BC00000F000F0213300F000F0013000F000F0C0
+:104BD000813F00F000F0013600F000F0013100529A
+:104BE0008130991F80D08AD7AA0C036000F0007032
+:104BF0003740D380007000F079C2007000F000F000
+:104C0000007030D06196007008D04190007008D0DC
+:104C10006190007008D04192007008D041940070FB
+:104C200008D06192007008D06194007008D041965D
+:104C3000007008D000F0712900F000F0F02800F0BA
+:104C400000F00070F0AF00F0F22A00F000F0334006
+:104C500000F08A90C641742B9AC2007000F0049153
+:104C6000007000F03C9F007005901483007000F00D
+:104C7000248300700394743BC60A80D2F03BC64183
+:104C800000F0713C007000F08EC3007000F0FF83F4
+:104C9000F23A1A943640F73A00F000F0732000F030
+:104CA0008EC3F42F00F0C79000701694FF9E15403D
+:104CB0000290F79E2540049000F000700E9000F0E6
+:104CC000F03F00F07530C50A80D200F0007010800F
+:104CD0002782762100F0F72113400C9486917530DD
+:104CE00000F000F07331019400F0F0300B80C791B8
+:104CF000F32000F03DC2F0300990FBC2007000F0DC
+:104D00005E83007000F000F0C20A80D700F00070EF
+:104D100005802782007000F000F01340019400F03D
+:104D20000070028000F0F03F00F000F0733000F0FF
+:104D300082900D030960BA9E00700390BA9E1622FD
+:104D4000059000F00070099000F096220A8009D2C8
+:104D50001030174000F0113200F000F0F73C08D09E
+:104D600000FF076000F000F0903000F0BEC300705C
+:104D700000F08EC5007000F000F0163208D009D2A5
+:104D8000103100F000F0913208D000FF076000F011
+:104D900000F0903100F0BEC3F42C00F08EC5154039
+:104DA00000400491963200F0753A703AC0E200F08B
+:104DB000007008D0C6410D03096000F00070474143
+:104DC0001122FF00006000F0932200F042C2007048
+:104DD00000F009D6007000F0C4C2007000F01BD6CD
+:104DE000007000F070C2054000F03882007000F0E2
+:104DF0004D91007040E0B0C2007000F03882007049
+:104E000000F04D91007040E0F0C2007000F0388278
+:104E1000007000F04D91007040E030C3007000F071
+:104E20003882762300F04D91007040E08091753417
+:104E3000C641759F0070249400F000700F9870C2F6
+:104E4000354000F03882007000F069C40070C0E0A6
+:104E5000B0C2007000F03882007000F0AAC4007088
+:104E6000C0E0F0C2007000F03882007000F0EBC4C7
+:104E70000070C0E030C3007000F03882762200F08D
+:104E80002CC50070C0E08691007000F017400070E3
+:104E90006E9600F00070148070C2354000F03882C9
+:104EA000007000F069C4007040E0B0C2007000F013
+:104EB0003882007000F0AAC4007040E0F0C20070B8
+:104EC00000F03882007000F0EBC4007040E030C3A6
+:104ED000007000F03882F62200F02CC5007040E02F
+:104EE0008691374000F000F00070069078C20070A4
+:104EF00000F0309E007000F0B8C200700398309E41
+:104F0000007000F000F00070019817400070598E9A
+:104F10000740007058AE09D2007000F05180007058
+:104F200000F01BD2113200F0E380007000F000F0BE
+:104F3000933200F0772D0D030960782D2917026058
+:104F400000F0100000F0D783100004C00010100023
+:104F500000F00010AB160A6000100D030960783DE8
+:104F60007A3DC0E200F0F22E00F000F0732E64AE45
+:104F70009F82742F00F08A901623049C0491F23EC5
+:104F800000F0A782007009D000F0007009D400F092
+:104F9000C30A80D000F0F02D00F08E912917026036
+:104FA0003190163300F01782007000F0F13DFA3DA9
+:104FB000C0E200F0007008D000F000701AA500F008
+:104FC0000070B7A200F000702EA500F0007033A5AD
+:104FD0006D7100603DA00100016021A000F0007033
+:104FE000008000F0007064A079120860BB81E80DB9
+:104FF0000860BA81DA0D0860B98100F06A040860BF
+:1050000000F0690409600020007000F011200070B9
+:1050100022A54990007000D079120860B381840401
+:105020000860008000F09604096000F0802100F024
+:1050300000F0912000F000F01221008008A0007024
+:1050400000F080A9FF7F016040D6007000F088AEBC
+:105050000070029400F00070019800F0007008D019
+:105060004090007008D08D040860F48F96040860AA
+:1050700012A500F0803000F000F0013108D0960455
+:1050800008600FA500F0803100F000F0013208D078
+:10509000960408600CA500F0812100F000F00222C7
+:1050A000EF8F2340124009A58A826B040860CB82EF
+:1050B00000700290951502600290FF7F02600180EF
+:1050C000DF1E0260008000F0007000F000F002308F
+:1050D000748100F0ED03096000F0EE030A60112016
+:1050E000007000F02220007008D010406D040860AD
+:1050F00000F09604096000308D040A6000F0580248
+:1051000002601A30791203602231007000F0A3327D
+:10511000007036A02A0E0860898100826D04086044
+:1051200000F09604096000308404016000F0007013
+:1051300000F01130007033A000F0007039A02A0E8A
+:10514000086082815D040860EEA4003000705F8119
+:10515000A6040860ECA40040022100F000F0012049
+:1051600000F08290007000F04190007009D400F0CF
+:10517000003000F000F0803044B400F00070DB84B8
+:105180001040A604086000F0007000F000F08030CD
+:1051900008D053090E6000F0FFF0066000F0419067
+:1051A000672000F0F0506050C0E2F7C3007000F0DC
+:1051B000C7C5007000F000F0673008D01640A604A4
+:1051C00008604290074000F000F0063100E27A9E4D
+:1051D000873100E200F0073100E2729E873100E281
+:1051E00000F0073100E200F0863100E200F00070CC
+:1051F00008D0A6040860D1A400F0002100F000F05F
+:10520000812100F000F0003200F000F0813208D07F
+:10521000A6040860CCA400F0002200F000F0812277
+:1052200000F000F0003100F000F0813108D04D04B2
+:105230000860C7A400F0003E00F000F0813E08D0F6
+:1052400001406D04096000F0007000F000F01130C2
+:10525000AEA400F00070B784F0404D04086000F088
+:10526000007000F000F0803F158000F0A604096097
+:1052700000F04D04086000F0112100F000F0002F54
+:1052800000F04190007000F000F0C40A80D500F0FA
+:10529000803F08D04D040860B6A400F00020B5A4FB
+:1052A0000080007000F000F0803108D001407404EC
+:1052B000096000F0007000F000F0113208D00040EA
+:1052C0004D04086000F0007000F000F0803708D056
+:1052D0004D040860ACA400F08027AB844403086050
+:1052E000AAA400F0003008D000406D04086000F06F
+:1052F000007000F000F0803008D010406D040860AD
+:105300000140007000F000F0803000F000F08131CA
+:1053100008D000F00070BAA400F05E0B80D200F05C
+:10532000310B80D000828D04086000F03C000260E8
+:105330008031E70D03600231007000F083320070AD
+:1053400000F06D04086099A40020007098A40090FB
+:10535000007000F000F000700194E50D08602881F5
+:105360002A0E0860278100F0E30809608D040860B8
+:105370008B8100F0BC0A80D000F0CA11086000F0F8
+:10538000B31F80D200F0007000A100F03603086067
+:1053900000F00060096000F020600B600930C06020
+:1053A00009608B30007000F00931007000F04B0391
+:1053B0000F6000F0BC00096000F0B8010A6034A082
+:1053C0004D030F6000F0B401096000F0C0010A60F5
+:1053D00031A04F030F6000F0B801096000F0CF0169
+:1053E0000A602EA051030F6000F0C001096000F0B8
+:1053F000D7010A602BA053030F6000F0C8010960B9
+:1054000000F04F210A6028A055030F6000F0D00182
+:10541000096000F05F210A6025A057030F6000F0CB
+:105420004021096000F049030A6022A059030F607F
+:1054300000F05021096000F04A030A601FA00082BA
+:105440004D040F6000F09F00086000F00070F03223
+:1054500000F00070783300F00070F03300F000705E
+:10546000F03700F00070B2AF00829800086000F0E2
+:10547000007008C000F00070001000F09604086092
+:1054800000F08D04096000F084040A60902100702F
+:1054900000F00A30007000F0A031007000F00082CF
+:1054A0006D04086000F0E2412140003020030360F9
+:1054B00000F0813000F000F0033100F07404086067
+:1054C0005AA400F0803300F000F0003400F000F047
+:1054D0000070F2A100F000706CA400F05E0B80D2AE
+:1054E00000826904086000F0007000F000F00030F5
+:1054F00000F02A0E0860E48000F0793000F000F03F
+:10550000FA3008D036030D6057A339030F60E6A0C8
+:1055100003A0A604086003B044030A60002045030A
+:105520000F6022205F040D600090F1200758D32007
+:105530000070539450804D040E60118000707030E4
+:10554000C2A100706526CAB10070F130EAA10070F6
+:10555000E025EAB10070E126C1A100706227C1B167
+:1055600000FF06608CA40070D33FB280007000F092
+:105570008DB400705430B2800070D53000F00070EF
+:10558000623700F0A404086000F038030E60802049
+:10559000E5080A606C20007000F00090007000F0D8
+:1055A00000F0007005902520007087C8252000704D
+:1055B00000F04518007000F0451843030F606C3090
+:1055C0000070C4A000F06D040D6000F05B030F607C
+:1055D000552040080A60782101050460F92137034D
+:1055E0000E607B20007000F04591FC2000F00082EE
+:1055F0000020C0E200F0110000F000F0203000F0C8
+:1056000000F0213182CC45910070A4316D20E20878
+:105610000A6000F0007000F02220007083C8222091
+:10562000007000F05218007000F0521869040A600F
+:105630006D3040080A602220007002C000F0007047
+:1056400000F000828020C0E200F0110000F000F0C5
+:105650000070203000F00070213100F00070202038
+:1056600000F00070A12000F00070301800F0007011
+:10567000411800F000707B3000F00070FC30D1D396
+:10568000007000F091D20070029400F000703E9023
+:1056900000F000704C80B99E007000F049D300709B
+:1056A00000F0A99E00704C90C9D2007000F0999E45
+:1056B00000704D9089D2007000F0899E00704E906D
+:1056C00089D2007000F0A99C00704E9089D20070C1
+:1056D00000F0999C00704E9089D2007000F0899C77
+:1056E00000705F905E040960FEA397200080036055
+:1056F00003A000701121FAA0E208086014AA00E0DB
+:1057000003607A82007087C8D2A00070043014AAA7
+:10571000007000F000F0007004303E030F6092A0B3
+:10572000FD020F6015A400F06D040F6000F070031F
+:105730000860F720740409600140002000F0C69161
+:10574000007000F0FE9FF22102902640732102902B
+:1057500000F07032078000F07132068000F00070B7
+:1057600000F09A80007000F0F131F23140EF80A239
+:10577000F63000EA8290703200EE00F0C40A80DB5E
+:1057800090216F030E6091236D040F6000F0172FBE
+:1057900000F00882142200F03AA2152400F08A805A
+:1057A000903200F02481632000F02C83923300F0CB
+:1057B0003EA3143300F0AE81922400F0C0A2772201
+:1057C00000F080A2163400F0E4A3007000F0268000
+:1057D000152600F02782007000F0A8A1007000F0EC
+:1057E00010AA007000F0E8B1103500F011BA007096
+:1057F00000F09135020780D2A0040F608AA17404E2
+:105800000860048300F04D040F6000F000000760A2
+:1058100000F00070732400F00070F42700F00070B6
+:10582000F52EE3820070762EEBA2782340E1F3A2FE
+:105830007022C0E1E3800D7C712500F00070022031
+:1058400000F00070F03500F00070713600F000706C
+:10585000F23600F00070773700F00070F3374B033A
+:105860000F6079A04D030F6078A000F00070BE8F2C
+:105870004F030F6081A051030F6080A000F0007003
+:10588000BB8F53030F607EA055030F607DA000F017
+:105890000070B88F57030F6087A000F00070B68FBC
+:1058A00059030F6085A000F00070B48F00F0490329
+:1058B000086000F04A030960002040080A601120D7
+:1058C0004D040B60203000090460A130007000F02E
+:1058D000A431007000F000F0302400F000F0B1219D
+:1058E00000F000F0B22000F00882007000F010A27A
+:1058F000007000F0418030200CC000F0B13100F0A9
+:1059000000F0252100F00A8E262007406D833231F9
+:1059100040E0BE8D353200F000F03634A18F4D04EA
+:105920000F609FA300F00070F62F00F0007070224F
+:1059300000F00070F12200F000707B230F820070F5
+:10594000F42300F00070332082910070F52DBA9F8F
+:105950000070C0E100F0F23F029C1C83371800F099
+:105960003C817B3300F003A00070F32462A500703B
+:10597000F433D2800070F03286910070723500F0FE
+:105980000070E9B200F000708F8F00F05D040860D5
+:1059900000F0FF7F0260002000708BA38182007006
+:1059A00000F04990007000F0C7D774040F60BF8208
+:1059B00084040E60CF918D040D6000F0773600F006
+:1059C00000F0673400F000F0573400F06B040E6014
+:1059D00082A36620007000F000F03E030F6086A3F3
+:1059E00039030E6000F00070763200F0007066320D
+:1059F00000F072BC076000F044030F60C7A30070A2
+:105A000000F03F880070773045030F6078A300F006
+:105A10000070F73000F08E98076000F04D040F60C2
+:105A2000C0A1007000F027AA007000F000F0007024
+:105A3000F73400F06F05076000F071660660CFA3D1
+:105A40007D040F60F781007000F000F0773008D01F
+:105A50006A0409606CA300F0183008D003A0650444
+:105A60000A6078200070096000F0007009A000F062
+:105A7000783008D003A061040A60782000700960C3
+:105A80002F170D6005A0AC7478300C8003A0630460
+:105A90000A6078200070096047170D6001A0AC749F
+:105AA000783008801108000882C91108000816C063
+:105AB00009A01108000809A09D7B8D7B0AA4007035
+:105AC0008D7900F00070221003A011080008FC205E
+:105AD0000D7C08D000F00070200000F0007041083C
+:105AE00000F0007072220882782100F010A200708D
+:105AF00023200980007000F0CB8200704118D3A2EF
+:105B00000070FC30C980FA2100F003A00070413021
+:105B10005100000800F05100000816C009A0510013
+:105B2000000809A0007000F00AA400700D7900F0D0
+:105B30000D7C223000F0783108D000F0007000F0C9
+:105B400078201810096003A00070FA2011000008E6
+:105B500000F01100000806C009A01100000809A00B
+:105B6000007000F00AA400708D7D00F00070221813
+:105B700000F00070FA3000F0783008D000F00070CB
+:105B800000F078201810096003A00070FA201100BE
+:105B9000000800F01100000806C009A0110000086C
+:105BA00009A0007000F009A000708D7D12AA00709D
+:105BB00000F000F00070221800F00070FA3000F0E1
+:105BC000783008D000F0007000F0782020100960D4
+:105BD00003A00070FA201100000800F01100000876
+:105BE0000EC009A01100000809A0007000F009A073
+:105BF00000708D7822AA007000F000F00070223052
+:105C000000F00070FA3000F0783008D000F000703A
+:105C100000F078203010096003A00070FA20110015
+:105C2000000800F0110000080EC009A011000008D3
+:105C300009A000708D7B09A000708D7932AA0070D8
+:105C4000783000F00070221803A00070FA301100C4
+:105C5000200800F0110020080EC009A01100200843
+:105C600009A000707B2109A0007000F0F2AB007069
+:105C700000F000F0323008D000F00070662078208C
+:105C80005010096003A00070FA2000F000700618A0
+:105C90001100000800F0110000080EC009A011005A
+:105CA000000809A0007000F00AA4783000F000F0AD
+:105CB000223008D01020FF1F07600524007005A3C4
+:105CC00028A2007000F040D0052300F0388A81211E
+:105CD00000F087D002221640C883032000F090A174
+:105CE000842000F019A0853340E121A00733C0E1F2
+:105CF00000A8052100F00880FF7F0760F2A880312E
+:105D000000F0BAC2812200F04591023200F07D9F7E
+:105D10000070C0E100F0053110D300F0007008D031
+:105D20000082010409600E040A6000F000F0903067
+:105D300000F000F0A03008D000F07612086000F00B
+:105D4000A81F80D200F08212086000F0A81F80D047
+:105D50004880EF03096008090F60DEAD00F0903164
+:105D600000F000F0F02CDCAD00F0103108D0AC03F6
+:105D70000960E7A200F0113208D000F0AC0309601E
+:105D8000C9D2007000F000F0913208D000F000009D
+:105D9000076000F001000660CF83020005608E837B
+:105DA000007002904D8300700B9000F00070058031
+:105DB000B683910309608D9188030A6015326C04E3
+:105DC0000B6000F0263200F000F0363008D0B683C9
+:105DD000910309608D9188030A6015326C040B6091
+:105DE00000F0253200F000F0363008D0B6836C04A5
+:105DF00009608E91007000F000F0163008D0880322
+:105E00000960008000F008090F6040900070C0AD8C
+:105E100000F0103000F000F0702DBEAD00F09030BA
+:105E200008D091030960C9A200F0113000F000F021
+:105E3000923008D07F030960C6A200F0113208D06A
+:105E40007F030960C4A211304504086000F092305D
+:105E500000F000F0133100F004304F1680D04504FC
+:105E60000860BFA201217F0309600090022000F0BA
+:105E700041908320029000F0007001909A8A007097
+:105E800000F000F0923108D045040860B8A200F09C
+:105E9000003108D0A3030960B6A200F0113208D087
+:105EA000A3030960E5AF00F0133108D09A0309603D
+:105EB000B2A200F0113208D09A030960E1AF00F0FD
+:105EC000133100F000F0943108D072030860ADA2E5
+:105ED00000F08021ACA200F0003608D07203086008
+:105EE000AAA200F00026168072030860A8A200F0A3
+:105EF000802114A000F00070178072030860A5A232
+:105F000000F00020118072030860A3A200F00021BD
+:105F10000F8072030860A1A200F080200D80720340
+:105F200008600C8000F0007023A100F0C008096038
+:105F300000F0340707607000007000F07000173246
+:105F400012C07000903200F090323507076000F008
+:105F5000903200F000F0173200F0008200700080F4
+:105F60007203086094A200F0803408D012400070E0
+:105F700000F000F0803100F00234014038A100F060
+:105F80000040448100407203086000F0007000F09F
+:105F900000F0003408D0AC0308608BA2002272032A
+:105FA00009608122007000F000F0103500F000F070
+:105FB000913508D07203086086A20025AC03096001
+:105FC0008125007000F000F0103200F000F09132F6
+:105FD00008D07203086081A28121AC0309600082AD
+:105FE000007000F0C9D2103200F000F0913208D0F9
+:105FF0001040AC03086000F0007000F000F00032C8
+:1060000008D07203086079A200F08021788200F045
+:10601000E011086000F0B31F80D200826C040860B9
+:106020008450EC0309600030ED030A601030EE0389
+:106030000B60203044040C603030007000F04430BD
+:10604000214094AD00F04204086000F08000006040
+:1060500000F0430409600030000D016000F00070A2
+:1060600000F01130007000F000F071030A6030059C
+:10607000026067A2223003000060020001600D810F
+:1060800000F05F03086000F00060006000F0600353
+:10609000096000300060016000F06F030A60113099
+:1060A000FF7F026000F070030B602230000003608D
+:1060B00000F0DF030C6033300000046000F0E00308
+:1060C0000D6044300000056000F0007000F05530B5
+:1060D000007000F00082EC0308600990EE03096094
+:1060E0000130ED030A601030007000F020300070C5
+:1060F00000F07203086051A2FF83802150A2C6D233
+:10610000073400F000F0863200F000000160F5A0D6
+:106110000000006001A1F040A0040F601240DC10FC
+:1061200001607030C1110360F130007000F000F0C8
+:10613000723100F000F0F33108D000F0007000F090
+:1061400000F0702000F0F74FF12000F0389E007052
+:1061500000F0388C007000F000F0703010D300F0C8
+:10616000007008D00020007000F01120007000F0D6
+:10617000922040080E6008A0C104046030AA62307A
+:1061800000F000F0603100F000F0E4310EC000F0EB
+:10619000007000F000F0E52000F000F0F63000F0B4
+:1061A00000F0253008D027406103086000F0491056
+:1061B00006607730B512096063030A60F18F6740AB
+:1061C0006103086000F04D1006607730B712096077
+:1061D00064030A60ED8F27406103086000F05110EE
+:1061E00006607730B912096065030A60E98F47409D
+:1061F0006103086000F0551006607730BB1209603B
+:1062000066030A60E58F27406103086000F05910BB
+:1062100006607730BD12096067030A60E18F27408E
+:106220006103086000F05D1006607730BF120960FE
+:1062300068030A60DD8F47406103086000F0611069
+:1062400006607730C112096069030A60D98F274060
+:106250006103086000F0651006607730C3120960C2
+:106260006A030A60D58F27406103086000F0691057
+:1062700006607730C51209606B030A60D18F474012
+:106280006103086000F06D1006607730C712096086
+:106290006C030A60CD8F27406103086000F0711025
+:1062A00006607730C91209606D030A60C98F274004
+:1062B0006103086000F0751006607730CB1209604A
+:1062C0006E030A60C58FE041821001602F170860DD
+:1062D00001A0461708600680703063030960F13042
+:1062E000007000F000F0100000F000F010000CC092
+:1062F0000010100000F06303096008D000F01000E7
+:1063000000F000F010000CC00014100000F000F0CD
+:10631000007008D027406203086000F08610066015
+:106320007730B512096063030A60B48F6740620377
+:10633000086000F08A1006607730B71209606403C5
+:106340000A60B08F27406203086000F08E1006607C
+:106350007730B912096065030A60AC8F4740620369
+:10636000086000F0921006607730BB120960660387
+:106370000A60A88F27406203086000F0961006604C
+:106380007730BD12096067030A60A48F274062035B
+:10639000086000F09A1006607730BF120960680349
+:1063A0000A60A08F47406203086000F09E100660FC
+:1063B0007730C112096069030A609C8F274062032D
+:1063C000086000F0A21006607730C31209606A030B
+:1063D0000A60988F27406203086000F0A6100660EC
+:1063E0007730C51209606B030A60948F47406203DF
+:1063F000086000F0AA1006607730C71209606C03CD
+:106400000A60908F27406203086000F0AE100660BB
+:106410007730C91209606D030A608C8F27406203D0
+:10642000086000F0B21006607730CB1209606E038E
+:106430000A60888F0046B510016047170860C4AF36
+:106440005E170860C98F00F00600006000F0C810F9
+:106450000160703087040860F1309B040E600020FA
+:106460005C040D60E121FD020C606220007000F010
+:1064700000F0552000F00882E32000F010A2C723AE
+:1064800000F00880642200F0C7911740E0311B8EB5
+:10649000E24F05943CC56621C0E014C3274040E0AC
+:1064A000768FD24F00F03CC50070C0E014C300707E
+:1064B00040E000F0643208D000F00200006000F01C
+:1064C000CC100160703001040F60F1300070168153
+:1064D00000F00400006000F0D010016070300E0485
+:1064E0000F60F1300070128100F00200006000F0D7
+:1064F000D410016070301B040F60F13000700E8109
+:1065000000F00200006000F0D81001607030280434
+:106510000F60F13000700A8100F00400006000F0AC
+:1065200059110160703035040F60F13000701D8129
+:1065300000F00400006000F0F110016070307203A0
+:106540000860F1308404096000F0012400F000F0DC
+:10655000822200F04190802100F000F09421049408
+:1065600053D5052394A12F8F862393A1F38A00701E
+:10657000C0E0C090833100F000F0007013A000F084
+:106580005D04086000F05F030960002060030A609A
+:10659000112061030B60222062030C6041A2007095
+:1065A00000F082A2313000F000F0423008D000F05C
+:1065B0000200006000F0F510016000F0703000F0A3
+:1065C00000F0F130208000F00800006072214510DA
+:1065D0000160F321F74F00F0BA9E00707030BA8C62
+:1065E0000070F13000F0723130D300F0007008D04C
+:1065F00000F0007001A000F00F3208D000900311ED
+:1066000007603E9A0070139838800070129C00F06A
+:10661000007077A17203086000D0CD120F60108067
+:10662000E1120F600F80F5120F600E8009130F60EA
+:106630000D801D130F600C8031130F600B8045130C
+:106640000F600A8059130F6009806D130F60088076
+:1066500081130F60078095130F600680A9130F60E8
+:106660000580BD130F600480D1130F600380E51314
+:106670000F600280F9130F6001800D140F6000801D
+:1066800000F0007008D00740C00809601540710391
+:106690000A60102072030F602220007000F02EC2EA
+:1066A00000702350B1C4474000E259C4F02400F008
+:1066B00079C47F2200F0AEC7007000F0B2C474004D
+:1066C00008A000F0123200E600F0123008D023508B
+:1066D000C00809608AD0354FD9AF10207203086016
+:1066E0009AC4007000F029C2802400F051C47400E4
+:1066F00000F00090113000F000F0113200E600F0E0
+:10670000007093C87400943000F000F0943200E6FA
+:1067100000F0943200E600F0943008D000F07103ED
+:10672000096000F0720308601220007000F000F0B1
+:10673000812400F082C4C008096041900070EB8F92
+:10674000072244040B6000F0102000F0C791812064
+:1067500000F0B68302201F900F82832100F0178281
+:106760000421019800F021200B80F78D40080D6076
+:106770005682212008905630C2080560D73000703C
+:1067800000F0D531007000F000F000700DC000F096
+:10679000007000F0E6820070572100F0007000F0F9
+:1067A000F7A3007000F0E78135200180C790352005
+:1067B00000F0C883007000F0EDA3007000F00389C2
+:1067C000007000F0ED8E022416406D83832309943F
+:1067D000C883007000F090A1042300F019A000709D
+:1067E00040E121A00070C0E100A8007000F0088026
+:1067F000FF7F0660F2A8203000F0B2C2007000F007
+:1068000000F0023408D000F0053400F000F027302A
+:1068100008D000F0822221A100F0223008D000F040
+:106820000200006000F05E11016070307F030860BC
+:10683000F1300D04096060030A60D68F00F0020099
+:10684000006000F063110160703088030860F1306F
+:106850001A040960DF030A60D18F00F004000060B1
+:1068600000F073110160703091030860F1305C0436
+:106870000960E0030A60CCAF00F0E003086000F0BC
+:10688000DF03096000206C040A601120A6040B607D
+:10689000272070030C600A8A362100F0C79100702F
+:1068A00000F092820070C0E08691007000F0928249
+:1068B0000070C0E04230007008D000F002000060BC
+:1068C00000F07811016070309A030860F1302704FD
+:1068D00009605F030A60BC8F00F00200006000F0F6
+:1068E0007D1101607030A3030860F1303404096049
+:1068F0006F030A60B78F00F01000006000F0DC103A
+:1069000001607030AC030860F13041040960770326
+:106910000A60B28F1130E10808605A202114096022
+:1069200003A0E1030F6000F084040E60170006204E
+:1069300087C81700062000F0B9A1261800F0B8A5F6
+:10694000261800F00089732300F000F0E42300F023
+:10695000C390652300F0F39E762106942D8300708A
+:1069600000F0A4A3F72100F02D8F007000F000F0DC
+:10697000773300E600F00070189400F0F2230580F1
+:1069800000F07333169C00F0742200F06D830070E9
+:1069900000F0E48EF22300F000F0753300E600F022
+:1069A000F52416401082F32000F0A8A1742000F016
+:1069B00019A05A3040E121A07124C0E100A8772538
+:1069C00000F01080FF7F0660F5A8F03300F075C37B
+:1069D000F32216400882F53400F0B8A1007000F0F0
+:1069E00019A0007000F000A8007000F00880FF7F80
+:1069F0000660F7A8703400F0F7C396040860773596
+:106A0000E308096008200070C78D5A3096040860BA
+:106A100000F0E308096008200070C48D00F00070E9
+:106A200000F000F0022200F000F0032100F092805C
+:106A3000812100F09AA2862000F05080842600F088
+:106A400000F005270598208207200A9030A20070E8
+:106A500040E138A20070C0E12480007000F0288B73
+:106A6000843606800088007000F02882072000F03D
+:106A700030A2007040E138A20070C0E12D800070AB
+:106A800000F0288B053700F000F0803708D000F0C8
+:106A90000100006000F0C51101607031007000F06D
+:106AA000F1310070868000F03D00006000F0CA11F6
+:106AB00001607031007000F0F131EF030F6000F001
+:106AC00000700A8000F00100006000F0CF1101604A
+:106AD0007031007000F0F131F5030F6000F00070CC
+:106AE000058000F00100006000F0C111016070310C
+:106AF000007000F0F131FB030F6000F000700080C7
+:106B0000B683F92000F000F0782000F000F01120AA
+:106B100000F000F0002000F04190732100F000F040
+:106B2000F42103901B8E772200F000F0007009D052
+:106B3000C791007003808E91F72200F0048F0070DF
+:106B400000F0C791007009D000F0163070D700F047
+:106B5000007008D000827B04086000F0E90309603F
+:106B6000012083040A60F22387040B600989F3255E
+:106B700000F05582F42100F02D8C112000F05D8B87
+:106B8000F22200F028A1F32400F05582F42000F056
+:106B90002D8C212000F05D8B722300F029A173253C
+:106BA00000F05582742100F02D8C312000F05D8BB7
+:106BB000722200F029A1732400F05582742000F0A5
+:106BC0002D8C007000F05D8B007000F02DA5007022
+:106BD00000F0288C007000F000F0703608D00082C1
+:106BE0007B04086000F08304096000F087040A60F9
+:106BF00000F0E8030B60012042040C60F223430420
+:106C00000D600989F32500F05582F42100F02D8CE8
+:106C1000112000F05D8B722300F028A1732500F095
+:106C20005582742100F02D8C262000F05D8B72229D
+:106C300000F029A1732400F09583742000F02D8CBE
+:106C4000312000F05D8BF22200F029A1F32400F046
+:106C500000F0F42000F000F0472000F000F0552094
+:106C600000F0BE8F007000F0698A0070C0E05582AD
+:106C7000007000F02D8C007000F05D8B007000F053
+:106C80002DA5007000F0288C007000F000F0703628
+:106C900008D090419B04086000F0FFFF016000F005
+:106CA000803000F000F001310EA000F000702C8068
+:106CB000004084040F6000F0E1030E60F0304D04EA
+:106CC0000D60703074040C6060309B040B60E03029
+:106CD000007000F0503E007000F0D03E007000F0F8
+:106CE0004030007000F0C030007000F0B030007034
+:106CF00000F0303100701E80CA0309600180B503C6
+:106D0000096000807F030F6017A088030F6016A042
+:106D100091030F6015A09A030F6014A0A3030F60E6
+:106D200013A0AC030F6012A0100084040F601100C8
+:106D3000007000F000F0F03000F000F0713000F072
+:106D40001000E1030F601100007000F000F07030DF
+:106D500000F000F0F13000F01000007040A000F0F2
+:106D6000F03200F010004D040F601100007000F0D0
+:106D700000F0703E00F000F0F13E00F010007404EE
+:106D80000F601100007000F000F0703000F000F0B3
+:106D9000F13008D000F00070100000F00070110019
+:106DA00000F0703300F000F0F13308D000407404BC
+:106DB000086000F0007002807404086030A000F0E9
+:106DC000802F2FA000F0003F08D000F04A0B80D2A7
+:106DD00000F0A60408604390DF03096000F08421FE
+:106DE00000F000F0112000F00491022100F0419029
+:106DF0000020029482908120089000F00070079497
+:106E000000F0007000F00090007000F0FF83007050
+:106E100009D000F0073078AB00F0007062AB00F0F2
+:106E200000707DAB00F00070148000F0007000F086
+:106E30004190007000F00090174009D0C39000709E
+:106E400009D407306C0B80D700F0007065AB00F000
+:106E5000007067AB00F000700F8000F0291408602C
+:106E600000F0B31F80D0FF83A4040860CF91FFDF40
+:106E7000016000F00020025200F087300C80FF8398
+:106E80006504096000F0A40408601730007000F089
+:106E90009730FFDF016000F00020024000F08730F3
+:106EA0000680A404086009A0C14F002000F0324011
+:106EB00000700380A404086006A0C14F002000F009
+:106EC00022400070008008C2007000F010C4E0088A
+:106ED000096000F0003000F000F0103008D000F041
+:106EE000007008D01040B204086000F0007002800A
+:106EF0000040B204086000F00070008000F0003232
+:106F000008D000F00070B2A00746B204086000820A
+:106F100010010960369E873200F000F0003500F065
+:106F200000F00032125086331CEF0360123700125B
+:106F30000460033F670005608430264000F0053799
+:106F4000174000F00634C80A016087360068026006
+:106F50008137034100F01234007000F013350070E7
+:106F600008D000F05314086000F0B31F80D200F086
+:106F7000007000800082B204086000F0F800096030
+:106F80000033007008C000F0101000F080351001D0
+:106F900009600036015400F09036007000F0913422
+:106FA000007008D000F0620B80D200F09B040E60ED
+:106FB0007728B204086066225E040960C791022E39
+:106FC00000F0CF91102009D0869100708C9000F0D5
+:106FD000912009D400F065040E601382C2040F6092
+:106FE00054826304096000F0662000F07B204008B2
+:106FF0000A60FC20E1000260102069040D60368800
+:10700000233100F000F0A63000F000F0203082CBF9
+:1070100000F0A23100F000F055200CC000F0E62096
+:1070200000F09020A4040D603688243100F000F0B8
+:10703000A63000F0D72069040D6000F0203000F089
+:10704000C791202000F000F0A12002940080007081
+:1070500000F04980007000F000F0301800F000F0FF
+:10706000411800F0EDD37B3000F000F0FC300194CB
+:1070700000F000701F80C6040F6098ACC9040F6058
+:1070800097ACB2040860B9AF802D5E070260012D95
+:107090004D04096000F0852700F00090832500F082
+:1070A0001088862601988090007000F0698A007030
+:1070B00000F02D88172100F0698C007000F0C79156
+:1070C000007000F000F000700F9408A00426174034
+:1070D000A8AF00700658D9A1007000F0A2A1FF7FF0
+:1070E0000760F3A8022400F0FBC2007000F004A8BF
+:1070F000062700F008A0002E00F0A1A1072200F052
+:107100008DAE007000F0C791007000F02880007014
+:1071100009D400F0003E00F000F0833500F000F0EC
+:10712000043608D0DB82822300F024830070F68FBF
+:1071300000F0AD040E60CC040F608AACB2040860AD
+:107140009AAF00F0072500F000F0F800066000F0AC
+:1071500010010D60F581007000F000F0D53795AF9B
+:1071600000F0D92794AF00F01D7C00F000F0102053
+:1071700000F000F09D78542700F0112000F03FDB74
+:10718000D22600F00B82007000F0E3A2007000F045
+:107190009A80007000F000F0D23600F000F08734E2
+:1071A00000F0B204086089AF87215D040E6000F032
+:1071B000002F00F03F89662000F000F0812E00F0E3
+:1071C00030A2007000F04180F80003605480813EDE
+:1071D00000F0E5DC843F00F06591062500F0588161
+:1071E000822200F09E81D0377EAF00F0D92700F0D8
+:1071F00000F0D63700F000F0112000F000F0DA27A0
+:1072000000F0C883007000F010A2232000F041803D
+:10721000007000F0CE8E113000F000F0053500E671
+:1072200000F0D13700F0AD78552400F000F02420B4
+:1072300000F0EBA2D33505541B8F543600F09BD3DE
+:10724000D62400F02B88572540E0F382007000F030
+:10725000FBA2007000F09D81007000F000F0D534BA
+:1072600000F00421FD020B60802F2503096000F06F
+:10727000062300F000F0812400F08691022000F047
+:10728000BE9F8320C0E00F82063300F0CF83B0237F
+:1072900000F0DF83832106588290073009D8F3C2BB
+:1072A000062309DCE4C667040D608691033100F013
+:1072B0000090075809D44591102B0194C491007097
+:1072C00040E19693543000F00633007000F000F077
+:1072D000922100F000F0912A00F010A2132155AF86
+:1072E0005980852154AF28A0044F00F042AEF740EA
+:1072F00000F0A28C962000F0BA8A1532074F95C78D
+:10730000923010407DC7007000F000F0D53000F0E2
+:10731000103DAF0B80D0690408604BAF00F0002037
+:107320004AAFC0D2007000F000F00070179000F07B
+:10733000007008D000F05F17086000F00A000060DD
+:1073400000F04023016000300B0002608130001427
+:10735000036002310C0004608331804D056004320B
+:107360000D0006608532C014076006336717096098
+:1073700087335F17006004406117016010306317A6
+:10738000026091306517036012316C170A60933107
+:10739000007000F01432007000F000F01B2000F0CC
+:1073A00000F0293000F00082AB3000F000F0203116
+:1073B00000F000F0A03108D06C17086030AF8920D1
+:1073C00067040A6000F0802100F000F0112000F056
+:1073D00000F00B20065809C0F440034F71C23C7006
+:1073E00000F000F0213000F0A430A330C0E208909B
+:1073F000007000F0079C022100F000821C7040E247
+:107400008A90803100F0B798893000F09282023182
+:107410000894332067170C6000F0023100F0C3902D
+:107420000B3000F067170B6000E200F00C3000E258
+:1074300000F0392000F000F0823100F000F08930D7
+:1074400000F000F0AF0B80D01140007001A000F000
+:10745000113008D07F0009602780205801601CA0EF
+:10746000806601602180204001601A80806C01608C
+:107470001F802000016018807F0009601BA0009021
+:10748000802C00F000F0812D09D000F0003BA045D9
+:1074900000F0813B00F000F0003E08D07F00096062
+:1074A00015A000900040016000F0004009D00130BC
+:1074B000E40F80D07F00096011A00090204001609F
+:1074C00000F0104009D00130E40F80D200F0D00F5E
+:1074D00080D07F0009600CA00090A04500F000F073
+:1074E000007009D000F0003E08D07F00096008A0BD
+:1074F00000900020114000F00070019040D4007016
+:1075000008D04090007008D07F00096003A0009070
+:10751000007000F000F0104009D00130E40F80D07E
+:1075200000F0D908086000F0102004807F00096096
+:10753000FDAF0090007000F000F0007009D000F086
+:10754000813F08D000F0007008D000F064060860A9
+:107550004982007000F00632007016A04982B678A9
+:10756000006000F0007076A011400070ABA000F049
+:107570000070D3A000F00070CDA000F00070578024
+:1075800006586806086000F01B0405608683072023
+:1075900000F0AEA3864B0460CF915206096036819D
+:1075A000073000F0163000706BA000F00070C9A02A
+:1075B00000F0007094A000F0A51480D0A608086028
+:1075C00018A000F0002000F000F0812008D000F0AA
+:1075D0000070E5A000F0007015A000F00070C780FA
+:1075E00066140F6012A0720052060E6072000070E6
+:1075F00004C07200621000F000F0621008D09282A5
+:1076000052060F604190007000F0F230732240E6A5
+:1076100000F0F13109D000F0F33008D052060E60CE
+:1076200005A000F0E73008D0D578056000F05206DC
+:107630000E6002A0EFA3007000F000F0673108D0E8
+:107640000049066002A070A0007000F037AA007028
+:1076500008D000F0007008D000F052060F6000F073
+:1076600057060E6076206B140F6000F0ED2200F0DC
+:107670007C216B2403A000F0007002A000F0ED322A
+:1076800000F000F06B3408D07820500800F000F0D3
+:10769000510800F000F0420000F000F0003000F06F
+:1076A000F720813000F000F0023100F0F9216A2269
+:1076B00000F000F0873100F003A01200200803B0B2
+:1076C00021088BC811A01200200851B0210800F039
+:1076D00010A4430000F051B4003000F000F08130FD
+:1076E00000F000F0033100F000F0873100F000F00E
+:1076F000802000F000F0320800F030A0682600F092
+:1077000013AAF921EA23D080007000F000F080185D
+:1077100000F003A011002008110020080AC009A0F1
+:107720001100200809A069227A2009A0EA2300F0AC
+:10773000A0209D7800F069322D7800F031A06836E5
+:1077400000F030A4EA330D7C00F0003008D0008255
+:10775000C008086000F07817096000303103076046
+:107760001000007002A078170960D1AFDF911000FF
+:1077700000F01000073012C01000803000F000F060
+:10778000803000F000F0803008D073060F6000F009
+:1077900078170060CAAFF030007000F07030D70A80
+:1077A00080D20082A5140F6000F0570608607100B7
+:1077B00000000960710000700CC07100011000F041
+:1077C000011020010A60B54A01103FC000F01010FE
+:1077D00000F000F010101EC000F0201000F020108B
+:1077E000A001096000F020100EC000F0101000F0A1
+:1077F000101040000A6000F0101026C000F02010A9
+:1078000000F020106A06096000F0201007C000F0A8
+:10781000101000F0101090010A6000F010100FC05E
+:1078200000F0201000F000F0201008D000F00E2B27
+:10783000076002A222870660B8A0E3C3056031A0FA
+:107840008F02036026AA64060860AE81007000F013
+:10785000F5D7003000F05DA3863000F07D9F00700A
+:1078600000F000F0853208D0792152060C6000F05B
+:10787000F82000F000F0C72100F000F0FB2000F03D
+:10788000C791101800F01718111840E6BD7879312B
+:1078900000F000F0792000F000F07A2000F003B052
+:1078A0001000830803A011009FC8C1A01000830826
+:1078B000C9B0110000F0C0A4F82000F0C9B4E03055
+:1078C00000F0C7910D78613000F0FB30029400F0B9
+:1078D000673100F000F0E73108D003B020008308E2
+:1078E00003A021009FC8C1A020008308C9B02100C7
+:1078F00000F0C0A4007000F0C9B4E03100F000F066
+:10790000613108D064233E200560E323C25F066036
+:1079100060A1622400F09FA5633300F098A1673254
+:1079200000F0AFA4E23300F000F0E73208D000F03E
+:107930006406086000F0A1140F600E217017096042
+:10794000852077170A6000F0640000F0EDD773001F
+:1079500004C967A3640000F0FE80730000F0FE829B
+:10796000161000F000F0261400F000F0007008D0AF
+:1079700000F06406086000F09914026000F09D14A5
+:107980000360759E007000F0C290813140E00231CA
+:107990000070EF8F03A05706096003B070170E60E8
+:1079A00000F0007000F00290982167004390007092
+:1079B00087C8B9A002086700F9B0030D00F0B9A0AC
+:1079C000003000F0F9B0813000F038A8983101A003
+:1079D00039B80070078084A9007000F064DE055893
+:1079E000029800A8007009D0789F007008D00C9110
+:1079F000007000F000A8007009D04091007008D01D
+:107A000084B9007000F064DE0558029801B8007077
+:107A100009D0799F007008D00C91007000F001B877
+:107A2000007009D04191007008D074000F6000F020
+:107A300000F0E10A80D078000F6000F000F0E10A69
+:107A400080D200F00070818F00F075060C60B68364
+:107A50000053076000F0463000F000F0C63100F03F
+:107A600000F0C73008D07506086051AF00F0003153
+:107A700008D04982750608600090007000F000F0A0
+:107A8000813100E600F0003008D000F057060E60AB
+:107A900000F079060B606A2575060D60E8257B14F9
+:107AA000096000F0562100F003A00070040800F007
+:107AB000EC25C4C934A311002208110022081CC0FF
+:107AC00051A01100220851A03410AD7B50A47B14AA
+:107AD000096030A204082D7903A0301000F0CD79A0
+:107AE0006A3500F000F0EC3508D075060B603BAF4E
+:107AF0000082312000F000F079060E604190B22142
+:107B000000F000F0600000E2E2080D6087C88280AB
+:107B1000600000E24190523000F08280B12000F01D
+:107B20005230E0080C6000F0B23100F000F041305B
+:107B300008D00B846A060E60098657060F60C09055
+:107B40000070A0AF00F0007085AF782352060C6083
+:107B5000F92481060D6000F0C72000F000F06022DB
+:107B600000F000F0D12300F000F0622100F00CA240
+:107B7000D12400F01481632000F00DA2041800F05D
+:107B80007EA2051800F09E81E02200F000F0161899
+:107B900000F000F0512400F000F0E22100F00CA20F
+:107BA000512500F01481E32000F00DA2041800F02C
+:107BB0007EA2051800F09E81783300F000F01618C0
+:107BC00000F000F0F93408D000F0B714096000F0BC
+:107BD000810608600082007007C00010100000F0ED
+:107BE00000F0007008D04982B21409604990810603
+:107BF000086000F0922100F003B0132200F012A2FE
+:107C0000003300F088A0007000F019A0007000F0B0
+:107C1000F2A8FF7F046003A8007000F0A2C28331C5
+:107C200000F05BD1023100F095D5007000F0EB80E0
+:107C3000007000F052D100300560A2C2007000F068
+:107C400052A3007000F08AB0007000F05AB10070CA
+:107C500000F0F2B8007000F003B8007000F0A2C2AB
+:107C6000833200F00232007008D0FF838106086082
+:107C70003FCAB2140960FFD7002000F01A2081200B
+:107C800000F085D51E2102214ED19F2083217581D0
+:107C900000702E30DD800070253194800070AF318F
+:107CA0004D91007040E13CC3007000F020800070F6
+:107CB00000F04990007040E16980007000F038C227
+:107CC000007000F086D5007000F04FD190060B6078
+:107CD000BE81812000F04D81263100F00481FF7FBC
+:107CE00007604D91002040E13CC3853000F06ED428
+:107CF000043000F000F0042200F000F0852200F0D3
+:107D000020808C060C604990363040E16980242048
+:107D100000F038C2A52000F0C6D5AF3100F08CD1FC
+:107D2000843300F0A6818534C3C95980461000F021
+:107D30001080007000F04990007040E138C22520AA
+:107D400000F0C6D5A42000F08DD1053400F0AE813E
+:107D5000043500F000F0461008D04040910608605D
+:107D60006241114000F00030CD140E608030A50655
+:107D700009600131610000F0823161000EC0111014
+:107D8000610000F01110007000F011100070008010
+:107D900000F09106086000F0DB07096000F0802029
+:107DA00000F01220BC140F600030950608607000CF
+:107DB0005C0809607000007009C07000001000F0DD
+:107DC000B29E0010125000F0001009D400F0923161
+:107DD00008D091060F601AA04982732119A0C390A0
+:107DE000722000F0799E007009D000F0712216A078
+:107DF0005382007000F000F0007009D849820070D2
+:107E000008D07A9E91060F60929A007009D800F00F
+:107E1000007009DC00F0F13008D091060F600EA070
+:107E200000F0F13108D0419091060D6000F0007033
+:107E3000E5B700F0513108D088D0A5060660419022
+:107E4000D1070F608681674109D800F0763006A01F
+:107E50007F8E7F2000F000F0007009D000F07210DB
+:107E600000F000F0731000F000F0741000F000F06B
+:107E7000751008D000F0007008D067DCD120703693
+:107E80003FC6512100EAF7365C080B6000F073230F
+:107E900000F064D0713400F0FB9E743700F0FF8373
+:107EA000733309D4A640B42000F01340F22300F04D
+:107EB00064D0763300F08290F33300F006417437DB
+:107EC00009D02440F02200F03640763300F00890CC
+:107ED000F73300F030C2F82400F0268EF0320F9411
+:107EE0007220A10608607022A1060960F721C7145C
+:107EF0000C601382FA2500F03B82F2200298008287
+:107F0000A5060A603B82723000F07C35C30A80D33C
+:107F100000F082060E6000F0220083C800F022000C
+:107F200000F000F0121000F00890121000F000F0C5
+:107F3000703200F0B683FA3500F0F6D2020000F09D
+:107F400000F0F83400F000F07A2500F0B3C2723788
+:107F500000F02400240140E600F07A3500F000F043
+:107F6000B43100F000F0323108D000F091060F601B
+:107F700000F082060E6072215E150D6065206A06B3
+:107F800008608290742757204591F0260B907DC39E
+:107F90007124D1BBECD5D82165300C8157207226D5
+:107FA000ADD1F43700F07DC3012000F07CC7FC2781
+:107FB00000F08AA2007000F055A3402000F014A346
+:107FC000C12000F020A06A0608606AA4007000F0DA
+:107FD00000F0023408D03200066003A000F0063042
+:107FE00000F000F0033300F000F0833308D000F01D
+:107FF000FD06086000F07A15006000F07B15016056
+:1080000000310000026001329315006082320816D0
+:10801000016080317201036000F0013408D000F08B
+:10802000BF1F80D200F0A70980D200F0DE1A80D2F4
+:1080300000F0281F80D2FF060860A3A000F00070A7
+:1080400000D2FD060D60A8A050244902016000F096
+:10805000522300F000F0030708608290DC7300D226
+:1080600000F0F71A80D200F0E00780D200F0860A14
+:1080700080D200F03C0A80D200F0007000F200F0E4
+:108080000070EF8FBA9E8320029000F002300194BE
+:108090004090033000F000F0503008D000F00307AB
+:1080A000086000F0007003A06A150060088000F00E
+:1080B000540280D208160060068000F0022094A0CE
+:1080C0008290832000F000F0007009D000F00330AF
+:1080D00008D000F0822090A000F0023008D0050700
+:1080E00008608A8000F0370780D01040951F80D24A
+:1080F00000F0F31A80D200F00070F3AF00F0BA0A7B
+:1081000080D000F0621508607A1501607EA000F052
+:10811000090000F000F000008CC800F0090000F039
+:108120001030000000F00040301B80D20140040BF2
+:1081300080D200F0C80680D20740C60780D0104029
+:10814000991F80D200F00070878400F0B00380D2C5
+:1081500010402040C0E200F0991F80D200F0007073
+:1081600083840607086071A01040991F80D700F033
+:108170000070808400F0A11F80D000F00070DD8FBF
+:1081800000F07A150860A315016069A000F00900ED
+:1081900000F000F000008CC800F0090000F0103082
+:1081A000000000F0F14F007099A00040301B80D219
+:1081B0000140040B80D200F0C80680D21740C607E9
+:1081C00080D01040951F80D200F0F31A80D200F0CA
+:1081D0000070CFAF00F0310780D000F0530D80D297
+:1081E00000F0370780D01040951F80D210400F1B41
+:1081F00080D200F00070C98F00F0A11F80D200F083
+:10820000940D80D200F0260780D000F0FD060860B3
+:108210001040B21502602140061B80D200F06313AB
+:1082200080D200F00070BEAF00F0510D80D200F09F
+:10823000281280D01040B61502602141061B80D262
+:1082400000F08C0780D200F0730780D0FD06086034
+:1082500051A000F0012013401040007000F0619A1E
+:10826000BC150260598C061B80D200F0661380D0CA
+:1082700000F0291280D200F0940D80D200F0A11FEE
+:1082800080D20052991F80D200F02B0780D010407E
+:10829000991F80D200F000706E84060708603DA030
+:1082A0001040991F80D700F00070678400F00070C4
+:1082B0009FA11040204040E600F0991F80D200F0BE
+:1082C0008C1B80D201900070FAA000F000706584D1
+:1082D00000F0007048A210402040C0E200F0991F5A
+:1082E00080D200F0007061841040991F80D200F0AD
+:1082F00000705B8400F0007099A21040204040E6BE
+:1083000000F0991F80D200F00070578400F00070D8
+:1083100015A31040204040E600F0991F80D200F0E5
+:10832000007053841040991F80D200F00070558473
+:108330001400016001803200016000F0FD06086059
+:10834000278000F092150860F21501601EA000F071
+:10835000090000F000F000008DC800F0090000F0F6
+:108360001030000000F01040301B80D20140040BA0
+:1083700080D2014000704CA000F0A01480D200F028
+:10838000931380D200F02D0080D21040C80180D21B
+:1083900000F0EC1480D200F0CC0A80D01040951F81
+:1083A00080D200F0F31A80D200F0007080AF00F0AD
+:1083B000BA0A80D000F0D00A80D01040991F80D235
+:1083C00000F000707284060708600BA01040991F2F
+:1083D00080D700F000706F841040951F80D210404D
+:1083E000A60180D200F00070768F0040671480D222
+:1083F00000F0CF0A80D20040A60180D200F0A11F79
+:1084000080D0FD06096008A000F0113108D000F00E
+:10841000007000F000F0002005A00090007008D06F
+:1084200000F0007000F000F0003008D000F00070A4
+:1084300000F000F0013008D000F0007008D0008299
+:10844000070708600F900070024080322A07096019
+:108450000033454600F00035F40103600730960014
+:108460000160023200100460813000100160943D10
+:1084700055B50460113E414600F0943E007000F096
+:10848000113F014600F0173D00140460153CFFFF4A
+:108490000260943C90010460123B3A070860943BF0
+:1084A0000100056000F03E070960053045070A60DD
+:1084B000133032000760233015070860A730000032
+:1084C00002600130014000F0823058070A6001313B
+:1084D000520709602130104000F091304C070860CD
+:1084E0001030114000F00030004054A4F14F004023
+:1084F0000DA000F0003422A0B141007000F05E1623
+:108500000060888000F08C1B80D201909B1B80D281
+:1085100000F0941380D200F0261F80D200F08A0D64
+:1085200080D200F0490780D200F0530180D00707C5
+:108530000860D6AF00F0013208D00B070860CD8F7D
+:1085400007070860D3AF00F0813408D01007086037
+:10855000CA8F07070860D0AF8034140480D2174058
+:10856000C60780D200F01E0480D000F00070FAAF81
+:1085700000F0F10380D200F0660D80D200F0FD0320
+:1085800080D200F0690D80D04090D01B80D20707C8
+:108590000960038007070960C5AF4090913200F081
+:1085A0001123E41E80D200F01040C2AF00F010355D
+:1085B000D48307070960C0AF00F0113301A000F0B9
+:1085C0000070FB8F07070960BDAF00F01123BCAF3F
+:1085D0004090007000F010409022C0E200F0E41ED5
+:1085E00080D000F07F1B80D200F0B90F80D0114006
+:1085F00007070960F040830A80D200F0913500E25D
+:1086000000F0007008D00E070860ABAF00F00070FB
+:1086100000D000070860A9AF00F0503008D007076D
+:10862000096000F008160160ADAF00F091339D8342
+:108630000E070860A78F0F070860A68F00F06E1C5A
+:1086400080D260160060FC8FDB070A60A7AF212094
+:1086500000709D8363160060F98F00F00070A483A2
+:1086600000F0E040F8AF00F00070A6A314070D6022
+:10867000F0AF00F0010480D200F000701E9400F012
+:1086800000702AAF00F07805016000F0861B80D2F0
+:10869000F04FA91B80D240405E1B80D200F05D1CD1
+:1086A00080D270160060EC8F00400070C6AF0040B2
+:1086B000B40380D273160060E98F10400070C3AF1E
+:1086C0001040B40380D276160060E68F00F00304F9
+:1086D00080D200F07008016000F0861B80D2F04F5D
+:1086E000A91B80D240405E1B80D200F05D1C80D26E
+:1086F0007D160060DF8F00F0D11B80D2004000703B
+:10870000B8AF0040B40380D281160060DB8F104008
+:108710000070B5AF1040B40380D284160060D88FCB
+:1087200000F0E80380D200F00070F9AEF14F007065
+:10873000ADAF00F0D606016000F0861B80D2F04F8E
+:10874000A91B80D200F06E0780D20140104000F0DB
+:10875000E241AE0780D21607086073AF00F0721BCB
+:1087600080D2319E404000F0C04F007040E000F0E9
+:108770005E1B80D200F05D1C80D294160060C88F12
+:1087800000F0007095AF00F00070D8AE00F09407D4
+:1087900080D200F00070029099160060198000F0FD
+:1087A0008C0780D200F0730780D214070860BD8F59
+:1087B00000F0F040C0AF00F0007071A300F0007056
+:1087C000DA8200F00041BDAF00F0007075A300F048
+:1087D00000703DAF0040301B80D200F0960380D285
+:1087E000A5160060B78F00F00070D9AE00F0070743
+:1087F0000960A916016060AF00F09136DE8F0007B6
+:108800000860AF8FAB160060B18F00F000707F83FF
+:10881000150708605BAF00F0812000F000F0003524
+:1088200000F000F0813230800707086057AF012068
+:1088300000700080B90A0260A9AF1040061B80D00A
+:1088400000F08C0D80D200F0CB0F80D200F07912B6
+:1088500080D200F07B0D80D200F01C1280D200F09C
+:108860007A1280D200F06E0780D200F0740780D2B6
+:1088700000F0671380D200F0590280D20040C41B80
+:1088800080D00040C91B80D200F0007069AF00F0BA
+:10889000CE0F80D200F0007078AF00F000708BAF88
+:1088A00000F05B0280D017070860408F1607086051
+:1088B0003F8FF14F0707086000F0007000F0114093
+:1088C00081340180014000700080180708603AAFD1
+:1088D00000F0104090AF00F0007065A3180708602A
+:1088E00032AF00F00070029400F0310780D2D2164F
+:1088F00000608A8F00F08C0D80D21507096034AFBC
+:108900001021851B80D200F0912000F01F070D6020
+:1089100080AF00F0913200F0F04FA91B80D2070722
+:1089200008602EAF00F0012200F000F080242CAF90
+:108930000F82007000F07F9E007002900040104097
+:10894000C0E200F0007057AF00F010407CAF00F0C4
+:108950006E0780D200F08C1B80D20190104000F096
+:108960001241AE0780D200F0007055AF00F00070E9
+:1089700068AF00F01507096000F0670280D200F0D0
+:108980001032059400825E1B80D200F05D1C80D204
+:10899000ED1600606F8F00F06B0280D2EF16006062
+:1089A0006D8F1A07086011AF00F0721B80D2019022
+:1089B000007000F0319E007004904040C04FC0E253
+:1089C00000F05E1B80D200F05D1C80D214170060A6
+:1089D000658F4040641B80D200F05D1C80D2FA1687
+:1089E0000060628F00F0D30F80D200F0520D80D271
+:1089F000FD1600605F8F1040C41B80D200F0650D33
+:108A000080D21507086008AF00F0003300F000F0D6
+:108A1000003400F0C04F641B80D200F05D1C80D297
+:108A200005170060578F00F0D30F80D200F0520D71
+:108A300080D208170060548F00F0650D80D21507B2
+:108A40000860FEAE00F00123FDAE0A82803300F024
+:108A500000F0003400EA00F0007005981040C91BD7
+:108A600080D200F000701AAF00F0CE0F80D24040EC
+:108A70005E1B80D200F000700180C04F5E1B80D270
+:108A800019070860ECAE00F00070029000F092024E
+:108A900080D218170060448F00F0D70F80D200F00A
+:108AA000520D80D21B170060418F00F000700EAF96
+:108AB00000F0650D80D215070860EAAE00F00120D5
+:108AC00000F000F0803400F00F82007000F000F041
+:108AD0000070029800F0D50F80D200F00070018085
+:108AE00000F0D70F80D21F070860338F00F02040BE
+:108AF00036AF00F000700EA300F02D0780D22A17C9
+:108B00000060328F00F0007089AF00F05E1C80D2F0
+:108B10002D1700602F8F00F0830D80D200F06513B9
+:108B200080D200F00070FAAE00F0CE0F80D21107B4
+:108B30000860CFAE00F0980280D30082007000F091
+:108B400012070860CFAE13070860CEAE00F094079E
+:108B500080D245170060789339170060798F11072C
+:108B60000860C7AE00F000700A9000F08C0780D259
+:108B700000F0730780D23E170060728F00F0007023
+:108B800012AF00F0112600F092209C0780D249908D
+:108B9000007003948882007000F03E170060019816
+:108BA00000F011366B8F00F0730780D200F0007078
+:108BB0000AAF00F0940280D245170060679300F07E
+:108BC000007024AE00F0260780D24C170060108F92
+:108BD00000F0007004AF12070860B3AE00F0007040
+:108BE00009D000F07C1280D200F0171280D200F081
+:108BF000EA0F80D20140007000F011070860B2AEA9
+:108C000000070860048F0040007000F02A07086029
+:108C1000B1AE008280311540719E007000F00030CE
+:108C20000530C0EB5190007040E1052FBD0400609D
+:108C3000A69F813F014080338333C0E20034043477
+:108C4000C0E281358535C0E200F0823008D000F006
+:108C5000007007A10291832E2040B69F042FF28F4F
+:108C60003040007000F0390708609E8E39070860B8
+:108C70009AAE3F9E007008D02A0709609FAE11226D
+:108C80008C1B80D2088223409DAE00F0933700E217
+:108C900000F0007008D001402A07096000F0304061
+:108CA000EEAE00F09137C9A200F0310780D2721702
+:108CB0000060EA8E2A07096095AE972F8C1B80D240
+:108CC00000F0B91B80D21220007092AEBA9E380715
+:108CD0000D60FA9F0070029042900070C0E080909A
+:108CE000007000F01032007000F049829227DBAE75
+:108CF000AA9E113100F000F000707D9000F08C0D04
+:108D000080D201402A07096000F03040DCAE00F05C
+:108D1000913700F0102BA91B80D200F0A70D80D254
+:108D200000F0ED0F80D221409E0D80D200F028127D
+:108D300080D22A07096080AE902D007000F0112EBD
+:108D4000B10D80D2122000707DAEBA9E007000F08E
+:108D500000F00070079000F00070DAAF00F00070D3
+:108D6000069000F00070048000F0FC0F80D200F04C
+:108D70000070DFAD00F00070D5AF00F000706790BC
+:108D8000902FAE1B80D20140991700601507086034
+:108D900071AE00F0003500F000F08132478F00F036
+:108DA0001507086000F02A07096081243040C1AE31
+:108DB00000F0922700F0DB82902000F0AA9E93360C
+:108DC00000F0428291325B9000F01336EF9B00F08E
+:108DD000510D80D21140007000F0A41700600E8F7A
+:108DE0002A07096063AE00F0922700F0912E9B1BCA
+:108DF00080D2AA9E007000F000F00070529008A28D
+:108E0000CE0D80D200F0FC0F80D2A140007000F0A7
+:108E1000AD170060058F00F0F70F80D200F0C90D8C
+:108E200080D22A07096058AE9227FF0F80D2219284
+:108E3000CC0D80D2AA9E922300F000F0132447901C
+:108E400050B0142600F0F6B8952500F00C9190343F
+:108E500000F08783113500F065831436D79B00F04E
+:108E6000007002981140007000F0AF170060F68E9D
+:108E700058B0007000F0F6B8007000F08783007002
+:108E800000F000F00070D09B2A07096047AE9227DF
+:108E90000707086000F0962600F0AA9E122C00F04A
+:108EA00000F0132636903041830A80D200F016413C
+:108EB00000E2CB90007007901041830A80D200211D
+:108EC000007003948121540B80D256413641C0E298
+:108ED00000F000700280D08274040A6000F0133643
+:108EE000029C1140963600F0C0170060E18EA2236C
+:108EF0009B1B80D200F0172D00F01289912C00F0FE
+:108F0000C791123300F000F00070039841A2007086
+:108F1000C0E08B82007000F000F00070B79F44400A
+:108F2000912100F000F092264341479000701040DC
+:108F30008FC213361D90A7C200701C9400F0007001
+:108F4000B19700F000708EAD00F0631380D200F096
+:108F5000510D80D24141007000F0E4170060CE8EC8
+:108F600000F0661380D22A07096022AE9227070715
+:108F7000086000F0132600F0AA9E952100F0CB9027
+:108F8000922B11903041830A80D200F0007003943C
+:108F90007F9F164200E200F000700A9000F09636C3
+:108FA00007801041830A80D2002100700394812140
+:108FB000540B80D256423642C0E200F0007004806A
+:108FC000D082007000F000F013369A9F11400070BC
+:108FD00000F0E5170060BA8EAFC39636104000F07F
+:108FE0000070969300F0903700F000F010210CAE66
+:108FF000009091270BAE7A9E0070129400F0122020
+:1090000006901507086008AEBA9E002100F06A9E1F
+:109010000070029000F0007001901022007000F0CB
+:1090200000F0851B80D200F000706BAD00F02912BB
+:1090300080D2F04FA91B80D209180060A38E00F0E7
+:109040002A07086000F01507096082278C1B80D270
+:10905000AA9E1121FBAD0A820070029400F00070FC
+:10906000019000F00070EB8F00F0AC0D80D200F0AA
+:10907000F20F80D238070860468E4790014041AF1A
+:10908000C1910040658200F00070B8A200900070AD
+:1090900008D001402A07096000F0404044AE00F0CB
+:1090A000913722A200F0310780D21C180060408E58
+:1090B00039070860E4AD2F9E007000F000F00070EA
+:1090C000169000F08C0D80D200F02A07096007404E
+:1090D0008C1B80D200F0B91B80D21032271805609B
+:1090E0001140007000F000F0153700F000F0113171
+:1090F000588F00F0404035AE39070860D8AD3F9E2C
+:109100002A07096000F00070049400F08C1B80D2E4
+:109110009122007061A200F000703AAF00F0007080
+:10912000509700F0007041AD15070960D7AD1021D0
+:10913000851B80D200F0291280D2F04FA91B80D26B
+:1091400035180060778E00070860238E3C070860A2
+:10915000CA8D3A070860CE8D3B070860CD8D00F0C0
+:10916000504023AE00F0007004A200F02D0780D222
+:109170003D1800601F8E00F0007076AE3A070D605B
+:10918000C9AD5120150709600040441802609132B2
+:10919000A91B80D2D020851B80D200F012359C8E76
+:1091A00000F0504018AE00F0830D80D200F0007047
+:1091B0002AAD00F01507086000F03A070D60524133
+:1091C000104000F00121AE0780D24982862400F0D1
+:1091D00000F0D13100F05631007071AE00F0007037
+:1091E0001FAD00F0651380D2511800605F8E00F053
+:1091F0003A070D60F040830A80D200F0D03100E2DF
+:1092000000F0007009D000F0260780D257180060E7
+:10921000058E00F0730780D23A070D60AFADD521FF
+:1092200011000460F040830A80D24581007040E064
+:109230002040830A80D24581007040E06583D531AB
+:1092400000F000F0007009D400F07C1280D200F031
+:10925000171280D200F0EA0F80D200070860F58D67
+:109260003E070860A3AD0082813000F000F00033BB
+:1092700000F000F0043100F000F0853100800707B5
+:1092800009609EAD00F0123100F000F0933108D07B
+:1092900043070860948D3E070D609AAD00F0D1221F
+:1092A00000F000F0522200F000F0532308D000F04C
+:1092B0006040EBAD00F00070CFA100F02D0780D230
+:1092C00075180060E78D00F000703EAE3E070D603F
+:1092D00091ADD020851B80D20040BB180260512088
+:1092E000061B80D27B180060318E00F06040E1AD3B
+:1092F00000F0830D80D200F01507096000F03E07F2
+:109300000D609624070709604982572187ADBF8306
+:109310005632104000F0113600F000F091355198AF
+:1093200000F00070E9AC00F0D50F80D200F0D70D4E
+:1093300080D200F0631380D200F00707096000F0CC
+:10934000940780D200F0112000E28C180060268E75
+:1093500000F08C0780D200F0730780D241070860CC
+:1093600072AD00F0A518006000F05C1680D100F02E
+:10937000940780D2941800601D9600F000700C8055
+:1093800000F00070BCAD00F00070039400F06613B4
+:1093900080D200F07C1280D200F0D70D80D2070777
+:1093A00009606EAD00F0112600F092209C0780D27B
+:1093B0004990007003948882007000F09418006057
+:1093C000019800F01136108E00F0260780D21207A7
+:1093D00008605FADA518006000F000F05C1680D159
+:1093E000AB180060B78DF040830A80D200F00070A7
+:1093F00009D400F0661380D200F07C1280D200F015
+:10940000D70D80D2AB180060B18D1041830A80D295
+:109410000540007009D400400F1B80D20707086088
+:1094200059AD00213E070D608121540B80D200F020
+:1094300052330894D120007012AED532171280D268
+:1094400000F0281280D28140007000F0B718006050
+:10945000FB8D00F0EA0F80D200F0291280D20007C5
+:1094600008609F8D00F02140018000F031400080B5
+:109470004307086049AD4107086043AD00F0007044
+:10948000029000F02D0780D2C11800609B8D00F083
+:1094900015070D606241104000F05121AE0780D2E7
+:1094A00000F06E0780D200F07C0780D200F00070E0
+:1094B000AAAC00F07B0D80D200F00070F6AD00F099
+:1094C000830D80D200F00070A3AC00F0631380D253
+:1094D000CD180060E38D00F0260780D2CF18006021
+:1094E0008D8D00F0730780D2F040830A80D200F0A7
+:1094F000007009D400F0661380D200F0D70D80D23E
+:1095000000F00070108000F0D03200F000400F1B1F
+:1095100080D200F0007099AC00F015070D60624237
+:10952000104000F05121AE0780D200F00070E3AD92
+:1095300000F0007091AC00F0651380D2DF1800607D
+:10954000D18D00F0260780D2E11800607B8D00F0FD
+:10955000730780D2F040830A80D200F0007009D4F3
+:1095600000F07C1280D200F0EA0F80D200F01712D7
+:1095700080D200070860718D450708601FAD00822A
+:10958000013100F000F0803200F000F084317D8F76
+:109590004B070860148D45070D601AAD00F051238C
+:1095A00000F000F0522200F000F0D32208D000F0CA
+:1095B00070406BAD00F0007052A100F0310780D216
+:1095C000F5180060678D00F08C0D80D245070D60A6
+:1095D00011AD51210070CDAD4090851B80D200406F
+:1095E0001E1902605120061B80D2FC180060B08D4D
+:1095F00000F0704060AD00F0007070AC00F06313DC
+:1096000080D200F0510D80D200F0281280D221408B
+:10961000007000F003190060AF8D00F08C0780D25D
+:1096200000F0730780D22141007000F0071900603C
+:10963000AB8D00F0661380D245070D60FFACD120E2
+:109640001340FEAC619A0C190060598C0070A68D15
+:1096500000F0291280D200F02B0780D200F015070D
+:10966000096000F045070D6000F0912400F000F063
+:10967000D021F6AC4282513200F000F00070089820
+:1096800015190060478D1041830A80D200F00070E8
+:1096900009D407070860F0AC002145070D6081215F
+:1096A000540B80D2D2320070029400F0014003804B
+:1096B00000F01140028000F02140018000F03140B4
+:1096C00000804B070860E6AC00400F1B80D200070B
+:1096D0000860378D1040007000F051070860E08C82
+:1096E00001404C07096000F0804037AD00F0913236
+:1096F00021A100F0310780D229190060338D510774
+:109700000860D7AC3F9E007000F000F00070099335
+:1097100000F04C0709602F190560DAAC00F0153233
+:10972000048000F080402DAD07070860D7AC00F042
+:10973000002205AD00F00070FC8E00F0104129AD54
+:1097400000F0902102AD00F08C0D80D200F01C12D0
+:1097500080D200F07A1280D200F0671380D24C07DA
+:109760000960CEAC00F090200F8000F0104121ADD8
+:1097700000F0007034AC15070860CAAC812400709A
+:109780007CA100F000700F9051070860C0AC3F9EB4
+:10979000007000F04C0709600C9000F08C1B80D228
+:1097A0000190961B80D24180007000F00088122149
+:1097B00000F040C2007000F08382007000F000F002
+:1097C0000070059800F0851B80D2112015070D60F0
+:1097D00000403B190260D132A91B80D200F0523503
+:1097E000918D00F07C1280D200F0171280D25007C9
+:1097F0000860078D53190060098D00F000700B811F
+:1098000000F0904008AD00F000700EA10140040B84
+:1098100080D20140007098A000402C1E80D20054DD
+:10982000331E80D214070D60FCAC53070860A5AC52
+:109830000190204000F09241AE0780D252070860AC
+:10984000A2AC399E52070860A04F6040C0E287205A
+:109850006A1B80D2C091851B80D2F04FA91B80D299
+:1098600000F06E0780D27A15016099AC00F05D1CA3
+:1098700080D268190060F48C00F00070C1AC00F078
+:10988000007004AC00F0940780D200F000700290E9
+:109890006D190060458D00F08C0780D200F07307D1
+:1098A00080D200F05D1480D200F0BA0A80D2721922
+:1098B0000060EA8C00F05B1480D2F21501608BAC82
+:1098C00000F0BA0A80D276190060E68C14070860AE
+:1098D000E28C00F0A040E5AC00F00070E8A000F0E1
+:1098E0006E0780D200F05E1C80D27C190060E08C94
+:1098F00000F00070ADAC5807086083AC00F01F1E8C
+:1099000080D700F0610280D200F00070EDAB0082E1
+:10991000007000F01307086081AC00F0940780D25B
+:1099200000F000700D90861900602C8D1107086002
+:109930007AAC00F000700A9000F08C0780D200F042
+:10994000730780D28B190060258D070709607CACF6
+:1099500000F0112600F092209C0780D24990007000
+:1099600003948882007000F08B190060019800F069
+:1099700011361E8D00F0730780D20140007000F098
+:109980001107086071AC00070860C38C00F007077E
+:10999000096000F0A019016000F0B040C4AC00F014
+:1099A000913600F000F00070D0A00140040B80D28E
+:1099B0000140007053A000402C1E80D20054331E82
+:1099C00080D200F00070BB8F00F0B040BCAC004013
+:1099D000C80180D21040671480D200F0CF0A80D234
+:1099E00000F054070D601140040B80D200F05120AC
+:1099F00000F000F0D320098000F00070C8AB5407DD
+:109A00000D605EAC00F054215DAC0491512000F07B
+:109A100000F0D3200D90618000700198C882007022
+:109A200001805882007000F0C190007040E1513018
+:109A3000590709605882B619026000F0503100E2FF
+:109A40001230140B80D200F00070168000F000700D
+:109A5000B7AB54070D6050AC00F0D12100F0A8194D
+:109A60000060F88C0140040B80D2000708609D8CD8
+:109A700000F0C040A0AC00F00070B0A059070D602D
+:109A800098AC00402C1E80D20054331E80D200F0CF
+:109A9000100B80D200F0007011901040671480D23B
+:109AA000580708603CACC91901600690104020407E
+:109AB000C0EB140708603EAC00F00070968F5807AA
+:109AC000086037AC00F01F1E80D20052331E80D2D7
+:109AD00000F0B50280D2CE1900608E8C00F06803D1
+:109AE00080D2D01900608C8C00F0350380D2D2195E
+:109AF00000608A8C580708602EAC10402C1E80D75E
+:109B000000F0007099AB59070860838C01404C0746
+:109B1000096000F0D04085AC00F0913298A000F0D0
+:109B20000070BAAB2040301B80D21040C80180D2F8
+:109B300000F04C070960DF1905602AAC00F015320F
+:109B4000548F00F0D0407DAC00F00070FEAB00F010
+:109B500007070960E419016025AC00F09136778FA2
+:109B600000070860748C53070860208C5207086057
+:109B70001F8C5407096020ACD082123000F024887A
+:109B8000933040E100F0143100F000F09531F98F8E
+:109B90004C0709601BAC00F0913010401231CE0030
+:109BA000016000F093318A8058070860158CFD062B
+:109BB000086016AC00F0813100F000F0823208D06D
+:109BC00000F0FD06096000F00007086000F090302A
+:109BD00002A0FE06086009AC00F0007000D000F0A2
+:109BE000007007AC00F0007000D0FD0608600CACFF
+:109BF00000F0012200F000F000320AAC00F000702A
+:109C000010D000F0DB0709607F9E007000F0779EA7
+:109C10001220049047900070049000F000700190B2
+:109C200000F0007008D000F01130138000F0113007
+:109C3000228000F01130558000F0007076AB00F00B
+:109C400000705A8C9C160060E98F9F160060E88FA8
+:109C50008915016000F001000260E3AF00F0970A8F
+:109C600080D08F15016000F002000260E0AF00F0CC
+:109C70009A0A80D000F000707FAB9315016000F06D
+:109C800000000260DCAF00F0970A80D08B15016005
+:109C900000F003000260D9AF00F0980A80D07B1575
+:109CA0000060E1AF00F00070478C00F0DB070A6055
+:109CB00000F0FD06086000F02220EAABB99E803477
+:109CC00000F0B19E00702C9081900070539000F0D5
+:109CD0000070E89300F0007008D0DB070860E4AB88
+:109CE00000F00220E3ABB99E007000F0B19E00705E
+:109CF0002B9000F0007051901040991F80D09F155C
+:109D00000060D1AF00F000707F8C00F0007068AB95
+:109D100000F000709A8C00F000707AABA51501601D
+:109D200000F000010260C1AF00F09B0A80D000F09B
+:109D3000007079AB00F00070FB8FC115016000F07E
+:109D400001010260BCAF00F0990A80D0C315016028
+:109D500000F002010260B9AF00F09A0A80D0C61587
+:109D6000016000F003010260B6AF00F09C0A80D0F1
+:109D7000CC15016000F004010260B3AF00F09D0A51
+:109D800080D0D015016000F005010260B0AF00F096
+:109D90009E0A80D0D215016000F006010260ADAFCE
+:109DA00000F09F0A80D0D615016000F00701026024
+:109DB000AAAF00F0A00A80D0DA15016000F0080117
+:109DC0000260A7AF00F0A10A80D0CA160060A88F79
+:109DD00026170060A78F6D170060A68F1718006008
+:109DE000A58F39180060A48F71180060A38FF11837
+:109DF0000060A28F24190060A18F00F0FD060860AA
+:109E000000F00301046080220401056000F00801F5
+:109E100006602182050204602982641780D13182A4
+:109E2000641780D12182221980D100F0221980D1BB
+:109E300000F0007008D0EE1500609DAF00F00070DB
+:109E4000F38E00F000707FAB00F00070F38EF5151C
+:109E5000016000F0020202608EAF00F09A0A80D02A
+:109E6000F315016000F0010202608BAF00F0A20A5E
+:109E700080D000F0007093ABF815016000F0000294
+:109E8000026087AF00F0A30A80D0F315016000F0F4
+:109E90000302026084AF00F0A40A80D0F5150160CF
+:109EA00000F00402026081AF00F0A50A80D0F31533
+:109EB000016000F0050202607EAF00F0A60A80D0CB
+:109EC000771900607F8F541900607E8F96190060AB
+:109ED0007D8F060708608CABBC1900607B8FD6199C
+:109EE00000607A8F75465A07086000F014400640FB
+:109EF0002DC0CE040960098D863000F0498B0631F3
+:109F000000F000F0013000F08933FF7F046000F0C2
+:109F100006329C7400F0893200F000F0843108D0E1
+:109F20009300FF7F076000F0930000F0C48E930061
+:109F300000F0C48E9300FF9700F0132C9C7700F084
+:109F4000942000F0C090101000F0FA82111000F080
+:109F500001911320FC9700F0007008D0FF835A078E
+:109F600008603FCACE040F60FFD7822000F00320B4
+:109F7000CE0409608421CE0406609D8E8E2200F0FE
+:109F80000D8F0422039000F0EC7000F08A908E3266
+:109F900000F000F082300B8000F0007009D02381C7
+:109FA000007000F09E81007000F0A482063300F083
+:109FB0003C9F007000F000F00A23059000F0007054
+:109FC00000F000F0252100F000F0A62100F03C9FF9
+:109FD000251000F000F02610FC9700F06730E0AF8D
+:109FE0008120CF040960B683007000F0719E930059
+:109FF00000F000829400059800F0833100F01D8F7E
+:10A00000007000F00890940002900391007000F03E
+:10A010000690007000F0799E833100F000F0063267
+:10A02000FA9F00F0007008D048D0CE0406605A07AE
+:10A03000096056AB86819220334000F016330C70D5
+:10A040008C82021000F03C9F1E2352AB054065003D
+:10A0500040EF0640660040EFFB9E051000F03C9F7D
+:10A060000610FC9700F0007008D05A0708604CAB4F
+:10A0700000F0892300F000F0022100F000F003203E
+:10A0800049AB988E007000F000F0007009D08A9003
+:10A09000111000F000F0893300F0D082023108D0B6
+:10A0A00000F0CE0406605A07096042AB8E8112218F
+:10A0B000634000F016330C7000F0021000F08C8248
+:10A0C0001E233EAB0640660040EFFB9E007000F092
+:10A0D0003C9F0610FD9700F0007008D05A070860FA
+:10A0E00039AB00F08020388B00826207086000F0F6
+:10A0F000007009C00010007000F000F0007008D07F
+:10A10000620708601DA0813103C0006059C402329B
+:10A1100000F08332971F80D269C4043300F0C391EA
+:10A1200085330190314006340A80F04F62070860A1
+:10A130004982007000F00130971F80D062070860EC
+:10A1400013A000F0012012A04190022100F000F0C5
+:10A15000832009D08290007000F0BA9E00700190B8
+:10A1600000F0023108D0799E62070960799E007084
+:10A170000490C39000700490FB9E0070F29300F076
+:10A18000833000F017401C71028027401C72018050
+:10A1900037401C73008000F0102000F000F0922087
+:10A1A00000F00090007000F0C1910231F49307308C
+:10A1B000A61F80D000F0007008D000826B070F60EF
+:10A1C00000F0007006C000F0701000F000F0701099
+:10A1D00008D06B070E6021A000F0602020A0009046
+:10A1E0006C070F6000F0007009D000F0007001A053
+:10A1F0006F070F601CA0F6206B070E607720FF7FB3
+:10A200000460BE9F602000F0FF9F752140E1A6C35F
+:10A21000007009D800F0773000F0C791F63009D40B
+:10A22000389E007009D400F0603050D000F069070B
+:10A230000F6000F080120760389E6B070E6078B0E8
+:10A240007C71FE9F91B8723100F0C9D7662000F092
+:10A2500092B9F13000F08E91723000F000F066306B
+:10A2600008D000F06B070E60498269070F60389EC6
+:10A27000662000F000F07C71FE9FBE9F722000F00F
+:10A2800000F0F32000F08290713000F0C390F130C4
+:10A29000019400F0007009D000F0663008D000F0A2
+:10A2A000007008D000F0007000F000F0002076810F
+:10A2B00000F0007000F000F0003008D0389E01007F
+:10A2C00073A100F01110FE9700F0007008D000F0AC
+:10A2D000B807086000F0731580D200F00070AF80FE
+:10A2E00000F0AC15086000F0B31F80D2C0407207C8
+:10A2F000086000F07E07096000F00245F5AFB8077E
+:10A30000086068A100F0823000F00230FF7F00603A
+:10A31000A08C01606FA0409000706CA000F00070F5
+:10A32000A4A000400070008000F0C208026003900A
+:10A330007E070B6072070B6000E23B9EC308036060
+:10A340009008026000E29308036000E232348B0759
+:10A350000A60B334007000F000F02B3208D07207AE
+:10A360000B6001807E070B60008000F0A8070C6086
+:10A370004090BE150960789E35220F90709E9C70AB
+:10A380000E90689E9C700D9000F0007004904190BB
+:10A3900012400280819022400180C19032400080B2
+:10A3A0000082007008D092070860D4AF009094201B
+:10A3B00000F080900070039418830070F99BD082A5
+:10A3C0000070F99B00F00070F89BD382142046A126
+:10A3D00012810070028000F0932000F000F0122043
+:10A3E00000F02D88B33200F0EBC232300540333339
+:10A3F000A8070C6000F0B13100F04891C53608D0D4
+:10A4000072070B6001807E070B6000804790007030
+:10A4100000F07F9E104000E2779E204000E200F0B6
+:10A42000404000E200F0B22200F00588303200F037
+:10A43000AAC2007000F000F0323308D0B6070860FE
+:10A44000BDAF0090007000F010400040C0EB114024
+:10A450000140C0EB12400240C0EB00F000703A80B7
+:10A46000B6070860B7AF0090007000F010400040E1
+:10A47000C0EB01401140C0EB02401240C0EB00F0C5
+:10A4800000703480B6070860B1AF0090007000F033
+:10A4900010400040C0EB01400140C0EB12400240C0
+:10A4A000C0EB00F000702E80B6070860A98F9307FC
+:10A4B0000860AA8FA8070C6020A12124C415086099
+:10A4C0004440322000F04190C3261CA19B80012013
+:10A4D00009D000F0822000F0C982007000F09A825A
+:10A4E0000521029800F0007001984091007008D09A
+:10A4F0003C9F0C7100F000F0007009D000F00120CA
+:10A50000F88F1F08026009A000F021080360118283
+:10A51000007000F01982007001900082007009D470
+:10A5200000F0104008D0B5070860968FA8070C60AF
+:10A530000DA04082007000F000F0C03608D0A807DF
+:10A540000C600AA000F0C12607A10880007008D0A6
+:10A55000B50708608D8F8B070A6004A1A0230070E7
+:10A5600004A10090B52200F04190104009D44D8321
+:10A57000007001980090007009DC0082007008D023
+:10A5800000F00070FEA000F03020FC8000F00070B1
+:10A59000FCA000F03022FA8091070860838FAB079F
+:10A5A0000860808FAB070860818FAC0708607E8FE2
+:10A5B000AC0708607F8FAA0708607C8F04415709A9
+:10A5C00008600390007004A04440C20808604390F3
+:10A5D000007002A04440C6080860839000700080AC
+:10A5E00026CA0520EDA075C3007000F0C39000706E
+:10A5F00000F065C50070C0E000F0053008D0A80785
+:10A600000C60E8A000F0C03708D0A8070C60E7A0F5
+:10A61000079000700CA000F000700280A8070C608A
+:10A62000E4A00790C02600F0C791362200F000F0A9
+:10A63000312303903082007000F04090007040E1C0
+:10A6400000F0C03608D03080007000F04182007009
+:10A6500000F00082007040E100F0C03608D0A8078A
+:10A660000C60D9A000F0362200F000F0C22600F005
+:10A670003488007000F0A0C2312300F082820070A4
+:10A6800000F0FD9F007001903080007040E0458236
+:10A69000007000F04090007040E100F0C03608D03B
+:10A6A00000F0B81709600790007000F0D217096039
+:10A6B00000E6A0419E07086000F00070558F00F092
+:10A6C000B81708600790007000F0D217086000E625
+:10A6D000A0419E07096000F0007050AF00F00070CC
+:10A6E00078A200F0007096808D0708604B8FB0074D
+:10A6F000086048AF8E070860498F00F0007008D0EE
+:10A7000000F0B807086000F08B070A6000F0022034
+:10A7100000F0A1246A15006082906A1580D0A80715
+:10A720000C60B9A000F0007005A100F00070EFA26D
+:10A7300000F0F71E80D700F0D11E80D700F0007027
+:10A74000EEA0E01B00607980A8070C60B2A000F0CA
+:10A750000070CAA000F0007009D000F00070F4A0F2
+:10A76000E51B00607480A8070C60ADA000F00070CD
+:10A77000C5A000F0007009D000F0007024A1F31B08
+:10A7800000606FA000F00070DBA100F0B80A80D07C
+:10A79000A8070C60A6A000F0D91B0160FF7F006035
+:10A7A000ADAFA08C0060AAAF0082513089A200F04A
+:10A7B000A02183A200F0B80A80D0A8070C609FA057
+:10A7C00000F00070B7A000F0007009D000F0007039
+:10A7D00056A100900C1C006000F0791580D5FA1B82
+:10A7E00000605F80A8070C6098A000F00070B0A027
+:10A7F00000F0007009D000F000706EA13A9E0C1CB1
+:10A80000006000F0791580D18A90031C0060FA1B6B
+:10A81000006000E200F000705680A8070C608FA076
+:10A8200000F00070A7A000F0007009D000F00070E8
+:10A8300097A13A9E0C1C006000F0791580D18A9097
+:10A84000FA1B0060031C006000E200F000704D8005
+:10A85000A8070C6086A000F0A22284A050D400704B
+:10A8600000F000F00070019400F0007003800C1CF8
+:10A870000260C3A281900070049400F00070D8A21E
+:10A88000411C0160B4A200F000700194181C01602A
+:10A89000AAA14090791580D0A8070C607AA000F09A
+:10A8A000007092A000F0007009D000F00070D1A1FB
+:10A8B00000F00070FEA100F00070B0A100F0007088
+:10A8C0000080A8070C6073A000F0921C006000F0EC
+:10A8D000791580D200F00070B6A200F0007042A09E
+:10A8E00000F0B10A80D0A8070C606DA000F0B22380
+:10A8F00000F000F06A150360BA9E2C1C016000F0A5
+:10A900000070019000F0533008D000F051301182F7
+:10A91000A8070C6066A000F000707EA000F0007038
+:10A9200009D000F00070DFA100F00070BCB500F0AD
+:10A930000070069000F000709BA100F0B80A80D271
+:10A940003A1C016000F042463A1C006000F07915A4
+:10A9500080D200F0223508D000F06A15006000F0C7
+:10A96000791580D0A8070C6058A04446202556A031
+:10A97000389E6A15056000F0203509D400F02435B2
+:10A98000F6A100F0007009D44091791580D0A80795
+:10A990000C6051A01F1C01604FA000F051303EA27E
+:10A9A0001040007035A200F0007043826A15036009
+:10A9B00074A200F0533009D000F000704AA000F0FB
+:10A9C000362548A08E91007000F03635B70A80D049
+:10A9D000A8070C6046A000F0007070A2501C006038
+:10A9E00000F0498200700980A8070C6042A000F0C6
+:10A9F000007069A200F00070F99700F00070CB8F32
+:10AA0000A8070C603EA000F0212607A2439000702A
+:10AA100009D400F03F1E80D7A025791580D000F022
+:10AA2000007000F0A035541C00602136791580D2EA
+:10AA300000F00070F88FEC1B01600E80A8070C601E
+:10AA400034A000F000706EA200F00070029400F0DC
+:10AA5000007067A200F00070E9970082007016A2F3
+:10AA6000F31B0160D9A100F000700680A8070C60FC
+:10AA70002CA0251C016000F0461C026060A28190A1
+:10AA80004446C0E0A134B80708602435731580D06F
+:10AA900000F0007000F04090791580D0A8070C609D
+:10AAA00024A000F0A02105A200F000703EA0721CBE
+:10AAB0000060E78FA8070C6020A000F0007038A0AD
+:10AAC00000F0007009D000F000703EA000F00070AF
+:10AAD000029400F0007048A0811C0060E08FA8077D
+:10AAE0000C6019A000F0007031A000F0007009D0D7
+:10AAF00000F0007037A000F00070119000F00070BE
+:10AB00003AA000F000700F94791C0060D88FA8075D
+:10AB10000C6011A000F0007029A000F0007009D0B6
+:10AB200000F000703CA000F00070019400F0007094
+:10AB30000880A8070C600BA000F0007023A000F0B4
+:10AB4000007009D000F0007036A000F00070039093
+:10AB500000F0007039A000F000700194871C0060C4
+:10AB6000CA8F00F0921C006000F0791580D200F0CE
+:10AB7000B10A80D000F0007008D08B070A60FEAFE9
+:10AB800000F02B22FD8F40C00220FCAF09CA0070EC
+:10AB900000F08AC2007000F082C4007000F000F083
+:10ABA000023008D011208B070A6000F0902000F0DE
+:10ABB0000AD20070254092D7007000F0A8A0007063
+:10ABC00000F003D3007000F01BD7007000F00CD62B
+:10ABD00000200560E3801B4301609BD8202300F028
+:10ABE000E9A0007000F0CBA200020560C3A2004003
+:10ABF0000660E9A0800007608AA2007000F082A2CF
+:10AC00000070154052DF007000F0A9A0007008D05D
+:10AC100044080960E5AF00F09021E4AF00900070B7
+:10AC200008D00000006000F04E090860E1AF00F0BD
+:10AC3000803B28C000F0007000F02140007008D078
+:10AC400000F04408096000F00070E4AF00F07023E9
+:10AC5000016080A8007000F0088E007008D04709DD
+:10AC60000860D8AF00F00020D7AF82D4007000F0A9
+:10AC7000025C0254C0E22140007000F010C4007079
+:10AC800000F050D4003008D0FF030060EF8F00F0D8
+:10AC90004408096000F00070D7AF00F0801C01602C
+:10ACA00080A8007000F0408E007008D0470908604E
+:10ACB000CBAF00F00020CAAF02D5007000F0025305
+:10ACC0000251C0E22140007000F010C4007000F09A
+:10ACD000D0D4003008D000824E0908601A9244088F
+:10ACE000096000F082300FC000F0007000F000F04A
+:10ACF00002300FC000F0007000F03C92212000F004
+:10AD000000F0043C00F000F0813B28C000F000702F
+:10AD100000F01190007008D000F04408096000F0C5
+:10AD2000A8070C604E090860BFAF85AAA12000F0FB
+:10AD30002340453A00F000F0813B28C000F000704D
+:10AD400000F0C190007008D000F0C02600F000F0C4
+:10AD5000312000F000F0422700F0088000707640BB
+:10AD60001080D0150D60C032DA150E6054000070EE
+:10AD700000F06500007000F02482007000F000F028
+:10AD8000C539019C8E910070FB8FC634D5150D60BE
+:10AD900000F00070B64054000070A4AF2482007030
+:10ADA00000F000F00070019CBE9F0070FC8FDB8201
+:10ADB000463500F0C0226A18066000F0007000F00E
+:10ADC00030A0007000F083A8412700F0DBD70070AE
+:10ADD00000F084A9433C00F024D2C22700F008828E
+:10ADE000C43B00F030B0C22700F0A3B8007000F000
+:10ADF000A4B9007000F08090007000F000F00070C6
+:10AE0000049824830070019063B80070028083B8B6
+:10AE1000007000F084B9007000F0DBD7007000F023
+:10AE200024D2433D00F070B0C43C00F094BA0070EE
+:10AE300000F08090007000F000F00070029874BA8A
+:10AE40000070019054BA007000F053AAC43D00F0A5
+:10AE500000F0433B08D000F044080960A8070C60EC
+:10AE600084AF4E0908608AAF83AA007000F000F03A
+:10AE7000C33A00F000F0C52900F000F0432A00F0CA
+:10AE800000F0C42A00F0E8A0007000F013AA0070DF
+:10AE900000F028A1007000F014AA007000F000F08B
+:10AEA000452B00F000F0007000F068A1007000F089
+:10AEB00005AA007000F0D8A0007000F013AA00707E
+:10AEC00000F020A140080D6014AA0209026000F001
+:10AED000533000F000F0D53000F000F0D23112C055
+:10AEE00000F0007000F000F0502100F000F054304D
+:10AEF00000F000F0D53000F000F0D23112C000F0C8
+:10AF0000007000F000F0512100F000F0232000F06C
+:10AF100000F0A42000F000F0007000F01A83007030
+:10AF200000F012D1007000F05BD0007000F064D02F
+:10AF3000007000F0C8A0007000F002A1007000F0E6
+:10AF400043AA007000F09B80007000F040D00070B9
+:10AF500000F049D0007000F04482007000F05430DE
+:10AF60000209026000F0D33000F000F0D23112C0CC
+:10AF700000F0007000F000F0502100F000F04625D5
+:10AF8000F74000D7C52400F000F0C73300F000F010
+:10AF9000403300F0DB82A03600F000F0233700F0F1
+:10AFA00000F0A33700F000F086300FC000F0007012
+:10AFB00000F000F005300FC000F0007000F081409C
+:10AFC000073C00F000F0803B28C000F0007000F06B
+:10AFD0000082007008D000F04408096000F04E09BB
+:10AFE0000860A8070C6043AF00F0007049AF00F0A4
+:10AFF000402C00F000F0C12B00F03AA0B52000F08A
+:10B0000072A0C72700F004A800702340ADD74623E4
+:10B01000049C84AAFFFF00602C81007000F000F007
+:10B020004030049C00F00070078084AA007010403B
+:10B030002C83007000F000F04030049CC791007039
+:10B0400000F00342007040E18340007040E000F0F7
+:10B05000104007808681007021400082463300F056
+:10B0600000F027272DAFCF91007000F000F02737B8
+:10B0700000F000F0863B28C000F0007000F062AAEB
+:10B08000007000F01289007000F0423F007008D09C
+:10B0900000F044080960A8070C6025AF00F00070BC
+:10B0A0002BAFB3204E09086080AA412B00F01BD7BC
+:10B0B000422F00F00C82007000F02489007000F034
+:10B0C000A782007000F000F04520149800F0007096
+:10B0D00013901F830070154000F00070049800F07A
+:10B0E000007003904782007000F0759F0070C0E10F
+:10B0F00000F0007002809282443F00F08890C03FD0
+:10B1000008D000F0462300F000F0453000F000F0D9
+:10B11000C03F00F0AE81443F00F000F0463300F045
+:10B1200000F027270DAFCF91007000F000F0273717
+:10B1300000F000F0863B28C000F0007000F00082B4
+:10B14000214008D000F0C72F00F045910070114059
+:10B15000C6830070029C0140007040E100F0007066
+:10B16000018001400070C0E100F0462300F000F0D3
+:10B17000C72300F000F0C13000F0AE83C03F00F004
+:10B180000082443F00F0EF81463300F000F0C73307
+:10B1900000F000F0073C00F000F02727F9AECF9157
+:10B1A000007000F000F0273700F000F0863B28C068
+:10B1B00000F0007000F0389E214008D000F04408F4
+:10B1C0000960A8070C60F3AE00F00070F9AE412BE7
+:10B1D0004E09086080AAC22300F000F02727EEAED7
+:10B1E000CF91007000F000F0273700F00C82B32000
+:10B1F00000F02489C03F00F01BD7443F00F01F83BC
+:10B20000007000F000F00070D29B00F00070D1934D
+:10B210008790C62000F08F980070029000F00070B8
+:10B22000019C00F045200D80BE9F007000F0FF8360
+:10B230004520CB93FE93412300F04591C63300F0A7
+:10B24000719C063C40E16990007000F000F04133D1
+:10B2500000F000F0A627DAAE8E91007000F000F04A
+:10B26000A63700F000F0813B28C000F0007000F02D
+:10B27000F89F214008D02140C623D4AEAE81007093
+:10B2800000F000F0C63300F00082063C08D02040F9
+:10B29000C727D0AEC791440809603090004240EA09
+:10B2A00000F0007000F01031007008D0A8070C60AA
+:10B2B000CCAEC02B00400660412C8000076030B04F
+:10B2C000007000F079B0007000F072BA46250FA04F
+:10B2D00000F0C33100F000F0423208D000F00070FE
+:10B2E000FCA000F00070019000F00070E18000F020
+:10B2F0004408096000F00070C7AE00F0C12700F0FC
+:10B3000092AA007000F04190007000F052AA007004
+:10B3100040E172AA007040E000F0462502A000F073
+:10B32000C33100F000F0423208D000F040080D6058
+:10B3300000F02823006052300209076000F0D0308E
+:10B3400000F0D731DF150F60899F007085C87C70D1
+:10B350007020C0E2799E007000F080A0007000F0C4
+:10B3600023AA007000F036D2007005C000F0004043
+:10B37000046037A3512100F03FD1FF7F066078B011
+:10B38000007000F022BA007000F08291007040E17D
+:10B3900000F0007008D000F04408096000F0007070
+:10B3A000ABAE82AA402D00F093A9007000F052D0FD
+:10B3B00000400660D2D7800007601BD2C12C04A0D9
+:10B3C0001489362500F03D83403100F08E910070E5
+:10B3D00009D83635B70A80D0B8B0442500F0F1B0AE
+:10B3E000007000F03AB0433E00F072B0C23E00F090
+:10B3F00082BA0070CEA000F0007008904340A422F2
+:10B4000093AE1CC3C52D00F0206E046000E23E67C1
+:10B41000046000E600F0372100F0A0A0007000F00A
+:10B4200040AA007000F0AA82007008D0E4D1007039
+:10B4300000F0A0B040080D6081B80209076053A871
+:10B44000D13000F000F0533000F000F0D73100F0C0
+:10B45000C32D007011C000F0372100F09A825021F6
+:10B46000838E00F04408096000F0007089AE00F09F
+:10B47000C22E00F000F0432E00F0BAA0007000F0E1
+:10B48000F2A0FCFF046080AAB72500F000890070DC
+:10B4900000F020C2007000F000F0007009D0CF91E1
+:10B4A000007000F00090B73508D0A8070C6077AEA8
+:10B4B00000F0BE2400F000F0402174AE00F06030D7
+:10B4C00008D00490007024A00390C02272AE429075
+:10B4D000412700F020806A1805600882007000F0A3
+:10B4E00028B0007000F0A0B8007000F0A1B90070A2
+:10B4F00000F0C0D794080860D0A1007000F099A1B6
+:10B50000007000F009D20070CDAF00F0003008D01C
+:10B510009108086065AE0120FE7F02600090007017
+:10B5200000F003581340C0E251C2007000F059C44B
+:10B53000007000F000F0013008D0E40808605EAE52
+:10B5400000F0003008D00082BE2400F000F042215C
+:10B5500000F000F061205AAE8F82007000F000F021
+:10B56000007009D0799E007001985190007000F031
+:10B570000890613008D00342007001808340007061
+:10B5800000804408096052AE1331007008D0A8074B
+:10B590000C6050AE412D800007600654C02C4E8ECA
+:10B5A000A8070C604DAEC12E800007600654402EE7
+:10B5B0004B8EA8070C604BAE00F04E090860FF03ED
+:10B5C000016000F000F0C22400F000F0432500F01C
+:10B5D00000F0442300F000F0C52300F000F0813BB0
+:10B5E00028C000F0007000F000F083300FC000F0C1
+:10B5F000007000F000F002300FC000F0007000F0AA
+:10B60000C1254B09096042264C090A6000F011303F
+:10B6100000F000F0223000F000F0843B00F000F079
+:10B62000053C28C000F0007000F000F0402419A094
+:10B6300000F00070BE8F1240007011A000F04409AD
+:10B640000D6000F047090E6080FF04600ACBF647EA
+:10B65000522030AE92D3452400F052D0632008909F
+:10B6600000F0024002947D9F007000F0558D007044
+:10B6700002804D91007000F0758B007000F0E3C205
+:10B68000453400F0EBC4007000F000F0633026AEEB
+:10B6900000F0532000F09282007001A09BD3007054
+:10B6A00008D000F043090E60BFFF056000F092D1A2
+:10B6B000642020AE2CC3007000F014C5007000F0B0
+:10B6C00000F0643008D047090E601CAE02486120CB
+:10B6D0001BAE51C2007000F041C4403400F000F0D5
+:10B6E000613008D04309086017AE012047FF0260AF
+:10B6F00000F0007000F051C2007000F00090007087
+:10B7000000F012CA0070019051C4007000F000F007
+:10B71000013008D02021F6280160C2224B090860C0
+:10B7200008A04C090960B0AB423600F000F0C0350B
+:10B7300000F000F0003000F000F0123008D0C0221D
+:10B740006A18026000F0007000F010A0007000F0B5
+:10B75000A3A8007000F0A2A9007000F0DBD7007071
+:10B7600000F012D2C33E00F000F0423E00F000F0C4
+:10B77000007039A000F000701694C02240080860E4
+:10B78000015202090260C0D0007000F00030E915DB
+:10B790000D608130E4150E608231007000F000F021
+:10B7A000412512C000F0422700F009D2032100F029
+:10B7B00050A0007000F0F1AAB82400F059A2422570
+:10B7C00000F000F0413100F08A9E013000F000F0FE
+:10B7D000670000F0BA9E510000F000F00070FD9F7D
+:10B7E000C9A2C02200F049D0007000F038A000705B
+:10B7F00000F073AA413200F000F0C33108D043409A
+:10B80000A022E8AD18C2412700F00554006000E214
+:10B81000C44E006000E600F0007000F008A0B824FC
+:10B8200000F0B0AA007000F000F0403100F000F02D
+:10B83000003000804340A022DFAD18C2007000F04D
+:10B8400000F0007002906D71006000F0B19E036026
+:10B850000280FD78006000F0C694036000F000F004
+:10B86000403200F000F0C33108D044090860D6AD82
+:10B87000C2400120D5AD51C2007008D000F0432372
+:10B88000FCAF48D34E09086048D700400394FF033B
+:10B89000026009D0CB90007000F0D38A0070028063
+:10B8A000FB9E007000F01B8C0070008000F0833B5A
+:10B8B00028C000F0007000F000F0433308D000F022
+:10B8C000A022C8ADC0D3007008D08B070A60C6ADF7
+:10B8D0002140A322C5ADC9C2007008D08B070A6001
+:10B8E000C3AD00F0A022C2AD40D4007008D0A008C3
+:10B8F0000860C0AD33430220BFAD9AC4007000F0B1
+:10B9000000F0023008D0A0080860BCAD414400201F
+:10B91000BBAD08C2007000F00882007008D0C344BC
+:10B92000A0080860A122FF7F04601040022000F000
+:10B9300061C2007000F09AC2007000F043C224405F
+:10B9400000F082C44540C0E063C2004100F06BC219
+:10B95000A132F29340D0007040E082C40070F08FBA
+:10B960008B070A60ECAFC24FA322ACADD3C200700C
+:10B9700000F049D0025800F008C4007000F010C474
+:10B98000007000F0C3C4007000F000F0A33208D0D3
+:10B990001440A322A5ADE0C2007000F064D0007096
+:10B9A0008BAFE0C2A108096000F000700194004074
+:10B9B000007003804040007004A0C0C2007000F01E
+:10B9C00030402040C0E200F0007000F000F0103085
+:10B9D00008D08240A3229AADD4C2B74F00F00241F2
+:10B9E00040060460FBC24640029400F0C52296ADBA
+:10B9F000658FA1220180D2C2A12200F0F3C40258B7
+:10BA0000C0E059C6007000F0D3C40070C0E000F080
+:10BA1000A33208D00082BA070860C1070E6016C0C2
+:10BA200000104D060160001085020260613DCD0CE2
+:10BA30000360E230CD0C0460633E02000560E43137
+:10BA400003000660E53F007000F06633007008D028
+:10BA50004190C107096000F0E801086092829137C7
+:10BA60003E9400F0023400F08234AD02086000F031
+:10BA70009902026000F09A0203600232A2020260A0
+:10BA80008332A30203600230AB0202608330AC0257
+:10BA900003600231007000F08331007008D0FF8332
+:10BAA000BA0709604190C10708609733171340E651
+:10BAB00000F0923000F000F0933100F000F014300C
+:10BAC00000F000F0153200F000F096324B80C10714
+:10BAD000096050A000F094274FA00491913F00F01E
+:10BAE00000F0123309D000F000702780C107086011
+:10BAF0004BA000F00037448000F0C1070E6000F05A
+:10BB0000BA4D0960E72740080D60E52C2105086063
+:10BB1000C791593000F000F0553109D0FF9FD8315E
+:10BB200000F0632DE32DC0E2E4206421C0E25B81DC
+:10BB3000672000F0EEC6593000F0AEC3573100F078
+:10BB400076D4E33C00F0E481E52200F0E4C7643001
+:10BB500000F0E7C3642600F07FD4E32600F000F095
+:10BB6000E73600F07D9FE52100F09CD3007040E0B7
+:10BB700028A1672200F02CA5E32500F03C81652E6A
+:10BB800000F0E384E43400F000F0633500F000F0EE
+:10BB9000D83100F000F0642F00F000F0D32000F066
+:10BBA0003C9FE72500F0B3D3E62E40E0E8A06734E1
+:10BBB00000F0EBA4007000F0F38000700DC000F006
+:10BBC000007000F000F0D42000F000F0E33500F049
+:10BBD00000F0643608D000F0962F00F000F0C707A0
+:10BBE00005608691AD020860728100700594A20222
+:10BBF000046000F09902026000F00430AB020460BF
+:10BC000000F0023200F000F00431038000F0023254
+:10BC100000F000F0023000F000F0023100F000F01F
+:10BC2000162318A08691007000F0738100700594AF
+:10BC3000A302046000F09A02036000F08430AC02BA
+:10BC4000046000F0833200F000F08431038000F0E3
+:10BC5000833200F000F0833000F000F0833100F018
+:10BC6000952FC707036000F0E8010C60EA800070C0
+:10BC700000F04591007000F086914534019000F08D
+:10BC8000423400F0F280C63409D000F0C23408D04B
+:10BC9000C107086005A000F0012D00F000F00227A8
+:10BCA00003A053A2812002A053A2833D00F000F024
+:10BCB000033108D000F0007008D00054D6070A60A5
+:10BCC0001140EE15086000F0A03000F000F02130C7
+:10BCD00000F000F0090000F000F000008DC800F056
+:10BCE000090000F01030000000F000F0007008D0F3
+:10BCF0000240DB070960A342D6070A601230FFFF4B
+:10BD0000046000F0A331454100F02431005800F0F8
+:10BD10002532F28F00F0007008D00082D207086050
+:10BD200000F03AE4016005200DB602608620285F2D
+:10BD300003604DC791C7046096C7052140E0862186
+:10BD4000DB070B605DC7003040E0A6C7003140E074
+:10BD500008900070C0E000F0B03008D000F0D207CA
+:10BD6000086000F03AE4016000F00DB602600130B6
+:10BD7000285F0360823091C704600331007000F0D7
+:10BD80008431007008D0D6070960ECAF00F01030A5
+:10BD900008D0D6070960EAAF00F0103108D0D60706
+:10BDA0000960E8AF00F0142100F000F09220035C7D
+:10BDB00020C2112000F0D3C2100908604190007029
+:10BDC00009D482C40070059000F0923008D0D607E4
+:10BDD0000960E0AF4982902000F0913010090860BE
+:10BDE0001130007000F000F0003008D01009086039
+:10BDF000DBAF00F0003008D0F441030000F000F0A9
+:10BE0000D1070F60E0C2090000F0DBD67830039064
+:10BE100000F0010000F0389E783000F000F01110C2
+:10BE2000FD97E0C2034000F0389E007009D0389EB4
+:10BE30001310FF9700F0007008D000F0020000F02F
+:10BE400000F00070F3AF00F07120CCAF51820070B1
+:10BE500000F000F00070FC9B00F0007008D0D607E6
+:10BE60000F60C8AF0082F721028000F0007009D88F
+:10BE700000F0007000F200F0007001A0FF9F007061
+:10BE8000FC8F00F0D607086000F06408096000F03D
+:10BE90000022C0AF00F0103008D0104064080960E4
+:10BEA00000F0007000F000F01030BCAF00F0007047
+:10BEB00000F200F0007000F200F0007008D024835F
+:10BEC000590908604190FF0F05605B9A06200398AE
+:10BED0004B98045200EEAEC3045100EE48090960CD
+:10BEE00003805B94480909607396045400EAAEC36A
+:10BEF000045800EA00F04A290360A6C511208440D6
+:10BF00009BA20630F0401C81FFF00660048B0440C9
+:10BF1000C0EB71C2007000F024D2007000F061C468
+:0ABF2000007000F000F0113008D0AE
+:00000001FF
diff --git a/firmware/EXT_src_coeff_1.1.fw.ihex b/firmware/EXT_src_coeff_1.1.fw.ihex
new file mode 100644
index 00000000000..7f1def62dd5
--- /dev/null
+++ b/firmware/EXT_src_coeff_1.1.fw.ihex
@@ -0,0 +1,130 @@
+:10000000070046B304080000F9FFFCFF2A007E0049
+:10001000A1004400B3FFA3FF34008600FAFF55FFA0
+:10002000BEFFBB00A20059FFF0FE610079011F0076
+:100030003AFE27FFDA01C30167FE38FDE600C6037A
+:1000400053006EFBDAFDF304A3045FFB11F82803F1
+:10005000730C790032ECCCF51529A45CA45C15294D
+:10006000CCF532EC7900730C280311F85FFBA30484
+:10007000F304DAFD6EFB5300C603E60038FD67FEAD
+:10008000C301DA0127FF3AFE1F0079016100F0FE8B
+:1000900059FFA200BB00BEFF55FFFAFF86003400E7
+:1000A000A3FFB3FF4400A1007E002A00FCFFF9FF7C
+:1000B0000000000000000000000000000000000040
+:1000C0000000000000000000000000000000000030
+:1000D0000000000000000000000000000000000020
+:1000E0000000000000000000000000000000000010
+:1000F0000000000000000000000000000000000000
+:1001000000000000000000000000000000000000EF
+:1001100000000000000000000000000000000000DF
+:1001200000000000000000000000000000000000CF
+:1001300000000000000000000000000000000000BF
+:1001400000000000000000000000000000000000AF
+:10015000000000000000000000000000000000009F
+:10016000000000000000000000000000000000008F
+:10017000000000000000000000000000000000007F
+:10018000000000000000000000000000000000006F
+:10019000000000000000000000000000000000005F
+:1001A000000000000000000000000000000000004F
+:1001B000000000000000000000000000000000003F
+:1001C000000000000000000000000000000000002F
+:1001D000000000000000000000000000000000001F
+:1001E000000000000000000000000000000000000F
+:1001F00000000000000000000000000000000000FF
+:1002000000000000000000000000000000000000EE
+:1002100000000000000000000000000000000000DE
+:1002200000000000000000000000000000000000CE
+:1002300000000000000000000000000000000000BE
+:1002400000000000000000000000000000000000AE
+:10025000000000000000000000000000000000009E
+:10026000000000000000000000000000000000008E
+:10027000000000000000000000000000000000007E
+:10028000000000000000000000000000000000006E
+:10029000000000000000000000000000000000005E
+:1002A000000000000000000000000000000000004E
+:1002B000000000000000000000000000000000003E
+:1002C000000000000000000000000000000000002E
+:1002D000000000000000000000000000000000001E
+:1002E000000000000000000000000000000000000E
+:1002F00000000000000000000000000000000000FE
+:1003000000000000000000000000000000000000ED
+:1003100000000000000000000000000000000000DD
+:1003200000000000000000000000000000000000CD
+:1003300000000000000000000000000000000000BD
+:1003400000000000000000000000000000000000AD
+:10035000000000000000000000000000000000009D
+:10036000000000000000000000000000000000008D
+:10037000000000000000000000000000000000007D
+:10038000000000000000000000000000000000006D
+:10039000000000000000000000000000000000005D
+:1003A000000000000000000000000000000000004D
+:1003B000000000000000000000000000000000003D
+:1003C000000000000000000000000000000000002D
+:1003D000000000000000000000000000000000001D
+:1003E000000000000000000000000000000000000D
+:1003F00000000000000000000000000000000000FD
+:1004000000000000000000001100060007000900C5
+:100410000A000C000D000F00110013001500180059
+:100420001B001D002000240027002B002F0033009C
+:1004300037003C00410046004C00510057005D0071
+:1004400064006A0071007800800087008F009700C8
+:10045000A000A800B100BA00C300CC00D500DE00A7
+:10046000E800F100FB0005010E01180121012A013D
+:1004700033013C0145014E0156015E0165016C01ED
+:10048000730179017E01830187018B018D018F0149
+:10049000900190018F018D01890185017F01790112
+:1004A000700167015C014F014101310120010D0123
+:1004B000F800E200CA00AF00930075005500340058
+:1004C0001000EAFFC2FF98FF6CFF3EFF0FFFDDFE4A
+:1004D000A9FE73FE3BFE02FEC6FD89FD4AFD09FD35
+:1004E000C6FC82FC3DFCF6FBAEFB65FB1AFBCFFABB
+:1004F00083FA36FAE8F99BF94CF9FEF8B0F861F89E
+:1005000014F8C6F77AF72EF7E4F69BF653F60DF6D5
+:10051000CAF588F549F50DF5D3F49DF46AF43BF47A
+:100520000FF4E8F3C5F3A7F38EF37AF36BF363F3F9
+:100530005FF363F36CF37CF393F3B1F3D7F304F459
+:1005400039F476F4BBF408F55EF5BDF524F695F6BE
+:100550000FF793F71FF8B6F856F900FAB4FA71FBE3
+:1005600039FC0BFDE7FDCDFEBDFFB700BB01C902A5
+:10057000E10302052E066207A108E809390B930C76
+:10058000F50D600FD3104E12D1135B15ED168518C3
+:10059000241AC91B741D241FDA2094225224142605
+:1005A000DA27A3296E2B3B2D092FD930A9327A34B3
+:1005B0004A361938E739B23B7C3D423F0541C342D8
+:1005C0007E443346E2478C492F4BCA4C5E4EEA4F7D
+:1005D0006D51E8525854BF551B576C58B259EC5ADC
+:1005E0001A5C3B5D505E575F50603C611962E86287
+:1005F000A7635864FA648C650E668066E2663467A9
+:100600007667A867C967D967D967C967A867766732
+:100610003467E26680660E668C65FA645864A76388
+:10062000E86219623C615060575F505E3B5D1A5C46
+:10063000EC5AB2596C581B57BF555854E8526D517B
+:10064000EA4F5E4ECA4C2F4B8C49E24733467E44FC
+:10065000C3420541423F7C3DB23BE73919384A3637
+:100660007A34A932D930092F3B2D6E2BA329DA27F2
+:10067000142652249422DA20241F741DC91B241A24
+:100680008518ED165B15D1134E12D310600FF50DC2
+:10069000930C390BE809A10862072E060205E10355
+:1006A000C902BB01B700BDFFCDFEE7FD0BFD39FC64
+:1006B00071FBB4FA00FA56F9B6F81FF893F70FF782
+:1006C00095F624F6BDF55EF508F5BBF476F439F43D
+:1006D00004F4D7F3B1F393F37CF36CF363F35FF3B8
+:1006E00063F36BF37AF38EF3A7F3C5F3E8F30FF438
+:1006F0003BF46AF49DF4D3F40DF549F588F5CAF599
+:100700000DF653F69BF6E4F62EF77AF7C6F714F8D3
+:1007100061F8B0F8FEF84CF99BF9E8F936FA83FA7B
+:10072000CFFA1AFB65FBAEFBF6FB3DFC82FCC6FC78
+:1007300009FD4AFD89FDC6FD02FE3BFE73FEA9FED2
+:10074000DDFE0FFF3EFF6CFF98FFC2FFEAFF1000C7
+:100750003400550075009300AF00CA00E200F800B5
+:100760000D012001310141014F015C016701700160
+:1007700079017F01850189018D018F01900190012F
+:100780008F018D018B01870183017E017901730146
+:100790006C0165015E0156014E0145013C013301CA
+:1007A0002A01210118010E010501FB00F100E800FA
+:1007B000DE00D500CC00C300BA00B100A800A00044
+:1007C00097008F0087008000780071006A00640045
+:1007D0005D00570051004C00460041003C003700CE
+:1007E00033002F002B002700240020001D001B00D9
+:1007F00018001500130011000F000D000C000A0076
+:080800000900070006001100C9
+:00000001FF
diff --git a/firmware/Makefile b/firmware/Makefile
index 99955ed8b19..656405255ab 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -138,6 +138,17 @@ fw-shipped-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda/xircom_pgs.fw
fw-shipped-$(CONFIG_USB_VICAM) += vicam/firmware.fw
fw-shipped-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin
fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin
+fw-shipped-$(CONFIG_MFD_CG2900) += cg2900_patch_info.fw cg2900_settings_info.fw \
+ STLC2600_R6_03_01.fw STLC2690_R6_03_A1_E5.fw \
+ STLC2600_R6_04_02.fw STLC2690_R6_04_A2.fw \
+ CG2900_1_0C4_1C5.fw CG2900_1_05_SOC_generic_V11_mod.fw
+
+fw-shipped-$(CONFIG_RADIO_CG2900) += cg2900_fm_bt_src_coeff_info.fw cg2900_fm_ext_src_coeff_info.fw \
+ cg2900_fm_fm_coeff_info.fw cg2900_fm_fm_prog_info.fw \
+ R1f.2_SoC1v20_BT_src_coeff_1.1.fw R1f.2_SoC1v20_EXT_src_coeff_1.1.fw \
+ R1f.2_SoC1v20_Cobra_FM_SOC1_coef.fw R1f.2_SoC1v20_Cobra_FM_SOC1_prog.fw \
+ R2c_SoC2v01_BT_src_coeff_1.1.fw R2c_SoC2v01_Cobra_FM_SOC2_coef.fw \
+ R2c_SoC2v01_Cobra_FM_SOC2_prog.fw R2c_SoC2v01_EXT_src_coeff_1.1.fw
fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-)
diff --git a/firmware/R1f.2_SoC1v20_BT_src_coeff_1.1.fw.ihex b/firmware/R1f.2_SoC1v20_BT_src_coeff_1.1.fw.ihex
new file mode 100644
index 00000000000..9922c736cd1
--- /dev/null
+++ b/firmware/R1f.2_SoC1v20_BT_src_coeff_1.1.fw.ihex
@@ -0,0 +1,130 @@
+:10000000080046B304080000F9FFFCFF2A007E0048
+:10001000A1004400B3FFA3FF34008600FAFF55FFA0
+:10002000BEFFBB00A20059FFF0FE610079011F0076
+:100030003AFE27FFDA01C30167FE38FDE600C6037A
+:1000400053006EFBDAFDF304A3045FFB11F82803F1
+:10005000730C790032ECCCF51529A45CA45C15294D
+:10006000CCF532EC7900730C280311F85FFBA30484
+:10007000F304DAFD6EFB5300C603E60038FD67FEAD
+:10008000C301DA0127FF3AFE1F0079016100F0FE8B
+:1000900059FFA200BB00BEFF55FFFAFF86003400E7
+:1000A000A3FFB3FF4400A1007E002A00FCFFF9FF7C
+:1000B0000000000000000000000000000000000040
+:1000C0000000000000000000000000000000000030
+:1000D0000000000000000000000000000000000020
+:1000E0000000000000000000000000000000000010
+:1000F0000000000000000000000000000000000000
+:1001000000000000000000000000000000000000EF
+:1001100000000000000000000000000000000000DF
+:1001200000000000000000000000000000000000CF
+:1001300000000000000000000000000000000000BF
+:1001400000000000000000000000000000000000AF
+:10015000000000000000000000000000000000009F
+:10016000000000000000000000000000000000008F
+:10017000000000000000000000000000000000007F
+:10018000000000000000000000000000000000006F
+:10019000000000000000000000000000000000005F
+:1001A000000000000000000000000000000000004F
+:1001B000000000000000000000000000000000003F
+:1001C000000000000000000000000000000000002F
+:1001D000000000000000000000000000000000001F
+:1001E000000000000000000000000000000000000F
+:1001F00000000000000000000000000000000000FF
+:1002000000000000000000000000000000000000EE
+:1002100000000000000000000000000000000000DE
+:1002200000000000000000000000000000000000CE
+:1002300000000000000000000000000000000000BE
+:1002400000000000000000000000000000000000AE
+:10025000000000000000000000000000000000009E
+:10026000000000000000000000000000000000008E
+:10027000000000000000000000000000000000007E
+:10028000000000000000000000000000000000006E
+:10029000000000000000000000000000000000005E
+:1002A000000000000000000000000000000000004E
+:1002B000000000000000000000000000000000003E
+:1002C000000000000000000000000000000000002E
+:1002D000000000000000000000000000000000001E
+:1002E000000000000000000000000000000000000E
+:1002F00000000000000000000000000000000000FE
+:1003000000000000000000000000000000000000ED
+:1003100000000000000000000000000000000000DD
+:1003200000000000000000000000000000000000CD
+:1003300000000000000000000000000000000000BD
+:1003400000000000000000000000000000000000AD
+:10035000000000000000000000000000000000009D
+:10036000000000000000000000000000000000008D
+:10037000000000000000000000000000000000007D
+:10038000000000000000000000000000000000006D
+:10039000000000000000000000000000000000005D
+:1003A000000000000000000000000000000000004D
+:1003B000000000000000000000000000000000003D
+:1003C000000000000000000000000000000000002D
+:1003D000000000000000000000000000000000001D
+:1003E000000000000000000000000000000000000D
+:1003F00000000000000000000000000000000000FD
+:1004000000000000000000001100060007000900C5
+:100410000A000C000D000F00110013001500180059
+:100420001B001D002000240027002B002F0033009C
+:1004300037003C00410046004C00510057005D0071
+:1004400064006A0071007800800087008F009700C8
+:10045000A000A800B100BA00C300CC00D500DE00A7
+:10046000E800F100FB0005010E01180121012A013D
+:1004700033013C0145014E0156015E0165016C01ED
+:10048000730179017E01830187018B018D018F0149
+:10049000900190018F018D01890185017F01790112
+:1004A000700167015C014F014101310120010D0123
+:1004B000F800E200CA00AF00930075005500340058
+:1004C0001000EAFFC2FF98FF6CFF3EFF0FFFDDFE4A
+:1004D000A9FE73FE3BFE02FEC6FD89FD4AFD09FD35
+:1004E000C6FC82FC3DFCF6FBAEFB65FB1AFBCFFABB
+:1004F00083FA36FAE8F99BF94CF9FEF8B0F861F89E
+:1005000014F8C6F77AF72EF7E4F69BF653F60DF6D5
+:10051000CAF588F549F50DF5D3F49DF46AF43BF47A
+:100520000FF4E8F3C5F3A7F38EF37AF36BF363F3F9
+:100530005FF363F36CF37CF393F3B1F3D7F304F459
+:1005400039F476F4BBF408F55EF5BDF524F695F6BE
+:100550000FF793F71FF8B6F856F900FAB4FA71FBE3
+:1005600039FC0BFDE7FDCDFEBDFFB700BB01C902A5
+:10057000E10302052E066207A108E809390B930C76
+:10058000F50D600FD3104E12D1135B15ED168518C3
+:10059000241AC91B741D241FDA2094225224142605
+:1005A000DA27A3296E2B3B2D092FD930A9327A34B3
+:1005B0004A361938E739B23B7C3D423F0541C342D8
+:1005C0007E443346E2478C492F4BCA4C5E4EEA4F7D
+:1005D0006D51E8525854BF551B576C58B259EC5ADC
+:1005E0001A5C3B5D505E575F50603C611962E86287
+:1005F000A7635864FA648C650E668066E2663467A9
+:100600007667A867C967D967D967C967A867766732
+:100610003467E26680660E668C65FA645864A76388
+:10062000E86219623C615060575F505E3B5D1A5C46
+:10063000EC5AB2596C581B57BF555854E8526D517B
+:10064000EA4F5E4ECA4C2F4B8C49E24733467E44FC
+:10065000C3420541423F7C3DB23BE73919384A3637
+:100660007A34A932D930092F3B2D6E2BA329DA27F2
+:10067000142652249422DA20241F741DC91B241A24
+:100680008518ED165B15D1134E12D310600FF50DC2
+:10069000930C390BE809A10862072E060205E10355
+:1006A000C902BB01B700BDFFCDFEE7FD0BFD39FC64
+:1006B00071FBB4FA00FA56F9B6F81FF893F70FF782
+:1006C00095F624F6BDF55EF508F5BBF476F439F43D
+:1006D00004F4D7F3B1F393F37CF36CF363F35FF3B8
+:1006E00063F36BF37AF38EF3A7F3C5F3E8F30FF438
+:1006F0003BF46AF49DF4D3F40DF549F588F5CAF599
+:100700000DF653F69BF6E4F62EF77AF7C6F714F8D3
+:1007100061F8B0F8FEF84CF99BF9E8F936FA83FA7B
+:10072000CFFA1AFB65FBAEFBF6FB3DFC82FCC6FC78
+:1007300009FD4AFD89FDC6FD02FE3BFE73FEA9FED2
+:10074000DDFE0FFF3EFF6CFF98FFC2FFEAFF1000C7
+:100750003400550075009300AF00CA00E200F800B5
+:100760000D012001310141014F015C016701700160
+:1007700079017F01850189018D018F01900190012F
+:100780008F018D018B01870183017E017901730146
+:100790006C0165015E0156014E0145013C013301CA
+:1007A0002A01210118010E010501FB00F100E800FA
+:1007B000DE00D500CC00C300BA00B100A800A00044
+:1007C00097008F0087008000780071006A00640045
+:1007D0005D00570051004C00460041003C003700CE
+:1007E00033002F002B002700240020001D001B00D9
+:1007F00018001500130011000F000D000C000A0076
+:080800000900070006001100C9
+:00000001FF
diff --git a/firmware/R1f.2_SoC1v20_Cobra_FM_SOC1_coef.fw.ihex b/firmware/R1f.2_SoC1v20_Cobra_FM_SOC1_coef.fw.ihex
new file mode 100644
index 00000000000..b67325acdc0
--- /dev/null
+++ b/firmware/R1f.2_SoC1v20_Cobra_FM_SOC1_coef.fw.ihex
@@ -0,0 +1,195 @@
+:1000000005009F23140C0000E8FFA6FF2FFF91FEC0
+:100010002EFE91FE5000D803E6089D0EAD139D16EE
+:100020009D16AD139D0EE608D803500091FE2EFEDE
+:1000300091FE2FFFA6FFE8FF0504F60B0014F11B4D
+:10004000F11B0014F60B0504B601DF03C2054407DB
+:10005000530890095E0ADF0ADF0A5E0A9009530816
+:100060004407C205DF03B6012F00D900630245052E
+:100070006209210E7C12021502157C12210E620902
+:1000800045056302D9002F0048FAF0E197BED5A3D9
+:1000900008A404BF43E25FFAA105BD1DFC40F85B64
+:1000A0002B5C6941101EB805B3FACCFC0FFA47FF70
+:1000B000CD064E11A61CFD21FD21A61C4E11CD061C
+:1000C00047FF0FFACCFCB3FA87108101F801B801A1
+:1000D000EA000502020000000000FF7F70177017A1
+:1000E000FF7FFF7F1F001F00E40016022100210098
+:1000F000200020002F02D8015A0000000004000454
+:10010000A6FF000400000000C264020001006F4569
+:10011000020000000100C264C2642C43030002001C
+:1001200002009D104D0121020100A91AAA3C010004
+:1001300010016A07C20027005206DD00CE04FF7FCF
+:10014000FF7FC70AE1251400860140051517280026
+:10015000C300A902650E4E004E0010016A07C200DE
+:100160002700CE10A3018202000084035A00A400DD
+:1001700092027245FF7F0000FF7FA4009B02FC6695
+:10018000FF7F0000FF7FA400A402FC66FF7F000049
+:10019000FF7F4700AD02A202A302AB02AC029902AC
+:1001A0009A02FFFFFFFF180007080B280D0812082E
+:1001B000134814082228264829282A282B482D28A5
+:1001C0003548372839083B283D48404842484428AC
+:1001D00045084B084F4852280F00700855285728EB
+:1001E00059285B285D285F8861086428662868288C
+:1001F00070086A286C286E281000712873287548CA
+:10020000772879287B287D287F28812883288528BE
+:10021000872889288B288D288F28380096689B2866
+:100220009D089F08A128A328A528A728A928AB488E
+:10023000AD48AF48B048B128B388B528B768B928E9
+:10024000BB88BD08BF28C728C828CA08CD08CF2842
+:10025000D128D308D508D728E048E348E628E8881D
+:10026000ED28F208F4A8DC28F90800290629082955
+:100270000A290C290E09100912091409160918492E
+:100280001C2922492F293129332935C91C003869F5
+:100290003D293F2944097409472949494B894D297A
+:1002A0004F295129530957295A495C296109642961
+:1002B00066A968296A296C296E49702972A974098E
+:1002C0007529740977290B008229844986C989090F
+:1002D0008DE9910993E99429952996A99B092849C3
+:1002E0000000084800000C7800200D600000F42693
+:1002F00000500C7800280C7800280D7800000D784C
+:1003000000200C7800200C7800000C41000436011D
+:1003100000041E5100041C5100040C590004E56245
+:10032000C6207013A40D5D0A3C08B9069705B304F6
+:10033000FC036403E40278021B02CB01850148013F
+:100340001401E600BF009D008000670052004000DD
+:10035000310025001B0013000D0008000500E262BB
+:10036000BE206213920D460A1F0898067105890483
+:10037000CD033103AE023F02DF018C0144010601CF
+:10038000D100A2007B00C31141007C007B00CA1198
+:1003900084001A03F6FF0060A4000300E0110400CB
+:1003A00039030C6080408240770404003E032C60D7
+:1003B000A040A240780401004303CC6004005B032A
+:1003C000B800B00161044503B51222004504006085
+:1003D0000035880072030E0003000A000E00E513CA
+:1003E000007018000F0028007F030003000C000EAF
+:1003F0000060010000600001002028008803380030
+:1004000040030000FF7F0100FF7F00010010280073
+:1004100091030004000A0000FF7F0100FF7F000439
+:10042000002028009A030000C000001800600100AE
+:100430000060800000082800A3030C003800004082
+:10044000FF7F0100FF7F000200102800AC030000C6
+:100450000004000400780100006000040010150092
+:10046000B5030001000880000004000400208000A3
+:1004700000024000000100010010200000010008FF
+:10048000100040000001000A800010001500CA039F
+:100490000010002000400040004000020004004026
+:1004A0000008007000010040000200080040000148
+:1004B000FF7F00200020001000046600E103000818
+:1004C000100099597900BFE040002500EF03870430
+:1004D000EC0316012C02BD0A4400F5035C04ED0395
+:1004E00033033D0A0600FB037003EE03D83B2549A6
+:1004F000BE0ABE0A6A000104FF7F008000000000FF
+:100500000000800200000000000E00206A000E04BF
+:10051000FF7F0080000000000000000B00000000D2
+:10052000000600206A001B04FF7F00FC00000000A2
+:100530000000000800000000000100204B0028041B
+:10054000FF7F00FF8003000000000014800800000F
+:100550006000002080032C003504FF7F80F700102E
+:100560000080000000020000001200020018001DC0
+:10057000001855859FFF009041FFAB9ABDFE55A521
+:1005800008FE00B013FDABBACCFB55C510FA00D085
+:10059000A2F7ABDAFDF355E5C6ED00F0F8DFABFAF4
+:1005A0005B9DF8FFE8FFC9FF9BFF5FFF1CFFDEFEBE
+:1005B000BDFED0FE36FF0600530120035F05F107A4
+:1005C000A30A3B0D760F1A11F81103000000F6FF85
+:1005D000D9FFA6FF59FFF9FE95FE4CFE46FEB3FE7D
+:1005E000BBFF7A01F20307077A0AF30D0A115D13C4
+:1005F0009D14090018002E003F003E001700BBFFAD
+:1006000025FF6AFEB7FD59FDA3FDE9FE5A01F4047A
+:1006100070094B0ED71260164F18030011002F00FF
+:100620005F009100B00094001F0042FF19FEF3FC30
+:100630004FFCBBFCB5FE7102BC07F20D1314001990
+:10064000BE1BFAFFF7FFFBFF19005400A600EA00EB
+:10065000EA006B0052FFC6FD47FC9CFB9FFCEBFFD2
+:100660009105E70C9F14121BBE1EF7FFE3FFC7FFA7
+:10067000B7FFD3FF2F00C7005F019401F80060FFB0
+:100680001DFD1BFBA5FAF8FCA6022B0BDC14581D64
+:100690004C220200F9FFE0FFB3FF8FFFA1FF15001E
+:1006A000E700C10104021301C9FED9FBD6F9ADFA76
+:1006B000BEFFF8088014231F86250C001C002400B0
+:1006C0000400B2FF50FF36FFBEFFF1003F029D0263
+:1006D0001C01C2FD13FAC0F865FCE9057913DB20A3
+:1006E0002C2907001D003C00460010008FFF03FF6F
+:1006F000F9FEE2FF97010403A802AFFF1EFBFCF71F
+:1007000000FA3C033A12F021002CFBFFFFFF170018
+:1007100048006200250078FFC4FED6FE3C006B0254
+:100720009A03DF0117FD1EF8DAF71F006310D622C7
+:10073000182FF7FFE8FFE7FF16006E009D0031005D
+:1007400026FF4AFED6FE2901BB03B90376FF09F94D
+:100750003FF600FD350E7B232C320200F3FFD5FF60
+:10076000C8FF0A009500E1003900B9FECEFD2BFF5D
+:100770009302E60468022DFB4FF570F9240BD82391
+:10078000CA350E001800FFFFB6FF8EFFFAFFE0002B
+:100790003601FBFFE1FD77FD7E00C304E10407FEA7
+:1007A0006FF54FF6C807D02349390B002B003E00E8
+:1007B000030080FF58FF2B0069014A0100FFC8FCBD
+:1007C00043FE6A035D0614018AF6D4F34D045923EF
+:1007D0007D3CF6FF02003B006E00190049FF1AFF46
+:1007E0007100FC01070199FD3DFCA900A1069F04D1
+:1007F00006F9BCF1F6FF5A224940FAFFD5FFBEFFC9
+:100800001000A400760033FFAAFE9200B002C600DA
+:1008100023FC7EFC2D04370817FEA2F0BFF90B2045
+:1008200082450D001A002F00450064008C00BE00B8
+:10083000F60034017A01C50114026102AD02F5022D
+:1008400037036E039903B703C703B703B8F38617DB
+:1008500053E0AD1F7AE8480C49FC531427004804C4
+:10086000ECA90001000A0700FFFF3002002005008C
+:1008700072042000200080001000000003008404A7
+:1008800000012000FFFF03008D0466086608FFFFDB
+:10089000240096048404FF7F0000FF7F43009B0434
+:1008A00000101900FFFF0200A40463AC01006614ED
+:1008B0004200C204E04000410300C604E840602159
+:1008C000AD040300C90408417021AC040200CC044B
+:1008D0008021B5040000000C5B030100000C4008FF
+:1008E00021018C066F14D4FFF700B8FCC50826EA76
+:1008F000914F914F26EAC508B8FCF700D4FF0700D6
+:10090000EDFF2B00ADFF920010FF7601CEFD360308
+:1009100061FB9F0659F6D20EC0E52D512D51C0E561
+:10092000D20E59F69F0661FB3603CEFD760110FF0D
+:100930009200ADFF2B00EDFF07007EFFA301BFF982
+:1009400039413DFF74029EF6D56165FF75011AFDC0
+:10095000FB09781700E03EE0902120612A613661B2
+:10096000A021A521AB2140804E805D80400801057B
+:10097000BA4D721C0E01B604F90011474CF5C3754F
+:100980000000030001000100DD14A106C714A50644
+:10099000FF7FFF7F000000200040006000A000807B
+:1009A00000A00080E80900804D460080E909008031
+:1009B00058200080EA090080696D0080EF090080FE
+:1009C00020740000960C0C1944251E317F3C4847CA
+:1009D0006151AF5A1C63936A02715B768F7A957D81
+:1009E000677FFF7F677F957D8F7A5B760271936A61
+:1009F0001C63AF5A615148477F3C1E3144250C1996
+:100A0000960C00006AF3F4E6BCDAE2CE81C3B8B813
+:100A10009FAE51A5E49C6D95FE8EA58971856B8274
+:100A20009980018099806B827185A589FE8E6D9574
+:100A3000E49C51A59FAEB8B881C3E2CEBCDAF4E61F
+:100A40006AF30000060DE11964266832C63D5A4873
+:100A50000652AF5A3F62A868DF6DE071AE745176FE
+:100A6000D6765276DA748D72896FF06BE967976388
+:100A7000225FAF5A61565C52BE4EA14B1F49484798
+:100A80002A46CD452A4648471F49A14BBE4E5C52D7
+:100A90006156AF5A225F9763E967F06B896F8D7279
+:100AA000DA745276D6765176AE74E071DF6DA8684E
+:100AB0003F62AF5A06525A48C63D68326426E11971
+:100AC000060D0000FF7FDD141D15540690082D490A
+:100AD000C208C003E4080000420900004109000008
+:100AE0007909000055090009D9080000E808839039
+:100AF00091083D0070090000A4081100A408370007
+:100B000090082D79C208C003E408000042090000E3
+:100B10004109BA075309430655090009D9080000DD
+:100B2000E80883907009000091083D00A4087E0049
+:100B300096080040970800409008BC99C208C10B75
+:100B4000E40800404209C3004109000053090106BE
+:100B500055090109D908000070090400E8088790C8
+:100B6000BE1588007207D6064E0062000000020023
+:100B70009A019A010100A5008A0700007F00FF0189
+:100B8000C8327F00D6069A01F00518017805F802F0
+:100B900020062706020028062F060100A907B10734
+:100BA0000200B207BB070100B107D6061E068C057E
+:100BB000E803F3073A078106C805E8039264005882
+:100BC000394E6646004024490040E33833338B2ECB
+:100BD000E61B6A18B3158813C111A3502A5CAE67CF
+:100BE0003373B87E4009FF934309070347097F0E1B
+:100BF00048091DA8490902004A09880790082D499B
+:100C0000E40800005E0901005C09901A5009080020
+:080C10007E0900932109080090
+:00000001FF
diff --git a/firmware/R1f.2_SoC1v20_Cobra_FM_SOC1_prog.fw.ihex b/firmware/R1f.2_SoC1v20_Cobra_FM_SOC1_prog.fw.ihex
new file mode 100644
index 00000000000..ee70c7a36e0
--- /dev/null
+++ b/firmware/R1f.2_SoC1v20_Cobra_FM_SOC1_prog.fw.ihex
@@ -0,0 +1,3060 @@
+:100000000400EF6726BF000000F0831F80D200F0DD
+:100010000070149000F0300A80D200F07C1F80D273
+:1000200000F0007022A000F0D01A80D200F0021F71
+:1000300080D200F0241B80D200F02A0280D200F08F
+:100040004D1580D200F0091680D200F0A60780D2AC
+:1000500000F0601380D200F0480D80D200F0C50699
+:1000600080D200F0230B80D200F0A01480D200F0E8
+:100070008B1380D200F02A0080D200F0E31480D2EB
+:1000800000F0CA0A80D200F00070108000F0731FE8
+:1000900080D200F000700FA000F0211B80D200F091
+:1000A0003F0280D200F0511580D200F0261680D297
+:1000B00000F0AA0780D200F0621380D200F04F0D4A
+:1000C00080D200F0C80680D200F0310B80D200F060
+:1000D000A01480D200F0931380D200F02D0080D2C3
+:1000E00000F0EC1480D200F0CC0A80D200F0591558
+:1000F00080D000F0F31A80D200F0970A80D200F08E
+:100100009E0980D000F06010086000F0B31F80D21C
+:1001100000F000708AA10082F20108601B020960F1
+:1001200006C01440001000F00602086006C000F08F
+:10013000101000F08434F801096000F0007034A160
+:1001400000F0143600F000F094333DA100F0DB071E
+:100150000A6000F0E801096000F027200280E80151
+:1001600009607CA1113F00700080112F88090A608E
+:10017000F09F42090C60834F222C09D40082442056
+:10018000754E9AC2010806604190932B00F02CC373
+:10019000912E069000F0263200F0AA90132E00F067
+:1001A0004190443015409290A330C0E0932D8409D3
+:1001B000066000F0223C05801B88A0308141DBD026
+:1001C000223C00F0CBC2007000F01CC5A6080660FF
+:1001D00000F0443006A08E91963F00F01630F301F7
+:1001E0000E60B683933004C000F0661000F000F09B
+:1001F0001531E1A000F000706681152F834162A1E6
+:100200004591991B80D21CC3142C09D4C0D703403C
+:10021000059020A0007000F000A8952C00F000CC04
+:10022000007000F04583007000F00BAE007000F02D
+:1002300000F0153100F000F0933008D0E8010960BB
+:1002400057A1913B0070DB8FE801096055A1913EF9
+:100250000070D98FE801096053A1113E0070D78F5B
+:1002600000F087100E60709EE8010960789EEC70C7
+:1002700000E2102F6C7000E200F0650100F000F069
+:10028000662000F00090153C00F000F0963C09D488
+:1002900000F00070CE8F0AA2007000F05382F13996
+:1002A000019800F0733908D05380713900F000F0E4
+:1002B000F33908D0E8010F6043A14090F12A00F023
+:1002C00000F0703BF88FE8010F6040A100F0702B48
+:1002D00000F000F0F13AF58FF09FE8010F6000F0B8
+:1002E00012400394419070283BA100887235C0E011
+:1002F00000F0703A08D00082FF7F02604190703AAF
+:1003000000F09282703540E000F0F23708D0E8014A
+:100310000F6034A100F0F13808D000F0F82F00F0A1
+:1003200000F0792000F000F0F32000F000F0002051
+:1003300000F000F0112000F018A0742100F058B077
+:10034000732400F008AF7824074209BFF42400F0BA
+:10035000C390F92400F00491002000E600F0112081
+:1003600000E638A0722600F078B0E07F06601586BF
+:10037000F32500F010821540029CF3A20070039850
+:1003800000F000580280F3A20070019C00F0FF7F93
+:10039000006059A1007000F0B1A0742700F003A81C
+:1003A000FF7F0560F3A8733600F0EDC2F32600F07E
+:1003B0006586F53500F061821540029CF3A200705D
+:1003C000039800F001580280F3A20070019C00F035
+:1003D000FF7F016059B1007000F031B1007000F092
+:1003E00003B8FF7F0560F3B8733700F0EBC2F7285E
+:1003F00000F000F0F33600F0FF9F742900F000F0E9
+:10040000F5290598FF9F007002900190007040E070
+:100410004090007002800884007000F0019000702D
+:1004200000F020A0007000F068B0007000F050AA4A
+:10043000742A00F051BAF32700F065DC772500F04C
+:10044000E382007000F0FF9F0070029C00F077359F
+:1004500000E2EBD7B30A80D318A2F33700F059A219
+:10046000F03100F000F0713208D00689007000F021
+:100470000F8913231440BE8D952200F018A100703F
+:1004800000F0AE83007000F09220122040EF00F0E8
+:10049000FF7F076091A1007000F006A8007000F0D7
+:1004A000AE81122200F0F3A8963200F0FBC2007079
+:1004B00000F08290133300F000F0132409D0068975
+:1004C000952300F018A1132500F0AE83922100F0CF
+:1004D00018B1122100EE0C89007000F091A100709B
+:1004E00000F006A8007000F0AE81952400F000F046
+:1004F000963300F02C83922100F0F6A8122100EE32
+:10050000BEC3007000F011B1007000F004B81634E2
+:1005100000F02C81007000F0F4B8943400F03CC37B
+:10052000007000F000F0143508D000F006020860FA
+:1005300000F0662400F000F0642500F000F0E524EF
+:1005400000F0A2A3007000F0AA80E52000F093A3C1
+:10055000E62200F01B83E23400F075A3672300F06D
+:10056000AAA2633500F0F383E42300F000F07528BD
+:10057000079000F0E235039CAE83007000F0BE8D62
+:10058000007000F000F0E6320E80AE81007000F0E6
+:10059000C691007040E100F0E6320B8000F0632667
+:1005A00000F03C9FE23500F0FB9E00700894C7917C
+:1005B00000700594E321632140E6C791FF7F02604C
+:1005C000E38C024000E6C390007000F000F062335C
+:1005D00000E6E38C007000F063367201046000F006
+:1005E000822300F000F0E43300F000F0862200F0F7
+:1005F000B29E072300F000F0E02500E2F383E1253E
+:1006000000E200F08225059000F00070029CAE83AD
+:10061000007000F0BE8D00700280AE81007000F0AE
+:10062000C691007040E130A2842400F071A28632AD
+:1006300000F000F0003700F000F0813700F0049186
+:10064000842F00F0BA9E032509D4349F823509D443
+:10065000C3909422119400F08520069000F0832628
+:1006600000F02C8F022000F0FB9E8321C0E200F0FE
+:100670000422054000F0833600F0C3900436078062
+:1006800000F0052100F000F0032600F0648FF24135
+:1006900000F0FB9E0322C0E200F08421154000F030
+:1006A000033600F0C390843600F00240023400E2CA
+:1006B00000F0053500E2FF83023340E283237C0033
+:1006C0000D60042472010260F683552100F0E68279
+:1006D000823509D44591842F09D0B683007009D0A2
+:1006E000349F007000F00041991F80D37C000D60A2
+:1006F0008FA0532100704BA0C390007000F000F059
+:100700000070069000F0100B80D228C6007000F038
+:1007100000F00070039041915D0280D24790080B79
+:1007200080D20040771A80D20602086085A0002798
+:10073000E8010F608127007008D02109086000F0EF
+:1007400000F0902B824200F00120F44DB683152D6D
+:1007500000F061C2923300F0F29F132F04427A9F9F
+:1007600016330394C29000700294029000700194BA
+:1007700061C40070C0E000F0013008D000F0F02B40
+:1007800000F0722D21090860732FC0000660BA9E28
+:10079000F42300F0C390752309D40090007009D4AD
+:1007A0000491022009D04591F3220B94B2C200704B
+:1007B00008948F02026009D000F0991B80D2C0D744
+:1007C000007000F010A2007000F018A0007000F09F
+:1007D000F5A9007000F0F4A875330044F433991FB4
+:1007E00080D07D9F007000F000F0753300F03C9FDA
+:1007F000007000F000F0F43308D000F0E801096068
+:10080000A2459B1B80D280A242090A6000F01038EA
+:1008100000F000F02420FBAEF8010E603B80E80100
+:1008200009605CA000F0113DD88FE80109605AA072
+:100830000082913200F000F0903300F000F01033AD
+:1008400008D016020E6056A000F0E12300F000F080
+:10085000E22408D016020E6053A00082613200F03C
+:1008600000F0E03300F000F0E03400F000F060341D
+:1008700000F000F0603508D01140832F06A0FB9EE9
+:10088000813500F0F3410320C0E2013516020A6011
+:100890004982033400F000F0A13200F000F021336F
+:1008A00008D000F0002200F000F0822100F000F0FB
+:1008B000003600F000F0823608D00602086042A040
+:1008C00000F00424064000F0F8010E600591FF7F5F
+:1008D00007603D9F84330990359F0070099000F0B8
+:1008E000007001901540073308D000F062223AA052
+:1008F0008290652100F000F0E52100E2FF830733DC
+:10090000C0E000F0653600F01540673308D00540C0
+:10091000063308D01540063308D040900602086020
+:10092000F241007040E000F0813F00F000F0023042
+:10093000E1AF00F000709E8F060208602DA000F06D
+:10094000813000F000F0023100F000F0833100F05F
+:1009500000F00432E28FF8010E6028A000F0E130D0
+:1009600000F000F0623000F000F0E33100F01140E0
+:10097000643100F000F0653200F000F06136008074
+:1009800000F0460B056062209B1B80D217405E4B37
+:100990000660A8A0E53400F0B9A1007000F065AAD7
+:1009A000007000F045A30040076092D7E12000F0FE
+:1009B000D783653400F079A2007000F000F0613553
+:1009C00008D00602086016A04190822F00F000F0C7
+:1009D0000120CD93BA9E007000F041900070CB973B
+:1009E00000F00140CA9700F0F241DD8F0602086076
+:1009F0000FA000F0803408D006020C600DA0C62FB6
+:100A0000100B80D20190C5230240B69F007000F009
+:100A10004D99007009D41240224040E600F0007069
+:100A200008D000F0E8010F6000F000708DAF00F01A
+:100A30000070D1AE1602096008AFF8010E6027AF52
+:100A400000F0421480D200F00070398000F0007095
+:100A500008D000F08D10086000F0B31F80D000F0C7
+:100A600028020860B683FF7F076000F0063700F0B9
+:100A700000F0873200F000F0863500F0BE9F872F2F
+:100A800000F000F0863400F000F0073300F000F0D2
+:100A9000072E00F000F0063400F000F0873308D095
+:100AA00028020E60F1AF4190E32F00F000F0E13C2E
+:100AB00009D000F0633308D000F0280208600090ED
+:100AC000007000F000F00035EE9300F0007008D0E8
+:100AD00000F028020E6000F0D148066049D0613D68
+:100AE00000F000F0623E00F070A0E23300F011AAC6
+:100AF000007000F000F0E13D08D089D39D10076040
+:100B000009D528020E607980CE04066092D3E137C1
+:100B100000F012D5E52F00F0BA80ED2700F000F0CC
+:100B2000E23700F000F0542100F000F0D220EC2772
+:100B3000A6815120E43FA681C221623F6583E13E48
+:100B400000F000F0643300E600F0623000F000F0E6
+:100B5000E63008D000F0642500F000F0E52100F058
+:100B60000491E42000F000F0EC210894648F6523E8
+:100B700000F0CE040C6000E27D9F007000F00040A9
+:100B80004020C0EB00F0401000F065334120C0EB86
+:100B900001404110C0E100F0EC3108D001400040BC
+:100BA00008D0028928020E600B89007000F09A8C30
+:100BB000E62DC4AF928DE42500F0938FE52C00F074
+:100BC0001C81623600F04591E43500F000F0E32628
+:100BD00009D000F06727EAAFD48E652400F000F05A
+:100BE000E03704908390E02E00F0FC82E52F00F0C7
+:100BF00000A3007000F000F0E03400F07D9F64205E
+:100C000000F000F0E0240198055865340480B887AE
+:100C1000FFFF056020A2007000F0288A007000F03D
+:100C2000C391E0340558C781E33600F07F9F007020
+:100C300040E1DF8B602F00F0BD8F673703583DCC5C
+:100C4000E2220194FD9E66370B807FC1B786046067
+:100C500076C1A3B50360E5A3007000F05D811B8041
+:100C60000360ECA3007000F0E482007000F028A1A3
+:100C7000007000F014AA007000F030A1FF7F036044
+:100C800015AA007000F0C590007040E155836532F0
+:100C900000F02DA2E02700F05581007000F028A29E
+:100CA000E53200F069A2007008D0008228020F60CF
+:100CB00000F064060E6000F0712100F000F0F323F4
+:100CC00000F0799EE22200F0FB9E713109DC00F019
+:100CD0007231029800F0F03500F000F0F33308D0E4
+:100CE00000F0F42500F0399E732E00F0049100709E
+:100CF00000F0FB9EF13309D000F0F33300F0F03543
+:100D0000BB0A80D0A1406902086096000260E4A19D
+:100D10008130444651A301306B0209602233A54063
+:100D200000F02434A64000F0A533FF7F076026368C
+:100D3000C8000060A732014500F04032024000F0D8
+:100D4000C132007000F02237E8030360A237670267
+:100D5000086093309001046013308116096084307C
+:100D600008000560023066080660D532007000F0A9
+:100D70008F90963000F0B733163000F000F0323725
+:100D800008D069020860D0A100F0731580D26B0210
+:100D9000086000F000F0731580D0690208603EA37F
+:100DA0008230771580D0690209603CA300F0902062
+:100DB0003BA300F0003008D000F0791580D0450248
+:100DC0000A6000F0690208602BA300F0202A00F0FE
+:100DD00000F0022000F000F0A12900F082906A15D6
+:100DE00080D06B02086000F0D41B006000F000F0BF
+:100DF000022000F08303016000F082906A1580D029
+:100E000000F01B1E80D245020A6034A200F0007080
+:100E100056A2000400606FA200F00070B7815B0969
+:100E2000086020A3801608602183801608601EA336
+:100E300000F000701E82439045020A60008000604E
+:100E400000F000F0C70480D3C190007008D04502C4
+:100E50000A6000F0008000605FA2DF02026009D03B
+:100E60004F02036000F000F0A23900F000F0233AD6
+:100E700008D01140361680D20090007000F04090EB
+:100E80000070C0E00090007008D000F08A160E607C
+:100E90000082007000F000F0603100F000F060327D
+:100EA00000F000F0E03100F0F400006000F04502D6
+:100EB0000A60B9A1213C10401BA274020060D48FCB
+:100EC00045020A600DA300F0202CC7A100F0A13C50
+:100ED0000CA278020060D08F45020A603DA2720227
+:100EE0000B603DA24040FF0402601340214055A228
+:100EF0007D020060CB8F00F00070F0A1A02F8A1659
+:100F00000E6000F0212000F000F0E03200F000F070
+:100F1000613300F0830200607A8345020A60FEA21A
+:100F2000A02F8A160E602120007000F000F06030C3
+:100F300000F000F0E13000F089020060788300F0FA
+:100F40001B1E80D200F00070FFA1D41B0560F2A22E
+:100F50000008006037A200F0A02EEDA100F06902A9
+:100F60000860A539731580D200F0B40A80D28205DA
+:100F70000060B68F00F000707DA100F00070FC8F63
+:100F80000004016000F053020860E4A208C200708F
+:100F900000F0088E007008D000F0361680D2009065
+:100FA00045020A60F400006009D40004006028A231
+:100FB00000F0681380D2F400006000F000F00070D0
+:100FC0008CA100F0213CE3A1A1020060A78F4502A3
+:100FD0000A60E0A200F0202C9AA100F0701B80D2E1
+:100FE0000090A70202600988007040E18090A13C57
+:100FF000A18F00F07B1380D245020A6009D000F077
+:101000006E1380D272020B600CA28040FF0402605B
+:101010001340114024A2F802006000F04702016072
+:10102000358200F0721380D2B1020060978F4502C2
+:101030000A60D8A100F0771380D20004006013A2E8
+:1010400082050060938F00F08A160E6000820070A7
+:1010500000F000F0603100F000F0603200F000F0CD
+:10106000E03100F000F00070F5A1045431000060A0
+:1010700045020A6088A10091A13CD8A100F020405F
+:101080008DA200F03040A5A2C1020060878F044607
+:10109000CFFF006045020A6082A10091213DE4A1DA
+:1010A000C5020060838F87900060E1A145020A605D
+:1010B000F0A100820070F8A14040130502600340D7
+:1010C000114007A2CB0200607D8F00F00070A2A14A
+:1010D000A02F8A160E6000F0212000F000F0E03210
+:1010E00000F000F0613300F0D10200602D83450272
+:1010F0000A60B0A2A02F8A160E602120007000F0B6
+:1011000000F0603000F000F0E13000F0D702006045
+:101110002B8300F01B1E80D200F045020A600008FD
+:101120000060EDA100400060ECA100800060E8A13B
+:1011300000F0A02E9EA100F0B40A80D282050060CB
+:10114000698F45020A60D0A12026DA0F80D2E20220
+:101150000060668F00F045020A6000F09D1B80D29F
+:1011600000F0A03C00F00041F70402600340114091
+:10117000EAA100F0E902006047020160FB8145023C
+:101180000A6098A200F0A02209A000F0222396A2F3
+:10119000878EA32700F0580300605A930040006038
+:1011A000D3A1C39000700290550300605797004090
+:1011B0000060D5A140000060D4A1FB020060548F04
+:1011C00000F021218DA20882007000F000890070DB
+:1011D00000F000F0203508D045020A6089A2FF7FA8
+:1011E0000060FAAF00F00070F78F8D1608607EA2E5
+:1011F000089000707FA200F05B09086000F04502D3
+:101200000A6000F0002000F0B683A12600F0F74746
+:10121000252500F00880A03400F0328C80000660A4
+:10122000BA8AA53500F086C3023000F000F0090349
+:10123000006047020160DC91120300603F8F4502AD
+:101240000A6000F000080060B7A1FF7F006000E6C0
+:1012500000F0A02200E200F0212174A208820070B8
+:1012600000F00089007000F000F0203500F012035B
+:101270000060368F45020A606FA2222500080060D8
+:1012800000F0A325ADA100F0A52609909F8EA42310
+:101290006BA2A78E00700390AF0200602F974000F2
+:1012A0000060ADA1FB0200602D8F40000060A6A190
+:1012B0002D8800700D9000F000700FA0AF0200604C
+:1012C000298F9F8E242462A2A78E0070039055035D
+:1012D0000060269740000060A4A1FB020060248FFC
+:1012E000400000609DA12D8800700490F40103600F
+:1012F00006A000F0A33700F0004000609BA155035A
+:1013000000601E8F00F0A53602A04000006098A18A
+:10131000FB0200601B8F00F045020A6000F05B09D1
+:10132000086000F0A02400F000F0A12500F000F01B
+:10133000003000F000F0213508D000F000704AA223
+:1013400000F04130378245020A604CA22026DA0FB5
+:1013500080D238030060108FCFFF006000F045029C
+:101360000A60F1A00082213C85A13C0300600C8F43
+:1013700045020A6045A200F0202CFFA0A13C0040DD
+:101380004FA100F0007043A141030060078F00F0FF
+:1013900045020A600041FF040260034011408DA134
+:1013A00000F046030060580201609E8100F01B1EA1
+:1013B00080D200F0007042A100F0007023A200F083
+:1013C000402010A200F0204001A200F000544AA1E9
+:1013D0004F03006035A200F0A03A00F05A0300600D
+:1013E000F98EDF0200602EA2A0396902086000F0C9
+:1013F000007062A100F0731580D200F0B60A80D2AE
+:1014000082050060F38E5A03006028A25803016031
+:101410002BA200F0A13AF08E45020A605BA1202ABF
+:10142000791580D045020A6000F0800300606BA14E
+:101430005D030060EB8E45020A6000F00041F70496
+:1014400002600340114071A100F062030060570286
+:101450000160828100F000701BA200F0C12000F04A
+:1014600000F042211DA2538220251CA21B89A03519
+:1014700000F000F02335BD8200F03040E3A100F021
+:10148000F040FBA1FF7F00602BA1839000603BA197
+:1014900000F0A04700F000F00070E1A000F0701B29
+:1014A00080D20090007000F00988007040E1409008
+:1014B00000704EA140D800700BA20040A03C28A1B3
+:1014C00000F0007028A176030060D28E45020A6009
+:1014D00040A10042F70402601340114058A17A0372
+:1014E00000600A8300F01B1E80D2004000601AA139
+:1014F000879000602AA14F02006000A2203A0240BB
+:1015000000F0014069020860D231731580D200F00A
+:10151000B50A80D282050060C58E00F09D1B80D286
+:1015200040D80070F9A100F0A03C2AA1839000608F
+:1015300020A1F040DA0F80D200F0F704026000F042
+:10154000800000601340114046A15F02016000F07E
+:101550008D030060578100F00070F0A191030460DA
+:1015600003A30091910680D593030060B78E5E02BD
+:101570000160ECA19303006051818790006013A18A
+:1015800000F000701FA1D41B0060B28E00F000704C
+:1015900019A100F00070D6A000F0A02F00F000F01C
+:1015A0002120E8A108840070E0A09C030060AC8EBC
+:1015B000839000600AA100F02040AEA100F0F0404E
+:1015C000C6A100F0007017A1A1030060A78E00F073
+:1015D0009D1B80D201900070DBA10082A13C1CA168
+:1015E00008900070A1A100F0405002A100F0F0406E
+:1015F00000F000F001407CA080400905026013402B
+:10160000114027A1AC03006000F06702016038813F
+:101610000082007099A100F0007006A100F0BC0AE1
+:1016200080D282050060988E67020860D1A100F028
+:10163000002000F000F08120CFA1408E007008D083
+:1016400072020B60CDA100F0B123CCA14190450204
+:101650000A60389E00700B9000F000700594F34013
+:10166000007068A0C090014069A00010006008A14F
+:1016700000F01040D1A0C70300608A8E00F0007017
+:1016800063A00082014064A00010006006A100F089
+:101690000040CCA0C7030060858E0140FF7F006042
+:1016A00000F0660D80D200F0690D80D200F000706D
+:1016B0001F80F400006000F045020A6060A04090C6
+:1016C000213C73A01040A13CC7A0CC0300607C8EDD
+:1016D0000040DA0F80D245020A60B5A072020B60AA
+:1016E00000F00082FF0402602340114000A1D203F9
+:1016F0000060768E45020A6000F000100060EEA0E7
+:101700001040007002907B02016000F0DA0300607C
+:101710000D8100F000706EA17D02016000F0DC031D
+:1017200000600A8131010260A3A100F0B0240380AF
+:101730000082007069A1A4040260A0A100F0B0259D
+:10174000008000F0007071A000F0660D80D200F003
+:1017500000707FA000F0690D80D200F00070A6A09C
+:1017600000F000703BA000F01B1E80D200F0BC0A0D
+:1017700080D282050060608E00F0007095A100F0BC
+:10178000302400F000F0B1247CA000F0303600F0EE
+:1017900000F0B13600F000F0302500F000F0B12587
+:1017A00078A000F0303700F000F0B13708D0029098
+:1017B000007006A0BA9EF206046031253124C0E212
+:1017C0001E41046000E632273226C0E2B327B3266A
+:1017D000C0E200F00070598000F08C1B80D20190B4
+:1017E000941B80D209807805006000F072020B60C3
+:1017F0004082007008D000F00070FAAF00F0312491
+:1018000000F000F0322600F000F0B3266080800285
+:10181000086078A10090007008D0720208607EA174
+:1018200000F0802400F000F0812500F000F000348A
+:1018300000F000F0013508D000F0007000F0A03B8F
+:101840000B04006000F0213B3D8E45020A6076A14A
+:1018500000F0A12B75A1799E202B00F000F0A13B98
+:1018600009D400F00070388E00F045020A60D41BE5
+:10187000006070A100F0A03900F000F0203A08D01C
+:10188000E54F41090860399E5509096042402240F0
+:10189000C0E20320F9FF016016400640C0E2CBC25F
+:1018A000142000F0D3C4007000F02CC3007000F0CE
+:1018B00034C5033000F000F0143008D000F00070A0
+:1018C00003A000F00070008050405509086000F04F
+:1018D0000070A88050405509086000F00070A98091
+:1018E00002D15309086008FF03601DA118C20070EF
+:1018F00000F010C4007000F008C400706080039015
+:10190000007000F0008200700180039000700BA056
+:101910000289991B80D29A80007000F012894008D9
+:10192000086016CC0209016092C1007000F080D7F7
+:10193000023000F000F0803000F000F0813112C081
+:1019400000F0007000F0969D01214CA189C100704B
+:1019500008D000F0441E80D278A0007000F031A0C2
+:10196000411E80D27AA0007000F032A0007000F01A
+:1019700070AA0070458101524008086003CC02093A
+:101980000260C0C0813000F000F0003000F000F0D4
+:10199000823112C000F0007000F0FB9C01213EA1DA
+:1019A000C9C0007008D002900070F1AF1280991B7E
+:1019B00080D2D2D04008086080D7007000F000F0DC
+:1019C0000209016000F0823000F000F0003000F009
+:1019D00000F0813112C000F0007000F000F0012131
+:1019E0003381C2D8991B80D240080860F78F400825
+:1019F00008600CA000F04008086005CC007000F002
+:101A000040C9007000F026CC007000F0A2C9007040
+:101A100000F0818E007000F000F000700294D2DFC0
+:101A2000007000F0BE9F007000F000F00070EDAF9D
+:101A30004090007000F07183007008D010A000701A
+:101A400000F0C8AE007000F00880007008D0B849FF
+:101A50000460FCAF20A0534000F000A8007000F02C
+:101A600000CC007000F0C182007000F008AE007081
+:101A700008D063403C5602604082007000F010A025
+:101A8000007000F000A8007000F000CC007000F0C2
+:101A9000C182007000F008AE007008D062408C1B5C
+:101AA00080D20190941B80D208808360016080D72F
+:101AB000208F036014403402056045020A6008A0CC
+:101AC0002630B35901605240059803600440F40089
+:101AD000056000F0374004A0B881A63F00F0A03DAB
+:101AE00072020B6000F0203E08D05B0908600C8099
+:101AF00000A0007000F08EAE007000F08EA30070A9
+:101B000000F018A0007000F009AF007000F08E81A6
+:101B1000007000F0AE81007008D0A040500908604D
+:101B200000F0007045A000407009086000F00070EF
+:101B300043805A09086000F000F0007000F000F0E7
+:101B4000003008D0A0405009086000F0007041A0AB
+:101B500000407009086000F000703F8000F07009DC
+:101B60000860389E0100006000F00070399000F0BD
+:101B700000703B8000F070090860389E0200006031
+:101B800000F00070359000F0007037809608086013
+:101B9000F1AF97080860F0AF98080860EFAF9908B8
+:101BA0000860EE8F96080860E7A000F00020E6804D
+:101BB0009A08086001809B080860008041D00258A4
+:101BC000A4A0C9D7007000F010C2007000F008C4D3
+:101BD0000070E78F9A08086001809B080860008009
+:101BE00000F000709EA040D0007000F0C0DF0070D8
+:101BF00008D0E8080860E08F9C080860DFAF9D0807
+:101C00000860DE8F00F09208086000F0004021A01C
+:101C100000F0F0401D8000F09208086000F0F040F5
+:101C20001EA000F000401A80BC070060D1A041094E
+:101C30000860D6AF0000006061AF2740C60780D0C3
+:101C40000082007000F041090860D28F0041D90F76
+:101C500080D00041DA0F80D000F0B12FC9A04290AF
+:101C6000007000F07A9E0070039000F00070039006
+:101C700000F0007001A0008800700180C3080860B7
+:101C8000C98FC7080860C88F93080860C78F950878
+:101C90000860C68F00F02127BFA041C2007008D0A5
+:101CA00000F02127BDA041C4007000F000F02137F2
+:101CB00008D000F0007000F000CA2127B9A041C28E
+:101CC0000070FC8F12400120B7A012C0007000F01D
+:101CD00050C40070BC8F12400120B4A012C000702C
+:101CE00000F012CA007000F050C20070B88F72028B
+:101CF0000B60B0A000F0B03D00F000F0B13F00F08C
+:101D000000F0B23100F000F0333008D0928233207E
+:101D1000ABA0C090FF7F01608116096008B4F09EFF
+:101D2000323E00F000F0B23E029000F0323F00F090
+:101D300000F0B13008D092313C000060113444050D
+:101D4000016010310020006000F09132E68F00F059
+:101D50009B1B80D2C0D7007000F04182007008D079
+:101D600072020B6000F000F00070008000F0B22101
+:101D70009BA000F0007000F000F0007020D0720214
+:101D80000B6098A030314802016000F0202E8FAF28
+:101D9000ED040060F98F4902016090A000F0232E4D
+:101DA00000F000F0A42092A0E08200708AAFF2045C
+:101DB0000060F48F470201608BA000F0232E00F03A
+:101DC00000F0A4208DA0E080322185AF80900070CB
+:101DD000EF8F3032FB04046000F0B132DDAF00F071
+:101DE000A02CBEAF019160400D8F72020B602AA043
+:101DF0000190B82209D000F0302200F000F001304C
+:101E0000498D00F0303200F000F0B132D5AF00F073
+:101E1000A02CB6AF00F0202C84AF0505016000F0C7
+:101E200000F03040038F72020B6020A000F0B92256
+:101E300009D00490302200F000F014303F8D00F003
+:101E4000303200F000F0B132CBAF00F0A02CB5AFD3
+:101E500000F0A02CABAF00F000709CAF0F0501604C
+:101E60000A8072020B6016A00490B92209D000F01B
+:101E700033229BAFC0901430358D00F0303200F02B
+:101E800000F0B132C1AF00F0A02CABAF00F0A02C3D
+:101E9000A1AF00F0007092AF1A05016000F00600DB
+:101EA0000060EE8E72020B600BA00490B92209D084
+:101EB00000F0202DA4AF00F0202D9AAF00F01430D8
+:101EC000B7AF20050160F98F72020B6005A0049086
+:101ED000B92209D000F033228AAF00F010205EA0B2
+:101EE0002484007000F0C0901430228D45020A60F6
+:101EF00012A0759F78020960811608600D9008A2F3
+:101F0000B32E174010A0342E0558D9A1362F00F05B
+:101F100062A1B72D00F08E91FF7F0560BE83363F32
+:101F200000F003A800700390F4A8333E00F02CC327
+:101F3000007000F09282B43E08D039CC124000F01C
+:101F400048AE007000F08290007008D03033720FFD
+:101F500080D2002000608AAF00F0802108D02240AB
+:101F6000B32F48A0C490B12000F0FC9E352004900F
+:101F700000F00070049000F0007002A00390007068
+:101F800002A01884007008D0E30808600180EB0804
+:101F90000860008000F0007000F000F000203E803B
+:101FA00000F045020A60002000607E8F0190420927
+:101FB0000860FFFE0260FBAF10C2125000F04190BB
+:101FC000007000F010C40070C0E000F000703D8FA1
+:101FD0005C09086035A000F0012034A089D70070AA
+:101FE00000F089D0007000F008C4007000F000F02C
+:101FF000003008D05C0908602FA000F000202EA05F
+:1020000080D3007000F080D4007008D000F0007021
+:10201000FBAF08900070F48F00F00070F9AF389EAD
+:102020000070F28F00F0414600F0DB82124000F0B9
+:102030000982A14600F083903240C0E10982014745
+:1020400000F083907240C0E10982614700F0839004
+:10205000F240C0E10982007000F083900070C0E19E
+:10206000C090007000805D090860228F5D090860E3
+:10207000DB8F5D090860DAAF40D0007000F0089097
+:1020800000701E8F5D090860D7AFC0D700701C8F2D
+:102090003642007011A0C0211157076041205555EC
+:1020A00005603882007000F07182007000F048A175
+:1020B000007000F092AA007000F08280007000F0C2
+:1020C00000F0A23200F000F0C23008D000F0A027EB
+:1020D0000BA0389E007000F000F0A03700EE00F07A
+:1020E000007008D000F0007000F000F000200680C2
+:1020F00000F0007000F000F0003008D045020A60E7
+:1021000000F072020B6000F055020C6000F05B0200
+:102110000D60008000F0007008D045020A60FEAF3C
+:102120008A160E60FDAF00F06221FCAF8A90632238
+:10213000FBAFCB9010403AAF63326231C0E200F0A7
+:10214000222200F0A3218305076000F0242F69A05C
+:102150004090007068A000900070059C0EC4007054
+:1021600004980E8000701B9000F00070259800F01D
+:102170000070599000F000702D800E80007000F00B
+:1021800000F00070029000F00070059800F0007000
+:102190000C8000F0007059A04190007000F000F039
+:1021A0000070039800F000700A8000F0007055A0E5
+:1021B0000188007000F08A80A13600F09A8CA1217D
+:1021C00000F08082242200F0188C2131DAAEA43194
+:1021D00049020160C091223E418F00F000704DA085
+:1021E0000190007000F08A80A13600F0A28AA1213F
+:1021F00000F08080232100F0208A2132D2AEA3316A
+:1022000047020160C091223E398FA2260070D6AFEE
+:102210008290007000F000F0222E049800F023203D
+:10222000D3AF9A82007000F000F00070F29B00F0D3
+:1022300000701E8000F0A32FCFAFD282007000F09C
+:1022400000F00070E69B00F0007011804040222EEC
+:102250000DAF223020400AAFB89EA32F049400F0A7
+:102260000070E19F00F0104007AF00F00070019493
+:1022700000F000700A8000F0007000F09A84007096
+:1022800000F000F0A23E34802040232E03AFA33F95
+:10229000404000AFF89E2220FA9700F00070DF9FC8
+:1022A00000F01040FDAE00F00070F79700F00070F5
+:1022B000098000F0007029A000F04040F9AEB89EFF
+:1022C0000070049400F08040F9AE00F00041F6AEDA
+:1022D00000F0A52F179000F000700B8000F0222076
+:1022E000CC9F00F0A33FED8F00F0007020A000F025
+:1022F0002040F0AEA0820070049400F00041F0AEE7
+:1023000000F08040EDAE00F0A52F0E9000F00070C0
+:1023100002800291A32FCB9B00F02230E48F00F0CB
+:10232000262000F04591007000F0A6830070039411
+:1023300000F000700294A52D0042E6AE00F0A53E2C
+:102340001580A5208040E7AE24300041E6AE00F0C5
+:10235000A33F00F0A536007000F0C091253E058F28
+:10236000A2261040DDAE8290007003941288A52D45
+:1023700000F0A236007000F0C091253E008F00F002
+:102380000070B99B00F00070B08F00F0007005A0E5
+:102390008182A23E00F0CB8C007000F08180A33FD0
+:1023A00000F0648A007000F000F0243003800340E5
+:1023B000A02000F0F447A12600F000F0222E8E8F1E
+:1023C00000F0A02A538CD582014000F02E890070C5
+:1023D00000F03683007000F0D5820070029C799E78
+:1023E000007001985190007000F0C290007000F0F1
+:1023F0007E9E232108D014000260018096000260B6
+:10240000008000F0A03A1EA083050060E88E0A005C
+:102410000260018005000260008000F0A03A1FA069
+:1024200000F0A02F00F000F021207CAF4282A52E0A
+:1024300000F0A39E0070039000F00070039800F07D
+:10244000253E00F083050060DE8E00F0A03EE88FA0
+:102450001080223100F000F002406DAEA231460241
+:10246000016010060060D48E45020A6071AF00F072
+:10247000242100F000F0A62F00F000F0A22000F0D0
+:10248000A581A3216DAFD08E007000F000F0A231C5
+:1024900000E63C9F253200E600F024310398A0813D
+:1024A000007061AE00F04602016010060060C88E48
+:1024B00000F0252265AF00F0A53ED68F00F0304039
+:1024C00000F000F0223F00F000F0A03000F000F03B
+:1024D000A03600F03F000060A48E00F01040FBAF7B
+:1024E000104000709F8E8F8E442200F000F0C522B5
+:1024F0001490E78E007000F0CD7C06600A94800096
+:10250000006098AECD7C0660089400F0007026AFA5
+:102510002F9E007039AF0F9CA4252C98CD7C0660AF
+:10252000389800F000706AAE3782007000F0A54E57
+:102530000660439800F000705080EF8E007066AE29
+:10254000378200704D94A54E06603F9800F00070F1
+:102550001BAF2F9E00702EAF0F9C0070479400F0B1
+:102560000070469400F000704880E78E007000F024
+:10257000330306600A948000006084AE3303066073
+:1025800008946D83007012AF478F007025AF478F9E
+:10259000A4250D9433030660209400F0007056AE1D
+:1025A000878F007000F0A54E0660259400F0007043
+:1025B0003C80EF8E007052AE878F00703994A54E2C
+:1025C0000660219400F0007007AF079000701AAF0A
+:1025D00007900070339400F00070329400F00070A7
+:1025E00034800002006072AEE78E0070049000F04C
+:1025F000007006B38000006071AE0003006073AE2F
+:1026000000F00070038000F0007002AF0001006075
+:102610006DAE00F00070008000F000543DAE5D0330
+:102620000060EE8B0001006067AEE78E00700490E2
+:1026300000F00070F9B28000006066AE0003006038
+:1026400068AE00F00070F88F00F00070F5AE000288
+:10265000006062AE00F00070F58F00F0007006AF11
+:1026600000F02040E7AE0001006061AE00F00070B5
+:10267000F18F00F00070FFAE00F01040E3AE0002FA
+:1026800000605DAE00F00070ED8F00F05501076056
+:10269000000100605AAEDB8B007000F0F0A000700B
+:1026A00000F043AA00702AAEC3A23303066018826A
+:1026B000007000F0808D007023AE8000006050AE8E
+:1026C0005D030060D38B00F05501076000020060DD
+:1026D00050AEDB8B007000F0F0A0007000F043AA59
+:1026E000007020AEC3A2FF7F06601880007000F06B
+:1026F0008091007040E100F0007018AE8000006032
+:1027000045AE5D030060C88B8000006046AE00F0FF
+:102710000070D68F0040006044AE00F0A02AC48B49
+:102720009A08086000F0A03A8706006000F0414176
+:1027300010804141890600609B0808600E80A1401E
+:102740008B0600609A0808600C80A1408D0600602E
+:102750009B0808600A8031408F0600609A08086074
+:1027600008809B080860EEAE3140A02A068000F089
+:10277000A03AF78F00F0512200F000F0D221EEAE27
+:102780008982D32200F00989007000F0C88E0070A1
+:1027900008D000F00070E6AED0359C0603605130E2
+:1027A0006402016000F0D83009AEC0905031488E0C
+:1027B00045020A601FA01080007022A000F0610294
+:1027C0000160A0060060448E45020A601BA01082D2
+:1027D00000701EA000F062020160A4060060408E3E
+:1027E00000F0007017A0F44FD12300F0168253239D
+:1027F000DBAE5D82007000F000F000700298C190C6
+:10280000144000F01680007000F000F0513400F029
+:1028100080915435F1AD5B020D60D4AE00F0D8204C
+:10282000F5ADD124FF3F0560045C5224D1AE89820E
+:10283000532000F000F05125059CD23445020A6077
+:1028400000F000700DA000F000700AA063020160AB
+:1028500000F0AD0600602C8E00F0007000F00988DA
+:10286000007008A000F0007005A000F0D0258C8B4F
+:102870005B020D60C5AE502100C004605220FF3FD6
+:10288000056000F0D82008D0208C007000F0288A65
+:102890000070DC8D4190007000F01B88007040E1FA
+:1028A0001880007008D000F0AD10086000F0B31F71
+:1028B00080D200F0007081A0008292020B60820240
+:1028C000096008A010329B020B60DB07086006A0BD
+:1028D0009032A4020B60072088090A608802086011
+:1028E00097A0C8090A6002A08D02086095A000F0B8
+:1028F0001120028000F0B03300F000F0303408D036
+:10290000845182020960FB9F410908600240113036
+:1029100009D47B9E002000F0739E324000E26B9E43
+:10292000224000E224CA124000E220C279090A6073
+:10293000D3D2007000F018C4223000F000F0003054
+:1029400008D092020A60C5A0A13000706B809B0283
+:102950000A60C3A0A1300070698092020A60C1A021
+:102960002131007067809B020A60BFA02131007096
+:102970006580A4020A60BDA02131007063809202CC
+:102980000A600280A4020A6001809B020A60008043
+:102990004190124000F001401140C0E200F0007090
+:1029A0000780BD9F92020A609282007040E000F0B2
+:1029B000007004809282A4020A6000F0007002801D
+:1029C00092829B020A6000F00070008000F0820298
+:1029D0000860FE9F007000F082908321059406211C
+:1029E0008620C0E2D3C4007000F04190007000F077
+:1029F00036888331C0E000F0263208D09282FF7F13
+:102A000006604190223200F0B6838231C0E000F0CF
+:102A1000A63108D000F0820208609202096008A086
+:102A20009B02096007A0A402096006A000F08521AE
+:102A300010A09202096014A09B02096013A0A402D6
+:102A4000096012A00082007009D08031B30A80D0E2
+:102A500000F0032200F000F0922100F000F0942238
+:102A600000F09EA2172300F034A3007000F0F7A33B
+:102A7000862200F020A0007000F014AA007000F080
+:102A800078B0943300F014BA007000F000F0143401
+:102A900008D0F380FF7F04600082033209DC869156
+:102AA000803200F000910070C0E10032B20A80D0A4
+:102AB0000082FF7F046000F0172287A0C791922157
+:102AC00086A0BA8000700590C7910070039C0191A8
+:102AD0000070C0E14982103240E14591913108D047
+:102AE0006D83923108D04591007008D08202096050
+:102AF0007EA000F0962000F000F09B1B80D286A301
+:102B0000007000F000F0963208D08202096079A0CF
+:102B100000F01621FB8F8202096077A000F096205A
+:102B200000F000F0007000F036880070F78F82022D
+:102B3000096073A000F01621FC8F840306600180F9
+:102B40005A00066000F0820208606FA000F00631B3
+:102B500008D0AD020C606DA04822A6080A60C92208
+:102B6000A7080B600020007000F01120007000F03A
+:102B7000C223007000F0432488090D6080C84423FC
+:102B800000F0C9C8482000F00083C92000F0098384
+:102B9000203000F000F0313002A04821007000F039
+:102BA000C921C8090D6000F0002000F000F01120DC
+:102BB00000F000F0503D00F000F0D13D08D092024E
+:102BC0000A6002A0A4020A6001A09B020A600080C1
+:102BD00000F09B1B80D22121018004602220007024
+:102BE00000F0618CA32000F082A2007000F08E90B3
+:102BF000007000F08F90007000F051A2007000F0A3
+:102C00008E830070C0E19EA3007000F04190A63258
+:102C100000F0CF81007040E1DFA3007000F000F011
+:102C2000273308D000F08802086000F088090A60A5
+:102C300001300070098000F08802086000F0880907
+:102C40000A6081300070068000F08D02086000F09C
+:102C5000C8090A6001300070038000F08D0208602E
+:102C600000F0C8090A60813000700080F49F222CB7
+:102C7000844F00F0032009D0A2C2842000F0C3904A
+:102C8000010801608A900070C0E00491213200F0D8
+:102C90009290A330C0E000F0223C08D017400070B2
+:102CA000008088090E6000F0C8090F6000F000F095
+:102CB000E73F00F000F0F73F08D007400070FB8FBF
+:102CC00088090F6000F08A02096000A000F07723F5
+:102CD00000F000F0F62300F000F0752400F017314A
+:102CE000C8090F6000F0963000F01C72153008D053
+:102CF0008A02096000F088090F6001A0C8090F600E
+:102D000000F000F0172100F01440962000F01C7233
+:102D1000152000F077D7773300F06ED3F6330351E8
+:102D2000F5C5753406525F83034100F0758300706A
+:102D3000019853408340C0EB00F0007000F0DBD1FD
+:102D4000007000F0E3C4007000F000F0733208D0AF
+:102D500088090F6018A00740762100F01440F52183
+:102D6000F3AFC8090F6015A00740762100F01440AA
+:102D7000F521F08F1740602C12A038C2007008D0E7
+:102D800000F088090E6000F0007002A0069000704C
+:102D900001A0318C007008D000F0E521F9AF459119
+:102DA0000070C0E020400070C0E0C8090E6008D08C
+:102DB00088090E6008A000F0E62CF4AF8091007046
+:102DC000019000F0007009D0C8090E6004A000F066
+:102DD000E62CF0AF80910070019000F0007008D0F8
+:102DE000C091007008D000F0007008D0124001407F
+:102DF00003A000F0113100F000F0123000F000F0FC
+:102E0000923008D000826B0008606800096003C03F
+:102E100000F0001000F000F0007008D068000960B9
+:102E200028A01032941B80D24180923100F000F033
+:102E3000102100F000F0913200F0009013090960B9
+:102E400000F0007009D000F0123008D0224040405D
+:102E500020A040C26800096080D7711B80D250C298
+:102E6000124000F0C0D7C00F80D250C2007000F0F6
+:102E700000F0103108D06C00096019A009090A603F
+:102E800082C800F0100017A000F0201000F000F041
+:102E9000007008D06800096014A000F011300280B2
+:102EA0006800096012A000F091300080E24B4109F7
+:102EB0000B60F34B42090C603620007000F0452097
+:102EC000007000F096C3680009605DC3007000F0F8
+:102ED000C49113201240FC9F00700790D3C2007071
+:102EE00002909BD1007000F05DC5007004809420BA
+:102EF000361680D20491134000F0049000700190C7
+:102F00009EC5007040E000F0363000F000F0453023
+:102F100008D000F0007008D0CE1009602D80CF10CE
+:102F200009602C80F81009602B80091109602A8043
+:102F3000421109602980CE1009602880E8100960DC
+:102F400027805F11096026800809086025A0F540E8
+:102F5000062500F000F0022C00F0AEC3D807036095
+:102F6000BE9F007009D014D60070F74150D7007092
+:102F7000159038C2D1070A60C38000701390019E7B
+:102F8000007000F000F00070119C00F0007030D272
+:102F900000F0293000F000F0112000F02020007037
+:102FA00017A02080007000F06182203015A000F092
+:102FB00029200A9800F0812C00F01020FF1F0760E4
+:102FC000022DDB070A6038C2832D00F000F02720B5
+:102FD0000FA000F0042E00D200F008090860009055
+:102FE000007000F000F0003000E600F0007008D043
+:102FF00000F00980006000F08230FA8F0809086054
+:1030000007A08030007000F002310B7F006081313A
+:103010000070F68F00F01240FB8F00F0022C00F0E1
+:103020000980006000F000F0823008D000F00070ED
+:1030300008D0DB070960FEAF11200901006000F035
+:10304000007000F000F0813008D000F0FF1980D24D
+:103050000802006008D000F08E1F80D24982040B65
+:1030600080D200F040090A604982B91F80D200F086
+:10307000213008D000F00070FB8F00F00070EF8F5F
+:10308000A808096000F07F090A6000F000F0040160
+:10309000016000F001800460922014F205601320AA
+:1030A0000800066081300F06006027200D000160D7
+:1030B00000F0023100F000F0043200F03FD285321F
+:1030C00000F0FBC4063300F000F0833100F000F0A4
+:1030D000813308D000F0892CE3AF00F0112000F01C
+:1030E00000F00907006000F0813008D000F0892C62
+:1030F00000F000F00808006000F0123008D000F086
+:103100000070D98F00F00070D88F8090981B80D20B
+:10311000080B006008D04190007000F000F00070D3
+:10312000039000F0330780D200F0DC1580D2080C49
+:10313000006008D000F0340780D200F0DD1580D2A6
+:10314000080C006008D000F0401680D2080D006026
+:1031500008D000F0B60780D2080E006008D000F05A
+:10316000BD0780D20A0F006008D000F0421680D25E
+:103170000810006008D000F01A0B80D200F01E0B7F
+:1031800080D20811006008D000F0471680D20812E3
+:10319000006008D000F0C91F80D20813006008D07A
+:1031A0000814006008D0C091007000F000F00070BA
+:1031B000029400F00B1A80D20815006008D020405D
+:1031C000991F80D20815006008D05B090960BAAF6A
+:1031D00000F01120B9AF00F0813000F00916006056
+:1031E00008D04190007000F000F0430280D308172F
+:1031F000006008D041900C7000F000F0450280D3D0
+:103200000918006008D000F0780080D23002006019
+:1032100008D000F0750080D23003006008D000F0C4
+:10322000720080D23004006008D000F05E0080D2CE
+:103230003005006008D000F0640080D230060060E5
+:1032400008D000F0620180D23007006008D000F0A2
+:103250005F0180D281303208006000F0023108D076
+:1032600000F0590180D23009006008D000F08100E0
+:1032700080D2300A006008D000F05B0180D2300BB1
+:10328000006008D000F0600080D2300D006008D0EF
+:1032900000F0390080D2300E006008D000F06200EB
+:1032A00080D2300F006008D000F00070928F00F0E4
+:1032B000DF0680D21001006008D000F0E30680D263
+:1032C0001002006008D000F0EF0680D2100300600A
+:1032D00008D000F0D40680D21004006008D000F0BE
+:1032E000E90680D21005006008D000F05A0780D2AD
+:1032F0001006006008D000F05D0780D21007006063
+:1033000008D000F0EA0680D21008006008D000F073
+:10331000E10680D21009006008D000F0E50680D2F6
+:10332000100A006008D000F0600780D2100B006027
+:1033300008D000F0630780D2100C006008D000F0C5
+:10334000F40680D2100D006008D000F0EB0680D2A9
+:10335000100E006008D000F0F20680D2100F00605E
+:1033600008D000F0E70680D21010006008D001906D
+:10337000007000F00809086073AF00F0813000F0C1
+:1033800000F0023100F0C091833108D000F0391B09
+:1033900080D200F0007002900140C51680D2180162
+:1033A000006008D018010060638F00F0541B80D2C9
+:1033B0001802006008D000F0770D80D21A03076071
+:1033C000F38F00F0590D80D219040760F08F00F0E0
+:1033D0008C0F80D21805006008D000F06F0D80D2ED
+:1033E0001806006008D000F0910F80D21807006026
+:1033F00008D000F0930F80D21808006008D000F0C9
+:10340000960F80D21809006008D000F0A90F80D272
+:10341000180A006008D000F0AF0F80D2180B0060CF
+:1034200008D000F00070538F00F00070528F00F051
+:10343000B20F80D2180E006008D000F0B40F80D216
+:10344000180F006008D000F0C20F80D21810006082
+:1034500008D000F0C40F80D21811006008D000F02E
+:10346000C60F80D21812006008D000F0C80F80D2BA
+:103470001813006008D000F04A0B80D219140760BE
+:10348000D38F729E007000F000F00070039C00F07B
+:103490004C0B80D200F0691280D21815006008D061
+:1034A00000F04C0B80D200F0651280D2181500603D
+:1034B00008D000F000703B8F00F0500B80D218173E
+:1034C000006008D000F0350B80D2181801603AAFC8
+:1034D0000880007008D000F0440B80D219190760F2
+:1034E000C38F00F0460B80D2181A006008D000F09D
+:1034F0004E0B80D2181B006008D000F0531A80D207
+:10350000181C006008D000F08C1B80D2191D0760C9
+:10351000BA8F00F08D1B80D2181E0060299300F036
+:10352000C51680D200F04B1A80D2181E006008D059
+:103530004090AB1B80D20190C51680D200F04B1A90
+:1035400080D21826006008D000F0551780D200F015
+:103550004D1A80D2181F006008D000F0131880D2D6
+:1035600000F04E1A80D21820006008D000F0B01A87
+:1035700080D21F21006008D000F08D1B80D218225D
+:103580000060189300F0E81880D200F0511A80D241
+:103590001822006008D000F08D1B80D21823006034
+:1035A000139300F0381880D200F04F1A80D21823FD
+:1035B000006008D000F0361880D2192407609D8F73
+:1035C00000F08D1B80D2182500600C93852E6418A6
+:1035D00080D200F0501A80D21825006008D000F088
+:1035E00008090F6000F08C1B80D2F030590D80D29A
+:1035F0007031770D80D200F04A0B80D2F2311C2757
+:10360000006000F0713208D04190007000F000F0CE
+:103610000070029000F0840F80D21828006008D05B
+:1036200000F0880F80D21828006008D000F0C6167D
+:1036300080D21829006008D000F0520B80D2182ADE
+:10364000006008D000F0371880D2182B006008D036
+:1036500000F0590B80D2182C006008D000F05B0BF2
+:1036600080D21A2D0760828F00F0810B80D2182E35
+:10367000006008D000F09A0B80D21E2F006008D0A6
+:1036800000F06D1880D21B3007607C8F00F0ED18C1
+:1036900080D21B3107607A8F08090F60EDAEF12CE4
+:1036A0009E0D80D2F12D970D80D21832006008D087
+:1036B000FE9F311680D200F0007002901040991FDA
+:1036C00080D21833006008D000F04B1A80D2183333
+:1036D000006008D084908D1B80D2469012400A90E2
+:1036E00001918D1B80D230832240089000F0007041
+:1036F0000798C190E54FDEAEE8C2007000F000F020
+:10370000324004948191007000F00291EC1980D253
+:1037100000F0231A80D21834006008D018340060FA
+:10372000CF8E00F0C41A80D21F35006008D000F0A0
+:10373000480B80D21836006008D000F0C40780D251
+:103740001837006008D000F0611780D200F04D1AE1
+:1037500080D21838006008D000F03A1B80D200F008
+:10376000007002900140E51980D22001006008D06D
+:1037700020010060C18E00F0551B80D22002006045
+:1037800008D000F08D1B80D220030060C19200F0B1
+:10379000E51980D200F0751A80D22003006008D0AD
+:1037A00000F0A80180D281302204006000F00231D4
+:1037B00008D000F03C1480D22006006008D000F051
+:1037C000830180D22007006008D000F0880180D2F9
+:1037D0002008006008D000F0C40180D220090060F9
+:1037E00008D000F0E61980D2200A006008D000F06E
+:1037F000A91380D2200B006008D000F008090F60E8
+:1038000000F08C1B80D200F0F03000F0210C006042
+:1038100008D000F0140B80D200F01E0B80D2200DD7
+:10382000006008D000F0CC0180D2200E006008D0EB
+:103830004190007000F00040C80180D700F0040BF8
+:1038400080D200F01E0B80D2200F006008D000F064
+:10385000F71480D200F0813000F02110006008D011
+:1038600000F0FF1480D22011006008D0852E0815CA
+:1038700080D22012006008D000F0051580D22013FD
+:10388000006008D000F0031580D22014006008D03A
+:1038900000F0AE1380D22015006008D000F0D301F4
+:1038A00080D22016006008D000F0C20780D2201716
+:1038B000006008D0852E8D0180D22018006008D0CD
+:1038C00000F000708E8E00F0B01380D2201A0060DD
+:1038D00008D043908C1B80D219808D1B80D2201C75
+:1038E000006007901989007000F0629E00700390DC
+:1038F000529E007004987A9A0070039000F0007055
+:10390000029CC190F01980D2201C006008D0C190A8
+:103910000070808E00F00C1F80D23801006008D04B
+:1039200000F0211F80D23802006008D000F0852E00
+:1039300000F0062F191F80D23803006008D000F075
+:103940009B1B80D2080908607BAE00F0803000F03D
+:103950003904006008D000F0852E00F000F0062F3A
+:1039600000F0872FD41A80D23805006008D000F00C
+:10397000DB1A80D23806006008D03807006008D013
+:103980003808006008D03809006008D000F08D1BAE
+:1039900080D2380A00606A92852EE71980D200F042
+:1039A000761A80D2380A006008D0380B00606AAE00
+:1039B0000030C31F80D20000006008D00082007079
+:1039C00000F00990E9020A60E802086004A000F033
+:1039D000213000F0EB02086002A0EC02086001A0B8
+:1039E00000F0EA02086000F0007000F000F0003023
+:1039F00008D0EA020860BFA049820020BEA0009063
+:103A0000013000F000F0007009D000F0007000D02C
+:103A100000F0D8020F6000F0EA02086000F07026A3
+:103A2000B8A00090AC09096000F07020019000F08F
+:103A3000093000F000F0F12000F000F0722100F0F9
+:103A400000F0F32100F000F0742200F000F0F52205
+:103A500000F000F0762300F000F0F72500F000F011
+:103A6000782400F000F0F92400F000F07F2500F049
+:103A700000F0F72300F000F0007070D0EB02086057
+:103A8000A8A000F00020A7A00890007000F000F0AF
+:103A9000003008D0B6020F60A4A000F0742000F03F
+:103AA0001740F82000F03C9FF32200F000F00020C7
+:103AB00000F0D8A1F12100F00089722140E03C9F84
+:103AC000007000F000A2007040E00882FF7F0760F5
+:103AD00011A0703200F000A8EA020E600880C2094E
+:103AE0000660F3A8F03100F0FBC2663000F000F091
+:103AF000F33208D0BC020F6094A07020EA020E607E
+:103B0000F120D2090D6000F0722100F00BA270319B
+:103B100000F0D4DFF52100F0E382762200F0DB80B4
+:103B2000007000F0EBA2733000F0F3806D3000F015
+:103B300000F0F33208D0C3020F6089A0F22FEA022E
+:103B40000E607320007000F07923007000F0F821FF
+:103B5000007000F07934007000F000F0F42300F001
+:103B600000F0723500F000F0712100F000F000204C
+:103B700000F0F234EF090D604782DD090C6000F0BF
+:103B80006D3000E204916C3000E6D3826D3000E2CB
+:103B9000CB90007000F000F0F33000F000F0F33252
+:103BA00008D0C3020F6077A0F523FD090C607824CC
+:103BB000EA020E60F924007000F0F622007000F0B6
+:103BC0004591772200F00000000840E6BE9F00709B
+:103BD00000F0FF9F1010039045910070FC97F9349E
+:103BE000EF090C6078340070C0E000F0F63200F0AD
+:103BF00000F06C3008D0C3020F6069A0F12F0640BE
+:103C000000F07220007000F07325007000F0F526BF
+:103C1000EA020E60F027FD090D60CC90F63500F049
+:103C2000CF8E763600F09F8E743515940040066076
+:103C300014945784007000F00090007000F0CC9055
+:103C4000007008903C83F72000F02489007000F099
+:103C5000FFD7007000F03C83007000F024890070F2
+:103C600000F03C9F007000F0A4D1007000F000F064
+:103C7000743700F000F0782500F000F0F63500F021
+:103C8000812F0080026003A0007000F08AA0007005
+:103C900000F00090007000F060A00070C0E049AF3C
+:103CA000007000F000F0713600F000F06D3008D0C8
+:103CB000D3020F604AA078201C0A0D607921EA0225
+:103CC0000E6000F0082000F000F0192000F07222D1
+:103CD0000D7C00F06D301D7C00F000F0002000F045
+:103CE00000F0112000F080C8007000F089C8F030AA
+:103CF00000F000F0F13108D0E5020F603EA078201E
+:103D0000280A0760F920EA020F60002089080A608B
+:103D10001120007000F000F0A03000F000F0213120
+:103D200000F000F0773008D01350ADDE006000F0F6
+:103D3000000008600008026005A000F0801608601E
+:103D40008001026003A01350007031A000F00070E9
+:103D500000F200F0007008D0C390BEBA0160BA9EB5
+:103D60000070FBB3FB9E0010FE9700F0813F08D06F
+:103D700000F06308086000F0E702096000206108B5
+:103D80000B609120E9020D60103000040260478E44
+:103D9000332000F000F0903000E69F8E552000F0B8
+:103DA000FFFF006009D04591933000F000F00070F3
+:103DB00009D400F0A61F80D01640EC02096000F084
+:103DC0007808086000F01630008000F0063008D057
+:103DD0000640EC02096000F07808086000F0163038
+:103DE000FC8F16407908086000F00070FA8F0640DA
+:103DF0007908086000F00070F88F16407A080860B3
+:103E000000F00070F68F06407A08086000F000703D
+:103E1000F48F92827B0808608A90007000F010C2D4
+:103E2000012000F08A90007000F051C2007000F094
+:103E300008C4007000F000F0003008D016407B0885
+:103E4000086000F00070EB8F06407B08086000F00F
+:103E50000070E98FEC02096004A01740162003A04F
+:103E6000BE9F78080860C691007040E100F01630EF
+:103E7000E48F00F0007008D000F0551680D000F0FC
+:103E8000551680D000F0551680D000F0551680D021
+:103E90000041991F80D00042991F80D000F0551634
+:103EA00080D000F0007057800044991F80D00040FF
+:103EB0001B1A80D08040991F80D000F0551680D00A
+:103EC0001040991F80D000F02A1680D000F05516BF
+:103ED00080D01050991F80D000F0551680D020500F
+:103EE000991F80D000F0551680D00042991F80D0D5
+:103EF00000826E000E605620007000F0D520603108
+:103F000000F000F0E63100F000F0603200F000F068
+:103F1000E53200F000F0E03008D06E000C6045A003
+:103F200000F0472044A0C783007008D06E000E60E8
+:103F300042A0E020680A0560DB82662100F0389E1E
+:103F4000E72100F000F0633009D800F0612200F0B2
+:103F5000BFC3E22213403CCCE030039452C2770A44
+:103F6000056014CCEC7009D0469000700341658167
+:103F70006E000D60E180FF3F03602488513000F047
+:103F80001BC1007000F09AC3007000F000F06231B5
+:103F900050D06B110D60E48F6D110D60E38F6F11C8
+:103FA0000D60E28F71110D60E18F73110D60E08F74
+:103FB00075110D60DF8F77110D60DE8F79110D6047
+:103FC000DD8F7B110D60DC8F7D110D60DB8F7F112C
+:103FD0000D60DA8F81110D60D98F83110D60D88F3C
+:103FE00085110D60D78F87110D60D68F89110D60F7
+:103FF000D58F70000E60008000F0007000F000F0BF
+:1040000067201FA0BEC5007000F000F0663000F011
+:104010006E000E601CA000F0E6201BA08E910070C8
+:1040200000F000F0E63008D072000E60F78F00401C
+:104030000660F58F00200660F48F04000660F38FA1
+:1040400000100660F28F00100660F18F001006600D
+:10405000F08F20000660EF8F02000660EE8F0800F0
+:104060000660ED8F00010660EC8F00040660F48F9F
+:1040700000080660EA8F00040660E98F000206600F
+:10408000E88F80000660E78F40000660E68F00083A
+:104090000660EE8F00400660ED8F10000660E38F33
+:1040A00001000660E28F00200660EA8F00100660C3
+:1040B000E98F00F08000006000F0991F80D000F0D0
+:1040C000007008D000F0007003A000F00070338092
+:1040D00000F0007001A000F00070358000F000706A
+:1040E00008D000F0007008D000F07B1480D200F0FF
+:1040F000BB1480D200F03B1580D200F0AF0180D21B
+:1041000000F0A11380D200F01B0280D200F00070FA
+:1041100008D0F02074000E6072208B1101606031B5
+:1041200040000060E130193A0160603078000D60B5
+:10413000E131AB110060523128000160D030A63B64
+:1041400000605130007000F0D031007008D077204E
+:10415000D1070960762101050460FFD7FE2000F039
+:10416000BA81E34F00F000F0123000F0F1219B1B08
+:1041700080D2BA9E1D2000F000F01230E6AF0AA2F5
+:104180001C2000F09AC2035400F000F040080960BF
+:10419000D3A2610000F000F0133100F0D3801130A1
+:1041A00000F06100943114C000F0962000F0FF9FF1
+:1041B000133100F0D380113000F06100943100F031
+:1041C00000F0133100F076D0113000F0D38056109B
+:1041D00000F000F046140DC000F0007000F0FF9FEA
+:1041E000007000F000F09620F89700F0007000F0EA
+:1041F00076D0007000F000F0561000F000F0461489
+:1042000008D000F0BF11086000F0B31F80D27C001E
+:104210000960CDAF00F0112011A000F0007008D0AF
+:104220007C000F60CAAF4790713102A000F05D02C0
+:1042300080D200F09F0180D000F042090F603FD291
+:10424000DB070A607620FFFE05602220007000F088
+:10425000AEC3007000F0B59E007000F0BEC50070E7
+:1042600040E000F0763008D042090F60BEAF00F0A9
+:104270007020BDAFC0D1007000F040D4007008D0F5
+:104280007C000960BAAF00F0922000F000F011301D
+:1042900000F08290007000F0518A0070C0E000F0E1
+:1042A000330380D041907C00096092820070C0E0AE
+:1042B00000F0112000F000F09230F68FDB070A606A
+:1042C000B0AF00F02020AFAF309E007000F0104083
+:1042D000991F80D51040771A80D02240FD020960D6
+:1042E0000082114000F01238624100F090310070FD
+:1042F00000F01132007000F09132007000F01033C5
+:10430000007000F0123E00080360123F544000F0BD
+:104310009334A54100F09435A64000F015370070A5
+:1043200000F09636007000F0913700700080008237
+:10433000FD02086000F0007000F08033007000F0B3
+:10434000003B007064810C70FD020F6000F02917C3
+:10435000026000F0F72E00F0F92D007000F0C79118
+:10436000007000F0FF9F004009D000F0F73E00F021
+:10437000F62D007000F000F0100000F096831000A1
+:1043800004C00010100000F00010AB160A6000100E
+:10439000007000F0F93DFA3DC0E200F0604008D046
+:1043A000FD0208605BA000F0812E08D0FD020860CD
+:1043B00059A000F0013E5181FD02086057A000F0B5
+:1043C000013F08D0FD02096055A09123007008D07C
+:1043D000FD02096053A0113800701080FD020960D1
+:1043E00051A09131007008D0FD0209604FA0113238
+:1043F000007008D0FD0209604DA09132007008D015
+:10440000FD0208604BA000F0822F00F00BC200708C
+:1044100000F08CC2007000F0E782007008D0FD024E
+:10442000096046A0113B007008D0FD02096044A05D
+:10443000912B007000F0122C007008D00082FD0259
+:10444000086000F0007000F08033007038A100F0C8
+:1044500000703F8025030E603DA0E72CFD020F6039
+:104460000082662E00F0C791F52900F08691742A2B
+:1044700042944591632D2F950491F0394995C3904D
+:10448000703A889500F0603DE09400F0007008D02C
+:10449000008214030A6000F0FD02086000F0212091
+:1044A00000F000F0003600F000F0803300F049909A
+:1044B000803F00F0003000700EB02130BF0A80D085
+:1044C000C741FD02086000F00070004000F00629BE
+:1044D000114000F0803C2240BEC381333340A79F8F
+:1044E000007000F0879F833A00E2A79D803A00E2C7
+:1044F000879D813A00E2A79B813A00E200F0823A70
+:1045000000E200F0C10A80D200F0C00A80D000F0C2
+:1045100014030B60FF83007005C000F0371000F03B
+:1045200000F0371008D014030A601AA000F026210A
+:1045300000F000F0A02000F0BE81A72200F008905B
+:10454000263100F000F0A030F69388D3262209A08F
+:1045500000F0A531F49390D3007007A000F0A531CE
+:10456000F29398D3007005A000F0A531F093A0D38A
+:10457000007003A000F0A531EE9300F0263200F0A9
+:1045800000F0A73208D040D0A521019CCF91007047
+:1045900008D000F00070019C8E91007008D04D9101
+:1045A000007008D000F014030A6000F009090B60E5
+:1045B00000F0200085C800F0200000F000F030106E
+:1045C00000F000F0301008D000F0007008D001407A
+:1045D0005C08086000010060FDAF8031A008026047
+:1045E0000131007006C000F0007000F082310070F0
+:1045F00000F00131C411086000F0A81F80D025032D
+:104600000A60F6AF00F0A52CF5AF7D9F50080B6057
+:104610006D83224040E100F0A53C09D400F0B230A7
+:10462000B18007585C080860865125030A60802025
+:10463000FD020960812167040D603FC2C54121264A
+:1046400073C2022048905BD500707EA0EB9E36407E
+:104650002740CB90C5411790CB9014260C9000F0CA
+:104660000070019000F0007032800C91007000F03A
+:104670002BC21800076000F014363390FB820070E4
+:1046800000F000F00070319091160F6001A000F072
+:1046900000703080248300701AC000F0741000F0A5
+:1046A00000F0007008D000F0952603400C91172709
+:1046B00000F02D8F143600F036C200700390BE9FBC
+:1046C00000702B9000F00070299000F000702180A5
+:1046D000E78F0070289000F000701E9400F00070CA
+:1046E000258000F0252600F0FF83112400F0459F6F
+:1046F000132500F036C294250A94719E1521089066
+:10470000CB900070079C4591952000F000F0007060
+:1047100002904291007000F0E091007000F01C8F58
+:10472000133500F000F000701D9000F00070128052
+:1047300000F017351B8000F0942700F000F0A12650
+:1047400036400491C54100F036C2242F17902DC287
+:1047500000700494679D007000F0479D00701490F5
+:10476000479B0070139000F0007012900291A425F6
+:1047700000F04090E3FF056020C4007000F0049159
+:10478000007000F028C20070C0E000F000700C80E3
+:1047900000F0133600F0A00804600C80F7411640CA
+:1047A00042A000F000707CAFA00804600980A0085F
+:1047B0000460088029C2007041A0201004600680B7
+:1047C000201004600580F74116403BA000F013352F
+:1047D0007DAF201804600280F741164038A02018F1
+:1047E0000460008000F05C08086000F067040D6061
+:1047F000843125030A6000F09116076000F0A62EB0
+:1048000000F04982007094418E8D007000F0A68BFC
+:10481000D1070F60F781812100F000F0773000F0C0
+:1048200000F0D32000F049D57F2000F0799E55207C
+:1048300000F09BD876200B901B88972400F0F38221
+:10484000007000F0FBA2112400F09B81242600F0F0
+:10485000719E007000F0249F0070059C00F00070B5
+:104860000494C590733000F000F035030F602F887A
+:10487000007000F000F0773000F000F050080B609E
+:104880000082972700F06DD4A12E00F0C79105316A
+:1048900000F04790007017907F984640029400F017
+:1048A000203700F07F98A03700F0479CD02001947B
+:1048B00000F0A63C00F000F000700998469C222011
+:1048C000255036880070F34FADC1007000F0AAC2C9
+:1048D000007000F018C6A427C0E00790007000F038
+:1048E0002CC50070019800F0A43700F000F00070B3
+:1048F00005800790055800F00E8824270398ADC165
+:10490000007000F02CC5007000F000F0243700F0BB
+:1049100000F0844043404190303000F0B430B33078
+:10492000C0E24990007000F000F0A13E08D000F015
+:10493000923800F03FC2963900F000F0173908D0E5
+:10494000B683A136A740C9D73A0C0560C98B8450FD
+:1049500000F04D81A63E00F0A4C2007000F000F00F
+:10496000007050D000F0007000F000F0007000F017
+:1049700000F000708140980105600B8000F000702D
+:10498000C14000F00070068000F000704141B401A9
+:104990000560078000F000704141B40105600580AA
+:1049A00000F000704140FC00056003800491680144
+:1049B000056000F0014100E65003056000E600F0EC
+:1049C000213600F000F0253008D02503096054AFEF
+:1049D0001140902D53AF088C40080E6007CC142274
+:1049E00000F0CD9101400260C0C115310154108C1E
+:1049F000972D00F060300209066000F00070E13091
+:104A000000F0E6310AC02489932216403C83922BA1
+:104A100000F098A1007000F011A1007000F004A84F
+:104A2000007000F03C81FF7F0560F3A8007000F08B
+:104A3000EBC2943D00F000F0933200F000F06021F2
+:104A400041AF00F0903108D0008225030960914108
+:104A5000007000F000F0903500F000F0103300F02E
+:104A600000F0903300F000F0103400F000F0113E40
+:104A700008D025030A6038AF272E50080B6000F0DD
+:104A8000007000F0C791262500F0F899B12109D0F7
+:104A9000B6D2A327069400F0302100F05DC622278D
+:104AA00000F0ADC5203F00F014C6253500F000F041
+:104AB000A43400F00558A13F0280F09D265005580F
+:104AC000FC9D22250398FF99A22400F0EDC10070FF
+:104AD00000F0AAC20070028036C1007000F0B2C2BD
+:104AE000007000F01140A02325AF0090007000F08E
+:104AF000829020230294A1332134C0E200F00070A0
+:104B00000B8045502325069400F0242400F0EBC2CE
+:104B1000354000F004910070029000F000700194A4
+:104B200000F02134018000F0A5350280089000706B
+:104B300000F000F0203300F00082007000F000F080
+:104B4000A03300F000F0202E15AF389E007000F06A
+:104B50000090203E00F01440A02309D435402325C6
+:104B600000F00090212300F0E3C2262C029049902F
+:104B700000700194799EA53500F000F0007000F0FF
+:104B80008F8F213300F000F0007009D000F0A535C0
+:104B900008D000F00070CFAF00F00070CE8F4982D7
+:104BA000AB16096081390D030A6000F0893D00F001
+:104BB00000F0093D00F000F0013A00F000F0813E05
+:104BC00000F000F0213300F000F0013000F000F0C0
+:104BD000813F00F000F0013600F000F0013100529A
+:104BE0008130991F80D08AD7AA0C036000F0007032
+:104BF0003740D380007000F079C2007000F000F000
+:104C0000007030D06196007008D04190007008D0DC
+:104C10006190007008D04192007008D041940070FB
+:104C200008D06192007008D06194007008D041965D
+:104C3000007008D000F0712900F000F0F02800F0BA
+:104C400000F00070F0AF00F0F22A00F000F0334006
+:104C500000F08A90C641742B9AC2007000F0049153
+:104C6000007000F03C9F007005901483007000F00D
+:104C7000248300700394743BC60A80D2F03BC64183
+:104C800000F0713C007000F08EC3007000F0FF83F4
+:104C9000F23A1A943640F73A00F000F0732000F030
+:104CA0008EC3F42F00F0C79000701694FF9E15403D
+:104CB0000290F79E2540049000F000700E9000F0E6
+:104CC000F03F00F07530C50A80D200F0007010800F
+:104CD0002782762100F0F72113400C9486917530DD
+:104CE00000F000F07331019400F0F0300B80C791B8
+:104CF000F32000F03DC2F0300990FBC2007000F0DC
+:104D00005E83007000F000F0C20A80D700F00070EF
+:104D100005802782007000F000F01340019400F03D
+:104D20000070028000F0F03F00F000F0733000F0FF
+:104D300082900D030960BA9E00700390BA9E1622FD
+:104D4000059000F00070099000F096220A8009D2C8
+:104D50001030174000F0113200F000F0F73C08D09E
+:104D600000FF076000F000F0903000F0BEC300705C
+:104D700000F08EC5007000F000F0163208D009D2A5
+:104D8000103100F000F0913208D000FF076000F011
+:104D900000F0903100F0BEC3F42C00F08EC5154039
+:104DA00000400491963200F0753A703AC0E200F08B
+:104DB000007008D0C6410D03096000F00070474143
+:104DC0001122FF00006000F0932200F042C2007048
+:104DD00000F009D6007000F0C4C2007000F01BD6CD
+:104DE000007000F070C2054000F03882007000F0E2
+:104DF0004D91007040E0B0C2007000F03882007049
+:104E000000F04D91007040E0F0C2007000F0388278
+:104E1000007000F04D91007040E030C3007000F071
+:104E20003882762300F04D91007040E08091753417
+:104E3000C641759F0070249400F000700F9870C2F6
+:104E4000354000F03882007000F069C40070C0E0A6
+:104E5000B0C2007000F03882007000F0AAC4007088
+:104E6000C0E0F0C2007000F03882007000F0EBC4C7
+:104E70000070C0E030C3007000F03882762200F08D
+:104E80002CC50070C0E08691007000F017400070E3
+:104E90006E9600F00070148070C2354000F03882C9
+:104EA000007000F069C4007040E0B0C2007000F013
+:104EB0003882007000F0AAC4007040E0F0C20070B8
+:104EC00000F03882007000F0EBC4007040E030C3A6
+:104ED000007000F03882F62200F02CC5007040E02F
+:104EE0008691374000F000F00070069078C20070A4
+:104EF00000F0309E007000F0B8C200700398309E41
+:104F0000007000F000F00070019817400070598E9A
+:104F10000740007058AE09D2007000F05180007058
+:104F200000F01BD2113200F0E380007000F000F0BE
+:104F3000933200F0772D0D030960782D2917026058
+:104F400000F0100000F0D783100004C00010100023
+:104F500000F00010AB160A6000100D030960783DE8
+:104F60007A3DC0E200F0F22E00F000F0732E64AE45
+:104F70009F82742F00F08A901623049C0491F23EC5
+:104F800000F0A782007009D000F0007009D400F092
+:104F9000C30A80D000F0F02D00F08E912917026036
+:104FA0003190163300F01782007000F0F13DFA3DA9
+:104FB000C0E200F0007008D000F000701AA500F008
+:104FC0000070B7A200F000702EA500F0007033A5AD
+:104FD0006D7100603DA00100016021A000F0007033
+:104FE000008000F0007064A079120860BB81E80DB9
+:104FF0000860BA81DA0D0860B98100F06A040860BF
+:1050000000F0690409600020007000F011200070B9
+:1050100022A54990007000D079120860B381840401
+:105020000860008000F09604096000F0802100F024
+:1050300000F0912000F000F01221008008A0007024
+:1050400000F080A9FF7F016040D6007000F088AEBC
+:105050000070029400F00070019800F0007008D019
+:105060004090007008D08D040860F48F96040860AA
+:1050700012A500F0803000F000F0013108D0960455
+:1050800008600FA500F0803100F000F0013208D078
+:10509000960408600CA500F0812100F000F00222C7
+:1050A000EF8F2340124009A58A826B040860CB82EF
+:1050B00000700290951502600290FF7F02600180EF
+:1050C000DF1E0260008000F0007000F000F002308F
+:1050D000748100F0ED03096000F0EE030A60112016
+:1050E000007000F02220007008D010406D040860AD
+:1050F00000F09604096000308D040A6000F0580248
+:1051000002601A30791203602231007000F0A3327D
+:10511000007036A02A0E0860898100826D04086044
+:1051200000F09604096000308404016000F0007013
+:1051300000F01130007033A000F0007039A02A0E8A
+:10514000086082815D040860EEA4003000705F8119
+:10515000A6040860ECA40040022100F000F0012049
+:1051600000F08290007000F04190007009D400F0CF
+:10517000003000F000F0803044B400F00070DB84B8
+:105180001040A604086000F0007000F000F08030CD
+:1051900008D053090E6000F0FFF0066000F0419067
+:1051A000672000F0F0506050C0E2F7C3007000F0DC
+:1051B000C7C5007000F000F0673008D01640A604A4
+:1051C00008604290074000F000F0063100E27A9E4D
+:1051D000873100E200F0073100E2729E873100E281
+:1051E00000F0073100E200F0863100E200F00070CC
+:1051F00008D0A6040860D1A400F0002100F000F05F
+:10520000812100F000F0003200F000F0813208D07F
+:10521000A6040860CCA400F0002200F000F0812277
+:1052200000F000F0003100F000F0813108D04D04B2
+:105230000860C7A400F0003E00F000F0813E08D0F6
+:1052400001406D04096000F0007000F000F01130C2
+:10525000AEA400F00070B784F0404D04086000F088
+:10526000007000F000F0803F158000F0A604096097
+:1052700000F04D04086000F0112100F000F0002F54
+:1052800000F04190007000F000F0C40A80D500F0FA
+:10529000803F08D04D040860B6A400F00020B5A4FB
+:1052A0000080007000F000F0803108D001407404EC
+:1052B000096000F0007000F000F0113208D00040EA
+:1052C0004D04086000F0007000F000F0803708D056
+:1052D0004D040860ACA400F08027AB844403086050
+:1052E000AAA400F0003008D000406D04086000F06F
+:1052F000007000F000F0803008D010406D040860AD
+:105300000140007000F000F0803000F000F08131CA
+:1053100008D000F00070BAA400F05E0B80D200F05C
+:10532000310B80D000828D04086000F03C000260E8
+:105330008031E70D03600231007000F083320070AD
+:1053400000F06D04086099A40020007098A40090FB
+:10535000007000F000F000700194E50D08602881F5
+:105360002A0E0860278100F0E30809608D040860B8
+:105370008B8100F0BC0A80D000F0CA11086000F0F8
+:10538000B31F80D200F0007000A100F03603086067
+:1053900000F00060096000F020600B600930C06020
+:1053A00009608B30007000F00931007000F04B0391
+:1053B0000F6000F0BC00096000F0B8010A6034A082
+:1053C0004D030F6000F0B401096000F0C0010A60F5
+:1053D00031A04F030F6000F0B801096000F0CF0169
+:1053E0000A602EA051030F6000F0C001096000F0B8
+:1053F000D7010A602BA053030F6000F0C8010960B9
+:1054000000F04F210A6028A055030F6000F0D00182
+:10541000096000F05F210A6025A057030F6000F0CB
+:105420004021096000F049030A6022A059030F607F
+:1054300000F05021096000F04A030A601FA00082BA
+:105440004D040F6000F09F00086000F00070F03223
+:1054500000F00070783300F00070F03300F000705E
+:10546000F03700F00070B2AF00829800086000F0E2
+:10547000007008C000F00070001000F09604086092
+:1054800000F08D04096000F084040A60902100702F
+:1054900000F00A30007000F0A031007000F00082CF
+:1054A0006D04086000F0E2412140003020030360F9
+:1054B00000F0813000F000F0033100F07404086067
+:1054C0005AA400F0803300F000F0003400F000F047
+:1054D0000070F2A100F000706CA400F05E0B80D2AE
+:1054E00000826904086000F0007000F000F00030F5
+:1054F00000F02A0E0860E48000F0793000F000F03F
+:10550000FA3008D036030D6057A339030F60E6A0C8
+:1055100003A0A604086003B044030A60002045030A
+:105520000F6022205F040D600090F1200758D32007
+:105530000070539450804D040E60118000707030E4
+:10554000C2A100706526CAB10070F130EAA10070F6
+:10555000E025EAB10070E126C1A100706227C1B167
+:1055600000FF06608CA40070D33FB280007000F092
+:105570008DB400705430B2800070D53000F00070EF
+:10558000623700F0A404086000F038030E60802049
+:10559000E5080A606C20007000F00090007000F0D8
+:1055A00000F0007005902520007087C8252000704D
+:1055B00000F04518007000F0451843030F606C3090
+:1055C0000070C4A000F06D040D6000F05B030F607C
+:1055D000552040080A60782101050460F92137034D
+:1055E0000E607B20007000F04591FC2000F00082EE
+:1055F0000020C0E200F0110000F000F0203000F0C8
+:1056000000F0213182CC45910070A4316D20E20878
+:105610000A6000F0007000F02220007083C8222091
+:10562000007000F05218007000F0521869040A600F
+:105630006D3040080A602220007002C000F0007047
+:1056400000F000828020C0E200F0110000F000F0C5
+:105650000070203000F00070213100F00070202038
+:1056600000F00070A12000F00070301800F0007011
+:10567000411800F000707B3000F00070FC30D1D396
+:10568000007000F091D20070029400F000703E9023
+:1056900000F000704C80B99E007000F049D300709B
+:1056A00000F0A99E00704C90C9D2007000F0999E45
+:1056B00000704D9089D2007000F0899E00704E906D
+:1056C00089D2007000F0A99C00704E9089D20070C1
+:1056D00000F0999C00704E9089D2007000F0899C77
+:1056E00000705F905E040960FEA397200080036055
+:1056F00003A000701121FAA0E208086014AA00E0DB
+:1057000003607A82007087C8D2A00070043014AAA7
+:10571000007000F000F0007004303E030F6092A0B3
+:10572000FD020F6015A400F06D040F6000F070031F
+:105730000860F720740409600140002000F0C69161
+:10574000007000F0FE9FF22102902640732102902B
+:1057500000F07032078000F07132068000F00070B7
+:1057600000F09A80007000F0F131F23140EF80A239
+:10577000F63000EA8290703200EE00F0C40A80DB5E
+:1057800090216F030E6091236D040F6000F0172FBE
+:1057900000F00882142200F03AA2152400F08A805A
+:1057A000903200F02481632000F02C83923300F0CB
+:1057B0003EA3143300F0AE81922400F0C0A2772201
+:1057C00000F080A2163400F0E4A3007000F0268000
+:1057D000152600F02782007000F0A8A1007000F0EC
+:1057E00010AA007000F0E8B1103500F011BA007096
+:1057F00000F09135020780D2A0040F608AA17404E2
+:105800000860048300F04D040F6000F000000760A2
+:1058100000F00070732400F00070F42700F00070B6
+:10582000F52EE3820070762EEBA2782340E1F3A2FE
+:105830007022C0E1E3800D7C712500F00070022031
+:1058400000F00070F03500F00070713600F000706C
+:10585000F23600F00070773700F00070F3374B033A
+:105860000F6079A04D030F6078A000F00070BE8F2C
+:105870004F030F6081A051030F6080A000F0007003
+:10588000BB8F53030F607EA055030F607DA000F017
+:105890000070B88F57030F6087A000F00070B68FBC
+:1058A00059030F6085A000F00070B48F00F0490329
+:1058B000086000F04A030960002040080A601120D7
+:1058C0004D040B60203000090460A130007000F02E
+:1058D000A431007000F000F0302400F000F0B1219D
+:1058E00000F000F0B22000F00882007000F010A27A
+:1058F000007000F0418030200CC000F0B13100F0A9
+:1059000000F0252100F00A8E262007406D833231F9
+:1059100040E0BE8D353200F000F03634A18F4D04EA
+:105920000F609FA300F00070F62F00F0007070224F
+:1059300000F00070F12200F000707B230F820070F5
+:10594000F42300F00070332082910070F52DBA9F8F
+:105950000070C0E100F0F23F029C1C83371800F099
+:105960003C817B3300F003A00070F32462A500703B
+:10597000F433D2800070F03286910070723500F0FE
+:105980000070E9B200F000708F8F00F05D040860D5
+:1059900000F0FF7F0260002000708BA38182007006
+:1059A00000F04990007000F0C7D774040F60BF8208
+:1059B00084040E60CF918D040D6000F0773600F006
+:1059C00000F0673400F000F0573400F06B040E6014
+:1059D00082A36620007000F000F03E030F6086A3F3
+:1059E00039030E6000F00070763200F0007066320D
+:1059F00000F072BC076000F044030F60C7A30070A2
+:105A000000F03F880070773045030F6078A300F006
+:105A10000070F73000F08E98076000F04D040F60C2
+:105A2000C0A1007000F027AA007000F000F0007024
+:105A3000F73400F06F05076000F071660660CFA3D1
+:105A40007D040F60F781007000F000F0773008D01F
+:105A50006A0409606CA300F0183008D003A0650444
+:105A60000A6078200070096000F0007009A000F062
+:105A7000783008D003A061040A60782000700960C3
+:105A80002F170D6005A0AC7478300C8003A0630460
+:105A90000A6078200070096047170D6001A0AC749F
+:105AA000783008801108000882C91108000816C063
+:105AB00009A01108000809A09D7B8D7B0AA4007035
+:105AC0008D7900F00070221003A011080008FC205E
+:105AD0000D7C08D000F00070200000F0007041083C
+:105AE00000F0007072220882782100F010A200708D
+:105AF00023200980007000F0CB8200704118D3A2EF
+:105B00000070FC30C980FA2100F003A00070413021
+:105B10005100000800F05100000816C009A0510013
+:105B2000000809A0007000F00AA400700D7900F0D0
+:105B30000D7C223000F0783108D000F0007000F0C9
+:105B400078201810096003A00070FA2011000008E6
+:105B500000F01100000806C009A01100000809A00B
+:105B6000007000F00AA400708D7D00F00070221813
+:105B700000F00070FA3000F0783008D000F00070CB
+:105B800000F078201810096003A00070FA201100BE
+:105B9000000800F01100000806C009A0110000086C
+:105BA00009A0007000F009A000708D7D12AA00709D
+:105BB00000F000F00070221800F00070FA3000F0E1
+:105BC000783008D000F0007000F0782020100960D4
+:105BD00003A00070FA201100000800F01100000876
+:105BE0000EC009A01100000809A0007000F009A073
+:105BF00000708D7822AA007000F000F00070223052
+:105C000000F00070FA3000F0783008D000F000703A
+:105C100000F078203010096003A00070FA20110015
+:105C2000000800F0110000080EC009A011000008D3
+:105C300009A000708D7B09A000708D7932AA0070D8
+:105C4000783000F00070221803A00070FA301100C4
+:105C5000200800F0110020080EC009A01100200843
+:105C600009A000707B2109A0007000F0F2AB007069
+:105C700000F000F0323008D000F00070662078208C
+:105C80005010096003A00070FA2000F000700618A0
+:105C90001100000800F0110000080EC009A011005A
+:105CA000000809A0007000F00AA4783000F000F0AD
+:105CB000223008D01020FF1F07600524007005A3C4
+:105CC00028A2007000F040D0052300F0388A81211E
+:105CD00000F087D002221640C883032000F090A174
+:105CE000842000F019A0853340E121A00733C0E1F2
+:105CF00000A8052100F00880FF7F0760F2A880312E
+:105D000000F0BAC2812200F04591023200F07D9F7E
+:105D10000070C0E100F0053110D300F0007008D031
+:105D20000082010409600E040A6000F000F0903067
+:105D300000F000F0A03008D000F07612086000F00B
+:105D4000A81F80D200F08212086000F0A81F80D047
+:105D50004880EF03096008090F60DEAD00F0903164
+:105D600000F000F0F02CDCAD00F0103108D0AC03F6
+:105D70000960E7A200F0113208D000F0AC0309601E
+:105D8000C9D2007000F000F0913208D000F000009D
+:105D9000076000F001000660CF83020005608E837B
+:105DA000007002904D8300700B9000F00070058031
+:105DB000B683910309608D9188030A6015326C04E3
+:105DC0000B6000F0263200F000F0363008D0B683C9
+:105DD000910309608D9188030A6015326C040B6091
+:105DE00000F0253200F000F0363008D0B6836C04A5
+:105DF00009608E91007000F000F0163008D0880322
+:105E00000960008000F008090F6040900070C0AD8C
+:105E100000F0103000F000F0702DBEAD00F09030BA
+:105E200008D091030960C9A200F0113000F000F021
+:105E3000923008D07F030960C6A200F0113208D06A
+:105E40007F030960C4A211304504086000F092305D
+:105E500000F000F0133100F004304F1680D04504FC
+:105E60000860BFA201217F0309600090022000F0BA
+:105E700041908320029000F0007001909A8A007097
+:105E800000F000F0923108D045040860B8A200F09C
+:105E9000003108D0A3030960B6A200F0113208D087
+:105EA000A3030960E5AF00F0133108D09A0309603D
+:105EB000B2A200F0113208D09A030960E1AF00F0FD
+:105EC000133100F000F0943108D072030860ADA2E5
+:105ED00000F08021ACA200F0003608D07203086008
+:105EE000AAA200F00026168072030860A8A200F0A3
+:105EF000802114A000F00070178072030860A5A232
+:105F000000F00020118072030860A3A200F00021BD
+:105F10000F8072030860A1A200F080200D80720340
+:105F200008600C8000F0007023A100F0C008096038
+:105F300000F0340707607000007000F07000173246
+:105F400012C07000903200F090323507076000F008
+:105F5000903200F000F0173200F0008200700080F4
+:105F60007203086094A200F0803408D012400070E0
+:105F700000F000F0803100F00234014038A100F060
+:105F80000040448100407203086000F0007000F09F
+:105F900000F0003408D0AC0308608BA2002272032A
+:105FA00009608122007000F000F0103500F000F070
+:105FB000913508D07203086086A20025AC03096001
+:105FC0008125007000F000F0103200F000F09132F6
+:105FD00008D07203086081A28121AC0309600082AD
+:105FE000007000F0C9D2103200F000F0913208D0F9
+:105FF0001040AC03086000F0007000F000F00032C8
+:1060000008D07203086079A200F08021788200F045
+:10601000E011086000F0B31F80D200826C040860B9
+:106020008450EC0309600030ED030A601030EE0389
+:106030000B60203044040C603030007000F04430BD
+:10604000214094AD00F04204086000F08000006040
+:1060500000F0430409600030000D016000F00070A2
+:1060600000F01130007000F000F071030A6030059C
+:10607000026067A2223003000060020001600D810F
+:1060800000F05F03086000F00060006000F0600353
+:10609000096000300060016000F06F030A60113099
+:1060A000FF7F026000F070030B602230000003608D
+:1060B00000F0DF030C6033300000046000F0E00308
+:1060C0000D6044300000056000F0007000F05530B5
+:1060D000007000F00082EC0308600990EE03096094
+:1060E0000130ED030A601030007000F020300070C5
+:1060F00000F07203086051A2FF83802150A2C6D233
+:10610000073400F000F0863200F000000160F5A0D6
+:106110000000006001A1F040A0040F601240DC10FC
+:1061200001607030C1110360F130007000F000F0C8
+:10613000723100F000F0F33108D000F0007000F090
+:1061400000F0702000F0F74FF12000F0389E007052
+:1061500000F0388C007000F000F0703010D300F0C8
+:10616000007008D00020007000F01120007000F0D6
+:10617000922040080E6008A0C104046030AA62307A
+:1061800000F000F0603100F000F0E4310EC000F0EB
+:10619000007000F000F0E52000F000F0F63000F0B4
+:1061A00000F0253008D027406103086000F0491056
+:1061B00006607730B512096063030A60F18F6740AB
+:1061C0006103086000F04D1006607730B712096077
+:1061D00064030A60ED8F27406103086000F05110EE
+:1061E00006607730B912096065030A60E98F47409D
+:1061F0006103086000F0551006607730BB1209603B
+:1062000066030A60E58F27406103086000F05910BB
+:1062100006607730BD12096067030A60E18F27408E
+:106220006103086000F05D1006607730BF120960FE
+:1062300068030A60DD8F47406103086000F0611069
+:1062400006607730C112096069030A60D98F274060
+:106250006103086000F0651006607730C3120960C2
+:106260006A030A60D58F27406103086000F0691057
+:1062700006607730C51209606B030A60D18F474012
+:106280006103086000F06D1006607730C712096086
+:106290006C030A60CD8F27406103086000F0711025
+:1062A00006607730C91209606D030A60C98F274004
+:1062B0006103086000F0751006607730CB1209604A
+:1062C0006E030A60C58FE041821001602F170860DD
+:1062D00001A0461708600680703063030960F13042
+:1062E000007000F000F0100000F000F010000CC092
+:1062F0000010100000F06303096008D000F01000E7
+:1063000000F000F010000CC00014100000F000F0CD
+:10631000007008D027406203086000F08610066015
+:106320007730B512096063030A60B48F6740620377
+:10633000086000F08A1006607730B71209606403C5
+:106340000A60B08F27406203086000F08E1006607C
+:106350007730B912096065030A60AC8F4740620369
+:10636000086000F0921006607730BB120960660387
+:106370000A60A88F27406203086000F0961006604C
+:106380007730BD12096067030A60A48F274062035B
+:10639000086000F09A1006607730BF120960680349
+:1063A0000A60A08F47406203086000F09E100660FC
+:1063B0007730C112096069030A609C8F274062032D
+:1063C000086000F0A21006607730C31209606A030B
+:1063D0000A60988F27406203086000F0A6100660EC
+:1063E0007730C51209606B030A60948F47406203DF
+:1063F000086000F0AA1006607730C71209606C03CD
+:106400000A60908F27406203086000F0AE100660BB
+:106410007730C91209606D030A608C8F27406203D0
+:10642000086000F0B21006607730CB1209606E038E
+:106430000A60888F0046B510016047170860C4AF36
+:106440005E170860C98F00F00600006000F0C810F9
+:106450000160703087040860F1309B040E600020FA
+:106460005C040D60E121FD020C606220007000F010
+:1064700000F0552000F00882E32000F010A2C723AE
+:1064800000F00880642200F0C7911740E0311B8EB5
+:10649000E24F05943CC56621C0E014C3274040E0AC
+:1064A000768FD24F00F03CC50070C0E014C300707E
+:1064B00040E000F0643208D000F00200006000F01C
+:1064C000CC100160703001040F60F1300070168153
+:1064D00000F00400006000F0D010016070300E0485
+:1064E0000F60F1300070128100F00200006000F0D7
+:1064F000D410016070301B040F60F13000700E8109
+:1065000000F00200006000F0D81001607030280434
+:106510000F60F13000700A8100F00400006000F0AC
+:1065200059110160703035040F60F13000701D8129
+:1065300000F00400006000F0F110016070307203A0
+:106540000860F1308404096000F0012400F000F0DC
+:10655000822200F04190802100F000F09421049408
+:1065600053D5052394A12F8F862393A1F38A00701E
+:10657000C0E0C090833100F000F0007013A000F084
+:106580005D04086000F05F030960002060030A609A
+:10659000112061030B60222062030C6041A2007095
+:1065A00000F082A2313000F000F0423008D000F05C
+:1065B0000200006000F0F510016000F0703000F0A3
+:1065C00000F0F130208000F00800006072214510DA
+:1065D0000160F321F74F00F0BA9E00707030BA8C62
+:1065E0000070F13000F0723130D300F0007008D04C
+:1065F00000F0007001A000F00F3208D000900311ED
+:1066000007603E9A0070139838800070129C00F06A
+:10661000007077A17203086000D0CD120F60108067
+:10662000E1120F600F80F5120F600E8009130F60EA
+:106630000D801D130F600C8031130F600B8045130C
+:106640000F600A8059130F6009806D130F60088076
+:1066500081130F60078095130F600680A9130F60E8
+:106660000580BD130F600480D1130F600380E51314
+:106670000F600280F9130F6001800D140F6000801D
+:1066800000F0007008D00740C00809601540710391
+:106690000A60102072030F602220007000F02EC2EA
+:1066A00000702350B1C4474000E259C4F02400F008
+:1066B00079C47F2200F0AEC7007000F0B2C474004D
+:1066C00008A000F0123200E600F0123008D023508B
+:1066D000C00809608AD0354FD9AF10207203086016
+:1066E0009AC4007000F029C2802400F051C47400E4
+:1066F00000F00090113000F000F0113200E600F0E0
+:10670000007093C87400943000F000F0943200E6FA
+:1067100000F0943200E600F0943008D000F07103ED
+:10672000096000F0720308601220007000F000F0B1
+:10673000812400F082C4C008096041900070EB8F92
+:10674000072244040B6000F0102000F0C791812064
+:1067500000F0B68302201F900F82832100F0178281
+:106760000421019800F021200B80F78D40080D6076
+:106770005682212008905630C2080560D73000703C
+:1067800000F0D531007000F000F000700DC000F096
+:10679000007000F0E6820070572100F0007000F0F9
+:1067A000F7A3007000F0E78135200180C790352005
+:1067B00000F0C883007000F0EDA3007000F00389C2
+:1067C000007000F0ED8E022416406D83832309943F
+:1067D000C883007000F090A1042300F019A000709D
+:1067E00040E121A00070C0E100A8007000F0088026
+:1067F000FF7F0660F2A8203000F0B2C2007000F007
+:1068000000F0023408D000F0053400F000F027302A
+:1068100008D000F0822221A100F0223008D000F040
+:106820000200006000F05E11016070307F030860BC
+:10683000F1300D04096060030A60D68F00F0020099
+:10684000006000F063110160703088030860F1306F
+:106850001A040960DF030A60D18F00F004000060B1
+:1068600000F073110160703091030860F1305C0436
+:106870000960E0030A60CCAF00F0E003086000F0BC
+:10688000DF03096000206C040A601120A6040B607D
+:10689000272070030C600A8A362100F0C79100702F
+:1068A00000F092820070C0E08691007000F0928249
+:1068B0000070C0E04230007008D000F002000060BC
+:1068C00000F07811016070309A030860F1302704FD
+:1068D00009605F030A60BC8F00F00200006000F0F6
+:1068E0007D1101607030A3030860F1303404096049
+:1068F0006F030A60B78F00F01000006000F0DC103A
+:1069000001607030AC030860F13041040960770326
+:106910000A60B28F1130E10808605A202114096022
+:1069200003A0E1030F6000F084040E60170006204E
+:1069300087C81700062000F0B9A1261800F0B8A5F6
+:10694000261800F00089732300F000F0E42300F023
+:10695000C390652300F0F39E762106942D8300708A
+:1069600000F0A4A3F72100F02D8F007000F000F0DC
+:10697000773300E600F00070189400F0F2230580F1
+:1069800000F07333169C00F0742200F06D830070E9
+:1069900000F0E48EF22300F000F0753300E600F022
+:1069A000F52416401082F32000F0A8A1742000F016
+:1069B00019A05A3040E121A07124C0E100A8772538
+:1069C00000F01080FF7F0660F5A8F03300F075C37B
+:1069D000F32216400882F53400F0B8A1007000F0F0
+:1069E00019A0007000F000A8007000F00880FF7F80
+:1069F0000660F7A8703400F0F7C396040860773596
+:106A0000E308096008200070C78D5A3096040860BA
+:106A100000F0E308096008200070C48D00F00070E9
+:106A200000F000F0022200F000F0032100F092805C
+:106A3000812100F09AA2862000F05080842600F088
+:106A400000F005270598208207200A9030A20070E8
+:106A500040E138A20070C0E12480007000F0288B73
+:106A6000843606800088007000F02882072000F03D
+:106A700030A2007040E138A20070C0E12D800070AB
+:106A800000F0288B053700F000F0803708D000F0C8
+:106A90000100006000F0C51101607031007000F06D
+:106AA000F1310070868000F03D00006000F0CA11F6
+:106AB00001607031007000F0F131EF030F6000F001
+:106AC00000700A8000F00100006000F0CF1101604A
+:106AD0007031007000F0F131F5030F6000F00070CC
+:106AE000058000F00100006000F0C111016070310C
+:106AF000007000F0F131FB030F6000F000700080C7
+:106B0000B683F92000F000F0782000F000F01120AA
+:106B100000F000F0002000F04190732100F000F040
+:106B2000F42103901B8E772200F000F0007009D052
+:106B3000C791007003808E91F72200F0048F0070DF
+:106B400000F0C791007009D000F0163070D700F047
+:106B5000007008D000827B04086000F0E90309603F
+:106B6000012083040A60F22387040B600989F3255E
+:106B700000F05582F42100F02D8C112000F05D8B87
+:106B8000F22200F028A1F32400F05582F42000F056
+:106B90002D8C212000F05D8B722300F029A173253C
+:106BA00000F05582742100F02D8C312000F05D8BB7
+:106BB000722200F029A1732400F05582742000F0A5
+:106BC0002D8C007000F05D8B007000F02DA5007022
+:106BD00000F0288C007000F000F0703608D00082C1
+:106BE0007B04086000F08304096000F087040A60F9
+:106BF00000F0E8030B60012042040C60F223430420
+:106C00000D600989F32500F05582F42100F02D8CE8
+:106C1000112000F05D8B722300F028A1732500F095
+:106C20005582742100F02D8C262000F05D8B72229D
+:106C300000F029A1732400F09583742000F02D8CBE
+:106C4000312000F05D8BF22200F029A1F32400F046
+:106C500000F0F42000F000F0472000F000F0552094
+:106C600000F0BE8F007000F0698A0070C0E05582AD
+:106C7000007000F02D8C007000F05D8B007000F053
+:106C80002DA5007000F0288C007000F000F0703628
+:106C900008D090419B04086000F0FFFF016000F005
+:106CA000803000F000F001310EA000F000702C8068
+:106CB000004084040F6000F0E1030E60F0304D04EA
+:106CC0000D60703074040C6060309B040B60E03029
+:106CD000007000F0503E007000F0D03E007000F0F8
+:106CE0004030007000F0C030007000F0B030007034
+:106CF00000F0303100701E80CA0309600180B503C6
+:106D0000096000807F030F6017A088030F6016A042
+:106D100091030F6015A09A030F6014A0A3030F60E6
+:106D200013A0AC030F6012A0100084040F601100C8
+:106D3000007000F000F0F03000F000F0713000F072
+:106D40001000E1030F601100007000F000F07030DF
+:106D500000F000F0F13000F01000007040A000F0F2
+:106D6000F03200F010004D040F601100007000F0D0
+:106D700000F0703E00F000F0F13E00F010007404EE
+:106D80000F601100007000F000F0703000F000F0B3
+:106D9000F13008D000F00070100000F00070110019
+:106DA00000F0703300F000F0F13308D000407404BC
+:106DB000086000F0007002807404086030A000F0E9
+:106DC000802F2FA000F0003F08D000F04A0B80D2A7
+:106DD00000F0A60408604390DF03096000F08421FE
+:106DE00000F000F0112000F00491022100F0419029
+:106DF0000020029482908120089000F00070079497
+:106E000000F0007000F00090007000F0FF83007050
+:106E100009D000F0073078AB00F0007062AB00F0F2
+:106E200000707DAB00F00070148000F0007000F086
+:106E30004190007000F00090174009D0C39000709E
+:106E400009D407306C0B80D700F0007065AB00F000
+:106E5000007067AB00F000700F8000F0291408602C
+:106E600000F0B31F80D0FF83A4040860CF91FFDF40
+:106E7000016000F00020025200F087300C80FF8398
+:106E80006504096000F0A40408601730007000F089
+:106E90009730FFDF016000F00020024000F08730F3
+:106EA0000680A404086009A0C14F002000F0324011
+:106EB00000700380A404086006A0C14F002000F009
+:106EC00022400070008008C2007000F010C4E0088A
+:106ED000096000F0003000F000F0103008D000F041
+:106EE000007008D01040B204086000F0007002800A
+:106EF0000040B204086000F00070008000F0003232
+:106F000008D000F00070B2A00746B204086000820A
+:106F100010010960369E873200F000F0003500F065
+:106F200000F00032125086331CEF0360123700125B
+:106F30000460033F670005608430264000F0053799
+:106F4000174000F00634C80A016087360068026006
+:106F50008137034100F01234007000F013350070E7
+:106F600008D000F05314086000F0B31F80D200F086
+:106F7000007000800082B204086000F0F800096030
+:106F80000033007008C000F0101000F080351001D0
+:106F900009600036015400F09036007000F0913422
+:106FA000007008D000F0620B80D200F09B040E60ED
+:106FB0007728B204086066225E040960C791022E39
+:106FC00000F0CF91102009D0869100708C9000F0D5
+:106FD000912009D400F065040E601382C2040F6092
+:106FE00054826304096000F0662000F07B204008B2
+:106FF0000A60FC20E1000260102069040D60368800
+:10700000233100F000F0A63000F000F0203082CBF9
+:1070100000F0A23100F000F055200CC000F0E62096
+:1070200000F09020A4040D603688243100F000F0B8
+:10703000A63000F0D72069040D6000F0203000F089
+:10704000C791202000F000F0A12002940080007081
+:1070500000F04980007000F000F0301800F000F0FF
+:10706000411800F0EDD37B3000F000F0FC300194CB
+:1070700000F000701F80C6040F6098ACC9040F6058
+:1070800097ACB2040860B9AF802D5E070260012D95
+:107090004D04096000F0852700F00090832500F082
+:1070A0001088862601988090007000F0698A007030
+:1070B00000F02D88172100F0698C007000F0C79156
+:1070C000007000F000F000700F9408A00426174034
+:1070D000A8AF00700658D9A1007000F0A2A1FF7FF0
+:1070E0000760F3A8022400F0FBC2007000F004A8BF
+:1070F000062700F008A0002E00F0A1A1072200F052
+:107100008DAE007000F0C791007000F02880007014
+:1071100009D400F0003E00F000F0833500F000F0EC
+:10712000043608D0DB82822300F024830070F68FBF
+:1071300000F0AD040E60CC040F608AACB2040860AD
+:107140009AAF00F0072500F000F0F800066000F0AC
+:1071500010010D60F581007000F000F0D53795AF9B
+:1071600000F0D92794AF00F01D7C00F000F0102053
+:1071700000F000F09D78542700F0112000F03FDB74
+:10718000D22600F00B82007000F0E3A2007000F045
+:107190009A80007000F000F0D23600F000F08734E2
+:1071A00000F0B204086089AF87215D040E6000F032
+:1071B000002F00F03F89662000F000F0812E00F0E3
+:1071C00030A2007000F04180F80003605480813EDE
+:1071D00000F0E5DC843F00F06591062500F0588161
+:1071E000822200F09E81D0377EAF00F0D92700F0D8
+:1071F00000F0D63700F000F0112000F000F0DA27A0
+:1072000000F0C883007000F010A2232000F041803D
+:10721000007000F0CE8E113000F000F0053500E671
+:1072200000F0D13700F0AD78552400F000F02420B4
+:1072300000F0EBA2D33505541B8F543600F09BD3DE
+:10724000D62400F02B88572540E0F382007000F030
+:10725000FBA2007000F09D81007000F000F0D534BA
+:1072600000F00421FD020B60802F2503096000F06F
+:10727000062300F000F0812400F08691022000F047
+:10728000BE9F8320C0E00F82063300F0CF83B0237F
+:1072900000F0DF83832106588290073009D8F3C2BB
+:1072A000062309DCE4C667040D608691033100F013
+:1072B0000090075809D44591102B0194C491007097
+:1072C00040E19693543000F00633007000F000F077
+:1072D000922100F000F0912A00F010A2132155AF86
+:1072E0005980852154AF28A0044F00F042AEF740EA
+:1072F00000F0A28C962000F0BA8A1532074F95C78D
+:10730000923010407DC7007000F000F0D53000F0E2
+:10731000103DAF0B80D0690408604BAF00F0002037
+:107320004AAFC0D2007000F000F00070179000F07B
+:10733000007008D000F05F17086000F00A000060DD
+:1073400000F04023016000300B0002608130001427
+:10735000036002310C0004608331804D056004320B
+:107360000D0006608532C014076006336717096098
+:1073700087335F17006004406117016010306317A6
+:10738000026091306517036012316C170A60933107
+:10739000007000F01432007000F000F01B2000F0CC
+:1073A00000F0293000F00082AB3000F000F0203116
+:1073B00000F000F0A03108D06C17086030AF8920D1
+:1073C00067040A6000F0802100F000F0112000F056
+:1073D00000F00B20065809C0F440034F71C23C7006
+:1073E00000F000F0213000F0A430A330C0E208909B
+:1073F000007000F0079C022100F000821C7040E247
+:107400008A90803100F0B798893000F09282023182
+:107410000894332067170C6000F0023100F0C3902D
+:107420000B3000F067170B6000E200F00C3000E258
+:1074300000F0392000F000F0823100F000F08930D7
+:1074400000F000F0AF0B80D01140007001A000F000
+:10745000113008D07F0009602780205801601CA0EF
+:10746000806601602180204001601A80806C01608C
+:107470001F802000016018807F0009601BA0009021
+:10748000802C00F000F0812D09D000F0003BA045D9
+:1074900000F0813B00F000F0003E08D07F00096062
+:1074A00015A000900040016000F0004009D00130BC
+:1074B000E40F80D07F00096011A00090204001609F
+:1074C00000F0104009D00130E40F80D200F0D00F5E
+:1074D00080D07F0009600CA00090A04500F000F073
+:1074E000007009D000F0003E08D07F00096008A0BD
+:1074F00000900020114000F00070019040D4007016
+:1075000008D04090007008D07F00096003A0009070
+:10751000007000F000F0104009D00130E40F80D07E
+:1075200000F0D908086000F0102004807F00096096
+:10753000FDAF0090007000F000F0007009D000F086
+:10754000813F08D000F0007008D000F064060860A9
+:107550004982007000F00632007016A04982B678A9
+:10756000006000F0007076A011400070ABA000F049
+:107570000070D3A000F00070CDA000F00070578024
+:1075800006586806086000F01B0405608683072023
+:1075900000F0AEA3864B0460CF915206096036819D
+:1075A000073000F0163000706BA000F00070C9A02A
+:1075B00000F0007094A000F0A51480D0A608086028
+:1075C00018A000F0002000F000F0812008D000F0AA
+:1075D0000070E5A000F0007015A000F00070C780FA
+:1075E00066140F6012A0720052060E6072000070E6
+:1075F00004C07200621000F000F0621008D09282A5
+:1076000052060F604190007000F0F230732240E6A5
+:1076100000F0F13109D000F0F33008D052060E60CE
+:1076200005A000F0E73008D0D578056000F05206DC
+:107630000E6002A0EFA3007000F000F0673108D0E8
+:107640000049066002A070A0007000F037AA007028
+:1076500008D000F0007008D000F052060F6000F073
+:1076600057060E6076206B140F6000F0ED2200F0DC
+:107670007C216B2403A000F0007002A000F0ED322A
+:1076800000F000F06B3408D07820500800F000F0D3
+:10769000510800F000F0420000F000F0003000F06F
+:1076A000F720813000F000F0023100F0F9216A2269
+:1076B00000F000F0873100F003A01200200803B0B2
+:1076C00021088BC811A01200200851B0210800F039
+:1076D00010A4430000F051B4003000F000F08130FD
+:1076E00000F000F0033100F000F0873100F000F00E
+:1076F000802000F000F0320800F030A0682600F092
+:1077000013AAF921EA23D080007000F000F080185D
+:1077100000F003A011002008110020080AC009A0F1
+:107720001100200809A069227A2009A0EA2300F0AC
+:10773000A0209D7800F069322D7800F031A06836E5
+:1077400000F030A4EA330D7C00F0003008D0008255
+:10775000C008086000F07817096000303103076046
+:107760001000007002A078170960D1AFDF911000FF
+:1077700000F01000073012C01000803000F000F060
+:10778000803000F000F0803008D073060F6000F009
+:1077900078170060CAAFF030007000F07030D70A80
+:1077A00080D20082A5140F6000F0570608607100B7
+:1077B00000000960710000700CC07100011000F041
+:1077C000011020010A60B54A01103FC000F01010FE
+:1077D00000F000F010101EC000F0201000F020108B
+:1077E000A001096000F020100EC000F0101000F0A1
+:1077F000101040000A6000F0101026C000F02010A9
+:1078000000F020106A06096000F0201007C000F0A8
+:10781000101000F0101090010A6000F010100FC05E
+:1078200000F0201000F000F0201008D000F00E2B27
+:10783000076002A222870660B8A0E3C3056031A0FA
+:107840008F02036026AA64060860AE81007000F013
+:10785000F5D7003000F05DA3863000F07D9F00700A
+:1078600000F000F0853208D0792152060C6000F05B
+:10787000F82000F000F0C72100F000F0FB2000F03D
+:10788000C791101800F01718111840E6BD7879312B
+:1078900000F000F0792000F000F07A2000F003B052
+:1078A0001000830803A011009FC8C1A01000830826
+:1078B000C9B0110000F0C0A4F82000F0C9B4E03055
+:1078C00000F0C7910D78613000F0FB30029400F0B9
+:1078D000673100F000F0E73108D003B020008308E2
+:1078E00003A021009FC8C1A020008308C9B02100C7
+:1078F00000F0C0A4007000F0C9B4E03100F000F066
+:10790000613108D064233E200560E323C25F066036
+:1079100060A1622400F09FA5633300F098A1673254
+:1079200000F0AFA4E23300F000F0E73208D000F03E
+:107930006406086000F0A1140F600E217017096042
+:10794000852077170A6000F0640000F0EDD773001F
+:1079500004C967A3640000F0FE80730000F0FE829B
+:10796000161000F000F0261400F000F0007008D0AF
+:1079700000F06406086000F09914026000F09D14A5
+:107980000360759E007000F0C290813140E00231CA
+:107990000070EF8F03A05706096003B070170E60E8
+:1079A00000F0007000F00290982167004390007092
+:1079B00087C8B9A002086700F9B0030D00F0B9A0AC
+:1079C000003000F0F9B0813000F038A8983101A003
+:1079D00039B80070078084A9007000F064DE055893
+:1079E000029800A8007009D0789F007008D00C9110
+:1079F000007000F000A8007009D04091007008D01D
+:107A000084B9007000F064DE0558029801B8007077
+:107A100009D0799F007008D00C91007000F001B877
+:107A2000007009D04191007008D074000F6000F020
+:107A300000F0E10A80D078000F6000F000F0E10A69
+:107A400080D200F00070818F00F075060C60B68364
+:107A50000053076000F0463000F000F0C63100F03F
+:107A600000F0C73008D07506086051AF00F0003153
+:107A700008D04982750608600090007000F000F0A0
+:107A8000813100E600F0003008D000F057060E60AB
+:107A900000F079060B606A2575060D60E8257B14F9
+:107AA000096000F0562100F003A00070040800F007
+:107AB000EC25C4C934A311002208110022081CC0FF
+:107AC00051A01100220851A03410AD7B50A47B14AA
+:107AD000096030A204082D7903A0301000F0CD79A0
+:107AE0006A3500F000F0EC3508D075060B603BAF4E
+:107AF0000082312000F000F079060E604190B22142
+:107B000000F000F0600000E2E2080D6087C88280AB
+:107B1000600000E24190523000F08280B12000F01D
+:107B20005230E0080C6000F0B23100F000F041305B
+:107B300008D00B846A060E60098657060F60C09055
+:107B40000070A0AF00F0007085AF782352060C6083
+:107B5000F92481060D6000F0C72000F000F06022DB
+:107B600000F000F0D12300F000F0622100F00CA240
+:107B7000D12400F01481632000F00DA2041800F05D
+:107B80007EA2051800F09E81E02200F000F0161899
+:107B900000F000F0512400F000F0E22100F00CA20F
+:107BA000512500F01481E32000F00DA2041800F02C
+:107BB0007EA2051800F09E81783300F000F01618C0
+:107BC00000F000F0F93408D000F0B714096000F0BC
+:107BD000810608600082007007C00010100000F0ED
+:107BE00000F0007008D04982B21409604990810603
+:107BF000086000F0922100F003B0132200F012A2FE
+:107C0000003300F088A0007000F019A0007000F0B0
+:107C1000F2A8FF7F046003A8007000F0A2C28331C5
+:107C200000F05BD1023100F095D5007000F0EB80E0
+:107C3000007000F052D100300560A2C2007000F068
+:107C400052A3007000F08AB0007000F05AB10070CA
+:107C500000F0F2B8007000F003B8007000F0A2C2AB
+:107C6000833200F00232007008D0FF838106086082
+:107C70003FCAB2140960FFD7002000F01A2081200B
+:107C800000F085D51E2102214ED19F2083217581D0
+:107C900000702E30DD800070253194800070AF318F
+:107CA0004D91007040E13CC3007000F020800070F6
+:107CB00000F04990007040E16980007000F038C227
+:107CC000007000F086D5007000F04FD190060B6078
+:107CD000BE81812000F04D81263100F00481FF7FBC
+:107CE00007604D91002040E13CC3853000F06ED428
+:107CF000043000F000F0042200F000F0852200F0D3
+:107D000020808C060C604990363040E16980242048
+:107D100000F038C2A52000F0C6D5AF3100F08CD1FC
+:107D2000843300F0A6818534C3C95980461000F021
+:107D30001080007000F04990007040E138C22520AA
+:107D400000F0C6D5A42000F08DD1053400F0AE813E
+:107D5000043500F000F0461008D04040910608605D
+:107D60006241114000F00030CD140E608030A50655
+:107D700009600131610000F0823161000EC0111014
+:107D8000610000F01110007000F011100070008010
+:107D900000F09106086000F0DB07096000F0802029
+:107DA00000F01220BC140F600030950608607000CF
+:107DB0005C0809607000007009C07000001000F0DD
+:107DC000B29E0010125000F0001009D400F0923161
+:107DD00008D091060F601AA04982732119A0C390A0
+:107DE000722000F0799E007009D000F0712216A078
+:107DF0005382007000F000F0007009D849820070D2
+:107E000008D07A9E91060F60929A007009D800F00F
+:107E1000007009DC00F0F13008D091060F600EA070
+:107E200000F0F13108D0419091060D6000F0007033
+:107E3000E5B700F0513108D088D0A5060660419022
+:107E4000D1070F608681674109D800F0763006A01F
+:107E50007F8E7F2000F000F0007009D000F07210DB
+:107E600000F000F0731000F000F0741000F000F06B
+:107E7000751008D000F0007008D067DCD120703693
+:107E80003FC6512100EAF7365C080B6000F073230F
+:107E900000F064D0713400F0FB9E743700F0FF8373
+:107EA000733309D4A640B42000F01340F22300F04D
+:107EB00064D0763300F08290F33300F006417437DB
+:107EC00009D02440F02200F03640763300F00890CC
+:107ED000F73300F030C2F82400F0268EF0320F9411
+:107EE0007220A10608607022A1060960F721C7145C
+:107EF0000C601382FA2500F03B82F2200298008287
+:107F0000A5060A603B82723000F07C35C30A80D33C
+:107F100000F082060E6000F0220083C800F022000C
+:107F200000F000F0121000F00890121000F000F0C5
+:107F3000703200F0B683FA3500F0F6D2020000F09D
+:107F400000F0F83400F000F07A2500F0B3C2723788
+:107F500000F02400240140E600F07A3500F000F043
+:107F6000B43100F000F0323108D000F091060F601B
+:107F700000F082060E6072215E150D6065206A06B3
+:107F800008608290742757204591F0260B907DC39E
+:107F90007124D1BBECD5D82165300C8157207226D5
+:107FA000ADD1F43700F07DC3012000F07CC7FC2781
+:107FB00000F08AA2007000F055A3402000F014A346
+:107FC000C12000F020A06A0608606AA4007000F0DA
+:107FD00000F0023408D03200066003A000F0063042
+:107FE00000F000F0033300F000F0833308D000F01D
+:107FF000FD06086000F07A15006000F07B15016056
+:1080000000310000026001329315006082320816D0
+:10801000016080317201036000F0013408D000F08B
+:10802000BF1F80D200F0A70980D200F0DE1A80D2F4
+:1080300000F0281F80D2FF060860A3A000F00070A7
+:1080400000D2FD060D60A8A050244902016000F096
+:10805000522300F000F0030708608290DC7300D226
+:1080600000F0F71A80D200F0E00780D200F0860A14
+:1080700080D200F03C0A80D200F0007000F200F0E4
+:108080000070EF8FBA9E8320029000F002300194BE
+:108090004090033000F000F0503008D000F00307AB
+:1080A000086000F0007003A06A150060088000F00E
+:1080B000540280D208160060068000F0022094A0CE
+:1080C0008290832000F000F0007009D000F00330AF
+:1080D00008D000F0822090A000F0023008D0050700
+:1080E00008608A8000F0370780D01040951F80D24A
+:1080F00000F0F31A80D200F00070F3AF00F0BA0A7B
+:1081000080D000F0621508607A1501607EA000F052
+:10811000090000F000F000008CC800F0090000F039
+:108120001030000000F00040301B80D20140040BF2
+:1081300080D200F0C80680D20740C60780D0104029
+:10814000991F80D200F00070878400F0B00380D2C5
+:1081500010402040C0E200F0991F80D200F0007073
+:1081600083840607086071A01040991F80D700F033
+:108170000070808400F0A11F80D000F00070DD8FBF
+:1081800000F07A150860A315016069A000F00900ED
+:1081900000F000F000008CC800F0090000F0103082
+:1081A000000000F0F14F007099A00040301B80D219
+:1081B0000140040B80D200F0C80680D21740C607E9
+:1081C00080D01040951F80D200F0F31A80D200F0CA
+:1081D0000070CFAF00F0310780D000F0530D80D297
+:1081E00000F0370780D01040951F80D210400F1B41
+:1081F00080D200F00070C98F00F0A11F80D200F083
+:10820000940D80D200F0260780D000F0FD060860B3
+:108210001040B21502602140061B80D200F06313AB
+:1082200080D200F00070BEAF00F0510D80D200F09F
+:10823000281280D01040B61502602141061B80D262
+:1082400000F08C0780D200F0730780D0FD06086034
+:1082500051A000F0012013401040007000F0619A1E
+:10826000BC150260598C061B80D200F0661380D0CA
+:1082700000F0291280D200F0940D80D200F0A11FEE
+:1082800080D20052991F80D200F02B0780D010407E
+:10829000991F80D200F000706E84060708603DA030
+:1082A0001040991F80D700F00070678400F00070C4
+:1082B0009FA11040204040E600F0991F80D200F0BE
+:1082C0008C1B80D201900070FAA000F000706584D1
+:1082D00000F0007048A210402040C0E200F0991F5A
+:1082E00080D200F0007061841040991F80D200F0AD
+:1082F00000705B8400F0007099A21040204040E6BE
+:1083000000F0991F80D200F00070578400F00070D8
+:1083100015A31040204040E600F0991F80D200F0E5
+:10832000007053841040991F80D200F00070558473
+:108330001400016001803200016000F0FD06086059
+:10834000278000F092150860F21501601EA000F071
+:10835000090000F000F000008DC800F0090000F0F6
+:108360001030000000F01040301B80D20140040BA0
+:1083700080D2014000704CA000F0A01480D200F028
+:10838000931380D200F02D0080D21040C80180D21B
+:1083900000F0EC1480D200F0CC0A80D01040951F81
+:1083A00080D200F0F31A80D200F0007080AF00F0AD
+:1083B000BA0A80D000F0D00A80D01040991F80D235
+:1083C00000F000707284060708600BA01040991F2F
+:1083D00080D700F000706F841040951F80D210404D
+:1083E000A60180D200F00070768F0040671480D222
+:1083F00000F0CF0A80D20040A60180D200F0A11F79
+:1084000080D0FD06096008A000F0113108D000F00E
+:10841000007000F000F0002005A00090007008D06F
+:1084200000F0007000F000F0003008D000F00070A4
+:1084300000F000F0013008D000F0007008D0008299
+:10844000070708600F900070024080322A07096019
+:108450000033454600F00035F40103600730960014
+:108460000160023200100460813000100160943D10
+:1084700055B50460113E414600F0943E007000F096
+:10848000113F014600F0173D00140460153CFFFF4A
+:108490000260943C90010460123B3A070860943BF0
+:1084A0000100056000F03E070960053045070A60DD
+:1084B000133032000760233015070860A730000032
+:1084C00002600130014000F0823058070A6001313B
+:1084D000520709602130104000F091304C070860CD
+:1084E0001030114000F00030004054A4F14F004023
+:1084F0000DA000F0003422A0B141007000F05E1623
+:108500000060888000F08C1B80D201909B1B80D281
+:1085100000F0941380D200F0261F80D200F08A0D64
+:1085200080D200F0490780D200F0530180D00707C5
+:108530000860D6AF00F0013208D00B070860CD8F7D
+:1085400007070860D3AF00F0813408D01007086037
+:10855000CA8F07070860D0AF8034140480D2174058
+:10856000C60780D200F01E0480D000F00070FAAF81
+:1085700000F0F10380D200F0660D80D200F0FD0320
+:1085800080D200F0690D80D04090D01B80D20707C8
+:108590000960038007070960C5AF4090913200F081
+:1085A0001123E41E80D200F01040C2AF00F010355D
+:1085B000D48307070960C0AF00F0113301A000F0B9
+:1085C0000070FB8F07070960BDAF00F01123BCAF3F
+:1085D0004090007000F010409022C0E200F0E41ED5
+:1085E00080D000F07F1B80D200F0B90F80D0114006
+:1085F00007070960F040830A80D200F0913500E25D
+:1086000000F0007008D00E070860ABAF00F00070FB
+:1086100000D000070860A9AF00F0503008D007076D
+:10862000096000F008160160ADAF00F091339D8342
+:108630000E070860A78F0F070860A68F00F06E1C5A
+:1086400080D260160060FC8FDB070A60A7AF212094
+:1086500000709D8363160060F98F00F00070A483A2
+:1086600000F0E040F8AF00F00070A6A314070D6022
+:10867000F0AF00F0010480D200F000701E9400F012
+:1086800000702AAF00F07805016000F0861B80D2F0
+:10869000F04FA91B80D240405E1B80D200F05D1CD1
+:1086A00080D270160060EC8F00400070C6AF0040B2
+:1086B000B40380D273160060E98F10400070C3AF1E
+:1086C0001040B40380D276160060E68F00F00304F9
+:1086D00080D200F07008016000F0861B80D2F04F5D
+:1086E000A91B80D240405E1B80D200F05D1C80D26E
+:1086F0007D160060DF8F00F0D11B80D2004000703B
+:10870000B8AF0040B40380D281160060DB8F104008
+:108710000070B5AF1040B40380D284160060D88FCB
+:1087200000F0E80380D200F00070F9AEF14F007065
+:10873000ADAF00F0D606016000F0861B80D2F04F8E
+:10874000A91B80D200F06E0780D20140104000F0DB
+:10875000E241AE0780D21607086073AF00F0721BCB
+:1087600080D2319E404000F0C04F007040E000F0E9
+:108770005E1B80D200F05D1C80D294160060C88F12
+:1087800000F0007095AF00F00070D8AE00F09407D4
+:1087900080D200F00070029099160060198000F0FD
+:1087A0008C0780D200F0730780D214070860BD8F59
+:1087B00000F0F040C0AF00F0007071A300F0007056
+:1087C000DA8200F00041BDAF00F0007075A300F048
+:1087D00000703DAF0040301B80D200F0960380D285
+:1087E000A5160060B78F00F00070D9AE00F0070743
+:1087F0000960A916016060AF00F09136DE8F0007B6
+:108800000860AF8FAB160060B18F00F000707F83FF
+:10881000150708605BAF00F0812000F000F0003524
+:1088200000F000F0813230800707086057AF012068
+:1088300000700080B90A0260A9AF1040061B80D00A
+:1088400000F08C0D80D200F0CB0F80D200F07912B6
+:1088500080D200F07B0D80D200F01C1280D200F09C
+:108860007A1280D200F06E0780D200F0740780D2B6
+:1088700000F0671380D200F0590280D20040C41B80
+:1088800080D00040C91B80D200F0007069AF00F0BA
+:10889000CE0F80D200F0007078AF00F000708BAF88
+:1088A00000F05B0280D017070860408F1607086051
+:1088B0003F8FF14F0707086000F0007000F0114093
+:1088C00081340180014000700080180708603AAFD1
+:1088D00000F0104090AF00F0007065A3180708602A
+:1088E00032AF00F00070029400F0310780D2D2164F
+:1088F00000608A8F00F08C0D80D21507096034AFBC
+:108900001021851B80D200F0912000F01F070D6020
+:1089100080AF00F0913200F0F04FA91B80D2070722
+:1089200008602EAF00F0012200F000F080242CAF90
+:108930000F82007000F07F9E007002900040104097
+:10894000C0E200F0007057AF00F010407CAF00F0C4
+:108950006E0780D200F08C1B80D20190104000F096
+:108960001241AE0780D200F0007055AF00F00070E9
+:1089700068AF00F01507096000F0670280D200F0D0
+:108980001032059400825E1B80D200F05D1C80D204
+:10899000ED1600606F8F00F06B0280D2EF16006062
+:1089A0006D8F1A07086011AF00F0721B80D2019022
+:1089B000007000F0319E007004904040C04FC0E253
+:1089C00000F05E1B80D200F05D1C80D214170060A6
+:1089D000658F4040641B80D200F05D1C80D2FA1687
+:1089E0000060628F00F0D30F80D200F0520D80D271
+:1089F000FD1600605F8F1040C41B80D200F0650D33
+:108A000080D21507086008AF00F0003300F000F0D6
+:108A1000003400F0C04F641B80D200F05D1C80D297
+:108A200005170060578F00F0D30F80D200F0520D71
+:108A300080D208170060548F00F0650D80D21507B2
+:108A40000860FEAE00F00123FDAE0A82803300F024
+:108A500000F0003400EA00F0007005981040C91BD7
+:108A600080D200F000701AAF00F0CE0F80D24040EC
+:108A70005E1B80D200F000700180C04F5E1B80D270
+:108A800019070860ECAE00F00070029000F092024E
+:108A900080D218170060448F00F0D70F80D200F00A
+:108AA000520D80D21B170060418F00F000700EAF96
+:108AB00000F0650D80D215070860EAAE00F00120D5
+:108AC00000F000F0803400F00F82007000F000F041
+:108AD0000070029800F0D50F80D200F00070018085
+:108AE00000F0D70F80D21F070860338F00F02040BE
+:108AF00036AF00F000700EA300F02D0780D22A17C9
+:108B00000060328F00F0007089AF00F05E1C80D2F0
+:108B10002D1700602F8F00F0830D80D200F06513B9
+:108B200080D200F00070FAAE00F0CE0F80D21107B4
+:108B30000860CFAE00F0980280D30082007000F091
+:108B400012070860CFAE13070860CEAE00F094079E
+:108B500080D245170060789339170060798F11072C
+:108B60000860C7AE00F000700A9000F08C0780D259
+:108B700000F0730780D23E170060728F00F0007023
+:108B800012AF00F0112600F092209C0780D249908D
+:108B9000007003948882007000F03E170060019816
+:108BA00000F011366B8F00F0730780D200F0007078
+:108BB0000AAF00F0940280D245170060679300F07E
+:108BC000007024AE00F0260780D24C170060108F92
+:108BD00000F0007004AF12070860B3AE00F0007040
+:108BE00009D000F07C1280D200F0171280D200F081
+:108BF000EA0F80D20140007000F011070860B2AEA9
+:108C000000070860048F0040007000F02A07086029
+:108C1000B1AE008280311540719E007000F00030CE
+:108C20000530C0EB5190007040E1052FBD0400609D
+:108C3000A69F813F014080338333C0E20034043477
+:108C4000C0E281358535C0E200F0823008D000F006
+:108C5000007007A10291832E2040B69F042FF28F4F
+:108C60003040007000F0390708609E8E39070860B8
+:108C70009AAE3F9E007008D02A0709609FAE11226D
+:108C80008C1B80D2088223409DAE00F0933700E217
+:108C900000F0007008D001402A07096000F0304061
+:108CA000EEAE00F09137C9A200F0310780D2721702
+:108CB0000060EA8E2A07096095AE972F8C1B80D240
+:108CC00000F0B91B80D21220007092AEBA9E380715
+:108CD0000D60FA9F0070029042900070C0E080909A
+:108CE000007000F01032007000F049829227DBAE75
+:108CF000AA9E113100F000F000707D9000F08C0D04
+:108D000080D201402A07096000F03040DCAE00F05C
+:108D1000913700F0102BA91B80D200F0A70D80D254
+:108D200000F0ED0F80D221409E0D80D200F028127D
+:108D300080D22A07096080AE902D007000F0112EBD
+:108D4000B10D80D2122000707DAEBA9E007000F08E
+:108D500000F00070079000F00070DAAF00F00070D3
+:108D6000069000F00070048000F0FC0F80D200F04C
+:108D70000070DFAD00F00070D5AF00F000706790BC
+:108D8000902FAE1B80D20140991700601507086034
+:108D900071AE00F0003500F000F08132478F00F036
+:108DA0001507086000F02A07096081243040C1AE31
+:108DB00000F0922700F0DB82902000F0AA9E93360C
+:108DC00000F0428291325B9000F01336EF9B00F08E
+:108DD000510D80D21140007000F0A41700600E8F7A
+:108DE0002A07096063AE00F0922700F0912E9B1BCA
+:108DF00080D2AA9E007000F000F00070529008A28D
+:108E0000CE0D80D200F0FC0F80D2A140007000F0A7
+:108E1000AD170060058F00F0F70F80D200F0C90D8C
+:108E200080D22A07096058AE9227FF0F80D2219284
+:108E3000CC0D80D2AA9E922300F000F0132447901C
+:108E400050B0142600F0F6B8952500F00C9190343F
+:108E500000F08783113500F065831436D79B00F04E
+:108E6000007002981140007000F0AF170060F68E9D
+:108E700058B0007000F0F6B8007000F08783007002
+:108E800000F000F00070D09B2A07096047AE9227DF
+:108E90000707086000F0962600F0AA9E122C00F04A
+:108EA00000F0132636903041830A80D200F016413C
+:108EB00000E2CB90007007901041830A80D200211D
+:108EC000007003948121540B80D256413641C0E298
+:108ED00000F000700280D08274040A6000F0133643
+:108EE000029C1140963600F0C0170060E18EA2236C
+:108EF0009B1B80D200F0172D00F01289912C00F0FE
+:108F0000C791123300F000F00070039841A2007086
+:108F1000C0E08B82007000F000F00070B79F44400A
+:108F2000912100F000F092264341479000701040DC
+:108F30008FC213361D90A7C200701C9400F0007001
+:108F4000B19700F000708EAD00F0631380D200F096
+:108F5000510D80D24141007000F0E4170060CE8EC8
+:108F600000F0661380D22A07096022AE9227070715
+:108F7000086000F0132600F0AA9E952100F0CB9027
+:108F8000922B11903041830A80D200F0007003943C
+:108F90007F9F164200E200F000700A9000F09636C3
+:108FA00007801041830A80D2002100700394812140
+:108FB000540B80D256423642C0E200F0007004806A
+:108FC000D082007000F000F013369A9F11400070BC
+:108FD00000F0E5170060BA8EAFC39636104000F07F
+:108FE0000070969300F0903700F000F010210CAE66
+:108FF000009091270BAE7A9E0070129400F0122020
+:1090000006901507086008AEBA9E002100F06A9E1F
+:109010000070029000F0007001901022007000F0CB
+:1090200000F0851B80D200F000706BAD00F02912BB
+:1090300080D2F04FA91B80D209180060A38E00F0E7
+:109040002A07086000F01507096082278C1B80D270
+:10905000AA9E1121FBAD0A820070029400F00070FC
+:10906000019000F00070EB8F00F0AC0D80D200F0AA
+:10907000F20F80D238070860468E4790014041AF1A
+:10908000C1910040658200F00070B8A200900070AD
+:1090900008D001402A07096000F0404044AE00F0CB
+:1090A000913722A200F0310780D21C180060408E58
+:1090B00039070860E4AD2F9E007000F000F00070EA
+:1090C000169000F08C0D80D200F02A07096007404E
+:1090D0008C1B80D200F0B91B80D21032271805609B
+:1090E0001140007000F000F0153700F000F0113171
+:1090F000588F00F0404035AE39070860D8AD3F9E2C
+:109100002A07096000F00070049400F08C1B80D2E4
+:109110009122007061A200F000703AAF00F0007080
+:10912000509700F0007041AD15070960D7AD1021D0
+:10913000851B80D200F0291280D2F04FA91B80D26B
+:1091400035180060778E00070860238E3C070860A2
+:10915000CA8D3A070860CE8D3B070860CD8D00F0C0
+:10916000504023AE00F0007004A200F02D0780D222
+:109170003D1800601F8E00F0007076AE3A070D605B
+:10918000C9AD5120150709600040441802609132B2
+:10919000A91B80D2D020851B80D200F012359C8E76
+:1091A00000F0504018AE00F0830D80D200F0007047
+:1091B0002AAD00F01507086000F03A070D60524133
+:1091C000104000F00121AE0780D24982862400F0D1
+:1091D00000F0D13100F05631007071AE00F0007037
+:1091E0001FAD00F0651380D2511800605F8E00F053
+:1091F0003A070D60F040830A80D200F0D03100E2DF
+:1092000000F0007009D000F0260780D257180060E7
+:10921000058E00F0730780D23A070D60AFADD521FF
+:1092200011000460F040830A80D24581007040E064
+:109230002040830A80D24581007040E06583D531AB
+:1092400000F000F0007009D400F07C1280D200F031
+:10925000171280D200F0EA0F80D200070860F58D67
+:109260003E070860A3AD0082813000F000F00033BB
+:1092700000F000F0043100F000F0853100800707B5
+:1092800009609EAD00F0123100F000F0933108D07B
+:1092900043070860948D3E070D609AAD00F0D1221F
+:1092A00000F000F0522200F000F0532308D000F04C
+:1092B0006040EBAD00F00070CFA100F02D0780D230
+:1092C00075180060E78D00F000703EAE3E070D603F
+:1092D00091ADD020851B80D20040BB180260512088
+:1092E000061B80D27B180060318E00F06040E1AD3B
+:1092F00000F0830D80D200F01507096000F03E07F2
+:109300000D609624070709604982572187ADBF8306
+:109310005632104000F0113600F000F091355198AF
+:1093200000F00070E9AC00F0D50F80D200F0D70D4E
+:1093300080D200F0631380D200F00707096000F0CC
+:10934000940780D200F0112000E28C180060268E75
+:1093500000F08C0780D200F0730780D241070860CC
+:1093600072AD00F0A518006000F05C1680D100F02E
+:10937000940780D2941800601D9600F000700C8055
+:1093800000F00070BCAD00F00070039400F06613B4
+:1093900080D200F07C1280D200F0D70D80D2070777
+:1093A00009606EAD00F0112600F092209C0780D27B
+:1093B0004990007003948882007000F09418006057
+:1093C000019800F01136108E00F0260780D21207A7
+:1093D00008605FADA518006000F000F05C1680D159
+:1093E000AB180060B78DF040830A80D200F00070A7
+:1093F00009D400F0661380D200F07C1280D200F015
+:10940000D70D80D2AB180060B18D1041830A80D295
+:109410000540007009D400400F1B80D20707086088
+:1094200059AD00213E070D608121540B80D200F020
+:1094300052330894D120007012AED532171280D268
+:1094400000F0281280D28140007000F0B718006050
+:10945000FB8D00F0EA0F80D200F0291280D20007C5
+:1094600008609F8D00F02140018000F031400080B5
+:109470004307086049AD4107086043AD00F0007044
+:10948000029000F02D0780D2C11800609B8D00F083
+:1094900015070D606241104000F05121AE0780D2E7
+:1094A00000F06E0780D200F07C0780D200F00070E0
+:1094B000AAAC00F07B0D80D200F00070F6AD00F099
+:1094C000830D80D200F00070A3AC00F0631380D253
+:1094D000CD180060E38D00F0260780D2CF18006021
+:1094E0008D8D00F0730780D2F040830A80D200F0A7
+:1094F000007009D400F0661380D200F0D70D80D23E
+:1095000000F00070108000F0D03200F000400F1B1F
+:1095100080D200F0007099AC00F015070D60624237
+:10952000104000F05121AE0780D200F00070E3AD92
+:1095300000F0007091AC00F0651380D2DF1800607D
+:10954000D18D00F0260780D2E11800607B8D00F0FD
+:10955000730780D2F040830A80D200F0007009D4F3
+:1095600000F07C1280D200F0EA0F80D200F01712D7
+:1095700080D200070860718D450708601FAD00822A
+:10958000013100F000F0803200F000F084317D8F76
+:109590004B070860148D45070D601AAD00F051238C
+:1095A00000F000F0522200F000F0D32208D000F0CA
+:1095B00070406BAD00F0007052A100F0310780D216
+:1095C000F5180060678D00F08C0D80D245070D60A6
+:1095D00011AD51210070CDAD4090851B80D200406F
+:1095E0001E1902605120061B80D2FC180060B08D4D
+:1095F00000F0704060AD00F0007070AC00F06313DC
+:1096000080D200F0510D80D200F0281280D221408B
+:10961000007000F003190060AF8D00F08C0780D25D
+:1096200000F0730780D22141007000F0071900603C
+:10963000AB8D00F0661380D245070D60FFACD120E2
+:109640001340FEAC619A0C190060598C0070A68D15
+:1096500000F0291280D200F02B0780D200F015070D
+:10966000096000F045070D6000F0912400F000F063
+:10967000D021F6AC4282513200F000F00070089820
+:1096800015190060478D1041830A80D200F00070E8
+:1096900009D407070860F0AC002145070D6081215F
+:1096A000540B80D2D2320070029400F0014003804B
+:1096B00000F01140028000F02140018000F03140B4
+:1096C00000804B070860E6AC00400F1B80D200070B
+:1096D0000860378D1040007000F051070860E08C82
+:1096E00001404C07096000F0804037AD00F0913236
+:1096F00021A100F0310780D229190060338D510774
+:109700000860D7AC3F9E007000F000F00070099335
+:1097100000F04C0709602F190560DAAC00F0153233
+:10972000048000F080402DAD07070860D7AC00F042
+:10973000002205AD00F00070FC8E00F0104129AD54
+:1097400000F0902102AD00F08C0D80D200F01C12D0
+:1097500080D200F07A1280D200F0671380D24C07DA
+:109760000960CEAC00F090200F8000F0104121ADD8
+:1097700000F0007034AC15070860CAAC812400709A
+:109780007CA100F000700F9051070860C0AC3F9EB4
+:10979000007000F04C0709600C9000F08C1B80D228
+:1097A0000190961B80D24180007000F00088122149
+:1097B00000F040C2007000F08382007000F000F002
+:1097C0000070059800F0851B80D2112015070D60F0
+:1097D00000403B190260D132A91B80D200F0523503
+:1097E000918D00F07C1280D200F0171280D25007C9
+:1097F0000860078D53190060098D00F000700B811F
+:1098000000F0904008AD00F000700EA10140040B84
+:1098100080D20140007098A000402C1E80D20054DD
+:10982000331E80D214070D60FCAC53070860A5AC52
+:109830000190204000F09241AE0780D252070860AC
+:10984000A2AC399E52070860A04F6040C0E287205A
+:109850006A1B80D2C091851B80D2F04FA91B80D299
+:1098600000F06E0780D27A15016099AC00F05D1CA3
+:1098700080D268190060F48C00F00070C1AC00F078
+:10988000007004AC00F0940780D200F000700290E9
+:109890006D190060458D00F08C0780D200F07307D1
+:1098A00080D200F05D1480D200F0BA0A80D2721922
+:1098B0000060EA8C00F05B1480D2F21501608BAC82
+:1098C00000F0BA0A80D276190060E68C14070860AE
+:1098D000E28C00F0A040E5AC00F00070E8A000F0E1
+:1098E0006E0780D200F05E1C80D27C190060E08C94
+:1098F00000F00070ADAC5807086083AC00F01F1E8C
+:1099000080D700F0610280D200F00070EDAB0082E1
+:10991000007000F01307086081AC00F0940780D25B
+:1099200000F000700D90861900602C8D1107086002
+:109930007AAC00F000700A9000F08C0780D200F042
+:10994000730780D28B190060258D070709607CACF6
+:1099500000F0112600F092209C0780D24990007000
+:1099600003948882007000F08B190060019800F069
+:1099700011361E8D00F0730780D20140007000F098
+:109980001107086071AC00070860C38C00F007077E
+:10999000096000F0A019016000F0B040C4AC00F014
+:1099A000913600F000F00070D0A00140040B80D28E
+:1099B0000140007053A000402C1E80D20054331E82
+:1099C00080D200F00070BB8F00F0B040BCAC004013
+:1099D000C80180D21040671480D200F0CF0A80D234
+:1099E00000F054070D601140040B80D200F05120AC
+:1099F00000F000F0D320098000F00070C8AB5407DD
+:109A00000D605EAC00F054215DAC0491512000F07B
+:109A100000F0D3200D90618000700198C882007022
+:109A200001805882007000F0C190007040E1513018
+:109A3000590709605882B619026000F0503100E2FF
+:109A40001230140B80D200F00070168000F000700D
+:109A5000B7AB54070D6050AC00F0D12100F0A8194D
+:109A60000060F88C0140040B80D2000708609D8CD8
+:109A700000F0C040A0AC00F00070B0A059070D602D
+:109A800098AC00402C1E80D20054331E80D200F0CF
+:109A9000100B80D200F0007011901040671480D23B
+:109AA000580708603CACC91901600690104020407E
+:109AB000C0EB140708603EAC00F00070968F5807AA
+:109AC000086037AC00F01F1E80D20052331E80D2D7
+:109AD00000F0B50280D2CE1900608E8C00F06803D1
+:109AE00080D2D01900608C8C00F0350380D2D2195E
+:109AF00000608A8C580708602EAC10402C1E80D75E
+:109B000000F0007099AB59070860838C01404C0746
+:109B1000096000F0D04085AC00F0913298A000F0D0
+:109B20000070BAAB2040301B80D21040C80180D2F8
+:109B300000F04C070960DF1905602AAC00F015320F
+:109B4000548F00F0D0407DAC00F00070FEAB00F010
+:109B500007070960E419016025AC00F09136778FA2
+:109B600000070860748C53070860208C5207086057
+:109B70001F8C5407096020ACD082123000F024887A
+:109B8000933040E100F0143100F000F09531F98F8E
+:109B90004C0709601BAC00F0913010401231CE0030
+:109BA000016000F093318A8058070860158CFD062B
+:109BB000086016AC00F0813100F000F0823208D06D
+:109BC00000F0FD06096000F00007086000F090302A
+:109BD00002A0FE06086009AC00F0007000D000F0A2
+:109BE000007007AC00F0007000D0FD0608600CACFF
+:109BF00000F0012200F000F000320AAC00F000702A
+:109C000010D000F0DB0709607F9E007000F0779EA7
+:109C10001220049047900070049000F000700190B2
+:109C200000F0007008D000F01130138000F0113007
+:109C3000228000F01130558000F0007076AB00F00B
+:109C400000705A8C9C160060E98F9F160060E88FA8
+:109C50008915016000F001000260E3AF00F0970A8F
+:109C600080D08F15016000F002000260E0AF00F0CC
+:109C70009A0A80D000F000707FAB9315016000F06D
+:109C800000000260DCAF00F0970A80D08B15016005
+:109C900000F003000260D9AF00F0980A80D07B1575
+:109CA0000060E1AF00F00070478C00F0DB070A6055
+:109CB00000F0FD06086000F02220EAABB99E803477
+:109CC00000F0B19E00702C9081900070539000F0D5
+:109CD0000070E89300F0007008D0DB070860E4AB88
+:109CE00000F00220E3ABB99E007000F0B19E00705E
+:109CF0002B9000F0007051901040991F80D09F155C
+:109D00000060D1AF00F000707F8C00F0007068AB95
+:109D100000F000709A8C00F000707AABA51501601D
+:109D200000F000010260C1AF00F09B0A80D000F09B
+:109D3000007079AB00F00070FB8FC115016000F07E
+:109D400001010260BCAF00F0990A80D0C315016028
+:109D500000F002010260B9AF00F09A0A80D0C61587
+:109D6000016000F003010260B6AF00F09C0A80D0F1
+:109D7000CC15016000F004010260B3AF00F09D0A51
+:109D800080D0D015016000F005010260B0AF00F096
+:109D90009E0A80D0D215016000F006010260ADAFCE
+:109DA00000F09F0A80D0D615016000F00701026024
+:109DB000AAAF00F0A00A80D0DA15016000F0080117
+:109DC0000260A7AF00F0A10A80D0CA160060A88F79
+:109DD00026170060A78F6D170060A68F1718006008
+:109DE000A58F39180060A48F71180060A38FF11837
+:109DF0000060A28F24190060A18F00F0FD060860AA
+:109E000000F00301046080220401056000F00801F5
+:109E100006602182050204602982641780D13182A4
+:109E2000641780D12182221980D100F0221980D1BB
+:109E300000F0007008D0EE1500609DAF00F00070DB
+:109E4000F38E00F000707FAB00F00070F38EF5151C
+:109E5000016000F0020202608EAF00F09A0A80D02A
+:109E6000F315016000F0010202608BAF00F0A20A5E
+:109E700080D000F0007093ABF815016000F0000294
+:109E8000026087AF00F0A30A80D0F315016000F0F4
+:109E90000302026084AF00F0A40A80D0F5150160CF
+:109EA00000F00402026081AF00F0A50A80D0F31533
+:109EB000016000F0050202607EAF00F0A60A80D0CB
+:109EC000771900607F8F541900607E8F96190060AB
+:109ED0007D8F060708608CABBC1900607B8FD6199C
+:109EE00000607A8F75465A07086000F014400640FB
+:109EF0002DC0CE040960098D863000F0498B0631F3
+:109F000000F000F0013000F08933FF7F046000F0C2
+:109F100006329C7400F0893200F000F0843108D0E1
+:109F20009300FF7F076000F0930000F0C48E930061
+:109F300000F0C48E9300FF9700F0132C9C7700F084
+:109F4000942000F0C090101000F0FA82111000F080
+:109F500001911320FC9700F0007008D0FF835A078E
+:109F600008603FCACE040F60FFD7822000F00320B4
+:109F7000CE0409608421CE0406609D8E8E2200F0FE
+:109F80000D8F0422039000F0EC7000F08A908E3266
+:109F900000F000F082300B8000F0007009D02381C7
+:109FA000007000F09E81007000F0A482063300F083
+:109FB0003C9F007000F000F00A23059000F0007054
+:109FC00000F000F0252100F000F0A62100F03C9FF9
+:109FD000251000F000F02610FC9700F06730E0AF8D
+:109FE0008120CF040960B683007000F0719E930059
+:109FF00000F000829400059800F0833100F01D8F7E
+:10A00000007000F00890940002900391007000F03E
+:10A010000690007000F0799E833100F000F0063267
+:10A02000FA9F00F0007008D048D0CE0406605A07AE
+:10A03000096056AB86819220334000F016330C70D5
+:10A040008C82021000F03C9F1E2352AB054065003D
+:10A0500040EF0640660040EFFB9E051000F03C9F7D
+:10A060000610FC9700F0007008D05A0708604CAB4F
+:10A0700000F0892300F000F0022100F000F003203E
+:10A0800049AB988E007000F000F0007009D08A9003
+:10A09000111000F000F0893300F0D082023108D0B6
+:10A0A00000F0CE0406605A07096042AB8E8112218F
+:10A0B000634000F016330C7000F0021000F08C8248
+:10A0C0001E233EAB0640660040EFFB9E007000F092
+:10A0D0003C9F0610FD9700F0007008D05A070860FA
+:10A0E00039AB00F08020388B00826207086000F0F6
+:10A0F000007009C00010007000F000F0007008D07F
+:10A10000620708601DA0813103C0006059C402329B
+:10A1100000F08332971F80D269C4043300F0C391EA
+:10A1200085330190314006340A80F04F62070860A1
+:10A130004982007000F00130971F80D062070860EC
+:10A1400013A000F0012012A04190022100F000F0C5
+:10A15000832009D08290007000F0BA9E00700190B8
+:10A1600000F0023108D0799E62070960799E007084
+:10A170000490C39000700490FB9E0070F29300F076
+:10A18000833000F017401C71028027401C72018050
+:10A1900037401C73008000F0102000F000F0922087
+:10A1A00000F00090007000F0C1910231F49307308C
+:10A1B000A61F80D000F0007008D000826B070F60EF
+:10A1C00000F0007006C000F0701000F000F0701099
+:10A1D00008D06B070E6021A000F0602020A0009046
+:10A1E0006C070F6000F0007009D000F0007001A053
+:10A1F0006F070F601CA0F6206B070E607720FF7FB3
+:10A200000460BE9F602000F0FF9F752140E1A6C35F
+:10A21000007009D800F0773000F0C791F63009D40B
+:10A22000389E007009D400F0603050D000F069070B
+:10A230000F6000F080120760389E6B070E6078B0E8
+:10A240007C71FE9F91B8723100F0C9D7662000F092
+:10A2500092B9F13000F08E91723000F000F066306B
+:10A2600008D000F06B070E60498269070F60389EC6
+:10A27000662000F000F07C71FE9FBE9F722000F00F
+:10A2800000F0F32000F08290713000F0C390F130C4
+:10A29000019400F0007009D000F0663008D000F0A2
+:10A2A000007008D000F0007000F000F0002076810F
+:10A2B00000F0007000F000F0003008D0389E01007F
+:10A2C00073A100F01110FE9700F0007008D000F0AC
+:10A2D000B807086000F0731580D200F00070AF80FE
+:10A2E00000F0AC15086000F0B31F80D2C0407207C8
+:10A2F000086000F07E07096000F00245F5AFB8077E
+:10A30000086068A100F0823000F00230FF7F00603A
+:10A31000A08C01606FA0409000706CA000F00070F5
+:10A32000A4A000400070008000F0C208026003900A
+:10A330007E070B6072070B6000E23B9EC308036060
+:10A340009008026000E29308036000E232348B0759
+:10A350000A60B334007000F000F02B3208D07207AE
+:10A360000B6001807E070B60008000F0A8070C6086
+:10A370004090BE150960789E35220F90709E9C70AB
+:10A380000E90689E9C700D9000F0007004904190BB
+:10A3900012400280819022400180C19032400080B2
+:10A3A0000082007008D092070860D4AF009094201B
+:10A3B00000F080900070039418830070F99BD082A5
+:10A3C0000070F99B00F00070F89BD382142046A126
+:10A3D00012810070028000F0932000F000F0122043
+:10A3E00000F02D88B33200F0EBC232300540333339
+:10A3F000A8070C6000F0B13100F04891C53608D0D4
+:10A4000072070B6001807E070B6000804790007030
+:10A4100000F07F9E104000E2779E204000E200F0B6
+:10A42000404000E200F0B22200F00588303200F037
+:10A43000AAC2007000F000F0323308D0B6070860FE
+:10A44000BDAF0090007000F010400040C0EB114024
+:10A450000140C0EB12400240C0EB00F000703A80B7
+:10A46000B6070860B7AF0090007000F010400040E1
+:10A47000C0EB01401140C0EB02401240C0EB00F0C5
+:10A4800000703480B6070860B1AF0090007000F033
+:10A4900010400040C0EB01400140C0EB12400240C0
+:10A4A000C0EB00F000702E80B6070860A98F9307FC
+:10A4B0000860AA8FA8070C6020A12124C415086099
+:10A4C0004440322000F04190C3261CA19B80012013
+:10A4D00009D000F0822000F0C982007000F09A825A
+:10A4E0000521029800F0007001984091007008D09A
+:10A4F0003C9F0C7100F000F0007009D000F00120CA
+:10A50000F88F1F08026009A000F021080360118283
+:10A51000007000F01982007001900082007009D470
+:10A5200000F0104008D0B5070860968FA8070C60AF
+:10A530000DA04082007000F000F0C03608D0A807DF
+:10A540000C600AA000F0C12607A10880007008D0A6
+:10A55000B50708608D8F8B070A6004A1A0230070E7
+:10A5600004A10090B52200F04190104009D44D8321
+:10A57000007001980090007009DC0082007008D023
+:10A5800000F00070FEA000F03020FC8000F00070B1
+:10A59000FCA000F03022FA8091070860838FAB079F
+:10A5A0000860808FAB070860818FAC0708607E8FE2
+:10A5B000AC0708607F8FAA0708607C8F04415709A9
+:10A5C00008600390007004A04440C20808604390F3
+:10A5D000007002A04440C6080860839000700080AC
+:10A5E00026CA0520EDA075C3007000F0C39000706E
+:10A5F00000F065C50070C0E000F0053008D0A80785
+:10A600000C60E8A000F0C03708D0A8070C60E7A0F5
+:10A61000079000700CA000F000700280A8070C608A
+:10A62000E4A00790C02600F0C791362200F000F0A9
+:10A63000312303903082007000F04090007040E1C0
+:10A6400000F0C03608D03080007000F04182007009
+:10A6500000F00082007040E100F0C03608D0A8078A
+:10A660000C60D9A000F0362200F000F0C22600F005
+:10A670003488007000F0A0C2312300F082820070A4
+:10A6800000F0FD9F007001903080007040E0458236
+:10A69000007000F04090007040E100F0C03608D03B
+:10A6A00000F0B81709600790007000F0D217096039
+:10A6B00000E6A0419E07086000F00070558F00F092
+:10A6C000B81708600790007000F0D217086000E625
+:10A6D000A0419E07096000F0007050AF00F00070CC
+:10A6E00078A200F0007096808D0708604B8FB0074D
+:10A6F000086048AF8E070860498F00F0007008D0EE
+:10A7000000F0B807086000F08B070A6000F0022034
+:10A7100000F0A1246A15006082906A1580D0A80715
+:10A720000C60B9A000F0007005A100F00070EFA26D
+:10A7300000F0F71E80D700F0D11E80D700F0007027
+:10A74000EEA0E01B00607980A8070C60B2A000F0CA
+:10A750000070CAA000F0007009D000F00070F4A0F2
+:10A76000E51B00607480A8070C60ADA000F00070CD
+:10A77000C5A000F0007009D000F0007024A1F31B08
+:10A7800000606FA000F00070DBA100F0B80A80D07C
+:10A79000A8070C60A6A000F0D91B0160FF7F006035
+:10A7A000ADAFA08C0060AAAF0082513089A200F04A
+:10A7B000A02183A200F0B80A80D0A8070C609FA057
+:10A7C00000F00070B7A000F0007009D000F0007039
+:10A7D00056A100900C1C006000F0791580D5FA1B82
+:10A7E00000605F80A8070C6098A000F00070B0A027
+:10A7F00000F0007009D000F000706EA13A9E0C1CB1
+:10A80000006000F0791580D18A90031C0060FA1B6B
+:10A81000006000E200F000705680A8070C608FA076
+:10A8200000F00070A7A000F0007009D000F00070E8
+:10A8300097A13A9E0C1C006000F0791580D18A9097
+:10A84000FA1B0060031C006000E200F000704D8005
+:10A85000A8070C6086A000F0A22284A050D400704B
+:10A8600000F000F00070019400F0007003800C1CF8
+:10A870000260C3A281900070049400F00070D8A21E
+:10A88000411C0160B4A200F000700194181C01602A
+:10A89000AAA14090791580D0A8070C607AA000F09A
+:10A8A000007092A000F0007009D000F00070D1A1FB
+:10A8B00000F00070FEA100F00070B0A100F0007088
+:10A8C0000080A8070C6073A000F0921C006000F0EC
+:10A8D000791580D200F00070B6A200F0007042A09E
+:10A8E00000F0B10A80D0A8070C606DA000F0B22380
+:10A8F00000F000F06A150360BA9E2C1C016000F0A5
+:10A900000070019000F0533008D000F051301182F7
+:10A91000A8070C6066A000F000707EA000F0007038
+:10A9200009D000F00070DFA100F00070BCB500F0AD
+:10A930000070069000F000709BA100F0B80A80D271
+:10A940003A1C016000F042463A1C006000F07915A4
+:10A9500080D200F0223508D000F06A15006000F0C7
+:10A96000791580D0A8070C6058A04446202556A031
+:10A97000389E6A15056000F0203509D400F02435B2
+:10A98000F6A100F0007009D44091791580D0A80795
+:10A990000C6051A01F1C01604FA000F051303EA27E
+:10A9A0001040007035A200F0007043826A15036009
+:10A9B00074A200F0533009D000F000704AA000F0FB
+:10A9C000362548A08E91007000F03635B70A80D049
+:10A9D000A8070C6046A000F0007070A2501C006038
+:10A9E00000F0498200700980A8070C6042A000F0C6
+:10A9F000007069A200F00070F99700F00070CB8F32
+:10AA0000A8070C603EA000F0212607A2439000702A
+:10AA100009D400F03F1E80D7A025791580D000F022
+:10AA2000007000F0A035541C00602136791580D2EA
+:10AA300000F00070F88FEC1B01600E80A8070C601E
+:10AA400034A000F000706EA200F00070029400F0DC
+:10AA5000007067A200F00070E9970082007016A2F3
+:10AA6000F31B0160D9A100F000700680A8070C60FC
+:10AA70002CA0251C016000F0461C026060A28190A1
+:10AA80004446C0E0A134B80708602435731580D06F
+:10AA900000F0007000F04090791580D0A8070C609D
+:10AAA00024A000F0A02105A200F000703EA0721CBE
+:10AAB0000060E78FA8070C6020A000F0007038A0AD
+:10AAC00000F0007009D000F000703EA000F00070AF
+:10AAD000029400F0007048A0811C0060E08FA8077D
+:10AAE0000C6019A000F0007031A000F0007009D0D7
+:10AAF00000F0007037A000F00070119000F00070BE
+:10AB00003AA000F000700F94791C0060D88FA8075D
+:10AB10000C6011A000F0007029A000F0007009D0B6
+:10AB200000F000703CA000F00070019400F0007094
+:10AB30000880A8070C600BA000F0007023A000F0B4
+:10AB4000007009D000F0007036A000F00070039093
+:10AB500000F0007039A000F000700194871C0060C4
+:10AB6000CA8F00F0921C006000F0791580D200F0CE
+:10AB7000B10A80D000F0007008D08B070A60FEAFE9
+:10AB800000F02B22FD8F40C00220FCAF09CA0070EC
+:10AB900000F08AC2007000F082C4007000F000F083
+:10ABA000023008D011208B070A6000F0902000F0DE
+:10ABB0000AD20070254092D7007000F0A8A0007063
+:10ABC00000F003D3007000F01BD7007000F00CD62B
+:10ABD00000200560E3801B4301609BD8202300F028
+:10ABE000E9A0007000F0CBA200020560C3A2004003
+:10ABF0000660E9A0800007608AA2007000F082A2CF
+:10AC00000070154052DF007000F0A9A0007008D05D
+:10AC100044080960E5AF00F09021E4AF00900070B7
+:10AC200008D00000006000F04E090860E1AF00F0BD
+:10AC3000803B28C000F0007000F02140007008D078
+:10AC400000F04408096000F00070E4AF00F07023E9
+:10AC5000016080A8007000F0088E007008D04709DD
+:10AC60000860D8AF00F00020D7AF82D4007000F0A9
+:10AC7000025C0254C0E22140007000F010C4007079
+:10AC800000F050D4003008D0FF030060EF8F00F0D8
+:10AC90004408096000F00070D7AF00F0801C01602C
+:10ACA00080A8007000F0408E007008D0470908604E
+:10ACB000CBAF00F00020CAAF02D5007000F0025305
+:10ACC0000251C0E22140007000F010C4007000F09A
+:10ACD000D0D4003008D000824E0908601A9244088F
+:10ACE000096000F082300FC000F0007000F000F04A
+:10ACF00002300FC000F0007000F03C92212000F004
+:10AD000000F0043C00F000F0813B28C000F000702F
+:10AD100000F01190007008D000F04408096000F0C5
+:10AD2000A8070C604E090860BFAF85AAA12000F0FB
+:10AD30002340453A00F000F0813B28C000F000704D
+:10AD400000F0C190007008D000F0C02600F000F0C4
+:10AD5000312000F000F0422700F0088000707640BB
+:10AD60001080D0150D60C032DA150E6054000070EE
+:10AD700000F06500007000F02482007000F000F028
+:10AD8000C539019C8E910070FB8FC634D5150D60BE
+:10AD900000F00070B64054000070A4AF2482007030
+:10ADA00000F000F00070019CBE9F0070FC8FDB8201
+:10ADB000463500F0C0226A18066000F0007000F00E
+:10ADC00030A0007000F083A8412700F0DBD70070AE
+:10ADD00000F084A9433C00F024D2C22700F008828E
+:10ADE000C43B00F030B0C22700F0A3B8007000F000
+:10ADF000A4B9007000F08090007000F000F00070C6
+:10AE0000049824830070019063B80070028083B8B6
+:10AE1000007000F084B9007000F0DBD7007000F023
+:10AE200024D2433D00F070B0C43C00F094BA0070EE
+:10AE300000F08090007000F000F00070029874BA8A
+:10AE40000070019054BA007000F053AAC43D00F0A5
+:10AE500000F0433B08D000F044080960A8070C60EC
+:10AE600084AF4E0908608AAF83AA007000F000F03A
+:10AE7000C33A00F000F0C52900F000F0432A00F0CA
+:10AE800000F0C42A00F0E8A0007000F013AA0070DF
+:10AE900000F028A1007000F014AA007000F000F08B
+:10AEA000452B00F000F0007000F068A1007000F089
+:10AEB00005AA007000F0D8A0007000F013AA00707E
+:10AEC00000F020A140080D6014AA0209026000F001
+:10AED000533000F000F0D53000F000F0D23112C055
+:10AEE00000F0007000F000F0502100F000F054304D
+:10AEF00000F000F0D53000F000F0D23112C000F0C8
+:10AF0000007000F000F0512100F000F0232000F06C
+:10AF100000F0A42000F000F0007000F01A83007030
+:10AF200000F012D1007000F05BD0007000F064D02F
+:10AF3000007000F0C8A0007000F002A1007000F0E6
+:10AF400043AA007000F09B80007000F040D00070B9
+:10AF500000F049D0007000F04482007000F05430DE
+:10AF60000209026000F0D33000F000F0D23112C0CC
+:10AF700000F0007000F000F0502100F000F04625D5
+:10AF8000F74000D7C52400F000F0C73300F000F010
+:10AF9000403300F0DB82A03600F000F0233700F0F1
+:10AFA00000F0A33700F000F086300FC000F0007012
+:10AFB00000F000F005300FC000F0007000F081409C
+:10AFC000073C00F000F0803B28C000F0007000F06B
+:10AFD0000082007008D000F04408096000F04E09BB
+:10AFE0000860A8070C6043AF00F0007049AF00F0A4
+:10AFF000402C00F000F0C12B00F03AA0B52000F08A
+:10B0000072A0C72700F004A800702340ADD74623E4
+:10B01000049C84AAFFFF00602C81007000F000F007
+:10B020004030049C00F00070078084AA007010403B
+:10B030002C83007000F000F04030049CC791007039
+:10B0400000F00342007040E18340007040E000F0F7
+:10B05000104007808681007021400082463300F056
+:10B0600000F027272DAFCF91007000F000F02737B8
+:10B0700000F000F0863B28C000F0007000F062AAEB
+:10B08000007000F01289007000F0423F007008D09C
+:10B0900000F044080960A8070C6025AF00F00070BC
+:10B0A0002BAFB3204E09086080AA412B00F01BD7BC
+:10B0B000422F00F00C82007000F02489007000F034
+:10B0C000A782007000F000F04520149800F0007096
+:10B0D00013901F830070154000F00070049800F07A
+:10B0E000007003904782007000F0759F0070C0E10F
+:10B0F00000F0007002809282443F00F08890C03FD0
+:10B1000008D000F0462300F000F0453000F000F0D9
+:10B11000C03F00F0AE81443F00F000F0463300F045
+:10B1200000F027270DAFCF91007000F000F0273717
+:10B1300000F000F0863B28C000F0007000F00082B4
+:10B14000214008D000F0C72F00F045910070114059
+:10B15000C6830070029C0140007040E100F0007066
+:10B16000018001400070C0E100F0462300F000F0D3
+:10B17000C72300F000F0C13000F0AE83C03F00F004
+:10B180000082443F00F0EF81463300F000F0C73307
+:10B1900000F000F0073C00F000F02727F9AECF9157
+:10B1A000007000F000F0273700F000F0863B28C068
+:10B1B00000F0007000F0389E214008D000F04408F4
+:10B1C0000960A8070C60F3AE00F00070F9AE412BE7
+:10B1D0004E09086080AAC22300F000F02727EEAED7
+:10B1E000CF91007000F000F0273700F00C82B32000
+:10B1F00000F02489C03F00F01BD7443F00F01F83BC
+:10B20000007000F000F00070D29B00F00070D1934D
+:10B210008790C62000F08F980070029000F00070B8
+:10B22000019C00F045200D80BE9F007000F0FF8360
+:10B230004520CB93FE93412300F04591C63300F0A7
+:10B24000719C063C40E16990007000F000F04133D1
+:10B2500000F000F0A627DAAE8E91007000F000F04A
+:10B26000A63700F000F0813B28C000F0007000F02D
+:10B27000F89F214008D02140C623D4AEAE81007093
+:10B2800000F000F0C63300F00082063C08D02040F9
+:10B29000C727D0AEC791440809603090004240EA09
+:10B2A00000F0007000F01031007008D0A8070C60AA
+:10B2B000CCAEC02B00400660412C8000076030B04F
+:10B2C000007000F079B0007000F072BA46250FA04F
+:10B2D00000F0C33100F000F0423208D000F00070FE
+:10B2E000FCA000F00070019000F00070E18000F020
+:10B2F0004408096000F00070C7AE00F0C12700F0FC
+:10B3000092AA007000F04190007000F052AA007004
+:10B3100040E172AA007040E000F0462502A000F073
+:10B32000C33100F000F0423208D000F040080D6058
+:10B3300000F02823006052300209076000F0D0308E
+:10B3400000F0D731DF150F60899F007085C87C70D1
+:10B350007020C0E2799E007000F080A0007000F0C4
+:10B3600023AA007000F036D2007005C000F0004043
+:10B37000046037A3512100F03FD1FF7F066078B011
+:10B38000007000F022BA007000F08291007040E17D
+:10B3900000F0007008D000F04408096000F0007070
+:10B3A000ABAE82AA402D00F093A9007000F052D0FD
+:10B3B00000400660D2D7800007601BD2C12C04A0D9
+:10B3C0001489362500F03D83403100F08E910070E5
+:10B3D00009D83635B70A80D0B8B0442500F0F1B0AE
+:10B3E000007000F03AB0433E00F072B0C23E00F090
+:10B3F00082BA0070CEA000F0007008904340A422F2
+:10B4000093AE1CC3C52D00F0206E046000E23E67C1
+:10B41000046000E600F0372100F0A0A0007000F00A
+:10B4200040AA007000F0AA82007008D0E4D1007039
+:10B4300000F0A0B040080D6081B80209076053A871
+:10B44000D13000F000F0533000F000F0D73100F0C0
+:10B45000C32D007011C000F0372100F09A825021F6
+:10B46000838E00F04408096000F0007089AE00F09F
+:10B47000C22E00F000F0432E00F0BAA0007000F0E1
+:10B48000F2A0FCFF046080AAB72500F000890070DC
+:10B4900000F020C2007000F000F0007009D0CF91E1
+:10B4A000007000F00090B73508D0A8070C6077AEA8
+:10B4B00000F0BE2400F000F0402174AE00F06030D7
+:10B4C00008D00490007024A00390C02272AE429075
+:10B4D000412700F020806A1805600882007000F0A3
+:10B4E00028B0007000F0A0B8007000F0A1B90070A2
+:10B4F00000F0C0D794080860D0A1007000F099A1B6
+:10B50000007000F009D20070CDAF00F0003008D01C
+:10B510009108086065AE0120FE7F02600090007017
+:10B5200000F003581340C0E251C2007000F059C44B
+:10B53000007000F000F0013008D0E40808605EAE52
+:10B5400000F0003008D00082BE2400F000F042215C
+:10B5500000F000F061205AAE8F82007000F000F021
+:10B56000007009D0799E007001985190007000F031
+:10B570000890613008D00342007001808340007061
+:10B5800000804408096052AE1331007008D0A8074B
+:10B590000C6050AE412D800007600654C02C4E8ECA
+:10B5A000A8070C604DAEC12E800007600654402EE7
+:10B5B0004B8EA8070C604BAE00F04E090860FF03ED
+:10B5C000016000F000F0C22400F000F0432500F01C
+:10B5D00000F0442300F000F0C52300F000F0813BB0
+:10B5E00028C000F0007000F000F083300FC000F0C1
+:10B5F000007000F000F002300FC000F0007000F0AA
+:10B60000C1254B09096042264C090A6000F011303F
+:10B6100000F000F0223000F000F0843B00F000F079
+:10B62000053C28C000F0007000F000F0402419A094
+:10B6300000F00070BE8F1240007011A000F04409AD
+:10B640000D6000F047090E6080FF04600ACBF647EA
+:10B65000522030AE92D3452400F052D0632008909F
+:10B6600000F0024002947D9F007000F0558D007044
+:10B6700002804D91007000F0758B007000F0E3C205
+:10B68000453400F0EBC4007000F000F0633026AEEB
+:10B6900000F0532000F09282007001A09BD3007054
+:10B6A00008D000F043090E60BFFF056000F092D1A2
+:10B6B000642020AE2CC3007000F014C5007000F0B0
+:10B6C00000F0643008D047090E601CAE02486120CB
+:10B6D0001BAE51C2007000F041C4403400F000F0D5
+:10B6E000613008D04309086017AE012047FF0260AF
+:10B6F00000F0007000F051C2007000F00090007087
+:10B7000000F012CA0070019051C4007000F000F007
+:10B71000013008D02021F6280160C2224B090860C0
+:10B7200008A04C090960B0AB423600F000F0C0350B
+:10B7300000F000F0003000F000F0123008D0C0221D
+:10B740006A18026000F0007000F010A0007000F0B5
+:10B75000A3A8007000F0A2A9007000F0DBD7007071
+:10B7600000F012D2C33E00F000F0423E00F000F0C4
+:10B77000007039A000F000701694C02240080860E4
+:10B78000015202090260C0D0007000F00030E915DB
+:10B790000D608130E4150E608231007000F000F021
+:10B7A000412512C000F0422700F009D2032100F029
+:10B7B00050A0007000F0F1AAB82400F059A2422570
+:10B7C00000F000F0413100F08A9E013000F000F0FE
+:10B7D000670000F0BA9E510000F000F00070FD9F7D
+:10B7E000C9A2C02200F049D0007000F038A000705B
+:10B7F00000F073AA413200F000F0C33108D043409A
+:10B80000A022E8AD18C2412700F00554006000E214
+:10B81000C44E006000E600F0007000F008A0B824FC
+:10B8200000F0B0AA007000F000F0403100F000F02D
+:10B83000003000804340A022DFAD18C2007000F04D
+:10B8400000F0007002906D71006000F0B19E036026
+:10B850000280FD78006000F0C694036000F000F004
+:10B86000403200F000F0C33108D044090860D6AD82
+:10B87000C2400120D5AD51C2007008D000F0432372
+:10B88000FCAF48D34E09086048D700400394FF033B
+:10B89000026009D0CB90007000F0D38A0070028063
+:10B8A000FB9E007000F01B8C0070008000F0833B5A
+:10B8B00028C000F0007000F000F0433308D000F022
+:10B8C000A022C8ADC0D3007008D08B070A60C6ADF7
+:10B8D0002140A322C5ADC9C2007008D08B070A6001
+:10B8E000C3AD00F0A022C2AD40D4007008D0A008C3
+:10B8F0000860C0AD33430220BFAD9AC4007000F0B1
+:10B9000000F0023008D0A0080860BCAD414400201F
+:10B91000BBAD08C2007000F00882007008D0C344BC
+:10B92000A0080860A122FF7F04601040022000F000
+:10B9300061C2007000F09AC2007000F043C224405F
+:10B9400000F082C44540C0E063C2004100F06BC219
+:10B95000A132F29340D0007040E082C40070F08FBA
+:10B960008B070A60ECAFC24FA322ACADD3C200700C
+:10B9700000F049D0025800F008C4007000F010C474
+:10B98000007000F0C3C4007000F000F0A33208D0D3
+:10B990001440A322A5ADE0C2007000F064D0007096
+:10B9A0008BAFE0C2A108096000F000700194004074
+:10B9B000007003804040007004A0C0C2007000F01E
+:10B9C00030402040C0E200F0007000F000F0103085
+:10B9D00008D08240A3229AADD4C2B74F00F00241F2
+:10B9E00040060460FBC24640029400F0C52296ADBA
+:10B9F000658FA1220180D2C2A12200F0F3C40258B7
+:10BA0000C0E059C6007000F0D3C40070C0E000F080
+:10BA1000A33208D00082BA070860C1070E6016C0C2
+:10BA200000104D060160001085020260613DCD0CE2
+:10BA30000360E230CD0C0460633E02000560E43137
+:10BA400003000660E53F007000F06633007008D028
+:10BA50004190C107096000F0E801086092829137C7
+:10BA60003E9400F0023400F08234AD02086000F031
+:10BA70009902026000F09A0203600232A2020260A0
+:10BA80008332A30203600230AB0202608330AC0257
+:10BA900003600231007000F08331007008D0FF8332
+:10BAA000BA0709604190C10708609733171340E651
+:10BAB00000F0923000F000F0933100F000F014300C
+:10BAC00000F000F0153200F000F096324B80C10714
+:10BAD000096050A000F094274FA00491913F00F01E
+:10BAE00000F0123309D000F000702780C107086011
+:10BAF0004BA000F00037448000F0C1070E6000F05A
+:10BB0000BA4D0960E72740080D60E52C2105086063
+:10BB1000C791593000F000F0553109D0FF9FD8315E
+:10BB200000F0632DE32DC0E2E4206421C0E25B81DC
+:10BB3000672000F0EEC6593000F0AEC3573100F078
+:10BB400076D4E33C00F0E481E52200F0E4C7643001
+:10BB500000F0E7C3642600F07FD4E32600F000F095
+:10BB6000E73600F07D9FE52100F09CD3007040E0B7
+:10BB700028A1672200F02CA5E32500F03C81652E6A
+:10BB800000F0E384E43400F000F0633500F000F0EE
+:10BB9000D83100F000F0642F00F000F0D32000F066
+:10BBA0003C9FE72500F0B3D3E62E40E0E8A06734E1
+:10BBB00000F0EBA4007000F0F38000700DC000F006
+:10BBC000007000F000F0D42000F000F0E33500F049
+:10BBD00000F0643608D000F0962F00F000F0C707A0
+:10BBE00005608691AD020860728100700594A20222
+:10BBF000046000F09902026000F00430AB020460BF
+:10BC000000F0023200F000F00431038000F0023254
+:10BC100000F000F0023000F000F0023100F000F01F
+:10BC2000162318A08691007000F0738100700594AF
+:10BC3000A302046000F09A02036000F08430AC02BA
+:10BC4000046000F0833200F000F08431038000F0E3
+:10BC5000833200F000F0833000F000F0833100F018
+:10BC6000952FC707036000F0E8010C60EA800070C0
+:10BC700000F04591007000F086914534019000F08D
+:10BC8000423400F0F280C63409D000F0C23408D04B
+:10BC9000C107086005A000F0012D00F000F00227A8
+:10BCA00003A053A2812002A053A2833D00F000F024
+:10BCB000033108D000F0007008D00054D6070A60A5
+:10BCC0001140EE15086000F0A03000F000F02130C7
+:10BCD00000F000F0090000F000F000008DC800F056
+:10BCE000090000F01030000000F000F0007008D0F3
+:10BCF0000240DB070960A342D6070A601230FFFF4B
+:10BD0000046000F0A331454100F02431005800F0F8
+:10BD10002532F28F00F0007008D00082D207086050
+:10BD200000F03AE4016005200DB602608620285F2D
+:10BD300003604DC791C7046096C7052140E0862186
+:10BD4000DB070B605DC7003040E0A6C7003140E074
+:10BD500008900070C0E000F0B03008D000F0D207CA
+:10BD6000086000F03AE4016000F00DB602600130B6
+:10BD7000285F0360823091C704600331007000F0D7
+:10BD80008431007008D0D6070960ECAF00F01030A5
+:10BD900008D0D6070960EAAF00F0103108D0D60706
+:10BDA0000960E8AF00F0142100F000F09220035C7D
+:10BDB00020C2112000F0D3C2100908604190007029
+:10BDC00009D482C40070059000F0923008D0D607E4
+:10BDD0000960E0AF4982902000F0913010090860BE
+:10BDE0001130007000F000F0003008D01009086039
+:10BDF000DBAF00F0003008D0F441030000F000F0A9
+:10BE0000D1070F60E0C2090000F0DBD67830039064
+:10BE100000F0010000F0389E783000F000F01110C2
+:10BE2000FD97E0C2034000F0389E007009D0389EB4
+:10BE30001310FF9700F0007008D000F0020000F02F
+:10BE400000F00070F3AF00F07120CCAF51820070B1
+:10BE500000F000F00070FC9B00F0007008D0D607E6
+:10BE60000F60C8AF0082F721028000F0007009D88F
+:10BE700000F0007000F200F0007001A0FF9F007061
+:10BE8000FC8F00F0D607086000F06408096000F03D
+:10BE90000022C0AF00F0103008D0104064080960E4
+:10BEA00000F0007000F000F01030BCAF00F0007047
+:10BEB00000F200F0007000F200F0007008D024835F
+:10BEC000590908604190FF0F05605B9A06200398AE
+:10BED0004B98045200EEAEC3045100EE48090960CD
+:10BEE00003805B94480909607396045400EAAEC36A
+:10BEF000045800EA00F04A290360A6C511208440D6
+:10BF00009BA20630F0401C81FFF00660048B0440C9
+:10BF1000C0EB71C2007000F024D2007000F061C468
+:0ABF2000007000F000F0113008D0AE
+:00000001FF
diff --git a/firmware/R1f.2_SoC1v20_EXT_src_coeff_1.1.fw.ihex b/firmware/R1f.2_SoC1v20_EXT_src_coeff_1.1.fw.ihex
new file mode 100644
index 00000000000..7f1def62dd5
--- /dev/null
+++ b/firmware/R1f.2_SoC1v20_EXT_src_coeff_1.1.fw.ihex
@@ -0,0 +1,130 @@
+:10000000070046B304080000F9FFFCFF2A007E0049
+:10001000A1004400B3FFA3FF34008600FAFF55FFA0
+:10002000BEFFBB00A20059FFF0FE610079011F0076
+:100030003AFE27FFDA01C30167FE38FDE600C6037A
+:1000400053006EFBDAFDF304A3045FFB11F82803F1
+:10005000730C790032ECCCF51529A45CA45C15294D
+:10006000CCF532EC7900730C280311F85FFBA30484
+:10007000F304DAFD6EFB5300C603E60038FD67FEAD
+:10008000C301DA0127FF3AFE1F0079016100F0FE8B
+:1000900059FFA200BB00BEFF55FFFAFF86003400E7
+:1000A000A3FFB3FF4400A1007E002A00FCFFF9FF7C
+:1000B0000000000000000000000000000000000040
+:1000C0000000000000000000000000000000000030
+:1000D0000000000000000000000000000000000020
+:1000E0000000000000000000000000000000000010
+:1000F0000000000000000000000000000000000000
+:1001000000000000000000000000000000000000EF
+:1001100000000000000000000000000000000000DF
+:1001200000000000000000000000000000000000CF
+:1001300000000000000000000000000000000000BF
+:1001400000000000000000000000000000000000AF
+:10015000000000000000000000000000000000009F
+:10016000000000000000000000000000000000008F
+:10017000000000000000000000000000000000007F
+:10018000000000000000000000000000000000006F
+:10019000000000000000000000000000000000005F
+:1001A000000000000000000000000000000000004F
+:1001B000000000000000000000000000000000003F
+:1001C000000000000000000000000000000000002F
+:1001D000000000000000000000000000000000001F
+:1001E000000000000000000000000000000000000F
+:1001F00000000000000000000000000000000000FF
+:1002000000000000000000000000000000000000EE
+:1002100000000000000000000000000000000000DE
+:1002200000000000000000000000000000000000CE
+:1002300000000000000000000000000000000000BE
+:1002400000000000000000000000000000000000AE
+:10025000000000000000000000000000000000009E
+:10026000000000000000000000000000000000008E
+:10027000000000000000000000000000000000007E
+:10028000000000000000000000000000000000006E
+:10029000000000000000000000000000000000005E
+:1002A000000000000000000000000000000000004E
+:1002B000000000000000000000000000000000003E
+:1002C000000000000000000000000000000000002E
+:1002D000000000000000000000000000000000001E
+:1002E000000000000000000000000000000000000E
+:1002F00000000000000000000000000000000000FE
+:1003000000000000000000000000000000000000ED
+:1003100000000000000000000000000000000000DD
+:1003200000000000000000000000000000000000CD
+:1003300000000000000000000000000000000000BD
+:1003400000000000000000000000000000000000AD
+:10035000000000000000000000000000000000009D
+:10036000000000000000000000000000000000008D
+:10037000000000000000000000000000000000007D
+:10038000000000000000000000000000000000006D
+:10039000000000000000000000000000000000005D
+:1003A000000000000000000000000000000000004D
+:1003B000000000000000000000000000000000003D
+:1003C000000000000000000000000000000000002D
+:1003D000000000000000000000000000000000001D
+:1003E000000000000000000000000000000000000D
+:1003F00000000000000000000000000000000000FD
+:1004000000000000000000001100060007000900C5
+:100410000A000C000D000F00110013001500180059
+:100420001B001D002000240027002B002F0033009C
+:1004300037003C00410046004C00510057005D0071
+:1004400064006A0071007800800087008F009700C8
+:10045000A000A800B100BA00C300CC00D500DE00A7
+:10046000E800F100FB0005010E01180121012A013D
+:1004700033013C0145014E0156015E0165016C01ED
+:10048000730179017E01830187018B018D018F0149
+:10049000900190018F018D01890185017F01790112
+:1004A000700167015C014F014101310120010D0123
+:1004B000F800E200CA00AF00930075005500340058
+:1004C0001000EAFFC2FF98FF6CFF3EFF0FFFDDFE4A
+:1004D000A9FE73FE3BFE02FEC6FD89FD4AFD09FD35
+:1004E000C6FC82FC3DFCF6FBAEFB65FB1AFBCFFABB
+:1004F00083FA36FAE8F99BF94CF9FEF8B0F861F89E
+:1005000014F8C6F77AF72EF7E4F69BF653F60DF6D5
+:10051000CAF588F549F50DF5D3F49DF46AF43BF47A
+:100520000FF4E8F3C5F3A7F38EF37AF36BF363F3F9
+:100530005FF363F36CF37CF393F3B1F3D7F304F459
+:1005400039F476F4BBF408F55EF5BDF524F695F6BE
+:100550000FF793F71FF8B6F856F900FAB4FA71FBE3
+:1005600039FC0BFDE7FDCDFEBDFFB700BB01C902A5
+:10057000E10302052E066207A108E809390B930C76
+:10058000F50D600FD3104E12D1135B15ED168518C3
+:10059000241AC91B741D241FDA2094225224142605
+:1005A000DA27A3296E2B3B2D092FD930A9327A34B3
+:1005B0004A361938E739B23B7C3D423F0541C342D8
+:1005C0007E443346E2478C492F4BCA4C5E4EEA4F7D
+:1005D0006D51E8525854BF551B576C58B259EC5ADC
+:1005E0001A5C3B5D505E575F50603C611962E86287
+:1005F000A7635864FA648C650E668066E2663467A9
+:100600007667A867C967D967D967C967A867766732
+:100610003467E26680660E668C65FA645864A76388
+:10062000E86219623C615060575F505E3B5D1A5C46
+:10063000EC5AB2596C581B57BF555854E8526D517B
+:10064000EA4F5E4ECA4C2F4B8C49E24733467E44FC
+:10065000C3420541423F7C3DB23BE73919384A3637
+:100660007A34A932D930092F3B2D6E2BA329DA27F2
+:10067000142652249422DA20241F741DC91B241A24
+:100680008518ED165B15D1134E12D310600FF50DC2
+:10069000930C390BE809A10862072E060205E10355
+:1006A000C902BB01B700BDFFCDFEE7FD0BFD39FC64
+:1006B00071FBB4FA00FA56F9B6F81FF893F70FF782
+:1006C00095F624F6BDF55EF508F5BBF476F439F43D
+:1006D00004F4D7F3B1F393F37CF36CF363F35FF3B8
+:1006E00063F36BF37AF38EF3A7F3C5F3E8F30FF438
+:1006F0003BF46AF49DF4D3F40DF549F588F5CAF599
+:100700000DF653F69BF6E4F62EF77AF7C6F714F8D3
+:1007100061F8B0F8FEF84CF99BF9E8F936FA83FA7B
+:10072000CFFA1AFB65FBAEFBF6FB3DFC82FCC6FC78
+:1007300009FD4AFD89FDC6FD02FE3BFE73FEA9FED2
+:10074000DDFE0FFF3EFF6CFF98FFC2FFEAFF1000C7
+:100750003400550075009300AF00CA00E200F800B5
+:100760000D012001310141014F015C016701700160
+:1007700079017F01850189018D018F01900190012F
+:100780008F018D018B01870183017E017901730146
+:100790006C0165015E0156014E0145013C013301CA
+:1007A0002A01210118010E010501FB00F100E800FA
+:1007B000DE00D500CC00C300BA00B100A800A00044
+:1007C00097008F0087008000780071006A00640045
+:1007D0005D00570051004C00460041003C003700CE
+:1007E00033002F002B002700240020001D001B00D9
+:1007F00018001500130011000F000D000C000A0076
+:080800000900070006001100C9
+:00000001FF
diff --git a/firmware/R2c_SoC2v01_BT_src_coeff_1.1.fw.ihex b/firmware/R2c_SoC2v01_BT_src_coeff_1.1.fw.ihex
new file mode 100644
index 00000000000..9922c736cd1
--- /dev/null
+++ b/firmware/R2c_SoC2v01_BT_src_coeff_1.1.fw.ihex
@@ -0,0 +1,130 @@
+:10000000080046B304080000F9FFFCFF2A007E0048
+:10001000A1004400B3FFA3FF34008600FAFF55FFA0
+:10002000BEFFBB00A20059FFF0FE610079011F0076
+:100030003AFE27FFDA01C30167FE38FDE600C6037A
+:1000400053006EFBDAFDF304A3045FFB11F82803F1
+:10005000730C790032ECCCF51529A45CA45C15294D
+:10006000CCF532EC7900730C280311F85FFBA30484
+:10007000F304DAFD6EFB5300C603E60038FD67FEAD
+:10008000C301DA0127FF3AFE1F0079016100F0FE8B
+:1000900059FFA200BB00BEFF55FFFAFF86003400E7
+:1000A000A3FFB3FF4400A1007E002A00FCFFF9FF7C
+:1000B0000000000000000000000000000000000040
+:1000C0000000000000000000000000000000000030
+:1000D0000000000000000000000000000000000020
+:1000E0000000000000000000000000000000000010
+:1000F0000000000000000000000000000000000000
+:1001000000000000000000000000000000000000EF
+:1001100000000000000000000000000000000000DF
+:1001200000000000000000000000000000000000CF
+:1001300000000000000000000000000000000000BF
+:1001400000000000000000000000000000000000AF
+:10015000000000000000000000000000000000009F
+:10016000000000000000000000000000000000008F
+:10017000000000000000000000000000000000007F
+:10018000000000000000000000000000000000006F
+:10019000000000000000000000000000000000005F
+:1001A000000000000000000000000000000000004F
+:1001B000000000000000000000000000000000003F
+:1001C000000000000000000000000000000000002F
+:1001D000000000000000000000000000000000001F
+:1001E000000000000000000000000000000000000F
+:1001F00000000000000000000000000000000000FF
+:1002000000000000000000000000000000000000EE
+:1002100000000000000000000000000000000000DE
+:1002200000000000000000000000000000000000CE
+:1002300000000000000000000000000000000000BE
+:1002400000000000000000000000000000000000AE
+:10025000000000000000000000000000000000009E
+:10026000000000000000000000000000000000008E
+:10027000000000000000000000000000000000007E
+:10028000000000000000000000000000000000006E
+:10029000000000000000000000000000000000005E
+:1002A000000000000000000000000000000000004E
+:1002B000000000000000000000000000000000003E
+:1002C000000000000000000000000000000000002E
+:1002D000000000000000000000000000000000001E
+:1002E000000000000000000000000000000000000E
+:1002F00000000000000000000000000000000000FE
+:1003000000000000000000000000000000000000ED
+:1003100000000000000000000000000000000000DD
+:1003200000000000000000000000000000000000CD
+:1003300000000000000000000000000000000000BD
+:1003400000000000000000000000000000000000AD
+:10035000000000000000000000000000000000009D
+:10036000000000000000000000000000000000008D
+:10037000000000000000000000000000000000007D
+:10038000000000000000000000000000000000006D
+:10039000000000000000000000000000000000005D
+:1003A000000000000000000000000000000000004D
+:1003B000000000000000000000000000000000003D
+:1003C000000000000000000000000000000000002D
+:1003D000000000000000000000000000000000001D
+:1003E000000000000000000000000000000000000D
+:1003F00000000000000000000000000000000000FD
+:1004000000000000000000001100060007000900C5
+:100410000A000C000D000F00110013001500180059
+:100420001B001D002000240027002B002F0033009C
+:1004300037003C00410046004C00510057005D0071
+:1004400064006A0071007800800087008F009700C8
+:10045000A000A800B100BA00C300CC00D500DE00A7
+:10046000E800F100FB0005010E01180121012A013D
+:1004700033013C0145014E0156015E0165016C01ED
+:10048000730179017E01830187018B018D018F0149
+:10049000900190018F018D01890185017F01790112
+:1004A000700167015C014F014101310120010D0123
+:1004B000F800E200CA00AF00930075005500340058
+:1004C0001000EAFFC2FF98FF6CFF3EFF0FFFDDFE4A
+:1004D000A9FE73FE3BFE02FEC6FD89FD4AFD09FD35
+:1004E000C6FC82FC3DFCF6FBAEFB65FB1AFBCFFABB
+:1004F00083FA36FAE8F99BF94CF9FEF8B0F861F89E
+:1005000014F8C6F77AF72EF7E4F69BF653F60DF6D5
+:10051000CAF588F549F50DF5D3F49DF46AF43BF47A
+:100520000FF4E8F3C5F3A7F38EF37AF36BF363F3F9
+:100530005FF363F36CF37CF393F3B1F3D7F304F459
+:1005400039F476F4BBF408F55EF5BDF524F695F6BE
+:100550000FF793F71FF8B6F856F900FAB4FA71FBE3
+:1005600039FC0BFDE7FDCDFEBDFFB700BB01C902A5
+:10057000E10302052E066207A108E809390B930C76
+:10058000F50D600FD3104E12D1135B15ED168518C3
+:10059000241AC91B741D241FDA2094225224142605
+:1005A000DA27A3296E2B3B2D092FD930A9327A34B3
+:1005B0004A361938E739B23B7C3D423F0541C342D8
+:1005C0007E443346E2478C492F4BCA4C5E4EEA4F7D
+:1005D0006D51E8525854BF551B576C58B259EC5ADC
+:1005E0001A5C3B5D505E575F50603C611962E86287
+:1005F000A7635864FA648C650E668066E2663467A9
+:100600007667A867C967D967D967C967A867766732
+:100610003467E26680660E668C65FA645864A76388
+:10062000E86219623C615060575F505E3B5D1A5C46
+:10063000EC5AB2596C581B57BF555854E8526D517B
+:10064000EA4F5E4ECA4C2F4B8C49E24733467E44FC
+:10065000C3420541423F7C3DB23BE73919384A3637
+:100660007A34A932D930092F3B2D6E2BA329DA27F2
+:10067000142652249422DA20241F741DC91B241A24
+:100680008518ED165B15D1134E12D310600FF50DC2
+:10069000930C390BE809A10862072E060205E10355
+:1006A000C902BB01B700BDFFCDFEE7FD0BFD39FC64
+:1006B00071FBB4FA00FA56F9B6F81FF893F70FF782
+:1006C00095F624F6BDF55EF508F5BBF476F439F43D
+:1006D00004F4D7F3B1F393F37CF36CF363F35FF3B8
+:1006E00063F36BF37AF38EF3A7F3C5F3E8F30FF438
+:1006F0003BF46AF49DF4D3F40DF549F588F5CAF599
+:100700000DF653F69BF6E4F62EF77AF7C6F714F8D3
+:1007100061F8B0F8FEF84CF99BF9E8F936FA83FA7B
+:10072000CFFA1AFB65FBAEFBF6FB3DFC82FCC6FC78
+:1007300009FD4AFD89FDC6FD02FE3BFE73FEA9FED2
+:10074000DDFE0FFF3EFF6CFF98FFC2FFEAFF1000C7
+:100750003400550075009300AF00CA00E200F800B5
+:100760000D012001310141014F015C016701700160
+:1007700079017F01850189018D018F01900190012F
+:100780008F018D018B01870183017E017901730146
+:100790006C0165015E0156014E0145013C013301CA
+:1007A0002A01210118010E010501FB00F100E800FA
+:1007B000DE00D500CC00C300BA00B100A800A00044
+:1007C00097008F0087008000780071006A00640045
+:1007D0005D00570051004C00460041003C003700CE
+:1007E00033002F002B002700240020001D001B00D9
+:1007F00018001500130011000F000D000C000A0076
+:080800000900070006001100C9
+:00000001FF
diff --git a/firmware/R2c_SoC2v01_Cobra_FM_SOC2_coef.fw.ihex b/firmware/R2c_SoC2v01_Cobra_FM_SOC2_coef.fw.ihex
new file mode 100644
index 00000000000..b67325acdc0
--- /dev/null
+++ b/firmware/R2c_SoC2v01_Cobra_FM_SOC2_coef.fw.ihex
@@ -0,0 +1,195 @@
+:1000000005009F23140C0000E8FFA6FF2FFF91FEC0
+:100010002EFE91FE5000D803E6089D0EAD139D16EE
+:100020009D16AD139D0EE608D803500091FE2EFEDE
+:1000300091FE2FFFA6FFE8FF0504F60B0014F11B4D
+:10004000F11B0014F60B0504B601DF03C2054407DB
+:10005000530890095E0ADF0ADF0A5E0A9009530816
+:100060004407C205DF03B6012F00D900630245052E
+:100070006209210E7C12021502157C12210E620902
+:1000800045056302D9002F0048FAF0E197BED5A3D9
+:1000900008A404BF43E25FFAA105BD1DFC40F85B64
+:1000A0002B5C6941101EB805B3FACCFC0FFA47FF70
+:1000B000CD064E11A61CFD21FD21A61C4E11CD061C
+:1000C00047FF0FFACCFCB3FA87108101F801B801A1
+:1000D000EA000502020000000000FF7F70177017A1
+:1000E000FF7FFF7F1F001F00E40016022100210098
+:1000F000200020002F02D8015A0000000004000454
+:10010000A6FF000400000000C264020001006F4569
+:10011000020000000100C264C2642C43030002001C
+:1001200002009D104D0121020100A91AAA3C010004
+:1001300010016A07C20027005206DD00CE04FF7FCF
+:10014000FF7FC70AE1251400860140051517280026
+:10015000C300A902650E4E004E0010016A07C200DE
+:100160002700CE10A3018202000084035A00A400DD
+:1001700092027245FF7F0000FF7FA4009B02FC6695
+:10018000FF7F0000FF7FA400A402FC66FF7F000049
+:10019000FF7F4700AD02A202A302AB02AC029902AC
+:1001A0009A02FFFFFFFF180007080B280D0812082E
+:1001B000134814082228264829282A282B482D28A5
+:1001C0003548372839083B283D48404842484428AC
+:1001D00045084B084F4852280F00700855285728EB
+:1001E00059285B285D285F8861086428662868288C
+:1001F00070086A286C286E281000712873287548CA
+:10020000772879287B287D287F28812883288528BE
+:10021000872889288B288D288F28380096689B2866
+:100220009D089F08A128A328A528A728A928AB488E
+:10023000AD48AF48B048B128B388B528B768B928E9
+:10024000BB88BD08BF28C728C828CA08CD08CF2842
+:10025000D128D308D508D728E048E348E628E8881D
+:10026000ED28F208F4A8DC28F90800290629082955
+:100270000A290C290E09100912091409160918492E
+:100280001C2922492F293129332935C91C003869F5
+:100290003D293F2944097409472949494B894D297A
+:1002A0004F295129530957295A495C296109642961
+:1002B00066A968296A296C296E49702972A974098E
+:1002C0007529740977290B008229844986C989090F
+:1002D0008DE9910993E99429952996A99B092849C3
+:1002E0000000084800000C7800200D600000F42693
+:1002F00000500C7800280C7800280D7800000D784C
+:1003000000200C7800200C7800000C41000436011D
+:1003100000041E5100041C5100040C590004E56245
+:10032000C6207013A40D5D0A3C08B9069705B304F6
+:10033000FC036403E40278021B02CB01850148013F
+:100340001401E600BF009D008000670052004000DD
+:10035000310025001B0013000D0008000500E262BB
+:10036000BE206213920D460A1F0898067105890483
+:10037000CD033103AE023F02DF018C0144010601CF
+:10038000D100A2007B00C31141007C007B00CA1198
+:1003900084001A03F6FF0060A4000300E0110400CB
+:1003A00039030C6080408240770404003E032C60D7
+:1003B000A040A240780401004303CC6004005B032A
+:1003C000B800B00161044503B51222004504006085
+:1003D0000035880072030E0003000A000E00E513CA
+:1003E000007018000F0028007F030003000C000EAF
+:1003F0000060010000600001002028008803380030
+:1004000040030000FF7F0100FF7F00010010280073
+:1004100091030004000A0000FF7F0100FF7F000439
+:10042000002028009A030000C000001800600100AE
+:100430000060800000082800A3030C003800004082
+:10044000FF7F0100FF7F000200102800AC030000C6
+:100450000004000400780100006000040010150092
+:10046000B5030001000880000004000400208000A3
+:1004700000024000000100010010200000010008FF
+:10048000100040000001000A800010001500CA039F
+:100490000010002000400040004000020004004026
+:1004A0000008007000010040000200080040000148
+:1004B000FF7F00200020001000046600E103000818
+:1004C000100099597900BFE040002500EF03870430
+:1004D000EC0316012C02BD0A4400F5035C04ED0395
+:1004E00033033D0A0600FB037003EE03D83B2549A6
+:1004F000BE0ABE0A6A000104FF7F008000000000FF
+:100500000000800200000000000E00206A000E04BF
+:10051000FF7F0080000000000000000B00000000D2
+:10052000000600206A001B04FF7F00FC00000000A2
+:100530000000000800000000000100204B0028041B
+:10054000FF7F00FF8003000000000014800800000F
+:100550006000002080032C003504FF7F80F700102E
+:100560000080000000020000001200020018001DC0
+:10057000001855859FFF009041FFAB9ABDFE55A521
+:1005800008FE00B013FDABBACCFB55C510FA00D085
+:10059000A2F7ABDAFDF355E5C6ED00F0F8DFABFAF4
+:1005A0005B9DF8FFE8FFC9FF9BFF5FFF1CFFDEFEBE
+:1005B000BDFED0FE36FF0600530120035F05F107A4
+:1005C000A30A3B0D760F1A11F81103000000F6FF85
+:1005D000D9FFA6FF59FFF9FE95FE4CFE46FEB3FE7D
+:1005E000BBFF7A01F20307077A0AF30D0A115D13C4
+:1005F0009D14090018002E003F003E001700BBFFAD
+:1006000025FF6AFEB7FD59FDA3FDE9FE5A01F4047A
+:1006100070094B0ED71260164F18030011002F00FF
+:100620005F009100B00094001F0042FF19FEF3FC30
+:100630004FFCBBFCB5FE7102BC07F20D1314001990
+:10064000BE1BFAFFF7FFFBFF19005400A600EA00EB
+:10065000EA006B0052FFC6FD47FC9CFB9FFCEBFFD2
+:100660009105E70C9F14121BBE1EF7FFE3FFC7FFA7
+:10067000B7FFD3FF2F00C7005F019401F80060FFB0
+:100680001DFD1BFBA5FAF8FCA6022B0BDC14581D64
+:100690004C220200F9FFE0FFB3FF8FFFA1FF15001E
+:1006A000E700C10104021301C9FED9FBD6F9ADFA76
+:1006B000BEFFF8088014231F86250C001C002400B0
+:1006C0000400B2FF50FF36FFBEFFF1003F029D0263
+:1006D0001C01C2FD13FAC0F865FCE9057913DB20A3
+:1006E0002C2907001D003C00460010008FFF03FF6F
+:1006F000F9FEE2FF97010403A802AFFF1EFBFCF71F
+:1007000000FA3C033A12F021002CFBFFFFFF170018
+:1007100048006200250078FFC4FED6FE3C006B0254
+:100720009A03DF0117FD1EF8DAF71F006310D622C7
+:10073000182FF7FFE8FFE7FF16006E009D0031005D
+:1007400026FF4AFED6FE2901BB03B90376FF09F94D
+:100750003FF600FD350E7B232C320200F3FFD5FF60
+:10076000C8FF0A009500E1003900B9FECEFD2BFF5D
+:100770009302E60468022DFB4FF570F9240BD82391
+:10078000CA350E001800FFFFB6FF8EFFFAFFE0002B
+:100790003601FBFFE1FD77FD7E00C304E10407FEA7
+:1007A0006FF54FF6C807D02349390B002B003E00E8
+:1007B000030080FF58FF2B0069014A0100FFC8FCBD
+:1007C00043FE6A035D0614018AF6D4F34D045923EF
+:1007D0007D3CF6FF02003B006E00190049FF1AFF46
+:1007E0007100FC01070199FD3DFCA900A1069F04D1
+:1007F00006F9BCF1F6FF5A224940FAFFD5FFBEFFC9
+:100800001000A400760033FFAAFE9200B002C600DA
+:1008100023FC7EFC2D04370817FEA2F0BFF90B2045
+:1008200082450D001A002F00450064008C00BE00B8
+:10083000F60034017A01C50114026102AD02F5022D
+:1008400037036E039903B703C703B703B8F38617DB
+:1008500053E0AD1F7AE8480C49FC531427004804C4
+:10086000ECA90001000A0700FFFF3002002005008C
+:1008700072042000200080001000000003008404A7
+:1008800000012000FFFF03008D0466086608FFFFDB
+:10089000240096048404FF7F0000FF7F43009B0434
+:1008A00000101900FFFF0200A40463AC01006614ED
+:1008B0004200C204E04000410300C604E840602159
+:1008C000AD040300C90408417021AC040200CC044B
+:1008D0008021B5040000000C5B030100000C4008FF
+:1008E00021018C066F14D4FFF700B8FCC50826EA76
+:1008F000914F914F26EAC508B8FCF700D4FF0700D6
+:10090000EDFF2B00ADFF920010FF7601CEFD360308
+:1009100061FB9F0659F6D20EC0E52D512D51C0E561
+:10092000D20E59F69F0661FB3603CEFD760110FF0D
+:100930009200ADFF2B00EDFF07007EFFA301BFF982
+:1009400039413DFF74029EF6D56165FF75011AFDC0
+:10095000FB09781700E03EE0902120612A613661B2
+:10096000A021A521AB2140804E805D80400801057B
+:10097000BA4D721C0E01B604F90011474CF5C3754F
+:100980000000030001000100DD14A106C714A50644
+:10099000FF7FFF7F000000200040006000A000807B
+:1009A00000A00080E80900804D460080E909008031
+:1009B00058200080EA090080696D0080EF090080FE
+:1009C00020740000960C0C1944251E317F3C4847CA
+:1009D0006151AF5A1C63936A02715B768F7A957D81
+:1009E000677FFF7F677F957D8F7A5B760271936A61
+:1009F0001C63AF5A615148477F3C1E3144250C1996
+:100A0000960C00006AF3F4E6BCDAE2CE81C3B8B813
+:100A10009FAE51A5E49C6D95FE8EA58971856B8274
+:100A20009980018099806B827185A589FE8E6D9574
+:100A3000E49C51A59FAEB8B881C3E2CEBCDAF4E61F
+:100A40006AF30000060DE11964266832C63D5A4873
+:100A50000652AF5A3F62A868DF6DE071AE745176FE
+:100A6000D6765276DA748D72896FF06BE967976388
+:100A7000225FAF5A61565C52BE4EA14B1F49484798
+:100A80002A46CD452A4648471F49A14BBE4E5C52D7
+:100A90006156AF5A225F9763E967F06B896F8D7279
+:100AA000DA745276D6765176AE74E071DF6DA8684E
+:100AB0003F62AF5A06525A48C63D68326426E11971
+:100AC000060D0000FF7FDD141D15540690082D490A
+:100AD000C208C003E4080000420900004109000008
+:100AE0007909000055090009D9080000E808839039
+:100AF00091083D0070090000A4081100A408370007
+:100B000090082D79C208C003E408000042090000E3
+:100B10004109BA075309430655090009D9080000DD
+:100B2000E80883907009000091083D00A4087E0049
+:100B300096080040970800409008BC99C208C10B75
+:100B4000E40800404209C3004109000053090106BE
+:100B500055090109D908000070090400E8088790C8
+:100B6000BE1588007207D6064E0062000000020023
+:100B70009A019A010100A5008A0700007F00FF0189
+:100B8000C8327F00D6069A01F00518017805F802F0
+:100B900020062706020028062F060100A907B10734
+:100BA0000200B207BB070100B107D6061E068C057E
+:100BB000E803F3073A078106C805E8039264005882
+:100BC000394E6646004024490040E33833338B2ECB
+:100BD000E61B6A18B3158813C111A3502A5CAE67CF
+:100BE0003373B87E4009FF934309070347097F0E1B
+:100BF00048091DA8490902004A09880790082D499B
+:100C0000E40800005E0901005C09901A5009080020
+:080C10007E0900932109080090
+:00000001FF
diff --git a/firmware/R2c_SoC2v01_Cobra_FM_SOC2_prog.fw.ihex b/firmware/R2c_SoC2v01_Cobra_FM_SOC2_prog.fw.ihex
new file mode 100644
index 00000000000..e6acb5ebe3a
--- /dev/null
+++ b/firmware/R2c_SoC2v01_Cobra_FM_SOC2_prog.fw.ihex
@@ -0,0 +1,3060 @@
+:100000000400F1AA26BF000000F0831F80D200F098
+:100010000070149000F0300A80D200F07C1F80D273
+:1000200000F0007022A000F0D01A80D200F0021F71
+:1000300080D200F0241B80D200F02A0280D200F08F
+:100040004D1580D200F0091680D200F0A60780D2AC
+:1000500000F0601380D200F0480D80D200F0C50699
+:1000600080D200F0230B80D200F0A01480D200F0E8
+:100070008B1380D200F02A0080D200F0E31480D2EB
+:1000800000F0CA0A80D200F00070108000F0731FE8
+:1000900080D200F000700FA000F0211B80D200F091
+:1000A0003F0280D200F0511580D200F0261680D297
+:1000B00000F0AA0780D200F0621380D200F04F0D4A
+:1000C00080D200F0C80680D200F0310B80D200F060
+:1000D000A01480D200F0931380D200F02D0080D2C3
+:1000E00000F0EC1480D200F0CC0A80D200F0591558
+:1000F00080D000F0F31A80D200F0970A80D200F08E
+:100100009E0980D000F06010086000F0B31F80D21C
+:1001100000F000708AA10082F20108601B020960F1
+:1001200006C01440001000F00602086006C000F08F
+:10013000101000F08434F801096000F0007034A160
+:1001400000F0143600F000F094333DA100F0DB071E
+:100150000A6000F0E801096000F027200280E80151
+:1001600009607CA1113F00700080112F88090A608E
+:10017000F09F42090C60834F222C09D40082442056
+:10018000754E9AC2010806604190932B00F02CC373
+:10019000912E069000F0263200F0AA90132E00F067
+:1001A0004190443015409290A330C0E0932D8409D3
+:1001B000066000F0223C05801B88A0308141DBD026
+:1001C000223C00F0CBC2007000F01CC5A6080660FF
+:1001D00000F0443006A08E91963F00F01630F301F7
+:1001E0000E60B683933004C000F0661000F000F09B
+:1001F0001531E1A000F000706681152F834162A1E6
+:100200004591991B80D21CC3142C09D4C0D703403C
+:10021000059020A0007000F000A8952C00F000CC04
+:10022000007000F04583007000F00BAE007000F02D
+:1002300000F0153100F000F0933008D0E8010960BB
+:1002400057A1913B0070DB8FE801096055A1913EF9
+:100250000070D98FE801096053A1113E0070D78F5B
+:1002600000F087100E60709EE8010960789EEC70C7
+:1002700000E2102F6C7000E200F0650100F000F069
+:10028000662000F00090153C00F000F0963C09D488
+:1002900000F00070CE8F0AA2007000F05382F13996
+:1002A000019800F0733908D05380713900F000F0E4
+:1002B000F33908D0E8010F6043A14090F12A00F023
+:1002C00000F0703BF88FE8010F6040A100F0702B48
+:1002D00000F000F0F13AF58FF09FE8010F6000F0B8
+:1002E00012400394419070283BA100887235C0E011
+:1002F00000F0703A08D00082FF7F02604190703AAF
+:1003000000F09282703540E000F0F23708D0E8014A
+:100310000F6034A100F0F13808D000F0F82F00F0A1
+:1003200000F0792000F000F0F32000F000F0002051
+:1003300000F000F0112000F018A0742100F058B077
+:10034000732400F008AF7824074209BFF42400F0BA
+:10035000C390F92400F00491002000E600F0112081
+:1003600000E638A0722600F078B0E07F06601586BF
+:10037000F32500F010821540029CF3A20070039850
+:1003800000F000580280F3A20070019C00F0FF7F93
+:10039000006059A1007000F0B1A0742700F003A81C
+:1003A000FF7F0560F3A8733600F0EDC2F32600F07E
+:1003B0006586F53500F061821540029CF3A200705D
+:1003C000039800F001580280F3A20070019C00F035
+:1003D000FF7F016059B1007000F031B1007000F092
+:1003E00003B8FF7F0560F3B8733700F0EBC2F7285E
+:1003F00000F000F0F33600F0FF9F742900F000F0E9
+:10040000F5290598FF9F007002900190007040E070
+:100410004090007002800884007000F0019000702D
+:1004200000F020A0007000F068B0007000F050AA4A
+:10043000742A00F051BAF32700F065DC772500F04C
+:10044000E382007000F0FF9F0070029C00F077359F
+:1004500000E2EBD7B30A80D318A2F33700F059A219
+:10046000F03100F000F0713208D00689007000F021
+:100470000F8913231440BE8D952200F018A100703F
+:1004800000F0AE83007000F09220122040EF00F0E8
+:10049000FF7F076091A1007000F006A8007000F0D7
+:1004A000AE81122200F0F3A8963200F0FBC2007079
+:1004B00000F08290133300F000F0132409D0068975
+:1004C000952300F018A1132500F0AE83922100F0CF
+:1004D00018B1122100EE0C89007000F091A100709B
+:1004E00000F006A8007000F0AE81952400F000F046
+:1004F000963300F02C83922100F0F6A8122100EE32
+:10050000BEC3007000F011B1007000F004B81634E2
+:1005100000F02C81007000F0F4B8943400F03CC37B
+:10052000007000F000F0143508D000F006020860FA
+:1005300000F0662400F000F0642500F000F0E524EF
+:1005400000F0A2A3007000F0AA80E52000F093A3C1
+:10055000E62200F01B83E23400F075A3672300F06D
+:10056000AAA2633500F0F383E42300F000F07528BD
+:10057000079000F0E235039CAE83007000F0BE8D62
+:10058000007000F000F0E6320E80AE81007000F0E6
+:10059000C691007040E100F0E6320B8000F0632667
+:1005A00000F03C9FE23500F0FB9E00700894C7917C
+:1005B00000700594E321632140E6C791FF7F02604C
+:1005C000E38C024000E6C390007000F000F062335C
+:1005D00000E6E38C007000F063367201046000F006
+:1005E000822300F000F0E43300F000F0862200F0F7
+:1005F000B29E072300F000F0E02500E2F383E1253E
+:1006000000E200F08225059000F00070029CAE83AD
+:10061000007000F0BE8D00700280AE81007000F0AE
+:10062000C691007040E130A2842400F071A28632AD
+:1006300000F000F0003700F000F0813700F0049186
+:10064000842F00F0BA9E032509D4349F823509D443
+:10065000C3909422119400F08520069000F0832628
+:1006600000F02C8F022000F0FB9E8321C0E200F0FE
+:100670000422054000F0833600F0C3900436078062
+:1006800000F0052100F000F0032600F0648FF24135
+:1006900000F0FB9E0322C0E200F08421154000F030
+:1006A000033600F0C390843600F00240023400E2CA
+:1006B00000F0053500E2FF83023340E283237C0033
+:1006C0000D60042472010260F683552100F0E68279
+:1006D000823509D44591842F09D0B683007009D0A2
+:1006E000349F007000F00041991F80D37C000D60A2
+:1006F0008FA0532100704BA0C390007000F000F059
+:100700000070069000F0100B80D228C6007000F038
+:1007100000F00070039041915D0280D24790080B79
+:1007200080D20040771A80D20602086085A0002798
+:10073000E8010F608127007008D02109086000F0EF
+:1007400000F0902B824200F00120F44DB683152D6D
+:1007500000F061C2923300F0F29F132F04427A9F9F
+:1007600016330394C29000700294029000700194BA
+:1007700061C40070C0E000F0013008D000F0F02B40
+:1007800000F0722D21090860732FC0000660BA9E28
+:10079000F42300F0C390752309D40090007009D4AD
+:1007A0000491022009D04591F3220B94B2C200704B
+:1007B00008948F02026009D000F0991B80D2C0D744
+:1007C000007000F010A2007000F018A0007000F09F
+:1007D000F5A9007000F0F4A875330044F433991FB4
+:1007E00080D07D9F007000F000F0753300F03C9FDA
+:1007F000007000F000F0F43308D000F0E801096068
+:10080000A2459B1B80D280A242090A6000F01038EA
+:1008100000F000F02420FBAEF8010E603B80E80100
+:1008200009605CA000F0113DD88FE80109605AA072
+:100830000082913200F000F0903300F000F01033AD
+:1008400008D016020E6056A000F0E12300F000F080
+:10085000E22408D016020E6053A00082613200F03C
+:1008600000F0E03300F000F0E03400F000F060341D
+:1008700000F000F0603508D01140832F06A0FB9EE9
+:10088000813500F0F3410320C0E2013516020A6011
+:100890004982033400F000F0A13200F000F021336F
+:1008A00008D000F0002200F000F0822100F000F0FB
+:1008B000003600F000F0823608D00602086042A040
+:1008C00000F00424064000F0F8010E600591FF7F5F
+:1008D00007603D9F84330990359F0070099000F0B8
+:1008E000007001901540073308D000F062223AA052
+:1008F0008290652100F000F0E52100E2FF830733DC
+:10090000C0E000F0653600F01540673308D00540C0
+:10091000063308D01540063308D040900602086020
+:10092000F241007040E000F0813F00F000F0023042
+:10093000E1AF00F000709E8F060208602DA000F06D
+:10094000813000F000F0023100F000F0833100F05F
+:1009500000F00432E28FF8010E6028A000F0E130D0
+:1009600000F000F0623000F000F0E33100F01140E0
+:10097000643100F000F0653200F000F06136008074
+:1009800000F0460B056062209B1B80D217405E4B37
+:100990000660A8A0E53400F0B9A1007000F065AAD7
+:1009A000007000F045A30040076092D7E12000F0FE
+:1009B000D783653400F079A2007000F000F0613553
+:1009C00008D00602086016A04190822F00F000F0C7
+:1009D0000120CD93BA9E007000F041900070CB973B
+:1009E00000F00140CA9700F0F241DD8F0602086076
+:1009F0000FA000F0803408D006020C600DA0C62FB6
+:100A0000100B80D20190C5230240B69F007000F009
+:100A10004D99007009D41240224040E600F0007069
+:100A200008D000F0E8010F6000F000708DAF00F01A
+:100A30000070D1AE1602096008AFF8010E6027AF52
+:100A400000F0421480D200F00070398000F0007095
+:100A500008D000F08D10086000F0B31F80D000F0C7
+:100A600028020860B683FF7F076000F0063700F0B9
+:100A700000F0873200F000F0863500F0BE9F872F2F
+:100A800000F000F0863400F000F0073300F000F0D2
+:100A9000072E00F000F0063400F000F0873308D095
+:100AA00028020E60F1AF4190E32F00F000F0E13C2E
+:100AB00009D000F0633308D000F0280208600090ED
+:100AC000007000F000F00035EE9300F0007008D0E8
+:100AD00000F028020E6000F0D148066049D0613D68
+:100AE00000F000F0623E00F070A0E23300F011AAC6
+:100AF000007000F000F0E13D08D089D39D10076040
+:100B000009D528020E607980CE04066092D3E137C1
+:100B100000F012D5E52F00F0BA80ED2700F000F0CC
+:100B2000E23700F000F0542100F000F0D220EC2772
+:100B3000A6815120E43FA681C221623F6583E13E48
+:100B400000F000F0643300E600F0623000F000F0E6
+:100B5000E63008D000F0642500F000F0E52100F058
+:100B60000491E42000F000F0EC210894648F6523E8
+:100B700000F0CE040C6000E27D9F007000F00040A9
+:100B80004020C0EB00F0401000F065334120C0EB86
+:100B900001404110C0E100F0EC3108D001400040BC
+:100BA00008D0028928020E600B89007000F09A8C30
+:100BB000E62DC4AF928DE42500F0938FE52C00F074
+:100BC0001C81623600F04591E43500F000F0E32628
+:100BD00009D000F06727EAAFD48E652400F000F05A
+:100BE000E03704908390E02E00F0FC82E52F00F0C7
+:100BF00000A3007000F000F0E03400F07D9F64205E
+:100C000000F000F0E0240198055865340480B887AE
+:100C1000FFFF056020A2007000F0288A007000F03D
+:100C2000C391E0340558C781E33600F07F9F007020
+:100C300040E1DF8B602F00F0BD8F673703583DCC5C
+:100C4000E2220194FD9E66370B807FC1B786046067
+:100C500076C1A3B50360E5A3007000F05D811B8041
+:100C60000360ECA3007000F0E482007000F028A1A3
+:100C7000007000F014AA007000F030A1FF7F036044
+:100C800015AA007000F0C590007040E155836532F0
+:100C900000F02DA2E02700F05581007000F028A29E
+:100CA000E53200F069A2007008D0008228020F60CF
+:100CB00000F064060E6000F0712100F000F0F323F4
+:100CC00000F0799EE22200F0FB9E713109DC00F019
+:100CD0007231029800F0F03500F000F0F33308D0E4
+:100CE00000F0F42500F0399E732E00F0049100709E
+:100CF00000F0FB9EF13309D000F0F33300F0F03543
+:100D0000BB0A80D0A1406902086096000260E4A19D
+:100D10008130444651A301306B0209602233A54063
+:100D200000F02434A64000F0A533FF7F076026368C
+:100D3000C8000060A732014500F04032024000F0D8
+:100D4000C132007000F02237E8030360A237670267
+:100D5000086093309001046013308116096084307C
+:100D600008000560023066080660D532007000F0A9
+:100D70008F90963000F0B733163000F000F0323725
+:100D800008D069020860D0A100F0731580D26B0210
+:100D9000086000F000F0731580D0690208603EA37F
+:100DA0008230771580D0690209603CA300F0902062
+:100DB0003BA300F0003008D000F0791580D0450248
+:100DC0000A6000F0690208602BA300F0202A00F0FE
+:100DD00000F0022000F000F0A12900F082906A15D6
+:100DE00080D06B02086000F0D41B006000F000F0BF
+:100DF000022000F08303016000F082906A1580D029
+:100E000000F01B1E80D245020A6034A200F0007080
+:100E100056A2000400606FA200F00070B7815B0969
+:100E2000086020A3801608602183801608601EA336
+:100E300000F000701E82439045020A60008000604E
+:100E400000F000F0C70480D3C190007008D04502C4
+:100E50000A6000F0008000605FA2DF02026009D03B
+:100E60004F02036000F000F0A23900F000F0233AD6
+:100E700008D01140361680D20090007000F04090EB
+:100E80000070C0E00090007008D000F08A160E607C
+:100E90000082007000F000F0603100F000F060327D
+:100EA00000F000F0E03100F0F400006000F04502D6
+:100EB0000A60B9A1213C10401BA274020060D48FCB
+:100EC00045020A600DA300F0202CC7A100F0A13C50
+:100ED0000CA278020060D08F45020A603DA2720227
+:100EE0000B603DA24040FF0402601340214055A228
+:100EF0007D020060CB8F00F00070F0A1A02F8A1659
+:100F00000E6000F0212000F000F0E03200F000F070
+:100F1000613300F0830200607A8345020A60FEA21A
+:100F2000A02F8A160E602120007000F000F06030C3
+:100F300000F000F0E13000F089020060788300F0FA
+:100F40001B1E80D200F00070FFA1D41B0560F2A22E
+:100F50000008006037A200F0A02EEDA100F06902A9
+:100F60000860A539731580D200F0B40A80D28205DA
+:100F70000060B68F00F000707DA100F00070FC8F63
+:100F80000004016000F053020860E4A208C200708F
+:100F900000F0088E007008D000F0361680D2009065
+:100FA00045020A60F400006009D40004006028A231
+:100FB00000F0681380D2F400006000F000F00070D0
+:100FC0008CA100F0213CE3A1A1020060A78F4502A3
+:100FD0000A60E0A200F0202C9AA100F0701B80D2E1
+:100FE0000090A70202600988007040E18090A13C57
+:100FF000A18F00F07B1380D245020A6009D000F077
+:101000006E1380D272020B600CA28040FF0402605B
+:101010001340114024A2F802006000F04702016072
+:10102000358200F0721380D2B1020060978F4502C2
+:101030000A60D8A100F0771380D20004006013A2E8
+:1010400082050060938F00F08A160E6000820070A7
+:1010500000F000F0603100F000F0603200F000F0CD
+:10106000E03100F000F00070F5A1045431000060A0
+:1010700045020A6088A10091A13CD8A100F020405F
+:101080008DA200F03040A5A2C1020060878F044607
+:10109000CFFF006045020A6082A10091213DE4A1DA
+:1010A000C5020060838F87900060E1A145020A605D
+:1010B000F0A100820070F8A14040130502600340D7
+:1010C000114007A2CB0200607D8F00F00070A2A14A
+:1010D000A02F8A160E6000F0212000F000F0E03210
+:1010E00000F000F0613300F0D10200602D83450272
+:1010F0000A60B0A2A02F8A160E602120007000F0B6
+:1011000000F0603000F000F0E13000F0D702006045
+:101110002B8300F01B1E80D200F045020A600008FD
+:101120000060EDA100400060ECA100800060E8A13B
+:1011300000F0A02E9EA100F0B40A80D282050060CB
+:10114000698F45020A60D0A12026DA0F80D2E20220
+:101150000060668F00F045020A6000F09D1B80D29F
+:1011600000F0A03C00F00041F70402600340114091
+:10117000EAA100F0E902006047020160FB8145023C
+:101180000A6098A200F0A02209A000F0222396A2F3
+:10119000878EA32700F0580300605A930040006038
+:1011A000D3A1C39000700290550300605797004090
+:1011B0000060D5A140000060D4A1FB020060548F04
+:1011C00000F021218DA20882007000F000890070DB
+:1011D00000F000F0203508D045020A6089A2FF7FA8
+:1011E0000060FAAF00F00070F78F8D1608607EA2E5
+:1011F000089000707FA200F05B09086000F04502D3
+:101200000A6000F0002000F0B683A12600F0F74746
+:10121000252500F00880A03400F0328C80000660A4
+:10122000BA8AA53500F086C3023000F000F0090349
+:10123000006047020160DC91120300603F8F4502AD
+:101240000A6000F000080060B7A1FF7F006000E6C0
+:1012500000F0A02200E200F0212174A208820070B8
+:1012600000F00089007000F000F0203500F012035B
+:101270000060368F45020A606FA2222500080060D8
+:1012800000F0A325ADA100F0A52609909F8EA42310
+:101290006BA2A78E00700390AF0200602F974000F2
+:1012A0000060ADA1FB0200602D8F40000060A6A190
+:1012B0002D8800700D9000F000700FA0AF0200604C
+:1012C000298F9F8E242462A2A78E0070039055035D
+:1012D0000060269740000060A4A1FB020060248FFC
+:1012E000400000609DA12D8800700490F40103600F
+:1012F00006A000F0A33700F0004000609BA155035A
+:1013000000601E8F00F0A53602A04000006098A18A
+:10131000FB0200601B8F00F045020A6000F05B09D1
+:10132000086000F0A02400F000F0A12500F000F01B
+:10133000003000F000F0213508D000F000704AA223
+:1013400000F04130378245020A604CA22026DA0FB5
+:1013500080D238030060108FCFFF006000F045029C
+:101360000A60F1A00082213C85A13C0300600C8F43
+:1013700045020A6045A200F0202CFFA0A13C0040DD
+:101380004FA100F0007043A141030060078F00F0FF
+:1013900045020A600041FF040260034011408DA134
+:1013A00000F046030060580201609E8100F01B1EA1
+:1013B00080D200F0007042A100F0007023A200F083
+:1013C000402010A200F0204001A200F000544AA1E9
+:1013D0004F03006035A200F0A03A00F05A0300600D
+:1013E000F98EDF0200602EA2A0396902086000F0C9
+:1013F000007062A100F0731580D200F0B60A80D2AE
+:1014000082050060F38E5A03006028A25803016031
+:101410002BA200F0A13AF08E45020A605BA1202ABF
+:10142000791580D045020A6000F0800300606BA14E
+:101430005D030060EB8E45020A6000F00041F70496
+:1014400002600340114071A100F062030060570286
+:101450000160828100F000701BA200F0C12000F04A
+:1014600000F042211DA2538220251CA21B89A03519
+:1014700000F000F02335BD8200F03040E3A100F021
+:10148000F040FBA1FF7F00602BA1839000603BA197
+:1014900000F0A04700F000F00070E1A000F0701B29
+:1014A00080D20090007000F00988007040E1409008
+:1014B00000704EA140D800700BA20040A03C28A1B3
+:1014C00000F0007028A176030060D28E45020A6009
+:1014D00040A10042F70402601340114058A17A0372
+:1014E00000600A8300F01B1E80D2004000601AA139
+:1014F000879000602AA14F02006000A2203A0240BB
+:1015000000F0014069020860D231731580D200F00A
+:10151000B50A80D282050060C58E00F09D1B80D286
+:1015200040D80070F9A100F0A03C2AA1839000608F
+:1015300020A1F040DA0F80D200F0F704026000F042
+:10154000800000601340114046A15F02016000F07E
+:101550008D030060578100F00070F0A191030460DA
+:1015600003A30091910680D593030060B78E5E02BD
+:101570000160ECA19303006051818790006013A18A
+:1015800000F000701FA1D41B0060B28E00F000704C
+:1015900019A100F00070D6A000F0A02F00F000F01C
+:1015A0002120E8A108840070E0A09C030060AC8EBC
+:1015B000839000600AA100F02040AEA100F0F0404E
+:1015C000C6A100F0007017A1A1030060A78E00F073
+:1015D0009D1B80D201900070DBA10082A13C1CA168
+:1015E00008900070A1A100F0405002A100F0F0406E
+:1015F00000F000F001407CA080400905026013402B
+:10160000114027A1AC03006000F06702016038813F
+:101610000082007099A100F0007006A100F0BC0AE1
+:1016200080D282050060988E67020860D1A100F028
+:10163000002000F000F08120CFA1408E007008D083
+:1016400072020B60CDA100F0B123CCA14190450204
+:101650000A60389E00700B9000F000700594F34013
+:10166000007068A0C090014069A00010006008A14F
+:1016700000F01040D1A0C70300608A8E00F0007017
+:1016800063A00082014064A00010006006A100F089
+:101690000040CCA0C7030060858E0140FF7F006042
+:1016A00000F0660D80D200F0690D80D200F000706D
+:1016B0001F80F400006000F045020A6060A04090C6
+:1016C000213C73A01040A13CC7A0CC0300607C8EDD
+:1016D0000040DA0F80D245020A60B5A072020B60AA
+:1016E00000F00082FF0402602340114000A1D203F9
+:1016F0000060768E45020A6000F000100060EEA0E7
+:101700001040007002907B02016000F0DA0300607C
+:101710000D8100F000706EA17D02016000F0DC031D
+:1017200000600A8131010260A3A100F0B0240380AF
+:101730000082007069A1A4040260A0A100F0B0259D
+:10174000008000F0007071A000F0660D80D200F003
+:1017500000707FA000F0690D80D200F00070A6A09C
+:1017600000F000703BA000F01B1E80D200F0BC0A0D
+:1017700080D282050060608E00F0007095A100F0BC
+:10178000302400F000F0B1247CA000F0303600F0EE
+:1017900000F0B13600F000F0302500F000F0B12587
+:1017A00078A000F0303700F000F0B13708D0029098
+:1017B000007006A0BA9EF206046031253124C0E212
+:1017C0001E41046000E632273226C0E2B327B3266A
+:1017D000C0E200F00070598000F08C1B80D20190B4
+:1017E000941B80D209807805006000F072020B60C3
+:1017F0004082007008D000F00070FAAF00F0312491
+:1018000000F000F0322600F000F0B3266080800285
+:10181000086078A10090007008D0720208607EA174
+:1018200000F0802400F000F0812500F000F000348A
+:1018300000F000F0013508D000F0007000F0A03B8F
+:101840000B04006000F0213B3D8E45020A6076A14A
+:1018500000F0A12B75A1799E202B00F000F0A13B98
+:1018600009D400F00070388E00F045020A60D41BE5
+:10187000006070A100F0A03900F000F0203A08D01C
+:10188000E54F41090860399E5509096042402240F0
+:10189000C0E20320F9FF016016400640C0E2CBC25F
+:1018A000142000F0D3C4007000F02CC3007000F0CE
+:1018B00034C5033000F000F0143008D000F00070A0
+:1018C00003A000F00070008050405509086000F04F
+:1018D0000070A88050405509086000F00070A98091
+:1018E00002D15309086008FF03601DA118C20070EF
+:1018F00000F010C4007000F008C400706080039015
+:10190000007000F0008200700180039000700BA056
+:101910000289991B80D29A80007000F012894008D9
+:10192000086016CC0209016092C1007000F080D7F7
+:10193000023000F000F0803000F000F0813112C081
+:1019400000F0007000F0969D01214CA189C100704B
+:1019500008D000F0441E80D278A0007000F031A0C2
+:10196000411E80D27AA0007000F032A0007000F01A
+:1019700070AA0070458101524008086003CC02093A
+:101980000260C0C0813000F000F0003000F000F0D4
+:10199000823112C000F0007000F0FB9C01213EA1DA
+:1019A000C9C0007008D002900070F1AF1280991B7E
+:1019B00080D2D2D04008086080D7007000F000F0DC
+:1019C0000209016000F0823000F000F0003000F009
+:1019D00000F0813112C000F0007000F000F0012131
+:1019E0003381C2D8991B80D240080860F78F400825
+:1019F00008600CA000F04008086005CC007000F002
+:101A000040C9007000F026CC007000F0A2C9007040
+:101A100000F0818E007000F000F000700294D2DFC0
+:101A2000007000F0BE9F007000F000F00070EDAF9D
+:101A30004090007000F07183007008D010A000701A
+:101A400000F0C8AE007000F00880007008D0B849FF
+:101A50000460FCAF20A0534000F000A8007000F02C
+:101A600000CC007000F0C182007000F008AE007081
+:101A700008D063403C5602604082007000F010A025
+:101A8000007000F000A8007000F000CC007000F0C2
+:101A9000C182007000F008AE007008D062408C1B5C
+:101AA00080D20190941B80D208808360016080D72F
+:101AB000208F036014403402056045020A6008A0CC
+:101AC0002630B35901605240059803600440F40089
+:101AD000056000F0374004A0B881A63F00F0A03DAB
+:101AE00072020B6000F0203E08D05B0908600C8099
+:101AF00000A0007000F08EAE007000F08EA30070A9
+:101B000000F018A0007000F009AF007000F08E81A6
+:101B1000007000F0AE81007008D0A040500908604D
+:101B200000F0007045A000407009086000F00070EF
+:101B300043805A09086000F000F0007000F000F0E7
+:101B4000003008D0A0405009086000F0007041A0AB
+:101B500000407009086000F000703F8000F07009DC
+:101B60000860389E0100006000F00070399000F0BD
+:101B700000703B8000F070090860389E0200006031
+:101B800000F00070359000F0007037809608086013
+:101B9000F1AF97080860F0AF98080860EFAF9908B8
+:101BA0000860EE8F96080860E7A000F00020E6804D
+:101BB0009A08086001809B080860008041D00258A4
+:101BC000A4A0C9D7007000F010C2007000F008C4D3
+:101BD0000070E78F9A08086001809B080860008009
+:101BE00000F000709EA040D0007000F0C0DF0070D8
+:101BF00008D0E8080860E08F9C080860DFAF9D0807
+:101C00000860DE8F00F09208086000F0004021A01C
+:101C100000F0F0401D8000F09208086000F0F040F5
+:101C20001EA000F000401A80BC070060D1A041094E
+:101C30000860D6AF0000006061AF2740C60780D0C3
+:101C40000082007000F041090860D28F0041D90F76
+:101C500080D00041DA0F80D000F0B12FC9A04290AF
+:101C6000007000F07A9E0070039000F00070039006
+:101C700000F0007001A0008800700180C3080860B7
+:101C8000C98FC7080860C88F93080860C78F950878
+:101C90000860C68F00F02127BFA041C2007008D0A5
+:101CA00000F02127BDA041C4007000F000F02137F2
+:101CB00008D000F0007000F000CA2127B9A041C28E
+:101CC0000070FC8F12400120B7A012C0007000F01D
+:101CD00050C40070BC8F12400120B4A012C000702C
+:101CE00000F012CA007000F050C20070B88F72028B
+:101CF0000B60B0A000F0B03D00F000F0B13F00F08C
+:101D000000F0B23100F000F0333008D0928233207E
+:101D1000ABA0C090FF7F01608116096008B4F09EFF
+:101D2000323E00F000F0B23E029000F0323F00F090
+:101D300000F0B13008D092313C000060113444050D
+:101D4000016010310020006000F09132E68F00F059
+:101D50009B1B80D2C0D7007000F04182007008D079
+:101D600072020B6000F000F00070008000F0B22101
+:101D70009BA000F0007000F000F0007020D0720214
+:101D80000B6098A030314802016000F0202E8FAF28
+:101D9000ED040060F98F4902016090A000F0232E4D
+:101DA00000F000F0A42092A0E08200708AAFF2045C
+:101DB0000060F48F470201608BA000F0232E00F03A
+:101DC00000F0A4208DA0E080322185AF80900070CB
+:101DD000EF8F3032FB04046000F0B132DDAF00F071
+:101DE000A02CBEAF019160400D8F72020B602AA043
+:101DF0000190B82209D000F0302200F000F001304C
+:101E0000498D00F0303200F000F0B132D5AF00F073
+:101E1000A02CB6AF00F0202C84AF0505016000F0C7
+:101E200000F03040038F72020B6020A000F0B92256
+:101E300009D00490302200F000F014303F8D00F003
+:101E4000303200F000F0B132CBAF00F0A02CB5AFD3
+:101E500000F0A02CABAF00F000709CAF0F0501604C
+:101E60000A8072020B6016A00490B92209D000F01B
+:101E700033229BAFC0901430358D00F0303200F02B
+:101E800000F0B132C1AF00F0A02CABAF00F0A02C3D
+:101E9000A1AF00F0007092AF1A05016000F00600DB
+:101EA0000060EE8E72020B600BA00490B92209D084
+:101EB00000F0202DA4AF00F0202D9AAF00F01430D8
+:101EC000B7AF20050160F98F72020B6005A0049086
+:101ED000B92209D000F033228AAF00F010205EA0B2
+:101EE0002484007000F0C0901430228D45020A60F6
+:101EF00012A0759F78020960811608600D9008A2F3
+:101F0000B32E174010A0342E0558D9A1362F00F05B
+:101F100062A1B72D00F08E91FF7F0560BE83363F32
+:101F200000F003A800700390F4A8333E00F02CC327
+:101F3000007000F09282B43E08D039CC124000F01C
+:101F400048AE007000F08290007008D03033720FFD
+:101F500080D2002000608AAF00F0802108D02240AB
+:101F6000B32F48A0C490B12000F0FC9E352004900F
+:101F700000F00070049000F0007002A00390007068
+:101F800002A01884007008D0E30808600180EB0804
+:101F90000860008000F0007000F000F000203E803B
+:101FA00000F045020A60002000607E8F0190420927
+:101FB0000860FFFE0260FBAF10C2125000F04190BB
+:101FC000007000F010C40070C0E000F000703D8FA1
+:101FD0005C09086035A000F0012034A089D70070AA
+:101FE00000F089D0007000F008C4007000F000F02C
+:101FF000003008D05C0908602FA000F000202EA05F
+:1020000080D3007000F080D4007008D000F0007021
+:10201000FBAF08900070F48F00F00070F9AF389EAD
+:102020000070F28F00F0414600F0DB82124000F0B9
+:102030000982A14600F083903240C0E10982014745
+:1020400000F083907240C0E10982614700F0839004
+:10205000F240C0E10982007000F083900070C0E19E
+:10206000C090007000805D090860228F5D090860E3
+:10207000DB8F5D090860DAAF40D0007000F0089097
+:1020800000701E8F5D090860D7AFC0D700701C8F2D
+:102090003642007011A0C0211157076041205555EC
+:1020A00005603882007000F07182007000F048A175
+:1020B000007000F092AA007000F08280007000F0C2
+:1020C00000F0A23200F000F0C23008D000F0A027EB
+:1020D0000BA0389E007000F000F0A03700EE00F07A
+:1020E000007008D000F0007000F000F000200680C2
+:1020F00000F0007000F000F0003008D045020A60E7
+:1021000000F072020B6000F055020C6000F05B0200
+:102110000D60008000F0007008D045020A60FEAF3C
+:102120008A160E60FDAF00F06221FCAF8A90632238
+:10213000FBAFCB9010403AAF63326231C0E200F0A7
+:10214000222200F0A3218305076000F0242F69A05C
+:102150004090007068A000900070059C0EC4007054
+:1021600004980E8000701B9000F00070259800F01D
+:102170000070599000F000702D800E80007000F00B
+:1021800000F00070029000F00070059800F0007000
+:102190000C8000F0007059A04190007000F000F039
+:1021A0000070039800F000700A8000F0007055A0E5
+:1021B0000188007000F08A80A13600F09A8CA1217D
+:1021C00000F08082242200F0188C2131DAAEA43194
+:1021D00049020160C091223E418F00F000704DA085
+:1021E0000190007000F08A80A13600F0A28AA1213F
+:1021F00000F08080232100F0208A2132D2AEA3316A
+:1022000047020160C091223E398FA2260070D6AFEE
+:102210008290007000F000F0222E049800F023203D
+:10222000D3AF9A82007000F000F00070F29B00F0D3
+:1022300000701E8000F0A32FCFAFD282007000F09C
+:1022400000F00070E69B00F0007011804040222EEC
+:102250000DAF223020400AAFB89EA32F049400F0A7
+:102260000070E19F00F0104007AF00F00070019493
+:1022700000F000700A8000F0007000F09A84007096
+:1022800000F000F0A23E34802040232E03AFA33F95
+:10229000404000AFF89E2220FA9700F00070DF9FC8
+:1022A00000F01040FDAE00F00070F79700F00070F5
+:1022B000098000F0007029A000F04040F9AEB89EFF
+:1022C0000070049400F08040F9AE00F00041F6AEDA
+:1022D00000F0A52F179000F000700B8000F0222076
+:1022E000CC9F00F0A33FED8F00F0007020A000F025
+:1022F0002040F0AEA0820070049400F00041F0AEE7
+:1023000000F08040EDAE00F0A52F0E9000F00070C0
+:1023100002800291A32FCB9B00F02230E48F00F0CB
+:10232000262000F04591007000F0A6830070039411
+:1023300000F000700294A52D0042E6AE00F0A53E2C
+:102340001580A5208040E7AE24300041E6AE00F0C5
+:10235000A33F00F0A536007000F0C091253E058F28
+:10236000A2261040DDAE8290007003941288A52D45
+:1023700000F0A236007000F0C091253E008F00F002
+:102380000070B99B00F00070B08F00F0007005A0E5
+:102390008182A23E00F0CB8C007000F08180A33FD0
+:1023A00000F0648A007000F000F0243003800340E5
+:1023B000A02000F0F447A12600F000F0222E8E8F1E
+:1023C00000F0A02A538CD582014000F02E890070C5
+:1023D00000F03683007000F0D5820070029C799E78
+:1023E000007001985190007000F0C290007000F0F1
+:1023F0007E9E232108D014000260018096000260B6
+:10240000008000F0A03A1EA083050060E88E0A005C
+:102410000260018005000260008000F0A03A1FA069
+:1024200000F0A02F00F000F021207CAF4282A52E0A
+:1024300000F0A39E0070039000F00070039800F07D
+:10244000253E00F083050060DE8E00F0A03EE88FA0
+:102450001080223100F000F002406DAEA231460241
+:10246000016010060060D48E45020A6071AF00F072
+:10247000242100F000F0A62F00F000F0A22000F0D0
+:10248000A581A3216DAFD08E007000F000F0A231C5
+:1024900000E63C9F253200E600F024310398A0813D
+:1024A000007061AE00F04602016010060060C88E48
+:1024B00000F0252265AF00F0A53ED68F00F0304039
+:1024C00000F000F0223F00F000F0A03000F000F03B
+:1024D000A03600F03F000060A48E00F01040FBAF7B
+:1024E000104000709F8E8F8E442200F000F0C522B5
+:1024F0001490E78E007000F0CD7C06600A94800096
+:10250000006098AECD7C0660089400F0007026AFA5
+:102510002F9E007039AF0F9CA4252C98CD7C0660AF
+:10252000389800F000706AAE3782007000F0A54E57
+:102530000660439800F000705080EF8E007066AE29
+:10254000378200704D94A54E06603F9800F00070F1
+:102550001BAF2F9E00702EAF0F9C0070479400F0B1
+:102560000070469400F000704880E78E007000F024
+:10257000330306600A948000006084AE3303066073
+:1025800008946D83007012AF478F007025AF478F9E
+:10259000A4250D9433030660209400F0007056AE1D
+:1025A000878F007000F0A54E0660259400F0007043
+:1025B0003C80EF8E007052AE878F00703994A54E2C
+:1025C0000660219400F0007007AF079000701AAF0A
+:1025D00007900070339400F00070329400F00070A7
+:1025E00034800002006072AEE78E0070049000F04C
+:1025F000007006B38000006071AE0003006073AE2F
+:1026000000F00070038000F0007002AF0001006075
+:102610006DAE00F00070008000F000543DAE5D0330
+:102620000060EE8B0001006067AEE78E00700490E2
+:1026300000F00070F9B28000006066AE0003006038
+:1026400068AE00F00070F88F00F00070F5AE000288
+:10265000006062AE00F00070F58F00F0007006AF11
+:1026600000F02040E7AE0001006061AE00F00070B5
+:10267000F18F00F00070FFAE00F01040E3AE0002FA
+:1026800000605DAE00F00070ED8F00F05501076056
+:10269000000100605AAEDB8B007000F0F0A000700B
+:1026A00000F043AA00702AAEC3A23303066018826A
+:1026B000007000F0808D007023AE8000006050AE8E
+:1026C0005D030060D38B00F05501076000020060DD
+:1026D00050AEDB8B007000F0F0A0007000F043AA59
+:1026E000007020AEC3A2FF7F06601880007000F06B
+:1026F0008091007040E100F0007018AE8000006032
+:1027000045AE5D030060C88B8000006046AE00F0FF
+:102710000070D68F0040006044AE00F0A02AC48B49
+:102720009A08086000F0A03A8706006000F0414176
+:1027300010804141890600609B0808600E80A1401E
+:102740008B0600609A0808600C80A1408D0600602E
+:102750009B0808600A8031408F0600609A08086074
+:1027600008809B080860EEAE3140A02A068000F089
+:10277000A03AF78F00F0512200F000F0D221EEAE27
+:102780008982D32200F00989007000F0C88E0070A1
+:1027900008D000F00070E6AED0359C0603605130E2
+:1027A0006402016000F0D83009AEC0905031488E0C
+:1027B00045020A601FA01080007022A000F0610294
+:1027C0000160A0060060448E45020A601BA01082D2
+:1027D00000701EA000F062020160A4060060408E3E
+:1027E00000F0007017A0F44FD12300F0168253239D
+:1027F000DBAE5D82007000F000F000700298C190C6
+:10280000144000F01680007000F000F0513400F029
+:1028100080915435F1AD5B020D60D4AE00F0D8204C
+:10282000F5ADD124FF3F0560045C5224D1AE89820E
+:10283000532000F000F05125059CD23445020A6077
+:1028400000F000700DA000F000700AA063020160AB
+:1028500000F0AD0600602C8E00F0007000F00988DA
+:10286000007008A000F0007005A000F0D0258C8B4F
+:102870005B020D60C5AE502100C004605220FF3FD6
+:10288000056000F0D82008D0208C007000F0288A65
+:102890000070DC8D4190007000F01B88007040E1FA
+:1028A0001880007008D000F0AD10086000F0B31F71
+:1028B00080D200F0007081A0008292020B60820240
+:1028C000096008A010329B020B60DB07086006A0BD
+:1028D0009032A4020B60072088090A608802086011
+:1028E00097A0C8090A6002A08D02086095A000F0B8
+:1028F0001120028000F0B03300F000F0303408D036
+:10290000845182020960FB9F410908600240113036
+:1029100009D47B9E002000F0739E324000E26B9E43
+:10292000224000E224CA124000E220C279090A6073
+:10293000D3D2007000F018C4223000F000F0003054
+:1029400008D092020A60C5A0A13000706B809B0283
+:102950000A60C3A0A1300070698092020A60C1A021
+:102960002131007067809B020A60BFA02131007096
+:102970006580A4020A60BDA02131007063809202CC
+:102980000A600280A4020A6001809B020A60008043
+:102990004190124000F001401140C0E200F0007090
+:1029A0000780BD9F92020A609282007040E000F0B2
+:1029B000007004809282A4020A6000F0007002801D
+:1029C00092829B020A6000F00070008000F0820298
+:1029D0000860FE9F007000F082908321059406211C
+:1029E0008620C0E2D3C4007000F04190007000F077
+:1029F00036888331C0E000F0263208D09282FF7F13
+:102A000006604190223200F0B6838231C0E000F0CF
+:102A1000A63108D000F0820208609202096008A086
+:102A20009B02096007A0A402096006A000F08521AE
+:102A300010A09202096014A09B02096013A0A402D6
+:102A4000096012A00082007009D08031B30A80D0E2
+:102A500000F0032200F000F0922100F000F0942238
+:102A600000F09EA2172300F034A3007000F0F7A33B
+:102A7000862200F020A0007000F014AA007000F080
+:102A800078B0943300F014BA007000F000F0143401
+:102A900008D0F380FF7F04600082033209DC869156
+:102AA000803200F000910070C0E10032B20A80D0A4
+:102AB0000082FF7F046000F0172287A0C791922157
+:102AC00086A0BA8000700590C7910070039C0191A8
+:102AD0000070C0E14982103240E14591913108D047
+:102AE0006D83923108D04591007008D08202096050
+:102AF0007EA000F0962000F000F09B1B80D286A301
+:102B0000007000F000F0963208D08202096079A0CF
+:102B100000F01621FB8F8202096077A000F096205A
+:102B200000F000F0007000F036880070F78F82022D
+:102B3000096073A000F01621FC8F840306600180F9
+:102B40005A00066000F0820208606FA000F00631B3
+:102B500008D0AD020C606DA04822A6080A60C92208
+:102B6000A7080B600020007000F01120007000F03A
+:102B7000C223007000F0432488090D6080C84423FC
+:102B800000F0C9C8482000F00083C92000F0098384
+:102B9000203000F000F0313002A04821007000F039
+:102BA000C921C8090D6000F0002000F000F01120DC
+:102BB00000F000F0503D00F000F0D13D08D092024E
+:102BC0000A6002A0A4020A6001A09B020A600080C1
+:102BD00000F09B1B80D22121018004602220007024
+:102BE00000F0618CA32000F082A2007000F08E90B3
+:102BF000007000F08F90007000F051A2007000F0A3
+:102C00008E830070C0E19EA3007000F04190A63258
+:102C100000F0CF81007040E1DFA3007000F000F011
+:102C2000273308D000F08802086000F088090A60A5
+:102C300001300070098000F08802086000F0880907
+:102C40000A6081300070068000F08D02086000F09C
+:102C5000C8090A6001300070038000F08D0208602E
+:102C600000F0C8090A60813000700080F49F222CB7
+:102C7000844F00F0032009D0A2C2842000F0C3904A
+:102C8000410801608A900070C0E00491213200F098
+:102C90009290A330C0E000F0223C08D017400070B2
+:102CA000008088090E6000F0C8090F6000F000F095
+:102CB000E73F00F000F0F73F08D007400070FB8FBF
+:102CC00088090F6000F08A02096000A000F07723F5
+:102CD00000F000F0F62300F000F0752400F017314A
+:102CE000C8090F6000F0963000F01C72153008D053
+:102CF0008A02096000F088090F6001A0C8090F600E
+:102D000000F000F0172100F01440962000F01C7233
+:102D1000152000F077D7773300F06ED3F6330351E8
+:102D2000F5C5753406525F83034100F0758300706A
+:102D3000019853408340C0EB00F0007000F0DBD1FD
+:102D4000007000F0E3C4007000F000F0733208D0AF
+:102D500088090F6018A00740762100F01444F5217F
+:102D6000F3AFC8090F6015A00740762100F01444A6
+:102D7000F521F08F1740602C12A038C2007008D0E7
+:102D800000F088090E6000F0007002A0069000704C
+:102D900001A0318C007008D000F0E521F9AF459119
+:102DA0000070C0E020400070C0E0C8090E6008D08C
+:102DB00088090E6008A000F0E62CF4AF8091007046
+:102DC000019000F0007009D0C8090E6004A000F066
+:102DD000E62CF0AF80910070019000F0007008D0F8
+:102DE000C091007008D000F0007008D0124001407F
+:102DF00003A000F0113100F000F0123000F000F0FC
+:102E0000923008D000826B0008606800096003C03F
+:102E100000F0001000F000F0007008D068000960B9
+:102E200028A01032941B80D24180923100F000F033
+:102E3000102100F000F0913200F0009013090960B9
+:102E400000F0007009D000F0123008D0224040405D
+:102E500020A040C26800096080D7711B80D250C298
+:102E6000124000F0C0D7C00F80D250C2007000F0F6
+:102E700000F0103108D06C00096019A009090A603F
+:102E800082C800F0100017A000F0201000F000F041
+:102E9000007008D06800096014A000F011300280B2
+:102EA0006800096012A000F091300080E24B4109F7
+:102EB0000B60F34B42090C603620007000F0452097
+:102EC000007000F096C3680009605DC3007000F0F8
+:102ED000C49113201240FC9F00700790D3C2007071
+:102EE00002909BD1007000F05DC5007004809420BA
+:102EF000361680D20491134000F0049000700190C7
+:102F00009EC5007040E000F0363000F000F0453023
+:102F100008D000F0007008D0CE1009602D80CF10CE
+:102F200009602C80F81009602B80091109602A8043
+:102F3000421109602980CE1009602880E8100960DC
+:102F400027805F11096026800809086025A0F540E8
+:102F5000062500F000F0022C00F0AEC3D807036095
+:102F6000BE9F007009D014D60070F74150D7007092
+:102F7000159038C2D1070A60C38000701390019E7B
+:102F8000007000F000F00070119C00F0007030D272
+:102F900000F0293000F000F0112000F02020007037
+:102FA00017A02080007000F06182203015A000F092
+:102FB00029200A9800F0812C00F01020FF1F0760E4
+:102FC000022DDB070A6038C2832D00F000F02720B5
+:102FD0000FA000F0042E00D200F008090860009055
+:102FE000007000F000F0003000E600F0007008D043
+:102FF00000F00980006000F08230FA8F0809086054
+:1030000007A08030007000F002310B7F006081313A
+:103010000070F68F00F01240FB8F00F0022C00F0E1
+:103020000980006000F000F0823008D000F00070ED
+:1030300008D0DB070960FEAF11200901006000F035
+:10304000007000F000F0813008D000F0FF1980D24D
+:103050000802006008D000F08E1F80D24982040B65
+:1030600080D200F040090A604982B91F80D200F086
+:10307000213008D000F00070FB8F00F00070EF8F5F
+:10308000A808096000F07F090A6000F000F0040160
+:10309000016000F002800460922001C005601320EE
+:1030A0000800066081300F06006027200E000160D6
+:1030B00000F0023100F000F0043200F03FD285321F
+:1030C00000F0FBC4063300F000F0833100F000F0A4
+:1030D000813308D000F0892CE3AF00F0112000F01C
+:1030E00000F00907006000F0813008D000F0892C62
+:1030F00000F000F00808006000F0123008D000F086
+:103100000070D98F00F00070D88F8090981B80D20B
+:10311000080B006008D04190007000F000F00070D3
+:10312000039000F0330780D200F0DC1580D2080C49
+:10313000006008D000F0340780D200F0DD1580D2A6
+:10314000080C006008D000F0401680D2080D006026
+:1031500008D000F0B60780D2080E006008D000F05A
+:10316000BD0780D20A0F006008D000F0421680D25E
+:103170000810006008D000F01A0B80D200F01E0B7F
+:1031800080D20811006008D000F0471680D20812E3
+:10319000006008D000F0C91F80D20813006008D07A
+:1031A0000814006008D0C091007000F000F00070BA
+:1031B000029400F00B1A80D20815006008D020405D
+:1031C000991F80D20815006008D05B090960BAAF6A
+:1031D00000F01120B9AF00F0813000F00916006056
+:1031E00008D04190007000F000F0430280D308172F
+:1031F000006008D041900C7000F000F0450280D3D0
+:103200000918006008D000F0780080D23002006019
+:1032100008D000F0750080D23003006008D000F0C4
+:10322000720080D23004006008D000F05E0080D2CE
+:103230003005006008D000F0640080D230060060E5
+:1032400008D000F0620180D23007006008D000F0A2
+:103250005F0180D281303208006000F0023108D076
+:1032600000F0590180D23009006008D000F08100E0
+:1032700080D2300A006008D000F05B0180D2300BB1
+:10328000006008D000F0600080D2300D006008D0EF
+:1032900000F0390080D2300E006008D000F06200EB
+:1032A00080D2300F006008D000F00070928F00F0E4
+:1032B000DF0680D21001006008D000F0E30680D263
+:1032C0001002006008D000F0EF0680D2100300600A
+:1032D00008D000F0D40680D21004006008D000F0BE
+:1032E000E90680D21005006008D000F05A0780D2AD
+:1032F0001006006008D000F05D0780D21007006063
+:1033000008D000F0EA0680D21008006008D000F073
+:10331000E10680D21009006008D000F0E50680D2F6
+:10332000100A006008D000F0600780D2100B006027
+:1033300008D000F0630780D2100C006008D000F0C5
+:10334000F40680D2100D006008D000F0EB0680D2A9
+:10335000100E006008D000F0F20680D2100F00605E
+:1033600008D000F0E70680D21010006008D001906D
+:10337000007000F00809086073AF00F0813000F0C1
+:1033800000F0023100F0C091833108D000F0391B09
+:1033900080D200F0007002900140C51680D2180162
+:1033A000006008D018010060638F00F0541B80D2C9
+:1033B0001802006008D000F0770D80D21A03076071
+:1033C000F38F00F0590D80D219040760F08F00F0E0
+:1033D0008C0F80D21805006008D000F06F0D80D2ED
+:1033E0001806006008D000F0910F80D21807006026
+:1033F00008D000F0930F80D21808006008D000F0C9
+:10340000960F80D21809006008D000F0A90F80D272
+:10341000180A006008D000F0AF0F80D2180B0060CF
+:1034200008D000F00070538F00F00070528F00F051
+:10343000B20F80D2180E006008D000F0B40F80D216
+:10344000180F006008D000F0C20F80D21810006082
+:1034500008D000F0C40F80D21811006008D000F02E
+:10346000C60F80D21812006008D000F0C80F80D2BA
+:103470001813006008D000F04A0B80D219140760BE
+:10348000D38F729E007000F000F00070039C00F07B
+:103490004C0B80D200F0691280D21815006008D061
+:1034A00000F04C0B80D200F0651280D2181500603D
+:1034B00008D000F000703B8F00F0500B80D218173E
+:1034C000006008D000F0350B80D2181801603AAFC8
+:1034D0000880007008D000F0440B80D219190760F2
+:1034E000C38F00F0460B80D2181A006008D000F09D
+:1034F0004E0B80D2181B006008D000F0531A80D207
+:10350000181C006008D000F08C1B80D2191D0760C9
+:10351000BA8F00F08D1B80D2181E0060299300F036
+:10352000C51680D200F04B1A80D2181E006008D059
+:103530004090AB1B80D20190C51680D200F04B1A90
+:1035400080D21826006008D000F0551780D200F015
+:103550004D1A80D2181F006008D000F0131880D2D6
+:1035600000F04E1A80D21820006008D000F0B01A87
+:1035700080D21F21006008D000F08D1B80D218225D
+:103580000060189300F0E81880D200F0511A80D241
+:103590001822006008D000F08D1B80D21823006034
+:1035A000139300F0381880D200F04F1A80D21823FD
+:1035B000006008D000F0361880D2192407609D8F73
+:1035C00000F08D1B80D2182500600C93852E6418A6
+:1035D00080D200F0501A80D21825006008D000F088
+:1035E00008090F6000F08C1B80D2F030590D80D29A
+:1035F0007031770D80D200F04A0B80D2F2311C2757
+:10360000006000F0713208D04190007000F000F0CE
+:103610000070029000F0840F80D21828006008D05B
+:1036200000F0880F80D21828006008D000F0C6167D
+:1036300080D21829006008D000F0520B80D2182ADE
+:10364000006008D000F0371880D2182B006008D036
+:1036500000F0590B80D2182C006008D000F05B0BF2
+:1036600080D21A2D0760828F00F0810B80D2182E35
+:10367000006008D000F09A0B80D21E2F006008D0A6
+:1036800000F06D1880D21B3007607C8F00F0ED18C1
+:1036900080D21B3107607A8F08090F60EDAEF12CE4
+:1036A0009E0D80D2F12D970D80D21832006008D087
+:1036B000FE9F311680D200F0007002901040991FDA
+:1036C00080D21833006008D000F04B1A80D2183333
+:1036D000006008D084908D1B80D2469012400A90E2
+:1036E00001918D1B80D230832240089000F0007041
+:1036F0000798C190E54FDEAEE8C2007000F000F020
+:10370000324004948191007000F00291EC1980D253
+:1037100000F0231A80D21834006008D018340060FA
+:10372000CF8E00F0C41A80D21F35006008D000F0A0
+:10373000480B80D21836006008D000F0C40780D251
+:103740001837006008D000F0611780D200F04D1AE1
+:1037500080D21838006008D000F03A1B80D200F008
+:10376000007002900140E51980D22001006008D06D
+:1037700020010060C18E00F0551B80D22002006045
+:1037800008D000F08D1B80D220030060C19200F0B1
+:10379000E51980D200F0751A80D22003006008D0AD
+:1037A00000F0A80180D281302204006000F00231D4
+:1037B00008D000F03C1480D22006006008D000F051
+:1037C000830180D22007006008D000F0880180D2F9
+:1037D0002008006008D000F0C40180D220090060F9
+:1037E00008D000F0E61980D2200A006008D000F06E
+:1037F000A91380D2200B006008D000F008090F60E8
+:1038000000F08C1B80D200F0F03000F0210C006042
+:1038100008D000F0140B80D200F01E0B80D2200DD7
+:10382000006008D000F0CC0180D2200E006008D0EB
+:103830004190007000F00040C80180D700F0040BF8
+:1038400080D200F01E0B80D2200F006008D000F064
+:10385000F71480D200F0813000F02110006008D011
+:1038600000F0FF1480D22011006008D0852E0815CA
+:1038700080D22012006008D000F0051580D22013FD
+:10388000006008D000F0031580D22014006008D03A
+:1038900000F0AE1380D22015006008D000F0D301F4
+:1038A00080D22016006008D000F0C20780D2201716
+:1038B000006008D0852E8D0180D22018006008D0CD
+:1038C00000F000708E8E00F0B01380D2201A0060DD
+:1038D00008D043908C1B80D219808D1B80D2201C75
+:1038E000006007901989007000F0629E00700390DC
+:1038F000529E007004987A9A0070039000F0007055
+:10390000029CC190F01980D2201C006008D0C190A8
+:103910000070808E00F00C1F80D23801006008D04B
+:1039200000F0211F80D23802006008D000F0852E00
+:1039300000F0062F191F80D23803006008D000F075
+:103940009B1B80D2080908607BAE00F0803000F03D
+:103950003904006008D000F0852E00F000F0062F3A
+:1039600000F0872FD41A80D23805006008D000F00C
+:10397000DB1A80D23806006008D03807006008D013
+:103980003808006008D03809006008D000F08D1BAE
+:1039900080D2380A00606A92852EE71980D200F042
+:1039A000761A80D2380A006008D0380B00606AAE00
+:1039B0000030C31F80D20000006008D00082007079
+:1039C00000F00990E9020A60E802086004A000F033
+:1039D000213000F0EB02086002A0EC02086001A0B8
+:1039E00000F0EA02086000F0007000F000F0003023
+:1039F00008D0EA020860BFA049820020BEA0009063
+:103A0000013000F000F0007009D000F0007000D02C
+:103A100000F0D8020F6000F0EA02086000F07026A3
+:103A2000B8A00090AC09096000F07020019000F08F
+:103A3000093000F000F0F12000F000F0722100F0F9
+:103A400000F0F32100F000F0742200F000F0F52205
+:103A500000F000F0762300F000F0F72500F000F011
+:103A6000782400F000F0F92400F000F07F2500F049
+:103A700000F0F72300F000F0007070D0EB02086057
+:103A8000A8A000F00020A7A00890007000F000F0AF
+:103A9000003008D0B6020F60A4A000F0742000F03F
+:103AA0001740F82000F03C9FF32200F000F00020C7
+:103AB00000F0D8A1F12100F00089722140E03C9F84
+:103AC000007000F000A2007040E00882FF7F0760F5
+:103AD00011A0703200F000A8EA020E600880C2094E
+:103AE0000660F3A8F03100F0FBC2663000F000F091
+:103AF000F33208D0BC020F6094A07020EA020E607E
+:103B0000F120D2090D6000F0722100F00BA270319B
+:103B100000F0D4DFF52100F0E382762200F0DB80B4
+:103B2000007000F0EBA2733000F0F3806D3000F015
+:103B300000F0F33208D0C3020F6089A0F22FEA022E
+:103B40000E607320007000F07923007000F0F821FF
+:103B5000007000F07934007000F000F0F42300F001
+:103B600000F0723500F000F0712100F000F000204C
+:103B700000F0F234EF090D604782DD090C6000F0BF
+:103B80006D3000E204916C3000E6D3826D3000E2CB
+:103B9000CB90007000F000F0F33000F000F0F33252
+:103BA00008D0C3020F6077A0F523FD090C607824CC
+:103BB000EA020E60F924007000F0F622007000F0B6
+:103BC0004591772200F00000000840E6BE9F00709B
+:103BD00000F0FF9F1010039045910070FC97F9349E
+:103BE000EF090C6078340070C0E000F0F63200F0AD
+:103BF00000F06C3008D0C3020F6069A0F12F0640BE
+:103C000000F07220007000F07325007000F0F526BF
+:103C1000EA020E60F027FD090D60CC90F63500F049
+:103C2000CF8E763600F09F8E743515940040066076
+:103C300014945784007000F00090007000F0CC9055
+:103C4000007008903C83F72000F02489007000F099
+:103C5000FFD7007000F03C83007000F024890070F2
+:103C600000F03C9F007000F0A4D1007000F000F064
+:103C7000743700F000F0782500F000F0F63500F021
+:103C8000812F0080026003A0007000F08AA0007005
+:103C900000F00090007000F060A00070C0E049AF3C
+:103CA000007000F000F0713600F000F06D3008D0C8
+:103CB000D3020F604AA078201C0A0D607921EA0225
+:103CC0000E6000F0082000F000F0192000F07222D1
+:103CD0000D7C00F06D301D7C00F000F0002000F045
+:103CE00000F0112000F080C8007000F089C8F030AA
+:103CF00000F000F0F13108D0E5020F603EA078201E
+:103D0000280A0760F920EA020F60002089080A608B
+:103D10001120007000F000F0A03000F000F0213120
+:103D200000F000F0773008D01350ADDE006000F0F6
+:103D3000000008600008026005A000F0801608601E
+:103D40008001026003A01350007031A000F00070E9
+:103D500000F200F0007008D0C390BEBA0160BA9EB5
+:103D60000070FBB3FB9E0010FE9700F0813F08D06F
+:103D700000F06308086000F0E702096000206108B5
+:103D80000B609120E9020D60103000040260478E44
+:103D9000332000F000F0903000E69F8E552000F0B8
+:103DA000FFFF006009D04591933000F000F00070F3
+:103DB00009D400F0A61F80D01640EC02096000F084
+:103DC0007808086000F01630008000F0063008D057
+:103DD0000640EC02096000F07808086000F0163038
+:103DE000FC8F16407908086000F00070FA8F0640DA
+:103DF0007908086000F00070F88F16407A080860B3
+:103E000000F00070F68F06407A08086000F000703D
+:103E1000F48F92827B0808608A90007000F010C2D4
+:103E2000012000F08A90007000F051C2007000F094
+:103E300008C4007000F000F0003008D016407B0885
+:103E4000086000F00070EB8F06407B08086000F00F
+:103E50000070E98FEC02096004A01740162003A04F
+:103E6000BE9F78080860C691007040E100F01630EF
+:103E7000E48F00F0007008D000F0551680D000F0FC
+:103E8000551680D000F0551680D000F0551680D021
+:103E90000041991F80D00042991F80D000F0551634
+:103EA00080D000F0007057800044991F80D00040FF
+:103EB0001B1A80D08040991F80D000F0551680D00A
+:103EC0001040991F80D000F02A1680D000F05516BF
+:103ED00080D01050991F80D000F0551680D020500F
+:103EE000991F80D000F0551680D00042991F80D0D5
+:103EF00000826E000E605620007000F0D520603108
+:103F000000F000F0E63100F000F0603200F000F068
+:103F1000E53200F000F0E03008D06E000C6045A003
+:103F200000F0472044A0C783007008D06E000E60E8
+:103F300042A0E020680A0560DB82662100F0389E1E
+:103F4000E72100F000F0633009D800F0612200F0B2
+:103F5000BFC3E22213403CCCE030039452C2770A44
+:103F6000056014CCEC7009D0469000700341658167
+:103F70006E000D60E180FF3F03602488513000F047
+:103F80001BC1007000F09AC3007000F000F06231B5
+:103F900050D06B110D60E48F6D110D60E38F6F11C8
+:103FA0000D60E28F71110D60E18F73110D60E08F74
+:103FB00075110D60DF8F77110D60DE8F79110D6047
+:103FC000DD8F7B110D60DC8F7D110D60DB8F7F112C
+:103FD0000D60DA8F81110D60D98F83110D60D88F3C
+:103FE00085110D60D78F87110D60D68F89110D60F7
+:103FF000D58F70000E60008000F0007000F000F0BF
+:1040000067201FA0BEC5007000F000F0663000F011
+:104010006E000E601CA000F0E6201BA08E910070C8
+:1040200000F000F0E63008D072000E60F78F00401C
+:104030000660F58F00200660F48F04000660F38FA1
+:1040400000100660F28F00100660F18F001006600D
+:10405000F08F20000660EF8F02000660EE8F0800F0
+:104060000660ED8F00010660EC8F00040660F48F9F
+:1040700000080660EA8F00040660E98F000206600F
+:10408000E88F80000660E78F40000660E68F00083A
+:104090000660EE8F00400660ED8F10000660E38F33
+:1040A00001000660E28F00200660EA8F00100660C3
+:1040B000E98F00F08000006000F0991F80D000F0D0
+:1040C000007008D000F0007003A000F00070338092
+:1040D00000F0007001A000F00070358000F000706A
+:1040E00008D000F0007008D000F07B1480D200F0FF
+:1040F000BB1480D200F03B1580D200F0AF0180D21B
+:1041000000F0A11380D200F01B0280D200F00070FA
+:1041100008D0F02074000E6072208B1101606031B5
+:1041200040000060E130193A0160603078000D60B5
+:10413000E131AB110060523128000160D030A63B64
+:1041400000605130007000F0D031007008D077204E
+:10415000D1070960762101050460FFD7FE2000F039
+:10416000BA81E34F00F000F0123000F0F1219B1B08
+:1041700080D2BA9E1D2000F000F01230E6AF0AA2F5
+:104180001C2000F09AC2035400F000F040080960BF
+:10419000D3A2610000F000F0133100F0D3801130A1
+:1041A00000F06100943114C000F0962000F0FF9FF1
+:1041B000133100F0D380113000F06100943100F031
+:1041C00000F0133100F076D0113000F0D38056109B
+:1041D00000F000F046140DC000F0007000F0FF9FEA
+:1041E000007000F000F09620F89700F0007000F0EA
+:1041F00076D0007000F000F0561000F000F0461489
+:1042000008D000F0BF11086000F0B31F80D27C001E
+:104210000960CDAF00F0112011A000F0007008D0AF
+:104220007C000F60CAAF4790713102A000F05D02C0
+:1042300080D200F09F0180D000F042090F603FD291
+:10424000DB070A607620FFFE05602220007000F088
+:10425000AEC3007000F0B59E007000F0BEC50070E7
+:1042600040E000F0763008D042090F60BEAF00F0A9
+:104270007020BDAFC0D1007000F040D4007008D0F5
+:104280007C000960BAAF00F0922000F000F011301D
+:1042900000F08290007000F0518A0070C0E000F0E1
+:1042A000330380D041907C00096092820070C0E0AE
+:1042B00000F0112000F000F09230F68FDB070A606A
+:1042C000B0AF00F02020AFAF309E007000F0104083
+:1042D000991F80D51040771A80D02240FD020960D6
+:1042E0000082114000F01238624100F090310070FD
+:1042F00000F01132007000F09132007000F01033C5
+:10430000007000F0123E00080360123F544000F0BD
+:104310009334A54100F09435A64000F015370070A5
+:1043200000F09636007000F0913700700080008237
+:10433000FD02086000F0007000F08033007000F0B3
+:10434000003B007064810C70FD020F6000F02917C3
+:10435000026000F0F72E00F0F92D007000F0C79118
+:10436000007000F0FF9F004009D000F0F73E00F021
+:10437000F62D007000F000F0100000F096831000A1
+:1043800004C00010100000F00010AB160A6000100E
+:10439000007000F0F93DFA3DC0E200F0604008D046
+:1043A000FD0208605BA000F0812E08D0FD020860CD
+:1043B00059A000F0013E5181FD02086057A000F0B5
+:1043C000013F08D0FD02096055A09123007008D07C
+:1043D000FD02096053A0113800701080FD020960D1
+:1043E00051A09131007008D0FD0209604FA0113238
+:1043F000007008D0FD0209604DA09132007008D015
+:10440000FD0208604BA000F0822F00F00BC200708C
+:1044100000F08CC2007000F0E782007008D0FD024E
+:10442000096046A0113B007008D0FD02096044A05D
+:10443000912B007000F0122C007008D00082FD0259
+:10444000086000F0007000F08033007038A100F0C8
+:1044500000703F8025030E603DA0E72CFD020F6039
+:104460000082662E00F0C791F52900F08691742A2B
+:1044700042944591632D2F950491F0394995C3904D
+:10448000703A889500F0603DE09400F0007008D02C
+:10449000008214030A6000F0FD02086000F0212091
+:1044A00000F000F0003600F000F0803300F049909A
+:1044B000803F00F0003000700EB02130BF0A80D085
+:1044C000C741FD02086000F00070004000F00629BE
+:1044D000114000F0803C2240BEC381333340A79F8F
+:1044E000007000F0879F833A00E2A79D803A00E2C7
+:1044F000879D813A00E2A79B813A00E200F0823A70
+:1045000000E200F0C10A80D200F0C00A80D000F0C2
+:1045100014030B60FF83007005C000F0371000F03B
+:1045200000F0371008D014030A601AA000F026210A
+:1045300000F000F0A02000F0BE81A72200F008905B
+:10454000263100F000F0A030F69388D3262209A08F
+:1045500000F0A531F49390D3007007A000F0A531CE
+:10456000F29398D3007005A000F0A531F093A0D38A
+:10457000007003A000F0A531EE9300F0263200F0A9
+:1045800000F0A73208D040D0A521019CCF91007047
+:1045900008D000F00070019C8E91007008D04D9101
+:1045A000007008D000F014030A6000F009090B60E5
+:1045B00000F0200085C800F0200000F000F030106E
+:1045C00000F000F0301008D000F0007008D001407A
+:1045D0005C08086000010060FDAF8031A008026047
+:1045E0000131007006C000F0007000F082310070F0
+:1045F00000F00131C411086000F0A81F80D025032D
+:104600000A60F6AF00F0A52CF5AF7D9F50080B6057
+:104610006D83224040E100F0A53C09D400F0B230A7
+:10462000B18007585C080860865125030A60802025
+:10463000FD020960812167040D603FC2C54121264A
+:1046400073C2022048905BD500707EA0EB9E36407E
+:104650002740CB90C5411790CB9014260C9000F0CA
+:104660000070019000F0007032800C91007000F03A
+:104670002BC21800076000F014363390FB820070E4
+:1046800000F000F00070319091160F6001A000F072
+:1046900000703080248300701AC000F0741000F0A5
+:1046A00000F0007008D000F0952603400C91172709
+:1046B00000F02D8F143600F036C200700390BE9FBC
+:1046C00000702B9000F00070299000F000702180A5
+:1046D000E78F0070289000F000701E9400F00070CA
+:1046E000258000F0252600F0FF83112400F0459F6F
+:1046F000132500F036C294250A94719E1521089066
+:10470000CB900070079C4591952000F000F0007060
+:1047100002904291007000F0E091007000F01C8F58
+:10472000133500F000F000701D9000F00070128052
+:1047300000F017351B8000F0942700F000F0A12650
+:1047400036400491C54100F036C2242F17902DC287
+:1047500000700494679D007000F0479D00701490F5
+:10476000479B0070139000F0007012900291A425F6
+:1047700000F04090E3FF056020C4007000F0049159
+:10478000007000F028C20070C0E000F000700C80E3
+:1047900000F0133600F0A00804600C80F7411640CA
+:1047A00042A000F000707CAFA00804600980A0085F
+:1047B0000460088029C2007041A0201004600680B7
+:1047C000201004600580F74116403BA000F013352F
+:1047D0007DAF201804600280F741164038A02018F1
+:1047E0000460008000F05C08086000F067040D6061
+:1047F000843125030A6000F09116076000F0A62EB0
+:1048000000F04982007094418E8D007000F0A68BFC
+:10481000D1070F60F781812100F000F0773000F0C0
+:1048200000F0D32000F049D57F2000F0799E55207C
+:1048300000F09BD876200B901B88972400F0F38221
+:10484000007000F0FBA2112400F09B81242600F0F0
+:10485000719E007000F0249F0070059C00F00070B5
+:104860000494C590733000F000F035030F602F887A
+:10487000007000F000F0773000F000F050080B609E
+:104880000082972700F06DD4A12E00F0C79105316A
+:1048900000F04790007017907F984640029400F017
+:1048A000203700F07F98A03700F0479CD02001947B
+:1048B00000F0A63C00F000F000700998469C222011
+:1048C000255036880070F34FADC1007000F0AAC2C9
+:1048D000007000F018C6A427C0E00790007000F038
+:1048E0002CC50070019800F0A43700F000F00070B3
+:1048F00005800790055800F00E8824270398ADC165
+:10490000007000F02CC5007000F000F0243700F0BB
+:1049100000F0844043404190303000F0B430B33078
+:10492000C0E24990007000F000F0A13E08D000F015
+:10493000923800F03FC2963900F000F0173908D0E5
+:10494000B683A136A740C9D73A0C0560C98B8450FD
+:1049500000F04D81A63E00F0A4C2007000F000F00F
+:10496000007050D000F0007000F000F0007000F017
+:1049700000F000708140980105600B8000F000702D
+:10498000C14000F00070068000F000704141B401A9
+:104990000560078000F000704141B40105600580AA
+:1049A00000F000704140FC00056003800491680144
+:1049B000056000F0014100E65003056000E600F0EC
+:1049C000213600F000F0253008D02503096054AFEF
+:1049D0001140902D53AF088C40080E6007CC142274
+:1049E00000F0CD9101400260C0C115310154108C1E
+:1049F000972D00F060300209066000F00070E13091
+:104A000000F0E6310AC02489932216403C83922BA1
+:104A100000F098A1007000F011A1007000F004A84F
+:104A2000007000F03C81FF7F0560F3A8007000F08B
+:104A3000EBC2943D00F000F0933200F000F06021F2
+:104A400041AF00F0903108D0008225030960914108
+:104A5000007000F000F0903500F000F0103300F02E
+:104A600000F0903300F000F0103400F000F0113E40
+:104A700008D025030A6038AF272E50080B6000F0DD
+:104A8000007000F0C791262500F0F899B12109D0F7
+:104A9000B6D2A327069400F0302100F05DC622278D
+:104AA00000F0ADC5203F00F014C6253500F000F041
+:104AB000A43400F00558A13F0280F09D265005580F
+:104AC000FC9D22250398FF99A22400F0EDC10070FF
+:104AD00000F0AAC20070028036C1007000F0B2C2BD
+:104AE000007000F01140A02325AF0090007000F08E
+:104AF000829020230294A1332134C0E200F00070A0
+:104B00000B8045502325069400F0242400F0EBC2CE
+:104B1000354000F004910070029000F000700194A4
+:104B200000F02134018000F0A5350280089000706B
+:104B300000F000F0203300F00082007000F000F080
+:104B4000A03300F000F0202E15AF389E007000F06A
+:104B50000090203E00F01440A02309D435402325C6
+:104B600000F00090212300F0E3C2262C029049902F
+:104B700000700194799EA53500F000F0007000F0FF
+:104B80008F8F213300F000F0007009D000F0A535C0
+:104B900008D000F00070CFAF00F00070CE8F4982D7
+:104BA000AB16096081390D030A6000F0893D00F001
+:104BB00000F0093D00F000F0013A00F000F0813E05
+:104BC00000F000F0213300F000F0013000F000F0C0
+:104BD000813F00F000F0013600F000F0013100529A
+:104BE0008130991F80D08AD7AA0C036000F0007032
+:104BF0003740D380007000F079C2007000F000F000
+:104C0000007030D06196007008D04190007008D0DC
+:104C10006190007008D04192007008D041940070FB
+:104C200008D06192007008D06194007008D041965D
+:104C3000007008D000F0712900F000F0F02800F0BA
+:104C400000F00070F0AF00F0F22A00F000F0334006
+:104C500000F08A90C641742B9AC2007000F0049153
+:104C6000007000F03C9F007005901483007000F00D
+:104C7000248300700394743BC60A80D2F03BC64183
+:104C800000F0713C007000F08EC3007000F0FF83F4
+:104C9000F23A1A943640F73A00F000F0732000F030
+:104CA0008EC3F42F00F0C79000701694FF9E15403D
+:104CB0000290F79E2540049000F000700E9000F0E6
+:104CC000F03F00F07530C50A80D200F0007010800F
+:104CD0002782762100F0F72113400C9486917530DD
+:104CE00000F000F07331019400F0F0300B80C791B8
+:104CF000F32000F03DC2F0300990FBC2007000F0DC
+:104D00005E83007000F000F0C20A80D700F00070EF
+:104D100005802782007000F000F01340019400F03D
+:104D20000070028000F0F03F00F000F0733000F0FF
+:104D300082900D030960BA9E00700390BA9E1622FD
+:104D4000059000F00070099000F096220A8009D2C8
+:104D50001030174000F0113200F000F0F73C08D09E
+:104D600000FF076000F000F0903000F0BEC300705C
+:104D700000F08EC5007000F000F0163208D009D2A5
+:104D8000103100F000F0913208D000FF076000F011
+:104D900000F0903100F0BEC3F42C00F08EC5154039
+:104DA00000400491963200F0753A703AC0E200F08B
+:104DB000007008D0C6410D03096000F00070474143
+:104DC0001122FF00006000F0932200F042C2007048
+:104DD00000F009D6007000F0C4C2007000F01BD6CD
+:104DE000007000F070C2054000F03882007000F0E2
+:104DF0004D91007040E0B0C2007000F03882007049
+:104E000000F04D91007040E0F0C2007000F0388278
+:104E1000007000F04D91007040E030C3007000F071
+:104E20003882762300F04D91007040E08091753417
+:104E3000C641759F0070249400F000700F9870C2F6
+:104E4000354000F03882007000F069C40070C0E0A6
+:104E5000B0C2007000F03882007000F0AAC4007088
+:104E6000C0E0F0C2007000F03882007000F0EBC4C7
+:104E70000070C0E030C3007000F03882762200F08D
+:104E80002CC50070C0E08691007000F017400070E3
+:104E90006E9600F00070148070C2354000F03882C9
+:104EA000007000F069C4007040E0B0C2007000F013
+:104EB0003882007000F0AAC4007040E0F0C20070B8
+:104EC00000F03882007000F0EBC4007040E030C3A6
+:104ED000007000F03882F62200F02CC5007040E02F
+:104EE0008691374000F000F00070069078C20070A4
+:104EF00000F0309E007000F0B8C200700398309E41
+:104F0000007000F000F00070019817400070598E9A
+:104F10000740007058AE09D2007000F05180007058
+:104F200000F01BD2113200F0E380007000F000F0BE
+:104F3000933200F0772D0D030960782D2917026058
+:104F400000F0100000F0D783100004C00010100023
+:104F500000F00010AB160A6000100D030960783DE8
+:104F60007A3DC0E200F0F22E00F000F0732E64AE45
+:104F70009F82742F00F08A901623049C0491F23EC5
+:104F800000F0A782007009D000F0007009D400F092
+:104F9000C30A80D000F0F02D00F08E912917026036
+:104FA0003190163300F01782007000F0F13DFA3DA9
+:104FB000C0E200F0007008D000F000701AA500F008
+:104FC0000070B7A200F000702EA500F0007033A5AD
+:104FD0006D7100603DA00100016021A000F0007033
+:104FE000008000F0007064A079120860BB81E80DB9
+:104FF0000860BA81DA0D0860B98100F06A040860BF
+:1050000000F0690409600020007000F011200070B9
+:1050100022A54990007000D079120860B381840401
+:105020000860008000F09604096000F0802100F024
+:1050300000F0912000F000F01221008008A0007024
+:1050400000F080A9FF7F016040D6007000F088AEBC
+:105050000070029400F00070019800F0007008D019
+:105060004090007008D08D040860F48F96040860AA
+:1050700012A500F0803000F000F0013108D0960455
+:1050800008600FA500F0803100F000F0013208D078
+:10509000960408600CA500F0812100F000F00222C7
+:1050A000EF8F2340124009A58A826B040860CB82EF
+:1050B00000700290951502600290FF7F02600180EF
+:1050C000DF1E0260008000F0007000F000F002308F
+:1050D000748100F0ED03096000F0EE030A60112016
+:1050E000007000F02220007008D010406D040860AD
+:1050F00000F09604096000308D040A6000F0580248
+:1051000002601A30791203602231007000F0A3327D
+:10511000007036A02A0E0860898100826D04086044
+:1051200000F09604096000308404016000F0007013
+:1051300000F01130007033A000F0007039A02A0E8A
+:10514000086082815D040860EEA4003000705F8119
+:10515000A6040860ECA40040022100F000F0012049
+:1051600000F08290007000F04190007009D400F0CF
+:10517000003000F000F0803044B400F00070DB84B8
+:105180001040A604086000F0007000F000F08030CD
+:1051900008D053090E6000F0FFF0066000F0419067
+:1051A000672000F0F0506050C0E2F7C3007000F0DC
+:1051B000C7C5007000F000F0673008D01640A604A4
+:1051C00008604290074000F000F0063100E27A9E4D
+:1051D000873100E200F0073100E2729E873100E281
+:1051E00000F0073100E200F0863100E200F00070CC
+:1051F00008D0A6040860D1A400F0002100F000F05F
+:10520000812100F000F0003200F000F0813208D07F
+:10521000A6040860CCA400F0002200F000F0812277
+:1052200000F000F0003100F000F0813108D04D04B2
+:105230000860C7A400F0003E00F000F0813E08D0F6
+:1052400001406D04096000F0007000F000F01130C2
+:10525000AEA400F00070B784F0404D04086000F088
+:10526000007000F000F0803F158000F0A604096097
+:1052700000F04D04086000F0112100F000F0002F54
+:1052800000F04190007000F000F0C40A80D500F0FA
+:10529000803F08D04D040860B6A400F00020B5A4FB
+:1052A0000080007000F000F0803108D001407404EC
+:1052B000096000F0007000F000F0113208D00040EA
+:1052C0004D04086000F0007000F000F0803708D056
+:1052D0004D040860ACA400F08027AB844403086050
+:1052E000AAA400F0003008D000406D04086000F06F
+:1052F000007000F000F0803008D010406D040860AD
+:105300000140007000F000F0803000F000F08131CA
+:1053100008D000F00070BAA400F05E0B80D200F05C
+:10532000310B80D000828D04086000F03C000260E8
+:105330008031E70D03600231007000F083320070AD
+:1053400000F06D04086099A40020007098A40090FB
+:10535000007000F000F000700194E50D08602881F5
+:105360002A0E0860278100F0E30809608D040860B8
+:105370008B8100F0BC0A80D000F0CA11086000F0F8
+:10538000B31F80D200F0007000A100F03603086067
+:1053900000F00060096000F020600B600930C06020
+:1053A00009608B30007000F00931007000F04B0391
+:1053B0000F6000F0BC00096000F0B8010A6034A082
+:1053C0004D030F6000F0B401096000F0C0010A60F5
+:1053D00031A04F030F6000F0B801096000F0CF0169
+:1053E0000A602EA051030F6000F0C001096000F0B8
+:1053F000D7010A602BA053030F6000F0C8010960B9
+:1054000000F04F210A6028A055030F6000F0D00182
+:10541000096000F05F210A6025A057030F6000F0CB
+:105420004021096000F049030A6022A059030F607F
+:1054300000F05021096000F04A030A601FA00082BA
+:105440004D040F6000F09F00086000F00070F03223
+:1054500000F00070783300F00070F03300F000705E
+:10546000F03700F00070B2AF00829800086000F0E2
+:10547000007008C000F00070001000F09604086092
+:1054800000F08D04096000F084040A60902100702F
+:1054900000F00A30007000F0A031007000F00082CF
+:1054A0006D04086000F0E2412140003020030360F9
+:1054B00000F0813000F000F0033100F07404086067
+:1054C0005AA400F0803300F000F0003400F000F047
+:1054D0000070F2A100F000706CA400F05E0B80D2AE
+:1054E00000826904086000F0007000F000F00030F5
+:1054F00000F02A0E0860E48000F0793000F000F03F
+:10550000FA3008D036030D6057A339030F60E6A0C8
+:1055100003A0A604086003B044030A60002045030A
+:105520000F6022205F040D600090F1200758D32007
+:105530000070539450804D040E60118000707030E4
+:10554000C2A100706526CAB10070F130EAA10070F6
+:10555000E025EAB10070E126C1A100706227C1B167
+:1055600000FF06608CA40070D33FB280007000F092
+:105570008DB400705430B2800070D53000F00070EF
+:10558000623700F0A404086000F038030E60802049
+:10559000E5080A606C20007000F00090007000F0D8
+:1055A00000F0007005902520007087C8252000704D
+:1055B00000F04518007000F0451843030F606C3090
+:1055C0000070C4A000F06D040D6000F05B030F607C
+:1055D000552040080A60782101050460F92137034D
+:1055E0000E607B20007000F04591FC2000F00082EE
+:1055F0000020C0E200F0110000F000F0203000F0C8
+:1056000000F0213182CC45910070A4316D20E20878
+:105610000A6000F0007000F02220007083C8222091
+:10562000007000F05218007000F0521869040A600F
+:105630006D3040080A602220007002C000F0007047
+:1056400000F000828020C0E200F0110000F000F0C5
+:105650000070203000F00070213100F00070202038
+:1056600000F00070A12000F00070301800F0007011
+:10567000411800F000707B3000F00070FC30D1D396
+:10568000007000F091D20070029400F000703E9023
+:1056900000F000704C80B99E007000F049D300709B
+:1056A00000F0A99E00704C90C9D2007000F0999E45
+:1056B00000704D9089D2007000F0899E00704E906D
+:1056C00089D2007000F0A99C00704E9089D20070C1
+:1056D00000F0999C00704E9089D2007000F0899C77
+:1056E00000705F905E040960FEA397200080036055
+:1056F00003A000701121FAA0E208086014AA00E0DB
+:1057000003607A82007087C8D2A00070043014AAA7
+:10571000007000F000F0007004303E030F6092A0B3
+:10572000FD020F6015A400F06D040F6000F070031F
+:105730000860F720740409600140002000F0C69161
+:10574000007000F0FE9FF22102902640732102902B
+:1057500000F07032078000F07132068000F00070B7
+:1057600000F09A80007000F0F131F23140EF80A239
+:10577000F63000EA8290703200EE00F0C40A80DB5E
+:1057800090216F030E6091236D040F6000F0172FBE
+:1057900000F00882142200F03AA2152400F08A805A
+:1057A000903200F02481632000F02C83923300F0CB
+:1057B0003EA3143300F0AE81922400F0C0A2772201
+:1057C00000F080A2163400F0E4A3007000F0268000
+:1057D000152600F02782007000F0A8A1007000F0EC
+:1057E00010AA007000F0E8B1103500F011BA007096
+:1057F00000F09135020780D2A0040F608AA17404E2
+:105800000860048300F04D040F6000F000000760A2
+:1058100000F00070732400F00070F42700F00070B6
+:10582000F52EE3820070762EEBA2782340E1F3A2FE
+:105830007022C0E1E3800D7C712500F00070022031
+:1058400000F00070F03500F00070713600F000706C
+:10585000F23600F00070773700F00070F3374B033A
+:105860000F6079A04D030F6078A000F00070BE8F2C
+:105870004F030F6081A051030F6080A000F0007003
+:10588000BB8F53030F607EA055030F607DA000F017
+:105890000070B88F57030F6087A000F00070B68FBC
+:1058A00059030F6085A000F00070B48F00F0490329
+:1058B000086000F04A030960002040080A601120D7
+:1058C0004D040B60203000090460A130007000F02E
+:1058D000A431007000F000F0302400F000F0B1219D
+:1058E00000F000F0B22000F00882007000F010A27A
+:1058F000007000F0418030200CC000F0B13100F0A9
+:1059000000F0252100F00A8E262007406D833231F9
+:1059100040E0BE8D353200F000F03634A18F4D04EA
+:105920000F609FA300F00070F62F00F0007070224F
+:1059300000F00070F12200F000707B230F820070F5
+:10594000F42300F00070332082910070F52DBA9F8F
+:105950000070C0E100F0F23F029C1C83371800F099
+:105960003C817B3300F003A00070F32462A500703B
+:10597000F433D2800070F03286910070723500F0FE
+:105980000070E9B200F000708F8F00F05D040860D5
+:1059900000F0FF7F0260002000708BA38182007006
+:1059A00000F04990007000F0C7D774040F60BF8208
+:1059B00084040E60CF918D040D6000F0773600F006
+:1059C00000F0673400F000F0573400F06B040E6014
+:1059D00082A36620007000F000F03E030F6086A3F3
+:1059E00039030E6000F00070763200F0007066320D
+:1059F00000F072BC076000F044030F60C7A30070A2
+:105A000000F03F880070773045030F6078A300F006
+:105A10000070F73000F08E98076000F04D040F60C2
+:105A2000C0A1007000F027AA007000F000F0007024
+:105A3000F73400F06F05076000F071660660CFA3D1
+:105A40007D040F60F781007000F000F0773008D01F
+:105A50006A0409606CA300F0183008D003A0650444
+:105A60000A6078200070096000F0007009A000F062
+:105A7000783008D003A061040A60782000700960C3
+:105A80002F170D6005A0AC7478300C8003A0630460
+:105A90000A6078200070096047170D6001A0AC749F
+:105AA000783008801108000882C91108000816C063
+:105AB00009A01108000809A09D7B8D7B0AA4007035
+:105AC0008D7900F00070221003A011080008FC205E
+:105AD0000D7C08D000F00070200000F0007041083C
+:105AE00000F0007072220882782100F010A200708D
+:105AF00023200980007000F0CB8200704118D3A2EF
+:105B00000070FC30C980FA2100F003A00070413021
+:105B10005100000800F05100000816C009A0510013
+:105B2000000809A0007000F00AA400700D7900F0D0
+:105B30000D7C223000F0783108D000F0007000F0C9
+:105B400078201810096003A00070FA2011000008E6
+:105B500000F01100000806C009A01100000809A00B
+:105B6000007000F00AA400708D7D00F00070221813
+:105B700000F00070FA3000F0783008D000F00070CB
+:105B800000F078201810096003A00070FA201100BE
+:105B9000000800F01100000806C009A0110000086C
+:105BA00009A0007000F009A000708D7D12AA00709D
+:105BB00000F000F00070221800F00070FA3000F0E1
+:105BC000783008D000F0007000F0782020100960D4
+:105BD00003A00070FA201100000800F01100000876
+:105BE0000EC009A01100000809A0007000F009A073
+:105BF00000708D7822AA007000F000F00070223052
+:105C000000F00070FA3000F0783008D000F000703A
+:105C100000F078203010096003A00070FA20110015
+:105C2000000800F0110000080EC009A011000008D3
+:105C300009A000708D7B09A000708D7932AA0070D8
+:105C4000783000F00070221803A00070FA301100C4
+:105C5000200800F0110020080EC009A01100200843
+:105C600009A000707B2109A0007000F0F2AB007069
+:105C700000F000F0323008D000F00070662078208C
+:105C80005010096003A00070FA2000F000700618A0
+:105C90001100000800F0110000080EC009A011005A
+:105CA000000809A0007000F00AA4783000F000F0AD
+:105CB000223008D01020FF1F07600524007005A3C4
+:105CC00028A2007000F040D0052300F0388A81211E
+:105CD00000F087D002221640C883032000F090A174
+:105CE000842000F019A0853340E121A00733C0E1F2
+:105CF00000A8052100F00880FF7F0760F2A880312E
+:105D000000F0BAC2812200F04591023200F07D9F7E
+:105D10000070C0E100F0053110D300F0007008D031
+:105D20000082010409600E040A6000F000F0903067
+:105D300000F000F0A03008D000F07612086000F00B
+:105D4000A81F80D200F08212086000F0A81F80D047
+:105D50004880EF03096008090F60DEAD00F0903164
+:105D600000F000F0F02CDCAD00F0103108D0AC03F6
+:105D70000960E7A200F0113208D000F0AC0309601E
+:105D8000C9D2007000F000F0913208D000F000009D
+:105D9000076000F001000660CF83020005608E837B
+:105DA000007002904D8300700B9000F00070058031
+:105DB000B683910309608D9188030A6015326C04E3
+:105DC0000B6000F0263200F000F0363008D0B683C9
+:105DD000910309608D9188030A6015326C040B6091
+:105DE00000F0253200F000F0363008D0B6836C04A5
+:105DF00009608E91007000F000F0163008D0880322
+:105E00000960008000F008090F6040900070C0AD8C
+:105E100000F0103000F000F0702DBEAD00F09030BA
+:105E200008D091030960C9A200F0113000F000F021
+:105E3000923008D07F030960C6A200F0113208D06A
+:105E40007F030960C4A211304504086000F092305D
+:105E500000F000F0133100F004304F1680D04504FC
+:105E60000860BFA201217F0309600090022000F0BA
+:105E700041908320029000F0007001909A8A007097
+:105E800000F000F0923108D045040860B8A200F09C
+:105E9000003108D0A3030960B6A200F0113208D087
+:105EA000A3030960E5AF00F0133108D09A0309603D
+:105EB000B2A200F0113208D09A030960E1AF00F0FD
+:105EC000133100F000F0943108D072030860ADA2E5
+:105ED00000F08021ACA200F0003608D07203086008
+:105EE000AAA200F00026168072030860A8A200F0A3
+:105EF000802114A000F00070178072030860A5A232
+:105F000000F00020118072030860A3A200F00021BD
+:105F10000F8072030860A1A200F080200D80720340
+:105F200008600C8000F0007023A100F0C008096038
+:105F300000F0340707607000007000F07000173246
+:105F400012C07000903200F090323507076000F008
+:105F5000903200F000F0173200F0008200700080F4
+:105F60007203086094A200F0803408D012400070E0
+:105F700000F000F0803100F00234014038A100F060
+:105F80000040448100407203086000F0007000F09F
+:105F900000F0003408D0AC0308608BA2002272032A
+:105FA00009608122007000F000F0103500F000F070
+:105FB000913508D07203086086A20025AC03096001
+:105FC0008125007000F000F0103200F000F09132F6
+:105FD00008D07203086081A28121AC0309600082AD
+:105FE000007000F0C9D2103200F000F0913208D0F9
+:105FF0001040AC03086000F0007000F000F00032C8
+:1060000008D07203086079A200F08021788200F045
+:10601000E011086000F0B31F80D200826C040860B9
+:106020008450EC0309600030ED030A601030EE0389
+:106030000B60203044040C603030007000F04430BD
+:10604000214094AD00F04204086000F08000006040
+:1060500000F0430409600030000D016000F00070A2
+:1060600000F01130007000F000F071030A6030059C
+:10607000026067A2223003000060020001600D810F
+:1060800000F05F03086000F00060006000F0600353
+:10609000096000300060016000F06F030A60113099
+:1060A000FF7F026000F070030B602230000003608D
+:1060B00000F0DF030C6033300000046000F0E00308
+:1060C0000D6044300000056000F0007000F05530B5
+:1060D000007000F00082EC0308600990EE03096094
+:1060E0000130ED030A601030007000F020300070C5
+:1060F00000F07203086051A2FF83802150A2C6D233
+:10610000073400F000F0863200F000000160F5A0D6
+:106110000000006001A1F040A0040F601240DC10FC
+:1061200001607030C1110360F130007000F000F0C8
+:10613000723100F000F0F33108D000F0007000F090
+:1061400000F0702000F0F74FF12000F0389E007052
+:1061500000F0388C007000F000F0703010D300F0C8
+:10616000007008D00020007000F01120007000F0D6
+:10617000922040080E6008A0C104046030AA62307A
+:1061800000F000F0603100F000F0E4310EC000F0EB
+:10619000007000F000F0E52000F000F0F63000F0B4
+:1061A00000F0253008D027406103086000F0491056
+:1061B00006607730B512096063030A60F18F6740AB
+:1061C0006103086000F04D1006607730B712096077
+:1061D00064030A60ED8F27406103086000F05110EE
+:1061E00006607730B912096065030A60E98F47409D
+:1061F0006103086000F0551006607730BB1209603B
+:1062000066030A60E58F27406103086000F05910BB
+:1062100006607730BD12096067030A60E18F27408E
+:106220006103086000F05D1006607730BF120960FE
+:1062300068030A60DD8F47406103086000F0611069
+:1062400006607730C112096069030A60D98F274060
+:106250006103086000F0651006607730C3120960C2
+:106260006A030A60D58F27406103086000F0691057
+:1062700006607730C51209606B030A60D18F474012
+:106280006103086000F06D1006607730C712096086
+:106290006C030A60CD8F27406103086000F0711025
+:1062A00006607730C91209606D030A60C98F274004
+:1062B0006103086000F0751006607730CB1209604A
+:1062C0006E030A60C58FE041821001602F170860DD
+:1062D00001A0461708600680703063030960F13042
+:1062E000007000F000F0100000F000F010000CC092
+:1062F0000010100000F06303096008D000F01000E7
+:1063000000F000F010000CC00014100000F000F0CD
+:10631000007008D027406203086000F08610066015
+:106320007730B512096063030A60B48F6740620377
+:10633000086000F08A1006607730B71209606403C5
+:106340000A60B08F27406203086000F08E1006607C
+:106350007730B912096065030A60AC8F4740620369
+:10636000086000F0921006607730BB120960660387
+:106370000A60A88F27406203086000F0961006604C
+:106380007730BD12096067030A60A48F274062035B
+:10639000086000F09A1006607730BF120960680349
+:1063A0000A60A08F47406203086000F09E100660FC
+:1063B0007730C112096069030A609C8F274062032D
+:1063C000086000F0A21006607730C31209606A030B
+:1063D0000A60988F27406203086000F0A6100660EC
+:1063E0007730C51209606B030A60948F47406203DF
+:1063F000086000F0AA1006607730C71209606C03CD
+:106400000A60908F27406203086000F0AE100660BB
+:106410007730C91209606D030A608C8F27406203D0
+:10642000086000F0B21006607730CB1209606E038E
+:106430000A60888F0046B510016047170860C4AF36
+:106440005E170860C98F00F00600006000F0C810F9
+:106450000160703087040860F1309B040E600020FA
+:106460005C040D60E121FD020C606220007000F010
+:1064700000F0552000F00882E32000F010A2C723AE
+:1064800000F00880642200F0C7911740E0311B8EB5
+:10649000E24F05943CC56621C0E014C3274040E0AC
+:1064A000768FD24F00F03CC50070C0E014C300707E
+:1064B00040E000F0643208D000F00200006000F01C
+:1064C000CC100160703001040F60F1300070168153
+:1064D00000F00400006000F0D010016070300E0485
+:1064E0000F60F1300070128100F00200006000F0D7
+:1064F000D410016070301B040F60F13000700E8109
+:1065000000F00200006000F0D81001607030280434
+:106510000F60F13000700A8100F00400006000F0AC
+:1065200059110160703035040F60F13000701D8129
+:1065300000F00400006000F0F110016070307203A0
+:106540000860F1308404096000F0012400F000F0DC
+:10655000822200F04190802100F000F09421049408
+:1065600053D5052394A12F8F862393A1F38A00701E
+:10657000C0E0C090833100F000F0007013A000F084
+:106580005D04086000F05F030960002060030A609A
+:10659000112061030B60222062030C6041A2007095
+:1065A00000F082A2313000F000F0423008D000F05C
+:1065B0000200006000F0F510016000F0703000F0A3
+:1065C00000F0F130208000F00800006072214510DA
+:1065D0000160F321F74F00F0BA9E00707030BA8C62
+:1065E0000070F13000F0723130D300F0007008D04C
+:1065F00000F0007001A000F00F3208D000900311ED
+:1066000007603E9A0070139838800070129C00F06A
+:10661000007077A17203086000D0CD120F60108067
+:10662000E1120F600F80F5120F600E8009130F60EA
+:106630000D801D130F600C8031130F600B8045130C
+:106640000F600A8059130F6009806D130F60088076
+:1066500081130F60078095130F600680A9130F60E8
+:106660000580BD130F600480D1130F600380E51314
+:106670000F600280F9130F6001800D140F6000801D
+:1066800000F0007008D00740C00809601540710391
+:106690000A60102072030F602220007000F02EC2EA
+:1066A00000702350B1C4474000E259C4F02400F008
+:1066B00079C47F2200F0AEC7007000F0B2C474004D
+:1066C00008A000F0123200E600F0123008D023508B
+:1066D000C00809608AD0354FD9AF10207203086016
+:1066E0009AC4007000F029C2802400F051C47400E4
+:1066F00000F00090113000F000F0113200E600F0E0
+:10670000007093C87400943000F000F0943200E6FA
+:1067100000F0943200E600F0943008D000F07103ED
+:10672000096000F0720308601220007000F000F0B1
+:10673000812400F082C4C008096041900070EB8F92
+:10674000072244040B6000F0102000F0C791812064
+:1067500000F0B68302201F900F82832100F0178281
+:106760000421019800F021200B80F78D40080D6076
+:106770005682212008905630C2080560D73000703C
+:1067800000F0D531007000F000F000700DC000F096
+:10679000007000F0E6820070572100F0007000F0F9
+:1067A000F7A3007000F0E78135200180C790352005
+:1067B00000F0C883007000F0EDA3007000F00389C2
+:1067C000007000F0ED8E022416406D83832309943F
+:1067D000C883007000F090A1042300F019A000709D
+:1067E00040E121A00070C0E100A8007000F0088026
+:1067F000FF7F0660F2A8203000F0B2C2007000F007
+:1068000000F0023408D000F0053400F000F027302A
+:1068100008D000F0822221A100F0223008D000F040
+:106820000200006000F05E11016070307F030860BC
+:10683000F1300D04096060030A60D68F00F0020099
+:10684000006000F063110160703088030860F1306F
+:106850001A040960DF030A60D18F00F004000060B1
+:1068600000F073110160703091030860F1305C0436
+:106870000960E0030A60CCAF00F0E003086000F0BC
+:10688000DF03096000206C040A601120A6040B607D
+:10689000272070030C600A8A362100F0C79100702F
+:1068A00000F092820070C0E08691007000F0928249
+:1068B0000070C0E04230007008D000F002000060BC
+:1068C00000F07811016070309A030860F1302704FD
+:1068D00009605F030A60BC8F00F00200006000F0F6
+:1068E0007D1101607030A3030860F1303404096049
+:1068F0006F030A60B78F00F01000006000F0DC103A
+:1069000001607030AC030860F13041040960770326
+:106910000A60B28F1130E10808605A202114096022
+:1069200003A0E1030F6000F084040E60170006204E
+:1069300087C81700062000F0B9A1261800F0B8A5F6
+:10694000261800F00089732300F000F0E42300F023
+:10695000C390652300F0F39E762106942D8300708A
+:1069600000F0A4A3F72100F02D8F007000F000F0DC
+:10697000773300E600F00070189400F0F2230580F1
+:1069800000F07333169C00F0742200F06D830070E9
+:1069900000F0E48EF22300F000F0753300E600F022
+:1069A000F52416401082F32000F0A8A1742000F016
+:1069B00019A05A3040E121A07124C0E100A8772538
+:1069C00000F01080FF7F0660F5A8F03300F075C37B
+:1069D000F32216400882F53400F0B8A1007000F0F0
+:1069E00019A0007000F000A8007000F00880FF7F80
+:1069F0000660F7A8703400F0F7C396040860773596
+:106A0000E308096008200070C78D5A3096040860BA
+:106A100000F0E308096008200070C48D00F00070E9
+:106A200000F000F0022200F000F0032100F092805C
+:106A3000812100F09AA2862000F05080842600F088
+:106A400000F005270598208207200A9030A20070E8
+:106A500040E138A20070C0E12480007000F0288B73
+:106A6000843606800088007000F02882072000F03D
+:106A700030A2007040E138A20070C0E12D800070AB
+:106A800000F0288B053700F000F0803708D000F0C8
+:106A90000100006000F0C51101607031007000F06D
+:106AA000F1310070868000F03D00006000F0CA11F6
+:106AB00001607031007000F0F131EF030F6000F001
+:106AC00000700A8000F00100006000F0CF1101604A
+:106AD0007031007000F0F131F5030F6000F00070CC
+:106AE000058000F00100006000F0C111016070310C
+:106AF000007000F0F131FB030F6000F000700080C7
+:106B0000B683F92000F000F0782000F000F01120AA
+:106B100000F000F0002000F04190732100F000F040
+:106B2000F42103901B8E772200F000F0007009D052
+:106B3000C791007003808E91F72200F0048F0070DF
+:106B400000F0C791007009D000F0163070D700F047
+:106B5000007008D000827B04086000F0E90309603F
+:106B6000012083040A60F22387040B600989F3255E
+:106B700000F05582F42100F02D8C112000F05D8B87
+:106B8000F22200F028A1F32400F05582F42000F056
+:106B90002D8C212000F05D8B722300F029A173253C
+:106BA00000F05582742100F02D8C312000F05D8BB7
+:106BB000722200F029A1732400F05582742000F0A5
+:106BC0002D8C007000F05D8B007000F02DA5007022
+:106BD00000F0288C007000F000F0703608D00082C1
+:106BE0007B04086000F08304096000F087040A60F9
+:106BF00000F0E8030B60012042040C60F223430420
+:106C00000D600989F32500F05582F42100F02D8CE8
+:106C1000112000F05D8B722300F028A1732500F095
+:106C20005582742100F02D8C262000F05D8B72229D
+:106C300000F029A1732400F09583742000F02D8CBE
+:106C4000312000F05D8BF22200F029A1F32400F046
+:106C500000F0F42000F000F0472000F000F0552094
+:106C600000F0BE8F007000F0698A0070C0E05582AD
+:106C7000007000F02D8C007000F05D8B007000F053
+:106C80002DA5007000F0288C007000F000F0703628
+:106C900008D090419B04086000F0FFFF016000F005
+:106CA000803000F000F001310EA000F000702C8068
+:106CB000004084040F6000F0E1030E60F0304D04EA
+:106CC0000D60703074040C6060309B040B60E03029
+:106CD000007000F0503E007000F0D03E007000F0F8
+:106CE0004030007000F0C030007000F0B030007034
+:106CF00000F0303100701E80CA0309600180B503C6
+:106D0000096000807F030F6017A088030F6016A042
+:106D100091030F6015A09A030F6014A0A3030F60E6
+:106D200013A0AC030F6012A0100084040F601100C8
+:106D3000007000F000F0F03000F000F0713000F072
+:106D40001000E1030F601100007000F000F07030DF
+:106D500000F000F0F13000F01000007040A000F0F2
+:106D6000F03200F010004D040F601100007000F0D0
+:106D700000F0703E00F000F0F13E00F010007404EE
+:106D80000F601100007000F000F0703000F000F0B3
+:106D9000F13008D000F00070100000F00070110019
+:106DA00000F0703300F000F0F13308D000407404BC
+:106DB000086000F0007002807404086030A000F0E9
+:106DC000802F2FA000F0003F08D000F04A0B80D2A7
+:106DD00000F0A60408604390DF03096000F08421FE
+:106DE00000F000F0112000F00491022100F0419029
+:106DF0000020029482908120089000F00070079497
+:106E000000F0007000F00090007000F0FF83007050
+:106E100009D000F0073078AB00F0007062AB00F0F2
+:106E200000707DAB00F00070148000F0007000F086
+:106E30004190007000F00090174009D0C39000709E
+:106E400009D407306C0B80D700F0007065AB00F000
+:106E5000007067AB00F000700F8000F0291408602C
+:106E600000F0B31F80D0FF83A4040860CF91FFDF40
+:106E7000016000F00020025200F087300C80FF8398
+:106E80006504096000F0A40408601730007000F089
+:106E90009730FFDF016000F00020024000F08730F3
+:106EA0000680A404086009A0C14F002000F0324011
+:106EB00000700380A404086006A0C14F002000F009
+:106EC00022400070008008C2007000F010C4E0088A
+:106ED000096000F0003000F000F0103008D000F041
+:106EE000007008D01040B204086000F0007002800A
+:106EF0000040B204086000F00070008000F0003232
+:106F000008D000F00070B2A00746B204086000820A
+:106F100010010960369E873200F000F0003500F065
+:106F200000F00032125086331CEF0360123700125B
+:106F30000460033F670005608430264000F0053799
+:106F4000174000F00634C80A016087360068026006
+:106F50008137034100F01234007000F013350070E7
+:106F600008D000F05314086000F0B31F80D200F086
+:106F7000007000800082B204086000F0F800096030
+:106F80000033007008C000F0101000F080351001D0
+:106F900009600036015400F09036007000F0913422
+:106FA000007008D000F0620B80D200F09B040E60ED
+:106FB0007728B204086066225E040960C791022E39
+:106FC00000F0CF91102009D0869100708C9000F0D5
+:106FD000912009D400F065040E601382C2040F6092
+:106FE00054826304096000F0662000F07B204008B2
+:106FF0000A60FC20E1000260102069040D60368800
+:10700000233100F000F0A63000F000F0203082CBF9
+:1070100000F0A23100F000F055200CC000F0E62096
+:1070200000F09020A4040D603688243100F000F0B8
+:10703000A63000F0D72069040D6000F0203000F089
+:10704000C791202000F000F0A12002940080007081
+:1070500000F04980007000F000F0301800F000F0FF
+:10706000411800F0EDD37B3000F000F0FC300194CB
+:1070700000F000701F80C6040F6098ACC9040F6058
+:1070800097ACB2040860B9AF802D5E070260012D95
+:107090004D04096000F0852700F00090832500F082
+:1070A0001088862601988090007000F0698A007030
+:1070B00000F02D88172100F0698C007000F0C79156
+:1070C000007000F000F000700F9408A00426174034
+:1070D000A8AF00700658D9A1007000F0A2A1FF7FF0
+:1070E0000760F3A8022400F0FBC2007000F004A8BF
+:1070F000062700F008A0002E00F0A1A1072200F052
+:107100008DAE007000F0C791007000F02880007014
+:1071100009D400F0003E00F000F0833500F000F0EC
+:10712000043608D0DB82822300F024830070F68FBF
+:1071300000F0AD040E60CC040F608AACB2040860AD
+:107140009AAF00F0072500F000F0F800066000F0AC
+:1071500010010D60F581007000F000F0D53795AF9B
+:1071600000F0D92794AF00F01D7C00F000F0102053
+:1071700000F000F09D78542700F0112000F03FDB74
+:10718000D22600F00B82007000F0E3A2007000F045
+:107190009A80007000F000F0D23600F000F08734E2
+:1071A00000F0B204086089AF87215D040E6000F032
+:1071B000002F00F03F89662000F000F0812E00F0E3
+:1071C00030A2007000F04180F80003605480813EDE
+:1071D00000F0E5DC843F00F06591062500F0588161
+:1071E000822200F09E81D0377EAF00F0D92700F0D8
+:1071F00000F0D63700F000F0112000F000F0DA27A0
+:1072000000F0C883007000F010A2232000F041803D
+:10721000007000F0CE8E113000F000F0053500E671
+:1072200000F0D13700F0AD78552400F000F02420B4
+:1072300000F0EBA2D33505541B8F543600F09BD3DE
+:10724000D62400F02B88572540E0F382007000F030
+:10725000FBA2007000F09D81007000F000F0D534BA
+:1072600000F00421FD020B60802F2503096000F06F
+:10727000062300F000F0812400F08691022000F047
+:10728000BE9F8320C0E00F82063300F0CF83B0237F
+:1072900000F0DF83832106588290073009D8F3C2BB
+:1072A000062309DCE4C667040D608691033100F013
+:1072B0000090075809D44591102B0194C491007097
+:1072C00040E19693543000F00633007000F000F077
+:1072D000922100F000F0912A00F010A2132155AF86
+:1072E0005980852154AF28A0044F00F042AEF740EA
+:1072F00000F0A28C962000F0BA8A1532074F95C78D
+:10730000923010407DC7007000F000F0D53000F0E2
+:10731000103DAF0B80D0690408604BAF00F0002037
+:107320004AAFC0D2007000F000F00070179000F07B
+:10733000007008D000F05F17086000F00A000060DD
+:1073400000F04023016000300B0002608130001427
+:10735000036002310C0004608331804D056004320B
+:107360000D0006608532C014076006336717096098
+:1073700087335F17006004406117016010306317A6
+:10738000026091306517036012316C170A60933107
+:10739000007000F01432007000F000F01B2000F0CC
+:1073A00000F0293000F00082AB3000F000F0203116
+:1073B00000F000F0A03108D06C17086030AF8920D1
+:1073C00067040A6000F0802100F000F0112000F056
+:1073D00000F00B20065809C0F440034F71C23C7006
+:1073E00000F000F0213000F0A430A330C0E208909B
+:1073F000007000F0079C022100F000821C7040E247
+:107400008A90803100F0B798893000F09282023182
+:107410000894332067170C6000F0023100F0C3902D
+:107420000B3000F067170B6000E200F00C3000E258
+:1074300000F0392000F000F0823100F000F08930D7
+:1074400000F000F0AF0B80D01140007001A000F000
+:10745000113008D07F0009602780205801601CA0EF
+:10746000806601602180204001601A80806C01608C
+:107470001F802000016018807F0009601BA0009021
+:10748000802C00F000F0812D09D000F0003BA045D9
+:1074900000F0813B00F000F0003E08D07F00096062
+:1074A00015A000900040016000F0004009D00130BC
+:1074B000E40F80D07F00096011A00090204001609F
+:1074C00000F0104009D00130E40F80D200F0D00F5E
+:1074D00080D07F0009600CA00090A04500F000F073
+:1074E000007009D000F0003E08D07F00096008A0BD
+:1074F00000900020114000F00070019040D4007016
+:1075000008D04090007008D07F00096003A0009070
+:10751000007000F000F0104009D00130E40F80D07E
+:1075200000F0D908086000F0102004807F00096096
+:10753000FDAF0090007000F000F0007009D000F086
+:10754000813F08D000F0007008D000F064060860A9
+:107550004982007000F00632007016A04982B678A9
+:10756000006000F0007076A011400070ABA000F049
+:107570000070D3A000F00070CDA000F00070578024
+:1075800006586806086000F01B0405608683072023
+:1075900000F0AEA3864B0460CF915206096036819D
+:1075A000073000F0163000706BA000F00070C9A02A
+:1075B00000F0007094A000F0A51480D0A608086028
+:1075C00018A000F0002000F000F0812008D000F0AA
+:1075D0000070E5A000F0007015A000F00070C780FA
+:1075E00066140F6012A0720052060E6072000070E6
+:1075F00004C07200621000F000F0621008D09282A5
+:1076000052060F604190007000F0F230732240E6A5
+:1076100000F0F13109D000F0F33008D052060E60CE
+:1076200005A000F0E73008D0D578056000F05206DC
+:107630000E6002A0EFA3007000F000F0673108D0E8
+:107640000049066002A070A0007000F037AA007028
+:1076500008D000F0007008D000F052060F6000F073
+:1076600057060E6076206B140F6000F0ED2200F0DC
+:107670007C216B2403A000F0007002A000F0ED322A
+:1076800000F000F06B3408D07820500800F000F0D3
+:10769000510800F000F0420000F000F0003000F06F
+:1076A000F720813000F000F0023100F0F9216A2269
+:1076B00000F000F0873100F003A01200200803B0B2
+:1076C00021088BC811A01200200851B0210800F039
+:1076D00010A4430000F051B4003000F000F08130FD
+:1076E00000F000F0033100F000F0873100F000F00E
+:1076F000802000F000F0320800F030A0682600F092
+:1077000013AAF921EA23D080007000F000F080185D
+:1077100000F003A011002008110020080AC009A0F1
+:107720001100200809A069227A2009A0EA2300F0AC
+:10773000A0209D7800F069322D7800F031A06836E5
+:1077400000F030A4EA330D7C00F0003008D0008255
+:10775000C008086000F07817096000303103076046
+:107760001000007002A078170960D1AFDF911000FF
+:1077700000F01000073012C01000803000F000F060
+:10778000803000F000F0803008D073060F6000F009
+:1077900078170060CAAFF030007000F07030D70A80
+:1077A00080D20082A5140F6000F0570608607100B7
+:1077B00000000960710000700CC07100011000F041
+:1077C000011020010A60B54A01103FC000F01010FE
+:1077D00000F000F010101EC000F0201000F020108B
+:1077E000A001096000F020100EC000F0101000F0A1
+:1077F000101040000A6000F0101026C000F02010A9
+:1078000000F020106A06096000F0201007C000F0A8
+:10781000101000F0101090010A6000F010100FC05E
+:1078200000F0201000F000F0201008D000F00E2B27
+:10783000076002A222870660B8A0E3C3056031A0FA
+:107840008F02036026AA64060860AE81007000F013
+:10785000F5D7003000F05DA3863000F07D9F00700A
+:1078600000F000F0853208D0792152060C6000F05B
+:10787000F82000F000F0C72100F000F0FB2000F03D
+:10788000C791101800F01718111840E6BD7879312B
+:1078900000F000F0792000F000F07A2000F003B052
+:1078A0001000830803A011009FC8C1A01000830826
+:1078B000C9B0110000F0C0A4F82000F0C9B4E03055
+:1078C00000F0C7910D78613000F0FB30029400F0B9
+:1078D000673100F000F0E73108D003B020008308E2
+:1078E00003A021009FC8C1A020008308C9B02100C7
+:1078F00000F0C0A4007000F0C9B4E03100F000F066
+:10790000613108D064233E200560E323C25F066036
+:1079100060A1622400F09FA5633300F098A1673254
+:1079200000F0AFA4E23300F000F0E73208D000F03E
+:107930006406086000F0A1140F600E217017096042
+:10794000852077170A6000F0640000F0EDD773001F
+:1079500004C967A3640000F0FE80730000F0FE829B
+:10796000161000F000F0261400F000F0007008D0AF
+:1079700000F06406086000F09914026000F09D14A5
+:107980000360759E007000F0C290813140E00231CA
+:107990000070EF8F03A05706096003B070170E60E8
+:1079A00000F0007000F00290982167004390007092
+:1079B00087C8B9A002086700F9B0030D00F0B9A0AC
+:1079C000003000F0F9B0813000F038A8983101A003
+:1079D00039B80070078084A9007000F064DE055893
+:1079E000029800A8007009D0789F007008D00C9110
+:1079F000007000F000A8007009D04091007008D01D
+:107A000084B9007000F064DE0558029801B8007077
+:107A100009D0799F007008D00C91007000F001B877
+:107A2000007009D04191007008D074000F6000F020
+:107A300000F0E10A80D078000F6000F000F0E10A69
+:107A400080D200F00070818F00F075060C60B68364
+:107A50000053076000F0463000F000F0C63100F03F
+:107A600000F0C73008D07506086051AF00F0003153
+:107A700008D04982750608600090007000F000F0A0
+:107A8000813100E600F0003008D000F057060E60AB
+:107A900000F079060B606A2575060D60E8257B14F9
+:107AA000096000F0562100F003A00070040800F007
+:107AB000EC25C4C934A311002208110022081CC0FF
+:107AC00051A01100220851A03410AD7B50A47B14AA
+:107AD000096030A204082D7903A0301000F0CD79A0
+:107AE0006A3500F000F0EC3508D075060B603BAF4E
+:107AF0000082312000F000F079060E604190B22142
+:107B000000F000F0600000E2E2080D6087C88280AB
+:107B1000600000E24190523000F08280B12000F01D
+:107B20005230E0080C6000F0B23100F000F041305B
+:107B300008D00B846A060E60098657060F60C09055
+:107B40000070A0AF00F0007085AF782352060C6083
+:107B5000F92481060D6000F0C72000F000F06022DB
+:107B600000F000F0D12300F000F0622100F00CA240
+:107B7000D12400F01481632000F00DA2041800F05D
+:107B80007EA2051800F09E81E02200F000F0161899
+:107B900000F000F0512400F000F0E22100F00CA20F
+:107BA000512500F01481E32000F00DA2041800F02C
+:107BB0007EA2051800F09E81783300F000F01618C0
+:107BC00000F000F0F93408D000F0B714096000F0BC
+:107BD000810608600082007007C00010100000F0ED
+:107BE00000F0007008D04982B21409604990810603
+:107BF000086000F0922100F003B0132200F012A2FE
+:107C0000003300F088A0007000F019A0007000F0B0
+:107C1000F2A8FF7F046003A8007000F0A2C28331C5
+:107C200000F05BD1023100F095D5007000F0EB80E0
+:107C3000007000F052D100300560A2C2007000F068
+:107C400052A3007000F08AB0007000F05AB10070CA
+:107C500000F0F2B8007000F003B8007000F0A2C2AB
+:107C6000833200F00232007008D0FF838106086082
+:107C70003FCAB2140960FFD7002000F01A2081200B
+:107C800000F085D51E2102214ED19F2083217581D0
+:107C900000702E30DD800070253194800070AF318F
+:107CA0004D91007040E13CC3007000F020800070F6
+:107CB00000F04990007040E16980007000F038C227
+:107CC000007000F086D5007000F04FD190060B6078
+:107CD000BE81812000F04D81263100F00481FF7FBC
+:107CE00007604D91002040E13CC3853000F06ED428
+:107CF000043000F000F0042200F000F0852200F0D3
+:107D000020808C060C604990363040E16980242048
+:107D100000F038C2A52000F0C6D5AF3100F08CD1FC
+:107D2000843300F0A6818534C3C95980461000F021
+:107D30001080007000F04990007040E138C22520AA
+:107D400000F0C6D5A42000F08DD1053400F0AE813E
+:107D5000043500F000F0461008D04040910608605D
+:107D60006241114000F00030CD140E608030A50655
+:107D700009600131610000F0823161000EC0111014
+:107D8000610000F01110007000F011100070008010
+:107D900000F09106086000F0DB07096000F0802029
+:107DA00000F01220BC140F600030950608607000CF
+:107DB0005C0809607000007009C07000001000F0DD
+:107DC000B29E0010125000F0001009D400F0923161
+:107DD00008D091060F601AA04982732119A0C390A0
+:107DE000722000F0799E007009D000F0712216A078
+:107DF0005382007000F000F0007009D849820070D2
+:107E000008D07A9E91060F60929A007009D800F00F
+:107E1000007009DC00F0F13008D091060F600EA070
+:107E200000F0F13108D0419091060D6000F0007033
+:107E3000E5B700F0513108D088D0A5060660419022
+:107E4000D1070F608681674109D800F0763006A01F
+:107E50007F8E7F2000F000F0007009D000F07210DB
+:107E600000F000F0731000F000F0741000F000F06B
+:107E7000751008D000F0007008D067DCD120703693
+:107E80003FC6512100EAF7365C080B6000F073230F
+:107E900000F064D0713400F0FB9E743700F0FF8373
+:107EA000733309D4A640B42000F01340F22300F04D
+:107EB00064D0763300F08290F33300F006417437DB
+:107EC00009D02440F02200F03640763300F00890CC
+:107ED000F73300F030C2F82400F0268EF0320F9411
+:107EE0007220A10608607022A1060960F721C7145C
+:107EF0000C601382FA2500F03B82F2200298008287
+:107F0000A5060A603B82723000F07C35C30A80D33C
+:107F100000F082060E6000F0220083C800F022000C
+:107F200000F000F0121000F00890121000F000F0C5
+:107F3000703200F0B683FA3500F0F6D2020000F09D
+:107F400000F0F83400F000F07A2500F0B3C2723788
+:107F500000F02400240140E600F07A3500F000F043
+:107F6000B43100F000F0323108D000F091060F601B
+:107F700000F082060E6072215E150D6065206A06B3
+:107F800008608290742757204591F0260B907DC39E
+:107F90007124D1BBECD5D82165300C8157207226D5
+:107FA000ADD1F43700F07DC3012000F07CC7FC2781
+:107FB00000F08AA2007000F055A3402000F014A346
+:107FC000C12000F020A06A0608606AA4007000F0DA
+:107FD00000F0023408D03200066003A000F0063042
+:107FE00000F000F0033300F000F0833308D000F01D
+:107FF000FD06086000F07A15006000F07B15016056
+:1080000000310000026001329315006082320816D0
+:10801000016080317201036000F0013408D000F08B
+:10802000BF1F80D200F0A70980D200F0DE1A80D2F4
+:1080300000F0281F80D2FF060860A3A000F00070A7
+:1080400000D2FD060D60A8A050244902016000F096
+:10805000522300F000F0030708608290DC7300D226
+:1080600000F0F71A80D200F0E00780D200F0860A14
+:1080700080D200F03C0A80D200F0007000F200F0E4
+:108080000070EF8FBA9E8320029000F002300194BE
+:108090004090033000F000F0503008D000F00307AB
+:1080A000086000F0007003A06A150060088000F00E
+:1080B000540280D208160060068000F0022094A0CE
+:1080C0008290832000F000F0007009D000F00330AF
+:1080D00008D000F0822090A000F0023008D0050700
+:1080E00008608A8000F0370780D01040951F80D24A
+:1080F00000F0F31A80D200F00070F3AF00F0BA0A7B
+:1081000080D000F0621508607A1501607EA000F052
+:10811000090000F000F000008CC800F0090000F039
+:108120001030000000F00040301B80D20140040BF2
+:1081300080D200F0C80680D20740C60780D0104029
+:10814000991F80D200F00070878400F0B00380D2C5
+:1081500010402040C0E200F0991F80D200F0007073
+:1081600083840607086071A01040991F80D700F033
+:108170000070808400F0A11F80D000F00070DD8FBF
+:1081800000F07A150860A315016069A000F00900ED
+:1081900000F000F000008CC800F0090000F0103082
+:1081A000000000F0F14F007099A00040301B80D219
+:1081B0000140040B80D200F0C80680D21740C607E9
+:1081C00080D01040951F80D200F0F31A80D200F0CA
+:1081D0000070CFAF00F0310780D000F0530D80D297
+:1081E00000F0370780D01040951F80D210400F1B41
+:1081F00080D200F00070C98F00F0A11F80D200F083
+:10820000940D80D200F0260780D000F0FD060860B3
+:108210001040B21502602140061B80D200F06313AB
+:1082200080D200F00070BEAF00F0510D80D200F09F
+:10823000281280D01040B61502602141061B80D262
+:1082400000F08C0780D200F0730780D0FD06086034
+:1082500051A000F0012013401040007000F0619A1E
+:10826000BC150260598C061B80D200F0661380D0CA
+:1082700000F0291280D200F0940D80D200F0A11FEE
+:1082800080D20052991F80D200F02B0780D010407E
+:10829000991F80D200F000706E84060708603DA030
+:1082A0001040991F80D700F00070678400F00070C4
+:1082B0009FA11040204040E600F0991F80D200F0BE
+:1082C0008C1B80D201900070FAA000F000706584D1
+:1082D00000F0007048A210402040C0E200F0991F5A
+:1082E00080D200F0007061841040991F80D200F0AD
+:1082F00000705B8400F0007099A21040204040E6BE
+:1083000000F0991F80D200F00070578400F00070D8
+:1083100015A31040204040E600F0991F80D200F0E5
+:10832000007053841040991F80D200F00070558473
+:108330001400016001803200016000F0FD06086059
+:10834000278000F092150860F21501601EA000F071
+:10835000090000F000F000008DC800F0090000F0F6
+:108360001030000000F01040301B80D20140040BA0
+:1083700080D2014000704CA000F0A01480D200F028
+:10838000931380D200F02D0080D21040C80180D21B
+:1083900000F0EC1480D200F0CC0A80D01040951F81
+:1083A00080D200F0F31A80D200F0007080AF00F0AD
+:1083B000BA0A80D000F0D00A80D01040991F80D235
+:1083C00000F000707284060708600BA01040991F2F
+:1083D00080D700F000706F841040951F80D210404D
+:1083E000A60180D200F00070768F0040671480D222
+:1083F00000F0CF0A80D20040A60180D200F0A11F79
+:1084000080D0FD06096008A000F0113108D000F00E
+:10841000007000F000F0002005A00090007008D06F
+:1084200000F0007000F000F0003008D000F00070A4
+:1084300000F000F0013008D000F0007008D0008299
+:10844000070708600F900070024080322A07096019
+:108450000033454600F00035F40103600730960014
+:108460000160023200100460813000100160943D10
+:1084700055B50460113E414600F0943E007000F096
+:10848000113F014600F0173D00140460153CFFFF4A
+:108490000260943C90010460123B3A070860943BF0
+:1084A0000100056000F03E070960053045070A60DD
+:1084B000133032000760233015070860A730000032
+:1084C00002600130014000F0823058070A6001313B
+:1084D000520709602130104000F091304C070860CD
+:1084E0001030114000F00030004054A4F14F004023
+:1084F0000DA000F0003422A0B141007000F05E1623
+:108500000060888000F08C1B80D201909B1B80D281
+:1085100000F0941380D200F0261F80D200F08A0D64
+:1085200080D200F0490780D200F0530180D00707C5
+:108530000860D6AF00F0013208D00B070860CD8F7D
+:1085400007070860D3AF00F0813408D01007086037
+:10855000CA8F07070860D0AF8034140480D2174058
+:10856000C60780D200F01E0480D000F00070FAAF81
+:1085700000F0F10380D200F0660D80D200F0FD0320
+:1085800080D200F0690D80D04090D01B80D20707C8
+:108590000960038007070960C5AF4090913200F081
+:1085A0001123E41E80D200F01040C2AF00F010355D
+:1085B000D48307070960C0AF00F0113301A000F0B9
+:1085C0000070FB8F07070960BDAF00F01123BCAF3F
+:1085D0004090007000F010409022C0E200F0E41ED5
+:1085E00080D000F07F1B80D200F0B90F80D0114006
+:1085F00007070960F040830A80D200F0913500E25D
+:1086000000F0007008D00E070860ABAF00F00070FB
+:1086100000D000070860A9AF00F0503008D007076D
+:10862000096000F008160160ADAF00F091339D8342
+:108630000E070860A78F0F070860A68F00F06E1C5A
+:1086400080D260160060FC8FDB070A60A7AF212094
+:1086500000709D8363160060F98F00F00070A483A2
+:1086600000F0E040F8AF00F00070A6A314070D6022
+:10867000F0AF00F0010480D200F000701E9400F012
+:1086800000702AAF00F07805016000F0861B80D2F0
+:10869000F04FA91B80D240405E1B80D200F05D1CD1
+:1086A00080D270160060EC8F00400070C6AF0040B2
+:1086B000B40380D273160060E98F10400070C3AF1E
+:1086C0001040B40380D276160060E68F00F00304F9
+:1086D00080D200F07008016000F0861B80D2F04F5D
+:1086E000A91B80D240405E1B80D200F05D1C80D26E
+:1086F0007D160060DF8F00F0D11B80D2004000703B
+:10870000B8AF0040B40380D281160060DB8F104008
+:108710000070B5AF1040B40380D284160060D88FCB
+:1087200000F0E80380D200F00070F9AEF14F007065
+:10873000ADAF00F0D606016000F0861B80D2F04F8E
+:10874000A91B80D200F06E0780D20140104000F0DB
+:10875000E241AE0780D21607086073AF00F0721BCB
+:1087600080D2319E404000F0C04F007040E000F0E9
+:108770005E1B80D200F05D1C80D294160060C88F12
+:1087800000F0007095AF00F00070D8AE00F09407D4
+:1087900080D200F00070029099160060198000F0FD
+:1087A0008C0780D200F0730780D214070860BD8F59
+:1087B00000F0F040C0AF00F0007071A300F0007056
+:1087C000DA8200F00041BDAF00F0007075A300F048
+:1087D00000703DAF0040301B80D200F0960380D285
+:1087E000A5160060B78F00F00070D9AE00F0070743
+:1087F0000960A916016060AF00F09136DE8F0007B6
+:108800000860AF8FAB160060B18F00F000707F83FF
+:10881000150708605BAF00F0812000F000F0003524
+:1088200000F000F0813230800707086057AF012068
+:1088300000700080B90A0260A9AF1040061B80D00A
+:1088400000F08C0D80D200F0CB0F80D200F07912B6
+:1088500080D200F07B0D80D200F01C1280D200F09C
+:108860007A1280D200F06E0780D200F0740780D2B6
+:1088700000F0671380D200F0590280D20040C41B80
+:1088800080D00040C91B80D200F0007069AF00F0BA
+:10889000CE0F80D200F0007078AF00F000708BAF88
+:1088A00000F05B0280D017070860408F1607086051
+:1088B0003F8FF14F0707086000F0007000F0114093
+:1088C00081340180014000700080180708603AAFD1
+:1088D00000F0104090AF00F0007065A3180708602A
+:1088E00032AF00F00070029400F0310780D2D2164F
+:1088F00000608A8F00F08C0D80D21507096034AFBC
+:108900001021851B80D200F0912000F01F070D6020
+:1089100080AF00F0913200F0F04FA91B80D2070722
+:1089200008602EAF00F0012200F000F080242CAF90
+:108930000F82007000F07F9E007002900040104097
+:10894000C0E200F0007057AF00F010407CAF00F0C4
+:108950006E0780D200F08C1B80D20190104000F096
+:108960001241AE0780D200F0007055AF00F00070E9
+:1089700068AF00F01507096000F0670280D200F0D0
+:108980001032059400825E1B80D200F05D1C80D204
+:10899000ED1600606F8F00F06B0280D2EF16006062
+:1089A0006D8F1A07086011AF00F0721B80D2019022
+:1089B000007000F0319E007004904040C04FC0E253
+:1089C00000F05E1B80D200F05D1C80D214170060A6
+:1089D000658F4040641B80D200F05D1C80D2FA1687
+:1089E0000060628F00F0D30F80D200F0520D80D271
+:1089F000FD1600605F8F1040C41B80D200F0650D33
+:108A000080D21507086008AF00F0003300F000F0D6
+:108A1000003400F0C04F641B80D200F05D1C80D297
+:108A200005170060578F00F0D30F80D200F0520D71
+:108A300080D208170060548F00F0650D80D21507B2
+:108A40000860FEAE00F00123FDAE0A82803300F024
+:108A500000F0003400EA00F0007005981040C91BD7
+:108A600080D200F000701AAF00F0CE0F80D24040EC
+:108A70005E1B80D200F000700180C04F5E1B80D270
+:108A800019070860ECAE00F00070029000F092024E
+:108A900080D218170060448F00F0D70F80D200F00A
+:108AA000520D80D21B170060418F00F000700EAF96
+:108AB00000F0650D80D215070860EAAE00F00120D5
+:108AC00000F000F0803400F00F82007000F000F041
+:108AD0000070029800F0D50F80D200F00070018085
+:108AE00000F0D70F80D21F070860338F00F02040BE
+:108AF00036AF00F000700EA300F02D0780D22A17C9
+:108B00000060328F00F0007089AF00F05E1C80D2F0
+:108B10002D1700602F8F00F0830D80D200F06513B9
+:108B200080D200F00070FAAE00F0CE0F80D21107B4
+:108B30000860CFAE00F0980280D30082007000F091
+:108B400012070860CFAE13070860CEAE00F094079E
+:108B500080D245170060789339170060798F11072C
+:108B60000860C7AE00F000700A9000F08C0780D259
+:108B700000F0730780D23E170060728F00F0007023
+:108B800012AF00F0112600F092209C0780D249908D
+:108B9000007003948882007000F03E170060019816
+:108BA00000F011366B8F00F0730780D200F0007078
+:108BB0000AAF00F0940280D245170060679300F07E
+:108BC000007024AE00F0260780D24C170060108F92
+:108BD00000F0007004AF12070860B3AE00F0007040
+:108BE00009D000F07C1280D200F0171280D200F081
+:108BF000EA0F80D20140007000F011070860B2AEA9
+:108C000000070860048F0040007000F02A07086029
+:108C1000B1AE008280311540719E007000F00030CE
+:108C20000530C0EB5190007040E1052FBD0400609D
+:108C3000A69F813F014080338333C0E20034043477
+:108C4000C0E281358535C0E200F0823008D000F006
+:108C5000007007A10291832E2040B69F042FF28F4F
+:108C60003040007000F0390708609E8E39070860B8
+:108C70009AAE3F9E007008D02A0709609FAE11226D
+:108C80008C1B80D2088223409DAE00F0933700E217
+:108C900000F0007008D001402A07096000F0304061
+:108CA000EEAE00F09137C9A200F0310780D2721702
+:108CB0000060EA8E2A07096095AE972F8C1B80D240
+:108CC00000F0B91B80D21220007092AEBA9E380715
+:108CD0000D60FA9F0070029042900070C0E080909A
+:108CE000007000F01032007000F049829227DBAE75
+:108CF000AA9E113100F000F000707D9000F08C0D04
+:108D000080D201402A07096000F03040DCAE00F05C
+:108D1000913700F0102BA91B80D200F0A70D80D254
+:108D200000F0ED0F80D221409E0D80D200F028127D
+:108D300080D22A07096080AE902D007000F0112EBD
+:108D4000B10D80D2122000707DAEBA9E007000F08E
+:108D500000F00070079000F00070DAAF00F00070D3
+:108D6000069000F00070048000F0FC0F80D200F04C
+:108D70000070DFAD00F00070D5AF00F000706790BC
+:108D8000902FAE1B80D20140991700601507086034
+:108D900071AE00F0003500F000F08132478F00F036
+:108DA0001507086000F02A07096081243040C1AE31
+:108DB00000F0922700F0DB82902000F0AA9E93360C
+:108DC00000F0428291325B9000F01336EF9B00F08E
+:108DD000510D80D21140007000F0A41700600E8F7A
+:108DE0002A07096063AE00F0922700F0912E9B1BCA
+:108DF00080D2AA9E007000F000F00070529008A28D
+:108E0000CE0D80D200F0FC0F80D2A140007000F0A7
+:108E1000AD170060058F00F0F70F80D200F0C90D8C
+:108E200080D22A07096058AE9227FF0F80D2219284
+:108E3000CC0D80D2AA9E922300F000F0132447901C
+:108E400050B0142600F0F6B8952500F00C9190343F
+:108E500000F08783113500F065831436D79B00F04E
+:108E6000007002981140007000F0AF170060F68E9D
+:108E700058B0007000F0F6B8007000F08783007002
+:108E800000F000F00070D09B2A07096047AE9227DF
+:108E90000707086000F0962600F0AA9E122C00F04A
+:108EA00000F0132636903041830A80D200F016413C
+:108EB00000E2CB90007007901041830A80D200211D
+:108EC000007003948121540B80D256413641C0E298
+:108ED00000F000700280D08274040A6000F0133643
+:108EE000029C1140963600F0C0170060E18EA2236C
+:108EF0009B1B80D200F0172D00F01289912C00F0FE
+:108F0000C791123300F000F00070039841A2007086
+:108F1000C0E08B82007000F000F00070B79F44400A
+:108F2000912100F000F092264341479000701040DC
+:108F30008FC213361D90A7C200701C9400F0007001
+:108F4000B19700F000708EAD00F0631380D200F096
+:108F5000510D80D24141007000F0E4170060CE8EC8
+:108F600000F0661380D22A07096022AE9227070715
+:108F7000086000F0132600F0AA9E952100F0CB9027
+:108F8000922B11903041830A80D200F0007003943C
+:108F90007F9F164200E200F000700A9000F09636C3
+:108FA00007801041830A80D2002100700394812140
+:108FB000540B80D256423642C0E200F0007004806A
+:108FC000D082007000F000F013369A9F11400070BC
+:108FD00000F0E5170060BA8EAFC39636104000F07F
+:108FE0000070969300F0903700F000F010210CAE66
+:108FF000009091270BAE7A9E0070129400F0122020
+:1090000006901507086008AEBA9E002100F06A9E1F
+:109010000070029000F0007001901022007000F0CB
+:1090200000F0851B80D200F000706BAD00F02912BB
+:1090300080D2F04FA91B80D209180060A38E00F0E7
+:109040002A07086000F01507096082278C1B80D270
+:10905000AA9E1121FBAD0A820070029400F00070FC
+:10906000019000F00070EB8F00F0AC0D80D200F0AA
+:10907000F20F80D238070860468E4790014041AF1A
+:10908000C1910040658200F00070B8A200900070AD
+:1090900008D001402A07096000F0404044AE00F0CB
+:1090A000913722A200F0310780D21C180060408E58
+:1090B00039070860E4AD2F9E007000F000F00070EA
+:1090C000169000F08C0D80D200F02A07096007404E
+:1090D0008C1B80D200F0B91B80D21032271805609B
+:1090E0001140007000F000F0153700F000F0113171
+:1090F000588F00F0404035AE39070860D8AD3F9E2C
+:109100002A07096000F00070049400F08C1B80D2E4
+:109110009122007061A200F000703AAF00F0007080
+:10912000509700F0007041AD15070960D7AD1021D0
+:10913000851B80D200F0291280D2F04FA91B80D26B
+:1091400035180060778E00070860238E3C070860A2
+:10915000CA8D3A070860CE8D3B070860CD8D00F0C0
+:10916000504023AE00F0007004A200F02D0780D222
+:109170003D1800601F8E00F0007076AE3A070D605B
+:10918000C9AD5120150709600040441802609132B2
+:10919000A91B80D2D020851B80D200F012359C8E76
+:1091A00000F0504018AE00F0830D80D200F0007047
+:1091B0002AAD00F01507086000F03A070D60524133
+:1091C000104000F00121AE0780D24982862400F0D1
+:1091D00000F0D13100F05631007071AE00F0007037
+:1091E0001FAD00F0651380D2511800605F8E00F053
+:1091F0003A070D60F040830A80D200F0D03100E2DF
+:1092000000F0007009D000F0260780D257180060E7
+:10921000058E00F0730780D23A070D60AFADD521FF
+:1092200011000460F040830A80D24581007040E064
+:109230002040830A80D24581007040E06583D531AB
+:1092400000F000F0007009D400F07C1280D200F031
+:10925000171280D200F0EA0F80D200070860F58D67
+:109260003E070860A3AD0082813000F000F00033BB
+:1092700000F000F0043100F000F0853100800707B5
+:1092800009609EAD00F0123100F000F0933108D07B
+:1092900043070860948D3E070D609AAD00F0D1221F
+:1092A00000F000F0522200F000F0532308D000F04C
+:1092B0006040EBAD00F00070CFA100F02D0780D230
+:1092C00075180060E78D00F000703EAE3E070D603F
+:1092D00091ADD020851B80D20040BB180260512088
+:1092E000061B80D27B180060318E00F06040E1AD3B
+:1092F00000F0830D80D200F01507096000F03E07F2
+:109300000D609624070709604982572187ADBF8306
+:109310005632104000F0113600F000F091355198AF
+:1093200000F00070E9AC00F0D50F80D200F0D70D4E
+:1093300080D200F0631380D200F00707096000F0CC
+:10934000940780D200F0112000E28C180060268E75
+:1093500000F08C0780D200F0730780D241070860CC
+:1093600072AD00F0A518006000F05C1680D100F02E
+:10937000940780D2941800601D9600F000700C8055
+:1093800000F00070BCAD00F00070039400F06613B4
+:1093900080D200F07C1280D200F0D70D80D2070777
+:1093A00009606EAD00F0112600F092209C0780D27B
+:1093B0004990007003948882007000F09418006057
+:1093C000019800F01136108E00F0260780D21207A7
+:1093D00008605FADA518006000F000F05C1680D159
+:1093E000AB180060B78DF040830A80D200F00070A7
+:1093F00009D400F0661380D200F07C1280D200F015
+:10940000D70D80D2AB180060B18D1041830A80D295
+:109410000540007009D400400F1B80D20707086088
+:1094200059AD00213E070D608121540B80D200F020
+:1094300052330894D120007012AED532171280D268
+:1094400000F0281280D28140007000F0B718006050
+:10945000FB8D00F0EA0F80D200F0291280D20007C5
+:1094600008609F8D00F02140018000F031400080B5
+:109470004307086049AD4107086043AD00F0007044
+:10948000029000F02D0780D2C11800609B8D00F083
+:1094900015070D606241104000F05121AE0780D2E7
+:1094A00000F06E0780D200F07C0780D200F00070E0
+:1094B000AAAC00F07B0D80D200F00070F6AD00F099
+:1094C000830D80D200F00070A3AC00F0631380D253
+:1094D000CD180060E38D00F0260780D2CF18006021
+:1094E0008D8D00F0730780D2F040830A80D200F0A7
+:1094F000007009D400F0661380D200F0D70D80D23E
+:1095000000F00070108000F0D03200F000400F1B1F
+:1095100080D200F0007099AC00F015070D60624237
+:10952000104000F05121AE0780D200F00070E3AD92
+:1095300000F0007091AC00F0651380D2DF1800607D
+:10954000D18D00F0260780D2E11800607B8D00F0FD
+:10955000730780D2F040830A80D200F0007009D4F3
+:1095600000F07C1280D200F0EA0F80D200F01712D7
+:1095700080D200070860718D450708601FAD00822A
+:10958000013100F000F0803200F000F084317D8F76
+:109590004B070860148D45070D601AAD00F051238C
+:1095A00000F000F0522200F000F0D32208D000F0CA
+:1095B00070406BAD00F0007052A100F0310780D216
+:1095C000F5180060678D00F08C0D80D245070D60A6
+:1095D00011AD51210070CDAD4090851B80D200406F
+:1095E0001E1902605120061B80D2FC180060B08D4D
+:1095F00000F0704060AD00F0007070AC00F06313DC
+:1096000080D200F0510D80D200F0281280D221408B
+:10961000007000F003190060AF8D00F08C0780D25D
+:1096200000F0730780D22141007000F0071900603C
+:10963000AB8D00F0661380D245070D60FFACD120E2
+:109640001340FEAC619A0C190060598C0070A68D15
+:1096500000F0291280D200F02B0780D200F015070D
+:10966000096000F045070D6000F0912400F000F063
+:10967000D021F6AC4282513200F000F00070089820
+:1096800015190060478D1041830A80D200F00070E8
+:1096900009D407070860F0AC002145070D6081215F
+:1096A000540B80D2D2320070029400F0014003804B
+:1096B00000F01140028000F02140018000F03140B4
+:1096C00000804B070860E6AC00400F1B80D200070B
+:1096D0000860378D1040007000F051070860E08C82
+:1096E00001404C07096000F0804037AD00F0913236
+:1096F00021A100F0310780D229190060338D510774
+:109700000860D7AC3F9E007000F000F00070099335
+:1097100000F04C0709602F190560DAAC00F0153233
+:10972000048000F080402DAD07070860D7AC00F042
+:10973000002205AD00F00070FC8E00F0104129AD54
+:1097400000F0902102AD00F08C0D80D200F01C12D0
+:1097500080D200F07A1280D200F0671380D24C07DA
+:109760000960CEAC00F090200F8000F0104121ADD8
+:1097700000F0007034AC15070860CAAC812400709A
+:109780007CA100F000700F9051070860C0AC3F9EB4
+:10979000007000F04C0709600C9000F08C1B80D228
+:1097A0000190961B80D24180007000F00088122149
+:1097B00000F040C2007000F08382007000F000F002
+:1097C0000070059800F0851B80D2112015070D60F0
+:1097D00000403B190260D132A91B80D200F0523503
+:1097E000918D00F07C1280D200F0171280D25007C9
+:1097F0000860078D53190060098D00F000700B811F
+:1098000000F0904008AD00F000700EA10140040B84
+:1098100080D20140007098A000402C1E80D20054DD
+:10982000331E80D214070D60FCAC53070860A5AC52
+:109830000190204000F09241AE0780D252070860AC
+:10984000A2AC399E52070860A04F6040C0E287205A
+:109850006A1B80D2C091851B80D2F04FA91B80D299
+:1098600000F06E0780D27A15016099AC00F05D1CA3
+:1098700080D268190060F48C00F00070C1AC00F078
+:10988000007004AC00F0940780D200F000700290E9
+:109890006D190060458D00F08C0780D200F07307D1
+:1098A00080D200F05D1480D200F0BA0A80D2721922
+:1098B0000060EA8C00F05B1480D2F21501608BAC82
+:1098C00000F0BA0A80D276190060E68C14070860AE
+:1098D000E28C00F0A040E5AC00F00070E8A000F0E1
+:1098E0006E0780D200F05E1C80D27C190060E08C94
+:1098F00000F00070ADAC5807086083AC00F01F1E8C
+:1099000080D700F0610280D200F00070EDAB0082E1
+:10991000007000F01307086081AC00F0940780D25B
+:1099200000F000700D90861900602C8D1107086002
+:109930007AAC00F000700A9000F08C0780D200F042
+:10994000730780D28B190060258D070709607CACF6
+:1099500000F0112600F092209C0780D24990007000
+:1099600003948882007000F08B190060019800F069
+:1099700011361E8D00F0730780D20140007000F098
+:109980001107086071AC00070860C38C00F007077E
+:10999000096000F0A019016000F0B040C4AC00F014
+:1099A000913600F000F00070D0A00140040B80D28E
+:1099B0000140007053A000402C1E80D20054331E82
+:1099C00080D200F00070BB8F00F0B040BCAC004013
+:1099D000C80180D21040671480D200F0CF0A80D234
+:1099E00000F054070D601140040B80D200F05120AC
+:1099F00000F000F0D320098000F00070C8AB5407DD
+:109A00000D605EAC00F054215DAC0491512000F07B
+:109A100000F0D3200D90618000700198C882007022
+:109A200001805882007000F0C190007040E1513018
+:109A3000590709605882B619026000F0503100E2FF
+:109A40001230140B80D200F00070168000F000700D
+:109A5000B7AB54070D6050AC00F0D12100F0A8194D
+:109A60000060F88C0140040B80D2000708609D8CD8
+:109A700000F0C040A0AC00F00070B0A059070D602D
+:109A800098AC00402C1E80D20054331E80D200F0CF
+:109A9000100B80D200F0007011901040671480D23B
+:109AA000580708603CACC91901600690104020407E
+:109AB000C0EB140708603EAC00F00070968F5807AA
+:109AC000086037AC00F01F1E80D20052331E80D2D7
+:109AD00000F0B50280D2CE1900608E8C00F06803D1
+:109AE00080D2D01900608C8C00F0350380D2D2195E
+:109AF00000608A8C580708602EAC10402C1E80D75E
+:109B000000F0007099AB59070860838C01404C0746
+:109B1000096000F0D04085AC00F0913298A000F0D0
+:109B20000070BAAB2040301B80D21040C80180D2F8
+:109B300000F04C070960DF1905602AAC00F015320F
+:109B4000548F00F0D0407DAC00F00070FEAB00F010
+:109B500007070960E419016025AC00F09136778FA2
+:109B600000070860748C53070860208C5207086057
+:109B70001F8C5407096020ACD082123000F024887A
+:109B8000933040E100F0143100F000F09531F98F8E
+:109B90004C0709601BAC00F0913010401231CE0030
+:109BA000016000F093318A8058070860158CFD062B
+:109BB000086016AC00F0813100F000F0823208D06D
+:109BC00000F0FD06096000F00007086000F090302A
+:109BD00002A0FE06086009AC00F0007000D000F0A2
+:109BE000007007AC00F0007000D0FD0608600CACFF
+:109BF00000F0012200F000F000320AAC00F000702A
+:109C000010D000F0DB0709607F9E007000F0779EA7
+:109C10001220049047900070049000F000700190B2
+:109C200000F0007008D000F01130138000F0113007
+:109C3000228000F01130558000F0007076AB00F00B
+:109C400000705A8C9C160060E98F9F160060E88FA8
+:109C50008915016000F001000260E3AF00F0970A8F
+:109C600080D08F15016000F002000260E0AF00F0CC
+:109C70009A0A80D000F000707FAB9315016000F06D
+:109C800000000260DCAF00F0970A80D08B15016005
+:109C900000F003000260D9AF00F0980A80D07B1575
+:109CA0000060E1AF00F00070478C00F0DB070A6055
+:109CB00000F0FD06086000F02220EAABB99E803477
+:109CC00000F0B19E00702C9081900070539000F0D5
+:109CD0000070E89300F0007008D0DB070860E4AB88
+:109CE00000F00220E3ABB99E007000F0B19E00705E
+:109CF0002B9000F0007051901040991F80D09F155C
+:109D00000060D1AF00F000707F8C00F0007068AB95
+:109D100000F000709A8C00F000707AABA51501601D
+:109D200000F000010260C1AF00F09B0A80D000F09B
+:109D3000007079AB00F00070FB8FC115016000F07E
+:109D400001010260BCAF00F0990A80D0C315016028
+:109D500000F002010260B9AF00F09A0A80D0C61587
+:109D6000016000F003010260B6AF00F09C0A80D0F1
+:109D7000CC15016000F004010260B3AF00F09D0A51
+:109D800080D0D015016000F005010260B0AF00F096
+:109D90009E0A80D0D215016000F006010260ADAFCE
+:109DA00000F09F0A80D0D615016000F00701026024
+:109DB000AAAF00F0A00A80D0DA15016000F0080117
+:109DC0000260A7AF00F0A10A80D0CA160060A88F79
+:109DD00026170060A78F6D170060A68F1718006008
+:109DE000A58F39180060A48F71180060A38FF11837
+:109DF0000060A28F24190060A18F00F0FD060860AA
+:109E000000F00301046080220401056000F00801F5
+:109E100006602182050204602982641780D13182A4
+:109E2000641780D12182221980D100F0221980D1BB
+:109E300000F0007008D0EE1500609DAF00F00070DB
+:109E4000F38E00F000707FAB00F00070F38EF5151C
+:109E5000016000F0020202608EAF00F09A0A80D02A
+:109E6000F315016000F0010202608BAF00F0A20A5E
+:109E700080D000F0007093ABF815016000F0000294
+:109E8000026087AF00F0A30A80D0F315016000F0F4
+:109E90000302026084AF00F0A40A80D0F5150160CF
+:109EA00000F00402026081AF00F0A50A80D0F31533
+:109EB000016000F0050202607EAF00F0A60A80D0CB
+:109EC000771900607F8F541900607E8F96190060AB
+:109ED0007D8F060708608CABBC1900607B8FD6199C
+:109EE00000607A8F75465A07086000F014400640FB
+:109EF0002DC0CE040960098D863000F0498B0631F3
+:109F000000F000F0013000F08933FF7F046000F0C2
+:109F100006329C7400F0893200F000F0843108D0E1
+:109F20009300FF7F076000F0930000F0C48E930061
+:109F300000F0C48E9300FF9700F0132C9C7700F084
+:109F4000942000F0C090101000F0FA82111000F080
+:109F500001911320FC9700F0007008D0FF835A078E
+:109F600008603FCACE040F60FFD7822000F00320B4
+:109F7000CE0409608421CE0406609D8E8E2200F0FE
+:109F80000D8F0422039000F0EC7000F08A908E3266
+:109F900000F000F082300B8000F0007009D02381C7
+:109FA000007000F09E81007000F0A482063300F083
+:109FB0003C9F007000F000F00A23059000F0007054
+:109FC00000F000F0252100F000F0A62100F03C9FF9
+:109FD000251000F000F02610FC9700F06730E0AF8D
+:109FE0008120CF040960B683007000F0719E930059
+:109FF00000F000829400059800F0833100F01D8F7E
+:10A00000007000F00890940002900391007000F03E
+:10A010000690007000F0799E833100F000F0063267
+:10A02000FA9F00F0007008D048D0CE0406605A07AE
+:10A03000096056AB86819220334000F016330C70D5
+:10A040008C82021000F03C9F1E2352AB054065003D
+:10A0500040EF0640660040EFFB9E051000F03C9F7D
+:10A060000610FC9700F0007008D05A0708604CAB4F
+:10A0700000F0892300F000F0022100F000F003203E
+:10A0800049AB988E007000F000F0007009D08A9003
+:10A09000111000F000F0893300F0D082023108D0B6
+:10A0A00000F0CE0406605A07096042AB8E8112218F
+:10A0B000634000F016330C7000F0021000F08C8248
+:10A0C0001E233EAB0640660040EFFB9E007000F092
+:10A0D0003C9F0610FD9700F0007008D05A070860FA
+:10A0E00039AB00F08020388B00826207086000F0F6
+:10A0F000007009C00010007000F000F0007008D07F
+:10A10000620708601DA0813103C0006059C402329B
+:10A1100000F08332971F80D269C4043300F0C391EA
+:10A1200085330190314006340A80F04F62070860A1
+:10A130004982007000F00130971F80D062070860EC
+:10A1400013A000F0012012A04190022100F000F0C5
+:10A15000832009D08290007000F0BA9E00700190B8
+:10A1600000F0023108D0799E62070960799E007084
+:10A170000490C39000700490FB9E0070F29300F076
+:10A18000833000F017401C71028027401C72018050
+:10A1900037401C73008000F0102000F000F0922087
+:10A1A00000F00090007000F0C1910231F49307308C
+:10A1B000A61F80D000F0007008D000826B070F60EF
+:10A1C00000F0007006C000F0701000F000F0701099
+:10A1D00008D06B070E6021A000F0602020A0009046
+:10A1E0006C070F6000F0007009D000F0007001A053
+:10A1F0006F070F601CA0F6206B070E607720FF7FB3
+:10A200000460BE9F602000F0FF9F752140E1A6C35F
+:10A21000007009D800F0773000F0C791F63009D40B
+:10A22000389E007009D400F0603050D000F069070B
+:10A230000F6000F080120760389E6B070E6078B0E8
+:10A240007C71FE9F91B8723100F0C9D7662000F092
+:10A2500092B9F13000F08E91723000F000F066306B
+:10A2600008D000F06B070E60498269070F60389EC6
+:10A27000662000F000F07C71FE9FBE9F722000F00F
+:10A2800000F0F32000F08290713000F0C390F130C4
+:10A29000019400F0007009D000F0663008D000F0A2
+:10A2A000007008D000F0007000F000F0002076810F
+:10A2B00000F0007000F000F0003008D0389E01007F
+:10A2C00073A100F01110FE9700F0007008D000F0AC
+:10A2D000B807086000F0731580D200F00070AF80FE
+:10A2E00000F0AC15086000F0B31F80D2C0407207C8
+:10A2F000086000F07E07096000F00245F5AFB8077E
+:10A30000086068A100F0823000F00230FF7F00603A
+:10A31000A08C01606FA0409000706CA000F00070F5
+:10A32000A4A000400070008000F0C208026003900A
+:10A330007E070B6072070B6000E23B9EC308036060
+:10A340009008026000E29308036000E232348B0759
+:10A350000A60B334007000F000F02B3208D07207AE
+:10A360000B6001807E070B60008000F0A8070C6086
+:10A370004090BE150960789E35220F90709E9C70AB
+:10A380000E90689E9C700D9000F0007004904190BB
+:10A3900012400280819022400180C19032400080B2
+:10A3A0000082007008D092070860D4AF009094201B
+:10A3B00000F080900070039418830070F99BD082A5
+:10A3C0000070F99B00F00070F89BD382142046A126
+:10A3D00012810070028000F0932000F000F0122043
+:10A3E00000F02D88B33200F0EBC232300540333339
+:10A3F000A8070C6000F0B13100F04891C53608D0D4
+:10A4000072070B6001807E070B6000804790007030
+:10A4100000F07F9E104000E2779E204000E200F0B6
+:10A42000404000E200F0B22200F00588303200F037
+:10A43000AAC2007000F000F0323308D0B6070860FE
+:10A44000BDAF0090007000F010400040C0EB114024
+:10A450000140C0EB12400240C0EB00F000703A80B7
+:10A46000B6070860B7AF0090007000F010400040E1
+:10A47000C0EB01401140C0EB02401240C0EB00F0C5
+:10A4800000703480B6070860B1AF0090007000F033
+:10A4900010400040C0EB01400140C0EB12400240C0
+:10A4A000C0EB00F000702E80B6070860A98F9307FC
+:10A4B0000860AA8FA8070C6020A12124C415086099
+:10A4C0004440322000F04190C3261CA19B80012013
+:10A4D00009D000F0822000F0C982007000F09A825A
+:10A4E0000521029800F0007001984091007008D09A
+:10A4F0003C9F0C7100F000F0007009D000F00120CA
+:10A50000F88F1F08026009A000F021080360118283
+:10A51000007000F01982007001900082007009D470
+:10A5200000F0104008D0B5070860968FA8070C60AF
+:10A530000DA04082007000F000F0C03608D0A807DF
+:10A540000C600AA000F0C12607A10880007008D0A6
+:10A55000B50708608D8F8B070A6004A1A0230070E7
+:10A5600004A10090B52200F04190104009D44D8321
+:10A57000007001980090007009DC0082007008D023
+:10A5800000F00070FEA000F03020FC8000F00070B1
+:10A59000FCA000F03022FA8091070860838FAB079F
+:10A5A0000860808FAB070860818FAC0708607E8FE2
+:10A5B000AC0708607F8FAA0708607C8F04415709A9
+:10A5C00008600390007004A04440C20808604390F3
+:10A5D000007002A04440C6080860839000700080AC
+:10A5E00026CA0520EDA075C3007000F0C39000706E
+:10A5F00000F065C50070C0E000F0053008D0A80785
+:10A600000C60E8A000F0C03708D0A8070C60E7A0F5
+:10A61000079000700CA000F000700280A8070C608A
+:10A62000E4A00790C02600F0C791362200F000F0A9
+:10A63000312303903082007000F04090007040E1C0
+:10A6400000F0C03608D03080007000F04182007009
+:10A6500000F00082007040E100F0C03608D0A8078A
+:10A660000C60D9A000F0362200F000F0C22600F005
+:10A670003488007000F0A0C2312300F082820070A4
+:10A6800000F0FD9F007001903080007040E0458236
+:10A69000007000F04090007040E100F0C03608D03B
+:10A6A00000F0B81709600790007000F0D217096039
+:10A6B00000E6A0419E07086000F00070558F00F092
+:10A6C000B81708600790007000F0D217086000E625
+:10A6D000A0419E07096000F0007050AF00F00070CC
+:10A6E00078A200F0007096808D0708604B8FB0074D
+:10A6F000086048AF8E070860498F00F0007008D0EE
+:10A7000000F0B807086000F08B070A6000F0022034
+:10A7100000F0A1246A15006082906A1580D0A80715
+:10A720000C60B9A000F0007005A100F00070EFA26D
+:10A7300000F0F71E80D700F0D11E80D700F0007027
+:10A74000EEA0E01B00607980A8070C60B2A000F0CA
+:10A750000070CAA000F0007009D000F00070F4A0F2
+:10A76000E51B00607480A8070C60ADA000F00070CD
+:10A77000C5A000F0007009D000F0007024A1F31B08
+:10A7800000606FA000F00070DBA100F0B80A80D07C
+:10A79000A8070C60A6A000F0D91B0160FF7F006035
+:10A7A000ADAFA08C0060AAAF0082513089A200F04A
+:10A7B000A02183A200F0B80A80D0A8070C609FA057
+:10A7C00000F00070B7A000F0007009D000F0007039
+:10A7D00056A100900C1C006000F0791580D5FA1B82
+:10A7E00000605F80A8070C6098A000F00070B0A027
+:10A7F00000F0007009D000F000706EA13A9E0C1CB1
+:10A80000006000F0791580D18A90031C0060FA1B6B
+:10A81000006000E200F000705680A8070C608FA076
+:10A8200000F00070A7A000F0007009D000F00070E8
+:10A8300097A13A9E0C1C006000F0791580D18A9097
+:10A84000FA1B0060031C006000E200F000704D8005
+:10A85000A8070C6086A000F0A22284A050D400704B
+:10A8600000F000F00070019400F0007003800C1CF8
+:10A870000260C3A281900070049400F00070D8A21E
+:10A88000411C0160B4A200F000700194181C01602A
+:10A89000AAA14090791580D0A8070C607AA000F09A
+:10A8A000007092A000F0007009D000F00070D1A1FB
+:10A8B00000F00070FEA100F00070B0A100F0007088
+:10A8C0000080A8070C6073A000F0921C006000F0EC
+:10A8D000791580D200F00070B6A200F0007042A09E
+:10A8E00000F0B10A80D0A8070C606DA000F0B22380
+:10A8F00000F000F06A150360BA9E2C1C016000F0A5
+:10A900000070019000F0533008D000F051301182F7
+:10A91000A8070C6066A000F000707EA000F0007038
+:10A9200009D000F00070DFA100F00070BCB500F0AD
+:10A930000070069000F000709BA100F0B80A80D271
+:10A940003A1C016000F042463A1C006000F07915A4
+:10A9500080D200F0223508D000F06A15006000F0C7
+:10A96000791580D0A8070C6058A04446202556A031
+:10A97000389E6A15056000F0203509D400F02435B2
+:10A98000F6A100F0007009D44091791580D0A80795
+:10A990000C6051A01F1C01604FA000F051303EA27E
+:10A9A0001040007035A200F0007043826A15036009
+:10A9B00074A200F0533009D000F000704AA000F0FB
+:10A9C000362548A08E91007000F03635B70A80D049
+:10A9D000A8070C6046A000F0007070A2501C006038
+:10A9E00000F0498200700980A8070C6042A000F0C6
+:10A9F000007069A200F00070F99700F00070CB8F32
+:10AA0000A8070C603EA000F0212607A2439000702A
+:10AA100009D400F03F1E80D7A025791580D000F022
+:10AA2000007000F0A035541C00602136791580D2EA
+:10AA300000F00070F88FEC1B01600E80A8070C601E
+:10AA400034A000F000706EA200F00070029400F0DC
+:10AA5000007067A200F00070E9970082007016A2F3
+:10AA6000F31B0160D9A100F000700680A8070C60FC
+:10AA70002CA0251C016000F0461C026060A28190A1
+:10AA80004446C0E0A134B80708602435731580D06F
+:10AA900000F0007000F04090791580D0A8070C609D
+:10AAA00024A000F0A02105A200F000703EA0721CBE
+:10AAB0000060E78FA8070C6020A000F0007038A0AD
+:10AAC00000F0007009D000F000703EA000F00070AF
+:10AAD000029400F0007048A0811C0060E08FA8077D
+:10AAE0000C6019A000F0007031A000F0007009D0D7
+:10AAF00000F0007037A000F00070119000F00070BE
+:10AB00003AA000F000700F94791C0060D88FA8075D
+:10AB10000C6011A000F0007029A000F0007009D0B6
+:10AB200000F000703CA000F00070019400F0007094
+:10AB30000880A8070C600BA000F0007023A000F0B4
+:10AB4000007009D000F0007036A000F00070039093
+:10AB500000F0007039A000F000700194871C0060C4
+:10AB6000CA8F00F0921C006000F0791580D200F0CE
+:10AB7000B10A80D000F0007008D08B070A60FEAFE9
+:10AB800000F02B22FD8F40C00220FCAF09CA0070EC
+:10AB900000F08AC2007000F082C4007000F000F083
+:10ABA000023008D011208B070A6000F0902000F0DE
+:10ABB0000AD20070254092D7007000F0A8A0007063
+:10ABC00000F003D3007000F01BD7007000F00CD62B
+:10ABD00000200560E3801B4301609BD8202300F028
+:10ABE000E9A0007000F0CBA200020560C3A2004003
+:10ABF0000660E9A0800007608AA2007000F082A2CF
+:10AC00000070154052DF007000F0A9A0007008D05D
+:10AC100044080960E5AF00F09021E4AF00900070B7
+:10AC200008D00000006000F04E090860E1AF00F0BD
+:10AC3000803B28C000F0007000F02140007008D078
+:10AC400000F04408096000F00070E4AF00F07023E9
+:10AC5000016080A8007000F0088E007008D04709DD
+:10AC60000860D8AF00F00020D7AF82D4007000F0A9
+:10AC7000025C0254C0E22140007000F010C4007079
+:10AC800000F050D4003008D0FF030060EF8F00F0D8
+:10AC90004408096000F00070D7AF00F0801C01602C
+:10ACA00080A8007000F0408E007008D0470908604E
+:10ACB000CBAF00F00020CAAF02D5007000F0025305
+:10ACC0000251C0E22140007000F010C4007000F09A
+:10ACD000D0D4003008D000824E0908601A9244088F
+:10ACE000096000F082300FC000F0007000F000F04A
+:10ACF00002300FC000F0007000F03C92212000F004
+:10AD000000F0043C00F000F0813B28C000F000702F
+:10AD100000F01190007008D000F04408096000F0C5
+:10AD2000A8070C604E090860BFAF85AAA12000F0FB
+:10AD30002340453A00F000F0813B28C000F000704D
+:10AD400000F0C190007008D000F0C02600F000F0C4
+:10AD5000312000F000F0422700F0088000707640BB
+:10AD60001080D0150D60C032DA150E6054000070EE
+:10AD700000F06500007000F02482007000F000F028
+:10AD8000C539019C8E910070FB8FC634D5150D60BE
+:10AD900000F00070B64054000070A4AF2482007030
+:10ADA00000F000F00070019CBE9F0070FC8FDB8201
+:10ADB000463500F0C0226A18066000F0007000F00E
+:10ADC00030A0007000F083A8412700F0DBD70070AE
+:10ADD00000F084A9433C00F024D2C22700F008828E
+:10ADE000C43B00F030B0C22700F0A3B8007000F000
+:10ADF000A4B9007000F08090007000F000F00070C6
+:10AE0000049824830070019063B80070028083B8B6
+:10AE1000007000F084B9007000F0DBD7007000F023
+:10AE200024D2433D00F070B0C43C00F094BA0070EE
+:10AE300000F08090007000F000F00070029874BA8A
+:10AE40000070019054BA007000F053AAC43D00F0A5
+:10AE500000F0433B08D000F044080960A8070C60EC
+:10AE600084AF4E0908608AAF83AA007000F000F03A
+:10AE7000C33A00F000F0C52900F000F0432A00F0CA
+:10AE800000F0C42A00F0E8A0007000F013AA0070DF
+:10AE900000F028A1007000F014AA007000F000F08B
+:10AEA000452B00F000F0007000F068A1007000F089
+:10AEB00005AA007000F0D8A0007000F013AA00707E
+:10AEC00000F020A140080D6014AA0209026000F001
+:10AED000533000F000F0D53000F000F0D23112C055
+:10AEE00000F0007000F000F0502100F000F054304D
+:10AEF00000F000F0D53000F000F0D23112C000F0C8
+:10AF0000007000F000F0512100F000F0232000F06C
+:10AF100000F0A42000F000F0007000F01A83007030
+:10AF200000F012D1007000F05BD0007000F064D02F
+:10AF3000007000F0C8A0007000F002A1007000F0E6
+:10AF400043AA007000F09B80007000F040D00070B9
+:10AF500000F049D0007000F04482007000F05430DE
+:10AF60000209026000F0D33000F000F0D23112C0CC
+:10AF700000F0007000F000F0502100F000F04625D5
+:10AF8000F74000D7C52400F000F0C73300F000F010
+:10AF9000403300F0DB82A03600F000F0233700F0F1
+:10AFA00000F0A33700F000F086300FC000F0007012
+:10AFB00000F000F005300FC000F0007000F081409C
+:10AFC000073C00F000F0803B28C000F0007000F06B
+:10AFD0000082007008D000F04408096000F04E09BB
+:10AFE0000860A8070C6043AF00F0007049AF00F0A4
+:10AFF000402C00F000F0C12B00F03AA0B52000F08A
+:10B0000072A0C72700F004A800702340ADD74623E4
+:10B01000049C84AAFFFF00602C81007000F000F007
+:10B020004030049C00F00070078084AA007010403B
+:10B030002C83007000F000F04030049CC791007039
+:10B0400000F00342007040E18340007040E000F0F7
+:10B05000104007808681007021400082463300F056
+:10B0600000F027272DAFCF91007000F000F02737B8
+:10B0700000F000F0863B28C000F0007000F062AAEB
+:10B08000007000F01289007000F0423F007008D09C
+:10B0900000F044080960A8070C6025AF00F00070BC
+:10B0A0002BAFB3204E09086080AA412B00F01BD7BC
+:10B0B000422F00F00C82007000F02489007000F034
+:10B0C000A782007000F000F04520149800F0007096
+:10B0D00013901F830070154000F00070049800F07A
+:10B0E000007003904782007000F0759F0070C0E10F
+:10B0F00000F0007002809282443F00F08890C03FD0
+:10B1000008D000F0462300F000F0453000F000F0D9
+:10B11000C03F00F0AE81443F00F000F0463300F045
+:10B1200000F027270DAFCF91007000F000F0273717
+:10B1300000F000F0863B28C000F0007000F00082B4
+:10B14000214008D000F0C72F00F045910070114059
+:10B15000C6830070029C0140007040E100F0007066
+:10B16000018001400070C0E100F0462300F000F0D3
+:10B17000C72300F000F0C13000F0AE83C03F00F004
+:10B180000082443F00F0EF81463300F000F0C73307
+:10B1900000F000F0073C00F000F02727F9AECF9157
+:10B1A000007000F000F0273700F000F0863B28C068
+:10B1B00000F0007000F0389E214008D000F04408F4
+:10B1C0000960A8070C60F3AE00F00070F9AE412BE7
+:10B1D0004E09086080AAC22300F000F02727EEAED7
+:10B1E000CF91007000F000F0273700F00C82B32000
+:10B1F00000F02489C03F00F01BD7443F00F01F83BC
+:10B20000007000F000F00070D29B00F00070D1934D
+:10B210008790C62000F08F980070029000F00070B8
+:10B22000019C00F045200D80BE9F007000F0FF8360
+:10B230004520CB93FE93412300F04591C63300F0A7
+:10B24000719C063C40E16990007000F000F04133D1
+:10B2500000F000F0A627DAAE8E91007000F000F04A
+:10B26000A63700F000F0813B28C000F0007000F02D
+:10B27000F89F214008D02140C623D4AEAE81007093
+:10B2800000F000F0C63300F00082063C08D02040F9
+:10B29000C727D0AEC791440809603090004240EA09
+:10B2A00000F0007000F01031007008D0A8070C60AA
+:10B2B000CCAEC02B00400660412C8000076030B04F
+:10B2C000007000F079B0007000F072BA46250FA04F
+:10B2D00000F0C33100F000F0423208D000F00070FE
+:10B2E000FCA000F00070019000F00070E18000F020
+:10B2F0004408096000F00070C7AE00F0C12700F0FC
+:10B3000092AA007000F04190007000F052AA007004
+:10B3100040E172AA007040E000F0462502A000F073
+:10B32000C33100F000F0423208D000F040080D6058
+:10B3300000F02823006052300209076000F0D0308E
+:10B3400000F0D731DF150F60899F007085C87C70D1
+:10B350007020C0E2799E007000F080A0007000F0C4
+:10B3600023AA007000F036D2007005C000F0004043
+:10B37000046037A3512100F03FD1FF7F066078B011
+:10B38000007000F022BA007000F08291007040E17D
+:10B3900000F0007008D000F04408096000F0007070
+:10B3A000ABAE82AA402D00F093A9007000F052D0FD
+:10B3B00000400660D2D7800007601BD2C12C04A0D9
+:10B3C0001489362500F03D83403100F08E910070E5
+:10B3D00009D83635B70A80D0B8B0442500F0F1B0AE
+:10B3E000007000F03AB0433E00F072B0C23E00F090
+:10B3F00082BA0070CEA000F0007008904340A422F2
+:10B4000093AE1CC3C52D00F0206E046000E23E67C1
+:10B41000046000E600F0372100F0A0A0007000F00A
+:10B4200040AA007000F0AA82007008D0E4D1007039
+:10B4300000F0A0B040080D6081B80209076053A871
+:10B44000D13000F000F0533000F000F0D73100F0C0
+:10B45000C32D007011C000F0372100F09A825021F6
+:10B46000838E00F04408096000F0007089AE00F09F
+:10B47000C22E00F000F0432E00F0BAA0007000F0E1
+:10B48000F2A0FCFF046080AAB72500F000890070DC
+:10B4900000F020C2007000F000F0007009D0CF91E1
+:10B4A000007000F00090B73508D0A8070C6077AEA8
+:10B4B00000F0BE2400F000F0402174AE00F06030D7
+:10B4C00008D00490007024A00390C02272AE429075
+:10B4D000412700F020806A1805600882007000F0A3
+:10B4E00028B0007000F0A0B8007000F0A1B90070A2
+:10B4F00000F0C0D794080860D0A1007000F099A1B6
+:10B50000007000F009D20070CDAF00F0003008D01C
+:10B510009108086065AE0120FE7F02600090007017
+:10B5200000F003581340C0E251C2007000F059C44B
+:10B53000007000F000F0013008D0E40808605EAE52
+:10B5400000F0003008D00082BE2400F000F042215C
+:10B5500000F000F061205AAE8F82007000F000F021
+:10B56000007009D0799E007001985190007000F031
+:10B570000890613008D00342007001808340007061
+:10B5800000804408096052AE1331007008D0A8074B
+:10B590000C6050AE412D800007600654C02C4E8ECA
+:10B5A000A8070C604DAEC12E800007600654402EE7
+:10B5B0004B8EA8070C604BAE00F04E090860FF03ED
+:10B5C000016000F000F0C22400F000F0432500F01C
+:10B5D00000F0442300F000F0C52300F000F0813BB0
+:10B5E00028C000F0007000F000F083300FC000F0C1
+:10B5F000007000F000F002300FC000F0007000F0AA
+:10B60000C1254B09096042264C090A6000F011303F
+:10B6100000F000F0223000F000F0843B00F000F079
+:10B62000053C28C000F0007000F000F0402419A094
+:10B6300000F00070BE8F1240007011A000F04409AD
+:10B640000D6000F047090E6080FF04600ACBF647EA
+:10B65000522030AE92D3452400F052D0632008909F
+:10B6600000F0024002947D9F007000F0558D007044
+:10B6700002804D91007000F0758B007000F0E3C205
+:10B68000453400F0EBC4007000F000F0633026AEEB
+:10B6900000F0532000F09282007001A09BD3007054
+:10B6A00008D000F043090E60BFFF056000F092D1A2
+:10B6B000642020AE2CC3007000F014C5007000F0B0
+:10B6C00000F0643008D047090E601CAE02486120CB
+:10B6D0001BAE51C2007000F041C4403400F000F0D5
+:10B6E000613008D04309086017AE012047FF0260AF
+:10B6F00000F0007000F051C2007000F00090007087
+:10B7000000F012CA0070019051C4007000F000F007
+:10B71000013008D02021F6280160C2224B090860C0
+:10B7200008A04C090960B0AB423600F000F0C0350B
+:10B7300000F000F0003000F000F0123008D0C0221D
+:10B740006A18026000F0007000F010A0007000F0B5
+:10B75000A3A8007000F0A2A9007000F0DBD7007071
+:10B7600000F012D2C33E00F000F0423E00F000F0C4
+:10B77000007039A000F000701694C02240080860E4
+:10B78000015202090260C0D0007000F00030E915DB
+:10B790000D608130E4150E608231007000F000F021
+:10B7A000412512C000F0422700F009D2032100F029
+:10B7B00050A0007000F0F1AAB82400F059A2422570
+:10B7C00000F000F0413100F08A9E013000F000F0FE
+:10B7D000670000F0BA9E510000F000F00070FD9F7D
+:10B7E000C9A2C02200F049D0007000F038A000705B
+:10B7F00000F073AA413200F000F0C33108D043409A
+:10B80000A022E8AD18C2412700F00554006000E214
+:10B81000C44E006000E600F0007000F008A0B824FC
+:10B8200000F0B0AA007000F000F0403100F000F02D
+:10B83000003000804340A022DFAD18C2007000F04D
+:10B8400000F0007002906D71006000F0B19E036026
+:10B850000280FD78006000F0C694036000F000F004
+:10B86000403200F000F0C33108D044090860D6AD82
+:10B87000C2400120D5AD51C2007008D000F0432372
+:10B88000FCAF48D34E09086048D700400394FF033B
+:10B89000026009D0CB90007000F0D38A0070028063
+:10B8A000FB9E007000F01B8C0070008000F0833B5A
+:10B8B00028C000F0007000F000F0433308D000F022
+:10B8C000A022C8ADC0D3007008D08B070A60C6ADF7
+:10B8D0002140A322C5ADC9C2007008D08B070A6001
+:10B8E000C3AD00F0A022C2AD40D4007008D0A008C3
+:10B8F0000860C0AD33430220BFAD9AC4007000F0B1
+:10B9000000F0023008D0A0080860BCAD414400201F
+:10B91000BBAD08C2007000F00882007008D0C344BC
+:10B92000A0080860A122FF7F04601040022000F000
+:10B9300061C2007000F09AC2007000F043C224405F
+:10B9400000F082C44540C0E063C2004100F06BC219
+:10B95000A132F29340D0007040E082C40070F08FBA
+:10B960008B070A60ECAFC24FA322ACADD3C200700C
+:10B9700000F049D0025800F008C4007000F010C474
+:10B98000007000F0C3C4007000F000F0A33208D0D3
+:10B990001440A322A5ADE0C2007000F064D0007096
+:10B9A0008BAFE0C2A108096000F000700194004074
+:10B9B000007003804040007004A0C0C2007000F01E
+:10B9C00030402040C0E200F0007000F000F0103085
+:10B9D00008D08240A3229AADD4C2B74F00F00241F2
+:10B9E00040060460FBC24640029400F0C52296ADBA
+:10B9F000658FA1220180D2C2A12200F0F3C40258B7
+:10BA0000C0E059C6007000F0D3C40070C0E000F080
+:10BA1000A33208D00082BA070860C1070E6016C0C2
+:10BA200000104D060160001085020260613DCD0CE2
+:10BA30000360E230CD0C0460633E02000560E43137
+:10BA400003000660E53F007000F06633007008D028
+:10BA50004190C107096000F0E801086092829137C7
+:10BA60003E9400F0023400F08234AD02086000F031
+:10BA70009902026000F09A0203600232A2020260A0
+:10BA80008332A30203600230AB0202608330AC0257
+:10BA900003600231007000F08331007008D0FF8332
+:10BAA000BA0709604190C10708609733171340E651
+:10BAB00000F0923000F000F0933100F000F014300C
+:10BAC00000F000F0153200F000F096324B80C10714
+:10BAD000096050A000F094274FA00491913F00F01E
+:10BAE00000F0123309D000F000702780C107086011
+:10BAF0004BA000F00037448000F0C1070E6000F05A
+:10BB0000BA4D0960E72740080D60E52C2105086063
+:10BB1000C791593000F000F0553109D0FF9FD8315E
+:10BB200000F0632DE32DC0E2E4206421C0E25B81DC
+:10BB3000672000F0EEC6593000F0AEC3573100F078
+:10BB400076D4E33C00F0E481E52200F0E4C7643001
+:10BB500000F0E7C3642600F07FD4E32600F000F095
+:10BB6000E73600F07D9FE52100F09CD3007040E0B7
+:10BB700028A1672200F02CA5E32500F03C81652E6A
+:10BB800000F0E384E43400F000F0633500F000F0EE
+:10BB9000D83100F000F0642F00F000F0D32000F066
+:10BBA0003C9FE72500F0B3D3E62E40E0E8A06734E1
+:10BBB00000F0EBA4007000F0F38000700DC000F006
+:10BBC000007000F000F0D42000F000F0E33500F049
+:10BBD00000F0643608D000F0962F00F000F0C707A0
+:10BBE00005608691AD020860728100700594A20222
+:10BBF000046000F09902026000F00430AB020460BF
+:10BC000000F0023200F000F00431038000F0023254
+:10BC100000F000F0023000F000F0023100F000F01F
+:10BC2000162318A08691007000F0738100700594AF
+:10BC3000A302046000F09A02036000F08430AC02BA
+:10BC4000046000F0833200F000F08431038000F0E3
+:10BC5000833200F000F0833000F000F0833100F018
+:10BC6000952FC707036000F0E8010C60EA800070C0
+:10BC700000F04591007000F086914534019000F08D
+:10BC8000423400F0F280C63409D000F0C23408D04B
+:10BC9000C107086005A000F0012D00F000F00227A8
+:10BCA00003A053A2812002A053A2833D00F000F024
+:10BCB000033108D000F0007008D00054D6070A60A5
+:10BCC0001140EE15086000F0A03000F000F02130C7
+:10BCD00000F000F0090000F000F000008DC800F056
+:10BCE000090000F01030000000F000F0007008D0F3
+:10BCF0000240DB070960A342D6070A601230FFFF4B
+:10BD0000046000F0A331454100F02431005800F0F8
+:10BD10002532F28F00F0007008D00082D207086050
+:10BD200000F03AE4016005200DB602608620285F2D
+:10BD300003604DC791C7046096C7052140E0862186
+:10BD4000DB070B605DC7003040E0A6C7003140E074
+:10BD500008900070C0E000F0B03008D000F0D207CA
+:10BD6000086000F03AE4016000F00DB602600130B6
+:10BD7000285F0360823091C704600331007000F0D7
+:10BD80008431007008D0D6070960ECAF00F01030A5
+:10BD900008D0D6070960EAAF00F0103108D0D60706
+:10BDA0000960E8AF00F0142100F000F09220035C7D
+:10BDB00020C2112000F0D3C2100908604190007029
+:10BDC00009D482C40070059000F0923008D0D607E4
+:10BDD0000960E0AF4982902000F0913010090860BE
+:10BDE0001130007000F000F0003008D01009086039
+:10BDF000DBAF00F0003008D0F441030000F000F0A9
+:10BE0000D1070F60E0C2090000F0DBD67830039064
+:10BE100000F0010000F0389E783000F000F01110C2
+:10BE2000FD97E0C2034000F0389E007009D0389EB4
+:10BE30001310FF9700F0007008D000F0020000F02F
+:10BE400000F00070F3AF00F07120CCAF51820070B1
+:10BE500000F000F00070FC9B00F0007008D0D607E6
+:10BE60000F60C8AF0082F721028000F0007009D88F
+:10BE700000F0007000F200F0007001A0FF9F007061
+:10BE8000FC8F00F0D607086000F06408096000F03D
+:10BE90000022C0AF00F0103008D0104064080960E4
+:10BEA00000F0007000F000F01030BCAF00F0007047
+:10BEB00000F200F0007000F200F0007008D024835F
+:10BEC000590908604190FF0F05605B9A06200398AE
+:10BED0004B98045200EEAEC3045100EE48090960CD
+:10BEE00003805B94480909607396045400EAAEC36A
+:10BEF000045800EA00F04A290360A6C511208440D6
+:10BF00009BA20630F0401C81FFF00660048B0440C9
+:10BF1000C0EB71C2007000F024D2007000F061C468
+:0ABF2000007000F000F0113008D0AE
+:00000001FF
diff --git a/firmware/R2c_SoC2v01_EXT_src_coeff_1.1.fw.ihex b/firmware/R2c_SoC2v01_EXT_src_coeff_1.1.fw.ihex
new file mode 100644
index 00000000000..7f1def62dd5
--- /dev/null
+++ b/firmware/R2c_SoC2v01_EXT_src_coeff_1.1.fw.ihex
@@ -0,0 +1,130 @@
+:10000000070046B304080000F9FFFCFF2A007E0049
+:10001000A1004400B3FFA3FF34008600FAFF55FFA0
+:10002000BEFFBB00A20059FFF0FE610079011F0076
+:100030003AFE27FFDA01C30167FE38FDE600C6037A
+:1000400053006EFBDAFDF304A3045FFB11F82803F1
+:10005000730C790032ECCCF51529A45CA45C15294D
+:10006000CCF532EC7900730C280311F85FFBA30484
+:10007000F304DAFD6EFB5300C603E60038FD67FEAD
+:10008000C301DA0127FF3AFE1F0079016100F0FE8B
+:1000900059FFA200BB00BEFF55FFFAFF86003400E7
+:1000A000A3FFB3FF4400A1007E002A00FCFFF9FF7C
+:1000B0000000000000000000000000000000000040
+:1000C0000000000000000000000000000000000030
+:1000D0000000000000000000000000000000000020
+:1000E0000000000000000000000000000000000010
+:1000F0000000000000000000000000000000000000
+:1001000000000000000000000000000000000000EF
+:1001100000000000000000000000000000000000DF
+:1001200000000000000000000000000000000000CF
+:1001300000000000000000000000000000000000BF
+:1001400000000000000000000000000000000000AF
+:10015000000000000000000000000000000000009F
+:10016000000000000000000000000000000000008F
+:10017000000000000000000000000000000000007F
+:10018000000000000000000000000000000000006F
+:10019000000000000000000000000000000000005F
+:1001A000000000000000000000000000000000004F
+:1001B000000000000000000000000000000000003F
+:1001C000000000000000000000000000000000002F
+:1001D000000000000000000000000000000000001F
+:1001E000000000000000000000000000000000000F
+:1001F00000000000000000000000000000000000FF
+:1002000000000000000000000000000000000000EE
+:1002100000000000000000000000000000000000DE
+:1002200000000000000000000000000000000000CE
+:1002300000000000000000000000000000000000BE
+:1002400000000000000000000000000000000000AE
+:10025000000000000000000000000000000000009E
+:10026000000000000000000000000000000000008E
+:10027000000000000000000000000000000000007E
+:10028000000000000000000000000000000000006E
+:10029000000000000000000000000000000000005E
+:1002A000000000000000000000000000000000004E
+:1002B000000000000000000000000000000000003E
+:1002C000000000000000000000000000000000002E
+:1002D000000000000000000000000000000000001E
+:1002E000000000000000000000000000000000000E
+:1002F00000000000000000000000000000000000FE
+:1003000000000000000000000000000000000000ED
+:1003100000000000000000000000000000000000DD
+:1003200000000000000000000000000000000000CD
+:1003300000000000000000000000000000000000BD
+:1003400000000000000000000000000000000000AD
+:10035000000000000000000000000000000000009D
+:10036000000000000000000000000000000000008D
+:10037000000000000000000000000000000000007D
+:10038000000000000000000000000000000000006D
+:10039000000000000000000000000000000000005D
+:1003A000000000000000000000000000000000004D
+:1003B000000000000000000000000000000000003D
+:1003C000000000000000000000000000000000002D
+:1003D000000000000000000000000000000000001D
+:1003E000000000000000000000000000000000000D
+:1003F00000000000000000000000000000000000FD
+:1004000000000000000000001100060007000900C5
+:100410000A000C000D000F00110013001500180059
+:100420001B001D002000240027002B002F0033009C
+:1004300037003C00410046004C00510057005D0071
+:1004400064006A0071007800800087008F009700C8
+:10045000A000A800B100BA00C300CC00D500DE00A7
+:10046000E800F100FB0005010E01180121012A013D
+:1004700033013C0145014E0156015E0165016C01ED
+:10048000730179017E01830187018B018D018F0149
+:10049000900190018F018D01890185017F01790112
+:1004A000700167015C014F014101310120010D0123
+:1004B000F800E200CA00AF00930075005500340058
+:1004C0001000EAFFC2FF98FF6CFF3EFF0FFFDDFE4A
+:1004D000A9FE73FE3BFE02FEC6FD89FD4AFD09FD35
+:1004E000C6FC82FC3DFCF6FBAEFB65FB1AFBCFFABB
+:1004F00083FA36FAE8F99BF94CF9FEF8B0F861F89E
+:1005000014F8C6F77AF72EF7E4F69BF653F60DF6D5
+:10051000CAF588F549F50DF5D3F49DF46AF43BF47A
+:100520000FF4E8F3C5F3A7F38EF37AF36BF363F3F9
+:100530005FF363F36CF37CF393F3B1F3D7F304F459
+:1005400039F476F4BBF408F55EF5BDF524F695F6BE
+:100550000FF793F71FF8B6F856F900FAB4FA71FBE3
+:1005600039FC0BFDE7FDCDFEBDFFB700BB01C902A5
+:10057000E10302052E066207A108E809390B930C76
+:10058000F50D600FD3104E12D1135B15ED168518C3
+:10059000241AC91B741D241FDA2094225224142605
+:1005A000DA27A3296E2B3B2D092FD930A9327A34B3
+:1005B0004A361938E739B23B7C3D423F0541C342D8
+:1005C0007E443346E2478C492F4BCA4C5E4EEA4F7D
+:1005D0006D51E8525854BF551B576C58B259EC5ADC
+:1005E0001A5C3B5D505E575F50603C611962E86287
+:1005F000A7635864FA648C650E668066E2663467A9
+:100600007667A867C967D967D967C967A867766732
+:100610003467E26680660E668C65FA645864A76388
+:10062000E86219623C615060575F505E3B5D1A5C46
+:10063000EC5AB2596C581B57BF555854E8526D517B
+:10064000EA4F5E4ECA4C2F4B8C49E24733467E44FC
+:10065000C3420541423F7C3DB23BE73919384A3637
+:100660007A34A932D930092F3B2D6E2BA329DA27F2
+:10067000142652249422DA20241F741DC91B241A24
+:100680008518ED165B15D1134E12D310600FF50DC2
+:10069000930C390BE809A10862072E060205E10355
+:1006A000C902BB01B700BDFFCDFEE7FD0BFD39FC64
+:1006B00071FBB4FA00FA56F9B6F81FF893F70FF782
+:1006C00095F624F6BDF55EF508F5BBF476F439F43D
+:1006D00004F4D7F3B1F393F37CF36CF363F35FF3B8
+:1006E00063F36BF37AF38EF3A7F3C5F3E8F30FF438
+:1006F0003BF46AF49DF4D3F40DF549F588F5CAF599
+:100700000DF653F69BF6E4F62EF77AF7C6F714F8D3
+:1007100061F8B0F8FEF84CF99BF9E8F936FA83FA7B
+:10072000CFFA1AFB65FBAEFBF6FB3DFC82FCC6FC78
+:1007300009FD4AFD89FDC6FD02FE3BFE73FEA9FED2
+:10074000DDFE0FFF3EFF6CFF98FFC2FFEAFF1000C7
+:100750003400550075009300AF00CA00E200F800B5
+:100760000D012001310141014F015C016701700160
+:1007700079017F01850189018D018F01900190012F
+:100780008F018D018B01870183017E017901730146
+:100790006C0165015E0156014E0145013C013301CA
+:1007A0002A01210118010E010501FB00F100E800FA
+:1007B000DE00D500CC00C300BA00B100A800A00044
+:1007C00097008F0087008000780071006A00640045
+:1007D0005D00570051004C00460041003C003700CE
+:1007E00033002F002B002700240020001D001B00D9
+:1007F00018001500130011000F000D000C000A0076
+:080800000900070006001100C9
+:00000001FF
diff --git a/firmware/STLC2600_R6_03_01.fw.ihex b/firmware/STLC2600_R6_03_01.fw.ihex
new file mode 100644
index 00000000000..25bebbb4949
--- /dev/null
+++ b/firmware/STLC2600_R6_03_01.fw.ihex
@@ -0,0 +1,29 @@
+:10000000010002B401080A0306000000000000001D
+:100010000002081E1E020C0A1B01015F12040003ED
+:10002000000300FD007A5601007B5B05007B556FE5
+:1000300016050004000400FA007A55FE007B5A02FF
+:10004000007B550600278A070102210401003002C7
+:100050002F0104380201743A01003B01473C0C02B5
+:10006000DB0B301F54000000000B4340010841012E
+:100070003146023D004C02F707600103620A00BFEF
+:1000800066EBFFAAA50A00006701406E01017A0233
+:1000900080788108FFEE8DFE9BEF798383010185D7
+:1000A0007A3C00135219701B001C542770335334D0
+:1000B000623A304700576259885A285B0C5E826169
+:1000C0006062686425658066AA67C96822693C6ABF
+:1000D000CA6C056DFF7E01F7207FC03CA04F6754BE
+:1000E00076419183019A03736860D18C0390649187
+:1000F0000492061F2256019375AC3FE612E812EAFD
+:1001000013EC13EE52F012F252AD813D87430044DE
+:100110002442148F20958696ADAE8086803F007471
+:1001200080758D77501E101760FF66B33BB53BB7E7
+:1001300053B95BBB43BD4BBF4BC153C353C55BC737
+:100140005BC963CB63CD6BCF6BD173D373D57BD7D7
+:10015000E3D9E3DBEBDD63DF63E153E353E55BE727
+:1001600063E9EBEBFBED7BEFEBF1FBB415B655B8B8
+:1001700057BA17BC55BE15C055C215C455C615C8CB
+:1001800055CA15CC55CE15D055D215D455D615D83F
+:1001900015DA55DC55DE13E053E212E45294010AFD
+:1001A0009501149601149701089801089B02360CDA
+:0401B000AE0102FF9B
+:00000001FF
diff --git a/firmware/STLC2600_R6_04_02.fw.ihex b/firmware/STLC2600_R6_04_02.fw.ihex
new file mode 100644
index 00000000000..13d12df5624
--- /dev/null
+++ b/firmware/STLC2600_R6_04_02.fw.ihex
@@ -0,0 +1,28 @@
+:10000000010002A801DC0A04060000000000000054
+:100010000002081E1A020C0A1B01015F12040003F1
+:10002000000300FF00781F0400F05809002F826FC2
+:1000300012040000000300FC005B1F0100FB5C06D3
+:10004000002F8A2004D3BF7D0021643100300213C9
+:100050005219701B001C542770335334623A3047D6
+:1000600000576259885A285B0C5E8261606268643E
+:1000700025658066AA67C96822693C6ACA6C056DF5
+:10008000FF7E09F7207FC03CA04F675476419183E3
+:10009000039A03736860D18C039064910492061FE5
+:1000A00022560193753D814300440042008F202F6A
+:1000B0000104380201743A01003C0C02DB0B3001F0
+:1000C00054000000000B4341013146023D004C0248
+:1000D00017064D024A00600103620A00FF66EBFE4C
+:1000E000AAA50A00006701018108FFEE8DFE9BEFC3
+:1000F000798383010185522800AE807480758D80DC
+:100100000896B09700AD83FF66B35BB55BB763B984
+:1001100063BB6BBD6BBF73C17BC3E3C5EBC7EBC9EF
+:10012000F3CBF3CDFBCFFBD1F3D3F3D5FBD7F3D98F
+:10013000F3DBFBDDF3DFEBE1F3E3EBE5FBE7F3E917
+:10014000FBEBF3EDE3EF7BF1FB86462200B41FB639
+:100150005FB81FBA5FBC1FBE5FC05FC21FC41FC6AF
+:100160001FC85FCA5FCC5ECE5ED01DD25CD41BD6EA
+:100170001BD85ADA19DC19DE18E057E257E456E6C4
+:1001800016E815EA55EC14EE53F052F2521E4A9B53
+:10019000088A018094010C95010E96010E980108C1
+:0801A0009B02360CAE0103FFC7
+:00000001FF
diff --git a/firmware/STLC2690_R6_03_A1_E5.fw.ihex b/firmware/STLC2690_R6_03_A1_E5.fw.ihex
new file mode 100644
index 00000000000..23603e2701e
--- /dev/null
+++ b/firmware/STLC2690_R6_03_A1_E5.fw.ihex
@@ -0,0 +1,386 @@
+:100000000000A0E10000A0E10C0000EB17130000CD
+:10001000110000EF8C17000020020000000000001B
+:1000200070000000200200003074000053544C4364
+:10003000323639302052362E3320202041312020D4
+:100040002030393032323030392030353A31393A97
+:1000500034384CE230209CE5010C12E334C09C158E
+:1000600000C08C0001C08CE00000A0E3000053E35E
+:100070000EF0A0D104008CE4043053005D753412FE
+:100080003EB504000D00684644F22AFB0A2228000F
+:10009000694601F08BFA28000A30FEA101F05EFAF1
+:1000A0001B2020703EBC08BC1847FF4810B50478E0
+:1000B00035F29DFC002C03D1FC4800684BF2DEFDBC
+:1000C00010BC08BC184710B50C0037F26FFBF8489D
+:1000D00000780128F4D02088401E2080F0E7F54900
+:1000E00010B50978012903D0F3490978002915D101
+:1000F000F2490978082911D3F14A0121117001014F
+:10010000F0480C18F049606809684BF2B8FD00200F
+:100110006060EE4800684BF2B1FDD1E737F219F8A4
+:10012000CEE7F3B5E54D0600287881B009281ED149
+:10013000E349E74C0120087021780820002900D00D
+:10014000481E20702078DF4FDF490001C019406849
+:1001500009684BF294FD217800200901C919486013
+:100160002878401E2870D94800684BF287FD029914
+:10017000300036F266FCFEBC08BC184770B4D54CA3
+:10018000D54D002001002B688200401C9950A042F0
+:10019000F9DB5B2300209B01BD2636012C68820021
+:1001A0001219D2181160401CB042F7DB0322002064
+:1001B000120315239B012E688400A419A418216042
+:1001C000401C9842F7DB70BC704738B5040008202B
+:1001D000FAF1A4FAC149C24D0090016029888180DA
+:1001E00006216846FAF1B6FABE490878022814D00A
+:1001F0000020C043BC4A28800220107000200870F4
+:10020000BA49BB4B0870FF20E279A1881B6879309E
+:100210004BF237FD38BC08BC1847200000F262FDE5
+:10022000F8E7FEB515001C00022B8C4615D288227B
+:100230004243B04B0021AE00D21897198B00D3185F
+:100240005B6F7E6BB34203D100234E009619F3839C
+:10025000491C0906090E0229F0D308A906C9230082
+:100260006C4606C42A0061460EF2B8FA83E710B560
+:10027000A14C2078002806D136F2EDFE01209F49DE
+:1002800020700020C8701BE7F8B50400007C0E0049
+:10029000A17B401C8006069F1D00000E002994468D
+:1002A00001D1800005E036235843C008012900D160
+:1002B0004008E17CA27C91420AD0824201D881426E
+:1002C00004D2814201D2080000E01000A074E07462
+:1002D0002B00310020006246009735F240FC388840
+:1002E00029784843E17A40183080F8BC08BC1847A8
+:1002F000F1B57048824D00782C78824E7F4F0028EF
+:100300000DD1F878012801D100202870009836F22C
+:10031000E8FA307804281AD10120F87017E0002C90
+:1003200015D036F2C4FA784909684B00591888424A
+:100330000BD271490020087005203070F878012830
+:1003400005D0009836F2CDFAE6E7082030702C7020
+:10035000CBE770B5694D04002879002813D15A49BC
+:10036000E06809684BF28BFC0020E06057480068A9
+:100370004BF284FC5249012008702879401C2871F6
+:1003800070BC08BC1847200037F230F8F8E710B509
+:1003900035F2D3FA59490020C870087190E6F3B5D8
+:1003A00005006B7B59A006684468032B97B06ED894
+:1003B000E87B03288446FAD8A87B0328F7D8297C51
+:1003C0000129F4D86A7C012AF1D8AF7C022F5ED3D0
+:1003D000EA7CFA2A1592EAD8189A1278002A0BD1E8
+:1003E000022802D24A1C920101E04A1CD201974223
+:1003F00006D918981221017019B0F0BC08BC184732
+:10040000491C8906090E05916146491C8906090E99
+:10041000002B049107D0012B07D0022B38D0032BDF
+:1004200006D13CA102E03DA100E03EA10E684C686F
+:1004300000282ED1049801F0BDF802AA149013915F
+:1004400003C2059801F0B6F838A20CCA01F0B6F85C
+:1004500002AA0CCA01F0B2F82300320001F0B2F88F
+:10046000089005980E00400801F0A4F8029031A011
+:100470000CC80C000898310001F0A8F8029A23007B
+:1004800001F0A4F806000B0013991498B9E001E1FB
+:1004900054E055E0485F54455354494E475F535527
+:1004A0004343455353000000AD1101007C1B010084
+:1004B000CA110100C4110100B8110100C0110100EE
+:1004C000B9110100A012010028240100A81E01009A
+:1004D000BE110100FF0400006CD70000EF0C00000B
+:1004E000480A0000750A0000770A0000760A00003A
+:1004F0004021010018EB0000C51101009C8900009B
+:10050000C3110100C91101003812010000000000F0
+:100510000000000000000000000048400000000053
+:1005200000003040000000000000404000000000DB
+:10053000000044400000000000001040FBA175E7EF
+:10054000012831D1049801F035F802AA03C20598B8
+:1005500001F030F806221191129001F03BF802AA46
+:100560000CCA01F02BF82300320001F02BF8060032
+:100570001298119C0290EF480CC8300001F026F848
+:10058000029A230001F022F8069004980E00400021
+:1005900001F010F80C00029006980322310001F0DF
+:1005A00019F8029A23006CE00228049831D101F076
+:1005B00001F802AA10900F9103C2059800F0FAFF0B
+:1005C00006220D910E9001F005F802AA0CCA00F067
+:1005D000F5FF2300320000F0F5FF04000E000DA827
+:1005E00003C80390D34802910CC83100200000F0EA
+:1005F000EDFF02AA0CCA00F0E9FF06000B000F99FC
+:1006000010980C00029003221900300000F0E2FF65
+:1006100035E000F0CFFF02AA0C900B9103C20598C1
+:1006200000F0C8FF062209910A9000F0D3FF02AA49
+:100630000CCA00F0C3FF2300320000F0C3FF030028
+:100640000C0009A803C80390BA48029144C81800D6
+:100650002100330000F0BAFF02AA0CCA00F0B6FF76
+:1006600084460C980B9C02900A98099E00900322E5
+:10067000604600F0AFFF009A330000F0A7FF029A37
+:10068000230000F09FFF00F0A9FF1599B94201D3A4
+:10069000874203D9189912200870ADE68142FCD92F
+:1006A0001420E874A8E6FFB50D00A34914000968FA
+:1006B00085B02031CA7A002A01D00022CA729F4F29
+:1006C0009F4E00287ED001287DD139000968302056
+:1006D0004BF2D5FA042108430700010032683020AC
+:1006E0004BF2CEFA380004218843010032683020F2
+:1006F0004BF2C6FA012D29D1924A0020060011685A
+:100700000E541168091840310E73401C0006000E8B
+:100710000B28F4D331F26CFE8B480068467101213E
+:10072000C1708A4E210030681BF287FC30680221BC
+:100730001BF2BCFF30680021801C1BF2F5FF306803
+:1007400000211BF2BFFF31F25BFE03E0804800682E
+:100750004BF294FA7F49804801800F98784E010649
+:100760003268090E00204BF28BFA0F983268010AAA
+:1007700035204BF285FA714F732039684BF27FFABE
+:1007800001210143326873204BF27AFA39685B2009
+:100790004BF275FA0E99F0229043002929D00129D5
+:1007A00029D002292AD0032900D110430100326840
+:1007B0005B204BF265FA4E2C00D94E24012D04D15A
+:1007C000802001E024E021E004433268A11C1220D3
+:1007D0004BF256FA012D19D0396864204BF24FFACA
+:1007E00018218843089902290BD0012908D110212A
+:1007F00007E0A02100E0E0210843D7E7B021FBE7B4
+:1008000008210143326864204BF23AFA09B0F4E55A
+:100810004F4800684BF232FA396864204BF22FFAE5
+:100820001A2188430100326864204BF229FA3968A2
+:100830005B204BF224FAF0218843010032685B20F0
+:100840004BF21EFA396873204BF219FA41083268EC
+:10085000490073204BF214FA396830204BF20FFA3A
+:100860000425284304000100326830204BF208FAC6
+:100870002000A8430100326830204BF201FA2E4CD0
+:10088000012120682030C172344B02211B685120A5
+:1008900004AA4BF2F6F96B46188AC1052068C90D07
+:1008A0000185018DAA011143018510F280FB2C49BD
+:1008B00001A810F2CCFB234C0C22206801A910F2F5
+:1008C00005F820680C224C3001A90FF2FFFF9DE7CC
+:1008D000F8B5244E002434708379234A2349012536
+:1008E000052B47D005DC00F07DFE0511454545454B
+:1008F0001500082B40D004DC062B3DD0072B09D176
+:1009000038E0092B36D0FF2B04D1147008200C706E
+:100910001FF2CFFA0420F9F101FF154900900160A0
+:1009200004216846F9F116FFDFE40000000000C072
+:10093000CC0C4640E4780000340F01001C27010075
+:1009400020270100300F0100B80E0100C00E010089
+:10095000D824010001040000103080006427010049
+:1009600084F10000CEF80000CCF8000090FF0000F9
+:10097000910C00001570CDE7157035700D70FF4AB1
+:10098000FF4B147395801B681C330B62437B002B59
+:1009900001D10D77BEE70C770821D1805473808890
+:1009A0001081B7E710B5002A09D1052907D1B42372
+:1009B0004343F44C1B199B7C0E2B00D001222CF2DC
+:1009C0008DFD60E47CB50400C01D002201A947F242
+:1009D0005FFF6B469988A58801227C2900D20022FE
+:1009E000694647F268FF6B469988E748814201D023
+:1009F000042928D16B4618882E2824D12421694344
+:100A0000E2480C18A07B00281AD0607B002817D180
+:100A1000A079032803D0052801D1032100E001219A
+:100A2000DB4A608812684BF22BF918F26EFBD94949
+:100A3000A071280009684BF222F97CBC08BC184759
+:100A4000D5492800F6E7200019F240FBF5E7F1B59B
+:100A5000D24982B00298096800254BF210F90128AA
+:100A600005D1CC49029809684BF209F951E0029886
+:100A700024235843C54901264418A27B0027012A94
+:100A800006D1A279002A06D1628801250A52678020
+:100A9000A079002801D0002600E0E773C048007864
+:100AA00001906179012907D12179032904D1BC4939
+:100AB000012801D103200870BA49029809684BF255
+:100AC000DEF8B7490198012E087002D1029818F299
+:100AD0002BFF012D277405D1B34A0299126800201B
+:100AE0004BF2CEF80820F9F119FE33210090016095
+:100AF0000299818021798171AC4801686846F9F1D9
+:100B000029FEAB4B00221C6802992E2013004BF2E9
+:100B1000B9F8A84800684BF2B1F8FEBC08BC184709
+:100B2000F1B582B0029824235843984F0190C4191C
+:100B3000A07B01280AD1E07B002807D1207C002877
+:100B400004D1A579002D05D1257903E0608818F23C
+:100B5000DCFA0500924800260378002B01D1012120
+:100B600000E01900A079032802D1227A012A07D0D7
+:100B70002279032A06D16779012F03D1012B01D1F4
+:100B80000020CAE7814F884201D88D420BD9618885
+:100B90000198854A39520020608002991268012626
+:100BA0004BF26EF819E0002801D18A420FD8A17BE0
+:100BB000012912D1E17B01290BD1A84202D00028E2
+:100BC00005D101E0002808D1AA4200D103E00126A6
+:100BD00003E0002801D1AA42F9D1A079A17B3A0013
+:100BE0000700002922D16E49257C09780B00012DD0
+:100BF00000D12179032B10D1E37B012B03D10128F4
+:100C000001D1012109E0002807D12079012804D170
+:100C1000E0790028F5D00020E0710198105A5C4A74
+:100C200012684BF22DF818F270FA0500A07900282E
+:100C300002D0A84204D002E02179A94200D02F00BE
+:100C4000B84201D00126A771300066E7F8B504006C
+:100C50000D0016002820F9F161FD57490090086049
+:100C600032002900200029F276FE6846F9F166FD7F
+:100C70005AE610B5082801D038F23EFFA1E64F4AE7
+:100C800010B5136800244101CB18DC821368CB181F
+:100C90009C821368CB189C81126889184C812EF2B3
+:100CA000CDFE47480078052808D146480121006854
+:100CB000490202888A4302808481C48281E6FEB5AB
+:100CC00041480078002802D123F24DFC25E73F4F30
+:100CD0006B461F8040495F8000249F803C4D3D4E05
+:100CE000098801206A4612E070234343EB5C012B24
+:100CF0000AD1122343439B199B79002B04D0630034
+:100D0000641C2406240ED052401C0004000C8842AF
+:100D1000EAD9002CDAD0002518E069006846475A65
+:100D20002A4887420FD000262C497001085AB84241
+:100D300004D100221100380023F2E3FC761C3606B1
+:100D4000360E022EF0D36D1C2D062D0EA542E4D3D7
+:100D5000E3E6F8B5224F040038780D00A04205D133
+:100D60007978A94202D1397B00295AD1A04247D0D3
+:100D7000FBF113F9154A054E002133E0B0FF0000E6
+:100D800054F90000AC0201007F0200004CF60000A4
+:100D90004C28010050280100FC20010044280100DB
+:100DA0000EF600006C28010048280100C4E800008D
+:100DB0000021010040280100D0190100100F01009E
+:100DC000FD110000140F0100CFF80000FFFF00002C
+:100DD00010FC0000C4F20000F8F8000090010100CF
+:100DE0003CF60000A0234B43C35C012B03D124231A
+:100DF0004B439B19DA82491C0904090C0A29BCD30C
+:100E00002100280014F2BBFE0A2C786005D10A2DBF
+:100E100003D10121C90308437860102078723C7027
+:100E20007D7081E5F8B505000C000126002926D06B
+:100E3000FA480078002802D1012038F281FBF84BF3
+:100E4000F84A11273F022878012C01D121030843D9
+:100E500018800021491C0904090C802903D210883C
+:100E6000C007F7D002E0802900D11F8016806D1CDA
+:100E7000641E2406240E03D08029E4D300E08021E0
+:100E80003000802900D300204EE5F8B506000D00A3
+:100E900017001C00002949D0002C47D0DF480078FB
+:100EA000002802D1012038F24BFBDD4ADD4B3078BF
+:100EB00010800021491C0904090C802903D21888DC
+:100EC000C007F7D004E0802902D111200002108071
+:100ED00001201880761C6D1E2D062D0E21D0802934
+:100EE000E5D31EE0FF200130012C01D111200002CA
+:100EF00010800021491C0904090C802903D218889C
+:100F00008007F7D504E0802902D11120000210806B
+:100F10000220188010883D007F1C641E2406240EC9
+:100F20002870002C03D08029DCD300E08021012030
+:100F3000802900D30020F7E410B5122038F27EFD9E
+:100F4000B94801880222114301803AE5B64910B53B
+:100F50000888022290430880122038F2CDFD30E547
+:100F600070B5B24C0121A170AC49097801290DD0AE
+:100F7000AF4940180DD1042565702078002805D1AF
+:100F8000FFF7DAFF2570E088401CE08070BC08BCE9
+:100F9000184703208002F9F15CFDF7E770B5A34C18
+:100FA0000025A178012916D19C490978012912D080
+:100FB0009F49C91E40180AD16570207804280AD1BB
+:100FC000FFF7C4FF25702089401C208103E0032027
+:100FD0008002F9F13EFDA570D8E770B58F49097818
+:100FE0000129D3D08F4909884907CFD48F4CA178E4
+:100FF0000129CBD1DB210901401A0425002811D099
+:1010000001281FD120780328C0D1FFF795FF257054
+:10101000A089401CA08160780028B7D18548FFF7DF
+:10102000BDFFB3E76570FFF791FF82490320207091
+:101030003322891C142000232CF2BAFF6089401C43
+:101040006081A3E703208002F9F103FD9EE708B564
+:101050000420F9F163FB77490090C91E0160042167
+:101060006846F9F177FB01B008BC184708B50420C1
+:10107000F9F154FB6F490090016004216846F9F1D1
+:1010800069FBF0E708B50420F9F148FBDB21090111
+:101090000090016004216846F9F15CFBE3E7F8B5D4
+:1010A000F9F198FBDB242401651C661E271F0090C4
+:1010B00013E0B04202D1FFF771FF08E0A04201D077
+:1010C000A84202D1FFF789FF01E0FFF749FF684618
+:1010D000F9F134FBF9F17EFB00900068B842E8D0EA
+:1010E0005449891E8842E4D0491C8842E1D0A0427C
+:1010F000DFD0A842DDD0B042DBD0009814E410B5B8
+:1011000037F29AFC4C480088400501D4FFF79FFF56
+:1011100057E410B514F225F847480088400501D57A
+:10112000FFF7A4FF4DE410B514F226F842480088FA
+:10113000400501D5FFF78BFF43E4404810B5008818
+:10114000400501D4FFF783FF1BF268FC39E410B5BA
+:101150001AF26CF9FFF78AFF33E47CB5040008004B
+:10116000150006A906C96E4606C601002A00200021
+:101170001AF21EFC012C01D1FFF769FF5DE410B5E6
+:10118000FAF1D6FC2949002048700870887018E4EC
+:1011900010B5040038F2D4F924488078012803D12E
+:1011A000002C01D1FFF76EFF0BE41E4810B500883C
+:1011B0001E4C2069012801D1FFF764FF0020206147
+:1011C0005CE510B51EF266FEFFF7EFFF56E508B5C9
+:1011D0002EF203FC1A48007800280AD1194800783A
+:1011E000052806D100221100222013000092F8F1F8
+:1011F00008FA38E710B51FF278FBFFF760FD3DE510
+:101200000A491148143108604860704707480F497F
+:101210005C3001600D491A31416070478C14010047
+:101220000008800004088000100880009C890000ED
+:1012300054F2FFFFAF0D0000741401001030800065
+:10124000FF110000FD110000082A000004CF21005A
+:10125000104B002002008100401C0004000C1028EC
+:101260005A50F8D300204100C9184031401C0004F6
+:10127000000C0A8002288A80F5D3CEE7054A0020B8
+:10128000411E48328300401C0006000E0328D15046
+:10129000F8D3C2E7B08900005A48018801229203BE
+:1012A00011430180704758485849704B08605848AE
+:1012B0005849694A08605848584908605848594987
+:1012C000086059485949086059485A4908605A48BD
+:1012D0005A4908605A485B4908605B485B490860A6
+:1012E0005B485C4908605D485D4908605D490020D5
+:1012F00008705D4919605E4908705E485E49086083
+:101300005E485F4908605F485F4908605F48604920
+:101310000860604860490860604861490860614849
+:101320006149086061486249086062486249086032
+:1013300062486349086063486349086063486449D8
+:101340000860644864490860644865490860654805
+:1013500065490860654866490860664866490860EE
+:10136000664867490860674867490860674869498F
+:1013700010606748086068486849086068486949BB
+:10138000086069486949086069486A4908606A48AC
+:101390006A490860704770B5F9F10EFA684B694CFC
+:1013A000A34209D068488208002003E081005D580C
+:1013B000401C65509042F9D36448654A8308002078
+:1013C000010002E08400401C11519842FAD3FFF75B
+:1013D0006AFFFFF73DFFFFF751FFFFF711FFFFF730
+:1013E00015FF5C4B5C481A1F1100403948F290FE13
+:1013F00048F2BCFEFFF750FFF9F1CEF970BC08BC13
+:101400000020184778098000317400004429010049
+:101410005B7400007C1F010077740000981E0100BF
+:101420008F740000B01E0100D3740000F81E01008C
+:101430001F760000801E010039760000CC1E0100DE
+:101440002D750000B81F01007B750000C021010050
+:10145000D3750000442A0100C4240100817C0000EF
+:10146000302C01009F890000A1760000141F0100AC
+:10147000A0890000037700009C1E01003F77000058
+:10148000A41E01004F770000502101002F800000B2
+:10149000081D0100557D0000B42F0100FD7F0000F4
+:1014A000CC250100757D000038210100FF7D000082
+:1014B0005C280100D17E0000442801002380000048
+:1014C0002C1C01006F800000C01C01000381000083
+:1014D000081E0100D5810000CC1D01003B820000E8
+:1014E000BC1D0100AF84000020280100C38400005F
+:1014F000741D0100D7840000981D0100EB840000DA
+:10150000501D0100FF840000B02401000B85000085
+:101510004F840000FC2D01002F8500007829010078
+:1015200041850000C01D0100738500004C2F0100A3
+:101530007F850000F01C0100A5850000582B0100EC
+:1015400030740000307400006C1500007000000062
+:101550009C890000F4890000F889000003000B4317
+:10156000020070B49B0710D10F4CE50100E008C2E7
+:1015700008C91E1B9E432E42F9D01906090E117090
+:10158000521C00290DD01B0AF7E70C78491C531C8C
+:10159000002C147005D00C78491C5A1C002C1C70AF
+:1015A000F3D170BC70470000010101017847C046CB
+:1015B000CC2809EA7847C046592D09EA7847C04641
+:1015C0005B2D09EA7847C046EB2B09EA7847C0460D
+:1015D000CF2D09EA7847C0461B3009EA7847C04654
+:1015E000162D09EA7847C0469D2909EA0800203BE4
+:1015F000A080203B7187203B0381203B0004D83C26
+:101600000004D83C0004D83C0004D83C0205D83C77
+:10161000B386803B0002C0320206D83C0000803C0A
+:101620000800203B1D81203B0080203B5580203B53
+:101630000F81203B4081203B4681203B4B00203BDB
+:101640000182203B1382203B8C82203BA182203BE5
+:10165000BC82203B5883203BA483203B0C84203B4E
+:101660006784203BBC84203B7B85203B7485203BEA
+:101670005900203B7287203BC387203B6288203B78
+:10168000D988203BC888203BBC88203B338F203B37
+:101690003C8F203B498F203B558F203B0890203BBF
+:1016A0002391203B6491203B4591203B9691203B28
+:1016B0009890203BAC90203B0D91203B958E203B99
+:1016C0009F8E203BAC8E203BC58E203BE588203B87
+:1016D0006089203B6B8D203BE18D203BEE89203BD8
+:1016E000FE89203B138B203B5A8A203B428A203BB9
+:1016F000278A203BEB8A203B7A8E203BC58B203B00
+:101700000C8C203BA38C203BAE8C203B8E8C203B52
+:10171000BC8C203B148D203B01FD3F6C7781803BCE
+:101720009C7E00B5F40400383FD8009521001038A5
+:1017300000E4BF7E00430032074000B521001138AD
+:10174000210010380003D83C074000B521001138B3
+:10175000FF0B0A389C7E14936700473B01FD3F6CEA
+:101760005F000A389C7E14938300633B760E6030E2
+:101770002700803B000850309C7E10928300633B22
+:10178000FF0B01348300203B847A00B59C7E16A3B6
+:101790007D00633B760E5030FFFF60302500803BBC
+:1017A000000840306C0E5030FFFF60302500803B59
+:1017B00000084030490080300800803A4900123863
+:1017C0001CFB42610564247B1BFB626209FB4262D5
+:1017D0001BFB42610564247B13000031C544207F5C
+:1017E000FF0B0A38857A00B59C7E16A38300653B03
+:1017F0009CFEB491FF0B0B38BE84803B68043134EF
+:0C1800003F5800B50003D83C7F7D4E7FB0
+:00000001FF
diff --git a/firmware/STLC2690_R6_04_A2.fw.ihex b/firmware/STLC2690_R6_04_A2.fw.ihex
new file mode 100644
index 00000000000..b255deceb7f
--- /dev/null
+++ b/firmware/STLC2690_R6_04_A2.fw.ihex
@@ -0,0 +1,334 @@
+:100000000000A0E10000A0E10C0000EB31110000B5
+:10001000110000EF481400002C0100000000000057
+:1000200024000000000000003074000053544C43D2
+:10003000323639302052362E3420202041322020D2
+:100040002032363036323030392031313A33303A9E
+:1000500031354CE230209CE5010C12E334C09C1594
+:1000600000C08C0001C08CE00000A0E3000053E35E
+:100070000EF0A0D104008CE404305300E27434127A
+:100080007FB54021FF4C201D01F080F9BF20207179
+:10009000FF2565710320A571E071CE202072EF204D
+:1000A0006572A0723F26E572002102A826731CF239
+:1000B000AAFF342102A81CF28CFF002803D1207B68
+:1000C000C02108432073EC206573A0731F20E073E8
+:1000D000F22020740F206074E820A074FE20E074E9
+:1000E000F720267560758F20A0750C20E5752076A9
+:1000F00068461DF2A8F96B461878042803D9207EBB
+:10010000102108432076002102A81CF27CFF3B212D
+:1001100002A81CF25EFF012800D1207704220021F2
+:1001200044200223F9F1EAFC7FBC08BC184710B553
+:1001300027F252F8D44A00204023115C4C0701D525
+:1001400019431154401C0006000E4F28F5D310BC73
+:1001500008BC18471CB500210191018900291FD056
+:1001600001683022487802409408C207D20F521C1E
+:1001700093008A780007241D810F0092220001A8B5
+:1001800047F20BF8C1496B460A889888824207D02B
+:10019000088047F22CFFBE490860BE4909684863E1
+:1001A0001CBC08BC184708B5162004F2B7F8BA49B9
+:1001B000009001600021017301214173062168460E
+:1001C00004F2C8F801B008BC184770B5B34D06007A
+:1001D00028680024002819D0B1480068B14909688E
+:1001E0004CF26DFD002811D0AF48007800280DD0EA
+:1001F0002868A94A0C30306028680168914201D112
+:10020000012401E0447BA41C40682860200070BCED
+:1002100008BC184710B50C001900A44B9854A4480A
+:1002200003785B1E03709748B82304714271120A69
+:1002300082713F220720F9F161FC88E7FEB598271B
+:100240000C004F43162363439A4A9B49D65D5D18C1
+:10025000697A002E03D0BA18527C0E2A02D12200ED
+:1002600002234DE0012922D901281DD10126EE7477
+:10027000E9726E720DF232F805008C4806552020A6
+:1002800004F24CF88D4A0090026002228480010042
+:1002900082717819027C5A200243CA710E720E765E
+:1002A0000221684604F256F8FEBC08BC1847012932
+:1002B000FAD1012806D17D48005D0028F4D1220042
+:1002C00008001CE00028EFD17848005D0128EBD140
+:1002D0007B4AE87A127890420FD801280DD900267F
+:1002E0006B461E71987177481E72036821002D209D
+:1002F00001AA2BF2FFF8EE72D6E7220000200023BD
+:10030000FFF788FFD0E7FEB504F264F8624F644C53
+:10031000103F6D4D002601902DE0B9420FD1017BB9
+:100320000E290CD157494A78022A08D18978102918
+:1003300005D1010020318A7803235A408A7006F2E1
+:1003400062FC04F239F80520694605F2C7FF01286E
+:1003500001D1320002E0002805D002000099206897
+:100360002B684CF2AEFC04F217F801A803F2E6FF8A
+:1003700004F230F80190484A01689142CDD0B94268
+:10038000CBD0524A0168914207D1C188040000795C
+:10039000FFF754FFFF21F53121600198474A0168BA
+:1003A000793A91420AD1414A002113000A3B56543E
+:1003B0005E54491C0906090E0A29F8D374E7F1B501
+:1003C000009800268079370035003400062801D0D7
+:1003D000082856D13E480078002806D12CF221F892
+:1003E0003C4908603A49012008700098407B012888
+:1003F0000098007B72D1472804D1472601271E258B
+:1004000020242AE04C2804D14C26032778257A247E
+:1004100023E04D2804D14D260327B425B6241CE043
+:10042000562804D1562601273C253E2415E067288E
+:1004300004D1672601275A255C240EE05C2805D1EB
+:10044000FF255C2603276935AC1C06E06D2804D126
+:1004500087256D260327AD00AC1C0098C089A842F3
+:1004600000D2050000981C49808809684CF227FCDE
+:1004700000990022097C45F2BEFD00981223808875
+:100480002DE05BE000D7000070FA0000CE170100FD
+:100490001C18010040D80000AC13000098EB0000CD
+:1004A00090EB00007CEB000071D600005C87000040
+:1004B000A6D60000CC11000060EE0000920C0000F7
+:1004C0005EEE00005828010050EB00009B03000086
+:1004D000F0180000281900001423010020E0584300
+:1004E000FF4940188179300042F2B4FDFD480068B0
+:1004F0000188FD4A114001221203891801800188F8
+:10050000D20011430180448084800583C582C18963
+:100510000905090D3A031143C181F8BC08BC18470D
+:10052000052802D105260C249CE7072801D10726BF
+:1005300002E0082896D10526202493E7009842F28D
+:100540000FFAEAE77CB504000E00150037F2EAF96D
+:100550006B461C805E809D80D880E44808226946F6
+:1005600003F243F8200011F20BFBB4206043E04992
+:100570004018807C042831D1062D2FD10321200082
+:1005800037F266FEDB484078C00714D098216143FB
+:10059000D9480D182800123034211CF21AFD002809
+:1005A00009D029001A31412201201CF228FF00281D
+:1005B00001D0012100E00021002907D00021200006
+:1005C00037F246FE0621CD4A200001E0CC4A200049
+:1005D00012684CF275FB7CBC08BC18472A0031003D
+:1005E00020003AF25DFEF6E7B423434370B5C04AFB
+:1005F0009C1822006034A57C0A2D01D00B2D08D157
+:10060000527D0B2A05D10022A27438F26AFEA5742D
+:10061000FDE538F266FEFAE5BA4A10B54100515AD6
+:100620008823B94A0905090D59438918897B00298E
+:1006300001D11EF277FA8AE510B5082806D31223F5
+:100640005843A7494018C079083003E0AF4909680A
+:100650004CF235FB0006000E79E5AD4910B549783E
+:10066000002901D121F2BBFA71E570B58188A94C4E
+:10067000A14218D103F2A0FEA74D2888A0420FD0B6
+:10068000A64E317800290BD1A54909684CF217FB19
+:10069000A4490020088002213170A3492C800870F1
+:1006A00003F27AFEB3E5FFF7D8FFB0E570B50400BA
+:1006B0000D001600FF38773806D003F27DFE94490E
+:1006C0000020487003F268FE32002900200011F279
+:1006D000DCFB9CE570B505000E000C2A0ED1934C96
+:1006E000207808280AD12800FF38793806D19048A8
+:1006F00000684CF2E3FA002002002070310028006C
+:10070000FFF7D4FF83E5F8B58A4C0600207800286F
+:100710002AD1082003F202FE7449874DCE39009099
+:100720000160298881800621684603F213FE0820B3
+:1007300003F2F4FD6D490090C33901600021C94303
+:1007400081800221684603F205FE082003F2E6FDDF
+:1007500066490090CA390160298881800121817130
+:100760000721684603F2F6FD2078012802D1300007
+:1007700011F244FDD1E610B56E4C2278002A14D156
+:100780006E49002008806E4908806E4908706E48E6
+:10079000142100F0FFFD68490020C04308800220BA
+:1007A0006249207008200870D1E411F275FDCEE492
+:1007B000F8B500258C46891C2B0003278646CE5CA5
+:1007C00000203C0084403440C440022C14D0032C50
+:1007D00002D0AD1C2D062D0E801C0006000E082830
+:1007E000EFD35B1C1B061B0E0A2BE8D3142D03D37F
+:1007F0006146704611F2C0F88FE610B58188454A0F
+:1008000091420DD08279012A0AD112235943344AE8
+:1008100089188979002903D04C4A1178491C117034
+:1008200032F25EFA93E47CB50400001D01A90FF2D8
+:100830000AFF002820D0E07A01281DD1444D6B46E4
+:10084000998828006A463EF25CFD012814D16B4667
+:100850001888404988420FD099889820264A4843F2
+:10086000105C012808D128003EF29DFC6B461988D7
+:10087000988801220CF234FF20000EF2BDF8AAE69F
+:1008800070B505001AF2E8F816206843324944189A
+:10089000A27B002A66D16288002A63D1085A2F49B8
+:1008A0002F4A097812684CF20BFA19F2F0FC217900
+:1008B000814257D0617A814254D3A179002951D124
+:1008C000E17B00294ED1217C00294BD1A071012070
+:1008D000E073280019F263FF012843D1280042E0A9
+:1008E0009CF900001C160100FFCF0000BD0D0000A8
+:1008F00028090100D0100100CC110000F82E0100E1
+:10090000942F010050FA0000F0F1000014230100C0
+:100910004C870000FFFF00007ED60000D9F10000E8
+:10092000B8220100E2F10000D7F10000B51100008B
+:1009300010270100B7110000B8090000BE11000027
+:10094000C0110000B61100003018000093FF000035
+:10095000180C0000FFFE000060EE00005EEE0000DC
+:100960004428010003E0F94909684CF2A8F94EE473
+:10097000F3B581B0F64A0025009512680700694674
+:100980004CF29EF96B4618889821F24E4143891922
+:100990004C783A68122A0BD1012C09D1B423584360
+:1009A000ED4A8018807C002802D0152800D04D70B8
+:1009B000029938000DF2C6FA6B46198898235943FC
+:1009C00089194C7070E438B51400032906D0010071
+:1009D0001220F9F160F838BC08BC1847DF490A78E2
+:1009E000521C0A7001000020F9F155F8082003F2AA
+:1009F00095FCDB4900900160A17801716278217853
+:100A000012021143C1800421684603F2A3FCE2E70D
+:100A1000F0B48505059BAD0D840A01263F2C03D15A
+:100A2000B82D01D1F0BCCEE71E70F0BC704710B5F8
+:100A300004003CF21FFECB49002008550A39085536
+:100A4000F9E500B53F2885B012D1B82910D1C64AC2
+:100A500003A904A86B4607C3C448C74B0268C4482F
+:100A60000178C448008806F256FE05B008BC184755
+:100A7000F9F159FBF9E7F7B5BA4E0400305C0F0005
+:100A8000012817D116206043BC494518E87C01288D
+:100A900010D1687AB8420DD1029800280AD12200FC
+:100AA000390001200023FFF7B5FB687A012801D93E
+:100AB00000203055029A3900200019F24AFF1BE449
+:100AC000F3B583B00CF20AFCA64E00210C000A36E6
+:100AD0006D4698224A436C54835C012B20D1121836
+:100AE000527C062A1CD00E2A1AD016224A43A34B47
+:100AF000A34FD218D37A3F78BB4211D8177D002F6D
+:100B00000ED1039F012F0BDB049F012F08D1954FBE
+:100B10007F5C012F04D173540123D47213756B547D
+:100B2000491C0904090C0A29D3D303A803C81AF2E3
+:100B300086F8924F00216A5C012A06D116234B43A6
+:100B4000725CDB19DA721C756C54491C0904090CBF
+:100B50000A29F0D305B0F0BC08BC18477CB50500E5
+:100B6000C01D002201A949F253FE6B469988AE8848
+:100B700001227C2900D20022694649F25CFE6B46C4
+:100B800099887E4A042902D07E48814211D16B4661
+:100B900018882E280DD1162070438018837B002BD7
+:100BA00007D0437B002B04D1037C012B01D1002310
+:100BB00003742E2929D1162070438418607A0128E5
+:100BC00006D16848805D012802D1287A01280DD11C
+:100BD0006B49287A0978884217D8E67A28001AF2F1
+:100BE000D1F9E07AB04200D2E672F4E4300019F2B2
+:100BF00017FB0100E27A287A824200D8E0722E22A6
+:100C000030000D2310F2D7FCE5E428001AF2BAF9FF
+:100C1000E1E4982242434F4910B551180A002031AF
+:100C20000B7B012B07D0127C002A04D18A79032A7E
+:100C300001D101228A710DF209F9FCE48288524B3C
+:100C400000219A4207D14A4A03231370807903286E
+:100C500001D1022010700800704710B5040003F2A3
+:100C6000ABFB404901201039487003F295FB20008E
+:100C700011F24AFADFE410B5444B040000221B686D
+:100C800011000A204CF21DF836480221103841703C
+:100C90008078002802D0A079012802D1200046F2F5
+:100CA00054FDC8E42F4A10B5103A9178491C917050
+:100CB00048F229FEBFE47CB52A4C103CA278521EB3
+:100CC00012061216A2700DD16278022A0AD130489B
+:100CD00000256B469D7100889880684646F235FD78
+:100CE000A57078E446F206FF75E438B5040003F217
+:100CF00063FB1C4900201039487003F24DFB0820AB
+:100D000003F20CFB2349009001602349098881808C
+:100D10000221684603F21EFB200011F234FA5AE663
+:100D200010B5D02806D111780E480C3801705178D2
+:100D3000417080E400F2D6FE7DE410B5D02801D1E8
+:100D4000022078E400F203FF75E400004828010067
+:100D50002C270100CC11000028090100A6D60000B4
+:100D60009B0300005C87000004D70000C4D600008D
+:100D7000AED60000B6D60000E8D6000060EE000057
+:100D80005EEE00007F020000C3FC00008C1F01002B
+:100D9000C0170100FA0C0000B8090000A84B10B5FC
+:100DA000A64A1B680221D0204BF28BFF3CF2B2FB1B
+:100DB00041E4FEB56B461880598000240E001700F0
+:100DC0009C80A04808226946DC8002F20EFC9B4809
+:100DD00050230178407859430D0085409A480029F6
+:100DE00040D03200994E012A1BD102000079002820
+:100DF0000FD0147110684B231B01984202D30022BC
+:100E0000310002E000223100180000233EF2BCF95C
+:100E1000D8E51068430818008B421360EFD21460C5
+:100E2000D0E5012F13D101220400027100680028CF
+:100E300001D1216005E040002060002130003EF239
+:100E4000B2F92068A84200D925602068D7E70500DC
+:100E50000068002804D0002130002C603EF2A3F985
+:100E60002C71AFE50471ADE5F0B4794C00290DD0DB
+:100E7000002A0BD0002307E09D00764F56593F68AB
+:100E80005B1C1B061B0E7E518B42F5D300220228F1
+:100E900002D1704909684A606F4901230968DB057E
+:100EA000C3180A606D4A1268536100E0641E0A6844
+:100EB000002A01D1002CF9D10968814201D8002C07
+:100EC00001D10020B1E50120AFE5F8B5B4214143DF
+:100ED000070063480E18B07C032801D0152827D1DD
+:100EE000380036F21FFD34002034A17F0500814216
+:100EF0001ED0380037F2B8FB707D0026002813D1D1
+:100F0000012D11D1A07F00280ED14C48801CC05D5E
+:100F1000002809D10120A0770321380037F298F981
+:100F2000380037F2A1FBA6774448801CC65521E45F
+:100F3000380037F299FB1DE470B50400B423584320
+:100F4000474BC51820352E7F20003AF25EFA042E5A
+:100F50000CD1287F062809D19820604341494018C8
+:100F6000007C012802D13549891C0855FFE4FEB5F3
+:100F70000C000600944608A807C8A505AD0DA70AF1
+:100F80003F2F09D103273F02BD4205D12B4F012539
+:100F90003F1F3D701D78FD706D4607C52100300074
+:100FA000624608F29AFA0DE538B5254B01211B6817
+:100FB00093206A464BF285FE6B461878FF2815D1C0
+:100FC0001E48001F0078012810D11C4A264C521ED2
+:100FD0002368012193204BF274FEF8F1E1F92368B4
+:100FE000012193206A464BF26CFEF4E4F8F1D8F943
+:100FF000F1E410B53DF286FA1C4C6088EE2803D06F
+:101000000FF2AEF9002804D160881AF27EFA0028A7
+:1010100013D0174CA079800705D5164AA08812680E
+:1010200001214BF24DFEA079400704D51249A0885A
+:1010300009684BF244FE0020A07101E550870000D2
+:1010400060270100DE0D0000E0080100B30C000085
+:10105000A086010058D8000040D80000D8D5000074
+:1010600028090100CC110000642701005816010076
+:10107000D0100100942F010078260100624908B5C4
+:10108000052008706149634A08706149116062492E
+:10109000624A11606249634A11606349634A1160A0
+:1010A0006349644A11606449644A11606449654A4D
+:1010B00011606549654A11606549664A1160664973
+:1010C000664A11606649674A11606749674A11605C
+:1010D0006749684A11606849684A11606849694A05
+:1010E00011606949694A116069496A4A11606A492F
+:1010F0006A4A11606A496B4A11606B496B4A116018
+:101100006B496C4A11606C496C4A11606C496D4ABC
+:1011100011606D496D4A11606D496E4A11606E49EA
+:101120006E4A11606E496F4A11606F496F4A1160D3
+:101130006F49704A11607049704A11607049714A74
+:1011400011607149714A11607149724A1160724AA5
+:1011500000211170714A11707149724A116072490F
+:10116000724A11607249734A11607349734A11607F
+:1011700073490A220A704870724873496A460860C7
+:10118000724873490860734873490860FF200090F3
+:1011900001219320FFF7C4FD704871490860714830
+:1011A0007149086071487249086001B008BC18476D
+:1011B00070B503F201F96F4B6F4CA34209D06F4831
+:1011C0008208002003E081005D58401C6550904279
+:1011D000F9D36B486B4A83080020010002E08400C9
+:1011E000401C11519842FAD3674A00201154401C08
+:1011F0000006000E0A28F9D3FFF740FF03F2CCF8EF
+:1012000070BC08BC002018477AD60000CCD500007E
+:101210003174000024200100DF740000B0290100B7
+:1012200005750000681F010057750000582C01006B
+:10123000B7760000D82D01007B750000502C01000E
+:101240006F770000E826010099790000102F010057
+:10125000F5780000A0250100C97900006C1B010091
+:10126000E9790000402E0100617B0000082B01009D
+:10127000AB7B0000542F0100D77B0000D829010070
+:10128000317C00004C280100217D0000DC2D010094
+:10129000DF7D000070260100F37D0000981C010036
+:1012A000277E00005C280100717E0000E823010019
+:1012B000C17D0000801D01000D7F0000F8230100AA
+:1012C000C37F0000402D01001B7A0000B022010006
+:1012D000857A000004210100B77A00009C210100FA
+:1012E000277B0000A02101000B8000008821010065
+:1012F00055800000101F010067800000BC1E010027
+:10130000278000009C1E01009B80000084210100BA
+:10131000ED7F00006C2801004D8700004E87000023
+:10132000D180000064270100EB80000060270100ED
+:1013300063810000682601004D8100006C260100D9
+:10134000508700007B8200001C2F0100E982000012
+:10135000EC250100198200008C1F01001F83000092
+:10136000281E01005983000088200100A38300008B
+:101370003825010030740000307400001C13000098
+:10138000240000004C8700005C8700007847C046BE
+:101390009A2D09EA7847C046C32D09EA0800203B88
+:1013A000A080203B7187203B0381203B0004D83C78
+:1013B0000004D83C0004D83C0004D83C0205D83CCA
+:1013C000B386803B0002C0320206D83C0000803C5D
+:1013D0000800203B1D81203B0080203B5580203BA6
+:1013E0000F81203B4081203B4681203B7781203B81
+:1013F0000182203B1382203B8C82203BA182203B38
+:10140000BC82203B5883203BA483203B0C84203BA0
+:101410006784203BBC84203B7B85203B7485203B3C
+:10142000BE84203B7287203BC387203B6288203BE1
+:10143000D988203BC888203BBC88203B338F203B89
+:101440003C8F203B498F203B558F203B0890203B11
+:101450002391203B6491203B4591203B9691203B7A
+:101460009890203BAC90203B0D91203B958E203BEB
+:101470009F8E203BAC8E203BC58E203BE588203BD9
+:101480006089203B6B8D203BE18D203BEE89203B2A
+:10149000FE89203B138B203B5A8A203B428A203B0B
+:1014A000278A203BEB8A203B7A8E203BC58B203B52
+:1014B0000C8C203BA38C203BAE8C203B8E8C203BA5
+:0814C000BC8C203B148D203B85
+:00000001FF
diff --git a/firmware/cg2900_fm_bt_src_coeff_info.fw.ihex b/firmware/cg2900_fm_bt_src_coeff_info.fw.ihex
new file mode 100644
index 00000000000..8ad5325300f
--- /dev/null
+++ b/firmware/cg2900_fm_bt_src_coeff_info.fw.ihex
@@ -0,0 +1,41 @@
+:1000000023232323232323232323232323232323C0
+:1000100023232323232323232323232323232323B0
+:1000200023232323232323232323232323232323A0
+:100030002323232323232323232323232323232390
+:100040002323232323232323230A232053542D450F
+:1000500072696373736F6E20436F6E6E656374694C
+:1000600076697479204368697020464D2042542097
+:10007000436F656666656369656E7420496E666F79
+:10008000726D6174696F6E2046696C650A230A237C
+:1000900020416C6C20696E666F726D6174696F6E61
+:1000A000206D7573742062652073746F72656420AF
+:1000B000617320666F6C6C6F77730A230A23204884
+:1000C00043495F7265766973696F6E094C4D505F85
+:1000D00053756276657273696F6E0946696C655F08
+:1000E0006E616D652028776974686F7574202E6F56
+:1000F000726720657874656E73696F6E290A230ACA
+:1001000023232323232323232323232323232323BF
+:1001100023232323232323232323232323232323AF
+:10012000232323232323232323232323232323239F
+:10013000232323232323232323232323232323238F
+:1001400023232323232323230A230A230A232323CA
+:10015000232323232323232323232323232323236F
+:10016000232323232323232323232323232323235F
+:10017000232323232323232323232323232323234F
+:10018000232323232323232323232323232323233F
+:1001900023232323230A230A2320464D20425420CD
+:1001A000436F656666656369656E742066696C6534
+:1001B00020666F722053542D4572696373736F6E9E
+:1001C000202D204347323930300A230A3078303727
+:1001D000303020307830303131205231662E325F6D
+:1001E000536F43317632305F42545F7372635F63A3
+:1001F0006F6566665F312E312E66770A3078303251
+:10020000303020307830303030205232635F536FDE
+:1002100043327630315F42545F7372635F636F6560
+:1002200066665F312E312E66770A230A2323232345
+:10023000232323232323232323232323232323238E
+:10024000232323232323232323232323232323237E
+:10025000232323232323232323232323232323236E
+:10026000232323232323232323232323232323235E
+:05027000232323230AF3
+:00000001FF
diff --git a/firmware/cg2900_fm_ext_src_coeff_info.fw.ihex b/firmware/cg2900_fm_ext_src_coeff_info.fw.ihex
new file mode 100644
index 00000000000..920d08b992e
--- /dev/null
+++ b/firmware/cg2900_fm_ext_src_coeff_info.fw.ihex
@@ -0,0 +1,41 @@
+:1000000023232323232323232323232323232323C0
+:1000100023232323232323232323232323232323B0
+:1000200023232323232323232323232323232323A0
+:100030002323232323232323232323232323232390
+:100040002323232323232323230A232053542D450F
+:1000500072696373736F6E20436F6E6E656374694C
+:1000600076697479204368697020464D204578741C
+:1000700020436F656666656369656E7420496E66C8
+:100080006F726D6174696F6E2046696C650A230A30
+:100090002320416C6C20696E666F726D6174696FAC
+:1000A0006E206D7573742062652073746F72656461
+:1000B00020617320666F6C6C6F77730A230A2320AC
+:1000C0004843495F7265766973696F6E094C4D509C
+:1000D0005F53756276657273696F6E0946696C6508
+:1000E0005F6E616D652028776974686F7574202E66
+:1000F0006F726720657874656E73696F6E290A2365
+:100100000A232323232323232323232323232323D8
+:1001100023232323232323232323232323232323AF
+:10012000232323232323232323232323232323239F
+:10013000232323232323232323232323232323238F
+:100140002323232323232323230A230A230A2323CA
+:10015000232323232323232323232323232323236F
+:10016000232323232323232323232323232323235F
+:10017000232323232323232323232323232323234F
+:10018000232323232323232323232323232323233F
+:100190002323232323230A230A2320464D204578A3
+:1001A0007420436F656666656369656E7420666971
+:1001B0006C6520666F722053542D457269637373AA
+:1001C0006F6E202D204347323930300A230A3078B1
+:1001D0003037303020307830303131205231662E97
+:1001E000325F536F43317632305F4558545F7372DC
+:1001F000635F636F6566665F312E312E66770A3006
+:100200007830323030203078303030302052326325
+:100210005F536F43327630315F4558545F7372637A
+:100220005F636F6566665F312E312E66770A230A3B
+:10023000232323232323232323232323232323238E
+:10024000232323232323232323232323232323237E
+:10025000232323232323232323232323232323236E
+:10026000232323232323232323232323232323235E
+:0902700023232323232323230A63
+:00000001FF
diff --git a/firmware/cg2900_fm_fm_coeff_info.fw.ihex b/firmware/cg2900_fm_fm_coeff_info.fw.ihex
new file mode 100644
index 00000000000..42e1ce48b2c
--- /dev/null
+++ b/firmware/cg2900_fm_fm_coeff_info.fw.ihex
@@ -0,0 +1,41 @@
+:1000000023232323232323232323232323232323C0
+:1000100023232323232323232323232323232323B0
+:1000200023232323232323232323232323232323A0
+:100030002323232323232323232323232323232390
+:100040002323232323232323230A232053542D450F
+:1000500072696373736F6E20436F6E6E656374694C
+:1000600076697479204368697020464D20436F6536
+:100070006666656369656E7420496E666F726D6150
+:1000800074696F6E2046696C650A230A2320416CEF
+:100090006C20696E666F726D6174696F6E206D752C
+:1000A00073742062652073746F72656420617320BD
+:1000B000666F6C6C6F77730A230A23204843495F8D
+:1000C0007265766973696F6E094C4D505F53756246
+:1000D00076657273696F6E0946696C655F6E616DF6
+:1000E000652028776974686F7574202E6F72672099
+:1000F000657874656E73696F6E290A230A2323235A
+:1001000023232323232323232323232323232323BF
+:1001100023232323232323232323232323232323AF
+:10012000232323232323232323232323232323239F
+:10013000232323232323232323232323232323238F
+:1001400023232323230A230A230A232323232323CA
+:10015000232323232323232323232323232323236F
+:10016000232323232323232323232323232323235F
+:10017000232323232323232323232323232323234F
+:10018000232323232323232323232323232323233F
+:1001900023230A230A2320464D20436F65666665A4
+:1001A0006369656E742066696C6520666F722053A2
+:1001B000542D4572696373736F6E202D204347324F
+:1001C0003930300A230A307830373030093078300F
+:1001D000303131205231662E325F536F43317632E7
+:1001E000305F436F6272615F464D5F534F43315FD3
+:1001F000636F65662E66770A307830323030203093
+:100200007830303030205232635F536F4332763073
+:10021000315F436F6272615F464D5F534F43325FA0
+:10022000636F65662E66770A230A2323232323231D
+:10023000232323232323232323232323232323238E
+:10024000232323232323232323232323232323237E
+:10025000232323232323232323232323232323236E
+:10026000232323232323232323232323232323235E
+:040270002323230A17
+:00000001FF
diff --git a/firmware/cg2900_fm_fm_prog_info.fw.ihex b/firmware/cg2900_fm_fm_prog_info.fw.ihex
new file mode 100644
index 00000000000..d1fde48d2bb
--- /dev/null
+++ b/firmware/cg2900_fm_fm_prog_info.fw.ihex
@@ -0,0 +1,40 @@
+:1000000023232323232323232323232323232323C0
+:1000100023232323232323232323232323232323B0
+:1000200023232323232323232323232323232323A0
+:100030002323232323232323232323232323232390
+:100040002323232323232323230A232053542D450F
+:1000500072696373736F6E20436F6E6E656374694C
+:1000600076697479204368697020464D204669722C
+:100070006D7761726520496E666F726D6174696F2C
+:100080006E2046696C650A230A2320416C6C206946
+:100090006E666F726D6174696F6E206D757374201A
+:1000A00062652073746F72656420617320666F6C83
+:1000B0006C6F77730A230A23204843495F72657681
+:1000C0006973696F6E094C4D505F53756276657246
+:1000D00073696F6E0946696C655F6E616D65202896
+:1000E000776974686F7574202E6F726720657874F5
+:1000F000656E73696F6E290A230A23232323232342
+:1001000023232323232323232323232323232323BF
+:1001100023232323232323232323232323232323AF
+:10012000232323232323232323232323232323239F
+:10013000232323232323232323232323232323238F
+:1001400023230A230A230A232323232323232323CA
+:10015000232323232323232323232323232323236F
+:10016000232323232323232323232323232323235F
+:10017000232323232323232323232323232323234F
+:100180002323232323232323232323232323230A58
+:10019000230A2320464D204669726D7761726520DF
+:1001A00066696C6520666F722053542D45726963D1
+:1001B00073736F6E202D204347323930300A230A83
+:1001C0003078303730302030783030313120523193
+:1001D000662E325F536F43317632305F436F627207
+:1001E000615F464D5F534F43315F70726F672E669C
+:1001F000770A30783032303020307830303030206C
+:100200005232635F536F43327630315F436F6272B5
+:10021000615F464D5F534F43325F70726F672E666A
+:10022000770A230A2323232323232323232323237C
+:10023000232323232323232323232323232323238E
+:10024000232323232323232323232323232323237E
+:10025000232323232323232323232323232323236E
+:0F02600023232323232323232323232323230A9B
+:00000001FF
diff --git a/firmware/cg2900_patch_info.fw.ihex b/firmware/cg2900_patch_info.fw.ihex
new file mode 100644
index 00000000000..7b633478b3f
--- /dev/null
+++ b/firmware/cg2900_patch_info.fw.ihex
@@ -0,0 +1,41 @@
+:1000000023232323232323232323232323232323C0
+:1000100023232323232323232323232323232323B0
+:1000200023232323232323232323232323232323A0
+:100030002323232323232323232323232323232390
+:1000400023232323232323230A232053542D4572C0
+:10005000696373736F6E20436F6E6E656374697648
+:10006000697479204368697020506174636820491D
+:100070006E666F726D6174696F6E2046696C650A99
+:10008000230A2320416C6C20706174636820696EC0
+:10009000666F726D6174696F6E206D757374206226
+:1000A000652073746F72656420617320666F6C6C79
+:1000B0006F77730A230A23204843495F7265766984
+:1000C00073696F6E094C4D505F537562766572733C
+:1000D000696F6E0946696C655F6E616D6520287792
+:1000E0006974686F7574202E6F7267206578746507
+:1000F0006E73696F6E290A230A2323232323232384
+:1001000023232323232323232323232323232323BF
+:1001100023232323232323232323232323232323AF
+:10012000232323232323232323232323232323239F
+:10013000232323232323232323232323232323238F
+:10014000230A230A230A23232323232323232323CA
+:10015000232323232323230A230A232050617463A8
+:10016000682066696C6520666F72205354204D6963
+:1001700063726F656C656374726F6E696373202D53
+:100180002053544C4332363930202D20437574208F
+:10019000322E310A230A3078303630330930783045
+:1001A0003031340953544C43323639305F52365F64
+:1001B00030335F41315F45352E66770A307830360F
+:1001C0003034093078303031440953544C4332369E
+:1001D00039305F52365F30345F41322E66770A2302
+:1001E0000A232323232323232323232323232323F8
+:1001F00023230A230A232050617463682066696CF4
+:100200006520666F722053542D4572696373736F56
+:100210006E202D204347323930300A230A3078309F
+:100220003730300930783030313109434732393096
+:10023000305F315F3043345F3143352E66770A30AB
+:100240007830373030093078303031330943473235
+:100250003930305F315F3043345F3143352E66775C
+:100260000A230A2323232323232323232323232390
+:05027000232323230AF3
+:00000001FF
diff --git a/firmware/cg2900_settings_info.fw.ihex b/firmware/cg2900_settings_info.fw.ihex
new file mode 100644
index 00000000000..bbe66e38a6c
--- /dev/null
+++ b/firmware/cg2900_settings_info.fw.ihex
@@ -0,0 +1,49 @@
+:1000000023232323232323232323232323232323C0
+:1000100023232323232323232323232323232323B0
+:1000200023232323232323232323232323232323A0
+:100030002323232323232323232323232323232390
+:1000400023232323232323230A232053542D4572C0
+:10005000696373736F6E20436F6E6E656374697648
+:10006000697479204368697020466163746F72799E
+:100070002053657474696E677320496E666F726D84
+:100080006174696F6E2046696C650A230A232041FA
+:100090006C6C20696E666F726D6174696F6E206D35
+:1000A0007573742062652073746F72656420617368
+:1000B00020666F6C6C6F77730A230A2320484349CC
+:1000C0005F7265766973696F6E094C4D505F537549
+:1000D0006276657273696F6E0946696C655F6E6101
+:1000E0006D652028776974686F7574202E6F72674C
+:1000F00020657874656E73696F6E290A230A23235D
+:1001000023232323232323232323232323232323BF
+:1001100023232323232323232323232323232323AF
+:10012000232323232323232323232323232323239F
+:10013000232323232323232323232323232323238F
+:100140002323232323230A230A230A2323232323CA
+:100150002323232323232323232323230A230A23A1
+:1001600020466163746F72792053657474696E6799
+:100170007320666F72205354204D6963726F656CF3
+:10018000656374726F6E696373202D2053544C4302
+:1001900032363930202D202043757420322E310A1A
+:1001A000230A23202054686573652073657474697D
+:1001B0006E67732061726520666F722074686520B7
+:1001C000533333352C204254322E312073757070E6
+:1001D0006F727420697320656E61626C65642E0AAB
+:1001E000230A3078303630330930783030313409F2
+:1001F00053544C43323630305F52365F30335F30C9
+:10020000312E66770A307830363034093078303025
+:1002100031440953544C43323630305F52365F30EC
+:10022000345F30322E66770A230A232323232323C5
+:1002300023232323232323232323230A23232323A7
+:10024000232323232323232323232323230A230AB0
+:100250002320466163746F72792053657474696EEC
+:10026000677320666F722053542D457269637373F0
+:100270006F6E202D204347323930300A230A307800
+:100280003037303009307830303131094347323936
+:1002900030305F315F30355F534F435F67656E6568
+:1002A0007269635F5631315F6D6F642E66770A3015
+:1002B00078303730300930783030313309434732C5
+:1002C0003930305F315F30355F534F435F67656E64
+:1002D000657269635F5631315F6D6F642E66770AB0
+:1002E000230A2323232323232323232323232323F7
+:0402F0002323230A97
+:00000001FF
diff --git a/fs/mpage.c b/fs/mpage.c
index fd56ca2ea55..ea5b3e685d5 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -52,6 +52,8 @@ static void mpage_end_io_read(struct bio *bio, int err)
prefetchw(&bvec->bv_page->flags);
if (uptodate) {
+ /* FIXME: fix to solve cache coherence issues. */
+ flush_dcache_page(page);
SetPageUptodate(page);
} else {
ClearPageUptodate(page);
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
index cb5f0a3f1b0..097be1934ee 100644
--- a/fs/partitions/Kconfig
+++ b/fs/partitions/Kconfig
@@ -68,6 +68,25 @@ config ACORN_PARTITION_RISCIX
of machines called RISCiX. If you say 'Y' here, Linux will be able
to read disks partitioned under RISCiX.
+config BLKDEV_PARTITION
+ bool "Blockdev commandline partition support" if PARTITION_ADVANCED
+ default n
+ help
+ Say Y if you like to setup partitions for block devices by reading
+ from the kernel command line (kernel boot arguments).
+
+ The format of the partitions on the command line:
+ blkdevparts=<blkdev-def>[;<blkdev-def>]
+ <blkdev-def> := <blkdev-id>:<partdef>[,<partdef>]
+ <partdef> := <size>[@<offset>]
+
+ <blkdev-id> := unique id used to map driver to blockdev name
+ <size> := size in numbers of sectors
+ <offset> := offset in sectors for partition to start at
+
+ Example:
+ blkdevparts=mmc0:1024@0,524288@1024;mmc1:8192@0,8192@8192
+
config OSF_PARTITION
bool "Alpha OSF partition support" if PARTITION_ADVANCED
default y if ALPHA
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
index 03af8eac51d..48b216c53db 100644
--- a/fs/partitions/Makefile
+++ b/fs/partitions/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_BLOCK) := check.o
obj-$(CONFIG_ACORN_PARTITION) += acorn.o
obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
obj-$(CONFIG_ATARI_PARTITION) += atari.o
+obj-$(CONFIG_BLKDEV_PARTITION) += blkdev_parts.o
obj-$(CONFIG_MAC_PARTITION) += mac.o
obj-$(CONFIG_LDM_PARTITION) += ldm.o
obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
diff --git a/fs/partitions/blkdev_parts.c b/fs/partitions/blkdev_parts.c
new file mode 100755
index 00000000000..48f4136d720
--- /dev/null
+++ b/fs/partitions/blkdev_parts.c
@@ -0,0 +1,127 @@
+/*
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ulf Hansson <ulf.hansson@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Create partitions for block devices by reading from the kernel
+ * command line (kernel boot arguments).
+ *
+ */
+
+#include "check.h"
+#include "blkdev_parts.h"
+
+static char *cmdline;
+
+/*
+ * This is the handler for our kernel commandline parameter,
+ * called from main.c::checksetup().
+ * Note that we can not yet kmalloc() anything, so we only save
+ * the commandline for later processing.
+ */
+static int cmdline_setup(char *s)
+{
+ cmdline = s;
+ return 1;
+}
+__setup("blkdevparts=", cmdline_setup);
+
+/* Parse for a matching blkdev-id and return pointer to partdef */
+static char *parse_blkdev_id(char *blkdev_name)
+{
+ int blkdev_id_len;
+ char *p, *blkdev_id;
+
+ /* Start parsing for a matching blkdev-id */
+ p = blkdev_id = cmdline;
+ while (blkdev_id != NULL) {
+
+ /* Find the end of the blkdev-id string */
+ p = strchr(blkdev_id, ':');
+ if (p == NULL)
+ return NULL;
+
+ /* Check if we found a matching blkdev-id */
+ blkdev_id_len = p - blkdev_id;
+ if (strlen(blkdev_name) == blkdev_id_len) {
+ if (strncmp(blkdev_name, blkdev_id, blkdev_id_len) == 0)
+ return p;
+ }
+
+ /* Move to next blkdev-id string if there is one */
+ blkdev_id = strchr(p, ';');
+ if (blkdev_id != NULL)
+ blkdev_id++;
+ }
+ return NULL;
+}
+
+static int parse_partdef(char **part, struct parsed_partitions *state, int part_nbr)
+{
+ sector_t size, offset;
+ char *p = *part;
+
+ /* Skip the beginning "," or ":" */
+ p++;
+
+ /* Fetch and verify size from partdef */
+ size = simple_strtoull(p, &p, 10);
+ if ((size == 0) || (*p != '@'))
+ return 0;
+
+ /* Skip the "@" */
+ p++;
+
+ /* Fetch offset from partdef and check if there are more parts */
+ offset = simple_strtoull(p, &p, 10);
+ if (*p == ',')
+ *part = p;
+ else
+ *part = NULL;
+
+ /* Add partition to state */
+ put_partition(state, part_nbr, offset, size);
+ printk(KERN_INFO "\nPartition: size=%llu, offset=%llu\n",
+ (unsigned long long) size,
+ (unsigned long long) offset);
+ return 1;
+}
+
+static int parse_blkdev_parts(char *blkdev_name, struct parsed_partitions *state)
+{
+ char *partdef;
+ int part_nbr = 0;
+
+ /* Find partdef */
+ partdef = parse_blkdev_id(blkdev_name);
+
+ /* Add parts */
+ while (partdef != NULL) {
+ /* Find next part and add it to state */
+ part_nbr++;
+ if (!parse_partdef(&partdef, state, part_nbr))
+ return 0;
+ }
+ return part_nbr;
+}
+
+int blkdev_partition(struct parsed_partitions *state, struct block_device *bdev)
+{
+ char blkdev_name[BDEVNAME_SIZE];
+
+ /* Check if there are any partitions to handle */
+ if (cmdline == NULL)
+ return 0;
+
+ /* Get the name of the blockdevice we are operating upon */
+ if (bdevname(bdev, blkdev_name) == NULL) {
+ printk(KERN_WARNING "Could not get a blkdev name\n");
+ return 0;
+ }
+
+ /* Parse for partitions and add them to the state */
+ return parse_blkdev_parts(blkdev_name, state);
+}
+
diff --git a/fs/partitions/blkdev_parts.h b/fs/partitions/blkdev_parts.h
new file mode 100755
index 00000000000..e6c5d40ed76
--- /dev/null
+++ b/fs/partitions/blkdev_parts.h
@@ -0,0 +1,14 @@
+/*
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ulf Hansson <ulf.hansson@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Create partitions for block devices by reading from the kernel
+ * command line (kernel boot arguments).
+ *
+ */
+
+int blkdev_partition(struct parsed_partitions *state, struct block_device *bdev);
+
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 64b299ac9bc..0696be674d2 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -27,6 +27,7 @@
#include "acorn.h"
#include "amiga.h"
#include "atari.h"
+#include "blkdev_parts.h"
#include "ldm.h"
#include "mac.h"
#include "msdos.h"
@@ -50,6 +51,9 @@ static int (*check_part[])(struct parsed_partitions *) = {
* Probe partition formats with tables at disk address 0
* that also have an ADFS boot block at 0xdc0.
*/
+#ifdef CONFIG_BLKDEV_PARTITION
+ blkdev_partition,
+#endif
#ifdef CONFIG_ACORN_PARTITION_ICS
adfspart_check_ICS,
#endif
diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h
index 8b103860783..86457ede09d 100644
--- a/include/linux/amba/bus.h
+++ b/include/linux/amba/bus.h
@@ -18,6 +18,7 @@
#include <linux/resource.h>
#define AMBA_NR_IRQS 2
+#define AMBA_CID 0xb105f00d
struct amba_device {
struct device dev;
@@ -59,9 +60,15 @@ struct amba_device *amba_find_device(const char *, struct device *, unsigned int
int amba_request_regions(struct amba_device *, const char *);
void amba_release_regions(struct amba_device *);
-#define amba_config(d) (((d)->periphid >> 24) & 0xff)
-#define amba_rev(d) (((d)->periphid >> 20) & 0x0f)
-#define amba_manf(d) (((d)->periphid >> 12) & 0xff)
-#define amba_part(d) ((d)->periphid & 0xfff)
+/* Some drivers don't use the struct amba_device */
+#define AMBA_CONFIG_BITS(a) (((a) >> 24) & 0xff)
+#define AMBA_REV_BITS(a) (((a) >> 20) & 0x0f)
+#define AMBA_MANF_BITS(a) (((a) >> 12) & 0xff)
+#define AMBA_PART_BITS(a) ((a) & 0xfff)
+
+#define amba_config(d) AMBA_CONFIG_BITS((d)->periphid)
+#define amba_rev(d) AMBA_REV_BITS((d)->periphid)
+#define amba_manf(d) AMBA_MANF_BITS((d)->periphid)
+#define amba_part(d) AMBA_PART_BITS((d)->periphid)
#endif
diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h
index 747dfb545c9..9a08aa941a8 100644
--- a/include/linux/amba/mmci.h
+++ b/include/linux/amba/mmci.h
@@ -24,24 +24,28 @@ struct embedded_sdio_data {
* @ocr_mask: available voltages on the 4 pins from the block, this
* is ignored if a regulator is used, see the MMC_VDD_* masks in
* mmc/host.h
- * @translate_vdd: a callback function to translate a MMC_VDD_*
- * mask into a value to be binary or:ed and written into the
- * MMCIPWR register of the block
+ * @vdd_handler: a callback function to translate a MMC_VDD_*
+ * mask into a value to be binary (or set some other custom bits
+ * in MMCIPWR) or:ed and written into the MMCIPWR register of the
+ * block. May also control external power based on the power_mode.
* @status: if no GPIO read function was given to the block in
* gpio_wp (below) this function will be called to determine
* whether a card is present in the MMC slot or not
* @gpio_wp: read this GPIO pin to see if the card is write protected
* @gpio_cd: read this GPIO pin to detect card insertion
+ * @cd_invert: true if the gpio_cd pin value is active low
* @capabilities: the capabilities of the block as implemented in
* this platform, signify anything MMC_CAP_* from mmc/host.h
*/
struct mmci_platform_data {
unsigned int f_max;
unsigned int ocr_mask;
- u32 (*translate_vdd)(struct device *, unsigned int);
+ u32 (*vdd_handler)(struct device *, unsigned int vdd,
+ unsigned char power_mode);
unsigned int (*status)(struct device *);
int gpio_wp;
int gpio_cd;
+ bool cd_invert;
unsigned long capabilities;
unsigned int status_irq;
struct embedded_sdio_data *embedded_sdio;
diff --git a/include/linux/amba/pl022.h b/include/linux/amba/pl022.h
index abf26cc47a2..4ce98f54186 100644
--- a/include/linux/amba/pl022.h
+++ b/include/linux/amba/pl022.h
@@ -228,6 +228,7 @@ enum ssp_chip_select {
};
+struct dma_chan;
/**
* struct pl022_ssp_master - device.platform_data for SPI controller devices.
* @num_chipselect: chipselects are used to distinguish individual
@@ -235,11 +236,16 @@ enum ssp_chip_select {
* each slave has a chipselect signal, but it's common that not
* every chipselect is connected to a slave.
* @enable_dma: if true enables DMA driven transfers.
+ * @dma_rx_param: parameter to locate an RX DMA channel.
+ * @dma_tx_param: parameter to locate a TX DMA channel.
*/
struct pl022_ssp_controller {
u16 bus_id;
u8 num_chipselect;
u8 enable_dma:1;
+ bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
+ void *dma_rx_param;
+ void *dma_tx_param;
};
/**
@@ -270,20 +276,13 @@ struct pl022_ssp_controller {
* @dma_config: DMA configuration for SSP controller and peripheral
*/
struct pl022_config_chip {
- struct device *dev;
- enum ssp_loopback lbm;
enum ssp_interface iface;
enum ssp_hierarchy hierarchy;
bool slave_tx_disable;
struct ssp_clock_params clk_freq;
- enum ssp_rx_endian endian_rx;
- enum ssp_tx_endian endian_tx;
- enum ssp_data_size data_size;
enum ssp_mode com_mode;
enum ssp_rx_level_trig rx_lev_trig;
enum ssp_tx_level_trig tx_lev_trig;
- enum ssp_spi_clk_phase clk_phase;
- enum ssp_spi_clk_pol clk_pol;
enum ssp_microwire_ctrl_len ctrl_len;
enum ssp_microwire_wait_state wait_state;
enum ssp_duplex duplex;
diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h
new file mode 100644
index 00000000000..521a0f8974a
--- /dev/null
+++ b/include/linux/amba/pl08x.h
@@ -0,0 +1,222 @@
+/*
+ * linux/amba/pl08x.h - ARM PrimeCell DMA Controller driver
+ *
+ * Copyright (C) 2005 ARM Ltd
+ * Copyright (C) 2010 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * pl08x information required by platform code
+ *
+ * Please credit ARM.com
+ * Documentation: ARM DDI 0196D
+ *
+ */
+
+#ifndef AMBA_PL08X_H
+#define AMBA_PL08X_H
+
+/* We need sizes of structs from this header */
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+
+/**
+ * struct pl08x_channel_data - data structure to pass info between
+ * platform and PL08x driver regarding channel configuration
+ * @bus_id: name of this device channel, not just a device name since
+ * devices may have more than one channel e.g. "foo_tx"
+ * @min_signal: the minimum DMA signal number to be muxed in for this
+ * channel (for platforms supporting muxed signals). If you have
+ * static assignments, make sure this is set to the assigned signal
+ * number, PL08x have 16 possible signals in number 0 thru 15 so
+ * when these are not enough they often get muxed (in hardware)
+ * disabling simultaneous use of the same channel for two devices.
+ * @max_signal: the maximum DMA signal number to be muxed in for
+ * the channel. Set to the same as min_signal for
+ * devices with static assignments
+ * @muxval: a number usually used to poke into some mux regiser to
+ * mux in the signal to this channel
+ * @cctl_opt: default options for the channel control register
+ * @addr: source/target address in physical memory for this DMA channel,
+ * can be the address of a FIFO register for burst requests for example.
+ * This can be left undefined if the PrimeCell API is used for configuring
+ * this.
+ * @circular_buffer: whether the buffer passed in is circular and
+ * shall simply be looped round round (like a record baby round
+ * round round round)
+ * @single: the device connected to this channel will request single
+ * DMA transfers, not bursts. (Bursts are default.)
+ */
+struct pl08x_channel_data {
+ char *bus_id;
+ int min_signal;
+ int max_signal;
+ u32 muxval;
+ u32 cctl;
+ u32 ccfg;
+ dma_addr_t addr;
+ bool circular_buffer;
+ bool single;
+};
+
+/**
+ * Struct pl08x_bus_data - information of source or destination
+ * busses for a transfer
+ * @addr: current address
+ * @maxwidth: the maximum width of a transfer on this bus
+ * @buswidth: the width of this bus in bytes: 1, 2 or 4
+ * @fill_bytes: bytes required to fill to the next bus memory
+ * boundary
+ */
+struct pl08x_bus_data {
+ dma_addr_t addr;
+ u8 maxwidth;
+ u8 buswidth;
+ u32 fill_bytes;
+};
+
+/**
+ * struct pl08x_phy_chan - holder for the physical channels
+ * @id: physical index to this channel
+ * @lock: a lock to use when altering an instance of this struct
+ * @signal: the physical signal (aka channel) serving this
+ * physical channel right now
+ * @serving: the virtual channel currently being served by this
+ * physical channel
+ */
+struct pl08x_phy_chan {
+ unsigned int id;
+ void __iomem *base;
+ spinlock_t lock;
+ int signal;
+ struct pl08x_dma_chan *serving;
+ u32 csrc;
+ u32 cdst;
+ u32 clli;
+ u32 cctl;
+ u32 ccfg;
+};
+
+/**
+ * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor
+ * @llis_bus: DMA memory address (physical) start for the LLIs
+ * @llis_va: virtual memory address start for the LLIs
+ */
+struct pl08x_txd {
+ struct dma_async_tx_descriptor tx;
+ struct list_head node;
+ enum dma_data_direction direction;
+ struct pl08x_bus_data srcbus;
+ struct pl08x_bus_data dstbus;
+ int len;
+ dma_addr_t llis_bus;
+ void *llis_va;
+ struct pl08x_channel_data *cd;
+ bool active;
+ /*
+ * Settings to be put into the physical channel when we
+ * trigger this txd
+ */
+ u32 csrc;
+ u32 cdst;
+ u32 clli;
+ u32 cctl;
+};
+
+/**
+ * struct pl08x_dma_chan_state - holds the PL08x specific virtual
+ * channel states
+ * @PL08X_CHAN_IDLE: the channel is idle
+ * @PL08X_CHAN_RUNNING: the channel has allocated a physical transport
+ * channel and is running a transfer on it
+ * @PL08X_CHAN_PAUSED: the channel has allocated a physical transport
+ * channel, but the transfer is currently paused
+ * @PL08X_CHAN_WAITING: the channel is waiting for a physical transport
+ * channel to become available (only pertains to memcpy channels)
+ */
+enum pl08x_dma_chan_state {
+ PL08X_CHAN_IDLE,
+ PL08X_CHAN_RUNNING,
+ PL08X_CHAN_PAUSED,
+ PL08X_CHAN_WAITING,
+};
+
+/**
+ * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel
+ * @chan: wrappped abstract channel
+ * @phychan: the physical channel utilized by this channel, if there is one
+ * @tasklet: tasklet scheduled by the IRQ to handle actual work etc
+ * @name: name of channel
+ * @cd: channel platform data
+ * @runtime_addr: address for RX/TX according to the runtime config
+ * @runtime_direction: current direction of this channel according to
+ * runtime config
+ * @lc: last completed transaction on this channel
+ * @desc_list: queued transactions pending on this channel
+ * @at: active transaction on this channel
+ * @lockflags: sometimes we let a lock last between two function calls,
+ * especially prep/submit, and then we need to store the IRQ flags
+ * in the channel state, here
+ * @lock: a lock for this channel data
+ * @host: a pointer to the host (internal use)
+ * @state: whether the channel is idle, paused, running etc
+ * @slave: whether this channel is a device (slave) or for memcpy
+ * @waiting: a TX descriptor on this channel which is waiting for
+ * a physical channel to become available
+ */
+struct pl08x_dma_chan {
+ struct dma_chan chan;
+ struct pl08x_phy_chan *phychan;
+ struct tasklet_struct tasklet;
+ char *name;
+ struct pl08x_channel_data *cd;
+ dma_addr_t runtime_addr;
+ enum dma_data_direction runtime_direction;
+ atomic_t last_issued;
+ dma_cookie_t lc;
+ struct list_head desc_list;
+ struct pl08x_txd *at;
+ unsigned long lockflags;
+ spinlock_t lock;
+ void *host;
+ enum pl08x_dma_chan_state state;
+ bool slave;
+ struct pl08x_txd *waiting;
+};
+
+/**
+ * struct pl08x_platform_data - the platform configuration for the
+ * PL08x PrimeCells.
+ * @slave_channels: the channels defined for the different devices on the
+ * platform, all inclusive, including multiplexed channels. The available
+ * physical channels will be multiplexed around these signals as they
+ * are requested, just enumerate all possible channels.
+ * @get_signal: request a physical signal to be used for a DMA
+ * transfer immediately: if there is some multiplexing or similar blocking
+ * the use of the channel the transfer can be denied by returning
+ * less than zero, else it returns the allocated signal number
+ * @put_signal: indicate to the platform that this physical signal is not
+ * running any DMA transfer and multiplexing can be recycled
+ * @bus_bit_lli: Bit[0] of the address indicated which AHB bus master the
+ * LLI addresses are on 0/1 Master 1/2.
+ */
+struct pl08x_platform_data {
+ struct pl08x_channel_data *slave_channels;
+ unsigned int num_slave_channels;
+ struct pl08x_channel_data memcpy_channel;
+ int (*get_signal)(struct pl08x_dma_chan *);
+ void (*put_signal)(struct pl08x_dma_chan *);
+};
+
+#ifdef CONFIG_AMBA_PL08X
+bool pl08x_filter_id(struct dma_chan *chan, void *chan_id);
+#else
+static inline bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
+{
+ return false;
+}
+#endif
+
+#endif /* AMBA_PL08X_H */
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index 5a5a7fd6249..6021588ba0a 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -32,16 +32,20 @@
#define UART01x_RSR 0x04 /* Receive status register (Read). */
#define UART01x_ECR 0x04 /* Error clear register (Write). */
#define UART010_LCRH 0x08 /* Line control register, high byte. */
+#define ST_UART011_DMAWM 0x08 /* DMA watermark configure register. */
#define UART010_LCRM 0x0C /* Line control register, middle byte. */
+#define ST_UART011_TIMEOUT 0x0C /* Timeout period register. */
#define UART010_LCRL 0x10 /* Line control register, low byte. */
#define UART010_CR 0x14 /* Control register. */
#define UART01x_FR 0x18 /* Flag register (Read only). */
#define UART010_IIR 0x1C /* Interrupt indentification register (Read). */
#define UART010_ICR 0x1C /* Interrupt clear register (Write). */
+#define ST_UART011_LCRH_RX 0x1C /* Rx line control register. */
#define UART01x_ILPR 0x20 /* IrDA low power counter register. */
#define UART011_IBRD 0x24 /* Integer baud rate divisor register. */
#define UART011_FBRD 0x28 /* Fractional baud rate divisor register. */
#define UART011_LCRH 0x2c /* Line control register. */
+#define ST_UART011_LCRH_TX 0x2c /* Tx Line control register. */
#define UART011_CR 0x30 /* Control register. */
#define UART011_IFLS 0x34 /* Interrupt fifo level select. */
#define UART011_IMSC 0x38 /* Interrupt mask. */
@@ -49,6 +53,15 @@
#define UART011_MIS 0x40 /* Masked interrupt status. */
#define UART011_ICR 0x44 /* Interrupt clear register. */
#define UART011_DMACR 0x48 /* DMA control register. */
+#define ST_UART011_XFCR 0x50 /* XON/XOFF control register. */
+#define ST_UART011_XON1 0x54 /* XON1 register. */
+#define ST_UART011_XON2 0x58 /* XON2 register. */
+#define ST_UART011_XOFF1 0x5C /* XON1 register. */
+#define ST_UART011_XOFF2 0x60 /* XON2 register. */
+#define ST_UART011_ITCR 0x80 /* Integration test control register. */
+#define ST_UART011_ITIP 0x84 /* Integration test input register. */
+#define ST_UART011_ABCR 0x100 /* Autobaud control register. */
+#define ST_UART011_ABIMSC 0x15C /* Autobaud interrupt mask/clear register. */
#define UART011_DR_OE (1 << 11)
#define UART011_DR_BE (1 << 10)
@@ -84,6 +97,7 @@
#define UART010_CR_TIE 0x0020
#define UART010_CR_RIE 0x0010
#define UART010_CR_MSIE 0x0008
+#define ST_UART011_CR_OVSFACT 0x0008 /* Oversampling factor */
#define UART01x_CR_IIRLP 0x0004 /* SIR low power mode */
#define UART01x_CR_SIREN 0x0002 /* SIR enable */
#define UART01x_CR_UARTEN 0x0001 /* UART enable */
diff --git a/include/linux/boottime.h b/include/linux/boottime.h
new file mode 100644
index 00000000000..f4c28bca0ec
--- /dev/null
+++ b/include/linux/boottime.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009-2010
+ *
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * boottime is a tool for collecting start-up timing
+ * information and can together with boot loader support
+ * display a total system start-up time.
+ *
+ */
+
+#ifndef LINUX_BOOTTIME_H
+#define LINUX_BOOTTIME_H
+
+#ifdef CONFIG_BOOTTIME
+#include <linux/kernel.h>
+
+/**
+ * struct boottime_timer - Callbacks for generic timer.
+ * @init: Function to call at boottime initialization
+ * @get_time: Returns the number of us since start-up
+ * Preferable this is based upon a free running timer.
+ * This is the only required entry.
+ * @finalize: Called before init is executed and boottime is done.
+ */
+struct boottime_timer {
+ int (*init)(void);
+ unsigned long (*get_time)(void);
+ void (*finalize)(void);
+};
+
+/**
+ * boottime_mark_wtime()
+ * Add a sample point with a given time. Useful for adding data collected
+ * by for example a boot loader.
+ * @name: The name of the sample point
+ * @time: The time in us when this point was reached
+ */
+void __init boottime_mark_wtime(char *name, unsigned long time);
+
+/**
+ * boottime_mark()
+ * Add a sample point with the current time.
+ * @name: The name of this sample point
+ */
+void __init boottime_mark(char *name);
+
+/**
+ * boottime_mark_symbolic()
+ * Add a sample point where the name is a symbolic function
+ * and %pF is needed to get the correct function name.
+ * @name: function name.
+ */
+void boottime_mark_symbolic(void *name);
+
+/**
+ * boottime_activate()
+ * Activates boottime and register callbacks.
+ * @bt: struct with callbacks.
+ */
+void __init boottime_activate(struct boottime_timer *bt);
+
+/**
+ * boottime_deactivate()
+ * This function is called when the kernel boot is done.
+ * (before "free init memory" is called)
+ */
+void __init boottime_deactivate(void);
+
+/**
+ * boottime_system_up()
+ * A function is called when the basics of the kernel
+ * is up and running.
+ */
+void __init boottime_system_up(void);
+
+#else
+
+#define boottime_mark_wtime(name, time)
+#define boottime_mark(name)
+#define boottime_mark_symbolic(name)
+#define boottime_activate(bt)
+#define boottime_deactivate()
+#define boottime_system_up()
+#endif
+
+#endif /* LINUX_BOOTTIME_H */
diff --git a/include/linux/caif/caif_socket.h b/include/linux/caif/caif_socket.h
index 2a61eb1beb8..d9cb19b7cff 100644
--- a/include/linux/caif/caif_socket.h
+++ b/include/linux/caif/caif_socket.h
@@ -62,6 +62,7 @@ enum caif_channel_priority {
* @CAIFPROTO_DATAGRAM_LOOP: Datagram loopback channel, used for testing.
* @CAIFPROTO_UTIL: Utility (Psock) channel.
* @CAIFPROTO_RFM: Remote File Manager
+ * @CAIFPROTO_DEBUG: Debug link
*
* This enum defines the CAIF Channel type to be used. This defines
* the service to connect to on the modem.
@@ -72,6 +73,7 @@ enum caif_protocol_type {
CAIFPROTO_DATAGRAM_LOOP,
CAIFPROTO_UTIL,
CAIFPROTO_RFM,
+ CAIFPROTO_DEBUG,
_CAIFPROTO_MAX
};
#define CAIFPROTO_MAX _CAIFPROTO_MAX
@@ -83,6 +85,28 @@ enum caif_protocol_type {
enum caif_at_type {
CAIF_ATTYPE_PLAIN = 2
};
+ /**
+ * enum caif_debug_type - Content selection for debug connection
+ * @CAIF_DEBUG_TRACE_INTERACTIVE: Connection will contain
+ * both trace and interactive debug.
+ * @CAIF_DEBUG_TRACE: Connection contains trace only.
+ * @CAIF_DEBUG_INTERACTIVE: Connection to interactive debug.
+ */
+enum caif_debug_type {
+ CAIF_DEBUG_TRACE_INTERACTIVE = 0,
+ CAIF_DEBUG_TRACE,
+ CAIF_DEBUG_INTERACTIVE,
+};
+
+/**
+ * enum caif_debug_service - Debug Service Endpoint
+ * @CAIF_RADIO_DEBUG_SERVICE: Debug service on the Radio sub-system
+ * @CAIF_APP_DEBUG_SERVICE: Debug for the applications sub-system
+ */
+enum caif_debug_service {
+ CAIF_RADIO_DEBUG_SERVICE = 1,
+ CAIF_APP_DEBUG_SERVICE
+};
/**
* struct sockaddr_caif - the sockaddr structure for CAIF sockets.
@@ -109,6 +133,12 @@ enum caif_at_type {
*
* @u.rfm.volume: Volume to mount.
*
+ * @u.dbg: Applies when family = CAIFPROTO_DEBUG.
+ *
+ * @u.dbg.type: Type of debug connection to set up
+ * (caif_debug_type).
+ *
+ * @u.dbg.service: Service sub-system to connect (caif_debug_service
* Description:
* This structure holds the connect parameters used for setting up a
* CAIF Channel. It defines the service to connect to on the modem.
@@ -130,6 +160,10 @@ struct sockaddr_caif {
__u32 connection_id;
char volume[16];
} rfm; /* CAIFPROTO_RFM */
+ struct {
+ __u8 type; /* type:enum caif_debug_type */
+ __u8 service; /* service:caif_debug_service */
+ } dbg; /* CAIFPROTO_DEBUG */
} u;
};
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 5204f018931..c11e90bab43 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -114,11 +114,17 @@ enum dma_ctrl_flags {
* @DMA_TERMINATE_ALL: terminate all ongoing transfers
* @DMA_PAUSE: pause ongoing transfers
* @DMA_RESUME: resume paused transfer
+ * @DMA_SLAVE_CONFIG: this command is only implemented by DMA controllers
+ * that need to runtime reconfigure the slave channels (as opposed to passing
+ * configuration data in statically from the platform). An additional
+ * argument of struct dma_slave_config must be passed in with this
+ * command.
*/
enum dma_ctrl_cmd {
DMA_TERMINATE_ALL,
DMA_PAUSE,
DMA_RESUME,
+ DMA_SLAVE_CONFIG,
};
/**
@@ -199,6 +205,71 @@ struct dma_chan_dev {
atomic_t *idr_ref;
};
+/**
+ * enum dma_slave_buswidth - defines bus with of the DMA slave
+ * device, source or target buses
+ */
+enum dma_slave_buswidth {
+ DMA_SLAVE_BUSWIDTH_UNDEFINED = 0,
+ DMA_SLAVE_BUSWIDTH_1_BYTE = 1,
+ DMA_SLAVE_BUSWIDTH_2_BYTES = 2,
+ DMA_SLAVE_BUSWIDTH_4_BYTES = 4,
+ DMA_SLAVE_BUSWIDTH_8_BYTES = 8,
+};
+
+/**
+ * struct dma_slave_config - dma slave channel runtime config
+ * @direction: whether the data shall go in or out on this slave
+ * channel, right now. DMA_TO_DEVICE and DMA_FROM_DEVICE are
+ * legal values, DMA_BIDIRECTIONAL is not acceptable since we
+ * need to differentiate source and target addresses.
+ * @src_addr: this is the physical address where DMA slave data
+ * should be read (RX), if the source is memory this argument is
+ * ignored.
+ * @dst_addr: this is the physical address where DMA slave data
+ * should be written (TX), if the source is memory this argument
+ * is ignored.
+ * @src_addr_width: this is the width in bytes of the source (RX)
+ * register where DMA data shall be read. If the source
+ * is memory this may be ignored depending on architecture.
+ * Legal values: 1, 2, 4, 8.
+ * @dst_addr_width: same as src_addr_width but for destination
+ * target (TX) mutatis mutandis.
+ * @src_maxburst: the maximum number of words (note: words, as in
+ * units of the src_addr_width member, not bytes) that can be sent
+ * in one burst to the device. Typically something like half the
+ * FIFO depth on I/O peripherals so you don't overflow it. This
+ * may or may not be applicable on memory sources.
+ * @dst_maxburst: same as src_maxburst but for destination target
+ * mutatis mutandis.
+ *
+ * This struct is passed in as configuration data to a DMA engine
+ * in order to set up a certain channel for DMA transport at runtime.
+ * The DMA device/engine has to provide support for an additional
+ * command in the channel config interface, DMA_SLAVE_CONFIG
+ * and this struct will then be passed in as an argument to the
+ * DMA engine device_control() function.
+ *
+ * The rationale for adding configuration information to this struct
+ * is as follows: if it is likely that most DMA slave controllers in
+ * the world will support the configuration option, then make it
+ * generic. If not: if it is fixed so that it be sent in static from
+ * the platform data, then prefer to do that. Else, if it is neither
+ * fixed at runtime, nor generic enough (such as bus mastership on
+ * some CPU family and whatnot) then create a custom slave config
+ * struct and pass that, then make this config a member of that
+ * struct, if applicable.
+ */
+struct dma_slave_config {
+ enum dma_data_direction direction;
+ dma_addr_t src_addr;
+ dma_addr_t dst_addr;
+ enum dma_slave_buswidth src_addr_width;
+ enum dma_slave_buswidth dst_addr_width;
+ u32 src_maxburst;
+ u32 dst_maxburst;
+};
+
static inline const char *dma_chan_name(struct dma_chan *chan)
{
return dev_name(&chan->dev->device);
@@ -245,14 +316,14 @@ struct dma_async_tx_descriptor {
dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
dma_async_tx_callback callback;
void *callback_param;
-#ifndef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH
+#ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
struct dma_async_tx_descriptor *next;
struct dma_async_tx_descriptor *parent;
spinlock_t lock;
#endif
};
-#ifdef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH
+#ifndef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
static inline void txd_lock(struct dma_async_tx_descriptor *txd)
{
}
@@ -535,11 +606,11 @@ static inline void net_dmaengine_put(void)
#ifdef CONFIG_ASYNC_TX_DMA
#define async_dmaengine_get() dmaengine_get()
#define async_dmaengine_put() dmaengine_put()
-#ifdef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH
+#ifndef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
#define async_dma_find_channel(type) dma_find_channel(DMA_ASYNC_TX)
#else
#define async_dma_find_channel(type) dma_find_channel(type)
-#endif /* CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH */
+#endif /* CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH */
#else
static inline void async_dmaengine_get(void)
{
diff --git a/include/linux/hsi-legacy.h b/include/linux/hsi-legacy.h
new file mode 100644
index 00000000000..c7e2ff5e829
--- /dev/null
+++ b/include/linux/hsi-legacy.h
@@ -0,0 +1,152 @@
+/*----------------------------------------------------------------------------------*/
+/* copyright STMicroelectronics, 2007. */
+/* */
+/* This program is free software; you can redistribute it and/or modify it under */
+/* the terms of the GNU General Public License as published by the Free */
+/* Software Foundation; either version 2.1 of the License, or (at your option) */
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but WITHOUT */
+/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS */
+/* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*----------------------------------------------------------------------------------*/
+
+#ifndef __HSI_DRIVER_IF_H__
+#define __HSI_DRIVER_IF_H__
+
+#include <linux/device.h>
+#include <mach/dma.h>
+#include <asm/irq.h>
+#include <linux/gpio.h>
+#include <plat/ste_dma40.h>
+
+/*
+ * Masks used to enable or disable the reception of certain hardware events
+ * for the hsi_device_drivers
+ */
+#define HSI_EVENT_CLEAR 0x00
+#define HSI_EVENT_MASK 0xFF
+#define HSI_EVENT_BREAK_DETECTED_MASK 0x01
+#define HSI_EVENT_ERROR_MASK 0x02
+
+#define HSI_CH_OPEN 0x1
+
+#define ANY_HSI_CONTROLLER -1
+#define ANY_CHANNEL -1
+#define CHANNEL(channel) (1<<channel)
+
+
+#define HSI_MAX_CHANNELS 8
+#define HSI_MAX_FRAMELEN 32
+
+#define HSIT_CTRLR_ID 0x0
+#define HSIR_CTRLR_ID 0x1
+
+
+extern struct bus_type hsi_bus_type;
+
+enum {
+ HSI_EXCEP_TIMEOUT,
+ HSI_EXCEP_PIPEBUF_OVERRUN,
+ HSI_EXCEP_BREAK_DETECTED,
+ HSI_EXCEP_PARITY_ERROR,
+ HSI_RXCHANNELS_OVERRUN,
+};
+
+
+/** HSI ioctls */
+enum {
+ HSI_IOCTL_SET_WATERMARK,
+ HSI_IOCTL_GET_WATERMARK,
+ HSI_IOCTL_SET_CURRMODE,
+ HSI_IOCTL_GET_CURRMODE,
+ HSI_IOCTL_SEND_BREAK,
+ HSI_IOCTL_SET_FRAMELEN,
+ HSI_IOCTL_GET_FRAMELEN,
+ HSI_IOCTL_SET_THRESHOLD,
+};
+
+struct base_span {
+ u8 base;
+ u8 span;
+};
+
+struct hsi_plat_data {
+ u8 dev_type;
+ u8 mode;
+ u8 parity;
+ u8 priority;
+ u8 channels;
+ u8 threshold;
+ u8 flushbits;
+ u8 dataswap;
+ u8 realtime;
+ u8 detector;
+ u8 framelen;
+ u8 watermark;
+ u8 currmode;
+ gpio_alt_function gpio_alt_func;
+ u32 divisor;
+ u32 burstlen;
+ u32 preamble;
+ u32 timeout;
+ struct base_span ch_base_span[HSI_MAX_CHANNELS];
+ struct stedma40_chan_cfg hsi_dma_info[HSI_MAX_CHANNELS];
+ struct hsi_dev *hsi_ctrlr;
+};
+
+enum hsi_mode{
+ HSI_POLLING_MODE=0x0,
+ HSI_INTERRUPT_MODE,
+ HSI_DMA_MODE,
+};
+
+
+struct hsi_device {
+ int ctrlrid;
+ enum hsi_mode curr_mode;
+ unsigned int chid;
+ char modalias[BUS_ID_SIZE];
+ struct hsi_channel *ch;
+ struct device device;
+};
+
+
+#define to_hsi_device(dev) container_of(dev, struct hsi_device, device)
+
+struct hsi_device_driver {
+ u32 ctrl_mask;
+ u32 ch_mask;
+ u32 excep_mask;
+ void (*excep_event) (unsigned int c_id,
+ unsigned int event, void *arg);
+ int (*probe)(struct hsi_device *dev);
+ int (*remove)(struct hsi_device *dev);
+ int (*suspend)(struct hsi_device *dev,
+ pm_message_t mesg);
+ int (*resume)(struct hsi_device *dev);
+ struct device_driver driver;
+};
+
+
+#define to_hsi_device_driver(drv) container_of(drv, \
+ struct hsi_device_driver, \
+ driver)
+
+int hsi_excep_handler(struct hsi_dev* hsi_ctrlr, unsigned int event, void *arg);
+
+int register_hsi_driver(struct hsi_device_driver *driver);
+void unregister_hsi_driver(struct hsi_device_driver *driver);
+int hsi_open(struct hsi_device *dev);
+int hsi_write(struct hsi_device *dev,void *data, u32 datawidth,unsigned int count);
+void hsi_write_cancel(struct hsi_device *dev);
+int hsi_read(struct hsi_device *dev, void *data, u32 datawidth,unsigned int count);
+void hsi_read_cancel(struct hsi_device *dev);
+int hsi_ioctl(struct hsi_device *dev, unsigned int command, void *arg);
+void hsi_close(struct hsi_device *dev);
+void hsi_dev_set_cb(struct hsi_device *dev, void (*r_cb)(struct hsi_device *dev)
+ , void (*w_cb)(struct hsi_device *dev));
+#endif
diff --git a/include/linux/hsi.h b/include/linux/hsi.h
new file mode 100644
index 00000000000..d6955360b54
--- /dev/null
+++ b/include/linux/hsi.h
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2007 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/ioctl.h>
+
+#include <plat/ste_dma40.h>
+
+#ifndef __HSI_DRIVER_IF_H__
+#define __HSI_DRIVER_IF_H__
+
+#define HSIT_CTRLR_ID 0x0
+#define HSIR_CTRLR_ID 0x1
+
+#define HSI_IOC_MAGIC 'h'
+
+/** HSI ioctls */
+#define HSI_IOC_SET_WATERMARK _IOW(HSI_IOC_MAGIC, 1, __u8)
+#define HSI_IOC_GET_WATERMARK _IOR(HSI_IOC_MAGIC, 1, __u8)
+
+/* Read / Write HSI watermark */
+#define HSI_IOC_SET_MODE _IOW(HSI_IOC_MAGIC, 2, __u8)
+#define HSI_IOC_GET_MODE _IOR(HSI_IOC_MAGIC, 2, __u8)
+
+/* Read / Write HSI device frame length (1..N) */
+#define HSI_IOC_SET_FRAMELEN _IOW(HSI_IOC_MAGIC, 3, __u8)
+#define HSI_IOC_GET_FRAMELEN _IOR(HSI_IOC_MAGIC, 3, __u8)
+
+/* HSI break and threshold settings */
+#define HSI_IOC_SEND_BREAK _IOW(HSI_IOC_MAGIC, 4, __u32)
+#define HSI_IOC_SET_THRESHOLD _IOW(HSI_IOC_MAGIC, 5, __u32)
+
+/* HSI channel operating modes */
+#define HSI_POLLING_MODE 0x00
+#define HSI_INTERRUPT_MODE 0x01
+#define HSI_DMA_MODE 0x02
+
+#define HSI_TYPE_SIZE 32
+
+#ifdef __KERNEL__
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+/** Error events enumeration
+ * Defines the type of errors that are encountered
+ * by a channel. This enumeration is used by the
+ * exception handler of each channel to take appropriate
+ * action.
+**/
+enum {
+ HSI_EXCEP_TIMEOUT,
+ HSI_EXCEP_PIPEBUF_OVERRUN,
+ HSI_EXCEP_BREAK_DETECTED,
+ HSI_EXCEP_PARITY_ERROR,
+ HSI_RXCHANNELS_OVERRUN,
+};
+
+/** struct hsi_device - HSI slave device
+ * @cid - Controller of the device
+ * @chid - Channel on which it transceives
+ * @curr_mode - DMA, Interrupt or Polling
+ * @ch - Channel information of the device
+ * @ctrlr - Controller data of the device
+ * dev - Device represention on sys interface
+ * A @hsi_device is used to interchange data between an HSI slave
+ * (usually a discrete chip) and CPU memory.
+ *
+**/
+struct hsi_device {
+ short cid;
+ short chid;
+ int curr_mode;
+ struct hsi_channel *ch;
+ struct hsi_controller *ctrlr;
+ struct device dev;
+};
+
+#define to_hsi_device(hdev) container_of(hdev, struct hsi_device, dev)
+
+#define hsi_get_platform_data(dev) (dev->platform_data)
+
+/**
+ * struct hsi_device_driver - Host side protocol driver
+ * @ctrl_mask - Controller(s) with which the chip can communicate
+ * @ch_mask - Channels on which the data can be recevied/trasnmitted
+ * @execp_mask - Mask of exceptions that can be handled
+ * @excep_event - Exception handler for the driver
+ *
+**/
+struct hsi_device_driver {
+ u32 ctrl_mask;
+ u32 ch_mask;
+ u32 excep_mask;
+ void (*excep_event) (unsigned int c_id, unsigned int event, void *arg);
+ int (*probe) (struct hsi_device *dev);
+ int (*remove) (struct hsi_device *dev);
+ int (*suspend) (struct hsi_device *dev, pm_message_t state);
+ int (*resume) (struct hsi_device *dev);
+ struct device_driver driver;
+};
+
+/**
+ * struct hsi_data - Payload to be trnasmitted to the controller.
+ * @data - Pointer to virtual memory containing the data
+ * @dma_addr - DMA address of the data source
+ * @datawidth - Framelength of the payload (8, 16, 32 bits)
+ * @count - Size in (framelength) words of the payload
+ * @is_dma - If the address is is dma-able/cacheable in which cache
+ * synchronisation is needed, before dma transfer
+**/
+struct hsi_data {
+ void *data;
+ dma_addr_t dma_addr;
+ int datawidth;
+ int count;
+ int is_dma;
+};
+
+/**
+ * struct hsi_board_info - Platform dependent client information
+ * structure.
+ * @type - Name of the device on HSI bus
+ * @flags - Flags to control operation
+ * @controller_id - Controller on which it resides
+ * @chan_num - Channel number on which it trasnceives
+ * @platform_data - Any platform data to be passed to its driver
+ * @mode - Reception/Transmssion device
+ * @list - To link on devices list of the HSI bus
+**/
+struct hsi_board_info {
+ char type[HSI_TYPE_SIZE];
+ unsigned short flags;
+ unsigned short controller_id;
+ unsigned short chan_num;
+ void *platform_data;
+ int irq;
+ int mode;
+ struct list_head list;
+};
+
+#define HSI_BOARD_INFO(name, flags, cid, chid) \
+ (.type = (name), .flags = (flags), \
+ .controller_id = (cid), .chan_num = (chid))
+
+/*
+ * Callbacks use by the HSI upper layer (HSI protocol) to receive data
+ * from the port channels.
+ */
+struct hsi_channel;
+
+/** struct hsi_channel_ops - Callbacks for channel events
+ * @write_done - Write completion notification
+ * @read_done - Read completion notification
+ * @read - Read routine for interrupt transfers
+ * @write - Write routine for interrupt transfers
+ *
+ * For HSI protocol drivers the callbacks could be used
+ * to wake up processes waiting for channel events. This
+ * means that read/write operations can block
+**/
+struct hsi_channel_ops {
+ void (*write) (struct hsi_channel *ch);
+ void (*read) (struct hsi_channel *ch);
+ void (*write_done) (struct hsi_device *dev);
+ void (*read_done) (struct hsi_device *dev);
+};
+
+struct dma_chan;
+struct stedma40_chan_cfg;
+
+/** struct hsi_channel - Channel information
+ * @id - Controller id this channel belongs to
+ * @read_data - Payload structure contaning buffer
+ * read pointer and length information
+ * @write_data - Payload structure contaning buffer
+ * write pointer and length information
+ * @ctrlr - Pointer to repective controller. Can be
+ * used to access controller algorithms
+ * @flags - Channel opened/busy
+ * @channel_number - Channel id within the controller
+ * @watermark - Programmed watermark level to trigger
+ * transfer
+ * @num_xfer_perintr - Number of transfers to be done
+ * @datawidth - Framelength of the payload
+ * @dma_pipe_id - DMA pipe id for performing DMA
+ * transfers on.
+ * @hsi_dma_info - Structure containing source and
+ * destination information
+ * @span - Span of the channel
+ * @n_bytes - Number of bytes to transfer
+ * @hsi_ch_lock - Channel lock
+ * @dev - Device presenting the channel which attaches
+ * to the controller as child
+ * @hsi_dma_tasklet - Tasklet to schedule on receving transfer
+ * completion
+ * @priv - Private information for the channel
+**/
+
+struct hsi_channel {
+ int id;
+ struct hsi_channel_ops ops;
+ struct hsi_data read_data;
+ struct hsi_data write_data;
+ struct hsi_controller *ctrlr;
+ u8 flags;
+ u8 channel_number;
+ u8 watermark;
+ u8 num_xfer_perintr;
+ u8 datawidth;
+ int dma_pipe_id;
+ struct stedma40_chan_cfg *hsi_dma_info;
+ u8 span;
+ u8 n_bytes;
+ spinlock_t hsi_ch_lock;
+ struct dma_chan *dma_chan;
+ struct hsi_device *dev;
+ struct tasklet_struct hsi_dma_tasklet;
+ void *priv;
+};
+#define HSI_MAX_CHANNELS 8
+struct hsi_backup_regs {
+ u32 framelen[HSI_MAX_CHANNELS];
+ u32 watermark[HSI_MAX_CHANNELS];
+ u32 rx_threshold;
+};
+/** struct hsi_controller - Struct definition to hold information
+ * about hsi controller
+ * @dev_type - Transmitter / receiver interface
+ * @flags - Initialized or exiting
+ * @max_ch - Maximum channels on this controller
+ * @mode - Interrupt / DMA / Polling
+ * @irq1/2 - IRQs for this controller
+ * @irqexcep - Exception interrupt
+ * @irq_choverrun - Array holding channel overrun information
+ * @name - Id for this controller
+ * @regbase - Virtual register address for this controller
+ * @lock - Spinlock for the controller
+ * @hsi_tx_tasklet - TX Tasklet to schedule on trasnfer completion
+ * @hsi_rx_tasklet - RX Tasklet to schedule on trasnfer completion
+ * @hsi_tx_channels - Transmitter channels information for transmitter
+ * @hsi_rx_channels - Receiver channels information for receiver
+ * @algo - Alorithm routines for the controller
+ * @dev - Device information on which registers on the bus
+**/
+struct hsi_controller {
+ u8 dev_type; /** tx or rx */
+ u8 flags;
+ u8 max_ch;
+ u8 mode;
+ u8 irq1;
+ u8 irq2;
+ u8 irqexcep;
+ u8 irq_choverrun[HSI_MAX_CHANNELS];
+ char name[20];
+ void __iomem *regbase;
+ struct clk *clk;
+ spinlock_t lock;
+ u32 tx_wmark_intrstatus;
+ struct tasklet_struct hsi_tx_tasklet;
+ struct tasklet_struct hsi_rx_tasklet;
+ struct tasklet_struct hsi_rxexcep_tasklet;
+ struct hsi_channel hsi_tx_channels[HSI_MAX_CHANNELS];
+ struct hsi_channel hsi_rx_channels[HSI_MAX_CHANNELS];
+ struct hsi_algorithm *algo;
+ struct device *dev;
+ struct hsi_backup_regs backup_regs;
+};
+
+/** struct hsi_ctrlr_excep - Exception information
+ * @ctrlr - Controller on which the exception occured
+ * @event - Type of event
+ * @priv - Private data for execption handler
+**/
+struct hsi_ctrlr_excep {
+ struct hsi_controller *ctrlr;
+ unsigned int event;
+ void *priv;
+};
+
+int hsi_bus_init(void);
+void hsi_bus_exit(void);
+/* End HSI Bus */
+
+#define to_hsi_device_driver(drv) container_of(drv, \
+ struct hsi_device_driver, \
+ driver)
+
+#ifdef CONFIG_HSI
+extern int hsi_register_board_info(struct hsi_board_info const *info, int n);
+#else
+/* board init code may ignore whether HSI is configured or not */
+static inline int
+hsi_register_board_info(struct hsi_board_info const *info, int n)
+{
+ return 0;
+}
+#endif
+
+struct hsi_algorithm {
+ int (*open) (struct hsi_device *dev);
+ int (*write) (struct hsi_device *dev, struct hsi_data *data);
+ int (*read) (struct hsi_device *dev, struct hsi_data *data);
+ int (*ioctl) (struct hsi_device *dev, unsigned int command, void *arg);
+ void (*close) (struct hsi_device *dev);
+ void (*set_cb) (struct hsi_device *dev,
+ void (*r_cb) (struct hsi_device *dev),
+ void (*w_cb) (struct hsi_device *dev));
+ void (*cancel_read) (struct hsi_device *dev);
+ void (*cancel_write) (struct hsi_device *dev);
+ int (*exception_handler) (struct device_driver *driver, void *event);
+
+};
+
+int hsi_excep_handler(struct hsi_controller *hsi, unsigned int event,
+ void *arg);
+
+extern int register_hsi_driver(struct hsi_device_driver *driver);
+extern void unregister_hsi_driver(struct hsi_device_driver *driver);
+extern int hsi_add_controller(struct hsi_controller *hsi_ctrlr);
+extern void hsi_remove_controller(struct hsi_controller *hsi_ctrlr);
+extern int hsi_open(struct hsi_device *dev);
+extern void hsi_close(struct hsi_device *dev);
+extern int hsi_write(struct hsi_device *dev, struct hsi_data *data);
+extern int hsi_read(struct hsi_device *dev, struct hsi_data *data);
+
+extern void hsi_write_cancel(struct hsi_device *dev);
+extern void hsi_read_cancel(struct hsi_device *dev);
+extern void hsi_set_callback(struct hsi_device *dev,
+ void (*r_cb) (struct hsi_device *dev)
+ , void (*w_cb) (struct hsi_device *dev));
+extern int hsi_ioctl(struct hsi_device *dev, unsigned int command, void *arg);
+extern int hsi_exception(struct hsi_controller *hsi_ctrlr, unsigned int event,
+ void *arg);
+
+#endif /* __KERNEL__ */
+
+#endif /* __HSI_H__ */
diff --git a/include/linux/hsi_test_prot.h b/include/linux/hsi_test_prot.h
new file mode 100644
index 00000000000..8e3babb8dd1
--- /dev/null
+++ b/include/linux/hsi_test_prot.h
@@ -0,0 +1,37 @@
+/*----------------------------------------------------------------------------------*/
+/* copyright STMicroelectronics, 2007. */
+/* */
+/* This program is free software; you can redistribute it and/or modify it under */
+/* the terms of the GNU General Public License as published by the Free */
+/* Software Foundation; either version 2.1 of the License, or (at your option) */
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but WITHOUT */
+/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS */
+/* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*----------------------------------------------------------------------------------*/
+
+#ifndef __HSI_TEST_PROT_DRIVER_IF_H__
+#define __HSI_TEST_PROT_DRIVER_IF_H__
+
+#define MAX_CHANNELS_MONITORED 4
+
+struct callback_data {
+ u8 read_done;
+ u8 write_done;
+};
+
+
+int hsi_testprot_drv_open(unsigned char flags);
+int hsi_testprot_drv_read(unsigned int ch,void* data,unsigned int datawidth, unsigned int count);
+int hsi_testprot_drv_read_cancel(unsigned int ch);
+int hsi_testprot_drv_write(unsigned int ch,void* data,unsigned int datawidth, unsigned int count);
+int hsi_testprot_drv_write_cancel(unsigned int ch);
+int hsi_testprot_drv_close(unsigned int ch);
+int hsi_testprot_drv_ioctl(unsigned int ch,unsigned int command,void *arg);
+
+
+#endif
diff --git a/include/linux/hsidev.h b/include/linux/hsidev.h
new file mode 100644
index 00000000000..39f734e4d9a
--- /dev/null
+++ b/include/linux/hsidev.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __HSIDEV_H__
+#define __HSIDEV_H__
+
+#ifdef __KERNEL__
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <mach/debug.h>
+
+#define MAX_CHANNELS_MONITORED 4
+
+#define DRIVER_NAME "HSI LOOPBACK"
+/* enables/disables debug msgs */
+#define DRIVER_DEBUG 0
+/* msg header represents this module */
+#define DRIVER_DEBUG_PFX DRIVER_NAME
+#define DRIVER_DBG KERN_ERR
+
+/** struct hsidev_data - HSI loopback slave device
+ * @devt - Device major and minor number for each channel
+ * @hsidev_lock - Lock protecting the channel from simultaneous
+ * operations.
+ * @wq - Wait queue for processed to sleep for event arrival
+ * @hsi - Slave hsi device representing the channel
+ * @device_entry - To enable insertion into loopback list
+ * @xfer - Structure representing each transfer
+ * @users - Number of users currently
+ * @xfer_done - Flag to indicate trnasfer completion
+**/
+struct hsidev_data {
+ dev_t devt;
+ struct mutex hsidev_lock;
+ wait_queue_head_t wq;
+ struct hsi_device *hsi;
+ struct list_head device_entry;
+ struct hsi_data *xfer;
+ unsigned users;
+ int xfer_done;
+};
+
+#endif
+
+#endif /* __HSIDEV_H__ */
diff --git a/include/linux/hwmem.h b/include/linux/hwmem.h
new file mode 100644
index 00000000000..5163aa97a50
--- /dev/null
+++ b/include/linux/hwmem.h
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * ST-Ericsson HW memory driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef _HWMEM_H_
+#define _HWMEM_H_
+
+#if !defined(__KERNEL__) && !defined(_KERNEL)
+#include <stdint.h>
+#include <sys/types.h>
+#else
+#include <linux/types.h>
+#include <linux/mm_types.h>
+#endif
+
+#define HWMEM_DEFAULT_DEVICE_NAME "hwmem"
+
+/**
+ * @brief Flags defining behavior of allocation
+ */
+enum hwmem_alloc_flags {
+ /**
+ * @brief Buffer will not be cached and not buffered
+ */
+ HWMEM_ALLOC_UNCACHED = (0 << 0),
+ /**
+ * @brief Buffer will be buffered, but not cached
+ */
+ HWMEM_ALLOC_BUFFERED = (1 << 0),
+ /**
+ * @brief Buffer will be cached and buffered, use cache hints to be
+ * more specific
+ */
+ HWMEM_ALLOC_CACHED = (3 << 0),
+ /**
+ * @brief Buffer should be cached write-back in both level 1 and 2 cache
+ */
+ HWMEM_ALLOC_CACHE_HINT_WB = (1 << 2),
+ /**
+ * @brief Buffer should be cached write-through in both level 1 and
+ * 2 cache
+ */
+ HWMEM_ALLOC_CACHE_HINT_WT = (2 << 2),
+ /**
+ * @brief Buffer should be cached write-back in level 1 cache
+ */
+ HWMEM_ALLOC_CACHE_HINT_WB_INNER = (3 << 2),
+ /**
+ * @brief Buffer should be cached write-through in level 1 cache
+ */
+ HWMEM_ALLOC_CACHE_HINT_WT_INNER = (4 << 2),
+ HWMEM_ALLOC_CACHE_HINT_MASK = 0x1C,
+};
+
+/**
+ * @brief Flags defining buffer access mode.
+ */
+enum hwmem_access {
+ /**
+ * @brief Buffer will be read from.
+ */
+ HWMEM_ACCESS_READ = (1 << 0),
+ /**
+ * @brief Buffer will be written to.
+ */
+ HWMEM_ACCESS_WRITE = (1 << 1),
+ /**
+ * @brief Buffer will be imported.
+ */
+ HWMEM_ACCESS_IMPORT = (1 << 2),
+};
+
+/**
+ * @brief Flags defining memory type.
+ */
+enum hwmem_mem_type {
+ /**
+ * @brief Scattered system memory. Currently not supported!
+ */
+ HWMEM_MEM_SCATTERED_SYS = (1 << 0),
+ /**
+ * @brief Contiguous system memory.
+ */
+ HWMEM_MEM_CONTIGUOUS_SYS = (1 << 1),
+};
+
+/**
+ * @brief Values defining memory domain.
+ */
+enum hwmem_domain {
+ /**
+ * @brief This value specifies the neutral memory domain. Setting this
+ * domain will syncronize all supported memory domains (currently CPU).
+ */
+ HWMEM_DOMAIN_SYNC = 0,
+ /**
+ * @brief This value specifies the CPU memory domain.
+ */
+ HWMEM_DOMAIN_CPU = 1,
+};
+
+/**
+ * @brief Structure defining a region of a memory buffer.
+ *
+ * A buffer is defined to contain a number of equally sized blocks. Each block
+ * has a part of it included in the region [<start>-<end>). That is
+ * <end>-<start> bytes. Each block is <size> bytes long. Total number of bytes
+ * in the region is (<end> - <start>) * <count>. First byte of the region is
+ * <skip> * <size> + <start> bytes into the buffer.
+ *
+ * Here's an example of a region in a graphics buffer (X = buffer, R = region):
+ *
+ * XXXXXXXXXXXXXXXXXXXX \
+ * XXXXXXXXXXXXXXXXXXXX |-- skip = 3
+ * XXXXXXXXXXXXXXXXXXXX /
+ * XXRRRRRRRRXXXXXXXXXX \
+ * XXRRRRRRRRXXXXXXXXXX |-- count = 4
+ * XXRRRRRRRRXXXXXXXXXX |
+ * XXRRRRRRRRXXXXXXXXXX /
+ * XXXXXXXXXXXXXXXXXXXX
+ * --| start = 2
+ * ----------| end = 10
+ * --------------------| size = 20
+ */
+struct hwmem_region {
+ /**
+ * @brief Indicates that region starts skip * size bytes from beginning
+ * of buffer.
+ */
+ uint32_t skip;
+ /**
+ * @brief The number of blocks included in this region.
+ */
+ uint32_t count;
+ /**
+ * @brief The index of the first byte included in this block.
+ */
+ uint32_t start;
+ /**
+ * @brief The index of the last byte included in this block plus one.
+ */
+ uint32_t end;
+ /**
+ * @brief The size in bytes of each block.
+ */
+ uint32_t size;
+};
+
+/* User space API */
+
+/**
+ * @brief Alloc request data.
+ */
+struct hwmem_alloc_request {
+ /**
+ * @brief [in] Size of requested allocation in bytes. Size will be
+ * aligned to PAGE_SIZE bytes.
+ */
+ uint32_t size;
+ /**
+ * @brief [in] Flags describing requested allocation options.
+ */
+ uint32_t flags; /* enum hwmem_alloc_flags */
+ /**
+ * @brief [in] Default access rights for buffer.
+ */
+ uint32_t default_access; /* enum hwmem_access */
+ /**
+ * @brief [in] Memory type of the buffer.
+ */
+ uint32_t mem_type; /* enum hwmem_mem_type */
+};
+
+/**
+ * @brief Set domain request data.
+ */
+struct hwmem_set_domain_request {
+ /**
+ * @brief [in] Identifier of buffer to be prepared. If 0 is specified
+ * the buffer associated with the current file instance will be used.
+ */
+ int32_t id;
+ /**
+ * @brief [in] Value specifying the new memory domain.
+ */
+ uint32_t domain; /* enum hwmem_domain */
+ /**
+ * @brief [in] Flags specifying access mode of the operation.
+ *
+ * One of HWMEM_ACCESS_READ and HWMEM_ACCESS_WRITE is required.
+ * For details, @see enum hwmem_access.
+ */
+ uint32_t access; /* enum hwmem_access */
+ /**
+ * @brief [in] The region of bytes to be prepared.
+ *
+ * For details, @see struct hwmem_region.
+ */
+ struct hwmem_region region;
+};
+
+/**
+ * @brief Pin request data.
+ */
+struct hwmem_pin_request {
+ /**
+ * @brief [in] Identifier of buffer to be pinned. If 0 is specified,
+ * the buffer associated with the current file instance will be used.
+ */
+ int32_t id;
+ /**
+ * @brief [out] Physical address of first word in buffer.
+ */
+ uint32_t phys_addr;
+ /**
+ * @brief [in] Pointer to buffer for physical addresses of pinned
+ * scattered buffer. Buffer must be (buffer_size / page_size) *
+ * sizeof(uint32_t) bytes.
+ * This field can be NULL for physically contiguos buffers.
+ */
+ uint32_t *scattered_addrs;
+};
+
+/**
+ * @brief Set access rights request data.
+ */
+struct hwmem_set_access_request {
+ /**
+ * @brief [in] Identifier of buffer to be pinned. If 0 is specified,
+ * the buffer associated with the current file instance will be used.
+ */
+ int32_t id;
+ /**
+ * @param access Access value indicating what is allowed.
+ */
+ uint32_t access; /* enum hwmem_access */
+ /**
+ * @param pid Process ID to set rights for.
+ */
+ pid_t pid;
+};
+
+/**
+ * @brief Get info request data.
+ */
+struct hwmem_get_info_request {
+ /**
+ * @brief [in] Identifier of buffer to get info about. If 0 is specified,
+ * the buffer associated with the current file instance will be used.
+ */
+ int32_t id;
+ /**
+ * @brief [out] Size in bytes of buffer.
+ */
+ uint32_t size;
+ /**
+ * @brief [out] Memory type of buffer.
+ */
+ uint32_t mem_type; /* enum hwmem_mem_type */
+ /**
+ * @brief [out] Access rights for buffer.
+ */
+ uint32_t access; /* enum hwmem_access */
+};
+
+/**
+ * @brief Allocates <size> number of bytes and returns a buffer identifier.
+ *
+ * Input is a pointer to a hwmem_alloc_request struct.
+ *
+ * @return A buffer identifier on success, or a negative error code.
+ */
+#define HWMEM_ALLOC_IOC _IOW('W', 1, struct hwmem_alloc_request)
+
+/**
+ * @brief Allocates <size> number of bytes and associates the created buffer
+ * with the current file instance.
+ *
+ * If the current file instance is already associated with a buffer the call
+ * will fail. Buffers referenced through files instances shall not be released
+ * with HWMEM_RELEASE_IOC, instead the file instance shall be closed.
+ *
+ * Input is a pointer to a hwmem_alloc_request struct.
+ *
+ * @return Zero on success, or a negative error code.
+ */
+#define HWMEM_ALLOC_FD_IOC _IOW('W', 2, struct hwmem_alloc_request)
+
+/**
+ * @brief Releases buffer.
+ *
+ * Buffers are reference counted and will not be destroyed until the last
+ * reference is released. Bufferes allocated with ALLOC_FD_IOC not allowed.
+ *
+ * Input is the buffer identifier.
+ *
+ * @return Zero on success, or a negative error code.
+ */
+#define HWMEM_RELEASE_IOC _IO('W', 3)
+
+/**
+ * @brief Set the buffer's memory domain and prepares it for access.
+ *
+ * Input is a pointer to a hwmem_set_domain_request struct.
+ *
+ * @return Zero on success, or a negative error code.
+ */
+#define HWMEM_SET_DOMAIN_IOC _IOR('W', 4, struct hwmem_set_domain_request)
+
+/**
+ * @brief Pins the buffer and returns the physical address of the buffer.
+ *
+ * @return Zero on success, or a negative error code.
+ */
+#define HWMEM_PIN_IOC _IOWR('W', 5, struct hwmem_pin_request)
+
+/**
+ * @brief Unpins the buffer.
+ *
+ * @return Zero on success, or a negative error code.
+ */
+#define HWMEM_UNPIN_IOC _IO('W', 6)
+
+/**
+ * @brief Set access rights for buffer.
+ *
+ * @return Zero on success, or a negative error code.
+ */
+#define HWMEM_SET_ACCESS_IOC _IOW('W', 7, struct hwmem_set_access_request)
+
+/**
+ * @brief Get buffer information.
+ *
+ * Input is the buffer identifier. If 0 is specified the buffer associated
+ * with the current file instance will be used.
+ *
+ * @return Zero on success, or a negative error code.
+ */
+#define HWMEM_GET_INFO_IOC _IOWR('W', 8, struct hwmem_get_info_request)
+
+/**
+ * @brief Export the buffer identifier for use in another process.
+ *
+ * The global name will not increase the buffers reference count and will
+ * therefore not keep the buffer alive.
+ *
+ * Input is the buffer identifier. If 0 is specified the buffer associated with
+ * the current file instance will be exported.
+ *
+ * @return A global buffer name on success, or a negative error code.
+ */
+#define HWMEM_EXPORT_IOC _IO('W', 9)
+
+/**
+ * @brief Import a buffer to allow local access to the buffer.
+ *
+ * Input is the buffer's global name.
+ *
+ * @return The imported buffer's identifier on success, or a negative error code.
+ */
+#define HWMEM_IMPORT_IOC _IO('W', 10)
+
+/**
+ * @brief Import a buffer to allow local access to the buffer using fd.
+ *
+ * Input is the buffer's global name.
+ *
+ * @return Zero on success, or a negative error code.
+ */
+#define HWMEM_IMPORT_FD_IOC _IO('W', 11)
+
+#ifdef __KERNEL__
+
+/* Kernel API */
+
+struct hwmem_alloc;
+
+/**
+ * @brief Allocates <size> number of bytes.
+ *
+ * @param size Number of bytes to allocate. All allocations are page aligned.
+ * @param flags Allocation options.
+ * @param def_access Default buffer access rights.
+ * @param mem_type Memory type.
+ *
+ * @return Pointer to allocation, or a negative error code.
+ */
+struct hwmem_alloc *hwmem_alloc(u32 size, enum hwmem_alloc_flags flags,
+ enum hwmem_access def_access, enum hwmem_mem_type mem_type);
+
+/**
+ * @brief Release a previously allocated buffer.
+ * When last reference is released, the buffer will be freed.
+ *
+ * @param alloc Buffer to be released.
+ */
+void hwmem_release(struct hwmem_alloc *alloc);
+
+/**
+ * @brief Set the buffer domain and prepare it for access.
+ *
+ * @param alloc Buffer to be prepared.
+ * @param access Flags defining memory access mode of the call.
+ * @param domain Value specifying the memory domain.
+ * @param region Structure defining the minimum area of the buffer to be
+ * prepared.
+ *
+ * @return Zero on success, or a negative error code.
+ */
+int hwmem_set_domain(struct hwmem_alloc *alloc, enum hwmem_access access,
+ enum hwmem_domain domain, struct hwmem_region *region);
+
+/**
+ * @brief Pins the buffer.
+ *
+ * @param alloc Buffer to be pinned.
+ * @param phys_addr Reference to variable to receive physical address.
+ * @param scattered_phys_addrs Pointer to buffer to receive physical addresses
+ * of all pages in the scattered buffer. Can be NULL if buffer is contigous.
+ * Buffer size must be (buffer_size / page_size) * sizeof(uint32_t) bytes.
+ */
+int hwmem_pin(struct hwmem_alloc *alloc, uint32_t *phys_addr,
+ uint32_t *scattered_phys_addrs);
+
+/**
+ * @brief Unpins the buffer.
+ *
+ * @param alloc Buffer to be unpinned.
+ */
+void hwmem_unpin(struct hwmem_alloc *alloc);
+
+/**
+ * @brief Map the buffer to user space.
+ *
+ * @param alloc Buffer to be unpinned.
+ */
+int hwmem_mmap(struct hwmem_alloc *alloc, struct vm_area_struct *vma);
+
+/**
+ * @brief Set access rights for buffer.
+ *
+ * @param alloc Buffer to set rights for.
+ * @param access Access value indicating what is allowed.
+ * @param pid Process ID to set rights for.
+ */
+int hwmem_set_access(struct hwmem_alloc *alloc, enum hwmem_access access,
+ pid_t pid);
+
+/**
+ * @brief Get buffer information.
+ *
+ * @param alloc Buffer to get information about.
+ * @param size Pointer to size output variable.
+ * @param size Pointer to memory type output variable.
+ * @param size Pointer to access rights output variable.
+ */
+void hwmem_get_info(struct hwmem_alloc *alloc, uint32_t *size,
+ enum hwmem_mem_type *mem_type, enum hwmem_access *access);
+
+/**
+ * @brief Allocate a global buffer name.
+ * Generated buffer name is valid in all processes. Consecutive calls will get
+ * the same name for the same buffer.
+ *
+ * @param alloc Buffer to be made public.
+ *
+ * @return Positive global name on success, or a negative error code.
+ */
+int hwmem_get_name(struct hwmem_alloc *alloc);
+
+/**
+ * @brief Import the global buffer name to allow local access to the buffer.
+ * This call will add a buffer reference. Resulting buffer should be
+ * released with a call to hwmem_release.
+ *
+ * @param name A valid global buffer name.
+ *
+ * @return Pointer to allocation, or a negative error code.
+ */
+struct hwmem_alloc *hwmem_resolve_by_name(s32 name);
+
+/* Internal */
+
+struct hwmem_platform_data {
+ /* Starting physical address of memory region */
+ unsigned long start;
+ /* Size of memory region */
+ unsigned long size;
+};
+
+#endif
+
+#endif /* _HWMEM_H_ */
diff --git a/include/linux/i2c/lp5521.h b/include/linux/i2c/lp5521.h
new file mode 100644
index 00000000000..0e0e9d3b678
--- /dev/null
+++ b/include/linux/i2c/lp5521.h
@@ -0,0 +1,43 @@
+/*
+ * lp5521.h - header for LP5521 LED driver
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Felipe Balbi <felipe.balbi@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __LP5521_H_
+#define __LP5521_H_
+
+enum lp5521_mode {
+ LP5521_MODE_LOAD,
+ LP5521_MODE_RUN,
+ LP5521_MODE_DIRECT_CONTROL,
+};
+
+struct lp5521_platform_data {
+ enum lp5521_mode mode;
+
+ unsigned red_present:1;
+ unsigned green_present:1;
+ unsigned blue_present:1;
+
+ const char *label;
+};
+
+#endif /* End of __LP5521_H */
diff --git a/include/linux/i2s/i2s.h b/include/linux/i2s/i2s.h
new file mode 100644
index 00000000000..adf49615155
--- /dev/null
+++ b/include/linux/i2s/i2s.h
@@ -0,0 +1,202 @@
+/*----------------------------------------------------------------------------*/
+/* copyright STMicroelectronics, 2007. */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the Free */
+/* Software Foundation; either version 2.1 of the License, or (at your option)*/
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY */
+/* or FITNESS */
+/* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more */
+/* details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+/*----------------------------------------------------------------------------*/
+
+#ifndef __LINUX_I2S_H
+#define __LINUX_I2S_H
+
+/*
+ * INTERFACES between I2S controller-side drivers and I2S infrastructure.
+ */
+extern struct bus_type i2s_bus_type;
+#define I2S_NAME_SIZE 48
+/**
+ * struct i2s_device - Controller side proxy for an I2S slave device
+ * @dev: Driver model representation of the device.
+ * @controller: I2S controller used with the device.
+ * @chip_select: Chipselect, distinguishing chips handled by @controller.
+ * @modalias: Name of the driver to use with this device, or an alias
+ * for that name. This appears in the sysfs "modalias" attribute
+ * for driver coldplugging, and in uevents used for hotplugging
+ *
+ * A @i2s_device is used to interchange data between an I2S slave
+ *
+ * In @dev, the platform_data is used to hold information about this
+ * device that's meaningful to the device's protocol driver, but not
+ * to its controller.
+ */
+struct i2s_device {
+ struct device dev;
+ struct i2s_controller *controller;
+ u8 chip_select;
+ char modalias[32];
+};
+struct i2s_board_info {
+ /* the device name and module name are coupled, like platform_bus;
+ * "modalias" is normally the driver name.
+ *
+ * platform_data goes to i2s_device.dev.platform_data,
+ */
+ char modalias[32];
+ const void *platform_data;
+ u16 id;
+ u16 chip_select;
+};
+
+#ifdef CONFIG_STM_I2S
+extern int
+i2s_register_board_info(struct i2s_board_info const *info, unsigned n);
+#else
+/* board init code may ignore whether I2S is configured or not */
+static inline int
+i2s_register_board_info(struct i2s_board_info const *info, unsigned n)
+{
+ return 0;
+}
+#endif
+
+static inline struct i2s_device *to_i2s_device(struct device *dev)
+{
+ return dev ? container_of(dev, struct i2s_device, dev) : NULL;
+}
+
+static inline struct i2s_device *i2s_dev_get(struct i2s_device *i2s)
+{
+ return (i2s && get_device(&i2s->dev)) ? i2s : NULL;
+}
+
+static inline void i2s_dev_put(struct i2s_device *i2s)
+{
+ if (i2s)
+ put_device(&i2s->dev);
+}
+
+static inline void i2s_set_drvdata(struct i2s_device *i2s, void *data)
+{
+ dev_set_drvdata(&i2s->dev, data);
+}
+
+static inline void *i2s_get_drvdata(struct i2s_device *i2s)
+{
+ return dev_get_drvdata(&i2s->dev);
+}
+
+struct i2s_device_id {
+ char name[I2S_NAME_SIZE];
+ /*currently not used may be used in future */
+ u32 device_id;
+ u32 vendor_id;
+};
+
+/**
+ * struct i2s_driver - Host side "protocol" driver
+ */
+struct i2s_driver {
+ int (*probe) (struct i2s_device * i2s);
+ int (*remove) (struct i2s_device * i2s);
+ void (*shutdown) (struct i2s_device * i2s);
+ int (*suspend) (struct i2s_device * i2s, pm_message_t mesg);
+ int (*resume) (struct i2s_device * i2s);
+ struct device_driver driver;
+ const struct i2s_device_id *id_table;
+
+};
+
+static inline struct i2s_driver *to_i2s_driver(struct device_driver *drv)
+{
+ return drv ? container_of(drv, struct i2s_driver, driver) : NULL;
+}
+
+extern int i2s_register_driver(struct i2s_driver *sdrv);
+
+/**
+ * i2s_unregister_driver - reverse effect of i2s_register_driver
+ * @sdrv: the driver to unregister
+ * Context: can sleep
+ */
+static inline void i2s_unregister_driver(struct i2s_driver *sdrv)
+{
+ if (sdrv)
+ driver_unregister(&sdrv->driver);
+}
+
+/**I2S controller parameters*/
+
+struct i2s_message {
+ size_t rxbytes;
+ size_t txbytes;
+ void *txdata;
+ void *rxdata;
+ int dma_flag;
+ int tx_offset;
+ int rx_offset;
+ int inf_loopback_xfer;
+};
+
+typedef enum {
+ DISABLE_ALL = 0,
+ DISABLE_TRANSMIT = 1,
+ DISABLE_RECEIVE = 2,
+} i2s_flag;
+
+struct i2s_algorithm {
+ int (*cont_setup) (struct i2s_controller * i2s_cont, void *config);
+ int (*cont_transfer) (struct i2s_controller * i2s_cont,
+ struct i2s_message * message);
+ int (*cont_cleanup) (struct i2s_controller * i2s_cont, i2s_flag flag);
+};
+
+struct i2s_controller {
+ struct module *owner;
+ unsigned int id;
+ unsigned int class;
+ const struct i2s_algorithm *algo; /* the algorithm to access the bus */
+ void *data;
+ struct mutex bus_lock;
+ struct device dev; /* the controller device */
+ char name[48];
+};
+#define to_i2s_controller(d) container_of(d, struct i2s_controller, dev)
+
+static inline void *i2s_get_contdata(struct i2s_controller *dev)
+{
+ return dev_get_drvdata(&dev->dev);
+}
+
+static inline void i2s_set_contdata(struct i2s_controller *dev, void *data)
+{
+ dev_set_drvdata(&dev->dev, data);
+}
+
+extern int i2s_add_controller(struct i2s_controller *controller);
+extern int i2s_del_controller(struct i2s_controller *controller);
+extern int i2s_cleanup(struct i2s_controller *i2s_cont, i2s_flag flag);
+extern int i2s_transfer(struct i2s_controller *i2s_cont,
+ struct i2s_message *message);
+extern int i2s_setup(struct i2s_controller *i2s_cont, void *config);
+
+extern struct i2s_device *i2s_alloc_device(struct device *dev);
+
+extern int i2s_add_device(struct i2s_device *i2s);
+
+static inline void i2s_unregister_device(struct i2s_device *i2s)
+{
+ if (i2s)
+ device_unregister(&i2s->dev);
+}
+
+#endif /* __LINUX_I2S_H */
diff --git a/include/linux/i2s/i2s_test_prot.h b/include/linux/i2s/i2s_test_prot.h
new file mode 100644
index 00000000000..8e63e0632a0
--- /dev/null
+++ b/include/linux/i2s/i2s_test_prot.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms:
+ *
+ * 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 __I2S_TEST_PROT_DRIVER_IF_H__
+#define __I2S_TEST_PROT_DRIVER_IF_H__
+#include <mach/msp.h>
+struct test_prot_config {
+ u32 tx_config_desc;
+ u32 rx_config_desc;
+ u32 frame_freq;
+ u32 frame_size;
+ u32 data_size;
+ u32 direction;
+ u32 protocol;
+ u32 work_mode;
+ struct msp_protocol_desc protocol_desc;
+ int (*handler) (void *data, int irq);
+ void *tx_callback_data;
+ void *rx_callback_data;
+ int multichannel_configured;
+ struct msp_multichannel_config multichannel_config;
+};
+
+int i2s_testprot_drv_open(int i2s_device_num);
+int i2s_testprot_drv_configure(int i2s_device_num,
+ struct test_prot_config *config);
+int i2s_config_default_protocol(int i2s_device_num,
+ struct test_prot_config *config);
+int __i2s_testprot_drv_configure(int i2s_device_num,
+ struct test_prot_config *config,
+ bool use_default);
+int i2s_testprot_drv_transfer(int i2s_device_num, void *txdata, size_t txbytes,
+ void *rxdata, size_t rxbytes);
+int i2s_testprot_drv_inf_loopback(int i2s_device_num, void *txdata,
+ size_t txbytes, void *rxdata, size_t rxbytes);
+int i2s_testprot_drv_close(int i2s_device_num);
+
+#endif
diff --git a/include/linux/input/bu21013.h b/include/linux/input/bu21013.h
new file mode 100644
index 00000000000..e3e0ed795e6
--- /dev/null
+++ b/include/linux/input/bu21013.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * License terms:GNU General Public License (GPL) version 2
+ */
+
+#ifndef _BU21013_H
+#define _BU21013_H
+
+/*
+ * Touch screen register offsets
+ */
+#define BU21013_SENSORS_BTN_0_7_REG 0x70
+#define BU21013_SENSORS_BTN_8_15_REG 0x71
+#define BU21013_SENSORS_BTN_16_23_REG 0x72
+#define BU21013_X1_POS_MSB_REG 0x73
+#define BU21013_X1_POS_LSB_REG 0x74
+#define BU21013_Y1_POS_MSB_REG 0x75
+#define BU21013_Y1_POS_LSB_REG 0x76
+#define BU21013_X2_POS_MSB_REG 0x77
+#define BU21013_X2_POS_LSB_REG 0x78
+#define BU21013_Y2_POS_MSB_REG 0x79
+#define BU21013_Y2_POS_LSB_REG 0x7A
+#define BU21013_INT_CLR_REG 0xE8
+#define BU21013_INT_MODE_REG 0xE9
+#define BU21013_GAIN_REG 0xEA
+#define BU21013_OFFSET_MODE_REG 0xEB
+#define BU21013_XY_EDGE_REG 0xEC
+#define BU21013_RESET_REG 0xED
+#define BU21013_CALIB_REG 0xEE
+#define BU21013_DONE_REG 0xEF
+#define BU21013_SENSOR_0_7_REG 0xF0
+#define BU21013_SENSOR_8_15_REG 0xF1
+#define BU21013_SENSOR_16_23_REG 0xF2
+#define BU21013_POS_MODE1_REG 0xF3
+#define BU21013_POS_MODE2_REG 0xF4
+#define BU21013_CLK_MODE_REG 0xF5
+#define BU21013_IDLE_REG 0xFA
+#define BU21013_FILTER_REG 0xFB
+#define BU21013_TH_ON_REG 0xFC
+#define BU21013_TH_OFF_REG 0xFD
+
+/*
+ * Touch screen register offset values
+ */
+#define BU21013_RESET_ENABLE 0x01
+
+/* Sensors Configuration */
+#define BU21013_SENSORS_EN_0_7 0x3F
+#define BU21013_SENSORS_EN_8_15 0xFC
+#define BU21013_SENSORS_EN_16_23 0x1F
+
+/* Position mode1 */
+#define BU21013_POS_MODE1_0 0x02
+#define BU21013_POS_MODE1_1 0x04
+#define BU21013_POS_MODE1_2 0x08
+
+/* Position mode2 */
+#define BU21013_POS_MODE2_ZERO 0x01
+#define BU21013_POS_MODE2_AVG1 0x02
+#define BU21013_POS_MODE2_AVG2 0x04
+#define BU21013_POS_MODE2_EN_XY 0x08
+#define BU21013_POS_MODE2_EN_RAW 0x10
+#define BU21013_POS_MODE2_MULTI 0x80
+
+/* Clock mode */
+#define BU21013_CLK_MODE_DIV 0x01
+#define BU21013_CLK_MODE_EXT 0x02
+#define BU21013_CLK_MODE_CALIB 0x80
+
+/* IDLE time */
+#define BU21013_IDLET_0 0x01
+#define BU21013_IDLET_1 0x02
+#define BU21013_IDLET_2 0x04
+#define BU21013_IDLET_3 0x08
+#define BU21013_IDLE_INTERMIT_EN 0x10
+
+/* FILTER reg values */
+#define BU21013_DELTA_0_6 0x7F
+#define BU21013_FILTER_EN 0x80
+
+/* interrupt mode */
+#define BU21013_INT_MODE_LEVEL 0x00
+#define BU21013_INT_MODE_EDGE 0x01
+
+/* Gain reg values */
+#define BU21013_GAIN_0 0x01
+#define BU21013_GAIN_1 0x02
+#define BU21013_GAIN_2 0x04
+
+/* OFFSET mode */
+#define BU21013_OFFSET_MODE_DEFAULT 0x00
+#define BU21013_OFFSET_MODE_MOVE 0x01
+#define BU21013_OFFSET_MODE_DISABLE 0x02
+
+/* Threshold ON values */
+#define BU21013_TH_ON_0 0x01
+#define BU21013_TH_ON_1 0x02
+#define BU21013_TH_ON_2 0x04
+#define BU21013_TH_ON_3 0x08
+#define BU21013_TH_ON_4 0x10
+#define BU21013_TH_ON_5 0x20
+#define BU21013_TH_ON_6 0x40
+#define BU21013_TH_ON_7 0x80
+#define BU21013_TH_ON_MAX 0xFF
+
+/* Threshold OFF values */
+#define BU21013_TH_OFF_0 0x01
+#define BU21013_TH_OFF_1 0x02
+#define BU21013_TH_OFF_2 0x04
+#define BU21013_TH_OFF_3 0x08
+#define BU21013_TH_OFF_4 0x10
+#define BU21013_TH_OFF_5 0x20
+#define BU21013_TH_OFF_6 0x40
+#define BU21013_TH_OFF_7 0x80
+#define BU21013_TH_OFF_MAX 0xFF
+
+/* FILTER reg values */
+#define BU21013_X_EDGE_0 0x01
+#define BU21013_X_EDGE_1 0x02
+#define BU21013_X_EDGE_2 0x04
+#define BU21013_X_EDGE_3 0x08
+#define BU21013_Y_EDGE_0 0x10
+#define BU21013_Y_EDGE_1 0x20
+#define BU21013_Y_EDGE_2 0x40
+#define BU21013_Y_EDGE_3 0x80
+
+#define BU21013_DONE 0x01
+#define BU21013_NUMBER_OF_X_SENSORS (6)
+#define BU21013_NUMBER_OF_Y_SENSORS (11)
+
+/**
+ * struct bu21013_platform_device - Handle the platform data
+ * @cs_en: pointer to the cs enable function
+ * @cs_dis: pointer to the cs disable function
+ * @irq_read_val: pointer to read the pen irq value function
+ * @x_max_res: xmax resolution
+ * @y_max_res: ymax resolution
+ * @touch_x_max: touch x max
+ * @touch_y_max: touch y max
+ * @tp_cntl: controller id
+ * @cs_pin: chip select pin
+ * @irq: irq pin
+ * @ext_clk_en: external clock flag
+ * @portrait: portrait mode flag
+ * @x_flip: x flip flag
+ * @y_flip: y flip flag
+ * This is used to handle the platform data
+ **/
+struct bu21013_platform_device {
+ int (*cs_en)(int reset_pin);
+ int (*cs_dis)(int reset_pin);
+ int (*irq_read_val)(void);
+ int x_max_res;
+ int y_max_res;
+ int touch_x_max;
+ int touch_y_max;
+ int tp_cntl;
+ unsigned int cs_pin;
+ unsigned int irq;
+ bool portrait;
+ bool ext_clk;
+ bool x_flip;
+ bool y_flip;
+};
+
+#endif
diff --git a/include/linux/input/synaptics_i2c_rmi4.h b/include/linux/input/synaptics_i2c_rmi4.h
new file mode 100644
index 00000000000..d299f765fcb
--- /dev/null
+++ b/include/linux/input/synaptics_i2c_rmi4.h
@@ -0,0 +1,269 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver.
+ * Copyright (c) 2007-2010, Synaptics Incorporated
+ *
+ * Author: Js HA <js.ha@stericsson.com> for ST-Ericsson
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Copyright 2010 (c) ST-Ericsson AB
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ *#############################################################################
+ */
+
+#ifndef _SYNAPTICS_RMI4_H_INCLUDED_
+#define _SYNAPTICS_RMI4_H_INCLUDED_
+
+#include <linux/workqueue.h>
+
+#define RMI4_TOUCH_MAX_PRESSURE (1)
+#define RMI4_TOUCH_MAX_TOOL_WIDTH (15)
+#define RMI4_TOUCH_MAX_TOUCH_MAJOR (255)
+#define RMI4_TOUCH_MAX_TOUCH_MINOR (15)
+
+#define MASK_16BIT 0xFFFF
+#define MASK_8BIT 0xFF
+#define MASK_7BIT 0x7F
+#define MASK_5BIT 0x1F
+#define MASK_4BIT 0x0F
+#define MASK_3BIT 0x07
+#define MASK_2BIT 0x03
+#define RMI4_TOUCH_POLLING_TIME_IN_IDLE (13000000)
+#define RMI4_TOUCH_POLLING_TIME_IN_PRESSED (3000000)
+#define RMI4_TOUCH_REPORT_RATE_80 (0)
+#define RMI4_TOUCH_REPORT_RATE_40 (1 << 6)
+#define RMI4_FUNCTION_HANDLER_TABLE_SIZE (1)
+#define RMI4_NUMBER_OF_MAX_FINGERS (8)
+#define SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM (0x11)
+#define SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM (0x01)
+
+/**
+ * struct synaptics_rmi4_fn_desc - contains the funtion descriptor information
+ * @query_base_addr: base address for query
+ * @cmd_base_addr: base address for command
+ * @ctrl_base_addr: base address for control
+ * @data_base_addr: base address for data
+ * @intr_src_count: count for the interrupt source
+ * @fn_number: function number
+ * This structure is used to gives the function descriptor information
+ * of the particular functionality.
+ */
+struct synaptics_rmi4_fn_desc {
+ unsigned char query_base_addr;
+ unsigned char cmd_base_addr;
+ unsigned char ctrl_base_addr;
+ unsigned char data_base_addr;
+ unsigned char intr_src_count;
+ unsigned char fn_number;
+};
+/**
+ * struct synaptics_rmi4_fn - contains the funtion information
+ * @fn_number: function number
+ * @num_of_data_sources: number of data sources
+ * @num_of_data_points: number of fingers touched
+ * @size_of_data_register_block: data register block size
+ * @index_to_intr_reg: index for interrupt register
+ * @intr_mask: interrupt mask value
+ * @fn_desc: variable for function descriptor structure
+ * @link: linked list for function descriptors
+ * This structure gives information about the number of data sources and
+ * the number of data registers associated with the function.
+ */
+struct synaptics_rmi4_fn {
+ unsigned char fn_number;
+ unsigned char num_of_data_sources;
+ unsigned char num_of_data_points;
+ unsigned char size_of_data_register_block;
+ unsigned char index_to_intr_reg;
+ unsigned char intr_mask;
+ struct synaptics_rmi4_fn_desc fn_desc;
+ struct list_head link;
+};
+/**
+ * struct synaptics_rmi4_device_info - contains the rmi4 device information
+ * @version_major: protocol major version number
+ * @version_minor: protocol minor version number
+ * @manufacturer_id: manufacturer identification byte
+ * @product_props: product properties information
+ * @product_info: product info array
+ * @date_code: device manufacture date
+ * @tester_id: tester id array
+ * @serial_number: serial number for that device
+ * @product_id_string: product id for the device
+ * @support_fn_list: linked list for device information
+ * This structure gives information about the number of data sources and
+ * the number of data registers associated with the function.
+ */
+struct synaptics_rmi4_device_info {
+ unsigned int version_major;
+ unsigned int version_minor;
+ unsigned char manufacturer_id;
+ unsigned char product_props;
+ unsigned char product_info[2];
+ unsigned char date_code[3];
+ unsigned short tester_id;
+ unsigned short serial_number;
+ unsigned char product_id_string[11];
+ struct list_head support_fn_list;
+};
+
+/**
+ * struct synaptics_rmi4_platform_data - contains the rmi4 platform data
+ * @irq_number: irq number
+ * @irq_type: irq type
+ * @x_max_res: maximum display x resolution
+ * @y_max_res: maximum display y resolution
+ * @portrait_mode: portrait mode flag
+ * @x flip: x flip flag
+ * @y flip: y flip flag
+ * This structure gives platform data for rmi4.
+ */
+struct synaptics_rmi4_platform_data {
+ int irq_number;
+ int irq_type;
+ int x_max_res;
+ int y_max_res;
+ bool portrait_mode;
+ bool x_flip;
+ bool y_flip;
+};
+
+/**
+ * struct synaptics_rmi4_i2c_data - contains the rmi4 i2c data
+ * @num_clients: i2c address
+ * @platformdata: pointer for platform data
+ * This structure gives i2c data for rmi4.
+ */
+struct synaptics_rmi4_i2c_data {
+ int num_clients;
+ struct synaptics_rmi4_platform_data *platformdata;
+};
+
+/**
+ * struct synaptics_rmi4_data - contains the rmi4 device data
+ * @rmi4_mod_info: structure variable for rmi4 device info
+ * @work: structure variable for work
+ * @timer: structure variable for hrtimer
+ * @input_dev: pointer for input device
+ * @i2c_client: pointer for i2c client
+ * @fn_list_mutex: mutex for funtion list
+ * @rmi4_page_mutex: mutex for rmi4 page
+ * @polling_required: polling mode flag
+ * @irq_number: interrupt number
+ * @irq_type: irq type
+ * @instance_number: instance number
+ * @current_page: variable for integer
+ * @number_of_interrupt_register: interrupt registers count
+ * @fn01_ctrl_base_addr: control base address for fn01
+ * @fn01_query_base_addr: query base address for fn01
+ * @fn01_data_base_addr: data base address for fn01
+ * @sensor_max_x: sensor maximum x value
+ * @sensor_max_y: sensor maximum y value
+ * @touch_pressed: touch pressed variable
+ * @factor_x: scale factor for x
+ * @factor_y: scale factor for y
+ * @x: array for number of x values
+ * @y: array for number of y values
+ * @wx: array for number of wx values
+ * @wy: array for number of wy values
+ * @x_max_res: maximum display x resolution
+ * @y_max_res: maximum display y resolution
+ * @portrait_mode: portrait mode flag
+ * @x flip: x flip flag
+ * @y flip: y flip flag
+ * @byte_read: function pointer to byte read
+ * @byte_write: function pointer to byte write
+ * @block_read: function pointer to block read
+ * @block_write: function pointer to block write
+ * This structure gives the device data information.
+ */
+struct synaptics_rmi4_data {
+ struct synaptics_rmi4_device_info rmi4_mod_info;
+ struct work_struct work;
+ struct hrtimer timer;
+ struct input_dev *input_dev;
+ struct i2c_client *i2c_client;
+ struct mutex fn_list_mutex;
+ struct mutex rmi4_page_mutex;
+ bool polling_required;
+ int irq_number;
+ int irq_type;
+ int instance_number;
+ int current_page;
+ unsigned int number_of_interrupt_register;
+ unsigned short fn01_ctrl_base_addr;
+ unsigned short fn01_query_base_addr;
+ unsigned short fn01_data_base_addr;
+ int sensor_max_x;
+ int sensor_max_y;
+ int touch_pressed;
+ int factor_x;
+ int factor_y;
+ int x[RMI4_NUMBER_OF_MAX_FINGERS];
+ int y[RMI4_NUMBER_OF_MAX_FINGERS];
+ int z[RMI4_NUMBER_OF_MAX_FINGERS];
+ int wx[RMI4_NUMBER_OF_MAX_FINGERS];
+ int wy[RMI4_NUMBER_OF_MAX_FINGERS];
+ int x_max_res;
+ int y_max_res;
+ bool portrait_mode;
+ bool x_flip;
+ bool y_flip;
+ int (*byte_read)(struct synaptics_rmi4_data *pdata,
+ unsigned short address,
+ unsigned char *valp);
+ int (*byte_write)(struct synaptics_rmi4_data *pdata,
+ unsigned short address,
+ unsigned char valp);
+ int (*block_read)(struct synaptics_rmi4_data *pdata,
+ unsigned short address,
+ unsigned char *valp, int size);
+ int (*block_write)(struct synaptics_rmi4_data *pdata,
+ unsigned short address,
+ unsigned char *valp, int size);
+};
+
+/**
+ * struct synaptics_rmi4_funtion_handler - contains rmi4 i2c function handlers
+ * @num_clients: i2c address
+ * @platformdata: pointer for platform data
+ * This structure is used to hold the rmi4 i2c function handlers for a
+ * particular funtionality.
+ */
+struct synaptics_rmi4_function_handler {
+ int fn_number;
+ int (*pfunc_report)(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi);
+ int (*pfunc_config)(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi);
+ int (*pfunc_init)(struct synaptics_rmi4_data *pdata);
+ int (*pfunc_detect)(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int interrupt_count);
+};
+
+int synpatics_rmi4_touchpad_report(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi);
+int synpatics_rmi4_touchpad_config(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi);
+int synpatics_rmi4_touchpad_init(struct synaptics_rmi4_data *pdata);
+int synpatics_rmi4_touchpad_detect(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int interruptcount);
+#endif
diff --git a/include/linux/leds_pwm.h b/include/linux/leds_pwm.h
index 33a07116748..9c5eab6e086 100644
--- a/include/linux/leds_pwm.h
+++ b/include/linux/leds_pwm.h
@@ -11,6 +11,7 @@ struct led_pwm {
u8 active_low;
unsigned max_brightness;
unsigned pwm_period_ns;
+ unsigned int lth_brightness;
};
struct led_pwm_platform_data {
diff --git a/include/linux/lsm303dlh.h b/include/linux/lsm303dlh.h
new file mode 100644
index 00000000000..b13e086ea7c
--- /dev/null
+++ b/include/linux/lsm303dlh.h
@@ -0,0 +1,117 @@
+/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
+*
+* File Name : lsm303dlh.h
+* Authors : MH - C&I BU - Application Team
+* : Carmine Iascone (carmine.iascone@st.com)
+* : Matteo Dameno (matteo.dameno@st.com)
+* Version : V 0.3
+* Date : 24/02/2010
+*
+********************************************************************************
+*
+* Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+* Copyright 2010 (c) ST-Ericsson AB
+*
+********************************************************************************
+*
+* 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.
+*
+* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
+* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE
+* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*
+* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
+*
+*******************************************************************************/
+
+#ifndef __LSM303DLH_H__
+#define __LSM303DLH_H__
+
+#include <linux/ioctl.h>
+
+#define LSM303DLH_IOCTL_BASE 0xA2
+
+/* Accelerometer IOCTLs */
+#define LSM303DLH_A_SET_RANGE _IOW(LSM303DLH_IOCTL_BASE, 1, char)
+#define LSM303DLH_A_SET_MODE _IOW(LSM303DLH_IOCTL_BASE, 2, char)
+#define LSM303DLH_A_SET_RATE _IOW(LSM303DLH_IOCTL_BASE, 3, char)
+#define LSM303DLH_A_GET_MODE _IOR(LSM303DLH_IOCTL_BASE, 4, char)
+
+/* Magnetometer IOCTLs */
+#define LSM303DLH_M_SET_RANGE _IOW(LSM303DLH_IOCTL_BASE, 11, char)
+#define LSM303DLH_M_SET_MODE _IOW(LSM303DLH_IOCTL_BASE, 12, char)
+#define LSM303DLH_M_SET_RATE _IOW(LSM303DLH_IOCTL_BASE, 13, char)
+#define LSM303DLH_M_GET_GAIN _IOR(LSM303DLH_IOCTL_BASE, 14, short[3])
+#define LSM303DLH_M_GET_MODE _IOR(LSM303DLH_IOCTL_BASE, 15, char)
+
+/* ioctl: LSM303DLH_A_SET_RANGE */
+#define LSM303DLH_A_RANGE_2G 0x00
+#define LSM303DLH_A_RANGE_4G 0x01
+#define LSM303DLH_A_RANGE_8G 0x03
+
+/* ioctl: LSM303DLH_A_SET_MODE */
+#define LSM303DLH_A_MODE_OFF 0x00
+#define LSM303DLH_A_MODE_NORMAL 0x01
+#define LSM303DLH_A_MODE_LP_HALF 0x02
+#define LSM303DLH_A_MODE_LP_1 0x03
+#define LSM303DLH_A_MODE_LP_2 0x02
+#define LSM303DLH_A_MODE_LP_5 0x05
+#define LSM303DLH_A_MODE_LP_10 0x06
+
+/* ioctl: LSM303DLH_A_SET_BW */
+#define LSM303DLH_A_RATE_50 0x00
+#define LSM303DLH_A_RATE_100 0x01
+#define LSM303DLH_A_RATE_400 0x02
+#define LSM303DLH_A_RATE_1000 0x03
+
+/* Magnetometer gain setting
+ * ioctl: LSM303DLH_M_SET_RANGE
+ */
+#define LSM303DLH_M_RANGE_1_3G 0x01
+#define LSM303DLH_M_RANGE_1_9G 0x02
+#define LSM303DLH_M_RANGE_2_5G 0x03
+#define LSM303DLH_M_RANGE_4_0G 0x04
+#define LSM303DLH_M_RANGE_4_7G 0x05
+#define LSM303DLH_M_RANGE_5_6G 0x06
+#define LSM303DLH_M_RANGE_8_1G 0x07
+
+/* Magnetometer capturing mode */
+/* ioctl: LSM303DLH_M_SET_MODE */
+#define LSM303DLH_M_MODE_CONTINUOUS 0
+#define LSM303DLH_M_MODE_SINGLE 1
+#define LSM303DLH_M_MODE_SLEEP 3
+
+/* Magnetometer output data rate */
+/* ioctl: LSM303DLH_M_SET_BANDWIDTH */
+#define LSM303DLH_M_RATE_00_75 0x00 /* 00.75 Hz */
+#define LSM303DLH_M_RATE_01_50 0x01 /* 01.50 Hz */
+#define LSM303DLH_M_RATE_03_00 0x02 /* 03.00 Hz */
+#define LSM303DLH_M_RATE_07_50 0x03 /* 07.50 Hz */
+#define LSM303DLH_M_RATE_15_00 0x04 /* 15.00 Hz */
+#define LSM303DLH_M_RATE_30_00 0x05 /* 30.00 Hz */
+#define LSM303DLH_M_RATE_75_00 0x06 /* 75.00 Hz */
+
+#ifdef __KERNEL__
+struct lsm303dlh_platform_data {
+ int (*register_irq)(struct device *dev,
+ void *data,
+ void (*gpio_ev_irq_handler)(void *data));
+ int (*free_irq)(struct device *dev);
+
+ u8 axis_map_x; /* [0-2] */
+ u8 axis_map_y; /* [0-2] */
+ u8 axis_map_z; /* [0-2] */
+
+ u8 negative_x; /* [0-1] */
+ u8 negative_y; /* [0-1] */
+ u8 negative_z; /* [0-1] */
+};
+#endif /* __KERNEL__ */
+
+#endif /* __LSM303DLH_H__ */
diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h
index b63ff3ba335..35affa43b77 100644
--- a/include/linux/mfd/ab8500.h
+++ b/include/linux/mfd/ab8500.h
@@ -10,6 +10,29 @@
#include <linux/device.h>
/*
+ * AB8500 bank addresses
+ */
+#define AB8500_SYS_CTRL1_BLOCK 0x1
+#define AB8500_SYS_CTRL2_BLOCK 0x2
+#define AB8500_REGU_CTRL1 0x3
+#define AB8500_REGU_CTRL2 0x4
+#define AB8500_USB 0x5
+#define AB8500_TVOUT 0x6
+#define AB8500_DBI 0x7
+#define AB8500_ECI_AV_ACC 0x8
+#define AB8500_RESERVED 0x9
+#define AB8500_GPADC 0xA
+#define AB8500_CHARGER 0xB
+#define AB8500_GAS_GAUGE 0xC
+#define AB8500_AUDIO 0xD
+#define AB8500_INTERRUPT 0xE
+#define AB8500_RTC 0xF
+#define AB8500_MISC 0x10
+#define AB8500_DEBUG 0x12
+#define AB8500_PROD_TEST 0x13
+#define AB8500_OTP_EMUL 0x15
+
+/*
* Interrupts
*/
@@ -68,35 +91,49 @@
#define AB8500_INT_ID_DET_R4F 93
#define AB8500_INT_USB_CHG_DET_DONE 94
#define AB8500_INT_USB_CH_TH_PROT_F 96
-#define AB8500_INT_USB_CH_TH_PROP_R 97
-#define AB8500_INT_MAIN_CH_TH_PROP_F 98
+#define AB8500_INT_USB_CH_TH_PROT_R 97
+#define AB8500_INT_MAIN_CH_TH_PROT_F 98
#define AB8500_INT_MAIN_CH_TH_PROT_R 99
#define AB8500_INT_USB_CHARGER_NOT_OKF 103
+#define AB8500_INT_ADP_SOURCE_ERROR 104
+#define AB8500_INT_ADP_SINK_ERROR 105
+#define AB8500_INT_ADP_PROBE_PLUG 106
+#define AB8500_INT_ADP_PROBE_UNPLUG 107
+#define AB8500_INT_ADP_SENSE_OFF 108
+#define AB8500_INT_USB_LINK_STATUS 111
-#define AB8500_NR_IRQS 104
+#define AB8500_NR_IRQS 112
#define AB8500_NUM_IRQ_REGS 13
+#define AB8500_NUM_REGULATORS 11
+
+/* Forward declaration */
+struct ab8500_gpadc;
+struct regulator_init_data;
+
/**
* struct ab8500 - ab8500 internal structure
* @dev: parent device
* @lock: read/write operations lock
* @irq_lock: genirq bus lock
- * @revision: chip revision
* @irq: irq line
+ * @chip_id: chip revision id
* @write: register write
* @read: register read
* @rx_buf: rx buf for SPI
* @tx_buf: tx buf for SPI
* @mask: cache of IRQ regs for bus lock
* @oldmask: cache of previous IRQ regs for bus lock
+ * @gpadc: pointer to the ab8500 gpadc device information.
+ * @battery: pointer to the battery driver device information.
*/
struct ab8500 {
struct device *dev;
struct mutex lock;
struct mutex irq_lock;
- int revision;
int irq_base;
int irq;
+ u8 chip_id;
int (*write) (struct ab8500 *a8500, u16 addr, u8 data);
int (*read) (struct ab8500 *a8500, u16 addr);
@@ -104,25 +141,37 @@ struct ab8500 {
unsigned long tx_buf[4];
unsigned long rx_buf[4];
- u8 mask[AB8500_NUM_IRQ_REGS];
- u8 oldmask[AB8500_NUM_IRQ_REGS];
+ /* MASK12 exists only in v2 so last element dedicated for MASK12 */
+ u8 mask[AB8500_NUM_IRQ_REGS + 1];
+ u8 oldmask[AB8500_NUM_IRQ_REGS + 1];
+
+ struct ab8500_gpadc *gpadc;
+ struct ab8500_bm *battery;
};
+struct regulator_init_data;
+struct ab8500_bm_platform_data;
+struct ab8500_denc_platform_data;
+
/**
* struct ab8500_platform_data - AB8500 platform data
* @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
* @init: board-specific initialization after detection of ab8500
+ * @regulator: machine-specific constraints for regulators
+ * @battery: machine-specific battery management data
*/
struct ab8500_platform_data {
int irq_base;
void (*init) (struct ab8500 *);
+ struct regulator_init_data *regulator[AB8500_NUM_REGULATORS];
+ struct ab8500_bm_platform_data *battery;
+ struct ab8500_denc_platform_data *denc;
};
-extern int ab8500_write(struct ab8500 *a8500, u16 addr, u8 data);
-extern int ab8500_read(struct ab8500 *a8500, u16 addr);
-extern int ab8500_set_bits(struct ab8500 *a8500, u16 addr, u8 mask, u8 data);
-
extern int __devinit ab8500_init(struct ab8500 *ab8500);
extern int __devexit ab8500_exit(struct ab8500 *ab8500);
+int __deprecated ab8500_write(u8 block, u32 adr, u8 data);
+int __deprecated ab8500_read(u8 block, u32 adr);
+
#endif /* MFD_AB8500_H */
diff --git a/include/linux/mfd/ab8500/ab8500-bm.h b/include/linux/mfd/ab8500/ab8500-bm.h
new file mode 100644
index 00000000000..b0a4bd6d380
--- /dev/null
+++ b/include/linux/mfd/ab8500/ab8500-bm.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright ST-Ericsson 2009.
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ * Licensed under GPLv2.
+ */
+
+#ifndef _AB8500_BM_H
+#define _AB8500_BM_H
+
+/* AB8500 CIDs*/
+#define AB8500_CUT1P0 0x10
+#define AB8500_CUT1P1 0x11
+#define AB8500_CUT2P0 0x20
+
+/* Main charge i/p current */
+#define MAIN_CH_IP_CUR_0P9A 0x80
+#define MAIN_CH_IP_CUR_1P0A 0x90
+#define MAIN_CH_IP_CUR_1P1A 0xA0
+#define MAIN_CH_IP_CUR_1P2A 0xB0
+#define MAIN_CH_IP_CUR_1P3A 0xC0
+#define MAIN_CH_IP_CUR_1P4A 0xD0
+#define MAIN_CH_IP_CUR_1P5A 0xE0
+
+/* ChVoltLevel */
+#define CH_VOL_LVL_3P5 0x00
+#define CH_VOL_LVL_4P0 0x14
+#define CH_VOL_LVL_4P05 0x16
+#define CH_VOL_LVL_4P1 0x1B
+#define CH_VOL_LVL_4P15 0x20
+#define CH_VOL_LVL_4P2 0x25
+#define CH_VOL_LVL_4P6 0x4D
+
+/* ChOutputCurrentLevel */
+#define CH_OP_CUR_LVL_0P1 0x00
+#define CH_OP_CUR_LVL_0P2 0x01
+#define CH_OP_CUR_LVL_0P3 0x02
+#define CH_OP_CUR_LVL_0P4 0x03
+#define CH_OP_CUR_LVL_0P5 0x04
+#define CH_OP_CUR_LVL_0P6 0x05
+#define CH_OP_CUR_LVL_0P7 0x06
+#define CH_OP_CUR_LVL_0P8 0x07
+#define CH_OP_CUR_LVL_0P9 0x08
+#define CH_OP_CUR_LVL_1P4 0x0D
+#define CH_OP_CUR_LVL_1P5 0x0E
+#define CH_OP_CUR_LVL_1P6 0x0F
+
+/* current is mA */
+#define USB_0P1A 100
+#define USB_0P2A 200
+#define USB_0P3A 300
+#define USB_0P4A 400
+#define USB_0P5A 500
+
+/* UsbChCurrLevel */
+#define USB_CH_IP_CUR_LVL_0P05 0x00
+#define USB_CH_IP_CUR_LVL_0P09 0x10
+#define USB_CH_IP_CUR_LVL_0P19 0x20
+#define USB_CH_IP_CUR_LVL_0P29 0x30
+#define USB_CH_IP_CUR_LVL_0P38 0x40
+#define USB_CH_IP_CUR_LVL_0P45 0x50
+#define USB_CH_IP_CUR_LVL_0P5 0x60
+#define USB_CH_IP_CUR_LVL_0P9 0xA0
+#define USB_CH_IP_CUR_LVL_1P0 0xB0
+#define USB_CH_IP_CUR_LVL_1P1 0xC0
+#define USB_CH_IP_CUR_LVL_1P5 0xF0
+
+#define LOW_BAT_3P1V 0x20
+#define LOW_BAT_2P3V 0x00
+#define LOW_BAT_RESET 0x01
+
+/* Backup battery constants */
+#define BUP_ICH_SEL_50UA 0x00
+#define BUP_ICH_SEL_150UA 0x04
+#define BUP_ICH_SEL_300UA 0x08
+#define BUP_ICH_SEL_700UA 0x0C
+
+#define BUP_VCH_SEL_2P5V 0x00
+#define BUP_VCH_SEL_2P6V 0x01
+#define BUP_VCH_SEL_2P8V 0x02
+#define BUP_VCH_SEL_3P1V 0x03
+
+/* Battery resistance */
+#define BATTERY_NOKIA_BL_5F 20
+#define BATTERY_NOKIA_BP_5M 63
+#define SUPPORTED_BATT 2
+
+/**
+ * struct battery_type - different batteries supported
+ * @name: battery technology
+ * @resis: battery resistance
+ * @termination_vol: max voltage upto which battery can be charged
+ * @normal_op_cur_lvl: charger current in normal state in mA
+ * @normal_ip_vol_lvl: charger voltage in normal state in mV
+ * @maint_a_op_cur_lvl: charger current in maintenance A state in mA
+ * @maint_a_ip_vol_lvl: charger voltage in maintenance A state in mV
+ * @maint_a_chg_timer_h: charge time in maintenance A state
+ * @maint_b_op_cur_lvl: charger current in maintenance B state in mA
+ * @maint_b_ip_vol_lvl: charger voltage in maintenance B state in mV
+ * @maint_b_chg_timer_h: charge time in maintenance B state
+ * @low_high_op_cur_lvl: charger current in temp low/high state in mA
+ * @low_high_ip_vol_lvl: charger voltage in temp low/high state in mV
+ */
+struct battery_type {
+ int name;
+ int resis;
+ int termination_vol;
+ int termination_curr;
+ int normal_op_cur_lvl;
+ int normal_ip_vol_lvl;
+ int maint_a_op_cur_lvl;
+ int maint_a_ip_vol_lvl;
+ int maint_a_chg_timer_h;
+ int maint_b_op_cur_lvl;
+ int maint_b_ip_vol_lvl;
+ int maint_b_chg_timer_h;
+ int low_high_op_cur_lvl;
+ int low_high_ip_vol_lvl;
+};
+
+/**
+ * struct ab8500_bm_platform_data - ab8500 EM paltform data
+ * @bat_type: array of supported battery types
+ * @temp_under under this temp, charging is stopped
+ * @temp_low between this temp and temp_under charging is reduced
+ * @temp_high between this temp and temp_over charging is reduced
+ * @temp_over over this temp, charging is stopped
+ * @main_safety_tmr_h safety timer for main charger
+ * @usb_safety_tmr_h safety timer for usb charger
+ * bkup_bat_v voltage which we charge the backup battery with
+ * bkup_bat_i current which we charge the backup battery with
+ */
+struct ab8500_bm_platform_data {
+ int temp_under;
+ int temp_low;
+ int temp_high;
+ int temp_over;
+ int main_safety_tmr_h;
+ int usb_safety_tmr_h;
+ int bkup_bat_v;
+ int bkup_bat_i;
+ struct battery_type bat_type[];
+};
+
+#ifdef CONFIG_AB8500_BM
+void ab8500_bm_usb_state_changed(u8 bm_usb_state, u16 mA);
+#else
+static void ab8500_bm_usb_state_changed(u8 bm_usb_state, u16 mA)
+{
+}
+#endif
+#endif /* _AB8500_BM_H */
diff --git a/include/linux/mfd/ab8500/ab8500-gpadc.h b/include/linux/mfd/ab8500/ab8500-gpadc.h
new file mode 100644
index 00000000000..ec62243a4f1
--- /dev/null
+++ b/include/linux/mfd/ab8500/ab8500-gpadc.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Licensed under GPLv2.
+ *
+ * Author: Arun R Murthy <arun.murthy@stericsson.com>
+ */
+
+#ifndef _AB8500_GPADC_H
+#define _AB8500_GPADC_H
+
+/* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2) */
+#define BAT_CTRL 0x01
+#define ACC_DETECT1 0x04
+#define ACC_DETECT2 0x05
+#define ADC_AUX1 0x06
+#define ADC_AUX2 0x07
+#define MAIN_BAT_V 0x08
+#define BK_BAT_V 0x0C
+#define VBUS_V 0x09
+#define MAIN_CHARGER_V 0x03
+#define MAIN_CHARGER_C 0x0A
+#define USB_CHARGER_C 0x0B
+#define DIE_TEMP 0x0D
+#define BTEMP_BALL 0x02
+
+/**
+ * struct ab8500_gpadc - ab8500 GPADC device information
+ * @dev: pointer to the struct device
+ * @parent: pointer to the parent device structure ab8500
+ * @ab8500_gpadc_complete: pointer to the struct completion, to indicate
+ * the completion of gpadc conversion
+ * @ab8500_gpadc_lock: structure of type mutex
+ * @regu: pointer to the struct regulator
+ * @irq: interrupt number that is used by gpadc
+ */
+struct ab8500_gpadc {
+ struct device *dev;
+ struct ab8500 *parent;
+ struct completion ab8500_gpadc_complete;
+ struct mutex ab8500_gpadc_lock;
+ struct regulator *regu;
+ int irq;
+};
+
+int ab8500_gpadc_convert(struct ab8500_gpadc *di, u8 input);
+
+#endif /* _AB8500_GPADC_H */
diff --git a/include/linux/mfd/ab8500/sysctrl.h b/include/linux/mfd/ab8500/sysctrl.h
new file mode 100644
index 00000000000..10da0291f8f
--- /dev/null
+++ b/include/linux/mfd/ab8500/sysctrl.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef __AB8500_SYSCTRL_H
+#define __AB8500_SYSCTRL_H
+
+#include <linux/bitops.h>
+
+#ifdef CONFIG_AB8500_CORE
+
+int ab8500_sysctrl_read(u16 reg, u8 *value);
+int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value);
+
+#else
+
+static inline int ab8500_sysctrl_read(u16 reg, u8 *value)
+{
+ return 0;
+}
+
+static inline int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
+{
+ return 0;
+}
+
+#endif /* CONFIG_AB8500_CORE */
+
+static inline int ab8500_sysctrl_set(u16 reg, u8 bits)
+{
+ return ab8500_sysctrl_write(reg, bits, bits);
+}
+
+static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
+{
+ return ab8500_sysctrl_write(reg, bits, 0);
+}
+
+/* Registers */
+#define AB8500_TURNONSTATUS 0x100
+#define AB8500_RESETSTATUS 0x101
+#define AB8500_PONKEY1PRESSSTATUS 0x102
+#define AB8500_SYSCLKREQSTATUS 0x142
+#define AB8500_STW4500CTRL1 0x180
+#define AB8500_STW4500CTRL2 0x181
+#define AB8500_STW4500CTRL3 0x200
+#define AB8500_MAINWDOGCTRL 0x201
+#define AB8500_MAINWDOGTIMER 0x202
+#define AB8500_LOWBAT 0x203
+#define AB8500_BATTOK 0x204
+#define AB8500_SYSCLKTIMER 0x205
+#define AB8500_SMPSCLKCTRL 0x206
+#define AB8500_SMPSCLKSEL1 0x207
+#define AB8500_SMPSCLKSEL2 0x208
+#define AB8500_SMPSCLKSEL3 0x209
+#define AB8500_SYSULPCLKCONF 0x20A
+#define AB8500_SYSULPCLKCTRL1 0x20B
+#define AB8500_SYSCLKCTRL 0x20C
+#define AB8500_SYSCLKREQ1VALID 0x20D
+#define AB8500_SYSTEMCTRLSUP 0x20F
+#define AB8500_SYSCLKREQ1RFCLKBUF 0x210
+#define AB8500_SYSCLKREQ2RFCLKBUF 0x211
+#define AB8500_SYSCLKREQ3RFCLKBUF 0x212
+#define AB8500_SYSCLKREQ4RFCLKBUF 0x213
+#define AB8500_SYSCLKREQ5RFCLKBUF 0x214
+#define AB8500_SYSCLKREQ6RFCLKBUF 0x215
+#define AB8500_SYSCLKREQ7RFCLKBUF 0x216
+#define AB8500_SYSCLKREQ8RFCLKBUF 0x217
+#define AB8500_DITHERCLKCTRL 0x220
+#define AB8500_SWATCTRL 0x230
+#define AB8500_HIQCLKCTRL 0x232
+#define AB8500_VSIMSYSCLKCTRL 0x233
+
+/* Bits */
+#define AB8500_TURNONSTATUS_PORNVBAT BIT(0)
+#define AB8500_TURNONSTATUS_PONKEY1DBF BIT(1)
+#define AB8500_TURNONSTATUS_PONKEY2DBF BIT(2)
+#define AB8500_TURNONSTATUS_RTCALARM BIT(3)
+#define AB8500_TURNONSTATUS_MAINCHDET BIT(4)
+#define AB8500_TURNONSTATUS_VBUSDET BIT(5)
+#define AB8500_TURNONSTATUS_USBIDDETECT BIT(6)
+
+#define AB8500_RESETSTATUS_RESETN4500NSTATUS BIT(0)
+#define AB8500_RESETSTATUS_SWRESETN4500NSTATUS BIT(2)
+
+#define AB8500_PONKEY1PRESSSTATUS_PONKEY1PRESSTIME_MASK 0x7F
+#define AB8500_PONKEY1PRESSSTATUS_PONKEY1PRESSTIME_SHIFT 0
+
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ1STATUS BIT(0)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ2STATUS BIT(1)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ3STATUS BIT(2)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ4STATUS BIT(3)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ5STATUS BIT(4)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ6STATUS BIT(5)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ7STATUS BIT(6)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ8STATUS BIT(7)
+
+#define AB8500_STW4500CTRL1_SWOFF BIT(0)
+#define AB8500_STW4500CTRL1_SWRESET4500N BIT(1)
+#define AB8500_STW4500CTRL1_THDB8500SWOFF BIT(2)
+
+#define AB8500_STW4500CTRL2_RESETNVAUX1VALID BIT(0)
+#define AB8500_STW4500CTRL2_RESETNVAUX2VALID BIT(1)
+#define AB8500_STW4500CTRL2_RESETNVAUX3VALID BIT(2)
+#define AB8500_STW4500CTRL2_RESETNVMODVALID BIT(3)
+#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY1VALID BIT(4)
+#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY2VALID BIT(5)
+#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY3VALID BIT(6)
+#define AB8500_STW4500CTRL2_RESETNVSMPS1VALID BIT(7)
+
+#define AB8500_STW4500CTRL3_CLK32KOUT2DIS BIT(0)
+#define AB8500_STW4500CTRL3_RESETAUDN BIT(1)
+#define AB8500_STW4500CTRL3_RESETDENCN BIT(2)
+#define AB8500_STW4500CTRL3_THSDENA BIT(3)
+
+#define AB8500_MAINWDOGCTRL_MAINWDOGENA BIT(0)
+#define AB8500_MAINWDOGCTRL_MAINWDOGKICK BIT(1)
+#define AB8500_MAINWDOGCTRL_WDEXPTURNONVALID BIT(4)
+
+#define AB8500_MAINWDOGTIMER_MAINWDOGTIMER_MASK 0x7F
+#define AB8500_MAINWDOGTIMER_MAINWDOGTIMER_SHIFT 0
+
+#define AB8500_LOWBAT_LOWBATENA BIT(0)
+#define AB8500_LOWBAT_LOWBAT_MASK 0x7E
+#define AB8500_LOWBAT_LOWBAT_SHIFT 1
+
+#define AB8500_BATTOK_BATTOKSEL0THF_MASK 0x0F
+#define AB8500_BATTOK_BATTOKSEL0THF_SHIFT 0
+#define AB8500_BATTOK_BATTOKSEL1THF_MASK 0xF0
+#define AB8500_BATTOK_BATTOKSEL1THF_SHIFT 4
+
+#define AB8500_SYSCLKTIMER_SYSCLKTIMER_MASK 0x0F
+#define AB8500_SYSCLKTIMER_SYSCLKTIMER_SHIFT 0
+#define AB8500_SYSCLKTIMER_SYSCLKTIMERADJ_MASK 0xF0
+#define AB8500_SYSCLKTIMER_SYSCLKTIMERADJ_SHIFT 4
+
+#define AB8500_SMPSCLKCTRL_SMPSCLKINTSEL_MASK 0x03
+#define AB8500_SMPSCLKCTRL_SMPSCLKINTSEL_SHIFT 0
+#define AB8500_SMPSCLKCTRL_3M2CLKINTENA BIT(2)
+
+#define AB8500_SMPSCLKSEL1_VARMCLKSEL_MASK 0x07
+#define AB8500_SMPSCLKSEL1_VARMCLKSEL_SHIFT 0
+#define AB8500_SMPSCLKSEL1_VAPECLKSEL_MASK 0x38
+#define AB8500_SMPSCLKSEL1_VAPECLKSEL_SHIFT 3
+
+#define AB8500_SMPSCLKSEL2_VMODCLKSEL_MASK 0x07
+#define AB8500_SMPSCLKSEL2_VMODCLKSEL_SHIFT 0
+#define AB8500_SMPSCLKSEL2_VSMPS1CLKSEL_MASK 0x38
+#define AB8500_SMPSCLKSEL2_VSMPS1CLKSEL_SHIFT 3
+
+#define AB8500_SMPSCLKSEL3_VSMPS2CLKSEL_MASK 0x07
+#define AB8500_SMPSCLKSEL3_VSMPS2CLKSEL_SHIFT 0
+#define AB8500_SMPSCLKSEL3_VSMPS3CLKSEL_MASK 0x38
+#define AB8500_SMPSCLKSEL3_VSMPS3CLKSEL_SHIFT 3
+
+#define AB8500_SYSULPCLKCONF_ULPCLKCONF_MASK 0x03
+#define AB8500_SYSULPCLKCONF_ULPCLKCONF_SHIFT 0
+#define AB8500_SYSULPCLKCONF_CLK27MHZSTRE BIT(2)
+#define AB8500_SYSULPCLKCONF_TVOUTCLKDELN BIT(3)
+#define AB8500_SYSULPCLKCONF_TVOUTCLKINV BIT(4)
+#define AB8500_SYSULPCLKCONF_ULPCLKSTRE BIT(5)
+#define AB8500_SYSULPCLKCONF_CLK27MHZBUFENA BIT(6)
+#define AB8500_SYSULPCLKCONF_CLK27MHZPDENA BIT(7)
+
+#define AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK 0x03
+#define AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_SHIFT 0
+#define AB8500_SYSULPCLKCTRL1_ULPCLKREQ BIT(2)
+#define AB8500_SYSULPCLKCTRL1_4500SYSCLKREQ BIT(3)
+#define AB8500_SYSULPCLKCTRL1_AUDIOCLKENA BIT(4)
+#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ BIT(5)
+#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ BIT(6)
+#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ BIT(7)
+
+#define AB8500_SYSCLKCTRL_TVOUTPLLENA BIT(0)
+#define AB8500_SYSCLKCTRL_TVOUTCLKENA BIT(1)
+#define AB8500_SYSCLKCTRL_USBCLKENA BIT(2)
+
+#define AB8500_SYSCLKREQ1VALID_SYSCLKREQ1VALID BIT(0)
+#define AB8500_SYSCLKREQ1VALID_ULPCLKREQ1VALID BIT(1)
+#define AB8500_SYSCLKREQ1VALID_USBSYSCLKREQ1VALID BIT(2)
+
+#define AB8500_SYSTEMCTRLSUP_EXTSUP12LPNCLKSEL_MASK 0x03
+#define AB8500_SYSTEMCTRLSUP_EXTSUP12LPNCLKSEL_SHIFT 0
+#define AB8500_SYSTEMCTRLSUP_EXTSUP3LPNCLKSEL_MASK 0x0C
+#define AB8500_SYSTEMCTRLSUP_EXTSUP3LPNCLKSEL_SHIFT 2
+#define AB8500_SYSTEMCTRLSUP_INTDB8500NOD BIT(4)
+
+#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF4 BIT(4)
+
+#define AB8500_DITHERCLKCTRL_VARMDITHERENA BIT(0)
+#define AB8500_DITHERCLKCTRL_VSMPS3DITHERENA BIT(1)
+#define AB8500_DITHERCLKCTRL_VSMPS1DITHERENA BIT(2)
+#define AB8500_DITHERCLKCTRL_VSMPS2DITHERENA BIT(3)
+#define AB8500_DITHERCLKCTRL_VMODDITHERENA BIT(4)
+#define AB8500_DITHERCLKCTRL_VAPEDITHERENA BIT(5)
+#define AB8500_DITHERCLKCTRL_DITHERDEL_MASK 0xC0
+#define AB8500_DITHERCLKCTRL_DITHERDEL_SHIFT 6
+
+#define AB8500_SWATCTRL_UPDATERF BIT(0)
+#define AB8500_SWATCTRL_SWATENABLE BIT(1)
+#define AB8500_SWATCTRL_RFOFFTIMER_MASK 0x1C
+#define AB8500_SWATCTRL_RFOFFTIMER_SHIFT 2
+#define AB8500_SWATCTRL_SWATBIT5 BIT(6)
+
+#define AB8500_HIQCLKCTRL_SYSCLKREQ1HIQENAVALID BIT(0)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ2HIQENAVALID BIT(1)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ3HIQENAVALID BIT(2)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ4HIQENAVALID BIT(3)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ5HIQENAVALID BIT(4)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ6HIQENAVALID BIT(5)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ7HIQENAVALID BIT(6)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ8HIQENAVALID BIT(7)
+
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ1VALID BIT(0)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ2VALID BIT(1)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ3VALID BIT(2)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ4VALID BIT(3)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ5VALID BIT(4)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ6VALID BIT(5)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ7VALID BIT(6)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ8VALID BIT(7)
+
+#endif /* __AB8500_SYSCTRL_H */
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index 390726fcbcb..1f52a034c60 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -6,8 +6,7 @@
*
* ABX500 core access functions.
* The abx500 interface is used for the Analog Baseband chip
- * ab3100, ab3550, ab5500 and possibly comming. It is not used for
- * ab4500 and ab8500 since they are another family of chip.
+ * ab3100, ab3550, ab5500, and ab8500.
*
* Author: Mattias Wallin <mattias.wallin@stericsson.com>
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
@@ -192,6 +191,51 @@ struct ab3550_platform_data {
unsigned int init_settings_sz;
};
+enum ab5500_devid {
+ AB5500_DEVID_ADC,
+ AB5500_DEVID_LEDS,
+ AB5500_DEVID_POWER,
+ AB5500_DEVID_REGULATORS,
+ AB5500_DEVID_SIM,
+ AB5500_DEVID_RTC,
+ AB5500_DEVID_CHARGER,
+ AB5500_DEVID_FUELGAUGE,
+ AB5500_DEVID_VIBRATOR,
+ AB5500_DEVID_CODEC,
+ AB5500_DEVID_USB,
+ AB5500_DEVID_OTP,
+ AB5500_DEVID_VIDEO,
+ AB5500_DEVID_DBIECI,
+ AB5500_NUM_DEVICES,
+};
+
+enum ab5500_banks {
+ AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP = 0,
+ AB5500_BANK_VDDDIG_IO_I2C_CLK_TST = 1,
+ AB5500_BANK_VDENC = 2,
+ AB5500_BANK_SIM_USBSIM = 3,
+ AB5500_BANK_LED = 4,
+ AB5500_BANK_ADC = 5,
+ AB5500_BANK_RTC = 6,
+ AB5500_BANK_STARTUP = 7,
+ AB5500_BANK_DBI_ECI = 8,
+ AB5500_BANK_CHG = 9,
+ AB5500_BANK_FG_BATTCOM_ACC = 10,
+ AB5500_BANK_USB = 11,
+ AB5500_BANK_IT = 12,
+ AB5500_BANK_VIBRA = 13,
+ AB5500_BANK_AUDIO_HEADSETUSB = 14,
+ AB5500_NUM_BANKS = 15,
+};
+
+struct ab5500_platform_data {
+ struct {unsigned int base; unsigned int count; } irq;
+ void *dev_data[AB5500_NUM_DEVICES];
+ size_t dev_data_sz[AB5500_NUM_DEVICES];
+ struct abx500_init_settings *init_settings;
+ unsigned int init_settings_sz;
+};
+
int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
u8 value);
int abx500_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
@@ -229,5 +273,5 @@ struct abx500_ops {
int (*startup_irq_enabled) (struct device *, unsigned int);
};
-int abx500_register_ops(struct device *core_dev, struct abx500_ops *ops);
+int abx500_register_ops(struct device *dev, struct abx500_ops *ops);
#endif
diff --git a/include/linux/mfd/cg2900.h b/include/linux/mfd/cg2900.h
new file mode 100644
index 00000000000..9c2afc5cca9
--- /dev/null
+++ b/include/linux/mfd/cg2900.h
@@ -0,0 +1,205 @@
+/*
+ * include/linux/mfd/cg2900.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth HCI H:4 Driver for ST-Ericsson CG2900 connectivity
+ * controller.
+ */
+
+#ifndef _CG2900_H_
+#define _CG2900_H_
+
+#include <linux/skbuff.h>
+
+#define CG2900_MAX_NAME_SIZE 30
+
+/*
+ * Channel names to use when registering to CG2900 driver
+ */
+
+/** CG2900_BT_CMD - Bluetooth HCI H4 channel for Bluetooth commands.
+ */
+#define CG2900_BT_CMD "cg2900_bt_cmd"
+
+/** CG2900_BT_ACL - Bluetooth HCI H4 channel for Bluetooth ACL data.
+ */
+#define CG2900_BT_ACL "cg2900_bt_acl"
+
+/** CG2900_BT_EVT - Bluetooth HCI H4 channel for Bluetooth events.
+ */
+#define CG2900_BT_EVT "cg2900_bt_evt"
+
+/** CG2900_FM_RADIO - Bluetooth HCI H4 channel for FM radio.
+ */
+#define CG2900_FM_RADIO "cg2900_fm_radio"
+
+/** CG2900_GNSS - Bluetooth HCI H4 channel for GNSS.
+ */
+#define CG2900_GNSS "cg2900_gnss"
+
+/** CG2900_DEBUG - Bluetooth HCI H4 channel for internal debug data.
+ */
+#define CG2900_DEBUG "cg2900_debug"
+
+/** CG2900_STE_TOOLS - Bluetooth HCI H4 channel for development tools data.
+ */
+#define CG2900_STE_TOOLS "cg2900_ste_tools"
+
+/** CG2900_HCI_LOGGER - BT channel for logging all transmitted H4 packets.
+ * Data read is copy of all data transferred on the other channels.
+ * Only write allowed is configuration of the HCI Logger.
+ */
+#define CG2900_HCI_LOGGER "cg2900_hci_logger"
+
+/** CG2900_US_CTRL - Channel for user space init and control of CG2900.
+ */
+#define CG2900_US_CTRL "cg2900_us_ctrl"
+
+/** CG2900_BT_AUDIO - HCI Channel for BT audio configuration commands.
+ * Maps to Bluetooth command and event channels.
+ */
+#define CG2900_BT_AUDIO "cg2900_bt_audio"
+
+/** CG2900_FM_RADIO_AUDIO - HCI channel for FM audio configuration commands.
+ * Maps to FM Radio channel.
+ */
+#define CG2900_FM_RADIO_AUDIO "cg2900_fm_audio"
+
+/** CG2900_CORE- Channel for keeping ST-Ericsson CG2900 enabled.
+ * Opening this channel forces the chip to stay powered.
+ * No data can be written to or read from this channel.
+ */
+#define CG2900_CORE "cg2900_core"
+
+struct cg2900_callbacks;
+
+/**
+ * struct cg2900_device - Device structure for CG2900 user.
+ * @h4_channel: HCI H:4 channel used by this device.
+ * @cb: Callback functions registered by this device.
+ * @logger_enabled: true if HCI logger is enabled for this channel,
+ * false otherwise.
+ * @user_data: Arbitrary data used by caller.
+ * @dev: Parent device this driver is connected to.
+ *
+ * Defines data needed to access an HCI channel.
+ */
+struct cg2900_device {
+ int h4_channel;
+ struct cg2900_callbacks *cb;
+ bool logger_enabled;
+ void *user_data;
+ struct device *dev;
+};
+
+/**
+ * struct cg2900_callbacks - Callback structure for CG2900 user.
+ * @read_cb: Callback function called when data is received from
+ * the connectivity controller.
+ * @reset_cb: Callback function called when the connectivity controller has
+ * been reset.
+ *
+ * Defines the callback functions provided from the caller.
+ */
+struct cg2900_callbacks {
+ void (*read_cb) (struct cg2900_device *dev, struct sk_buff *skb);
+ void (*reset_cb) (struct cg2900_device *dev);
+};
+
+/**
+ * struct cg2900_rev_data - Contains revision data for the local controller.
+ * @revision: Revision of the controller, e.g. to indicate that it is
+ * a CG2900 controller.
+ * @sub_version: Subversion of the controller, e.g. to indicate a certain
+ * tape-out of the controller.
+ *
+ * The values to match retrieved values to each controller may be retrieved from
+ * the manufacturer.
+ */
+struct cg2900_rev_data {
+ int revision;
+ int sub_version;
+};
+
+/**
+ * cg2900_register_user() - Register CG2900 user.
+ * @name: Name of HCI H:4 channel to register to.
+ * @cb: Callback structure to use for the H:4 channel.
+ *
+ * Returns:
+ * Pointer to CG2900 device structure if successful.
+ * NULL upon failure.
+ */
+extern struct cg2900_device *cg2900_register_user(char *name,
+ struct cg2900_callbacks *cb);
+
+/**
+ * cg2900_deregister_user() - Remove registration of CG2900 user.
+ * @dev: CG2900 device.
+ */
+extern void cg2900_deregister_user(struct cg2900_device *dev);
+
+/**
+ * cg2900_reset() - Reset the CG2900 controller.
+ * @dev: CG2900 device.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EACCES if driver has not been initialized.
+ */
+extern int cg2900_reset(struct cg2900_device *dev);
+
+/**
+ * cg2900_alloc_skb() - Alloc an sk_buff structure for CG2900 handling.
+ * @size: Size in number of octets.
+ * @priority: Allocation priority, e.g. GFP_KERNEL.
+ *
+ * Returns:
+ * Pointer to sk_buff buffer structure if successful.
+ * NULL upon allocation failure.
+ */
+extern struct sk_buff *cg2900_alloc_skb(unsigned int size, gfp_t priority);
+
+/**
+ * cg2900_write() - Send data to the connectivity controller.
+ * @dev: CG2900 device.
+ * @skb: Data packet.
+ *
+ * The cg2900_write() function sends data to the connectivity controller.
+ * If the return value is 0 the skb will be freed by the driver,
+ * otherwise it won't be freed.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EACCES if driver has not been initialized or trying to write while driver
+ * is not active.
+ * -EINVAL if NULL pointer was supplied.
+ * -EPERM if operation is not permitted, e.g. trying to write to a channel
+ * that doesn't handle write operations.
+ * Error codes returned from core_enable_hci_logger.
+ */
+extern int cg2900_write(struct cg2900_device *dev, struct sk_buff *skb);
+
+/**
+ * cg2900_get_local_revision() - Read revision of the connected controller.
+ * @rev_data: Revision data structure to fill. Must be allocated by caller.
+ *
+ * The cg2900_get_local_revision() function returns the revision data of the
+ * local controller if available. If data is not available, e.g. because the
+ * controller has not yet been started this function will return false.
+ *
+ * Returns:
+ * true if revision data is available.
+ * false if no revision data is available.
+ */
+extern bool cg2900_get_local_revision(struct cg2900_rev_data *rev_data);
+
+#endif /* _CG2900_H_ */
diff --git a/include/linux/mfd/cg2900_audio.h b/include/linux/mfd/cg2900_audio.h
new file mode 100644
index 00000000000..8ac4de4a602
--- /dev/null
+++ b/include/linux/mfd/cg2900_audio.h
@@ -0,0 +1,587 @@
+/*
+ * include/linux/mfd/cg2900_audio.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Linux Bluetooth Audio Driver for ST-Ericsson controller.
+ */
+
+#ifndef _CG2900_AUDIO_H_
+#define _CG2900_AUDIO_H_
+
+#include <linux/types.h>
+
+/*
+ * Digital Audio Interface configuration types
+ */
+
+/** CG2900_A2DP_MAX_AVDTP_HDR_LEN - Max length of a AVDTP header.
+ * Max length of a AVDTP header for an A2DP packet.
+ */
+#define CG2900_A2DP_MAX_AVDTP_HDR_LEN 25
+
+/**
+ * enum cg2900_dai_dir - Contains the DAI port directions alternatives.
+ * @DAI_DIR_B_RX_A_TX: Port B as Rx and port A as Tx.
+ * @DAI_DIR_B_TX_A_RX: Port B as Tx and port A as Rx.
+ */
+enum cg2900_dai_dir {
+ DAI_DIR_B_RX_A_TX = 0x00,
+ DAI_DIR_B_TX_A_RX = 0x01
+};
+
+/**
+ * enum cg2900_dai_mode - DAI mode alternatives.
+ * @DAI_MODE_SLAVE: Slave.
+ * @DAI_MODE_MASTER: Master.
+ */
+enum cg2900_dai_mode {
+ DAI_MODE_SLAVE = 0x00,
+ DAI_MODE_MASTER = 0x01
+};
+
+/**
+ * enum cg2900_dai_stream_ratio - Voice stream ratio alternatives.
+ * @STREAM_RATIO_FM16_VOICE16: FM 16kHz, Voice 16kHz.
+ * @STREAM_RATIO_FM16_VOICE8: FM 16kHz, Voice 8kHz.
+ * @STREAM_RATIO_FM48_VOICE16: FM 48kHz, Voice 16Khz.
+ * @STREAM_RATIO_FM48_VOICE8: FM 48kHz, Voice 8kHz.
+ *
+ * Contains the alternatives for the voice stream ratio between the Audio stream
+ * sample rate and the Voice stream sample rate.
+ */
+enum cg2900_dai_stream_ratio {
+ STREAM_RATIO_FM16_VOICE16 = 0x01,
+ STREAM_RATIO_FM16_VOICE8 = 0x02,
+ STREAM_RATIO_FM48_VOICE16 = 0x03,
+ STREAM_RATIO_FM48_VOICE8 = 0x06
+};
+
+/**
+ * enum cg2900_dai_fs_duration - Frame sync duration alternatives.
+ * @SYNC_DURATION_8: 8 frames sync duration.
+ * @SYNC_DURATION_16: 16 frames sync duration.
+ * @SYNC_DURATION_24: 24 frames sync duration.
+ * @SYNC_DURATION_32: 32 frames sync duration.
+ * @SYNC_DURATION_48: 48 frames sync duration.
+ * @SYNC_DURATION_50: 50 frames sync duration.
+ * @SYNC_DURATION_64: 64 frames sync duration.
+ * @SYNC_DURATION_75: 75 frames sync duration.
+ * @SYNC_DURATION_96: 96 frames sync duration.
+ * @SYNC_DURATION_125: 125 frames sync duration.
+ * @SYNC_DURATION_128: 128 frames sync duration.
+ * @SYNC_DURATION_150: 150 frames sync duration.
+ * @SYNC_DURATION_192: 192 frames sync duration.
+ * @SYNC_DURATION_250: 250 frames sync duration.
+ * @SYNC_DURATION_256: 256 frames sync duration.
+ * @SYNC_DURATION_300: 300 frames sync duration.
+ * @SYNC_DURATION_384: 384 frames sync duration.
+ * @SYNC_DURATION_500: 500 frames sync duration.
+ * @SYNC_DURATION_512: 512 frames sync duration.
+ * @SYNC_DURATION_600: 600 frames sync duration.
+ * @SYNC_DURATION_768: 768 frames sync duration.
+ *
+ * This parameter sets the PCM frame sync duration. It is calculated as the
+ * ratio between the bit clock and the frame rate. For example, if the bit
+ * clock is 512 kHz and the stream sample rate is 8 kHz, the PCM frame sync
+ * duration is 512 / 8 = 64.
+ */
+enum cg2900_dai_fs_duration {
+ SYNC_DURATION_8 = 0,
+ SYNC_DURATION_16 = 1,
+ SYNC_DURATION_24 = 2,
+ SYNC_DURATION_32 = 3,
+ SYNC_DURATION_48 = 4,
+ SYNC_DURATION_50 = 5,
+ SYNC_DURATION_64 = 6,
+ SYNC_DURATION_75 = 7,
+ SYNC_DURATION_96 = 8,
+ SYNC_DURATION_125 = 9,
+ SYNC_DURATION_128 = 10,
+ SYNC_DURATION_150 = 11,
+ SYNC_DURATION_192 = 12,
+ SYNC_DURATION_250 = 13,
+ SYNC_DURATION_256 = 14,
+ SYNC_DURATION_300 = 15,
+ SYNC_DURATION_384 = 16,
+ SYNC_DURATION_500 = 17,
+ SYNC_DURATION_512 = 18,
+ SYNC_DURATION_600 = 19,
+ SYNC_DURATION_768 = 20
+};
+
+/**
+ * enum cg2900_dai_bit_clk - Bit Clock alternatives.
+ * @BIT_CLK_128: 128 Kbits clock.
+ * @BIT_CLK_256: 256 Kbits clock.
+ * @BIT_CLK_512: 512 Kbits clock.
+ * @BIT_CLK_768: 768 Kbits clock.
+ * @BIT_CLK_1024: 1024 Kbits clock.
+ * @BIT_CLK_1411_76: 1411.76 Kbits clock.
+ * @BIT_CLK_1536: 1536 Kbits clock.
+ * @BIT_CLK_2000: 2000 Kbits clock.
+ * @BIT_CLK_2048: 2048 Kbits clock.
+ * @BIT_CLK_2400: 2400 Kbits clock.
+ * @BIT_CLK_2823_52: 2823.52 Kbits clock.
+ * @BIT_CLK_3072: 3072 Kbits clock.
+ *
+ * This parameter sets the bit clock speed. This is the clocking of the actual
+ * data. A usual parameter for eSCO voice is 512 kHz.
+ */
+enum cg2900_dai_bit_clk {
+ BIT_CLK_128 = 0x00,
+ BIT_CLK_256 = 0x01,
+ BIT_CLK_512 = 0x02,
+ BIT_CLK_768 = 0x03,
+ BIT_CLK_1024 = 0x04,
+ BIT_CLK_1411_76 = 0x05,
+ BIT_CLK_1536 = 0x06,
+ BIT_CLK_2000 = 0x07,
+ BIT_CLK_2048 = 0x08,
+ BIT_CLK_2400 = 0x09,
+ BIT_CLK_2823_52 = 0x0A,
+ BIT_CLK_3072 = 0x0B
+};
+
+/**
+ * enum cg2900_dai_sample_rate - Sample rates alternatives.
+ * @SAMPLE_RATE_8: 8 kHz sample rate.
+ * @SAMPLE_RATE_16: 16 kHz sample rate.
+ * @SAMPLE_RATE_44_1: 44.1 kHz sample rate.
+ * @SAMPLE_RATE_48: 48 kHz sample rate.
+ */
+enum cg2900_dai_sample_rate {
+ SAMPLE_RATE_8 = 0,
+ SAMPLE_RATE_16 = 1,
+ SAMPLE_RATE_44_1 = 2,
+ SAMPLE_RATE_48 = 3
+};
+
+/**
+ * enum cg2900_dai_port_protocol - Port protocol alternatives.
+ * @PORT_PROTOCOL_PCM: Protocol PCM.
+ * @PORT_PROTOCOL_I2S: Protocol I2S.
+ */
+enum cg2900_dai_port_protocol {
+ PORT_PROTOCOL_PCM = 0x00,
+ PORT_PROTOCOL_I2S = 0x01
+};
+
+/**
+ * enum cg2900_dai_channel_sel - The channel selection alternatives.
+ * @CHANNEL_SELECTION_RIGHT: Right channel used.
+ * @CHANNEL_SELECTION_LEFT: Left channel used.
+ * @CHANNEL_SELECTION_BOTH: Both channels used.
+ */
+enum cg2900_dai_channel_sel {
+ CHANNEL_SELECTION_RIGHT = 0x00,
+ CHANNEL_SELECTION_LEFT = 0x01,
+ CHANNEL_SELECTION_BOTH = 0x02
+};
+
+/**
+ * struct cg2900_dai_conf_i2s_pcm - Port configuration structure.
+ * @mode: Operational mode of the port configured.
+ * @i2s_channel_sel: I2S channels used. Only valid if used in I2S mode.
+ * @slot_0_used: True if SCO slot 0 is used.
+ * @slot_1_used: True if SCO slot 1 is used.
+ * @slot_2_used: True if SCO slot 2 is used.
+ * @slot_3_used: True if SCO slot 3 is used.
+ * @slot_0_dir: Direction of slot 0.
+ * @slot_1_dir: Direction of slot 1.
+ * @slot_2_dir: Direction of slot 2.
+ * @slot_3_dir: Direction of slot 3.
+ * @slot_0_start: Slot 0 start (relative to the PCM frame sync).
+ * @slot_1_start: Slot 1 start (relative to the PCM frame sync)
+ * @slot_2_start: Slot 2 start (relative to the PCM frame sync)
+ * @slot_3_start: Slot 3 start (relative to the PCM frame sync)
+ * @ratio: Voice stream ratio between the Audio stream sample rate
+ * and the Voice stream sample rate.
+ * @protocol: Protocol used on port.
+ * @duration: Frame sync duration.
+ * @clk: Bit clock.
+ * @sample_rate: Sample rate.
+ */
+struct cg2900_dai_conf_i2s_pcm {
+ enum cg2900_dai_mode mode;
+ enum cg2900_dai_channel_sel i2s_channel_sel;
+ bool slot_0_used;
+ bool slot_1_used;
+ bool slot_2_used;
+ bool slot_3_used;
+ enum cg2900_dai_dir slot_0_dir;
+ enum cg2900_dai_dir slot_1_dir;
+ enum cg2900_dai_dir slot_2_dir;
+ enum cg2900_dai_dir slot_3_dir;
+ __u8 slot_0_start;
+ __u8 slot_1_start;
+ __u8 slot_2_start;
+ __u8 slot_3_start;
+ enum cg2900_dai_stream_ratio ratio;
+ enum cg2900_dai_port_protocol protocol;
+ enum cg2900_dai_fs_duration duration;
+ enum cg2900_dai_bit_clk clk;
+ enum cg2900_dai_sample_rate sample_rate;
+};
+
+/**
+ * enum cg2900_dai_half_period - Half period duration alternatives.
+ * @HALF_PER_DUR_8: 8 Bits.
+ * @HALF_PER_DUR_16: 16 Bits.
+ * @HALF_PER_DUR_24: 24 Bits.
+ * @HALF_PER_DUR_25: 25 Bits.
+ * @HALF_PER_DUR_32: 32 Bits.
+ * @HALF_PER_DUR_48: 48 Bits.
+ * @HALF_PER_DUR_64: 64 Bits.
+ * @HALF_PER_DUR_75: 75 Bits.
+ * @HALF_PER_DUR_96: 96 Bits.
+ * @HALF_PER_DUR_128: 128 Bits.
+ * @HALF_PER_DUR_150: 150 Bits.
+ * @HALF_PER_DUR_192: 192 Bits.
+ *
+ * This parameter sets the number of bits contained in each I2S half period,
+ * i.e. each channel slot. A usual value is 16 bits.
+ */
+enum cg2900_dai_half_period {
+ HALF_PER_DUR_8 = 0x00,
+ HALF_PER_DUR_16 = 0x01,
+ HALF_PER_DUR_24 = 0x02,
+ HALF_PER_DUR_25 = 0x03,
+ HALF_PER_DUR_32 = 0x04,
+ HALF_PER_DUR_48 = 0x05,
+ HALF_PER_DUR_64 = 0x06,
+ HALF_PER_DUR_75 = 0x07,
+ HALF_PER_DUR_96 = 0x08,
+ HALF_PER_DUR_128 = 0x09,
+ HALF_PER_DUR_150 = 0x0A,
+ HALF_PER_DUR_192 = 0x0B
+};
+
+/**
+ * enum cg2900_dai_word_width - Word width alternatives.
+ * @WORD_WIDTH_16: 16 bits words.
+ * @WORD_WIDTH_32: 32 bits words.
+ */
+enum cg2900_dai_word_width {
+ WORD_WIDTH_16 = 0x00,
+ WORD_WIDTH_32 = 0x01
+};
+
+/**
+ * struct cg2900_dai_conf_i2s - Port configuration struct for I2S.
+ * @mode: Operational mode of the port.
+ * @half_period: Half period duration.
+ * @channel_sel: Channel selection.
+ * @sample_rate: Sample rate.
+ * @word_width: Word width.
+ */
+struct cg2900_dai_conf_i2s {
+ enum cg2900_dai_mode mode;
+ enum cg2900_dai_half_period half_period;
+ enum cg2900_dai_channel_sel channel_sel;
+ enum cg2900_dai_sample_rate sample_rate;
+ enum cg2900_dai_word_width word_width;
+};
+
+/**
+ * union cg2900_dai_port_conf - DAI port configuration union.
+ * @i2s: The configuration struct for a port supporting only I2S.
+ * @i2s_pcm: The configuration struct for a port supporting both PCM and I2S.
+ */
+union cg2900_dai_port_conf {
+ struct cg2900_dai_conf_i2s i2s;
+ struct cg2900_dai_conf_i2s_pcm i2s_pcm;
+};
+
+/**
+ * enum cg2900_dai_ext_port_id - DAI external port id alternatives.
+ * @PORT_0_I2S: Port id is 0 and it supports only I2S.
+ * @PORT_1_I2S_PCM: Port id is 1 and it supports both I2S and PCM.
+ */
+enum cg2900_dai_ext_port_id {
+ PORT_0_I2S,
+ PORT_1_I2S_PCM
+};
+
+/**
+ * enum cg2900_audio_endpoint_id - Audio endpoint id alternatives.
+ * @ENDPOINT_PORT_0_I2S: Internal audio endpoint of the external I2S
+ * interface.
+ * @ENDPOINT_PORT_1_I2S_PCM: Internal audio endpoint of the external I2S/PCM
+ * interface.
+ * @ENDPOINT_SLIMBUS_VOICE: Internal audio endpoint of the external Slimbus
+ * voice interface. (Currently not supported)
+ * @ENDPOINT_SLIMBUS_AUDIO: Internal audio endpoint of the external Slimbus
+ * audio interface. (Currently not supported)
+ * @ENDPOINT_BT_SCO_INOUT: Bluetooth SCO bidirectional.
+ * @ENDPOINT_BT_A2DP_SRC: Bluetooth A2DP source.
+ * @ENDPOINT_BT_A2DP_SNK: Bluetooth A2DP sink.
+ * @ENDPOINT_FM_RX: FM receive.
+ * @ENDPOINT_FM_TX: FM transmit.
+ * @ENDPOINT_ANALOG_OUT: Analog out.
+ * @ENDPOINT_DSP_AUDIO_IN: DSP audio in.
+ * @ENDPOINT_DSP_AUDIO_OUT: DSP audio out.
+ * @ENDPOINT_DSP_VOICE_IN: DSP voice in.
+ * @ENDPOINT_DSP_VOICE_OUT: DSP voice out.
+ * @ENDPOINT_DSP_TONE_IN: DSP tone in.
+ * @ENDPOINT_BURST_BUFFER_IN: Burst buffer in.
+ * @ENDPOINT_BURST_BUFFER_OUT: Burst buffer out.
+ * @ENDPOINT_MUSIC_DECODER: Music decoder.
+ * @ENDPOINT_HCI_AUDIO_IN: HCI audio in.
+ */
+enum cg2900_audio_endpoint_id {
+ ENDPOINT_PORT_0_I2S,
+ ENDPOINT_PORT_1_I2S_PCM,
+ ENDPOINT_SLIMBUS_VOICE,
+ ENDPOINT_SLIMBUS_AUDIO,
+ ENDPOINT_BT_SCO_INOUT,
+ ENDPOINT_BT_A2DP_SRC,
+ ENDPOINT_BT_A2DP_SNK,
+ ENDPOINT_FM_RX,
+ ENDPOINT_FM_TX,
+ ENDPOINT_ANALOG_OUT,
+ ENDPOINT_DSP_AUDIO_IN,
+ ENDPOINT_DSP_AUDIO_OUT,
+ ENDPOINT_DSP_VOICE_IN,
+ ENDPOINT_DSP_VOICE_OUT,
+ ENDPOINT_DSP_TONE_IN,
+ ENDPOINT_BURST_BUFFER_IN,
+ ENDPOINT_BURST_BUFFER_OUT,
+ ENDPOINT_MUSIC_DECODER,
+ ENDPOINT_HCI_AUDIO_IN
+};
+
+/**
+ * struct cg2900_dai_config - Configuration struct for Digital Audio Interface.
+ * @port: The port id to configure. Acts as a discriminator for @conf parameter
+ * which is a union.
+ * @conf: The configuration union that contains the parameters for the port.
+ */
+struct cg2900_dai_config {
+ enum cg2900_dai_ext_port_id port;
+ union cg2900_dai_port_conf conf;
+};
+
+/*
+ * Endpoint configuration types
+ */
+
+/**
+ * enum cg2900_endpoint_sample_rate - Audio endpoint configuration sample rate alternatives.
+ *
+ * This enum defines the same values as @cg2900_dai_sample_rate, but
+ * is kept to preserve the API.
+ *
+ * @ENDPOINT_SAMPLE_RATE_8_KHZ: 8 kHz sample rate.
+ * @ENDPOINT_SAMPLE_RATE_16_KHZ: 16 kHz sample rate.
+ * @ENDPOINT_SAMPLE_RATE_44_1_KHZ: 44.1 kHz sample rate.
+ * @ENDPOINT_SAMPLE_RATE_48_KHZ: 48 kHz sample rate.
+ */
+enum cg2900_endpoint_sample_rate {
+ ENDPOINT_SAMPLE_RATE_8_KHZ = SAMPLE_RATE_8,
+ ENDPOINT_SAMPLE_RATE_16_KHZ = SAMPLE_RATE_16,
+ ENDPOINT_SAMPLE_RATE_44_1_KHZ = SAMPLE_RATE_44_1,
+ ENDPOINT_SAMPLE_RATE_48_KHZ = SAMPLE_RATE_48
+};
+
+
+/**
+ * struct cg2900_endpoint_config_a2dp_src - A2DP source audio endpoint configurations.
+ * @sample_rate: Sample rate.
+ * @channel_count: Number of channels.
+ */
+struct cg2900_endpoint_config_a2dp_src {
+ enum cg2900_endpoint_sample_rate sample_rate;
+ unsigned int channel_count;
+};
+
+/**
+ * struct cg2900_endpoint_config_fm - Configuration parameters for an FM endpoint.
+ * @sample_rate: The sample rate alternatives for the FM audio endpoints.
+ */
+struct cg2900_endpoint_config_fm {
+ enum cg2900_endpoint_sample_rate sample_rate;
+};
+
+
+/**
+ * struct cg2900_endpoint_config_sco_in_out - SCO audio endpoint configuration structure.
+ * @sample_rate: Sample rate, valid values are
+ * * ENDPOINT_SAMPLE_RATE_8_KHZ
+ * * ENDPOINT_SAMPLE_RATE_16_KHZ.
+ */
+struct cg2900_endpoint_config_sco_in_out {
+ enum cg2900_endpoint_sample_rate sample_rate;
+};
+
+/**
+ * union cg2900_endpoint_config - Different audio endpoint configurations.
+ * @sco: SCO audio endpoint configuration structure.
+ * @a2dp_src: A2DP source audio endpoint configuration structure.
+ * @fm: FM audio endpoint configuration structure.
+ */
+union cg2900_endpoint_config_union {
+ struct cg2900_endpoint_config_sco_in_out sco;
+ struct cg2900_endpoint_config_a2dp_src a2dp_src;
+ struct cg2900_endpoint_config_fm fm;
+};
+
+/**
+ * struct cg2900_endpoint_config - Audio endpoint configuration.
+ * @endpoint_id: Identifies the audio endpoint. Works as a discriminator
+ * for the config union.
+ * @config: Union holding the configuration parameters for
+ * the endpoint.
+ */
+struct cg2900_endpoint_config {
+ enum cg2900_audio_endpoint_id endpoint_id;
+ union cg2900_endpoint_config_union config;
+};
+
+/*
+ * ST-Ericsson CG2900 audio control driver interfaces methods
+ */
+
+/**
+ * cg2900_audio_open() - Opens a session to the ST-Ericsson CG2900 Audio control interface.
+ * @session: [out] Address where to store the session identifier.
+ * Allocated by caller, must not be NULL.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL upon bad input parameter.
+ * -ENOMEM upon allocation failure.
+ * -EMFILE if no more user session could be opened.
+ * -EIO upon failure to register to CG2900.
+ */
+int cg2900_audio_open(unsigned int *session);
+
+/**
+ * cg2900_audio_close() - Closes an opened session to the ST-Ericsson CG2900 audio control interface.
+ * @session: [in_out] Pointer to session identifier to close.
+ * Will be 0 after this call.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL upon bad input parameter.
+ * -EIO if driver has not been opened.
+ * -EACCES if session has not opened.
+ */
+int cg2900_audio_close(unsigned int *session);
+
+/**
+ * cg2900_audio_set_dai_config() - Sets the Digital Audio Interface configuration.
+ * @session: Session identifier this call is related to.
+ * @config: Pointer to the configuration to set.
+ * Allocated by caller, must not be NULL.
+ *
+ * Sets the Digital Audio Interface (DAI) configuration. The DAI is the external
+ * interface between the combo chip and the platform.
+ * For example the PCM or I2S interface.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL upon bad input parameter.
+ * -EIO if driver has not been opened.
+ * -ENOMEM upon allocation failure.
+ * -EACCES if trying to set unsupported configuration.
+ * Errors from @receive_bt_cmd_complete.
+ */
+int cg2900_audio_set_dai_config(unsigned int session,
+ struct cg2900_dai_config *config);
+
+/**
+ * cg2900_audio_get_dai_config() - Gets the current Digital Audio Interface configuration.
+ * @session: Session identifier this call is related to.
+ * @config: [out] Pointer to the configuration to get.
+ * Allocated by caller, must not be NULL.
+ *
+ * Gets the current Digital Audio Interface configuration. Currently this method
+ * can only be called after some one has called
+ * cg2900_audio_set_dai_config(), there is today no way of getting
+ * the static settings file parameters from this method.
+ * Note that the @port parameter within @config must be set when calling this
+ * function so that the ST-Ericsson CG2900 Audio driver will know which
+ * configuration to return.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL upon bad input parameter.
+ * -EIO if driver has not been opened or configuration has not been set.
+ */
+int cg2900_audio_get_dai_config(unsigned int session,
+ struct cg2900_dai_config *config);
+
+/**
+ * cg2900_audio_config_endpoint() - Configures one endpoint in the combo chip's audio system.
+ * @session: Session identifier this call is related to.
+ * @config: Pointer to the endpoint's configuration structure.
+ *
+ * Configures one endpoint in the combo chip's audio system.
+ * Supported @endpoint_id values are:
+ * * ENDPOINT_BT_SCO_INOUT
+ * * ENDPOINT_BT_A2DP_SRC
+ * * ENDPOINT_FM_RX
+ * * ENDPOINT_FM_TX
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL upon bad input parameter.
+ * -EIO if driver has not been opened.
+ * -EACCES if supplied cg2900_dai_config struct contains not supported
+ * endpoint_id.
+ */
+int cg2900_audio_config_endpoint(unsigned int session,
+ struct cg2900_endpoint_config *config);
+
+/**
+ * cg2900_audio_start_stream() - Connects two endpoints and starts the audio stream.
+ * @session: Session identifier this call is related to.
+ * @ep_1: One of the endpoints, no relation to direction or role.
+ * @ep_2: The other endpoint, no relation to direction or role.
+ * @stream_handle: Pointer where to store the stream handle.
+ * Allocated by caller, must not be NULL.
+ *
+ * Connects two endpoints and starts the audio stream.
+ * Note that the endpoints need to be configured before the stream is started;
+ * DAI endpoints, such as ENDPOINT_PORT_0_I2S, are
+ * configured through @cg2900_audio_set_dai_config() while other
+ * endpoints are configured through @cg2900_audio_config_endpoint().
+ *
+ * Supported @endpoint_id values are:
+ * * ENDPOINT_PORT_0_I2S
+ * * ENDPOINT_PORT_1_I2S_PCM
+ * * ENDPOINT_BT_SCO_INOUT
+ * * ENDPOINT_FM_RX
+ * * ENDPOINT_FM_TX
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL upon bad input parameter or unsupported configuration.
+ * -EIO if driver has not been opened.
+ * Errors from @conn_start_i2s_to_fm_rx, @conn_start_i2s_to_fm_tx, and
+ * @conn_start_pcm_to_sco.
+ */
+int cg2900_audio_start_stream(unsigned int session,
+ enum cg2900_audio_endpoint_id ep_1,
+ enum cg2900_audio_endpoint_id ep_2,
+ unsigned int *stream_handle);
+
+/**
+ * cg2900_audio_stop_stream() - Stops a stream and disconnects the endpoints.
+ * @session: Session identifier this call is related to.
+ * @stream_handle: Handle to the stream to stop.
+ *
+ * Returns:
+ * 0 if there is no error.
+ * -EINVAL upon bad input parameter.
+ * -EIO if driver has not been opened.
+ */
+int cg2900_audio_stop_stream(unsigned int session,
+ unsigned int stream_handle);
+
+#endif /* _CG2900_AUDIO_H_ */
diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h
new file mode 100644
index 00000000000..e762c270d8d
--- /dev/null
+++ b/include/linux/mfd/stmpe.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ */
+
+#ifndef __LINUX_MFD_STMPE_H
+#define __LINUX_MFD_STMPE_H
+
+#include <linux/device.h>
+
+enum stmpe_block {
+ STMPE_BLOCK_GPIO = 1 << 0,
+ STMPE_BLOCK_KEYPAD = 1 << 1,
+ STMPE_BLOCK_TOUCHSCREEN = 1 << 2,
+ STMPE_BLOCK_ADC = 1 << 3,
+ STMPE_BLOCK_PWM = 1 << 4,
+ STMPE_BLOCK_ROTATOR = 1 << 5,
+};
+
+enum stmpe_partnum {
+ STMPE811,
+ STMPE1601,
+ STMPE2401,
+ STMPE2403,
+};
+
+/*
+ * For registers whose locations differ on variants, the correct address is
+ * obtained by indexing stmpe->regs with one of the following.
+ */
+enum {
+ STMPE_IDX_CHIP_ID,
+ STMPE_IDX_ICR_LSB,
+ STMPE_IDX_IER_LSB,
+ STMPE_IDX_ISR_MSB,
+ STMPE_IDX_GPMR_LSB,
+ STMPE_IDX_GPSR_LSB,
+ STMPE_IDX_GPCR_LSB,
+ STMPE_IDX_GPDR_LSB,
+ STMPE_IDX_GPEDR_MSB,
+ STMPE_IDX_GPRER_LSB,
+ STMPE_IDX_GPFER_LSB,
+ STMPE_IDX_GPAFR_U_MSB,
+ STMPE_IDX_IEGPIOR_LSB,
+ STMPE_IDX_ISGPIOR_MSB,
+ STMPE_IDX_MAX,
+};
+
+
+struct stmpe_variant_info;
+
+/**
+ * struct stmpe - STMPE MFD structure
+ * @lock: lock protecting I/O operations
+ * @irq_lock: IRQ bus lock
+ * @dev: device, mostly for dev_dbg()
+ * @i2c: i2c client
+ * @variant: the detected STMPE model number
+ * @regs: list of addresses of registers which are at different addresses on
+ * different variants. Indexed by one of STMPE_IDX_*.
+ * @irq_base: starting IRQ number for internal IRQs
+ * @num_gpios: number of gpios, differs for variants
+ * @ier: cache of IER registers for bus_lock
+ * @oldier: cache of IER registers for bus_lock
+ * @pdata: platform data
+ */
+struct stmpe {
+ struct mutex lock;
+ struct mutex irq_lock;
+ struct device *dev;
+ struct i2c_client *i2c;
+ enum stmpe_partnum partnum;
+ struct stmpe_variant_info *variant;
+ const u8 *regs;
+
+ int irq_base;
+ int num_gpios;
+ u8 ier[2];
+ u8 oldier[2];
+ struct stmpe_platform_data *pdata;
+};
+
+extern int stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 data);
+extern int stmpe_reg_read(struct stmpe *stmpe, u8 reg);
+extern int stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length,
+ u8 *values);
+extern int stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
+ const u8 *values);
+extern int stmpe_set_bits(struct stmpe *stmpe, u8 reg, u8 mask, u8 val);
+extern int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins,
+ enum stmpe_block block);
+extern int stmpe_enable(struct stmpe *stmpe, unsigned int blocks);
+extern int stmpe_disable(struct stmpe *stmpe, unsigned int blocks);
+
+struct matrix_keymap_data;
+
+/**
+ * struct stmpe_keypad_platform_data - STMPE keypad platform data
+ * @keymap_data: key map table and size
+ * @debounce_ms: debounce interval, in ms. Maximum is
+ * %STMPE_KEYPAD_MAX_DEBOUNCE.
+ * @scan_count: number of key scanning cycles to confirm key data.
+ * Maximum is %STMPE_KEYPAD_MAX_SCAN_COUNT.
+ * @no_autorepeat: disable key autorepeat
+ */
+struct stmpe_keypad_platform_data {
+ struct matrix_keymap_data *keymap_data;
+ unsigned int debounce_ms;
+ unsigned int scan_count;
+ bool no_autorepeat;
+};
+
+#define STMPE_GPIO_NOREQ_811_TOUCH (0xf0)
+
+/**
+ * struct stmpe_gpio_platform_data - STMPE GPIO platform data
+ * @gpio_base: first gpio number assigned. A maximum of
+ * %STMPE_NR_GPIOS GPIOs will be allocated.
+ * @norequest_mask: bitmask specifying which GPIOs should _not_ be
+ * requestable due to different usage (e.g. touch, keypad)
+ * STMPE_GPIO_NOREQ_* macros can be used here.
+ */
+struct stmpe_gpio_platform_data {
+ int gpio_base;
+ unsigned norequest_mask;
+ void (*setup)(struct stmpe *stmpe, unsigned gpio_base);
+ void (*remove)(struct stmpe *stmpe, unsigned gpio_base);
+};
+
+/**
+ * struct stmpe_ts_platform_data - stmpe811 touch screen controller platform
+ * data
+ * @sample_time: ADC converstion time in number of clock.
+ * (0 -> 36 clocks, 1 -> 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks,
+ * 4 -> 80 clocks, 5 -> 96 clocks, 6 -> 144 clocks),
+ * recommended is 4.
+ * @mod_12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC)
+ * @ref_sel: ADC reference source
+ * (0 -> internal reference, 1 -> external reference)
+ * @adc_freq: ADC Clock speed
+ * (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz)
+ * @ave_ctrl: Sample average control
+ * (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples)
+ * @touch_det_delay: Touch detect interrupt delay
+ * (0 -> 10 us, 1 -> 50 us, 2 -> 100 us, 3 -> 500 us,
+ * 4-> 1 ms, 5 -> 5 ms, 6 -> 10 ms, 7 -> 50 ms)
+ * recommended is 3
+ * @settling: Panel driver settling time
+ * (0 -> 10 us, 1 -> 100 us, 2 -> 500 us, 3 -> 1 ms,
+ * 4 -> 5 ms, 5 -> 10 ms, 6 for 50 ms, 7 -> 100 ms)
+ * recommended is 2
+ * @fraction_z: Length of the fractional part in z
+ * (fraction_z ([0..7]) = Count of the fractional part)
+ * recommended is 7
+ * @i_drive: current limit value of the touchscreen drivers
+ * (0 -> 20 mA typical 35 mA max, 1 -> 50 mA typical 80 mA max)
+ *
+ * */
+struct stmpe_ts_platform_data {
+ u8 sample_time;
+ u8 mod_12b;
+ u8 ref_sel;
+ u8 adc_freq;
+ u8 ave_ctrl;
+ u8 touch_det_delay;
+ u8 settling;
+ u8 fraction_z;
+ u8 i_drive;
+};
+
+/**
+ * struct stmpe_platform_data - STMPE platform data
+ * @id: device id to distinguish between multiple STMPEs on the same board
+ * @blocks: bitmask of blocks to enable (use STMPE_BLOCK_*)
+ * @irq_trigger: IRQ trigger to use for the interrupt to the host
+ * @irq_invert_polarity: IRQ line is connected with reversed polarity
+ * @autosleep: bool to enable/disable stmpe autosleep
+ * @autosleep_timeout: inactivity timeout in milliseconds for autosleep
+ * @irq_base: base IRQ number. %STMPE_NR_IRQS irqs will be used, or
+ * %STMPE_NR_INTERNAL_IRQS if the GPIO driver is not used.
+ * @gpio: GPIO-specific platform data
+ * @keypad: keypad-specific platform data
+ * @ts: touchscreen-specific platform data
+ */
+struct stmpe_platform_data {
+ int id;
+ unsigned int blocks;
+ int irq_base;
+ unsigned int irq_trigger;
+ bool irq_invert_polarity;
+ bool autosleep;
+ int autosleep_timeout;
+
+ struct stmpe_gpio_platform_data *gpio;
+ struct stmpe_keypad_platform_data *keypad;
+ struct stmpe_ts_platform_data *ts;
+};
+
+#define STMPE_NR_INTERNAL_IRQS 9
+#define STMPE_INT_GPIO(x) (STMPE_NR_INTERNAL_IRQS + (x))
+
+#define STMPE_NR_GPIOS 24
+#define STMPE_NR_IRQS STMPE_INT_GPIO(STMPE_NR_GPIOS)
+
+#endif
diff --git a/include/linux/mfd/tc35892.h b/include/linux/mfd/tc35892.h
index e47f770d306..eff3094ca84 100644
--- a/include/linux/mfd/tc35892.h
+++ b/include/linux/mfd/tc35892.h
@@ -111,9 +111,13 @@ extern int tc35892_set_bits(struct tc35892 *tc35892, u8 reg, u8 mask, u8 val);
* struct tc35892_gpio_platform_data - TC35892 GPIO platform data
* @gpio_base: first gpio number assigned to TC35892. A maximum of
* %TC35892_NR_GPIOS GPIOs will be allocated.
+ * @setup: callback for board-specific initialization
+ * @remove: callback for board-specific teardown
*/
struct tc35892_gpio_platform_data {
int gpio_base;
+ void (*setup)(struct tc35892 *tc35892, unsigned gpio_base);
+ void (*remove)(struct tc35892 *tc35892, unsigned gpio_base);
};
/**
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c83c7a7303f..3e89cf9ec84 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -45,6 +45,7 @@ struct mmc_ext_csd {
unsigned int sa_timeout; /* Units: 100ns */
unsigned int hs_max_dtr;
unsigned int sectors;
+ unsigned int card_type;
};
struct sd_scr {
@@ -98,6 +99,7 @@ struct mmc_card {
#define MMC_STATE_READONLY (1<<1) /* card is read-only */
#define MMC_STATE_HIGHSPEED (1<<2) /* card is in high speed mode */
#define MMC_STATE_BLOCKADDR (1<<3) /* card uses block-addressing */
+#define MMC_STATE_HIGHSPEED_DDR (1<<4) /* card is in high speed mode */
unsigned int quirks; /* card quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
@@ -131,11 +133,13 @@ struct mmc_card {
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED)
#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
+#define mmc_card_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
+#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
{
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index e4898e9eeb5..550cf3da330 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -107,6 +107,7 @@ struct mmc_data {
#define MMC_DATA_WRITE (1 << 8)
#define MMC_DATA_READ (1 << 9)
#define MMC_DATA_STREAM (1 << 10)
+#define MMC_DDR_MODE (1 << 11)
unsigned int bytes_xfered;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 229ba190607..26cd95befec 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -156,6 +156,11 @@ struct mmc_host {
#define MMC_CAP_DISABLE (1 << 7) /* Can the host be disabled */
#define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */
#define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */
+#define MMC_CAP_POWER_OF_TWO_BLKSIZE (1 << 10) /* Host requires that blocksize must be power of two */
+#define MMC_CAP_1_8V_DDR (1 << 11) /* can support */
+ /* DDR mode at 1.8V */
+#define MMC_CAP_1_2V_DDR (1 << 12) /* can support */
+ /* DDR mode at 1.2V */
mmc_pm_flag_t pm_caps; /* supported pm features */
@@ -204,6 +209,7 @@ struct mmc_host {
unsigned int bus_resume_flags;
#define MMC_BUSRESUME_MANUAL_RESUME (1 << 0)
#define MMC_BUSRESUME_NEEDS_RESUME (1 << 1)
+#define MMC_NEEDS_UNSAFE_RESUME (1 << 2)
unsigned int sdio_irqs;
struct task_struct *sdio_irq_thread;
@@ -215,6 +221,10 @@ struct mmc_host {
struct led_trigger *led; /* activity led */
#endif
+#ifdef CONFIG_REGULATOR
+ bool regulator_enabled; /* regulator state */
+#endif
+
struct dentry *debugfs_root;
#ifdef CONFIG_MMC_EMBEDDED_SDIO
@@ -282,8 +292,24 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
struct regulator;
+#ifdef CONFIG_REGULATOR
int mmc_regulator_get_ocrmask(struct regulator *supply);
-int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit);
+int mmc_regulator_set_ocr(struct mmc_host *mmc,
+ struct regulator *supply,
+ unsigned short vdd_bit);
+#else
+static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
+{
+ return 0;
+}
+
+static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
+ struct regulator *supply,
+ unsigned short vdd_bit)
+{
+ return 0;
+}
+#endif
int mmc_card_awake(struct mmc_host *host);
int mmc_card_sleep(struct mmc_host *host);
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 5414fa6a47f..41e961be646 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -269,11 +269,19 @@ struct _mmc_csd {
#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */
-#define EXT_CSD_CARD_TYPE_MASK 0x3 /* Mask out reserved and DDR bits */
+#define EXT_CSD_CARD_TYPE_MASK 0xF /* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */
+ /* DDR mode @1.8V or 3V I/O */
+#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
+ /* DDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
+ | EXT_CSD_CARD_TYPE_DDR_1_2V)
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
+#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
+#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
/*
* MMC_SWITCH access modes
diff --git a/include/linux/phonet.h b/include/linux/phonet.h
index e5126cff9b2..3f63819b9f0 100644
--- a/include/linux/phonet.h
+++ b/include/linux/phonet.h
@@ -36,6 +36,10 @@
/* Socket options for SOL_PNPIPE level */
#define PNPIPE_ENCAP 1
#define PNPIPE_IFINDEX 2
+#define PNPIPE_CREATE 3
+#define PNPIPE_ENABLE 4
+/* unused slot */
+#define PNPIPE_DESTROY 6
#define PNADDR_ANY 0
#define PNADDR_BROADCAST 0xFC
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index 01b3d759f1f..e031e1a486d 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -8,6 +8,7 @@ struct platform_pwm_backlight_data {
int pwm_id;
unsigned int max_brightness;
unsigned int dft_brightness;
+ unsigned int lth_brightness;
unsigned int pwm_period_ns;
int (*init)(struct device *dev);
int (*notify)(struct device *dev, int brightness);
diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h
new file mode 100644
index 00000000000..661026bdd6b
--- /dev/null
+++ b/include/linux/regulator/ab8500.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ * Changes: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ */
+
+#ifndef __LINUX_MFD_AB8500_REGULATOR_H
+#define __LINUX_MFD_AB8500_REGULATOR_H
+
+/* AB8500 regulators */
+#define AB8500_LDO_AUX1 0
+#define AB8500_LDO_AUX2 1
+#define AB8500_LDO_AUX3 2
+#define AB8500_LDO_INTCORE 3
+#define AB8500_LDO_TVOUT 4
+#define AB8500_LDO_USB 5
+#define AB8500_LDO_AUDIO 6
+#define AB8500_LDO_ANAMIC1 7
+#define AB8500_LDO_ANAMIC2 8
+#define AB8500_LDO_DMIC 9
+#define AB8500_LDO_ANA 10
+
+#endif
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index fb46aba11fb..7638deaaba6 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -32,6 +32,9 @@ struct plat_serial8250_port {
unsigned int type; /* If UPF_FIXED_TYPE */
unsigned int (*serial_in)(struct uart_port *, int);
void (*serial_out)(struct uart_port *, int, int);
+ void (*set_termios)(struct uart_port *,
+ struct ktermios *new,
+ struct ktermios *old);
};
/*
@@ -71,5 +74,7 @@ extern int early_serial_setup(struct uart_port *port);
extern int serial8250_find_port(struct uart_port *p);
extern int serial8250_find_port_for_earlycon(void);
extern int setup_early_serial8250_console(char *cmdline);
+extern void serial8250_do_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old);
#endif
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 027b8a0c0ff..1cb31275ed8 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -44,7 +44,8 @@
#define PORT_RM9000 16 /* PMC-Sierra RM9xxx internal UART */
#define PORT_OCTEON 17 /* Cavium OCTEON internal UART */
#define PORT_AR7 18 /* Texas Instruments AR7 internal UART */
-#define PORT_MAX_8250 18 /* max port ID */
+#define PORT_U6_16550A 19 /* ST-Ericsson U6xxx internal UART */
+#define PORT_MAX_8250 19 /* max port ID */
/*
* ARM specific type numbers. These are not currently guaranteed
@@ -277,6 +278,9 @@ struct uart_port {
unsigned char __iomem *membase; /* read/write[bwl] */
unsigned int (*serial_in)(struct uart_port *, int);
void (*serial_out)(struct uart_port *, int, int);
+ void (*set_termios)(struct uart_port *,
+ struct ktermios *new,
+ struct ktermios *old);
unsigned int irq; /* irq number */
unsigned long irqflags; /* irq flags */
unsigned int uartclk; /* base uart clock */
diff --git a/include/linux/spi/stm_msp.h b/include/linux/spi/stm_msp.h
new file mode 100644
index 00000000000..2d067ae1077
--- /dev/null
+++ b/include/linux/spi/stm_msp.h
@@ -0,0 +1,542 @@
+/*****************************************************************************
+ * copyright STMicroelectronics, 2007.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *****************************************************************************/
+
+#ifndef MSP_SPI_HEADER
+#define MSP_SPI_HEADER
+
+#define DEFAULT_MSP_CLK 48000000
+#define MAX_SCKDIV 1023
+#define MSP_FIFO_DEPTH 8
+
+/**
+ * MSP Global Configuration Register - msp_gcr
+ */
+#define MSP_GCR_MASK_RXEN ((u32)(0x1UL << 0))
+#define MSP_GCR_MASK_RFFEN ((u32)(0x1UL << 1))
+#define MSP_GCR_MASK_RFSPOL ((u32)(0x1UL << 2))
+#define MSP_GCR_MASK_DCM ((u32)(0x1UL << 3))
+#define MSP_GCR_MASK_RFSSEL ((u32)(0x1UL << 4))
+#define MSP_GCR_MASK_RCKPOL ((u32)(0x1UL << 5))
+#define MSP_GCR_MASK_RCKSEL ((u32)(0x1UL << 6))
+#define MSP_GCR_MASK_LBM ((u32)(0x1UL << 7))
+#define MSP_GCR_MASK_TXEN ((u32)(0x1UL << 8))
+#define MSP_GCR_MASK_TFFEN ((u32)(0x1UL << 9))
+#define MSP_GCR_MASK_TFSPOL ((u32)(0x1UL << 10))
+#define MSP_GCR_MASK_TFSSEL ((u32)(0x3UL << 11))
+#define MSP_GCR_MASK_TCKPOL ((u32)(0x1UL << 13))
+#define MSP_GCR_MASK_TCKSEL ((u32)(0x1UL << 14))
+#define MSP_GCR_MASK_TXDDL ((u32)(0x1UL << 15))
+#define MSP_GCR_MASK_SGEN ((u32)(0x1UL << 16))
+#define MSP_GCR_MASK_SCKPOL ((u32)(0x1UL << 17))
+#define MSP_GCR_MASK_SCKSEL ((u32)(0x3UL << 18))
+#define MSP_GCR_MASK_FGEN ((u32)(0x1UL << 20))
+#define MSP_GCR_MASK_SPICKM ((u32)(0x3UL << 21))
+#define MSP_GCR_MASK_SPIBME ((u32)(0x1UL << 23))
+
+/**
+ * MSP Transmit Configuration Register - msp_tcf
+ */
+#define MSP_TCF_MASK_TP1ELEN ((u32)(0x7UL << 0))
+#define MSP_TCF_MASK_TP1FLEN ((u32)(0x7FUL << 3))
+#define MSP_TCF_MASK_TDTYP ((u32)(0x3UL << 10))
+#define MSP_TCF_MASK_TENDN ((u32)(0x1UL << 12))
+#define MSP_TCF_MASK_TDDLY ((u32)(0x3UL << 13))
+#define MSP_TCF_MASK_TFSIG ((u32)(0x1UL << 15))
+#define MSP_TCF_MASK_TP2ELEN ((u32)(0x7UL << 16))
+#define MSP_TCF_MASK_TP2FLEN ((u32)(0x7FUL << 19))
+#define MSP_TCF_MASK_TP2SM ((u32)(0x1UL << 26))
+#define MSP_TCF_MASK_TP2EN ((u32)(0x1UL << 27))
+#define MSP_TCF_MASK_TBSWAP ((u32)(0x3UL << 28))
+
+/**
+ * MSP Receive Configuration Register - msp_rcf
+ */
+#define MSP_RCF_MASK_RP1ELEN ((u32)(0x7UL << 0))
+#define MSP_RCF_MASK_RP1FLEN ((u32)(0x7FUL << 3))
+#define MSP_RCF_MASK_RDTYP ((u32)(0x3UL << 10))
+#define MSP_RCF_MASK_RENDN ((u32)(0x1UL << 12))
+#define MSP_RCF_MASK_RDDLY ((u32)(0x3UL << 13))
+#define MSP_RCF_MASK_RFSIG ((u32)(0x1UL << 15))
+#define MSP_RCF_MASK_RP2ELEN ((u32)(0x7UL << 16))
+#define MSP_RCF_MASK_RP2FLEN ((u32)(0x7FUL << 19))
+#define MSP_RCF_MASK_RP2SM ((u32)(0x1UL << 26))
+#define MSP_RCF_MASK_RP2EN ((u32)(0x1UL << 27))
+#define MSP_RCF_MASK_RBSWAP ((u32)(0x3UL << 28))
+
+/**
+ * MSP Sample Rate Generator Register - msp_srg
+ */
+#define MSP_SRG_MASK_SCKDIV ((u32)(0x3FFUL << 0))
+#define MSP_SRG_MASK_FRWID ((u32)(0x3FUL << 10))
+#define MSP_SRG_MASK_FRPER ((u32)(0x1FFFUL << 16))
+
+/**
+ * MSP Flag Register - msp_flr
+ */
+#define MSP_FLR_MASK_RBUSY ((u32)(0x1UL << 0))
+#define MSP_FLR_MASK_RFE ((u32)(0x1UL << 1))
+#define MSP_FLR_MASK_RFU ((u32)(0x1UL << 2))
+#define MSP_FLR_MASK_TBUSY ((u32)(0x1UL << 3))
+#define MSP_FLR_MASK_TFE ((u32)(0x1UL << 4))
+#define MSP_FLR_MASK_TFU ((u32)(0x1UL << 5))
+
+/**
+ * MSP DMA Control Register - msp_dmacr
+ */
+#define MSP_DMACR_MASK_RDMAE ((u32)(0x1UL << 0))
+#define MSP_DMACR_MASK_TDMAE ((u32)(0x1UL << 1))
+
+/**
+ * MSP Interrupt Mask Set/Clear Register - msp_imsc
+ */
+#define MSP_IMSC_MASK_RXIM ((u32)(0x1UL << 0))
+#define MSP_IMSC_MASK_ROEIM ((u32)(0x1UL << 1))
+#define MSP_IMSC_MASK_RSEIM ((u32)(0x1UL << 2))
+#define MSP_IMSC_MASK_RFSIM ((u32)(0x1UL << 3))
+#define MSP_IMSC_MASK_TXIM ((u32)(0x1UL << 4))
+#define MSP_IMSC_MASK_TUEIM ((u32)(0x1UL << 5))
+#define MSP_IMSC_MASK_TSEIM ((u32)(0x1UL << 6))
+#define MSP_IMSC_MASK_TFSIM ((u32)(0x1UL << 7))
+#define MSP_IMSC_MASK_RFOIM ((u32)(0x1UL << 8))
+#define MSP_IMSC_MASK_TFOIM ((u32)(0x1UL << 9))
+
+/**
+ * MSP Raw Interrupt status Register - msp_ris
+ */
+#define MSP_RIS_MASK_RXRIS ((u32)(0x1UL << 0))
+#define MSP_RIS_MASK_ROERIS ((u32)(0x1UL << 1))
+#define MSP_RIS_MASK_RSERIS ((u32)(0x1UL << 2))
+#define MSP_RIS_MASK_RFSRIS ((u32)(0x1UL << 3))
+#define MSP_RIS_MASK_TXRIS ((u32)(0x1UL << 4))
+#define MSP_RIS_MASK_TUERIS ((u32)(0x1UL << 5))
+#define MSP_RIS_MASK_TSERIS ((u32)(0x1UL << 6))
+#define MSP_RIS_MASK_TFSRIS ((u32)(0x1UL << 7))
+#define MSP_RIS_MASK_RFORIS ((u32)(0x1UL << 8))
+#define MSP_RIS_MASK_TFORIS ((u32)(0x1UL << 9))
+
+/**
+ * MSP Masked Interrupt status Register - msp_mis
+ */
+#define MSP_MIS_MASK_RXMIS ((u32)(0x1UL << 0))
+#define MSP_MIS_MASK_ROEMIS ((u32)(0x1UL << 1))
+#define MSP_MIS_MASK_RSEMIS ((u32)(0x1UL << 2))
+#define MSP_MIS_MASK_RFSMIS ((u32)(0x1UL << 3))
+#define MSP_MIS_MASK_TXMIS ((u32)(0x1UL << 4))
+#define MSP_MIS_MASK_TUEMIS ((u32)(0x1UL << 5))
+#define MSP_MIS_MASK_TSEMIS ((u32)(0x1UL << 6))
+#define MSP_MIS_MASK_TFSMIS ((u32)(0x1UL << 7))
+#define MSP_MIS_MASK_RFOMIS ((u32)(0x1UL << 8))
+#define MSP_MIS_MASK_TFOMIS ((u32)(0x1UL << 9))
+
+/**
+ * MSP Interrupt Clear Register - msp_icr
+ */
+#define MSP_ICR_MASK_ROEIC ((u32)(0x1UL << 1))
+#define MSP_ICR_MASK_RSEIC ((u32)(0x1UL << 2))
+#define MSP_ICR_MASK_RFSIC ((u32)(0x1UL << 3))
+#define MSP_ICR_MASK_TUEIC ((u32)(0x1UL << 5))
+#define MSP_ICR_MASK_TSEIC ((u32)(0x1UL << 6))
+#define MSP_ICR_MASK_TFSIC ((u32)(0x1UL << 7))
+
+/**
+ * MSP Receiver/Transmitter states (Enabled or disabled)
+ */
+#define MSP_RECEIVER_DISABLED 0
+#define MSP_RECEIVER_ENABLED 1
+#define MSP_TRANSMITTER_DISABLED 0
+#define MSP_TRANSMITTER_ENABLED 1
+
+/**
+ * MSP Receiver/Transmitter FIFO constants
+ */
+#define MSP_LOOPBACK_DISABLED 0
+#define MSP_LOOPBACK_ENABLED 1
+
+#define MSP_TX_FIFO_DISABLED 0
+#define MSP_TX_FIFO_ENABLED 1
+#define MSP_TX_ENDIANESS_MSB 0
+#define MSP_TX_ENDIANESS_LSB 1
+
+#define MSP_RX_FIFO_DISABLED 0
+#define MSP_RX_FIFO_ENABLED 1
+#define MSP_RX_ENDIANESS_MSB 0
+#define MSP_RX_ENDIANESS_LSB 1
+
+/**
+ * MSP Controller State constants
+ */
+#define MSP_IS_SPI_SLAVE 0
+#define MSP_IS_SPI_MASTER 1
+
+#define SPI_BURST_MODE_DISABLE 0
+#define SPI_BURST_MODE_ENABLE 1
+
+/**
+ * MSP Phase and Polarity constants
+ */
+#define MSP_SPI_PHASE_ZERO_CYCLE_DELAY 0x2
+#define MSP_SPI_PHASE_HALF_CYCLE_DELAY 0x3
+
+#define MSP_TX_CLOCK_POL_LOW 0
+#define MSP_TX_CLOCK_POL_HIGH 1
+
+/**
+ * MSP SRG and Frame related constants
+ */
+#define MSP_FRAME_GEN_DISABLE 0
+#define MSP_FRAME_GEN_ENABLE 1
+
+#define MSP_SAMPLE_RATE_GEN_DISABLE 0
+#define MSP_SAMPLE_RATE_GEN_ENABLE 1
+
+#define MSP_CLOCK_INTERNAL 0x0 /*48 MHz*/
+#define MSP_CLOCK_EXTERNAL 0x2 /*SRG is derived from MSPSCK*/
+/* SRG is derived from MSPSCK pin but is resynchronized on MSPRFS
+ * (Receive Frame Sync signal)*/
+#define MSP_CLOCK_EXTERNAL_RESYNC 0x3
+
+#define MSP_TRANSMIT_DATA_WITHOUT_DELAY 0
+#define MSP_TRANSMIT_DATA_WITH_DELAY 1
+
+/* INT: means frame sync signal provided by frame generator logic in the MSP
+EXT: means frame sync signal provided by external pin MSPTFS
+*/
+#define MSP_TX_FRAME_SYNC_EXT 0x0
+#define MSP_TX_FRAME_SYNC_INT 0x2
+#define MSP_TX_FRAME_SYNC_INT_CFG 0x3
+
+#define MSP_TX_FRAME_SYNC_POL_HIGH 0
+#define MSP_TX_FRAME_SYNC_POL_LOW 1
+
+#define MSP_HANDLE_RX_FRAME_SYNC_PULSE 0
+#define MSP_IGNORE_RX_FRAME_SYNC_PULSE 1
+
+#define MSP_RX_NO_DATA_DELAY 0x0
+#define MSP_RX_1BIT_DATA_DELAY 0x1
+#define MSP_RX_2BIT_DATA_DELAY 0x2
+#define MSP_RX_3BIT_DATA_DELAY 0x3
+
+#define MSP_HANDLE_TX_FRAME_SYNC_PULSE 0
+#define MSP_IGNORE_TX_FRAME_SYNC_PULSE 1
+
+#define MSP_TX_NO_DATA_DELAY 0x0
+#define MSP_TX_1BIT_DATA_DELAY 0x1
+#define MSP_TX_2BIT_DATA_DELAY 0x2
+#define MSP_TX_3BIT_DATA_DELAY 0x3
+
+/**
+ * MSP Interrupt related Macros
+ */
+#define DISABLE_ALL_MSP_INTERRUPTS 0x0
+#define ENABLE_ALL_MSP_INTERRUPTS 0x333
+#define CLEAR_ALL_MSP_INTERRUPTS 0xEE
+
+/**
+ * Default MSP Register Values
+ */
+#define DEFAULT_MSP_REG_DMACR 0x00000000
+#define DEFAULT_MSP_REG_SRG 0x1FFF0000
+#define DEFAULT_MSP_REG_GCR ( \
+ GEN_MASK_BITS(MSP_RECEIVER_DISABLED, MSP_GCR_MASK_RXEN, 0) |\
+ GEN_MASK_BITS(MSP_RX_FIFO_ENABLED, MSP_GCR_MASK_RFFEN, 1) |\
+ GEN_MASK_BITS(MSP_LOOPBACK_DISABLED, MSP_GCR_MASK_LBM, 7) |\
+ GEN_MASK_BITS(MSP_TRANSMITTER_DISABLED, MSP_GCR_MASK_TXEN, 8) |\
+ GEN_MASK_BITS(MSP_TX_FIFO_ENABLED, MSP_GCR_MASK_TFFEN, 9) |\
+ GEN_MASK_BITS(MSP_TX_FRAME_SYNC_POL_LOW, MSP_GCR_MASK_TFSPOL, 10)|\
+ GEN_MASK_BITS(MSP_TX_FRAME_SYNC_INT, MSP_GCR_MASK_TFSSEL, 11) |\
+ GEN_MASK_BITS(MSP_TX_CLOCK_POL_HIGH, MSP_GCR_MASK_TCKPOL, 13) |\
+ GEN_MASK_BITS(MSP_IS_SPI_MASTER, MSP_GCR_MASK_TCKSEL, 14) |\
+ GEN_MASK_BITS(MSP_TRANSMIT_DATA_WITHOUT_DELAY, MSP_GCR_MASK_TXDDL, 15)|\
+ GEN_MASK_BITS(MSP_SAMPLE_RATE_GEN_ENABLE, MSP_GCR_MASK_SGEN, 16)|\
+ GEN_MASK_BITS(MSP_CLOCK_INTERNAL, MSP_GCR_MASK_SCKSEL, 18) |\
+ GEN_MASK_BITS(MSP_FRAME_GEN_ENABLE, MSP_GCR_MASK_FGEN, 20) |\
+ GEN_MASK_BITS(MSP_SPI_PHASE_ZERO_CYCLE_DELAY, MSP_GCR_MASK_SPICKM, 21)|\
+ GEN_MASK_BITS(SPI_BURST_MODE_DISABLE, MSP_GCR_MASK_SPIBME, 23)\
+ )
+
+#define DEFAULT_MSP_REG_RCF ( \
+ GEN_MASK_BITS(MSP_DATA_BITS_32, MSP_RCF_MASK_RP1ELEN, 0) | \
+ GEN_MASK_BITS(MSP_IGNORE_RX_FRAME_SYNC_PULSE, MSP_RCF_MASK_RFSIG, 15) |\
+ GEN_MASK_BITS(MSP_RX_1BIT_DATA_DELAY, MSP_RCF_MASK_RDDLY, 13) | \
+ GEN_MASK_BITS(MSP_RX_ENDIANESS_LSB, MSP_RCF_MASK_RENDN, 12) \
+ )
+
+#define DEFAULT_MSP_REG_TCF ( \
+ GEN_MASK_BITS(MSP_DATA_BITS_32, MSP_TCF_MASK_TP1ELEN, 0) | \
+ GEN_MASK_BITS(MSP_IGNORE_TX_FRAME_SYNC_PULSE, MSP_TCF_MASK_TFSIG, 15) |\
+ GEN_MASK_BITS(MSP_TX_1BIT_DATA_DELAY, MSP_TCF_MASK_TDDLY, 13) | \
+ GEN_MASK_BITS(MSP_TX_ENDIANESS_LSB, MSP_TCF_MASK_TENDN, 12) \
+ )
+
+/* Private Interface : Not meant for client drivers*/
+
+#define SPI_REG_WRITE_BITS(reg, val, mask, sb) \
+ ((reg) = (((reg) & ~(mask)) | (((val)<<(sb)) & (mask))))
+#define GEN_MASK_BITS(val, mask, sb) ((u32)((((u32)val)<<(sb)) & (mask)))
+
+/* Message State */
+#define START_STATE ((void *)0)
+#define RUNNING_STATE ((void *)1)
+#define DONE_STATE ((void *)2)
+#define ERROR_STATE ((void *)-1)
+
+enum msp_data_size {
+ MSP_DATA_BITS_DEFAULT = -1,
+ MSP_DATA_BITS_8 = 0x00,
+ MSP_DATA_BITS_10,
+ MSP_DATA_BITS_12,
+ MSP_DATA_BITS_14,
+ MSP_DATA_BITS_16,
+ MSP_DATA_BITS_20,
+ MSP_DATA_BITS_24,
+ MSP_DATA_BITS_32,
+};
+
+enum msp_clk_src {
+ MSP_INTERNAL_CLK = 0x0,
+ MSP_EXTERNAL_CLK,
+};
+
+struct msp_clock_params {
+ enum msp_clk_src clk_src;
+ /* value from 0 to 1023 */
+ u16 sckdiv;
+ /*Used only when MSPSCK clocks the sample rate generator (SCKSEL = 1Xb):
+ * 0b: The rising edge of MSPSCK clocks the sample rate generator
+ * 1b: The falling edge of MSPSCK clocks the sample rate generator */
+ int sckpol;
+};
+
+/* Common configuration for different SPI controllers */
+enum spi_loopback {
+ SPI_LOOPBACK_DISABLED,
+ SPI_LOOPBACK_ENABLED
+};
+
+enum spi_hierarchy {
+ SPI_MASTER,
+ SPI_SLAVE
+};
+
+/* Endianess of FIFO Data */
+enum spi_fifo_endian {
+ SPI_FIFO_MSB,
+ SPI_FIFO_LSB
+};
+
+/**
+ * SPI mode of operation (Communication modes)
+ */
+enum spi_mode {
+ SPI_INTERRUPT_TRANSFER,
+ SPI_POLLING_TRANSFER,
+};
+
+/**
+ * CHIP select/deselect commands
+ */
+enum spi_chip_select {
+ SPI_CHIP_SELECT,
+ SPI_CHIP_DESELECT
+};
+
+/**
+ * Protocols supported across different SPI controllers
+ */
+enum spi_interface {
+ SPI_INTERFACE_MOTOROLA_SPI, /* Motorola Interface */
+ SPI_INTERFACE_TI_SYNC_SERIAL, /* Texas Instrument Synch Serial iface*/
+ SPI_INTERFACE_NATIONAL_MICROWIRE,/* National Semiconductor uwire iface*/
+ SPI_INTERFACE_UNIDIRECTIONAL /* Unidirectional interface */
+};
+
+/* Motorola SPI protocol specific definitions */
+enum spi_clk_phase {
+ SPI_CLK_ZERO_CYCLE_DELAY = 0x0, /* Receive data on rising edge. */
+ SPI_CLK_HALF_CYCLE_DELAY /* Receive data on falling edge. */
+};
+
+/* SPI Clock Polarity */
+enum spi_clk_pol {
+ SPI_CLK_POL_IDLE_LOW, /* Low inactive level */
+ SPI_CLK_POL_IDLE_HIGH /* High inactive level */
+};
+
+struct motorola_spi_proto_params {
+ enum spi_clk_phase clk_phase;
+ enum spi_clk_pol clk_pol;
+};
+
+/* MICROWIRE protocol*/
+
+/**
+ * Microwire Conrol Lengths Command size in microwire format
+ */
+enum microwire_ctrl_len {
+ MWLEN_BITS_4 = 0x03, MWLEN_BITS_5, MWLEN_BITS_6,
+ MWLEN_BITS_7, MWLEN_BITS_8, MWLEN_BITS_9,
+ MWLEN_BITS_10, MWLEN_BITS_11, MWLEN_BITS_12,
+ MWLEN_BITS_13, MWLEN_BITS_14, MWLEN_BITS_15,
+ MWLEN_BITS_16, MWLEN_BITS_17, MWLEN_BITS_18,
+ MWLEN_BITS_19, MWLEN_BITS_20, MWLEN_BITS_21,
+ MWLEN_BITS_22, MWLEN_BITS_23, MWLEN_BITS_24,
+ MWLEN_BITS_25, MWLEN_BITS_26, MWLEN_BITS_27,
+ MWLEN_BITS_28, MWLEN_BITS_29, MWLEN_BITS_30,
+ MWLEN_BITS_31, MWLEN_BITS_32
+};
+
+/**
+ * Microwire Wait State
+ */
+enum microwire_wait_state {
+ MWIRE_WAIT_ZERO,/* No wait state inserted after last command bit */
+ MWIRE_WAIT_ONE /* One wait state inserted after last command bit */
+};
+
+/**
+ * Microwire : whether Full/Half Duplex
+ */
+enum mw_duplex {
+ /* SSPTXD becomes bi-directional, SSPRXD not used */
+ MICROWIRE_CHANNEL_FULL_DUPLEX,
+ /* SSPTXD is an output, SSPRXD is an input. */
+ MICROWIRE_CHANNEL_HALF_DUPLEX
+};
+
+struct microwire_proto_params {
+ enum microwire_ctrl_len ctrl_len;
+ enum microwire_wait_state wait_state;
+ enum mw_duplex duplex;
+};
+
+struct msp_controller {
+ enum spi_loopback lbm;
+ enum spi_interface iface;
+ enum spi_hierarchy hierarchy;
+ enum spi_fifo_endian endian_rx;
+ enum spi_fifo_endian endian_tx;
+ enum spi_mode com_mode;
+ enum msp_data_size data_size;
+ struct msp_clock_params clk_freq;
+ int spi_burst_mode_enable;
+ union {
+ struct motorola_spi_proto_params moto;
+ struct microwire_proto_params micro;
+ } proto_params;
+
+ u32 freq;
+ void (*cs_control) (u32 control);
+};
+
+struct msp_regs{
+ u32 gcr;
+ u32 tcf;
+ u32 rcf;
+ u32 srg;
+ u32 dmacr;
+};
+
+/* CONTROLLER COMMANDS */
+enum cntlr_commands {
+ DISABLE_CONTROLLER = 0,
+ ENABLE_CONTROLLER ,
+ DISABLE_ALL_INTERRUPT ,
+ ENABLE_ALL_INTERRUPT ,
+ FLUSH_FIFO ,
+ RESTORE_STATE ,
+ LOAD_DEFAULT_CONFIG ,
+ CLEAR_ALL_INTERRUPT,
+};
+
+/**
+ * Private Driver Data structure used by spi controllers
+ */
+struct driver_data {
+ struct amba_device *adev;
+ struct spi_master *master;
+ struct spi_master_cntlr *master_info;
+ void __iomem *regs;
+ struct clk *clk;
+#ifdef CONFIG_SPI_WORKQUEUE
+ struct workqueue_struct *workqueue;
+#endif
+ struct work_struct spi_work;
+ spinlock_t lock;
+ struct list_head queue;
+
+ int busy;
+ int run;
+
+ struct tasklet_struct pump_transfers;
+ struct timer_list spi_notify_timer;
+ int spi_io_error;
+ struct spi_message *cur_msg;
+ struct spi_transfer *cur_transfer;
+ struct chip_data *cur_chip;
+ void *tx;
+ void *tx_end;
+ void *rx;
+ void *rx_end;
+ void (*write) (struct driver_data *drv_data);
+ void (*read) (struct driver_data *drv_data);
+ void (*delay) (struct driver_data *drv_data);
+};
+
+/**
+ * struct chip_data - To maintain runtime state of SPICntlr for each client chip
+ * @ctr_regs: void pointer which is assigned a struct having regs of the cntlr.
+ * @chip_id: Chip Id assigned to this client to identify it.
+ * @n_bytes: how many bytes(power of 2) reqd for a given data width of client
+ * @write: function to be used to write when doing xfer for this chip
+ * @null_write: function to be used for dummy write for receiving data.
+ * @read: function to be used to read when doing xfer for this chip
+ * @null_read: function to be used to for dummy read while writting data.
+ * @cs_control: chip select callback provided by chip
+ * @xfer_type: polling/interrupt
+ *
+ * Runtime state of the SPI controller, maintained per chip,
+ * This would be set according to the current message that would be served
+ */
+struct chip_data {
+ void *ctr_regs;
+ u32 chip_id;
+ u8 n_bytes;
+ void (*write) (struct driver_data *drv_data);
+ void (*null_write) (struct driver_data *drv_data);
+ void (*read) (struct driver_data *drv_data);
+ void (*null_read) (struct driver_data *drv_data);
+ void (*delay) (struct driver_data *drv_data);
+ void (*cs_control) (u32 command);
+ int xfer_type;
+};
+
+/**
+ * struct spi_master_cntlr - device.platform_data for SPI cntlr devices.
+ * @num_chipselect: chipselects are used to distinguish individual
+ * SPI slaves, and are numbered from zero to num_chipselects - 1.
+ * each slave has a chipselect signal, but it's common that not
+ * every chipselect is connected to a slave.
+ */
+struct spi_master_cntlr {
+ u8 num_chipselect;
+ u32 id;
+ u32 base_addr;
+ gpio_alt_function gpio_alt_func;
+ char *device_name;
+};
+#endif
diff --git a/include/linux/tee.h b/include/linux/tee.h
new file mode 100644
index 00000000000..0cdec2d254a
--- /dev/null
+++ b/include/linux/tee.h
@@ -0,0 +1,143 @@
+/*
+ * Trusted Execution Environment (TEE) interface for TrustZone enabled ARM CPUs.
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com>
+ * Author: Martin Hovang <martin.xm.hovang@stericsson.com
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef TEE_H
+#define TEE_H
+
+/* tee_cmd id values */
+#define TEED_OPEN_SESSION 0x00000000U
+#define TEED_CLOSE_SESSION 0x00000001U
+#define TEED_INVOKE 0x00000002U
+
+/* tee_retval id values */
+#define TEED_SUCCESS 0x00000000U
+#define TEED_ERROR_GENERIC 0xFFFF0000U
+#define TEED_ERROR_ACCESS_DENIED 0xFFFF0001U
+#define TEED_ERROR_CANCEL 0xFFFF0002U
+#define TEED_ERROR_ACCESS_CONFLICT 0xFFFF0003U
+#define TEED_ERROR_EXCESS_DATA 0xFFFF0004U
+#define TEED_ERROR_BAD_FORMAT 0xFFFF0005U
+#define TEED_ERROR_BAD_PARAMETERS 0xFFFF0006U
+#define TEED_ERROR_BAD_STATE 0xFFFF0007U
+#define TEED_ERROR_ITEM_NOT_FOUND 0xFFFF0008U
+#define TEED_ERROR_NOT_IMPLEMENTED 0xFFFF0009U
+#define TEED_ERROR_NOT_SUPPORTED 0xFFFF000AU
+#define TEED_ERROR_NO_DATA 0xFFFF000BU
+#define TEED_ERROR_OUT_OF_MEMORY 0xFFFF000CU
+#define TEED_ERROR_BUSY 0xFFFF000DU
+#define TEED_ERROR_COMMUNICATION 0xFFFF000EU
+#define TEED_ERROR_SECURITY 0xFFFF000FU
+#define TEED_ERROR_SHORT_BUFFER 0xFFFF0010U
+
+/* TEE origin codes */
+#define TEED_ORIGIN_DRIVER 0x00000002U
+#define TEED_ORIGIN_TEE 0x00000003U
+#define TEED_ORIGIN_TEE_APPLICATION 0x00000004U
+
+#define TEE_UUID_CLOCK_SIZE 8
+
+#define TEEC_CONFIG_PAYLOAD_REF_COUNT 4
+
+/**
+ * struct tee_uuid - Structure that represent an uuid.
+ * @timeLow: The low field of the time stamp.
+ * @timeMid: The middle field of the time stamp.
+ * @timeHiAndVersion: The high field of the timestamp multiplexed
+ * with the version number.
+ * @clockSeqAndNode: The clock sequence and the node.
+ *
+ * This structure have different naming (camel case) to comply with Global
+ * Platforms TEE Client API spec. This type is defined in RFC4122.
+ */
+struct tee_uuid {
+ uint32_t timeLow;
+ uint16_t timeMid;
+ uint16_t timeHiAndVersion;
+ uint8_t clockSeqAndNode[TEE_UUID_CLOCK_SIZE];
+};
+
+/**
+ * struct tee_sharedmemory - Shared memory block for TEE.
+ * @buffer: The in/out data to TEE.
+ * @size: The size of the data.
+ * @flags: Variable telling whether it is a in, out or in/out parameter.
+ */
+struct tee_sharedmemory {
+ void *buffer;
+ size_t size;
+ uint32_t flags;
+};
+
+/**
+ * struct tee_operation - Payload for sessions or invoke operation.
+ * @shm: Array containing the shared memory buffers.
+ * @flags: Tells which if memory buffers that are in use.
+ */
+struct tee_operation {
+ struct tee_sharedmemory shm[TEEC_CONFIG_PAYLOAD_REF_COUNT];
+ uint32_t flags;
+};
+
+/**
+ * struct tee_session - The session of an open tee device.
+ * @state: The current state in the linux kernel.
+ * @err: Error code (as in Global Platform TEE Client API spec)
+ * @origin: Origin for the error code (also from spec).
+ * @id: Implementation defined type, 0 if not used.
+ * @ta: The trusted application.
+ * @uuid: The uuid for the trusted application.
+ * @cmd: The command to be executed in the trusted application.
+ * @driver_cmd: The command type in the driver. This is used from a client (user
+ * space to tell the Linux kernel whether it's a open-,
+ * close-session or if it is an invoke command.
+ * @ta_size: The size of the trusted application.
+ * @op: The payload for the trusted application.
+ * @sync: Mutex to handle multiple use of clients.
+ *
+ * This structure is mainly used in the Linux kernel as a session context for
+ * ongoing operations. Other than that it is also used in the communication with
+ * the user space.
+ */
+struct tee_session {
+ uint32_t state;
+ uint32_t err;
+ uint32_t origin;
+ uint32_t id;
+ void *ta;
+ struct tee_uuid *uuid;
+ unsigned int cmd;
+ unsigned int driver_cmd;
+ unsigned int ta_size;
+ struct tee_operation *op;
+ struct mutex *sync;
+};
+
+/**
+ * struct tee_read - Contains the error message and the origin.
+ * @err: Error code (as in Global Platform TEE Client API spec)
+ * @origin: Origin for the error code (also from spec).
+ *
+ * This is used by user space when a user space application wants to get more
+ * information about an error.
+ */
+struct tee_read {
+ unsigned int err; /* return value */
+ unsigned int origin; /* error origin */
+};
+
+/**
+ * Function that handles the function calls to trusted applications.
+ * @param ts: The session of a operation to be executed.
+ * @param sec_cmd: The type of command to be executed, open-, close-session,
+ * invoke command.
+ */
+int call_sec_world(struct tee_session *ts, int sec_cmd);
+
+#endif
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index da2ed77d3e8..b0f7e9f5717 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -808,4 +808,14 @@ enum usb_device_state {
*/
};
+/*-------------------------------------------------------------------------*/
+
+/*
+ * As per USB compliance update, a device that is actively drawing
+ * more than 100mA from USB must report itself as bus-powered in
+ * the GetStatus(DEVICE) call.
+ * http://compliance.usb.org/index.asp?UpdateFile=Electrical&Format=Standard#34
+ */
+#define USB_SELF_POWER_VBUS_MAX_DRAW 100
+
#endif /* __LINUX_USB_CH9_H */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 047f7e6edb8..de42f9bc6aa 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1259,6 +1259,32 @@ enum v4l2_mpeg_cx2341x_video_median_filter_type {
#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+10)
#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS (V4L2_CID_MPEG_CX2341X_BASE+11)
+/* Private Base control IDs specific to the CG2900 FM driver as defined by V4L2 */
+#define V4L2_CID_CG2900_RADIO_PRIVATE_BASE (V4L2_CID_PRIVATE_BASE | 0x1000)
+#define V4L2_CID_CG2900_RADIO_BANDSCAN (V4L2_CID_CG2900_RADIO_PRIVATE_BASE+1)
+enum v4l2_cg2900_radio_bandscan {
+ V4L2_CG2900_RADIO_BANDSCAN_START = 0,
+ V4L2_CG2900_RADIO_BANDSCAN_STOP = 1,
+};
+#define V4L2_CID_CG2900_RADIO_BANDSCAN_GET_RESULTS (V4L2_CID_CG2900_RADIO_PRIVATE_BASE+2)
+#define V4L2_CID_CG2900_RADIO_BLOCKSCAN_START (V4L2_CID_CG2900_RADIO_PRIVATE_BASE+3)
+#define V4L2_CID_CG2900_RADIO_BLOCKSCAN_GET_RESULTS (V4L2_CID_CG2900_RADIO_PRIVATE_BASE+4)
+#define V4L2_CID_CG2900_RADIO_CHIP_STATE (V4L2_CID_CG2900_RADIO_PRIVATE_BASE+5)
+enum v4l2_cg2900_radio_chip_state {
+ V4L2_CG2900_RADIO_STANDBY = 0,
+ V4L2_CG2900_RADIO_POWERUP = 1,
+};
+#define V4L2_CID_CG2900_RADIO_RSSI_THRESHOLD (V4L2_CID_CG2900_RADIO_PRIVATE_BASE+6)
+#define V4L2_CID_CG2900_RADIO_SELECT_ANTENNA (V4L2_CID_CG2900_RADIO_PRIVATE_BASE+7)
+enum v4l2_cg2900_radio_select_antenna {
+ V4L2_CG2900_RADIO_EMBEDDED_ANTENNA = 0,
+ V4L2_CG2900_RADIO_WIRED_ANTENNA = 1,
+};
+#define V4L2_CID_CG2900_RADIO_RDS_AF_UPDATE_START (V4L2_CID_CG2900_RADIO_PRIVATE_BASE+8)
+#define V4L2_CID_CG2900_RADIO_RDS_AF_UPDATE_GET_RESULT (V4L2_CID_CG2900_RADIO_PRIVATE_BASE+9)
+#define V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_START (V4L2_CID_CG2900_RADIO_PRIVATE_BASE+10)
+#define V4L2_CID_CG2900_RADIO_RDS_AF_SWITCH_GET_RESULT (V4L2_CID_CG2900_RADIO_PRIVATE_BASE+11)
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 2d3591f9c82..508d46912e4 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -99,6 +99,7 @@ enum {
#define HCISETLINKMODE _IOW('H', 226, int)
#define HCISETACLMTU _IOW('H', 227, int)
#define HCISETSCOMTU _IOW('H', 228, int)
+#define HCISETCONNINFO _IOW('H', 229, int)
#define HCIINQUIRY _IOR('H', 240, int)
@@ -227,6 +228,15 @@ enum {
#define HCI_AT_GENERAL_BONDING 0x04
#define HCI_AT_GENERAL_BONDING_MITM 0x05
+/* Link Key types */
+#define HCI_LK_COMBINATION 0x00
+#define HCI_LK_LOCAL_UNIT 0x01
+#define HCI_LK_REMOTE_UNIT 0x02
+#define HCI_LK_DEBUG_COMBINATION 0x03
+#define HCI_LK_UNAUTHENTICATED_COMBINATION 0x04
+#define HCI_LK_AUTHENTICATED_COMBINATION 0x05
+#define HCI_LK_CHANGEED_COMBINATION_KEY 0x06
+
/* ----- HCI Commands ---- */
#define HCI_OP_INQUIRY 0x0401
struct hci_cp_inquiry {
@@ -1028,9 +1038,16 @@ struct hci_conn_info_req {
struct hci_conn_info conn_info[0];
};
+struct hci_set_conn_info_req {
+ bdaddr_t bdaddr;
+ __u8 pin_len;
+ __u8 key_type;
+};
+
struct hci_auth_info_req {
bdaddr_t bdaddr;
__u8 type;
+ __u8 level;
};
struct hci_inquiry_req {
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index bf8b0d46b61..55d2790bdbf 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -177,6 +177,8 @@ struct hci_conn {
__u32 link_mode;
__u8 auth_type;
__u8 sec_level;
+ __u8 key_type;
+ __u8 pin_len;
__u8 power_save;
__u16 disc_timeout;
unsigned long pend;
@@ -427,6 +429,8 @@ int hci_get_dev_info(void __user *arg);
int hci_get_conn_list(void __user *arg);
int hci_get_conn_info(struct hci_dev *hdev, void __user *arg);
int hci_get_auth_info(struct hci_dev *hdev, void __user *arg);
+int hci_set_conn_info(struct hci_dev *hdev, void __user *arg);
+
int hci_inquiry(void __user *arg);
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h
index 318ab9478a4..6da573c75d5 100644
--- a/include/net/caif/caif_dev.h
+++ b/include/net/caif/caif_dev.h
@@ -50,6 +50,9 @@ struct caif_connect_request {
* @client_layer: User implementation of client layer. This layer
* MUST have receive and control callback functions
* implemented.
+ * @ifindex: Link layer interface index used for this connection.
+ * @headroom: Head room needed by CAIF protocol.
+ * @tailroom: Tail room needed by CAIF protocol.
*
* This function connects a CAIF channel. The Client must implement
* the struct cflayer. This layer represents the Client layer and holds
@@ -59,8 +62,9 @@ struct caif_connect_request {
* E.g. CAIF Socket will call this function for each socket it connects
* and have one client_layer instance for each socket.
*/
-int caif_connect_client(struct caif_connect_request *config,
- struct cflayer *client_layer);
+int caif_connect_client(struct caif_connect_request *conn_req,
+ struct cflayer *client_layer, int *ifindex,
+ int *headroom, int *tailroom);
/**
* caif_disconnect_client - Disconnects a client from the CAIF stack.
diff --git a/include/net/caif/caif_layer.h b/include/net/caif/caif_layer.h
index 25c472f0e5b..c8b07a904e7 100644
--- a/include/net/caif/caif_layer.h
+++ b/include/net/caif/caif_layer.h
@@ -15,14 +15,8 @@ struct cfpktq;
struct caif_payload_info;
struct caif_packet_funcs;
-#define CAIF_MAX_FRAMESIZE 4096
-#define CAIF_MAX_PAYLOAD_SIZE (4096 - 64)
-#define CAIF_NEEDED_HEADROOM (10)
-#define CAIF_NEEDED_TAILROOM (2)
#define CAIF_LAYER_NAME_SZ 16
-#define CAIF_SUCCESS 1
-#define CAIF_FAILURE 0
/**
* caif_assert() - Assert function for CAIF.
diff --git a/include/net/caif/caif_spi.h b/include/net/caif/caif_spi.h
new file mode 100644
index 00000000000..ce4570dff02
--- /dev/null
+++ b/include/net/caif/caif_spi.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_SPI_H_
+#define CAIF_SPI_H_
+
+#include <net/caif/caif_device.h>
+
+#define SPI_CMD_WR 0x00
+#define SPI_CMD_RD 0x01
+#define SPI_CMD_EOT 0x02
+#define SPI_CMD_IND 0x04
+
+#define SPI_DMA_BUF_LEN 8192
+
+#define WL_SZ 2 /* 16 bits. */
+#define SPI_CMD_SZ 4 /* 32 bits. */
+#define SPI_IND_SZ 4 /* 32 bits. */
+
+#define SPI_XFER 0
+#define SPI_SS_ON 1
+#define SPI_SS_OFF 2
+#define SPI_TERMINATE 3
+
+/* Minimum time between different levels is 50 microseconds. */
+#define MIN_TRANSITION_TIME_USEC 50
+
+/* Defines for calculating duration of SPI transfers for a particular
+ * number of bytes.
+ */
+#define SPI_MASTER_CLK_MHZ 13
+#define SPI_XFER_TIME_USEC(bytes, clk) (((bytes) * 8) / clk)
+
+/* Normally this should be aligned on the modem in order to benefit from full
+ * duplex transfers. However a size of 8188 provokes errors when running with
+ * the modem. These errors occur when packet sizes approaches 4 kB of data.
+ */
+#define CAIF_MAX_SPI_FRAME 4092
+
+/* Maximum number of uplink CAIF frames that can reside in the same SPI frame.
+ * This number should correspond with the modem setting. The application side
+ * CAIF accepts any number of embedded downlink CAIF frames.
+ */
+#define CAIF_MAX_SPI_PKTS 9
+
+/* Decides if SPI buffers should be prefilled with 0xFF pattern for easier
+ * debugging. Both TX and RX buffers will be filled before the transfer.
+ */
+#define CFSPI_DBG_PREFILL 0
+
+/* Structure describing a SPI transfer. */
+struct cfspi_xfer {
+ u16 tx_dma_len;
+ u16 rx_dma_len;
+ void *va_tx;
+ dma_addr_t pa_tx;
+ void *va_rx;
+ dma_addr_t pa_rx;
+};
+
+/* Structure implemented by the SPI interface. */
+struct cfspi_ifc {
+ void (*ss_cb) (bool assert, struct cfspi_ifc *ifc);
+ void (*xfer_done_cb) (struct cfspi_ifc *ifc);
+ void *priv;
+};
+
+/* Structure implemented by SPI clients. */
+struct cfspi_dev {
+ int (*init_xfer) (struct cfspi_xfer *xfer, struct cfspi_dev *dev);
+ void (*sig_xfer) (bool xfer, struct cfspi_dev *dev);
+ struct cfspi_ifc *ifc;
+ char *name;
+ u32 clk_mhz;
+ void *priv;
+};
+
+/* Enumeration describing the CAIF SPI state. */
+enum cfspi_state {
+ CFSPI_STATE_WAITING = 0,
+ CFSPI_STATE_AWAKE,
+ CFSPI_STATE_FETCH_PKT,
+ CFSPI_STATE_GET_NEXT,
+ CFSPI_STATE_INIT_XFER,
+ CFSPI_STATE_WAIT_ACTIVE,
+ CFSPI_STATE_SIG_ACTIVE,
+ CFSPI_STATE_WAIT_XFER_DONE,
+ CFSPI_STATE_XFER_DONE,
+ CFSPI_STATE_WAIT_INACTIVE,
+ CFSPI_STATE_SIG_INACTIVE,
+ CFSPI_STATE_DELIVER_PKT,
+ CFSPI_STATE_MAX,
+};
+
+/* Structure implemented by SPI physical interfaces. */
+struct cfspi {
+ struct caif_dev_common cfdev;
+ struct net_device *ndev;
+ struct platform_device *pdev;
+ struct sk_buff_head qhead;
+ struct sk_buff_head chead;
+ u16 cmd;
+ u16 tx_cpck_len;
+ u16 tx_npck_len;
+ u16 rx_cpck_len;
+ u16 rx_npck_len;
+ struct cfspi_ifc ifc;
+ struct cfspi_xfer xfer;
+ struct cfspi_dev *dev;
+ unsigned long state;
+ struct work_struct work;
+ struct workqueue_struct *wq;
+ struct list_head list;
+ int flow_off_sent;
+ u32 qd_low_mark;
+ u32 qd_high_mark;
+ struct completion comp;
+ wait_queue_head_t wait;
+ spinlock_t lock;
+ bool flow_stop;
+#ifdef CONFIG_DEBUG_FS
+ enum cfspi_state dbg_state;
+ u16 pcmd;
+ u16 tx_ppck_len;
+ u16 rx_ppck_len;
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_state;
+ struct dentry *dbgfs_frame;
+#endif /* CONFIG_DEBUG_FS */
+};
+
+extern int spi_frm_align;
+extern int spi_up_head_align;
+extern int spi_up_tail_align;
+extern int spi_down_head_align;
+extern int spi_down_tail_align;
+extern struct platform_driver cfspi_spi_driver;
+
+void cfspi_dbg_state(struct cfspi *cfspi, int state);
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_xmitlen(struct cfspi *cfspi);
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_spi_remove(struct platform_device *pdev);
+int cfspi_spi_probe(struct platform_device *pdev);
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_xmitlen(struct cfspi *cfspi);
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+void cfspi_xfer(struct work_struct *work);
+
+#endif /* CAIF_SPI_H_ */
diff --git a/include/net/caif/cfcnfg.h b/include/net/caif/cfcnfg.h
index 9fc2fc20b88..bd646faffa4 100644
--- a/include/net/caif/cfcnfg.h
+++ b/include/net/caif/cfcnfg.h
@@ -7,6 +7,7 @@
#ifndef CFCNFG_H_
#define CFCNFG_H_
#include <linux/spinlock.h>
+#include <linux/netdevice.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfctrl.h>
@@ -73,8 +74,8 @@ void cfcnfg_remove(struct cfcnfg *cfg);
void
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
- void *dev, struct cflayer *phy_layer, u16 *phyid,
- enum cfcnfg_phy_preference pref,
+ struct net_device *dev, struct cflayer *phy_layer,
+ u16 *phyid, enum cfcnfg_phy_preference pref,
bool fcs, bool stx);
/**
@@ -114,11 +115,18 @@ void cfcnfg_release_adap_layer(struct cflayer *adap_layer);
* @param: Link setup parameters.
* @adap_layer: Specify the adaptation layer; the receive and
* flow-control functions MUST be set in the structure.
- *
+ * @ifindex: Link layer interface index used for this connection.
+ * @proto_head: Protocol head-space needed by CAIF protocol,
+ * excluding link layer.
+ * @proto_tail: Protocol tail-space needed by CAIF protocol,
+ * excluding link layer.
*/
int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
struct cfctrl_link_param *param,
- struct cflayer *adap_layer);
+ struct cflayer *adap_layer,
+ int *ifindex,
+ int *proto_head,
+ int *proto_tail);
/**
* cfcnfg_get_phyid() - Get physical ID, given type.
diff --git a/include/net/caif/cfsrvl.h b/include/net/caif/cfsrvl.h
index 2dc9eb193ec..b1fa87ee099 100644
--- a/include/net/caif/cfsrvl.h
+++ b/include/net/caif/cfsrvl.h
@@ -16,6 +16,8 @@ struct cfsrvl {
bool open;
bool phy_flow_on;
bool modem_flow_on;
+ bool supports_flowctrl;
+ void (*release)(struct kref *);
struct dev_info dev_info;
struct kref ref;
};
@@ -25,13 +27,15 @@ struct cflayer *cfvei_create(u8 linkid, struct dev_info *dev_info);
struct cflayer *cfdgml_create(u8 linkid, struct dev_info *dev_info);
struct cflayer *cfutill_create(u8 linkid, struct dev_info *dev_info);
struct cflayer *cfvidl_create(u8 linkid, struct dev_info *dev_info);
-struct cflayer *cfrfml_create(u8 linkid, struct dev_info *dev_info);
+struct cflayer *cfrfml_create(u8 linkid, struct dev_info *dev_info,
+ int mtu_size);
struct cflayer *cfdbgl_create(u8 linkid, struct dev_info *dev_info);
bool cfsrvl_phyid_match(struct cflayer *layer, int phyid);
void cfservl_destroy(struct cflayer *layer);
void cfsrvl_init(struct cfsrvl *service,
- u8 channel_id,
- struct dev_info *dev_info);
+ u8 channel_id,
+ struct dev_info *dev_info,
+ bool supports_flowctrl);
bool cfsrvl_ready(struct cfsrvl *service, int *err);
u8 cfsrvl_getphyid(struct cflayer *layer);
@@ -50,7 +54,10 @@ static inline void cfsrvl_put(struct cflayer *layr)
if (layr == NULL)
return;
s = container_of(layr, struct cfsrvl, layer);
- kref_put(&s->ref, cfsrvl_release);
+
+ WARN_ON(!s->release);
+ if (s->release)
+ kref_put(&s->ref, s->release);
}
#endif /* CFSRVL_H_ */
diff --git a/include/net/phonet/pep.h b/include/net/phonet/pep.h
index 35672b1cf44..28957f486c1 100644
--- a/include/net/phonet/pep.h
+++ b/include/net/phonet/pep.h
@@ -45,6 +45,10 @@ struct pep_sock {
u8 tx_fc; /* TX flow control */
u8 init_enable; /* auto-enable at creation */
u8 aligned;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ u16 remote_pep;
+ u8 pipe_state;
+#endif
};
static inline struct pep_sock *pep_sk(struct sock *sk)
@@ -160,4 +164,21 @@ enum {
PEP_IND_READY,
};
+#ifdef CONFIG_PHONET_PIPECTRLR
+#define PNS_PEP_CONNECT_UTID 0x02
+#define PNS_PIPE_CREATED_IND_UTID 0x04
+#define PNS_PIPE_ENABLE_UTID 0x0A
+#define PNS_PIPE_ENABLED_IND_UTID 0x0C
+#define PNS_PIPE_DISABLE_UTID 0x0F
+#define PNS_PIPE_DISABLED_IND_UTID 0x11
+#define PNS_PEP_DISCONNECT_UTID 0x06
+
+/* Used for tracking state of a pipe */
+enum {
+ PIPE_IDLE,
+ PIPE_DISABLED,
+ PIPE_ENABLED,
+};
+#endif /* CONFIG_PHONET_PIPECTRLR */
+
#endif
diff --git a/include/video/av8100.h b/include/video/av8100.h
new file mode 100644
index 00000000000..32ed4eef4bb
--- /dev/null
+++ b/include/video/av8100.h
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * AV8100 driver
+ *
+ * Author: Per Persson <per.xb.persson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __AV8100__H__
+#define __AV8100__H__
+
+/* Temp: TODO: remove (or move to menuconfig) */
+/*#define CONFIG_AV8100_SDTV*/
+
+#define AV8100_CEC_MESSAGE_SIZE 16
+#define AV8100_HDCP_SEND_KEY_SIZE 16
+#define AV8100_INFOFRAME_SIZE 28
+#define AV8100_FUSE_KEY_SIZE 16
+#define AV8100_CHIPVER_1 1
+#define AV8100_CHIPVER_2 2
+
+struct av8100_platform_data {
+ unsigned gpio_base;
+ int irq;
+};
+
+enum av8100_error {
+ AV8100_OK = 0x0,
+ AV8100_INVALID_COMMAND = 0x1,
+ AV8100_INVALID_INTERFACE = 0x2,
+ AV8100_INVALID_IOCTL = 0x3,
+ AV8100_COMMAND_FAIL = 0x4,
+ AV8100_FWDOWNLOAD_FAIL = 0x5,
+ AV8100_FAIL = 0xFF,
+};
+
+enum av8100_command_type {
+ AV8100_COMMAND_VIDEO_INPUT_FORMAT = 0x1,
+ AV8100_COMMAND_AUDIO_INPUT_FORMAT,
+ AV8100_COMMAND_VIDEO_OUTPUT_FORMAT,
+ AV8100_COMMAND_VIDEO_SCALING_FORMAT,
+ AV8100_COMMAND_COLORSPACECONVERSION,
+ AV8100_COMMAND_CEC_MESSAGE_WRITE,
+ AV8100_COMMAND_CEC_MESSAGE_READ_BACK,
+ AV8100_COMMAND_DENC,
+ AV8100_COMMAND_HDMI,
+ AV8100_COMMAND_HDCP_SENDKEY,
+ AV8100_COMMAND_HDCP_MANAGEMENT,
+ AV8100_COMMAND_INFOFRAMES,
+ AV8100_COMMAND_EDID_SECTION_READBACK,
+ AV8100_COMMAND_PATTERNGENERATOR,
+ AV8100_COMMAND_FUSE_AES_KEY,
+};
+
+enum interface_type {
+ I2C_INTERFACE = 0x0,
+ DSI_INTERFACE = 0x1,
+};
+
+enum av8100_dsi_mode {
+ AV8100_HDMI_DSI_OFF,
+ AV8100_HDMI_DSI_COMMAND_MODE,
+ AV8100_HDMI_DSI_VIDEO_MODE
+};
+
+enum av8100_pixel_format {
+ AV8100_INPUT_PIX_RGB565,
+ AV8100_INPUT_PIX_RGB666,
+ AV8100_INPUT_PIX_RGB666P,
+ AV8100_INPUT_PIX_RGB888,
+ AV8100_INPUT_PIX_YCBCR422
+};
+
+enum av8100_video_mode {
+ AV8100_VIDEO_INTERLACE,
+ AV8100_VIDEO_PROGRESSIVE
+};
+
+enum av8100_dsi_nb_data_lane {
+ AV8100_DATA_LANES_USED_0,
+ AV8100_DATA_LANES_USED_1,
+ AV8100_DATA_LANES_USED_2,
+ AV8100_DATA_LANES_USED_3,
+ AV8100_DATA_LANES_USED_4
+};
+
+enum av8100_te_config {
+ AV8100_TE_OFF, /* NO TE*/
+ AV8100_TE_DSI_LANE, /* TE generated on DSI lane */
+ AV8100_TE_IT_LINE, /* TE generated on IT line (GPIO) */
+ AV8100_TE_DSI_IT, /* TE generatedon both DSI lane & IT line*/
+ AV8100_TE_GPIO_IT /* TE on GPIO I2S DAT3 & or IT line*/
+};
+
+enum av8100_audio_if_format {
+ AV8100_AUDIO_I2S_MODE,
+ AV8100_AUDIO_I2SDELAYED_MODE, /* I2S Mode by default*/
+ AV8100_AUDIO_TDM_MODE /* 8 Channels by default*/
+};
+
+enum av8100_sample_freq {
+ AV8100_AUDIO_FREQ_32KHZ,
+ AV8100_AUDIO_FREQ_44_1KHZ,
+ AV8100_AUDIO_FREQ_48KHZ,
+ AV8100_AUDIO_FREQ_64KHZ,
+ AV8100_AUDIO_FREQ_88_2KHZ,
+ AV8100_AUDIO_FREQ_96KHZ,
+ AV8100_AUDIO_FREQ_128KHZ,
+ AV8100_AUDIO_FREQ_176_1KHZ,
+ AV8100_AUDIO_FREQ_192KHZ
+};
+
+enum av8100_audio_word_length {
+ AV8100_AUDIO_16BITS,
+ AV8100_AUDIO_20BITS,
+ AV8100_AUDIO_24BITS
+};
+
+enum av8100_audio_format {
+ AV8100_AUDIO_LPCM_MODE,
+ AV8100_AUDIO_COMPRESS_MODE
+};
+
+enum av8100_audio_if_mode {
+ AV8100_AUDIO_SLAVE,
+ AV8100_AUDIO_MASTER
+};
+
+enum av8100_audio_mute {
+ AV8100_AUDIO_MUTE_DISABLE,
+ AV8100_AUDIO_MUTE_ENABLE
+};
+
+enum av8100_output_CEA_VESA {
+ AV8100_CUSTOM,
+ AV8100_CEA1_640X480P_59_94HZ,
+ AV8100_CEA2_3_720X480P_59_94HZ,
+ AV8100_CEA4_1280X720P_60HZ,
+ AV8100_CEA5_1920X1080I_60HZ,
+ AV8100_CEA6_7_NTSC_60HZ,
+ AV8100_CEA14_15_480p_60HZ,
+ AV8100_CEA16_1920X1080P_60HZ,
+ AV8100_CEA17_18_720X576P_50HZ,
+ AV8100_CEA19_1280X720P_50HZ,
+ AV8100_CEA20_1920X1080I_50HZ,
+ AV8100_CEA21_22_576I_PAL_50HZ,
+ AV8100_CEA29_30_576P_50HZ,
+ AV8100_CEA31_1920x1080P_50Hz,
+ AV8100_CEA32_1920X1080P_24HZ,
+ AV8100_CEA33_1920X1080P_25HZ,
+ AV8100_CEA34_1920X1080P_30HZ,
+ AV8100_CEA60_1280X720P_24HZ,
+ AV8100_CEA61_1280X720P_25HZ,
+ AV8100_CEA62_1280X720P_30HZ,
+ AV8100_VESA9_800X600P_60_32HZ,
+ AV8100_VESA14_848X480P_60HZ,
+ AV8100_VESA16_1024X768P_60HZ,
+ AV8100_VESA22_1280X768P_59_99HZ,
+ AV8100_VESA23_1280X768P_59_87HZ,
+ AV8100_VESA27_1280X800P_59_91HZ,
+ AV8100_VESA28_1280X800P_59_81HZ,
+ AV8100_VESA39_1360X768P_60_02HZ,
+ AV8100_VESA81_1366X768P_59_79HZ,
+ AV8100_VIDEO_OUTPUT_CEA_VESA_MAX
+};
+
+enum av8100_video_sync_pol {
+ AV8100_SYNC_POSITIVE,
+ AV8100_SYNC_NEGATIVE
+};
+
+enum av8100_hdmi_mode {
+ AV8100_HDMI_OFF,
+ AV8100_HDMI_ON,
+ AV8100_HDMI_AVMUTE
+};
+
+enum av8100_hdmi_format {
+ AV8100_HDMI,
+ AV8100_DVI
+};
+
+enum av8100_DVI_format {
+ AV8100_DVI_CTRL_CTL0,
+ AV8100_DVI_CTRL_CTL1,
+ AV8100_DVI_CTRL_CTL2
+};
+
+enum av8100_pattern_type {
+ AV8100_PATTERN_OFF,
+ AV8100_PATTERN_GENERATOR,
+ AV8100_PRODUCTION_TESTING
+};
+
+enum av8100_pattern_format {
+ AV8100_NO_PATTERN,
+ AV8100_PATTERN_VGA,
+ AV8100_PATTERN_720P,
+ AV8100_PATTERN_1080P
+};
+
+enum av8100_pattern_audio {
+ AV8100_PATTERN_AUDIO_OFF,
+ AV8100_PATTERN_AUDIO_ON,
+ AV8100_PATTERN_AUDIO_I2S_MEM
+};
+
+struct av8100_video_input_format_cmd {
+ enum av8100_dsi_mode dsi_input_mode;
+ enum av8100_pixel_format input_pixel_format;
+ unsigned short total_horizontal_pixel;
+ unsigned short total_horizontal_active_pixel;
+ unsigned short total_vertical_lines;
+ unsigned short total_vertical_active_lines;
+ enum av8100_video_mode video_mode;
+ enum av8100_dsi_nb_data_lane nb_data_lane;
+ unsigned char nb_virtual_ch_command_mode;
+ unsigned char nb_virtual_ch_video_mode;
+ unsigned short TE_line_nb;
+ enum av8100_te_config TE_config;
+ unsigned long master_clock_freq;
+ unsigned char ui_x4;
+};
+
+struct av8100_audio_input_format_cmd {
+ enum av8100_audio_if_format audio_input_if_format;
+ unsigned char i2s_input_nb;
+ enum av8100_sample_freq sample_audio_freq;
+ enum av8100_audio_word_length audio_word_lg;
+ enum av8100_audio_format audio_format;
+ enum av8100_audio_if_mode audio_if_mode;
+ enum av8100_audio_mute audio_mute;
+};
+
+struct av8100_video_output_format_cmd {
+ enum av8100_output_CEA_VESA video_output_cea_vesa;
+ enum av8100_video_sync_pol vsync_polarity;
+ enum av8100_video_sync_pol hsync_polarity;
+ unsigned short total_horizontal_pixel;
+ unsigned short total_horizontal_active_pixel;
+ unsigned short total_vertical_in_half_lines;
+ unsigned short total_vertical_active_in_half_lines;
+ unsigned short hsync_start_in_pixel;
+ unsigned short hsync_length_in_pixel;
+ unsigned short vsync_start_in_half_line;
+ unsigned short vsync_length_in_half_line;
+ unsigned short hor_video_start_pixel;
+ unsigned short vert_video_start_pixel;
+ enum av8100_video_mode video_type;
+ unsigned short pixel_repeat;
+ unsigned long pixel_clock_freq_Hz;
+};
+
+struct av8100_video_scaling_format_cmd {
+ unsigned short h_start_in_pixel;
+ unsigned short h_stop_in_pixel;
+ unsigned short v_start_in_line;
+ unsigned short v_stop_in_line;
+ unsigned short h_start_out_pixel;
+ unsigned short h_stop_out_pixel;
+ unsigned short v_start_out_line;
+ unsigned short v_stop_out_line;
+};
+
+struct av8100_color_space_conversion_format_cmd {
+ unsigned short c0;
+ unsigned short c1;
+ unsigned short c2;
+ unsigned short c3;
+ unsigned short c4;
+ unsigned short c5;
+ unsigned short c6;
+ unsigned short c7;
+ unsigned short c8;
+ unsigned short aoffset;
+ unsigned short boffset;
+ unsigned short coffset;
+ unsigned char lmax;
+ unsigned char lmin;
+ unsigned char cmax;
+ unsigned char cmin;
+};
+
+const extern struct av8100_color_space_conversion_format_cmd col_cvt_identity;
+const extern struct av8100_color_space_conversion_format_cmd
+ col_cvt_identity_clamp_yuv;
+const extern struct av8100_color_space_conversion_format_cmd
+ col_cvt_yuv422_to_rgb;
+const extern struct av8100_color_space_conversion_format_cmd
+ col_cvt_yuv422_to_denc;
+const extern struct av8100_color_space_conversion_format_cmd
+ col_cvt_rgb_to_denc;
+
+struct av8100_cec_message_write_format_cmd {
+ unsigned char buffer_length;
+ unsigned char buffer[AV8100_CEC_MESSAGE_SIZE];
+};
+
+struct av8100_cec_message_read_back_format_cmd {
+};
+
+enum av8100_cvbs_video_format {
+ AV8100_CVBS_625,
+ AV8100_CVBS_525,
+};
+
+enum av8100_standard_selection {
+ AV8100_PAL_BDGHI,
+ AV8100_PAL_N,
+ AV8100_NTSC_M,
+ AV8100_PAL_M
+};
+
+struct av8100_denc_format_cmd {
+ enum av8100_cvbs_video_format cvbs_video_format;
+ enum av8100_standard_selection standard_selection;
+ unsigned char enable;
+ unsigned char macrovision_enable;
+ unsigned char internal_generator;
+};
+
+struct av8100_hdmi_cmd {
+ enum av8100_hdmi_mode hdmi_mode;
+ enum av8100_hdmi_format hdmi_format;
+ enum av8100_DVI_format dvi_format; /* used only if HDMI_format = DVI*/
+};
+
+struct av8100_hdcp_send_key_format_cmd {
+ unsigned char key_number;
+ unsigned char data_len;
+ unsigned char data[AV8100_HDCP_SEND_KEY_SIZE];
+};
+
+enum av8100_hdcp_auth_req_type {
+ AV8100_HDCP_AUTH_REQ_OFF = 0,
+ AV8100_HDCP_AUTH_REQ_ON = 1,
+ AV8100_HDCP_REV_LIST_REQ = 2,
+ AV8100_HDCP_AUTH_CONT = 3,
+};
+
+enum av8100_hdcp_encr_req_type {
+ AV8100_HDCP_ENCR_REQ_OFF = 0,
+ AV8100_HDCP_ENCR_REQ_ON = 1,
+};
+
+enum av8100_hdcp_encr_use {
+ AV8100_HDCP_ENCR_USE_OESS = 0,
+ AV8100_HDCP_ENCR_USE_EESS = 1,
+};
+
+struct av8100_hdcp_management_format_cmd {
+ unsigned char req_type;
+ unsigned char req_encr;
+ unsigned char encr_use;
+};
+
+struct av8100_infoframes_format_cmd {
+ unsigned char type;
+ unsigned char version;
+ unsigned char length;
+ unsigned char crc;
+ unsigned char data[AV8100_INFOFRAME_SIZE];
+};
+
+struct av8100_edid_section_readback_format_cmd {
+ unsigned char address;
+ unsigned char block_number;
+};
+
+struct av8100_pattern_generator_format_cmd {
+ enum av8100_pattern_type pattern_type;
+ enum av8100_pattern_format pattern_video_format;
+ enum av8100_pattern_audio pattern_audio_mode;
+};
+
+enum av8100_fuse_operation {
+ AV8100_FUSE_READ = 0,
+ AV8100_FUSE_WRITE = 1,
+};
+
+struct av8100_fuse_aes_key_format_cmd {
+ unsigned char fuse_operation;
+ unsigned char key[AV8100_FUSE_KEY_SIZE];
+};
+
+union av8100_configuration {
+ struct av8100_video_input_format_cmd video_input_format;
+ struct av8100_audio_input_format_cmd audio_input_format;
+ struct av8100_video_output_format_cmd video_output_format;
+ struct av8100_video_scaling_format_cmd video_scaling_format;
+ struct av8100_color_space_conversion_format_cmd
+ color_space_conversion_format;
+ struct av8100_cec_message_write_format_cmd
+ cec_message_write_format;
+ struct av8100_cec_message_read_back_format_cmd
+ cec_message_read_back_format;
+ struct av8100_denc_format_cmd denc_format;
+ struct av8100_hdmi_cmd hdmi_format;
+ struct av8100_hdcp_send_key_format_cmd hdcp_send_key_format;
+ struct av8100_hdcp_management_format_cmd hdcp_management_format;
+ struct av8100_infoframes_format_cmd infoframes_format;
+ struct av8100_edid_section_readback_format_cmd
+ edid_section_readback_format;
+ struct av8100_pattern_generator_format_cmd pattern_generator_format;
+ struct av8100_fuse_aes_key_format_cmd fuse_aes_key_format;
+};
+
+enum av8100_operating_mode {
+ AV8100_OPMODE_UNDEFINED = 0,
+ AV8100_OPMODE_SHUTDOWN,
+ AV8100_OPMODE_STANDBY,
+ AV8100_OPMODE_SCAN,
+ AV8100_OPMODE_INIT,
+ AV8100_OPMODE_IDLE,
+ AV8100_OPMODE_VIDEO,
+};
+
+enum av8100_plugin_status {
+ AV8100_PLUGIN_NONE = 0x0,
+ AV8100_HDMI_PLUGIN = 0x1,
+ AV8100_CVBS_PLUGIN = 0x2,
+};
+
+enum av8100_hdmi_event {
+ AV8100_HDMI_EVENT_NONE = 0x0,
+ AV8100_HDMI_EVENT_HDMI_PLUGIN = 0x1,
+ AV8100_HDMI_EVENT_HDMI_PLUGOUT = 0x2,
+ AV8100_HDMI_EVENT_CEC = 0x4,
+ AV8100_HDMI_EVENT_HDCP = 0x8,
+};
+
+struct av8100_status {
+ enum av8100_operating_mode av8100_state;
+ enum av8100_plugin_status av8100_plugin_status;
+ int hdmi_on;
+};
+
+
+int av8100_init(void);
+void av8100_exit(void);
+int av8100_powerup(void);
+int av8100_powerdown(void);
+int av8100_disable_interrupt(void);
+int av8100_enable_interrupt(void);
+int av8100_download_firmware(char *fw_buff, int numOfBytes,
+ enum interface_type if_type);
+int av8100_reg_stby_w(
+ unsigned char cpd,
+ unsigned char stby,
+ unsigned char mclkrng);
+int av8100_reg_hdmi_5_volt_time_w(
+ unsigned char denc_off_time,
+ unsigned char hdmi_off_time,
+ unsigned char on_time);
+int av8100_reg_stby_int_mask_w(
+ unsigned char hpdm,
+ unsigned char cpdm,
+ unsigned char stbygpiocfg,
+ unsigned char ipol);
+int av8100_reg_stby_pend_int_w(
+ unsigned char hpdi,
+ unsigned char cpdi,
+ unsigned char oni);
+int av8100_reg_gen_int_mask_w(
+ unsigned char eocm,
+ unsigned char vsim,
+ unsigned char vsom,
+ unsigned char cecm,
+ unsigned char hdcpm,
+ unsigned char uovbm,
+ unsigned char tem);
+int av8100_reg_gen_int_w(
+ unsigned char eoci,
+ unsigned char vsii,
+ unsigned char vsoi,
+ unsigned char ceci,
+ unsigned char hdcpi,
+ unsigned char uovbi);
+int av8100_reg_gpio_conf_w(
+ unsigned char dat3dir,
+ unsigned char dat3val,
+ unsigned char dat2dir,
+ unsigned char dat2val,
+ unsigned char dat1dir,
+ unsigned char dat1val,
+ unsigned char ucdbg);
+int av8100_reg_gen_ctrl_w(
+ unsigned char fdl,
+ unsigned char hld,
+ unsigned char wa,
+ unsigned char ra);
+int av8100_reg_fw_dl_entry_w(
+ unsigned char mbyte_code_entry);
+int av8100_reg_w(
+ unsigned char offset,
+ unsigned char value);
+int av8100_reg_stby_r(
+ unsigned char *cpd,
+ unsigned char *stby,
+ unsigned char *hpds,
+ unsigned char *cpds,
+ unsigned char *mclkrng);
+int av8100_reg_hdmi_5_volt_time_r(
+ unsigned char *denc_off_time,
+ unsigned char *hdmi_off_time,
+ unsigned char *on_time);
+int av8100_reg_stby_int_mask_r(
+ unsigned char *hpdm,
+ unsigned char *cpdm,
+ unsigned char *stbygpiocfg,
+ unsigned char *ipol);
+int av8100_reg_stby_pend_int_r(
+ unsigned char *hpdi,
+ unsigned char *cpdi,
+ unsigned char *oni,
+ unsigned char *sid);
+int av8100_reg_gen_int_mask_r(
+ unsigned char *eocm,
+ unsigned char *vsim,
+ unsigned char *vsom,
+ unsigned char *cecm,
+ unsigned char *hdcpm,
+ unsigned char *uovbm,
+ unsigned char *tem);
+int av8100_reg_gen_int_r(
+ unsigned char *eoci,
+ unsigned char *vsii,
+ unsigned char *vsoi,
+ unsigned char *ceci,
+ unsigned char *hdcpi,
+ unsigned char *uovbi,
+ unsigned char *tei);
+int av8100_reg_gen_status_r(
+ unsigned char *cecrec,
+ unsigned char *cectrx,
+ unsigned char *uc,
+ unsigned char *onuvb,
+ unsigned char *hdcps);
+int av8100_reg_gpio_conf_r(
+ unsigned char *dat3dir,
+ unsigned char *dat3val,
+ unsigned char *dat2dir,
+ unsigned char *dat2val,
+ unsigned char *dat1dir,
+ unsigned char *dat1val,
+ unsigned char *ucdbg);
+int av8100_reg_gen_ctrl_r(
+ unsigned char *fdl,
+ unsigned char *hld,
+ unsigned char *wa,
+ unsigned char *ra);
+int av8100_reg_fw_dl_entry_r(
+ unsigned char *mbyte_code_entry);
+int av8100_reg_r(
+ unsigned char offset,
+ unsigned char *value);
+int av8100_conf_get(enum av8100_command_type command_type,
+ union av8100_configuration *config);
+int av8100_conf_prep(enum av8100_command_type command_type,
+ union av8100_configuration *config);
+int av8100_conf_w(enum av8100_command_type command_type,
+ unsigned char *return_buffer_length,
+ unsigned char *return_buffer, enum interface_type if_type);
+int av8100_conf_w_raw(enum av8100_command_type command_type,
+ unsigned char buffer_length,
+ unsigned char *buffer,
+ unsigned char *return_buffer_length,
+ unsigned char *return_buffer);
+struct av8100_status av8100_status_get(void);
+enum av8100_output_CEA_VESA av8100_video_output_format_get(int xres,
+ int yres,
+ int htot,
+ int vtot,
+ int pixelclk,
+ bool interlaced);
+void av8100_hdmi_event_cb_set(void (*event_callback)(enum av8100_hdmi_event));
+u8 av8100_ver_get(void);
+
+#endif /* __AV8100__H__ */
diff --git a/include/video/b2r2_blt.h b/include/video/b2r2_blt.h
new file mode 100644
index 00000000000..a7f52fcda27
--- /dev/null
+++ b/include/video/b2r2_blt.h
@@ -0,0 +1,580 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson B2R2 user interface
+ *
+ * Author: Robert Fekete <robert.fekete@stericsson.com>
+ * Author: Paul Wannback
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+
+#ifndef _LINUX_VIDEO_B2R2_BLT_H
+#define _LINUX_VIDEO_B2R2_BLT_H
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+/**
+ * struct b2r2_blt_rect - Specifies a B2R2 rectangle
+ *
+ * @left: X-coordinate of top left corner
+ * @top: Y-coordinate of top left corner
+ * @width: Rectangle width. Must be >= 0.
+ * @height: Rectangle height. Must be >= 0.
+ */
+struct b2r2_blt_rect {
+ __s32 x;
+ __s32 y;
+ __s32 width;
+ __s32 height;
+};
+
+/**
+ * enum b2r2_blt_fmt - Defines the available B2R2 buffer formats
+ *
+ * Inspired by Khronos OpenMAX, please see
+ * OpenMAX IL specification for detailed descriptions of the formats
+ *
+ * @B2R2_BLT_FMT_UNUSED: Placeholder value when format is unknown,
+ * or specified using a vendor-specific means.
+ * @B2R2_BLT_FMT_16_BIT_ARGB4444: 16 bits per pixel ARGB format with colors
+ * stored as Alpha 15:12, Red 11:8, Green 7:4, and Blue 3:0.
+ * @B2R2_BLT_FMT_16_BIT_ARGB1555: 16 bits per pixel ARGB format with colors
+ * stored as Alpha 15, Red 14:10, Green 9:5, and Blue 4:0.
+ * @B2R2_BLT_FMT_16_BIT_RGB565: 16 bits per pixel RGB format with colors
+ * stored as Red 15:11, Green 10:5, and Blue 4:0.
+ * @B2R2_BLT_FMT_24_BIT_RGB888: 24 bits per pixel RGB format with colors
+ * stored as Red 23:16, Green 15:8, and Blue 7:0.
+ * @B2R2_BLT_FMT_32_BIT_ARGB8888: 32 bits per pixel ARGB format with colors
+ * stored as Alpha 31:24, Red 23:16, Green 15:8, and Blue 7:0.
+ * @B2R2_BLT_FMT_YUV420_PACKED_PLANAR: YUV planar format, organized with
+ * three separate planes for each color component, namely Y, U, and V.
+ * U and V pixels are sub-sampled by a factor of two both horizontally and
+ * vertically. The buffer shall contain a plane of Y, U, and V data in this
+ * order
+ * @B2R2_BLT_FMT_YUV422_PACKED_PLANAR: YUV planar format, organized with
+ * three separate planes for each color component, namely Y, U, and V.
+ * U and V pixels are subsampled by a factor of two horizontally.
+ * The buffer shall contain a plane of Y, U, and V data in this order.
+ * @B2R2_BLT_FMT_Y_CB_Y_CR: 16 bits per pixel YUV interleaved format organized
+ * as YUYV (i.e., YCbYCr).
+ * (Corresponds to YUV422 interleaved)
+ * @B2R2_BLT_FMT_CB_Y_CR_Y: 16 bits per pixel YUV interleaved format organized
+ * as UYVY (i.e., CbYCrY).
+ * (Corresponds to YUV422R)
+ * @B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: YUV planar format, organized with
+ * a first plane containing Y pixels, and a second plane containing U and V
+ * pixels interleaved with the first U value first. U and V pixels are
+ * sub-sampled by a factor of two both horizontally and vertically. The buffer
+ * shall contain a plane of Y, U and V data.
+ * (Same as B2R2 420 Raster 2 buffer - 420 R2B)
+ * @B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: YUV planar format, organized with
+ * a first plane containing Y pixels, and a second plane containing U and V
+ * pixels interleaved with the first U value first. U and V pixels are
+ * sub-sampled by a factor of two horizontally. The buffer shall contain a
+ * plane of Y, U and V data.
+ * (Same as B2R2 422 Raster 2 buffer - 422 R2B)
+ * @B2R2_BLT_FMT_32_BIT_ABGR8888: 32 bits per pixel ABGR format with colors
+ * stored as Alpha 31:24,Blue 23:16, Green 15:8, and Red 7:0.
+ * @B2R2_BLT_FMT_24_BIT_ARGB8565: 24 bits per pixel ARGB format with colors
+ * stored as Alpha 23:16, Red 15:11, Green 10:5, and Blue 4:0.
+ * @B2R2_BLT_FMT_24_BIT_YUV888: 24 bits per pixel YUV format with colors
+ * stored as Y 23:16, U 15:8, and V 7:0.
+ * @B2R2_BLT_FMT_32_BIT_AYUV8888: 32 bits per pixel AYUV format with colors
+ * stored as Alpha 31:24, Y 23:16, U 15:8, and V 7:0.
+ * @B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: Nomadik YUV 420 macro block
+ * format, see B2R2 spec for details
+ * @B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: Nomadik YUV 422 macro block
+ * format, see B2R2 spec for details
+ * @B2R2_BLT_FMT_1_BIT_A1: 1 bit per pixel A format, 1 bit alpha
+ * @B2R2_BLT_FMT_8_BIT_A8: 8 bit per pixel A format, 8 bit alpha
+ * @B2R2_BLT_FMT_YUV444_PACKED_PLANAR: YUV planar format, organized with
+ * three separate planes, one for each color component, namely Y, U, and V.
+ * All planes use full resolution, there is no subsampling.
+ * The buffer shall contain a plane of Y, U, and V data in this order.
+ */
+enum b2r2_blt_fmt {
+ B2R2_BLT_FMT_UNUSED = 0,
+ B2R2_BLT_FMT_16_BIT_ARGB4444 = 4,
+ B2R2_BLT_FMT_16_BIT_ARGB1555 = 5,
+ B2R2_BLT_FMT_16_BIT_RGB565 = 6,
+ B2R2_BLT_FMT_24_BIT_RGB888 = 11,
+ B2R2_BLT_FMT_32_BIT_ARGB8888 = 16,
+ B2R2_BLT_FMT_YUV420_PACKED_PLANAR = 20,
+ B2R2_BLT_FMT_YUV422_PACKED_PLANAR = 23,
+ B2R2_BLT_FMT_Y_CB_Y_CR = 25,
+ B2R2_BLT_FMT_CB_Y_CR_Y = 27,
+ B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR = 39,
+ B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR = 40,
+ /* Extensions, non OpenMAX formats */
+ B2R2_BLT_FMT_32_BIT_ABGR8888 = 0x7F000000, /* OpenMax vendor start */
+ B2R2_BLT_FMT_24_BIT_ARGB8565 = 0x7F000001,
+ B2R2_BLT_FMT_24_BIT_YUV888 = 0x7F000002,
+ B2R2_BLT_FMT_32_BIT_AYUV8888 = 0x7F000003,
+ B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE = 0x7F000004,
+ B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE = 0x7F000005,
+ B2R2_BLT_FMT_1_BIT_A1 = 0x7F000006,
+ B2R2_BLT_FMT_8_BIT_A8 = 0x7F000007,
+ B2R2_BLT_FMT_YUV444_PACKED_PLANAR = 0x7F000008,
+};
+
+/**
+ * enum b2r2_blt_ptr_type - Specifies a B2R2 buffer pointer type
+ *
+ * @B2R2_BLT_PTR_NONE:
+ * No pointer (NULL). E.g. src fill.
+ * @B2R2_BLT_PTR_VIRTUAL:
+ * Use offset as a userspace virtual address
+ * @B2R2_BLT_PTR_PHYSICAL:
+ * Use offset as a physical address
+ * @B2R2_BLT_PTR_FD_OFFSET:
+ * Use fd + offset to determine buffer location.
+ * @B2R2_BLT_PTR_HWMEM_BUF_NAME:
+ * Use hwmem_buf_name and offset to determine buffer location.
+ */
+enum b2r2_blt_ptr_type {
+ B2R2_BLT_PTR_NONE,
+ B2R2_BLT_PTR_VIRTUAL,
+ B2R2_BLT_PTR_PHYSICAL,
+ B2R2_BLT_PTR_FD_OFFSET,
+ B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET,
+};
+
+/**
+ * struct b2r2_blt_buf - Specifies a B2R2 buffer pointer
+ *
+ * @type: Buffer pointer type
+ * @hwmem_global_buf_id: Hwmem buffer name
+ * @fd: File descriptor (e.g. file handle to pmem or fb device)
+ * @offset: Offset where buffer can be found or address. When used in
+ * conjunction with a hwmem buffer the offset must be a multiple of the
+ * image size.
+ * @len: Size of buffer in bytes
+ * @bits: Pointer to the bitmap data. This field can be used to specify
+ * an alternative way to access the buffer. Whenever the 'bits' pointer
+ * is set to non-NULL, the underlying implementation is free to decide
+ * whether or not to use it in favor of other ways to locate the buffer.
+ */
+struct b2r2_blt_buf {
+ enum b2r2_blt_ptr_type type;
+ __s32 hwmem_buf_name;
+ __s32 fd;
+ __u32 offset;
+ __u32 len;
+ void *bits;
+};
+
+
+/**
+ * struct b2r2_blt_img - Specifies a B2R2 image
+ *
+ * @fmt: Pixel format of image
+ * @buf: Pixel buffer
+ * @width: Width in pixels
+ * @height: Height in pixels
+ * @pitch: Pitch in bytes (from start of one line to start of next)
+ */
+struct b2r2_blt_img {
+ enum b2r2_blt_fmt fmt;
+ struct b2r2_blt_buf buf;
+ __s32 width;
+ __s32 height;
+ __u32 pitch;
+};
+
+
+/**
+ * enum b2r2_blt_transform- Specifies rotation and flipping, mutually exclusive
+ * @B2R2_BLT_TRANSFORM_NONE:
+ * No rotation or flip
+ * @B2R2_BLT_TRANSFORM_FLIP_H
+ * Flip horizontally
+ * @B2R2_BLT_TRANSFORM_FLIP_V
+ * Flip vertically
+ * @B2R2_BLT_TRANSFORM_CCW_ROT_90
+ * Rotate 90 degrees counter clockwise
+ * @B2R2_BLT_TRANSFORM_CCW_ROT_180
+ * Rotate 180 degrees (same as flip horizontally together with
+ * flip vertically)
+ * @B2R2_BLT_TRANSFORM_CCW_ROT_270
+ * Rotate 270 degrees counter clockwise
+ * @B2R2_BLT_TRANSFORM_FLIP_H_CCW_ROT_90
+ * Flip horizontally and then rotate 90 degrees counter clockwise
+ * @B2R2_BLT_TRANSFORM_FLIP_V_CCW_ROT_90
+ * Flip vertically and then rotate 90 degrees counter clockwise
+ */
+enum b2r2_blt_transform {
+ B2R2_BLT_TRANSFORM_NONE = 0,
+ B2R2_BLT_TRANSFORM_FLIP_H = 1,
+ B2R2_BLT_TRANSFORM_FLIP_V = 2,
+ B2R2_BLT_TRANSFORM_CCW_ROT_90 = 4,
+ B2R2_BLT_TRANSFORM_CCW_ROT_180 = 3,
+ B2R2_BLT_TRANSFORM_CCW_ROT_270 = 7,
+ B2R2_BLT_TRANSFORM_FLIP_H_CCW_ROT_90 = 5,
+ B2R2_BLT_TRANSFORM_FLIP_V_CCW_ROT_90 = 6,
+};
+
+
+/**
+ * enum b2r2_blt_flag - Flags that controls the B2R2 request
+ *
+ * Can be combined.
+ *
+ * @B2R2_BLT_FLAG_ASYNCH:
+ * Asynchronous request. b2r2_blt will returns when the request
+ * has been queued.
+ * @B2R2_BLT_FLAG_DRY_RUN:
+ * Dry run, just to check if request can be performed.
+ * @B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND:
+ * Enable per pixel alpha blend
+ * @B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND:
+ * Enable global alpha blend (alpha value in global_alpha)
+ * @B2R2_BLT_FLAG_SOURCE_COLOR_KEY:
+ * Enable source color key (color in src_color). Color should be in raw
+ * format.
+ * B2R2_BLT_FLAG_SOURCE_COLOR_KEY, B2R2_BLT_FLAG_SOURCE_FILL and
+ * B2R2_BLT_FLAG_SOURCE_FILL_RAW cannot be specified at the same time.
+ * B2R2_BLT_FLAG_SOURCE_COLOR_KEY and B2R2_BLT_FLAG_DEST_COLOR_KEY cannot be
+ * specified at the same time.
+ * @B2R2_BLT_FLAG_SOURCE_FILL:
+ * Enable ARGB/AYUV source fill (color in src_color). Which of ARGB and AYUV
+ * is determined by the destination format.
+ * B2R2_BLT_FLAG_SOURCE_COLOR_KEY, B2R2_BLT_FLAG_SOURCE_FILL and
+ * B2R2_BLT_FLAG_SOURCE_FILL_RAW cannot be specified at the same time
+ * @B2R2_BLT_FLAG_SOURCE_FILL_RAW:
+ * Enable raw color source fill (color in src_color)
+ * B2R2_BLT_FLAG_SOURCE_COLOR_KEY, B2R2_BLT_FLAG_SOURCE_FILL and
+ * B2R2_BLT_FLAG_SOURCE_FILL_RAW cannot be specified at the same time
+ * @B2R2_BLT_FLAG_DEST_COLOR_KEY:
+ * Enable dest color key (color in dst_color). Color in raw format.
+ * @B2R2_BLT_FLAG_SRC_IS_NOT_PREMULT:
+ * Source color not premultiplied (Valid for alpha formats only).
+ * @B2R2_BLT_FLAG_DITHER:
+ * Enable dithering
+ * @B2R2_BLT_FLAG_BLUR:
+ * Enable blur
+ * @B2R2_BLT_FLAG_SOURCE_MASK:
+ * Enable source mask
+ * @B2R2_BLT_FLAG_DESTINATION_CLIP:
+ * Enable destination clip rectangle
+ * @B2R2_BLT_FLAG_INHERIT_PRIO
+ * Inherit process priority
+ * @B2R2_BLT_FLAG_REPORT_WHEN_DONE
+ * Report through b2r2_blt file when done. A b2r2_blt_report structure is
+ * read. Use poll() or select() if anything to read. (i.e. to help user space
+ * to implement callback functionality)
+ * @B2R2_BLT_FLAG_REPORT_PERFORMANCE
+ * Include performance data in the report structure
+ * @B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION
+ * Use color look-up table for color correction.
+ * Pointer to the table must be specified in *clut field of
+ * the b2r2_blt_req structure.
+ * The table must map all input color values
+ * for each channel to the desired output values.
+ * It is an array with the following format:
+ * R0 G0 B0 A0 R1 G1 B1 A1...R255 G255 B255 A255
+ * where R0 is the 8 bit output value for red channel whenever its input
+ * equals 0.
+ * Similarly, R1 through R255 are the red channel outputs whenever
+ * the channel's inputs equal 1 through 255 respectively.
+ * Gn, Bn, An denote green, blue and alpha channel.
+ * Whenever the input bitmap format lacks the alpha channel,
+ * all alpha values in the color correction table should be set to 255.
+ * Size of the array that specifies the color correction table
+ * must be 1024 bytes.
+ * A table that does not change anything has the form:
+ * 0 0 0 0 1 1 1 1 2 2 2 2 ... 254 254 254 254 255 255 255 255.
+ * CLUT color correction can be applied to YUV raster buffers as well,
+ * in which case the RGB color channels are mapped onto YUV-space
+ * as follows:
+ * R = red chrominance
+ * G = luminance
+ * B = blue chrominance
+ * A = alpha
+ * If any of the planar or semi-planar formats is used, luminance cannot
+ * be changed by the color correction table.
+ */
+#if !defined(__KERNEL__) && !defined(_KERNEL)
+#define BIT(nr) (1UL << (nr))
+#endif
+enum b2r2_blt_flag {
+ B2R2_BLT_FLAG_ASYNCH = BIT(0),/*0x1*/
+ B2R2_BLT_FLAG_DRY_RUN = BIT(1),/*0x2*/
+ B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND = BIT(2),/*0x4*/
+ B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND = BIT(3),/*0x8*/
+ B2R2_BLT_FLAG_SOURCE_COLOR_KEY = BIT(4),/*0x10*/
+ B2R2_BLT_FLAG_SOURCE_FILL = BIT(5),/*0x20*/
+ B2R2_BLT_FLAG_SOURCE_FILL_RAW = BIT(6),/*0x40*/
+ B2R2_BLT_FLAG_DEST_COLOR_KEY = BIT(7),/*0x80*/
+ B2R2_BLT_FLAG_SRC_IS_NOT_PREMULT = BIT(8),/*0x100*/
+ B2R2_BLT_FLAG_DITHER = BIT(9),/*0x200*/
+ B2R2_BLT_FLAG_BLUR = BIT(10),/*0x400*/
+ B2R2_BLT_FLAG_SOURCE_MASK = BIT(11),/*0x800*/
+ B2R2_BLT_FLAG_DESTINATION_CLIP = BIT(12),/*0x1000*/
+ B2R2_BLT_FLAG_INHERIT_PRIO = BIT(13),/*0x2000*/
+ B2R2_BLT_FLAG_SRC_NO_CACHE_FLUSH = BIT(14),/*0x4000*/
+ B2R2_BLT_FLAG_SRC_MASK_NO_CACHE_FLUSH = BIT(15),/*0x8000*/
+ B2R2_BLT_FLAG_DST_NO_CACHE_FLUSH = BIT(16),/*0x10000*/
+ B2R2_BLT_FLAG_REPORT_WHEN_DONE = BIT(29),/*0x20000000*/
+ B2R2_BLT_FLAG_REPORT_PERFORMANCE = BIT(30),/*0x40000000*/
+ B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION = BIT(31),/*0x80000000*/
+};
+
+
+/**
+ * struct b2r2_blt_req - Specifies a request to B2R2
+ *
+ * @size: Size of this structure. Used for versioning. MUST be specified.
+ * @flags: Flags that control the B2R2 request ORed together
+ * @tfm: How source should be flipped and rotated when blitting
+ * @prio: Priority (-20 to 19). Inherits process prio
+ * if B2R2_BLT_FLAG_INHERIT_PRIO. Given priority is mapped onto B2R2.
+ * TBD: How?
+ * @clut: Pointer to the look-up table for color correction.
+ * @src_img: Source image. Not used if source fill.
+ * @src_mask: Source mask. Not used if source fill.
+ * @src_rect: Source area to be blitted.
+ * @src_color: Source fill color or color key
+ * @dst_img: Destination image.
+ * @dst_rect: Destination area to be blitted to.
+ * @dst_color: Destination color key
+ * @dst_clip_rect: Destination clip rectangle.
+ * @global_alpha: Global alpha value (0 - 255)
+ * @report1: Data 1 to report back when request is done.
+ * See struct b2r2_blt_report.
+ * @report2: Data 2 to report back when request is done.
+ * See struct b2r2_blt_report.
+ *
+ */
+struct b2r2_blt_req {
+ __u32 size;
+ enum b2r2_blt_flag flags;
+ enum b2r2_blt_transform transform;
+ __s32 prio;
+ void *clut;
+ struct b2r2_blt_img src_img;
+ struct b2r2_blt_img src_mask;
+ struct b2r2_blt_rect src_rect;
+ __u32 src_color;
+ struct b2r2_blt_img dst_img;
+ struct b2r2_blt_rect dst_rect;
+ struct b2r2_blt_rect dst_clip_rect;
+ __u32 dst_color;
+ __u8 global_alpha;
+ __u32 report1;
+ __u32 report2;
+};
+
+/**
+ * enum b2r2_blt_cap - Capabilities that can be queried for.
+ *
+ * Capabilities can be queried for a specific format or for formats in
+ * general. To query for capabilities in general, specify BLT_FMT_UNUSED
+ * as format.
+ *
+ * B2R2_BLT_CAP_UNUSED: Unused/unspecified capability
+ * B2R2_BLT_CAP_FMT_SOURCE: Is format supported as source?
+ * B2R2_BLT_CAP_FMT_SOURCE_MASK: Is format supported as source mask?
+ * B2R2_BLT_CAP_FMT_DEST: Is format supported as dest?
+ * B2R2_BLT_CAP_PER_PIXEL_ALPHA_BLEND: Is per pixel alpha blending supported
+ * with format as source
+ * B2R2_BLT_CAP_GLOBAL_ALPHA_BLEND: Is per global alpha blending supported
+ * with format as source
+ * B2R2_BLT_CAP_SOURCE_COLOR_KEY: Is source color key supported with format as
+ * source
+ * B2R2_BLT_CAP_SOURCE_FILL: Is source fill supported with format as source
+ * B2R2_BLT_CAP_SOURCE_FILL_RAW: Is source fill raw supported with format as
+ * dest
+ * B2R2_BLT_CAP_DEST_COLOR_KEY: Is dest color key supported with format as dest
+ * B2R2_BLT_CAP_DITHER: Is dithering supported with format as source
+ * B2R2_BLT_CAP_BLUR: Is blur supported with format as source
+ * B2R2_BLT_CAP_MINIFICATION_LIMIT: Minification limit (copybit support)
+ * B2R2_BLT_CAP_MAGNIFICATION_LIMIT: Magnification limit (copybit support)
+ * B2R2_BLT_CAP_SCALING_FRAC_BITS: Number of scaling fractional bits (copybit
+ * support)
+ * B2R2_BLT_CAP_ROTATION_STEP_DEG: Supported rotation step in degrees (copybit
+ * support)
+ */
+
+enum b2r2_blt_cap {
+ B2R2_BLT_CAP_UNUSED = 0,
+ /**
+ * @brief Is format supported as source.
+ */
+ B2R2_BLT_CAP_FMT_SOURCE,
+ /**
+ * @brief Is format supported as source mask
+ */
+ B2R2_BLT_CAP_FMT_SOURCE_MASK,
+ /**
+ * @brief Is format supported as destination
+ */
+ B2R2_BLT_CAP_FMT_DEST,
+ /**
+ * @brief Is per pixel alpha blending supported with format as source
+ */
+ B2R2_BLT_CAP_PER_PIXEL_ALPHA_BLEND,
+ /**
+ * @brief Is global alpha blending supported with format as source
+ */
+ B2R2_BLT_CAP_GLOBAL_ALPHA_BLEND,
+ /**
+ * @brief Is source color key supported with format as source
+ */
+ B2R2_BLT_CAP_SOURCE_COLOR_KEY,
+ /**
+ * @brief Is source fill supported with format as source
+ */
+ B2R2_BLT_CAP_SOURCE_FILL,
+ /**
+ * @brief Is source fill raw supported with format as dest
+ */
+ B2R2_BLT_CAP_SOURCE_FILL_RAW,
+ /**
+ * @brief Is dest color key supported with format as dest
+ */
+ B2R2_BLT_CAP_DEST_COLOR_KEY,
+ /**
+ * @brief Is dithering supported with format as source
+ */
+ B2R2_BLT_CAP_DITHER,
+ /**
+ * @brief Is blur supported with format as source
+ */
+ B2R2_BLT_CAP_BLUR,
+ /**
+ * @brief Minification limit (copybit support)
+ */
+ B2R2_BLT_CAP_MINIFICATION_LIMIT,
+ /**
+ * @brief Magnification limit (copybit support)
+ */
+ B2R2_BLT_CAP_MAGNIFICATION_LIMIT,
+ /**
+ * @brief Number of scaling fractional bits (copybit support)
+ */
+ B2R2_BLT_CAP_SCALING_FRAC_BITS,
+ /**
+ * @brief Supported rotation step in degrees (copybit support)
+ */
+ B2R2_BLT_CAP_ROTATION_STEP_DEG,
+};
+
+/**
+ * struct b2r2_blt_query_cap - Query B2R2 capabilities
+ *
+ * fmt: Format to query capabilities for or BLT_FMT_UNUSED for all
+ * cap: Capability to query for
+ * result: Returned capability. Interpretaion of this variable varies
+ * with the capability queried
+ */
+struct b2r2_blt_query_cap {
+ enum b2r2_blt_fmt fmt;
+ enum b2r2_blt_cap cap;
+ __u32 result;
+};
+
+/**
+ * struct b2r2_blt_report - Report from B2R2 driver back to user space
+ *
+ * This structure can be read from B2R2 driver if B2R2_BLT_FLAG_REPORT_WHEN_DONE
+ * flag was specified when the request was issued.
+ *
+ * @request_id: The id for the request, same as reported from blt_request
+ * @report1: Client data specified in struct blt_request
+ * @report2: Client data specified in struct blt_request
+ * @usec_elapsed: Number of microseconds needed to perform this blit
+ * if B2R2_BLT_FLAG_REPORT_PERFORMANCE was specified when the
+ * request was issued.
+ *
+ */
+struct b2r2_blt_report {
+ __u32 request_id;
+ __u32 report1;
+ __u32 report2;
+ __u32 usec_elapsed;
+};
+
+/**
+ * B2R2 BLT driver is used in the following way:
+ *
+ * Obtain a file descriptor to the driver:
+ * fd = open("/dev/b2r2_blt", O_RDWR);
+ *
+ * Issue requests:
+ * struct b2r2_blt_request blt_request;
+ * blt_request.size = sizeof(blt_request);
+ * ... Fill request with data...
+ *
+ * request_id = ioctl(fd, B2R2_BLT_IOC, (__u32) &blt_request);
+ *
+ * Wait for a request to finish
+ * ret = ioctl(fd, B2R2_BLT_SYNCH_IOC, (__u32) request_id);
+ *
+ * Wait for all requests from this context to finish
+ * ret = ioctl(fd, B2R2_BLT_SYNCH_IOC, (__u32) 0);
+ *
+ * Wait indefinitely for report data from driver:
+ * pollfd.fd = fd
+ * pollfd.events = 0xFFFFFFFF;
+ * pollfd.revents = 0;
+ * ret = poll(&pollfd, 1, -1);
+ *
+ * Read report data from driver
+ * struct b2r2_blt_report blt_report;
+ *
+ * nread = read(fd, &blt_report, sizeof(blt_report));
+ *
+ * Close the driver
+ * close(fd);
+ */
+
+/* B2R2 BLT IOCTLS */
+
+/**
+ * B2R2_BLT_IOC_MAGIC is ioctl type group for B2R2 driver
+ */
+#define B2R2_BLT_IOC_MAGIC 0xb2
+
+/**
+ * The B2R2_BLT_IOC ioctl adds a blit request to B2R2.
+ *
+ * The ioctl returns when the blit has been performed if not
+ * asynchronous execution has been specified. If asynchronous,
+ * control is returned as soon as the request has been queued.
+ *
+ * Supplied parameter shall be a pointer to a struct b2r2_blt_req.
+ *
+ * Returns an unique request id if >= 0, else a negative error code.
+ * This request id can be waited for using B2R2_BLT_SYNC_IOC.
+ * Return values: -ESOMERROR Description of an error
+ */
+#define B2R2_BLT_IOC _IOW(B2R2_BLT_IOC_MAGIC, 1, struct b2r2_blt_req)
+
+/**
+ * The B2R2_BLT_SYNC_IOC waits for all or a specified request to be finished.
+ *
+ * Supplied parameter shall be a request id previously returned by
+ * B2R2_BLT_IOC or 0 for all requests.
+ *
+ * Returns 0 if OK, else a negative error code
+ * Return value: -ESOMERROR Description of an error
+ */
+#define B2R2_BLT_SYNCH_IOC _IOW(B2R2_BLT_IOC_MAGIC, 2, int)
+
+/**
+ * The BLT_QUERY_CAP_IOC returns capability information for all or
+ * for a certain format
+ *
+ * Supplied parameter shall be a pointer to a struct b2r2_blt_query_cap.
+ *
+ * @return Returns 0 if OK, else a negative error code
+ * @retval -ESOMERROR Description of an error
+ */
+#define B2R2_BLT_QUERY_CAP_IOC _IOWR(B2R2_BLT_IOC_MAGIC, 3, \
+ struct b2r2_blt_query_cap)
+
+#endif /* #ifdef _LINUX_VIDEO_B2R2_BLT_H */
diff --git a/include/video/hdmi.h b/include/video/hdmi.h
new file mode 100644
index 00000000000..a60a974763c
--- /dev/null
+++ b/include/video/hdmi.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * HDMI driver
+ *
+ * Author: Per Persson <per.xb.persson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __HDMI__H__
+#define __HDMI__H__
+
+
+#define HDMI_CEC_READ_MAXSIZE 16
+#define HDMI_CEC_WRITE_MAXSIZE 15
+#define HDMI_INFOFRAME_MAX_SIZE 27
+#define HDMI_HDCP_FUSEAES_KEYSIZE 16
+#define HDMI_HDCP_AES_BLOCK_START 128
+#define HDMI_HDCP_KSV_BLOCK 40
+#define HDMI_HDCP_AES_NR_OF_BLOCKS 18
+#define HDMI_HDCP_AES_KEYSIZE 16
+#define HDMI_HDCP_AES_KSVSIZE 5
+#define HDMI_HDCP_AES_KSVZEROESSIZE 3
+
+#define HDMI_STOREASTEXT_TEXT_SIZE 2
+#define HDMI_STOREASTEXT_BIN_SIZE 1
+#define HDMI_PLUGDETEN_TEXT_SIZE 6
+#define HDMI_PLUGDETEN_BIN_SIZE 3
+#define HDMI_EDIDREAD_TEXT_SIZE 4
+#define HDMI_EDIDREAD_BIN_SIZE 2
+#define HDMI_CECEVEN_TEXT_SIZE 2
+#define HDMI_CECEVEN_BIN_SIZE 1
+#define HDMI_CECSEND_TEXT_SIZE_MAX 37
+#define HDMI_CECSEND_TEXT_SIZE_MIN 6
+#define HDMI_CECSEND_BIN_SIZE_MAX 18
+#define HDMI_CECSEND_BIN_SIZE_MIN 3
+#define HDMI_INFOFRSEND_TEXT_SIZE_MIN 8
+#define HDMI_INFOFRSEND_TEXT_SIZE_MAX 63
+#define HDMI_INFOFRSEND_BIN_SIZE_MIN 4
+#define HDMI_INFOFRSEND_BIN_SIZE_MAX 31
+#define HDMI_HDCPEVEN_TEXT_SIZE 2
+#define HDMI_HDCPEVEN_BIN_SIZE 1
+#define HDMI_HDCP_FUSEAES_TEXT_SIZE 34
+#define HDMI_HDCP_FUSEAES_BIN_SIZE 17
+#define HDMI_HDCP_LOADAES_TEXT_SIZE 586
+#define HDMI_HDCP_LOADAES_BIN_SIZE 293
+#define HDMI_HDCPAUTHENCR_TEXT_SIZE 4
+#define HDMI_HDCPAUTHENCR_BIN_SIZE 2
+#define HDMI_EVCLR_TEXT_SIZE 2
+#define HDMI_EVCLR_BIN_SIZE 1
+#define HDMI_AUDIOCFG_TEXT_SIZE 14
+#define HDMI_AUDIOCFG_BIN_SIZE 7
+
+#define HDMI_IOC_MAGIC 0xcc
+
+/** IOCTL Operations */
+#define IOC_PLUG_DETECT_ENABLE _IOWR(HDMI_IOC_MAGIC, 1, int)
+#define IOC_EDID_READ _IOWR(HDMI_IOC_MAGIC, 2, int)
+#define IOC_CEC_EVENT_ENABLE _IOWR(HDMI_IOC_MAGIC, 3, int)
+#define IOC_CEC_READ _IOWR(HDMI_IOC_MAGIC, 4, int)
+#define IOC_CEC_SEND _IOWR(HDMI_IOC_MAGIC, 5, int)
+#define IOC_INFOFRAME_SEND _IOWR(HDMI_IOC_MAGIC, 6, int)
+#define IOC_HDCP_EVENT_ENABLE _IOWR(HDMI_IOC_MAGIC, 7, int)
+#define IOC_HDCP_CHKAESOTP _IOWR(HDMI_IOC_MAGIC, 8, int)
+#define IOC_HDCP_FUSEAES _IOWR(HDMI_IOC_MAGIC, 9, int)
+#define IOC_HDCP_LOADAES _IOWR(HDMI_IOC_MAGIC, 10, int)
+#define IOC_HDCP_AUTHENCR_REQ _IOWR(HDMI_IOC_MAGIC, 11, int)
+#define IOC_HDCP_STATE_GET _IOWR(HDMI_IOC_MAGIC, 12, int)
+#define IOC_REVOCATION_LIST_GET _IOWR(HDMI_IOC_MAGIC, 13, int)
+#define IOC_REVOCATION_LIST_SET _IOWR(HDMI_IOC_MAGIC, 14, int)
+#define IOC_EVENTS_READ _IOWR(HDMI_IOC_MAGIC, 15, int)
+#define IOC_EVENTS_CLEAR _IOWR(HDMI_IOC_MAGIC, 16, int)
+#define IOC_AUDIO_CFG _IOWR(HDMI_IOC_MAGIC, 17, int)
+#define IOC_PLUG_STATUS _IOWR(HDMI_IOC_MAGIC, 18, int)
+
+
+/* HDMI driver */
+void hdmi_event(enum av8100_hdmi_event);
+int hdmi_init(void);
+void hdmi_exit(void);
+
+enum hdmi_event {
+ HDMI_EVENT_NONE = 0x0,
+ HDMI_EVENT_HDMI_PLUGIN = 0x1,
+ HDMI_EVENT_HDMI_PLUGOUT = 0x2,
+ HDMI_EVENT_CEC = 0x4,
+ HDMI_EVENT_HDCP = 0x8,
+};
+
+enum hdmi_hdcp_auth_type {
+ HDMI_HDCP_AUTH_OFF = 0,
+ HDMI_HDCP_AUTH_START = 1,
+ HDMI_HDCP_AUTH_CONT = 2,
+};
+
+enum hdmi_hdcp_encr_type {
+ HDMI_HDCP_ENCR_OFF = 0,
+ HDMI_HDCP_ENCR_OESS = 1,
+ HDMI_HDCP_ENCR_EESS = 2,
+};
+
+struct plug_detect {
+ u8 hdmi_detect_enable;
+ u8 on_time;
+ u8 hdmi_off_time;
+};
+
+struct edid_read {
+ u8 address;
+ u8 block_nr;
+ u8 data_length;
+ u8 data[128];
+};
+
+struct cec_rw {
+ u8 src;
+ u8 dest;
+ u8 length;
+ u8 data[15];
+};
+
+struct info_fr {
+ u8 type;
+ u8 ver;
+ u8 crc;
+ u8 length;
+ u8 data[27];
+};
+
+struct hdcp_fuseaes {
+ u8 key[16];
+ u8 crc;
+ u8 result;
+};
+
+struct hdcp_loadaesall {
+ u8 ksv[5];
+ u8 key[288];
+ u8 result;
+};
+
+struct hdcp_authencr {
+ u8 auth_type;
+ u8 encr_type;
+};
+
+struct audio_cfg {
+ u8 if_format;
+ u8 i2s_entries;
+ u8 freq;
+ u8 word_length;
+ u8 format;
+ u8 if_mode;
+ u8 mute;
+};
+
+#endif /* __HDMI__H__ */
diff --git a/include/video/mcde.h b/include/video/mcde.h
new file mode 100644
index 00000000000..5d7fbd170e9
--- /dev/null
+++ b/include/video/mcde.h
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson MCDE base driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __MCDE__H__
+#define __MCDE__H__
+
+/* Physical interface types */
+enum mcde_port_type {
+ MCDE_PORTTYPE_DSI = 0,
+ MCDE_PORTTYPE_DPI = 1,
+};
+
+/* Interface mode */
+enum mcde_port_mode {
+ MCDE_PORTMODE_CMD = 0,
+ MCDE_PORTMODE_VID = 1,
+};
+
+/* MCDE fifos */
+enum mcde_fifo {
+ MCDE_FIFO_A = 0,
+ MCDE_FIFO_B = 1,
+ MCDE_FIFO_C0 = 2,
+ MCDE_FIFO_C1 = 3,
+};
+
+/* MCDE channels (pixel pipelines) */
+enum mcde_chnl {
+ MCDE_CHNL_A = 0,
+ MCDE_CHNL_B = 1,
+ MCDE_CHNL_C0 = 2,
+ MCDE_CHNL_C1 = 3,
+};
+
+/* Channel path */
+#define MCDE_CHNLPATH(__chnl, __fifo, __type, __ifc, __link) \
+ (((__chnl) << 16) | ((__fifo) << 12) | \
+ ((__type) << 8) | ((__ifc) << 4) | ((__link) << 0))
+enum mcde_chnl_path {
+ /* Channel A */
+ MCDE_CHNLPATH_CHNLA_FIFOA_DPI_0 = MCDE_CHNLPATH(MCDE_CHNL_A,
+ MCDE_FIFO_A, MCDE_PORTTYPE_DPI, 0, 0),
+ MCDE_CHNLPATH_CHNLA_FIFOA_DSI_IFC0_0 = MCDE_CHNLPATH(MCDE_CHNL_A,
+ MCDE_FIFO_A, MCDE_PORTTYPE_DSI, 0, 0),
+ MCDE_CHNLPATH_CHNLA_FIFOA_DSI_IFC0_1 = MCDE_CHNLPATH(MCDE_CHNL_A,
+ MCDE_FIFO_A, MCDE_PORTTYPE_DSI, 0, 1),
+ MCDE_CHNLPATH_CHNLA_FIFOC0_DSI_IFC0_2 = MCDE_CHNLPATH(MCDE_CHNL_A,
+ MCDE_FIFO_C0, MCDE_PORTTYPE_DSI, 0, 2),
+ MCDE_CHNLPATH_CHNLA_FIFOC0_DSI_IFC1_0 = MCDE_CHNLPATH(MCDE_CHNL_A,
+ MCDE_FIFO_C0, MCDE_PORTTYPE_DSI, 1, 0),
+ MCDE_CHNLPATH_CHNLA_FIFOC0_DSI_IFC1_1 = MCDE_CHNLPATH(MCDE_CHNL_A,
+ MCDE_FIFO_C0, MCDE_PORTTYPE_DSI, 1, 1),
+ MCDE_CHNLPATH_CHNLA_FIFOA_DSI_IFC1_2 = MCDE_CHNLPATH(MCDE_CHNL_A,
+ MCDE_FIFO_A, MCDE_PORTTYPE_DSI, 1, 2),
+ /* Channel B */
+ MCDE_CHNLPATH_CHNLB_FIFOB_DPI_1 = MCDE_CHNLPATH(MCDE_CHNL_B,
+ MCDE_FIFO_B, MCDE_PORTTYPE_DPI, 0, 1),
+ MCDE_CHNLPATH_CHNLB_FIFOB_DSI_IFC0_0 = MCDE_CHNLPATH(MCDE_CHNL_B,
+ MCDE_FIFO_B, MCDE_PORTTYPE_DSI, 0, 0),
+ MCDE_CHNLPATH_CHNLB_FIFOB_DSI_IFC0_1 = MCDE_CHNLPATH(MCDE_CHNL_B,
+ MCDE_FIFO_B, MCDE_PORTTYPE_DSI, 0, 1),
+ MCDE_CHNLPATH_CHNLB_FIFOC1_DSI_IFC0_2 = MCDE_CHNLPATH(MCDE_CHNL_B,
+ MCDE_FIFO_C1, MCDE_PORTTYPE_DSI, 0, 2),
+ MCDE_CHNLPATH_CHNLB_FIFOC1_DSI_IFC1_0 = MCDE_CHNLPATH(MCDE_CHNL_B,
+ MCDE_FIFO_C1, MCDE_PORTTYPE_DSI, 1, 0),
+ MCDE_CHNLPATH_CHNLB_FIFOC1_DSI_IFC1_1 = MCDE_CHNLPATH(MCDE_CHNL_B,
+ MCDE_FIFO_C1, MCDE_PORTTYPE_DSI, 1, 1),
+ MCDE_CHNLPATH_CHNLB_FIFOB_DSI_IFC1_2 = MCDE_CHNLPATH(MCDE_CHNL_B,
+ MCDE_FIFO_B, MCDE_PORTTYPE_DSI, 1, 2),
+ /* Channel C0 */
+ MCDE_CHNLPATH_CHNLC0_FIFOA_DSI_IFC0_0 = MCDE_CHNLPATH(MCDE_CHNL_C0,
+ MCDE_FIFO_A, MCDE_PORTTYPE_DSI, 0, 0),
+ MCDE_CHNLPATH_CHNLC0_FIFOA_DSI_IFC0_1 = MCDE_CHNLPATH(MCDE_CHNL_C0,
+ MCDE_FIFO_A, MCDE_PORTTYPE_DSI, 0, 1),
+ MCDE_CHNLPATH_CHNLC0_FIFOC0_DSI_IFC0_2 = MCDE_CHNLPATH(MCDE_CHNL_C0,
+ MCDE_FIFO_C0, MCDE_PORTTYPE_DSI, 0, 2),
+ MCDE_CHNLPATH_CHNLC0_FIFOC0_DSI_IFC1_0 = MCDE_CHNLPATH(MCDE_CHNL_C0,
+ MCDE_FIFO_C0, MCDE_PORTTYPE_DSI, 1, 0),
+ MCDE_CHNLPATH_CHNLC0_FIFOC0_DSI_IFC1_1 = MCDE_CHNLPATH(MCDE_CHNL_C0,
+ MCDE_FIFO_C0, MCDE_PORTTYPE_DSI, 1, 1),
+ MCDE_CHNLPATH_CHNLC0_FIFOA_DSI_IFC1_2 = MCDE_CHNLPATH(MCDE_CHNL_C0,
+ MCDE_FIFO_A, MCDE_PORTTYPE_DSI, 1, 2),
+ /* Channel C1 */
+ MCDE_CHNLPATH_CHNLC1_FIFOB_DSI_IFC0_0 = MCDE_CHNLPATH(MCDE_CHNL_C1,
+ MCDE_FIFO_B, MCDE_PORTTYPE_DSI, 0, 0),
+ MCDE_CHNLPATH_CHNLC1_FIFOB_DSI_IFC0_1 = MCDE_CHNLPATH(MCDE_CHNL_C1,
+ MCDE_FIFO_B, MCDE_PORTTYPE_DSI, 0, 1),
+ MCDE_CHNLPATH_CHNLC1_FIFOC1_DSI_IFC0_2 = MCDE_CHNLPATH(MCDE_CHNL_C1,
+ MCDE_FIFO_C1, MCDE_PORTTYPE_DSI, 0, 2),
+ MCDE_CHNLPATH_CHNLC1_FIFOC1_DSI_IFC1_0 = MCDE_CHNLPATH(MCDE_CHNL_C1,
+ MCDE_FIFO_C1, MCDE_PORTTYPE_DSI, 1, 0),
+ MCDE_CHNLPATH_CHNLC1_FIFOC1_DSI_IFC1_1 = MCDE_CHNLPATH(MCDE_CHNL_C1,
+ MCDE_FIFO_C1, MCDE_PORTTYPE_DSI, 1, 1),
+ MCDE_CHNLPATH_CHNLC1_FIFOB_DSI_IFC1_2 = MCDE_CHNLPATH(MCDE_CHNL_C1,
+ MCDE_FIFO_B, MCDE_PORTTYPE_DSI, 1, 2),
+};
+
+/* Update sync mode */
+enum mcde_sync_src {
+ MCDE_SYNCSRC_OFF = 0, /* No sync */
+ MCDE_SYNCSRC_TE0 = 1, /* MCDE ext TE0 */
+ MCDE_SYNCSRC_TE1 = 2, /* MCDE ext TE1 */
+ MCDE_SYNCSRC_BTA = 3, /* DSI BTA */
+};
+
+/* Interface pixel formats (output) */
+/*
+* REVIEW: Define formats
+* Add explanatory comments how the formats are ordered in memory
+*/
+enum mcde_port_pix_fmt {
+ /* MIPI standard formats */
+
+ MCDE_PORTPIXFMT_DPI_16BPP_C1 = 0x21,
+ MCDE_PORTPIXFMT_DPI_16BPP_C2 = 0x22,
+ MCDE_PORTPIXFMT_DPI_16BPP_C3 = 0x23,
+ MCDE_PORTPIXFMT_DPI_18BPP_C1 = 0x24,
+ MCDE_PORTPIXFMT_DPI_18BPP_C2 = 0x25,
+ MCDE_PORTPIXFMT_DPI_24BPP = 0x26,
+
+ MCDE_PORTPIXFMT_DSI_16BPP = 0x31,
+ MCDE_PORTPIXFMT_DSI_18BPP = 0x32,
+ MCDE_PORTPIXFMT_DSI_18BPP_PACKED = 0x33,
+ MCDE_PORTPIXFMT_DSI_24BPP = 0x34,
+
+ /* Custom formats */
+ MCDE_PORTPIXFMT_DSI_YCBCR422 = 0x40,
+};
+
+struct mcde_col_convert {
+ u16 matrix[3][3];
+ u16 offset[3];
+};
+
+#define MCDE_PORT_DPI_NO_CLOCK_DIV 0
+
+#define DPI_ACT_HIGH_ALL 0 /* all signals are active high */
+#define DPI_ACT_LOW_HSYNC 1 /* horizontal sync signal is active low */
+#define DPI_ACT_LOW_VSYNC 2 /* vertical sync signal is active low */
+#define DPI_ACT_LOW_DATA_ENABLE 4 /* data enable signal is active low */
+#define DPI_ACT_ON_FALLING_EDGE 8 /* drive data on the falling edge of the
+ * pixel clock
+ */
+
+struct mcde_port {
+ enum mcde_port_type type;
+ enum mcde_port_mode mode;
+ enum mcde_port_pix_fmt pixel_format;
+ u8 ifc;
+ u8 link;
+ enum mcde_sync_src sync_src;
+ bool update_auto_trig;
+ union {
+ struct {
+ u8 virt_id;
+ u8 num_data_lanes;
+ u8 ui;
+ bool clk_cont;
+ } dsi;
+ struct {
+ u8 bus_width;
+ bool tv_mode;
+ u16 clock_div; /* use 0 or 1 for no clock divider */
+ u32 polarity; /* see DPI_ACT_LOW_* definitions */
+ } dpi;
+ } phy;
+};
+
+/* Overlay pixel formats (input) *//* REVIEW: Define byte order */
+enum mcde_ovly_pix_fmt {
+ MCDE_OVLYPIXFMT_RGB565 = 1,
+ MCDE_OVLYPIXFMT_RGBA5551 = 2,
+ MCDE_OVLYPIXFMT_RGBA4444 = 3,
+ MCDE_OVLYPIXFMT_RGB888 = 4,
+ MCDE_OVLYPIXFMT_RGBX8888 = 5,
+ MCDE_OVLYPIXFMT_RGBA8888 = 6,
+ MCDE_OVLYPIXFMT_YCbCr422 = 7,/* REVIEW: Capitalize */
+};
+
+/* Display power modes */
+enum mcde_display_power_mode {
+ MCDE_DISPLAY_PM_OFF = 0, /* Power off */
+ MCDE_DISPLAY_PM_STANDBY = 1, /* DCS sleep mode */
+ MCDE_DISPLAY_PM_ON = 2, /* DCS normal mode, display on */
+};
+
+/* Display rotation */
+enum mcde_display_rotation {
+ MCDE_DISPLAY_ROT_0 = 0,
+ MCDE_DISPLAY_ROT_90_CCW = 90,
+ MCDE_DISPLAY_ROT_180_CCW = 180,
+ MCDE_DISPLAY_ROT_270_CCW = 270,
+ MCDE_DISPLAY_ROT_90_CW = MCDE_DISPLAY_ROT_270_CCW,
+ MCDE_DISPLAY_ROT_180_CW = MCDE_DISPLAY_ROT_180_CCW,
+ MCDE_DISPLAY_ROT_270_CW = MCDE_DISPLAY_ROT_90_CCW,
+};
+
+/* REVIEW: Verify */
+#define MCDE_MIN_WIDTH 16
+#define MCDE_MIN_HEIGHT 16
+#define MCDE_MAX_WIDTH 2048
+#define MCDE_MAX_HEIGHT 2048
+#define MCDE_BUF_START_ALIGMENT 8
+#define MCDE_BUF_LINE_ALIGMENT 8
+
+#define MCDE_FIFO_AB_SIZE 640
+#define MCDE_FIFO_C0C1_SIZE 160
+
+#define MCDE_PIXFETCH_LARGE_WTRMRKLVL 128
+#define MCDE_PIXFETCH_MEDIUM_WTRMRKLVL 64
+#define MCDE_PIXFETCH_SMALL_WTRMRKLVL 16
+
+/* Tv-out defines */
+#define MCDE_CONFIG_TVOUT_HBORDER 2
+#define MCDE_CONFIG_TVOUT_VBORDER 2
+#define MCDE_CONFIG_TVOUT_BACKGROUND_LUMINANCE 0x83
+#define MCDE_CONFIG_TVOUT_BACKGROUND_CHROMINANCE_CB 0x9C
+#define MCDE_CONFIG_TVOUT_BACKGROUND_CHROMINANCE_CR 0x2C
+
+/* In seconds */
+#define MCDE_AUTO_SYNC_WATCHDOG 5
+
+/* Hardware versions */
+#define MCDE_CHIP_VERSION_3_0_8 2
+#define MCDE_CHIP_VERSION_3_0_5 1
+#define MCDE_CHIP_VERSION_3 0
+
+/* DSI modes */
+#define DSI_VIDEO_MODE 0
+#define DSI_CMD_MODE 1
+
+/* Video mode descriptor */
+struct mcde_video_mode {/* REVIEW: Join 1 & 2 */
+ u32 xres;
+ u32 yres;
+ u32 pixclock; /* pixel clock in ps (pico seconds) */
+ u32 hbp; /* hor back porch = left_margin */
+ u32 hfp; /* hor front porch equals to right_margin */
+ u32 hsw; /* horizontal sync width */
+ u32 vbp1; /* field 1: vert back porch equals to upper_margin */
+ u32 vfp1; /* field 1: vert front porch equals to lower_margin */
+ u32 vbp2; /* field 2: vert back porch equals to upper_margin */
+ u32 vfp2; /* field 2: vert front porch equals to lower_margin */
+ u32 vsw; /* vertical sync width*/
+ bool interlaced;
+};
+
+struct mcde_rectangle {
+ u16 x;
+ u16 y;
+ u16 w;
+ u16 h;
+};
+
+struct mcde_overlay_info {
+ u32 paddr;
+ u16 stride; /* buffer line len in bytes */
+ enum mcde_ovly_pix_fmt fmt;
+
+ u16 src_x;
+ u16 src_y;
+ u16 dst_x;
+ u16 dst_y;
+ u16 dst_z;
+ u16 w;
+ u16 h;
+ struct mcde_rectangle dirty;
+};
+
+struct mcde_overlay {
+ struct kobject kobj;
+ struct list_head list; /* mcde_display_device.ovlys */
+
+ struct mcde_display_device *ddev;
+ struct mcde_overlay_info info;
+ struct mcde_ovly_state *state;
+};
+
+struct mcde_chnl_state;
+
+struct mcde_chnl_state *mcde_chnl_get(enum mcde_chnl chnl_id,
+ enum mcde_fifo fifo, const struct mcde_port *port);
+int mcde_chnl_set_pixel_format(struct mcde_chnl_state *chnl,
+ enum mcde_port_pix_fmt pix_fmt);
+void mcde_chnl_set_col_convert(struct mcde_chnl_state *chnl,
+ struct mcde_col_convert *col_convert);
+int mcde_chnl_set_video_mode(struct mcde_chnl_state *chnl,
+ struct mcde_video_mode *vmode);
+/* TODO: Remove rotbuf* parameters when ESRAM allocator is implemented*/
+int mcde_chnl_set_rotation(struct mcde_chnl_state *chnl,
+ enum mcde_display_rotation rotation, u32 rotbuf1, u32 rotbuf2);
+int mcde_chnl_enable_synchronized_update(struct mcde_chnl_state *chnl,
+ bool enable);
+int mcde_chnl_set_power_mode(struct mcde_chnl_state *chnl,
+ enum mcde_display_power_mode power_mode);
+
+int mcde_chnl_apply(struct mcde_chnl_state *chnl);
+int mcde_chnl_update(struct mcde_chnl_state *chnl,
+ struct mcde_rectangle *update_area);
+void mcde_chnl_put(struct mcde_chnl_state *chnl);
+
+void mcde_chnl_stop_flow(struct mcde_chnl_state *chnl);
+
+/* MCDE overlay */
+struct mcde_ovly_state;
+
+struct mcde_ovly_state *mcde_ovly_get(struct mcde_chnl_state *chnl);
+void mcde_ovly_set_source_buf(struct mcde_ovly_state *ovly,
+ u32 paddr);
+void mcde_ovly_set_source_info(struct mcde_ovly_state *ovly,
+ u32 stride, enum mcde_ovly_pix_fmt pix_fmt);
+void mcde_ovly_set_source_area(struct mcde_ovly_state *ovly,
+ u16 x, u16 y, u16 w, u16 h);
+void mcde_ovly_set_dest_pos(struct mcde_ovly_state *ovly,
+ u16 x, u16 y, u8 z);
+void mcde_ovly_apply(struct mcde_ovly_state *ovly);
+void mcde_ovly_put(struct mcde_ovly_state *ovly);
+
+/* MCDE dsi */
+
+#define DCS_CMD_ENTER_IDLE_MODE 0x39
+#define DCS_CMD_ENTER_INVERT_MODE 0x21
+#define DCS_CMD_ENTER_NORMAL_MODE 0x13
+#define DCS_CMD_ENTER_PARTIAL_MODE 0x12
+#define DCS_CMD_ENTER_SLEEP_MODE 0x10
+#define DCS_CMD_EXIT_IDLE_MODE 0x38
+#define DCS_CMD_EXIT_INVERT_MODE 0x20
+#define DCS_CMD_EXIT_SLEEP_MODE 0x11
+#define DCS_CMD_GET_ADDRESS_MODE 0x0B
+#define DCS_CMD_GET_BLUE_CHANNEL 0x08
+#define DCS_CMD_GET_DIAGNOSTIC_RESULT 0x0F
+#define DCS_CMD_GET_DISPLAY_MODE 0x0D
+#define DCS_CMD_GET_GREEN_CHANNEL 0x07
+#define DCS_CMD_GET_PIXEL_FORMAT 0x0C
+#define DCS_CMD_GET_POWER_MODE 0x0A
+#define DCS_CMD_GET_RED_CHANNEL 0x06
+#define DCS_CMD_GET_SCANLINE 0x45
+#define DCS_CMD_GET_SIGNAL_MODE 0x0E
+#define DCS_CMD_NOP 0x00
+#define DCS_CMD_READ_DDB_CONTINUE 0xA8
+#define DCS_CMD_READ_DDB_START 0xA1
+#define DCS_CMD_READ_MEMORY_CONTINE 0x3E
+#define DCS_CMD_READ_MEMORY_START 0x2E
+#define DCS_CMD_SET_ADDRESS_MODE 0x36
+#define DCS_CMD_SET_COLUMN_ADDRESS 0x2A
+#define DCS_CMD_SET_DISPLAY_OFF 0x28
+#define DCS_CMD_SET_DISPLAY_ON 0x29
+#define DCS_CMD_SET_GAMMA_CURVE 0x26
+#define DCS_CMD_SET_PAGE_ADDRESS 0x2B
+#define DCS_CMD_SET_PARTIAL_AREA 0x30
+#define DCS_CMD_SET_PIXEL_FORMAT 0x3A
+#define DCS_CMD_SET_SCROLL_AREA 0x33
+#define DCS_CMD_SET_SCROLL_START 0x37
+#define DCS_CMD_SET_TEAR_OFF 0x34
+#define DCS_CMD_SET_TEAR_ON 0x35
+#define DCS_CMD_SET_TEAR_SCANLINE 0x44
+#define DCS_CMD_SOFT_RESET 0x01
+#define DCS_CMD_WRITE_LUT 0x2D
+#define DCS_CMD_WRITE_CONTINUE 0x3C
+#define DCS_CMD_WRITE_START 0x2C
+
+#define MCDE_MAX_DCS_READ 4
+#define MCDE_MAX_DCS_WRITE 15
+
+int mcde_dsi_dcs_write(struct mcde_chnl_state *chnl, u8 cmd, u8* data, int len);
+int mcde_dsi_dcs_read(struct mcde_chnl_state *chnl, u8 cmd, u8* data, int *len);
+
+/* MCDE */
+
+/* Driver data */
+#define MCDE_IRQ "MCDE IRQ"
+#define MCDE_IO_AREA "MCDE I/O Area"
+
+struct mcde_platform_data {
+ /* DSI */
+ int num_dsilinks;
+
+ /* DPI */
+ u8 outmux[5]; /* MCDE_CONF0.OUTMUXx */
+ u8 syncmux; /* MCDE_CONF0.SYNCMUXx */
+
+ const char *regulator_id;
+ const char *clock_dsi_id;
+ const char *clock_dsi_lp_id;
+ const char *clock_dpi_id;
+ const char *clock_mcde_id;
+};
+
+int mcde_init(void);
+void mcde_exit(void);
+
+#endif /* __MCDE__H__ */
+
diff --git a/include/video/mcde_display-ab8500.h b/include/video/mcde_display-ab8500.h
new file mode 100644
index 00000000000..adab52787bb
--- /dev/null
+++ b/include/video/mcde_display-ab8500.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * AB8500 tvout driver interface
+ *
+ * Author: Marcel Tunnissen <marcel.tuennissen@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __DISPLAY_AB8500__H__
+#define __DISPLAY_AB8500__H__
+
+#include <video/mcde.h>
+
+struct ab8500_display_platform_data {
+ /* Platform info */
+ const char *regulator_id;
+ struct mcde_col_convert rgb_2_yCbCr_convert;
+ /* Driver data */ /* TODO: move to driver data instead */
+ struct regulator *regulator;
+};
+
+#endif /* __DISPLAY_AB8500__H__*/
+
diff --git a/include/video/mcde_display-av8100.h b/include/video/mcde_display-av8100.h
new file mode 100644
index 00000000000..e93b3961a6d
--- /dev/null
+++ b/include/video/mcde_display-av8100.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson MCDE HDMI display driver
+ *
+ * Author: Per Persson <per-xb-persson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __DISPLAY_AV8100__H__
+#define __DISPLAY_AV8100__H__
+
+#include <linux/regulator/consumer.h>
+
+#include "mcde_display.h"
+
+#define GPIO_AV8100_RSTN 196
+
+struct mcde_display_hdmi_platform_data {
+ /* Platform info */
+ int reset_gpio;
+ bool reset_high;
+ const char *regulator_id;
+ int reset_delay; /* ms */
+ u32 ddb_id;
+ struct mcde_col_convert rgb_2_yCbCr_convert;
+
+ /* Driver data */ /* TODO: move to driver data instead */
+ bool hdmi_platform_enable;
+ struct regulator *regulator;
+};
+
+#endif /* __DISPLAY_AV8100__H__ */
diff --git a/include/video/mcde_display-generic_dsi.h b/include/video/mcde_display-generic_dsi.h
new file mode 100644
index 00000000000..48790617090
--- /dev/null
+++ b/include/video/mcde_display-generic_dsi.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson MCDE generic DCS display driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __MCDE_DISPLAY_GENERIC__H__
+#define __MCDE_DISPLAY_GENERIC__H__
+
+#include <linux/regulator/consumer.h>
+
+#include "mcde_display.h"
+
+struct mcde_display_generic_platform_data {
+ /* Platform info */
+ int reset_gpio;
+ bool reset_high;
+ const char *regulator_id;
+ int reset_delay; /* ms */
+ u32 ddb_id;
+
+ /* Driver data */
+ bool generic_platform_enable;
+ struct regulator *regulator;
+ int max_supply_voltage;
+ int min_supply_voltage;
+};
+
+#endif /* __MCDE_DISPLAY_GENERIC__H__ */
+
diff --git a/include/video/mcde_display-sony_sy35560_dsi.h b/include/video/mcde_display-sony_sy35560_dsi.h
new file mode 100644
index 00000000000..997a7ed1f85
--- /dev/null
+++ b/include/video/mcde_display-sony_sy35560_dsi.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson MCDE Sony sy35560 DCS display driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __MCDE_DISPLAY_SONY_SY35560__H__
+#define __MCDE_DISPLAY_SONY_SY35560__H__
+
+#include <linux/regulator/consumer.h>
+
+#include "mcde_display.h"
+#include <linux/workqueue.h>
+
+/* period between ESD status checks */
+#define SONY_SY35560_ESD_CHECK_PERIOD msecs_to_jiffies(10000)
+
+struct sony_sy35560_platform_data {
+ /* Platform info */
+ int reset_gpio;
+ bool reset_high;
+ const char *regulator_id;
+ bool skip_init;
+
+ /* Driver data */
+ int max_supply_voltage;
+ int min_supply_voltage;
+};
+
+struct sony_sy35560_device {
+ struct mcde_display_device base;
+
+ struct regulator *regulator;
+
+ /* ESD workqueue */
+ struct workqueue_struct *esd_wq;
+ struct delayed_work esd_work;
+};
+
+#endif /* __MCDE_DISPLAY_SONY_SY35560__H__ */
+
diff --git a/include/video/mcde_display-vuib500-dpi.h b/include/video/mcde_display-vuib500-dpi.h
new file mode 100644
index 00000000000..94bad83bf97
--- /dev/null
+++ b/include/video/mcde_display-vuib500-dpi.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson MCDE DPI display driver
+ *
+ * Author: Torbjorn Svensson <torbjorn.x.svensson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __MCDE_DISPLAY_DPI__H__
+#define __MCDE_DISPLAY_DPI__H__
+
+#include <linux/regulator/consumer.h>
+
+#include "mcde_display.h"
+
+struct mcde_display_dpi_platform_data {
+ /* Platform info */
+ int reset_gpio;
+ bool reset_high;
+ const char *regulator_id;
+ int reset_delay;
+
+ /* Driver data */
+ struct regulator *regulator;
+ int max_supply_voltage;
+ int min_supply_voltage;
+};
+#endif /* __MCDE_DISPLAY_DPI__H__ */
diff --git a/include/video/mcde_display.h b/include/video/mcde_display.h
new file mode 100644
index 00000000000..aa184cb6162
--- /dev/null
+++ b/include/video/mcde_display.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * ST-Ericsson MCDE display driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __MCDE_DISPLAY__H__
+#define __MCDE_DISPLAY__H__
+
+#include <linux/device.h>
+#include <linux/pm.h>
+
+#include <video/mcde.h>
+
+#define UPDATE_FLAG_PIXEL_FORMAT 0x1
+#define UPDATE_FLAG_VIDEO_MODE 0x2
+#define UPDATE_FLAG_ROTATION 0x4
+
+#define to_mcde_display_device(__dev) \
+ container_of((__dev), struct mcde_display_device, dev)
+
+struct mcde_display_device {
+ /* MCDE driver static */
+ struct device dev;
+ const char *name;
+ int id;
+ struct mcde_port *port;
+
+ /* MCDE dss driver internal */
+ bool initialized;
+ enum mcde_chnl chnl_id;
+ enum mcde_fifo fifo;
+ bool first_update;
+
+ bool enabled;
+ struct mcde_chnl_state *chnl_state;
+ struct list_head ovlys;
+ struct mcde_rectangle update_area;
+ /* TODO: Remove once ESRAM allocator is done */
+ u32 rotbuf1;
+ u32 rotbuf2;
+
+ /* Display driver internal */
+ u16 native_x_res;
+ u16 native_y_res;
+ u16 physical_width;
+ u16 physical_height;
+ enum mcde_display_power_mode power_mode;
+ enum mcde_ovly_pix_fmt default_pixel_format;
+ enum mcde_ovly_pix_fmt pixel_format;
+ enum mcde_display_rotation rotation;
+ bool synchronized_update;
+ struct mcde_video_mode video_mode;
+ int update_flags;
+
+ /* Driver API */
+ void (*get_native_resolution)(struct mcde_display_device *dev,
+ u16 *x_res, u16 *y_res);
+ enum mcde_ovly_pix_fmt (*get_default_pixel_format)(
+ struct mcde_display_device *dev);
+ void (*get_physical_size)(struct mcde_display_device *dev,
+ u16 *x_size, u16 *y_size);
+
+ int (*set_power_mode)(struct mcde_display_device *dev,
+ enum mcde_display_power_mode power_mode);
+ enum mcde_display_power_mode (*get_power_mode)(
+ struct mcde_display_device *dev);
+
+ int (*try_video_mode)(struct mcde_display_device *dev,
+ struct mcde_video_mode *video_mode);
+ int (*set_video_mode)(struct mcde_display_device *dev,
+ struct mcde_video_mode *video_mode);
+ void (*get_video_mode)(struct mcde_display_device *dev,
+ struct mcde_video_mode *video_mode);
+
+ int (*set_pixel_format)(struct mcde_display_device *dev,
+ enum mcde_ovly_pix_fmt pix_fmt);
+ enum mcde_ovly_pix_fmt (*get_pixel_format)(
+ struct mcde_display_device *dev);
+ enum mcde_port_pix_fmt (*get_port_pixel_format)(
+ struct mcde_display_device *dev);
+
+ int (*set_rotation)(struct mcde_display_device *dev,
+ enum mcde_display_rotation rotation);
+ enum mcde_display_rotation (*get_rotation)(
+ struct mcde_display_device *dev);
+
+ int (*set_synchronized_update)(struct mcde_display_device *dev,
+ bool enable);
+ bool (*get_synchronized_update)(struct mcde_display_device *dev);
+
+ int (*apply_config)(struct mcde_display_device *dev);
+ int (*invalidate_area)(struct mcde_display_device *dev,
+ struct mcde_rectangle *area);
+ int (*update)(struct mcde_display_device *dev);
+ int (*prepare_for_update)(struct mcde_display_device *dev,
+ u16 x, u16 y, u16 w, u16 h);
+ int (*on_first_update)(struct mcde_display_device *dev);
+ int (*platform_enable)(struct mcde_display_device *dev);
+ int (*platform_disable)(struct mcde_display_device *dev);
+};
+
+struct mcde_display_driver {
+ int (*probe)(struct mcde_display_device *dev);
+ int (*remove)(struct mcde_display_device *dev);
+ void (*shutdown)(struct mcde_display_device *dev);
+ int (*suspend)(struct mcde_display_device *dev,
+ pm_message_t state);
+ int (*resume)(struct mcde_display_device *dev);
+
+ struct device_driver driver;
+};
+
+/* MCDE dsi (Used by MCDE display drivers) */
+
+int mcde_display_dsi_dcs_write(struct mcde_display_device *dev,
+ u8 cmd, u8 *data, int len);
+int mcde_display_dsi_dcs_read(struct mcde_display_device *dev,
+ u8 cmd, u8 *data, int *len);
+int mcde_display_dsi_bta_sync(struct mcde_display_device *dev);
+
+/* MCDE display bus */
+
+int mcde_display_driver_register(struct mcde_display_driver *drv);
+void mcde_display_driver_unregister(struct mcde_display_driver *drv);
+int mcde_display_device_register(struct mcde_display_device *dev);
+void mcde_display_device_unregister(struct mcde_display_device *dev);
+
+void mcde_display_init_device(struct mcde_display_device *dev);
+
+int mcde_display_init(void);
+void mcde_display_exit(void);
+
+#endif /* __MCDE_DISPLAY__H__ */
+
diff --git a/include/video/mcde_dss.h b/include/video/mcde_dss.h
new file mode 100644
index 00000000000..a32b2dfdeba
--- /dev/null
+++ b/include/video/mcde_dss.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * ST-Ericsson MCDE display sub system driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __MCDE_DSS__H__
+#define __MCDE_DSS__H__
+
+#include <linux/kobject.h>
+#include <linux/notifier.h>
+
+#include "mcde.h"
+#include "mcde_display.h"
+
+/* Public MCDE dss (Used by MCDE fb ioctl & MCDE display sysfs) */
+
+int mcde_dss_enable_display(struct mcde_display_device *ddev);
+void mcde_dss_disable_display(struct mcde_display_device *ddev);
+int mcde_dss_apply_channel(struct mcde_display_device *ddev);
+struct mcde_overlay *mcde_dss_create_overlay(struct mcde_display_device *ddev,
+ struct mcde_overlay_info *info);
+void mcde_dss_destroy_overlay(struct mcde_overlay *ovl);
+int mcde_dss_enable_overlay(struct mcde_overlay *ovl);
+void mcde_dss_disable_overlay(struct mcde_overlay *ovl);
+int mcde_dss_apply_overlay(struct mcde_overlay *ovl,
+ struct mcde_overlay_info *info);
+int mcde_dss_update_overlay(struct mcde_overlay *ovl);
+
+void mcde_dss_get_native_resolution(struct mcde_display_device *ddev,
+ u16 *x_res, u16 *y_res);
+enum mcde_ovl_pix_fmt mcde_dss_get_default_color_format(
+ struct mcde_display_device *ddev);
+void mcde_dss_get_physical_size(struct mcde_display_device *ddev,
+ u16 *x_size, u16 *y_size); /* mm */
+
+int mcde_dss_try_video_mode(struct mcde_display_device *ddev,
+ struct mcde_video_mode *video_mode);
+int mcde_dss_set_video_mode(struct mcde_display_device *ddev,
+ struct mcde_video_mode *video_mode);
+void mcde_dss_get_video_mode(struct mcde_display_device *ddev,
+ struct mcde_video_mode *video_mode);
+
+int mcde_dss_set_pixel_format(struct mcde_display_device *ddev,
+ enum mcde_ovly_pix_fmt pix_fmt);
+int mcde_dss_get_pixel_format(struct mcde_display_device *ddev);
+
+int mcde_dss_set_rotation(struct mcde_display_device *ddev,
+ enum mcde_display_rotation rotation);
+enum mcde_display_rotation mcde_dss_get_rotation(
+ struct mcde_display_device *ddev);
+
+int mcde_dss_set_synchronized_update(struct mcde_display_device *ddev,
+ bool enable);
+bool mcde_dss_get_synchronized_update(struct mcde_display_device *ddev);
+
+/* MCDE dss events */
+
+/* A display device and driver has been loaded, probed and bound */
+#define MCDE_DSS_EVENT_DISPLAY_REGISTERED 1
+/* A display device has been removed */
+#define MCDE_DSS_EVENT_DISPLAY_UNREGISTERED 2
+
+/* Note! Notifier callback will be called holding the dev sem */
+int mcde_dss_register_notifier(struct notifier_block *nb);
+int mcde_dss_unregister_notifier(struct notifier_block *nb);
+
+/* MCDE dss driver */
+
+int mcde_dss_init(void);
+void mcde_dss_exit(void);
+
+#endif /* __MCDE_DSS__H__ */
+
diff --git a/include/video/mcde_fb.h b/include/video/mcde_fb.h
new file mode 100644
index 00000000000..1ef1c7175e5
--- /dev/null
+++ b/include/video/mcde_fb.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ *
+ * ST-Ericsson MCDE display sub system frame buffer driver
+ *
+ * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+#ifndef __MCDE_FB__H__
+#define __MCDE_FB__H__
+
+#include <linux/fb.h>
+#include <linux/ioctl.h>
+#if !defined(__KERNEL__) && !defined(_KERNEL)
+#include <stdint.h>
+#else
+#include <linux/types.h>
+#include <linux/hwmem.h>
+#endif
+
+#ifdef __KERNEL__
+#include "mcde_dss.h"
+#endif
+
+#define MCDE_GET_BUFFER_NAME_IOC _IO('M', 1)
+
+#ifdef __KERNEL__
+#define to_mcde_fb(x) ((struct mcde_fb *)(x)->par)
+
+#define MCDE_FB_MAX_NUM_OVERLAYS 3
+
+struct mcde_fb {
+ int num_ovlys;
+ struct mcde_overlay *ovlys[MCDE_FB_MAX_NUM_OVERLAYS];
+ u32 pseudo_palette[17];
+ enum mcde_ovly_pix_fmt pix_fmt;
+ int id;
+ struct hwmem_alloc *alloc;
+ int alloc_name;
+};
+
+/* MCDE fbdev API */
+struct fb_info *mcde_fb_create(struct mcde_display_device *ddev,
+ uint16_t w, uint16_t h, uint16_t vw, uint16_t vh,
+ enum mcde_ovly_pix_fmt pix_fmt, uint32_t rotate);
+
+int mcde_fb_attach_overlay(struct fb_info *fb_info,
+ struct mcde_overlay *ovl);
+void mcde_fb_destroy(struct fb_info *fb_info);
+
+/* MCDE fb driver */
+int mcde_fb_init(void);
+void mcde_fb_exit(void);
+#endif
+
+#endif /* __MCDE_FB__H__ */
+
diff --git a/init/Kconfig b/init/Kconfig
index 7a4328c9591..632decd5a42 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1149,6 +1149,15 @@ config PROFILING
Say Y here to enable the extended profiling support mechanisms used
by profilers such as OProfile.
+config BOOTTIME
+ bool "Boot time measurments"
+ default n
+ help
+ Adds sysfs entries (boottime/) with start-up timing information.
+ If CONFIG_DEBUG_FS is enabled, detailed information about the
+ boot time, including system load during boot can be extraced.
+ This information can be visualised with help of the bootgraph script.
+
#
# Place an empty function call at each tracepoint site. Can be
# dynamically changed for a probe function.
diff --git a/init/Makefile b/init/Makefile
index 0bf677aa087..6b77be3855f 100644
--- a/init/Makefile
+++ b/init/Makefile
@@ -9,6 +9,7 @@ else
obj-$(CONFIG_BLK_DEV_INITRD) += initramfs.o
endif
obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o
+obj-$(CONFIG_BOOTTIME) += boottime.o
mounts-y := do_mounts.o
mounts-$(CONFIG_BLK_DEV_RAM) += do_mounts_rd.o
diff --git a/init/boottime.c b/init/boottime.c
new file mode 100644
index 00000000000..c6c1330854b
--- /dev/null
+++ b/init/boottime.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009-2010
+ *
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * boottime is a tool for collecting start-up timing
+ * information and can together with boot loader support
+ * display a total system start-up time.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/spinlock.h>
+#include <linux/boottime.h>
+#include <linux/kernel_stat.h>
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/slab.h>
+
+/*
+ * BOOTTIME_MAX_NAME_LEN is defined in arch/arm/include/asm/setup.h to 64.
+ * No crisis if they don't match.
+ */
+#ifndef BOOTTIME_MAX_NAME_LEN
+#define BOOTTIME_MAX_NAME_LEN 64
+#endif
+
+/*
+ * We have a few static entries, since it is good to have measure points
+ * before the system is up and running properly
+ */
+#define NUM_STATIC_BOOTTIME_ENTRIES 16
+
+struct boottime_list {
+ struct list_head list;
+ char name[BOOTTIME_MAX_NAME_LEN];
+ /* Time in us since power on, possible including boot loader. */
+ unsigned long time;
+ bool cpu_load;
+ struct cpu_usage_stat cpu_usage[NR_CPUS];
+};
+
+enum boottime_filter_type {
+ BOOTTIME_FILTER_OUT_ZERO,
+ BOOTTIME_FILTER_OUT_LESS_100,
+ BOOTTIME_FILTER_NOTHING,
+};
+
+enum boottime_symbolic_print {
+ BOOTTIME_SYMBOLIC_PRINT,
+ BOOTTIME_NORMAL_PRINT,
+};
+
+enum boottime_cpu_load {
+ BOOTTIME_CPU_LOAD,
+ BOOTTIME_NO_CPU_LOAD,
+};
+
+static LIST_HEAD(boottime_list);
+static __initdata DEFINE_SPINLOCK(boottime_list_lock);
+static __initdata struct boottime_timer boottime_timer;
+static __initdata int num_const_boottime_list;
+static struct boottime_list const_boottime_list[NUM_STATIC_BOOTTIME_ENTRIES];
+static unsigned long time_kernel_done;
+static unsigned long time_bootloader_done;
+static __initdata bool system_up;
+static bool boottime_done;
+
+int __attribute__((weak)) boottime_arch_startup(void)
+{
+ return 0;
+}
+
+int __attribute__((weak)) boottime_bootloader_idle(void)
+{
+ return 0;
+}
+
+static void __init boottime_mark_core(char *name,
+ unsigned long time,
+ enum boottime_symbolic_print symbolic,
+ enum boottime_cpu_load cpu_load)
+{
+ struct boottime_list *b;
+ unsigned long flags = 0;
+ int i;
+
+ if (system_up) {
+ b = kmalloc(sizeof(struct boottime_list), GFP_KERNEL);
+ if (!b) {
+ printk(KERN_ERR
+ "boottime: failed to allocate memory!\n");
+ return;
+ }
+
+ } else {
+ if (num_const_boottime_list < NUM_STATIC_BOOTTIME_ENTRIES) {
+ b = &const_boottime_list[num_const_boottime_list];
+ num_const_boottime_list++;
+ } else {
+ printk(KERN_ERR
+ "boottime: too many early measure points!\n");
+ return;
+ }
+ }
+
+ INIT_LIST_HEAD(&b->list);
+
+ if (symbolic == BOOTTIME_SYMBOLIC_PRINT)
+ snprintf(b->name, BOOTTIME_MAX_NAME_LEN, "%pF", name);
+ else
+ strncpy(b->name, name, BOOTTIME_MAX_NAME_LEN);
+
+ b->name[BOOTTIME_MAX_NAME_LEN - 1] = '\0';
+ b->time = time;
+ b->cpu_load = cpu_load;
+
+ if (cpu_load == BOOTTIME_CPU_LOAD && system_up)
+ for_each_possible_cpu(i) {
+ b->cpu_usage[i].system = kstat_cpu(i).cpustat.system;
+ b->cpu_usage[i].idle = kstat_cpu(i).cpustat.idle;
+ b->cpu_usage[i].iowait = kstat_cpu(i).cpustat.iowait;
+ b->cpu_usage[i].irq = kstat_cpu(i).cpustat.irq;
+ /*
+ * TODO: Make sure that user, nice, softirq, steal
+ * and guest are not used during boot
+ */
+ }
+ else
+ b->cpu_load = BOOTTIME_NO_CPU_LOAD;
+
+ if (system_up) {
+ spin_lock_irqsave(&boottime_list_lock, flags);
+ list_add(&b->list, &boottime_list);
+ spin_unlock_irqrestore(&boottime_list_lock, flags);
+ } else {
+ list_add(&b->list, &boottime_list);
+ }
+}
+
+void __init boottime_mark_wtime(char *name, unsigned long time)
+{
+ boottime_mark_core(name, time,
+ BOOTTIME_NORMAL_PRINT,
+ BOOTTIME_NO_CPU_LOAD);
+}
+
+void boottime_mark_symbolic(void *name)
+{
+
+ if (boottime_done)
+ return;
+
+ if (boottime_timer.get_time)
+ boottime_mark_core((char *) name,
+ boottime_timer.get_time(),
+ BOOTTIME_SYMBOLIC_PRINT,
+ BOOTTIME_CPU_LOAD);
+}
+
+void __init boottime_mark(char *name)
+{
+ if (boottime_timer.get_time)
+ boottime_mark_core(name,
+ boottime_timer.get_time(),
+ BOOTTIME_NORMAL_PRINT,
+ BOOTTIME_CPU_LOAD);
+}
+
+void __init boottime_activate(struct boottime_timer *bt)
+{
+ struct boottime_list *b;
+ int res = 0;
+ unsigned long flags;
+
+ if (bt == NULL) {
+ printk(KERN_ERR
+ "boottime: error: bad configured\n");
+ return;
+ }
+
+ if (bt->get_time == NULL) {
+ printk(KERN_ERR
+ "boottime: error: you must provide a get_time() function\n");
+ return;
+ }
+ memcpy(&boottime_timer, bt, sizeof(struct boottime_timer));
+
+ if (boottime_timer.init)
+ res = boottime_timer.init();
+
+ if (res) {
+ printk(KERN_ERR "boottime: initialization failed\n");
+ return;
+ }
+
+ if (boottime_arch_startup())
+ printk(KERN_ERR
+ "boottime: arch specfic initialization failed\n");
+
+ spin_lock_irqsave(&boottime_list_lock, flags);
+
+ if (!list_empty(&boottime_list)) {
+
+ b = list_first_entry(&boottime_list, struct boottime_list,
+ list);
+ if (b)
+ time_bootloader_done = b->time;
+ }
+
+ spin_unlock_irqrestore(&boottime_list_lock, flags);
+}
+
+void __init boottime_system_up(void)
+{
+ system_up = true;
+}
+
+void __init boottime_deactivate(void)
+{
+ struct boottime_list *b;
+ unsigned long flags;
+
+ boottime_mark("execute_init+0x0/0x0");
+
+ boottime_done = true;
+
+ spin_lock_irqsave(&boottime_list_lock, flags);
+ b = list_first_entry(&boottime_list, struct boottime_list, list);
+ spin_unlock_irqrestore(&boottime_list_lock, flags);
+
+ time_kernel_done = b->time;
+
+ if (boottime_timer.finalize)
+ boottime_timer.finalize();
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void boottime_debugfs_load(struct seq_file *s,
+ struct boottime_list *b,
+ struct boottime_list *p)
+{
+ int i;
+ unsigned long total_p, total_b;
+ unsigned long system_total, idle_total, irq_total, iowait_total;
+ unsigned long system_load, idle_load, irq_load, iowait_load;
+
+ for_each_possible_cpu(i) {
+ total_b = (b->cpu_usage[i].system +
+ b->cpu_usage[i].idle +
+ b->cpu_usage[i].iowait +
+ b->cpu_usage[i].irq);
+
+ total_p = (p->cpu_usage[i].system +
+ p->cpu_usage[i].idle +
+ p->cpu_usage[i].iowait +
+ p->cpu_usage[i].irq);
+
+ if (total_b == total_p)
+ continue;
+
+ system_total = b->cpu_usage[i].system - p->cpu_usage[i].system;
+ idle_total = b->cpu_usage[i].idle - p->cpu_usage[i].idle;
+ irq_total = b->cpu_usage[i].irq - p->cpu_usage[i].irq;
+ iowait_total = b->cpu_usage[i].iowait - p->cpu_usage[i].iowait;
+
+ system_load = (100 * system_total / (total_b - total_p));
+ idle_load = (100 * idle_total / (total_b - total_p));
+ irq_load = (100 * irq_total / (total_b - total_p));
+ iowait_load = (100 * iowait_total / (total_b - total_p));
+
+ seq_printf(s,
+ " cpu%d system: %lu%% idle: %lu%% iowait: %lu%% irq: %lu%%",
+ i,
+ system_load,
+ idle_load,
+ iowait_load,
+ irq_load);
+ }
+ seq_printf(s, "\n");
+}
+
+static void boottime_debugfs_print(struct seq_file *s,
+ struct boottime_list *b,
+ struct boottime_list *p)
+{
+ seq_printf(s, "[%5lu.%06lu] calling %s\n",
+ p->time / 1000000,
+ (p->time % 1000000),
+ p->name);
+ seq_printf(s, "[%5lu.%06lu] initcall %s returned 0 after %ld msecs.",
+ b->time / 1000000,
+ (b->time % 1000000),
+ p->name, (b->time - p->time) / 1000);
+
+ if (p->cpu_load == BOOTTIME_NO_CPU_LOAD ||
+ b->cpu_load == BOOTTIME_NO_CPU_LOAD) {
+ seq_printf(s, "\n");
+ return;
+ }
+
+ boottime_debugfs_load(s, b, p);
+}
+
+static int boottime_debugfs_bootgraph_show(struct seq_file *s, void *iter)
+{
+ struct boottime_list *b, *p = NULL, *old_p = NULL;
+ enum boottime_filter_type filter = (int)s->private;
+
+ list_for_each_entry_reverse(b, &boottime_list, list) {
+ if (p) {
+ if (!(filter == BOOTTIME_FILTER_OUT_ZERO &&
+ (b->time - p->time) / 1000 == 0)
+ && !(filter == BOOTTIME_FILTER_OUT_LESS_100 &&
+ (b->time - p->time) < 100 * 1000))
+ boottime_debugfs_print(s, b, p);
+ old_p = p;
+ }
+ p = b;
+ }
+
+ if (filter == BOOTTIME_FILTER_NOTHING && p)
+ boottime_debugfs_print(s, p, p);
+
+ if (p)
+ seq_printf(s, "[%5lu.%06lu] Freeing init memory: 0K\n",
+ p->time / 1000000, p->time % 1000000);
+ return 0;
+}
+
+static int boottime_debugfs_summary_show(struct seq_file *s, void *data)
+{
+ struct boottime_list *b, b_zero;
+
+ if (time_bootloader_done)
+ seq_printf(s, "bootloader: %ld msecs\n",
+ time_bootloader_done / 1000);
+
+ seq_printf(s, "kernel: %ld msecs\ntotal: %ld msecs\n",
+ (time_kernel_done - time_bootloader_done) / 1000,
+ time_kernel_done / 1000);
+ seq_printf(s, "kernel:");
+ b = list_first_entry(&boottime_list,
+ struct boottime_list, list);
+ memset(&b_zero, 0, sizeof(struct boottime_list));
+ boottime_debugfs_load(s, b, &b_zero);
+
+ if (time_bootloader_done)
+ seq_printf(s,
+ "bootloader: cpu0 system: %d%% idle: %d%% iowait: 0%% irq: 0%%\n",
+ 100 - boottime_bootloader_idle(),
+ boottime_bootloader_idle());
+ return 0;
+}
+
+static int boottime_debugfs_bootgraph_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file,
+ boottime_debugfs_bootgraph_show,
+ inode->i_private);
+}
+
+static int boottime_debugfs_summary_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file,
+ boottime_debugfs_summary_show,
+ inode->i_private);
+}
+
+static const struct file_operations boottime_debugfs_bootgraph_operations = {
+ .open = boottime_debugfs_bootgraph_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations boottime_debugfs_summary_operations = {
+ .open = boottime_debugfs_summary_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void boottime_debugfs_init(void)
+{
+ struct dentry *dir;
+
+ dir = debugfs_create_dir("boottime", NULL);
+
+ (void) debugfs_create_file("bootgraph", S_IFREG | S_IRUGO,
+ dir, (void *)BOOTTIME_FILTER_NOTHING,
+ &boottime_debugfs_bootgraph_operations);
+ (void) debugfs_create_file("bootgraph_all_except0", S_IFREG | S_IRUGO,
+ dir, (void *)BOOTTIME_FILTER_OUT_ZERO,
+ &boottime_debugfs_bootgraph_operations);
+ (void) debugfs_create_file("bootgraph_larger100",
+ S_IFREG | S_IRUGO,
+ dir, (void *)BOOTTIME_FILTER_OUT_LESS_100,
+ &boottime_debugfs_bootgraph_operations);
+ (void) debugfs_create_file("summary", S_IFREG | S_IRUGO,
+ dir, NULL,
+ &boottime_debugfs_summary_operations);
+}
+#else
+#define boottime_debugfs_init(x)
+#endif
+
+static ssize_t show_bootloader(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%ld\n", time_bootloader_done / 1000);
+}
+
+static ssize_t show_kernel(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%ld\n",
+ (time_kernel_done - time_bootloader_done) / 1000);
+}
+
+DEVICE_ATTR(kernel, 0444, show_kernel, NULL);
+DEVICE_ATTR(bootloader, 0444, show_bootloader, NULL);
+
+static struct attribute *boottime_sysfs_entries[] = {
+ &dev_attr_kernel.attr,
+ &dev_attr_bootloader.attr,
+ NULL
+};
+
+static struct attribute_group boottime_attr_grp = {
+ .name = NULL,
+ .attrs = boottime_sysfs_entries,
+};
+
+static int __init boottime_init(void)
+{
+ struct kobject *boottime_kobj;
+
+ boottime_kobj = kobject_create_and_add("boottime", NULL);
+ if (!boottime_kobj) {
+ printk(KERN_ERR "boottime: out of memory!\n");
+ return -ENOMEM;
+ }
+
+ if (sysfs_create_group(boottime_kobj, &boottime_attr_grp) < 0) {
+ kobject_put(boottime_kobj);
+ printk(KERN_ERR "boottime: Failed creating sysfs group\n");
+ return -ENOMEM;
+ }
+
+ boottime_debugfs_init();
+
+ return 0;
+}
+
+late_initcall(boottime_init);
diff --git a/init/main.c b/init/main.c
index a42fdf4aeba..7014eba711c 100644
--- a/init/main.c
+++ b/init/main.c
@@ -70,6 +70,7 @@
#include <linux/sfi.h>
#include <linux/shmem_fs.h>
#include <linux/slab.h>
+#include <linux/boottime.h>
#include <trace/boot.h>
#include <asm/io.h>
@@ -741,6 +742,8 @@ int do_one_initcall(initcall_t fn)
enable_boot_trace();
}
+ boottime_mark_symbolic(fn);
+
ret.result = fn();
if (initcall_debug) {
@@ -828,6 +831,7 @@ static noinline int init_post(void)
{
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
+ boottime_deactivate();
free_initmem();
unlock_kernel();
mark_rodata_ro();
@@ -895,6 +899,7 @@ static int __init kernel_init(void * unused)
do_pre_smp_initcalls();
start_boot_trace();
+ boottime_system_up();
smp_init();
sched_init_smp();
@@ -917,6 +922,7 @@ static int __init kernel_init(void * unused)
if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
ramdisk_execute_command = NULL;
+ boottime_mark("mount+0x0/0x0");
prepare_namespace();
}
diff --git a/kernel/printk.c b/kernel/printk.c
index 0e218d9f28c..d92bab447fe 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -55,7 +55,7 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
-#ifdef CONFIG_DEBUG_LL
+#ifdef CONFIG_PRINTK_LL
extern void printascii(char *);
#endif
@@ -800,7 +800,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
printed_len += vscnprintf(printk_buf + printed_len,
sizeof(printk_buf) - printed_len, fmt, args);
-#ifdef CONFIG_DEBUG_LL
+#ifdef CONFIG_PRINTK_LL
printascii(printk_buf);
#endif
diff --git a/kernel/time.c b/kernel/time.c
index 848b1c2ab09..d6ffa17b22c 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -724,3 +724,5 @@ struct timespec timespec_add_safe(const struct timespec lhs,
return res;
}
+EXPORT_SYMBOL(timespec_add_safe);
+
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 1c8c30d52b5..6d681727c0d 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -234,6 +234,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type,
conn->mode = HCI_CM_ACTIVE;
conn->state = BT_OPEN;
conn->auth_type = HCI_AT_GENERAL_BONDING;
+ conn->key_type = 0xff;
+ conn->pin_len = 0;
conn->power_save = 1;
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
@@ -444,15 +446,11 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
EXPORT_SYMBOL(hci_conn_check_link_mode);
/* Authenticate remote device */
-static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
+static void hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
{
BT_DBG("conn %p", conn);
- if (sec_level > conn->sec_level)
- conn->sec_level = sec_level;
- else if (conn->link_mode & HCI_LM_AUTH)
- return 1;
-
+ conn->sec_level = sec_level;
conn->auth_type = auth_type;
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
@@ -461,8 +459,20 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
sizeof(cp), &cp);
}
+}
- return 0;
+/* Encrypt the the link */
+static void hci_conn_encrypt(struct hci_conn *conn)
+{
+ BT_DBG("conn %p", conn);
+
+ if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+ struct hci_cp_set_conn_encrypt cp;
+ cp.handle = cpu_to_le16(conn->handle);
+ cp.encrypt = 1;
+ hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
+ sizeof(cp), &cp);
+ }
}
/* Enable security */
@@ -470,28 +480,54 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
{
BT_DBG("conn %p", conn);
+ /* For sdp we do not need the link key. */
if (sec_level == BT_SECURITY_SDP)
return 1;
+ /* For non 2.1 devices and low security level we do not need the
+ link key. */
if (sec_level == BT_SECURITY_LOW &&
(!conn->ssp_mode || !conn->hdev->ssp_mode))
return 1;
- if (conn->link_mode & HCI_LM_ENCRYPT)
- return hci_conn_auth(conn, sec_level, auth_type);
-
+ /* For other security levels we need link key. */
+ if (!(conn->link_mode & HCI_LM_AUTH))
+ goto do_auth;
+
+ /* An authenticated combination key has sufficient security for any
+ security level. */
+ if (conn->key_type == HCI_LK_AUTHENTICATED_COMBINATION)
+ goto do_encrypt;
+
+ /* An unauthenticated combination key has sufficient security for
+ security level 1 and 2. */
+ if (conn->key_type == HCI_LK_UNAUTHENTICATED_COMBINATION
+ && (sec_level == BT_SECURITY_MEDIUM
+ || sec_level == BT_SECURITY_LOW))
+ goto do_encrypt;
+
+ /* A combination key has always sufficient security for the security
+ levels 1 or 2. High security level requires that the combination key
+ was generated using the maximum PIN code length (16).
+ For pre 2.1 units. */
+ if ((conn->key_type == HCI_LK_COMBINATION))
+ if ((sec_level != BT_SECURITY_HIGH) || (conn->pin_len >= 16))
+ goto do_encrypt;
+
+do_auth:
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
return 0;
- if (hci_conn_auth(conn, sec_level, auth_type)) {
- struct hci_cp_set_conn_encrypt cp;
- cp.handle = cpu_to_le16(conn->handle);
- cp.encrypt = 1;
- hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
- sizeof(cp), &cp);
- }
-
+ hci_conn_auth(conn, sec_level, auth_type);
return 0;
+
+do_encrypt:
+ if (conn->link_mode & HCI_LM_ENCRYPT)
+ return 1; /* sufficient link key */
+ else{
+ hci_conn_encrypt(conn);
+ return 0; /* auth pending */
+ }
}
EXPORT_SYMBOL(hci_conn_security);
@@ -742,6 +778,30 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
}
+int hci_set_conn_info(struct hci_dev *hdev, void __user *arg)
+{
+ struct hci_set_conn_info_req req;
+ struct hci_conn *conn;
+
+ if (copy_from_user(&req, arg, sizeof(req))) {
+ BT_DBG("copy from user failed");
+ return -EFAULT;
+ }
+
+ hci_dev_lock_bh(hdev);
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
+ if (conn) {
+ conn->pin_len = req.pin_len;
+ conn->key_type = req.key_type;
+ }
+ hci_dev_unlock_bh(hdev);
+
+ if (!conn)
+ return -ENOENT;
+
+ return 0;
+}
+
int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
{
struct hci_auth_info_req req;
@@ -754,6 +814,7 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
if (conn)
req.type = conn->auth_type;
+ req.level = conn->sec_level;
hci_dev_unlock_bh(hdev);
if (!conn)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index e5e55bc89f7..b53e24d7412 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1523,6 +1523,10 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (conn) {
hci_conn_hold(conn);
+ /* For Changed Combination Link Key the only link key has
+ * been changed, not link key type. */
+ if (conn->key_type != HCI_LK_CHANGEED_COMBINATION_KEY)
+ conn->key_type = ev->key_type;
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
hci_conn_put(conn);
}
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 38f08f6b86f..063eaafeb3d 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -191,6 +191,9 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
case HCIGETCONNINFO:
return hci_get_conn_info(hdev, (void __user *) arg);
+ case HCISETCONNINFO:
+ return hci_set_conn_info(hdev, (void __user *) arg);
+
case HCIGETAUTHINFO:
return hci_get_auth_info(hdev, (void __user *) arg);
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index ecda6d52d4d..b000f5e2a74 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -2031,7 +2031,15 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
continue;
if (!status)
- set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
+ if (d->sec_level != BT_SECURITY_HIGH)
+ set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
+ else
+ if ((conn->key_type == HCI_LK_AUTHENTICATED_COMBINATION)
+ || (conn->key_type == HCI_LK_COMBINATION
+ && conn->pin_len >= 16))
+ set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
+ else
+ set_bit(RFCOMM_AUTH_REJECT, &d->flags);
else
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
}
diff --git a/net/caif/Kconfig b/net/caif/Kconfig
index ed651786f16..529750da962 100644
--- a/net/caif/Kconfig
+++ b/net/caif/Kconfig
@@ -21,19 +21,18 @@ menuconfig CAIF
See Documentation/networking/caif for a further explanation on how to
use and configure CAIF.
-if CAIF
-
config CAIF_DEBUG
bool "Enable Debug"
+ depends on CAIF
default n
--- help ---
Enable the inclusion of debug code in the CAIF stack.
Be aware that doing this will impact performance.
If unsure say N.
-
config CAIF_NETDEV
tristate "CAIF GPRS Network device"
+ depends on CAIF
default CAIF
---help---
Say Y if you will be using a CAIF based GPRS network device.
@@ -41,5 +40,3 @@ config CAIF_NETDEV
If you select to build it as a built-in then the main CAIF device must
also be a built-in.
If unsure say Y.
-
-endif
diff --git a/net/caif/Makefile b/net/caif/Makefile
index 34852af2595..f87481fb0e6 100644
--- a/net/caif/Makefile
+++ b/net/caif/Makefile
@@ -1,23 +1,13 @@
-ifeq ($(CONFIG_CAIF_DEBUG),1)
-CAIF_DBG_FLAGS := -DDEBUG
+ifeq ($(CONFIG_CAIF_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
endif
-ccflags-y := $(CAIF_FLAGS) $(CAIF_DBG_FLAGS)
-
caif-objs := caif_dev.o \
cfcnfg.o cfmuxl.o cfctrl.o \
cffrml.o cfveil.o cfdbgl.o\
cfserl.o cfdgml.o \
cfrfml.o cfvidl.o cfutill.o \
cfsrvl.o cfpkt_skbuff.o caif_config_util.o
-clean-dirs:= .tmp_versions
-
-clean-files:= \
- Module.symvers \
- modules.order \
- *.cmd \
- *.o \
- *~
obj-$(CONFIG_CAIF) += caif.o
obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o
diff --git a/net/caif/caif_config_util.c b/net/caif/caif_config_util.c
index 6f36580366f..76ae68303d3 100644
--- a/net/caif/caif_config_util.c
+++ b/net/caif/caif_config_util.c
@@ -80,6 +80,11 @@ int connect_req_to_link_param(struct cfcnfg *cnfg,
l->u.utility.paramlen);
break;
+ case CAIFPROTO_DEBUG:
+ l->linktype = CFCTRL_SRV_DBG;
+ l->endpoint = s->sockaddr.u.dbg.service;
+ l->chtype = s->sockaddr.u.dbg.type;
+ break;
default:
return -EINVAL;
}
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
index e2b86f1f5a4..584aa555ee4 100644
--- a/net/caif/caif_dev.c
+++ b/net/caif/caif_dev.c
@@ -9,6 +9,8 @@
* and Sakari Ailus <sakari.ailus@nokia.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -171,7 +173,7 @@ static int receive(struct sk_buff *skb, struct net_device *dev,
net = dev_net(dev);
pkt = cfpkt_fromnative(CAIF_DIR_IN, skb);
caifd = caif_get(dev);
- if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd)
+ if (!caifd || !caifd->layer.up || !caifd->layer.up->receive)
return NET_RX_DROP;
if (caifd->layer.up->receive(caifd->layer.up, pkt))
@@ -214,7 +216,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
switch (what) {
case NETDEV_REGISTER:
- pr_info("CAIF: %s():register %s\n", __func__, dev->name);
+ pr_info("register %s\n", dev->name);
caifd = caif_device_alloc(dev);
if (caifd == NULL)
break;
@@ -225,14 +227,13 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
break;
case NETDEV_UP:
- pr_info("CAIF: %s(): up %s\n", __func__, dev->name);
+ pr_info("up %s\n", dev->name);
caifd = caif_get(dev);
if (caifd == NULL)
break;
caifdev = netdev_priv(dev);
if (atomic_read(&caifd->state) == NETDEV_UP) {
- pr_info("CAIF: %s():%s already up\n",
- __func__, dev->name);
+ pr_info("%s already up\n", dev->name);
break;
}
atomic_set(&caifd->state, what);
@@ -255,7 +256,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
pref = CFPHYPREF_HIGH_BW;
break;
}
-
+ dev_hold(dev);
cfcnfg_add_phy_layer(get_caif_conf(),
phy_type,
dev,
@@ -273,7 +274,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
caifd = caif_get(dev);
if (caifd == NULL)
break;
- pr_info("CAIF: %s():going down %s\n", __func__, dev->name);
+ pr_info("going down %s\n", dev->name);
if (atomic_read(&caifd->state) == NETDEV_GOING_DOWN ||
atomic_read(&caifd->state) == NETDEV_DOWN)
@@ -285,6 +286,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
caifd->layer.up->ctrlcmd(caifd->layer.up,
_CAIF_CTRLCMD_PHYIF_DOWN_IND,
caifd->layer.id);
+ might_sleep();
res = wait_event_interruptible_timeout(caifd->event,
atomic_read(&caifd->in_use) == 0,
TIMEOUT);
@@ -294,18 +296,18 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
caifd = caif_get(dev);
if (caifd == NULL)
break;
- pr_info("CAIF: %s(): down %s\n", __func__, dev->name);
+ pr_info("down %s\n", dev->name);
if (atomic_read(&caifd->in_use))
- pr_warning("CAIF: %s(): "
- "Unregistering an active CAIF device: %s\n",
- __func__, dev->name);
+ pr_warn("Unregistering an active CAIF device: %s\n",
+ dev->name);
cfcnfg_del_phy_layer(get_caif_conf(), &caifd->layer);
+ dev_put(dev);
atomic_set(&caifd->state, what);
break;
case NETDEV_UNREGISTER:
caifd = caif_get(dev);
- pr_info("CAIF: %s(): unregister %s\n", __func__, dev->name);
+ pr_info("unregister %s\n", dev->name);
atomic_set(&caifd->state, what);
caif_device_destroy(dev);
break;
@@ -326,7 +328,8 @@ struct cfcnfg *get_caif_conf(void)
EXPORT_SYMBOL(get_caif_conf);
int caif_connect_client(struct caif_connect_request *conn_req,
- struct cflayer *client_layer)
+ struct cflayer *client_layer, int *ifindex,
+ int *headroom, int *tailroom)
{
struct cfctrl_link_param param;
int ret;
@@ -334,8 +337,9 @@ int caif_connect_client(struct caif_connect_request *conn_req,
if (ret)
return ret;
/* Hook up the adaptation layer. */
- return cfcnfg_add_adaptation_layer(get_caif_conf(),
- &param, client_layer);
+ return cfcnfg_add_adaptation_layer(get_caif_conf(), &param,
+ client_layer, ifindex,
+ headroom, tailroom);
}
EXPORT_SYMBOL(caif_connect_client);
@@ -387,7 +391,7 @@ static int __init caif_device_init(void)
int result;
cfg = cfcnfg_create();
if (!cfg) {
- pr_warning("CAIF: %s(): can't create cfcnfg.\n", __func__);
+ pr_warn("can't create cfcnfg\n");
goto err_cfcnfg_create_failed;
}
result = register_pernet_device(&caif_net_ops);
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 3d0e09584fa..2eca2dd0000 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -15,7 +17,6 @@
#include <linux/poll.h>
#include <linux/tcp.h>
#include <linux/uaccess.h>
-#include <linux/mutex.h>
#include <linux/debugfs.h>
#include <linux/caif/caif_socket.h>
#include <asm/atomic.h>
@@ -28,9 +29,6 @@
MODULE_LICENSE("GPL");
MODULE_ALIAS_NETPROTO(AF_CAIF);
-#define CAIF_DEF_SNDBUF (CAIF_MAX_PAYLOAD_SIZE*10)
-#define CAIF_DEF_RCVBUF (CAIF_MAX_PAYLOAD_SIZE*100)
-
/*
* CAIF state is re-using the TCP socket states.
* caif_states stored in sk_state reflect the state as reported by
@@ -76,6 +74,7 @@ struct caifsock {
struct caif_connect_request conn_req;
struct mutex readlock;
struct dentry *debugfs_socket_dir;
+ int headroom, tailroom, maxframe;
};
static int rx_flow_is_on(struct caifsock *cf_sk)
@@ -156,9 +155,7 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
(unsigned)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) {
- trace_printk("CAIF: %s():"
- " sending flow OFF (queue len = %d %d)\n",
- __func__,
+ pr_debug("sending flow OFF (queue len = %d %d)\n",
atomic_read(&cf_sk->sk.sk_rmem_alloc),
sk_rcvbuf_lowwater(cf_sk));
set_rx_flow_off(cf_sk);
@@ -171,9 +168,7 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
return err;
if (!sk_rmem_schedule(sk, skb->truesize) && rx_flow_is_on(cf_sk)) {
set_rx_flow_off(cf_sk);
- trace_printk("CAIF: %s():"
- " sending flow OFF due to rmem_schedule\n",
- __func__);
+ pr_debug("sending flow OFF due to rmem_schedule\n");
dbfs_atomic_inc(&cnt.num_rx_flow_off);
caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ);
}
@@ -274,8 +269,7 @@ static void caif_ctrl_cb(struct cflayer *layr,
break;
default:
- pr_debug("CAIF: %s(): Unexpected flow command %d\n",
- __func__, flow);
+ pr_debug("Unexpected flow command %d\n", flow);
}
}
@@ -535,8 +529,7 @@ static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk,
/* Slight paranoia, probably not needed. */
if (unlikely(loopcnt++ > 1000)) {
- pr_warning("CAIF: %s(): transmit retries failed,"
- " error = %d\n", __func__, ret);
+ pr_warn("transmit retries failed, error = %d\n", ret);
break;
}
@@ -594,27 +587,32 @@ static int caif_seqpkt_sendmsg(struct kiocb *kiocb, struct socket *sock,
goto err;
noblock = msg->msg_flags & MSG_DONTWAIT;
- buffer_size = len + CAIF_NEEDED_HEADROOM + CAIF_NEEDED_TAILROOM;
-
- ret = -EMSGSIZE;
- if (buffer_size > CAIF_MAX_PAYLOAD_SIZE)
- goto err;
-
timeo = sock_sndtimeo(sk, noblock);
timeo = caif_wait_for_flow_on(container_of(sk, struct caifsock, sk),
1, timeo, &ret);
+ if (ret)
+ goto err;
ret = -EPIPE;
if (cf_sk->sk.sk_state != CAIF_CONNECTED ||
sock_flag(sk, SOCK_DEAD) ||
(sk->sk_shutdown & RCV_SHUTDOWN))
goto err;
+ /* Error if trying to write more than maximum frame size. */
+ ret = -EMSGSIZE;
+ if (len > cf_sk->maxframe && cf_sk->sk.sk_protocol != CAIFPROTO_RFM)
+ goto err;
+
+ buffer_size = len + cf_sk->headroom + cf_sk->tailroom;
+
ret = -ENOMEM;
skb = sock_alloc_send_skb(sk, buffer_size, noblock, &ret);
- if (!skb)
+
+ if (!skb || skb_tailroom(skb) < buffer_size)
goto err;
- skb_reserve(skb, CAIF_NEEDED_HEADROOM);
+
+ skb_reserve(skb, cf_sk->headroom);
ret = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
@@ -645,7 +643,6 @@ static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
long timeo;
err = -EOPNOTSUPP;
-
if (unlikely(msg->msg_flags&MSG_OOB))
goto out_err;
@@ -662,8 +659,8 @@ static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
size = len-sent;
- if (size > CAIF_MAX_PAYLOAD_SIZE)
- size = CAIF_MAX_PAYLOAD_SIZE;
+ if (size > cf_sk->maxframe)
+ size = cf_sk->maxframe;
/* If size is more than half of sndbuf, chop up message */
if (size > ((sk->sk_sndbuf >> 1) - 64))
@@ -673,14 +670,14 @@ static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
size = SKB_MAX_ALLOC;
skb = sock_alloc_send_skb(sk,
- size + CAIF_NEEDED_HEADROOM
- + CAIF_NEEDED_TAILROOM,
+ size + cf_sk->headroom +
+ cf_sk->tailroom,
msg->msg_flags&MSG_DONTWAIT,
&err);
if (skb == NULL)
goto out_err;
- skb_reserve(skb, CAIF_NEEDED_HEADROOM);
+ skb_reserve(skb, cf_sk->headroom);
/*
* If you pass two values to the sock_alloc_send_skb
* it tries to grab the large buffer with GFP_NOFS
@@ -821,17 +818,16 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
long timeo;
int err;
+ int ifindex, headroom, tailroom;
+ unsigned int mtu;
+ struct net_device *dev;
+
lock_sock(sk);
err = -EAFNOSUPPORT;
if (uaddr->sa_family != AF_CAIF)
goto out;
- err = -ESOCKTNOSUPPORT;
- if (unlikely(!(sk->sk_type == SOCK_STREAM &&
- cf_sk->sk.sk_protocol == CAIFPROTO_AT) &&
- sk->sk_type != SOCK_SEQPACKET))
- goto out;
switch (sock->state) {
case SS_UNCONNECTED:
/* Normal case, a fresh connect */
@@ -874,8 +870,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
sk_stream_kill_queues(&cf_sk->sk);
err = -EINVAL;
- if (addr_len != sizeof(struct sockaddr_caif) ||
- !uaddr)
+ if (addr_len != sizeof(struct sockaddr_caif))
goto out;
memcpy(&cf_sk->conn_req.sockaddr, uaddr,
@@ -888,13 +883,31 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
dbfs_atomic_inc(&cnt.num_connect_req);
cf_sk->layer.receive = caif_sktrecv_cb;
err = caif_connect_client(&cf_sk->conn_req,
- &cf_sk->layer);
+ &cf_sk->layer, &ifindex, &headroom, &tailroom);
if (err < 0) {
cf_sk->sk.sk_socket->state = SS_UNCONNECTED;
cf_sk->sk.sk_state = CAIF_DISCONNECTED;
goto out;
}
+ err = -ENODEV;
+ rcu_read_lock();
+ dev = dev_get_by_index_rcu(sock_net(sk), ifindex);
+ if (!dev) {
+ rcu_read_unlock();
+ goto out;
+ }
+ cf_sk->headroom = LL_RESERVED_SPACE_EXTRA(dev, headroom);
+ mtu = dev->mtu;
+ rcu_read_unlock();
+
+ cf_sk->tailroom = tailroom;
+ cf_sk->maxframe = mtu - (headroom + tailroom);
+ if (cf_sk->maxframe < 1) {
+ pr_warn("CAIF Interface MTU too small (%d)\n", dev->mtu);
+ goto out;
+ }
+
err = -EINPROGRESS;
wait_connect:
@@ -1110,10 +1123,6 @@ static int caif_create(struct net *net, struct socket *sock, int protocol,
/* Store the protocol */
sk->sk_protocol = (unsigned char) protocol;
- /* Sendbuf dictates the amount of outbound packets not yet sent */
- sk->sk_sndbuf = CAIF_DEF_SNDBUF;
- sk->sk_rcvbuf = CAIF_DEF_RCVBUF;
-
/*
* Lock in order to try to stop someone from opening the socket
* too early.
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index df43f264d9f..41adafd1891 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -3,9 +3,13 @@
* Author: Sjur Brendeland/sjur.brandeland@stericsson.com
* License terms: GNU General Public License (GPL) version 2
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/slab.h>
+#include <linux/netdevice.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfpkt.h>
#include <net/caif/cfcnfg.h>
@@ -22,6 +26,7 @@
#define PHY_NAME_LEN 20
#define container_obj(layr) container_of(layr, struct cfcnfg, layer)
+#define RFM_FRAGMENT_SIZE 4030
/* Information about CAIF physical interfaces held by Config Module in order
* to manage physical interfaces
@@ -41,6 +46,15 @@ struct cfcnfg_phyinfo {
/* Information about the physical device */
struct dev_info dev_info;
+
+ /* Interface index */
+ int ifindex;
+
+ /* Use Start of frame extension */
+ bool use_stx;
+
+ /* Use Start of frame checksum */
+ bool use_fcs;
};
struct cfcnfg {
@@ -67,7 +81,7 @@ struct cfcnfg *cfcnfg_create(void)
/* Initiate this layer */
this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC);
if (!this) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
this->mux = cfmuxl_create();
@@ -95,7 +109,7 @@ struct cfcnfg *cfcnfg_create(void)
layer_set_up(this->ctrl, this);
return this;
out_of_mem:
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
kfree(this->mux);
kfree(this->ctrl);
kfree(this);
@@ -183,7 +197,7 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
caif_assert(adap_layer != NULL);
channel_id = adap_layer->id;
if (adap_layer->dn == NULL || channel_id == 0) {
- pr_err("CAIF: %s():adap_layer->id is 0\n", __func__);
+ pr_err("adap_layer->dn == NULL or adap_layer->id is 0\n");
ret = -ENOTCONN;
goto end;
}
@@ -193,9 +207,8 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
layer_set_up(servl, NULL);
ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
if (servl == NULL) {
- pr_err("CAIF: %s(): PROTOCOL ERROR "
- "- Error removing service_layer Channel_Id(%d)",
- __func__, channel_id);
+ pr_err("PROTOCOL ERROR - Error removing service_layer Channel_Id(%d)",
+ channel_id);
ret = -EINVAL;
goto end;
}
@@ -205,18 +218,14 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
if (phyinfo == NULL) {
- pr_warning("CAIF: %s(): "
- "No interface to send disconnect to\n",
- __func__);
+ pr_warn("No interface to send disconnect to\n");
ret = -ENODEV;
goto end;
}
if (phyinfo->id != phyid ||
phyinfo->phy_layer->id != phyid ||
phyinfo->frm_layer->id != phyid) {
- pr_err("CAIF: %s(): "
- "Inconsistency in phy registration\n",
- __func__);
+ pr_err("Inconsistency in phy registration\n");
ret = -EINVAL;
goto end;
}
@@ -248,27 +257,37 @@ static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
{
}
+int protohead[CFCTRL_SRV_MASK] = {
+ [CFCTRL_SRV_VEI] = 4,
+ [CFCTRL_SRV_DATAGRAM] = 7,
+ [CFCTRL_SRV_UTIL] = 4,
+ [CFCTRL_SRV_RFM] = 3,
+ [CFCTRL_SRV_DBG] = 3,
+};
+
int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
struct cfctrl_link_param *param,
- struct cflayer *adap_layer)
+ struct cflayer *adap_layer,
+ int *ifindex,
+ int *proto_head,
+ int *proto_tail)
{
struct cflayer *frml;
if (adap_layer == NULL) {
- pr_err("CAIF: %s(): adap_layer is zero", __func__);
+ pr_err("adap_layer is zero\n");
return -EINVAL;
}
if (adap_layer->receive == NULL) {
- pr_err("CAIF: %s(): adap_layer->receive is NULL", __func__);
+ pr_err("adap_layer->receive is NULL\n");
return -EINVAL;
}
if (adap_layer->ctrlcmd == NULL) {
- pr_err("CAIF: %s(): adap_layer->ctrlcmd == NULL", __func__);
+ pr_err("adap_layer->ctrlcmd == NULL\n");
return -EINVAL;
}
frml = cnfg->phy_layers[param->phyid].frm_layer;
if (frml == NULL) {
- pr_err("CAIF: %s(): Specified PHY type does not exist!",
- __func__);
+ pr_err("Specified PHY type does not exist!\n");
return -ENODEV;
}
caif_assert(param->phyid == cnfg->phy_layers[param->phyid].id);
@@ -276,6 +295,14 @@ int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
param->phyid);
caif_assert(cnfg->phy_layers[param->phyid].phy_layer->id ==
param->phyid);
+
+ *ifindex = cnfg->phy_layers[param->phyid].ifindex;
+ *proto_head =
+ protohead[param->linktype]+
+ (cnfg->phy_layers[param->phyid].use_stx ? 1 : 0);
+
+ *proto_tail = 2;
+
/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
cfctrl_enum_req(cnfg->ctrl, param->phyid);
return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer);
@@ -297,10 +324,10 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
struct cfcnfg *cnfg = container_obj(layer);
struct cflayer *servicel = NULL;
struct cfcnfg_phyinfo *phyinfo;
+ struct net_device *netdev;
+
if (adapt_layer == NULL) {
- pr_debug("CAIF: %s(): link setup response "
- "but no client exist, send linkdown back\n",
- __func__);
+ pr_debug("link setup response but no client exist, send linkdown back\n");
cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
return;
}
@@ -308,19 +335,15 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
caif_assert(cnfg != NULL);
caif_assert(phyid != 0);
phyinfo = &cnfg->phy_layers[phyid];
- caif_assert(phyinfo != NULL);
caif_assert(phyinfo->id == phyid);
caif_assert(phyinfo->phy_layer != NULL);
caif_assert(phyinfo->phy_layer->id == phyid);
- if (phyinfo != NULL &&
- phyinfo->phy_ref_count++ == 0 &&
- phyinfo->phy_layer != NULL &&
+ phyinfo->phy_ref_count++;
+ if (phyinfo->phy_ref_count == 1 &&
phyinfo->phy_layer->modemcmd != NULL) {
- caif_assert(phyinfo->phy_layer->id == phyid);
phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
_CAIF_MODEMCMD_PHYIF_USEFULL);
-
}
adapt_layer->id = channel_id;
@@ -332,7 +355,9 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
servicel = cfdgml_create(channel_id, &phyinfo->dev_info);
break;
case CFCTRL_SRV_RFM:
- servicel = cfrfml_create(channel_id, &phyinfo->dev_info);
+ netdev = phyinfo->dev_info.dev;
+ servicel = cfrfml_create(channel_id, &phyinfo->dev_info,
+ netdev->mtu);
break;
case CFCTRL_SRV_UTIL:
servicel = cfutill_create(channel_id, &phyinfo->dev_info);
@@ -344,13 +369,11 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
servicel = cfdbgl_create(channel_id, &phyinfo->dev_info);
break;
default:
- pr_err("CAIF: %s(): Protocol error. "
- "Link setup response - unknown channel type\n",
- __func__);
+ pr_err("Protocol error. Link setup response - unknown channel type\n");
return;
}
if (!servicel) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
layer_set_dn(servicel, cnfg->mux);
@@ -363,8 +386,8 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
void
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
- void *dev, struct cflayer *phy_layer, u16 *phyid,
- enum cfcnfg_phy_preference pref,
+ struct net_device *dev, struct cflayer *phy_layer,
+ u16 *phyid, enum cfcnfg_phy_preference pref,
bool fcs, bool stx)
{
struct cflayer *frml;
@@ -388,7 +411,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
}
}
if (*phyid == 0) {
- pr_err("CAIF: %s(): No Available PHY ID\n", __func__);
+ pr_err("No Available PHY ID\n");
return;
}
@@ -397,7 +420,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
phy_driver =
cfserl_create(CFPHYTYPE_FRAG, *phyid, stx);
if (!phy_driver) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
@@ -406,7 +429,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
phy_driver = NULL;
break;
default:
- pr_err("CAIF: %s(): %d", __func__, phy_type);
+ pr_err("%d\n", phy_type);
return;
break;
}
@@ -418,10 +441,14 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
cnfg->phy_layers[*phyid].dev_info.dev = dev;
cnfg->phy_layers[*phyid].phy_layer = phy_layer;
cnfg->phy_layers[*phyid].phy_ref_count = 0;
+ cnfg->phy_layers[*phyid].ifindex = dev->ifindex;
+ cnfg->phy_layers[*phyid].use_stx = stx;
+ cnfg->phy_layers[*phyid].use_fcs = fcs;
+
phy_layer->type = phy_type;
frml = cffrml_create(*phyid, fcs);
if (!frml) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
cnfg->phy_layers[*phyid].frm_layer = frml;
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index fcfda98a5e6..08f267a109a 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -19,7 +21,7 @@
#ifdef CAIF_NO_LOOP
static int handle_loop(struct cfctrl *ctrl,
int cmd, struct cfpkt *pkt){
- return CAIF_FAILURE;
+ return -1;
}
#else
static int handle_loop(struct cfctrl *ctrl,
@@ -36,14 +38,14 @@ struct cflayer *cfctrl_create(void)
struct cfctrl *this =
kmalloc(sizeof(struct cfctrl), GFP_ATOMIC);
if (!this) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
memset(&dev_info, 0, sizeof(dev_info));
dev_info.id = 0xff;
memset(this, 0, sizeof(*this));
- cfsrvl_init(&this->serv, 0, &dev_info);
+ cfsrvl_init(&this->serv, 0, &dev_info, false);
atomic_set(&this->req_seq_no, 1);
atomic_set(&this->rsp_seq_no, 1);
this->serv.layer.receive = cfctrl_recv;
@@ -132,9 +134,7 @@ struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
if (cfctrl_req_eq(req, p)) {
if (p != first)
- pr_warning("CAIF: %s(): Requests are not "
- "received in order\n",
- __func__);
+ pr_warn("Requests are not received in order\n");
atomic_set(&ctrl->rsp_seq_no,
p->sequence_no);
@@ -177,7 +177,7 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
int ret;
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
@@ -189,8 +189,7 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
ret =
cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
if (ret < 0) {
- pr_err("CAIF: %s(): Could not transmit enum message\n",
- __func__);
+ pr_err("Could not transmit enum message\n");
cfpkt_destroy(pkt);
}
}
@@ -208,7 +207,7 @@ int cfctrl_linkup_request(struct cflayer *layer,
char utility_name[16];
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return -ENOMEM;
}
cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP);
@@ -253,13 +252,13 @@ int cfctrl_linkup_request(struct cflayer *layer,
param->u.utility.paramlen);
break;
default:
- pr_warning("CAIF: %s():Request setup of bad link type = %d\n",
- __func__, param->linktype);
+ pr_warn("Request setup of bad link type = %d\n",
+ param->linktype);
return -EINVAL;
}
req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return -ENOMEM;
}
req->client_layer = user_layer;
@@ -276,8 +275,7 @@ int cfctrl_linkup_request(struct cflayer *layer,
ret =
cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
if (ret < 0) {
- pr_err("CAIF: %s(): Could not transmit linksetup request\n",
- __func__);
+ pr_err("Could not transmit linksetup request\n");
cfpkt_destroy(pkt);
return -ENODEV;
}
@@ -291,7 +289,7 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
struct cfctrl *cfctrl = container_obj(layer);
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return -ENOMEM;
}
cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY);
@@ -300,8 +298,7 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
ret =
cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
if (ret < 0) {
- pr_err("CAIF: %s(): Could not transmit link-down request\n",
- __func__);
+ pr_err("Could not transmit link-down request\n");
cfpkt_destroy(pkt);
}
return ret;
@@ -313,7 +310,7 @@ void cfctrl_sleep_req(struct cflayer *layer)
struct cfctrl *cfctrl = container_obj(layer);
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
cfpkt_addbdy(pkt, CFCTRL_CMD_SLEEP);
@@ -330,7 +327,7 @@ void cfctrl_wake_req(struct cflayer *layer)
struct cfctrl *cfctrl = container_obj(layer);
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
cfpkt_addbdy(pkt, CFCTRL_CMD_WAKE);
@@ -347,7 +344,7 @@ void cfctrl_getstartreason_req(struct cflayer *layer)
struct cfctrl *cfctrl = container_obj(layer);
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
cfpkt_addbdy(pkt, CFCTRL_CMD_START_REASON);
@@ -364,12 +361,11 @@ void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
struct cfctrl_request_info *p, *tmp;
struct cfctrl *ctrl = container_obj(layr);
spin_lock(&ctrl->info_list_lock);
- pr_warning("CAIF: %s(): enter\n", __func__);
+ pr_warn("enter\n");
list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
if (p->client_layer == adap_layer) {
- pr_warning("CAIF: %s(): cancel req :%d\n", __func__,
- p->sequence_no);
+ pr_warn("cancel req :%d\n", p->sequence_no);
list_del(&p->list);
kfree(p);
}
@@ -395,7 +391,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
cmd = cmdrsp & CFCTRL_CMD_MASK;
if (cmd != CFCTRL_CMD_LINK_ERR
&& CFCTRL_RSP_BIT != (CFCTRL_RSP_BIT & cmdrsp)) {
- if (handle_loop(cfctrl, cmd, pkt) == CAIF_FAILURE)
+ if (handle_loop(cfctrl, cmd, pkt) != 0)
cmdrsp |= CFCTRL_ERR_BIT;
}
@@ -520,9 +516,8 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
cfpkt_extr_head(pkt, &param, len);
break;
default:
- pr_warning("CAIF: %s(): Request setup "
- "- invalid link type (%d)",
- __func__, serv);
+ pr_warn("Request setup - invalid link type (%d)\n",
+ serv);
goto error;
}
@@ -532,9 +527,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) ||
cfpkt_erroneous(pkt)) {
- pr_err("CAIF: %s(): Invalid O/E bit or parse "
- "error on CAIF control channel",
- __func__);
+ pr_err("Invalid O/E bit or parse error on CAIF control channel\n");
cfctrl->res.reject_rsp(cfctrl->serv.layer.up,
0,
req ? req->client_layer
@@ -556,8 +549,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid);
break;
case CFCTRL_CMD_LINK_ERR:
- pr_err("CAIF: %s(): Frame Error Indication received\n",
- __func__);
+ pr_err("Frame Error Indication received\n");
cfctrl->res.linkerror_ind();
break;
case CFCTRL_CMD_ENUM:
@@ -576,7 +568,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
cfctrl->res.radioset_rsp();
break;
default:
- pr_err("CAIF: %s(): Unrecognized Control Frame\n", __func__);
+ pr_err("Unrecognized Control Frame\n");
goto error;
break;
}
@@ -595,8 +587,7 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
case CAIF_CTRLCMD_FLOW_OFF_IND:
spin_lock(&this->info_list_lock);
if (!list_empty(&this->list)) {
- pr_debug("CAIF: %s(): Received flow off in "
- "control layer", __func__);
+ pr_debug("Received flow off in control layer\n");
}
spin_unlock(&this->info_list_lock);
break;
@@ -620,7 +611,7 @@ static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt)
if (!ctrl->loop_linkused[linkid])
goto found;
spin_unlock(&ctrl->loop_linkid_lock);
- pr_err("CAIF: %s(): Out of link-ids\n", __func__);
+ pr_err("Out of link-ids\n");
return -EINVAL;
found:
if (!ctrl->loop_linkused[linkid])
@@ -647,6 +638,6 @@ found:
default:
break;
}
- return CAIF_SUCCESS;
+ return 0;
}
#endif
diff --git a/net/caif/cfdbgl.c b/net/caif/cfdbgl.c
index ab6b6dc34cf..496fda9ac66 100644
--- a/net/caif/cfdbgl.c
+++ b/net/caif/cfdbgl.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/slab.h>
#include <net/caif/caif_layer.h>
@@ -17,12 +19,12 @@ struct cflayer *cfdbgl_create(u8 channel_id, struct dev_info *dev_info)
{
struct cfsrvl *dbg = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
if (!dbg) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
memset(dbg, 0, sizeof(struct cfsrvl));
- cfsrvl_init(dbg, channel_id, dev_info);
+ cfsrvl_init(dbg, channel_id, dev_info, false);
dbg->layer.receive = cfdbgl_receive;
dbg->layer.transmit = cfdbgl_transmit;
snprintf(dbg->layer.name, CAIF_LAYER_NAME_SZ - 1, "dbg%d", channel_id);
diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c
index 53194840ecb..d3ed264ad6c 100644
--- a/net/caif/cfdgml.c
+++ b/net/caif/cfdgml.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -17,6 +19,7 @@
#define DGM_FLOW_OFF 0x81
#define DGM_FLOW_ON 0x80
#define DGM_CTRL_PKT_SIZE 1
+#define DGM_MTU 1500
static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt);
static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt);
@@ -25,12 +28,12 @@ struct cflayer *cfdgml_create(u8 channel_id, struct dev_info *dev_info)
{
struct cfsrvl *dgm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
if (!dgm) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
memset(dgm, 0, sizeof(struct cfsrvl));
- cfsrvl_init(dgm, channel_id, dev_info);
+ cfsrvl_init(dgm, channel_id, dev_info, true);
dgm->layer.receive = cfdgml_receive;
dgm->layer.transmit = cfdgml_transmit;
snprintf(dgm->layer.name, CAIF_LAYER_NAME_SZ - 1, "dgm%d", channel_id);
@@ -48,14 +51,14 @@ static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt)
caif_assert(layr->ctrlcmd != NULL);
if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
if ((cmd & DGM_CMD_BIT) == 0) {
if (cfpkt_extr_head(pkt, &dgmhdr, 3) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -74,8 +77,7 @@ static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt)
return 0;
default:
cfpkt_destroy(pkt);
- pr_info("CAIF: %s(): Unknown datagram control %d (0x%x)\n",
- __func__, cmd, cmd);
+ pr_info("Unknown datagram control %d (0x%x)\n", cmd, cmd);
return -EPROTO;
}
}
@@ -89,6 +91,10 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt)
if (!cfsrvl_ready(service, &ret))
return ret;
+ /* STE Modem cannot handle more than 1500 bytes datagrams */
+ if (cfpkt_getlen(pkt) > DGM_MTU)
+ return -EMSGSIZE;
+
cfpkt_add_head(pkt, &zero, 4);
/* Add info for MUX-layer to route the packet out. */
diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c
index e86a4ca3b21..a445043931a 100644
--- a/net/caif/cffrml.c
+++ b/net/caif/cffrml.c
@@ -6,6 +6,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -32,7 +34,7 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs)
{
struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC);
if (!this) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cffrml, layer) == 0);
@@ -83,7 +85,7 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
if (cfpkt_setlen(pkt, len) < 0) {
++cffrml_rcv_error;
- pr_err("CAIF: %s():Framing length error (%d)\n", __func__, len);
+ pr_err("Framing length error (%d)\n", len);
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -99,14 +101,14 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
cfpkt_add_trail(pkt, &tmp, 2);
++cffrml_rcv_error;
++cffrml_rcv_checsum_error;
- pr_info("CAIF: %s(): Frame checksum error "
- "(0x%x != 0x%x)\n", __func__, hdrchks, pktchks);
+ pr_info("Frame checksum error (0x%x != 0x%x)\n",
+ hdrchks, pktchks);
return -EILSEQ;
}
}
if (cfpkt_erroneous(pkt)) {
++cffrml_rcv_error;
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -132,7 +134,7 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt)
cfpkt_add_head(pkt, &tmp, 2);
cfpkt_info(pkt)->hdr_len += 2;
if (cfpkt_erroneous(pkt)) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
return -EPROTO;
}
ret = layr->dn->transmit(layr->dn, pkt);
diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c
index 80c8d332b25..46f34b2e047 100644
--- a/net/caif/cfmuxl.c
+++ b/net/caif/cfmuxl.c
@@ -3,6 +3,9 @@
* Author: Sjur Brendeland/sjur.brandeland@stericsson.com
* License terms: GNU General Public License (GPL) version 2
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -190,7 +193,7 @@ static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt)
u8 id;
struct cflayer *up;
if (cfpkt_extr_head(pkt, &id, 1) < 0) {
- pr_err("CAIF: %s(): erroneous Caif Packet\n", __func__);
+ pr_err("erroneous Caif Packet\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -199,8 +202,8 @@ static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt)
up = get_up(muxl, id);
spin_unlock(&muxl->receive_lock);
if (up == NULL) {
- pr_info("CAIF: %s():Received data on unknown link ID = %d "
- "(0x%x) up == NULL", __func__, id, id);
+ pr_info("Received data on unknown link ID = %d (0x%x) up == NULL",
+ id, id);
cfpkt_destroy(pkt);
/*
* Don't return ERROR, since modem misbehaves and sends out
@@ -223,9 +226,8 @@ static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt)
struct caif_payload_info *info = cfpkt_info(pkt);
dn = get_dn(muxl, cfpkt_info(pkt)->dev_info);
if (dn == NULL) {
- pr_warning("CAIF: %s(): Send data on unknown phy "
- "ID = %d (0x%x)\n",
- __func__, info->dev_info->id, info->dev_info->id);
+ pr_warn("Send data on unknown phy ID = %d (0x%x)\n",
+ info->dev_info->id, info->dev_info->id);
return -ENOTCONN;
}
info->hdr_len += 1;
diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c
index a6fdf899741..d7e865e2ff6 100644
--- a/net/caif/cfpkt_skbuff.c
+++ b/net/caif/cfpkt_skbuff.c
@@ -4,19 +4,22 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/hardirq.h>
#include <net/caif/cfpkt.h>
-#define PKT_PREFIX CAIF_NEEDED_HEADROOM
-#define PKT_POSTFIX CAIF_NEEDED_TAILROOM
+#define PKT_PREFIX 48
+#define PKT_POSTFIX 2
#define PKT_LEN_WHEN_EXTENDING 128
-#define PKT_ERROR(pkt, errmsg) do { \
- cfpkt_priv(pkt)->erronous = true; \
- skb_reset_tail_pointer(&pkt->skb); \
- pr_warning("CAIF: " errmsg);\
- } while (0)
+#define PKT_ERROR(pkt, errmsg) \
+do { \
+ cfpkt_priv(pkt)->erronous = true; \
+ skb_reset_tail_pointer(&pkt->skb); \
+ pr_warn(errmsg); \
+} while (0)
struct cfpktq {
struct sk_buff_head head;
@@ -130,13 +133,13 @@ int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len)
return -EPROTO;
if (unlikely(len > skb->len)) {
- PKT_ERROR(pkt, "cfpkt_extr_head read beyond end of packet\n");
+ PKT_ERROR(pkt, "read beyond end of packet\n");
return -EPROTO;
}
if (unlikely(len > skb_headlen(skb))) {
if (unlikely(skb_linearize(skb) != 0)) {
- PKT_ERROR(pkt, "cfpkt_extr_head linearize failed\n");
+ PKT_ERROR(pkt, "linearize failed\n");
return -EPROTO;
}
}
@@ -156,11 +159,11 @@ int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len)
return -EPROTO;
if (unlikely(skb_linearize(skb) != 0)) {
- PKT_ERROR(pkt, "cfpkt_extr_trail linearize failed\n");
+ PKT_ERROR(pkt, "linearize failed\n");
return -EPROTO;
}
if (unlikely(skb->data + len > skb_tail_pointer(skb))) {
- PKT_ERROR(pkt, "cfpkt_extr_trail read beyond end of packet\n");
+ PKT_ERROR(pkt, "read beyond end of packet\n");
return -EPROTO;
}
from = skb_tail_pointer(skb) - len;
@@ -202,7 +205,7 @@ int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len)
/* Make sure data is writable */
if (unlikely(skb_cow_data(skb, addlen, &lastskb) < 0)) {
- PKT_ERROR(pkt, "cfpkt_add_body: cow failed\n");
+ PKT_ERROR(pkt, "cow failed\n");
return -EPROTO;
}
/*
@@ -211,8 +214,7 @@ int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len)
* lengths of the top SKB.
*/
if (lastskb != skb) {
- pr_warning("CAIF: %s(): Packet is non-linear\n",
- __func__);
+ pr_warn("Packet is non-linear\n");
skb->len += len;
skb->data_len += len;
}
@@ -242,14 +244,14 @@ int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len)
if (unlikely(is_erronous(pkt)))
return -EPROTO;
if (unlikely(skb_headroom(skb) < len)) {
- PKT_ERROR(pkt, "cfpkt_add_head: no headroom\n");
+ PKT_ERROR(pkt, "no headroom\n");
return -EPROTO;
}
/* Make sure data is writable */
ret = skb_cow_data(skb, 0, &lastskb);
if (unlikely(ret < 0)) {
- PKT_ERROR(pkt, "cfpkt_add_head: cow failed\n");
+ PKT_ERROR(pkt, "cow failed\n");
return ret;
}
@@ -283,7 +285,7 @@ inline u16 cfpkt_iterate(struct cfpkt *pkt,
if (unlikely(is_erronous(pkt)))
return -EPROTO;
if (unlikely(skb_linearize(&pkt->skb) != 0)) {
- PKT_ERROR(pkt, "cfpkt_iterate: linearize failed\n");
+ PKT_ERROR(pkt, "linearize failed\n");
return -EPROTO;
}
return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt));
@@ -309,7 +311,7 @@ int cfpkt_setlen(struct cfpkt *pkt, u16 len)
/* Need to expand SKB */
if (unlikely(!cfpkt_pad_trail(pkt, len - skb->len)))
- PKT_ERROR(pkt, "cfpkt_setlen: skb_pad_trail failed\n");
+ PKT_ERROR(pkt, "skb_pad_trail failed\n");
return cfpkt_getlen(pkt);
}
@@ -338,7 +340,6 @@ struct cfpkt *cfpkt_append(struct cfpkt *dstpkt,
u16 dstlen;
u16 createlen;
if (unlikely(is_erronous(dstpkt) || is_erronous(addpkt))) {
- cfpkt_destroy(addpkt);
return dstpkt;
}
if (expectlen > addlen)
@@ -381,8 +382,7 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos)
return NULL;
if (skb->data + pos > skb_tail_pointer(skb)) {
- PKT_ERROR(pkt,
- "cfpkt_split: trying to split beyond end of packet");
+ PKT_ERROR(pkt, "trying to split beyond end of packet\n");
return NULL;
}
@@ -456,17 +456,17 @@ int cfpkt_raw_append(struct cfpkt *pkt, void **buf, unsigned int buflen)
return -EPROTO;
/* Make sure SKB is writable */
if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) {
- PKT_ERROR(pkt, "cfpkt_raw_append: skb_cow_data failed\n");
+ PKT_ERROR(pkt, "skb_cow_data failed\n");
return -EPROTO;
}
if (unlikely(skb_linearize(skb) != 0)) {
- PKT_ERROR(pkt, "cfpkt_raw_append: linearize failed\n");
+ PKT_ERROR(pkt, "linearize failed\n");
return -EPROTO;
}
if (unlikely(skb_tailroom(skb) < buflen)) {
- PKT_ERROR(pkt, "cfpkt_raw_append: buffer too short - failed\n");
+ PKT_ERROR(pkt, "buffer too short - failed\n");
return -EPROTO;
}
@@ -484,14 +484,13 @@ int cfpkt_raw_extract(struct cfpkt *pkt, void **buf, unsigned int buflen)
return -EPROTO;
if (unlikely(buflen > skb->len)) {
- PKT_ERROR(pkt, "cfpkt_raw_extract: buflen too large "
- "- failed\n");
+ PKT_ERROR(pkt, "buflen too large - failed\n");
return -EPROTO;
}
if (unlikely(buflen > skb_headlen(skb))) {
if (unlikely(skb_linearize(skb) != 0)) {
- PKT_ERROR(pkt, "cfpkt_raw_extract: linearize failed\n");
+ PKT_ERROR(pkt, "linearize failed\n");
return -EPROTO;
}
}
diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c
index fd27b172fb5..38152c41aba 100644
--- a/net/caif/cfrfml.c
+++ b/net/caif/cfrfml.c
@@ -4,105 +4,305 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/unaligned/le_byteshift.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfsrvl.h>
#include <net/caif/cfpkt.h>
-#define container_obj(layr) container_of(layr, struct cfsrvl, layer)
-
+#define container_obj(layr) container_of(layr, struct cfrfml, serv.layer)
#define RFM_SEGMENTATION_BIT 0x01
-#define RFM_PAYLOAD 0x00
-#define RFM_CMD_BIT 0x80
-#define RFM_FLOW_OFF 0x81
-#define RFM_FLOW_ON 0x80
-#define RFM_SET_PIN 0x82
-#define RFM_CTRL_PKT_SIZE 1
+#define RFM_HEAD_SIZE 7
static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt);
static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt);
-static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl);
-struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info)
+struct cfrfml {
+ struct cfsrvl serv;
+ struct cfpkt *incomplete_frm;
+ int fragment_size;
+ u8 seghead[6];
+ u16 pdu_size;
+ /* Protects serialized processing of packets */
+ spinlock_t sync;
+};
+
+static void cfrfml_release(struct kref *kref)
+{
+ struct cfsrvl *srvl = container_of(kref, struct cfsrvl, ref);
+ struct cfrfml *rfml = container_obj(&srvl->layer);
+
+ if (rfml->incomplete_frm)
+ cfpkt_destroy(rfml->incomplete_frm);
+
+ kfree(srvl);
+}
+
+struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info,
+ int mtu_size)
{
- struct cfsrvl *rfm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
- if (!rfm) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ int tmp;
+ struct cfrfml *this =
+ kzalloc(sizeof(struct cfrfml), GFP_ATOMIC);
+
+ if (!this) {
+ pr_warn("Out of memory\n");
return NULL;
}
- caif_assert(offsetof(struct cfsrvl, layer) == 0);
- memset(rfm, 0, sizeof(struct cfsrvl));
- cfsrvl_init(rfm, channel_id, dev_info);
- rfm->layer.modemcmd = cfservl_modemcmd;
- rfm->layer.receive = cfrfml_receive;
- rfm->layer.transmit = cfrfml_transmit;
- snprintf(rfm->layer.name, CAIF_LAYER_NAME_SZ, "rfm%d", channel_id);
- return &rfm->layer;
+
+ cfsrvl_init(&this->serv, channel_id, dev_info, false);
+ this->serv.release = cfrfml_release;
+ this->serv.layer.receive = cfrfml_receive;
+ this->serv.layer.transmit = cfrfml_transmit;
+
+ /* Round down to closest multiple of 16 */
+ tmp = (mtu_size - RFM_HEAD_SIZE - 6) / 16;
+ tmp *= 16;
+
+ this->fragment_size = tmp;
+ spin_lock_init(&this->sync);
+ snprintf(this->serv.layer.name, CAIF_LAYER_NAME_SZ,
+ "rfm%d", channel_id);
+
+ return &this->serv.layer;
}
-static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
+static struct cfpkt *rfm_append(struct cfrfml *rfml, char *seghead,
+ struct cfpkt *pkt, int *err)
{
- return -EPROTO;
+ struct cfpkt *tmppkt;
+ *err = -EPROTO;
+ /* n-th but not last segment */
+
+ if (cfpkt_extr_head(pkt, seghead, 6) < 0)
+ return NULL;
+
+ /* Verify correct header */
+ if (memcmp(seghead, rfml->seghead, 6) != 0)
+ return NULL;
+
+ tmppkt = cfpkt_append(rfml->incomplete_frm, pkt,
+ rfml->pdu_size + RFM_HEAD_SIZE);
+
+ /* If cfpkt_append failes input pkts are not freed */
+ *err = -ENOMEM;
+ if (tmppkt == NULL)
+ return NULL;
+
+ *err = 0;
+ return tmppkt;
}
static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt)
{
u8 tmp;
bool segmented;
- int ret;
+ int err;
+ u8 seghead[6];
+ struct cfrfml *rfml;
+ struct cfpkt *tmppkt = NULL;
+
caif_assert(layr->up != NULL);
caif_assert(layr->receive != NULL);
+ rfml = container_obj(layr);
+ spin_lock(&rfml->sync);
+
+ err = -EPROTO;
+ if (cfpkt_extr_head(pkt, &tmp, 1) < 0)
+ goto out;
+ segmented = tmp & RFM_SEGMENTATION_BIT;
+
+ if (segmented) {
+ if (rfml->incomplete_frm == NULL) {
+ /* Initial Segment */
+ if (cfpkt_peek_head(pkt, rfml->seghead, 6) < 0)
+ goto out;
+
+ rfml->pdu_size = get_unaligned_le16(rfml->seghead+4);
+
+ if (cfpkt_erroneous(pkt))
+ goto out;
+ rfml->incomplete_frm = pkt;
+ pkt = NULL;
+ } else {
+
+ tmppkt = rfm_append(rfml, seghead, pkt, &err);
+ if (tmppkt == NULL)
+ goto out;
+
+ if (cfpkt_erroneous(tmppkt))
+ goto out;
+
+ rfml->incomplete_frm = tmppkt;
+
+
+ if (cfpkt_erroneous(tmppkt))
+ goto out;
+ }
+ err = 0;
+ goto out;
+ }
+
+ if (rfml->incomplete_frm) {
+
+ /* Last Segment */
+ tmppkt = rfm_append(rfml, seghead, pkt, &err);
+ if (tmppkt == NULL)
+ goto out;
+
+ if (cfpkt_erroneous(tmppkt))
+ goto out;
+
+ rfml->incomplete_frm = NULL;
+ pkt = tmppkt;
+ tmppkt = NULL;
+
+ /* Verify that length is correct */
+ err = EPROTO;
+ if (rfml->pdu_size != cfpkt_getlen(pkt) - RFM_HEAD_SIZE + 1)
+ goto out;
+ }
+
+ err = rfml->serv.layer.up->receive(rfml->serv.layer.up, pkt);
+
+out:
+
+ if (err != 0) {
+ if (tmppkt)
+ cfpkt_destroy(tmppkt);
+ if (pkt)
+ cfpkt_destroy(pkt);
+ if (rfml->incomplete_frm)
+ cfpkt_destroy(rfml->incomplete_frm);
+ rfml->incomplete_frm = NULL;
+
+ pr_info("Connection error %d triggered on RFM link\n", err);
+
+ /* Trigger connection error upon failure.*/
+ layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND,
+ rfml->serv.dev_info.id);
+ }
+ spin_unlock(&rfml->sync);
+ return err;
+}
+
+
+static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt)
+{
+ caif_assert(!cfpkt_getlen(pkt) < rfml->fragment_size);
+
+ /* Add info for MUX-layer to route the packet out. */
+ cfpkt_info(pkt)->channel_id = rfml->serv.layer.id;
/*
- * RFM is taking care of segmentation and stripping of
- * segmentation bit.
+ * To optimize alignment, we add up the size of CAIF header before
+ * payload.
*/
- if (cfpkt_extr_head(pkt, &tmp, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
- cfpkt_destroy(pkt);
- return -EPROTO;
- }
- segmented = tmp & RFM_SEGMENTATION_BIT;
- caif_assert(!segmented);
+ cfpkt_info(pkt)->hdr_len = RFM_HEAD_SIZE;
+ cfpkt_info(pkt)->dev_info = &rfml->serv.dev_info;
- ret = layr->up->receive(layr->up, pkt);
- return ret;
+ return rfml->serv.layer.dn->transmit(rfml->serv.layer.dn, pkt);
}
static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
{
- u8 tmp = 0;
- int ret;
- struct cfsrvl *service = container_obj(layr);
+ int err;
+ u8 seg;
+ u8 head[6];
+ struct cfpkt *rearpkt = NULL;
+ struct cfpkt *frontpkt = pkt;
+ struct cfrfml *rfml = container_obj(layr);
caif_assert(layr->dn != NULL);
caif_assert(layr->dn->transmit != NULL);
- if (!cfsrvl_ready(service, &ret))
- return ret;
+ if (!cfsrvl_ready(&rfml->serv, &err))
+ return err;
+
+ err = -EPROTO;
+ if (cfpkt_getlen(pkt) <= RFM_HEAD_SIZE-1)
+ goto out;
+
+ err = 0;
+ if (cfpkt_getlen(pkt) > rfml->fragment_size + RFM_HEAD_SIZE)
+ err = cfpkt_peek_head(pkt, head, 6);
+
+ if (err < 0)
+ goto out;
+
+ while (cfpkt_getlen(frontpkt) > rfml->fragment_size + RFM_HEAD_SIZE) {
+
+ seg = 1;
+ err = -EPROTO;
+
+ if (cfpkt_add_head(frontpkt, &seg, 1) < 0)
+ goto out;
+ /*
+ * On OOM error cfpkt_split returns NULL.
+ *
+ * NOTE: Segmented pdu is not correctly aligned.
+ * This has negative performance impact.
+ */
+
+ rearpkt = cfpkt_split(frontpkt, rfml->fragment_size);
+ if (rearpkt == NULL)
+ goto out;
+
+ err = cfrfml_transmit_segment(rfml, frontpkt);
+
+ if (err != 0)
+ goto out;
+ frontpkt = rearpkt;
+ rearpkt = NULL;
+
+ err = -ENOMEM;
+ if (frontpkt == NULL)
+ goto out;
+ err = -EPROTO;
+ if (cfpkt_add_head(frontpkt, head, 6) < 0)
+ goto out;
- if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
- pr_err("CAIF: %s():Packet too large - size=%d\n",
- __func__, cfpkt_getlen(pkt));
- return -EOVERFLOW;
}
- if (cfpkt_add_head(pkt, &tmp, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
- return -EPROTO;
+
+ seg = 0;
+ err = -EPROTO;
+
+ if (cfpkt_add_head(frontpkt, &seg, 1) < 0)
+ goto out;
+
+ err = cfrfml_transmit_segment(rfml, frontpkt);
+
+ frontpkt = NULL;
+out:
+
+ if (err != 0) {
+ pr_info("Connection error %d triggered on RFM link\n", err);
+ /* Trigger connection error upon failure.*/
+
+ layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND,
+ rfml->serv.dev_info.id);
+
+ if (rearpkt)
+ cfpkt_destroy(rearpkt);
+
+ if (frontpkt && frontpkt != pkt) {
+
+ cfpkt_destroy(frontpkt);
+ /*
+ * Socket layer will free the original packet,
+ * but this packet may already be sent and
+ * freed. So we have to return 0 in this case
+ * to avoid socket layer to re-free this packet.
+ * The return of shutdown indication will
+ * cause connection to be invalidated anyhow.
+ */
+ err = 0;
+ }
}
- /* Add info for MUX-layer to route the packet out. */
- cfpkt_info(pkt)->channel_id = service->layer.id;
- /*
- * To optimize alignment, we add up the size of CAIF header before
- * payload.
- */
- cfpkt_info(pkt)->hdr_len = 1;
- cfpkt_info(pkt)->dev_info = &service->dev_info;
- ret = layr->dn->transmit(layr->dn, pkt);
- if (ret < 0)
- cfpkt_extr_head(pkt, &tmp, 1);
- return ret;
+ return err;
}
diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c
index 965c5baace4..9297f7dea9d 100644
--- a/net/caif/cfserl.c
+++ b/net/caif/cfserl.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -14,7 +16,8 @@
#define container_obj(layr) ((struct cfserl *) layr)
#define CFSERL_STX 0x02
-#define CAIF_MINIUM_PACKET_SIZE 4
+#define SERIAL_MINIUM_PACKET_SIZE 4
+#define SERIAL_MAX_FRAMESIZE 4096
struct cfserl {
struct cflayer layer;
struct cfpkt *incomplete_frm;
@@ -33,7 +36,7 @@ struct cflayer *cfserl_create(int type, int instance, bool use_stx)
{
struct cfserl *this = kmalloc(sizeof(struct cfserl), GFP_ATOMIC);
if (!this) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfserl, layer) == 0);
@@ -119,8 +122,8 @@ static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt)
/*
* Frame error handling
*/
- if (expectlen < CAIF_MINIUM_PACKET_SIZE
- || expectlen > CAIF_MAX_FRAMESIZE) {
+ if (expectlen < SERIAL_MINIUM_PACKET_SIZE
+ || expectlen > SERIAL_MAX_FRAMESIZE) {
if (!layr->usestx) {
if (pkt != NULL)
cfpkt_destroy(pkt);
diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c
index 6e5b7079a68..ab5e542526b 100644
--- a/net/caif/cfsrvl.c
+++ b/net/caif/cfsrvl.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -24,8 +26,10 @@ static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
int phyid)
{
struct cfsrvl *service = container_obj(layr);
+
caif_assert(layr->up != NULL);
caif_assert(layr->up->ctrlcmd != NULL);
+
switch (ctrl) {
case CAIF_CTRLCMD_INIT_RSP:
service->open = true;
@@ -77,8 +81,7 @@ static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
layr->up->ctrlcmd(layr->up, ctrl, phyid);
break;
default:
- pr_warning("CAIF: %s(): "
- "Unexpected ctrl in cfsrvl (%d)\n", __func__, ctrl);
+ pr_warn("Unexpected ctrl in cfsrvl (%d)\n", ctrl);
/* We have both modem and phy flow on, send flow on */
layr->up->ctrlcmd(layr->up, ctrl, phyid);
service->phy_flow_on = true;
@@ -89,9 +92,14 @@ static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
{
struct cfsrvl *service = container_obj(layr);
+
caif_assert(layr != NULL);
caif_assert(layr->dn != NULL);
caif_assert(layr->dn->transmit != NULL);
+
+ if (!service->supports_flowctrl)
+ return 0;
+
switch (ctrl) {
case CAIF_MODEMCMD_FLOW_ON_REQ:
{
@@ -100,14 +108,12 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
u8 flow_on = SRVL_FLOW_ON;
pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n",
- __func__);
+ pr_warn("Out of memory\n");
return -ENOMEM;
}
if (cfpkt_add_head(pkt, &flow_on, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n",
- __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -124,14 +130,12 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
u8 flow_off = SRVL_FLOW_OFF;
pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n",
- __func__);
+ pr_warn("Out of memory\n");
return -ENOMEM;
}
if (cfpkt_add_head(pkt, &flow_off, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n",
- __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -152,9 +156,17 @@ void cfservl_destroy(struct cflayer *layer)
kfree(layer);
}
+void cfsrvl_release(struct kref *kref)
+{
+ struct cfsrvl *service = container_of(kref, struct cfsrvl, ref);
+ kfree(service);
+}
+
void cfsrvl_init(struct cfsrvl *service,
- u8 channel_id,
- struct dev_info *dev_info)
+ u8 channel_id,
+ struct dev_info *dev_info,
+ bool supports_flowctrl
+ )
{
caif_assert(offsetof(struct cfsrvl, layer) == 0);
service->open = false;
@@ -164,14 +176,11 @@ void cfsrvl_init(struct cfsrvl *service,
service->layer.ctrlcmd = cfservl_ctrlcmd;
service->layer.modemcmd = cfservl_modemcmd;
service->dev_info = *dev_info;
+ service->supports_flowctrl = supports_flowctrl;
+ service->release = cfsrvl_release;
kref_init(&service->ref);
}
-void cfsrvl_release(struct kref *kref)
-{
- struct cfsrvl *service = container_of(kref, struct cfsrvl, ref);
- kfree(service);
-}
bool cfsrvl_ready(struct cfsrvl *service, int *err)
{
diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c
index 5fd2c9ea8b4..efad410e4c8 100644
--- a/net/caif/cfutill.c
+++ b/net/caif/cfutill.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
@@ -26,12 +28,12 @@ struct cflayer *cfutill_create(u8 channel_id, struct dev_info *dev_info)
{
struct cfsrvl *util = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
if (!util) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
memset(util, 0, sizeof(struct cfsrvl));
- cfsrvl_init(util, channel_id, dev_info);
+ cfsrvl_init(util, channel_id, dev_info, true);
util->layer.receive = cfutill_receive;
util->layer.transmit = cfutill_transmit;
snprintf(util->layer.name, CAIF_LAYER_NAME_SZ - 1, "util1");
@@ -47,7 +49,7 @@ static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt)
caif_assert(layr->up->receive != NULL);
caif_assert(layr->up->ctrlcmd != NULL);
if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -64,16 +66,14 @@ static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt)
cfpkt_destroy(pkt);
return 0;
case UTIL_REMOTE_SHUTDOWN: /* Remote Shutdown Request */
- pr_err("CAIF: %s(): REMOTE SHUTDOWN REQUEST RECEIVED\n",
- __func__);
+ pr_err("REMOTE SHUTDOWN REQUEST RECEIVED\n");
layr->ctrlcmd(layr, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, 0);
service->open = false;
cfpkt_destroy(pkt);
return 0;
default:
cfpkt_destroy(pkt);
- pr_warning("CAIF: %s(): Unknown service control %d (0x%x)\n",
- __func__, cmd, cmd);
+ pr_warn("Unknown service control %d (0x%x)\n", cmd, cmd);
return -EPROTO;
}
}
@@ -90,12 +90,6 @@ static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt)
if (!cfsrvl_ready(service, &ret))
return ret;
- if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
- pr_err("CAIF: %s(): packet too large size=%d\n",
- __func__, cfpkt_getlen(pkt));
- return -EOVERFLOW;
- }
-
cfpkt_add_head(pkt, &zero, 1);
/* Add info for MUX-layer to route the packet out. */
info = cfpkt_info(pkt);
diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c
index e04f7d964e8..3b425b189a9 100644
--- a/net/caif/cfveil.c
+++ b/net/caif/cfveil.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/slab.h>
#include <net/caif/caif_layer.h>
@@ -25,12 +27,12 @@ struct cflayer *cfvei_create(u8 channel_id, struct dev_info *dev_info)
{
struct cfsrvl *vei = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
if (!vei) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
memset(vei, 0, sizeof(struct cfsrvl));
- cfsrvl_init(vei, channel_id, dev_info);
+ cfsrvl_init(vei, channel_id, dev_info, true);
vei->layer.receive = cfvei_receive;
vei->layer.transmit = cfvei_transmit;
snprintf(vei->layer.name, CAIF_LAYER_NAME_SZ - 1, "vei%d", channel_id);
@@ -47,7 +49,7 @@ static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt)
if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -67,8 +69,7 @@ static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt)
cfpkt_destroy(pkt);
return 0;
default: /* SET RS232 PIN */
- pr_warning("CAIF: %s():Unknown VEI control packet %d (0x%x)!\n",
- __func__, cmd, cmd);
+ pr_warn("Unknown VEI control packet %d (0x%x)!\n", cmd, cmd);
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -84,14 +85,9 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt)
return ret;
caif_assert(layr->dn != NULL);
caif_assert(layr->dn->transmit != NULL);
- if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
- pr_warning("CAIF: %s(): Packet too large - size=%d\n",
- __func__, cfpkt_getlen(pkt));
- return -EOVERFLOW;
- }
if (cfpkt_add_head(pkt, &tmp, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
return -EPROTO;
}
diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c
index 89ad4ea239f..bf6fef2a0ef 100644
--- a/net/caif/cfvidl.c
+++ b/net/caif/cfvidl.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
@@ -21,13 +23,13 @@ struct cflayer *cfvidl_create(u8 channel_id, struct dev_info *dev_info)
{
struct cfsrvl *vid = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
if (!vid) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
memset(vid, 0, sizeof(struct cfsrvl));
- cfsrvl_init(vid, channel_id, dev_info);
+ cfsrvl_init(vid, channel_id, dev_info, false);
vid->layer.receive = cfvidl_receive;
vid->layer.transmit = cfvidl_transmit;
snprintf(vid->layer.name, CAIF_LAYER_NAME_SZ - 1, "vid1");
@@ -38,7 +40,7 @@ static int cfvidl_receive(struct cflayer *layr, struct cfpkt *pkt)
{
u32 videoheader;
if (cfpkt_extr_head(pkt, &videoheader, 4) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
index 610966abe2d..84a422c9894 100644
--- a/net/caif/chnl_net.c
+++ b/net/caif/chnl_net.c
@@ -5,6 +5,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/init.h>
@@ -23,14 +25,11 @@
#include <net/caif/caif_dev.h>
/* GPRS PDP connection has MTU to 1500 */
-#define SIZE_MTU 1500
+#define GPRS_PDP_MTU 1500
/* 5 sec. connect timeout */
#define CONNECT_TIMEOUT (5 * HZ)
#define CAIF_NET_DEFAULT_QUEUE_LEN 500
-#undef pr_debug
-#define pr_debug pr_warning
-
/*This list is protected by the rtnl lock. */
static LIST_HEAD(chnl_net_list);
@@ -142,8 +141,7 @@ static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
int phyid)
{
struct chnl_net *priv = container_of(layr, struct chnl_net, chnl);
- pr_debug("CAIF: %s(): NET flowctrl func called flow: %s\n",
- __func__,
+ pr_debug("NET flowctrl func called flow: %s\n",
flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" :
flow == CAIF_CTRLCMD_INIT_RSP ? "INIT" :
flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" :
@@ -196,12 +194,12 @@ static int chnl_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
priv = netdev_priv(dev);
if (skb->len > priv->netdev->mtu) {
- pr_warning("CAIF: %s(): Size of skb exceeded MTU\n", __func__);
+ pr_warn("Size of skb exceeded MTU\n");
return -ENOSPC;
}
if (!priv->flowenabled) {
- pr_debug("CAIF: %s(): dropping packets flow off\n", __func__);
+ pr_debug("dropping packets flow off\n");
return NETDEV_TX_BUSY;
}
@@ -232,50 +230,95 @@ static int chnl_net_open(struct net_device *dev)
{
struct chnl_net *priv = NULL;
int result = -1;
+ int llifindex, headroom, tailroom, mtu;
+ struct net_device *lldev;
ASSERT_RTNL();
priv = netdev_priv(dev);
if (!priv) {
- pr_debug("CAIF: %s(): chnl_net_open: no priv\n", __func__);
+ pr_debug("chnl_net_open: no priv\n");
return -ENODEV;
}
if (priv->state != CAIF_CONNECTING) {
priv->state = CAIF_CONNECTING;
- result = caif_connect_client(&priv->conn_req, &priv->chnl);
+ result = caif_connect_client(&priv->conn_req, &priv->chnl,
+ &llifindex, &headroom, &tailroom);
if (result != 0) {
- priv->state = CAIF_DISCONNECTED;
- pr_debug("CAIF: %s(): err: "
- "Unable to register and open device,"
- " Err:%d\n",
- __func__,
- result);
- return result;
+ pr_debug("err: "
+ "Unable to register and open device,"
+ " Err:%d\n",
+ result);
+ goto error;
+ }
+
+ lldev = dev_get_by_index(dev_net(dev), llifindex);
+
+ if (lldev == NULL) {
+ pr_debug("no interface?\n");
+ result = -ENODEV;
+ goto error;
+ }
+
+ dev->needed_tailroom = tailroom + lldev->needed_tailroom;
+ dev->hard_header_len = headroom + lldev->hard_header_len +
+ lldev->needed_tailroom;
+
+ /*
+ * MTU, head-room etc is not know before we have a
+ * CAIF link layer device available. MTU calculation may
+ * override initial RTNL configuration.
+ * MTU is minimum of current mtu, link layer mtu pluss
+ * CAIF head and tail, and PDP GPRS contexts max MTU.
+ */
+ mtu = min_t(int, dev->mtu, lldev->mtu - (headroom + tailroom));
+ mtu = min_t(int, GPRS_PDP_MTU, mtu);
+ dev_set_mtu(dev, mtu);
+ dev_put(lldev);
+
+ if (mtu < 100) {
+ pr_warn("CAIF Interface MTU too small (%d)\n", mtu);
+ result = -ENODEV;
+ goto error;
}
}
+ rtnl_unlock(); /* Release RTNL lock during connect wait */
+
result = wait_event_interruptible_timeout(priv->netmgmt_wq,
priv->state != CAIF_CONNECTING,
CONNECT_TIMEOUT);
+ rtnl_lock();
+
if (result == -ERESTARTSYS) {
- pr_debug("CAIF: %s(): wait_event_interruptible"
- " woken by a signal\n", __func__);
- return -ERESTARTSYS;
+ pr_debug("wait_event_interruptible woken by a signal\n");
+ result = -ERESTARTSYS;
+ goto error;
}
+
if (result == 0) {
- pr_debug("CAIF: %s(): connect timeout\n", __func__);
+ pr_debug("connect timeout\n");
caif_disconnect_client(&priv->chnl);
priv->state = CAIF_DISCONNECTED;
- pr_debug("CAIF: %s(): state disconnected\n", __func__);
- return -ETIMEDOUT;
+ pr_debug("state disconnected\n");
+ result = -ETIMEDOUT;
+ goto error;
}
if (priv->state != CAIF_CONNECTED) {
- pr_debug("CAIF: %s(): connect failed\n", __func__);
- return -ECONNREFUSED;
+ pr_debug("connect failed\n");
+ result = -ECONNREFUSED;
+ goto error;
}
- pr_debug("CAIF: %s(): CAIF Netdevice connected\n", __func__);
+ pr_debug("CAIF Netdevice connected\n");
return 0;
+
+error:
+ caif_disconnect_client(&priv->chnl);
+ priv->state = CAIF_DISCONNECTED;
+ pr_debug("state disconnected\n");
+ return result;
+
}
static int chnl_net_stop(struct net_device *dev)
@@ -321,9 +364,7 @@ static void ipcaif_net_setup(struct net_device *dev)
dev->destructor = free_netdev;
dev->flags |= IFF_NOARP;
dev->flags |= IFF_POINTOPOINT;
- dev->needed_headroom = CAIF_NEEDED_HEADROOM;
- dev->needed_tailroom = CAIF_NEEDED_TAILROOM;
- dev->mtu = SIZE_MTU;
+ dev->mtu = GPRS_PDP_MTU;
dev->tx_queue_len = CAIF_NET_DEFAULT_QUEUE_LEN;
priv = netdev_priv(dev);
@@ -366,7 +407,7 @@ static void caif_netlink_parms(struct nlattr *data[],
struct caif_connect_request *conn_req)
{
if (!data) {
- pr_warning("CAIF: %s: no params data found\n", __func__);
+ pr_warn("no params data found\n");
return;
}
if (data[IFLA_CAIF_IPV4_CONNID])
@@ -395,8 +436,7 @@ static int ipcaif_newlink(struct net *src_net, struct net_device *dev,
ret = register_netdevice(dev);
if (ret)
- pr_warning("CAIF: %s(): device rtml registration failed\n",
- __func__);
+ pr_warn("device rtml registration failed\n");
return ret;
}
diff --git a/net/phonet/Kconfig b/net/phonet/Kconfig
index 6ec7d55b176..901956ada9c 100644
--- a/net/phonet/Kconfig
+++ b/net/phonet/Kconfig
@@ -14,3 +14,14 @@ config PHONET
To compile this driver as a module, choose M here: the module
will be called phonet. If unsure, say N.
+
+config PHONET_PIPECTRLR
+ bool "Phonet Pipe Controller"
+ depends on PHONET
+ default N
+ help
+ The Pipe Controller implementation in Phonet stack to support Pipe
+ data with Nokia Slim modems like WG2.5 used on ST-Ericsson U8500
+ platform.
+
+ If unsure, say N.
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index b2a3ae6cad7..1214ed0cef3 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -88,6 +88,15 @@ static int pep_reply(struct sock *sk, struct sk_buff *oskb,
const struct pnpipehdr *oph = pnp_hdr(oskb);
struct pnpipehdr *ph;
struct sk_buff *skb;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ const struct phonethdr *hdr = pn_hdr(oskb);
+ struct sockaddr_pn spn = {
+ .spn_family = AF_PHONET,
+ .spn_resource = 0xD9,
+ .spn_dev = hdr->pn_sdev,
+ .spn_obj = hdr->pn_sobj,
+ };
+#endif
skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority);
if (!skb)
@@ -105,10 +114,262 @@ static int pep_reply(struct sock *sk, struct sk_buff *oskb,
ph->pipe_handle = oph->pipe_handle;
ph->error_code = code;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ return pn_skb_send(sk, skb, &spn);
+#else
return pn_skb_send(sk, skb, &pipe_srv);
+#endif
}
#define PAD 0x00
+
+#ifdef CONFIG_PHONET_PIPECTRLR
+static u8 pipe_negotiate_fc(u8 *host_fc, u8 *remote_fc, int len)
+{
+ int i, j;
+ u8 base_fc, final_fc;
+
+ for (i = 0; i < len; i++) {
+ base_fc = host_fc[i];
+ for (j = 0; j < len; j++) {
+ if (remote_fc[j] == base_fc) {
+ final_fc = base_fc;
+ goto done;
+ }
+ }
+ }
+ return -EINVAL;
+
+done:
+ return final_fc;
+
+}
+
+static int pipe_get_flow_info(struct sock *sk, struct sk_buff *skb,
+ u8 *pref_rx_fc, u8 *req_tx_fc)
+{
+ struct pnpipehdr *hdr;
+ u8 n_sb;
+
+ if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
+ return -EINVAL;
+
+ hdr = pnp_hdr(skb);
+ n_sb = hdr->data[4];
+
+ __skb_pull(skb, sizeof(*hdr) + 4);
+ while (n_sb > 0) {
+ u8 type, buf[3], len = sizeof(buf);
+ u8 *data = pep_get_sb(skb, &type, &len, buf);
+
+ if (data == NULL)
+ return -EINVAL;
+
+ switch (type) {
+ case PN_PIPE_SB_REQUIRED_FC_TX:
+ if (len < 3 || (data[2] | data[3] | data[4]) > 3)
+ break;
+ req_tx_fc[0] = data[2];
+ req_tx_fc[1] = data[3];
+ req_tx_fc[2] = data[4];
+ break;
+
+ case PN_PIPE_SB_PREFERRED_FC_RX:
+ if (len < 3 || (data[2] | data[3] | data[4]) > 3)
+ break;
+ pref_rx_fc[0] = data[2];
+ pref_rx_fc[1] = data[3];
+ pref_rx_fc[2] = data[4];
+ break;
+
+ }
+ n_sb--;
+ }
+ return 0;
+}
+
+static int pipe_handler_send_req(struct sock *sk, u16 dobj, u8 utid,
+ u8 msg_id, u8 p_handle, gfp_t priority)
+{
+ int len;
+ struct pnpipehdr *ph;
+ struct sk_buff *skb;
+ struct sockaddr_pn spn = {
+ .spn_family = AF_PHONET,
+ .spn_resource = 0xD9,
+ .spn_dev = pn_dev(dobj),
+ .spn_obj = pn_obj(dobj),
+ };
+
+ static const u8 data[4] = {
+ PAD, PAD, PAD, PAD,
+ };
+
+ switch (msg_id) {
+ case PNS_PEP_CONNECT_REQ:
+ len = sizeof(data);
+ break;
+
+ case PNS_PEP_DISCONNECT_REQ:
+ case PNS_PEP_ENABLE_REQ:
+ case PNS_PEP_DISABLE_REQ:
+ len = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority);
+ if (!skb)
+ return -ENOMEM;
+ skb_set_owner_w(skb, sk);
+
+ skb_reserve(skb, MAX_PNPIPE_HEADER);
+ if (len) {
+ __skb_put(skb, len);
+ skb_copy_to_linear_data(skb, data, len);
+ }
+ __skb_push(skb, sizeof(*ph));
+ skb_reset_transport_header(skb);
+ ph = pnp_hdr(skb);
+ ph->utid = utid;
+ ph->message_id = msg_id;
+ ph->pipe_handle = p_handle;
+ ph->error_code = PN_PIPE_NO_ERROR;
+
+ return pn_skb_send(sk, skb, &spn);
+}
+
+static int pipe_handler_send_created_ind(struct sock *sk, u16 dobj,
+ u8 utid, u8 p_handle, u8 msg_id, u8 tx_fc, u8 rx_fc)
+{
+ int err_code;
+ struct pnpipehdr *ph;
+ struct sk_buff *skb;
+ struct sockaddr_pn spn = {
+ .spn_family = AF_PHONET,
+ .spn_resource = 0xD9,
+ .spn_dev = pn_dev(dobj),
+ .spn_obj = pn_obj(dobj),
+ };
+
+ static u8 data[4] = {
+ 0x03, 0x04,
+ };
+ data[2] = tx_fc;
+ data[3] = rx_fc;
+
+ /*
+ * actually, below is number of sub-blocks and not error code.
+ * Pipe_created_ind message format does not have any
+ * error code field. However, the Phonet stack will always send
+ * an error code as part of pnpipehdr. So, use that err_code to
+ * specify the number of sub-blocks.
+ */
+ err_code = 0x01;
+
+ skb = alloc_skb(MAX_PNPIPE_HEADER + sizeof(data), GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+ skb_set_owner_w(skb, sk);
+
+ skb_reserve(skb, MAX_PNPIPE_HEADER);
+ __skb_put(skb, sizeof(data));
+ skb_copy_to_linear_data(skb, data, sizeof(data));
+ __skb_push(skb, sizeof(*ph));
+ skb_reset_transport_header(skb);
+ ph = pnp_hdr(skb);
+ ph->utid = utid;
+ ph->message_id = msg_id;
+ ph->pipe_handle = p_handle;
+ ph->error_code = err_code;
+
+ return pn_skb_send(sk, skb, &spn);
+}
+
+static int pipe_handler_send_ind(struct sock *sk, u16 dobj, u8 utid,
+ u8 p_handle, u8 msg_id)
+{
+ int err_code;
+ struct pnpipehdr *ph;
+ struct sk_buff *skb;
+ struct sockaddr_pn spn = {
+ .spn_family = AF_PHONET,
+ .spn_resource = 0xD9,
+ .spn_dev = pn_dev(dobj),
+ .spn_obj = pn_obj(dobj),
+ };
+
+ /*
+ * actually, below is a filler.
+ * Pipe_enabled/disabled_ind message format does not have any
+ * error code field. However, the Phonet stack will always send
+ * an error code as part of pnpipehdr. So, use that err_code to
+ * specify the filler value.
+ */
+ err_code = 0x0;
+
+ skb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+ skb_set_owner_w(skb, sk);
+
+ skb_reserve(skb, MAX_PNPIPE_HEADER);
+ __skb_push(skb, sizeof(*ph));
+ skb_reset_transport_header(skb);
+ ph = pnp_hdr(skb);
+ ph->utid = utid;
+ ph->message_id = msg_id;
+ ph->pipe_handle = p_handle;
+ ph->error_code = err_code;
+
+ return pn_skb_send(sk, skb, &spn);
+}
+
+static int pipe_handler_enable_pipe(struct sock *sk, int enable)
+{
+ struct pep_sock *pn = pep_sk(sk);
+ int utid, req;
+
+ if (enable) {
+ utid = PNS_PIPE_ENABLE_UTID;
+ req = PNS_PEP_ENABLE_REQ;
+ } else {
+ utid = PNS_PIPE_DISABLE_UTID;
+ req = PNS_PEP_DISABLE_REQ;
+ }
+ return pipe_handler_send_req(sk, pn->pn_sk.sobject, utid, req,
+ pn->pipe_handle, GFP_ATOMIC);
+}
+
+static int pipe_handler_create_pipe(struct sock *sk, int pipe_handle, int cmd)
+{
+ int ret;
+ struct pep_sock *pn = pep_sk(sk);
+
+ switch (cmd) {
+ case PNPIPE_CREATE:
+ ret = pipe_handler_send_req(sk, pn->pn_sk.sobject,
+ PNS_PEP_CONNECT_UTID, PNS_PEP_CONNECT_REQ,
+ pipe_handle, GFP_ATOMIC);
+ break;
+
+ case PNPIPE_DESTROY:
+ ret = pipe_handler_send_req(sk, pn->remote_pep,
+ PNS_PEP_DISCONNECT_UTID,
+ PNS_PEP_DISCONNECT_REQ,
+ pn->pipe_handle, GFP_ATOMIC);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+#endif
+
static int pep_accept_conn(struct sock *sk, struct sk_buff *skb)
{
static const u8 data[20] = {
@@ -173,6 +434,14 @@ static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority)
struct pep_sock *pn = pep_sk(sk);
struct pnpipehdr *ph;
struct sk_buff *skb;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ struct sockaddr_pn spn = {
+ .spn_family = AF_PHONET,
+ .spn_resource = 0xD9,
+ .spn_dev = pn_dev(pn->remote_pep),
+ .spn_obj = pn_obj(pn->remote_pep),
+ };
+#endif
skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority);
if (!skb)
@@ -192,7 +461,11 @@ static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority)
ph->data[3] = PAD;
ph->data[4] = status;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ return pn_skb_send(sk, skb, &spn);
+#else
return pn_skb_send(sk, skb, &pipe_srv);
+#endif
}
/* Send our RX flow control information to the sender.
@@ -225,12 +498,13 @@ static void pipe_grant_credits(struct sock *sk)
static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
{
struct pep_sock *pn = pep_sk(sk);
- struct pnpipehdr *hdr = pnp_hdr(skb);
+ struct pnpipehdr *hdr;
int wake = 0;
if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
return -EINVAL;
+ hdr = pnp_hdr(skb);
if (hdr->data[0] != PN_PEP_TYPE_COMMON) {
LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP type: %u\n",
(unsigned)hdr->data[0]);
@@ -308,6 +582,12 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
struct pnpipehdr *hdr = pnp_hdr(skb);
struct sk_buff_head *queue;
int err = 0;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ struct phonethdr *ph = pn_hdr(skb);
+ static u8 host_pref_rx_fc[3], host_req_tx_fc[3];
+ u8 remote_pref_rx_fc[3], remote_req_tx_fc[3];
+ u8 negotiated_rx_fc, negotiated_tx_fc;
+#endif
BUG_ON(sk->sk_state == TCP_CLOSE_WAIT);
@@ -316,6 +596,40 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE);
break;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNS_PEP_CONNECT_RESP:
+ if ((ph->pn_sdev == pn_dev(pn->remote_pep)) &&
+ (ph->pn_sobj == pn_obj(pn->remote_pep))) {
+ pipe_get_flow_info(sk, skb, remote_pref_rx_fc,
+ remote_req_tx_fc);
+
+ negotiated_tx_fc = pipe_negotiate_fc(remote_req_tx_fc,
+ host_pref_rx_fc,
+ sizeof(host_pref_rx_fc));
+ negotiated_rx_fc = pipe_negotiate_fc(host_req_tx_fc,
+ remote_pref_rx_fc,
+ sizeof(host_pref_rx_fc));
+
+ pn->pipe_state = PIPE_DISABLED;
+ pipe_handler_send_created_ind(sk, pn->remote_pep,
+ PNS_PIPE_CREATED_IND_UTID,
+ pn->pipe_handle, PNS_PIPE_CREATED_IND,
+ negotiated_tx_fc, negotiated_rx_fc);
+ pipe_handler_send_created_ind(sk, pn->pn_sk.sobject,
+ PNS_PIPE_CREATED_IND_UTID,
+ pn->pipe_handle, PNS_PIPE_CREATED_IND,
+ negotiated_tx_fc, negotiated_rx_fc);
+ } else {
+ pipe_handler_send_req(sk, pn->remote_pep,
+ PNS_PEP_CONNECT_UTID,
+ PNS_PEP_CONNECT_REQ, pn->pipe_handle,
+ GFP_ATOMIC);
+ pipe_get_flow_info(sk, skb, host_pref_rx_fc,
+ host_req_tx_fc);
+ }
+ break;
+#endif
+
case PNS_PEP_DISCONNECT_REQ:
pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
sk->sk_state = TCP_CLOSE_WAIT;
@@ -323,11 +637,41 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
sk->sk_state_change(sk);
break;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNS_PEP_DISCONNECT_RESP:
+ pn->pipe_state = PIPE_IDLE;
+ pipe_handler_send_req(sk, pn->pn_sk.sobject,
+ PNS_PEP_DISCONNECT_UTID,
+ PNS_PEP_DISCONNECT_REQ, pn->pipe_handle,
+ GFP_KERNEL);
+ break;
+#endif
+
case PNS_PEP_ENABLE_REQ:
/* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */
pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
break;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNS_PEP_ENABLE_RESP:
+ if ((ph->pn_sdev == pn_dev(pn->remote_pep)) &&
+ (ph->pn_sobj == pn_obj(pn->remote_pep))) {
+ pn->pipe_state = PIPE_ENABLED;
+ pipe_handler_send_ind(sk, pn->remote_pep,
+ PNS_PIPE_ENABLED_IND_UTID,
+ pn->pipe_handle, PNS_PIPE_ENABLED_IND);
+ pipe_handler_send_ind(sk, pn->pn_sk.sobject,
+ PNS_PIPE_ENABLED_IND_UTID,
+ pn->pipe_handle, PNS_PIPE_ENABLED_IND);
+ } else
+ pipe_handler_send_req(sk, pn->remote_pep,
+ PNS_PIPE_ENABLE_UTID,
+ PNS_PEP_ENABLE_REQ, pn->pipe_handle,
+ GFP_KERNEL);
+
+ break;
+#endif
+
case PNS_PEP_RESET_REQ:
switch (hdr->state_after_reset) {
case PN_PIPE_DISABLE:
@@ -346,6 +690,27 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
break;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNS_PEP_DISABLE_RESP:
+ if ((ph->pn_sdev == pn_dev(pn->remote_pep)) &&
+ (ph->pn_sobj == pn_obj(pn->remote_pep))) {
+ pn->pipe_state = PIPE_DISABLED;
+ pipe_handler_send_ind(sk, pn->remote_pep,
+ PNS_PIPE_DISABLED_IND_UTID,
+ pn->pipe_handle,
+ PNS_PIPE_DISABLED_IND);
+ pipe_handler_send_ind(sk, pn->pn_sk.sobject,
+ PNS_PIPE_DISABLED_IND_UTID,
+ pn->pipe_handle,
+ PNS_PIPE_DISABLED_IND);
+ } else
+ pipe_handler_send_req(sk, pn->remote_pep,
+ PNS_PIPE_DISABLE_UTID,
+ PNS_PEP_DISABLE_REQ, pn->pipe_handle,
+ GFP_KERNEL);
+ break;
+#endif
+
case PNS_PEP_CTRL_REQ:
if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) {
atomic_inc(&sk->sk_drops);
@@ -519,6 +884,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
newpn->init_enable = enabled;
newpn->aligned = aligned;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ newpn->remote_pep = pn->remote_pep;
+#endif
BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue));
skb_queue_head(&newsk->sk_receive_queue, skb);
@@ -756,6 +1124,10 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
{
struct pep_sock *pn = pep_sk(sk);
int val = 0, err = 0;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ int remote_pep;
+ int pipe_handle;
+#endif
if (level != SOL_PNPIPE)
return -ENOPROTOOPT;
@@ -766,6 +1138,31 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
lock_sock(sk);
switch (optname) {
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNPIPE_CREATE:
+ if (val) {
+ if (pn->pipe_state > PIPE_IDLE) {
+ err = -EFAULT;
+ break;
+ }
+ remote_pep = val & 0xFFFF;
+ pipe_handle = (val >> 16) & 0xFF;
+ pn->remote_pep = remote_pep;
+ err = pipe_handler_create_pipe(sk, pipe_handle,
+ PNPIPE_CREATE);
+ break;
+ }
+
+ case PNPIPE_DESTROY:
+ if (pn->pipe_state < PIPE_DISABLED) {
+ err = -EFAULT;
+ break;
+ }
+
+ err = pipe_handler_create_pipe(sk, 0x0, PNPIPE_DESTROY);
+ break;
+#endif
+
case PNPIPE_ENCAP:
if (val && val != PNPIPE_ENCAP_IP) {
err = -EINVAL;
@@ -791,6 +1188,17 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
err = 0;
}
goto out_norel;
+
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNPIPE_ENABLE:
+ if (pn->pipe_state <= PIPE_IDLE) {
+ err = -ENOTCONN;
+ break;
+ }
+ err = pipe_handler_enable_pipe(sk, val);
+ break;
+#endif
+
default:
err = -ENOPROTOOPT;
}
@@ -815,9 +1223,19 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
case PNPIPE_ENCAP:
val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE;
break;
+
case PNPIPE_IFINDEX:
val = pn->ifindex;
break;
+
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNPIPE_ENABLE:
+ if (pn->pipe_state <= PIPE_IDLE)
+ return -ENOTCONN;
+ val = pn->pipe_state != PIPE_DISABLED;
+ break;
+#endif
+
default:
return -ENOPROTOOPT;
}
@@ -834,6 +1252,16 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
{
struct pep_sock *pn = pep_sk(sk);
struct pnpipehdr *ph;
+ int err;
+
+#ifdef CONFIG_PHONET_PIPECTRLR
+ struct sockaddr_pn spn = {
+ .spn_family = AF_PHONET,
+ .spn_resource = 0xD9,
+ .spn_dev = pn_dev(pn->remote_pep),
+ .spn_obj = pn_obj(pn->remote_pep),
+ };
+#endif
if (pn_flow_safe(pn->tx_fc) &&
!atomic_add_unless(&pn->tx_credits, -1, 0)) {
@@ -852,7 +1280,15 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
ph->message_id = PNS_PIPE_DATA;
ph->pipe_handle = pn->pipe_handle;
- return pn_skb_send(sk, skb, &pipe_srv);
+#ifdef CONFIG_PHONET_PIPECTRLR
+ err = pn_skb_send(sk, skb, &spn);
+#else
+ err = pn_skb_send(sk, skb, &pipe_srv);
+#endif
+
+ if (err && pn_flow_safe(pn->tx_fc))
+ atomic_inc(&pn->tx_credits);
+ return err;
}
static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index bd88f11b095..fdabb835fcc 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1299,7 +1299,11 @@ sub process {
$here = "#$realline: " if ($file);
# extract the filename as it passes
- if ($line=~/^\+\+\+\s+(\S+)/) {
+ if ($line =~ /^diff --git.*?(\S+)$/) {
+ $realfile = $1;
+ $realfile =~ s@^([^/]*)/@@;
+
+ } elsif ($line =~ /^\+\+\+\s+(\S+)/) {
$realfile = $1;
$realfile =~ s@^([^/]*)/@@;
@@ -1323,6 +1327,14 @@ sub process {
$cnt_lines++ if ($realcnt != 0);
+# Check for incorrect file permissions
+ if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) {
+ my $permhere = $here . "FILE: $realfile\n";
+ if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) {
+ ERROR("do not set execute permissions for source files\n" . $permhere);
+ }
+ }
+
#check the patch for a signoff:
if ($line =~ /^\s*signed-off-by:/i) {
# This is a signoff, if ugly, so do not double report.
diff --git a/sound/Kconfig b/sound/Kconfig
index fcad760f569..952e18963b5 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -23,6 +23,46 @@ menuconfig SOUND
and read <file:Documentation/sound/oss/README.modules>; the module
will be called soundcore.
+# added for U8500 audio codec device
+config U8500_ACODEC
+ tristate "U8500 audio codec generic module (used both by SAA and ALSA)"
+ depends on STM_MSP_I2S
+ default Y
+ help
+ Say Y here if you have a U8500 based device
+ and want to use its audio codec chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called u8500mod_acodec.
+
+choice
+ prompt "Audio codec type"
+ depends on U8500_ACODEC
+ default U8500_AB8500_ED
+
+ config U8500_AB8500_ED
+ bool "U8500 ab8500 v0 audio codec"
+
+ config U8500_AB8500_CUT10
+ bool "U8500 ab8500 v1.x audio codec"
+
+endchoice
+
+choice
+ prompt "Driver mode"
+ depends on U8500_ACODEC
+ default U8500_ACODEC_DMA
+
+ config U8500_ACODEC_DMA
+ bool "DMA mode"
+
+ config U8500_ACODEC_POLL
+ bool "Polling mode"
+
+ config U8500_ACODEC_INTR
+ bool "Interrupt mode"
+endchoice
+
if SOUND
config SOUND_OSS_CORE
diff --git a/sound/Makefile b/sound/Makefile
index ec467decfa7..890fd1aeb25 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -16,4 +16,11 @@ ifeq ($(CONFIG_SND),y)
obj-y += last.o
endif
+obj-$(CONFIG_U8500_ACODEC) += u8500mod_acodec.o
+ifeq ($(CONFIG_U8500_AB8500_CUT10),y)
+ u8500mod_acodec-objs := u8500_acodec_ab8500.o ab8500_codec_v1_0.o
+else
+ u8500mod_acodec-objs := u8500_acodec_ab8500.o ab8500_codec.o
+endif
+
soundcore-objs := sound_core.o
diff --git a/sound/ab8500_codec.c b/sound/ab8500_codec.c
new file mode 100644
index 00000000000..fd4975bbdce
--- /dev/null
+++ b/sound/ab8500_codec.c
@@ -0,0 +1,6697 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: ST-Ericsson
+ *
+ * License terms:
+ *
+ * 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.
+ */
+
+ /*----------------------------------------------------------------------------
+ * Includes
+ *---------------------------------------------------------------------------*/
+#include <mach/ab8500_codec.h>
+#include <mach/ab8500_codec_p.h>
+
+/*--------------------------------------------------------------------------*
+ * debug stuff *
+ *--------------------------------------------------------------------------*/
+#ifdef __DEBUG
+#define MY_DEBUG_LEVEL_VAR_NAME myDebugLevel_AB8500_CODEC
+#define MY_DEBUG_ID myDebugID_AB8500_CODEC
+PRIVATE t_dbg_level MY_DEBUG_LEVEL_VAR_NAME = DEBUG_LEVEL0;
+PRIVATE t_dbg_id MY_DEBUG_ID = AB8500_CODEC_HCL_DBG_ID;
+#endif
+
+/*--------------------------------------------------------------------------*
+ * Global data for interrupt mode management *
+ *--------------------------------------------------------------------------*/
+PRIVATE t_ab8500_codec_system_context g_ab8500_codec_system_context;
+
+/*--------------------------------------------------------------------------*
+ * Default Values *
+ *--------------------------------------------------------------------------*/
+#define AB8500_CODEC_DEFAULT_SLAVE_ADDRESS_OF_CODEC 0xD
+#define AB8500_CODEC_DEFAULT_DIRECTION AB8500_CODEC_DIRECTION_OUT
+
+#define AB8500_CODEC_DEFAULT_MODE_IN AB8500_CODEC_MODE_VOICE
+#define AB8500_CODEC_DEFAULT_MODE_OUT AB8500_CODEC_MODE_VOICE
+
+#define AB8500_CODEC_DEFAULT_INPUT_SRC AB8500_CODEC_SRC_MICROPHONE_1A
+#define AB8500_CODEC_DEFAULT_OUTPUT_DEST AB8500_CODEC_DEST_HEADSET
+
+#define AB8500_CODEC_DEFAULT_VOLUME_LEFT_IN 75
+#define AB8500_CODEC_DEFAULT_VOLUME_RIGHT_IN 75
+#define AB8500_CODEC_DEFAULT_VOLUME_LEFT_OUT 75
+#define AB8500_CODEC_DEFAULT_VOLUME_RIGHT_OUT 75
+
+/*---------------------------------------------------------------------
+ * PRIVATE APIs
+ *--------------------------------------------------------------------*/
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch1(IN
+ t_ab8500_codec_slot
+ ad_slot,
+ IN
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation
+ value);
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch2(IN
+ t_ab8500_codec_slot
+ ad_slot,
+ IN
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation
+ value);
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch3(IN
+ t_ab8500_codec_slot
+ ad_slot,
+ IN
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation
+ value);
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch4(IN
+ t_ab8500_codec_slot
+ ad_slot,
+ IN
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation
+ value);
+PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch1(IN
+ t_ab8500_codec_src
+ src_device,
+ t_ab8500_codec_src_state
+ state);
+PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch2(IN
+ t_ab8500_codec_src
+ src_device,
+ t_ab8500_codec_src_state
+ state);
+PRIVATE t_ab8500_codec_error ab8500_codec_SetModeAndDirectionUpdateCR(void);
+PRIVATE t_ab8500_codec_error ab8500_codec_SetSrcVolumeUpdateCR(void);
+PRIVATE t_ab8500_codec_error ab8500_codec_SetDestVolumeUpdateCR(void);
+PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionIN(void);
+PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionOUT(void);
+PRIVATE t_ab8500_codec_error ab8500_codec_DestPowerControlUpdateCR(void);
+
+/********************************************************************************************/
+/* Name: ab8500_codec_SingleWrite */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_SingleWrite(t_uint8 register_offset,
+ t_uint8 data)
+{
+ return (t_ab8500_codec_error) (AB8500_CODEC_Write
+ (register_offset, 0x01, &data));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_SingleRead */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_SingleRead(t_uint8 register_offset,
+ t_uint8 data)
+{
+ t_uint8 dummy_data = 0xAA;
+
+ return (t_ab8500_codec_error) (AB8500_CODEC_Read
+ (register_offset, 0x01, &dummy_data,
+ &data));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR0 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR0(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr0_powerup,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR0_POWERUP);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr0_enaana,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR0_ENAANA);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR0, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR1 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR1(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr1_swreset,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR1_SWRESET);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR1, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR2 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR2(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr2_enad1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR2_ENAD1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr2_enad2,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR2_ENAD2);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr2_enad3,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR2_ENAD3);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr2_enad4,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR2_ENAD4);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr2_enad5,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR2_ENAD5);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr2_enad6,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR2_ENAD6);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR2, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR3 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR3(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr3_enda1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR3_ENDA1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr3_enda2,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR3_ENDA2);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr3_enda3,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR3_ENDA3);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr3_enda4,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR3_ENDA4);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr3_enda5,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR3_ENDA5);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr3_enda6,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR3_ENDA6);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR3, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR4 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR4(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr4_lowpowhs,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR4_LOWPOWHS);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr4_lowpowdachs,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR4_LOWPOWDACHS);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr4_lowpowear,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR4_LOWPOWEAR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr4_ear_sel_cm,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR4_EAR_SEL_CM);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr4_hs_hp_dis,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR4_HS_HP_DIS);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr4_ear_hp_dis,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR4_EAR_HP_DIS);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR4, value));
+}
+#endif
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR5 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR5(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr5_enmic1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_ENMIC1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr5_enmic2,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_ENMIC2);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr5_enlinl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_ENLINL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr5_enlinr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_ENLINR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr5_mutmic1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_MUTMIC1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr5_mutmic2,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_MUTMIC2);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr5_mutlinl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_MUTELINL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr5_mutlinr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR5_MUTELINR);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR5, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR6 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR6(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr6_endmic1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR6_ENDMIC1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr6_endmic2,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR6_ENDMIC2);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr6_endmic3,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR6_ENDMIC3);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr6_endmic4,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR6_ENDMIC4);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr6_endmic5,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR6_ENDMIC5);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr6_endmic6,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR6_ENDMIC6);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR6, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR7 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR7(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr7_mic1sel,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_MIC1SEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr7_linrsel,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_LINRSEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr7_endrvhsl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_ENDRVHSL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr7_endrvhsr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_ENDRVHSR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr7_enadcmic,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_ENADCMIC);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr7_enadclinl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_ENADCLINL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr7_enadclinr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR7_ENADCLINR);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR7, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR8 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR8(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr8_cp_dis_pldwn,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_CP_DIS_PLDWN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr8_enear,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENEAR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr8_enhsl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENHSL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr8_enhsr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENHSR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr8_enhfl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENHFL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr8_enhfr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENHFR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr8_envibl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENVIBL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr8_envibr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR8_ENVIBR);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR8, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR9 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR9(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr9_endacear,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACEAR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr9_endachsl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACHSL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr9_endachsr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACHSR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr9_endachfl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACHFL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr9_endachfr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACHFR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr9_endacvibl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACVIBL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr9_endacvibr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR9_ENADACVIBR);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR9, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR10 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR10(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr10_muteear,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEEAR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr10_mutehsl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEHSL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr10_mutehsr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEHSR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr10_mutehfl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEHFL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr10_mutehfr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEHFR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr10_mutevibl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEVIBL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr10_mutevibr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR10_MUTEVIBR);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR10, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR11 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR11(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr11_earshortpwd,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_ENSHORTPWD);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr11_earshortdis,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_EARSHORTDIS);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr11_hslshortdis,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_HSLSHORTDIS);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr11_hsrshortdis,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_HSRSHORTDIS);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr11_hflshortdis,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_HFLSHORTDIS);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr11_hfrshortdis,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_HFRSHORTDIS);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr11_viblshortdis,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_VIBLSHORTDIS);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr11_vibrshortdis,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR11_VIBRSHORTDIS);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR11, value));
+}
+
+#endif
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR12 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR12(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr12_encphs,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR12_ENCPHS);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr12_hsautotime,
+ AB8500_CODEC_MASK_THREE_BITS, AB8500_CODEC_CR12_HSAUTOTIME);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr12_hsautoensel,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR12_HSAUTOENSEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr12_hsautoen,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR12_HSAUTOEN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR12, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR13 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR13(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr13_envdet_hthresh,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR13_ENVDET_HTHRESH);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr13_envdet_lthresh,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR13_ENVDET_LTHRESH);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR13, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR14 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR14(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr14_smpslven,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR14_SMPSLVEN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr14_envdetsmpsen,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR14_ENVDETSMPSEN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr14_cplven,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR14_CPLVEN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr14_envdetcpen,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR14_ENVDETCPEN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr14_envet_time,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR14_ENVDET_TIME);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR14, value));
+}
+#endif
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR15 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR15(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr15_pwmtovibl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMTOVIBL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr15_pwmtovibr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMTOVIBR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr15_pwmlctrl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMLCTRL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr15_pwmrctrl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMRCTRL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr15_pwmnlctrl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMNLCTRL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr15_pwmplctrl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMPLCTRL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr15_pwmnrctrl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMNRCTRL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr15_pwmprctrl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR15_PWMPRCTRL);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR15, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR16 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR16(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr16_pwmnlpol,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR16_PWMNLPOL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr16_pwmnldutycycle,
+ AB8500_CODEC_MASK_SEVEN_BITS, AB8500_CODEC_CR16_PWMNLDUTYCYCLE);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR16, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR17 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR17(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr17_pwmplpol,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR17_PWMPLPOL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr17_pwmpldutycycle,
+ AB8500_CODEC_MASK_SEVEN_BITS, AB8500_CODEC_CR17_PWMLPDUTYCYCLE);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR17, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR18 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR18(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr18_pwmnrpol,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR18_PWMNRPOL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr18_pwmnrdutycycle,
+ AB8500_CODEC_MASK_SEVEN_BITS, AB8500_CODEC_CR18_PWMNRDUTYCYCLE);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR18, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR19 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR19(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr19_pwmprpol,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR19_PWMPRPOL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr19_pwmprdutycycle,
+ AB8500_CODEC_MASK_SEVEN_BITS, AB8500_CODEC_CR19_PWMRPDUTYCYCLE);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR19, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR20 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR20(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr20_en_se_mic1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR20_EN_SE_MIC1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr20_mic1_gain,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR20_MIC1_GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR20, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR21 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR21(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr21_en_se_mic2,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR21_EN_SE_MIC2);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr21_mic2_gain,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR21_MIC2_GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR21, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR22 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR22(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr22_hsl_gain,
+ AB8500_CODEC_MASK_THREE_BITS, AB8500_CODEC_CR22_HSL_GAIN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr22_linl_gain,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR22_LINL_GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR22, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR23 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR23(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr23_hsr_gain,
+ AB8500_CODEC_MASK_THREE_BITS, AB8500_CODEC_CR23_HSR_GAIN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr23_linr_gain,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR23_LINR_GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR23, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR24 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR24(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr24_lintohsl_gain,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR24_LINTOHSL_GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR24, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR25 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR25(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr25_lintohsr_gain,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR25_LINTOHSR_GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR25, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR26 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR26(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr26_ad1nh,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD1NH);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr26_ad2nh,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD2NH);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr26_ad3nh,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD3NH);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr26_ad4nh,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD4NH);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr26_ad1_voice,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD1_VOICE);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr26_ad2_voice,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD2_VOICE);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr26_ad3_voice,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD3_VOICE);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr26_ad4_voice,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR26_AD4_VOICE);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR26, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR27 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR27(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr27_en_mastgen,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR27_EN_MASTGEN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr27_if1_bitclk_osr,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR27_IF1_BITCLK_OSR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr27_enfs_bitclk1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR27_ENFS_BITCLK1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr27_if0_bitclk_osr,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR27_IF0_BITCLK_OSR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr27_enfs_bitclk0,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR27_ENFS_BITCLK0);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR27, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR28 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR28(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr28_fsync0p,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR28_FSYNC0P);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr28_bitclk0p,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR28_BITCLK0P);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr28_if0del,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR28_IF0DEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr28_if0format,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR28_IF0FORMAT);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr28_if0wl,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR28_IF0WL);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR28, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR29 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR29(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr29_if0datoif1ad,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF0DATOIF1AD);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr29_if0cktoif1ck,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF0CKTOIF1CK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr29_if1master,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF1MASTER);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr29_if1datoif0ad,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF1DATOIF0AD);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr29_if1cktoif0ck,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF1CKTOIF0CK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr29_if0master,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF0MASTER);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr29_if0bfifoen,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR29_IF0BFIFOEN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR29, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR30 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR30(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr30_fsync1p,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR30_FSYNC1P);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr30_bitclk1p,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR30_BITCLK1P);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr30_if1del,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR30_IF1DEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr30_if1format,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR30_IF1FORMAT);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr30_if1wl,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR30_IF1WL);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR30, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR31 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR31(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr31_adotoslot1,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR31_ADOTOSLOT1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr31_adotoslot0,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR31_ADOTOSLOT0);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR31, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR32 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR32(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr32_adotoslot3,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR32_ADOTOSLOT3);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr32_adotoslot2,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR32_ADOTOSLOT2);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR32, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR33 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR33(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr33_adotoslot5,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR33_ADOTOSLOT5);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr33_adotoslot4,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR33_ADOTOSLOT4);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR33, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR34 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR34(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr34_adotoslot7,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR34_ADOTOSLOT7);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr34_adotoslot6,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR34_ADOTOSLOT6);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR34, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR35 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR35(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr35_adotoslot9,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR35_ADOTOSLOT9);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr35_adotoslot8,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR35_ADOTOSLOT8);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR35, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR36 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR36(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr36_adotoslot11,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR36_ADOTOSLOT11);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr36_adotoslot10,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR36_ADOTOSLOT10);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR36, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR37 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR37(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr37_adotoslot13,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR37_ADOTOSLOT13);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr37_adotoslot12,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR37_ADOTOSLOT12);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR37, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR38 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR38(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr38_adotoslot15,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR38_ADOTOSLOT15);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr38_adotoslot14,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR38_ADOTOSLOT14);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR38, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR39 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR39(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr39_adotoslot17,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR39_ADOTOSLOT17);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr39_adotoslot16,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR39_ADOTOSLOT16);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR39, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR40 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR40(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr40_adotoslot19,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR40_ADOTOSLOT19);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr40_adotoslot18,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR40_ADOTOSLOT18);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR40, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR41 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR41(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr41_adotoslot21,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR41_ADOTOSLOT21);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr41_adotoslot20,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR41_ADOTOSLOT20);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR41, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR42 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR42(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr42_adotoslot23,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR42_ADOTOSLOT23);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr42_adotoslot22,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR42_ADOTOSLOT22);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR42, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR43 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR43(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr43_adotoslot25,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR43_ADOTOSLOT25);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr43_adotoslot24,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR43_ADOTOSLOT24);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR43, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR44 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR44(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr44_adotoslot27,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR44_ADOTOSLOT27);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr44_adotoslot26,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR44_ADOTOSLOT26);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR44, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR45 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR45(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr45_adotoslot29,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR45_ADOTOSLOT29);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr45_adotoslot28,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR45_ADOTOSLOT28);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR45, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR46 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR46(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr46_adotoslot31,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR46_ADOTOSLOT31);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr46_adotoslot30,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR46_ADOTOSLOT30);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR46, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR47 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR47(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl7,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL7);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl6,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL6);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl5,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL5);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl4,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL4);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl3,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL3);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl2,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL2);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr47_hiz_sl0,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR47_HIZ_SL0);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR47, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR48 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR48(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl15,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL15);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl14,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL14);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl13,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL13);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl12,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL12);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl11,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL11);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl10,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL10);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl9,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL9);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr48_hiz_sl8,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR48_HIZ_SL8);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR48, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR49 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR49(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl23,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL23);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl22,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL22);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl21,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL21);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl20,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL20);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl19,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL19);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl18,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL18);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl17,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL17);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr49_hiz_sl16,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR49_HIZ_SL16);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR49, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR50 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR50(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl31,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL31);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl30,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL30);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl29,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL29);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl28,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL28);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl27,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL27);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl26,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL26);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl25,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL25);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr50_hiz_sl24,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR50_HIZ_SL24);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR50, value));
+}
+
+#endif
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR51 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR51(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr51_da12_voice,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR51_DA12_VOICE);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr51_sldai1toslado1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR51_SLDAI1TOSLADO1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr51_sltoda1,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR51_SLTODA1);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR51, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR52 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR52(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr52_sldai2toslado2,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR52_SLDAI1TOSLADO2);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr52_sltoda2,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR52_SLTODA2);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR52, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR53 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR53(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr53_da34_voice,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR53_DA34_VOICE);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr53_sldai3toslado3,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR53_SLDAI1TOSLADO3);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr53_sltoda3,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR53_SLTODA3);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR53, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR54 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR54(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr54_sldai4toslado4,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR54_SLDAI1TOSLADO4);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr54_sltoda4,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR54_SLTODA4);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR54, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR55 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR55(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr55_da56_voice,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR55_DA56_VOICE);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr55_sldai5toslado5,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR55_SLDAI1TOSLADO5);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr55_sltoda5,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR55_SLTODA5);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR55, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR56 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR56(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr56_sldai6toslado7,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR56_SLDAI1TOSLADO6);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr56_sltoda6,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR56_SLTODA6);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR56, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR57 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR57(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr57_bfifull_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_BFIFULL_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr57_bfiempt_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_BFIEMPT_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr57_dachan_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_DACHAN_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr57_gain_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_GAIN_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr57_dspad_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_DSPAD_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr57_dspda_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_DSPDA_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr57_stfir_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR57_STFIR_MSK);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR57, value));
+}
+
+/* CR58 is Read Only */
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR59 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR59(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr59_vssready_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_VSSREADY_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr59_shrtvibl_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTVIBL_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr59_shrtvibr_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTVIBR_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr59_shrthfl_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTHFL_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr59_shrthfr_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTHFR_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr59_shrthsl_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTHSL_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr59_shrthsr_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTHSR_MSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr59_shrtear_msk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR59_SHRTEAR_MSK);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR59, value));
+}
+
+/* CR60 is Read Only */
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR61 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR61(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ /* 5 bits are Read Only */
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr61_fade_speed,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR61_FADE_SPEED);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR61, value));
+}
+#endif
+/* CR62 is Read Only */
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR63 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR63(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr63_datohslen,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_DATOHSLEN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr63_datohsren,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_DATOHSREN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr63_ad1sel,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_AD1SEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr63_ad2sel,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_AD2SEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr63_ad3sel,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_AD3SEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr63_ad5sel,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_AD5SEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr63_ad6sel,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_AD6SEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr63_ancsel,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR63_ANCSEL);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR63, value));
+}
+
+#if 0
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR64 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR64(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr64_datohfren,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR64_DATOHFREN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr64_datohflen,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR64_DATOHFLEN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr64_hfrsel,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR64_HFRSEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr64_hflsel,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR64_HFLSEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr64_stfir1sel,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR64_STFIR1SEL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr64_stfir2sel,
+ AB8500_CODEC_MASK_TWO_BITS, AB8500_CODEC_CR64_STFIR2SEL);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR64, value));
+}
+
+#endif
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR65 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR65(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr65_fadedis_ad1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR65_FADEDIS_AD1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr65_ad1gain,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR65_AD1GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR65, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR66 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR66(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr66_fadedis_ad2,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR66_FADEDIS_AD2);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr66_ad2gain,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR66_AD2GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR66, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR67 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR67(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr67_fadedis_ad3,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR67_FADEDIS_AD3);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr67_ad3gain,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR67_AD3GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR67, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR68 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR68(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr68_fadedis_ad4,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR68_FADEDIS_AD4);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr68_ad4gain,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR68_AD4GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR68, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR69 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR69(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr69_fadedis_ad5,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR69_FADEDIS_AD5);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr69_ad5gain,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR69_AD5GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR69, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR70 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR70(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr70_fadedis_ad6,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR70_FADEDIS_AD6);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr70_ad6gain,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR70_AD6GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR70, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR71 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR71(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr71_fadedis_da1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR71_FADEDIS_DA1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr71_da1gain,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR71_DA1GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR71, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR72 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR72(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr72_fadedis_da2,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR72_FADEDIS_DA2);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr72_da2gain,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR72_DA2GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR72, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR73 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR73(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr73_fadedis_da3,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR73_FADEDIS_DA3);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr73_da3gain,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR73_DA3GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR73, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR74 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR74(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr74_fadedis_da4,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR74_FADEDIS_DA4);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr74_da4gain,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR74_DA4GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR74, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR75 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR75(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr75_fadedis_da5,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR75_FADEDIS_DA5);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr75_da5gain,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR75_DA5GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR75, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR76 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR76(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr76_fadedis_da6,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR76_FADEDIS_DA6);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr76_da6gain,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR76_DA6GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR76, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR77 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR77(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr77_fadedis_ad1l,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR77_FADEDIS_AD1L);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr77_ad1lbgain_to_hfl,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR77_AD1LBGAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR77, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR78 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR78(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr78_fadedis_ad2l,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR78_FADEDIS_AD2L);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr78_ad2lbgain_to_hfr,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR78_AD2LBGAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR78, value));
+}
+#endif
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR79 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR79(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr79_hssinc1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR79_HSSINC1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr79_fadedis_hsl,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR79_FADEDIS_HSL);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr79_hsldgain,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR79_HSLDGAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR79, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR80 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR80(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr80_fadedis_hsr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR80_FADEDIS_HSR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr80_hsrdgain,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR80_HSRDGAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR80, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR81 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR81(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr81_stfir1gain,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR81_STFIR1GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR81, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR82 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR82(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr82_stfir2gain,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR82_STFIR2GAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR82, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR83 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR83(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr83_enanc,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR83_ENANC);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr83_anciirinit,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR83_ANCIIRINIT);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr83_ancfirupdate,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR83_ANCFIRUPDATE);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR83, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR84 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR84(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr84_ancinshift,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR84_ANCINSHIFT);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR84, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR85 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR85(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr85_ancfiroutshift,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR85_ANCFIROUTSHIFT);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR85, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR86 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR86(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr86_ancshiftout,
+ AB8500_CODEC_MASK_FIVE_BITS, AB8500_CODEC_CR86_ANCSHIFTOUT);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR86, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR87 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR87(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr87_ancfircoeff_msb,
+ AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR87_ANCFIRCOEFF_MSB);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR87, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR88 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR88(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr88_ancfircoeff_lsb,
+ AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR88_ANCFIRCOEFF_LSB);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR88, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR89 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR89(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr89_anciircoeff_msb,
+ AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR89_ANCIIRCOEFF_MSB);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR89, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR90 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR90(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr90_anciircoeff_lsb,
+ AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR90_ANCIIRCOEFF_LSB);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR90, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR91 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR91(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr91_ancwarpdel_msb,
+ AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR91_ANCWARPDEL_MSB);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR91, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR92 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR92(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr92_ancwarpdel_lsb,
+ AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR92_ANCWARPDEL_LSB);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR92, value));
+}
+
+/* CR93 is Read Only */
+/* CR94 is Read Only */
+/* CR95 is Read Only */
+/* CR96 is Read Only */
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR97 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR97(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr97_stfir_set,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR97_STFIR_SET);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr97_stfir_addr,
+ AB8500_CODEC_MASK_SEVEN_BITS, AB8500_CODEC_CR97_STFIR_ADDR);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR97, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR98 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR98(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr98_stfir_coeff_msb,
+ AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR98_STFIR_COEFF_MSB);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR98, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR99 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR99(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr99_stfir_coeff_lsb,
+ AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR99_STFIR_COEFF_LSB);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR99, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR100 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR100(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr100_enstfirs,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR100_ENSTFIRS);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr100_stfirstoif1,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR100_STFIRSTOIF1);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr100_stfir_busy,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR100_STFIR_BUSY);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR100, value));
+}
+
+#endif
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR101 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR101(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr101_parlhf,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR101_PARLHF);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr101_parlvib,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR101_PARLVIB);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr101_classd_viblswapen,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR101_CLASSDVIBLSWAPEN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr101_classd_vibrswapen,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR101_CLASSDVIBRSWAPEN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr101_classd_hflswapen,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR101_CLASSDHFLSWAPEN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr101_classd_hfrswapen,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR101_CLASSDHFRSWAPEN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR101, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR102 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR102(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr102_classd_firbyp,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR102_CLASSD_FIRBYP);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr102_classd_highvolen,
+ AB8500_CODEC_MASK_FOUR_BITS, AB8500_CODEC_CR102_CLASSD_HIGHVOLEN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR102, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR103 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR103(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr103_classd_ditherhpgain,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR103_CLASSD_DITHERHPGAIN);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr103_classd_ditherwgain,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR103_CLASSD_DITHERWGAIN);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR103, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR104 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR104(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr104_bfifoint,
+ AB8500_CODEC_MASK_SIX_BITS, AB8500_CODEC_CR104_BFIFOINT);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR104, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR105 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR105(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr105_bfifotx,
+ AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR105_BFIFOTX);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR105, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR106 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR106(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr106_bfifofsext,
+ AB8500_CODEC_MASK_THREE_BITS, AB8500_CODEC_CR106_BFIFOFSEXT);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr106_bfifomsk,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR106_BFIFOMSK);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr106_bfifomstr,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR106_BFIFOMSTR);
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr106_bfifostrt,
+ AB8500_CODEC_MASK_ONE_BIT, AB8500_CODEC_CR106_BFIFOSTRT);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR106, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR107 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR107(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr107_bfifosampnr,
+ AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR107_BFIFOSAMPNR);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR107, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR108 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR108(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr108_bfifowakeup,
+ AB8500_CODEC_MASK_EIGHT_BITS, AB8500_CODEC_CR108_BFIFOWAKEUP);
+
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR108, value));
+}
+
+/* CR109 is Read Only */
+/********************************************************************************************/
+/* Name: ab8500_codec_Reset() */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_Reset(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ p_ab8500_codec_configuration->cr1_swreset =
+ AB8500_CODEC_CR1_SWRESET_ENABLED;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR1();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return (ab8500_codec_error);
+ }
+
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirection(IN
+ t_ab8500_codec_direction
+ ab8500_codec_direction)
+{ /*only IN or OUT must be passed (not INOUT) */
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+
+ if (AB8500_CODEC_DIRECTION_IN == ab8500_codec_direction) {
+ ab8500_codec_error = ab8500_codec_ProgramDirectionIN();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+
+ if (AB8500_CODEC_DIRECTION_OUT == ab8500_codec_direction) {
+ ab8500_codec_error = ab8500_codec_ProgramDirectionOUT();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_SetDirection(IN
+ t_ab8500_codec_direction
+ ab8500_codec_direction)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ switch (ab8500_codec_direction) {
+ case AB8500_CODEC_DIRECTION_IN:
+ ab8500_codec_error =
+ ab8500_codec_ProgramDirection(AB8500_CODEC_DIRECTION_IN);
+ break;
+
+ case AB8500_CODEC_DIRECTION_OUT:
+ ab8500_codec_error =
+ ab8500_codec_ProgramDirection(AB8500_CODEC_DIRECTION_OUT);
+ break;
+
+ case AB8500_CODEC_DIRECTION_INOUT:
+ ab8500_codec_error =
+ ab8500_codec_ProgramDirection(AB8500_CODEC_DIRECTION_IN);
+ if (AB8500_CODEC_OK == ab8500_codec_error) {
+ ab8500_codec_error =
+ ab8500_codec_ProgramDirection
+ (AB8500_CODEC_DIRECTION_OUT);
+ }
+ break;
+ }
+
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR5();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR6();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR7();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR8();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR9();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR10();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR12();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR15();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR63();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return (ab8500_codec_error);
+ }
+
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_Init */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Initialize the global variables & stores the slave address of codec. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* slave_address_of_ab8500_codec: Audio codec slave address */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* Returns AB8500_CODEC_OK */
+/* COMMENTS: */
+/* 1) Saves the supplied slave_address_of_codec in global variable */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_Init(IN t_uint8
+ slave_address_of_ab8500_codec)
+{
+ DBGENTER1(" (%lx)", slave_address_of_ab8500_codec);
+
+ g_ab8500_codec_system_context.slave_address_of_ab8500_codec =
+ slave_address_of_ab8500_codec;
+
+ DBGEXIT(AB8500_CODEC_OK);
+ return (AB8500_CODEC_OK);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_Reset */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Reset the global variables and clear audiocodec settings to default. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_Reset(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+
+ DBGENTER();
+
+ g_ab8500_codec_system_context.ab8500_codec_direction =
+ AB8500_CODEC_DEFAULT_DIRECTION;
+ g_ab8500_codec_system_context.ab8500_codec_mode_in =
+ AB8500_CODEC_DEFAULT_MODE_IN;
+ g_ab8500_codec_system_context.ab8500_codec_mode_out =
+ AB8500_CODEC_DEFAULT_MODE_OUT;
+
+ g_ab8500_codec_system_context.ab8500_codec_src =
+ AB8500_CODEC_DEFAULT_INPUT_SRC;
+ g_ab8500_codec_system_context.ab8500_codec_dest =
+ AB8500_CODEC_DEFAULT_OUTPUT_DEST;
+
+ g_ab8500_codec_system_context.in_left_volume =
+ AB8500_CODEC_DEFAULT_VOLUME_LEFT_IN;
+ g_ab8500_codec_system_context.in_right_volume =
+ AB8500_CODEC_DEFAULT_VOLUME_RIGHT_IN;
+ g_ab8500_codec_system_context.out_left_volume =
+ AB8500_CODEC_DEFAULT_VOLUME_LEFT_OUT;
+ g_ab8500_codec_system_context.out_right_volume =
+ AB8500_CODEC_DEFAULT_VOLUME_RIGHT_OUT;
+
+ ab8500_codec_error = ab8500_codec_Reset();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SetModeAndDirection */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Configures the whole audio codec to work in audio mode */
+/* (using I2S protocol). */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* direction: select the direction (IN, OUT or INOUT) */
+/* in_mode: codec mode for recording. If direction is OUT only, */
+/* this parameter is ignored. */
+/* out_mode: codec mode for playing. If direction is IN only, */
+/* this parameter is ignored. */
+/* p_tdm_config: TDM configuration required to be configured by user */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_UNSUPPORTED_FEATURE: The API may not allow setting */
+/* 2 different modes, in which case it should return this value. */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SetModeAndDirection
+ (IN t_ab8500_codec_direction ab8500_codec_direction,
+ IN t_ab8500_codec_mode ab8500_codec_mode_in,
+ IN t_ab8500_codec_mode ab8500_codec_mode_out,
+ IN t_ab8500_codec_tdm_config const *const p_tdm_config) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ DBGENTER3(" (%lx %lx %lx)", ab8500_codec_direction,
+ ab8500_codec_mode_in, ab8500_codec_mode_out);
+
+ if (AB8500_CODEC_AUDIO_INTERFACE_1 ==
+ g_ab8500_codec_system_context.audio_interface) {
+ if (AB8500_CODEC_DIRECTION_OUT == ab8500_codec_direction
+ || AB8500_CODEC_DIRECTION_INOUT == ab8500_codec_direction) {
+ p_ab8500_codec_configuration->cr3_enda1 =
+ AB8500_CODEC_CR3_ENDA1_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda2 =
+ AB8500_CODEC_CR3_ENDA2_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda3 =
+ AB8500_CODEC_CR3_ENDA3_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda4 =
+ AB8500_CODEC_CR3_ENDA4_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda5 =
+ AB8500_CODEC_CR3_ENDA5_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda6 =
+ AB8500_CODEC_CR3_ENDA6_ENABLED;
+
+ p_ab8500_codec_configuration->cr27_if1_bitclk_osr =
+ p_tdm_config->cr27_if1_bitclk_osr;
+
+ if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_out) {
+ p_ab8500_codec_configuration->cr30_fsync1p =
+ AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_bitclk1p =
+ AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_if1del =
+ AB8500_CODEC_CR30_IF1DEL_DELAYED;
+ p_ab8500_codec_configuration->cr30_if1format =
+ AB8500_CODEC_CR30_IF1FORMAT_I2S_LEFTALIGNED;
+ p_ab8500_codec_configuration->cr30_if1wl =
+ p_tdm_config->cr30_if1wl;
+ } else {
+ p_ab8500_codec_configuration->cr30_fsync1p =
+ AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_bitclk1p =
+ AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_if1del =
+ AB8500_CODEC_CR30_IF1DEL_DELAYED;
+ p_ab8500_codec_configuration->cr30_if1format =
+ AB8500_CODEC_CR30_IF1FORMAT_TDM;
+ p_ab8500_codec_configuration->cr30_if1wl =
+ p_tdm_config->cr30_if1wl;
+ }
+ }
+
+ if (AB8500_CODEC_DIRECTION_IN == ab8500_codec_direction
+ || AB8500_CODEC_DIRECTION_INOUT == ab8500_codec_direction) {
+ p_ab8500_codec_configuration->cr2_enad1 =
+ AB8500_CODEC_CR2_ENAD1_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad2 =
+ AB8500_CODEC_CR2_ENAD2_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad3 =
+ AB8500_CODEC_CR2_ENAD3_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad4 =
+ AB8500_CODEC_CR2_ENAD4_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad5 =
+ AB8500_CODEC_CR2_ENAD5_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad6 =
+ AB8500_CODEC_CR2_ENAD6_ENABLED;
+
+ p_ab8500_codec_configuration->cr27_if1_bitclk_osr =
+ p_tdm_config->cr27_if1_bitclk_osr;
+
+ if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_in) {
+ p_ab8500_codec_configuration->cr30_fsync1p =
+ AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_bitclk1p =
+ AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_if1del =
+ AB8500_CODEC_CR30_IF1DEL_DELAYED;
+ p_ab8500_codec_configuration->cr30_if1format =
+ AB8500_CODEC_CR30_IF1FORMAT_I2S_LEFTALIGNED;
+ p_ab8500_codec_configuration->cr30_if1wl =
+ p_tdm_config->cr30_if1wl;
+ } else {
+ p_ab8500_codec_configuration->cr30_fsync1p =
+ AB8500_CODEC_CR30_FSYNC1P_RISING_EDGE;
+ p_ab8500_codec_configuration->cr30_bitclk1p =
+ AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_if1del =
+ AB8500_CODEC_CR30_IF1DEL_NOT_DELAYED;
+ p_ab8500_codec_configuration->cr30_if1format =
+ AB8500_CODEC_CR30_IF1FORMAT_TDM;
+ p_ab8500_codec_configuration->cr30_if1wl =
+ p_tdm_config->cr30_if1wl;
+ }
+ }
+ } else {
+ if (AB8500_CODEC_DIRECTION_OUT == ab8500_codec_direction
+ || AB8500_CODEC_DIRECTION_INOUT == ab8500_codec_direction) {
+ p_ab8500_codec_configuration->cr3_enda1 =
+ AB8500_CODEC_CR3_ENDA1_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda2 =
+ AB8500_CODEC_CR3_ENDA2_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda3 =
+ AB8500_CODEC_CR3_ENDA3_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda4 =
+ AB8500_CODEC_CR3_ENDA4_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda5 =
+ AB8500_CODEC_CR3_ENDA5_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda6 =
+ AB8500_CODEC_CR3_ENDA6_ENABLED;
+
+ p_ab8500_codec_configuration->cr27_if0_bitclk_osr =
+ p_tdm_config->cr27_if0_bitclk_osr;
+
+ p_ab8500_codec_configuration->cr63_datohslen =
+ AB8500_CODEC_CR63_DATOHSLEN_ENABLED;
+ p_ab8500_codec_configuration->cr63_datohsren =
+ AB8500_CODEC_CR63_DATOHSREN_ENABLED;
+
+ if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_out) {
+ p_ab8500_codec_configuration->cr28_fsync0p =
+ AB8500_CODEC_CR28_FSYNC0P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; */
+ p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_DELAYED; */
+ p_ab8500_codec_configuration->cr28_if0format =
+ AB8500_CODEC_CR28_IF0FORMAT_I2S_LEFTALIGNED;
+ p_ab8500_codec_configuration->cr28_if0wl =
+ p_tdm_config->cr28_if0wl;
+ } else {
+ p_ab8500_codec_configuration->cr28_fsync0p =
+ AB8500_CODEC_CR28_FSYNC0P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; */
+ p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_DELAYED; */
+ p_ab8500_codec_configuration->cr28_if0format =
+ AB8500_CODEC_CR28_IF0FORMAT_TDM;
+ p_ab8500_codec_configuration->cr28_if0wl =
+ p_tdm_config->cr28_if0wl;
+ }
+ }
+
+ if (AB8500_CODEC_DIRECTION_IN == ab8500_codec_direction
+ || AB8500_CODEC_DIRECTION_INOUT == ab8500_codec_direction) {
+ p_ab8500_codec_configuration->cr2_enad1 =
+ AB8500_CODEC_CR2_ENAD1_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad2 =
+ AB8500_CODEC_CR2_ENAD2_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad3 =
+ AB8500_CODEC_CR2_ENAD3_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad4 =
+ AB8500_CODEC_CR2_ENAD4_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad5 =
+ AB8500_CODEC_CR2_ENAD5_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad6 =
+ AB8500_CODEC_CR2_ENAD6_ENABLED;
+
+ p_ab8500_codec_configuration->cr26_ad1_voice =
+ AB8500_CODEC_CR26_AD1_VOICE_LOWLATENCYFILTER;
+ p_ab8500_codec_configuration->cr26_ad2_voice =
+ AB8500_CODEC_CR26_AD2_VOICE_LOWLATENCYFILTER;
+ p_ab8500_codec_configuration->cr26_ad3_voice =
+ AB8500_CODEC_CR26_AD3_VOICE_LOWLATENCYFILTER;
+ p_ab8500_codec_configuration->cr26_ad4_voice =
+ AB8500_CODEC_CR26_AD4_VOICE_LOWLATENCYFILTER;
+
+ p_ab8500_codec_configuration->cr27_if0_bitclk_osr =
+ p_tdm_config->cr27_if0_bitclk_osr;
+
+ if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_in) {
+ p_ab8500_codec_configuration->cr28_fsync0p =
+ AB8500_CODEC_CR28_FSYNC0P_RISING_EDGE;
+ p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_RISING_EDGE; */
+ p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED; */
+ p_ab8500_codec_configuration->cr28_if0format =
+ AB8500_CODEC_CR28_IF0FORMAT_I2S_LEFTALIGNED;
+ p_ab8500_codec_configuration->cr28_if0wl =
+ p_tdm_config->cr28_if0wl;
+ } else {
+ p_ab8500_codec_configuration->cr28_fsync0p =
+ AB8500_CODEC_CR28_FSYNC0P_RISING_EDGE;
+ p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; */
+ p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED; */
+ p_ab8500_codec_configuration->cr28_if0format =
+ AB8500_CODEC_CR28_IF0FORMAT_TDM;
+ p_ab8500_codec_configuration->cr28_if0wl =
+ p_tdm_config->cr28_if0wl;
+ }
+ }
+ }
+
+ ab8500_codec_error = ab8500_codec_SetModeAndDirectionUpdateCR();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ g_ab8500_codec_system_context.ab8500_codec_direction =
+ ab8500_codec_direction;
+ g_ab8500_codec_system_context.ab8500_codec_mode_in =
+ ab8500_codec_mode_in;
+ g_ab8500_codec_system_context.ab8500_codec_mode_out =
+ ab8500_codec_mode_out;
+
+ ab8500_codec_error = ab8500_codec_SetDirection(ab8500_codec_direction);
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SetSrcVolume */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Sets the record volumes. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* t_ab8500_codec_src: select source device for recording. */
+/* in_left_volume: record volume for left channel. */
+/* in_right_volume: record volume for right channel. */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SetSrcVolume
+ (IN t_ab8500_codec_src src_device,
+ IN t_uint8 in_left_volume, IN t_uint8 in_right_volume) {
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ DBGENTER3(" (%lx %lx %lx)", src_device, in_left_volume,
+ in_right_volume);
+
+ if (in_left_volume > AB8500_CODEC_MAX_VOLUME) {
+ in_left_volume = AB8500_CODEC_MAX_VOLUME;
+ }
+
+ if (in_right_volume > AB8500_CODEC_MAX_VOLUME) {
+ in_right_volume = AB8500_CODEC_MAX_VOLUME;
+ }
+
+ g_ab8500_codec_system_context.in_left_volume = in_left_volume;
+ g_ab8500_codec_system_context.in_right_volume = in_right_volume;
+
+ p_ab8500_codec_configuration->cr65_ad1gain =
+ AB8500_CODEC_AD_D_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_AD_D_VOLUME_MAX -
+ AB8500_CODEC_AD_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr66_ad2gain =
+ AB8500_CODEC_AD_D_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_AD_D_VOLUME_MAX -
+ AB8500_CODEC_AD_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr67_ad3gain =
+ AB8500_CODEC_AD_D_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_AD_D_VOLUME_MAX -
+ AB8500_CODEC_AD_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr68_ad4gain =
+ AB8500_CODEC_AD_D_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_AD_D_VOLUME_MAX -
+ AB8500_CODEC_AD_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr69_ad5gain =
+ AB8500_CODEC_AD_D_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_AD_D_VOLUME_MAX -
+ AB8500_CODEC_AD_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr70_ad6gain =
+ AB8500_CODEC_AD_D_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_AD_D_VOLUME_MAX -
+ AB8500_CODEC_AD_D_VOLUME_MIN)) / 100;
+
+ /* Set mininimum volume if volume is zero */
+ switch (src_device) {
+ case AB8500_CODEC_SRC_LINEIN:
+ p_ab8500_codec_configuration->cr22_linl_gain =
+ AB8500_CODEC_LINEIN_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_LINEIN_VOLUME_MAX -
+ AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr23_linr_gain =
+ AB8500_CODEC_LINEIN_VOLUME_MIN +
+ (in_right_volume *
+ (AB8500_CODEC_LINEIN_VOLUME_MAX -
+ AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100;
+ break;
+
+ case AB8500_CODEC_SRC_MICROPHONE_1A:
+ case AB8500_CODEC_SRC_MICROPHONE_1B:
+ p_ab8500_codec_configuration->cr20_mic1_gain =
+ AB8500_CODEC_MIC_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_MIC_VOLUME_MAX -
+ AB8500_CODEC_MIC_VOLUME_MIN)) / 100;
+ break;
+
+ case AB8500_CODEC_SRC_MICROPHONE_2:
+ p_ab8500_codec_configuration->cr21_mic2_gain =
+ AB8500_CODEC_MIC_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_MIC_VOLUME_MAX -
+ AB8500_CODEC_MIC_VOLUME_MIN)) / 100;
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_1:
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_2:
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_3:
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_4:
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_5:
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_6:
+ break;
+
+ case AB8500_CODEC_SRC_ALL:
+ p_ab8500_codec_configuration->cr22_linl_gain =
+ AB8500_CODEC_LINEIN_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_LINEIN_VOLUME_MAX -
+ AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr23_linr_gain =
+ AB8500_CODEC_LINEIN_VOLUME_MIN +
+ (in_right_volume *
+ (AB8500_CODEC_LINEIN_VOLUME_MAX -
+ AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100;
+
+ p_ab8500_codec_configuration->cr20_mic1_gain =
+ AB8500_CODEC_MIC_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_MIC_VOLUME_MAX -
+ AB8500_CODEC_MIC_VOLUME_MIN)) / 100;
+
+ p_ab8500_codec_configuration->cr21_mic2_gain =
+ AB8500_CODEC_MIC_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_MIC_VOLUME_MAX -
+ AB8500_CODEC_MIC_VOLUME_MIN)) / 100;
+ break;
+
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_SetSrcVolumeUpdateCR();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SetDestVolume */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Sets the play volumes. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* out_left_volume: play volume for left channel. */
+/* out_right_volume: play volume for right channel. */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SetDestVolume
+ (IN t_ab8500_codec_dest dest_device,
+ IN t_uint8 out_left_volume, IN t_uint8 out_right_volume) {
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ DBGENTER3(" (%lx %lx %lx)", dest_device, out_left_volume,
+ out_right_volume);
+
+ if (out_left_volume > AB8500_CODEC_MAX_VOLUME) {
+ out_left_volume = AB8500_CODEC_MAX_VOLUME;
+ }
+
+ if (out_right_volume > AB8500_CODEC_MAX_VOLUME) {
+ out_right_volume = AB8500_CODEC_MAX_VOLUME;
+ }
+
+ g_ab8500_codec_system_context.out_left_volume = out_left_volume;
+ g_ab8500_codec_system_context.out_right_volume = out_right_volume;
+
+ p_ab8500_codec_configuration->cr71_da1gain =
+ AB8500_CODEC_DA_D_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_DA_D_VOLUME_MAX -
+ AB8500_CODEC_DA_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr72_da2gain =
+ AB8500_CODEC_DA_D_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_DA_D_VOLUME_MAX -
+ AB8500_CODEC_DA_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr73_da3gain =
+ AB8500_CODEC_DA_D_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_DA_D_VOLUME_MAX -
+ AB8500_CODEC_DA_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr74_da4gain =
+ AB8500_CODEC_DA_D_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_DA_D_VOLUME_MAX -
+ AB8500_CODEC_DA_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr75_da5gain =
+ AB8500_CODEC_DA_D_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_DA_D_VOLUME_MAX -
+ AB8500_CODEC_DA_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr76_da6gain =
+ AB8500_CODEC_DA_D_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_DA_D_VOLUME_MAX -
+ AB8500_CODEC_DA_D_VOLUME_MIN)) / 100;
+
+ /* Set mininimum volume if volume is zero */
+ switch (dest_device) {
+ case AB8500_CODEC_DEST_HEADSET:
+ p_ab8500_codec_configuration->cr22_hsl_gain =
+ AB8500_CODEC_HEADSET_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_HEADSET_VOLUME_MAX -
+ AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr23_hsr_gain =
+ AB8500_CODEC_HEADSET_VOLUME_MIN +
+ (out_right_volume *
+ (AB8500_CODEC_HEADSET_VOLUME_MAX -
+ AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100;
+
+ p_ab8500_codec_configuration->cr79_hsldgain =
+ AB8500_CODEC_HEADSET_D_VOLUME_0DB;
+ p_ab8500_codec_configuration->cr80_hsrdgain =
+ AB8500_CODEC_HEADSET_D_VOLUME_0DB;
+ break;
+
+ case AB8500_CODEC_DEST_EARPIECE:
+ p_ab8500_codec_configuration->cr79_hsldgain =
+ AB8500_CODEC_HEADSET_D_VOLUME_0DB;
+ break;
+
+ case AB8500_CODEC_DEST_HANDSFREE:
+
+ p_ab8500_codec_configuration->cr101_parlhf =
+ AB8500_CODEC_CR101_PARLHF_INDEPENDENT;
+ p_ab8500_codec_configuration->cr101_parlvib =
+ AB8500_CODEC_CR101_PARLVIB_INDEPENDENT;
+ p_ab8500_codec_configuration->cr101_classd_viblswapen =
+ AB8500_CODEC_CR101_CLASSD_VIBLSWAPEN_DISABLED;
+ p_ab8500_codec_configuration->cr101_classd_vibrswapen =
+ AB8500_CODEC_CR101_CLASSD_VIBRSWAPEN_DISABLED;
+ p_ab8500_codec_configuration->cr101_classd_hflswapen =
+ AB8500_CODEC_CR101_CLASSD_HFLSWAPEN_DISABLED;
+ p_ab8500_codec_configuration->cr101_classd_hfrswapen =
+ AB8500_CODEC_CR101_CLASSD_HFRSWAPEN_DISABLED;
+
+ p_ab8500_codec_configuration->cr102_classd_firbyp =
+ AB8500_CODEC_CR102_CLASSD_FIRBYP_ALL_ENABLED;
+ p_ab8500_codec_configuration->cr102_classd_highvolen =
+ AB8500_CODEC_CR102_CLASSD_HIGHVOLEN_DISABLED;
+
+ p_ab8500_codec_configuration->cr103_classd_ditherhpgain = 0x8;
+ p_ab8500_codec_configuration->cr103_classd_ditherwgain = 0x4;
+
+ break;
+
+ case AB8500_CODEC_DEST_VIBRATOR_L:
+ p_ab8500_codec_configuration->cr16_pwmnldutycycle =
+ AB8500_CODEC_VIBRATOR_VOLUME_MIN;
+ p_ab8500_codec_configuration->cr17_pwmpldutycycle =
+ AB8500_CODEC_VIBRATOR_VOLUME_MIN +
+ (out_right_volume *
+ (AB8500_CODEC_VIBRATOR_VOLUME_MAX -
+ AB8500_CODEC_VIBRATOR_VOLUME_MIN)) / 100;
+ break;
+
+ case AB8500_CODEC_DEST_VIBRATOR_R:
+ p_ab8500_codec_configuration->cr18_pwmnrdutycycle =
+ AB8500_CODEC_VIBRATOR_VOLUME_MIN;
+ p_ab8500_codec_configuration->cr19_pwmprdutycycle =
+ AB8500_CODEC_VIBRATOR_VOLUME_MIN +
+ (out_right_volume *
+ (AB8500_CODEC_VIBRATOR_VOLUME_MAX -
+ AB8500_CODEC_VIBRATOR_VOLUME_MIN)) / 100;
+ break;
+
+ case AB8500_CODEC_DEST_ALL:
+ p_ab8500_codec_configuration->cr22_hsl_gain =
+ AB8500_CODEC_HEADSET_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_HEADSET_VOLUME_MAX -
+ AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr23_hsr_gain =
+ AB8500_CODEC_HEADSET_VOLUME_MIN +
+ (out_right_volume *
+ (AB8500_CODEC_HEADSET_VOLUME_MAX -
+ AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100;
+
+ p_ab8500_codec_configuration->cr79_hsldgain =
+ AB8500_CODEC_HEADSET_D_VOLUME_0DB;
+ break;
+
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_SetDestVolumeUpdateCR();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SetMasterMode */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Set the Audio Codec in Master mode. */
+/* */
+/* ARGUMENTS */
+/* IN: t_codec_master_mode: Enable/disable master mode */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/* REMARK: Call this API after calling AB8500_CODEC_SetModeAndDirection() API*/
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SetMasterMode(IN
+ t_ab8500_codec_master_mode
+ mode)
+{
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER0();
+
+ if (AB8500_CODEC_AUDIO_INTERFACE_1 ==
+ g_ab8500_codec_system_context.audio_interface) {
+
+ p_ab8500_codec_configuration->cr27_en_mastgen =
+ AB8500_CODEC_CR27_EN_MASTGEN_ENABLED;
+ p_ab8500_codec_configuration->cr27_enfs_bitclk1 =
+ AB8500_CODEC_CR27_ENFS_BITCLK1_ENABLED;
+
+ if (AB8500_CODEC_MASTER_MODE_ENABLE == mode) {
+ p_ab8500_codec_configuration->cr29_if1master =
+ AB8500_CODEC_CR29_IF1MASTER_FS1CK1_OUTPUT;
+ } else {
+ p_ab8500_codec_configuration->cr29_if1master =
+ AB8500_CODEC_CR29_IF1MASTER_FS1CK1_INPUT;
+ }
+
+ } else {
+
+ p_ab8500_codec_configuration->cr27_en_mastgen =
+ AB8500_CODEC_CR27_EN_MASTGEN_ENABLED;
+ p_ab8500_codec_configuration->cr27_enfs_bitclk0 =
+ AB8500_CODEC_CR27_ENFS_BITCLK0_ENABLED;
+
+ if (AB8500_CODEC_MASTER_MODE_ENABLE == mode) {
+ p_ab8500_codec_configuration->cr29_if0master =
+ AB8500_CODEC_CR29_IF0MASTER_FS0CK0_OUTPUT;
+ } else {
+ p_ab8500_codec_configuration->cr29_if0master =
+ AB8500_CODEC_CR29_IF0MASTER_FS0CK0_INPUT;
+ }
+
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR27();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR29();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SelectInput */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Select input source for recording. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* input_src: select input source for recording when several sources */
+/* are supported in codec. */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_INVALID_PARAMETER: If input_src provided is invalid */
+/* by the codec hardware in use. */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SelectInput(IN t_ab8500_codec_src
+ ab8500_codec_src)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER1(" (%lx)", ab8500_codec_src);
+
+ g_ab8500_codec_system_context.ab8500_codec_src = ab8500_codec_src;
+
+ ab8500_codec_error =
+ ab8500_codec_SetDirection(AB8500_CODEC_DIRECTION_IN);
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SelectOutput */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Select output desination for playing. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* output_dest: select output destination for playing when several are */
+/* supported by codec hardware. */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_INVALID_PARAMETER: If output_src provided is invalid */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SelectOutput(IN t_ab8500_codec_dest
+ ab8500_codec_dest)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ g_ab8500_codec_system_context.ab8500_codec_dest = ab8500_codec_dest;
+ DBGENTER1(" (%lx)", ab8500_codec_dest);
+
+ ab8500_codec_error =
+ ab8500_codec_SetDirection(AB8500_CODEC_DIRECTION_OUT);
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_PowerDown */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Shuts the audio codec down completely. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* OUT: */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_PowerDown(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+
+ g_ab8500_codec_system_context.ab8500_codec_configuration.cr0_powerup =
+ AB8500_CODEC_CR0_POWERUP_OFF;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR0();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_PowerUp */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Switch on the audio codec. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_PowerUp(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+
+ DBGENTER();
+
+ /*g_ab8500_codec_system_context.ab8500_codec_configuration.cr1_swreset = AB8500_CODEC_CR1_SWRESET_ENABLED; Removed by kardad
+ ab8500_codec_error = ab8500_codec_UpdateCR1();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return(ab8500_codec_error);
+ } */
+
+ g_ab8500_codec_system_context.ab8500_codec_configuration.cr0_powerup =
+ AB8500_CODEC_CR0_POWERUP_ON;
+ g_ab8500_codec_system_context.ab8500_codec_configuration.cr0_enaana =
+ AB8500_CODEC_CR0_ENAANA_ON;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR0();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SelectInterface */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Select the Audio Interface 0 or 1. */
+/* */
+/* ARGUMENTS */
+/* IN: t_ab8500_codec_audio_interface: The selected interface */
+/* */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_OK: Always. */
+/* REMARK: Call this API before using a function of the low level drivers */
+/* to select the interface that you want to configure */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SelectInterface(IN
+ t_ab8500_codec_audio_interface
+ audio_interface)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER0();
+
+ g_ab8500_codec_system_context.audio_interface = audio_interface;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_GetInterface */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Get the Audio Interface 0 or 1. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: p_audio_interface: Store the selected interface */
+/* RETURN: */
+/* AB8500_CODEC_OK: Always */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Re-Entrant */
+/* REENTRANCY ISSUES: No Issues */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_GetInterface(OUT
+ t_ab8500_codec_audio_interface
+ * p_audio_interface)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER0();
+
+ *p_audio_interface = g_ab8500_codec_system_context.audio_interface;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SetAnalogLoopback */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Sets Line-In to HeadSet loopback with the required gain. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* out_left_volume: play volume for left channel. */
+/* out_right_volume: play volume for right channel. */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SetAnalogLoopback(IN t_uint8
+ out_left_volume,
+ IN t_uint8
+ out_right_volume)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ DBGENTER2(" (%lx %lx)", out_left_volume, out_right_volume);
+
+ if (out_left_volume > AB8500_CODEC_MAX_VOLUME) {
+ out_left_volume = AB8500_CODEC_MAX_VOLUME;
+ }
+
+ if (out_right_volume > AB8500_CODEC_MAX_VOLUME) {
+ out_right_volume = AB8500_CODEC_MAX_VOLUME;
+ }
+
+ g_ab8500_codec_system_context.out_left_volume = out_left_volume;
+ g_ab8500_codec_system_context.out_right_volume = out_right_volume;
+
+ p_ab8500_codec_configuration->cr24_lintohsl_gain =
+ AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MAX -
+ AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr25_lintohsr_gain =
+ AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN +
+ (out_right_volume *
+ (AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MAX -
+ AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN)) / 100;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR24();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR25();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_RemoveAnalogLoopback */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Remove Line-In to HeadSet loopback. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_RemoveAnalogLoopback(void)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ DBGENTER0();
+
+ p_ab8500_codec_configuration->cr24_lintohsl_gain =
+ AB8500_CODEC_LINEIN_TO_HS_L_R_LOOP_OPEN;
+ p_ab8500_codec_configuration->cr25_lintohsr_gain =
+ AB8500_CODEC_LINEIN_TO_HS_L_R_LOOP_OPEN;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR24();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR25();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_EnableBypassMode */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Enables IF0 to IF1 path or vice versa */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_EnableBypassMode(void)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ DBGENTER0();
+
+ if (AB8500_CODEC_AUDIO_INTERFACE_1 ==
+ g_ab8500_codec_system_context.audio_interface) {
+ p_ab8500_codec_configuration->cr29_if1datoif0ad =
+ AB8500_CODEC_CR29_IF1DATOIF0AD_SENT;
+ p_ab8500_codec_configuration->cr29_if1cktoif0ck =
+ AB8500_CODEC_CR29_IF1CKTOIF0CK_SENT;
+ } else {
+ p_ab8500_codec_configuration->cr29_if0datoif1ad =
+ AB8500_CODEC_CR29_IF0DATOIF1AD_SENT;
+ p_ab8500_codec_configuration->cr29_if0cktoif1ck =
+ AB8500_CODEC_CR29_IF0CKTOIF1CK_SENT;
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR29();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_DisableBypassMode */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Disables IF0 to IF1 path or vice versa */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_DisableBypassMode(void)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ DBGENTER0();
+
+ if (AB8500_CODEC_AUDIO_INTERFACE_1 ==
+ g_ab8500_codec_system_context.audio_interface) {
+ p_ab8500_codec_configuration->cr29_if1datoif0ad =
+ AB8500_CODEC_CR29_IF1DATOIF0AD_NOTSENT;
+ p_ab8500_codec_configuration->cr29_if1cktoif0ck =
+ AB8500_CODEC_CR29_IF1CKTOIF0CK_NOTSENT;
+ } else {
+ p_ab8500_codec_configuration->cr29_if0datoif1ad =
+ AB8500_CODEC_CR29_IF0DATOIF1AD_NOTSENT;
+ p_ab8500_codec_configuration->cr29_if0cktoif1ck =
+ AB8500_CODEC_CR29_IF0CKTOIF1CK_NOTSENT;
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR29();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SrcPowerControl */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Enables/Disables & UnMute/Mute the desired source */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* t_ab8500_codec_src: select source device for enabling/disabling. */
+/* t_ab8500_codec_src_state: Enable/Disable */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SrcPowerControl(IN t_ab8500_codec_src
+ src_device,
+ t_ab8500_codec_src_state
+ state)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+
+ DBGENTER2(" (%lx %lx)", src_device, state);
+
+ if (src_device <= AB8500_CODEC_SRC_D_MICROPHONE_2) {
+ ab8500_codec_error =
+ ab8500_codec_SrcPowerControlSwitch1(src_device, state);
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ } else if (src_device <= AB8500_CODEC_SRC_ALL) {
+ ab8500_codec_error =
+ ab8500_codec_SrcPowerControlSwitch2(src_device, state);
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ } else {
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR5();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR6();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR7();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR63();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_DestPowerControl */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Enables/Disables & UnMute/Mute the desired destination */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* t_ab8500_codec_dest: select destination device for enabling/disabling. */
+/* t_ab8500_codec_dest_state: Enable/Disable */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_DestPowerControl(IN t_ab8500_codec_dest
+ dest_device,
+ t_ab8500_codec_dest_state
+ state)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ DBGENTER2(" (%lx %lx)", dest_device, state);
+
+ switch (dest_device) {
+ case AB8500_CODEC_DEST_HEADSET:
+
+ if (AB8500_CODEC_DEST_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_DISABLED;
+ } else {
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED;
+ }
+ break;
+
+ case AB8500_CODEC_DEST_EARPIECE:
+
+ if (AB8500_CODEC_DEST_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacear =
+ AB8500_CODEC_CR9_ENDACEAR_ENABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_DISABLED;
+ } else {
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacear =
+ AB8500_CODEC_CR9_ENDACEAR_DISABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED;
+ }
+ break;
+
+ case AB8500_CODEC_DEST_HANDSFREE:
+
+ if (AB8500_CODEC_DEST_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfl =
+ AB8500_CODEC_CR9_ENDACHFL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfr =
+ AB8500_CODEC_CR9_ENDACHFR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehfl =
+ AB8500_CODEC_CR10_MUTEHFL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehfr =
+ AB8500_CODEC_CR10_MUTEHFR_DISABLED;
+ } else {
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endachfl =
+ AB8500_CODEC_CR9_ENDACHFL_DISABLED;
+ p_ab8500_codec_configuration->cr9_endachfr =
+ AB8500_CODEC_CR9_ENDACHFR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehfl =
+ AB8500_CODEC_CR10_MUTEHFL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehfr =
+ AB8500_CODEC_CR10_MUTEHFR_ENABLED;
+ }
+ break;
+
+ case AB8500_CODEC_DEST_VIBRATOR_L:
+
+ if (AB8500_CODEC_DEST_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibl =
+ AB8500_CODEC_CR9_ENDACVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutevibl =
+ AB8500_CODEC_CR10_MUTEVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibl =
+ AB8500_CODEC_CR15_PWMTOVIBL_PWM;
+ p_ab8500_codec_configuration->cr15_pwmlctrl =
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnlctrl =
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmplctrl =
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE;
+ } else {
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacvibl =
+ AB8500_CODEC_CR9_ENDACVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutevibl =
+ AB8500_CODEC_CR10_MUTEVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibl =
+ AB8500_CODEC_CR15_PWMTOVIBL_DA_PATH;
+ p_ab8500_codec_configuration->cr15_pwmlctrl =
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLGPOL;
+ p_ab8500_codec_configuration->cr15_pwmnlctrl =
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLGPOL;
+ p_ab8500_codec_configuration->cr15_pwmplctrl =
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLGPOL;
+ }
+ break;
+
+ case AB8500_CODEC_DEST_VIBRATOR_R:
+
+ if (AB8500_CODEC_DEST_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibr =
+ AB8500_CODEC_CR9_ENDACVIBR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutevibr =
+ AB8500_CODEC_CR10_MUTEVIBR_DISABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibr =
+ AB8500_CODEC_CR15_PWMTOVIBR_PWM;
+ p_ab8500_codec_configuration->cr15_pwmrctrl =
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnrctrl =
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmprctrl =
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE;
+ } else {
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacvibr =
+ AB8500_CODEC_CR9_ENDACVIBR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutevibr =
+ AB8500_CODEC_CR10_MUTEVIBR_ENABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibr =
+ AB8500_CODEC_CR15_PWMTOVIBR_DA_PATH;
+ p_ab8500_codec_configuration->cr15_pwmrctrl =
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRGPOL;
+ p_ab8500_codec_configuration->cr15_pwmnrctrl =
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRGPOL;
+ p_ab8500_codec_configuration->cr15_pwmprctrl =
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRGPOL;
+ }
+ break;
+
+ case AB8500_CODEC_DEST_ALL:
+
+ if (AB8500_CODEC_DEST_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_ENABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_ENABLED;
+
+ p_ab8500_codec_configuration->cr9_endacear =
+ AB8500_CODEC_CR9_ENDACEAR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfl =
+ AB8500_CODEC_CR9_ENDACHFL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfr =
+ AB8500_CODEC_CR9_ENDACHFR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibl =
+ AB8500_CODEC_CR9_ENDACVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibr =
+ AB8500_CODEC_CR9_ENDACVIBR_ENABLED;
+
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_DISABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehfl =
+ AB8500_CODEC_CR10_MUTEHFL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehfr =
+ AB8500_CODEC_CR10_MUTEHFR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutevibl =
+ AB8500_CODEC_CR10_MUTEVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutevibr =
+ AB8500_CODEC_CR10_MUTEVIBR_DISABLED;
+
+ p_ab8500_codec_configuration->cr15_pwmtovibl =
+ AB8500_CODEC_CR15_PWMTOVIBL_PWM;
+ p_ab8500_codec_configuration->cr15_pwmlctrl =
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnlctrl =
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmplctrl =
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmtovibr =
+ AB8500_CODEC_CR15_PWMTOVIBR_PWM;
+ p_ab8500_codec_configuration->cr15_pwmrctrl =
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnrctrl =
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmprctrl =
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE;
+ } else {
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_DISABLED;
+
+ p_ab8500_codec_configuration->cr9_endacear =
+ AB8500_CODEC_CR9_ENDACEAR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endachfl =
+ AB8500_CODEC_CR9_ENDACHFL_DISABLED;
+ p_ab8500_codec_configuration->cr9_endachfr =
+ AB8500_CODEC_CR9_ENDACHFR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacvibl =
+ AB8500_CODEC_CR9_ENDACVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacvibr =
+ AB8500_CODEC_CR9_ENDACVIBR_DISABLED;
+
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehfl =
+ AB8500_CODEC_CR10_MUTEHFL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehfr =
+ AB8500_CODEC_CR10_MUTEHFR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutevibl =
+ AB8500_CODEC_CR10_MUTEVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutevibr =
+ AB8500_CODEC_CR10_MUTEVIBR_ENABLED;
+
+ p_ab8500_codec_configuration->cr15_pwmtovibl =
+ AB8500_CODEC_CR15_PWMTOVIBL_DA_PATH;
+ p_ab8500_codec_configuration->cr15_pwmlctrl =
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLGPOL;
+ p_ab8500_codec_configuration->cr15_pwmnlctrl =
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLGPOL;
+ p_ab8500_codec_configuration->cr15_pwmplctrl =
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLGPOL;
+ p_ab8500_codec_configuration->cr15_pwmtovibr =
+ AB8500_CODEC_CR15_PWMTOVIBR_DA_PATH;
+ p_ab8500_codec_configuration->cr15_pwmrctrl =
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRGPOL;
+ p_ab8500_codec_configuration->cr15_pwmnrctrl =
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRGPOL;
+ p_ab8500_codec_configuration->cr15_pwmprctrl =
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRGPOL;
+
+ }
+ break;
+
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_DestPowerControlUpdateCR();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_GetVersion */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* This routine populates the pVersion structure with */
+/* the current version of HCL. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* p_version: this parameter is used to return current HCL version. */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_ERROR: if p_version is NULL. */
+/* AB8500_CODEC_OK: if successful */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Re-Entrant */
+/* REENTRANCY ISSUES: No Issues */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_GetVersion(OUT t_version * p_version)
+{
+ DBGENTER1(" (%lx)", p_version);
+ if (p_version != NULL) {
+ p_version->minor = AB8500_CODEC_HCL_MINOR_ID;
+ p_version->major = AB8500_CODEC_HCL_MAJOR_ID;
+ p_version->version = AB8500_CODEC_HCL_VERSION_ID;
+ DBGEXIT0(AB8500_CODEC_OK);
+ return (AB8500_CODEC_OK);
+ } else {
+ DBGEXIT0(AB8500_CODEC_INVALID_PARAMETER);
+ return (AB8500_CODEC_INVALID_PARAMETER);
+ }
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SetDbgLevel */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Set the debug level used by the debug module (mask-like value). */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* debug_level: debug level to be set */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_OK: always */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Re-Entrant */
+/* REENTRANCY ISSUES: No Issues */
+
+/****************************************************************************/
+/*
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SetDbgLevel(IN t_dbg_level dbg_level)
+{
+ DBGENTER1(" (%d)", dbg_level);
+ dbg_level = dbg_level;
+#ifdef __DEBUG
+ MY_DEBUG_LEVEL_VAR_NAME = dbg_level;
+#endif
+ DBGEXIT(AB8500_CODEC_OK);
+ return(AB8500_CODEC_OK);
+}*/
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_GetDbgLevel */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Set the debug level used by the debug module (mask-like value). */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* p_dbg_level: this parameter is used to return debug level. */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_ERROR: if p_version is NULL. */
+/* AB8500_CODEC_OK: if successful */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Re-Entrant */
+/* REENTRANCY ISSUES: No Issues */
+
+/****************************************************************************/
+/*
+PUBLIC t_ab8500_codec_error AB8500_CODEC_GetDbgLevel(OUT t_dbg_level *p_dbg_level)
+{
+ if (NULL == p_dbg_level)
+ {
+ DBGEXIT(AB8500_CODEC_INVALID_PARAMETER);
+ return(AB8500_CODEC_INVALID_PARAMETER);
+ }
+
+#ifdef __DEBUG
+ * p_dbg_level = MY_DEBUG_LEVEL_VAR_NAME;
+#endif
+ DBGEXIT(AB8500_CODEC_OK);
+ return(AB8500_CODEC_OK);
+}
+*/
+/****************************************************************************/
+/* NAME: AB8500_CODEC_ADSlotAllocation */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* AD Data Allocation in slots. */
+/* */
+/* ARGUMENTS */
+/* IN: t_ab8500_codec_slot: The slot to be allocated. */
+/* IN: t_ab8500_codec_cr31_to_cr46_ad_data_allocation: The value */
+/* to be allocated. */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_INVALID_PARAMETER: If invalid slot number */
+/* AB8500_CODEC_OK: if successful. */
+/* REMARK: */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_ADSlotAllocation
+ (IN t_ab8500_codec_slot ad_slot,
+ IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+
+ DBGENTER2(" (%lx %lx)", ad_slot, value);
+
+ if (ad_slot <= AB8500_CODEC_SLOT7) {
+ ab8500_codec_error =
+ ab8500_codec_ADSlotAllocationSwitch1(ad_slot, value);
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ } else if (ad_slot <= AB8500_CODEC_SLOT15) {
+ ab8500_codec_error =
+ ab8500_codec_ADSlotAllocationSwitch2(ad_slot, value);
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ } else if (ad_slot <= AB8500_CODEC_SLOT23) {
+ ab8500_codec_error =
+ ab8500_codec_ADSlotAllocationSwitch3(ad_slot, value);
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ } else if (ad_slot <= AB8500_CODEC_SLOT31) {
+ ab8500_codec_error =
+ ab8500_codec_ADSlotAllocationSwitch4(ad_slot, value);
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ } else {
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_DASlotAllocation */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Allocate the Audio Interface slot for DA paths. */
+/* */
+/* ARGUMENTS */
+/* IN: t_ab8500_codec_da_channel_number: Channel number 1/2/3/4/5/6 */
+/* IN: t_ab8500_codec_cr51_to_cr56_sltoda: Slot number */
+/* */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_INVALID_PARAMETER: If invalid channel number */
+/* AB8500_CODEC_OK: if successful. */
+/* REMARK: */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_DASlotAllocation
+ (IN t_ab8500_codec_da_channel_number channel_number,
+ IN t_ab8500_codec_cr51_to_cr56_sltoda slot) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ t_ab8500_codec_cr0_powerup ab8500_codec_cr0_powerup;
+
+ DBGENTER2(" (%lx %lx)", channel_number, slot);
+
+ p_ab8500_codec_configuration->cr51_da12_voice =
+ AB8500_CODEC_CR51_DA12_VOICE_LOWLATENCYFILTER;
+
+ switch (channel_number) {
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_1:
+ p_ab8500_codec_configuration->cr51_sltoda1 = slot;
+ break;
+
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_2:
+ p_ab8500_codec_configuration->cr52_sltoda2 = slot;
+ break;
+
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_3:
+ p_ab8500_codec_configuration->cr53_sltoda3 = slot;
+ break;
+
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_4:
+ p_ab8500_codec_configuration->cr54_sltoda4 = slot;
+ break;
+
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_5:
+ p_ab8500_codec_configuration->cr55_sltoda5 = slot;
+ break;
+
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_6:
+ p_ab8500_codec_configuration->cr56_sltoda6 = slot;
+ break;
+
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_cr0_powerup = p_ab8500_codec_configuration->cr0_powerup;
+
+ p_ab8500_codec_configuration->cr0_powerup =
+ AB8500_CODEC_CR0_POWERUP_OFF;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR0();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR51();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR52();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR53();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR54();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR55();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR56();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ p_ab8500_codec_configuration->cr0_powerup = ab8500_codec_cr0_powerup;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR0();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_ConfigureBurstFifo */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Configuration for Burst FIFO control */
+/* */
+/* ARGUMENTS */
+/* IN: t_ab8500_codec_burst_fifo_config: structure for configuration of */
+/* burst FIFO */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_INVALID_PARAMETER: If invalid parameter */
+/* AB8500_CODEC_UNSUPPORTED_FEATURE: If interface 1 selected */
+/* AB8500_CODEC_OK: if successful. */
+/* REMARK: */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+t_ab8500_codec_error AB8500_CODEC_ConfigureBurstFifo(IN
+ t_ab8500_codec_burst_fifo_config
+ const *const
+ p_burst_fifo_config)
+{
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER1(" (%lx)", p_burst_fifo_config);
+
+ if (AB8500_CODEC_AUDIO_INTERFACE_0 ==
+ g_ab8500_codec_system_context.audio_interface) {
+ if (AB8500_CODEC_CR27_EN_MASTGEN_ENABLED ==
+ p_ab8500_codec_configuration->cr27_en_mastgen) {
+ p_ab8500_codec_configuration->cr104_bfifoint =
+ p_burst_fifo_config->cr104_bfifoint;
+
+ p_ab8500_codec_configuration->cr105_bfifotx =
+ p_burst_fifo_config->cr105_bfifotx;
+
+ p_ab8500_codec_configuration->cr106_bfifofsext =
+ p_burst_fifo_config->cr106_bfifofsext;
+ p_ab8500_codec_configuration->cr106_bfifomsk =
+ p_burst_fifo_config->cr106_bfifomsk;
+ p_ab8500_codec_configuration->cr106_bfifomstr =
+ p_burst_fifo_config->cr106_bfifomstr;
+ p_ab8500_codec_configuration->cr106_bfifostrt =
+ p_burst_fifo_config->cr106_bfifostrt;
+
+ p_ab8500_codec_configuration->cr107_bfifosampnr =
+ p_burst_fifo_config->cr107_bfifosampnr;
+
+ p_ab8500_codec_configuration->cr108_bfifowakeup =
+ p_burst_fifo_config->cr108_bfifowakeup;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR104();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR105();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR106();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR107();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR108();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ } else {
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ } else {
+ ab8500_codec_error = AB8500_CODEC_UNSUPPORTED_FEATURE;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_EnableBurstFifo */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Enable the Burst FIFO for Interface 0 */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_UNSUPPORTED_FEATURE: If Interface 1 is selected */
+/* AB8500_CODEC_OK: if successful. */
+/* REMARK: */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_EnableBurstFifo(void)
+{
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER0();
+
+ if (AB8500_CODEC_AUDIO_INTERFACE_0 ==
+ g_ab8500_codec_system_context.audio_interface) {
+ p_ab8500_codec_configuration->cr29_if0bfifoen =
+ AB8500_CODEC_CR29_IF0BFIFOEN_BURST_MODE;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR29();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ } else {
+ ab8500_codec_error = AB8500_CODEC_UNSUPPORTED_FEATURE;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_DisableBurstFifo */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Disable the Burst FIFO for Interface 0 */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_UNSUPPORTED_FEATURE: If Interface 1 is selected */
+/* AB8500_CODEC_OK: if successful. */
+/* REMARK: */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_DisableBurstFifo(void)
+{
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER0();
+
+ if (AB8500_CODEC_AUDIO_INTERFACE_0 ==
+ g_ab8500_codec_system_context.audio_interface) {
+ p_ab8500_codec_configuration->cr29_if0bfifoen =
+ AB8500_CODEC_CR29_IF0BFIFOEN_NORMAL_MODE;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR29();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ } else {
+ ab8500_codec_error = AB8500_CODEC_UNSUPPORTED_FEATURE;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch1
+ (IN t_ab8500_codec_slot ad_slot,
+ IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ switch (ad_slot) {
+ case AB8500_CODEC_SLOT0:
+ p_ab8500_codec_configuration->cr31_adotoslot0 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR31();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT1:
+ p_ab8500_codec_configuration->cr31_adotoslot1 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR31();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT2:
+ p_ab8500_codec_configuration->cr32_adotoslot2 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR32();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT3:
+ p_ab8500_codec_configuration->cr32_adotoslot3 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR32();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT4:
+ p_ab8500_codec_configuration->cr33_adotoslot4 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR33();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT5:
+ p_ab8500_codec_configuration->cr33_adotoslot5 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR33();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT6:
+ p_ab8500_codec_configuration->cr34_adotoslot6 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR34();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT7:
+ p_ab8500_codec_configuration->cr34_adotoslot7 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR34();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch2
+ (IN t_ab8500_codec_slot ad_slot,
+ IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ switch (ad_slot) {
+ case AB8500_CODEC_SLOT8:
+ p_ab8500_codec_configuration->cr35_adotoslot8 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR35();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT9:
+ p_ab8500_codec_configuration->cr35_adotoslot9 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR35();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT10:
+ p_ab8500_codec_configuration->cr36_adotoslot10 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR36();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT11:
+ p_ab8500_codec_configuration->cr36_adotoslot11 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR36();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT12:
+ p_ab8500_codec_configuration->cr37_adotoslot12 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR37();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT13:
+ p_ab8500_codec_configuration->cr37_adotoslot13 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR37();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT14:
+ p_ab8500_codec_configuration->cr38_adotoslot14 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR38();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT15:
+ p_ab8500_codec_configuration->cr38_adotoslot15 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR38();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch3
+ (IN t_ab8500_codec_slot ad_slot,
+ IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ switch (ad_slot) {
+ case AB8500_CODEC_SLOT16:
+ p_ab8500_codec_configuration->cr39_adotoslot16 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR39();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT17:
+ p_ab8500_codec_configuration->cr39_adotoslot17 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR39();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT18:
+ p_ab8500_codec_configuration->cr40_adotoslot18 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR40();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT19:
+ p_ab8500_codec_configuration->cr40_adotoslot19 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR40();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT20:
+ p_ab8500_codec_configuration->cr41_adotoslot20 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR41();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT21:
+ p_ab8500_codec_configuration->cr41_adotoslot21 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR41();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT22:
+ p_ab8500_codec_configuration->cr42_adotoslot22 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR42();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT23:
+ p_ab8500_codec_configuration->cr42_adotoslot23 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR42();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch4
+ (IN t_ab8500_codec_slot ad_slot,
+ IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ switch (ad_slot) {
+ case AB8500_CODEC_SLOT24:
+ p_ab8500_codec_configuration->cr43_adotoslot24 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR43();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT25:
+ p_ab8500_codec_configuration->cr43_adotoslot25 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR43();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT26:
+ p_ab8500_codec_configuration->cr44_adotoslot26 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR44();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT27:
+ p_ab8500_codec_configuration->cr44_adotoslot27 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR44();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT28:
+ p_ab8500_codec_configuration->cr45_adotoslot28 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR45();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT29:
+ p_ab8500_codec_configuration->cr45_adotoslot29 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR45();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT30:
+ p_ab8500_codec_configuration->cr46_adotoslot30 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR46();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ case AB8500_CODEC_SLOT31:
+ p_ab8500_codec_configuration->cr46_adotoslot31 = value;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR46();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch1(IN
+ t_ab8500_codec_src
+ src_device,
+ t_ab8500_codec_src_state
+ state)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ switch (src_device) {
+ case AB8500_CODEC_SRC_LINEIN:
+
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_linrsel =
+ AB8500_CODEC_CR7_LINRSEL_LINR;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_ENABLED;
+ } else {
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+
+ p_ab8500_codec_configuration->cr7_linrsel =
+ AB8500_CODEC_CR7_LINRSEL_MIC2;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+ }
+ break;
+
+ case AB8500_CODEC_SRC_MICROPHONE_1A:
+
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_mic1sel =
+ AB8500_CODEC_CR7_MIC1SEL_MIC1A;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ } else {
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_DISABLED;
+ }
+ break;
+
+ case AB8500_CODEC_SRC_MICROPHONE_1B:
+
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_mic1sel =
+ AB8500_CODEC_CR7_MIC1SEL_MIC1B;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ } else {
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_DISABLED;
+ }
+ break;
+
+ case AB8500_CODEC_SRC_MICROPHONE_2:
+
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_linrsel =
+ AB8500_CODEC_CR7_LINRSEL_MIC2;
+ } else {
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+
+ p_ab8500_codec_configuration->cr7_linrsel =
+ AB8500_CODEC_CR7_LINRSEL_LINR;
+ }
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_1:
+
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_ENABLED;
+
+ p_ab8500_codec_configuration->cr63_ad1sel =
+ AB8500_CODEC_CR63_AD1SEL_DMIC1_SELECTED;
+ } else {
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+
+ p_ab8500_codec_configuration->cr63_ad1sel =
+ AB8500_CODEC_CR63_AD1SEL_LINLADL_SELECTED;
+ }
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_2:
+
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_ENABLED;
+
+ p_ab8500_codec_configuration->cr63_ad2sel =
+ AB8500_CODEC_CR63_AD2SEL_DMIC2_SELECTED;
+ } else {
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+
+ p_ab8500_codec_configuration->cr63_ad2sel =
+ AB8500_CODEC_CR63_AD2SEL_LINRADR_SELECTED;
+ }
+ break;
+
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch2(IN
+ t_ab8500_codec_src
+ src_device,
+ t_ab8500_codec_src_state
+ state)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ switch (src_device) {
+ case AB8500_CODEC_SRC_D_MICROPHONE_3:
+
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_ENABLED;
+
+ p_ab8500_codec_configuration->cr63_ad3sel =
+ AB8500_CODEC_CR63_AD3SEL_DMIC3_SELECTED;
+ } else {
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+
+ p_ab8500_codec_configuration->cr63_ad3sel =
+ AB8500_CODEC_CR63_AD3SEL_ADMO_SELECTED;
+ }
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_4:
+
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_ENABLED;
+ } else {
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ }
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_5:
+
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_ENABLED;
+
+ p_ab8500_codec_configuration->cr63_ad5sel =
+ AB8500_CODEC_CR63_AD5SEL_DMIC5_SELECTED;
+ } else {
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+
+ p_ab8500_codec_configuration->cr63_ad5sel =
+ AB8500_CODEC_CR63_AD5SEL_AMADR_SELECTED;
+ }
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_6:
+
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_ENABLED;
+
+ p_ab8500_codec_configuration->cr63_ad6sel =
+ AB8500_CODEC_CR63_AD6SEL_DMIC6_SELECTED;
+ } else {
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+
+ p_ab8500_codec_configuration->cr63_ad6sel =
+ AB8500_CODEC_CR63_AD6SEL_ADMO_SELECTED;
+ }
+ break;
+
+ case AB8500_CODEC_SRC_ALL:
+
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state) {
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_DISABLED;
+ } else {
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_DISABLED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+ }
+ break;
+ case AB8500_CODEC_SRC_FM_RX:
+ break;
+
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_SetModeAndDirectionUpdateCR(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ t_ab8500_codec_cr0_powerup ab8500_codec_cr0_powerup;
+
+ ab8500_codec_cr0_powerup = p_ab8500_codec_configuration->cr0_powerup;
+
+ p_ab8500_codec_configuration->cr0_powerup =
+ AB8500_CODEC_CR0_POWERUP_OFF;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR0();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR2();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR3();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR26();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR28();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR30();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR63();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ p_ab8500_codec_configuration->cr0_powerup = ab8500_codec_cr0_powerup;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR0();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_SetSrcVolumeUpdateCR(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR20();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR21();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR22();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR23();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR65();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR66();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR67();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR68();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR69();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR70();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_SetDestVolumeUpdateCR(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR16();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR17();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR18();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR19();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR22();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR23();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR71();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR72();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR73();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR74();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR75();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR76();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR79();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR80();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR101();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR102();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR103();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionIN(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ switch (g_ab8500_codec_system_context.ab8500_codec_src) {
+ case AB8500_CODEC_SRC_LINEIN:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_linrsel =
+ AB8500_CODEC_CR7_LINRSEL_LINR;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_ENABLED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+
+ break;
+
+ case AB8500_CODEC_SRC_MICROPHONE_1A:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_mic1sel =
+ AB8500_CODEC_CR7_MIC1SEL_MIC1A;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+
+ break;
+
+ case AB8500_CODEC_SRC_MICROPHONE_1B:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_mic1sel =
+ AB8500_CODEC_CR7_MIC1SEL_MIC1B;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+
+ break;
+
+ case AB8500_CODEC_SRC_MICROPHONE_2:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_ENABLED;
+
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ p_ab8500_codec_configuration->cr7_linrsel =
+ AB8500_CODEC_CR7_LINRSEL_MIC2;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_DISABLED;
+
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_1:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+
+ p_ab8500_codec_configuration->cr63_ad1sel =
+ AB8500_CODEC_CR63_AD1SEL_DMIC1_SELECTED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_2:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+
+ p_ab8500_codec_configuration->cr63_ad2sel =
+ AB8500_CODEC_CR63_AD2SEL_DMIC2_SELECTED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_3:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+
+ p_ab8500_codec_configuration->cr63_ad3sel =
+ AB8500_CODEC_CR63_AD3SEL_DMIC3_SELECTED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_4:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_5:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+
+ p_ab8500_codec_configuration->cr63_ad5sel =
+ AB8500_CODEC_CR63_AD5SEL_DMIC5_SELECTED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+
+ break;
+
+ case AB8500_CODEC_SRC_D_MICROPHONE_6:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+
+ p_ab8500_codec_configuration->cr63_ad6sel =
+ AB8500_CODEC_CR63_AD6SEL_DMIC6_SELECTED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+
+ break;
+
+ case AB8500_CODEC_SRC_ALL:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_ENABLED;
+
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_DISABLED;
+
+ break;
+
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionOUT(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration *p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+
+ switch (g_ab8500_codec_system_context.ab8500_codec_dest) {
+ case AB8500_CODEC_DEST_HEADSET:
+ p_ab8500_codec_configuration->cr7_endrvhsl =
+ AB8500_CODEC_CR7_ENDRVHSL_ENABLED;
+ p_ab8500_codec_configuration->cr7_endrvhsr =
+ AB8500_CODEC_CR7_ENDRVHSR_ENABLED;
+
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_DISABLED;
+
+ p_ab8500_codec_configuration->cr9_endachsl =
+ AB8500_CODEC_CR9_ENDACHSL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachsr =
+ AB8500_CODEC_CR9_ENDACHSR_ENABLED;
+
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehfl =
+ AB8500_CODEC_CR10_MUTEHFL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehfr =
+ AB8500_CODEC_CR10_MUTEHFR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutevibl =
+ AB8500_CODEC_CR10_MUTEVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutevibr =
+ AB8500_CODEC_CR10_MUTEVIBR_ENABLED;
+
+ p_ab8500_codec_configuration->cr12_encphs =
+ AB8500_CODEC_CR12_ENCPHS_ENABLED;
+
+ break;
+
+ case AB8500_CODEC_DEST_EARPIECE:
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_DISABLED;
+
+ p_ab8500_codec_configuration->cr9_endacear =
+ AB8500_CODEC_CR9_ENDACEAR_ENABLED;
+
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehfl =
+ AB8500_CODEC_CR10_MUTEHFL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehfr =
+ AB8500_CODEC_CR10_MUTEHFR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutevibl =
+ AB8500_CODEC_CR10_MUTEVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutevibr =
+ AB8500_CODEC_CR10_MUTEVIBR_ENABLED;
+
+ break;
+
+ case AB8500_CODEC_DEST_HANDSFREE:
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_ENABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_DISABLED;
+
+ p_ab8500_codec_configuration->cr9_endachfl =
+ AB8500_CODEC_CR9_ENDACHFL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfr =
+ AB8500_CODEC_CR9_ENDACHFR_ENABLED;
+
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehfl =
+ AB8500_CODEC_CR10_MUTEHFL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehfr =
+ AB8500_CODEC_CR10_MUTEHFR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutevibl =
+ AB8500_CODEC_CR10_MUTEVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutevibr =
+ AB8500_CODEC_CR10_MUTEVIBR_ENABLED;
+
+ break;
+
+ case AB8500_CODEC_DEST_VIBRATOR_L:
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_DISABLED;
+
+ p_ab8500_codec_configuration->cr9_endacvibl =
+ AB8500_CODEC_CR9_ENDACVIBL_ENABLED;
+
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehfl =
+ AB8500_CODEC_CR10_MUTEHFL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehfr =
+ AB8500_CODEC_CR10_MUTEHFR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutevibl =
+ AB8500_CODEC_CR10_MUTEVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutevibr =
+ AB8500_CODEC_CR10_MUTEVIBR_ENABLED;
+
+ p_ab8500_codec_configuration->cr15_pwmtovibl =
+ AB8500_CODEC_CR15_PWMTOVIBL_PWM;
+ p_ab8500_codec_configuration->cr15_pwmlctrl =
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnlctrl =
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmplctrl =
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE;
+
+ break;
+
+ case AB8500_CODEC_DEST_VIBRATOR_R:
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_ENABLED;
+
+ p_ab8500_codec_configuration->cr9_endacvibr =
+ AB8500_CODEC_CR9_ENDACVIBR_ENABLED;
+
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehfl =
+ AB8500_CODEC_CR10_MUTEHFL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehfr =
+ AB8500_CODEC_CR10_MUTEHFR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutevibl =
+ AB8500_CODEC_CR10_MUTEVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutevibr =
+ AB8500_CODEC_CR10_MUTEVIBR_DISABLED;
+
+ p_ab8500_codec_configuration->cr15_pwmtovibr =
+ AB8500_CODEC_CR15_PWMTOVIBR_PWM;
+ p_ab8500_codec_configuration->cr15_pwmrctrl =
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnrctrl =
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmprctrl =
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE;
+
+ break;
+
+ case AB8500_CODEC_DEST_ALL:
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_ENABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_ENABLED;
+
+ p_ab8500_codec_configuration->cr9_endacear =
+ AB8500_CODEC_CR9_ENDACEAR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfl =
+ AB8500_CODEC_CR9_ENDACHFL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfr =
+ AB8500_CODEC_CR9_ENDACHFR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibl =
+ AB8500_CODEC_CR9_ENDACVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibr =
+ AB8500_CODEC_CR9_ENDACVIBR_ENABLED;
+
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_DISABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehfl =
+ AB8500_CODEC_CR10_MUTEHFL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehfr =
+ AB8500_CODEC_CR10_MUTEHFR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutevibl =
+ AB8500_CODEC_CR10_MUTEVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutevibr =
+ AB8500_CODEC_CR10_MUTEVIBR_DISABLED;
+
+ p_ab8500_codec_configuration->cr15_pwmtovibl =
+ AB8500_CODEC_CR15_PWMTOVIBL_PWM;
+ p_ab8500_codec_configuration->cr15_pwmlctrl =
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnlctrl =
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmplctrl =
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmtovibr =
+ AB8500_CODEC_CR15_PWMTOVIBR_PWM;
+ p_ab8500_codec_configuration->cr15_pwmrctrl =
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnrctrl =
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmprctrl =
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE;
+
+ break;
+
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_DestPowerControlUpdateCR(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+
+ ab8500_codec_error = ab8500_codec_UpdateCR8();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR9();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR10();
+ if (ab8500_codec_error != AB8500_CODEC_OK) {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+
+ ab8500_codec_error = ab8500_codec_UpdateCR15();
+
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
diff --git a/sound/ab8500_codec_v1_0.c b/sound/ab8500_codec_v1_0.c
new file mode 100644
index 00000000000..5df1ca3eae4
--- /dev/null
+++ b/sound/ab8500_codec_v1_0.c
@@ -0,0 +1,6405 @@
+/*****************************************************************************/
+
+/**
+* © ST-Ericsson, 2009 - All rights reserved
+* Reproduction and Communication of this document is strictly prohibited
+* unless specifically authorized in writing by ST-Ericsson
+*
+* \brief This module provides some support routines for the AB8500 CODEC
+* \author ST-Ericsson
+*/
+/*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * Includes
+ *---------------------------------------------------------------------------*/
+
+#ifdef CONFIG_U8500_AB8500_CUT10
+#include <mach/ab8500_codec_v1_0.h>
+#include <mach/ab8500_codec_p_v1_0.h>
+#else /* */
+#include <mach/ab8500_codec.h>
+#include <mach/ab8500_codec_p.h>
+#endif /* */
+
+/*--------------------------------------------------------------------------*
+ * debug stuff *
+ *--------------------------------------------------------------------------*/
+#ifdef __DEBUG
+#define MY_DEBUG_LEVEL_VAR_NAME myDebugLevel_AB8500_CODEC
+#define MY_DEBUG_ID myDebugID_AB8500_CODEC
+PRIVATE t_dbg_level MY_DEBUG_LEVEL_VAR_NAME = DEBUG_LEVEL0;
+PRIVATE t_dbg_id MY_DEBUG_ID = AB8500_CODEC_HCL_DBG_ID;
+
+#endif /* */
+
+/*--------------------------------------------------------------------------*
+ * Global data for interrupt mode management *
+ *--------------------------------------------------------------------------*/
+PRIVATE t_ab8500_codec_system_context g_ab8500_codec_system_context;
+
+/*--------------------------------------------------------------------------*
+ * Default Values *
+ *--------------------------------------------------------------------------*/
+#define AB8500_CODEC_DEFAULT_SLAVE_ADDRESS_OF_CODEC 0xD
+#define AB8500_CODEC_DEFAULT_DIRECTION AB8500_CODEC_DIRECTION_OUT
+
+#define AB8500_CODEC_DEFAULT_MODE_IN AB8500_CODEC_MODE_VOICE
+#define AB8500_CODEC_DEFAULT_MODE_OUT AB8500_CODEC_MODE_VOICE
+
+#define AB8500_CODEC_DEFAULT_INPUT_SRC AB8500_CODEC_SRC_MICROPHONE_1A
+#define AB8500_CODEC_DEFAULT_OUTPUT_DEST AB8500_CODEC_DEST_HEADSET
+
+#define AB8500_CODEC_DEFAULT_VOLUME_LEFT_IN 75
+#define AB8500_CODEC_DEFAULT_VOLUME_RIGHT_IN 75
+#define AB8500_CODEC_DEFAULT_VOLUME_LEFT_OUT 75
+#define AB8500_CODEC_DEFAULT_VOLUME_RIGHT_OUT 75
+
+/*---------------------------------------------------------------------
+ * PRIVATE APIs
+ *--------------------------------------------------------------------*/
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch1(IN
+ t_ab8500_codec_slot
+ ad_slot,
+ IN
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation
+ value);
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch2(IN
+ t_ab8500_codec_slot
+ ad_slot,
+ IN
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation
+ value);
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch3(IN
+ t_ab8500_codec_slot
+ ad_slot,
+ IN
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation
+ value);
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch4(IN
+ t_ab8500_codec_slot
+ ad_slot,
+ IN
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation
+ value);
+PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch1(IN
+ t_ab8500_codec_src
+ src_device,
+ t_ab8500_codec_src_state
+ state);
+PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch2(IN
+ t_ab8500_codec_src
+ src_device,
+ t_ab8500_codec_src_state
+ state);
+PRIVATE t_ab8500_codec_error ab8500_codec_SetModeAndDirectionUpdateCR(void);
+PRIVATE t_ab8500_codec_error ab8500_codec_SetSrcVolumeUpdateCR(void);
+PRIVATE t_ab8500_codec_error ab8500_codec_SetDestVolumeUpdateCR(void);
+PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionIN(void);
+PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionOUT(void);
+PRIVATE t_ab8500_codec_error ab8500_codec_DestPowerControlUpdateCR(void);
+
+/********************************************************************************************/
+/* Name: ab8500_codec_SingleWrite */
+/********************************************************************************************/
+ PRIVATE t_ab8500_codec_error ab8500_codec_SingleWrite(t_uint8
+ register_offset,
+ t_uint8 data)
+{
+ return (t_ab8500_codec_error) (AB8500_CODEC_Write
+ (register_offset, 0x01, &data));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_SingleRead */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_SingleRead(t_uint8
+ register_offset,
+ t_uint8 data)
+{
+ t_uint8 dummy_data = 0xAA;
+ return (t_ab8500_codec_error) (AB8500_CODEC_Read
+ (register_offset, 0x01, &dummy_data,
+ &data));
+}
+
+#endif /* */
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR0 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR0(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr0_powerup, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR0_POWERUP );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr0_enaana, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR0_ENAANA );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR0, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR1 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR1(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr1_swreset, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR1_SWRESET );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR1, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR2 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR2(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr2_enad1, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR2_ENAD1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr2_enad2, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR2_ENAD2 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr2_enad3, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR2_ENAD3 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr2_enad4, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR2_ENAD4 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr2_enad5, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR2_ENAD5 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr2_enad6, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR2_ENAD6 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR2, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR3 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR3(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr3_enda1, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR3_ENDA1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr3_enda2, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR3_ENDA2 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr3_enda3, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR3_ENDA3 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr3_enda4, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR3_ENDA4 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr3_enda5, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR3_ENDA5 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr3_enda6, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR3_ENDA6 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR3, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR4 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR4(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr4_lowpowhs, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR4_LOWPOWHS );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr4_lowpowdachs,
+ AB8500_CODEC_MASK_TWO_BITS,
+ AB8500_CODEC_CR4_LOWPOWDACHS );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr4_lowpowear, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR4_LOWPOWEAR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr4_ear_sel_cm, AB8500_CODEC_MASK_TWO_BITS,
+ AB8500_CODEC_CR4_EAR_SEL_CM );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr4_hs_hp_en, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR4_HS_HP_EN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR4, value));
+}
+
+#endif /* */
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR5 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR5(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr5_enmic1, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR5_ENMIC1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr5_enmic2, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR5_ENMIC2 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr5_enlinl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR5_ENLINL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr5_enlinr, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR5_ENLINR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr5_mutmic1, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR5_MUTMIC1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr5_mutmic2, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR5_MUTMIC2 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr5_mutlinl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR5_MUTELINL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr5_mutlinr, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR5_MUTELINR );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR5, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR6 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR6(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr6_endmic1, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR6_ENDMIC1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr6_endmic2, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR6_ENDMIC2 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr6_endmic3, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR6_ENDMIC3 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr6_endmic4, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR6_ENDMIC4 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr6_endmic5, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR6_ENDMIC5 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr6_endmic6, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR6_ENDMIC6 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR6, value));
+}
+
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR7 */
+/********************************************************************************************/
+ PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR7(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr7_mic1sel, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR7_MIC1SEL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr7_linrsel, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR7_LINRSEL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr7_endrvhsl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR7_ENDRVHSL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr7_endrvhsr, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR7_ENDRVHSR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr7_enadcmic, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR7_ENADCMIC );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr7_enadclinl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR7_ENADCLINL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr7_enadclinr, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR7_ENADCLINR );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR7, value));
+}
+
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR8 */
+/********************************************************************************************/
+ PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR8(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr8_cp_dis_pldwn,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR8_CP_DIS_PLDWN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr8_enear, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR8_ENEAR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr8_enhsl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR8_ENHSL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr8_enhsr, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR8_ENHSR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr8_enhfl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR8_ENHFL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr8_enhfr, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR8_ENHFR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr8_envibl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR8_ENVIBL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr8_envibr, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR8_ENVIBR );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR8, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR9 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR9(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr9_endacear, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR9_ENADACEAR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr9_endachsl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR9_ENADACHSL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr9_endachsr, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR9_ENADACHSR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr9_endachfl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR9_ENADACHFL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr9_endachfr, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR9_ENADACHFR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr9_endacvibl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR9_ENADACVIBL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr9_endacvibr, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR9_ENADACVIBR );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR9, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR10 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR10(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr10_muteear, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR10_MUTEEAR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr10_mutehsl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR10_MUTEHSL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr10_mutehsr, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR10_MUTEHSR );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR10, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR11 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR11(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr11_earshortpwd,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR11_ENSHORTPWD );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr11_earshortdis,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR11_EARSHORTDIS );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr11_hsshortdis, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR11_HSSHORTDIS );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr11_hspullden, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR11_HSPULLDEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr11_hsoscen, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR11_HSOSCEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr11_hsfaden, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR11_HSFADEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr11_hszcddis, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR11_HSZCDDIS );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR11, value));
+}
+
+#endif /* */
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR12 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR12(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr12_encphs, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR12_ENCPHS );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr12_hsautoen, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR12_HSAUTOEN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR12, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR13 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR13(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr13_envdet_hthresh,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR13_ENVDET_HTHRESH );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr13_envdet_lthresh,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR13_ENVDET_LTHRESH );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR13, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR14 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR14(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr14_smpslven, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR14_SMPSLVEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr14_envdetsmpsen,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR14_ENVDETSMPSEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr14_cplven, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR14_CPLVEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr14_envdetcpen, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR14_ENVDETCPEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr14_envet_time,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR14_ENVDET_TIME );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR14, value));
+}
+
+#endif /* */
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR15 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR15(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr15_pwmtovibl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR15_PWMTOVIBL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr15_pwmtovibr, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR15_PWMTOVIBR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr15_pwmlctrl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR15_PWMLCTRL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr15_pwmrctrl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR15_PWMRCTRL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr15_pwmnlctrl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR15_PWMNLCTRL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr15_pwmplctrl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR15_PWMPLCTRL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr15_pwmnrctrl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR15_PWMNRCTRL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr15_pwmprctrl, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR15_PWMPRCTRL );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR15, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR16 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR16(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr16_pwmnlpol, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR16_PWMNLPOL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr16_pwmnldutycycle,
+ AB8500_CODEC_MASK_SEVEN_BITS,
+ AB8500_CODEC_CR16_PWMNLDUTYCYCLE );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR16, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR17 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR17(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr17_pwmplpol, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR17_PWMPLPOL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr17_pwmpldutycycle,
+ AB8500_CODEC_MASK_SEVEN_BITS,
+ AB8500_CODEC_CR17_PWMLPDUTYCYCLE );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR17, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR18 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR18(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr18_pwmnrpol, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR18_PWMNRPOL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr18_pwmnrdutycycle,
+ AB8500_CODEC_MASK_SEVEN_BITS,
+ AB8500_CODEC_CR18_PWMNRDUTYCYCLE );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR18, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR19 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR19(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr19_pwmprpol, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR19_PWMPRPOL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr19_pwmprdutycycle,
+ AB8500_CODEC_MASK_SEVEN_BITS,
+ AB8500_CODEC_CR19_PWMRPDUTYCYCLE );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR19, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR20 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR20(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr20_en_se_mic1,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR20_EN_SE_MIC1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr20_low_pow_mic1,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR20_LOW_POW_MIC1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr20_mic1_gain,
+ AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR20_MIC1_GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR20, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR21 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR21(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr21_en_se_mic2,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR21_EN_SE_MIC2 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr21_low_pow_mic2,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR21_LOW_POW_MIC2 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr21_mic2_gain,
+ AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR21_MIC2_GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR21, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR22 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR22(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr22_hsl_gain,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR22_HSL_GAIN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr22_hsr_gain, AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR22_HSR_GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR22, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR23 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR23(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr23_linl_gain,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR23_LINL_GAIN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr23_linr_gain,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR23_LINR_GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR23, value));
+}
+
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR24 */
+/********************************************************************************************/
+ PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR24(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr24_lintohsl_gain,
+ AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR24_LINTOHSL_GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR24, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR25 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR25(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr25_lintohsr_gain,
+ AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR25_LINTOHSR_GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR25, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR26 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR26(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr26_ad1nh, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR26_AD1NH );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr26_ad2nh, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR26_AD2NH );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr26_ad3nh, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR26_AD3NH );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr26_ad4nh, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR26_AD4NH );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr26_ad1_voice, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR26_AD1_VOICE );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr26_ad2_voice, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR26_AD2_VOICE );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr26_ad3_voice, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR26_AD3_VOICE );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr26_ad4_voice, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR26_AD4_VOICE );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR26, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR27 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR27(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr27_en_mastgen,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR27_EN_MASTGEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr27_if1_bitclk_osr,
+ AB8500_CODEC_MASK_TWO_BITS,
+ AB8500_CODEC_CR27_IF1_BITCLK_OSR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr27_enfs_bitclk1,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR27_ENFS_BITCLK1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr27_if0_bitclk_osr,
+ AB8500_CODEC_MASK_TWO_BITS,
+ AB8500_CODEC_CR27_IF0_BITCLK_OSR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr27_enfs_bitclk0,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR27_ENFS_BITCLK0 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR27, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR28 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR28(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr28_fsync0p, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR28_FSYNC0P );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr28_bitclk0p, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR28_BITCLK0P );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr28_if0del, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR28_IF0DEL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr28_if0format, AB8500_CODEC_MASK_TWO_BITS,
+ AB8500_CODEC_CR28_IF0FORMAT );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr28_if0wl, AB8500_CODEC_MASK_TWO_BITS,
+ AB8500_CODEC_CR28_IF0WL );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR28, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR29 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR29(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr29_if0datoif1ad,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR29_IF0DATOIF1AD );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr29_if0cktoif1ck,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR29_IF0CKTOIF1CK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr29_if1master, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR29_IF1MASTER );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr29_if1datoif0ad,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR29_IF1DATOIF0AD );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr29_if1cktoif0ck,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR29_IF1CKTOIF0CK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr29_if0master, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR29_IF0MASTER );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr29_if0bfifoen, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR29_IF0BFIFOEN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR29, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR30 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR30(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr30_fsync1p, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR30_FSYNC1P );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr30_bitclk1p, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR30_BITCLK1P );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr30_if1del, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR30_IF1DEL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr30_if1format, AB8500_CODEC_MASK_TWO_BITS,
+ AB8500_CODEC_CR30_IF1FORMAT );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr30_if1wl, AB8500_CODEC_MASK_TWO_BITS,
+ AB8500_CODEC_CR30_IF1WL );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR30, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR31 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR31(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr31_adotoslot1,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR31_ADOTOSLOT1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr31_adotoslot0,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR31_ADOTOSLOT0 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR31, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR32 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR32(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr32_adotoslot3,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR32_ADOTOSLOT3 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr32_adotoslot2,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR32_ADOTOSLOT2 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR32, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR33 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR33(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr33_adotoslot5,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR33_ADOTOSLOT5 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr33_adotoslot4,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR33_ADOTOSLOT4 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR33, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR34 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR34(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr34_adotoslot7,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR34_ADOTOSLOT7 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr34_adotoslot6,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR34_ADOTOSLOT6 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR34, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR35 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR35(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr35_adotoslot9,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR35_ADOTOSLOT9 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr35_adotoslot8,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR35_ADOTOSLOT8 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR35, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR36 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR36(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr36_adotoslot11,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR36_ADOTOSLOT11 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr36_adotoslot10,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR36_ADOTOSLOT10 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR36, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR37 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR37(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr37_adotoslot13,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR37_ADOTOSLOT13 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr37_adotoslot12,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR37_ADOTOSLOT12 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR37, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR38 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR38(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr38_adotoslot15,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR38_ADOTOSLOT15 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr38_adotoslot14,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR38_ADOTOSLOT14 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR38, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR39 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR39(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr39_adotoslot17,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR39_ADOTOSLOT17 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr39_adotoslot16,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR39_ADOTOSLOT16 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR39, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR40 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR40(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr40_adotoslot19,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR40_ADOTOSLOT19 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr40_adotoslot18,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR40_ADOTOSLOT18 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR40, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR41 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR41(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr41_adotoslot21,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR41_ADOTOSLOT21 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr41_adotoslot20,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR41_ADOTOSLOT20 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR41, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR42 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR42(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr42_adotoslot23,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR42_ADOTOSLOT23 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr42_adotoslot22,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR42_ADOTOSLOT22 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR42, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR43 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR43(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr43_adotoslot25,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR43_ADOTOSLOT25 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr43_adotoslot24,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR43_ADOTOSLOT24 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR43, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR44 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR44(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr44_adotoslot27,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR44_ADOTOSLOT27 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr44_adotoslot26,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR44_ADOTOSLOT26 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR44, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR45 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR45(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr45_adotoslot29,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR45_ADOTOSLOT29 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr45_adotoslot28,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR45_ADOTOSLOT28 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR45, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR46 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR46(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr46_adotoslot31,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR46_ADOTOSLOT31 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr46_adotoslot30,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR46_ADOTOSLOT30 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR46, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR47 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR47(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr47_hiz_sl7, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR47_HIZ_SL7 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr47_hiz_sl6, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR47_HIZ_SL6 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr47_hiz_sl5, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR47_HIZ_SL5 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr47_hiz_sl4, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR47_HIZ_SL4 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr47_hiz_sl3, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR47_HIZ_SL3 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr47_hiz_sl2, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR47_HIZ_SL2 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr47_hiz_sl1, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR47_HIZ_SL1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr47_hiz_sl0, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR47_HIZ_SL0 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR47, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR48 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR48(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr48_hiz_sl15, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR48_HIZ_SL15 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr48_hiz_sl14, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR48_HIZ_SL14 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr48_hiz_sl13, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR48_HIZ_SL13 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr48_hiz_sl12, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR48_HIZ_SL12 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr48_hiz_sl11, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR48_HIZ_SL11 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr48_hiz_sl10, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR48_HIZ_SL10 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr48_hiz_sl9, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR48_HIZ_SL9 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr48_hiz_sl8, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR48_HIZ_SL8 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR48, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR49 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR49(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr49_hiz_sl23, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR49_HIZ_SL23 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr49_hiz_sl22, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR49_HIZ_SL22 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr49_hiz_sl21, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR49_HIZ_SL21 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr49_hiz_sl20, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR49_HIZ_SL20 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr49_hiz_sl19, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR49_HIZ_SL19 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr49_hiz_sl18, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR49_HIZ_SL18 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr49_hiz_sl17, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR49_HIZ_SL17 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr49_hiz_sl16, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR49_HIZ_SL16 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR49, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR50 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR50(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr50_hiz_sl31, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR50_HIZ_SL31 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr50_hiz_sl30, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR50_HIZ_SL30 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr50_hiz_sl29, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR50_HIZ_SL29 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr50_hiz_sl28, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR50_HIZ_SL28 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr50_hiz_sl27, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR50_HIZ_SL27 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr50_hiz_sl26, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR50_HIZ_SL26 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr50_hiz_sl25, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR50_HIZ_SL25 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr50_hiz_sl24, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR50_HIZ_SL24 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR50, value));
+}
+
+#endif /* */
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR51 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR51(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr51_da12_voice,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR51_DA12_VOICE );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr51_swapda12_34,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR51_SWAP_DA12_34 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr51_sldai7toslado1,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR51_SLDAI7TOSLADO1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr51_sltoda1, AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR51_SLTODA1 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR51, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR52 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR52(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr52_sldai8toslado2,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR52_SLDAI8TOSLADO2 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr52_sltoda2, AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR52_SLTODA2 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR52, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR53 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR53(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr53_da34_voice,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR53_DA34_VOICE );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr53_sldai7toslado3,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR53_SLDAI7TOSLADO3 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr53_sltoda3, AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR53_SLTODA3 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR53, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR54 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR54(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr54_sldai8toslado4,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR54_SLDAI8TOSLADO4 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr54_sltoda4, AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR54_SLTODA4 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR54, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR55 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR55(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr55_da56_voice,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR55_DA56_VOICE );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr55_sldai7toslado5,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR55_SLDAI7TOSLADO5 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr55_sltoda5, AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR55_SLTODA5 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR55, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR56 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR56(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr56_sldai8toslado6,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR56_SLDAI8TOSLADO6 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr56_sltoda6, AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR56_SLTODA6 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR56, value));
+}
+
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR57 */
+/********************************************************************************************/
+ PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR57(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr57_sldai8toslado7,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR57_SLDAI8TOSLADO7 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr57_sltoda7, AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR57_SLTODA7 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR57, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR58 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR58(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr58_sldai7toslado8,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR58_SLDAI7TOSLADO8 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr58_sltoda8, AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR58_SLTODA8 );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR58, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR59 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR59(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr59_parlhf, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR59_PARLHF );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr59_parlvib, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR59_PARLVIB );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr59_classdvib1_swapen,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR59_CLASSDVIB1SWAPEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr59_classdvib2_swapen,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR59_CLASSDVIB2SWAPEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr59_classdhfl_swapen,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR59_CLASSDHFLSWAPEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr59_classdhfr_swapen,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR59_CLASSDHFRSWAPEN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR59, value));
+}
+
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR60 */
+/********************************************************************************************/
+ PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR60(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr60_classd_firbyp,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR60_CLASSD_FIR_BYP );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr60_classd_highvolen,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR60_CLASSD_HIGHVOL_EN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR60, value));
+}
+
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR61 */
+/********************************************************************************************/
+ PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR61(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+
+ /* 5 bits are Read Only */
+ AB8500_CODEC_WRITE_BITS
+ (value,
+ (t_uint8) p_ab8500_codec_configuration->cr61_classddith_hpgain,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR61_CLASSD_DITH_HPGAIN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr61_classddith_wgain,
+ AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR61_CLASSD_DITH_WGAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR61, value));
+}
+
+#endif /* */
+
+/* CR62 is Read Only */
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR63 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR63(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr63_datohslen, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR63_DATOHSLEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr63_datohsren, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR63_DATOHSREN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr63_ad1sel, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR63_AD1SEL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr63_ad2sel, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR63_AD2SEL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr63_ad3sel, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR63_AD3SEL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr63_ad5sel, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR63_AD5SEL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr63_ad6sel, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR63_AD6SEL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr63_ancsel, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR63_ANCSEL );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR63, value));
+}
+
+#if 0
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR64 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR64(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr64_datohfren, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR64_DATOHFREN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr64_datohflen, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR64_DATOHFLEN );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr64_hfrsel, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR64_HFRSEL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr64_hflsel, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR64_HFLSEL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr64_stfir1sel, AB8500_CODEC_MASK_TWO_BITS,
+ AB8500_CODEC_CR64_STFIR1SEL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr64_stfir2sel, AB8500_CODEC_MASK_TWO_BITS,
+ AB8500_CODEC_CR64_STFIR2SEL );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR64, value));
+}
+
+#endif /* */
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR65 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR65(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr65_fadedis_ad1,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR65_FADEDIS_AD1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr65_ad1gain, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR65_AD1GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR65, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR66 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR66(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr66_fadedis_ad2,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR66_FADEDIS_AD2 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr66_ad2gain, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR66_AD2GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR66, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR67 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR67(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr67_fadedis_ad3,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR67_FADEDIS_AD3 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr67_ad3gain, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR67_AD3GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR67, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR68 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR68(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr68_fadedis_ad4,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR68_FADEDIS_AD4 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr68_ad4gain, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR68_AD4GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR68, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR69 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR69(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr69_fadedis_ad5,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR69_FADEDIS_AD5 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr69_ad5gain, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR69_AD5GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR69, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR70 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR70(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr70_fadedis_ad6,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR70_FADEDIS_AD6 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr70_ad6gain, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR70_AD6GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR70, value));
+}
+
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR71 */
+/********************************************************************************************/
+ PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR71(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr71_fadedis_da1,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR71_FADEDIS_DA1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr71_da1gain, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR71_DA1GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR71, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR72 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR72(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr72_fadedis_da2,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR72_FADEDIS_DA2 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr72_da2gain, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR72_DA2GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR72, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR73 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR73(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr73_fadedis_da3,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR73_FADEDIS_DA3 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr73_da3gain, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR73_DA3GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR73, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR74 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR74(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr74_fadedis_da4,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR74_FADEDIS_DA4 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr74_da4gain, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR74_DA4GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR74, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR75 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR75(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr75_fadedis_da5,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR75_FADEDIS_DA5 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr75_da5gain, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR75_DA5GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR75, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR76 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR76(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr76_fadedis_da6,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR76_FADEDIS_DA6 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr76_da6gain, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR76_DA6GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR76, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR77 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR77(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr77_fadedis_ad1l,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR77_FADEDIS_AD1L );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr77_ad1lbgain_to_hfl,
+ AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR77_AD1LBGAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR77, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR78 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR78(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr78_fadedis_ad2l,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR78_FADEDIS_AD2L );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr78_ad2lbgain_to_hfr,
+ AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR78_AD2LBGAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR78, value));
+}
+
+#endif /* */
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR79 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR79(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr79_hssinc1, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR79_HSSINC1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr79_fadedis_hsl,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR79_FADEDIS_HSL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr79_hsldgain, AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR79_HSLDGAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR79, value));
+}
+
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR80 */
+/********************************************************************************************/
+ PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR80(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr80_fade_speed,
+ AB8500_CODEC_MASK_TWO_BITS,
+ AB8500_CODEC_CR80_FADE_SPEED );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr80_fadedis_hsr,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR80_FADEDIS_HSR );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr80_hsrdgain, AB8500_CODEC_MASK_FOUR_BITS,
+ AB8500_CODEC_CR80_HSRDGAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR80, value));
+}
+
+#if 0
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR81 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR81(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr81_stfir1gain,
+ AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR81_STFIR1GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR81, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR82 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR82(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr82_stfir2gain,
+ AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR82_STFIR2GAIN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR82, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR83 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR83(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr83_enanc, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR83_ENANC );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr83_anciirinit, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR83_ANCIIRINIT );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr83_ancfirupdate,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR83_ANCFIRUPDATE );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR83, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR84 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR84(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr84_ancinshift,
+ AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR84_ANCINSHIFT );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR84, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR85 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR85(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr85_ancfiroutshift,
+ AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR85_ANCFIROUTSHIFT );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR85, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR86 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR86(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr86_ancshiftout,
+ AB8500_CODEC_MASK_FIVE_BITS,
+ AB8500_CODEC_CR86_ANCSHIFTOUT );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR86, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR87 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR87(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr87_ancfircoeff_msb,
+ AB8500_CODEC_MASK_EIGHT_BITS,
+ AB8500_CODEC_CR87_ANCFIRCOEFF_MSB );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR87, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR88 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR88(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr88_ancfircoeff_lsb,
+ AB8500_CODEC_MASK_EIGHT_BITS,
+ AB8500_CODEC_CR88_ANCFIRCOEFF_LSB );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR88, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR89 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR89(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr89_anciircoeff_msb,
+ AB8500_CODEC_MASK_EIGHT_BITS,
+ AB8500_CODEC_CR89_ANCIIRCOEFF_MSB );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR89, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR90 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR90(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr90_anciircoeff_lsb,
+ AB8500_CODEC_MASK_EIGHT_BITS,
+ AB8500_CODEC_CR90_ANCIIRCOEFF_LSB );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR90, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR91 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR91(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr91_ancwarpdel_msb,
+ AB8500_CODEC_MASK_EIGHT_BITS,
+ AB8500_CODEC_CR91_ANCWARPDEL_MSB );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR91, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR92 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR92(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr92_ancwarpdel_lsb,
+ AB8500_CODEC_MASK_EIGHT_BITS,
+ AB8500_CODEC_CR92_ANCWARPDEL_LSB );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR92, value));
+}
+
+/* CR93 is Read Only */
+/* CR94 is Read Only */
+/* CR95 is Read Only */
+/* CR96 is Read Only */
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR97 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR97(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr97_stfir_set, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR97_STFIR_SET );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr97_stfir_addr,
+ AB8500_CODEC_MASK_SEVEN_BITS,
+ AB8500_CODEC_CR97_STFIR_ADDR );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR97, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR98 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR98(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr98_stfir_coeff_msb,
+ AB8500_CODEC_MASK_EIGHT_BITS,
+ AB8500_CODEC_CR98_STFIR_COEFF_MSB );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR98, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR99 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR99(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr99_stfir_coeff_lsb,
+ AB8500_CODEC_MASK_EIGHT_BITS,
+ AB8500_CODEC_CR99_STFIR_COEFF_LSB );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR99, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR100 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR100(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr100_enstfirs, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR100_ENSTFIRS );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr100_stfirstoif1,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR100_STFIRSTOIF1 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr100_stfir_busy,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR100_STFIR_BUSY );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR100, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR101 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR101(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr101_hsoffst_mask,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR101_HSOFFSTMASK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr101_fifofull_mask,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR101_FIFOFULLMASK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr101_fifoempty_mask,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR101_FIFOEMPTYMASK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr101_dasat_mask,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR101_DASATMASK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr101_adsat_mask,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR101_ADSATMASK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr101_addsp_mask,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR101_ADDSPMASK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr101_dadsp_mask,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR101_DADSPMASK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr101_firsid_mask,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR101_FIRSIDMASK );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR101, value));
+}
+
+/* CR102 is Read Only */
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR103 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR103(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr103_vssready_mask,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR103_VSSREADYMASK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr103_shorthsl_mask,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR103_SHORTHSLMASK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr103_shorthsr_mask,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR103_SHORTHSRMASK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr103_shortear_mask,
+ AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR103_SHORTEARMASK );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR103, value));
+}
+
+#endif /* */
+
+/* CR104 is Read Only */
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR105 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR105(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr105_bfifomsk, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR105_BFIFOMASK );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr105_bfifoint, AB8500_CODEC_MASK_SIX_BITS,
+ AB8500_CODEC_CR105_BFIFOINT );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR105, value));
+}
+
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR106 */
+/********************************************************************************************/
+ PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR106(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr106_bfifotx,
+ AB8500_CODEC_MASK_EIGHT_BITS,
+ AB8500_CODEC_CR106_BFIFOTX );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR106, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR107 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR107(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr107_bfifoexsl,
+ AB8500_CODEC_MASK_THREE_BITS,
+ AB8500_CODEC_CR107_BFIFOEXSL );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr107_prebitclk0,
+ AB8500_CODEC_MASK_THREE_BITS,
+ AB8500_CODEC_CR107_PREBITCLK0 );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr107_bfifomast, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR107_BFIFOMAST );
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr107_bfiforun, AB8500_CODEC_MASK_ONE_BIT,
+ AB8500_CODEC_CR107_BFIFORUN );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR107, value));
+}
+
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR108 */
+/********************************************************************************************/
+ PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR108(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr108_bfifoframsw,
+ AB8500_CODEC_MASK_EIGHT_BITS,
+ AB8500_CODEC_CR108_BFIFOFRAMESW );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR108, value));
+}
+
+/********************************************************************************************/
+/* Name: ab8500_codec_UpdateCR109 */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_UpdateCR109(void)
+{
+ t_uint8 value = 0x00;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ AB8500_CODEC_WRITE_BITS (value,
+ (t_uint8) p_ab8500_codec_configuration->
+ cr109_bfifowakeup,
+ AB8500_CODEC_MASK_EIGHT_BITS,
+ AB8500_CODEC_CR109_BFIFOWAKEUP );
+ return (ab8500_codec_SingleWrite(AB8500_CODEC_CR109, value));
+}
+
+/* CR110 is Read Only */
+
+/* CR111 is Read Only */
+
+/********************************************************************************************/
+/* Name: ab8500_codec_Reset() */
+
+/********************************************************************************************/
+PRIVATE t_ab8500_codec_error ab8500_codec_Reset(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ p_ab8500_codec_configuration->cr1_swreset =
+ AB8500_CODEC_CR1_SWRESET_ENABLED;
+ ab8500_codec_error = ab8500_codec_UpdateCR1();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return (ab8500_codec_error);
+ }
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirection(IN
+ t_ab8500_codec_direction
+ ab8500_codec_direction)
+ /*only IN or OUT must be passed (not INOUT) */
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ if (AB8500_CODEC_DIRECTION_IN == ab8500_codec_direction)
+ {
+ ab8500_codec_error = ab8500_codec_ProgramDirectionIN();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+ if (AB8500_CODEC_DIRECTION_OUT == ab8500_codec_direction)
+ {
+ ab8500_codec_error = ab8500_codec_ProgramDirectionOUT();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_SetDirection(IN
+ t_ab8500_codec_direction
+ ab8500_codec_direction)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ switch (ab8500_codec_direction)
+ {
+ case AB8500_CODEC_DIRECTION_IN:
+ ab8500_codec_error =
+ ab8500_codec_ProgramDirection(AB8500_CODEC_DIRECTION_IN);
+ break;
+ case AB8500_CODEC_DIRECTION_OUT:
+ ab8500_codec_error =
+ ab8500_codec_ProgramDirection(AB8500_CODEC_DIRECTION_OUT);
+ break;
+ case AB8500_CODEC_DIRECTION_INOUT:
+ ab8500_codec_error =
+ ab8500_codec_ProgramDirection(AB8500_CODEC_DIRECTION_IN);
+ if (AB8500_CODEC_OK == ab8500_codec_error)
+ {
+ ab8500_codec_error =
+ ab8500_codec_ProgramDirection
+ (AB8500_CODEC_DIRECTION_OUT);
+ }
+ break;
+ }
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR5();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR6();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR7();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR8();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR9();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR10();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR12();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR15();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR63();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return (ab8500_codec_error);
+ }
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_Init */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Initialize the global variables & stores the slave address of codec. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* slave_address_of_ab8500_codec: Audio codec slave address */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* Returns AB8500_CODEC_OK */
+/* COMMENTS: */
+/* 1) Saves the supplied slave_address_of_codec in global variable */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_Init(IN t_uint8
+ slave_address_of_ab8500_codec)
+{
+ DBGENTER1(" (%lx)", slave_address_of_ab8500_codec);
+ g_ab8500_codec_system_context.slave_address_of_ab8500_codec =
+ slave_address_of_ab8500_codec;
+ DBGEXIT(AB8500_CODEC_OK);
+ return (AB8500_CODEC_OK);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_Reset */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Reset the global variables and clear audiocodec settings to default. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_Reset(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER();
+ g_ab8500_codec_system_context.ab8500_codec_direction =
+ AB8500_CODEC_DEFAULT_DIRECTION;
+ g_ab8500_codec_system_context.ab8500_codec_mode_in =
+ AB8500_CODEC_DEFAULT_MODE_IN;
+ g_ab8500_codec_system_context.ab8500_codec_mode_out =
+ AB8500_CODEC_DEFAULT_MODE_OUT;
+ g_ab8500_codec_system_context.ab8500_codec_src =
+ AB8500_CODEC_DEFAULT_INPUT_SRC;
+ g_ab8500_codec_system_context.ab8500_codec_dest =
+ AB8500_CODEC_DEFAULT_OUTPUT_DEST;
+ g_ab8500_codec_system_context.in_left_volume =
+ AB8500_CODEC_DEFAULT_VOLUME_LEFT_IN;
+ g_ab8500_codec_system_context.in_right_volume =
+ AB8500_CODEC_DEFAULT_VOLUME_RIGHT_IN;
+ g_ab8500_codec_system_context.out_left_volume =
+ AB8500_CODEC_DEFAULT_VOLUME_LEFT_OUT;
+ g_ab8500_codec_system_context.out_right_volume =
+ AB8500_CODEC_DEFAULT_VOLUME_RIGHT_OUT;
+ ab8500_codec_error = ab8500_codec_Reset();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SetModeAndDirection */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Configures the whole audio codec to work in audio mode */
+/* (using I2S protocol). */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* direction: select the direction (IN, OUT or INOUT) */
+/* in_mode: codec mode for recording. If direction is OUT only, */
+/* this parameter is ignored. */
+/* out_mode: codec mode for playing. If direction is IN only, */
+/* this parameter is ignored. */
+/* p_tdm_config: TDM configuration required to be configured by user */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_UNSUPPORTED_FEATURE: The API may not allow setting */
+/* 2 different modes, in which case it should return this value. */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SetModeAndDirection
+ (IN t_ab8500_codec_direction ab8500_codec_direction,
+ IN t_ab8500_codec_mode ab8500_codec_mode_in,
+ IN t_ab8500_codec_mode ab8500_codec_mode_out,
+ IN t_ab8500_codec_tdm_config const *const p_tdm_config ) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ DBGENTER3(" (%lx %lx %lx)", ab8500_codec_direction,
+ ab8500_codec_mode_in, ab8500_codec_mode_out);
+ if (AB8500_CODEC_AUDIO_INTERFACE_1 ==
+ g_ab8500_codec_system_context.audio_interface)
+ {
+ if (AB8500_CODEC_DIRECTION_OUT == ab8500_codec_direction
+ || AB8500_CODEC_DIRECTION_INOUT ==
+ ab8500_codec_direction )
+ {
+ p_ab8500_codec_configuration->cr3_enda1 =
+ AB8500_CODEC_CR3_ENDA1_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda2 =
+ AB8500_CODEC_CR3_ENDA2_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda3 =
+ AB8500_CODEC_CR3_ENDA3_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda4 =
+ AB8500_CODEC_CR3_ENDA4_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda5 =
+ AB8500_CODEC_CR3_ENDA5_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda6 =
+ AB8500_CODEC_CR3_ENDA6_ENABLED;
+ p_ab8500_codec_configuration->cr27_if1_bitclk_osr =
+ p_tdm_config->cr27_if1_bitclk_osr;
+ if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_out)
+ {
+ p_ab8500_codec_configuration->cr30_fsync1p =
+ AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_bitclk1p =
+ AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_if1del =
+ AB8500_CODEC_CR30_IF1DEL_DELAYED;
+ p_ab8500_codec_configuration->cr30_if1format =
+ AB8500_CODEC_CR30_IF1FORMAT_I2S_LEFTALIGNED;
+ p_ab8500_codec_configuration->cr30_if1wl =
+ p_tdm_config->cr30_if1wl;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr30_fsync1p =
+ AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_bitclk1p =
+ AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_if1del =
+ AB8500_CODEC_CR30_IF1DEL_DELAYED;
+ p_ab8500_codec_configuration->cr30_if1format =
+ AB8500_CODEC_CR30_IF1FORMAT_TDM;
+ p_ab8500_codec_configuration->cr30_if1wl =
+ p_tdm_config->cr30_if1wl;
+ }
+ }
+ if (AB8500_CODEC_DIRECTION_IN == ab8500_codec_direction
+ || AB8500_CODEC_DIRECTION_INOUT ==
+ ab8500_codec_direction )
+ {
+ p_ab8500_codec_configuration->cr2_enad1 =
+ AB8500_CODEC_CR2_ENAD1_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad2 =
+ AB8500_CODEC_CR2_ENAD2_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad3 =
+ AB8500_CODEC_CR2_ENAD3_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad4 =
+ AB8500_CODEC_CR2_ENAD4_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad5 =
+ AB8500_CODEC_CR2_ENAD5_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad6 =
+ AB8500_CODEC_CR2_ENAD6_ENABLED;
+ p_ab8500_codec_configuration->cr27_if1_bitclk_osr =
+ p_tdm_config->cr27_if1_bitclk_osr;
+ if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_in)
+ {
+ p_ab8500_codec_configuration->cr30_fsync1p =
+ AB8500_CODEC_CR30_FSYNC1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_bitclk1p =
+ AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_if1del =
+ AB8500_CODEC_CR30_IF1DEL_DELAYED;
+ p_ab8500_codec_configuration->cr30_if1format =
+ AB8500_CODEC_CR30_IF1FORMAT_I2S_LEFTALIGNED;
+ p_ab8500_codec_configuration->cr30_if1wl =
+ p_tdm_config->cr30_if1wl;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr30_fsync1p =
+ AB8500_CODEC_CR30_FSYNC1P_RISING_EDGE;
+ p_ab8500_codec_configuration->cr30_bitclk1p =
+ AB8500_CODEC_CR30_BITCLK1P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr30_if1del =
+ AB8500_CODEC_CR30_IF1DEL_NOT_DELAYED;
+ p_ab8500_codec_configuration->cr30_if1format =
+ AB8500_CODEC_CR30_IF1FORMAT_TDM;
+ p_ab8500_codec_configuration->cr30_if1wl =
+ p_tdm_config->cr30_if1wl;
+ }
+ }
+ }
+
+ else
+ {
+ if (AB8500_CODEC_DIRECTION_OUT == ab8500_codec_direction
+ || AB8500_CODEC_DIRECTION_INOUT ==
+ ab8500_codec_direction )
+ {
+ p_ab8500_codec_configuration->cr3_enda1 =
+ AB8500_CODEC_CR3_ENDA1_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda2 =
+ AB8500_CODEC_CR3_ENDA2_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda3 =
+ AB8500_CODEC_CR3_ENDA3_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda4 =
+ AB8500_CODEC_CR3_ENDA4_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda5 =
+ AB8500_CODEC_CR3_ENDA5_ENABLED;
+ p_ab8500_codec_configuration->cr3_enda6 =
+ AB8500_CODEC_CR3_ENDA6_ENABLED;
+ p_ab8500_codec_configuration->cr27_if0_bitclk_osr =
+ p_tdm_config->cr27_if0_bitclk_osr;
+ p_ab8500_codec_configuration->cr63_datohslen =
+ AB8500_CODEC_CR63_DATOHSLEN_ENABLED;
+ p_ab8500_codec_configuration->cr63_datohsren =
+ AB8500_CODEC_CR63_DATOHSREN_ENABLED;
+ if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_out)
+ {
+ p_ab8500_codec_configuration->cr28_fsync0p =
+ AB8500_CODEC_CR28_FSYNC0P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; */
+ p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_DELAYED; */
+ p_ab8500_codec_configuration->cr28_if0format =
+ AB8500_CODEC_CR28_IF0FORMAT_I2S_LEFTALIGNED;
+ p_ab8500_codec_configuration->cr28_if0wl =
+ p_tdm_config->cr28_if0wl;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr28_fsync0p =
+ AB8500_CODEC_CR28_FSYNC0P_FALLING_EDGE;
+ p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; */
+ p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_DELAYED; */
+ p_ab8500_codec_configuration->cr28_if0format =
+ AB8500_CODEC_CR28_IF0FORMAT_TDM;
+ p_ab8500_codec_configuration->cr28_if0wl =
+ p_tdm_config->cr28_if0wl;
+ }
+ }
+ if (AB8500_CODEC_DIRECTION_IN == ab8500_codec_direction
+ || AB8500_CODEC_DIRECTION_INOUT ==
+ ab8500_codec_direction )
+ {
+ p_ab8500_codec_configuration->cr2_enad1 =
+ AB8500_CODEC_CR2_ENAD1_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad2 =
+ AB8500_CODEC_CR2_ENAD2_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad3 =
+ AB8500_CODEC_CR2_ENAD3_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad4 =
+ AB8500_CODEC_CR2_ENAD4_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad5 =
+ AB8500_CODEC_CR2_ENAD5_ENABLED;
+ p_ab8500_codec_configuration->cr2_enad6 =
+ AB8500_CODEC_CR2_ENAD6_ENABLED;
+ p_ab8500_codec_configuration->cr26_ad1_voice =
+ AB8500_CODEC_CR26_AD1_VOICE_LOWLATENCYFILTER;
+ p_ab8500_codec_configuration->cr26_ad2_voice =
+ AB8500_CODEC_CR26_AD2_VOICE_LOWLATENCYFILTER;
+ p_ab8500_codec_configuration->cr26_ad3_voice =
+ AB8500_CODEC_CR26_AD3_VOICE_LOWLATENCYFILTER;
+ p_ab8500_codec_configuration->cr26_ad4_voice =
+ AB8500_CODEC_CR26_AD4_VOICE_LOWLATENCYFILTER;
+ p_ab8500_codec_configuration->cr27_if0_bitclk_osr =
+ p_tdm_config->cr27_if0_bitclk_osr;
+ if (AB8500_CODEC_MODE_HIFI == ab8500_codec_mode_in)
+ {
+ p_ab8500_codec_configuration->cr28_fsync0p =
+ AB8500_CODEC_CR28_FSYNC0P_RISING_EDGE;
+ p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_RISING_EDGE; */
+ p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED; */
+ p_ab8500_codec_configuration->cr28_if0format =
+ AB8500_CODEC_CR28_IF0FORMAT_I2S_LEFTALIGNED;
+ p_ab8500_codec_configuration->cr28_if0wl =
+ p_tdm_config->cr28_if0wl;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr28_fsync0p =
+ AB8500_CODEC_CR28_FSYNC0P_RISING_EDGE;
+ p_ab8500_codec_configuration->cr28_bitclk0p = p_tdm_config->cr28_bitclk0p; /*AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE; */
+ p_ab8500_codec_configuration->cr28_if0del = p_tdm_config->cr28_if0del; /*AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED; */
+ p_ab8500_codec_configuration->cr28_if0format =
+ AB8500_CODEC_CR28_IF0FORMAT_TDM;
+ p_ab8500_codec_configuration->cr28_if0wl =
+ p_tdm_config->cr28_if0wl;
+ }
+ }
+ }
+ ab8500_codec_error = ab8500_codec_SetModeAndDirectionUpdateCR();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ g_ab8500_codec_system_context.ab8500_codec_direction =
+ ab8500_codec_direction;
+ g_ab8500_codec_system_context.ab8500_codec_mode_in =
+ ab8500_codec_mode_in;
+ g_ab8500_codec_system_context.ab8500_codec_mode_out =
+ ab8500_codec_mode_out;
+ ab8500_codec_error =
+ ab8500_codec_SetDirection(ab8500_codec_direction);
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SetSrcVolume */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Sets the record volumes. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* t_ab8500_codec_src: select source device for recording. */
+/* in_left_volume: record volume for left channel. */
+/* in_right_volume: record volume for right channel. */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SetSrcVolume
+ (IN t_ab8500_codec_src src_device, IN t_uint8 in_left_volume,
+ IN t_uint8 in_right_volume ) {
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ DBGENTER3(" (%lx %lx %lx)", src_device, in_left_volume,
+ in_right_volume);
+ if (in_left_volume > AB8500_CODEC_MAX_VOLUME)
+ {
+ in_left_volume = AB8500_CODEC_MAX_VOLUME;
+ }
+ if (in_right_volume > AB8500_CODEC_MAX_VOLUME)
+ {
+ in_right_volume = AB8500_CODEC_MAX_VOLUME;
+ }
+ g_ab8500_codec_system_context.in_left_volume = in_left_volume;
+ g_ab8500_codec_system_context.in_right_volume = in_right_volume;
+ p_ab8500_codec_configuration->cr65_ad1gain =
+ AB8500_CODEC_AD_D_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_AD_D_VOLUME_MAX -
+ AB8500_CODEC_AD_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr66_ad2gain =
+ AB8500_CODEC_AD_D_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_AD_D_VOLUME_MAX -
+ AB8500_CODEC_AD_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr67_ad3gain =
+ AB8500_CODEC_AD_D_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_AD_D_VOLUME_MAX -
+ AB8500_CODEC_AD_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr68_ad4gain =
+ AB8500_CODEC_AD_D_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_AD_D_VOLUME_MAX -
+ AB8500_CODEC_AD_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr69_ad5gain =
+ AB8500_CODEC_AD_D_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_AD_D_VOLUME_MAX -
+ AB8500_CODEC_AD_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr70_ad6gain =
+ AB8500_CODEC_AD_D_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_AD_D_VOLUME_MAX -
+ AB8500_CODEC_AD_D_VOLUME_MIN)) / 100;
+
+ /* Set mininimum volume if volume is zero */
+ switch (src_device)
+ {
+ case AB8500_CODEC_SRC_LINEIN:
+ p_ab8500_codec_configuration->cr23_linl_gain =
+ AB8500_CODEC_LINEIN_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_LINEIN_VOLUME_MAX -
+ AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr23_linr_gain =
+ AB8500_CODEC_LINEIN_VOLUME_MIN +
+ (in_right_volume *
+ (AB8500_CODEC_LINEIN_VOLUME_MAX -
+ AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100;
+ break;
+ case AB8500_CODEC_SRC_MICROPHONE_1A:
+ case AB8500_CODEC_SRC_MICROPHONE_1B:
+ p_ab8500_codec_configuration->cr20_mic1_gain =
+ AB8500_CODEC_MIC_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_MIC_VOLUME_MAX -
+ AB8500_CODEC_MIC_VOLUME_MIN)) / 100;
+ break;
+ case AB8500_CODEC_SRC_MICROPHONE_2:
+ p_ab8500_codec_configuration->cr21_mic2_gain =
+ AB8500_CODEC_MIC_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_MIC_VOLUME_MAX -
+ AB8500_CODEC_MIC_VOLUME_MIN)) / 100;
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_1:
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_2:
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_3:
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_4:
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_5:
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_6:
+ break;
+ case AB8500_CODEC_SRC_ALL:
+ p_ab8500_codec_configuration->cr23_linl_gain =
+ AB8500_CODEC_LINEIN_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_LINEIN_VOLUME_MAX -
+ AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr23_linr_gain =
+ AB8500_CODEC_LINEIN_VOLUME_MIN +
+ (in_right_volume *
+ (AB8500_CODEC_LINEIN_VOLUME_MAX -
+ AB8500_CODEC_LINEIN_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr20_mic1_gain =
+ AB8500_CODEC_MIC_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_MIC_VOLUME_MAX -
+ AB8500_CODEC_MIC_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr21_mic2_gain =
+ AB8500_CODEC_MIC_VOLUME_MIN +
+ (in_left_volume *
+ (AB8500_CODEC_MIC_VOLUME_MAX -
+ AB8500_CODEC_MIC_VOLUME_MIN)) / 100;
+ break;
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_SetSrcVolumeUpdateCR();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SetDestVolume */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Sets the play volumes. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* out_left_volume: play volume for left channel. */
+/* out_right_volume: play volume for right channel. */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SetDestVolume
+ (IN t_ab8500_codec_dest dest_device, IN t_uint8 out_left_volume,
+ IN t_uint8 out_right_volume ) {
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ DBGENTER3(" (%lx %lx %lx)", dest_device, out_left_volume,
+ out_right_volume);
+ if (out_left_volume > AB8500_CODEC_MAX_VOLUME)
+ {
+ out_left_volume = AB8500_CODEC_MAX_VOLUME;
+ }
+ if (out_right_volume > AB8500_CODEC_MAX_VOLUME)
+ {
+ out_right_volume = AB8500_CODEC_MAX_VOLUME;
+ }
+ g_ab8500_codec_system_context.out_left_volume = out_left_volume;
+ g_ab8500_codec_system_context.out_right_volume = out_right_volume;
+ p_ab8500_codec_configuration->cr71_da1gain =
+ AB8500_CODEC_DA_D_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_DA_D_VOLUME_MAX -
+ AB8500_CODEC_DA_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr72_da2gain =
+ AB8500_CODEC_DA_D_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_DA_D_VOLUME_MAX -
+ AB8500_CODEC_DA_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr73_da3gain =
+ AB8500_CODEC_DA_D_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_DA_D_VOLUME_MAX -
+ AB8500_CODEC_DA_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr74_da4gain =
+ AB8500_CODEC_DA_D_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_DA_D_VOLUME_MAX -
+ AB8500_CODEC_DA_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr75_da5gain =
+ AB8500_CODEC_DA_D_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_DA_D_VOLUME_MAX -
+ AB8500_CODEC_DA_D_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr76_da6gain =
+ AB8500_CODEC_DA_D_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_DA_D_VOLUME_MAX -
+ AB8500_CODEC_DA_D_VOLUME_MIN)) / 100;
+
+ /* Set mininimum volume if volume is zero */
+ switch (dest_device)
+ {
+ case AB8500_CODEC_DEST_HEADSET:
+ p_ab8500_codec_configuration->cr22_hsl_gain =
+ AB8500_CODEC_HEADSET_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_HEADSET_VOLUME_MAX -
+ AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr22_hsr_gain =
+ AB8500_CODEC_HEADSET_VOLUME_MIN +
+ (out_right_volume *
+ (AB8500_CODEC_HEADSET_VOLUME_MAX -
+ AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr79_hsldgain =
+ AB8500_CODEC_HEADSET_D_VOLUME_0DB;
+ p_ab8500_codec_configuration->cr80_hsrdgain =
+ AB8500_CODEC_HEADSET_D_VOLUME_0DB;
+ break;
+ case AB8500_CODEC_DEST_EARPIECE:
+ p_ab8500_codec_configuration->cr79_hsldgain =
+ AB8500_CODEC_HEADSET_D_VOLUME_0DB;
+ break;
+ case AB8500_CODEC_DEST_HANDSFREE:
+ break;
+ case AB8500_CODEC_DEST_VIBRATOR_L:
+ p_ab8500_codec_configuration->cr16_pwmnldutycycle =
+ AB8500_CODEC_VIBRATOR_VOLUME_MIN;
+ p_ab8500_codec_configuration->cr17_pwmpldutycycle =
+ AB8500_CODEC_VIBRATOR_VOLUME_MIN +
+ (out_right_volume *
+ (AB8500_CODEC_VIBRATOR_VOLUME_MAX -
+ AB8500_CODEC_VIBRATOR_VOLUME_MIN)) / 100;
+ break;
+ case AB8500_CODEC_DEST_VIBRATOR_R:
+ p_ab8500_codec_configuration->cr18_pwmnrdutycycle =
+ AB8500_CODEC_VIBRATOR_VOLUME_MIN;
+ p_ab8500_codec_configuration->cr19_pwmprdutycycle =
+ AB8500_CODEC_VIBRATOR_VOLUME_MIN +
+ (out_right_volume *
+ (AB8500_CODEC_VIBRATOR_VOLUME_MAX -
+ AB8500_CODEC_VIBRATOR_VOLUME_MIN)) / 100;
+ break;
+ case AB8500_CODEC_DEST_ALL:
+ p_ab8500_codec_configuration->cr22_hsl_gain =
+ AB8500_CODEC_HEADSET_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_HEADSET_VOLUME_MAX -
+ AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr22_hsr_gain =
+ AB8500_CODEC_HEADSET_VOLUME_MIN +
+ (out_right_volume *
+ (AB8500_CODEC_HEADSET_VOLUME_MAX -
+ AB8500_CODEC_HEADSET_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr79_hsldgain =
+ AB8500_CODEC_HEADSET_D_VOLUME_0DB;
+ break;
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_SetDestVolumeUpdateCR();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SetMasterMode */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Set the Audio Codec in Master mode. */
+/* */
+/* ARGUMENTS */
+/* IN: t_codec_master_mode: Enable/disable master mode */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/* REMARK: Call this API after calling AB8500_CODEC_SetModeAndDirection() API*/
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SetMasterMode(IN
+ t_ab8500_codec_master_mode
+ mode)
+{
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER0();
+ if (AB8500_CODEC_AUDIO_INTERFACE_1 ==
+ g_ab8500_codec_system_context.audio_interface)
+ {
+ p_ab8500_codec_configuration->cr27_en_mastgen =
+ AB8500_CODEC_CR27_EN_MASTGEN_ENABLED;
+ p_ab8500_codec_configuration->cr27_enfs_bitclk1 =
+ AB8500_CODEC_CR27_ENFS_BITCLK1_ENABLED;
+ if (AB8500_CODEC_MASTER_MODE_ENABLE == mode)
+ {
+ p_ab8500_codec_configuration->cr29_if1master =
+ AB8500_CODEC_CR29_IF1MASTER_FS1CK1_OUTPUT;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr29_if1master =
+ AB8500_CODEC_CR29_IF1MASTER_FS1CK1_INPUT;
+ }
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr27_en_mastgen =
+ AB8500_CODEC_CR27_EN_MASTGEN_ENABLED;
+ p_ab8500_codec_configuration->cr27_enfs_bitclk0 =
+ AB8500_CODEC_CR27_ENFS_BITCLK0_ENABLED;
+ if (AB8500_CODEC_MASTER_MODE_ENABLE == mode)
+ {
+ p_ab8500_codec_configuration->cr29_if0master =
+ AB8500_CODEC_CR29_IF0MASTER_FS0CK0_OUTPUT;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr29_if0master =
+ AB8500_CODEC_CR29_IF0MASTER_FS0CK0_INPUT;
+ }
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR27();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR29();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SelectInput */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Select input source for recording. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* input_src: select input source for recording when several sources */
+/* are supported in codec. */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_INVALID_PARAMETER: If input_src provided is invalid */
+/* by the codec hardware in use. */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SelectInput(IN t_ab8500_codec_src
+ ab8500_codec_src)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER1(" (%lx)", ab8500_codec_src);
+ g_ab8500_codec_system_context.ab8500_codec_src = ab8500_codec_src;
+ ab8500_codec_error =
+ ab8500_codec_SetDirection(AB8500_CODEC_DIRECTION_IN);
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SelectOutput */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Select output desination for playing. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* output_dest: select output destination for playing when several are */
+/* supported by codec hardware. */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_INVALID_PARAMETER: If output_src provided is invalid */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SelectOutput(IN t_ab8500_codec_dest
+ ab8500_codec_dest)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ g_ab8500_codec_system_context.ab8500_codec_dest = ab8500_codec_dest;
+ DBGENTER1(" (%lx)", ab8500_codec_dest);
+ ab8500_codec_error =
+ ab8500_codec_SetDirection(AB8500_CODEC_DIRECTION_OUT);
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_PowerDown */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Shuts the audio codec down completely. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* OUT: */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_PowerDown(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ g_ab8500_codec_system_context.ab8500_codec_configuration.cr0_powerup =
+ AB8500_CODEC_CR0_POWERUP_OFF;
+ ab8500_codec_error = ab8500_codec_UpdateCR0();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_PowerUp */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Switch on the audio codec. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_PowerUp(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER();
+ g_ab8500_codec_system_context.ab8500_codec_configuration.cr0_powerup =
+ AB8500_CODEC_CR0_POWERUP_ON;
+ g_ab8500_codec_system_context.ab8500_codec_configuration.cr0_enaana =
+ AB8500_CODEC_CR0_ENAANA_ON;
+ ab8500_codec_error = ab8500_codec_UpdateCR0();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SelectInterface */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Select the Audio Interface 0 or 1. */
+/* */
+/* ARGUMENTS */
+/* IN: t_ab8500_codec_audio_interface: The selected interface */
+/* */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_OK: Always. */
+/* REMARK: Call this API before using a function of the low level drivers */
+/* to select the interface that you want to configure */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SelectInterface(IN
+ t_ab8500_codec_audio_interface
+ audio_interface)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER0();
+ g_ab8500_codec_system_context.audio_interface = audio_interface;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_GetInterface */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Get the Audio Interface 0 or 1. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: p_audio_interface: Store the selected interface */
+/* RETURN: */
+/* AB8500_CODEC_OK: Always */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Re-Entrant */
+/* REENTRANCY ISSUES: No Issues */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_GetInterface(OUT
+ t_ab8500_codec_audio_interface
+ * p_audio_interface)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER0();
+ *p_audio_interface = g_ab8500_codec_system_context.audio_interface;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SetAnalogLoopback */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Sets Line-In to HeadSet loopback with the required gain. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* out_left_volume: play volume for left channel. */
+/* out_right_volume: play volume for right channel. */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SetAnalogLoopback(IN t_uint8
+ out_left_volume,
+ IN t_uint8
+ out_right_volume)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ DBGENTER2(" (%lx %lx)", out_left_volume, out_right_volume);
+ if (out_left_volume > AB8500_CODEC_MAX_VOLUME)
+ {
+ out_left_volume = AB8500_CODEC_MAX_VOLUME;
+ }
+ if (out_right_volume > AB8500_CODEC_MAX_VOLUME)
+ {
+ out_right_volume = AB8500_CODEC_MAX_VOLUME;
+ }
+ g_ab8500_codec_system_context.out_left_volume = out_left_volume;
+ g_ab8500_codec_system_context.out_right_volume = out_right_volume;
+ p_ab8500_codec_configuration->cr24_lintohsl_gain =
+ AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN +
+ (out_left_volume *
+ (AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MAX -
+ AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN)) / 100;
+ p_ab8500_codec_configuration->cr25_lintohsr_gain =
+ AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN +
+ (out_right_volume *
+ (AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MAX -
+ AB8500_CODEC_LINEIN_TO_HS_L_R_VOLUME_MIN)) / 100;
+ ab8500_codec_error = ab8500_codec_UpdateCR24();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR25();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_RemoveAnalogLoopback */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Remove Line-In to HeadSet loopback. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_RemoveAnalogLoopback(void)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ DBGENTER0();
+ p_ab8500_codec_configuration->cr24_lintohsl_gain =
+ AB8500_CODEC_LINEIN_TO_HS_L_R_LOOP_OPEN;
+ p_ab8500_codec_configuration->cr25_lintohsr_gain =
+ AB8500_CODEC_LINEIN_TO_HS_L_R_LOOP_OPEN;
+ ab8500_codec_error = ab8500_codec_UpdateCR24();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR25();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_EnableBypassMode */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Enables IF0 to IF1 path or vice versa */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_EnableBypassMode(void)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ DBGENTER0();
+ if (AB8500_CODEC_AUDIO_INTERFACE_1 ==
+ g_ab8500_codec_system_context.audio_interface)
+ {
+ p_ab8500_codec_configuration->cr29_if1datoif0ad =
+ AB8500_CODEC_CR29_IF1DATOIF0AD_SENT;
+ p_ab8500_codec_configuration->cr29_if1cktoif0ck =
+ AB8500_CODEC_CR29_IF1CKTOIF0CK_SENT;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr29_if0datoif1ad =
+ AB8500_CODEC_CR29_IF0DATOIF1AD_SENT;
+ p_ab8500_codec_configuration->cr29_if0cktoif1ck =
+ AB8500_CODEC_CR29_IF0CKTOIF1CK_SENT;
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR29();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_DisableBypassMode */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Disables IF0 to IF1 path or vice versa */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_DisableBypassMode(void)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ DBGENTER0();
+ if (AB8500_CODEC_AUDIO_INTERFACE_1 ==
+ g_ab8500_codec_system_context.audio_interface)
+ {
+ p_ab8500_codec_configuration->cr29_if1datoif0ad =
+ AB8500_CODEC_CR29_IF1DATOIF0AD_NOTSENT;
+ p_ab8500_codec_configuration->cr29_if1cktoif0ck =
+ AB8500_CODEC_CR29_IF1CKTOIF0CK_NOTSENT;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr29_if0datoif1ad =
+ AB8500_CODEC_CR29_IF0DATOIF1AD_NOTSENT;
+ p_ab8500_codec_configuration->cr29_if0cktoif1ck =
+ AB8500_CODEC_CR29_IF0CKTOIF1CK_NOTSENT;
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR29();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SrcPowerControl */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Enables/Disables & UnMute/Mute the desired source */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* t_ab8500_codec_src: select source device for enabling/disabling. */
+/* t_ab8500_codec_src_state: Enable/Disable */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SrcPowerControl(IN
+ t_ab8500_codec_src
+ src_device,
+ t_ab8500_codec_src_state
+ state)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+ DBGENTER2(" (%lx %lx)", src_device, state);
+ if (src_device <= AB8500_CODEC_SRC_D_MICROPHONE_2)
+ {
+ ab8500_codec_error =
+ ab8500_codec_SrcPowerControlSwitch1(src_device, state);
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+
+ else if (src_device <= AB8500_CODEC_SRC_ALL)
+ {
+ ab8500_codec_error =
+ ab8500_codec_SrcPowerControlSwitch2(src_device, state);
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+
+ else
+ {
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR5();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR6();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR7();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR63();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_DestPowerControl */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Enables/Disables & UnMute/Mute the desired destination */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* t_ab8500_codec_dest: select destination device for enabling/disabling. */
+/* t_ab8500_codec_dest_state: Enable/Disable */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_TRANSACTION_FAILED: If transaction fails. */
+/* AB8500_CODEC_OK: if successful. */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_DestPowerControl(IN
+ t_ab8500_codec_dest
+ dest_device,
+ t_ab8500_codec_dest_state
+ state)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context.ab8500_codec_configuration;
+ DBGENTER2(" (%lx %lx)", dest_device, state);
+ switch (dest_device)
+ {
+ case AB8500_CODEC_DEST_HEADSET:
+ if (AB8500_CODEC_DEST_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endachsl =
+ AB8500_CODEC_CR9_ENDACHSL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachsr =
+ AB8500_CODEC_CR9_ENDACHSR_ENABLED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachsl =
+ AB8500_CODEC_CR9_ENDACHSL_DISABLED;
+ p_ab8500_codec_configuration->cr9_endachsr =
+ AB8500_CODEC_CR9_ENDACHSR_DISABLED;
+ }
+ break;
+ case AB8500_CODEC_DEST_EARPIECE:
+ if (AB8500_CODEC_DEST_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacear =
+ AB8500_CODEC_CR9_ENDACEAR_ENABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_DISABLED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacear =
+ AB8500_CODEC_CR9_ENDACEAR_DISABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED;
+ }
+ break;
+ case AB8500_CODEC_DEST_HANDSFREE:
+ if (AB8500_CODEC_DEST_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfl =
+ AB8500_CODEC_CR9_ENDACHFL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfr =
+ AB8500_CODEC_CR9_ENDACHFR_ENABLED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endachfl =
+ AB8500_CODEC_CR9_ENDACHFL_DISABLED;
+ p_ab8500_codec_configuration->cr9_endachfr =
+ AB8500_CODEC_CR9_ENDACHFR_DISABLED;
+ }
+ break;
+ case AB8500_CODEC_DEST_VIBRATOR_L:
+ if (AB8500_CODEC_DEST_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibl =
+ AB8500_CODEC_CR9_ENDACVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibl =
+ AB8500_CODEC_CR15_PWMTOVIBL_PWM;
+ p_ab8500_codec_configuration->cr15_pwmlctrl =
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnlctrl =
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmplctrl =
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacvibl =
+ AB8500_CODEC_CR9_ENDACVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibl =
+ AB8500_CODEC_CR15_PWMTOVIBL_DA_PATH;
+ p_ab8500_codec_configuration->cr15_pwmlctrl =
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLGPOL;
+ p_ab8500_codec_configuration->cr15_pwmnlctrl =
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLGPOL;
+ p_ab8500_codec_configuration->cr15_pwmplctrl =
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLGPOL;
+ }
+ break;
+ case AB8500_CODEC_DEST_VIBRATOR_R:
+ if (AB8500_CODEC_DEST_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibr =
+ AB8500_CODEC_CR9_ENDACVIBR_ENABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibr =
+ AB8500_CODEC_CR15_PWMTOVIBR_PWM;
+ p_ab8500_codec_configuration->cr15_pwmrctrl =
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnrctrl =
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmprctrl =
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacvibr =
+ AB8500_CODEC_CR9_ENDACVIBR_DISABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibr =
+ AB8500_CODEC_CR15_PWMTOVIBR_DA_PATH;
+ p_ab8500_codec_configuration->cr15_pwmrctrl =
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRGPOL;
+ p_ab8500_codec_configuration->cr15_pwmnrctrl =
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRGPOL;
+ p_ab8500_codec_configuration->cr15_pwmprctrl =
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRGPOL;
+ }
+ break;
+ case AB8500_CODEC_DEST_ALL:
+ if (AB8500_CODEC_DEST_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_ENABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacear =
+ AB8500_CODEC_CR9_ENDACEAR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfl =
+ AB8500_CODEC_CR9_ENDACHFL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfr =
+ AB8500_CODEC_CR9_ENDACHFR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibl =
+ AB8500_CODEC_CR9_ENDACVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibr =
+ AB8500_CODEC_CR9_ENDACVIBR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_DISABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_DISABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibl =
+ AB8500_CODEC_CR15_PWMTOVIBL_PWM;
+ p_ab8500_codec_configuration->cr15_pwmlctrl =
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnlctrl =
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmplctrl =
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmtovibr =
+ AB8500_CODEC_CR15_PWMTOVIBR_PWM;
+ p_ab8500_codec_configuration->cr15_pwmrctrl =
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnrctrl =
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmprctrl =
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacear =
+ AB8500_CODEC_CR9_ENDACEAR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endachfl =
+ AB8500_CODEC_CR9_ENDACHFL_DISABLED;
+ p_ab8500_codec_configuration->cr9_endachfr =
+ AB8500_CODEC_CR9_ENDACHFR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacvibl =
+ AB8500_CODEC_CR9_ENDACVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacvibr =
+ AB8500_CODEC_CR9_ENDACVIBR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibl =
+ AB8500_CODEC_CR15_PWMTOVIBL_DA_PATH;
+ p_ab8500_codec_configuration->cr15_pwmlctrl =
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLGPOL;
+ p_ab8500_codec_configuration->cr15_pwmnlctrl =
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLGPOL;
+ p_ab8500_codec_configuration->cr15_pwmplctrl =
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLGPOL;
+ p_ab8500_codec_configuration->cr15_pwmtovibr =
+ AB8500_CODEC_CR15_PWMTOVIBR_DA_PATH;
+ p_ab8500_codec_configuration->cr15_pwmrctrl =
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRGPOL;
+ p_ab8500_codec_configuration->cr15_pwmnrctrl =
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRGPOL;
+ p_ab8500_codec_configuration->cr15_pwmprctrl =
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRGPOL;
+ }
+ break;
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_DestPowerControlUpdateCR();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_GetVersion */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* This routine populates the pVersion structure with */
+/* the current version of HCL. */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* p_version: this parameter is used to return current HCL version. */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_ERROR: if p_version is NULL. */
+/* AB8500_CODEC_OK: if successful */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Re-Entrant */
+/* REENTRANCY ISSUES: No Issues */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_GetVersion(OUT t_version * p_version)
+{
+ DBGENTER1(" (%lx)", p_version);
+ if (p_version != NULL)
+ {
+ p_version->minor = AB8500_CODEC_HCL_MINOR_ID;
+ p_version->major = AB8500_CODEC_HCL_MAJOR_ID;
+ p_version->version = AB8500_CODEC_HCL_VERSION_ID;
+ DBGEXIT0(AB8500_CODEC_OK);
+ return (AB8500_CODEC_OK);
+ }
+
+ else
+ {
+ DBGEXIT0(AB8500_CODEC_INVALID_PARAMETER);
+ return (AB8500_CODEC_INVALID_PARAMETER);
+ }
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_SetDbgLevel */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Set the debug level used by the debug module (mask-like value). */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* debug_level: debug level to be set */
+/* OUT: */
+/* None */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_OK: always */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Re-Entrant */
+/* REENTRANCY ISSUES: No Issues */
+
+/****************************************************************************/
+/*
+PUBLIC t_ab8500_codec_error AB8500_CODEC_SetDbgLevel(IN t_dbg_level dbg_level)
+{
+ DBGENTER1(" (%d)", dbg_level);
+ dbg_level = dbg_level;
+#ifdef __DEBUG
+ MY_DEBUG_LEVEL_VAR_NAME = dbg_level;
+#endif
+ DBGEXIT(AB8500_CODEC_OK);
+ return(AB8500_CODEC_OK);
+}
+ */
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_GetDbgLevel */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Set the debug level used by the debug module (mask-like value). */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* p_dbg_level: this parameter is used to return debug level. */
+/* */
+/* RETURN: */
+/* AB8500_CODEC_ERROR: if p_version is NULL. */
+/* AB8500_CODEC_OK: if successful */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Re-Entrant */
+/* REENTRANCY ISSUES: No Issues */
+
+/****************************************************************************/
+/*
+PUBLIC t_ab8500_codec_error AB8500_CODEC_GetDbgLevel(OUT t_dbg_level *p_dbg_level)
+{
+ if (NULL == p_dbg_level)
+ {
+ DBGEXIT(AB8500_CODEC_INVALID_PARAMETER);
+ return(AB8500_CODEC_INVALID_PARAMETER);
+ }
+
+#ifdef __DEBUG
+ * p_dbg_level = MY_DEBUG_LEVEL_VAR_NAME;
+#endif
+ DBGEXIT(AB8500_CODEC_OK);
+ return(AB8500_CODEC_OK);
+}
+*/
+/****************************************************************************/
+/* NAME: AB8500_CODEC_ADSlotAllocation */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* AD Data Allocation in slots. */
+/* */
+/* ARGUMENTS */
+/* IN: t_ab8500_codec_slot: The slot to be allocated. */
+/* IN: t_ab8500_codec_cr31_to_cr46_ad_data_allocation: The value */
+/* to be allocated. */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_INVALID_PARAMETER: If invalid slot number */
+/* AB8500_CODEC_OK: if successful. */
+/* REMARK: */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_ADSlotAllocation
+ (IN t_ab8500_codec_slot ad_slot,
+ IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value ) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER2(" (%lx %lx)", ad_slot, value);
+ if (ad_slot <= AB8500_CODEC_SLOT7)
+ {
+ ab8500_codec_error =
+ ab8500_codec_ADSlotAllocationSwitch1(ad_slot, value);
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+
+ else if (ad_slot <= AB8500_CODEC_SLOT15)
+ {
+ ab8500_codec_error =
+ ab8500_codec_ADSlotAllocationSwitch2(ad_slot, value);
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+
+ else if (ad_slot <= AB8500_CODEC_SLOT23)
+ {
+ ab8500_codec_error =
+ ab8500_codec_ADSlotAllocationSwitch3(ad_slot, value);
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+
+ else if (ad_slot <= AB8500_CODEC_SLOT31)
+ {
+ ab8500_codec_error =
+ ab8500_codec_ADSlotAllocationSwitch4(ad_slot, value);
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+
+ else
+ {
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_DASlotAllocation */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Allocate the Audio Interface slot for DA paths. */
+/* */
+/* ARGUMENTS */
+/* IN: t_ab8500_codec_da_channel_number: Channel number 1/2/3/4/5/6 */
+/* IN: t_ab8500_codec_cr51_to_cr56_sltoda: Slot number */
+/* */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_INVALID_PARAMETER: If invalid channel number */
+/* AB8500_CODEC_OK: if successful. */
+/* REMARK: */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_DASlotAllocation
+ (IN t_ab8500_codec_da_channel_number channel_number,
+ IN t_ab8500_codec_cr51_to_cr58_sltoda slot ) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ t_ab8500_codec_cr0_powerup ab8500_codec_cr0_powerup;
+ DBGENTER2(" (%lx %lx)", channel_number, slot);
+ p_ab8500_codec_configuration->cr51_da12_voice =
+ AB8500_CODEC_CR51_DA12_VOICE_LOWLATENCYFILTER;
+ switch (channel_number)
+ {
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_1:
+ p_ab8500_codec_configuration->cr51_sltoda1 = slot;
+ break;
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_2:
+ p_ab8500_codec_configuration->cr52_sltoda2 = slot;
+ break;
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_3:
+ p_ab8500_codec_configuration->cr53_sltoda3 = slot;
+ break;
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_4:
+ p_ab8500_codec_configuration->cr54_sltoda4 = slot;
+ break;
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_5:
+ p_ab8500_codec_configuration->cr55_sltoda5 = slot;
+ break;
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_6:
+ p_ab8500_codec_configuration->cr56_sltoda6 = slot;
+ break;
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_7:
+ p_ab8500_codec_configuration->cr57_sltoda7 = slot;
+ break;
+ case AB8500_CODEC_DA_CHANNEL_NUMBER_8:
+ p_ab8500_codec_configuration->cr58_sltoda8 = slot;
+ break;
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_cr0_powerup = p_ab8500_codec_configuration->cr0_powerup;
+ p_ab8500_codec_configuration->cr0_powerup =
+ AB8500_CODEC_CR0_POWERUP_OFF;
+ ab8500_codec_error = ab8500_codec_UpdateCR0();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR51();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR52();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR53();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR54();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR55();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR56();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR57();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR58();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ p_ab8500_codec_configuration->cr0_powerup = ab8500_codec_cr0_powerup;
+ ab8500_codec_error = ab8500_codec_UpdateCR0();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_ConfigureBurstFifo */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Configuration for Burst FIFO control */
+/* */
+/* ARGUMENTS */
+/* IN: t_ab8500_codec_burst_fifo_config: structure for configuration of */
+/* burst FIFO */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_INVALID_PARAMETER: If invalid parameter */
+/* AB8500_CODEC_UNSUPPORTED_FEATURE: If interface 1 selected */
+/* AB8500_CODEC_OK: if successful. */
+/* REMARK: */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+t_ab8500_codec_error AB8500_CODEC_ConfigureBurstFifo(IN
+ t_ab8500_codec_burst_fifo_config
+ const *const
+ p_burst_fifo_config)
+{
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER1(" (%lx)", p_burst_fifo_config);
+ if (AB8500_CODEC_AUDIO_INTERFACE_0 ==
+ g_ab8500_codec_system_context.audio_interface)
+ {
+ if (AB8500_CODEC_CR27_EN_MASTGEN_ENABLED ==
+ p_ab8500_codec_configuration->cr27_en_mastgen)
+ {
+ p_ab8500_codec_configuration->cr105_bfifomsk =
+ p_burst_fifo_config->cr105_bfifomsk;
+ p_ab8500_codec_configuration->cr105_bfifoint =
+ p_burst_fifo_config->cr105_bfifoint;
+ p_ab8500_codec_configuration->cr106_bfifotx =
+ p_burst_fifo_config->cr106_bfifotx;
+ p_ab8500_codec_configuration->cr107_bfifoexsl =
+ p_burst_fifo_config->cr107_bfifoexsl;
+ p_ab8500_codec_configuration->cr107_bfifomast =
+ p_burst_fifo_config->cr107_bfifomast;
+ p_ab8500_codec_configuration->cr107_bfiforun =
+ p_burst_fifo_config->cr107_bfiforun;
+ p_ab8500_codec_configuration->cr108_bfifoframsw =
+ p_burst_fifo_config->cr108_bfifoframsw;
+ p_ab8500_codec_configuration->cr109_bfifowakeup =
+ p_burst_fifo_config->cr109_bfifowakeup;
+ ab8500_codec_error = ab8500_codec_UpdateCR105();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR106();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR107();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR108();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR109();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+
+ else
+ {
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+
+ else
+ {
+ ab8500_codec_error = AB8500_CODEC_UNSUPPORTED_FEATURE;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_EnableBurstFifo */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Enable the Burst FIFO for Interface 0 */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_UNSUPPORTED_FEATURE: If Interface 1 is selected */
+/* AB8500_CODEC_OK: if successful. */
+/* REMARK: */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_EnableBurstFifo(void)
+{
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER0();
+ if (AB8500_CODEC_AUDIO_INTERFACE_0 ==
+ g_ab8500_codec_system_context.audio_interface)
+ {
+ p_ab8500_codec_configuration->cr29_if0bfifoen =
+ AB8500_CODEC_CR29_IF0BFIFOEN_BURST_MODE;
+ ab8500_codec_error = ab8500_codec_UpdateCR29();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+
+ else
+ {
+ ab8500_codec_error = AB8500_CODEC_UNSUPPORTED_FEATURE;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+/****************************************************************************/
+/* NAME: AB8500_CODEC_DisableBurstFifo */
+/*--------------------------------------------------------------------------*/
+/* DESCRIPTION: */
+/* Disable the Burst FIFO for Interface 0 */
+/* */
+/* ARGUMENTS */
+/* IN: */
+/* None */
+/* OUT: */
+/* None */
+/* RETURN: */
+/* AB8500_CODEC_UNSUPPORTED_FEATURE: If Interface 1 is selected */
+/* AB8500_CODEC_OK: if successful. */
+/* REMARK: */
+/*--------------------------------------------------------------------------*/
+/* REENTRANCY: Non Re-Entrant */
+
+/****************************************************************************/
+PUBLIC t_ab8500_codec_error AB8500_CODEC_DisableBurstFifo(void)
+{
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ DBGENTER0();
+ if (AB8500_CODEC_AUDIO_INTERFACE_0 ==
+ g_ab8500_codec_system_context.audio_interface)
+ {
+ p_ab8500_codec_configuration->cr29_if0bfifoen =
+ AB8500_CODEC_CR29_IF0BFIFOEN_NORMAL_MODE;
+ ab8500_codec_error = ab8500_codec_UpdateCR29();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ }
+
+ else
+ {
+ ab8500_codec_error = AB8500_CODEC_UNSUPPORTED_FEATURE;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch1
+ (IN t_ab8500_codec_slot ad_slot,
+ IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value ) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ switch (ad_slot)
+ {
+ case AB8500_CODEC_SLOT0:
+ p_ab8500_codec_configuration->cr31_adotoslot0 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR31();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT1:
+ p_ab8500_codec_configuration->cr31_adotoslot1 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR31();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT2:
+ p_ab8500_codec_configuration->cr32_adotoslot2 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR32();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT3:
+ p_ab8500_codec_configuration->cr32_adotoslot3 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR32();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT4:
+ p_ab8500_codec_configuration->cr33_adotoslot4 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR33();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT5:
+ p_ab8500_codec_configuration->cr33_adotoslot5 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR33();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT6:
+ p_ab8500_codec_configuration->cr34_adotoslot6 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR34();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT7:
+ p_ab8500_codec_configuration->cr34_adotoslot7 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR34();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch2
+ (IN t_ab8500_codec_slot ad_slot,
+ IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value ) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ switch (ad_slot)
+ {
+ case AB8500_CODEC_SLOT8:
+ p_ab8500_codec_configuration->cr35_adotoslot8 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR35();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT9:
+ p_ab8500_codec_configuration->cr35_adotoslot9 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR35();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT10:
+ p_ab8500_codec_configuration->cr36_adotoslot10 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR36();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT11:
+ p_ab8500_codec_configuration->cr36_adotoslot11 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR36();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT12:
+ p_ab8500_codec_configuration->cr37_adotoslot12 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR37();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT13:
+ p_ab8500_codec_configuration->cr37_adotoslot13 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR37();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT14:
+ p_ab8500_codec_configuration->cr38_adotoslot14 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR38();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT15:
+ p_ab8500_codec_configuration->cr38_adotoslot15 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR38();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch3
+ (IN t_ab8500_codec_slot ad_slot,
+ IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value ) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ switch (ad_slot)
+ {
+ case AB8500_CODEC_SLOT16:
+ p_ab8500_codec_configuration->cr39_adotoslot16 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR39();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT17:
+ p_ab8500_codec_configuration->cr39_adotoslot17 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR39();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT18:
+ p_ab8500_codec_configuration->cr40_adotoslot18 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR40();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT19:
+ p_ab8500_codec_configuration->cr40_adotoslot19 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR40();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT20:
+ p_ab8500_codec_configuration->cr41_adotoslot20 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR41();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT21:
+ p_ab8500_codec_configuration->cr41_adotoslot21 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR41();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT22:
+ p_ab8500_codec_configuration->cr42_adotoslot22 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR42();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT23:
+ p_ab8500_codec_configuration->cr42_adotoslot23 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR42();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ADSlotAllocationSwitch4
+ (IN t_ab8500_codec_slot ad_slot,
+ IN t_ab8500_codec_cr31_to_cr46_ad_data_allocation value ) {
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ switch (ad_slot)
+ {
+ case AB8500_CODEC_SLOT24:
+ p_ab8500_codec_configuration->cr43_adotoslot24 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR43();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT25:
+ p_ab8500_codec_configuration->cr43_adotoslot25 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR43();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT26:
+ p_ab8500_codec_configuration->cr44_adotoslot26 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR44();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT27:
+ p_ab8500_codec_configuration->cr44_adotoslot27 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR44();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT28:
+ p_ab8500_codec_configuration->cr45_adotoslot28 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR45();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT29:
+ p_ab8500_codec_configuration->cr45_adotoslot29 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR45();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT30:
+ p_ab8500_codec_configuration->cr46_adotoslot30 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR46();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ case AB8500_CODEC_SLOT31:
+ p_ab8500_codec_configuration->cr46_adotoslot31 = value;
+ ab8500_codec_error = ab8500_codec_UpdateCR46();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ break;
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch1(IN
+ t_ab8500_codec_src
+ src_device,
+ t_ab8500_codec_src_state
+ state)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ switch (src_device)
+ {
+ case AB8500_CODEC_SRC_LINEIN:
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_DISABLED;
+ p_ab8500_codec_configuration->cr7_linrsel =
+ AB8500_CODEC_CR7_LINRSEL_LINR;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_ENABLED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr7_linrsel =
+ AB8500_CODEC_CR7_LINRSEL_MIC2;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+ }
+ break;
+ case AB8500_CODEC_SRC_MICROPHONE_1A:
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr7_mic1sel =
+ AB8500_CODEC_CR7_MIC1SEL_MIC1A;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_DISABLED;
+ }
+ break;
+ case AB8500_CODEC_SRC_MICROPHONE_1B:
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr7_mic1sel =
+ AB8500_CODEC_CR7_MIC1SEL_MIC1B;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_DISABLED;
+ }
+ break;
+ case AB8500_CODEC_SRC_MICROPHONE_2:
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr7_linrsel =
+ AB8500_CODEC_CR7_LINRSEL_MIC2;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_ENABLED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr7_linrsel =
+ AB8500_CODEC_CR7_LINRSEL_LINR;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_1:
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr63_ad1sel =
+ AB8500_CODEC_CR63_AD1SEL_DMIC1_SELECTED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr63_ad1sel =
+ AB8500_CODEC_CR63_AD1SEL_LINLADL_SELECTED;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_2:
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr63_ad2sel =
+ AB8500_CODEC_CR63_AD2SEL_DMIC2_SELECTED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr63_ad2sel =
+ AB8500_CODEC_CR63_AD2SEL_LINRADR_SELECTED;
+ }
+ break;
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_SrcPowerControlSwitch2(IN
+ t_ab8500_codec_src
+ src_device,
+ t_ab8500_codec_src_state
+ state)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ switch (src_device)
+ {
+ case AB8500_CODEC_SRC_D_MICROPHONE_3:
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_ENABLED;
+ p_ab8500_codec_configuration->cr63_ad3sel =
+ AB8500_CODEC_CR63_AD3SEL_DMIC3_SELECTED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr63_ad3sel =
+ AB8500_CODEC_CR63_AD3SEL_ADMO_SELECTED;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_4:
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_ENABLED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_5:
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_ENABLED;
+ p_ab8500_codec_configuration->cr63_ad5sel =
+ AB8500_CODEC_CR63_AD5SEL_DMIC5_SELECTED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr63_ad5sel =
+ AB8500_CODEC_CR63_AD5SEL_AMADR_SELECTED;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_6:
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_ENABLED;
+ p_ab8500_codec_configuration->cr63_ad6sel =
+ AB8500_CODEC_CR63_AD6SEL_DMIC6_SELECTED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr63_ad6sel =
+ AB8500_CODEC_CR63_AD6SEL_ADMO_SELECTED;
+ }
+ break;
+ case AB8500_CODEC_SRC_ALL:
+ if (AB8500_CODEC_SRC_STATE_ENABLE == state)
+ {
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_DISABLED;
+ }
+
+ else
+ {
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+ }
+ break;
+ case AB8500_CODEC_SRC_FM_RX:
+ break;
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_SetModeAndDirectionUpdateCR(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ t_ab8500_codec_cr0_powerup ab8500_codec_cr0_powerup;
+ ab8500_codec_cr0_powerup = p_ab8500_codec_configuration->cr0_powerup;
+ p_ab8500_codec_configuration->cr0_powerup =
+ AB8500_CODEC_CR0_POWERUP_OFF;
+ ab8500_codec_error = ab8500_codec_UpdateCR0();
+ if (AB8500_CODEC_OK != ab8500_codec_error)
+ {
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR2();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR3();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR26();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR27();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR28();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR30();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR63();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ p_ab8500_codec_configuration->cr0_powerup = ab8500_codec_cr0_powerup;
+ ab8500_codec_error = ab8500_codec_UpdateCR0();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_SetSrcVolumeUpdateCR(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ ab8500_codec_error = ab8500_codec_UpdateCR20();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR21();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR23();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR65();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR66();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR67();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR68();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR69();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR70();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_SetDestVolumeUpdateCR(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ ab8500_codec_error = ab8500_codec_UpdateCR16();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR17();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR18();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR19();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR22();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR71();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR72();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR73();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR74();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR75();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR76();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR79();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR80();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionIN(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ switch (g_ab8500_codec_system_context.ab8500_codec_src)
+ {
+ case AB8500_CODEC_SRC_LINEIN:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr7_linrsel =
+ AB8500_CODEC_CR7_LINRSEL_LINR;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+ break;
+ case AB8500_CODEC_SRC_MICROPHONE_1A:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr7_mic1sel =
+ AB8500_CODEC_CR7_MIC1SEL_MIC1A;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+ break;
+ case AB8500_CODEC_SRC_MICROPHONE_1B:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr7_mic1sel =
+ AB8500_CODEC_CR7_MIC1SEL_MIC1B;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+ break;
+ case AB8500_CODEC_SRC_MICROPHONE_2:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ p_ab8500_codec_configuration->cr7_linrsel =
+ AB8500_CODEC_CR7_LINRSEL_MIC2;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_DISABLED;
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_1:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+ p_ab8500_codec_configuration->cr63_ad1sel =
+ AB8500_CODEC_CR63_AD1SEL_DMIC1_SELECTED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_2:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+ p_ab8500_codec_configuration->cr63_ad2sel =
+ AB8500_CODEC_CR63_AD2SEL_DMIC2_SELECTED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_3:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+ p_ab8500_codec_configuration->cr63_ad3sel =
+ AB8500_CODEC_CR63_AD3SEL_DMIC3_SELECTED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_4:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_5:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+ p_ab8500_codec_configuration->cr63_ad5sel =
+ AB8500_CODEC_CR63_AD5SEL_DMIC5_SELECTED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_6:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_DISABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_DISABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_DISABLED;
+ p_ab8500_codec_configuration->cr63_ad6sel =
+ AB8500_CODEC_CR63_AD6SEL_DMIC6_SELECTED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_ENABLED;
+ break;
+ case AB8500_CODEC_SRC_ALL:
+ p_ab8500_codec_configuration->cr5_enlinl =
+ AB8500_CODEC_CR5_ENLINL_ENABLED;
+ p_ab8500_codec_configuration->cr5_enlinr =
+ AB8500_CODEC_CR5_ENLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic1 =
+ AB8500_CODEC_CR5_ENMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr5_enmic2 =
+ AB8500_CODEC_CR5_ENMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic1 =
+ AB8500_CODEC_CR6_ENDMIC1_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic2 =
+ AB8500_CODEC_CR6_ENDMIC2_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic3 =
+ AB8500_CODEC_CR6_ENDMIC3_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic4 =
+ AB8500_CODEC_CR6_ENDMIC4_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic5 =
+ AB8500_CODEC_CR6_ENDMIC5_ENABLED;
+ p_ab8500_codec_configuration->cr6_endmic6 =
+ AB8500_CODEC_CR6_ENDMIC6_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadcmic =
+ AB8500_CODEC_CR7_ENADCMIC_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadclinl =
+ AB8500_CODEC_CR7_ENADCLINL_ENABLED;
+ p_ab8500_codec_configuration->cr7_enadclinr =
+ AB8500_CODEC_CR7_ENADCLINR_ENABLED;
+ p_ab8500_codec_configuration->cr5_mutlinl =
+ AB8500_CODEC_CR5_MUTLINL_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutlinr =
+ AB8500_CODEC_CR5_MUTLINR_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic1 =
+ AB8500_CODEC_CR5_MUTMIC1_DISABLED;
+ p_ab8500_codec_configuration->cr5_mutmic2 =
+ AB8500_CODEC_CR5_MUTMIC2_DISABLED;
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_12:
+ case AB8500_CODEC_SRC_D_MICROPHONE_34:
+ case AB8500_CODEC_SRC_D_MICROPHONE_56:
+ break;
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_ProgramDirectionOUT(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ t_ab8500_codec_configuration * p_ab8500_codec_configuration =
+ &g_ab8500_codec_system_context. ab8500_codec_configuration;
+ switch (g_ab8500_codec_system_context.ab8500_codec_dest)
+ {
+ case AB8500_CODEC_DEST_HEADSET:
+ p_ab8500_codec_configuration->cr7_endrvhsl =
+ AB8500_CODEC_CR7_ENDRVHSL_ENABLED;
+ p_ab8500_codec_configuration->cr7_endrvhsr =
+ AB8500_CODEC_CR7_ENDRVHSR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endachsl =
+ AB8500_CODEC_CR9_ENDACHSL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachsr =
+ AB8500_CODEC_CR9_ENDACHSR_ENABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_DISABLED;
+ p_ab8500_codec_configuration->cr12_encphs =
+ AB8500_CODEC_CR12_ENCPHS_ENABLED;
+ break;
+ case AB8500_CODEC_DEST_EARPIECE:
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacear =
+ AB8500_CODEC_CR9_ENDACEAR_ENABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED;
+ break;
+ case AB8500_CODEC_DEST_HANDSFREE:
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_ENABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endachfl =
+ AB8500_CODEC_CR9_ENDACHFL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfr =
+ AB8500_CODEC_CR9_ENDACHFR_ENABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED;
+ break;
+ case AB8500_CODEC_DEST_VIBRATOR_L:
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_DISABLED;
+ p_ab8500_codec_configuration->cr9_endacvibl =
+ AB8500_CODEC_CR9_ENDACVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibl =
+ AB8500_CODEC_CR15_PWMTOVIBL_PWM;
+ p_ab8500_codec_configuration->cr15_pwmlctrl =
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnlctrl =
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmplctrl =
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE;
+ break;
+ case AB8500_CODEC_DEST_VIBRATOR_R:
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_DISABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_DISABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibr =
+ AB8500_CODEC_CR9_ENDACVIBR_ENABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_ENABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibr =
+ AB8500_CODEC_CR15_PWMTOVIBR_PWM;
+ p_ab8500_codec_configuration->cr15_pwmrctrl =
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnrctrl =
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmprctrl =
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE;
+ break;
+ case AB8500_CODEC_DEST_ALL:
+ p_ab8500_codec_configuration->cr8_enhsl =
+ AB8500_CODEC_CR8_ENHSL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhsr =
+ AB8500_CODEC_CR8_ENHSR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enear =
+ AB8500_CODEC_CR8_ENEAR_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfl =
+ AB8500_CODEC_CR8_ENHFL_ENABLED;
+ p_ab8500_codec_configuration->cr8_enhfr =
+ AB8500_CODEC_CR8_ENHFR_ENABLED;
+ p_ab8500_codec_configuration->cr8_envibl =
+ AB8500_CODEC_CR8_ENVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr8_envibr =
+ AB8500_CODEC_CR8_ENVIBR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacear =
+ AB8500_CODEC_CR9_ENDACEAR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfl =
+ AB8500_CODEC_CR9_ENDACHFL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endachfr =
+ AB8500_CODEC_CR9_ENDACHFR_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibl =
+ AB8500_CODEC_CR9_ENDACVIBL_ENABLED;
+ p_ab8500_codec_configuration->cr9_endacvibr =
+ AB8500_CODEC_CR9_ENDACVIBR_ENABLED;
+ p_ab8500_codec_configuration->cr10_mutehsl =
+ AB8500_CODEC_CR10_MUTEHSL_DISABLED;
+ p_ab8500_codec_configuration->cr10_mutehsr =
+ AB8500_CODEC_CR10_MUTEHSR_DISABLED;
+ p_ab8500_codec_configuration->cr10_muteear =
+ AB8500_CODEC_CR10_MUTEEAR_DISABLED;
+ p_ab8500_codec_configuration->cr15_pwmtovibl =
+ AB8500_CODEC_CR15_PWMTOVIBL_PWM;
+ p_ab8500_codec_configuration->cr15_pwmlctrl =
+ AB8500_CODEC_CR15_PWMLCTRL_PWMNPLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnlctrl =
+ AB8500_CODEC_CR15_PWMNLCTRL_PWMNLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmplctrl =
+ AB8500_CODEC_CR15_PWMPLCTRL_PWMPLDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmtovibr =
+ AB8500_CODEC_CR15_PWMTOVIBR_PWM;
+ p_ab8500_codec_configuration->cr15_pwmrctrl =
+ AB8500_CODEC_CR15_PWMRCTRL_PWMNPRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmnrctrl =
+ AB8500_CODEC_CR15_PWMNRCTRL_PWMNRDUTYCYCLE;
+ p_ab8500_codec_configuration->cr15_pwmprctrl =
+ AB8500_CODEC_CR15_PWMPRCTRL_PWMPRDUTYCYCLE;
+ break;
+ default:
+ ab8500_codec_error = AB8500_CODEC_INVALID_PARAMETER;
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
+
+PRIVATE t_ab8500_codec_error ab8500_codec_DestPowerControlUpdateCR(void)
+{
+ t_ab8500_codec_error ab8500_codec_error = AB8500_CODEC_OK;
+ ab8500_codec_error = ab8500_codec_UpdateCR8();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR9();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR10();
+ if (ab8500_codec_error != AB8500_CODEC_OK)
+ {
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+ }
+ ab8500_codec_error = ab8500_codec_UpdateCR15();
+ DBGEXIT(ab8500_codec_error);
+ return (ab8500_codec_error);
+}
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
index 885683a3b0b..86cd48bfd8d 100644
--- a/sound/arm/Kconfig
+++ b/sound/arm/Kconfig
@@ -39,5 +39,17 @@ config SND_PXA2XX_AC97
Say Y or M if you want to support any AC97 codec attached to
the PXA2xx AC97 interface.
+config SND_U8500_ALSA_AB8500
+ tristate "U8500 alsa support for AB8500"
+ depends on SND && STE_DMA40 && U8500_ACODEC && (U8500_AB8500_ED || U8500_AB8500_CUT10)
+ default y
+ select SND_PCM
+ help
+ Say Y here if you have a u8500 based device
+ and want to use alsa for pcm playback and capture.
+
+ To compile this driver as a module, choose M here: the module
+ will be called u8500mod_alsa.
+
endif # SND_ARM
diff --git a/sound/arm/Makefile b/sound/arm/Makefile
index 8c0c851d464..e41f1f4db14 100644
--- a/sound/arm/Makefile
+++ b/sound/arm/Makefile
@@ -14,3 +14,7 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o
obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
+obj-$(CONFIG_SND_U8500_ALSA_AB8500) += u8500mod_alsa.o
+ifneq ($(CONFIG_SND_U8500_ALSA_AB8500),n)
+u8500mod_alsa-objs := u8500_alsa_ab8500.o u8500_alsa_hdmi.o
+endif
diff --git a/sound/arm/u8500_alsa_ab8500.c b/sound/arm/u8500_alsa_ab8500.c
new file mode 100644
index 00000000000..c14eed19196
--- /dev/null
+++ b/sound/arm/u8500_alsa_ab8500.c
@@ -0,0 +1,2710 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Deepak Karda
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.1 as published
+ * by the Free Software Foundation.
+ */
+
+/* This include must be defined at this point */
+//#include <sound/driver.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <mach/hardware.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* alsa system */
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include "u8500_alsa_ab8500.h"
+#include <mach/msp.h>
+#include <mach/debug.h>
+
+#define ALSA_NAME "DRIVER ALSA"
+
+#define DRIVER_DEBUG CONFIG_STM_ALSA_DEBUG /* enables/disables debug msgs */
+#define DRIVER_DEBUG_PFX ALSA_NAME /* msg header represents this module */
+#define DRIVER_DBG KERN_ERR /* message level */
+
+static struct platform_device *device;
+static int active_user = 0;
+
+/*
+** Externel references
+*/
+#if DRIVER_DEBUG > 0
+t_ab8500_codec_error dump_acodec_registers(void);
+t_ab8500_codec_error dump_msp_registers(void);
+#endif
+
+extern int u8500_acodec_rates[MAX_NO_OF_RATES];
+extern char *lpbk_state_in_texts[NUMBER_LOOPBACK_STATE];
+extern char *switch_state_in_texts[NUMBER_SWITCH_STATE];
+extern char *power_state_in_texts[NUMBER_POWER_STATE];
+extern char *tdm_mode_state_in_texts[NUMBER_TDM_MODE_STATE];
+extern char *direct_rendering_state_in_texts[NUMBER_DIRECT_RENDERING_STATE];
+extern char *pcm_rendering_state_in_texts[NUMBER_PCM_RENDERING_STATE];
+extern char *codec_dest_texts[NUMBER_OUTPUT_DEVICE];
+extern char *codec_in_texts[NUMBER_INPUT_DEVICE];
+extern struct driver_debug_st DBG_ST;
+extern int second_config;
+extern int u8500_register_alsa_hdmi_controls(struct snd_card *card,
+ u8500_acodec_chip_t * u8500_chip);
+extern int snd_card_u8500_alsa_hdmi_new(u8500_acodec_chip_t * chip, int device);
+/*
+** Declaration for local functions
+*/
+static int u8500_analog_lpbk_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_analog_lpbk_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_analog_lpbk_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+static int u8500_digital_lpbk_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_digital_lpbk_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_digital_lpbk_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+static int u8500_playback_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_playback_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_playback_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+static int u8500_capture_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_capture_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_capture_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+static int u8500_playback_sink_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_playback_sink_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_playback_sink_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+static int u8500_capture_src_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_capture_src_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_capture_src_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+static int u8500_playback_switch_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_playback_switch_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_playback_switch_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+static int u8500_capture_switch_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_capture_switch_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_capture_switch_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+static int u8500_playback_power_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_playback_power_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_playback_power_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+static int u8500_capture_power_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_capture_power_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_capture_power_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+static int u8500_tdm_mode_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_tdm_mode_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_tdm_mode_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+static int u8500_direct_rendering_mode_ctrl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info
+ *uinfo);
+static int u8500_direct_rendering_mode_ctrl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
+ *uinfo);
+static int u8500_direct_rendering_mode_ctrl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
+ *uinfo);
+static int u8500_register_alsa_controls(struct snd_card *card,
+ u8500_acodec_chip_t * u8500_chip);
+
+static int u8500_pcm_rendering_mode_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_pcm_rendering_mode_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_pcm_rendering_mode_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+#if 0 /* DUMP REGISTER CONTROL */
+static int u8500_dump_register_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_dump_register_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_dump_register_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+#endif /* DUMP REGISTER CONTROL */
+
+static int configure_rate(struct snd_pcm_substream *,
+ t_u8500_acodec_config_need acodec_config_need);
+static void dma_eot_handler(void *data);
+/**
+* configure_rate
+* @substream - pointer to the playback/capture substream structure
+*
+* This functions configures audio codec in to stream frequency frequency
+*/
+
+static int configure_rate(struct snd_pcm_substream *substream,
+ t_u8500_acodec_config_need acodec_config_need)
+{
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+ t_codec_sample_frequency sampling_frequency = 0;
+ t_ab8500_codec_direction direction = 0;
+ struct acodec_configuration acodec_config;
+ int stream_id = substream->pstr->stream;
+
+ FUNC_ENTER();
+ switch (chip->freq) {
+ case 48000:
+ sampling_frequency = CODEC_SAMPLING_FREQ_48KHZ;
+ break;
+ default:
+ printk("not supported frequnecy \n");
+ stm_error("not supported frequnecy \n");
+ return -EINVAL;
+ }
+
+ switch (stream_id) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ direction = AB8500_CODEC_DIRECTION_OUT;
+ break;
+ case SNDRV_PCM_STREAM_CAPTURE:
+ direction = AB8500_CODEC_DIRECTION_IN;
+ break;
+ default:
+ stm_error(": wrong pcm stream\n");
+ return -EINVAL;
+ }
+
+ stm_dbg(DBG_ST.alsa, "enabling audiocodec audio mode\n");
+ acodec_config.direction = direction;
+ acodec_config.input_frequency = T_CODEC_SAMPLING_FREQ_48KHZ;
+ acodec_config.output_frequency = T_CODEC_SAMPLING_FREQ_48KHZ;
+ acodec_config.mspClockSel = CODEC_MSP_APB_CLOCK;
+ acodec_config.mspInClockFreq = CODEC_MSP_INPUT_FREQ_48MHZ;
+ acodec_config.channels = chip->channels;
+ acodec_config.user = 2;
+ acodec_config.acodec_config_need = acodec_config_need;
+ acodec_config.handler = dma_eot_handler;
+ acodec_config.tx_callback_data =
+ &chip->stream[ALSA_PCM_DEV][SNDRV_PCM_STREAM_PLAYBACK];
+ acodec_config.rx_callback_data =
+ &chip->stream[ALSA_PCM_DEV][SNDRV_PCM_STREAM_CAPTURE];
+ acodec_config.direct_rendering_mode = chip->direct_rendering_mode;
+ acodec_config.tdm8_ch_mode = chip->tdm8_ch_mode;
+ acodec_config.digital_loopback = DISABLE;
+ u8500_acodec_enable_audio_mode(&acodec_config);
+ FUNC_EXIT();
+
+ return 0;
+}
+
+/*
+****************************************************************************************
+* playback vol control *
+****************************************************************************************
+*/
+
+struct snd_kcontrol_new u8500_playback_vol_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .subdevice = 0,
+ .name = "PCM Playback Volume",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_playback_vol_info,
+ .get = u8500_playback_vol_get,
+ .put = u8500_playback_vol_put
+};
+
+/**
+* u8500_playback_vol_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback volume info into user structure.
+*/
+
+static int u8500_playback_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 100;
+ uinfo->value.integer.step = 10;
+ return 0;
+}
+
+/**
+* u8500_playback_vol_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills the current volume setting to user structure.
+*/
+
+static int u8500_playback_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+
+ int *p_left_volume = NULL;
+ int *p_right_volume = NULL;
+
+ p_left_volume = (int *)&uinfo->value.integer.value[0];
+ p_right_volume = (int *)&uinfo->value.integer.value[1];
+
+ u8500_acodec_get_output_volume(chip->output_device, p_left_volume,
+ p_right_volume, USER_ALSA);
+ return 0;
+}
+
+/**
+* u8500_playback_vol_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure.
+*
+* This functions sets the playback audio codec volume .
+*/
+
+static int u8500_playback_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0, error = 0;
+
+ if (chip->output_lvolume != uinfo->value.integer.value[0]
+ || chip->output_rvolume != uinfo->value.integer.value[1]) {
+ chip->output_lvolume = uinfo->value.integer.value[0];
+ chip->output_rvolume = uinfo->value.integer.value[1];
+
+ if (chip->output_lvolume > 100)
+ chip->output_lvolume = 100;
+ else if (chip->output_lvolume < 0)
+ chip->output_lvolume = 0;
+
+ if (chip->output_rvolume > 100)
+ chip->output_rvolume = 100;
+ else if (chip->output_rvolume < 0)
+ chip->output_rvolume = 0;
+
+ error =
+ u8500_acodec_set_output_volume(chip->output_device,
+ chip->output_lvolume,
+ chip->output_rvolume,
+ USER_ALSA);
+
+ if (error) {
+ stm_error
+ (" : set volume for speaker/headphone failed\n");
+ return changed;
+ }
+ changed = 1;
+ }
+
+ return changed;
+}
+
+/*
+****************************************************************************************
+* capture vol control *
+****************************************************************************************
+*/
+
+struct snd_kcontrol_new u8500_capture_vol_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .subdevice = 1,
+ .name = "PCM Capture Volume",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_capture_vol_info,
+ .get = u8500_capture_vol_get,
+ .put = u8500_capture_vol_put
+};
+
+/**
+* u8500_capture_vol_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills capture volume info into user structure.
+*/
+static int u8500_capture_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 100;
+ uinfo->value.integer.step = 10;
+ return 0;
+}
+
+/**
+* u8500_capture_vol_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current capture volume setting to user structure.
+*/
+
+static int u8500_capture_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+
+ int *p_left_volume = NULL;
+ int *p_right_volume = NULL;
+
+ p_left_volume = (int *)&uinfo->value.integer.value[0];
+ p_right_volume = (int *)&uinfo->value.integer.value[1];
+
+ u8500_acodec_get_input_volume(chip->input_device, p_left_volume,
+ p_right_volume, USER_ALSA);
+ return 0;
+}
+
+/**
+* u8500_capture_vol_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure.
+*
+* This functions sets the capture audio codec volume with values provided.
+*/
+
+static int u8500_capture_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0, error = 0;
+
+ if (chip->input_lvolume != uinfo->value.integer.value[0]
+ || chip->input_rvolume != uinfo->value.integer.value[1]) {
+ chip->input_lvolume = uinfo->value.integer.value[0];
+ chip->input_rvolume = uinfo->value.integer.value[1];
+
+ if (chip->input_lvolume > 100)
+ chip->input_lvolume = 100;
+ else if (chip->input_lvolume < 0)
+ chip->input_lvolume = 0;
+
+ if (chip->input_rvolume > 100)
+ chip->input_rvolume = 100;
+ else if (chip->input_rvolume < 0)
+ chip->input_rvolume = 0;
+
+ error = u8500_acodec_set_input_volume(chip->input_device,
+ chip->input_rvolume,
+ chip->input_lvolume,
+ USER_ALSA);
+ if (error) {
+ stm_error(" : set input volume failed\n");
+ return changed;
+ }
+ changed = 1;
+ }
+
+ return changed;
+}
+
+/*
+****************************************************************************************
+* playback sink control *
+****************************************************************************************
+*/
+
+static struct snd_kcontrol_new u8500_playback_sink_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .subdevice = 0,
+ .name = "PCM Playback Sink",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xffff,
+ .info = u8500_playback_sink_info,
+ .get = u8500_playback_sink_get,
+ .put = u8500_playback_sink_put
+};
+
+/**
+* u8500_playback_sink_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback device info into user structure.
+*/
+static int u8500_playback_sink_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_OUTPUT_DEVICE;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= NUMBER_OUTPUT_DEVICE)
+ uinfo->value.enumerated.item = NUMBER_OUTPUT_DEVICE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ codec_dest_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_playback_sink_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current playback device selected.
+*/
+static int u8500_playback_sink_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] = chip->output_device;
+ return 0;
+}
+
+/**
+* u8500_playback_sink_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @ .
+*
+* This functions sets the playback device.
+*/
+static int u8500_playback_sink_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0, error;
+
+ if (chip->output_device != uinfo->value.enumerated.item[0]) {
+ chip->output_device = uinfo->value.enumerated.item[0];
+ error =
+ u8500_acodec_select_output(chip->output_device,
+ USER_ALSA, chip->tdm8_ch_mode);
+ if (error) {
+ stm_error(" : select output failed\n");
+ return changed;
+ }
+ changed = 1;
+ }
+ return changed;
+}
+
+/*
+****************************************************************************************
+* capture src control *
+****************************************************************************************
+*/
+
+static struct snd_kcontrol_new u8500_capture_src_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .subdevice = 1,
+ .name = "PCM Capture Source",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xffff,
+ .info = u8500_capture_src_ctrl_info,
+ .get = u8500_capture_src_ctrl_get,
+ .put = u8500_capture_src_ctrl_put
+};
+
+/**
+* u8500_capture_src_ctrl_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills capture device info into user structure.
+*/
+static int u8500_capture_src_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_INPUT_DEVICE;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= NUMBER_INPUT_DEVICE)
+ uinfo->value.enumerated.item = NUMBER_INPUT_DEVICE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ codec_in_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_capture_src_ctrl_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current capture device selected.
+*/
+static int u8500_capture_src_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] = chip->input_device;
+ return 0;
+}
+
+/**
+* u8500_capture_src_ctrl_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure,
+*
+* This functions sets the capture device.
+*/
+static int u8500_capture_src_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0, error;
+
+ if (chip->input_device != uinfo->value.enumerated.item[0]) {
+ chip->input_device = uinfo->value.enumerated.item[0];
+ error =
+ u8500_acodec_select_input(chip->input_device, USER_ALSA,
+ chip->tdm8_ch_mode);
+ if (error) {
+ stm_error(" : select input failed\n");
+ return changed;
+ }
+ changed = 1;
+ }
+ return changed;
+}
+
+/*
+***************************************************************************************
+* analog lpbk control *
+***************************************************************************************
+*/
+
+struct snd_kcontrol_new u8500_analog_lpbk_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .name = "Analog Loopback",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_analog_lpbk_info,
+ .get = u8500_analog_lpbk_get,
+ .put = u8500_analog_lpbk_put
+};
+
+/**
+* u8500_analog_lpbk_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback device info into user structure.
+*/
+static int u8500_analog_lpbk_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_LOOPBACK_STATE;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= NUMBER_LOOPBACK_STATE)
+ uinfo->value.enumerated.item = NUMBER_LOOPBACK_STATE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ lpbk_state_in_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_analog_lpbk_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current playback device selected.
+*/
+static int u8500_analog_lpbk_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] = chip->analog_lpbk;
+ return 0;
+}
+
+/**
+* u8500_analog_lpbk_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @ .
+*
+* This functions sets the playback device.
+*/
+static int u8500_analog_lpbk_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ t_ab8500_codec_error error;
+
+ if (chip->analog_lpbk != uinfo->value.enumerated.item[0]) {
+ chip->analog_lpbk = uinfo->value.enumerated.item[0];
+
+ error =
+ u8500_acodec_toggle_analog_lpbk(chip->analog_lpbk,
+ USER_ALSA);
+
+ if (AB8500_CODEC_OK != error) {
+ stm_error
+ (" : select u8500_acodec_set_analog_lpbk_state failed\n");
+ return changed;
+ }
+ changed = 1;
+ }
+ return changed;
+}
+
+/*
+****************************************************************************************
+* digital lpbk control *
+****************************************************************************************
+*/
+
+struct snd_kcontrol_new u8500_digital_lpbk_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .name = "Digital Loopback",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_digital_lpbk_info,
+ .get = u8500_digital_lpbk_get,
+ .put = u8500_digital_lpbk_put
+};
+
+/**
+* u8500_digital_lpbk_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback device info into user structure.
+*/
+static int u8500_digital_lpbk_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_LOOPBACK_STATE;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= NUMBER_LOOPBACK_STATE)
+ uinfo->value.enumerated.item = NUMBER_LOOPBACK_STATE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ lpbk_state_in_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_digital_lpbk_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current playback device selected.
+*/
+static int u8500_digital_lpbk_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] = chip->digital_lpbk;
+ return 0;
+}
+
+/**
+* u8500_analog_lpbk_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @ .
+*
+* This functions sets the playback device.
+*/
+static int u8500_digital_lpbk_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ t_ab8500_codec_error error;
+
+ if (chip->digital_lpbk != uinfo->value.enumerated.item[0]) {
+ chip->digital_lpbk = uinfo->value.enumerated.item[0];
+
+ error = u8500_acodec_toggle_digital_lpbk(chip->digital_lpbk,
+ chip->output_device,
+ chip->input_device,
+ USER_ALSA,
+ chip->tdm8_ch_mode);
+
+ /*if((error = u8500_acodec_set_output_volume(chip->output_device,50,50,USER_ALSA)))
+ {
+ stm_error(" : set output volume failed\n");
+ return error;
+ }
+
+ if ((error = u8500_acodec_set_input_volume(chip->input_device,50,50,USER_ALSA)))
+ {
+ stm_error(" : set input volume failed\n");
+ return error;
+ } */
+
+ if (AB8500_CODEC_OK != error) {
+ stm_error
+ (" : select u8500_acodec_set_digital_lpbk_state failed\n");
+ return changed;
+ }
+ changed = 1;
+ }
+ return changed;
+}
+
+/*
+****************************************************************************************
+* playback switch control *
+****************************************************************************************
+*/
+
+struct snd_kcontrol_new u8500_playback_switch_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .subdevice = 0,
+ .name = "PCM Playback Mute",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_playback_switch_ctrl_info,
+ .get = u8500_playback_switch_ctrl_get,
+ .put = u8500_playback_switch_ctrl_put
+};
+
+/**
+* u8500_playback_switch_ctrl_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback device info into user structure.
+*/
+static int u8500_playback_switch_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_SWITCH_STATE;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= NUMBER_SWITCH_STATE)
+ uinfo->value.enumerated.item = NUMBER_SWITCH_STATE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ switch_state_in_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_playback_switch_ctrl_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current playback device selected.
+*/
+static int u8500_playback_switch_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] = chip->playback_switch;
+ return 0;
+}
+
+/**
+* u8500_playback_switch_ctrl_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @ .
+*
+* This functions sets the playback device.
+*/
+static int u8500_playback_switch_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ t_ab8500_codec_error error;
+
+ if (chip->playback_switch != uinfo->value.enumerated.item[0]) {
+ chip->playback_switch = uinfo->value.enumerated.item[0];
+
+ error =
+ u8500_acodec_toggle_playback_mute_control(chip->
+ output_device,
+ chip->
+ playback_switch,
+ USER_ALSA);
+
+ if (AB8500_CODEC_OK != error) {
+ stm_error
+ (" : select u8500_playback_switch_ctrl_put failed\n");
+ return changed;
+ }
+ changed = 1;
+ }
+ return changed;
+}
+
+/*
+****************************************************************************************
+* Capture switch control *
+****************************************************************************************
+*/
+
+struct snd_kcontrol_new u8500_capture_switch_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .subdevice = 1,
+ .name = "PCM Capture Mute",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_capture_switch_ctrl_info,
+ .get = u8500_capture_switch_ctrl_get,
+ .put = u8500_capture_switch_ctrl_put
+};
+
+/**
+* u8500_capture_switch_ctrl_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback device info into user structure.
+*/
+static int u8500_capture_switch_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_SWITCH_STATE;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= NUMBER_SWITCH_STATE)
+ uinfo->value.enumerated.item = NUMBER_SWITCH_STATE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ switch_state_in_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_capture_switch_ctrl_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current playback device selected.
+*/
+static int u8500_capture_switch_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] = chip->capture_switch;
+ return 0;
+}
+
+/**
+* u8500_capture_switch_ctrl_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @ .
+*
+* This functions sets the playback device.
+*/
+static int u8500_capture_switch_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ t_ab8500_codec_error error;
+
+ if (chip->capture_switch != uinfo->value.enumerated.item[0]) {
+ chip->capture_switch = uinfo->value.enumerated.item[0];
+
+ error =
+ u8500_acodec_toggle_capture_mute_control(chip->input_device,
+ chip->
+ capture_switch,
+ USER_ALSA);
+
+ if (AB8500_CODEC_OK != error) {
+ stm_error
+ (" : select u8500_capture_switch_ctrl_put failed\n");
+ return changed;
+ }
+ changed = 1;
+ }
+ return changed;
+}
+
+/*
+****************************************************************************************
+* playback power control *
+****************************************************************************************
+*/
+
+struct snd_kcontrol_new u8500_playback_power_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .subdevice = 0,
+ .name = "PCM Playback Power",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_playback_power_ctrl_info,
+ .get = u8500_playback_power_ctrl_get,
+ .put = u8500_playback_power_ctrl_put
+};
+
+/**
+* u8500_playback_power_ctrl_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback device info into user structure.
+*/
+static int u8500_playback_power_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_POWER_STATE;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= NUMBER_POWER_STATE)
+ uinfo->value.enumerated.item = NUMBER_POWER_STATE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ power_state_in_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_playback_power_ctrl_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current playback device selected.
+*/
+static int u8500_playback_power_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] =
+ u8500_acodec_get_dest_power_state(chip->output_device);
+ return 0;
+}
+
+/**
+* u8500_playback_power_ctrl_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @ .
+*
+* This functions sets the playback device.
+*/
+static int u8500_playback_power_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ t_ab8500_codec_error error;
+ t_u8500_bool_state power_state;
+
+ power_state = u8500_acodec_get_dest_power_state(chip->output_device);
+
+ if (power_state != uinfo->value.enumerated.item[0]) {
+ power_state = uinfo->value.enumerated.item[0];
+
+ error =
+ u8500_acodec_set_dest_power_cntrl(chip->output_device,
+ power_state);
+
+ if (AB8500_CODEC_OK != error) {
+ stm_error
+ (" : select u8500_acodec_set_dest_power_cntrl failed\n");
+ return changed;
+ }
+
+ /* configure the volume settings for the acodec */
+ if ((error =
+ u8500_acodec_set_output_volume(chip->output_device,
+ chip->output_lvolume,
+ chip->output_rvolume,
+ USER_ALSA))) {
+ stm_error(" : set output volume failed\n");
+ return error;
+ }
+ changed = 1;
+ }
+ return changed;
+}
+
+/*
+****************************************************************************************
+* capture power control *
+****************************************************************************************
+*/
+
+struct snd_kcontrol_new u8500_capture_power_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .subdevice = 0,
+ .name = "PCM Capture Power",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_capture_power_ctrl_info,
+ .get = u8500_capture_power_ctrl_get,
+ .put = u8500_capture_power_ctrl_put
+};
+
+/**
+* u8500_capture_power_ctrl_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback device info into user structure.
+*/
+static int u8500_capture_power_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_POWER_STATE;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= NUMBER_POWER_STATE)
+ uinfo->value.enumerated.item = NUMBER_POWER_STATE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ power_state_in_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_capture_power_ctrl_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current playback device selected.
+*/
+static int u8500_capture_power_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] =
+ u8500_acodec_get_src_power_state(chip->input_device);
+ return 0;
+}
+
+/**
+* u8500_capture_power_ctrl_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @ .
+*
+* This functions sets the playback device.
+*/
+static int u8500_capture_power_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ t_ab8500_codec_error error;
+ t_u8500_bool_state power_state;
+
+ power_state = u8500_acodec_get_src_power_state(chip->input_device);
+
+ if (power_state != uinfo->value.enumerated.item[0]) {
+ power_state = uinfo->value.enumerated.item[0];
+
+ error =
+ u8500_acodec_set_src_power_cntrl(chip->input_device,
+ power_state);
+
+ if (AB8500_CODEC_OK != error) {
+ stm_error
+ (" : select u8500_acodec_set_src_power_cntrl failed\n");
+ return changed;
+ }
+ changed = 1;
+ }
+ return changed;
+}
+
+/*
+****************************************************************************************
+* TDM 8 channel mode control *
+****************************************************************************************
+*/
+
+struct snd_kcontrol_new u8500_tdm_mode_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .subdevice = 0,
+ .name = "TDM 8 Channel Mode",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_tdm_mode_ctrl_info,
+ .get = u8500_tdm_mode_ctrl_get,
+ .put = u8500_tdm_mode_ctrl_put
+};
+
+/**
+* u8500_tdm_mode_ctrl_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback device info into user structure.
+*/
+static int u8500_tdm_mode_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_TDM_MODE_STATE;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= NUMBER_TDM_MODE_STATE)
+ uinfo->value.enumerated.item = NUMBER_TDM_MODE_STATE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ tdm_mode_state_in_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_tdm_mode_ctrl_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current playback device selected.
+*/
+static int u8500_tdm_mode_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] = chip->tdm8_ch_mode;
+ return 0;
+}
+
+/**
+* u8500_tdm_mode_ctrl_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @ .
+*
+* This functions sets the playback device.
+*/
+static int u8500_tdm_mode_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ t_ab8500_codec_error error;
+
+ chip->tdm8_ch_mode = uinfo->value.enumerated.item[0];
+
+ if (ENABLE == chip->tdm8_ch_mode)
+ printk("\n TDM 8 channel mode enabled\n");
+ else
+ printk("\n TDM 8 channel mode disabled\n");
+
+ changed = 1;
+
+ return changed;
+}
+
+/*
+****************************************************************************************
+* Direct Rendering Mode control *
+****************************************************************************************
+*/
+
+struct snd_kcontrol_new u8500_direct_rendering_mode_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .name = "Direct Rendering Mode",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_direct_rendering_mode_ctrl_info,
+ .get = u8500_direct_rendering_mode_ctrl_get,
+ .put = u8500_direct_rendering_mode_ctrl_put
+};
+
+/**
+* u8500_direct_rendering_mode_ctrl_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback device info into user structure.
+*/
+static int u8500_direct_rendering_mode_ctrl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info
+ *uinfo)
+{
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_DIRECT_RENDERING_STATE;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= NUMBER_DIRECT_RENDERING_STATE)
+ uinfo->value.enumerated.item =
+ NUMBER_DIRECT_RENDERING_STATE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ direct_rendering_state_in_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_direct_rendering_mode_ctrl_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current playback device selected.
+*/
+static int u8500_direct_rendering_mode_ctrl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
+ *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] = chip->direct_rendering_mode;
+ return 0;
+}
+
+/**
+* u8500_direct_rendering_mode_ctrl_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @ .
+*
+* This functions sets the playback device.
+*/
+static int u8500_direct_rendering_mode_ctrl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
+ *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ t_ab8500_codec_error error;
+
+ chip->direct_rendering_mode = uinfo->value.enumerated.item[0];
+
+ if (ENABLE == chip->direct_rendering_mode) {
+ stm_gpio_altfuncenable(GPIO_ALT_MSP_1);
+ printk("\n stm_gpio_altfuncenable for GPIO_ALT_MSP_1\n");
+ printk("\n Direct Rendering mode enabled\n");
+ } else {
+ stm_gpio_altfuncdisable(GPIO_ALT_MSP_1);
+ printk("\n stm_gpio_altfuncdisable for GPIO_ALT_MSP_1\n");
+ printk("\n Direct Rendering mode disabled\n");
+ }
+
+ changed = 1;
+
+ return changed;
+}
+
+/*
+****************************************************************************************
+* PCM Rendering Mode control *
+****************************************************************************************
+*/
+
+struct snd_kcontrol_new u8500_pcm_rendering_mode_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .name = "PCM Rendering Mode",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_pcm_rendering_mode_ctrl_info,
+ .get = u8500_pcm_rendering_mode_ctrl_get,
+ .put = u8500_pcm_rendering_mode_ctrl_put
+};
+
+/**
+* u8500_pcm_rendering_mode_ctrl_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback device info into user structure.
+*/
+static int u8500_pcm_rendering_mode_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_PCM_RENDERING_STATE;
+ uinfo->count = 3;
+ if (uinfo->value.enumerated.item >= NUMBER_PCM_RENDERING_STATE)
+ uinfo->value.enumerated.item = NUMBER_PCM_RENDERING_STATE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ pcm_rendering_state_in_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_pcm_rendering_mode_ctrl_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current playback device selected.
+*/
+static int u8500_pcm_rendering_mode_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] = chip->burst_fifo_mode;
+ uinfo->value.enumerated.item[1] = chip->fm_playback_mode;
+ uinfo->value.enumerated.item[2] = chip->fm_tx_mode;
+ return 0;
+}
+
+/**
+* u8500_pcm_rendering_mode_ctrl_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @ .
+*
+* This functions sets the playback device.
+*/
+static int u8500_pcm_rendering_mode_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ t_ab8500_codec_error error;
+
+ if (RENDERING_PENDING == uinfo->value.enumerated.item[0]) {
+ return changed;
+ }
+ if (chip->burst_fifo_mode != uinfo->value.enumerated.item[0]) {
+ chip->burst_fifo_mode = uinfo->value.enumerated.item[0];
+ u8500_acodec_set_burst_mode_fifo(chip->burst_fifo_mode);
+ }
+
+ chip->fm_playback_mode = uinfo->value.enumerated.item[1];
+ chip->fm_tx_mode = uinfo->value.enumerated.item[2];
+
+ changed = 1;
+
+ return changed;
+}
+
+#if 0 /* DUMP REGISTER CONTROL */
+/*
+****************************************************************************************
+* dump registers control *
+****************************************************************************************
+*/
+
+struct snd_kcontrol_new u8500_dump_register_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 0,
+ .name = "",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_dump_register_ctrl_info,
+ .get = u8500_dump_register_ctrl_get,
+ .put = u8500_dump_register_ctrl_put
+};
+
+/**
+* u8500_dump_register_ctrl_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback device info into user structure.
+*/
+static int u8500_dump_register_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_PCM_RENDERING_STATE;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= NUMBER_PCM_RENDERING_STATE)
+ uinfo->value.enumerated.item = NUMBER_PCM_RENDERING_STATE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ pcm_rendering_state_in_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_dump_register_ctrl_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current playback device selected.
+*/
+static int u8500_dump_register_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] = chip->burst_fifo_mode;
+ uinfo->value.enumerated.item[1] = chip->fm_playback_mode;
+ uinfo->value.enumerated.item[2] = chip->fm_tx_mode;
+ return 0;
+}
+
+/**
+* u8500_dump_register_ctrl_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @ .
+*
+* This functions sets the playback device.
+*/
+static int u8500_dump_register_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ t_ab8500_codec_error error;
+
+ if (RENDERING_PENDING == uinfo->value.enumerated.item[0]) {
+ return changed;
+ }
+ if (chip->burst_fifo_mode != uinfo->value.enumerated.item[0]) {
+ chip->burst_fifo_mode = uinfo->value.enumerated.item[0];
+ //u8500_acodec_set_burst_mode_fifo(chip->burst_fifo_mode);
+ }
+
+ chip->fm_playback_mode = uinfo->value.enumerated.item[1];
+ chip->fm_tx_mode = uinfo->value.enumerated.item[2];
+
+ changed = 1;
+
+ return changed;
+}
+
+#endif /* DUMP REGISTER CONTROL */
+
+/* Hardware description , this structure (struct snd_pcm_hardware )
+ * contains the definitions of the fundamental hardware configuration.
+ * This configuration will be applied on the runtime structure
+ */
+static struct snd_pcm_hardware snd_u8500_playback_hw = {
+ .info =
+ (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE),
+ .formats =
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE |
+ SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_BE |
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE |
+ SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_U24_BE |
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE |
+ SNDRV_PCM_FMTBIT_S32_BE | SNDRV_PCM_FMTBIT_U32_BE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = MIN_RATE_PLAYBACK,
+ .rate_max = MAX_RATE_PLAYBACK,
+ .channels_min = 1,
+ .channels_max = 8,
+ .buffer_bytes_max = NMDK_BUFFER_SIZE,
+ .period_bytes_min = 128,
+ .period_bytes_max = PAGE_SIZE,
+ .periods_min = NMDK_BUFFER_SIZE / PAGE_SIZE,
+ .periods_max = NMDK_BUFFER_SIZE / 128
+};
+
+static struct snd_pcm_hardware snd_u8500_capture_hw = {
+ .info =
+ (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE),
+ .formats =
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE |
+ SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_BE |
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE |
+ SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_U24_BE |
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE |
+ SNDRV_PCM_FMTBIT_S32_BE | SNDRV_PCM_FMTBIT_U32_BE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = MIN_RATE_CAPTURE,
+ .rate_max = MAX_RATE_CAPTURE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .buffer_bytes_max = NMDK_BUFFER_SIZE,
+ .period_bytes_min = 128,
+ .period_bytes_max = PAGE_SIZE,
+ .periods_min = NMDK_BUFFER_SIZE / PAGE_SIZE,
+ .periods_max = NMDK_BUFFER_SIZE / 128
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rate = {
+ .count = sizeof(u8500_acodec_rates) / sizeof(u8500_acodec_rates[0]),
+ .list = u8500_acodec_rates,
+ .mask = 0,
+};
+
+/**
+ * snd_u8500_alsa_pcm_close
+ * @substream - pointer to the playback/capture substream structure
+ *
+ * This routine is used by alsa framework to close a pcm stream .
+ * Here a dma pipe is disabled and freed.
+ */
+static int snd_u8500_alsa_pcm_close(struct snd_pcm_substream *substream)
+{
+ int stream_id, error = 0;
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+ audio_stream_t *ptr_audio_stream = NULL;
+
+ stream_id = substream->pstr->stream;
+ ptr_audio_stream = &chip->stream[ALSA_PCM_DEV][stream_id];
+
+ if (ENABLE == chip->direct_rendering_mode) {
+ ptr_audio_stream->substream = NULL;
+ return 0;
+ } else {
+ stm_close_alsa(chip, ALSA_PCM_DEV, stream_id);
+
+ /* reset the different variables to default */
+
+ ptr_audio_stream->active = 0;
+ ptr_audio_stream->period = 0;
+ ptr_audio_stream->periods = 0;
+ ptr_audio_stream->old_offset = 0;
+ ptr_audio_stream->substream = NULL;
+ if (!(--active_user)) {
+ /* Disable the MSP1 */
+ error = u8500_acodec_unsetuser(USER_ALSA);
+ u8500_acodec_close(I2S_CLIENT_MSP1, ACODEC_DISABLE_ALL);
+ } else {
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+ u8500_acodec_close(I2S_CLIENT_MSP1,
+ ACODEC_DISABLE_TRANSMIT);
+ else if (stream_id == SNDRV_PCM_STREAM_CAPTURE)
+ u8500_acodec_close(I2S_CLIENT_MSP1,
+ ACODEC_DISABLE_RECEIVE);
+ }
+
+ stm_hw_free(substream);
+
+ return error;
+ }
+}
+
+void my_write(u32 address, u8 data)
+{
+ ab8500_write(AB8500_AUDIO, address, data);
+}
+
+void dsp_configure_audio_codec(void)
+{
+ //4500 config for both record DMIC1&2 and playback HS stereo
+ //data width is 16 bits
+
+ my_write(0x200, 0x02); // Start-up audio unreset
+ my_write(0x20B, 0x10); // Start-up audio clk audio enable
+ my_write(0x383, 0x06); // Start-up audio Vaudio supply
+
+ my_write(0xD00, 0x88); // General power up=0x88
+ my_write(0xD01, 0x00); // Software Reset=0x0
+ my_write(0xD02, 0xC0); // Digital AD Channels Enable=0xC0
+ my_write(0xD03, 0xC0); // Digital DA Channels Enable=0xC0
+ my_write(0xD04, 0x00); // Low Power and Conf=0x0
+ my_write(0xD05, 0x0F); // Line in Conf=0xF
+ my_write(0xD06, 0xC0); // Analog Inputs Enable=0xC0
+ my_write(0xD07, 0x30); // ADC Enable=0x30
+ my_write(0xD08, 0x30); // Analog Output Enable=0x30
+ my_write(0xD09, 0x30); // Digital Output Enable=0x30
+ my_write(0xD0A, 0x4F); // Mute Enable=0x4F
+ my_write(0xD0B, 0x7F); // Short Circuit Disable=0x7F
+ my_write(0xD0C, 0x80); // Power-up for Headset=0x80
+ my_write(0xD0D, 0x00); // Envelope Threshold=0x0
+ my_write(0xD0E, 0x00); // Envelope Decay Time=0x0
+ my_write(0xD0F, 0xF0); // Class-D Configuration=0xF0
+ my_write(0xD10, 0x32); // PWM VIBNL Configuration=0x32
+ my_write(0xD11, 0x32); // PWM VIBPL Configuration=0x32
+ my_write(0xD12, 0x32); // PWM VIBNR Configuration=0x32
+ my_write(0xD13, 0x32); // PWM VIBPR Configuration=0x32
+ my_write(0xD14, 0x00); // Microphone 1 Gain=0x0
+ my_write(0xD15, 0x00); // Microphone 2 Gain=0x0
+ my_write(0xD16, 0x00); // Left line-in and HS Analog Gain=0x0
+ my_write(0xD17, 0x00); // Right line-in and HS Analog Gain=0x0
+ my_write(0xD18, 0x1F); // Line-in to HSL Gain=0x1F
+ my_write(0xD19, 0x1F); // Line-in to HSR Gain=0x1F
+ my_write(0xD1A, 0xF0); // AD Channel Filters Configuration=0xF0
+ my_write(0xD1B, 0x85); // TDM Configuration 1=0x85
+ my_write(0xD1C, 0x94); // TDM Configuration 2=0x94
+ my_write(0xD1D, 0x02); // TDM loopback control=0x2
+ my_write(0xD1E, 0x00); // TDM format=0x0
+ my_write(0xD1F, 0x10); // AD Data allocation in Slot 0 to 1=0x10
+ my_write(0xD20, 0xCC); // AD Data allocation in Slot 2 to 3=0xCC
+ my_write(0xD21, 0xCC); // AD Data allocation in Slots 4 to 5=0xCC
+ my_write(0xD22, 0xCC); // AD Data allocation in Slots 6 to 7=0xCC
+ my_write(0xD23, 0xCC); // AD Data allocation in Slots 8 to 9=0xCC
+ my_write(0xD24, 0xCC); // AD Data allocation in Slots 10 to 11=0xCC
+ my_write(0xD25, 0xCC); // AD Data allocation in Slots 12 to 13=0xCC
+ my_write(0xD26, 0xCC); // AD Data allocation in Slots 14 to 15=0xCC
+ my_write(0xD27, 0xCC); // AD Data allocation in Slots 16 to 17=0xCC
+ my_write(0xD28, 0xCC); // AD Data allocation in Slots 18 to 19=0xCC
+ my_write(0xD29, 0xCC); // AD Data allocation in Slots 20 to 21=0xCC
+ my_write(0xD2A, 0xCC); // AD Data allocation in Slots 22 to 23=0xCC
+ my_write(0xD2B, 0xCC); // AD Data allocation in Slots 24 to 25=0xCC
+ my_write(0xD2C, 0xCC); // AD Data allocation in Slots 26 to 27=0xCC
+ my_write(0xD2D, 0xCC); // AD Data allocation in Slots 28 to 29=0xCC
+ my_write(0xD2E, 0xCC); // AD Data allocation in Slots 30 to 31=0xCC
+ my_write(0xD2F, 0x00); // AD slot 0/7 tristate=0x0
+ my_write(0xD30, 0x00); // AD slot 8/15 tristate=0x0
+ my_write(0xD31, 0x00); // AD slot 16/23 tristate=0x0
+ my_write(0xD32, 0x00); // AD slot 24/31 tristate=0x0
+ my_write(0xD33, 0x08); // Slots selection for DA path 1=0x8
+ my_write(0xD34, 0x09); // Slots selection for DA path 2=0x9
+ my_write(0xD35, 0x00); // Slots selection for DA path 3=0x0
+ my_write(0xD36, 0x00); // Slots selection for DA path 4=0x0
+ my_write(0xD37, 0x00); // Slots selection for DA path 5=0x0
+ my_write(0xD38, 0x00); // Slots selection for DA path 6=0x0
+ my_write(0xD39, 0x00); // IRQ mask lsb=0x0
+ my_write(0xD3A, 0x00); // IRQ status lsb=0x0
+ my_write(0xD3B, 0x00); // IRQ mask msb=0x0
+ my_write(0xD3C, 0x00); // IRQ status msb=0x0
+ my_write(0xD3D, 0x00); // Fade speed=0x0
+ my_write(0xD3E, 0x00); // DMIC decimator filter=0x0
+ my_write(0xD3F, 0xF0); // muxing lsb=0xF0
+ my_write(0xD40, 0x00); // muxing msb=0x0
+ my_write(0xD41, 0x1F); // AD1 Digital Gain=0x1F
+ my_write(0xD42, 0x1F); // AD2 Digital Gain=0x1F
+ my_write(0xD43, 0x1F); // AD3 Digital Gain=0x1F
+ my_write(0xD44, 0x1F); // AD4 Digital Gain=0x1F
+ my_write(0xD45, 0x1F); // AD5 Digital Gain=0x1F
+ my_write(0xD46, 0x1F); // AD6 Digital Gain=0x1F
+ my_write(0xD47, 0x00); // DA1 digital Gain=0x00
+ my_write(0xD48, 0x00); // DA2 digital Gain=0x00
+ my_write(0xD49, 0x3F); // DA3 digital Gain=0x3F
+ my_write(0xD4A, 0x3F); // DA4 digital Gain=0x3F
+ my_write(0xD4B, 0x3F); // DA5 digital Gain=0x3F
+ my_write(0xD4C, 0x3F); // DA6 digital Gain=0x3F
+ my_write(0xD4D, 0x3F); // AD1 loopback to HFL digital gain=0x3F
+ my_write(0xD4E, 0x3F); // AD2 loopback to HFR digital gain=0x3F
+ my_write(0xD4F, 0x08); // HSL and EAR digital gain=0x8
+ my_write(0xD50, 0x08); // HSR digital gain=0x8
+ my_write(0xD51, 0x1F); // Side tone FIR1 gain=0x1F
+ my_write(0xD52, 0x1F); // Side tone FIR2 gain=0x1F
+ my_write(0xD53, 0x00); // ANC filter control=0x0
+ my_write(0xD54, 0x00); // ANC Warped Delay Line Shift=0x0
+ my_write(0xD55, 0x00); // ANC FIR output Shift=0x0
+ my_write(0xD56, 0x00); // ANC IIR output Shift=0x0
+ my_write(0xD57, 0x00); // ANC FIR coefficients msb=0x0
+ my_write(0xD58, 0x00); // ANC FIR coefficients lsb=0x0
+ my_write(0xD59, 0x00); // ANC IIR coefficients msb=0x0
+ my_write(0xD5A, 0x00); // ANC IIR coefficients lsb=0x0
+ my_write(0xD5B, 0x00); // ANC Warp delay msb=0x0
+ my_write(0xD5C, 0x00); // ANC Warp delay lsb=0x0
+ my_write(0xD5D, 0x00); // ANC FIR peak register MSB=0x0
+ my_write(0xD5E, 0x00); // ANC FIR peak register LSB=0x0
+ my_write(0xD5F, 0x00); // ANC IIR peak register. MSB part=0x0
+ my_write(0xD60, 0x00); // ANC IIR peak register. LSB part=0x0
+ my_write(0xD61, 0x00); // Side tone FIR address=0x0
+ my_write(0xD62, 0x00); // Side tone FIR coefficient MSB=0x0
+ my_write(0xD63, 0x00); // Side tone FIR coefficient LSB=0x0
+ my_write(0xD64, 0x00); // Filters control=0x0
+ my_write(0xD65, 0x00); // Class D EMI Control=0x0
+ my_write(0xD66, 0x00); // Class D control path=0x0
+ my_write(0xD67, 0x00); // Class D control gain=0x0
+ my_write(0xD68, 0x00); // Burst FIFO int control=0x0
+ my_write(0xD69, 0x00); // Burst FIFO length=0x0
+ my_write(0xD6A, 0x00); // Burst FIFO control=0x0
+ my_write(0xD6B, 0x00); // Burst FIFO switch frame=0x0
+ my_write(0xD6C, 0x00); // Burst FIFO wake up delay=0x0
+ my_write(0xD6D, 0x00); // Burst FIFO samples number=0x0
+ my_write(0xD70, 0x00); // CR112=0x0
+ my_write(0xD71, 0x04); // CR113=0x4
+ my_write(0xD72, 0x00); // CR114=0x0
+ my_write(0xD73, 0x00); // CR115=0x0
+ my_write(0xD74, 0x00); // CR116=0x0
+ my_write(0xD75, 0x00); // CR117=0x0
+ my_write(0xD76, 0x00); // CR118=0x0
+ my_write(0xD77, 0x00); // CR119=0x0
+ my_write(0xD78, 0x00); // CR120=0x0
+ my_write(0xD79, 0x00); // CR121=0x0
+ my_write(0xD7A, 0x00); // CR122=0x0
+ my_write(0xD7B, 0x00); // CR123=0x0
+}
+
+static int configure_direct_rendering(struct snd_pcm_substream *substream)
+{
+ int error = 0, stream_id;
+ int status = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+ audio_stream_t *ptr_audio_stream = NULL;
+
+ stream_id = substream->pstr->stream;
+
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw = snd_u8500_playback_hw;
+ } else {
+ runtime->hw = snd_u8500_capture_hw;
+ }
+
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x04))); //MSP_GCR
+
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x08))); //MSP
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x0C))); //MSP
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x10))); //MSP
+
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x30))); //MSP
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x34))); //MSP
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x38))); //MSP
+
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x40))); //MSP
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x44))); //MSP
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x48))); //MSP
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x4C))); //MSP
+
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x60))); //MSP
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x64))); //MSP
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x68))); //MSP
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x6C))); //MSP
+
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x18))); //MSP
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x20))); //MSP
+ writel(0x0, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x2C))); //MSP
+
+ status = stm_gpio_altfuncenable(GPIO_ALT_MSP_1);
+ if (status) {
+ printk("Error in stm_gpio_altfuncenable, status is %d\n",
+ status);
+ }
+
+ printk("\n stm_gpio_altfuncenable for GPIO_ALT_MSP_1\n");
+
+ dsp_configure_audio_codec();
+
+#if DRIVER_DEBUG > 0
+ {
+ dump_msp_registers();
+ dump_acodec_registers();
+ }
+#endif
+
+ ptr_audio_stream = &chip->stream[ALSA_PCM_DEV][stream_id];
+
+ ptr_audio_stream->substream = substream;
+
+ FUNC_EXIT();
+ return 0;
+}
+
+/**
+ * snd_u8500_alsa_pcm_open
+ * @substream - pointer to the playback/capture substream structure
+ *
+ * This routine is used by alsa framework to open a pcm stream .
+ * Here a dma pipe is requested and device is configured(default).
+ */
+static int snd_u8500_alsa_pcm_open(struct snd_pcm_substream *substream)
+{
+ int error = 0, stream_id, status = 0;
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ audio_stream_t *ptr_audio_stream = NULL;
+
+ FUNC_ENTER();
+
+ if (ENABLE == chip->direct_rendering_mode) {
+ configure_direct_rendering(substream);
+ return 0;
+ } else {
+ stream_id = substream->pstr->stream;
+ status = u8500_acodec_open(I2S_CLIENT_MSP1, stream_id);
+
+ if (status) {
+ printk("failed in getting open\n");
+ return -1;
+ }
+
+ if (!active_user)
+ error = u8500_acodec_setuser(USER_ALSA);
+ if (error)
+ return error;
+ else
+ active_user++;
+
+ error =
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_rate);
+ if (error < 0) {
+ stm_error
+ (": error initializing hw sample rate constraint\n");
+ return error;
+ }
+
+ /* configure the default sampling rate for the acodec */
+ second_config = 0;
+
+ if ((error = configure_rate(substream, ACODEC_CONFIG_REQUIRED)))
+ return error;
+
+ /* Set the hardware configuration */
+ stream_id = substream->pstr->stream;
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw = snd_u8500_playback_hw;
+ /* configure the output sink for the acodec */
+ if ((error =
+ u8500_acodec_select_output(chip->output_device,
+ USER_ALSA,
+ chip->tdm8_ch_mode))) {
+ stm_error(" : select output failed\n");
+ return error;
+ }
+
+ /* configure the volume settings for the acodec */
+ if ((error =
+ u8500_acodec_set_output_volume(chip->output_device,
+ chip->
+ output_lvolume,
+ chip->
+ output_rvolume,
+ USER_ALSA))) {
+ stm_error(" : set output volume failed\n");
+ return error;
+ }
+ } else {
+ runtime->hw = snd_u8500_capture_hw;
+ /* configure the input source for the acodec */
+ if ((error =
+ u8500_acodec_select_input(chip->input_device,
+ USER_ALSA,
+ chip->tdm8_ch_mode))) {
+ stm_error(" : select input failed\n");
+ return error;
+ }
+ /*u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_1,ENABLE);
+ u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_2,ENABLE);
+
+ u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_1,
+ chip->input_lvolume,
+ chip->input_rvolume,
+ USER_ALSA);
+
+ u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_2,
+ chip->input_lvolume,
+ chip->input_rvolume,
+ USER_ALSA);
+ */
+
+ if ((error =
+ u8500_acodec_set_input_volume(chip->input_device,
+ chip->input_lvolume,
+ chip->input_rvolume,
+ USER_ALSA))) {
+ stm_error(" : set input volume failed\n");
+ return error;
+ }
+ }
+
+ u8500_acodec_set_burst_mode_fifo(chip->burst_fifo_mode);
+
+#if DRIVER_DEBUG > 0
+ {
+ dump_msp_registers();
+ dump_acodec_registers();
+ }
+#endif
+
+ ptr_audio_stream = &chip->stream[ALSA_PCM_DEV][stream_id];
+
+ ptr_audio_stream->substream = substream;
+
+ if (DISABLE == chip->direct_rendering_mode) {
+ stm_config_hw(chip, substream, ALSA_PCM_DEV, stream_id);
+ }
+ init_MUTEX(&(ptr_audio_stream->alsa_sem));
+ init_completion(&(ptr_audio_stream->alsa_com));
+ ptr_audio_stream->state = ALSA_STATE_UNPAUSE;
+
+ FUNC_EXIT();
+ return 0;
+ }
+}
+
+/**
+ * snd_u8500_alsa_pcm_hw_params
+ * @substream - pointer to the playback/capture substream structure
+ * @hw_params - specifies the hw parameters like format/no of channels etc
+ *
+ * This routine is used by alsa framework to allocate a dma buffer
+ * used to transfer the data from user space to kernel space
+ *
+ */
+static int snd_u8500_alsa_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ return snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+}
+
+/**
+ * snd_u8500_alsa_pcm_hw_free
+ * @substream - pointer to the playback/capture substream structure
+ *
+ * This routine is used by alsa framework to deallocate a dma buffer
+ * allocated berfore by snd_u8500_alsa_pcm_hw_params
+ */
+static int snd_u8500_alsa_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ stm_hw_free(substream);
+ return 0;
+}
+
+/**
+ * snd_u8500_alsa_pcm_prepare
+ * @substream - pointer to the playback/capture substream structure
+ *
+ * This callback is called whene the pcm is "prepared" Here is possible
+ * to set the format type ,sample rate ,etc.The callback is called as
+ * well everytime a recovery after an underrun happens.
+ */
+
+static int snd_u8500_alsa_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int error, stream_id;
+
+ FUNC_ENTER();
+
+ if (chip->freq != runtime->rate || chip->channels != runtime->channels) {
+ stm_dbg(DBG_ST.alsa, " freq not same, %d %d\n", chip->freq,
+ runtime->rate);
+ stm_dbg(DBG_ST.alsa, " channels not same, %d %d\n",
+ chip->channels, runtime->channels);
+ if (chip->channels != runtime->channels) {
+ chip->channels = runtime->channels;
+ if ((error =
+ stm_config_hw(chip, substream, ALSA_PCM_DEV,
+ -1))) {
+ stm_dbg(DBG_ST.alsa,
+ "In func %s, stm_config_hw fails",
+ __FUNCTION__);
+ return error;
+ }
+ }
+ chip->freq = runtime->rate;
+ second_config = 1;
+ stream_id = substream->pstr->stream;
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+ u8500_acodec_close(I2S_CLIENT_MSP1,
+ ACODEC_DISABLE_TRANSMIT);
+ else if (stream_id == SNDRV_PCM_STREAM_CAPTURE)
+ u8500_acodec_close(I2S_CLIENT_MSP1,
+ ACODEC_DISABLE_RECEIVE);
+
+ error = u8500_acodec_open(I2S_CLIENT_MSP1, stream_id);
+ if (error) {
+ printk("failed in getting open\n");
+ return -1;
+ }
+ if ((error =
+ configure_rate(substream, ACODEC_CONFIG_NOT_REQUIRED))) {
+ stm_dbg(DBG_ST.alsa, "In func %s, configure_rate fails",
+ __FUNCTION__);
+ return error;
+ }
+ }
+
+ FUNC_EXIT();
+ return 0;
+}
+
+/**
+ * snd_u8500_alsa_pcm_trigger
+ * @substream - pointer to the playback/capture substream structure
+ * @cmd - specifies the command : start/stop/pause/resume
+ *
+ * This callback is called whene the pcm is started ,stopped or paused
+ * The action is specified in the second argument, SND_PCM_TRIGGER_XXX in
+ * <sound/pcm.h>.
+ * This callback is atomic and the interrupts are disabled , so you can't
+ * call other functions that need interrupts without possible risks
+ */
+static int snd_u8500_alsa_pcm_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ int stream_id = substream->pstr->stream;
+ audio_stream_t *stream = NULL;
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+ int error = 0;
+
+ FUNC_ENTER();
+
+ stream = &chip->stream[ALSA_PCM_DEV][stream_id];
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* Start the pcm engine */
+ stm_dbg(DBG_ST.alsa, " TRIGGER START\n");
+ if (stream->active == 0) {
+ stream->active = 1;
+ stm_trigger_alsa(stream);
+ break;
+ }
+ stm_error(": H/w is busy\n");
+ return -EINVAL;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ stm_dbg(DBG_ST.alsa, " SNDRV_PCM_TRIGGER_PAUSE_PUSH\n");
+ if (stream->active == 1) {
+ stm_pause_alsa(stream);
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ stm_dbg(DBG_ST.alsa, " SNDRV_PCM_TRIGGER_PAUSE_RELEASE\n");
+ if (stream->active == 1)
+ stm_unpause_alsa(stream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* Stop the pcm engine */
+ stm_dbg(DBG_ST.alsa, " TRIGGER STOP\n");
+ if (stream->active == 1)
+ stm_stop_alsa(stream);
+ break;
+ default:
+ stm_error(": invalid command in pcm trigger\n");
+ return -EINVAL;
+ }
+
+ FUNC_EXIT();
+ return error;
+}
+
+/**
+ * snd_u8500_alsa_pcm_pointer
+ * @substream - pointer to the playback/capture substream structure
+ *
+ * This callback is called whene the pcm middle layer inquires the current
+ * hardware position on the buffer .The position is returned in frames
+ * ranged from 0 to buffer_size -1
+ */
+static snd_pcm_uframes_t snd_u8500_alsa_pcm_pointer(struct snd_pcm_substream
+ *substream)
+{
+ unsigned int offset;
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+ audio_stream_t *stream =
+ &chip->stream[ALSA_PCM_DEV][substream->pstr->stream];
+ struct snd_pcm_runtime *runtime = stream->substream->runtime;
+
+ offset = bytes_to_frames(runtime, stream->old_offset);
+ if (offset < 0 || stream->old_offset < 0)
+ stm_dbg(DBG_ST.alsa, " Offset=%i %i\n", offset,
+ stream->old_offset);
+
+ return offset;
+}
+
+static struct snd_pcm_ops snd_u8500_alsa_playback_ops = {
+ .open = snd_u8500_alsa_pcm_open,
+ .close = snd_u8500_alsa_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_u8500_alsa_pcm_hw_params,
+ .hw_free = snd_u8500_alsa_pcm_hw_free,
+ .prepare = snd_u8500_alsa_pcm_prepare,
+ .trigger = snd_u8500_alsa_pcm_trigger,
+ .pointer = snd_u8500_alsa_pcm_pointer,
+};
+
+static struct snd_pcm_ops snd_u8500_alsa_capture_ops = {
+ .open = snd_u8500_alsa_pcm_open,
+ .close = snd_u8500_alsa_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_u8500_alsa_pcm_hw_params,
+ .hw_free = snd_u8500_alsa_pcm_hw_free,
+ .prepare = snd_u8500_alsa_pcm_prepare,
+ .trigger = snd_u8500_alsa_pcm_trigger,
+ .pointer = snd_u8500_alsa_pcm_pointer,
+};
+
+#ifdef CONFIG_U8500_ACODEC_POLL
+
+/**
+* u8500_alsa_pio_start
+* @stream - pointer to the playback/capture audio_stream_t structure
+*
+* This function sends/receive one chunck of stream data to/from MSP
+*/
+static void u8500_alsa_pio_start(audio_stream_t * stream)
+{
+ unsigned int offset, dma_size, stream_id;
+ int ret_val;
+ struct snd_pcm_substream *substream = stream->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ stream_id = substream->pstr->stream;
+
+ FUNC_ENTER();
+ dma_size = frames_to_bytes(runtime, runtime->period_size);
+ offset = dma_size * stream->period;
+ stream->old_offset = offset;
+
+ stm_dbg(DBG_ST.alsa, " Transfer started\n");
+ stm_dbg(DBG_ST.alsa, " address = %x size=%d\n",
+ (runtime->dma_addr + offset), dma_size);
+
+ /* Send our stuff */
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+#ifdef CONFIG_U8500_ACODEC_DMA
+ u8500_acodec_send_data(I2S_CLIENT_MSP1,
+ (void *)(runtime->dma_addr + offset),
+ dma_size, 1);
+#else
+ u8500_acodec_send_data(I2S_CLIENT_MSP1,
+ (void *)(runtime->dma_area + offset),
+ dma_size, 0);
+#endif
+ else
+#ifdef CONFIG_U8500_ACODEC_DMA
+ u8500_acodec_receive_data(I2S_CLIENT_MSP1,
+ (void *)(runtime->dma_addr + offset),
+ dma_size, 1);
+#else
+ u8500_acodec_receive_data(I2S_CLIENT_MSP1,
+ (void *)(runtime->dma_area + offset),
+ dma_size, 0);
+#endif
+
+ stream->period++;
+ stream->period %= runtime->periods;
+ stream->periods++;
+
+ FUNC_EXIT();
+
+}
+
+/**
+* acodec_feeding_thread
+* @data - void pointer to the playback/capture audio_stream_t structure
+*
+* This thread sends/receive data to MSP while stream is active
+*/
+static int acodec_feeding_thread(void *data)
+{
+ audio_stream_t *stream = (audio_stream_t *) data;
+
+ FUNC_ENTER();
+ daemonize("acodec_feeding_thread");
+ allow_signal(SIGKILL);
+ down(&stream->alsa_sem);
+
+ while ((!signal_pending(current)) && (stream->active)) {
+ if (stream->state == ALSA_STATE_PAUSE)
+ wait_for_completion(&(stream->alsa_com));
+
+ u8500_alsa_pio_start(stream);
+ if (stream->substream)
+ snd_pcm_period_elapsed(stream->substream);
+ }
+
+ up(&stream->alsa_sem);
+
+ FUNC_EXIT();
+ return 0;
+}
+
+/**
+* acodec_feeding_thread
+* @stream - pointer to the playback/capture audio_stream_t structure
+*
+* This function creates a kernel thread .
+*/
+
+int spawn_acodec_feeding_thread(audio_stream_t * stream)
+{
+ pid_t pid;
+
+ FUNC_ENTER();
+
+ pid =
+ kernel_thread(acodec_feeding_thread, stream,
+ CLONE_FS | CLONE_SIGHAND);
+
+ FUNC_EXIT();
+ return 0;
+}
+#endif
+
+/**
+ * dma_eot_handler
+ * @data - pointer to structure set in the dma callback handler
+ *
+ * This is the PCM tasklet handler linked to a pipe, its role is to tell
+ * the PCM middler layer whene the buffer position goes across the prescribed
+ * period size.To inform of this the snd_pcm_period_elapsed is called.
+ *
+ * this callback will be called in case of DMA_EVENT_TC only
+ */
+static void dma_eot_handler(void *data)
+{
+ audio_stream_t *stream = data;
+
+ /* snd_pcm_period_elapsed() is _not_ to be protected
+ */
+ stm_dbg(DBG_ST.alsa,
+ "One transfer complete.. going to start the next one\n");
+
+ if (stream->substream)
+ snd_pcm_period_elapsed(stream->substream);
+ if (stream->state == ALSA_STATE_PAUSE)
+ return;
+ if (stream->active == 1) {
+ u8500_alsa_dma_start(stream);
+ }
+}
+
+/**
+ * u8500_alsa_dma_start - used to transmit or recive a dma chunk
+ * @stream - specifies the playback/record stream structure
+ */
+void u8500_alsa_dma_start(audio_stream_t * stream)
+{
+ unsigned int offset, dma_size, stream_id;
+
+ struct snd_pcm_substream *substream = stream->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ u8500_acodec_chip_t *u8500_chip = NULL;
+ stream_id = substream->pstr->stream;
+ u8500_chip = snd_pcm_substream_chip(substream);
+
+ dma_size = frames_to_bytes(runtime, runtime->period_size);
+ offset = dma_size * stream->period;
+ stream->old_offset = offset;
+
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+#ifdef CONFIG_U8500_ACODEC_DMA
+ u8500_acodec_send_data(I2S_CLIENT_MSP1,
+ (void *)(runtime->dma_addr + offset),
+ dma_size, 1);
+#else
+ u8500_acodec_send_data(I2S_CLIENT_MSP1,
+ (void *)(runtime->dma_area + offset),
+ dma_size, 0);
+#endif
+ else
+#ifdef CONFIG_U8500_ACODEC_DMA
+ u8500_acodec_receive_data(I2S_CLIENT_MSP1,
+ (void *)(runtime->dma_addr + offset),
+ dma_size, 1);
+#else
+ u8500_acodec_receive_data(I2S_CLIENT_MSP1,
+ (void *)(runtime->dma_area + offset),
+ dma_size, 0);
+#endif
+
+ stm_dbg(DBG_ST.alsa, " DMA Transfer started\n");
+ stm_dbg(DBG_ST.alsa, " address = %x size=%d\n",
+ (runtime->dma_addr + offset), dma_size);
+
+ stream->period++;
+ stream->period %= runtime->periods;
+ stream->periods++;
+}
+
+/**
+* u8500_audio_init
+* @chip - pointer to u8500_acodec_chip_t structure.
+*
+* This function intialises the u8500 chip structure with default values
+*/
+static void u8500_audio_init(u8500_acodec_chip_t * chip)
+{
+ audio_stream_t *ptr_audio_stream = NULL;
+
+ ptr_audio_stream =
+ &chip->stream[ALSA_PCM_DEV][SNDRV_PCM_STREAM_PLAYBACK];
+ /* Setup DMA stuff */
+ strlcpy(ptr_audio_stream->id, "u8500 playback",
+ sizeof(ptr_audio_stream->id));
+ ptr_audio_stream->stream_id = SNDRV_PCM_STREAM_PLAYBACK;
+
+ /* default initialization for playback */
+ ptr_audio_stream->active = 0;
+ ptr_audio_stream->period = 0;
+ ptr_audio_stream->periods = 0;
+ ptr_audio_stream->old_offset = 0;
+
+ ptr_audio_stream =
+ &chip->stream[ALSA_PCM_DEV][SNDRV_PCM_STREAM_CAPTURE];
+ strlcpy(ptr_audio_stream->id, "u8500 capture",
+ sizeof(ptr_audio_stream->id));
+ ptr_audio_stream->stream_id = SNDRV_PCM_STREAM_CAPTURE;
+
+ /* default initialization for capture */
+ ptr_audio_stream->active = 0;
+ ptr_audio_stream->period = 0;
+ ptr_audio_stream->periods = 0;
+ ptr_audio_stream->old_offset = 0;
+
+ chip->freq = DEFAULT_SAMPLE_RATE;
+ chip->channels = 1;
+ chip->input_lvolume = DEFAULT_GAIN;
+ chip->input_rvolume = DEFAULT_GAIN;
+ chip->output_lvolume = DEFAULT_VOLUME;
+ chip->output_rvolume = DEFAULT_VOLUME;
+ chip->output_device = DEFAULT_OUTPUT_DEVICE;
+ chip->input_device = DEFAULT_INPUT_DEVICE;
+ chip->analog_lpbk = DEFAULT_LOOPBACK_STATE;
+ chip->digital_lpbk = DEFAULT_LOOPBACK_STATE;
+ chip->playback_switch = DEFAULT_SWITCH_STATE;
+ chip->capture_switch = DEFAULT_SWITCH_STATE;
+ chip->tdm8_ch_mode = DEFAULT_TDM8_CH_MODE_STATE;
+ chip->direct_rendering_mode = DEFAULT_DIRECT_RENDERING_STATE;
+ chip->burst_fifo_mode = DEFAULT_BURST_FIFO_STATE;
+ chip->fm_playback_mode = DEFAULT_FM_PLAYBACK_STATE;
+ chip->fm_tx_mode = DEFAULT_FM_TX_STATE;
+
+ //HDMI Default params set
+ chip->hdmi_params.sampling_freq = 48000;
+ chip->hdmi_params.channel_count = 2;
+}
+
+/**
+ * snd_card_u8500_alsa_pcm_new - constructor for a new pcm cmponent
+ * @chip - pointer to chip specific data
+ * @device - specifies the card number
+ */
+static int snd_card_u8500_alsa_pcm_new(u8500_acodec_chip_t * chip, int device)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ if ((err = snd_pcm_new(chip->card, "u8500", device, 1, 1, &pcm)) < 0) {
+ stm_error(": error in snd_pcm_new\n");
+ return err;
+ }
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_u8500_alsa_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_u8500_alsa_capture_ops);
+
+ pcm->private_data = chip;
+ pcm->info_flags = 0;
+ chip->pcm = pcm;
+ strcpy(pcm->name, "u8500_alsa");
+
+ u8500_audio_init(pcm->private_data);
+ return 0;
+}
+
+static int u8500_register_alsa_controls(struct snd_card *card,
+ u8500_acodec_chip_t * u8500_chip)
+{
+ int error;
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_playback_vol_ctrl,
+ u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_playback_vol_ctrl interface \n\n");
+ return (-1);
+ }
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_capture_vol_ctrl,
+ u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_capture_vol_ctrl interface \n\n");
+ return (-1);
+ }
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_playback_sink_ctrl,
+ u8500_chip))) < 0) {
+ stm_error(": error initializing playback ctrl interface \n\n");
+ return (-1);
+ }
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_capture_src_ctrl,
+ u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_playback_sink_ctrl interface \n\n");
+ return (-1);
+ }
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_analog_lpbk_ctrl,
+ u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_analog_lpbk_ctrl interface \n\n");
+ return (-1);
+ }
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_digital_lpbk_ctrl,
+ u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_digital_lpbk_ctrl interface \n\n");
+ return (-1);
+ }
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_playback_switch_ctrl,
+ u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_playback_switch_ctrl interface \n\n");
+ return (-1);
+ }
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_capture_switch_ctrl,
+ u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_capture_switch_ctrl interface \n\n");
+ return (-1);
+ }
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_playback_power_ctrl,
+ u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_playback_power_ctrl interface \n\n");
+ return (-1);
+ }
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_capture_power_ctrl,
+ u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_capture_power_ctrl interface \n\n");
+ return (-1);
+ }
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_tdm_mode_ctrl, u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_tdm_mode_ctrl interface \n\n");
+ return (-1);
+ }
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_direct_rendering_mode_ctrl,
+ u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_direct_rendering_mode_ctrl interface \n\n");
+ return (-1);
+ }
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_pcm_rendering_mode_ctrl,
+ u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_pcm_rendering_mode_ctrl interface \n\n");
+ return (-1);
+ }
+
+ return 0;
+}
+
+static int __init u8500_alsa_probe(struct platform_device *devptr)
+{
+ //static int card_count=0;
+ int error;
+ struct snd_card *card, *hdmi_card;
+ u8500_acodec_chip_t *u8500_chip;
+
+ /*Set currently active users to 0 */
+ active_user = 0;
+
+ error = snd_card_create(0, NULL, THIS_MODULE, sizeof(u8500_acodec_chip_t), &card);
+ if (error < 0) {
+ stm_error(": error in snd_card_create\n");
+ return error;
+ }
+
+ u8500_chip = (u8500_acodec_chip_t *) card->private_data;
+ u8500_chip->card = card;
+
+ if ((error = snd_card_u8500_alsa_pcm_new(u8500_chip, 0)) < 0) {
+ stm_error(": pcm interface can't be initialized\n\n");
+ goto nodev;
+ }
+
+ if ((error = snd_card_u8500_alsa_hdmi_new(u8500_chip, 1)) < 0) {
+ stm_error(": alsa HDMI interface can't be initialized\n\n");
+ goto nodev;
+ }
+
+ if (u8500_register_alsa_controls(card, u8500_chip) < 0) {
+ goto nodev;
+ }
+
+ if (u8500_register_alsa_hdmi_controls(card, u8500_chip) < 0) {
+ goto nodev;
+ }
+#if 0
+ ///////////////////////////////$ H D M I $//////////////////////////////////////
+
+ if (card_count == 1) {
+ hdmi_card =
+ snd_card_new(1, NULL, THIS_MODULE,
+ sizeof(u8500_acodec_chip_t));
+ if (hdmi_card == NULL) {
+ stm_error(": error in hdmi - snd_card_new\n");
+ return -ENOMEM;
+ }
+
+ u8500_chip = (u8500_acodec_chip_t *) hdmi_card->private_data;
+ u8500_chip->card = hdmi_card;
+
+ if ((error = snd_card_u8500_alsa_hdmi_new(u8500_chip, 0)) < 0) {
+ stm_error
+ (": alsa HDMI interface can't be initialized\n\n");
+ goto nodev;
+ }
+
+ if (u8500_register_alsa_hdmi_controls(card, u8500_chip) < 0) {
+ goto nodev;
+ }
+ }
+#endif ////////////////////////////////////////////////////////
+
+ /*char driver[16]; driver name
+ char shortname[32]; short name of this soundcard
+ char longname[80]; name of this soundcard
+ char mixername[80]; mixer name
+ char components[80]; card components delimited withspace */
+
+ strcpy(card->driver, "u8500 alsa");
+ strcpy(card->shortname, "u8500 alsa pcm hdmi driver");
+ strcpy(card->longname, "u8500 alsa pcm hdmi driver");
+
+ snd_card_set_dev(card, &devptr->dev);
+
+ if ((error = snd_card_register(card)) == 0) {
+ stm_info("u8500 audio <hdmi> support running..\n");
+ platform_set_drvdata(devptr, card);
+ return 0;
+ }
+
+ nodev:
+ snd_card_free(card);
+ return error;
+}
+
+static int __devexit u8500_alsa_remove(struct platform_device *devptr)
+{
+ snd_card_free(platform_get_drvdata(devptr));
+ platform_set_drvdata(devptr, NULL);
+ stm_info("u8500 audio support stopped\n");
+
+ /*Set currently active users to 0 */
+ active_user = 0;
+
+ return 0;
+}
+
+static struct platform_driver u8500_alsa_driver = {
+ .probe = u8500_alsa_probe,
+ .remove = __devexit_p(u8500_alsa_remove),
+ .driver = {
+ .name = U8500_ALSA_DRIVER,
+ },
+};
+
+/**
+* u8500_alsa_init - Entry function of AB8500 alsa driver
+*
+* This function registers u8500 alsa driver with linux framework
+*/
+static int __init u8500_alsa_init(void)
+{
+ int err;
+
+ if ((err = platform_driver_register(&u8500_alsa_driver)) < 0)
+ return err;
+ device =
+ platform_device_register_simple(U8500_ALSA_DRIVER, -1, NULL, 0);
+ if (IS_ERR(device)) {
+ platform_driver_unregister(&u8500_alsa_driver);
+ return PTR_ERR(device);
+ }
+ //DBG_ST.acodec = 1;
+ //DBG_ST.alsa = 1;
+
+ return 0;
+}
+
+static void __exit u8500_alsa_exit(void)
+{
+ platform_device_unregister(device);
+ platform_driver_unregister(&u8500_alsa_driver);
+}
+
+module_init(u8500_alsa_init);
+module_exit(u8500_alsa_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AB8500 ALSA driver");
diff --git a/sound/arm/u8500_alsa_ab8500.h b/sound/arm/u8500_alsa_ab8500.h
new file mode 100644
index 00000000000..dda802c2156
--- /dev/null
+++ b/sound/arm/u8500_alsa_ab8500.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Deepak Karda
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 _U8500_ALSA_H_
+#define _U8500_ALSA_H_
+
+#ifdef CONFIG_U8500_AB8500_CUT10
+#include <mach/ab8500_codec_v1_0.h>
+//#include <mach/ab8500_codec_p_v1_0.h>
+#else
+//#include <mach/ab8500_codec_p.h>
+#include <mach/ab8500_codec.h>
+#endif
+#include <mach/u8500_acodec_ab8500.h>
+
+#define DEFAULT_SAMPLE_RATE 48000
+#define NMDK_BUFFER_SIZE (64*1024)
+#define U8500_ALSA_DRIVER "u8500_alsa"
+
+#define MAX_NUMBER_OF_DEVICES 3 /* ALSA_PCM, ALSA_BT, ALSA_HDMI */
+#define MAX_NUMBER_OF_STREAMS 2 /* PLAYBACK, CAPTURE */
+
+#define ALSA_PCM_DEV 0
+#define ALSA_BT_DEV 2
+#define ALSA_HDMI_DEV 1
+
+/* Debugging stuff */
+#ifndef CONFIG_DEBUG_USER
+#define DEBUG_LEVEL 0
+#else
+#define DEBUG_LEVEL 10
+#endif
+
+#if DEBUG_LEVEL > 0
+static int u8500_acodec_debug = DEBUG_LEVEL;
+#define DEBUG(n, args...) do { if (u8500_acodec_debug>(n)) printk(args); } while (0)
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+enum alsa_state {
+ ALSA_STATE_PAUSE,
+ ALSA_STATE_UNPAUSE
+};
+
+/* audio stream definition */
+typedef struct audio_stream_s {
+ char id[64]; /* module identifier string */
+ int stream_id; /* stream identifier */
+ int status;
+ int active; /* we are using this stream for transfer now */
+ int period; /* current transfer period */
+ int periods; /* current count of periods registerd in the DMA engine */
+ enum alsa_state state;
+ unsigned int old_offset;
+ struct snd_pcm_substream *substream;
+ unsigned int exchId;
+ snd_pcm_uframes_t played_frame;
+ struct semaphore alsa_sem;
+ struct completion alsa_com;
+
+} audio_stream_t;
+
+typedef struct hdmi_params_s {
+ int sampling_freq;
+ int channel_count;
+} hdmi_params_t;
+
+/* chip structure definition */
+typedef struct u8500_acodec_s {
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ struct snd_pcm *pcm_hdmi;
+ struct snd_pcm *pcm_bt;
+ unsigned int freq;
+ unsigned int channels;
+ unsigned int input_lvolume;
+ unsigned int input_rvolume;
+ unsigned int output_lvolume;
+ unsigned int output_rvolume;
+ t_ab8500_codec_src input_device;
+ t_ab8500_codec_dest output_device;
+ t_u8500_bool_state analog_lpbk;
+ t_u8500_bool_state digital_lpbk;
+ t_u8500_bool_state playback_switch;
+ t_u8500_bool_state capture_switch;
+ t_u8500_bool_state tdm8_ch_mode;
+ t_u8500_bool_state direct_rendering_mode;
+ t_u8500_pmc_rendering_state burst_fifo_mode;
+ t_u8500_pmc_rendering_state fm_playback_mode;
+ t_u8500_pmc_rendering_state fm_tx_mode;
+ audio_stream_t stream[MAX_NUMBER_OF_DEVICES][MAX_NUMBER_OF_STREAMS];
+ hdmi_params_t hdmi_params;
+} u8500_acodec_chip_t;
+
+void u8500_alsa_dma_start(audio_stream_t * stream);
+
+#if (defined(CONFIG_U8500_ACODEC_DMA) || defined(CONFIG_U8500_ACODEC_INTR))
+
+#define stm_trigger_alsa(x) u8500_alsa_dma_start(x)
+static void inline stm_pause_alsa(audio_stream_t * stream)
+{
+ if (stream->state == ALSA_STATE_UNPAUSE) {
+ stream->state = ALSA_STATE_PAUSE;
+ }
+
+}
+static void inline stm_unpause_alsa(audio_stream_t * stream)
+{
+ if (stream->state == ALSA_STATE_PAUSE) {
+ stream->state = ALSA_STATE_UNPAUSE;
+ stm_trigger_alsa(stream);
+ }
+}
+static void inline stm_stop_alsa(audio_stream_t * stream)
+{
+ stream->active = 0;
+ stream->period = 0;
+
+}
+static void inline stm_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_lib_free_pages(substream);
+}
+
+#define stm_close_alsa(x, y,z)
+#define stm_config_hw(w,x, y, z) 0
+
+#else ////// CONFIG_U8500_ACODEC_POLL ////////////
+
+int spawn_acodec_feeding_thread(audio_stream_t * stream);
+//static int configure_dmadev_acodec(struct snd_pcm_substream *substream);
+
+#define stm_trigger_alsa(x) spawn_acodec_feeding_thread(x)
+#define stm_close_alsa(x, y,z)
+#define stm_config_hw(w,x, y, z) 0
+#define stm_hw_free(x)
+static void inline stm_pause_alsa(audio_stream_t * stream)
+{
+ stream->state = ALSA_STATE_PAUSE;
+}
+static void inline stm_unpause_alsa(audio_stream_t * stream)
+{
+ stream->state = ALSA_STATE_UNPAUSE;
+ complete(&stream->alsa_com);
+}
+static void inline stm_stop_alsa(audio_stream_t * stream)
+{
+ stream->active = 0;
+ stream->period = 0;
+ if (stream->state == ALSA_STATE_PAUSE)
+ complete(&stream->alsa_com);
+}
+
+#endif
+#endif /*END OF HEADER FILE */
diff --git a/sound/arm/u8500_alsa_hdmi.c b/sound/arm/u8500_alsa_hdmi.c
new file mode 100644
index 00000000000..dfadc1ee624
--- /dev/null
+++ b/sound/arm/u8500_alsa_hdmi.c
@@ -0,0 +1,936 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL),
+ * version 2.
+ */
+
+/* This include must be defined at this point */
+//#include <sound/driver.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <mach/hardware.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* alsa system */
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include "u8500_alsa_ab8500.h"
+#include <mach/msp.h>
+#include <mach/debug.h>
+
+#define ALSA_NAME "DRIVER ALSA HDMI"
+
+/* enables/disables debug msgs */
+#define DRIVER_DEBUG CONFIG_STM_ALSA_DEBUG
+/* msg header represents this module */
+#define DRIVER_DEBUG_PFX ALSA_NAME
+/* message level */
+#define DRIVER_DBG KERN_ERR
+#define ELEMENT_SIZE 0
+
+extern char *power_state_in_texts[NUMBER_POWER_STATE];
+
+static int u8500_hdmi_power_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+static int u8500_hdmi_power_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+static int u8500_hdmi_power_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo);
+
+void dump_msp2_registers();
+
+#ifdef CONFIG_U8500_ACODEC_DMA
+
+static void u8500_alsa_hdmi_dma_start(audio_stream_t * stream);
+#define stm_trigger_hdmi(x) u8500_alsa_hdmi_dma_start(x)
+static void inline stm_pause_hdmi(audio_stream_t * stream)
+{
+ if (stream->state == ALSA_STATE_UNPAUSE) {
+ stream->state = ALSA_STATE_PAUSE;
+ }
+}
+static void inline stm_unpause_hdmi(audio_stream_t * stream)
+{
+ if (stream->state == ALSA_STATE_PAUSE) {
+ stream->state = ALSA_STATE_UNPAUSE;
+ stm_trigger_hdmi(stream);
+ }
+}
+static void inline stm_stop_hdmi(audio_stream_t * stream)
+{
+ stream->active = 0;
+ stream->period = 0;
+}
+#else /* Polling */
+
+static int spawn_hdmi_feeding_thread(audio_stream_t * stream);
+static int hdmi_feeding_thread(void *data);
+static void u8500_hdmi_pio_start(audio_stream_t * stream);
+
+#define stm_trigger_hdmi(x) spawn_hdmi_feeding_thread(x);
+
+static void inline stm_pause_hdmi(audio_stream_t * stream)
+{
+ stream->state = ALSA_STATE_PAUSE;
+}
+static void inline stm_unpause_hdmi(audio_stream_t * stream)
+{
+ stream->state = ALSA_STATE_UNPAUSE;
+ complete(&stream->alsa_com);
+}
+static void inline stm_stop_hdmi(audio_stream_t * stream)
+{
+ stream->active = 0;
+ stream->period = 0;
+ if (stream->state == ALSA_STATE_PAUSE)
+ complete(&stream->alsa_com);
+}
+
+#endif
+
+extern struct driver_debug_st DBG_ST;
+extern struct i2sdrv_data *i2sdrv[MAX_I2S_CLIENTS];
+
+static void u8500_audio_hdmi_init(u8500_acodec_chip_t * chip);
+int u8500_register_alsa_hdmi_controls(struct snd_card *card,
+ u8500_acodec_chip_t * u8500_chip);
+static int snd_u8500_alsa_hdmi_open(struct snd_pcm_substream *substream);
+static int snd_u8500_alsa_hdmi_close(struct snd_pcm_substream *substream);
+static int snd_u8500_alsa_hdmi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params);
+static int snd_u8500_alsa_hdmi_hw_free(struct snd_pcm_substream *substream);
+static int snd_u8500_alsa_hdmi_prepare(struct snd_pcm_substream *substream);
+static int snd_u8500_alsa_hdmi_trigger(struct snd_pcm_substream *substream,
+ int cmd);
+static snd_pcm_uframes_t snd_u8500_alsa_hdmi_pointer(struct snd_pcm_substream
+ *substream);
+static int configure_hdmi_rate(struct snd_pcm_substream *);
+static int configure_msp_hdmi(int sampling_freq, int channel_count);
+
+int u8500_hdmi_rates[] = { 32000, 44100, 48000, 64000, 88200,
+ 96000, 128000, 176100, 192000
+};
+
+typedef enum {
+ HDMI_SAMPLING_FREQ_32KHZ = 32,
+ HDMI_SAMPLING_FREQ_44_1KHZ = 44,
+ HDMI_SAMPLING_FREQ_48KHZ = 48,
+ HDMI_SAMPLING_FREQ_64KHZ = 64,
+ HDMI_SAMPLING_FREQ_88_2KHZ = 88,
+ HDMI_SAMPLING_FREQ_96KHZ = 96,
+ HDMI_SAMPLING_FREQ_128KHZ = 128,
+ HDMI_SAMPLING_FREQ_176_1KHZ = 176,
+ HDMI_SAMPLING_FREQ_192KHZ = 192
+} t_hdmi_sample_freq;
+
+static struct snd_pcm_ops snd_u8500_alsa_hdmi_playback_ops = {
+ .open = snd_u8500_alsa_hdmi_open,
+ .close = snd_u8500_alsa_hdmi_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_u8500_alsa_hdmi_hw_params,
+ .hw_free = snd_u8500_alsa_hdmi_hw_free,
+ .prepare = snd_u8500_alsa_hdmi_prepare,
+ .trigger = snd_u8500_alsa_hdmi_trigger,
+ .pointer = snd_u8500_alsa_hdmi_pointer,
+};
+
+static struct snd_pcm_ops snd_u8500_alsa_hdmi_capture_ops = {
+ .open = snd_u8500_alsa_hdmi_open,
+ .close = snd_u8500_alsa_hdmi_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_u8500_alsa_hdmi_hw_params,
+ .hw_free = snd_u8500_alsa_hdmi_hw_free,
+ .prepare = snd_u8500_alsa_hdmi_prepare,
+ .trigger = snd_u8500_alsa_hdmi_trigger,
+ .pointer = snd_u8500_alsa_hdmi_pointer,
+};
+
+/* Hardware description , this structure (struct snd_pcm_hardware )
+ * contains the definitions of the fundamental hardware configuration.
+ * This configuration will be applied on the runtime structure
+ */
+static struct snd_pcm_hardware snd_u8500_hdmi_playback_hw = {
+ .info =
+ (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE),
+ .formats =
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE |
+ SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_BE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = MIN_RATE_PLAYBACK,
+ .rate_max = MAX_RATE_PLAYBACK,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = NMDK_BUFFER_SIZE,
+ .period_bytes_min = 128,
+ .period_bytes_max = PAGE_SIZE,
+ .periods_min = NMDK_BUFFER_SIZE / PAGE_SIZE,
+ .periods_max = NMDK_BUFFER_SIZE / 128
+};
+
+static struct snd_pcm_hardware snd_u8500_hdmi_capture_hw = {
+ .info =
+ (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE),
+ .formats =
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE |
+ SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_BE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = MIN_RATE_CAPTURE,
+ .rate_max = MAX_RATE_CAPTURE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = NMDK_BUFFER_SIZE,
+ .period_bytes_min = 128,
+ .period_bytes_max = PAGE_SIZE,
+ .periods_min = NMDK_BUFFER_SIZE / PAGE_SIZE,
+ .periods_max = NMDK_BUFFER_SIZE / 128
+};
+
+static struct snd_pcm_hw_constraint_list constraints_hdmi_rate = {
+ .count = sizeof(u8500_hdmi_rates) / sizeof(u8500_hdmi_rates[0]),
+ .list = u8500_hdmi_rates,
+ .mask = 0,
+};
+
+/**
+ * snd_card_u8500_alsa_hdmi_new - constructor for a new pcm cmponent
+ * @chip - pointer to chip specific data
+ * @device - specifies the card number
+ */
+int snd_card_u8500_alsa_hdmi_new(u8500_acodec_chip_t * chip, int device)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ if ((err =
+ snd_pcm_new(chip->card, "u8500_hdmi", device, 1, 1, &pcm)) < 0) {
+ stm_error(" : error in snd_pcm_new\n");
+ return err;
+ }
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_u8500_alsa_hdmi_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_u8500_alsa_hdmi_capture_ops);
+
+ pcm->private_data = chip;
+ pcm->info_flags = 0;
+ chip->pcm_hdmi = pcm;
+ strcpy(pcm->name, "u8500_alsa_hdmi");
+
+ u8500_audio_hdmi_init(pcm->private_data);
+ return 0;
+}
+
+/**
+* u8500_audio_hdmi_init
+* @chip - pointer to u8500_acodec_chip_t structure.
+*
+* This function intialises the u8500 chip structure with default values
+*/
+static void u8500_audio_hdmi_init(u8500_acodec_chip_t * chip)
+{
+ audio_stream_t *ptr_audio_stream = NULL;
+
+ ptr_audio_stream =
+ &chip->stream[ALSA_HDMI_DEV][SNDRV_PCM_STREAM_PLAYBACK];
+ /* Setup DMA stuff */
+
+ strlcpy(ptr_audio_stream->id, "u8500 hdmi playback",
+ sizeof(ptr_audio_stream->id));
+
+ ptr_audio_stream->stream_id = SNDRV_PCM_STREAM_PLAYBACK;
+
+ /* default initialization for playback */
+ ptr_audio_stream->active = 0;
+ ptr_audio_stream->period = 0;
+ ptr_audio_stream->periods = 0;
+ ptr_audio_stream->old_offset = 0;
+
+ ptr_audio_stream =
+ &chip->stream[ALSA_HDMI_DEV][SNDRV_PCM_STREAM_CAPTURE];
+
+ strlcpy(ptr_audio_stream->id, "u8500 hdmi capture",
+ sizeof(ptr_audio_stream->id));
+
+ ptr_audio_stream->stream_id = SNDRV_PCM_STREAM_CAPTURE;
+
+ /* default initialization for capture */
+ ptr_audio_stream->active = 0;
+ ptr_audio_stream->period = 0;
+ ptr_audio_stream->periods = 0;
+ ptr_audio_stream->old_offset = 0;
+
+}
+
+/**
+ * snd_u8500_alsa_hdmi_open
+ * @substream - pointer to the playback/capture substream structure
+ *
+ * This routine is used by alsa framework to open a pcm stream .
+ * Here a dma pipe is requested and device is configured(default).
+ */
+static int snd_u8500_alsa_hdmi_open(struct snd_pcm_substream *substream)
+{
+ int error = 0, stream_id, status = 0;
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ audio_stream_t *ptr_audio_stream = NULL;
+
+ stream_id = substream->pstr->stream;
+ error = u8500_acodec_setuser(USER_ALSA);
+ status = u8500_acodec_open(I2S_CLIENT_MSP2, stream_id);
+ if (status) {
+ printk("failed in getting open\n");
+ return (-1);
+ }
+
+ error = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_hdmi_rate);
+ if (error < 0) {
+ stm_error
+ (": error initializing hdmi hw sample rate constraint\n");
+ return error;
+ }
+
+ if ((error = configure_hdmi_rate(substream)))
+ return error;
+
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw = snd_u8500_hdmi_playback_hw;
+ } else {
+ runtime->hw = snd_u8500_hdmi_capture_hw;
+ }
+
+ ptr_audio_stream = &chip->stream[ALSA_HDMI_DEV][stream_id];
+
+ ptr_audio_stream->substream = substream;
+
+ stm_config_hw(chip, substream, ALSA_HDMI_DEV, stream_id);
+ init_MUTEX(&(ptr_audio_stream->alsa_sem));
+ init_completion(&(ptr_audio_stream->alsa_com));
+
+ ptr_audio_stream->state = ALSA_STATE_UNPAUSE;
+ return 0;
+}
+
+/**
+ * snd_u8500_alsa_hdmi_close
+ * @substream - pointer to the playback/capture substream structure
+ *
+ * This routine is used by alsa framework to close a pcm stream .
+ * Here a dma pipe is disabled and freed.
+ */
+
+static int snd_u8500_alsa_hdmi_close(struct snd_pcm_substream *substream)
+{
+ int stream_id, error = 0;
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+ audio_stream_t *ptr_audio_stream = NULL;
+
+ stream_id = substream->pstr->stream;
+ ptr_audio_stream = &chip->stream[ALSA_HDMI_DEV][stream_id];
+
+ stm_close_alsa(chip, ALSA_HDMI_DEV, stream_id);
+
+ /* reset the different variables to default */
+
+ ptr_audio_stream->active = 0;
+ ptr_audio_stream->period = 0;
+ ptr_audio_stream->periods = 0;
+ ptr_audio_stream->old_offset = 0;
+ ptr_audio_stream->substream = NULL;
+
+ /* Disable the MSP2 */
+ error = u8500_acodec_unsetuser(USER_ALSA);
+ u8500_acodec_close(I2S_CLIENT_MSP2, ACODEC_DISABLE_ALL);
+
+ return error;
+
+}
+
+/**
+ * snd_u8500_alsa_hdmi_hw_params
+ * @substream - pointer to the playback/capture substream structure
+ * @hw_params - specifies the hw parameters like format/no of channels etc
+ *
+ * This routine is used by alsa framework to allocate a dma buffer
+ * used to transfer the data from user space to kernel space
+ *
+ */
+static int snd_u8500_alsa_hdmi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ return snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+}
+
+/**
+ * snd_u8500_alsa_hdmi_hw_free
+ * @substream - pointer to the playback/capture substream structure
+ *
+ * This routine is used by alsa framework to deallocate a dma buffer
+ * allocated berfore by snd_u8500_alsa_pcm_hw_params
+ */
+static int snd_u8500_alsa_hdmi_hw_free(struct snd_pcm_substream *substream)
+{
+ stm_hw_free(substream);
+ return 0;
+}
+
+/**
+ * snd_u8500_alsa_hdmi_pointer
+ * @substream - pointer to the playback/capture substream structure
+ *
+ * This callback is called whene the pcm middle layer inquires the current
+ * hardware position on the buffer .The position is returned in frames
+ * ranged from 0 to buffer_size -1
+ */
+static snd_pcm_uframes_t snd_u8500_alsa_hdmi_pointer(struct snd_pcm_substream
+ *substream)
+{
+ unsigned int offset;
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+ audio_stream_t *stream =
+ &chip->stream[ALSA_HDMI_DEV][substream->pstr->stream];
+ struct snd_pcm_runtime *runtime = stream->substream->runtime;
+
+ offset = bytes_to_frames(runtime, stream->old_offset);
+ if (offset < 0 || stream->old_offset < 0)
+ stm_dbg(DBG_ST.alsa, " Offset=%i %i\n", offset,
+ stream->old_offset);
+
+ return offset;
+}
+
+/**
+ * snd_u8500_alsa_hdmi_prepare
+ * @substream - pointer to the playback/capture substream structure
+ *
+ * This callback is called whene the pcm is "prepared" Here is possible
+ * to set the format type ,sample rate ,etc.The callback is called as
+ * well everytime a recovery after an underrun happens.
+ */
+
+static int snd_u8500_alsa_hdmi_prepare(struct snd_pcm_substream *substream)
+{
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int error;
+
+ if (chip->hdmi_params.sampling_freq != runtime->rate
+ || chip->hdmi_params.channel_count != runtime->channels) {
+ stm_dbg(DBG_ST.alsa, " freq not same, %d %d\n",
+ chip->hdmi_params.sampling_freq, runtime->rate);
+ stm_dbg(DBG_ST.alsa, " channels not same, %d %d\n",
+ chip->hdmi_params.channel_count, runtime->channels);
+ if (chip->hdmi_params.channel_count != runtime->channels) {
+ chip->hdmi_params.channel_count = runtime->channels;
+ if ((error =
+ stm_config_hw(chip, substream, ALSA_HDMI_DEV,
+ -1))) {
+ stm_dbg(DBG_ST.alsa,
+ "In func %s, stm_config_hw fails",
+ __FUNCTION__);
+ return error;
+ }
+ }
+ chip->hdmi_params.sampling_freq = runtime->rate;
+ if ((error = configure_hdmi_rate(substream))) {
+ stm_dbg(DBG_ST.alsa, "In func %s, configure_rate fails",
+ __FUNCTION__);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * snd_u8500_alsa_hdmi_trigger
+ * @substream - pointer to the playback/capture substream structure
+ * @cmd - specifies the command : start/stop/pause/resume
+ *
+ * This callback is called whene the pcm is started ,stopped or paused
+ * The action is specified in the second argument, SND_PCM_TRIGGER_XXX in
+ * <sound/pcm.h>.
+ * This callback is atomic and the interrupts are disabled , so you can't
+ * call other functions that need interrupts without possible risks
+ */
+static int snd_u8500_alsa_hdmi_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ int stream_id = substream->pstr->stream;
+ audio_stream_t *stream = NULL;
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+ int error = 0;
+
+ stream = &chip->stream[ALSA_HDMI_DEV][stream_id];
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* Start the pcm engine */
+ stm_dbg(DBG_ST.alsa, " TRIGGER START\n");
+ if (stream->active == 0) {
+ stream->active = 1;
+ stm_trigger_hdmi(stream);
+ break;
+ }
+ stm_error(": H/w is busy\n");
+ return -EINVAL;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ stm_dbg(DBG_ST.alsa, " SNDRV_PCM_TRIGGER_PAUSE_PUSH\n");
+ if (stream->active == 1) {
+ stm_pause_hdmi(stream);
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ stm_dbg(DBG_ST.alsa, " SNDRV_PCM_TRIGGER_PAUSE_RELEASE\n");
+ if (stream->active == 1)
+ stm_unpause_hdmi(stream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* Stop the pcm engine */
+ stm_dbg(DBG_ST.alsa, " TRIGGER STOP\n");
+ if (stream->active == 1)
+ stm_stop_hdmi(stream);
+ break;
+ default:
+ stm_error(": invalid command in pcm trigger\n");
+ return -EINVAL;
+ }
+
+ return error;
+
+}
+
+struct snd_kcontrol_new u8500_hdmi_power_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .device = 1,
+ .subdevice = 0,
+ .name = "HDMI Power",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = 0xfff,
+ .info = u8500_hdmi_power_ctrl_info,
+ .get = u8500_hdmi_power_ctrl_get,
+ .put = u8500_hdmi_power_ctrl_put
+};
+
+/**
+* u8500_hdmi_power_ctrl_info
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions fills playback device info into user structure.
+*/
+static int u8500_hdmi_power_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = NUMBER_POWER_STATE;
+ uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= NUMBER_POWER_STATE)
+ uinfo->value.enumerated.item = NUMBER_POWER_STATE - 1;
+ strcpy(uinfo->value.enumerated.name,
+ power_state_in_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+/**
+* u8500_hdmi_power_ctrl_get
+* @kcontrol - pointer to the snd_kcontrol structure
+* @uinfo - pointer to the snd_ctl_elem_info structure, this is filled by the function
+*
+* This functions returns the current playback device selected.
+*/
+static int u8500_hdmi_power_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ uinfo->value.enumerated.item[0] = 0;
+ return 0;
+}
+
+/**
+* u8500_hdmi_power_ctrl_put
+* @kcontrol - pointer to the snd_kcontrol structure
+* @ .
+*
+* This functions sets the playback device.
+*/
+static int u8500_hdmi_power_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uinfo)
+{
+ u8500_acodec_chip_t *chip =
+ (u8500_acodec_chip_t *) snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ t_ab8500_codec_error error;
+ t_u8500_bool_state power_state;
+
+ power_state = uinfo->value.enumerated.item[0];
+
+ changed = 1;
+
+ return changed;
+}
+
+int u8500_register_alsa_hdmi_controls(struct snd_card *card,
+ u8500_acodec_chip_t * u8500_chip)
+{
+ int error;
+
+ if ((error =
+ snd_ctl_add(card,
+ snd_ctl_new1(&u8500_hdmi_power_ctrl,
+ u8500_chip))) < 0) {
+ stm_error
+ (": error initializing u8500_hdmi_power_ctrl interface \n\n");
+ return (-1);
+ }
+
+ return 0;
+}
+
+/**
+* configure_hdmi_rate
+* @substream - pointer to the playback/capture substream structure
+*
+* This functions configures audio codec in to stream frequency frequency
+*/
+static int configure_hdmi_rate(struct snd_pcm_substream *substream)
+{
+ t_hdmi_sample_freq hdmi_sampling_freq;
+
+ u8500_acodec_chip_t *chip = snd_pcm_substream_chip(substream);
+
+ switch (chip->hdmi_params.sampling_freq) {
+ case 32000:
+ hdmi_sampling_freq = HDMI_SAMPLING_FREQ_32KHZ;
+ break;
+ case 44100:
+ hdmi_sampling_freq = HDMI_SAMPLING_FREQ_44_1KHZ;
+ break;
+ case 48000:
+ hdmi_sampling_freq = HDMI_SAMPLING_FREQ_48KHZ;
+ break;
+ case 64000:
+ hdmi_sampling_freq = HDMI_SAMPLING_FREQ_64KHZ;
+ break;
+ case 88200:
+ hdmi_sampling_freq = HDMI_SAMPLING_FREQ_88_2KHZ;
+ break;
+ case 96000:
+ hdmi_sampling_freq = HDMI_SAMPLING_FREQ_96KHZ;
+ break;
+ case 128000:
+ hdmi_sampling_freq = HDMI_SAMPLING_FREQ_128KHZ;
+ break;
+ case 176100:
+ hdmi_sampling_freq = HDMI_SAMPLING_FREQ_176_1KHZ;
+ break;
+ case 192000:
+ hdmi_sampling_freq = HDMI_SAMPLING_FREQ_192KHZ;
+ default:
+ stm_error("not supported frequnecy\n");
+ return -EINVAL;
+ }
+
+ configure_msp_hdmi(hdmi_sampling_freq, chip->hdmi_params.channel_count);
+
+ return 0;
+
+}
+
+static int configure_msp_hdmi(int sampling_freq, int channel_count)
+{
+ struct i2s_device *i2s_dev = i2sdrv[I2S_CLIENT_MSP2]->i2s;
+ struct msp_config msp_config;
+ t_ab8500_codec_error error_status = AB8500_CODEC_OK;
+
+ memset(&msp_config, 0, sizeof(msp_config));
+
+
+ if (i2sdrv[I2S_CLIENT_MSP2]->flag) {
+ stm_dbg(DBG_ST.acodec, " I2S controller not available\n");
+ return -1;
+ }
+
+ /* MSP configuration */
+
+ msp_config.tx_clock_sel = 0;
+ msp_config.rx_clock_sel = 0;
+
+ msp_config.tx_frame_sync_sel = 0;
+ msp_config.rx_frame_sync_sel = 0;
+
+ msp_config.input_clock_freq = MSP_INPUT_FREQ_48MHZ;
+ msp_config.srg_clock_sel = 0;
+
+ msp_config.rx_frame_sync_pol = RX_FIFO_SYNC_HI;
+ msp_config.tx_frame_sync_pol = TX_FIFO_SYNC_HI;
+
+ msp_config.rx_fifo_config = 0;
+ msp_config.tx_fifo_config = TX_FIFO_ENABLE;
+
+ msp_config.spi_clk_mode = SPI_CLK_MODE_NORMAL;
+ msp_config.spi_burst_mode = 0;
+ msp_config.tx_data_enable = 0;
+ msp_config.loopback_enable = 0;
+ msp_config.default_protocol_desc = 1;
+ msp_config.direction = MSP_TRANSMIT_MODE;
+ msp_config.protocol = MSP_I2S_PROTOCOL;
+ msp_config.frame_size = ELEMENT_SIZE;
+ msp_config.frame_freq = sampling_freq;
+ msp_config.def_elem_len = 0;
+ /* enable msp for both tr and rx mode with dma data transfer.
+ THIS IS NOW DONE SEPARATELY from SAA. */
+ msp_config.data_size = MSP_DATA_SIZE_16BIT;
+
+#ifdef CONFIG_U8500_ACODEC_DMA
+ msp_config.work_mode = MSP_DMA_MODE;
+#elif defined(CONFIG_U8500_ACODEC_POLL)
+ msp_config.work_mode = MSP_POLLING_MODE;
+#else
+ msp_config.work_mode = MSP_INTERRUPT_MODE;
+#endif
+ msp_config.default_protocol_desc = 0;
+
+ msp_config.protocol_desc.rx_phase_mode = MSP_DUAL_PHASE;
+ msp_config.protocol_desc.tx_phase_mode = MSP_DUAL_PHASE;
+ msp_config.protocol_desc.rx_phase2_start_mode =
+ MSP_PHASE2_START_MODE_FRAME_SYNC;
+ msp_config.protocol_desc.tx_phase2_start_mode =
+ MSP_PHASE2_START_MODE_FRAME_SYNC;
+ msp_config.protocol_desc.rx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST;
+ msp_config.protocol_desc.tx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST;
+ msp_config.protocol_desc.rx_frame_length_1 = MSP_FRAME_LENGTH_1;
+ msp_config.protocol_desc.rx_frame_length_2 = MSP_FRAME_LENGTH_1;
+ msp_config.protocol_desc.tx_frame_length_1 = MSP_FRAME_LENGTH_1;
+ msp_config.protocol_desc.tx_frame_length_2 = MSP_FRAME_LENGTH_1;
+ msp_config.protocol_desc.rx_element_length_1 = MSP_ELEM_LENGTH_16;
+ msp_config.protocol_desc.rx_element_length_2 = MSP_ELEM_LENGTH_16;
+ msp_config.protocol_desc.tx_element_length_1 = MSP_ELEM_LENGTH_16;
+ msp_config.protocol_desc.tx_element_length_2 = MSP_ELEM_LENGTH_16;
+ msp_config.protocol_desc.rx_data_delay = MSP_DELAY_1;
+ msp_config.protocol_desc.tx_data_delay = MSP_DELAY_1;
+ msp_config.protocol_desc.rx_clock_pol = MSP_RISING_EDGE;
+ msp_config.protocol_desc.tx_clock_pol = 0;
+ msp_config.protocol_desc.rx_frame_sync_pol =
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH;
+ msp_config.protocol_desc.tx_frame_sync_pol =
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH;
+ msp_config.protocol_desc.rx_half_word_swap = MSP_HWS_NO_SWAP;
+ msp_config.protocol_desc.tx_half_word_swap = MSP_HWS_NO_SWAP;
+ msp_config.protocol_desc.compression_mode = MSP_COMPRESS_MODE_LINEAR;
+ msp_config.protocol_desc.expansion_mode = MSP_EXPAND_MODE_LINEAR;
+ msp_config.protocol_desc.spi_clk_mode = MSP_SPI_CLOCK_MODE_NON_SPI;
+ msp_config.protocol_desc.spi_burst_mode = MSP_SPI_BURST_MODE_DISABLE;
+ msp_config.protocol_desc.frame_period = 63;
+ msp_config.protocol_desc.frame_width = 31;
+ msp_config.protocol_desc.total_clocks_for_one_frame = 64;
+ msp_config.multichannel_configured = 0;
+ msp_config.multichannel_config.tx_multichannel_enable = 0;
+ /* Channel 1 and channel 3 */
+ msp_config.multichannel_config.tx_channel_0_enable = 0x0000005;
+ msp_config.multichannel_config.tx_channel_1_enable = 0x0000000;
+ msp_config.multichannel_config.tx_channel_2_enable = 0x0000000;
+ msp_config.multichannel_config.tx_channel_3_enable = 0x0000000;
+ error_status = i2s_setup(i2s_dev->controller, &msp_config);
+
+#ifdef CONFIG_DEBUG
+ {
+ dump_msp2_registers();
+ }
+#endif
+
+ if (error_status < 0) {
+ printk("error in msp enable, error_status is %d\n",
+ error_status);
+ return error_status;
+ }
+
+ return 0;
+
+}
+
+#ifdef CONFIG_U8500_ACODEC_DMA
+/**
+ * u8500_alsa_hdmi_dma_start - used to transmit or recive a dma chunk
+ * @stream - specifies the playback/record stream structure
+ */
+static void u8500_alsa_hdmi_dma_start(audio_stream_t * stream)
+{
+ unsigned int offset, dma_size, stream_id;
+
+ struct snd_pcm_substream *substream = stream->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ stream_id = substream->pstr->stream;
+
+ dma_size = frames_to_bytes(runtime, runtime->period_size);
+ offset = dma_size * stream->period;
+ stream->old_offset = offset;
+
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+#ifdef CONFIG_U8500_ACODEC_DMA
+ u8500_acodec_send_data(I2S_CLIENT_MSP2,
+ (void *)(runtime->dma_addr + offset),
+ dma_size, 1);
+#else
+ u8500_acodec_send_data(I2S_CLIENT_MSP2,
+ (void *)(runtime->dma_area + offset),
+ dma_size, 0);
+#endif
+ else
+#ifdef CONFIG_U8500_ACODEC_DMA
+ u8500_acodec_receive_data(I2S_CLIENT_MSP2,
+ (void *)(runtime->dma_addr + offset),
+ dma_size, 1);
+#else
+ u8500_acodec_receive_data(I2S_CLIENT_MSP2,
+ (void *)(runtime->dma_area + offset),
+ dma_size, 0);
+#endif
+
+ stm_dbg(DBG_ST.alsa, " DMA Transfer started\n");
+ stm_dbg(DBG_ST.alsa, " address = %x size=%d\n",
+ (runtime->dma_addr + offset), dma_size);
+
+ stream->period++;
+ stream->period %= runtime->periods;
+ stream->periods++;
+
+
+}
+
+#else
+
+/**
+* acodec_feeding_thread
+* @stream - pointer to the playback/capture audio_stream_t structure
+*
+* This function creates a kernel thread .
+*/
+
+static int spawn_hdmi_feeding_thread(audio_stream_t * stream)
+{
+ pid_t pid;
+
+ pid =
+ kernel_thread(hdmi_feeding_thread, stream,
+ CLONE_FS | CLONE_SIGHAND);
+
+ return 0;
+}
+
+/**
+* hdmi_feeding_thread
+* @data - void pointer to the playback/capture audio_stream_t structure
+*
+* This thread sends/receive data to MSP while stream is active
+*/
+static int hdmi_feeding_thread(void *data)
+{
+ audio_stream_t *stream = (audio_stream_t *) data;
+
+ daemonize("hdmi_feeding_thread");
+ allow_signal(SIGKILL);
+ down(&stream->alsa_sem);
+
+ while ((!signal_pending(current)) && (stream->active)) {
+ if (stream->state == ALSA_STATE_PAUSE)
+ wait_for_completion(&(stream->alsa_com));
+
+ u8500_hdmi_pio_start(stream);
+ if (stream->substream)
+ snd_pcm_period_elapsed(stream->substream);
+ }
+
+ up(&stream->alsa_sem);
+
+ return 0;
+}
+
+/**
+* u8500_hdmi_pio_start
+* @stream - pointer to the playback/capture audio_stream_t structure
+*
+* This function sends/receive one chunck of stream data to/from MSP
+*/
+static void u8500_hdmi_pio_start(audio_stream_t * stream)
+{
+ unsigned int offset, dma_size, stream_id;
+ struct snd_pcm_substream *substream = stream->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ stream_id = substream->pstr->stream;
+
+ dma_size = frames_to_bytes(runtime, runtime->period_size);
+ offset = dma_size * stream->period;
+ stream->old_offset = offset;
+
+ stm_dbg(DBG_ST.alsa, " Transfer started\n");
+ stm_dbg(DBG_ST.alsa, " address = %x size=%d\n",
+ (runtime->dma_addr + offset), dma_size);
+
+ /* Send our stuff */
+ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+#ifdef CONFIG_U8500_ACODEC_DMA
+ u8500_acodec_send_data(I2S_CLIENT_MSP2,
+ (void *)(runtime->dma_addr + offset),
+ dma_size, 1);
+#else
+ u8500_acodec_send_data(I2S_CLIENT_MSP2,
+ (void *)(runtime->dma_area + offset),
+ dma_size, 0);
+#endif
+ else
+#ifdef CONFIG_U8500_ACODEC_DMA
+ u8500_acodec_receive_data(I2S_CLIENT_MSP2,
+ (void *)(runtime->dma_addr + offset),
+ dma_size, 1);
+#else
+ u8500_acodec_receive_data(I2S_CLIENT_MSP2,
+ (void *)(runtime->dma_area + offset),
+ dma_size, 0);
+#endif
+
+ stream->period++;
+ stream->period %= runtime->periods;
+ stream->periods++;
+}
+#endif
+
+void dump_msp2_registers()
+{
+ int i;
+
+ stm_dbg(DBG_ST.acodec, "\nMSP_2 base add = 0x%x\n",
+ (unsigned int)U8500_MSP2_BASE);
+
+ for (i = 0; i < 0x40; i += 4)
+ stm_dbg(DBG_ST.acodec, "msp[0x%x]=0x%x\n", i,
+ readl((char *)(IO_ADDRESS(U8500_MSP2_BASE) + i)));
+
+ return 0;
+}
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index b1749bc6797..23591d0bac3 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -36,6 +36,7 @@ source "sound/soc/s3c24xx/Kconfig"
source "sound/soc/s6000/Kconfig"
source "sound/soc/sh/Kconfig"
source "sound/soc/txx9/Kconfig"
+source "sound/soc/ux500/Kconfig"
# Supported codecs
source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 1470141d416..f3384c084ec 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_SND_SOC) += s3c24xx/
obj-$(CONFIG_SND_SOC) += s6000/
obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += txx9/
+obj-$(CONFIG_SND_SOC) += ux500/
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 5da30eb6ad0..96b641131fb 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -70,6 +70,9 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM9705 if SND_SOC_AC97_BUS
select SND_SOC_WM9712 if SND_SOC_AC97_BUS
select SND_SOC_WM9713 if SND_SOC_AC97_BUS
+ select SND_SOC_AB3550
+ select SND_SOC_CG29XX
+ select SND_SOC_AV8100
help
Normally ASoC codec drivers are only built if a machine driver which
uses them is also built since they are only usable with a machine
@@ -269,6 +272,15 @@ config SND_SOC_WM9712
config SND_SOC_WM9713
tristate
+config SND_SOC_AB3550
+ tristate
+
+config SND_SOC_CG29XX
+ tristate
+
+config SND_SOC_AV8100
+ tristate
+
# Amp
config SND_SOC_MAX9877
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 91429eab070..b6361f7803a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,3 +1,4 @@
+snd-soc-ab3550-objs := ab3550.o
snd-soc-ac97-objs := ac97.o
snd-soc-ad1836-objs := ad1836.o
snd-soc-ad193x-objs := ad193x.o
@@ -8,6 +9,8 @@ snd-soc-ak4104-objs := ak4104.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-ak4642-objs := ak4642.o
snd-soc-ak4671-objs := ak4671.o
+snd-soc-av8100_audio-objs := av8100_audio.o
+snd-soc-cg29xx-objs := cg29xx.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cx20442-objs := cx20442.o
@@ -63,6 +66,7 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o
snd-soc-wm2000-objs := wm2000.o
snd-soc-wm9090-objs := wm9090.o
+obj-$(CONFIG_SND_SOC_AB3550) += snd-soc-ab3550.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
@@ -73,6 +77,8 @@ obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
+obj-$(CONFIG_SND_SOC_AV8100) += snd-soc-av8100_audio.o
+obj-$(CONFIG_SND_SOC_CG29XX) += snd-soc-cg29xx.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
diff --git a/sound/soc/codecs/ab3550.c b/sound/soc/codecs/ab3550.c
new file mode 100644
index 00000000000..e0a4c6d7f06
--- /dev/null
+++ b/sound/soc/codecs/ab3550.c
@@ -0,0 +1,1456 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Xie Xiaolei <xie.xiaolei@etericsson.com>,
+ * Roger Nilsson <roger.xr.nilsson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/mfd/abx500.h>
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <asm/atomic.h>
+#include <linux/rwsem.h>
+#include <linux/mutex.h>
+#include <stdarg.h>
+#include "ab3550.h"
+
+
+#define I2C_BANK 0
+
+static struct device *ab3550_dev;
+static struct snd_soc_codec *ab3550_codec;
+
+static u8 virtual_regs[] = {
+ 0, 0
+};
+
+static void set_reg(u8 reg, u8 val)
+{
+ if (!ab3550_dev) {
+ pr_err("%s: The AB3550 codec driver not initialized.\n",
+ __func__);
+ return;
+ }
+ if (reg < AB3550_FIRST_REG)
+ return;
+ else if (reg <= AB3550_LAST_REG) {
+ abx500_set_register_interruptible(
+ ab3550_dev, I2C_BANK, reg, val);
+ } else if (reg - AB3550_LAST_REG - 1 < ARRAY_SIZE(virtual_regs)) {
+ virtual_regs[reg - AB3550_LAST_REG - 1] = val;
+ }
+}
+
+static void mask_set_reg(u8 reg, u8 mask, u8 val)
+{
+ if (!ab3550_dev) {
+ pr_err("%s: The AB3550 codec driver not initialized.\n",
+ __func__);
+ return;
+ }
+ if (reg < AB3550_FIRST_REG)
+ return;
+ else if (reg <= AB3550_LAST_REG) {
+ abx500_mask_and_set_register_interruptible(
+ ab3550_dev, I2C_BANK, reg, mask, val);
+ } else if (reg - AB3550_LAST_REG - 1 < ARRAY_SIZE(virtual_regs)) {
+ virtual_regs[reg - AB3550_LAST_REG - 1] &= ~mask;
+ virtual_regs[reg - AB3550_LAST_REG - 1] |= val & mask;
+ }
+}
+
+static u8 read_reg(u8 reg)
+{
+ if (!ab3550_dev) {
+ pr_err("%s: The AB3550 codec driver not initialized.\n",
+ __func__);
+ return 0;
+ }
+ if (reg < AB3550_FIRST_REG)
+ return 0;
+ else if (reg <= AB3550_LAST_REG) {
+ u8 val;
+ abx500_get_register_interruptible(
+ ab3550_dev, I2C_BANK, reg, &val);
+ return val;
+ } else if (reg - AB3550_LAST_REG - 1 < ARRAY_SIZE(virtual_regs))
+ return virtual_regs[reg - AB3550_LAST_REG - 1];
+ dev_warn(ab3550_dev, "%s: out-of-scope reigster %u.\n",
+ __func__, reg);
+ return 0;
+}
+
+/* Components that can be powered up/down */
+enum enum_widget {
+ widget_ear = 0,
+ widget_auxo1,
+ widget_auxo2,
+
+ widget_spkr,
+ widget_line1,
+ widget_line2,
+
+ widget_dac1,
+ widget_dac2,
+ widget_dac3,
+
+ widget_rx1,
+ widget_rx2,
+ widget_rx3,
+
+ widget_mic1,
+ widget_mic2,
+
+ widget_micbias1,
+ widget_micbias2,
+
+ widget_apga1,
+ widget_apga2,
+
+ widget_tx1,
+ widget_tx2,
+
+ widget_adc1,
+ widget_adc2,
+
+ widget_if0_dld_l,
+ widget_if0_dld_r,
+ widget_if0_uld_l,
+ widget_if0_uld_r,
+ widget_if1_dld_l,
+ widget_if1_dld_r,
+ widget_if1_uld_l,
+ widget_if1_uld_r,
+
+ widget_mic1p1,
+ widget_mic1n1,
+ widget_mic1p2,
+ widget_mic1n2,
+
+ widget_mic2p1,
+ widget_mic2n1,
+ widget_mic2p2,
+ widget_mic2n2,
+
+ widget_clock,
+
+ number_of_widgets
+};
+
+/* This is only meant for debugging */
+static const char *widget_names[] = {
+ "EAR", "AUXO1", "AUXO2", "SPKR", "LINE1", "LINE2",
+ "DAC1", "DAC2", "DAC3",
+ "RX1", "RX2", "RX3",
+ "MIC1", "MIC2",
+ "MIC-BIAS1", "MIC-BIAS2",
+ "APGA1", "APGA2",
+ "TX1", "TX2",
+ "ADC1", "ADC2",
+ "IF0-DLD-L", "IF0-DLD-R", "IF0-ULD-L", "IF0-ULD-R",
+ "IF1-DLD-L", "IF1-DLD-R", "IF1-ULD-L", "IF1-ULD-R",
+ "MIC1P1", "MIC1N1", "MIC1P2", "MIC1N2",
+ "MIC2P1", "MIC2N1", "MIC2P2", "MIC2N2",
+ "CLOCK"
+};
+
+struct widget_pm {
+ enum enum_widget widget;
+ u8 reg;
+ u8 shift;
+
+ unsigned long source_list[BIT_WORD(number_of_widgets) + 1];
+ unsigned long sink_list[BIT_WORD(number_of_widgets) + 1];
+};
+
+static struct widget_pm widget_pm_array[] = {
+ {.widget = widget_ear, .reg = EAR, .shift = EAR_PWR_SHIFT},
+ {.widget = widget_auxo1, .reg = AUXO1, .shift = AUXOx_PWR_SHIFT},
+ {.widget = widget_auxo2, .reg = AUXO2, .shift = AUXOx_PWR_SHIFT},
+ {.widget = widget_spkr, .reg = SPKR, .shift = SPKR_PWR_SHIFT},
+ {.widget = widget_line1, .reg = LINE1, .shift = LINEx_PWR_SHIFT},
+ {.widget = widget_line2, .reg = LINE2, .shift = LINEx_PWR_SHIFT},
+
+ {.widget = widget_dac1, .reg = RX1, .shift = DACx_PWR_SHIFT},
+ {.widget = widget_dac2, .reg = RX2, .shift = DACx_PWR_SHIFT},
+ {.widget = widget_dac3, .reg = RX3, .shift = DACx_PWR_SHIFT},
+
+ {.widget = widget_rx1, .reg = RX1, .shift = RXx_PWR_SHIFT},
+ {.widget = widget_rx2, .reg = RX2, .shift = RXx_PWR_SHIFT},
+ {.widget = widget_rx3, .reg = RX3, .shift = RXx_PWR_SHIFT},
+
+ {.widget = widget_mic1, .reg = MIC1_GAIN, .shift = MICx_PWR_SHIFT},
+ {.widget = widget_mic2, .reg = MIC2_GAIN, .shift = MICx_PWR_SHIFT},
+
+ {.widget = widget_micbias1, .reg = MIC_BIAS1,
+ .shift = MBIAS_PWR_SHIFT},
+ {.widget = widget_micbias2, .reg = MIC_BIAS2,
+ .shift = MBIAS_PWR_SHIFT},
+
+ {.widget = widget_apga1, .reg = ANALOG_LOOP_PGA1,
+ .shift = APGAx_PWR_SHIFT},
+ {.widget = widget_apga2, .reg = ANALOG_LOOP_PGA2,
+ .shift = APGAx_PWR_SHIFT},
+
+ {.widget = widget_tx1, .reg = TX1, .shift = TXx_PWR_SHIFT},
+ {.widget = widget_tx2, .reg = TX2, .shift = TXx_PWR_SHIFT},
+
+ {.widget = widget_adc1, .reg = TX1, .shift = ADCx_PWR_SHIFT},
+ {.widget = widget_adc2, .reg = TX2, .shift = ADCx_PWR_SHIFT},
+
+ {.widget = widget_if0_dld_l, .reg = AB3550_VIRTUAL_REG1,
+ .shift = IF0_DLD_L_PW_SHIFT},
+ {.widget = widget_if0_dld_r, .reg = AB3550_VIRTUAL_REG1,
+ .shift = IF0_DLD_R_PW_SHIFT},
+ {.widget = widget_if0_uld_l, .reg = AB3550_VIRTUAL_REG1,
+ .shift = IF0_ULD_L_PW_SHIFT},
+ {.widget = widget_if0_uld_r, .reg = AB3550_VIRTUAL_REG1,
+ .shift = IF0_ULD_R_PW_SHIFT},
+
+ {.widget = widget_if1_dld_l, .reg = AB3550_VIRTUAL_REG1,
+ .shift = IF1_DLD_L_PW_SHIFT},
+ {.widget = widget_if1_dld_r, .reg = AB3550_VIRTUAL_REG1,
+ .shift = IF1_DLD_R_PW_SHIFT},
+ {.widget = widget_if1_uld_l, .reg = AB3550_VIRTUAL_REG1,
+ .shift = IF1_ULD_L_PW_SHIFT},
+ {.widget = widget_if1_uld_r, .reg = AB3550_VIRTUAL_REG1,
+ .shift = IF1_ULD_R_PW_SHIFT},
+
+ {.widget = widget_mic1p1, .reg = AB3550_VIRTUAL_REG2,
+ .shift = MIC1P1_PW_SHIFT},
+ {.widget = widget_mic1n1, .reg = AB3550_VIRTUAL_REG2,
+ .shift = MIC1N1_PW_SHIFT},
+ {.widget = widget_mic1p2, .reg = AB3550_VIRTUAL_REG2,
+ .shift = MIC1P2_PW_SHIFT},
+ {.widget = widget_mic1n2, .reg = AB3550_VIRTUAL_REG2,
+ .shift = MIC1N2_PW_SHIFT},
+
+ {.widget = widget_mic2p1, .reg = AB3550_VIRTUAL_REG2,
+ .shift = MIC2P1_PW_SHIFT},
+ {.widget = widget_mic2n1, .reg = AB3550_VIRTUAL_REG2,
+ .shift = MIC2N1_PW_SHIFT},
+ {.widget = widget_mic2p2, .reg = AB3550_VIRTUAL_REG2,
+ .shift = MIC2P2_PW_SHIFT},
+ {.widget = widget_mic2n2, .reg = AB3550_VIRTUAL_REG2,
+ .shift = MIC2N2_PW_SHIFT},
+
+ {.widget = widget_clock, .reg = CLOCK, .shift = CLOCK_ENABLE_SHIFT},
+};
+
+DEFINE_MUTEX(ab3550_pm_mutex);
+
+static struct {
+ enum enum_widget stack[number_of_widgets];
+ int p;
+} pm_stack;
+
+struct ab3550_dai_private {
+ unsigned int fmt;
+};
+
+#define pm_stack_as_bitmap ({ \
+ unsigned long bitmap[BIT_WORD(number_of_widgets) + 1]; \
+ int i; \
+ memset(bitmap, 0, sizeof(bitmap)); \
+ for (i = 0; i < pm_stack.p; i++) { \
+ set_bit(pm_stack.stack[i], bitmap); \
+ } \
+ bitmap; \
+ })
+
+/* These are only meant to meet the obligations of DAPM */
+static const struct snd_soc_dapm_widget ab3550_dapm_widgets[] = {
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+};
+
+
+static const char *enum_rx2_select[] = {"I2S0", "I2S1"};
+static const char *enum_i2s_input_select[] = {
+ "tri-state", "MIC1", "MIC2", "mute"
+};
+static const char *enum_apga1_source[] = {"LINEIN1", "MIC1", "MIC2"};
+static const char *enum_apga2_source[] = {"LINEIN2", "MIC1", "MIC2"};
+static const char *enum_dac_side_tone[] = {"TX1", "TX2"};
+static const char *enum_dac_power_mode[] = {"100%", "75%", "55%"};
+static const char *enum_ear_power_mode[] = {"100%", "70%"};
+static const char *enum_auxo_power_mode[] = {
+ "100%", "67%", "50%", "25%", "auto"
+};
+static const char *enum_onoff[] = {"Off", "On"};
+static const char *enum_mbias_hiz_option[] = {"GND", "HiZ"};
+static const char *enum_mbias2_output_voltage[] = {"2.0v", "2.2v"};
+static const char *enum_mic_input_impedance[] = {
+ "12.5 kohm", "25 kohm", "50 kohm"
+};
+static const char *enum_hp_filter[] = {"HP3", "HP1", "bypass"};
+static const char *enum_i2s_word_length[] = {"16 bits", "24 bits"};
+static const char *enum_i2s_mode[] = {"Master Mode", "Slave Mode"};
+static const char *enum_i2s_tristate[] = {"Normal", "Tri-state"};
+static const char *enum_optional_resistor[] = {"disconnected", "connected"};
+static const char *enum_i2s_sample_rate[] = {
+ "8 kHz", "16 kHz", "44.1 kHz", "48 kHz"
+};
+static const char *enum_signal_inversion[] = {"normal", "inverted"};
+
+/* RX2 Select */
+static struct soc_enum soc_enum_rx2_select =
+ SOC_ENUM_SINGLE(RX2, 4, ARRAY_SIZE(enum_rx2_select), enum_rx2_select);
+
+/* I2S0 Input Select */
+static struct soc_enum soc_enum_i2s0_input_select =
+ SOC_ENUM_DOUBLE(INTERFACE0_DATA, 0, 2,
+ ARRAY_SIZE(enum_i2s_input_select),
+ enum_i2s_input_select);
+/* I2S1 Input Select */
+static struct soc_enum soc_enum_i2s1_input_select =
+ SOC_ENUM_DOUBLE(INTERFACE1_DATA, 0, 2,
+ ARRAY_SIZE(enum_i2s_input_select),
+ enum_i2s_input_select);
+
+/* APGA1 Source */
+static struct soc_enum soc_enum_apga1_source =
+ SOC_ENUM_SINGLE(ANALOG_LOOP_PGA1, APGAx_MUX_SHIFT,
+ ARRAY_SIZE(enum_apga1_source), enum_apga1_source);
+
+/* APGA2 Source */
+static struct soc_enum soc_enum_apga2_source =
+ SOC_ENUM_SINGLE(ANALOG_LOOP_PGA2, APGAx_MUX_SHIFT,
+ ARRAY_SIZE(enum_apga2_source), enum_apga2_source);
+
+static struct soc_enum soc_enum_apga1_enable =
+ SOC_ENUM_SINGLE(ANALOG_LOOP_PGA1, APGAx_PWR_SHIFT,
+ ARRAY_SIZE(enum_onoff), enum_onoff);
+
+static struct soc_enum soc_enum_apga2_enable =
+ SOC_ENUM_SINGLE(ANALOG_LOOP_PGA2, APGAx_PWR_SHIFT,
+ ARRAY_SIZE(enum_onoff), enum_onoff);
+
+/* DAC1 Side Tone */
+static struct soc_enum soc_enum_dac1_side_tone =
+ SOC_ENUM_SINGLE(SIDETONE1_PGA, STx_MUX_SHIFT,
+ ARRAY_SIZE(enum_dac_side_tone), enum_dac_side_tone);
+
+/* DAC2 Side Tone */
+static struct soc_enum soc_enum_dac2_side_tone =
+ SOC_ENUM_SINGLE(SIDETONE2_PGA, STx_MUX_SHIFT,
+ ARRAY_SIZE(enum_dac_side_tone), enum_dac_side_tone);
+
+/* DAC1 Power Mode */
+static struct soc_enum soc_enum_dac1_power_mode =
+ SOC_ENUM_SINGLE(RX1, DACx_PWR_MODE_SHIFT,
+ ARRAY_SIZE(enum_dac_power_mode), enum_dac_power_mode);
+
+/* DAC2 Power Mode */
+static struct soc_enum soc_enum_dac2_power_mode =
+ SOC_ENUM_SINGLE(RX2, DACx_PWR_MODE_SHIFT,
+ ARRAY_SIZE(enum_dac_power_mode), enum_dac_power_mode);
+
+/* DAC3 Power Mode */
+static struct soc_enum soc_enum_dac3_power_mode =
+ SOC_ENUM_SINGLE(RX3, DACx_PWR_MODE_SHIFT,
+ ARRAY_SIZE(enum_dac_power_mode), enum_dac_power_mode);
+
+/* EAR Power Mode */
+static struct soc_enum soc_enum_ear_power_mode =
+ SOC_ENUM_SINGLE(EAR, EAR_PWR_MODE_SHIFT,
+ ARRAY_SIZE(enum_ear_power_mode), enum_ear_power_mode);
+
+/* AUXO Power Mode */
+static struct soc_enum soc_enum_auxo_power_mode =
+ SOC_ENUM_SINGLE(AUXO_PWR_MODE, AUXO_PWR_MODE_SHIFT,
+ ARRAY_SIZE(enum_auxo_power_mode),
+ enum_auxo_power_mode);
+
+/* MBIAS1 HiZ Option */
+static struct soc_enum soc_enum_mbias1_hiz_option =
+ SOC_ENUM_SINGLE(MIC_BIAS1, MBIAS_PDN_IMP_SHIFT,
+ ARRAY_SIZE(enum_mbias_hiz_option),
+ enum_mbias_hiz_option);
+
+/* MBIAS1 HiZ Option */
+static struct soc_enum soc_enum_mbias2_hiz_option =
+ SOC_ENUM_SINGLE(MIC_BIAS2, MBIAS_PDN_IMP_SHIFT,
+ ARRAY_SIZE(enum_mbias_hiz_option),
+ enum_mbias_hiz_option);
+
+/* MBIAS2 Output voltage */
+static struct soc_enum soc_enum_mbias2_output_voltage =
+ SOC_ENUM_SINGLE(MIC_BIAS2, MBIAS2_OUT_V_SHIFT,
+ ARRAY_SIZE(enum_mbias2_output_voltage),
+ enum_mbias2_output_voltage);
+
+static struct soc_enum soc_enum_mbias2_internal_resistor =
+ SOC_ENUM_SINGLE(MIC_BIAS2_VAD, MBIAS2_R_INT_SHIFT,
+ ARRAY_SIZE(enum_optional_resistor),
+ enum_optional_resistor);
+
+static struct soc_enum soc_enum_mic1_input_impedance =
+ SOC_ENUM_SINGLE(MIC1_GAIN, MICx_IN_IMP_SHIFT,
+ ARRAY_SIZE(enum_mic_input_impedance),
+ enum_mic_input_impedance);
+
+static struct soc_enum soc_enum_mic2_input_impedance =
+ SOC_ENUM_SINGLE(MIC2_GAIN, MICx_IN_IMP_SHIFT,
+ ARRAY_SIZE(enum_mic_input_impedance),
+ enum_mic_input_impedance);
+
+static struct soc_enum soc_enum_tx1_hp_filter =
+ SOC_ENUM_SINGLE(TX1, TXx_HP_FILTER_SHIFT,
+ ARRAY_SIZE(enum_hp_filter),
+ enum_hp_filter);
+
+static struct soc_enum soc_enum_tx2_hp_filter =
+ SOC_ENUM_SINGLE(TX2, TXx_HP_FILTER_SHIFT,
+ ARRAY_SIZE(enum_hp_filter),
+ enum_hp_filter);
+
+static struct soc_enum soc_enum_st1_hp_filter =
+ SOC_ENUM_SINGLE(SIDETONE1_PGA, STx_HP_FILTER_SHIFT,
+ ARRAY_SIZE(enum_hp_filter),
+ enum_hp_filter);
+
+static struct soc_enum soc_enum_st2_hp_filter =
+ SOC_ENUM_SINGLE(SIDETONE2_PGA, STx_HP_FILTER_SHIFT,
+ ARRAY_SIZE(enum_hp_filter),
+ enum_hp_filter);
+
+static struct soc_enum soc_enum_i2s0_word_length =
+ SOC_ENUM_SINGLE(INTERFACE0, I2Sx_WORDLENGTH_SHIFT,
+ ARRAY_SIZE(enum_i2s_word_length),
+ enum_i2s_word_length);
+
+static struct soc_enum soc_enum_i2s1_word_length =
+ SOC_ENUM_SINGLE(INTERFACE1, I2Sx_WORDLENGTH_SHIFT,
+ ARRAY_SIZE(enum_i2s_word_length),
+ enum_i2s_word_length);
+
+static struct soc_enum soc_enum_i2s0_mode =
+ SOC_ENUM_SINGLE(INTERFACE0, I2Sx_MODE_SHIFT,
+ ARRAY_SIZE(enum_i2s_mode),
+ enum_i2s_mode);
+
+static struct soc_enum soc_enum_i2s1_mode =
+ SOC_ENUM_SINGLE(INTERFACE1, I2Sx_MODE_SHIFT,
+ ARRAY_SIZE(enum_i2s_mode),
+ enum_i2s_mode);
+
+static struct soc_enum soc_enum_i2s0_tristate =
+ SOC_ENUM_SINGLE(INTERFACE0, I2Sx_TRISTATE_SHIFT,
+ ARRAY_SIZE(enum_i2s_tristate),
+ enum_i2s_tristate);
+
+static struct soc_enum soc_enum_i2s1_tristate =
+ SOC_ENUM_SINGLE(INTERFACE1, I2Sx_TRISTATE_SHIFT,
+ ARRAY_SIZE(enum_i2s_tristate),
+ enum_i2s_tristate);
+
+static struct soc_enum soc_enum_i2s0_pulldown_resistor =
+ SOC_ENUM_SINGLE(INTERFACE0, I2Sx_PULLDOWN_SHIFT,
+ ARRAY_SIZE(enum_optional_resistor),
+ enum_optional_resistor);
+
+static struct soc_enum soc_enum_i2s1_pulldown_resistor =
+ SOC_ENUM_SINGLE(INTERFACE1, I2Sx_PULLDOWN_SHIFT,
+ ARRAY_SIZE(enum_optional_resistor),
+ enum_optional_resistor);
+
+static struct soc_enum soc_enum_i2s0_sample_rate =
+ SOC_ENUM_SINGLE(INTERFACE0, I2Sx_SR_SHIFT,
+ ARRAY_SIZE(enum_i2s_sample_rate),
+ enum_i2s_sample_rate);
+
+static struct soc_enum soc_enum_i2s1_sample_rate =
+ SOC_ENUM_SINGLE(INTERFACE1, I2Sx_SR_SHIFT,
+ ARRAY_SIZE(enum_i2s_sample_rate),
+ enum_i2s_sample_rate);
+
+static struct soc_enum soc_enum_line1_inversion =
+ SOC_ENUM_SINGLE(LINE1, LINEx_INV_SHIFT,
+ ARRAY_SIZE(enum_signal_inversion),
+ enum_signal_inversion);
+
+static struct soc_enum soc_enum_line2_inversion =
+ SOC_ENUM_SINGLE(LINE2, LINEx_INV_SHIFT,
+ ARRAY_SIZE(enum_signal_inversion),
+ enum_signal_inversion);
+
+static struct soc_enum soc_enum_auxo1_inversion =
+ SOC_ENUM_SINGLE(AUXO1, AUXOx_INV_SHIFT,
+ ARRAY_SIZE(enum_signal_inversion),
+ enum_signal_inversion);
+
+static struct soc_enum soc_enum_auxo2_inversion =
+ SOC_ENUM_SINGLE(AUXO1, AUXOx_INV_SHIFT,
+ ARRAY_SIZE(enum_signal_inversion),
+ enum_signal_inversion);
+
+static struct soc_enum soc_enum_auxo1_pulldown_resistor =
+ SOC_ENUM_SINGLE(AUXO1, AUXOx_PULLDOWN_SHIFT,
+ ARRAY_SIZE(enum_optional_resistor),
+ enum_optional_resistor);
+
+static struct soc_enum soc_enum_auxo2_pulldown_resistor =
+ SOC_ENUM_SINGLE(AUXO1, AUXOx_PULLDOWN_SHIFT,
+ ARRAY_SIZE(enum_optional_resistor),
+ enum_optional_resistor);
+
+static struct snd_kcontrol_new ab3550_snd_controls[] = {
+ /* RX Routing */
+ SOC_ENUM("RX2 Select", soc_enum_rx2_select),
+ SOC_SINGLE("LINE1 Adder", LINE1_ADDER, 0, 0x07, 0),
+ SOC_SINGLE("LINE2 Adder", LINE2_ADDER, 0, 0x07, 0),
+ SOC_SINGLE("EAR Adder", EAR_ADDER, 0, 0x07, 0),
+ SOC_SINGLE("SPKR Adder", SPKR_ADDER, 0, 0x07, 0),
+ SOC_SINGLE("AUXO1 Adder", AUXO1_ADDER, 0, 0x07, 0),
+ SOC_SINGLE("AUXO2 Adder", AUXO2_ADDER, 0, 0x07, 0),
+ /* TX Routing */
+ SOC_SINGLE("MIC1 Input Select", MIC1_INPUT_SELECT, 0, 0xff, 0),
+ SOC_SINGLE("MIC2 Input Select", MIC1_INPUT_SELECT, 0, 0xff, 0),
+ SOC_SINGLE("MIC2 to MIC1", MIC2_TO_MIC1, 0, 0x03, 0),
+ SOC_ENUM("I2S0 Input Select", soc_enum_i2s0_input_select),
+ SOC_ENUM("I2S1 Input Select", soc_enum_i2s1_input_select),
+ /* Routing of Side Tone and Analop Loop */
+ SOC_ENUM("APGA1 Source", soc_enum_apga1_source),
+ SOC_ENUM("APGA2 Source", soc_enum_apga2_source),
+ SOC_ENUM("APGA1 Enable", soc_enum_apga1_enable),
+ SOC_ENUM("APGA2 Enable", soc_enum_apga2_enable),
+ SOC_SINGLE("APGA1 Destination", APGA1_ADDER, 0, 0x3f, 0),
+ SOC_SINGLE("APGA2 Destination", APGA2_ADDER, 0, 0x3f, 0),
+ SOC_ENUM("DAC1 Side Tone", soc_enum_dac1_side_tone),
+ SOC_ENUM("DAC2 Side Tone", soc_enum_dac2_side_tone),
+ /* RX Volume Control */
+ SOC_SINGLE("RX-DPGA1 Gain", RX1_DIGITAL_PGA, 0, 0x43, 0),
+ SOC_SINGLE("RX-DPGA2 Gain", RX1_DIGITAL_PGA, 0, 0x43, 0),
+ SOC_SINGLE("RX-DPGA3 Gain", RX3_DIGITAL_PGA, 0, 0x43, 0),
+ SOC_SINGLE("LINE1 Gain", LINE1, LINEx_GAIN_SHIFT, 0x0a, 0),
+ SOC_SINGLE("LINE2 Gain", LINE2, LINEx_GAIN_SHIFT, 0x0a, 0),
+ SOC_SINGLE("SPKR Gain", SPKR, SPKR_GAIN_SHIFT, 0x16, 0),
+ SOC_SINGLE("EAR Gain", EAR, EAR_GAIN_SHIFT, 0x0e, 0),
+ SOC_SINGLE("AUXO1 Gain", AUXO1, AUXOx_GAIN_SHIFT, 0x0c, 0),
+ SOC_SINGLE("AUXO2 Gain", AUXO2, AUXOx_GAIN_SHIFT, 0x0c, 0),
+ /* TX Volume Control */
+ SOC_SINGLE("MIC1 Gain", MIC1_GAIN, MICx_GAIN_SHIFT, 0x0a, 0),
+ SOC_SINGLE("MIC2 Gain", MIC2_GAIN, MICx_GAIN_SHIFT, 0x0a, 0),
+ SOC_SINGLE("TX-DPGA1 Gain", TX_DIGITAL_PGA1, TXDPGAx_SHIFT, 0x0f, 0),
+ SOC_SINGLE("TX-DPGA2 Gain", TX_DIGITAL_PGA2, TXDPGAx_SHIFT, 0x0f, 0),
+ /* Volume Control of Side Tone and Analog Loop */
+ SOC_SINGLE("ST-PGA1 Gain", SIDETONE1_PGA, STx_PGA_SHIFT, 0x0a, 0),
+ SOC_SINGLE("ST-PGA2 Gain", SIDETONE2_PGA, STx_PGA_SHIFT, 0x0a, 0),
+ SOC_SINGLE("APGA1 Gain", ANALOG_LOOP_PGA1, APGAx_GAIN_SHIFT, 0x1d, 0),
+ SOC_SINGLE("APGA2 Gain", ANALOG_LOOP_PGA2, APGAx_GAIN_SHIFT, 0x1d, 0),
+ /* RX Properties */
+ SOC_ENUM("DAC1 Power Mode", soc_enum_dac1_power_mode),
+ SOC_ENUM("DAC2 Power Mode", soc_enum_dac2_power_mode),
+ SOC_ENUM("DAC3 Power Mode", soc_enum_dac3_power_mode),
+ SOC_ENUM("EAR Power Mode", soc_enum_ear_power_mode),
+ SOC_ENUM("AUXO Power Mode", soc_enum_auxo_power_mode),
+ SOC_ENUM("LINE1 Inversion", soc_enum_line1_inversion),
+ SOC_ENUM("LINE2 Inversion", soc_enum_line2_inversion),
+ SOC_ENUM("AUXO1 Inversion", soc_enum_auxo1_inversion),
+ SOC_ENUM("AUXO2 Inversion", soc_enum_auxo2_inversion),
+ SOC_ENUM("AUXO1 Pulldown Resistor", soc_enum_auxo1_pulldown_resistor),
+ SOC_ENUM("AUXO2 Pulldown Resistor", soc_enum_auxo2_pulldown_resistor),
+ /* TX Properties */
+ SOC_SINGLE("MIC1 VMID", MIC1_VMID_SELECT, 0, 0xff, 0),
+ SOC_SINGLE("MIC2 VMID", MIC2_VMID_SELECT, 0, 0xff, 0),
+ SOC_ENUM("MBIAS1 HiZ Option", soc_enum_mbias1_hiz_option),
+ SOC_ENUM("MBIAS2 HiZ Option", soc_enum_mbias2_hiz_option),
+ SOC_ENUM("MBIAS2 Output Voltage", soc_enum_mbias2_output_voltage),
+ SOC_ENUM("MBIAS2 Internal Resistor", soc_enum_mbias2_internal_resistor),
+ SOC_ENUM("MIC1 Input Impedance", soc_enum_mic1_input_impedance),
+ SOC_ENUM("MIC2 Input Impedance", soc_enum_mic2_input_impedance),
+ SOC_ENUM("TX1 HP Filter", soc_enum_tx1_hp_filter),
+ SOC_ENUM("TX2 HP Filter", soc_enum_tx2_hp_filter),
+ /* Side Tone and Analog Loop Properties */
+ SOC_ENUM("ST1 HP Filter", soc_enum_st1_hp_filter),
+ SOC_ENUM("ST2 HP Filter", soc_enum_st2_hp_filter),
+ /* I2S Interface Properties */
+ SOC_ENUM("I2S0 Word Length", soc_enum_i2s0_word_length),
+ SOC_ENUM("I2S1 Word Length", soc_enum_i2s1_word_length),
+ SOC_ENUM("I2S0 Mode", soc_enum_i2s0_mode),
+ SOC_ENUM("I2S1 Mode", soc_enum_i2s1_mode),
+ SOC_ENUM("I2S0 tri-state", soc_enum_i2s0_tristate),
+ SOC_ENUM("I2S1 tri-state", soc_enum_i2s1_tristate),
+ SOC_ENUM("I2S0 Pulldown Resistor", soc_enum_i2s0_pulldown_resistor),
+ SOC_ENUM("I2S1 Pulldown Resistor", soc_enum_i2s1_pulldown_resistor),
+ SOC_ENUM("I2S0 Sample Rate", soc_enum_i2s0_sample_rate),
+ SOC_ENUM("I2S1 Sample Rate", soc_enum_i2s1_sample_rate),
+ SOC_SINGLE("Interface Loop", INTERFACE_LOOP, 0, 0x0f, 0),
+ SOC_SINGLE("Interface Swap", INTERFACE_SWAP, 0, 0x1f, 0),
+ /* Miscellaneous */
+ SOC_SINGLE("Negative Charge Pump", NEGATIVE_CHARGE_PUMP, 0, 0x03, 0)
+};
+
+/* count the number of 1 */
+#define count_ones(x) ({ \
+ int num; \
+ for (num = 0; x; (x) &= (x) - 1, num++) \
+ ; \
+ num; \
+ })
+
+enum enum_power {
+ POWER_OFF = 0,
+ POWER_ON = 1
+};
+
+enum enum_link {
+ UNLINK = 0,
+ LINK = 1
+};
+
+static unsigned int ab3550_read_reg(struct snd_soc_codec *codec,
+ unsigned int reg);
+
+static enum enum_power get_widget_power_status(enum enum_widget widget)
+{
+ u8 val;
+
+ if (widget >= number_of_widgets)
+ return POWER_OFF;
+ val = read_reg(widget_pm_array[widget].reg);
+ if (val & (1 << widget_pm_array[widget].shift))
+ return POWER_ON;
+ else
+ return POWER_OFF;
+}
+
+static int count_powered_neighbors(const unsigned long *neighbors)
+{
+ unsigned long i;
+ int n = 0;
+ for_each_set_bit(i, neighbors, number_of_widgets) {
+ if (get_widget_power_status(i) == POWER_ON)
+ n++;
+ }
+ return n;
+}
+
+static int has_powered_neighbors(const unsigned long *neighbors)
+{
+ unsigned int i;
+ for_each_set_bit(i, neighbors, number_of_widgets) {
+ if (get_widget_power_status(i) == POWER_ON)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int has_stacked_neighbors(const unsigned long *neighbors)
+{
+ unsigned long *stack_map = pm_stack_as_bitmap;
+ return bitmap_intersects(stack_map, neighbors, number_of_widgets);
+}
+
+static void power_widget_unlocked(enum enum_power onoff,
+ enum enum_widget widget)
+{
+ enum enum_widget w;
+ int done;
+
+ if (widget >= number_of_widgets)
+ return;
+ if (get_widget_power_status(widget) == onoff)
+ return;
+
+ for (w = widget, done = 0; !done;) {
+ unsigned long i;
+ unsigned long *srcs = widget_pm_array[w].source_list;
+ unsigned long *sinks = widget_pm_array[w].sink_list;
+
+ dev_dbg(ab3550_dev, "%s: processing widget %s.\n",
+ __func__, widget_names[w]);
+ if (onoff == POWER_ON &&
+ !bitmap_empty(srcs, number_of_widgets) &&
+ !has_powered_neighbors(srcs)) {
+ pm_stack.stack[pm_stack.p++] = w;
+ for_each_set_bit(i, srcs, number_of_widgets) {
+ pm_stack.stack[pm_stack.p++] = i;
+ }
+ w = pm_stack.stack[--pm_stack.p];
+ continue;
+ } else if (onoff == POWER_OFF &&
+ has_powered_neighbors(sinks)) {
+ int n = 0;
+ pm_stack.stack[pm_stack.p++] = w;
+ for_each_set_bit(i, sinks, number_of_widgets) {
+ if (count_powered_neighbors(
+ widget_pm_array[i].source_list)
+ == 1 &&
+ get_widget_power_status(i) == POWER_ON) {
+ pm_stack.stack[pm_stack.p++] = i;
+ n++;
+ }
+ }
+ if (n) {
+ w = pm_stack.stack[--pm_stack.p];
+ continue;
+ } else
+ --pm_stack.p;
+ }
+ mask_set_reg(widget_pm_array[w].reg,
+ 1 << widget_pm_array[w].shift,
+ onoff == POWER_ON ? 0xff : 0);
+ dev_dbg(ab3550_dev, "%s: widget %s powered %s.\n",
+ __func__, widget_names[w],
+ onoff == POWER_ON ? "on" : "off");
+
+ if (onoff == POWER_ON &&
+ !bitmap_empty(sinks, number_of_widgets) &&
+ !has_powered_neighbors(sinks) &&
+ !has_stacked_neighbors(sinks)) {
+ for_each_set_bit(i, sinks, number_of_widgets) {
+ pm_stack.stack[pm_stack.p++] = i;
+ }
+ w = pm_stack.stack[--pm_stack.p];
+ continue;
+ } else if (onoff == POWER_OFF) {
+ for_each_set_bit(i, srcs, number_of_widgets) {
+ if (!has_powered_neighbors(
+ widget_pm_array[i].sink_list)
+ && get_widget_power_status(i) == POWER_ON
+ && !test_bit(i, pm_stack_as_bitmap)) {
+ pm_stack.stack[pm_stack.p++] = i;
+ }
+ }
+ }
+ if (pm_stack.p > 0)
+ w = pm_stack.stack[--pm_stack.p];
+ else
+ done = 1;
+ }
+}
+
+static void power_widget_locked(enum enum_power onoff,
+ enum enum_widget widget)
+{
+ if (mutex_lock_interruptible(&ab3550_pm_mutex)) {
+ dev_warn(ab3550_dev,
+ "%s: Signal received while waiting on the PM mutex.\n",
+ __func__);
+ return;
+ }
+ power_widget_unlocked(onoff, widget);
+ mutex_unlock(&ab3550_pm_mutex);
+}
+
+static void dump_registers(const char *where, ...)
+{
+ va_list ap;
+ va_start(ap, where);
+ do {
+ short reg = va_arg(ap, int);
+ if (reg < 0)
+ break;
+ dev_dbg(ab3550_dev, "%s from %s> 0x%02X : 0x%02X.\n",
+ __func__, where, reg, read_reg(reg));
+ } while (1);
+ va_end(ap);
+}
+
+/**
+ * update the link between two widgets.
+ * @op: 1 - connect; 0 - disconnect
+ * @src: source of the connection
+ * @sink: sink of the connection
+ */
+static int update_widgets_link(enum enum_link op, enum enum_widget src,
+ enum enum_widget sink,
+ u8 reg, u8 mask, u8 newval)
+{
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&ab3550_pm_mutex)) {
+ dev_warn(ab3550_dev, "%s: A signal is received while waiting on"
+ " the PM mutex.\n", __func__);
+ return -EINTR;
+ }
+
+ switch (op << 2 | test_bit(sink, widget_pm_array[src].sink_list) << 1 |
+ test_bit(src, widget_pm_array[sink].source_list)) {
+ case 3: /* UNLINK, sink in sink_list, src in source_list */
+ case 4: /* LINK, sink not in sink_list, src not in source_list */
+ break;
+ default:
+ ret = -EINVAL;
+ goto end;
+ }
+ switch (((int)op) << 2 | get_widget_power_status(src) << 1 |
+ get_widget_power_status(sink)) {
+ case 3: /* op = 0, src on, sink on */
+ if (count_powered_neighbors(widget_pm_array[sink].source_list)
+ == 1)
+ power_widget_unlocked(POWER_OFF, sink);
+ mask_set_reg(reg, mask, newval);
+ break;
+ case 6: /* op = 1, src on, sink off */
+ mask_set_reg(reg, mask, newval);
+ power_widget_unlocked(POWER_ON, sink);
+ break;
+ default:
+ /* op = 0, src off, sink off */
+ /* op = 0, src off, sink on */
+ /* op = 0, src on, sink off */
+ /* op = 1, src off, sink off */
+ /* op = 1, src off, sink on */
+ /* op = 1, src on, sink on */
+ mask_set_reg(reg, mask, newval);
+ }
+ change_bit(sink, widget_pm_array[src].sink_list);
+ change_bit(src, widget_pm_array[sink].source_list);
+end:
+ mutex_unlock(&ab3550_pm_mutex);
+ return ret;
+};
+
+static enum enum_widget apga_source_translate(u8 reg_value)
+{
+ switch (reg_value) {
+ case 1:
+ return widget_mic1;
+ case 2:
+ return widget_mic2;
+ default:
+ return number_of_widgets;
+ }
+}
+
+static enum enum_widget adder_sink_translate(u8 reg)
+{
+ switch (reg) {
+ case EAR_ADDER:
+ return widget_ear;
+ case AUXO1_ADDER:
+ return widget_auxo1;
+ case AUXO2_ADDER:
+ return widget_auxo2;
+ case SPKR_ADDER:
+ return widget_spkr;
+ case LINE1_ADDER:
+ return widget_line1;
+ case LINE2_ADDER:
+ return widget_line2;
+ case APGA1_ADDER:
+ return widget_apga1;
+ case APGA2_ADDER:
+ return widget_apga2;
+ default:
+ return number_of_widgets;
+ }
+}
+
+/**
+ This function is only called by the SOC framework to
+ set registers associated to the mixer controls.
+*/
+static int ab3550_write_reg(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ if (reg < MIC_BIAS1 || reg > INTERFACE_SWAP)
+ return -EINVAL;
+ switch (reg) {
+ u8 diff, oldval;
+ case ANALOG_LOOP_PGA1:
+ case ANALOG_LOOP_PGA2: {
+ enum enum_widget apga = reg == ANALOG_LOOP_PGA1 ?
+ widget_apga1 : widget_apga2;
+
+ oldval = read_reg(reg);
+ diff = value ^ oldval;
+
+ /* The APGA is to be turned on/off.
+ The power bit and the other bits in the
+ same register won't be changed at the same time
+ since they belong to different controls.
+ */
+ if (diff & (1 << APGAx_PWR_SHIFT)) {
+ power_widget_locked(value >> APGAx_PWR_SHIFT & 1,
+ apga);
+ } else if (diff & APGAx_MUX_MASK) {
+ enum enum_widget old_source =
+ apga_source_translate(oldval);
+ enum enum_widget new_source =
+ apga_source_translate(value);
+ update_widgets_link(UNLINK, old_source, apga,
+ reg, APGAx_MUX_MASK, 0);
+ update_widgets_link(LINK, new_source, apga,
+ reg, APGAx_MUX_MASK, value);
+ } else {
+ set_reg(reg, value);
+ }
+ break;
+ }
+
+ case APGA1_ADDER:
+ case APGA2_ADDER: {
+ int i;
+ enum enum_widget apga;
+ enum enum_widget apga_dst[] = {
+ widget_auxo2, widget_auxo1, widget_ear, widget_spkr,
+ widget_line2, widget_line1
+ };
+
+ apga = adder_sink_translate(reg);
+ oldval = read_reg(reg);
+ diff = value ^ oldval;
+ for (i = 0; diff; i++) {
+ if (!(diff & 1 << i))
+ continue;
+ diff ^= 1 << i;
+ update_widgets_link(value >> i & 1, apga, apga_dst[i],
+ reg, 1 << i, value);
+ }
+ break;
+ }
+
+ case EAR_ADDER:
+ case AUXO1_ADDER:
+ case AUXO2_ADDER:
+ case SPKR_ADDER:
+ case LINE1_ADDER:
+ case LINE2_ADDER: {
+ int i;
+ enum enum_widget widgets[] = {
+ widget_dac1, widget_dac2, widget_dac3,
+ };
+ oldval = read_reg(reg);
+ diff = value ^ oldval;
+ for (i = 0; diff; i++) {
+ if (!(diff & 1 << i))
+ continue;
+ diff ^= 1 << i;
+ update_widgets_link(value >> i & 1, widgets[i],
+ adder_sink_translate(reg),
+ reg, 1 << i, value);
+ }
+ break;
+ }
+
+ default:
+ set_reg(reg, value);
+ }
+ return 0;
+}
+
+static unsigned int ab3550_read_reg(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ return read_reg(reg);
+}
+
+static int ab3550_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, ab3550_dapm_widgets,
+ ARRAY_SIZE(ab3550_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+static void power_for_playback(enum enum_power onoff, int ifsel)
+{
+ dev_dbg(ab3550_dev, "%s: interface %d power %s.\n", __func__,
+ ifsel, onoff == POWER_ON ? "on" : "off");
+ if (mutex_lock_interruptible(&ab3550_pm_mutex)) {
+ dev_warn(ab3550_dev,
+ "%s: Signal received while waiting on the PM mutex.\n",
+ __func__);
+ return;
+ }
+ power_widget_unlocked(onoff, ifsel == 0 ?
+ widget_if0_dld_l : widget_if1_dld_l);
+ power_widget_unlocked(onoff, ifsel == 0 ?
+ widget_if0_dld_r : widget_if1_dld_r);
+ mutex_unlock(&ab3550_pm_mutex);
+}
+
+static void power_for_capture(enum enum_power onoff, int ifsel)
+{
+ dev_dbg(ab3550_dev, "%s: interface %d power %s", __func__,
+ ifsel, onoff == POWER_ON ? "on" : "off");
+ if (mutex_lock_interruptible(&ab3550_pm_mutex)) {
+ dev_warn(ab3550_dev,
+ "%s: Signal received while waiting on the PM mutex.\n",
+ __func__);
+ return;
+ }
+ power_widget_unlocked(onoff, ifsel == 0 ?
+ widget_if0_uld_l : widget_if1_uld_l);
+ power_widget_unlocked(onoff, ifsel == 0 ?
+ widget_if0_uld_r : widget_if1_uld_r);
+ mutex_unlock(&ab3550_pm_mutex);
+}
+
+static int ab3550_add_controls(struct snd_soc_codec *codec)
+{
+ int err = 0, i, n = ARRAY_SIZE(ab3550_snd_controls);
+
+ pr_debug("%s: %s called.\n", __FILE__, __func__);
+ for (i = 0; i < n; i++) {
+ err = snd_ctl_add(codec->card, snd_ctl_new1(
+ &ab3550_snd_controls[i], codec));
+ if (err < 0) {
+ pr_err("%s failed to add control No.%d of %d.\n",
+ __func__, i, n);
+ return err;
+ }
+ }
+ return err;
+}
+
+static int ab3550_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params,
+ struct snd_soc_dai *dai)
+{
+ u8 val;
+ u8 reg = dai->id == 0 ? INTERFACE0 : INTERFACE1;
+
+ if (!ab3550_dev) {
+ pr_err("%s: The AB3550 codec driver not initialized.\n",
+ __func__);
+ return -EAGAIN;
+ }
+ dev_info(ab3550_dev, "%s called.\n", __func__);
+ switch (params_rate(hw_params)) {
+ case 8000:
+ val = I2Sx_SR_8000Hz;
+ break;
+ case 16000:
+ val = I2Sx_SR_16000Hz;
+ break;
+ case 44100:
+ val = I2Sx_SR_44100Hz;
+ break;
+ case 48000:
+ val = I2Sx_SR_48000Hz;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ !dai->capture.active : !dai->playback.active) {
+
+ mask_set_reg(reg, I2Sx_SR_MASK, val << I2Sx_SR_SHIFT);
+ if ((read_reg(reg) & I2Sx_MODE_MASK) == 0) {
+ mask_set_reg(reg, MASTER_GENx_PWR_MASK,
+ 1 << MASTER_GENx_PWR_SHIFT);
+ }
+ }
+ return 0;
+}
+
+static int ab3550_pcm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ dai->playback.active : dai->capture.active) {
+
+ dev_err(ab3550_dev, "%s: A %s stream is already active.\n",
+ __func__,
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "PLAYBACK" : "CAPTURE");
+ return -EBUSY;
+ }
+ return 0;
+}
+static int ab3550_pcm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ dev_info(ab3550_dev, "%s called.\n", __func__);
+
+ /* Configure registers for either playback or capture */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ power_for_playback(POWER_ON, dai->id);
+ dump_registers(__func__,
+ dai->id == 0 ? INTERFACE0 : INTERFACE1,
+ RX1, RX2, SPKR, EAR, -1);
+ } else {
+ power_for_capture(POWER_ON, dai->id);
+ dump_registers(__func__, MIC_BIAS1, MIC_BIAS2, MIC1_GAIN, TX1,
+ dai->id == 0 ? INTERFACE0 : INTERFACE1, -1);
+ }
+ return 0;
+}
+
+static void ab3550_pcm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai* dai)
+{
+ u8 iface = dai->id == 0 ? INTERFACE0 : INTERFACE1;
+ dev_info(ab3550_dev, "%s called.\n", __func__);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ power_for_playback(POWER_OFF, dai->id);
+ } else {
+ power_for_capture(POWER_OFF, dai->id);
+ }
+ if (!dai->playback.active && !dai->capture.active &&
+ (read_reg(iface) & I2Sx_MODE_MASK) == 0)
+ mask_set_reg(iface, MASTER_GENx_PWR_MASK, 0);
+}
+
+static int ab3550_set_dai_sysclk(struct snd_soc_dai* dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ return 0;
+}
+
+static int ab3550_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ u8 iface = (codec_dai->id == 0) ? INTERFACE0 : INTERFACE1;
+ u8 val = 0;
+ dev_info(ab3550_dev, "%s called.\n", __func__);
+
+ switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
+ SND_SOC_DAIFMT_MASTER_MASK)) {
+
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+ val |= 1 << I2Sx_MODE_SHIFT;
+ break;
+
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+ break;
+
+ default:
+ dev_warn(ab3550_dev, "AB3550_dai: unsupported DAI format "
+ "0x%x\n", fmt);
+ return -EINVAL;
+ }
+ if (codec_dai->playback.active && codec_dai->capture.active) {
+ if ((read_reg(iface) & I2Sx_MODE_MASK) == val)
+ return 0;
+ else {
+ dev_err(ab3550_dev,
+ "%s: DAI format set differently "
+ "by an existing stream.\n", __func__);
+ return -EINVAL;
+ }
+ }
+ mask_set_reg(iface, I2Sx_MODE_MASK, val);
+ return 0;
+}
+
+struct snd_soc_dai ab3550_codec_dai[] = {
+ {
+ .name = "ab3550_0",
+ .id = 0,
+ .playback = {
+ .stream_name = "ab3550_0",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AB3550_SUPPORTED_RATE,
+ .formats = AB3550_SUPPORTED_FMT,
+ },
+ .capture = {
+ .stream_name = "ab3550_0",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AB3550_SUPPORTED_RATE,
+ .formats = AB3550_SUPPORTED_FMT,
+ },
+ .ops = (struct snd_soc_dai_ops[]) {
+ {
+ .startup = ab3550_pcm_startup,
+ .prepare = ab3550_pcm_prepare,
+ .hw_params = ab3550_pcm_hw_params,
+ .shutdown = ab3550_pcm_shutdown,
+ .set_sysclk = ab3550_set_dai_sysclk,
+ .set_fmt = ab3550_set_dai_fmt,
+ }
+ },
+ .symmetric_rates = 1,
+ .private_data = NULL
+ },
+ {
+ .name = "ab3550_1",
+ .id = 1,
+ .playback = {
+ .stream_name = "ab3550_1",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AB3550_SUPPORTED_RATE,
+ .formats = AB3550_SUPPORTED_FMT,
+ },
+ .capture = {
+ .stream_name = "ab3550_1",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AB3550_SUPPORTED_RATE,
+ .formats = AB3550_SUPPORTED_FMT,
+ },
+ .ops = (struct snd_soc_dai_ops[]) {
+ {
+ .startup = ab3550_pcm_startup,
+ .prepare = ab3550_pcm_prepare,
+ .hw_params = ab3550_pcm_hw_params,
+ .shutdown = ab3550_pcm_shutdown,
+ .set_sysclk = ab3550_set_dai_sysclk,
+ .set_fmt = ab3550_set_dai_fmt,
+ }
+ },
+ .symmetric_rates = 1,
+ .private_data = NULL
+ }
+};
+EXPORT_SYMBOL_GPL(ab3550_codec_dai);
+
+static int ab3550_codec_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ int ret;
+
+ dev_info(&pdev->dev, "%s called. pdev = %p.\n", __func__, pdev);
+ if (!ab3550_codec) {
+ dev_err(&pdev->dev, "%s: Codec device not registered.\n",
+ __func__);
+ return -EAGAIN;
+ }
+ socdev->card->codec = ab3550_codec;
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "%s: Failed to create a new card "
+ "and new PCMs. error %d\n", __func__, ret);
+ goto err;
+ }
+ /* Add controls */
+ if (ab3550_add_controls(ab3550_codec) < 0)
+ goto err;
+ ab3550_add_widgets(ab3550_codec);
+ return 0;
+
+err:
+ snd_soc_free_pcms(socdev);
+ return ret;
+}
+
+static int ab3550_codec_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ab3550_codec_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ dev_dbg(ab3550_dev, "%s : pdev=%p.\n", __func__, pdev);
+ mask_set_reg(CLOCK, CLOCK_ENABLE_MASK, 0);
+ return 0;
+}
+
+static int ab3550_codec_resume(struct platform_device *pdev)
+{
+ dev_dbg(ab3550_dev, "%s : pdev=%p.\n", __func__, pdev);
+ mask_set_reg(CLOCK, CLOCK_ENABLE_MASK, 0xff);
+ return 0;
+}
+#else
+#define ab3550_codec_resume NULL
+#define ab3550_codec_suspend NULL
+#endif
+
+struct snd_soc_codec_device soc_codec_dev_ab3550 = {
+ .probe = ab3550_codec_probe,
+ .remove = ab3550_codec_remove,
+ .suspend = ab3550_codec_suspend,
+ .resume = ab3550_codec_resume
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_ab3550);
+
+static inline void init_playback_route(void)
+{
+ update_widgets_link(LINK, widget_if0_dld_l, widget_rx1, 0, 0, 0);
+ update_widgets_link(LINK, widget_rx1, widget_dac1, 0, 0, 0);
+ update_widgets_link(LINK, widget_dac1, widget_spkr,
+ SPKR_ADDER, DAC1_TO_ADDER_MASK, 0xff);
+
+ update_widgets_link(LINK, widget_if0_dld_r, widget_rx2,
+ RX2, RX2_IF_SELECT_MASK, 0);
+ update_widgets_link(LINK, widget_rx2, widget_dac2, 0, 0, 0);
+ update_widgets_link(LINK, widget_dac2, widget_ear,
+ EAR_ADDER, DAC2_TO_ADDER_MASK, 0xff);
+}
+
+static inline void init_capture_route(void)
+{
+ update_widgets_link(LINK, widget_micbias2, widget_mic1p1,
+ 0, 0, 0);
+ update_widgets_link(LINK, widget_micbias2, widget_mic1n1,
+ 0, 0, 0);
+ update_widgets_link(LINK, widget_mic1p1, widget_mic1,
+ MIC1_INPUT_SELECT, MICxP1_SEL_MASK, 0xff);
+ update_widgets_link(LINK, widget_mic1n1, widget_mic1,
+ MIC1_INPUT_SELECT, MICxN1_SEL_MASK, 0xff);
+ update_widgets_link(LINK, widget_mic1, widget_adc1,
+ 0, 0, 0);
+ update_widgets_link(LINK, widget_adc1, widget_tx1,
+ 0, 0, 0);
+ update_widgets_link(LINK, widget_tx1, widget_if0_uld_l,
+ INTERFACE0_DATA, I2Sx_L_DATA_MASK,
+ I2Sx_L_DATA_TX1_MASK);
+ update_widgets_link(LINK, widget_tx1, widget_if0_uld_r,
+ INTERFACE0_DATA, I2Sx_R_DATA_MASK,
+ I2Sx_R_DATA_TX1_MASK);
+}
+
+static inline void init_playback_gain(void)
+{
+ mask_set_reg(RX1_DIGITAL_PGA, RXx_PGA_GAIN_MASK,
+ 0x40 << RXx_PGA_GAIN_SHIFT);
+ mask_set_reg(RX2_DIGITAL_PGA, RXx_PGA_GAIN_MASK,
+ 0x40 << RXx_PGA_GAIN_SHIFT);
+ mask_set_reg(EAR, EAR_GAIN_MASK, 0x06 << EAR_GAIN_SHIFT);
+ mask_set_reg(SPKR, SPKR_GAIN_MASK, 0x6 << SPKR_GAIN_SHIFT);
+}
+
+static inline void init_capture_gain(void)
+{
+ mask_set_reg(MIC1_GAIN, MICx_GAIN_MASK, 0x06 << MICx_GAIN_SHIFT);
+ mask_set_reg(TX_DIGITAL_PGA1, TXDPGAx_MASK, 0x0f << TXDPGAx_SHIFT);
+}
+
+static int __init ab3550_platform_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ int i;
+ u8 reg;
+
+ pr_debug("%s invoked with pdev = %p.\n", __func__, pdev);
+ ab3550_dev = &pdev->dev;
+ /* Initialize the codec registers */
+ for (reg = AB3550_FIRST_REG; reg <= AB3550_LAST_REG; reg++)
+ set_reg(reg, 0);
+
+ mask_set_reg(CLOCK, CLOCK_REF_SELECT_MASK | CLOCK_ENABLE_MASK,
+ 1 << CLOCK_REF_SELECT_SHIFT | 1 << CLOCK_ENABLE_SHIFT);
+ init_playback_route();
+ init_playback_gain();
+ init_capture_route();
+ init_capture_gain();
+ memset(&pm_stack, 0, sizeof(pm_stack));
+
+ ab3550_codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (ab3550_codec == NULL)
+ return -ENOMEM;
+ ab3550_codec->name = "AB3550";
+ ab3550_codec->owner = THIS_MODULE;
+ ab3550_codec->dai = ab3550_codec_dai;
+ ab3550_codec->num_dai = 2;
+ ab3550_codec->read = ab3550_read_reg;
+ ab3550_codec->write = ab3550_write_reg;
+ ab3550_codec->reg_cache_size = 0;
+ ab3550_codec->reg_cache = NULL;
+ INIT_LIST_HEAD(&ab3550_codec->dapm_widgets);
+ INIT_LIST_HEAD(&ab3550_codec->dapm_paths);
+ mutex_init(&ab3550_codec->mutex);
+ ret = snd_soc_register_codec(ab3550_codec);
+ if (ret) {
+ dev_err(ab3550_dev, "%s: Failed to register codec: %d.\n",
+ __func__, ret);
+ kfree(ab3550_codec);
+ }
+
+ for (i = 0; !ret && i < ARRAY_SIZE(ab3550_codec_dai); i++)
+ ret = snd_soc_register_dai(ab3550_codec_dai + i);
+ if (ret && i == 1) {
+ snd_soc_unregister_codec(ab3550_codec);
+ kfree(ab3550_codec);
+ }
+
+ return ret;
+}
+
+static int ab3550_platform_remove(struct platform_device *pdev)
+{
+ int i;
+
+ pr_debug("%s called.\n", __func__);
+ mask_set_reg(CLOCK, CLOCK_ENABLE_MASK, 0);
+ for (i = 0; i < ARRAY_SIZE(ab3550_codec_dai); i++)
+ snd_soc_unregister_dai(ab3550_codec_dai + i);
+ snd_soc_unregister_codec(ab3550_codec);
+ kfree(ab3550_codec);
+ ab3550_dev = NULL;
+ return 0;
+}
+
+static int ab3550_platform_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ return 0;
+}
+
+static int ab3550_platform_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver ab3550_platform_driver = {
+ .driver = {
+ .name = "ab3550-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab3550_platform_probe,
+ .remove = ab3550_platform_remove,
+ .suspend = ab3550_platform_suspend,
+ .resume = ab3550_platform_resume,
+};
+
+
+static int __devinit ab3550_init(void)
+{
+ int ret1;
+
+ pr_debug("%s called.\n", __func__);
+
+ ab3550_dev = NULL;
+ ab3550_codec = NULL;
+ /* Register codec platform driver. */
+ ret1 = platform_driver_register(&ab3550_platform_driver);
+ if (ret1 < 0) {
+ pr_debug("%s: Error %d: Failed to register codec platform "
+ "driver.\n", __func__, ret1);
+ }
+ return ret1;
+}
+
+static void __devexit ab3550_exit(void)
+{
+ pr_debug("u8500_ab3550_init: Enter.\n");
+
+ /* Register codec platform driver. */
+ pr_debug("%s: Un-register codec platform driver.\n", __func__);
+ platform_driver_unregister(&ab3550_platform_driver);
+}
+
+module_init(ab3550_init);
+module_exit(ab3550_exit);
+
+MODULE_DESCRIPTION("AB3550 Codec driver");
+MODULE_AUTHOR("Xie Xiaolei <xie.xiaolei@stericsson.com>");
+MODULE_LICENSE("GPLv2");
diff --git a/sound/soc/codecs/ab3550.h b/sound/soc/codecs/ab3550.h
new file mode 100644
index 00000000000..f553fdce96b
--- /dev/null
+++ b/sound/soc/codecs/ab3550.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Xie Xiaolei <xie.xiaolei@etericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 AB3550_CODEC_REGISTERS_H
+#define AB3550_CODEC_REGISTERS_H
+
+extern struct snd_soc_dai ab3550_codec_dai[2];
+extern struct snd_soc_codec_device soc_codec_dev_ab3550;
+
+#define AB3550_SUPPORTED_RATE (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define AB3550_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+/* MIC BIAS */
+
+#define MIC_BIAS1 0X31
+#define MIC_BIAS2 0X32
+#define MBIAS2_OUT_V_MASK 0x04
+#define MBIAS2_OUT_V_SHIFT 2
+#define MBIAS_PWR_MASK 0x02
+#define MBIAS_PWR_SHIFT 1
+#define MBIAS_PDN_IMP_MASK 0x01
+#define MBIAS_PDN_IMP_SHIFT 0
+
+#define MIC_BIAS2_VAD 0x33
+#define MBIAS2_R_INT_MASK 0x01
+#define MBIAS2_R_INT_SHIFT 0
+
+/* MIC */
+#define MIC1_GAIN 0x34
+#define MIC2_GAIN 0x35
+#define MICx_GAIN_MASK 0xF0
+#define MICx_GAIN_SHIFT 4
+#define MICx_IN_IMP_MASK 0x0C
+#define MICx_IN_IMP_SHIFT 2
+#define MICx_PWR_MASK 0x01
+#define MICx_PWR_SHIFT 0
+
+#define MIC1_INPUT_SELECT 0x36
+#define MIC2_INPUT_SELECT 0x37
+#define MICxP1_SEL_MASK 0x80
+#define MICxP1_SEL_SHIFT 7
+#define MICxN1_SEL_MASK 0x40
+#define MICxN1_SEL_SHIFT 6
+#define MICxP2_SEL_MASK 0x20
+#define MICxP2_SEL_SHIFT 5
+#define MICxN2_SEL_MASK 0x10
+#define MICxN2_SEL_SHIFT 4
+#define LINEIN_SEL_MASK 0x03
+#define LINEIN_SEL_SHIFT 0
+
+#define MIC1_VMID_SELECT 0x38
+#define MIC2_VMID_SELECT 0x39
+#define VMIDx_ENABLE_MASK 0xC0
+#define VMIDx_ENABLE_SHIFT 6
+#define VMIDx_LINEIN1_N_MASK 0x20
+#define VMIDx_LINEIN1_N_SHIFT 5
+#define VMIDx_LINEIN2_N_MASK 0x10
+#define VMIDx_LINEIN2_N_SHIFT 4
+#define VMIDx_MICxP1_MASK 0x08
+#define VMIDx_MICxP1_SHIFT 3
+#define VMIDx_MICxP2_MASK 0x04
+#define VMIDx_MICxP2_SHIFT 2
+#define VMIDx_MICxN1_MASK 0x02
+#define VMIDx_MICxN1_SHIFT 1
+#define VMIDx_MICxN2_MASK 0x01
+#define VMIDx_MICxN2_SHIFT 0
+
+#define MIC2_TO_MIC1 0x3A
+#define MIC2_TO_MIC1_MASK 0x03
+#define MIC2_TO_MIC1_SHIFT 0
+
+/* Analog Loop */
+#define ANALOG_LOOP_PGA1 0x3B
+#define ANALOG_LOOP_PGA2 0x3C
+#define APGAx_GAIN_MASK 0xF8
+#define APGAx_GAIN_SHIFT 3
+#define APGAx_PWR_MASK 0x04
+#define APGAx_PWR_SHIFT 2
+#define APGAx_MUX_MASK 0x03
+#define APGAx_MUX_SHIFT 0
+#define APGAx_MUX_MIC1_MASK 0x01
+#define APGAx_MUX_MIC1_SHIFT 0
+#define APGAx_MUX_MIC2_MASK 0x02
+#define APGAx_MUX_MIC2_SHIFT 1
+
+
+#define APGA_VMID_SELECT 0x3D
+#define VMID_APGA1_ENABLE_MASK 0xC0
+#define VMID_APGA1_ENABLE_SHIFT 6
+#define VMID_APGA1_LINEIN1_MASK 0x20
+#define VMID_APGA1_LINEIN1_SHIFT 5
+#define VMID_APGA2_ENABLE_MASK 0x0C
+#define VMID_APGA2_ENABLE_SHIFT 2
+#define VMID_APGA2_LINEIN2_MASK 0x02
+#define VMID_APGA2_LINEIN2_SHIFT 1
+
+/* Output Amplifiers */
+#define EAR 0x3E
+#define EAR_PWR_MODE_MASK 0x20
+#define EAR_PWR_MODE_SHIFT 5
+#define EAR_PWR_MASK 0x10
+#define EAR_PWR_SHIFT 4
+#define EAR_GAIN_MASK 0x0F
+#define EAR_GAIN_SHIFT 0
+
+#define AUXO1 0x3F
+#define AUXO2 0x40
+#define AUXOx_PWR_MASK 0x80
+#define AUXOx_PWR_SHIFT 7
+#define AUXOx_INV_MASK 0x40
+#define AUXOx_INV_SHIFT 6
+#define AUXOx_PULLDOWN_MASK 0x20
+#define AUXOx_PULLDOWN_SHIFT 5
+#define AUXOx_GAIN_MASK 0x0F
+#define AUXOx_GAIN_SHIFT 0
+
+#define AUXO_PWR_MODE 0x41
+#define AUT_PWR_MODE_MASK 0x04
+#define AUT_PWR_MODE_SHIFT 2
+#define AUXO_PWR_MODE_MASK 0x03
+#define AUXO_PWR_MODE_SHIFT 0
+
+#define OFFSET_CANCEL 0x42
+#define SPKR_OFF_CANC_MASK 0x04
+#define SPKR_OFF_CANC_SHIFT 2
+#define AUXO_OFF_CANC_MASK 0x02
+#define AUXO_OFF_CANC_SHIFT 1
+#define OFFSET_CLOCK_MASK 0x01
+#define OFFSET_CLOCK_SHIFT 0
+
+#define SPKR 0x43
+#define OVR_CURR_PROT_MASK 0x80
+#define OVR_CURR_PROT_SHIFT 7
+#define SPKR_PWR_MASK 0x40
+#define SPKR_PWR_SHIFT 6
+#define SPKR_GAIN_MASK 0x1F
+#define SPKR_GAIN_SHIFT 0
+
+#define LINE1 0x44
+#define LINE2 0x45
+#define LINEx_PWR_MASK 0x80
+#define LINEx_PWR_SHIFT 7
+#define LINEx_INV_MASK 0x40
+#define LINEx_INV_SHIFT 6
+#define VMID_BUFFx_MASK 0x10
+#define VMID_BUFFx_SHIFT 4
+#define LINEx_GAIN_MASK 0x0F
+#define LINEx_GAIN_SHIFT 0
+
+/* Analog loop Routing */
+
+#define APGA1_ADDER 0x46
+#define APGA2_ADDER 0x47
+#define APGAx_TO_LINE1_MASK 0x20
+#define APGAx_TO_LINE1_SHIFT 0x5F
+#define APGAx_TO_LINE2_MASK 0x10
+#define APGAx_TO_LINE2_SHIFT 4
+#define APGAx_TO_SPKR_MASK 0x08
+#define APGAx_TO_SPKR_SHIFT 3
+#define APGAx_TO_EAR_MASK 0x04
+#define APGAx_TO_EAR_SHIFT 2
+#define APGAx_TO_AUXO1_MASK 0x02
+#define APGAx_TO_AUXO1_SHIFT 1
+#define APGAx_TO_AUXO2_MASK 0x01
+#define APGAx_TO_AUXO2_SHIFT 0
+#define APGAx_ADDER_VALID_BITS_MASK 0x3F
+
+/* Output Amplifiers Routing */
+
+#define EAR_ADDER 0x48
+#define AUXO1_ADDER 0x49
+#define AUXO2_ADDER 0x4A
+#define SPKR_ADDER 0x4B
+#define LINE1_ADDER 0x4C
+#define LINE2_ADDER 0x4D
+#define DAC3_TO_ADDER_MASK 0x04
+#define DAC3_TO_ADDER_SHIFT 2
+#define DAC2_TO_ADDER_MASK 0x02
+#define DAC2_TO_ADDER_SHIFT 1
+#define DAC1_TO_ADDER_MASK 0x01
+#define DAC1_TO_ADDER_SHIFT 0
+
+#define EAR_TO_MIC2 0x4E
+#define EAR_TO_MIC2_MASK 0x01
+#define EAR_TO_MIC2_SHIFT 0
+
+#define SPKR_TO_MIC2 0x4F
+#define SPKR_TO_MIC2_MASK 0x01
+#define SPKR_TO_MIC2_SHIFT 0
+
+#define NEGATIVE_CHARGE_PUMP 0x50
+#define NCP_MODE_MASK 0x02
+#define NCP_MODE_SHIFT 1
+#define NCP_PWR_MASK 0x01
+#define NCP_PWR_SHIFT 0
+
+#define TX1 0x51
+#define TX2 0x52
+#define TXx_HP_FILTER_MASK 0x0C
+#define TXx_HP_FILTER_SHIFT 2
+#define TXx_PWR_MASK 0x02
+#define TXx_PWR_SHIFT 1
+#define ADCx_PWR_MASK 0x01
+#define ADCx_PWR_SHIFT 0
+
+#define RX1 0x53
+#define RX2 0x54
+#define RX2_IF_SELECT_MASK 0x10
+#define RX2_IF_SELECT_SHIFT 4
+#define RX3 0x55
+#define RXx_PWR_MASK 0x08
+#define RXx_PWR_SHIFT 3
+#define DACx_PWR_MASK 0x04
+#define DACx_PWR_SHIFT 2
+#define DACx_PWR_MODE_MASK 0x03
+#define DACx_PWR_MODE_SHIFT 0
+
+#define TX_DIGITAL_PGA1 0X56
+#define TX_DIGITAL_PGA2 0X57
+#define TXDPGAx_MASK 0x0F
+#define TXDPGAx_SHIFT 0
+
+#define RX1_DIGITAL_PGA 0x58
+#define RX2_DIGITAL_PGA 0x59
+#define RX3_DIGITAL_PGA 0x5A
+#define RXx_PGA_GAIN_MASK 0x7F
+#define RXx_PGA_GAIN_SHIFT 0
+
+#define SIDETONE1_PGA 0x5B
+#define SIDETONE2_PGA 0x5C
+#define STx_HP_FILTER_MASK 0x60
+#define STx_HP_FILTER_SHIFT 5
+#define STx_MUX_MASK 0x10
+#define STx_MUX_SHIFT 4
+#define STx_PGA_MASK 0x0F
+#define STx_PGA_SHIFT 0
+
+/* clock */
+
+#define CLOCK 0x5D
+#define CLOCK_REF_SELECT_MASK 0x02
+#define CLOCK_REF_SELECT_SHIFT 1
+#define CLOCK_ENABLE_MASK 0x01
+#define CLOCK_ENABLE_SHIFT 0
+
+/* Interface */
+
+#define INTERFACE0 0x5E
+#define INTERFACE1 0x60
+#define I2Sx_WORDLENGTH_MASK 0x40
+#define I2Sx_WORDLENGTH_SHIFT 6
+#define MASTER_GENx_PWR_MASK 0x20
+#define MASTER_GENx_PWR_SHIFT 5
+#define I2Sx_MODE_MASK 0x10
+#define I2Sx_MODE_SHIFT 4
+#define I2Sx_TRISTATE_MASK 0x08
+#define I2Sx_TRISTATE_SHIFT 3
+#define I2Sx_PULLDOWN_MASK 0x04
+#define I2Sx_PULLDOWN_SHIFT 2
+#define I2Sx_SR_MASK 0x03
+#define I2Sx_SR_SHIFT 0
+#define I2Sx_SR_8000Hz 0
+#define I2Sx_SR_16000Hz 1
+#define I2Sx_SR_44100Hz 2
+#define I2Sx_SR_48000Hz 3
+
+#define INTERFACE0_DATA 0x5F
+#define INTERFACE1_DATA 0x61
+#define I2Sx_L_DATA_MASK 0x0C
+#define I2Sx_L_DATA_TX1_MASK 0x04
+#define I2Sx_L_DATA_TX2_MASK 0x08
+#define I2Sx_L_DATA_SHIFT 2
+#define I2Sx_R_DATA_MASK 0x03
+#define I2Sx_R_DATA_TX1_MASK 0x01
+#define I2Sx_R_DATA_TX2_MASK 0x02
+#define I2Sx_R_DATA_SHIFT 0
+
+#define INTERFACE_LOOP 0x62
+#define I2S0_INT_LOOP_MASK 0x08
+#define I2S0_INT_LOOP_SHIFT 3
+#define I2S0_EXT_LOOP_MASK 0x04
+#define I2S0_EXT_LOOP_SHIFT 2
+#define I2S1_INT_LOOP_MASK 0x02
+#define I2S1_INT_LOOP_SHIFT 1
+#define I2S1_EXT_LOOP_MASK 0x01
+#define I2S1_EXT_LOOP_SHIFT 0
+
+#define INTERFACE_SWAP 0x63
+#define RX_SWAP0_MASK 0x10
+#define RX_SWAP0_SHIFT 4
+#define RX_SWAP1_MASK 0x08
+#define RX_SWAP1_SHIFT 3
+#define IF_SWAP_MASK 0x04
+#define IF_SWAP_SHIFT 2
+#define IO_SWAP0_MASK 0x02
+#define IO_SWAP0_SHIFT 1
+#define IO_SWAP1_MASK 0x01
+#define IO_SWAP1_SHIFT 0
+
+#define AB3550_FIRST_REG MIC_BIAS1
+#define AB3550_LAST_REG INTERFACE_SWAP
+
+#define AB3550_VIRTUAL_REG1 (AB3550_LAST_REG + 1)
+#define IF0_DLD_L_PW_SHIFT 0
+#define IF0_DLD_R_PW_SHIFT 1
+#define IF0_ULD_L_PW_SHIFT 2
+#define IF0_ULD_R_PW_SHIFT 3
+#define IF1_DLD_L_PW_SHIFT 4
+#define IF1_DLD_R_PW_SHIFT 5
+#define IF1_ULD_L_PW_SHIFT 6
+#define IF1_ULD_R_PW_SHIFT 7
+
+#define AB3550_VIRTUAL_REG2 (AB3550_LAST_REG + 2)
+#define MIC1P1_PW_SHIFT 0
+#define MIC1N1_PW_SHIFT 1
+#define MIC1P2_PW_SHIFT 2
+#define MIC1N2_PW_SHIFT 3
+#define MIC2P1_PW_SHIFT 4
+#define MIC2N1_PW_SHIFT 5
+#define MIC2P2_PW_SHIFT 6
+#define MIC2N2_PW_SHIFT 7
+
+
+#endif
diff --git a/sound/soc/codecs/av8100_audio.c b/sound/soc/codecs/av8100_audio.c
new file mode 100644
index 00000000000..7bcb985b9eb
--- /dev/null
+++ b/sound/soc/codecs/av8100_audio.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ola Lilja (ola.o.lilja@stericsson.com)
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <video/av8100.h>
+#include <video/hdmi.h>
+
+#include "av8100_audio.h"
+
+#define AV8100_SUPPORTED_RATE (SNDRV_PCM_RATE_48000)
+#define AV8100_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE)
+
+static int setupAV8100_stereo(void)
+{
+ union av8100_configuration config;
+ struct av8100_status status;
+ int ret;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ /* Startup AV8100 if it is not already started */
+ status = av8100_status_get();
+ if (status.av8100_state < AV8100_OPMODE_STANDBY) {
+ pr_info("%s: Powering up AV8100.", __func__);
+ ret = av8100_powerup();
+ if (ret != 0) {
+ pr_err("%s: Power up AV8100 failed "
+ "(av8100_powerup returned %d)!\n",
+ __func__,
+ ret);
+ return -EINVAL;
+ }
+ }
+ if (status.av8100_state < AV8100_OPMODE_INIT) {
+ ret = av8100_download_firmware(NULL, 0, I2C_INTERFACE);
+ if (ret != 0) {
+ pr_err("%s: Download firmware failed "
+ "(av8100_download_firmware returned %d)!\n",
+ __func__,
+ ret);
+ return -EINVAL;
+ }
+ }
+
+ /* Set the HDMI format of AV8100 */
+ pr_info("%s: Setting hdmi_format.", __func__);
+ config.hdmi_format.hdmi_mode = AV8100_HDMI_ON;
+ config.hdmi_format.hdmi_format = AV8100_HDMI;
+ ret = av8100_conf_prep(AV8100_COMMAND_AUDIO_INPUT_FORMAT, &config);
+ if (ret != 0) {
+ pr_err("%s: Setting hdmi_format failed "
+ "(av8100_conf_prep returned %d)!\n",
+ __func__,
+ ret);
+ return -EINVAL;
+ }
+ ret = av8100_conf_w(AV8100_COMMAND_AUDIO_INPUT_FORMAT,
+ NULL,
+ NULL,
+ I2C_INTERFACE);
+ if (ret != 0) {
+ pr_err("%s: Setting hdmi_format failed "
+ "(av8100_conf_w returned %d)!\n",
+ __func__,
+ ret);
+ return -EINVAL;
+ }
+
+ /* Set the audio input format of AV8100 */
+ pr_info("%s: Setting audio_input_format.", __func__);
+ config.audio_input_format.audio_input_if_format = AV8100_AUDIO_I2SDELAYED_MODE;
+ config.audio_input_format.i2s_input_nb = 1;
+ config.audio_input_format.sample_audio_freq = AV8100_AUDIO_FREQ_48KHZ;
+ config.audio_input_format.audio_word_lg = AV8100_AUDIO_16BITS;
+ config.audio_input_format.audio_format = AV8100_AUDIO_LPCM_MODE;
+ config.audio_input_format.audio_if_mode = AV8100_AUDIO_MASTER;
+ config.audio_input_format.audio_mute = AV8100_AUDIO_MUTE_DISABLE;
+ ret = av8100_conf_prep(AV8100_COMMAND_AUDIO_INPUT_FORMAT, &config);
+ if (ret != 0) {
+ pr_err("%s: Setting audio_input_format failed "
+ "(av8100_conf_prep returned %d)!\n",
+ __func__,
+ ret);
+ return -EINVAL;
+ }
+ if (av8100_conf_w(AV8100_COMMAND_AUDIO_INPUT_FORMAT,
+ NULL, NULL, I2C_INTERFACE) != 0) {
+ pr_err("%s: Setting audio_input_format failed "
+ "(av8100_conf_w returned %d)!\n",
+ __func__,
+ ret);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int av8100_codec_pcm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ pr_debug("%s: Enter.\n", __func__);
+
+ return 0;
+}
+
+static int av8100_codec_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params,
+ struct snd_soc_dai *dai)
+{
+ int ret;
+ int channels;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ channels = params_channels(hw_params);
+ switch (channels) {
+ case 1:
+ goto error_channels;
+ case 2:
+ ret = setupAV8100_stereo();
+ break;
+ case 6:
+ goto error_channels;
+ default:
+ goto error_channels;
+ }
+
+ return ret;
+
+error_channels:
+ pr_err("%s: Unsupported number of channels (%d)!\n", __func__, channels);
+
+ return -1;
+}
+
+static void av8100_codec_pcm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ pr_debug("%s: Enter.\n", __func__);
+}
+
+static int av8100_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id,
+ unsigned int freq, int dir)
+{
+ pr_debug("%s: Enter.\n", __func__);
+
+ return 0;
+}
+
+static int av8100_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ pr_debug("%s: Enter.\n", __func__);
+
+ return 0;
+}
+
+struct snd_soc_dai av8100_codec_dai[] = {
+ {
+ .name = "av8100_0",
+ .playback = {
+ .stream_name = "av8100_0",
+ .channels_min = 2,
+ .channels_max = 6,
+ .rates = AV8100_SUPPORTED_RATE,
+ .formats = AV8100_SUPPORTED_FMT,
+ },
+ .capture = {
+ .stream_name = "av8100_0",
+ .channels_min = 2,
+ .channels_max = 6,
+ .rates = AV8100_SUPPORTED_RATE,
+ .formats = AV8100_SUPPORTED_FMT,
+ },
+ .ops = (struct snd_soc_dai_ops[]) {
+ {
+ .prepare = av8100_codec_pcm_prepare,
+ .hw_params = av8100_codec_pcm_hw_params,
+ .shutdown = av8100_codec_pcm_shutdown,
+ .set_sysclk = av8100_codec_set_dai_sysclk,
+ .set_fmt = av8100_codec_set_dai_fmt,
+ }
+ },
+ }
+};
+EXPORT_SYMBOL_GPL(av8100_codec_dai);
+
+static unsigned int av8100_codec_read(struct snd_soc_codec *codec,
+ unsigned int ctl)
+{
+ pr_debug("%s: Enter.\n", __func__);
+
+ return 0;
+}
+
+static int av8100_codec_write(struct snd_soc_codec *codec,
+ unsigned int ctl,
+ unsigned int value)
+{
+ pr_debug("%s: Enter.\n", __func__);
+
+ return 0;
+}
+
+static int av8100_codec_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret;
+
+ pr_info("%s: Enter (pdev = %p).\n", __func__, pdev);
+
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (codec == NULL)
+ return -ENOMEM;
+ codec->name = "AV8100";
+ codec->owner = THIS_MODULE;
+ codec->dai = &av8100_codec_dai[0];
+ codec->num_dai = 1;
+ codec->read = av8100_codec_read;
+ codec->write = av8100_codec_write;
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ mutex_init(&codec->mutex);
+
+ socdev->card->codec = codec;
+
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ pr_err("%s: Error: to create new PCMs. error %d\n",
+ __func__,
+ ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ kfree(codec);
+ return ret;
+}
+
+static int av8100_codec_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ pr_debug("%s: Enter (pdev = %p).\n", __func__, pdev);
+
+ if (!codec)
+ return 0;
+
+ snd_soc_free_pcms(socdev);
+ kfree(socdev->card->codec);
+
+ return 0;
+}
+
+static int av8100_codec_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ pr_debug("%s: Enter (pdev = %p).\n", __func__, pdev);
+
+ return 0;
+}
+
+static int av8100_codec_resume(struct platform_device *pdev)
+{
+ pr_debug("%s: Enter (pdev = %p).\n", __func__, pdev);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_av8100 = {
+ .probe = av8100_codec_probe,
+ .remove = av8100_codec_remove,
+ .suspend = av8100_codec_suspend,
+ .resume = av8100_codec_resume
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_av8100);
+
+static int __devinit av8100_codec_init(void)
+{
+ int ret;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ pr_info("%s: Register codec-dai.\n", __func__);
+ ret = snd_soc_register_dai(&av8100_codec_dai[0]);
+ if (ret < 0) {
+ pr_debug("%s: Error: Failed to register codec-dai (ret = %d).\n",
+ __func__,
+ ret);
+ }
+
+ return ret;
+}
+
+static void av8100_codec_exit(void)
+{
+ pr_debug("%s: Enter.\n", __func__);
+
+ snd_soc_unregister_dai(&av8100_codec_dai[0]);
+}
+
+module_init(av8100_codec_init);
+module_exit(av8100_codec_exit);
+
+MODULE_DESCRIPTION("AV8100 ASoC codec driver");
+MODULE_AUTHOR("www.stericsson.com");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/av8100_audio.h b/sound/soc/codecs/av8100_audio.h
new file mode 100644
index 00000000000..6d2a7e7a801
--- /dev/null
+++ b/sound/soc/codecs/av8100_audio.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ola Lilja ola.o.lilja@stericsson.com,
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 AV8100_CODEC_H
+#define AV8100_CODEC_H
+
+extern struct snd_soc_dai av8100_codec_dai[];
+extern struct snd_soc_codec_device soc_codec_dev_av8100;
+
+#endif /* AV8100_CODEC_H */
+
+
+
diff --git a/sound/soc/codecs/cg29xx.c b/sound/soc/codecs/cg29xx.c
new file mode 100644
index 00000000000..a138f2c211a
--- /dev/null
+++ b/sound/soc/codecs/cg29xx.c
@@ -0,0 +1,778 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Roger Nilsson roger.xr.nilsson@stericsson.com
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+ #include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/bitops.h>
+#include <linux/mfd/cg2900_audio.h>
+
+#include "cg29xx.h"
+
+#define CG29XX_NBR_OF_DAI 2
+#define CG29XX_SUPPORTED_RATE_PCM (SNDRV_PCM_RATE_8000 | \
+ SNDRV_PCM_RATE_16000)
+
+#define CG29XX_SUPPORTED_RATE (SNDRV_PCM_RATE_8000 | \
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define CG29XX_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE)
+
+enum cg29xx_dai_direction {
+ CG29XX_DAI_DIRECTION_TX,
+ CG29XX_DAI_DIRECTION_RX
+};
+
+static int cg29xx_dai_startup(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+
+static int cg29xx_dai_prepare(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+
+static int cg29xx_dai_hw_params(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params,
+ struct snd_soc_dai *dai);
+
+static void cg29xx_dai_shutdown(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+
+static int cg29xx_set_dai_sysclk(
+ struct snd_soc_dai *codec_dai,
+ int clk_id,
+ unsigned int freq, int dir);
+
+static int cg29xx_set_dai_fmt(
+ struct snd_soc_dai *codec_dai,
+ unsigned int fmt);
+
+static int cg29xx_set_tdm_slot(
+ struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots,
+ int slot_width);
+
+static struct cg29xx_codec codec_private = {
+ .session = 0,
+};
+
+static struct snd_soc_codec *cg29xx_codec;
+
+static struct cg29xx_dai
+ cg29xx_dai_private[CG29XX_NBR_OF_DAI] = {
+ {
+ .tx_active = 0,
+ .rx_active = 0,
+ .input_select = 0,
+ .output_select = 0,
+ .config = {
+ .port = PORT_0_I2S,
+ .conf.i2s.mode = DAI_MODE_SLAVE,
+ .conf.i2s.half_period = HALF_PER_DUR_16,
+ .conf.i2s.channel_sel = CHANNEL_SELECTION_BOTH,
+ .conf.i2s.sample_rate = SAMPLE_RATE_48,
+ .conf.i2s.word_width = WORD_WIDTH_32
+ }
+ },
+ {
+ .tx_active = 0,
+ .rx_active = 0,
+ .input_select = 0,
+ .output_select = 0,
+ .config = {
+ .port = PORT_1_I2S_PCM,
+ .conf.i2s_pcm.mode = DAI_MODE_SLAVE,
+ .conf.i2s_pcm.slot_0_dir = DAI_DIR_B_RX_A_TX,
+ .conf.i2s_pcm.slot_1_dir = DAI_DIR_B_TX_A_RX,
+ .conf.i2s_pcm.slot_2_dir = DAI_DIR_B_RX_A_TX,
+ .conf.i2s_pcm.slot_3_dir = DAI_DIR_B_RX_A_TX,
+ .conf.i2s_pcm.slot_0_used = true,
+ .conf.i2s_pcm.slot_1_used = false,
+ .conf.i2s_pcm.slot_2_used = false,
+ .conf.i2s_pcm.slot_3_used = false,
+ .conf.i2s_pcm.slot_0_start = 0,
+ .conf.i2s_pcm.slot_1_start = 16,
+ .conf.i2s_pcm.slot_2_start = 32,
+ .conf.i2s_pcm.slot_3_start = 48,
+ .conf.i2s_pcm.protocol = PORT_PROTOCOL_PCM,
+ .conf.i2s_pcm.ratio = STREAM_RATIO_FM48_VOICE16,
+ .conf.i2s_pcm.duration = SYNC_DURATION_32,
+ .conf.i2s_pcm.clk = BIT_CLK_512,
+ .conf.i2s_pcm.sample_rate = SAMPLE_RATE_16,
+ }
+ },
+};
+
+static struct snd_soc_dai_ops cg29xx_dai_ops = {
+ .startup = cg29xx_dai_startup,
+ .prepare = cg29xx_dai_prepare,
+ .hw_params = cg29xx_dai_hw_params,
+ .shutdown = cg29xx_dai_shutdown,
+ .set_sysclk = cg29xx_set_dai_sysclk,
+ .set_fmt = cg29xx_set_dai_fmt,
+ .set_tdm_slot = cg29xx_set_tdm_slot
+};
+
+struct snd_soc_dai cg29xx_codec_dai[] = {
+ {
+ .name = "cg29xx_0",
+ .id = 0,
+ .playback = {
+ .stream_name = "cg29xx_0_pb",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = CG29XX_SUPPORTED_RATE,
+ .formats = CG29XX_SUPPORTED_FMT,
+ },
+ .capture = {
+ .stream_name = "cg29xx_0_cap",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = CG29XX_SUPPORTED_RATE,
+ .formats = CG29XX_SUPPORTED_FMT,
+ },
+ .ops = &cg29xx_dai_ops,
+ .symmetric_rates = 1,
+ .private_data = &cg29xx_dai_private[0]
+ },
+ {
+ .name = "cg29xx_1",
+ .id = 1,
+ .playback = {
+ .stream_name = "cg29xx_1_pb",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = CG29XX_SUPPORTED_RATE_PCM,
+ .formats = CG29XX_SUPPORTED_FMT,
+ },
+ .capture = {
+ .stream_name = "cg29xx_1_cap",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = CG29XX_SUPPORTED_RATE_PCM,
+ .formats = CG29XX_SUPPORTED_FMT,
+ },
+ .ops = &cg29xx_dai_ops,
+ .symmetric_rates = 1,
+ .private_data = &cg29xx_dai_private[1]
+ }
+};
+EXPORT_SYMBOL_GPL(cg29xx_codec_dai);
+
+static const char *enum_ifs_input_select[] = {
+ "BT_SCO", "FM_RX"
+};
+
+static const char *enum_ifs_output_select[] = {
+ "BT_SCO", "FM_TX"
+};
+
+/* If0 Input Select */
+static struct soc_enum if0_input_select =
+ SOC_ENUM_SINGLE(INTERFACE0_INPUT_SELECT, 0,
+ ARRAY_SIZE(enum_ifs_input_select),
+ enum_ifs_input_select);
+
+/* If1 Input Select */
+static struct soc_enum if1_input_select =
+ SOC_ENUM_SINGLE(INTERFACE1_INPUT_SELECT, 0,
+ ARRAY_SIZE(enum_ifs_input_select),
+ enum_ifs_input_select);
+
+/* If0 Output Select */
+static struct soc_enum if0_output_select =
+ SOC_ENUM_SINGLE(INTERFACE0_OUTPUT_SELECT, 0,
+ ARRAY_SIZE(enum_ifs_output_select),
+ enum_ifs_output_select);
+
+/* If1 Output Select */
+static struct soc_enum if1_output_select =
+ SOC_ENUM_SINGLE(INTERFACE1_OUTPUT_SELECT, 4,
+ ARRAY_SIZE(enum_ifs_output_select),
+ enum_ifs_output_select);
+
+static struct snd_kcontrol_new cg29xx_snd_controls[] = {
+ SOC_ENUM("If0 Input Select", if0_input_select),
+ SOC_ENUM("If1 Input Select", if1_input_select),
+ SOC_ENUM("If0 Output Select", if0_output_select),
+ SOC_ENUM("If1 Output Select", if1_output_select),
+};
+
+static int cg29xx_set_dai_sysclk(
+ struct snd_soc_dai *codec_dai,
+ int clk_id,
+ unsigned int freq, int dir)
+{
+ return 0;
+}
+
+static int cg29xx_set_dai_fmt(
+ struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct cg29xx_dai *private =
+ codec_dai->private_data;
+ unsigned int prot;
+ unsigned int msel;
+
+ prot = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ msel = fmt & SND_SOC_DAIFMT_MASTER_MASK;
+
+ switch (prot) {
+ case SND_SOC_DAIFMT_I2S:
+ if (private->config.port != PORT_0_I2S) {
+ pr_err("cg29xx_dai: unsupported DAI format 0x%x\n",
+ fmt);
+ return -EINVAL;
+ }
+
+ if (msel == SND_SOC_DAIFMT_CBM_CFM)
+ private->config.conf.i2s.mode = DAI_MODE_MASTER;
+ else
+ private->config.conf.i2s.mode = DAI_MODE_SLAVE;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_A:
+ if (private->config.port != PORT_1_I2S_PCM ||
+ msel == SND_SOC_DAIFMT_CBM_CFM) {
+ pr_err("cg29xx_dai: unsupported DAI format 0x%x\n",
+ fmt);
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cg29xx_set_tdm_slot(
+ struct snd_soc_dai *dai,
+ unsigned int tx_mask,
+ unsigned int rx_mask,
+ int slots,
+ int slot_width)
+{
+ struct cg29xx_dai *private =
+ dai->private_data;
+
+ if (private->config.port != PORT_1_I2S_PCM)
+ return -EINVAL;
+
+ private->config.conf.i2s_pcm.slot_0_used =
+ (tx_mask | rx_mask) & (1<<CG29XX_DAI_SLOT0_SHIFT) ?
+ true : false;
+ private->config.conf.i2s_pcm.slot_1_used =
+ (tx_mask | rx_mask) & (1<<CG29XX_DAI_SLOT1_SHIFT) ?
+ true : false;
+ private->config.conf.i2s_pcm.slot_2_used =
+ (tx_mask | rx_mask) & (1<<CG29XX_DAI_SLOT2_SHIFT) ?
+ true : false;
+ private->config.conf.i2s_pcm.slot_3_used =
+ (tx_mask | rx_mask) & (1<<CG29XX_DAI_SLOT3_SHIFT) ?
+ true : false;
+
+ private->config.conf.i2s_pcm.slot_0_start = 0;
+ private->config.conf.i2s_pcm.slot_1_start = slot_width;
+ private->config.conf.i2s_pcm.slot_2_start = 2 * slot_width;
+ private->config.conf.i2s_pcm.slot_3_start = 3 * slot_width;
+
+ return 0;
+}
+
+static int cg29xx_configure_endp(
+ struct cg29xx_dai *dai,
+ enum cg2900_audio_endpoint_id endpid)
+{
+ struct cg2900_endpoint_config config;
+ int err;
+ enum cg2900_dai_sample_rate dai_sr;
+ enum cg2900_endpoint_sample_rate endp_sr;
+
+ switch (dai->config.port) {
+ default:
+ case PORT_0_I2S:
+ dai_sr = dai->config.conf.i2s.sample_rate;
+ break;
+
+ case PORT_1_I2S_PCM:
+ dai_sr = dai->config.conf.i2s_pcm.sample_rate;
+ break;
+ }
+
+ switch (dai_sr) {
+ default:
+ case SAMPLE_RATE_8:
+ endp_sr = ENDPOINT_SAMPLE_RATE_8_KHZ;
+ break;
+ case SAMPLE_RATE_16:
+ endp_sr = ENDPOINT_SAMPLE_RATE_16_KHZ;
+ break;
+ case SAMPLE_RATE_44_1:
+ endp_sr = ENDPOINT_SAMPLE_RATE_44_1_KHZ;
+ break;
+ case SAMPLE_RATE_48:
+ endp_sr = ENDPOINT_SAMPLE_RATE_48_KHZ;
+ break;
+ }
+
+ config.endpoint_id = endpid;
+
+ switch (endpid) {
+ default:
+ case ENDPOINT_BT_SCO_INOUT:
+ config.config.sco.sample_rate = endp_sr;
+ break;
+
+ case ENDPOINT_FM_TX:
+ case ENDPOINT_FM_RX:
+ config.config.fm.sample_rate = endp_sr;
+ break;
+ }
+
+ err = cg2900_audio_config_endpoint(codec_private.session, &config);
+
+ return err;
+}
+
+static int cg29xx_stop_if(
+ struct cg29xx_dai *dai,
+ enum cg29xx_dai_direction direction)
+{
+ int err = 0;
+ unsigned int *stream;
+
+ if (direction == CG29XX_DAI_DIRECTION_TX)
+ stream = &dai->tx_active;
+ else
+ stream = &dai->rx_active;
+
+ if (*stream) {
+ err = cg2900_audio_stop_stream(
+ codec_private.session,
+ *stream);
+ if (!err) {
+ *stream = 0;
+ } else {
+ pr_err("asoc cg29xx - %s - Failed to stop stream on interface %d.\n",
+ __func__,
+ dai->config.port);
+ }
+ }
+
+ return err;
+}
+
+static int cg29xx_start_if(
+ struct cg29xx_dai *dai,
+ enum cg29xx_dai_direction direction)
+{
+ enum cg2900_audio_endpoint_id if_endpid;
+ enum cg2900_audio_endpoint_id endpid;
+ unsigned int *stream;
+ int err;
+
+ if (dai->config.port == PORT_0_I2S)
+ if_endpid = ENDPOINT_PORT_0_I2S;
+ else
+ if_endpid = ENDPOINT_PORT_1_I2S_PCM;
+
+ if (direction == CG29XX_DAI_DIRECTION_RX) {
+ switch (dai->output_select) {
+ default:
+ case 0:
+ endpid = ENDPOINT_BT_SCO_INOUT;
+ break;
+ case 1:
+ endpid = ENDPOINT_FM_TX;
+ }
+ stream = &dai->rx_active;
+ } else {
+ switch (dai->input_select) {
+ default:
+ case 0:
+ endpid = ENDPOINT_BT_SCO_INOUT;
+ break;
+ case 1:
+ endpid = ENDPOINT_FM_RX;
+ }
+
+ stream = &dai->tx_active;
+ }
+
+ if (*stream) {
+ pr_debug("asoc cg29xx - %s - The interface has already been started.\n",
+ __func__);
+ return 0;
+ }
+
+ pr_debug("asoc cg29xx - %s - direction: %d, if_id: %d endpid: %d\n",
+ __func__,
+ direction,
+ if_endpid,
+ endpid);
+
+ err = cg29xx_configure_endp(dai, endpid);
+
+ if (err) {
+ pr_err("asoc cg29xx - %s - Configure endpoint id: %d failed.\n",
+ __func__,
+ endpid);
+
+ return err;
+ }
+
+ err = cg2900_audio_start_stream(
+ codec_private.session,
+ if_endpid,
+ endpid,
+ stream);
+
+ return err;
+}
+
+static int cg29xx_dai_startup(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int err = 0;
+
+ if (!codec_private.session)
+ err = cg2900_audio_open(&codec_private.session);
+
+ return err;
+}
+
+static int cg29xx_dai_prepare(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int err = 0;
+ enum cg29xx_dai_direction direction;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ direction = CG29XX_DAI_DIRECTION_RX;
+ else
+ direction = CG29XX_DAI_DIRECTION_TX;
+
+ err = cg29xx_start_if(dai->private_data, direction);
+
+ return err;
+}
+
+static void cg29xx_dai_shutdown(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ enum cg29xx_dai_direction direction;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ direction = CG29XX_DAI_DIRECTION_RX;
+ else
+ direction = CG29XX_DAI_DIRECTION_TX;
+
+ (void) cg29xx_stop_if(dai->private_data, direction);
+}
+
+static int cg29xx_dai_hw_params(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params,
+ struct snd_soc_dai *dai)
+{
+ struct cg29xx_dai *private = dai->private_data;
+ enum cg2900_dai_fs_duration duration = SYNC_DURATION_32;
+ enum cg2900_dai_bit_clk bclk = BIT_CLK_512;
+ int sr;
+ int err = 0;
+ enum cg2900_dai_stream_ratio ratio = STREAM_RATIO_FM48_VOICE16;
+
+ pr_debug("cg29xx asoc - %s called. Port: %d.\n",
+ __func__,
+ private->config.port);
+
+ switch (params_rate(hw_params)) {
+ case 8000:
+ sr = SAMPLE_RATE_8;
+ bclk = BIT_CLK_512;
+ duration = SYNC_DURATION_32;
+ ratio = STREAM_RATIO_FM48_VOICE8;
+ break;
+ case 16000:
+ sr = SAMPLE_RATE_16;
+ bclk = BIT_CLK_512;
+ duration = SYNC_DURATION_32;
+ ratio = STREAM_RATIO_FM48_VOICE16;
+ break;
+ case 44100:
+ sr = SAMPLE_RATE_44_1;
+ break;
+ case 48000:
+ sr = SAMPLE_RATE_48;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (private->config.port == PORT_0_I2S) {
+ private->config.conf.i2s.sample_rate = sr;
+ } else {
+ private->config.conf.i2s_pcm.sample_rate = sr;
+ private->config.conf.i2s_pcm.duration = duration;
+ private->config.conf.i2s_pcm.clk = bclk;
+ private->config.conf.i2s_pcm.ratio = ratio;
+ }
+
+ if (!(private->tx_active | private->rx_active)) {
+ err = cg2900_audio_set_dai_config(
+ codec_private.session,
+ &private->config);
+
+ pr_debug("asoc cg29xx: cg2900_audio_set_dai_config"
+ "on port %d completed with result: %d.\n",
+ private->config.port,
+ err);
+ }
+
+ return err;
+}
+
+static unsigned int cg29xx_codec_read(
+ struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+
+ switch (reg) {
+
+ case INTERFACE0_INPUT_SELECT:
+ return cg29xx_dai_private[0].input_select;
+
+ case INTERFACE1_INPUT_SELECT:
+ return cg29xx_dai_private[1].input_select;
+
+ case INTERFACE0_OUTPUT_SELECT:
+ return cg29xx_dai_private[0].output_select;
+
+ case INTERFACE1_OUTPUT_SELECT:
+ return cg29xx_dai_private[1].output_select;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int cg29xx_codec_write(
+ struct snd_soc_codec *codec,
+ unsigned int reg,
+ unsigned int value)
+{
+ int old_value;
+ struct cg29xx_dai *dai;
+ enum cg29xx_dai_direction direction;
+ bool restart_if = false;
+
+ switch (reg) {
+
+ case INTERFACE0_INPUT_SELECT:
+ dai = &cg29xx_dai_private[0];
+ direction = CG29XX_DAI_DIRECTION_TX;
+
+ old_value = dai->input_select;
+ dai->input_select = value;
+
+ if ((old_value ^ value) && dai->tx_active)
+ restart_if = true;
+ break;
+
+ case INTERFACE1_INPUT_SELECT:
+ dai = &cg29xx_dai_private[1];
+ direction = CG29XX_DAI_DIRECTION_TX;
+
+ old_value = dai->input_select;
+ dai->input_select = value;
+
+ if ((old_value ^ value) && dai->tx_active)
+ restart_if = true;
+ break;
+
+ case INTERFACE0_OUTPUT_SELECT:
+ dai = &cg29xx_dai_private[0];
+ direction = CG29XX_DAI_DIRECTION_RX;
+
+ old_value = dai->output_select;
+ dai->output_select = value;
+
+ if ((old_value ^ value) && dai->rx_active)
+ restart_if = true;
+ break;
+
+ case INTERFACE1_OUTPUT_SELECT:
+ dai = &cg29xx_dai_private[1];
+ direction = CG29XX_DAI_DIRECTION_RX;
+
+ old_value = dai->output_select;
+ dai->output_select = value;
+
+ if ((old_value ^ value) && dai->rx_active)
+ restart_if = true;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (restart_if) {
+ (void) cg29xx_stop_if(dai, direction);
+ (void) cg29xx_start_if(dai, direction);
+ }
+
+ return 0;
+}
+
+static int cg29xx_soc_probe(struct platform_device *pdev)
+{
+ int err;
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ socdev->card->codec = cg29xx_codec;
+
+ err = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (err < 0) {
+ pr_err("cg29xx asoc - snd_soc_new_pcms failed with error: %d\n",
+ err);
+ goto err1;
+ }
+
+ snd_soc_add_controls(
+ cg29xx_codec,
+ cg29xx_snd_controls,
+ ARRAY_SIZE(cg29xx_snd_controls));
+
+ return 0;
+
+ snd_soc_free_pcms(socdev);
+err1:
+ return err;
+}
+
+static int cg29xx_soc_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+
+ return 0;
+}
+
+static int cg29xx_soc_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ return 0;
+}
+
+static int cg29xx_soc_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_cg29xx = {
+ .probe = cg29xx_soc_probe,
+ .remove = cg29xx_soc_remove,
+ .suspend = cg29xx_soc_suspend,
+ .resume = cg29xx_soc_resume
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_cg29xx);
+
+static int __init cg29xx_init(void)
+{
+ int err;
+ int i;
+
+ cg29xx_codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+
+ if (!cg29xx_codec)
+ return -ENOMEM;
+
+ cg29xx_codec->name = "CG29XX";
+ cg29xx_codec->owner = THIS_MODULE;
+ cg29xx_codec->dai = cg29xx_codec_dai;
+ cg29xx_codec->num_dai = CG29XX_NBR_OF_DAI;
+ cg29xx_codec->read = cg29xx_codec_read;
+ cg29xx_codec->write = cg29xx_codec_write;
+ INIT_LIST_HEAD(&cg29xx_codec->dapm_widgets);
+ INIT_LIST_HEAD(&cg29xx_codec->dapm_paths);
+ mutex_init(&cg29xx_codec->mutex);
+
+ err = snd_soc_register_codec(cg29xx_codec);
+
+ if (err) {
+ pr_err(
+ "asoc cg29xx - snd_soc_register_codec"
+ " failed with error: %d.\n",
+ err);
+
+ return err;
+ }
+
+ for (i = 0; i < CG29XX_NBR_OF_DAI; i++) {
+ mutex_init(&cg29xx_dai_private[i].mutex);
+
+ err = snd_soc_register_dai(&cg29xx_codec_dai[i]);
+
+ if (err) {
+ pr_err(
+ "asoc cg29xx - snd_soc_register_dai"
+ " failed with error: %d.\n",
+ err);
+ return err;
+ }
+ }
+
+ return err;
+}
+module_init(cg29xx_init);
+
+static void __exit cg29xx_exit(void)
+{
+ int i;
+
+ (void) cg2900_audio_close(&codec_private.session);
+
+ if (cg29xx_codec) {
+ snd_soc_unregister_codec(cg29xx_codec);
+ kfree(cg29xx_codec);
+ cg29xx_codec = NULL;
+ }
+
+ for (i = 0; i < CG29XX_NBR_OF_DAI; i++)
+ snd_soc_unregister_dai(&cg29xx_codec_dai[i]);
+}
+module_exit(cg29xx_exit);
+
+MODULE_DESCRIPTION("CG29xx codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/cg29xx.h b/sound/soc/codecs/cg29xx.h
new file mode 100644
index 00000000000..e7ced7f9e24
--- /dev/null
+++ b/sound/soc/codecs/cg29xx.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Roger Nilsson roger.xr.nilsson@stericsson.com
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 CG29XX_CODEC_H
+#define CG29XX_CODEC_H
+
+#include <linux/mfd/cg2900_audio.h>
+
+extern struct snd_soc_dai cg29xx_codec_dai[];
+extern struct snd_soc_codec_device soc_codec_dev_cg29xx;
+
+struct cg29xx_dai {
+ struct mutex mutex;
+ unsigned int rx_active;
+ unsigned int tx_active;
+ int input_select;
+ int output_select;
+ struct cg2900_dai_config config;
+};
+
+struct cg29xx_codec{
+ unsigned int session;
+};
+
+#define CG29XX_DAI_SLOT0_SHIFT 0
+#define CG29XX_DAI_SLOT1_SHIFT 1
+#define CG29XX_DAI_SLOT2_SHIFT 2
+#define CG29XX_DAI_SLOT3_SHIFT 3
+
+#define INTERFACE0_INPUT_SELECT 0x00
+#define INTERFACE1_INPUT_SELECT 0x01
+#define INTERFACE0_OUTPUT_SELECT 0x02
+#define INTERFACE1_OUTPUT_SELECT 0x03
+
+#endif /* CG29XX_CODEC_H */
diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig
new file mode 100644
index 00000000000..52944f6fa64
--- /dev/null
+++ b/sound/soc/ux500/Kconfig
@@ -0,0 +1,46 @@
+#
+# Ux500 SoC audio configuration
+#
+
+config SND_SOC_UX500
+ bool "SoC Audio support for Ux500 platform"
+ depends on SND_SOC && STM_I2S && STM_MSP_I2S
+ default n
+ help
+ Say Y if you want to add support for the codecs attached to
+ the I2S of the Ux500. You will also need
+ to select the audio codec to be supported in the driver.
+
+choice
+ prompt "Codec to be used in Ux500 ASoC driver"
+ depends on SND_SOC_UX500
+ default SND_SOC_CG29XX
+
+config SND_SOC_UX500_AB3550
+ bool "AB3550"
+ depends on AB3550_CORE
+ select SND_SOC_AB3550
+ help
+ Say Y if you want to use AB3550 codec (Petronella MSA).
+
+config SND_SOC_UX500_CG29XX
+ bool "CG29xx"
+ select SND_SOC_CG29XX
+ help
+ Say Y if you want to use CG29xx codec (Combo chip).
+
+config SND_SOC_UX500_AV8100
+ bool "AV8100"
+ depends on AV8100
+ select SND_SOC_AV8100
+ help
+ Say Y if you want to use AV8100 codec (HDMI chip).
+
+endchoice
+
+config SND_SOC_UX500_DEBUG
+ bool "Activate Ux500 platform debug-mode (pr_debug)"
+ depends on SND_SOC && STM_I2S && STM_MSP_I2S
+ default n
+ help
+ Say Y if you want to add debug level prints for Ux500 code-files.
diff --git a/sound/soc/ux500/Makefile b/sound/soc/ux500/Makefile
new file mode 100644
index 00000000000..9c594d025ad
--- /dev/null
+++ b/sound/soc/ux500/Makefile
@@ -0,0 +1,20 @@
+# Ux500 Platform Support
+
+ifdef CONFIG_SND_SOC_UX500_DEBUG
+CFLAGS_av8100_audio.o := -DDEBUG
+CFLAGS_ab3550.o := -DDEBUG
+CFLAGS_cg29xx.o := -DDEBUG
+CFLAGS_ux500_pcm.o := -DDEBUG
+CFLAGS_ux500_msp_dai.o := -DDEBUG
+CFLAGS_ux500_av8100.o := -DDEBUG
+endif
+
+snd-soc-ux500-objs := ux500_pcm.o ux500_msp_dai.o
+snd-soc-ux500-ab3550-objs := ux500_ab3550.o
+snd-soc-ux500-cg29xx-objs := ux500_cg29xx.o
+snd-soc-ux500-av8100-objs := ux500_av8100.o
+
+obj-$(CONFIG_SND_SOC_UX500) += snd-soc-ux500.o
+obj-$(CONFIG_SND_SOC_UX500_AB3550) += snd-soc-ux500-ab3550.o
+obj-$(CONFIG_SND_SOC_UX500_CG29XX) += snd-soc-ux500-cg29xx.o
+obj-$(CONFIG_SND_SOC_UX500_AV8100) += snd-soc-ux500-av8100.o
diff --git a/sound/soc/ux500/ux500_ab3550.c b/sound/soc/ux500/ux500_ab3550.c
new file mode 100644
index 00000000000..103e8b2cfb5
--- /dev/null
+++ b/sound/soc/ux500/ux500_ab3550.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ola Lilja ola.o.lilja@stericsson.com,
+ * Roger Nilsson roger.xr.nilsson@stericsson.com
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <sound/soc.h>
+
+#include "ux500_pcm.h"
+#include "ux500_msp_dai.h"
+#include "mach/hardware.h"
+#include "../codecs/ab3550.h"
+
+static struct platform_device *ux500_ab3550_platform_device;
+
+#define AB3550_DAI_FMT_I2S_M (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM)
+#define AB3550_DAI_FMT_I2S_S (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS)
+#define AB3550_DAI_FMT AB3550_DAI_FMT_I2S_S
+
+static int ux500_ab3550_startup(struct snd_pcm_substream *substream)
+{
+ dev_dbg(&ux500_ab3550_platform_device->dev,
+ "%s: Enter\n",
+ __func__);
+ return 0;
+}
+
+static void ux500_ab3550_shutdown(struct snd_pcm_substream *substream)
+{
+ dev_dbg(&ux500_ab3550_platform_device->dev,
+ "%s: Enter\n",
+ __func__);
+}
+
+static int ux500_ab3550_hw_params(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ifid, ret = 0;
+
+ dev_dbg(&ux500_ab3550_platform_device->dev,
+ "%s: Enter\n",
+ __func__);
+
+ dev_dbg(&ux500_ab3550_platform_device->dev,
+ "%s: substream->pcm->name = %s\n"
+ "substream->pcm->id = %s.\n"
+ "substream->name = %s.\n"
+ "substream->number = %d.\n",
+ __func__,
+ substream->pcm->name,
+ substream->pcm->id,
+ substream->name,
+ substream->number);
+
+ for (ifid = 0; ifid < ARRAY_SIZE(ab3550_codec_dai); ifid++) {
+ if (strcmp(codec_dai->name, ab3550_codec_dai[ifid].name) == 0)
+ break;
+ }
+
+ if (codec_dai->ops->set_fmt) {
+ ret = snd_soc_dai_set_fmt(codec_dai, AB3550_DAI_FMT);
+ if (ret < 0) {
+ dev_dbg(&ux500_ab3550_platform_device->dev,
+ "%s: snd_soc_dai_set_fmt failed with %d.\n",
+ __func__,
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, AB3550_DAI_FMT);
+
+ if (ret < 0) {
+ dev_dbg(&ux500_ab3550_platform_device->dev,
+ "%s: snd_soc_dai_set_fmt"
+ " failed with %d.\n", __func__, ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static struct snd_soc_ops ux500_ab3550_ops = {
+ .startup = ux500_ab3550_startup,
+ .shutdown = ux500_ab3550_shutdown,
+ .hw_params = ux500_ab3550_hw_params,
+};
+
+struct snd_soc_dai_link ux500_ab3550_dai_links[] = {
+ {
+ .name = "ab3550_0",
+ .stream_name = "ab3550_0",
+ .cpu_dai = &ux500_msp_dai[0],
+ .codec_dai = &ab3550_codec_dai[0],
+ .init = NULL,
+ .ops = &ux500_ab3550_ops,
+ },
+ {
+ .name = "ab3550_1",
+ .stream_name = "ab3550_1",
+ .cpu_dai = &ux500_msp_dai[1],
+ .codec_dai = &ab3550_codec_dai[1],
+ .init = NULL,
+ .ops = &ux500_ab3550_ops,
+ },
+};
+
+static struct snd_soc_card ux500_ab3550 = {
+ .name = "ab3550",
+ .probe = NULL,
+ .dai_link = ux500_ab3550_dai_links,
+ .num_links = ARRAY_SIZE(ux500_ab3550_dai_links),
+ .platform = &ux500_soc_platform,
+};
+
+struct snd_soc_device ux500_ab3550_drvdata = {
+ .card = &ux500_ab3550,
+ .codec_dev = &soc_codec_dev_ab3550,
+};
+
+static int __init mop500_ab3550_soc_init(void)
+{
+ int i;
+ int ret = 0;
+
+ pr_debug("%s: Enter\n",
+ __func__);
+ pr_debug("%s: Card name: %s\n",
+ __func__,
+ ux500_ab3550_drvdata.card->name);
+
+ for (i = 0; i < ARRAY_SIZE(ux500_ab3550_dai_links); i++) {
+ pr_debug("%s: DAI-link %d, name: %s\n",
+ __func__,
+ i,
+ ux500_ab3550_drvdata.card->dai_link[i].name);
+ pr_debug("%s: DAI-link %d, stream_name: %s\n",
+ __func__,
+ i,
+ ux500_ab3550_drvdata.card->dai_link[i].stream_name);
+ }
+
+ pr_debug("%s: Allocate platform device (%s)\n",
+ __func__,
+ ux500_ab3550_drvdata.card->name);
+ ux500_ab3550_platform_device = platform_device_alloc("soc-audio", -1);
+ if (!ux500_ab3550_platform_device)
+ return -ENOMEM;
+
+ dev_dbg(&ux500_ab3550_platform_device->dev,
+ "%s: Set platform drvdata (%s)\n",
+ __func__,
+ ux500_ab3550_drvdata.card->name);
+ platform_set_drvdata(
+ ux500_ab3550_platform_device,
+ &ux500_ab3550_drvdata);
+
+ dev_dbg(&ux500_ab3550_platform_device->dev,
+ "%s: Add platform device (%s)\n",
+ __func__,
+ ux500_ab3550_drvdata.card->name);
+ ux500_ab3550_drvdata.dev = &ux500_ab3550_platform_device->dev;
+
+ ret = platform_device_add(ux500_ab3550_platform_device);
+ if (ret) {
+ dev_dbg(&ux500_ab3550_platform_device->dev,
+ "%s: Error: Failed to add platform device (%s)\n",
+ __func__,
+ ux500_ab3550_drvdata.card->name);
+ platform_device_put(ux500_ab3550_platform_device);
+ }
+
+ return ret;
+}
+module_init(mop500_ab3550_soc_init);
+
+static void __exit mop500_ab3550_soc_exit(void)
+{
+ dev_dbg(&ux500_ab3550_platform_device->dev,
+ "%s: Enter.\n",
+ __func__);
+
+ dev_dbg(&ux500_ab3550_platform_device->dev,
+ "%s: Un-register platform device (%s)\n",
+ __func__,
+ ux500_ab3550_drvdata.card->name);
+ platform_device_unregister(ux500_ab3550_platform_device);
+}
+module_exit(mop500_ab3550_soc_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ux500/ux500_av8100.c b/sound/soc/ux500/ux500_av8100.c
new file mode 100644
index 00000000000..b6cced7f1e5
--- /dev/null
+++ b/sound/soc/ux500/ux500_av8100.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ola Lilja (ola.o.lilja@stericsson.com)
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <sound/soc.h>
+
+#include "ux500_pcm.h"
+#include "ux500_msp_dai.h"
+
+#include <linux/spi/spi.h>
+#include <sound/initval.h>
+
+#include "../codecs/av8100_audio.h"
+
+static struct platform_device *ux500_av8100_platform_device;
+
+static int ux500_av8100_hw_params(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret = 0;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ pr_debug("%s: substream->pcm->name = %s.\n", __func__, substream->pcm->name);
+ pr_debug("%s: substream->pcm->id = %s.\n", __func__, substream->pcm->id);
+ pr_debug("%s: substream->name = %s.\n", __func__, substream->name);
+ pr_debug("%s: substream->number = %d.\n", __func__, substream->number);
+
+ if (cpu_dai->ops->set_fmt) {
+ dev_dbg(&ux500_av8100_platform_device->dev,
+ "%s: Setting format on codec_dai: "
+ "SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM.",
+ __func__);
+ ret = snd_soc_dai_set_fmt(
+ codec_dai,
+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0) {
+ dev_dbg(&ux500_av8100_platform_device->dev,
+ "%s: snd_soc_dai_set_fmt failed with %d.\n",
+ __func__,
+ ret);
+ return ret;
+ }
+
+ dev_dbg(&ux500_av8100_platform_device->dev,
+ "%s: Setting format on cpu_dai: "
+ "SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM.",
+ __func__);
+ ret = snd_soc_dai_set_fmt(
+ cpu_dai,
+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0) {
+ dev_dbg(&ux500_av8100_platform_device->dev,
+ "%s: snd_soc_dai_set_fmt failed with %d.\n",
+ __func__,
+ ret);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+struct snd_soc_dai_link ux500_av8100_dai_links[] = {
+ {
+ .name = "hdmi",
+ .stream_name = "hdmi",
+ .cpu_dai = &ux500_msp_dai[2],
+ .codec_dai = &av8100_codec_dai[0],
+ .init = NULL,
+ .ops = (struct snd_soc_ops[]) {
+ {
+ .hw_params = ux500_av8100_hw_params,
+ }
+ }
+ },
+};
+
+static struct snd_soc_card ux500_av8100 = {
+ .name = "hdmi",
+ .probe = NULL,
+ .dai_link = ux500_av8100_dai_links,
+ .num_links = ARRAY_SIZE(ux500_av8100_dai_links),
+ .platform = &ux500_soc_platform,
+};
+
+struct snd_soc_device ux500_av8100_drvdata = {
+ .card = &ux500_av8100,
+ .codec_dev = &soc_codec_dev_av8100,
+};
+
+static int __init ux500_av8100_soc_init(void)
+{
+ int ret = 0;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ pr_info("%s: Card name: %s\n",
+ __func__,
+ ux500_av8100_drvdata.card->name);
+
+ pr_debug("%s: DAI-link 0, name: %s\n",
+ __func__,
+ ux500_av8100_drvdata.card->dai_link[0].name);
+ pr_debug("%s: DAI-link 0, stream_name: %s\n",
+ __func__,
+ ux500_av8100_drvdata.card->dai_link[0].stream_name);
+
+ pr_debug("%s: Allocate platform device (%s).\n",
+ __func__,
+ ux500_av8100_drvdata.card->name);
+ ux500_av8100_platform_device = platform_device_alloc("soc-audio", -1);
+ if (!ux500_av8100_platform_device)
+ return -ENOMEM;
+
+ pr_debug("%s: Set platform drvdata (%s).\n",
+ __func__,
+ ux500_av8100_drvdata.card->name);
+ platform_set_drvdata(
+ ux500_av8100_platform_device,
+ &ux500_av8100_drvdata);
+ ux500_av8100_drvdata.dev = &ux500_av8100_platform_device->dev;
+
+ pr_debug("%s: Add platform device (%s).\n",
+ __func__,
+ ux500_av8100_drvdata.card->name);
+ ret = platform_device_add(ux500_av8100_platform_device);
+ if (ret) {
+ pr_err("%s: Error: Failed to add platform device (%s).\n",
+ __func__,
+ ux500_av8100_drvdata.card->name);
+ platform_device_put(ux500_av8100_platform_device);
+ }
+
+ return ret;
+}
+
+static void __exit ux500_av8100_soc_exit(void)
+{
+ pr_debug("%s: Enter.\n", __func__);
+
+ pr_debug("%s: Unregister platform device (%s).\n",
+ __func__,
+ ux500_av8100_drvdata.card->name);
+ platform_device_unregister(ux500_av8100_platform_device);
+}
+
+module_init(ux500_av8100_soc_init);
+module_exit(ux500_av8100_soc_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ux500/ux500_cg29xx.c b/sound/soc/ux500/ux500_cg29xx.c
new file mode 100644
index 00000000000..0c74bbe4550
--- /dev/null
+++ b/sound/soc/ux500/ux500_cg29xx.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Roger Nilsson roger.xr.nilsson@stericsson.com
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <sound/soc.h>
+
+#include "ux500_pcm.h"
+#include "ux500_msp_dai.h"
+#include "../codecs/cg29xx.h"
+
+#define UX500_CG29XX_DAI_SLOT_WIDTH 16
+#define UX500_CG29XX_DAI_SLOTS 2
+#define UX500_CG29XX_DAI_ACTIVE_SLOTS 0x01
+
+static struct platform_device *ux500_cg29xx_platform_device;
+
+static int ux500_cg29xx_hw_params(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+
+ int err;
+
+ pr_debug("%s: substream->pcm->name = %s.\n"
+ "substream->pcm->id = %s.\n"
+ "substream->name = %s.\n"
+ "substream->number = %d.\n",
+ __func__,
+ substream->pcm->name,
+ substream->pcm->id,
+ substream->name,
+ substream->number);
+
+ err = snd_soc_dai_set_fmt(
+ codec_dai,
+ SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS);
+
+ if (err) {
+ pr_err("%s: snd_soc_dai_set_fmt(codec)"
+ " failed with %d.\n",
+ __func__,
+ err);
+ goto out_err;
+ }
+
+ err = snd_soc_dai_set_tdm_slot(
+ codec_dai,
+ 1 << CG29XX_DAI_SLOT0_SHIFT,
+ 1 << CG29XX_DAI_SLOT0_SHIFT,
+ UX500_CG29XX_DAI_SLOTS,
+ UX500_CG29XX_DAI_SLOT_WIDTH);
+
+ if (err) {
+ pr_err("%s: cg29xx_set_tdm_slot(codec)"
+ " failed with %d.\n",
+ __func__,
+ err);
+ goto out_err;
+ }
+
+ err = snd_soc_dai_set_fmt(
+ cpu_dai,
+ SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS |
+ SND_SOC_DAIFMT_NB_NF);
+
+ if (err) {
+ pr_err("%s: snd_soc_dai_set_fmt(dai)"
+ " failed with %d.\n",
+ __func__,
+ err);
+ goto out_err;
+ }
+
+ err = snd_soc_dai_set_tdm_slot(cpu_dai,
+ UX500_CG29XX_DAI_ACTIVE_SLOTS,
+ UX500_CG29XX_DAI_ACTIVE_SLOTS,
+ UX500_CG29XX_DAI_SLOTS,
+ UX500_CG29XX_DAI_SLOT_WIDTH);
+
+ if (err) {
+ pr_err("%s: cg29xx_set_tdm_slot(dai)"
+ " failed with %d.\n",
+ __func__,
+ err);
+ goto out_err;
+ }
+
+out_err:
+ return err;
+}
+
+static struct snd_soc_ops ux500_cg29xx_ops = {
+ .hw_params = ux500_cg29xx_hw_params,
+};
+
+struct snd_soc_dai_link ux500_cg29xx_dai_links[] = {
+ {
+ .name = "cg29xx_0",
+ .stream_name = "cg29xx_0",
+ .cpu_dai = &ux500_msp_dai[0],
+ .codec_dai = &cg29xx_codec_dai[1],
+ .init = NULL,
+ .ops = &ux500_cg29xx_ops,
+ },
+};
+
+static struct snd_soc_card ux500_cg29xx = {
+ .name = "cg29xx",
+ .probe = NULL,
+ .dai_link = ux500_cg29xx_dai_links,
+ .num_links = ARRAY_SIZE(ux500_cg29xx_dai_links),
+ .platform = &ux500_soc_platform,
+};
+
+struct snd_soc_device ux500_cg29xx_drvdata = {
+ .card = &ux500_cg29xx,
+ .codec_dev = &soc_codec_dev_cg29xx,
+};
+
+static int __init ux500_cg29xx_soc_init(void)
+{
+ int err;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ux500_cg29xx_dai_links); i++) {
+ pr_debug("%s: DAI-link %d, name: %s\n",
+ __func__,
+ i,
+ ux500_cg29xx_drvdata.card->dai_link[i].name);
+ }
+
+ ux500_cg29xx_platform_device =
+ platform_device_alloc("soc-audio", -1);
+ if (!ux500_cg29xx_platform_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(
+ ux500_cg29xx_platform_device,
+ &ux500_cg29xx_drvdata);
+
+ ux500_cg29xx_drvdata.dev = &ux500_cg29xx_platform_device->dev;
+
+ err = platform_device_add(ux500_cg29xx_platform_device);
+ if (err) {
+ pr_err("%s: Error: Failed to add platform device (%s).\n",
+ __func__,
+ ux500_cg29xx_drvdata.card->name);
+ platform_device_put(ux500_cg29xx_platform_device);
+ }
+
+ return err;
+}
+module_init(ux500_cg29xx_soc_init);
+
+static void __exit ux500_cg29xx_soc_exit(void)
+{
+ platform_device_unregister(ux500_cg29xx_platform_device);
+}
+module_exit(ux500_cg29xx_soc_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
new file mode 100644
index 00000000000..36836918a36
--- /dev/null
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -0,0 +1,961 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ola Lilja (ola.o.lilja@stericsson.com),
+ * Roger Nilsson (roger.xr.nilsson@stericsson.com)
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <asm/dma.h>
+#include "ux500_msp_dai.h"
+#include "ux500_pcm.h"
+
+#include <mach/msp.h>
+#include <linux/i2s/i2s.h>
+#include <linux/bitops.h>
+
+static struct ux500_msp_dai_private ux500_msp_dai_private[UX500_NBR_OF_DAI] = {
+ {
+ .lock = __SPIN_LOCK_UNLOCKED(ux500_msp_dai_private[0].lock),
+ .i2s = NULL,
+ .fmt = 0,
+ .slots = 1,
+ .tx_mask = 0x01,
+ .rx_mask = 0x01,
+ .slot_width = 16,
+ },
+ {
+ .lock = __SPIN_LOCK_UNLOCKED(ux500_msp_dai_private[1].lock),
+ .i2s = NULL,
+ .fmt = 0,
+ .slots = 1,
+ .tx_mask = 0x01,
+ .rx_mask = 0x01,
+ .slot_width = 16,
+ },
+ {
+ .lock = __SPIN_LOCK_UNLOCKED(ux500_msp_dai_private[2].lock),
+ .i2s = NULL,
+ .fmt = 0,
+ .slots = 1,
+ .tx_mask = 0x01,
+ .rx_mask = 0x01,
+ .slot_width = 16,
+ },
+};
+
+static int ux500_msp_dai_i2s_probe(struct i2s_device *i2s)
+{
+ unsigned long flags;
+
+ pr_info("%s: Enter (chip_select = %d, i2s = %d).\n",
+ __func__,
+ (int)i2s->chip_select, (int)(i2s));
+
+ spin_lock_irqsave(
+ &ux500_msp_dai_private[i2s->chip_select].lock,
+ flags);
+ ux500_msp_dai_private[i2s->chip_select].i2s = i2s;
+ spin_unlock_irqrestore(
+ &ux500_msp_dai_private[i2s->chip_select].lock,
+ flags);
+ try_module_get(i2s->controller->dev.parent->driver->owner);
+ i2s_set_drvdata(
+ i2s,
+ (void *)&ux500_msp_dai_private[i2s->chip_select]);
+
+ return 0;
+}
+
+static int ux500_msp_dai_i2s_remove(struct i2s_device *i2s)
+{
+ unsigned long flags;
+ struct ux500_msp_dai_private *ux500_msp_dai_private =
+ i2s_get_drvdata(i2s);
+
+ pr_debug("%s: Enter (chip_select = %d).\n",
+ __func__,
+ (int)i2s->chip_select);
+
+ spin_lock_irqsave(&ux500_msp_dai_private->lock, flags);
+
+ ux500_msp_dai_private->i2s = NULL;
+ i2s_set_drvdata(i2s, NULL);
+ spin_unlock_irqrestore(
+ &ux500_msp_dai_private->lock,
+ flags);
+
+ pr_debug("%s: Calling module_put.\n",
+ __func__);
+ module_put(i2s->controller->dev.parent->driver->owner);
+
+ return 0;
+}
+
+static const struct i2s_device_id dev_id_table[] = {
+ { "i2s_device.0", 0, 0 },
+ { "i2s_device.1", 0, 0 },
+ { "i2s_device.2", 0, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2s, dev_id_table);
+
+static struct i2s_driver i2sdrv_i2s = {
+ .driver = {
+ .name = "ux500_asoc_i2s",
+ .owner = THIS_MODULE,
+ },
+ .probe = ux500_msp_dai_i2s_probe,
+ .remove = __devexit_p(ux500_msp_dai_i2s_remove),
+ .id_table = dev_id_table,
+};
+
+int ux500_msp_dai_i2s_send_data(void *data,
+ size_t bytes,
+ int dai_idx)
+{
+ unsigned long flags;
+ struct ux500_msp_dai_private *dai_private =
+ &ux500_msp_dai_private[dai_idx];
+ struct i2s_message message;
+ struct i2s_device *i2s_dev;
+ int ret = 0;
+
+ pr_debug("%s: Enter MSP Index:%d bytes = %d).\n",
+ __func__,
+ dai_idx,
+ (int)bytes);
+ spin_lock_irqsave(&dai_private->lock, flags);
+
+ i2s_dev = dai_private->i2s;
+
+ if (!ux500_msp_dai[dai_idx].playback.active) {
+ pr_err("%s: The I2S controller is not available."
+ "MSP index:%d\n",
+ __func__,
+ dai_idx);
+ spin_unlock_irqrestore(&dai_private->lock, flags);
+ return ret;
+ }
+
+ message.txbytes = bytes;
+ message.txdata = data;
+ message.rxbytes = 0;
+ message.rxdata = NULL;
+ message.dma_flag = 1;
+
+ spin_unlock_irqrestore(&dai_private->lock, flags);
+
+ ret = i2s_transfer(i2s_dev->controller, &message);
+ if (ret < 0) {
+ pr_err("%s: Error: i2s_transfer failed. MSP index: %d\n",
+ __func__,
+ dai_idx);
+ }
+
+ return ret;
+}
+
+int ux500_msp_dai_i2s_receive_data(void *data,
+ size_t bytes,
+ int dai_idx)
+{
+ unsigned long flags;
+ struct ux500_msp_dai_private *dai_private =
+ &ux500_msp_dai_private[dai_idx];
+ struct i2s_message message;
+ struct i2s_device *i2s_dev;
+ int ret = 0;
+
+ pr_debug("%s: Enter MSP Index: %d, bytes = %d).\n",
+ __func__,
+ dai_idx,
+ (int)bytes);
+
+ spin_lock_irqsave(&dai_private->lock, flags);
+
+ i2s_dev = dai_private->i2s;
+
+ if (!ux500_msp_dai[dai_idx].capture.active) {
+ pr_err("%s: The MSP controller is not available."
+ "MSP index: %d\n",
+ __func__,
+ dai_idx);
+ spin_unlock_irqrestore(&dai_private->lock, flags);
+ return ret;
+ }
+
+ message.rxbytes = bytes;
+ message.rxdata = data;
+ message.txbytes = 0;
+ message.txdata = NULL;
+ message.dma_flag = 1;
+
+ spin_unlock_irqrestore(&dai_private->lock, flags);
+
+ ret = i2s_transfer(i2s_dev->controller, &message);
+ if (ret < 0) {
+ pr_err("%s: Error: i2s_transfer failed. Msp index: %d\n",
+ __func__,
+ dai_idx);
+ }
+
+ return ret;
+}
+
+static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *msp_dai)
+{
+ struct ux500_msp_dai_private *dai_private = msp_dai->private_data;
+
+ pr_info("%s: Enter (stream = %s).\n",
+ __func__,
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "SNDRV_PCM_STREAM_PLAYBACK" : "SNDRV_PCM_STREAM_CAPTURE");
+ if (dai_private == NULL)
+ return;
+
+ pr_debug("%s: chip_select = %d.\n",
+ __func__,
+ (int)dai_private->i2s->chip_select);
+
+ if (i2s_cleanup(dai_private->i2s->controller,
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ DISABLE_TRANSMIT : DISABLE_RECEIVE)) {
+
+ pr_err("%s: Error closing i2s for %s.\n",
+ __func__,
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "playback" : "capture");
+ }
+ return;
+}
+
+static int ux500_msp_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *msp_dai)
+{
+ struct ux500_msp_dai_private *dai_private =
+ &ux500_msp_dai_private[msp_dai->id];
+
+ pr_info("%s: MSP Index: %d.\n",
+ __func__,
+ msp_dai->id);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ msp_dai->playback.active : msp_dai->capture.active) {
+ pr_err("%s: A %s stream is already active.\n",
+ __func__,
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "PLAYBACK" : "CAPTURE");
+ return -EBUSY;
+ }
+
+ msp_dai->private_data = dai_private;
+
+ if (dai_private->i2s == NULL) {
+ pr_err("%s: MSP index: %d"
+ "i2sdrv.i2s == NULL\n",
+ __func__,
+ msp_dai->id);
+ return -1;
+ }
+
+ if (dai_private->i2s->controller == NULL) {
+ pr_err("%s: MSP index: %d"
+ "i2sdrv.i2s->controller == NULL.\n",
+ __func__,
+ msp_dai->id);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void ux500_msp_dai_setup_multichannel(
+ struct ux500_msp_dai_private *private,
+ struct msp_config *msp_config)
+{
+ struct msp_multichannel_config *multi =
+ &msp_config->multichannel_config;
+
+ if (private->slots > 1) {
+ msp_config->multichannel_configured = 1;
+
+ multi->tx_multichannel_enable = true;
+ multi->rx_multichannel_enable = true;
+ multi->rx_comparison_enable_mode = MSP_COMPARISON_DISABLED;
+
+ multi->tx_channel_0_enable = private->tx_mask;
+ multi->tx_channel_1_enable = 0;
+ multi->tx_channel_2_enable = 0;
+ multi->tx_channel_3_enable = 0;
+
+ multi->rx_channel_0_enable = private->rx_mask;
+ multi->rx_channel_1_enable = 0;
+ multi->rx_channel_2_enable = 0;
+ multi->rx_channel_3_enable = 0;
+
+ pr_debug("%s: Multichannel enabled."
+ "Slots: %d TX: %u RX: %u\n",
+ __func__,
+ private->slots,
+ multi->tx_channel_0_enable,
+ multi->rx_channel_0_enable);
+ }
+}
+
+static void ux500_msp_dai_setup_frameper(
+ struct ux500_msp_dai_private *private,
+ unsigned int rate,
+ struct msp_protocol_desc *prot_desc)
+{
+ switch (private->slots) {
+ default:
+ case 1:
+ switch (rate) {
+ case 8000:
+ prot_desc->frame_period =
+ FRAME_PER_SINGLE_SLOT_8_KHZ;
+ break;
+ case 16000:
+ prot_desc->frame_period =
+ FRAME_PER_SINGLE_SLOT_16_KHZ;
+ break;
+ case 44100:
+ prot_desc->frame_period =
+ FRAME_PER_SINGLE_SLOT_44_1_KHZ;
+ break;
+ case 48000:
+ default:
+ prot_desc->frame_period =
+ FRAME_PER_SINGLE_SLOT_48_KHZ;
+ break;
+ }
+ break;
+
+ case 2:
+ prot_desc->frame_period = FRAME_PER_2_SLOTS;
+ break;
+
+ case 8:
+ prot_desc->frame_period =
+ FRAME_PER_8_SLOTS;
+ break;
+
+ case 16:
+ prot_desc->frame_period =
+ FRAME_PER_16_SLOTS;
+ break;
+ }
+
+ prot_desc->total_clocks_for_one_frame =
+ prot_desc->frame_period+1;
+
+ pr_debug("%s: Total clocks per frame: %u\n",
+ __func__,
+ prot_desc->total_clocks_for_one_frame);
+}
+
+static void ux500_msp_dai_setup_framing_pcm(
+ struct ux500_msp_dai_private *private,
+ unsigned int rate,
+ struct msp_protocol_desc *prot_desc)
+{
+ u32 frame_length = MSP_FRAME_LENGTH_1;
+ prot_desc->frame_width = 0;
+
+ switch (private->slots) {
+ default:
+ case 1:
+ frame_length = MSP_FRAME_LENGTH_1;
+ break;
+
+ case 2:
+ frame_length = MSP_FRAME_LENGTH_2;
+ break;
+
+ case 8:
+ frame_length = MSP_FRAME_LENGTH_8;
+ break;
+
+ case 16:
+ frame_length = MSP_FRAME_LENGTH_16;
+ break;
+ }
+
+ prot_desc->tx_frame_length_1 = frame_length;
+ prot_desc->rx_frame_length_1 = frame_length;
+ prot_desc->tx_frame_length_2 = frame_length;
+ prot_desc->rx_frame_length_2 = frame_length;
+
+ prot_desc->tx_element_length_1 = MSP_ELEM_LENGTH_16;
+ prot_desc->rx_element_length_1 = MSP_ELEM_LENGTH_16;
+ prot_desc->tx_element_length_2 = MSP_ELEM_LENGTH_16;
+ prot_desc->rx_element_length_2 = MSP_ELEM_LENGTH_16;
+
+ ux500_msp_dai_setup_frameper(private, rate, prot_desc);
+}
+
+static void ux500_msp_dai_setup_clocking(
+ unsigned int fmt,
+ struct msp_config *msp_config)
+{
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ default:
+ case SND_SOC_DAIFMT_NB_NF:
+ msp_config->tx_frame_sync_pol =
+ MSP_FRAME_SYNC_POL(MSP_FRAME_SYNC_POL_ACTIVE_HIGH);
+ msp_config->rx_frame_sync_pol =
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH << RFSPOL_SHIFT;
+ break;
+
+ case SND_SOC_DAIFMT_NB_IF:
+ msp_config->tx_frame_sync_pol =
+ MSP_FRAME_SYNC_POL(MSP_FRAME_SYNC_POL_ACTIVE_LOW);
+ msp_config->rx_frame_sync_pol =
+ MSP_FRAME_SYNC_POL_ACTIVE_LOW << RFSPOL_SHIFT;
+ break;
+ }
+
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) {
+ pr_debug("%s: Codec is MASTER.\n",
+ __func__);
+
+ msp_config->rx_frame_sync_sel = 0;
+ msp_config->tx_frame_sync_sel = 1 << TFSSEL_SHIFT;
+ msp_config->tx_clock_sel = 0;
+ msp_config->rx_clock_sel = 0;
+ msp_config->srg_clock_sel = 0x2 << SCKSEL_SHIFT;
+ } else {
+ pr_debug("%s: Codec is SLAVE.\n",
+ __func__);
+
+ msp_config->tx_clock_sel = TX_CLK_SEL_SRG;
+ msp_config->tx_frame_sync_sel = TX_SYNC_SRG_PROG;
+ msp_config->rx_clock_sel = RX_CLK_SEL_SRG;
+ msp_config->rx_frame_sync_sel = RX_SYNC_SRG;
+ msp_config->srg_clock_sel = 1 << SCKSEL_SHIFT;
+ }
+}
+
+static void ux500_msp_dai_compile_prot_desc_pcm(
+ unsigned int fmt,
+ struct msp_protocol_desc *prot_desc)
+{
+ prot_desc->rx_phase_mode = MSP_SINGLE_PHASE;
+ prot_desc->tx_phase_mode = MSP_SINGLE_PHASE;
+ prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE;
+ prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE;
+ prot_desc->rx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST;
+ prot_desc->tx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST;
+ prot_desc->rx_data_delay = MSP_DELAY_0;
+ prot_desc->tx_data_delay = MSP_DELAY_0;
+
+ if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A) {
+ pr_debug("%s: DSP_A.\n",
+ __func__);
+ prot_desc->tx_clock_pol = MSP_FALLING_EDGE;
+ prot_desc->rx_clock_pol = MSP_FALLING_EDGE;
+ } else {
+ pr_debug("%s: DSP_B.\n",
+ __func__);
+ prot_desc->tx_clock_pol = MSP_RISING_EDGE;
+ prot_desc->rx_clock_pol = MSP_RISING_EDGE;
+ }
+
+ prot_desc->rx_half_word_swap = MSP_HWS_NO_SWAP;
+ prot_desc->tx_half_word_swap = MSP_HWS_NO_SWAP;
+ prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR;
+ prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR;
+ prot_desc->spi_clk_mode = MSP_SPI_CLOCK_MODE_NON_SPI;
+ prot_desc->spi_burst_mode = MSP_SPI_BURST_MODE_DISABLE;
+ prot_desc->frame_sync_ignore = MSP_FRAME_SYNC_IGNORE;
+}
+
+static void ux500_msp_dai_compile_prot_desc_i2s(
+ struct msp_protocol_desc *prot_desc)
+{
+ prot_desc->rx_phase_mode = MSP_DUAL_PHASE;
+ prot_desc->tx_phase_mode = MSP_DUAL_PHASE;
+ prot_desc->rx_phase2_start_mode =
+ MSP_PHASE2_START_MODE_FRAME_SYNC;
+ prot_desc->tx_phase2_start_mode =
+ MSP_PHASE2_START_MODE_FRAME_SYNC;
+ prot_desc->rx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST;
+ prot_desc->tx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST;
+ prot_desc->rx_data_delay = MSP_DELAY_0;
+ prot_desc->tx_data_delay = MSP_DELAY_0;
+
+ prot_desc->rx_frame_length_1 = MSP_FRAME_LENGTH_1;
+ prot_desc->rx_frame_length_2 = MSP_FRAME_LENGTH_1;
+ prot_desc->tx_frame_length_1 = MSP_FRAME_LENGTH_1;
+ prot_desc->tx_frame_length_2 = MSP_FRAME_LENGTH_1;
+ prot_desc->rx_element_length_1 = MSP_ELEM_LENGTH_16;
+ prot_desc->rx_element_length_2 = MSP_ELEM_LENGTH_16;
+ prot_desc->tx_element_length_1 = MSP_ELEM_LENGTH_16;
+ prot_desc->tx_element_length_2 = MSP_ELEM_LENGTH_16;
+
+ prot_desc->rx_clock_pol = MSP_RISING_EDGE;
+ prot_desc->tx_clock_pol = MSP_RISING_EDGE;
+
+ prot_desc->tx_half_word_swap = MSP_HWS_NO_SWAP;
+ prot_desc->rx_half_word_swap = MSP_HWS_NO_SWAP;
+ prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR;
+ prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR;
+ prot_desc->spi_clk_mode = MSP_SPI_CLOCK_MODE_NON_SPI;
+ prot_desc->spi_burst_mode = MSP_SPI_BURST_MODE_DISABLE;
+ prot_desc->frame_sync_ignore = MSP_FRAME_SYNC_IGNORE;
+}
+
+static void ux500_msp_dai_compile_msp_config(
+ struct snd_pcm_substream *substream,
+ struct ux500_msp_dai_private *private,
+ unsigned int rate,
+ struct msp_config *msp_config)
+{
+ struct msp_protocol_desc *prot_desc = &msp_config->protocol_desc;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned int fmt = private->fmt;
+
+ memset(msp_config, 0, sizeof(*msp_config));
+
+ msp_config->input_clock_freq = UX500_MSP_INTERNAL_CLOCK_FREQ;
+ msp_config->tx_fifo_config = TX_FIFO_ENABLE;
+ msp_config->rx_fifo_config = RX_FIFO_ENABLE;
+ msp_config->spi_clk_mode = SPI_CLK_MODE_NORMAL;
+ msp_config->spi_burst_mode = 0;
+ msp_config->handler = ux500_pcm_dma_eot_handler;
+ msp_config->tx_callback_data =
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ substream : NULL;
+ msp_config->rx_callback_data =
+ substream->stream == SNDRV_PCM_STREAM_CAPTURE ?
+ substream : NULL;
+ msp_config->def_elem_len = 1;
+ msp_config->direction =
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ MSP_TRANSMIT_MODE : MSP_RECEIVE_MODE;
+ msp_config->data_size = MSP_DATA_BITS_32;
+ msp_config->work_mode = MSP_DMA_MODE;
+ msp_config->frame_freq = rate;
+
+ /* To avoid division by zero in I2S-driver (i2s_setup) */
+ prot_desc->total_clocks_for_one_frame = 1;
+
+ pr_debug("%s: rate: %u channels: %d.\n",
+ __func__,
+ rate,
+ runtime->channels);
+ switch (fmt &
+ (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
+
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+ pr_debug("%s: SND_SOC_DAIFMT_I2S.\n",
+ __func__);
+
+ msp_config->default_protocol_desc = 1;
+ msp_config->protocol = MSP_I2S_PROTOCOL;
+ break;
+
+ default:
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+ pr_debug("%s: SND_SOC_DAIFMT_I2S.\n",
+ __func__);
+
+ msp_config->data_size = MSP_DATA_BITS_16;
+ msp_config->protocol = MSP_I2S_PROTOCOL;
+
+ ux500_msp_dai_compile_prot_desc_i2s(prot_desc);
+ break;
+
+ case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
+ pr_debug("%s: PCM format.\n",
+ __func__);
+ msp_config->data_size = MSP_DATA_BITS_16;
+ msp_config->protocol = MSP_PCM_PROTOCOL;
+
+ ux500_msp_dai_compile_prot_desc_pcm(fmt, prot_desc);
+ ux500_msp_dai_setup_multichannel(private, msp_config);
+ ux500_msp_dai_setup_framing_pcm(private, rate, prot_desc);
+ break;
+ }
+
+ ux500_msp_dai_setup_clocking(fmt, msp_config);
+}
+
+static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *msp_dai)
+{
+ int ret = 0;
+ unsigned long flags_private;
+ struct ux500_msp_dai_private *dai_private = msp_dai->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msp_config msp_config;
+
+ pr_debug("%s: Enter (stream = %p - %s, chip_select = %d).\n",
+ __func__,
+ substream,
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "SNDRV_PCM_STREAM_PLAYBACK" : "SNDRV_PCM_STREAM_CAPTURE",
+ (int)dai_private->i2s->chip_select);
+
+ pr_debug("%s: Setting up dai with rate %u.\n",
+ __func__,
+ runtime->rate);
+ spin_lock_irqsave(&dai_private->lock, flags_private);
+ ux500_msp_dai_compile_msp_config(substream, dai_private,
+ runtime->rate, &msp_config);
+ spin_unlock_irqrestore(&dai_private->lock, flags_private);
+
+ ret = i2s_setup(dai_private->i2s->controller, &msp_config);
+ if (ret < 0) {
+ pr_err("u8500_msp_dai_prepare: i2s_setup failed! "
+ "ret = %d\n", ret);
+ goto cleanup;
+ }
+
+cleanup:
+ return ret;
+}
+
+static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *msp_dai)
+{
+ unsigned int mask, slots_active;
+ struct ux500_msp_dai_private *private = msp_dai->private_data;
+
+ pr_debug("%s: Enter stream: %s, MSP index: %d.\n",
+ __func__,
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "SNDRV_PCM_STREAM_PLAYBACK" :
+ "SNDRV_PCM_STREAM_CAPTURE",
+ (int)private->i2s->chip_select);
+
+ switch (private->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ if (params_channels(params) != 2) {
+ pr_err("%s: The I2S requires "
+ "that the channel count of the substream "
+ "is two. Substream channels: %d.\n",
+ __func__,
+ params_channels(params));
+ return -EINVAL;
+ }
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ case SND_SOC_DAIFMT_DSP_A:
+
+ mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ private->tx_mask :
+ private->rx_mask;
+
+ slots_active = hweight32(mask);
+
+ pr_debug("TDM slots active: %d", slots_active);
+
+ if (params_channels(params) != slots_active) {
+ pr_err("%s: The PCM format requires "
+ "that the channel count of the substream "
+ "matches the number of active slots.\n"
+ "Number of active slots: %d\n"
+ "Substream channels: %d.\n",
+ __func__,
+ slots_active,
+ params_channels(params));
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *msp_dai,
+ unsigned int fmt)
+{
+ struct ux500_msp_dai_private *dai_private =
+ msp_dai->private_data;
+
+ pr_debug("%s: MSP index: %d: Enter.\n",
+ __func__,
+ (int)dai_private->i2s->chip_select);
+
+ switch (fmt &
+ (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+ break;
+
+ default:
+ pr_err("Unsupported DAI format (0x%x)!\n",
+ fmt);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ case SND_SOC_DAIFMT_NB_IF:
+ break;
+
+ default:
+ pr_err("Unsupported DAI format (0x%x)!\n",
+ fmt);
+ return -EINVAL;
+ }
+
+ dai_private->fmt = fmt;
+ return 0;
+}
+
+static int ux500_msp_dai_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask,
+ unsigned int rx_mask,
+ int slots,
+ int slot_width)
+{
+ struct ux500_msp_dai_private *private =
+ dai->private_data;
+ unsigned int cap;
+
+ if (!(slots == 1 || slots == 2 || slots == 8 || slots == 16)) {
+ pr_err("%s - error: slots %d Supported values are 1/2/8/16.\n",
+ __func__,
+ slots);
+ return -EINVAL;
+ }
+ private->slots = slots;
+
+ if (!(slot_width == 16)) {
+ pr_err("%s - error: slot_width %d Supported value is 16.\n",
+ __func__,
+ slot_width);
+ return -EINVAL;
+ }
+ private->slot_width = slot_width;
+
+ switch (slots) {
+ default:
+ case 1:
+ cap = 0x01;
+ break;
+ case 2:
+ cap = 0x03;
+ break;
+ case 8:
+ cap = 0xFF;
+ break;
+ case 16:
+ cap = 0xFFFF;
+ break;
+ }
+
+ private->tx_mask = tx_mask & cap;
+ private->rx_mask = rx_mask & cap;
+
+ return 0;
+}
+
+static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd,
+ struct snd_soc_dai *msp_dai)
+{
+ unsigned long flags;
+ int ret = 0;
+ struct ux500_msp_dai_private *dai_private =
+ msp_dai->private_data;
+
+ pr_debug("%s: Enter (stream = %p - %s,"
+ " chip_select = %d, cmd = %d).\n",
+ __func__,
+ substream,
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "SNDRV_PCM_STREAM_PLAYBACK" :
+ "SNDRV_PCM_STREAM_CAPTURE",
+ (int)dai_private->i2s->chip_select,
+ cmd);
+
+ spin_lock_irqsave(&dai_private->lock, flags);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ ret = 0;
+ break;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ret = 0;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ ret = 0;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ spin_unlock_irqrestore(&dai_private->lock, flags);
+ return ret;
+}
+
+struct snd_soc_dai ux500_msp_dai[UX500_NBR_OF_DAI] = {
+ {
+ .name = "ux500_i2s-0",
+ .id = 0,
+ .suspend = NULL,
+ .resume = NULL,
+ .playback = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .capture = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .ops = (struct snd_soc_dai_ops[]) {
+ {
+ .set_sysclk = NULL,
+ .set_fmt = ux500_msp_dai_set_dai_fmt,
+ .set_tdm_slot = ux500_msp_dai_set_tdm_slot,
+ .startup = ux500_msp_dai_startup,
+ .shutdown = ux500_msp_dai_shutdown,
+ .prepare = ux500_msp_dai_prepare,
+ .trigger = ux500_msp_dai_trigger,
+ .hw_params = ux500_msp_dai_hw_params,
+ }
+ },
+ .private_data = &ux500_msp_dai_private[0],
+ },
+ {
+ .name = "ux500_i2s-1",
+ .id = 1,
+ .suspend = NULL,
+ .resume = NULL,
+ .playback = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .capture = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .ops = (struct snd_soc_dai_ops[]) {
+ {
+ .set_sysclk = NULL,
+ .set_fmt = ux500_msp_dai_set_dai_fmt,
+ .set_tdm_slot = ux500_msp_dai_set_tdm_slot,
+ .startup = ux500_msp_dai_startup,
+ .shutdown = ux500_msp_dai_shutdown,
+ .prepare = ux500_msp_dai_prepare,
+ .trigger = ux500_msp_dai_trigger,
+ .hw_params = ux500_msp_dai_hw_params,
+ }
+ },
+ .private_data = &ux500_msp_dai_private[1],
+ },
+ {
+ .name = "ux500_i2s-2",
+ .id = 2,
+ .suspend = NULL,
+ .resume = NULL,
+ .playback = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .capture = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .ops = (struct snd_soc_dai_ops[]) {
+ {
+ .set_sysclk = NULL,
+ .set_fmt = ux500_msp_dai_set_dai_fmt,
+ .set_tdm_slot = ux500_msp_dai_set_tdm_slot,
+ .startup = ux500_msp_dai_startup,
+ .shutdown = ux500_msp_dai_shutdown,
+ .prepare = ux500_msp_dai_prepare,
+ .trigger = ux500_msp_dai_trigger,
+ .hw_params = ux500_msp_dai_hw_params,
+ }
+ },
+ .private_data = &ux500_msp_dai_private[2],
+ },
+};
+EXPORT_SYMBOL(ux500_msp_dai);
+
+static int __init ux500_msp_dai_init(void)
+{
+ int i;
+ int ret = 0;
+
+ ret = i2s_register_driver(&i2sdrv_i2s);
+ if (ret < 0) {
+ pr_err("%s: Unable to register as a I2S driver.\n",
+ __func__);
+ return ret;
+ }
+
+ for (i = 0; i < UX500_NBR_OF_DAI; i++) {
+ pr_debug("%s: Register MSP dai %d.\n",
+ __func__,
+ i);
+ ret = snd_soc_register_dai(&ux500_msp_dai[i]);
+ if (ret < 0) {
+ pr_err("Error: Failed to register MSP dai %d.\n",
+ i);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static void __exit ux500_msp_dai_exit(void)
+{
+ int i;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ i2s_unregister_driver(&i2sdrv_i2s);
+
+ for (i = 0; i < UX500_NBR_OF_DAI; i++)
+ snd_soc_unregister_dai(&ux500_msp_dai[i]);
+}
+
+module_init(ux500_msp_dai_init);
+module_exit(ux500_msp_dai_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h
new file mode 100644
index 00000000000..0ad8b380318
--- /dev/null
+++ b/sound/soc/ux500/ux500_msp_dai.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ola Lilja ola.o.lilja@stericsson.com,
+ * Roger Nilsson roger.xr.nilsson@stericsson.com
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 UX500_msp_dai_H
+#define UX500_msp_dai_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/i2s/i2s.h>
+
+#define UX500_NBR_OF_DAI 3
+
+#define UX500_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define UX500_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+#define FRAME_PER_SINGLE_SLOT_8_KHZ 31
+#define FRAME_PER_SINGLE_SLOT_16_KHZ 124
+#define FRAME_PER_SINGLE_SLOT_44_1_KHZ 63
+#define FRAME_PER_SINGLE_SLOT_48_KHZ 49
+#define FRAME_PER_2_SLOTS 31
+#define FRAME_PER_8_SLOTS 138
+#define FRAME_PER_16_SLOTS 277
+
+#define UX500_MSP_INTERNAL_CLOCK_FREQ 40000000;
+#define UX500_MSP_MIN_CHANNELS 1
+#define UX500_MSP_MAX_CHANNELS 8
+
+struct ux500_msp_dai_private {
+ spinlock_t lock;
+ struct i2s_device *i2s;
+ unsigned int fmt;
+ unsigned int tx_mask;
+ unsigned int rx_mask;
+ int slots;
+ int slot_width;
+};
+
+extern struct snd_soc_dai ux500_msp_dai[UX500_NBR_OF_DAI];
+
+int ux500_msp_dai_i2s_send_data(void *data, size_t bytes, int dai_idx);
+int ux500_msp_dai_i2s_receive_data(void *data, size_t bytes, int dai_idx);
+
+#endif
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c
new file mode 100644
index 00000000000..6a5567e1445
--- /dev/null
+++ b/sound/soc/ux500/ux500_pcm.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ola Lilja (ola.o.lilja@stericsson.com),
+ * Roger Nilsson (roger.xr.nilsson@stericsson.com)
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <asm/page.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "ux500_pcm.h"
+#include "ux500_msp_dai.h"
+
+static struct snd_pcm_hardware ux500_pcm_hw_playback = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE |
+ SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_BE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = UX500_PLATFORM_MIN_RATE_PLAYBACK,
+ .rate_max = UX500_PLATFORM_MAX_RATE_PLAYBACK,
+ .channels_min = UX500_PLATFORM_MIN_CHANNELS,
+ .channels_max = UX500_PLATFORM_MAX_CHANNELS,
+ .buffer_bytes_max = UX500_PLATFORM_BUFFER_SIZE,
+ .period_bytes_min = UX500_PLATFORM_MIN_PERIOD_BYTES,
+ .period_bytes_max = PAGE_SIZE,
+ .periods_min = UX500_PLATFORM_BUFFER_SIZE / PAGE_SIZE,
+ .periods_max = UX500_PLATFORM_BUFFER_SIZE /
+ UX500_PLATFORM_MIN_PERIOD_BYTES
+};
+
+static struct snd_pcm_hardware ux500_pcm_hw_capture = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE |
+ SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_BE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = UX500_PLATFORM_MIN_RATE_CAPTURE,
+ .rate_max = UX500_PLATFORM_MAX_RATE_CAPTURE,
+ .channels_min = UX500_PLATFORM_MIN_CHANNELS,
+ .channels_max = UX500_PLATFORM_MAX_CHANNELS,
+ .buffer_bytes_max = UX500_PLATFORM_BUFFER_SIZE,
+ .period_bytes_min = UX500_PLATFORM_MIN_PERIOD_BYTES,
+ .period_bytes_max = PAGE_SIZE,
+ .periods_min = UX500_PLATFORM_BUFFER_SIZE / PAGE_SIZE,
+ .periods_max = UX500_PLATFORM_BUFFER_SIZE /
+ UX500_PLATFORM_MIN_PERIOD_BYTES
+};
+
+static void ux500_pcm_dma_enqueue(struct snd_pcm_substream *substream)
+{
+ unsigned int dma_size;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct ux500_pcm_private *private = substream->runtime->private_data;
+
+ pr_debug("%s: Enter MSP Index: %d.\n",
+ __func__,
+ private->msp_id);
+
+ dma_size = frames_to_bytes(runtime, runtime->period_size);
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ux500_msp_dai_i2s_send_data(
+ (void *)(runtime->dma_addr + private->offset),
+ dma_size,
+ private->msp_id);
+ } else{
+ ux500_msp_dai_i2s_receive_data(
+ (void *)(runtime->dma_addr + private->offset),
+ dma_size,
+ private->msp_id);
+ }
+
+ private->period++;
+ private->period %= runtime->periods;
+ private->offset =
+ frames_to_bytes(runtime, runtime->period_size) *
+ private->period;
+}
+
+static void ux500_pcm_dma_hw_free(struct device *dev,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_dma_buffer *buf = runtime->dma_buffer_p;
+
+ if (runtime->dma_area == NULL)
+ return;
+
+ if (buf != &substream->dma_buffer) {
+ dma_free_coherent(
+ buf->dev.dev,
+ buf->bytes,
+ buf->area,
+ buf->addr);
+ kfree(runtime->dma_buffer_p);
+ }
+
+ snd_pcm_set_runtime_buffer(substream, NULL);
+}
+
+void ux500_pcm_dma_eot_handler(void *data)
+{
+ struct snd_pcm_substream *substream = data;
+ struct snd_pcm_runtime *runtime;
+ struct ux500_pcm_private *private;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ if (substream) {
+ runtime = substream->runtime;
+ private = substream->runtime->private_data;
+
+ snd_pcm_period_elapsed(substream);
+
+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+ ux500_pcm_dma_enqueue(substream);
+ }
+}
+EXPORT_SYMBOL(ux500_pcm_dma_eot_handler);
+
+static int ux500_pcm_open(struct snd_pcm_substream *substream)
+{
+ int stream_id = substream->pstr->stream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct ux500_pcm_private *private;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ pr_info("%s: Enter\n", __func__);
+
+ private = kzalloc(sizeof(struct ux500_pcm_private), GFP_KERNEL);
+ if (private == NULL)
+ return -ENOMEM;
+
+ private->msp_id = rtd->dai->cpu_dai->id;
+ runtime->private_data = private;
+
+ pr_debug("%s: Setting HW-config\n", __func__);
+ runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ?
+ ux500_pcm_hw_playback : ux500_pcm_hw_capture;
+
+ return 0;
+}
+
+static int ux500_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct ux500_pcm_private *private = substream->runtime->private_data;
+
+ pr_info("%s: Enter\n", __func__);
+
+ kfree(private);
+
+ return 0;
+}
+
+static int ux500_pcm_hw_params(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_dma_buffer *buf = runtime->dma_buffer_p;
+ int ret = 0;
+ int size;
+
+ pr_info("%s: Enter\n", __func__);
+
+ size = params_buffer_bytes(hw_params);
+
+ if (buf) {
+ if (buf->bytes >= size)
+ goto out;
+ ux500_pcm_dma_hw_free(NULL, substream);
+ }
+
+ if (substream->dma_buffer.area != NULL &&
+ substream->dma_buffer.bytes >= size) {
+ buf = &substream->dma_buffer;
+ } else {
+ buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
+ if (!buf)
+ goto nomem;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = NULL;
+ buf->area = dma_alloc_coherent(
+ NULL,
+ size,
+ &buf->addr,
+ GFP_KERNEL);
+ buf->bytes = size;
+ buf->private_data = NULL;
+
+ if (!buf->area)
+ goto free;
+ }
+ snd_pcm_set_runtime_buffer(substream, buf);
+ ret = 1;
+ out:
+ runtime->dma_bytes = size;
+ return ret;
+
+ free:
+ kfree(buf);
+ nomem:
+ return -ENOMEM;
+}
+
+static int ux500_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ pr_debug("%s: Enter\n", __func__);
+
+ ux500_pcm_dma_hw_free(NULL, substream);
+
+ return 0;
+}
+
+static int ux500_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ pr_debug("%s: Enter\n", __func__);
+
+ return 0;
+}
+
+static int ux500_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int i;
+ struct ux500_pcm_private *private = substream->runtime->private_data;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ for (i = 0; i < UX500_PLATFORM_PERIODS_QUEUED_DMA; i++)
+ ux500_pcm_dma_enqueue(substream);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("%s: SNDRV_PCM_TRIGGER_STOP\n", __func__);
+ private->period = 0;
+ break;
+
+ default:
+ pr_err("%s: Invalid command in pcm trigger\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static snd_pcm_uframes_t ux500_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ unsigned int offset;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct ux500_pcm_private *private = substream->runtime->private_data;
+
+ pr_debug("%s: Enter\n", __func__);
+
+ offset = bytes_to_frames(runtime, private->offset);
+ if (offset < 0 || private->offset < 0)
+ pr_debug("%s: Offset=%i %i\n",
+ __func__,
+ offset,
+ private->offset);
+
+ return offset;
+}
+
+static int ux500_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ return dma_mmap_coherent(
+ NULL,
+ vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops ux500_pcm_ops = {
+ .open = ux500_pcm_open,
+ .close = ux500_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = ux500_pcm_hw_params,
+ .hw_free = ux500_pcm_hw_free,
+ .prepare = ux500_pcm_prepare,
+ .trigger = ux500_pcm_trigger,
+ .pointer = ux500_pcm_pointer,
+ .mmap = ux500_pcm_mmap
+};
+
+int ux500_pcm_new(struct snd_card *card,
+ struct snd_soc_dai *dai,
+ struct snd_pcm *pcm)
+{
+ pr_debug("%s: pcm = %d\n", __func__, (int)pcm);
+
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "UX500_PCM");
+
+ pr_debug("%s: pcm->name = %s.\n", __func__, pcm->name);
+
+ return 0;
+}
+
+static void ux500_pcm_free(struct snd_pcm *pcm)
+{
+ pr_debug("%s: Enter\n", __func__);
+}
+
+static int ux500_pcm_suspend(struct snd_soc_dai *dai)
+{
+ pr_debug("%s: Enter\n", __func__);
+
+ return 0;
+}
+
+static int ux500_pcm_resume(struct snd_soc_dai *dai)
+{
+ pr_debug("%s: Enter\n", __func__);
+
+ return 0;
+}
+
+struct snd_soc_platform ux500_soc_platform = {
+ .name = "ux500-audio",
+ .pcm_ops = &ux500_pcm_ops,
+ .pcm_new = ux500_pcm_new,
+ .pcm_free = ux500_pcm_free,
+ .suspend = ux500_pcm_suspend,
+ .resume = ux500_pcm_resume,
+};
+EXPORT_SYMBOL(ux500_soc_platform);
+
+static int __init ux500_pcm_init(void)
+{
+ int ret;
+
+ pr_debug("%s: Register platform.\n", __func__);
+ ret = snd_soc_register_platform(&ux500_soc_platform);
+ if (ret < 0)
+ pr_debug("%s: Error: Failed to register platform!\n",
+ __func__);
+
+ return 0;
+}
+
+static void __exit ux500_pcm_exit(void)
+{
+ snd_soc_unregister_platform(&ux500_soc_platform);
+}
+
+module_init(ux500_pcm_init);
+module_exit(ux500_pcm_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h
new file mode 100644
index 00000000000..80f050128c8
--- /dev/null
+++ b/sound/soc/ux500/ux500_pcm.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ola Lilja ola.o.lilja@stericsson.com,
+ * Roger Nilsson roger.xr.nilsson@stericsson.com
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 UX500_PCM_H
+#define UX500_PCM_H
+
+#include <mach/msp.h>
+
+#define UX500_PLATFORM_BUFFER_SIZE (64*1024)
+
+#define UX500_PLATFORM_MIN_RATE_PLAYBACK 8000
+#define UX500_PLATFORM_MAX_RATE_PLAYBACK 48000
+#define UX500_PLATFORM_MIN_RATE_CAPTURE 8000
+#define UX500_PLATFORM_MAX_RATE_CAPTURE 48000
+
+#define UX500_PLATFORM_MIN_CHANNELS 1
+#define UX500_PLATFORM_MAX_CHANNELS 8
+#define UX500_PLATFORM_MIN_PERIOD_BYTES 128
+
+#define UX500_PLATFORM_PERIODS_QUEUED_DMA 5
+
+extern struct snd_soc_platform ux500_soc_platform;
+
+struct ux500_pcm_private {
+ int msp_id;
+ int stream_id;
+ int period;
+ unsigned int offset;
+};
+
+void ux500_pcm_dma_eot_handler(void *data);
+
+#endif
diff --git a/sound/u8500_acodec_ab8500.c b/sound/u8500_acodec_ab8500.c
new file mode 100644
index 00000000000..2c1ae702b79
--- /dev/null
+++ b/sound/u8500_acodec_ab8500.c
@@ -0,0 +1,2522 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Deepak Karda
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+/*-----------------------------------------------------------------------------
+* Common Includes
+*---------------------------------------------------------------------------*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/soundcard.h>
+#include <linux/sound.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/i2s/i2s.h>
+#include <mach/msp.h>
+#include <linux/gpio.h>
+/*#include <mach/i2c.h>*/
+#include <mach/debug.h>
+#include <mach/u8500_acodec_ab8500.h>
+#include <mach/ab8500.h>
+
+#ifdef CONFIG_U8500_AB8500_CUT10
+#include <mach/ab8500_codec_v1_0.h>
+#endif
+#ifdef CONFIG_U8500_AB8500_ED
+#include <mach/ab8500_codec.h>
+#endif
+
+#define ELEMENT_SIZE 0
+#define FRAME_SIZE -1
+#define MSP_NUM 0
+
+/* Debugging stuff */
+
+#define ACODEC_NAME "DRIVER ACODEC"
+#define DRIVER_DEBUG CONFIG_STM_ACODEC_DEBUG /* enables/disables debug msgs */
+#define DRIVER_DEBUG_PFX ACODEC_NAME /* msg header represents this module */
+#define DRIVER_DBG KERN_ERR /* message level */
+#define NMDK_DEBUG CONFIG_STM_ACODEC_DEBUG
+extern struct driver_debug_st DBG_ST;
+
+#if NMDK_DEBUG > 0
+t_ab8500_codec_error dump_acodec_registers(void);
+t_ab8500_codec_error dump_msp_registers(void);
+#endif
+
+#ifdef CONFIG_U8500_ACODEC_DMA
+static void u8500_digital_lpbk_tx_dma_start(void);
+static void u8500_digital_lpbk_rx_dma_start(void);
+#endif
+
+int second_config;
+/*----------------------------------------------------------------------------
+* global declarations
+*---------------------------------------------------------------------------*/
+t_u8500_codec_system_context g_codec_system_context;
+
+int u8500_acodec_rates[MAX_NO_OF_RATES] = { 48000 };
+
+char *codec_dest_texts[NUMBER_OUTPUT_DEVICE] = {
+ "CODEC_DEST_HEADSET", "CODEC_DEST_EARPIECE", "CODEC_DEST_HANDSFREE",
+ "CODEC_DEST_VIBRATOR1", "CODEC_DEST_VIBRATOR2"
+};
+
+char *codec_in_texts[NUMBER_INPUT_DEVICE] = {
+ "CODEC_SRC_LINEIN", "CODEC_SRC_MICROPHONE_1A",
+ "CODEC_SRC_MICROPHONE_1B",
+ "CODEC_SRC_MICROPHONE_2", "CODEC_SRC_D_MICROPHONE_1",
+ "CODEC_SRC_D_MICROPHONE_2",
+ "CODEC_SRC_D_MICROPHONE_3", "CODEC_SRC_D_MICROPHONE_4",
+ "CODEC_SRC_D_MICROPHONE_5",
+ "CODEC_SRC_D_MICROPHONE_6", "CODEC_SRC_D_MICROPHONE_12",
+ "CODEC_SRC_D_MICROPHONE_34",
+ "CODEC_SRC_D_MICROPHONE_56"
+};
+
+char *lpbk_state_in_texts[NUMBER_LOOPBACK_STATE] = { "DISABLE", "ENABLE" };
+char *switch_state_in_texts[NUMBER_SWITCH_STATE] = { "DISABLE", "ENABLE" };
+char *power_state_in_texts[NUMBER_POWER_STATE] = { "DISABLE", "ENABLE" };
+char *tdm_mode_state_in_texts[NUMBER_POWER_STATE] = { "DISABLE", "ENABLE" };
+char *direct_rendering_state_in_texts[NUMBER_DIRECT_RENDERING_STATE] =
+ { "DISABLE", "ENABLE" };
+char *pcm_rendering_state_in_texts[NUMBER_PCM_RENDERING_STATE] =
+ { "DISABLE", "ENABLE", "PENDING" };
+
+EXPORT_SYMBOL(codec_dest_texts);
+EXPORT_SYMBOL(codec_in_texts);
+
+static void ab8500_codec_power_init(void);
+static int check_device_id();
+t_ab8500_codec_error perform_src_routing(t_ab8500_codec_src input_device);
+t_ab8500_codec_error
+ u8500_acodec_allocate_all_mono_slots
+ (t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line1);
+t_ab8500_codec_error
+ u8500_acodec_allocate_all_stereo_slots
+ (t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line1,
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line2);
+
+#if 0 //from Arnaud
+/* For Codec in Master mode for recording*/
+struct msp_protocol_desc protocol_desc_tdm_mode = {
+ MSP_DATA_TRANSFER_WIDTH_HALFWORD, /*rx_data_transfer_width */
+ MSP_DATA_TRANSFER_WIDTH_HALFWORD, /*tx_data_transfer_width */
+ MSP_SINGLE_PHASE, /*rx_phase_mode */
+ MSP_SINGLE_PHASE, /*tx_phase_mode */
+ MSP_PHASE2_START_MODE_IMEDIATE, /*rx_phase2_start_mode */
+ MSP_PHASE2_START_MODE_IMEDIATE, /*tx_phase2_start_mode */
+ MSP_BTF_MS_BIT_FIRST, /*rx_endianess */
+ MSP_BTF_MS_BIT_FIRST, /*tx_endianess */
+ MSP_FRAME_LENGTH_2, /*rx_frame_length_1 */
+ MSP_FRAME_LENGTH_2, /*rx_frame_length_2 */
+ MSP_FRAME_LENGTH_2, /*tx_frame_length_1 */
+ MSP_FRAME_LENGTH_2, /*tx_frame_length_2 */
+ MSP_ELEM_LENGTH_16, /*rx_element_length_1 */
+ MSP_ELEM_LENGTH_16, /*rx_element_length_2 */
+ MSP_ELEM_LENGTH_16, /*tx_element_length_1 */
+ MSP_ELEM_LENGTH_16, /*tx_element_length_2 */
+ MSP_DELAY_0, /*rx_data_delay */
+ MSP_DELAY_0, /*tx_data_delay */
+ MSP_FALLING_EDGE, /*rx_clock_pol */
+ MSP_RISING_EDGE, /*tx_clock_pol */
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, /*rx_msp_frame_pol */
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, /*tx_msp_frame_pol */
+ MSP_HWS_NO_SWAP, /*rx_half_word_swap */
+ MSP_HWS_NO_SWAP, /*tx_half_word_swap */
+ MSP_COMPRESS_MODE_LINEAR, /*compression_mode */
+ MSP_EXPAND_MODE_LINEAR, /*expansion_mode */
+ MSP_SPI_CLOCK_MODE_NON_SPI, /*spi_clk_mode */
+ MSP_SPI_BURST_MODE_DISABLE, /*spi_burst_mode */
+ 63, /*frame_period */
+ 31, /*frame_width */
+ 64, /*total_clocks_for_one_frame */
+};
+#endif
+
+#if 0 //from HCL
+/* For Codec in Master mode for recording*/
+struct msp_protocol_desc protocol_desc_tdm_mode = {
+ MSP_DATA_TRANSFER_WIDTH_WORD, /*rx_data_transfer_width */
+ MSP_DATA_TRANSFER_WIDTH_WORD, /*tx_data_transfer_width */
+ MSP_DUAL_PHASE, /*rx_phase_mode */
+ MSP_DUAL_PHASE, /*tx_phase_mode */
+ MSP_PHASE2_START_MODE_FRAME_SYNC, /*rx_phase2_start_mode */
+ MSP_PHASE2_START_MODE_FRAME_SYNC, /*tx_phase2_start_mode */
+ MSP_BTF_MS_BIT_FIRST, /*rx_endianess */
+ MSP_BTF_MS_BIT_FIRST, /*tx_endianess */
+ MSP_FRAME_LENGTH_1, /*rx_frame_length_1 */
+ MSP_FRAME_LENGTH_1, /*rx_frame_length_2 */
+ MSP_FRAME_LENGTH_1, /*tx_frame_length_1 */
+ MSP_FRAME_LENGTH_1, /*tx_frame_length_2 */
+ MSP_ELEM_LENGTH_16, /*rx_element_length_1 */
+ MSP_ELEM_LENGTH_16, /*rx_element_length_2 */
+ MSP_ELEM_LENGTH_16, /*tx_element_length_1 */
+ MSP_ELEM_LENGTH_16, /*tx_element_length_2 */
+ MSP_DELAY_0, /*rx_data_delay */
+ MSP_DELAY_0, /*tx_data_delay */
+ MSP_RISING_EDGE, /*rx_clock_pol */
+ MSP_RISING_EDGE, /*tx_clock_pol */
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, /*rx_msp_frame_pol */
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, /*tx_msp_frame_pol */
+ MSP_HWS_NO_SWAP, /*rx_half_word_swap */
+ MSP_HWS_NO_SWAP, /*tx_half_word_swap */
+ MSP_COMPRESS_MODE_LINEAR, /*compression_mode */
+ MSP_EXPAND_MODE_LINEAR, /*expansion_mode */
+ MSP_SPI_CLOCK_MODE_NON_SPI, /*spi_clk_mode */
+ MSP_SPI_BURST_MODE_DISABLE, /*spi_burst_mode */
+ 255, /*frame_period */
+ 0, /*frame_width */
+ 256, /*total_clocks_for_one_frame */
+};
+
+#endif
+
+#if 0 //from STS
+struct msp_protocol_desc protocol_desc_tdm_mode = {
+ MSP_DATA_TRANSFER_WIDTH_HALFWORD, /*rx_data_transfer_width */
+ MSP_DATA_TRANSFER_WIDTH_HALFWORD, /*tx_data_transfer_width */
+ MSP_SINGLE_PHASE, /*rx_phase_mode */
+ MSP_SINGLE_PHASE, /*tx_phase_mode */
+ MSP_PHASE2_START_MODE_IMEDIATE, /*rx_phase2_start_mode */
+ MSP_PHASE2_START_MODE_IMEDIATE, /*tx_phase2_start_mode */
+ MSP_BTF_MS_BIT_FIRST, /*rx_endianess */
+ MSP_BTF_MS_BIT_FIRST, /*tx_endianess */
+ MSP_FRAME_LENGTH_2, /*rx_frame_length_1 */
+ MSP_FRAME_LENGTH_1, /*rx_frame_length_2 */
+ MSP_FRAME_LENGTH_2, /*tx_frame_length_1 */
+ MSP_FRAME_LENGTH_1, /*tx_frame_length_2 */
+ MSP_ELEM_LENGTH_16, /*rx_element_length_1 */
+ MSP_ELEM_LENGTH_16, /*rx_element_length_2 */
+ MSP_ELEM_LENGTH_16, /*tx_element_length_1 */
+ MSP_ELEM_LENGTH_16, /*tx_element_length_2 */
+ MSP_DELAY_0, /*rx_data_delay */
+ MSP_DELAY_0, /*tx_data_delay */
+ MSP_FALLING_EDGE, /*rx_clock_pol */
+ MSP_RISING_EDGE, /*tx_clock_pol */
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, /*rx_msp_frame_pol */
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH, /*tx_msp_frame_pol */
+ MSP_HWS_NO_SWAP, /*rx_half_word_swap */
+ MSP_HWS_NO_SWAP, /*tx_half_word_swap */
+ MSP_COMPRESS_MODE_LINEAR, /*compression_mode */
+ MSP_EXPAND_MODE_LINEAR, /*expansion_mode */
+ MSP_SPI_CLOCK_MODE_NON_SPI, /*spi_clk_mode */
+ MSP_SPI_BURST_MODE_DISABLE, /*spi_burst_mode */
+ 25, /*frame_period */
+ 32, /*frame_width */
+ 32, /*total_clocks_for_one_frame */
+};
+#endif
+
+#define DIGITAL_LPBK_MAX_BIFFERS 3
+
+#ifdef CONFIG_U8500_AB8500_CUT10
+#define NB_OF_CHANNEL_USED 8
+#else
+#define NB_OF_CHANNEL_USED 6
+#endif
+
+#define MONO_SRC 1
+#define STEREO_SRC 2
+
+typedef struct {
+ unsigned char *area; /* virtual pointer */
+ dma_addr_t addr; /* physical address */
+} t_dma_buffer;
+
+typedef struct {
+ struct completion tx_dma_com;
+ struct completion rx_dma_com;
+ volatile int rx_active;
+ volatile int tx_active;
+ t_dma_buffer buffer;
+ int data_size;
+ int rx_index;
+ int tx_index;
+} t_digital_lpbk_cnxt;
+
+const int play_flag = 1;
+const int capture_flag = 2;
+
+t_digital_lpbk_cnxt digital_lpbk_cnxt;
+
+void u8500_set_defaults()
+{
+ int i;
+
+ for (i = 0; i < NUMBER_INPUT_DEVICE; i++) {
+ g_codec_system_context.input_config[i].left_volume = 0;
+ g_codec_system_context.input_config[i].right_volume = 0;
+ g_codec_system_context.input_config[i].mute_state = DISABLE;
+ g_codec_system_context.input_config[i].power_state = DISABLE;
+ }
+
+ for (i = 0; i < NUMBER_OUTPUT_DEVICE; i++) {
+ g_codec_system_context.output_config[i].left_volume = 0;
+ g_codec_system_context.output_config[i].right_volume = 0;
+ g_codec_system_context.output_config[i].mute_state = DISABLE;
+ g_codec_system_context.output_config[i].power_state = DISABLE;
+ }
+
+} //END OF FUNCTION
+
+struct i2sdrv_data *i2sdrv[MAX_I2S_CLIENTS];
+
+t_ab8500_codec_error u8500_acodec_open(int client_id, int stream_id)
+{
+ struct i2sdrv_data *p_i2sdrv_data = NULL;
+ struct i2s_device *i2s;
+
+ p_i2sdrv_data = i2sdrv[client_id];
+
+ if (!p_i2sdrv_data)
+ return (-1);
+
+ i2s = p_i2sdrv_data->i2s;
+
+ if (stream_id == 0) //PLAYBACK
+ {
+ if (p_i2sdrv_data->tx_status)
+ return -1;
+ else {
+ p_i2sdrv_data->tx_status = 1;
+ }
+ } else if (stream_id == 1) //CAPTURE
+ {
+ if (p_i2sdrv_data->rx_status)
+ return -1;
+ else {
+ p_i2sdrv_data->rx_status = 1;
+ }
+ }
+
+ p_i2sdrv_data->flag = 0;
+
+ return 0;
+}
+
+t_ab8500_codec_error u8500_acodec_send_data(int client_id, void *data,
+ size_t bytes, int dma_flag)
+{
+ struct i2sdrv_data *p_i2sdrv_data = NULL;
+ struct i2s_device *i2s_dev = NULL;
+ int bytes_transmit;
+ struct i2s_message message;
+
+ p_i2sdrv_data = i2sdrv[client_id];
+
+ if (!p_i2sdrv_data)
+ return (-1);
+
+ i2s_dev = p_i2sdrv_data->i2s;
+
+ if (p_i2sdrv_data->flag) {
+ stm_dbg(DBG_ST.acodec, " I2S controller not available\n");
+ return -1;
+ }
+ message.txbytes = bytes;
+ message.txdata = data;
+ message.rxbytes = 0;
+ message.rxdata = NULL;
+ message.dma_flag = dma_flag;
+
+ bytes_transmit = i2s_transfer(i2s_dev->controller, &message);
+
+ if (bytes_transmit < 0) {
+ printk("error in transfer\n");
+ return -1;
+ }
+ return bytes_transmit;
+
+}
+
+t_ab8500_codec_error u8500_acodec_loopback_configure(int client_id, void *data,
+ size_t bytes, int dma_flag)
+{
+ struct i2sdrv_data *p_i2sdrv_data = NULL;
+ struct i2s_device *i2s_dev = NULL;
+ int bytes_receive;
+ struct i2s_message message;
+
+ p_i2sdrv_data = i2sdrv[client_id];
+
+ if (!p_i2sdrv_data)
+ return (-1);
+
+ i2s_dev = p_i2sdrv_data->i2s;
+
+ if (p_i2sdrv_data->flag) {
+ stm_dbg(DBG_ST.acodec, " I2S controller not available\n");
+ return -1;
+ }
+
+ message.rxbytes = bytes;
+ message.rxdata = data;
+ message.txbytes = bytes;
+ message.txdata = data;
+ message.dma_flag = dma_flag;
+ message.inf_loopback_xfer = true;
+
+ bytes_receive = i2s_transfer(i2s_dev->controller, &message);
+
+ if (bytes_receive < 0) {
+ printk(" not get\n");
+ return -1;
+ }
+ return bytes_receive;
+
+}
+
+t_ab8500_codec_error u8500_acodec_receive_data(int client_id, void *data,
+ size_t bytes, int dma_flag)
+{
+ struct i2sdrv_data *p_i2sdrv_data = NULL;
+ struct i2s_device *i2s_dev = NULL;
+ int bytes_receive;
+ struct i2s_message message;
+
+ p_i2sdrv_data = i2sdrv[client_id];
+
+ if (!p_i2sdrv_data)
+ return (-1);
+
+ i2s_dev = p_i2sdrv_data->i2s;
+
+ if (p_i2sdrv_data->flag) {
+ stm_dbg(DBG_ST.acodec, " I2S controller not available\n");
+ return -1;
+ }
+
+ message.rxbytes = bytes;
+ message.rxdata = data;
+ message.txbytes = 0;
+ message.txdata = NULL;
+ message.dma_flag = dma_flag;
+
+ bytes_receive = i2s_transfer(i2s_dev->controller, &message);
+
+ if (bytes_receive < 0) {
+ printk(" not get\n");
+ return -1;
+ }
+ return bytes_receive;
+
+}
+
+t_ab8500_codec_error u8500_acodec_close(int client_id, t_acodec_disable flag)
+{
+ struct i2sdrv_data *p_i2sdrv_data = NULL;
+ struct i2s_device *i2s_dev = NULL;
+ int status = 0;
+
+ p_i2sdrv_data = i2sdrv[client_id];
+
+ if (!p_i2sdrv_data)
+ return (-1);
+
+ i2s_dev = p_i2sdrv_data->i2s;
+
+ if (p_i2sdrv_data->flag) {
+ stm_dbg(DBG_ST.acodec, " I2S controller not available\n");
+ return -1;
+ }
+
+ if (flag == DISABLE_ALL) {
+ p_i2sdrv_data->flag = -1;
+ p_i2sdrv_data->tx_status = 0;
+ p_i2sdrv_data->rx_status = 0;
+ } else if (flag == DISABLE_TRANSMIT) {
+ p_i2sdrv_data->tx_status = 0;
+ } else if (flag == DISABLE_RECEIVE) {
+ p_i2sdrv_data->rx_status = 0;
+ }
+ status = i2s_cleanup(i2s_dev->controller, flag);
+ if (status) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+* u8500_acodec_enable_audio_mode
+*
+* @direction - direction of data flow (from/to) audiocode
+* @mspClockSel - clock for MSP
+* @mspInClockFreq - input clock for MSP
+* @channels - number of channel, 1 for mono and 2 for stereo
+*
+* It configures the audiocodec in audio mode. In this case,the I2S
+* protocol is used for data exchanges.
+*/
+
+t_ab8500_codec_error u8500_acodec_enable_audio_mode(struct acodec_configuration
+ * acodec_config)
+{
+ struct i2s_device *i2s_dev = NULL;
+ t_ab8500_codec_error error_status = AB8500_CODEC_OK;
+ struct msp_config msp_config;
+ t_ab8500_codec_error codec_error;
+ t_ab8500_codec_mode codec_in_mode = AB8500_CODEC_MODE_MANUAL_SETTING;
+ t_ab8500_codec_mode codec_out_mode = AB8500_CODEC_MODE_MANUAL_SETTING;
+ t_ab8500_codec_direction codec_direction;
+/*#ifdef CONFIG_U8500_AB8500_CUT10*/
+#if 1
+ t_ab8500_codec_tdm_config tdm_config;
+#endif
+
+ memset(&msp_config, 0, sizeof(msp_config));
+
+ FUNC_ENTER();
+ stm_dbg(DBG_ST.acodec,
+ " Entering in u8500_acodec_enable_audio_mode()\n");
+
+ if (i2sdrv[I2S_CLIENT_MSP1]->flag) {
+ stm_dbg(DBG_ST.acodec, " I2S controller not available\n");
+ return -1;
+ }
+
+ i2s_dev = i2sdrv[I2S_CLIENT_MSP1]->i2s;
+
+ if (g_codec_system_context.cur_user == NO_USER) {
+ stm_error("Audiocodec not yet configured by any user\n");
+ return (AB8500_CODEC_ERROR);
+ } else if (g_codec_system_context.cur_user != acodec_config->user) {
+ stm_error
+ (" Trying to acces audiocodec already in use by user %d\n",
+ g_codec_system_context.cur_user);
+ return (AB8500_CODEC_ERROR);
+ }
+
+ switch (acodec_config->direction) {
+ case AB8500_CODEC_DIRECTION_INOUT:
+ codec_direction = AB8500_CODEC_DIRECTION_INOUT;
+ codec_in_mode = AB8500_CODEC_MODE_VOICE; //HIFI
+ codec_out_mode = AB8500_CODEC_MODE_VOICE; //VOICE
+ break;
+ case AB8500_CODEC_DIRECTION_IN:
+ codec_direction = AB8500_CODEC_DIRECTION_IN;
+ codec_in_mode = AB8500_CODEC_MODE_VOICE; //HIFI
+ break;
+ case AB8500_CODEC_DIRECTION_OUT:
+ codec_direction = AB8500_CODEC_DIRECTION_OUT;
+ codec_out_mode = AB8500_CODEC_MODE_VOICE; //HIFI
+ break;
+ default:
+ stm_error("Invalid direction\n");
+ return AB8500_CODEC_ERROR;
+ }
+
+ /* MSP configuration */
+
+ msp_config.tx_clock_sel = 0; //TX_CLK_SEL_SRG;
+ msp_config.rx_clock_sel = 0; //RX_CLK_SEL_SRG;
+
+ msp_config.tx_frame_sync_sel = 0; //0x00000400; Frame synchronization signal is provided by an external source. MSPTFS is an input pin
+ msp_config.rx_frame_sync_sel = 0; //0: Rx Frame synchronization signal is provided by an external source. MSPRFS is an input pin
+
+ msp_config.input_clock_freq = MSP_INPUT_FREQ_48MHZ;
+
+ msp_config.srg_clock_sel = 0; //0x000C0000
+
+ //msp_config.rx_endianess = MSP_BIG_ENDIAN;
+ //msp_config.tx_endianess = MSP_BIG_ENDIAN;
+
+ msp_config.rx_frame_sync_pol = RX_FIFO_SYNC_HI;
+ msp_config.tx_frame_sync_pol = TX_FIFO_SYNC_HI;
+
+ //msp_config.rx_unexpect_frame_sync = MSP_UNEXPECTED_FS_IGNORE;
+ //msp_config.tx_unexpect_frame_sync = MSP_UNEXPECTED_FS_IGNORE;
+
+ msp_config.rx_fifo_config = RX_FIFO_ENABLE;
+ msp_config.tx_fifo_config = TX_FIFO_ENABLE;
+
+ msp_config.spi_clk_mode = SPI_CLK_MODE_NORMAL;
+ msp_config.spi_burst_mode = 0;
+
+ msp_config.handler = acodec_config->handler;
+ msp_config.tx_callback_data = acodec_config->tx_callback_data;
+ msp_config.tx_data_enable = 0;
+ msp_config.rx_callback_data = acodec_config->rx_callback_data;
+
+ msp_config.loopback_enable = 0;
+ msp_config.multichannel_configured = 0;
+
+ msp_config.def_elem_len = 0;
+ //msp_config.loopback_enable = g_codec_system_context.msp_loopback;
+
+ stm_dbg(DBG_ST.acodec, " msp_config.loopback_enable = 0x%x \n",
+ msp_config.loopback_enable);
+
+#if 0
+ msp_config.default_protocol_desc = 1;
+#else
+ msp_config.default_protocol_desc = 0;
+ msp_config.protocol_desc.rx_phase_mode = MSP_SINGLE_PHASE;
+ msp_config.protocol_desc.tx_phase_mode = MSP_SINGLE_PHASE;
+ msp_config.protocol_desc.rx_phase2_start_mode =
+ MSP_PHASE2_START_MODE_IMEDIATE;
+ msp_config.protocol_desc.tx_phase2_start_mode =
+ MSP_PHASE2_START_MODE_IMEDIATE;
+ msp_config.protocol_desc.rx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST;
+ msp_config.protocol_desc.tx_bit_transfer_format = MSP_BTF_MS_BIT_FIRST;
+ msp_config.protocol_desc.rx_frame_length_1 = MSP_FRAME_LENGTH_1;
+ msp_config.protocol_desc.rx_frame_length_2 = MSP_FRAME_LENGTH_1;
+ msp_config.protocol_desc.tx_frame_length_1 = MSP_FRAME_LENGTH_1;
+ msp_config.protocol_desc.tx_frame_length_2 = MSP_FRAME_LENGTH_1;
+ msp_config.protocol_desc.rx_element_length_1 = MSP_ELEM_LENGTH_32;
+ msp_config.protocol_desc.rx_element_length_2 = MSP_ELEM_LENGTH_32;
+ msp_config.protocol_desc.tx_element_length_1 = MSP_ELEM_LENGTH_32;
+ msp_config.protocol_desc.tx_element_length_2 = MSP_ELEM_LENGTH_32;
+ msp_config.protocol_desc.rx_data_delay = MSP_DELAY_0;
+ msp_config.protocol_desc.tx_data_delay = MSP_DELAY_0;
+ msp_config.protocol_desc.rx_clock_pol = MSP_RISING_EDGE;
+ msp_config.protocol_desc.tx_clock_pol = MSP_FALLING_EDGE;
+ msp_config.protocol_desc.rx_frame_sync_pol =
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH;
+ msp_config.protocol_desc.tx_frame_sync_pol =
+ MSP_FRAME_SYNC_POL_ACTIVE_HIGH;
+ msp_config.protocol_desc.rx_half_word_swap = MSP_HWS_NO_SWAP;
+ msp_config.protocol_desc.tx_half_word_swap = MSP_HWS_NO_SWAP;
+ msp_config.protocol_desc.compression_mode = MSP_COMPRESS_MODE_LINEAR;
+ msp_config.protocol_desc.expansion_mode = MSP_EXPAND_MODE_LINEAR;
+ msp_config.protocol_desc.spi_clk_mode = MSP_SPI_CLOCK_MODE_NON_SPI;
+ msp_config.protocol_desc.spi_burst_mode = MSP_SPI_BURST_MODE_DISABLE;
+ msp_config.protocol_desc.frame_sync_ignore = MSP_FRAME_SYNC_IGNORE;
+ msp_config.protocol_desc.frame_period = 63;
+ msp_config.protocol_desc.frame_width = 31;
+ msp_config.protocol_desc.total_clocks_for_one_frame = 64;
+
+#endif
+
+ msp_config.direction = MSP_BOTH_T_R_MODE;
+ msp_config.protocol = MSP_PCM_PROTOCOL; //MSP_I2S_PROTOCOL
+ msp_config.frame_size = ELEMENT_SIZE;
+ // msp_config.frame_freq = freq; $kardad$
+ msp_config.frame_freq = CODEC_SAMPLING_FREQ_48KHZ;
+
+ /* enable msp for both tr and rx mode with dma data transfer. THIS IS NOW DONE SEPARATELY from SAA. */
+
+ if (acodec_config->channels == 1)
+ msp_config.data_size = MSP_DATA_SIZE_16BIT;
+ else
+ msp_config.data_size = MSP_DATA_SIZE_32BIT;
+
+#ifdef CONFIG_U8500_ACODEC_DMA
+ msp_config.work_mode = MSP_DMA_MODE;
+#elif defined(CONFIG_U8500_ACODEC_POLL)
+ msp_config.work_mode = MSP_POLLING_MODE;
+#else
+ msp_config.work_mode = MSP_INTERRUPT_MODE;
+#endif
+
+ if (DISABLE == acodec_config->direct_rendering_mode) {
+ msp_config.multichannel_configured = 1;
+ msp_config.multichannel_config.tx_multichannel_enable = 1;
+ if (acodec_config->channels == 1) {
+ msp_config.multichannel_config.tx_channel_0_enable =
+ 0x0000001;
+ } else {
+ msp_config.multichannel_config.tx_channel_0_enable =
+ 0x0000003;
+ }
+ msp_config.multichannel_config.tx_channel_1_enable = 0x0000000;
+ msp_config.multichannel_config.tx_channel_2_enable = 0x0000000;
+ msp_config.multichannel_config.tx_channel_3_enable = 0x0000000;
+
+ msp_config.multichannel_config.rx_multichannel_enable = 1;
+
+ if (acodec_config->channels == 1) {
+ msp_config.multichannel_config.rx_channel_0_enable =
+ 0x0000001;
+ } else {
+ msp_config.multichannel_config.rx_channel_0_enable =
+ 0x0000003;
+ }
+ msp_config.multichannel_config.rx_channel_1_enable = 0x0000000;
+ msp_config.multichannel_config.rx_channel_2_enable = 0x0000000;
+ msp_config.multichannel_config.rx_channel_3_enable = 0x0000000;
+
+ if (acodec_config->tdm8_ch_mode == ENABLE) {
+ msp_config.def_elem_len = 1;
+
+ msp_config.protocol_desc.tx_element_length_1 =
+ MSP_ELEM_LENGTH_20;
+ msp_config.protocol_desc.tx_frame_length_1 =
+ MSP_FRAME_LENGTH_8;
+ msp_config.protocol_desc.tx_data_delay = MSP_DELAY_1;
+
+ msp_config.protocol_desc.tx_element_length_2 =
+ MSP_ELEM_LENGTH_8;
+ msp_config.protocol_desc.tx_frame_length_2 =
+ MSP_FRAME_LENGTH_1;
+
+ msp_config.protocol_desc.rx_element_length_1 =
+ MSP_ELEM_LENGTH_20;
+ msp_config.protocol_desc.rx_frame_length_1 =
+ MSP_FRAME_LENGTH_8;
+ msp_config.protocol_desc.rx_data_delay = MSP_DELAY_1;
+
+ msp_config.protocol_desc.rx_element_length_2 =
+ MSP_ELEM_LENGTH_8;
+ msp_config.protocol_desc.rx_frame_length_2 =
+ MSP_FRAME_LENGTH_1;
+
+ msp_config.protocol_desc.frame_sync_ignore =
+ MSP_FRAME_SYNC_UNIGNORE;
+ msp_config.protocol_desc.rx_clock_pol = MSP_RISING_EDGE;
+
+ //if(acodec_config->digital_loopback == ENABLE) {
+ if (1) {
+ msp_config.multichannel_config.
+ tx_channel_0_enable =
+ (1 << NB_OF_CHANNEL_USED) - 1;
+ msp_config.multichannel_config.
+ rx_channel_0_enable =
+ (1 << NB_OF_CHANNEL_USED) - 1;
+ } else {
+ msp_config.multichannel_config.
+ tx_channel_0_enable = 0x3;
+ msp_config.multichannel_config.
+ rx_channel_0_enable = 0x3;
+ }
+ }
+
+ if (acodec_config->tdm8_ch_mode == ENABLE) {
+ /* TFSDLY = 2 delay units */
+ msp_config.iodelay = 0x20;
+ }
+
+ error_status = i2s_setup(i2s_dev->controller, &msp_config);
+ if (error_status < 0) {
+ stm_error("error in msp enable, error_status is %d\n",
+ error_status);
+ return error_status;
+ }
+ } else if (ENABLE == acodec_config->direct_rendering_mode) {
+ writel(0x00, ((char *)(IO_ADDRESS(U8500_MSP1_BASE) + 0x04))); //MSP_GCR
+ }
+
+ if (ACODEC_CONFIG_REQUIRED == acodec_config->acodec_config_need) {
+ AB8500_CODEC_SelectInterface(AB8500_CODEC_AUDIO_INTERFACE_0);
+
+ codec_error = AB8500_CODEC_PowerUp();
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("AB8500_CODEC_PowerUp failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+
+/*#ifdef CONFIG_U8500_AB8500_CUT10*/
+#if 1
+ tdm_config.cr27_if1_bitclk_osr =
+ AB8500_CODEC_CR27_IF1_BITCLK_OSR_32;
+ tdm_config.cr27_if0_bitclk_osr =
+ AB8500_CODEC_CR27_IF0_BITCLK_OSR_32;
+ tdm_config.cr28_if0wl = AB8500_CODEC_CR28_IF0WL_16BITS;
+ tdm_config.cr30_if1wl = AB8500_CODEC_CR30_IF1WL_16BITS;
+
+ switch (acodec_config->direction) {
+ case AB8500_CODEC_DIRECTION_INOUT:
+ tdm_config.cr28_bitclk0p =
+ AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE;
+ tdm_config.cr28_if0del =
+ AB8500_CODEC_CR28_IF0DEL_DELAYED;
+ break;
+ case AB8500_CODEC_DIRECTION_IN:
+ tdm_config.cr28_bitclk0p =
+ AB8500_CODEC_CR28_BITCLK0P_RISING_EDGE;
+ tdm_config.cr28_if0del =
+ AB8500_CODEC_CR28_IF0DEL_NOT_DELAYED;
+ break;
+ case AB8500_CODEC_DIRECTION_OUT:
+ tdm_config.cr28_bitclk0p =
+ AB8500_CODEC_CR28_BITCLK0P_FALLING_EDGE;
+ tdm_config.cr28_if0del =
+ AB8500_CODEC_CR28_IF0DEL_DELAYED;
+ break;
+ default:
+ stm_error("Invalid direction\n");
+ return AB8500_CODEC_ERROR;
+ }
+
+ if (acodec_config->tdm8_ch_mode == ENABLE) {
+ tdm_config.cr27_if0_bitclk_osr =
+ AB8500_CODEC_CR27_IF0_BITCLK_OSR_256;
+ tdm_config.cr28_if0wl = AB8500_CODEC_CR28_IF0WL_20BITS;
+ tdm_config.cr28_bitclk0p =
+ AB8500_CODEC_CR28_BITCLK0P_RISING_EDGE;
+ tdm_config.cr28_if0del =
+ AB8500_CODEC_CR28_IF0DEL_DELAYED;
+ codec_in_mode = AB8500_CODEC_MODE_VOICE;
+ codec_out_mode = AB8500_CODEC_MODE_VOICE;
+ acodec_config->direction = AB8500_CODEC_DIRECTION_INOUT;
+ }
+
+ codec_error =
+ AB8500_CODEC_SetModeAndDirection(acodec_config->direction,
+ codec_in_mode,
+ codec_out_mode,
+ &tdm_config);
+#else
+ codec_error =
+ AB8500_CODEC_SetModeAndDirection(acodec_config->direction,
+ codec_in_mode,
+ codec_out_mode);
+#endif
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("set mode and direction failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+
+ codec_error =
+ AB8500_CODEC_SetMasterMode(AB8500_CODEC_MASTER_MODE_ENABLE);
+
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("set mode and direction failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+
+ /*codec_error = trg_codec_set_sample_frequency(0); */
+
+ /*u8500_acodec_set_volume(g_codec_system_context.in_left_volume,
+ g_codec_system_context.in_right_volume,
+ g_codec_system_context.out_left_volume,
+ g_codec_system_context.out_right_volume,
+ user); */
+#if 0
+ if (AB8500_CODEC_DIRECTION_IN == acodec_config->direction
+ || AB8500_CODEC_DIRECTION_INOUT ==
+ acodec_config->direction) {
+
+ u8500_acodec_allocate_ad_slot
+ (AB8500_CODEC_SRC_D_MICROPHONE_1, TDM_8_CH_MODE);
+ u8500_acodec_allocate_ad_slot
+ (AB8500_CODEC_SRC_D_MICROPHONE_2, TDM_8_CH_MODE);
+
+ /*codec_error = AB8500_CODEC_ADSlotAllocation (AB8500_CODEC_SLOT0,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT3);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_adslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ codec_error = AB8500_CODEC_ADSlotAllocation (AB8500_CODEC_SLOT1,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_IS_TRISTATE);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_adslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ } */
+
+ }
+
+ if (AB8500_CODEC_DIRECTION_OUT == acodec_config->direction
+ || AB8500_CODEC_DIRECTION_INOUT ==
+ acodec_config->direction) {
+ u8500_acodec_allocate_da_slot(AB8500_CODEC_DEST_HEADSET,
+ TDM_8_CH_MODE);
+ /*codec_error = AB8500_CODEC_DASlotAllocation (AB8500_CODEC_DA_CHANNEL_NUMBER_1,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT08);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error
+ ("ab8500_codec_daslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ codec_error = AB8500_CODEC_DASlotAllocation (AB8500_CODEC_DA_CHANNEL_NUMBER_2,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT09);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error
+ ("ab8500_codec_daslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ } */
+
+ }
+#endif
+
+ } //END of if acodec_config_need
+
+/*#if DRIVER_DEBUG > 0
+ {
+ dump_msp_registers();
+ dump_acodec_registers();
+ }
+#endif*/
+
+ stm_dbg(DBG_ST.acodec,
+ "leaving in u8500_acodec_enable_audio_mode() \n");
+
+ FUNC_EXIT();
+ return AB8500_CODEC_OK;
+}
+
+/**
+* u8500_acodec_set_output_volume - configures the volume level for both speakers
+* @in_left_volume - volume for left channel of mic
+* @in_right_volume - volume for right channel of mic
+* @out_left_volume - volume for left speaker
+* @out_right_volume - volume for right speaker
+*/
+t_ab8500_codec_error u8500_acodec_set_output_volume(t_ab8500_codec_dest
+ dest_device,
+ int left_volume,
+ int right_volume,
+ t_acodec_user user)
+{
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ stm_dbg(DBG_ST.acodec,
+ " Entering in u8500_acodec_set_output_volume()\n");
+
+ FUNC_ENTER();
+
+ user = user; //keep compiler happy
+
+ g_codec_system_context.output_config[dest_device].left_volume =
+ left_volume;
+ g_codec_system_context.output_config[dest_device].right_volume =
+ right_volume;
+
+ AB8500_CODEC_SetDestVolume(dest_device, left_volume, right_volume);
+
+ FUNC_EXIT();
+ return codec_error;
+}
+
+/*u8500_acodec_get_output_volume*/
+
+t_ab8500_codec_error u8500_acodec_get_output_volume(t_ab8500_codec_dest
+ dest_device,
+ int *p_left_volume,
+ int *p_right_volume,
+ t_acodec_user user)
+{
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ stm_dbg(DBG_ST.acodec,
+ " Entering in u8500_acodec_set_output_volume()\n");
+
+ user = user; //keep compiler happy
+
+ *p_left_volume =
+ g_codec_system_context.output_config[dest_device].left_volume;
+ *p_right_volume =
+ g_codec_system_context.output_config[dest_device].right_volume;
+
+ return codec_error;
+}
+
+/**
+* u8500_acodec_set_input_volume - configures the volume level for both speakers
+* @in_left_volume - volume for left channel of mic
+* @in_right_volume - volume for right channel of mic
+* @out_left_volume - volume for left speaker
+* @out_right_volume - volume for right speaker
+*/
+t_ab8500_codec_error u8500_acodec_set_input_volume(t_ab8500_codec_src
+ src_device, int left_volume,
+ int right_volume,
+ t_acodec_user user)
+{
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ stm_dbg(DBG_ST.acodec,
+ " Entering in u8500_acodec_set_input_volume()\n");
+
+ user = user; //keep compiler happy
+
+ g_codec_system_context.input_config[src_device].left_volume =
+ left_volume;
+ g_codec_system_context.input_config[src_device].right_volume =
+ right_volume;
+
+ AB8500_CODEC_SetSrcVolume(src_device, left_volume, right_volume);
+
+ return codec_error;
+}
+
+/**
+* u8500_acodec_get_input_volume - configures the volume level for both speakers
+* @in_left_volume - volume for left channel of mic
+* @in_right_volume - volume for right channel of mic
+* @out_left_volume - volume for left speaker
+* @out_right_volume - volume for right speaker
+*/
+t_ab8500_codec_error u8500_acodec_get_input_volume(t_ab8500_codec_src
+ src_device,
+ int *p_left_volume,
+ int *p_right_volume,
+ t_acodec_user user)
+{
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ stm_dbg(DBG_ST.acodec,
+ " Entering in u8500_acodec_get_input_volume()\n");
+
+ user = user; //keep compiler happy
+
+ *p_left_volume =
+ g_codec_system_context.input_config[src_device].left_volume;
+ *p_right_volume =
+ g_codec_system_context.input_config[src_device].right_volume;
+
+ return codec_error;
+}
+
+/**
+* u8500_acodec_toggle_playback_mute_control - configures the mute for both speakers
+* @in_left_volume - volume for left channel of mic
+* @in_right_volume - volume for right channel of mic
+* @out_left_volume - volume for left speaker
+* @out_right_volume - volume for right speaker
+*/
+t_ab8500_codec_error
+u8500_acodec_toggle_playback_mute_control(t_ab8500_codec_dest dest_device,
+ t_u8500_bool_state mute_state,
+ t_acodec_user user)
+{
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ stm_dbg(DBG_ST.acodec,
+ " Entering in u8500_acodec_toggle_playback_mute_control \n");
+
+ user = user; //keep compiler happy
+
+ g_codec_system_context.output_config[dest_device].mute_state =
+ mute_state;
+
+ if (ENABLE == mute_state) {
+ AB8500_CODEC_DestPowerControl(dest_device,
+ AB8500_CODEC_SRC_STATE_ENABLE);
+ } else {
+ AB8500_CODEC_DestPowerControl(dest_device,
+ AB8500_CODEC_SRC_STATE_DISABLE);
+ }
+
+ return codec_error;
+}
+
+/**
+* u8500_acodec_toggle_capture_mute_control - configures the mute for both speakers
+* @in_left_volume - volume for left channel of mic
+* @in_right_volume - volume for right channel of mic
+* @out_left_volume - volume for left speaker
+* @out_right_volume - volume for right speaker
+*/
+t_ab8500_codec_error u8500_acodec_toggle_capture_mute_control(t_ab8500_codec_src
+ src_device,
+ t_u8500_bool_state
+ mute_state,
+ t_acodec_user
+ user)
+{
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ stm_dbg(DBG_ST.acodec,
+ " Entering in u8500_acodec_toggle_capture_mute_control \n");
+
+ user = user; //keep compiler happy
+
+ g_codec_system_context.input_config[src_device].mute_state = mute_state;
+
+ if (ENABLE == mute_state) {
+ AB8500_CODEC_SrcPowerControl(src_device,
+ AB8500_CODEC_SRC_STATE_ENABLE);
+ } else {
+ AB8500_CODEC_SrcPowerControl(src_device,
+ AB8500_CODEC_SRC_STATE_DISABLE);
+ }
+
+ return codec_error;
+}
+
+/**
+* u8500_acodec_select_input
+* @input_device: MIC or linein.
+*
+* This routine selects the input device mic or linein.
+*/
+
+t_ab8500_codec_error u8500_acodec_select_input(t_ab8500_codec_src
+ input_device,
+ t_acodec_user user,
+ t_u8500_mode mode)
+{
+
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ stm_dbg(DBG_ST.acodec, " Entering u8500_acodec_select_input\n");
+
+ if (TDM_8_CH_MODE == mode)
+ u8500_acodec_allocate_ad_slot(input_device, TDM_8_CH_MODE);
+ else
+ u8500_acodec_allocate_ad_slot(input_device, CLASSICAL_MODE);
+
+ codec_error = AB8500_CODEC_SelectInput(input_device);
+
+ stm_dbg(DBG_ST.acodec, " leaving u8500_acodec_select_input\n");
+ return codec_error;
+}
+
+/**
+* u8500_acodec_select_output
+* @output_device: output device HP/LSP
+*
+* This routine selects the output device Headphone or loud speaker
+*/
+
+t_ab8500_codec_error u8500_acodec_select_output(t_ab8500_codec_dest
+ output_device,
+ t_acodec_user user,
+ t_u8500_mode mode)
+{
+
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ FUNC_ENTER();
+ stm_dbg(DBG_ST.acodec, " Entering u8500_acodec_select_output()\n");
+
+ if (TDM_8_CH_MODE == mode)
+ u8500_acodec_allocate_da_slot(output_device, TDM_8_CH_MODE);
+ else
+ u8500_acodec_allocate_da_slot(output_device, CLASSICAL_MODE);
+
+ codec_error = AB8500_CODEC_SelectOutput(output_device);
+
+ stm_dbg(DBG_ST.acodec, " leaving u8500_acodec_select_output()\n");
+ FUNC_EXIT();
+ return codec_error;
+}
+
+t_ab8500_codec_error u8500_acodec_allocate_ad_slot(t_ab8500_codec_src
+ input_device,
+ t_u8500_mode mode)
+{
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line1,
+ ad_data_line2;
+ t_ab8500_codec_slot slot1, slot2;
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ slot1 = AB8500_CODEC_SLOT_UNDEFINED;
+ slot2 = AB8500_CODEC_SLOT_UNDEFINED;
+
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_UNDEFINED;
+ ad_data_line2 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_UNDEFINED;
+
+ switch (input_device) {
+ case AB8500_CODEC_SRC_D_MICROPHONE_1:
+ {
+ slot1 = AB8500_CODEC_SLOT0;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1;
+ }
+ break;
+ case AB8500_CODEC_SRC_MICROPHONE_2:
+ case AB8500_CODEC_SRC_D_MICROPHONE_2:
+ {
+ slot1 = AB8500_CODEC_SLOT1;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_3:
+ case AB8500_CODEC_SRC_MICROPHONE_1A:
+ case AB8500_CODEC_SRC_MICROPHONE_1B:
+ {
+ slot1 = AB8500_CODEC_SLOT2;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT3;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_4:
+ {
+ slot1 = AB8500_CODEC_SLOT3;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT4;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_5:
+ {
+ slot1 = AB8500_CODEC_SLOT4;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT5;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_6:
+ {
+ slot1 = AB8500_CODEC_SLOT5;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT6;
+ }
+ break;
+ case AB8500_CODEC_SRC_LINEIN:
+ {
+ slot1 = AB8500_CODEC_SLOT0;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1;
+
+ slot2 = AB8500_CODEC_SLOT1;
+ ad_data_line2 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2;
+ }
+ case AB8500_CODEC_SRC_FM_RX:
+ {
+ slot1 = AB8500_CODEC_SLOT6;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT7;
+
+ slot2 = AB8500_CODEC_SLOT7;
+ ad_data_line2 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT8;
+ }
+ break;
+ case AB8500_CODEC_SRC_ALL:
+ break;
+ }
+
+ if ((AB8500_CODEC_SLOT_UNDEFINED != slot1)
+ && (AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_UNDEFINED !=
+ ad_data_line1)) {
+ if (CLASSICAL_MODE == mode) {
+ slot1 = AB8500_CODEC_SLOT0;
+ }
+ codec_error =
+ AB8500_CODEC_ADSlotAllocation(slot1, ad_data_line1);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_adslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ }
+
+ if ((AB8500_CODEC_SLOT_UNDEFINED != slot2)
+ && (AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_UNDEFINED !=
+ ad_data_line2)) {
+ if (CLASSICAL_MODE == mode) {
+ slot2 = AB8500_CODEC_SLOT1;
+ }
+ codec_error =
+ AB8500_CODEC_ADSlotAllocation(slot2, ad_data_line2);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_adslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ }
+
+ return AB8500_CODEC_OK;
+}
+
+t_ab8500_codec_error u8500_acodec_unallocate_ad_slot(t_ab8500_codec_src
+ input_device,
+ t_u8500_mode mode)
+{
+ t_ab8500_codec_slot slot1, slot2;
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ slot1 = AB8500_CODEC_SLOT_UNDEFINED;
+ slot2 = AB8500_CODEC_SLOT_UNDEFINED;
+
+ switch (input_device) {
+ case AB8500_CODEC_SRC_D_MICROPHONE_1:
+ {
+ slot1 = AB8500_CODEC_SLOT0;
+ }
+ break;
+ case AB8500_CODEC_SRC_MICROPHONE_2:
+ case AB8500_CODEC_SRC_D_MICROPHONE_2:
+ {
+ slot1 = AB8500_CODEC_SLOT1;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_3:
+ case AB8500_CODEC_SRC_MICROPHONE_1A:
+ case AB8500_CODEC_SRC_MICROPHONE_1B:
+ {
+ slot1 = AB8500_CODEC_SLOT2;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_4:
+ {
+ slot1 = AB8500_CODEC_SLOT3;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_5:
+ {
+ slot1 = AB8500_CODEC_SLOT4;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_6:
+ {
+ slot1 = AB8500_CODEC_SLOT5;
+ }
+ break;
+ case AB8500_CODEC_SRC_LINEIN:
+ {
+ slot1 = AB8500_CODEC_SLOT0;
+ slot2 = AB8500_CODEC_SLOT1;
+ }
+ break;
+ case AB8500_CODEC_SRC_ALL:
+ break;
+ }
+
+ if (AB8500_CODEC_SLOT_UNDEFINED != slot1) {
+ if (CLASSICAL_MODE == mode) {
+ slot1 = AB8500_CODEC_SLOT0;
+ }
+ codec_error =
+ AB8500_CODEC_ADSlotAllocation(slot1,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_IS_TRISTATE);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_adslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ }
+
+ if (AB8500_CODEC_SLOT_UNDEFINED != slot2) {
+ if (CLASSICAL_MODE == mode) {
+ slot2 = AB8500_CODEC_SLOT1;
+ }
+ codec_error =
+ AB8500_CODEC_ADSlotAllocation(slot2,
+ AB8500_CODEC_CR31_TO_CR46_SLOT_IS_TRISTATE);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_adslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ }
+
+ return AB8500_CODEC_OK;
+}
+
+#ifdef CONFIG_U8500_AB8500_CUT10
+t_ab8500_codec_error u8500_acodec_allocate_da_slot(t_ab8500_codec_dest
+ output_device,
+ t_u8500_mode mode)
+{
+ t_ab8500_codec_da_channel_number da_ch_no1, da_ch_no2;
+ t_ab8500_codec_cr51_to_cr58_sltoda da_slot1, da_slot2;
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED;
+ da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED;
+
+ da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT_UNDEFINED;
+ da_slot2 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT_UNDEFINED;
+
+ switch (output_device) {
+ case AB8500_CODEC_DEST_HEADSET:
+ {
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_1;
+ da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT08;
+
+ da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_2;
+ da_slot2 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT09;
+ }
+ break;
+ case AB8500_CODEC_DEST_EARPIECE:
+ {
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_1;
+ da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT08;
+ }
+ break;
+ case AB8500_CODEC_DEST_HANDSFREE:
+ {
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_3;
+ da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT10;
+
+ da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_4;
+ da_slot2 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT11;
+ }
+ break;
+ case AB8500_CODEC_DEST_VIBRATOR_L:
+ {
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_5;
+ da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT12;
+ }
+ break;
+ case AB8500_CODEC_DEST_VIBRATOR_R:
+ {
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_6;
+ da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT13;
+ }
+ break;
+
+ case AB8500_CODEC_DEST_FM_TX:
+ {
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_7;
+ da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT14;
+
+ da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_8;
+ da_slot2 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT15;
+ }
+
+ case AB8500_CODEC_DEST_ALL:
+ break;
+ }
+
+ if ((AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED != da_ch_no1)
+ && (AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT_UNDEFINED != da_slot1)) {
+ if (CLASSICAL_MODE == mode) {
+ da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT08;
+ }
+ codec_error =
+ AB8500_CODEC_DASlotAllocation(da_ch_no1, da_slot1);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_daslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ }
+
+ if ((AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED != da_ch_no2)
+ && (AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT_UNDEFINED != da_slot2)) {
+ if (CLASSICAL_MODE == mode) {
+ da_slot1 = AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT09;
+ }
+ codec_error =
+ AB8500_CODEC_DASlotAllocation(da_ch_no2, da_slot2);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_daslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ }
+
+ return AB8500_CODEC_OK;
+}
+
+#else
+t_ab8500_codec_error u8500_acodec_allocate_da_slot(t_ab8500_codec_dest
+ output_device,
+ t_u8500_mode mode)
+{
+ t_ab8500_codec_da_channel_number da_ch_no1, da_ch_no2;
+ t_ab8500_codec_cr51_to_cr56_sltoda da_slot1, da_slot2;
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED;
+ da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED;
+
+ da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT_UNDEFINED;
+ da_slot2 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT_UNDEFINED;
+
+ switch (output_device) {
+ case AB8500_CODEC_DEST_HEADSET:
+ {
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_1;
+ da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT08;
+
+ da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_2;
+ da_slot2 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT09;
+ }
+ break;
+ case AB8500_CODEC_DEST_EARPIECE:
+ {
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_1;
+ da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT08;
+ }
+ break;
+ case AB8500_CODEC_DEST_HANDSFREE:
+ {
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_3;
+ da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT10;
+
+ da_ch_no2 = AB8500_CODEC_DA_CHANNEL_NUMBER_4;
+ da_slot2 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT11;
+ }
+ break;
+ case AB8500_CODEC_DEST_VIBRATOR_L:
+ {
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_5;
+ da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT12;
+ }
+ break;
+ case AB8500_CODEC_DEST_VIBRATOR_R:
+ {
+ da_ch_no1 = AB8500_CODEC_DA_CHANNEL_NUMBER_6;
+ da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT13;
+ }
+ break;
+
+ case AB8500_CODEC_DEST_ALL:
+ break;
+ }
+
+ if ((AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED != da_ch_no1)
+ && (AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT_UNDEFINED != da_slot1)) {
+ if (CLASSICAL_MODE == mode) {
+ da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT08;
+ }
+ codec_error =
+ AB8500_CODEC_DASlotAllocation(da_ch_no1, da_slot1);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_daslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ }
+
+ if ((AB8500_CODEC_DA_CHANNEL_NUMBER_UNDEFINED != da_ch_no2)
+ && (AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT_UNDEFINED != da_slot2)) {
+ if (CLASSICAL_MODE == mode) {
+ da_slot1 = AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT09;
+ }
+ codec_error =
+ AB8500_CODEC_DASlotAllocation(da_ch_no2, da_slot2);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_daslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ }
+
+ return AB8500_CODEC_OK;
+}
+#endif
+
+t_ab8500_codec_error u8500_acodec_unallocate_da_slot(t_ab8500_codec_dest
+ output_device,
+ t_u8500_mode mode)
+{
+ return AB8500_CODEC_OK;
+}
+
+t_ab8500_codec_error u8500_acodec_set_src_power_cntrl(t_ab8500_codec_src
+ input_device,
+ t_u8500_bool_state
+ pwr_state)
+{
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ if (ENABLE == pwr_state) {
+ u8500_acodec_allocate_ad_slot(input_device, TDM_8_CH_MODE);
+ codec_error =
+ AB8500_CODEC_SrcPowerControl(input_device,
+ AB8500_CODEC_SRC_STATE_ENABLE);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("AB8500_CODEC_SrcPowerControl failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ g_codec_system_context.input_config[input_device].power_state =
+ ENABLE;
+ } else {
+ u8500_acodec_unallocate_ad_slot(input_device, TDM_8_CH_MODE);
+ codec_error =
+ AB8500_CODEC_SrcPowerControl(input_device,
+ AB8500_CODEC_SRC_STATE_DISABLE);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("AB8500_CODEC_SrcPowerControl failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ g_codec_system_context.input_config[input_device].power_state =
+ DISABLE;
+ }
+
+ return AB8500_CODEC_OK;
+}
+
+t_u8500_bool_state u8500_acodec_get_src_power_state(t_ab8500_codec_src
+ input_device)
+{
+ return (g_codec_system_context.input_config[input_device].power_state);
+}
+
+t_ab8500_codec_error u8500_acodec_set_dest_power_cntrl(t_ab8500_codec_dest
+ output_device,
+ t_u8500_bool_state
+ pwr_state)
+{
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ if (ENABLE == pwr_state) {
+ AB8500_CODEC_SelectInterface(AB8500_CODEC_AUDIO_INTERFACE_0);
+
+ codec_error = AB8500_CODEC_PowerUp();
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("AB8500_CODEC_PowerUp failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+
+ u8500_acodec_allocate_da_slot(output_device, TDM_8_CH_MODE);
+
+ codec_error =
+ AB8500_CODEC_DestPowerControl(output_device,
+ AB8500_CODEC_DEST_STATE_ENABLE);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("AB8500_CODEC_DestPowerControl failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ g_codec_system_context.output_config[output_device].
+ power_state = ENABLE;
+ } else {
+ u8500_acodec_unallocate_da_slot(output_device, TDM_8_CH_MODE);
+ codec_error =
+ AB8500_CODEC_DestPowerControl(output_device,
+ AB8500_CODEC_DEST_STATE_DISABLE);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("AB8500_CODEC_DestPowerControl failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ g_codec_system_context.output_config[output_device].
+ power_state = DISABLE;
+ }
+
+ return AB8500_CODEC_OK;
+}
+
+t_u8500_bool_state u8500_acodec_get_dest_power_state(t_ab8500_codec_dest
+ output_device)
+{
+ return (g_codec_system_context.output_config[output_device].
+ power_state);
+}
+
+/**
+* u8500_acodec_toggle_analog_lpbk
+* @output_device: output device HP/LSP
+*
+* This routine selects the output device Headphone or loud speaker
+*/
+t_ab8500_codec_error u8500_acodec_toggle_analog_lpbk(t_u8500_bool_state
+ lpbk_state,
+ t_acodec_user user)
+{
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ stm_dbg(DBG_ST.acodec,
+ " Entering inu8500_acodec_toggle_analog_lpbk() \n");
+
+ user = user; //keep compiler happy
+
+ if (ENABLE == lpbk_state) {
+ /* Reset CODEC */
+ codec_error = AB8500_CODEC_Reset();
+
+ AB8500_CODEC_SelectInterface(AB8500_CODEC_AUDIO_INTERFACE_0);
+
+ codec_error = AB8500_CODEC_PowerUp();
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("AB8500_CODEC_PowerUp failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+
+ codec_error = AB8500_CODEC_SelectInput(AB8500_CODEC_SRC_LINEIN);
+
+ codec_error =
+ AB8500_CODEC_SrcPowerControl(AB8500_CODEC_SRC_LINEIN,
+ AB8500_CODEC_SRC_STATE_ENABLE);
+
+ //codec_error = AB8500_CODEC_SetSrcVolume(AB8500_CODEC_SRC_LINEIN,VOL_MAX,VOL_MAX);
+
+ codec_error =
+ AB8500_CODEC_SelectOutput(AB8500_CODEC_DEST_HEADSET);
+
+ codec_error =
+ AB8500_CODEC_DestPowerControl(AB8500_CODEC_DEST_HEADSET,
+ AB8500_CODEC_DEST_STATE_ENABLE);
+
+ //codec_error = AB8500_CODEC_SetDestVolume(AB8500_CODEC_DEST_HEADSET,0,0);
+
+ codec_error = AB8500_CODEC_SetAnalogLoopback(VOL_MAX, VOL_MAX);
+
+ ab8500_write(AB8500_AUDIO, 0xd05, 0x30);
+ ab8500_write(AB8500_AUDIO, 0xd07, 0xf3);
+ ab8500_write(AB8500_AUDIO, 0xd16, 0xdd);
+ ab8500_write(AB8500_AUDIO, 0xd17, 0x55);
+ ab8500_write(AB8500_AUDIO, 0xd3f, 0xc0);
+
+ } else {
+ codec_error = AB8500_CODEC_RemoveAnalogLoopback();
+ }
+
+#if DRIVER_DEBUG > 0
+ {
+ dump_acodec_registers();
+ }
+#endif
+
+ return codec_error;
+}
+
+#ifdef CONFIG_U8500_ACODEC_POLL
+
+static int digital_lpbk_msp_rx_tx_thread(void *data)
+{
+ t_digital_lpbk_cnxt *p_cnxt = (t_digital_lpbk_cnxt *) data;
+ unsigned int sample[8], count = 32;
+
+ daemonize("digital_lpbk_msp_rx_tx_thread");
+ allow_signal(SIGKILL);
+
+ printk("\n Rx-Tx : digital_lpbk_msp_rx_tx_thread started \n");
+
+ while ((!signal_pending(current)) && (p_cnxt->rx_active)) {
+
+// ret_val = u8500_msp_receive_data(alsa_msp_adev,p_cnxt->buffer[p_cnxt->rx_index],p_cnxt->data_size);
+
+ //u8500_msp_transceive_data(alsa_msp_adev,p_cnxt->buffer[0], p_cnxt->data_size,p_cnxt->buffer[1], p_cnxt->data_size);
+
+ //u8500_msp_transceive_data(alsa_msp_adev,p_cnxt->buffer[1], p_cnxt->data_size,p_cnxt->buffer[0], p_cnxt->data_size);
+
+#if DRIVER_DEBUG > 1
+ stm_dbg(DBG_ST.alsa, " Receiving \n");
+#endif
+ u8500_acodec_receive_data(I2S_CLIENT_MSP1, (void *)sample,
+ count, 0);
+
+#if DRIVER_DEBUG > 1
+ stm_dbg(DBG_ST.alsa, " Transmitting \n");
+#endif
+ u8500_acodec_send_data(I2S_CLIENT_MSP1, (void *)sample, count,
+ 0);
+
+ }
+ printk("\n Rx-Tx : digital_lpbk_msp_rx_tx_thread ended \n");
+ return 0;
+}
+
+#endif
+
+#ifdef CONFIG_U8500_ACODEC_DMA
+
+static void u8500_digital_lpbk_dma_start()
+{
+ u8500_acodec_loopback_configure(I2S_CLIENT_MSP1,
+ (void *)digital_lpbk_cnxt.buffer.addr,
+ digital_lpbk_cnxt.data_size, 1);
+
+ stm_dbg(DBG_ST.alsa, " Rx DMA Transfer started\n");
+ stm_dbg(DBG_ST.alsa, " Rx : add = %x size=%d\n",
+ (int)(digital_lpbk_cnxt.buffer.addr),
+ digital_lpbk_cnxt.data_size);
+
+}
+#endif
+
+/**
+* u8500_acodec_toggle_digital_lpbk
+* @output_device: output device HP/LSP
+*
+* This routine selects the output device Headphone or loud speaker
+*/
+
+t_ab8500_codec_error u8500_acodec_toggle_digital_lpbk(t_u8500_bool_state
+ lpbk_state,
+ t_ab8500_codec_dest
+ dest_device,
+ t_ab8500_codec_src
+ src_device,
+ t_acodec_user user,
+ t_u8500_bool_state
+ tdm8_ch_mode)
+{
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+ struct acodec_configuration acodec_config;
+ int status = 0;
+
+ stm_dbg(DBG_ST.acodec,
+ " Entering u8500_acodec_toggle_digital_lpbk() \n");
+
+ user = user; //keep compiler happy
+
+ if (ENABLE == lpbk_state) {
+ //data_size = 1024*100;
+
+ //data[0] = (unsigned char *)kmalloc(data_size, GFP_KERNEL);
+
+ codec_error = AB8500_CODEC_Reset();
+
+ //AB8500_CODEC_SelectInterface(AB8500_CODEC_AUDIO_INTERFACE_0);
+
+ //codec_error = AB8500_CODEC_PowerUp();
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("AB8500_CODEC_PowerUp failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+
+ status = u8500_acodec_open(I2S_CLIENT_MSP1, 0);
+ if (status) {
+ printk("failed in getting acodec playback open\n");
+ return -1;
+ }
+ status = u8500_acodec_open(I2S_CLIENT_MSP1, 1);
+ if (status) {
+ printk("failed in getting acdoec capture open\n");
+ return -1;
+ }
+
+ u8500_acodec_setuser(USER_ALSA);
+
+ if (ENABLE == tdm8_ch_mode) {
+ printk("\n 20 bit 8 ch Digital Loopback");
+ printk("\n DMIC1 -> HS-L");
+ printk("\n DMIC2 -> HS-R");
+ printk("\n DMIC3 -> IHF-L");
+ printk("\n DMIC5 -> Vibra-L\n");
+ printk("\n DMIC6 -> Vibra-R\n");
+ printk("\n FM -> FM Tx\n");
+ } else {
+ printk("\n 16 bit 2 ch Digital Loopback");
+ printk("\n DMIC1 -> HS-L");
+ printk("\n DMIC2 -> HS-R");
+ }
+
+ stm_dbg(DBG_ST.alsa, "enabling audiocodec audio mode\n");
+ acodec_config.direction = AB8500_CODEC_DIRECTION_INOUT;
+ acodec_config.input_frequency = T_CODEC_SAMPLING_FREQ_48KHZ;
+ acodec_config.output_frequency = T_CODEC_SAMPLING_FREQ_48KHZ;
+ acodec_config.mspClockSel = CODEC_MSP_APB_CLOCK;
+ acodec_config.mspInClockFreq = CODEC_MSP_INPUT_FREQ_48MHZ;
+ acodec_config.channels = 2;
+ acodec_config.user = 2;
+ acodec_config.acodec_config_need = ACODEC_CONFIG_REQUIRED;
+ acodec_config.direct_rendering_mode = DISABLE;
+ acodec_config.tdm8_ch_mode = tdm8_ch_mode;
+ acodec_config.digital_loopback = ENABLE;
+#ifdef CONFIG_U8500_ACODEC_POLL
+ acodec_config.handler = NULL;
+ acodec_config.tx_callback_data = NULL;
+ acodec_config.rx_callback_data = NULL;
+#endif
+ u8500_acodec_enable_audio_mode(&acodec_config);
+
+ /*turn on src devices */
+
+ perform_src_routing(src_device);
+
+/* u8500_acodec_set_src_power_cntrl(src_device,ENABLE);
+ u8500_acodec_set_input_volume(src_device,50,50,USER_ALSA);
+
+ u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_2,ENABLE);
+ u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_2,50,50,USER_ALSA);
+
+ u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_3,ENABLE);
+ u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_3,50,50,USER_ALSA);
+
+ u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_4,ENABLE);
+ u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_4,50,50,USER_ALSA);
+
+ u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_5,ENABLE);
+ u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_5,50,50,USER_ALSA);
+
+ u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_6,ENABLE);
+ u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_6,50,50,USER_ALSA);
+
+ u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_D_MICROPHONE_6,ENABLE);
+ u8500_acodec_set_input_volume(AB8500_CODEC_SRC_D_MICROPHONE_6,50,50,USER_ALSA);
+
+ u8500_acodec_set_src_power_cntrl(AB8500_CODEC_SRC_FM_RX,ENABLE); */
+
+ /*turn on dest devices */
+
+ //u8500_acodec_set_dest_power_cntrl(dest_device,ENABLE);
+ u8500_acodec_allocate_da_slot(dest_device, TDM_8_CH_MODE);
+ codec_error = AB8500_CODEC_SelectOutput(dest_device);
+ u8500_acodec_set_output_volume(dest_device, 100, 100,
+ USER_ALSA);
+
+ /*u8500_acodec_set_dest_power_cntrl(AB8500_CODEC_DEST_HEADSET,ENABLE);
+ u8500_acodec_set_output_volume(AB8500_CODEC_DEST_HEADSET,100,100,USER_ALSA); */
+
+ /*u8500_acodec_set_dest_power_cntrl(AB8500_CODEC_DEST_HANDSFREE,ENABLE);
+ u8500_acodec_set_output_volume(AB8500_CODEC_DEST_HANDSFREE,100,100,USER_ALSA); */
+
+#ifdef CONFIG_U8500_AB8500_CUT10
+ codec_error =
+ AB8500_CODEC_DASlotAllocation
+ (AB8500_CODEC_DA_CHANNEL_NUMBER_5,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT12);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_daslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+
+ codec_error =
+ AB8500_CODEC_DASlotAllocation
+ (AB8500_CODEC_DA_CHANNEL_NUMBER_6,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT13);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_daslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+
+ codec_error =
+ AB8500_CODEC_DASlotAllocation
+ (AB8500_CODEC_DA_CHANNEL_NUMBER_7,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT14);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_daslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+
+ codec_error =
+ AB8500_CODEC_DASlotAllocation
+ (AB8500_CODEC_DA_CHANNEL_NUMBER_8,
+ AB8500_CODEC_CR51_TO_CR58_SLTODA_SLOT15);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_daslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+#else
+ codec_error =
+ AB8500_CODEC_DASlotAllocation
+ (AB8500_CODEC_DA_CHANNEL_NUMBER_5,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT12);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_daslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+
+ codec_error =
+ AB8500_CODEC_DASlotAllocation
+ (AB8500_CODEC_DA_CHANNEL_NUMBER_6,
+ AB8500_CODEC_CR51_TO_CR56_SLTODA_SLOT13);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_daslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+#endif
+
+ digital_lpbk_cnxt.data_size = 2048;
+
+ digital_lpbk_cnxt.rx_active = 1;
+ digital_lpbk_cnxt.tx_active = 1;
+
+ digital_lpbk_cnxt.rx_index = 0;
+ digital_lpbk_cnxt.tx_index = 2;
+
+ digital_lpbk_cnxt.buffer.area =
+ dma_alloc_coherent(NULL, digital_lpbk_cnxt.data_size,
+ &digital_lpbk_cnxt.buffer.addr,
+ GFP_KERNEL);
+ if (NULL == digital_lpbk_cnxt.buffer.area) {
+ printk("\n dma_alloc_coherent failed \n");
+ }
+#if DRIVER_DEBUG > 0
+ {
+ dump_msp_registers();
+ dump_acodec_registers();
+ }
+#endif
+
+#ifdef CONFIG_U8500_ACODEC_POLL
+ {
+ pid_t pid_rx_tx;
+ pid_rx_tx =
+ kernel_thread(digital_lpbk_msp_rx_tx_thread,
+ &digital_lpbk_cnxt,
+ CLONE_FS | CLONE_SIGHAND);
+ }
+#elif defined(CONFIG_U8500_ACODEC_DMA)
+ {
+ u8500_digital_lpbk_dma_start();
+ }
+#endif
+ } else //lpbk is disable
+ {
+
+ digital_lpbk_cnxt.rx_active = 0;
+ digital_lpbk_cnxt.tx_active = 0;
+
+ dma_free_coherent(NULL, digital_lpbk_cnxt.data_size,
+ digital_lpbk_cnxt.buffer.area,
+ digital_lpbk_cnxt.buffer.addr);
+
+ u8500_acodec_set_src_power_cntrl
+ (AB8500_CODEC_SRC_D_MICROPHONE_1, DISABLE);
+ u8500_acodec_set_src_power_cntrl
+ (AB8500_CODEC_SRC_D_MICROPHONE_2, DISABLE);
+ u8500_acodec_set_src_power_cntrl
+ (AB8500_CODEC_SRC_D_MICROPHONE_3, DISABLE);
+ u8500_acodec_set_src_power_cntrl
+ (AB8500_CODEC_SRC_D_MICROPHONE_4, DISABLE);
+
+ u8500_acodec_set_dest_power_cntrl(AB8500_CODEC_DEST_HEADSET,
+ DISABLE);
+ u8500_acodec_set_dest_power_cntrl(AB8500_CODEC_DEST_HANDSFREE,
+ DISABLE);
+
+ u8500_acodec_unsetuser(USER_ALSA);
+ u8500_acodec_close(I2S_CLIENT_MSP1, ACODEC_DISABLE_ALL);
+ }
+ return codec_error;
+}
+
+t_ab8500_codec_error perform_src_routing(t_ab8500_codec_src input_device)
+{
+ int src_type = 0;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line1;
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line2;
+ t_ab8500_codec_src input_device1;
+ t_ab8500_codec_src input_device2;
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ switch (input_device) {
+ case AB8500_CODEC_SRC_D_MICROPHONE_1:
+ {
+ src_type = MONO_SRC;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1;
+ }
+ break;
+ case AB8500_CODEC_SRC_MICROPHONE_2:
+ case AB8500_CODEC_SRC_D_MICROPHONE_2:
+ {
+ src_type = MONO_SRC;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_3:
+ case AB8500_CODEC_SRC_MICROPHONE_1A:
+ case AB8500_CODEC_SRC_MICROPHONE_1B:
+ {
+ src_type = MONO_SRC;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT3;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_4:
+ {
+ src_type = MONO_SRC;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT4;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_5:
+ {
+ src_type = MONO_SRC;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT5;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_6:
+ {
+ src_type = MONO_SRC;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT6;
+ }
+ break;
+ case AB8500_CODEC_SRC_LINEIN:
+ {
+ src_type = STEREO_SRC;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1;
+ ad_data_line2 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2;
+ input_device1 = AB8500_CODEC_SRC_LINEIN;
+ input_device2 = AB8500_CODEC_SRC_LINEIN;
+ }
+ break;
+#ifdef CONFIG_U8500_AB8500_CUT10
+ case AB8500_CODEC_SRC_D_MICROPHONE_12:
+ {
+ src_type = STEREO_SRC;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT1;
+ ad_data_line2 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT2;
+ input_device1 = AB8500_CODEC_SRC_D_MICROPHONE_1;
+ input_device2 = AB8500_CODEC_SRC_D_MICROPHONE_2;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_34:
+ {
+ src_type = STEREO_SRC;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT3;
+ ad_data_line2 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT4;
+ input_device1 = AB8500_CODEC_SRC_D_MICROPHONE_3;
+ input_device2 = AB8500_CODEC_SRC_D_MICROPHONE_4;
+ }
+ break;
+ case AB8500_CODEC_SRC_D_MICROPHONE_56:
+ {
+ src_type = STEREO_SRC;
+ ad_data_line1 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT5;
+ ad_data_line2 =
+ AB8500_CODEC_CR31_TO_CR46_SLOT_OUTPUTS_DATA_FROM_AD_OUT6;
+ input_device1 = AB8500_CODEC_SRC_D_MICROPHONE_5;
+ input_device2 = AB8500_CODEC_SRC_D_MICROPHONE_6;
+ }
+ break;
+#endif /* #ifdef CONFIG_U8500_AB8500_CUT10 */
+ }
+ if (STEREO_SRC == src_type) {
+ u8500_acodec_allocate_all_stereo_slots(ad_data_line1,
+ ad_data_line2);
+ codec_error =
+ AB8500_CODEC_SrcPowerControl(input_device1,
+ AB8500_CODEC_SRC_STATE_ENABLE);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("AB8500_CODEC_SrcPowerControl failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ g_codec_system_context.input_config[input_device1].power_state =
+ ENABLE;
+
+ u8500_acodec_set_input_volume(input_device1, 50, 50, USER_ALSA);
+
+ codec_error =
+ AB8500_CODEC_SrcPowerControl(input_device2,
+ AB8500_CODEC_SRC_STATE_ENABLE);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("AB8500_CODEC_SrcPowerControl failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ g_codec_system_context.input_config[input_device2].power_state =
+ ENABLE;
+
+ u8500_acodec_set_input_volume(input_device2, 50, 50, USER_ALSA);
+ } else {
+ u8500_acodec_allocate_all_mono_slots(ad_data_line1);
+ codec_error =
+ AB8500_CODEC_SrcPowerControl(input_device,
+ AB8500_CODEC_SRC_STATE_ENABLE);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("AB8500_CODEC_SrcPowerControl failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ g_codec_system_context.input_config[input_device].power_state =
+ ENABLE;
+
+ u8500_acodec_set_input_volume(input_device, 50, 50, USER_ALSA);
+ }
+ return AB8500_CODEC_OK;
+}
+
+t_ab8500_codec_error
+ u8500_acodec_allocate_all_mono_slots
+ (t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line1) {
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+ int i;
+
+ for (i = AB8500_CODEC_SLOT0; i <= AB8500_CODEC_SLOT7; i++) {
+ codec_error = AB8500_CODEC_ADSlotAllocation(i, ad_data_line1);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_adslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ }
+ return AB8500_CODEC_OK;
+}
+
+t_ab8500_codec_error
+ u8500_acodec_allocate_all_stereo_slots
+ (t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line1,
+ t_ab8500_codec_cr31_to_cr46_ad_data_allocation ad_data_line2) {
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+ int i;
+
+ for (i = AB8500_CODEC_SLOT0; i <= AB8500_CODEC_SLOT7; i += 2) {
+ codec_error = AB8500_CODEC_ADSlotAllocation(i, ad_data_line1);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_adslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ codec_error =
+ AB8500_CODEC_ADSlotAllocation(i + 1, ad_data_line2);
+ if (AB8500_CODEC_OK != codec_error) {
+ stm_error("ab8500_codec_adslot_allocation failed\n");
+ return AB8500_CODEC_ERROR;
+ }
+ }
+ return AB8500_CODEC_OK;
+}
+
+#ifdef CONFIG_U8500_AB8500_CUT10
+t_ab8500_codec_error
+u8500_acodec_set_burst_mode_fifo(t_u8500_pmc_rendering_state fifo_state)
+{
+
+}
+#else
+t_ab8500_codec_error
+u8500_acodec_set_burst_mode_fifo(t_u8500_pmc_rendering_state fifo_state)
+{
+ t_ab8500_codec_error ab8500_codec_error;
+ t_ab8500_codec_burst_fifo_config burst_fifo_config;
+
+ if (RENDERING_ENABLE == fifo_state) {
+ burst_fifo_config.cr104_bfifoint = 0x1;
+ burst_fifo_config.cr105_bfifotx = 0xC0;
+ burst_fifo_config.cr106_bfifofsext =
+ AB8500_CODEC_CR106_BFIFOFSEXT_6SLOT_EXTRA_CLK;
+ burst_fifo_config.cr106_bfifomsk =
+ AB8500_CODEC_CR106_BFIFOMSK_AD_DATA0_UNMASKED;
+ burst_fifo_config.cr106_bfifomstr =
+ AB8500_CODEC_CR106_BFIFOMSTR_MASTER_MODE;
+ burst_fifo_config.cr106_bfifostrt =
+ AB8500_CODEC_CR106_BFIFOSTRT_RUNNING;
+ burst_fifo_config.cr107_bfifosampnr = 0x100;
+ burst_fifo_config.cr108_bfifowakeup = 0x1;
+
+ ab8500_codec_error =
+ AB8500_CODEC_ConfigureBurstFifo(&burst_fifo_config);
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return ab8500_codec_error;
+ }
+
+ ab8500_codec_error = AB8500_CODEC_EnableBurstFifo();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return ab8500_codec_error;
+ }
+
+ printk("\n Burst mode activated\n");
+ } else if (RENDERING_DISABLE == fifo_state) {
+ ab8500_codec_error = AB8500_CODEC_DisableBurstFifo();
+ if (AB8500_CODEC_OK != ab8500_codec_error) {
+ return ab8500_codec_error;
+ }
+ printk("\n Burst mode deactivated\n");
+ }
+ return AB8500_CODEC_OK;
+}
+#endif
+/**
+* u8500_acodec_set_user
+*
+* Set the current user for acodec.
+*/
+
+t_ab8500_codec_error u8500_acodec_setuser(t_acodec_user user)
+{
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ FUNC_ENTER();
+
+ if ((g_codec_system_context.cur_user == NO_USER)
+ || (g_codec_system_context.cur_user == user))
+ g_codec_system_context.cur_user = user;
+ else {
+ stm_error
+ (" Trying to acces audiocodec already in use by user %d\n",
+ g_codec_system_context.cur_user);
+ return AB8500_CODEC_ERROR;
+ }
+ FUNC_EXIT();
+ return (codec_error);
+}
+
+/**
+* u8500_acodec_unset_user
+*
+* Unset the current user for acodec.
+*/
+
+t_ab8500_codec_error u8500_acodec_unsetuser(t_acodec_user user)
+{
+ t_ab8500_codec_error codec_error = AB8500_CODEC_OK;
+
+ if (g_codec_system_context.cur_user != user) {
+ stm_error
+ (" Trying to free audiocodec already in use by other user %d\n",
+ g_codec_system_context.cur_user);
+ return AB8500_CODEC_ERROR;
+ } else
+ g_codec_system_context.cur_user = NO_USER;
+
+ return (codec_error);
+}
+
+#if DRIVER_DEBUG > 0
+t_ab8500_codec_error dump_acodec_registers()
+{
+ u8 i;
+
+ for (i = 0; i <= 0x6D; i++)
+ stm_dbg(DBG_ST.acodec, "block=0x0D, adr=%x = %x\n", i,
+ ab8500_read(AB8500_AUDIO, i));
+
+ /*for (i = 0; i < 0x5e; i++)
+ stm_dbg(DBG_ST.acodec,"\n block 1,reg =%d val %x", i, ab8500_read(AB8500_AUDIO, i));
+ */
+ return 0;
+}
+
+t_ab8500_codec_error dump_msp_registers()
+{
+ int i;
+
+ stm_dbg(DBG_ST.acodec, "\nMSP_1 base add = 0x%x\n",
+ (unsigned int)U8500_MSP1_BASE);
+
+ for (i = 0; i < 0x40; i += 4)
+ stm_dbg(DBG_ST.acodec, "msp[0x%x]=0x%x\n", i,
+ readl((char *)(IO_ADDRESS(U8500_MSP1_BASE) + i)));
+
+ return 0;
+}
+
+EXPORT_SYMBOL(dump_msp_registers);
+EXPORT_SYMBOL(dump_acodec_registers);
+#endif
+
+/**
+* u8500_acodec_powerdown
+*
+* This function power off the audio codec.
+*/
+void u8500_acodec_powerdown()
+{
+ AB8500_CODEC_PowerDown();
+}
+
+/**
+* u8500_acodec_init
+*
+* This is the init function for STW5098 audiocodec driver.
+*/
+
+static int i2sdrv_probe(struct i2s_device *i2s)
+{
+
+ /* Allocate driver data */
+ try_module_get(i2s->controller->dev.parent->driver->owner);
+
+ /* Allocate memory to i2sdrv structure */
+ i2sdrv[i2s->chip_select] =
+ kzalloc(sizeof(*i2sdrv[i2s->chip_select]), GFP_KERNEL);
+ if (!i2sdrv[i2s->chip_select])
+ return -ENOMEM;
+
+ /* Initialize the driver data */
+ i2sdrv[i2s->chip_select]->i2s = i2s;
+ i2sdrv[i2s->chip_select]->flag = -1;
+ i2sdrv[i2s->chip_select]->tx_status = 0;
+ i2sdrv[i2s->chip_select]->rx_status = 0;
+ spin_lock_init(&i2sdrv[i2s->chip_select]->i2s_lock);
+
+ i2s_set_drvdata(i2s, (void *)i2sdrv[i2s->chip_select]);
+ return 0;
+}
+
+static int i2sdrv_remove(struct i2s_device *i2s)
+{
+ struct i2sdrv_data *i2sdrv = i2s_get_drvdata(i2s);
+
+ spin_lock_irq(&i2sdrv->i2s_lock);
+ i2sdrv->i2s = NULL;
+ i2s_set_drvdata(i2s, NULL);
+ spin_unlock_irq(&i2sdrv->i2s_lock);
+
+ stm_dbg(DBG_ST.acodec, "Entering AUDIOTRG_CODEC_DeIni\n");
+ stm_dbg(DBG_ST.acodec, "leaving AUDIOTRG_CODEC_DeIni\n");
+ module_put(i2s->controller->dev.parent->driver->owner);
+ printk("Remove of I2S gets called\n");
+ return 0;
+}
+static const struct i2s_device_id acodec_id_table[] = {
+ {"i2s_device.2", 0, 0},
+ {"i2s_device.1", 0, 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2s, acodec_id_table);
+
+static struct i2s_driver i2sdrv_i2s = {
+ .driver = {
+ .name = "u8500_acodec",
+ .owner = THIS_MODULE,
+ },
+ .probe = i2sdrv_probe,
+ .remove = __devexit_p(i2sdrv_remove),
+ .id_table = acodec_id_table,
+
+};
+
+static void ab8500_codec_power_init(void)
+{
+ __u8 data, old_data;
+
+ old_data =
+ ab8500_read(AB8500_SYS_CTRL2_BLOCK, (AB8500_CTRL3_REG & 0xFF));
+
+ data = 0xFE & old_data;
+ ab8500_write(AB8500_SYS_CTRL2_BLOCK, (AB8500_CTRL3_REG & 0xFF), data); //0x0200
+
+ data = 0x02 | old_data;
+ ab8500_write(AB8500_SYS_CTRL2_BLOCK, (AB8500_CTRL3_REG & 0xFF), data); //0x0200
+
+ old_data =
+ ab8500_read(AB8500_SYS_CTRL2_BLOCK,
+ (AB8500_SYSULPCLK_CTRL1_REG & 0xFF));
+#ifdef CONFIG_U8500_AB8500_CUT10
+ data = 0x18 | old_data;
+#else
+ data = 0x10 | old_data;
+#endif
+ ab8500_write(AB8500_SYS_CTRL2_BLOCK, (AB8500_SYSULPCLK_CTRL1_REG & 0xFF), data); //0x020B
+
+ old_data =
+ ab8500_read(AB8500_REGU_CTRL1, (AB8500_REGU_MISC1_REG & 0xFF));
+ data = 0x04 | old_data;
+ ab8500_write(AB8500_REGU_CTRL1, (AB8500_REGU_MISC1_REG & 0xFF), data); //0x380
+
+ old_data =
+ ab8500_read(AB8500_REGU_CTRL1,
+ (AB8500_REGU_VAUDIO_SUPPLY_REG & 0xFF));
+ data = 0x5E | old_data;
+ ab8500_write(AB8500_REGU_CTRL1, (AB8500_REGU_VAUDIO_SUPPLY_REG & 0xFF), data); //0x0383
+
+#ifdef CONFIG_U8500_AB8500_CUT10
+ old_data = ab8500_read(AB8500_MISC, (AB8500_GPIO_DIR4_REG & 0xFF));
+ data = 0x54 | old_data;
+ ab8500_write(AB8500_MISC, (AB8500_GPIO_DIR4_REG & 0xFF), data); //0x1013
+#endif
+}
+
+/**
+* u8500_acodec_deinit
+*
+* exit function for STW5098 audiocodec driver.
+*/
+static int check_device_id()
+{
+ __u8 data;
+
+ data = ab8500_read(AB8500_MISC, (0x80 & 0xFF));
+ if (((data & 0xF0) == 0x10) || ((data & 0xF0) == 0x11)) {
+ /* V1 version */
+#ifndef CONFIG_U8500_AB8500_CUT10
+ printk("ERROR: AB8500 hardware detected is CUT1x\n");
+ return -ENODEV;
+#endif
+ } else {
+#ifndef CONFIG_U8500_AB8500_ED
+ /* ED version */
+ printk("ERROR: AB8500 hardware detected is EarlyDrop\n");
+ return -ENODEV;
+#endif
+ }
+ return 0;
+}
+
+static int __init u8500_acodec_init(void)
+{
+ int status, ret_val;
+ t_ab8500_codec_error error;
+
+ ret_val = check_device_id();
+ if (0 != ret_val)
+ return ret_val;
+
+ status = i2s_register_driver(&i2sdrv_i2s);
+ if (status < 0) {
+ printk("Unable to register i2s driver\n");
+ return status;
+ }
+
+ /*Initialize Audiocodec */
+
+ ab8500_codec_power_init();
+
+ AB8500_CODEC_Init(TRG_CODEC_ADDRESS_ON_SPI_BUS);
+
+ /* Reset CODEC */
+ error = AB8500_CODEC_Reset();
+ if (AB8500_CODEC_OK != error) {
+ stm_error("Error in AB8500_CODEC_Reset\n");
+ return -1;
+ }
+
+ stm_dbg(DBG_ST.acodec, " leaving u8500_acodec_init() \n");
+ return 0;
+}
+
+static void __exit u8500_acodec_deinit(void)
+{
+ stm_dbg(DBG_ST.acodec, "Entering AUDIOTRG_CODEC_DeIni\n");
+ stm_dbg(DBG_ST.acodec, "leaving AUDIOTRG_CODEC_DeIni\n");
+ i2s_unregister_driver(&i2sdrv_i2s);
+}
+
+module_init(u8500_acodec_init);
+module_exit(u8500_acodec_deinit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AB8500 stw5098 audiocodec driver");
+
+/* exported function by audiocodec to be used by SAA driver and ALSA driver */
+
+EXPORT_SYMBOL(u8500_acodec_open);
+EXPORT_SYMBOL(u8500_acodec_close);
+EXPORT_SYMBOL(u8500_acodec_send_data);
+EXPORT_SYMBOL(u8500_acodec_receive_data);
+EXPORT_SYMBOL(u8500_acodec_rates);
+EXPORT_SYMBOL(u8500_acodec_powerdown);
+EXPORT_SYMBOL(u8500_acodec_setuser);
+EXPORT_SYMBOL(u8500_acodec_unsetuser);
+EXPORT_SYMBOL(u8500_acodec_enable_audio_mode);
+//EXPORT_SYMBOL(u8500_acodec_enable_voice_mode);
+EXPORT_SYMBOL(u8500_acodec_get_output_volume);
+EXPORT_SYMBOL(u8500_acodec_get_input_volume);
+EXPORT_SYMBOL(u8500_acodec_set_output_volume);
+EXPORT_SYMBOL(u8500_acodec_set_input_volume);
+EXPORT_SYMBOL(u8500_acodec_select_input);
+EXPORT_SYMBOL(u8500_acodec_select_output);
+
+t_ab8500_codec_error AB8500_CODEC_Write(IN t_uint8 register_offset,
+ IN t_uint8 count, IN t_uint8 * ptr_data)
+{
+ int i;
+ u32 address;
+
+ for (i = 0; i < count; i++) {
+ address = (AB8500_AUDIO << 8) | (register_offset + i);
+ ab8500_write(AB8500_AUDIO, address, ptr_data[i]);
+ }
+ return AB8500_CODEC_OK;
+}
+
+t_ab8500_codec_error AB8500_CODEC_Read(IN t_uint8 register_offset,
+ IN t_uint8 count,
+ IN t_uint8 * dummy_data,
+ IN t_uint8 * ptr_data)
+{
+ int i;
+ u32 address;
+
+ dummy_data = dummy_data; /*keep compiler happy */
+
+ for (i = 0; i < count; i++) {
+ address = (AB8500_AUDIO << 8) | (register_offset + i);
+ ptr_data[i] = ab8500_read(AB8500_AUDIO, address);
+ }
+
+ return AB8500_CODEC_OK;
+}
+
+EXPORT_SYMBOL(u8500_acodec_set_src_power_cntrl);
+EXPORT_SYMBOL(u8500_acodec_set_burst_mode_fifo);
+EXPORT_SYMBOL(u8500_acodec_get_dest_power_state);
+EXPORT_SYMBOL(lpbk_state_in_texts);
+EXPORT_SYMBOL(u8500_acodec_toggle_playback_mute_control);
+EXPORT_SYMBOL(u8500_acodec_set_dest_power_cntrl);
+EXPORT_SYMBOL(power_state_in_texts);
+EXPORT_SYMBOL(u8500_acodec_toggle_capture_mute_control);
+EXPORT_SYMBOL(u8500_acodec_toggle_analog_lpbk);
+EXPORT_SYMBOL(u8500_acodec_toggle_digital_lpbk);
+EXPORT_SYMBOL(tdm_mode_state_in_texts);
+EXPORT_SYMBOL(switch_state_in_texts);
+EXPORT_SYMBOL(pcm_rendering_state_in_texts);
+EXPORT_SYMBOL(direct_rendering_state_in_texts);
+EXPORT_SYMBOL(u8500_acodec_get_src_power_state);
+EXPORT_SYMBOL(i2sdrv);
+EXPORT_SYMBOL(second_config);
diff --git a/tools/svpboot/Makefile b/tools/svpboot/Makefile
new file mode 100644
index 00000000000..59aff9b08c8
--- /dev/null
+++ b/tools/svpboot/Makefile
@@ -0,0 +1,21 @@
+CC = $(CROSS_COMPILE)gcc
+LD = $(CROSS_COMPILE)ld
+KERNELDIR ?= ../..
+
+SCRIPT = svpboot.ld
+ASFLAGS = -D__ASSEMBLY__ -I$(KERNELDIR)/include -I$(KERNELDIR)/arch/arm/include
+ASFLAGS += -I$(KERNELDIR)/arch/arm/mach-ux500/include
+LDFLAGS = -nostdlib -Wl,-T,$(SCRIPT)
+
+OBJS = svp5500 svp8500v1 svp8500v2
+
+all:
+ $(CC) $(ASFLAGS) -c svpboot.S -DSVP5500 -o svp5500.o
+ $(CC) $(ASFLAGS) -c svpboot.S -DSVP8500V1 -o svp8500v1.o
+ $(CC) $(ASFLAGS) -c svpboot.S -DSVP8500V2 -o svp8500v2.o
+ $(CC) $(LDFLAGS) svp5500.o -o svp5500
+ $(CC) $(LDFLAGS) svp8500v1.o -o svp8500v1
+ $(CC) $(LDFLAGS) svp8500v2.o -o svp8500v2
+
+clean:
+ rm -rf $(OBJS) *.o *.bin
diff --git a/tools/svpboot/README b/tools/svpboot/README
new file mode 100644
index 00000000000..010eabed64b
--- /dev/null
+++ b/tools/svpboot/README
@@ -0,0 +1,18 @@
+BUILDING SVPBOOT:
+
+ $ CROSS_COMPILE=<your-arm-cc> make -C tools/svpboot/
+
+RUNNING SVP WITH SVPBOOT:
+
+ Use the svpboot ELF binaries appropriate for your SVP as the "-arm_lib"
+ argument, and use "-dram_img" to load the Image of the kernel to 0x8000.
+
+ For example, on SVP5500:
+
+ $ tlm_run.exe -arm_lib tools/svpboot/svp5500 -dram_img 0x8000 \
+ arch/arm/boot/Image 0x3000000 initrd -open_mcde -open_telnet
+
+ For example, on SVP8500v1:
+
+ $ tlm_run.exe -arm_lib tools/svpboot/svp8500v1 -dram_img 0x8000 \
+ arch/arm/boot/Image 0x800000 initrd -open_mcde -open_telnet
diff --git a/tools/svpboot/svp5500.S b/tools/svpboot/svp5500.S
new file mode 100644
index 00000000000..73feb880405
--- /dev/null
+++ b/tools/svpboot/svp5500.S
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/amba/serial.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+#define MACH_TYPE MACH_TYPE_U5500
+#define CMDLINE \
+ "root=/dev/ram0 init=init rw " \
+ "console=ttyAMA0,115200n8 " \
+ "mem=24MB@0 mem=208M@48M " \
+ "initrd=0x3000000,60M " \
+ "earlyprintk " \
+ "memmap=0x01800000$0x01800000 " \
+ "mloader_helper.shm_total_size=0x00030000"
+
+#define CPU1_WAKEMAGIC_ADDR (U5500_BACKUPRAM0_BASE + 0x1ff0)
+
+#define NMK_GPIO_AFSLA 0x20
+
+.macro init_console_uart
+ /* Enable GPIOs for UART0 (28, 29 -> AltA) */
+ ldr r5, =U5500_GPIO0_BASE
+ ldr r6, =((1 << 28) | (1 << 29))
+ str r6, [r5, #NMK_GPIO_AFSLA]
+
+ /* Enable UART0 */
+ ldr r5, =U5500_UART0_BASE
+ ldr r6, =(UART011_CR_TXE | UART01x_CR_UARTEN)
+ str r6, [r5, #UART011_CR]
+.endm
diff --git a/tools/svpboot/svp8500v1.S b/tools/svpboot/svp8500v1.S
new file mode 100644
index 00000000000..d3507e1031a
--- /dev/null
+++ b/tools/svpboot/svp8500v1.S
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/amba/serial.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+#define MACH_TYPE MACH_TYPE_SVP8500V1
+#define CMDLINE \
+ "root=/dev/ram0 init=init rw " \
+ "console=ttyAMA2,115200n8 " \
+ "mem=256M " \
+ "initrd=0x800000,60M " \
+ "earlyprintk" \
+
+#define CPU1_WAKEMAGIC_ADDR (U8500_BACKUPRAM0_BASE + 0x1ff0)
+
+#define NMK_GPIO_AFSLA 0x20
+#define NMK_GPIO_AFSLB 0x24
+
+.macro init_console_uart
+ /* Enable GPIOs for UART2 (29, 30 -> AltC) */
+ ldr r5, =U8500_GPIO0_BASE
+ ldr r6, =((1 << 29) | (1 << 30))
+ str r6, [r5, #NMK_GPIO_AFSLA]
+ str r6, [r5, #NMK_GPIO_AFSLB]
+
+ /* Enable UART2 */
+ ldr r5, =U8500_UART2_BASE
+ ldr r6, =(UART011_CR_TXE | UART01x_CR_UARTEN)
+ str r6, [r5, #UART011_CR]
+.endm
diff --git a/tools/svpboot/svp8500v2.S b/tools/svpboot/svp8500v2.S
new file mode 100644
index 00000000000..b8235d2defe
--- /dev/null
+++ b/tools/svpboot/svp8500v2.S
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/amba/serial.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+#define MACH_TYPE MACH_TYPE_SVP8500V2
+#define CMDLINE \
+ "root=/dev/ram0 init=init rw " \
+ "console=ttyAMA2,115200n8 " \
+ "mem=256M " \
+ "initrd=0x800000,60M " \
+ "earlyprintk" \
+
+#define CPU1_WAKEMAGIC_ADDR (U8500_BACKUPRAM0_BASE + 0x1ff0)
+
+#define NMK_GPIO_AFSLA 0x20
+#define NMK_GPIO_AFSLB 0x24
+
+.macro init_console_uart
+ /* Enable GPIOs for UART2 (29, 30 -> AltC) */
+ ldr r5, =U8500_GPIO0_BASE
+ ldr r6, =((1 << 29) | (1 << 30))
+ str r6, [r5, #NMK_GPIO_AFSLA]
+ str r6, [r5, #NMK_GPIO_AFSLB]
+
+ /* Enable UART2 */
+ ldr r5, =U8500_UART2_BASE
+ ldr r6, =(UART011_CR_TXE | UART01x_CR_UARTEN)
+ str r6, [r5, #UART011_CR]
+.endm
diff --git a/tools/svpboot/svpboot.S b/tools/svpboot/svpboot.S
new file mode 100644
index 00000000000..51c478f1b6d
--- /dev/null
+++ b/tools/svpboot/svpboot.S
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+#ifdef SVP5500
+#include "svp5500.S"
+#elif defined(SVP8500V1)
+#include "svp8500v1.S"
+#elif defined(SVP8500V2)
+#include "svp8500v2.S"
+#endif
+
+ .text
+
+ENTRY(_start)
+ /* Enable SWP */
+ mrc p15, 0, r1, c1, c0, 0
+ orr r1, r1, #1 << 10
+ mcr p15, 0, r1, c1, c0, 0
+
+ mrc p15, 0, r3, c0, c0, 5
+ ands r3, r3, #0xf
+ bne core2
+
+ init_console_uart
+
+ mov r0, #0
+ ldr r1, =MACH_TYPE
+ ldr r2, =taglist
+
+ b kernel
+
+core2:
+ ldr r0, =CPU1_WAKEMAGIC_ADDR
+ ldr r2, =0xA1FEED01
+
+1: ldr r1, [r0]
+ cmp r1, r2
+ bne 1b
+
+ /* Jump Addr is at WakeMagic + 4 */
+ ldr r1, [r0, #4]
+ bx r1
+
+ .data
+#define ATAG_CORE 0x54410001
+#define ATAG_CMDLINE 0x54410009
+#define ATAG_NONE 0x00000000
+
+taglist:
+ .long 2
+ .long ATAG_CORE
+ .long 2 + (cmdlineend - cmdlinestart) / 4
+ .long ATAG_CMDLINE
+cmdlinestart:
+ .ascii CMDLINE
+ .align 2
+cmdlineend:
+ .long 0
+ .long ATAG_NONE
diff --git a/tools/svpboot/svpboot.ld b/tools/svpboot/svpboot.ld
new file mode 100644
index 00000000000..e6a5af49d88
--- /dev/null
+++ b/tools/svpboot/svpboot.ld
@@ -0,0 +1,11 @@
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0x0;
+ .text : { *(.text) }
+ . = 0x100;
+ .data : { *(.data) }
+ PROVIDE (kernel = 0x8000);
+}