Merge branch 'android-bridge-2.6.29'
* 'android-bridge-2.6.29'
* of git://dev.omapzoom.org/pub/scm/tidspbridge/kernel-dspbridge:
Mailbox: flush pending deferred works before freeing blk queue
Mailbox: free mailbox interrupt before freeing blk queue
Mailbox: Check valid registered callback before calling
DSPBRIDGE: Initialize status in bridge_release
DSPBRIDGE: fix regression introduced by other patch
DSPBRIDGE: DSP recovery feature
Revert "DSPBRIDGE: cache operation against kernel address instead of user's"
Revert "DSPBRIDGE: Replace flushtype with ulFlags"
Revert "DSPBRIDGE: cache against kernel address fix"
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 7453ae8..f48c25b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -160,6 +160,12 @@
if OPROFILE
+config OPROFILE_OMAP_GPTIMER
+ def_bool y
+ depends on ARCH_OMAP
+ select CONFIG_OMAP_32K_TIMER
+ select CONFIG_OMAP_DM_TIMER
+
config OPROFILE_ARMV6
def_bool y
depends on CPU_V6 && !SMP
@@ -174,7 +180,7 @@
bool
config OPROFILE_ARMV7
- def_bool y
+ def_bool n
depends on CPU_V7 && !SMP
bool
@@ -709,18 +715,49 @@
comment "errata"
config ARM_ERRATA_430973
- bool "430973: Stale prediction on replaced interworking branch on Cortex-A8"
- depends on CPU_V7
- default n
- help
- This option enables the workaround for the 430973 Cortex-A8
- (r1p0) erratum. If a code sequence containing an ARM/Thumb
- interworking branch is replaced with another code sequence
- at the same virtual address, whether due to self-modifying
- code or virtual to physical address re-mapping, Cortex-A8
- does not recover from the stale interworking branch
- prediction. This results in Cortex-A8 executing the new code
- sequence in the incorrect ARM or Thumb state.
+
+ bool "ARM errata: Stale prediction on replaced interworking branch"
+ depends on CPU_V7
+ help
+ This option enables the workaround for the 430973 Cortex-A8
+ (r1p0..r1p2) erratum. If a code sequence containing an ARM/Thumb
+ interworking branch is replaced with another code sequence at the
+ same virtual address, whether due to self-modifying code or virtual
+ to physical address re-mapping, Cortex-A8 does not recover from the
+ stale interworking branch prediction. This results in Cortex-A8
+ executing the new code sequence in the incorrect ARM or Thumb state.
+ The workaround enables the BTB/BTAC operations by setting ACTLR.IBE
+ and also flushes the branch target cache at every context switch.
+ Note that setting specific bits in the ACTLR register may not be
+ available in non-secure mode.
+
+config ARM_ERRATA_451027
+ bool "Neon loads/stores may incorrectly report data abort on Cortex-A8"
+ depends on CPU_V7 && NEON
+ default n
+ help
+ This option enables the workaround for the erratum 451027
+ Cortex-A8(r1p0,r1p1,r1p2,r1p3).
+ For a specific sequence of load and store operations, it is possible
+ for an erroneous abort response to be reported on a Neon load or
+ store instruction.
+ This workaround fixes the AXI errors generated on cache lines issue.
+
+config ARM_ERRATUM_451034
+ bool "Enable workaround for ARM erratum 451034"
+ depends on VFPv3 && NEON
+ help
+ On Cortex-A8 r1p0 and r1p1, executing a NEON store with an integer
+ store in the store buffer, can cause a processor deadlock under
+ certain conditions.
+
+ See ARM Cortex-A8 Errata Notice (PR120-PRDC-008070) for full details.
+
+ Say Y to include a partial workaround.
+
+ WARNING: Even with this option enabled, userspace code can trigger
+ the deadlock. To safely run untrusted code, a different fix is
+ required.
endmenu
diff --git a/arch/arm/configs/zoom2_pm_defconfig b/arch/arm/configs/omap_3430sdp_android_defconfig
similarity index 82%
rename from arch/arm/configs/zoom2_pm_defconfig
rename to arch/arm/configs/omap_3430sdp_android_defconfig
index 28988a3..2fe5ab2 100644
--- a/arch/arm/configs/zoom2_pm_defconfig
+++ b/arch/arm/configs/omap_3430sdp_android_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.29-omap1
-# Mon Aug 3 10:55:29 2009
+# Tue Oct 6 20:05:14 2009
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -23,6 +23,8 @@
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_OPROFILE_OMAP_GPTIMER=y
+# CONFIG_OPROFILE_ARMV7 is not set
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -94,7 +96,10 @@
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
@@ -108,7 +113,7 @@
# CONFIG_MODULE_FORCE_LOAD is not set
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_BLOCK=y
# CONFIG_LBD is not set
@@ -198,22 +203,38 @@
CONFIG_OMAP_MUX_DEBUG=y
CONFIG_OMAP_MUX_WARNINGS=y
CONFIG_OMAP_MCBSP=y
-# CONFIG_OMAP_MBOX_FWK is not set
-# CONFIG_OMAP_IOMMU is not set
+CONFIG_OMAP_MBOX_FWK=y
+CONFIG_OMAP_IOMMU=y
# CONFIG_OMAP_MPU_TIMER is not set
CONFIG_OMAP_32K_TIMER=y
# CONFIG_OMAP3_DEBOBS is not set
CONFIG_OMAP_32K_TIMER_HZ=128
CONFIG_OMAP_TICK_GPTIMER=1
CONFIG_OMAP_DM_TIMER=y
-# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
# CONFIG_OMAP_LL_DEBUG_UART2 is not set
# CONFIG_OMAP_LL_DEBUG_UART3 is not set
-CONFIG_OMAP_LL_DEBUG_UART_EXT=y
+# CONFIG_OMAP_LL_DEBUG_UART_EXT is not set
CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# USBHOST Port Configuration
+#
+CONFIG_OMAP_EHCI_PHY_MODE_PORT1=y
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT1 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT1 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT1 is not set
+CONFIG_OMAP_EHCI_PHY_MODE_PORT2=y
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT2 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT2 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT2 is not set
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT3 is not set
+CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT3=y
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT3 is not set
# CONFIG_OMAP_PM_NONE is not set
# CONFIG_OMAP_PM_NOOP is not set
CONFIG_OMAP_PM_SRF=y
+# CONFIG_OMAP3_MPU_L2_CACHE_WORKAROUND is not set
CONFIG_ARCH_OMAP34XX=y
CONFIG_ARCH_OMAP3430=y
@@ -222,10 +243,10 @@
#
# CONFIG_MACH_NOKIA_RX51 is not set
# CONFIG_MACH_OMAP_LDP is not set
-CONFIG_MACH_OMAP_ZOOM2=y
-CONFIG_WIFI_CONTROL_FUNC=y
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+# CONFIG_L2CACHE_OMAP3_DISABLE is not set
# CONFIG_TIWLAN_SDIO is not set
-# CONFIG_MACH_OMAP_3430SDP is not set
+CONFIG_MACH_OMAP_3430SDP=y
# CONFIG_MACH_OMAP3EVM is not set
# CONFIG_MACH_OMAP3_BEAGLE is not set
# CONFIG_MACH_OVERO is not set
@@ -256,13 +277,14 @@
# CONFIG_CPU_ICACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_CPU_USER_L2_PLE_ACCESS is not set
# CONFIG_HAS_TLS_REG is not set
# CONFIG_OUTER_CACHE is not set
#
# errata
#
-# CONFIG_ARM_ERRATA_430973 is not set
+CONFIG_ARM_ERRATA_430973=y
#
# Bus support
@@ -301,6 +323,7 @@
CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
CONFIG_UNEVICTABLE_LRU=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
# CONFIG_LEDS is not set
CONFIG_ALIGNMENT_TRAP=y
@@ -329,7 +352,7 @@
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
-# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_MIN_TICKS=10
CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER=1000
@@ -349,7 +372,7 @@
# CONFIG_FPE_FASTFPE is not set
CONFIG_VFP=y
CONFIG_VFPv3=y
-CONFIG_NEON=y
+# CONFIG_NEON is not set
#
# Userspace binary formats
@@ -357,7 +380,7 @@
CONFIG_BINFMT_ELF=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_HAVE_AOUT=y
-CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
CONFIG_BINFMT_MISC=y
#
@@ -371,7 +394,15 @@
CONFIG_SUSPEND=y
# CONFIG_PM_TEST_SUSPEND is not set
CONFIG_SUSPEND_FREEZER=y
-# CONFIG_WAKELOCK is not set
+CONFIG_HAS_WAKELOCK=y
+CONFIG_HAS_EARLYSUSPEND=y
+CONFIG_WAKELOCK=y
+CONFIG_WAKELOCK_STAT=y
+CONFIG_USER_WAKELOCK=y
+CONFIG_EARLYSUSPEND=y
+# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set
+# CONFIG_CONSOLE_EARLYSUSPEND is not set
+CONFIG_FB_EARLYSUSPEND=y
# CONFIG_APM_EMULATION is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_NET=y
@@ -386,12 +417,12 @@
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
# CONFIG_XFRM_SUB_POLICY is not set
-CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_MIGRATE is not set
# CONFIG_XFRM_STATISTICS is not set
CONFIG_NET_KEY=y
-CONFIG_NET_KEY_MIGRATE=y
+# CONFIG_NET_KEY_MIGRATE is not set
CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
+# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
@@ -400,7 +431,6 @@
CONFIG_IP_PNP_RARP=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
@@ -447,44 +477,17 @@
# CONFIG_HAMRADIO is not set
# CONFIG_CAN is not set
# CONFIG_IRDA is not set
-CONFIG_BT=y
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-# CONFIG_BT_BNEP_MC_FILTER is not set
-# CONFIG_BT_BNEP_PROTO_FILTER is not set
-CONFIG_BT_HIDP=y
-
-#
-# Bluetooth device drivers
-#
-# CONFIG_BT_HCIBTUSB is not set
-# CONFIG_BT_HCIBTSDIO is not set
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-# CONFIG_BT_HCIUART_BCSP is not set
-CONFIG_BT_HCIUART_LL=y
-# CONFIG_BT_HCIBCM203X is not set
-# CONFIG_BT_HCIBPA10X is not set
-# CONFIG_BT_HCIBFUSB is not set
-# CONFIG_BT_HCIBRF6150 is not set
-# CONFIG_BT_HCIH4P is not set
-# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
# CONFIG_PHONET is not set
CONFIG_WIRELESS=y
# CONFIG_CFG80211 is not set
CONFIG_WIRELESS_OLD_REGULATORY=y
-CONFIG_WIRELESS_EXT=y
-CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
# CONFIG_MAC80211 is not set
# CONFIG_WIMAX is not set
-CONFIG_RFKILL=y
-CONFIG_RFKILL_PM=y
-# CONFIG_RFKILL_INPUT is not set
+# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
#
@@ -501,11 +504,9 @@
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
-CONFIG_CONNECTOR=y
-CONFIG_PROC_EVENTS=y
+# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
-CONFIG_MTD_DEBUG=y
-CONFIG_MTD_DEBUG_VERBOSE=0
+# CONFIG_MTD_DEBUG is not set
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_TESTS is not set
@@ -530,8 +531,10 @@
#
# RAM/ROM/Flash chip drivers
#
-# CONFIG_MTD_CFI is not set
+CONFIG_MTD_CFI=y
# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
CONFIG_MTD_MAP_BANK_WIDTH_1=y
CONFIG_MTD_MAP_BANK_WIDTH_2=y
CONFIG_MTD_MAP_BANK_WIDTH_4=y
@@ -542,6 +545,10 @@
CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I4 is not set
# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
@@ -550,6 +557,9 @@
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
# CONFIG_MTD_PLATRAM is not set
#
@@ -570,17 +580,22 @@
# CONFIG_MTD_DOC2001PLUS is not set
CONFIG_MTD_NAND=y
# CONFIG_MTD_NAND_VERIFY_WRITE is not set
-# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND_ECC_SMC=y
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
# CONFIG_MTD_NAND_GPIO is not set
CONFIG_MTD_NAND_OMAP2=y
-CONFIG_MTD_NAND_OMAP_HWECC=y
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
# CONFIG_MTD_NAND_PLATFORM is not set
# CONFIG_MTD_ALAUDA is not set
-# CONFIG_MTD_ONENAND is not set
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+# CONFIG_MTD_ONENAND_OTP is not set
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+# CONFIG_MTD_ONENAND_SIM is not set
#
# LPDDR flash memory drivers
@@ -600,7 +615,7 @@
# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_SIZE=16384
# CONFIG_BLK_DEV_XIP is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -611,7 +626,6 @@
# CONFIG_ENCLOSURE_SERVICES is not set
# CONFIG_KERNEL_DEBUGGER_CORE is not set
# CONFIG_UID_STAT is not set
-# CONFIG_WL127X_RFKILL is not set
# CONFIG_C2PORT is not set
#
@@ -661,7 +675,10 @@
# CONFIG_SCSI_ISCSI_ATTRS is not set
# CONFIG_SCSI_SAS_LIBSAS is not set
# CONFIG_SCSI_SRP_ATTRS is not set
-# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_DH is not set
# CONFIG_ATA is not set
# CONFIG_MD is not set
@@ -670,16 +687,16 @@
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
-CONFIG_TUN=y
+# CONFIG_TUN is not set
# CONFIG_VETH is not set
# CONFIG_PHYLIB is not set
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_AX88796 is not set
-# CONFIG_SMC91X is not set
+CONFIG_SMC91X=y
# CONFIG_DM9000 is not set
# CONFIG_ENC28J60 is not set
-CONFIG_SMC911X=y
+# CONFIG_SMC911X is not set
# CONFIG_SMSC911X is not set
# CONFIG_DNET is not set
# CONFIG_IBM_NEW_EMAC_ZMII is not set
@@ -690,8 +707,8 @@
# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
#
# Wireless LAN
@@ -712,7 +729,6 @@
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
# CONFIG_USB_USBNET is not set
-# CONFIG_USB_HSO is not set
# CONFIG_WAN is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
@@ -749,12 +765,12 @@
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_KEYBOARD_OMAP is not set
CONFIG_KEYBOARD_TWL4030=y
-# CONFIG_KEYBOARD_GPIO is not set
+CONFIG_KEYBOARD_GPIO=y
# 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_ADS7846=y
# CONFIG_TOUCHSCREEN_FUJITSU is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
@@ -763,7 +779,7 @@
# CONFIG_TOUCHSCREEN_INEXIO is not set
# CONFIG_TOUCHSCREEN_MK712 is not set
# CONFIG_TOUCHSCREEN_PENMOUNT is not set
-CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI=y
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set
# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
# CONFIG_TOUCHSCREEN_TSC2005 is not set
@@ -771,17 +787,7 @@
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_TOUCHSCREEN_TSC2007 is not set
-CONFIG_INPUT_MISC=y
-# CONFIG_INPUT_ATI_REMOTE is not set
-# CONFIG_INPUT_ATI_REMOTE2 is not set
-# CONFIG_INPUT_KEYSPAN_REMOTE is not set
-# CONFIG_INPUT_POWERMATE is not set
-# CONFIG_INPUT_YEALINK is not set
-# CONFIG_INPUT_CM109 is not set
-CONFIG_INPUT_TWL4030_PWRBUTTON=y
-# CONFIG_INPUT_UINPUT is not set
-# CONFIG_INPUT_GPIO is not set
-# CONFIG_INPUT_KEYCHORD is not set
+# CONFIG_INPUT_MISC is not set
#
# Hardware I/O ports
@@ -867,8 +873,8 @@
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
-CONFIG_TWL4030_MADC=y
-CONFIG_TWL4030_POWEROFF=y
+# CONFIG_TWL4030_MADC is not set
+# CONFIG_TWL4030_POWEROFF is not set
# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_SENSORS_PCA963X is not set
@@ -877,7 +883,7 @@
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
CONFIG_SPI=y
-CONFIG_SPI_DEBUG=y
+# CONFIG_SPI_DEBUG is not set
CONFIG_SPI_MASTER=y
#
@@ -920,38 +926,13 @@
#
# CONFIG_GPIO_MAX7301 is not set
# CONFIG_GPIO_MCP23S08 is not set
-CONFIG_W1=y
-CONFIG_W1_CON=y
-
-#
-# 1-wire Bus Masters
-#
-# CONFIG_W1_MASTER_DS2490 is not set
-# CONFIG_W1_MASTER_DS2482 is not set
-# CONFIG_W1_MASTER_DS1WM is not set
-# CONFIG_W1_MASTER_GPIO is not set
-CONFIG_HDQ_MASTER_OMAP=y
-
-#
-# 1-wire Slaves
-#
-# CONFIG_W1_SLAVE_THERM is not set
-# CONFIG_W1_SLAVE_SMEM is not set
-# CONFIG_W1_SLAVE_DS2431 is not set
-# CONFIG_W1_SLAVE_DS2433 is not set
-# CONFIG_W1_SLAVE_DS2760 is not set
-# CONFIG_W1_SLAVE_BQ27000 is not set
-CONFIG_POWER_SUPPLY=y
-# CONFIG_POWER_SUPPLY_DEBUG is not set
-# CONFIG_PDA_POWER is not set
-# CONFIG_BATTERY_DS2760 is not set
-CONFIG_TWL4030_BCI_BATTERY=y
-# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_WATCHDOG_NOWAYOUT=y
#
# Watchdog Device Drivers
@@ -980,7 +961,7 @@
# CONFIG_HTC_PASIC3 is not set
# CONFIG_TPS65010 is not set
CONFIG_TWL4030_CORE=y
-CONFIG_TWL4030_POWER=y
+# CONFIG_TWL4030_POWER is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
@@ -1004,17 +985,75 @@
#
# Multimedia drivers
#
-# CONFIG_DAB is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
#
# Graphics support
#
# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_FB_OMAP_LCD_WVGA is not set
-# CONFIG_OMAP2_DSS is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=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_S1D13XXX is not set
+CONFIG_FB_VIRTUAL=y
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+CONFIG_FB_OMAP_LCD_VGA=y
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_OMAP2_DSS=y
+CONFIG_OMAP2_DSS_VRAM_SIZE=4
+CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
+# CONFIG_OMAP2_DSS_RFBI is not set
+CONFIG_OMAP2_DSS_VENC=y
+# CONFIG_OMAP2_DSS_SDI is not set
+# CONFIG_OMAP2_DSS_DSI is not set
+# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
+
+#
+# OMAP2/3 Display Device Drivers
+#
+# CONFIG_PANEL_GENERIC is not set
+# CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C is not set
+CONFIG_PANEL_SHARP_LS037V7DW01=y
+# CONFIG_PANEL_N800 is not set
+# CONFIG_PANEL_ZOOM2 is not set
+# CONFIG_CTRL_BLIZZARD is not set
+# CONFIG_SIL9022 is not set
+CONFIG_FB_OMAP2=y
+CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
+# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
+CONFIG_FB_OMAP2_NUM_FBS=3
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=m
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+CONFIG_BACKLIGHT_GENERIC=m
#
# Display device support
@@ -1026,22 +1065,75 @@
#
# 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=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
# CONFIG_SOUND is not set
-# CONFIG_HID_SUPPORT is not set
+CONFIG_HID_SUPPORT=y
CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
#
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
-CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
CONFIG_USB_SUSPEND=y
CONFIG_USB_OTG=y
@@ -1055,10 +1147,24 @@
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
-# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_OMAP_EHCI_PHY_MODE=y
+# CONFIG_OMAP_EHCI_TLL_MODE is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
-# CONFIG_USB_OHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+CONFIG_OMAP_OHCI_PHY_MODE=y
+CONFIG_OMAP_OHCI_PHY_MODE_PINS=y
+CONFIG_OMAP_OHCI_PHY_MODE_3PIN=y
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_6PIN_DAT_SE0 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_6PIN_DP_DM is not set
+# CONFIG_OMAP_OHCI_TLL_MODE is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
# CONFIG_USB_SL811_HCD is not set
# CONFIG_USB_R8A66597_HCD is not set
# CONFIG_USB_HWA_HCD is not set
@@ -1094,7 +1200,7 @@
# see USB_STORAGE Help for more information
#
CONFIG_USB_STORAGE=y
-# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DEBUG=y
# CONFIG_USB_STORAGE_DATAFAB is not set
# CONFIG_USB_STORAGE_FREECOM is not set
# CONFIG_USB_STORAGE_ISD200 is not set
@@ -1137,16 +1243,17 @@
# 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_TEST=y
# CONFIG_USB_ISIGHTFW is not set
# CONFIG_USB_VST is not set
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DEBUG=y
CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_DEBUG_FS=y
+# CONFIG_USB_GADGET_DEBUG_FS is not set
CONFIG_USB_GADGET_VBUS_DRAW=2
CONFIG_USB_GADGET_SELECTED=y
# CONFIG_USB_GADGET_AT91 is not set
@@ -1166,14 +1273,15 @@
# CONFIG_USB_GADGET_GOKU is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
-# CONFIG_USB_ZERO is not set
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ZERO_HNPTEST is not set
# CONFIG_USB_ETH is not set
# CONFIG_USB_GADGETFS is not set
# CONFIG_USB_FILE_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_ANDROID=y
+# CONFIG_USB_ANDROID is not set
# CONFIG_USB_CDC_COMPOSITE is not set
#
@@ -1183,9 +1291,10 @@
# CONFIG_USB_GPIO_VBUS is not set
# CONFIG_ISP1301_OMAP is not set
CONFIG_TWL4030_USB=y
+CONFIG_ISP1301_HOST=y
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
-CONFIG_MMC_UNSAFE_RESUME=y
+# CONFIG_MMC_UNSAFE_RESUME is not set
# CONFIG_MMC_EMBEDDED_SDIO is not set
# CONFIG_MMC_PARANOID_SD_INIT is not set
@@ -1209,8 +1318,7 @@
# CONFIG_MEMSTICK is not set
# CONFIG_ACCESSIBILITY is not set
# CONFIG_NEW_LEDS is not set
-CONFIG_SWITCH=y
-# CONFIG_SWITCH_GPIO is not set
+# CONFIG_SWITCH is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
@@ -1276,7 +1384,7 @@
#
# CONFIG_DMADEVICES is not set
CONFIG_REGULATOR=y
-CONFIG_REGULATOR_DEBUG=y
+# CONFIG_REGULATOR_DEBUG is not set
# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
# CONFIG_REGULATOR_BQ24022 is not set
@@ -1310,7 +1418,20 @@
# CBUS support
#
# CONFIG_CBUS is not set
-# CONFIG_MPU_BRIDGE is not set
+CONFIG_MPU_BRIDGE=y
+CONFIG_BRIDGE_DVFS=y
+CONFIG_BRIDGE_MEMPOOL_SIZE=0x600000
+# CONFIG_BRIDGE_DEBUG is not set
+
+#
+# Bridge Hacking
+#
+# CONFIG_BRIDGE_CHECK_ALIGN_128 is not set
+
+#
+# Bridge Notifications
+#
+# CONFIG_BRIDGE_NTFY_PWRERR is not set
#
# File systems
@@ -1379,7 +1500,16 @@
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-# CONFIG_YAFFS_FS is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1517,8 +1647,9 @@
# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
# CONFIG_DEBUG_KOBJECT is not set
-CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_WRITECOUNT is not set
@@ -1534,7 +1665,10 @@
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
+CONFIG_NOP_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
#
# Tracers
@@ -1547,6 +1681,7 @@
# CONFIG_BOOT_TRACER is not set
# CONFIG_TRACE_BRANCH_PROFILING is not set
# CONFIG_STACK_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
@@ -1554,8 +1689,7 @@
# CONFIG_DEBUG_USER is not set
# CONFIG_DEBUG_ERRORS is not set
# CONFIG_DEBUG_STACK_USAGE is not set
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_LL is not set
#
# Security options
diff --git a/arch/arm/configs/omap_3430sdp_defconfig b/arch/arm/configs/omap_3430sdp_defconfig
index b686f34..eb94c77 100644
--- a/arch/arm/configs/omap_3430sdp_defconfig
+++ b/arch/arm/configs/omap_3430sdp_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27-omap1
-# Fri Oct 17 13:41:54 2008
+# Linux kernel version: 2.6.29-omap1
+# Fri Sep 18 18:30:00 2009
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -22,8 +22,6 @@
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
-CONFIG_ZONE_DMA=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -44,14 +42,23 @@
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
# CONFIG_TASKSTATS is not set
# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
CONFIG_GROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
# CONFIG_RT_GROUP_SCHED is not set
CONFIG_USER_SCHED=y
# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_RELAY is not set
@@ -60,6 +67,8 @@
CONFIG_INITRAMFS_SOURCE=""
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 is not set
@@ -70,36 +79,29 @@
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
+CONFIG_AIO=y
+# CONFIG_ASHMEM 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_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
-# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
-# CONFIG_HAVE_IOREMAP_PROT is not set
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
-# CONFIG_HAVE_ARCH_TRACEHOOK is not set
-# CONFIG_HAVE_DMA_ATTRS is not set
-# CONFIG_USE_GENERIC_SMP_HELPERS is not set
CONFIG_HAVE_CLK=y
-CONFIG_PROC_PAGE_MONITOR=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
# CONFIG_MODULE_FORCE_LOAD is not set
@@ -107,11 +109,9 @@
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_KMOD=y
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -127,7 +127,7 @@
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
-CONFIG_CLASSIC_RCU=y
+CONFIG_FREEZER=y
#
# System Type
@@ -137,7 +137,6 @@
# CONFIG_ARCH_REALVIEW is not set
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_AT91 is not set
-# CONFIG_ARCH_CLPS7500 is not set
# CONFIG_ARCH_CLPS711X is not set
# CONFIG_ARCH_EBSA110 is not set
# CONFIG_ARCH_EP93XX is not set
@@ -164,11 +163,13 @@
# 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_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_DAVINCI is not set
CONFIG_ARCH_OMAP=y
-# CONFIG_ARCH_MSM7X00A is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
#
# TI OMAP Implementations
@@ -181,6 +182,8 @@
#
# OMAP Feature Selections
#
+CONFIG_ARCH_OMAP3_GP=y
+# CONFIG_ARCH_OMAP3_HS is not set
# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
CONFIG_OMAP_SMARTREFLEX=y
@@ -194,36 +197,52 @@
CONFIG_OMAP_MUX_DEBUG=y
CONFIG_OMAP_MUX_WARNINGS=y
# CONFIG_OMAP_MCBSP is not set
-# CONFIG_OMAP_MMU_FWK is not set
# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_IOMMU is not set
# CONFIG_OMAP_MPU_TIMER is not set
CONFIG_OMAP_32K_TIMER=y
CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_TICK_GPTIMER=1
CONFIG_OMAP_DM_TIMER=y
CONFIG_OMAP_LL_DEBUG_UART1=y
# CONFIG_OMAP_LL_DEBUG_UART2 is not set
# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+# CONFIG_OMAP_LL_DEBUG_UART_EXT is not set
CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# USBHOST Port Configuration
+#
+CONFIG_OMAP_EHCI_PHY_MODE_PORT1=y
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT1 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT1 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT1 is not set
+CONFIG_OMAP_EHCI_PHY_MODE_PORT2=y
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT2 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT2 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT2 is not set
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT3 is not set
+CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT3=y
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT3 is not set
+# CONFIG_OMAP_PM_NONE is not set
+# CONFIG_OMAP_PM_NOOP is not set
+CONFIG_OMAP_PM_SRF=y
CONFIG_ARCH_OMAP34XX=y
CONFIG_ARCH_OMAP3430=y
#
# OMAP Board Type
#
+# CONFIG_MACH_NOKIA_RX51 is not set
# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+# CONFIG_L2CACHE_OMAP3_DISABLE is not set
+# CONFIG_TIWLAN_SDIO is not set
CONFIG_MACH_OMAP_3430SDP=y
# CONFIG_MACH_OMAP3EVM is not set
# CONFIG_MACH_OMAP3_BEAGLE is not set
# CONFIG_MACH_OVERO is not set
-CONFIG_OMAP_TICK_GPTIMER=1
-
-#
-# Boot options
-#
-
-#
-# Power management
-#
+# CONFIG_MACH_OMAP3_PANDORA is not set
#
# Processor Type
@@ -250,10 +269,16 @@
# 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_CPU_USER_L2_PLE_ACCESS is not set
+# CONFIG_HAS_TLS_REG is not set
# CONFIG_OUTER_CACHE is not set
#
+# errata
+#
+# CONFIG_ARM_ERRATA_430973 is not set
+
+#
# Bus support
#
# CONFIG_PCI_SYSCALL is not set
@@ -267,26 +292,30 @@
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_PREEMPT is not set
CONFIG_HZ=128
CONFIG_AEABI=y
CONFIG_OABI_COMPAT=y
CONFIG_ARCH_FLATMEM_HAS_HOLES=y
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL 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_SPARSEMEM_STATIC is not set
-# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
# CONFIG_LEDS is not set
CONFIG_ALIGNMENT_TRAP=y
@@ -300,9 +329,28 @@
# CONFIG_KEXEC is not set
#
-# CPU Frequency scaling
+# CPU Power Management
#
-# CONFIG_CPU_FREQ is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_MIN_TICKS=10
+CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER=1000
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
#
# Floating point emulation
@@ -322,6 +370,8 @@
# 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=y
@@ -333,6 +383,7 @@
CONFIG_PM_SLEEP=y
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
+# CONFIG_WAKELOCK is not set
# CONFIG_APM_EMULATION is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_NET=y
@@ -340,6 +391,7 @@
#
# Networking options
#
+CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
@@ -378,6 +430,7 @@
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
+CONFIG_ANDROID_PARANOID_NETWORK=y
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
@@ -385,6 +438,7 @@
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
@@ -395,6 +449,7 @@
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
#
# Network testing
@@ -405,14 +460,14 @@
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
+# CONFIG_PHONET is not set
+CONFIG_WIRELESS=y
# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -435,6 +490,7 @@
# CONFIG_MTD_DEBUG is not set
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=y
# CONFIG_MTD_AFS_PARTS is not set
@@ -507,6 +563,7 @@
# CONFIG_MTD_NAND_VERIFY_WRITE is not set
CONFIG_MTD_NAND_ECC_SMC=y
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
CONFIG_MTD_NAND_OMAP2=y
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
@@ -522,6 +579,11 @@
# CONFIG_MTD_ONENAND_SIM is not set
#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
# UBI - Unsorted block images
#
# CONFIG_MTD_UBI is not set
@@ -539,9 +601,21 @@
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
+CONFIG_ANDROID_PMEM=y
+# CONFIG_ICS932S401 is not set
# CONFIG_OMAP_STI is not set
# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_KERNEL_DEBUGGER_CORE is not set
+# CONFIG_UID_STAT 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_93CX6 is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -584,6 +658,7 @@
# CONFIG_SCSI_SRP_ATTRS is not set
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_DH is not set
# CONFIG_ATA is not set
@@ -603,10 +678,15 @@
# CONFIG_DM9000 is not set
# CONFIG_ENC28J60 is not set
# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
# CONFIG_IBM_NEW_EMAC_ZMII is not set
# CONFIG_IBM_NEW_EMAC_RGMII is not set
# CONFIG_IBM_NEW_EMAC_TAH is not set
# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
CONFIG_NETDEV_1000=y
CONFIG_NETDEV_10000=y
@@ -619,6 +699,10 @@
# CONFIG_IWLWIFI_LEDS is not set
#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
# USB Network Adapters
#
# CONFIG_USB_CATC is not set
@@ -648,6 +732,7 @@
# 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
@@ -659,8 +744,8 @@
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_OMAP is not set
CONFIG_KEYBOARD_TWL4030=y
-# CONFIG_KEYBOARD_LM8323 is not set
# CONFIG_KEYBOARD_GPIO is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
@@ -670,18 +755,19 @@
# 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_MTOUCH is not set
# CONFIG_TOUCHSCREEN_INEXIO is not set
# CONFIG_TOUCHSCREEN_MK712 is not set
# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set
# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
# CONFIG_TOUCHSCREEN_TSC2005 is not set
-# CONFIG_TOUCHSCREEN_TSC2102 is not set
# CONFIG_TOUCHSCREEN_TSC210X is not set
-# CONFIG_TOUCHSCREEN_UCB1400 is not set
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
# CONFIG_INPUT_MISC is not set
#
@@ -698,35 +784,34 @@
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVMEM=y
CONFIG_DEVKMEM=y
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_DETECT_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
+# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
+# CONFIG_SERIAL_OMAP_DMA_UART1 is not set
+# CONFIG_SERIAL_OMAP_DMA_UART2 is not set
+# CONFIG_SERIAL_OMAP_DMA_UART3 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=y
-# CONFIG_NVRAM is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
+# CONFIG_DCC_TTY is not set
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_CHARDEV=y
@@ -761,22 +846,15 @@
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_AT24 is not set
-# CONFIG_SENSORS_EEPROM is not set
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_ISP1301_OMAP is not set
-# CONFIG_TPS65010 is not set
-# CONFIG_SENSORS_TLV320AIC23 is not set
# CONFIG_TWL4030_MADC is not set
-CONFIG_TWL4030_USB=y
-# CONFIG_TWL4030_PWRBUTTON is not set
# CONFIG_TWL4030_POWEROFF is not set
# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
-# CONFIG_LP5521 is not set
+# CONFIG_SENSORS_PCA963X is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -789,14 +867,12 @@
# SPI Master Controller Drivers
#
# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
CONFIG_SPI_OMAP24XX=y
#
# SPI Protocol Masters
#
-# CONFIG_SPI_AT25 is not set
-# CONFIG_SPI_TSC2101 is not set
-# CONFIG_SPI_TSC2102 is not set
# CONFIG_SPI_TSC210X is not set
# CONFIG_SPI_TSC2301 is not set
# CONFIG_SPI_SPIDEV is not set
@@ -807,6 +883,10 @@
# CONFIG_GPIO_SYSFS is not set
#
+# Memory mapped GPIO expanders:
+#
+
+#
# I2C GPIO expanders:
#
# CONFIG_GPIO_MAX732X is not set
@@ -826,6 +906,8 @@
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
@@ -839,11 +921,11 @@
# USB-based Watchdog Cards
#
# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
#
# Sonics Silicon Backplane
#
-CONFIG_SSB_POSSIBLE=y
# CONFIG_SSB is not set
#
@@ -854,11 +936,17 @@
# CONFIG_MFD_ASIC3 is not set
# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
CONFIG_TWL4030_CORE=y
+# CONFIG_TWL4030_POWER is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
#
# Multimedia devices
@@ -885,6 +973,7 @@
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
@@ -905,10 +994,14 @@
#
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCD_VGA is not set
# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_OMAP2_DSS is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -941,9 +1034,34 @@
# USB Input Devices
#
CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
+# CONFIG_HID_PID is not set
# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -963,6 +1081,8 @@
# 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
@@ -973,11 +1093,22 @@
# CONFIG_OMAP_EHCI_TLL_MODE is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
-# CONFIG_USB_ISP1760_HCD is not set
-# CONFIG_USB_OHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+CONFIG_OMAP_OHCI_PHY_MODE=y
+CONFIG_OMAP_OHCI_PHY_MODE_PINS=y
+CONFIG_OMAP_OHCI_PHY_MODE_3PIN=y
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_6PIN_DAT_SE0 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_6PIN_DP_DM is not set
+# CONFIG_OMAP_OHCI_TLL_MODE is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
# CONFIG_USB_SL811_HCD is not set
# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
CONFIG_USB_MUSB_HDRC=y
CONFIG_USB_MUSB_SOC=y
@@ -1000,20 +1131,20 @@
# CONFIG_USB_ACM is not set
# CONFIG_USB_PRINTER is not set
# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
#
#
-# may also be needed; see USB_STORAGE Help for more information
+# see USB_STORAGE Help for more information
#
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DEBUG=y
# CONFIG_USB_STORAGE_DATAFAB is not set
# CONFIG_USB_STORAGE_FREECOM is not set
# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
# CONFIG_USB_STORAGE_USBAT is not set
# CONFIG_USB_STORAGE_SDDR09 is not set
# CONFIG_USB_STORAGE_SDDR55 is not set
@@ -1041,6 +1172,7 @@
# 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
@@ -1058,22 +1190,27 @@
# CONFIG_USB_IOWARRIOR is not set
CONFIG_USB_TEST=y
# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DEBUG=y
CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_VBUS_DRAW=2
CONFIG_USB_GADGET_SELECTED=y
-# CONFIG_USB_GADGET_AMD5536UDC is not set
+# 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_NET2280 is not set
-# CONFIG_USB_GADGET_PXA25X is not set
-# CONFIG_USB_GADGET_M66592 is not set
-# CONFIG_USB_GADGET_PXA27X is not set
-# CONFIG_USB_GADGET_GOKU 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_PXA27X is not set
# CONFIG_USB_GADGET_S3C2410 is not set
-# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_IMX 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_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
CONFIG_USB_ZERO=m
@@ -1084,26 +1221,44 @@
# CONFIG_USB_G_SERIAL is not set
# CONFIG_USB_MIDI_GADGET is not set
# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_ANDROID is not set
# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_ISP1301_OMAP is not set
+CONFIG_TWL4030_USB=y
+CONFIG_ISP1301_HOST=y
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
# CONFIG_MMC_UNSAFE_RESUME is not set
+# CONFIG_MMC_EMBEDDED_SDIO is not set
+# CONFIG_MMC_PARANOID_SD_INIT is not set
#
-# MMC/SD Card Drivers
+# 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 Host Controller Drivers
+# MMC/SD/SDIO Host Controller Drivers
#
# CONFIG_MMC_SDHCI is not set
CONFIG_MMC_OMAP_HS=m
+# CONFIG_OMAP_HS_MMC2 is not set
+# CONFIG_OMAP_HS_MMC3 is not set
# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
# CONFIG_NEW_LEDS is not set
+# CONFIG_SWITCH is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
@@ -1117,6 +1272,7 @@
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_DRV_TEST is not set
#
@@ -1135,47 +1291,52 @@
CONFIG_RTC_DRV_TWL4030=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 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
#
# Platform RTC drivers
#
# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
# CONFIG_RTC_DRV_DS1511 is not set
# CONFIG_RTC_DRV_DS1553 is not set
# CONFIG_RTC_DRV_DS1742 is not set
# CONFIG_RTC_DRV_STK17TA8 is not set
# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
# CONFIG_RTC_DRV_V3020 is not set
#
# on-CPU RTC drivers
#
# CONFIG_DMADEVICES is not set
-
-#
-# Voltage and Current regulators
-#
CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
# CONFIG_REGULATOR_BQ24022 is not set
CONFIG_REGULATOR_TWL4030=y
# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
#
# CBUS support
#
# CONFIG_CBUS is not set
+# CONFIG_MPU_BRIDGE is not set
#
# File systems
@@ -1185,19 +1346,22 @@
# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set
-# CONFIG_EXT4DEV_FS is not set
+# CONFIG_EXT4_FS is not set
CONFIG_JBD=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
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_TREE=y
# CONFIG_QFMT_V1 is not set
CONFIG_QFMT_V2=y
CONFIG_QUOTACTL=y
@@ -1226,15 +1390,13 @@
#
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
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
@@ -1242,6 +1404,7 @@
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_YAFFS_FS is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1258,6 +1421,7 @@
# CONFIG_JFFS2_CMODE_SIZE is not set
# CONFIG_JFFS2_CMODE_FAVOURLZO 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
@@ -1278,6 +1442,7 @@
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
@@ -1387,18 +1552,28 @@
# 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_FRAME_POINTER=y
# 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_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
-CONFIG_HAVE_FTRACE=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-# CONFIG_FTRACE is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
@@ -1413,15 +1588,24 @@
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
CONFIG_CRYPTO=y
#
# Crypto core or helper
#
+# CONFIG_CRYPTO_FIPS is not set
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_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
# CONFIG_CRYPTO_GF128MUL is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_CRYPTD is not set
@@ -1455,7 +1639,7 @@
#
# Digest
#
-# CONFIG_CRYPTO_CRC32C is not set
+CONFIG_CRYPTO_CRC32C=y
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_MICHAEL_MIC is not set
@@ -1493,14 +1677,18 @@
#
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRYPTO_HW=y
#
# Library routines
#
CONFIG_BITREVERSE=y
-# CONFIG_GENERIC_FIND_FIRST_BIT is not set
-# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_GENERIC_FIND_LAST_BIT=y
CONFIG_CRC_CCITT=y
# CONFIG_CRC16 is not set
# CONFIG_CRC_T10DIF is not set
diff --git a/arch/arm/configs/zoom2_pm_defconfig b/arch/arm/configs/omap_3630sdp_defconfig
old mode 100644
new mode 100755
similarity index 81%
copy from arch/arm/configs/zoom2_pm_defconfig
copy to arch/arm/configs/omap_3630sdp_defconfig
index 28988a3..c8dbaa0
--- a/arch/arm/configs/zoom2_pm_defconfig
+++ b/arch/arm/configs/omap_3630sdp_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.29-omap1
-# Mon Aug 3 10:55:29 2009
+# Tue Dec 1 00:45:33 2009
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -23,6 +23,8 @@
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_OPROFILE_OMAP_GPTIMER=y
+# CONFIG_OPROFILE_ARMV7 is not set
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -60,8 +62,7 @@
CONFIG_USER_SCHED=y
# CONFIG_CGROUP_SCHED is not set
# CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
# CONFIG_RELAY is not set
# CONFIG_NAMESPACES is not set
CONFIG_BLK_DEV_INITRD=y
@@ -94,7 +95,10 @@
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
@@ -108,7 +112,7 @@
# CONFIG_MODULE_FORCE_LOAD is not set
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_BLOCK=y
# CONFIG_LBD is not set
@@ -198,22 +202,39 @@
CONFIG_OMAP_MUX_DEBUG=y
CONFIG_OMAP_MUX_WARNINGS=y
CONFIG_OMAP_MCBSP=y
-# CONFIG_OMAP_MBOX_FWK is not set
-# CONFIG_OMAP_IOMMU is not set
+CONFIG_OMAP_MBOX_FWK=y
+CONFIG_OMAP_IOMMU=y
# CONFIG_OMAP_MPU_TIMER is not set
CONFIG_OMAP_32K_TIMER=y
# CONFIG_OMAP3_DEBOBS is not set
CONFIG_OMAP_32K_TIMER_HZ=128
CONFIG_OMAP_TICK_GPTIMER=1
CONFIG_OMAP_DM_TIMER=y
-# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
# CONFIG_OMAP_LL_DEBUG_UART2 is not set
# CONFIG_OMAP_LL_DEBUG_UART3 is not set
-CONFIG_OMAP_LL_DEBUG_UART_EXT=y
+# CONFIG_OMAP_LL_DEBUG_UART_EXT is not set
CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# USBHOST Port Configuration
+#
+CONFIG_OMAP_EHCI_PHY_MODE_PORT1=y
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT1 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT1 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT1 is not set
+CONFIG_OMAP_EHCI_PHY_MODE_PORT2=y
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT2 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT2 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT2 is not set
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT3 is not set
+CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT3=y
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT3 is not set
# CONFIG_OMAP_PM_NONE is not set
# CONFIG_OMAP_PM_NOOP is not set
CONFIG_OMAP_PM_SRF=y
+CONFIG_OMAP3_MPU_L2_CACHE_WORKAROUND=y
+CONFIG_VOLTSCALE_VPFORCE=y
CONFIG_ARCH_OMAP34XX=y
CONFIG_ARCH_OMAP3430=y
@@ -222,9 +243,12 @@
#
# CONFIG_MACH_NOKIA_RX51 is not set
# CONFIG_MACH_OMAP_LDP is not set
-CONFIG_MACH_OMAP_ZOOM2=y
-CONFIG_WIFI_CONTROL_FUNC=y
-# CONFIG_TIWLAN_SDIO is not set
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+# CONFIG_MACH_OMAP_ZOOM3 is not set
+CONFIG_MACH_OMAP_3630SDP=y
+# CONFIG_L2CACHE_OMAP3_DISABLE is not set
+CONFIG_TIWLAN_SDIO=y
+CONFIG_TIWLAN_MMC_CONTROLLER=3
# CONFIG_MACH_OMAP_3430SDP is not set
# CONFIG_MACH_OMAP3EVM is not set
# CONFIG_MACH_OMAP3_BEAGLE is not set
@@ -256,13 +280,16 @@
# CONFIG_CPU_ICACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_CPU_USER_L2_PLE_ACCESS is not set
# CONFIG_HAS_TLS_REG is not set
# CONFIG_OUTER_CACHE is not set
#
# errata
#
-# CONFIG_ARM_ERRATA_430973 is not set
+CONFIG_ARM_ERRATA_430973=y
+CONFIG_ARM_ERRATA_451027=y
+CONFIG_ARM_ERRATUM_451034=y
#
# Bus support
@@ -301,6 +328,7 @@
CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
CONFIG_UNEVICTABLE_LRU=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
# CONFIG_LEDS is not set
CONFIG_ALIGNMENT_TRAP=y
@@ -329,7 +357,7 @@
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
-# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_MIN_TICKS=10
CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER=1000
@@ -357,7 +385,7 @@
CONFIG_BINFMT_ELF=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_HAVE_AOUT=y
-CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
CONFIG_BINFMT_MISC=y
#
@@ -371,7 +399,15 @@
CONFIG_SUSPEND=y
# CONFIG_PM_TEST_SUSPEND is not set
CONFIG_SUSPEND_FREEZER=y
-# CONFIG_WAKELOCK is not set
+CONFIG_HAS_WAKELOCK=y
+CONFIG_HAS_EARLYSUSPEND=y
+CONFIG_WAKELOCK=y
+CONFIG_WAKELOCK_STAT=y
+CONFIG_USER_WAKELOCK=y
+CONFIG_EARLYSUSPEND=y
+# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set
+# CONFIG_CONSOLE_EARLYSUSPEND is not set
+CONFIG_FB_EARLYSUSPEND=y
# CONFIG_APM_EMULATION is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_NET=y
@@ -384,7 +420,7 @@
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
+CONFIG_XFRM_USER=y
# CONFIG_XFRM_SUB_POLICY is not set
CONFIG_XFRM_MIGRATE=y
# CONFIG_XFRM_STATISTICS is not set
@@ -504,8 +540,7 @@
CONFIG_CONNECTOR=y
CONFIG_PROC_EVENTS=y
CONFIG_MTD=y
-CONFIG_MTD_DEBUG=y
-CONFIG_MTD_DEBUG_VERBOSE=0
+# CONFIG_MTD_DEBUG is not set
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_TESTS is not set
@@ -530,8 +565,10 @@
#
# RAM/ROM/Flash chip drivers
#
-# CONFIG_MTD_CFI is not set
+CONFIG_MTD_CFI=y
# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
CONFIG_MTD_MAP_BANK_WIDTH_1=y
CONFIG_MTD_MAP_BANK_WIDTH_2=y
CONFIG_MTD_MAP_BANK_WIDTH_4=y
@@ -542,6 +579,10 @@
CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I4 is not set
# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
@@ -550,6 +591,9 @@
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
# CONFIG_MTD_PLATRAM is not set
#
@@ -574,7 +618,6 @@
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
# CONFIG_MTD_NAND_GPIO is not set
CONFIG_MTD_NAND_OMAP2=y
-CONFIG_MTD_NAND_OMAP_HWECC=y
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
@@ -600,7 +643,7 @@
# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_SIZE=16384
# CONFIG_BLK_DEV_XIP is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -611,7 +654,9 @@
# CONFIG_ENCLOSURE_SERVICES is not set
# CONFIG_KERNEL_DEBUGGER_CORE is not set
# CONFIG_UID_STAT is not set
-# CONFIG_WL127X_RFKILL is not set
+CONFIG_WL127X_RFKILL=y
+# CONFIG_APANIC is not set
+CONFIG_APANIC_PLABEL="kpanic"
# CONFIG_C2PORT is not set
#
@@ -661,7 +706,10 @@
# CONFIG_SCSI_ISCSI_ATTRS is not set
# CONFIG_SCSI_SAS_LIBSAS is not set
# CONFIG_SCSI_SRP_ATTRS is not set
-# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_DH is not set
# CONFIG_ATA is not set
# CONFIG_MD is not set
@@ -670,16 +718,16 @@
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
-CONFIG_TUN=y
+# CONFIG_TUN is not set
# CONFIG_VETH is not set
# CONFIG_PHYLIB is not set
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_AX88796 is not set
-# CONFIG_SMC91X is not set
+CONFIG_SMC91X=y
# CONFIG_DM9000 is not set
# CONFIG_ENC28J60 is not set
-CONFIG_SMC911X=y
+# CONFIG_SMC911X is not set
# CONFIG_SMSC911X is not set
# CONFIG_DNET is not set
# CONFIG_IBM_NEW_EMAC_ZMII is not set
@@ -690,8 +738,8 @@
# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
#
# Wireless LAN
@@ -771,17 +819,7 @@
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_TOUCHSCREEN_TSC2007 is not set
-CONFIG_INPUT_MISC=y
-# CONFIG_INPUT_ATI_REMOTE is not set
-# CONFIG_INPUT_ATI_REMOTE2 is not set
-# CONFIG_INPUT_KEYSPAN_REMOTE is not set
-# CONFIG_INPUT_POWERMATE is not set
-# CONFIG_INPUT_YEALINK is not set
-# CONFIG_INPUT_CM109 is not set
-CONFIG_INPUT_TWL4030_PWRBUTTON=y
-# CONFIG_INPUT_UINPUT is not set
-# CONFIG_INPUT_GPIO is not set
-# CONFIG_INPUT_KEYCHORD is not set
+# CONFIG_INPUT_MISC is not set
#
# Hardware I/O ports
@@ -804,22 +842,18 @@
#
# Serial drivers
#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_DETECT_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
+# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_OMAP is not set
+CONFIG_SERIAL_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
+# CONFIG_SERIAL_OMAP_DMA_UART1 is not set
+# CONFIG_SERIAL_OMAP_DMA_UART2 is not set
+# CONFIG_SERIAL_OMAP_DMA_UART3 is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
@@ -868,7 +902,7 @@
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
CONFIG_TWL4030_MADC=y
-CONFIG_TWL4030_POWEROFF=y
+# CONFIG_TWL4030_POWEROFF is not set
# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_SENSORS_PCA963X is not set
@@ -877,7 +911,7 @@
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
CONFIG_SPI=y
-CONFIG_SPI_DEBUG=y
+# CONFIG_SPI_DEBUG is not set
CONFIG_SPI_MASTER=y
#
@@ -940,7 +974,7 @@
# CONFIG_W1_SLAVE_DS2431 is not set
# CONFIG_W1_SLAVE_DS2433 is not set
# CONFIG_W1_SLAVE_DS2760 is not set
-# CONFIG_W1_SLAVE_BQ27000 is not set
+CONFIG_W1_SLAVE_BQ27000=y
CONFIG_POWER_SUPPLY=y
# CONFIG_POWER_SUPPLY_DEBUG is not set
# CONFIG_PDA_POWER is not set
@@ -951,7 +985,7 @@
# CONFIG_THERMAL is not set
# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_WATCHDOG_NOWAYOUT=y
#
# Watchdog Device Drivers
@@ -997,24 +1031,99 @@
#
# Multimedia core support
#
-# CONFIG_VIDEO_DEV is not set
+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 is not set
+CONFIG_VIDEO_MEDIA=y
#
# Multimedia drivers
#
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+# CONFIG_MEDIA_TUNER_CUSTOMIZE 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_VIDEO_V4L2=y
+CONFIG_VIDEO_V4L1=y
+# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
+# CONFIG_RADIO_ADAPTERS is not set
# CONFIG_DAB is not set
#
# Graphics support
#
# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_FB_OMAP_LCD_WVGA is not set
-# CONFIG_OMAP2_DSS is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_OMAP2_DSS=y
+CONFIG_OMAP2_DSS_VRAM_SIZE=4
+CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
+# CONFIG_OMAP2_DSS_RFBI is not set
+# CONFIG_OMAP2_DSS_VENC is not set
+# CONFIG_OMAP2_DSS_SDI is not set
+# CONFIG_OMAP2_DSS_DSI is not set
+# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
+
+#
+# OMAP2/3 Display Device Drivers
+#
+# CONFIG_PANEL_GENERIC is not set
+# CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C is not set
+# CONFIG_PANEL_SHARP_LS037V7DW01 is not set
+# CONFIG_PANEL_N800 is not set
+CONFIG_PANEL_ZOOM2=y
+# CONFIG_CTRL_BLIZZARD is not set
+# CONFIG_SIL9022 is not set
+CONFIG_FB_OMAP2=y
+CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
+# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
+CONFIG_FB_OMAP2_NUM_FBS=1
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
#
# Display device support
@@ -1026,25 +1135,99 @@
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
-# CONFIG_SOUND is not set
-# CONFIG_HID_SUPPORT is not set
+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_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_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_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_SPI=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
#
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
-CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
CONFIG_USB_SUSPEND=y
-CONFIG_USB_OTG=y
+# CONFIG_USB_OTG is not set
# CONFIG_USB_OTG_WHITELIST is not set
# CONFIG_USB_OTG_BLACKLIST_HUB is not set
CONFIG_USB_MON=y
@@ -1055,10 +1238,24 @@
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
-# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_OMAP_EHCI_PHY_MODE=y
+# CONFIG_OMAP_EHCI_TLL_MODE is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
-# CONFIG_USB_OHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+CONFIG_OMAP_OHCI_PHY_MODE=y
+CONFIG_OMAP_OHCI_PHY_MODE_PINS=y
+CONFIG_OMAP_OHCI_PHY_MODE_3PIN=y
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_6PIN_DAT_SE0 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_6PIN_DP_DM is not set
+# CONFIG_OMAP_OHCI_TLL_MODE is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
# CONFIG_USB_SL811_HCD is not set
# CONFIG_USB_R8A66597_HCD is not set
# CONFIG_USB_HWA_HCD is not set
@@ -1069,10 +1266,9 @@
# OMAP 343x high speed USB support
#
# CONFIG_USB_MUSB_HOST is not set
-# CONFIG_USB_MUSB_PERIPHERAL is not set
-CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_MUSB_PERIPHERAL=y
+# CONFIG_USB_MUSB_OTG is not set
CONFIG_USB_GADGET_MUSB_HDRC=y
-CONFIG_USB_MUSB_HDRC_HCD=y
# CONFIG_MUSB_PIO_ONLY is not set
CONFIG_USB_INVENTRA_DMA=y
# CONFIG_USB_TI_CPPI_DMA is not set
@@ -1084,7 +1280,7 @@
# CONFIG_USB_ACM is not set
# CONFIG_USB_PRINTER is not set
# CONFIG_USB_WDM is not set
-# CONFIG_USB_TMC is not set
+CONFIG_USB_TMC=y
#
# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
@@ -1137,16 +1333,17 @@
# 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_TEST=y
# CONFIG_USB_ISIGHTFW is not set
# CONFIG_USB_VST is not set
CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_DEBUG_FS=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=2
CONFIG_USB_GADGET_SELECTED=y
# CONFIG_USB_GADGET_AT91 is not set
@@ -1166,14 +1363,14 @@
# CONFIG_USB_GADGET_GOKU is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
-# CONFIG_USB_ZERO is not set
+CONFIG_USB_ZERO=y
# CONFIG_USB_ETH is not set
# CONFIG_USB_GADGETFS is not set
# CONFIG_USB_FILE_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_ANDROID=y
+# CONFIG_USB_ANDROID is not set
# CONFIG_USB_CDC_COMPOSITE is not set
#
@@ -1183,6 +1380,7 @@
# CONFIG_USB_GPIO_VBUS is not set
# CONFIG_ISP1301_OMAP is not set
CONFIG_TWL4030_USB=y
+CONFIG_ISP1301_HOST=y
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
CONFIG_MMC_UNSAFE_RESUME=y
@@ -1204,13 +1402,13 @@
# CONFIG_MMC_SDHCI is not set
CONFIG_MMC_OMAP_HS=y
# CONFIG_OMAP_HS_MMC2 is not set
-# CONFIG_OMAP_HS_MMC3 is not set
+CONFIG_OMAP_HS_MMC3=y
# CONFIG_MMC_SPI is not set
# CONFIG_MEMSTICK is not set
# CONFIG_ACCESSIBILITY is not set
# CONFIG_NEW_LEDS is not set
CONFIG_SWITCH=y
-# CONFIG_SWITCH_GPIO is not set
+CONFIG_SWITCH_GPIO=y
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
@@ -1276,7 +1474,7 @@
#
# CONFIG_DMADEVICES is not set
CONFIG_REGULATOR=y
-CONFIG_REGULATOR_DEBUG=y
+# CONFIG_REGULATOR_DEBUG is not set
# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
# CONFIG_REGULATOR_BQ24022 is not set
@@ -1310,7 +1508,20 @@
# CBUS support
#
# CONFIG_CBUS is not set
-# CONFIG_MPU_BRIDGE is not set
+CONFIG_MPU_BRIDGE=y
+CONFIG_BRIDGE_DVFS=y
+CONFIG_BRIDGE_MEMPOOL_SIZE=0x600000
+# CONFIG_BRIDGE_DEBUG is not set
+
+#
+# Bridge Hacking
+#
+# CONFIG_BRIDGE_CHECK_ALIGN_128 is not set
+
+#
+# Bridge Notifications
+#
+# CONFIG_BRIDGE_NTFY_PWRERR is not set
#
# File systems
@@ -1379,7 +1590,16 @@
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-# CONFIG_YAFFS_FS is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1517,8 +1737,9 @@
# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
# CONFIG_DEBUG_KOBJECT is not set
-CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_WRITECOUNT is not set
@@ -1534,7 +1755,10 @@
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
+CONFIG_NOP_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
#
# Tracers
@@ -1547,6 +1771,7 @@
# CONFIG_BOOT_TRACER is not set
# CONFIG_TRACE_BRANCH_PROFILING is not set
# CONFIG_STACK_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
diff --git a/arch/arm/configs/zoom2_defconfig b/arch/arm/configs/zoom2_defconfig
index 2a09205..62a1f10 100644
--- a/arch/arm/configs/zoom2_defconfig
+++ b/arch/arm/configs/zoom2_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.29-omap1
-# Wed Aug 12 19:24:25 2009
+# Mon Feb 15 21:11:53 2010
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -23,6 +23,8 @@
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_OPROFILE_OMAP_GPTIMER=y
+# CONFIG_OPROFILE_ARMV7 is not set
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -93,7 +95,10 @@
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
@@ -197,7 +202,7 @@
CONFIG_OMAP_MUX_DEBUG=y
CONFIG_OMAP_MUX_WARNINGS=y
CONFIG_OMAP_MCBSP=y
-# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MBOX_FWK=y
CONFIG_OMAP_IOMMU=y
# CONFIG_OMAP_MPU_TIMER is not set
CONFIG_OMAP_32K_TIMER=y
@@ -208,11 +213,14 @@
# CONFIG_OMAP_LL_DEBUG_UART1 is not set
# CONFIG_OMAP_LL_DEBUG_UART2 is not set
# CONFIG_OMAP_LL_DEBUG_UART3 is not set
-CONFIG_OMAP_LL_DEBUG_UART_EXT=y
+# CONFIG_OMAP_LL_DEBUG_UART_EXT is not set
+CONFIG_OMAP_LL_DEBUG_NONE=y
CONFIG_OMAP_SERIAL_WAKE=y
# CONFIG_OMAP_PM_NONE is not set
# CONFIG_OMAP_PM_NOOP is not set
CONFIG_OMAP_PM_SRF=y
+CONFIG_OMAP3_MPU_L2_CACHE_WORKAROUND=y
+CONFIG_VOLTSCALE_VPFORCE=y
CONFIG_ARCH_OMAP34XX=y
CONFIG_ARCH_OMAP3430=y
@@ -222,6 +230,9 @@
# CONFIG_MACH_NOKIA_RX51 is not set
# CONFIG_MACH_OMAP_LDP is not set
CONFIG_MACH_OMAP_ZOOM2=y
+# CONFIG_MACH_OMAP_ZOOM3 is not set
+# CONFIG_MACH_OMAP_3630SDP is not set
+# CONFIG_L2CACHE_OMAP3_DISABLE is not set
CONFIG_WIFI_CONTROL_FUNC=y
CONFIG_TIWLAN_SDIO=y
CONFIG_TIWLAN_MMC_CONTROLLER=3
@@ -256,13 +267,17 @@
# CONFIG_CPU_ICACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_CPU_USER_L2_PLE_ACCESS is not set
# CONFIG_HAS_TLS_REG is not set
# CONFIG_OUTER_CACHE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=6
#
# errata
#
-# CONFIG_ARM_ERRATA_430973 is not set
+CONFIG_ARM_ERRATA_430973=y
+CONFIG_ARM_ERRATA_451027=y
+CONFIG_ARM_ERRATUM_451034=y
#
# Bus support
@@ -301,6 +316,7 @@
CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
CONFIG_UNEVICTABLE_LRU=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
# CONFIG_LEDS is not set
CONFIG_ALIGNMENT_TRAP=y
@@ -328,9 +344,9 @@
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
-# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_CPU_FREQ_MIN_TICKS=10
CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER=1000
CONFIG_CPU_IDLE=y
@@ -349,7 +365,7 @@
# CONFIG_FPE_FASTFPE is not set
CONFIG_VFP=y
CONFIG_VFPv3=y
-# CONFIG_NEON is not set
+CONFIG_NEON=y
#
# Userspace binary formats
@@ -505,7 +521,9 @@
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+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
@@ -590,7 +608,8 @@
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
# CONFIG_MTD_NAND_GPIO is not set
CONFIG_MTD_NAND_OMAP2=y
-CONFIG_MTD_NAND_OMAP_HWECC=y
+CONFIG_MTD_NAND_OMAP_PREFETCH=y
+# CONFIG_MTD_NAND_OMAP_PREFETCH_DMA is not set
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
@@ -628,6 +647,9 @@
# CONFIG_KERNEL_DEBUGGER_CORE is not set
# CONFIG_UID_STAT is not set
CONFIG_WL127X_RFKILL=y
+# CONFIG_APANIC is not set
+CONFIG_APANIC_PLABEL="kpanic"
+CONFIG_BUILD_TI_ST=y
# CONFIG_C2PORT is not set
#
@@ -637,6 +659,14 @@
# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_TI_ST=m
+CONFIG_TI_ST_BT=m
+# CONFIG_TI_ST_FM is not set
+# CONFIG_TI_ST_GPS is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -691,15 +721,34 @@
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_VETH is not set
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_AX88796 is not set
# CONFIG_SMC91X is not set
# CONFIG_DM9000 is not set
# CONFIG_ENC28J60 is not set
-CONFIG_SMC911X=y
-# CONFIG_SMSC911X is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
# CONFIG_DNET is not set
# CONFIG_IBM_NEW_EMAC_ZMII is not set
# CONFIG_IBM_NEW_EMAC_RGMII is not set
@@ -790,7 +839,17 @@
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_TOUCHSCREEN_TSC2007 is not set
-# CONFIG_INPUT_MISC is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_TWL4030_PWRBUTTON is not set
+CONFIG_INPUT_UINPUT=y
+# CONFIG_INPUT_GPIO is not set
+# CONFIG_INPUT_KEYCHORD is not set
#
# Hardware I/O ports
@@ -813,22 +872,20 @@
#
# Serial drivers
#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_DETECT_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
+# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_OMAP is not set
+CONFIG_SERIAL_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
+# CONFIG_SERIAL_OMAP_DMA_UART1 is not set
+CONFIG_SERIAL_OMAP_DMA_UART2=y
+CONFIG_SERIAL_OMAP_UART2_RXDMA_TIMEOUT=1
+CONFIG_SERIAL_OMAP_UART2_RXDMA_BUFSIZE=4096
+# CONFIG_SERIAL_OMAP_DMA_UART3 is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
@@ -877,7 +934,7 @@
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
CONFIG_TWL4030_MADC=y
-# CONFIG_TWL4030_POWEROFF is not set
+CONFIG_TWL4030_POWEROFF=y
# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_SENSORS_PCA963X is not set
@@ -989,7 +1046,7 @@
# CONFIG_HTC_PASIC3 is not set
# CONFIG_TPS65010 is not set
CONFIG_TWL4030_CORE=y
-# CONFIG_TWL4030_POWER is not set
+CONFIG_TWL4030_POWER=y
# CONFIG_MFD_TMIO is not set
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
@@ -1031,8 +1088,6 @@
CONFIG_VIDEO_V4L1=y
CONFIG_VIDEOBUF_GEN=y
CONFIG_VIDEOBUF_DMA_SG=y
-CONFIG_VIDEO_OMAP_VIDEOOUT=y
-# CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL is not set
CONFIG_VIDEO_CAPTURE_DRIVERS=y
# CONFIG_VIDEO_ADV_DEBUG is not set
# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
@@ -1110,13 +1165,13 @@
# CONFIG_VIDEO_SAA5246A is not set
# CONFIG_VIDEO_SAA5249 is not set
CONFIG_VIDEO_OMAP3=y
-CONFIG_VIDEO_OMAP34XX_ISP_PREVIEWER=y
-CONFIG_VIDEO_OMAP34XX_ISP_RESIZER=y
CONFIG_VIDEO_OMAP3_V4L2=y
CONFIG_VIDEO_OMAP_VIDEOLIB=y
CONFIG_VIDEO_OMAP_VIDEOOUT=y
CONFIG_NTSC_M=y
# CONFIG_PAL_BDGHI is not set
+CONFIG_VIDEO_OMAP34XX_ISP_PREVIEWER=y
+CONFIG_VIDEO_OMAP34XX_ISP_RESIZER=y
# CONFIG_SOC_CAMERA is not set
# CONFIG_V4L_USB_DRIVERS is not set
# CONFIG_RADIO_ADAPTERS is not set
@@ -1154,7 +1209,6 @@
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FB_METRONOME is not set
# CONFIG_FB_MB862XX is not set
-CONFIG_FB_OMAP_LCD_WVGA=y
# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
CONFIG_OMAP2_DSS=y
CONFIG_OMAP2_DSS_VRAM_SIZE=4
@@ -1162,9 +1216,11 @@
# CONFIG_OMAP2_DSS_RFBI is not set
# CONFIG_OMAP2_DSS_VENC is not set
# CONFIG_OMAP2_DSS_SDI is not set
-# CONFIG_OMAP2_DSS_DSI is not set
+CONFIG_OMAP2_DSS_DSI=y
+CONFIG_OMAP2_DSS_USE_DSI_PLL=y
+CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI=y
# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
-CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=3
#
# OMAP2/3 Display Device Drivers
@@ -1174,8 +1230,8 @@
# CONFIG_PANEL_SHARP_LS037V7DW01 is not set
# CONFIG_PANEL_N800 is not set
CONFIG_PANEL_ZOOM2=y
-CONFIG_SIL9022=y
# CONFIG_CTRL_BLIZZARD is not set
+CONFIG_SIL9022=y
CONFIG_FB_OMAP2=y
CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
@@ -1213,6 +1269,9 @@
CONFIG_SOUND=y
# CONFIG_SOUND_OSS_CORE is not set
CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
# CONFIG_SND_SEQUENCER is not set
# CONFIG_SND_MIXER_OSS is not set
# CONFIG_SND_PCM_OSS is not set
@@ -1232,7 +1291,13 @@
CONFIG_SND_USB=y
# CONFIG_SND_USB_AUDIO is not set
# CONFIG_SND_USB_CAIAQ is not set
-# CONFIG_SND_SOC is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_MCBSP=y
+CONFIG_SND_OMAP_SOC_ZOOM2=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_TWL4030=y
# CONFIG_SOUND_PRIME is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=y
@@ -1276,14 +1341,14 @@
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
#
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
-CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
CONFIG_USB_SUSPEND=y
CONFIG_USB_OTG=y
@@ -1323,7 +1388,7 @@
#
# USB Device Class drivers
#
-# CONFIG_USB_ACM is not set
+CONFIG_USB_ACM=m
# CONFIG_USB_PRINTER is not set
# CONFIG_USB_WDM is not set
# CONFIG_USB_TMC is not set
@@ -1335,7 +1400,19 @@
#
# see USB_STORAGE Help for more information
#
-# CONFIG_USB_STORAGE is not set
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_DEBUG=y
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
# CONFIG_USB_LIBUSUAL is not set
#
@@ -1347,7 +1424,63 @@
#
# USB port drivers
#
-# CONFIG_USB_SERIAL is not set
+CONFIG_USB_SERIAL=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN=m
+# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
#
# USB Miscellaneous drivers
@@ -1396,14 +1529,17 @@
# CONFIG_USB_GADGET_GOKU is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
-# CONFIG_USB_ZERO is not set
-# CONFIG_USB_ETH is not set
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FILE_STORAGE is not set
-# CONFIG_USB_G_SERIAL is not set
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ZERO_HNPTEST is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
# CONFIG_USB_MIDI_GADGET is not set
# CONFIG_USB_G_PRINTER is not set
-CONFIG_USB_ANDROID=y
+CONFIG_USB_ANDROID=m
# CONFIG_USB_CDC_COMPOSITE is not set
#
@@ -1424,7 +1560,7 @@
#
CONFIG_MMC_BLOCK=y
CONFIG_MMC_BLOCK_BOUNCE=y
-CONFIG_MMC_BLOCK_PARANOID_RESUME=y
+# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
# CONFIG_SDIO_UART is not set
# CONFIG_MMC_TEST is not set
@@ -1440,7 +1576,7 @@
# CONFIG_ACCESSIBILITY is not set
# CONFIG_NEW_LEDS is not set
CONFIG_SWITCH=y
-# CONFIG_SWITCH_GPIO is not set
+CONFIG_SWITCH_GPIO=y
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
@@ -1546,6 +1682,16 @@
# CONFIG_BRIDGE_DEBUG is not set
#
+# Bridge Hacking
+#
+# CONFIG_BRIDGE_CACHE_LINE_CHECK is not set
+
+#
+# Bridge Notifications
+#
+# CONFIG_BRIDGE_NTFY_PWRERR is not set
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1622,6 +1768,7 @@
# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1759,6 +1906,7 @@
# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_INFO=y
@@ -1776,7 +1924,10 @@
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
+CONFIG_NOP_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
#
# Tracers
@@ -1789,6 +1940,7 @@
# CONFIG_BOOT_TRACER is not set
# CONFIG_TRACE_BRANCH_PROFILING is not set
# CONFIG_STACK_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
diff --git a/arch/arm/configs/zoom2_pm_defconfig b/arch/arm/configs/zoom3_defconfig
similarity index 68%
copy from arch/arm/configs/zoom2_pm_defconfig
copy to arch/arm/configs/zoom3_defconfig
index 28988a3..fb3a0ca 100644
--- a/arch/arm/configs/zoom2_pm_defconfig
+++ b/arch/arm/configs/zoom3_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.29-omap1
-# Mon Aug 3 10:55:29 2009
+# Mon Feb 15 21:10:47 2010
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -23,6 +23,8 @@
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_OPROFILE_OMAP_GPTIMER=y
+# CONFIG_OPROFILE_ARMV7 is not set
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -60,8 +62,7 @@
CONFIG_USER_SCHED=y
# CONFIG_CGROUP_SCHED is not set
# CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
# CONFIG_RELAY is not set
# CONFIG_NAMESPACES is not set
CONFIG_BLK_DEV_INITRD=y
@@ -94,7 +95,10 @@
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
@@ -108,7 +112,7 @@
# CONFIG_MODULE_FORCE_LOAD is not set
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_BLOCK=y
# CONFIG_LBD is not set
@@ -188,7 +192,7 @@
# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
CONFIG_OMAP_SMARTREFLEX=y
-# CONFIG_OMAP_SMARTREFLEX_TESTING is not set
+CONFIG_OMAP_SMARTREFLEX_TESTING=y
CONFIG_OMAP_RESET_CLOCKS=y
CONFIG_OMAP_BOOT_TAG=y
CONFIG_OMAP_BOOT_REASON=y
@@ -198,8 +202,8 @@
CONFIG_OMAP_MUX_DEBUG=y
CONFIG_OMAP_MUX_WARNINGS=y
CONFIG_OMAP_MCBSP=y
-# CONFIG_OMAP_MBOX_FWK is not set
-# CONFIG_OMAP_IOMMU is not set
+CONFIG_OMAP_MBOX_FWK=y
+CONFIG_OMAP_IOMMU=y
# CONFIG_OMAP_MPU_TIMER is not set
CONFIG_OMAP_32K_TIMER=y
# CONFIG_OMAP3_DEBOBS is not set
@@ -209,11 +213,14 @@
# CONFIG_OMAP_LL_DEBUG_UART1 is not set
# CONFIG_OMAP_LL_DEBUG_UART2 is not set
# CONFIG_OMAP_LL_DEBUG_UART3 is not set
-CONFIG_OMAP_LL_DEBUG_UART_EXT=y
+# CONFIG_OMAP_LL_DEBUG_UART_EXT is not set
+CONFIG_OMAP_LL_DEBUG_NONE=y
CONFIG_OMAP_SERIAL_WAKE=y
# CONFIG_OMAP_PM_NONE is not set
# CONFIG_OMAP_PM_NOOP is not set
CONFIG_OMAP_PM_SRF=y
+CONFIG_OMAP3_MPU_L2_CACHE_WORKAROUND=y
+CONFIG_VOLTSCALE_VPFORCE=y
CONFIG_ARCH_OMAP34XX=y
CONFIG_ARCH_OMAP3430=y
@@ -222,9 +229,13 @@
#
# CONFIG_MACH_NOKIA_RX51 is not set
# CONFIG_MACH_OMAP_LDP is not set
-CONFIG_MACH_OMAP_ZOOM2=y
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+CONFIG_MACH_OMAP_ZOOM3=y
+# CONFIG_MACH_OMAP_3630SDP is not set
+# CONFIG_L2CACHE_OMAP3_DISABLE is not set
CONFIG_WIFI_CONTROL_FUNC=y
-# CONFIG_TIWLAN_SDIO is not set
+CONFIG_TIWLAN_SDIO=y
+CONFIG_TIWLAN_MMC_CONTROLLER=3
# CONFIG_MACH_OMAP_3430SDP is not set
# CONFIG_MACH_OMAP3EVM is not set
# CONFIG_MACH_OMAP3_BEAGLE is not set
@@ -256,13 +267,17 @@
# CONFIG_CPU_ICACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_CPU_USER_L2_PLE_ACCESS is not set
# CONFIG_HAS_TLS_REG is not set
# CONFIG_OUTER_CACHE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=6
#
# errata
#
-# CONFIG_ARM_ERRATA_430973 is not set
+CONFIG_ARM_ERRATA_430973=y
+CONFIG_ARM_ERRATA_451027=y
+CONFIG_ARM_ERRATUM_451034=y
#
# Bus support
@@ -301,6 +316,7 @@
CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
CONFIG_UNEVICTABLE_LRU=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
# CONFIG_LEDS is not set
CONFIG_ALIGNMENT_TRAP=y
@@ -328,9 +344,9 @@
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
-# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_CPU_FREQ_MIN_TICKS=10
CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER=1000
CONFIG_CPU_IDLE=y
@@ -357,7 +373,7 @@
CONFIG_BINFMT_ELF=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_HAVE_AOUT=y
-CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
CONFIG_BINFMT_MISC=y
#
@@ -371,7 +387,15 @@
CONFIG_SUSPEND=y
# CONFIG_PM_TEST_SUSPEND is not set
CONFIG_SUSPEND_FREEZER=y
-# CONFIG_WAKELOCK is not set
+CONFIG_HAS_WAKELOCK=y
+CONFIG_HAS_EARLYSUSPEND=y
+CONFIG_WAKELOCK=y
+CONFIG_WAKELOCK_STAT=y
+CONFIG_USER_WAKELOCK=y
+CONFIG_EARLYSUSPEND=y
+# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set
+# CONFIG_CONSOLE_EARLYSUSPEND is not set
+CONFIG_FB_EARLYSUSPEND=y
# CONFIG_APM_EMULATION is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_NET=y
@@ -384,7 +408,7 @@
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
+CONFIG_XFRM_USER=y
# CONFIG_XFRM_SUB_POLICY is not set
CONFIG_XFRM_MIGRATE=y
# CONFIG_XFRM_STATISTICS is not set
@@ -392,8 +416,13 @@
CONFIG_NET_KEY_MIGRATE=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
@@ -421,7 +450,115 @@
# CONFIG_IPV6 is not set
CONFIG_ANDROID_PARANOID_NETWORK=y
# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER 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=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+# 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=y
+CONFIG_NF_CONNTRACK_TFTP=y
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NETFILTER_TPROXY is not set
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP 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_NOTRACK is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP 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_IPRANGE=y
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+# 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 is not set
+# 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=y
+# 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=y
+# 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=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+CONFIG_IP_NF_TARGET_REDIRECT=y
+# CONFIG_IP_NF_TARGET_IDLETIMER is not set
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+CONFIG_NF_NAT_FTP=y
+CONFIG_NF_NAT_IRC=y
+CONFIG_NF_NAT_TFTP=y
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+CONFIG_NF_NAT_H323=y
+CONFIG_NF_NAT_SIP=y
+CONFIG_IP_NF_MANGLE=y
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
# CONFIG_TIPC is not set
@@ -436,7 +573,7 @@
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
+CONFIG_WAN_ROUTER=y
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -497,15 +634,16 @@
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+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=y
CONFIG_PROC_EVENTS=y
CONFIG_MTD=y
-CONFIG_MTD_DEBUG=y
-CONFIG_MTD_DEBUG_VERBOSE=0
+# CONFIG_MTD_DEBUG is not set
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_TESTS is not set
@@ -530,8 +668,10 @@
#
# RAM/ROM/Flash chip drivers
#
-# CONFIG_MTD_CFI is not set
+CONFIG_MTD_CFI=y
# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
CONFIG_MTD_MAP_BANK_WIDTH_1=y
CONFIG_MTD_MAP_BANK_WIDTH_2=y
CONFIG_MTD_MAP_BANK_WIDTH_4=y
@@ -542,6 +682,10 @@
CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I4 is not set
# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
@@ -550,6 +694,9 @@
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
# CONFIG_MTD_PLATRAM is not set
#
@@ -574,7 +721,8 @@
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
# CONFIG_MTD_NAND_GPIO is not set
CONFIG_MTD_NAND_OMAP2=y
-CONFIG_MTD_NAND_OMAP_HWECC=y
+CONFIG_MTD_NAND_OMAP_PREFETCH=y
+# CONFIG_MTD_NAND_OMAP_PREFETCH_DMA is not set
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
@@ -600,7 +748,7 @@
# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_SIZE=16384
# CONFIG_BLK_DEV_XIP is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -611,7 +759,10 @@
# CONFIG_ENCLOSURE_SERVICES is not set
# CONFIG_KERNEL_DEBUGGER_CORE is not set
# CONFIG_UID_STAT is not set
-# CONFIG_WL127X_RFKILL is not set
+CONFIG_WL127X_RFKILL=y
+# CONFIG_APANIC is not set
+CONFIG_APANIC_PLABEL="kpanic"
+CONFIG_BUILD_TI_ST=y
# CONFIG_C2PORT is not set
#
@@ -621,6 +772,14 @@
# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_TI_ST=m
+CONFIG_TI_ST_BT=m
+CONFIG_TI_ST_FM=m
+CONFIG_TI_ST_GPS=m
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -661,7 +820,10 @@
# CONFIG_SCSI_ISCSI_ATTRS is not set
# CONFIG_SCSI_SAS_LIBSAS is not set
# CONFIG_SCSI_SRP_ATTRS is not set
-# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_DH is not set
# CONFIG_ATA is not set
# CONFIG_MD is not set
@@ -670,17 +832,36 @@
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
-CONFIG_TUN=y
+# CONFIG_TUN is not set
# CONFIG_VETH is not set
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_AX88796 is not set
# CONFIG_SMC91X is not set
# CONFIG_DM9000 is not set
# CONFIG_ENC28J60 is not set
-CONFIG_SMC911X=y
-# CONFIG_SMSC911X is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
# CONFIG_DNET is not set
# CONFIG_IBM_NEW_EMAC_ZMII is not set
# CONFIG_IBM_NEW_EMAC_RGMII is not set
@@ -690,8 +871,8 @@
# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
#
# Wireless LAN
@@ -778,8 +959,8 @@
# CONFIG_INPUT_POWERMATE is not set
# CONFIG_INPUT_YEALINK is not set
# CONFIG_INPUT_CM109 is not set
-CONFIG_INPUT_TWL4030_PWRBUTTON=y
-# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_TWL4030_PWRBUTTON is not set
+CONFIG_INPUT_UINPUT=y
# CONFIG_INPUT_GPIO is not set
# CONFIG_INPUT_KEYCHORD is not set
@@ -804,22 +985,20 @@
#
# Serial drivers
#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_DETECT_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
+# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_OMAP is not set
+CONFIG_SERIAL_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
+# CONFIG_SERIAL_OMAP_DMA_UART1 is not set
+CONFIG_SERIAL_OMAP_DMA_UART2=y
+CONFIG_SERIAL_OMAP_UART2_RXDMA_TIMEOUT=1
+CONFIG_SERIAL_OMAP_UART2_RXDMA_BUFSIZE=4096
+# CONFIG_SERIAL_OMAP_DMA_UART3 is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
@@ -877,7 +1056,7 @@
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
CONFIG_SPI=y
-CONFIG_SPI_DEBUG=y
+# CONFIG_SPI_DEBUG is not set
CONFIG_SPI_MASTER=y
#
@@ -940,7 +1119,7 @@
# CONFIG_W1_SLAVE_DS2431 is not set
# CONFIG_W1_SLAVE_DS2433 is not set
# CONFIG_W1_SLAVE_DS2760 is not set
-# CONFIG_W1_SLAVE_BQ27000 is not set
+CONFIG_W1_SLAVE_BQ27000=y
CONFIG_POWER_SUPPLY=y
# CONFIG_POWER_SUPPLY_DEBUG is not set
# CONFIG_PDA_POWER is not set
@@ -951,7 +1130,7 @@
# CONFIG_THERMAL is not set
# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_WATCHDOG_NOWAYOUT=y
#
# Watchdog Device Drivers
@@ -997,24 +1176,186 @@
#
# Multimedia core support
#
-# CONFIG_VIDEO_DEV is not set
+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 is not set
+CONFIG_VIDEO_MEDIA=y
#
# Multimedia drivers
#
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+# CONFIG_MEDIA_TUNER_CUSTOMIZE 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_VIDEO_V4L2=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_DMA_SG=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TDA9875 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+
+#
+# Video decoders
+#
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_TCM825X is not set
+CONFIG_VIDEO_IMX046=y
+CONFIG_VIDEO_LV8093=y
+# CONFIG_VIDEO_SAA7110 is not set
+# CONFIG_VIDEO_SAA7111 is not set
+# CONFIG_VIDEO_SAA7114 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_SAA7191 is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_VPX3220 is not set
+
+#
+# Video and audio decoders
+#
+# CONFIG_VIDEO_CX25840 is not set
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+CONFIG_VIDEO_OMAP3=y
+CONFIG_VIDEO_OMAP3_V4L2=y
+CONFIG_VIDEO_OMAP_VIDEOLIB=y
+CONFIG_VIDEO_OMAP_VIDEOOUT=y
+CONFIG_NTSC_M=y
+# CONFIG_PAL_BDGHI is not set
+CONFIG_VIDEO_OMAP34XX_ISP_PREVIEWER=y
+CONFIG_VIDEO_OMAP34XX_ISP_RESIZER=y
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_V4L_USB_DRIVERS is not set
+# CONFIG_RADIO_ADAPTERS is not set
# CONFIG_DAB is not set
#
# Graphics support
#
# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_FB_OMAP_LCD_WVGA is not set
-# CONFIG_OMAP2_DSS is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_OMAP2_DSS=y
+CONFIG_OMAP2_DSS_VRAM_SIZE=4
+CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
+# CONFIG_OMAP2_DSS_RFBI is not set
+# CONFIG_OMAP2_DSS_VENC is not set
+# CONFIG_OMAP2_DSS_SDI is not set
+CONFIG_OMAP2_DSS_DSI=y
+# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=2
+
+#
+# OMAP2/3 Display Device Drivers
+#
+# CONFIG_PANEL_GENERIC is not set
+# CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C is not set
+# CONFIG_PANEL_SHARP_LS037V7DW01 is not set
+# CONFIG_PANEL_N800 is not set
+CONFIG_PANEL_ZOOM2=y
+# CONFIG_CTRL_BLIZZARD is not set
+CONFIG_SIL9022=y
+CONFIG_FB_OMAP2=y
+CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
+# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
+CONFIG_FB_OMAP2_NUM_FBS=1
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
#
# Display device support
@@ -1026,22 +1367,99 @@
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
-# CONFIG_SOUND is not set
-# CONFIG_HID_SUPPORT is not set
+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_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_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_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_SPI=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_MCBSP=y
+CONFIG_SND_OMAP_SOC_ZOOM2=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_TWL4030=y
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
#
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
-CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
CONFIG_USB_SUSPEND=y
CONFIG_USB_OTG=y
@@ -1081,7 +1499,7 @@
#
# USB Device Class drivers
#
-# CONFIG_USB_ACM is not set
+CONFIG_USB_ACM=m
# CONFIG_USB_PRINTER is not set
# CONFIG_USB_WDM is not set
# CONFIG_USB_TMC is not set
@@ -1093,8 +1511,8 @@
#
# see USB_STORAGE Help for more information
#
-CONFIG_USB_STORAGE=y
-# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_DEBUG=y
# CONFIG_USB_STORAGE_DATAFAB is not set
# CONFIG_USB_STORAGE_FREECOM is not set
# CONFIG_USB_STORAGE_ISD200 is not set
@@ -1117,7 +1535,63 @@
#
# USB port drivers
#
-# CONFIG_USB_SERIAL is not set
+CONFIG_USB_SERIAL=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN=m
+# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
#
# USB Miscellaneous drivers
@@ -1144,9 +1618,9 @@
# CONFIG_USB_ISIGHTFW is not set
# CONFIG_USB_VST is not set
CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_DEBUG_FS=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=2
CONFIG_USB_GADGET_SELECTED=y
# CONFIG_USB_GADGET_AT91 is not set
@@ -1166,14 +1640,17 @@
# CONFIG_USB_GADGET_GOKU is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
-# CONFIG_USB_ZERO is not set
-# CONFIG_USB_ETH is not set
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FILE_STORAGE is not set
-# CONFIG_USB_G_SERIAL is not set
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ZERO_HNPTEST is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
# CONFIG_USB_MIDI_GADGET is not set
# CONFIG_USB_G_PRINTER is not set
-CONFIG_USB_ANDROID=y
+CONFIG_USB_ANDROID=m
# CONFIG_USB_CDC_COMPOSITE is not set
#
@@ -1204,13 +1681,14 @@
# CONFIG_MMC_SDHCI is not set
CONFIG_MMC_OMAP_HS=y
# CONFIG_OMAP_HS_MMC2 is not set
-# CONFIG_OMAP_HS_MMC3 is not set
+CONFIG_OMAP_HS_MMC3=y
+CONFIG_HC_Broken_eMMC_ZOOM2=y
# CONFIG_MMC_SPI is not set
# CONFIG_MEMSTICK is not set
# CONFIG_ACCESSIBILITY is not set
# CONFIG_NEW_LEDS is not set
CONFIG_SWITCH=y
-# CONFIG_SWITCH_GPIO is not set
+CONFIG_SWITCH_GPIO=y
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
@@ -1276,7 +1754,7 @@
#
# CONFIG_DMADEVICES is not set
CONFIG_REGULATOR=y
-CONFIG_REGULATOR_DEBUG=y
+# CONFIG_REGULATOR_DEBUG is not set
# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
# CONFIG_REGULATOR_BQ24022 is not set
@@ -1310,7 +1788,20 @@
# CBUS support
#
# CONFIG_CBUS is not set
-# CONFIG_MPU_BRIDGE is not set
+CONFIG_MPU_BRIDGE=y
+CONFIG_BRIDGE_DVFS=y
+CONFIG_BRIDGE_MEMPOOL_SIZE=0x600000
+# CONFIG_BRIDGE_DEBUG is not set
+
+#
+# Bridge Hacking
+#
+# CONFIG_BRIDGE_CACHE_LINE_CHECK is not set
+
+#
+# Bridge Notifications
+#
+# CONFIG_BRIDGE_NTFY_PWRERR is not set
#
# File systems
@@ -1379,7 +1870,17 @@
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-# CONFIG_YAFFS_FS is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1517,8 +2018,9 @@
# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
# CONFIG_DEBUG_KOBJECT is not set
-CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_WRITECOUNT is not set
@@ -1534,7 +2036,10 @@
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
+CONFIG_NOP_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
#
# Tracers
@@ -1547,6 +2052,7 @@
# CONFIG_BOOT_TRACER is not set
# CONFIG_TRACE_BRANCH_PROFILING is not set
# CONFIG_STACK_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
@@ -1554,8 +2060,7 @@
# CONFIG_DEBUG_USER is not set
# CONFIG_DEBUG_ERRORS is not set
# CONFIG_DEBUG_STACK_USAGE is not set
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_LL is not set
#
# Security options
diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h
index cb7a9e9..66c160b 100644
--- a/arch/arm/include/asm/cache.h
+++ b/arch/arm/include/asm/cache.h
@@ -4,7 +4,23 @@
#ifndef __ASMARM_CACHE_H
#define __ASMARM_CACHE_H
-#define L1_CACHE_SHIFT 5
+#define L1_CACHE_SHIFT CONFIG_ARM_L1_CACHE_SHIFT
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
+/*
+ * Memory returned by kmalloc() may be used for DMA, so we must make
+ * sure that all such allocations are cache aligned. Otherwise,
+ * unrelated code may cause parts of the buffer to be read into the
+ * cache before the transfer is done, causing old data to be seen by
+ * the CPU.
+ */
+#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES
+
+/*
+ * With EABI on ARMv5 and above we must have 64-bit aligned slab pointers.
+ */
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define ARCH_SLAB_MINALIGN 8
+#endif
+
#endif
diff --git a/arch/arm/include/asm/hwcap.h b/arch/arm/include/asm/hwcap.h
index bda489f..f7bd52b 100644
--- a/arch/arm/include/asm/hwcap.h
+++ b/arch/arm/include/asm/hwcap.h
@@ -17,6 +17,8 @@
#define HWCAP_CRUNCH 1024
#define HWCAP_THUMBEE 2048
#define HWCAP_NEON 4096
+#define HWCAP_VFPv3 8192
+#define HWCAP_VFPv3D16 16384
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
/*
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index cbdadfe..d2a59cf 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -75,12 +75,6 @@
extern void __iounmap(volatile void __iomem *addr);
/*
- * external interface to remap single page with appropriate type
- */
-extern int ioremap_page(unsigned long virt, unsigned long phys,
- unsigned int mtype);
-
-/*
* Bad read/write accesses...
*/
extern void __readwrite_bug(const char *fn);
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index 58cf91f..742c2aa 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -30,6 +30,14 @@
#ifdef CONFIG_MMU
extern void iotable_init(struct map_desc *, int);
+
+struct mem_type;
+extern const struct mem_type *get_mem_type(unsigned int type);
+/*
+ * external interface to remap single page with appropriate type
+ */
+extern int ioremap_page(unsigned long virt, unsigned long phys,
+ const struct mem_type *mtype);
#else
#define iotable_init(map,num) do { } while (0)
#endif
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index f341c9d..1c75656 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -194,13 +194,6 @@
(((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-/*
- * With EABI on ARMv5 and above we must have 64-bit aligned slab pointers.
- */
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define ARCH_SLAB_MINALIGN 8
-#endif
-
#include <asm-generic/page.h>
#endif
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 7319261..236a06b 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -27,6 +27,8 @@
/* PTRACE_SYSCALL is 24 */
#define PTRACE_GETCRUNCHREGS 25
#define PTRACE_SETCRUNCHREGS 26
+#define PTRACE_GETVFPREGS 27
+#define PTRACE_SETVFPREGS 28
/*
* PSR bits
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 68b9ec8..b9dc8a8 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -113,6 +113,8 @@
extern void iwmmxt_task_release(struct thread_info *);
extern void iwmmxt_task_switch(struct thread_info *);
+extern void vfp_sync_state(struct thread_info *thread);
+
#endif
/*
diff --git a/arch/arm/include/asm/user.h b/arch/arm/include/asm/user.h
index 825c1e7..df95e05 100644
--- a/arch/arm/include/asm/user.h
+++ b/arch/arm/include/asm/user.h
@@ -81,4 +81,13 @@
#define HOST_TEXT_START_ADDR (u.start_code)
#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+/*
+ * User specific VFP registers. If only VFPv2 is present, registers 16 to 31
+ * are ignored by the ptrace system call.
+ */
+struct user_vfp {
+ unsigned long long fpregs[32];
+ unsigned long fpscr;
+};
+
#endif /* _ARM_USER_H */
diff --git a/arch/arm/include/asm/vfpmacros.h b/arch/arm/include/asm/vfpmacros.h
index 422f3cc..934798b 100644
--- a/arch/arm/include/asm/vfpmacros.h
+++ b/arch/arm/include/asm/vfpmacros.h
@@ -32,6 +32,9 @@
@ write all the working registers out of the VFP
.macro VFPFSTMIA, base, tmp
+#ifdef CONFIG_ARM_ERRATUM_451034
+ dmb
+#endif
#if __LINUX_ARM_ARCH__ < 6
STC p11, cr0, [\base],#33*4 @ FSTMIAX \base!, {d0-d15}
#else
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 85040cf..4c482b1 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -154,6 +154,9 @@
__dabt_svc:
svc_entry
+#ifdef CONFIG_ARM_ERRATA_451027
+ dmb
+#endif
@
@ get ready to re-enable interrupts if appropriate
@
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 159d041..8f7fe18 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -69,6 +69,9 @@
/* perform architecture specific actions before user return */
arch_ret_to_user r1, lr
+#ifdef CONFIG_ARM_ERRATUM_451034
+ dmb
+#endif
@ slow_restore_user_regs
ldr r1, [sp, #S_PSR] @ get calling cpsr
ldr lr, [sp, #S_PC]! @ get pc
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 994b4d3..f884b85 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -234,7 +234,7 @@
printk("%04lx ", (unsigned long)p & 0xffff);
for (j = 0; j < 8; j++) {
u32 data;
- if (__get_user(data, p)) {
+ if (probe_kernel_address(p, data)) {
printk(" ********");
} else {
printk(" %08x", data);
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index df653ea..89882a1 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -653,6 +653,54 @@
}
#endif
+#ifdef CONFIG_VFP
+/*
+ * Get the child VFP state.
+ */
+static int ptrace_getvfpregs(struct task_struct *tsk, void __user *data)
+{
+ struct thread_info *thread = task_thread_info(tsk);
+ union vfp_state *vfp = &thread->vfpstate;
+ struct user_vfp __user *ufp = data;
+
+ vfp_sync_state(thread);
+
+ /* copy the floating point registers */
+ if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs,
+ sizeof(vfp->hard.fpregs)))
+ return -EFAULT;
+
+ /* copy the status and control register */
+ if (put_user(vfp->hard.fpscr, &ufp->fpscr))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * Set the child VFP state.
+ */
+static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data)
+{
+ struct thread_info *thread = task_thread_info(tsk);
+ union vfp_state *vfp = &thread->vfpstate;
+ struct user_vfp __user *ufp = data;
+
+ vfp_sync_state(thread);
+
+ /* copy the floating point registers */
+ if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs,
+ sizeof(vfp->hard.fpregs)))
+ return -EFAULT;
+
+ /* copy the status and control register */
+ if (get_user(vfp->hard.fpscr, &ufp->fpscr))
+ return -EFAULT;
+
+ return 0;
+}
+#endif
+
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
int ret;
@@ -775,6 +823,16 @@
break;
#endif
+#ifdef CONFIG_VFP
+ case PTRACE_GETVFPREGS:
+ ret = ptrace_getvfpregs(child, (void __user *)data);
+ break;
+
+ case PTRACE_SETVFPREGS:
+ ret = ptrace_setvfpregs(child, (void __user *)data);
+ break;
+#endif
+
default:
ret = ptrace_request(child, request, addr, data);
break;
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 68d6494..d301a53 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -780,6 +780,8 @@
"crunch",
"thumbee",
"neon",
+ "vfpv3",
+ "vfpv3d16",
NULL
};
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 13ad26a..921d02b 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -117,9 +117,23 @@
bool "OMAP3 ZOOM2 board"
depends on ARCH_OMAP3 && ARCH_OMAP34XX
+config MACH_OMAP_ZOOM3
+ bool "OMAP3 ZOOM3 board"
+ depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP_3630SDP
+ bool "OMAP3 3630 SDP board"
+ depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config L2CACHE_OMAP3_DISABLE
+ bool "Disable level 2 cache in Aux cntrl reg"
+ depends on ARCH_OMAP3
+ help
+ Say Y here to disable L2 cache.
+
config WIFI_CONTROL_FUNC
bool "Enable WiFi control function abstraction"
- depends on MACH_OMAP_ZOOM2
+ depends on MACH_OMAP_ZOOM2 || MACH_OMAP_ZOOM3
help
Enables Power/Reset/Carddetect function abstraction
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 3d6ee06..8cb7175 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -74,6 +74,13 @@
board-ldp-flash.o \
board-zoom2-camera.o \
board-zoom2-wifi.o
+obj-$(CONFIG_MACH_OMAP_ZOOM3) += board-zoom2.o \
+ mmc-twl4030.o \
+ board-ldp-flash.o \
+ board-zoom2-camera.o \
+ board-zoom2-wifi.o
+obj-$(CONFIG_MACH_OMAP_3630SDP) += board-3630sdp.o \
+ mmc-twl4030.o
obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o \
board-apollon-mmc.o \
board-apollon-keys.o
@@ -105,3 +112,7 @@
obj-y += usb-ehci.o
endif
+ifneq ($(CONFIG_USB_OHCI_HCD),)
+ obj-y += usb-ohci.o
+endif
+
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 76fdaef..cc59d04 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -42,7 +42,6 @@
#include <mach/control.h>
#include <mach/clock.h>
-
#include "sdram-qimonda-hyb18m512160af-6.h"
#include "mmc-twl4030.h"
#include "pm.h"
@@ -424,8 +423,31 @@
static void __init omap_3430sdp_init_irq(void)
{
- omap2_init_common_hw(hyb18m512160af6_sdrc_params, omap3_mpu_rate_table,
- omap3_dsp_rate_table, omap3_l3_rate_table);
+ switch (omap_rev_id()) {
+ case OMAP_3420:
+ omap2_init_common_hw(hyb18m512160af6_sdrc_params,
+ omap3_mpu_rate_table, omap3_dsp_rate_table_3420,
+ omap3_l3_rate_table);
+ break;
+
+ case OMAP_3430:
+ omap2_init_common_hw(hyb18m512160af6_sdrc_params,
+ omap3_mpu_rate_table, omap3_dsp_rate_table,
+ omap3_l3_rate_table);
+ break;
+
+ case OMAP_3440:
+ omap2_init_common_hw(hyb18m512160af6_sdrc_params,
+ omap3_mpu_rate_table, omap3_dsp_rate_table_3440,
+ omap3_l3_rate_table);
+ break;
+
+ default:
+ omap2_init_common_hw(hyb18m512160af6_sdrc_params,
+ omap3_mpu_rate_table, omap3_dsp_rate_table,
+ omap3_l3_rate_table);
+ break;
+ }
omap_init_irq();
omap_gpio_init();
sdp3430_init_smc91x();
@@ -777,7 +799,7 @@
.vpll2 = &sdp3430_vpll2,
};
-static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
+static struct i2c_board_info __initdata sdp3430_i2c1_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
.flags = I2C_CLIENT_WAKE,
@@ -786,13 +808,29 @@
},
};
+/* I2C Address for ISP1301 Transceiver */
+#define ISP1301_I2C_ADDR1 0x2C
+#define ISP1301_I2C_ADDR2 0x2D
+
+static struct i2c_board_info __initdata sdp3430_i2c2_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("isp1301_host", ISP1301_I2C_ADDR1),
+ .type = "isp1301_host",
+ },
+ {
+ I2C_BOARD_INFO("isp1301_host", ISP1301_I2C_ADDR2),
+ .type = "isp1301_host",
+ },
+};
+
static int __init omap3430_i2c_init(void)
{
/* i2c1 for PMIC only */
- omap_register_i2c_bus(1, 2600, sdp3430_i2c_boardinfo,
- ARRAY_SIZE(sdp3430_i2c_boardinfo));
- /* i2c2 on camera connector (for sensor control) and optional isp1301 */
- omap_register_i2c_bus(2, 400, NULL, 0);
+ omap_register_i2c_bus(1, 2600, sdp3430_i2c1_boardinfo,
+ ARRAY_SIZE(sdp3430_i2c1_boardinfo));
+ /* i2c2 optional isp1301 */
+ omap_register_i2c_bus(2, 100, sdp3430_i2c2_boardinfo,
+ ARRAY_SIZE(sdp3430_i2c2_boardinfo));
/* i2c3 on display connector (for DVI, tfp410) */
omap_register_i2c_bus(3, 400, NULL, 0);
return 0;
@@ -817,6 +855,7 @@
omap_serial_init();
usb_musb_init();
usb_ehci_init();
+ usb_ohci_init();
sdp3430_display_init();
}
@@ -829,7 +868,7 @@
MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
/* Maintainer: Syed Khasim - Texas Instruments Inc */
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap_3430sdp_map_io,
.init_irq = omap_3430sdp_init_irq,
diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c
new file mode 100644
index 0000000..3e20015
--- /dev/null
+++ b/arch/arm/mach-omap2/board-3630sdp.c
@@ -0,0 +1,963 @@
+/*
+ * linux/arch/arm/mach-omap2/board-sdp3630.c
+ *
+ * Copyright (C) 2009 Texas Instruments Inc.
+ * Harish Hanumanthappa <h-harish@ti.com>
+ *
+ * Modified from mach-omap2/board-zoom2.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/workqueue.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/synaptics_i2c_rmi.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/machine.h>
+#ifdef CONFIG_SIL9022
+#include <linux/sil9022.h>
+#endif
+#include <linux/switch.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/board-zoom2.h>
+#include <mach/mcspi.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/gpmc.h>
+#include <mach/usb.h>
+#include <mach/mux.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <mach/control.h>
+
+#include <mach/display.h>
+#include <mach/hdq.h>
+
+#include "mmc-twl4030.h"
+#include "omap3-opp.h"
+#include "sdram-hynix-h8mbx00u0mer-0em.h"
+
+#include <media/v4l2-int-device.h>
+
+#ifdef CONFIG_PM
+#include <../drivers/media/video/omap/omap_voutdef.h>
+#endif
+
+#ifdef CONFIG_VIDEO_LV8093
+#include <media/lv8093.h>
+#define LV8093_PS_GPIO 7
+/* GPIO7 is connected to lens PS pin through inverter */
+#define LV8093_PWR_OFF 1
+#define LV8093_PWR_ON (!LV8093_PWR_OFF)
+#endif
+
+#ifndef CONFIG_TWL4030_CORE
+#error "no power companion board defined!"
+#endif
+
+#ifdef CONFIG_WL127X_RFKILL
+#include <linux/wl127x-rfkill.h>
+#endif
+
+#define OMAP_SYNAPTICS_GPIO 163
+
+#define SDP3630_SMC91X_CS 3
+#define SDP3630_ETHR_SMC91X_GPIO 158
+
+#define TWL4030_MSECURE_GPIO 22
+
+static struct pin_config sdp3630_mux_pins[] = {
+/*
+ * Name, reg-offset,
+ * mux-mode | [active-mode | off-mode]
+ */
+
+/* McBSPs */
+MUX_CFG_34XX("MCBSP2_SLAVE", 0x13c /* FSX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP2_SLAVE", 0x13e /* CLKX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP2_SLAVE", 0x140 /* DR */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP2_SLAVE", 0x142 /* DX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x194 /* CLKS */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x172 /* FSX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x170 /* CLKX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x16e /* DR */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x16c /* DX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x172 /* FSX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x170 /* CLKX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x16e /* DR */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x16c /* DX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x172 /* FSX */,
+ OMAP34XX_MUX_MODE7)
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x170 /* CLKX */,
+ OMAP34XX_MUX_MODE7)
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x16e /* DR */,
+ OMAP34XX_MUX_MODE7)
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x16c /* DX */,
+ OMAP34XX_MUX_MODE7)
+MUX_CFG_34XX("MCBSP4_MASTER", 0x194 /* CLKS */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP4_MASTER", 0x18a /* FSX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP4_MASTER", 0x0b6 /* CLKX */,
+ OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP4_MASTER", 0x0b8 /* DR */,
+ OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP4_MASTER", 0x0ba /* DX */,
+ OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP4_SLAVE", 0x18a /* FSX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP4_SLAVE", 0x0b6 /* CLKX */,
+ OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP4_SLAVE", 0x0b8 /* DR */,
+ OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP4_SLAVE", 0x0ba /* DX */,
+ OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
+};
+
+static struct omap_mux_cfg sdp3630_mux_cfg = {
+ .pins = sdp3630_mux_pins,
+ .size = ARRAY_SIZE(sdp3630_mux_pins),
+};
+
+static struct resource sdp3630_smc91x_resources[] = {
+ [0] = {
+ .start = OMAP34XX_ETHR_START,
+ .end = OMAP34XX_ETHR_START + SZ_4K,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+ },
+};
+
+static struct platform_device sdp3630_smc91x_device = {
+ .name = "smc91x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(sdp3630_smc91x_resources),
+ .resource = sdp3630_smc91x_resources,
+};
+
+/* sdp3630 has Qwerty keyboard*/
+static int sdp3630_twl4030_keymap[] = {
+ KEY(0, 0, KEY_E),
+ KEY(1, 0, KEY_R),
+ KEY(2, 0, KEY_T),
+ KEY(3, 0, KEY_HOME),
+ KEY(6, 0, KEY_I),
+ KEY(7, 0, KEY_LEFTSHIFT),
+ KEY(0, 1, KEY_D),
+ KEY(1, 1, KEY_F),
+ KEY(2, 1, KEY_G),
+ KEY(3, 1, KEY_SEND),
+ KEY(6, 1, KEY_K),
+ KEY(7, 1, KEY_ENTER),
+ KEY(0, 2, KEY_X),
+ KEY(1, 2, KEY_C),
+ KEY(2, 2, KEY_V),
+ KEY(3, 2, KEY_END),
+ KEY(6, 2, KEY_DOT),
+ KEY(7, 2, KEY_CAPSLOCK),
+ KEY(0, 3, KEY_Z),
+ KEY(1, 3, KEY_KPPLUS),
+ KEY(2, 3, KEY_B),
+ KEY(3, 3, KEY_F1),
+ KEY(6, 3, KEY_O),
+ KEY(7, 3, KEY_SPACE),
+ KEY(0, 4, KEY_W),
+ KEY(1, 4, KEY_Y),
+ KEY(2, 4, KEY_U),
+ KEY(3, 4, KEY_F2),
+ KEY(4, 4, KEY_VOLUMEUP),
+ KEY(6, 4, KEY_L),
+ KEY(7, 4, KEY_LEFT),
+ KEY(0, 5, KEY_S),
+ KEY(1, 5, KEY_H),
+ KEY(2, 5, KEY_J),
+ KEY(3, 5, KEY_F3),
+ KEY(5, 5, KEY_VOLUMEDOWN),
+ KEY(6, 5, KEY_M),
+ KEY(4, 5, KEY_ENTER),
+ KEY(7, 5, KEY_RIGHT),
+ KEY(0, 6, KEY_Q),
+ KEY(1, 6, KEY_A),
+ KEY(2, 6, KEY_N),
+ KEY(3, 6, KEY_BACKSPACE),
+ KEY(6, 6, KEY_P),
+ KEY(7, 6, KEY_UP),
+ KEY(6, 7, KEY_SELECT),
+ KEY(7, 7, KEY_DOWN),
+ KEY(0, 7, KEY_PROG1), /*MACRO 1 <User defined> */
+ KEY(1, 7, KEY_PROG2), /*MACRO 2 <User defined> */
+ KEY(2, 7, KEY_PROG3), /*MACRO 3 <User defined> */
+ KEY(3, 7, KEY_PROG4), /*MACRO 4 <User defined> */
+ 0
+};
+
+static struct twl4030_keypad_data sdp3630_kp_twl4030_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap = sdp3630_twl4030_keymap,
+ .keymapsize = ARRAY_SIZE(sdp3630_twl4030_keymap),
+ .rep = 1,
+};
+
+static int __init msecure_init(void)
+{
+ int ret = 0;
+
+#ifdef CONFIG_RTC_DRV_TWL4030
+ /* 3430ES2.0 doesn't have msecure/gpio-22 line connected to T2 */
+ if (omap_type() == OMAP2_DEVICE_TYPE_GP &&
+ omap_rev() < OMAP3430_REV_ES2_0) {
+ void __iomem *msecure_pad_config_reg =
+ omap_ctrl_base_get() + 0xA3C;
+ int mux_mask = 0x04;
+ u16 tmp;
+
+ ret = gpio_request(TWL4030_MSECURE_GPIO, "msecure");
+ if (ret < 0) {
+ printk(KERN_ERR "msecure_init: can't"
+ "reserve GPIO:%d !\n", TWL4030_MSECURE_GPIO);
+ goto out;
+ }
+ /*
+ * TWL4030 will be in secure mode if msecure line from OMAP
+ * is low. Make msecure line high in order to change the
+ * TWL4030 RTC time and calender registers.
+ */
+
+ tmp = __raw_readw(msecure_pad_config_reg);
+ tmp &= 0xF8; /* To enable mux mode 03/04 = GPIO_RTC */
+ tmp |= mux_mask;/* To enable mux mode 03/04 = GPIO_RTC */
+ __raw_writew(tmp, msecure_pad_config_reg);
+
+ gpio_direction_output(TWL4030_MSECURE_GPIO, 1);
+ }
+out:
+#endif
+ return ret;
+}
+
+static struct omap2_mcspi_device_config sdp3630_lcd_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1, /* 0: slave, 1: master */
+};
+
+static struct spi_board_info sdp3630_spi_board_info[] __initdata = {
+ [0] = {
+ .modalias = "sdp3630_disp_spi",
+ .bus_num = 1,
+ .chip_select = 2,
+ .max_speed_hz = 375000,
+ .controller_data = &sdp3630_lcd_mcspi_config,
+ },
+};
+
+#define LCD_PANEL_BACKLIGHT_GPIO (7 + OMAP_MAX_GPIO_LINES)
+
+#define LCD_PANEL_RESET_GPIO 55
+#define LCD_PANEL_QVGA_GPIO 56
+
+#define TV_PANEL_ENABLE_GPIO 95
+
+
+#define PM_RECEIVER TWL4030_MODULE_PM_RECEIVER
+#define ENABLE_VAUX2_DEDICATED 0x09
+#define ENABLE_VAUX2_DEV_GRP 0x20
+
+#define ENABLE_VPLL2_DEDICATED 0x05
+#define ENABLE_VPLL2_DEV_GRP 0xE0
+#define TWL4030_VPLL2_DEV_GRP 0x33
+#define TWL4030_VPLL2_DEDICATED 0x36
+
+#define SIL9022_RESET_GPIO 97
+
+#define t2_out(c, r, v) twl4030_i2c_write_u8(c, r, v)
+
+static int sdp3630_panel_power_enable(int enable)
+{
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ (enable) ? ENABLE_VPLL2_DEDICATED : 0,
+ TWL4030_VPLL2_DEDICATED);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ (enable) ? ENABLE_VPLL2_DEV_GRP : 0,
+ TWL4030_VPLL2_DEV_GRP);
+ return 0;
+}
+
+static int sdp3630_panel_enable_lcd(struct omap_dss_device *dssdev)
+{
+ sdp3630_panel_power_enable(1);
+
+ gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 1);
+
+ return 0;
+}
+
+static void sdp3630_panel_disable_lcd(struct omap_dss_device *dssdev)
+{
+#ifndef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+ sdp3630_panel_power_enable(0);
+#endif
+
+ gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 0);
+
+}
+
+static struct omap_dss_device sdp3630_lcd_device = {
+ .name = "lcd",
+ .driver_name = "sdp3630_panel",
+ .type = OMAP_DISPLAY_TYPE_DPI,
+ .phy.dpi.data_lines = 24,
+ .platform_enable = sdp3630_panel_enable_lcd,
+ .platform_disable = sdp3630_panel_disable_lcd,
+ };
+
+#ifdef CONFIG_SIL9022
+static void sdp3630_hdmi_reset_enable(int level)
+{
+ /* Set GPIO_97 to high to pull SiI9022 HDMI transmitter
+ * out of reset and low to disable it.
+ */
+ gpio_request(SIL9022_RESET_GPIO, "hdmi reset");
+ gpio_direction_output(SIL9022_RESET_GPIO, level);
+}
+
+static int sdp3630_panel_enable_hdmi(struct omap_dss_device *dssdev)
+{
+ sdp3630_panel_power_enable(1);
+ sdp3630_hdmi_reset_enable(1);
+
+ return 0;
+}
+
+static void sdp3630_panel_disable_hdmi(struct omap_dss_device *dssdev)
+{
+ sdp3630_hdmi_reset_enable(0);
+#ifndef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+ sdp3630_panel_power_enable(0);
+#endif
+}
+struct hdmi_platform_data sdp3630_hdmi_data = {
+#ifdef CONFIG_PM
+ .set_min_bus_tput = omap_pm_set_min_bus_tput,
+#endif
+};
+
+static struct omap_dss_device sdp3630_hdmi_device = {
+ .name = "hdmi",
+ .driver_name = "hdmi_panel",
+ .type = OMAP_DISPLAY_TYPE_HDMI,
+ .phy.dpi.data_lines = 24,
+ .platform_enable = sdp3630_panel_enable_hdmi,
+ .platform_disable = sdp3630_panel_disable_hdmi,
+ .dev = {
+ .platform_data = &sdp3630_hdmi_data,
+ },
+};
+#endif
+
+
+static int sdp3630_panel_enable_tv(struct omap_dss_device *dssdev)
+{
+#define ENABLE_VDAC_DEDICATED 0x03
+#define ENABLE_VDAC_DEV_GRP 0x20
+
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ ENABLE_VDAC_DEDICATED,
+ TWL4030_VDAC_DEDICATED);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ ENABLE_VDAC_DEV_GRP, TWL4030_VDAC_DEV_GRP);
+
+ return 0;
+}
+
+static void sdp3630_panel_disable_tv(struct omap_dss_device *dssdev)
+{
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x00,
+ TWL4030_VDAC_DEDICATED);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x00,
+ TWL4030_VDAC_DEV_GRP);
+}
+static struct omap_dss_device sdp3630_tv_device = {
+ .name = "tv",
+ .driver_name = "venc",
+ .type = OMAP_DISPLAY_TYPE_VENC,
+ .phy.venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE,
+ .platform_enable = sdp3630_panel_enable_tv,
+ .platform_disable = sdp3630_panel_disable_tv,
+};
+
+static struct omap_dss_device *sdp3630_dss_devices[] = {
+ &sdp3630_lcd_device,
+ &sdp3630_tv_device,
+#ifdef CONFIG_SIL9022
+ &sdp3630_hdmi_device,
+#endif
+};
+
+static struct omap_dss_board_info sdp3630_dss_data = {
+ .get_last_off_on_transaction_id = get_last_off_on_transaction_id,
+ .num_devices = ARRAY_SIZE(sdp3630_dss_devices),
+ .devices = sdp3630_dss_devices,
+ .default_device = &sdp3630_lcd_device,
+};
+
+static struct platform_device sdp3630_dss_device = {
+ .name = "omapdss",
+ .id = -1,
+ .dev = {
+ .platform_data = &sdp3630_dss_data,
+ },
+};
+
+static struct regulator_consumer_supply sdp3630_vdda_dac_supply = {
+ .supply = "vdda_dac",
+ .dev = &sdp3630_dss_device.dev,
+};
+
+static struct regulator_consumer_supply sdp3630_vdds_dsi_supply = {
+ .supply = "vdds_dsi",
+ .dev = &sdp3630_dss_device.dev,
+};
+
+#ifdef CONFIG_FB_OMAP2
+static struct resource sdp3630_vout_resource[3 - CONFIG_FB_OMAP2_NUM_FBS] = {
+};
+#else
+static struct resource sdp3630_vout_resource[2] = {
+};
+#endif
+
+#ifdef CONFIG_PM
+struct vout_platform_data sdp3630_vout_data = {
+ .set_min_bus_tput = omap_pm_set_min_bus_tput,
+ .set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat,
+ .set_vdd1_opp = omap_pm_set_min_mpu_freq,
+ .set_cpu_freq = omap_pm_cpu_set_freq,
+};
+#endif
+
+static struct platform_device sdp3630_vout_device = {
+ .name = "omap_vout",
+ .num_resources = ARRAY_SIZE(sdp3630_vout_resource),
+ .resource = &sdp3630_vout_resource[0],
+ .id = -1,
+#ifdef CONFIG_PM
+ .dev = {
+ .platform_data = &sdp3630_vout_data,
+ }
+#else
+ .dev = {
+ .platform_data = NULL,
+ }
+#endif
+};
+
+static struct gpio_switch_platform_data headset_switch_data = {
+ .name = "h2w",
+ .gpio = OMAP_MAX_GPIO_LINES + 2, /* TWL4030 GPIO_2 */
+};
+
+static struct platform_device headset_switch_device = {
+ .name = "switch-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &headset_switch_data,
+ }
+};
+
+static struct platform_device *sdp3630_devices[] __initdata = {
+ &sdp3630_dss_device,
+ &sdp3630_smc91x_device,
+#if defined(CONFIG_HDQ_MASTER_OMAP) || defined(CONFIG_HDQ_MASTER_OMAP_MODULE)
+ &omap_hdq_device,
+#endif
+ &sdp3630_vout_device,
+ &headset_switch_device,
+};
+
+static inline void __init sdp3630_init_smc91x(void)
+{
+ int eth_cs;
+ unsigned long cs_mem_base;
+ int eth_gpio = 0;
+
+ eth_cs = SDP3630_SMC91X_CS;
+
+ if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
+ printk(KERN_ERR "Failed to request GPMC mem for smc911x\n");
+ return;
+ }
+
+ sdp3630_smc91x_resources[0].start = cs_mem_base + 0x300;
+ sdp3630_smc91x_resources[0].end = cs_mem_base + 0x30f;
+ udelay(100);
+
+ eth_gpio = SDP3630_ETHR_SMC91X_GPIO;
+
+ sdp3630_smc91x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
+
+ if (gpio_request(eth_gpio, "smc91x irq") < 0) {
+ printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n",
+ eth_gpio);
+ return;
+ }
+ gpio_direction_input(eth_gpio);
+}
+
+/* Quad UART (TL16CP754C) is on sdp3630 debug board */
+/* Map registers to GPMC CS3 */
+
+static void __init omap_sdp3630_init_irq(void)
+{
+ omap2_init_common_hw(h8mbx00u0mer0em_sdrc_params,
+ omap3630_mpu_rate_table, omap3630_dsp_rate_table,
+ omap3630_l3_rate_table);
+ /* Production board supports McBSP4 */
+ omap2_mux_register(&sdp3630_mux_cfg);
+ omap_init_irq();
+ omap_gpio_init();
+ sdp3630_init_smc91x();
+}
+
+static struct regulator_consumer_supply sdp3630_vmmc1_supply = {
+ .supply = "vmmc",
+};
+
+static struct regulator_consumer_supply sdp3630_vsim_supply = {
+ .supply = "vmmc_aux",
+};
+
+static struct regulator_consumer_supply sdp3630_vmmc2_supply = {
+ .supply = "vmmc",
+};
+
+/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
+static struct regulator_init_data sdp3630_vmmc1 = {
+ .constraints = {
+ .min_uV = 1850000,
+ .max_uV = 3150000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &sdp3630_vmmc1_supply,
+};
+
+/* VMMC2 for MMC2 card */
+static struct regulator_init_data sdp3630_vmmc2 = {
+ .constraints = {
+ .min_uV = 1850000,
+ .max_uV = 1850000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &sdp3630_vmmc2_supply,
+};
+
+/* VSIM for OMAP VDD_MMC1A (i/o for DAT4..DAT7) */
+static struct regulator_init_data sdp3630_vsim = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 3000000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &sdp3630_vsim_supply,
+};
+
+static struct regulator_init_data sdp3630_vdac = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &sdp3630_vdda_dac_supply,
+};
+
+static struct regulator_init_data sdp3630_vdsi = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &sdp3630_vdds_dsi_supply,
+};
+
+static struct twl4030_hsmmc_info mmc[] __initdata = {
+ {
+ .mmc = 1,
+ .wires = 4,
+ .gpio_wp = -EINVAL,
+ },
+ {} /* Terminator */
+};
+
+static int sdp3630_twl_gpio_setup(struct device *dev,
+ unsigned gpio, unsigned ngpio)
+{
+ /* gpio + 0 is "mmc0_cd" (input/IRQ),
+ * gpio + 1 is "mmc1_cd" (input/IRQ)
+ */
+ mmc[0].gpio_cd = gpio + 0;
+ mmc[1].gpio_cd = gpio + 1;
+ twl4030_mmc_init(mmc);
+
+ /* link regulators to MMC adapters ... we "know" the
+ * regulators will be set up only *after* we return.
+ */
+ sdp3630_vmmc1_supply.dev = mmc[0].dev;
+ sdp3630_vsim_supply.dev = mmc[0].dev;
+ sdp3630_vmmc2_supply.dev = mmc[1].dev;
+
+ return 0;
+}
+
+static struct omap_lcd_config sdp3630_lcd_config __initdata = {
+ .ctrl_name = "internal",
+};
+
+static struct omap_uart_config sdp3630_uart_config __initdata = {
+ .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)),
+};
+
+static struct omap_board_config_kernel sdp3630_config[] __initdata = {
+ { OMAP_TAG_UART, &sdp3630_uart_config },
+ { OMAP_TAG_LCD, &sdp3630_lcd_config },
+};
+
+static int sdp3630_batt_table[] = {
+/* 0 C*/
+30800, 29500, 28300, 27100,
+26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
+17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
+11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310,
+8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830,
+5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170,
+4040, 3910, 3790, 3670, 3550
+};
+
+static struct twl4030_bci_platform_data sdp3630_bci_data = {
+ .battery_tmp_tbl = sdp3630_batt_table,
+ .tblsize = ARRAY_SIZE(sdp3630_batt_table),
+ .twl4030_bci_charging_current = 1100, /* 1.1A for sdp3630 */
+};
+
+static struct twl4030_usb_data sdp3630_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
+static struct twl4030_gpio_platform_data sdp3630_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+ .setup = sdp3630_twl_gpio_setup,
+};
+
+static struct twl4030_madc_platform_data sdp3630_madc_data = {
+ .irq_line = 1,
+};
+
+static struct twl4030_ins __initdata sleep_on_seq[] = {
+
+ /* Turn off HFCLKOUT */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_OFF), 2},
+ /* Turn OFF VDD1 */
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_OFF), 2},
+ /* Turn OFF VDD2 */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_OFF), 2},
+ /* Turn OFF VPLL1 */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_OFF), 2},
+};
+
+static struct twl4030_script sleep_on_script __initdata = {
+ .script = sleep_on_seq,
+ .size = ARRAY_SIZE(sleep_on_seq),
+ .flags = TRITON_SLEEP_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_p12_seq[] __initdata = {
+ /* Turn on HFCLKOUT */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+ /* Turn ON VDD1 */
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 2},
+ /* Turn ON VDD2 */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 2},
+ /* Turn ON VPLL1 */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_p12_script __initdata = {
+ .script = wakeup_p12_seq,
+ .size = ARRAY_SIZE(wakeup_p12_seq),
+ .flags = TRITON_WAKEUP12_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_p3_seq[] __initdata = {
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_p3_script __initdata = {
+ .script = wakeup_p3_seq,
+ .size = ARRAY_SIZE(wakeup_p3_seq),
+ .flags = TRITON_WAKEUP3_SCRIPT,
+};
+
+static struct twl4030_ins wrst_seq[] __initdata = {
+/*
+ * Reset twl4030.
+ * Reset VDD1 regulator.
+ * Reset VDD2 regulator.
+ * Reset VPLL1 regulator.
+ * Enable sysclk output.
+ * Reenable twl4030.
+ */
+ {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_OFF), 2},
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_WRST), 15},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_WRST), 15},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_WRST), 0x60},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+ {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wrst_script __initdata = {
+ .script = wrst_seq,
+ .size = ARRAY_SIZE(wrst_seq),
+ .flags = TRITON_WRST_SCRIPT,
+};
+
+static struct twl4030_script *twl4030_scripts[] __initdata = {
+ &sleep_on_script,
+ &wakeup_p12_script,
+ &wakeup_p3_script,
+ &wrst_script,
+};
+
+static struct twl4030_resconfig twl4030_rconfig[] = {
+ { .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3, .type = -1,
+ .type2 = -1 },
+ { .resource = RES_VDD1, .devgroup = DEV_GRP_P1, .type = -1,
+ .type2 = -1 },
+ { .resource = RES_VDD2, .devgroup = DEV_GRP_P1, .type = -1,
+ .type2 = -1 },
+ { 0, 0},
+};
+
+static struct twl4030_power_data sdp3630_t2scripts_data __initdata = {
+ .scripts = twl4030_scripts,
+ .size = ARRAY_SIZE(twl4030_scripts),
+ .resource_config = twl4030_rconfig,
+};
+
+static struct twl4030_platform_data sdp3630_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .bci = &sdp3630_bci_data,
+ .madc = &sdp3630_madc_data,
+ .usb = &sdp3630_usb_data,
+ .gpio = &sdp3630_gpio_data,
+ .keypad = &sdp3630_kp_twl4030_data,
+ .power = &sdp3630_t2scripts_data,
+ .vmmc1 = &sdp3630_vmmc1,
+ .vmmc2 = &sdp3630_vmmc2,
+ .vsim = &sdp3630_vsim,
+ .vdac = &sdp3630_vdac,
+ .vpll2 = &sdp3630_vdsi,
+};
+
+static struct i2c_board_info __initdata sdp3630_i2c_bus1_info[] = {
+ {
+ I2C_BOARD_INFO("twl4030", 0x48),
+ .flags = I2C_CLIENT_WAKE,
+ .irq = INT_34XX_SYS_NIRQ,
+ .platform_data = &sdp3630_twldata,
+ },
+};
+
+static void synaptics_dev_init(void)
+{
+ /* Set the ts_gpio pin mux */
+ omap_cfg_reg(H18_34XX_GPIO163);
+
+ if (gpio_request(OMAP_SYNAPTICS_GPIO, "touch") < 0) {
+ printk(KERN_ERR "can't get synaptics pen down GPIO\n");
+ return;
+ }
+ gpio_direction_input(OMAP_SYNAPTICS_GPIO);
+ omap_set_gpio_debounce(OMAP_SYNAPTICS_GPIO, 1);
+ omap_set_gpio_debounce_time(OMAP_SYNAPTICS_GPIO, 0xa);
+}
+
+static int synaptics_power(int power_state)
+{
+ /* TODO: synaptics is powered by vbatt */
+ return 0;
+}
+
+static struct synaptics_i2c_rmi_platform_data synaptics_platform_data[] = {
+ {
+ .version = 0x0,
+ .power = &synaptics_power,
+ .flags = SYNAPTICS_SWAP_XY,
+ .irqflags = IRQF_TRIGGER_LOW,
+ }
+};
+
+/* I2C Address for ISP1301 Transceiver */
+#define ISP1301_I2C_ADDR1 0x2C
+#define ISP1301_I2C_ADDR2 0x2D
+
+static struct i2c_board_info __initdata sdp3630_i2c_bus2_info[] = {
+ {
+ I2C_BOARD_INFO(SYNAPTICS_I2C_RMI_NAME, 0x20),
+ .platform_data = &synaptics_platform_data,
+ .irq = OMAP_GPIO_IRQ(OMAP_SYNAPTICS_GPIO),
+ },
+#ifdef CONFIG_VIDEO_LV8093
+ {
+ I2C_BOARD_INFO(LV8093_NAME, LV8093_AF_I2C_ADDR),
+ .platform_data = &sdp3630_lv8093_platform_data,
+ },
+#endif
+ {
+ I2C_BOARD_INFO("isp1301_host", ISP1301_I2C_ADDR1),
+ .type = "isp1301_host",
+ },
+ {
+ I2C_BOARD_INFO("isp1301_host", ISP1301_I2C_ADDR2),
+ .type = "isp1301_host",
+ },
+};
+
+static struct i2c_board_info __initdata sdp3630_i2c_bus3_info[] = {
+#ifdef CONFIG_SIL9022
+ {
+ I2C_BOARD_INFO(SIL9022_DRV_NAME, SI9022_I2CSLAVEADDRESS),
+ },
+#endif
+};
+
+
+static int __init omap_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 100, sdp3630_i2c_bus1_info,
+ ARRAY_SIZE(sdp3630_i2c_bus1_info));
+ omap_register_i2c_bus(2, 100, sdp3630_i2c_bus2_info,
+ ARRAY_SIZE(sdp3630_i2c_bus2_info));
+ omap_register_i2c_bus(3, 400, sdp3630_i2c_bus3_info,
+ ARRAY_SIZE(sdp3630_i2c_bus3_info));
+ return 0;
+}
+
+/* usb1hs reset is routed to chip select pin of ISP1504
+ * on 750-2099-003(A) daughter card */
+static void config_usb1hs_gpio(void)
+{
+ omap_cfg_reg(D25_34XX_GPIO126);
+}
+
+/* Set GPIO56 to safemode (input only),
+ * this prevents a toggle on RCV pin of ISP1301
+ */
+static void config_usb3fs_gpio(void)
+{
+ omap_cfg_reg(R8_34XX_GPIO56_TRISTATE);
+}
+
+static void enable_board_wakeup_source(void)
+{
+ omap_cfg_reg(AF26_34XX_SYS_NIRQ);
+}
+
+static void __init omap_sdp3630_init(void)
+{
+ omap_i2c_init();
+ platform_add_devices(sdp3630_devices, ARRAY_SIZE(sdp3630_devices));
+ omap_board_config = sdp3630_config;
+ omap_board_config_size = ARRAY_SIZE(sdp3630_config);
+ spi_register_board_info(sdp3630_spi_board_info,
+ ARRAY_SIZE(sdp3630_spi_board_info));
+ synaptics_dev_init();
+ msecure_init();
+ omap_serial_init();
+ usb_musb_init();
+ config_usb1hs_gpio();
+ usb_ehci_init();
+ config_usb3fs_gpio();
+ usb_ohci_init();
+#ifdef CONFIG_SIL9022
+ config_hdmi_gpio();
+ sdp3630_hdmi_reset_enable(1);
+#endif
+ enable_board_wakeup_source();
+}
+
+static void __init omap_sdp3630_map_io(void)
+{
+ omap2_set_globals_343x();
+ omap2_map_common_io();
+}
+
+MACHINE_START(OMAP_3630SDP, "OMAP 3630SDP board")
+ .phys_io = 0x48000000,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = omap_sdp3630_map_io,
+ .init_irq = omap_sdp3630_init_irq,
+ .init_machine = omap_sdp3630_init,
+ .timer = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-ldp-flash.c b/arch/arm/mach-omap2/board-ldp-flash.c
index bbc84df..feb5d4a 100644
--- a/arch/arm/mach-omap2/board-ldp-flash.c
+++ b/arch/arm/mach-omap2/board-ldp-flash.c
@@ -12,6 +12,7 @@
*/
#include <linux/kernel.h>
+#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -24,7 +25,7 @@
#include <mach/gpmc.h>
#include <mach/nand.h>
-#ifdef CONFIG_MACH_OMAP_ZOOM2
+#if defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)
#include <mach/board-zoom2.h>
#else
#include <mach/board-ldp.h>
@@ -65,6 +66,77 @@
struct gpmc_freq_config freq_config[NO_GPMC_FREQ_SUPPORTED];
#endif
+#define NAND_CMD_UNLOCK1 0x23
+#define NAND_CMD_UNLOCK2 0x24
+/**
+ * @brief platform specific unlock function
+ *
+ * @param mtd - mtd info
+ * @param ofs - offset to start unlock from
+ * @param len - length to unlock
+ *
+ * @return - unlock status
+ */
+static int omap_zoom2_nand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ int ret = 0;
+ int chipnr;
+ int status;
+ unsigned long page;
+ struct nand_chip *this = mtd->priv;
+ printk(KERN_INFO "nand_unlock: start: %08x, length: %d!\n",
+ (int)ofs, (int)len);
+
+ /* select the NAND device */
+ chipnr = (int)(ofs >> this->chip_shift);
+ this->select_chip(mtd, chipnr);
+ /* check the WP bit */
+ this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+ if ((this->read_byte(mtd) & 0x80) == 0) {
+ printk(KERN_ERR "nand_unlock: Device is write protected!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if ((ofs & (mtd->writesize - 1)) != 0) {
+ printk(KERN_ERR "nand_unlock: Start address must be"
+ "beginning of nand page!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (len == 0 || (len & (mtd->writesize - 1)) != 0) {
+ printk(KERN_ERR "nand_unlock: Length must be a multiple of "
+ "nand page size!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* submit address of first page to unlock */
+ page = (unsigned long)(ofs >> this->page_shift);
+ this->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & this->pagemask);
+
+ /* submit ADDRESS of LAST page to unlock */
+ page += (unsigned long)((ofs + len) >> this->page_shift) ;
+ this->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & this->pagemask);
+
+ /* call wait ready function */
+ status = this->waitfunc(mtd, this);
+ udelay(1000);
+ /* see if device thinks it succeeded */
+ if (status & 0x01) {
+ /* there was an error */
+ printk(KERN_ERR "nand_unlock: error status =0x%08x ", status);
+ ret = -EIO;
+ goto out;
+ }
+
+ out:
+ /* de-select the NAND device */
+ this->select_chip(mtd, -1);
+ return ret;
+}
+
static struct mtd_partition ldp_nand_partitions[] = {
/* All the partition sizes are listed in terms of NAND block size */
{
@@ -89,6 +161,7 @@
.offset = 0x0200000,
.size = 0x1C00000, /* 30M */
},
+#ifdef CONFIG_ANDROID
{
.name = "system",
.offset = 0x2000000,
@@ -104,8 +177,33 @@
.offset = 0xE000000,
.size = 0x2000000, /* 32M */
},
+#endif
};
+/*
+ * Unlock the nand partitions "system", "userdata", "cache" on Zoom2
+ * once CORE hits OFF mode.
+ */
+#if defined(CONFIG_ANDROID) && defined(CONFIG_MACH_OMAP_ZOOM2)
+static void zoom2_nand_unlock(struct mtd_info *mtd, struct device *dev)
+{
+ static int off_counter;
+
+ if (get_last_off_on_transaction_id(dev) != off_counter) {
+ int offset, size;
+
+ offset = ldp_nand_partitions[4].offset;
+ size = ldp_nand_partitions[4].size + ldp_nand_partitions[5].size
+ + ldp_nand_partitions[6].size;
+ /* Unlock the partitions "system", "userdata" and "cache" */
+ omap_zoom2_nand_unlock(mtd, offset, size);
+ off_counter = get_last_off_on_transaction_id(dev);
+ }
+}
+#else
+#define zoom2_nand_unlock NULL
+#endif
+
/* NAND chip access: 16 bit */
static struct omap_nand_platform_data ldp_nand_data = {
.parts = ldp_nand_partitions,
@@ -113,6 +211,9 @@
.nand_setup = NULL,
.dma_channel = -1, /* disable DMA in OMAP NAND driver */
.dev_ready = NULL,
+ .unlock = omap_zoom2_nand_unlock,
+ .board_unlock = zoom2_nand_unlock,
+ .ecc_opt = 0x1,
};
static struct resource ldp_nand_resource = {
diff --git a/arch/arm/mach-omap2/board-zoom2-camera.c b/arch/arm/mach-omap2/board-zoom2-camera.c
index 349a25f..edfa809 100644
--- a/arch/arm/mach-omap2/board-zoom2-camera.c
+++ b/arch/arm/mach-omap2/board-zoom2-camera.c
@@ -12,13 +12,13 @@
* published by the Free Software Foundation.
*/
-#ifdef CONFIG_TWL4030_CORE
-
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/mm.h>
+#if defined(CONFIG_TWL4030_CORE) && defined(CONFIG_VIDEO_OMAP3)
+
#include <linux/i2c/twl4030.h>
#include <asm/io.h>
@@ -41,6 +41,10 @@
#define VAUX_DEV_GRP_P1 0x20
#define VAUX_DEV_GRP_NONE 0x00
+#define CAMZOOM2_USE_XCLKB 1
+
+#define ISP_IMX046_MCLK 216000000
+
/* Sensor specific GPIO signals */
#define IMX046_RESET_GPIO 98
#define IMX046_STANDBY_GPIO 58
@@ -124,17 +128,15 @@
static struct omap34xxcam_sensor_config imx046_hwc = {
.sensor_isp = 0,
- .xclk = OMAP34XXCAM_XCLK_B,
.capture_mem = IMX046_BIGGEST_FRAME_BYTE_SIZE * 2,
.ival_default = { 1, 10 },
};
-static int imx046_sensor_set_prv_data(void *priv)
+static int imx046_sensor_set_prv_data(struct v4l2_int_device *s, void *priv)
{
struct omap34xxcam_hw_config *hwc = priv;
- hwc->u.sensor.xclk = imx046_hwc.xclk;
- hwc->u.sensor.sensor_isp = imx046_hwc.sensor_isp;
+ hwc->u.sensor = imx046_hwc;
hwc->dev_index = 2;
hwc->dev_minor = 5;
hwc->dev_type = OMAP34XXCAM_SLAVE_SENSOR;
@@ -150,7 +152,8 @@
.prestrobe = 0x0,
.shutter = 0x0,
.wenlog = ISPCCDC_CFG_WENLOG_AND,
- .wait_hs_vs = 2,
+ .wait_hs_vs = 0,
+ .cam_mclk = ISP_IMX046_MCLK,
.raw_fmt_in = ISPCCDC_INPUT_FMT_RG_GB,
.u.csi.crc = 0x0,
.u.csi.mode = 0x0,
@@ -166,8 +169,10 @@
};
-static int imx046_sensor_power_set(struct device *dev, enum v4l2_power power)
+static int imx046_sensor_power_set(struct v4l2_int_device *s, enum v4l2_power power)
{
+ struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+ struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
struct isp_csi2_lanes_cfg lanecfg;
struct isp_csi2_phy_cfg phyconfig;
static enum v4l2_power previous_power = V4L2_POWER_OFF;
@@ -181,9 +186,9 @@
/* Through-put requirement:
* 3280 x 2464 x 2Bpp x 7.5fps x 3 memory ops = 355163 KByte/s
*/
- omap_pm_set_min_bus_tput(dev, OCP_INITIATOR_AGENT, 355163);
+ omap_pm_set_min_bus_tput(vdev->cam->isp, OCP_INITIATOR_AGENT, 355163);
- isp_csi2_reset();
+ isp_csi2_reset(&isp->isp_csi2);
lanecfg.clk.pol = IMX046_CSI2_CLOCK_POLARITY;
lanecfg.clk.pos = IMX046_CSI2_CLOCK_LANE;
@@ -195,57 +200,57 @@
lanecfg.data[2].pos = 0;
lanecfg.data[3].pol = 0;
lanecfg.data[3].pos = 0;
- isp_csi2_complexio_lanes_config(&lanecfg);
- isp_csi2_complexio_lanes_update(true);
+ isp_csi2_complexio_lanes_config(&isp->isp_csi2, &lanecfg);
+ isp_csi2_complexio_lanes_update(&isp->isp_csi2, true);
- isp_csi2_ctrl_config_ecc_enable(true);
+ isp_csi2_ctrl_config_ecc_enable(&isp->isp_csi2, true);
phyconfig.ths_term = IMX046_CSI2_PHY_THS_TERM;
phyconfig.ths_settle = IMX046_CSI2_PHY_THS_SETTLE;
phyconfig.tclk_term = IMX046_CSI2_PHY_TCLK_TERM;
phyconfig.tclk_miss = IMX046_CSI2_PHY_TCLK_MISS;
phyconfig.tclk_settle = IMX046_CSI2_PHY_TCLK_SETTLE;
- isp_csi2_phy_config(&phyconfig);
- isp_csi2_phy_update(true);
+ isp_csi2_phy_config(&isp->isp_csi2, &phyconfig);
+ isp_csi2_phy_update(&isp->isp_csi2, true);
- isp_configure_interface(&imx046_if_config);
+ isp_configure_interface(vdev->cam->isp, &imx046_if_config);
- if (previous_power == V4L2_POWER_OFF) {
- /* Request and configure gpio pins */
- if (gpio_request(IMX046_RESET_GPIO, "imx046_rst") != 0)
- return -EIO;
+ /* Request and configure gpio pins */
+ if (gpio_request(IMX046_RESET_GPIO, "imx046_rst") != 0)
+ return -EIO;
- /* nRESET is active LOW. set HIGH to release reset */
- gpio_set_value(IMX046_RESET_GPIO, 1);
+ /* nRESET is active LOW. set HIGH to release reset */
+ gpio_set_value(IMX046_RESET_GPIO, 1);
- /* set to output mode */
- gpio_direction_output(IMX046_RESET_GPIO, true);
+ /* set to output mode */
+ gpio_direction_output(IMX046_RESET_GPIO, true);
- /* turn on analog power */
- twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
- VAUX_2_8_V, TWL4030_VAUX2_DEDICATED);
- twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
- VAUX_DEV_GRP_P1, TWL4030_VAUX2_DEV_GRP);
+ /* turn on analog power */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ VAUX_2_8_V, TWL4030_VAUX2_DEDICATED);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ VAUX_DEV_GRP_P1, TWL4030_VAUX2_DEV_GRP);
- twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
- VAUX_1_8_V, TWL4030_VAUX4_DEDICATED);
- twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
- VAUX_DEV_GRP_P1, TWL4030_VAUX4_DEV_GRP);
- udelay(100);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ VAUX_1_8_V, TWL4030_VAUX4_DEDICATED);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ VAUX_DEV_GRP_P1, TWL4030_VAUX4_DEV_GRP);
+ udelay(100);
- /* have to put sensor to reset to guarantee detection */
- gpio_set_value(IMX046_RESET_GPIO, 0);
- udelay(1500);
+ /* have to put sensor to reset to guarantee detection */
+ gpio_set_value(IMX046_RESET_GPIO, 0);
+ udelay(1500);
- /* nRESET is active LOW. set HIGH to release reset */
- gpio_set_value(IMX046_RESET_GPIO, 1);
- udelay(300);
- }
+ /* nRESET is active LOW. set HIGH to release reset */
+ gpio_set_value(IMX046_RESET_GPIO, 1);
+ udelay(300);
break;
case V4L2_POWER_OFF:
- printk(KERN_DEBUG "imx046_sensor_power_set(OFF)\n");
+ case V4L2_POWER_STANDBY:
+ printk(KERN_DEBUG "imx046_sensor_power_set(%s)\n",
+ (power == V4L2_POWER_OFF) ? "OFF" : "STANDBY");
/* Power Down Sequence */
- isp_csi2_complexio_power(ISP_CSI2_POWER_OFF);
+ isp_csi2_complexio_power(&isp->isp_csi2, ISP_CSI2_POWER_OFF);
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
VAUX_DEV_GRP_NONE, TWL4030_VAUX4_DEV_GRP);
@@ -253,12 +258,11 @@
VAUX_DEV_GRP_NONE, TWL4030_VAUX2_DEV_GRP);
gpio_free(IMX046_RESET_GPIO);
- omap_pm_set_min_bus_tput(dev, OCP_INITIATOR_AGENT, 0);
- break;
- case V4L2_POWER_STANDBY:
- printk(KERN_DEBUG "imx046_sensor_power_set(STANDBY)\n");
- /*TODO*/
- omap_pm_set_min_bus_tput(dev, OCP_INITIATOR_AGENT, 0);
+ omap_pm_set_min_bus_tput(vdev->cam->isp, OCP_INITIATOR_AGENT, 0);
+
+ /* Make sure not to disable the MCLK twice in a row */
+ if (previous_power == V4L2_POWER_ON)
+ isp_disable_mclk(isp);
break;
}
@@ -267,16 +271,76 @@
return err;
}
+static u32 imx046_sensor_set_xclk(struct v4l2_int_device *s, u32 xclkfreq)
+{
+ struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+
+ return isp_set_xclk(vdev->cam->isp, xclkfreq, CAMZOOM2_USE_XCLKB);
+}
+
+static int imx046_csi2_lane_count(struct v4l2_int_device *s, int count)
+{
+ struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+ struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
+
+ return isp_csi2_complexio_lanes_count(&isp->isp_csi2, count);
+}
+
+static int imx046_csi2_cfg_vp_out_ctrl(struct v4l2_int_device *s,
+ u8 vp_out_ctrl)
+{
+ struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+ struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
+
+ return isp_csi2_ctrl_config_vp_out_ctrl(&isp->isp_csi2, vp_out_ctrl);
+}
+
+static int imx046_csi2_ctrl_update(struct v4l2_int_device *s, bool force_update)
+{
+ struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+ struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
+
+ return isp_csi2_ctrl_update(&isp->isp_csi2, force_update);
+}
+
+static int imx046_csi2_cfg_virtual_id(struct v4l2_int_device *s, u8 ctx, u8 id)
+{
+ struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+ struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
+
+ return isp_csi2_ctx_config_virtual_id(&isp->isp_csi2, ctx, id);
+}
+
+static int imx046_csi2_ctx_update(struct v4l2_int_device *s, u8 ctx,
+ bool force_update)
+{
+ struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+ struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
+
+ return isp_csi2_ctx_update(&isp->isp_csi2, ctx, force_update);
+}
+
+static int imx046_csi2_calc_phy_cfg0(struct v4l2_int_device *s,
+ u32 mipiclk, u32 lbound_hs_settle,
+ u32 ubound_hs_settle)
+{
+ struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+ struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
+
+ return isp_csi2_calc_phy_cfg0(&isp->isp_csi2, mipiclk,
+ lbound_hs_settle, ubound_hs_settle);
+}
+
struct imx046_platform_data zoom2_imx046_platform_data = {
.power_set = imx046_sensor_power_set,
.priv_data_set = imx046_sensor_set_prv_data,
- .set_xclk = isp_set_xclk,
- .csi2_lane_count = isp_csi2_complexio_lanes_count,
- .csi2_cfg_vp_out_ctrl = isp_csi2_ctrl_config_vp_out_ctrl,
- .csi2_ctrl_update = isp_csi2_ctrl_update,
- .csi2_cfg_virtual_id = isp_csi2_ctx_config_virtual_id,
- .csi2_ctx_update = isp_csi2_ctx_update,
- .csi2_calc_phy_cfg0 = isp_csi2_calc_phy_cfg0,
+ .set_xclk = imx046_sensor_set_xclk,
+ .csi2_lane_count = imx046_csi2_lane_count,
+ .csi2_cfg_vp_out_ctrl = imx046_csi2_cfg_vp_out_ctrl,
+ .csi2_ctrl_update = imx046_csi2_ctrl_update,
+ .csi2_cfg_virtual_id = imx046_csi2_cfg_virtual_id,
+ .csi2_ctx_update = imx046_csi2_ctx_update,
+ .csi2_calc_phy_cfg0 = imx046_csi2_calc_phy_cfg0,
};
#endif
@@ -295,8 +359,4 @@
cam_inited = 1;
}
-#else
-void __init zoom2_cam_init(void)
-{
-}
#endif
diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c
index e97a65a..c5f1bb4 100644
--- a/arch/arm/mach-omap2/board-zoom2.c
+++ b/arch/arm/mach-omap2/board-zoom2.c
@@ -28,6 +28,8 @@
#ifdef CONFIG_SIL9022
#include <linux/sil9022.h>
#endif
+#include <linux/switch.h>
+#include <linux/smsc911x.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -54,18 +56,28 @@
#include "mmc-twl4030.h"
#include "omap3-opp.h"
+#include "sdram-hynix-h8mbx00u0mer-0em.h"
#include "sdram-micron-mt46h32m32lf-6.h"
#include <media/v4l2-int-device.h>
-#if defined(CONFIG_VIDEO_IMX046) || defined(CONFIG_VIDEO_IMX046_MODULE)
+#if (defined(CONFIG_VIDEO_IMX046) || defined(CONFIG_VIDEO_IMX046_MODULE)) && \
+ defined(CONFIG_VIDEO_OMAP3)
#include <media/imx046.h>
extern struct imx046_platform_data zoom2_imx046_platform_data;
#endif
+#ifdef CONFIG_VIDEO_OMAP3
extern void zoom2_cam_init(void);
+#else
+#define zoom2_cam_init() NULL
+#endif
-#ifdef CONFIG_VIDEO_LV8093
+#ifdef CONFIG_PM
+#include <../drivers/media/video/omap/omap_voutdef.h>
+#endif
+
+#if defined(CONFIG_VIDEO_LV8093) && defined(CONFIG_VIDEO_OMAP3)
#include <media/lv8093.h>
extern struct imx046_platform_data zoom2_lv8093_platform_data;
#define LV8093_PS_GPIO 7
@@ -92,6 +104,11 @@
#define ENABLE_VAUX3_DEDICATED 0x03
#define ENABLE_VAUX3_DEV_GRP 0x20
#define TWL4030_MSECURE_GPIO 22
+#define WL127X_BTEN_GPIO 109
+
+#define ZOOM2_EXT_QUART_PHYS 0x10000000
+#define ZOOM2_EXT_QUART_VIRT 0xfa400000
+#define ZOOM2_EXT_QUART_SIZE SZ_256
static struct pin_config zoom2_mux_pins[] = {
/*
@@ -110,29 +127,29 @@
OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
MUX_CFG_34XX("MCBSP3_MASTER", 0x194 /* CLKS */,
OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
-MUX_CFG_34XX("MCBSP3_MASTER", 0x196 /* FSX */,
- OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
-MUX_CFG_34XX("MCBSP3_MASTER", 0x198 /* CLKX */,
- OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
-MUX_CFG_34XX("MCBSP3_MASTER", 0x192 /* DR */,
- OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
-MUX_CFG_34XX("MCBSP3_MASTER", 0x190 /* DX */,
- OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
-MUX_CFG_34XX("MCBSP3_SLAVE", 0x196 /* FSX */,
- OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
-MUX_CFG_34XX("MCBSP3_SLAVE", 0x198 /* CLKX */,
- OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
-MUX_CFG_34XX("MCBSP3_SLAVE", 0x192 /* DR */,
- OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
-MUX_CFG_34XX("MCBSP3_SLAVE", 0x190 /* DX */,
- OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
-MUX_CFG_34XX("MCBSP3_TRISTATE", 0x196 /* FSX */,
+MUX_CFG_34XX("MCBSP3_MASTER", 0x172 /* FSX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x170 /* CLKX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x16e /* DR */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x16c /* DX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x172 /* FSX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x170 /* CLKX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x16e /* DR */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x16c /* DX */,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x172 /* FSX */,
OMAP34XX_MUX_MODE7)
-MUX_CFG_34XX("MCBSP3_TRISTATE", 0x198 /* CLKX */,
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x170 /* CLKX */,
OMAP34XX_MUX_MODE7)
-MUX_CFG_34XX("MCBSP3_TRISTATE", 0x192 /* DR */,
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x16e /* DR */,
OMAP34XX_MUX_MODE7)
-MUX_CFG_34XX("MCBSP3_TRISTATE", 0x190 /* DX */,
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x16c /* DX */,
OMAP34XX_MUX_MODE7)
MUX_CFG_34XX("MCBSP4_MASTER", 0x194 /* CLKS */,
OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
@@ -159,7 +176,7 @@
.size = ARRAY_SIZE(zoom2_mux_pins),
};
-static struct resource zoom2_smc911x_resources[] = {
+static struct resource zoom2_smsc911x_resources[] = {
[0] = {
.start = OMAP34XX_ETHR_START,
.end = OMAP34XX_ETHR_START + SZ_4K,
@@ -172,11 +189,21 @@
},
};
-static struct platform_device zoom2_smc911x_device = {
- .name = "smc911x",
+static struct smsc911x_platform_config zoom_smsc911x_config = {
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+ .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+ .flags = SMSC911X_USE_32BIT,
+ .phy_interface = PHY_INTERFACE_MODE_MII,
+};
+
+static struct platform_device zoom2_smsc911x_device = {
+ .name = "smsc911x",
.id = -1,
- .num_resources = ARRAY_SIZE(zoom2_smc911x_resources),
- .resource = zoom2_smc911x_resources,
+ .num_resources = ARRAY_SIZE(zoom2_smsc911x_resources),
+ .resource = zoom2_smsc911x_resources,
+ .dev = {
+ .platform_data = &zoom_smsc911x_config,
+ }
};
#ifdef CONFIG_WL127X_RFKILL
@@ -192,6 +219,15 @@
};
#endif
+/* GPIOS need to be in order of BT, FM and GPS
+ * provide -1 is Not applicable for chip */
+static int gpios[] = {109, 161, -1};
+static struct platform_device zoom_btfmgps_device = {
+ .name = "kim", /* named after init manager for ST */
+ .id = -1,
+ .dev.platform_data = &gpios,
+};
+
/* Zoom2 has Qwerty keyboard*/
static int zoom2_twl4030_keymap[] = {
KEY(0, 0, KEY_E),
@@ -308,8 +344,7 @@
},
};
-#define LCD_PANEL_BACKLIGHT_GPIO (15 + OMAP_MAX_GPIO_LINES)
-#define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES)
+#define LCD_PANEL_BACKLIGHT_GPIO (7 + OMAP_MAX_GPIO_LINES)
#define LCD_PANEL_RESET_GPIO 55
#define LCD_PANEL_QVGA_GPIO 56
@@ -336,18 +371,19 @@
{
unsigned char lcd_panel_reset_gpio;
- omap_cfg_reg(AF21_34XX_GPIO8);
+ if (!cpu_is_omap3630())
+ omap_cfg_reg(AF21_34XX_GPIO8);
omap_cfg_reg(B23_34XX_GPIO167);
omap_cfg_reg(AB1_34XX_McSPI1_CS2);
omap_cfg_reg(A24_34XX_GPIO94);
- if (omap_rev() > OMAP3430_REV_ES3_0) {
- /* Production Zoom2 Board:
- * GPIO-96 is the LCD_RESET_GPIO
- */
- omap_cfg_reg(C25_34XX_GPIO96);
- lcd_panel_reset_gpio = 96;
- } else {
+ /* Production Zoom2 Board:
+ * GPIO-96 is the LCD_RESET_GPIO
+ */
+ omap_cfg_reg(C25_34XX_GPIO96);
+ lcd_panel_reset_gpio = 96;
+
+ if (cpu_is_omap34xx() && (omap_rev() <= OMAP3430_REV_ES3_0)) {
/* Pilot Zoom2 board
* GPIO-55 is the LCD_RESET_GPIO
*/
@@ -357,14 +393,12 @@
gpio_request(lcd_panel_reset_gpio, "lcd reset");
gpio_request(LCD_PANEL_QVGA_GPIO, "lcd qvga");
- gpio_request(LCD_PANEL_ENABLE_GPIO, "lcd panel");
gpio_request(LCD_PANEL_BACKLIGHT_GPIO, "lcd backlight");
gpio_request( TV_PANEL_ENABLE_GPIO, "tv panel");
gpio_direction_output(LCD_PANEL_QVGA_GPIO, 0);
gpio_direction_output(lcd_panel_reset_gpio, 0);
- gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 0);
gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 0);
gpio_direction_output(TV_PANEL_ENABLE_GPIO, 0);
@@ -387,7 +421,6 @@
{
zoom2_panel_power_enable(1);
- gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 1);
gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 1);
return 0;
@@ -395,9 +428,10 @@
static void zoom2_panel_disable_lcd(struct omap_dss_device *dssdev)
{
+#ifndef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
zoom2_panel_power_enable(0);
+#endif
- gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 0);
gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 0);
}
@@ -432,8 +466,15 @@
static void zoom2_panel_disable_hdmi(struct omap_dss_device *dssdev)
{
zoom2_hdmi_reset_enable(0);
+#ifndef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
zoom2_panel_power_enable(0);
+#endif
}
+struct hdmi_platform_data zoom2_hdmi_data = {
+#ifdef CONFIG_PM
+ .set_min_bus_tput = omap_pm_set_min_bus_tput,
+#endif
+};
static struct omap_dss_device zoom2_hdmi_device = {
.name = "hdmi",
@@ -442,6 +483,9 @@
.phy.dpi.data_lines = 24,
.platform_enable = zoom2_panel_enable_hdmi,
.platform_disable = zoom2_panel_disable_hdmi,
+ .dev = {
+ .platform_data = &zoom2_hdmi_data,
+ },
};
#endif
@@ -485,6 +529,7 @@
};
static struct omap_dss_board_info zoom2_dss_data = {
+ .get_last_off_on_transaction_id = get_last_off_on_transaction_id,
.num_devices = ARRAY_SIZE(zoom2_dss_devices),
.devices = zoom2_dss_devices,
.default_device = &zoom2_lcd_device,
@@ -503,6 +548,11 @@
.dev = &zoom2_dss_device.dev,
};
+static struct regulator_consumer_supply zoom2_vdds_dsi_supply = {
+ .supply = "vdds_dsi",
+ .dev = &zoom2_dss_device.dev,
+};
+
#ifdef CONFIG_FB_OMAP2
static struct resource zoom2_vout_resource[3 - CONFIG_FB_OMAP2_NUM_FBS] = {
};
@@ -511,16 +561,47 @@
};
#endif
+#ifdef CONFIG_PM
+struct vout_platform_data zoom2_vout_data = {
+ .set_min_bus_tput = omap_pm_set_min_bus_tput,
+ .set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat,
+ .set_vdd1_opp = omap_pm_set_min_mpu_freq,
+ .set_cpu_freq = omap_pm_cpu_set_freq,
+};
+#endif
+
static struct platform_device zoom2_vout_device = {
.name = "omap_vout",
.num_resources = ARRAY_SIZE(zoom2_vout_resource),
.resource = &zoom2_vout_resource[0],
.id = -1,
+#ifdef CONFIG_PM
+ .dev = {
+ .platform_data = &zoom2_vout_data,
+ }
+#else
+ .dev = {
+ .platform_data = NULL,
+ }
+#endif
+};
+
+static struct gpio_switch_platform_data headset_switch_data = {
+ .name = "h2w",
+ .gpio = OMAP_MAX_GPIO_LINES + 2, /* TWL4030 GPIO_2 */
+};
+
+static struct platform_device headset_switch_device = {
+ .name = "switch-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &headset_switch_data,
+ }
};
static struct platform_device *zoom2_devices[] __initdata = {
&zoom2_dss_device,
- &zoom2_smc911x_device,
+ &zoom2_smsc911x_device,
#ifdef CONFIG_WL127X_RFKILL
&zoom2_wl127x_device,
#endif
@@ -528,6 +609,8 @@
&omap_hdq_device,
#endif
&zoom2_vout_device,
+ &headset_switch_device,
+ &zoom_btfmgps_device,
};
static inline void __init zoom2_init_smc911x(void)
@@ -543,13 +626,13 @@
return;
}
- zoom2_smc911x_resources[0].start = cs_mem_base + 0x0;
- zoom2_smc911x_resources[0].end = cs_mem_base + 0xf;
+ zoom2_smsc911x_resources[0].start = cs_mem_base + 0x0;
+ zoom2_smsc911x_resources[0].end = cs_mem_base + 0xf;
udelay(100);
eth_gpio = LDP_SMC911X_GPIO;
- zoom2_smc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
+ zoom2_smsc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
if (gpio_request(eth_gpio, "smc911x irq") < 0) {
printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n",
@@ -585,9 +668,51 @@
static void __init omap_zoom2_init_irq(void)
{
- omap2_init_common_hw(mt46h32m32lf6_sdrc_params, omap3_mpu_rate_table,
- omap3_dsp_rate_table, omap3_l3_rate_table);
- omap2_mux_register(&zoom2_mux_cfg);
+ if (cpu_is_omap3630()) {
+ omap2_init_common_hw(h8mbx00u0mer0em_sdrc_params,
+ omap3630_mpu_rate_table, omap3630_dsp_rate_table,
+ omap3630_l3_rate_table);
+ } else {
+ switch (omap_rev_id()) {
+ case OMAP_3420:
+ omap2_init_common_hw(mt46h32m32lf6_sdrc_params,
+ omap3_mpu_rate_table, omap3_dsp_rate_table_3420,
+ omap3_l3_rate_table);
+ break;
+
+ case OMAP_3430:
+ omap2_init_common_hw(mt46h32m32lf6_sdrc_params,
+ omap3_mpu_rate_table, omap3_dsp_rate_table,
+ omap3_l3_rate_table);
+ break;
+
+ case OMAP_3440:
+ omap2_init_common_hw(mt46h32m32lf6_sdrc_params,
+ omap3_mpu_rate_table, omap3_dsp_rate_table_3440,
+ omap3_l3_rate_table);
+ break;
+
+ default:
+ omap2_init_common_hw(mt46h32m32lf6_sdrc_params,
+ omap3_mpu_rate_table, omap3_dsp_rate_table,
+ omap3_l3_rate_table);
+ break;
+ }
+ }
+
+ /* Set Mcbsp only for Producton units */
+ /* Else you will see white screen on beta boards */
+
+ if (cpu_is_omap3630() || (omap_rev() > OMAP3430_REV_ES3_0)) {
+ /* Production board supports McBSP4 */
+ omap2_mux_register(&zoom2_mux_cfg);
+ } else {
+ /* McBSP4_CLK is linked to LCD_RESET line
+ * on Pre-Production zoom2's
+ * Hence a white screen seen
+ */
+ printk(KERN_WARNING "Issue: McBSP4 not supported on this baord");
+ }
omap_init_irq();
omap_gpio_init();
zoom2_init_smc911x();
@@ -663,17 +788,32 @@
.consumer_supplies = &zoom2_vdda_dac_supply,
};
+static struct regulator_init_data zoom2_vdsi = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &zoom2_vdds_dsi_supply,
+};
+
static struct twl4030_hsmmc_info mmc[] __initdata = {
{
.mmc = 1,
.wires = 4,
.gpio_wp = -EINVAL,
},
+#ifdef CONFIG_OMAP_HS_MMC2
{
.mmc = 2,
- .wires = 4,
+ .wires = 8,
.gpio_wp = -EINVAL,
},
+#endif
{
.mmc = 3,
.wires = 4,
@@ -747,6 +887,97 @@
.irq_line = 1,
};
+static struct twl4030_ins __initdata sleep_on_seq[] = {
+
+ /* Turn off HFCLKOUT */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_OFF), 2},
+ /* Turn OFF VDD1 */
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_OFF), 2},
+ /* Turn OFF VDD2 */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_OFF), 2},
+ /* Turn OFF VPLL1 */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_OFF), 2},
+};
+
+static struct twl4030_script sleep_on_script __initdata = {
+ .script = sleep_on_seq,
+ .size = ARRAY_SIZE(sleep_on_seq),
+ .flags = TRITON_SLEEP_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_p12_seq[] __initdata = {
+ /* Turn on HFCLKOUT */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+ /* Turn ON VDD1 */
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 2},
+ /* Turn ON VDD2 */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 2},
+ /* Turn ON VPLL1 */
+ {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_p12_script __initdata = {
+ .script = wakeup_p12_seq,
+ .size = ARRAY_SIZE(wakeup_p12_seq),
+ .flags = TRITON_WAKEUP12_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_p3_seq[] __initdata = {
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_p3_script __initdata = {
+ .script = wakeup_p3_seq,
+ .size = ARRAY_SIZE(wakeup_p3_seq),
+ .flags = TRITON_WAKEUP3_SCRIPT,
+};
+
+static struct twl4030_ins wrst_seq[] __initdata = {
+/*
+ * Reset twl4030.
+ * Reset VDD1 regulator.
+ * Reset VDD2 regulator.
+ * Reset VPLL1 regulator.
+ * Enable sysclk output.
+ * Reenable twl4030.
+ */
+ {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_OFF), 2},
+ {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_WRST), 15},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_WRST), 15},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_WRST), 0x60},
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+ {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wrst_script __initdata = {
+ .script = wrst_seq,
+ .size = ARRAY_SIZE(wrst_seq),
+ .flags = TRITON_WRST_SCRIPT,
+};
+
+static struct twl4030_script *twl4030_scripts[] __initdata = {
+ &sleep_on_script,
+ &wakeup_p12_script,
+ &wakeup_p3_script,
+ &wrst_script,
+};
+
+static struct twl4030_resconfig twl4030_rconfig[] = {
+ { .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3, .type = -1,
+ .type2 = -1 },
+ { .resource = RES_VDD1, .devgroup = DEV_GRP_P1, .type = -1,
+ .type2 = -1 },
+ { .resource = RES_VDD2, .devgroup = DEV_GRP_P1, .type = -1,
+ .type2 = -1 },
+ { 0, 0},
+};
+
+static struct twl4030_power_data zoom2_t2scripts_data __initdata = {
+ .scripts = twl4030_scripts,
+ .size = ARRAY_SIZE(twl4030_scripts),
+ .resource_config = twl4030_rconfig,
+};
+
static struct twl4030_platform_data zoom2_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
@@ -757,10 +988,12 @@
.usb = &zoom2_usb_data,
.gpio = &zoom2_gpio_data,
.keypad = &zoom2_kp_twl4030_data,
+ .power = &zoom2_t2scripts_data,
.vmmc1 = &zoom2_vmmc1,
.vmmc2 = &zoom2_vmmc2,
.vsim = &zoom2_vsim,
.vdac = &zoom2_vdac,
+ .vpll2 = &zoom2_vdsi,
};
static struct i2c_board_info __initdata zoom2_i2c_bus1_info[] = {
@@ -807,13 +1040,14 @@
.platform_data = &synaptics_platform_data,
.irq = OMAP_GPIO_IRQ(OMAP_SYNAPTICS_GPIO),
},
-#if defined(CONFIG_VIDEO_IMX046) || defined(CONFIG_VIDEO_IMX046_MODULE)
+#if (defined(CONFIG_VIDEO_IMX046) || defined(CONFIG_VIDEO_IMX046_MODULE)) && \
+ defined(CONFIG_VIDEO_OMAP3)
{
I2C_BOARD_INFO("imx046", IMX046_I2C_ADDR),
.platform_data = &zoom2_imx046_platform_data,
},
#endif
-#ifdef CONFIG_VIDEO_LV8093
+#if defined(CONFIG_VIDEO_LV8093) && defined(CONFIG_VIDEO_OMAP3)
{
I2C_BOARD_INFO(LV8093_NAME, LV8093_AF_I2C_ADDR),
.platform_data = &zoom2_lv8093_platform_data,
@@ -832,6 +1066,30 @@
static int __init omap_i2c_init(void)
{
+
+/* Disable OMAP 3630 internal pull-ups for I2Ci */
+ if (cpu_is_omap3630()) {
+
+ u32 prog_io;
+
+ prog_io = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1);
+ /* Program (bit 19)=1 to disable internal pull-up on I2C1 */
+ prog_io |= OMAP3630_PRG_I2C1_PULLUPRESX;
+ /* Program (bit 0)=1 to disable internal pull-up on I2C2 */
+ prog_io |= OMAP3630_PRG_I2C2_PULLUPRESX;
+ omap_ctrl_writel(prog_io, OMAP343X_CONTROL_PROG_IO1);
+
+ prog_io = omap_ctrl_readl(OMAP36XX_CONTROL_PROG_IO2);
+ /* Program (bit 7)=1 to disable internal pull-up on I2C3 */
+ prog_io |= OMAP3630_PRG_I2C3_PULLUPRESX;
+ omap_ctrl_writel(prog_io, OMAP36XX_CONTROL_PROG_IO2);
+
+ prog_io = omap_ctrl_readl(OMAP36XX_CONTROL_PROG_IO_WKUP1);
+ /* Program (bit 5)=1 to disable internal pull-up on I2C4(SR) */
+ prog_io |= OMAP3630_PRG_SR_PULLUPRESX;
+ omap_ctrl_writel(prog_io, OMAP36XX_CONTROL_PROG_IO_WKUP1);
+ }
+
omap_register_i2c_bus(1, 100, zoom2_i2c_bus1_info,
ARRAY_SIZE(zoom2_i2c_bus1_info));
omap_register_i2c_bus(2, 100, zoom2_i2c_bus2_info,
@@ -848,6 +1106,12 @@
omap_cfg_reg(W21_34XX_GPIO162);
}
+static void config_bt_gpio(void)
+{
+ /* configure BT_EN gpio */
+ omap_cfg_reg(B25_34XX_GPIO109);
+}
+
static void enable_board_wakeup_source(void)
{
omap_cfg_reg(AF26_34XX_SYS_NIRQ);
@@ -859,9 +1123,37 @@
omap_cfg_reg(C27_34XX_CAM_PCLK);
}
+static void config_mux_mcbsp3(void)
+{
+ /*Mux setting for GPIO164 McBSP3*/
+ omap_cfg_reg(H19_34XX_GPIO164_OUT);
+}
+static int __init wl127x_vio_leakage_fix(void)
+{
+ int ret = 0;
+
+ ret = gpio_request(WL127X_BTEN_GPIO, "wl127x_bten");
+ if (ret < 0) {
+ printk(KERN_ERR "wl127x_bten gpio_%d request fail",
+ WL127X_BTEN_GPIO);
+ goto fail;
+ }
+
+ gpio_direction_output(WL127X_BTEN_GPIO, 1);
+ mdelay(10);
+ gpio_direction_output(WL127X_BTEN_GPIO, 0);
+ udelay(64);
+
+ gpio_free(WL127X_BTEN_GPIO);
+fail:
+ return ret;
+}
+
static void __init omap_zoom2_init(void)
{
omap_i2c_init();
+ /* Fix to prevent VIO leakage on wl127x */
+ wl127x_vio_leakage_fix();
platform_add_devices(zoom2_devices, ARRAY_SIZE(zoom2_devices));
omap_board_config = zoom2_config;
omap_board_config_size = ARRAY_SIZE(zoom2_config);
@@ -874,8 +1166,10 @@
omap_serial_init();
usb_musb_init();
config_wlan_gpio();
+ config_bt_gpio();
zoom2_cam_init();
zoom2_lcd_tv_panel_init();
+ config_mux_mcbsp3();
#ifdef CONFIG_SIL9022
config_hdmi_gpio();
zoom2_hdmi_reset_enable(1);
@@ -885,9 +1179,9 @@
static struct map_desc zoom2_io_desc[] __initdata = {
{
- .virtual = ZOOM2_QUART_VIRT,
+ .virtual = ZOOM2_EXT_QUART_VIRT,
.pfn = __phys_to_pfn(ZOOM2_QUART_PHYS),
- .length = ZOOM2_QUART_SIZE,
+ .length = ZOOM2_EXT_QUART_SIZE,
.type = MT_DEVICE
},
};
@@ -899,12 +1193,16 @@
omap2_map_common_io();
}
+#ifdef CONFIG_MACH_OMAP_ZOOM3
+MACHINE_START(OMAP_ZOOM3, "OMAP ZOOM3 board")
+#else
MACHINE_START(OMAP_ZOOM2, "OMAP ZOOM2 board")
+#endif
/* phys_io is only used for DEBUG_LL early printing. The Zoom2's
* console is on an external quad UART sitting at address 0x10000000
*/
- .phys_io = 0x10000000,
- .io_pg_offst = ((0xfb000000) >> 18) & 0xfffc,
+ .phys_io = ZOOM2_EXT_QUART_PHYS,
+ .io_pg_offst = ((ZOOM2_EXT_QUART_VIRT) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap_zoom2_map_io,
.init_irq = omap_zoom2_init_irq,
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 672cfb6..f377a2e 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -448,6 +448,41 @@
return 0;
}
+/** omap3_pwrdn_bug_clk_enable - enable clocks suffering from PWRDN bug
+ * @clk: DPLL output struct clk
+ *
+ * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck, dpll4_m5_ck
+ * & dpll4_m6_ck dividers get lost after their respective PWRDN bits are set.
+ * Any write to the corresponding CM_CLKSEL register will refresh the
+ * dividers. Only x2 clocks are affected, so it is safe to trust the parent
+ * clock information to refresh the CM_CLKSEL registers.
+ */
+int omap3_pwrdn_bug_clk_enable(struct clk *clk)
+{
+ u32 v;
+
+ v = _omap2_clk_read_reg(clk->enable_reg, clk);
+ if (clk->flags & INVERT_ENABLE)
+ v &= ~(1 << clk->enable_bit);
+ else
+ v |= (1 << clk->enable_bit);
+ _omap2_clk_write_reg(v, clk->enable_reg, clk);
+ v = _omap2_clk_read_reg(clk->enable_reg, clk); /* OCP barrier */
+
+ omap2_clk_wait_ready(clk);
+
+ v = __raw_readl(OMAP34XX_CM_REGADDR(clk->parent->prcm_mod,
+ clk->parent->clksel_reg));
+ v += (1 << clk->parent->clksel_shift);
+ __raw_writel(v, OMAP34XX_CM_REGADDR(clk->parent->prcm_mod,
+ clk->parent->clksel_reg));
+ v -= (1 << clk->parent->clksel_shift);
+ __raw_writel(v, OMAP34XX_CM_REGADDR(clk->parent->prcm_mod,
+ clk->parent->clksel_reg));
+
+ return 0;
+}
+
/* Disables clock without considering parent dependencies or use count */
static void _omap2_clk_disable(struct clk *clk)
{
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 4964aad..f06add5 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -47,6 +47,7 @@
int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance);
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate);
struct clk *omap2_clk_get_parent(struct clk *clk);
+int omap3_pwrdn_bug_clk_enable(struct clk *clk);
#ifdef CONFIG_OMAP_RESET_CLOCKS
void omap2_clk_disable_unused(struct clk *clk);
@@ -72,7 +73,7 @@
const char *name);
void omap2_clk_prepare_for_reboot(void);
-extern void omap3_lock_dpll5();
+extern void omap3_lock_dpll5(void);
extern u8 cpu_mask;
/* clksel_rate data common to 24xx/343x */
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index 35cf4b3..c3e3535 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -28,6 +28,7 @@
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/cpufreq.h>
+#include <linux/i2c/twl4030.h>
#include <mach/clock.h>
#include <mach/sram.h>
@@ -62,7 +63,7 @@
* SDRC_MPURATE_LOOPS: Number of MPU loops to execute at
* 2^MPURATE_BASE_SHIFT MHz for SDRC to stabilize
*/
-#define SDRC_MPURATE_LOOPS 96
+#define SDRC_MPURATE_LOOPS 24
/**
* omap3_dpll_recalc - recalculate DPLL rate
@@ -311,7 +312,7 @@
}
/**
- * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode
+ * omap3_noncore_dpll_disable - instruct a DPLL to enter bypass or lock mode
* @clk: pointer to a DPLL struct clk
*
* Instructs a non-CORE DPLL to enable, e.g., to enter bypass or lock.
@@ -332,8 +333,34 @@
_omap3_noncore_dpll_stop(clk);
}
+/* OMAP3630 j-type DPLL4 compensation variables */
+void lookup_dco_sddiv(struct clk *clk, u8 *dco, u8 *sd_div, u16 m, u8 n)
+{
+ unsigned long fint, clkinp, sd; /* watch out for overflow */
+ int mod1, mod2;
-/* Non-CORE DPLL rate set code */
+ ++n; /* always n+1 below */
+ clkinp = clk->parent->rate;
+ fint = (clkinp / n) * m;
+
+ if (fint < 1000000000)
+ *dco = 2;
+ else
+ *dco = 4;
+ /*
+ * target sigma-delta to near 250MHz
+ * sd = ceil[(m/(n+1)) * (clkinp_MHz / 250)]
+ */
+ clkinp /= 100000; /* shift from MHz to 10*Hz for 38.4 and 19.2*/
+ mod1 = (clkinp * m) % (250 * n);
+ sd = (clkinp * m) / (250 * n);
+ mod2 = sd % 10;
+ sd /= 10;
+
+ if (mod1 + mod2)
+ ++sd;
+ *sd_div = sd;
+}
/*
* omap3_noncore_dpll_program - set non-core DPLL M,N values directly
@@ -383,6 +410,13 @@
v &= ~(dd->mult_mask | dd->div1_mask);
v |= m << __ffs(dd->mult_mask);
v |= (n - 1) << __ffs(dd->div1_mask);
+ if (dd->jtype) {
+ u8 dco, sd_div;
+ lookup_dco_sddiv(clk, &dco, &sd_div, m, n);
+ v &= ~(dd->dco_sel_mask | dd->sd_div_mask);
+ v |= dco << __ffs(dd->dco_sel_mask);
+ v |= sd_div << __ffs(dd->sd_div_mask);
+ }
cm_write_mod_reg(v, clk->prcm_mod, dd->mult_div1_reg);
/* We let the clock framework set the other output dividers later */
@@ -644,7 +678,7 @@
v = cm_read_mod_reg(pclk->prcm_mod, dd->control_reg) & dd->enable_mask;
v >>= __ffs(dd->enable_mask);
- if (v == OMAP3XXX_EN_DPLL_LOCKED)
+ if (v == OMAP3XXX_EN_DPLL_LOCKED && (!dd->jtype))
rate *= 2;
if (rate_storage == CURRENT_RATE)
@@ -662,7 +696,7 @@
#if defined(CONFIG_ARCH_OMAP3)
#ifdef CONFIG_CPU_FREQ
-static struct cpufreq_frequency_table freq_table[MAX_VDD1_OPP+1];
+static struct cpufreq_frequency_table freq_table[VDD1_OPP6+1];
void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
{
@@ -672,8 +706,7 @@
if (!mpu_opps)
return;
- /* Avoid registering the 120% Overdrive with CPUFreq */
- prcm = mpu_opps + MAX_VDD1_OPP - 1;
+ prcm = mpu_opps + MAX_VDD1_OPP;
for (; prcm->rate; prcm--) {
freq_table[i].index = i;
freq_table[i].frequency = prcm->rate / 1000;
@@ -714,6 +747,8 @@
*/
void omap2_clk_prepare_for_reboot(void)
{
+ int err = 0;
+
/* REVISIT: Not ready for 343x */
#if 0
u32 rate;
@@ -724,9 +759,21 @@
rate = clk_get_rate(sclk);
clk_set_rate(vclk, rate);
#endif
+
+ /*
+ * PRCM on OMAP3 will drive SYS_OFFMODE low during DPLL3 warm reset.
+ * This causes Gaia sleep script to execute, usually killing VDD1 and
+ * VDD2 while code is running. WA is to disable the sleep script
+ * before warm reset.
+ */
+#ifdef CONFIG_TWL4030_POWER
+ err = twl4030_remove_script(TRITON_SLEEP_SCRIPT);
+ if (err)
+ pr_err("twl4030: error trying to disable sleep script!\n");
+#endif
}
-void omap3_lock_dpll5()
+void omap3_lock_dpll5(void)
{
struct clk *dpll5_clk;
struct clk *dpll5_m2_clk;
@@ -807,13 +854,46 @@
cpu_mask |= RATE_IN_3430ES2;
cpu_clkflg |= CLOCK_IN_OMAP3430ES2;
}
- }
+ if (cpu_is_omap3630()) {
+ dpll4_ck.dpll_data->jtype = 1;
+ dpll4_dd.mult_mask =
+ OMAP3430_PERIPH_DPLL_36XX_MULT_MASK;
+ dpll3_m3x2_ck.enable =
+ &omap3_pwrdn_bug_clk_enable;
+ dpll4_m2x2_ck.enable =
+ &omap3_pwrdn_bug_clk_enable;
+ dpll4_m3x2_ck.enable =
+ &omap3_pwrdn_bug_clk_enable;
+ dpll4_m4x2_ck.enable =
+ &omap3_pwrdn_bug_clk_enable;
+ dpll4_m5x2_ck.enable =
+ &omap3_pwrdn_bug_clk_enable;
+ dpll4_m6x2_ck.enable =
+ &omap3_pwrdn_bug_clk_enable;
+
+ cpu_clkflg |= CLOCK_IN_OMAP363X;
+ cpu_mask |= RATE_IN_363X;
+
+ omap_96m_alwon_fck.parent = &omap_192m_alwon_ck;
+ omap_96m_alwon_fck.init = &omap2_init_clksel_parent;
+ omap_96m_alwon_fck.clksel_reg = CM_CLKSEL;
+ omap_96m_alwon_fck.prcm_mod = CORE_MOD;
+ omap_96m_alwon_fck.clksel_mask =
+ OMAP3630_CLKSEL_96M_MASK;
+ omap_96m_alwon_fck.clksel = omap_96m_alwon_fck_clksel;
+ omap_96m_alwon_fck.recalc = &omap2_clksel_recalc;
+ }
+ }
clk_init(&omap2_clk_functions);
for (clkp = onchip_34xx_clks;
clkp < onchip_34xx_clks + ARRAY_SIZE(onchip_34xx_clks);
clkp++) {
+ if (cpu_is_omap3630()) {
+ if ((*clkp)->flags & CLOCK_IN_OMAP363X)
+ (*clkp)->clksel_mask = (*clkp)->clksel_mask2;
+ }
if ((*clkp)->flags & cpu_clkflg)
clk_register(*clkp);
}
diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h
index f00bdf7..dca19ad 100644
--- a/arch/arm/mach-omap2/clock34xx.h
+++ b/arch/arm/mach-omap2/clock34xx.h
@@ -253,6 +253,22 @@
{ .div = 14, .val = 14, .flags = RATE_IN_343X },
{ .div = 15, .val = 15, .flags = RATE_IN_343X },
{ .div = 16, .val = 16, .flags = RATE_IN_343X },
+ { .div = 17, .val = 17, .flags = RATE_IN_343X },
+ { .div = 18, .val = 18, .flags = RATE_IN_343X },
+ { .div = 19, .val = 19, .flags = RATE_IN_343X },
+ { .div = 20, .val = 20, .flags = RATE_IN_343X },
+ { .div = 21, .val = 21, .flags = RATE_IN_343X },
+ { .div = 22, .val = 22, .flags = RATE_IN_343X },
+ { .div = 23, .val = 23, .flags = RATE_IN_343X },
+ { .div = 24, .val = 24, .flags = RATE_IN_343X },
+ { .div = 25, .val = 25, .flags = RATE_IN_343X },
+ { .div = 26, .val = 26, .flags = RATE_IN_343X },
+ { .div = 27, .val = 27, .flags = RATE_IN_343X },
+ { .div = 28, .val = 28, .flags = RATE_IN_343X },
+ { .div = 29, .val = 29, .flags = RATE_IN_343X },
+ { .div = 30, .val = 30, .flags = RATE_IN_343X },
+ { .div = 31, .val = 31, .flags = RATE_IN_343X },
+ { .div = 32, .val = 32, .flags = RATE_IN_343X },
{ .div = 0 }
};
@@ -514,6 +530,7 @@
.init = &omap2_init_clksel_parent,
.clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP3430_DIV_DPLL3_MASK,
+ .clksel_shift = OMAP3430_DIV_DPLL3_SHIFT,
.clksel = div16_dpll3_clksel,
.flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
.clkdm = { .name = "dpll3_clkdm" },
@@ -592,6 +609,7 @@
.init = &omap2_init_clksel_parent,
.clksel_reg = OMAP3430_CM_CLKSEL3,
.clksel_mask = OMAP3430_DIV_96M_MASK,
+ .clksel_shift = OMAP3430_DIV_96M_SHIFT,
.clksel = div16_dpll4_clksel,
.flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
.clkdm = { .name = "dpll4_clkdm" },
@@ -616,6 +634,27 @@
* 96M_ALWON_FCLK (called "omap_96m_alwon_fck" below) and
* CM_96K_(F)CLK.
*/
+
+static struct clk omap_192m_alwon_ck = {
+ .name = "omap_192m_alwon_ck",
+ .parent = &dpll4_m2x2_ck,
+ .flags = CLOCK_IN_OMAP363X | PARENT_CONTROLS_CLOCK,
+ .clkdm = { .name = "prm_clkdm" },
+ .recalc = &followparent_recalc,
+ };
+
+static const struct clksel_rate omap_96m_alwon_fck_rates[] = {
+ { .div = 1, .val = 1, .flags = RATE_IN_363X },
+ { .div = 2, .val = 2, .flags = RATE_IN_363X | DEFAULT_RATE },
+ { .div = 0 }
+};
+
+static const struct clksel omap_96m_alwon_fck_clksel[] = {
+ { .parent = &omap_192m_alwon_ck, .rates = omap_96m_alwon_fck_rates },
+ { .parent = NULL }
+};
+
+
static struct clk omap_96m_alwon_fck = {
.name = "omap_96m_alwon_fck",
.parent = &dpll4_m2x2_ck,
@@ -669,8 +708,11 @@
.init = &omap2_init_clksel_parent,
.clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_TV_MASK,
+ .clksel_mask2 = OMAP3630_CLKSEL_TV_MASK,
+ .clksel_shift = OMAP3430_CLKSEL_TV_SHIFT,
.clksel = div16_dpll4_clksel,
- .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK
+ | CLOCK_IN_OMAP363X,
.clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
@@ -761,8 +803,11 @@
.init = &omap2_init_clksel_parent,
.clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_DSS1_MASK,
+ .clksel_mask2 = OMAP3630_CLKSEL_DSS1_MASK,
+ .clksel_shift = OMAP3430_CLKSEL_DSS1_SHIFT,
.clksel = div16_dpll4_clksel,
- .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK
+ | CLOCK_IN_OMAP363X,
.clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap2_clksel_recalc,
.set_rate = &omap2_clksel_set_rate,
@@ -789,10 +834,15 @@
.init = &omap2_init_clksel_parent,
.clksel_reg = CM_CLKSEL,
.clksel_mask = OMAP3430_CLKSEL_CAM_MASK,
+ .clksel_mask2 = OMAP3630_CLKSEL_CAM_MASK,
+ .clksel_shift = OMAP3430_CLKSEL_CAM_SHIFT,
.clksel = div16_dpll4_clksel,
- .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK
+ | CLOCK_IN_OMAP363X,
.clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap2_clksel_recalc,
+ .set_rate = &omap2_clksel_set_rate,
+ .round_rate = &omap2_clksel_round_rate,
};
/* The PWRDN bit is apparently only available on 3430ES2 and above */
@@ -815,8 +865,11 @@
.init = &omap2_init_clksel_parent,
.clksel_reg = CM_CLKSEL1,
.clksel_mask = OMAP3430_DIV_DPLL4_MASK,
+ .clksel_mask2 = OMAP3630_DIV_DPLL4_MASK,
+ .clksel_shift = OMAP3430_DIV_DPLL4_SHIFT,
.clksel = div16_dpll4_clksel,
- .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+ .flags = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK
+ | CLOCK_IN_OMAP363X,
.clkdm = { .name = "dpll4_clkdm" },
.recalc = &omap2_clksel_recalc,
};
@@ -1204,12 +1257,24 @@
/* SGX power domain - 3430ES2 only */
static const struct clksel_rate sgx_core_rates[] = {
+ { .div = 2, .val = 5, .flags = RATE_IN_363X },
{ .div = 3, .val = 0, .flags = RATE_IN_343X | DEFAULT_RATE },
{ .div = 4, .val = 1, .flags = RATE_IN_343X },
{ .div = 6, .val = 2, .flags = RATE_IN_343X },
{ .div = 0 },
};
+static const struct clksel_rate sgx_192m_rates[] = {
+ { .div = 1, .val = 4, .flags = RATE_IN_363X | DEFAULT_RATE },
+ { .div = 0 },
+};
+
+static const struct clksel_rate sgx_corex2_rates[] = {
+ { .div = 3, .val = 6, .flags = RATE_IN_363X | DEFAULT_RATE },
+ { .div = 5, .val = 7, .flags = RATE_IN_363X },
+ { .div = 0 },
+};
+
static const struct clksel_rate sgx_96m_rates[] = {
{ .div = 1, .val = 3, .flags = RATE_IN_343X | DEFAULT_RATE },
{ .div = 0 },
@@ -1218,6 +1283,9 @@
static const struct clksel sgx_clksel[] = {
{ .parent = &core_ck, .rates = sgx_core_rates },
{ .parent = &cm_96m_fck, .rates = sgx_96m_rates },
+ { .parent = &omap_192m_alwon_ck, .rates = sgx_192m_rates },
+ { .parent = &corex2_fck, .rates = sgx_corex2_rates },
+
{ .parent = NULL },
};
@@ -1233,6 +1301,8 @@
.flags = CLOCK_IN_OMAP3430ES2,
.clkdm = { .name = "sgx_clkdm" },
.recalc = &omap2_clksel_recalc,
+ .set_rate = &omap2_clksel_set_rate,
+ .round_rate = &omap2_clksel_round_rate,
};
static struct clk sgx_ick = {
@@ -3368,6 +3438,7 @@
&dpll3_m3x2_ck,
&emu_core_alwon_ck,
&dpll4_ck,
+ &omap_192m_alwon_ck,
&omap_96m_alwon_fck,
&omap_96m_fck,
&cm_96m_fck,
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index fa55b6f..fc1e65e 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -134,6 +134,37 @@
}
+/*
+ * _omap2_clkdm_set_hwsup - set the hwsup idle transition bit
+ * @clkdm: struct clockdomain *
+ * @enable: int 0 to disable, 1 to enable
+ *
+ * Internal helper for actually switching the bit that controls hwsup
+ * idle transitions for clkdm.
+ */
+static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable)
+{
+ u32 v;
+
+ if (cpu_is_omap24xx()) {
+ if (enable)
+ v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO;
+ else
+ v = OMAP24XX_CLKSTCTRL_DISABLE_AUTO;
+ } else if (cpu_is_omap34xx()) {
+ if (enable)
+ v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO;
+ else
+ v = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
+ } else {
+ BUG();
+ }
+
+ cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
+ v << __ffs(clkdm->clktrctrl_mask),
+ clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
+}
+
static struct clockdomain *_clkdm_lookup(const char *name)
{
struct clockdomain *clkdm, *temp_clkdm;
@@ -452,7 +483,6 @@
*/
void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
{
- u32 v;
if (!clkdm)
return;
@@ -468,20 +498,7 @@
if (atomic_read(&clkdm->usecount) > 0)
_clkdm_add_autodeps(clkdm);
-
- if (cpu_is_omap24xx())
- v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO;
- else if (cpu_is_omap34xx())
- v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO;
- else
- BUG();
-
-
- cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
- v << __ffs(clkdm->clktrctrl_mask),
- clkdm->pwrdm.ptr->prcm_offs,
- CM_CLKSTCTRL);
-
+ _omap2_clkdm_set_hwsup(clkdm, 1);
pwrdm_clkdm_state_switch(clkdm);
}
@@ -496,7 +513,6 @@
*/
void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
{
- u32 v;
if (!clkdm)
return;
@@ -510,17 +526,7 @@
pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
clkdm->name);
- if (cpu_is_omap24xx())
- v = OMAP24XX_CLKSTCTRL_DISABLE_AUTO;
- else if (cpu_is_omap34xx())
- v = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
- else
- BUG();
-
- cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
- v << __ffs(clkdm->clktrctrl_mask),
- clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
-
+ _omap2_clkdm_set_hwsup(clkdm, 0);
if (atomic_read(&clkdm->usecount) > 0)
_clkdm_del_autodeps(clkdm);
}
@@ -565,11 +571,14 @@
v = omap2_clkdm_clktrctrl_read(clkdm);
if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
- (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
+ (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) {
+ /* Disable HW transitions when we are changing deps */
+ _omap2_clkdm_set_hwsup(clkdm, 0);
_clkdm_add_autodeps(clkdm);
- else
+ _omap2_clkdm_set_hwsup(clkdm, 1);
+ } else {
omap2_clkdm_wakeup(clkdm);
-
+ }
pwrdm_wait_transition(clkdm->pwrdm.ptr);
pwrdm_clkdm_state_switch(clkdm);
@@ -619,11 +628,14 @@
v = omap2_clkdm_clktrctrl_read(clkdm);
if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
- (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
+ (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) {
+ /*Disable HW transitions when we are changing deps */
+ _omap2_clkdm_set_hwsup(clkdm, 0);
_clkdm_del_autodeps(clkdm);
- else
+ _omap2_clkdm_set_hwsup(clkdm, 1);
+ } else {
omap2_clkdm_sleep(clkdm);
-
+ }
pwrdm_clkdm_state_switch(clkdm);
return 0;
diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index 6923deb..159cb3e 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -81,7 +81,7 @@
/* CM_CLKSEL1_PLL_IVA2 */
#define OMAP3430_IVA2_CLK_SRC_SHIFT 19
-#define OMAP3430_IVA2_CLK_SRC_MASK (0x3 << 19)
+#define OMAP3430_IVA2_CLK_SRC_MASK (0x7 << 19)
#define OMAP3430_IVA2_DPLL_MULT_SHIFT 8
#define OMAP3430_IVA2_DPLL_MULT_MASK (0x7ff << 8)
#define OMAP3430_IVA2_DPLL_DIV_SHIFT 0
@@ -126,7 +126,7 @@
/* CM_CLKSEL1_PLL_MPU */
#define OMAP3430_MPU_CLK_SRC_SHIFT 19
-#define OMAP3430_MPU_CLK_SRC_MASK (0x3 << 19)
+#define OMAP3430_MPU_CLK_SRC_MASK (0x7 << 19)
#define OMAP3430_MPU_DPLL_MULT_SHIFT 8
#define OMAP3430_MPU_DPLL_MULT_MASK (0x7ff << 8)
#define OMAP3430_MPU_DPLL_DIV_SHIFT 0
@@ -336,6 +336,8 @@
#define OMAP3430_CLKSEL_L4_MASK (0x3 << 2)
#define OMAP3430_CLKSEL_L3_SHIFT 0
#define OMAP3430_CLKSEL_L3_MASK (0x3 << 0)
+#define OMAP3630_CLKSEL_96M_SHIFT 12
+#define OMAP3630_CLKSEL_96M_MASK (0x3 << 12)
/* CM_CLKSTCTRL_CORE */
#define OMAP3430ES1_CLKTRCTRL_D2D_SHIFT 4
@@ -517,8 +519,13 @@
/* CM_CLKSEL2_PLL */
#define OMAP3430_PERIPH_DPLL_MULT_SHIFT 8
#define OMAP3430_PERIPH_DPLL_MULT_MASK (0x7ff << 8)
+#define OMAP3430_PERIPH_DPLL_36XX_MULT_MASK (0xfff << 8)
#define OMAP3430_PERIPH_DPLL_DIV_SHIFT 0
#define OMAP3430_PERIPH_DPLL_DIV_MASK (0x7f << 0)
+#define OMAP3630_PERIPH_DPLL_DCO_SEL_SHIFT 21
+#define OMAP3630_PERIPH_DPLL_DCO_SEL_MASK (0x7 << 21)
+#define OMAP3630_PERIPH_DPLL_SD_DIV_SHIFT 24
+#define OMAP3630_PERIPH_DPLL_SD_DIV_MASK (0xff << 24)
/* CM_CLKSEL3_PLL */
#define OMAP3430_DIV_96M_SHIFT 0
@@ -569,8 +576,10 @@
/* CM_CLKSEL_DSS */
#define OMAP3430_CLKSEL_TV_SHIFT 8
#define OMAP3430_CLKSEL_TV_MASK (0x1f << 8)
+#define OMAP3630_CLKSEL_TV_MASK (0x3f << 8)
#define OMAP3430_CLKSEL_DSS1_SHIFT 0
#define OMAP3430_CLKSEL_DSS1_MASK (0x1f << 0)
+#define OMAP3630_CLKSEL_DSS1_MASK (0x3f << 0)
/* CM_SLEEPDEP_DSS specific bits */
@@ -598,6 +607,7 @@
/* CM_CLKSEL_CAM */
#define OMAP3430_CLKSEL_CAM_SHIFT 0
#define OMAP3430_CLKSEL_CAM_MASK (0x1f << 0)
+#define OMAP3630_CLKSEL_CAM_MASK (0x3f << 0)
/* CM_SLEEPDEP_CAM specific bits */
@@ -693,8 +703,10 @@
/* CM_CLKSEL1_EMU */
#define OMAP3430_DIV_DPLL4_SHIFT 24
#define OMAP3430_DIV_DPLL4_MASK (0x1f << 24)
+#define OMAP3630_DIV_DPLL4_MASK (0x3f << 24)
#define OMAP3430_DIV_DPLL3_SHIFT 16
#define OMAP3430_DIV_DPLL3_MASK (0x1f << 16)
+#define OMAP3630_DIV_DPLL3_MASK (0x3f << 16)
#define OMAP3430_CLKSEL_TRACECLK_SHIFT 11
#define OMAP3430_CLKSEL_TRACECLK_MASK (0x7 << 11)
#define OMAP3430_CLKSEL_PCLK_SHIFT 8
diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index c9407c0..4219314 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -209,8 +209,7 @@
/* Populate the Scratchpad contents */
scratchpad_contents.boot_config_ptr = 0x0;
- if (omap_rev() != OMAP3430_REV_ES3_0 &&
- omap_rev() != OMAP3430_REV_ES3_1)
+ if (omap_rev() < OMAP3430_REV_ES3_0)
scratchpad_contents.public_restore_ptr =
virt_to_phys(get_restore_pointer());
else
@@ -331,6 +330,27 @@
sizeof(sdrc_block_contents), &arm_context_addr, 4);
}
+void omap3_scratchpad_dpll4autoidle(int enable)
+{
+ void * __iomem scratchpad_address;
+ struct omap3_scratchpad_prcm_block prcm_block_contents;
+
+ scratchpad_address = OMAP2_IO_ADDRESS(OMAP343X_SCRATCHPAD);
+
+ memcpy_fromio(&prcm_block_contents, scratchpad_address + 0x2C,
+ sizeof(prcm_block_contents));
+ if (enable)
+ prcm_block_contents.cm_autoidle_pll |=
+ (1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT);
+ else
+ prcm_block_contents.cm_autoidle_pll &=
+ ~OMAP3430_AUTO_PERIPH_DPLL_MASK;
+
+ memcpy_toio(scratchpad_address + 0x2C, &prcm_block_contents,
+ sizeof(prcm_block_contents));
+
+}
+
void omap3_control_save_context(void)
{
control_context.sysconfig = omap_ctrl_readl(OMAP2_CONTROL_SYSCONFIG);
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 6ac2c66..6086837 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -35,14 +35,17 @@
#ifdef CONFIG_CPU_IDLE
-#define OMAP3_MAX_STATES 7
+#define OMAP3_MAX_STATES 9
#define OMAP3_STATE_C1 0 /* C1 - MPU WFI + Core active */
-#define OMAP3_STATE_C2 1 /* C2 - MPU WFI + Core inactive */
+#define OMAP3_STATE_C2 1 /* C2 - MPU inactive + Core inactive */
#define OMAP3_STATE_C3 2 /* C3 - MPU CSWR + Core inactive */
-#define OMAP3_STATE_C4 3 /* C4 - MPU OFF + Core iactive */
-#define OMAP3_STATE_C5 4 /* C5 - MPU RET + Core RET */
-#define OMAP3_STATE_C6 5 /* C6 - MPU OFF + Core RET */
-#define OMAP3_STATE_C7 6 /* C7 - MPU OFF + Core OFF */
+#define OMAP3_STATE_C4 3 /* C4 - MPU OFF + Core inactive */
+#define OMAP3_STATE_C5 4 /* C5 - MPU CSWR + Core CSWR */
+#define OMAP3_STATE_C6 5 /* C6 - MPU OFF + Core CSWR */
+#define OMAP3_STATE_C7 6 /* C7 - MPU OSWR + CORE OSWR */
+#define OMAP3_STATE_C8 7 /* C8 - MPU OFF + CORE OSWR */
+#define OMAP3_STATE_C9 8 /* C9 - MPU OFF + CORE OFF */
+
struct omap3_processor_cx {
u8 valid;
@@ -51,13 +54,19 @@
u32 wakeup_latency;
u32 mpu_state;
u32 core_state;
+ u32 mpu_logicl1_ret_state;
+ u32 mpu_l2cache_ret_state;
+ u32 core_logic_state;
+ u32 core_mem1_ret_state;
+ u32 core_mem2_ret_state;
u32 threshold;
u32 flags;
};
struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES];
struct omap3_processor_cx current_cx_state;
-struct powerdomain *mpu_pd, *core_pd, *per_pd;
+struct powerdomain *mpu_pd, *core_pd, *per_pd, *iva2_pd;
+struct powerdomain *sgx_pd, *usb_pd, *cam_pd, *dss_pd;
static int omap3_idle_bm_check(void)
{
@@ -66,19 +75,13 @@
return 0;
}
-static int _cpuidle_allow_idle(struct powerdomain *pwrdm,
- struct clockdomain *clkdm)
+static int pwrdm_get_idle_state(struct powerdomain *pwrdm)
{
- omap2_clkdm_allow_idle(clkdm);
- return 0;
+ if (pwrdm_can_idle(pwrdm))
+ return pwrdm_read_next_pwrst(pwrdm);
+ return PWRDM_POWER_ON;
}
-static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
- struct clockdomain *clkdm)
-{
- omap2_clkdm_deny_idle(clkdm);
- return 0;
-}
/**
* omap3_enter_idle - Programs OMAP3 to enter the specified state
@@ -94,7 +97,11 @@
struct omap3_processor_cx *cx = cpuidle_get_statedata(state);
struct timespec ts_preidle, ts_postidle, ts_idle;
u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
-
+ u32 mpu_logicl1_ret_state = cx->mpu_logicl1_ret_state;
+ u32 mpu_l2cache_ret_state = cx->mpu_l2cache_ret_state;
+ u32 core_logic_state = cx->core_logic_state;
+ u32 core_mem1_ret_state = cx->core_mem1_ret_state;
+ u32 core_mem2_ret_state = cx->core_mem2_ret_state;
current_cx_state = *cx;
/* Used to keep track of the total time in idle */
@@ -103,31 +110,45 @@
local_irq_disable();
local_fiq_disable();
- if (!enable_off_mode) {
- if (mpu_state < PWRDM_POWER_RET)
- mpu_state = PWRDM_POWER_RET;
- if (core_state < PWRDM_POWER_RET)
- core_state = PWRDM_POWER_RET;
+
+ if (!enable_oswr_ret) {
+ if (mpu_logicl1_ret_state == PWRDM_POWER_OFF)
+ mpu_logicl1_ret_state = PWRDM_POWER_RET;
+ if (mpu_l2cache_ret_state == PWRDM_POWER_OFF)
+ mpu_l2cache_ret_state = PWRDM_POWER_RET;
+ if (core_logic_state == PWRDM_POWER_OFF)
+ core_logic_state = PWRDM_POWER_RET;
+ if (core_mem1_ret_state == PWRDM_POWER_OFF)
+ core_mem1_ret_state = PWRDM_POWER_RET;
+ if (core_mem2_ret_state == PWRDM_POWER_OFF)
+ core_mem2_ret_state = PWRDM_POWER_RET;
}
+ if (mpu_logicl1_ret_state != 0xFF)
+ pwrdm_set_logic_retst(mpu_pd, mpu_logicl1_ret_state);
+
+ if (mpu_l2cache_ret_state != 0xFF)
+ pwrdm_set_mem_retst(mpu_pd, 0, mpu_l2cache_ret_state);
+
+ if (core_logic_state != 0xFF)
+ pwrdm_set_logic_retst(core_pd, core_logic_state);
+
+ if (core_mem1_ret_state != 0xFF)
+ pwrdm_set_mem_retst(core_pd, 0, core_mem1_ret_state);
+
+ if (core_mem2_ret_state != 0xFF)
+ pwrdm_set_mem_retst(core_pd, 1, core_mem2_ret_state);
+
pwrdm_set_next_pwrst(mpu_pd, mpu_state);
pwrdm_set_next_pwrst(core_pd, core_state);
if (omap_irq_pending() || need_resched())
goto return_sleep_time;
- if (cx->type == OMAP3_STATE_C1) {
- pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle);
- pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle);
- }
/* Execute ARM wfi */
omap_sram_idle();
- if (cx->type == OMAP3_STATE_C1) {
- pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle);
- pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle);
- }
return_sleep_time:
getnstimeofday(&ts_postidle);
@@ -136,9 +157,8 @@
local_irq_enable();
local_fiq_enable();
- return (u32)timespec_to_ns(&ts_idle)/1000;
+ return ts_idle.tv_nsec/NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC;
}
-
/**
* omap3_enter_idle_bm - Checks for any bus activity
* @dev: cpuidle device
@@ -153,13 +173,90 @@
{
struct cpuidle_state *new_state = state;
- if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) {
- BUG_ON(!dev->safe_state);
- new_state = dev->safe_state;
- }
+ u32 per_state = 0, saved_per_state = 0, cam_state, usb_state;
+ u32 iva2_state, sgx_state, dss_state, new_core_state;
+ struct omap3_processor_cx *cx;
+ int ret;
+ if (state->flags & CPUIDLE_FLAG_CHECK_BM) {
+ if (omap3_idle_bm_check()) {
+ BUG_ON(!dev->safe_state);
+ new_state = dev->safe_state;
+ goto select_state;
+ }
+ cx = cpuidle_get_statedata(state);
+ new_core_state = cx->core_state;
+
+ /* Check if CORE is active, if yes, fallback to inactive */
+ if (!pwrdm_can_idle(core_pd))
+ new_core_state = PWRDM_POWER_INACTIVE;
+
+ /*
+ * Prevent idle completely if CAM is active.
+ * CAM does not have wakeup capability in OMAP3.
+ */
+ cam_state = pwrdm_get_idle_state(cam_pd);
+ if (cam_state == PWRDM_POWER_ON) {
+ new_state = dev->safe_state;
+ goto select_state;
+ }
+
+ /*
+ * Check if PER can idle or not. If we are not likely
+ * to idle, deny PER off. This prevents unnecessary
+ * context save/restore.
+ */
+ saved_per_state = pwrdm_read_next_pwrst(per_pd);
+ if (pwrdm_can_idle(per_pd)) {
+ per_state = saved_per_state;
+ /*
+ * Prevent PER off if CORE is active as this
+ * would disable PER wakeups completely
+ */
+ if (per_state == PWRDM_POWER_OFF &&
+ new_core_state > PWRDM_POWER_RET)
+ per_state = PWRDM_POWER_RET;
+
+ } else if (saved_per_state == PWRDM_POWER_OFF)
+ per_state = PWRDM_POWER_RET;
+
+ /*
+ * If we are attempting CORE off, check if any other
+ * powerdomains are at retention or higher. CORE off causes
+ * chipwide reset which would reset these domains also.
+ */
+ if (new_core_state == PWRDM_POWER_OFF) {
+ dss_state = pwrdm_get_idle_state(dss_pd);
+ iva2_state = pwrdm_get_idle_state(iva2_pd);
+ sgx_state = pwrdm_get_idle_state(sgx_pd);
+ usb_state = pwrdm_get_idle_state(usb_pd);
+
+ if (cam_state > PWRDM_POWER_OFF ||
+ dss_state > PWRDM_POWER_OFF ||
+ iva2_state > PWRDM_POWER_OFF ||
+ per_state > PWRDM_POWER_OFF ||
+ sgx_state > PWRDM_POWER_OFF ||
+ usb_state > PWRDM_POWER_OFF)
+ new_core_state = PWRDM_POWER_RET;
+ }
+ /* Fallback to new target core state */
+ while (cx->core_state > new_core_state) {
+ state--;
+ cx = cpuidle_get_statedata(state);
+ }
+ new_state = state;
+ /* Are we changing PER target state? */
+ if (per_state != saved_per_state)
+ pwrdm_set_next_pwrst(per_pd, per_state);
+
+ }
+select_state:
dev->last_state = new_state;
- return omap3_enter_idle(dev, new_state);
+ ret = omap3_enter_idle(dev, new_state);
+ /* Restore potentially tampered PER state */
+ if (per_state != saved_per_state)
+ pwrdm_set_next_pwrst(per_pd, saved_per_state);
+ return ret;
}
DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
@@ -168,15 +265,29 @@
*
* Below is the desciption of each C state.
* C1 . MPU WFI + Core active
- * C2 . MPU WFI + Core inactive
+ * C2 . MPU inactive + Core inactive
* C3 . MPU CSWR + Core inactive
* C4 . MPU OFF + Core inactive
* C5 . MPU CSWR + Core CSWR
* C6 . MPU OFF + Core CSWR
- * C7 . MPU OFF + Core OFF
+ * C7 . MPU OSWR + Core OSWR
+ * C8 . MPU OFF + Core OSWR
+ * C9 . MPU OFF + Core OFF
*/
void omap_init_power_states(void)
{
+ int i;
+ struct omap3_processor_cx *cx;
+
+ for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
+ cx = &omap3_power_states[i];
+ cx->mpu_logicl1_ret_state = 0xFF;
+ cx->mpu_l2cache_ret_state = 0xFF;
+ cx->core_logic_state = 0xFF;
+ cx->core_mem1_ret_state = 0xFF;
+ cx->core_mem2_ret_state = 0xFF;
+ }
+
/* C1 . MPU WFI + Core active */
omap3_power_states[OMAP3_STATE_C1].valid = 1;
omap3_power_states[OMAP3_STATE_C1].type = OMAP3_STATE_C1;
@@ -193,9 +304,10 @@
omap3_power_states[OMAP3_STATE_C2].sleep_latency = 0;
omap3_power_states[OMAP3_STATE_C2].wakeup_latency = 18;
omap3_power_states[OMAP3_STATE_C2].threshold = 20;
- omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON;
- omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON;
- omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID;
+ omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_INACTIVE;
+ omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_INACTIVE;
+ omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID |
+ CPUIDLE_FLAG_CHECK_BM;
/* C3 . MPU CSWR + Core inactive */
omap3_power_states[OMAP3_STATE_C3].valid = 1;
@@ -203,8 +315,16 @@
omap3_power_states[OMAP3_STATE_C3].sleep_latency = 150;
omap3_power_states[OMAP3_STATE_C3].wakeup_latency = 260;
omap3_power_states[OMAP3_STATE_C3].threshold = 500;
+#ifdef CONFIG_OMAP3_MPU_L2_CACHE_WORKAROUND
+ omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_INACTIVE;
+#else
omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_RET;
+#endif
omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_INACTIVE;
+ omap3_power_states[OMAP3_STATE_C3].mpu_logicl1_ret_state =
+ PWRDM_POWER_RET;
+ omap3_power_states[OMAP3_STATE_C3].mpu_l2cache_ret_state =
+ PWRDM_POWER_RET;
omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID |
CPUIDLE_FLAG_CHECK_BM;
@@ -225,8 +345,21 @@
omap3_power_states[OMAP3_STATE_C5].sleep_latency = 310;
omap3_power_states[OMAP3_STATE_C5].wakeup_latency = 2850;
omap3_power_states[OMAP3_STATE_C5].threshold = 5000;
+#ifdef CONFIG_OMAP3_MPU_L2_CACHE_WORKAROUND
+ omap3_power_states[OMAP3_STATE_C5].mpu_state = PWRDM_POWER_INACTIVE;
+#else
omap3_power_states[OMAP3_STATE_C5].mpu_state = PWRDM_POWER_RET;
+#endif
omap3_power_states[OMAP3_STATE_C5].core_state = PWRDM_POWER_RET;
+ omap3_power_states[OMAP3_STATE_C5].mpu_logicl1_ret_state =
+ PWRDM_POWER_RET;
+ omap3_power_states[OMAP3_STATE_C5].mpu_l2cache_ret_state =
+ PWRDM_POWER_RET;
+ omap3_power_states[OMAP3_STATE_C5].core_logic_state = PWRDM_POWER_RET;
+ omap3_power_states[OMAP3_STATE_C5].core_mem1_ret_state =
+ PWRDM_POWER_RET;
+ omap3_power_states[OMAP3_STATE_C5].core_mem2_ret_state =
+ PWRDM_POWER_RET;
omap3_power_states[OMAP3_STATE_C5].flags = CPUIDLE_FLAG_TIME_VALID |
CPUIDLE_FLAG_CHECK_BM;
@@ -238,20 +371,87 @@
omap3_power_states[OMAP3_STATE_C6].threshold = 10000;
omap3_power_states[OMAP3_STATE_C6].mpu_state = PWRDM_POWER_OFF;
omap3_power_states[OMAP3_STATE_C6].core_state = PWRDM_POWER_RET;
+ omap3_power_states[OMAP3_STATE_C6].core_logic_state = PWRDM_POWER_RET;
+ omap3_power_states[OMAP3_STATE_C6].core_mem1_ret_state =
+ PWRDM_POWER_RET;
+ omap3_power_states[OMAP3_STATE_C6].core_mem2_ret_state =
+ PWRDM_POWER_RET;
omap3_power_states[OMAP3_STATE_C6].flags = CPUIDLE_FLAG_TIME_VALID |
CPUIDLE_FLAG_CHECK_BM;
- /* C7 . MPU OFF + Core OFF */
+ /* C7 . MPU OSWR + Core OSWR */
omap3_power_states[OMAP3_STATE_C7].valid = 1;
omap3_power_states[OMAP3_STATE_C7].type = OMAP3_STATE_C7;
- omap3_power_states[OMAP3_STATE_C7].sleep_latency = 10000;
- omap3_power_states[OMAP3_STATE_C7].wakeup_latency = 30000;
- omap3_power_states[OMAP3_STATE_C7].threshold = 300000;
- omap3_power_states[OMAP3_STATE_C7].mpu_state = PWRDM_POWER_OFF;
- omap3_power_states[OMAP3_STATE_C7].core_state = PWRDM_POWER_OFF;
+ omap3_power_states[OMAP3_STATE_C7].sleep_latency = 4000;
+ omap3_power_states[OMAP3_STATE_C7].wakeup_latency = 9000;
+ omap3_power_states[OMAP3_STATE_C7].threshold = 18000;
+ omap3_power_states[OMAP3_STATE_C7].mpu_state = PWRDM_POWER_RET;
+ omap3_power_states[OMAP3_STATE_C7].core_state = PWRDM_POWER_RET;
+ omap3_power_states[OMAP3_STATE_C7].mpu_logicl1_ret_state =
+ PWRDM_POWER_OFF;
+ omap3_power_states[OMAP3_STATE_C7].mpu_l2cache_ret_state =
+ PWRDM_POWER_OFF;
+ omap3_power_states[OMAP3_STATE_C7].core_logic_state = PWRDM_POWER_OFF;
+ omap3_power_states[OMAP3_STATE_C7].core_mem1_ret_state =
+ PWRDM_POWER_OFF;
+ omap3_power_states[OMAP3_STATE_C7].core_mem2_ret_state =
+ PWRDM_POWER_OFF;
omap3_power_states[OMAP3_STATE_C7].flags = CPUIDLE_FLAG_TIME_VALID |
CPUIDLE_FLAG_CHECK_BM;
+
+ /* C8 . MPU OFF + Core OSWR */
+ omap3_power_states[OMAP3_STATE_C8].valid = 1;
+ omap3_power_states[OMAP3_STATE_C8].type = OMAP3_STATE_C7;
+ omap3_power_states[OMAP3_STATE_C8].sleep_latency = 8000;
+ omap3_power_states[OMAP3_STATE_C8].wakeup_latency = 25000;
+ omap3_power_states[OMAP3_STATE_C8].threshold = 250000;
+ omap3_power_states[OMAP3_STATE_C8].mpu_state = PWRDM_POWER_OFF;
+ omap3_power_states[OMAP3_STATE_C8].core_state = PWRDM_POWER_RET;
+ omap3_power_states[OMAP3_STATE_C8].core_logic_state = PWRDM_POWER_OFF;
+ omap3_power_states[OMAP3_STATE_C8].core_mem1_ret_state =
+ PWRDM_POWER_OFF;
+ omap3_power_states[OMAP3_STATE_C8].core_mem2_ret_state =
+ PWRDM_POWER_OFF;
+ omap3_power_states[OMAP3_STATE_C8].flags = CPUIDLE_FLAG_TIME_VALID |
+ CPUIDLE_FLAG_CHECK_BM;
+
+ /* C9 . MPU OFF + Core OFF */
+ omap3_power_states[OMAP3_STATE_C9].valid = 1;
+ omap3_power_states[OMAP3_STATE_C9].type = OMAP3_STATE_C7;
+ omap3_power_states[OMAP3_STATE_C9].sleep_latency = 10000;
+ omap3_power_states[OMAP3_STATE_C9].wakeup_latency = 30000;
+ omap3_power_states[OMAP3_STATE_C9].threshold = 300000;
+ omap3_power_states[OMAP3_STATE_C9].mpu_state = PWRDM_POWER_OFF;
+ omap3_power_states[OMAP3_STATE_C9].core_state = PWRDM_POWER_OFF;
+ omap3_power_states[OMAP3_STATE_C9].flags = CPUIDLE_FLAG_TIME_VALID |
+ CPUIDLE_FLAG_CHECK_BM;
+
}
+/**
+ * omap3_cpuidle_update_states - Update the cpuidle states.
+ *
+ * Currently, this function toggles the validity of idle states based upon
+ * the flag 'enable_off_mode'. When the flag is set all states are valid.
+ * Else, states leading to OFF state set to be invalid.
+ */
+void omap3_cpuidle_update_states(void)
+{
+ int i;
+
+ for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
+ if (enable_off_mode) {
+ omap3_power_states[i].valid = 1;
+ } else {
+ if ((omap3_power_states[i].mpu_state
+ == PWRDM_POWER_OFF)
+ || (omap3_power_states[i].core_state
+ == PWRDM_POWER_RET))
+ omap3_power_states[i].valid = 0;
+ }
+ }
+}
+
+
struct cpuidle_driver omap3_idle_driver = {
.name = "omap3_idle",
@@ -274,6 +474,11 @@
mpu_pd = pwrdm_lookup("mpu_pwrdm");
core_pd = pwrdm_lookup("core_pwrdm");
per_pd = pwrdm_lookup("per_pwrdm");
+ iva2_pd = pwrdm_lookup("iva2_pwrdm");
+ sgx_pd = pwrdm_lookup("sgx_pwrdm");
+ usb_pd = pwrdm_lookup("usbhost_pwrdm");
+ cam_pd = pwrdm_lookup("cam_pwrdm");
+ dss_pd = pwrdm_lookup("dss_pwrdm");
omap_init_power_states();
cpuidle_register_driver(&omap3_idle_driver);
@@ -302,6 +507,8 @@
return -EINVAL;
dev->state_count = count;
+ omap3_cpuidle_update_states();
+
if (cpuidle_register_device(dev)) {
printk(KERN_ERR "%s: CPUidle register device failed\n",
__func__);
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index f816b56..937d3ec 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -113,6 +113,11 @@
.flags = IORESOURCE_MEM,
},
{
+ .start = OMAP3430_ISP_CSI2PHY2_BASE,
+ .end = OMAP3430_ISP_CSI2PHY2_END,
+ .flags = IORESOURCE_MEM,
+ },
+ {
.start = INT_34XX_CAM_IRQ,
.flags = IORESOURCE_IRQ,
}
@@ -545,19 +550,24 @@
}
}
- if (cpu_is_omap3430()) {
+ if (cpu_is_omap3430() || cpu_is_omap3630()) {
u32 dev_conf = 0, v_shift = 0;
if (controller_nr == 0) {
omap_cfg_reg(N28_3430_MMC1_CLK);
omap_cfg_reg(M27_3430_MMC1_CMD);
omap_cfg_reg(N27_3430_MMC1_DAT0);
- omap_cfg_reg(N26_3430_MMC1_DAT1);
- omap_cfg_reg(N25_3430_MMC1_DAT2);
- omap_cfg_reg(P28_3430_MMC1_DAT3);
- omap_cfg_reg(P27_3430_MMC1_DAT4);
- omap_cfg_reg(P26_3430_MMC1_DAT5);
- omap_cfg_reg(R27_3430_MMC1_DAT6);
- omap_cfg_reg(R25_3430_MMC1_DAT7);
+ if (mmc_controller->slots[0].wires == 4 ||
+ mmc_controller->slots[0].wires == 8) {
+ omap_cfg_reg(N26_3430_MMC1_DAT1);
+ omap_cfg_reg(N25_3430_MMC1_DAT2);
+ omap_cfg_reg(P28_3430_MMC1_DAT3);
+ }
+ if (mmc_controller->slots[0].wires == 8) {
+ omap_cfg_reg(P27_3430_MMC1_DAT4);
+ omap_cfg_reg(P26_3430_MMC1_DAT5);
+ omap_cfg_reg(R27_3430_MMC1_DAT6);
+ omap_cfg_reg(R25_3430_MMC1_DAT7);
+ }
dev_conf = OMAP2_CONTROL_DEVCONF0;
v_shift = OMAP2_MMCSDIO1ADPCLKISEL;
}
@@ -566,9 +576,18 @@
omap_cfg_reg(AE2_3430_MMC2_CLK);
omap_cfg_reg(AG5_3430_MMC2_CMD);
omap_cfg_reg(AH5_3430_MMC2_DAT0);
- omap_cfg_reg(AH4_3430_MMC2_DAT1);
- omap_cfg_reg(AG4_3430_MMC2_DAT2);
- omap_cfg_reg(AF4_3430_MMC2_DAT3);
+ if (mmc_controller->slots[0].wires == 4 ||
+ mmc_controller->slots[0].wires == 8) {
+ omap_cfg_reg(AH4_3430_MMC2_DAT1);
+ omap_cfg_reg(AG4_3430_MMC2_DAT2);
+ omap_cfg_reg(AF4_3430_MMC2_DAT3);
+ }
+ if (mmc_controller->slots[0].wires == 8) {
+ omap_cfg_reg(AE4_3430_MMC2_DAT4);
+ omap_cfg_reg(AH3_3430_MMC2_DAT5);
+ omap_cfg_reg(AF3_3430_MMC2_DAT6);
+ omap_cfg_reg(AE3_3430_MMC2_DAT7);
+ }
dev_conf = OMAP343X_CONTROL_DEVCONF1;
v_shift = OMAP2_MMCSDIO2ADPCLKISEL;
}
@@ -577,9 +596,12 @@
omap_cfg_reg(AF10_3430_MMC3_CLK);
omap_cfg_reg(AC3_3430_MMC3_CMD);
omap_cfg_reg(AE11_3430_MMC3_DAT0);
- omap_cfg_reg(AH9_3430_MMC3_DAT1);
- omap_cfg_reg(AF13_3430_MMC3_DAT2);
- omap_cfg_reg(AE13_3430_MMC3_DAT3);
+ if (mmc_controller->slots[0].wires == 4 ||
+ mmc_controller->slots[0].wires == 8) {
+ omap_cfg_reg(AH9_3430_MMC3_DAT1);
+ omap_cfg_reg(AF13_3430_MMC3_DAT2);
+ omap_cfg_reg(AE13_3430_MMC3_DAT3);
+ }
}
/*
@@ -619,7 +641,7 @@
irq = INT_24XX_MMC2_IRQ;
break;
case 2:
- if (!cpu_is_omap34xx())
+ if (!(cpu_is_omap34xx() || cpu_is_omap3630()))
return;
base = OMAP3_MMC3_BASE;
irq = INT_34XX_MMC3_IRQ;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 9458869..7982cc3 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -54,6 +54,11 @@
#define GPMC_CHUNK_SHIFT 24 /* 16 MB */
#define GPMC_SECTION_SHIFT 28 /* 128 MB */
+#define PREFETCH_FIFOTHRESHOLD (0x40 << 8)
+#define CS_NUM_SHIFT 24
+#define ENABLE_PREFETCH (0x1 << 7)
+#define DMA_MPU_MODE 2
+
/* Structure to save gpmc cs context */
struct gpmc_cs_config {
u32 config1;
@@ -411,6 +416,63 @@
}
EXPORT_SYMBOL(gpmc_cs_free);
+/**
+ * gpmc_prefetch_enable - configures and starts prefetch transfer
+ * @cs: nand cs (chip select) number
+ * @dma_mode: dma mode enable (1) or disable (0)
+ * @u32_count: number of bytes to be transferred
+ * @is_write: prefetch read(0) or write post(1) mode
+ */
+int gpmc_prefetch_enable(int cs, int dma_mode,
+ unsigned int u32_count, int is_write)
+{
+ uint32_t prefetch_config1;
+
+ if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
+ /* Set the amount of bytes to be prefetched */
+ gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
+
+ /* Set dma/mpu mode, the prefetch read / post write and
+ * enable the engine. Set which cs is has requested for.
+ */
+ prefetch_config1 = ((cs << CS_NUM_SHIFT) |
+ PREFETCH_FIFOTHRESHOLD |
+ ENABLE_PREFETCH |
+ (dma_mode << DMA_MPU_MODE) |
+ (0x1 & is_write));
+ gpmc_write_reg(GPMC_PREFETCH_CONFIG1, prefetch_config1);
+ } else {
+ return -EBUSY;
+ }
+ /* Start the prefetch engine */
+ gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x1);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpmc_prefetch_enable);
+
+/**
+ * gpmc_prefetch_reset - disables and stops the prefetch engine
+ */
+void gpmc_prefetch_reset(void)
+{
+ /* Stop the PFPW engine */
+ gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0);
+
+ /* Reset/disable the PFPW engine */
+ gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0);
+}
+EXPORT_SYMBOL(gpmc_prefetch_reset);
+
+/**
+ * gpmc_prefetch_status - reads prefetch status of engine
+ */
+int gpmc_prefetch_status(void)
+{
+ return gpmc_read_reg(GPMC_PREFETCH_STATUS);
+}
+EXPORT_SYMBOL(gpmc_prefetch_status);
+
static void __init gpmc_mem_init(void)
{
int cs;
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 32ceaa6..6424b23 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -23,8 +23,9 @@
#include <mach/cpu.h>
static struct omap_chip_id omap_chip;
-static unsigned int omap_revision;
+static unsigned int omap_revision, omap_revision_id;
+static char *rev_name = "ES1.0 ";
unsigned int omap_rev(void)
{
@@ -32,6 +33,12 @@
}
EXPORT_SYMBOL(omap_rev);
+unsigned int omap_rev_id(void)
+{
+ return omap_revision_id;
+}
+EXPORT_SYMBOL(omap_rev_id);
+
/**
* omap_chip_is - test whether currently running OMAP matches a chip type
* @oc: omap_chip_t to test against
@@ -157,7 +164,6 @@
u32 cpuid, idcode;
u16 hawkeye;
u8 rev;
- char *rev_name = "ES1.0";
/*
* We cannot access revision registers on ES1.0.
@@ -180,7 +186,9 @@
hawkeye = (idcode >> 12) & 0xffff;
rev = (idcode >> 28) & 0xff;
- if (hawkeye == 0xb7ae) {
+ switch (hawkeye) {
+ case 0xb7ae:
+ /* Handle 34xx/35xx devices */
switch (rev) {
case 0:
omap_revision = OMAP3430_REV_ES2_0;
@@ -203,6 +211,21 @@
omap_revision = OMAP3430_REV_ES3_1;
rev_name = "Unknown revision\n";
}
+ break;
+ case 0xb891:
+ /* Handle 36xx devices */
+ switch (rev) {
+ case 0:
+ omap_revision = OMAP3630_REV_ES1_0;
+ break;
+ default:
+ /* Use the latest known revision as default */
+ omap_revision = OMAP3630_REV_ES1_0;
+ }
+ break;
+ default:
+ /* Unknown default to latest silicon rev as default*/
+ omap_revision = OMAP3630_REV_ES1_0;
}
out:
@@ -246,6 +269,8 @@
omap_chip.oc |= CHIP_IS_OMAP3430ES3_0;
else if (omap_rev() == OMAP3430_REV_ES3_1)
omap_chip.oc |= CHIP_IS_OMAP3430ES3_1;
+ else if (omap_rev() == OMAP3630_REV_ES1_0)
+ omap_chip.oc |= CHIP_IS_OMAP3630ES1;
} else {
pr_err("Uninitialized omap_chip, please fix!\n");
}
@@ -268,3 +293,74 @@
else
tap_prod_id = 0x0208;
}
+
+void __init omap_l2cache_enable(void)
+{
+ u32 l2_val;
+
+ asm volatile("mrc p15, 0, %0, c1, c0, 1":"=r" (l2_val));
+ if ((l2_val & 0x2) == 0) {
+ printk(KERN_WARNING "L2 CACHE is not enabled in bootloader\n"
+ "Enable the L2 Cache here\n");
+#ifndef CONFIG_L2CACHE_OMAP3_DISABLE
+ l2_val |= 0x2;
+ asm volatile("mcr p15, 0, %0, c1, c0, 1"::"r" (l2_val));
+#endif
+ } else
+ printk(KERN_WARNING "L2 CACHE is enabled in bootloader\n");
+}
+
+/*
+ * Get OMAP chip version details from bootargs
+ */
+int omap34xx_get_omap_version(char *str)
+{
+ unsigned int rev_id;
+ if (get_option(&str, &rev_id) == 1) {
+ switch (rev_id) {
+ case 3420:
+ omap_revision_id = OMAP_3420;
+ omap_revision = OMAP3430_REV_ES3_1;
+ omap_chip.oc |= CHIP_IS_OMAP3430ES3_1;
+ rev_name = "ES3.1";
+ break;
+ case 3430:
+ omap_revision_id = OMAP_3430;
+ omap_revision = OMAP3430_REV_ES3_1;
+ omap_chip.oc |= CHIP_IS_OMAP3430ES3_1;
+ rev_name = "ES3.1";
+ break;
+ case 3440:
+ omap_revision_id = OMAP_3440;
+ omap_revision = OMAP3430_REV_ES3_1_1;
+ omap_chip.oc |= CHIP_IS_OMAP3430ES3_1_1;
+ rev_name = "ES3.1.1";
+ break;
+ case 3630:
+ omap_revision_id = OMAP_3630;
+ omap_chip.oc |= CHIP_IS_OMAP3630ES1;
+ omap_revision = OMAP3630_REV_ES1_0;
+ break;
+ case 3630800:
+ omap_revision_id = OMAP_3630_800;
+ omap_chip.oc |= CHIP_IS_OMAP3630ES1;
+ omap_revision = OMAP3630_REV_ES1_0;
+ break;
+ case 36301000:
+ omap_revision_id = OMAP_3630_1000;
+ omap_chip.oc |= CHIP_IS_OMAP3630ES1;
+ omap_revision = OMAP3630_REV_ES1_0;
+ break;
+ default:
+ pr_err("OMAP revision unknown, please fix!\n");
+ return 1;
+ }
+ pr_info("OMAP%04x %s\n", omap_rev() >> 16, rev_name);
+ pr_info("OMAP Version is OMAP%04d\n", rev_id);
+ }
+
+ return 1;
+}
+
+__setup("omap_version=", omap34xx_get_omap_version);
+
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 1241d60..142d18e 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -175,6 +175,8 @@
void __init omap2_map_common_io(void)
{
+ omap_l2cache_enable();
+
#if defined(CONFIG_ARCH_OMAP2420)
iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc));
iotable_init(omap242x_io_desc, ARRAY_SIZE(omap242x_io_desc));
diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c
index 88a44f1..4a0e1cd 100644
--- a/arch/arm/mach-omap2/iommu2.c
+++ b/arch/arm/mach-omap2/iommu2.c
@@ -17,10 +17,7 @@
#include <linux/module.h>
#include <linux/stringify.h>
-#include <asm/io.h>
-
#include <mach/iommu.h>
-#include <mach/iommu2.h>
/*
* omap2 architecture specific register bit definitions
@@ -82,7 +79,7 @@
l = iommu_read_reg(obj, MMU_SYSSTATUS);
if (l & MMU_SYS_RESETDONE)
break;
- } while (time_after(jiffies, timeout));
+ } while (!time_after(jiffies, timeout));
if (!(l & MMU_SYS_RESETDONE)) {
dev_err(obj->dev, "can't take mmu out of reset\n");
@@ -220,10 +217,19 @@
}
#define pr_reg(name) \
- p += sprintf(p, "%20s: %08x\n", \
- __stringify(name), iommu_read_reg(obj, MMU_##name));
+ do { \
+ ssize_t bytes; \
+ const char *str = "%20s: %08x\n"; \
+ const int maxcol = 32; \
+ bytes = snprintf(p, maxcol, str, __stringify(name), \
+ iommu_read_reg(obj, MMU_##name)); \
+ p += bytes; \
+ len -= bytes; \
+ if (len < maxcol) \
+ goto out; \
+ } while (0)
-static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf)
+static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t len)
{
char *p = buf;
@@ -245,7 +251,7 @@
pr_reg(READ_CAM);
pr_reg(READ_RAM);
pr_reg(EMU_FAULT_AD);
-
+out:
return p - buf;
}
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 700fc3d..f349a96 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -192,6 +192,17 @@
return 0;
}
+void omap3_intc_autoidle(int enable)
+{
+ u32 read_val;
+
+ read_val = intc_bank_read_reg(&irq_banks[0], INTC_SYSCONFIG);
+ if (!enable)
+ read_val &= ~0x1;
+ else
+ read_val |= 0x1;
+ intc_bank_write_reg(read_val, &irq_banks[0], INTC_SYSCONFIG);
+}
void __init omap_init_irq(void)
{
@@ -272,4 +283,11 @@
}
/* MIRs are saved and restore with other PRCM registers */
}
+
+void omap3_intc_suspend(void)
+{
+ /* A pending interrupt would prevent OMAP from entering suspend */
+ omap_ack_irq(0);
+}
+
#endif /* CONFIG_ARCH_OMAP3 */
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
index a23fbb8..bc80a5a 100644
--- a/arch/arm/mach-omap2/mailbox.c
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -177,6 +177,9 @@
u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
mbox_write_reg(bit, p->irqstatus);
+
+ /* Flush posted writes to avoid spurious IRQ */
+ mbox_read_reg(p->irqstatus);
}
static int omap2_mbox_is_irq(struct omap_mbox *mbox,
diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/mmc-twl4030.c
index 898a805..9e6e089 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.c
+++ b/arch/arm/mach-omap2/mmc-twl4030.c
@@ -29,6 +29,7 @@
#endif
#include "mmc-twl4030.h"
+#include <mach/omap-pm.h>
#if defined(CONFIG_REGULATOR) && \
@@ -236,7 +237,7 @@
static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
int vdd)
{
- u32 reg;
+ u32 reg, prog_io;
int ret = 0;
struct twl_mmc_controller *c = &hsmmc[0];
struct omap_mmc_platform_data *mmc = dev->platform_data;
@@ -268,34 +269,38 @@
}
reg = omap_ctrl_readl(control_pbias_offset);
- reg |= OMAP2_PBIASSPEEDCTRL0;
+ if (cpu_is_omap3630()) {
+ /* Set MMC I/O to 52Mhz */
+ prog_io = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1);
+ prog_io |= OMAP3630_PRG_SDMMC1_SPEEDCTRL;
+ omap_ctrl_writel(prog_io, OMAP343X_CONTROL_PROG_IO1);
+ } else {
+ reg |= OMAP2_PBIASSPEEDCTRL0;
+ }
reg &= ~OMAP2_PBIASLITEPWRDNZ0;
omap_ctrl_writel(reg, control_pbias_offset);
- ret = mmc_regulator_set_ocr(c->vcc, vdd);
-
- /* 100ms delay required for PBIAS configuration */
- msleep(100);
reg = omap_ctrl_readl(control_pbias_offset);
- reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0);
if ((1 << vdd) <= MMC_VDD_165_195)
reg &= ~OMAP2_PBIASLITEVMODE0;
else
reg |= OMAP2_PBIASLITEVMODE0;
omap_ctrl_writel(reg, control_pbias_offset);
+
+ mmc_regulator_set_ocr(c->vcc, vdd);
+
+ /* 400uS required for VDDS to stable */
+ udelay(400);
+
+ reg = omap_ctrl_readl(control_pbias_offset);
+ reg |= OMAP2_PBIASLITEPWRDNZ0;
+ omap_ctrl_writel(reg, control_pbias_offset);
} else {
reg = omap_ctrl_readl(control_pbias_offset);
reg &= ~OMAP2_PBIASLITEPWRDNZ0;
omap_ctrl_writel(reg, control_pbias_offset);
ret = mmc_regulator_set_ocr(c->vcc, 0);
-
- /* 100ms delay required for PBIAS configuration */
- msleep(100);
- reg = omap_ctrl_readl(control_pbias_offset);
- reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 |
- OMAP2_PBIASLITEVMODE0);
- omap_ctrl_writel(reg, control_pbias_offset);
}
return ret;
@@ -413,6 +418,15 @@
mmc->dma_mask = 0xffffffff;
mmc->init = twl_mmc_late_init;
mmc->context_loss = get_last_off_on_transaction_id;
+ mmc->set_vdd1_opp = omap_pm_set_min_mpu_freq;
+ if (cpu_is_omap3630()) {
+ mmc->max_vdd1_opp = 600000000;
+ mmc->min_vdd1_opp = 150000000;
+ } else if (cpu_is_omap3430()) {
+ mmc->max_vdd1_opp = 500000000;
+ mmc->min_vdd1_opp = 125000000;
+ } else
+ mmc->set_vdd1_opp = NULL;
/* note: twl4030 card detect GPIOs can disable VMMCx ... */
if (gpio_is_valid(c->gpio_cd)) {
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 69bf44b..ada9895 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -526,6 +526,8 @@
OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT_PULLUP)
MUX_CFG_34XX("B24_34XX_GPIO101_OUT", 0x11A,
OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("B25_34XX_GPIO109", 0x12A,
+ OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
MUX_CFG_34XX("B26_34XX_GPIO111", 0x12e,
OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
MUX_CFG_34XX("AG4_34XX_GPIO134_OUT", 0x160,
@@ -549,7 +551,7 @@
MUX_CFG_34XX("AA21_34XX_GPIO157_OUT", 0x18e,
OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
MUX_CFG_34XX("W21_34XX_GPIO162", 0x198,
- OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT_PULLUP)
+ OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
MUX_CFG_34XX("H18_34XX_GPIO163", 0x19a,
OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT_PULLUP)
MUX_CFG_34XX("H19_34XX_GPIO164_OUT", 0x19c,
@@ -612,6 +614,14 @@
OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
MUX_CFG_34XX("AF4_3430_MMC2_DAT3", 0x162,
OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AE4_3430_MMC2_DAT4", 0x164,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AH3_3430_MMC2_DAT5", 0x166,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AF3_3430_MMC2_DAT6", 0x168,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AE3_3430_MMC2_DAT7", 0x16A,
+ OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
/* MMC3 */
MUX_CFG_34XX("AF10_3430_MMC3_CLK", 0x5d8,
@@ -738,6 +748,10 @@
MUX_CFG_34XX("AF26_34XX_SYS_NIRQ", 0x1E0,
OMAP3_WAKEUP_EN | OMAP34XX_PIN_INPUT_PULLUP |
OMAP34XX_MUX_MODE0)
+MUX_CFG_34XX("D25_34XX_GPIO126", 0x132,
+ OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("R8_34XX_GPIO56_TRISTATE", 0x0b8,
+ OMAP34XX_MUX_MODE7)
};
#define OMAP34XX_PINS_SZ ARRAY_SIZE(omap34xx_pins)
diff --git a/arch/arm/mach-omap2/omap3-iommu.c b/arch/arm/mach-omap2/omap3-iommu.c
index b732519..6abc217 100644
--- a/arch/arm/mach-omap2/omap3-iommu.c
+++ b/arch/arm/mach-omap2/omap3-iommu.c
@@ -11,71 +11,70 @@
*/
#include <linux/platform_device.h>
-#include <linux/io.h>
#include <mach/iommu.h>
-#define OMAP3_MMU1_BASE 0x480bd400
-#define OMAP3_MMU2_BASE 0x5d000000
-#define OMAP3_MMU1_IRQ 24
-#define OMAP3_MMU2_IRQ 28
-
-static struct resource omap3_iommu_res[] = {
- { /* Camera ISP MMU */
- .start = OMAP3_MMU1_BASE,
- .end = OMAP3_MMU1_BASE + MMU_REG_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = OMAP3_MMU1_IRQ,
- .flags = IORESOURCE_IRQ,
- },
- { /* IVA2.2 MMU */
- .start = OMAP3_MMU2_BASE,
- .end = OMAP3_MMU2_BASE + MMU_REG_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = OMAP3_MMU2_IRQ,
- .flags = IORESOURCE_IRQ,
- },
+struct iommu_device {
+ resource_size_t base;
+ int irq;
+ struct iommu_platform_data pdata;
+ struct resource res[2];
};
-#define NR_IOMMU_RES (ARRAY_SIZE(omap3_iommu_res) / 2)
-static const struct iommu_platform_data omap3_iommu_pdata[] __initconst = {
+static struct iommu_device devices[] = {
{
- .name = "isp",
- .nr_tlb_entries = 8,
- .clk_name = "cam_ick",
+ .base = 0x480bd400,
+ .irq = 24,
+ .pdata = {
+ .name = "isp",
+ .nr_tlb_entries = 8,
+ .clk_name = "cam_ick",
+ },
},
#if defined(CONFIG_MPU_BRIDGE_IOMMU)
{
- .name = "iva2",
- .nr_tlb_entries = 32,
- .clk_name = "iva2_ck",
+ .base = 0x5d000000,
+ .irq = 28,
+ .pdata = {
+ .name = "iva2",
+ .nr_tlb_entries = 32,
+ .clk_name = "iva2_ck",
+ },
},
#endif
};
-#define NR_IOMMU_DEVICES ARRAY_SIZE(omap3_iommu_pdata)
+#define NR_IOMMU_DEVICES ARRAY_SIZE(devices)
static struct platform_device *omap3_iommu_pdev[NR_IOMMU_DEVICES];
static int __init omap3_iommu_init(void)
{
int i, err;
+ struct resource res[] = {
+ { .flags = IORESOURCE_MEM },
+ { .flags = IORESOURCE_IRQ },
+ };
for (i = 0; i < NR_IOMMU_DEVICES; i++) {
struct platform_device *pdev;
+ const struct iommu_device *d = &devices[i];
- pdev = platform_device_alloc("omap-iommu", i + 1);
- if (!pdev)
+ pdev = platform_device_alloc("omap-iommu", i);
+ if (!pdev) {
+ err = -ENOMEM;
goto err_out;
- err = platform_device_add_resources(pdev,
- &omap3_iommu_res[2 * i], NR_IOMMU_RES);
+ }
+
+ res[0].start = d->base;
+ res[0].end = d->base + MMU_REG_SIZE - 1;
+ res[1].start = res[1].end = d->irq;
+
+ err = platform_device_add_resources(pdev, res,
+ ARRAY_SIZE(res));
if (err)
goto err_out;
- err = platform_device_add_data(pdev, &omap3_iommu_pdata[i],
- sizeof(omap3_iommu_pdata[0]));
+ err = platform_device_add_data(pdev, &d->pdata,
+ sizeof(d->pdata));
if (err)
goto err_out;
err = platform_device_add(pdev);
diff --git a/arch/arm/mach-omap2/omap3-opp.h b/arch/arm/mach-omap2/omap3-opp.h
index 3c9a582..5046a51 100644
--- a/arch/arm/mach-omap2/omap3-opp.h
+++ b/arch/arm/mach-omap2/omap3-opp.h
@@ -4,22 +4,70 @@
#include <mach/omap-pm.h>
/* MPU speeds */
+#define S1000M 1000000000
+#define S800M 800000000
+#define S720M 720000000
#define S600M 600000000
#define S550M 550000000
+#define S520M 520000000
#define S500M 500000000
+#define S300M 300000000
#define S250M 250000000
+#define S150M 150000000
#define S125M 125000000
/* DSP speeds */
+#define S875M 875000000
+#define S760M 760000000
+#define S660M 660000000
+#define S520M 520000000
#define S430M 430000000
#define S400M 400000000
#define S360M 360000000
+#define S260M 260000000
#define S180M 180000000
+#define S130M 130000000
#define S90M 90000000
/* L3 speeds */
+#define S50M 50000000
#define S83M 83000000
+#define S100M 100000000
#define S166M 166000000
+#define S200M 200000000
+
+static struct omap_opp omap3630_mpu_rate_table[] = {
+ {0, 0, 0},
+ /*OPP1 (OPP50) - 0.93mV*/
+ {S300M, VDD1_OPP1, 0x1b},
+ /*OPP2 (OPP100) - 1.1V*/
+ {S600M, VDD1_OPP2, 0x28},
+ /*OPP3 (OPP130) - 1.26V*/
+ {S800M, VDD1_OPP3, 0x35},
+ /*OPP4 (OPP-1G) - 1.35V*/
+ {S1000M, VDD1_OPP4, 0x3C},
+
+};
+
+static struct omap_opp omap3630_l3_rate_table[] = {
+ {0, 0, 0},
+ /*OPP1 (OPP50) - 0.93V*/
+ {S100M, VDD2_OPP1, 0x1b},
+ /*OPP2 (OPP100) - 1.1375V*/
+ {S200M, VDD2_OPP2, 0x2b},
+};
+
+static struct omap_opp omap3630_dsp_rate_table[] = {
+ {0, 0, 0},
+ /*OPP1 (OPP50) - 0.93V*/
+ {S260M, VDD1_OPP1, 0x1b},
+ /*OPP2 (OPP100) - 1.1V*/
+ {S520M, VDD1_OPP2, 0x28},
+ /*OPP3 (OPP130) - 1.26V*/
+ {S660M, VDD1_OPP3, 0x35},
+ /*OPP4 (OPP-1G) - 1.35V*/
+ {S800M, VDD1_OPP4, 0x3C},
+};
static struct omap_opp omap3_mpu_rate_table[] = {
{0, 0, 0},
@@ -33,6 +81,8 @@
{S550M, VDD1_OPP4, 0x36},
/*OPP5*/
{S600M, VDD1_OPP5, 0x3C},
+ /*OPP6*/
+ {S720M, VDD1_OPP6, 0x3C},
};
static struct omap_opp omap3_l3_rate_table[] = {
@@ -45,6 +95,22 @@
{S166M, VDD2_OPP3, 0x2C},
};
+/* iva rate table for 3420 */
+static struct omap_opp omap3_dsp_rate_table_3420[] = {
+ {0, 0, 0},
+ /*OPP1*/
+ {S90M, VDD1_OPP1, 0x1E},
+ /*OPP2*/
+ {S180M, VDD1_OPP2, 0x26},
+ /*OPP3*/
+ {S360M, VDD1_OPP3, 0x30},
+ /*OPP4*/
+ {S360M, VDD1_OPP4, 0x36},
+ /*OPP5*/
+ {S360M, VDD1_OPP5, 0x36},
+};
+
+/* iva rate table for 3430 */
static struct omap_opp omap3_dsp_rate_table[] = {
{0, 0, 0},
/*OPP1*/
@@ -54,9 +120,26 @@
/*OPP3*/
{S360M, VDD1_OPP3, 0x30},
/*OPP4*/
- {S400M, VDD1_OPP4, 0x36},
+ {S430M, VDD1_OPP4, 0x36},
/*OPP5*/
{S430M, VDD1_OPP5, 0x3C},
};
+/* iva rate table for 3430 */
+static struct omap_opp omap3_dsp_rate_table_3440[] = {
+ {0, 0, 0},
+ /*OPP1*/
+ {S90M, VDD1_OPP1, 0x1E},
+ /*OPP2*/
+ {S180M, VDD1_OPP2, 0x26},
+ /*OPP3*/
+ {S360M, VDD1_OPP3, 0x30},
+ /*OPP4*/
+ {S430M, VDD1_OPP4, 0x36},
+ /*OPP5*/
+ {S430M, VDD1_OPP5, 0x3C},
+ /*OPP6*/
+ {S520M, VDD1_OPP6, 0x3C},
+};
+
#endif
diff --git a/arch/arm/mach-omap2/omapdev-common.h b/arch/arm/mach-omap2/omapdev-common.h
index a2d4855..e5233f5 100644
--- a/arch/arm/mach-omap2/omapdev-common.h
+++ b/arch/arm/mach-omap2/omapdev-common.h
@@ -204,6 +204,7 @@
&modem_intc_3xxx_omapdev,
&sms_3xxx_omapdev,
&gpmc_3xxx_omapdev,
+ &nand_3xxx_omapdev,
&sdrc_3xxx_omapdev,
&ocm_ram_3xxx_omapdev,
&ocm_rom_3xxx_omapdev,
diff --git a/arch/arm/mach-omap2/omapdev3xxx.h b/arch/arm/mach-omap2/omapdev3xxx.h
index f6970d8..0c77ce4 100644
--- a/arch/arm/mach-omap2/omapdev3xxx.h
+++ b/arch/arm/mach-omap2/omapdev3xxx.h
@@ -105,6 +105,14 @@
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
+static struct omapdev nand_3xxx_omapdev = {
+ .name = "nand_omapdev",
+ .pwrdm = { .name = "core_pwrdm" },
+ .pdev_name = "omap2-nand",
+ .pdev_id = 0,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
static struct omapdev sdrc_3xxx_omapdev = {
.name = "sdrc_omapdev",
.pwrdm = { .name = "core_pwrdm" },
@@ -663,7 +671,7 @@
static struct omapdev usbotg_3xxx_omapdev = {
.name = "usbotg_omapdev",
- .pwrdm = { .name = "usbhost_pwrdm" },
+ .pwrdm = { .name = "core_pwrdm" },
.pdev_name = "musb_hdrc",
.pdev_id = -1,
.omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2),
@@ -682,7 +690,7 @@
static struct omapdev dsi_3xxx_omapdev = {
.name = "dsi_omapdev",
.pwrdm = { .name = "dss_pwrdm" },
- .pdev_name = "omapfb",
+ .pdev_name = "omapdss",
.pdev_id = -1,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
@@ -690,7 +698,7 @@
static struct omapdev dsi_phy_3xxx_omapdev = {
.name = "dsi_phy_omapdev",
.pwrdm = { .name = "dss_pwrdm" },
- .pdev_name = "omapfb",
+ .pdev_name = "omapdss",
.pdev_id = -1,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
@@ -698,7 +706,7 @@
static struct omapdev dsi_pll_3xxx_omapdev = {
.name = "dsi_pll_omapdev",
.pwrdm = { .name = "dss_pwrdm" },
- .pdev_name = "omapfb",
+ .pdev_name = "omapdss",
.pdev_id = -1,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
@@ -706,7 +714,7 @@
static struct omapdev dss_3xxx_omapdev = {
.name = "dss_omapdev",
.pwrdm = { .name = "dss_pwrdm" },
- .pdev_name = "omapfb",
+ .pdev_name = "omapdss",
.pdev_id = -1,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
@@ -714,7 +722,7 @@
static struct omapdev dispc_3xxx_omapdev = {
.name = "dispc_omapdev",
.pwrdm = { .name = "dss_pwrdm" },
- .pdev_name = "omapfb",
+ .pdev_name = "omapdss",
.pdev_id = -1,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
@@ -722,7 +730,7 @@
static struct omapdev rfbi_3xxx_omapdev = {
.name = "rfbi_omapdev",
.pwrdm = { .name = "dss_pwrdm" },
- .pdev_name = "omapfb",
+ .pdev_name = "omapdss",
.pdev_id = -1,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
@@ -730,7 +738,7 @@
static struct omapdev venc_3xxx_omapdev = {
.name = "venc_omapdev",
.pwrdm = { .name = "dss_pwrdm" },
- .pdev_name = "omapfb",
+ .pdev_name = "omapdss",
.pdev_id = -1,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index 993498b..3797b2a 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -382,6 +382,9 @@
for (i = 0; i < 4; i++)
seq_printf(s, ",%s:%d", pwrdm_state_names[i],
pwrdm->state_counter[i]);
+ seq_printf(s, ",RET-LOGIC-OFF:%d,RET-MEM-OFF:%d",
+ pwrdm->ret_logic_off_counter,
+ pwrdm->ret_mem_off_counter);
seq_printf(s, "\n");
@@ -539,7 +542,7 @@
(void) debugfs_create_file("time", S_IRUGO,
d, (void *)DEBUG_FILE_TIMERS, &debug_fops);
- pwrdm_for_each(pwrdms_setup, (void *)d);
+ pwrdm_for_each_nolock(pwrdms_setup, (void *)d);
pm_dbg_dir = debugfs_create_dir("registers", d);
if (IS_ERR(pm_dbg_dir))
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index d07b722..b2d6638 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -37,17 +37,23 @@
#include "prm-regbits-34xx.h"
#include "pm.h"
+#include <mach/omap-pm.h>
unsigned short enable_dyn_sleep;
unsigned short enable_off_mode;
EXPORT_SYMBOL(enable_off_mode);
+unsigned short enable_oswr_ret;
+EXPORT_SYMBOL(enable_oswr_ret);
unsigned short voltage_off_while_idle;
unsigned short wakeup_timer_seconds;
+unsigned long max_dsp_frequency;
atomic_t sleep_block = ATOMIC_INIT(0);
static ssize_t idle_show(struct kobject *, struct kobj_attribute *, char *);
static ssize_t idle_store(struct kobject *k, struct kobj_attribute *,
const char *buf, size_t n);
+static ssize_t vdd_max_dsp_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf);
static struct kobj_attribute sleep_while_idle_attr =
__ATTR(sleep_while_idle, 0644, idle_show, idle_store);
@@ -55,23 +61,30 @@
static struct kobj_attribute enable_off_mode_attr =
__ATTR(enable_off_mode, 0644, idle_show, idle_store);
+static struct kobj_attribute enable_oswr_ret_attr =
+ __ATTR(enable_oswr_ret, 0644, idle_show, idle_store);
+
static struct kobj_attribute voltage_off_while_idle_attr =
__ATTR(voltage_off_while_idle, 0644, idle_show, idle_store);
+static struct kobj_attribute max_dsp_frequency_attr =
+ __ATTR(max_dsp_frequency, 0644, vdd_max_dsp_show, NULL);
#ifdef CONFIG_OMAP_PM_SRF
static ssize_t vdd_opp_show(struct kobject *, struct kobj_attribute *, char *);
static ssize_t vdd_opp_store(struct kobject *k, struct kobj_attribute *,
const char *buf, size_t n);
+static ssize_t vdd_opp_lock_store(struct kobject *k, struct kobj_attribute *,
+ const char *buf, size_t n);
+
static struct kobj_attribute vdd1_opp_attr =
__ATTR(vdd1_opp, 0644, vdd_opp_show, vdd_opp_store);
static struct kobj_attribute vdd2_opp_attr =
__ATTR(vdd2_opp, 0644, vdd_opp_show, vdd_opp_store);
static struct kobj_attribute vdd1_lock_attr =
- __ATTR(vdd1_lock, 0644, vdd_opp_show, vdd_opp_store);
+ __ATTR(vdd1_lock, 0644, vdd_opp_show, vdd_opp_lock_store);
static struct kobj_attribute vdd2_lock_attr =
- __ATTR(vdd2_lock, 0644, vdd_opp_show, vdd_opp_store);
-
+ __ATTR(vdd2_lock, 0644, vdd_opp_show, vdd_opp_lock_store);
#endif
static struct kobj_attribute wakeup_timer_seconds_attr =
@@ -84,6 +97,8 @@
return sprintf(buf, "%hu\n", enable_dyn_sleep);
else if (attr == &enable_off_mode_attr)
return sprintf(buf, "%hu\n", enable_off_mode);
+ else if (attr == &enable_oswr_ret_attr)
+ return sprintf(buf, "%hu\n", enable_oswr_ret);
else if (attr == &voltage_off_while_idle_attr)
return sprintf(buf, "%hu\n", voltage_off_while_idle);
else if (attr == &wakeup_timer_seconds_attr)
@@ -107,6 +122,8 @@
} else if (attr == &enable_off_mode_attr) {
enable_off_mode = value;
omap3_pm_off_mode_enable(enable_off_mode);
+ } else if (attr == &enable_oswr_ret_attr) {
+ enable_oswr_ret = value;
} else if (attr == &wakeup_timer_seconds_attr) {
wakeup_timer_seconds = value;
} else if (attr == &voltage_off_while_idle_attr) {
@@ -128,18 +145,19 @@
#include <mach/omap34xx.h>
static int vdd1_locked;
static int vdd2_locked;
+static struct device sysfs_cpufreq_dev;
static ssize_t vdd_opp_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
if (attr == &vdd1_opp_attr)
- return sprintf(buf, "%hu\n", resource_get_level("vdd1_opp"));
+ return sprintf(buf, "%u\n", resource_get_level("vdd1_opp"));
else if (attr == &vdd2_opp_attr)
- return sprintf(buf, "%hu\n", resource_get_level("vdd2_opp"));
+ return sprintf(buf, "%u\n", resource_get_level("vdd2_opp"));
else if (attr == &vdd1_lock_attr)
- return sprintf(buf, "%hu\n", resource_get_opp_lock(VDD1_OPP));
+ return sprintf(buf, "%u\n", resource_get_opp_lock(VDD1_OPP));
else if (attr == &vdd2_lock_attr)
- return sprintf(buf, "%hu\n", resource_get_opp_lock(VDD2_OPP));
+ return sprintf(buf, "%u\n", resource_get_opp_lock(VDD2_OPP));
else
return -EINVAL;
}
@@ -148,6 +166,42 @@
const char *buf, size_t n)
{
unsigned short value;
+ struct omap_opp *opp_table;
+
+ if (sscanf(buf, "%hu", &value) != 1)
+ return -EINVAL;
+
+ if (attr == &vdd1_opp_attr) {
+ if (value < MIN_VDD1_OPP || value > MAX_VDD1_OPP) {
+ printk(KERN_ERR "vdd_opp_store: Invalid value\n");
+ return -EINVAL;
+ }
+ opp_table = omap_get_mpu_rate_table();
+ omap_pm_set_min_mpu_freq(&sysfs_cpufreq_dev,
+ opp_table[value].rate);
+ } else if (attr == &vdd2_opp_attr) {
+ if (value < MIN_VDD2_OPP || (value > MAX_VDD2_OPP)) {
+ printk(KERN_ERR "vdd_opp_store: Invalid value\n");
+ return -EINVAL;
+ }
+ if (value == VDD2_OPP2)
+ omap_pm_set_min_bus_tput(&sysfs_cpufreq_dev,
+ OCP_INITIATOR_AGENT, 83*1000*4);
+ else if (value == VDD2_OPP3)
+ omap_pm_set_min_bus_tput(&sysfs_cpufreq_dev,
+ OCP_INITIATOR_AGENT, 166*1000*4);
+
+ } else {
+ return -EINVAL;
+ }
+ return n;
+}
+
+
+static ssize_t vdd_opp_lock_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t n)
+{
+ unsigned short value;
int flags = 0;
if (sscanf(buf, "%hu", &value) != 1)
@@ -166,6 +220,11 @@
if (vdd1_locked == 0 && value != 0) {
resource_lock_opp(VDD1_OPP);
vdd1_locked = 1;
+ if (value < MIN_VDD1_OPP || value > MAX_VDD1_OPP) {
+ printk(KERN_ERR "vdd_opp_store: Invalid value\n");
+ return -EINVAL;
+ }
+ resource_set_opp_level(VDD1_OPP, value, flags);
}
} else if (attr == &vdd2_lock_attr) {
flags = OPP_IGNORE_LOCK;
@@ -179,26 +238,27 @@
if (vdd2_locked == 0 && value != 0) {
resource_lock_opp(VDD2_OPP);
vdd2_locked = 1;
+ if (value < MIN_VDD2_OPP || value > MAX_VDD2_OPP) {
+ printk(KERN_ERR "vdd_opp_store: Invalid value\n");
+ return -EINVAL;
+ }
+ resource_set_opp_level(VDD2_OPP, value, flags);
}
- }
-
- if (attr == &vdd1_opp_attr) {
- if (value < 1 || value > 5) {
- printk(KERN_ERR "vdd_opp_store: Invalid value\n");
- return -EINVAL;
- }
- resource_set_opp_level(VDD1_OPP, value, flags);
- } else if (attr == &vdd2_opp_attr) {
- if (value < 1 || value > 3) {
- printk(KERN_ERR "vdd_opp_store: Invalid value\n");
- return -EINVAL;
- }
- resource_set_opp_level(VDD2_OPP, value, flags);
- } else {
+ } else {
return -EINVAL;
}
return n;
}
+
+static ssize_t vdd_max_dsp_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct omap_opp *dsp_rate;
+ if (attr == &max_dsp_frequency_attr) {
+ dsp_rate = omap_get_dsp_rate_table();
+ return sprintf(buf, "%ld\n", dsp_rate[MAX_VDD1_OPP].rate);
+ }
+}
#endif
void omap2_block_sleep(void)
@@ -254,9 +314,21 @@
return error;
}
error = sysfs_create_file(power_kobj,
+ &enable_oswr_ret_attr.attr);
+ if (error) {
+ printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+ return error;
+ }
+ error = sysfs_create_file(power_kobj,
&wakeup_timer_seconds_attr.attr);
if (error)
printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+
+ error = sysfs_create_file(power_kobj,
+ &max_dsp_frequency_attr.attr);
+ if (error)
+ printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+
#ifdef CONFIG_OMAP_PM_SRF
error = sysfs_create_file(power_kobj,
&vdd1_opp_attr.attr);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 9e112b3..53d5666 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -25,6 +25,7 @@
extern unsigned short enable_dyn_sleep;
extern unsigned short enable_off_mode;
+extern unsigned short enable_oswr_ret;
extern unsigned short voltage_off_while_idle;
extern atomic_t sleep_block;
extern void *omap3_secure_ram_storage;
@@ -33,12 +34,18 @@
extern struct omap_dm_timer *gptimer_wakeup;
#ifdef CONFIG_ARCH_OMAP3
-struct prm_setup_vc {
+struct prm_setup_times_vc {
u16 clksetup;
u16 voltsetup_time1;
u16 voltsetup_time2;
- u16 voltoffset;
u16 voltsetup2;
+ u16 voltsetup1;
+};
+
+struct prm_setup_vc {
+ struct prm_setup_times_vc *setup_times;
+ struct prm_setup_times_vc *setup_times_off;
+ u16 voltoffset;
/* PRM_VC_CMD_VAL_0 specific bits */
u16 vdd0_on;
u16 vdd0_onlp;
@@ -56,7 +63,6 @@
u32 vdd_ch_conf;
u32 vdd_i2c_cfg;
};
-
extern void omap3_pm_off_mode_enable(int);
extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm);
extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state);
@@ -107,6 +113,7 @@
static inline void omap2_allow_sleep(void) { }
#endif
+extern void omap3_cpuidle_update_states(void);
extern unsigned int omap24xx_idle_loop_suspend_sz;
extern unsigned int omap34xx_suspend_sz;
extern unsigned int save_secure_ram_context_sz;
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 1ca6815..156c8d7 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -27,8 +27,10 @@
#include <linux/list.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/reboot.h>
#include <mach/gpio.h>
+#include <mach/cpu.h>
#include <mach/sram.h>
#include <mach/prcm.h>
#include <mach/clockdomain.h>
@@ -43,6 +45,7 @@
#include <mach/gpmc.h>
#include <mach/dma.h>
#include <mach/dmtimer.h>
+#include <mach/usb.h>
#include <asm/tlbflush.h>
@@ -56,14 +59,21 @@
#include "pm.h"
#include "smartreflex.h"
#include "sdrc.h"
+#include <mach/omap-pm.h>
+#include "../vfp/vfp.h"
static int regset_save_on_suspend;
+/* Function pointer need to be called from idle and suspend/resume path */
+static int (*core_off_notification)(bool);
+
/* Scratchpad offsets */
#define OMAP343X_TABLE_ADDRESS_OFFSET 0x31
#define OMAP343X_TABLE_VALUE_OFFSET 0x30
#define OMAP343X_CONTROL_REG_VALUE_OFFSET 0x32
+#define VP_TRANXDONE_TIMEOUT 62
+
struct power_state {
struct powerdomain *pwrdm;
u32 next_state;
@@ -81,14 +91,19 @@
static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
static struct powerdomain *core_pwrdm, *per_pwrdm;
-static struct powerdomain *cam_pwrdm;
+static struct powerdomain *wkup_pwrdm;
-static struct prm_setup_vc prm_setup = {
+static struct prm_setup_times_vc prm_setup_times_default = {
.clksetup = 0xff,
.voltsetup_time1 = 0xfff,
.voltsetup_time2 = 0xfff,
- .voltoffset = 0xff,
.voltsetup2 = 0xff,
+};
+
+static struct prm_setup_vc prm_setup_default = {
+ .setup_times = &prm_setup_times_default,
+ .setup_times_off = NULL,
+ .voltoffset = 0xff,
.vdd0_on = 0x30,
.vdd0_onlp = 0x1e,
.vdd0_ret = 0x1e,
@@ -105,14 +120,26 @@
.vdd_cmd_ra = (R_VDD2_SR_CONTROL << OMAP3430_VOLRA1_SHIFT) |
(R_VDD1_SR_CONTROL << OMAP3430_VOLRA0_SHIFT),
.vdd_ch_conf = OMAP3430_CMD1 | OMAP3430_RAV1,
- .vdd_i2c_cfg = OMAP3430_MCODE_SHIFT | OMAP3430_HSEN | OMAP3430_SREN,
+ .vdd_i2c_cfg = OMAP3430_MCODE_SHIFT | OMAP3430_HSEN ,
};
+static struct prm_setup_vc *prm_setup = &prm_setup_default;
+
static inline void omap3_per_save_context(void)
{
omap3_gpio_save_context();
}
+static void prm_program_setup_times(struct prm_setup_times_vc *times)
+{
+ prm_write_mod_reg(times->voltsetup1, OMAP3430_GR_MOD,
+ OMAP3_PRM_VOLTSETUP1_OFFSET);
+ prm_write_mod_reg(times->voltsetup2, OMAP3430_GR_MOD,
+ OMAP3_PRM_VOLTSETUP2_OFFSET);
+ prm_write_mod_reg(times->clksetup, OMAP3430_GR_MOD,
+ OMAP3_PRM_CLKSETUP_OFFSET);
+}
+
static inline void omap3_per_restore_context(void)
{
omap3_gpio_restore_context();
@@ -147,31 +174,48 @@
prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN);
}
-static void omap3_core_save_context(void)
+static void omap3_core_save_context(int core_state)
{
- u32 control_padconf_off;
- /* Save the padconf registers */
- control_padconf_off =
- omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_OFF);
- control_padconf_off |= START_PADCONF_SAVE;
- omap_ctrl_writel(control_padconf_off, OMAP343X_CONTROL_PADCONF_OFF);
- /* wait for the save to complete */
- while (!omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS)
- & PADCONF_SAVE_DONE)
- ;
+ if (core_state == PWRDM_POWER_OFF) {
+ u32 control_padconf_off;
+ /* Save the padconf registers */
+ control_padconf_off =
+ omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_OFF);
+ control_padconf_off |= START_PADCONF_SAVE;
+ omap_ctrl_writel(control_padconf_off,
+ OMAP343X_CONTROL_PADCONF_OFF);
+ /* Due to Silicon Bug on context restore it is found
+ * that the CONTROL_PAD_CONF_ETK14 register is not saved into
+ * scratch pad memory sometimes. To rectify it delay acess by Mpu
+ * for 300us for scm to finish saving task
+ */
+ udelay(300);
+ /* wait for the save to complete */
+ while (!(omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS)
+ & PADCONF_SAVE_DONE))
+ ;
+ /* Save the system control module context,
+ * padconf already save above
+ */
+ omap3_control_save_context();
+ }
+
/* Save the Interrupt controller context */
omap3_intc_save_context();
/* Save the GPMC context */
omap3_gpmc_save_context();
- /* Save the system control module context, padconf already save above*/
- omap3_control_save_context();
omap_dma_global_context_save();
}
-static void omap3_core_restore_context(void)
+static void omap3_core_restore_context(int core_state)
{
- /* Restore the control module context, padconf restored by h/w */
- omap3_control_restore_context();
+ if (core_state == PWRDM_POWER_OFF)
+
+ /* Restore the control module context,
+ * padconf restored by h/w
+ */
+ omap3_control_restore_context();
+
/* Restore the GPMC context */
omap3_gpmc_restore_context();
/* Restore the interrupt controller context */
@@ -219,7 +263,7 @@
* that any peripheral wake-up events occurring while attempting to
* clear the PM_WKST_x are detected and cleared.
*/
-static void prcm_clear_mod_irqs(s16 module, u8 regs)
+static int prcm_clear_mod_irqs(s16 module, u8 regs)
{
u32 wkst, fclk, iclk, clken;
u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
@@ -227,6 +271,7 @@
u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
u16 grpsel_off = (regs == 3) ?
OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
+ int c = 0;
wkst = prm_read_mod_reg(module, wkst_off);
wkst &= prm_read_mod_reg(module, grpsel_off);
@@ -245,11 +290,27 @@
cm_set_mod_reg_bits(clken, module, fclk_off);
prm_write_mod_reg(wkst, module, wkst_off);
wkst = prm_read_mod_reg(module, wkst_off);
+ c++;
}
cm_write_mod_reg(iclk, module, iclk_off);
cm_write_mod_reg(fclk, module, fclk_off);
}
+ return c;
}
+static int _prcm_int_handle_wakeup(void)
+{
+ int c;
+
+ c = prcm_clear_mod_irqs(WKUP_MOD, 1);
+ c += prcm_clear_mod_irqs(CORE_MOD, 1);
+ c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
+ c += prcm_clear_mod_irqs(CORE_MOD, 3);
+ c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
+ }
+
+ return c;
+ }
/*
* PRCM Interrupt Handler
@@ -271,18 +332,36 @@
static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
{
u32 irqstatus_mpu;
+ int c = 0;
do {
- prcm_clear_mod_irqs(WKUP_MOD, 1);
- prcm_clear_mod_irqs(CORE_MOD, 1);
- prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
- if (omap_rev() > OMAP3430_REV_ES1_0) {
- prcm_clear_mod_irqs(CORE_MOD, 3);
- prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
- }
-
irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+ if (irqstatus_mpu & (OMAP3430_WKUP_ST | OMAP3430_IO_ST)) {
+ c = _prcm_int_handle_wakeup();
+
+ /*
+ * Is the MPU PRCM interrupt handler racing with the
+ * IVA2 PRCM interrupt handler ?
+ */
+ WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup "
+ "but no wakeup sources are marked\n");
+ } else if (irqstatus_mpu & (OMAP3430_VP1_ST | OMAP3430_VP2_ST |
+ OMAP3430_VC_ST)) {
+ /* Clear all the VP1/2 and VC status flag here */
+ prm_write_mod_reg((irqstatus_mpu &
+ (OMAP3430_VP1_ST |
+ OMAP3430_VP2_ST |
+ OMAP3430_VC_ST)), OCP_MOD,
+ OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+
+ } else {
+
+ /* XXX we need to expand our PRCM interrupt handler */
+ WARN(1, "prcm: WARNING: PRCM interrupt received, but "
+ "no code to handle it (%08x)\n", irqstatus_mpu);
+ }
+
prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
@@ -330,9 +409,9 @@
int mpu_next_state = PWRDM_POWER_ON;
int per_next_state = PWRDM_POWER_ON;
int core_next_state = PWRDM_POWER_ON;
- int core_prev_state, per_prev_state;
+ int mpu_prev_state, core_prev_state, per_prev_state;
+ int mpu_logic_state, mpu_mem_state, core_logic_state, core_mem_state;
u32 sdrc_pwr = 0;
- int per_state_modified = 0;
if (!_omap_sram_idle)
return;
@@ -343,12 +422,26 @@
pwrdm_clear_all_prev_pwrst(per_pwrdm);
mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
+ mpu_logic_state = pwrdm_read_next_logic_pwrst(mpu_pwrdm);
+ mpu_mem_state = pwrdm_read_next_mem_pwrst(mpu_pwrdm, 0);
+
switch (mpu_next_state) {
+ case PWRDM_POWER_INACTIVE:
case PWRDM_POWER_ON:
- case PWRDM_POWER_RET:
/* No need to save context */
save_state = 0;
break;
+ case PWRDM_POWER_RET:
+ if (!mpu_logic_state && !mpu_mem_state)
+ save_state = 3;
+ else if (!mpu_mem_state)
+ save_state = 2;
+ else if (!mpu_logic_state)
+ save_state = 1;
+ else
+ /* No need to save context */
+ save_state = 0;
+ break;
case PWRDM_POWER_OFF:
save_state = 3;
break;
@@ -361,46 +454,85 @@
pwrdm_pre_transition();
/* NEON control */
- if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
+ if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) {
+ if (mpu_next_state == PWRDM_POWER_OFF)
+ vfp_pm_save_context();
pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state);
+ }
/* PER */
per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
- if (per_next_state < PWRDM_POWER_ON) {
- omap_uart_prepare_idle(2);
- omap2_gpio_prepare_for_idle(per_next_state);
- if (per_next_state == PWRDM_POWER_OFF) {
- if (core_next_state == PWRDM_POWER_ON) {
- per_next_state = PWRDM_POWER_RET;
- pwrdm_set_next_pwrst(per_pwrdm, per_next_state);
- per_state_modified = 1;
- } else
- omap3_per_save_context();
- }
- }
+ core_logic_state = pwrdm_read_next_logic_pwrst(core_pwrdm);
+ core_mem_state = pwrdm_read_next_mem_pwrst(core_pwrdm, 0) |
+ pwrdm_read_next_mem_pwrst(core_pwrdm, 1);
- if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON)
- omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]);
+ if (per_next_state < PWRDM_POWER_ON) {
+ omap_uart_prepare_idle(2, per_next_state);
+ omap2_gpio_prepare_for_idle(per_next_state);
+ if (per_next_state == PWRDM_POWER_OFF)
+ omap3_per_save_context();
+ } else
+ omap_uart_prepare_idle(2, per_next_state);
+
/* CORE */
if (core_next_state < PWRDM_POWER_ON) {
/* Disable smartreflex before entering WFI */
disable_smartreflex(SR1);
disable_smartreflex(SR2);
- omap_uart_prepare_idle(0);
- omap_uart_prepare_idle(1);
+ omap_uart_prepare_idle(0, core_next_state & core_logic_state);
+ omap_uart_prepare_idle(1, core_next_state & core_logic_state);
if (core_next_state == PWRDM_POWER_OFF) {
prm_set_mod_reg_bits(OMAP3430_AUTO_OFF,
OMAP3430_GR_MOD,
OMAP3_PRM_VOLTCTRL_OFFSET);
- omap3_core_save_context();
+ omap3_core_save_context(PWRDM_POWER_OFF);
omap3_prcm_save_context();
- }
+ if (core_off_notification != NULL)
+ core_off_notification(PRCM_ENTER_OFF);
+ } else if ((core_next_state == PWRDM_POWER_RET) &&
+ (core_logic_state == PWRDM_POWER_OFF) &&
+ (core_mem_state == PWRDM_POWER_OFF)) {
+ omap3_core_save_context(PWRDM_POWER_RET);
+ omap3_prcm_save_context();
+ if (prm_setup->setup_times_off != NULL)
+ prm_program_setup_times(
+ prm_setup->setup_times_off);
+ /*
+ * This is a hack. Currently OSWR does not
+ * work if rom code restores DPLL4 to non
+ * auto idle mode.
+ * ROM restore takes 20mS longer if PER/DPLL4
+ * idle is enabled before OFF.So it is typically
+ * not enabled. Since OSWR hangs if it is not enabled
+ * enable it for OSWR alone. Later in the restore path
+ * it is disabled again
+ */
+
+ omap3_scratchpad_dpll4autoidle(1);
+ prm_set_mod_reg_bits(OMAP3430_AUTO_RET,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VOLTCTRL_OFFSET);
+ } else if (core_next_state == PWRDM_POWER_RET) {
+ prm_set_mod_reg_bits(OMAP3430_AUTO_RET,
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VOLTCTRL_OFFSET);
+ }
+
/* Enable IO-PAD and IO-CHAIN wakeups */
prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
omap3_enable_io_chain();
+ } else {
+ omap_uart_prepare_idle(0, core_next_state & core_logic_state);
+ omap_uart_prepare_idle(1, core_next_state & core_logic_state);
}
+ /*
+ * Disable INTC autoidle as it can cause interrupt controller
+ * to enter unknown state with right combination of sleep / wakeup
+ * transitions
+ */
+ omap3_intc_autoidle(0);
/*
* On EMU/HS devices ROM code restores a SRDC value
@@ -430,47 +562,85 @@
core_next_state == PWRDM_POWER_OFF)
sdrc_write_reg(sdrc_pwr, SDRC_POWER);
- /* Restore table entry modified during MMU restoration */
- if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF)
- restore_table_entry();
+ mpu_prev_state = pwrdm_read_prev_pwrst(mpu_pwrdm);
+ /* Restore table entry modified during MMU restoration */
+ if (((mpu_prev_state == PWRDM_POWER_RET) &&
+ (pwrdm_read_prev_logic_pwrst(mpu_pwrdm) ==
+ PWRDM_POWER_OFF)) ||
+ (mpu_prev_state == PWRDM_POWER_OFF))
+ restore_table_entry();
/* CORE */
if (core_next_state < PWRDM_POWER_ON) {
core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm);
- if (core_prev_state == PWRDM_POWER_OFF) {
- omap3_core_restore_context();
+ if ((core_prev_state == PWRDM_POWER_OFF) ||
+ (core_prev_state == PWRDM_POWER_RET &&
+ pwrdm_read_prev_logic_pwrst(core_pwrdm) ==
+ PWRDM_POWER_OFF)) {
+ omap3_core_restore_context(core_prev_state);
omap3_prcm_restore_context();
omap3_sram_restore_context();
omap2_sms_restore_context();
+
+ if (core_off_notification != NULL)
+ core_off_notification(PRCM_EXIT_OFF);
+ /*
+ * For OSWR to work we put PER DPLL in auto
+ * idle mode in scratchpad. Clear it so that
+ * next time if a OFF is attempted the ROM restore
+ * does nt take long
+ */
+ if (core_prev_state == PWRDM_POWER_RET)
+ omap3_scratchpad_dpll4autoidle(0);
+ /*
+ * Errata 1.164 fix : OTG autoidle can prevent
+ * sleep
+ */
+ usb_musb_disable_autoidle();
+
}
omap_uart_resume_idle(0);
omap_uart_resume_idle(1);
- if (core_next_state == PWRDM_POWER_OFF)
+ if (core_next_state == PWRDM_POWER_OFF) {
prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF,
OMAP3430_GR_MOD,
OMAP3_PRM_VOLTCTRL_OFFSET);
+ if (prm_setup->setup_times_off != NULL)
+ prm_program_setup_times(prm_setup->setup_times);
+ }
/* Enable smartreflex after WFI */
enable_smartreflex(SR1);
enable_smartreflex(SR2);
+ } else {
+ omap_uart_resume_idle(0);
+ omap_uart_resume_idle(1);
}
+ /* Re-enable interrupt controller autoidle */
+ omap3_intc_autoidle(1);
/* PER */
if (per_next_state < PWRDM_POWER_ON) {
- per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
+ if (per_next_state == PWRDM_POWER_OFF) {
+ /*
+ * Reading the prev-state takes long time (11us@OPP2),
+ * only do it, if we really tried to put PER in OFF
+ */
+ per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
if (per_prev_state == PWRDM_POWER_OFF) {
- omap3_per_restore_context();
- omap3_gpio_restore_pad_context(0);
- } else if (per_next_state == PWRDM_POWER_OFF)
- omap3_gpio_restore_pad_context(1);
+ omap3_per_restore_context();
+ omap3_gpio_restore_pad_context(0);
+ } else if (per_next_state == PWRDM_POWER_OFF) {
+ omap3_gpio_restore_pad_context(1);
+ }
+ }
omap2_gpio_resume_after_idle();
omap_uart_resume_idle(2);
- if (per_state_modified)
- pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF);
- }
+ } else
+ omap_uart_resume_idle(2);
/* Disable IO-PAD and IO-CHAIN wakeup */
- if (core_next_state < PWRDM_POWER_ON) {
+ if (core_next_state <= PWRDM_POWER_ON) {
prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
omap3_disable_io_chain();
}
@@ -478,7 +648,6 @@
pwrdm_post_transition();
- omap2_clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
}
int omap3_can_sleep(void)
@@ -514,6 +683,17 @@
if (cur_state == state)
return ret;
+ /*
+ * check if bridge has hibernated? if yes then just return success
+ * If OFF mode is not enabled, sleep switch is performed for IVA which is not
+ * necessary.
+ * REVISIT: Bridge has to set powerstate based on enable_off_mode state.
+ */
+ if (!strcmp(pwrdm->name, "iva2_pwrdm")) {
+ /* if (cur_state == PWRDM_POWER_OFF) */
+ return 0;
+ }
+
if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
sleep_switch = 1;
@@ -528,7 +708,6 @@
}
if (sleep_switch) {
- omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
pwrdm_wait_transition(pwrdm);
pwrdm_state_switch(pwrdm);
}
@@ -602,7 +781,7 @@
}
omap_uart_prepare_suspend();
-
+ omap3_intc_suspend();
regset_save_on_suspend = 1;
omap_sram_idle();
regset_save_on_suspend = 0;
@@ -653,8 +832,7 @@
static int omap3_pm_begin(suspend_state_t state)
{
suspend_state = state;
- omap_uart_enable_irqs(0);
- return 0;
+ return omap_uart_enable_irqs(0);
}
static void omap3_pm_end(void)
@@ -724,6 +902,23 @@
static void __init prcm_setup_regs(void)
{
+ u32 cm_clksel1_mpu, cm_clksel1_iva2;
+
+ /*set Bypass clock dividers for MPU and IVA */
+ cm_clksel1_mpu = cm_read_mod_reg(MPU_MOD, CM_CLKSEL1);
+ cm_clksel1_iva2 = cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL1);
+ if (cpu_is_omap3630()) {
+ cm_clksel1_iva2 = (cm_clksel1_iva2 & ~(OMAP3430_IVA2_CLK_SRC_MASK)) |
+ (0x2 << OMAP3430_IVA2_CLK_SRC_SHIFT);
+ cm_clksel1_mpu = (cm_clksel1_mpu & ~(OMAP3430_MPU_CLK_SRC_MASK)) |
+ (0x1 << OMAP3430_MPU_CLK_SRC_SHIFT);
+ } else if (cpu_is_omap34xx()) {
+ cm_clksel1_iva2 = (cm_clksel1_iva2 & ~(OMAP3430_IVA2_CLK_SRC_MASK)) |
+ (0x4 << OMAP3430_IVA2_CLK_SRC_SHIFT);
+ cm_clksel1_mpu = (cm_clksel1_mpu & ~(OMAP3430_MPU_CLK_SRC_MASK)) |
+ (0x2 << OMAP3430_MPU_CLK_SRC_SHIFT);
+ }
+
/* reset modem */
prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
@@ -735,6 +930,11 @@
prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
+
+ /* Enable PM_WKEN to support DSS LPR */
+ prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS,
+ OMAP3430_DSS_MOD, PM_WKEN);
+
prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
@@ -845,6 +1045,8 @@
CM_AUTOIDLE);
}
+ omap_ctrl_writel(OMAP3430_AUTOIDLE, OMAP2_CONTROL_SYSCONFIG);
+
/*
* Set all plls to autoidle. This is needed until autoidle is
* enabled by clockfw
@@ -906,6 +1108,26 @@
omap3_iva_idle();
}
+/* Function to register smc notification used in driver code */
+void pm_register_sleep_notification(u32 domain_id, int (*notification)(bool))
+{
+ if (core_off_notification == NULL)
+ core_off_notification = notification;
+ else
+ printk(KERN_ERR "This function is already registered\n");
+}
+EXPORT_SYMBOL(pm_register_sleep_notification);
+
+/* Function to unregister smc notification used in driver code */
+void pm_unregister_sleep_notification(u32 domain_id, int (*notification)(bool))
+{
+ if (core_off_notification != NULL)
+ core_off_notification = NULL;
+ else
+ printk(KERN_ERR "This function is already unregistered\n");
+}
+EXPORT_SYMBOL(pm_unregister_sleep_notification);
+
void omap3_pm_off_mode_enable(int enable)
{
struct power_state *pwrst;
@@ -916,6 +1138,8 @@
else
state = PWRDM_POWER_RET;
+ omap3_cpuidle_update_states();
+
#ifdef CONFIG_OMAP_PM_SRF
resource_lock_opp(VDD1_OPP);
resource_lock_opp(VDD2_OPP);
@@ -954,26 +1178,147 @@
return -EINVAL;
}
+static void omap3_init_prm_setup_times(struct prm_setup_times_vc *conf)
+{
+ if (conf == NULL)
+ return;
+
+ conf->voltsetup1 =
+ (conf->voltsetup_time2 << OMAP3430_SETUP_TIME2_SHIFT) |
+ (conf->voltsetup_time1 << OMAP3430_SETUP_TIME1_SHIFT);
+}
+
+#ifdef CONFIG_VOLTSCALE_VPFORCE
+/* Voltage Scale using vp force update */
+static int voltagescale_vpforceupdate(u32 target_opp, u32 current_opp,
+ u8 target_vsel, u8 current_vsel)
+{
+ u32 vdd, target_opp_no, current_opp_no;
+ u32 t2_smps_delay = 0;
+ u32 t2_smps_steps = 0;
+ u32 vpconfig, vp_config_offs, vp_tranxdone_st;
+ int timeout = 0;
+
+ vdd = get_vdd(target_opp);
+ target_opp_no = get_opp_no(target_opp);
+ current_opp_no = get_opp_no(current_opp);
+ t2_smps_steps = abs(target_vsel - current_vsel);
+
+ if (vdd == VDD1_OPP) {
+ vp_config_offs = OMAP3_PRM_VP1_CONFIG_OFFSET;
+ vp_tranxdone_st = OMAP3430_VP1_TRANXDONE_ST;
+ vpconfig = target_vsel << OMAP3430_INITVOLTAGE_SHIFT |
+ ((target_opp_no < VDD1_OPP3)
+ ? PRM_VP1_CONFIG_ERRORGAIN_OPPLOW
+ : PRM_VP1_CONFIG_ERRORGAIN_OPPHIGH);
+ prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
+ (target_vsel << OMAP3430_VC_CMD_ON_SHIFT),
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VC_CMD_VAL_0_OFFSET);
+ } else if (vdd == VDD2_OPP) {
+ vp_config_offs = OMAP3_PRM_VP2_CONFIG_OFFSET;
+ vp_tranxdone_st = OMAP3430_VP2_TRANXDONE_ST;
+ vpconfig = target_vsel << OMAP3430_INITVOLTAGE_SHIFT |
+ ((target_opp_no < VDD2_OPP3)
+ ? PRM_VP2_CONFIG_ERRORGAIN_OPPLOW
+ : PRM_VP2_CONFIG_ERRORGAIN_OPPHIGH);
+ prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
+ (target_vsel << OMAP3430_VC_CMD_ON_SHIFT),
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VC_CMD_VAL_1_OFFSET);
+ } else {
+ pr_warning("Wrong VDD passed.VDD %d does not exist\n", vdd);
+ return -1;
+ }
+ /* Clear all pending TransactionDone interrupt/status */
+ while (timeout < VP_TRANXDONE_TIMEOUT) {
+ prm_write_mod_reg(vp_tranxdone_st, OCP_MOD,
+ OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+ if (!(prm_read_mod_reg(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET)
+ & vp_tranxdone_st))
+ break;
+
+ udelay(1);
+ timeout++;
+ }
+ if (timeout == VP_TRANXDONE_TIMEOUT)
+ pr_warning("VP1:TRANXDONE timeout exceeded still\
+ going ahead with voltage changed\n");
+
+ /* Configuring for vpforceupdate */
+ prm_rmw_mod_reg_bits(OMAP3430_ERRORGAIN_MASK |
+ OMAP3430_INITVOLTAGE_MASK | OMAP3430_INITVDD |
+ OMAP3430_FORCEUPDATE, vpconfig, OMAP3430_GR_MOD,
+ vp_config_offs);
+ /* Initialize VP voltage */
+ prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
+ vp_config_offs);
+ /* Force update of voltage */
+ prm_set_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD,
+ vp_config_offs);
+ timeout = 0;
+ /* Wait for TransactionDone */
+ while ((timeout < VP_TRANXDONE_TIMEOUT) &&
+ (!(prm_read_mod_reg(OCP_MOD,
+ OMAP2_PRM_IRQSTATUS_MPU_OFFSET) &
+ vp_tranxdone_st))) {
+ udelay(1);
+ timeout++;
+ }
+
+ if (timeout == VP_TRANXDONE_TIMEOUT)
+ pr_warning("VP1:TRANXDONE timeout exceeded going ahead with\
+ the t2 smps wait\n");
+
+ /* Wait for voltage to settle with SW wait-loop */
+ t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2;
+ udelay(t2_smps_delay);
+
+ timeout = 0;
+ /* Clear all pending TransactionDone interrupt/status */
+ while (timeout < VP_TRANXDONE_TIMEOUT) {
+ prm_write_mod_reg(vp_tranxdone_st, OCP_MOD,
+ OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+ if (!(prm_read_mod_reg(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET)
+ & vp_tranxdone_st))
+ break;
+
+ udelay(1);
+ timeout++;
+ }
+ if (timeout == VP_TRANXDONE_TIMEOUT)
+ pr_warning("VP1:TRANXDONE timeout exceeded\n");
+
+ /* Clear INITVDD bit */
+ prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
+ vp_config_offs);
+
+ /* Clear force bit */
+ prm_clear_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD,
+ vp_config_offs);
+ return 0;
+}
+#endif
+
+/* Scale voltage using vcbypass or vpforceupdate */
+int omap_scale_voltage(u32 target_opp, u32 current_opp,
+ u8 target_vsel, u8 current_vsel)
+{
+ #if defined(CONFIG_VOLTSCALE_VPFORCE)
+ return voltagescale_vpforceupdate(target_opp, current_opp,
+ target_vsel, current_vsel);
+ #elif defined(CONFIG_OMAP_SMARTREFLEX)
+ return sr_voltagescale_vcbypass(target_opp, current_opp,
+ target_vsel, current_vsel);
+ #else
+ return 0;
+ #endif
+}
+EXPORT_SYMBOL(omap_scale_voltage);
+
void omap3_set_prm_setup_vc(struct prm_setup_vc *setup_vc)
{
- prm_setup.clksetup = setup_vc->clksetup;
- prm_setup.voltsetup_time1 = setup_vc->voltsetup_time1;
- prm_setup.voltsetup_time2 = setup_vc->voltsetup_time2;
- prm_setup.voltoffset = setup_vc->voltoffset;
- prm_setup.voltsetup2 = setup_vc->voltsetup2;
- prm_setup.vdd0_on = setup_vc->vdd0_on;
- prm_setup.vdd0_onlp = setup_vc->vdd0_onlp;
- prm_setup.vdd0_ret = setup_vc->vdd0_ret;
- prm_setup.vdd0_off = setup_vc->vdd0_off;
- prm_setup.vdd1_on = setup_vc->vdd1_on;
- prm_setup.vdd1_onlp = setup_vc->vdd1_onlp;
- prm_setup.vdd1_ret = setup_vc->vdd1_ret;
- prm_setup.vdd1_off = setup_vc->vdd1_off;
- prm_setup.i2c_slave_ra = setup_vc->i2c_slave_ra;
- prm_setup.vdd_vol_ra = setup_vc->vdd_vol_ra;
- prm_setup.vdd_cmd_ra = setup_vc->vdd_cmd_ra;
- prm_setup.vdd_ch_conf = setup_vc->vdd_ch_conf;
- prm_setup.vdd_i2c_cfg = setup_vc->vdd_i2c_cfg;
+ prm_setup = setup_vc;
}
static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
@@ -983,7 +1328,7 @@
if (!pwrdm->pwrsts)
return 0;
- pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
+ pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC);
if (!pwrst)
return -ENOMEM;
pwrst->pwrdm = pwrdm;
@@ -1020,6 +1365,49 @@
save_secure_ram_context_sz);
}
+#ifdef CONFIG_OMAP_PM_SRF
+static void set_opps_max(void)
+{
+ resource_set_opp_level(VDD2_OPP, MAX_VDD2_OPP, OPP_IGNORE_LOCK);
+ resource_set_opp_level(VDD1_OPP, MAX_VDD1_OPP, OPP_IGNORE_LOCK);
+ return;
+}
+#else
+static void set_opps_max(void)
+{
+ return;
+}
+#endif
+
+static int prcm_prepare_reboot(struct notifier_block *this, unsigned long code,
+ void *x)
+{
+ if ((code == SYS_DOWN) || (code == SYS_HALT) ||
+ (code == SYS_POWER_OFF)) {
+ set_opps_max();
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block prcm_notifier = {
+ .notifier_call = prcm_prepare_reboot,
+ .next = NULL,
+ .priority = INT_MAX,
+};
+
+static int panic_prepare_reboot(struct notifier_block *this,
+ unsigned long code, void *x)
+{
+ set_opps_max();
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block prcm_panic_notifier = {
+ .notifier_call = panic_prepare_reboot,
+ .next = NULL,
+ .priority = INT_MAX,
+};
+
int __init omap3_pm_init(void)
{
struct power_state *pwrst, *tmp;
@@ -1057,7 +1445,7 @@
neon_pwrdm = pwrdm_lookup("neon_pwrdm");
per_pwrdm = pwrdm_lookup("per_pwrdm");
core_pwrdm = pwrdm_lookup("core_pwrdm");
- cam_pwrdm = pwrdm_lookup("cam_pwrdm");
+ wkup_pwrdm = pwrdm_lookup("wkup_pwrdm");
omap_push_sram_idle();
@@ -1077,6 +1465,14 @@
* http://marc.info/?l=linux-omap&m=121852150710062&w=2
*/
pwrdm_add_wkdep(per_pwrdm, core_pwrdm);
+ /*
+ * A part of the fix for errata 1.158.
+ * GPIO pad spurious transition (glitch/spike) upon wakeup
+ * from SYSTEM OFF mode. The remaining fix is in:
+ * omap3_gpio_save_context, omap3_gpio_restore_context.
+ */
+ if (omap_rev() <= OMAP3430_REV_ES3_1)
+ pwrdm_add_wkdep(per_pwrdm, wkup_pwrdm);
if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
omap3_secure_ram_storage =
@@ -1097,6 +1493,9 @@
}
omap3_save_scratchpad_contents();
+ register_reboot_notifier(&prcm_notifier);
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &prcm_panic_notifier);
err1:
return ret;
err2:
@@ -1144,32 +1543,32 @@
static void __init configure_vc(void)
{
- prm_write_mod_reg(prm_setup.i2c_slave_ra, OMAP3430_GR_MOD,
+ prm_write_mod_reg(prm_setup->i2c_slave_ra, OMAP3430_GR_MOD,
OMAP3_PRM_VC_SMPS_SA_OFFSET);
- prm_write_mod_reg(prm_setup.vdd_vol_ra, OMAP3430_GR_MOD,
+ prm_write_mod_reg(prm_setup->vdd_vol_ra, OMAP3430_GR_MOD,
OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET);
/* Only set if power_ic has different voltage and cmd addrs */
- if (prm_setup.vdd_vol_ra != prm_setup.vdd_cmd_ra)
- prm_write_mod_reg(prm_setup.vdd_cmd_ra, OMAP3430_GR_MOD,
+ if (prm_setup->vdd_vol_ra != prm_setup->vdd_cmd_ra)
+ prm_write_mod_reg(prm_setup->vdd_cmd_ra, OMAP3430_GR_MOD,
OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET);
- prm_write_mod_reg((prm_setup.vdd0_on << OMAP3430_VC_CMD_ON_SHIFT) |
- (prm_setup.vdd0_onlp << OMAP3430_VC_CMD_ONLP_SHIFT) |
- (prm_setup.vdd0_ret << OMAP3430_VC_CMD_RET_SHIFT) |
- (prm_setup.vdd0_off << OMAP3430_VC_CMD_OFF_SHIFT),
+ prm_write_mod_reg((prm_setup->vdd0_on << OMAP3430_VC_CMD_ON_SHIFT) |
+ (prm_setup->vdd0_onlp << OMAP3430_VC_CMD_ONLP_SHIFT) |
+ (prm_setup->vdd0_ret << OMAP3430_VC_CMD_RET_SHIFT) |
+ (prm_setup->vdd0_off << OMAP3430_VC_CMD_OFF_SHIFT),
OMAP3430_GR_MOD, OMAP3_PRM_VC_CMD_VAL_0_OFFSET);
- prm_write_mod_reg((prm_setup.vdd1_on << OMAP3430_VC_CMD_ON_SHIFT) |
- (prm_setup.vdd1_onlp << OMAP3430_VC_CMD_ONLP_SHIFT) |
- (prm_setup.vdd1_ret << OMAP3430_VC_CMD_RET_SHIFT) |
- (prm_setup.vdd1_off << OMAP3430_VC_CMD_OFF_SHIFT),
+ prm_write_mod_reg((prm_setup->vdd1_on << OMAP3430_VC_CMD_ON_SHIFT) |
+ (prm_setup->vdd1_onlp << OMAP3430_VC_CMD_ONLP_SHIFT) |
+ (prm_setup->vdd1_ret << OMAP3430_VC_CMD_RET_SHIFT) |
+ (prm_setup->vdd1_off << OMAP3430_VC_CMD_OFF_SHIFT),
OMAP3430_GR_MOD, OMAP3_PRM_VC_CMD_VAL_1_OFFSET);
- prm_write_mod_reg(prm_setup.vdd_ch_conf, OMAP3430_GR_MOD,
+ prm_write_mod_reg(prm_setup->vdd_ch_conf, OMAP3430_GR_MOD,
OMAP3_PRM_VC_CH_CONF_OFFSET);
- prm_write_mod_reg(prm_setup.vdd_i2c_cfg, OMAP3430_GR_MOD,
+ prm_write_mod_reg(prm_setup->vdd_i2c_cfg, OMAP3430_GR_MOD,
OMAP3_PRM_VC_I2C_CFG_OFFSET);
/* Setup value for voltctrl */
@@ -1177,18 +1576,11 @@
OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET);
/* Write setup times */
- prm_write_mod_reg(prm_setup.clksetup, OMAP3430_GR_MOD,
- OMAP3_PRM_CLKSETUP_OFFSET);
- prm_write_mod_reg((prm_setup.voltsetup_time2 <<
- OMAP3430_SETUP_TIME2_SHIFT) |
- (prm_setup.voltsetup_time1 <<
- OMAP3430_SETUP_TIME1_SHIFT),
- OMAP3430_GR_MOD, OMAP3_PRM_VOLTSETUP1_OFFSET);
-
- prm_write_mod_reg(prm_setup.voltoffset, OMAP3430_GR_MOD,
+ omap3_init_prm_setup_times(prm_setup->setup_times);
+ omap3_init_prm_setup_times(prm_setup->setup_times_off);
+ prm_program_setup_times(prm_setup->setup_times);
+ prm_write_mod_reg(prm_setup->voltoffset, OMAP3430_GR_MOD,
OMAP3_PRM_VOLTOFFSET_OFFSET);
- prm_write_mod_reg(prm_setup.voltsetup2, OMAP3430_GR_MOD,
- OMAP3_PRM_VOLTSETUP2_OFFSET);
pm_dbg_regset_init(1);
}
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 7aa64a8..ad47e3d 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -112,8 +112,8 @@
static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
{
- int prev;
- int state;
+ u8 prev;
+ u8 state;
if (pwrdm == NULL)
return -EINVAL;
@@ -128,6 +128,16 @@
prev = pwrdm_read_prev_pwrst(pwrdm);
if (pwrdm->state != prev)
pwrdm->state_counter[prev]++;
+ if (prev == PWRDM_POWER_RET) {
+ if ((pwrdm->pwrsts_logic_ret == PWRSTS_OFF_RET) &&
+ (pwrdm_read_prev_logic_pwrst(pwrdm) ==
+ PWRDM_POWER_OFF))
+ pwrdm->ret_logic_off_counter++;
+ if ((pwrdm->pwrsts_mem_ret[0] == PWRSTS_OFF_RET) &&
+ (pwrdm_read_prev_mem_pwrst(pwrdm, 0) ==
+ PWRDM_POWER_OFF))
+ pwrdm->ret_mem_off_counter++;
+ }
break;
default:
return -EINVAL;
@@ -159,12 +169,20 @@
static __init void _pwrdm_setup(struct powerdomain *pwrdm)
{
int i;
+ int state;
for (i = 0; i < 4; i++)
pwrdm->state_counter[i] = 0;
+ pwrdm->ret_logic_off_counter = 0;
+ pwrdm->ret_mem_off_counter = 0;
pwrdm_wait_transition(pwrdm);
- pwrdm->state = pwrdm_read_pwrst(pwrdm);
+ state = pwrdm_read_pwrst(pwrdm);
+ if (state < 0) {
+ pr_err("powerdomain: invalid state for %s\n", pwrdm->name);
+ return;
+ }
+ pwrdm->state = state;
pwrdm->state_counter[pwrdm->state] = 1;
}
@@ -221,6 +239,7 @@
pr_debug("powerdomain: registered %s\n", pwrdm->name);
ret = 0;
+ pwrdm->next_state = -1;
pr_unlock:
write_unlock_irqrestore(&pwrdm_rwlock, flags);
@@ -273,35 +292,49 @@
}
/**
- * pwrdm_for_each - call function on each registered clockdomain
+ * pwrdm_for_each_nolock - call function on each registered clockdomain
* @fn: callback function *
*
* Call the supplied function for each registered powerdomain. The
* callback function can return anything but 0 to bail out early from
- * the iterator. The callback function is called with the pwrdm_rwlock
- * held for reading, so no powerdomain structure manipulation
- * functions should be called from the callback, although hardware
- * powerdomain control functions are fine. Returns the last return
- * value of the callback function, which should be 0 for success or
- * anything else to indicate failure; or -EINVAL if the function
- * pointer is null.
+ * the iterator.Returns the last return value of the callback function, which
+ * should be 0 for success or anything else to indicate failure; or -EINVAL
+ * if the function pointer is null.
*/
-int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
+int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user),
void *user)
{
struct powerdomain *temp_pwrdm;
- unsigned long flags;
int ret = 0;
if (!fn)
return -EINVAL;
- read_lock_irqsave(&pwrdm_rwlock, flags);
list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
ret = (*fn)(temp_pwrdm, user);
if (ret)
break;
}
+
+ return ret;
+}
+/**
+ * pwrdm_for_each - call function on each registered clockdomain
+ * @fn: callback function
+ *
+ * This function is the same as 'pwrdm_for_each_nolock()', but keeps the
+ * &pwrdm_rwlock locked for reading, so no powerdomain structure manipulation
+ * functions should be called from the callback, although hardware powerdomain
+ * control functions are fine.
+ */
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
+ void *user)
+{
+ unsigned long flags;
+ int ret;
+
+ read_lock_irqsave(&pwrdm_rwlock, flags);
+ ret = pwrdm_for_each_nolock(fn, user);
read_unlock_irqrestore(&pwrdm_rwlock, flags);
return ret;
@@ -686,19 +719,37 @@
*/
int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
{
+ u8 prg_pwrst;
+
if (!pwrdm)
return -EINVAL;
+ if (pwrdm->next_state == pwrst)
+ return 0;
+
if (!(pwrdm->pwrsts & (1 << pwrst)))
return -EINVAL;
pr_debug("powerdomain: setting next powerstate for %s to %0x\n",
pwrdm->name, pwrst);
+ /* INACTIVE is reserved, so we program pwrdm as ON */
+ if (pwrst == PWRDM_POWER_INACTIVE)
+ prg_pwrst = PWRDM_POWER_ON;
+ else
+ prg_pwrst = pwrst;
+
prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
- (pwrst << OMAP_POWERSTATE_SHIFT),
+ (prg_pwrst << OMAP_POWERSTATE_SHIFT),
pwrdm->prcm_offs, PM_PWSTCTRL);
+ /* If next state is ON, prevent idle */
+ if (pwrst == PWRDM_POWER_ON)
+ omap2_clkdm_deny_idle(pwrdm->pwrdm_clkdms[0]);
+ else
+ omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+ pwrdm->next_state = pwrst;
+
return 0;
}
@@ -715,6 +766,9 @@
if (!pwrdm)
return -EINVAL;
+ if (pwrdm->next_state > -1)
+ return pwrdm->next_state;
+
return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTCTRL,
OMAP_POWERSTATE_MASK);
}
@@ -951,6 +1005,29 @@
}
/**
+ * pwrdm_read_next_logic_pwrst - get next powerdomain logic power state
+ * @pwrdm: struct powerdomain * to get next logic power state
+ *
+ * Return the powerdomain pwrdm's logic power state. Returns -EINVAL
+ * if the powerdomain pointer is null or returns the next logic
+ * power state upon success.
+ */
+int pwrdm_read_next_logic_pwrst(struct powerdomain *pwrdm)
+{
+ if (!pwrdm)
+ return -EINVAL;
+
+ /*
+ * The register bit names below may not correspond to the
+ * actual names of the bits in each powerdomain's register,
+ * but the type of value returned is the same for each
+ * powerdomain.
+ */
+ return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTCTRL,
+ OMAP3430_LOGICSTATEST);
+}
+
+/**
* pwrdm_read_mem_pwrst - get current memory bank power state
* @pwrdm: struct powerdomain * to get current memory bank power state
* @bank: memory bank number (0-3)
@@ -1017,6 +1094,16 @@
if (pwrdm->banks < (bank + 1))
return -EEXIST;
+#ifdef CONFIG_ARCH_OMAP3430
+ /*
+ * In 3430, for MPU domain bank 0 status bits
+ * are displayed in the position of bank1 status bits
+ * in PREPWST . So the hack. Think of a cleaner
+ * way of doing this
+ */
+ if (!strcmp("mpu_pwrdm", pwrdm->name))
+ bank = 1;
+#endif
/*
* The register bit names below may not correspond to the
* actual names of the bits in each powerdomain's register,
@@ -1046,6 +1133,54 @@
}
/**
+ * pwrdm_read_next_mem_pwrst - get next memory bank power state
+ * @pwrdm: struct powerdomain * to get mext memory bank power state
+ * @bank: memory bank number (0-3)
+ *
+ * Return the powerdomain pwrdm's next memory power state for bank
+ * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
+ * the target memory bank does not exist or is not controllable, or
+ * returns the next memory power state upon success.
+ */
+int pwrdm_read_next_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
+{
+ u32 m;
+
+ if (!pwrdm)
+ return -EINVAL;
+
+ if (pwrdm->banks < (bank + 1))
+ return -EEXIST;
+
+ /*
+ * The register bit names below may not correspond to the
+ * actual names of the bits in each powerdomain's register,
+ * but the type of value returned is the same for each
+ * powerdomain.
+ */
+ switch (bank) {
+ case 0:
+ m = OMAP3430_SHAREDL1CACHEFLATRETSTATE;
+ break;
+ case 1:
+ m = OMAP3430_L1FLATMEMRETSTATE;
+ break;
+ case 2:
+ m = OMAP3430_SHAREDL2CACHEFLATRETSTATE;
+ break;
+ case 3:
+ m = OMAP3430_SHAREDL2CACHEFLATRETSTATE;
+ break;
+ default:
+ WARN_ON(1); /* should never happen */
+ return -EEXIST;
+ }
+
+ return prm_read_mod_bits_shift(pwrdm->prcm_offs,
+ PM_PWSTCTRL, m);
+}
+
+/**
* pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
* @pwrdm: struct powerdomain * to clear
*
@@ -1180,6 +1315,29 @@
return 0;
}
+/**
+ * pwrdm_can_idle - check if the powerdomain can enter idle
+ * @pwrdm: struct powerdomain * the powerdomain to check status of
+ *
+ * Does a functional clock check for the powerdomain and returns 1 if the
+ * powerdomain can enter idle, 0 if not.
+ */
+int pwrdm_can_idle(struct powerdomain *pwrdm)
+{
+ int i;
+ const int fclk_regs[] = { CM_FCLKEN, OMAP3430ES2_CM_FCLKEN3 };
+
+ if (!pwrdm)
+ return -EINVAL;
+
+ for (i = 0; i < pwrdm->fclk_reg_amt; i++)
+ if (cm_read_mod_reg(pwrdm->prcm_offs, fclk_regs[i]) &
+ (0xffffffff ^ pwrdm->fclk_masks[i]))
+ return 0;
+ return 1;
+}
+
+
int pwrdm_state_switch(struct powerdomain *pwrdm)
{
return _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h
index 87e8111..c376efa 100644
--- a/arch/arm/mach-omap2/powerdomains34xx.h
+++ b/arch/arm/mach-omap2/powerdomains34xx.h
@@ -165,7 +165,7 @@
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
.dep_bit = OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT,
.wkdep_srcs = iva2_wkdeps,
- .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts = PWRSTS_OFF_RET_INA_ON,
.pwrsts_logic_ret = PWRSTS_OFF_RET,
.banks = 4,
.pwrsts_mem_ret = {
@@ -180,6 +180,7 @@
[2] = PWRSTS_OFF_ON,
[3] = PWRDM_POWER_ON,
},
+ .fclk_reg_amt = 1,
};
static struct powerdomain mpu_34xx_pwrdm = {
@@ -188,7 +189,7 @@
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
.dep_bit = OMAP3430_EN_MPU_SHIFT,
.wkdep_srcs = mpu_34xx_wkdeps,
- .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts = PWRSTS_OFF_RET_INA_ON,
.pwrsts_logic_ret = PWRSTS_OFF_RET,
.banks = 1,
.pwrsts_mem_ret = {
@@ -206,7 +207,8 @@
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 |
CHIP_IS_OMAP3430ES2 |
CHIP_IS_OMAP3430ES3_0),
- .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts = PWRSTS_OFF_RET_INA_ON,
+ .pwrsts_logic_ret = PWRSTS_OFF_RET,
.dep_bit = OMAP3430_EN_CORE_SHIFT,
.banks = 2,
.pwrsts_mem_ret = {
@@ -214,8 +216,8 @@
[1] = PWRSTS_OFF_RET, /* MEM2RETSTATE */
},
.pwrsts_mem_on = {
- [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
- [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
+ [0] = PWRSTS_OFF_RET_INA_ON, /* MEM1ONSTATE */
+ [1] = PWRSTS_OFF_RET_INA_ON, /* MEM2ONSTATE */
},
};
@@ -224,7 +226,8 @@
.name = "core_pwrdm",
.prcm_offs = CORE_MOD,
.omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES3_1),
- .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts = PWRSTS_OFF_RET_INA_ON,
+ .pwrsts_logic_ret = PWRSTS_OFF_RET,
.dep_bit = OMAP3430_EN_CORE_SHIFT,
.flags = PWRDM_HAS_HDWR_SAR, /* for USBTLL only */
.banks = 2,
@@ -233,9 +236,15 @@
[1] = PWRSTS_OFF_RET, /* MEM2RETSTATE */
},
.pwrsts_mem_on = {
- [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
- [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
+ [0] = PWRSTS_OFF_RET_INA_ON, /* MEM1ONSTATE */
+ [1] = PWRSTS_OFF_RET_INA_ON, /* MEM2ONSTATE */
},
+ .fclk_reg_amt = 2,
+ .fclk_masks = {
+ [0] = OMAP3430_EN_UART2 | OMAP3430_EN_UART1,
+ [1] = 0,
+ },
+
};
/* Another case of bit name collisions between several registers: EN_DSS */
@@ -246,7 +255,7 @@
.dep_bit = OMAP3430_PM_WKDEP_MPU_EN_DSS_SHIFT,
.wkdep_srcs = cam_dss_wkdeps,
.sleepdep_srcs = dss_per_usbhost_sleepdeps,
- .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts = PWRSTS_OFF_RET_INA_ON,
.pwrsts_logic_ret = PWRDM_POWER_RET,
.banks = 1,
.pwrsts_mem_ret = {
@@ -255,6 +264,7 @@
.pwrsts_mem_on = {
[0] = PWRDM_POWER_ON, /* MEMONSTATE */
},
+ .fclk_reg_amt = 1,
};
/*
@@ -278,6 +288,7 @@
.pwrsts_mem_on = {
[0] = PWRDM_POWER_ON, /* MEMONSTATE */
},
+ .fclk_reg_amt = 1,
};
static struct powerdomain cam_pwrdm = {
@@ -286,7 +297,7 @@
.prcm_offs = OMAP3430_CAM_MOD,
.wkdep_srcs = cam_dss_wkdeps,
.sleepdep_srcs = cam_gfx_sleepdeps,
- .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts = PWRSTS_OFF_RET_INA_ON,
.pwrsts_logic_ret = PWRDM_POWER_RET,
.banks = 1,
.pwrsts_mem_ret = {
@@ -295,6 +306,7 @@
.pwrsts_mem_on = {
[0] = PWRDM_POWER_ON, /* MEMONSTATE */
},
+ .fclk_reg_amt = 1,
};
static struct powerdomain per_pwrdm = {
@@ -304,7 +316,7 @@
.dep_bit = OMAP3430_EN_PER_SHIFT,
.wkdep_srcs = per_usbhost_wkdeps,
.sleepdep_srcs = dss_per_usbhost_sleepdeps,
- .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts = PWRSTS_OFF_RET_INA_ON,
.pwrsts_logic_ret = PWRSTS_OFF_RET,
.banks = 1,
.pwrsts_mem_ret = {
@@ -313,6 +325,10 @@
.pwrsts_mem_on = {
[0] = PWRDM_POWER_ON, /* MEMONSTATE */
},
+ .fclk_reg_amt = 1,
+ .fclk_masks = {
+ [0] = OMAP3430_EN_UART3,
+ },
};
static struct powerdomain emu_pwrdm = {
@@ -326,7 +342,7 @@
.prcm_offs = OMAP3430_NEON_MOD,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
.wkdep_srcs = neon_wkdeps,
- .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts = PWRSTS_OFF_RET_INA_ON,
.pwrsts_logic_ret = PWRDM_POWER_RET,
};
@@ -336,7 +352,7 @@
.omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2),
.wkdep_srcs = per_usbhost_wkdeps,
.sleepdep_srcs = dss_per_usbhost_sleepdeps,
- .pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts = PWRSTS_OFF_RET_INA_ON,
.pwrsts_logic_ret = PWRDM_POWER_RET,
/*
* REVISIT: Enabling usb host save and restore mechanism seems to
@@ -353,6 +369,7 @@
.pwrsts_mem_on = {
[0] = PWRDM_POWER_ON, /* MEMONSTATE */
},
+ .fclk_reg_amt = 1,
};
static struct powerdomain dpll1_pwrdm = {
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index 3f2520d..6b21032 100644
--- a/arch/arm/mach-omap2/prcm.c
+++ b/arch/arm/mach-omap2/prcm.c
@@ -26,7 +26,9 @@
#include <mach/prcm.h>
#include <mach/irqs.h>
#include <mach/control.h>
+#include <mach/sram.h>
+#include "sdrc.h"
#include "clock.h"
#include "cm.h"
#include "prm.h"
@@ -129,11 +131,13 @@
void omap_prcm_arch_reset(char mode)
{
s16 prcm_offs;
+
omap2_clk_prepare_for_reboot();
- if (cpu_is_omap24xx())
+ if (cpu_is_omap24xx()) {
prcm_offs = WKUP_MOD;
- else if (cpu_is_omap34xx()) {
+ prm_set_mod_reg_bits(OMAP_RST_DPLL3, prcm_offs, RM_RSTCTRL);
+ } else if (cpu_is_omap34xx()) {
u32 l;
prcm_offs = OMAP3430_GR_MOD;
@@ -144,10 +148,11 @@
* cf. OMAP34xx TRM, Initialization / Software Booting
* Configuration. */
omap_writel(l, OMAP343X_SCRATCHPAD + 4);
+
+ omap3_configure_core_dpll_warmreset();
+
} else
WARN_ON(1);
-
- prm_set_mod_reg_bits(OMAP_RST_DPLL3, prcm_offs, RM_RSTCTRL);
}
static inline u32 __omap_prcm_read(void __iomem *base, s16 module, u16 reg)
@@ -237,7 +242,6 @@
prcm_context.cm_sysconfig = __raw_readl(OMAP3430_CM_SYSCONFIG);
prcm_context.sgx_cm_clksel =
cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_CLKSEL);
- prcm_context.wkup_cm_clksel = cm_read_mod_reg(WKUP_MOD, CM_CLKSEL);
prcm_context.dss_cm_clksel =
cm_read_mod_reg(OMAP3430_DSS_MOD, CM_CLKSEL);
prcm_context.cam_cm_clksel =
@@ -254,8 +258,6 @@
cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL4);
prcm_context.pll_cm_clksel5 =
cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL5);
- prcm_context.pll_cm_clken =
- cm_read_mod_reg(PLL_MOD, CM_CLKEN);
prcm_context.pll_cm_clken2 =
cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKEN2);
prcm_context.cm_polctrl = __raw_readl(OMAP3430_CM_POLCTRL);
@@ -301,8 +303,6 @@
cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
prcm_context.mpu_cm_autoidle2 =
cm_read_mod_reg(MPU_MOD, CM_AUTOIDLE2);
- prcm_context.pll_cm_autoidle =
- cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
prcm_context.iva2_cm_clkstctrl =
cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSTCTRL);
prcm_context.mpu_cm_clkstctrl =
@@ -394,7 +394,6 @@
__raw_writel(prcm_context.cm_sysconfig, OMAP3430_CM_SYSCONFIG);
cm_write_mod_reg(prcm_context.sgx_cm_clksel, OMAP3430ES2_SGX_MOD,
CM_CLKSEL);
- cm_write_mod_reg(prcm_context.wkup_cm_clksel, WKUP_MOD, CM_CLKSEL);
cm_write_mod_reg(prcm_context.dss_cm_clksel, OMAP3430_DSS_MOD,
CM_CLKSEL);
cm_write_mod_reg(prcm_context.cam_cm_clksel, OMAP3430_CAM_MOD,
@@ -411,7 +410,6 @@
OMAP3430ES2_CM_CLKSEL4);
cm_write_mod_reg(prcm_context.pll_cm_clksel5, PLL_MOD,
OMAP3430ES2_CM_CLKSEL5);
- cm_write_mod_reg(prcm_context.pll_cm_clken, PLL_MOD, CM_CLKEN);
cm_write_mod_reg(prcm_context.pll_cm_clken2, PLL_MOD,
OMAP3430ES2_CM_CLKEN2);
__raw_writel(prcm_context.cm_polctrl, OMAP3430_CM_POLCTRL);
@@ -450,7 +448,6 @@
cm_write_mod_reg(prcm_context.iva2_cm_autiidle2, OMAP3430_IVA2_MOD,
CM_AUTOIDLE2);
cm_write_mod_reg(prcm_context.mpu_cm_autoidle2, MPU_MOD, CM_AUTOIDLE2);
- cm_write_mod_reg(prcm_context.pll_cm_autoidle, PLL_MOD, CM_AUTOIDLE);
cm_write_mod_reg(prcm_context.iva2_cm_clkstctrl, OMAP3430_IVA2_MOD,
CM_CLKSTCTRL);
cm_write_mod_reg(prcm_context.mpu_cm_clkstctrl, MPU_MOD, CM_CLKSTCTRL);
diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h b/arch/arm/mach-omap2/prm-regbits-34xx.h
index d4ea370..8ae9fe5 100644
--- a/arch/arm/mach-omap2/prm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/prm-regbits-34xx.h
@@ -243,6 +243,23 @@
#define OMAP3430_EVGENON_ST (1 << 2)
#define OMAP3430_FS_USB_WKUP_ST (1 << 1)
+#define OMAP3430_VP1_ST (OMAP3430_VP1_OPPCHANGEDONE_ST | \
+ OMAP3430_VP1_MINVDD_ST | \
+ OMAP3430_VP1_MAXVDD_ST | \
+ OMAP3430_VP1_NOSMPSACK_ST | \
+ OMAP3430_VP1_EQVALUE_ST | \
+ OMAP3430_VP1_TRANXDONE_ST)
+
+#define OMAP3430_VP2_ST (OMAP3430_VP2_OPPCHANGEDONE_ST | \
+ OMAP3430_VP2_MINVDD_ST | \
+ OMAP3430_VP2_MAXVDD_ST | \
+ OMAP3430_VP2_NOSMPSACK_ST | \
+ OMAP3430_VP2_EQVALUE_ST | \
+ OMAP3430_VP2_TRANXDONE_ST)
+
+#define OMAP3430_VC_ST (OMAP3430_VC_SAERR_ST | \
+ OMAP3430_VC_RAERR_ST | \
+ OMAP3430_VC_TIMEOUTERR_ST)
/* PRM_IRQENABLE_MPU specific bits */
#define OMAP3430ES2_SND_PERIPH_DPLL_RECAL_EN_SHIFT 25
#define OMAP3430ES2_SND_PERIPH_DPLL_RECAL_EN (1 << 25)
diff --git a/arch/arm/mach-omap2/resource34xx.c b/arch/arm/mach-omap2/resource34xx.c
index 68616f0..238129c 100644
--- a/arch/arm/mach-omap2/resource34xx.c
+++ b/arch/arm/mach-omap2/resource34xx.c
@@ -38,7 +38,7 @@
void init_latency(struct shared_resource *resp)
{
resp->no_of_users = 0;
- resp->curr_level = RES_DEFAULTLEVEL;
+ resp->curr_level = RES_LATENCY_DEFAULTLEVEL;
*((u8 *)resp->resource_data) = 0;
return;
}
@@ -62,7 +62,7 @@
resp->curr_level = latency;
pm_qos_req_added = resp->resource_data;
- if (latency == RES_DEFAULTLEVEL)
+ if (latency == RES_LATENCY_DEFAULTLEVEL)
/* No more users left, remove the pm_qos_req if present */
if (*pm_qos_req_added) {
pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY,
@@ -237,9 +237,29 @@
{
int ret = 0, l3_div;
int *curr_opp;
+ u32 cm_clksel1_mpu;
lock_scratchpad_sem();
if (res == VDD1_OPP) {
+ if (target_level == VDD1_OPP1) {
+ cm_clksel1_mpu = cm_read_mod_reg(MPU_MOD, CM_CLKSEL1);
+ if (cpu_is_omap3630())
+ cm_clksel1_mpu = (cm_clksel1_mpu & ~(OMAP3430_MPU_CLK_SRC_MASK)) |
+ (0x2 << OMAP3430_MPU_CLK_SRC_SHIFT);
+ else if (cpu_is_omap34xx())
+ cm_clksel1_mpu = (cm_clksel1_mpu & ~(OMAP3430_MPU_CLK_SRC_MASK)) |
+ (0x4 << OMAP3430_MPU_CLK_SRC_SHIFT);
+ cm_write_mod_reg(cm_clksel1_mpu, MPU_MOD, CM_CLKSEL1);
+ } else if ((current_level == VDD1_OPP1) && (target_level != VDD1_OPP1)) {
+ cm_clksel1_mpu = cm_read_mod_reg(MPU_MOD, CM_CLKSEL1);
+ if (cpu_is_omap3630())
+ cm_clksel1_mpu = (cm_clksel1_mpu & ~(OMAP3430_MPU_CLK_SRC_MASK)) |
+ (0x1 << OMAP3430_MPU_CLK_SRC_SHIFT);
+ else if (cpu_is_omap34xx())
+ cm_clksel1_mpu = (cm_clksel1_mpu & ~(OMAP3430_MPU_CLK_SRC_MASK)) |
+ (0x2 << OMAP3430_MPU_CLK_SRC_SHIFT);
+ cm_write_mod_reg(cm_clksel1_mpu, MPU_MOD, CM_CLKSEL1);
+ }
curr_opp = &curr_vdd1_opp;
clk_set_rate(dpll1_clk, mpu_opps[target_level].rate);
clk_set_rate(dpll2_clk, dsp_opps[target_level].rate);
@@ -273,29 +293,31 @@
int current_level)
{
int i, ret = 0, raise;
-#ifdef CONFIG_OMAP_SMARTREFLEX
unsigned long t_opp, c_opp;
t_opp = ID_VDD(res) | ID_OPP_NO(opp[target_level].opp_id);
c_opp = ID_VDD(res) | ID_OPP_NO(opp[current_level].opp_id);
-#endif
+ /* Sanity check of the OPP params before attempting to set */
+ if (!opp[target_level].rate || !opp[target_level].vsel)
+ return -EINVAL;
if (target_level > current_level)
raise = 1;
else
raise = 0;
+ disable_smartreflex(res);
+
for (i = 0; i < 2; i++) {
if (i == raise)
ret = program_opp_freq(res, target_level,
current_level);
-#ifdef CONFIG_OMAP_SMARTREFLEX
else
- sr_voltagescale_vcbypass(t_opp, c_opp,
+ omap_scale_voltage(t_opp, c_opp,
opp[target_level].vsel,
opp[current_level].vsel);
-#endif
}
+ enable_smartreflex(res);
return ret;
}
@@ -362,17 +384,18 @@
int ind;
if (resp == vdd1_resp) {
- if (target_level < 3)
+ if (target_level < VDD1_THRESHOLD)
resource_release("vdd2_opp", &vdd2_dev);
resource_set_opp_level(VDD1_OPP, target_level, 0);
/*
* For VDD1 OPP3 and above, make sure the interconnect
- * is at 100Mhz or above.
- * throughput in KiB/s for 100 Mhz = 100 * 1000 * 4.
+ * is strictly above 100Mhz.
+ * throughput in KiB/s for 200 Mhz = 200 * 1000 * 4.
*/
- if (target_level >= 3)
- resource_request("vdd2_opp", &vdd2_dev, 400000);
+ if (target_level >= VDD1_THRESHOLD)
+ resource_request("vdd2_opp", &vdd2_dev,
+ 4 * l3_opps[omap_pm_get_max_vdd2_opp()].rate/1000);
} else if (resp == vdd2_resp) {
tput = target_level;
@@ -380,7 +403,7 @@
/* Convert the tput in KiB/s to Bus frequency in MHz */
req_l3_freq = (tput * 1000)/4;
- for (ind = 2; ind <= MAX_VDD2_OPP; ind++)
+ for (ind = MIN_VDD2_OPP; ind <= MAX_VDD2_OPP; ind++)
if ((l3_opps + ind)->rate >= req_l3_freq) {
target_level = ind;
break;
diff --git a/arch/arm/mach-omap2/resource34xx.h b/arch/arm/mach-omap2/resource34xx.h
index 5b5618a..ac6476e 100644
--- a/arch/arm/mach-omap2/resource34xx.h
+++ b/arch/arm/mach-omap2/resource34xx.h
@@ -28,7 +28,7 @@
#include <mach/omap-pm.h>
#include <mach/omap34xx.h>
-extern int sr_voltagescale_vcbypass(u32 t_opp, u32 c_opp, u8 t_vsel, u8 c_vsel);
+extern int omap_scale_voltage(u32 t_opp, u32 c_opp, u8 t_vsel, u8 c_vsel);
extern void lock_scratchpad_sem();
extern void unlock_scratchpad_sem();
@@ -49,6 +49,7 @@
static struct shared_resource mpu_latency = {
.name = "mpu_latency",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_LATENCY,
.resource_data = &mpu_qos_req_added,
.ops = &lat_res_ops,
};
@@ -56,6 +57,7 @@
static struct shared_resource core_latency = {
.name = "core_latency",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_LATENCY,
.resource_data = &core_qos_req_added,
.ops = &lat_res_ops,
};
@@ -91,6 +93,7 @@
static struct shared_resource core_pwrdm_latency = {
.name = "core_pwrdm_latency",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_LATENCY,
.resource_data = &core_qos_req_added,
.ops = &lat_res_ops,
};
@@ -106,6 +109,7 @@
static struct shared_resource iva2_pwrdm_latency = {
.name = "iva2_pwrdm_latency",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_LATENCY,
.resource_data = &iva2_pwrdm_lat_db,
.ops = &pd_lat_res_ops,
};
@@ -129,6 +133,7 @@
static struct shared_resource gfx_pwrdm_latency = {
.name = "gfx_pwrdm_latency",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
+ .flags = RES_TYPE_LATENCY,
.resource_data = &gfx_pwrdm_lat_db,
.ops = &pd_lat_res_ops,
};
@@ -136,6 +141,7 @@
static struct shared_resource sgx_pwrdm_latency = {
.name = "sgx_pwrdm_latency",
.omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2),
+ .flags = RES_TYPE_LATENCY,
.resource_data = &sgx_pwrdm_lat_db,
.ops = &pd_lat_res_ops,
};
@@ -151,6 +157,7 @@
static struct shared_resource dss_pwrdm_latency = {
.name = "dss_pwrdm_latency",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_LATENCY,
.resource_data = &dss_pwrdm_lat_db,
.ops = &pd_lat_res_ops,
};
@@ -166,6 +173,7 @@
static struct shared_resource cam_pwrdm_latency = {
.name = "cam_pwrdm_latency",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_LATENCY,
.resource_data = &cam_pwrdm_lat_db,
.ops = &pd_lat_res_ops,
};
@@ -181,6 +189,7 @@
static struct shared_resource per_pwrdm_latency = {
.name = "per_pwrdm_latency",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_LATENCY,
.resource_data = &per_pwrdm_lat_db,
.ops = &pd_lat_res_ops,
};
@@ -196,6 +205,7 @@
static struct shared_resource neon_pwrdm_latency = {
.name = "neon_pwrdm_latency",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_LATENCY,
.resource_data = &neon_pwrdm_lat_db,
.ops = &pd_lat_res_ops,
};
@@ -211,6 +221,7 @@
static struct shared_resource usbhost_pwrdm_latency = {
.name = "usbhost_pwrdm_latency",
.omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2),
+ .flags = RES_TYPE_LATENCY,
.resource_data = &usbhost_pwrdm_lat_db,
.ops = &pd_lat_res_ops,
};
@@ -226,6 +237,7 @@
static struct shared_resource emu_pwrdm_latency = {
.name = "emu_pwrdm",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_LATENCY,
.resource_data = &emu_pwrdm_lat_db,
.ops = &pd_lat_res_ops,
};
@@ -251,6 +263,7 @@
static struct shared_resource vdd1_opp = {
.name = "vdd1_opp",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_PERFORMANCE,
.ops = &opp_res_ops,
};
@@ -264,6 +277,7 @@
static struct shared_resource vdd2_opp = {
.name = "vdd2_opp",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_PERFORMANCE,
.resource_data = &l3_throughput_db,
.ops = &opp_res_ops,
};
@@ -279,6 +293,7 @@
static struct shared_resource mpu_freq = {
.name = "mpu_freq",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_PERFORMANCE,
.resource_data = &linked_res,
.ops = &freq_res_ops,
};
@@ -286,6 +301,7 @@
static struct shared_resource dsp_freq = {
.name = "dsp_freq",
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = RES_TYPE_PERFORMANCE,
.resource_data = &linked_res,
.ops = &freq_res_ops,
};
diff --git a/arch/arm/mach-omap2/sdram-hynix-h8mbx00u0mer-0em.h b/arch/arm/mach-omap2/sdram-hynix-h8mbx00u0mer-0em.h
new file mode 100644
index 0000000..adef6b9
--- /dev/null
+++ b/arch/arm/mach-omap2/sdram-hynix-h8mbx00u0mer-0em.h
@@ -0,0 +1,55 @@
+/*
+ * SDRC register values for the Hynix H8MBX00U0MER-0EM
+ *
+ * Copyright (C) 2008-2009 Texas Instruments, Inc.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Nicole Chalhoub / Vincent Bour
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ARCH_ARM_MACH_OMAP2_SDRAM_HYNIX_H8MBX00U0MER0EM
+#define ARCH_ARM_MACH_OMAP2_SDRAM_HYNIX_H8MBX00U0MER0EM
+
+#include <mach/sdrc.h>
+
+/* Hynix H8MBX00U0MER-0EM */
+static struct omap_sdrc_params h8mbx00u0mer0em_sdrc_params[] = {
+ [0] = {
+ .rate = 200000000,
+ .actim_ctrla = 0xa2e1b4c6,
+ .actim_ctrlb = 0x0002131c,
+ .rfr_ctrl = 0x0005e601,
+ .mr = 0x00000032,
+ },
+ [1] = {
+ .rate = 166000000,
+ .actim_ctrla = 0x629db4c6,
+ .actim_ctrlb = 0x00012214,
+ .rfr_ctrl = 0x0004dc01,
+ .mr = 0x00000032,
+ },
+ [2] = {
+ .rate = 100000000,
+ .actim_ctrla = 0x51912284,
+ .actim_ctrlb = 0x0002120e,
+ .rfr_ctrl = 0x0002d101,
+ .mr = 0x00000022,
+ },
+ [3] = {
+ .rate = 83000000,
+ .actim_ctrla = 0x31512283,
+ .actim_ctrlb = 0x0001220a,
+ .rfr_ctrl = 0x00025501,
+ .mr = 0x00000022,
+ },
+ [4] = {
+ .rate = 0
+ },
+};
+
+#endif
+
diff --git a/arch/arm/mach-omap2/sdrc.h b/arch/arm/mach-omap2/sdrc.h
index 1a8bbd0..3af2ff9 100644
--- a/arch/arm/mach-omap2/sdrc.h
+++ b/arch/arm/mach-omap2/sdrc.h
@@ -50,7 +50,8 @@
#else
#define OMAP242X_SDRC_REGADDR(reg) IO_ADDRESS(OMAP2420_SDRC_BASE + (reg))
#define OMAP243X_SDRC_REGADDR(reg) IO_ADDRESS(OMAP243X_SDRC_BASE + (reg))
-#define OMAP34XX_SDRC_REGADDR(reg) IO_ADDRESS(OMAP343X_SDRC_BASE + (reg))
+#define OMAP34XX_SDRC_REGADDR(reg) L3_IO_ADDRESS \
+ (OMAP343X_SDRC_BASE + (reg))
#endif /* __ASSEMBLER__ */
#endif
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 9d59eb1..b4a97d3 100755
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -21,6 +21,7 @@
#include <linux/clk.h>
#ifdef CONFIG_SERIAL_OMAP
#include <linux/platform_device.h>
+#include <mach/omap-serial.h>
#endif
#include <linux/io.h>
#include <linux/wakelock.h>
@@ -48,6 +49,10 @@
u32 wk_mask;
u32 padconf;
+ u32 rts_padconf;
+ int rts_override;
+ u16 rts_padvalue;
+
struct clk *ick;
struct clk *fck;
int clocked;
@@ -55,6 +60,7 @@
struct plat_serial8250_port *p;
struct list_head node;
+ int use_dma;
#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
int context_valid;
@@ -65,6 +71,7 @@
u16 sysc;
u16 scr;
u16 wer;
+ u16 mcr;
#endif
};
@@ -79,8 +86,6 @@
wake_lock_timeout(&omap_serial_wakelock, 10*HZ);
}
-
-
static struct plat_serial8250_port serial_platform_data[] = {
{
.membase = IO_ADDRESS(OMAP_UART1_BASE),
@@ -111,7 +116,7 @@
.pm = omap_serial_pm,
},
#define QUART_CLK (1843200)
-#ifdef CONFIG_MACH_OMAP_ZOOM2
+#if defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)
{
.membase = ZOOM2_QUART_VIRT,
.mapbase = 0x10000000,
@@ -162,7 +167,7 @@
}
};
-#ifdef CONFIG_MACH_OMAP_ZOOM2
+#if defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)
static struct resource omap2_quaduart_resources[] = {
{
.start = 0x10000000,
@@ -195,7 +200,7 @@
.resource = omap2_uart3_resources,
};
-#ifdef CONFIG_MACH_OMAP_ZOOM2
+#if defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)
static struct platform_device quaduart_device = {
.name = "omap-uart",
@@ -209,7 +214,7 @@
&uart1_device,
&uart2_device,
&uart3_device,
-#ifdef CONFIG_MACH_OMAP_ZOOM2
+#if defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)
&quaduart_device
#endif
};
@@ -262,9 +267,6 @@
u16 lcr = 0;
struct plat_serial8250_port *p = uart->p;
- if (!enable_off_mode)
- return;
-
lcr = serial_read_reg(p, UART_LCR);
serial_write_reg(p, UART_LCR, 0xBF);
uart->dll = serial_read_reg(p, UART_DLL);
@@ -275,6 +277,10 @@
uart->scr = serial_read_reg(p, UART_OMAP_SCR);
uart->wer = serial_read_reg(p, UART_OMAP_WER);
+ serial_write_reg(p, UART_LCR, 0x80);
+ uart->mcr = serial_read_reg(p, UART_MCR);
+ serial_write_reg(p, UART_LCR, lcr);
+
uart->context_valid = 1;
}
@@ -283,9 +289,6 @@
u16 efr = 0;
struct plat_serial8250_port *p = uart->p;
- if (!enable_off_mode)
- return;
-
if (!uart->context_valid)
return;
@@ -302,7 +305,14 @@
serial_write_reg(p, UART_DLM, uart->dlh);
serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
serial_write_reg(p, UART_IER, uart->ier);
- serial_write_reg(p, UART_FCR, 0xA1);
+ if (uart->use_dma)
+ serial_write_reg(p, UART_FCR, 0x59);
+ else
+ serial_write_reg(p, UART_FCR, 0x51);
+
+ serial_write_reg(p, UART_LCR, 0x80);
+ serial_write_reg(p, UART_MCR, uart->mcr);
+
serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
serial_write_reg(p, UART_EFR, efr);
serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
@@ -323,21 +333,41 @@
u16 sysc;
sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
- if (enable)
- sysc |= 0x2 << 3;
- else
- sysc |= 0x1 << 3;
-
+ if (enable) {
+ /* Errata 2.15: Force idle if in DMA mode */
+ sysc |= uart->use_dma ? 0x0 : (0x2 << 3);
+ } else {
+ sysc |= 0x1 << 3;
+ }
serial_write_reg(p, UART_OMAP_SYSC, sysc);
}
+static inline void omap_uart_disable_rtspullup(struct omap_uart_state *uart)
+{
+ if (!uart->rts_padconf || !uart->rts_override)
+ return;
+ omap_ctrl_writew(uart->rts_padvalue, uart->rts_padconf);
+ uart->rts_override = 0;
+}
+
+static inline void omap_uart_enable_rtspullup(struct omap_uart_state *uart)
+{
+ if (!uart->rts_padconf || uart->rts_override)
+ return;
+
+ uart->rts_padvalue = omap_ctrl_readw(uart->rts_padconf);
+ omap_ctrl_writew(0x118 | 0x7, uart->rts_padconf);
+ uart->rts_override = 1;
+}
+
static inline void omap_uart_restore(struct omap_uart_state *uart)
{
omap_uart_enable_clocks(uart);
omap_uart_restore_context(uart);
}
-static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
+static inline void omap_uart_disable_clocks(struct omap_uart_state *uart,
+ int power_state)
{
if (!uart->clocked)
return;
@@ -345,7 +375,9 @@
if (uart->num == 3)
return;
- omap_uart_save_context(uart);
+ if (power_state == PWRDM_POWER_OFF)
+ omap_uart_save_context(uart);
+
uart->clocked = 0;
clk_disable(uart->ick);
clk_disable(uart->fck);
@@ -377,16 +409,27 @@
{
struct omap_uart_state *uart = (struct omap_uart_state *)data;
+#ifdef CONFIG_SERIAL_OMAP
+ /* check if the uart port is active
+ * if port is active then dont allow
+ * sleep.
+ */
+ if (omap_uart_active(uart->num)) {
+ omap_uart_block_sleep(uart);
+ return;
+ }
+#endif
omap_uart_allow_sleep(uart);
}
-void omap_uart_prepare_idle(int num)
+void omap_uart_prepare_idle(int num, int power_state)
{
struct omap_uart_state *uart;
list_for_each_entry(uart, &uart_list, node) {
if (num == uart->num && uart->can_sleep) {
- omap_uart_disable_clocks(uart);
+ omap_uart_enable_rtspullup(uart);
+ omap_uart_disable_clocks(uart, power_state);
return;
}
}
@@ -399,6 +442,7 @@
list_for_each_entry(uart, &uart_list, node) {
if (num == uart->num) {
omap_uart_restore(uart);
+ omap_uart_disable_rtspullup(uart);
/* Check for IO pad wakeup */
if (cpu_is_omap34xx() && uart->padconf) {
@@ -426,6 +470,29 @@
}
}
+int uart_in_dma_mode(int num)
+{
+ int using_dma = 0;
+ switch (num) {
+ case 0:
+ #ifdef CONFIG_SERIAL_OMAP_DMA_UART1
+ using_dma = 1;
+ #endif
+ break;
+ case 1:
+ #ifdef CONFIG_SERIAL_OMAP_DMA_UART2
+ using_dma = 1;
+ #endif
+ break;
+ case 2:
+ #ifdef CONFIG_SERIAL_OMAP_DMA_UART3
+ using_dma = 1;
+ #endif
+ break;
+ }
+ return using_dma;
+}
+
int omap_uart_can_sleep(void)
{
struct omap_uart_state *uart;
@@ -467,9 +534,46 @@
static u32 sleep_timeout = DEFAULT_TIMEOUT;
-static void omap_uart_idle_init(struct omap_uart_state *uart)
+static void omap_uart_wakeup_enable(struct omap_uart_state *uart)
{
u32 v;
+ /* Set wake-enable bit */
+ if (uart->wk_en && uart->wk_mask) {
+ v = __raw_readl(uart->wk_en);
+ v |= uart->wk_mask;
+ __raw_writel(v, uart->wk_en);
+ }
+
+ /* Ensure IOPAD wake-enables are set */
+ if (cpu_is_omap34xx() && uart->padconf) {
+ u16 v;
+
+ v = omap_ctrl_readw(uart->padconf);
+ v |= OMAP3_PADCONF_WAKEUPENABLE0;
+ omap_ctrl_writew(v, uart->padconf);
+ }
+}
+
+
+static void omap_uart_rtspad_init(struct omap_uart_state *uart)
+{
+ if (!cpu_is_omap34xx())
+ return;
+ switch (uart->num) {
+ case 0:
+ uart->rts_padconf = 0x17e;
+ break;
+ case 1:
+ uart->rts_padconf = 0x176;
+ break;
+ default:
+ uart->rts_padconf = 0;
+ break;
+ }
+}
+
+static void omap_uart_idle_init(struct omap_uart_state *uart)
+{
struct plat_serial8250_port *p = uart->p;
int ret, irq_flags = 0;
@@ -538,21 +642,18 @@
uart->padconf = 0;
}
- /* Set wake-enable bit */
- if (uart->wk_en && uart->wk_mask) {
- v = __raw_readl(uart->wk_en);
- v |= uart->wk_mask;
- __raw_writel(v, uart->wk_en);
- }
+#ifdef CONFIG_SERIAL_OMAP
+ /* use rx as wakeup source only for uart3,
+ * uart1,2 will wakeup using CTS PIN
+ * This is supported by omap-serial
+ * driver
+ */
+ if (uart->num == 2 || uart->num == 3)
+ omap_uart_wakeup_enable(uart);
- /* Ensure IOPAD wake-enables are set */
- if (cpu_is_omap34xx() && uart->padconf) {
- u16 v;
-
- v = omap_ctrl_readw(uart->padconf);
- v |= OMAP3_PADCONF_WAKEUPENABLE0;
- omap_ctrl_writew(v, uart->padconf);
- }
+#elif CONFIG_SERIAL_8250
+ omap_uart_wakeup_enable(uart);
+#endif
p->flags |= UPF_SHARE_IRQ;
@@ -567,18 +668,24 @@
WARN_ON(ret);
}
-void omap_uart_enable_irqs(int enable)
+int omap_uart_enable_irqs(int enable)
{
- int ret;
+ int ret = 0;
struct omap_uart_state *uart;
list_for_each_entry(uart, &uart_list, node) {
- if (enable)
- ret = request_irq(uart->p->irq, omap_uart_interrupt,
- IRQF_SHARED, "serial idle", (void *)uart);
- else
+ if (enable) {
+ int irq_flags = 0;
+ if (uart->p->flags & UPF_SHARE_IRQ)
+ irq_flags |= IRQF_SHARED;
+ if (uart->p->flags & UPF_TRIGGER_HIGH)
+ irq_flags |= IRQF_TRIGGER_HIGH;
+ ret += request_irq(uart->p->irq, omap_uart_interrupt,
+ irq_flags, "serial idle", (void *)uart);
+ } else
free_irq(uart->p->irq, (void *)uart);
}
+ return ret;
}
static ssize_t sleep_timeout_show(struct kobject *kobj,
@@ -674,8 +781,11 @@
uart->p = p;
list_add(&uart->node, &uart_list);
+ uart->use_dma = uart_in_dma_mode(i);
+
omap_uart_enable_clocks(uart);
omap_uart_reset(uart);
+ omap_uart_rtspad_init(uart);
omap_uart_idle_init(uart);
}
}
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
index aedcf94..8796620 100644
--- a/arch/arm/mach-omap2/sleep34xx.S
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -39,7 +39,7 @@
#define PM_PREPWSTST_MPU_V OMAP34XX_PRM_REGADDR(MPU_MOD, \
OMAP3430_PM_PREPWSTST)
#define CM_IDLEST1_CORE_V OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST1)
-#define SDRC_SCRATCHPAD_SEM_V 0xd800291C
+#define SDRC_SCRATCHPAD_SEM_V IO_ADDRESS(L4_34XX_BASE + 0x291C)
/*
* This is the physical address of the register as specified
@@ -260,8 +260,12 @@
and r2, r2, #0x3
cmp r2, #0x0 @ Check if target power state was OFF or RET
moveq r9, #0x3 @ MPU OFF => L1 and L2 lost
+ beq restore_from_off
+ cmp r2, #0x1
+ moveq r9, #0x3
movne r9, #0x1 @ Only L1 and L2 lost => avoid L2 invalidation
bne logic_l1_restore
+restore_from_off:
ldr r0, control_stat
ldr r1, [r0]
and r1, #0x700
@@ -277,12 +281,14 @@
mcr p15, 0, r0, c7, c10, 5 @ data memory barrier
.word 0xE1600071 @ call SMI monitor (smi #1)
/* Write to Aux control register to set some bits */
+ ldr r4, scratchpad_base
+ ldr r3, [r4, #0xBC] @ r3 points to the location which has the value
+ @ to be written to Aux Control
mov r0, #42 @ set service ID for PPA
mov r12, r0 @ copy secure Service ID in r12
mov r1, #0 @ set task id for ROM code in r1
mov r2, #4 @ set some flags in r2, r6
mov r6, #0xff
- adr r3, write_aux_control_params @ r3 points to parameters
mcr p15, 0, r0, c7, c10, 4 @ data write barrier
mcr p15, 0, r0, c7, c10, 5 @ data memory barrier
.word 0xE1600071 @ call SMI monitor (smi #1)
@@ -290,14 +296,14 @@
b logic_l1_restore
l2_inv_api_params:
.word 0x1, 0x00
-write_aux_control_params:
- .word 0x1, 0x72
l2_inv_gp:
/* Execute smi to invalidate L2 cache */
mov r12, #0x1 @ set up to invalide L2
smi: .word 0xE1600070 @ Call SMI monitor (smieq)
+ ldr r4, scratchpad_base
+ ldr r3, [r4, #0xBC]
+ ldr r0, [r3]
/* Write to Aux control register to set some bits */
- mov r0, #0x72
mov r12, #0x3
.word 0xE1600070 @ Call SMI monitor (smieq)
logic_l1_restore:
@@ -306,8 +312,7 @@
* and flush branch target cache */
mcr p15, 0, r1, c7, c5, 0
- ldr r4, scratchpad_base
- ldr r3, [r4,#0xBC]
+ add r3, r3, #0x4
ldmia r3!, {r4-r6}
mov sp, r4
msr spsr_cxsf, r5
@@ -328,7 +333,12 @@
/* data fault status Register */
MCR p15, 0, r9, c5, c0, 0
+#ifdef CONFIG_CPU_USER_L2_PLE_ACCESS
+ ldmia r3!,{r4-r9}
+#else
ldmia r3!,{r4-r8}
+#endif
+
/* instruction fault status Register */
MCR p15, 0, r4, c5, c0, 1
/*Data Auxiliary Fault Status Register */
@@ -339,6 +349,12 @@
MCR p15, 0, r7, c6, c0, 0
/*Instruction Fault Address Register*/
MCR p15, 0, r8, c6, c0, 2
+
+#ifdef CONFIG_CPU_USER_L2_PLE_ACCESS
+ /* PLE User Accessibility Register */
+ MCR p15, 0, r9, c11, c1, 0
+#endif
+
ldmia r3!,{r4-r7}
/* user r/w thread and process ID */
@@ -424,6 +440,10 @@
save_context_wfi:
/*b save_context_wfi*/ @ enable to debug save code
mov r8, r0 /* Store SDRAM address in r8 */
+ /* Save AUXCR register */
+ mrc p15, 0, r4, c1, c0, 1
+ str r4, [r8]
+ add r8, r8, #0x4
/* Check what that target sleep state is:stored in r1*/
/* 1 - Only L1 and logic lost */
/* 2 - Only L2 lost */
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
old mode 100644
new mode 100755
index 15e8e14..eae0aa5
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -36,7 +36,26 @@
#include "smartreflex.h"
#include "prm-regbits-34xx.h"
-#define MAX_TRIES 100
+/* The timeout values have been measured using 32Khz timer
+ * for rover codebase by Nishant Menon. It is found to be
+ * working for Zoom2 also. Should get proper timeout values
+ * from h/w team. The SR disbale time out value 3472 was found
+ * to be insufficient on zoom2 where we get occasional timeouts.
+ * Increasing it to a safer value.
+*/
+#define SR_DISABLE_TIMEOUT 10000
+#define VP_TRANXDONE_TIMEOUT 62
+#define VP_IDLE_TIMEOUT 3472
+
+#define INTC_MIR0 0x48200084
+#define INTC_MIR_CLEAR0 0x48200088
+#define INTC_MIR_SET0 0x4820008C
+#define INTC_SR1 (0x1 << 18)
+#define INTC_SR2 (0x1 << 19)
+#define ERRCONFIG_STATUS_MASK (ERRCONFIG_VPBOUNDINTST | \
+ ERRCONFIG_MCUBOUNDINTST | ERRCONFIG_MCUDISACKINTST)
+
+
struct omap_sr {
int srid;
@@ -46,7 +65,7 @@
u32 clk_length;
u32 req_opp_no;
u32 opp1_nvalue, opp2_nvalue, opp3_nvalue, opp4_nvalue;
- u32 opp5_nvalue;
+ u32 opp5_nvalue, opp6_nvalue;
u32 senp_mod, senn_mod;
void __iomem *srbase_addr;
void __iomem *vpbase_addr;
@@ -68,6 +87,8 @@
u32 value)
{
u32 reg_val;
+ if (offset == ERRCONFIG)
+ mask |= ERRCONFIG_STATUS_MASK;
reg_val = __raw_readl(SR_REGADDR(offset));
reg_val &= ~mask;
@@ -88,6 +109,10 @@
return -1;
}
+ if (cpu_is_omap3630())
+ sr_modify_reg(sr, ERRCONFIG, SR_IDLEMODE_MASK,
+ SR_SMART_IDLE);
+ else
/* set fclk- active , iclk- idle */
sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
SR_CLKACTIVITY_IOFF_FON);
@@ -97,6 +122,10 @@
static void sr_clk_disable(struct omap_sr *sr)
{
+ if (cpu_is_omap3630())
+ sr_modify_reg(sr, ERRCONFIG, SR_IDLEMODE_MASK,
+ SR_FORCE_IDLE);
+ else
/* set fclk, iclk- idle */
sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
SR_CLKACTIVITY_IOFF_FOFF);
@@ -150,6 +179,31 @@
(rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
}
+void sr_calculate_rg(u32 rfuse, u32 gain_fuse, u32 delta_nt,
+ u32 *rnsen, u32 *sengain)
+{
+ u32 nadj;
+ nadj = ((1 << (gain_fuse + 8)) / rfuse) + delta_nt;
+ cal_reciprocal(nadj, sengain, rnsen);
+}
+
+/* extrapolate OPP6 nvalues from OPP5 value */
+static u32 calculate_opp_nvalue(u32 opp5_nvalue, u32 delta_p, u32 delta_n)
+{
+ u32 sen_pgain_fuse, sen_ngain_fuse, sen_prn_fuse, sen_nrn_fuse;
+ u32 sen_nrn, sen_ngain, sen_prn, sen_pgain;
+ sen_pgain_fuse = (opp5_nvalue & 0x00F0000) >> 0x14;
+ sen_ngain_fuse = (opp5_nvalue & 0x000F0000) >> 0x10;
+ sen_prn_fuse = (opp5_nvalue & 0x0000FF00) >> 0x08;
+ sen_nrn_fuse = (opp5_nvalue & 0x000000FF);
+ sr_calculate_rg(sen_nrn_fuse, sen_ngain_fuse, delta_n, &sen_nrn,
+ &sen_ngain);
+ sr_calculate_rg(sen_prn_fuse, sen_pgain_fuse, delta_p, &sen_prn,
+ &sen_pgain);
+ return (sen_pgain << 0x14) | (sen_ngain << 0x10)
+ | (sen_prn << 0x08) | (sen_nrn);
+}
+
/* determine the current OPP from the frequency
* we need to give this function last element of OPP rate table
* and the frequency
@@ -234,6 +288,10 @@
OMAP343X_CONTROL_FUSE_OPP2_VDD1);
sr->opp1_nvalue = omap_ctrl_readl(
OMAP343X_CONTROL_FUSE_OPP1_VDD1);
+ if (sr->opp5_nvalue) {
+ sr->opp6_nvalue = calculate_opp_nvalue(sr->opp5_nvalue,
+ 227, 379);
+ }
} else if (sr->srid == SR2) {
sr->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
OMAP343X_SR2_SENNENABLE_MASK) >>
@@ -256,22 +314,54 @@
static void sr_set_testing_nvalues(struct omap_sr *sr)
{
if (sr->srid == SR1) {
+ if (cpu_is_omap3630()) {
+ sr->senp_mod = 0x1;
+ sr->senn_mod = 0x1;
+
+ /* calculate nvalues for each opp */
+ sr->opp1_nvalue = cal_test_nvalue(557, 470);
+ sr->opp2_nvalue = cal_test_nvalue(997, 844);
+ sr->opp3_nvalue = cal_test_nvalue(1556, 1330);
+ sr->opp4_nvalue = cal_test_nvalue(1728, 1480);
+ } else {
sr->senp_mod = 0x03; /* SenN-M5 enabled */
sr->senn_mod = 0x03;
/* calculate nvalues for each opp */
- sr->opp5_nvalue = cal_test_nvalue(0xacd + 0x330, 0x848 + 0x330);
- sr->opp4_nvalue = cal_test_nvalue(0x964 + 0x2a0, 0x727 + 0x2a0);
- sr->opp3_nvalue = cal_test_nvalue(0x85b + 0x200, 0x655 + 0x200);
- sr->opp2_nvalue = cal_test_nvalue(0x506 + 0x1a0, 0x3be + 0x1a0);
- sr->opp1_nvalue = cal_test_nvalue(0x373 + 0x100, 0x28c + 0x100);
+ sr->opp1_nvalue = cal_test_nvalue(0x373 + 0x100,
+ 0x28c + 0x100);
+ sr->opp2_nvalue = cal_test_nvalue(0x506 + 0x1a0,
+ 0x3be + 0x1a0);
+ sr->opp3_nvalue = cal_test_nvalue(0x85b + 0x200,
+ 0x655 + 0x200);
+ sr->opp4_nvalue = cal_test_nvalue(0x964 + 0x2a0,
+ 0x727 + 0x2a0);
+ sr->opp5_nvalue = cal_test_nvalue(0xacd + 0x330,
+ 0x848 + 0x330);
+ }
+ if (sr->opp5_nvalue) {
+ sr->opp6_nvalue = calculate_opp_nvalue(sr->opp5_nvalue,
+ 227, 379);
+ }
} else if (sr->srid == SR2) {
- sr->senp_mod = 0x03;
- sr->senn_mod = 0x03;
+ if (cpu_is_omap3630()) {
+ sr->senp_mod = 0x1;
+ sr->senn_mod = 0x1;
- sr->opp3_nvalue = cal_test_nvalue(0x76f + 0x200, 0x579 + 0x200);
- sr->opp2_nvalue = cal_test_nvalue(0x4f5 + 0x1c0, 0x390 + 0x1c0);
- sr->opp1_nvalue = cal_test_nvalue(0x359, 0x25d);
+ sr->opp1_nvalue = cal_test_nvalue(556, 468);
+ sr->opp2_nvalue = cal_test_nvalue(1099, 933);
+
+ } else {
+ sr->senp_mod = 0x03;
+ sr->senn_mod = 0x03;
+
+ sr->opp1_nvalue = cal_test_nvalue(0x359, 0x25d);
+ sr->opp2_nvalue = cal_test_nvalue(0x4f5 + 0x1c0,
+ 0x390 + 0x1c0);
+ sr->opp3_nvalue = cal_test_nvalue(0x76f + 0x200,
+ 0x579 + 0x200);
+ }
+
}
}
@@ -292,17 +382,20 @@
if (srid == SR1) {
target_opp_no = get_vdd1_opp();
- if (!target_opp_no)
+ if (!target_opp_no) {
/* Assume Nominal OPP as current OPP unknown */
vsel = mpu_opps[VDD1_OPP3].vsel;
+ target_opp_no = VDD1_OPP3;
+ }
else
vsel = mpu_opps[target_opp_no].vsel;
vpconfig = PRM_VP1_CONFIG_ERROROFFSET |
- PRM_VP1_CONFIG_ERRORGAIN |
- PRM_VP1_CONFIG_TIMEOUTEN |
- vsel << OMAP3430_INITVOLTAGE_SHIFT;
-
+ OMAP3430_TIMEOUTEN |
+ vsel << OMAP3430_INITVOLTAGE_SHIFT |
+ ((target_opp_no < VDD1_OPP3)
+ ? PRM_VP1_CONFIG_ERRORGAIN_OPPLOW
+ : PRM_VP1_CONFIG_ERRORGAIN_OPPHIGH);
prm_write_mod_reg(vpconfig, OMAP3430_GR_MOD,
OMAP3_PRM_VP1_CONFIG_OFFSET);
prm_write_mod_reg(PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN |
@@ -322,11 +415,11 @@
OMAP3_PRM_VP1_VLIMITTO_OFFSET);
/* Trigger initVDD value copy to voltage processor */
- prm_set_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD,
+ prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
OMAP3_PRM_VP1_CONFIG_OFFSET);
/* Clear initVDD copy trigger bit */
- prm_clear_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD,
+ prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
OMAP3_PRM_VP1_CONFIG_OFFSET);
/* Force update of voltage */
@@ -338,17 +431,20 @@
} else if (srid == SR2) {
target_opp_no = get_vdd2_opp();
- if (!target_opp_no)
+ if (!target_opp_no) {
/* Assume Nominal OPP */
vsel = l3_opps[VDD2_OPP3].vsel;
+ target_opp_no = VDD2_OPP3;
+ }
else
vsel = l3_opps[target_opp_no].vsel;
vpconfig = PRM_VP2_CONFIG_ERROROFFSET |
- PRM_VP2_CONFIG_ERRORGAIN |
- PRM_VP2_CONFIG_TIMEOUTEN |
- vsel << OMAP3430_INITVOLTAGE_SHIFT;
-
+ OMAP3430_TIMEOUTEN |
+ vsel << OMAP3430_INITVOLTAGE_SHIFT |
+ ((target_opp_no < VDD2_OPP3)
+ ? PRM_VP2_CONFIG_ERRORGAIN_OPPLOW
+ : PRM_VP2_CONFIG_ERRORGAIN_OPPHIGH);
prm_write_mod_reg(vpconfig, OMAP3430_GR_MOD,
OMAP3_PRM_VP2_CONFIG_OFFSET);
prm_write_mod_reg(PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN |
@@ -368,11 +464,11 @@
OMAP3_PRM_VP2_VLIMITTO_OFFSET);
/* Trigger initVDD value copy to voltage processor */
- prm_set_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD,
+ prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
OMAP3_PRM_VP2_CONFIG_OFFSET);
/* Clear initVDD copy trigger bit */
- prm_clear_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD,
+ prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
OMAP3_PRM_VP2_CONFIG_OFFSET);
/* Force update of voltage */
@@ -385,7 +481,7 @@
}
}
-static void sr_configure(struct omap_sr *sr)
+static void sr_configure(struct omap_sr *sr, u32 target_opp)
{
u32 sr_config;
u32 senp_en , senn_en;
@@ -396,38 +492,78 @@
senp_en = sr->senp_mod;
senn_en = sr->senn_mod;
if (sr->srid == SR1) {
- sr_config = SR1_SRCONFIG_ACCUMDATA |
+ if (cpu_is_omap3630()) {
+ sr_config = SR1_SRCONFIG_ACCUMDATA |
(sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
- SRCONFIG_MINMAXAVG_EN |
+ (senn_en << SRCONFIG_SENNENABLE_SHIFT_36XX) |
+ (senp_en << SRCONFIG_SENPENABLE_SHIFT_36XX);
+
+ sr_write_reg(sr, SRCONFIG, sr_config);
+ sr_write_reg(sr, AVGWEIGHT,
+ SR1_AVGWEIGHT_SENPAVGWEIGHT |
+ SR1_AVGWEIGHT_SENNAVGWEIGHT);
+
+ sr_modify_reg(sr, ERRCONFIG_36XX, (SR_ERRWEIGHT_MASK |
+ SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
+ (SR1_ERRWEIGHT | SR1_ERRMAXLIMIT |
+ ((target_opp < VDD1_OPP3) ? SR1_ERRMINLIMIT_OPPLOW
+ : SR1_ERRMINLIMIT_OPPHIGH)));
+ } else {
+ sr_config = SR1_SRCONFIG_ACCUMDATA |
+ (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+ SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
(senn_en << SRCONFIG_SENNENABLE_SHIFT) |
(senp_en << SRCONFIG_SENPENABLE_SHIFT) |
SRCONFIG_DELAYCTRL;
- sr_write_reg(sr, SRCONFIG, sr_config);
- sr_write_reg(sr, AVGWEIGHT, SR1_AVGWEIGHT_SENPAVGWEIGHT |
+ sr_write_reg(sr, SRCONFIG, sr_config);
+ sr_write_reg(sr, AVGWEIGHT,
+ SR1_AVGWEIGHT_SENPAVGWEIGHT |
SR1_AVGWEIGHT_SENNAVGWEIGHT);
- sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
+ sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
- (SR1_ERRWEIGHT | SR1_ERRMAXLIMIT | SR1_ERRMINLIMIT));
-
+ (SR1_ERRWEIGHT | SR1_ERRMAXLIMIT |
+ ((target_opp < VDD1_OPP3) ? SR1_ERRMINLIMIT_OPPLOW
+ : SR1_ERRMINLIMIT_OPPHIGH)));
+ }
} else if (sr->srid == SR2) {
- sr_config = SR2_SRCONFIG_ACCUMDATA |
+ if (cpu_is_omap3630()) {
+ sr_config = SR2_SRCONFIG_ACCUMDATA |
(sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
- SRCONFIG_MINMAXAVG_EN |
+ (senn_en << SRCONFIG_SENNENABLE_SHIFT_36XX) |
+ (senp_en << SRCONFIG_SENPENABLE_SHIFT_36XX);
+
+ sr_write_reg(sr, SRCONFIG, sr_config);
+ sr_write_reg(sr, AVGWEIGHT,
+ SR2_AVGWEIGHT_SENPAVGWEIGHT |
+ SR2_AVGWEIGHT_SENNAVGWEIGHT);
+ sr_modify_reg(sr, ERRCONFIG_36XX, (SR_ERRWEIGHT_MASK |
+ SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
+ (SR2_ERRWEIGHT | SR2_ERRMAXLIMIT |
+ ((target_opp < VDD2_OPP3) ? SR2_ERRMINLIMIT_OPPLOW
+ : SR2_ERRMINLIMIT_OPPHIGH)));
+
+ } else {
+ sr_config = SR2_SRCONFIG_ACCUMDATA |
+ (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+ SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
(senn_en << SRCONFIG_SENNENABLE_SHIFT) |
(senp_en << SRCONFIG_SENPENABLE_SHIFT) |
SRCONFIG_DELAYCTRL;
- sr_write_reg(sr, SRCONFIG, sr_config);
- sr_write_reg(sr, AVGWEIGHT, SR2_AVGWEIGHT_SENPAVGWEIGHT |
+ sr_write_reg(sr, SRCONFIG, sr_config);
+ sr_write_reg(sr, AVGWEIGHT,
+ SR2_AVGWEIGHT_SENPAVGWEIGHT |
SR2_AVGWEIGHT_SENNAVGWEIGHT);
- sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
+ sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
- (SR2_ERRWEIGHT | SR2_ERRMAXLIMIT | SR2_ERRMINLIMIT));
-
+ (SR2_ERRWEIGHT | SR2_ERRMAXLIMIT |
+ ((target_opp < VDD2_OPP3) ? SR2_ERRMINLIMIT_OPPLOW
+ : SR2_ERRMINLIMIT_OPPHIGH)));
+ }
}
sr->is_sr_reset = 0;
}
@@ -515,6 +651,9 @@
if (sr->srid == SR1) {
switch (target_opp_no) {
+ case 6:
+ nvalue_reciprocal = sr->opp6_nvalue;
+ break;
case 5:
nvalue_reciprocal = sr->opp5_nvalue;
break;
@@ -552,20 +691,27 @@
}
if (nvalue_reciprocal == 0) {
- pr_notice("OPP%d doesn't support SmartReflex\n",
+ pr_notice("OPP%d doesn't support SmartReflex \n",
target_opp_no);
return false;
}
sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
-
+ if (cpu_is_omap3630()) {
+ /* Enable the interrupt */
+ sr_modify_reg(sr, ERRCONFIG_36XX,
+ (ERRCONFIG_VPBOUNDINTEN_36XX |
+ ERRCONFIG_VPBOUNDINTST_36XX),
+ (ERRCONFIG_VPBOUNDINTEN_36XX |
+ ERRCONFIG_VPBOUNDINTST_36XX));
+ } else {
/* Enable the interrupt */
sr_modify_reg(sr, ERRCONFIG,
(ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST |
ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST),
(ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST |
ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST));
-
+ }
if (sr->srid == SR1) {
/* set/latch init voltage */
v = prm_read_mod_reg(OMAP3430_GR_MOD,
@@ -582,7 +728,7 @@
prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
OMAP3_PRM_VP1_CONFIG_OFFSET);
/* Enable VP1 */
- prm_set_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD,
+ prm_set_mod_reg_bits(OMAP3430_VPENABLE, OMAP3430_GR_MOD,
OMAP3_PRM_VP1_CONFIG_OFFSET);
} else if (sr->srid == SR2) {
/* set/latch init voltage */
@@ -600,7 +746,7 @@
prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
OMAP3_PRM_VP2_CONFIG_OFFSET);
/* Enable VP2 */
- prm_set_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD,
+ prm_set_mod_reg_bits(OMAP3430_VPENABLE, OMAP3430_GR_MOD,
OMAP3_PRM_VP2_CONFIG_OFFSET);
}
@@ -609,45 +755,145 @@
return true;
}
-static void sr_disable(struct omap_sr *sr)
+static int vp_disable(struct omap_sr *sr)
{
- u32 i = 0;
+ u32 vp_config_offs, vp_status_offs, vp_tranxdone_st;
+ int timeout = 0;
+
+ if (sr->srid == SR1) {
+ vp_config_offs = OMAP3_PRM_VP1_CONFIG_OFFSET;
+ vp_status_offs = OMAP3_PRM_VP1_STATUS_OFFSET;
+ vp_tranxdone_st = OMAP3430_VP1_TRANXDONE_ST;
+ } else if (sr->srid == SR2) {
+ vp_config_offs = OMAP3_PRM_VP2_CONFIG_OFFSET;
+ vp_status_offs = OMAP3_PRM_VP2_STATUS_OFFSET;
+ vp_tranxdone_st = OMAP3430_VP2_TRANXDONE_ST;
+ } else {
+ pr_warning("Wrong SR id. SR %d does not exost\n", sr->srid);
+ return -1;
+ }
+
+ while (timeout < VP_TRANXDONE_TIMEOUT) {
+ prm_write_mod_reg(vp_tranxdone_st, OCP_MOD,
+ OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+ if (!(prm_read_mod_reg(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET)
+ & vp_tranxdone_st))
+ break;
+
+ udelay(1);
+ timeout++;
+ }
+
+ if (timeout == VP_TRANXDONE_TIMEOUT)
+ pr_warning("VP:TRANXDONE timeout exceeded still going ahead\
+ with disabling VP%d\n", sr->srid);
+
+ /* Disable VP */
+ prm_clear_mod_reg_bits(OMAP3430_VPENABLE, OMAP3430_GR_MOD,
+ vp_config_offs);
+
+ /* Wait for VP to be in IDLE - typical latency < 1 microsecond */
+ timeout = 0;
+ while (timeout < VP_IDLE_TIMEOUT &&
+ !(prm_read_mod_reg(OMAP3430_GR_MOD, vp_status_offs) &
+ OMAP3430_VPINIDLE)) {
+ udelay(1);
+ timeout++;
+ }
+ if (timeout == VP_IDLE_TIMEOUT)
+ pr_warning("VP%d not idle timedout\n", sr->srid);
+ return 0;
+}
+
+
+static int sr_disable(struct omap_sr *sr)
+{
+ int c = 0;
+ u32 sr_int_status = 0;
+
+ /*Disable VP before disabling SR */
+ if (vp_disable(sr))
+ return -1;
sr->is_sr_reset = 1;
+ /* Check to see if SR is already disabled.
+ * If so do nothing and return
+ */
+ if (!(sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE))
+ return 0;
+
+ /*Check if SR interrupt is enabled at INTC level */
+ if (sr->srid == SR1)
+ sr_int_status = omap_readl(INTC_MIR0) & INTC_SR1;
+ else if (sr->srid == SR2)
+ sr_int_status = omap_readl(INTC_MIR0) & INTC_SR2;
+
+ /* Mask the SR1 or SR2 interrupt at INTC level if unmasked
+ * so that the isr is not called. If this step is
+ * is not done random spurious SR1/SR2 interrupts or
+ * system suspend not working due to spurious interrupts
+ * can be ovbserved.
+ */
+ if (!sr_int_status) {
+ if (sr->srid == SR1)
+ omap_writel(INTC_SR1, INTC_MIR_SET0);
+ if (sr->srid == SR2)
+ omap_writel(INTC_SR2, INTC_MIR_SET0);
+ /* DSB is essential as none of the memory is
+ * Strongly ordered
+ */
+ dsb();
+ }
+ /* Enable MCUDisableAcknowledge interrupt, Disable VPBOUND interrupt
+ * and Clean VPBOUNT interrupt status
+ */
+ if (cpu_is_omap3430())
+ sr_modify_reg(sr, ERRCONFIG,
+ ERRCONFIG_MCUDISACKINTEN | ERRCONFIG_VPBOUNDINTEN,
+ ERRCONFIG_MCUDISACKINTEN | ERRCONFIG_VPBOUNDINTST);
/* SRCONFIG - disable SR */
sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, ~SRCONFIG_SRENABLE);
- if (sr->srid == SR1) {
- /* Wait for VP idle before disabling VP */
- while ((!prm_read_mod_reg(OMAP3430_GR_MOD,
- OMAP3_PRM_VP1_STATUS_OFFSET))
- && i++ < MAX_TRIES)
+ /* Wait for SR to be disabled.
+ * wait until ERRCONFIG.MCUDISACKINTST = 1
+ * Typical latency is < 1us.
+ */
+ if (cpu_is_omap3430()) {
+ while ((c < SR_DISABLE_TIMEOUT) &&
+ (!(sr_read_reg(sr, ERRCONFIG) &
+ ERRCONFIG_MCUDISACKINTST))) {
udelay(1);
+ c++;
+ }
+ if (c == SR_DISABLE_TIMEOUT)
+ pr_warning("SR%d not disabled\n", sr->srid);
- if (i >= MAX_TRIES)
- pr_warning("VP1 not idle, still going ahead with \
- VP1 disable\n");
- /* Disable VP1 */
- prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD,
- OMAP3_PRM_VP1_CONFIG_OFFSET);
-
- } else if (sr->srid == SR2) {
- /* Wait for VP idle before disabling VP */
- while ((!prm_read_mod_reg(OMAP3430_GR_MOD,
- OMAP3_PRM_VP2_STATUS_OFFSET))
- && i++ < MAX_TRIES)
- udelay(1);
-
- if (i >= MAX_TRIES)
- pr_warning("VP2 not idle, still going ahead with \
- VP2 disable\n");
-
- /* Disable VP2 */
- prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD,
- OMAP3_PRM_VP2_CONFIG_OFFSET);
+ /* Disable MCUDisableAcknowledge interrupt &
+ * clear pending interrupt Also enable VPBOUND interrrupt
+ */
+ sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_MCUDISACKINTEN,
+ ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_MCUDISACKINTST);
}
+
+ /* DSB is essential as none of the memory is Strongly ordered */
+ dsb();
+ /* Wait till ERRCONFIG_MCUDISACKINTST is cleared before unmasking
+ * SR interrupts. Else we can have spurious interrupts
+ */
+ if (cpu_is_omap3430())
+ while (sr_read_reg(sr, ERRCONFIG) & ERRCONFIG_MCUDISACKINTST)
+ ;
+
+ if (!sr_int_status) {
+ /* Unmask the SR interrrupts if previously unmasked*/
+ if (sr->srid == SR1)
+ omap_writel(INTC_SR1, INTC_MIR_CLEAR0);
+ if (sr->srid == SR2)
+ omap_writel(INTC_SR2, INTC_MIR_CLEAR0);
+ }
+ return 0;
}
static void change_ret_volt(struct omap_sr *sr, u32 val)
@@ -731,13 +977,16 @@
return;
if (sr->is_sr_reset == 1) {
- sr_clk_enable(sr);
- sr_configure(sr);
+ if (sr_clk_enable(sr))
+ return;
+ sr_configure(sr, target_opp_no);
}
- if (sr->is_autocomp_active == 1)
+ if (sr->is_autocomp_active == 1) {
pr_warning("SR%d: VDD autocomp is already active\n",
srid);
+ return;
+ }
sr->is_autocomp_active = 1;
if (!sr_enable(sr, target_opp_no)) {
@@ -761,7 +1010,8 @@
return -EINVAL;
if (sr->is_autocomp_active == 1) {
- sr_disable(sr);
+ if (sr_disable(sr))
+ pr_warning("Problems in SR Disable!!!!\n");
sr_clk_disable(sr);
sr->is_autocomp_active = 0;
/* Reset the volatage for current OPP */
@@ -788,7 +1038,8 @@
if (sr->is_autocomp_active == 1) {
if (sr->is_sr_reset == 1) {
/* Enable SR clks */
- sr_clk_enable(sr);
+ if (sr_clk_enable(sr))
+ return;
if (srid == SR1)
target_opp_no = get_vdd1_opp();
@@ -800,7 +1051,7 @@
Cannot configure SR\n");
}
- sr_configure(sr);
+ sr_configure(sr, target_opp_no);
if (!sr_enable(sr, target_opp_no))
sr_clk_disable(sr);
@@ -810,8 +1061,6 @@
void disable_smartreflex(int srid)
{
- u32 i = 0;
-
struct omap_sr *sr = NULL;
if (srid == SR1)
@@ -823,45 +1072,10 @@
if (sr->is_autocomp_active == 1) {
if (sr->is_sr_reset == 0) {
-
- sr->is_sr_reset = 1;
- /* SRCONFIG - disable SR */
- sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE,
- ~SRCONFIG_SRENABLE);
-
- /* Disable SR clk */
+ if (sr_disable(sr))
+ pr_warning("Problems in SR Disable!!!!\n");
+ /* Disable SR clk */
sr_clk_disable(sr);
- if (sr->srid == SR1) {
- /* Wait for VP idle before disabling VP */
- while ((!prm_read_mod_reg(OMAP3430_GR_MOD,
- OMAP3_PRM_VP1_STATUS_OFFSET))
- && i++ < MAX_TRIES)
- udelay(1);
-
- if (i >= MAX_TRIES)
- pr_warning("VP1 not idle, still going \
- ahead with VP1 disable\n");
-
- /* Disable VP1 */
- prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE,
- OMAP3430_GR_MOD,
- OMAP3_PRM_VP1_CONFIG_OFFSET);
- } else if (sr->srid == SR2) {
- /* Wait for VP idle before disabling VP */
- while ((!prm_read_mod_reg(OMAP3430_GR_MOD,
- OMAP3_PRM_VP2_STATUS_OFFSET))
- && i++ < MAX_TRIES)
- udelay(1);
-
- if (i >= MAX_TRIES)
- pr_warning("VP2 not idle, still going \
- ahead with VP2 disable\n");
-
- /* Disable VP2 */
- prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE,
- OMAP3430_GR_MOD,
- OMAP3_PRM_VP2_CONFIG_OFFSET);
- }
/* Reset the volatage for current OPP */
sr_reset_voltage(srid);
}
@@ -877,13 +1091,13 @@
int sr_voltagescale_vcbypass(u32 target_opp, u32 current_opp,
u8 target_vsel, u8 current_vsel)
{
- int sr_status = 0;
u32 vdd, target_opp_no, current_opp_no;
u32 vc_bypass_value;
u32 reg_addr = 0;
u32 loop_cnt = 0, retries_cnt = 0;
u32 t2_smps_steps = 0;
u32 t2_smps_delay = 0;
+ u32 error_gain;
if (omap3_volscale_vcbypass_fun)
return omap3_volscale_vcbypass_fun(target_opp, current_opp,
@@ -894,9 +1108,12 @@
current_opp_no = get_opp_no(current_opp);
if (vdd == VDD1_OPP) {
- sr_status = sr_stop_vddautocomap(SR1);
t2_smps_steps = abs(target_vsel - current_vsel);
-
+ error_gain = ((target_opp_no < VDD1_OPP3)
+ ? PRM_VP1_CONFIG_ERRORGAIN_OPPLOW
+ : PRM_VP1_CONFIG_ERRORGAIN_OPPHIGH);
+ prm_rmw_mod_reg_bits(OMAP3430_ERRORGAIN_MASK, error_gain,
+ OMAP3430_GR_MOD, OMAP3_PRM_VP1_CONFIG_OFFSET);
prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
(target_vsel << OMAP3430_VC_CMD_ON_SHIFT),
OMAP3430_GR_MOD,
@@ -904,9 +1121,12 @@
reg_addr = R_VDD1_SR_CONTROL;
} else if (vdd == VDD2_OPP) {
- sr_status = sr_stop_vddautocomap(SR2);
t2_smps_steps = abs(target_vsel - current_vsel);
-
+ error_gain = ((target_opp_no < VDD2_OPP3)
+ ? PRM_VP2_CONFIG_ERRORGAIN_OPPLOW
+ : PRM_VP2_CONFIG_ERRORGAIN_OPPHIGH);
+ prm_rmw_mod_reg_bits(OMAP3430_ERRORGAIN_MASK, error_gain,
+ OMAP3430_GR_MOD, OMAP3_PRM_VP2_CONFIG_OFFSET);
prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
(target_vsel << OMAP3430_VC_CMD_ON_SHIFT),
OMAP3430_GR_MOD,
@@ -947,13 +1167,6 @@
t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2;
udelay(t2_smps_delay);
- if (sr_status) {
- if (vdd == VDD1_OPP)
- sr_start_vddautocomap(SR1, target_opp_no);
- else if (vdd == VDD2_OPP)
- sr_start_vddautocomap(SR2, target_opp_no);
- }
-
return 0;
}
@@ -1048,8 +1261,15 @@
if (dev_id == &sr2)
try_change_ret_volt(dev_id, &vp2_volt);
- sr_modify_reg(dev_id, ERRCONFIG, ERRCONFIG_MCUBOUNDINTST,
- ERRCONFIG_MCUBOUNDINTST);
+ if (cpu_is_omap34xx()) {
+ sr_modify_reg(dev_id, ERRCONFIG, ERRCONFIG_MCUBOUNDINTST,
+ ERRCONFIG_MCUBOUNDINTST);
+
+ /* Flush posted writes to avoid spurious IRQ */
+ sr_read_reg(dev_id, ERRCONFIG);
+ } else if (cpu_is_omap3630())
+ /* Flush posted writes to avoid spurious IRQ */
+ sr_read_reg(dev_id, ERRCONFIG_36XX);
return IRQ_HANDLED;
}
@@ -1058,6 +1278,7 @@
{
int ret = 0;
u8 RdReg;
+ u32 current_opp_no;
/* Exit if OPP tables are not defined */
if (!(mpu_opps && l3_opps)) {
@@ -1126,6 +1347,27 @@
if (ret)
pr_err("sysfs_create_file failed: %d\n", ret);
+ /* Enable SR only for 3430 for now */
+ if (!cpu_is_omap3630()) {
+ if (sr1.opp3_nvalue) {
+ current_opp_no = get_vdd1_opp();
+ if (!current_opp_no) {
+ pr_err("omap3_sr_init: Current VDD1 opp unknown\n");
+ return -EINVAL;
+ }
+ sr_start_vddautocomap(SR1, current_opp_no);
+ }
+ if (sr2.opp3_nvalue) {
+ current_opp_no = get_vdd2_opp();
+ if (!current_opp_no) {
+ pr_err("omap3_sr_init: Current VDD2 opp unknown\n");
+ return -EINVAL;
+ }
+ sr_start_vddautocomap(SR2, current_opp_no);
+ pr_info("SmartReflex: enabling autocompensation\n");
+ }
+ }
+
return 0;
/*
diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h
index 7d1c470..1987740 100644
--- a/arch/arm/mach-omap2/smartreflex.h
+++ b/arch/arm/mach-omap2/smartreflex.h
@@ -29,6 +29,8 @@
#define NVALUERECIPROCAL 0x1C
#define SENERROR 0x20
#define ERRCONFIG 0x24
+#define SENERROR_36XX 0x34
+#define ERRCONFIG_36XX 0x38
/* SR Modules */
#define SR1 1
@@ -48,48 +50,42 @@
/* PRM_VP1_CONFIG */
#define PRM_VP1_CONFIG_ERROROFFSET (0x00 << 24)
-#define PRM_VP1_CONFIG_ERRORGAIN (0x20 << 16)
+#define PRM_VP1_CONFIG_ERRORGAIN_OPPLOW (0x0C << 16)
+#define PRM_VP1_CONFIG_ERRORGAIN_OPPHIGH (0x18 << 16)
#define PRM_VP1_CONFIG_INITVOLTAGE (0x30 << 8) /* 1.2 volt */
-#define PRM_VP1_CONFIG_TIMEOUTEN BIT(3)
-#define PRM_VP1_CONFIG_INITVDD BIT(2)
-#define PRM_VP1_CONFIG_FORCEUPDATE BIT(1)
-#define PRM_VP1_CONFIG_VPENABLE BIT(0)
/* PRM_VP1_VSTEPMIN */
-#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN (0x01F4 << 8)
+#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN (0x3C << 8)
#define PRM_VP1_VSTEPMIN_VSTEPMIN BIT(0)
/* PRM_VP1_VSTEPMAX */
-#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX (0x01F4 << 8)
+#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX (0x3C << 8)
#define PRM_VP1_VSTEPMAX_VSTEPMAX (0x04 << 0)
/* PRM_VP1_VLIMITTO */
-#define PRM_VP1_VLIMITTO_VDDMAX (0x3C << 24)
-#define PRM_VP1_VLIMITTO_VDDMIN (0x0 << 16)
+#define PRM_VP1_VLIMITTO_VDDMAX (0x44 << 24)
+#define PRM_VP1_VLIMITTO_VDDMIN (0x14 << 16)
#define PRM_VP1_VLIMITTO_TIMEOUT (0xFFFF << 0)
/* PRM_VP2_CONFIG */
#define PRM_VP2_CONFIG_ERROROFFSET (0x00 << 24)
-#define PRM_VP2_CONFIG_ERRORGAIN (0x20 << 16)
+#define PRM_VP2_CONFIG_ERRORGAIN_OPPLOW (0x0C << 16)
+#define PRM_VP2_CONFIG_ERRORGAIN_OPPHIGH (0x18 << 16)
#define PRM_VP2_CONFIG_INITVOLTAGE (0x30 << 8) /* 1.2 volt */
-#define PRM_VP2_CONFIG_TIMEOUTEN BIT(3)
-#define PRM_VP2_CONFIG_INITVDD BIT(2)
-#define PRM_VP2_CONFIG_FORCEUPDATE BIT(1)
-#define PRM_VP2_CONFIG_VPENABLE BIT(0)
/* PRM_VP2_VSTEPMIN */
-#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN (0x01F4 << 8)
+#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN (0x3C << 8)
#define PRM_VP2_VSTEPMIN_VSTEPMIN BIT(0)
/* PRM_VP2_VSTEPMAX */
-#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX (0x01F4 << 8)
+#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX (0x3C << 8)
#define PRM_VP2_VSTEPMAX_VSTEPMAX (0x04 << 0)
/* PRM_VP2_VLIMITTO */
-#define PRM_VP2_VLIMITTO_VDDMAX (0x2C << 24)
-#define PRM_VP2_VLIMITTO_VDDMIN (0x0 << 16)
+#define PRM_VP2_VLIMITTO_VDDMAX (0x42 << 24)
+#define PRM_VP2_VLIMITTO_VDDMIN (0x18 << 16)
#define PRM_VP2_VLIMITTO_TIMEOUT (0xFFFF << 0)
/* SRCONFIG */
@@ -105,6 +101,8 @@
#define SRCONFIG_SRCLKLENGTH_SHIFT 12
#define SRCONFIG_SENNENABLE_SHIFT 5
#define SRCONFIG_SENPENABLE_SHIFT 3
+#define SRCONFIG_SENNENABLE_SHIFT_36XX 1
+#define SRCONFIG_SENPENABLE_SHIFT_36XX 0
#define SRCONFIG_SRENABLE BIT(11)
#define SRCONFIG_SENENABLE BIT(10)
@@ -136,19 +134,32 @@
#define SR_CLKACTIVITY_IOFF_FOFF (0x00 << 20)
#define SR_CLKACTIVITY_IOFF_FON (0x02 << 20)
+/* IDLEMODE SETTINGS for OMAP3630 */
+#define SR_IDLEMODE_MASK (0x3 << 24)
+#define SR_FORCE_IDLE 0x0
+#define SR_NO_IDLE 0x1
+#define SR_SMART_IDLE 0x2
+#define SR_SMART_IDLE_WKUP 0x3
+
#define ERRCONFIG_VPBOUNDINTEN BIT(31)
#define ERRCONFIG_VPBOUNDINTST BIT(30)
+#define ERRCONFIG_VPBOUNDINTEN_36XX BIT(23)
+#define ERRCONFIG_VPBOUNDINTST_36XX BIT(22)
#define ERRCONFIG_MCUBOUNDINTEN BIT(25)
#define ERRCONFIG_MCUBOUNDINTST BIT(24)
+#define ERRCONFIG_MCUDISACKINTEN BIT(23)
+#define ERRCONFIG_MCUDISACKINTST BIT(22)
-#define SR1_ERRWEIGHT (0x07 << 16)
+#define SR1_ERRWEIGHT (0x04 << 16)
#define SR1_ERRMAXLIMIT (0x02 << 8)
-#define SR1_ERRMINLIMIT (0xFA << 0)
+#define SR1_ERRMINLIMIT_OPPLOW (0xF4 << 0)
+#define SR1_ERRMINLIMIT_OPPHIGH (0xF9 << 0)
#define SR1_IRQ 18
-#define SR2_ERRWEIGHT (0x07 << 16)
+#define SR2_ERRWEIGHT (0x04 << 16)
#define SR2_ERRMAXLIMIT (0x02 << 8)
-#define SR2_ERRMINLIMIT (0xF9 << 0)
+#define SR2_ERRMINLIMIT_OPPLOW (0xF4 << 0)
+#define SR2_ERRMINLIMIT_OPPHIGH (0xF9 << 0)
#define SR2_IRQ 19
/* T2 SMART REFLEX */
diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S
index b250535..1391455 100644
--- a/arch/arm/mach-omap2/sram34xx.S
+++ b/arch/arm/mach-omap2/sram34xx.S
@@ -33,6 +33,8 @@
#include "sdrc.h"
#include "cm.h"
+#include "prcm-common.h"
+#include "prm.h"
.text
@@ -68,6 +70,9 @@
/* CM_CLKSEL1_PLL bit settings */
#define CORE_DPLL_CLKOUT_DIV_SHIFT 0x1b
+/* PRM_RSTCTRL bit setting */
+#define EN_DPLL3_RESET 0x4
+
/*
* omap3_sram_configure_core_dpll - change DPLL3 M2 divider
* r0 = new SDRC_RFR_CTRL register contents
@@ -187,10 +192,6 @@
configure_sdrc:
ldr r11, omap3_sdrc_rfr_ctrl
str r0, [r11]
- ldr r11, omap3_sdrc_actim_ctrla
- str r1, [r11]
- ldr r11, omap3_sdrc_actim_ctrlb
- str r2, [r11]
ldr r11, omap3_sdrc_mr_0
str r6, [r11]
ldr r6, [r11] @ posted-write barrier for SDRC
@@ -221,3 +222,50 @@
ENTRY(omap3_sram_configure_core_dpll_sz)
.word . - omap3_sram_configure_core_dpll
+
+
+/* omap3_sram_configure_core_dpll_warmreset
+* Enable SDRC self refresh on idle request, put SDRC in idle,
+* wait until SDRC goes to idle
+* Enable DPLL3 reset bit in RM_RSTCTRL
+*/
+
+ENTRY(omap3_sram_configure_core_dpll_warmreset)
+
+ bl sdram_in_selfrefresh1
+ ldr r11, omap3_reset_cntrl
+ ldr r12, [r11]
+ orr r12, r12, #EN_DPLL3_RESET @ Enable DPLL3 reset bit
+ str r12, [r11]
+
+sdram_in_selfrefresh1:
+ ldr r11, omap3_sdrc_power1 @ read the SDRC_POWER register
+ ldr r12, [r11] @ read the contents of SDRC_POWER
+ mov r9, r12 @ keep a copy of SDRC_POWER bits
+ orr r12, r12, #SRFRONIDLEREQ_MASK @ enable self refresh on idle
+ str r12, [r11] @ write back to SDRC_POWER register
+ ldr r12, [r11] @ posted-write barrier for SDRC
+ ldr r11, omap3_cm_iclken1_core1 @ read the CM_ICLKEN1_CORE reg
+ ldr r12, [r11]
+ bic r12, r12, #EN_SDRC_MASK @ disable iclk bit for SDRC
+ str r12, [r11]
+wait_sdrc_idle2:
+ ldr r11, omap3_cm_idlest1_core1
+ ldr r12, [r11]
+ and r12, r12, #ST_SDRC_MASK @ check for SDRC idle
+ cmp r12, #ST_SDRC_MASK
+ bne wait_sdrc_idle2
+ bx lr
+
+omap3_reset_cntrl:
+ .word OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, RM_RSTCTRL)
+omap3_sdrc_power1:
+ .word OMAP34XX_SDRC_REGADDR(SDRC_POWER)
+omap3_cm_idlest1_core1:
+ .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST)
+omap3_cm_iclken1_core1:
+ .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_ICLKEN1)
+
+ENTRY(omap3_sram_configure_core_dpll_warmreset_sz)
+ .word . - omap3_sram_configure_core_dpll_warmreset
+
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 37ad014..7245577 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -32,13 +32,25 @@
#include <mach/irqs.h>
#include <mach/mux.h>
#include <mach/usb.h>
+#include <mach/omap-pm.h>
#define OTG_SYSCONFIG 0x404
#define OTG_SYSC_SOFTRESET BIT(1)
+#define OTG_SYSSTATUS 0x408
+#define OTG_SYSS_RESETDONE BIT(0)
+
+static struct platform_device dummy_pdev = {
+ .dev = {
+ .bus = &platform_bus_type,
+ },
+};
+
+static void __iomem *otg_base;
+static struct clk *otg_clk;
static void __init usb_musb_pm_init(void)
{
- void __iomem *otg_base;
+ struct device *dev = &dummy_pdev.dev;
if (!cpu_is_omap34xx())
return;
@@ -47,13 +59,30 @@
if (WARN_ON(!otg_base))
return;
- /* Reset OTG controller. After reset, it will be in
- * force-idle, force-standby mode. */
- __raw_writel(OTG_SYSC_SOFTRESET, otg_base + OTG_SYSCONFIG);
+ otg_clk = clk_get(dev, "hsotgusb_ick");
- iounmap(otg_base);
+ if (otg_clk && clk_enable(otg_clk)) {
+ printk(KERN_WARNING
+ "%s: Unable to enable clocks for MUSB, "
+ "cannot reset.\n", __func__);
+ } else {
+ /* Reset OTG controller. After reset, it will be in
+ * force-idle, force-standby mode. */
+ __raw_writel(OTG_SYSC_SOFTRESET, otg_base + OTG_SYSCONFIG);
+
+ while (!(OTG_SYSS_RESETDONE &
+ __raw_readl(otg_base + OTG_SYSSTATUS)))
+ cpu_relax();
+ }
+
+ if (otg_clk)
+ clk_disable(otg_clk);
}
+void usb_musb_disable_autoidle(void)
+{
+ __raw_writel(0, otg_base + OTG_SYSCONFIG);
+}
#ifdef CONFIG_USB_MUSB_SOC
static struct resource musb_resources[] = {
[0] = { /* start and end set dynamically */
@@ -135,6 +164,8 @@
.eps_bits = musb_eps,
};
+extern unsigned get_last_off_on_transaction_id(struct device *dev);
+
static struct musb_hdrc_platform_data musb_plat = {
#ifdef CONFIG_USB_MUSB_OTG
.mode = MUSB_OTG,
@@ -152,6 +183,9 @@
* "mode", and should be passed to usb_musb_init().
*/
.power = 50, /* up to 100 mA */
+
+ .context_loss_counter = get_last_off_on_transaction_id,
+ .set_vdd1_opp = omap_pm_set_min_mpu_freq,
};
static u64 musb_dmamask = DMA_32BIT_MASK;
diff --git a/arch/arm/mach-omap2/usb-ohci.c b/arch/arm/mach-omap2/usb-ohci.c
new file mode 100644
index 0000000..2110ef9
--- /dev/null
+++ b/arch/arm/mach-omap2/usb-ohci.c
@@ -0,0 +1,129 @@
+/*
+ * linux/arch/arm/mach-omap2/usb-ohci.c
+ *
+ * This file will contain the board specific details for the
+ * Synopsys OHCI host controller on OMAP3430
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Author: Vikram Pandita <vikram.pandita@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <mach/mux.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/usb.h>
+
+/* OHCI platform specific data */
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static struct resource ohci_resources[] = {
+ [0] = {
+ .start = OMAP34XX_HSUSB_HOST_BASE + 0x400,
+ .end = OMAP34XX_HSUSB_HOST_BASE + 0x400 + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = { /* general IRQ */
+ .start = 76,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32)0;
+
+static void usb_release(struct device *dev)
+{
+ /* normally not freed */
+}
+
+static struct platform_device ohci_device = {
+ .name = "ohci-omap",
+ .id = 0,
+ .dev = {
+ .release = usb_release,
+ .dma_mask = &ohci_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = NULL,
+ },
+ .num_resources = ARRAY_SIZE(ohci_resources),
+ .resource = ohci_resources,
+};
+#endif /* OHCI specific data */
+
+/* MUX settings for OHCI pins */
+/*
+ * setup_ehci_io_mux - initialize IO pad mux for USBHOST
+ */
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static void setup_ohci_io_mux(void)
+{
+
+/* Configure pin-muxing on a per-port basis
+ * We can configure a port for either ULPI PHY mode (EHCI), or for
+ * ULPI TLL mode (EHCI), or for serial PHY mode (OHCI)
+ * TODO: Add pin-mux settings for PORT 2 serial PHY mode
+ * and for OHCI TLL mode
+ */
+
+/* PHY mode for board: 750-2083-001
+ * On this board, ISP1301 is connected to Port 1
+ * Another ISP1301 transceiver is connected to Port 3
+ */
+
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT1) || \
+ defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT1)
+
+ omap_cfg_reg(AF10_3430_USB1FS_PHY_MM1_RXDP);
+ omap_cfg_reg(AG9_3430_USB1FS_PHY_MM1_RXDM);
+ omap_cfg_reg(W13_3430_USB1FS_PHY_MM1_RXRCV);
+ omap_cfg_reg(W12_3430_USB1FS_PHY_MM1_TXSE0);
+ omap_cfg_reg(W11_3430_USB1FS_PHY_MM1_TXDAT);
+ omap_cfg_reg(Y11_3430_USB1FS_PHY_MM1_TXEN_N);
+
+#endif /* Port 1 */
+
+/* PHY mode for board: 750-2099-001(C)
+ * On this board, there is only one ISP1301 connected to Port3
+ */
+
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT3) || \
+ defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT3)
+
+ omap_cfg_reg(AH3_3430_USB3FS_PHY_MM3_RXDP);
+ omap_cfg_reg(AE3_3430_USB3FS_PHY_MM3_RXDM);
+ omap_cfg_reg(AD1_3430_USB3FS_PHY_MM3_RXRCV);
+ omap_cfg_reg(AE1_3430_USB3FS_PHY_MM3_TXSE0);
+ omap_cfg_reg(AD2_3430_USB3FS_PHY_MM3_TXDAT);
+ omap_cfg_reg(AC1_3430_USB3FS_PHY_MM3_TXEN_N);
+
+#endif /* Port3: */
+
+ return;
+}
+#endif /* CONFIG_USB_OHCI_HCD */
+
+
+void __init usb_ohci_init(void)
+{
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+
+ /* Setup Pin IO MUX for OHCI */
+ if (cpu_is_omap34xx())
+ setup_ohci_io_mux();
+
+ if (platform_device_register(&ohci_device) < 0) {
+ printk(KERN_ERR "Unable to register FS-USB (OHCI) device\n");
+ return;
+ }
+#endif
+}
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 9a6a482..7a2bbd1 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -657,6 +657,14 @@
help
Say Y here to disable branch prediction. If unsure, say N.
+config CPU_USER_L2_PLE_ACCESS
+ bool "Allow user space to access cache preload engine"
+ depends on ARCH_OMAP34XX && EXPERIMENTAL
+ default n
+ help
+ Say Y to allow user space to access preload engine. This is useful
+ for data steaming to a NEON codec
+
config TLS_REG_EMUL
bool
help
@@ -717,3 +725,8 @@
select OUTER_CACHE
help
This option enables the L2 cache on XScale3.
+
+config ARM_L1_CACHE_SHIFT
+ int
+ default 6 if ARCH_OMAP3
+ default 5
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 8441351..0ab75c6 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -110,15 +110,10 @@
return err;
}
-int ioremap_page(unsigned long virt, unsigned long phys, unsigned int mtype)
+int ioremap_page(unsigned long virt, unsigned long phys,
+ const struct mem_type *mtype)
{
- const struct mem_type *type;
-
- type = get_mem_type(mtype);
- if (!type)
- return -EINVAL;
-
- return remap_area_pages(virt, __phys_to_pfn(phys), PAGE_SIZE, type);
+ return remap_area_pages(virt, __phys_to_pfn(phys), PAGE_SIZE, mtype);
}
EXPORT_SYMBOL(ioremap_page);
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 6031abc..9b54429 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -253,6 +253,7 @@
{
return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL;
}
+EXPORT_SYMBOL(get_mem_type);
/*
* Adjust the PMD section entries according to the CPU in use.
@@ -717,7 +718,7 @@
* the vmalloc area.
*/
if (__va(bank->start) >= VMALLOC_MIN ||
- __va(bank->start) < PAGE_OFFSET) {
+ __va(bank->start) < (void *)PAGE_OFFSET) {
printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx "
"(vmalloc region overlap).\n",
bank->start, bank->start + bank->size - 1);
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index cdaba2e..9088886 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -205,6 +205,10 @@
ldr r6, =0x40e040e0
mcr p15, 0, r5, c10, c2, 0 @ write PRRR
mcr p15, 0, r6, c10, c2, 1 @ write NMRR
+#ifdef CONFIG_CPU_USER_L2_PLE_ACCESS
+ mov r10, #0x3
+ mcr p15, 0, r10, c11, c1, 0
+#endif
adr r5, v7_crval
ldmia r5, {r5, r6}
mrc p15, 0, r0, c1, c0, 0 @ read control register
diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile
index 88e31f5..fc2bc02 100644
--- a/arch/arm/oprofile/Makefile
+++ b/arch/arm/oprofile/Makefile
@@ -8,6 +8,7 @@
oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
oprofile-$(CONFIG_CPU_XSCALE) += op_model_xscale.o
+oprofile-$(CONFIG_OPROFILE_OMAP_GPTIMER) += op_model_omap_gptimer.o
oprofile-$(CONFIG_OPROFILE_ARM11_CORE) += op_model_arm11_core.o
oprofile-$(CONFIG_OPROFILE_ARMV6) += op_model_v6.o
oprofile-$(CONFIG_OPROFILE_MPCORE) += op_model_mpcore.o
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index 3fcd752..add3cb4 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -133,6 +133,11 @@
ops->backtrace = arm_backtrace;
+/* comes first, so that it can be overrided by a better implementation */
+#ifdef CONFIG_OPROFILE_OMAP_GPTIMER
+ spec = &op_omap_gptimer_spec;
+#endif
+
#ifdef CONFIG_CPU_XSCALE
spec = &op_xscale_spec;
#endif
diff --git a/arch/arm/oprofile/op_arm_model.h b/arch/arm/oprofile/op_arm_model.h
index 8c4e4f6..db936da 100644
--- a/arch/arm/oprofile/op_arm_model.h
+++ b/arch/arm/oprofile/op_arm_model.h
@@ -24,6 +24,8 @@
extern struct op_arm_model_spec op_xscale_spec;
#endif
+extern struct op_arm_model_spec op_omap_gptimer_spec;
+
extern struct op_arm_model_spec op_armv6_spec;
extern struct op_arm_model_spec op_mpcore_spec;
extern struct op_arm_model_spec op_armv7_spec;
diff --git a/arch/arm/oprofile/op_model_omap_gptimer.c b/arch/arm/oprofile/op_model_omap_gptimer.c
new file mode 100644
index 0000000..c93fac9
--- /dev/null
+++ b/arch/arm/oprofile/op_model_omap_gptimer.c
@@ -0,0 +1,93 @@
+/**
+ * OMAP gptimer based event monitor driver for oprofile
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Siarhei Siamashka <siarhei.siamashka@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/oprofile.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <mach/dmtimer.h>
+
+#include "op_counter.h"
+#include "op_arm_model.h"
+
+static struct omap_dm_timer *gptimer;
+
+static int gptimer_init(void)
+{
+ return 0;
+}
+
+static int gptimer_setup(void)
+{
+ return 0;
+}
+
+static irqreturn_t gptimer_interrupt(int irq, void *arg)
+{
+ omap_dm_timer_write_status(gptimer, OMAP_TIMER_INT_OVERFLOW);
+ oprofile_add_sample(get_irq_regs(), 0);
+ return IRQ_HANDLED;
+}
+
+static int gptimer_start(void)
+{
+ int err;
+ u32 count = counter_config[0].count;
+
+ BUG_ON(gptimer != NULL);
+ /* First try to request timers from CORE power domain for OMAP3 */
+ if (cpu_is_omap34xx()) {
+ gptimer = omap_dm_timer_request_specific(10);
+ if (gptimer == NULL)
+ gptimer = omap_dm_timer_request_specific(11);
+ }
+ /* Just any timer would be fine */
+ if (gptimer == NULL)
+ gptimer = omap_dm_timer_request();
+ if (gptimer == NULL)
+ return -ENODEV;
+
+ omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_32_KHZ);
+ err = request_irq(omap_dm_timer_get_irq(gptimer), gptimer_interrupt,
+ IRQF_DISABLED, "oprofile gptimer", NULL);
+ if (err) {
+ omap_dm_timer_free(gptimer);
+ gptimer = NULL;
+ printk(KERN_ERR "oprofile: unable to request gptimer IRQ\n");
+ return err;
+ }
+
+ if (count < 1)
+ count = 1;
+
+ omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - count);
+ omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
+ return 0;
+}
+
+static void gptimer_stop(void)
+{
+ omap_dm_timer_set_int_enable(gptimer, 0);
+ free_irq(omap_dm_timer_get_irq(gptimer), NULL);
+ omap_dm_timer_free(gptimer);
+ gptimer = NULL;
+}
+
+struct op_arm_model_spec op_omap_gptimer_spec = {
+ .init = gptimer_init,
+ .num_counters = 1,
+ .setup_ctrs = gptimer_setup,
+ .start = gptimer_start,
+ .stop = gptimer_stop,
+ .name = "timer",
+};
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 12ffecd..483c228 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -197,6 +197,10 @@
Say Y here if you want to use OMAP IOMMU support for IVA2 and
Camera in OMAP3.
+config OMAP_IOMMU_DEBUG
+ depends on OMAP_IOMMU
+ tristate
+
choice
prompt "System timer"
default OMAP_MPU_TIMER
@@ -260,7 +264,7 @@
choice
prompt "Low-level debug console UART"
depends on ARCH_OMAP
- default OMAP_LL_DEBUG_UART1
+ default OMAP_LL_DEBUG_NONE
config OMAP_LL_DEBUG_UART1
bool "UART1"
@@ -274,6 +278,9 @@
config OMAP_LL_DEBUG_UART_EXT
bool "UART_EXT"
+config OMAP_LL_DEBUG_NONE
+ bool "None"
+
endchoice
config OMAP_SERIAL_WAKE
@@ -285,6 +292,96 @@
to data on the serial RX line. This allows you to wake the
system from serial console.
+comment "USBHOST Port Configuration"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+
+choice
+ prompt "Port 1"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ default OMAP_EHCI_PHY_MODE_PORT1
+
+config OMAP_EHCI_PHY_MODE_PORT1
+ bool "ULPI PHY mode: 12-pin ULPI"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ help
+ 12-pin ULPI PHY Mode. For use with a HS transceiver.
+
+config OMAP_EHCI_TLL_MODE_PORT1
+ bool "ULPI TLL mode: 12-pin ULPI"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ help
+ 12-pin ULPI TLL Mode
+
+config OMAP_OHCI_PHY_MODE_3PIN_PORT1
+ bool "Serial PHY mode: 3-pin Bi-directional DAT/SE0"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ help
+ Serial PHY Mode (3-pin Bi-directional DAT/SE0)
+
+config OMAP_OHCI_PHY_MODE_4PIN_PORT1
+ bool "Serial PHY mode: 4-pin Bi-directional DP/DM"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ help
+ Serial PHY Mode (4-pin Bidirectional DP/DM)
+
+endchoice
+
+choice
+ prompt "Port 2"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ default OMAP_EHCI_PHY_MODE_PORT2
+
+config OMAP_EHCI_PHY_MODE_PORT2
+ bool "ULPI PHY mode: 12-pin ULPI"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ help
+ 12-pin ULPI PHY Mode
+
+config OMAP_EHCI_TLL_MODE_PORT2
+ bool "ULPI TLL mode: 12-pin ULPI"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ help
+ 12-pin ULPI TLL Mode
+
+config OMAP_OHCI_PHY_MODE_3PIN_PORT2
+ bool "Serial PHY mode: 3-pin Bi-directional DAT/SE0"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ help
+ Serial PHY Mode (3-pin Bi-directional DAT/SE0)
+
+config OMAP_OHCI_PHY_MODE_4PIN_PORT2
+ bool "Serial PHY mode: 4-pin Bi-directional DP/DM"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ help
+ Serial PHY Mode (4-pin Bidirectional DP/DM)
+
+endchoice
+
+choice
+ prompt "Port 3"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ default OMAP_OHCI_PHY_MODE_3PIN_PORT3
+
+config OMAP_EHCI_TLL_MODE_PORT3
+ bool "ULPI TLL mode: 12-pin ULPI"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ help
+ 12-pin ULPI TLL Mode
+
+config OMAP_OHCI_PHY_MODE_3PIN_PORT3
+ bool "Serial PHY mode: 3-pin Bi-directional DAT/SE0"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ help
+ Serial PHY Mode (3-pin Bidirectional DAT/SE0)
+
+config OMAP_OHCI_PHY_MODE_4PIN_PORT3
+ bool "Serial PHY mode: 4-pin Bi-directional DP/DM"
+ depends on USB_EHCI_HCD || USB_OHCI_HCD
+ help
+ Serial PHY Mode (4-pin Bidirectional DP/DM)
+
+endchoice
+
choice
prompt "OMAP PM layer selection"
depends on ARCH_OMAP
@@ -302,6 +399,27 @@
endchoice
+config OMAP3_MPU_L2_CACHE_WORKAROUND
+ bool "Enable workaround for lockup on MPU cache corruption"
+ depends on ARCH_OMAP3 || PM
+ help
+ Workaround replaces MPU RETENTION state with INACTIVE state.
+ Some OMAP3's manufactured before July 2009 suffer from L2
+ cache corruption. When the MPU fetches a corrupted
+ instruction a system hang or reset via watchdog occurs. OFF
+ mode is still safe to use.
+
+config VOLTSCALE_VPFORCE
+ bool "Voltage scaling using VP force update method"
+ depends on ARCH_OMAP3 && PM
+ default y
+ help
+ Say Y if you want to enable VP force update method
+ of voltage scaling. This is the h/w recomended way
+ of voltage scaling.
+
+ If not enabled and if OMAP_SMARTREFLEX is enabled
+ vcbypass method will be used for voltage scaling.
endmenu
endif
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index f946d83..94d1500 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -14,6 +14,7 @@
obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
obj-$(CONFIG_OMAP_IOMMU) += iommu.o iovmm.o
+obj-$(CONFIG_OMAP_IOMMU_DEBUG) += iommu-debug.o
obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index a1a09ef..3af8697 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -919,7 +919,7 @@
}
return 0;
err_out:
- debugfs_remove(clk_debugfs_root); /* REVISIT: Cleanup correctly */
+ debugfs_remove_recursive(clk_debugfs_root);
return err;
}
late_initcall(clk_debugfs_init);
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index 393c905..0f68936 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -155,7 +155,7 @@
policy->cur = omap_getspeed(0);
/* FIXME: what's the actual transition time? */
- policy->cpuinfo.transition_latency = 10 * 1000 * 1000;
+ policy->cpuinfo.transition_latency = 300 * 1000;
return 0;
}
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index e66dd8a..aba1e5c 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -336,7 +336,7 @@
wdt_resources[0].start = 0x48022000; /* WDT2 */
else if (cpu_is_omap2430())
wdt_resources[0].start = 0x49016000; /* WDT2 */
- else if (cpu_is_omap343x())
+ else if (cpu_is_omap34xx())
wdt_resources[0].start = 0x48314000; /* WDT2 */
else
return;
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index cd53b28..e12094b 100755
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -316,14 +316,10 @@
void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color)
{
- u16 w;
-
BUG_ON(omap_dma_in_1510_mode());
- if (cpu_class_is_omap2()) {
- REVISIT_24XX();
- return;
- }
+ if (cpu_class_is_omap1()) {
+ u16 w;
w = dma_read(CCR2(lch));
w &= ~0x03;
@@ -351,6 +347,31 @@
w |= 1; /* Channel type G */
}
dma_write(w, LCH_CTRL(lch));
+ }
+
+ if (cpu_class_is_omap2()) {
+ u32 val;
+
+ val = dma_read(CCR(lch));
+ val &= ~((1 << 17) | (1 << 16));
+
+ switch (mode) {
+ case OMAP_DMA_CONSTANT_FILL:
+ val |= 1 << 16;
+ break;
+ case OMAP_DMA_TRANSPARENT_COPY:
+ val |= 1 << 17;
+ break;
+ case OMAP_DMA_COLOR_DIS:
+ break;
+ default:
+ BUG();
+ }
+ dma_write(val, CCR(lch));
+
+ color &= 0xffffff;
+ dma_write(color, COLOR(lch));
+ }
}
EXPORT_SYMBOL(omap_set_dma_color_mode);
@@ -455,6 +476,35 @@
}
EXPORT_SYMBOL(omap_set_dma_src_data_pack);
+/**
+ * @brief omap_set_dma_prefetch : Enable/disable prefetch
+ * for a logical channel
+ *
+ * @param lch : Logical channel number
+ * @param enable : 1 to enable / 0 to disable
+ *
+ * Prefetch can only be enabled for destination synchronized transfer.
+ * It is SW user responsibility to have prefetch disabled for source
+ * synchronized transfers.
+ * It improves DMA performance by fetching data before receiving
+ * the DMA request. Therefore, the data source shall be available when
+ * the logical channel is enabled.
+ *
+ */
+void omap_set_dma_prefetch(int lch, int enable)
+{
+ u32 l;
+
+ if (cpu_class_is_omap2()) {
+ l = dma_read(CCR(lch));
+ l &= ~(1 << 23);
+ if (enable)
+ l |= (1 << 23);
+ dma_write(l, CCR(lch));
+ }
+}
+EXPORT_SYMBOL(omap_set_dma_prefetch);
+
void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
{
unsigned int burst = 0;
@@ -800,7 +850,10 @@
/* Disable all DMA interrupts for the channel. */
dma_write(0, CICR(lch));
- /* Make sure the DMA transfer is stopped. */
+ /*
+ * Make sure the DMA transfer is stopped
+ * and disable prefetch.
+ */
dma_write(0, CCR(lch));
omap_clear_dma(lch);
}
@@ -929,7 +982,9 @@
cur_lch = next_lch;
} while (next_lch != -1);
- } else if (cpu_class_is_omap2()) {
+ } else if (cpu_is_omap242x() ||
+ (cpu_is_omap243x() && omap_type() <= OMAP2430_REV_ES1_0)) {
+
/* Errata: Need to write lch even if not using chaining */
dma_write(lch, CLNK_CTRL(lch));
}
@@ -989,6 +1044,15 @@
}
EXPORT_SYMBOL(omap_stop_dma);
+void omap_disable_lch(int lch)
+{
+ u32 l;
+ l = dma_read(CCR(lch));
+ l &= ~OMAP_DMA_CCR_EN;
+ dma_write(l, CCR(lch));
+}
+EXPORT_SYMBOL(omap_disable_lch);
+
/*
* Allows changing the DMA callback function or data. This may be needed if
* the driver shares a single DMA channel for multiple dma triggers.
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index a05205c..4618963 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -503,6 +503,17 @@
if (l & OMAP_TIMER_CTRL_ST) {
l &= ~0x1;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+ /* Readback to make sure write has completed */
+ omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+ /*
+ * Wait for functional clock period x 3.5 to make sure that
+ * timer is stopped
+ */
+ udelay(3500000 / clk_get_rate(timer->fclk) + 1);
+ /* Ack possibly pending interrupt */
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG,
+ OMAP_TIMER_INT_OVERFLOW);
+
}
}
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
index 1dc3415..76cc0ae 100644
--- a/arch/arm/plat-omap/fb.c
+++ b/arch/arm/plat-omap/fb.c
@@ -107,6 +107,10 @@
* address.
*/
memset(rg, 0, sizeof(*rg));
+#ifdef CONFIG_FB_OMAP2_32_BPP
+ rg->format = OMAPFB_COLOR_ARGB32;
+ rg->format_used = 1;
+#endif
rg->type = paddr & ~PAGE_MASK;
rg->paddr = paddr & PAGE_MASK;
rg->size = PAGE_ALIGN(conf->size);
@@ -350,6 +354,14 @@
static inline int omap_init_fb(void)
{
+#ifdef CONFIG_FB_OMAP2_32_BPP
+ /* add support for RGB32*/
+ int i;
+ for (i = 0; i < OMAPFB_PLANE_NUM; i++) {
+ omapfb_config.mem_desc.region[0].format_used = 1;
+ omapfb_config.mem_desc.region[0].format = OMAPFB_COLOR_ARGB32;
+ }
+#endif
return platform_device_register(&omap_fb_device);
}
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 667dd60..d0267fe 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -529,7 +529,7 @@
{
struct gpio_bank *bank;
void __iomem *reg;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
u32 val, l = 1 << get_gpio_index(gpio);
if (cpu_class_is_omap1())
@@ -709,7 +709,7 @@
struct gpio_bank *bank;
unsigned gpio;
int retval;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
if (!cpu_class_is_omap2() && irq > IH_MPUIO_BASE)
gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
@@ -926,7 +926,7 @@
*/
static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
{
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
switch (bank->method) {
#ifdef CONFIG_ARCH_OMAP16XX
@@ -989,7 +989,7 @@
static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
spin_lock_irqsave(&bank->lock, flags);
@@ -1015,7 +1015,7 @@
static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
spin_lock_irqsave(&bank->lock, flags);
#ifdef CONFIG_ARCH_OMAP16XX
@@ -1234,7 +1234,7 @@
{
struct gpio_bank *bank = platform_get_drvdata(pdev);
void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
spin_lock_irqsave(&bank->lock, flags);
bank->saved_wakeup = __raw_readl(mask_reg);
@@ -1248,7 +1248,7 @@
{
struct gpio_bank *bank = platform_get_drvdata(pdev);
void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
spin_lock_irqsave(&bank->lock, flags);
__raw_writel(bank->saved_wakeup, mask_reg);
@@ -1307,7 +1307,7 @@
static int gpio_input(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
bank = container_of(chip, struct gpio_bank, chip);
spin_lock_irqsave(&bank->lock, flags);
@@ -1324,7 +1324,7 @@
static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
{
struct gpio_bank *bank;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
bank = container_of(chip, struct gpio_bank, chip);
spin_lock_irqsave(&bank->lock, flags);
@@ -1337,7 +1337,7 @@
static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct gpio_bank *bank;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
bank = container_of(chip, struct gpio_bank, chip);
spin_lock_irqsave(&bank->lock, flags);
@@ -1670,7 +1670,7 @@
void __iomem *wake_status;
void __iomem *wake_clear;
void __iomem *wake_set;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
switch (bank->method) {
#ifdef CONFIG_ARCH_OMAP16XX
@@ -1732,7 +1732,7 @@
struct gpio_bank *bank = &gpio_bank[i];
void __iomem *wake_clear;
void __iomem *wake_set;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
switch (bank->method) {
#ifdef CONFIG_ARCH_OMAP16XX
diff --git a/arch/arm/plat-omap/include/mach/board-zoom2.h b/arch/arm/plat-omap/include/mach/board-zoom2.h
index 780e7fd..5899bd6 100644
--- a/arch/arm/plat-omap/include/mach/board-zoom2.h
+++ b/arch/arm/plat-omap/include/mach/board-zoom2.h
@@ -31,6 +31,7 @@
extern void ldp_flash_init(void);
extern void twl4030_bci_battery_init(void);
+extern unsigned get_last_off_on_transaction_id(struct device *dev);
#define TWL4030_IRQNUM INT_34XX_SYS_NIRQ
#define LDP3430_NAND_CS 0
diff --git a/arch/arm/plat-omap/include/mach/clock.h b/arch/arm/plat-omap/include/mach/clock.h
index 3927781..f29cf76 100644
--- a/arch/arm/plat-omap/include/mach/clock.h
+++ b/arch/arm/plat-omap/include/mach/clock.h
@@ -57,6 +57,9 @@
u32 autoidle_mask;
u32 idlest_mask;
u32 freqsel_mask;
+ u32 dco_sel_mask;
+ u32 sd_div_mask;
+ u8 jtype;
# endif
};
@@ -132,8 +135,8 @@
__s8 usecount;
u8 idlest_bit;
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
- u8 fixed_div;
- u32 clksel_mask;
+ u8 fixed_div, clksel_shift;
+ u32 clksel_mask, clksel_mask2;
const struct clksel *clksel;
struct dpll_data *dpll_data;
union {
@@ -216,6 +219,7 @@
#define PARENT_CONTROLS_CLOCK (1 << 28)
#define CLOCK_IN_OMAP3430ES1 (1 << 29) /* 3430ES1 clocks only */
#define CLOCK_IN_OMAP3430ES2 (1 << 30) /* 3430ES2+ clocks only */
+#define CLOCK_IN_OMAP363X (1 << 31)
/* Clksel_rate flags */
#define DEFAULT_RATE (1 << 0)
@@ -223,6 +227,8 @@
#define RATE_IN_243X (1 << 2)
#define RATE_IN_343X (1 << 3) /* rates common to all 343X */
#define RATE_IN_3430ES2 (1 << 4) /* 3430ES2+ rates only */
+#define RATE_IN_363X (1 << 5) /* rates common to all 3630 */
+
#define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X)
diff --git a/arch/arm/plat-omap/include/mach/control.h b/arch/arm/plat-omap/include/mach/control.h
index 3b3375e..16831da 100644
--- a/arch/arm/plat-omap/include/mach/control.h
+++ b/arch/arm/plat-omap/include/mach/control.h
@@ -166,6 +166,8 @@
#define OMAP343X_CONTROL_SRAMLDO5 (OMAP2_CONTROL_GENERAL + 0x02C0)
#define OMAP343X_CONTROL_CSI (OMAP2_CONTROL_GENERAL + 0x02C4)
+/* 36xx-only CONTROL_GENERAL register offsets */
+#define OMAP36XX_CONTROL_PROG_IO2 (OMAP2_CONTROL_GENERAL + 0x0198)
/* 34xx PADCONF register offsets */
#define OMAP343X_PADCONF_ETK(i) (OMAP2_CONTROL_PADCONFS + 0x5a8 + \
@@ -198,6 +200,9 @@
#define OMAP343X_CONTROL_WKUP_DEBOBS3 (OMAP343X_CONTROL_GENERAL_WKUP + 0x014)
#define OMAP343X_CONTROL_WKUP_DEBOBS4 (OMAP343X_CONTROL_GENERAL_WKUP + 0x018)
+/* 36xx-only GENERAL_WKUP register offsets */
+#define OMAP36XX_CONTROL_PROG_IO_WKUP1 (OMAP343X_CONTROL_GENERAL_WKUP + 0x020)
+
/*
* REVISIT: This list of registers is not comprehensive - there are more
* that should be added.
@@ -253,6 +258,17 @@
#define OMAP2_PBIASLITEPWRDNZ0 (1 << 1)
#define OMAP2_PBIASLITEVMODE0 (1 << 0)
+/* CONTROL_PROG_IO1 bits on omap3630 */
+#define OMAP3630_PRG_I2C2_PULLUPRESX (1 << 0)
+#define OMAP3630_PRG_I2C1_PULLUPRESX (1 << 19)
+#define OMAP3630_PRG_SDMMC1_SPEEDCTRL (1 << 20)
+
+/* CONTROL_PROG_IO2 bits on omap3630 */
+#define OMAP3630_PRG_I2C3_PULLUPRESX (1 << 7)
+
+/* CONTROL_PROG_IO_WKUP1 bits on omap3630 */
+#define OMAP3630_PRG_SR_PULLUPRESX (1 << 5)
+
/* CONTROL_PADCONF_X bits */
#define OMAP3_PADCONF_WAKEUPEVENT0 (1 << 15)
#define OMAP3_PADCONF_WAKEUPENABLE0 (1 << 14)
@@ -287,6 +303,7 @@
extern u32 omap3_arm_context[128];
extern void omap3_control_save_context(void);
extern void omap3_control_restore_context(void);
+extern void omap3_scratchpad_dpll4autoidle(int enable);
#else
#define omap_ctrl_base_get() 0
diff --git a/arch/arm/plat-omap/include/mach/cpu.h b/arch/arm/plat-omap/include/mach/cpu.h
index 4166a97..b292e93 100644
--- a/arch/arm/plat-omap/include/mach/cpu.h
+++ b/arch/arm/plat-omap/include/mach/cpu.h
@@ -27,7 +27,7 @@
#define __ASM_ARCH_OMAP_CPU_H
struct omap_chip_id {
- u8 oc;
+ u16 oc;
u8 type;
};
@@ -40,6 +40,7 @@
* CPU class bits (15xx, 16xx, 24xx, 34xx...) [07:00]
*/
unsigned int omap_rev(void);
+unsigned int omap_rev_id(void);
/*
* Test if multicore OMAP support is needed
@@ -138,6 +139,7 @@
IS_OMAP_SUBCLASS(242x, 0x242)
IS_OMAP_SUBCLASS(243x, 0x243)
IS_OMAP_SUBCLASS(343x, 0x343)
+IS_OMAP_SUBCLASS(363x, 0x363)
#define cpu_is_omap7xx() 0
#define cpu_is_omap15xx() 0
@@ -147,6 +149,7 @@
#define cpu_is_omap243x() 0
#define cpu_is_omap34xx() 0
#define cpu_is_omap343x() 0
+#define cpu_is_omap3630() 0
#if defined(MULTI_OMAP1)
# if defined(CONFIG_ARCH_OMAP730)
@@ -190,6 +193,7 @@
# undef cpu_is_omap343x
# define cpu_is_omap34xx() is_omap34xx()
# define cpu_is_omap343x() is_omap343x()
+# define cpu_is_omap3630() is_omap363x()
# endif
#else
# if defined(CONFIG_ARCH_OMAP24XX)
@@ -207,6 +211,8 @@
# if defined(CONFIG_ARCH_OMAP34XX)
# undef cpu_is_omap34xx
# define cpu_is_omap34xx() 1
+# undef cpu_is_omap3630
+# define cpu_is_omap3630() is_omap363x()
# endif
# if defined(CONFIG_ARCH_OMAP3430)
# undef cpu_is_omap343x
@@ -230,6 +236,7 @@
* cpu_is_omap2423(): True for OMAP2423
* cpu_is_omap2430(): True for OMAP2430
* cpu_is_omap3430(): True for OMAP3430
+ * cpu_is_omap3630(): True for OMAP3630
*/
#define GET_OMAP_TYPE ((omap_rev() >> 16) & 0xffff)
@@ -334,12 +341,14 @@
#define OMAP243X_CLASS 0x24300024
#define OMAP2430_REV_ES1_0 0x24300024
-#define OMAP343X_CLASS 0x34300034
-#define OMAP3430_REV_ES1_0 0x34300034
-#define OMAP3430_REV_ES2_0 0x34301034
-#define OMAP3430_REV_ES2_1 0x34302034
-#define OMAP3430_REV_ES3_0 0x34303034
-#define OMAP3430_REV_ES3_1 0x34304034
+#define OMAP343X_CLASS 0x34300034
+#define OMAP3430_REV_ES1_0 0x34300034
+#define OMAP3430_REV_ES2_0 0x34301034
+#define OMAP3430_REV_ES2_1 0x34302034
+#define OMAP3430_REV_ES3_0 0x34303034
+#define OMAP3430_REV_ES3_1 0x34304034
+#define OMAP3430_REV_ES3_1_1 0x34305034
+#define OMAP3630_REV_ES1_0 0x36300034
/*
* omap_chip bits
@@ -362,6 +371,8 @@
#define CHIP_IS_OMAP3430ES2 (1 << 4)
#define CHIP_IS_OMAP3430ES3_0 (1 << 5)
#define CHIP_IS_OMAP3430ES3_1 (1 << 6)
+#define CHIP_IS_OMAP3430ES3_1_1 (1 << 7)
+#define CHIP_IS_OMAP3630ES1 (1 << 8)
#define CHIP_IS_OMAP24XX (CHIP_IS_OMAP2420 | CHIP_IS_OMAP2430)
@@ -373,9 +384,13 @@
*/
#define CHIP_GE_OMAP3430ES2 (CHIP_IS_OMAP3430ES2 | \
CHIP_IS_OMAP3430ES3_0 | \
- CHIP_IS_OMAP3430ES3_1)
-#define CHIP_GE_OMAP3430ES3_1 (CHIP_IS_OMAP3430ES3_1)
+ CHIP_IS_OMAP3430ES3_1 | \
+ CHIP_IS_OMAP3430ES3_1_1 |\
+ CHIP_IS_OMAP3630ES1)
+#define CHIP_GE_OMAP3430ES3_1 (CHIP_IS_OMAP3430ES3_1 | \
+ CHIP_IS_OMAP3430ES3_1_1 | \
+ CHIP_IS_OMAP3630ES1)
int omap_chip_is(struct omap_chip_id oci);
int omap_type(void);
@@ -389,8 +404,19 @@
#define OMAP2_DEVICE_TYPE_GP 3
#define OMAP2_DEVICE_TYPE_BAD 4
+/*
+ * Macro to detect omap revision number (for SW tiering */
+#define OMAP_3420 0x3420
+#define OMAP_3430 0x3430
+#define OMAP_3440 0x3440
+#define OMAP_3630 0x3630
+#define OMAP_3630_800 0x3630800
+#define OMAP_3630_1000 0x36301000
+
void omap2_check_revision(void);
+void omap_l2cache_enable(void);
+
#endif /* defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) */
#endif
diff --git a/arch/arm/plat-omap/include/mach/debug-macro.S b/arch/arm/plat-omap/include/mach/debug-macro.S
index 6fd3184..6515629 100644
--- a/arch/arm/plat-omap/include/mach/debug-macro.S
+++ b/arch/arm/plat-omap/include/mach/debug-macro.S
@@ -39,10 +39,10 @@
#elif CONFIG_ARCH_OMAP3
#ifdef CONFIG_OMAP_LL_DEBUG_UART_EXT
moveq \rx, #0x10000000 @ physical base address
- movne \rx, #0xfb000000 @ virtual base address
+ ldrne \rx, =0xfa400000
#else
moveq \rx, #0x48000000 @ physical base address
- movne \rx, #0xd8000000 @ virtual base
+ movne \rx, #0xfa000000 @ virtual base
orr \rx, \rx, #0x0006a000
#ifdef CONFIG_OMAP_LL_DEBUG_UART2
add \rx, \rx, #0x00002000 @ UART 2
diff --git a/arch/arm/plat-omap/include/mach/dma.h b/arch/arm/plat-omap/include/mach/dma.h
index c023e89..88b112c 100755
--- a/arch/arm/plat-omap/include/mach/dma.h
+++ b/arch/arm/plat-omap/include/mach/dma.h
@@ -144,6 +144,7 @@
#define OMAP_DMA4_CSSA_U(n) 0
#define OMAP_DMA4_CDSA_L(n) 0
#define OMAP_DMA4_CDSA_U(n) 0
+#define OMAP1_DMA_COLOR(n) 0
/*----------------------------------------------------------------------------*/
@@ -496,6 +497,7 @@
extern void omap_free_dma(int ch);
extern void omap_start_dma(int lch);
extern void omap_stop_dma(int lch);
+extern void omap_disable_lch(int lch);
extern void omap_set_dma_transfer_params(int lch, int data_type,
int elem_count, int frame_count,
int sync_mode,
@@ -510,6 +512,7 @@
int src_ei, int src_fi);
extern void omap_set_dma_src_index(int lch, int eidx, int fidx);
extern void omap_set_dma_src_data_pack(int lch, int enable);
+extern void omap_set_dma_prefetch(int lch, int enable);
extern void omap_set_dma_src_burst_mode(int lch,
enum omap_dma_burst_mode burst_mode);
diff --git a/arch/arm/plat-omap/include/mach/gpmc.h b/arch/arm/plat-omap/include/mach/gpmc.h
index a37cfc6..2ebc0a7 100644
--- a/arch/arm/plat-omap/include/mach/gpmc.h
+++ b/arch/arm/plat-omap/include/mach/gpmc.h
@@ -114,6 +114,10 @@
extern void gpmc_cs_free(int cs);
extern int gpmc_cs_set_reserved(int cs, int reserved);
extern int gpmc_cs_reserved(int cs);
+extern int gpmc_prefetch_enable(int cs, int dma_mode,
+ unsigned int u32_count, int is_write);
+extern void gpmc_prefetch_reset(void);
+extern int gpmc_prefetch_status(void);
extern void omap3_gpmc_save_context(void);
extern void omap3_gpmc_restore_context(void);
extern void __init gpmc_init(void);
diff --git a/arch/arm/plat-omap/include/mach/io.h b/arch/arm/plat-omap/include/mach/io.h
index 4c8dcfa..cb54bfd 100644
--- a/arch/arm/plat-omap/include/mach/io.h
+++ b/arch/arm/plat-omap/include/mach/io.h
@@ -109,7 +109,7 @@
#define L3_34XX_SIZE SZ_1M /* 44kB of 128MB used, want 1MB sect */
#define L4_34XX_PHYS L4_34XX_BASE /* 0x48000000 */
-#define L4_34XX_VIRT 0xd8000000
+#define L4_34XX_VIRT 0xfa000000
#define L4_34XX_SIZE SZ_4M /* 1MB of 128MB used, want 1MB sect */
/*
@@ -118,16 +118,16 @@
*/
#define L4_WK_34XX_PHYS L4_WK_34XX_BASE /* 0x48300000 */
-#define L4_WK_34XX_VIRT 0xd8300000
+#define L4_WK_34XX_VIRT 0xfa300000
#define L4_WK_34XX_SIZE SZ_1M
#define L4_PER_34XX_PHYS L4_PER_34XX_BASE /* 0x49000000 */
-#define L4_PER_34XX_VIRT 0xd9000000
+#define L4_PER_34XX_VIRT 0xfb000000
#define L4_PER_34XX_SIZE SZ_1M
#define L4_EMU_34XX_PHYS L4_EMU_34XX_BASE /* 0x54000000 */
-#define L4_EMU_34XX_VIRT 0xe4000000
-#define L4_EMU_34XX_SIZE SZ_64M
+#define L4_EMU_34XX_VIRT 0xf9000000
+#define L4_EMU_34XX_SIZE SZ_8M
#define OMAP34XX_GPMC_PHYS OMAP34XX_GPMC_BASE /* 0x6E000000 */
#define OMAP34XX_GPMC_VIRT 0xFE000000
@@ -141,12 +141,30 @@
#define OMAP343X_SDRC_VIRT 0xFD000000
#define OMAP343X_SDRC_SIZE SZ_1M
+#define L3_IO_OFFSET 0x90000000
+#define IO_OFFSET 0xb2000000
-#define IO_OFFSET 0x90000000
-#define __IO_ADDRESS(pa) ((pa) + IO_OFFSET) /* Works for L3 and L4 */
-#define __OMAP2_IO_ADDRESS(pa) ((pa) + IO_OFFSET) /* Works for L3 and L4 */
-#define io_v2p(va) ((va) - IO_OFFSET) /* Works for L3 and L4 */
-#define io_p2v(pa) ((pa) + IO_OFFSET) /* Works for L3 and L4 */
+#ifndef __ASSEMBLER__
+/* Works for L3 and L4 */
+#define __IO_ADDRESS(pa) ((pa) >= L3_34XX_PHYS ? \
+ ((pa) + L3_IO_OFFSET) : ((pa) + IO_OFFSET))
+
+#define __OMAP2_IO_ADDRESS(pa) __IO_ADDRESS(pa)
+/* #define io_v2p(va) ((va) - IO_OFFSET) */
+#define io_p2v(pa) __IO_ADDRESS(pa)
+#else
+/* Works for L3 */
+#define __L3_IO_ADDRESS(pa) ((pa) + L3_IO_OFFSET)
+#define __OMAP2_L3_IO_ADDRESS(pa) ((pa) + L3_IO_OFFSET)
+#define l3_io_v2p(va) ((va) - L3_IO_OFFSET)
+#define l3_io_p2v(pa) ((pa) + L3_IO_OFFSET)
+
+/* Works for L4 */
+#define __IO_ADDRESS(pa) ((pa) + IO_OFFSET)
+#define __OMAP2_IO_ADDRESS(pa) ((pa) + IO_OFFSET)
+#define io_p2v(pa) ((pa) + IO_OFFSET)
+#define io_v2p(va) ((va) - IO_OFFSET)
+#endif
/* DSP */
#define DSP_MEM_34XX_PHYS OMAP34XX_DSP_MEM_BASE /* 0x58000000 */
@@ -159,15 +177,28 @@
#define DSP_MMU_34XX_VIRT 0xe2000000
#define DSP_MMU_34XX_SIZE SZ_4K
+
#define ZOOM2_QUART_PHYS 0x10000000
-#define ZOOM2_QUART_VIRT 0xFB000000
+#define ZOOM2_QUART_VIRT 0xfa400000
#define ZOOM2_QUART_SIZE SZ_1M
#endif
+#ifndef __ASSEMBLER__
#define IO_ADDRESS(pa) IOMEM(__IO_ADDRESS(pa))
#define OMAP1_IO_ADDRESS(pa) IOMEM(__OMAP1_IO_ADDRESS(pa))
#define OMAP2_IO_ADDRESS(pa) IOMEM(__OMAP2_IO_ADDRESS(pa))
+#define L3_IO_ADDRESS(pa) IOMEM(__L3_IO_ADDRESS(pa))
+#define OMAP2_L3_IO_ADDRESS(pa) IOMEM(__OMAP2_L3_IO_ADDRESS(pa))
+
+#else
+
+#define L3_IO_ADDRESS(pa) IOMEM(__L3_IO_ADDRESS(pa))
+#define OMAP2_L3_IO_ADDRESS(pa) IOMEM(__OMAP2_L3_IO_ADDRESS(pa))
+
+#define IO_ADDRESS(pa) IOMEM(__IO_ADDRESS(pa))
+#define OMAP2_IO_ADDRESS(pa) IOMEM(__OMAP2_IO_ADDRESS(pa))
+#endif
#ifdef __ASSEMBLER__
#define IOMEM(x) x
diff --git a/arch/arm/plat-omap/include/mach/iommu.h b/arch/arm/plat-omap/include/mach/iommu.h
index ef04d7a..46d41ac 100644
--- a/arch/arm/plat-omap/include/mach/iommu.h
+++ b/arch/arm/plat-omap/include/mach/iommu.h
@@ -95,7 +95,7 @@
void (*save_ctx)(struct iommu *obj);
void (*restore_ctx)(struct iommu *obj);
- ssize_t (*dump_ctx)(struct iommu *obj, char *buf);
+ ssize_t (*dump_ctx)(struct iommu *obj, char *buf, ssize_t len);
};
struct iommu_platform_data {
@@ -104,7 +104,11 @@
const int nr_tlb_entries;
};
+#if defined(CONFIG_ARCH_OMAP1)
+#error "iommu for this processor not implemented yet"
+#else
#include <mach/iommu2.h>
+#endif
/*
* utilities for super page(16MB, 1MB, 64KB and 4KB)
@@ -135,13 +139,14 @@
*/
extern u32 iommu_arch_version(void);
+extern void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e);
+extern u32 iotlb_cr_to_virt(struct cr_regs *cr);
+
extern int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e);
extern void flush_iotlb_page(struct iommu *obj, u32 da);
extern void flush_iotlb_range(struct iommu *obj, u32 start, u32 end);
extern void flush_iotlb_all(struct iommu *obj);
-ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf);
-
extern int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e);
extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova);
@@ -154,4 +159,10 @@
extern int install_iommu_arch(const struct iommu_functions *ops);
extern void uninstall_iommu_arch(const struct iommu_functions *ops);
+extern int foreach_iommu_device(void *data,
+ int (*fn)(struct device *, void *));
+
+extern ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t len);
+extern size_t dump_tlb_entries(struct iommu *obj, char *buf, ssize_t len);
+
#endif /* __MACH_IOMMU_H */
diff --git a/arch/arm/plat-omap/include/mach/iommu2.h b/arch/arm/plat-omap/include/mach/iommu2.h
index d746047..10ad05f 100644
--- a/arch/arm/plat-omap/include/mach/iommu2.h
+++ b/arch/arm/plat-omap/include/mach/iommu2.h
@@ -13,6 +13,8 @@
#ifndef __MACH_IOMMU2_H
#define __MACH_IOMMU2_H
+#include <linux/io.h>
+
/*
* MMU Register offsets
*/
diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/mach/irqs.h
index c9a5b19..f775408 100644
--- a/arch/arm/plat-omap/include/mach/irqs.h
+++ b/arch/arm/plat-omap/include/mach/irqs.h
@@ -388,8 +388,10 @@
#ifndef __ASSEMBLY__
extern void omap_init_irq(void);
extern int omap_irq_pending(void);
+void omap3_intc_autoidle(int enable);
void omap3_intc_save_context(void);
void omap3_intc_restore_context(void);
+void omap3_intc_suspend(void);
#endif
#include <mach/hardware.h>
diff --git a/arch/arm/plat-omap/include/mach/isp_user.h b/arch/arm/plat-omap/include/mach/isp_user.h
index b819e26..c517f99 100644
--- a/arch/arm/plat-omap/include/mach/isp_user.h
+++ b/arch/arm/plat-omap/include/mach/isp_user.h
@@ -38,6 +38,26 @@
_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct af_configuration)
#define VIDIOC_PRIVATE_ISP_AF_REQ \
_IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct isp_af_data)
+#define VIDIOC_PRIVATE_OMAP34XXCAM_SENSOR_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct omap34xxcam_sensor_info)
+
+/*
+ * P R I V A T E E V E N T S
+ */
+
+#define V4L2_EVENT_OMAP3ISP_CLASS (V4L2_EVENT_PRIVATE_START | 0x100)
+#define V4L2_EVENT_OMAP3ISP_AEWB (V4L2_EVENT_OMAP3ISP_CLASS | 0x1)
+#define V4L2_EVENT_OMAP3ISP_AF (V4L2_EVENT_OMAP3ISP_CLASS | 0x2)
+#define V4L2_EVENT_OMAP3ISP_HIST (V4L2_EVENT_OMAP3ISP_CLASS | 0x3)
+#define V4L2_EVENT_OMAP3ISP_HS_VS (V4L2_EVENT_OMAP3ISP_CLASS | 0x4)
+
+/* Structre for getting Sensor Information*/
+struct omap34xxcam_sensor_info {
+ __u32 current_xclk;
+ struct v4l2_rect active_size;
+ struct v4l2_rect full_size;
+ struct v4l2_rect pixel_size;
+};
/* AE/AWB related structures and flags*/
@@ -157,41 +177,57 @@
/* Histogram related structs */
+
/* Flags for number of bins */
-#define BINS_32 0x0
-#define BINS_64 0x1
-#define BINS_128 0x2
-#define BINS_256 0x3
+#define HIST_BINS_32 0
+#define HIST_BINS_64 1
+#define HIST_BINS_128 2
+#define HIST_BINS_256 3
+#define HIST_MEM_SIZE_BINS(n) ((n)*16)
+
+#define HIST_MEM_SIZE 1024
+#define HIST_MIN_REGIONS 1
+#define HIST_MAX_REGIONS 4
+#define HIST_MAX_WB_GAIN 255
+#define HIST_MIN_WB_GAIN 0
+#define HIST_MAX_BIT_WIDTH 14
+#define HIST_MIN_BIT_WIDTH 8
+#define HIST_MAX_BUFF 5
+#define HIST_MAX_WG 4
+
+/* Source */
+#define HIST_SOURCE_CCDC 0
+#define HIST_SOURCE_MEM 1
+
+/* CFA pattern */
+#define HIST_CFA_BAYER 0
+#define HIST_CFA_FOVEONX3 1
struct isp_hist_config {
- __u8 hist_source; /* CCDC or Memory */
+ __u8 enable;
+ __u8 source; /* CCDC or memory */
__u8 input_bit_width; /* Needed o know the size per pixel */
- __u8 hist_frames; /* Num of frames to be processed and
- * accumulated
- */
+ __u8 num_acc_frames; /* Num of frames to be processed and accumulated
+ for each generated histogram frame */
__u8 hist_h_v_info; /* frame-input width and height if source is
- * memory
- */
- __u16 hist_radd; /* frame-input address in memory */
+ * memory */
+ __u16 hist_radd; /* frame-input address in memory */
__u16 hist_radd_off; /* line-offset for frame-input */
__u16 hist_bins; /* number of bins: 32, 64, 128, or 256 */
- __u16 wb_gain_R; /* White Balance Field-to-Pattern Assignments */
- __u16 wb_gain_RG; /* White Balance Field-to-Pattern Assignments */
- __u16 wb_gain_B; /* White Balance Field-to-Pattern Assignments */
- __u16 wb_gain_BG; /* White Balance Field-to-Pattern Assignments */
- __u8 num_regions; /* number of regions to be configured */
- __u16 reg0_hor; /* Region 0 size and position */
- __u16 reg0_ver; /* Region 0 size and position */
- __u16 reg1_hor; /* Region 1 size and position */
- __u16 reg1_ver; /* Region 1 size and position */
- __u16 reg2_hor; /* Region 2 size and position */
- __u16 reg2_ver; /* Region 2 size and position */
- __u16 reg3_hor; /* Region 3 size and position */
- __u16 reg3_ver; /* Region 3 size and position */
+ __u8 cfa; /* BAYER or FOVEON X3 */
+ __u8 wg[HIST_MAX_WG]; /* White Balance Gain */
+ __u8 num_regions; /* number of regions to be configured */
+ __u32 reg_hor[HIST_MAX_REGIONS]; /* Regions size and position */
+ __u32 reg_ver[HIST_MAX_REGIONS]; /* Regions size and position */
};
struct isp_hist_data {
__u32 *hist_statistics_buf; /* Pointer to pass to user */
+ __u8 update;
+ __u16 frame_number;
+ __u16 curr_frame;
+ __u32 config_counter;
+ struct timeval ts;
};
/* Auto Focus related structs */
diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h
index ec61b89..2d3c499 100644
--- a/arch/arm/plat-omap/include/mach/mcbsp.h
+++ b/arch/arm/plat-omap/include/mach/mcbsp.h
@@ -136,6 +136,7 @@
#define OMAP_MCBSP_REG_XCERG 0x74
#define OMAP_MCBSP_REG_XCERH 0x78
#define OMAP_MCBSP_REG_SYSCON 0x8C
+#define OMAP_MCBSP_REG_THRSH2 0x90
#define OMAP_MCBSP_REG_WAKEUPEN 0xA8
#define OMAP_MCBSP_REG_XCCR 0xAC
#define OMAP_MCBSP_REG_RCCR 0xB0
@@ -298,6 +299,7 @@
u16 xcerh;
u16 xccr;
u16 rccr;
+ u16 wken;
};
typedef enum {
@@ -308,6 +310,20 @@
OMAP_MCBSP5
} omap_mcbsp_id;
+/* McBSP threshold */
+#if defined(CONFIG_ARCH_OMAP34XX)
+static const int omap34xx_mcbsp_thresholds[][2] = {
+ { 0, 0 },
+ { 1260, 0},
+ { 0, 0},
+ { 0, 0},
+ { 0, 0},
+};
+#else
+static const int omap34xx_mcbsp_thresholds[][2] = {};
+#endif
+
+
typedef int __bitwise omap_mcbsp_io_type_t;
#define OMAP_MCBSP_IRQ_IO ((__force omap_mcbsp_io_type_t) 1)
#define OMAP_MCBSP_POLL_IO ((__force omap_mcbsp_io_type_t) 2)
@@ -409,8 +425,10 @@
void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config);
int omap_mcbsp_request(unsigned int id);
void omap_mcbsp_free(unsigned int id);
-void omap_mcbsp_start(unsigned int id);
-void omap_mcbsp_stop(unsigned int id);
+void omap_mcbsp_disable_fclk(unsigned int id);
+void omap_mcbsp_enable_fclk(unsigned int id);
+void omap_mcbsp_start(unsigned int id, int tx, int rx);
+void omap_mcbsp_stop(unsigned int id, int tx, int rx);
void omap_mcbsp_xmit_word(unsigned int id, u32 word);
u32 omap_mcbsp_recv_word(unsigned int id);
@@ -418,6 +436,7 @@
int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length);
int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word);
int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word);
+void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold);
/* SPI specific API */
diff --git a/arch/arm/plat-omap/include/mach/mmc.h b/arch/arm/plat-omap/include/mach/mmc.h
index 94617d3..22154f0 100644
--- a/arch/arm/plat-omap/include/mach/mmc.h
+++ b/arch/arm/plat-omap/include/mach/mmc.h
@@ -64,6 +64,10 @@
/* To get the OFF mode counter */
unsigned (*context_loss) (struct device *dev);
+ /* Setup the vdd1 opp */
+ void (*set_vdd1_opp) (struct device *dev, unsigned long);
+ unsigned long max_vdd1_opp;
+ unsigned long min_vdd1_opp;
u64 dma_mask;
diff --git a/arch/arm/plat-omap/include/mach/mux.h b/arch/arm/plat-omap/include/mach/mux.h
index 3cf9467..dfe50e5 100644
--- a/arch/arm/plat-omap/include/mach/mux.h
+++ b/arch/arm/plat-omap/include/mach/mux.h
@@ -826,6 +826,7 @@
AH17_34XX_GPIO100,
B24_34XX_GPIO101,
B24_34XX_GPIO101_OUT,
+ B25_34XX_GPIO109,
B26_34XX_GPIO111,
AG4_34XX_GPIO134_OUT,
AE4_34XX_GPIO136_OUT,
@@ -871,6 +872,10 @@
AH4_3430_MMC2_DAT1,
AG4_3430_MMC2_DAT2,
AF4_3430_MMC2_DAT3,
+ AE4_3430_MMC2_DAT4,
+ AH3_3430_MMC2_DAT5,
+ AF3_3430_MMC2_DAT6,
+ AE3_3430_MMC2_DAT7,
/* MMC3 */
AF10_3430_MMC3_CLK,
@@ -944,6 +949,8 @@
/* SYS_NIRQ T2 INT1 */
AF26_34XX_SYS_NIRQ,
+ D25_34XX_GPIO126,
+ R8_34XX_GPIO56_TRISTATE,
};
struct omap_mux_cfg {
diff --git a/arch/arm/plat-omap/include/mach/nand.h b/arch/arm/plat-omap/include/mach/nand.h
index 631a7be..1612e35 100644
--- a/arch/arm/plat-omap/include/mach/nand.h
+++ b/arch/arm/plat-omap/include/mach/nand.h
@@ -18,7 +18,11 @@
int nr_parts;
int (*nand_setup)(void __iomem *);
int (*dev_ready)(struct omap_nand_platform_data *);
+ int (*unlock)(struct mtd_info *, loff_t, size_t);
+ void (*board_unlock)(struct mtd_info *,
+ struct device *);
int dma_channel;
void __iomem *gpmc_cs_baseaddr;
void __iomem *gpmc_baseaddr;
+ int ecc_opt; /* 0x0 - sw ecc, 0x1 - hw ecc */
};
diff --git a/arch/arm/plat-omap/include/mach/omap-pm.h b/arch/arm/plat-omap/include/mach/omap-pm.h
index f690a05..26f8ee0 100644
--- a/arch/arm/plat-omap/include/mach/omap-pm.h
+++ b/arch/arm/plat-omap/include/mach/omap-pm.h
@@ -273,6 +273,63 @@
*/
/**
+ * omap_pm_get_max_vdd1_opp - get the maximum supported VDD1 OPP number
+ *
+ * Report the maximum VDD1 OPP number.
+ *
+ * Returns the maximum supported VDD1 OPP number.
+ */
+u8 omap_pm_get_max_vdd1_opp(void);
+
+
+/**
+ * omap_pm_get_min_vdd1_opp - get the minimum supported VDD1 OPP number
+ *
+ * Report the minimum VDD1 OPP number.
+ *
+ * Returns the minimum supported VDD1 OPP number.
+ */
+u8 omap_pm_get_min_vdd1_opp(void);
+
+
+/**
+ * omap_pm_get_max_vdd2_opp - get the maximum supported VDD2 OPP number
+ *
+ * Report the maximum VDD2 OPP number.
+ *
+ * Returns the maximum supported VDD2 OPP number.
+ */
+u8 omap_pm_get_max_vdd2_opp(void);
+
+
+/**
+ * omap_pm_get_min_vdd2_opp - get the minimum supported VDD2 OPP number
+ *
+ * Report the minimum VDD2 OPP number.
+ *
+ * Returns the minimum supported VDD2 OPP number.
+ */
+u8 omap_pm_get_min_vdd2_opp(void);
+
+/**
+ * omap_get_mpu_rate_table - get the mpu OPP table
+ *
+ * returns mpu rate table.
+ *
+ * Returns the pointer to rate table
+ */
+struct omap_opp *omap_get_mpu_rate_table(void);
+
+/**
+ * omap_get_dsp_rate_table - get the dsp OPP table
+ *
+ * returns dsp rate table.
+ *
+ * Returns the pointer to rate table
+ */
+struct omap_opp *omap_get_dsp_rate_table(void);
+
+/**
* omap_pm_cpu_get_freq_table - return a cpufreq_frequency_table array ptr
*
* Provide a frequency table usable by CPUFreq for the current chip/board.
@@ -293,13 +350,24 @@
void omap_pm_cpu_set_freq(unsigned long f);
/**
+ * omap_pm_set_min_mpu_freq - set the current minimum MPU frequency
+ * @f: MPU frequency in Hz
+ * @dev: struct device *
+ *
+ * Set the current minimum CPU frequency. The actual CPU frequency
+ * used could end up higher if the DSP requested a higher OPP.
+ * Intended to be called by all Kernel components. No
+ * return value.
+ */
+void omap_pm_set_min_mpu_freq(struct device *dev, unsigned long f);
+
+/**
* omap_pm_cpu_get_freq - report the current CPU frequency
*
* Returns the current MPU frequency, or 0 upon error.
*/
unsigned long omap_pm_cpu_get_freq(void);
-
/*
* Device context loss tracking
*/
diff --git a/arch/arm/plat-omap/include/mach/omap-serial.h b/arch/arm/plat-omap/include/mach/omap-serial.h
index 45aa4a4..cc94e66 100644
--- a/arch/arm/plat-omap/include/mach/omap-serial.h
+++ b/arch/arm/plat-omap/include/mach/omap-serial.h
@@ -33,11 +33,8 @@
IO_ADDRESS(OMAP_UART3_BASE) ))
extern unsigned int fcr[MAX_UARTS];
-/* This allows the OMAP to wake-up from the UARTs[cts line],
- * the definition should come from drivers/serial/omap-serial.c
- * BT in that case uses UART2 [uart_no=1], and state=1[enable]
- */
-extern int omap24xx_uart_cts_wakeup(int uart_no, int state);
+int omap_uart_active(int num);
+int omap_uart_cts_wakeup(int uart_no, int state);
#endif /* __OMAP_SERIAL_H__ */
diff --git a/arch/arm/plat-omap/include/mach/omap34xx.h b/arch/arm/plat-omap/include/mach/omap34xx.h
index 8535173..b7cbfc0 100644
--- a/arch/arm/plat-omap/include/mach/omap34xx.h
+++ b/arch/arm/plat-omap/include/mach/omap34xx.h
@@ -23,12 +23,10 @@
#ifndef __ASM_ARCH_OMAP34XX_H
#define __ASM_ARCH_OMAP34XX_H
-
/*
* Please place only base defines here and put the rest in device
* specific headers.
*/
-
#define L4_34XX_BASE 0x48000000
#define L4_WK_34XX_BASE 0x48300000
#define L4_WK_OMAP_BASE L4_WK_34XX_BASE
@@ -62,6 +60,7 @@
#define OMAP3430_ISP_MMU_BASE (OMAP3430_ISP_BASE + 0x1400)
#define OMAP3430_ISP_CSI2A_BASE (OMAP3430_ISP_BASE + 0x1800)
#define OMAP3430_ISP_CSI2PHY_BASE (OMAP3430_ISP_BASE + 0x1970)
+#define OMAP3430_ISP_CSI2PHY2_BASE (OMAP3430_ISP_BASE + 0x1D70)
#define OMAP3430_ISP_END (OMAP3430_ISP_BASE + 0x06F)
#define OMAP3430_ISP_CBUFF_END (OMAP3430_ISP_CBUFF_BASE + 0x077)
@@ -75,6 +74,7 @@
#define OMAP3430_ISP_MMU_END (OMAP3430_ISP_MMU_BASE + 0x06F)
#define OMAP3430_ISP_CSI2A_END (OMAP3430_ISP_CSI2A_BASE + 0x16F)
#define OMAP3430_ISP_CSI2PHY_END (OMAP3430_ISP_CSI2PHY_BASE + 0x007)
+#define OMAP3430_ISP_CSI2PHY2_END (OMAP3430_ISP_CSI2PHY2_BASE + 0x007)
#define OMAP34XX_IVA_INTC_BASE 0x40000000
#define OMAP34XX_HSUSB_OTG_BASE (L4_34XX_BASE + 0xAB000)
@@ -110,16 +110,19 @@
#define VDD1_OPP3 0x3
#define VDD1_OPP4 0x4
#define VDD1_OPP5 0x5
+#define VDD1_OPP6 0x6
/* VDD2 OPPS */
#define VDD2_OPP1 0x1
#define VDD2_OPP2 0x2
#define VDD2_OPP3 0x3
+#define VDD2_OPP4 0x4
-#define MIN_VDD1_OPP VDD1_OPP1
-#define MAX_VDD1_OPP VDD1_OPP5
-#define MIN_VDD2_OPP VDD2_OPP1
-#define MAX_VDD2_OPP VDD2_OPP3
+#define MIN_VDD1_OPP (omap_pm_get_min_vdd1_opp())
+#define MAX_VDD1_OPP (omap_pm_get_max_vdd1_opp())
+#define MIN_VDD2_OPP (omap_pm_get_min_vdd2_opp())
+#define MAX_VDD2_OPP (omap_pm_get_max_vdd2_opp())
+#define VDD1_THRESHOLD MAX_VDD2_OPP
#endif /* __ASM_ARCH_OMAP34XX_H */
diff --git a/arch/arm/plat-omap/include/mach/powerdomain.h b/arch/arm/plat-omap/include/mach/powerdomain.h
index 6271d85..bae4e7d 100644
--- a/arch/arm/plat-omap/include/mach/powerdomain.h
+++ b/arch/arm/plat-omap/include/mach/powerdomain.h
@@ -37,6 +37,8 @@
#define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | (1 << PWRDM_POWER_ON))
+#define PWRSTS_OFF_RET_INA_ON (PWRSTS_OFF_RET_ON | \
+ (1 << PWRDM_POWER_INACTIVE))
/* Powerdomain flags */
#define PWRDM_HAS_HDWR_SAR (1 << 0) /* hardware save-and-restore support */
@@ -53,6 +55,11 @@
* CORE powerdomain on OMAP3 is the worst case
*/
#define PWRDM_MAX_CLKDMS 4
+/*
+ * Maximum number of FCLK register masks that can be associated with a
+ * powerdomain. CORE powerdomain on OMAP3 is the worst case
+ */
+#define PWRDM_MAX_FCLK 2
/* XXX A completely arbitrary number. What is reasonable here? */
#define PWRDM_TRANSITION_BAILOUT 100000
@@ -117,9 +124,14 @@
struct list_head node;
- int state;
+ s8 state;
+ s8 next_state;
unsigned state_counter[4];
+ unsigned ret_logic_off_counter;
+ unsigned ret_mem_off_counter;
+ u8 fclk_reg_amt;
+ u32 fclk_masks[PWRDM_MAX_FCLK];
#ifdef CONFIG_PM_DEBUG
s64 timer;
s64 state_timer[4];
@@ -135,6 +147,8 @@
int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
void *user);
+int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user),
+ void *user);
int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
@@ -163,14 +177,17 @@
int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm);
int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_next_logic_pwrst(struct powerdomain *pwrdm);
int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
+int pwrdm_read_next_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm);
int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm);
bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
int pwrdm_wait_transition(struct powerdomain *pwrdm);
+int pwrdm_can_idle(struct powerdomain *pwrdm);
int pwrdm_state_switch(struct powerdomain *pwrdm);
int pwrdm_clkdm_state_switch(struct clockdomain *clkdm);
diff --git a/arch/arm/plat-omap/include/mach/prcm.h b/arch/arm/plat-omap/include/mach/prcm.h
index d0cbe80..d28fda4 100644
--- a/arch/arm/plat-omap/include/mach/prcm.h
+++ b/arch/arm/plat-omap/include/mach/prcm.h
@@ -35,6 +35,10 @@
void omap3_prcm_save_context(void);
void omap3_prcm_restore_context(void);
+
+/* SMC core off notification defines */
+#define PRCM_ENTER_OFF 1
+#define PRCM_EXIT_OFF 0
#endif
diff --git a/arch/arm/plat-omap/include/mach/resource.h b/arch/arm/plat-omap/include/mach/resource.h
index f91d8ce..f5d7f26 100644
--- a/arch/arm/plat-omap/include/mach/resource.h
+++ b/arch/arm/plat-omap/include/mach/resource.h
@@ -25,7 +25,12 @@
#include <linux/device.h>
#include <mach/cpu.h>
-#define RES_DEFAULTLEVEL 0x0
+#define RES_PERFORMANCE_DEFAULTLEVEL 0
+#define RES_LATENCY_DEFAULTLEVEL -1
+
+/* Types of resources */
+#define RES_TYPE_PERFORMANCE 0x1
+#define RES_TYPE_LATENCY 0x2
struct shared_resource_ops; /* forward declaration */
@@ -35,6 +40,8 @@
char *name;
/* Used to represent the OMAP chip types containing this res */
const struct omap_chip_id omap_chip;
+ /* Resource type flags */
+ const u8 flags;
/* Total no of users at any point of this resource */
u8 no_of_users;
/* Current level of this resource */
@@ -46,6 +53,8 @@
/* Shared resource operations */
struct shared_resource_ops *ops;
struct list_head node;
+ /* Protect each resource */
+ struct mutex resource_mutex;
};
struct shared_resource_ops {
diff --git a/arch/arm/plat-omap/include/mach/sdrc.h b/arch/arm/plat-omap/include/mach/sdrc.h
index 4af5c6a..0b13837 100644
--- a/arch/arm/plat-omap/include/mach/sdrc.h
+++ b/arch/arm/plat-omap/include/mach/sdrc.h
@@ -44,6 +44,7 @@
#define SDRC_RFR_CTRL_1 0x0D4
#define SDRC_MANUAL_1 0x0D8
+#define SDRC_POWER_SRFRONRESET_SHIFT 7
#define SDRC_POWER_AUTOCOUNT_SHIFT 8
#define SDRC_POWER_AUTOCOUNT_MASK (0xffff << SDRC_POWER_AUTOCOUNT_SHIFT)
#define SDRC_POWER_CLKCTRL_SHIFT 4
@@ -87,7 +88,11 @@
#define OMAP242X_SMS_REGADDR(reg) IO_ADDRESS(OMAP2420_SMS_BASE + reg)
#define OMAP243X_SMS_REGADDR(reg) IO_ADDRESS(OMAP243X_SMS_BASE + reg)
+#ifdef __ASSEMBLER__
+#define OMAP343X_SMS_REGADDR(reg) L3_IO_ADDRESS(OMAP343X_SMS_BASE + reg)
+#else
#define OMAP343X_SMS_REGADDR(reg) IO_ADDRESS(OMAP343X_SMS_BASE + reg)
+#endif
/* SMS register offsets - read/write with sms_{read,write}_reg() */
diff --git a/arch/arm/plat-omap/include/mach/serial.h b/arch/arm/plat-omap/include/mach/serial.h
index 4f877ad..4da9721 100644
--- a/arch/arm/plat-omap/include/mach/serial.h
+++ b/arch/arm/plat-omap/include/mach/serial.h
@@ -28,7 +28,7 @@
#define OMAP_UART_EXT_BASE 0x10000000
#endif
-#ifdef CONFIG_MACH_OMAP_ZOOM2
+#if defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)
#define OMAP_MAX_NR_PORTS 4
#else
#define OMAP_MAX_NR_PORTS 3
@@ -50,9 +50,9 @@
extern int omap_uart_can_sleep(void);
extern void omap_uart_check_wakeup(void);
extern void omap_uart_prepare_suspend(void);
-extern void omap_uart_prepare_idle(int num);
+extern void omap_uart_prepare_idle(int num, int power_state);
extern void omap_uart_resume_idle(int num);
-extern void omap_uart_enable_irqs(int enable);
+extern int omap_uart_enable_irqs(int enable);
#endif
#endif
diff --git a/arch/arm/plat-omap/include/mach/sram.h b/arch/arm/plat-omap/include/mach/sram.h
index ad0a600..6a6c488 100644
--- a/arch/arm/plat-omap/include/mach/sram.h
+++ b/arch/arm/plat-omap/include/mach/sram.h
@@ -26,6 +26,9 @@
u32 sdrc_actim_ctrlb, u32 m2,
u32 unlock_dll, u32 f, u32 sdrc_mr,
u32 inc);
+
+extern u32 omap3_configure_core_dpll_warmreset(void);
+
extern void omap3_sram_restore_context(void);
/* Do not use these */
@@ -68,6 +71,10 @@
u32 inc);
extern unsigned long omap3_sram_configure_core_dpll_sz;
+extern u32 omap3_sram_configure_core_dpll_warmreset(void);
+
+extern unsigned long omap3_sram_configure_core_dpll_warmreset_sz;
+
#ifdef CONFIG_PM
extern void omap_push_sram_idle(void);
#else
diff --git a/arch/arm/plat-omap/include/mach/uncompress.h b/arch/arm/plat-omap/include/mach/uncompress.h
index 082c0cd..d29e4b4 100644
--- a/arch/arm/plat-omap/include/mach/uncompress.h
+++ b/arch/arm/plat-omap/include/mach/uncompress.h
@@ -46,8 +46,12 @@
uart = (volatile u8 *)(OMAP_UART3_BASE);
#elif defined(CONFIG_OMAP_LL_DEBUG_UART2)
uart = (volatile u8 *)(OMAP_UART2_BASE);
-#else
+#elif defined(CONFIG_OMAP_LL_DEBUG_UART1)
uart = (volatile u8 *)(OMAP_UART1_BASE);
+#elif defined(CONFIG_OMAP_LL_DEBUG_NONE)
+ return;
+#else
+ return;
#endif
#ifdef CONFIG_ARCH_OMAP1
diff --git a/arch/arm/plat-omap/include/mach/usb.h b/arch/arm/plat-omap/include/mach/usb.h
index daedcb5..7293ab8 100644
--- a/arch/arm/plat-omap/include/mach/usb.h
+++ b/arch/arm/plat-omap/include/mach/usb.h
@@ -37,6 +37,18 @@
}
#endif /* !OMAP1 && !EHCI */
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+extern void usb_ohci_init(void);
+#else
+static inline void usb_ohci_init(void)
+{
+}
+#endif /* !OMAP1 && !OHCI */
+
+/* This is needed for OMAP3 errata 1.164: enabled autoidle can prevent sleep */
+extern void usb_musb_disable_autoidle(void);
+
+
#endif /* !OMAP1 */
void omap_usb_init(struct omap_usb_config *pdata);
diff --git a/arch/arm/plat-omap/include/mach/vmalloc.h b/arch/arm/plat-omap/include/mach/vmalloc.h
index b97dfaf..9eebf62 100644
--- a/arch/arm/plat-omap/include/mach/vmalloc.h
+++ b/arch/arm/plat-omap/include/mach/vmalloc.h
@@ -17,5 +17,5 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define VMALLOC_END (PAGE_OFFSET + 0x18000000)
+#define VMALLOC_END (PAGE_OFFSET + 0x38000000)
diff --git a/arch/arm/plat-omap/iommu-debug.c b/arch/arm/plat-omap/iommu-debug.c
new file mode 100644
index 0000000..9811c19
--- /dev/null
+++ b/arch/arm/plat-omap/iommu-debug.c
@@ -0,0 +1,334 @@
+/*
+ * omap iommu: debugfs interface
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.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/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+
+#include <mach/iommu.h>
+#include <mach/iovmm.h>
+
+#include "iopgtable.h"
+
+#define MAXCOLUMN 100 /* for short messages */
+
+static DEFINE_MUTEX(iommu_debug_lock);
+static char local_buffer[SZ_4K];
+
+static struct dentry *iommu_debug_root;
+
+static ssize_t debug_read_ver(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ u32 ver = iommu_arch_version();
+ char buf[MAXCOLUMN], *p = buf;
+
+ p += sprintf(p, "H/W version: %d.%d\n", (ver >> 4) & 0xf , ver & 0xf);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+
+static ssize_t debug_read_regs(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct iommu *obj = file->private_data;
+ char *p = local_buffer;
+ ssize_t bytes;
+
+ mutex_lock(&iommu_debug_lock);
+ p += iommu_dump_ctx(obj, p);
+ bytes = simple_read_from_buffer(userbuf, count, ppos, local_buffer,
+ p - local_buffer);
+ mutex_unlock(&iommu_debug_lock);
+ return bytes;
+}
+
+static ssize_t debug_read_tlb(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct iommu *obj = file->private_data;
+ char *p = local_buffer;
+ ssize_t bytes;
+
+ mutex_lock(&iommu_debug_lock);
+ p += sprintf(p, "%8s %8s\n", "cam:", "ram:");
+ p += sprintf(p, "-----------------------------------------\n");
+ p += dump_tlb_entries(obj, p);
+ bytes = simple_read_from_buffer(userbuf, count, ppos, local_buffer,
+ p - local_buffer);
+ mutex_unlock(&iommu_debug_lock);
+ return bytes;
+}
+
+static ssize_t debug_write_pagetable(struct file *file,
+ const char __user *userbuf, size_t count, loff_t *ppos)
+{
+ struct iotlb_entry e;
+ struct cr_regs cr;
+ int err;
+ struct iommu *obj = file->private_data;
+ char buf[MAXCOLUMN], *p = buf;
+
+ count = min(count, sizeof(buf));
+
+ mutex_lock(&iommu_debug_lock);
+ if (copy_from_user(p, userbuf, count)) {
+ mutex_unlock(&iommu_debug_lock);
+ return -EFAULT;
+ }
+
+ sscanf(p, "%x %x", &cr.cam, &cr.ram);
+ if (!cr.cam || !cr.ram) {
+ mutex_unlock(&iommu_debug_lock);
+ return -EINVAL;
+ }
+
+ iotlb_cr_to_e(&cr, &e);
+ err = iopgtable_store_entry(obj, &e);
+ if (err)
+ dev_err(obj->dev, "%s: fail to store cr\n", __func__);
+
+ mutex_unlock(&iommu_debug_lock);
+ return count;
+}
+
+static ssize_t debug_read_pagetable(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ int i;
+ u32 *iopgd;
+ struct iommu *obj = file->private_data;
+ char *p = local_buffer;
+ ssize_t bytes;
+
+ mutex_lock(&iommu_debug_lock);
+
+ p += sprintf(p, "L: %8s %8s\n", "da:", "pa:");
+ p += sprintf(p, "-----------------------------------------\n");
+
+ spin_lock(&obj->page_table_lock);
+
+ iopgd = iopgd_offset(obj, 0);
+ for (i = 0; i < PTRS_PER_IOPGD; i++, iopgd++) {
+ int j;
+ u32 *iopte;
+
+ if (!*iopgd)
+ continue;
+
+ if (!(*iopgd & IOPGD_TABLE)) {
+ u32 da;
+
+ da = i << IOPGD_SHIFT;
+ p += sprintf(p, "1: %08x %08x\n", da, *iopgd);
+ continue;
+ }
+
+ iopte = iopte_offset(iopgd, 0);
+
+ for (j = 0; j < PTRS_PER_IOPTE; j++, iopte++) {
+ u32 da;
+
+ if (!*iopte)
+ continue;
+
+ da = (i << IOPGD_SHIFT) + (j << IOPTE_SHIFT);
+ p += sprintf(p, "2: %08x %08x\n", da, *iopte);
+ }
+ }
+ spin_unlock(&obj->page_table_lock);
+
+ bytes = simple_read_from_buffer(userbuf, count, ppos, local_buffer,
+ p - local_buffer);
+ mutex_unlock(&iommu_debug_lock);
+ return bytes;
+}
+
+static ssize_t debug_read_mmap(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct iommu *obj = file->private_data;
+ char *p = local_buffer;
+ struct iovm_struct *tmp;
+ int uninitialized_var(i);
+ ssize_t bytes;
+
+ mutex_lock(&iommu_debug_lock);
+
+ p += sprintf(p, "%-3s %-8s %-8s %6s %8s\n",
+ "No", "start", "end", "size", "flags");
+ p += sprintf(p, "-------------------------------------------------\n");
+
+ list_for_each_entry(tmp, &obj->mmap, list) {
+ size_t len;
+
+ len = tmp->da_end - tmp->da_start;
+ p += sprintf(p, "%3d %08x-%08x %6x %8x\n",
+ i, tmp->da_start, tmp->da_end, len, tmp->flags);
+ i++;
+ }
+ bytes = simple_read_from_buffer(userbuf, count, ppos, local_buffer,
+ p - local_buffer);
+ mutex_unlock(&iommu_debug_lock);
+ return bytes;
+}
+
+static ssize_t debug_read_mem(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct iommu *obj = file->private_data;
+ char *p = local_buffer;
+ struct iovm_struct *area;
+ ssize_t bytes;
+
+ mutex_lock(&iommu_debug_lock);
+
+ area = find_iovm_area(obj, (u32)ppos);
+ if (IS_ERR(area)) {
+ mutex_unlock(&iommu_debug_lock);
+ return -EINVAL;
+ }
+ memcpy(p, area->va, count);
+ p += count;
+
+ bytes = simple_read_from_buffer(userbuf, count, ppos, local_buffer,
+ p - local_buffer);
+ mutex_unlock(&iommu_debug_lock);
+ return bytes;
+}
+
+static ssize_t debug_write_mem(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct iommu *obj = file->private_data;
+ struct iovm_struct *area;
+ char *p = local_buffer;
+
+ count = min(count, sizeof(local_buffer));
+
+ mutex_lock(&iommu_debug_lock);
+
+ if (copy_from_user(p, userbuf, count)) {
+ mutex_unlock(&iommu_debug_lock);
+ return -EFAULT;
+ }
+
+ area = find_iovm_area(obj, (u32)ppos);
+ if (IS_ERR(area)) {
+ mutex_unlock(&iommu_debug_lock);
+ return -EINVAL;
+ }
+ memcpy(area->va, p, count);
+ mutex_unlock(&iommu_debug_lock);
+ return count;
+}
+
+static int debug_open_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+#define DEBUG_FOPS(name) \
+ static const struct file_operations debug_##name##_fops = { \
+ .open = debug_open_generic, \
+ .read = debug_read_##name, \
+ .write = debug_write_##name, \
+ };
+
+#define DEBUG_FOPS_RO(name) \
+ static const struct file_operations debug_##name##_fops = { \
+ .open = debug_open_generic, \
+ .read = debug_read_##name, \
+ };
+
+DEBUG_FOPS_RO(ver);
+DEBUG_FOPS_RO(regs);
+DEBUG_FOPS_RO(tlb);
+DEBUG_FOPS(pagetable);
+DEBUG_FOPS_RO(mmap);
+DEBUG_FOPS(mem);
+
+#define __DEBUG_ADD_FILE(attr, mode) \
+ { \
+ struct dentry *dent; \
+ dent = debugfs_create_file(#attr, mode, parent, \
+ obj, &debug_##attr##_fops); \
+ if (!dent) \
+ return -ENOMEM; \
+ }
+
+#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 600)
+#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 400)
+
+static int iommu_debug_register(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct iommu *obj = platform_get_drvdata(pdev);
+ struct dentry *d, *parent;
+
+ if (!obj || !obj->dev)
+ return -EINVAL;
+
+ d = debugfs_create_dir(obj->name, iommu_debug_root);
+ if (!d)
+ return -ENOMEM;
+ parent = d;
+
+ d = debugfs_create_u8("nr_tlb_entries", 400, parent,
+ (u8 *)&obj->nr_tlb_entries);
+ if (!d)
+ return -ENOMEM;
+
+ DEBUG_ADD_FILE_RO(ver);
+ DEBUG_ADD_FILE_RO(regs);
+ DEBUG_ADD_FILE_RO(tlb);
+ DEBUG_ADD_FILE(pagetable);
+ DEBUG_ADD_FILE_RO(mmap);
+ DEBUG_ADD_FILE(mem);
+
+ return 0;
+}
+
+static int __init iommu_debug_init(void)
+{
+ struct dentry *d;
+ int err;
+
+ d = debugfs_create_dir("iommu", NULL);
+ if (!d)
+ return -ENOMEM;
+ iommu_debug_root = d;
+
+ err = foreach_iommu_device(d, iommu_debug_register);
+ if (err)
+ goto err_out;
+ return 0;
+
+err_out:
+ debugfs_remove_recursive(iommu_debug_root);
+ return err;
+}
+module_init(iommu_debug_init)
+
+static void __exit iommu_debugfs_exit(void)
+{
+ debugfs_remove_recursive(iommu_debug_root);
+}
+module_exit(iommu_debugfs_exit)
+
+MODULE_DESCRIPTION("omap iommu: debugfs interface");
+MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
index e638883..d1a0661 100644
--- a/arch/arm/plat-omap/iommu.c
+++ b/arch/arm/plat-omap/iommu.c
@@ -1,7 +1,7 @@
/*
* omap iommu: tlb and pagetable primitives
*
- * Copyright (C) 2008-2009 Nokia Corporation
+ * Copyright (C) 2008-2010 Nokia Corporation
*
* Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>,
* Paul Mundt and Toshihiro Kobayashi
@@ -18,10 +18,8 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
-#include <asm/io.h>
#include <asm/cacheflush.h>
-#include <mach/clock.h>
#include <mach/iommu.h>
#include "iopgtable.h"
@@ -33,7 +31,7 @@
static struct kmem_cache *iopte_cachep;
/**
- * install_iommu_arch() - Install archtecure specific iommu functions
+ * install_iommu_arch - Install archtecure specific iommu functions
* @ops: a pointer to architecture specific iommu functions
*
* There are several kind of iommu algorithm(tlb, pagetable) among
@@ -50,7 +48,7 @@
EXPORT_SYMBOL_GPL(install_iommu_arch);
/**
- * uninstall_iommu_arch() - Uninstall archtecure specific iommu functions
+ * uninstall_iommu_arch - Uninstall archtecure specific iommu functions
* @ops: a pointer to architecture specific iommu functions
*
* This interface uninstalls the iommu algorighm installed previously.
@@ -65,7 +63,7 @@
EXPORT_SYMBOL_GPL(uninstall_iommu_arch);
/**
- * iommu_save_ctx() - Save registers for pm off-mode support
+ * iommu_save_ctx - Save registers for pm off-mode support
* @obj: target iommu
**/
void iommu_save_ctx(struct iommu *obj)
@@ -75,7 +73,7 @@
EXPORT_SYMBOL_GPL(iommu_save_ctx);
/**
- * iommu_restore_ctx() - Restore registers for pm off-mode support
+ * iommu_restore_ctx - Restore registers for pm off-mode support
* @obj: target iommu
**/
void iommu_restore_ctx(struct iommu *obj)
@@ -85,7 +83,7 @@
EXPORT_SYMBOL_GPL(iommu_restore_ctx);
/**
- * iommu_arch_version() - Return running iommu arch version
+ * iommu_arch_version - Return running iommu arch version
**/
u32 iommu_arch_version(void)
{
@@ -120,25 +118,16 @@
clk_disable(obj->clk);
}
-#ifdef DEBUG
-static ssize_t iommu_dump_ctx(struct iommu *obj, char *buf)
-{
- if (!obj || !buf)
- return -EINVAL;
-
- return arch_iommu->dump_ctx(obj, buf);
-}
-#endif
-
/*
* TLB operations
*/
-static inline void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
+void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
{
BUG_ON(!cr || !e);
arch_iommu->cr_to_e(cr, e);
}
+EXPORT_SYMBOL_GPL(iotlb_cr_to_e);
static inline int iotlb_cr_valid(struct cr_regs *cr)
{
@@ -157,10 +146,11 @@
return arch_iommu->alloc_cr(obj, e);
}
-static inline u32 iotlb_cr_to_virt(struct cr_regs *cr)
+u32 iotlb_cr_to_virt(struct cr_regs *cr)
{
return arch_iommu->cr_to_virt(cr);
}
+EXPORT_SYMBOL_GPL(iotlb_cr_to_virt);
static u32 get_iopte_attr(struct iotlb_entry *e)
{
@@ -210,21 +200,21 @@
}
/**
- * iotlb_dump_cr() - Dump an iommu tlb entry into buf
+ * iotlb_dump_cr - Dump an iommu tlb entry into buf
* @obj: target iommu
* @cr: contents of cam and ram register
* @buf: output buffer
**/
-ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf)
+static inline ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr,
+ char *buf)
{
BUG_ON(!cr || !buf);
return arch_iommu->dump_cr(obj, cr, buf);
}
-EXPORT_SYMBOL_GPL(iotlb_dump_cr);
/**
- * load_iotlb_entry() - Set an iommu tlb entry
+ * load_iotlb_entry - Set an iommu tlb entry
* @obj: target iommu
* @e: an iommu tlb entry info
**/
@@ -277,7 +267,7 @@
EXPORT_SYMBOL_GPL(load_iotlb_entry);
/**
- * flush_iotlb_page() - Clear an iommu tlb entry
+ * flush_iotlb_page - Clear an iommu tlb entry
* @obj: target iommu
* @da: iommu device virtual address
*
@@ -308,7 +298,7 @@
if ((start <= da) && (da < start + bytes)) {
dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
__func__, start, da, bytes);
-
+ iotlb_load_cr(obj, &cr);
iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
}
}
@@ -320,7 +310,7 @@
EXPORT_SYMBOL_GPL(flush_iotlb_page);
/**
- * flush_iotlb_range() - Clear an iommu tlb entries
+ * flush_iotlb_range - Clear an iommu tlb entries
* @obj: target iommu
* @start: iommu device virtual address(start)
* @end: iommu device virtual address(end)
@@ -340,7 +330,7 @@
EXPORT_SYMBOL_GPL(flush_iotlb_range);
/**
- * flush_iotlb_all() - Clear all iommu tlb entries
+ * flush_iotlb_all - Clear all iommu tlb entries
* @obj: target iommu
**/
void flush_iotlb_all(struct iommu *obj)
@@ -359,6 +349,88 @@
}
EXPORT_SYMBOL_GPL(flush_iotlb_all);
+#if defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
+
+ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t bytes)
+{
+ if (!obj || !buf)
+ return -EINVAL;
+
+ clk_enable(obj->clk);
+
+ bytes = arch_iommu->dump_ctx(obj, buf, bytes);
+
+ clk_disable(obj->clk);
+
+ return bytes;
+}
+EXPORT_SYMBOL_GPL(iommu_dump_ctx);
+
+static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs, int num)
+{
+ int i;
+ struct iotlb_lock saved, l;
+ struct cr_regs *p = crs;
+
+ clk_enable(obj->clk);
+
+ iotlb_lock_get(obj, &saved);
+ memcpy(&l, &saved, sizeof(saved));
+
+ for (i = 0; i < num; i++) {
+ struct cr_regs tmp;
+
+ iotlb_lock_get(obj, &l);
+ l.vict = i;
+ iotlb_lock_set(obj, &l);
+ iotlb_read_cr(obj, &tmp);
+ if (!iotlb_cr_valid(&tmp))
+ continue;
+
+ *p++ = tmp;
+ }
+ iotlb_lock_set(obj, &saved);
+ clk_disable(obj->clk);
+
+ return p - crs;
+}
+
+/**
+ * dump_tlb_entries - dump cr arrays to given buffer
+ * @obj: target iommu
+ * @buf: output buffer
+ **/
+size_t dump_tlb_entries(struct iommu *obj, char *buf, ssize_t bytes)
+{
+ int i, num;
+ struct cr_regs *cr;
+ char *p = buf;
+
+ num = bytes / sizeof(*cr);
+ num = min(obj->nr_tlb_entries, num);
+
+ cr = kcalloc(num, sizeof(*cr), GFP_KERNEL);
+ if (!cr)
+ return 0;
+
+ num = __dump_tlb_entries(obj, cr, num);
+ for (i = 0; i < num; i++)
+ p += iotlb_dump_cr(obj, cr + i, p);
+ kfree(cr);
+
+ return p - buf;
+}
+EXPORT_SYMBOL_GPL(dump_tlb_entries);
+
+int foreach_iommu_device(void *data, int (*fn)(struct device *, void *))
+{
+ return driver_for_each_device(&omap_iommu_driver.driver,
+ NULL, data, fn);
+}
+EXPORT_SYMBOL_GPL(foreach_iommu_device);
+
+#endif /* CONFIG_OMAP_IOMMU_DEBUG_MODULE */
+
/*
* H/W pagetable operations
*/
@@ -515,41 +587,8 @@
return err;
}
-#ifdef DEBUG
-static void dump_tlb_entries(struct iommu *obj)
-{
- int i;
- struct iotlb_lock l;
-
- clk_enable(obj->clk);
-
- pr_info("%8s %8s\n", "cam:", "ram:");
- pr_info("-----------------------------------------\n");
-
- for (i = 0; i < obj->nr_tlb_entries; i++) {
- struct cr_regs cr;
- static char buf[4096];
-
- iotlb_lock_get(obj, &l);
- l.vict = i;
- iotlb_lock_set(obj, &l);
- iotlb_read_cr(obj, &cr);
- if (!iotlb_cr_valid(&cr))
- continue;
-
- memset(buf, 0, 4096);
- iotlb_dump_cr(obj, &cr, buf);
- pr_err("%s", buf);
- }
-
- clk_disable(obj->clk);
-}
-#else
-static inline void dump_tlb_entries(struct iommu *obj) {}
-#endif
-
/**
- * iopgtable_store_entry() - Make an iommu pte entry
+ * iopgtable_store_entry - Make an iommu pte entry
* @obj: target iommu
* @e: an iommu tlb entry info
**/
@@ -559,7 +598,7 @@
flush_iotlb_page(obj, e->da);
err = iopgtable_store_entry_core(obj, e);
-#ifdef USE_IOTLB
+#ifdef PREFETCH_IOTLB
if (!err)
load_iotlb_entry(obj, e);
#endif
@@ -568,7 +607,7 @@
EXPORT_SYMBOL_GPL(iopgtable_store_entry);
/**
- * iopgtable_lookup_entry() - Lookup an iommu pte entry
+ * iopgtable_lookup_entry - Lookup an iommu pte entry
* @obj: target iommu
* @da: iommu device virtual address
* @ppgd: iommu pgd entry pointer to be returned
@@ -607,7 +646,7 @@
if (*iopte & IOPTE_LARGE) {
nent *= 16;
/* rewind to the 1st entry */
- iopte = (u32 *)((u32)iopte & IOLARGE_MASK);
+ iopte = iopte_offset(iopgd, (da & IOLARGE_MASK));
}
bytes *= nent;
memset(iopte, 0, nent * sizeof(*iopte));
@@ -625,10 +664,10 @@
nent = 1; /* for the next L1 entry */
} else {
bytes = IOPGD_SIZE;
- if (*iopgd & IOPGD_SUPER) {
+ if ((*iopgd & IOPGD_SUPER) == IOPGD_SUPER) {
nent *= 16;
/* rewind to the 1st entry */
- iopgd = (u32 *)((u32)iopgd & IOSUPER_MASK);
+ iopgd = iopgd_offset(obj, (da & IOSUPER_MASK));
}
bytes *= nent;
}
@@ -639,7 +678,7 @@
}
/**
- * iopgtable_clear_entry() - Remove an iommu pte entry
+ * iopgtable_clear_entry - Remove an iommu pte entry
* @obj: target iommu
* @da: iommu device virtual address
**/
@@ -696,6 +735,9 @@
int err = -EIO;
struct iommu *obj = data;
+ if (!obj->refcount)
+ return IRQ_NONE;
+
/* Dynamic loading TLB or PTE */
if (obj->isr)
err = obj->isr(obj);
@@ -703,7 +745,9 @@
if (!err)
return IRQ_HANDLED;
+ clk_enable(obj->clk);
stat = iommu_report_fault(obj, &da);
+ clk_disable(obj->clk);
if (!stat)
return IRQ_HANDLED;
@@ -720,8 +764,6 @@
dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n",
__func__, da, iopgd, *iopgd, iopte, *iopte);
- dump_tlb_entries(obj);
-
return IRQ_NONE;
}
@@ -736,7 +778,7 @@
}
/**
- * iommu_put() - Get iommu handler
+ * iommu_get - Get iommu handler
* @name: target iommu name
**/
struct iommu *iommu_get(const char *name)
@@ -773,13 +815,14 @@
if (obj->refcount == 1)
iommu_disable(obj);
err_enable:
+ obj->refcount--;
mutex_unlock(&obj->iommu_lock);
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(iommu_get);
/**
- * iommu_put() - Put back iommu handler
+ * iommu_put - Put back iommu handler
* @obj: target iommu
**/
void iommu_put(struct iommu *obj)
@@ -928,8 +971,9 @@
{
struct kmem_cache *p;
const unsigned long flags = SLAB_HWCACHE_ALIGN;
+ size_t align = 1 << 10; /* L2 pagetable alignement */
- p = kmem_cache_create("iopte_cache", IOPTE_TABLE_SIZE, 0, flags,
+ p = kmem_cache_create("iopte_cache", IOPTE_TABLE_SIZE, align, flags,
iopte_cachep_ctor);
if (!p)
return -ENOMEM;
diff --git a/arch/arm/plat-omap/iopgtable.h b/arch/arm/plat-omap/iopgtable.h
index 37dac43..ab23b6a 100644
--- a/arch/arm/plat-omap/iopgtable.h
+++ b/arch/arm/plat-omap/iopgtable.h
@@ -1,7 +1,7 @@
/*
* omap iommu: pagetable definitions
*
- * Copyright (C) 2008-2009 Nokia Corporation
+ * Copyright (C) 2008-2010 Nokia Corporation
*
* Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
*
@@ -13,26 +13,52 @@
#ifndef __PLAT_OMAP_IOMMU_H
#define __PLAT_OMAP_IOMMU_H
+/*
+ * "L2 table" address mask and size definitions.
+ */
#define IOPGD_SHIFT 20
-#define IOPGD_SIZE (1 << IOPGD_SHIFT)
+#define IOPGD_SIZE (1UL << IOPGD_SHIFT)
#define IOPGD_MASK (~(IOPGD_SIZE - 1))
-#define IOSECTION_MASK IOPGD_MASK
-#define PTRS_PER_IOPGD (1 << (32 - IOPGD_SHIFT))
-#define IOPGD_TABLE_SIZE (PTRS_PER_IOPGD * sizeof(u32))
-#define IOSUPER_SIZE (IOPGD_SIZE << 4)
+/*
+ * "section" address mask and size definitions.
+ */
+#define IOSECTION_SHIFT 20
+#define IOSECTION_SIZE (1UL << IOSECTION_SHIFT)
+#define IOSECTION_MASK (~(IOSECTION_SIZE - 1))
+
+/*
+ * "supersection" address mask and size definitions.
+ */
+#define IOSUPER_SHIFT 24
+#define IOSUPER_SIZE (1UL << IOSUPER_SHIFT)
#define IOSUPER_MASK (~(IOSUPER_SIZE - 1))
-#define IOPTE_SHIFT 12
-#define IOPTE_SIZE (1 << IOPTE_SHIFT)
-#define IOPTE_MASK (~(IOPTE_SIZE - 1))
-#define IOPAGE_MASK IOPTE_MASK
-#define PTRS_PER_IOPTE (1 << (IOPGD_SHIFT - IOPTE_SHIFT))
-#define IOPTE_TABLE_SIZE (PTRS_PER_IOPTE * sizeof(u32))
+#define PTRS_PER_IOPGD (1UL << (32 - IOPGD_SHIFT))
+#define IOPGD_TABLE_SIZE (PTRS_PER_IOPGD * sizeof(u32))
-#define IOLARGE_SIZE (IOPTE_SIZE << 4)
+/*
+ * "small page" address mask and size definitions.
+ */
+#define IOPTE_SHIFT 12
+#define IOPTE_SIZE (1UL << IOPTE_SHIFT)
+#define IOPTE_MASK (~(IOPTE_SIZE - 1))
+
+/*
+ * "large page" address mask and size definitions.
+ */
+#define IOLARGE_SHIFT 16
+#define IOLARGE_SIZE (1UL << IOLARGE_SHIFT)
#define IOLARGE_MASK (~(IOLARGE_SIZE - 1))
+#define PTRS_PER_IOPTE (1UL << (IOPGD_SHIFT - IOPTE_SHIFT))
+#define IOPTE_TABLE_SIZE (PTRS_PER_IOPTE * sizeof(u32))
+
+#define IOPAGE_MASK IOPTE_MASK
+
+/*
+ * some descriptor attributes.
+ */
#define IOPGD_TABLE (1 << 0)
#define IOPGD_SECTION (2 << 0)
#define IOPGD_SUPER (1 << 18 | 2 << 0)
@@ -40,12 +66,14 @@
#define IOPTE_SMALL (2 << 0)
#define IOPTE_LARGE (1 << 0)
+/* to find an entry in a page-table-directory */
#define iopgd_index(da) (((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1))
#define iopgd_offset(obj, da) ((obj)->iopgd + iopgd_index(da))
#define iopte_paddr(iopgd) (*iopgd & ~((1 << 10) - 1))
#define iopte_vaddr(iopgd) ((u32 *)phys_to_virt(iopte_paddr(iopgd)))
+/* to find an entry in the second-level page table. */
#define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1))
#define iopte_offset(iopgd, da) (iopte_vaddr(iopgd) + iopte_index(da))
diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c
index bdfbb09..6792f3d 100644
--- a/arch/arm/plat-omap/iovmm.c
+++ b/arch/arm/plat-omap/iovmm.c
@@ -15,8 +15,8 @@
#include <linux/device.h>
#include <linux/scatterlist.h>
-#include <asm/io.h>
#include <asm/cacheflush.h>
+#include <asm/mach/map.h>
#include <mach/iommu.h>
#include <mach/iovmm.h>
@@ -47,7 +47,7 @@
* 'va': mpu virtual address
*
* 'c': contiguous memory area
- * 'd': dicontiguous memory area
+ * 'd': discontiguous memory area
* 'a': anonymous memory allocation
* '()': optional feature
*
@@ -167,6 +167,11 @@
unsigned int i;
struct scatterlist *sg;
struct vm_struct *new;
+ const struct mem_type *mtype;
+
+ mtype = get_mem_type(MT_DEVICE);
+ if (!mtype)
+ return ERR_PTR(-EINVAL);
total = sgtable_len(sgt);
if (!total)
@@ -187,14 +192,15 @@
BUG_ON(bytes != PAGE_SIZE);
- err = ioremap_page(va, pa, MT_DEVICE);
+ err = ioremap_page(va, pa, mtype);
if (err)
goto err_out;
va += bytes;
}
- flush_cache_vmap(new->addr, total);
+ flush_cache_vmap((unsigned long)new->addr,
+ (unsigned long)(new->addr + total));
return new->addr;
err_out:
@@ -353,12 +359,13 @@
area = __find_iovm_area(obj, da);
if (!area) {
- dev_warn(obj->dev, "%s: no da area(%08x)\n", __func__, da);
+ dev_dbg(obj->dev, "%s: no da area(%08x)\n", __func__, da);
goto out;
}
va = area->va;
- mutex_unlock(&obj->mmap_lock);
out:
+ mutex_unlock(&obj->mmap_lock);
+
return va;
}
EXPORT_SYMBOL_GPL(da_to_va);
@@ -385,14 +392,13 @@
}
va_end = _va + PAGE_SIZE * i;
- flush_cache_vmap(_va, va_end);
}
static inline void sgtable_drain_vmalloc(struct sg_table *sgt)
{
/*
* Actually this is not necessary at all, just exists for
- * consistency of the code readibility.
+ * consistency of the code readability.
*/
BUG_ON(!sgt);
}
@@ -420,15 +426,13 @@
len -= bytes;
}
BUG_ON(len);
-
- clean_dcache_area(va, len);
}
static inline void sgtable_drain_kmalloc(struct sg_table *sgt)
{
/*
* Actually this is not necessary at all, just exists for
- * consistency of the code readibility
+ * consistency of the code readability
*/
BUG_ON(!sgt);
}
@@ -442,7 +446,7 @@
struct scatterlist *sg;
u32 da = new->da_start;
- if (!obj || !new || !sgt)
+ if (!obj || !sgt)
return -EINVAL;
BUG_ON(!sgtable_ok(sgt));
@@ -532,7 +536,7 @@
area = __find_iovm_area(obj, da);
if (!area) {
- dev_err(obj->dev, "%s: no da area(%08x)\n", __func__, da);
+ dev_dbg(obj->dev, "%s: no da area(%08x)\n", __func__, da);
goto out;
}
@@ -610,7 +614,7 @@
u32 flags)
{
size_t bytes;
- void *va;
+ void *va = NULL;
if (!obj || !obj->dev || !sgt)
return -EINVAL;
@@ -620,9 +624,11 @@
return -EINVAL;
bytes = PAGE_ALIGN(bytes);
- va = vmap_sg(sgt);
- if (IS_ERR(va))
- return PTR_ERR(va);
+ if (flags & IOVMF_MMIO) {
+ va = vmap_sg(sgt);
+ if (IS_ERR(va))
+ return PTR_ERR(va);
+ }
flags &= IOVMF_HW_MASK;
flags |= IOVMF_DISCONT;
@@ -654,7 +660,7 @@
*/
sgt = unmap_vm_area(obj, da, vunmap_sg, IOVMF_DISCONT | IOVMF_MMIO);
if (!sgt)
- dev_err(obj->dev, "%s: No sgt\n", __func__);
+ dev_dbg(obj->dev, "%s: No sgt\n", __func__);
return sgt;
}
EXPORT_SYMBOL_GPL(iommu_vunmap);
@@ -724,7 +730,7 @@
sgt = unmap_vm_area(obj, da, vfree, IOVMF_DISCONT | IOVMF_ALLOC);
if (!sgt)
- dev_err(obj->dev, "%s: No sgt\n", __func__);
+ dev_dbg(obj->dev, "%s: No sgt\n", __func__);
sgtable_free(sgt);
}
EXPORT_SYMBOL_GPL(iommu_vfree);
@@ -797,10 +803,12 @@
void iommu_kunmap(struct iommu *obj, u32 da)
{
struct sg_table *sgt;
+ typedef void (*func_t)(const void *);
- sgt = unmap_vm_area(obj, da, __iounmap, IOVMF_LINEAR | IOVMF_MMIO);
+ sgt = unmap_vm_area(obj, da, (func_t)__iounmap,
+ IOVMF_LINEAR | IOVMF_MMIO);
if (!sgt)
- dev_err(obj->dev, "%s: No sgt\n", __func__);
+ dev_dbg(obj->dev, "%s: No sgt\n", __func__);
sgtable_free(sgt);
}
EXPORT_SYMBOL_GPL(iommu_kunmap);
@@ -857,7 +865,7 @@
sgt = unmap_vm_area(obj, da, kfree, IOVMF_LINEAR | IOVMF_ALLOC);
if (!sgt)
- dev_err(obj->dev, "%s: No sgt\n", __func__);
+ dev_dbg(obj->dev, "%s: No sgt\n", __func__);
sgtable_free(sgt);
}
EXPORT_SYMBOL_GPL(iommu_kfree);
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index e2e8b76..2eafca0 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -91,11 +91,20 @@
static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
{
struct omap_mcbsp *mcbsp_tx = dev_id;
+ u16 irqst_spcr2;
- dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n",
- OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
+ irqst_spcr2 = OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2);
+ dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
- complete(&mcbsp_tx->tx_irq_completion);
+ if (irqst_spcr2 & XSYNC_ERR) {
+ dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n",
+ irqst_spcr2);
+ /* Writing zero to XSYNC_ERR clears the IRQ */
+ OMAP_MCBSP_WRITE(mcbsp_tx->io_base, SPCR2,
+ irqst_spcr2 & ~(XSYNC_ERR));
+ } else {
+ complete(&mcbsp_tx->tx_irq_completion);
+ }
return IRQ_HANDLED;
}
@@ -103,11 +112,20 @@
static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
{
struct omap_mcbsp *mcbsp_rx = dev_id;
+ u16 irqst_spcr1;
- dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n",
- OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
+ irqst_spcr1 = OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR1);
+ dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
- complete(&mcbsp_rx->rx_irq_completion);
+ if (irqst_spcr1 & RSYNC_ERR) {
+ dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n",
+ irqst_spcr1);
+ /* Writing zero to RSYNC_ERR clears the IRQ */
+ OMAP_MCBSP_WRITE(mcbsp_rx->io_base, SPCR1,
+ irqst_spcr1 & ~(RSYNC_ERR));
+ } else {
+ complete(&mcbsp_rx->tx_irq_completion);
+ }
return IRQ_HANDLED;
}
@@ -176,6 +194,7 @@
if (cpu_is_omap2430() || cpu_is_omap34xx()) {
OMAP_MCBSP_WRITE(io_base, XCCR, config->xccr);
OMAP_MCBSP_WRITE(io_base, RCCR, config->rccr);
+ OMAP_MCBSP_WRITE(io_base, WAKEUPEN, config->wken);
}
}
EXPORT_SYMBOL(omap_mcbsp_config);
@@ -290,6 +309,33 @@
}
EXPORT_SYMBOL(omap_mcbsp_request);
+void omap_mcbsp_disable_fclk(unsigned int id)
+{
+ struct omap_mcbsp *mcbsp;
+
+ if (!omap_mcbsp_check_valid_id(id)) {
+ printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
+ return;
+ }
+ mcbsp = id_to_mcbsp_ptr(id);
+ clk_disable(mcbsp->clks[1]);
+}
+EXPORT_SYMBOL(omap_mcbsp_disable_fclk);
+
+
+void omap_mcbsp_enable_fclk(unsigned int id)
+{
+ struct omap_mcbsp *mcbsp;
+
+ if (!omap_mcbsp_check_valid_id(id)) {
+ printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
+ return;
+ }
+ mcbsp = id_to_mcbsp_ptr(id);
+ clk_enable(mcbsp->clks[1]);
+}
+EXPORT_SYMBOL(omap_mcbsp_enable_fclk);
+
void omap_mcbsp_free(unsigned int id)
{
struct omap_mcbsp *mcbsp;
@@ -343,15 +389,16 @@
}
EXPORT_SYMBOL(omap_mcbsp_free);
-/*
- * Here we start the McBSP, by enabling the sample
- * generator, both transmitter and receivers,
- * and the frame sync.
- */
-void omap_mcbsp_start(unsigned int id)
+ /*
+ * Here we start the McBSP, by enabling transmitter, receiver or both.
+ * If no transmitter or receiver is active prior calling, then sample-rate
+ * generator and frame sync are started.
+ */
+void omap_mcbsp_start(unsigned int id, int tx, int rx)
{
struct omap_mcbsp *mcbsp;
void __iomem *io_base;
+ int idle;
u16 w;
if (!omap_mcbsp_check_valid_id(id)) {
@@ -364,32 +411,40 @@
mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7;
mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7;
- /* Start the sample generator */
- w = OMAP_MCBSP_READ(io_base, SPCR2);
- OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
+ idle = !((OMAP_MCBSP_READ(io_base, SPCR2) |
+ OMAP_MCBSP_READ(io_base, SPCR1)) & 1);
+
+ if (idle) {
+ /* Start the sample generator */
+ w = OMAP_MCBSP_READ(io_base, SPCR2);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
+ }
/* Enable transmitter and receiver */
w = OMAP_MCBSP_READ(io_base, SPCR2);
- OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w | (tx & 1));
w = OMAP_MCBSP_READ(io_base, SPCR1);
- OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1);
+ OMAP_MCBSP_WRITE(io_base, SPCR1, w | (rx & 1));
udelay(100);
- /* Start frame sync */
- w = OMAP_MCBSP_READ(io_base, SPCR2);
- OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
+ if (idle) {
+ /* Start frame sync */
+ w = OMAP_MCBSP_READ(io_base, SPCR2);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
+ }
/* Dump McBSP Regs */
omap_mcbsp_dump_reg(id);
}
EXPORT_SYMBOL(omap_mcbsp_start);
-void omap_mcbsp_stop(unsigned int id)
+void omap_mcbsp_stop(unsigned int id, int tx, int rx)
{
struct omap_mcbsp *mcbsp;
void __iomem *io_base;
+ int idle;
u16 w;
if (!omap_mcbsp_check_valid_id(id)) {
@@ -402,15 +457,20 @@
/* Reset transmitter */
w = OMAP_MCBSP_READ(io_base, SPCR2);
- OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1));
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(tx & 1));
/* Reset receiver */
w = OMAP_MCBSP_READ(io_base, SPCR1);
- OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1));
+ OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(rx & 1));
- /* Reset the sample rate generator */
- w = OMAP_MCBSP_READ(io_base, SPCR2);
- OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
+ idle = !((OMAP_MCBSP_READ(io_base, SPCR2) |
+ OMAP_MCBSP_READ(io_base, SPCR1)) & 1);
+
+ if (idle) {
+ /* Reset the sample rate generator */
+ w = OMAP_MCBSP_READ(io_base, SPCR2);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
+ }
}
EXPORT_SYMBOL(omap_mcbsp_stop);
@@ -899,6 +959,21 @@
}
EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
+void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
+{
+ struct omap_mcbsp *mcbsp;
+ void __iomem *io_base;
+ u16 w;
+
+ mcbsp = id_to_mcbsp_ptr(id);
+ io_base = mcbsp->io_base;
+
+
+ OMAP_MCBSP_WRITE(io_base, THRSH2, threshold-1);
+ w = OMAP_MCBSP_READ(io_base, THRSH2);
+}
+EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold);
+
/*
* McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
* 730 has only 2 McBSP, and both of them are MPU peripherals.
diff --git a/arch/arm/plat-omap/omap-pm-srf.c b/arch/arm/plat-omap/omap-pm-srf.c
index 226662d..19bff37 100644
--- a/arch/arm/plat-omap/omap-pm-srf.c
+++ b/arch/arm/plat-omap/omap-pm-srf.c
@@ -27,6 +27,7 @@
#include <mach/powerdomain.h>
#include <mach/resource.h>
#include <mach/omapdev.h>
+#include <mach/omap34xx.h>
struct omap_opp *dsp_opps;
struct omap_opp *mpu_opps;
@@ -93,6 +94,7 @@
resource_request("vdd2_opp", dev, r);
}
}
+EXPORT_SYMBOL(omap_pm_set_min_bus_tput);
void omap_pm_set_max_dev_wakeup_lat(struct device *dev, long t)
{
@@ -183,7 +185,7 @@
* array should have .rate = .opp_id = 0.
*/
- return NULL;
+ return dsp_opps;
}
EXPORT_SYMBOL(omap_pm_dsp_get_opp_table);
@@ -263,6 +265,21 @@
}
EXPORT_SYMBOL(omap_pm_cpu_set_freq);
+void omap_pm_set_min_mpu_freq(struct device *dev, unsigned long f)
+{
+ if (f == 0) {
+ WARN_ON(1);
+ return;
+ }
+
+ pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n",
+ f);
+
+ resource_request("mpu_freq", dev, f);
+ return;
+}
+EXPORT_SYMBOL(omap_pm_set_min_mpu_freq);
+
unsigned long omap_pm_cpu_get_freq(void)
{
pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n");
@@ -352,3 +369,70 @@
{
/* Deallocate CPUFreq frequency table here */
}
+
+u8 omap_pm_get_max_vdd1_opp()
+{
+ if (cpu_is_omap3630()) {
+ switch (omap_rev_id()) {
+ case OMAP_3630:
+ default:
+ return VDD1_OPP4;
+ case OMAP_3630_800:
+ return VDD1_OPP3;
+ case OMAP_3630_1000:
+ return VDD1_OPP4;
+ }
+ } else {
+ if (omap_rev() < OMAP3430_REV_ES3_1)
+ return VDD1_OPP5;
+ else {
+ switch (omap_rev_id()) {
+ case OMAP_3420:
+ case OMAP_3430:
+ return VDD1_OPP5;
+ case OMAP_3440:
+ return VDD1_OPP6;
+ default:
+ return VDD1_OPP5;
+ }
+ }
+ }
+}
+EXPORT_SYMBOL(omap_pm_get_max_vdd1_opp);
+
+u8 omap_pm_get_min_vdd1_opp(void)
+{
+ return VDD1_OPP1;
+}
+EXPORT_SYMBOL(omap_pm_get_min_vdd1_opp);
+
+
+u8 omap_pm_get_max_vdd2_opp(void)
+{
+ if (cpu_is_omap3630())
+ return VDD2_OPP2;
+ else
+ return VDD2_OPP3;
+}
+EXPORT_SYMBOL(omap_pm_get_max_vdd2_opp);
+
+u8 omap_pm_get_min_vdd2_opp(void)
+{
+ if (cpu_is_omap3630())
+ return VDD2_OPP1;
+ else
+ return VDD2_OPP2;
+}
+EXPORT_SYMBOL(omap_pm_get_min_vdd2_opp);
+
+struct omap_opp *omap_get_mpu_rate_table()
+{
+ return mpu_opps;
+}
+EXPORT_SYMBOL(omap_get_mpu_rate_table);
+
+struct omap_opp *omap_get_dsp_rate_table()
+{
+ return dsp_opps;
+}
+EXPORT_SYMBOL(omap_get_dsp_rate_table);
diff --git a/arch/arm/plat-omap/resource.c b/arch/arm/plat-omap/resource.c
index ec31727..80e42da 100644
--- a/arch/arm/plat-omap/resource.c
+++ b/arch/arm/plat-omap/resource.c
@@ -106,11 +106,20 @@
int ret;
/* Regenerate the target_value for the resource */
- target_level = RES_DEFAULTLEVEL;
- list_for_each_entry(user, &resp->users_list, node)
- if (user->level > target_level)
- target_level = user->level;
-
+ if (resp->flags & RES_TYPE_PERFORMANCE) {
+ target_level = RES_PERFORMANCE_DEFAULTLEVEL;
+ list_for_each_entry(user, &resp->users_list, node)
+ if (user->level > target_level)
+ target_level = user->level;
+ } else if (resp->flags & RES_TYPE_LATENCY) {
+ target_level = RES_LATENCY_DEFAULTLEVEL;
+ list_for_each_entry(user, &resp->users_list, node)
+ if (user->level < target_level)
+ target_level = user->level;
+ } else {
+ pr_debug("SRF: Unknown resource type\n");
+ return -EINVAL;
+ }
pr_debug("SRF: Changing Level for resource %s to %ld\n",
resp->name, target_level);
ret = resp->ops->change_level(resp, target_level);
@@ -182,7 +191,6 @@
kfree(user);
} else {
user->usage = UNUSED;
- user->level = RES_DEFAULTLEVEL;
user->dev = NULL;
}
}
@@ -213,7 +221,6 @@
for (ind = 0; ind < MAX_USERS; ind++) {
usr_list[ind].usage = UNUSED;
usr_list[ind].dev = NULL;
- usr_list[ind].level = RES_DEFAULTLEVEL;
}
if (resources)
@@ -253,6 +260,8 @@
*/
int resource_register(struct shared_resource *resp)
{
+ int ret = 0;
+
if (!resp)
return -EINVAL;
@@ -260,12 +269,15 @@
return -EINVAL;
/* Verify that the resource is not already registered */
- if (resource_lookup(resp->name))
- return -EEXIST;
+ down(&res_mutex);
+ if (_resource_lookup(resp->name)) {
+ ret = -EEXIST;
+ goto out;
+ }
INIT_LIST_HEAD(&resp->users_list);
+ mutex_init(&resp->resource_mutex);
- down(&res_mutex);
/* Add the resource to the resource list */
list_add(&resp->node, &res_list);
@@ -273,10 +285,11 @@
if (resp->ops->init)
resp->ops->init(resp);
- up(&res_mutex);
pr_debug("resource: registered %s\n", resp->name);
- return 0;
+out:
+ up(&res_mutex);
+ return ret;
}
EXPORT_SYMBOL(resource_register);
@@ -326,14 +339,13 @@
struct users_list *user;
int found = 0, ret = 0;
- down(&res_mutex);
- resp = _resource_lookup(name);
+ resp = resource_lookup(name);
if (!resp) {
printk(KERN_ERR "resource_request: Invalid resource name\n");
- ret = -EINVAL;
- goto res_unlock;
+ return -EINVAL;
}
+ mutex_lock(&resp->resource_mutex);
/* Call the resource specific validate function */
if (resp->ops->validate_level) {
ret = resp->ops->validate_level(resp, level);
@@ -361,16 +373,11 @@
}
user->level = level;
+ /* Recompute and set the current level for the resource */
+ ret = update_resource_level(resp);
+
res_unlock:
- up(&res_mutex);
- /*
- * Recompute and set the current level for the resource.
- * NOTE: update_resource level moved out of spin_lock, as it may call
- * pm_qos_add_requirement, which does a kzmalloc. This won't be allowed
- * in iterrupt context. The spin_lock still protects add/remove users.
- */
- if (!ret)
- ret = update_resource_level(resp);
+ mutex_unlock(&resp->resource_mutex);
return ret;
}
EXPORT_SYMBOL(resource_request);
@@ -393,14 +400,13 @@
struct users_list *user;
int found = 0, ret = 0;
- down(&res_mutex);
- resp = _resource_lookup(name);
+ resp = resource_lookup(name);
if (!resp) {
printk(KERN_ERR "resource_release: Invalid resource name\n");
- ret = -EINVAL;
- goto res_unlock;
+ return -EINVAL;
}
+ mutex_lock(&resp->resource_mutex);
list_for_each_entry(user, &resp->users_list, node) {
if (user->dev == dev) {
found = 1;
@@ -421,7 +427,7 @@
/* Recompute and set the current level for the resource */
ret = update_resource_level(resp);
res_unlock:
- up(&res_mutex);
+ mutex_unlock(&resp->resource_mutex);
return ret;
}
EXPORT_SYMBOL(resource_release);
@@ -438,15 +444,14 @@
struct shared_resource *resp;
u32 ret;
- down(&res_mutex);
- resp = _resource_lookup(name);
+ resp = resource_lookup(name);
if (!resp) {
printk(KERN_ERR "resource_release: Invalid resource name\n");
- up(&res_mutex);
return -EINVAL;
}
+ mutex_lock(&resp->resource_mutex);
ret = resp->curr_level;
- up(&res_mutex);
+ mutex_unlock(&resp->resource_mutex);
return ret;
}
EXPORT_SYMBOL(resource_get_level);
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 755ccaa..1ed08b5 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -38,10 +38,10 @@
#define OMAP1_SRAM_VA VMALLOC_END
#define OMAP2_SRAM_PA 0x40200000
#define OMAP2_SRAM_PUB_PA 0x4020f800
-#define OMAP2_SRAM_VA 0xe3000000
+#define OMAP2_SRAM_VA 0xfe400000
#define OMAP2_SRAM_PUB_VA (OMAP2_SRAM_VA + 0x800)
#define OMAP3_SRAM_PA 0x40200000
-#define OMAP3_SRAM_VA 0xe3000000
+#define OMAP3_SRAM_VA 0xfc800000
#define OMAP3_SRAM_PUB_PA 0x40208000
#define OMAP3_SRAM_PUB_VA (OMAP3_SRAM_VA + 0x8000)
@@ -386,6 +386,20 @@
unlock_dll, f, sdrc_mr, inc);
}
+
+/* Function for SDRC config for warm reset */
+static u32 (*_omap3_sram_configure_core_dpll_warmreset)(void);
+
+u32 omap3_configure_core_dpll_warmreset(void)
+{
+ if (!_omap3_sram_configure_core_dpll_warmreset)
+ omap_sram_error();
+
+ return _omap3_sram_configure_core_dpll_warmreset();
+}
+
+
+
#ifdef CONFIG_PM
void omap3_sram_restore_context(void)
{
@@ -394,6 +408,11 @@
_omap3_sram_configure_core_dpll =
omap_sram_push(omap3_sram_configure_core_dpll,
omap3_sram_configure_core_dpll_sz);
+
+ _omap3_sram_configure_core_dpll_warmreset =
+ omap_sram_push(omap3_sram_configure_core_dpll_warmreset,
+ omap3_sram_configure_core_dpll_warmreset_sz);
+
omap_push_sram_idle();
}
#endif /* CONFIG_PM */
@@ -403,6 +422,11 @@
_omap3_sram_configure_core_dpll =
omap_sram_push(omap3_sram_configure_core_dpll,
omap3_sram_configure_core_dpll_sz);
+
+ _omap3_sram_configure_core_dpll_warmreset =
+ omap_sram_push(omap3_sram_configure_core_dpll_warmreset,
+ omap3_sram_configure_core_dpll_warmreset_sz);
+
omap_push_sram_idle();
return 0;
}
diff --git a/arch/arm/plat-omap/vrfb.c b/arch/arm/plat-omap/vrfb.c
index f84d2f5..4ce57df 100644
--- a/arch/arm/plat-omap/vrfb.c
+++ b/arch/arm/plat-omap/vrfb.c
@@ -87,8 +87,7 @@
void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
u16 width, u16 height,
- enum omap_color_mode color_mode,
- int rotation)
+ enum omap_color_mode color_mode, int rotation)
{
unsigned pixel_size_exp;
u16 vrfb_width;
@@ -129,6 +128,7 @@
color_mode == OMAP_DSS_COLOR_UYVY)
width >>= 1;
+ /* Configure the vrfb buffer for rotation*/
if (rotation == 1 || rotation == 3) {
temp = width;
width = height;
@@ -142,6 +142,14 @@
else
BUG();
+ /* VDMA Optimization */
+ /* TODO: VDMA support for RGB16 mode */
+ if (cpu_is_omap3630())
+ if (color_mode == OMAP_DSS_COLOR_YUV2)
+ if ((rotation == 1) || (rotation == 3))
+ pixel_size_exp = 2;
+
+
vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT);
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index b4211d8b2..7581295 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -12,7 +12,7 @@
#
# http://www.arm.linux.org.uk/developer/machines/?action=new
#
-# Last update: Thu Mar 12 18:01:45 2009
+# Last update: Fri Oct 9 02:40:40 2009
#
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
#
@@ -916,7 +916,7 @@
apf9328 MACH_APF9328 APF9328 906
omap_wipoq MACH_OMAP_WIPOQ OMAP_WIPOQ 907
omap_twip MACH_OMAP_TWIP OMAP_TWIP 908
-palmt650 MACH_PALMT650 PALMT650 909
+treo650 MACH_TREO650 TREO650 909
acumen MACH_ACUMEN ACUMEN 910
xp100 MACH_XP100 XP100 911
fs2410 MACH_FS2410 FS2410 912
@@ -1232,7 +1232,7 @@
vpac270 MACH_VPAC270 VPAC270 1227
rd129 MACH_RD129 RD129 1228
htcwizard MACH_HTCWIZARD HTCWIZARD 1229
-xscale_treo680 MACH_XSCALE_TREO680 XSCALE_TREO680 1230
+treo680 MACH_TREO680 TREO680 1230
tecon_tmezon MACH_TECON_TMEZON TECON_TMEZON 1231
zylonite MACH_ZYLONITE ZYLONITE 1233
gene1270 MACH_GENE1270 GENE1270 1234
@@ -1418,10 +1418,10 @@
cnty_titan MACH_CNTY_TITAN CNTY_TITAN 1418
app3xx MACH_APP3XX APP3XX 1419
sideoatsgrama MACH_SIDEOATSGRAMA SIDEOATSGRAMA 1420
-palmtreo700p MACH_PALMTREO700P PALMTREO700P 1421
-palmtreo700w MACH_PALMTREO700W PALMTREO700W 1422
-palmtreo750 MACH_PALMTREO750 PALMTREO750 1423
-palmtreo755p MACH_PALMTREO755P PALMTREO755P 1424
+treo700p MACH_TREO700P TREO700P 1421
+treo700w MACH_TREO700W TREO700W 1422
+treo750 MACH_TREO750 TREO750 1423
+treo755p MACH_TREO755P TREO755P 1424
ezreganut9200 MACH_EZREGANUT9200 EZREGANUT9200 1425
sarge MACH_SARGE SARGE 1426
a696 MACH_A696 A696 1427
@@ -1455,7 +1455,7 @@
h6044 MACH_H6044 H6044 1458
app MACH_APP APP 1459
tct_hammer MACH_TCT_HAMMER TCT_HAMMER 1460
-herald MACH_HERMES HERMES 1461
+herald MACH_HERALD HERALD 1461
artemis MACH_ARTEMIS ARTEMIS 1462
htctitan MACH_HTCTITAN HTCTITAN 1463
qranium MACH_QRANIUM QRANIUM 1464
@@ -1638,7 +1638,7 @@
aml_m8050 MACH_AML_M8050 AML_M8050 1644
mx35_3ds MACH_MX35_3DS MX35_3DS 1645
mars MACH_MARS MARS 1646
-ntosd_644xa MACH_NTOSD_644XA NTOSD_644XA 1647
+neuros_osd2 MACH_NEUROS_OSD2 NEUROS_OSD2 1647
badger MACH_BADGER BADGER 1648
trizeps4wl MACH_TRIZEPS4WL TRIZEPS4WL 1649
trizeps5 MACH_TRIZEPS5 TRIZEPS5 1650
@@ -1654,7 +1654,7 @@
zoran43xx MACH_ZORAN43XX ZORAN43XX 1660
sonix926 MACH_SONIX926 SONIX926 1661
celestialsemi MACH_CELESTIALSEMI CELESTIALSEMI 1662
-cc9m2443 MACH_CC9M2443 CC9M2443 1663
+cc9m2443js MACH_CC9M2443JS CC9M2443JS 1663
tw5334 MACH_TW5334 TW5334 1664
omap_htcartemis MACH_HTCARTEMIS HTCARTEMIS 1665
nal_hlite MACH_NAL_HLITE NAL_HLITE 1666
@@ -1721,7 +1721,7 @@
csb637xo MACH_CSB637XO CSB637XO 1730
evisiong MACH_EVISIONG EVISIONG 1731
stmp37xx MACH_STMP37XX STMP37XX 1732
-stmp378x MACH_STMP38XX STMP38XX 1733
+stmp378x MACH_STMP378X STMP378X 1733
tnt MACH_TNT TNT 1734
tbxt MACH_TBXT TBXT 1735
playmate MACH_PLAYMATE PLAYMATE 1736
@@ -1769,7 +1769,7 @@
mi424wr MACH_MI424WR MI424WR 1778
axs_ultrax MACH_AXS_ULTRAX AXS_ULTRAX 1779
at572d940deb MACH_AT572D940DEB AT572D940DEB 1780
-davinci_da8xx_evm MACH_DAVINCI_DA8XX_EVM DAVINCI_DA8XX_EVM 1781
+davinci_da830_evm MACH_DAVINCI_DA830_EVM DAVINCI_DA830_EVM 1781
ep9302 MACH_EP9302 EP9302 1782
at572d940hfek MACH_AT572D940HFEB AT572D940HFEB 1783
cybook3 MACH_CYBOOK3 CYBOOK3 1784
@@ -1802,7 +1802,7 @@
rd88f5181l_ge MACH_RD88F5181L_GE RD88F5181L_GE 1812
sifmain MACH_SIFMAIN SIFMAIN 1813
sam9_l9261 MACH_SAM9_L9261 SAM9_L9261 1814
-cc9m2443js MACH_CC9M2443JS CC9M2443JS 1815
+cc9m2443 MACH_CC9M2443 CC9M2443 1815
xaria300 MACH_XARIA300 XARIA300 1816
it9200 MACH_IT9200 IT9200 1817
rd88f5181l_fxo MACH_RD88F5181L_FXO RD88F5181L_FXO 1818
@@ -1817,7 +1817,7 @@
tavorevb MACH_TAVOREVB TAVOREVB 1827
saar MACH_SAAR SAAR 1828
deister_eyecam MACH_DEISTER_EYECAM DEISTER_EYECAM 1829
-at91sam9m10ek MACH_AT91SAM9M10EK AT91SAM9M10EK 1830
+at91sam9m10g45ek MACH_AT91SAM9M10G45EK AT91SAM9M10G45EK 1830
linkstation_produo MACH_LINKSTATION_PRODUO LINKSTATION_PRODUO 1831
hit_b0 MACH_HIT_B0 HIT_B0 1832
adx_rmu MACH_ADX_RMU ADX_RMU 1833
@@ -1962,7 +1962,7 @@
arm11 MACH_ARM11 ARM11 1972
cpuat9260 MACH_CPUAT9260 CPUAT9260 1973
cpupxa255 MACH_CPUPXA255 CPUPXA255 1974
-cpuimx27 MACH_CPUIMX27 CPUIMX27 1975
+eukrea_cpuimx27 MACH_CPUIMX27 CPUIMX27 1975
cheflux MACH_CHEFLUX CHEFLUX 1976
eb_cpux9k2 MACH_EB_CPUX9K2 EB_CPUX9K2 1977
opcotec MACH_OPCOTEC OPCOTEC 1978
@@ -2124,3 +2124,336 @@
fmzwebmodul MACH_FMZWEBMODUL FMZWEBMODUL 2134
rd78x00_masa MACH_RD78X00_MASA RD78X00_MASA 2135
smallogger MACH_SMALLOGGER SMALLOGGER 2136
+ccw9p9215 MACH_CCW9P9215 CCW9P9215 2137
+dm355_leopard MACH_DM355_LEOPARD DM355_LEOPARD 2138
+ts219 MACH_TS219 TS219 2139
+tny_a9263 MACH_TNY_A9263 TNY_A9263 2140
+apollo MACH_APOLLO APOLLO 2141
+at91cap9stk MACH_AT91CAP9STK AT91CAP9STK 2142
+spc300 MACH_SPC300 SPC300 2143
+eko MACH_EKO EKO 2144
+ccw9m2443 MACH_CCW9M2443 CCW9M2443 2145
+ccw9m2443js MACH_CCW9M2443JS CCW9M2443JS 2146
+m2m_router_device MACH_M2M_ROUTER_DEVICE M2M_ROUTER_DEVICE 2147
+str9104nas MACH_STAR9104NAS STAR9104NAS 2148
+pca100 MACH_PCA100 PCA100 2149
+z3_dm365_mod_01 MACH_Z3_DM365_MOD_01 Z3_DM365_MOD_01 2150
+hipox MACH_HIPOX HIPOX 2151
+omap3_piteds MACH_OMAP3_PITEDS OMAP3_PITEDS 2152
+bm150r MACH_BM150R BM150R 2153
+tbone MACH_TBONE TBONE 2154
+merlin MACH_MERLIN MERLIN 2155
+falcon MACH_FALCON FALCON 2156
+davinci_da850_evm MACH_DAVINCI_DA850_EVM DAVINCI_DA850_EVM 2157
+s5p6440 MACH_S5P6440 S5P6440 2158
+at91sam9g10ek MACH_AT91SAM9G10EK AT91SAM9G10EK 2159
+omap_4430sdp MACH_OMAP_4430SDP OMAP_4430SDP 2160
+lpc313x MACH_LPC313X LPC313X 2161
+magx_zn5 MACH_MAGX_ZN5 MAGX_ZN5 2162
+magx_em30 MACH_MAGX_EM30 MAGX_EM30 2163
+magx_ve66 MACH_MAGX_VE66 MAGX_VE66 2164
+meesc MACH_MEESC MEESC 2165
+otc570 MACH_OTC570 OTC570 2166
+bcu2412 MACH_BCU2412 BCU2412 2167
+beacon MACH_BEACON BEACON 2168
+actia_tgw MACH_ACTIA_TGW ACTIA_TGW 2169
+e4430 MACH_E4430 E4430 2170
+ql300 MACH_QL300 QL300 2171
+btmavb101 MACH_BTMAVB101 BTMAVB101 2172
+btmawb101 MACH_BTMAWB101 BTMAWB101 2173
+sq201 MACH_SQ201 SQ201 2174
+quatro45xx MACH_QUATRO45XX QUATRO45XX 2175
+openpad MACH_OPENPAD OPENPAD 2176
+tx25 MACH_TX25 TX25 2177
+omap3_torpedo MACH_OMAP3_TORPEDO OMAP3_TORPEDO 2178
+htcraphael_k MACH_HTCRAPHAEL_K HTCRAPHAEL_K 2179
+lal43 MACH_LAL43 LAL43 2181
+htcraphael_cdma500 MACH_HTCRAPHAEL_CDMA500 HTCRAPHAEL_CDMA500 2182
+anw6410 MACH_ANW6410 ANW6410 2183
+htcprophet MACH_HTCPROPHET HTCPROPHET 2185
+cfa_10022 MACH_CFA_10022 CFA_10022 2186
+imx27_visstrim_m10 MACH_IMX27_VISSTRIM_M10 IMX27_VISSTRIM_M10 2187
+px2imx27 MACH_PX2IMX27 PX2IMX27 2188
+stm3210e_eval MACH_STM3210E_EVAL STM3210E_EVAL 2189
+dvs10 MACH_DVS10 DVS10 2190
+portuxg20 MACH_PORTUXG20 PORTUXG20 2191
+arm_spv MACH_ARM_SPV ARM_SPV 2192
+smdkc110 MACH_SMDKC110 SMDKC110 2193
+cabespresso MACH_CABESPRESSO CABESPRESSO 2194
+hmc800 MACH_HMC800 HMC800 2195
+sholes MACH_SHOLES SHOLES 2196
+btmxc31 MACH_BTMXC31 BTMXC31 2197
+dt501 MACH_DT501 DT501 2198
+ktx MACH_KTX KTX 2199
+omap3517evm MACH_OMAP3517EVM OMAP3517EVM 2200
+netspace_v2 MACH_NETSPACE_V2 NETSPACE_V2 2201
+netspace_max_v2 MACH_NETSPACE_MAX_V2 NETSPACE_MAX_V2 2202
+d2net_v2 MACH_D2NET_V2 D2NET_V2 2203
+net2big_v2 MACH_NET2BIG_V2 NET2BIG_V2 2204
+net4big_v2 MACH_NET4BIG_V2 NET4BIG_V2 2205
+net5big_v2 MACH_NET5BIG_V2 NET5BIG_V2 2206
+endb2443 MACH_ENDB2443 ENDB2443 2207
+inetspace_v2 MACH_INETSPACE_V2 INETSPACE_V2 2208
+tros MACH_TROS TROS 2209
+pelco_homer MACH_PELCO_HOMER PELCO_HOMER 2210
+ofsp8 MACH_OFSP8 OFSP8 2211
+at91sam9g45ekes MACH_AT91SAM9G45EKES AT91SAM9G45EKES 2212
+guf_cupid MACH_GUF_CUPID GUF_CUPID 2213
+eab1r MACH_EAB1R EAB1R 2214
+desirec MACH_DESIREC DESIREC 2215
+cordoba MACH_CORDOBA CORDOBA 2216
+irvine MACH_IRVINE IRVINE 2217
+sff772 MACH_SFF772 SFF772 2218
+pelco_milano MACH_PELCO_MILANO PELCO_MILANO 2219
+pc7302 MACH_PC7302 PC7302 2220
+bip6000 MACH_BIP6000 BIP6000 2221
+silvermoon MACH_SILVERMOON SILVERMOON 2222
+vc0830 MACH_VC0830 VC0830 2223
+dt430 MACH_DT430 DT430 2224
+ji42pf MACH_JI42PF JI42PF 2225
+gnet_ksm MACH_GNET_KSM GNET_KSM 2226
+gnet_sgm MACH_GNET_SGM GNET_SGM 2227
+gnet_sgr MACH_GNET_SGR GNET_SGR 2228
+omap3_icetekevm MACH_OMAP3_ICETEKEVM OMAP3_ICETEKEVM 2229
+pnp MACH_PNP PNP 2230
+ctera_2bay_k MACH_CTERA_2BAY_K CTERA_2BAY_K 2231
+ctera_2bay_u MACH_CTERA_2BAY_U CTERA_2BAY_U 2232
+sas_c MACH_SAS_C SAS_C 2233
+vma2315 MACH_VMA2315 VMA2315 2234
+vcs MACH_VCS VCS 2235
+spear600 MACH_SPEAR600 SPEAR600 2236
+spear300 MACH_SPEAR300 SPEAR300 2237
+spear1300 MACH_SPEAR1300 SPEAR1300 2238
+lilly1131 MACH_LILLY1131 LILLY1131 2239
+arvoo_ax301 MACH_ARVOO_AX301 ARVOO_AX301 2240
+mapphone MACH_MAPPHONE MAPPHONE 2241
+legend MACH_LEGEND LEGEND 2242
+salsa MACH_SALSA SALSA 2243
+lounge MACH_LOUNGE LOUNGE 2244
+vision MACH_VISION VISION 2245
+vmb20 MACH_VMB20 VMB20 2246
+hy2410 MACH_HY2410 HY2410 2247
+hy9315 MACH_HY9315 HY9315 2248
+bullwinkle MACH_BULLWINKLE BULLWINKLE 2249
+arm_ultimator2 MACH_ARM_ULTIMATOR2 ARM_ULTIMATOR2 2250
+vs_v210 MACH_VS_V210 VS_V210 2252
+vs_v212 MACH_VS_V212 VS_V212 2253
+hmt MACH_HMT HMT 2254
+suen3 MACH_SUEN3 SUEN3 2255
+vesper MACH_VESPER VESPER 2256
+str9 MACH_STR9 STR9 2257
+omap3_wl_ff MACH_OMAP3_WL_FF OMAP3_WL_FF 2258
+simcom MACH_SIMCOM SIMCOM 2259
+mcwebio MACH_MCWEBIO MCWEBIO 2260
+omap3_phrazer MACH_OMAP3_PHRAZER OMAP3_PHRAZER 2261
+darwin MACH_DARWIN DARWIN 2262
+oratiscomu MACH_ORATISCOMU ORATISCOMU 2263
+rtsbc20 MACH_RTSBC20 RTSBC20 2264
+sgh_i780 MACH_I780 I780 2265
+gemini324 MACH_GEMINI324 GEMINI324 2266
+oratislan MACH_ORATISLAN ORATISLAN 2267
+oratisalog MACH_ORATISALOG ORATISALOG 2268
+oratismadi MACH_ORATISMADI ORATISMADI 2269
+oratisot16 MACH_ORATISOT16 ORATISOT16 2270
+oratisdesk MACH_ORATISDESK ORATISDESK 2271
+v2_ca9 MACH_V2P_CA9 V2P_CA9 2272
+sintexo MACH_SINTEXO SINTEXO 2273
+cm3389 MACH_CM3389 CM3389 2274
+omap3_cio MACH_OMAP3_CIO OMAP3_CIO 2275
+sgh_i900 MACH_SGH_I900 SGH_I900 2276
+bst100 MACH_BST100 BST100 2277
+passion MACH_PASSION PASSION 2278
+indesign_at91sam MACH_INDESIGN_AT91SAM INDESIGN_AT91SAM 2279
+c4_badger MACH_C4_BADGER C4_BADGER 2280
+c4_viper MACH_C4_VIPER C4_VIPER 2281
+d2net MACH_D2NET D2NET 2282
+bigdisk MACH_BIGDISK BIGDISK 2283
+notalvision MACH_NOTALVISION NOTALVISION 2284
+omap3_kboc MACH_OMAP3_KBOC OMAP3_KBOC 2285
+cyclone MACH_CYCLONE CYCLONE 2286
+ninja MACH_NINJA NINJA 2287
+at91sam9g20ek_2mmc MACH_AT91SAM9G20EK_2MMC AT91SAM9G20EK_2MMC 2288
+bcmring MACH_BCMRING BCMRING 2289
+resol_dl2 MACH_RESOL_DL2 RESOL_DL2 2290
+ifosw MACH_IFOSW IFOSW 2291
+htcrhodium MACH_HTCRHODIUM HTCRHODIUM 2292
+htctopaz MACH_HTCTOPAZ HTCTOPAZ 2293
+matrix504 MACH_MATRIX504 MATRIX504 2294
+mrfsa MACH_MRFSA MRFSA 2295
+sc_p270 MACH_SC_P270 SC_P270 2296
+atlas5_evb MACH_ATLAS5_EVB ATLAS5_EVB 2297
+pelco_lobox MACH_PELCO_LOBOX PELCO_LOBOX 2298
+dilax_pcu200 MACH_DILAX_PCU200 DILAX_PCU200 2299
+leonardo MACH_LEONARDO LEONARDO 2300
+zoran_approach7 MACH_ZORAN_APPROACH7 ZORAN_APPROACH7 2301
+dp6xx MACH_DP6XX DP6XX 2302
+bcm2153_vesper MACH_BCM2153_VESPER BCM2153_VESPER 2303
+mahimahi MACH_MAHIMAHI MAHIMAHI 2304
+clickc MACH_CLICKC CLICKC 2305
+zb_gateway MACH_ZB_GATEWAY ZB_GATEWAY 2306
+tazcard MACH_TAZCARD TAZCARD 2307
+tazdev MACH_TAZDEV TAZDEV 2308
+annax_cb_arm MACH_ANNAX_CB_ARM ANNAX_CB_ARM 2309
+annax_dm3 MACH_ANNAX_DM3 ANNAX_DM3 2310
+cerebric MACH_CEREBRIC CEREBRIC 2311
+orca MACH_ORCA ORCA 2312
+pc9260 MACH_PC9260 PC9260 2313
+ems285a MACH_EMS285A EMS285A 2314
+gec2410 MACH_GEC2410 GEC2410 2315
+gec2440 MACH_GEC2440 GEC2440 2316
+mw903 MACH_ARCH_MW903 ARCH_MW903 2317
+mw2440 MACH_MW2440 MW2440 2318
+ecac2378 MACH_ECAC2378 ECAC2378 2319
+tazkiosk MACH_TAZKIOSK TAZKIOSK 2320
+whiterabbit_mch MACH_WHITERABBIT_MCH WHITERABBIT_MCH 2321
+sbox9263 MACH_SBOX9263 SBOX9263 2322
+oreo MACH_OREO OREO 2323
+smdk6442 MACH_SMDK6442 SMDK6442 2324
+openrd_base MACH_OPENRD_BASE OPENRD_BASE 2325
+incredible MACH_INCREDIBLE INCREDIBLE 2326
+incrediblec MACH_INCREDIBLEC INCREDIBLEC 2327
+heroct MACH_HEROCT HEROCT 2328
+mmnet1000 MACH_MMNET1000 MMNET1000 2329
+devkit8000 MACH_DEVKIT8000 DEVKIT8000 2330
+devkit9000 MACH_DEVKIT9000 DEVKIT9000 2331
+mx31txtr MACH_MX31TXTR MX31TXTR 2332
+u380 MACH_U380 U380 2333
+oamp3_hualu MACH_HUALU_BOARD HUALU_BOARD 2334
+npcmx50 MACH_NPCMX50 NPCMX50 2335
+mx51_lange51 MACH_MX51_LANGE51 MX51_LANGE51 2336
+mx51_lange52 MACH_MX51_LANGE52 MX51_LANGE52 2337
+riom MACH_RIOM RIOM 2338
+comcas MACH_COMCAS COMCAS 2339
+wsi_mx27 MACH_WSI_MX27 WSI_MX27 2340
+cm_t35 MACH_CM_T35 CM_T35 2341
+net2big MACH_NET2BIG NET2BIG 2342
+motorola_a1600 MACH_MOTOROLA_A1600 MOTOROLA_A1600 2343
+igep0020 MACH_IGEP0020 IGEP0020 2344
+igep0010 MACH_IGEP0010 IGEP0010 2345
+mv6281gtwge2 MACH_MV6281GTWGE2 MV6281GTWGE2 2346
+scat100 MACH_SCAT100 SCAT100 2347
+sanmina MACH_SANMINA SANMINA 2348
+momento MACH_MOMENTO MOMENTO 2349
+nuc9xx MACH_NUC9XX NUC9XX 2350
+nuc910evb MACH_NUC910EVB NUC910EVB 2351
+nuc920evb MACH_NUC920EVB NUC920EVB 2352
+nuc950evb MACH_NUC950EVB NUC950EVB 2353
+nuc945evb MACH_NUC945EVB NUC945EVB 2354
+nuc960evb MACH_NUC960EVB NUC960EVB 2355
+nuc932evb MACH_NUC932EVB NUC932EVB 2356
+nuc900 MACH_NUC900 NUC900 2357
+sd1soc MACH_SD1SOC SD1SOC 2358
+ln2440bc MACH_LN2440BC LN2440BC 2359
+rsbc MACH_RSBC RSBC 2360
+openrd_client MACH_OPENRD_CLIENT OPENRD_CLIENT 2361
+hpipaq11x MACH_HPIPAQ11X HPIPAQ11X 2362
+wayland MACH_WAYLAND WAYLAND 2363
+acnbsx102 MACH_ACNBSX102 ACNBSX102 2364
+hwat91 MACH_HWAT91 HWAT91 2365
+at91sam9263cs MACH_AT91SAM9263CS AT91SAM9263CS 2366
+csb732 MACH_CSB732 CSB732 2367
+u8500 MACH_U8500 U8500 2368
+huqiu MACH_HUQIU HUQIU 2369
+mx51_kunlun MACH_MX51_KUNLUN MX51_KUNLUN 2370
+pmt1g MACH_PMT1G PMT1G 2371
+htcelf MACH_HTCELF HTCELF 2372
+armadillo420 MACH_ARMADILLO420 ARMADILLO420 2373
+armadillo440 MACH_ARMADILLO440 ARMADILLO440 2374
+u_chip_dual_arm MACH_U_CHIP_DUAL_ARM U_CHIP_DUAL_ARM 2375
+csr_bdb3 MACH_CSR_BDB3 CSR_BDB3 2376
+dolby_cat1018 MACH_DOLBY_CAT1018 DOLBY_CAT1018 2377
+hy9307 MACH_HY9307 HY9307 2378
+aspire_easystore MACH_A_ES A_ES 2379
+davinci_irif MACH_DAVINCI_IRIF DAVINCI_IRIF 2380
+agama9263 MACH_AGAMA9263 AGAMA9263 2381
+marvell_jasper MACH_MARVELL_JASPER MARVELL_JASPER 2382
+flint MACH_FLINT FLINT 2383
+tavorevb3 MACH_TAVOREVB3 TAVOREVB3 2384
+sch_m490 MACH_SCH_M490 SCH_M490 2386
+rbl01 MACH_RBL01 RBL01 2387
+omnifi MACH_OMNIFI OMNIFI 2388
+otavalo MACH_OTAVALO OTAVALO 2389
+sienna MACH_SIENNA SIENNA 2390
+htc_excalibur_s620 MACH_HTC_EXCALIBUR_S620 HTC_EXCALIBUR_S620 2391
+htc_opal MACH_HTC_OPAL HTC_OPAL 2392
+touchbook MACH_TOUCHBOOK TOUCHBOOK 2393
+latte MACH_LATTE LATTE 2394
+xa200 MACH_XA200 XA200 2395
+nimrod MACH_NIMROD NIMROD 2396
+cc9p9215_3g MACH_CC9P9215_3G CC9P9215_3G 2397
+cc9p9215_3gjs MACH_CC9P9215_3GJS CC9P9215_3GJS 2398
+tk71 MACH_TK71 TK71 2399
+comham3525 MACH_COMHAM3525 COMHAM3525 2400
+mx31erebus MACH_MX31EREBUS MX31EREBUS 2401
+mcardmx27 MACH_MCARDMX27 MCARDMX27 2402
+paradise MACH_PARADISE PARADISE 2403
+tide MACH_TIDE TIDE 2404
+wzl2440 MACH_WZL2440 WZL2440 2405
+sdrdemo MACH_SDRDEMO SDRDEMO 2406
+ethercan2 MACH_ETHERCAN2 ETHERCAN2 2407
+ecmimg20 MACH_ECMIMG20 ECMIMG20 2408
+omap_dragon MACH_OMAP_DRAGON OMAP_DRAGON 2409
+halo MACH_HALO HALO 2410
+huangshan MACH_HUANGSHAN HUANGSHAN 2411
+vl_ma2sc MACH_VL_MA2SC VL_MA2SC 2412
+raumfeld_rc MACH_RAUMFELD_RC RAUMFELD_RC 2413
+raumfeld_connector MACH_RAUMFELD_CONNECTOR RAUMFELD_CONNECTOR 2414
+raumfeld_speaker MACH_RAUMFELD_SPEAKER RAUMFELD_SPEAKER 2415
+multibus_master MACH_MULTIBUS_MASTER MULTIBUS_MASTER 2416
+multibus_pbk MACH_MULTIBUS_PBK MULTIBUS_PBK 2417
+tnetv107x MACH_TNETV107X TNETV107X 2418
+snake MACH_SNAKE SNAKE 2419
+cwmx27 MACH_CWMX27 CWMX27 2420
+sch_m480 MACH_SCH_M480 SCH_M480 2421
+platypus MACH_PLATYPUS PLATYPUS 2422
+pss2 MACH_PSS2 PSS2 2423
+davinci_apm150 MACH_DAVINCI_APM150 DAVINCI_APM150 2424
+str9100 MACH_STR9100 STR9100 2425
+net5big MACH_NET5BIG NET5BIG 2426
+seabed9263 MACH_SEABED9263 SEABED9263 2427
+mx51_m2id MACH_MX51_M2ID MX51_M2ID 2428
+octvocplus_eb MACH_OCTVOCPLUS_EB OCTVOCPLUS_EB 2429
+klk_firefox MACH_KLK_FIREFOX KLK_FIREFOX 2430
+klk_wirma_module MACH_KLK_WIRMA_MODULE KLK_WIRMA_MODULE 2431
+klk_wirma_mmi MACH_KLK_WIRMA_MMI KLK_WIRMA_MMI 2432
+supersonic MACH_SUPERSONIC SUPERSONIC 2433
+liberty MACH_LIBERTY LIBERTY 2434
+mh355 MACH_MH355 MH355 2435
+pc7802 MACH_PC7802 PC7802 2436
+gnet_sgc MACH_GNET_SGC GNET_SGC 2437
+einstein15 MACH_EINSTEIN15 EINSTEIN15 2438
+cmpd MACH_CMPD CMPD 2439
+davinci_hase1 MACH_DAVINCI_HASE1 DAVINCI_HASE1 2440
+lgeincitephone MACH_LGEINCITEPHONE LGEINCITEPHONE 2441
+ea313x MACH_EA313X EA313X 2442
+fwbd_39064 MACH_FWBD_39064 FWBD_39064 2443
+fwbd_390128 MACH_FWBD_390128 FWBD_390128 2444
+pelco_moe MACH_PELCO_MOE PELCO_MOE 2445
+minimix27 MACH_MINIMIX27 MINIMIX27 2446
+omap3_thunder MACH_OMAP3_THUNDER OMAP3_THUNDER 2447
+passionc MACH_PASSIONC PASSIONC 2448
+mx27amata MACH_MX27AMATA MX27AMATA 2449
+bgat1 MACH_BGAT1 BGAT1 2450
+buzz MACH_BUZZ BUZZ 2451
+mb9g20 MACH_MB9G20 MB9G20 2452
+yushan MACH_YUSHAN YUSHAN 2453
+lizard MACH_LIZARD LIZARD 2454
+omap3polycom MACH_OMAP3POLYCOM OMAP3POLYCOM 2455
+smdkv210 MACH_SMDKV210 SMDKV210 2456
+bravo MACH_BRAVO BRAVO 2457
+siogentoo1 MACH_SIOGENTOO1 SIOGENTOO1 2458
+siogentoo2 MACH_SIOGENTOO2 SIOGENTOO2 2459
+sm3k MACH_SM3K SM3K 2460
+acer_tempo_f900 MACH_ACER_TEMPO_F900 ACER_TEMPO_F900 2461
+sst61vc010_dev MACH_SST61VC010_DEV SST61VC010_DEV 2462
+glittertind MACH_GLITTERTIND GLITTERTIND 2463
+omap_zoom3 MACH_OMAP_ZOOM3 OMAP_ZOOM3 2464
+omap_3630sdp MACH_OMAP_3630SDP OMAP_3630SDP 2465
+cybook2440 MACH_CYBOOK2440 CYBOOK2440 2466
+torino_s MACH_TORINO_S TORINO_S 2467
+havana MACH_HAVANA HAVANA 2468
+beaumont_11 MACH_BEAUMONT_11 BEAUMONT_11 2469
+vanguard MACH_VANGUARD VANGUARD 2470
+s5pc110_draco MACH_S5PC110_DRACO S5PC110_DRACO 2471
+cartesio_two MACH_CARTESIO_TWO CARTESIO_TWO 2472
+aster MACH_ASTER ASTER 2473
diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
index ba592a9..a2bed62 100644
--- a/arch/arm/vfp/entry.S
+++ b/arch/arm/vfp/entry.S
@@ -15,13 +15,16 @@
* r10 = thread_info structure
* lr = failure return
*/
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/asm-offsets.h>
-#include <asm/assembler.h>
+#include <asm/thread_info.h>
#include <asm/vfpmacros.h>
+#include "../kernel/entry-header.S"
ENTRY(do_vfp)
+#ifdef CONFIG_PREEMPT
+ ldr r4, [r10, #TI_PREEMPT] @ get preempt count
+ add r11, r4, #1 @ increment it
+ str r11, [r10, #TI_PREEMPT]
+#endif
enable_irq
ldr r4, .LCvfp
ldr r11, [r10, #TI_CPU] @ CPU number
@@ -30,6 +33,12 @@
ENDPROC(do_vfp)
ENTRY(vfp_null_entry)
+#ifdef CONFIG_PREEMPT
+ get_thread_info r10
+ ldr r4, [r10, #TI_PREEMPT] @ get preempt count
+ sub r11, r4, #1 @ decrement it
+ str r11, [r10, #TI_PREEMPT]
+#endif
mov pc, lr
ENDPROC(vfp_null_entry)
@@ -41,6 +50,12 @@
__INIT
ENTRY(vfp_testing_entry)
+#ifdef CONFIG_PREEMPT
+ get_thread_info r10
+ ldr r4, [r10, #TI_PREEMPT] @ get preempt count
+ sub r11, r4, #1 @ decrement it
+ str r11, [r10, #TI_PREEMPT]
+#endif
ldr r0, VFP_arch_address
str r5, [r0] @ known non-zero value
mov pc, r9 @ we have handled the fault
diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
index 8de86e4..3394d42 100644
--- a/arch/arm/vfp/vfp.h
+++ b/arch/arm/vfp/vfp.h
@@ -377,6 +377,5 @@
u32 flags;
};
-#if defined(CONFIG_SMP) || defined(CONFIG_PM)
extern void vfp_save_state(void *location, u32 fpexc);
-#endif
+extern void vfp_pm_save_context(void);
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index c92a08b..83c4e38 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -137,6 +137,12 @@
VFPFMXR FPEXC, r1 @ restore FPEXC last
sub r2, r2, #4
str r2, [sp, #S_PC] @ retry the instruction
+#ifdef CONFIG_PREEMPT
+ get_thread_info r10
+ ldr r4, [r10, #TI_PREEMPT] @ get preempt count
+ sub r11, r4, #1 @ decrement it
+ str r11, [r10, #TI_PREEMPT]
+#endif
mov pc, r9 @ we think we have handled things
@@ -155,6 +161,12 @@
@ not recognised by VFP
DBGSTR "not VFP"
+#ifdef CONFIG_PREEMPT
+ get_thread_info r10
+ ldr r4, [r10, #TI_PREEMPT] @ get preempt count
+ sub r11, r4, #1 @ decrement it
+ str r11, [r10, #TI_PREEMPT]
+#endif
mov pc, lr
process_exception:
@@ -172,7 +184,6 @@
@ retry the faulted instruction
ENDPROC(vfp_support_entry)
-#if defined(CONFIG_SMP) || defined(CONFIG_PM)
ENTRY(vfp_save_state)
@ Save the current VFP state
@ r0 - save location
@@ -190,7 +201,6 @@
stmia r0, {r1, r2, r3, r12} @ save FPEXC, FPSCR, FPINST, FPINST2
mov pc, lr
ENDPROC(vfp_save_state)
-#endif
last_VFP_context_address:
.word last_VFP_context
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 9f476a1..93da971 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -266,7 +266,7 @@
* on VFP subarch 1.
*/
vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs);
- return;
+ goto exit;
}
/*
@@ -297,7 +297,7 @@
* the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.
*/
if (fpexc ^ (FPEXC_EX | FPEXC_FP2V))
- return;
+ goto exit;
/*
* The barrier() here prevents fpinst2 being read
@@ -310,6 +310,8 @@
exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs);
if (exceptions)
vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
+ exit:
+ preempt_enable();
}
static void vfp_enable(void *unused)
@@ -325,34 +327,41 @@
#ifdef CONFIG_PM
#include <linux/sysdev.h>
+ void vfp_pm_save_context(void)
+ {
+ struct thread_info *thread = current_thread_info();
+ u32 fpexc = fmrx(FPEXC);
+ __u32 cpu = thread->cpu;
+ int vfp_enabled;
+
+ vfp_enabled = fpexc & FPEXC_EN;
+
+ if (last_VFP_context[cpu]) {
+ if (!vfp_enabled) {
+ /* enable vfp now to save context */
+ vfp_enable(NULL);
+ fmxr(FPEXC, fmrx(FPEXC) | FPEXC_EN);
+ }
+ vfp_save_state(last_VFP_context[cpu], fpexc);
+
+ /* Disable vfp. The next inst traps an exception and restores*/
+ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
+
+ /*
+ * This is needed else the restore might fail if it sees
+ * last_VFP_context if same as the current threads vfp_state.
+ */
+ last_VFP_context[cpu] = NULL;
+ }
+ }
+
static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state)
{
- struct thread_info *ti = current_thread_info();
- u32 fpexc = fmrx(FPEXC);
-
- /* if vfp is on, then save state for resumption */
- if (fpexc & FPEXC_EN) {
- printk(KERN_DEBUG "%s: saving vfp state\n", __func__);
- vfp_save_state(&ti->vfpstate, fpexc);
-
- /* disable, just in case */
- fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
- }
-
- /* clear any information we had about last context state */
- memset(last_VFP_context, 0, sizeof(last_VFP_context));
-
return 0;
}
static int vfp_pm_resume(struct sys_device *dev)
{
- /* ensure we have access to the vfp */
- vfp_enable(NULL);
-
- /* and disable it to ensure the next usage restores the state */
- fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
-
return 0;
}
@@ -377,6 +386,55 @@
static inline void vfp_pm_init(void) { }
#endif /* CONFIG_PM */
+/*
+ * Synchronise the hardware VFP state of a thread other than current with the
+ * saved one. This function is used by the ptrace mechanism.
+ */
+#ifdef CONFIG_SMP
+void vfp_sync_state(struct thread_info *thread)
+{
+ /*
+ * On SMP systems, the VFP state is automatically saved at every
+ * context switch. We mark the thread VFP state as belonging to a
+ * non-existent CPU so that the saved one will be reloaded when
+ * needed.
+ */
+ thread->vfpstate.hard.cpu = NR_CPUS;
+}
+#else
+void vfp_sync_state(struct thread_info *thread)
+{
+ unsigned int cpu = get_cpu();
+ u32 fpexc = fmrx(FPEXC);
+
+ /*
+ * If VFP is enabled, the previous state was already saved and
+ * last_VFP_context updated.
+ */
+ if (fpexc & FPEXC_EN)
+ goto out;
+
+ if (!last_VFP_context[cpu])
+ goto out;
+
+ /*
+ * Save the last VFP state on this CPU.
+ */
+ fmxr(FPEXC, fpexc | FPEXC_EN);
+ vfp_save_state(last_VFP_context[cpu], fpexc);
+ fmxr(FPEXC, fpexc);
+
+ /*
+ * Set the context to NULL to force a reload the next time the thread
+ * uses the VFP.
+ */
+ last_VFP_context[cpu] = NULL;
+
+out:
+ put_cpu();
+}
+#endif
+
#include <linux/smp.h>
/*
@@ -427,6 +485,18 @@
* in place; report VFP support to userspace.
*/
elf_hwcap |= HWCAP_VFP;
+#ifdef CONFIG_VFPv3
+ if (VFP_arch >= 3) {
+ elf_hwcap |= HWCAP_VFPv3;
+
+ /*
+ * Check for VFPv3 D16. CPUs in this configuration
+ * only have 16 x 64bit registers.
+ */
+ if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1)
+ elf_hwcap |= HWCAP_VFPv3D16;
+ }
+#endif
#ifdef CONFIG_NEON
/*
* Check for the presence of the Advanced SIMD
diff --git a/block/genhd.c b/block/genhd.c
index a9ec910..21f8b4e 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -977,6 +977,22 @@
free_part_stats(&disk->part0);
kfree(disk);
}
+
+static int disk_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct gendisk *disk = dev_to_disk(dev);
+ struct disk_part_iter piter;
+ struct hd_struct *part;
+ int cnt = 0;
+
+ disk_part_iter_init(&piter, disk, 0);
+ while((part = disk_part_iter_next(&piter)))
+ cnt++;
+ disk_part_iter_exit(&piter);
+ add_uevent_var(env, "NPARTS=%u", cnt);
+ return 0;
+}
+
struct class block_class = {
.name = "block",
};
@@ -985,6 +1001,7 @@
.name = "disk",
.groups = disk_attr_groups,
.release = disk_release,
+ .uevent = disk_uevent,
};
#ifdef CONFIG_PROC_FS
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index a942bf1..a73ff9e 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -32,7 +32,6 @@
#include <linux/init.h>
#include <linux/sched.h>
-#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
@@ -49,9 +48,10 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
-#ifdef CONFIG_SERIAL_OMAP
-#include <mach/omap-serial.h>
-#endif
+#include <linux/stddef.h>
+#include <linux/spinlock.h>
+#include <linux/gfp.h>
+#include <net/bluetooth/hci.h>
#include "hci_uart.h"
@@ -69,12 +69,10 @@
#define HCILL_W4_DATA 4
/* HCILL states */
-enum hcill_states_e {
- HCILL_ASLEEP,
- HCILL_ASLEEP_TO_AWAKE,
- HCILL_AWAKE,
- HCILL_AWAKE_TO_ASLEEP
-};
+#define HCILL_ASLEEP 0
+#define HCILL_ASLEEP_TO_AWAKE 1
+#define HCILL_AWAKE 2
+#define HCILL_AWAKE_TO_ASLEEP 3
struct hcill_cmd {
u8 cmd;
@@ -90,6 +88,7 @@
struct sk_buff_head tx_wait_q; /* HCILL wait queue */
};
+static inline int ll_check_data_len(struct ll_struct *ll, int len);
/*
* Builds and sends an HCILL command packet.
* These are very simple packets with only 1 cmd byte
@@ -198,7 +197,7 @@
*/
static void ll_device_want_to_wakeup(struct hci_uart *hu)
{
- unsigned long flags;
+ unsigned long flags = 0;
struct ll_struct *ll = hu->priv;
BT_DBG("hu %p", hu);
@@ -248,7 +247,7 @@
*/
static void ll_device_want_to_sleep(struct hci_uart *hu)
{
- unsigned long flags;
+ unsigned long flags = 0;
struct ll_struct *ll = hu->priv;
BT_DBG("hu %p", hu);
@@ -281,7 +280,7 @@
*/
static void ll_device_woke_up(struct hci_uart *hu)
{
- unsigned long flags;
+ unsigned long flags = 0;
struct ll_struct *ll = hu->priv;
BT_DBG("hu %p", hu);
@@ -530,16 +529,10 @@
else
BT_ERR("HCILL protocol registration failed");
-#ifdef CONFIG_SERIAL_OMAP
- omap24xx_uart_cts_wakeup(1, 1);
-#endif
return err;
}
int ll_deinit(void)
{
-#ifdef CONFIG_SERIAL_OMAP
- omap24xx_uart_cts_wakeup(1, 0);
-#endif
return hci_uart_unregister_proto(&llp);
}
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index cbfc99d..2ca76ef 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -522,7 +522,7 @@
if (latency == 0)
latency = 1;
- def_sampling_rate = 10 * latency *
+ def_sampling_rate = latency *
CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER;
if (def_sampling_rate < MIN_STAT_SAMPLING_RATE)
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 6c80533..2999fa7 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -489,7 +489,8 @@
/* We want all CPUs to do sampling nearly on same jiffy */
int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
- delay -= jiffies % delay;
+ if (num_online_cpus() > 1)
+ delay -= jiffies % delay;
if (lock_policy_rwsem_write(cpu) < 0)
return;
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index c0ff97d..ee53ccb 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -23,10 +23,11 @@
static spinlock_t cpufreq_stats_lock;
-#define CPUFREQ_STATDEVICE_ATTR(_name,_mode,_show) \
+#define CPUFREQ_STATDEVICE_ATTR(_name,_mode,_show, _store) \
static struct freq_attr _attr_##_name = {\
.attr = {.name = __stringify(_name), .mode = _mode, }, \
.show = _show,\
+ .store = _store,\
};
struct cpufreq_stats {
@@ -43,6 +44,8 @@
#endif
};
+static int ignore_idle;
+
static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table);
struct cpufreq_stats_attribute {
@@ -139,15 +142,33 @@
return PAGE_SIZE;
return len;
}
-CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table);
+CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table, NULL);
#endif
-CPUFREQ_STATDEVICE_ATTR(total_trans,0444,show_total_trans);
-CPUFREQ_STATDEVICE_ATTR(time_in_state,0444,show_time_in_state);
+static ssize_t store_ignore_idle(struct cpufreq_policy *policy, char *buf)
+{
+ int input;
+ if (sscanf(buf, "%d", &input) != 1)
+ return -EINVAL;
+
+ ignore_idle = input;
+ return 1;
+}
+
+static ssize_t show_ignore_idle(struct cpufreq_policy *policy, char *buf)
+{
+ return sprintf(buf, "%d\n", ignore_idle);
+}
+
+CPUFREQ_STATDEVICE_ATTR(total_trans,0444,show_total_trans, NULL);
+CPUFREQ_STATDEVICE_ATTR(time_in_state,0444,show_time_in_state, NULL);
+CPUFREQ_STATDEVICE_ATTR(ignore_idle, 0664, show_ignore_idle, store_ignore_idle);
+
static struct attribute *default_attrs[] = {
&_attr_total_trans.attr,
&_attr_time_in_state.attr,
+ &_attr_ignore_idle.attr,
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
&_attr_trans_table.attr,
#endif
@@ -308,6 +329,21 @@
return 0;
}
+void cpufreq_exit_idle(int cpu, unsigned long ticks)
+{
+ struct cpufreq_stats *stat;
+ stat = per_cpu(cpufreq_stats_table, cpu);
+
+ /* Wait until cpu stats is initalized */
+ if (!ignore_idle || !stat || !stat->time_in_state)
+ return;
+
+ spin_lock(&cpufreq_stats_lock);
+ stat->time_in_state[stat->last_index] =
+ cputime_sub(stat->time_in_state[stat->last_index], ticks);
+ spin_unlock(&cpufreq_stats_lock);
+}
+
static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 8504a21..03e78c6 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -75,8 +75,10 @@
#endif
/* ask the governor for the next state */
next_state = cpuidle_curr_governor->select(dev);
- if (need_resched())
+ if (need_resched()) {
+ local_irq_enable();
return;
+ }
target_state = &dev->states[next_state];
/* enter the state and update stats */
@@ -175,6 +177,7 @@
}
dev->last_residency = 0;
dev->last_state = NULL;
+ dev->max_state = dev->state_count;
smp_wmb();
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index f1df59f..5f4a26d 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -56,7 +56,7 @@
data->predicted_us /= 100;
/* find the deepest idle state that satisfies our constraints */
- for (i = CPUIDLE_DRIVER_STATE_START + 1; i < dev->state_count; i++) {
+ for (i = CPUIDLE_DRIVER_STATE_START + 1; i < dev->max_state; i++) {
struct cpuidle_state *s = &dev->states[i];
if (s->target_residency > data->expected_us)
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 97b0038..2d70050 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -162,12 +162,36 @@
#define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj)
#define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr)
+
+static ssize_t show_cpuidle_maxstate(struct cpuidle_device *dev, char *buf)
+{
+ return sprintf(buf, "%x\n", (dev->max_state - 1));
+}
+
+static size_t store_cpuidle_maxstate(struct cpuidle_device *dev, char *buf,
+ size_t count)
+{
+ int value;
+
+ if (sscanf(buf, "%x", &value) != 1) {
+ printk(KERN_ERR "store_cpuidle_maxstate: Invalid value\n");
+ return -EINVAL;
+ }
+ dev->max_state = value + 1;
+ return count;
+}
+
+define_one_rw(max_state, show_cpuidle_maxstate, store_cpuidle_maxstate);
+static struct attribute *cpuidle_default_attr[] = {
+ &attr_max_state.attr,
+ NULL
+};
+
static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf)
{
int ret = -EIO;
struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
-
if (cattr->show) {
mutex_lock(&cpuidle_lock);
ret = cattr->show(dev, buf);
@@ -205,6 +229,7 @@
static struct kobj_type ktype_cpuidle = {
.sysfs_ops = &cpuidle_sysfs_ops,
+ .default_attrs = cpuidle_default_attr,
.release = cpuidle_sysfs_release,
};
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 42fb2fd..501fb64 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -140,7 +140,7 @@
int __init gpiochip_reserve(int start, int ngpio)
{
int ret = 0;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
int i;
if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1))
@@ -435,7 +435,7 @@
*/
int gpio_export(unsigned gpio, bool direction_may_change)
{
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
struct gpio_desc *desc;
int status = -EINVAL;
@@ -559,7 +559,7 @@
mutex_unlock(&sysfs_lock);
if (status) {
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
unsigned gpio;
spin_lock_irqsave(&gpio_lock, flags);
@@ -599,7 +599,7 @@
static int __init gpiolib_sysfs_init(void)
{
int status;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
unsigned gpio;
status = class_register(&gpio_class);
@@ -662,7 +662,7 @@
*/
int gpiochip_add(struct gpio_chip *chip)
{
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
int status = 0;
unsigned id;
int base = chip->base;
@@ -729,7 +729,7 @@
*/
int gpiochip_remove(struct gpio_chip *chip)
{
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
int status = 0;
unsigned id;
@@ -765,7 +765,7 @@
struct gpio_desc *desc;
struct gpio_chip *chip;
int status = -EINVAL;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
spin_lock_irqsave(&gpio_lock, flags);
@@ -816,7 +816,7 @@
void gpio_free(unsigned gpio)
{
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
struct gpio_desc *desc;
struct gpio_chip *chip;
@@ -892,7 +892,7 @@
int gpio_direction_input(unsigned gpio)
{
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL;
@@ -945,7 +945,7 @@
int gpio_direction_output(unsigned gpio, int value)
{
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL;
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index c35ada8..1ee0bfd 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -37,6 +37,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <mach/omap-pm.h>
/* I2C controller revisions */
#define OMAP_I2C_REV_2 0x20
@@ -156,6 +157,9 @@
#define SYSC_IDLEMODE_SMART 0x2
#define SYSC_CLOCKACTIVITY_FCLK 0x2
+/* MPU wake-up latency Constraint in usec */
+#define OMAP_MPU_WAKEUP_LAT 400
+
struct omap_i2c_dev {
struct device *dev;
@@ -238,12 +242,14 @@
clk_enable(dev->iclk);
clk_enable(dev->fclk);
if (cpu_is_omap34xx()) {
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate);
omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate);
omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate);
omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
}
dev->idle = 0;
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
@@ -280,6 +286,21 @@
unsigned long internal_clk = 0;
if (dev->rev >= OMAP_I2C_REV_2) {
+ /* Disable I2C controller before soft reset */
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+ omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
+ ~(OMAP_I2C_CON_EN));
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ while ((omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
+ OMAP_I2C_CON_EN)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting "
+ "for controller reset\n");
+ return -ETIMEDOUT;
+ }
+ schedule();
+ }
+
omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK);
/* For some reason we need to set the EN bit before the
* reset done bit gets set. */
@@ -292,7 +313,7 @@
"for controller reset\n");
return -ETIMEDOUT;
}
- msleep(1);
+ schedule();
}
/* SYSC register is cleared by the reset; rewrite it */
@@ -530,8 +551,16 @@
* REVISIT: We should abort the transfer on signals, but the bus goes
* into arbitration and we're currently unable to recover from it.
*/
+
+ /*
+ * REVISIT: Add a mpu wake-up latency constraint to let us wake
+ * quickly enough for i2c transfers to work properly. Should change
+ * the code to use a latency constraint function passed from pdata.
+ */
+ omap_pm_set_max_mpu_wakeup_lat(dev->dev, OMAP_MPU_WAKEUP_LAT);
r = wait_for_completion_timeout(&dev->cmd_complete,
OMAP_I2C_TIMEOUT);
+ omap_pm_set_max_mpu_wakeup_lat(dev->dev, -1);
dev->buf_len = 0;
if (r < 0)
return r;
@@ -675,37 +704,6 @@
#define omap_i2c_rev1_isr NULL
#endif
-/* I2C Errata 1.153:
- * When an XRDY/XDR is hit, wait for XUDF before writing data to DATA_REG.
- * Otherwise some data bytes can be lost while transferring them from the
- * memory to the I2C interface.
- */
-
-static int omap_i2c_wait_for_xudf(struct omap_i2c_dev *dev)
-{
- u16 xudf;
- int counter = 500;
-
- /* We are in interrupt context. Wait for XUDF for max 7 msec */
- xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
- while (!(xudf & OMAP_I2C_STAT_XUDF) && counter--) {
- if (xudf & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_NACK |
- OMAP_I2C_STAT_AL))
- return -EINVAL;
- udelay(10);
- xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
- }
-
- if (!counter) {
- /* Clear Tx FIFO */
- omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
- OMAP_I2C_BUF_TXFIF_CLR);
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
static irqreturn_t
omap_i2c_isr(int this_irq, void *dev_id)
{
@@ -713,7 +711,6 @@
u16 bits;
u16 stat, w;
int err, count = 0;
- int error;
if (dev->idle)
return IRQ_NONE;
@@ -726,9 +723,18 @@
break;
}
- omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
-
err = 0;
+
+complete:
+ /*
+ * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be
+ * acked after the data operation is complete.
+ * Ref: TRM SWPU114Q Figure 18-31
+ */
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
+ ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
+ OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+
if (stat & OMAP_I2C_STAT_NACK) {
err |= OMAP_I2C_STAT_NACK;
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
@@ -739,8 +745,13 @@
err |= OMAP_I2C_STAT_AL;
}
if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
- OMAP_I2C_STAT_AL))
+ OMAP_I2C_STAT_AL)) {
+ omap_i2c_ack_stat(dev, stat &
+ (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
+ OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
omap_i2c_complete_cmd(dev, err);
+ return IRQ_HANDLED;
+ }
if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
u8 num_bytes = 1;
/* 3430 I2C Errata 1.15
@@ -801,23 +812,11 @@
& 0x3F;
}
while (num_bytes) {
+ num_bytes--;
w = 0;
if (dev->buf_len) {
- if (cpu_is_omap34xx()) {
- /* OMAP3430 Errata 1.153 */
- error = omap_i2c_wait_for_xudf(dev);
- if (error) {
- omap_i2c_ack_stat(dev, stat &
- (OMAP_I2C_STAT_XRDY |
- OMAP_I2C_STAT_XDR));
- dev_err(dev->dev, "Transmit error\n");
- omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_XUDF);
-
- return IRQ_HANDLED;
- }
- }
-
w = *dev->buf++;
+ dev->buf_len--;
/* Data reg from 2430 is 8 bit wide */
if (!cpu_is_omap2430() &&
!cpu_is_omap34xx()) {
@@ -826,10 +825,6 @@
dev->buf_len--;
}
}
- omap_i2c_write_reg(dev,
- OMAP_I2C_DATA_REG, w);
- num_bytes--;
- dev->buf_len--;
} else {
if (stat & OMAP_I2C_STAT_XRDY)
dev_err(dev->dev,
@@ -841,6 +836,28 @@
"data to send\n");
break;
}
+
+ /*
+ * OMAP3430 Errata 1.153: When an XRDY/XDR
+ * is hit, wait for XUDF before writing data
+ * to DATA_REG. Otherwise some data bytes can
+ * be lost while transferring them from the
+ * memory to the I2C interface.
+ */
+
+ if (dev->rev <= OMAP_I2C_REV_ON_3430) {
+ while (!(stat & OMAP_I2C_STAT_XUDF)) {
+ if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
+ omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+ err |= OMAP_I2C_STAT_XUDF;
+ goto complete;
+ }
+ cpu_relax();
+ stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+ }
+ }
+
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
}
omap_i2c_ack_stat(dev,
stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
diff --git a/drivers/i2c/chips/twl4030-poweroff.c b/drivers/i2c/chips/twl4030-poweroff.c
index 0ebab0b..89761fe 100644
--- a/drivers/i2c/chips/twl4030-poweroff.c
+++ b/drivers/i2c/chips/twl4030-poweroff.c
@@ -27,29 +27,47 @@
#define PWR_P1_SW_EVENTS 0x10
#define PWR_DEVOFF (1<<0)
+#define PWR_STOPON_POWERON (1<<6)
+
+#define CFG_P123_TRANSITION 0x03
+#define SEQ_OFFSYNC (1<<0)
static void twl4030_poweroff(void)
{
- u8 val;
+ u8 uninitialized_var(val);
int err;
+ /* Make sure SEQ_OFFSYNC is set so that all the res goes to wait-on */
+ err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
+ CFG_P123_TRANSITION);
+ if (err) {
+ pr_warning("I2C error %d while reading TWL4030 PM_MASTER CFG_P123_TRANSITION\n", err);
+ return;
+ }
+
+ val |= SEQ_OFFSYNC;
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
+ CFG_P123_TRANSITION);
+ if (err) {
+ pr_warning("I2C error %d while writing TWL4030 PM_MASTER CFG_P123_TRANSITION\n", err);
+ return;
+ }
+
err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
PWR_P1_SW_EVENTS);
if (err) {
- printk(KERN_WARNING "I2C error %d while reading TWL4030"
- "PM_MASTER P1_SW_EVENTS\n", err);
- return ;
+ pr_warning("I2C error %d while reading TWL4030 PM_MASTER P1_SW_EVENTS\n", err);
+ return;
}
- val |= PWR_DEVOFF;
+ val |= PWR_STOPON_POWERON | PWR_DEVOFF;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
PWR_P1_SW_EVENTS);
if (err) {
- printk(KERN_WARNING "I2C error %d while writing TWL4030"
- "PM_MASTER P1_SW_EVENTS\n", err);
- return ;
+ pr_warning("I2C error %d while writing TWL4030 PM_MASTER P1_SW_EVENTS\n", err);
+ return;
}
return;
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index af87135..88f3259 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -45,6 +45,7 @@
struct evdev *evdev;
struct list_head node;
struct wake_lock wake_lock;
+ char name[28];
};
static struct evdev *evdev_table[EVDEV_MINORS];
@@ -279,7 +280,9 @@
}
spin_lock_init(&client->buffer_lock);
- wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, "evdev");
+ snprintf(client->name, sizeof(client->name), "%s-%d", evdev->name,
+ task_tgid_vnr(current));
+ wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name);
client->evdev = evdev;
evdev_attach_client(evdev, client);
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index 8bfd650..bb8976e 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -270,7 +270,7 @@
static irqreturn_t do_kp_irq(int irq, void *_kp)
{
struct twl4030_keypad *kp = _kp;
- u8 reg;
+ u8 uninitialized_var(reg);
int ret;
#ifdef CONFIG_LOCKDEP
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 94b4c75..5ab3146 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -49,7 +49,6 @@
tristate
depends on MEDIA_TUNER
-source "drivers/media/video/omap-vout/Kconfig"
#
# Multimedia Video device configuration
#
@@ -747,7 +746,7 @@
---help---
V4L2 DSS and Camera driver support for OMAP2/3 based boards.
-# source "drivers/media/video/omap/Kconfig"
+source "drivers/media/video/omap/Kconfig"
source "drivers/media/video/isp/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 2c6194a..18f928f 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -10,7 +10,8 @@
omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
-videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-subdev.o
+videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-subdev.o \
+ v4l2-fh.o v4l2-event.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
ifeq ($(CONFIG_COMPAT),y)
@@ -112,6 +113,8 @@
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+obj-$(CONFIG_VIDEO_OMAP3_V4L2) += omap/
+
obj-$(CONFIG_VIDEO_IMX046) += imx046.o
obj-$(CONFIG_VIDEO_LV8093) += lv8093.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
@@ -143,7 +146,6 @@
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
-obj-$(CONFIG_VIDEO_OMAP_VIDEOOUT) += omap-vout/
obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
diff --git a/drivers/media/video/imx046.c b/drivers/media/video/imx046.c
index 852e1a1..84cc80c 100644
--- a/drivers/media/video/imx046.c
+++ b/drivers/media/video/imx046.c
@@ -93,7 +93,6 @@
int scaler;
int ver;
int fps;
- int state;
bool resuming;
};
@@ -105,15 +104,13 @@
/* list of image formats supported by imx046 sensor */
const static struct v4l2_fmtdesc imx046_formats[] = {
{
- .description = "Bayer10 (GrR/BGb)",
- .pixelformat = V4L2_PIX_FMT_SGRBG10,
+ .description = "Bayer10 (RGr/GbB)",
+ .pixelformat = V4L2_PIX_FMT_SRGGB10,
}
};
#define NUM_CAPTURE_FORMATS ARRAY_SIZE(imx046_formats)
-static u32 min_exposure_time = 1000;
-static u32 max_exposure_time = 128000;
static enum v4l2_power current_power_state;
/* Structure of Sensor settings that change with image size */
@@ -190,6 +187,41 @@
},
},
+ /* 729p_MP */
+ {
+ .clk = {
+ .pre_pll_div = 1,
+ .pll_mult = 36,
+ .post_pll_div = 1,
+ .vt_pix_clk_div = 10,
+ .vt_sys_clk_div = 1,
+ },
+ .mipi = {
+ .data_lanes = 1,
+ .ths_prepare = 6,
+ .ths_zero = 9,
+ .ths_settle_lower = 23,
+ .ths_settle_upper = 59,
+ },
+ .frame = {
+ .frame_len_lines_min = 1250,
+ .line_len_pck = 3456,
+ .x_addr_start = 348,
+ .x_addr_end = 2931,
+ .y_addr_start = 503,
+ .y_addr_end = 1960,
+ .x_output_size = 1292,
+ .y_output_size = 729,
+ .x_even_inc = 1,
+ .x_odd_inc = 3,
+ .y_even_inc = 1,
+ .y_odd_inc = 3,
+ .v_mode_add = 0,
+ .h_mode_add = 0,
+ .h_add_ave = 1,
+ },
+ },
+
/* TWO_MP */
{
.clk = {
@@ -201,10 +233,10 @@
},
.mipi = {
.data_lanes = 2,
- .ths_prepare = 4,
- .ths_zero = 5,
- .ths_settle_lower = 13,
- .ths_settle_upper = 33,
+ .ths_prepare = 2,
+ .ths_zero = 4,
+ .ths_settle_lower = 8,
+ .ths_settle_upper = 24,
},
.frame = {
.frame_len_lines_min = 629,
@@ -236,10 +268,10 @@
},
.mipi = {
.data_lanes = 2,
- .ths_prepare = 4,
- .ths_zero = 5,
- .ths_settle_lower = 13,
- .ths_settle_upper = 33,
+ .ths_prepare = 2,
+ .ths_zero = 4,
+ .ths_settle_lower = 8,
+ .ths_settle_upper = 24,
},
.frame = {
.frame_len_lines_min = 2510,
@@ -545,7 +577,6 @@
u16 isize = isize_current;
u32 frame_length_lines, line_time_q8;
struct imx046_sensor *sensor = s->priv;
- struct i2c_client *client = sensor->i2c_client;
struct imx046_sensor_settings *ss;
if ((fper->numerator == 0) || (fper->denominator == 0)) {
@@ -579,17 +610,11 @@
else if (frame_length_lines < ss->frame.frame_len_lines_min)
frame_length_lines = ss->frame.frame_len_lines_min;
- imx046_write_reg(client, IMX046_REG_FRAME_LEN_LINES,
- frame_length_lines, I2C_16BIT);
-
sensor_settings[isize].frame.frame_len_lines = frame_length_lines;
- /* Update max exposure time */
- max_exposure_time = (line_time_q8 * (frame_length_lines - 1)) >> 8;
-
printk(KERN_DEBUG "IMX046 Set Framerate: fper=%d/%d, "
"frame_len_lines=%d, max_expT=%dus\n", fper->numerator,
- fper->denominator, frame_length_lines, max_exposure_time);
+ fper->denominator, frame_length_lines, IMX046_MAX_EXPOSURE);
return err;
}
@@ -645,22 +670,24 @@
struct imx046_sensor_settings *ss;
if ((current_power_state == V4L2_POWER_ON) || sensor->resuming) {
- if (exp_time < min_exposure_time) {
+ if (exp_time < IMX046_MIN_EXPOSURE) {
v4l_err(client, "Exposure time %d us not within"
" the legal range.\n", exp_time);
v4l_err(client, "Exposure time must be between"
" %d us and %d us\n",
- min_exposure_time, max_exposure_time);
- exp_time = min_exposure_time;
+ IMX046_MIN_EXPOSURE,
+ IMX046_MAX_EXPOSURE);
+ exp_time = IMX046_MIN_EXPOSURE;
}
- if (exp_time > max_exposure_time) {
+ if (exp_time > IMX046_MAX_EXPOSURE) {
v4l_err(client, "Exposure time %d us not within"
" the legal range.\n", exp_time);
v4l_err(client, "Exposure time must be between"
" %d us and %d us\n",
- min_exposure_time, max_exposure_time);
- exp_time = max_exposure_time;
+ IMX046_MIN_EXPOSURE,
+ IMX046_MAX_EXPOSURE);
+ exp_time = IMX046_MAX_EXPOSURE;
}
ss = &sensor_settings[isize_current];
@@ -673,7 +700,15 @@
line_time_q8;
if (coarse_int_time > ss->frame.frame_len_lines - 2)
- coarse_int_time = ss->frame.frame_len_lines - 2;
+ err = imx046_write_reg(client,
+ IMX046_REG_FRAME_LEN_LINES,
+ coarse_int_time + 2,
+ I2C_16BIT);
+ else
+ err = imx046_write_reg(client,
+ IMX046_REG_FRAME_LEN_LINES,
+ ss->frame.frame_len_lines,
+ I2C_16BIT);
err = imx046_write_reg(client, IMX046_REG_COARSE_INT_TIME,
coarse_int_time, I2C_16BIT);
@@ -846,9 +881,10 @@
* @c: i2c client driver structure
* @isize: image size enum
*/
-int imx046_setup_mipi(struct imx046_sensor *sensor,
+int imx046_setup_mipi(struct v4l2_int_device *s,
enum imx046_image_size isize)
{
+ struct imx046_sensor *sensor = s->priv;
struct i2c_client *client = sensor->i2c_client;
/* NOTE: Make sure imx046_update_clocks is called 1st */
@@ -873,10 +909,11 @@
imx046_write_reg(client, IMX046_REG_RGLANESEL, 0x01, I2C_8BIT);
/* Set number of lanes in isp */
- sensor->pdata->csi2_lane_count(sensor_settings[isize].mipi.data_lanes);
+ sensor->pdata->csi2_lane_count(s,
+ sensor_settings[isize].mipi.data_lanes);
/* Send settings to ISP-CSI2 Receiver PHY */
- sensor->pdata->csi2_calc_phy_cfg0(current_clk.mipi_clk,
+ sensor->pdata->csi2_calc_phy_cfg0(s, current_clk.mipi_clk,
sensor_settings[isize].mipi.ths_settle_lower,
sensor_settings[isize].mipi.ths_settle_upper);
@@ -902,7 +939,7 @@
u32 val;
imx046_write_reg(client, IMX046_REG_FRAME_LEN_LINES,
- sensor_settings[isize].frame.frame_len_lines_min, I2C_16BIT);
+ sensor_settings[isize].frame.frame_len_lines, I2C_16BIT);
imx046_write_reg(client, IMX046_REG_LINE_LEN_PCK,
sensor_settings[isize].frame.line_len_pck, I2C_16BIT);
@@ -1029,38 +1066,30 @@
static int imx046_configure(struct v4l2_int_device *s)
{
struct imx046_sensor *sensor = s->priv;
- struct v4l2_pix_format *pix = &sensor->pix;
struct i2c_client *client = sensor->i2c_client;
- enum imx046_image_size isize;
+ enum imx046_image_size isize = isize_current;
int err, i;
struct vcontrol *lvc = NULL;
- isize = imx046_find_size(pix->width, pix->height);
- isize_current = isize;
-
err = imx046_write_reg(client, IMX046_REG_SW_RESET, 0x01, I2C_8BIT);
mdelay(5);
imx046_write_regs(client, initial_list);
- imx046_update_clocks(xclk_current, isize);
imx046_setup_pll(client, isize);
- imx046_setup_mipi(sensor, isize);
+ imx046_setup_mipi(s, isize);
/* configure image size and pixel format */
imx046_configure_frame(client, isize);
- /* Setting of frame rate */
- err = imx046_set_framerate(s, &sensor->timeperframe);
-
imx046_set_orientation(client, sensor->ver);
- sensor->pdata->csi2_cfg_vp_out_ctrl(2);
- sensor->pdata->csi2_ctrl_update(false);
+ sensor->pdata->csi2_cfg_vp_out_ctrl(s, 2);
+ sensor->pdata->csi2_ctrl_update(s, false);
- sensor->pdata->csi2_cfg_virtual_id(0, IMX046_CSI2_VIRTUAL_ID);
- sensor->pdata->csi2_ctx_update(0, false);
+ sensor->pdata->csi2_cfg_virtual_id(s, 0, IMX046_CSI2_VIRTUAL_ID);
+ sensor->pdata->csi2_ctx_update(s, 0, false);
imx046_set_virtual_id(client, IMX046_CSI2_VIRTUAL_ID);
/* Set initial exposure and gain */
@@ -1283,6 +1312,7 @@
struct v4l2_pix_format *pix2 = &sensor->pix;
isize = imx046_find_size(pix->width, pix->height);
+ isize_current = isize;
pix->width = imx046_sizes[isize].width;
pix->height = imx046_sizes[isize].height;
@@ -1346,6 +1376,87 @@
}
/**
+ * ioctl_g_pixclk - V4L2 sensor interface handler for ioctl_g_pixclk
+ * @s: pointer to standard V4L2 device structure
+ * @pixclk: pointer to unsigned 32 var to store pixelclk in HZ
+ *
+ * Returns the sensor's current pixel clock in HZ
+ */
+static int ioctl_priv_g_pixclk(struct v4l2_int_device *s, u32 *pixclk)
+{
+ *pixclk = current_clk.vt_pix_clk;
+
+ return 0;
+}
+
+/**
+ * ioctl_g_activesize - V4L2 sensor interface handler for ioctl_g_activesize
+ * @s: pointer to standard V4L2 device structure
+ * @pix: pointer to standard V4L2 v4l2_pix_format structure
+ *
+ * Returns the sensor's current active image basesize.
+ */
+static int ioctl_priv_g_activesize(struct v4l2_int_device *s,
+ struct v4l2_rect *pix)
+{
+ struct imx046_frame_settings *frm;
+
+ frm = &sensor_settings[isize_current].frame;
+ pix->left = frm->x_addr_start /
+ ((frm->x_even_inc + frm->x_odd_inc) / 2);
+ pix->top = frm->y_addr_start /
+ ((frm->y_even_inc + frm->y_odd_inc) / 2);
+ pix->width = ((frm->x_addr_end + 1) - frm->x_addr_start) /
+ ((frm->x_even_inc + frm->x_odd_inc) / 2);
+ pix->height = ((frm->y_addr_end + 1) - frm->y_addr_start) /
+ ((frm->y_even_inc + frm->y_odd_inc) / 2);
+
+ return 0;
+}
+
+/**
+ * ioctl_g_fullsize - V4L2 sensor interface handler for ioctl_g_fullsize
+ * @s: pointer to standard V4L2 device structure
+ * @pix: pointer to standard V4L2 v4l2_pix_format structure
+ *
+ * Returns the sensor's biggest image basesize.
+ */
+static int ioctl_priv_g_fullsize(struct v4l2_int_device *s,
+ struct v4l2_rect *pix)
+{
+ struct imx046_frame_settings *frm;
+
+ frm = &sensor_settings[isize_current].frame;
+ pix->left = 0;
+ pix->top = 0;
+ pix->width = frm->line_len_pck;
+ pix->height = frm->frame_len_lines;
+
+ return 0;
+}
+
+/**
+ * ioctl_g_pixelsize - V4L2 sensor interface handler for ioctl_g_pixelsize
+ * @s: pointer to standard V4L2 device structure
+ * @pix: pointer to standard V4L2 v4l2_pix_format structure
+ *
+ * Returns the sensor's configure pixel size.
+ */
+static int ioctl_priv_g_pixelsize(struct v4l2_int_device *s,
+ struct v4l2_rect *pix)
+{
+ struct imx046_frame_settings *frm;
+
+ frm = &sensor_settings[isize_current].frame;
+ pix->left = 0;
+ pix->top = 0;
+ pix->width = (frm->x_even_inc + frm->x_odd_inc) / 2;
+ pix->height = (frm->y_even_inc + frm->y_odd_inc) / 2;
+
+ return 0;
+}
+
+/**
* ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
* @s: pointer to standard V4L2 device structure
* @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
@@ -1384,12 +1495,15 @@
{
struct imx046_sensor *sensor = s->priv;
struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ int err = 0;
sensor->timeperframe = *timeperframe;
imx046sensor_calc_xclk();
+ imx046_update_clocks(xclk_current, isize_current);
+ err = imx046_set_framerate(s, &sensor->timeperframe);
*timeperframe = sensor->timeperframe;
- return 0;
+ return err;
}
@@ -1404,10 +1518,57 @@
{
struct imx046_sensor *sensor = s->priv;
- return sensor->pdata->priv_data_set(p);
+ return sensor->pdata->priv_data_set(s, p);
}
+static int __imx046_power_off_standby(struct v4l2_int_device *s,
+ enum v4l2_power on)
+{
+ struct imx046_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ int rval;
+
+ rval = sensor->pdata->power_set(s, on);
+ if (rval < 0) {
+ v4l_err(client, "Unable to set the power state: "
+ IMX046_DRIVER_NAME " sensor\n");
+ return rval;
+ }
+
+ sensor->pdata->set_xclk(s, 0);
+ return 0;
+}
+
+static int imx046_power_off(struct v4l2_int_device *s)
+{
+ return __imx046_power_off_standby(s, V4L2_POWER_OFF);
+}
+
+static int imx046_power_standby(struct v4l2_int_device *s)
+{
+ return __imx046_power_off_standby(s, V4L2_POWER_STANDBY);
+}
+
+static int imx046_power_on(struct v4l2_int_device *s)
+{
+ struct imx046_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ int rval;
+
+ sensor->pdata->set_xclk(s, xclk_current);
+
+ rval = sensor->pdata->power_set(s, V4L2_POWER_ON);
+ if (rval < 0) {
+ v4l_err(client, "Unable to set the power state: "
+ IMX046_DRIVER_NAME " sensor\n");
+ sensor->pdata->set_xclk(s, 0);
+ return rval;
+ }
+
+ return 0;
+}
+
/**
* ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num
* @s: pointer to standard V4L2 device structure
@@ -1418,57 +1579,20 @@
static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)
{
struct imx046_sensor *sensor = s->priv;
- struct i2c_client *client = sensor->i2c_client;
- struct omap34xxcam_hw_config hw_config;
struct vcontrol *lvc;
- int rval, i;
+ int i;
- rval = ioctl_g_priv(s, &hw_config);
- if (rval) {
- v4l_err(client, "Unable to get hw params\n");
- return rval;
- }
-
- if ((on == V4L2_POWER_STANDBY) && (sensor->state == SENSOR_DETECTED)) {
- /* imx046_write_regs(c, stream_off_list,
- I2C_STREAM_OFF_LIST_SIZE); */
- }
-
- if (on != V4L2_POWER_ON)
- sensor->pdata->set_xclk(0, hw_config.u.sensor.xclk);
- else
- sensor->pdata->set_xclk(xclk_current, hw_config.u.sensor.xclk);
-
- rval = sensor->pdata->power_set(&client->dev, on);
- if (rval < 0) {
- v4l_err(client, "Unable to set the power state: "
- IMX046_DRIVER_NAME " sensor\n");
- sensor->pdata->set_xclk(0, hw_config.u.sensor.xclk);
- return rval;
- }
-
- if ((current_power_state == V4L2_POWER_STANDBY) &&
- (on == V4L2_POWER_ON) &&
- (sensor->state == SENSOR_DETECTED)) {
- sensor->resuming = true;
- imx046_configure(s);
- }
-
- if ((on == V4L2_POWER_ON) && (sensor->state == SENSOR_NOT_DETECTED)) {
- rval = imx046_detect(client);
- if (rval < 0) {
- v4l_err(client, "Unable to detect "
- IMX046_DRIVER_NAME " sensor\n");
- sensor->state = SENSOR_NOT_DETECTED;
- return rval;
+ switch (on) {
+ case V4L2_POWER_ON:
+ imx046_power_on(s);
+ if (current_power_state == V4L2_POWER_STANDBY) {
+ sensor->resuming = true;
+ imx046_configure(s);
}
- sensor->state = SENSOR_DETECTED;
- sensor->ver = rval;
- v4l_info(client, IMX046_DRIVER_NAME
- " chip version 0x%02x detected\n", sensor->ver);
- }
+ break;
+ case V4L2_POWER_OFF:
+ imx046_power_off(s);
- if (on == V4L2_POWER_OFF) {
/* Reset defaults for controls */
i = find_vctrl(V4L2_CID_GAIN);
if (i >= 0) {
@@ -1485,6 +1609,10 @@
lvc = &imx046sensor_video_control[i];
lvc->current_value = IMX046_MIN_TEST_PATT_MODE;
}
+ break;
+ case V4L2_POWER_STANDBY:
+ imx046_power_standby(s);
+ break;
}
sensor->resuming = false;
@@ -1527,16 +1655,23 @@
struct i2c_client *client = sensor->i2c_client;
int err;
+ err = imx046_power_on(s);
+ if (err)
+ return -ENODEV;
+
err = imx046_detect(client);
if (err < 0) {
- v4l_err(client, "Unable to detect " IMX046_DRIVER_NAME
- " sensor\n");
+ v4l_err(client, "Unable to detect "
+ IMX046_DRIVER_NAME " sensor\n");
return err;
}
-
sensor->ver = err;
- v4l_info(client, IMX046_DRIVER_NAME " chip version "
- "0x%02x detected\n", sensor->ver);
+ v4l_info(client, IMX046_DRIVER_NAME
+ " chip version 0x%02x detected\n", sensor->ver);
+
+ err = imx046_power_off(s);
+ if (err)
+ return -ENODEV;
return 0;
}
@@ -1575,6 +1710,10 @@
const struct v4l2_fract imx046_frameintervals[] = {
{ .numerator = 3, .denominator = 30 },
+ { .numerator = 2, .denominator = 25 },
+ { .numerator = 1, .denominator = 15 },
+ { .numerator = 1, .denominator = 20 },
+ { .numerator = 1, .denominator = 25 },
{ .numerator = 1, .denominator = 30 },
};
@@ -1645,6 +1784,14 @@
.func = (v4l2_int_ioctl_func *)ioctl_g_ctrl },
{ .num = vidioc_int_s_ctrl_num,
.func = (v4l2_int_ioctl_func *)ioctl_s_ctrl },
+ { .num = vidioc_int_priv_g_pixclk_num,
+ .func = (v4l2_int_ioctl_func *)ioctl_priv_g_pixclk },
+ { .num = vidioc_int_priv_g_activesize_num,
+ .func = (v4l2_int_ioctl_func *)ioctl_priv_g_activesize },
+ { .num = vidioc_int_priv_g_fullsize_num,
+ .func = (v4l2_int_ioctl_func *)ioctl_priv_g_fullsize },
+ { .num = vidioc_int_priv_g_pixelsize_num,
+ .func = (v4l2_int_ioctl_func *)ioctl_priv_g_pixelsize },
};
static struct v4l2_int_slave imx046_slave = {
@@ -1690,10 +1837,10 @@
i2c_set_clientdata(client, sensor);
- /* Make the default capture format QCIF V4L2_PIX_FMT_SGRBG10 */
+ /* Make the default capture format QCIF V4L2_PIX_FMT_SRGGB10 */
sensor->pix.width = IMX046_IMAGE_WIDTH_MAX;
sensor->pix.height = IMX046_IMAGE_HEIGHT_MAX;
- sensor->pix.pixelformat = V4L2_PIX_FMT_SGRBG10;
+ sensor->pix.pixelformat = V4L2_PIX_FMT_SRGGB10;
err = v4l2_int_device_register(sensor->v4l2_int_device);
if (err)
@@ -1744,7 +1891,6 @@
.numerator = 1,
.denominator = 30,
},
- .state = SENSOR_NOT_DETECTED,
};
/**
diff --git a/drivers/media/video/imx046_regs.h b/drivers/media/video/imx046_regs.h
index 1ab2e63..62c4ff2 100644
--- a/drivers/media/video/imx046_regs.h
+++ b/drivers/media/video/imx046_regs.h
@@ -15,8 +15,6 @@
#ifndef IMX046_REGS_H
#define IMX046_REGS_H
-#define V4L2_CID_TEST_PATTERN (V4L2_CID_PRIVATE_BASE + 1)
-
/* The ID values we are looking for */
#define IMX046_MOD_ID 0x0046
#define IMX046_MFR_ID 0x000B
@@ -209,10 +207,12 @@
enum imx046_image_size {
QUART_MP,
HALF_MP,
+ p729p_MP,
TWO_MP,
EIGHT_MP
};
+#define NUM_IMAGE_SIZES ARRAY_SIZE(imx046_sizes)
/**
* struct imx046_capture_size - image capture size information
* @width: image width in pixels
@@ -230,7 +230,7 @@
struct imx046_clk_settings {
u16 pre_pll_div;
u16 pll_mult;
- u16 post_pll_div;
+ u16 post_pll_div;
u16 vt_pix_clk_div;
u16 vt_sys_clk_div;
};
@@ -298,16 +298,9 @@
const static struct imx046_capture_size imx046_sizes[] = {
{ 410, 308 }, /* QUART_MP - 1/8 Vertical Elim */
{ 820, 616 }, /* 0.5Mp - 4X Horizontal & Vertical Elim. */
+ { 1292, 729}, /*1292x729 - 1/2 vertical & horizontal Elim. */
{ 3280, 616 }, /* 2Mp - 4X Vertical Elim. */
{ 3280, 2464}, /* 8MP - Full Resolution */
};
-/* PLL settings for imx046 */
-enum imx046_pll_type {
- PLL_QUART_MP = 0,
- PLL_0_5MP,
- PLL_2MP,
- PLL_8MP,
-};
-
#endif /* ifndef IMX046_REGS_H */
diff --git a/drivers/media/video/isp/Kconfig b/drivers/media/video/isp/Kconfig
index eeabc8f..230a1fe 100644
--- a/drivers/media/video/isp/Kconfig
+++ b/drivers/media/video/isp/Kconfig
@@ -2,8 +2,8 @@
config VIDEO_OMAP34XX_ISP_PREVIEWER
tristate "OMAP ISP Previewer"
- depends on !ARCH_OMAP3410
+ depends on !ARCH_OMAP3410 && VIDEO_OMAP3
config VIDEO_OMAP34XX_ISP_RESIZER
tristate "OMAP ISP Resizer"
- depends on !ARCH_OMAP3410
+ depends on !ARCH_OMAP3410 && VIDEO_OMAP3
diff --git a/drivers/media/video/isp/Makefile b/drivers/media/video/isp/Makefile
index 67329ef..3bb3702 100644
--- a/drivers/media/video/isp/Makefile
+++ b/drivers/media/video/isp/Makefile
@@ -1,12 +1,9 @@
# Makefile for OMAP3 ISP driver
-ifdef CONFIG_ARCH_OMAP3410
isp-mod-objs += \
- isp.o ispccdc.o
-else
-isp-mod-objs += \
- isp.o ispccdc.o ispmmu.o \
- isppreview.o ispresizer.o isph3a.o isphist.o isp_af.o ispcsi2.o
+ isp.o ispccdc.o \
+ isppreview.o ispresizer.o isph3a.o isphist.o isp_af.o ispcsi2.o \
+ ispstat.o
obj-$(CONFIG_VIDEO_OMAP34XX_ISP_PREVIEWER) += \
omap_previewer.o
@@ -14,6 +11,5 @@
obj-$(CONFIG_VIDEO_OMAP34XX_ISP_RESIZER) += \
omap_resizer.o
-endif
-
obj-$(CONFIG_VIDEO_OMAP3) += isp-mod.o
+
diff --git a/drivers/media/video/isp/isp.c b/drivers/media/video/isp/isp.c
index dee2b0f..a9e9735 100644
--- a/drivers/media/video/isp/isp.c
+++ b/drivers/media/video/isp/isp.c
@@ -32,9 +32,9 @@
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
#include <linux/platform_device.h>
+#include <linux/device.h>
#include "isp.h"
-#include "ispmmu.h"
#include "ispreg.h"
#include "ispccdc.h"
#include "isph3a.h"
@@ -44,16 +44,14 @@
#include "ispresizer.h"
#include "ispcsi2.h"
-static struct isp_device *omap3isp;
+static struct platform_device *omap3isp_pdev;
+static int isp_complete_reset = 1;
-static int isp_try_size(struct v4l2_pix_format *pix_input,
- struct v4l2_pix_format *pix_output);
+static void isp_save_ctx(struct device *dev);
-static void isp_save_ctx(void);
+static void isp_restore_ctx(struct device *dev);
-static void isp_restore_ctx(void);
-
-static void isp_buf_init(void);
+static void isp_buf_init(struct device *dev);
/* List of image formats supported via OMAP ISP */
const static struct v4l2_fmtdesc isp_formats[] = {
@@ -69,12 +67,20 @@
.description = "Bayer10 (GrR/BGb)",
.pixelformat = V4L2_PIX_FMT_SGRBG10,
},
+ {
+ .description = "Bayer10 (GrR/BGb)",
+ .pixelformat = V4L2_PIX_FMT_SRGGB10,
+ },
+ {
+ .description = "Bayer10 (GrR/BGb)",
+ .pixelformat = V4L2_PIX_FMT_SGBRG10,
+ },
+ {
+ .description = "Bayer10 (GrR/BGb)",
+ .pixelformat = V4L2_PIX_FMT_SBGGR10,
+ },
};
-/* ISP Crop capabilities */
-static struct v4l2_rect ispcroprect;
-static struct v4l2_rect cur_rect;
-
/**
* struct vcontrol - Video control structure.
* @qc: V4L2 Query control structure.
@@ -140,129 +146,6 @@
},
};
-struct isp_buf {
- dma_addr_t isp_addr;
- void (*complete)(struct videobuf_buffer *vb, void *priv);
- struct videobuf_buffer *vb;
- void *priv;
- u32 vb_state;
-};
-
-#define ISP_BUFS_IS_FULL(bufs) \
- (((bufs)->queue + 1) % NUM_BUFS == (bufs)->done)
-#define ISP_BUFS_IS_EMPTY(bufs) ((bufs)->queue == (bufs)->done)
-#define ISP_BUFS_IS_LAST(bufs) \
- ((bufs)->queue == ((bufs)->done + 1) % NUM_BUFS)
-#define ISP_BUFS_QUEUED(bufs) \
- ((((bufs)->done - (bufs)->queue + NUM_BUFS)) % NUM_BUFS)
-#define ISP_BUF_DONE(bufs) ((bufs)->buf + (bufs)->done)
-#define ISP_BUF_NEXT_DONE(bufs) \
- ((bufs)->buf + ((bufs)->done + 1) % NUM_BUFS)
-#define ISP_BUF_QUEUE(bufs) ((bufs)->buf + (bufs)->queue)
-#define ISP_BUF_MARK_DONE(bufs) \
- (bufs)->done = ((bufs)->done + 1) % NUM_BUFS;
-#define ISP_BUF_MARK_QUEUED(bufs) \
- (bufs)->queue = ((bufs)->queue + 1) % NUM_BUFS;
-
-struct isp_bufs {
- dma_addr_t isp_addr_capture[VIDEO_MAX_FRAME];
- spinlock_t lock; /* For handling current buffer */
- /* queue full: (ispsg.queue + 1) % NUM_BUFS == ispsg.done
- queue empty: ispsg.queue == ispsg.done */
- struct isp_buf buf[NUM_BUFS];
- /* Next slot to queue a buffer. */
- int queue;
- /* Buffer that is being processed. */
- int done;
- /* Wait for this many hs_vs before anything else. */
- int wait_hs_vs;
-};
-
-/**
- * struct ispirq - Structure for containing callbacks to be called in ISP ISR.
- * @isp_callbk: Array which stores callback functions, indexed by the type of
- * callback (8 possible types).
- * @isp_callbk_arg1: Pointer to array containing pointers to the first argument
- * to be passed to the requested callback function.
- * @isp_callbk_arg2: Pointer to array containing pointers to the second
- * argument to be passed to the requested callback function.
- *
- * This structure is used to contain all the callback functions related for
- * each callback type (CBK_CCDC_VD0, CBK_CCDC_VD1, CBK_PREV_DONE,
- * CBK_RESZ_DONE, CBK_MMU_ERR, CBK_H3A_AWB_DONE, CBK_HIST_DONE, CBK_HS_VS,
- * CBK_LSC_ISR).
- */
-struct isp_irq {
- isp_callback_t isp_callbk[CBK_END];
- isp_vbq_callback_ptr isp_callbk_arg1[CBK_END];
- void *isp_callbk_arg2[CBK_END];
-};
-
-/**
- * struct ispmodule - Structure for storing ISP sub-module information.
- * @isp_pipeline: Bit mask for submodules enabled within the ISP.
- * @applyCrop: Flag to do a crop operation when video buffer queue ISR is done
- * @pix: Structure containing the format and layout of the output image.
- * @ccdc_input_width: ISP CCDC module input image width.
- * @ccdc_input_height: ISP CCDC module input image height.
- * @ccdc_output_width: ISP CCDC module output image width.
- * @ccdc_output_height: ISP CCDC module output image height.
- * @preview_input_width: ISP Preview module input image width.
- * @preview_input_height: ISP Preview module input image height.
- * @preview_output_width: ISP Preview module output image width.
- * @preview_output_height: ISP Preview module output image height.
- * @resizer_input_width: ISP Resizer module input image width.
- * @resizer_input_height: ISP Resizer module input image height.
- * @resizer_output_width: ISP Resizer module output image width.
- * @resizer_output_height: ISP Resizer module output image height.
- */
-struct isp_module {
- unsigned int isp_pipeline;
- int applyCrop;
- struct v4l2_pix_format pix;
- unsigned int ccdc_input_width;
- unsigned int ccdc_input_height;
- unsigned int ccdc_output_width;
- unsigned int ccdc_output_height;
- unsigned int preview_input_width;
- unsigned int preview_input_height;
- unsigned int preview_output_width;
- unsigned int preview_output_height;
- unsigned int resizer_input_width;
- unsigned int resizer_input_height;
- unsigned int resizer_output_width;
- unsigned int resizer_output_height;
-};
-
-#define RAW_CAPTURE(isp) \
- (!((isp)->module.isp_pipeline & OMAP_ISP_PREVIEW))
-
-/**
- * struct isp - Structure for storing ISP Control module information
- * @lock: Spinlock to sync between isr and processes.
- * @isp_mutex: Semaphore used to get access to the ISP.
- * @ref_count: Reference counter.
- * @cam_ick: Pointer to ISP Interface clock.
- * @cam_fck: Pointer to ISP Functional clock.
- *
- * This structure is used to store the OMAP ISP Control Information.
- */
-static struct isp {
- spinlock_t lock; /* For handling registered ISP callbacks */
- struct mutex isp_mutex; /* For handling ref_count field */
- int ref_count;
- struct clk *cam_ick;
- struct clk *cam_mclk;
- struct clk *csi2_fck;
- struct isp_interface_config *config;
- dma_addr_t tmp_buf;
- size_t tmp_buf_size;
- unsigned long tmp_buf_offset;
- struct isp_bufs bufs;
- struct isp_irq irq;
- struct isp_module module;
-} isp_obj;
-
/* Structure for saving/restoring ISP module registers */
static struct isp_reg isp_reg_list[] = {
{OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG, 0},
@@ -292,19 +175,21 @@
{0, ISP_TOK_TERM, 0}
};
-u32 isp_reg_readl(enum isp_mem_resources isp_mmio_range, u32 reg_offset)
+/**
+ * isp_flush - Post pending L3 bus writes by doing a register readback
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ *
+ * In order to force posting of pending writes, we need to write and
+ * readback the same register, in this case the revision register.
+ *
+ * See this link for reference:
+ * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
+ **/
+void isp_flush(struct device *dev)
{
- return __raw_readl(omap3isp->mmio_base[isp_mmio_range] + reg_offset);
+ isp_reg_writel(dev, 0, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
}
-EXPORT_SYMBOL(isp_reg_readl);
-
-void isp_reg_writel(u32 reg_value, enum isp_mem_resources isp_mmio_range,
- u32 reg_offset)
-{
- __raw_writel(reg_value,
- omap3isp->mmio_base[isp_mmio_range] + reg_offset);
-}
-EXPORT_SYMBOL(isp_reg_writel);
/*
*
@@ -313,7 +198,7 @@
*/
/**
- * find_vctrl - Returns the index of the ctrl array of the requested ctrl ID.
+ * find_vctrl - Return the index of the ctrl array of the requested ctrl ID.
* @id: Requested control ID.
*
* Returns 0 if successful, -EINVAL if not found, or -EDOM if its out of
@@ -336,6 +221,12 @@
return i;
}
+/**
+ * find_next_vctrl - Return next v4l2 ctrl ID available after the specified ID
+ * @id: Reference V4L2 control ID.
+ *
+ * Returns 0 if successful, or -EINVAL if not found.
+ **/
static int find_next_vctrl(int id)
{
int i;
@@ -357,7 +248,7 @@
}
/**
- * find_vmenu - Returns index of the menu array of the requested ctrl option.
+ * find_vmenu - Return index of the menu array of the requested ctrl option.
* @id: Requested control ID.
* @index: Requested menu option index.
*
@@ -381,80 +272,128 @@
}
/**
- * isp_release_resources - Free ISP submodules
+ * isp_release_resources - Free all currently requested ISP submodules.
+ * @dev: Device pointer specific to the OMAP3 ISP.
**/
-static void isp_release_resources(void)
+static void isp_release_resources(struct device *dev)
{
- if (isp_obj.module.isp_pipeline & OMAP_ISP_CCDC)
- ispccdc_free();
+ struct isp_device *isp = dev_get_drvdata(dev);
- if (isp_obj.module.isp_pipeline & OMAP_ISP_PREVIEW)
- isppreview_free();
+ if (isp->pipeline.modules & OMAP_ISP_CCDC)
+ ispccdc_free(&isp->isp_ccdc);
- if (isp_obj.module.isp_pipeline & OMAP_ISP_RESIZER)
- ispresizer_free();
+ if (isp->pipeline.modules & OMAP_ISP_PREVIEW)
+ isppreview_free(&isp->isp_prev);
+
+ if (isp->pipeline.modules & OMAP_ISP_RESIZER)
+ ispresizer_free(&isp->isp_res);
return;
}
-static int isp_wait(int (*busy)(void), int wait_for_busy, int max_wait)
+/**
+ * isp_wait - Wait for idle or busy state transition with a time limit
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @busy: Function pointer which determines if submodule is busy.
+ * @wait_for_busy: If 0, waits for idle state, if 1, waits for busy state.
+ * @max_wait: Max retry count in us for wait for idle/busy transition.
+ * @priv: Function parameter to send to busy check function.
+ **/
+static int isp_wait(struct device *dev, int (*busy)(void *), int wait_for_busy,
+ int max_wait, void *priv)
{
int wait = 0;
if (max_wait == 0)
max_wait = 10000; /* 10 ms */
- while ((wait_for_busy && !busy())
- || (!wait_for_busy && busy())) {
+ while ((wait_for_busy && !busy(priv))
+ || (!wait_for_busy && busy(priv))) {
rmb();
udelay(1);
wait++;
- if (wait > max_wait) {
- printk(KERN_ALERT "%s: wait is too much\n", __func__);
+ if (wait > max_wait)
return -EBUSY;
- }
}
DPRINTK_ISPCTRL(KERN_ALERT "%s: wait %d\n", __func__, wait);
return 0;
}
-static int ispccdc_sbl_wait_idle(int max_wait)
+/**
+ * ispccdc_sbl_wait_idle - Wrapper to wait for ccdc sbl status bits to be idle.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @max_wait: Max retry count for wait for idle transition of the CCDC SBL bits
+ **/
+static int ispccdc_sbl_wait_idle(struct isp_ccdc_device *isp_ccdc, int max_wait)
{
- return isp_wait(ispccdc_sbl_busy, 0, max_wait);
+ struct device *dev = to_device(isp_ccdc);
+
+ return isp_wait(dev, ispccdc_sbl_busy, 0, max_wait, isp_ccdc);
}
-static void isp_enable_interrupts(int is_raw)
+/**
+ * isp_enable_interrupts - Enable ISP interrupts.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+static void isp_enable_interrupts(struct device *dev)
{
- isp_reg_writel(-1, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
- isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
- IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ |
- IRQ0ENABLE_HS_VS_IRQ |
- IRQ0ENABLE_CCDC_VD0_IRQ |
- IRQ0ENABLE_CCDC_VD1_IRQ);
+ struct isp_device *isp = dev_get_drvdata(dev);
+ u32 irq0enable;
- if (is_raw)
- return;
+ irq0enable = IRQ0ENABLE_CCDC_VD0_IRQ
+ | IRQ0ENABLE_CSIA_IRQ
+ | IRQ0ENABLE_CSIB_IRQ | IRQ0ENABLE_HIST_DONE_IRQ
+ | IRQ0ENABLE_H3A_AWB_DONE_IRQ | IRQ0ENABLE_H3A_AF_DONE_IRQ
+ | isp->interrupts;
- isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
- IRQ0ENABLE_PRV_DONE_IRQ |
- IRQ0ENABLE_RSZ_DONE_IRQ);
+ if (CCDC_PREV_CAPTURE(isp))
+ irq0enable |= IRQ0ENABLE_PRV_DONE_IRQ;
+
+ if (CCDC_PREV_RESZ_CAPTURE(isp))
+ irq0enable |= IRQ0ENABLE_PRV_DONE_IRQ | IRQ0ENABLE_RSZ_DONE_IRQ;
+
+ if (isp_complete_reset) {
+ isp_reg_writel(dev, -1, OMAP3_ISP_IOMEM_MAIN,
+ ISP_IRQ0STATUS);
+ isp_complete_reset = 0;
+ }
+ isp_reg_writel(dev, irq0enable, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
return;
}
-static void isp_disable_interrupts(void)
+/**
+ * isp_disable_interrupts - Disable all ISP interrupts.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+static void isp_disable_interrupts(struct device *dev)
{
- isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
- ~(IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ |
- IRQ0ENABLE_HS_VS_IRQ |
- IRQ0ENABLE_CCDC_VD0_IRQ |
- IRQ0ENABLE_CCDC_VD1_IRQ |
- IRQ0ENABLE_PRV_DONE_IRQ |
- IRQ0ENABLE_RSZ_DONE_IRQ));
+ struct isp_device *isp = dev_get_drvdata(dev);
+ u32 irq0enable;
+ u32 v ;
+
+ irq0enable = ~(IRQ0ENABLE_CCDC_VD0_IRQ
+ | IRQ0ENABLE_CSIA_IRQ
+ | IRQ0ENABLE_CSIB_IRQ | IRQ0ENABLE_HIST_DONE_IRQ
+ | IRQ0ENABLE_H3A_AWB_DONE_IRQ | IRQ0ENABLE_H3A_AF_DONE_IRQ
+ | isp->interrupts);
+
+ if (CCDC_PREV_CAPTURE(isp))
+ irq0enable &= ~IRQ0ENABLE_PRV_DONE_IRQ;
+
+ if (CCDC_PREV_RESZ_CAPTURE(isp))
+ irq0enable &= ~(IRQ0ENABLE_PRV_DONE_IRQ
+ | IRQ0ENABLE_RSZ_DONE_IRQ);
+
+ v = isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
+
+ isp_reg_writel(dev, v & irq0enable,
+ OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
}
/**
- * isp_set_callback - Sets the callback for the ISP module done events.
+ * isp_set_callback - Set an external callback for an ISP interrupt.
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @type: Type of the event for which callback is requested.
* @callback: Method to be called as callback in the ISR context.
* @arg1: First argument to be passed when callback is called in ISR.
@@ -463,10 +402,11 @@
* This function sets a callback function for a done event in the ISP
* module, and enables the corresponding interrupt.
**/
-int isp_set_callback(enum isp_callback_type type, isp_callback_t callback,
- isp_vbq_callback_ptr arg1,
+int isp_set_callback(struct device *dev, enum isp_callback_type type,
+ isp_callback_t callback, isp_vbq_callback_ptr arg1,
void *arg2)
{
+ struct isp_device *isp = dev_get_drvdata(dev);
unsigned long irqflags = 0;
if (callback == NULL) {
@@ -474,41 +414,23 @@
return -EINVAL;
}
- spin_lock_irqsave(&isp_obj.lock, irqflags);
- isp_obj.irq.isp_callbk[type] = callback;
- isp_obj.irq.isp_callbk_arg1[type] = arg1;
- isp_obj.irq.isp_callbk_arg2[type] = arg2;
- spin_unlock_irqrestore(&isp_obj.lock, irqflags);
+ spin_lock_irqsave(&isp->lock, irqflags);
+ isp->irq.isp_callbk[type] = callback;
+ isp->irq.isp_callbk_arg1[type] = arg1;
+ isp->irq.isp_callbk_arg2[type] = arg2;
+ spin_unlock_irqrestore(&isp->lock, irqflags);
switch (type) {
- case CBK_H3A_AWB_DONE:
- isp_reg_writel(IRQ0ENABLE_H3A_AWB_DONE_IRQ,
- OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
- isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
- IRQ0ENABLE_H3A_AWB_DONE_IRQ);
- break;
- case CBK_H3A_AF_DONE:
- isp_reg_writel(IRQ0ENABLE_H3A_AF_DONE_IRQ,
- OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
- isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
- IRQ0ENABLE_H3A_AF_DONE_IRQ);
- break;
- case CBK_HIST_DONE:
- isp_reg_writel(IRQ0ENABLE_HIST_DONE_IRQ,
- OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
- isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
- IRQ0ENABLE_HIST_DONE_IRQ);
- break;
case CBK_PREV_DONE:
- isp_reg_writel(IRQ0ENABLE_PRV_DONE_IRQ,
+ isp_reg_writel(dev, IRQ0ENABLE_PRV_DONE_IRQ,
OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
- isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
IRQ0ENABLE_PRV_DONE_IRQ);
break;
case CBK_RESZ_DONE:
- isp_reg_writel(IRQ0ENABLE_RSZ_DONE_IRQ,
+ isp_reg_writel(dev, IRQ0ENABLE_RSZ_DONE_IRQ,
OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
- isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
IRQ0ENABLE_RSZ_DONE_IRQ);
break;
default:
@@ -521,49 +443,30 @@
/**
* isp_unset_callback - Clears the callback for the ISP module done events.
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @type: Type of the event for which callback to be cleared.
*
* This function clears a callback function for a done event in the ISP
* module, and disables the corresponding interrupt.
**/
-int isp_unset_callback(enum isp_callback_type type)
+int isp_unset_callback(struct device *dev, enum isp_callback_type type)
{
+ struct isp_device *isp = dev_get_drvdata(dev);
unsigned long irqflags = 0;
- spin_lock_irqsave(&isp_obj.lock, irqflags);
- isp_obj.irq.isp_callbk[type] = NULL;
- isp_obj.irq.isp_callbk_arg1[type] = NULL;
- isp_obj.irq.isp_callbk_arg2[type] = NULL;
- spin_unlock_irqrestore(&isp_obj.lock, irqflags);
+ spin_lock_irqsave(&isp->lock, irqflags);
+ isp->irq.isp_callbk[type] = NULL;
+ isp->irq.isp_callbk_arg1[type] = NULL;
+ isp->irq.isp_callbk_arg2[type] = NULL;
+ spin_unlock_irqrestore(&isp->lock, irqflags);
switch (type) {
- case CBK_H3A_AWB_DONE:
- isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
- ~IRQ0ENABLE_H3A_AWB_DONE_IRQ);
- break;
- case CBK_H3A_AF_DONE:
- isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
- ~IRQ0ENABLE_H3A_AF_DONE_IRQ);
- break;
- case CBK_HIST_DONE:
- isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
- ~IRQ0ENABLE_HIST_DONE_IRQ);
- break;
- case CBK_CSIA:
- isp_csi2_irq_set(0);
- break;
- case CBK_CSIB:
- isp_reg_writel(IRQ0ENABLE_CSIB_IRQ, OMAP3_ISP_IOMEM_MAIN,
- ISP_IRQ0STATUS);
- isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
- IRQ0ENABLE_CSIB_IRQ);
- break;
case CBK_PREV_DONE:
- isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
~IRQ0ENABLE_PRV_DONE_IRQ);
break;
case CBK_RESZ_DONE:
- isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
~IRQ0ENABLE_RSZ_DONE_IRQ);
break;
default:
@@ -576,29 +479,31 @@
/**
* isp_set_xclk - Configures the specified cam_xclk to the desired frequency.
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @xclk: Desired frequency of the clock in Hz.
* @xclksel: XCLK to configure (0 = A, 1 = B).
*
* Configures the specified MCLK divisor in the ISP timing control register
* (TCTRL_CTRL) to generate the desired xclk clock value.
*
- * Divisor = CM_CAM_MCLK_HZ / xclk
+ * Divisor = mclk / xclk
*
* Returns the final frequency that is actually being generated
**/
-u32 isp_set_xclk(u32 xclk, u8 xclksel)
+u32 isp_set_xclk(struct device *dev, u32 xclk, u8 xclksel)
{
u32 divisor;
u32 currentxclk;
+ struct isp_device *isp = dev_get_drvdata(dev);
- if (xclk >= CM_CAM_MCLK_HZ) {
+ if (xclk >= isp->mclk) {
divisor = ISPTCTRL_CTRL_DIV_BYPASS;
- currentxclk = CM_CAM_MCLK_HZ;
+ currentxclk = isp->mclk;
} else if (xclk >= 2) {
- divisor = CM_CAM_MCLK_HZ / xclk;
+ divisor = isp->mclk / xclk;
if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS)
divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1;
- currentxclk = CM_CAM_MCLK_HZ / divisor;
+ currentxclk = isp->mclk / divisor;
} else {
divisor = xclk;
currentxclk = 0;
@@ -606,14 +511,14 @@
switch (xclksel) {
case 0:
- isp_reg_and_or(OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
~ISPTCTRL_CTRL_DIVA_MASK,
divisor << ISPTCTRL_CTRL_DIVA_SHIFT);
DPRINTK_ISPCTRL("isp_set_xclk(): cam_xclka set to %d Hz\n",
currentxclk);
break;
case 1:
- isp_reg_and_or(OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
~ISPTCTRL_CTRL_DIVB_MASK,
divisor << ISPTCTRL_CTRL_DIVB_SHIFT);
DPRINTK_ISPCTRL("isp_set_xclk(): cam_xclkb set to %d Hz\n",
@@ -621,8 +526,7 @@
break;
default:
DPRINTK_ISPCTRL("ISP_ERR: isp_set_xclk(): Invalid requested "
- "xclk. Must be 0 (A) or 1 (B)."
- "\n");
+ "xclk. Must be 0 (A) or 1 (B).\n");
return -EINVAL;
}
@@ -632,54 +536,53 @@
/**
* isp_power_settings - Sysconfig settings, for Power Management.
- * @isp_sysconfig: Structure containing the power settings for ISP to configure
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @idle: Consider idle state.
*
* Sets the power settings for the ISP, and SBL bus.
**/
-static void isp_power_settings(int idle)
+static void isp_power_settings(struct device *dev, int idle)
{
if (idle) {
- isp_reg_writel(ISP_SYSCONFIG_AUTOIDLE |
+ isp_reg_writel(dev,
(ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY <<
ISP_SYSCONFIG_MIDLEMODE_SHIFT),
- OMAP3_ISP_IOMEM_MAIN,
- ISP_SYSCONFIG);
+ OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
if (omap_rev() == OMAP3430_REV_ES1_0) {
- isp_reg_writel(ISPCSI1_AUTOIDLE |
+ isp_reg_writel(dev, ISPCSI1_AUTOIDLE |
(ISPCSI1_MIDLEMODE_SMARTSTANDBY <<
ISPCSI1_MIDLEMODE_SHIFT),
OMAP3_ISP_IOMEM_CSI2A,
ISP_CSIA_SYSCONFIG);
- isp_reg_writel(ISPCSI1_AUTOIDLE |
+ isp_reg_writel(dev, ISPCSI1_AUTOIDLE |
(ISPCSI1_MIDLEMODE_SMARTSTANDBY <<
ISPCSI1_MIDLEMODE_SHIFT),
OMAP3_ISP_IOMEM_CCP2,
ISP_CSIB_SYSCONFIG);
}
- isp_reg_writel(ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN,
+ isp_reg_writel(dev, ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN,
ISP_CTRL);
} else {
- isp_reg_writel(ISP_SYSCONFIG_AUTOIDLE |
+ isp_reg_writel(dev,
(ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY <<
ISP_SYSCONFIG_MIDLEMODE_SHIFT),
- OMAP3_ISP_IOMEM_MAIN,
- ISP_SYSCONFIG);
+ OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
if (omap_rev() == OMAP3430_REV_ES1_0) {
- isp_reg_writel(ISPCSI1_AUTOIDLE |
+ isp_reg_writel(dev, ISPCSI1_AUTOIDLE |
(ISPCSI1_MIDLEMODE_FORCESTANDBY <<
ISPCSI1_MIDLEMODE_SHIFT),
OMAP3_ISP_IOMEM_CSI2A,
ISP_CSIA_SYSCONFIG);
- isp_reg_writel(ISPCSI1_AUTOIDLE |
+ isp_reg_writel(dev, ISPCSI1_AUTOIDLE |
(ISPCSI1_MIDLEMODE_FORCESTANDBY <<
ISPCSI1_MIDLEMODE_SHIFT),
OMAP3_ISP_IOMEM_CCP2,
ISP_CSIB_SYSCONFIG);
}
- isp_reg_writel(ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN,
+ isp_reg_writel(dev, ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN,
ISP_CTRL);
}
}
@@ -690,7 +593,31 @@
| (val << shift); \
} while (0)
-static int isp_init_csi(struct isp_interface_config *config)
+/**
+ * isp_csi_enable - Enable CSI1/CCP2 interface.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @enable: Enable flag.
+ **/
+static void isp_csi_enable(struct device *dev, u8 enable)
+{
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL,
+ ~(BIT(0) | BIT(4)),
+ enable ? (BIT(0) | BIT(4)) : 0);
+}
+
+/**
+ * isp_init_csi - Initialize CSI1/CCP2 interface.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @config: Pointer to ISP interface config structure.
+ *
+ * This will analize the parameters passed by the interface config
+ * structure, and configure the respective registers for proper CSI1/CCP2
+ * config.
+ *
+ * Returns -EINVAL if wrong format, -EIO if strobe is choosen in CSI1 mode, or
+ * 0 on success.
+ **/
+static int isp_init_csi(struct device *dev, struct isp_interface_config *config)
{
u32 i = 0, val, reg;
int format;
@@ -703,29 +630,28 @@
format = 0x12; /* RAW8+DPCM10+VP */
break;
default:
- printk(KERN_ERR "isp_init_csi: bad csi format\n");
+ dev_err(dev, "isp_init_csi: bad csi format\n");
return -EINVAL;
}
/* Reset the CSI and wait for reset to complete */
- isp_reg_writel(isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, ISPCSI1_SYSCONFIG) |
- BIT(1),
- OMAP3_ISP_IOMEM_CCP2,
- ISPCSI1_SYSCONFIG);
- while (!(isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, ISPCSI1_SYSSTATUS) &
+ isp_reg_writel(dev, isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2,
+ ISPCSI1_SYSCONFIG) | BIT(1),
+ OMAP3_ISP_IOMEM_CCP2, ISPCSI1_SYSCONFIG);
+ while (!(isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_SYSSTATUS) &
BIT(0))) {
udelay(10);
if (i++ > 10)
break;
}
- if (!(isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, ISPCSI1_SYSSTATUS) &
+ if (!(isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_SYSSTATUS) &
BIT(0))) {
- printk(KERN_WARNING
+ dev_warn(dev,
"omap3_isp: timeout waiting for csi reset\n");
}
/* ISPCSI1_CTRL */
- val = isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL);
+ val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL);
val &= ~BIT(11); /* Enable VP only off ->
extract embedded data to interconnect */
BIT_SET(val, 8, 0x3, config->u.csi.vpclk); /* Video port clock */
@@ -740,43 +666,55 @@
BIT_SET(val, 1, 1, config->u.csi.signalling);
BIT_SET(val, 10, 1, config->u.csi.strobe_clock_inv);
val |= BIT(4); /* Magic bit to enable CSI1 and strobe mode */
- isp_reg_writel(val, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL);
/* ISPCSI1_LCx_CTRL logical channel #0 */
reg = ISPCSI1_LCx_CTRL(0); /* reg = ISPCSI1_CTRL1; */
- val = isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, reg);
+ val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2, reg);
/* Format = RAW10+VP or RAW8+DPCM10+VP*/
BIT_SET(val, 3, 0x1f, format);
/* Enable setting of frame regions of interest */
BIT_SET(val, 1, 1, 1);
BIT_SET(val, 2, 1, config->u.csi.crc);
- isp_reg_writel(val, OMAP3_ISP_IOMEM_CCP2, reg);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_CCP2, reg);
/* ISPCSI1_DAT_START for logical channel #0 */
reg = ISPCSI1_LCx_DAT_START(0); /* reg = ISPCSI1_DAT_START; */
- val = isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, reg);
+ val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2, reg);
BIT_SET(val, 16, 0xfff, config->u.csi.data_start);
- isp_reg_writel(val, OMAP3_ISP_IOMEM_CCP2, reg);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_CCP2, reg);
/* ISPCSI1_DAT_SIZE for logical channel #0 */
reg = ISPCSI1_LCx_DAT_SIZE(0); /* reg = ISPCSI1_DAT_SIZE; */
- val = isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, reg);
+ val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2, reg);
BIT_SET(val, 16, 0xfff, config->u.csi.data_size);
- isp_reg_writel(val, OMAP3_ISP_IOMEM_CCP2, reg);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_CCP2, reg);
/* Clear status bits for logical channel #0 */
- isp_reg_writel(0xFFF & ~BIT(6), OMAP3_ISP_IOMEM_CCP2,
+ val = ISPCSI1_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
+ ISPCSI1_LC01_IRQSTATUS_LC0_CRC_IRQ |
+ ISPCSI1_LC01_IRQSTATUS_LC0_FSP_IRQ |
+ ISPCSI1_LC01_IRQSTATUS_LC0_FW_IRQ |
+ ISPCSI1_LC01_IRQSTATUS_LC0_FSC_IRQ |
+ ISPCSI1_LC01_IRQSTATUS_LC0_SSC_IRQ;
+
+ /* Clear IRQ status bits for logical channel #0 */
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_CCP2,
ISPCSI1_LC01_IRQSTATUS);
- /* Enable CSI1 */
- val = isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL);
- val |= BIT(0) | BIT(4);
- isp_reg_writel(val, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL);
+ /* Enable IRQs for logical channel #0 */
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_LC01_IRQENABLE, val);
- if (!(isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL) & BIT(4))) {
- printk(KERN_WARNING "OMAP3 CSI1 bus not available\n");
- if (config->u.csi.signalling) /* Strobe mode requires CSI1 */
+ /* Enable CSI1 */
+ isp_csi_enable(dev, 1);
+
+ if (!(isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2,
+ ISPCSI1_CTRL) & BIT(4))) {
+ dev_warn(dev, "OMAP3 CSI1 bus not available\n");
+ if (config->u.csi.signalling) {
+ /* Strobe mode requires CCP2 */
return -EIO;
+ }
}
return 0;
@@ -784,8 +722,9 @@
/**
* isp_configure_interface - Configures ISP Control I/F related parameters.
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @config: Pointer to structure containing the desired configuration for the
- * ISP.
+ * ISP.
*
* Configures ISP control register (ISP_CTRL) with the values specified inside
* the config structure. Controls:
@@ -794,13 +733,18 @@
* - Pixel clock polarity.
* - 8 to 16-bit bridge at the input of CCDC module.
* - HS or VS synchronization signal detection
+ *
+ * Returns 0 on success, otherwise, will return other negative error value.
**/
-int isp_configure_interface(struct isp_interface_config *config)
+int isp_configure_interface(struct device *dev,
+ struct isp_interface_config *config)
{
- u32 ispctrl_val = isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+ struct isp_device *isp = dev_get_drvdata(dev);
+ u32 ispctrl_val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+ u32 fmtcfg;
int r;
- isp_obj.config = config;
+ isp->config = config;
ispctrl_val &= ISPCTRL_SHIFT_MASK;
ispctrl_val |= config->dataline_shift << ISPCTRL_SHIFT_SHIFT;
@@ -808,7 +752,7 @@
ispctrl_val &= ISPCTRL_PAR_SER_CLK_SEL_MASK;
- isp_buf_init();
+ isp_buf_init(dev);
switch (config->ccdc_par_ser) {
case ISP_PARLL:
@@ -824,26 +768,27 @@
ispctrl_val &= ~ISPCTRL_PAR_BRIDGE_BENDIAN;
if (config->u.csi.crc)
- isp_csi2_ctrl_config_ecc_enable(true);
+ isp_csi2_ctrl_config_ecc_enable(&isp->isp_csi2, true);
- isp_csi2_ctrl_config_vp_out_ctrl(config->u.csi.vpclk);
- isp_csi2_ctrl_config_vp_only_enable(true);
- isp_csi2_ctrl_config_vp_clk_enable(true);
- isp_csi2_ctrl_update(false);
+ isp_csi2_ctrl_config_vp_out_ctrl(&isp->isp_csi2,
+ config->u.csi.vpclk);
+ isp_csi2_ctrl_config_vp_only_enable(&isp->isp_csi2, true);
+ isp_csi2_ctrl_config_vp_clk_enable(&isp->isp_csi2, true);
+ isp_csi2_ctrl_update(&isp->isp_csi2, false);
- isp_csi2_ctx_config_format(0, config->u.csi.format);
- isp_csi2_ctx_update(0, false);
+ isp_csi2_ctx_config_format(&isp->isp_csi2, 0,
+ config->u.csi.format);
+ isp_csi2_ctx_update(&isp->isp_csi2, 0, false);
- isp_csi2_irq_complexio1_set(1);
- isp_csi2_irq_status_set(1);
- isp_csi2_irq_set(1);
+ isp_csi2_irq_complexio1_set(&isp->isp_csi2, 1);
+ isp_csi2_irq_status_set(&isp->isp_csi2, 1);
- isp_csi2_enable(1);
+ isp_csi2_enable(&isp->isp_csi2, 1);
mdelay(3);
break;
case ISP_CSIB:
ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIB;
- r = isp_init_csi(config);
+ r = isp_init_csi(dev, config);
if (r)
return r;
break;
@@ -856,90 +801,190 @@
ispctrl_val &= ~ISPCTRL_SYNC_DETECT_VSRISE;
ispctrl_val |= config->hsvs_syncdetect;
- isp_reg_writel(ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+ isp_reg_writel(dev, ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
- /* Set sensor specific fields in CCDC and Previewer module.*/
- ispccdc_set_wenlog(config->wenlog);
- ispccdc_set_crop_offset(config->raw_fmt_in);
+ /* Set sensor specific fields in CCDC and Previewer module. */
+ ispccdc_set_wenlog(&isp->isp_ccdc, config->wenlog);
+ ispccdc_set_raw_offset(&isp->isp_ccdc, config->raw_fmt_in);
+
+ isp->mclk = config->cam_mclk;
+ isp_enable_mclk(dev);
+ /* FIXME: this should be set in ispccdc_config_vp() */
+ fmtcfg = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
+ fmtcfg &= ISPCCDC_FMTCFG_VPIF_FRQ_MASK;
+ if (config->pixelclk) {
+ unsigned long l3_ick = clk_get_rate(isp->l3_ick);
+ unsigned long div = l3_ick / config->pixelclk;
+ if (div < 2)
+ div = 2;
+ if (div > 6)
+ div = 6;
+ fmtcfg |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
+ }
+ isp_reg_writel(dev, fmtcfg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
return 0;
}
EXPORT_SYMBOL(isp_configure_interface);
-static int isp_buf_process(struct isp_bufs *bufs);
+void isp_hist_dma_done(struct device *dev)
+{
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_irq *irqdis = &isp->irq;
+
+ isp_hist_enable(&isp->isp_hist, 1);
+ if (ispccdc_busy(&isp->isp_ccdc)) {
+ /* Histogram cannot be enabled in this frame anymore */
+ isp_hist_enable(&isp->isp_hist, 0);
+ if (isp_hist_busy(&isp->isp_hist))
+ isp_hist_mark_invalid_buf(&isp->isp_hist);
+ }
+ if (irqdis->isp_callbk[CBK_CATCHALL]) {
+ irqdis->isp_callbk[CBK_CATCHALL](
+ HIST_DONE,
+ irqdis->isp_callbk_arg1[CBK_CATCHALL],
+ irqdis->isp_callbk_arg2[CBK_CATCHALL]);
+ }
+}
+
+static void isp_buf_process(struct device *dev, struct isp_bufs *bufs);
/**
- * omap34xx_isp_isr - Interrupt Service Routine for Camera ISP module.
+ * isp_isr - Interrupt Service Routine for Camera ISP module.
* @irq: Not used currently.
- * @ispirq_disp: Pointer to the object that is passed while request_irq is
- * called. This is the isp_obj.irq object containing info on the
- * callback.
+ * @_pdev: Pointer to the platform device associated with the OMAP3 ISP.
*
* Handles the corresponding callback if plugged in.
*
* Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
* IRQ wasn't handled.
**/
-static irqreturn_t omap34xx_isp_isr(int irq, void *_isp)
+static irqreturn_t isp_isr(int irq, void *_pdev)
{
- struct isp *isp = _isp;
+ struct device *dev = &((struct platform_device *)_pdev)->dev;
+ struct isp_device *isp = dev_get_drvdata(dev);
struct isp_irq *irqdis = &isp->irq;
struct isp_bufs *bufs = &isp->bufs;
+ struct isp_buf *buf;
unsigned long flags;
u32 irqstatus = 0;
- unsigned long irqflags = 0;
+ u32 sbl_pcr;
int wait_hs_vs = 0;
+ int ret;
- irqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
- isp_reg_writel(irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+ if ((isp->running == ISP_STOPPED) &&
+ !irqdis->isp_callbk[CBK_RESZ_DONE])
+ return IRQ_NONE;
- spin_lock_irqsave(&bufs->lock, flags);
+ irqstatus = isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+ isp_reg_writel(dev, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+
+ /* Handle first LSC states */
+ if ((irqstatus & LSC_DONE) || (irqstatus & LSC_DONE) ||
+ (irqstatus & CCDC_VD1))
+ ispccdc_lsc_state_handler(&isp->isp_ccdc, irqstatus);
+
+ if ((isp->running == ISP_STOPPING) &&
+ !(irqdis->isp_callbk[CBK_RESZ_DONE] &&
+ (irqstatus & RESZ_DONE)))
+ goto out_stopping_isp;
+
+ spin_lock_irqsave(&isp->lock, flags);
wait_hs_vs = bufs->wait_hs_vs;
- if (irqstatus & HS_VS && bufs->wait_hs_vs)
+ if (irqstatus & CCDC_VD0 && bufs->wait_hs_vs)
bufs->wait_hs_vs--;
- spin_unlock_irqrestore(&bufs->lock, flags);
-
- spin_lock_irqsave(&isp_obj.lock, irqflags);
/*
* We need to wait for the first HS_VS interrupt from CCDC.
* Otherwise our frame (and everything else) might be bad.
*/
- if (wait_hs_vs)
- goto out_ignore_buff;
+ switch (wait_hs_vs) {
+ case 1:
+ /*
+ * Enable preview for the first time. We just have
+ * missed the start-of-frame so we can do it now.
+ */
+ if (irqstatus & CCDC_VD0) {
+ /*
+ * For some reason resizer is always busy after boot up
+ * do not check resizer busy now.
+ */
+ if ((isp->pipeline.modules & OMAP_ISP_RESIZER) &&
+ (isp->pipeline.rsz_in == RSZ_OTFLY_YUV) &&
+ !(isp_reg_readl(dev, OMAP3_ISP_IOMEM_RESZ,
+ ISPRSZ_PCR) & (ISPRSZ_PCR_ENABLE |
+ ISPRSZ_PCR_BUSY))) {
+ ispresizer_config_shadow_registers(
+ &isp->isp_res);
+ ispresizer_enable(&isp->isp_res, 1);
+ }
+ if (((isp)->pipeline.modules & OMAP_ISP_PREVIEW) &&
+ !(isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_PCR) & (ISPPRV_PCR_BUSY |
+ ISPPRV_PCR_EN))) {
+ isppreview_config_shadow_registers(
+ &isp->isp_prev);
+ isppreview_enable(&isp->isp_prev, 1);
+ }
+ }
+ default:
+ /*
+ * For some sensors (like stingray), after a _restart_
+ * from sw standby state, starting couple of frames
+ * are erroneous. From stingray datasheet:
+ * "When sensor restarts, Normal image can get 2 frames after"
+ *
+ * So while we wait for HS_VS, check cnd clear the CSIA and
+ * CSIB error interrupts, if any
+ */
+ if (irqstatus & CSIA)
+ isp_csi2_isr(&isp->isp_csi2);
- if (irqstatus & CCDC_VD0) {
- if (RAW_CAPTURE(&isp_obj))
- isp_buf_process(bufs);
- if (!ispccdc_busy())
- ispccdc_config_shadow_registers();
+ if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
+ u32 csib;
+
+ csib = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2,
+ ISPCSI1_LC01_IRQSTATUS);
+ isp_reg_writel(dev, csib, OMAP3_ISP_IOMEM_CCP2,
+ ISPCSI1_LC01_IRQSTATUS);
+ }
+
+ if (!(irqstatus & RESZ_DONE) || CCDC_PREV_RESZ_CAPTURE(isp))
+ goto out_ignore_buff;
+ case 0:
+ break;
}
- if (irqstatus & PREV_DONE) {
- if (irqdis->isp_callbk[CBK_PREV_DONE])
- irqdis->isp_callbk[CBK_PREV_DONE](
- PREV_DONE,
- irqdis->isp_callbk_arg1[CBK_PREV_DONE],
- irqdis->isp_callbk_arg2[CBK_PREV_DONE]);
- else if (!RAW_CAPTURE(&isp_obj) && !ispresizer_busy()) {
- if (isp_obj.module.applyCrop) {
- ispresizer_applycrop();
- if (!ispresizer_busy())
- isp_obj.module.applyCrop = 0;
- }
- if (!isppreview_busy()) {
- ispresizer_enable(1);
- if (isppreview_busy()) {
- /* FIXME: locking! */
- ISP_BUF_DONE(bufs)->vb_state =
- VIDEOBUF_ERROR;
- printk(KERN_ERR "%s: can't stop"
- " preview\n", __func__);
- }
- }
- if (!isppreview_busy())
- isppreview_config_shadow_registers();
- if (!isppreview_busy())
- isph3a_update_wb();
+ buf = ISP_BUF_DONE(bufs);
+
+ if (irqstatus & LSC_PRE_ERR) {
+ /* Mark buffer faulty. */
+ buf->vb_state = VIDEOBUF_ERROR;
+ dev_dbg(dev, "lsc prefetch error \n");
+ }
+
+ if (irqstatus & CSIA) {
+ int ret = isp_csi2_isr(&isp->isp_csi2);
+ if (ret)
+ buf->vb_state = VIDEOBUF_ERROR;
+ }
+
+ if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
+ static const u32 ISPCSI1_LC01_ERROR =
+ ISPCSI1_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
+ ISPCSI1_LC01_IRQSTATUS_LC0_CRC_IRQ |
+ ISPCSI1_LC01_IRQSTATUS_LC0_FSP_IRQ |
+ ISPCSI1_LC01_IRQSTATUS_LC0_FW_IRQ |
+ ISPCSI1_LC01_IRQSTATUS_LC0_FSC_IRQ |
+ ISPCSI1_LC01_IRQSTATUS_LC0_SSC_IRQ;
+ u32 ispcsi1_irqstatus;
+
+ ispcsi1_irqstatus = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2,
+ ISPCSI1_LC01_IRQSTATUS);
+ isp_reg_writel(dev, ispcsi1_irqstatus, OMAP3_ISP_IOMEM_CCP2,
+ ISPCSI1_LC01_IRQSTATUS);
+ if (ispcsi1_irqstatus & ISPCSI1_LC01_ERROR) {
+ buf->vb_state = VIDEOBUF_ERROR;
+ dev_dbg(dev, "CCP2 err:%x\n", ispcsi1_irqstatus);
}
}
@@ -949,59 +994,143 @@
RESZ_DONE,
irqdis->isp_callbk_arg1[CBK_RESZ_DONE],
irqdis->isp_callbk_arg2[CBK_RESZ_DONE]);
- else if (!RAW_CAPTURE(&isp_obj)) {
- if (!ispresizer_busy())
- ispresizer_config_shadow_registers();
- isp_buf_process(bufs);
+ else if (CCDC_PREV_RESZ_CAPTURE(isp)) {
+ isp_buf_process(dev, bufs);
}
}
- if (irqstatus & H3A_AWB_DONE) {
- if (irqdis->isp_callbk[CBK_H3A_AWB_DONE])
- irqdis->isp_callbk[CBK_H3A_AWB_DONE](
- H3A_AWB_DONE,
- irqdis->isp_callbk_arg1[CBK_H3A_AWB_DONE],
- irqdis->isp_callbk_arg2[CBK_H3A_AWB_DONE]);
+ if (irqstatus & CCDC_VD1) {
+ ispccdc_config_shadow_registers(&isp->isp_ccdc);
+ /*
+ * If CCDC is writing to memory stop CCDC here
+ * preventig to write to any of our buffers.
+ */
+ if (CCDC_CAPTURE(isp))
+ ispccdc_enable(&isp->isp_ccdc, 0);
}
- if (irqstatus & HIST_DONE) {
- if (irqdis->isp_callbk[CBK_HIST_DONE])
- irqdis->isp_callbk[CBK_HIST_DONE](
- HIST_DONE,
- irqdis->isp_callbk_arg1[CBK_HIST_DONE],
- irqdis->isp_callbk_arg2[CBK_HIST_DONE]);
+ if (irqstatus & CCDC_VD0) {
+ if (CCDC_CAPTURE(isp))
+ isp_buf_process(dev, bufs);
+
+ /* Enabling configured statistic modules */
+ if (!(irqstatus & H3A_AWB_DONE))
+ isph3a_aewb_try_enable(&isp->isp_h3a);
+ if (!(irqstatus & H3A_AF_DONE))
+ isp_af_try_enable(&isp->isp_af);
+ if (!(irqstatus & HIST_DONE))
+ isp_hist_try_enable(&isp->isp_hist);
+ }
+
+ if (irqstatus & PREV_DONE) {
+ if (irqdis->isp_callbk[CBK_PREV_DONE])
+ irqdis->isp_callbk[CBK_PREV_DONE](
+ PREV_DONE,
+ irqdis->isp_callbk_arg1[CBK_PREV_DONE],
+ irqdis->isp_callbk_arg2[CBK_PREV_DONE]);
+ else {
+ if (CCDC_PREV_RESZ_CAPTURE(isp)) {
+ if (ispresizer_busy(&isp->isp_res)) {
+ buf->vb_state = VIDEOBUF_ERROR;
+ dev_dbg(dev, "resizer busy.\n");
+ } else if (!ISP_BUFS_IS_EMPTY(bufs)) {
+ ispresizer_config_shadow_registers(
+ &isp->isp_res);
+ ispresizer_enable(&isp->isp_res, 1);
+ }
+ }
+ if (!ISP_BUFS_IS_EMPTY(bufs)) {
+ isppreview_config_shadow_registers(
+ &isp->isp_prev);
+ isppreview_enable(&isp->isp_prev, 1);
+ }
+ if (CCDC_PREV_CAPTURE(isp))
+ isp_buf_process(dev, bufs);
+ }
+ }
+
+ /*
+ * Handle shared buffer logic overflows for video buffers.
+ * ISPSBL_PCR_CCDCPRV_2_RSZ_OVF can be safely ignored.
+ */
+ sbl_pcr = isp_reg_readl(dev, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR) &
+ ~ISPSBL_PCR_CCDCPRV_2_RSZ_OVF;
+ isp_reg_writel(dev, sbl_pcr, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR);
+ if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF
+ | ISPSBL_PCR_RSZ2_WBL_OVF
+ | ISPSBL_PCR_RSZ3_WBL_OVF
+ | ISPSBL_PCR_RSZ4_WBL_OVF
+ | ISPSBL_PCR_PRV_WBL_OVF
+ | ISPSBL_PCR_CCDC_WBL_OVF
+ | ISPSBL_PCR_CSIA_WBL_OVF
+ | ISPSBL_PCR_CSIB_WBL_OVF)) {
+ buf->vb_state = VIDEOBUF_ERROR;
+ isp->isp_af.buf_err = 1;
+ isp->isp_h3a.buf_err = 1;
+ isp_hist_mark_invalid_buf(&isp->isp_hist);
+ dev_dbg(dev, "sbl overflow, sbl_pcr = %8.8x\n", sbl_pcr);
+ }
+
+ if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF) {
+ dev_dbg(dev, "af: sbl overflow detected.\n");
+ isp->isp_af.buf_err = 1;
+ }
+
+ if (sbl_pcr & ISPSBL_PCR_H3A_AEAWB_WBL_OVF) {
+ dev_dbg(dev, "h3a: sbl overflow detected.\n");
+ isp->isp_h3a.buf_err = 1;
+ }
+
+ if (irqstatus & H3A_AWB_DONE) {
+ isph3a_aewb_enable(&isp->isp_h3a, 0);
+ /* If it's busy we can't process this buffer anymore */
+ if (!isph3a_aewb_busy(&isp->isp_h3a)) {
+ ret = isph3a_aewb_buf_process(&isp->isp_h3a);
+ isph3a_aewb_config_registers(&isp->isp_h3a);
+ } else {
+ ret = -1;
+ dev_dbg(dev, "h3a: cannot process buffer, device is "
+ "busy.\n");
+ }
+ if (ret)
+ irqstatus &= ~H3A_AWB_DONE;
+ isph3a_aewb_enable(&isp->isp_h3a, 1);
}
if (irqstatus & H3A_AF_DONE) {
- if (irqdis->isp_callbk[CBK_H3A_AF_DONE])
- irqdis->isp_callbk[CBK_H3A_AF_DONE](
- H3A_AF_DONE,
- irqdis->isp_callbk_arg1[CBK_H3A_AF_DONE],
- irqdis->isp_callbk_arg2[CBK_H3A_AF_DONE]);
+ isp_af_enable(&isp->isp_af, 0);
+ /* If it's busy we can't process this buffer anymore */
+ if (!isp_af_busy(&isp->isp_af)) {
+ ret = isp_af_buf_process(&isp->isp_af);
+ isp_af_config_registers(&isp->isp_af);
+ } else {
+ ret = -1;
+ dev_dbg(dev, "af: cannot process buffer, device is "
+ "busy.\n");
+ }
+ if (ret)
+ irqstatus &= ~H3A_AF_DONE;
+ isp_af_enable(&isp->isp_af, 1);
}
-
-out_ignore_buff:
- if (irqstatus & LSC_PRE_ERR) {
- struct isp_buf *buf = ISP_BUF_DONE(bufs);
- /* Mark buffer faulty. */
- buf->vb_state = VIDEOBUF_ERROR;
- ispccdc_lsc_error_handler();
- printk(KERN_ERR "%s: lsc prefetch error\n", __func__);
- }
-
- if (irqstatus & CSIA) {
- struct isp_buf *buf = ISP_BUF_DONE(bufs);
- isp_csi2_isr();
- buf->vb_state = VIDEOBUF_ERROR;
- }
-
- if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
- u32 ispcsi1_irqstatus;
-
- ispcsi1_irqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_CCP2,
- ISPCSI1_LC01_IRQSTATUS);
- DPRINTK_ISPCTRL("%x\n", ispcsi1_irqstatus);
+ if (irqstatus & HIST_DONE) {
+ isp_hist_enable(&isp->isp_hist, 0);
+ /* If it's busy we can't process this buffer anymore */
+ if (!isp_hist_busy(&isp->isp_hist)) {
+ ret = isp_hist_buf_process(&isp->isp_hist);
+ isp_hist_config_registers(&isp->isp_hist);
+ } else {
+ dev_dbg(dev, "hist: cannot process buffer, device is "
+ "busy.\n");
+ /* current and next buffer might have invalid data */
+ isp_hist_mark_invalid_buf(&isp->isp_hist);
+ irqstatus &= ~HIST_DONE;
+ ret = HIST_NO_BUF;
+ }
+ if (ret != HIST_BUF_WAITING_DMA)
+ isp_hist_enable(&isp->isp_hist, 1);
+ if (ret != HIST_BUF_DONE)
+ irqstatus &= ~HIST_DONE;
}
if (irqdis->isp_callbk[CBK_CATCHALL]) {
@@ -1011,7 +1140,14 @@
irqdis->isp_callbk_arg2[CBK_CATCHALL]);
}
- spin_unlock_irqrestore(&isp_obj.lock, irqflags);
+out_ignore_buff:
+ spin_unlock_irqrestore(&isp->lock, flags);
+
+ if (irqstatus & LSC_PRE_COMP)
+ ispccdc_lsc_pref_comp_handler(&isp->isp_ccdc);
+
+out_stopping_isp:
+ isp_flush(dev);
#if 1
{
@@ -1074,55 +1210,68 @@
};
/**
- * isp_tmp_buf_free - To free allocated 10MB memory
- *
+ * isp_tmp_buf_free - Free buffer for CCDC->PRV->RSZ datapath workaround.
+ * @dev: Device pointer specific to the OMAP3 ISP.
**/
-static void isp_tmp_buf_free(void)
+static void isp_tmp_buf_free(struct device *dev)
{
- if (isp_obj.tmp_buf) {
- ispmmu_vfree(isp_obj.tmp_buf);
- isp_obj.tmp_buf = 0;
- isp_obj.tmp_buf_size = 0;
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ if (isp->tmp_buf) {
+ iommu_vfree(isp->iommu, isp->tmp_buf);
+ isp->tmp_buf = 0;
+ isp->tmp_buf_size = 0;
+ isp->tmp_buf_offset = 0;
}
}
/**
- * isp_tmp_buf_alloc - To allocate a 10MB memory
+ * isp_tmp_buf_alloc - Allocate buffer for CCDC->PRV->RSZ datapath workaround.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @size: Byte size of the buffer to allocate
*
+ * Returns 0 if successful, or -ENOMEM if there's no available memory.
**/
-static u32 isp_tmp_buf_alloc(size_t size)
+static u32 isp_tmp_buf_alloc(struct device *dev, struct isp_pipeline *pipe)
{
- isp_tmp_buf_free();
+ struct isp_device *isp = dev_get_drvdata(dev);
+ u32 da;
+ size_t size = PAGE_ALIGN(isp->pipeline.prv_out_w *
+ isp->pipeline.prv_out_h *
+ ISP_BYTES_PER_PIXEL);
- printk(KERN_INFO "%s: allocating %d bytes\n", __func__, size);
+ ispresizer_config_inlineoffset(&isp->isp_res,
+ pipe->prv_out_w * ISP_BYTES_PER_PIXEL);
- isp_obj.tmp_buf = ispmmu_vmalloc(size);
- if (IS_ERR((void *)isp_obj.tmp_buf)) {
- printk(KERN_ERR "ispmmu_vmap mapping failed ");
+ if (isp->tmp_buf_size >= size)
+ return 0;
+
+ isp_tmp_buf_free(dev);
+
+ da = iommu_vmalloc(isp->iommu, 0, size, IOMMU_FLAG);
+ if (IS_ERR_VALUE(da)) {
+ dev_err(dev, "iommu_vmap mapping failed\n");
return -ENOMEM;
}
- isp_obj.tmp_buf_size = size;
+ isp->tmp_buf = da;
+ isp->tmp_buf_size = size;
- isppreview_set_outaddr(isp_obj.tmp_buf);
- ispresizer_set_inaddr(isp_obj.tmp_buf);
+ isppreview_set_outaddr(&isp->isp_prev, isp->tmp_buf);
+ ispresizer_set_inaddr(&isp->isp_res, isp->tmp_buf, 0);
return 0;
}
/**
- * isp_start - Starts ISP submodule
- *
- * Start the needed isp components assuming these components
- * are configured correctly.
+ * isp_start - Set ISP in running state
+ * @dev: Device pointer specific to the OMAP3 ISP.
**/
-void isp_start(void)
+void isp_start(struct device *dev)
{
- if (isp_obj.module.isp_pipeline & OMAP_ISP_PREVIEW
- && is_isppreview_enabled())
- isppreview_enable(1);
+ struct isp_device *isp = dev_get_drvdata(dev);
- isph3a_notify(0);
- isp_af_notify(0);
+ isp->running = ISP_RUNNING;
+
return;
}
EXPORT_SYMBOL(isp_start);
@@ -1130,38 +1279,57 @@
#define ISP_STATISTICS_BUSY \
()
#define ISP_STOP_TIMEOUT msecs_to_jiffies(1000)
-static int __isp_disable_modules(int suspend)
+
+/**
+ * __isp_disable_modules - Disable ISP submodules with a timeout to be idle.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @suspend: If 0, disable modules; if 1, send modules to suspend state.
+ *
+ * Returns 0 if stop/suspend left in idle state all the submodules properly,
+ * or returns 1 if a general Reset is required to stop/suspend the submodules.
+ **/
+static int __isp_disable_modules(struct device *dev, int suspend)
{
+ struct isp_device *isp = dev_get_drvdata(dev);
unsigned long timeout = jiffies + ISP_STOP_TIMEOUT;
int reset = 0;
+ /* We need to disble the first LSC module */
+ timeout = jiffies + ISP_STOP_TIMEOUT;
+ while (ispccdc_lsc_delay_stop(&isp->isp_ccdc)) {
+ if (time_after(jiffies, timeout)) {
+ printk(KERN_ERR "%s: can't stop lsc "
+ "disabling lsc anyway. \n", __func__);
+ reset = 1;
+ break;
+ }
+ msleep(1);
+ }
+ /* We can disable lsc now */
+ ispccdc_enable_lsc(&isp->isp_ccdc, 0);
+
/*
- * We need to stop all the modules after CCDC first or they'll
+ * We need to stop all the modules after CCDC or they'll
* never stop since they may not get a full frame from CCDC.
*/
if (suspend) {
- isp_af_suspend();
- isph3a_aewb_suspend();
- isp_hist_suspend();
- isppreview_suspend();
- ispresizer_suspend();
+ isp_af_suspend(&isp->isp_af);
+ isph3a_aewb_suspend(&isp->isp_h3a);
+ isp_hist_suspend(&isp->isp_hist);
} else {
- isp_af_enable(0);
- isph3a_aewb_enable(0);
- isp_hist_enable(0);
- isppreview_enable(0);
- ispresizer_enable(0);
+ isp_af_enable(&isp->isp_af, 0);
+ isph3a_aewb_enable(&isp->isp_h3a, 0);
+ isp_hist_enable(&isp->isp_hist, 0);
}
timeout = jiffies + ISP_STOP_TIMEOUT;
- while (isp_af_busy()
- || isph3a_aewb_busy()
- || isp_hist_busy()
- || isppreview_busy()
- || ispresizer_busy()) {
+ while (isp_af_busy(&isp->isp_af)
+ || isph3a_aewb_busy(&isp->isp_h3a)
+ || isp_hist_busy(&isp->isp_hist)
+ || isppreview_busy(&isp->isp_prev)
+ || ispresizer_busy(&isp->isp_res)) {
if (time_after(jiffies, timeout)) {
- printk(KERN_ERR "%s: can't stop non-ccdc modules\n",
- __func__);
+ dev_info(dev, "can't stop non-ccdc modules.\n");
reset = 1;
break;
}
@@ -1169,57 +1337,92 @@
}
/* Let's stop CCDC now. */
- if (suspend)
- /* This function supends lsc too */
- ispccdc_suspend();
- else {
- ispccdc_enable_lsc(0);
- ispccdc_enable(0);
- }
+ ispccdc_enable(&isp->isp_ccdc, 0);
timeout = jiffies + ISP_STOP_TIMEOUT;
- while (ispccdc_busy()) {
+ while (ispccdc_busy(&isp->isp_ccdc)) {
if (time_after(jiffies, timeout)) {
- printk(KERN_ERR "%s: can't stop ccdc\n", __func__);
+ dev_info(dev, "can't stop ccdc module.\n");
reset = 1;
break;
}
msleep(1);
}
+ if (!reset) {
+ DPRINTK_ISPCTRL(KERN_INFO
+ "(%s) isp_complete_reset \n", __func__);
+ isp_complete_reset = 1;
+ }
+
+ isp_csi_enable(dev, 0);
+ isp_csi2_enable(&isp->isp_csi2, 0);
+ isp_buf_init(dev);
+
return reset;
}
-static int isp_stop_modules(void)
+/**
+ * isp_stop_modules - Stop ISP submodules.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ *
+ * Returns 0 if stop left in idle state all the submodules properly,
+ * or returns 1 if a general Reset is required to stop the submodules.
+ **/
+static int isp_stop_modules(struct device *dev)
{
- return __isp_disable_modules(0);
+ return __isp_disable_modules(dev, 0);
}
-static int isp_suspend_modules(void)
+/**
+ * isp_suspend_modules - Suspend ISP submodules.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ *
+ * Returns 0 if suspend left in idle state all the submodules properly,
+ * or returns 1 if a general Reset is required to suspend the submodules.
+ **/
+static int isp_suspend_modules(struct device *dev)
{
- return __isp_disable_modules(1);
+ return __isp_disable_modules(dev, 1);
}
-static void isp_resume_modules(void)
+/**
+ * isp_resume_modules - Resume ISP submodules.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+static void isp_resume_modules(struct device *dev)
{
- ispresizer_resume();
- isppreview_resume();
- isp_hist_resume();
- isph3a_aewb_resume();
- isp_af_resume();
- ispccdc_resume();
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ isp_hist_resume(&isp->isp_hist);
+ isph3a_aewb_resume(&isp->isp_h3a);
+ isp_af_resume(&isp->isp_af);
+
+ if (isp->running == ISP_RUNNING) {
+ ispccdc_enable(&isp->isp_ccdc, 1);
+ ispresizer_enable(&isp->isp_res, 1);
+ isppreview_enable(&isp->isp_prev, 1);
+ isp_csi_enable(dev, 1);
+ isp_csi2_enable(&isp->isp_csi2, 1);
+ }
}
-static void isp_reset(void)
+/**
+ * isp_reset - Reset ISP with a timeout wait for idle.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+static void isp_reset(struct device *dev)
{
unsigned long timeout = 0;
- isp_reg_writel(isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG)
+ isp_reg_writel(dev,
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG)
| ISP_SYSCONFIG_SOFTRESET,
OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
- while (!(isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_SYSSTATUS) & 0x1)) {
+ while (!(isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_SYSSTATUS) & 0x1)) {
if (timeout++ > 10000) {
- printk(KERN_ALERT "%s: cannot reset ISP\n", __func__);
+ dev_alert(dev, "cannot reset ISP\n");
break;
}
udelay(1);
@@ -1227,130 +1430,322 @@
}
/**
- * isp_stop - Stops isp submodules
+ * isp_stop - Stop ISP.
+ * @dev: Device pointer specific to the OMAP3 ISP.
**/
-void isp_stop()
+void isp_stop(struct device *dev)
{
+ struct isp_device *isp = dev_get_drvdata(dev);
int reset;
- isph3a_notify(1);
- isp_af_notify(1);
- isp_disable_interrupts();
- reset = isp_stop_modules();
- isp_buf_init();
+ isp->running = ISP_STOPPING;
+ isp_disable_interrupts(dev);
+ synchronize_irq(((struct isp_device *)dev_get_drvdata(dev))->irq_num);
+ reset = isp_stop_modules(dev);
+ isp->running = ISP_STOPPED;
if (!reset)
return;
- isp_save_ctx();
- isp_reset();
- isp_restore_ctx();
+ isp_save_ctx(dev);
+ isp_reset(dev);
+ isp_restore_ctx(dev);
}
EXPORT_SYMBOL(isp_stop);
-static void isp_set_buf(struct isp_buf *buf)
+/**
+ * isp_set_buf - Program output buffer address based on current pipeline.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @buf: Pointer to ISP buffer structure.
+ **/
+static void isp_set_buf(struct device *dev, struct isp_buf *buf)
{
- if (isp_obj.module.isp_pipeline & OMAP_ISP_RESIZER
- && is_ispresizer_enabled())
- ispresizer_set_outaddr(buf->isp_addr);
- else if (isp_obj.module.isp_pipeline & OMAP_ISP_CCDC)
- ispccdc_set_outaddr(buf->isp_addr);
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ if (CCDC_PREV_RESZ_CAPTURE(isp))
+ ispresizer_set_outaddr(&isp->isp_res, buf->isp_addr);
+ else if (CCDC_PREV_CAPTURE(isp))
+ isppreview_set_outaddr(&isp->isp_prev, buf->isp_addr);
+ else if (CCDC_CAPTURE(isp))
+ ispccdc_set_outaddr(&isp->isp_ccdc, buf->isp_addr);
}
/**
- * isp_calc_pipeline - Sets pipeline depending of input and output pixel format
- * @pix_input: Pointer to V4L2 pixel format structure for input image.
- * @pix_output: Pointer to V4L2 pixel format structure for output image.
+ * isp_try_pipeline - Retrieve and simulate resulting internal ISP pipeline.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @pix_input: Pointer to pixel format to use as input in the ISP.
+ * @pipe: Pointer to ISP pipeline structure to fill back.
+ *
+ * Returns the closest possible output size based on silicon limitations
+ * detailed through the pipe structure.
+ *
+ * If the input can't be read, it'll return -EINVAL. Returns 0 on success.
**/
-static u32 isp_calc_pipeline(struct v4l2_pix_format *pix_input,
- struct v4l2_pix_format *pix_output)
+static int isp_try_pipeline(struct device *dev,
+ struct v4l2_pix_format *pix_input,
+ struct isp_pipeline *pipe)
{
- isp_release_resources();
- if ((pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10
- || pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8)
- && pix_output->pixelformat != V4L2_PIX_FMT_SGRBG10) {
- isp_obj.module.isp_pipeline =
- OMAP_ISP_CCDC | OMAP_ISP_PREVIEW | OMAP_ISP_RESIZER;
- ispccdc_request();
- isppreview_request();
- ispresizer_request();
- ispccdc_config_datapath(CCDC_RAW, CCDC_OTHERS_VP);
- isppreview_config_datapath(PRV_RAW_CCDC, PREVIEW_MEM);
- ispresizer_config_datapath(RSZ_MEM_YUV);
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct v4l2_pix_format *pix_output = &pipe->pix;
+ unsigned int wanted_width = pix_output->width;
+ unsigned int wanted_height = pix_output->height;
+ int ifmt;
+ int rval;
+
+ if ((pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10 ||
+ pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8 ||
+ pix_input->pixelformat == V4L2_PIX_FMT_SRGGB10 ||
+ pix_input->pixelformat == V4L2_PIX_FMT_SBGGR10 ||
+ pix_input->pixelformat == V4L2_PIX_FMT_SGBRG10) &&
+ (pix_output->pixelformat == V4L2_PIX_FMT_YUYV ||
+ pix_output->pixelformat == V4L2_PIX_FMT_UYVY)) {
+ if (pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10 ||
+ pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8)
+ pipe->ccdc_in = CCDC_RAW_GRBG;
+ if (pix_input->pixelformat == V4L2_PIX_FMT_SRGGB10)
+ pipe->ccdc_in = CCDC_RAW_RGGB;
+ if (pix_input->pixelformat == V4L2_PIX_FMT_SBGGR10)
+ pipe->ccdc_in = CCDC_RAW_BGGR;
+ if (pix_input->pixelformat == V4L2_PIX_FMT_SGBRG10)
+ pipe->ccdc_in = CCDC_RAW_GBRG;
+ pipe->ccdc_out = CCDC_OTHERS_VP;
+ pipe->prv_in = PRV_RAW_CCDC;
+ if ((pix_output->width == 1280) &&
+ (pix_output->height == 720)) {
+ pipe->modules = OMAP_ISP_PREVIEW |
+ OMAP_ISP_CCDC;
+ pipe->prv_out = PREVIEW_MEM;
+ } else {
+ pipe->modules = OMAP_ISP_PREVIEW |
+ OMAP_ISP_RESIZER |
+ OMAP_ISP_CCDC;
+ if (isp->revision <= ISP_REVISION_2_0) {
+ pipe->prv_out = PREVIEW_MEM;
+ pipe->rsz_in = RSZ_MEM_YUV;
+ } else {
+ pipe->prv_out = PREVIEW_RSZ;
+ pipe->rsz_in = RSZ_OTFLY_YUV;
+ }
+ }
} else {
- isp_obj.module.isp_pipeline = OMAP_ISP_CCDC;
- ispccdc_request();
- if (pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10
- || pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8)
- ispccdc_config_datapath(CCDC_RAW, CCDC_OTHERS_VP_MEM);
- else
- ispccdc_config_datapath(CCDC_YUV_SYNC,
- CCDC_OTHERS_MEM);
+ pipe->modules = OMAP_ISP_CCDC;
+ if (pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10 ||
+ pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8 ||
+ pix_input->pixelformat == V4L2_PIX_FMT_SRGGB10 ||
+ pix_input->pixelformat == V4L2_PIX_FMT_SBGGR10 ||
+ pix_input->pixelformat == V4L2_PIX_FMT_SGBRG10) {
+ pipe->ccdc_out = CCDC_OTHERS_VP_MEM;
+ if (pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10 ||
+ pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8)
+ pipe->ccdc_in = CCDC_RAW_GRBG;
+ if (pix_input->pixelformat == V4L2_PIX_FMT_SRGGB10)
+ pipe->ccdc_in = CCDC_RAW_RGGB;
+ if (pix_input->pixelformat == V4L2_PIX_FMT_SBGGR10)
+ pipe->ccdc_in = CCDC_RAW_BGGR;
+ if (pix_input->pixelformat == V4L2_PIX_FMT_SGBRG10)
+ pipe->ccdc_in = CCDC_RAW_GBRG;
+ } else if (pix_input->pixelformat == V4L2_PIX_FMT_YUYV ||
+ pix_input->pixelformat == V4L2_PIX_FMT_UYVY) {
+ pipe->ccdc_in = CCDC_YUV_SYNC;
+ pipe->ccdc_out = CCDC_OTHERS_MEM;
+ } else
+ return -EINVAL;
}
+
+ if (pipe->modules & OMAP_ISP_CCDC) {
+ pipe->ccdc_in_w = pix_input->width;
+ pipe->ccdc_in_h = pix_input->height;
+ rval = ispccdc_try_pipeline(&isp->isp_ccdc, pipe);
+ if (rval) {
+ dev_dbg(dev, "the dimensions %dx%d are not"
+ " supported\n", pix_input->width,
+ pix_input->height);
+ return rval;
+ }
+ pix_output->width = pipe->ccdc_out_w_img;
+ pix_output->height = pipe->ccdc_out_h;
+ pix_output->bytesperline =
+ pipe->ccdc_out_w * ISP_BYTES_PER_PIXEL;
+ }
+
+ if (pipe->modules & OMAP_ISP_PREVIEW) {
+ pipe->prv_out_w = wanted_width;
+ pipe->prv_out_h = wanted_height;
+ rval = isppreview_try_pipeline(&isp->isp_prev, pipe);
+ if (rval) {
+ dev_dbg(dev, "the dimensions %dx%d are not"
+ " supported\n", pix_input->width,
+ pix_input->height);
+ return rval;
+ }
+ pix_output->width = pipe->prv_out_w;
+ pix_output->height = pipe->prv_out_h;
+ pix_output->bytesperline =
+ pipe->prv_out_w * ISP_BYTES_PER_PIXEL;
+ }
+
+ if (pipe->modules & OMAP_ISP_RESIZER) {
+ pipe->rsz_out_w = wanted_width;
+ pipe->rsz_out_h = wanted_height;
+
+ pipe->rsz_crop.left = pipe->rsz_crop.top = 0;
+ pipe->rsz_crop.width = pipe->prv_out_w_img;
+ pipe->rsz_crop.height = pipe->prv_out_h_img;
+
+ rval = ispresizer_try_pipeline(&isp->isp_res, pipe);
+ if (rval) {
+ dev_dbg(dev, "The dimensions %dx%d are not"
+ " supported\n", pix_input->width,
+ pix_input->height);
+ return rval;
+ }
+
+ pix_output->width = pipe->rsz_out_w;
+ pix_output->height = pipe->rsz_out_h;
+ pix_output->bytesperline =
+ pipe->rsz_out_w * ISP_BYTES_PER_PIXEL;
+ }
+
+ pix_output->field = V4L2_FIELD_NONE;
+ pix_output->sizeimage =
+ PAGE_ALIGN(pix_output->bytesperline * pix_output->height);
+ pix_output->priv = 0;
+
+ for (ifmt = 0; ifmt < NUM_ISP_CAPTURE_FORMATS; ifmt++) {
+ if (pix_output->pixelformat == isp_formats[ifmt].pixelformat)
+ break;
+ }
+ if (ifmt == NUM_ISP_CAPTURE_FORMATS)
+ pix_output->pixelformat = V4L2_PIX_FMT_YUYV;
+
+ switch (pix_output->pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ pix_output->colorspace = V4L2_COLORSPACE_JPEG;
+ break;
+ default:
+ pix_output->colorspace = V4L2_COLORSPACE_SRGB;
+ }
+
return 0;
}
/**
- * isp_config_pipeline - Configures the image size and ycpos for ISP submodules
- * @pix_input: Pointer to V4L2 pixel format structure for input image.
- * @pix_output: Pointer to V4L2 pixel format structure for output image.
+ * isp_s_pipeline - Configure internal ISP pipeline.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @pix_input: Pointer to pixel format to use as input in the ISP.
+ * @pix_output: Pointer to pixel format to use as output in the ISP.
*
- * The configuration of ycpos depends on the output pixel format for both the
- * Preview and Resizer submodules.
+ * Returns the closest possible output size based on silicon limitations.
+ *
+ * If the input can't be read, it'll return -EINVAL. Returns 0 on success.
**/
-static void isp_config_pipeline(struct v4l2_pix_format *pix_input,
- struct v4l2_pix_format *pix_output)
+static int isp_s_pipeline(struct device *dev,
+ struct v4l2_pix_format *pix_input,
+ struct v4l2_pix_format *pix_output)
{
- ispccdc_config_size(isp_obj.module.ccdc_input_width,
- isp_obj.module.ccdc_input_height,
- isp_obj.module.ccdc_output_width,
- isp_obj.module.ccdc_output_height);
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_pipeline pipe;
+ int rval;
- if (isp_obj.module.isp_pipeline & OMAP_ISP_PREVIEW) {
- isppreview_config_size(isp_obj.module.preview_input_width,
- isp_obj.module.preview_input_height,
- isp_obj.module.preview_output_width,
- isp_obj.module.preview_output_height);
+ isp_release_resources(dev);
+
+ pipe.pix = *pix_output;
+
+ rval = isp_try_pipeline(dev, pix_input, &pipe);
+ if (rval)
+ return rval;
+
+ ispccdc_request(&isp->isp_ccdc);
+ ispccdc_s_pipeline(&isp->isp_ccdc, &pipe);
+
+ if (pipe.modules & OMAP_ISP_PREVIEW) {
+ isppreview_request(&isp->isp_prev);
+ isppreview_s_pipeline(&isp->isp_prev, &pipe);
}
- if (isp_obj.module.isp_pipeline & OMAP_ISP_RESIZER) {
- ispresizer_config_size(isp_obj.module.resizer_input_width,
- isp_obj.module.resizer_input_height,
- isp_obj.module.resizer_output_width,
- isp_obj.module.resizer_output_height);
+ if (pipe.modules & OMAP_ISP_RESIZER) {
+ ispresizer_request(&isp->isp_res);
+ ispresizer_s_pipeline(&isp->isp_res, &pipe);
}
- if (pix_output->pixelformat == V4L2_PIX_FMT_UYVY) {
- isppreview_config_ycpos(YCPOS_YCrYCb);
- if (is_ispresizer_enabled())
- ispresizer_config_ycpos(0);
- } else {
- isppreview_config_ycpos(YCPOS_CrYCbY);
- if (is_ispresizer_enabled())
- ispresizer_config_ycpos(1);
- }
+ isp->pipeline = pipe;
+ *pix_output = isp->pipeline.pix;
- return;
+ return 0;
}
-void isp_set_hs_vs(int hs_vs)
+void isp_set_hs_vs(struct device *dev, int hs_vs)
{
- struct isp_bufs *bufs = &isp_obj.bufs;
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_bufs *bufs = &isp->bufs;
bufs->wait_hs_vs = hs_vs;
return;
}
EXPORT_SYMBOL(isp_set_hs_vs);
-static void isp_buf_init(void)
+/**
+ * isp_vbq_sync - keep the video buffers coherent between cpu and isp
+ *
+ * The typical operation required here is Cache Invalidation across
+ * the (user space) buffer address range. And this _must_ be done
+ * at QBUF stage (and *only* at QBUF).
+ *
+ * We try to use optimal cache invalidation function:
+ * - dmac_inv_range:
+ * - used when the number of pages are _low_.
+ * - it becomes quite slow as the number of pages increase.
+ * - for 648x492 viewfinder (150 pages) it takes 1.3 ms.
+ * - for 5 Mpix buffer (2491 pages) it takes between 25-50 ms.
+ *
+ * - flush_cache_all:
+ * - used when the number of pages are _high_.
+ * - time taken in the range of 500-900 us.
+ * - has a higher penalty but, as whole dcache + icache is invalidated
+ **/
+/**
+ * FIXME: dmac_inv_range crashes randomly on the user space buffer
+ * address. Fall back to flush_cache_all for now.
+ */
+#define ISP_CACHE_FLUSH_PAGES_MAX 0
+
+static int isp_vbq_sync(struct videobuf_buffer *vb)
{
- struct isp_bufs *bufs = &isp_obj.bufs;
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ if (!vb->baddr || !dma || !dma->nr_pages ||
+ dma->nr_pages > ISP_CACHE_FLUSH_PAGES_MAX)
+ flush_cache_all();
+ else {
+ dmac_inv_range((void *)vb->baddr,
+ (void *)vb->baddr + vb->bsize);
+ outer_inv_range(vb->baddr, vb->baddr + vb->bsize);
+ }
+
+ return 0;
+}
+
+/**
+ * isp_buf_init - Initialize the internal buffer queue handling.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+static void isp_buf_init(struct device *dev)
+{
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_bufs *bufs = &isp->bufs;
int sg;
+ isp_complete_reset = 1;
bufs->queue = 0;
bufs->done = 0;
- bufs->wait_hs_vs = isp_obj.config->wait_hs_vs;
+ bufs->wait_hs_vs = isp->config->wait_hs_vs;
for (sg = 0; sg < NUM_BUFS; sg++) {
+ if (bufs->buf[sg].vb) {
+ bufs->buf[sg].vb->state = VIDEOBUF_ERROR;
+ bufs->buf[sg].complete(bufs->buf[sg].vb,
+ bufs->buf[sg].priv);
+ }
bufs->buf[sg].complete = NULL;
bufs->buf[sg].vb = NULL;
bufs->buf[sg].priv = NULL;
@@ -1358,31 +1753,27 @@
}
/**
- * isp_vbq_sync - Walks the pages table and flushes the cache for
- * each page.
+ * isp_buf_process - Do final handling when a buffer has been processed.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @bufs: Pointer to ISP buffer handling structure.
+ *
+ * Updates the pointers accordingly depending of the internal pipeline.
**/
-static int isp_vbq_sync(struct videobuf_buffer *vb, int when)
+static void isp_buf_process(struct device *dev, struct isp_bufs *bufs)
{
- flush_cache_all();
-
- return 0;
-}
-
-static int isp_buf_process(struct isp_bufs *bufs)
-{
- struct isp_buf *buf = NULL;
- unsigned long flags;
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_buf *buf;
int last;
- spin_lock_irqsave(&bufs->lock, flags);
-
if (ISP_BUFS_IS_EMPTY(bufs))
- goto out;
+ return;
- if (RAW_CAPTURE(&isp_obj) && ispccdc_sbl_wait_idle(1000)) {
- printk(KERN_ERR "ccdc %d won't become idle!\n",
- RAW_CAPTURE(&isp_obj));
- goto out;
+ if (CCDC_CAPTURE(isp)) {
+ if (ispccdc_sbl_wait_idle(&isp->isp_ccdc, 1000)) {
+ ispccdc_enable(&isp->isp_ccdc, 1);
+ dev_info(dev, "ccdc won't become idle!\n");
+ return;
+ }
}
/* We had at least one buffer in queue. */
@@ -1391,42 +1782,12 @@
if (!last) {
/* Set new buffer address. */
- isp_set_buf(ISP_BUF_NEXT_DONE(bufs));
+ isp_set_buf(dev, ISP_BUF_NEXT_DONE(bufs));
+ if (CCDC_CAPTURE(isp))
+ ispccdc_enable(&isp->isp_ccdc, 1);
} else {
/* Tell ISP not to write any of our buffers. */
- isp_disable_interrupts();
- if (RAW_CAPTURE(&isp_obj))
- ispccdc_enable(0);
- else
- ispresizer_enable(0);
- /*
- * We must wait for the HS_VS since before that the
- * CCDC may trigger interrupts even if it's not
- * receiving a frame.
- */
- bufs->wait_hs_vs = isp_obj.config->wait_hs_vs;
- }
- if ((RAW_CAPTURE(&isp_obj) && ispccdc_busy())
- || (!RAW_CAPTURE(&isp_obj) && ispresizer_busy())) {
- /*
- * Next buffer available: for the transfer to succeed, the
- * CCDC (RAW capture) or resizer (YUV capture) must be idle
- * for the duration of transfer setup. Bad things happen
- * otherwise!
- *
- * Next buffer not available: if we fail to stop the
- * ISP the buffer is probably going to be bad.
- */
- /* Mark this buffer faulty. */
- buf->vb_state = VIDEOBUF_ERROR;
- /* Mark next faulty, too, in case we have one. */
- if (!last) {
- ISP_BUF_NEXT_DONE(bufs)->vb_state =
- VIDEOBUF_ERROR;
- printk(KERN_ALERT "OUCH!!!\n");
- } else {
- printk(KERN_ALERT "Ouch!\n");
- }
+ isp_disable_interrupts(dev);
}
/* Mark the current buffer as done. */
@@ -1437,38 +1798,48 @@
(bufs->buf+((bufs->done - 1 + NUM_BUFS)
% NUM_BUFS))->isp_addr);
-out:
- spin_unlock_irqrestore(&bufs->lock, flags);
-
- if (buf != NULL) {
- /*
- * We want to dequeue a buffer from the video buffer
- * queue. Let's do it!
- */
- isp_vbq_sync(buf->vb, DMA_FROM_DEVICE);
- buf->vb->state = buf->vb_state;
- buf->complete(buf->vb, buf->priv);
- }
-
- return 0;
+ /*
+ * We want to dequeue a buffer from the video buffer
+ * queue. Let's do it!
+ */
+ buf->vb->state = buf->vb_state;
+ buf->complete(buf->vb, buf->priv);
+ buf->vb = NULL;
}
-int isp_buf_queue(struct videobuf_buffer *vb,
+/**
+ * isp_buf_queue - Queue a buffer into the internal ISP queue list.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @vb: Pointer to video buffer to queue.
+ * @complete: Pointer to function to call when buffer is completely processed.
+ * @priv: Pointer to private paramemter to send to complete function.
+ *
+ * Always returns 0.
+ **/
+int isp_buf_queue(struct device *dev, struct videobuf_buffer *vb,
void (*complete)(struct videobuf_buffer *vb, void *priv),
void *priv)
{
+ struct isp_device *isp = dev_get_drvdata(dev);
unsigned long flags;
struct isp_buf *buf;
struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
const struct scatterlist *sglist = dma->sglist;
- struct isp_bufs *bufs = &isp_obj.bufs;
+ struct isp_bufs *bufs = &isp->bufs;
int sglen = dma->sglen;
+ if (isp->running != ISP_RUNNING) {
+ vb->state = VIDEOBUF_ERROR;
+ complete(vb, priv);
+
+ return 0;
+ }
+
BUG_ON(sglen < 0 || !sglist);
- isp_vbq_sync(vb, DMA_TO_DEVICE);
+ isp_vbq_sync(vb);
- spin_lock_irqsave(&bufs->lock, flags);
+ spin_lock_irqsave(&isp->lock, flags);
BUG_ON(ISP_BUFS_IS_FULL(bufs));
@@ -1479,17 +1850,26 @@
buf->vb = vb;
buf->priv = priv;
buf->vb_state = VIDEOBUF_DONE;
+ buf->vb->state = VIDEOBUF_ACTIVE;
if (ISP_BUFS_IS_EMPTY(bufs)) {
- isp_enable_interrupts(RAW_CAPTURE(&isp_obj));
- isp_set_buf(buf);
- ispccdc_enable(1);
- isp_start();
+ /*
+ * We must wait for the HS_VS since before that the
+ * CCDC may trigger interrupts even if it's not
+ * receiving a frame.
+ */
+ bufs->wait_hs_vs++;
+ isp_enable_interrupts(dev);
+ isp_set_buf(dev, buf);
+ isp_af_try_enable(&isp->isp_af);
+ isph3a_aewb_try_enable(&isp->isp_h3a);
+ isp_hist_try_enable(&isp->isp_hist);
+ ispccdc_enable(&isp->isp_ccdc, 1);
}
ISP_BUF_MARK_QUEUED(bufs);
- spin_unlock_irqrestore(&bufs->lock, flags);
+ spin_unlock_irqrestore(&isp->lock, flags);
DPRINTK_ISPCTRL(KERN_ALERT "%s: queue %d vb %d, mmu %p\n", __func__,
(bufs->queue - 1 + NUM_BUFS) % NUM_BUFS, vb->i,
@@ -1499,24 +1879,98 @@
}
EXPORT_SYMBOL(isp_buf_queue);
-int isp_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
- unsigned int *size)
+/**
+ * isp_vbq_setup - Do ISP specific actions when the VB wueue is set.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @vbq: Pointer to video buffer queue.
+ * @cnt: Pointer to buffer count size of the queue list.
+ * @size: Pointer to the bytesize of every video buffer queue entry.
+ *
+ * Currently, this just allocates the temporary buffer used for the
+ * ISP Workaround when having CCDC->PRV->RSZ internal datapath.
+ **/
+int isp_vbq_setup(struct device *dev, struct videobuf_queue *vbq,
+ unsigned int *cnt, unsigned int *size)
{
- int rval = 0;
- size_t tmp_size = PAGE_ALIGN(isp_obj.module.preview_output_width
- * isp_obj.module.preview_output_height
- * ISP_BYTES_PER_PIXEL);
+ struct isp_device *isp = dev_get_drvdata(dev);
- if (isp_obj.module.isp_pipeline & OMAP_ISP_PREVIEW
- && isp_obj.tmp_buf_size < tmp_size)
- rval = isp_tmp_buf_alloc(tmp_size);
+ if (CCDC_PREV_RESZ_CAPTURE(isp) &&
+ isp->revision <= ISP_REVISION_2_0)
+ return isp_tmp_buf_alloc(dev, &isp->pipeline);
- return rval;
+ return 0;
}
EXPORT_SYMBOL(isp_vbq_setup);
/**
+ * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @sglist: Pointer to source Scatter gather list to allocate.
+ * @sglen: Number of elements of the scatter-gatter list.
+ *
+ * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if
+ * we ran out of memory.
+ **/
+dma_addr_t ispmmu_vmap(struct device *dev, const struct scatterlist *sglist,
+ int sglen)
+{
+ struct isp_device *isp = dev_get_drvdata(dev);
+ int err;
+ u32 da;
+ struct sg_table *sgt;
+ unsigned int i;
+ struct scatterlist *sg, *src = (struct scatterlist *)sglist;
+
+ /*
+ * convert isp sglist to iommu sgt
+ * FIXME: should be fixed in the upper layer?
+ */
+ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
+ if (!sgt)
+ return -ENOMEM;
+ err = sg_alloc_table(sgt, sglen, GFP_KERNEL);
+ if (err)
+ goto err_sg_alloc;
+
+ for_each_sg(sgt->sgl, sg, sgt->nents, i)
+ sg_set_buf(sg, phys_to_virt(sg_dma_address(src + i)),
+ sg_dma_len(src + i));
+
+ da = iommu_vmap(isp->iommu, 0, sgt, IOMMU_FLAG);
+ if (IS_ERR_VALUE(da))
+ goto err_vmap;
+
+ return (dma_addr_t)da;
+
+err_vmap:
+ sg_free_table(sgt);
+err_sg_alloc:
+ kfree(sgt);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(ispmmu_vmap);
+
+/**
+ * ispmmu_vunmap - Unmap a device address from the ISP MMU
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @da: Device address generated from a ispmmu_vmap call.
+ **/
+void ispmmu_vunmap(struct device *dev, dma_addr_t da)
+{
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct sg_table *sgt;
+
+ sgt = iommu_vunmap(isp->iommu, (u32)da);
+ if (!sgt)
+ return;
+ sg_free_table(sgt);
+ kfree(sgt);
+}
+EXPORT_SYMBOL_GPL(ispmmu_vunmap);
+
+/**
* isp_vbq_prepare - Videobuffer queue prepare.
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @vbq: Pointer to videobuf_queue structure.
* @vb: Pointer to videobuf_buffer structure.
* @field: Requested Field order for the videobuffer.
@@ -1524,18 +1978,19 @@
* Returns 0 if successful, or -EIO if the ispmmu was unable to map a
* scatter-gather linked list data space.
**/
-int isp_vbq_prepare(struct videobuf_queue *vbq, struct videobuf_buffer *vb,
- enum v4l2_field field)
+int isp_vbq_prepare(struct device *dev, struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb, enum v4l2_field field)
{
+ struct isp_device *isp = dev_get_drvdata(dev);
unsigned int isp_addr;
struct videobuf_dmabuf *vdma;
- struct isp_bufs *bufs = &isp_obj.bufs;
+ struct isp_bufs *bufs = &isp->bufs;
int err = 0;
vdma = videobuf_to_dma(vb);
- isp_addr = ispmmu_vmap(vdma->sglist, vdma->sglen);
+ isp_addr = ispmmu_vmap(dev, vdma->sglist, vdma->sglen);
if (IS_ERR_VALUE(isp_addr))
err = -EIO;
@@ -1548,14 +2003,17 @@
/**
* isp_vbq_release - Videobuffer queue release.
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @vbq: Pointer to videobuf_queue structure.
* @vb: Pointer to videobuf_buffer structure.
**/
-void isp_vbq_release(struct videobuf_queue *vbq, struct videobuf_buffer *vb)
+void isp_vbq_release(struct device *dev, struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb)
{
- struct isp_bufs *bufs = &isp_obj.bufs;
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_bufs *bufs = &isp->bufs;
- ispmmu_vunmap(bufs->isp_addr_capture[vb->i]);
+ ispmmu_vunmap(dev, bufs->isp_addr_capture[vb->i]);
bufs->isp_addr_capture[vb->i] = (dma_addr_t)NULL;
return;
}
@@ -1607,30 +2065,32 @@
EXPORT_SYMBOL(isp_querymenu);
/**
- * isp_g_ctrl - Gets value of the desired V4L2 control.
+ * isp_g_ctrl - Get value of the desired V4L2 control.
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @a: V4L2 control to read actual value from.
*
* Return 0 if successful, or -EINVAL if chosen control is not found.
**/
-int isp_g_ctrl(struct v4l2_control *a)
+int isp_g_ctrl(struct device *dev, struct v4l2_control *a)
{
+ struct isp_device *isp = dev_get_drvdata(dev);
u8 current_value;
int rval = 0;
- if (!isp_obj.ref_count)
+ if (!isp->ref_count)
return -EINVAL;
switch (a->id) {
case V4L2_CID_BRIGHTNESS:
- isppreview_query_brightness(¤t_value);
+ isppreview_query_brightness(&isp->isp_prev, ¤t_value);
a->value = current_value / ISPPRV_BRIGHT_UNITS;
break;
case V4L2_CID_CONTRAST:
- isppreview_query_contrast(¤t_value);
+ isppreview_query_contrast(&isp->isp_prev, ¤t_value);
a->value = current_value / ISPPRV_CONTRAST_UNITS;
break;
case V4L2_CID_COLORFX:
- isppreview_get_color(¤t_value);
+ isppreview_get_color(&isp->isp_prev, ¤t_value);
a->value = current_value;
break;
default:
@@ -1643,7 +2103,8 @@
EXPORT_SYMBOL(isp_g_ctrl);
/**
- * isp_s_ctrl - Sets value of the desired V4L2 control.
+ * isp_s_ctrl - Set value of the desired V4L2 control.
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @a: V4L2 control to read actual value from.
*
* Return 0 if successful, -EINVAL if chosen control is not found or value
@@ -1651,32 +2112,34 @@
* from camera abstraction layer related controls or the transfered user space
* pointer via the value field is not set properly.
**/
-int isp_s_ctrl(struct v4l2_control *a)
+int isp_s_ctrl(struct device *dev, struct v4l2_control *a)
{
+ struct isp_device *isp = dev_get_drvdata(dev);
int rval = 0;
u8 new_value = a->value;
- if (!isp_obj.ref_count)
+ if (!isp->ref_count)
return -EINVAL;
switch (a->id) {
case V4L2_CID_BRIGHTNESS:
- if (new_value > ISPPRV_BRIGHT_HIGH)
+ if (a->value > ISPPRV_BRIGHT_HIGH)
rval = -EINVAL;
else
- isppreview_update_brightness(&new_value);
+ isppreview_update_brightness(&isp->isp_prev,
+ &new_value);
break;
case V4L2_CID_CONTRAST:
- if (new_value > ISPPRV_CONTRAST_HIGH)
+ if (a->value > ISPPRV_CONTRAST_HIGH)
rval = -EINVAL;
else
- isppreview_update_contrast(&new_value);
+ isppreview_update_contrast(&isp->isp_prev, &new_value);
break;
case V4L2_CID_COLORFX:
- if (new_value > V4L2_COLORFX_SEPIA)
+ if (a->value > V4L2_COLORFX_SEPIA)
rval = -EINVAL;
else
- isppreview_set_color(&new_value);
+ isppreview_set_color(&isp->isp_prev, &new_value);
break;
default:
rval = -EINVAL;
@@ -1689,6 +2152,7 @@
/**
* isp_handle_private - Handle all private ioctls for isp module.
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @cmd: ioctl cmd value
* @arg: ioctl arg value
*
@@ -1697,54 +2161,68 @@
* Function simply routes the input ioctl cmd id to the appropriate handler in
* the isp module.
**/
-int isp_handle_private(int cmd, void *arg)
+int isp_handle_private(struct device *dev, struct mutex *vdev_mutex, int cmd,
+ void *arg)
{
+ struct isp_device *isp = dev_get_drvdata(dev);
int rval = 0;
- if (!isp_obj.ref_count)
+ if (!isp->ref_count)
return -EINVAL;
switch (cmd) {
case VIDIOC_PRIVATE_ISP_CCDC_CFG:
- rval = omap34xx_isp_ccdc_config(arg);
+ mutex_lock(vdev_mutex);
+ rval = ispccdc_config(&isp->isp_ccdc, arg);
+ mutex_unlock(vdev_mutex);
break;
case VIDIOC_PRIVATE_ISP_PRV_CFG:
- rval = omap34xx_isp_preview_config(arg);
+ mutex_lock(vdev_mutex);
+ rval = isppreview_config(&isp->isp_prev, arg);
+ mutex_unlock(vdev_mutex);
break;
case VIDIOC_PRIVATE_ISP_AEWB_CFG: {
struct isph3a_aewb_config *params;
params = (struct isph3a_aewb_config *)arg;
- rval = isph3a_aewb_configure(params);
+ mutex_lock(vdev_mutex);
+ rval = isph3a_aewb_config(&isp->isp_h3a, params);
+ mutex_unlock(vdev_mutex);
}
break;
case VIDIOC_PRIVATE_ISP_AEWB_REQ: {
struct isph3a_aewb_data *data;
data = (struct isph3a_aewb_data *)arg;
- rval = isph3a_aewb_request_statistics(data);
+ rval = isph3a_aewb_request_statistics(&isp->isp_h3a, data);
}
break;
case VIDIOC_PRIVATE_ISP_HIST_CFG: {
struct isp_hist_config *params;
params = (struct isp_hist_config *)arg;
- rval = isp_hist_configure(params);
+ mutex_lock(vdev_mutex);
+ rval = isp_hist_config(&isp->isp_hist, params);
+ mutex_unlock(vdev_mutex);
}
break;
case VIDIOC_PRIVATE_ISP_HIST_REQ: {
struct isp_hist_data *data;
data = (struct isp_hist_data *)arg;
- rval = isp_hist_request_statistics(data);
+ mutex_lock(vdev_mutex);
+ rval = isp_hist_request_statistics(&isp->isp_hist, data);
+ mutex_unlock(vdev_mutex);
}
break;
case VIDIOC_PRIVATE_ISP_AF_CFG: {
struct af_configuration *params;
params = (struct af_configuration *)arg;
- rval = isp_af_configure(params);
+ mutex_lock(vdev_mutex);
+ rval = isp_af_config(&isp->isp_af, params);
+ mutex_unlock(vdev_mutex);
}
break;
case VIDIOC_PRIVATE_ISP_AF_REQ: {
struct isp_af_data *data;
data = (struct isp_af_data *)arg;
- rval = isp_af_request_statistics(data);
+ rval = isp_af_request_statistics(&isp->isp_af, data);
}
break;
default:
@@ -1756,7 +2234,7 @@
EXPORT_SYMBOL(isp_handle_private);
/**
- * isp_enum_fmt_cap - Gets more information of chosen format index and type
+ * isp_enum_fmt_cap - Get more information of chosen format index and type
* @f: Pointer to structure containing index and type of format to read from.
*
* Returns 0 if successful, or -EINVAL if format index or format type is
@@ -1793,452 +2271,298 @@
EXPORT_SYMBOL(isp_enum_fmt_cap);
/**
- * isp_g_fmt_cap - Gets current output image format.
- * @f: Pointer to V4L2 format structure to be filled with current output format
+ * isp_g_fmt_cap - Get current output image format.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @pix: Pointer to V4L2 format structure to return current output format
**/
-void isp_g_fmt_cap(struct v4l2_pix_format *pix)
+void isp_g_fmt_cap(struct device *dev, struct v4l2_pix_format *pix)
{
- *pix = isp_obj.module.pix;
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ *pix = isp->pipeline.pix;
return;
}
EXPORT_SYMBOL(isp_g_fmt_cap);
/**
- * isp_s_fmt_cap - Sets I/O formats and crop and configures pipeline in ISP
- * @f: Pointer to V4L2 format structure to be filled with current output format
+ * isp_s_fmt_cap - Set I/O formats and crop, and configure pipeline in ISP
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @pix_input: Pointer to V4L2 format structure to represent current input.
+ * @pix_output: Pointer to V4L2 format structure to represent current output.
*
- * Returns 0 if successful, or return value of either isp_try_size or
- * isp_try_fmt if there is an error.
+ * Returns 0 if successful, -EINVAL if ISP hasn't been opened, or return
+ * value of isp_s_pipeline if there is an error.
**/
-int isp_s_fmt_cap(struct v4l2_pix_format *pix_input,
+int isp_s_fmt_cap(struct device *dev, struct v4l2_pix_format *pix_input,
struct v4l2_pix_format *pix_output)
{
- int crop_scaling_w = 0, crop_scaling_h = 0;
- int rval = 0;
+ struct isp_device *isp = dev_get_drvdata(dev);
- if (!isp_obj.ref_count)
+
+ if (!isp->ref_count)
return -EINVAL;
- rval = isp_calc_pipeline(pix_input, pix_output);
- if (rval)
- goto out;
-
- rval = isp_try_size(pix_input, pix_output);
- if (rval)
- goto out;
-
- rval = isp_try_fmt(pix_input, pix_output);
- if (rval)
- goto out;
-
- if (ispcroprect.width != pix_output->width) {
- crop_scaling_w = 1;
- ispcroprect.left = 0;
- ispcroprect.width = pix_output->width;
- }
-
- if (ispcroprect.height != pix_output->height) {
- crop_scaling_h = 1;
- ispcroprect.top = 0;
- ispcroprect.height = pix_output->height;
- }
-
- isp_config_pipeline(pix_input, pix_output);
-
- if (isp_obj.module.isp_pipeline & OMAP_ISP_RESIZER
- && (crop_scaling_h || crop_scaling_w))
- isp_config_crop(pix_output);
-
-out:
- return rval;
+ return isp_s_pipeline(dev, pix_input, pix_output);
}
EXPORT_SYMBOL(isp_s_fmt_cap);
/**
- * isp_config_crop - Configures crop parameters in isp resizer.
- * @croppix: Pointer to V4L2 pixel format structure containing crop parameters
+ * isp_get_buf_offset - Gets offset of start of crop.
+ *
+ * Returns the offset (in bytes) of the start of the crop rectangle.
**/
-void isp_config_crop(struct v4l2_pix_format *croppix)
+unsigned long isp_get_buf_offset(struct device *dev)
{
- u8 crop_scaling_w;
- u8 crop_scaling_h;
- unsigned long org_left, num_pix, new_top;
+ struct isp_device *isp = dev_get_drvdata(dev);
- struct v4l2_pix_format *pix = croppix;
-
- crop_scaling_w = (isp_obj.module.preview_output_width * 10) /
- pix->width;
- crop_scaling_h = (isp_obj.module.preview_output_height * 10) /
- pix->height;
-
- cur_rect.left = (ispcroprect.left * crop_scaling_w) / 10;
- cur_rect.top = (ispcroprect.top * crop_scaling_h) / 10;
- cur_rect.width = (ispcroprect.width * crop_scaling_w) / 10;
- cur_rect.height = (ispcroprect.height * crop_scaling_h) / 10;
-
- org_left = cur_rect.left;
- while (((int)cur_rect.left & 0xFFFFFFF0) != (int)cur_rect.left)
- (int)cur_rect.left--;
-
- num_pix = org_left - cur_rect.left;
- new_top = (int)(num_pix * 3) / 4;
- cur_rect.top = cur_rect.top - new_top;
- cur_rect.height = (2 * new_top) + cur_rect.height;
-
- cur_rect.width = cur_rect.width + (2 * num_pix);
- while (((int)cur_rect.width & 0xFFFFFFF0) != (int)cur_rect.width)
- (int)cur_rect.width--;
-
- isp_obj.tmp_buf_offset =
- cur_rect.left * 2 +
- isp_obj.module.preview_output_width * 2 * cur_rect.top;
-
- ispresizer_trycrop(cur_rect.left, cur_rect.top, cur_rect.width,
- cur_rect.height,
- isp_obj.module.resizer_output_width,
- isp_obj.module.resizer_output_height);
-
- return;
+ return isp->tmp_buf_offset;
}
-EXPORT_SYMBOL(isp_config_crop);
+EXPORT_SYMBOL(isp_get_buf_offset);
/**
- * isp_g_crop - Gets crop rectangle size and position.
- * @a: Pointer to V4L2 crop structure to be filled.
+ * isp_g_crop - Get crop rectangle size and position.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @crop: Pointer to V4L2 crop structure to be filled.
*
* Always returns 0.
**/
-int isp_g_crop(struct v4l2_crop *a)
+int isp_g_crop(struct device *dev, struct v4l2_crop *crop)
{
- struct v4l2_crop *crop = a;
+ struct isp_device *isp = dev_get_drvdata(dev);
- crop->c = ispcroprect;
+ if (isp->pipeline.modules & OMAP_ISP_RESIZER) {
+ crop->c = isp->pipeline.rsz_crop;
+ } else {
+ crop->c.left = 0;
+ crop->c.top = 0;
+ crop->c.width = isp->pipeline.ccdc_out_w_img;
+ crop->c.height = isp->pipeline.ccdc_out_h;
+ }
return 0;
}
EXPORT_SYMBOL(isp_g_crop);
/**
- * isp_s_crop - Sets crop rectangle size and position and queues crop operation
+ * isp_s_crop - Set crop rectangle size and position.
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @a: Pointer to V4L2 crop structure with desired parameters.
- * @pix: Pointer to V4L2 pixel format structure with desired parameters.
*
- * Returns 0 if successful, or -EINVAL if crop parameters are out of bounds.
+ * Always returns 0.
+ *
+ * FIXME: Hardcoded to configure always the resizer, which could not be always
+ * the case.
**/
-int isp_s_crop(struct v4l2_crop *a, struct v4l2_pix_format *pix)
+int isp_s_crop(struct device *dev, struct v4l2_crop *a)
{
- struct v4l2_crop *crop = a;
- int rval = 0;
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_pipeline *pipe = &isp->pipeline;
- if (!isp_obj.ref_count)
- return -EINVAL;
+ /*
+ * Reset resizer output size.
+ * FIXME: resizer should not touch the output size in the first place,
+ * it should always correspond to the size set by S_FMT or S_FMT
+ * should fail if not possible. If necessary, resizer should adjust
+ * the source rectangle in ispresizer_try_pipeline instead.
+ * When the resizer is fixed, its output size does not need to be
+ * adjusted anymore here.
+ */
+ pipe->rsz_out_w_img = pipe->pix.width;
+ pipe->rsz_out_w = pipe->pix.width;
+ pipe->rsz_out_h = pipe->pix.height;
- if (crop->c.left < 0)
- crop->c.left = 0;
- if (crop->c.width < 0)
- crop->c.width = 0;
- if (crop->c.top < 0)
- crop->c.top = 0;
- if (crop->c.height < 0)
- crop->c.height = 0;
+ ispresizer_config_crop(&isp->isp_res, a);
- if (crop->c.left >= pix->width)
- crop->c.left = pix->width - 1;
- if (crop->c.top >= pix->height)
- crop->c.top = pix->height - 1;
-
- if (crop->c.left + crop->c.width > pix->width)
- crop->c.width = pix->width - crop->c.left;
- if (crop->c.top + crop->c.height > pix->height)
- crop->c.height = pix->height - crop->c.top;
-
- ispcroprect.left = crop->c.left;
- ispcroprect.top = crop->c.top;
- ispcroprect.width = crop->c.width;
- ispcroprect.height = crop->c.height;
-
- isp_config_crop(pix);
-
- isp_obj.module.applyCrop = 1;
-
- return rval;
+ return 0;
}
EXPORT_SYMBOL(isp_s_crop);
/**
- * isp_try_fmt_cap - Tries desired input/output image formats
+ * isp_try_fmt_cap - Try desired input/output image formats
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @pix_input: Pointer to V4L2 pixel format structure for input image.
* @pix_output: Pointer to V4L2 pixel format structure for output image.
*
* Returns 0 if successful, or return value of either isp_try_size or
* isp_try_fmt if there is an error.
**/
-int isp_try_fmt_cap(struct v4l2_pix_format *pix_input,
+int isp_try_fmt_cap(struct device *dev, struct v4l2_pix_format *pix_input,
struct v4l2_pix_format *pix_output)
{
- int rval = 0;
+ struct isp_pipeline pipe;
+ int rval;
- rval = isp_calc_pipeline(pix_input, pix_output);
+ pipe.pix = *pix_output;
+
+ rval = isp_try_pipeline(dev, pix_input, &pipe);
if (rval)
- goto out;
+ return rval;
- rval = isp_try_size(pix_input, pix_output);
- if (rval)
- goto out;
+ *pix_output = pipe.pix;
- rval = isp_try_fmt(pix_input, pix_output);
- if (rval)
- goto out;
-
-out:
- return rval;
+ return 0;
}
EXPORT_SYMBOL(isp_try_fmt_cap);
/**
- * isp_try_size - Tries size configuration for I/O images of each ISP submodule
- * @pix_input: Pointer to V4L2 pixel format structure for input image.
- * @pix_output: Pointer to V4L2 pixel format structure for output image.
- *
- * Returns 0 if successful, or return value of ispccdc_try_size,
- * isppreview_try_size, or ispresizer_try_size (depending on the pipeline
- * configuration) if there is an error.
- **/
-static int isp_try_size(struct v4l2_pix_format *pix_input,
- struct v4l2_pix_format *pix_output)
-{
- int rval = 0;
-
- if (pix_output->width <= ISPRSZ_MIN_OUTPUT
- || pix_output->height <= ISPRSZ_MIN_OUTPUT)
- return -EINVAL;
-
- if (pix_output->width >= ISPRSZ_MAX_OUTPUT
- || pix_output->height > ISPRSZ_MAX_OUTPUT)
- return -EINVAL;
-
- isp_obj.module.ccdc_input_width = pix_input->width;
- isp_obj.module.ccdc_input_height = pix_input->height;
- isp_obj.module.resizer_output_width = pix_output->width;
- isp_obj.module.resizer_output_height = pix_output->height;
-
- if (isp_obj.module.isp_pipeline & OMAP_ISP_CCDC) {
- rval = ispccdc_try_size(isp_obj.module.ccdc_input_width,
- isp_obj.module.ccdc_input_height,
- &isp_obj.module.ccdc_output_width,
- &isp_obj.module.ccdc_output_height);
- if (rval) {
- printk(KERN_ERR "ISP_ERR: The dimensions %dx%d are not"
- " supported\n", pix_input->width,
- pix_input->height);
- return rval;
- }
- pix_output->width = isp_obj.module.ccdc_output_width;
- pix_output->height = isp_obj.module.ccdc_output_height;
- }
-
- if (isp_obj.module.isp_pipeline & OMAP_ISP_PREVIEW) {
- isp_obj.module.preview_input_width =
- isp_obj.module.ccdc_output_width;
- isp_obj.module.preview_input_height =
- isp_obj.module.ccdc_output_height;
- rval = isppreview_try_size(
- isp_obj.module.preview_input_width,
- isp_obj.module.preview_input_height,
- &isp_obj.module.preview_output_width,
- &isp_obj.module.preview_output_height);
- if (rval) {
- printk(KERN_ERR "ISP_ERR: The dimensions %dx%d are not"
- " supported\n", pix_input->width,
- pix_input->height);
- return rval;
- }
- pix_output->width = isp_obj.module.preview_output_width;
- pix_output->height = isp_obj.module.preview_output_height;
- }
-
- if (isp_obj.module.isp_pipeline & OMAP_ISP_RESIZER) {
- isp_obj.module.resizer_input_width =
- isp_obj.module.preview_output_width;
- isp_obj.module.resizer_input_height =
- isp_obj.module.preview_output_height;
- rval = ispresizer_try_size(
- &isp_obj.module.resizer_input_width,
- &isp_obj.module.resizer_input_height,
- &isp_obj.module.resizer_output_width,
- &isp_obj.module.resizer_output_height);
- if (rval) {
- printk(KERN_ERR "ISP_ERR: The dimensions %dx%d are not"
- " supported\n", pix_input->width,
- pix_input->height);
- return rval;
- }
- pix_output->width = isp_obj.module.resizer_output_width;
- pix_output->height = isp_obj.module.resizer_output_height;
- }
-
- return rval;
-}
-
-/**
- * isp_try_fmt - Validates input/output format parameters.
- * @pix_input: Pointer to V4L2 pixel format structure for input image.
- * @pix_output: Pointer to V4L2 pixel format structure for output image.
- *
- * Always returns 0.
- **/
-int isp_try_fmt(struct v4l2_pix_format *pix_input,
- struct v4l2_pix_format *pix_output)
-{
- int ifmt;
-
- for (ifmt = 0; ifmt < NUM_ISP_CAPTURE_FORMATS; ifmt++) {
- if (pix_output->pixelformat == isp_formats[ifmt].pixelformat)
- break;
- }
- if (ifmt == NUM_ISP_CAPTURE_FORMATS)
- ifmt = 1;
- pix_output->pixelformat = isp_formats[ifmt].pixelformat;
- pix_output->field = V4L2_FIELD_NONE;
- pix_output->bytesperline = pix_output->width * ISP_BYTES_PER_PIXEL;
- pix_output->sizeimage =
- PAGE_ALIGN(pix_output->bytesperline * pix_output->height);
- pix_output->priv = 0;
- switch (pix_output->pixelformat) {
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_UYVY:
- pix_output->colorspace = V4L2_COLORSPACE_JPEG;
- break;
- default:
- pix_output->colorspace = V4L2_COLORSPACE_SRGB;
- }
-
- isp_obj.module.pix.pixelformat = pix_output->pixelformat;
- isp_obj.module.pix.width = pix_output->width;
- isp_obj.module.pix.height = pix_output->height;
- isp_obj.module.pix.field = pix_output->field;
- isp_obj.module.pix.bytesperline = pix_output->bytesperline;
- isp_obj.module.pix.sizeimage = pix_output->sizeimage;
- isp_obj.module.pix.priv = pix_output->priv;
- isp_obj.module.pix.colorspace = pix_output->colorspace;
-
- return 0;
-}
-EXPORT_SYMBOL(isp_try_fmt);
-
-/**
* isp_save_ctx - Saves ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
+ * @dev: Device pointer specific to the OMAP3 ISP.
*
* Routine for saving the context of each module in the ISP.
* CCDC, HIST, H3A, PREV, RESZ and MMU.
**/
-static void isp_save_ctx(void)
+static void isp_save_ctx(struct device *dev)
{
- isp_save_context(isp_reg_list);
- ispccdc_save_context();
- ispmmu_save_context();
- isphist_save_context();
- isph3a_save_context();
- isppreview_save_context();
- ispresizer_save_context();
- ispcsi2_save_context();
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ isp_save_context(dev, isp_reg_list);
+ ispccdc_save_context(dev);
+ if (isp->iommu)
+ iommu_save_ctx(isp->iommu);
+ isp_hist_save_context(dev);
+ isph3a_save_context(dev);
+ isppreview_save_context(dev);
+ ispresizer_save_context(dev);
+ ispcsi2_save_context(dev);
}
/**
* isp_restore_ctx - Restores ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
+ * @dev: Device pointer specific to the OMAP3 ISP.
*
* Routine for restoring the context of each module in the ISP.
* CCDC, HIST, H3A, PREV, RESZ and MMU.
**/
-static void isp_restore_ctx(void)
+static void isp_restore_ctx(struct device *dev)
{
- isp_restore_context(isp_reg_list);
- ispccdc_restore_context();
- ispmmu_restore_context();
- isphist_restore_context();
- isph3a_restore_context();
- isppreview_restore_context();
- ispresizer_restore_context();
- ispcsi2_restore_context();
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ isp_restore_context(dev, isp_reg_list);
+ ispccdc_restore_context(dev);
+ if (isp->iommu)
+ iommu_restore_ctx(isp->iommu);
+ isp_hist_restore_context(dev);
+ isph3a_restore_context(dev);
+ isppreview_restore_context(dev);
+ ispresizer_restore_context(dev);
+ ispcsi2_restore_context(dev);
}
-static int isp_enable_clocks(void)
+/**
+ * isp_enable_clocks - Enable ISP clocks
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ *
+ * Return 0 if successful, or clk_enable return value if any of tthem fails.
+ **/
+static int isp_enable_clocks(struct device *dev)
{
+ struct isp_device *isp = dev_get_drvdata(dev);
int r;
- r = clk_enable(isp_obj.cam_ick);
+ r = clk_enable(isp->cam_ick);
if (r) {
- DPRINTK_ISPCTRL("ISP_ERR: clk_en for ick failed\n");
+ dev_err(dev, "clk_enable cam_ick failed\n");
goto out_clk_enable_ick;
}
- r = clk_enable(isp_obj.cam_mclk);
+ r = clk_enable(isp->csi2_fck);
if (r) {
- DPRINTK_ISPCTRL("ISP_ERR: clk_en for mclk failed\n");
- goto out_clk_enable_mclk;
- }
- r = clk_enable(isp_obj.csi2_fck);
- if (r) {
- DPRINTK_ISPCTRL("ISP_ERR: clk_en for csi2_fclk"
- " failed\n");
+ dev_err(dev, "clk_enable csi2_fck failed\n");
goto out_clk_enable_csi2_fclk;
}
return 0;
out_clk_enable_csi2_fclk:
- clk_disable(isp_obj.cam_mclk);
-out_clk_enable_mclk:
- clk_disable(isp_obj.cam_ick);
+ clk_disable(isp->cam_ick);
out_clk_enable_ick:
return r;
}
-static void isp_disable_clocks(void)
+int isp_enable_mclk(struct device *dev)
{
- clk_disable(isp_obj.cam_ick);
- clk_disable(isp_obj.cam_mclk);
- clk_disable(isp_obj.csi2_fck);
+ struct isp_device *isp = dev_get_drvdata(dev);
+ int r;
+ unsigned long curr_mclk, curr_dpll4_m5, ratio;
+
+ /* Check ratio between DPLL4_M5 and CAM_MCLK */
+ curr_mclk = clk_get_rate(isp->cam_mclk);
+ curr_dpll4_m5 = clk_get_rate(isp->dpll4_m5_ck);
+
+ /* Protection for potential Zero division, or zero-ratio result */
+ if (!curr_mclk || !curr_dpll4_m5)
+ BUG();
+
+ ratio = curr_mclk / curr_dpll4_m5;
+
+ r = clk_set_rate(isp->dpll4_m5_ck, isp->mclk / ratio);
+ if (r) {
+ dev_err(dev, "clk_set_rate for dpll4_m5_ck failed\n");
+ return r;
+ }
+ r = clk_enable(isp->cam_mclk);
+ if (r) {
+ dev_err(dev, "clk_enable cam_mclk failed\n");
+ return r;
+ }
+ return 0;
+}
+
+void isp_disable_mclk(struct isp_device *isp)
+{
+ clk_disable(isp->cam_mclk);
}
/**
- * isp_get - Adquires the ISP resource.
+ * isp_disable_clocks - Disable ISP clocks
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+static void isp_disable_clocks(struct device *dev)
+{
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ clk_disable(isp->cam_ick);
+ clk_disable(isp->csi2_fck);
+}
+
+/**
+ * isp_get - Acquire the ISP resource.
*
* Initializes the clocks for the first acquire.
+ *
+ * Returns pointer for isp device structure.
**/
-int isp_get(void)
+struct device *isp_get(void)
{
+ struct platform_device *pdev = omap3isp_pdev;
+ struct isp_device *isp;
static int has_context;
int ret_err = 0;
- if (omap3isp == NULL)
- return -EBUSY;
+ if (!pdev)
+ return NULL;
+ isp = platform_get_drvdata(pdev);
- DPRINTK_ISPCTRL("isp_get: old %d\n", isp_obj.ref_count);
- mutex_lock(&(isp_obj.isp_mutex));
- if (isp_obj.ref_count == 0) {
- ret_err = isp_enable_clocks();
+ DPRINTK_ISPCTRL("isp_get: old %d\n", isp->ref_count);
+ mutex_lock(&(isp->isp_mutex));
+ if (isp->ref_count == 0) {
+ ret_err = isp_enable_clocks(&pdev->dev);
if (ret_err)
goto out_err;
/* We don't want to restore context before saving it! */
if (has_context)
- isp_restore_ctx();
+ isp_restore_ctx(&pdev->dev);
else
has_context = 1;
- /* HACK: Allow multiple opens meanwhile a better solution is
- * found for the case of different devices sharing ISP
- * settings. */
-/* } else {
- mutex_unlock(&isp_obj.isp_mutex);
- return -EBUSY; */
}
- isp_obj.ref_count++;
- mutex_unlock(&(isp_obj.isp_mutex));
+ isp->ref_count++;
+ mutex_unlock(&(isp->isp_mutex));
- DPRINTK_ISPCTRL("isp_get: new %d\n", isp_obj.ref_count);
- return isp_obj.ref_count;
+ DPRINTK_ISPCTRL("isp_get: new %d\n", isp->ref_count);
+ /* FIXME: ISP should register as v4l2 device to store its priv data */
+ return &pdev->dev;
out_err:
- mutex_unlock(&(isp_obj.isp_mutex));
- return ret_err;
+ mutex_unlock(&(isp->isp_mutex));
+ return NULL;
}
EXPORT_SYMBOL(isp_get);
@@ -2246,83 +2570,97 @@
* isp_put - Releases the ISP resource.
*
* Releases the clocks also for the last release.
+ *
+ * Return resulting reference count, or -EBUSY if ISP structure is not
+ * allocated.
**/
int isp_put(void)
{
- if (omap3isp == NULL)
+ struct platform_device *pdev = omap3isp_pdev;
+ struct isp_device *isp = platform_get_drvdata(pdev);
+
+ if (!isp)
return -EBUSY;
- DPRINTK_ISPCTRL("isp_put: old %d\n", isp_obj.ref_count);
- mutex_lock(&(isp_obj.isp_mutex));
- if (isp_obj.ref_count) {
- if (--isp_obj.ref_count == 0) {
- isp_save_ctx();
- isp_tmp_buf_free();
- isp_release_resources();
- isp_obj.module.isp_pipeline = 0;
- isp_disable_clocks();
- memset(&ispcroprect, 0, sizeof(ispcroprect));
- memset(&cur_rect, 0, sizeof(cur_rect));
+ DPRINTK_ISPCTRL("isp_put: old %d\n", isp->ref_count);
+ mutex_lock(&(isp->isp_mutex));
+ if (isp->ref_count) {
+ if (--isp->ref_count == 0) {
+ isp_save_ctx(&pdev->dev);
+ if (isp->revision <= ISP_REVISION_2_0)
+ isp_tmp_buf_free(&pdev->dev);
+ isp_release_resources(&pdev->dev);
+ isp_disable_clocks(&pdev->dev);
}
}
- mutex_unlock(&(isp_obj.isp_mutex));
- DPRINTK_ISPCTRL("isp_put: new %d\n", isp_obj.ref_count);
- return isp_obj.ref_count;
+ mutex_unlock(&(isp->isp_mutex));
+ DPRINTK_ISPCTRL("isp_put: new %d\n", isp->ref_count);
+ return isp->ref_count;
}
EXPORT_SYMBOL(isp_put);
/**
* isp_save_context - Saves the values of the ISP module registers.
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @reg_list: Structure containing pairs of register address and value to
* modify on OMAP.
**/
-void isp_save_context(struct isp_reg *reg_list)
+void isp_save_context(struct device *dev, struct isp_reg *reg_list)
{
struct isp_reg *next = reg_list;
for (; next->reg != ISP_TOK_TERM; next++)
- next->val = isp_reg_readl(next->mmio_range, next->reg);
+ next->val = isp_reg_readl(dev, next->mmio_range, next->reg);
}
-EXPORT_SYMBOL(isp_save_context);
/**
* isp_restore_context - Restores the values of the ISP module registers.
+ * @dev: Device pointer specific to the OMAP3 ISP.
* @reg_list: Structure containing pairs of register address and value to
* modify on OMAP.
**/
-void isp_restore_context(struct isp_reg *reg_list)
+void isp_restore_context(struct device *dev, struct isp_reg *reg_list)
{
struct isp_reg *next = reg_list;
for (; next->reg != ISP_TOK_TERM; next++)
- isp_reg_writel(next->val, next->mmio_range, next->reg);
+ isp_reg_writel(dev, next->val, next->mmio_range, next->reg);
}
-EXPORT_SYMBOL(isp_restore_context);
+/**
+ * isp_remove - Remove ISP platform device
+ * @pdev: Pointer to ISP platform device
+ *
+ * Always returns 0.
+ **/
static int isp_remove(struct platform_device *pdev)
{
struct isp_device *isp = platform_get_drvdata(pdev);
int i;
- isp_csi2_cleanup();
- isp_af_exit();
- isp_resizer_cleanup();
- isp_preview_cleanup();
- ispmmu_cleanup();
- isph3a_aewb_cleanup();
- isp_hist_cleanup();
- isp_ccdc_cleanup();
-
if (!isp)
return 0;
- clk_put(isp_obj.cam_ick);
- clk_put(isp_obj.cam_mclk);
- clk_put(isp_obj.csi2_fck);
+ isp_csi2_cleanup(&pdev->dev);
+ isp_af_exit(&pdev->dev);
+ isp_resizer_cleanup(&pdev->dev);
+ isp_get();
+ if (isp->iommu)
+ iommu_put(isp->iommu);
+ isp_put();
+ isph3a_aewb_cleanup(&pdev->dev);
+ isp_hist_cleanup(&pdev->dev);
+ isp_ccdc_cleanup(&pdev->dev);
- free_irq(isp->irq, &isp_obj);
+ clk_put(isp->cam_ick);
+ clk_put(isp->cam_mclk);
+ clk_put(isp->dpll4_m5_ck);
+ clk_put(isp->csi2_fck);
+ clk_put(isp->l3_ick);
- for (i = 0; i <= OMAP3_ISP_IOMEM_CSI2PHY; i++) {
+ free_irq(isp->irq_num, isp);
+
+ for (i = 0; i <= OMAP3_ISP_IOMEM_CSI2PHY2; i++) {
if (isp->mmio_base[i]) {
iounmap((void *)isp->mmio_base[i]);
isp->mmio_base[i] = 0;
@@ -2335,8 +2673,7 @@
}
}
- omap3isp = NULL;
-
+ omap3isp_pdev = NULL;
kfree(isp);
return 0;
@@ -2344,50 +2681,68 @@
#ifdef CONFIG_PM
+/**
+ * isp_suspend - Suspend routine for the ISP
+ * @pdev: Pointer to Platform device
+ * @state: New power state
+ *
+ * Always returns 0.
+ **/
static int isp_suspend(struct platform_device *pdev, pm_message_t state)
{
+ struct isp_device *isp = platform_get_drvdata(pdev);
int reset;
- mutex_lock(&(isp_obj.isp_mutex));
DPRINTK_ISPCTRL("isp_suspend: starting\n");
- if (isp_obj.ref_count == 0)
+
+ WARN_ON(mutex_is_locked(&isp->isp_mutex));
+
+ if (isp->ref_count == 0)
goto out;
- isp_disable_interrupts();
- reset = isp_suspend_modules();
- isp_save_ctx();
+ isp_disable_interrupts(&pdev->dev);
+ reset = isp_suspend_modules(&pdev->dev);
+ isp_save_ctx(&pdev->dev);
if (reset)
- isp_reset();
+ isp_reset(&pdev->dev);
- isp_disable_clocks();
+ isp_disable_clocks(&pdev->dev);
+ isp_disable_mclk(isp);
out:
DPRINTK_ISPCTRL("isp_suspend: done\n");
- mutex_unlock(&(isp_obj.isp_mutex));
+
return 0;
}
+/**
+ * isp_resume - Resume routine for the ISP
+ * @pdev: Pointer to platform device
+ *
+ * Returns 0 if successful, or isp_enable_clocks return value otherwise.
+ **/
static int isp_resume(struct platform_device *pdev)
{
+ struct isp_device *isp = platform_get_drvdata(pdev);
int ret_err = 0;
DPRINTK_ISPCTRL("isp_resume: starting\n");
- if (omap3isp == NULL)
+ if (isp->ref_count == 0)
goto out;
- if (isp_obj.ref_count >= 0) {
- ret_err = isp_enable_clocks();
- if (ret_err)
- goto out;
- isp_restore_ctx();
- isp_resume_modules();
- isp_enable_interrupts(RAW_CAPTURE(&isp_obj));
- isp_start();
- }
+ ret_err = isp_enable_clocks(&pdev->dev);
+ if (ret_err)
+ goto out;
+ ret_err = isp_enable_mclk(&pdev->dev);
+ if (ret_err)
+ goto out;
+ isp_restore_ctx(&pdev->dev);
+ isp_resume_modules(&pdev->dev);
out:
DPRINTK_ISPCTRL("isp_resume: done \n");
+
return ret_err;
}
@@ -2398,7 +2753,19 @@
#endif /* CONFIG_PM */
+static u64 raw_dmamask = DMA_32BIT_MASK;
+/**
+ * isp_probe - Probe ISP platform device
+ * @pdev: Pointer to ISP platform device
+ *
+ * Returns 0 if successful,
+ * -ENOMEM if no memory available,
+ * -ENODEV if no platform device resources found
+ * or no space for remapping registers,
+ * -EINVAL if couldn't install ISR,
+ * or clk_get return error value.
+ **/
static int isp_probe(struct platform_device *pdev)
{
struct isp_device *isp;
@@ -2415,21 +2782,22 @@
isp->dev = &pdev->dev;
- for (i = 0; i <= OMAP3_ISP_IOMEM_CSI2PHY; i++) {
+ for (i = 0; i <= OMAP3_ISP_IOMEM_CSI2PHY2; i++) {
struct resource *mem;
/* request the mem region for the camera registers */
mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!mem) {
dev_err(isp->dev, "no mem resource?\n");
- return -ENODEV;
+ ret_err = -ENODEV;
+ goto out_free_mmio;
}
if (!request_mem_region(mem->start, mem->end - mem->start + 1,
pdev->name)) {
dev_err(isp->dev,
"cannot reserve camera register I/O region\n");
- return -ENODEV;
-
+ ret_err = -ENODEV;
+ goto out_free_mmio;
}
isp->mmio_base_phys[i] = mem->start;
isp->mmio_size[i] = mem->end - mem->start + 1;
@@ -2441,83 +2809,126 @@
if (!isp->mmio_base[i]) {
dev_err(isp->dev,
"cannot map camera register I/O region\n");
- return -ENODEV;
+ ret_err = -ENODEV;
+ goto out_free_mmio;
}
}
- isp->irq = platform_get_irq(pdev, 0);
- if (isp->irq <= 0) {
+ isp->irq_num = platform_get_irq(pdev, 0);
+ if (isp->irq_num <= 0) {
dev_err(isp->dev, "no irq for camera?\n");
- return -ENODEV;
+ ret_err = -ENODEV;
+ goto out_free_mmio;
}
- isp_obj.cam_ick = clk_get(&camera_dev, "cam_ick");
- if (IS_ERR(isp_obj.cam_ick)) {
- DPRINTK_ISPCTRL("ISP_ERR: clk_get for "
- "cam_ick failed\n");
- return PTR_ERR(isp_obj.cam_ick);
+ isp->mclk = CM_CAM_MCLK_HZ / 2;
+
+ isp->cam_ick = clk_get(&camera_dev, "cam_ick");
+ if (IS_ERR(isp->cam_ick)) {
+ dev_err(isp->dev, "clk_get cam_ick failed\n");
+ ret_err = PTR_ERR(isp->cam_ick);
+ goto out_free_mmio;
}
- isp_obj.cam_mclk = clk_get(&camera_dev, "cam_mclk");
- if (IS_ERR(isp_obj.cam_mclk)) {
- DPRINTK_ISPCTRL("ISP_ERR: clk_get for "
- "cam_mclk failed\n");
- ret_err = PTR_ERR(isp_obj.cam_mclk);
+ isp->cam_mclk = clk_get(&camera_dev, "cam_mclk");
+ if (IS_ERR(isp->cam_mclk)) {
+ dev_err(isp->dev, "clk_get cam_mclk failed\n");
+ ret_err = PTR_ERR(isp->cam_mclk);
goto out_clk_get_mclk;
}
- isp_obj.csi2_fck = clk_get(&camera_dev, "csi2_96m_fck");
- if (IS_ERR(isp_obj.csi2_fck)) {
- DPRINTK_ISPCTRL("ISP_ERR: clk_get for csi2_fclk"
- " failed\n");
- ret_err = PTR_ERR(isp_obj.csi2_fck);
+ isp->dpll4_m5_ck = clk_get(&camera_dev, "dpll4_m5_ck");
+ if (IS_ERR(isp->dpll4_m5_ck)) {
+ dev_err(isp->dev, "clk_get dpll4_m5_ck failed\n");
+ ret_err = PTR_ERR(isp->dpll4_m5_ck);
+ goto out_clk_get_dpll4_m5_ck;
+ }
+ isp->csi2_fck = clk_get(&camera_dev, "csi2_96m_fck");
+ if (IS_ERR(isp->csi2_fck)) {
+ dev_err(isp->dev, "clk_get csi2_96m_fck failed\n");
+ ret_err = PTR_ERR(isp->csi2_fck);
goto out_clk_get_csi2_fclk;
}
+ isp->l3_ick = clk_get(&camera_dev, "l3_ick");
+ if (IS_ERR(isp->l3_ick)) {
+ dev_err(isp->dev, "clk_get l3_ick failed\n");
+ ret_err = PTR_ERR(isp->l3_ick);
+ goto out_clk_get_l3_ick;
+ }
- if (request_irq(isp->irq, omap34xx_isp_isr, IRQF_SHARED,
- "Omap 3 Camera ISP", &isp_obj)) {
- DPRINTK_ISPCTRL("Could not install ISR\n");
+ if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED,
+ "Omap 3 Camera ISP", pdev)) {
+ dev_err(isp->dev, "could not install isr\n");
ret_err = -EINVAL;
goto out_request_irq;
}
- isp_obj.ref_count = 0;
+ isp->ref_count = 0;
+ omap3isp_pdev = pdev;
- mutex_init(&(isp_obj.isp_mutex));
- spin_lock_init(&isp_obj.lock);
- spin_lock_init(&isp_obj.bufs.lock);
+ mutex_init(&(isp->isp_mutex));
+ spin_lock_init(&isp->lock);
+ spin_lock_init(&isp->h3a_lock);
- omap3isp = isp;
-
- ret_err = ispmmu_init();
- if (ret_err)
- goto out_ispmmu_init;
-
- isp_ccdc_init();
- isp_hist_init();
- isph3a_aewb_init();
- isp_preview_init();
- isp_resizer_init();
- isp_af_init();
- isp_csi2_init();
+ isp->dev->dma_mask = &raw_dmamask;
+ isp->dev->coherent_dma_mask = DMA_32BIT_MASK;
isp_get();
- isp_power_settings(1);
- isp_put();
+ /* Get ISP revision */
+ isp->revision = isp_reg_readl(isp->dev,
+ OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+ dev_info(isp->dev, "Revision %d.%d found\n",
+ (isp->revision & 0xF0) >> 4, isp->revision & 0xF);
- isph3a_notify(1);
- isp_af_notify(1);
+ isp->iommu = iommu_get("isp");
+ if (IS_ERR(isp->iommu)) {
+ ret_err = PTR_ERR(isp->iommu);
+ isp->iommu = NULL;
+ }
+ isp_put();
+ if (!isp->iommu)
+ goto out_iommu_get;
+
+ isp_ccdc_init(&pdev->dev);
+ isp_hist_init(&pdev->dev);
+ isph3a_aewb_init(&pdev->dev);
+ isp_preview_init(&pdev->dev);
+ isp_resizer_init(&pdev->dev);
+ isp_af_init(&pdev->dev);
+ isp_csi2_init(&pdev->dev);
+
+ isp_get();
+ isp_power_settings(&pdev->dev, 1);
+ isp_put();
return 0;
-out_ispmmu_init:
- omap3isp = NULL;
- free_irq(isp->irq, &isp_obj);
+out_iommu_get:
+ free_irq(isp->irq_num, isp);
+ omap3isp_pdev = NULL;
out_request_irq:
- clk_put(isp_obj.csi2_fck);
+ clk_put(isp->l3_ick);
+out_clk_get_l3_ick:
+ clk_put(isp->csi2_fck);
out_clk_get_csi2_fclk:
- clk_put(isp_obj.cam_mclk);
+ clk_put(isp->dpll4_m5_ck);
+out_clk_get_dpll4_m5_ck:
+ clk_put(isp->cam_mclk);
out_clk_get_mclk:
- clk_put(isp_obj.cam_ick);
+ clk_put(isp->cam_ick);
+out_free_mmio:
+ for (i = 0; i <= OMAP3_ISP_IOMEM_CSI2PHY; i++) {
+ if (isp->mmio_base[i]) {
+ iounmap((void *)isp->mmio_base[i]);
+ isp->mmio_base[i] = 0;
+ }
+ if (isp->mmio_base_phys[i]) {
+ release_mem_region(isp->mmio_base_phys[i],
+ isp->mmio_size[i]);
+ isp->mmio_base_phys[i] = 0;
+ }
+ }
+
+ kfree(isp);
return ret_err;
}
@@ -2549,28 +2960,31 @@
/**
* isp_print_status - Prints the values of the ISP Control Module registers
- *
- * Also prints other debug information stored in the ISP module structure.
+ * @dev: Device pointer specific to the OMAP3 ISP.
**/
-void isp_print_status(void)
+void isp_print_status(struct device *dev)
{
if (!is_ispctrl_debug_enabled())
return;
DPRINTK_ISPCTRL("###ISP_CTRL=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
DPRINTK_ISPCTRL("###ISP_TCTRL_CTRL=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_TCTRL_CTRL));
DPRINTK_ISPCTRL("###ISP_SYSCONFIG=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_SYSCONFIG));
DPRINTK_ISPCTRL("###ISP_SYSSTATUS=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_SYSSTATUS));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_SYSSTATUS));
DPRINTK_ISPCTRL("###ISP_IRQ0ENABLE=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_IRQ0ENABLE));
DPRINTK_ISPCTRL("###ISP_IRQ0STATUS=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_IRQ0STATUS));
}
-EXPORT_SYMBOL(isp_print_status);
module_init(isp_init);
module_exit(isp_cleanup);
diff --git a/drivers/media/video/isp/isp.h b/drivers/media/video/isp/isp.h
index 43a32bf..b54cd06 100644
--- a/drivers/media/video/isp/isp.h
+++ b/drivers/media/video/isp/isp.h
@@ -9,7 +9,7 @@
*
* Contributors:
* Sameer Venkatraman <sameerv@ti.com>
- * Mohit Jalori <mjalori@ti.com>
+ * Mohit Jalori
* Sergio Aguirre <saaguirre@ti.com>
* Sakari Ailus <sakari.ailus@nokia.com>
* Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
@@ -28,6 +28,26 @@
#include <mach/cpu.h>
#include <media/videobuf-dma-sg.h>
#include <linux/videodev2.h>
+
+#include <asm/io.h>
+
+#include <mach/iommu.h>
+#include <mach/iovmm.h>
+
+struct isp_pipeline;
+
+#include "ispstat.h"
+#include "isp_af.h"
+#include "isphist.h"
+#include "ispccdc.h"
+#include "ispreg.h"
+#include "isph3a.h"
+#include "ispresizer.h"
+#include "isppreview.h"
+#include "ispcsi2.h"
+
+#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
+
#define OMAP_ISP_CCDC (1 << 0)
#define OMAP_ISP_PREVIEW (1 << 1)
#define OMAP_ISP_RESIZER (1 << 2)
@@ -41,19 +61,19 @@
*/
#define NUM_BUFS VIDEO_MAX_FRAME
-#ifndef CONFIG_ARCH_OMAP3410
-#define USE_ISP_PREVIEW
-#define USE_ISP_RESZ
-#define is_isppreview_enabled() 1
-#define is_ispresizer_enabled() 1
-#else
-#define is_isppreview_enabled() 0
-#define is_ispresizer_enabled() 0
-#endif
+#define ISP_REVISION_2_0 0x20
+#define ISP_REVISION_2_1 0x21
+#define ISP_REVISION_RAPXXX 0xF0
#define ISP_BYTES_PER_PIXEL 2
#define NUM_ISP_CAPTURE_FORMATS (sizeof(isp_formats) / \
sizeof(isp_formats[0]))
+
+#define to_isp_device(ptr_module) \
+ container_of(ptr_module, struct isp_device, ptr_module)
+#define to_device(ptr_module) \
+ (to_isp_device(ptr_module)->dev)
+
typedef int (*isp_vbq_callback_ptr) (struct videobuf_buffer *vb);
typedef void (*isp_callback_t) (unsigned long status,
isp_vbq_callback_ptr arg1, void *arg2);
@@ -69,29 +89,8 @@
OMAP3_ISP_IOMEM_RESZ,
OMAP3_ISP_IOMEM_SBL,
OMAP3_ISP_IOMEM_CSI2A,
- OMAP3_ISP_IOMEM_CSI2PHY
-};
-
-struct isp_device {
- struct device *dev;
-
- /*** platform HW resources ***/
- unsigned int irq;
-
-#define mmio_base_main mmio_base[OMAP3_ISP_IOMEM_MAIN]
-#define mmio_cbuff_main mmio_base[OMAP3_ISP_IOMEM_CBUFF]
-#define mmio_ccp2_main mmio_base[OMAP3_ISP_IOMEM_CCP2]
-#define mmio_ccdc_main mmio_base[OMAP3_ISP_IOMEM_CCDC]
-#define mmio_hist_main mmio_base[OMAP3_ISP_IOMEM_HIST]
-#define mmio_h3a_main mmio_base[OMAP3_ISP_IOMEM_H3A]
-#define mmio_prev_main mmio_base[OMAP3_ISP_IOMEM_PREV]
-#define mmio_resz_main mmio_base[OMAP3_ISP_IOMEM_RESZ]
-#define mmio_sbl_main mmio_base[OMAP3_ISP_IOMEM_SBL]
-#define mmio_csi2_main mmio_base[OMAP3_ISP_IOMEM_CSI2A]
-#define mmio_csi2phy_main mmio_base[OMAP3_ISP_IOMEM_CSI2PHY]
- unsigned long mmio_base[OMAP3_ISP_IOMEM_CSI2PHY + 1];
- unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_CSI2PHY + 1];
- unsigned long mmio_size[OMAP3_ISP_IOMEM_CSI2PHY + 1];
+ OMAP3_ISP_IOMEM_CSI2PHY,
+ OMAP3_ISP_IOMEM_CSI2PHY2
};
enum isp_interface_type {
@@ -128,22 +127,19 @@
CBK_PREV_DONE,
CBK_RESZ_DONE,
CBK_MMU_ERR,
- CBK_H3A_AWB_DONE,
CBK_HIST_DONE,
CBK_HS_VS,
CBK_LSC_ISR,
- CBK_H3A_AF_DONE,
CBK_CATCHALL,
CBK_CSIA,
CBK_CSIB,
CBK_END,
};
-enum ispccdc_raw_fmt {
- ISPCCDC_INPUT_FMT_GR_BG,
- ISPCCDC_INPUT_FMT_RG_GB,
- ISPCCDC_INPUT_FMT_BG_GR,
- ISPCCDC_INPUT_FMT_GB_RG,
+enum isp_running {
+ ISP_STOPPED,
+ ISP_RUNNING,
+ ISP_STOPPING,
};
/**
@@ -160,11 +156,6 @@
/**
* struct isp_interface_config - ISP interface configuration.
* @ccdc_par_ser: ISP interface type. 0 - Parallel, 1 - CSIA, 2 - CSIB to CCDC.
- * @par_bridge: CCDC Bridge input control. Parallel interface.
- * 0 - Disable, 1 - Enable, first byte->cam_d(bits 7 to 0)
- * 2 - Enable, first byte -> cam_d(bits 15 to 8)
- * @par_clk_pol: Pixel clock polarity on the parallel interface.
- * 0 - Non Inverted, 1 - Inverted
* @dataline_shift: Data lane shifter.
* 0 - No Shift, 1 - CAMEXT[13 to 2]->CAM[11 to 0]
* 2 - CAMEXT[13 to 4]->CAM[9 to 0]
@@ -175,10 +166,27 @@
* @strobe: Strobe related parameter.
* @prestrobe: PreStrobe related parameter.
* @shutter: Shutter related parameter.
- * @hskip: Horizontal Start Pixel performed in Preview module.
- * @vskip: Vertical Start Line performed in Preview module.
+ * @prev_sph: Horizontal Start Pixel performed in Preview module.
+ * @prev_slv: Vertical Start Line performed in Preview module.
* @wenlog: Store the value for the sensor specific wenlog field.
* @wait_hs_vs: Wait for this many hs_vs before anything else in the beginning.
+ * @pixelclk: Pixel data rate from sensor.
+ * @par_bridge: CCDC Bridge input control. Parallel interface.
+ * 0 - Disable, 1 - Enable, first byte->cam_d(bits 7 to 0)
+ * 2 - Enable, first byte -> cam_d(bits 15 to 8)
+ * @par_clk_pol: Pixel clock polarity on the parallel interface.
+ * 0 - Non Inverted, 1 - Inverted
+ * @crc: Use cyclic redundancy check.
+ * @mode: (?)
+ * @edge: Falling or rising edge
+ * @signalling: Use strobe mode (only valid for CCP2 mode)
+ * @strobe_clock_inv: Strobe/clock signal inversion.
+ * @vs_edge: Type of edge used for detecting VSync signal.
+ * @channel: Logical channel number used in transmission.
+ * @vpclk: Video port output clock.
+ * @data_start: Start vertical position of the region of interest.
+ * @data_size: Vertical size of the region of interest.
+ * @format: V4L2 format which matches with the transmitted frame data.
*/
struct isp_interface_config {
enum isp_interface_type ccdc_par_ser;
@@ -189,7 +197,9 @@
int shutter;
u32 wenlog;
int wait_hs_vs;
+ u32 cam_mclk;
enum ispccdc_raw_fmt raw_fmt_in;
+ unsigned int pixelclk;
union {
struct par {
unsigned par_bridge:2;
@@ -211,116 +221,416 @@
} u;
};
-u32 isp_reg_readl(enum isp_mem_resources isp_mmio_range, u32 reg_offset);
+/**
+ * struct isp_buf - ISP buffer information structure.
+ * @isp_addr: MMU mapped address (a.k.a. device address) of the buffer.
+ * @complete: Pointer to function used to handle the buffer once its complete
+ * @vb: Pointer to associated video buffer structure.
+ * @priv: Private pointer to send to associated complete handling function.
+ * @vb_state: Current ISP video buffer state.
+ */
+struct isp_buf {
+ dma_addr_t isp_addr;
+ void (*complete)(struct videobuf_buffer *vb, void *priv);
+ struct videobuf_buffer *vb;
+ void *priv;
+ u32 vb_state;
+};
-void isp_reg_writel(u32 reg_value, enum isp_mem_resources isp_mmio_range,
- u32 reg_offset);
+#define ISP_BUFS_IS_FULL(bufs) \
+ (((bufs)->queue + 1) % NUM_BUFS == (bufs)->done)
+#define ISP_BUFS_IS_EMPTY(bufs) ((bufs)->queue == (bufs)->done)
+#define ISP_BUFS_IS_LAST(bufs) \
+ ((bufs)->queue == ((bufs)->done + 1) % NUM_BUFS)
+#define ISP_BUFS_QUEUED(bufs) \
+ ((((bufs)->done - (bufs)->queue + NUM_BUFS)) % NUM_BUFS)
+#define ISP_BUF_DONE(bufs) ((bufs)->buf + (bufs)->done)
+#define ISP_BUF_NEXT_DONE(bufs) \
+ ((bufs)->buf + ((bufs)->done + 1) % NUM_BUFS)
+#define ISP_BUF_QUEUE(bufs) ((bufs)->buf + (bufs)->queue)
+#define ISP_BUF_MARK_DONE(bufs) \
+ (bufs)->done = ((bufs)->done + 1) % NUM_BUFS;
+#define ISP_BUF_MARK_QUEUED(bufs) \
+ (bufs)->queue = ((bufs)->queue + 1) % NUM_BUFS;
-static inline void isp_reg_and(enum isp_mem_resources mmio_range, u32 reg,
- u32 and_bits)
-{
- u32 v = isp_reg_readl(mmio_range, reg);
+/**
+ * struct isp_bufs - ISP internal buffer queue list.
+ * @isp_addr_capture: Array of addresses for the ISP buffers inside the list.
+ * @buf: Array of ISP buffers inside the list.
+ * @queue: Next slot to queue a buffer.
+ * @done: Buffer that is being processed.
+ * @wait_hs_vs: Wait for this many hs_vs before anything else.
+ */
+struct isp_bufs {
+ dma_addr_t isp_addr_capture[VIDEO_MAX_FRAME];
+ struct isp_buf buf[NUM_BUFS];
+ int queue;
+ int done;
+ int wait_hs_vs;
+};
- isp_reg_writel(v & and_bits, mmio_range, reg);
-}
+/**
+ * struct ispirq - Structure for containing callbacks to be called in ISP ISR.
+ * @isp_callbk: Array which stores callback functions, indexed by the type of
+ * callback (8 possible types).
+ * @isp_callbk_arg1: Pointer to array containing pointers to the first argument
+ * to be passed to the requested callback function.
+ * @isp_callbk_arg2: Pointer to array containing pointers to the second
+ * argument to be passed to the requested callback function.
+ *
+ * This structure is used to contain all the callback functions related for
+ * each callback type (CBK_CCDC_VD0, CBK_CCDC_VD1, CBK_PREV_DONE,
+ * CBK_RESZ_DONE, CBK_MMU_ERR, CBK_H3A_AWB_DONE, CBK_HIST_DONE, CBK_HS_VS,
+ * CBK_LSC_ISR).
+ */
+struct isp_irq {
+ isp_callback_t isp_callbk[CBK_END];
+ isp_vbq_callback_ptr isp_callbk_arg1[CBK_END];
+ void *isp_callbk_arg2[CBK_END];
+};
-static inline void isp_reg_or(enum isp_mem_resources mmio_range, u32 reg,
- u32 or_bits)
-{
- u32 v = isp_reg_readl(mmio_range, reg);
+/**
+ * struct isp_pipeline - ISP pipeline description.
+ * @modules: ISP submodules in use.
+ * @pix: Output pixel format details in v4l2_pix_format structure.
+ * @ccdc_in_v_st: CCDC input vertical start.
+ * @ccdc_in_h_st: CCDC input horizontal start.
+ * @ccdc_in_w: CCDC input width.
+ * @ccdc_in_h: CCDC input height.
+ * @ccdc_out_w: CCDC output width (with extra padding pixels).
+ * @ccdc_out_h: CCDC output height.
+ * @ccdc_out_w_img: CCDC output width.
+ * @ccdc_in: CCDC input source.
+ * @ccdc_out: CCDC output destination.
+ * @prv_out_w: Preview output width (with extra padding pixels).
+ * @prv_out_h: Preview output height (with extra padding pixels).
+ * @prv_out_w_img: Preview output width.
+ * @prv_out_h_img: Preview output height.
+ * @prv_fmt_avg: Preview formatter averager.
+ * @prv_in: Preview input source.
+ * @prv_out: Preview output destination.
+ * @rsz_crop: Resizer crop region.
+ * @rsz_out_w: Resizer output width (with extra padding pixels).
+ * @rsz_out_h: Resizer output height.
+ * @rsz_out_w_img: Resizer output width (valid image region).
+ * @rsz_in: Resizer input source.
+ */
+struct isp_pipeline {
+ unsigned int modules; /* modules in use */
+ struct v4l2_pix_format pix; /* output pix */
+ unsigned int ccdc_in_v_st;
+ unsigned int ccdc_in_h_st;
+ unsigned int ccdc_in_w;
+ unsigned int ccdc_in_h;
+ unsigned int ccdc_out_w; /* ccdc output data width (pixels) */
+ unsigned int ccdc_out_h; /* ccdc output data height */
+ unsigned int ccdc_out_w_img; /* ccdc output visible image width */
+ enum ccdc_input ccdc_in;
+ enum ccdc_output ccdc_out;
+ unsigned int prv_out_w;
+ unsigned int prv_out_h;
+ unsigned int prv_out_w_img;
+ unsigned int prv_out_h_img;
+ unsigned int prv_fmt_avg;
+ enum preview_input prv_in;
+ enum preview_output prv_out;
+ struct v4l2_rect rsz_crop;
+ unsigned int rsz_out_w;
+ unsigned int rsz_out_h;
+ unsigned int rsz_out_w_img;
+ enum resizer_input rsz_in;
+};
- isp_reg_writel(v | or_bits, mmio_range, reg);
-}
+#define CCDC_CAPTURE(isp) \
+ ((isp)->pipeline.modules == OMAP_ISP_CCDC)
-static inline void isp_reg_and_or(enum isp_mem_resources mmio_range, u32 reg,
- u32 and_bits, u32 or_bits)
-{
- u32 v = isp_reg_readl(mmio_range, reg);
+#define CCDC_PREV_CAPTURE(isp) \
+ ((isp)->pipeline.modules == (OMAP_ISP_CCDC | OMAP_ISP_PREVIEW))
- isp_reg_writel((v & and_bits) | or_bits, mmio_range, reg);
-}
+#define CCDC_PREV_RESZ_CAPTURE(isp) \
+ ((isp)->pipeline.modules == (OMAP_ISP_CCDC | \
+ OMAP_ISP_PREVIEW | \
+ OMAP_ISP_RESIZER))
-void isp_start(void);
+/**
+ * struct isp_device - ISP device structure.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @revision: Stores current ISP module revision.
+ * @irq_num: Currently used IRQ number.
+ * @mmio_base: Array with kernel base addresses for ioremapped ISP register
+ * regions.
+ * @mmio_base_phys: Array with physical L4 bus addresses for ISP register
+ * regions.
+ * @mmio_size: Array with ISP register regions size in bytes.
+ * @lock: Spinlock for handling registered ISP callbacks.
+ * @h3a_lock: Spinlock for handling H3a (Not used) (?)
+ * @isp_mutex: Mutex for serializing requests to ISP.
+ * @ref_count: Reference count for handling multiple ISP requests.
+ * @cam_ick: Pointer to camera interface clock structure.
+ * @cam_mclk: Pointer to camera functional clock structure.
+ * @dpll4_m5_ck: Pointer to DPLL4 M5 clock structure.
+ * @csi2_fck: Pointer to camera CSI2 complexIO clock structure.
+ * @l3_ick: Pointer to OMAP3 L3 bus interface clock.
+ * @config: Pointer to currently set ISP interface configuration.
+ * @tmp_buf: ISP MMU mapped temporary buffer address used for 34xx Workaround
+ * for CCDC->PRV->RSZ datapath errata.
+ * @tmp_buf_size: ISP MMU mapped temporary buffer size used for 34xx Workaround
+ * for CCDC->PRV->RSZ datapath errata.
+ * @tmp_buf_offset: ISP MMU mapped temporary buffer line offset used for 34xx
+ * Workaround for CCDC->PRV->RSZ datapath errata.
+ * @bufs: Internal ISP buffer queue list.
+ * @irq: Currently attached ISP ISR callbacks information structure.
+ * @pipeline: Currently used internal ISP pipeline information.
+ * @interrupts: ISP interrupts staged for deferred enabling.
+ * @running: Current running/stopped status of ISP.
+ * @isp_af: Pointer to current settings for ISP AutoFocus SCM.
+ * @isp_hist: Pointer to current settings for ISP Histogram SCM.
+ * @isp_h3a: Pointer to current settings for ISP Auto Exposure and
+ * White Balance SCM.
+ * @isp_res: Pointer to current settings for ISP Resizer.
+ * @isp_prev: Pointer to current settings for ISP Preview.
+ * @isp_ccdc: Pointer to current settings for ISP CCDC.
+ * @iommu: Pointer to requested IOMMU instance for ISP.
+ *
+ * This structure is used to store the OMAP ISP Information.
+ */
+struct isp_device {
+ struct device *dev;
+ u32 revision;
-void isp_stop(void);
+ /*** platform HW resources ***/
+ unsigned int irq_num;
-int isp_buf_queue(struct videobuf_buffer *vb,
+#define mmio_base_main mmio_base[OMAP3_ISP_IOMEM_MAIN]
+#define mmio_cbuff_main mmio_base[OMAP3_ISP_IOMEM_CBUFF]
+#define mmio_ccp2_main mmio_base[OMAP3_ISP_IOMEM_CCP2]
+#define mmio_ccdc_main mmio_base[OMAP3_ISP_IOMEM_CCDC]
+#define mmio_hist_main mmio_base[OMAP3_ISP_IOMEM_HIST]
+#define mmio_h3a_main mmio_base[OMAP3_ISP_IOMEM_H3A]
+#define mmio_prev_main mmio_base[OMAP3_ISP_IOMEM_PREV]
+#define mmio_resz_main mmio_base[OMAP3_ISP_IOMEM_RESZ]
+#define mmio_sbl_main mmio_base[OMAP3_ISP_IOMEM_SBL]
+#define mmio_csi2_main mmio_base[OMAP3_ISP_IOMEM_CSI2A]
+#define mmio_csi2phy_main mmio_base[OMAP3_ISP_IOMEM_CSI2PHY2]
+ unsigned long mmio_base[OMAP3_ISP_IOMEM_CSI2PHY2 + 1];
+ unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_CSI2PHY2 + 1];
+ unsigned long mmio_size[OMAP3_ISP_IOMEM_CSI2PHY2 + 1];
+
+ /* ISP Obj */
+ spinlock_t lock; /* For handling registered ISP callbacks */
+ spinlock_t h3a_lock;
+ struct mutex isp_mutex; /* For handling ref_count field */
+ int ref_count;
+ struct clk *cam_ick;
+ struct clk *cam_mclk;
+ struct clk *dpll4_m5_ck;
+ struct clk *csi2_fck;
+ struct clk *l3_ick;
+ struct isp_interface_config *config;
+ dma_addr_t tmp_buf;
+ size_t tmp_buf_size;
+ unsigned long tmp_buf_offset;
+ struct isp_bufs bufs;
+ struct isp_irq irq;
+ struct isp_pipeline pipeline;
+ u32 interrupts;
+ u32 mclk;
+ enum isp_running running;
+
+ /* ISP modules */
+ struct isp_af_device isp_af;
+ struct isp_hist_device isp_hist;
+ struct isp_h3a_device isp_h3a;
+ struct isp_res_device isp_res;
+ struct isp_prev_device isp_prev;
+ struct isp_ccdc_device isp_ccdc;
+ struct isp_csi2_device isp_csi2;
+
+ struct iommu *iommu;
+};
+
+void isp_hist_dma_done(struct device *dev);
+
+u32 isp_rev(struct device *dev);
+
+void isp_flush(struct device *dev);
+
+void isp_start(struct device *dev);
+
+void isp_stop(struct device *dev);
+
+int isp_buf_queue(struct device *dev, struct videobuf_buffer *vb,
void (*complete)(struct videobuf_buffer *vb, void *priv),
void *priv);
-int isp_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
- unsigned int *size);
+int isp_vbq_setup(struct device *dev, struct videobuf_queue *vbq,
+ unsigned int *cnt, unsigned int *size);
-int isp_vbq_prepare(struct videobuf_queue *vbq, struct videobuf_buffer *vb,
- enum v4l2_field field);
+int isp_vbq_prepare(struct device *dev, struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb, enum v4l2_field field);
-void isp_vbq_release(struct videobuf_queue *vbq, struct videobuf_buffer *vb);
+void isp_vbq_release(struct device *dev, struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb);
-int isp_set_callback(enum isp_callback_type type, isp_callback_t callback,
- isp_vbq_callback_ptr arg1, void *arg2);
+int isp_set_callback(struct device *dev, enum isp_callback_type type,
+ isp_callback_t callback, isp_vbq_callback_ptr arg1,
+ void *arg2);
-int isp_unset_callback(enum isp_callback_type type);
+int isp_unset_callback(struct device *dev, enum isp_callback_type type);
-u32 isp_set_xclk(u32 xclk, u8 xclksel);
+u32 isp_set_xclk(struct device *dev, u32 xclk, u8 xclksel);
-int isp_configure_interface(struct isp_interface_config *config);
+int isp_configure_interface(struct device *dev,
+ struct isp_interface_config *config);
-int isp_get(void);
+struct device *isp_get(void);
int isp_put(void);
+int isp_enable_mclk(struct device *dev);
+
+void isp_disable_mclk(struct isp_device *dev);
+
int isp_queryctrl(struct v4l2_queryctrl *a);
int isp_querymenu(struct v4l2_querymenu *a);
-int isp_g_ctrl(struct v4l2_control *a);
+int isp_g_ctrl(struct device *dev, struct v4l2_control *a);
-int isp_s_ctrl(struct v4l2_control *a);
+int isp_s_ctrl(struct device *dev, struct v4l2_control *a);
int isp_enum_fmt_cap(struct v4l2_fmtdesc *f);
-int isp_try_fmt_cap(struct v4l2_pix_format *pix_input,
+int isp_try_fmt_cap(struct device *dev, struct v4l2_pix_format *pix_input,
struct v4l2_pix_format *pix_output);
-void isp_g_fmt_cap(struct v4l2_pix_format *pix);
+void isp_g_fmt_cap(struct device *dev, struct v4l2_pix_format *pix);
-int isp_s_fmt_cap(struct v4l2_pix_format *pix_input,
+int isp_s_fmt_cap(struct device *dev, struct v4l2_pix_format *pix_input,
struct v4l2_pix_format *pix_output);
-int isp_g_crop(struct v4l2_crop *a);
+int isp_g_crop(struct device *dev, struct v4l2_crop *a);
-int isp_s_crop(struct v4l2_crop *a, struct v4l2_pix_format *pix);
+int isp_s_crop(struct device *dev, struct v4l2_crop *a);
-void isp_config_crop(struct v4l2_pix_format *pix);
-
-int isp_try_fmt(struct v4l2_pix_format *pix_input,
+int isp_try_fmt(struct device *dev, struct v4l2_pix_format *pix_input,
struct v4l2_pix_format *pix_output);
-int isp_handle_private(int cmd, void *arg);
+int isp_handle_private(struct device *dev, struct mutex *, int cmd, void *arg);
-void isp_save_context(struct isp_reg *);
+void isp_save_context(struct device *dev, struct isp_reg *);
-void isp_restore_context(struct isp_reg *);
+void isp_restore_context(struct device *dev, struct isp_reg *);
-void isp_print_status(void);
+void isp_print_status(struct device *dev);
-void isp_set_hs_vs(int);
+void isp_set_hs_vs(struct device *dev, int hs_vs);
-int __init isp_ccdc_init(void);
-int __init isp_hist_init(void);
-int __init isph3a_aewb_init(void);
-int __init isp_preview_init(void);
-int __init isp_resizer_init(void);
-int __init isp_af_init(void);
-int __init isp_csi2_init(void);
+unsigned long isp_get_buf_offset(struct device *dev);
-void isp_ccdc_cleanup(void);
-void isp_hist_cleanup(void);
-void isph3a_aewb_cleanup(void);
-void isp_preview_cleanup(void);
-void isp_hist_cleanup(void);
-void isp_resizer_cleanup(void);
-void isp_af_exit(void);
-void isp_csi2_cleanup(void);
+int __init isp_ccdc_init(struct device *dev);
+int __init isp_hist_init(struct device *dev);
+int __init isph3a_aewb_init(struct device *dev);
+int __init isp_preview_init(struct device *dev);
+int __init isp_resizer_init(struct device *dev);
+int __init isp_af_init(struct device *dev);
+int __init isp_csi2_init(struct device *dev);
+
+void isp_ccdc_cleanup(struct device *dev);
+void isp_hist_cleanup(struct device *dev);
+void isph3a_aewb_cleanup(struct device *dev);
+void isp_resizer_cleanup(struct device *dev);
+void isp_af_exit(struct device *dev);
+void isp_csi2_cleanup(struct device *dev);
+
+/* FIXME: Remove these when iommu supports these directly. */
+dma_addr_t ispmmu_vmap(struct device *dev, const struct scatterlist *sglist,
+ int sglen);
+void ispmmu_vunmap(struct device *dev, dma_addr_t da);
+
+/**
+ * isp_reg_readl - Read value of an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp_mmio_range: Range to which the register offset refers to.
+ * @reg_offset: Register offset to read from.
+ *
+ * Returns an unsigned 32 bit value with the required register contents.
+ **/
+static inline
+u32 isp_reg_readl(struct device *dev, enum isp_mem_resources isp_mmio_range,
+ u32 reg_offset)
+{
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ return __raw_readl(isp->mmio_base[isp_mmio_range] + reg_offset);
+}
+
+/**
+ * isp_reg_writel - Write value to an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @reg_value: 32 bit value to write to the register.
+ * @isp_mmio_range: Range to which the register offset refers to.
+ * @reg_offset: Register offset to write into.
+ **/
+static inline
+void isp_reg_writel(struct device *dev, u32 reg_value,
+ enum isp_mem_resources isp_mmio_range, u32 reg_offset)
+{
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ __raw_writel(reg_value, isp->mmio_base[isp_mmio_range] + reg_offset);
+}
+
+/**
+ * isp_reg_and - Do AND binary operation within an OMAP3 ISP register value
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @and_bits: 32 bit value which would be 'ANDed' with current register value.
+ **/
+static inline
+void isp_reg_and(struct device *dev, enum isp_mem_resources mmio_range, u32 reg,
+ u32 and_bits)
+{
+ u32 v = isp_reg_readl(dev, mmio_range, reg);
+
+ isp_reg_writel(dev, v & and_bits, mmio_range, reg);
+}
+
+/**
+ * isp_reg_or - Do OR binary operation within an OMAP3 ISP register value
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @or_bits: 32 bit value which would be 'ORed' with current register value.
+ **/
+static inline
+void isp_reg_or(struct device *dev, enum isp_mem_resources mmio_range, u32 reg,
+ u32 or_bits)
+{
+ u32 v = isp_reg_readl(dev, mmio_range, reg);
+
+ isp_reg_writel(dev, v | or_bits, mmio_range, reg);
+}
+
+/**
+ * isp_reg_and_or - Do AND and OR binary ops within an OMAP3 ISP register value
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @and_bits: 32 bit value which would be 'ANDed' with current register value.
+ * @or_bits: 32 bit value which would be 'ORed' with current register value.
+ *
+ * The AND operation is done first, and then the OR operation. Mostly useful
+ * when clearing a group of bits before setting a value.
+ **/
+static inline
+void isp_reg_and_or(struct device *dev, enum isp_mem_resources mmio_range,
+ u32 reg, u32 and_bits, u32 or_bits)
+{
+ u32 v = isp_reg_readl(dev, mmio_range, reg);
+
+ isp_reg_writel(dev, (v & and_bits) | or_bits, mmio_range, reg);
+}
#endif /* OMAP_ISP_TOP_H */
diff --git a/drivers/media/video/isp/isp_af.c b/drivers/media/video/isp/isp_af.c
index a607b97..c7fdb6f 100644
--- a/drivers/media/video/isp/isp_af.c
+++ b/drivers/media/video/isp/isp_af.c
@@ -8,6 +8,7 @@
* Contributors:
* Sergio Aguirre <saaguirre@ti.com>
* Troy Laramy
+ * David Cohen <david.cohen@nokia.com>
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,766 +20,457 @@
*/
/* Linux specific include files */
-#include <asm/cacheflush.h>
-
-#include <linux/uaccess.h>
-#include <linux/dma-mapping.h>
-#include <asm/atomic.h>
+#include <linux/device.h>
#include "isp.h"
#include "ispreg.h"
#include "isph3a.h"
#include "isp_af.h"
-#include "ispmmu.h"
-
-/**
- * struct isp_af_buffer - AF frame stats buffer.
- * @virt_addr: Virtual address to mmap the buffer.
- * @phy_addr: Physical address of the buffer.
- * @addr_align: Virtual Address 32 bytes aligned.
- * @ispmmu_addr: Address of the buffer mapped by the ISPMMU.
- * @mmap_addr: Mapped memory area of buffer. For userspace access.
- * @locked: 1 - Buffer locked from write. 0 - Buffer can be overwritten.
- * @frame_num: Frame number from which the statistics are taken.
- * @lens_position: Lens position currently set in the DW9710 Coil motor driver.
- * @next: Pointer to link next buffer.
- */
-struct isp_af_buffer {
- unsigned long virt_addr;
- unsigned long phy_addr;
- unsigned long addr_align;
- unsigned long ispmmu_addr;
- unsigned long mmap_addr;
-
- u8 locked;
- u16 frame_num;
- u32 config_counter;
- struct isp_af_xtrastats xtrastats;
- struct isp_af_buffer *next;
-};
-
-/**
- * struct isp_af_status - AF status.
- * @initialized: 1 - Buffers initialized.
- * @update: 1 - Update registers.
- * @stats_req: 1 - Future stats requested.
- * @stats_done: 1 - Stats ready for user.
- * @frame_req: Number of frame requested for statistics.
- * @af_buff: Array of statistics buffers to access.
- * @stats_buf_size: Statistics buffer size.
- * @curr_cfg_buf_size: Current user configured stats buff size.
- * @min_buf_size: Minimum statisitics buffer size.
- * @frame_count: Frame Count.
- * @stats_wait: Wait primitive for locking/unlocking the stats request.
- * @buffer_lock: Spinlock for statistics buffers access.
- */
-static struct isp_af_status {
- u8 initialized;
- u8 update;
- u8 stats_req;
- u8 stats_done;
- u16 frame_req;
-
- struct isp_af_buffer af_buff[H3A_MAX_BUFF];
- unsigned int stats_buf_size;
- unsigned int min_buf_size;
- unsigned int curr_cfg_buf_size;
-
- int pm_state;
- u32 frame_count;
- wait_queue_head_t stats_wait;
- atomic_t config_counter;
- spinlock_t buffer_lock; /* For stats buffers read/write sync */
-} afstat;
-
-struct af_device *af_dev_configptr;
-static struct isp_af_buffer *active_buff;
-static int af_major = -1;
-static int camnotify;
-
-/**
- * isp_af_setxtrastats - Receives extra statistics from prior frames.
- * @xtrastats: Pointer to structure containing extra statistics fields like
- * field count and timestamp of frame.
- *
- * Called from update_vbq in camera driver
- **/
-void isp_af_setxtrastats(struct isp_af_xtrastats *xtrastats, u8 updateflag)
-{
- int i, past_i;
-
- if (active_buff == NULL)
- return;
-
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- if (afstat.af_buff[i].frame_num == active_buff->frame_num)
- break;
- }
-
- if (i == H3A_MAX_BUFF)
- return;
-
- if (i == 0) {
- if (afstat.af_buff[H3A_MAX_BUFF - 1].locked == 0)
- past_i = H3A_MAX_BUFF - 1;
- else
- past_i = H3A_MAX_BUFF - 2;
- } else if (i == 1) {
- if (afstat.af_buff[0].locked == 0)
- past_i = 0;
- else
- past_i = H3A_MAX_BUFF - 1;
- } else {
- if (afstat.af_buff[i - 1].locked == 0)
- past_i = i - 1;
- else
- past_i = i - 2;
- }
-
- if (updateflag & AF_UPDATEXS_TS)
- afstat.af_buff[past_i].xtrastats.ts = xtrastats->ts;
-
- if (updateflag & AF_UPDATEXS_FIELDCOUNT)
- afstat.af_buff[past_i].xtrastats.field_count =
- xtrastats->field_count;
-}
-EXPORT_SYMBOL(isp_af_setxtrastats);
-
-/*
- * Helper function to update buffer cache pages
- */
-static void isp_af_update_req_buffer(struct isp_af_buffer *buffer)
-{
- int size = afstat.stats_buf_size;
-
- size = PAGE_ALIGN(size);
- /* Update the kernel pages of the requested buffer */
- dmac_inv_range((void *)buffer->addr_align, (void *)buffer->addr_align +
- size);
-}
#define IS_OUT_OF_BOUNDS(value, min, max) \
(((value) < (min)) || ((value) > (max)))
/* Function to check paxel parameters */
-int isp_af_check_paxel(void)
+static int isp_af_check_params(struct isp_af_device *isp_af,
+ struct af_configuration *afconfig)
{
- struct af_paxel *paxel_cfg = &af_dev_configptr->config->paxel_config;
- struct af_iir *iir_cfg = &af_dev_configptr->config->iir_config;
+ struct af_paxel *paxel_cfg = &afconfig->paxel_config;
+ struct af_iir *iir_cfg = &afconfig->iir_config;
+ int index;
/* Check horizontal Count */
if (IS_OUT_OF_BOUNDS(paxel_cfg->hz_cnt, AF_PAXEL_HORIZONTAL_COUNT_MIN,
- AF_PAXEL_HORIZONTAL_COUNT_MAX)) {
- DPRINTK_ISP_AF("Error : Horizontal Count is incorrect");
+ AF_PAXEL_HORIZONTAL_COUNT_MAX))
return -AF_ERR_HZ_COUNT;
- }
- /*Check Vertical Count */
+ /* Check Vertical Count */
if (IS_OUT_OF_BOUNDS(paxel_cfg->vt_cnt, AF_PAXEL_VERTICAL_COUNT_MIN,
- AF_PAXEL_VERTICAL_COUNT_MAX)) {
- DPRINTK_ISP_AF("Error : Vertical Count is incorrect");
+ AF_PAXEL_VERTICAL_COUNT_MAX))
return -AF_ERR_VT_COUNT;
- }
- /*Check Height */
+ /* Check Height */
if (IS_OUT_OF_BOUNDS(paxel_cfg->height, AF_PAXEL_HEIGHT_MIN,
- AF_PAXEL_HEIGHT_MAX)) {
- DPRINTK_ISP_AF("Error : Height is incorrect");
+ AF_PAXEL_HEIGHT_MAX))
return -AF_ERR_HEIGHT;
- }
- /*Check width */
+ /* Check width */
if (IS_OUT_OF_BOUNDS(paxel_cfg->width, AF_PAXEL_WIDTH_MIN,
- AF_PAXEL_WIDTH_MAX)) {
- DPRINTK_ISP_AF("Error : Width is incorrect");
+ AF_PAXEL_WIDTH_MAX))
return -AF_ERR_WIDTH;
- }
- /*Check Line Increment */
+ /* Check Line Increment */
if (IS_OUT_OF_BOUNDS(paxel_cfg->line_incr, AF_PAXEL_INCREMENT_MIN,
- AF_PAXEL_INCREMENT_MAX)) {
- DPRINTK_ISP_AF("Error : Line Increment is incorrect");
+ AF_PAXEL_INCREMENT_MAX))
return -AF_ERR_INCR;
- }
- /*Check Horizontal Start */
+ /* Check Horizontal Start */
if ((paxel_cfg->hz_start % 2 != 0) ||
(paxel_cfg->hz_start < (iir_cfg->hz_start_pos + 2)) ||
IS_OUT_OF_BOUNDS(paxel_cfg->hz_start,
- AF_PAXEL_HZSTART_MIN, AF_PAXEL_HZSTART_MAX)) {
- DPRINTK_ISP_AF("Error : Horizontal Start is incorrect");
+ AF_PAXEL_HZSTART_MIN, AF_PAXEL_HZSTART_MAX))
return -AF_ERR_HZ_START;
- }
- /*Check Vertical Start */
+ /* Check Vertical Start */
if (IS_OUT_OF_BOUNDS(paxel_cfg->vt_start, AF_PAXEL_VTSTART_MIN,
- AF_PAXEL_VTSTART_MAX)) {
- DPRINTK_ISP_AF("Error : Vertical Start is incorrect");
+ AF_PAXEL_VTSTART_MAX))
return -AF_ERR_VT_START;
- }
- return 0;
-}
-/**
- * isp_af_check_iir - Function to check IIR Coefficient.
- **/
-int isp_af_check_iir(void)
-{
- struct af_iir *iir_cfg = &af_dev_configptr->config->iir_config;
- int index;
-
+ /* Check IIR */
for (index = 0; index < AF_NUMBER_OF_COEF; index++) {
- if ((iir_cfg->coeff_set0[index]) > AF_COEF_MAX) {
- DPRINTK_ISP_AF("Error : Coefficient for set 0 is "
- "incorrect");
+ if ((iir_cfg->coeff_set0[index]) > AF_COEF_MAX)
return -AF_ERR_IIR_COEF;
- }
- if ((iir_cfg->coeff_set1[index]) > AF_COEF_MAX) {
- DPRINTK_ISP_AF("Error : Coefficient for set 1 is "
- "incorrect");
+ if ((iir_cfg->coeff_set1[index]) > AF_COEF_MAX)
return -AF_ERR_IIR_COEF;
- }
}
if (IS_OUT_OF_BOUNDS(iir_cfg->hz_start_pos, AF_IIRSH_MIN,
- AF_IIRSH_MAX)) {
- DPRINTK_ISP_AF("Error : IIRSH is incorrect");
+ AF_IIRSH_MAX))
return -AF_ERR_IIRSH;
- }
-
- return 0;
-}
-/**
- * isp_af_unlock_buffers - Helper function to unlock all buffers.
- **/
-static void isp_af_unlock_buffers(void)
-{
- int i;
- unsigned long irqflags;
-
- spin_lock_irqsave(&afstat.buffer_lock, irqflags);
- for (i = 0; i < H3A_MAX_BUFF; i++)
- afstat.af_buff[i].locked = 0;
-
- spin_unlock_irqrestore(&afstat.buffer_lock, irqflags);
-}
-
-/*
- * Helper function to link allocated buffers
- */
-static void isp_af_link_buffers(void)
-{
- int i;
-
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- if ((i + 1) < H3A_MAX_BUFF)
- afstat.af_buff[i].next = &afstat.af_buff[i + 1];
- else
- afstat.af_buff[i].next = &afstat.af_buff[0];
- }
-}
-
-/* Function to perform hardware set up */
-int isp_af_configure(struct af_configuration *afconfig)
-{
- int result;
- int buff_size, i;
- unsigned int busyaf;
- struct af_configuration *af_curr_cfg = af_dev_configptr->config;
-
- if (NULL == afconfig) {
- printk(KERN_ERR "Null argument in configuration. \n");
- return -EINVAL;
- }
-
- memcpy(af_curr_cfg, afconfig, sizeof(struct af_configuration));
- /* Get the value of PCR register */
- busyaf = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
-
- if ((busyaf & AF_BUSYAF) == AF_BUSYAF) {
- DPRINTK_ISP_AF("AF_register_setup_ERROR : Engine Busy");
- DPRINTK_ISP_AF("\n Configuration cannot be done ");
- return -AF_ERR_ENGINE_BUSY;
- }
-
- /* Check IIR Coefficient and start Values */
- result = isp_af_check_iir();
- if (result < 0)
- return result;
-
- /* Check Paxel Values */
- result = isp_af_check_paxel();
- if (result < 0)
- return result;
/* Check HMF Threshold Values */
- if (af_curr_cfg->hmf_config.threshold > AF_THRESHOLD_MAX) {
- DPRINTK_ISP_AF("Error : HMF Threshold is incorrect");
+ if (afconfig->hmf_config.threshold > AF_THRESHOLD_MAX)
return -AF_ERR_THRESHOLD;
- }
- /* Compute buffer size */
- buff_size = (af_curr_cfg->paxel_config.hz_cnt + 1) *
- (af_curr_cfg->paxel_config.vt_cnt + 1) * AF_PAXEL_SIZE;
-
- afstat.curr_cfg_buf_size = buff_size;
- /* Deallocate the previous buffers */
- if (afstat.stats_buf_size && buff_size > afstat.stats_buf_size) {
- isp_af_enable(0);
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- ispmmu_kunmap(afstat.af_buff[i].ispmmu_addr);
- dma_free_coherent(
- NULL, afstat.min_buf_size,
- (void *)afstat.af_buff[i].virt_addr,
- (dma_addr_t)afstat.af_buff[i].phy_addr);
- afstat.af_buff[i].virt_addr = 0;
- }
- afstat.stats_buf_size = 0;
- }
-
- if (!afstat.af_buff[0].virt_addr) {
- afstat.stats_buf_size = buff_size;
- afstat.min_buf_size = PAGE_ALIGN(afstat.stats_buf_size);
-
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- afstat.af_buff[i].virt_addr =
- (unsigned long)dma_alloc_coherent(
- NULL,
- afstat.min_buf_size,
- (dma_addr_t *)
- &afstat.af_buff[i].phy_addr,
- GFP_KERNEL | GFP_DMA);
- if (afstat.af_buff[i].virt_addr == 0) {
- printk(KERN_ERR "Can't acquire memory for "
- "buffer[%d]\n", i);
- return -ENOMEM;
- }
- afstat.af_buff[i].addr_align =
- afstat.af_buff[i].virt_addr;
- while ((afstat.af_buff[i].addr_align & 0xFFFFFFC0) !=
- afstat.af_buff[i].addr_align)
- afstat.af_buff[i].addr_align++;
- afstat.af_buff[i].ispmmu_addr =
- ispmmu_kmap(afstat.af_buff[i].phy_addr,
- afstat.min_buf_size);
- }
- isp_af_unlock_buffers();
- isp_af_link_buffers();
-
- /* First active buffer */
- if (active_buff == NULL)
- active_buff = &afstat.af_buff[0];
- isp_af_set_address(active_buff->ispmmu_addr);
- }
-
- result = isp_af_register_setup(af_dev_configptr);
- if (result < 0)
- return result;
- af_dev_configptr->size_paxel = buff_size;
- atomic_inc(&afstat.config_counter);
- afstat.initialized = 1;
- afstat.frame_count = 1;
- active_buff->frame_num = 1;
- /* Set configuration flag to indicate HW setup done */
- if (af_curr_cfg->af_config)
- isp_af_enable(1);
- else
- isp_af_enable(0);
-
- /* Success */
return 0;
}
-EXPORT_SYMBOL(isp_af_configure);
-int isp_af_register_setup(struct af_device *af_dev)
+void isp_af_config_registers(struct isp_af_device *isp_af)
{
+ struct device *dev = to_device(isp_af);
unsigned int pcr = 0, pax1 = 0, pax2 = 0, paxstart = 0;
unsigned int coef = 0;
unsigned int base_coef_set0 = 0;
unsigned int base_coef_set1 = 0;
int index;
+ unsigned long irqflags;
+
+ if (!isp_af->config.af_config)
+ return;
+
+ spin_lock_irqsave(isp_af->lock, irqflags);
+
+ isp_reg_writel(dev, isp_af->buf_next->iommu_addr, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AFBUFST);
+
+ if (!isp_af->update) {
+ spin_unlock_irqrestore(isp_af->lock, irqflags);
+ return;
+ }
/* Configure Hardware Registers */
- /* Read PCR Register */
- pcr = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
-
- /* Set Accumulator Mode */
- if (af_dev->config->mode == ACCUMULATOR_PEAK)
- pcr |= FVMODE;
- else
- pcr &= ~FVMODE;
-
- /* Set A-law */
- if (af_dev->config->alaw_enable == H3A_AF_ALAW_ENABLE)
- pcr |= AF_ALAW_EN;
- else
- pcr &= ~AF_ALAW_EN;
-
- /* Set RGB Position */
- pcr &= ~RGBPOS;
- pcr |= af_dev->config->rgb_pos << AF_RGBPOS_SHIFT;
-
- /* HMF Configurations */
- if (af_dev->config->hmf_config.enable == H3A_AF_HMF_ENABLE) {
- pcr &= ~AF_MED_EN;
- /* Enable HMF */
- pcr |= AF_MED_EN;
-
- /* Set Median Threshold */
- pcr &= ~MED_TH;
- pcr |= af_dev->config->hmf_config.threshold << AF_MED_TH_SHIFT;
- } else
- pcr &= ~AF_MED_EN;
-
- /* Set PCR Register */
- isp_reg_writel(pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
-
- pax1 &= ~PAXW;
- pax1 |= af_dev->config->paxel_config.width << AF_PAXW_SHIFT;
-
+ pax1 |= isp_af->config.paxel_config.width << AF_PAXW_SHIFT;
/* Set height in AFPAX1 */
- pax1 &= ~PAXH;
- pax1 |= af_dev->config->paxel_config.height;
-
- isp_reg_writel(pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1);
+ pax1 |= isp_af->config.paxel_config.height;
+ isp_reg_writel(dev, pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1);
/* Configure AFPAX2 Register */
/* Set Line Increment in AFPAX2 Register */
- pax2 &= ~AFINCV;
- pax2 |= af_dev->config->paxel_config.line_incr << AF_LINE_INCR_SHIFT;
+ pax2 |= isp_af->config.paxel_config.line_incr << AF_LINE_INCR_SHIFT;
/* Set Vertical Count */
- pax2 &= ~PAXVC;
- pax2 |= af_dev->config->paxel_config.vt_cnt << AF_VT_COUNT_SHIFT;
+ pax2 |= isp_af->config.paxel_config.vt_cnt << AF_VT_COUNT_SHIFT;
/* Set Horizontal Count */
- pax2 &= ~PAXHC;
- pax2 |= af_dev->config->paxel_config.hz_cnt;
- isp_reg_writel(pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2);
+ pax2 |= isp_af->config.paxel_config.hz_cnt;
+ isp_reg_writel(dev, pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2);
/* Configure PAXSTART Register */
/*Configure Horizontal Start */
- paxstart &= ~PAXSH;
- paxstart |= af_dev->config->paxel_config.hz_start << AF_HZ_START_SHIFT;
+ paxstart |= isp_af->config.paxel_config.hz_start << AF_HZ_START_SHIFT;
/* Configure Vertical Start */
- paxstart &= ~PAXSV;
- paxstart |= af_dev->config->paxel_config.vt_start;
- isp_reg_writel(paxstart, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAXSTART);
+ paxstart |= isp_af->config.paxel_config.vt_start;
+ isp_reg_writel(dev, paxstart, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AFPAXSTART);
/*SetIIRSH Register */
- isp_reg_writel(af_dev->config->iir_config.hz_start_pos,
+ isp_reg_writel(dev, isp_af->config.iir_config.hz_start_pos,
OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH);
- /*Set IIR Filter0 Coefficients */
base_coef_set0 = ISPH3A_AFCOEF010;
- for (index = 0; index <= 8; index += 2) {
- coef &= ~COEF_MASK0;
- coef |= af_dev->config->iir_config.coeff_set0[index];
- coef &= ~COEF_MASK1;
- coef |= af_dev->config->iir_config.coeff_set0[index + 1] <<
- AF_COEF_SHIFT;
- isp_reg_writel(coef, OMAP3_ISP_IOMEM_H3A, base_coef_set0);
- base_coef_set0 = base_coef_set0 + AFCOEF_OFFSET;
- }
-
- /* set AFCOEF0010 Register */
- isp_reg_writel(af_dev->config->iir_config.coeff_set0[10],
- OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF010);
-
- /*Set IIR Filter1 Coefficients */
-
base_coef_set1 = ISPH3A_AFCOEF110;
for (index = 0; index <= 8; index += 2) {
- coef &= ~COEF_MASK0;
- coef |= af_dev->config->iir_config.coeff_set1[index];
- coef &= ~COEF_MASK1;
- coef |= af_dev->config->iir_config.coeff_set1[index + 1] <<
- AF_COEF_SHIFT;
- isp_reg_writel(coef, OMAP3_ISP_IOMEM_H3A, base_coef_set1);
+ /*Set IIR Filter0 Coefficients */
+ coef = 0;
+ coef |= isp_af->config.iir_config.coeff_set0[index] &
+ COEF_MASK0;
+ coef |= (isp_af->config.iir_config.coeff_set0[index + 1] <<
+ AF_COEF_SHIFT) & COEF_MASK1;
+ isp_reg_writel(dev, coef, OMAP3_ISP_IOMEM_H3A,
+ base_coef_set0);
+ base_coef_set0 += AFCOEF_OFFSET;
- base_coef_set1 = base_coef_set1 + AFCOEF_OFFSET;
+ /*Set IIR Filter1 Coefficients */
+ coef = 0;
+ coef |= isp_af->config.iir_config.coeff_set1[index] &
+ COEF_MASK0;
+ coef |= (isp_af->config.iir_config.coeff_set1[index + 1] <<
+ AF_COEF_SHIFT) & COEF_MASK1;
+ isp_reg_writel(dev, coef, OMAP3_ISP_IOMEM_H3A,
+ base_coef_set1);
+ base_coef_set1 += AFCOEF_OFFSET;
}
- isp_reg_writel(af_dev->config->iir_config.coeff_set1[10],
+ /* set AFCOEF0010 Register */
+ isp_reg_writel(dev, isp_af->config.iir_config.coeff_set0[10],
+ OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010);
+ /* set AFCOEF1010 Register */
+ isp_reg_writel(dev, isp_af->config.iir_config.coeff_set1[10],
OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010);
- return 0;
+ /* PCR Register */
+ /* Set Accumulator Mode */
+ if (isp_af->config.mode == ACCUMULATOR_PEAK)
+ pcr |= FVMODE;
+ /* Set A-law */
+ if (isp_af->config.alaw_enable == H3A_AF_ALAW_ENABLE)
+ pcr |= AF_ALAW_EN;
+ /* Set RGB Position */
+ pcr |= isp_af->config.rgb_pos << AF_RGBPOS_SHIFT;
+ /* HMF Configurations */
+ if (isp_af->config.hmf_config.enable == H3A_AF_HMF_ENABLE) {
+ /* Enable HMF */
+ pcr |= AF_MED_EN;
+ /* Set Median Threshold */
+ pcr |= isp_af->config.hmf_config.threshold << AF_MED_TH_SHIFT;
+ }
+ /* Set PCR Register */
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+ ~AF_PCR_MASK, pcr);
+
+ isp_af->update = 0;
+
+ spin_unlock_irqrestore(isp_af->lock, irqflags);
}
-/* Function to set address */
-void isp_af_set_address(unsigned long address)
+/* Update local parameters */
+static void isp_af_update_params(struct isp_af_device *isp_af,
+ struct af_configuration *afconfig)
{
- isp_reg_writel(address, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFBUFST);
-}
+ int update = 0;
+ int index;
-static int isp_af_stats_available(struct isp_af_data *afdata)
-{
- int i, ret;
- unsigned long irqflags;
+ /* alaw */
+ if (isp_af->config.alaw_enable != afconfig->alaw_enable) {
+ update = 1;
+ goto out;
+ }
- spin_lock_irqsave(&afstat.buffer_lock, irqflags);
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- DPRINTK_ISP_AF("Checking Stats buff[%d] (%d) for %d\n",
- i, afstat.af_buff[i].frame_num,
- afdata->frame_number);
- if (afdata->frame_number == afstat.af_buff[i].frame_num
- && afstat.af_buff[i].frame_num != active_buff->frame_num) {
- afstat.af_buff[i].locked = 1;
- spin_unlock_irqrestore(&afstat.buffer_lock, irqflags);
- isp_af_update_req_buffer(&afstat.af_buff[i]);
- afstat.af_buff[i].frame_num = 0;
- ret = copy_to_user((void *)afdata->af_statistics_buf,
- (void *)afstat.af_buff[i].virt_addr,
- afstat.curr_cfg_buf_size);
- if (ret) {
- printk(KERN_ERR "Failed copy_to_user for "
- "H3A stats buff, %d\n", ret);
- }
- afdata->xtrastats.ts = afstat.af_buff[i].xtrastats.ts;
- afdata->xtrastats.field_count =
- afstat.af_buff[i].xtrastats.field_count;
- return 0;
+ /* hmf */
+ if (isp_af->config.hmf_config.enable != afconfig->hmf_config.enable) {
+ update = 1;
+ goto out;
+ }
+ if (isp_af->config.hmf_config.threshold !=
+ afconfig->hmf_config.threshold) {
+ update = 1;
+ goto out;
+ }
+
+ /* rgbpos */
+ if (isp_af->config.rgb_pos != afconfig->rgb_pos) {
+ update = 1;
+ goto out;
+ }
+
+ /* iir */
+ if (isp_af->config.iir_config.hz_start_pos !=
+ afconfig->iir_config.hz_start_pos) {
+ update = 1;
+ goto out;
+ }
+ for (index = 0; index < AF_NUMBER_OF_COEF; index++) {
+ if (isp_af->config.iir_config.coeff_set0[index] !=
+ afconfig->iir_config.coeff_set0[index]) {
+ update = 1;
+ goto out;
+ }
+ if (isp_af->config.iir_config.coeff_set1[index] !=
+ afconfig->iir_config.coeff_set1[index]) {
+ update = 1;
+ goto out;
}
}
- spin_unlock_irqrestore(&afstat.buffer_lock, irqflags);
- /* Stats unavailable */
- return -1;
-}
+ /* paxel */
+ if ((isp_af->config.paxel_config.width !=
+ afconfig->paxel_config.width) ||
+ (isp_af->config.paxel_config.height !=
+ afconfig->paxel_config.height) ||
+ (isp_af->config.paxel_config.hz_start !=
+ afconfig->paxel_config.hz_start) ||
+ (isp_af->config.paxel_config.vt_start !=
+ afconfig->paxel_config.vt_start) ||
+ (isp_af->config.paxel_config.hz_cnt !=
+ afconfig->paxel_config.hz_cnt) ||
+ (isp_af->config.paxel_config.line_incr !=
+ afconfig->paxel_config.line_incr)) {
+ update = 1;
+ goto out;
+ }
-void isp_af_notify(int notify)
-{
- camnotify = notify;
- if (camnotify && afstat.initialized) {
- printk(KERN_DEBUG "Warning Camera Off \n");
- afstat.stats_req = 0;
- afstat.stats_done = 1;
- wake_up_interruptible(&afstat.stats_wait);
+ /* af_mode */
+ if (isp_af->config.mode != afconfig->mode) {
+ update = 1;
+ goto out;
+ }
+
+ isp_af->config.af_config = afconfig->af_config;
+
+out:
+ if (update) {
+ memcpy(&isp_af->config, afconfig, sizeof(*afconfig));
+ isp_af->update = 1;
}
}
-EXPORT_SYMBOL(isp_af_notify);
+
+void isp_af_try_enable(struct isp_af_device *isp_af)
+{
+ unsigned long irqflags;
+
+ if (!isp_af->config.af_config)
+ return;
+
+ spin_lock_irqsave(isp_af->lock, irqflags);
+ if (unlikely(!isp_af->enabled && isp_af->config.af_config)) {
+ isp_af->update = 1;
+ isp_af->buf_next = ispstat_buf_next(&isp_af->stat);
+ spin_unlock_irqrestore(isp_af->lock, irqflags);
+ isp_af_config_registers(isp_af);
+ isp_af_enable(isp_af, 1);
+ } else
+ spin_unlock_irqrestore(isp_af->lock, irqflags);
+}
+
+/* Function to perform hardware set up */
+int isp_af_config(struct isp_af_device *isp_af,
+ struct af_configuration *afconfig)
+{
+ struct device *dev = to_device(isp_af);
+ int result;
+ int buf_size;
+ unsigned long irqflags;
+
+ if (!afconfig) {
+ dev_dbg(dev, "af: Null argument in configuration.\n");
+ return -EINVAL;
+ }
+
+ /* Check Parameters */
+ spin_lock_irqsave(isp_af->lock, irqflags);
+ result = isp_af_check_params(isp_af, afconfig);
+ spin_unlock_irqrestore(isp_af->lock, irqflags);
+ if (result) {
+ dev_dbg(dev, "af: wrong configure params received.\n");
+ return result;
+ }
+
+ /* Compute buffer size */
+ buf_size = (afconfig->paxel_config.hz_cnt + 1) *
+ (afconfig->paxel_config.vt_cnt + 1) * AF_PAXEL_SIZE;
+
+ result = ispstat_bufs_alloc(&isp_af->stat, buf_size, 0);
+ if (result)
+ return result;
+
+ spin_lock_irqsave(isp_af->lock, irqflags);
+ isp_af_update_params(isp_af, afconfig);
+ spin_unlock_irqrestore(isp_af->lock, irqflags);
+
+ /* Success */
+ return 0;
+}
+EXPORT_SYMBOL(isp_af_config);
+
/*
* This API allows the user to update White Balance gains, as well as
* exposure time and analog gain. It is also used to request frame
* statistics.
*/
-int isp_af_request_statistics(struct isp_af_data *afdata)
+int isp_af_request_statistics(struct isp_af_device *isp_af,
+ struct isp_af_data *afdata)
{
- int ret = 0;
- u16 frame_diff = 0;
- u16 frame_cnt = afstat.frame_count;
- wait_queue_t wqt;
+ struct device *dev = to_device(isp_af);
+ struct ispstat_buffer *buf;
- if (!af_dev_configptr->config->af_config) {
- printk(KERN_ERR "AF engine not enabled\n");
+ if (!isp_af->config.af_config) {
+ dev_dbg(dev, "af: statistics requested while af engine"
+ " is not configured\n");
return -EINVAL;
}
- if (!(afdata->update & REQUEST_STATISTICS)) {
- afdata->af_statistics_buf = NULL;
- goto out;
+ if (afdata->update & REQUEST_STATISTICS) {
+ buf = ispstat_buf_get(&isp_af->stat,
+ (void *)afdata->af_statistics_buf,
+ afdata->frame_number);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ afdata->xtrastats.ts = buf->ts;
+ afdata->config_counter = buf->config_counter;
+ afdata->frame_number = buf->frame_number;
+
+ ispstat_buf_release(&isp_af->stat);
}
- isp_af_unlock_buffers();
- /* Stats available? */
- DPRINTK_ISP_AF("Stats available?\n");
- ret = isp_af_stats_available(afdata);
- if (!ret)
- goto out;
-
- /* Stats in near future? */
- DPRINTK_ISP_AF("Stats in near future?\n");
- if (afdata->frame_number > frame_cnt)
- frame_diff = afdata->frame_number - frame_cnt;
- else if (afdata->frame_number < frame_cnt) {
- if (frame_cnt > MAX_FRAME_COUNT - MAX_FUTURE_FRAMES
- && afdata->frame_number < MAX_FRAME_COUNT) {
- frame_diff = afdata->frame_number + MAX_FRAME_COUNT -
- frame_cnt;
- } else {
- /* Frame unavailable */
- frame_diff = MAX_FUTURE_FRAMES + 1;
- }
- }
-
- if (frame_diff > MAX_FUTURE_FRAMES) {
- printk(KERN_ERR "Invalid frame requested, returning current"
- " frame stats\n");
- afdata->frame_number = frame_cnt;
- }
- if (!camnotify) {
- /* Block until frame in near future completes */
- afstat.frame_req = afdata->frame_number;
- afstat.stats_req = 1;
- afstat.stats_done = 0;
- init_waitqueue_entry(&wqt, current);
- ret = wait_event_interruptible(afstat.stats_wait,
- afstat.stats_done == 1);
- if (ret < 0) {
- afdata->af_statistics_buf = NULL;
- return ret;
- }
- DPRINTK_ISP_AF("ISP AF request status interrupt raised\n");
-
- /* Stats now available */
- ret = isp_af_stats_available(afdata);
- if (ret) {
- printk(KERN_ERR "After waiting for stats, stats not"
- " available!!\n");
- afdata->af_statistics_buf = NULL;
- }
- }
-
-out:
- afdata->curr_frame = afstat.frame_count;
+ afdata->curr_frame = isp_af->stat.frame_number;
return 0;
}
EXPORT_SYMBOL(isp_af_request_statistics);
-/* This function will handle the H3A interrupt. */
-static void isp_af_isr(unsigned long status, isp_vbq_callback_ptr arg1,
- void *arg2)
+/* This function will handle the AF buffer. */
+int isp_af_buf_process(struct isp_af_device *isp_af)
{
- u16 frame_align;
+ if (likely(!isp_af->buf_err && isp_af->config.af_config)) {
+ int ret;
- if ((H3A_AF_DONE & status) != H3A_AF_DONE)
- return;
-
- /* timestamp stats buffer */
- do_gettimeofday(&active_buff->xtrastats.ts);
- active_buff->config_counter = atomic_read(&afstat.config_counter);
-
- /* Exchange buffers */
- active_buff = active_buff->next;
- if (active_buff->locked == 1)
- active_buff = active_buff->next;
- isp_af_set_address(active_buff->ispmmu_addr);
-
- /* Update frame counter */
- afstat.frame_count++;
- frame_align = afstat.frame_count;
- if (afstat.frame_count > MAX_FRAME_COUNT) {
- afstat.frame_count = 1;
- frame_align++;
- }
- active_buff->frame_num = afstat.frame_count;
-
- /* Future Stats requested? */
- if (afstat.stats_req) {
- /* Is the frame we want already done? */
- if (frame_align >= afstat.frame_req + 1) {
- afstat.stats_req = 0;
- afstat.stats_done = 1;
- wake_up_interruptible(&afstat.stats_wait);
- }
+ ret = ispstat_buf_queue(&isp_af->stat);
+ isp_af->buf_next = ispstat_buf_next(&isp_af->stat);
+ return ret;
+ } else {
+ isp_af->buf_err = 0;
+ return -1;
}
}
-int __isp_af_enable(int enable)
+static void __isp_af_enable(struct isp_af_device *isp_af, int enable)
{
+ struct device *dev = to_device(isp_af);
unsigned int pcr;
- pcr = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
+ pcr = isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
/* Set AF_EN bit in PCR Register */
- if (enable) {
- if (isp_set_callback(CBK_H3A_AF_DONE, isp_af_isr,
- (void *)NULL, (void *)NULL)) {
- printk(KERN_ERR "No callback for AF\n");
- return -EINVAL;
- }
-
+ if (enable)
pcr |= AF_EN;
- } else {
- isp_unset_callback(CBK_H3A_AF_DONE);
+ else
pcr &= ~AF_EN;
- }
- isp_reg_writel(pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
- return 0;
+
+ isp_reg_writel(dev, pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
}
/* Function to Enable/Disable AF Engine */
-int isp_af_enable(int enable)
+void isp_af_enable(struct isp_af_device *isp_af, int enable)
{
- int rval;
+ unsigned long irqflags;
- rval = __isp_af_enable(enable);
+ spin_lock_irqsave(isp_af->lock, irqflags);
- if (!rval)
- afstat.pm_state = enable;
+ if (!isp_af->config.af_config && enable) {
+ spin_unlock_irqrestore(isp_af->lock, irqflags);
+ return;
+ }
- return rval;
+ __isp_af_enable(isp_af, enable);
+ isp_af->enabled = enable;
+
+ spin_unlock_irqrestore(isp_af->lock, irqflags);
}
/* Function to Suspend AF Engine */
-void isp_af_suspend(void)
+void isp_af_suspend(struct isp_af_device *isp_af)
{
- if (afstat.pm_state)
- __isp_af_enable(0);
+ unsigned long irqflags;
+
+ spin_lock_irqsave(isp_af->lock, irqflags);
+ if (isp_af->enabled)
+ __isp_af_enable(isp_af, 0);
+ spin_unlock_irqrestore(isp_af->lock, irqflags);
}
/* Function to Resume AF Engine */
-void isp_af_resume(void)
+void isp_af_resume(struct isp_af_device *isp_af)
{
- if (afstat.pm_state)
- __isp_af_enable(1);
+ unsigned long irqflags;
+
+ spin_lock_irqsave(isp_af->lock, irqflags);
+ if (isp_af->enabled)
+ __isp_af_enable(isp_af, 1);
+ spin_unlock_irqrestore(isp_af->lock, irqflags);
}
-int isp_af_busy(void)
+int isp_af_busy(struct isp_af_device *isp_af)
{
- return isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
+ struct device *dev = to_device(isp_af);
+
+ return isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
& ISPH3A_PCR_BUSYAF;
}
/* Function to register the AF character device driver. */
-int __init isp_af_init(void)
+int __init isp_af_init(struct device *dev)
{
- /*allocate memory for device structure and initialize it with 0 */
- af_dev_configptr = kzalloc(sizeof(struct af_device), GFP_KERNEL);
- if (!af_dev_configptr)
- goto err_nomem1;
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_af_device *isp_af = &isp->isp_af;
- active_buff = NULL;
-
- af_dev_configptr->config = (struct af_configuration *)
- kzalloc(sizeof(struct af_configuration), GFP_KERNEL);
-
- if (af_dev_configptr->config == NULL)
- goto err_nomem2;
-
- memset(&afstat, 0, sizeof(afstat));
-
- init_waitqueue_head(&afstat.stats_wait);
- spin_lock_init(&afstat.buffer_lock);
+ isp_af->lock = &isp->h3a_lock;
+ ispstat_init(dev, "AF", &isp_af->stat, H3A_MAX_BUFF, MAX_FRAME_COUNT);
return 0;
-
-err_nomem2:
- kfree(af_dev_configptr);
-err_nomem1:
- printk(KERN_ERR "Error: kmalloc fail");
- return -ENOMEM;
}
-void isp_af_exit(void)
+void isp_af_exit(struct device *dev)
{
- int i;
+ struct isp_device *isp = dev_get_drvdata(dev);
/* Free buffers */
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- if (!afstat.af_buff[i].phy_addr)
- continue;
-
- ispmmu_kunmap(afstat.af_buff[i].ispmmu_addr);
-
- dma_free_coherent(NULL,
- afstat.min_buf_size,
- (void *)afstat.af_buff[i].virt_addr,
- (dma_addr_t)afstat.af_buff[i].phy_addr);
- }
- kfree(af_dev_configptr->config);
- kfree(af_dev_configptr);
-
- memset(&afstat, 0, sizeof(afstat));
-
- af_major = -1;
+ ispstat_free(&isp->isp_af.stat);
}
diff --git a/drivers/media/video/isp/isp_af.h b/drivers/media/video/isp/isp_af.h
index ee2b89f..fbdafdb 100644
--- a/drivers/media/video/isp/isp_af.h
+++ b/drivers/media/video/isp/isp_af.h
@@ -24,6 +24,9 @@
#include <mach/isp_user.h>
+#include "isph3a.h"
+#include "ispstat.h"
+
#define AF_MAJOR_NUMBER 0
#define ISPAF_NAME "OMAPISP_AF"
#define AF_NR_DEVS 1
@@ -64,6 +67,8 @@
#define AF_MED_EN (1 << 2)
#define AF_ALAW_EN (1 << 1)
#define AF_EN (1 << 0)
+#define AF_PCR_MASK (FVMODE | RGBPOS | MED_TH | \
+ AF_MED_EN | AF_ALAW_EN)
/*
* AFPAX1 fields
@@ -104,22 +109,29 @@
#define AF_UPDATEXS_FIELDCOUNT (1 << 1)
#define AF_UPDATEXS_LENSPOS (1 << 2)
-/* Structure for device of AF Engine */
-struct af_device {
- struct af_configuration *config; /*Device configuration structure */
- int size_paxel; /*Paxel size in bytes */
+/**
+ * struct isp_af_status - AF status.
+ * @update: 1 - Update registers.
+ */
+struct isp_af_device {
+ u8 update;
+ u8 buf_err;
+ int enabled;
+ struct ispstat stat;
+ struct af_configuration config; /*Device configuration structure */
+ struct ispstat_buffer *buf_next;
+ spinlock_t *lock;
};
-int isp_af_check_paxel(void);
-int isp_af_check_iir(void);
-int isp_af_register_setup(struct af_device *af_dev);
-int isp_af_enable(int);
-void isp_af_suspend(void);
-void isp_af_resume(void);
-int isp_af_busy(void);
-void isp_af_notify(int notify);
-int isp_af_request_statistics(struct isp_af_data *afdata);
-int isp_af_configure(struct af_configuration *afconfig);
-void isp_af_set_address(unsigned long);
-void isp_af_setxtrastats(struct isp_af_xtrastats *xtrastats, u8 updateflag);
+int isp_af_buf_process(struct isp_af_device *isp_af);
+void isp_af_enable(struct isp_af_device *, int);
+void isp_af_try_enable(struct isp_af_device *isp_af);
+void isp_af_suspend(struct isp_af_device *);
+void isp_af_resume(struct isp_af_device *);
+int isp_af_busy(struct isp_af_device *);
+void isp_af_config_registers(struct isp_af_device *isp_af);
+int isp_af_request_statistics(struct isp_af_device *,
+ struct isp_af_data *afdata);
+int isp_af_config(struct isp_af_device *, struct af_configuration *afconfig);
+
#endif /* OMAP_ISP_AF_H */
diff --git a/drivers/media/video/isp/ispccdc.c b/drivers/media/video/isp/ispccdc.c
index 557db28..bde91ab 100644
--- a/drivers/media/video/isp/ispccdc.c
+++ b/drivers/media/video/isp/ispccdc.c
@@ -22,70 +22,15 @@
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/device.h>
#include "isp.h"
#include "ispreg.h"
#include "ispccdc.h"
-#include "ispmmu.h"
#define LSC_TABLE_INIT_SIZE 50052
-
-static u32 *fpc_table_add;
-static unsigned long fpc_table_add_m;
-
-/**
- * struct isp_ccdc - Structure for the CCDC module to store its own information
- * @ccdc_inuse: Flag to determine if CCDC has been reserved or not (0 or 1).
- * @ccdcout_w: CCDC output width.
- * @ccdcout_h: CCDC output height.
- * @ccdcin_w: CCDC input width.
- * @ccdcin_h: CCDC input height.
- * @ccdcin_woffset: CCDC input horizontal offset.
- * @ccdcin_hoffset: CCDC input vertical offset.
- * @crop_w: Crop width.
- * @crop_h: Crop weight.
- * @ccdc_inpfmt: CCDC input format.
- * @ccdc_outfmt: CCDC output format.
- * @vpout_en: Video port output enable.
- * @wen: Data write enable.
- * @exwen: External data write enable.
- * @refmt_en: Reformatter enable.
- * @ccdcslave: CCDC slave mode enable.
- * @syncif_ipmod: Image
- * @obclamp_en: Data input format.
- * @mutexlock: Mutex used to get access to the CCDC.
- */
-static struct isp_ccdc {
- u8 ccdc_inuse;
- u32 ccdcout_w;
- u32 ccdcout_h;
- u32 ccdcin_w;
- u32 ccdcin_h;
- u32 ccdcin_woffset;
- u32 ccdcin_hoffset;
- u32 crop_w;
- u32 crop_h;
- u8 ccdc_inpfmt;
- u8 ccdc_outfmt;
- u8 vpout_en;
- u8 wen;
- u8 exwen;
- u8 refmt_en;
- u8 ccdcslave;
- u8 syncif_ipmod;
- u8 obclamp_en;
- u8 pm_state;
- u8 lsc_enable;
- int lsc_state;
- struct mutex mutexlock; /* For checking/modifying ccdc_inuse */
- u32 wenlog;
-} ispccdc_obj;
-
-static struct ispccdc_lsc_config lsc_config;
-static u8 *lsc_gain_table;
-static unsigned long lsc_ispmmu_addr;
-static int lsc_initialized;
-static u8 *lsc_gain_table_tmp;
+#define PTR_FREE ((u32)(-ENOMEM))
/* Structure for saving/restoring CCDC module registers*/
static struct isp_reg ispccdc_reg_list[] = {
@@ -103,8 +48,8 @@
{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB, 0},
{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN, 0},
{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP, 0},
- {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, 0},
{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC_ADDR, 0},
+ {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, 0},
{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT, 0},
{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW, 0},
{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, 0},
@@ -133,420 +78,617 @@
};
/**
- * omap34xx_isp_ccdc_config - Sets CCDC configuration from userspace
- * @userspace_add: Structure containing CCDC configuration sent from userspace.
+ * ispccdc_print_status - Print current CCDC Module register values.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @pipe: Pointer to current ISP pipeline structure.
*
- * Returns 0 if successful, -EINVAL if the pointer to the configuration
- * structure is null, or the copy_from_user function fails to copy user space
- * memory to kernel space memory.
+ * Also prints other debug information stored in the CCDC module.
**/
-int omap34xx_isp_ccdc_config(void *userspace_add)
+static void ispccdc_print_status(struct isp_ccdc_device *isp_ccdc,
+ struct isp_pipeline *pipe)
{
- struct ispccdc_bclamp bclamp_t;
- struct ispccdc_blcomp blcomp_t;
- struct ispccdc_fpc fpc_t;
- struct ispccdc_culling cull_t;
- struct ispccdc_update_config *ccdc_struct;
+#ifdef OMAP_ISPCCDC_DEBUG
+ struct device *dev = to_device(isp_ccdc);
+#endif
- if (userspace_add == NULL)
- return -EINVAL;
+ if (!is_ispccdc_debug_enabled())
+ return;
- ccdc_struct = userspace_add;
+ DPRINTK_ISPCCDC("Module in use =%d\n", isp_ccdc->ccdc_inuse);
+ DPRINTK_ISPCCDC("Accepted CCDC Input (width = %d,Height = %d)\n",
+ pipe->ccdc_in_w,
+ pipe->ccdc_in_h);
+ DPRINTK_ISPCCDC("Accepted CCDC Output (width = %d,Height = %d)\n",
+ pipe->ccdc_out_w,
+ pipe->ccdc_out_h);
+ DPRINTK_ISPCCDC("###CCDC PCR=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_PCR));
+ DPRINTK_ISPCCDC("ISP_CTRL =0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_CTRL));
+ switch (pipe->ccdc_in) {
+ case CCDC_RAW_GRBG:
+ case CCDC_RAW_RGGB:
+ case CCDC_RAW_BGGR:
+ case CCDC_RAW_GBRG:
+ DPRINTK_ISPCCDC("ccdc input format is CCDC_RAW\n");
+ break;
+ case CCDC_YUV_SYNC:
+ DPRINTK_ISPCCDC("ccdc input format is CCDC_YUV_SYNC\n");
+ break;
+ case CCDC_YUV_BT:
+ DPRINTK_ISPCCDC("ccdc input format is CCDC_YUV_BT\n");
+ break;
+ default:
+ break;
+ }
- if (ISP_ABS_CCDC_ALAW & ccdc_struct->flag) {
- if (ISP_ABS_CCDC_ALAW & ccdc_struct->update)
- ispccdc_config_alaw(ccdc_struct->alawip);
- ispccdc_enable_alaw(1);
- } else if (ISP_ABS_CCDC_ALAW & ccdc_struct->update)
- ispccdc_enable_alaw(0);
+ switch (pipe->ccdc_out) {
+ case CCDC_OTHERS_VP:
+ DPRINTK_ISPCCDC("ccdc output format is CCDC_OTHERS_VP\n");
+ break;
+ case CCDC_OTHERS_MEM:
+ DPRINTK_ISPCCDC("ccdc output format is CCDC_OTHERS_MEM\n");
+ break;
+ case CCDC_YUV_RSZ:
+ DPRINTK_ISPCCDC("ccdc output format is CCDC_YUV_RSZ\n");
+ break;
+ default:
+ break;
+ }
- if (ISP_ABS_CCDC_LPF & ccdc_struct->flag)
- ispccdc_enable_lpf(1);
- else
- ispccdc_enable_lpf(0);
+ DPRINTK_ISPCCDC("###ISP_CTRL in ccdc =0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_CTRL));
+ DPRINTK_ISPCCDC("###ISP_IRQ0ENABLE in ccdc =0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_IRQ0ENABLE));
+ DPRINTK_ISPCCDC("###ISP_IRQ0STATUS in ccdc =0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_IRQ0STATUS));
+ DPRINTK_ISPCCDC("###CCDC SYN_MODE=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SYN_MODE));
+ DPRINTK_ISPCCDC("###CCDC HORZ_INFO=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_HORZ_INFO));
+ DPRINTK_ISPCCDC("###CCDC VERT_START=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_VERT_START));
+ DPRINTK_ISPCCDC("###CCDC VERT_LINES=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_VERT_LINES));
+ DPRINTK_ISPCCDC("###CCDC CULLING=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_CULLING));
+ DPRINTK_ISPCCDC("###CCDC HSIZE_OFF=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_HSIZE_OFF));
+ DPRINTK_ISPCCDC("###CCDC SDOFST=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SDOFST));
+ DPRINTK_ISPCCDC("###CCDC SDR_ADDR=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SDR_ADDR));
+ DPRINTK_ISPCCDC("###CCDC CLAMP=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_CLAMP));
+ DPRINTK_ISPCCDC("###CCDC COLPTN=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_COLPTN));
+ DPRINTK_ISPCCDC("###CCDC CFG=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_CFG));
+ DPRINTK_ISPCCDC("###CCDC VP_OUT=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_VP_OUT));
+ DPRINTK_ISPCCDC("###CCDC_SDR_ADDR= 0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SDR_ADDR));
+ DPRINTK_ISPCCDC("###CCDC FMTCFG=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_FMTCFG));
+ DPRINTK_ISPCCDC("###CCDC FMT_HORZ=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_FMT_HORZ));
+ DPRINTK_ISPCCDC("###CCDC FMT_VERT=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_FMT_VERT));
+ DPRINTK_ISPCCDC("###CCDC LSC_CONFIG=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_LSC_CONFIG));
+ DPRINTK_ISPCCDC("###CCDC LSC_INIT=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_LSC_INITIAL));
+ DPRINTK_ISPCCDC("###CCDC LSC_TABLE BASE=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_LSC_TABLE_BASE));
+ DPRINTK_ISPCCDC("###CCDC LSC TABLE OFFSET=0x%x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_LSC_TABLE_OFFSET));
+}
- if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->flag) {
- if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->update) {
- if (copy_from_user(&bclamp_t, (struct ispccdc_bclamp *)
- ccdc_struct->bclamp,
- sizeof(struct ispccdc_bclamp)))
- goto copy_from_user_err;
+/**
+ * ispccdc_config_black_clamp - Configures the clamp parameters in CCDC.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @bclamp: Structure containing the optical black average gain, optical black
+ * sample length, sample lines, and the start pixel position of the
+ * samples w.r.t the HS pulse.
+ *
+ * Configures the clamp parameters in CCDC. Either if its being used the
+ * optical black clamp, or the digital clamp. If its a digital clamp, then
+ * assures to put a valid DC substraction level.
+ *
+ * Returns always 0 when completed.
+ **/
+static int ispccdc_config_black_clamp(struct isp_ccdc_device *isp_ccdc,
+ struct ispccdc_bclamp bclamp)
+{
+ struct device *dev = to_device(isp_ccdc);
+ u32 bclamp_val = 0;
- ispccdc_enable_black_clamp(1);
- ispccdc_config_black_clamp(bclamp_t);
- } else
- ispccdc_enable_black_clamp(1);
+ if (isp_ccdc->obclamp_en) {
+ bclamp_val |= bclamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT;
+ bclamp_val |= bclamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT;
+ bclamp_val |= bclamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT;
+ bclamp_val |= bclamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT;
+ isp_reg_writel(dev, bclamp_val,
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP);
} else {
- if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->update) {
- if (copy_from_user(&bclamp_t, (struct ispccdc_bclamp *)
- ccdc_struct->bclamp,
- sizeof(struct ispccdc_bclamp)))
- goto copy_from_user_err;
-
- ispccdc_enable_black_clamp(0);
- ispccdc_config_black_clamp(bclamp_t);
- }
+ if (omap_rev() < OMAP3430_REV_ES2_0)
+ if (isp_ccdc->syncif_ipmod == YUV16 ||
+ isp_ccdc->syncif_ipmod == YUV8 ||
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_REC656IF) &
+ ISPCCDC_REC656IF_R656ON)
+ bclamp.dcsubval = 0;
+ isp_reg_writel(dev, bclamp.dcsubval,
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB);
}
-
- if (ISP_ABS_CCDC_BCOMP & ccdc_struct->update) {
- if (copy_from_user(&blcomp_t, (struct ispccdc_blcomp *)
- ccdc_struct->blcomp,
- sizeof(blcomp_t)))
- goto copy_from_user_err;
-
- ispccdc_config_black_comp(blcomp_t);
- }
-
- if (ISP_ABS_CCDC_FPC & ccdc_struct->flag) {
- if (ISP_ABS_CCDC_FPC & ccdc_struct->update) {
- if (copy_from_user(&fpc_t, (struct ispccdc_fpc *)
- ccdc_struct->fpc,
- sizeof(fpc_t)))
- goto copy_from_user_err;
- fpc_table_add = kmalloc(64 + fpc_t.fpnum * 4,
- GFP_KERNEL | GFP_DMA);
- if (!fpc_table_add) {
- printk(KERN_ERR "Cannot allocate memory for"
- " FPC table");
- return -ENOMEM;
- }
- while (((unsigned long)fpc_table_add & 0xFFFFFFC0)
- != (unsigned long)fpc_table_add)
- fpc_table_add++;
-
- fpc_table_add_m = ispmmu_kmap(virt_to_phys
- (fpc_table_add),
- fpc_t.fpnum * 4);
-
- if (copy_from_user(fpc_table_add, (u32 *)fpc_t.fpcaddr,
- fpc_t.fpnum * 4))
- goto copy_from_user_err;
-
- fpc_t.fpcaddr = fpc_table_add_m;
- ispccdc_config_fpc(fpc_t);
- }
- ispccdc_enable_fpc(1);
- } else if (ISP_ABS_CCDC_FPC & ccdc_struct->update)
- ispccdc_enable_fpc(0);
-
- if (ISP_ABS_CCDC_CULL & ccdc_struct->update) {
- if (copy_from_user(&cull_t, (struct ispccdc_culling *)
- ccdc_struct->cull,
- sizeof(cull_t)))
- goto copy_from_user_err;
- ispccdc_config_culling(cull_t);
- }
-
- if (is_isplsc_activated()) {
- if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->flag) {
- if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->update) {
- if (copy_from_user(
- &lsc_config,
- (struct ispccdc_lsc_config *)
- ccdc_struct->lsc_cfg,
- sizeof(struct ispccdc_lsc_config)))
- goto copy_from_user_err;
- ispccdc_config_lsc(&lsc_config);
- }
- ispccdc_enable_lsc(1);
- } else if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->update) {
- ispccdc_enable_lsc(0);
- }
- if (ISP_ABS_TBL_LSC & ccdc_struct->update) {
- if (copy_from_user(lsc_gain_table,
- ccdc_struct->lsc, lsc_config.size))
- goto copy_from_user_err;
- ispccdc_load_lsc(lsc_gain_table, lsc_config.size);
- }
- }
-
- if (ISP_ABS_CCDC_COLPTN & ccdc_struct->update)
- ispccdc_config_imgattr(ccdc_struct->colptn);
-
- return 0;
-
-copy_from_user_err:
- printk(KERN_ERR "CCDC Config:Copy From User Error");
- return -EINVAL ;
-}
-EXPORT_SYMBOL(omap34xx_isp_ccdc_config);
-
-/**
- * Set the value to be used for CCDC_CFG.WENLOG.
- * w - Value of wenlog.
- */
-void ispccdc_set_wenlog(u32 wenlog)
-{
- ispccdc_obj.wenlog = wenlog;
-}
-EXPORT_SYMBOL(ispccdc_set_wenlog);
-
-/**
- * ispccdc_set_crop_offset - Store the component order as component offset.
- * @raw_fmt: Input data component order.
- *
- * Turns the component order into a horizontal & vertical offset and store
- * offsets to be used later.
- **/
-void ispccdc_set_crop_offset(enum ispccdc_raw_fmt raw_fmt)
-{
- switch (raw_fmt) {
- case ISPCCDC_INPUT_FMT_GR_BG:
- ispccdc_obj.ccdcin_woffset = 1;
- ispccdc_obj.ccdcin_hoffset = 0;
- break;
- case ISPCCDC_INPUT_FMT_BG_GR:
- ispccdc_obj.ccdcin_woffset = 1;
- ispccdc_obj.ccdcin_hoffset = 1;
- break;
- case ISPCCDC_INPUT_FMT_RG_GB:
- ispccdc_obj.ccdcin_woffset = 0;
- ispccdc_obj.ccdcin_hoffset = 0;
- break;
- case ISPCCDC_INPUT_FMT_GB_RG:
- ispccdc_obj.ccdcin_woffset = 0;
- ispccdc_obj.ccdcin_hoffset = 1;
- break;
- }
-}
-EXPORT_SYMBOL(ispccdc_set_crop_offset);
-
-/**
- * ispccdc_request - Reserves the CCDC module.
- *
- * Reserves the CCDC module and assures that is used only once at a time.
- *
- * Returns 0 if successful, or -EBUSY if CCDC module is busy.
- **/
-int ispccdc_request(void)
-{
- mutex_lock(&ispccdc_obj.mutexlock);
- if (ispccdc_obj.ccdc_inuse) {
- mutex_unlock(&ispccdc_obj.mutexlock);
- DPRINTK_ISPCCDC("ISP_ERR : CCDC Module Busy\n");
- return -EBUSY;
- }
-
- ispccdc_obj.ccdc_inuse = 1;
- mutex_unlock(&ispccdc_obj.mutexlock);
- isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, ISPCTRL_CCDC_RAM_EN |
- ISPCTRL_CCDC_CLK_EN |
- ISPCTRL_SBL_WR1_RAM_EN);
- isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_VDLC);
return 0;
}
-EXPORT_SYMBOL(ispccdc_request);
/**
- * ispccdc_free - Frees the CCDC module.
+ * ispccdc_enable_black_clamp - Enables/Disables the optical black clamp.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables optical black clamp, 1 Enables optical black clamp.
*
- * Frees the CCDC module so it can be used by another process.
- *
- * Returns 0 if successful, or -EINVAL if module has been already freed.
+ * Enables or disables the optical black clamp. When disabled, the digital
+ * clamp operates.
**/
-int ispccdc_free(void)
+static void ispccdc_enable_black_clamp(struct isp_ccdc_device *isp_ccdc,
+ u8 enable)
{
- mutex_lock(&ispccdc_obj.mutexlock);
- if (!ispccdc_obj.ccdc_inuse) {
- mutex_unlock(&ispccdc_obj.mutexlock);
- DPRINTK_ISPCCDC("ISP_ERR: CCDC Module already freed\n");
+ struct device *dev = to_device(isp_ccdc);
+
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP,
+ ~ISPCCDC_CLAMP_CLAMPEN,
+ enable ? ISPCCDC_CLAMP_CLAMPEN : 0);
+ isp_ccdc->obclamp_en = enable;
+}
+
+/**
+ * ispccdc_config_fpc - Configures the Faulty Pixel Correction parameters.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @fpc: Structure containing the number of faulty pixels corrected in the
+ * frame, address of the FPC table.
+ *
+ * Returns 0 if successful, or -EINVAL if FPC Address is not on the 64 byte
+ * boundary.
+ **/
+static int ispccdc_config_fpc(struct isp_ccdc_device *isp_ccdc,
+ struct ispccdc_fpc fpc)
+{
+ struct device *dev = to_device(isp_ccdc);
+ u32 fpc_val = 0;
+
+ fpc_val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_FPC);
+
+ if ((fpc.fpcaddr & 0xFFFFFFC0) == fpc.fpcaddr) {
+ isp_reg_writel(dev, fpc_val & (~ISPCCDC_FPC_FPCEN),
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+ isp_reg_writel(dev, fpc.fpcaddr,
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC_ADDR);
+ } else {
+ DPRINTK_ISPCCDC("FPC Address should be on 64byte boundary\n");
+ return -EINVAL;
+ }
+ isp_reg_writel(dev, fpc_val |
+ (fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT),
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+ return 0;
+}
+
+/**
+ * ispccdc_enable_fpc - Enable Faulty Pixel Correction.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables FPC, 1 Enables FPC.
+ **/
+static void ispccdc_enable_fpc(struct isp_ccdc_device *isp_ccdc, u8 enable)
+{
+ struct device *dev = to_device(isp_ccdc);
+
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC,
+ ~ISPCCDC_FPC_FPCEN,
+ enable ? ISPCCDC_FPC_FPCEN : 0);
+}
+
+/**
+ * ispccdc_config_black_comp - Configure Black Level Compensation.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @blcomp: Structure containing the black level compensation value for RGrGbB
+ * pixels. in 2's complement.
+ **/
+static void ispccdc_config_black_comp(struct isp_ccdc_device *isp_ccdc,
+ struct ispccdc_blcomp blcomp)
+{
+ struct device *dev = to_device(isp_ccdc);
+ u32 blcomp_val = 0;
+
+ blcomp_val |= blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT;
+ blcomp_val |= blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT;
+ blcomp_val |= blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT;
+ blcomp_val |= blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT;
+
+ isp_reg_writel(dev, blcomp_val, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_BLKCMP);
+}
+
+/**
+ * ispccdc_config_vp - Configure the Video Port.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @vpcfg: Structure containing the Video Port input frequency, and the 10 bit
+ * format.
+ **/
+static void ispccdc_config_vp(struct isp_ccdc_device *isp_ccdc,
+ struct ispccdc_vp vpcfg)
+{
+ struct device *dev = to_device(isp_ccdc);
+ u32 fmtcfg_vp = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_FMTCFG);
+
+ fmtcfg_vp &= ISPCCDC_FMTCFG_VPIN_MASK & ISPCCDC_FMTCFG_VPIF_FRQ_MASK;
+
+ switch (vpcfg.bitshift_sel) {
+ case BIT9_0:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
+ break;
+ case BIT10_1:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
+ break;
+ case BIT11_2:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
+ break;
+ case BIT12_3:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
+ break;
+ };
+ switch (vpcfg.freq_sel) {
+ case PIXCLKBY2:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY2;
+ break;
+ case PIXCLKBY3_5:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY3;
+ break;
+ case PIXCLKBY4_5:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY4;
+ break;
+ case PIXCLKBY5_5:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY5;
+ break;
+ case PIXCLKBY6_5:
+ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY6;
+ break;
+ };
+ isp_reg_writel(dev, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_FMTCFG);
+}
+
+/**
+ * ispccdc_enable_vp - Enable Video Port.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables VP, 1 Enables VP
+ *
+ * This is needed for outputting image to Preview, H3A and HIST ISP submodules.
+ **/
+static void ispccdc_enable_vp(struct isp_ccdc_device *isp_ccdc, u8 enable)
+{
+ struct device *dev = to_device(isp_ccdc);
+
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
+ ~ISPCCDC_FMTCFG_VPEN,
+ enable ? ISPCCDC_FMTCFG_VPEN : 0);
+}
+
+/**
+ * ispccdc_config_culling - Configure culling parameters.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @cull: Structure containing the vertical culling pattern, and horizontal
+ * culling pattern for odd and even lines.
+ **/
+static void ispccdc_config_culling(struct isp_ccdc_device *isp_ccdc,
+ struct ispccdc_culling cull)
+{
+ struct device *dev = to_device(isp_ccdc);
+ u32 culling_val = 0;
+
+ culling_val |= cull.v_pattern << ISPCCDC_CULLING_CULV_SHIFT;
+ culling_val |= cull.h_even << ISPCCDC_CULLING_CULHEVN_SHIFT;
+ culling_val |= cull.h_odd << ISPCCDC_CULLING_CULHODD_SHIFT;
+
+ isp_reg_writel(dev, culling_val, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_CULLING);
+}
+
+/**
+ * ispccdc_enable_lpf - Enable Low-Pass Filter (LPF).
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables LPF, 1 Enables LPF
+ **/
+static void ispccdc_enable_lpf(struct isp_ccdc_device *isp_ccdc, u8 enable)
+{
+ struct device *dev = to_device(isp_ccdc);
+
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE,
+ ~ISPCCDC_SYN_MODE_LPF,
+ enable ? ISPCCDC_SYN_MODE_LPF : 0);
+}
+
+/**
+ * ispccdc_config_alaw - Configure the input width for A-law compression.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @ipwidth: Input width for A-law
+ **/
+static void ispccdc_config_alaw(struct isp_ccdc_device *isp_ccdc,
+ enum alaw_ipwidth ipwidth)
+{
+ struct device *dev = to_device(isp_ccdc);
+
+ isp_reg_writel(dev, ipwidth << ISPCCDC_ALAW_GWDI_SHIFT,
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW);
+}
+
+/**
+ * ispccdc_enable_alaw - Enable A-law compression.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 - Disables A-law, 1 - Enables A-law
+ **/
+static void ispccdc_enable_alaw(struct isp_ccdc_device *isp_ccdc, u8 enable)
+{
+ struct device *dev = to_device(isp_ccdc);
+
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW,
+ ~ISPCCDC_ALAW_CCDTBL,
+ enable ? ISPCCDC_ALAW_CCDTBL : 0);
+}
+
+/**
+ * ispccdc_config_imgattr - Configure sensor image specific attributes.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @colptn: Color pattern of the sensor.
+ **/
+static void ispccdc_config_imgattr(struct isp_ccdc_device *isp_ccdc, u32 colptn)
+{
+ struct device *dev = to_device(isp_ccdc);
+
+ isp_reg_writel(dev, colptn, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_COLPTN);
+}
+
+/**
+ * ispccdc_validate_config_lsc - Check that LSC configuration is valid.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @lsc_cfg: the LSC configuration to check.
+ * @pipe: if not NULL, verify the table size against CCDC input size.
+ *
+ * Returns 0 if the LSC configuration is valid, or -EINVAL if invalid.
+ **/
+static int ispccdc_validate_config_lsc(struct isp_ccdc_device *isp_ccdc,
+ struct ispccdc_lsc_config *lsc_cfg)
+{
+ struct isp_device *isp = to_isp_device(isp_ccdc);
+ struct device *dev = to_device(isp_ccdc);
+ unsigned int paxel_width, paxel_height;
+ unsigned int paxel_shift_x, paxel_shift_y;
+ unsigned int min_width, min_height, min_size;
+ unsigned int input_width, input_height;
+
+ paxel_shift_x = lsc_cfg->gain_mode_m;
+ paxel_shift_y = lsc_cfg->gain_mode_n;
+
+ if ((paxel_shift_x < 2) || (paxel_shift_x > 6) ||
+ (paxel_shift_y < 2) || (paxel_shift_y > 6)) {
+ dev_err(dev, "CCDC: LSC: Invalid paxel size\n");
return -EINVAL;
}
- ispccdc_obj.ccdc_inuse = 0;
- mutex_unlock(&ispccdc_obj.mutexlock);
- isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
- ~(ISPCTRL_CCDC_CLK_EN |
- ISPCTRL_CCDC_RAM_EN |
- ISPCTRL_SBL_WR1_RAM_EN));
- return 0;
-}
-EXPORT_SYMBOL(ispccdc_free);
-
-/**
- * ispccdc_free_lsc - Frees Lens Shading Compensation table
- *
- * Always returns 0.
- **/
-static int ispccdc_free_lsc(void)
-{
- if (!lsc_ispmmu_addr)
- return 0;
-
- ispccdc_enable_lsc(0);
- lsc_initialized = 0;
- isp_reg_writel(0, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE);
- ispmmu_kunmap(lsc_ispmmu_addr);
- kfree(lsc_gain_table);
- return 0;
-}
-
-/**
- * ispccdc_allocate_lsc - Allocate space for Lens Shading Compensation table
- * @table_size: LSC gain table size.
- *
- * Returns 0 if successful, -ENOMEM of its no memory available, or -EINVAL if
- * table_size is zero.
- **/
-static int ispccdc_allocate_lsc(u32 table_size)
-{
- if (table_size == 0)
+ if (lsc_cfg->offset & 3) {
+ dev_err(dev,
+ "CCDC: LSC: Offset must be a multiple of 4\n");
return -EINVAL;
-
- if ((lsc_config.size >= table_size) && lsc_gain_table)
- return 0;
-
- ispccdc_free_lsc();
-
- lsc_gain_table = kmalloc(table_size, GFP_KERNEL | GFP_DMA);
-
- if (!lsc_gain_table) {
- printk(KERN_ERR "Cannot allocate memory for gain tables \n");
- return -ENOMEM;
}
- lsc_ispmmu_addr = ispmmu_kmap(virt_to_phys(lsc_gain_table), table_size);
- if (lsc_ispmmu_addr <= 0) {
- printk(KERN_ERR "Cannot map memory for gain tables \n");
- kfree(lsc_gain_table);
- return -ENOMEM;
+ if ((lsc_cfg->initial_x & 1) || (lsc_cfg->initial_y & 1)) {
+ dev_err(dev,
+ "CCDC: LSC: initial_x and y must be even\n");
+ return -EINVAL;
}
+ input_width = isp->pipeline.ccdc_in_w;
+ input_height = isp->pipeline.ccdc_in_h;
+
+ /* Calculate minimum bytesize for validation */
+ paxel_width = 1 << paxel_shift_x;
+ min_width = ((input_width + lsc_cfg->initial_x + paxel_width - 1)
+ >> paxel_shift_x) + 1;
+
+ paxel_height = 1 << paxel_shift_y;
+ min_height = ((input_height + lsc_cfg->initial_y + paxel_height - 1)
+ >> paxel_shift_y) + 1;
+
+ min_size = 4 * min_width * min_height;
+ if (min_size > lsc_cfg->size) {
+ dev_err(dev, "CCDC: LSC: too small table\n");
+ return -EINVAL;
+ }
+ if (lsc_cfg->offset < (min_width * 4)) {
+ dev_err(dev, "CCDC: LSC: Offset is too small\n");
+ return -EINVAL;
+ }
+ if ((lsc_cfg->size / lsc_cfg->offset) < min_height) {
+ dev_err(dev, "CCDC: LSC: Wrong size/offset combination\n");
+ return -EINVAL;
+ }
return 0;
}
/**
- * ispccdc_program_lsc - Program Lens Shading Compensation table.
- * @table_size: LSC gain table size.
- *
- * Returns 0 if successful, or -EINVAL if there's no mapped address for the
- * table yet.
+ * ispccdc_program_lsc - Program Lens Shading Compensation table address.
+ * @isp_ccdc: Pointer to ISP CCDC device.
**/
-static int ispccdc_program_lsc(void)
+static void ispccdc_program_lsc(struct isp_ccdc_device *isp_ccdc)
{
- if (!lsc_ispmmu_addr)
- return -EINVAL;
+ struct device *dev = to_device(isp_ccdc);
- if (lsc_initialized)
- return 0;
-
- isp_reg_writel(lsc_ispmmu_addr, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_LSC_TABLE_BASE);
- lsc_initialized = 1;
- return 0;
+ isp_reg_writel(dev, isp_ccdc->lsc_table_inuse,
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE);
}
/**
- * ispccdc_load_lsc - Load Lens Shading Compensation table.
- * @table_addr: LSC gain table MMU Mapped address.
- * @table_size: LSC gain table size.
- *
- * Returns 0 if successful, -ENOMEM of its no memory available, or -EINVAL if
- * table_size is zero.
- **/
-int ispccdc_load_lsc(u8 *table_addr, u32 table_size)
-{
- int ret;
-
- if (!is_isplsc_activated())
- return 0;
-
- if (!table_addr)
- return -EINVAL;
-
- ret = ispccdc_allocate_lsc(table_size);
- if (ret)
- return ret;
-
- if (table_addr != lsc_gain_table)
- memcpy(lsc_gain_table, table_addr, table_size);
- ret = ispccdc_program_lsc();
- if (ret)
- return ret;
- return 0;
-}
-EXPORT_SYMBOL(ispccdc_load_lsc);
-
-/**
* ispccdc_config_lsc - Configures the lens shading compensation module
- * @lsc_cfg: LSC configuration structure
+ * @isp_ccdc: Pointer to ISP CCDC device.
**/
-void ispccdc_config_lsc(struct ispccdc_lsc_config *lsc_cfg)
+static void ispccdc_config_lsc(struct isp_ccdc_device *isp_ccdc)
{
+ struct device *dev = to_device(isp_ccdc);
+ struct ispccdc_lsc_config *lsc_cfg = &isp_ccdc->lsc_config;
int reg;
- if (!is_isplsc_activated())
- return;
-
- ispccdc_enable_lsc(0);
- isp_reg_writel(lsc_cfg->offset, OMAP3_ISP_IOMEM_CCDC,
+ isp_reg_writel(dev, lsc_cfg->offset, OMAP3_ISP_IOMEM_CCDC,
ISPCCDC_LSC_TABLE_OFFSET);
reg = 0;
reg |= lsc_cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT;
reg |= lsc_cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT;
reg |= lsc_cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT;
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG);
+ isp_reg_writel(dev, reg, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_LSC_CONFIG);
reg = 0;
reg &= ~ISPCCDC_LSC_INITIAL_X_MASK;
reg |= lsc_cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT;
reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK;
reg |= lsc_cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT;
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_INITIAL);
+ isp_reg_writel(dev, reg, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_LSC_INITIAL);
}
-EXPORT_SYMBOL(ispccdc_config_lsc);
-int __ispccdc_enable_lsc(u8 enable)
+void ispccdc_lsc_state_handler(struct isp_ccdc_device *isp_ccdc,
+ unsigned long status)
{
- if (!is_isplsc_activated())
- return -ENODEV;
+ if (!isp_ccdc->lsc_enable)
+ return;
- if (enable) {
- if (!ispccdc_busy()) {
- isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
- ISPCTRL_SBL_SHARED_RPORTB
- | ISPCTRL_SBL_RD_RAM_EN);
+ if (status & CCDC_VD1)
+ isp_ccdc->lsc_delay_stop = 0;
- isp_reg_or(OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_LSC_CONFIG, 0x1);
+ if (status & LSC_DONE)
+ isp_ccdc->lsc_delay_stop = 1;
- ispccdc_obj.lsc_state = 1;
- } else {
- /* Postpone enabling LSC */
- ispccdc_obj.lsc_enable = 1;
- return -EBUSY;
- }
- } else {
- isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG, 0xFFFE);
- ispccdc_obj.lsc_state = ispccdc_obj.lsc_enable = 0;
+ if (status & LSC_PRE_ERR) {
+ /* If we have LSC prefetch error, LSC engine is blocked
+ * and the only way it can recover is to do isp sw reset */
+ ispccdc_enable_lsc(isp_ccdc, 0);
+ isp_ccdc->lsc_delay_stop = 1;
}
+}
- return 0;
+static void __ispccdc_enable_lsc(struct isp_ccdc_device *isp_ccdc, u8 enable)
+{
+ isp_reg_and_or(to_device(isp_ccdc), OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_LSC_CONFIG,
+ ~ISPCCDC_LSC_ENABLE,
+ enable ? ISPCCDC_LSC_ENABLE : 0);
}
/**
* ispccdc_enable_lsc - Enables/Disables the Lens Shading Compensation module.
+ * @isp_ccdc: Pointer to ISP CCDC device.
* @enable: 0 Disables LSC, 1 Enables LSC.
**/
-void ispccdc_enable_lsc(u8 enable)
+void ispccdc_enable_lsc(struct isp_ccdc_device *isp_ccdc, u8 enable)
{
- if (__ispccdc_enable_lsc(enable)) {
- if (enable)
- ispccdc_obj.lsc_state = 1;
- else
- ispccdc_obj.lsc_state = ispccdc_obj.lsc_enable = 0;
+ struct device *dev = to_device(isp_ccdc);
+
+ if (enable) {
+ isp_reg_writel(dev, IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ |
+ IRQ0ENABLE_CCDC_LSC_DONE_IRQ,
+ OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+ IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ |
+ IRQ0ENABLE_CCDC_LSC_DONE_IRQ);
+
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_CTRL, ISPCTRL_SBL_SHARED_RPORTB
+ | ISPCTRL_SBL_RD_RAM_EN);
+
+ __ispccdc_enable_lsc(isp_ccdc, 1);
+ isp_ccdc->lsc_request_enable = 0;
+ } else {
+ __ispccdc_enable_lsc(isp_ccdc, 0);
+
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+ ~(IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ |
+ IRQ0ENABLE_CCDC_LSC_DONE_IRQ));
}
+ isp_ccdc->lsc_enable = enable;
}
-EXPORT_SYMBOL(ispccdc_enable_lsc);
-void ispccdc_lsc_error_handler(void)
+/**
+ * ispccdc_setup_lsc - apply user LSC settings
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @pipe: Pointer to ISP pipeline structure.
+ *
+ * Consume the new LSC configuration and table set by user space application
+ * and program to CCDC. This function must be called from process context
+ * before streamon when ISP is not yet running.
+ */
+static void ispccdc_setup_lsc(struct isp_ccdc_device *isp_ccdc,
+ struct isp_pipeline *pipe)
{
- int lsc_enable = ispccdc_obj.lsc_state;
+ struct isp_device *isp = to_isp_device(isp_ccdc);
- ispccdc_enable_lsc(0);
+ ispccdc_enable_lsc(isp_ccdc, 0); /* Disable LSC */
+ if (((pipe->ccdc_in == CCDC_RAW_GRBG) ||
+ (pipe->ccdc_in == CCDC_RAW_RGGB) ||
+ (pipe->ccdc_in == CCDC_RAW_BGGR) ||
+ (pipe->ccdc_in == CCDC_RAW_GBRG)) &&
+ isp_ccdc->lsc_request_enable) {
+ /* LSC is requested to be enabled, so configure it */
+ if (isp_ccdc->update_lsc_table) {
+ BUG_ON(isp_ccdc->lsc_table_new == PTR_FREE);
+ iommu_vfree(isp->iommu, isp_ccdc->lsc_table_inuse);
+ isp_ccdc->lsc_table_inuse = isp_ccdc->lsc_table_new;
+ isp_ccdc->lsc_table_new = PTR_FREE;
+ isp_ccdc->update_lsc_table = 0;
+ }
+ ispccdc_config_lsc(isp_ccdc);
+ ispccdc_program_lsc(isp_ccdc);
+ }
+ isp_ccdc->update_lsc_config = 0;
+}
- ispccdc_obj.lsc_enable = lsc_enable;
+/**
+ * ispccdc_lsc_error_handler - Handle LSC prefetch error scenario.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ *
+ * Disables LSC, and defers enablement to shadow registers update time.
+ **/
+void ispccdc_lsc_error_handler(struct isp_ccdc_device *isp_ccdc)
+{
+ ispccdc_enable_lsc(isp_ccdc, 0);
}
/**
@@ -565,191 +707,138 @@
* 3) Crop height is always even.
* 4) Crop width is always a multiple of 16 pixels
**/
-void ispccdc_config_crop(u32 left, u32 top, u32 height, u32 width)
+static void ispccdc_config_crop(struct isp_ccdc_device *isp_ccdc, u32 left,
+ u32 top, u32 height, u32 width)
{
- ispccdc_obj.ccdcin_woffset = left + (left % 2);
- ispccdc_obj.ccdcin_hoffset = top + (top % 2);
+ isp_ccdc->ccdcin_woffset = left + (left % 2);
+ isp_ccdc->ccdcin_hoffset = top + (top % 2);
- ispccdc_obj.crop_w = width - (width % 16);
- ispccdc_obj.crop_h = height + (height % 2);
+ isp_ccdc->crop_w = width - (width % 16);
+ isp_ccdc->crop_h = height + (height % 2);
DPRINTK_ISPCCDC("\n\tOffsets L %d T %d W %d H %d\n",
- ispccdc_obj.ccdcin_woffset,
- ispccdc_obj.ccdcin_hoffset,
- ispccdc_obj.crop_w,
- ispccdc_obj.crop_h);
+ isp_ccdc->ccdcin_woffset,
+ isp_ccdc->ccdcin_hoffset,
+ isp_ccdc->crop_w,
+ isp_ccdc->crop_h);
}
/**
- * ispccdc_config_datapath - Specifies the input and output modules for CCDC.
- * @input: Indicates the module that inputs the image to the CCDC.
- * @output: Indicates the module to which the CCDC outputs the image.
+ * ispccdc_config_outlineoffset - Configure memory saving output line offset
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @offset: Address offset to start a new line. Must be twice the
+ * Output width and aligned on 32 byte boundary
+ * @oddeven: Specifies the odd/even line pattern to be chosen to store the
+ * output.
+ * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
*
- * Configures the default configuration for the CCDC to work with.
+ * - Configures the output line offset when stored in memory
+ * - Sets the odd/even line pattern to store the output
+ * (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
+ * - Configures the number of even and odd line fields in case of rearranging
+ * the lines.
*
- * The valid values for the input are CCDC_RAW (0), CCDC_YUV_SYNC (1),
- * CCDC_YUV_BT (2), and CCDC_OTHERS (3).
- *
- * The valid values for the output are CCDC_YUV_RSZ (0), CCDC_YUV_MEM_RSZ (1),
- * CCDC_OTHERS_VP (2), CCDC_OTHERS_MEM (3), CCDC_OTHERS_VP_MEM (4).
- *
- * Returns 0 if successful, or -EINVAL if wrong I/O combination or wrong input
- * or output values.
+ * Returns 0 if successful, or -EINVAL if the offset is not in 32 byte
+ * boundary.
**/
-int ispccdc_config_datapath(enum ccdc_input input, enum ccdc_output output)
+static int ispccdc_config_outlineoffset(struct isp_ccdc_device *isp_ccdc,
+ u32 offset, u8 oddeven, u8 numlines)
{
- u32 syn_mode = 0;
- struct ispccdc_vp vpcfg;
- struct ispccdc_syncif syncif;
- struct ispccdc_bclamp blkcfg;
+ struct device *dev = to_device(isp_ccdc);
- u32 colptn = ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
- ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
- ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
- ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
- ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
-
- /* CCDC does not convert the image format */
- if ((input == CCDC_RAW || input == CCDC_OTHERS) &&
- output == CCDC_YUV_RSZ) {
- DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC I/O Combination\n");
+ if ((offset & ISP_32B_BOUNDARY_OFFSET) == offset) {
+ isp_reg_writel(dev, (offset & 0xFFFF),
+ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF);
+ } else {
+ DPRINTK_ISPCCDC("ISP_ERR : Offset should be in 32 byte"
+ " boundary\n");
return -EINVAL;
}
- syn_mode = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+ ~ISPCCDC_SDOFST_FINV);
- switch (output) {
- case CCDC_YUV_RSZ:
- syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
- syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+ ~ISPCCDC_SDOFST_FOFST_4L);
+
+ switch (oddeven) {
+ case EVENEVEN:
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SDOFST,
+ (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
break;
-
- case CCDC_YUV_MEM_RSZ:
- syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
- ispccdc_obj.wen = 1;
- syn_mode |= ISPCCDC_SYN_MODE_WEN;
+ case ODDEVEN:
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SDOFST,
+ (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
break;
-
- case CCDC_OTHERS_VP:
- syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
- syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
- syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
- vpcfg.bitshift_sel = BIT9_0;
- vpcfg.freq_sel = PIXCLKBY2;
- ispccdc_config_vp(vpcfg);
- ispccdc_enable_vp(1);
+ case EVENODD:
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SDOFST,
+ (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
break;
-
- case CCDC_OTHERS_MEM:
- syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
- syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
- syn_mode |= ISPCCDC_SYN_MODE_WEN;
- syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN;
- isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
- ~ISPCCDC_CFG_WENLOG);
- vpcfg.bitshift_sel = BIT11_2;
- vpcfg.freq_sel = PIXCLKBY2;
- ispccdc_config_vp(vpcfg);
- ispccdc_enable_vp(0);
- break;
-
- case CCDC_OTHERS_VP_MEM:
- syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
- syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
- syn_mode |= ISPCCDC_SYN_MODE_WEN;
- syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN;
-
- isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
- ~ISPCCDC_CFG_WENLOG,
- ispccdc_obj.wenlog);
- vpcfg.bitshift_sel = BIT9_0;
- vpcfg.freq_sel = PIXCLKBY2;
- ispccdc_config_vp(vpcfg);
- ispccdc_enable_vp(1);
+ case ODDODD:
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SDOFST,
+ (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
break;
default:
- DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Output\n");
- return -EINVAL;
- };
-
- isp_reg_writel(syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
-
- switch (input) {
- case CCDC_RAW:
- syncif.ccdc_mastermode = 0;
- syncif.datapol = 0;
- syncif.datsz = DAT10;
- syncif.fldmode = 0;
- syncif.fldout = 0;
- syncif.fldpol = 0;
- syncif.fldstat = 0;
- syncif.hdpol = 0;
- syncif.ipmod = RAW;
- syncif.vdpol = 0;
- ispccdc_config_sync_if(syncif);
- ispccdc_config_imgattr(colptn);
- blkcfg.dcsubval = 64;
- ispccdc_config_black_clamp(blkcfg);
- if (is_isplsc_activated()) {
- ispccdc_config_lsc(&lsc_config);
- ispccdc_load_lsc(lsc_gain_table_tmp,
- LSC_TABLE_INIT_SIZE);
- }
-
break;
- case CCDC_YUV_SYNC:
- syncif.ccdc_mastermode = 0;
- syncif.datapol = 0;
- syncif.datsz = DAT8;
- syncif.fldmode = 0;
- syncif.fldout = 0;
- syncif.fldpol = 0;
- syncif.fldstat = 0;
- syncif.hdpol = 0;
- syncif.ipmod = YUV16;
- syncif.vdpol = 1;
- ispccdc_config_imgattr(0);
- ispccdc_config_sync_if(syncif);
- blkcfg.dcsubval = 0;
- ispccdc_config_black_clamp(blkcfg);
- break;
- case CCDC_YUV_BT:
- break;
- case CCDC_OTHERS:
- break;
- default:
- DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Input\n");
- return -EINVAL;
}
-
- ispccdc_obj.ccdc_inpfmt = input;
- ispccdc_obj.ccdc_outfmt = output;
- ispccdc_print_status();
- isp_print_status();
return 0;
}
-EXPORT_SYMBOL(ispccdc_config_datapath);
/**
- * ispccdc_config_sync_if - Sets the sync i/f params between sensor and CCDC.
+ * ispccdc_set_outaddr - Set memory address to save output image
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
+ *
+ * Sets the memory address where the output will be saved.
+ *
+ * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte
+ * boundary.
+ **/
+int ispccdc_set_outaddr(struct isp_ccdc_device *isp_ccdc, u32 addr)
+{
+ struct device *dev = to_device(isp_ccdc);
+
+ if ((addr & ISP_32B_BOUNDARY_BUF) == addr) {
+ isp_reg_writel(dev, addr, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SDR_ADDR);
+ return 0;
+ } else {
+ DPRINTK_ISPCCDC("ISP_ERR : Address should be in 32 byte"
+ " boundary\n");
+ return -EINVAL;
+ }
+
+}
+
+void ispccdc_lsc_pref_comp_handler(struct isp_ccdc_device *isp_ccdc)
+{
+ struct device *dev = to_device(isp_ccdc);
+
+ if (!isp_ccdc->lsc_enable)
+ return;
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+ ~IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ);
+
+ ispccdc_enable(isp_ccdc, 1);
+}
+
+/**
+ * ispccdc_config_sync_if - Set CCDC sync interface params between sensor and CCDC.
+ * @isp_ccdc: Pointer to ISP CCDC device.
* @syncif: Structure containing the sync parameters like field state, CCDC in
* master/slave mode, raw/yuv data, polarity of data, field, hs, vs
* signals.
**/
-void ispccdc_config_sync_if(struct ispccdc_syncif syncif)
+static void ispccdc_config_sync_if(struct isp_ccdc_device *isp_ccdc,
+ struct ispccdc_syncif syncif)
{
- u32 syn_mode = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+ struct device *dev = to_device(isp_ccdc);
+ u32 syn_mode = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SYN_MODE);
syn_mode |= ISPCCDC_SYN_MODE_VDHDEN;
@@ -759,7 +848,7 @@
syn_mode &= ~ISPCCDC_SYN_MODE_FLDSTAT;
syn_mode &= ISPCCDC_SYN_MODE_INPMOD_MASK;
- ispccdc_obj.syncif_ipmod = syncif.ipmod;
+ isp_ccdc->syncif_ipmod = syncif.ipmod;
switch (syncif.ipmod) {
case RAW:
@@ -815,12 +904,14 @@
if (syncif.ccdc_mastermode) {
syn_mode |= ISPCCDC_SYN_MODE_FLDOUT | ISPCCDC_SYN_MODE_VDHDOUT;
- isp_reg_writel(syncif.hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT
+ isp_reg_writel(dev,
+ syncif.hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT
| syncif.vs_width << ISPCCDC_HD_VD_WID_VDW_SHIFT,
OMAP3_ISP_IOMEM_CCDC,
ISPCCDC_HD_VD_WID);
- isp_reg_writel(syncif.ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT
+ isp_reg_writel(dev,
+ syncif.ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT
| syncif.hlprf << ISPCCDC_PIX_LINES_HLPRF_SHIFT,
OMAP3_ISP_IOMEM_CCDC,
ISPCCDC_PIX_LINES);
@@ -828,391 +919,260 @@
syn_mode &= ~(ISPCCDC_SYN_MODE_FLDOUT |
ISPCCDC_SYN_MODE_VDHDOUT);
- isp_reg_writel(syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+ isp_reg_writel(dev, syn_mode, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SYN_MODE);
if (!(syncif.bt_r656_en)) {
- isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
- ~ISPCCDC_REC656IF_R656ON);
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_REC656IF, ~ISPCCDC_REC656IF_R656ON);
}
}
-EXPORT_SYMBOL(ispccdc_config_sync_if);
/**
- * ispccdc_config_black_clamp - Configures the clamp parameters in CCDC.
- * @bclamp: Structure containing the optical black average gain, optical black
- * sample length, sample lines, and the start pixel position of the
- * samples w.r.t the HS pulse.
- * Configures the clamp parameters in CCDC. Either if its being used the
- * optical black clamp, or the digital clamp. If its a digital clamp, then
- * assures to put a valid DC substraction level.
- *
- * Returns always 0 when completed.
- **/
-int ispccdc_config_black_clamp(struct ispccdc_bclamp bclamp)
+ * ispccdc_set_wenlog - Set the CCDC Write Enable valid region.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @wenlog: Write enable logic to apply against valid area. 0 - AND, 1 - OR.
+ */
+void ispccdc_set_wenlog(struct isp_ccdc_device *isp_ccdc, u32 wenlog)
{
- u32 bclamp_val = 0;
-
- if (ispccdc_obj.obclamp_en) {
- bclamp_val |= bclamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT;
- bclamp_val |= bclamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT;
- bclamp_val |= bclamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT;
- bclamp_val |= bclamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT;
- isp_reg_writel(bclamp_val, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_CLAMP);
- } else {
- if (omap_rev() < OMAP3430_REV_ES2_0)
- if (ispccdc_obj.syncif_ipmod == YUV16 ||
- ispccdc_obj.syncif_ipmod == YUV8 ||
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_REC656IF) &
- ISPCCDC_REC656IF_R656ON)
- bclamp.dcsubval = 0;
- isp_reg_writel(bclamp.dcsubval, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_DCSUB);
- }
- return 0;
+ isp_ccdc->wenlog = wenlog;
}
-EXPORT_SYMBOL(ispccdc_config_black_clamp);
/**
- * ispccdc_enable_black_clamp - Enables/Disables the optical black clamp.
- * @enable: 0 Disables optical black clamp, 1 Enables optical black clamp.
+ * ispccdc_config_datapath - Specify the input and output modules for CCDC.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @pipe: Pointer to ISP pipeline structure to base on for config.
*
- * Enables or disables the optical black clamp. When disabled, the digital
- * clamp operates.
- **/
-void ispccdc_enable_black_clamp(u8 enable)
-{
- isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP,
- ~ISPCCDC_CLAMP_CLAMPEN,
- enable ? ISPCCDC_CLAMP_CLAMPEN : 0);
- ispccdc_obj.obclamp_en = enable;
-}
-EXPORT_SYMBOL(ispccdc_enable_black_clamp);
-
-/**
- * ispccdc_config_fpc - Configures the Faulty Pixel Correction parameters.
- * @fpc: Structure containing the number of faulty pixels corrected in the
- * frame, address of the FPC table.
+ * Configures the default configuration for the CCDC to work with.
*
- * Returns 0 if successful, or -EINVAL if FPC Address is not on the 64 byte
- * boundary.
+ * The valid values for the input are CCDC_RAW (0), CCDC_YUV_SYNC (1),
+ * CCDC_YUV_BT (2), and CCDC_OTHERS (3).
+ *
+ * The valid values for the output are CCDC_YUV_RSZ (0), CCDC_YUV_MEM_RSZ (1),
+ * CCDC_OTHERS_VP (2), CCDC_OTHERS_MEM (3), CCDC_OTHERS_VP_MEM (4).
+ *
+ * Returns 0 if successful, or -EINVAL if wrong I/O combination or wrong input
+ * or output values.
**/
-int ispccdc_config_fpc(struct ispccdc_fpc fpc)
+static int ispccdc_config_datapath(struct isp_ccdc_device *isp_ccdc,
+ struct isp_pipeline *pipe)
{
- u32 fpc_val = 0;
+ struct device *dev = to_device(isp_ccdc);
+ u32 syn_mode = 0;
+ struct ispccdc_vp vpcfg;
+ struct ispccdc_syncif syncif;
+ struct ispccdc_bclamp blkcfg;
- fpc_val = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+ u32 colptn = ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
- if ((fpc.fpcaddr & 0xFFFFFFC0) == fpc.fpcaddr) {
- isp_reg_writel(fpc_val & (~ISPCCDC_FPC_FPCEN),
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
- isp_reg_writel(fpc.fpcaddr,
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC_ADDR);
- } else {
- DPRINTK_ISPCCDC("FPC Address should be on 64byte boundary\n");
+ syn_mode = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SYN_MODE);
+
+ switch (pipe->ccdc_out) {
+ case CCDC_YUV_RSZ:
+ syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
+ syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
+ break;
+
+ case CCDC_YUV_MEM_RSZ:
+ syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
+ isp_ccdc->wen = 1;
+ syn_mode |= ISPCCDC_SYN_MODE_WEN;
+ break;
+
+ case CCDC_OTHERS_VP:
+ syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
+ syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
+ syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
+ vpcfg.bitshift_sel = BIT9_0;
+ vpcfg.freq_sel = PIXCLKBY2;
+ ispccdc_config_vp(isp_ccdc, vpcfg);
+ ispccdc_enable_vp(isp_ccdc, 1);
+ break;
+
+ case CCDC_OTHERS_MEM:
+ syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
+ syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
+ syn_mode |= ISPCCDC_SYN_MODE_WEN;
+ syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN;
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+ ~ISPCCDC_CFG_WENLOG);
+ vpcfg.bitshift_sel = BIT9_0;
+ vpcfg.freq_sel = PIXCLKBY2;
+ ispccdc_config_vp(isp_ccdc, vpcfg);
+ ispccdc_enable_vp(isp_ccdc, 0);
+ break;
+
+ case CCDC_OTHERS_VP_MEM:
+ syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
+ syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
+ syn_mode |= ISPCCDC_SYN_MODE_WEN;
+ syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN;
+
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_CFG, ~ISPCCDC_CFG_WENLOG,
+ isp_ccdc->wenlog);
+ vpcfg.bitshift_sel = BIT9_0;
+ vpcfg.freq_sel = PIXCLKBY2;
+ ispccdc_config_vp(isp_ccdc, vpcfg);
+ ispccdc_enable_vp(isp_ccdc, 1);
+ break;
+ default:
+ DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Output\n");
+ return -EINVAL;
+ };
+
+ isp_reg_writel(dev, syn_mode, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SYN_MODE);
+
+ switch (pipe->ccdc_in) {
+ case CCDC_RAW_GRBG:
+ case CCDC_RAW_RGGB:
+ case CCDC_RAW_BGGR:
+ case CCDC_RAW_GBRG:
+ syncif.ccdc_mastermode = 0;
+ syncif.datapol = 0;
+ syncif.datsz = DAT10;
+ syncif.fldmode = 0;
+ syncif.fldout = 0;
+ syncif.fldpol = 0;
+ syncif.fldstat = 0;
+ syncif.hdpol = 0;
+ syncif.ipmod = RAW;
+ syncif.vdpol = 0;
+ ispccdc_config_sync_if(isp_ccdc, syncif);
+ ispccdc_config_imgattr(isp_ccdc, colptn);
+ blkcfg.oblen = 0;
+ blkcfg.dcsubval = 64;
+ ispccdc_config_black_clamp(isp_ccdc, blkcfg);
+ break;
+ case CCDC_YUV_SYNC:
+ syncif.ccdc_mastermode = 0;
+ syncif.datapol = 0;
+ syncif.datsz = DAT8;
+ syncif.fldmode = 0;
+ syncif.fldout = 0;
+ syncif.fldpol = 0;
+ syncif.fldstat = 0;
+ syncif.hdpol = 0;
+ syncif.ipmod = YUV16;
+ syncif.vdpol = 1;
+ ispccdc_config_imgattr(isp_ccdc, 0);
+ ispccdc_config_sync_if(isp_ccdc, syncif);
+ blkcfg.oblen = 0;
+ blkcfg.dcsubval = 0;
+ ispccdc_config_black_clamp(isp_ccdc, blkcfg);
+ break;
+ case CCDC_YUV_BT:
+ break;
+ case CCDC_OTHERS:
+ break;
+ default:
+ DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Input\n");
return -EINVAL;
}
- isp_reg_writel(fpc_val | (fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT),
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+
+ ispccdc_config_crop(isp_ccdc, 0, 0, 0, 0);
+ ispccdc_print_status(isp_ccdc, pipe);
+ isp_print_status(dev);
return 0;
}
-EXPORT_SYMBOL(ispccdc_config_fpc);
/**
- * ispccdc_enable_fpc - Enables the Faulty Pixel Correction.
- * @enable: 0 Disables FPC, 1 Enables FPC.
- **/
-void ispccdc_enable_fpc(u8 enable)
-{
- isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC,
- ~ISPCCDC_FPC_FPCEN,
- enable ? ISPCCDC_FPC_FPCEN : 0);
-}
-EXPORT_SYMBOL(ispccdc_enable_fpc);
-
-/**
- * ispccdc_config_black_comp - Configures Black Level Compensation parameters.
- * @blcomp: Structure containing the black level compensation value for RGrGbB
- * pixels. in 2's complement.
- **/
-void ispccdc_config_black_comp(struct ispccdc_blcomp blcomp)
-{
- u32 blcomp_val = 0;
-
- blcomp_val |= blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT;
- blcomp_val |= blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT;
- blcomp_val |= blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT;
- blcomp_val |= blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT;
-
- isp_reg_writel(blcomp_val, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP);
-}
-EXPORT_SYMBOL(ispccdc_config_black_comp);
-
-/**
- * ispccdc_config_vp - Configures the Video Port Configuration parameters.
- * @vpcfg: Structure containing the Video Port input frequency, and the 10 bit
- * format.
- **/
-void ispccdc_config_vp(struct ispccdc_vp vpcfg)
-{
- u32 fmtcfg_vp = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
-
- fmtcfg_vp &= ISPCCDC_FMTCFG_VPIN_MASK & ISPCCDC_FMTCF_VPIF_FRQ_MASK;
-
- switch (vpcfg.bitshift_sel) {
- case BIT9_0:
- fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
- break;
- case BIT10_1:
- fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
- break;
- case BIT11_2:
- fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
- break;
- case BIT12_3:
- fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
- break;
- };
- switch (vpcfg.freq_sel) {
- case PIXCLKBY2:
- fmtcfg_vp |= ISPCCDC_FMTCF_VPIF_FRQ_BY2;
- break;
- case PIXCLKBY3_5:
- fmtcfg_vp |= ISPCCDC_FMTCF_VPIF_FRQ_BY3;
- break;
- case PIXCLKBY4_5:
- fmtcfg_vp |= ISPCCDC_FMTCF_VPIF_FRQ_BY4;
- break;
- case PIXCLKBY5_5:
- fmtcfg_vp |= ISPCCDC_FMTCF_VPIF_FRQ_BY5;
- break;
- case PIXCLKBY6_5:
- fmtcfg_vp |= ISPCCDC_FMTCF_VPIF_FRQ_BY6;
- break;
- };
- isp_reg_writel(fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
-}
-EXPORT_SYMBOL(ispccdc_config_vp);
-
-/**
- * ispccdc_enable_vp - Enables the Video Port.
- * @enable: 0 Disables VP, 1 Enables VP
- **/
-void ispccdc_enable_vp(u8 enable)
-{
- isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
- ~ISPCCDC_FMTCFG_VPEN,
- enable ? ISPCCDC_FMTCFG_VPEN : 0);
-}
-EXPORT_SYMBOL(ispccdc_enable_vp);
-
-/**
- * ispccdc_config_reformatter - Configures the Reformatter.
- * @refmt: Structure containing the memory address to format and the bit fields
- * for the reformatter registers.
- *
- * Configures the Reformatter register values if line alternating is disabled.
- * Else, just enabling line alternating is enough.
- **/
-void ispccdc_config_reformatter(struct ispccdc_refmt refmt)
-{
- u32 fmtcfg_val = 0;
-
- fmtcfg_val = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
-
- if (refmt.lnalt)
- fmtcfg_val |= ISPCCDC_FMTCFG_LNALT;
- else {
- fmtcfg_val &= ~ISPCCDC_FMTCFG_LNALT;
- fmtcfg_val &= 0xFFFFF003;
- fmtcfg_val |= refmt.lnum << ISPCCDC_FMTCFG_LNUM_SHIFT;
- fmtcfg_val |= refmt.plen_even <<
- ISPCCDC_FMTCFG_PLEN_EVEN_SHIFT;
- fmtcfg_val |= refmt.plen_odd << ISPCCDC_FMTCFG_PLEN_ODD_SHIFT;
-
- isp_reg_writel(refmt.prgeven0, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_PRGEVEN0);
- isp_reg_writel(refmt.prgeven1, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_PRGEVEN1);
- isp_reg_writel(refmt.prgodd0, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_PRGODD0);
- isp_reg_writel(refmt.prgodd1, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_PRGODD1);
- isp_reg_writel(refmt.fmtaddr0, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FMT_ADDR0);
- isp_reg_writel(refmt.fmtaddr1, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FMT_ADDR1);
- isp_reg_writel(refmt.fmtaddr2, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FMT_ADDR2);
- isp_reg_writel(refmt.fmtaddr3, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FMT_ADDR3);
- isp_reg_writel(refmt.fmtaddr4, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FMT_ADDR4);
- isp_reg_writel(refmt.fmtaddr5, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FMT_ADDR5);
- isp_reg_writel(refmt.fmtaddr6, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FMT_ADDR6);
- isp_reg_writel(refmt.fmtaddr7, OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FMT_ADDR7);
- }
- isp_reg_writel(fmtcfg_val, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
-}
-EXPORT_SYMBOL(ispccdc_config_reformatter);
-
-/**
- * ispccdc_enable_reformatter - Enables the Reformatter.
- * @enable: 0 Disables Reformatter, 1- Enables Data Reformatter
- **/
-void ispccdc_enable_reformatter(u8 enable)
-{
- isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
- ~ISPCCDC_FMTCFG_FMTEN,
- enable ? ISPCCDC_FMTCFG_FMTEN : 0);
- ispccdc_obj.refmt_en = enable;
-}
-EXPORT_SYMBOL(ispccdc_enable_reformatter);
-
-/**
- * ispccdc_config_culling - Configures the culling parameters.
- * @cull: Structure containing the vertical culling pattern, and horizontal
- * culling pattern for odd and even lines.
- **/
-void ispccdc_config_culling(struct ispccdc_culling cull)
-{
- u32 culling_val = 0;
-
- culling_val |= cull.v_pattern << ISPCCDC_CULLING_CULV_SHIFT;
- culling_val |= cull.h_even << ISPCCDC_CULLING_CULHEVN_SHIFT;
- culling_val |= cull.h_odd << ISPCCDC_CULLING_CULHODD_SHIFT;
-
- isp_reg_writel(culling_val, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CULLING);
-}
-EXPORT_SYMBOL(ispccdc_config_culling);
-
-/**
- * ispccdc_enable_lpf - Enables the Low-Pass Filter (LPF).
- * @enable: 0 Disables LPF, 1 Enables LPF
- **/
-void ispccdc_enable_lpf(u8 enable)
-{
- isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE,
- ~ISPCCDC_SYN_MODE_LPF,
- enable ? ISPCCDC_SYN_MODE_LPF : 0);
-}
-EXPORT_SYMBOL(ispccdc_enable_lpf);
-
-/**
- * ispccdc_config_alaw - Configures the input width for A-law.
- * @ipwidth: Input width for A-law
- **/
-void ispccdc_config_alaw(enum alaw_ipwidth ipwidth)
-{
- isp_reg_writel(ipwidth << ISPCCDC_ALAW_GWDI_SHIFT,
- OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW);
-}
-EXPORT_SYMBOL(ispccdc_config_alaw);
-
-/**
- * ispccdc_enable_alaw - Enables the A-law compression.
- * @enable: 0 - Disables A-law, 1 - Enables A-law
- **/
-void ispccdc_enable_alaw(u8 enable)
-{
- isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW,
- ~ISPCCDC_ALAW_CCDTBL,
- enable ? ISPCCDC_ALAW_CCDTBL : 0);
-}
-EXPORT_SYMBOL(ispccdc_enable_alaw);
-
-/**
- * ispccdc_config_imgattr - Configures the sensor image specific attributes.
- * @colptn: Color pattern of the sensor.
- **/
-void ispccdc_config_imgattr(u32 colptn)
-{
- isp_reg_writel(colptn, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN);
-}
-EXPORT_SYMBOL(ispccdc_config_imgattr);
-
-void ispccdc_config_shadow_registers(void)
-{
- if (ispccdc_obj.lsc_enable) {
- ispccdc_enable_lsc(1);
- ispccdc_obj.lsc_enable = 0;
- }
-}
-
-/**
- * ispccdc_try_size - Checks if requested Input/output dimensions are valid
- * @input_w: input width for the CCDC in number of pixels per line
- * @input_h: input height for the CCDC in number of lines
- * @output_w: output width from the CCDC in number of pixels per line
- * @output_h: output height for the CCDC in number of lines
+ * ispccdc_try_pipeline - Checks if requested Input/output dimensions are valid
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @pipe: Pointer to ISP pipeline structure to fill back.
*
* Calculates the number of pixels cropped if the reformater is disabled,
* Fills up the output width and height variables in the isp_ccdc structure.
*
* Returns 0 if successful, or -EINVAL if the input width is less than 2 pixels
**/
-int ispccdc_try_size(u32 input_w, u32 input_h, u32 *output_w, u32 *output_h)
+int ispccdc_try_pipeline(struct isp_ccdc_device *isp_ccdc,
+ struct isp_pipeline *pipe)
{
- if (input_w < 32 || input_h < 32) {
+ struct isp_device *isp = to_isp_device(isp_ccdc);
+
+ if (pipe->ccdc_in_w < 32 || pipe->ccdc_in_h < 32) {
DPRINTK_ISPCCDC("ISP_ERR: CCDC cannot handle input width less"
" than 32 pixels or height less than 32\n");
return -EINVAL;
}
- if (ispccdc_obj.crop_w)
- *output_w = ispccdc_obj.crop_w;
- else
- *output_w = input_w;
-
- if (ispccdc_obj.crop_h)
- *output_h = ispccdc_obj.crop_h;
- else
- *output_h = input_h;
-
- if (!ispccdc_obj.refmt_en
- && ispccdc_obj.ccdc_outfmt != CCDC_OTHERS_MEM
- && ispccdc_obj.ccdc_outfmt != CCDC_OTHERS_VP_MEM)
- *output_h -= 1;
-
- if (ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_VP) {
- *output_h -= ispccdc_obj.ccdcin_hoffset;
- *output_w -= ispccdc_obj.ccdcin_woffset;
- *output_h &= 0xFFFFFFFE;
- *output_w &= 0xFFFFFFFE;
+ /* CCDC does not convert the image format */
+ if ((pipe->ccdc_in == CCDC_RAW_GRBG ||
+ pipe->ccdc_in == CCDC_RAW_RGGB ||
+ pipe->ccdc_in == CCDC_RAW_BGGR ||
+ pipe->ccdc_in == CCDC_RAW_GBRG ||
+ pipe->ccdc_in == CCDC_OTHERS) &&
+ pipe->ccdc_out == CCDC_YUV_RSZ) {
+ dev_info(isp->dev, "wrong CCDC I/O Combination\n");
+ return -EINVAL;
}
- if (ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_MEM
- || ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_VP_MEM) {
- if (*output_w % 32)
- *output_w -= (*output_w % 32);
+ pipe->ccdc_in_h_st = 0;
+ pipe->ccdc_in_v_st = 0;
+ pipe->ccdc_out_w = pipe->ccdc_in_w;
+ pipe->ccdc_out_h = pipe->ccdc_in_h;
+
+ if (!isp_ccdc->refmt_en
+ && pipe->ccdc_out != CCDC_OTHERS_MEM
+ && pipe->ccdc_out != CCDC_OTHERS_VP_MEM)
+ pipe->ccdc_out_h -= 1;
+
+ if (pipe->ccdc_out == CCDC_OTHERS_VP) {
+ switch (pipe->ccdc_in) {
+ case CCDC_RAW_GRBG:
+ pipe->ccdc_in_h_st = 1;
+ pipe->ccdc_in_v_st = 0;
+ break;
+ case CCDC_RAW_BGGR:
+ pipe->ccdc_in_h_st = 1;
+ pipe->ccdc_in_v_st = 1;
+ break;
+ case CCDC_RAW_RGGB:
+ pipe->ccdc_in_h_st = 0;
+ pipe->ccdc_in_v_st = 0;
+ break;
+ case CCDC_RAW_GBRG:
+ pipe->ccdc_in_h_st = 0;
+ pipe->ccdc_in_v_st = 1;
+ break;
+ default:
+ break;
+ }
+ pipe->ccdc_out_h -= pipe->ccdc_in_v_st;
+ pipe->ccdc_out_w -= pipe->ccdc_in_h_st;
+ pipe->ccdc_out_h -= (pipe->ccdc_out_h % 2);
+ pipe->ccdc_out_w -= (pipe->ccdc_out_w % 2);
}
- ispccdc_obj.ccdcout_w = *output_w;
- ispccdc_obj.ccdcout_h = *output_h;
- ispccdc_obj.ccdcin_w = input_w;
- ispccdc_obj.ccdcin_h = input_h;
-
- DPRINTK_ISPCCDC("try size: ccdcin_w=%u,ccdcin_h=%u,ccdcout_w=%u,"
- " ccdcout_h=%u\n",
- ispccdc_obj.ccdcin_w,
- ispccdc_obj.ccdcin_h,
- ispccdc_obj.ccdcout_w,
- ispccdc_obj.ccdcout_h);
+ pipe->ccdc_out_w_img = pipe->ccdc_out_w;
+ /* Round up to nearest 32 pixels. */
+ pipe->ccdc_out_w = ALIGN(pipe->ccdc_out_w, 0x20);
return 0;
}
-EXPORT_SYMBOL(ispccdc_try_size);
/**
- * ispccdc_config_size - Configure the dimensions of the CCDC input/output
- * @input_w: input width for the CCDC in number of pixels per line
- * @input_h: input height for the CCDC in number of lines
- * @output_w: output width from the CCDC in number of pixels per line
- * @output_h: output height for the CCDC in number of lines
+ * ispccdc_s_pipeline - Configure the CCDC based on overall ISP pipeline.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @pipe: Pointer to ISP pipeline structure to configure.
*
* Configures the appropriate values stored in the isp_ccdc structure to
* HORZ/VERT_INFO registers and the VP_OUT depending on whether the image
@@ -1221,460 +1181,559 @@
* Returns 0 if successful, or -EINVAL if try_size was not called before to
* validate the requested dimensions.
**/
-int ispccdc_config_size(u32 input_w, u32 input_h, u32 output_w, u32 output_h)
+int ispccdc_s_pipeline(struct isp_ccdc_device *isp_ccdc,
+ struct isp_pipeline *pipe)
{
- DPRINTK_ISPCCDC("config size: input_w=%u, input_h=%u, output_w=%u,"
- " output_h=%u\n",
- input_w, input_h,
- output_w, output_h);
- if (output_w != ispccdc_obj.ccdcout_w
- || output_h != ispccdc_obj.ccdcout_h) {
- DPRINTK_ISPCCDC("ISP_ERR : ispccdc_try_size should"
- " be called before config size\n");
- return -EINVAL;
- }
+ struct device *dev = to_device(isp_ccdc);
+ int rval;
- if (ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_VP) {
- isp_reg_writel((ispccdc_obj.ccdcin_woffset <<
- ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
- ((ispccdc_obj.ccdcin_w-ispccdc_obj.ccdcin_woffset) <<
- ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FMT_HORZ);
- isp_reg_writel((ispccdc_obj.ccdcin_hoffset <<
- ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
- ((ispccdc_obj.ccdcin_h-ispccdc_obj.ccdcin_hoffset) <<
- ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FMT_VERT);
- isp_reg_writel((ispccdc_obj.ccdcout_w <<
- ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
- (ispccdc_obj.ccdcout_h <<
- ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
- OMAP3_ISP_IOMEM_CCDC,
+ rval = ispccdc_config_datapath(isp_ccdc, pipe);
+ if (rval)
+ return rval;
+
+ isp_reg_writel(dev,
+ (pipe->ccdc_in_h_st << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
+ ((pipe->ccdc_in_w - pipe->ccdc_in_h_st) <<
+ ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
+ OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_FMT_HORZ);
+ isp_reg_writel(dev,
+ (pipe->ccdc_in_v_st << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
+ ((pipe->ccdc_in_h - pipe->ccdc_in_v_st) <<
+ ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
+ OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_FMT_VERT);
+ isp_reg_writel(dev,
+ pipe->ccdc_in_v_st << ISPCCDC_VERT_START_SLV0_SHIFT,
+ OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_VERT_START);
+ isp_reg_writel(dev, (pipe->ccdc_out_h - pipe->ccdc_in_v_st - 1) <<
+ ISPCCDC_VERT_LINES_NLV_SHIFT,
+ OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_VERT_LINES);
+ isp_reg_writel(dev,
+ (pipe->ccdc_in_h_st << ISPCCDC_HORZ_INFO_SPH_SHIFT)
+ | ((pipe->ccdc_out_w - pipe->ccdc_in_h_st)
+ << ISPCCDC_HORZ_INFO_NPH_SHIFT),
+ OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_HORZ_INFO);
+ ispccdc_config_outlineoffset(isp_ccdc, pipe->ccdc_out_w * 2, 0, 0);
+ isp_reg_writel(dev, (((pipe->ccdc_out_h - 2) &
+ ISPCCDC_VDINT_0_MASK) <<
+ ISPCCDC_VDINT_0_SHIFT) |
+ ((50 & ISPCCDC_VDINT_1_MASK) <<
+ ISPCCDC_VDINT_1_SHIFT),
+ OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_VDINT);
+
+ if (pipe->ccdc_out == CCDC_OTHERS_MEM) {
+ isp_reg_writel(dev, 0, OMAP3_ISP_IOMEM_CCDC,
ISPCCDC_VP_OUT);
- isp_reg_writel((((ispccdc_obj.ccdcout_h - 25) &
- ISPCCDC_VDINT_0_MASK) <<
- ISPCCDC_VDINT_0_SHIFT) |
- ((50 & ISPCCDC_VDINT_1_MASK) <<
- ISPCCDC_VDINT_1_SHIFT),
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_VDINT);
+ } else {
+ isp_reg_writel(dev,
+ ((pipe->ccdc_out_w - pipe->ccdc_in_h_st)
+ << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
+ ((pipe->ccdc_out_h - pipe->ccdc_in_v_st - 1) <<
+ ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
+ OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_VP_OUT);
+ }
- } else if (ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_MEM) {
- isp_reg_writel(0, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
- if (ispccdc_obj.ccdc_inpfmt == CCDC_RAW) {
- isp_reg_writel(ispccdc_obj.ccdcin_woffset <<
- ISPCCDC_HORZ_INFO_SPH_SHIFT
- | ((ispccdc_obj.ccdcout_w - 1)
- << ISPCCDC_HORZ_INFO_NPH_SHIFT),
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_HORZ_INFO);
- } else {
- isp_reg_writel(0 << ISPCCDC_HORZ_INFO_SPH_SHIFT
- | ((ispccdc_obj.ccdcout_w - 1)
- << ISPCCDC_HORZ_INFO_NPH_SHIFT),
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_HORZ_INFO);
- }
- isp_reg_writel(ispccdc_obj.ccdcin_hoffset <<
- ISPCCDC_VERT_START_SLV0_SHIFT,
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_VERT_START);
- isp_reg_writel((ispccdc_obj.ccdcout_h - 1) <<
- ISPCCDC_VERT_LINES_NLV_SHIFT,
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_VERT_LINES);
-
- ispccdc_config_outlineoffset(ispccdc_obj.ccdcout_w * 2, 0, 0);
- isp_reg_writel((((ispccdc_obj.ccdcout_h - 2) &
- ISPCCDC_VDINT_0_MASK) <<
- ISPCCDC_VDINT_0_SHIFT) |
- ((100 & ISPCCDC_VDINT_1_MASK) <<
- ISPCCDC_VDINT_1_SHIFT),
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_VDINT);
- } else if (ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_VP_MEM) {
- isp_reg_writel((ispccdc_obj.ccdcin_woffset <<
- ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
- ((ispccdc_obj.ccdcin_w - ispccdc_obj.ccdcin_woffset) <<
- ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FMT_HORZ);
- isp_reg_writel((ispccdc_obj.ccdcin_hoffset <<
- ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
- ((ispccdc_obj.ccdcin_h - ispccdc_obj.ccdcin_hoffset) <<
- ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_FMT_VERT);
-
- isp_reg_writel((ispccdc_obj.ccdcout_w
- << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
- ((ispccdc_obj.ccdcout_h - 1) <<
- ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_VP_OUT);
- isp_reg_writel((ispccdc_obj.ccdcin_woffset
- << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
- ((ispccdc_obj.ccdcout_w - 1) <<
- ISPCCDC_HORZ_INFO_NPH_SHIFT),
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_HORZ_INFO);
- isp_reg_writel(ispccdc_obj.ccdcin_hoffset
- << ISPCCDC_VERT_START_SLV0_SHIFT,
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_VERT_START);
- isp_reg_writel((ispccdc_obj.ccdcout_h - 1) <<
- ISPCCDC_VERT_LINES_NLV_SHIFT,
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_VERT_LINES);
- ispccdc_config_outlineoffset(ispccdc_obj.ccdcout_w * 2, 0, 0);
- isp_reg_writel((((ispccdc_obj.ccdcout_h - 2) &
- ISPCCDC_VDINT_0_MASK) <<
- ISPCCDC_VDINT_0_SHIFT) |
- ((100 & ISPCCDC_VDINT_1_MASK) <<
- ISPCCDC_VDINT_1_SHIFT),
- OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_VDINT);
- }
-
- if (is_isplsc_activated()) {
- if (ispccdc_obj.ccdc_inpfmt == CCDC_RAW) {
- ispccdc_config_lsc(&lsc_config);
- ispccdc_load_lsc(lsc_gain_table, lsc_config.size);
- }
- }
+ ispccdc_setup_lsc(isp_ccdc, pipe);
return 0;
}
-EXPORT_SYMBOL(ispccdc_config_size);
/**
- * ispccdc_config_outlineoffset - Configures the output line offset
- * @offset: Must be twice the Output width and aligned on 32 byte boundary
- * @oddeven: Specifies the odd/even line pattern to be chosen to store the
- * output.
- * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
+ * ispccdc_set_raw_offset - Store the component order as component offset.
+ * @raw_fmt: Input data component order.
*
- * - Configures the output line offset when stored in memory
- * - Sets the odd/even line pattern to store the output
- * (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
- * - Configures the number of even and odd line fields in case of rearranging
- * the lines.
- *
- * Returns 0 if successful, or -EINVAL if the offset is not in 32 byte
- * boundary.
+ * Turns the component order into a horizontal & vertical offset and store
+ * offsets to be used later.
**/
-int ispccdc_config_outlineoffset(u32 offset, u8 oddeven, u8 numlines)
+void ispccdc_set_raw_offset(struct isp_ccdc_device *isp_ccdc,
+ enum ispccdc_raw_fmt raw_fmt)
{
- if ((offset & ISP_32B_BOUNDARY_OFFSET) == offset) {
- isp_reg_writel((offset & 0xFFFF), OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_HSIZE_OFF);
- } else {
- DPRINTK_ISPCCDC("ISP_ERR : Offset should be in 32 byte"
- " boundary\n");
- return -EINVAL;
- }
-
- isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
- ~ISPCCDC_SDOFST_FINV);
-
- isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
- ~ISPCCDC_SDOFST_FOFST_4L);
-
- switch (oddeven) {
- case EVENEVEN:
- isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
- (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
- break;
- case ODDEVEN:
- isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
- (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
- break;
- case EVENODD:
- isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
- (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
- break;
- case ODDODD:
- isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
- (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
- break;
- default:
- break;
- }
- return 0;
+ isp_ccdc->raw_fmt_in = raw_fmt;
}
-EXPORT_SYMBOL(ispccdc_config_outlineoffset);
+EXPORT_SYMBOL(ispccdc_set_raw_offset);
/**
- * ispccdc_set_outaddr - Sets the memory address where the output will be saved
- * @addr: 32-bit memory address aligned on 32 byte boundary.
- *
- * Sets the memory address where the output will be saved.
- *
- * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte
- * boundary.
- **/
-int ispccdc_set_outaddr(u32 addr)
-{
- if ((addr & ISP_32B_BOUNDARY_BUF) == addr) {
- isp_reg_writel(addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR);
- return 0;
- } else {
- DPRINTK_ISPCCDC("ISP_ERR : Address should be in 32 byte"
- " boundary\n");
- return -EINVAL;
- }
-
-}
-EXPORT_SYMBOL(ispccdc_set_outaddr);
-
-void __ispccdc_enable(u8 enable)
-{
- if (enable) {
- if (ispccdc_obj.lsc_enable
- && ispccdc_obj.ccdc_inpfmt == CCDC_RAW)
- ispccdc_enable_lsc(1);
-
- } else {
- ispccdc_obj.lsc_enable = ispccdc_obj.lsc_state;
- }
-
- isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR, ~ISPCCDC_PCR_EN,
- enable ? ISPCCDC_PCR_EN : 0);
-}
-
-/**
- * ispccdc_enable - Enables the CCDC module.
+ * ispccdc_enable - Enable the CCDC module.
+ * @isp_ccdc: Pointer to ISP CCDC device.
* @enable: 0 Disables CCDC, 1 Enables CCDC
*
* Client should configure all the sub modules in CCDC before this.
**/
-void ispccdc_enable(u8 enable)
+void ispccdc_enable(struct isp_ccdc_device *isp_ccdc, u8 enable)
{
- __ispccdc_enable(enable);
- ispccdc_obj.pm_state = enable;
-}
-EXPORT_SYMBOL(ispccdc_enable);
+ struct isp_device *isp = to_isp_device(isp_ccdc);
+ struct device *dev = to_device(isp_ccdc);
+ int enable_lsc;
-/**
- * ispccdc_suspend - Suspend the CCDC module.
- **/
-void ispccdc_suspend(void)
-{
- if (ispccdc_obj.pm_state) {
- if (ispccdc_obj.lsc_state)
- __ispccdc_enable_lsc(0);
- else if (ispccdc_obj.lsc_enable) {
- ispccdc_obj.lsc_state = 1;
- ispccdc_obj.lsc_enable = 0;
+ if (enable) {
+ enable_lsc = enable &&
+ ((isp->pipeline.ccdc_in == CCDC_RAW_GRBG) ||
+ (isp->pipeline.ccdc_in == CCDC_RAW_RGGB) ||
+ (isp->pipeline.ccdc_in == CCDC_RAW_BGGR) ||
+ (isp->pipeline.ccdc_in == CCDC_RAW_GBRG)) &&
+ isp_ccdc->lsc_request_enable &&
+ ispccdc_validate_config_lsc(isp_ccdc,
+ &isp_ccdc->lsc_config) == 0;
+
+ if (enable_lsc) {
+ /* Defer CCDC enablement for
+ * when the prefetch is completed. */
+ isp_reg_writel(dev, IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ,
+ OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+ IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ);
+ ispccdc_enable_lsc(isp_ccdc, 1);
+ return;
}
- __ispccdc_enable(0);
+ isp_reg_writel(dev, IRQ0ENABLE_CCDC_VD1_IRQ,
+ OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+ IRQ0ENABLE_CCDC_VD1_IRQ);
+ } else {
+ ispccdc_enable_lsc(isp_ccdc, 0);
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+ ~IRQ0ENABLE_CCDC_VD1_IRQ);
+ isp_ccdc->lsc_request_enable = isp_ccdc->lsc_enable;
}
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
+ ~ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
}
-EXPORT_SYMBOL(ispccdc_suspend);
/**
- * ispccdc_resume - Resume the CCDC module.
- **/
-void ispccdc_resume(void)
-{
- if (ispccdc_obj.pm_state) {
- if (ispccdc_obj.lsc_state)
- __ispccdc_enable_lsc(1);
- __ispccdc_enable(1);
- }
-}
-EXPORT_SYMBOL(ispccdc_resume);
-
-/*
+ * ispccdc_sbl_busy - Poll idle state of CCDC and related SBL memory write bits
+ * @_isp_ccdc: Pointer to ISP CCDC device.
+ *
* Returns zero if the CCDC is idle and the image has been written to
* memory, too.
- */
-int ispccdc_sbl_busy(void)
+ **/
+int ispccdc_sbl_busy(void *_isp_ccdc)
{
- return ispccdc_busy()
- | (isp_reg_readl(OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_0) &
+ struct isp_ccdc_device *isp_ccdc = _isp_ccdc;
+ struct device *dev = to_device(isp_ccdc);
+
+ return ispccdc_busy(isp_ccdc)
+ | (isp_reg_readl(dev, OMAP3_ISP_IOMEM_SBL,
+ ISPSBL_CCDC_WR_0) &
ISPSBL_CCDC_WR_0_DATA_READY)
- | (isp_reg_readl(OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_1) &
+ | (isp_reg_readl(dev, OMAP3_ISP_IOMEM_SBL,
+ ISPSBL_CCDC_WR_1) &
ISPSBL_CCDC_WR_0_DATA_READY)
- | (isp_reg_readl(OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_2) &
+ | (isp_reg_readl(dev, OMAP3_ISP_IOMEM_SBL,
+ ISPSBL_CCDC_WR_2) &
ISPSBL_CCDC_WR_0_DATA_READY)
- | (isp_reg_readl(OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_3) &
+ | (isp_reg_readl(dev, OMAP3_ISP_IOMEM_SBL,
+ ISPSBL_CCDC_WR_3) &
ISPSBL_CCDC_WR_0_DATA_READY);
}
-EXPORT_SYMBOL(ispccdc_sbl_busy);
/**
- * ispccdc_busy - Gets busy state of the CCDC.
+ * ispccdc_busy - Get busy state of the CCDC.
+ * @isp_ccdc: Pointer to ISP CCDC device.
**/
-int ispccdc_busy(void)
+int ispccdc_busy(struct isp_ccdc_device *isp_ccdc)
{
- return isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR) &
+ struct device *dev = to_device(isp_ccdc);
+
+ return isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_PCR) &
ISPCCDC_PCR_BUSY;
}
-EXPORT_SYMBOL(ispccdc_busy);
/**
- * ispccdc_save_context - Saves the values of the CCDC module registers
+ * ispccdc_lsc_can_stop - Indicate if ccdc lsc module can be stopped corectly.
+ * @isp_ccdc: Pointer to ISP CCDC device.
**/
-void ispccdc_save_context(void)
+int ispccdc_lsc_delay_stop(struct isp_ccdc_device *isp_ccdc)
+{
+ return isp_ccdc->lsc_delay_stop;
+}
+EXPORT_SYMBOL(ispccdc_lsc_delay_stop);
+
+/**
+ * ispccdc_config_shadow_registers - Configure CCDC during interframe time.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ *
+ * Executes LSC deferred enablement before next frame starts.
+ **/
+void ispccdc_config_shadow_registers(struct isp_ccdc_device *isp_ccdc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&isp_ccdc->lock, flags);
+ if (isp_ccdc->shadow_update)
+ goto skip;
+
+ if (isp_ccdc->lsc_defer_setup) {
+ __ispccdc_enable_lsc(isp_ccdc, 0);
+ isp_ccdc->lsc_defer_setup = 0;
+ goto skip;
+ }
+
+ if (isp_ccdc->update_lsc_table) {
+ unsigned long n = isp_ccdc->lsc_table_new;
+ /* Swap tables--no need to vfree in interrupt context */
+ isp_ccdc->lsc_table_new = isp_ccdc->lsc_table_inuse;
+ isp_ccdc->lsc_table_inuse = n;
+ ispccdc_program_lsc(isp_ccdc);
+ isp_ccdc->update_lsc_table = 0;
+ }
+
+ if (isp_ccdc->update_lsc_config) {
+ ispccdc_config_lsc(isp_ccdc);
+ __ispccdc_enable_lsc(isp_ccdc, isp_ccdc->lsc_request_enable);
+ isp_ccdc->update_lsc_config = 0;
+ }
+
+skip:
+ spin_unlock_irqrestore(&isp_ccdc->lock, flags);
+}
+
+/**
+ * ispccdc_config - Set CCDC configuration from userspace
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @userspace_add: Structure containing CCDC configuration sent from userspace.
+ *
+ * Returns 0 if successful, -EINVAL if the pointer to the configuration
+ * structure is null, or the copy_from_user function fails to copy user space
+ * memory to kernel space memory.
+ **/
+int ispccdc_config(struct isp_ccdc_device *isp_ccdc,
+ void *userspace_add)
+{
+ struct isp_device *isp = to_isp_device(isp_ccdc);
+ struct device *dev = to_device(isp_ccdc);
+ struct ispccdc_bclamp bclamp_t;
+ struct ispccdc_blcomp blcomp_t;
+ struct ispccdc_fpc fpc_t;
+ struct ispccdc_culling cull_t;
+ struct ispccdc_update_config *ccdc_struct;
+ unsigned long flags;
+ int ret = 0;
+
+ if (userspace_add == NULL)
+ return -EINVAL;
+
+ ccdc_struct = userspace_add;
+
+ spin_lock_irqsave(&isp_ccdc->lock, flags);
+ isp_ccdc->shadow_update = 1;
+ spin_unlock_irqrestore(&isp_ccdc->lock, flags);
+
+ if (ISP_ABS_CCDC_ALAW & ccdc_struct->flag) {
+ if (ISP_ABS_CCDC_ALAW & ccdc_struct->update)
+ ispccdc_config_alaw(isp_ccdc, ccdc_struct->alawip);
+ ispccdc_enable_alaw(isp_ccdc, 1);
+ } else if (ISP_ABS_CCDC_ALAW & ccdc_struct->update)
+ ispccdc_enable_alaw(isp_ccdc, 0);
+
+ if (ISP_ABS_CCDC_LPF & ccdc_struct->flag)
+ ispccdc_enable_lpf(isp_ccdc, 1);
+ else
+ ispccdc_enable_lpf(isp_ccdc, 0);
+
+ if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->flag) {
+ if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->update) {
+ if (copy_from_user(&bclamp_t, (struct ispccdc_bclamp *)
+ ccdc_struct->bclamp,
+ sizeof(struct ispccdc_bclamp))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ispccdc_enable_black_clamp(isp_ccdc, 1);
+ ispccdc_config_black_clamp(isp_ccdc, bclamp_t);
+ } else
+ ispccdc_enable_black_clamp(isp_ccdc, 1);
+ } else {
+ if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->update) {
+ if (copy_from_user(&bclamp_t, (struct ispccdc_bclamp *)
+ ccdc_struct->bclamp,
+ sizeof(struct ispccdc_bclamp))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ispccdc_enable_black_clamp(isp_ccdc, 0);
+ ispccdc_config_black_clamp(isp_ccdc, bclamp_t);
+ }
+ }
+
+ if (ISP_ABS_CCDC_BCOMP & ccdc_struct->update) {
+ if (copy_from_user(&blcomp_t, (struct ispccdc_blcomp *)
+ ccdc_struct->blcomp,
+ sizeof(blcomp_t))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ispccdc_config_black_comp(isp_ccdc, blcomp_t);
+ }
+
+ if (ISP_ABS_CCDC_FPC & ccdc_struct->flag) {
+ if (ISP_ABS_CCDC_FPC & ccdc_struct->update) {
+ if (copy_from_user(&fpc_t, (struct ispccdc_fpc *)
+ ccdc_struct->fpc,
+ sizeof(fpc_t))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ isp_ccdc->fpc_table_add = kmalloc(64 + fpc_t.fpnum * 4,
+ GFP_KERNEL | GFP_DMA);
+ if (!isp_ccdc->fpc_table_add) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ while (((unsigned long)isp_ccdc->fpc_table_add
+ & 0xFFFFFFC0)
+ != (unsigned long)isp_ccdc->fpc_table_add)
+ isp_ccdc->fpc_table_add++;
+
+ isp_ccdc->fpc_table_add_m = iommu_kmap(
+ isp->iommu,
+ 0,
+ virt_to_phys(isp_ccdc->fpc_table_add),
+ fpc_t.fpnum * 4,
+ IOMMU_FLAG);
+ /* FIXME: Correct unwinding */
+ BUG_ON(IS_ERR_VALUE(isp_ccdc->fpc_table_add_m));
+
+ if (copy_from_user(isp_ccdc->fpc_table_add,
+ (u32 *)fpc_t.fpcaddr,
+ fpc_t.fpnum * 4)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ fpc_t.fpcaddr = isp_ccdc->fpc_table_add_m;
+ ispccdc_config_fpc(isp_ccdc, fpc_t);
+ }
+ ispccdc_enable_fpc(isp_ccdc, 1);
+ } else if (ISP_ABS_CCDC_FPC & ccdc_struct->update)
+ ispccdc_enable_fpc(isp_ccdc, 0);
+
+ if (ISP_ABS_CCDC_CULL & ccdc_struct->update) {
+ if (copy_from_user(&cull_t, (struct ispccdc_culling *)
+ ccdc_struct->cull,
+ sizeof(cull_t))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ ispccdc_config_culling(isp_ccdc, cull_t);
+ }
+
+ if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->update) {
+ if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->flag) {
+ struct ispccdc_lsc_config cfg;
+ if (copy_from_user(&cfg, ccdc_struct->lsc_cfg,
+ sizeof(cfg))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ ret = ispccdc_validate_config_lsc(isp_ccdc, &cfg);
+ if (ret)
+ goto out;
+ memcpy(&isp_ccdc->lsc_config, &cfg,
+ sizeof(isp_ccdc->lsc_config));
+ isp_ccdc->lsc_request_enable = 1;
+ } else {
+ isp_ccdc->lsc_request_enable = 0;
+ }
+ isp_ccdc->update_lsc_config = 1;
+ }
+
+ if (ISP_ABS_TBL_LSC & ccdc_struct->update) {
+ void *n;
+ if (isp_ccdc->lsc_table_new != PTR_FREE)
+ iommu_vfree(isp->iommu, isp_ccdc->lsc_table_new);
+ isp_ccdc->lsc_table_new = iommu_vmalloc(isp->iommu, 0,
+ isp_ccdc->lsc_config.size,
+ IOMMU_FLAG);
+ if (IS_ERR_VALUE(isp_ccdc->lsc_table_new)) {
+ /* Disable LSC if table can not be allocated */
+ isp_ccdc->lsc_table_new = PTR_FREE;
+ isp_ccdc->lsc_request_enable = 0;
+ isp_ccdc->update_lsc_config = 1;
+ ret = -ENOMEM;
+ goto out;
+ }
+ n = da_to_va(isp->iommu, isp_ccdc->lsc_table_new);
+ if (copy_from_user(n, ccdc_struct->lsc,
+ isp_ccdc->lsc_config.size)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ isp_ccdc->update_lsc_table = 1;
+ }
+
+ if (isp_ccdc->update_lsc_table || isp_ccdc->update_lsc_config) {
+ if (isp->running != ISP_RUNNING)
+ ispccdc_setup_lsc(isp_ccdc, &isp->pipeline);
+ else if (isp_ccdc->lsc_enable)
+ isp_ccdc->lsc_defer_setup = 1;
+ else if (isp_ccdc->lsc_request_enable) {
+ ispccdc_setup_lsc(isp_ccdc, &isp->pipeline);
+ ispccdc_enable_lsc(isp_ccdc, 1);
+ }
+ }
+
+ if (ISP_ABS_CCDC_COLPTN & ccdc_struct->update)
+ ispccdc_config_imgattr(isp_ccdc, ccdc_struct->colptn);
+
+out:
+ if (ret == -EFAULT)
+ dev_err(dev,
+ "ccdc: user provided bad configuration data address");
+
+ if (ret == -ENOMEM)
+ dev_err(dev,
+ "ccdc: can not allocate memory");
+
+ isp_ccdc->shadow_update = 0;
+ return ret;
+}
+
+/**
+ * ispccdc_request - Reserve the CCDC module.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * Reserves the CCDC module and assures that is used only once at a time.
+ *
+ * Returns 0 if successful, or -EBUSY if CCDC module is busy.
+ **/
+int ispccdc_request(struct isp_ccdc_device *isp_ccdc)
+{
+ struct device *dev = to_device(isp_ccdc);
+
+ mutex_lock(&isp_ccdc->mutexlock);
+ if (isp_ccdc->ccdc_inuse) {
+ mutex_unlock(&isp_ccdc->mutexlock);
+ DPRINTK_ISPCCDC("ISP_ERR : CCDC Module Busy\n");
+ return -EBUSY;
+ }
+
+ isp_ccdc->ccdc_inuse = 1;
+ mutex_unlock(&isp_ccdc->mutexlock);
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+ ISPCTRL_CCDC_RAM_EN | ISPCTRL_CCDC_CLK_EN |
+ ISPCTRL_SBL_WR1_RAM_EN);
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+ ISPCCDC_CFG_VDLC);
+ return 0;
+}
+
+/**
+ * ispccdc_free - Free the CCDC module.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ *
+ * Frees the CCDC module so it can be used by another process.
+ *
+ * Returns 0 if successful, or -EINVAL if module has been already freed.
+ **/
+int ispccdc_free(struct isp_ccdc_device *isp_ccdc)
+{
+ struct device *dev = to_device(isp_ccdc);
+
+ mutex_lock(&isp_ccdc->mutexlock);
+ if (!isp_ccdc->ccdc_inuse) {
+ mutex_unlock(&isp_ccdc->mutexlock);
+ DPRINTK_ISPCCDC("ISP_ERR: CCDC Module already freed\n");
+ return -EINVAL;
+ }
+
+ isp_ccdc->ccdc_inuse = 0;
+ mutex_unlock(&isp_ccdc->mutexlock);
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+ ~(ISPCTRL_CCDC_CLK_EN |
+ ISPCTRL_CCDC_RAM_EN |
+ ISPCTRL_SBL_WR1_RAM_EN));
+ return 0;
+}
+
+/**
+ * ispccdc_save_context - Save values of the CCDC module registers
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+void ispccdc_save_context(struct device *dev)
{
DPRINTK_ISPCCDC("Saving context\n");
- isp_save_context(ispccdc_reg_list);
+ isp_save_context(dev, ispccdc_reg_list);
}
-EXPORT_SYMBOL(ispccdc_save_context);
/**
- * ispccdc_restore_context - Restores the values of the CCDC module registers
+ * ispccdc_restore_context - Restore values of the CCDC module registers
+ * @dev: Pointer to ISP device
**/
-void ispccdc_restore_context(void)
+void ispccdc_restore_context(struct device *dev)
{
DPRINTK_ISPCCDC("Restoring context\n");
- isp_restore_context(ispccdc_reg_list);
+ isp_restore_context(dev, ispccdc_reg_list);
}
-EXPORT_SYMBOL(ispccdc_restore_context);
-
-/**
- * ispccdc_print_status - Prints the values of the CCDC Module registers
- *
- * Also prints other debug information stored in the CCDC module.
- **/
-void ispccdc_print_status(void)
-{
- if (!is_ispccdc_debug_enabled())
- return;
-
- DPRINTK_ISPCCDC("Module in use =%d\n", ispccdc_obj.ccdc_inuse);
- DPRINTK_ISPCCDC("Accepted CCDC Input (width = %d,Height = %d)\n",
- ispccdc_obj.ccdcin_w,
- ispccdc_obj.ccdcin_h);
- DPRINTK_ISPCCDC("Accepted CCDC Output (width = %d,Height = %d)\n",
- ispccdc_obj.ccdcout_w,
- ispccdc_obj.ccdcout_h);
- DPRINTK_ISPCCDC("###CCDC PCR=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR));
- DPRINTK_ISPCCDC("ISP_CTRL =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
- switch (ispccdc_obj.ccdc_inpfmt) {
- case CCDC_RAW:
- DPRINTK_ISPCCDC("ccdc input format is CCDC_RAW\n");
- break;
- case CCDC_YUV_SYNC:
- DPRINTK_ISPCCDC("ccdc input format is CCDC_YUV_SYNC\n");
- break;
- case CCDC_YUV_BT:
- DPRINTK_ISPCCDC("ccdc input format is CCDC_YUV_BT\n");
- break;
- }
-
- switch (ispccdc_obj.ccdc_outfmt) {
- case CCDC_OTHERS_VP:
- DPRINTK_ISPCCDC("ccdc output format is CCDC_OTHERS_VP\n");
- break;
- case CCDC_OTHERS_MEM:
- DPRINTK_ISPCCDC("ccdc output format is CCDC_OTHERS_MEM\n");
- break;
- case CCDC_YUV_RSZ:
- DPRINTK_ISPCCDC("ccdc output format is CCDC_YUV_RSZ\n");
- break;
- }
-
- DPRINTK_ISPCCDC("###ISP_CTRL in ccdc =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
- DPRINTK_ISPCCDC("###ISP_IRQ0ENABLE in ccdc =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE));
- DPRINTK_ISPCCDC("###ISP_IRQ0STATUS in ccdc =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS));
- DPRINTK_ISPCCDC("###CCDC SYN_MODE=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE));
- DPRINTK_ISPCCDC("###CCDC HORZ_INFO=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO));
- DPRINTK_ISPCCDC("###CCDC VERT_START=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_VERT_START));
- DPRINTK_ISPCCDC("###CCDC VERT_LINES=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_VERT_LINES));
- DPRINTK_ISPCCDC("###CCDC CULLING=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CULLING));
- DPRINTK_ISPCCDC("###CCDC HSIZE_OFF=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF));
- DPRINTK_ISPCCDC("###CCDC SDOFST=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST));
- DPRINTK_ISPCCDC("###CCDC SDR_ADDR=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR));
- DPRINTK_ISPCCDC("###CCDC CLAMP=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP));
- DPRINTK_ISPCCDC("###CCDC COLPTN=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN));
- DPRINTK_ISPCCDC("###CCDC CFG=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG));
- DPRINTK_ISPCCDC("###CCDC VP_OUT=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT));
- DPRINTK_ISPCCDC("###CCDC_SDR_ADDR= 0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR));
- DPRINTK_ISPCCDC("###CCDC FMTCFG=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG));
- DPRINTK_ISPCCDC("###CCDC FMT_HORZ=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ));
- DPRINTK_ISPCCDC("###CCDC FMT_VERT=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT));
- DPRINTK_ISPCCDC("###CCDC LSC_CONFIG=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_LSC_CONFIG));
- DPRINTK_ISPCCDC("###CCDC LSC_INIT=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_LSC_INITIAL));
- DPRINTK_ISPCCDC("###CCDC LSC_TABLE BASE=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_LSC_TABLE_BASE));
- DPRINTK_ISPCCDC("###CCDC LSC TABLE OFFSET=0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
- ISPCCDC_LSC_TABLE_OFFSET));
-}
-EXPORT_SYMBOL(ispccdc_print_status);
/**
* isp_ccdc_init - CCDC module initialization.
+ * @dev: Device pointer specific to the OMAP3 ISP.
*
* Always returns 0
**/
-int __init isp_ccdc_init(void)
+int __init isp_ccdc_init(struct device *dev)
{
- ispccdc_obj.ccdc_inuse = 0;
- ispccdc_config_crop(0, 0, 0, 0);
- mutex_init(&ispccdc_obj.mutexlock);
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_ccdc_device *isp_ccdc = &isp->isp_ccdc;
+ void *p;
- if (is_isplsc_activated()) {
- lsc_gain_table_tmp = kmalloc(LSC_TABLE_INIT_SIZE, GFP_KERNEL |
- GFP_DMA);
- memset(lsc_gain_table_tmp, 0x40, LSC_TABLE_INIT_SIZE);
- lsc_config.initial_x = 0;
- lsc_config.initial_y = 0;
- lsc_config.gain_mode_n = 0x6;
- lsc_config.gain_mode_m = 0x6;
- lsc_config.gain_format = 0x4;
- lsc_config.offset = 0x60;
- lsc_config.size = LSC_TABLE_INIT_SIZE;
- ispccdc_obj.lsc_enable = 1;
- }
+ isp_ccdc->ccdc_inuse = 0;
+ ispccdc_config_crop(isp_ccdc, 0, 0, 0, 0);
+ mutex_init(&isp_ccdc->mutexlock);
+
+ isp_ccdc->update_lsc_config = 0;
+ isp_ccdc->lsc_request_enable = 1;
+ isp_ccdc->lsc_defer_setup = 0;
+ isp_ccdc->lsc_delay_stop = 0;
+
+ isp_ccdc->lsc_config.initial_x = 0;
+ isp_ccdc->lsc_config.initial_y = 0;
+ isp_ccdc->lsc_config.gain_mode_n = 0x6;
+ isp_ccdc->lsc_config.gain_mode_m = 0x6;
+ isp_ccdc->lsc_config.gain_format = 0x4;
+ isp_ccdc->lsc_config.offset = 0x60;
+ isp_ccdc->lsc_config.size = LSC_TABLE_INIT_SIZE;
+
+ isp_ccdc->update_lsc_table = 0;
+ isp_ccdc->lsc_table_new = PTR_FREE;
+ isp_ccdc->lsc_table_inuse = iommu_vmalloc(isp->iommu, 0,
+ LSC_TABLE_INIT_SIZE,
+ IOMMU_FLAG);
+ if (IS_ERR_VALUE(isp_ccdc->lsc_table_inuse))
+ return -ENOMEM;
+ p = da_to_va(isp->iommu, isp_ccdc->lsc_table_inuse);
+ memset(p, 0x40, LSC_TABLE_INIT_SIZE);
+
+ isp_ccdc->shadow_update = 0;
+ spin_lock_init(&isp_ccdc->lock);
return 0;
}
/**
* isp_ccdc_cleanup - CCDC module cleanup.
+ * @dev: Device pointer specific to the OMAP3 ISP.
**/
-void isp_ccdc_cleanup(void)
+void isp_ccdc_cleanup(struct device *dev)
{
- if (is_isplsc_activated()) {
- ispccdc_free_lsc();
- kfree(lsc_gain_table_tmp);
- }
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_ccdc_device *isp_ccdc = &isp->isp_ccdc;
- if (fpc_table_add_m != 0) {
- ispmmu_kunmap(fpc_table_add_m);
- kfree(fpc_table_add);
+ iommu_vfree(isp->iommu, isp_ccdc->lsc_table_inuse);
+ if (isp_ccdc->lsc_table_new != PTR_FREE)
+ iommu_vfree(isp->iommu, isp_ccdc->lsc_table_new);
+
+ if (isp_ccdc->fpc_table_add_m != 0) {
+ iommu_kunmap(isp->iommu, isp_ccdc->fpc_table_add_m);
+ kfree(isp_ccdc->fpc_table_add);
}
}
diff --git a/drivers/media/video/isp/ispccdc.h b/drivers/media/video/isp/ispccdc.h
index 606857a..9cfbc5c 100644
--- a/drivers/media/video/isp/ispccdc.h
+++ b/drivers/media/video/isp/ispccdc.h
@@ -28,7 +28,10 @@
/* Enumeration constants for CCDC input output format */
enum ccdc_input {
- CCDC_RAW,
+ CCDC_RAW_GRBG,
+ CCDC_RAW_RGGB,
+ CCDC_RAW_BGGR,
+ CCDC_RAW_GBRG,
CCDC_YUV_SYNC,
CCDC_YUV_BT,
CCDC_OTHERS
@@ -130,82 +133,97 @@
u32 fmtaddr7;
};
-int ispccdc_request(void);
+enum ispccdc_raw_fmt {
+ ISPCCDC_INPUT_FMT_GR_BG,
+ ISPCCDC_INPUT_FMT_RG_GB,
+ ISPCCDC_INPUT_FMT_BG_GR,
+ ISPCCDC_INPUT_FMT_GB_RG,
+};
-int ispccdc_free(void);
+/**
+ * struct isp_ccdc_device - Structure for the CCDC module to store its own
+ * information
+ * @ccdc_inuse: Flag to determine if CCDC has been reserved or not (0 or 1).
+ * @ccdcin_woffset: CCDC input horizontal offset.
+ * @ccdcin_hoffset: CCDC input vertical offset.
+ * @crop_w: Crop width.
+ * @crop_h: Crop weight.
+ * @vpout_en: Video port output enable.
+ * @wen: Data write enable.
+ * @exwen: External data write enable.
+ * @refmt_en: Reformatter enable.
+ * @ccdcslave: CCDC slave mode enable.
+ * @syncif_ipmod: Image
+ * @obclamp_en: Data input format.
+ * @mutexlock: Mutex used to get access to the CCDC.
+ * @wenlog: Write Enable logic to use against valid data signal.
+ * @fpc_table_add_m: ISP MMU mapped address of the current used FPC table.
+ * @fpc_table_add: Virtual address of the current used FPC table.
+ * @update_lsc_config: Set when user changes lsc_config
+ * @lsc_request_enable: Whether LSC is requested to be enabled
+ * @lsc_config: LSC config set by user
+ * @update_lsc_table: Set when user provides a new LSC table to lsc_table_new
+ * @lsc_table_new: LSC table set by user, ISP address
+ * @lsc_table_inuse: LSC table currently in use, ISP address
+ * @shadow_update: non-zero when user is updating CCDC configuration
+ * @lock: serializes shadow_update with interrupt handler
+ */
+struct isp_ccdc_device {
+ u8 ccdc_inuse;
+ u32 ccdcin_woffset;
+ u32 ccdcin_hoffset;
+ u32 crop_w;
+ u32 crop_h;
+ u8 vpout_en;
+ u8 wen;
+ u8 exwen;
+ u8 refmt_en;
+ u8 ccdcslave;
+ u8 syncif_ipmod;
+ u8 obclamp_en;
+ struct mutex mutexlock; /* For checking/modifying ccdc_inuse */
+ u32 wenlog;
+ unsigned long fpc_table_add_m;
+ u32 *fpc_table_add;
+ enum ispccdc_raw_fmt raw_fmt_in;
-int ispccdc_config_datapath(enum ccdc_input input, enum ccdc_output output);
+ /* LSC related fields */
+ u8 lsc_delay_stop;
+ u8 lsc_enable;
+ u8 update_lsc_config;
+ u8 lsc_request_enable;
+ u8 lsc_defer_setup;
+ struct ispccdc_lsc_config lsc_config;
+ u8 update_lsc_table;
+ u32 lsc_table_new;
+ u32 lsc_table_inuse;
-void ispccdc_config_crop(u32 left, u32 top, u32 height, u32 width);
+ int shadow_update;
+ spinlock_t lock;
+};
-void ispccdc_config_sync_if(struct ispccdc_syncif syncif);
-
-int ispccdc_config_black_clamp(struct ispccdc_bclamp bclamp);
-
-void ispccdc_enable_black_clamp(u8 enable);
-
-int ispccdc_config_fpc(struct ispccdc_fpc fpc);
-
-void ispccdc_enable_fpc(u8 enable);
-
-void ispccdc_config_black_comp(struct ispccdc_blcomp blcomp);
-
-void ispccdc_config_vp(struct ispccdc_vp vp);
-
-void ispccdc_enable_vp(u8 enable);
-
-void ispccdc_config_reformatter(struct ispccdc_refmt refmt);
-
-void ispccdc_enable_reformatter(u8 enable);
-
-void ispccdc_config_culling(struct ispccdc_culling culling);
-
-void ispccdc_enable_lpf(u8 enable);
-
-void ispccdc_config_alaw(enum alaw_ipwidth ipwidth);
-
-void ispccdc_enable_alaw(u8 enable);
-
-int ispccdc_load_lsc(u8 *table_addr, u32 table_size);
-
-void ispccdc_config_lsc(struct ispccdc_lsc_config *lsc_cfg);
-
-void ispccdc_enable_lsc(u8 enable);
-
-void ispccdc_lsc_error_handler(void);
-
-void ispccdc_config_imgattr(u32 colptn);
-
-void ispccdc_config_shadow_registers(void);
-
-int ispccdc_try_size(u32 input_w, u32 input_h, u32 *output_w, u32 *output_h);
-
-int ispccdc_config_size(u32 input_w, u32 input_h, u32 output_w, u32 output_h);
-
-int ispccdc_config_outlineoffset(u32 offset, u8 oddeven, u8 numlines);
-
-int ispccdc_set_outaddr(u32 addr);
-
-void ispccdc_enable(u8 enable);
-
-void ispccdc_suspend(void);
-
-void ispccdc_resume(void);
-
-int ispccdc_sbl_busy(void);
-
-int ispccdc_busy(void);
-
-void ispccdc_save_context(void);
-
-void ispccdc_restore_context(void);
-
-void ispccdc_print_status(void);
-
-int omap34xx_isp_ccdc_config(void *userspace_add);
-
-void ispccdc_set_wenlog(u32 wenlog);
-
-void ispccdc_set_crop_offset(enum ispccdc_raw_fmt);
+int ispccdc_set_outaddr(struct isp_ccdc_device *isp_ccdc, u32 addr);
+void ispccdc_set_wenlog(struct isp_ccdc_device *isp_ccdc, u32 wenlog);
+int ispccdc_try_pipeline(struct isp_ccdc_device *isp_ccdc,
+ struct isp_pipeline *pipe);
+int ispccdc_s_pipeline(struct isp_ccdc_device *isp_ccdc,
+ struct isp_pipeline *pipe);
+void ispccdc_set_raw_offset(struct isp_ccdc_device *isp_ccdc,
+ enum ispccdc_raw_fmt raw_fmt);
+void ispccdc_enable(struct isp_ccdc_device *isp_ccdc, u8 enable);
+int ispccdc_sbl_busy(void *_isp_ccdc);
+int ispccdc_busy(struct isp_ccdc_device *isp_ccdc);
+void ispccdc_config_shadow_registers(struct isp_ccdc_device *isp_ccdc);
+int ispccdc_config(struct isp_ccdc_device *isp_ccdc,
+ void *userspace_add);
+int ispccdc_request(struct isp_ccdc_device *isp_ccdc);
+int ispccdc_free(struct isp_ccdc_device *isp_ccdc);
+void ispccdc_save_context(struct device *dev);
+void ispccdc_restore_context(struct device *dev);
+void ispccdc_enable_lsc(struct isp_ccdc_device *isp_ccdc, u8 enable);
+int ispccdc_lsc_delay_stop(struct isp_ccdc_device *isp_ccdc);
+void ispccdc_lsc_state_handler(struct isp_ccdc_device *isp_ccdc,
+ unsigned long status);
+void ispccdc_lsc_pref_comp_handler(struct isp_ccdc_device *isp_ccdc);
#endif /* OMAP_ISP_CCDC_H */
diff --git a/drivers/media/video/isp/ispcsi2.c b/drivers/media/video/isp/ispcsi2.c
index 00aa362..cc8fa39 100644
--- a/drivers/media/video/isp/ispcsi2.c
+++ b/drivers/media/video/isp/ispcsi2.c
@@ -26,19 +26,6 @@
#include "ispreg.h"
#include "ispcsi2.h"
-static struct isp_csi2_cfg current_csi2_cfg;
-static struct isp_csi2_cfg_update current_csi2_cfg_update;
-
-static bool update_complexio_cfg1;
-static bool update_phy_cfg0;
-static bool update_phy_cfg1;
-static bool update_ctx_ctrl1[8];
-static bool update_ctx_ctrl2[8];
-static bool update_ctx_ctrl3[8];
-static bool update_timing;
-static bool update_ctrl;
-static bool uses_videoport;
-
/* Structure for saving/restoring CSI2 module registers*/
static struct isp_reg ispcsi2_reg_list[] = {
{OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG, 0},
@@ -75,13 +62,14 @@
* position. To apply this settings, use the isp_csi2_complexio_lanes_update()
* function just after calling this function.
**/
-int isp_csi2_complexio_lanes_config(struct isp_csi2_lanes_cfg *reqcfg)
+int isp_csi2_complexio_lanes_config(struct isp_csi2_device *isp_csi2,
+ struct isp_csi2_lanes_cfg *reqcfg)
{
int i;
bool pos_occupied[5] = {false, false, false, false, false};
- struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes;
+ struct isp_csi2_lanes_cfg *currlanes = &isp_csi2->current_cfg.lanes;
struct isp_csi2_lanes_cfg_update *currlanes_u =
- ¤t_csi2_cfg_update.lanes;
+ &isp_csi2->current_cfg_update.lanes;
/* Validating parameters sent by driver */
if (reqcfg == NULL) {
@@ -97,8 +85,10 @@
" parameters for data lane #%d\n", i);
goto err_einval;
}
- if (pos_occupied[reqcfg->data[i].pos - 1] &&
- reqcfg->data[i].pos > 0) {
+ if (!reqcfg->data[i].pos)
+ continue;
+
+ if (pos_occupied[reqcfg->data[i].pos - 1]) {
printk(KERN_ERR "Lane #%d already occupied\n",
reqcfg->data[i].pos);
goto err_einval;
@@ -124,12 +114,12 @@
if (currlanes->data[i].pos != reqcfg->data[i].pos) {
currlanes->data[i].pos = reqcfg->data[i].pos;
currlanes_u->data[i] = true;
- update_complexio_cfg1 = true;
+ isp_csi2->update_complexio_cfg1 = true;
}
if (currlanes->data[i].pol != reqcfg->data[i].pol) {
currlanes->data[i].pol = reqcfg->data[i].pol;
currlanes_u->data[i] = true;
- update_complexio_cfg1 = true;
+ isp_csi2->update_complexio_cfg1 = true;
}
/* If the lane position is non zero then we can assume that
* the initial lane state is on.
@@ -141,12 +131,12 @@
if (currlanes->clk.pos != reqcfg->clk.pos) {
currlanes->clk.pos = reqcfg->clk.pos;
currlanes_u->clk = true;
- update_complexio_cfg1 = true;
+ isp_csi2->update_complexio_cfg1 = true;
}
if (currlanes->clk.pol != reqcfg->clk.pol) {
currlanes->clk.pol = reqcfg->clk.pol;
currlanes_u->clk = true;
- update_complexio_cfg1 = true;
+ isp_csi2->update_complexio_cfg1 = true;
}
return 0;
err_einval:
@@ -163,18 +153,20 @@
* set to true.
* Always returns 0.
**/
-int isp_csi2_complexio_lanes_update(bool force_update)
+int isp_csi2_complexio_lanes_update(struct isp_csi2_device *isp_csi2,
+ bool force_update)
{
- struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes;
+ struct isp_csi2_lanes_cfg *currlanes = &isp_csi2->current_cfg.lanes;
struct isp_csi2_lanes_cfg_update *currlanes_u =
- ¤t_csi2_cfg_update.lanes;
+ &isp_csi2->current_cfg_update.lanes;
u32 reg;
int i;
- if (!update_complexio_cfg1 && !force_update)
+ if (!isp_csi2->update_complexio_cfg1 && !force_update)
return 0;
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1);
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_COMPLEXIO_CFG1);
for (i = 0; i < 4; i++) {
if (currlanes_u->data[i] || force_update) {
reg &= ~(ISPCSI2_COMPLEXIO_CFG1_DATA_POL_MASK(i + 1) |
@@ -199,9 +191,10 @@
ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_SHIFT);
currlanes_u->clk = false;
}
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1);
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_COMPLEXIO_CFG1);
- update_complexio_cfg1 = false;
+ isp_csi2->update_complexio_cfg1 = false;
return 0;
}
@@ -211,9 +204,9 @@
*
* Always returns 0.
**/
-int isp_csi2_complexio_lanes_count(int cnt)
+int isp_csi2_complexio_lanes_count(struct isp_csi2_device *isp_csi2, int cnt)
{
- struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes;
+ struct isp_csi2_lanes_cfg *currlanes = &isp_csi2->current_cfg.lanes;
int i;
for (i = 0; i < 4; i++) {
@@ -223,7 +216,7 @@
currlanes->data[i].state = ISP_CSI2_LANE_OFF;
}
- isp_csi2_complexio_lanes_update(true);
+ isp_csi2_complexio_lanes_update(isp_csi2, true);
return 0;
}
EXPORT_SYMBOL(isp_csi2_complexio_lanes_count);
@@ -234,15 +227,16 @@
* Gets settings from HW registers and fills in the internal driver memory
* Always returns 0.
**/
-int isp_csi2_complexio_lanes_get(void)
+int isp_csi2_complexio_lanes_get(struct isp_csi2_device *isp_csi2)
{
- struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes;
+ struct isp_csi2_lanes_cfg *currlanes = &isp_csi2->current_cfg.lanes;
struct isp_csi2_lanes_cfg_update *currlanes_u =
- ¤t_csi2_cfg_update.lanes;
+ &isp_csi2->current_cfg_update.lanes;
u32 reg;
int i;
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1);
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_COMPLEXIO_CFG1);
for (i = 0; i < 4; i++) {
currlanes->data[i].pol = (reg &
ISPCSI2_COMPLEXIO_CFG1_DATA_POL_MASK(i + 1)) >>
@@ -259,7 +253,7 @@
ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_SHIFT;
currlanes_u->clk = false;
- update_complexio_cfg1 = false;
+ isp_csi2->update_complexio_cfg1 = false;
return 0;
}
@@ -269,12 +263,14 @@
* Returns 3 possible valid states: ISP_CSI2_POWER_OFF, ISP_CSI2_POWER_ON,
* and ISP_CSI2_POWER_ULPW.
**/
-static enum isp_csi2_power_cmds isp_csi2_complexio_power_status(void)
+static enum isp_csi2_power_cmds isp_csi2_complexio_power_status(
+ struct isp_csi2_device *isp_csi2)
{
enum isp_csi2_power_cmds ret;
u32 reg;
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1) &
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_COMPLEXIO_CFG1) &
ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_MASK;
switch (reg) {
case ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_OFF:
@@ -298,11 +294,13 @@
*
* Always returns 0.
**/
-int isp_csi2_complexio_power_autoswitch(bool enable)
+int isp_csi2_complexio_power_autoswitch(struct isp_csi2_device *isp_csi2,
+ bool enable)
{
u32 reg;
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1);
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_COMPLEXIO_CFG1);
reg &= ~ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_MASK;
if (enable)
@@ -310,7 +308,8 @@
else
reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_DISABLE;
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1);
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_COMPLEXIO_CFG1);
return 0;
}
@@ -320,13 +319,15 @@
*
* Returns 0 if successful, or -EBUSY if the retry count is exceeded.
**/
-int isp_csi2_complexio_power(enum isp_csi2_power_cmds power_cmd)
+int isp_csi2_complexio_power(struct isp_csi2_device *isp_csi2,
+ enum isp_csi2_power_cmds power_cmd)
{
enum isp_csi2_power_cmds current_state;
u32 reg;
u8 retry_count;
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1) &
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_COMPLEXIO_CFG1) &
~ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_MASK;
switch (power_cmd) {
case ISP_CSI2_POWER_OFF:
@@ -342,12 +343,13 @@
printk(KERN_ERR "CSI2: ERROR - Wrong Power command!\n");
return -EINVAL;
}
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1);
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_COMPLEXIO_CFG1);
retry_count = 0;
do {
udelay(50);
- current_state = isp_csi2_complexio_power_status();
+ current_state = isp_csi2_complexio_power_status(isp_csi2);
if (current_state != power_cmd) {
printk(KERN_DEBUG "CSI2: Complex IO power command not"
@@ -376,16 +378,17 @@
* Validates and saves to internal driver memory the passed configuration.
* Always returns 0.
**/
-int isp_csi2_ctrl_config_frame_mode(enum isp_csi2_frame_mode frame_mode)
+int isp_csi2_ctrl_config_frame_mode(struct isp_csi2_device *isp_csi2,
+ enum isp_csi2_frame_mode frame_mode)
{
- struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
struct isp_csi2_ctrl_cfg_update *currctrl_u =
- ¤t_csi2_cfg_update.ctrl;
+ &isp_csi2->current_cfg_update.ctrl;
if (currctrl->frame_mode != frame_mode) {
currctrl->frame_mode = frame_mode;
currctrl_u->frame_mode = true;
- update_ctrl = true;
+ isp_csi2->update_ctrl = true;
}
return 0;
}
@@ -397,16 +400,17 @@
* Validates and saves to internal driver memory the passed configuration.
* Always returns 0.
**/
-int isp_csi2_ctrl_config_vp_clk_enable(bool vp_clk_enable)
+int isp_csi2_ctrl_config_vp_clk_enable(struct isp_csi2_device *isp_csi2,
+ bool vp_clk_enable)
{
- struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
struct isp_csi2_ctrl_cfg_update *currctrl_u =
- ¤t_csi2_cfg_update.ctrl;
+ &isp_csi2->current_cfg_update.ctrl;
if (currctrl->vp_clk_enable != vp_clk_enable) {
currctrl->vp_clk_enable = vp_clk_enable;
currctrl_u->vp_clk_enable = true;
- update_ctrl = true;
+ isp_csi2->update_ctrl = true;
}
return 0;
}
@@ -419,16 +423,17 @@
* Validates and saves to internal driver memory the passed configuration.
* Always returns 0.
**/
-int isp_csi2_ctrl_config_vp_only_enable(bool vp_only_enable)
+int isp_csi2_ctrl_config_vp_only_enable(struct isp_csi2_device *isp_csi2,
+ bool vp_only_enable)
{
- struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
struct isp_csi2_ctrl_cfg_update *currctrl_u =
- ¤t_csi2_cfg_update.ctrl;
+ &isp_csi2->current_cfg_update.ctrl;
if (currctrl->vp_only_enable != vp_only_enable) {
currctrl->vp_only_enable = vp_only_enable;
currctrl_u->vp_only_enable = true;
- update_ctrl = true;
+ isp_csi2->update_ctrl = true;
}
return 0;
}
@@ -441,11 +446,12 @@
* Validates and saves to internal driver memory the passed configuration.
* Returns 0 if successful, or -EINVAL if wrong divider value is passed.
**/
-int isp_csi2_ctrl_config_vp_out_ctrl(u8 vp_out_ctrl)
+int isp_csi2_ctrl_config_vp_out_ctrl(struct isp_csi2_device *isp_csi2,
+ u8 vp_out_ctrl)
{
- struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
struct isp_csi2_ctrl_cfg_update *currctrl_u =
- ¤t_csi2_cfg_update.ctrl;
+ &isp_csi2->current_cfg_update.ctrl;
if ((vp_out_ctrl == 0) || (vp_out_ctrl > 4)) {
printk(KERN_ERR "CSI2: Wrong divisor value. Must be between"
@@ -456,7 +462,7 @@
if (currctrl->vp_out_ctrl != vp_out_ctrl) {
currctrl->vp_out_ctrl = vp_out_ctrl;
currctrl_u->vp_out_ctrl = true;
- update_ctrl = true;
+ isp_csi2->update_ctrl = true;
}
return 0;
}
@@ -467,16 +473,17 @@
*
* Always returns 0.
**/
-int isp_csi2_ctrl_config_debug_enable(bool debug_enable)
+int isp_csi2_ctrl_config_debug_enable(struct isp_csi2_device *isp_csi2,
+ bool debug_enable)
{
- struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
struct isp_csi2_ctrl_cfg_update *currctrl_u =
- ¤t_csi2_cfg_update.ctrl;
+ &isp_csi2->current_cfg_update.ctrl;
if (currctrl->debug_enable != debug_enable) {
currctrl->debug_enable = debug_enable;
currctrl_u->debug_enable = true;
- update_ctrl = true;
+ isp_csi2->update_ctrl = true;
}
return 0;
}
@@ -487,11 +494,12 @@
*
* Returns 0 if successful, or -EINVAL if burst size is wrong.
**/
-int isp_csi2_ctrl_config_burst_size(u8 burst_size)
+int isp_csi2_ctrl_config_burst_size(struct isp_csi2_device *isp_csi2,
+ u8 burst_size)
{
- struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
struct isp_csi2_ctrl_cfg_update *currctrl_u =
- ¤t_csi2_cfg_update.ctrl;
+ &isp_csi2->current_cfg_update.ctrl;
if (burst_size > 3) {
printk(KERN_ERR "CSI2: Wrong burst size. Must be between"
" 0 and 3");
@@ -501,7 +509,7 @@
if (currctrl->burst_size != burst_size) {
currctrl->burst_size = burst_size;
currctrl_u->burst_size = true;
- update_ctrl = true;
+ isp_csi2->update_ctrl = true;
}
return 0;
}
@@ -512,16 +520,17 @@
*
* Always returns 0.
**/
-int isp_csi2_ctrl_config_ecc_enable(bool ecc_enable)
+int isp_csi2_ctrl_config_ecc_enable(struct isp_csi2_device *isp_csi2,
+ bool ecc_enable)
{
- struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
struct isp_csi2_ctrl_cfg_update *currctrl_u =
- ¤t_csi2_cfg_update.ctrl;
+ &isp_csi2->current_cfg_update.ctrl;
if (currctrl->ecc_enable != ecc_enable) {
currctrl->ecc_enable = ecc_enable;
currctrl_u->ecc_enable = true;
- update_ctrl = true;
+ isp_csi2->update_ctrl = true;
}
return 0;
}
@@ -532,16 +541,17 @@
*
* Always returns 0.
**/
-int isp_csi2_ctrl_config_secure_mode(bool secure_mode)
+int isp_csi2_ctrl_config_secure_mode(struct isp_csi2_device *isp_csi2,
+ bool secure_mode)
{
- struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
struct isp_csi2_ctrl_cfg_update *currctrl_u =
- ¤t_csi2_cfg_update.ctrl;
+ &isp_csi2->current_cfg_update.ctrl;
if (currctrl->secure_mode != secure_mode) {
currctrl->secure_mode = secure_mode;
currctrl_u->secure_mode = true;
- update_ctrl = true;
+ isp_csi2->update_ctrl = true;
}
return 0;
}
@@ -552,16 +562,17 @@
*
* Always returns 0.
**/
-int isp_csi2_ctrl_config_if_enable(bool if_enable)
+int isp_csi2_ctrl_config_if_enable(struct isp_csi2_device *isp_csi2,
+ bool if_enable)
{
- struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
struct isp_csi2_ctrl_cfg_update *currctrl_u =
- ¤t_csi2_cfg_update.ctrl;
+ &isp_csi2->current_cfg_update.ctrl;
if (currctrl->if_enable != if_enable) {
currctrl->if_enable = if_enable;
currctrl_u->if_enable = true;
- update_ctrl = true;
+ isp_csi2->update_ctrl = true;
}
return 0;
}
@@ -576,15 +587,16 @@
* set to true.
* Always returns 0.
**/
-int isp_csi2_ctrl_update(bool force_update)
+int isp_csi2_ctrl_update(struct isp_csi2_device *isp_csi2, bool force_update)
{
- struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
struct isp_csi2_ctrl_cfg_update *currctrl_u =
- ¤t_csi2_cfg_update.ctrl;
+ &isp_csi2->current_cfg_update.ctrl;
u32 reg;
- if (update_ctrl || force_update) {
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTRL);
+ if (isp_csi2->update_ctrl || force_update) {
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_CTRL);
if (currctrl_u->frame_mode || force_update) {
reg &= ~ISPCSI2_CTRL_FRAME_MASK;
if (currctrl->frame_mode)
@@ -603,7 +615,7 @@
}
if (currctrl_u->vp_only_enable || force_update) {
reg &= ~ISPCSI2_CTRL_VP_ONLY_EN_MASK;
- uses_videoport = currctrl->vp_only_enable;
+ isp_csi2->uses_videoport = currctrl->vp_only_enable;
if (currctrl->vp_only_enable)
reg |= ISPCSI2_CTRL_VP_ONLY_EN_ENABLE;
else
@@ -654,8 +666,9 @@
reg |= ISPCSI2_CTRL_IF_EN_DISABLE;
currctrl_u->if_enable = false;
}
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTRL);
- update_ctrl = false;
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_CTRL);
+ isp_csi2->update_ctrl = false;
}
return 0;
}
@@ -665,14 +678,15 @@
*
* Always returns 0.
**/
-int isp_csi2_ctrl_get(void)
+int isp_csi2_ctrl_get(struct isp_csi2_device *isp_csi2)
{
- struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
struct isp_csi2_ctrl_cfg_update *currctrl_u =
- ¤t_csi2_cfg_update.ctrl;
+ &isp_csi2->current_cfg_update.ctrl;
u32 reg;
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTRL);
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_CTRL);
currctrl->frame_mode = (reg & ISPCSI2_CTRL_FRAME_MASK) >>
ISPCSI2_CTRL_FRAME_SHIFT;
currctrl_u->frame_mode = false;
@@ -689,7 +703,7 @@
currctrl->vp_only_enable = true;
else
currctrl->vp_only_enable = false;
- uses_videoport = currctrl->vp_only_enable;
+ isp_csi2->uses_videoport = currctrl->vp_only_enable;
currctrl_u->vp_only_enable = false;
currctrl->vp_out_ctrl = ((reg & ISPCSI2_CTRL_VP_OUT_CTRL_MASK) >>
@@ -724,7 +738,7 @@
currctrl->if_enable = false;
currctrl_u->if_enable = false;
- update_ctrl = false;
+ isp_csi2->update_ctrl = false;
return 0;
}
@@ -751,7 +765,8 @@
*
* Returns 0 if successful, or -EINVAL if Virtual ID is not in range (0-3).
**/
-int isp_csi2_ctx_config_virtual_id(u8 ctxnum, u8 virtual_id)
+int isp_csi2_ctx_config_virtual_id(struct isp_csi2_device *isp_csi2, u8 ctxnum,
+ u8 virtual_id)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -763,13 +778,13 @@
return -EINVAL;
}
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
if (selected_ctx->virtual_id != virtual_id) {
selected_ctx->virtual_id = virtual_id;
selected_ctx_u->virtual_id = true;
- update_ctx_ctrl2[ctxnum] = true;
+ isp_csi2->update_ctx_ctrl2[ctxnum] = true;
}
return 0;
@@ -782,20 +797,21 @@
*
* Always returns 0.
**/
-int isp_csi2_ctx_config_frame_count(u8 ctxnum, u8 frame_count)
+int isp_csi2_ctx_config_frame_count(struct isp_csi2_device *isp_csi2, u8 ctxnum,
+ u8 frame_count)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
isp_csi2_ctx_validate(&ctxnum);
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
if (selected_ctx->frame_count != frame_count) {
selected_ctx->frame_count = frame_count;
selected_ctx_u->frame_count = true;
- update_ctx_ctrl1[ctxnum] = true;
+ isp_csi2->update_ctx_ctrl1[ctxnum] = true;
}
return 0;
@@ -809,7 +825,8 @@
* Returns 0 if successful, or -EINVAL if the format is not supported by the
* receiver.
**/
-int isp_csi2_ctx_config_format(u8 ctxnum, u32 pixformat)
+int isp_csi2_ctx_config_format(struct isp_csi2_device *isp_csi2, u8 ctxnum,
+ u32 pixformat)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -832,12 +849,12 @@
return -EINVAL;
}
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
selected_ctx->format = pix;
selected_ctx_u->format = true;
- update_ctx_ctrl2[ctxnum] = true;
+ isp_csi2->update_ctx_ctrl2[ctxnum] = true;
return 0;
}
@@ -849,7 +866,8 @@
*
* Returns 0 if successful, or -EINVAL if the alpha value is bigger than 16383.
**/
-int isp_csi2_ctx_config_alpha(u8 ctxnum, u16 alpha)
+int isp_csi2_ctx_config_alpha(struct isp_csi2_device *isp_csi2, u8 ctxnum,
+ u16 alpha)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -861,13 +879,13 @@
return -EINVAL;
}
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
if (selected_ctx->alpha != alpha) {
selected_ctx->alpha = alpha;
selected_ctx_u->alpha = true;
- update_ctx_ctrl3[ctxnum] = true;
+ isp_csi2->update_ctx_ctrl3[ctxnum] = true;
}
return 0;
}
@@ -879,7 +897,8 @@
*
* Returns 0 if successful, or -EINVAL if the line offset is bigger than 1023.
**/
-int isp_csi2_ctx_config_data_offset(u8 ctxnum, u16 data_offset)
+int isp_csi2_ctx_config_data_offset(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, u16 data_offset)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -891,8 +910,8 @@
return -EINVAL;
}
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
if (selected_ctx->data_offset != data_offset) {
selected_ctx->data_offset = data_offset;
@@ -908,7 +927,8 @@
*
* Always returns 0.
**/
-int isp_csi2_ctx_config_ping_addr(u8 ctxnum, u32 ping_addr)
+int isp_csi2_ctx_config_ping_addr(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, u32 ping_addr)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -917,8 +937,8 @@
ping_addr &= ~(0x1F);
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
if (selected_ctx->ping_addr != ping_addr) {
selected_ctx->ping_addr = ping_addr;
@@ -934,7 +954,8 @@
*
* Always returns 0.
**/
-int isp_csi2_ctx_config_pong_addr(u8 ctxnum, u32 pong_addr)
+int isp_csi2_ctx_config_pong_addr(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, u32 pong_addr)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -943,8 +964,8 @@
pong_addr &= ~(0x1F);
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
if (selected_ctx->pong_addr != pong_addr) {
selected_ctx->pong_addr = pong_addr;
@@ -961,20 +982,21 @@
*
* Always returns 0.
**/
-int isp_csi2_ctx_config_eof_enabled(u8 ctxnum, bool eof_enabled)
+int isp_csi2_ctx_config_eof_enabled(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, bool eof_enabled)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
isp_csi2_ctx_validate(&ctxnum);
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
if (selected_ctx->eof_enabled != eof_enabled) {
selected_ctx->eof_enabled = eof_enabled;
selected_ctx_u->eof_enabled = true;
- update_ctx_ctrl1[ctxnum] = true;
+ isp_csi2->update_ctx_ctrl1[ctxnum] = true;
}
return 0;
}
@@ -987,20 +1009,21 @@
*
* Always returns 0.
**/
-int isp_csi2_ctx_config_eol_enabled(u8 ctxnum, bool eol_enabled)
+int isp_csi2_ctx_config_eol_enabled(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, bool eol_enabled)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
isp_csi2_ctx_validate(&ctxnum);
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
if (selected_ctx->eol_enabled != eol_enabled) {
selected_ctx->eol_enabled = eol_enabled;
selected_ctx_u->eol_enabled = true;
- update_ctx_ctrl1[ctxnum] = true;
+ isp_csi2->update_ctx_ctrl1[ctxnum] = true;
}
return 0;
}
@@ -1013,20 +1036,21 @@
*
* Always returns 0.
**/
-int isp_csi2_ctx_config_checksum_enabled(u8 ctxnum, bool checksum_enabled)
+int isp_csi2_ctx_config_checksum_enabled(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, bool checksum_enabled)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
isp_csi2_ctx_validate(&ctxnum);
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
if (selected_ctx->checksum_enabled != checksum_enabled) {
selected_ctx->checksum_enabled = checksum_enabled;
selected_ctx_u->checksum_enabled = true;
- update_ctx_ctrl1[ctxnum] = true;
+ isp_csi2->update_ctx_ctrl1[ctxnum] = true;
}
return 0;
}
@@ -1038,20 +1062,21 @@
*
* Always returns 0.
**/
-int isp_csi2_ctx_config_enabled(u8 ctxnum, bool enabled)
+int isp_csi2_ctx_config_enabled(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, bool enabled)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
isp_csi2_ctx_validate(&ctxnum);
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
if (selected_ctx->enabled != enabled) {
selected_ctx->enabled = enabled;
selected_ctx_u->enabled = true;
- update_ctx_ctrl1[ctxnum] = true;
+ isp_csi2->update_ctx_ctrl1[ctxnum] = true;
}
return 0;
}
@@ -1067,7 +1092,8 @@
* set to true.
* Always returns 0.
**/
-int isp_csi2_ctx_update(u8 ctxnum, bool force_update)
+int isp_csi2_ctx_update(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, bool force_update)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -1075,11 +1101,11 @@
isp_csi2_ctx_validate(&ctxnum);
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
- if (update_ctx_ctrl1[ctxnum] || force_update) {
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ if (isp_csi2->update_ctx_ctrl1[ctxnum] || force_update) {
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_CTRL1(ctxnum));
if (selected_ctx_u->frame_count || force_update) {
reg &= ~(ISPCSI2_CTX_CTRL1_COUNT_MASK);
@@ -1119,13 +1145,13 @@
reg |= ISPCSI2_CTX_CTRL1_CTX_EN_DISABLE;
selected_ctx_u->enabled = false;
}
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_CTRL1(ctxnum));
- update_ctx_ctrl1[ctxnum] = false;
+ isp_csi2->update_ctx_ctrl1[ctxnum] = false;
}
- if (update_ctx_ctrl2[ctxnum] || force_update) {
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ if (isp_csi2->update_ctx_ctrl2[ctxnum] || force_update) {
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_CTRL2(ctxnum));
if (selected_ctx_u->virtual_id || force_update) {
reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK);
@@ -1147,7 +1173,7 @@
break;
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
- if (uses_videoport)
+ if (isp_csi2->uses_videoport)
new_format = 0x9E;
else
new_format = 0x1E;
@@ -1157,7 +1183,7 @@
new_format = 0xA1;
break;
case V4L2_PIX_FMT_SGRBG10:
- if (uses_videoport)
+ if (isp_csi2->uses_videoport)
new_format = 0x12F;
else
new_format = 0xAB;
@@ -1166,13 +1192,13 @@
reg |= (new_format << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT);
selected_ctx_u->format = false;
}
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_CTRL2(ctxnum));
- update_ctx_ctrl2[ctxnum] = false;
+ isp_csi2->update_ctx_ctrl2[ctxnum] = false;
}
- if (update_ctx_ctrl3[ctxnum] || force_update) {
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ if (isp_csi2->update_ctx_ctrl3[ctxnum] || force_update) {
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_CTRL3(ctxnum));
if (selected_ctx_u->alpha || force_update) {
reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK);
@@ -1180,32 +1206,32 @@
ISPCSI2_CTX_CTRL3_ALPHA_SHIFT);
selected_ctx_u->alpha = false;
}
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_CTRL3(ctxnum));
- update_ctx_ctrl3[ctxnum] = false;
+ isp_csi2->update_ctx_ctrl3[ctxnum] = false;
}
if (selected_ctx_u->data_offset) {
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_DAT_OFST(ctxnum));
reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK;
reg |= selected_ctx->data_offset <<
ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_DAT_OFST(ctxnum));
selected_ctx_u->data_offset = false;
}
if (selected_ctx_u->ping_addr) {
reg = selected_ctx->ping_addr;
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_DAT_PING_ADDR(ctxnum));
selected_ctx_u->ping_addr = false;
}
if (selected_ctx_u->pong_addr) {
reg = selected_ctx->pong_addr;
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_DAT_PONG_ADDR(ctxnum));
selected_ctx_u->pong_addr = false;
}
@@ -1218,7 +1244,7 @@
*
* Always returns 0.
**/
-int isp_csi2_ctx_get(u8 ctxnum)
+int isp_csi2_ctx_get(struct isp_csi2_device *isp_csi2, u8 ctxnum)
{
struct isp_csi2_ctx_cfg *selected_ctx;
struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -1226,10 +1252,11 @@
isp_csi2_ctx_validate(&ctxnum);
- selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
- selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+ selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+ selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTX_CTRL1(ctxnum));
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_CTX_CTRL1(ctxnum));
selected_ctx->frame_count = (reg & ISPCSI2_CTX_CTRL1_COUNT_MASK) >>
ISPCSI2_CTX_CTRL1_COUNT_SHIFT;
selected_ctx_u->frame_count = false;
@@ -1261,9 +1288,10 @@
else
selected_ctx->enabled = false;
selected_ctx_u->enabled = false;
- update_ctx_ctrl1[ctxnum] = false;
+ isp_csi2->update_ctx_ctrl1[ctxnum] = false;
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTX_CTRL2(ctxnum));
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_CTX_CTRL2(ctxnum));
selected_ctx->virtual_id = (reg & ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK) >>
ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT;
@@ -1287,26 +1315,30 @@
break;
}
selected_ctx_u->format = false;
- update_ctx_ctrl2[ctxnum] = false;
+ isp_csi2->update_ctx_ctrl2[ctxnum] = false;
- selected_ctx->alpha = (isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ selected_ctx->alpha = (isp_reg_readl(isp_csi2->dev,
+ OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_CTRL3(ctxnum)) &
ISPCSI2_CTX_CTRL3_ALPHA_MASK) >>
ISPCSI2_CTX_CTRL3_ALPHA_SHIFT;
selected_ctx_u->alpha = false;
- update_ctx_ctrl3[ctxnum] = false;
+ isp_csi2->update_ctx_ctrl3[ctxnum] = false;
- selected_ctx->data_offset = (isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ selected_ctx->data_offset = (isp_reg_readl(isp_csi2->dev,
+ OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_DAT_OFST(ctxnum)) &
ISPCSI2_CTX_DAT_OFST_OFST_MASK) >>
ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
selected_ctx_u->data_offset = false;
- selected_ctx->ping_addr = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ selected_ctx->ping_addr = isp_reg_readl(isp_csi2->dev,
+ OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_DAT_PING_ADDR(ctxnum));
selected_ctx_u->ping_addr = false;
- selected_ctx->pong_addr = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ selected_ctx->pong_addr = isp_reg_readl(isp_csi2->dev,
+ OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_DAT_PONG_ADDR(ctxnum));
selected_ctx_u->pong_addr = false;
return 0;
@@ -1322,12 +1354,12 @@
* set to true.
* Always returns 0.
**/
-int isp_csi2_ctx_update_all(bool force_update)
+int isp_csi2_ctx_update_all(struct isp_csi2_device *isp_csi2, bool force_update)
{
u8 ctxnum;
for (ctxnum = 0; ctxnum < 8; ctxnum++)
- isp_csi2_ctx_update(ctxnum, force_update);
+ isp_csi2_ctx_update(isp_csi2, ctxnum, force_update);
return 0;
}
@@ -1337,21 +1369,22 @@
*
* Always returns 0.
**/
-int isp_csi2_ctx_get_all(void)
+int isp_csi2_ctx_get_all(struct isp_csi2_device *isp_csi2)
{
u8 ctxnum;
for (ctxnum = 0; ctxnum < 8; ctxnum++)
- isp_csi2_ctx_get(ctxnum);
+ isp_csi2_ctx_get(isp_csi2, ctxnum);
return 0;
}
-int isp_csi2_phy_config(struct isp_csi2_phy_cfg *desiredphyconfig)
+int isp_csi2_phy_config(struct isp_csi2_device *isp_csi2,
+ struct isp_csi2_phy_cfg *desiredphyconfig)
{
- struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy;
+ struct isp_csi2_phy_cfg *currphy = &isp_csi2->current_cfg.phy;
struct isp_csi2_phy_cfg_update *currphy_u =
- ¤t_csi2_cfg_update.phy;
+ &isp_csi2->current_cfg_update.phy;
if ((desiredphyconfig->tclk_term > 0x7f) ||
(desiredphyconfig->tclk_miss > 0x3)) {
@@ -1363,27 +1396,27 @@
if (currphy->ths_term != desiredphyconfig->ths_term) {
currphy->ths_term = desiredphyconfig->ths_term;
currphy_u->ths_term = true;
- update_phy_cfg0 = true;
+ isp_csi2->update_phy_cfg0 = true;
}
if (currphy->ths_settle != desiredphyconfig->ths_settle) {
currphy->ths_settle = desiredphyconfig->ths_settle;
currphy_u->ths_settle = true;
- update_phy_cfg0 = true;
+ isp_csi2->update_phy_cfg0 = true;
}
if (currphy->tclk_term != desiredphyconfig->tclk_term) {
currphy->tclk_term = desiredphyconfig->tclk_term;
currphy_u->tclk_term = true;
- update_phy_cfg1 = true;
+ isp_csi2->update_phy_cfg1 = true;
}
if (currphy->tclk_miss != desiredphyconfig->tclk_miss) {
currphy->tclk_miss = desiredphyconfig->tclk_miss;
currphy_u->tclk_miss = true;
- update_phy_cfg1 = true;
+ isp_csi2->update_phy_cfg1 = true;
}
if (currphy->tclk_settle != desiredphyconfig->tclk_settle) {
currphy->tclk_settle = desiredphyconfig->tclk_settle;
currphy_u->tclk_settle = true;
- update_phy_cfg1 = true;
+ isp_csi2->update_phy_cfg1 = true;
}
return 0;
}
@@ -1402,12 +1435,13 @@
*
* Always returns 0.
*/
-int isp_csi2_calc_phy_cfg0(u32 mipiclk, u32 lbound_hs_settle,
- u32 ubound_hs_settle)
+int isp_csi2_calc_phy_cfg0(struct isp_csi2_device *isp_csi2,
+ u32 mipiclk, u32 lbound_hs_settle,
+ u32 ubound_hs_settle)
{
- struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy;
+ struct isp_csi2_phy_cfg *currphy = &isp_csi2->current_cfg.phy;
struct isp_csi2_phy_cfg_update *currphy_u =
- ¤t_csi2_cfg_update.phy;
+ &isp_csi2->current_cfg_update.phy;
u32 tmp, ddrclk = mipiclk >> 1;
/* Calculate THS_TERM */
@@ -1421,7 +1455,7 @@
currphy->ths_settle = (ubound_hs_settle + lbound_hs_settle) / 2;
currphy_u->ths_settle = true;
- isp_csi2_phy_update(true);
+ isp_csi2_phy_update(isp_csi2, true);
return 0;
}
EXPORT_SYMBOL(isp_csi2_calc_phy_cfg0);
@@ -1436,15 +1470,17 @@
* set to true.
* Always returns 0.
**/
-int isp_csi2_phy_update(bool force_update)
+int isp_csi2_phy_update(struct isp_csi2_device *isp_csi2, bool force_update)
{
- struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy;
+ struct isp_csi2_phy_cfg *currphy = &isp_csi2->current_cfg.phy;
struct isp_csi2_phy_cfg_update *currphy_u =
- ¤t_csi2_cfg_update.phy;
+ &isp_csi2->current_cfg_update.phy;
u32 reg;
- if (update_phy_cfg0 || force_update) {
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG0);
+ if (isp_csi2->update_phy_cfg0 || force_update) {
+ reg = isp_reg_readl(isp_csi2->dev,
+ OMAP3_ISP_IOMEM_CSI2PHY,
+ ISPCSI2PHY_CFG0);
if (currphy_u->ths_term || force_update) {
reg &= ~ISPCSI2PHY_CFG0_THS_TERM_MASK;
reg |= (currphy->ths_term <<
@@ -1457,12 +1493,14 @@
ISPCSI2PHY_CFG0_THS_SETTLE_SHIFT);
currphy_u->ths_settle = false;
}
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG0);
- update_phy_cfg0 = false;
+ isp_reg_writel(isp_csi2->dev, reg,
+ OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG0);
+ isp_csi2->update_phy_cfg0 = false;
}
- if (update_phy_cfg1 || force_update) {
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1);
+ if (isp_csi2->update_phy_cfg1 || force_update) {
+ reg = isp_reg_readl(isp_csi2->dev,
+ OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1);
if (currphy_u->tclk_term || force_update) {
reg &= ~ISPCSI2PHY_CFG1_TCLK_TERM_MASK;
reg |= (currphy->tclk_term <<
@@ -1481,8 +1519,9 @@
ISPCSI2PHY_CFG1_TCLK_SETTLE_SHIFT);
currphy_u->tclk_settle = false;
}
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1);
- update_phy_cfg1 = false;
+ isp_reg_writel(isp_csi2->dev, reg,
+ OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1);
+ isp_csi2->update_phy_cfg1 = false;
}
return 0;
}
@@ -1493,14 +1532,15 @@
* Gets settings from HW registers and fills in the internal driver memory
* Always returns 0.
**/
-int isp_csi2_phy_get(void)
+int isp_csi2_phy_get(struct isp_csi2_device *isp_csi2)
{
- struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy;
+ struct isp_csi2_phy_cfg *currphy = &isp_csi2->current_cfg.phy;
struct isp_csi2_phy_cfg_update *currphy_u =
- ¤t_csi2_cfg_update.phy;
+ &isp_csi2->current_cfg_update.phy;
u32 reg;
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG0);
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2PHY,
+ ISPCSI2PHY_CFG0);
currphy->ths_term = (reg & ISPCSI2PHY_CFG0_THS_TERM_MASK) >>
ISPCSI2PHY_CFG0_THS_TERM_SHIFT;
currphy_u->ths_term = false;
@@ -1508,9 +1548,10 @@
currphy->ths_settle = (reg & ISPCSI2PHY_CFG0_THS_SETTLE_MASK) >>
ISPCSI2PHY_CFG0_THS_SETTLE_SHIFT;
currphy_u->ths_settle = false;
- update_phy_cfg0 = false;
+ isp_csi2->update_phy_cfg0 = false;
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1);
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2PHY,
+ ISPCSI2PHY_CFG1);
currphy->tclk_term = (reg & ISPCSI2PHY_CFG1_TCLK_TERM_MASK) >>
ISPCSI2PHY_CFG1_TCLK_TERM_SHIFT;
@@ -1524,7 +1565,7 @@
ISPCSI2PHY_CFG1_TCLK_SETTLE_SHIFT;
currphy_u->tclk_settle = false;
- update_phy_cfg1 = false;
+ isp_csi2->update_phy_cfg1 = false;
return 0;
}
@@ -1534,7 +1575,8 @@
*
* Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
**/
-int isp_csi2_timings_config_forcerxmode(u8 io, bool force_rx_mode)
+int isp_csi2_timings_config_forcerxmode(struct isp_csi2_device *isp_csi2,
+ u8 io, bool force_rx_mode)
{
struct isp_csi2_timings_cfg *currtimings;
struct isp_csi2_timings_cfg_update *currtimings_u;
@@ -1544,12 +1586,12 @@
return -EINVAL;
}
- currtimings = ¤t_csi2_cfg.timings[io - 1];
- currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
+ currtimings = &isp_csi2->current_cfg.timings[io - 1];
+ currtimings_u = &isp_csi2->current_cfg_update.timings[io - 1];
if (currtimings->force_rx_mode != force_rx_mode) {
currtimings->force_rx_mode = force_rx_mode;
currtimings_u->force_rx_mode = true;
- update_timing = true;
+ isp_csi2->update_timing = true;
}
return 0;
}
@@ -1560,7 +1602,8 @@
*
* Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
**/
-int isp_csi2_timings_config_stopstate_16x(u8 io, bool stop_state_16x)
+int isp_csi2_timings_config_stopstate_16x(struct isp_csi2_device *isp_csi2,
+ u8 io, bool stop_state_16x)
{
struct isp_csi2_timings_cfg *currtimings;
struct isp_csi2_timings_cfg_update *currtimings_u;
@@ -1570,12 +1613,12 @@
return -EINVAL;
}
- currtimings = ¤t_csi2_cfg.timings[io - 1];
- currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
+ currtimings = &isp_csi2->current_cfg.timings[io - 1];
+ currtimings_u = &isp_csi2->current_cfg_update.timings[io - 1];
if (currtimings->stop_state_16x != stop_state_16x) {
currtimings->stop_state_16x = stop_state_16x;
currtimings_u->stop_state_16x = true;
- update_timing = true;
+ isp_csi2->update_timing = true;
}
return 0;
}
@@ -1586,7 +1629,8 @@
*
* Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
**/
-int isp_csi2_timings_config_stopstate_4x(u8 io, bool stop_state_4x)
+int isp_csi2_timings_config_stopstate_4x(struct isp_csi2_device *isp_csi2,
+ u8 io, bool stop_state_4x)
{
struct isp_csi2_timings_cfg *currtimings;
struct isp_csi2_timings_cfg_update *currtimings_u;
@@ -1596,12 +1640,12 @@
return -EINVAL;
}
- currtimings = ¤t_csi2_cfg.timings[io - 1];
- currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
+ currtimings = &isp_csi2->current_cfg.timings[io - 1];
+ currtimings_u = &isp_csi2->current_cfg_update.timings[io - 1];
if (currtimings->stop_state_4x != stop_state_4x) {
currtimings->stop_state_4x = stop_state_4x;
currtimings_u->stop_state_4x = true;
- update_timing = true;
+ isp_csi2->update_timing = true;
}
return 0;
}
@@ -1612,7 +1656,8 @@
*
* Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
**/
-int isp_csi2_timings_config_stopstate_cnt(u8 io, u16 stop_state_counter)
+int isp_csi2_timings_config_stopstate_cnt(struct isp_csi2_device *isp_csi2,
+ u8 io, u16 stop_state_counter)
{
struct isp_csi2_timings_cfg *currtimings;
struct isp_csi2_timings_cfg_update *currtimings_u;
@@ -1622,12 +1667,12 @@
return -EINVAL;
}
- currtimings = ¤t_csi2_cfg.timings[io - 1];
- currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
+ currtimings = &isp_csi2->current_cfg.timings[io - 1];
+ currtimings_u = &isp_csi2->current_cfg_update.timings[io - 1];
if (currtimings->stop_state_counter != stop_state_counter) {
currtimings->stop_state_counter = (stop_state_counter & 0x1FFF);
currtimings_u->stop_state_counter = true;
- update_timing = true;
+ isp_csi2->update_timing = true;
}
return 0;
}
@@ -1643,7 +1688,8 @@
* set to true.
* Returns 0 if successful, or -EINVAL if invalid IO number is passed.
**/
-int isp_csi2_timings_update(u8 io, bool force_update)
+int isp_csi2_timings_update(struct isp_csi2_device *isp_csi2,
+ u8 io, bool force_update)
{
struct isp_csi2_timings_cfg *currtimings;
struct isp_csi2_timings_cfg_update *currtimings_u;
@@ -1654,11 +1700,12 @@
return -EINVAL;
}
- currtimings = ¤t_csi2_cfg.timings[io - 1];
- currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
+ currtimings = &isp_csi2->current_cfg.timings[io - 1];
+ currtimings_u = &isp_csi2->current_cfg_update.timings[io - 1];
- if (update_timing || force_update) {
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_TIMING);
+ if (isp_csi2->update_timing || force_update) {
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_TIMING);
if (currtimings_u->force_rx_mode || force_update) {
reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO_MASK(io);
if (currtimings->force_rx_mode)
@@ -1696,8 +1743,9 @@
ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(io);
currtimings_u->stop_state_counter = false;
}
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_TIMING);
- update_timing = false;
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_TIMING);
+ isp_csi2->update_timing = false;
}
return 0;
}
@@ -1709,7 +1757,7 @@
* Gets settings from HW registers and fills in the internal driver memory
* Returns 0 if successful, or -EINVAL if invalid IO number is passed.
**/
-int isp_csi2_timings_get(u8 io)
+int isp_csi2_timings_get(struct isp_csi2_device *isp_csi2, u8 io)
{
struct isp_csi2_timings_cfg *currtimings;
struct isp_csi2_timings_cfg_update *currtimings_u;
@@ -1720,10 +1768,11 @@
return -EINVAL;
}
- currtimings = ¤t_csi2_cfg.timings[io - 1];
- currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
+ currtimings = &isp_csi2->current_cfg.timings[io - 1];
+ currtimings_u = &isp_csi2->current_cfg_update.timings[io - 1];
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_TIMING);
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_TIMING);
if ((reg & ISPCSI2_TIMING_FORCE_RX_MODE_IO_MASK(io)) ==
ISPCSI2_TIMING_FORCE_RX_MODE_IO_ENABLE(io))
currtimings->force_rx_mode = true;
@@ -1749,7 +1798,7 @@
ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(io)) >>
ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(io);
currtimings_u->stop_state_counter = false;
- update_timing = false;
+ isp_csi2->update_timing = false;
return 0;
}
@@ -1763,12 +1812,13 @@
* set to true.
* Always returns 0.
**/
-int isp_csi2_timings_update_all(bool force_update)
+int isp_csi2_timings_update_all(struct isp_csi2_device *isp_csi2,
+ bool force_update)
{
int i;
for (i = 1; i < 3; i++)
- isp_csi2_timings_update(i, force_update);
+ isp_csi2_timings_update(isp_csi2, i, force_update);
return 0;
}
@@ -1777,62 +1827,83 @@
*
* Always returns 0.
**/
-int isp_csi2_timings_get_all(void)
+int isp_csi2_timings_get_all(struct isp_csi2_device *isp_csi2)
{
int i;
for (i = 1; i < 3; i++)
- isp_csi2_timings_get(i);
+ isp_csi2_timings_get(isp_csi2, i);
return 0;
}
/**
* isp_csi2_isr - CSI2 interrupt handling.
+ *
+ * Return -EIO on Transmission error
**/
-void isp_csi2_isr(void)
+int isp_csi2_isr(struct isp_csi2_device *isp_csi2)
{
+ int retval = 0;
u32 csi2_irqstatus, cpxio1_irqstatus, ctxirqstatus;
- csi2_irqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ csi2_irqstatus = isp_reg_readl(isp_csi2->dev,
+ OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_IRQSTATUS);
- isp_reg_writel(csi2_irqstatus, OMAP3_ISP_IOMEM_CSI2A,
- ISPCSI2_IRQSTATUS);
+ isp_reg_writel(isp_csi2->dev, csi2_irqstatus,
+ OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_IRQSTATUS);
+ /* Failure Cases */
if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) {
- cpxio1_irqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ cpxio1_irqstatus = isp_reg_readl(isp_csi2->dev,
+ OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_COMPLEXIO1_IRQSTATUS);
- isp_reg_writel(cpxio1_irqstatus, OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_writel(isp_csi2->dev, cpxio1_irqstatus,
+ OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_COMPLEXIO1_IRQSTATUS);
- printk(KERN_ERR "CSI2: ComplexIO Error IRQ %x\n",
- cpxio1_irqstatus);
+ dev_dbg(isp_csi2->dev, "CSI2: ComplexIO Error IRQ %x\n",
+ cpxio1_irqstatus);
+ retval = -EIO;
}
+ if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
+ ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
+ ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
+ ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
+ ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) {
+ dev_dbg(isp_csi2->dev, "CSI2 Err:"
+ " OCP:%d,"
+ " Short_pack:%d,"
+ " ECC:%d,"
+ " CPXIO2:%d,"
+ " FIFO_OVF:%d,"
+ "\n",
+ (csi2_irqstatus &
+ ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0,
+ (csi2_irqstatus &
+ ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0,
+ (csi2_irqstatus &
+ ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0,
+ (csi2_irqstatus &
+ ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0,
+ (csi2_irqstatus &
+ ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0);
+ retval = -EIO;
+ }
+
+ /* Successful cases */
if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) {
- ctxirqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ ctxirqstatus = isp_reg_readl(isp_csi2->dev,
+ OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_IRQSTATUS(0));
- isp_reg_writel(ctxirqstatus, OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_writel(isp_csi2->dev, ctxirqstatus,
+ OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_IRQSTATUS(0));
}
- if (csi2_irqstatus & ISPCSI2_IRQSTATUS_OCP_ERR_IRQ)
- printk(KERN_ERR "CSI2: OCP Transmission Error\n");
-
- if (csi2_irqstatus & ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ)
- printk(KERN_ERR "CSI2: Short packet receive error\n");
-
if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
- printk(KERN_DEBUG "CSI2: ECC correction done\n");
+ dev_dbg(isp_csi2->dev, "CSI2: ECC correction done\n");
- if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ)
- printk(KERN_ERR "CSI2: ECC correction failed\n");
-
- if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ)
- printk(KERN_ERR "CSI2: ComplexIO #2 failed\n");
-
- if (csi2_irqstatus & ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)
- printk(KERN_ERR "CSI2: FIFO overflow error\n");
-
- return;
+ return retval;
}
EXPORT_SYMBOL(isp_csi2_isr);
@@ -1840,7 +1911,7 @@
* isp_csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs.
* @enable: Enable/disable CSI2 ComplexIO #1 interrupts
**/
-void isp_csi2_irq_complexio1_set(int enable)
+void isp_csi2_irq_complexio1_set(struct isp_csi2_device *isp_csi2, int enable)
{
u32 reg;
reg = ISPCSI2_COMPLEXIO1_IRQENABLE_STATEALLULPMEXIT |
@@ -1870,14 +1941,15 @@
ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC1 |
ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS1 |
ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS1;
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_COMPLEXIO1_IRQSTATUS);
if (enable) {
- reg |= isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ reg |= isp_reg_readl(isp_csi2->dev,
+ OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_COMPLEXIO1_IRQENABLE);
} else
reg = 0;
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_COMPLEXIO1_IRQENABLE);
}
EXPORT_SYMBOL(isp_csi2_irq_complexio1_set);
@@ -1886,20 +1958,21 @@
* isp_csi2_irq_ctx_set - Enables CSI2 Context IRQs.
* @enable: Enable/disable CSI2 Context interrupts
**/
-void isp_csi2_irq_ctx_set(int enable)
+void isp_csi2_irq_ctx_set(struct isp_csi2_device *isp_csi2, int enable)
{
u32 reg;
int i;
reg = ISPCSI2_CTX_IRQSTATUS_FS_IRQ | ISPCSI2_CTX_IRQSTATUS_FE_IRQ;
for (i = 0; i < 8; i++) {
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_IRQSTATUS(i));
if (enable) {
- isp_reg_or(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_or(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_IRQENABLE(i), reg);
} else {
- isp_reg_writel(0, OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_writel(isp_csi2->dev, 0,
+ OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_IRQENABLE(i));
}
}
@@ -1911,7 +1984,7 @@
* isp_csi2_irq_status_set - Enables CSI2 Status IRQs.
* @enable: Enable/disable CSI2 Status interrupts
**/
-void isp_csi2_irq_status_set(int enable)
+void isp_csi2_irq_status_set(struct isp_csi2_device *isp_csi2, int enable)
{
u32 reg;
reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
@@ -1922,46 +1995,34 @@
ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ |
ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ |
ISPCSI2_IRQSTATUS_CONTEXT(0);
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_IRQSTATUS);
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_IRQSTATUS);
if (enable)
- reg |= isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_IRQENABLE);
+ reg |= isp_reg_readl(isp_csi2->dev,
+ OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_IRQENABLE);
else
reg = 0;
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_IRQENABLE);
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_IRQENABLE);
}
EXPORT_SYMBOL(isp_csi2_irq_status_set);
/**
- * isp_csi2_irq_status_set - Enables main CSI2 IRQ.
- * @enable: Enable/disable main CSI2 interrupt
- **/
-void isp_csi2_irq_set(int enable)
-{
- isp_reg_writel(IRQ0STATUS_CSIA_IRQ, OMAP3_ISP_IOMEM_MAIN,
- ISP_IRQ0STATUS);
- isp_reg_and_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
- ~IRQ0ENABLE_CSIA_IRQ,
- (enable ? IRQ0ENABLE_CSIA_IRQ : 0));
-}
-EXPORT_SYMBOL(isp_csi2_irq_set);
-
-/**
* isp_csi2_irq_all_set - Enable/disable CSI2 interrupts.
* @enable: 0-Disable, 1-Enable.
**/
-void isp_csi2_irq_all_set(int enable)
+void isp_csi2_irq_all_set(struct isp_csi2_device *isp_csi2, int enable)
{
if (enable) {
- isp_csi2_irq_complexio1_set(enable);
- isp_csi2_irq_ctx_set(enable);
- isp_csi2_irq_status_set(enable);
- isp_csi2_irq_set(enable);
+ isp_csi2_irq_complexio1_set(isp_csi2, enable);
+ isp_csi2_irq_ctx_set(isp_csi2, enable);
+ isp_csi2_irq_status_set(isp_csi2, enable);
} else {
- isp_csi2_irq_set(enable);
- isp_csi2_irq_status_set(enable);
- isp_csi2_irq_ctx_set(enable);
- isp_csi2_irq_complexio1_set(enable);
+ isp_csi2_irq_status_set(isp_csi2, enable);
+ isp_csi2_irq_ctx_set(isp_csi2, enable);
+ isp_csi2_irq_complexio1_set(isp_csi2, enable);
}
return;
}
@@ -1972,18 +2033,31 @@
*
* Returns 0 if successful, or -EBUSY if power command didn't respond.
**/
-int isp_csi2_reset(void)
+int isp_csi2_reset(struct isp_csi2_device *isp_csi2)
{
+ struct isp_device *isp = dev_get_drvdata(isp_csi2->dev);
u32 reg;
u8 soft_reset_retries = 0;
int i;
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG);
+ memset(&isp_csi2->current_cfg, 0, sizeof(isp_csi2->current_cfg));
+ memset(&isp_csi2->current_cfg_update, 0,
+ sizeof(isp_csi2->current_cfg_update));
+
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_SYSCONFIG);
reg |= ISPCSI2_SYSCONFIG_SOFT_RESET_RESET;
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG);
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_SYSCONFIG);
+
+ if (isp->revision > ISP_REVISION_2_0)
+ isp_reg_or(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_COMPLEXIO_CFG1,
+ ISPCSI2_COMPLEXIO_CFG1_RESET_CTRL_DEASSERTED);
do {
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSSTATUS) &
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_SYSSTATUS) &
ISPCSI2_SYSSTATUS_RESET_DONE_MASK;
if (reg == ISPCSI2_SYSSTATUS_RESET_DONE_DONE)
break;
@@ -1997,37 +2071,56 @@
return -EBUSY;
}
- reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG);
+ i = 100;
+ do {
+ reg = isp_reg_readl(isp_csi2->dev,
+ OMAP3_ISP_IOMEM_CSI2PHY,
+ ISPCSI2PHY_CFG1) &
+ ISPCSI2PHY_CFG1_RESETDONECTRLCLK_MASK;
+ if (reg == ISPCSI2PHY_CFG1_RESETDONECTRLCLK_MASK)
+ break;
+ udelay(100);
+ } while (--i > 0);
+
+ if (i == 0) {
+ printk(KERN_ERR
+ "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n");
+ return -EBUSY;
+ }
+
+ reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_SYSCONFIG);
reg &= ~ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK;
reg |= ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART;
reg &= ~ISPCSI2_SYSCONFIG_AUTO_IDLE_MASK;
reg |= ISPCSI2_SYSCONFIG_AUTO_IDLE_AUTO;
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG);
+ isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_SYSCONFIG);
- uses_videoport = false;
- update_complexio_cfg1 = false;
- update_phy_cfg0 = false;
- update_phy_cfg1 = false;
+ isp_csi2->uses_videoport = false;
+ isp_csi2->update_complexio_cfg1 = false;
+ isp_csi2->update_phy_cfg0 = false;
+ isp_csi2->update_phy_cfg1 = false;
for (i = 0; i < 8; i++) {
- update_ctx_ctrl1[i] = false;
- update_ctx_ctrl2[i] = false;
- update_ctx_ctrl3[i] = false;
+ isp_csi2->update_ctx_ctrl1[i] = false;
+ isp_csi2->update_ctx_ctrl2[i] = false;
+ isp_csi2->update_ctx_ctrl3[i] = false;
}
- update_timing = false;
- update_ctrl = false;
+ isp_csi2->update_timing = false;
+ isp_csi2->update_ctrl = false;
- isp_csi2_complexio_lanes_get();
- isp_csi2_ctrl_get();
- isp_csi2_ctx_get_all();
- isp_csi2_phy_get();
- isp_csi2_timings_get_all();
+ isp_csi2_complexio_lanes_get(isp_csi2);
+ isp_csi2_ctrl_get(isp_csi2);
+ isp_csi2_ctx_get_all(isp_csi2);
+ isp_csi2_phy_get(isp_csi2);
+ isp_csi2_timings_get_all(isp_csi2);
- isp_csi2_complexio_power_autoswitch(true);
- isp_csi2_complexio_power(ISP_CSI2_POWER_ON);
+ isp_csi2_complexio_power(isp_csi2, ISP_CSI2_POWER_ON);
+ isp_csi2_complexio_power_autoswitch(isp_csi2, true);
- isp_csi2_timings_config_forcerxmode(1, true);
- isp_csi2_timings_config_stopstate_cnt(1, 0x1FF);
- isp_csi2_timings_update_all(true);
+ isp_csi2_timings_config_forcerxmode(isp_csi2, 1, true);
+ isp_csi2_timings_config_stopstate_cnt(isp_csi2, 1, 0x1FF);
+ isp_csi2_timings_update_all(isp_csi2, true);
return 0;
}
@@ -2036,26 +2129,26 @@
* isp_csi2_enable - Enables the CSI2 module.
* @enable: Enables/disables the CSI2 module.
**/
-void isp_csi2_enable(int enable)
+void isp_csi2_enable(struct isp_csi2_device *isp_csi2, int enable)
{
if (enable) {
- isp_csi2_ctx_config_enabled(0, true);
- isp_csi2_ctx_config_eof_enabled(0, true);
- isp_csi2_ctx_config_checksum_enabled(0, true);
- isp_csi2_ctx_update(0, false);
+ isp_csi2_ctx_config_enabled(isp_csi2, 0, true);
+ isp_csi2_ctx_config_eof_enabled(isp_csi2, 0, true);
+ isp_csi2_ctx_config_checksum_enabled(isp_csi2, 0, true);
+ isp_csi2_ctx_update(isp_csi2, 0, false);
- isp_csi2_ctrl_config_ecc_enable(true);
- isp_csi2_ctrl_config_if_enable(true);
- isp_csi2_ctrl_update(false);
+ isp_csi2_ctrl_config_ecc_enable(isp_csi2, true);
+ isp_csi2_ctrl_config_if_enable(isp_csi2, true);
+ isp_csi2_ctrl_update(isp_csi2, false);
} else {
- isp_csi2_ctx_config_enabled(0, false);
- isp_csi2_ctx_config_eof_enabled(0, false);
- isp_csi2_ctx_config_checksum_enabled(0, false);
- isp_csi2_ctx_update(0, false);
+ isp_csi2_ctx_config_enabled(isp_csi2, 0, false);
+ isp_csi2_ctx_config_eof_enabled(isp_csi2, 0, false);
+ isp_csi2_ctx_config_checksum_enabled(isp_csi2, 0, false);
+ isp_csi2_ctx_update(isp_csi2, 0, false);
- isp_csi2_ctrl_config_ecc_enable(false);
- isp_csi2_ctrl_config_if_enable(false);
- isp_csi2_ctrl_update(false);
+ isp_csi2_ctrl_config_ecc_enable(isp_csi2, false);
+ isp_csi2_ctrl_config_if_enable(isp_csi2, false);
+ isp_csi2_ctrl_update(isp_csi2, false);
}
}
EXPORT_SYMBOL(isp_csi2_enable);
@@ -2063,111 +2156,120 @@
/**
* isp_csi2_regdump - Prints CSI2 debug information.
**/
-void isp_csi2_regdump(void)
+void isp_csi2_regdump(struct isp_csi2_device *isp_csi2)
{
printk(KERN_DEBUG "-------------Register dump-------------\n");
printk(KERN_DEBUG "ISP_CTRL: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_CTRL));
printk(KERN_DEBUG "ISP_TCTRL_CTRL: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL));
-
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_TCTRL_CTRL));
printk(KERN_DEBUG "ISPCCDC_SDR_ADDR: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR));
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SDR_ADDR));
printk(KERN_DEBUG "ISPCCDC_SYN_MODE: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE));
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_SYN_MODE));
printk(KERN_DEBUG "ISPCCDC_CFG: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG));
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_CFG));
printk(KERN_DEBUG "ISPCCDC_FMTCFG: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG));
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_FMTCFG));
printk(KERN_DEBUG "ISPCCDC_HSIZE_OFF: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF));
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_HSIZE_OFF));
printk(KERN_DEBUG "ISPCCDC_HORZ_INFO: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO));
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
+ ISPCCDC_HORZ_INFO));
printk(KERN_DEBUG "ISPCCDC_VERT_START: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
ISPCCDC_VERT_START));
printk(KERN_DEBUG "ISPCCDC_VERT_LINES: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
ISPCCDC_VERT_LINES));
printk(KERN_DEBUG "ISPCSI2_COMPLEXIO_CFG1: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_COMPLEXIO_CFG1));
printk(KERN_DEBUG "ISPCSI2_SYSSTATUS: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_SYSSTATUS));
printk(KERN_DEBUG "ISPCSI2_SYSCONFIG: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_SYSCONFIG));
printk(KERN_DEBUG "ISPCSI2_IRQENABLE: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_IRQENABLE));
printk(KERN_DEBUG "ISPCSI2_IRQSTATUS: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_IRQSTATUS));
printk(KERN_DEBUG "ISPCSI2_CTX_IRQENABLE(0): %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_IRQENABLE(0)));
printk(KERN_DEBUG "ISPCSI2_CTX_IRQSTATUS(0): %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_IRQSTATUS(0)));
printk(KERN_DEBUG "ISPCSI2_TIMING: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_TIMING));
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_TIMING));
printk(KERN_DEBUG "ISPCSI2PHY_CFG0: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2PHY,
ISPCSI2PHY_CFG0));
printk(KERN_DEBUG "ISPCSI2PHY_CFG1: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2PHY,
ISPCSI2PHY_CFG1));
printk(KERN_DEBUG "ISPCSI2_CTX_CTRL1(0): %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_CTRL1(0)));
printk(KERN_DEBUG "ISPCSI2_CTX_CTRL2(0): %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_CTRL2(0)));
printk(KERN_DEBUG "ISPCSI2_CTX_CTRL3(0): %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_CTRL3(0)));
printk(KERN_DEBUG "ISPCSI2_CTX_DAT_OFST(0): %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_DAT_OFST(0)));
printk(KERN_DEBUG "ISPCSI2_CTX_DAT_PING_ADDR(0): %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_DAT_PING_ADDR(0)));
printk(KERN_DEBUG "ISPCSI2_CTX_DAT_PONG_ADDR(0): %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
ISPCSI2_CTX_DAT_PONG_ADDR(0)));
printk(KERN_DEBUG "ISPCSI2_CTRL: %x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTRL));
+ isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+ ISPCSI2_CTRL));
printk(KERN_DEBUG "---------------------------------------\n");
}
/**
* ispcsi2_save_context - Saves the values of the CSI1 module registers
**/
-void ispcsi2_save_context(void)
+void ispcsi2_save_context(struct device *dev)
{
printk(KERN_DEBUG "Saving csi2 context\n");
- isp_save_context(ispcsi2_reg_list);
+ isp_save_context(dev, ispcsi2_reg_list);
}
EXPORT_SYMBOL(ispcsi2_save_context);
/**
* ispcsi2_restore_context - Restores the values of the CSI2 module registers
**/
-void ispcsi2_restore_context(void)
+void ispcsi2_restore_context(struct device *dev)
{
printk(KERN_DEBUG "Restoring csi2 context\n");
- isp_restore_context(ispcsi2_reg_list);
+ isp_restore_context(dev, ispcsi2_reg_list);
}
EXPORT_SYMBOL(ispcsi2_restore_context);
/**
* isp_csi2_cleanup - Routine for module driver cleanup
**/
-void isp_csi2_cleanup(void)
+void isp_csi2_cleanup(struct device *dev)
{
return;
}
@@ -2175,23 +2277,26 @@
/**
* isp_csi2_init - Routine for module driver init
**/
-int __init isp_csi2_init(void)
+int __init isp_csi2_init(struct device *dev)
{
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_csi2_device *isp_csi2 = &isp->isp_csi2;
int i;
- update_complexio_cfg1 = false;
- update_phy_cfg0 = false;
- update_phy_cfg1 = false;
+ isp_csi2->dev = dev;
+ isp_csi2->update_complexio_cfg1 = false;
+ isp_csi2->update_phy_cfg0 = false;
+ isp_csi2->update_phy_cfg1 = false;
for (i = 0; i < 8; i++) {
- update_ctx_ctrl1[i] = false;
- update_ctx_ctrl2[i] = false;
- update_ctx_ctrl3[i] = false;
+ isp_csi2->update_ctx_ctrl1[i] = false;
+ isp_csi2->update_ctx_ctrl2[i] = false;
+ isp_csi2->update_ctx_ctrl3[i] = false;
}
- update_timing = false;
- update_ctrl = false;
+ isp_csi2->update_timing = false;
+ isp_csi2->update_ctrl = false;
- memset(¤t_csi2_cfg, 0, sizeof(current_csi2_cfg));
- memset(¤t_csi2_cfg_update, 0, sizeof(current_csi2_cfg_update));
+ memset(&isp_csi2->current_cfg, 0, sizeof(isp_csi2->current_cfg));
+ memset(&isp_csi2->current_cfg_update, 0, sizeof(isp_csi2->current_cfg_update));
return 0;
}
diff --git a/drivers/media/video/isp/ispcsi2.h b/drivers/media/video/isp/ispcsi2.h
index 3fc5e55..a6ad66a 100644
--- a/drivers/media/video/isp/ispcsi2.h
+++ b/drivers/media/video/isp/ispcsi2.h
@@ -177,64 +177,112 @@
struct isp_csi2_ctrl_cfg_update ctrl;
};
-int isp_csi2_complexio_lanes_config(struct isp_csi2_lanes_cfg *reqcfg);
-int isp_csi2_complexio_lanes_update(bool force_update);
-int isp_csi2_complexio_lanes_count(int cnt);
-int isp_csi2_complexio_lanes_get(void);
-int isp_csi2_complexio_power_autoswitch(bool enable);
-int isp_csi2_complexio_power(enum isp_csi2_power_cmds power_cmd);
-int isp_csi2_ctrl_config_frame_mode(enum isp_csi2_frame_mode frame_mode);
-int isp_csi2_ctrl_config_vp_clk_enable(bool vp_clk_enable);
-int isp_csi2_ctrl_config_vp_only_enable(bool vp_only_enable);
-int isp_csi2_ctrl_config_debug_enable(bool debug_enable);
-int isp_csi2_ctrl_config_burst_size(u8 burst_size);
-int isp_csi2_ctrl_config_ecc_enable(bool ecc_enable);
-int isp_csi2_ctrl_config_secure_mode(bool secure_mode);
-int isp_csi2_ctrl_config_if_enable(bool if_enable);
-int isp_csi2_ctrl_config_vp_out_ctrl(u8 vp_out_ctrl);
-int isp_csi2_ctrl_update(bool force_update);
-int isp_csi2_ctrl_get(void);
-int isp_csi2_ctx_config_virtual_id(u8 ctxnum, u8 virtual_id);
-int isp_csi2_ctx_config_frame_count(u8 ctxnum, u8 frame_count);
-int isp_csi2_ctx_config_format(u8 ctxnum, u32 pixformat);
-int isp_csi2_ctx_config_alpha(u8 ctxnum, u16 alpha);
-int isp_csi2_ctx_config_data_offset(u8 ctxnum, u16 data_offset);
-int isp_csi2_ctx_config_ping_addr(u8 ctxnum, u32 ping_addr);
-int isp_csi2_ctx_config_pong_addr(u8 ctxnum, u32 pong_addr);
-int isp_csi2_ctx_config_eof_enabled(u8 ctxnum, bool eof_enabled);
-int isp_csi2_ctx_config_eol_enabled(u8 ctxnum, bool eol_enabled);
-int isp_csi2_ctx_config_checksum_enabled(u8 ctxnum, bool checksum_enabled);
-int isp_csi2_ctx_config_enabled(u8 ctxnum, bool enabled);
-int isp_csi2_ctx_update(u8 ctxnum, bool force_update);
-int isp_csi2_ctx_get(u8 ctxnum);
-int isp_csi2_ctx_update_all(bool force_update);
-int isp_csi2_ctx_get_all(void);
-int isp_csi2_phy_config(struct isp_csi2_phy_cfg *desiredphyconfig);
-int isp_csi2_calc_phy_cfg0(u32 mipiclk, u32 lbound_hs_settle,
+struct isp_csi2_device {
+ struct device *dev;
+ struct isp_csi2_cfg current_cfg;
+ struct isp_csi2_cfg_update current_cfg_update;
+ bool update_complexio_cfg1;
+ bool update_phy_cfg0;
+ bool update_phy_cfg1;
+ bool update_ctx_ctrl1[8];
+ bool update_ctx_ctrl2[8];
+ bool update_ctx_ctrl3[8];
+ bool update_timing;
+ bool update_ctrl;
+ bool uses_videoport;
+};
+
+int isp_csi2_complexio_lanes_config(struct isp_csi2_device *isp_csi2,
+ struct isp_csi2_lanes_cfg *reqcfg);
+int isp_csi2_complexio_lanes_update(struct isp_csi2_device *isp_csi2,
+ bool force_update);
+int isp_csi2_complexio_lanes_count(struct isp_csi2_device *isp_csi2, int cnt);
+int isp_csi2_complexio_lanes_get(struct isp_csi2_device *isp_csi2);
+int isp_csi2_complexio_power_autoswitch(struct isp_csi2_device *isp_csi2,
+ bool enable);
+int isp_csi2_complexio_power(struct isp_csi2_device *isp_csi2,
+ enum isp_csi2_power_cmds power_cmd);
+int isp_csi2_ctrl_config_frame_mode(struct isp_csi2_device *isp_csi2,
+ enum isp_csi2_frame_mode frame_mode);
+int isp_csi2_ctrl_config_vp_clk_enable(struct isp_csi2_device *isp_csi2,
+ bool vp_clk_enable);
+int isp_csi2_ctrl_config_vp_only_enable(struct isp_csi2_device *isp_csi2,
+ bool vp_only_enable);
+int isp_csi2_ctrl_config_debug_enable(struct isp_csi2_device *isp_csi2,
+ bool debug_enable);
+int isp_csi2_ctrl_config_burst_size(struct isp_csi2_device *isp_csi2,
+ u8 burst_size);
+int isp_csi2_ctrl_config_ecc_enable(struct isp_csi2_device *isp_csi2,
+ bool ecc_enable);
+int isp_csi2_ctrl_config_secure_mode(struct isp_csi2_device *isp_csi2,
+ bool secure_mode);
+int isp_csi2_ctrl_config_if_enable(struct isp_csi2_device *isp_csi2,
+ bool if_enable);
+int isp_csi2_ctrl_config_vp_out_ctrl(struct isp_csi2_device *isp_csi2,
+ u8 vp_out_ctrl);
+int isp_csi2_ctrl_update(struct isp_csi2_device *isp_csi2, bool force_update);
+int isp_csi2_ctrl_get(struct isp_csi2_device *isp_csi2);
+int isp_csi2_ctx_config_virtual_id(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, u8 virtual_id);
+int isp_csi2_ctx_config_frame_count(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, u8 frame_count);
+int isp_csi2_ctx_config_format(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, u32 pixformat);
+int isp_csi2_ctx_config_alpha(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, u16 alpha);
+int isp_csi2_ctx_config_data_offset(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, u16 data_offset);
+int isp_csi2_ctx_config_ping_addr(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, u32 ping_addr);
+int isp_csi2_ctx_config_pong_addr(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, u32 pong_addr);
+int isp_csi2_ctx_config_eof_enabled(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, bool eof_enabled);
+int isp_csi2_ctx_config_eol_enabled(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, bool eol_enabled);
+int isp_csi2_ctx_config_checksum_enabled(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, bool checksum_enabled);
+int isp_csi2_ctx_config_enabled(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, bool enabled);
+int isp_csi2_ctx_update(struct isp_csi2_device *isp_csi2,
+ u8 ctxnum, bool force_update);
+int isp_csi2_ctx_get(struct isp_csi2_device *isp_csi2, u8 ctxnum);
+int isp_csi2_ctx_update_all(struct isp_csi2_device *isp_csi2,
+ bool force_update);
+int isp_csi2_ctx_get_all(struct isp_csi2_device *isp_csi2);
+int isp_csi2_phy_config(struct isp_csi2_device *isp_csi2,
+ struct isp_csi2_phy_cfg *desiredphyconfig);
+int isp_csi2_calc_phy_cfg0(struct isp_csi2_device *isp_csi2,
+ u32 mipiclk, u32 lbound_hs_settle,
u32 ubound_hs_settle);
-int isp_csi2_phy_update(bool force_update);
-int isp_csi2_phy_get(void);
-int isp_csi2_timings_config_forcerxmode(u8 io, bool force_rx_mode);
-int isp_csi2_timings_config_stopstate_16x(u8 io, bool stop_state_16x);
-int isp_csi2_timings_config_stopstate_4x(u8 io, bool stop_state_4x);
-int isp_csi2_timings_config_stopstate_cnt(u8 io, u16 stop_state_counter);
-int isp_csi2_timings_update(u8 io, bool force_update);
-int isp_csi2_timings_get(u8 io);
-int isp_csi2_timings_update_all(bool force_update);
-int isp_csi2_timings_get_all(void);
-void isp_csi2_irq_complexio1_set(int enable);
-void isp_csi2_irq_ctx_set(int enable);
-void isp_csi2_irq_status_set(int enable);
-void isp_csi2_irq_set(int enable);
-void isp_csi2_irq_all_set(int enable);
+int isp_csi2_phy_update(struct isp_csi2_device *isp_csi2,
+ bool force_update);
+int isp_csi2_phy_get(struct isp_csi2_device *isp_csi2);
+int isp_csi2_timings_config_forcerxmode(struct isp_csi2_device *isp_csi2,
+ u8 io, bool force_rx_mode);
+int isp_csi2_timings_config_stopstate_16x(struct isp_csi2_device *isp_csi2,
+ u8 io, bool stop_state_16x);
+int isp_csi2_timings_config_stopstate_4x(struct isp_csi2_device *isp_csi2,
+ u8 io, bool stop_state_4x);
+int isp_csi2_timings_config_stopstate_cnt(struct isp_csi2_device *isp_csi2,
+ u8 io, u16 stop_state_counter);
+int isp_csi2_timings_update(struct isp_csi2_device *isp_csi2,
+ u8 io, bool force_update);
+int isp_csi2_timings_get(struct isp_csi2_device *isp_csi2, u8 io);
+int isp_csi2_timings_update_all(struct isp_csi2_device *isp_csi2, bool force_update);
+int isp_csi2_timings_get_all(struct isp_csi2_device *isp_csi2);
+void isp_csi2_irq_complexio1_set(struct isp_csi2_device *isp_csi2, int enable);
+void isp_csi2_irq_ctx_set(struct isp_csi2_device *isp_csi2, int enable);
+void isp_csi2_irq_status_set(struct isp_csi2_device *isp_csi2, int enable);
+void isp_csi2_irq_all_set(struct isp_csi2_device *isp_csi2, int enable);
-void isp_csi2_isr(void);
-int isp_csi2_reset(void);
-void isp_csi2_enable(int enable);
-void isp_csi2_regdump(void);
+int isp_csi2_isr(struct isp_csi2_device *isp_csi2);
+int isp_csi2_reset(struct isp_csi2_device *isp_csi2);
+void isp_csi2_enable(struct isp_csi2_device *isp_csi2, int enable);
+void isp_csi2_regdump(struct isp_csi2_device *isp_csi2);
-void ispcsi2_save_context(void);
-void ispcsi2_restore_context(void);
+void ispcsi2_save_context(struct device *dev);
+void ispcsi2_restore_context(struct device *dev);
#endif /* OMAP_ISP_CSI2_H */
diff --git a/drivers/media/video/isp/isph3a.c b/drivers/media/video/isp/isph3a.c
index dc38a91..fc4632d 100644
--- a/drivers/media/video/isp/isph3a.c
+++ b/drivers/media/video/isp/isph3a.c
@@ -18,109 +18,10 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#include <asm/cacheflush.h>
-
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
#include "isp.h"
-#include "ispreg.h"
-#include "isph3a.h"
-#include "ispmmu.h"
-#include "isppreview.h"
-
-/**
- * struct isph3a_aewb_buffer - AE, AWB frame stats buffer.
- * @virt_addr: Virtual address to mmap the buffer.
- * @phy_addr: Physical address of the buffer.
- * @addr_align: Virtual Address 32 bytes aligned.
- * @ispmmu_addr: Address of the buffer mapped by the ISPMMU.
- * @mmap_addr: Mapped memory area of buffer. For userspace access.
- * @locked: 1 - Buffer locked from write. 0 - Buffer can be overwritten.
- * @frame_num: Frame number from which the statistics are taken.
- * @next: Pointer to link next buffer.
- */
-struct isph3a_aewb_buffer {
- unsigned long virt_addr;
- unsigned long phy_addr;
- unsigned long addr_align;
- unsigned long ispmmu_addr;
- unsigned long mmap_addr; /* For userspace */
- struct timeval ts;
- u32 config_counter;
-
- u8 locked;
- u16 frame_num;
- struct isph3a_aewb_buffer *next;
-};
-
-/**
- * struct isph3a_aewb_status - AE, AWB status.
- * @initialized: 1 - Buffers initialized.
- * @update: 1 - Update registers.
- * @stats_req: 1 - Future stats requested.
- * @stats_done: 1 - Stats ready for user.
- * @frame_req: Number of frame requested for statistics.
- * @h3a_buff: Array of statistics buffers to access.
- * @stats_buf_size: Statistics buffer size.
- * @min_buf_size: Minimum statisitics buffer size.
- * @win_count: Window Count.
- * @frame_count: Frame Count.
- * @stats_wait: Wait primitive for locking/unlocking the stats request.
- * @buffer_lock: Spinlock for statistics buffers access.
- */
-static struct isph3a_aewb_status {
- u8 initialized;
- u8 update;
- u8 stats_req;
- u8 stats_done;
- u16 frame_req;
- int pm_state;
-
- struct isph3a_aewb_buffer h3a_buff[H3A_MAX_BUFF];
- unsigned int stats_buf_size;
- unsigned int min_buf_size;
- unsigned int curr_cfg_buf_size;
-
- atomic_t config_counter;
-
- u16 win_count;
- u32 frame_count;
- wait_queue_head_t stats_wait;
- spinlock_t buffer_lock; /* For stats buffers read/write sync */
-} aewbstat;
-
-/**
- * struct isph3a_aewb_regs - Current value of AE, AWB configuration registers.
- * reg_pcr: Peripheral control register.
- * reg_win1: Control register.
- * reg_start: Start position register.
- * reg_blk: Black line register.
- * reg_subwin: Configuration register.
- */
-static struct isph3a_aewb_regs {
- u32 reg_pcr;
- u32 reg_win1;
- u32 reg_start;
- u32 reg_blk;
- u32 reg_subwin;
-} aewb_regs;
-
-static struct isph3a_aewb_config aewb_config_local = {
- .saturation_limit = 0x3FF,
- .win_height = 0,
- .win_width = 0,
- .ver_win_count = 0,
- .hor_win_count = 0,
- .ver_win_start = 0,
- .hor_win_start = 0,
- .blk_ver_win_start = 0,
- .blk_win_height = 0,
- .subsample_ver_inc = 0,
- .subsample_hor_inc = 0,
- .alaw_enable = 0,
- .aewb_enable = 0,
-};
/* Structure for saving/restoring h3a module registers */
static struct isp_reg isph3a_reg_list[] = {
@@ -150,72 +51,18 @@
{0, ISP_TOK_TERM, 0}
};
-static struct ispprev_wbal h3awb_update;
-static struct isph3a_aewb_buffer *active_buff;
-static struct isph3a_aewb_xtrastats h3a_xtrastats[H3A_MAX_BUFF];
-static int camnotify;
-static int wb_update;
-static void isph3a_print_status(void);
+static void isph3a_print_status(struct isp_h3a_device *isp_h3a);
-/**
- * isph3a_aewb_setxtrastats - Receives extra statistics from prior frames.
- * @xtrastats: Pointer to structure containing extra statistics fields like
- * field count and timestamp of frame.
- *
- * Called from update_vbq in camera driver
- **/
-void isph3a_aewb_setxtrastats(struct isph3a_aewb_xtrastats *xtrastats)
+void __isph3a_aewb_enable(struct isp_h3a_device *isp_h3a, u8 enable)
{
- int i;
+ struct device *dev = to_device(isp_h3a);
+ u32 pcr = isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
- if (active_buff == NULL)
- return;
-
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- if (aewbstat.h3a_buff[i].frame_num != active_buff->frame_num)
- continue;
-
- if (i == 0) {
- if (aewbstat.h3a_buff[H3A_MAX_BUFF - 1].locked == 0) {
- h3a_xtrastats[H3A_MAX_BUFF - 1] =
- *xtrastats;
- } else {
- h3a_xtrastats[H3A_MAX_BUFF - 2] =
- *xtrastats;
- }
- } else if (i == 1) {
- if (aewbstat.h3a_buff[0].locked == 0)
- h3a_xtrastats[0] = *xtrastats;
- else {
- h3a_xtrastats[H3A_MAX_BUFF - 1] =
- *xtrastats;
- }
- } else {
- if (aewbstat.h3a_buff[i - 1].locked == 0)
- h3a_xtrastats[i - 1] = *xtrastats;
- else
- h3a_xtrastats[i - 2] = *xtrastats;
- }
- return;
- }
-}
-EXPORT_SYMBOL(isph3a_aewb_setxtrastats);
-
-void __isph3a_aewb_enable(u8 enable)
-{
- isp_reg_writel(IRQ0STATUS_H3A_AWB_DONE_IRQ, OMAP3_ISP_IOMEM_MAIN,
- ISP_IRQ0STATUS);
-
- if (enable) {
- aewb_regs.reg_pcr |= ISPH3A_PCR_AEW_EN;
- DPRINTK_ISPH3A(" H3A enabled \n");
- } else {
- aewb_regs.reg_pcr &= ~ISPH3A_PCR_AEW_EN;
- DPRINTK_ISPH3A(" H3A disabled \n");
- }
- isp_reg_and_or(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, ~ISPH3A_PCR_AEW_EN,
- (enable ? ISPH3A_PCR_AEW_EN : 0));
- aewb_config_local.aewb_enable = enable;
+ if (enable)
+ pcr |= ISPH3A_PCR_AEW_EN;
+ else
+ pcr &= ~ISPH3A_PCR_AEW_EN;
+ isp_reg_writel(dev, pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
}
/**
@@ -224,46 +71,90 @@
*
* Client should configure all the AE & AWB registers in H3A before this.
**/
-void isph3a_aewb_enable(u8 enable)
+void isph3a_aewb_enable(struct isp_h3a_device *isp_h3a, u8 enable)
{
- __isph3a_aewb_enable(enable);
- aewbstat.pm_state = enable;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(isp_h3a->lock, irqflags);
+
+ if (!isp_h3a->aewb_config_local.aewb_enable && enable) {
+ spin_unlock_irqrestore(isp_h3a->lock, irqflags);
+ return;
+ }
+
+ __isph3a_aewb_enable(isp_h3a, enable);
+ isp_h3a->enabled = enable;
+
+ spin_unlock_irqrestore(isp_h3a->lock, irqflags);
}
/**
* isph3a_aewb_suspend - Suspend AE, AWB engine in the H3A module.
**/
-void isph3a_aewb_suspend(void)
+void isph3a_aewb_suspend(struct isp_h3a_device *isp_h3a)
{
- if (aewbstat.pm_state)
- __isph3a_aewb_enable(0);
+ unsigned long flags;
+
+ spin_lock_irqsave(isp_h3a->lock, flags);
+
+ if (isp_h3a->enabled)
+ __isph3a_aewb_enable(isp_h3a, 0);
+
+ spin_unlock_irqrestore(isp_h3a->lock, flags);
}
/**
* isph3a_aewb_resume - Resume AE, AWB engine in the H3A module.
**/
-void isph3a_aewb_resume(void)
+void isph3a_aewb_resume(struct isp_h3a_device *isp_h3a)
{
- if (aewbstat.pm_state)
- __isph3a_aewb_enable(1);
+ unsigned long flags;
+
+ spin_lock_irqsave(isp_h3a->lock, flags);
+
+ if (isp_h3a->enabled)
+ __isph3a_aewb_enable(isp_h3a, 1);
+
+ spin_unlock_irqrestore(isp_h3a->lock, flags);
}
-int isph3a_aewb_busy(void)
+int isph3a_aewb_busy(struct isp_h3a_device *isp_h3a)
{
- return isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
+ struct device *dev = to_device(isp_h3a);
+
+ return isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
& ISPH3A_PCR_BUSYAEAWB;
}
+void isph3a_aewb_try_enable(struct isp_h3a_device *isp_h3a)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(isp_h3a->lock, irqflags);
+ if (!isp_h3a->enabled && isp_h3a->aewb_config_local.aewb_enable) {
+ isp_h3a->update = 1;
+ isp_h3a->buf_next = ispstat_buf_next(&isp_h3a->stat);
+ spin_unlock_irqrestore(isp_h3a->lock, irqflags);
+ isph3a_aewb_config_registers(isp_h3a);
+ isph3a_aewb_enable(isp_h3a, 1);
+ } else
+ spin_unlock_irqrestore(isp_h3a->lock, irqflags);
+}
+
/**
* isph3a_update_wb - Updates WB parameters.
*
* Needs to be called when no ISP Preview processing is taking place.
**/
-void isph3a_update_wb(void)
+void isph3a_update_wb(struct isp_h3a_device *isp_h3a)
{
- if (wb_update) {
- isppreview_config_whitebalance(h3awb_update);
- wb_update = 0;
+ struct isp_device *isp = to_isp_device(isp_h3a);
+
+ if (isp_h3a->wb_update) {
+ /* FIXME: Get the preview crap out of here!!! */
+ isppreview_config_whitebalance(&isp->isp_prev,
+ isp_h3a->h3awb_update);
+ isp_h3a->wb_update = 0;
}
return;
}
@@ -272,30 +163,38 @@
/**
* isph3a_aewb_update_regs - Helper function to update h3a registers.
**/
-static void isph3a_aewb_update_regs(void)
+void isph3a_aewb_config_registers(struct isp_h3a_device *isp_h3a)
{
- isp_reg_writel(aewb_regs.reg_pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
- isp_reg_writel(aewb_regs.reg_win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1);
- isp_reg_writel(aewb_regs.reg_start, OMAP3_ISP_IOMEM_H3A,
+ struct device *dev = to_device(isp_h3a);
+ unsigned long irqflags;
+
+ if (!isp_h3a->aewb_config_local.aewb_enable)
+ return;
+
+ spin_lock_irqsave(isp_h3a->lock, irqflags);
+
+ isp_reg_writel(dev, isp_h3a->buf_next->iommu_addr,
+ OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST);
+
+ if (!isp_h3a->update) {
+ spin_unlock_irqrestore(isp_h3a->lock, irqflags);
+ return;
+ }
+
+ isp_reg_writel(dev, isp_h3a->regs.win1, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AEWWIN1);
+ isp_reg_writel(dev, isp_h3a->regs.start, OMAP3_ISP_IOMEM_H3A,
ISPH3A_AEWINSTART);
- isp_reg_writel(aewb_regs.reg_blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK);
- isp_reg_writel(aewb_regs.reg_subwin, OMAP3_ISP_IOMEM_H3A,
+ isp_reg_writel(dev, isp_h3a->regs.blk, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AEWINBLK);
+ isp_reg_writel(dev, isp_h3a->regs.subwin, OMAP3_ISP_IOMEM_H3A,
ISPH3A_AEWSUBWIN);
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+ ~ISPH3A_PCR_AEW_MASK, isp_h3a->regs.pcr);
- aewbstat.update = 0;
-}
+ isp_h3a->update = 0;
-/**
- * isph3a_aewb_update_req_buffer - Helper function to update buffer cache pages
- * @buffer: Pointer to structure
- **/
-static void isph3a_aewb_update_req_buffer(struct isph3a_aewb_buffer *buffer)
-{
- int size = aewbstat.stats_buf_size;
-
- size = PAGE_ALIGN(size);
- dmac_inv_range((void *)buffer->addr_align,
- (void *)buffer->addr_align + size);
+ spin_unlock_irqrestore(isp_h3a->lock, irqflags);
}
/**
@@ -304,116 +203,95 @@
*
* Returns 0 if successful, or -1 if statistics are unavailable.
**/
-static int isph3a_aewb_stats_available(struct isph3a_aewb_data *aewbdata)
+static int isph3a_aewb_get_stats(struct isp_h3a_device *isp_h3a,
+ struct isph3a_aewb_data *aewbdata)
{
- int i, ret;
- unsigned long irqflags;
+ struct ispstat_buffer *buf;
- spin_lock_irqsave(&aewbstat.buffer_lock, irqflags);
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- DPRINTK_ISPH3A("Checking Stats buff[%d] (%d) for %d\n",
- i, aewbstat.h3a_buff[i].frame_num,
- aewbdata->frame_number);
- if ((aewbdata->frame_number !=
- aewbstat.h3a_buff[i].frame_num) ||
- (aewbstat.h3a_buff[i].frame_num ==
- active_buff->frame_num))
- continue;
- aewbstat.h3a_buff[i].locked = 1;
- spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags);
- isph3a_aewb_update_req_buffer(&aewbstat.h3a_buff[i]);
- aewbstat.h3a_buff[i].frame_num = 0;
- ret = copy_to_user((void *)aewbdata->h3a_aewb_statistics_buf,
- (void *)aewbstat.h3a_buff[i].virt_addr,
- aewbstat.curr_cfg_buf_size);
- if (ret) {
- printk(KERN_ERR "Failed copy_to_user for "
- "H3A stats buff, %d\n", ret);
- }
- aewbdata->ts = aewbstat.h3a_buff[i].ts;
- aewbdata->config_counter = aewbstat.h3a_buff[i].config_counter;
- aewbdata->field_count = h3a_xtrastats[i].field_count;
- return 0;
- }
- spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags);
+ buf = ispstat_buf_get(&isp_h3a->stat,
+ (void *)aewbdata->h3a_aewb_statistics_buf,
+ aewbdata->frame_number);
- return -1;
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ aewbdata->ts = buf->ts;
+ aewbdata->config_counter = buf->config_counter;
+ aewbdata->frame_number = buf->frame_number;
+
+ ispstat_buf_release(&isp_h3a->stat);
+
+ return 0;
}
/**
- * isph3a_aewb_link_buffers - Helper function to link allocated buffers.
- **/
-static void isph3a_aewb_link_buffers(void)
-{
- int i;
-
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- if ((i + 1) < H3A_MAX_BUFF) {
- aewbstat.h3a_buff[i].next = &aewbstat.h3a_buff[i + 1];
- h3a_xtrastats[i].next = &h3a_xtrastats[i + 1];
- } else {
- aewbstat.h3a_buff[i].next = &aewbstat.h3a_buff[0];
- h3a_xtrastats[i].next = &h3a_xtrastats[0];
- }
- }
-}
-
-/**
- * isph3a_aewb_unlock_buffers - Helper function to unlock all buffers.
- **/
-static void isph3a_aewb_unlock_buffers(void)
-{
- int i;
- unsigned long irqflags;
-
- spin_lock_irqsave(&aewbstat.buffer_lock, irqflags);
- for (i = 0; i < H3A_MAX_BUFF; i++)
- aewbstat.h3a_buff[i].locked = 0;
-
- spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags);
-}
-
-/**
- * isph3a_aewb_isr - Callback from ISP driver for H3A AEWB interrupt.
- * @status: IRQ0STATUS in case of MMU error, 0 for H3A interrupt.
- * @arg1: Not used as of now.
- * @arg2: Not used as of now.
+ * isph3a_aewb_buf_process - Process H3A AEWB buffer.
*/
-static void isph3a_aewb_isr(unsigned long status, isp_vbq_callback_ptr arg1,
- void *arg2)
+int isph3a_aewb_buf_process(struct isp_h3a_device *isp_h3a)
{
- u16 frame_align;
+ isph3a_update_wb(isp_h3a);
+ if (likely(!isp_h3a->buf_err &&
+ isp_h3a->aewb_config_local.aewb_enable)) {
+ int ret;
- if ((H3A_AWB_DONE & status) != H3A_AWB_DONE)
- return;
-
- do_gettimeofday(&active_buff->ts);
- active_buff->config_counter = atomic_read(&aewbstat.config_counter);
- active_buff = active_buff->next;
- if (active_buff->locked == 1)
- active_buff = active_buff->next;
- isp_reg_writel(active_buff->ispmmu_addr, OMAP3_ISP_IOMEM_H3A,
- ISPH3A_AEWBUFST);
-
- aewbstat.frame_count++;
- frame_align = aewbstat.frame_count;
- if (aewbstat.frame_count > MAX_FRAME_COUNT) {
- aewbstat.frame_count = 1;
- frame_align++;
+ ret = ispstat_buf_queue(&isp_h3a->stat);
+ isp_h3a->buf_next = ispstat_buf_next(&isp_h3a->stat);
+ return ret;
+ } else {
+ isp_h3a->buf_err = 0;
+ return -1;
}
- active_buff->frame_num = aewbstat.frame_count;
+}
- if (aewbstat.stats_req) {
- DPRINTK_ISPH3A("waiting for frame %d\n", aewbstat.frame_req);
- if (frame_align >= aewbstat.frame_req + 1) {
- aewbstat.stats_req = 0;
- aewbstat.stats_done = 1;
- wake_up_interruptible(&aewbstat.stats_wait);
- }
- }
+static int isph3a_aewb_validate_params(struct isp_h3a_device *isp_h3a,
+ struct isph3a_aewb_config *user_cfg)
+{
+ if (unlikely(user_cfg->saturation_limit > MAX_SATURATION_LIM))
+ return -EINVAL;
- if (aewbstat.update)
- isph3a_aewb_update_regs();
+ if (unlikely(user_cfg->win_height < MIN_WIN_H ||
+ user_cfg->win_height > MAX_WIN_H ||
+ user_cfg->win_height & 0x01))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->win_width < MIN_WIN_W ||
+ user_cfg->win_width > MAX_WIN_W ||
+ user_cfg->win_width & 0x01))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->ver_win_count < 1 ||
+ user_cfg->ver_win_count > MAX_WINVC))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->hor_win_count < 1 ||
+ user_cfg->hor_win_count > MAX_WINHC))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->ver_win_start > MAX_WINSTART))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->hor_win_start > MAX_WINSTART))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->blk_ver_win_start > MAX_WINSTART))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->blk_win_height < MIN_WIN_H ||
+ user_cfg->blk_win_height > MAX_WIN_H ||
+ user_cfg->blk_win_height & 0x01))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->subsample_ver_inc < MIN_SUB_INC ||
+ user_cfg->subsample_ver_inc > MAX_SUB_INC ||
+ user_cfg->subsample_ver_inc & 0x01))
+ return -EINVAL;
+
+ if (unlikely(user_cfg->subsample_hor_inc < MIN_SUB_INC ||
+ user_cfg->subsample_hor_inc > MAX_SUB_INC ||
+ user_cfg->subsample_hor_inc & 0x01))
+ return -EINVAL;
+
+ return 0;
}
/**
@@ -425,287 +303,156 @@
*
* Returns 0 if successful, or -EINVAL if any of the parameters are invalid.
**/
-static int isph3a_aewb_set_params(struct isph3a_aewb_config *user_cfg)
+static void isph3a_aewb_set_params(struct isp_h3a_device *isp_h3a,
+ struct isph3a_aewb_config *user_cfg)
{
- if (unlikely(user_cfg->saturation_limit > MAX_SATURATION_LIM)) {
- printk(KERN_ERR "Invalid Saturation_limit: %d\n",
- user_cfg->saturation_limit);
- return -EINVAL;
- }
- if (aewb_config_local.saturation_limit != user_cfg->saturation_limit) {
- WRITE_SAT_LIM(aewb_regs.reg_pcr, user_cfg->saturation_limit);
- aewb_config_local.saturation_limit =
+ if (isp_h3a->aewb_config_local.saturation_limit !=
+ user_cfg->saturation_limit) {
+ WRITE_SAT_LIM(isp_h3a->regs.pcr, user_cfg->saturation_limit);
+ isp_h3a->aewb_config_local.saturation_limit =
user_cfg->saturation_limit;
- aewbstat.update = 1;
+ isp_h3a->update = 1;
}
- if (aewb_config_local.alaw_enable != user_cfg->alaw_enable) {
- WRITE_ALAW(aewb_regs.reg_pcr, user_cfg->alaw_enable);
- aewb_config_local.alaw_enable = user_cfg->alaw_enable;
- aewbstat.update = 1;
+ if (isp_h3a->aewb_config_local.alaw_enable != user_cfg->alaw_enable) {
+ WRITE_ALAW(isp_h3a->regs.pcr, user_cfg->alaw_enable);
+ isp_h3a->aewb_config_local.alaw_enable = user_cfg->alaw_enable;
+ isp_h3a->update = 1;
}
- if (unlikely(user_cfg->win_height < MIN_WIN_H ||
- user_cfg->win_height > MAX_WIN_H ||
- user_cfg->win_height & 0x01)) {
- printk(KERN_ERR "Invalid window height: %d\n",
- user_cfg->win_height);
- return -EINVAL;
- }
- if (aewb_config_local.win_height != user_cfg->win_height) {
- WRITE_WIN_H(aewb_regs.reg_win1, user_cfg->win_height);
- aewb_config_local.win_height = user_cfg->win_height;
- aewbstat.update = 1;
+ if (isp_h3a->aewb_config_local.win_height != user_cfg->win_height) {
+ WRITE_WIN_H(isp_h3a->regs.win1, user_cfg->win_height);
+ isp_h3a->aewb_config_local.win_height = user_cfg->win_height;
+ isp_h3a->update = 1;
}
- if (unlikely(user_cfg->win_width < MIN_WIN_W ||
- user_cfg->win_width > MAX_WIN_W ||
- user_cfg->win_width & 0x01)) {
- printk(KERN_ERR "Invalid window width: %d\n",
- user_cfg->win_width);
- return -EINVAL;
- }
- if (aewb_config_local.win_width != user_cfg->win_width) {
- WRITE_WIN_W(aewb_regs.reg_win1, user_cfg->win_width);
- aewb_config_local.win_width = user_cfg->win_width;
- aewbstat.update = 1;
+ if (isp_h3a->aewb_config_local.win_width != user_cfg->win_width) {
+ WRITE_WIN_W(isp_h3a->regs.win1, user_cfg->win_width);
+ isp_h3a->aewb_config_local.win_width = user_cfg->win_width;
+ isp_h3a->update = 1;
}
- if (unlikely(user_cfg->ver_win_count < 1 ||
- user_cfg->ver_win_count > MAX_WINVC)) {
- printk(KERN_ERR "Invalid vertical window count: %d\n",
- user_cfg->ver_win_count);
- return -EINVAL;
- }
- if (aewb_config_local.ver_win_count != user_cfg->ver_win_count) {
- WRITE_VER_C(aewb_regs.reg_win1, user_cfg->ver_win_count);
- aewb_config_local.ver_win_count = user_cfg->ver_win_count;
- aewbstat.update = 1;
+ if (isp_h3a->aewb_config_local.ver_win_count !=
+ user_cfg->ver_win_count) {
+ WRITE_VER_C(isp_h3a->regs.win1, user_cfg->ver_win_count);
+ isp_h3a->aewb_config_local.ver_win_count =
+ user_cfg->ver_win_count;
+ isp_h3a->update = 1;
}
- if (unlikely(user_cfg->hor_win_count < 1 ||
- user_cfg->hor_win_count > MAX_WINHC)) {
- printk(KERN_ERR "Invalid horizontal window count: %d\n",
- user_cfg->hor_win_count);
- return -EINVAL;
- }
- if (aewb_config_local.hor_win_count != user_cfg->hor_win_count) {
- WRITE_HOR_C(aewb_regs.reg_win1, user_cfg->hor_win_count);
- aewb_config_local.hor_win_count = user_cfg->hor_win_count;
- aewbstat.update = 1;
+ if (isp_h3a->aewb_config_local.hor_win_count !=
+ user_cfg->hor_win_count) {
+ WRITE_HOR_C(isp_h3a->regs.win1, user_cfg->hor_win_count);
+ isp_h3a->aewb_config_local.hor_win_count =
+ user_cfg->hor_win_count;
+ isp_h3a->update = 1;
}
- if (unlikely(user_cfg->ver_win_start > MAX_WINSTART)) {
- printk(KERN_ERR "Invalid vertical window start: %d\n",
- user_cfg->ver_win_start);
- return -EINVAL;
- }
- if (aewb_config_local.ver_win_start != user_cfg->ver_win_start) {
- WRITE_VER_WIN_ST(aewb_regs.reg_start, user_cfg->ver_win_start);
- aewb_config_local.ver_win_start = user_cfg->ver_win_start;
- aewbstat.update = 1;
+ if (isp_h3a->aewb_config_local.ver_win_start !=
+ user_cfg->ver_win_start) {
+ WRITE_VER_WIN_ST(isp_h3a->regs.start, user_cfg->ver_win_start);
+ isp_h3a->aewb_config_local.ver_win_start =
+ user_cfg->ver_win_start;
+ isp_h3a->update = 1;
}
- if (unlikely(user_cfg->hor_win_start > MAX_WINSTART)) {
- printk(KERN_ERR "Invalid horizontal window start: %d\n",
- user_cfg->hor_win_start);
- return -EINVAL;
- }
- if (aewb_config_local.hor_win_start != user_cfg->hor_win_start) {
- WRITE_HOR_WIN_ST(aewb_regs.reg_start, user_cfg->hor_win_start);
- aewb_config_local.hor_win_start = user_cfg->hor_win_start;
- aewbstat.update = 1;
+ if (isp_h3a->aewb_config_local.hor_win_start !=
+ user_cfg->hor_win_start) {
+ WRITE_HOR_WIN_ST(isp_h3a->regs.start, user_cfg->hor_win_start);
+ isp_h3a->aewb_config_local.hor_win_start =
+ user_cfg->hor_win_start;
+ isp_h3a->update = 1;
}
- if (unlikely(user_cfg->blk_ver_win_start > MAX_WINSTART)) {
- printk(KERN_ERR "Invalid black vertical window start: %d\n",
- user_cfg->blk_ver_win_start);
- return -EINVAL;
- }
- if (aewb_config_local.blk_ver_win_start !=
+ if (isp_h3a->aewb_config_local.blk_ver_win_start !=
user_cfg->blk_ver_win_start) {
- WRITE_BLK_VER_WIN_ST(aewb_regs.reg_blk,
+ WRITE_BLK_VER_WIN_ST(isp_h3a->regs.blk,
user_cfg->blk_ver_win_start);
- aewb_config_local.blk_ver_win_start =
+ isp_h3a->aewb_config_local.blk_ver_win_start =
user_cfg->blk_ver_win_start;
- aewbstat.update = 1;
+ isp_h3a->update = 1;
}
- if (unlikely(user_cfg->blk_win_height < MIN_WIN_H ||
- user_cfg->blk_win_height > MAX_WIN_H ||
- user_cfg->blk_win_height & 0x01)) {
- printk(KERN_ERR "Invalid black window height: %d\n",
- user_cfg->blk_win_height);
- return -EINVAL;
- }
- if (aewb_config_local.blk_win_height != user_cfg->blk_win_height) {
- WRITE_BLK_WIN_H(aewb_regs.reg_blk, user_cfg->blk_win_height);
- aewb_config_local.blk_win_height = user_cfg->blk_win_height;
- aewbstat.update = 1;
+ if (isp_h3a->aewb_config_local.blk_win_height !=
+ user_cfg->blk_win_height) {
+ WRITE_BLK_WIN_H(isp_h3a->regs.blk, user_cfg->blk_win_height);
+ isp_h3a->aewb_config_local.blk_win_height =
+ user_cfg->blk_win_height;
+ isp_h3a->update = 1;
}
- if (unlikely(user_cfg->subsample_ver_inc < MIN_SUB_INC ||
- user_cfg->subsample_ver_inc > MAX_SUB_INC ||
- user_cfg->subsample_ver_inc & 0x01)) {
- printk(KERN_ERR "Invalid vertical subsample increment: %d\n",
- user_cfg->subsample_ver_inc);
- return -EINVAL;
- }
- if (aewb_config_local.subsample_ver_inc !=
+ if (isp_h3a->aewb_config_local.subsample_ver_inc !=
user_cfg->subsample_ver_inc) {
- WRITE_SUB_VER_INC(aewb_regs.reg_subwin,
+ WRITE_SUB_VER_INC(isp_h3a->regs.subwin,
user_cfg->subsample_ver_inc);
- aewb_config_local.subsample_ver_inc =
+ isp_h3a->aewb_config_local.subsample_ver_inc =
user_cfg->subsample_ver_inc;
- aewbstat.update = 1;
+ isp_h3a->update = 1;
}
- if (unlikely(user_cfg->subsample_hor_inc < MIN_SUB_INC ||
- user_cfg->subsample_hor_inc > MAX_SUB_INC ||
- user_cfg->subsample_hor_inc & 0x01)) {
- printk(KERN_ERR "Invalid horizontal subsample increment: %d\n",
- user_cfg->subsample_hor_inc);
- return -EINVAL;
- }
- if (aewb_config_local.subsample_hor_inc !=
+ if (isp_h3a->aewb_config_local.subsample_hor_inc !=
user_cfg->subsample_hor_inc) {
- WRITE_SUB_HOR_INC(aewb_regs.reg_subwin,
+ WRITE_SUB_HOR_INC(isp_h3a->regs.subwin,
user_cfg->subsample_hor_inc);
- aewb_config_local.subsample_hor_inc =
+ isp_h3a->aewb_config_local.subsample_hor_inc =
user_cfg->subsample_hor_inc;
- aewbstat.update = 1;
+ isp_h3a->update = 1;
}
- if (!aewbstat.initialized || !aewb_config_local.aewb_enable) {
- isph3a_aewb_update_regs();
- aewbstat.initialized = 1;
- }
- return 0;
+ isp_h3a->aewb_config_local.aewb_enable = user_cfg->aewb_enable;;
}
/**
- * isph3a_aewb_configure - Configure AEWB regs, enable/disable H3A engine.
+ * isph3a_aewb_config - Configure AEWB regs, enable/disable H3A engine.
* @aewbcfg: Pointer to AEWB config structure.
*
* Returns 0 if successful, -EINVAL if aewbcfg pointer is NULL, -ENOMEM if
* was unable to allocate memory for the buffer, of other errors if H3A
* callback is not set or the parameters for AEWB are invalid.
**/
-int isph3a_aewb_configure(struct isph3a_aewb_config *aewbcfg)
+int isph3a_aewb_config(struct isp_h3a_device *isp_h3a,
+ struct isph3a_aewb_config *aewbcfg)
{
+ struct device *dev = to_device(isp_h3a);
int ret = 0;
- int i;
int win_count = 0;
+ unsigned int buf_size;
+ unsigned long irqflags;
if (NULL == aewbcfg) {
- printk(KERN_ERR "Null argument in configuration. \n");
+ dev_dbg(dev, "h3a: Null argument in configuration\n");
return -EINVAL;
}
- if (!aewbstat.initialized) {
- DPRINTK_ISPH3A("Setting callback for H3A\n");
- ret = isp_set_callback(CBK_H3A_AWB_DONE, isph3a_aewb_isr,
- (void *)NULL, (void *)NULL);
- if (ret) {
- printk(KERN_ERR "No callback for H3A\n");
- return ret;
- }
- }
-
- ret = isph3a_aewb_set_params(aewbcfg);
- if (ret) {
- printk(KERN_ERR "Invalid parameters! \n");
+ ret = isph3a_aewb_validate_params(isp_h3a, aewbcfg);
+ if (ret)
return ret;
- }
+ /* FIXME: This win_count handling looks really fishy. */
win_count = aewbcfg->ver_win_count * aewbcfg->hor_win_count;
win_count += aewbcfg->hor_win_count;
ret = win_count / 8;
win_count += win_count % 8 ? 1 : 0;
win_count += ret;
- aewbstat.win_count = win_count;
- aewbstat.curr_cfg_buf_size = win_count * AEWB_PACKET_SIZE;
+ buf_size = win_count * AEWB_PACKET_SIZE;
- if (aewbstat.stats_buf_size
- && win_count * AEWB_PACKET_SIZE > aewbstat.stats_buf_size) {
- DPRINTK_ISPH3A("There was a previous buffer... "
- "Freeing/unmapping current stat busffs\n");
- isph3a_aewb_enable(0);
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- ispmmu_kunmap(aewbstat.h3a_buff[i].ispmmu_addr);
- dma_free_coherent(
- NULL,
- aewbstat.min_buf_size,
- (void *)aewbstat.h3a_buff[i].virt_addr,
- (dma_addr_t)aewbstat.h3a_buff[i].phy_addr);
- aewbstat.h3a_buff[i].virt_addr = 0;
- }
- aewbstat.stats_buf_size = 0;
- }
+ ret = ispstat_bufs_alloc(&isp_h3a->stat, buf_size, 0);
+ if (ret)
+ return ret;
- if (!aewbstat.h3a_buff[0].virt_addr) {
- aewbstat.stats_buf_size = win_count * AEWB_PACKET_SIZE;
- aewbstat.min_buf_size = PAGE_ALIGN(aewbstat.stats_buf_size);
+ spin_lock_irqsave(isp_h3a->lock, irqflags);
- DPRINTK_ISPH3A("Allocating/mapping new stat buffs\n");
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- aewbstat.h3a_buff[i].frame_num = 0;
- aewbstat.h3a_buff[i].virt_addr =
- (unsigned long)dma_alloc_coherent(
- NULL,
- aewbstat.min_buf_size,
- (dma_addr_t *)
- &aewbstat.h3a_buff[i].phy_addr,
- GFP_KERNEL | GFP_DMA);
- if (aewbstat.h3a_buff[i].virt_addr == 0) {
- printk(KERN_ERR "Can't acquire memory for "
- "buffer[%d]\n", i);
- return -ENOMEM;
- }
- aewbstat.h3a_buff[i].addr_align =
- aewbstat.h3a_buff[i].virt_addr;
- while ((aewbstat.h3a_buff[i].addr_align & 0xFFFFFFC0) !=
- aewbstat.h3a_buff[i].addr_align)
- aewbstat.h3a_buff[i].addr_align++;
- aewbstat.h3a_buff[i].ispmmu_addr =
- ispmmu_kmap(aewbstat.h3a_buff[i].phy_addr,
- aewbstat.min_buf_size);
- }
- isph3a_aewb_unlock_buffers();
- isph3a_aewb_link_buffers();
+ isp_h3a->win_count = win_count;
+ isph3a_aewb_set_params(isp_h3a, aewbcfg);
- if (active_buff == NULL)
- active_buff = &aewbstat.h3a_buff[0];
+ spin_unlock_irqrestore(isp_h3a->lock, irqflags);
- isp_reg_writel(active_buff->ispmmu_addr, OMAP3_ISP_IOMEM_H3A,
- ISPH3A_AEWBUFST);
- }
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- DPRINTK_ISPH3A("buff[%d] addr is:\n virt 0x%lX\n"
- " aligned 0x%lX\n"
- " phys 0x%lX\n"
- " ispmmu 0x%08lX\n"
- " mmapped 0x%lX\n"
- " frame_num %d\n", i,
- aewbstat.h3a_buff[i].virt_addr,
- aewbstat.h3a_buff[i].addr_align,
- aewbstat.h3a_buff[i].phy_addr,
- aewbstat.h3a_buff[i].ispmmu_addr,
- aewbstat.h3a_buff[i].mmap_addr,
- aewbstat.h3a_buff[i].frame_num);
- }
-
- active_buff->frame_num = 1;
- aewbstat.frame_count = 1;
-
- atomic_inc(&aewbstat.config_counter);
- isph3a_aewb_enable(aewbcfg->aewb_enable);
- isph3a_print_status();
+ isph3a_print_status(isp_h3a);
return 0;
}
-EXPORT_SYMBOL(isph3a_aewb_configure);
+EXPORT_SYMBOL(isph3a_aewb_config);
/**
* isph3a_aewb_request_statistics - REquest statistics and update gains in AEWB
@@ -718,22 +465,23 @@
* Returns 0 if successful, -EINVAL when H3A engine is not enabled, or other
* errors when setting gains.
**/
-int isph3a_aewb_request_statistics(struct isph3a_aewb_data *aewbdata)
+int isph3a_aewb_request_statistics(struct isp_h3a_device *isp_h3a,
+ struct isph3a_aewb_data *aewbdata)
{
+ struct device *dev = to_device(isp_h3a);
+ unsigned long irqflags;
int ret = 0;
- u16 frame_diff = 0;
- u16 frame_cnt = aewbstat.frame_count;
- wait_queue_t wqt;
- if (!aewb_config_local.aewb_enable) {
- printk(KERN_ERR "H3A engine not enabled\n");
+ if (!isp_h3a->aewb_config_local.aewb_enable) {
+ dev_dbg(dev, "h3a: engine not enabled\n");
return -EINVAL;
}
DPRINTK_ISPH3A("isph3a_aewb_request_statistics: Enter "
"(frame req. => %d, current frame => %d,"
"update => %d)\n",
- aewbdata->frame_number, frame_cnt, aewbdata->update);
+ aewbdata->frame_number, isp_h3a->stat.frame_number,
+ aewbdata->update);
DPRINTK_ISPH3A("User data received: \n");
DPRINTK_ISPH3A("Digital gain = 0x%04x\n", aewbdata->dgain);
DPRINTK_ISPH3A("WB gain b *= 0x%04x\n", aewbdata->wb_gain_b);
@@ -741,93 +489,31 @@
DPRINTK_ISPH3A("WB gain gb = 0x%04x\n", aewbdata->wb_gain_gb);
DPRINTK_ISPH3A("WB gain gr = 0x%04x\n", aewbdata->wb_gain_gr);
- if (!aewbdata->update) {
- aewbdata->h3a_aewb_statistics_buf = NULL;
- goto out;
- }
+ spin_lock_irqsave(isp_h3a->lock, irqflags);
+
if (aewbdata->update & SET_DIGITAL_GAIN)
- h3awb_update.dgain = (u16)aewbdata->dgain;
+ isp_h3a->h3awb_update.dgain = (u16)aewbdata->dgain;
if (aewbdata->update & SET_COLOR_GAINS) {
- h3awb_update.coef0 = (u8)aewbdata->wb_gain_r;
- h3awb_update.coef1 = (u8)aewbdata->wb_gain_gr;
- h3awb_update.coef2 = (u8)aewbdata->wb_gain_gb;
- h3awb_update.coef3 = (u8)aewbdata->wb_gain_b;
+ isp_h3a->h3awb_update.coef0 = (u8)aewbdata->wb_gain_r;
+ isp_h3a->h3awb_update.coef1 = (u8)aewbdata->wb_gain_gr;
+ isp_h3a->h3awb_update.coef2 = (u8)aewbdata->wb_gain_gb;
+ isp_h3a->h3awb_update.coef3 = (u8)aewbdata->wb_gain_b;
}
if (aewbdata->update & (SET_COLOR_GAINS | SET_DIGITAL_GAIN))
- wb_update = 1;
+ isp_h3a->wb_update = 1;
- if (!(aewbdata->update & REQUEST_STATISTICS)) {
- aewbdata->h3a_aewb_statistics_buf = NULL;
- goto out;
- }
+ spin_unlock_irqrestore(isp_h3a->lock, irqflags);
- if (aewbdata->frame_number < 1) {
- printk(KERN_ERR "Illeagal frame number "
- "requested (%d)\n",
- aewbdata->frame_number);
- return -EINVAL;
- }
+ if (aewbdata->update & REQUEST_STATISTICS)
+ ret = isph3a_aewb_get_stats(isp_h3a, aewbdata);
- isph3a_aewb_unlock_buffers();
+ aewbdata->curr_frame = isp_h3a->stat.frame_number;
- DPRINTK_ISPH3A("Stats available?\n");
- ret = isph3a_aewb_stats_available(aewbdata);
- if (!ret)
- goto out;
-
- DPRINTK_ISPH3A("Stats in near future?\n");
- if (aewbdata->frame_number > frame_cnt)
- frame_diff = aewbdata->frame_number - frame_cnt;
- else if (aewbdata->frame_number < frame_cnt) {
- if ((frame_cnt > (MAX_FRAME_COUNT - MAX_FUTURE_FRAMES)) &&
- (aewbdata->frame_number < MAX_FRAME_COUNT)) {
- frame_diff = aewbdata->frame_number + MAX_FRAME_COUNT -
- frame_cnt;
- } else
- frame_diff = MAX_FUTURE_FRAMES + 1;
- }
-
- if (frame_diff > MAX_FUTURE_FRAMES) {
- printk(KERN_ERR "Invalid frame requested, returning current"
- " frame stats\n");
- aewbdata->frame_number = frame_cnt;
- }
- if (camnotify) {
- DPRINTK_ISPH3A("NOT Waiting on stats IRQ for frame %d "
- "because camnotify set\n",
- aewbdata->frame_number);
- aewbdata->h3a_aewb_statistics_buf = NULL;
- goto out;
- }
- DPRINTK_ISPH3A("Waiting on stats IRQ for frame %d\n",
- aewbdata->frame_number);
- aewbstat.frame_req = aewbdata->frame_number;
- aewbstat.stats_req = 1;
- aewbstat.stats_done = 0;
- init_waitqueue_entry(&wqt, current);
- ret = wait_event_interruptible(aewbstat.stats_wait,
- aewbstat.stats_done == 1);
- if (ret < 0) {
- printk(KERN_ERR "isph3a_aewb_request_statistics"
- " Error on wait event %d\n", ret);
- aewbdata->h3a_aewb_statistics_buf = NULL;
- return ret;
- }
-
- DPRINTK_ISPH3A("ISP AEWB request status interrupt raised\n");
- ret = isph3a_aewb_stats_available(aewbdata);
- if (ret) {
- DPRINTK_ISPH3A("After waiting for stats,"
- " stats not available!!\n");
- aewbdata->h3a_aewb_statistics_buf = NULL;
- }
-out:
DPRINTK_ISPH3A("isph3a_aewb_request_statistics: "
"aewbdata->h3a_aewb_statistics_buf => %p\n",
aewbdata->h3a_aewb_statistics_buf);
- aewbdata->curr_frame = aewbstat.frame_count;
- return 0;
+ return ret;
}
EXPORT_SYMBOL(isph3a_aewb_request_statistics);
@@ -836,98 +522,77 @@
*
* Always returns 0.
**/
-int __init isph3a_aewb_init(void)
+int __init isph3a_aewb_init(struct device *dev)
{
- memset(&aewbstat, 0, sizeof(aewbstat));
- memset(&aewb_regs, 0, sizeof(aewb_regs));
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_h3a_device *isp_h3a = &isp->isp_h3a;
- init_waitqueue_head(&aewbstat.stats_wait);
- spin_lock_init(&aewbstat.buffer_lock);
+ isp_h3a->lock = &isp->h3a_lock;
+ isp_h3a->aewb_config_local.saturation_limit = AEWB_SATURATION_LIMIT;
+ ispstat_init(dev, "H3A", &isp_h3a->stat, H3A_MAX_BUFF, MAX_FRAME_COUNT);
+
return 0;
}
/**
* isph3a_aewb_cleanup - Module exit.
**/
-void isph3a_aewb_cleanup(void)
+void isph3a_aewb_cleanup(struct device *dev)
{
- int i;
+ struct isp_device *isp = dev_get_drvdata(dev);
- for (i = 0; i < H3A_MAX_BUFF; i++) {
- if (!aewbstat.h3a_buff[i].phy_addr)
- continue;
-
- ispmmu_kunmap(aewbstat.h3a_buff[i].ispmmu_addr);
- dma_free_coherent(NULL,
- aewbstat.min_buf_size,
- (void *)aewbstat.h3a_buff[i].virt_addr,
- (dma_addr_t)aewbstat.h3a_buff[i].phy_addr);
- }
- memset(&aewbstat, 0, sizeof(aewbstat));
- memset(&aewb_regs, 0, sizeof(aewb_regs));
+ ispstat_free(&isp->isp_h3a.stat);
}
/**
* isph3a_print_status - Debug print. Values of H3A related registers.
**/
-static void isph3a_print_status(void)
+static void isph3a_print_status(struct isp_h3a_device *isp_h3a)
{
- DPRINTK_ISPH3A("ISPH3A_PCR = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR));
- DPRINTK_ISPH3A("ISPH3A_AEWWIN1 = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1));
- DPRINTK_ISPH3A("ISPH3A_AEWINSTART = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINSTART));
- DPRINTK_ISPH3A("ISPH3A_AEWINBLK = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK));
- DPRINTK_ISPH3A("ISPH3A_AEWSUBWIN = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWSUBWIN));
- DPRINTK_ISPH3A("ISPH3A_AEWBUFST = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST));
- DPRINTK_ISPH3A("stats windows = %d\n", aewbstat.win_count);
- DPRINTK_ISPH3A("stats buff size = %d\n", aewbstat.stats_buf_size);
- DPRINTK_ISPH3A("currently configured stats buff size = %d\n",
- aewbstat.curr_cfg_buf_size);
-}
+#ifdef OMAP_ISPH3A_DEBUG
+ struct device *dev = to_device(isp_h3a);
+#endif
-/**
- * isph3a_notify - Unblocks user request for statistics when camera is off
- * @notify: 1 - Camera is turned off
- *
- * Used when the user has requested statistics about a future frame, but the
- * camera is turned off before it happens, and this function unblocks the
- * request so the user can continue in its program.
- **/
-void isph3a_notify(int notify)
-{
- camnotify = notify;
- if (camnotify && aewbstat.initialized) {
- printk(KERN_DEBUG "Warning Camera Off \n");
- aewbstat.stats_req = 0;
- aewbstat.stats_done = 1;
- wake_up_interruptible(&aewbstat.stats_wait);
- }
+ DPRINTK_ISPH3A("ISPH3A_PCR = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_PCR));
+ DPRINTK_ISPH3A("ISPH3A_AEWWIN1 = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AEWWIN1));
+ DPRINTK_ISPH3A("ISPH3A_AEWINSTART = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AEWINSTART));
+ DPRINTK_ISPH3A("ISPH3A_AEWINBLK = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AEWINBLK));
+ DPRINTK_ISPH3A("ISPH3A_AEWSUBWIN = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AEWSUBWIN));
+ DPRINTK_ISPH3A("ISPH3A_AEWBUFST = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A,
+ ISPH3A_AEWBUFST));
+ DPRINTK_ISPH3A("stats windows = %d\n", isp_h3a->win_count);
+ DPRINTK_ISPH3A("stats buf size = %d\n", isp_h3a->stat.buf_size);
}
-EXPORT_SYMBOL(isph3a_notify);
/**
* isph3a_save_context - Saves the values of the h3a module registers.
**/
-void isph3a_save_context(void)
+void isph3a_save_context(struct device *dev)
{
DPRINTK_ISPH3A(" Saving context\n");
- isp_save_context(isph3a_reg_list);
+ isp_save_context(dev, isph3a_reg_list);
/* Avoid enable during restore ctx */
- isph3a_reg_list[0].val &= ~ISPH3A_PCR_AEW_EN;
+ isph3a_reg_list[0].val &= ~(ISPH3A_PCR_AEW_EN | ISPH3A_PCR_AF_EN);
}
EXPORT_SYMBOL(isph3a_save_context);
/**
* isph3a_restore_context - Restores the values of the h3a module registers.
**/
-void isph3a_restore_context(void)
+void isph3a_restore_context(struct device *dev)
{
DPRINTK_ISPH3A(" Restoring context\n");
- isp_restore_context(isph3a_reg_list);
+ isp_restore_context(dev, isph3a_reg_list);
}
EXPORT_SYMBOL(isph3a_restore_context);
diff --git a/drivers/media/video/isp/isph3a.h b/drivers/media/video/isp/isph3a.h
index 7d4c765..5b0179c 100644
--- a/drivers/media/video/isp/isph3a.h
+++ b/drivers/media/video/isp/isph3a.h
@@ -25,6 +25,7 @@
#define AEWB_PACKET_SIZE 16
#define H3A_MAX_BUFF 5
+#define AEWB_SATURATION_LIMIT 0x3FF
/* Flags for changed registers */
#define PCR_CHNG (1 << 0)
@@ -43,6 +44,8 @@
#define ISPH3A_PCR_AEW_EN (1 << 16)
#define ISPH3A_PCR_AEW_ALAW_EN (1 << 17)
#define ISPH3A_PCR_AEW_BUSY (1 << 18)
+#define ISPH3A_PCR_AEW_MASK (ISPH3A_PCR_AEW_ALAW_EN | \
+ ISPH3A_PCR_AEW_AVE2LMT_MASK)
#define WRITE_SAT_LIM(reg, sat_limit) \
(reg = (reg & (~(ISPH3A_PCR_AEW_AVE2LMT_MASK))) \
@@ -94,34 +97,62 @@
| (((sub_hor_inc >> 1) - 1) << ISPH3A_AEWSUBWIN_AEWINCH_SHIFT))
/**
- * struct isph3a_aewb_xtrastats - Structure with extra statistics sent by cam.
- * @field_count: Sequence number of returned framestats.
- * @isph3a_aewb_xtrastats: Pointer to next buffer with extra stats.
+ * struct isph3a_aewb_regs - Current value of AE, AWB configuration registers.
+ * pcr: Peripheral control register.
+ * win1: Control register.
+ * start: Start position register.
+ * blk: Black line register.
+ * subwin: Configuration register.
*/
-struct isph3a_aewb_xtrastats {
- unsigned long field_count;
- struct isph3a_aewb_xtrastats *next;
+struct isph3a_aewb_regs {
+ u32 pcr;
+ u32 win1;
+ u32 start;
+ u32 blk;
+ u32 subwin;
};
-void isph3a_aewb_setxtrastats(struct isph3a_aewb_xtrastats *xtrastats);
+struct isp_h3a_device {
+ spinlock_t *lock; /* Lock for this struct */
-int isph3a_aewb_configure(struct isph3a_aewb_config *aewbcfg);
+ u8 update;
+ u8 buf_err;
+ int enabled;
+ int wb_update;
-int isph3a_aewb_request_statistics(struct isph3a_aewb_data *aewbdata);
+ struct isph3a_aewb_regs regs;
+ struct ispprev_wbal h3awb_update;
+ struct isph3a_aewb_config aewb_config_local;
+ struct ispstat_buffer *buf_next;
+ u16 win_count;
-void isph3a_save_context(void);
+ struct ispstat stat;
+};
-void isph3a_restore_context(void);
+int isph3a_aewb_config(struct isp_h3a_device *isp_h3a,
+ struct isph3a_aewb_config *aewbcfg);
-void isph3a_aewb_enable(u8 enable);
+int isph3a_aewb_request_statistics(struct isp_h3a_device *isp_h3a,
+ struct isph3a_aewb_data *aewbdata);
-int isph3a_aewb_busy(void);
+void isph3a_save_context(struct device *dev);
-void isph3a_aewb_suspend(void);
+void isph3a_restore_context(struct device *dev);
-void isph3a_aewb_resume(void);
+void isph3a_aewb_enable(struct isp_h3a_device *isp_h3a, u8 enable);
-void isph3a_update_wb(void);
+void isph3a_aewb_try_enable(struct isp_h3a_device *isp_h3a);
-void isph3a_notify(int notify);
+int isph3a_aewb_busy(struct isp_h3a_device *isp_h3a);
+
+void isph3a_aewb_suspend(struct isp_h3a_device *isp_h3a);
+
+void isph3a_aewb_resume(struct isp_h3a_device *isp_h3a);
+
+void isph3a_update_wb(struct isp_h3a_device *isp_h3a);
+
+int isph3a_aewb_buf_process(struct isp_h3a_device *isp_h3a);
+
+void isph3a_aewb_config_registers(struct isp_h3a_device *isp_h3a);
+
#endif /* OMAP_ISP_H3A_H */
diff --git a/drivers/media/video/isp/isphist.c b/drivers/media/video/isp/isphist.c
index c6f6a77..2f89ca3 100644
--- a/drivers/media/video/isp/isphist.c
+++ b/drivers/media/video/isp/isphist.c
@@ -6,6 +6,7 @@
* Copyright (C) 2009 Texas Instruments, Inc.
*
* Contributors:
+ * David Cohen <david.cohen@nokia.com>
* Sergio Aguirre <saaguirre@ti.com>
* Troy Laramy
*
@@ -18,87 +19,15 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#include <asm/cacheflush.h>
-
#include <linux/delay.h>
-#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
+#include <linux/device.h>
#include "isp.h"
#include "ispreg.h"
#include "isphist.h"
-#include "ispmmu.h"
-/**
- * struct isp_hist_status - Histogram status.
- * @hist_enable: Enables the histogram module.
- * @initialized: Flag to indicate that the module is correctly initializated.
- * @frame_cnt: Actual frame count.
- * @frame_req: Frame requested by user.
- * @completed: Flag to indicate if a frame request is completed.
- */
-struct isp_hist_status {
- u8 hist_enable;
- u8 pm_state;
- u8 initialized;
- u8 frame_cnt;
- u8 frame_req;
- u8 completed;
-} histstat;
-
-/**
- * struct isp_hist_buffer - Frame histogram buffer.
- * @virt_addr: Virtual address to mmap the buffer.
- * @phy_addr: Physical address of the buffer.
- * @addr_align: Virtual Address 32 bytes aligned.
- * @ispmmu_addr: Address of the buffer mapped by the ISPMMU.
- * @mmap_addr: Mapped memory area of buffer. For userspace access.
- */
-struct isp_hist_buffer {
- unsigned long virt_addr;
- unsigned long phy_addr;
- unsigned long addr_align;
- unsigned long ispmmu_addr;
- unsigned long mmap_addr;
-} hist_buff;
-
-/**
- * struct isp_hist_regs - Current value of Histogram configuration registers.
- * @reg_pcr: Peripheral control register.
- * @reg_cnt: Histogram control register.
- * @reg_wb_gain: Histogram white balance gain register.
- * @reg_r0_h: Region 0 horizontal register.
- * @reg_r0_v: Region 0 vertical register.
- * @reg_r1_h: Region 1 horizontal register.
- * @reg_r1_v: Region 1 vertical register.
- * @reg_r2_h: Region 2 horizontal register.
- * @reg_r2_v: Region 2 vertical register.
- * @reg_r3_h: Region 3 horizontal register.
- * @reg_r3_v: Region 3 vertical register.
- * @reg_hist_addr: Histogram address register.
- * @reg_hist_data: Histogram data.
- * @reg_hist_radd: Address register. When input data comes from mem.
- * @reg_hist_radd_off: Address offset register. When input data comes from mem.
- * @reg_h_v_info: Image size register. When input data comes from mem.
- */
-static struct isp_hist_regs {
- u32 reg_pcr;
- u32 reg_cnt;
- u32 reg_wb_gain;
- u32 reg_r0_h;
- u32 reg_r0_v;
- u32 reg_r1_h;
- u32 reg_r1_v;
- u32 reg_r2_h;
- u32 reg_r2_v;
- u32 reg_r3_h;
- u32 reg_r3_v;
- u32 reg_hist_addr;
- u32 reg_hist_data;
- u32 reg_hist_radd;
- u32 reg_hist_radd_off;
- u32 reg_h_v_info;
-} hist_regs;
+#define HIST_USE_DMA 1
/* Structure for saving/restoring histogram module registers */
struct isp_reg isphist_reg_list[] = {
@@ -119,18 +48,22 @@
{0, ISP_TOK_TERM, 0}
};
-static void isp_hist_print_status(void);
+static void isp_hist_print_status(struct isp_hist_device *isp_hist);
-void __isp_hist_enable(u8 enable)
+static void __isp_hist_enable(struct isp_hist_device *isp_hist, u8 enable)
{
- if (enable)
- DPRINTK_ISPHIST(" histogram enabled \n");
- else
- DPRINTK_ISPHIST(" histogram disabled \n");
+ struct device *dev = to_device(isp_hist);
+ unsigned int pcr;
- isp_reg_and_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, ~ISPHIST_PCR_EN,
- (enable ? ISPHIST_PCR_EN : 0));
- histstat.hist_enable = enable;
+ pcr = isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR);
+
+ /* Set AF_EN bit in PCR Register */
+ if (enable)
+ pcr |= ISPHIST_PCR_EN;
+ else
+ pcr &= ~ISPHIST_PCR_EN;
+
+ isp_reg_writel(dev, pcr, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR);
}
/**
@@ -140,314 +73,493 @@
* Client should configure all the Histogram registers before calling this
* function.
**/
-void isp_hist_enable(u8 enable)
+void isp_hist_enable(struct isp_hist_device *isp_hist, u8 enable)
{
- __isp_hist_enable(enable);
- histstat.pm_state = enable;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&isp_hist->lock, irqflags);
+
+ if (!isp_hist->config.enable) {
+ spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+ return;
+ }
+
+ __isp_hist_enable(isp_hist, enable);
+ isp_hist->enabled = enable;
+
+ spin_unlock_irqrestore(&isp_hist->lock, irqflags);
}
/**
* isp_hist_suspend - Suspend ISP Histogram submodule.
**/
-void isp_hist_suspend(void)
+void isp_hist_suspend(struct isp_hist_device *isp_hist)
{
- if (histstat.pm_state)
- __isp_hist_enable(0);
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&isp_hist->lock, irqflags);
+ if (isp_hist->enabled)
+ __isp_hist_enable(isp_hist, 0);
+ spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+}
+
+void isp_hist_try_enable(struct isp_hist_device *isp_hist)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&isp_hist->lock, irqflags);
+ if (unlikely(!isp_hist->enabled && isp_hist->config.enable &&
+ !isp_hist->waiting_dma)) {
+ isp_hist->update = 1;
+ isp_hist->active_buf = ispstat_buf_next(&isp_hist->stat);
+ spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+ isp_hist_config_registers(isp_hist);
+ isp_hist_enable(isp_hist, 1);
+ } else
+ spin_unlock_irqrestore(&isp_hist->lock, irqflags);
}
/**
* isp_hist_resume - Resume ISP Histogram submodule.
**/
-void isp_hist_resume(void)
+void isp_hist_resume(struct isp_hist_device *isp_hist)
{
- if (histstat.pm_state)
- __isp_hist_enable(1);
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&isp_hist->lock, irqflags);
+ if (isp_hist->enabled)
+ __isp_hist_enable(isp_hist, 1);
+ spin_unlock_irqrestore(&isp_hist->lock, irqflags);
}
-int isp_hist_busy(void)
+int isp_hist_busy(struct isp_hist_device *isp_hist)
{
- return isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR) &
- ISPHIST_PCR_BUSY;
-}
+ struct device *dev = to_device(isp_hist);
-
-/**
- * isp_hist_update_regs - Helper function to update Histogram registers.
- **/
-static void isp_hist_update_regs(void)
-{
- isp_reg_writel(hist_regs.reg_pcr, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR);
- isp_reg_writel(hist_regs.reg_cnt, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT);
- isp_reg_writel(hist_regs.reg_wb_gain, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_WB_GAIN);
- isp_reg_writel(hist_regs.reg_r0_h, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_R0_HORZ);
- isp_reg_writel(hist_regs.reg_r0_v, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_R0_VERT);
- isp_reg_writel(hist_regs.reg_r1_h, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_R1_HORZ);
- isp_reg_writel(hist_regs.reg_r1_v, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_R1_VERT);
- isp_reg_writel(hist_regs.reg_r2_h, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_R2_HORZ);
- isp_reg_writel(hist_regs.reg_r2_v, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_R2_VERT);
- isp_reg_writel(hist_regs.reg_r3_h, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_R3_HORZ);
- isp_reg_writel(hist_regs.reg_r3_v, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_R3_VERT);
- isp_reg_writel(hist_regs.reg_hist_addr, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_ADDR);
- isp_reg_writel(hist_regs.reg_hist_data, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_DATA);
- isp_reg_writel(hist_regs.reg_hist_radd, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_RADD);
- isp_reg_writel(hist_regs.reg_hist_radd_off, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_RADD_OFF);
- isp_reg_writel(hist_regs.reg_h_v_info, OMAP3_ISP_IOMEM_HIST,
- ISPHIST_H_V_INFO);
-}
-
-/**
- * isp_hist_isr - Callback from ISP driver for HIST interrupt.
- * @status: IRQ0STATUS in case of MMU error, 0 for hist interrupt.
- * arg1 and arg2 Not used as of now.
- **/
-static void isp_hist_isr(unsigned long status, isp_vbq_callback_ptr arg1,
- void *arg2)
-{
- isp_hist_enable(0);
-
- if (!(status & HIST_DONE))
- return;
-
- if (!histstat.completed) {
- if (histstat.frame_req == histstat.frame_cnt) {
- histstat.frame_cnt = 0;
- histstat.frame_req = 0;
- histstat.completed = 1;
- } else {
- isp_hist_enable(1);
- histstat.frame_cnt++;
- }
- }
+ return isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR)
+ & ISPHIST_PCR_BUSY;
}
/**
* isp_hist_reset_mem - clear Histogram memory before start stats engine.
- *
- * Returns 0 after histogram memory was cleared.
**/
-static int isp_hist_reset_mem(void)
+static void isp_hist_reset_mem(struct isp_hist_device *isp_hist)
{
- int i;
+ struct device *dev = to_device(isp_hist);
+ unsigned int i;
- isp_reg_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLR_EN);
+ isp_reg_writel(dev, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
- for (i = 0; i < HIST_MEM_SIZE; i++)
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ /*
+ * By setting it, the histogram internal buffer is being cleared at the
+ * same time it's being read. This bit must be cleared afterwards.
+ */
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLR_EN);
- isp_reg_and(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ~ISPHIST_CNT_CLR_EN);
+ /*
+ * We'll clear 4 words at each iteration for optimization. It avoids
+ * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4.
+ */
+ for (i = HIST_MEM_SIZE / 4; i > 0; i--) {
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ }
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+ ~ISPHIST_CNT_CLR_EN);
+}
+
+static void isp_hist_dma_config(struct isp_hist_device *isp_hist)
+{
+ struct omap_dma_channel_params *dma_config = &isp_hist->dma_config;
+
+ dma_config->data_type = OMAP_DMA_DATA_TYPE_S32;
+ dma_config->sync_mode = OMAP_DMA_SYNC_ELEMENT;
+ dma_config->elem_count = (isp_hist->buf_size / sizeof(u32));
+ dma_config->frame_count = 1;
+ dma_config->src_amode = OMAP_DMA_AMODE_CONSTANT;
+ dma_config->src_start = OMAP3ISP_HIST_REG_BASE + ISPHIST_DATA;
+ dma_config->dst_amode = OMAP_DMA_AMODE_POST_INC;
+ dma_config->src_or_dst_synch = OMAP_DMA_SRC_SYNC;
+}
+
+/**
+ * isp_hist_set_regs - Helper function to update Histogram registers.
+ **/
+void isp_hist_config_registers(struct isp_hist_device *isp_hist)
+{
+ struct device *dev = to_device(isp_hist);
+ unsigned long irqflags;
+
+ if (!isp_hist->update || !isp_hist->config.enable)
+ return;
+
+ spin_lock_irqsave(&isp_hist->lock, irqflags);
+ isp_hist->num_acc_frames = isp_hist->config.num_acc_frames;
+ isp_hist_reset_mem(isp_hist);
+
+ isp_reg_writel(dev, isp_hist->regs.cnt, OMAP3_ISP_IOMEM_HIST,
+ ISPHIST_CNT);
+ isp_reg_writel(dev, isp_hist->regs.wb_gain,
+ OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN);
+ isp_reg_writel(dev, isp_hist->regs.reg_hor[0], OMAP3_ISP_IOMEM_HIST,
+ ISPHIST_R0_HORZ);
+ isp_reg_writel(dev, isp_hist->regs.reg_ver[0], OMAP3_ISP_IOMEM_HIST,
+ ISPHIST_R0_VERT);
+ isp_reg_writel(dev, isp_hist->regs.reg_hor[1], OMAP3_ISP_IOMEM_HIST,
+ ISPHIST_R1_HORZ);
+ isp_reg_writel(dev, isp_hist->regs.reg_ver[1], OMAP3_ISP_IOMEM_HIST,
+ ISPHIST_R1_VERT);
+ isp_reg_writel(dev, isp_hist->regs.reg_hor[2], OMAP3_ISP_IOMEM_HIST,
+ ISPHIST_R2_HORZ);
+ isp_reg_writel(dev, isp_hist->regs.reg_ver[2], OMAP3_ISP_IOMEM_HIST,
+ ISPHIST_R2_VERT);
+ isp_reg_writel(dev, isp_hist->regs.reg_hor[3], OMAP3_ISP_IOMEM_HIST,
+ ISPHIST_R3_HORZ);
+ isp_reg_writel(dev, isp_hist->regs.reg_ver[3], OMAP3_ISP_IOMEM_HIST,
+ ISPHIST_R3_VERT);
+ isp_reg_writel(dev, isp_hist->regs.hist_radd,
+ OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD);
+ isp_reg_writel(dev, isp_hist->regs.hist_radd_off,
+ OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD_OFF);
+ isp_reg_writel(dev, isp_hist->regs.h_v_info,
+ OMAP3_ISP_IOMEM_HIST, ISPHIST_H_V_INFO);
+
+ isp_hist_dma_config(isp_hist);
+
+ isp_hist->update = 0;
+ spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+
+ isp_hist_print_status(isp_hist);
+}
+
+static void isp_hist_dma_cb(int lch, u16 ch_status, void *data)
+{
+ struct isp_hist_device *isp_hist = data;
+ struct device *dev = to_device(isp_hist);
+
+ if (ch_status & ~OMAP_DMA_BLOCK_IRQ) {
+ dev_dbg(dev, "hist: DMA error. status = %02x\n", ch_status);
+ omap_stop_dma(lch);
+ isp_hist_reset_mem(isp_hist);
+ } else {
+ int ret;
+
+ ret = ispstat_buf_queue(&isp_hist->stat);
+ isp_hist->active_buf = ispstat_buf_next(&isp_hist->stat);
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+ ~ISPHIST_CNT_CLR_EN);
+ if (!ret)
+ isp_hist_dma_done(dev);
+ }
+ isp_hist->waiting_dma = 0;
+}
+
+static int isp_hist_buf_dma(struct isp_hist_device *isp_hist)
+{
+ struct device *dev = to_device(isp_hist);
+ dma_addr_t dma_addr = isp_hist->active_buf->dma_addr;
+
+ if (!dma_addr) {
+ dev_dbg(dev, "hist: invalid DMA buffer address\n");
+ isp_hist_reset_mem(isp_hist);
+ return HIST_NO_BUF;
+ }
+
+ isp_hist->waiting_dma = 1;
+ isp_reg_writel(dev, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+ ISPHIST_CNT_CLR_EN);
+ isp_flush(dev);
+ isp_hist->dma_config.dst_start = dma_addr;
+ omap_set_dma_params(isp_hist->dma_ch, &isp_hist->dma_config);
+ omap_start_dma(isp_hist->dma_ch);
+
+ return HIST_BUF_WAITING_DMA;
+}
+
+static int isp_hist_buf_pio(struct isp_hist_device *isp_hist)
+{
+ struct device *dev = to_device(isp_hist);
+ u32 *buf = isp_hist->active_buf->virt_addr;
+ unsigned int i;
+ int ret;
+
+ if (!buf) {
+ dev_dbg(dev, "hist: invalid PIO buffer address\n");
+ isp_hist_reset_mem(isp_hist);
+ return HIST_NO_BUF;
+ }
+
+ isp_reg_writel(dev, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+
+ /*
+ * By setting it, the histogram internal buffer is being cleared at the
+ * same time it's being read. This bit must be cleared just after all
+ * data is acquired.
+ */
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+ ISPHIST_CNT_CLR_EN);
+
+ /*
+ * We'll read 4 times a 4-bytes-word at each iteration for
+ * optimization. It avoids 3/4 of the jumps. We also know buf_size is
+ * divisible by 16.
+ */
+ for (i = isp_hist->buf_size / 16; i > 0; i--) {
+ *buf++ = isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ *buf++ = isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ *buf++ = isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ *buf++ = isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+ }
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+ ~ISPHIST_CNT_CLR_EN);
+
+ ret = ispstat_buf_queue(&isp_hist->stat);
+ isp_hist->active_buf = ispstat_buf_next(&isp_hist->stat);
+
+ if (ret)
+ return HIST_NO_BUF;
+ else
+ return HIST_BUF_DONE;
+}
+
+/**
+ * isp_hist_isr - Callback from ISP driver for HIST interrupt.
+ **/
+int isp_hist_buf_process(struct isp_hist_device *isp_hist)
+{
+ unsigned long irqflags;
+ int ret = HIST_NO_BUF;
+
+ spin_lock_irqsave(&isp_hist->lock, irqflags);
+
+ if (isp_hist->invalid_buf || !isp_hist->config.enable) {
+ isp_hist->invalid_buf = 0;
+ isp_hist_reset_mem(isp_hist);
+ goto out_invalid;
+ }
+
+ if (--(isp_hist->num_acc_frames))
+ goto out_acc;
+
+ if (isp_hist->use_dma)
+ ret = isp_hist_buf_dma(isp_hist);
+ else
+ ret = isp_hist_buf_pio(isp_hist);
+
+out_invalid:
+ isp_hist->num_acc_frames = isp_hist->config.num_acc_frames;
+out_acc:
+ spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+
+ return ret;
+}
+
+void isp_hist_mark_invalid_buf(struct isp_hist_device *isp_hist)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&isp_hist->lock, irqflags);
+ isp_hist->invalid_buf = 1;
+ spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+}
+
+/**
+ * isp_hist_validate_params - Helper function to check user given params.
+ * @user_cfg: Pointer to user configuration structure.
+ *
+ * Returns 0 on success configuration.
+ **/
+static int isp_hist_validate_params(struct isp_hist_config *user_cfg)
+{
+ int c;
+
+ if (user_cfg->source > HIST_SOURCE_MEM)
+ return -EINVAL;
+
+ if (user_cfg->source == HIST_SOURCE_MEM) {
+ if ((user_cfg->input_bit_width < HIST_MIN_BIT_WIDTH) ||
+ (user_cfg->input_bit_width > HIST_MAX_BIT_WIDTH))
+ return -EINVAL;
+
+ /* Should be in 32 byte boundary if source is mem */
+ if ((user_cfg->hist_radd & ~ISP_32B_BOUNDARY_BUF) ||
+ (user_cfg->hist_radd_off & ~ISP_32B_BOUNDARY_OFFSET))
+ return -EINVAL;
+ } else if (user_cfg->input_bit_width != 10) /* CCDC must be 10bits */
+ return -EINVAL;
+
+ if (user_cfg->cfa > HIST_CFA_FOVEONX3)
+ return -EINVAL;
+
+ /* Regions size and position */
+
+ if ((user_cfg->num_regions < HIST_MIN_REGIONS) ||
+ (user_cfg->num_regions > HIST_MAX_REGIONS))
+ return -EINVAL;
+
+ /* Regions */
+ for (c = 0; c < user_cfg->num_regions; c++) {
+ if (user_cfg->reg_hor[c] & ~ISPHIST_REGHORIZ_HEND_MASK &
+ ~ISPHIST_REGHORIZ_HSTART_MASK)
+ return -EINVAL;
+ if ((user_cfg->reg_hor[c] & ISPHIST_REGHORIZ_HEND_MASK) <=
+ ((user_cfg->reg_hor[c] & ISPHIST_REGHORIZ_HSTART_MASK) >>
+ ISPHIST_REGHORIZ_HSTART_SHIFT))
+ return -EINVAL;
+ if (user_cfg->reg_ver[c] & ~ISPHIST_REGVERT_VEND_MASK &
+ ~ISPHIST_REGVERT_VSTART_MASK)
+ return -EINVAL;
+ if ((user_cfg->reg_ver[c] & ISPHIST_REGVERT_VEND_MASK) <=
+ ((user_cfg->reg_ver[c] & ISPHIST_REGVERT_VSTART_MASK) >>
+ ISPHIST_REGVERT_VSTART_SHIFT))
+ return -EINVAL;
+ }
+
+ switch (user_cfg->num_regions) {
+ case 1:
+ if (user_cfg->hist_bins > HIST_BINS_256)
+ return -EINVAL;
+ break;
+ case 2:
+ if (user_cfg->hist_bins > HIST_BINS_128)
+ return -EINVAL;
+ break;
+ default: /* 3 or 4 */
+ if (user_cfg->hist_bins > HIST_BINS_64)
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+static int isp_hist_comp_params(struct isp_hist_device *isp_hist,
+ struct isp_hist_config *user_cfg)
+{
+ struct isp_hist_config *cur_cfg = &isp_hist->config;
+ int c;
+
+ if ((cur_cfg->source && !user_cfg->source) ||
+ (!cur_cfg->source && user_cfg->source))
+ return 1;
+
+ if (cur_cfg->input_bit_width != user_cfg->input_bit_width)
+ return 1;
+
+ if (user_cfg->source) {
+ if (cur_cfg->hist_h_v_info != user_cfg->hist_h_v_info)
+ return 1;
+ if (cur_cfg->hist_radd != user_cfg->hist_radd)
+ return 1;
+ if (cur_cfg->hist_radd_off != user_cfg->hist_radd_off)
+ return 1;
+ }
+
+ if (cur_cfg->cfa != user_cfg->cfa)
+ return 1;
+
+ if (cur_cfg->num_acc_frames != user_cfg->num_acc_frames)
+ return 1;
+
+ if (cur_cfg->hist_bins != user_cfg->hist_bins)
+ return 1;
+
+ for (c = 0; c < HIST_MAX_WG; c++) {
+ if (c == 3 && user_cfg->cfa == HIST_CFA_FOVEONX3)
+ break;
+ else if (cur_cfg->wg[c] != user_cfg->wg[c])
+ return 1;
+ }
+
+ if (cur_cfg->num_regions != user_cfg->num_regions)
+ return 1;
+
+ /* Regions */
+ for (c = 0; c < user_cfg->num_regions; c++) {
+ if (cur_cfg->reg_hor[c] != user_cfg->reg_hor[c])
+ return 1;
+ if (cur_cfg->reg_ver[c] != user_cfg->reg_ver[c])
+ return 1;
+ }
return 0;
}
/**
- * isp_hist_set_params - Helper function to check and store user given params.
+ * isp_hist_update_params - Helper function to check and store user given params.
* @user_cfg: Pointer to user configuration structure.
*
* Returns 0 on success configuration.
**/
-static int isp_hist_set_params(struct isp_hist_config *user_cfg)
+static void isp_hist_update_params(struct isp_hist_device *isp_hist,
+ struct isp_hist_config *user_cfg)
{
+ int bit_shift;
+ int c;
- int reg_num = 0;
- int bit_shift = 0;
+ if (!isp_hist_comp_params(isp_hist, user_cfg)) {
+ isp_hist->config.enable = user_cfg->enable;
+ return;
+ }
+ memcpy(&isp_hist->config, user_cfg, sizeof(*user_cfg));
- if (isp_hist_busy())
- return -EINVAL;
-
- if (user_cfg->input_bit_width > MIN_BIT_WIDTH)
- WRITE_DATA_SIZE(hist_regs.reg_cnt, 0);
+ if (user_cfg->input_bit_width > HIST_MIN_BIT_WIDTH)
+ WRITE_DATA_SIZE(isp_hist->regs.cnt, 0);
else
- WRITE_DATA_SIZE(hist_regs.reg_cnt, 1);
+ WRITE_DATA_SIZE(isp_hist->regs.cnt, 1);
- WRITE_SOURCE(hist_regs.reg_cnt, user_cfg->hist_source);
+ WRITE_SOURCE(isp_hist->regs.cnt, user_cfg->source);
- if (user_cfg->hist_source) {
- WRITE_HV_INFO(hist_regs.reg_h_v_info, user_cfg->hist_h_v_info);
-
- if ((user_cfg->hist_radd & ISP_32B_BOUNDARY_BUF) ==
- user_cfg->hist_radd) {
- WRITE_RADD(hist_regs.reg_hist_radd,
- user_cfg->hist_radd);
- } else {
- printk(KERN_ERR "Address should be in 32 byte boundary"
- "\n");
- return -EINVAL;
- }
-
- if ((user_cfg->hist_radd_off & ISP_32B_BOUNDARY_OFFSET) ==
- user_cfg->hist_radd_off) {
- WRITE_RADD_OFF(hist_regs.reg_hist_radd_off,
- user_cfg->hist_radd_off);
- } else {
- printk(KERN_ERR "Offset should be in 32 byte boundary"
- "\n");
- return -EINVAL;
- }
-
+ if (user_cfg->source == HIST_SOURCE_MEM) {
+ WRITE_HV_INFO(isp_hist->regs.h_v_info, user_cfg->hist_h_v_info);
+ WRITE_RADD(isp_hist->regs.hist_radd, user_cfg->hist_radd);
+ WRITE_RADD_OFF(isp_hist->regs.hist_radd_off,
+ user_cfg->hist_radd_off);
}
- isp_hist_reset_mem();
- DPRINTK_ISPHIST("ISPHIST: Memory Cleared\n");
- histstat.frame_req = user_cfg->hist_frames;
+ WRITE_CFA(isp_hist->regs.cnt, user_cfg->cfa);
- if (unlikely(user_cfg->wb_gain_R > MAX_WB_GAIN ||
- user_cfg->wb_gain_RG > MAX_WB_GAIN ||
- user_cfg->wb_gain_B > MAX_WB_GAIN ||
- user_cfg->wb_gain_BG > MAX_WB_GAIN)) {
- printk(KERN_ERR "Invalid WB gain\n");
- return -EINVAL;
- } else {
- WRITE_WB_R(hist_regs.reg_wb_gain, user_cfg->wb_gain_R);
- WRITE_WB_RG(hist_regs.reg_wb_gain, user_cfg->wb_gain_RG);
- WRITE_WB_B(hist_regs.reg_wb_gain, user_cfg->wb_gain_B);
- WRITE_WB_BG(hist_regs.reg_wb_gain, user_cfg->wb_gain_BG);
- }
+ WRITE_WG0(isp_hist->regs.wb_gain, user_cfg->wg[0]);
+ WRITE_WG1(isp_hist->regs.wb_gain, user_cfg->wg[1]);
+ WRITE_WG2(isp_hist->regs.wb_gain, user_cfg->wg[2]);
+ if (user_cfg->cfa == HIST_CFA_BAYER)
+ WRITE_WG3(isp_hist->regs.wb_gain, user_cfg->wg[3]);
/* Regions size and position */
-
- if (user_cfg->num_regions > MAX_REGIONS)
- return -EINVAL;
-
- if (likely((user_cfg->reg0_hor & ISPHIST_REGHORIZ_HEND_MASK) -
- ((user_cfg->reg0_hor & ISPHIST_REGHORIZ_HSTART_MASK) >>
- ISPHIST_REGHORIZ_HSTART_SHIFT))) {
- WRITE_REG_HORIZ(hist_regs.reg_r0_h, user_cfg->reg0_hor);
- reg_num++;
- } else {
- printk(KERN_ERR "Invalid Region parameters\n");
- return -EINVAL;
- }
-
- if (likely((user_cfg->reg0_ver & ISPHIST_REGVERT_VEND_MASK) -
- ((user_cfg->reg0_ver & ISPHIST_REGVERT_VSTART_MASK) >>
- ISPHIST_REGVERT_VSTART_SHIFT))) {
- WRITE_REG_VERT(hist_regs.reg_r0_v, user_cfg->reg0_ver);
- } else {
- printk(KERN_ERR "Invalid Region parameters\n");
- return -EINVAL;
- }
-
- if (user_cfg->num_regions >= 1) {
- if (likely((user_cfg->reg1_hor & ISPHIST_REGHORIZ_HEND_MASK) -
- ((user_cfg->reg1_hor &
- ISPHIST_REGHORIZ_HSTART_MASK) >>
- ISPHIST_REGHORIZ_HSTART_SHIFT))) {
- WRITE_REG_HORIZ(hist_regs.reg_r1_h, user_cfg->reg1_hor);
+ for (c = 0; c < HIST_MAX_REGIONS; c++) {
+ if (c < user_cfg->num_regions) {
+ WRITE_REG_HORIZ(isp_hist->regs.reg_hor[c],
+ user_cfg->reg_hor[c]);
+ WRITE_REG_VERT(isp_hist->regs.reg_ver[c],
+ user_cfg->reg_ver[c]);
} else {
- printk(KERN_ERR "Invalid Region parameters\n");
- return -EINVAL;
- }
-
- if (likely((user_cfg->reg1_ver & ISPHIST_REGVERT_VEND_MASK) -
- ((user_cfg->reg1_ver &
- ISPHIST_REGVERT_VSTART_MASK) >>
- ISPHIST_REGVERT_VSTART_SHIFT))) {
- WRITE_REG_VERT(hist_regs.reg_r1_v, user_cfg->reg1_ver);
- } else {
- printk(KERN_ERR "Invalid Region parameters\n");
- return -EINVAL;
+ isp_hist->regs.reg_hor[c] = 0;
+ isp_hist->regs.reg_ver[c] = 0;
}
}
- if (user_cfg->num_regions >= 2) {
- if (likely((user_cfg->reg2_hor & ISPHIST_REGHORIZ_HEND_MASK) -
- ((user_cfg->reg2_hor &
- ISPHIST_REGHORIZ_HSTART_MASK) >>
- ISPHIST_REGHORIZ_HSTART_SHIFT))) {
- WRITE_REG_HORIZ(hist_regs.reg_r2_h, user_cfg->reg2_hor);
- } else {
- printk(KERN_ERR "Invalid Region parameters\n");
- return -EINVAL;
- }
-
- if (likely((user_cfg->reg2_ver & ISPHIST_REGVERT_VEND_MASK) -
- ((user_cfg->reg2_ver &
- ISPHIST_REGVERT_VSTART_MASK) >>
- ISPHIST_REGVERT_VSTART_SHIFT))) {
- WRITE_REG_VERT(hist_regs.reg_r2_v, user_cfg->reg2_ver);
- } else {
- printk(KERN_ERR "Invalid Region parameters\n");
- return -EINVAL;
- }
+ WRITE_NUM_BINS(isp_hist->regs.cnt, user_cfg->hist_bins);
+ switch (user_cfg->hist_bins) {
+ case HIST_BINS_256:
+ bit_shift = user_cfg->input_bit_width - 8;
+ break;
+ case HIST_BINS_128:
+ bit_shift = user_cfg->input_bit_width - 7;
+ break;
+ case HIST_BINS_64:
+ bit_shift = user_cfg->input_bit_width - 6;
+ break;
+ default: /* HIST_BINS_32 */
+ bit_shift = user_cfg->input_bit_width - 5;
+ break;
}
+ WRITE_BIT_SHIFT(isp_hist->regs.cnt, bit_shift);
- if (user_cfg->num_regions >= 3) {
- if (likely((user_cfg->reg3_hor & ISPHIST_REGHORIZ_HEND_MASK) -
- ((user_cfg->reg3_hor &
- ISPHIST_REGHORIZ_HSTART_MASK) >>
- ISPHIST_REGHORIZ_HSTART_SHIFT))) {
- WRITE_REG_HORIZ(hist_regs.reg_r3_h, user_cfg->reg3_hor);
- } else {
- printk(KERN_ERR "Invalid Region parameters\n");
- return -EINVAL;
- }
-
- if (likely((user_cfg->reg3_ver & ISPHIST_REGVERT_VEND_MASK) -
- ((user_cfg->reg3_ver &
- ISPHIST_REGVERT_VSTART_MASK) >>
- ISPHIST_REGVERT_VSTART_SHIFT))) {
- WRITE_REG_VERT(hist_regs.reg_r3_v, user_cfg->reg3_ver);
- } else {
- printk(KERN_ERR "Invalid Region parameters\n");
- return -EINVAL;
- }
- }
- reg_num = user_cfg->num_regions;
- if (unlikely(((user_cfg->hist_bins > BINS_256) &&
- (user_cfg->hist_bins != BINS_32)) ||
- ((user_cfg->hist_bins == BINS_256) &&
- reg_num != 0) || ((user_cfg->hist_bins ==
- BINS_128) && reg_num >= 2))) {
- printk(KERN_ERR "Invalid Bins Number: %d\n",
- user_cfg->hist_bins);
- return -EINVAL;
- } else {
- WRITE_NUM_BINS(hist_regs.reg_cnt, user_cfg->hist_bins);
- }
-
- if (user_cfg->input_bit_width > MAX_BIT_WIDTH ||
- user_cfg->input_bit_width < MIN_BIT_WIDTH) {
- printk(KERN_ERR "Invalid Bit Width: %d\n",
- user_cfg->input_bit_width);
- return -EINVAL;
- } else {
- switch (user_cfg->hist_bins) {
- case BINS_256:
- bit_shift = user_cfg->input_bit_width - 8;
- break;
- case BINS_128:
- bit_shift = user_cfg->input_bit_width - 7;
- break;
- case BINS_64:
- bit_shift = user_cfg->input_bit_width - 6;
- break;
- case BINS_32:
- bit_shift = user_cfg->input_bit_width - 5;
- break;
- default:
- return -EINVAL;
- }
- WRITE_BIT_SHIFT(hist_regs.reg_cnt, bit_shift);
- }
-
- isp_hist_update_regs();
- histstat.initialized = 1;
-
- return 0;
+ isp_hist->update = 1;
}
/**
@@ -456,40 +568,68 @@
*
* Returns 0 on success configuration.
**/
-int isp_hist_configure(struct isp_hist_config *histcfg)
+int isp_hist_config(struct isp_hist_device *isp_hist,
+ struct isp_hist_config *histcfg)
{
-
+ struct device *dev = to_device(isp_hist);
+ unsigned long irqflags;
int ret = 0;
+ unsigned int size;
+ int use_dma = HIST_USE_DMA;
+ const unsigned int size_bins[] =
+ { HIST_MEM_SIZE_BINS(32), HIST_MEM_SIZE_BINS(64),
+ HIST_MEM_SIZE_BINS(128), HIST_MEM_SIZE_BINS(256) };
- if (NULL == histcfg) {
- printk(KERN_ERR "Null argument in configuration. \n");
+ if (!histcfg) {
+ dev_dbg(dev, "hist: Null argument in configuration.\n");
return -EINVAL;
}
- if (!histstat.initialized) {
- DPRINTK_ISPHIST("Setting callback for HISTOGRAM\n");
- ret = isp_set_callback(CBK_HIST_DONE, isp_hist_isr,
- (void *)NULL, (void *)NULL);
- if (ret) {
- printk(KERN_ERR "No callback for HIST\n");
- return ret;
- }
- }
-
- ret = isp_hist_set_params(histcfg);
+ /* Check Parameters */
+ ret = isp_hist_validate_params(histcfg);
if (ret) {
- printk(KERN_ERR "Invalid parameters! \n");
+ dev_dbg(dev, "hist: wrong configure params received.\n");
return ret;
}
- histstat.frame_cnt = 0;
- histstat.completed = 0;
- isp_hist_enable(1);
- isp_hist_print_status();
+ size = size_bins[histcfg->hist_bins] * histcfg->num_regions;
+
+ /* Cannot use DMA if no channel is available */
+ if (unlikely(HIST_USE_DMA && (isp_hist->dma_ch < 0)))
+ use_dma = 0;
+
+ /* Alloc buffers */
+ spin_lock_irqsave(&isp_hist->lock, irqflags);
+ if (isp_hist->waiting_dma) {
+ omap_stop_dma(isp_hist->dma_ch);
+ isp_hist->waiting_dma = 0;
+ }
+ spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+
+ ret = ispstat_bufs_alloc(&isp_hist->stat, size, use_dma);
+ if (ret) {
+ if (use_dma)
+ ret = ispstat_bufs_alloc(&isp_hist->stat, size, 0);
+
+ if (ret) {
+ dev_err(dev, "hist: unable to alloc buffers.\n");
+ isp_hist->config.enable = 0;
+ return ret;
+ } else {
+ use_dma = 0;
+ dev_dbg(dev, "hist: unable to alloc buffers for DMA. "
+ "PIO will be used.\n");
+ }
+ }
+
+ spin_lock_irqsave(&isp_hist->lock, irqflags);
+ isp_hist->buf_size = size;
+ isp_hist->use_dma = use_dma;
+ isp_hist_update_params(isp_hist, histcfg);
+ spin_unlock_irqrestore(&isp_hist->lock, irqflags);
return 0;
}
-EXPORT_SYMBOL(isp_hist_configure);
/**
* isp_hist_request_statistics - Request statistics in Histogram.
@@ -499,110 +639,135 @@
*
* Returns 0 on successful request.
**/
-int isp_hist_request_statistics(struct isp_hist_data *histdata)
+int isp_hist_request_statistics(struct isp_hist_device *isp_hist,
+ struct isp_hist_data *histdata)
{
- int i, ret;
- u32 curr;
+ struct device *dev = to_device(isp_hist);
+ struct ispstat_buffer *buf;
- if (isp_hist_busy())
- return -EBUSY;
-
- if (!histstat.completed && histstat.initialized)
+ if (!isp_hist->config.enable) {
+ dev_dbg(dev, "hist: statistics requested while engine is not "
+ "configured\n");
return -EINVAL;
-
- isp_reg_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLR_EN);
-
- for (i = 0; i < HIST_MEM_SIZE; i++) {
- curr = isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
- ret = put_user(curr, histdata->hist_statistics_buf + i);
- if (ret) {
- printk(KERN_ERR "Failed copy_to_user for "
- "HIST stats buff, %d\n", ret);
- }
}
- isp_reg_and(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
- ~ISPHIST_CNT_CLR_EN);
- histstat.completed = 0;
+ if (histdata->update & REQUEST_STATISTICS) {
+ buf = ispstat_buf_get(&isp_hist->stat,
+ (void *)histdata->hist_statistics_buf,
+ histdata->frame_number);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ histdata->ts = buf->ts;
+ histdata->config_counter = buf->config_counter;
+ histdata->frame_number = buf->frame_number;
+
+ ispstat_buf_release(&isp_hist->stat);
+ }
+
+ histdata->curr_frame = isp_hist->stat.frame_number;
+
return 0;
}
-EXPORT_SYMBOL(isp_hist_request_statistics);
/**
* isp_hist_init - Module Initialization.
*
* Returns 0 if successful.
**/
-int __init isp_hist_init(void)
+int __init isp_hist_init(struct device *dev)
{
- memset(&histstat, 0, sizeof(histstat));
- memset(&hist_regs, 0, sizeof(hist_regs));
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_hist_device *isp_hist = &isp->isp_hist;
+ int ret = -1;
- return 0;
+ if (HIST_USE_DMA)
+ ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST",
+ isp_hist_dma_cb, isp_hist,
+ &isp_hist->dma_ch);
+ if (ret) {
+ if (HIST_USE_DMA)
+ dev_info(dev, "hist: DMA request channel failed. Using "
+ "PIO only.\n");
+ isp_hist->dma_ch = -1;
+ } else {
+ dev_dbg(dev, "hist: DMA channel = %d\n", isp_hist->dma_ch);
+ omap_enable_dma_irq(isp_hist->dma_ch, OMAP_DMA_BLOCK_IRQ);
+ }
+
+ spin_lock_init(&isp_hist->lock);
+ ret = ispstat_init(dev, "HIST", &isp_hist->stat, HIST_MAX_BUFF,
+ MAX_FRAME_COUNT);
+ if (ret && (isp_hist->dma_ch >= 0))
+ omap_free_dma(isp_hist->dma_ch);
+
+ return ret;
}
/**
* isp_hist_cleanup - Module cleanup.
**/
-void isp_hist_cleanup(void)
+void isp_hist_cleanup(struct device *dev)
{
- memset(&histstat, 0, sizeof(histstat));
- memset(&hist_regs, 0, sizeof(hist_regs));
+ struct isp_device *isp = dev_get_drvdata(dev);
+
+ isp->isp_hist.active_buf = NULL;
+ ispstat_free(&isp->isp_hist.stat);
+ if (isp->isp_hist.dma_ch >= 0)
+ omap_free_dma(isp->isp_hist.dma_ch);
}
/**
- * isphist_save_context - Saves the values of the histogram module registers.
+ * isp_hist_save_context - Saves the values of the histogram module registers.
**/
-void isphist_save_context(void)
+void isp_hist_save_context(struct device *dev)
{
- DPRINTK_ISPHIST(" Saving context\n");
- isp_save_context(isphist_reg_list);
+ isp_save_context(dev, isphist_reg_list);
}
-EXPORT_SYMBOL(isphist_save_context);
/**
- * isphist_restore_context - Restores the values of the histogram module regs.
+ * isp_hist_restore_context - Restores the values of the histogram module regs.
**/
-void isphist_restore_context(void)
+void isp_hist_restore_context(struct device *dev)
{
- DPRINTK_ISPHIST(" Restoring context\n");
- isp_restore_context(isphist_reg_list);
+ isp_restore_context(dev, isphist_reg_list);
}
-EXPORT_SYMBOL(isphist_restore_context);
/**
* isp_hist_print_status - Debug print
**/
-static void isp_hist_print_status(void)
+static void isp_hist_print_status(struct isp_hist_device *isp_hist)
{
- DPRINTK_ISPHIST("ISPHIST_PCR = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR));
- DPRINTK_ISPHIST("ISPHIST_CNT = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT));
- DPRINTK_ISPHIST("ISPHIST_WB_GAIN = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN));
- DPRINTK_ISPHIST("ISPHIST_R0_HORZ = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ));
- DPRINTK_ISPHIST("ISPHIST_R0_VERT = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT));
- DPRINTK_ISPHIST("ISPHIST_R1_HORZ = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ));
- DPRINTK_ISPHIST("ISPHIST_R1_VERT = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT));
- DPRINTK_ISPHIST("ISPHIST_R2_HORZ = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ));
- DPRINTK_ISPHIST("ISPHIST_R2_VERT = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT));
- DPRINTK_ISPHIST("ISPHIST_R3_HORZ = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ));
- DPRINTK_ISPHIST("ISPHIST_R3_VERT = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT));
- DPRINTK_ISPHIST("ISPHIST_ADDR = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR));
- DPRINTK_ISPHIST("ISPHIST_RADD = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD));
- DPRINTK_ISPHIST("ISPHIST_RADD_OFF = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD_OFF));
- DPRINTK_ISPHIST("ISPHIST_H_V_INFO = 0x%08x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_H_V_INFO));
+#ifdef ISP_HIST_DEBUG
+ struct device *dev = to_device(isp_hist);
+
+ dev_dbg(dev, "hist: ISPHIST_PCR = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR));
+ dev_dbg(dev, "hist: ISPHIST_CNT = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT));
+ dev_dbg(dev, "hist: ISPHIST_WB_GAIN = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN));
+ dev_dbg(dev, "hist: ISPHIST_R0_HORZ = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ));
+ dev_dbg(dev, "hist: ISPHIST_R0_VERT = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT));
+ dev_dbg(dev, "hist: ISPHIST_R1_HORZ = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ));
+ dev_dbg(dev, "hist: ISPHIST_R1_VERT = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT));
+ dev_dbg(dev, "hist: ISPHIST_R2_HORZ = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ));
+ dev_dbg(dev, "hist: ISPHIST_R2_VERT = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT));
+ dev_dbg(dev, "hist: ISPHIST_R3_HORZ = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ));
+ dev_dbg(dev, "hist: ISPHIST_R3_VERT = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT));
+ dev_dbg(dev, "hist: ISPHIST_RADD = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD));
+ dev_dbg(dev, "hist: ISPHIST_RADD_OFF = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD_OFF));
+ dev_dbg(dev, "hist: ISPHIST_H_V_INFO = 0x%08x\n",
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_H_V_INFO));
+#endif
}
diff --git a/drivers/media/video/isp/isphist.h b/drivers/media/video/isp/isphist.h
index 6b17c4e..d726298 100644
--- a/drivers/media/video/isp/isphist.h
+++ b/drivers/media/video/isp/isphist.h
@@ -6,6 +6,7 @@
* Copyright (C) 2009 Texas Instruments, Inc.
*
* Contributors:
+ * David Cohen <david.cohen@nokia.com>
* Sergio Aguirre <saaguirre@ti.com>
* Troy Laramy
*
@@ -22,15 +23,11 @@
#define OMAP_ISP_HIST_H
#include <mach/isp_user.h>
+#include <mach/dma.h>
-#define MAX_REGIONS 0x4
-#define MAX_WB_GAIN 255
-#define MIN_WB_GAIN 0x0
-#define MAX_BIT_WIDTH 14
-#define MIN_BIT_WIDTH 8
+#include "ispstat.h"
#define ISPHIST_PCR_EN (1 << 0)
-#define HIST_MEM_SIZE 1024
#define ISPHIST_CNT_CLR_EN (1 << 7)
#define WRITE_SOURCE(reg, source) \
@@ -61,19 +58,23 @@
(reg = (reg & ~(ISPHIST_CNT_BINS_MASK)) \
| (num_bins << ISPHIST_CNT_BINS_SHIFT))
-#define WRITE_WB_R(reg, reg_wb_gain) \
+#define WRITE_CFA(reg, cfa) \
+ (reg = (reg & ~(ISPHIST_CNT_CFA_MASK)) \
+ | (cfa << ISPHIST_CNT_CFA_SHIFT))
+
+#define WRITE_WG0(reg, reg_wb_gain) \
reg = ((reg & ~(ISPHIST_WB_GAIN_WG00_MASK)) \
| (reg_wb_gain << ISPHIST_WB_GAIN_WG00_SHIFT))
-#define WRITE_WB_RG(reg, reg_wb_gain) \
+#define WRITE_WG1(reg, reg_wb_gain) \
(reg = (reg & ~(ISPHIST_WB_GAIN_WG01_MASK)) \
| (reg_wb_gain << ISPHIST_WB_GAIN_WG01_SHIFT))
-#define WRITE_WB_B(reg, reg_wb_gain) \
+#define WRITE_WG2(reg, reg_wb_gain) \
(reg = (reg & ~(ISPHIST_WB_GAIN_WG02_MASK)) \
| (reg_wb_gain << ISPHIST_WB_GAIN_WG02_SHIFT))
-#define WRITE_WB_BG(reg, reg_wb_gain) \
+#define WRITE_WG3(reg, reg_wb_gain) \
(reg = (reg & ~(ISPHIST_WB_GAIN_WG03_MASK)) \
| (reg_wb_gain << ISPHIST_WB_GAIN_WG03_SHIFT))
@@ -85,21 +86,74 @@
(reg = ((reg & ~ISPHIST_REGVERT_MASK) \
| (reg_n_vert & ISPHIST_REGVERT_MASK)))
+/**
+ * struct isp_hist_regs - Current value of Histogram configuration registers.
+ * @pcr: Peripheral control register.
+ * @cnt: Histogram control register.
+ * @wb_gain: Histogram white balance gain register.
+ * @reg_hor[]: Region N horizontal register.
+ * @reg_ver[]: Region N vertical register.
+ * @hist_radd: Address register. When input data comes from mem.
+ * @hist_radd_off: Address offset register. When input data comes from mem.
+ * @h_v_info: Image size register. When input data comes from mem.
+ */
+struct isp_hist_regs {
+ u32 pcr;
+ u32 cnt;
+ u32 wb_gain;
+ u32 reg_hor[HIST_MAX_REGIONS];
+ u32 reg_ver[HIST_MAX_REGIONS];
+ u32 hist_radd;
+ u32 hist_radd_off;
+ u32 h_v_info;
+};
-void isp_hist_enable(u8 enable);
+/**
+ * struct isp_hist_status - Histogram status.
+ * @hist_enable: Enables the histogram module.
+ * @initialized: Flag to indicate that the module is correctly initialized.
+ * @frame_cnt: Actual frame count.
+ * @num_acc_frames: Num accumulated image frames per hist frame
+ * @completed: Flag to indicate if a frame request is completed.
+ */
+struct isp_hist_device {
+ u8 enabled;
+ u8 update;
+ u8 num_acc_frames;
+ u8 waiting_dma;
+ u8 invalid_buf;
+ u8 use_dma;
+ int dma_ch;
+ struct timeval ts;
-int isp_hist_busy(void);
+ struct omap_dma_channel_params dma_config;
+ struct isp_hist_regs regs;
+ struct isp_hist_config config;
+ struct ispstat_buffer *active_buf;
+ unsigned int buf_size;
+ struct ispstat stat;
-int isp_hist_configure(struct isp_hist_config *histcfg);
+ spinlock_t lock; /* serialize access to hist device's fields */
+};
-int isp_hist_request_statistics(struct isp_hist_data *histdata);
+#define HIST_BUF_DONE 0
+#define HIST_NO_BUF 1
+#define HIST_BUF_WAITING_DMA 2
-void isphist_save_context(void);
-
-void isp_hist_suspend(void);
-
-void isp_hist_resume(void);
-
-void isphist_restore_context(void);
+int isp_hist_busy(struct isp_hist_device *isp_hist);
+void isp_hist_enable(struct isp_hist_device *isp_hist, u8 enable);
+void isp_hist_try_enable(struct isp_hist_device *isp_hist);
+int isp_hist_busy(struct isp_hist_device *isp_hist);
+int isp_hist_buf_process(struct isp_hist_device *isp_hist);
+void isp_hist_mark_invalid_buf(struct isp_hist_device *isp_hist);
+void isp_hist_config_registers(struct isp_hist_device *isp_hist);
+void isp_hist_suspend(struct isp_hist_device *isp_hist);
+void isp_hist_resume(struct isp_hist_device *isp_hist);
+void isp_hist_save_context(struct device *dev);
+void isp_hist_restore_context(struct device *dev);
+int isp_hist_config(struct isp_hist_device *isp_hist,
+ struct isp_hist_config *histcfg);
+int isp_hist_request_statistics(struct isp_hist_device *isp_hist,
+ struct isp_hist_data *histdata);
#endif /* OMAP_ISP_HIST */
diff --git a/drivers/media/video/isp/ispmmu.c b/drivers/media/video/isp/ispmmu.c
deleted file mode 100644
index f872c71..0000000
--- a/drivers/media/video/isp/ispmmu.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * omap iommu wrapper for TI's OMAP3430 Camera ISP
- *
- * Copyright (C) 2008--2009 Nokia.
- *
- * Contributors:
- * Hiroshi Doyu <hiroshi.doyu@nokia.com>
- * Sakari Ailus <sakari.ailus@nokia.com>
- *
- * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#include <linux/module.h>
-
-#include "ispmmu.h"
-#include "isp.h"
-
-#include <mach/iommu.h>
-#include <mach/iovmm.h>
-
-#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
-
-static struct iommu *isp_iommu;
-
-dma_addr_t ispmmu_vmalloc(size_t bytes)
-{
- return (dma_addr_t)iommu_vmalloc(isp_iommu, 0, bytes, IOMMU_FLAG);
-}
-
-void ispmmu_vfree(const dma_addr_t da)
-{
- iommu_vfree(isp_iommu, (u32)da);
-}
-
-dma_addr_t ispmmu_kmap(u32 pa, int size)
-{
- void *da;
-
- da = (void *)iommu_kmap(isp_iommu, 0, pa, size, IOMMU_FLAG);
- if (IS_ERR(da))
- return PTR_ERR(da);
-
- return (dma_addr_t)da;
-}
-
-void ispmmu_kunmap(dma_addr_t da)
-{
- iommu_kunmap(isp_iommu, (u32)da);
-}
-
-dma_addr_t ispmmu_vmap(const struct scatterlist *sglist,
- int sglen)
-{
- int err;
- void *da;
- struct sg_table *sgt;
- unsigned int i;
- struct scatterlist *sg, *src = (struct scatterlist *)sglist;
-
- /*
- * convert isp sglist to iommu sgt
- * FIXME: should be fixed in the upper layer?
- */
- sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
- if (!sgt)
- return -ENOMEM;
- err = sg_alloc_table(sgt, sglen, GFP_KERNEL);
- if (err)
- goto err_sg_alloc;
-
- for_each_sg(sgt->sgl, sg, sgt->nents, i)
- sg_set_buf(sg, phys_to_virt(sg_dma_address(src + i)),
- sg_dma_len(src + i));
-
- da = (void *)iommu_vmap(isp_iommu, 0, sgt, IOMMU_FLAG);
- if (IS_ERR(da))
- goto err_vmap;
-
- return (dma_addr_t)da;
-
-err_vmap:
- sg_free_table(sgt);
-err_sg_alloc:
- kfree(sgt);
- return -ENOMEM;
-}
-EXPORT_SYMBOL_GPL(ispmmu_vmap);
-
-void ispmmu_vunmap(dma_addr_t da)
-{
- struct sg_table *sgt;
-
- sgt = iommu_vunmap(isp_iommu, (u32)da);
- if (!sgt)
- return;
- sg_free_table(sgt);
- kfree(sgt);
-}
-EXPORT_SYMBOL_GPL(ispmmu_vunmap);
-
-void ispmmu_save_context(void)
-{
- if (isp_iommu)
- iommu_save_ctx(isp_iommu);
-}
-
-void ispmmu_restore_context(void)
-{
- if (isp_iommu)
- iommu_restore_ctx(isp_iommu);
-}
-
-int __init ispmmu_init(void)
-{
- int err = 0;
-
- isp_get();
- isp_iommu = iommu_get("isp");
- if (IS_ERR(isp_iommu)) {
- err = PTR_ERR(isp_iommu);
- isp_iommu = NULL;
- }
- isp_put();
-
- return err;
-}
-
-void ispmmu_cleanup(void)
-{
- isp_get();
- if (isp_iommu)
- iommu_put(isp_iommu);
- isp_put();
- isp_iommu = NULL;
-}
diff --git a/drivers/media/video/isp/ispmmu.h b/drivers/media/video/isp/ispmmu.h
deleted file mode 100644
index 0bc5bcb..0000000
--- a/drivers/media/video/isp/ispmmu.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * omap iommu wrapper for TI's OMAP3430 Camera ISP
- *
- * Copyright (C) 2008--2009 Nokia.
- *
- * Contributors:
- * Hiroshi Doyu <hiroshi.doyu@nokia.com>
- * Sakari Ailus <sakari.ailus@nokia.com>
- *
- * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#ifndef OMAP_ISP_MMU_H
-#define OMAP_ISP_MMU_H
-
-#include <linux/err.h>
-#include <linux/scatterlist.h>
-
-dma_addr_t ispmmu_vmalloc(size_t bytes);
-void ispmmu_vfree(const dma_addr_t da);
-dma_addr_t ispmmu_kmap(u32 pa, int size);
-void ispmmu_kunmap(dma_addr_t da);
-dma_addr_t ispmmu_vmap(const struct scatterlist *sglist, int sglen);
-void ispmmu_vunmap(dma_addr_t da);
-void ispmmu_save_context(void);
-void ispmmu_restore_context(void);
-int ispmmu_init(void);
-void ispmmu_cleanup(void);
-
-#endif /* OMAP_ISP_MMU_H */
diff --git a/drivers/media/video/isp/isppreview.c b/drivers/media/video/isp/isppreview.c
index 02390e1..4f5da4e 100644
--- a/drivers/media/video/isp/isppreview.c
+++ b/drivers/media/video/isp/isppreview.c
@@ -22,17 +22,15 @@
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/uaccess.h>
+#include <linux/device.h>
#include "isp.h"
#include "ispreg.h"
#include "isppreview.h"
-static struct ispprev_nf prev_nf_t;
-static struct prev_params *params;
-static int rg_update, gg_update, bg_update, nf_enable, nf_update;
-
/* Structure for saving/restoring preview module registers */
static struct isp_reg ispprev_reg_list[] = {
+ {OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 0x0000}, /* See context saving. */
{OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO, 0x0000},
{OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO, 0x0000},
{OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR, 0x0000},
@@ -67,7 +65,6 @@
{OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1, 0x0000},
{OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2, 0x0000},
{OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3, 0x0000},
- {OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 0x0000},
{0, ISP_TOK_TERM, 0x0000}
};
@@ -139,61 +136,6 @@
#define FLR_BLKADJ_GREEN 0x0
#define FLR_BLKADJ_RED 0x0
-static int update_color_matrix;
-
-/**
- * struct isp_prev - Structure for storing ISP Preview module information
- * @prev_inuse: Flag to determine if CCDC has been reserved or not (0 or 1).
- * @prevout_w: Preview output width.
- * @prevout_h: Preview output height.
- * @previn_w: Preview input width.
- * @previn_h: Preview input height.
- * @prev_inpfmt: Preview input format.
- * @prev_outfmt: Preview output format.
- * @hmed_en: Horizontal median filter enable.
- * @nf_en: Noise filter enable.
- * @dcor_en: Defect correction enable.
- * @cfa_en: Color Filter Array (CFA) interpolation enable.
- * @csup_en: Chrominance suppression enable.
- * @yenh_en: Luma enhancement enable.
- * @fmtavg: Number of horizontal pixels to average in input formatter. The
- * input width should be a multiple of this number.
- * @brightness: Brightness in preview module.
- * @contrast: Contrast in preview module.
- * @color: Color effect in preview module.
- * @cfafmt: Color Filter Array (CFA) Format.
- * @ispprev_mutex: Mutex for isp preview.
- *
- * This structure is used to store the OMAP ISP Preview module Information.
- */
-static struct isp_prev {
- int pm_state;
- u8 prev_inuse;
- u32 prevout_w;
- u32 prevout_h;
- u32 previn_w;
- u32 previn_h;
- enum preview_input prev_inpfmt;
- enum preview_output prev_outfmt;
- u8 hmed_en;
- u8 nf_en;
- u8 dcor_en;
- u8 cfa_en;
- u8 csup_en;
- u8 yenh_en;
- u8 fmtavg;
- u8 brightness;
- u8 contrast;
- enum v4l2_colorfx color;
- enum cfa_fmt cfafmt;
- struct mutex ispprev_mutex; /* For checking/modifying prev_inuse */
- u32 sph;
- u32 slv;
-} ispprev_obj;
-
-/* Saved parameters */
-static struct prev_params *prev_config_params;
-
/*
* Coeficient Tables for the submodules in Preview.
* Array is initialised with the values from.the tables text file.
@@ -242,208 +184,223 @@
#include "luma_enhance_table.h"
};
+static int isppreview_tables_update(struct isp_prev_device *isp_prev,
+ struct isptables_update *isptables_struct);
+
+
/**
- * omap34xx_isp_preview_config - Abstraction layer Preview configuration.
+ * isppreview_config - Abstraction layer Preview configuration.
* @userspace_add: Pointer from Userspace to structure with flags and data to
* update.
**/
-int omap34xx_isp_preview_config(void *userspace_add)
+int isppreview_config(struct isp_prev_device *isp_prev, void *userspace_add)
{
+ struct device *dev = to_device(isp_prev);
+ struct isp_device *isp = to_isp_device(isp_prev);
struct ispprev_hmed prev_hmed_t;
- struct ispprev_cfa prev_cfa_t;
struct ispprev_csup csup_t;
- struct ispprev_wbal prev_wbal_t;
struct ispprev_blkadj prev_blkadj_t;
- struct ispprev_rgbtorgb rgb2rgb_t;
- struct ispprev_csc prev_csc_t;
struct ispprev_yclimit yclimit_t;
struct ispprev_dcor prev_dcor_t;
- struct ispprv_update_config *preview_struct;
+ struct ispprv_update_config *config;
struct isptables_update isp_table_update;
int yen_t[ISPPRV_YENH_TBL_SIZE];
+ struct prev_params *params = &isp_prev->params;
+ unsigned long flags;
if (userspace_add == NULL)
return -EINVAL;
- preview_struct = userspace_add;
+ spin_lock_irqsave(&isp_prev->lock, flags);
+ isp_prev->shadow_update = 1;
+ spin_unlock_irqrestore(&isp_prev->lock, flags);
- if (ISP_ABS_PREV_LUMAENH & preview_struct->flag) {
- if (ISP_ABS_PREV_LUMAENH & preview_struct->update) {
- if (copy_from_user(yen_t, preview_struct->yen,
+ config = userspace_add;
+
+ if (isp->running != ISP_STOPPED)
+ goto out_config_shadow;
+
+ if (ISP_ABS_PREV_LUMAENH & config->flag) {
+ if (ISP_ABS_PREV_LUMAENH & config->update) {
+ if (copy_from_user(yen_t, config->yen,
sizeof(yen_t)))
goto err_copy_from_user;
- isppreview_config_luma_enhancement(yen_t);
+ isppreview_config_luma_enhancement(isp_prev, yen_t);
}
params->features |= PREV_LUMA_ENHANCE;
- } else if (ISP_ABS_PREV_LUMAENH & preview_struct->update)
+ } else if (ISP_ABS_PREV_LUMAENH & config->update)
params->features &= ~PREV_LUMA_ENHANCE;
- if (ISP_ABS_PREV_INVALAW & preview_struct->flag) {
- isppreview_enable_invalaw(1);
+ if (ISP_ABS_PREV_INVALAW & config->flag) {
+ isppreview_enable_invalaw(isp_prev, 1);
params->features |= PREV_INVERSE_ALAW;
} else {
- isppreview_enable_invalaw(0);
+ isppreview_enable_invalaw(isp_prev, 0);
params->features &= ~PREV_INVERSE_ALAW;
}
- if (ISP_ABS_PREV_HRZ_MED & preview_struct->flag) {
- if (ISP_ABS_PREV_HRZ_MED & preview_struct->update) {
+ if (ISP_ABS_PREV_HRZ_MED & config->flag) {
+ if (ISP_ABS_PREV_HRZ_MED & config->update) {
if (copy_from_user(&prev_hmed_t,
(struct ispprev_hmed *)
- preview_struct->prev_hmed,
+ config->prev_hmed,
sizeof(struct ispprev_hmed)))
goto err_copy_from_user;
- isppreview_config_hmed(prev_hmed_t);
+ isppreview_config_hmed(isp_prev, prev_hmed_t);
}
- isppreview_enable_hmed(1);
+ isppreview_enable_hmed(isp_prev, 1);
params->features |= PREV_HORZ_MEDIAN_FILTER;
- } else if (ISP_ABS_PREV_HRZ_MED & preview_struct->update) {
- isppreview_enable_hmed(0);
+ } else if (ISP_ABS_PREV_HRZ_MED & config->update) {
+ isppreview_enable_hmed(isp_prev, 0);
params->features &= ~PREV_HORZ_MEDIAN_FILTER;
}
- if (ISP_ABS_PREV_CFA & preview_struct->flag) {
- if (ISP_ABS_PREV_CFA & preview_struct->update) {
- if (copy_from_user(&prev_cfa_t,
- (struct ispprev_cfa *)
- preview_struct->prev_cfa,
- sizeof(struct ispprev_cfa)))
- goto err_copy_from_user;
-
- isppreview_config_cfa(prev_cfa_t);
- }
- isppreview_enable_cfa(1);
- params->features |= PREV_CFA;
- } else if (ISP_ABS_PREV_CFA & preview_struct->update) {
- isppreview_enable_cfa(0);
- params->features &= ~PREV_CFA;
- }
-
- if (ISP_ABS_PREV_CHROMA_SUPP & preview_struct->flag) {
- if (ISP_ABS_PREV_CHROMA_SUPP & preview_struct->update) {
+ if (ISP_ABS_PREV_CHROMA_SUPP & config->flag) {
+ if (ISP_ABS_PREV_CHROMA_SUPP & config->update) {
if (copy_from_user(&csup_t,
(struct ispprev_csup *)
- preview_struct->csup,
+ config->csup,
sizeof(struct ispprev_csup)))
goto err_copy_from_user;
- isppreview_config_chroma_suppression(csup_t);
+ isppreview_config_chroma_suppression(isp_prev, csup_t);
}
- isppreview_enable_chroma_suppression(1);
+ isppreview_enable_chroma_suppression(isp_prev, 1);
params->features |= PREV_CHROMA_SUPPRESS;
- } else if (ISP_ABS_PREV_CHROMA_SUPP & preview_struct->update) {
- isppreview_enable_chroma_suppression(0);
+ } else if (ISP_ABS_PREV_CHROMA_SUPP & config->update) {
+ isppreview_enable_chroma_suppression(isp_prev, 0);
params->features &= ~PREV_CHROMA_SUPPRESS;
}
- if (ISP_ABS_PREV_WB & preview_struct->update) {
- if (copy_from_user(&prev_wbal_t, (struct ispprev_wbal *)
- preview_struct->prev_wbal,
- sizeof(struct ispprev_wbal)))
- goto err_copy_from_user;
- isppreview_config_whitebalance(prev_wbal_t);
- }
-
- if (ISP_ABS_PREV_BLKADJ & preview_struct->update) {
+ if (ISP_ABS_PREV_BLKADJ & config->update) {
if (copy_from_user(&prev_blkadj_t, (struct ispprev_blkadjl *)
- preview_struct->prev_blkadj,
+ config->prev_blkadj,
sizeof(struct ispprev_blkadj)))
goto err_copy_from_user;
- isppreview_config_blkadj(prev_blkadj_t);
+ isppreview_config_blkadj(isp_prev, prev_blkadj_t);
}
- if (ISP_ABS_PREV_RGB2RGB & preview_struct->update) {
- if (copy_from_user(&rgb2rgb_t, (struct ispprev_rgbtorgb *)
- preview_struct->rgb2rgb,
- sizeof(struct ispprev_rgbtorgb)))
- goto err_copy_from_user;
- isppreview_config_rgb_blending(rgb2rgb_t);
- }
-
- if (ISP_ABS_PREV_COLOR_CONV & preview_struct->update) {
- if (copy_from_user(&prev_csc_t, (struct ispprev_csc *)
- preview_struct->prev_csc,
- sizeof(struct ispprev_csc)))
- goto err_copy_from_user;
- isppreview_config_rgb_to_ycbcr(prev_csc_t);
- }
-
- if (ISP_ABS_PREV_YC_LIMIT & preview_struct->update) {
+ if (ISP_ABS_PREV_YC_LIMIT & config->update) {
if (copy_from_user(&yclimit_t, (struct ispprev_yclimit *)
- preview_struct->yclimit,
+ config->yclimit,
sizeof(struct ispprev_yclimit)))
goto err_copy_from_user;
- isppreview_config_yc_range(yclimit_t);
+ isppreview_config_yc_range(isp_prev, yclimit_t);
}
- if (ISP_ABS_PREV_DEFECT_COR & preview_struct->flag) {
- if (ISP_ABS_PREV_DEFECT_COR & preview_struct->update) {
+ if (ISP_ABS_PREV_DEFECT_COR & config->flag) {
+ if (ISP_ABS_PREV_DEFECT_COR & config->update) {
if (copy_from_user(&prev_dcor_t,
(struct ispprev_dcor *)
- preview_struct->prev_dcor,
+ config->prev_dcor,
sizeof(struct ispprev_dcor)))
goto err_copy_from_user;
- isppreview_config_dcor(prev_dcor_t);
+ isppreview_config_dcor(isp_prev, prev_dcor_t);
}
- isppreview_enable_dcor(1);
+ isppreview_enable_dcor(isp_prev, 1);
params->features |= PREV_DEFECT_COR;
- } else if (ISP_ABS_PREV_DEFECT_COR & preview_struct->update) {
- isppreview_enable_dcor(0);
+ } else if (ISP_ABS_PREV_DEFECT_COR & config->update) {
+ isppreview_enable_dcor(isp_prev, 0);
params->features &= ~PREV_DEFECT_COR;
}
- if (ISP_ABS_PREV_GAMMABYPASS & preview_struct->flag) {
- isppreview_enable_gammabypass(1);
+ if (ISP_ABS_PREV_GAMMABYPASS & config->flag) {
+ isppreview_enable_gammabypass(isp_prev, 1);
params->features |= PREV_GAMMA_BYPASS;
} else {
- isppreview_enable_gammabypass(0);
+ isppreview_enable_gammabypass(isp_prev, 0);
params->features &= ~PREV_GAMMA_BYPASS;
}
- isp_table_update.update = preview_struct->update;
- isp_table_update.flag = preview_struct->flag;
- isp_table_update.prev_nf = preview_struct->prev_nf;
- isp_table_update.red_gamma = preview_struct->red_gamma;
- isp_table_update.green_gamma = preview_struct->green_gamma;
- isp_table_update.blue_gamma = preview_struct->blue_gamma;
+out_config_shadow:
+ if (ISP_ABS_PREV_RGB2RGB & config->update) {
+ if (copy_from_user(¶ms->rgb2rgb,
+ (struct ispprev_rgbtorgb *)
+ config->rgb2rgb,
+ sizeof(struct ispprev_rgbtorgb)))
+ goto err_copy_from_user;
+ /* The function call above prevents compiler from reordering
+ * writes so that the flag below is always set after
+ * isp_prev->params.rgb2rgb is written to. */
+ isp_prev->update_rgb_blending = 1;
+ }
- if (omap34xx_isp_tables_update(&isp_table_update))
+ if (ISP_ABS_PREV_COLOR_CONV & config->update) {
+ if (copy_from_user(¶ms->rgb2ycbcr, (struct ispprev_csc *)
+ config->prev_csc,
+ sizeof(struct ispprev_csc)))
+ goto err_copy_from_user;
+ /* Same here... this flag has to be set after rgb2ycbcr
+ * structure is written to. */
+ isp_prev->update_rgb_to_ycbcr = 1;
+ }
+
+ isp_table_update.update = config->update;
+ isp_table_update.flag = config->flag;
+ isp_table_update.prev_nf = config->prev_nf;
+ isp_table_update.red_gamma = config->red_gamma;
+ isp_table_update.green_gamma = config->green_gamma;
+ isp_table_update.blue_gamma = config->blue_gamma;
+ isp_table_update.prev_cfa = config->prev_cfa;
+ isp_table_update.prev_wbal = config->prev_wbal;
+
+ if (isppreview_tables_update(isp_prev, &isp_table_update))
goto err_copy_from_user;
+ isp_prev->shadow_update = 0;
+
+ /* If the stream is stopped then update registers immediately */
+ if (isp->running == ISP_STOPPED)
+ isppreview_config_shadow_registers(isp_prev);
+
return 0;
err_copy_from_user:
- printk(KERN_ERR "Preview Config: Copy From User Error\n");
+ isp_prev->shadow_update = 0;
+ dev_err(dev, "preview: Config: Copy From User Error\n");
return -EFAULT;
}
-EXPORT_SYMBOL_GPL(omap34xx_isp_preview_config);
+EXPORT_SYMBOL_GPL(isppreview_config);
/**
- * omap34xx_isp_tables_update - Abstraction layer Tables update.
+ * isppreview_tables_update - Abstraction layer Tables update.
* @isptables_struct: Pointer from Userspace to structure with flags and table
* data to update.
**/
-int omap34xx_isp_tables_update(struct isptables_update *isptables_struct)
+static int isppreview_tables_update(struct isp_prev_device *isp_prev,
+ struct isptables_update *isptables_struct)
{
+ struct device *dev = to_device(isp_prev);
+ struct prev_params *params = &isp_prev->params;
+
+ if (ISP_ABS_PREV_WB & isptables_struct->update) {
+ if (copy_from_user(&isp_prev->params.wbal,
+ isptables_struct->prev_wbal,
+ sizeof(struct ispprev_wbal)))
+ goto err_copy_from_user;
+
+ isp_prev->wbal_update = 1;
+ }
if (ISP_ABS_TBL_NF & isptables_struct->flag) {
- nf_enable = 1;
+ isp_prev->nf_enable = 1;
params->features |= PREV_NOISE_FILTER;
if (ISP_ABS_TBL_NF & isptables_struct->update) {
- if (copy_from_user(&prev_nf_t, (struct ispprev_nf *)
+ if (copy_from_user(&isp_prev->prev_nf_t,
+ (struct ispprev_nf *)
isptables_struct->prev_nf,
sizeof(struct ispprev_nf)))
goto err_copy_from_user;
- nf_update = 1;
+ isp_prev->nf_update = 1;
} else
- nf_update = 0;
+ isp_prev->nf_update = 0;
} else {
- nf_enable = 0;
+ isp_prev->nf_enable = 0;
params->features &= ~PREV_NOISE_FILTER;
if (ISP_ABS_TBL_NF & isptables_struct->update)
- nf_update = 1;
+ isp_prev->nf_update = 1;
else
- nf_update = 0;
+ isp_prev->nf_update = 0;
}
if (ISP_ABS_TBL_REDGAMMA & isptables_struct->update) {
@@ -451,18 +408,18 @@
sizeof(redgamma_table))) {
goto err_copy_from_user;
}
- rg_update = 1;
+ isp_prev->rg_update = 1;
} else
- rg_update = 0;
+ isp_prev->rg_update = 0;
if (ISP_ABS_TBL_GREENGAMMA & isptables_struct->update) {
if (copy_from_user(greengamma_table,
isptables_struct->green_gamma,
sizeof(greengamma_table)))
goto err_copy_from_user;
- gg_update = 1;
+ isp_prev->gg_update = 1;
} else
- gg_update = 0;
+ isp_prev->gg_update = 0;
if (ISP_ABS_TBL_BLUEGAMMA & isptables_struct->update) {
if (copy_from_user(bluegamma_table,
@@ -470,14 +427,40 @@
sizeof(bluegamma_table))) {
goto err_copy_from_user;
}
- bg_update = 1;
+ isp_prev->bg_update = 1;
} else
- bg_update = 0;
+ isp_prev->bg_update = 0;
+
+ if (ISP_ABS_PREV_CFA & isptables_struct->update) {
+ struct ispprev_cfa cfa;
+ if (isptables_struct->prev_cfa) {
+ if (copy_from_user(&cfa,
+ isptables_struct->prev_cfa,
+ sizeof(struct ispprev_cfa)))
+ goto err_copy_from_user;
+ if (cfa.cfa_table != NULL) {
+ if (copy_from_user(cfa_coef_table,
+ cfa.cfa_table,
+ sizeof(cfa_coef_table)))
+ goto err_copy_from_user;
+ }
+ cfa.cfa_table = cfa_coef_table;
+ isp_prev->params.cfa = cfa;
+ }
+ if (ISP_ABS_PREV_CFA & isptables_struct->flag) {
+ isp_prev->cfa_en = 1;
+ isp_prev->params.features |= PREV_CFA;
+ } else {
+ isp_prev->cfa_en = 0;
+ isp_prev->params.features &= ~PREV_CFA;
+ }
+ isp_prev->cfa_update = 1;
+ }
return 0;
err_copy_from_user:
- printk(KERN_ERR "Preview Tables:Copy From User Error\n");
+ dev_err(dev, "preview tables: Copy From User Error\n");
return -EFAULT;
}
@@ -486,116 +469,131 @@
*
* Allows user to program shadow registers associated with preview module.
**/
-void isppreview_config_shadow_registers()
+void isppreview_config_shadow_registers(struct isp_prev_device *isp_prev)
{
+ struct device *dev = to_device(isp_prev);
u8 current_brightness_contrast;
- int ctr, prv_disabled;
+ int ctr;
+ unsigned long flags;
- isppreview_query_brightness(¤t_brightness_contrast);
+ spin_lock_irqsave(&isp_prev->lock, flags);
+ if (isp_prev->shadow_update) {
+ spin_unlock_irqrestore(&isp_prev->lock, flags);
+ return;
+ }
+
+ isppreview_query_brightness(isp_prev, ¤t_brightness_contrast);
if (current_brightness_contrast !=
- ispprev_obj.brightness) {
+ isp_prev->brightness) {
DPRINTK_ISPPREV(" Changing Brightness level to %d\n",
- ispprev_obj.brightness);
- isppreview_config_brightness(ispprev_obj.brightness);
+ isp_prev->brightness);
+ isppreview_config_brightness(isp_prev, isp_prev->brightness);
}
- isppreview_query_contrast(¤t_brightness_contrast);
+ isppreview_query_contrast(isp_prev, ¤t_brightness_contrast);
if (current_brightness_contrast !=
- ispprev_obj.contrast) {
+ isp_prev->contrast) {
DPRINTK_ISPPREV(" Changing Contrast level to %d\n",
- ispprev_obj.contrast);
- isppreview_config_contrast(ispprev_obj.contrast);
+ isp_prev->contrast);
+ isppreview_config_contrast(isp_prev, isp_prev->contrast);
}
- if (update_color_matrix) {
- isppreview_config_rgb_to_ycbcr(flr_prev_csc[ispprev_obj.color]);
- update_color_matrix = 0;
+ if (isp_prev->wbal_update) {
+ isppreview_config_whitebalance(isp_prev,
+ isp_prev->params.wbal);
+ isp_prev->wbal_update = 0;
}
- if (gg_update || rg_update || bg_update || nf_update) {
- isppreview_enable(0);
- prv_disabled = 1;
+ if (isp_prev->update_color_matrix) {
+ isppreview_config_rgb_to_ycbcr(isp_prev,
+ flr_prev_csc[isp_prev->color]);
+ isp_prev->update_color_matrix = 0;
+ }
+ if (isp_prev->update_rgb_blending) {
+ isp_prev->update_rgb_blending = 0;
+ isppreview_config_rgb_blending(isp_prev,
+ isp_prev->params.rgb2rgb);
+ }
+ if (isp_prev->update_rgb_to_ycbcr) {
+ isp_prev->update_rgb_to_ycbcr = 0;
+ isppreview_config_rgb_to_ycbcr(isp_prev,
+ isp_prev->params.rgb2ycbcr);
}
- if (gg_update) {
- isp_reg_writel(ISPPRV_TBL_ADDR_GREEN_G_START,
+ if (isp_prev->gg_update) {
+ isp_reg_writel(dev, ISPPRV_TBL_ADDR_GREEN_G_START,
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
for (ctr = 0; ctr < ISP_GAMMA_TABLE_SIZE; ctr++) {
- isp_reg_writel(greengamma_table[ctr],
+ isp_reg_writel(dev, greengamma_table[ctr],
OMAP3_ISP_IOMEM_PREV,
ISPPRV_SET_TBL_DATA);
}
- gg_update = 0;
+ isp_prev->gg_update = 0;
}
- if (rg_update) {
- isp_reg_writel(ISPPRV_TBL_ADDR_RED_G_START,
+ if (isp_prev->rg_update) {
+ isp_reg_writel(dev, ISPPRV_TBL_ADDR_RED_G_START,
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
for (ctr = 0; ctr < ISP_GAMMA_TABLE_SIZE; ctr++) {
- isp_reg_writel(redgamma_table[ctr],
+ isp_reg_writel(dev, redgamma_table[ctr],
OMAP3_ISP_IOMEM_PREV,
ISPPRV_SET_TBL_DATA);
}
- rg_update = 0;
+ isp_prev->rg_update = 0;
}
- if (bg_update) {
- isp_reg_writel(ISPPRV_TBL_ADDR_BLUE_G_START,
+ if (isp_prev->bg_update) {
+ isp_reg_writel(dev, ISPPRV_TBL_ADDR_BLUE_G_START,
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
for (ctr = 0; ctr < ISP_GAMMA_TABLE_SIZE; ctr++) {
- isp_reg_writel(bluegamma_table[ctr],
+ isp_reg_writel(dev, bluegamma_table[ctr],
OMAP3_ISP_IOMEM_PREV,
ISPPRV_SET_TBL_DATA);
}
- bg_update = 0;
+ isp_prev->bg_update = 0;
}
- if (nf_update && nf_enable) {
- isp_reg_writel(0xC00,
+ if (isp_prev->cfa_update) {
+ isp_prev->cfa_update = 0;
+ isppreview_config_cfa(isp_prev, isp_prev->params.cfa);
+ isppreview_enable_cfa(isp_prev, isp_prev->cfa_en);
+ }
+
+ if (isp_prev->nf_update && isp_prev->nf_enable) {
+ isppreview_enable_noisefilter(isp_prev, 0);
+ isp_reg_writel(dev, 0xC00,
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
- isp_reg_writel(prev_nf_t.spread,
+ isp_reg_writel(dev, isp_prev->prev_nf_t.spread,
OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
for (ctr = 0; ctr < ISPPRV_NF_TBL_SIZE; ctr++) {
- isp_reg_writel(prev_nf_t.table[ctr],
+ isp_reg_writel(dev,
+ isp_prev->prev_nf_t.table[ctr],
OMAP3_ISP_IOMEM_PREV,
ISPPRV_SET_TBL_DATA);
}
- isppreview_enable_noisefilter(1);
- nf_update = 0;
+ isppreview_enable_noisefilter(isp_prev, 1);
+ isp_prev->nf_update = 0;
}
- if (~nf_update && nf_enable)
- isppreview_enable_noisefilter(1);
+ if (isp_prev->nf_update && ~isp_prev->nf_enable)
+ isppreview_enable_noisefilter(isp_prev, 0);
- if (nf_update && ~nf_enable)
- isppreview_enable_noisefilter(0);
-
- if (prv_disabled) {
- isppreview_enable(1);
- prv_disabled = 0;
- }
+ spin_unlock_irqrestore(&isp_prev->lock, flags);
}
-EXPORT_SYMBOL_GPL(isppreview_config_shadow_registers);
/**
* isppreview_request - Reserves the preview module.
*
* Returns 0 if successful, or -EBUSY if the module was already reserved.
**/
-int isppreview_request()
+int isppreview_request(struct isp_prev_device *isp_prev)
{
- mutex_lock(&ispprev_obj.ispprev_mutex);
- if (ispprev_obj.prev_inuse) {
- mutex_unlock(&ispprev_obj.ispprev_mutex);
- printk(KERN_ERR "ISP_ERR : Preview Module Busy\n");
- return -EBUSY;
- }
- ispprev_obj.prev_inuse = 1;
- mutex_unlock(&ispprev_obj.ispprev_mutex);
- isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, ISPCTRL_PREV_RAM_EN |
- ISPCTRL_PREV_CLK_EN |
- ISPCTRL_SBL_WR1_RAM_EN);
+ struct device *dev = to_device(isp_prev);
+
+ isp_reg_or(dev,
+ OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, ISPCTRL_PREV_RAM_EN |
+ ISPCTRL_PREV_CLK_EN | ISPCTRL_SBL_WR1_RAM_EN);
return 0;
}
EXPORT_SYMBOL_GPL(isppreview_request);
@@ -605,23 +603,14 @@
*
* Returns 0 if successful, or -EINVAL if the module was already freed.
**/
-int isppreview_free()
+void isppreview_free(struct isp_prev_device *isp_prev)
{
- mutex_lock(&ispprev_obj.ispprev_mutex);
- if (ispprev_obj.prev_inuse) {
- ispprev_obj.prev_inuse = 0;
- mutex_unlock(&ispprev_obj.ispprev_mutex);
- isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+ struct device *dev = to_device(isp_prev);
+
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
~(ISPCTRL_PREV_CLK_EN |
ISPCTRL_PREV_RAM_EN |
ISPCTRL_SBL_WR1_RAM_EN));
- return 0;
- } else {
- mutex_unlock(&ispprev_obj.ispprev_mutex);
- DPRINTK_ISPPREV("ISP_ERR : Preview Module already freed\n");
- return -EINVAL;
- }
-
}
EXPORT_SYMBOL_GPL(isppreview_free);
@@ -639,47 +628,39 @@
* Returns 0 if successful, or -EINVAL if wrong input or output values are
* specified.
**/
-int isppreview_config_datapath(enum preview_input input,
- enum preview_output output)
+int isppreview_config_datapath(struct isp_prev_device *isp_prev,
+ struct isp_pipeline *pipe)
{
+ struct device *dev = to_device(isp_prev);
u32 pcr = 0;
u8 enable = 0;
- struct prev_params *params = prev_config_params;
+ struct prev_params *params = &isp_prev->params;
struct ispprev_yclimit yclimit;
- pcr = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+ pcr = isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
- switch (input) {
+ switch (pipe->prv_in) {
case PRV_RAW_CCDC:
pcr &= ~ISPPRV_PCR_SOURCE;
- pcr &= ~ISPPRV_PCR_ONESHOT;
- ispprev_obj.prev_inpfmt = PRV_RAW_CCDC;
break;
case PRV_RAW_MEM:
pcr |= ISPPRV_PCR_SOURCE;
- pcr |= ISPPRV_PCR_ONESHOT;
- ispprev_obj.prev_inpfmt = PRV_RAW_MEM;
break;
case PRV_CCDC_DRKF:
pcr |= ISPPRV_PCR_DRKFCAP;
- pcr |= ISPPRV_PCR_ONESHOT;
- ispprev_obj.prev_inpfmt = PRV_CCDC_DRKF;
break;
case PRV_COMPCFA:
- ispprev_obj.prev_inpfmt = PRV_COMPCFA;
break;
case PRV_OTHERS:
- ispprev_obj.prev_inpfmt = PRV_OTHERS;
break;
case PRV_RGBBAYERCFA:
- ispprev_obj.prev_inpfmt = PRV_RGBBAYERCFA;
break;
default:
- printk(KERN_ERR "ISP_ERR : Wrong Input\n");
+ dev_err(dev, "preview: Wrong Input\n");
return -EINVAL;
};
- switch (output) {
+ switch (pipe->prv_out) {
case PREVIEW_RSZ:
pcr |= ISPPRV_PCR_RSZPORT;
pcr &= ~ISPPRV_PCR_SDRPORT;
@@ -689,60 +670,60 @@
pcr |= ISPPRV_PCR_SDRPORT;
break;
default:
- printk(KERN_ERR "ISP_ERR : Wrong Output\n");
+ dev_err(dev, "preview: Wrong Output\n");
return -EINVAL;
}
- ispprev_obj.prev_outfmt = output;
- isp_reg_writel(pcr, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+ isp_reg_writel(dev, pcr, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
- isppreview_config_ycpos(params->pix_fmt);
-
- if (params->cfa.cfa_table != NULL)
- isppreview_config_cfa(params->cfa);
if (params->csup.hypf_en == 1)
- isppreview_config_chroma_suppression(params->csup);
+ isppreview_config_chroma_suppression(isp_prev, params->csup);
if (params->ytable != NULL)
- isppreview_config_luma_enhancement(params->ytable);
+ isppreview_config_luma_enhancement(isp_prev, params->ytable);
if (params->gtable.redtable != NULL)
- isppreview_config_gammacorrn(params->gtable);
+ isppreview_config_gammacorrn(isp_prev, params->gtable);
+
+ isp_prev->cfa_update = 0;
+ isppreview_config_cfa(isp_prev, params->cfa);
enable = (params->features & PREV_CFA) ? 1 : 0;
- isppreview_enable_cfa(enable);
+ isppreview_enable_cfa(isp_prev, enable);
enable = (params->features & PREV_CHROMA_SUPPRESS) ? 1 : 0;
- isppreview_enable_chroma_suppression(enable);
+ isppreview_enable_chroma_suppression(isp_prev, enable);
enable = (params->features & PREV_LUMA_ENHANCE) ? 1 : 0;
- isppreview_enable_luma_enhancement(enable);
+ isppreview_enable_luma_enhancement(isp_prev, enable);
enable = (params->features & PREV_NOISE_FILTER) ? 1 : 0;
if (enable)
- isppreview_config_noisefilter(params->nf);
- isppreview_enable_noisefilter(enable);
+ isppreview_config_noisefilter(isp_prev, params->nf);
+ isppreview_enable_noisefilter(isp_prev, enable);
enable = (params->features & PREV_DEFECT_COR) ? 1 : 0;
if (enable)
- isppreview_config_dcor(params->dcor);
- isppreview_enable_dcor(enable);
+ isppreview_config_dcor(isp_prev, params->dcor);
+ isppreview_enable_dcor(isp_prev, enable);
enable = (params->features & PREV_GAMMA_BYPASS) ? 1 : 0;
- isppreview_enable_gammabypass(enable);
+ isppreview_enable_gammabypass(isp_prev, enable);
- isppreview_config_whitebalance(params->wbal);
- isppreview_config_blkadj(params->blk_adj);
- isppreview_config_rgb_blending(params->rgb2rgb);
- isppreview_config_rgb_to_ycbcr(params->rgb2ycbcr);
+ isppreview_config_whitebalance(isp_prev, params->wbal);
+ isp_prev->wbal_update = 0;
- isppreview_config_contrast(params->contrast);
- isppreview_config_brightness(params->brightness);
+ isppreview_config_blkadj(isp_prev, params->blk_adj);
+ isppreview_config_rgb_blending(isp_prev, params->rgb2rgb);
+ isppreview_config_rgb_to_ycbcr(isp_prev, params->rgb2ycbcr);
+
+ isppreview_config_contrast(isp_prev, params->contrast);
+ isppreview_config_brightness(isp_prev, params->brightness);
yclimit.minC = ISPPRV_YC_MIN;
yclimit.maxC = ISPPRV_YC_MAX;
yclimit.minY = ISPPRV_YC_MIN;
yclimit.maxY = ISPPRV_YC_MAX;
- isppreview_config_yc_range(yclimit);
+ isppreview_config_yc_range(isp_prev, yclimit);
return 0;
}
@@ -753,10 +734,10 @@
* h - Start Pixel Horizontal.
* v - Start Line Vertical.
**/
-void isppreview_set_skip(u32 h, u32 v)
+void isppreview_set_skip(struct isp_prev_device *isp_prev, u32 h, u32 v)
{
- ispprev_obj.sph = h;
- ispprev_obj.slv = v;
+ isp_prev->sph = h;
+ isp_prev->slv = v;
}
EXPORT_SYMBOL_GPL(isppreview_set_skip);
@@ -764,12 +745,16 @@
* isppreview_config_ycpos - Configure byte layout of YUV image.
* @mode: Indicates the required byte layout.
**/
-void isppreview_config_ycpos(enum preview_ycpos_mode mode)
+void isppreview_config_ycpos(struct isp_prev_device *isp_prev,
+ enum preview_ycpos_mode mode)
{
- u32 pcr = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+ struct device *dev = to_device(isp_prev);
+ u32 pcr = isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+
pcr &= ~ISPPRV_PCR_YCPOS_CrYCbY;
pcr |= (mode << ISPPRV_PCR_YCPOS_SHIFT);
- isp_reg_writel(pcr, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+ isp_reg_writel(dev, pcr, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
}
EXPORT_SYMBOL_GPL(isppreview_config_ycpos);
@@ -777,12 +762,13 @@
* isppreview_config_averager - Enable / disable / configure averager
* @average: Average value to be configured.
**/
-void isppreview_config_averager(u8 average)
+void isppreview_config_averager(struct isp_prev_device *isp_prev, u8 average)
{
+ struct device *dev = to_device(isp_prev);
int reg = 0;
reg = AVE_ODD_PIXEL_DIST | AVE_EVEN_PIXEL_DIST | average;
- isp_reg_writel(reg, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
+ isp_reg_writel(dev, reg, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
}
EXPORT_SYMBOL_GPL(isppreview_config_averager);
@@ -790,16 +776,19 @@
* isppreview_enable_invalaw - Enable/Disable Inverse A-Law module in Preview.
* @enable: 1 - Reverse the A-Law done in CCDC.
**/
-void isppreview_enable_invalaw(u8 enable)
+void isppreview_enable_invalaw(struct isp_prev_device *isp_prev, u8 enable)
{
+ struct device *dev = to_device(isp_prev);
u32 pcr_val = 0;
- pcr_val = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+ pcr_val = isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
if (enable) {
- isp_reg_writel(pcr_val | ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW,
+ isp_reg_writel(dev,
+ pcr_val | ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW,
OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
} else {
- isp_reg_writel(pcr_val &
+ isp_reg_writel(dev, pcr_val &
~(ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW),
OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
}
@@ -813,12 +802,15 @@
*
* The proccess is applied for each captured frame.
**/
-void isppreview_enable_drkframe(u8 enable)
+void isppreview_enable_drkframe(struct isp_prev_device *isp_prev, u8 enable)
{
+ struct device *dev = to_device(isp_prev);
+
if (enable)
- isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_DRKFEN);
+ isp_reg_or(dev,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_DRKFEN);
else {
- isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
~ISPPRV_PCR_DRKFEN);
}
}
@@ -831,15 +823,16 @@
* If dark frame subtract won't be used, then enable this shading
* compensation.
**/
-void isppreview_enable_shadcomp(u8 enable)
+void isppreview_enable_shadcomp(struct isp_prev_device *isp_prev, u8 enable)
{
+ struct device *dev = to_device(isp_prev);
if (enable) {
- isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
ISPPRV_PCR_SCOMP_EN);
- isppreview_enable_drkframe(1);
+ isppreview_enable_drkframe(isp_prev, 1);
} else {
- isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
~ISPPRV_PCR_SCOMP_EN);
}
}
@@ -849,12 +842,16 @@
* isppreview_config_drkf_shadcomp - Configures shift value in shading comp.
* @scomp_shtval: 3bit value of shift used in shading compensation.
**/
-void isppreview_config_drkf_shadcomp(u8 scomp_shtval)
+void isppreview_config_drkf_shadcomp(struct isp_prev_device *isp_prev,
+ u8 scomp_shtval)
{
- u32 pcr_val = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+ struct device *dev = to_device(isp_prev);
+ u32 pcr_val = isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
pcr_val &= ISPPRV_PCR_SCOMP_SFT_MASK;
- isp_reg_writel(pcr_val | (scomp_shtval << ISPPRV_PCR_SCOMP_SFT_SHIFT),
+ isp_reg_writel(dev,
+ pcr_val | (scomp_shtval << ISPPRV_PCR_SCOMP_SFT_SHIFT),
OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
}
EXPORT_SYMBOL_GPL(isppreview_config_drkf_shadcomp);
@@ -863,15 +860,18 @@
* isppreview_enable_hmed - Enables/Disables of the Horizontal Median Filter.
* @enable: 1 - Enables Horizontal Median Filter.
**/
-void isppreview_enable_hmed(u8 enable)
+void isppreview_enable_hmed(struct isp_prev_device *isp_prev, u8 enable)
{
+ struct device *dev = to_device(isp_prev);
+
if (enable)
- isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_HMEDEN);
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_HMEDEN);
else {
- isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
~ISPPRV_PCR_HMEDEN);
}
- ispprev_obj.hmed_en = enable ? 1 : 0;
+ isp_prev->hmed_en = enable ? 1 : 0;
}
EXPORT_SYMBOL_GPL(isppreview_enable_hmed);
@@ -880,9 +880,10 @@
* @prev_hmed: Structure containing the odd and even distance between the
* pixels in the image along with the filter threshold.
**/
-void isppreview_config_hmed(struct ispprev_hmed prev_hmed)
+void isppreview_config_hmed(struct isp_prev_device *isp_prev,
+ struct ispprev_hmed prev_hmed)
{
-
+ struct device *dev = to_device(isp_prev);
u32 odddist = 0;
u32 evendist = 0;
@@ -896,7 +897,7 @@
else
evendist = ISPPRV_HMED_EVENDIST;
- isp_reg_writel(odddist | evendist | (prev_hmed.thres <<
+ isp_reg_writel(dev, odddist | evendist | (prev_hmed.thres <<
ISPPRV_HMED_THRESHOLD_SHIFT),
OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
@@ -908,16 +909,19 @@
* @prev_nf: Structure containing the noisefilter table, strength to be used
* for the noise filter and the defect correction enable flag.
**/
-void isppreview_config_noisefilter(struct ispprev_nf prev_nf)
+void isppreview_config_noisefilter(struct isp_prev_device *isp_prev,
+ struct ispprev_nf prev_nf)
{
+ struct device *dev = to_device(isp_prev);
int i = 0;
- isp_reg_writel(prev_nf.spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
- isp_reg_writel(ISPPRV_NF_TABLE_ADDR, OMAP3_ISP_IOMEM_PREV,
- ISPPRV_SET_TBL_ADDR);
+ isp_reg_writel(dev, prev_nf.spread, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_NF);
+ isp_reg_writel(dev, ISPPRV_NF_TABLE_ADDR,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
for (i = 0; i < ISPPRV_NF_TBL_SIZE; i++) {
- isp_reg_writel(prev_nf.table[i], OMAP3_ISP_IOMEM_PREV,
- ISPPRV_SET_TBL_DATA);
+ isp_reg_writel(dev, prev_nf.table[i],
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
}
}
EXPORT_SYMBOL_GPL(isppreview_config_noisefilter);
@@ -926,20 +930,24 @@
* isppreview_config_dcor - Configures the defect correction
* @prev_nf: Structure containing the defect correction structure
**/
-void isppreview_config_dcor(struct ispprev_dcor prev_dcor)
+void isppreview_config_dcor(struct isp_prev_device *isp_prev,
+ struct ispprev_dcor prev_dcor)
{
+ struct device *dev = to_device(isp_prev);
+
if (prev_dcor.couplet_mode_en) {
- isp_reg_writel(prev_dcor.detect_correct[0],
+ isp_reg_writel(dev, prev_dcor.detect_correct[0],
OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
- isp_reg_writel(prev_dcor.detect_correct[1],
+ isp_reg_writel(dev, prev_dcor.detect_correct[1],
OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
- isp_reg_writel(prev_dcor.detect_correct[2],
+ isp_reg_writel(dev, prev_dcor.detect_correct[2],
OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
- isp_reg_writel(prev_dcor.detect_correct[3],
+ isp_reg_writel(dev, prev_dcor.detect_correct[3],
OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
- isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_DCCOUP);
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_DCCOUP);
} else {
- isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
~ISPPRV_PCR_DCCOUP);
}
}
@@ -950,25 +958,28 @@
* @prev_cfa: Structure containing the CFA interpolation table, CFA format
* in the image, vertical and horizontal gradient threshold.
**/
-void isppreview_config_cfa(struct ispprev_cfa prev_cfa)
+void isppreview_config_cfa(struct isp_prev_device *isp_prev,
+ struct ispprev_cfa prev_cfa)
{
+ struct device *dev = to_device(isp_prev);
int i = 0;
- ispprev_obj.cfafmt = prev_cfa.cfafmt;
+ isp_prev->cfafmt = prev_cfa.cfafmt;
- isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- (prev_cfa.cfafmt << ISPPRV_PCR_CFAFMT_SHIFT));
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ~ISPPRV_PCR_CFAFMT_MASK,
+ (prev_cfa.cfafmt << ISPPRV_PCR_CFAFMT_SHIFT));
- isp_reg_writel(
+ isp_reg_writel(dev,
(prev_cfa.cfa_gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) |
(prev_cfa.cfa_gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT),
OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA);
- isp_reg_writel(ISPPRV_CFA_TABLE_ADDR, OMAP3_ISP_IOMEM_PREV,
- ISPPRV_SET_TBL_ADDR);
+ isp_reg_writel(dev, ISPPRV_CFA_TABLE_ADDR,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
for (i = 0; i < ISPPRV_CFA_TBL_SIZE; i++) {
- isp_reg_writel(prev_cfa.cfa_table[i],
+ isp_reg_writel(dev, prev_cfa.cfa_table[i],
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
}
}
@@ -978,58 +989,49 @@
* isppreview_config_gammacorrn - Configures the Gamma Correction table values
* @gtable: Structure containing the table for red, blue, green gamma table.
**/
-void isppreview_config_gammacorrn(struct ispprev_gtable gtable)
+void isppreview_config_gammacorrn(struct isp_prev_device *isp_prev,
+ struct ispprev_gtable gtable)
{
+ struct device *dev = to_device(isp_prev);
int i = 0;
- isp_reg_writel(ISPPRV_REDGAMMA_TABLE_ADDR,
+ isp_reg_writel(dev, ISPPRV_REDGAMMA_TABLE_ADDR,
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
for (i = 0; i < ISPPRV_GAMMA_TBL_SIZE; i++) {
- isp_reg_writel(gtable.redtable[i],
+ isp_reg_writel(dev, gtable.redtable[i],
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
}
- isp_reg_writel(ISPPRV_GREENGAMMA_TABLE_ADDR,
+ isp_reg_writel(dev, ISPPRV_GREENGAMMA_TABLE_ADDR,
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
for (i = 0; i < ISPPRV_GAMMA_TBL_SIZE; i++) {
- isp_reg_writel(gtable.greentable[i],
+ isp_reg_writel(dev, gtable.greentable[i],
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
}
- isp_reg_writel(ISPPRV_BLUEGAMMA_TABLE_ADDR,
+ isp_reg_writel(dev, ISPPRV_BLUEGAMMA_TABLE_ADDR,
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
for (i = 0; i < ISPPRV_GAMMA_TBL_SIZE; i++) {
- isp_reg_writel(gtable.bluetable[i],
+ isp_reg_writel(dev, gtable.bluetable[i],
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
}
}
EXPORT_SYMBOL_GPL(isppreview_config_gammacorrn);
/**
- * isppreview_set_luma_enhancement - Stores the Luminance Enhancement table.
+ * isppreview_config_luma_enhancement - Sets the Luminance Enhancement table.
* @ytable: Structure containing the table for Luminance Enhancement table.
**/
-void isppreview_set_luma_enhancement(u32 *ytable)
+void isppreview_config_luma_enhancement(struct isp_prev_device *isp_prev,
+ u32 *ytable)
{
- int i;
-
- for (i = 0; i < ISPPRV_YENH_TBL_SIZE; i++)
- params->ytable[i] = ytable[i];
-}
-EXPORT_SYMBOL_GPL(isppreview_set_luma_enhancement);
-
-/**
- * isppreview_config_luma_enhancement - Writes the Luminance Enhancement table.
- * @ytable: Structure containing the table for Luminance Enhancement table.
- **/
-void isppreview_config_luma_enhancement(u32 *ytable)
-{
+ struct device *dev = to_device(isp_prev);
int i = 0;
- isp_reg_writel(ISPPRV_YENH_TABLE_ADDR,
+ isp_reg_writel(dev, ISPPRV_YENH_TABLE_ADDR,
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
for (i = 0; i < ISPPRV_YENH_TBL_SIZE; i++) {
- isp_reg_writel(ytable[i],
+ isp_reg_writel(dev, ytable[i],
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
}
}
@@ -1040,9 +1042,13 @@
* @csup: Structure containing the threshold value for suppression
* and the hypass filter enable flag.
**/
-void isppreview_config_chroma_suppression(struct ispprev_csup csup)
+void isppreview_config_chroma_suppression(struct isp_prev_device *isp_prev,
+ struct ispprev_csup csup)
{
- isp_reg_writel(csup.gain | (csup.thres << ISPPRV_CSUP_THRES_SHIFT) |
+ struct device *dev = to_device(isp_prev);
+
+ isp_reg_writel(dev,
+ csup.gain | (csup.thres << ISPPRV_CSUP_THRES_SHIFT) |
(csup.hypf_en << ISPPRV_CSUP_HPYF_SHIFT),
OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP);
}
@@ -1052,13 +1058,17 @@
* isppreview_enable_noisefilter - Enables/Disables the Noise Filter.
* @enable: 1 - Enables the Noise Filter.
**/
-void isppreview_enable_noisefilter(u8 enable)
+void isppreview_enable_noisefilter(struct isp_prev_device *isp_prev, u8 enable)
{
+ struct device *dev = to_device(isp_prev);
+
if (enable)
- isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_NFEN);
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_NFEN);
else
- isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ~ISPPRV_PCR_NFEN);
- ispprev_obj.nf_en = enable ? 1 : 0;
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ~ISPPRV_PCR_NFEN);
+ isp_prev->nf_en = enable ? 1 : 0;
}
EXPORT_SYMBOL_GPL(isppreview_enable_noisefilter);
@@ -1066,15 +1076,18 @@
* isppreview_enable_dcor - Enables/Disables the defect correction.
* @enable: 1 - Enables the defect correction.
**/
-void isppreview_enable_dcor(u8 enable)
+void isppreview_enable_dcor(struct isp_prev_device *isp_prev, u8 enable)
{
+ struct device *dev = to_device(isp_prev);
+
if (enable)
- isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_DCOREN);
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_DCOREN);
else {
- isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
~ISPPRV_PCR_DCOREN);
}
- ispprev_obj.dcor_en = enable ? 1 : 0;
+ isp_prev->dcor_en = enable ? 1 : 0;
}
EXPORT_SYMBOL_GPL(isppreview_enable_dcor);
@@ -1082,15 +1095,18 @@
* isppreview_enable_cfa - Enable/Disable the CFA Interpolation.
* @enable: 1 - Enables the CFA.
**/
-void isppreview_enable_cfa(u8 enable)
+void isppreview_enable_cfa(struct isp_prev_device *isp_prev, u8 enable)
{
+ struct device *dev = to_device(isp_prev);
+
if (enable)
- isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_CFAEN);
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_CFAEN);
else {
- isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
~ISPPRV_PCR_CFAEN);
}
- ispprev_obj.cfa_en = enable ? 1 : 0;
+ isp_prev->cfa_en = enable ? 1 : 0;
}
EXPORT_SYMBOL_GPL(isppreview_enable_cfa);
@@ -1099,13 +1115,15 @@
* @enable: 1 - Bypasses Gamma - 10bit input is cropped to 8MSB.
* 0 - Goes through Gamma Correction. input and output is 10bit.
**/
-void isppreview_enable_gammabypass(u8 enable)
+void isppreview_enable_gammabypass(struct isp_prev_device *isp_prev, u8 enable)
{
+ struct device *dev = to_device(isp_prev);
+
if (enable) {
- isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
ISPPRV_PCR_GAMMA_BYPASS);
} else {
- isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
~ISPPRV_PCR_GAMMA_BYPASS);
}
}
@@ -1115,16 +1133,19 @@
* isppreview_enable_luma_enhancement - Enables/Disables Luminance Enhancement
* @enable: 1 - Enable the Luminance Enhancement.
**/
-void isppreview_enable_luma_enhancement(u8 enable)
+void isppreview_enable_luma_enhancement(struct isp_prev_device *isp_prev,
+ u8 enable)
{
+ struct device *dev = to_device(isp_prev);
+
if (enable) {
- isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
ISPPRV_PCR_YNENHEN);
} else {
- isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
~ISPPRV_PCR_YNENHEN);
}
- ispprev_obj.yenh_en = enable ? 1 : 0;
+ isp_prev->yenh_en = enable ? 1 : 0;
}
EXPORT_SYMBOL_GPL(isppreview_enable_luma_enhancement);
@@ -1132,15 +1153,19 @@
* isppreview_enable_chroma_suppression - Enables/Disables Chrominance Suppr.
* @enable: 1 - Enable the Chrominance Suppression.
**/
-void isppreview_enable_chroma_suppression(u8 enable)
+void isppreview_enable_chroma_suppression(struct isp_prev_device *isp_prev,
+ u8 enable)
{
+ struct device *dev = to_device(isp_prev);
+
if (enable)
- isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_SUPEN);
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_SUPEN);
else {
- isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
~ISPPRV_PCR_SUPEN);
}
- ispprev_obj.csup_en = enable ? 1 : 0;
+ isp_prev->csup_en = enable ? 1 : 0;
}
EXPORT_SYMBOL_GPL(isppreview_enable_chroma_suppression);
@@ -1151,19 +1176,24 @@
*
* Coefficient matrix always with default values.
**/
-void isppreview_config_whitebalance(struct ispprev_wbal prev_wbal)
+void isppreview_config_whitebalance(struct isp_prev_device *isp_prev,
+ struct ispprev_wbal prev_wbal)
{
+ struct device *dev = to_device(isp_prev);
u32 val;
- isp_reg_writel(prev_wbal.dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
+ isp_reg_writel(dev, prev_wbal.dgain, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_WB_DGAIN);
val = prev_wbal.coef0 << ISPPRV_WBGAIN_COEF0_SHIFT;
val |= prev_wbal.coef1 << ISPPRV_WBGAIN_COEF1_SHIFT;
val |= prev_wbal.coef2 << ISPPRV_WBGAIN_COEF2_SHIFT;
val |= prev_wbal.coef3 << ISPPRV_WBGAIN_COEF3_SHIFT;
- isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_WBGAIN);
- isp_reg_writel(ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
+ isp_reg_writel(dev,
+ ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT |
ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT |
ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT |
@@ -1190,17 +1220,20 @@
*
* Coefficient matrix can be changed.
**/
-void isppreview_config_whitebalance2(struct prev_white_balance prev_wbal)
+void isppreview_config_whitebalance2(struct isp_prev_device *isp_prev,
+ struct prev_white_balance prev_wbal)
{
- isp_reg_writel(prev_wbal.wb_dgain,
+ struct device *dev = to_device(isp_prev);
+
+ isp_reg_writel(dev, prev_wbal.wb_dgain,
OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
- isp_reg_writel(prev_wbal.wb_gain[0] |
+ isp_reg_writel(dev, prev_wbal.wb_gain[0] |
prev_wbal.wb_gain[1] << ISPPRV_WBGAIN_COEF1_SHIFT |
prev_wbal.wb_gain[2] << ISPPRV_WBGAIN_COEF2_SHIFT |
prev_wbal.wb_gain[3] << ISPPRV_WBGAIN_COEF3_SHIFT,
OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
- isp_reg_writel(
+ isp_reg_writel(dev,
prev_wbal.wb_coefmatrix[0][0] << ISPPRV_WBSEL_N0_0_SHIFT |
prev_wbal.wb_coefmatrix[0][1] << ISPPRV_WBSEL_N0_1_SHIFT |
prev_wbal.wb_coefmatrix[0][2] << ISPPRV_WBSEL_N0_2_SHIFT |
@@ -1226,9 +1259,12 @@
* @prev_blkadj: Structure containing the black adjustment towards red, green,
* blue.
**/
-void isppreview_config_blkadj(struct ispprev_blkadj prev_blkadj)
+void isppreview_config_blkadj(struct isp_prev_device *isp_prev,
+ struct ispprev_blkadj prev_blkadj)
{
- isp_reg_writel(prev_blkadj.blue |
+ struct device *dev = to_device(isp_prev);
+
+ isp_reg_writel(dev, prev_blkadj.blue |
(prev_blkadj.green << ISPPRV_BLKADJOFF_G_SHIFT) |
(prev_blkadj.red << ISPPRV_BLKADJOFF_R_SHIFT),
OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF);
@@ -1240,35 +1276,44 @@
* @rgb2rgb: Structure containing the rgb to rgb blending matrix and the rgb
* offset.
**/
-void isppreview_config_rgb_blending(struct ispprev_rgbtorgb rgb2rgb)
+void isppreview_config_rgb_blending(struct isp_prev_device *isp_prev,
+ struct ispprev_rgbtorgb rgb2rgb)
{
+ struct device *dev = to_device(isp_prev);
u32 val = 0;
val = (rgb2rgb.matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT;
val |= (rgb2rgb.matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT;
- isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_MAT1);
val = (rgb2rgb.matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT;
val |= (rgb2rgb.matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT;
- isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_MAT2);
val = (rgb2rgb.matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT;
val |= (rgb2rgb.matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT;
- isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_MAT3);
val = (rgb2rgb.matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT;
val |= (rgb2rgb.matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT;
- isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_MAT4);
val = (rgb2rgb.matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT;
- isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_MAT5);
- val = (rgb2rgb.offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
- val |= (rgb2rgb.offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
- isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1);
+ val = (rgb2rgb.offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
+ val |= (rgb2rgb.offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_OFF1);
val = (rgb2rgb.offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT;
- isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_OFF2);
}
EXPORT_SYMBOL_GPL(isppreview_config_rgb_blending);
@@ -1277,29 +1322,32 @@
* @prev_csc: Structure containing the RGB to YCbYCr matrix and the
* YCbCr offset.
**/
-void isppreview_config_rgb_to_ycbcr(struct ispprev_csc prev_csc)
+void isppreview_config_rgb_to_ycbcr(struct isp_prev_device *isp_prev,
+ struct ispprev_csc prev_csc)
{
+ struct device *dev = to_device(isp_prev);
u32 val = 0;
val = (prev_csc.matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
val |= (prev_csc.matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT;
val |= (prev_csc.matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT;
- isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
val = (prev_csc.matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT;
val |= (prev_csc.matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT;
val |= (prev_csc.matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT;
- isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
val = (prev_csc.matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT;
val |= (prev_csc.matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT;
val |= (prev_csc.matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT;
- isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
- val = (prev_csc.offset[0] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
+ val = (prev_csc.offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
val |= (prev_csc.offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT;
- val |= (prev_csc.offset[2] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
- isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
+ val |= (prev_csc.offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_CSC_OFFSET);
}
EXPORT_SYMBOL_GPL(isppreview_config_rgb_to_ycbcr);
@@ -1307,11 +1355,13 @@
* isppreview_query_contrast - Query the contrast.
* @contrast: Pointer to hold the current programmed contrast value.
**/
-void isppreview_query_contrast(u8 *contrast)
+void isppreview_query_contrast(struct isp_prev_device *isp_prev, u8 *contrast)
{
+ struct device *dev = to_device(isp_prev);
u32 brt_cnt_val = 0;
- brt_cnt_val = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT);
+ brt_cnt_val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_CNT_BRT);
*contrast = (brt_cnt_val >> ISPPRV_CNT_BRT_CNT_SHIFT) & 0xff;
DPRINTK_ISPPREV(" Current brt cnt value in hw is %x\n", brt_cnt_val);
}
@@ -1323,9 +1373,9 @@
*
* Value should be programmed before enabling the module.
**/
-void isppreview_update_contrast(u8 *contrast)
+void isppreview_update_contrast(struct isp_prev_device *isp_prev, u8 *contrast)
{
- ispprev_obj.contrast = *contrast;
+ isp_prev->contrast = *contrast;
}
EXPORT_SYMBOL_GPL(isppreview_update_contrast);
@@ -1335,14 +1385,17 @@
*
* Value should be programmed before enabling the module.
**/
-void isppreview_config_contrast(u8 contrast)
+void isppreview_config_contrast(struct isp_prev_device *isp_prev, u8 contrast)
{
+ struct device *dev = to_device(isp_prev);
u32 brt_cnt_val = 0;
- brt_cnt_val = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT);
+ brt_cnt_val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_CNT_BRT);
brt_cnt_val &= ~(0xff << ISPPRV_CNT_BRT_CNT_SHIFT);
contrast &= 0xff;
- isp_reg_writel(brt_cnt_val | contrast << ISPPRV_CNT_BRT_CNT_SHIFT,
+ isp_reg_writel(dev,
+ brt_cnt_val | contrast << ISPPRV_CNT_BRT_CNT_SHIFT,
OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT);
}
EXPORT_SYMBOL_GPL(isppreview_config_contrast);
@@ -1364,9 +1417,10 @@
* @brightness: Pointer to hold the current programmed brightness value.
*
**/
-void isppreview_update_brightness(u8 *brightness)
+void isppreview_update_brightness(struct isp_prev_device *isp_prev,
+ u8 *brightness)
{
- ispprev_obj.brightness = *brightness;
+ isp_prev->brightness = *brightness;
}
EXPORT_SYMBOL_GPL(isppreview_update_brightness);
@@ -1374,15 +1428,19 @@
* isppreview_config_brightness - Configures the brightness.
* @contrast: 8bitvalue in U8Q0 format.
**/
-void isppreview_config_brightness(u8 brightness)
+void isppreview_config_brightness(struct isp_prev_device *isp_prev,
+ u8 brightness)
{
+ struct device *dev = to_device(isp_prev);
u32 brt_cnt_val = 0;
DPRINTK_ISPPREV("\tConfiguring brightness in ISP: %d\n", brightness);
- brt_cnt_val = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT);
+ brt_cnt_val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_CNT_BRT);
brt_cnt_val &= ~(0xff << ISPPRV_CNT_BRT_BRT_SHIFT);
brightness &= 0xff;
- isp_reg_writel(brt_cnt_val | brightness << ISPPRV_CNT_BRT_BRT_SHIFT,
+ isp_reg_writel(dev,
+ brt_cnt_val | brightness << ISPPRV_CNT_BRT_BRT_SHIFT,
OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT);
}
EXPORT_SYMBOL_GPL(isppreview_config_brightness);
@@ -1391,9 +1449,13 @@
* isppreview_query_brightness - Query the brightness.
* @brightness: Pointer to hold the current programmed brightness value.
**/
-void isppreview_query_brightness(u8 *brightness)
+void isppreview_query_brightness(struct isp_prev_device *isp_prev,
+ u8 *brightness)
{
- *brightness = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT);
+ struct device *dev = to_device(isp_prev);
+
+ *brightness = isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_CNT_BRT);
}
EXPORT_SYMBOL_GPL(isppreview_query_brightness);
@@ -1413,10 +1475,10 @@
* isppreview_set_color - Sets the color effect.
* @mode: Indicates the required color effect.
**/
-void isppreview_set_color(u8 *mode)
+void isppreview_set_color(struct isp_prev_device *isp_prev, u8 *mode)
{
- ispprev_obj.color = *mode;
- update_color_matrix = 1;
+ isp_prev->color = *mode;
+ isp_prev->update_color_matrix = 1;
}
EXPORT_SYMBOL_GPL(isppreview_set_color);
@@ -1424,9 +1486,9 @@
* isppreview_get_color - Gets the current color effect.
* @mode: Indicates the current color effect.
**/
-void isppreview_get_color(u8 *mode)
+void isppreview_get_color(struct isp_prev_device *isp_prev, u8 *mode)
{
- *mode = ispprev_obj.color;
+ *mode = isp_prev->color;
}
EXPORT_SYMBOL_GPL(isppreview_get_color);
@@ -1434,9 +1496,13 @@
* isppreview_config_yc_range - Configures the max and min Y and C values.
* @yclimit: Structure containing the range of Y and C values.
**/
-void isppreview_config_yc_range(struct ispprev_yclimit yclimit)
+void isppreview_config_yc_range(struct isp_prev_device *isp_prev,
+ struct ispprev_yclimit yclimit)
{
- isp_reg_writel(yclimit.maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
+ struct device *dev = to_device(isp_prev);
+
+ isp_reg_writel(dev,
+ yclimit.maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
yclimit.maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
yclimit.minC << ISPPRV_SETUP_YC_MINC_SHIFT |
yclimit.minY << ISPPRV_SETUP_YC_MINY_SHIFT,
@@ -1454,18 +1520,19 @@
* Calculates the number of pixels cropped in the submodules that are enabled,
* Fills up the output width height variables in the isp_prev structure.
**/
-int isppreview_try_size(u32 input_w, u32 input_h, u32 *output_w, u32 *output_h)
+int isppreview_try_pipeline(struct isp_prev_device *isp_prev,
+ struct isp_pipeline *pipe)
{
- u32 prevout_w = input_w;
- u32 prevout_h = input_h;
+ struct device *dev = to_device(isp_prev);
u32 div = 0;
int max_out;
+ unsigned int wanted_width;
+ unsigned int wanted_height;
+ unsigned int left_boundary;
+ unsigned int right_boundary;
- ispprev_obj.previn_w = input_w;
- ispprev_obj.previn_h = input_h;
-
- if (input_w < 32 || input_h < 32) {
- printk(KERN_ERR "ISP_ERR : preview does not support "
+ if (pipe->ccdc_out_w_img < 32 || pipe->ccdc_out_h < 32) {
+ dev_err(dev, "preview does not support "
"width < 16 or height < 32 \n");
return -EINVAL;
}
@@ -1474,75 +1541,84 @@
else
max_out = ISPPRV_MAXOUTPUT_WIDTH_ES2;
- ispprev_obj.fmtavg = 0;
+ wanted_width = pipe->prv_out_w;
+ wanted_height = pipe->prv_out_h;
+ pipe->prv_out_w = pipe->ccdc_out_w;
+ pipe->prv_out_h = pipe->ccdc_out_h;
+ pipe->prv_out_w_img = pipe->ccdc_out_w_img;
+ pipe->prv_out_h_img = pipe->ccdc_out_h;
- if (input_w > max_out) {
- div = (input_w/max_out);
- if (div >= 2 && div < 4) {
- ispprev_obj.fmtavg = 1;
- prevout_w /= 2;
- } else if (div >= 4 && div < 8) {
- ispprev_obj.fmtavg = 2;
- prevout_w /= 4;
- } else if (div >= 8) {
- ispprev_obj.fmtavg = 3;
- prevout_w /= 8;
- }
- }
-
- if (ispprev_obj.hmed_en)
- prevout_w -= 4;
- if (ispprev_obj.nf_en) {
- prevout_w -= 4;
- prevout_h -= 4;
- }
- if (ispprev_obj.cfa_en) {
- switch (ispprev_obj.cfafmt) {
- case CFAFMT_BAYER:
- case CFAFMT_SONYVGA:
- prevout_w -= 4;
- prevout_h -= 4;
- break;
- case CFAFMT_RGBFOVEON:
- case CFAFMT_RRGGBBFOVEON:
- case CFAFMT_DNSPL:
- case CFAFMT_HONEYCOMB:
- prevout_h -= 2;
- break;
- };
- }
- if (ispprev_obj.yenh_en || ispprev_obj.csup_en)
- prevout_w -= 2;
+/* if (isp_prev->hmed_en) */
+ pipe->prv_out_w_img -= 4;
+/* if (isp_prev->nf_en) */
+ pipe->prv_out_w_img -= 4;
+ pipe->prv_out_h_img -= 4;
+/* if (isp_prev->cfa_en) */
+ switch (isp_prev->cfafmt) {
+ case CFAFMT_BAYER:
+ case CFAFMT_SONYVGA:
+ pipe->prv_out_w_img -= 4;
+ pipe->prv_out_h_img -= 4;
+ break;
+ case CFAFMT_RGBFOVEON:
+ case CFAFMT_RRGGBBFOVEON:
+ case CFAFMT_DNSPL:
+ case CFAFMT_HONEYCOMB:
+ pipe->prv_out_h_img -= 2;
+ break;
+ };
+/* if (isp_prev->yenh_en || isp_prev->csup_en) */
+ pipe->prv_out_w_img -= 2;
/* Start at the correct row/column by skipping
* a Sensor specific amount.
*/
- prevout_w -= ispprev_obj.sph;
- prevout_h -= ispprev_obj.slv;
+ pipe->prv_out_w_img -= isp_prev->sph;
+ pipe->prv_out_h_img -= isp_prev->slv;
-
- if (prevout_w % 2)
- prevout_w -= 1;
-
- if (ispprev_obj.prev_outfmt == PREVIEW_MEM) {
- if (((prevout_w * 2) & ISP_32B_BOUNDARY_OFFSET) !=
- (prevout_w * 2)) {
- prevout_w = ((prevout_w * 2) &
- ISP_32B_BOUNDARY_OFFSET) / 2;
- }
+ div = DIV_ROUND_UP(pipe->ccdc_out_w_img, max_out);
+ if (div == 1) {
+ pipe->prv_fmt_avg = 0;
+ } else if (div <= 2) {
+ pipe->prv_fmt_avg = 1;
+ pipe->prv_out_w_img /= 2;
+ } else if (div <= 4) {
+ pipe->prv_fmt_avg = 2;
+ pipe->prv_out_w_img /= 4;
+ } else if (div <= 8) {
+ pipe->prv_fmt_avg = 3;
+ pipe->prv_out_w_img /= 8;
+ } else {
+ return -EINVAL;
}
- *output_w = prevout_w;
- ispprev_obj.prevout_w = prevout_w;
- *output_h = prevout_h;
- ispprev_obj.prevout_h = prevout_h;
+
+ /* output width must be even */
+ pipe->prv_out_w_img &= ~1;
+
+ if (pipe->modules == (OMAP_ISP_CCDC | OMAP_ISP_PREVIEW)) {
+ left_boundary = ALIGN(pipe->prv_out_w_img - 0x20, 0x20);
+ right_boundary = ALIGN(pipe->prv_out_w_img, 0x20);
+ if (wanted_width >= left_boundary &&
+ wanted_width <= right_boundary){
+ pipe->prv_out_w = ALIGN(wanted_width, 0x20);
+ pipe->prv_out_h = wanted_height;
+ } else {
+ pipe->prv_out_w = right_boundary;
+ pipe->prv_out_h = pipe->prv_out_h_img;
+ }
+ } else {
+ /* FIXME: This doesn't apply for prv -> rsz. */
+ pipe->prv_out_w = ALIGN(pipe->prv_out_w, 0x20);
+ }
+
return 0;
}
-EXPORT_SYMBOL_GPL(isppreview_try_size);
+EXPORT_SYMBOL_GPL(isppreview_try_pipeline);
/**
* isppreview_config_size - Sets the size of ISP preview output.
- * @input_w: input width for the preview in number of pixels per line
- * @input_h: input height for the preview in number of lines
+ * @pipe->ccdc_out_w: input width for the preview in number of pixels per line
+ * @pipe->ccdc_out_h: input height for the preview in number of lines
* @output_w: output width from the preview in number of pixels per line
* @output_h: output height for the preview in number of lines
*
@@ -1550,57 +1626,68 @@
* HORZ/VERT_INFO. Configures PRV_AVE if needed for downsampling as calculated
* in trysize.
**/
-int isppreview_config_size(u32 input_w, u32 input_h, u32 output_w, u32 output_h)
+int isppreview_s_pipeline(struct isp_prev_device *isp_prev,
+ struct isp_pipeline *pipe)
{
+ struct device *dev = to_device(isp_prev);
u32 prevsdroff;
+ int rval;
- if ((output_w != ispprev_obj.prevout_w) ||
- (output_h != ispprev_obj.prevout_h)) {
- printk(KERN_ERR "ISP_ERR : isppreview_try_size should "
- "be called before config size\n");
- return -EINVAL;
- }
+ rval = isppreview_config_datapath(isp_prev, pipe);
+ if (rval)
+ return rval;
- isp_reg_writel((ispprev_obj.sph << ISPPRV_HORZ_INFO_SPH_SHIFT) |
- (ispprev_obj.previn_w - 1),
+ isp_reg_writel(dev,
+ (isp_prev->sph << ISPPRV_HORZ_INFO_SPH_SHIFT) |
+ (pipe->ccdc_out_w - 1),
OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
- isp_reg_writel((ispprev_obj.slv << ISPPRV_VERT_INFO_SLV_SHIFT) |
- (ispprev_obj.previn_h - 1),
+ isp_reg_writel(dev,
+ (isp_prev->slv << ISPPRV_VERT_INFO_SLV_SHIFT) |
+ (pipe->ccdc_out_h - 1),
OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
- if (ispprev_obj.cfafmt == CFAFMT_BAYER)
- isp_reg_writel(ISPPRV_AVE_EVENDIST_2 <<
+ if (isp_prev->cfafmt == CFAFMT_BAYER)
+ isp_reg_writel(dev,
+ ISPPRV_AVE_EVENDIST_2 <<
ISPPRV_AVE_EVENDIST_SHIFT |
ISPPRV_AVE_ODDDIST_2 <<
ISPPRV_AVE_ODDDIST_SHIFT |
- ispprev_obj.fmtavg,
+ pipe->prv_fmt_avg,
OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
- if (ispprev_obj.prev_outfmt == PREVIEW_MEM) {
- prevsdroff = ispprev_obj.prevout_w * 2;
+ if (pipe->prv_out == PREVIEW_MEM) {
+ prevsdroff = pipe->prv_out_w * ISP_BYTES_PER_PIXEL;
if ((prevsdroff & ISP_32B_BOUNDARY_OFFSET) != prevsdroff) {
DPRINTK_ISPPREV("ISP_WARN: Preview output buffer line"
" size is truncated"
" to 32byte boundary\n");
prevsdroff &= ISP_32B_BOUNDARY_BUF ;
}
- isppreview_config_outlineoffset(prevsdroff);
+ isppreview_config_outlineoffset(isp_prev, prevsdroff);
}
+
+ if (pipe->pix.pixelformat == V4L2_PIX_FMT_UYVY)
+ isppreview_config_ycpos(isp_prev, YCPOS_YCrYCb);
+ else
+ isppreview_config_ycpos(isp_prev, YCPOS_CrYCbY);
+
return 0;
}
-EXPORT_SYMBOL_GPL(isppreview_config_size);
+EXPORT_SYMBOL_GPL(isppreview_s_pipeline);
/**
* isppreview_config_inlineoffset - Configures the Read address line offset.
* @offset: Line Offset for the input image.
**/
-int isppreview_config_inlineoffset(u32 offset)
+int isppreview_config_inlineoffset(struct isp_prev_device *isp_prev, u32 offset)
{
+ struct device *dev = to_device(isp_prev);
+
if ((offset & ISP_32B_BOUNDARY_OFFSET) == offset) {
- isp_reg_writel(offset & 0xffff,
+ isp_reg_writel(dev, offset & 0xffff,
OMAP3_ISP_IOMEM_PREV, ISPPRV_RADR_OFFSET);
} else {
- printk(KERN_ERR "ISP_ERR : Offset should be in 32 byte "
+ dev_err(dev, "preview: Offset should be in 32 byte "
"boundary\n");
return -EINVAL;
}
@@ -1614,12 +1701,15 @@
*
* Configures the memory address from which the input frame is to be read.
**/
-int isppreview_set_inaddr(u32 addr)
+int isppreview_set_inaddr(struct isp_prev_device *isp_prev, u32 addr)
{
+ struct device *dev = to_device(isp_prev);
+
if ((addr & ISP_32B_BOUNDARY_BUF) == addr)
- isp_reg_writel(addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
+ isp_reg_writel(dev, addr,
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
else {
- printk(KERN_ERR "ISP_ERR: Address should be in 32 byte "
+ dev_err(dev, "preview: Address should be in 32 byte "
"boundary\n");
return -EINVAL;
}
@@ -1631,14 +1721,17 @@
* isppreview_config_outlineoffset - Configures the Write address line offset.
* @offset: Line Offset for the preview output.
**/
-int isppreview_config_outlineoffset(u32 offset)
+int isppreview_config_outlineoffset(struct isp_prev_device *isp_prev,
+ u32 offset)
{
+ struct device *dev = to_device(isp_prev);
+
if ((offset & ISP_32B_BOUNDARY_OFFSET) != offset) {
- printk(KERN_ERR "ISP_ERR : Offset should be in 32 byte "
+ dev_err(dev, "preview: Offset should be in 32 byte "
"boundary\n");
return -EINVAL;
}
- isp_reg_writel(offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
+ isp_reg_writel(dev, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
ISPPRV_WADD_OFFSET);
return 0;
}
@@ -1650,14 +1743,17 @@
*
* Configures the memory address to which the output frame is written.
**/
-int isppreview_set_outaddr(u32 addr)
+int isppreview_set_outaddr(struct isp_prev_device *isp_prev, u32 addr)
{
+ struct device *dev = to_device(isp_prev);
+
if ((addr & ISP_32B_BOUNDARY_BUF) != addr) {
- printk(KERN_ERR "ISP_ERR: Address should be in 32 byte "
+ dev_err(dev, "preview: Address should be in 32 byte "
"boundary\n");
return -EINVAL;
}
- isp_reg_writel(addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
+ isp_reg_writel(dev, addr, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_WSDR_ADDR);
return 0;
}
EXPORT_SYMBOL_GPL(isppreview_set_outaddr);
@@ -1666,14 +1762,17 @@
* isppreview_config_darklineoffset - Sets the Dark frame address line offset.
* @offset: Line Offset for the Darkframe.
**/
-int isppreview_config_darklineoffset(u32 offset)
+int isppreview_config_darklineoffset(struct isp_prev_device *isp_prev,
+ u32 offset)
{
+ struct device *dev = to_device(isp_prev);
+
if ((offset & ISP_32B_BOUNDARY_OFFSET) != offset) {
- printk(KERN_ERR "ISP_ERR : Offset should be in 32 byte "
+ dev_err(dev, "preview: Offset should be in 32 byte "
"boundary\n");
return -EINVAL;
}
- isp_reg_writel(offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
+ isp_reg_writel(dev, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
ISPPRV_DRKF_OFFSET);
return 0;
}
@@ -1683,96 +1782,71 @@
* isppreview_set_darkaddr - Sets the memory address to store Dark frame.
* @addr: 32bit memory address aligned on 32 bit boundary.
**/
-int isppreview_set_darkaddr(u32 addr)
+int isppreview_set_darkaddr(struct isp_prev_device *isp_prev, u32 addr)
{
+ struct device *dev = to_device(isp_prev);
+
if ((addr & ISP_32B_BOUNDARY_BUF) != addr) {
- printk(KERN_ERR "ISP_ERR : Address should be in 32 byte "
+ dev_err(dev, "preview: Address should be in 32 byte "
"boundary\n");
return -EINVAL;
}
- isp_reg_writel(addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_DSDR_ADDR);
+ isp_reg_writel(dev, addr, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_DSDR_ADDR);
return 0;
}
EXPORT_SYMBOL_GPL(isppreview_set_darkaddr);
-void __isppreview_enable(int enable)
-{
- if (enable)
- isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_EN);
- else
- isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ~ISPPRV_PCR_EN);
-}
-
/**
* isppreview_enable - Enables the Preview module.
* @enable: 1 - Enables the preview module.
*
* Client should configure all the sub modules in Preview before this.
**/
-void isppreview_enable(int enable)
+void isppreview_enable(struct isp_prev_device *isp_prev, int enable)
{
- __isppreview_enable(enable);
- ispprev_obj.pm_state = enable;
+ struct device *dev = to_device(isp_prev);
+
+ if (enable)
+ isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT);
+ else
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ~(ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT));
}
EXPORT_SYMBOL_GPL(isppreview_enable);
/**
- * isppreview_suspend - Suspend Preview module.
- **/
-void isppreview_suspend(void)
-{
- if (ispprev_obj.pm_state)
- __isppreview_enable(0);
-}
-EXPORT_SYMBOL_GPL(isppreview_suspend);
-
-/**
- * isppreview_resume - Resume Preview module.
- **/
-void isppreview_resume(void)
-{
- if (ispprev_obj.pm_state)
- __isppreview_enable(1);
-}
-EXPORT_SYMBOL_GPL(isppreview_resume);
-
-
-/**
* isppreview_busy - Gets busy state of preview module.
**/
-int isppreview_busy(void)
+int isppreview_busy(struct isp_prev_device *isp_prev)
{
- return isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR) &
- ISPPRV_PCR_BUSY;
+ struct device *dev = to_device(isp_prev);
+
+ return isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR)
+ & ISPPRV_PCR_BUSY;
}
EXPORT_SYMBOL_GPL(isppreview_busy);
/**
- * isppreview_get_config - Gets parameters of preview module.
- **/
-struct prev_params *isppreview_get_config(void)
-{
- return prev_config_params;
-}
-EXPORT_SYMBOL_GPL(isppreview_get_config);
-
-/**
* isppreview_save_context - Saves the values of the preview module registers.
**/
-void isppreview_save_context(void)
+void isppreview_save_context(struct device *dev)
{
DPRINTK_ISPPREV("Saving context\n");
- isp_save_context(ispprev_reg_list);
+ isp_save_context(dev, ispprev_reg_list);
+ /* Avoid unwanted enabling when restoring the context. */
+ ispprev_reg_list[0].val &= ~ISPPRV_PCR_EN;
}
EXPORT_SYMBOL_GPL(isppreview_save_context);
/**
* isppreview_restore_context - Restores the values of preview module registers
**/
-void isppreview_restore_context(void)
+void isppreview_restore_context(struct device *dev)
{
DPRINTK_ISPPREV("Restoring context\n");
- isp_restore_context(ispprev_reg_list);
+ isp_restore_context(dev, ispprev_reg_list);
}
EXPORT_SYMBOL_GPL(isppreview_restore_context);
@@ -1781,119 +1855,137 @@
*
* Also prints other debug information stored in the preview moduel.
**/
-void isppreview_print_status(void)
+void isppreview_print_status(struct isp_prev_device *isp_prev,
+ struct isp_pipeline *pipe)
{
- DPRINTK_ISPPREV("Module in use =%d\n", ispprev_obj.prev_inuse);
+#ifdef OMAP_ISPPREV_DEBUG
+ struct device *dev = to_device(isp_prev);
+#endif
+
DPRINTK_ISPPREV("Preview Input format =%d, Output Format =%d\n",
- ispprev_obj.prev_inpfmt,
- ispprev_obj.prev_outfmt);
- DPRINTK_ISPPREV("Accepted Preview Input (width = %d,Height = %d)\n",
- ispprev_obj.previn_w,
- ispprev_obj.previn_h);
+ pipe->prv_in, pipe->prv_out);
+ DPRINTK_ISPPREV("Accepted CCDC Output (width = %d,Height = %d)\n",
+ pipe->ccdc_out_w,
+ pipe->ccdc_out_h);
DPRINTK_ISPPREV("Accepted Preview Output (width = %d,Height = %d)\n",
- ispprev_obj.prevout_w,
- ispprev_obj.prevout_h);
+ pipe->prv_out_w,
+ pipe->prv_out_h);
DPRINTK_ISPPREV("###ISP_CTRL in preview =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_CTRL));
DPRINTK_ISPPREV("###ISP_IRQ0ENABLE in preview =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_IRQ0ENABLE));
DPRINTK_ISPPREV("###ISP_IRQ0STATUS in preview =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+ ISP_IRQ0STATUS));
DPRINTK_ISPPREV("###PRV PCR =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_PCR));
DPRINTK_ISPPREV("###PRV HORZ_INFO =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_HORZ_INFO));
DPRINTK_ISPPREV("###PRV VERT_INFO =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_VERT_INFO));
DPRINTK_ISPPREV("###PRV WSDR_ADDR =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_WSDR_ADDR));
DPRINTK_ISPPREV("###PRV WADD_OFFSET =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV,
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
ISPPRV_WADD_OFFSET));
DPRINTK_ISPPREV("###PRV AVE =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_AVE));
DPRINTK_ISPPREV("###PRV HMED =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_HMED));
DPRINTK_ISPPREV("###PRV NF =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_NF));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_NF));
DPRINTK_ISPPREV("###PRV WB_DGAIN =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_WB_DGAIN));
DPRINTK_ISPPREV("###PRV WBGAIN =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_WBGAIN));
DPRINTK_ISPPREV("###PRV WBSEL =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_WBSEL));
DPRINTK_ISPPREV("###PRV CFA =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_CFA));
DPRINTK_ISPPREV("###PRV BLKADJOFF =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_BLKADJOFF));
DPRINTK_ISPPREV("###PRV RGB_MAT1 =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_MAT1));
DPRINTK_ISPPREV("###PRV RGB_MAT2 =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_MAT2));
DPRINTK_ISPPREV("###PRV RGB_MAT3 =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_MAT3));
DPRINTK_ISPPREV("###PRV RGB_MAT4 =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_MAT4));
DPRINTK_ISPPREV("###PRV RGB_MAT5 =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_MAT5));
DPRINTK_ISPPREV("###PRV RGB_OFF1 =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_OFF1));
DPRINTK_ISPPREV("###PRV RGB_OFF2 =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_RGB_OFF2));
DPRINTK_ISPPREV("###PRV CSC0 =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_CSC0));
DPRINTK_ISPPREV("###PRV CSC1 =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_CSC1));
DPRINTK_ISPPREV("###PRV CSC2 =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_CSC2));
DPRINTK_ISPPREV("###PRV CSC_OFFSET =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_CSC_OFFSET));
DPRINTK_ISPPREV("###PRV CNT_BRT =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_CNT_BRT));
DPRINTK_ISPPREV("###PRV CSUP =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_CSUP));
DPRINTK_ISPPREV("###PRV SETUP_YC =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC));
+ isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_SETUP_YC));
}
EXPORT_SYMBOL_GPL(isppreview_print_status);
/**
* isp_preview_init - Module Initialization.
**/
-int __init isp_preview_init(void)
+int __init isp_preview_init(struct device *dev)
{
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_prev_device *isp_prev = &isp->isp_prev;
+ struct prev_params *params = &isp_prev->params;
int i = 0;
- prev_config_params = kmalloc(sizeof(*prev_config_params), GFP_KERNEL);
- if (!prev_config_params) {
- printk(KERN_ERR "Can't get memory for isp_preview params!\n");
- return -ENOMEM;
- }
-
- /* Dynamically allocate luma table */
- prev_config_params->ytable = kmalloc(ISPPRV_YENH_TBL_SIZE*sizeof(u32),
- GFP_KERNEL);
- if (!prev_config_params->ytable) {
- printk(KERN_ERR "Can't get memory for preview luna table!\n");
- kfree(prev_config_params);
- return -ENOMEM;
- }
-
- params = prev_config_params;
- ispprev_obj.prev_inuse = 0;
- mutex_init(&ispprev_obj.ispprev_mutex);
-
/* Init values */
- ispprev_obj.sph = 2;
- ispprev_obj.slv = 0;
- ispprev_obj.color = V4L2_COLORFX_NONE;
- ispprev_obj.contrast = ISPPRV_CONTRAST_DEF;
+ isp_prev->update_color_matrix = 0;
+ isp_prev->update_rgb_blending = 0;
+ isp_prev->update_rgb_to_ycbcr = 0;
+ isp_prev->sph = 2;
+ isp_prev->slv = 0;
+ isp_prev->color = V4L2_COLORFX_NONE;
+ isp_prev->contrast = ISPPRV_CONTRAST_DEF;
params->contrast = ISPPRV_CONTRAST_DEF;
- ispprev_obj.brightness = ISPPRV_BRIGHT_DEF;
+ isp_prev->brightness = ISPPRV_BRIGHT_DEF;
params->brightness = ISPPRV_BRIGHT_DEF;
params->average = NO_AVE;
params->lens_shading_shift = 0;
- params->pix_fmt = YCPOS_YCrYCb;
params->cfa.cfafmt = CFAFMT_BAYER;
params->cfa.cfa_table = cfa_coef_table;
params->cfa.cfa_gradthrs_horz = FLR_CFA_GRADTHRS_HORZ;
@@ -1901,7 +1993,7 @@
params->csup.gain = FLR_CSUP_GAIN;
params->csup.thres = FLR_CSUP_THRES;
params->csup.hypf_en = 0;
- isppreview_set_luma_enhancement(luma_enhance_table);
+ params->ytable = luma_enhance_table;
params->nf.spread = FLR_NF_STRGTH;
memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table));
params->dcor.couplet_mode_en = 1;
@@ -1926,7 +2018,7 @@
params->blk_adj.green = FLR_BLKADJ_GREEN;
params->blk_adj.blue = FLR_BLKADJ_BLUE;
params->rgb2rgb = flr_rgb2rgb;
- params->rgb2ycbcr = flr_prev_csc[ispprev_obj.color];
+ params->rgb2ycbcr = flr_prev_csc[isp_prev->color];
params->features = PREV_CFA | PREV_DEFECT_COR | PREV_NOISE_FILTER;
params->features &= ~(PREV_AVERAGER | PREV_INVERSE_ALAW |
@@ -1937,14 +2029,8 @@
PREV_DARK_FRAME_CAPTURE |
PREV_CHROMA_SUPPRESS |
PREV_LUMA_ENHANCE);
- return 0;
-}
-/**
- * isp_preview_cleanup - Module Cleanup.
- **/
-void isp_preview_cleanup(void)
-{
- kfree(prev_config_params->ytable);
- kfree(prev_config_params);
+ spin_lock_init(&isp_prev->lock);
+
+ return 0;
}
diff --git a/drivers/media/video/isp/isppreview.h b/drivers/media/video/isp/isppreview.h
index eb7d92a..2ea1aba 100644
--- a/drivers/media/video/isp/isppreview.h
+++ b/drivers/media/video/isp/isppreview.h
@@ -162,7 +162,6 @@
/**
* struct prev_params - Structure for all configuration
* @features: Set of features enabled.
- * @pix_fmt: Output pixel format.
* @cfa: CFA coefficients.
* @csup: Chroma suppression coefficients.
* @ytable: Pointer to Luma enhancement coefficients.
@@ -212,6 +211,8 @@
* @red_gamma: Pointer to red gamma correction table.
* @green_gamma: Pointer to green gamma correction table.
* @blue_gamma: Pointer to blue gamma correction table.
+ * @prev_cfa: Pointer to color filter array configuration.
+ * @prev_wbal: Pointer to colour and digital gain configuration.
*/
struct isptables_update {
u16 update;
@@ -221,136 +222,197 @@
u32 *red_gamma;
u32 *green_gamma;
u32 *blue_gamma;
+ struct ispprev_cfa *prev_cfa;
+ struct ispprev_wbal *prev_wbal;
};
-void isppreview_config_shadow_registers(void);
+/**
+ * struct isp_prev_device - Structure for storing ISP Preview module information
+ * @prevout_w: Preview output width.
+ * @prevout_h: Preview output height.
+ * @previn_w: Preview input width.
+ * @previn_h: Preview input height.
+ * @prev_inpfmt: Preview input format.
+ * @prev_outfmt: Preview output format.
+ * @hmed_en: Horizontal median filter enable.
+ * @nf_en: Noise filter enable.
+ * @dcor_en: Defect correction enable.
+ * @cfa_en: Color Filter Array (CFA) interpolation enable.
+ * @csup_en: Chrominance suppression enable.
+ * @yenh_en: Luma enhancement enable.
+ * @fmtavg: Number of horizontal pixels to average in input formatter. The
+ * input width should be a multiple of this number.
+ * @brightness: Brightness in preview module.
+ * @contrast: Contrast in preview module.
+ * @color: Color effect in preview module.
+ * @cfafmt: Color Filter Array (CFA) Format.
+ * @wbal_update: Update digital and colour gains in Previewer
+ *
+ * This structure is used to store the OMAP ISP Preview module Information.
+ */
+struct isp_prev_device {
+ int update_color_matrix;
+ u8 update_rgb_blending;
+ u8 update_rgb_to_ycbcr;
+ u8 hmed_en;
+ u8 nf_en;
+ u8 dcor_en;
+ u8 cfa_en;
+ u8 csup_en;
+ u8 yenh_en;
+ u8 rg_update;
+ u8 gg_update;
+ u8 bg_update;
+ u8 cfa_update;
+ u8 nf_enable;
+ u8 nf_update;
+ u8 wbal_update;
+ u8 fmtavg;
+ u8 brightness;
+ u8 contrast;
+ enum v4l2_colorfx color;
+ enum cfa_fmt cfafmt;
+ struct ispprev_nf prev_nf_t;
+ struct prev_params params;
+ int shadow_update;
+ u32 sph;
+ u32 slv;
+ spinlock_t lock;
+};
-int isppreview_request(void);
+void isppreview_config_shadow_registers(struct isp_prev_device *isp_prev);
-int isppreview_free(void);
+int isppreview_request(struct isp_prev_device *isp_prev);
-int isppreview_config_datapath(enum preview_input input,
- enum preview_output output);
+void isppreview_free(struct isp_prev_device *isp_prev);
-void isppreview_config_ycpos(enum preview_ycpos_mode mode);
+int isppreview_config_datapath(struct isp_prev_device *isp_prev,
+ struct isp_pipeline *pipe);
-void isppreview_config_averager(u8 average);
+void isppreview_config_ycpos(struct isp_prev_device *isp_prev,
+ enum preview_ycpos_mode mode);
-void isppreview_enable_invalaw(u8 enable);
+void isppreview_config_averager(struct isp_prev_device *isp_prev, u8 average);
-void isppreview_enable_drkframe(u8 enable);
+void isppreview_enable_invalaw(struct isp_prev_device *isp_prev, u8 enable);
-void isppreview_enable_shadcomp(u8 enable);
+void isppreview_enable_drkframe(struct isp_prev_device *isp_prev, u8 enable);
-void isppreview_config_drkf_shadcomp(u8 scomp_shtval);
+void isppreview_enable_shadcomp(struct isp_prev_device *isp_prev, u8 enable);
-void isppreview_enable_gammabypass(u8 enable);
+void isppreview_config_drkf_shadcomp(struct isp_prev_device *isp_prev,
+ u8 scomp_shtval);
-void isppreview_enable_hmed(u8 enable);
+void isppreview_enable_gammabypass(struct isp_prev_device *isp_prev, u8 enable);
-void isppreview_config_hmed(struct ispprev_hmed);
+void isppreview_enable_hmed(struct isp_prev_device *isp_prev, u8 enable);
-void isppreview_enable_noisefilter(u8 enable);
+void isppreview_config_hmed(struct isp_prev_device *isp_prev,
+ struct ispprev_hmed);
-void isppreview_config_noisefilter(struct ispprev_nf prev_nf);
+void isppreview_enable_noisefilter(struct isp_prev_device *isp_prev, u8 enable);
-void isppreview_enable_dcor(u8 enable);
+void isppreview_config_noisefilter(struct isp_prev_device *isp_prev,
+ struct ispprev_nf prev_nf);
-void isppreview_config_dcor(struct ispprev_dcor prev_dcor);
+void isppreview_enable_dcor(struct isp_prev_device *isp_prev, u8 enable);
+
+void isppreview_config_dcor(struct isp_prev_device *isp_prev,
+ struct ispprev_dcor prev_dcor);
-void isppreview_config_cfa(struct ispprev_cfa);
+void isppreview_config_cfa(struct isp_prev_device *isp_prev,
+ struct ispprev_cfa);
-void isppreview_config_gammacorrn(struct ispprev_gtable);
+void isppreview_config_gammacorrn(struct isp_prev_device *isp_prev,
+ struct ispprev_gtable);
-void isppreview_config_chroma_suppression(struct ispprev_csup csup);
+void isppreview_config_chroma_suppression(struct isp_prev_device *isp_prev,
+ struct ispprev_csup csup);
-void isppreview_enable_cfa(u8 enable);
+void isppreview_enable_cfa(struct isp_prev_device *isp_prev, u8 enable);
-void isppreview_set_luma_enhancement(u32 *ytable);
+void isppreview_config_luma_enhancement(struct isp_prev_device *isp_prev,
+ u32 *ytable);
-void isppreview_config_luma_enhancement(u32 *ytable);
+void isppreview_enable_luma_enhancement(struct isp_prev_device *isp_prev,
+ u8 enable);
-void isppreview_enable_luma_enhancement(u8 enable);
+void isppreview_enable_chroma_suppression(struct isp_prev_device *isp_prev,
+ u8 enable);
-void isppreview_enable_chroma_suppression(u8 enable);
+void isppreview_config_whitebalance(struct isp_prev_device *isp_prev,
+ struct ispprev_wbal);
-void isppreview_config_whitebalance(struct ispprev_wbal);
+void isppreview_config_blkadj(struct isp_prev_device *isp_prev,
+ struct ispprev_blkadj);
-void isppreview_config_blkadj(struct ispprev_blkadj);
+void isppreview_config_rgb_blending(struct isp_prev_device *isp_prev,
+ struct ispprev_rgbtorgb);
-void isppreview_config_rgb_blending(struct ispprev_rgbtorgb);
+void isppreview_config_rgb_to_ycbcr(struct isp_prev_device *isp_prev,
+ struct ispprev_csc);
-void isppreview_config_rgb_to_ycbcr(struct ispprev_csc);
+void isppreview_update_contrast(struct isp_prev_device *isp_prev, u8 *contrast);
-void isppreview_update_contrast(u8 *contrast);
+void isppreview_query_contrast(struct isp_prev_device *isp_prev, u8 *contrast);
-void isppreview_query_contrast(u8 *contrast);
-
-void isppreview_config_contrast(u8 contrast);
+void isppreview_config_contrast(struct isp_prev_device *isp_prev, u8 contrast);
void isppreview_get_contrast_range(u8 *min_contrast, u8 *max_contrast);
-void isppreview_update_brightness(u8 *brightness);
+void isppreview_update_brightness(struct isp_prev_device *isp_prev,
+ u8 *brightness);
-void isppreview_config_brightness(u8 brightness);
+void isppreview_config_brightness(struct isp_prev_device *isp_prev,
+ u8 brightness);
void isppreview_get_brightness_range(u8 *min_brightness, u8 *max_brightness);
-void isppreview_set_color(u8 *mode);
+void isppreview_set_color(struct isp_prev_device *isp_prev, u8 *mode);
-void isppreview_get_color(u8 *mode);
+void isppreview_get_color(struct isp_prev_device *isp_prev, u8 *mode);
-void isppreview_query_brightness(u8 *brightness);
+void isppreview_query_brightness(struct isp_prev_device *isp_prev,
+ u8 *brightness);
-void isppreview_config_yc_range(struct ispprev_yclimit yclimit);
+void isppreview_config_yc_range(struct isp_prev_device *isp_prev,
+ struct ispprev_yclimit yclimit);
-int isppreview_try_size(u32 input_w, u32 input_h, u32 *output_w,
- u32 *output_h);
+int isppreview_try_pipeline(struct isp_prev_device *isp_prev,
+ struct isp_pipeline *pipe);
-int isppreview_config_size(u32 input_w, u32 input_h, u32 output_w,
- u32 output_h);
+int isppreview_s_pipeline(struct isp_prev_device *isp_prev,
+ struct isp_pipeline *pipe);
-int isppreview_config_inlineoffset(u32 offset);
+int isppreview_config_inlineoffset(struct isp_prev_device *isp_prev,
+ u32 offset);
-int isppreview_set_inaddr(u32 addr);
+int isppreview_set_inaddr(struct isp_prev_device *isp_prev, u32 addr);
-int isppreview_config_outlineoffset(u32 offset);
+int isppreview_config_outlineoffset(struct isp_prev_device *isp_prev,
+ u32 offset);
-int isppreview_set_outaddr(u32 addr);
+int isppreview_set_outaddr(struct isp_prev_device *isp_prev, u32 addr);
-int isppreview_config_darklineoffset(u32 offset);
+int isppreview_config_darklineoffset(struct isp_prev_device *isp_prev,
+ u32 offset);
-int isppreview_set_darkaddr(u32 addr);
+int isppreview_set_darkaddr(struct isp_prev_device *isp_prev, u32 addr);
-void isppreview_enable(int enable);
+void isppreview_enable(struct isp_prev_device *isp_prev, int enable);
-void isppreview_suspend(void);
+int isppreview_busy(struct isp_prev_device *isp_prev);
-void isppreview_resume(void);
+void isppreview_print_status(struct isp_prev_device *isp_prev,
+ struct isp_pipeline *pipe);
-int isppreview_busy(void);
+void isppreview_save_context(struct device *dev);
-struct prev_params *isppreview_get_config(void);
+void isppreview_restore_context(struct device *dev);
-void isppreview_print_status(void);
+int isppreview_config(struct isp_prev_device *isp_prev, void *userspace_add);
-#ifndef CONFIG_ARCH_OMAP3410
-void isppreview_save_context(void);
-#else
-static inline void isppreview_save_context(void) {}
-#endif
-
-#ifndef CONFIG_ARCH_OMAP3410
-void isppreview_restore_context(void);
-#else
-static inline void isppreview_restore_context(void) {}
-#endif
-
-int omap34xx_isp_preview_config(void *userspace_add);
-
-int omap34xx_isp_tables_update(struct isptables_update *isptables_struct);
-
-void isppreview_set_skip(u32 h, u32 v);
+void isppreview_set_skip(struct isp_prev_device *isp_prev, u32 h, u32 v);
#endif/* OMAP_ISP_PREVIEW_H */
diff --git a/drivers/media/video/isp/ispreg.h b/drivers/media/video/isp/ispreg.h
index 4f8e1ef..2198a53 100644
--- a/drivers/media/video/isp/ispreg.h
+++ b/drivers/media/video/isp/ispreg.h
@@ -116,7 +116,7 @@
#define ISP_32B_BOUNDARY_BUF 0xFFFFFFE0
#define ISP_32B_BOUNDARY_OFFSET 0x0000FFE0
-#define CM_CAM_MCLK_HZ 216000000
+#define CM_CAM_MCLK_HZ 172800000 /* Hz */
/* ISP Submodules offset */
@@ -209,6 +209,18 @@
#define ISPCSI1_SYSSTATUS (0x008)
#define ISPCSI1_LC01_IRQENABLE (0x00C)
#define ISPCSI1_LC01_IRQSTATUS (0x010)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_FS_IRQ (1 << 11)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_LE_IRQ (1 << 10)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_LS_IRQ (1 << 9)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_FE_IRQ (1 << 8)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_COUNT_IRQ (1 << 7)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ (1 << 5)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_CRC_IRQ (1 << 4)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_FSP_IRQ (1 << 3)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_FW_IRQ (1 << 2)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_FSC_IRQ (1 << 1)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_SSC_IRQ (1 << 0)
+
#define ISPCSI1_LC23_IRQENABLE (0x014)
#define ISPCSI1_LC23_IRQSTATUS (0x018)
#define ISPCSI1_LCM_IRQENABLE (0x02C)
@@ -305,12 +317,32 @@
#define ISPCCDC_LSC_TABLE_OFFSET (0x0A4)
/* SBL */
+#define ISPSBL_PCR 0x4
+#define ISPSBL_PCR_H3A_AEAWB_WBL_OVF (1 << 16)
+#define ISPSBL_PCR_H3A_AF_WBL_OVF (1 << 17)
+#define ISPSBL_PCR_RSZ4_WBL_OVF (1 << 18)
+#define ISPSBL_PCR_RSZ3_WBL_OVF (1 << 19)
+#define ISPSBL_PCR_RSZ2_WBL_OVF (1 << 20)
+#define ISPSBL_PCR_RSZ1_WBL_OVF (1 << 21)
+#define ISPSBL_PCR_PRV_WBL_OVF (1 << 22)
+#define ISPSBL_PCR_CCDC_WBL_OVF (1 << 23)
+#define ISPSBL_PCR_CCDCPRV_2_RSZ_OVF (1 << 24)
+#define ISPSBL_PCR_CSIA_WBL_OVF (1 << 25)
+#define ISPSBL_PCR_CSIB_WBL_OVF (1 << 26)
#define ISPSBL_CCDC_WR_0 (0x028)
#define ISPSBL_CCDC_WR_0_DATA_READY (1 << 21)
#define ISPSBL_CCDC_WR_1 (0x02C)
#define ISPSBL_CCDC_WR_2 (0x030)
#define ISPSBL_CCDC_WR_3 (0x034)
+#define ISPSBL_SDR_REQ_EXP 0xF8
+#define ISPSBL_SDR_REQ_HIST_EXP_SHIFT 0
+#define ISPSBL_SDR_REQ_HIST_EXP_MASK (0x3FF)
+#define ISPSBL_SDR_REQ_RSZ_EXP_SHIFT 10
+#define ISPSBL_SDR_REQ_RSZ_EXP_MASK (0x3FF << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT)
+#define ISPSBL_SDR_REQ_PRV_EXP_SHIFT 20
+#define ISPSBL_SDR_REQ_PRV_EXP_MASK (0x3FF << ISPSBL_SDR_REQ_PRV_EXP_SHIFT)
+
/* Histogram registers */
#define ISPHIST_PID (0x000)
#define ISPHIST_PCR (0x004)
@@ -623,8 +655,9 @@
/* Define bit fields within selected registers */
#define ISP_REVISION_SHIFT 0
+#define ISP_REVISION_MASK 0xFF
-#define ISP_SYSCONFIG_AUTOIDLE 0
+#define ISP_SYSCONFIG_AUTOIDLE (1 << 0)
#define ISP_SYSCONFIG_SOFTRESET (1 << 1)
#define ISP_SYSCONFIG_MIDLEMODE_SHIFT 12
#define ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY 0x0
@@ -905,12 +938,13 @@
#define ISPCCDC_FMTCFG_VPIN_9_0 (0x6 << 12)
#define ISPCCDC_FMTCFG_VPEN (1 << 15)
-#define ISPCCDC_FMTCF_VPIF_FRQ_MASK 0xFFF8FFFF
-#define ISPCCDC_FMTCF_VPIF_FRQ_BY2 (0x0 << 16)
-#define ISPCCDC_FMTCF_VPIF_FRQ_BY3 (0x1 << 16)
-#define ISPCCDC_FMTCF_VPIF_FRQ_BY4 (0x2 << 16)
-#define ISPCCDC_FMTCF_VPIF_FRQ_BY5 (0x3 << 16)
-#define ISPCCDC_FMTCF_VPIF_FRQ_BY6 (0x4 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_MASK 0xFFF8FFFF
+#define ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT 16
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY2 (0x0 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY3 (0x1 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY4 (0x2 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY5 (0x3 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY6 (0x4 << 16)
#define ISPCCDC_FMT_HORZ_FMTLNH_SHIFT 0
#define ISPCCDC_FMT_HORZ_FMTSPH_SHIFT 16
@@ -932,8 +966,9 @@
#define ISPRSZ_PID_CID_SHIFT 8
#define ISPRSZ_PID_TID_SHIFT 16
-#define ISPRSZ_PCR_ENABLE 0x5
+#define ISPRSZ_PCR_ENABLE 1
#define ISPRSZ_PCR_BUSY (1 << 1)
+#define ISPRSZ_PCR_ONESHOT (1 << 2)
#define ISPRSZ_CNT_HRSZ_SHIFT 0
#define ISPRSZ_CNT_HRSZ_MASK 0x3FF
@@ -952,9 +987,9 @@
#define ISPRSZ_CNT_CBILIN (1 << 29)
#define ISPRSZ_OUT_SIZE_HORZ_SHIFT 0
-#define ISPRSZ_OUT_SIZE_HORZ_MASK 0x7FF
+#define ISPRSZ_OUT_SIZE_HORZ_MASK 0xFFF
#define ISPRSZ_OUT_SIZE_VERT_SHIFT 16
-#define ISPRSZ_OUT_SIZE_VERT_MASK 0x7FF0000
+#define ISPRSZ_OUT_SIZE_VERT_MASK 0xFFF0000
#define ISPRSZ_IN_START_HORZ_ST_SHIFT 0
@@ -1242,6 +1277,7 @@
#define ISPHIST_HV_INFO_MASK 0x3FFF3FFF
+#define ISPCCDC_LSC_ENABLE 1
#define ISPCCDC_LSC_GAIN_MODE_N_MASK 0x700
#define ISPCCDC_LSC_GAIN_MODE_N_SHIFT 8
#define ISPCCDC_LSC_GAIN_MODE_M_MASK 0x3800
@@ -1381,6 +1417,9 @@
#define ISPCSI2_DBG_H (0x044)
#define ISPCSI2_GNQ (0x048)
#define ISPCSI2_COMPLEXIO_CFG1 (0x050)
+#define ISPCSI2_COMPLEXIO_CFG1_RESET_CTRL_SHIFT 30
+#define ISPCSI2_COMPLEXIO_CFG1_RESET_CTRL_DEASSERTED \
+ (0x1 << ISPCSI2_COMPLEXIO_CFG1_RESET_CTRL_SHIFT)
#define ISPCSI2_COMPLEXIO_CFG1_RESET_DONE_SHIFT 29
#define ISPCSI2_COMPLEXIO_CFG1_RESET_DONE_MASK \
(0x1 << ISPCSI2_COMPLEXIO_CFG1_RESET_DONE_SHIFT)
@@ -1642,6 +1681,9 @@
#define ISPCSI2PHY_CFG0_THS_SETTLE_RESETVAL \
(0x27 << ISPCSI2PHY_CFG0_THS_SETTLE_SHIFT)
#define ISPCSI2PHY_CFG1 (0x004)
+#define ISPCSI2PHY_CFG1_RESETDONECTRLCLK_SHIFT 29
+#define ISPCSI2PHY_CFG1_RESETDONECTRLCLK_MASK \
+ (0x1 << ISPCSI2PHY_CFG1_RESETDONECTRLCLK_SHIFT)
#define ISPCSI2PHY_CFG1_TCLK_TERM_SHIFT 18
#define ISPCSI2PHY_CFG1_TCLK_TERM_MASK \
(0x7F << ISPCSI2PHY_CFG1_TCLK_TERM_SHIFT)
diff --git a/drivers/media/video/isp/ispresizer.c b/drivers/media/video/isp/ispresizer.c
index d437b40..78a1a64 100644
--- a/drivers/media/video/isp/ispresizer.c
+++ b/drivers/media/video/isp/ispresizer.c
@@ -20,13 +20,13 @@
*/
#include <linux/module.h>
+#include <linux/device.h>
#include "isp.h"
#include "ispreg.h"
#include "ispresizer.h"
/* Default configuration of resizer,filter coefficients,yenh for camera isp */
-static struct isprsz_yenh ispreszdefaultyenh = {0, 0, 0, 0};
static struct isprsz_coef ispreszdefcoef = {
{
0x0000, 0x0100, 0x0000, 0x0000,
@@ -68,50 +68,6 @@
}
};
-/**
- * struct isp_res - Structure for the resizer module to store its information.
- * @res_inuse: Indicates if resizer module has been reserved. 1 - Reserved,
- * 0 - Freed.
- * @h_startphase: Horizontal starting phase.
- * @v_startphase: Vertical starting phase.
- * @h_resz: Horizontal resizing value.
- * @v_resz: Vertical resizing value.
- * @outputwidth: Output Image Width in pixels.
- * @outputheight: Output Image Height in pixels.
- * @inputwidth: Input Image Width in pixels.
- * @inputheight: Input Image Height in pixels.
- * @algo: Algorithm select. 0 - Disable, 1 - [-1 2 -1]/2 high-pass filter,
- * 2 - [-1 -2 6 -2 -1]/4 high-pass filter.
- * @ipht_crop: Vertical start line for cropping.
- * @ipwd_crop: Horizontal start pixel for cropping.
- * @cropwidth: Crop Width.
- * @cropheight: Crop Height.
- * @resinput: Resizer input.
- * @coeflist: Register configuration for Resizer.
- * @ispres_mutex: Mutex for isp resizer.
- */
-static struct isp_res {
- int pm_state;
- u8 res_inuse;
- u8 h_startphase;
- u8 v_startphase;
- u16 h_resz;
- u16 v_resz;
- u32 outputwidth;
- u32 outputheight;
- u32 inputwidth;
- u32 inputheight;
- u8 algo;
- u32 ipht_crop;
- u32 ipwd_crop;
- u32 cropwidth;
- u32 cropheight;
- dma_addr_t tmp_buf;
- enum ispresizer_input resinput;
- struct isprsz_coef coeflist;
- struct mutex ispres_mutex; /* For checking/modifying res_inuse */
-} ispres_obj;
-
/* Structure for saving/restoring resizer module registers */
static struct isp_reg isprsz_reg_list[] = {
{OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, 0x0000},
@@ -159,46 +115,80 @@
};
/**
- * ispresizer_config_shadow_registers - Configure shadow registers.
- **/
-void ispresizer_config_shadow_registers()
-{
- return;
-}
-EXPORT_SYMBOL(ispresizer_config_shadow_registers);
-
-/**
- * ispresizer_trycrop - Validate crop dimensions.
- * @left: Left distance to start position of crop.
- * @top: Top distance to start position of crop.
- * @width: Width of input image.
- * @height: Height of input image.
- * @ow: Width of output image.
- * @oh: Height of output image.
- **/
-void ispresizer_trycrop(u32 left, u32 top, u32 width, u32 height, u32 ow,
- u32 oh)
-{
- ispres_obj.cropwidth = width + 6;
- ispres_obj.cropheight = height + 6;
- ispresizer_try_size(&ispres_obj.cropwidth, &ispres_obj.cropheight, &ow,
- &oh);
- ispres_obj.ipht_crop = top;
- ispres_obj.ipwd_crop = left;
-}
-EXPORT_SYMBOL(ispresizer_trycrop);
-
-/**
* ispresizer_applycrop - Apply crop to input image.
**/
-void ispresizer_applycrop(void)
+void ispresizer_applycrop(struct isp_res_device *isp_res)
{
- ispresizer_config_size(ispres_obj.cropwidth, ispres_obj.cropheight,
- ispres_obj.outputwidth,
- ispres_obj.outputheight);
+ struct isp_device *isp = to_isp_device(isp_res);
+
+ if (!isp_res->applycrop)
+ return;
+
+ ispresizer_s_pipeline(isp_res, &isp->pipeline);
+
+ isp_res->applycrop = 0;
+
return;
}
-EXPORT_SYMBOL(ispresizer_applycrop);
+
+/**
+ * ispresizer_config_shadow_registers - Configure shadow registers.
+ **/
+void ispresizer_config_shadow_registers(struct isp_res_device *isp_res)
+{
+ ispresizer_applycrop(isp_res);
+
+ return;
+}
+
+int ispresizer_config_crop(struct isp_res_device *isp_res,
+ struct v4l2_crop *a)
+{
+ struct isp_device *isp = to_isp_device(isp_res);
+ struct v4l2_crop *crop = a;
+ int rval;
+
+ if (crop->c.left < 0)
+ crop->c.left = 0;
+ if (crop->c.width < 0)
+ crop->c.width = 0;
+ if (crop->c.top < 0)
+ crop->c.top = 0;
+ if (crop->c.height < 0)
+ crop->c.height = 0;
+
+ if (crop->c.left >= isp->pipeline.prv_out_w_img)
+ crop->c.left = isp->pipeline.prv_out_w_img - 1;
+ if (crop->c.top >= isp->pipeline.rsz_out_h)
+ crop->c.top = isp->pipeline.rsz_out_h - 1;
+
+ /* Make sure the crop rectangle is never smaller than width
+ * and height divided by 4, since the resizer cannot upscale it
+ * by more than 4x. */
+
+ if (crop->c.width < (isp->pipeline.rsz_out_w + 3) / 4)
+ crop->c.width = (isp->pipeline.rsz_out_w + 3) / 4;
+ if (crop->c.height < (isp->pipeline.rsz_out_h + 3) / 4)
+ crop->c.height = (isp->pipeline.rsz_out_h + 3) / 4;
+
+ if (crop->c.left + crop->c.width > isp->pipeline.prv_out_w_img)
+ crop->c.width = isp->pipeline.prv_out_w_img - crop->c.left;
+ if (crop->c.top + crop->c.height > isp->pipeline.prv_out_h_img)
+ crop->c.height = isp->pipeline.prv_out_h_img - crop->c.top;
+
+ isp->pipeline.rsz_crop = crop->c;
+
+ rval = ispresizer_try_pipeline(isp_res, &isp->pipeline);
+ if (rval)
+ return rval;
+
+ isp_res->applycrop = 1;
+
+ if (isp->running == ISP_STOPPED)
+ ispresizer_applycrop(isp_res);
+
+ return 0;
+}
/**
* ispresizer_request - Reserves the Resizer module.
@@ -207,46 +197,50 @@
*
* Returns 0 if successful, or -EBUSY if resizer module was already requested.
**/
-int ispresizer_request()
+int ispresizer_request(struct isp_res_device *isp_res)
{
- mutex_lock(&ispres_obj.ispres_mutex);
- if (!ispres_obj.res_inuse) {
- ispres_obj.res_inuse = 1;
- mutex_unlock(&ispres_obj.ispres_mutex);
- isp_reg_writel(isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL) |
+ struct device *dev = to_device(isp_res);
+
+ mutex_lock(&isp_res->ispres_mutex);
+ if (!isp_res->res_inuse) {
+ isp_res->res_inuse = 1;
+ mutex_unlock(&isp_res->ispres_mutex);
+ isp_reg_writel(dev,
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_MAIN, ISP_CTRL) |
ISPCTRL_SBL_WR0_RAM_EN |
ISPCTRL_RSZ_CLK_EN,
OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
return 0;
} else {
- mutex_unlock(&ispres_obj.ispres_mutex);
- printk(KERN_ERR "ISP_ERR : Resizer Module Busy\n");
+ mutex_unlock(&isp_res->ispres_mutex);
+ dev_err(dev, "resizer: Module Busy\n");
return -EBUSY;
}
}
-EXPORT_SYMBOL(ispresizer_request);
/**
* ispresizer_free - Makes Resizer module free.
*
* Returns 0 if successful, or -EINVAL if resizer module was already freed.
**/
-int ispresizer_free()
+int ispresizer_free(struct isp_res_device *isp_res)
{
- mutex_lock(&ispres_obj.ispres_mutex);
- if (ispres_obj.res_inuse) {
- ispres_obj.res_inuse = 0;
- mutex_unlock(&ispres_obj.ispres_mutex);
- isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+ struct device *dev = to_device(isp_res);
+
+ mutex_lock(&isp_res->ispres_mutex);
+ if (isp_res->res_inuse) {
+ isp_res->res_inuse = 0;
+ mutex_unlock(&isp_res->ispres_mutex);
+ isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
~(ISPCTRL_RSZ_CLK_EN | ISPCTRL_SBL_WR0_RAM_EN));
return 0;
} else {
- mutex_unlock(&ispres_obj.ispres_mutex);
+ mutex_unlock(&isp_res->ispres_mutex);
DPRINTK_ISPRESZ("ISP_ERR : Resizer Module already freed\n");
return -EINVAL;
}
}
-EXPORT_SYMBOL(ispresizer_free);
/**
* ispresizer_config_datapath - Specifies which input to use in resizer module
@@ -256,17 +250,20 @@
*
* Returns 0 if successful, or -EINVAL if an unsupported input was requested.
**/
-int ispresizer_config_datapath(enum ispresizer_input input)
+int ispresizer_config_datapath(struct isp_res_device *isp_res,
+ struct isp_pipeline *pipe)
{
+ struct device *dev = to_device(isp_res);
u32 cnt = 0;
+
DPRINTK_ISPRESZ("ispresizer_config_datapath()+\n");
- ispres_obj.resinput = input;
- switch (input) {
+
+ switch (pipe->rsz_in) {
case RSZ_OTFLY_YUV:
cnt &= ~ISPRSZ_CNT_INPTYP;
cnt &= ~ISPRSZ_CNT_INPSRC;
- ispresizer_set_inaddr(0);
- ispresizer_config_inlineoffset(0);
+ ispresizer_set_inaddr(isp_res, 0, 0);
+ ispresizer_config_inlineoffset(isp_res, 0);
break;
case RSZ_MEM_YUV:
cnt |= ISPRSZ_CNT_INPSRC;
@@ -277,18 +274,19 @@
cnt |= ISPRSZ_CNT_INPTYP;
break;
default:
- printk(KERN_ERR "ISP_ERR : Wrong Input\n");
+ dev_err(dev, "resizer: Wrong Input\n");
return -EINVAL;
}
- isp_reg_or(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, cnt);
- ispresizer_config_ycpos(0);
- ispresizer_config_filter_coef(&ispreszdefcoef);
- ispresizer_enable_cbilin(0);
- ispresizer_config_luma_enhance(&ispreszdefaultyenh);
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+ ~(ISPRSZ_CNT_INPSRC | ISPRSZ_CNT_INPTYP),
+ cnt);
+ ispresizer_config_ycpos(isp_res, 0);
+ ispresizer_config_filter_coef(isp_res, &ispreszdefcoef);
+ ispresizer_enable_cbilin(isp_res, 0);
+ ispresizer_config_luma_enhance(isp_res, &isp_res->defaultyenh);
DPRINTK_ISPRESZ("ispresizer_config_datapath()-\n");
return 0;
}
-EXPORT_SYMBOL(ispresizer_config_datapath);
/**
* ispresizer_try_size - Validates input and output images size.
@@ -296,7 +294,8 @@
* @input_h: input height for the resizer in number of lines
* @output_w: output width from the resizer in number of pixels per line
* resizer when writing to memory needs this to be multiple of 16.
- * @output_h: output height for the resizer in number of lines, must be even.
+ * @pipe->rsz_out_h: output height for the resizer in number of lines, must be
+ * even.
*
* Calculates the horizontal and vertical resize ratio, number of pixels to
* be cropped in the resizer module and checks the validity of various
@@ -325,34 +324,29 @@
* Fills up the output/input widht/height, horizontal/vertical resize ratio,
* horizontal/vertical crop variables in the isp_res structure.
**/
-int ispresizer_try_size(u32 *input_width, u32 *input_height, u32 *output_w,
- u32 *output_h)
+int ispresizer_try_pipeline(struct isp_res_device *isp_res,
+ struct isp_pipeline *pipe)
{
+ struct device *dev = to_device(isp_res);
u32 rsz, rsz_7, rsz_4;
u32 sph;
- u32 input_w, input_h;
int max_in_otf, max_out_7tap;
- input_w = *input_width;
- input_h = *input_height;
-
- if (input_w < 32 || input_h < 32) {
+ if (pipe->rsz_crop.width < 32 || pipe->rsz_crop.height < 32) {
DPRINTK_ISPCCDC("ISP_ERR: RESIZER cannot handle input width"
" less than 32 pixels or height less than"
" 32\n");
return -EINVAL;
}
- input_w -= 6;
- input_h -= 6;
- if (input_h > MAX_IN_HEIGHT)
+ if (pipe->rsz_crop.height > MAX_IN_HEIGHT)
return -EINVAL;
- if (*output_w < 16)
- *output_w = 16;
+ if (pipe->rsz_out_w < 16)
+ pipe->rsz_out_w = 16;
- if (*output_h < 2)
- *output_h = 2;
+ if (pipe->rsz_out_h < 2)
+ pipe->rsz_out_h = 2;
if (omap_rev() == OMAP3430_REV_ES1_0) {
max_in_otf = MAX_IN_WIDTH_ONTHEFLY_MODE;
@@ -362,110 +356,118 @@
max_out_7tap = MAX_7TAP_VRSZ_OUTWIDTH_ES2;
}
- if (ispres_obj.resinput == RSZ_OTFLY_YUV) {
- if (input_w > max_in_otf)
+ if (pipe->rsz_in == RSZ_OTFLY_YUV) {
+ if (pipe->rsz_crop.width > max_in_otf)
return -EINVAL;
} else {
- if (input_w > MAX_IN_WIDTH_MEMORY_MODE)
+ if (pipe->rsz_crop.width > MAX_IN_WIDTH_MEMORY_MODE)
return -EINVAL;
}
- *output_h &= 0xfffffffe;
+ pipe->rsz_out_h &= 0xfffffffe;
sph = DEFAULTSTPHASE;
- rsz_7 = ((input_h - 7) * 256) / (*output_h - 1);
- rsz_4 = ((input_h - 4) * 256) / (*output_h - 1);
+ rsz_7 = ((pipe->rsz_crop.height - 7) * 256) / (pipe->rsz_out_h - 1);
+ rsz_4 = ((pipe->rsz_crop.height - 4) * 256) / (pipe->rsz_out_h - 1);
- rsz = (input_h * 256) / *output_h;
+ rsz = (pipe->rsz_crop.height * 256) / pipe->rsz_out_h;
if (rsz <= MID_RESIZE_VALUE) {
rsz = rsz_4;
if (rsz < MINIMUM_RESIZE_VALUE) {
rsz = MINIMUM_RESIZE_VALUE;
- *output_h = (((input_h - 4) * 256) / rsz) + 1;
- printk(KERN_INFO "%s: using output_h %d instead\n",
- __func__, *output_h);
+ pipe->rsz_out_h =
+ (((pipe->rsz_crop.height - 4) * 256) / rsz) + 1;
+ dev_dbg(dev,
+ "resizer: %s: using height %d instead\n",
+ __func__, pipe->rsz_out_h);
}
} else {
rsz = rsz_7;
- if (*output_w > max_out_7tap)
- *output_w = max_out_7tap;
+ if (pipe->rsz_out_w > max_out_7tap)
+ pipe->rsz_out_w = max_out_7tap;
if (rsz > MAXIMUM_RESIZE_VALUE) {
rsz = MAXIMUM_RESIZE_VALUE;
- *output_h = (((input_h - 7) * 256) / rsz) + 1;
- printk(KERN_INFO "%s: using output_h %d instead\n",
- __func__, *output_h);
+ pipe->rsz_out_h =
+ (((pipe->rsz_crop.height - 7) * 256) / rsz) + 1;
+ dev_dbg(dev,
+ "resizer: %s: using height %d instead\n",
+ __func__, pipe->rsz_out_h);
}
}
if (rsz > MID_RESIZE_VALUE) {
- input_h =
- (((64 * sph) + ((*output_h - 1) * rsz) + 32) / 256) + 7;
+ pipe->rsz_crop.height =
+ (((64 * sph) + ((pipe->rsz_out_h - 1) * rsz) + 32)
+ / 256) + 7;
} else {
- input_h =
- (((32 * sph) + ((*output_h - 1) * rsz) + 16) / 256) + 4;
+ pipe->rsz_crop.height =
+ (((32 * sph) + ((pipe->rsz_out_h - 1) * rsz) + 16)
+ / 256) + 4;
}
- ispres_obj.outputheight = *output_h;
- ispres_obj.v_resz = rsz;
- ispres_obj.inputheight = input_h;
- ispres_obj.ipht_crop = DEFAULTSTPIXEL;
- ispres_obj.v_startphase = sph;
+ isp_res->v_resz = rsz;
+ /* FIXME: pipe->rsz_crop.height here is the real input height! */
+ isp_res->v_startphase = sph;
- *output_w &= 0xfffffff0;
+ pipe->rsz_out_w &= 0xfffffff0;
sph = DEFAULTSTPHASE;
- rsz_7 = ((input_w - 7) * 256) / (*output_w - 1);
- rsz_4 = ((input_w - 4) * 256) / (*output_w - 1);
+ rsz_7 = ((pipe->rsz_crop.width - 7) * 256) / (pipe->rsz_out_w - 1);
+ rsz_4 = ((pipe->rsz_crop.width - 4) * 256) / (pipe->rsz_out_w - 1);
- rsz = (input_w * 256) / *output_w;
+ rsz = (pipe->rsz_crop.width * 256) / pipe->rsz_out_w;
if (rsz > MID_RESIZE_VALUE) {
rsz = rsz_7;
if (rsz > MAXIMUM_RESIZE_VALUE) {
rsz = MAXIMUM_RESIZE_VALUE;
- *output_w = (((input_w - 7) * 256) / rsz) + 1;
- *output_w = (*output_w + 0xf) & 0xfffffff0;
- printk(KERN_INFO "%s: using output_w %d instead\n",
- __func__, *output_w);
+ pipe->rsz_out_w =
+ (((pipe->rsz_crop.width - 7) * 256) / rsz) + 1;
+ pipe->rsz_out_w = (pipe->rsz_out_w + 0xf) & 0xfffffff0;
+ dev_dbg(dev,
+ "resizer: %s: using width %d instead\n",
+ __func__, pipe->rsz_out_w);
}
} else {
rsz = rsz_4;
if (rsz < MINIMUM_RESIZE_VALUE) {
rsz = MINIMUM_RESIZE_VALUE;
- *output_w = (((input_w - 4) * 256) / rsz) + 1;
- *output_w = (*output_w + 0xf) & 0xfffffff0;
- printk(KERN_INFO "%s: using output_w %d instead\n",
- __func__, *output_w);
+ pipe->rsz_out_w =
+ (((pipe->rsz_crop.width - 4) * 256) / rsz) + 1;
+ pipe->rsz_out_w = (pipe->rsz_out_w + 0xf) & 0xfffffff0;
+ dev_dbg(dev,
+ "resizer: %s: using width %d instead\n",
+ __func__, pipe->rsz_out_w);
}
}
/* Recalculate input based on TRM equations */
if (rsz > MID_RESIZE_VALUE) {
- input_w =
- (((64 * sph) + ((*output_w - 1) * rsz) + 32) / 256) + 7;
+ pipe->rsz_crop.width =
+ (((64 * sph) + ((pipe->rsz_out_w - 1) * rsz) + 32)
+ / 256) + 7;
} else {
- input_w =
- (((32 * sph) + ((*output_w - 1) * rsz) + 16) / 256) + 7;
+ pipe->rsz_crop.width =
+ (((32 * sph) + ((pipe->rsz_out_w - 1) * rsz) + 16)
+ / 256) + 7;
}
- ispres_obj.outputwidth = *output_w;
- ispres_obj.h_resz = rsz;
- ispres_obj.inputwidth = input_w;
- ispres_obj.ipwd_crop = DEFAULTSTPIXEL;
- ispres_obj.h_startphase = sph;
+ isp_res->h_resz = rsz;
+ /* FIXME: pipe->rsz_crop.width here is the real input width! */
+ isp_res->h_startphase = sph;
- *input_height = input_h;
- *input_width = input_w;
+ pipe->rsz_out_w_img = pipe->rsz_out_w;
+
return 0;
}
-EXPORT_SYMBOL(ispresizer_try_size);
/**
* ispresizer_config_size - Configures input and output image size.
- * @input_w: input width for the resizer in number of pixels per line.
- * @input_h: input height for the resizer in number of lines.
- * @output_w: output width from the resizer in number of pixels per line.
- * @output_h: output height for the resizer in number of lines.
+ * @pipe->rsz_crop.width: input width for the resizer in number of pixels per
+ * line.
+ * @pipe->rsz_crop.height: input height for the resizer in number of lines.
+ * @pipe->rsz_out_w: output width from the resizer in number of pixels per line.
+ * @pipe->rsz_out_h: output height for the resizer in number of lines.
*
* Configures the appropriate values stored in the isp_res structure in the
* resizer registers.
@@ -473,93 +475,86 @@
* Returns 0 if successful, or -EINVAL if passed values haven't been verified
* with ispresizer_try_size() previously.
**/
-int ispresizer_config_size(u32 input_w, u32 input_h, u32 output_w,
- u32 output_h)
+int ispresizer_s_pipeline(struct isp_res_device *isp_res,
+ struct isp_pipeline *pipe)
{
+ struct device *dev = to_device(isp_res);
+ struct isp_device *isp = to_isp_device(isp_res);
int i, j;
u32 res;
- DPRINTK_ISPRESZ("ispresizer_config_size()+, input_w = %d,input_h ="
- " %d, output_w = %d, output_h"
- " = %d,hresz = %d,vresz = %d,"
- " hcrop = %d, vcrop = %d,"
- " hstph = %d, vstph = %d\n",
- ispres_obj.inputwidth,
- ispres_obj.inputheight,
- ispres_obj.outputwidth,
- ispres_obj.outputheight,
- ispres_obj.h_resz,
- ispres_obj.v_resz,
- ispres_obj.ipwd_crop,
- ispres_obj.ipht_crop,
- ispres_obj.h_startphase,
- ispres_obj.v_startphase);
- if ((output_w != ispres_obj.outputwidth)
- || (output_h != ispres_obj.outputheight)) {
- printk(KERN_ERR "Output parameters passed do not match the"
- " values calculated by the"
- " trysize passed w %d, h %d"
- " \n", output_w , output_h);
- return -EINVAL;
- }
+ int rval;
- /* Set Resizer input address and offset adderss */
- ispresizer_config_inlineoffset(isp_reg_readl(OMAP3_ISP_IOMEM_PREV,
- ISPPRV_WADD_OFFSET));
+ rval = ispresizer_config_datapath(isp_res, pipe);
+ if (rval)
+ return rval;
- res = isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
+ res = isp_reg_readl(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
- isp_reg_writel(res |
- (ispres_obj.h_startphase << ISPRSZ_CNT_HSTPH_SHIFT) |
- (ispres_obj.v_startphase << ISPRSZ_CNT_VSTPH_SHIFT),
+ isp_reg_writel(dev, res |
+ (isp_res->h_startphase << ISPRSZ_CNT_HSTPH_SHIFT) |
+ (isp_res->v_startphase << ISPRSZ_CNT_VSTPH_SHIFT),
OMAP3_ISP_IOMEM_RESZ,
ISPRSZ_CNT);
- /* Set start address for cropping */
- isp_reg_writel(ispres_obj.tmp_buf + 2 *
- (ispres_obj.ipht_crop * ispres_obj.inputwidth +
- (ispres_obj.ipwd_crop & ~15)),
- OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
- isp_reg_writel(
- ((ispres_obj.ipwd_crop & 15) << ISPRSZ_IN_START_HORZ_ST_SHIFT) |
- (0x00 << ISPRSZ_IN_START_VERT_ST_SHIFT),
- OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
+ /* Set Resizer input address and offset adderss */
+ if (pipe->rsz_in == RSZ_OTFLY_YUV) {
+ /* Set the fractional part of the starting address.*/
+ isp_reg_writel(dev,
+ ((pipe->rsz_crop.left * 2)<<
+ ISPRSZ_IN_START_HORZ_ST_SHIFT) |
+ ((pipe->rsz_crop.top) <<
+ ISPRSZ_IN_START_VERT_ST_SHIFT),
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
+ } else {
+ /* Set start address for cropping */
+ ispresizer_set_inaddr(isp_res, isp_res->in_buf_addr,
+ ISP_BYTES_PER_PIXEL *
+ ((isp->pipeline.rsz_crop.left & ~0xf) +
+ isp->pipeline.prv_out_w *
+ isp->pipeline.rsz_crop.top));
- isp_reg_writel((0x00 << ISPRSZ_IN_START_HORZ_ST_SHIFT) |
- (0x00 << ISPRSZ_IN_START_VERT_ST_SHIFT),
- OMAP3_ISP_IOMEM_RESZ,
- ISPRSZ_IN_START);
+ /* Set the fractional part of the starting address.*/
+ isp_reg_writel(dev, ((isp->pipeline.rsz_crop.left & 0xf) <<
+ ISPRSZ_IN_START_HORZ_ST_SHIFT) |
+ (0x00 << ISPRSZ_IN_START_VERT_ST_SHIFT),
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
+ }
- isp_reg_writel((ispres_obj.inputwidth << ISPRSZ_IN_SIZE_HORZ_SHIFT) |
- (ispres_obj.inputheight <<
+ isp_reg_writel(dev,
+ (pipe->rsz_crop.width << ISPRSZ_IN_SIZE_HORZ_SHIFT) |
+ (pipe->rsz_crop.height <<
ISPRSZ_IN_SIZE_VERT_SHIFT),
OMAP3_ISP_IOMEM_RESZ,
ISPRSZ_IN_SIZE);
- if (!ispres_obj.algo) {
- isp_reg_writel((output_w << ISPRSZ_OUT_SIZE_HORZ_SHIFT) |
- (output_h << ISPRSZ_OUT_SIZE_VERT_SHIFT),
+ if (!isp_res->algo) {
+ isp_reg_writel(dev,
+ (pipe->rsz_out_w << ISPRSZ_OUT_SIZE_HORZ_SHIFT) |
+ (pipe->rsz_out_h << ISPRSZ_OUT_SIZE_VERT_SHIFT),
OMAP3_ISP_IOMEM_RESZ,
ISPRSZ_OUT_SIZE);
} else {
- isp_reg_writel(((output_w - 4) << ISPRSZ_OUT_SIZE_HORZ_SHIFT) |
- (output_h << ISPRSZ_OUT_SIZE_VERT_SHIFT),
+ isp_reg_writel(dev,
+ ((pipe->rsz_out_w - 4)
+ << ISPRSZ_OUT_SIZE_HORZ_SHIFT) |
+ (pipe->rsz_out_h << ISPRSZ_OUT_SIZE_VERT_SHIFT),
OMAP3_ISP_IOMEM_RESZ,
ISPRSZ_OUT_SIZE);
}
- res = isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
+ res = isp_reg_readl(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
- isp_reg_writel(res |
- ((ispres_obj.h_resz - 1) << ISPRSZ_CNT_HRSZ_SHIFT) |
- ((ispres_obj.v_resz - 1) << ISPRSZ_CNT_VRSZ_SHIFT),
+ isp_reg_writel(dev, res |
+ ((isp_res->h_resz - 1) << ISPRSZ_CNT_HRSZ_SHIFT) |
+ ((isp_res->v_resz - 1) << ISPRSZ_CNT_VRSZ_SHIFT),
OMAP3_ISP_IOMEM_RESZ,
ISPRSZ_CNT);
- if (ispres_obj.h_resz <= MID_RESIZE_VALUE) {
+ if (isp_res->h_resz <= MID_RESIZE_VALUE) {
j = 0;
for (i = 0; i < 16; i++) {
- isp_reg_writel(
- (ispres_obj.coeflist.h_filter_coef_4tap[j]
+ isp_reg_writel(dev,
+ (isp_res->coeflist.h_filter_coef_4tap[j]
<< ISPRSZ_HFILT10_COEF0_SHIFT) |
- (ispres_obj.coeflist.h_filter_coef_4tap[j + 1]
+ (isp_res->coeflist.h_filter_coef_4tap[j + 1]
<< ISPRSZ_HFILT10_COEF1_SHIFT),
OMAP3_ISP_IOMEM_RESZ,
ISPRSZ_HFILT10 + (i * 0x04));
@@ -569,17 +564,19 @@
j = 0;
for (i = 0; i < 16; i++) {
if ((i + 1) % 4 == 0) {
- isp_reg_writel((ispres_obj.coeflist.
+ isp_reg_writel(dev,
+ (isp_res->coeflist.
h_filter_coef_7tap[j] <<
ISPRSZ_HFILT10_COEF0_SHIFT),
OMAP3_ISP_IOMEM_RESZ,
ISPRSZ_HFILT10 + (i * 0x04));
j += 1;
} else {
- isp_reg_writel((ispres_obj.coeflist.
+ isp_reg_writel(dev,
+ (isp_res->coeflist.
h_filter_coef_7tap[j] <<
ISPRSZ_HFILT10_COEF0_SHIFT) |
- (ispres_obj.coeflist.
+ (isp_res->coeflist.
h_filter_coef_7tap[j+1] <<
ISPRSZ_HFILT10_COEF1_SHIFT),
OMAP3_ISP_IOMEM_RESZ,
@@ -588,13 +585,13 @@
}
}
}
- if (ispres_obj.v_resz <= MID_RESIZE_VALUE) {
+ if (isp_res->v_resz <= MID_RESIZE_VALUE) {
j = 0;
for (i = 0; i < 16; i++) {
- isp_reg_writel((ispres_obj.coeflist.
+ isp_reg_writel(dev, (isp_res->coeflist.
v_filter_coef_4tap[j] <<
ISPRSZ_VFILT10_COEF0_SHIFT) |
- (ispres_obj.coeflist.
+ (isp_res->coeflist.
v_filter_coef_4tap[j + 1] <<
ISPRSZ_VFILT10_COEF1_SHIFT),
OMAP3_ISP_IOMEM_RESZ,
@@ -605,17 +602,19 @@
j = 0;
for (i = 0; i < 16; i++) {
if ((i + 1) % 4 == 0) {
- isp_reg_writel((ispres_obj.coeflist.
+ isp_reg_writel(dev,
+ (isp_res->coeflist.
v_filter_coef_7tap[j] <<
ISPRSZ_VFILT10_COEF0_SHIFT),
OMAP3_ISP_IOMEM_RESZ,
ISPRSZ_VFILT10 + (i * 0x04));
j += 1;
} else {
- isp_reg_writel((ispres_obj.coeflist.
+ isp_reg_writel(dev,
+ (isp_res->coeflist.
v_filter_coef_7tap[j] <<
ISPRSZ_VFILT10_COEF0_SHIFT) |
- (ispres_obj.coeflist.
+ (isp_res->coeflist.
v_filter_coef_7tap[j+1] <<
ISPRSZ_VFILT10_COEF1_SHIFT),
OMAP3_ISP_IOMEM_RESZ,
@@ -625,26 +624,16 @@
}
}
- ispresizer_config_outlineoffset(output_w*2);
+ ispresizer_config_outlineoffset(isp_res, pipe->rsz_out_w*2);
+
+ if (pipe->pix.pixelformat == V4L2_PIX_FMT_UYVY)
+ ispresizer_config_ycpos(isp_res, 0);
+ else
+ ispresizer_config_ycpos(isp_res, 1);
+
DPRINTK_ISPRESZ("ispresizer_config_size()-\n");
return 0;
}
-EXPORT_SYMBOL(ispresizer_config_size);
-
-void __ispresizer_enable(int enable)
-{
- int val;
- DPRINTK_ISPRESZ("+ispresizer_enable()+\n");
- if (enable) {
- val = (isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) & 0x2) |
- ISPRSZ_PCR_ENABLE;
- } else {
- val = isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
- ~ISPRSZ_PCR_ENABLE;
- }
- isp_reg_writel(val, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR);
- DPRINTK_ISPRESZ("+ispresizer_enable()-\n");
-}
/**
* ispresizer_enable - Enables the resizer module.
@@ -652,44 +641,37 @@
*
* Client should configure all the sub modules in resizer before this.
**/
-void ispresizer_enable(int enable)
+void ispresizer_enable(struct isp_res_device *isp_res, int enable)
{
- __ispresizer_enable(enable);
- ispres_obj.pm_state = enable;
-}
-EXPORT_SYMBOL(ispresizer_enable);
+ struct device *dev = to_device(isp_res);
+ int val;
-/**
- * ispresizer_suspend - Suspend resizer module.
- **/
-void ispresizer_suspend(void)
-{
- if (ispres_obj.pm_state)
- __ispresizer_enable(0);
+ DPRINTK_ISPRESZ("+ispresizer_enable()+\n");
+ if (enable) {
+ val = (isp_reg_readl(dev, OMAP3_ISP_IOMEM_RESZ,
+ ISPRSZ_PCR) & ISPRSZ_PCR_ONESHOT) |
+ ISPRSZ_PCR_ENABLE;
+ } else {
+ val = isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
+ ~ISPRSZ_PCR_ENABLE;
+ }
+ isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR);
+ DPRINTK_ISPRESZ("+ispresizer_enable()-\n");
}
-EXPORT_SYMBOL(ispresizer_suspend);
-
-/**
- * ispresizer_resume - Resume resizer module.
- **/
-void ispresizer_resume(void)
-{
- if (ispres_obj.pm_state)
- __ispresizer_enable(1);
-}
-EXPORT_SYMBOL(ispresizer_resume);
/**
* ispresizer_busy - Checks if ISP resizer is busy.
*
* Returns busy field from ISPRSZ_PCR register.
**/
-int ispresizer_busy(void)
+int ispresizer_busy(struct isp_res_device *isp_res)
{
- return isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
- ISPPRV_PCR_BUSY;
+ struct device *dev = to_device(isp_res);
+
+ return isp_reg_readl(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
+ ISPRSZ_PCR_BUSY;
}
-EXPORT_SYMBOL(ispresizer_busy);
/**
* ispresizer_config_startphase - Sets the horizontal and vertical start phase.
@@ -699,52 +681,57 @@
* This API just updates the isp_res struct. Actual register write happens in
* ispresizer_config_size.
**/
-void ispresizer_config_startphase(u8 hstartphase, u8 vstartphase)
+void ispresizer_config_startphase(struct isp_res_device *isp_res,
+ u8 hstartphase, u8 vstartphase)
{
DPRINTK_ISPRESZ("ispresizer_config_startphase()+\n");
- ispres_obj.h_startphase = hstartphase;
- ispres_obj.v_startphase = vstartphase;
+ isp_res->h_startphase = hstartphase;
+ isp_res->v_startphase = vstartphase;
DPRINTK_ISPRESZ("ispresizer_config_startphase()-\n");
}
-EXPORT_SYMBOL(ispresizer_config_startphase);
/**
* ispresizer_config_ycpos - Specifies if output should be in YC or CY format.
* @yc: 0 - YC format, 1 - CY format
**/
-void ispresizer_config_ycpos(u8 yc)
+void ispresizer_config_ycpos(struct isp_res_device *isp_res, u8 yc)
{
+ struct device *dev = to_device(isp_res);
+
DPRINTK_ISPRESZ("ispresizer_config_ycpos()+\n");
- isp_reg_and_or(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ~ISPRSZ_CNT_YCPOS,
- (yc ? ISPRSZ_CNT_YCPOS : 0));
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+ ~ISPRSZ_CNT_YCPOS, (yc ? ISPRSZ_CNT_YCPOS : 0));
DPRINTK_ISPRESZ("ispresizer_config_ycpos()-\n");
}
-EXPORT_SYMBOL(ispresizer_config_ycpos);
/**
* Sets the chrominance algorithm
* @cbilin: 0 - chrominance uses same processing as luminance,
* 1 - bilinear interpolation processing
**/
-void ispresizer_enable_cbilin(u8 enable)
+void ispresizer_enable_cbilin(struct isp_res_device *isp_res, u8 enable)
{
+ struct device *dev = to_device(isp_res);
+
DPRINTK_ISPRESZ("ispresizer_enable_cbilin()+\n");
- isp_reg_and_or(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ~ISPRSZ_CNT_CBILIN,
- (enable ? ISPRSZ_CNT_CBILIN : 0));
+ isp_reg_and_or(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+ ~ISPRSZ_CNT_CBILIN, (enable ? ISPRSZ_CNT_CBILIN : 0));
DPRINTK_ISPRESZ("ispresizer_enable_cbilin()-\n");
}
-EXPORT_SYMBOL(ispresizer_enable_cbilin);
/**
* ispresizer_config_luma_enhance - Configures luminance enhancer parameters.
* @yenh: Pointer to structure containing desired values for core, slope, gain
* and algo parameters.
**/
-void ispresizer_config_luma_enhance(struct isprsz_yenh *yenh)
+void ispresizer_config_luma_enhance(struct isp_res_device *isp_res,
+ struct isprsz_yenh *yenh)
{
+ struct device *dev = to_device(isp_res);
+
DPRINTK_ISPRESZ("ispresizer_config_luma_enhance()+\n");
- ispres_obj.algo = yenh->algo;
- isp_reg_writel((yenh->algo << ISPRSZ_YENH_ALGO_SHIFT) |
+ isp_res->algo = yenh->algo;
+ isp_reg_writel(dev, (yenh->algo << ISPRSZ_YENH_ALGO_SHIFT) |
(yenh->gain << ISPRSZ_YENH_GAIN_SHIFT) |
(yenh->slope << ISPRSZ_YENH_SLOP_SHIFT) |
(yenh->coreoffset << ISPRSZ_YENH_CORE_SHIFT),
@@ -752,7 +739,6 @@
ISPRSZ_YENH);
DPRINTK_ISPRESZ("ispresizer_config_luma_enhance()-\n");
}
-EXPORT_SYMBOL(ispresizer_config_luma_enhance);
/**
* ispresizer_config_filter_coef - Sets filter coefficients for 4 & 7-tap mode.
@@ -761,25 +747,25 @@
* @coef: Structure containing horizontal and vertical filter coefficients for
* both 4-tap and 7-tap mode.
**/
-void ispresizer_config_filter_coef(struct isprsz_coef *coef)
+void ispresizer_config_filter_coef(struct isp_res_device *isp_res,
+ struct isprsz_coef *coef)
{
int i;
DPRINTK_ISPRESZ("ispresizer_config_filter_coef()+\n");
for (i = 0; i < 32; i++) {
- ispres_obj.coeflist.h_filter_coef_4tap[i] =
+ isp_res->coeflist.h_filter_coef_4tap[i] =
coef->h_filter_coef_4tap[i];
- ispres_obj.coeflist.v_filter_coef_4tap[i] =
+ isp_res->coeflist.v_filter_coef_4tap[i] =
coef->v_filter_coef_4tap[i];
}
for (i = 0; i < 28; i++) {
- ispres_obj.coeflist.h_filter_coef_7tap[i] =
+ isp_res->coeflist.h_filter_coef_7tap[i] =
coef->h_filter_coef_7tap[i];
- ispres_obj.coeflist.v_filter_coef_7tap[i] =
+ isp_res->coeflist.v_filter_coef_7tap[i] =
coef->v_filter_coef_7tap[i];
}
DPRINTK_ISPRESZ("ispresizer_config_filter_coef()-\n");
}
-EXPORT_SYMBOL(ispresizer_config_filter_coef);
/**
* ispresizer_config_inlineoffset - Configures the read address line offset.
@@ -787,36 +773,44 @@
*
* Returns 0 if successful, or -EINVAL if offset is not 32 bits aligned.
**/
-int ispresizer_config_inlineoffset(u32 offset)
+int ispresizer_config_inlineoffset(struct isp_res_device *isp_res, u32 offset)
{
+ struct device *dev = to_device(isp_res);
+
DPRINTK_ISPRESZ("ispresizer_config_inlineoffset()+\n");
if (offset % 32)
return -EINVAL;
- isp_reg_writel(offset << ISPRSZ_SDR_INOFF_OFFSET_SHIFT,
+ isp_reg_writel(dev, offset << ISPRSZ_SDR_INOFF_OFFSET_SHIFT,
OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
DPRINTK_ISPRESZ("ispresizer_config_inlineoffset()-\n");
return 0;
}
-EXPORT_SYMBOL(ispresizer_config_inlineoffset);
/**
* ispresizer_set_inaddr - Sets the memory address of the input frame.
* @addr: 32bit memory address aligned on 32byte boundary.
+ * @offset: Starting offset.
*
* Returns 0 if successful, or -EINVAL if address is not 32 bits aligned.
**/
-int ispresizer_set_inaddr(u32 addr)
+int ispresizer_set_inaddr(struct isp_res_device *isp_res, u32 addr, u32 offset)
{
+ struct device *dev = to_device(isp_res);
+
DPRINTK_ISPRESZ("ispresizer_set_inaddr()+\n");
- if (addr % 32)
+
+ if ((addr + offset) % 32)
return -EINVAL;
- isp_reg_writel(addr << ISPRSZ_SDR_INADD_ADDR_SHIFT,
- OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
- ispres_obj.tmp_buf = addr;
+
+ isp_res->in_buf_addr = addr;
+ isp_res->in_buf_addr_off = offset;
+
+ isp_reg_writel(dev, (addr + offset),
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
+
DPRINTK_ISPRESZ("ispresizer_set_inaddr()-\n");
return 0;
}
-EXPORT_SYMBOL(ispresizer_set_inaddr);
/**
* ispresizer_config_outlineoffset - Configures the write address line offset.
@@ -824,105 +818,124 @@
*
* Returns 0 if successful, or -EINVAL if address is not 32 bits aligned.
**/
-int ispresizer_config_outlineoffset(u32 offset)
+int ispresizer_config_outlineoffset(struct isp_res_device *isp_res, u32 offset)
{
+ struct device *dev = to_device(isp_res);
+
DPRINTK_ISPRESZ("ispresizer_config_outlineoffset()+\n");
if (offset % 32)
return -EINVAL;
- isp_reg_writel(offset << ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT,
+ isp_reg_writel(dev, offset << ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT,
OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
DPRINTK_ISPRESZ("ispresizer_config_outlineoffset()-\n");
return 0;
}
-EXPORT_SYMBOL(ispresizer_config_outlineoffset);
/**
* Configures the memory address to which the output frame is written.
* @addr: 32bit memory address aligned on 32byte boundary.
**/
-int ispresizer_set_outaddr(u32 addr)
+int ispresizer_set_outaddr(struct isp_res_device *isp_res, u32 addr)
{
+ struct device *dev = to_device(isp_res);
+
DPRINTK_ISPRESZ("ispresizer_set_outaddr()+\n");
if (addr % 32)
return -EINVAL;
- isp_reg_writel(addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
+ isp_reg_writel(dev, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
DPRINTK_ISPRESZ("ispresizer_set_outaddr()-\n");
return 0;
}
-EXPORT_SYMBOL(ispresizer_set_outaddr);
/**
* ispresizer_save_context - Saves the values of the resizer module registers.
**/
-void ispresizer_save_context(void)
+void ispresizer_save_context(struct device *dev)
{
DPRINTK_ISPRESZ("Saving context\n");
- isp_save_context(isprsz_reg_list);
+ isp_save_context(dev, isprsz_reg_list);
}
-EXPORT_SYMBOL(ispresizer_save_context);
/**
* ispresizer_restore_context - Restores resizer module register values.
**/
-void ispresizer_restore_context(void)
+void ispresizer_restore_context(struct device *dev)
{
DPRINTK_ISPRESZ("Restoring context\n");
- isp_restore_context(isprsz_reg_list);
+ isp_restore_context(dev, isprsz_reg_list);
}
-EXPORT_SYMBOL(ispresizer_restore_context);
/**
* ispresizer_print_status - Prints the values of the resizer module registers.
**/
-void ispresizer_print_status()
+void ispresizer_print_status(struct isp_res_device *isp_res)
{
+#ifdef OMAP_ISPRESZ_DEBUG
+ struct device *dev = to_device(isp_res);
+#endif
+
if (!is_ispresz_debug_enabled())
return;
DPRINTK_ISPRESZ("###ISP_CTRL inresizer =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
DPRINTK_ISPRESZ("###ISP_IRQ0ENABLE in resizer =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE));
DPRINTK_ISPRESZ("###ISP_IRQ0STATUS in resizer =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS));
DPRINTK_ISPRESZ("###RSZ PCR =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR));
DPRINTK_ISPRESZ("###RSZ CNT =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT));
DPRINTK_ISPRESZ("###RSZ OUT SIZE =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE));
DPRINTK_ISPRESZ("###RSZ IN START =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START));
DPRINTK_ISPRESZ("###RSZ IN SIZE =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE));
DPRINTK_ISPRESZ("###RSZ SDR INADD =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD));
DPRINTK_ISPRESZ("###RSZ SDR INOFF =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF));
DPRINTK_ISPRESZ("###RSZ SDR OUTADD =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD));
DPRINTK_ISPRESZ("###RSZ SDR OTOFF =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF));
DPRINTK_ISPRESZ("###RSZ YENH =0x%x\n",
- isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH));
+ isp_reg_readl(dev,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH));
}
-EXPORT_SYMBOL(ispresizer_print_status);
/**
* isp_resizer_init - Module Initialisation.
*
* Always returns 0.
**/
-int __init isp_resizer_init(void)
+int __init isp_resizer_init(struct device *dev)
{
- mutex_init(&ispres_obj.ispres_mutex);
- ispres_obj.pm_state = 0;
+ struct isp_device *isp = dev_get_drvdata(dev);
+ struct isp_res_device *isp_res = &isp->isp_res;
+
+ mutex_init(&isp_res->ispres_mutex);
+
return 0;
}
/**
* isp_resizer_cleanup - Module Cleanup.
**/
-void isp_resizer_cleanup(void)
+void isp_resizer_cleanup(struct device *dev)
{
}
diff --git a/drivers/media/video/isp/ispresizer.h b/drivers/media/video/isp/ispresizer.h
index 4e92225..47100e4 100644
--- a/drivers/media/video/isp/ispresizer.h
+++ b/drivers/media/video/isp/ispresizer.h
@@ -66,7 +66,7 @@
* - free()
*/
-enum ispresizer_input {
+enum resizer_input {
RSZ_OTFLY_YUV,
RSZ_MEM_YUV,
RSZ_MEM_COL8
@@ -104,55 +104,87 @@
u8 coreoffset;
};
-void ispresizer_config_shadow_registers(void);
+/**
+ * struct isp_res_device - Structure for the resizer module to store its
+ * information.
+ * @res_inuse: Indicates if resizer module has been reserved. 1 - Reserved,
+ * 0 - Freed.
+ * @h_startphase: Horizontal starting phase.
+ * @v_startphase: Vertical starting phase.
+ * @h_resz: Horizontal resizing value.
+ * @v_resz: Vertical resizing value.
+ * @outputwidth: Output Image Width in pixels.
+ * @outputheight: Output Image Height in pixels.
+ * @inputwidth: Input Image Width in pixels.
+ * @inputheight: Input Image Height in pixels.
+ * @algo: Algorithm select. 0 - Disable, 1 - [-1 2 -1]/2 high-pass filter,
+ * 2 - [-1 -2 6 -2 -1]/4 high-pass filter.
+ * @ipht_crop: Vertical start line for cropping.
+ * @ipwd_crop: Horizontal start pixel for cropping.
+ * @cropwidth: Crop Width.
+ * @cropheight: Crop Height.
+ * @resinput: Resizer input.
+ * @coeflist: Register configuration for Resizer.
+ * @ispres_mutex: Mutex for isp resizer.
+ */
+struct isp_res_device {
+ u8 res_inuse;
+ u8 h_startphase;
+ u8 v_startphase;
+ u16 h_resz;
+ u16 v_resz;
+ u8 algo;
+ dma_addr_t in_buf_addr;
+ dma_addr_t in_buf_addr_off;
+ struct isprsz_coef coeflist;
+ struct mutex ispres_mutex; /* For checking/modifying res_inuse */
+ struct isprsz_yenh defaultyenh;
+ int applycrop;
+};
-int ispresizer_request(void);
+int ispresizer_config_crop(struct isp_res_device *isp_res,
+ struct v4l2_crop *a);
+void ispresizer_config_shadow_registers(struct isp_res_device *isp_res);
-int ispresizer_free(void);
+int ispresizer_request(struct isp_res_device *isp_res);
-int ispresizer_config_datapath(enum ispresizer_input input);
+int ispresizer_free(struct isp_res_device *isp_res);
-void ispresizer_enable_cbilin(u8 enable);
+void ispresizer_enable_cbilin(struct isp_res_device *isp_res, u8 enable);
-void ispresizer_config_ycpos(u8 yc);
+void ispresizer_config_ycpos(struct isp_res_device *isp_res, u8 yc);
-void ispresizer_config_startphase(u8 hstartphase, u8 vstartphase);
+void ispresizer_config_startphase(struct isp_res_device *isp_res,
+ u8 hstartphase, u8 vstartphase);
-void ispresizer_config_filter_coef(struct isprsz_coef *coef);
+void ispresizer_config_filter_coef(struct isp_res_device *isp_res,
+ struct isprsz_coef *coef);
-void ispresizer_config_luma_enhance(struct isprsz_yenh *yenh);
+void ispresizer_config_luma_enhance(struct isp_res_device *isp_res,
+ struct isprsz_yenh *yenh);
-int ispresizer_try_size(u32 *input_w, u32 *input_h, u32 *output_w,
- u32 *output_h);
+int ispresizer_try_pipeline(struct isp_res_device *isp_res,
+ struct isp_pipeline *pipe);
-void ispresizer_applycrop(void);
+int ispresizer_s_pipeline(struct isp_res_device *isp_res,
+ struct isp_pipeline *pipe);
-void ispresizer_trycrop(u32 left, u32 top, u32 width, u32 height, u32 ow,
- u32 oh);
+int ispresizer_config_inlineoffset(struct isp_res_device *isp_res, u32 offset);
-int ispresizer_config_size(u32 input_w, u32 input_h, u32 output_w,
- u32 output_h);
+int ispresizer_set_inaddr(struct isp_res_device *isp_res, u32 addr, u32 offset);
-int ispresizer_config_inlineoffset(u32 offset);
+int ispresizer_config_outlineoffset(struct isp_res_device *isp_res, u32 offset);
-int ispresizer_set_inaddr(u32 addr);
+int ispresizer_set_outaddr(struct isp_res_device *isp_res, u32 addr);
-int ispresizer_config_outlineoffset(u32 offset);
+void ispresizer_enable(struct isp_res_device *isp_res, int enable);
-int ispresizer_set_outaddr(u32 addr);
+int ispresizer_busy(struct isp_res_device *isp_res);
-void ispresizer_enable(int enable);
+void ispresizer_save_context(struct device *dev);
-void ispresizer_suspend(void);
+void ispresizer_restore_context(struct device *dev);
-void ispresizer_resume(void);
-
-int ispresizer_busy(void);
-
-void ispresizer_save_context(void);
-
-void ispresizer_restore_context(void);
-
-void ispresizer_print_status(void);
+void ispresizer_print_status(struct isp_res_device *isp_res);
#endif /* OMAP_ISP_RESIZER_H */
diff --git a/drivers/media/video/isp/ispstat.c b/drivers/media/video/isp/ispstat.c
new file mode 100644
index 0000000..ca2d337
--- /dev/null
+++ b/drivers/media/video/isp/ispstat.c
@@ -0,0 +1,342 @@
+/*
+ * ispstat.c
+ *
+ * STAT module for TI's OMAP3 Camera ISP
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contributors:
+ * Sergio Aguirre <saaguirre@ti.com>
+ * Troy Laramy
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/uaccess.h>
+
+#include "isp.h"
+
+inline int greater_overflow(int a, int b, int limit)
+{
+ int limit2 = limit / 2;
+
+ if (b - a > limit2)
+ return 1;
+ else if (a - b > limit2)
+ return 0;
+ else
+ return a > b;
+}
+
+int ispstat_buf_queue(struct ispstat *stat)
+{
+ unsigned long flags;
+
+ if (!stat->active_buf)
+ return -1;
+
+ do_gettimeofday(&stat->active_buf->ts);
+
+ spin_lock_irqsave(&stat->lock, flags);
+
+ stat->active_buf->config_counter = stat->config_counter;
+ stat->active_buf->frame_number = stat->frame_number;
+
+ stat->frame_number++;
+ if (stat->frame_number == stat->max_frame)
+ stat->frame_number = 0;
+
+ stat->active_buf = NULL;
+
+ spin_unlock_irqrestore(&stat->lock, flags);
+
+ return 0;
+}
+
+/* Get next free buffer to write the statistics to and mark it active. */
+struct ispstat_buffer *ispstat_buf_next(struct ispstat *stat)
+{
+ unsigned long flags;
+ struct ispstat_buffer *found = NULL;
+ int i;
+
+ spin_lock_irqsave(&stat->lock, flags);
+
+ if (stat->active_buf)
+ dev_dbg(stat->dev, "%s: new buffer requested without queuing "
+ "active one.\n", stat->tag);
+
+ for (i = 0; i < stat->nbufs; i++) {
+ struct ispstat_buffer *curr = &stat->buf[i];
+
+ /*
+ * Don't select the buffer which is being copied to
+ * userspace.
+ */
+ if (curr == stat->locked_buf)
+ continue;
+
+ /* Uninitialised buffer -- pick that one over anything else. */
+ if (curr->frame_number == stat->max_frame) {
+ found = curr;
+ break;
+ }
+
+ if (!found ||
+ !greater_overflow(curr->frame_number, found->frame_number,
+ stat->max_frame))
+ found = curr;
+ }
+
+ stat->active_buf = found;
+
+ spin_unlock_irqrestore(&stat->lock, flags);
+
+ return found;
+}
+
+/* Get buffer to userspace. */
+static struct ispstat_buffer *ispstat_buf_find(
+ struct ispstat *stat, u32 frame_number)
+{
+ int i;
+
+ for (i = 0; i < stat->nbufs; i++) {
+ struct ispstat_buffer *curr = &stat->buf[i];
+
+ /* We cannot deal with the active buffer. */
+ if (curr == stat->active_buf)
+ continue;
+
+ /* Don't take uninitialised buffers. */
+ if (curr->frame_number == stat->max_frame)
+ continue;
+
+ /* Found correct number. */
+ if (curr->frame_number == frame_number)
+ return curr;
+ }
+
+ return NULL;
+}
+
+/**
+ * ispstat_stats_available - Check for stats available of specified frame.
+ * @aewbdata: Pointer to return AE AWB statistics data
+ *
+ * Returns 0 if successful, or -1 if statistics are unavailable.
+ **/
+struct ispstat_buffer *ispstat_buf_get(struct ispstat *stat,
+ void __user *ptr,
+ unsigned int frame_number)
+{
+ int rval = 0;
+ unsigned long flags;
+ struct ispstat_buffer *buf;
+
+ spin_lock_irqsave(&stat->lock, flags);
+
+ buf = ispstat_buf_find(stat, frame_number);
+ if (!buf) {
+ spin_unlock_irqrestore(&stat->lock, flags);
+ dev_dbg(stat->dev, "%s: cannot find requested buffer. "
+ "frame_number = %d\n", stat->tag, frame_number);
+ return ERR_PTR(-EBUSY);
+ }
+
+ stat->locked_buf = buf;
+
+ spin_unlock_irqrestore(&stat->lock, flags);
+
+ rval = copy_to_user((void *)ptr,
+ buf->virt_addr,
+ stat->buf_size);
+
+ if (rval) {
+ dev_info(stat->dev,
+ "%s: failed copying %d bytes of stat data\n",
+ stat->tag, rval);
+ buf = ERR_PTR(-EFAULT);
+ ispstat_buf_release(stat);
+ }
+
+ return buf;
+}
+
+void ispstat_buf_release(struct ispstat *stat)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&stat->lock, flags);
+ stat->locked_buf = NULL;
+ spin_unlock_irqrestore(&stat->lock, flags);
+}
+
+void ispstat_bufs_free(struct ispstat *stat)
+{
+ struct isp_device *isp = dev_get_drvdata(stat->dev);
+ int i;
+
+ for (i = 0; i < stat->nbufs; i++) {
+ struct ispstat_buffer *buf = &stat->buf[i];
+
+ if (!stat->dma_buf) {
+ if (!buf->iommu_addr)
+ continue;
+
+ iommu_vfree(isp->iommu, buf->iommu_addr);
+ } else {
+ if (!buf->virt_addr)
+ continue;
+
+ dma_free_coherent(stat->dev, stat->buf_alloc_size,
+ buf->virt_addr, buf->dma_addr);
+ }
+ buf->iommu_addr = 0;
+ buf->dma_addr = 0;
+ buf->virt_addr = NULL;
+ }
+
+ stat->buf_alloc_size = 0;
+}
+
+static int ispstat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size)
+{
+ struct isp_device *isp = dev_get_drvdata(stat->dev);
+ int i;
+
+ stat->buf_alloc_size = size;
+
+ for (i = 0; i < stat->nbufs; i++) {
+ struct ispstat_buffer *buf = &stat->buf[i];
+
+ WARN_ON(buf->dma_addr);
+ buf->iommu_addr = iommu_vmalloc(isp->iommu, 0, size,
+ IOMMU_FLAG);
+ if (buf->iommu_addr == 0) {
+ dev_err(stat->dev,
+ "%s stat: Can't acquire memory for "
+ "buffer %d\n", stat->tag, i);
+ ispstat_bufs_free(stat);
+ return -ENOMEM;
+ }
+ buf->virt_addr = da_to_va(isp->iommu, (u32)buf->iommu_addr);
+ buf->frame_number = stat->max_frame;
+ }
+ stat->dma_buf = 0;
+
+ return 0;
+}
+
+static int ispstat_bufs_alloc_dma(struct ispstat *stat, unsigned int size)
+{
+ int i;
+
+ /* dma_alloc_coherent() size is PAGE_ALIGNED */
+ size = PAGE_ALIGN(size);
+ stat->buf_alloc_size = size;
+
+ for (i = 0; i < stat->nbufs; i++) {
+ struct ispstat_buffer *buf = &stat->buf[i];
+
+ WARN_ON(buf->iommu_addr);
+ buf->virt_addr = dma_alloc_coherent(stat->dev, size,
+ &buf->dma_addr, GFP_KERNEL | GFP_DMA);
+
+ if (!buf->virt_addr || !buf->dma_addr) {
+ dev_info(stat->dev,
+ "%s stat: Can't acquire memory for "
+ "DMA buffer %d\n", stat->tag, i);
+ ispstat_bufs_free(stat);
+ return -ENOMEM;
+ }
+ buf->frame_number = stat->max_frame;
+ }
+ stat->dma_buf = 1;
+
+ return 0;
+}
+
+int ispstat_bufs_alloc(struct ispstat *stat,
+ unsigned int size, int dma_buf)
+{
+ struct isp_device *isp = dev_get_drvdata(stat->dev);
+ unsigned long flags;
+ int ret = 0;
+ int i;
+
+ spin_lock_irqsave(&stat->lock, flags);
+
+ BUG_ON(stat->locked_buf != NULL);
+
+ dma_buf = dma_buf ? 1 : 0;
+
+ /* Are the old buffers big enough? */
+ if ((stat->buf_alloc_size >= size) && (stat->dma_buf == dma_buf)) {
+ for (i = 0; i < stat->nbufs; i++)
+ stat->buf[i].frame_number = stat->max_frame;
+ spin_unlock_irqrestore(&stat->lock, flags);
+ goto out;
+ }
+
+ if (isp->running != ISP_STOPPED) {
+ dev_info(stat->dev,
+ "%s stat: trying to configure when busy\n",
+ stat->tag);
+ spin_unlock_irqrestore(&stat->lock, flags);
+ return -EBUSY;
+ }
+
+ spin_unlock_irqrestore(&stat->lock, flags);
+
+ ispstat_bufs_free(stat);
+
+ if (dma_buf)
+ ret = ispstat_bufs_alloc_dma(stat, size);
+ else
+ ret = ispstat_bufs_alloc_iommu(stat, size);
+ if (ret)
+ size = 0;
+
+out:
+ stat->buf_size = size;
+ stat->active_buf = NULL;
+
+ return ret;
+}
+
+int ispstat_init(struct device *dev, char *tag, struct ispstat *stat,
+ unsigned int nbufs, unsigned int max_frame)
+{
+ BUG_ON(nbufs < 2);
+ BUG_ON(max_frame < 2);
+ BUG_ON(nbufs >= max_frame);
+
+ memset(stat, 0, sizeof(*stat));
+
+ stat->buf = kcalloc(nbufs, sizeof(*stat->buf), GFP_KERNEL);
+ if (!stat->buf)
+ return -ENOMEM;
+
+ spin_lock_init(&stat->lock);
+ stat->nbufs = nbufs;
+ stat->dev = dev;
+ stat->tag = tag;
+ stat->max_frame = max_frame;
+ stat->frame_number = 1;
+
+ return 0;
+}
+
+void ispstat_free(struct ispstat *stat)
+{
+ ispstat_bufs_free(stat);
+ kfree(stat->buf);
+}
diff --git a/drivers/media/video/isp/ispstat.h b/drivers/media/video/isp/ispstat.h
new file mode 100644
index 0000000..984a76b
--- /dev/null
+++ b/drivers/media/video/isp/ispstat.h
@@ -0,0 +1,69 @@
+/*
+ * ispstat.h
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef ISPSTAT_H
+#define ISPSTAT_H
+
+#include "isp.h"
+
+struct ispstat_buffer {
+ unsigned long iommu_addr;
+ void *virt_addr;
+ dma_addr_t dma_addr;
+ struct timeval ts;
+ u32 config_counter;
+ u32 frame_number;
+};
+
+struct ispstat {
+ spinlock_t lock; /* Lock for this struct */
+
+ u8 dma_buf;
+ unsigned int nbufs;
+ struct ispstat_buffer *buf;
+ unsigned int buf_size;
+ unsigned int buf_alloc_size;
+ struct ispstat_buffer *active_buf;
+ struct ispstat_buffer *locked_buf;
+ unsigned int frame_number;
+ unsigned int max_frame;
+ unsigned int config_counter;
+
+ struct device *dev;
+ char *tag; /* ispstat instantiation tag */
+};
+
+int ispstat_buf_queue(struct ispstat *stat);
+struct ispstat_buffer *ispstat_buf_next(struct ispstat *stat);
+struct ispstat_buffer *ispstat_buf_get(struct ispstat *stat,
+ void __user *ptr,
+ unsigned int frame_number);
+void ispstat_buf_release(struct ispstat *stat);
+void ispstat_bufs_free(struct ispstat *stat);
+int ispstat_bufs_alloc(struct ispstat *stat,
+ unsigned int size, int dma_buf);
+int ispstat_init(struct device *dev, char *tag, struct ispstat *stat,
+ unsigned int nbufs, unsigned int max_frame);
+void ispstat_free(struct ispstat *stat);
+
+#endif /* ISPSTAT_H */
diff --git a/drivers/media/video/isp/omap_previewer.c b/drivers/media/video/isp/omap_previewer.c
index 6405ea5..22bcab3 100644
--- a/drivers/media/video/isp/omap_previewer.c
+++ b/drivers/media/video/isp/omap_previewer.c
@@ -32,8 +32,6 @@
#include <asm/cacheflush.h>
#include "isp.h"
-#include "ispmmu.h"
-#include "ispreg.h"
#include "omap_previewer.h"
#define OMAP_PREV_NAME "omap-previewer"
@@ -44,22 +42,20 @@
| (val << shift); \
} while (0)
-/*
-#define OMAP_ISP_PREVIEWER_DEBUG
-*/
-#undef OMAP_ISP_PREVIEWER_DEBUG
-
-#ifdef OMAP_ISP_PREVIEWER_DEBUG
-#define DPRINTK_PREVIEWER(format, ...) \
- printk(KERN_DEBUG "PREV: " format, ## __VA_ARGS__)
-#else
-#define DPRINTK_PREVIEWER(format, ...)
-#endif
-
#define ISP_CTRL_SBL_SHARED_RPORTB (1 << 28)
-#define ISP_CTRL_SBL_SHARED_RPORTA (1 << 27)
+#define ISP_CTRL_SBL_SHARED_RPORTA (1 << 27)
#define SBL_RD_RAM_EN 18
+static struct isp_interface_config prevwrap_config = {
+ .ccdc_par_ser = ISP_NONE,
+ .dataline_shift = 0,
+ .hsvs_syncdetect = ISPCTRL_SYNC_DETECT_VSRISE,
+ .strobe = 0,
+ .prestrobe = 0,
+ .shutter = 0,
+ .wait_hs_vs = 0,
+};
+
static u32 isp_ctrl;
static u32 prv_wsdr_addr;
static int prev_major = -1;
@@ -67,10 +63,9 @@
static struct class *prev_class;
static struct prev_device *prevdevice;
static struct platform_driver omap_previewer_driver;
-
static u32 prev_bufsize;
static u32 lsc_bufsize;
-static u32 ytable[ISPPRV_YENH_TBL_SIZE];
+static struct prev_params isppreview_tmp;
/**
* prev_calculate_crop - Calculate crop size according to device parameters
@@ -83,22 +78,20 @@
static int prev_calculate_crop(struct prev_device *device,
struct prev_cropsize *crop)
{
- int ret;
-
- dev_dbg(prev_dev, "prev_calculate_crop E\n");
+ int ret = 0;
if (!device || !crop) {
- dev_err(prev_dev, "\nErron in argument");
+ dev_err(prev_dev, "%s: invalid argument\n", __func__);
return -EINVAL;
}
- ret = isppreview_try_size(device->params->size_params.hsize,
- device->params->size_params.vsize,
- &crop->hcrop, &crop->vcrop);
+ crop->hcrop = device->out_hsize;
+ crop->vcrop = device->out_vsize;
- crop->hcrop &= PREV_16PIX_ALIGN_MASK;
-
- dev_dbg(prev_dev, "prev_calculate_crop L\n");
+ dev_dbg(prev_dev, "%s: Exit (%dx%d -> %dx%d)\n", __func__,
+ device->params->size_params.hsize,
+ device->params->size_params.vsize,
+ crop->hcrop, crop->vcrop);
return ret;
}
@@ -113,11 +106,13 @@
**/
static int prev_get_status(struct prev_status *status)
{
+ struct isp_device *isp = dev_get_drvdata(prevdevice->isp);
+
if (!status) {
- dev_err(prev_dev, "get_status: invalid parameter\n");
+ dev_err(prev_dev, "%s: invalid argument\n", __func__);
return -EINVAL;
}
- status->hw_busy = (char)isppreview_busy();
+ status->hw_busy = (char)isppreview_busy(&isp->isp_prev);
return 0;
}
@@ -132,45 +127,47 @@
**/
static int prev_hw_setup(struct prev_params *config)
{
- dev_dbg(prev_dev, "prev_hw_setup E\n");
+ struct isp_device *isp = dev_get_drvdata(prevdevice->isp);
+
+ dev_dbg(prev_dev, "%s: Enter\n", __func__);
if (config->features & PREV_AVERAGER)
- isppreview_config_averager(config->average);
+ isppreview_config_averager(&isp->isp_prev, config->average);
else
- isppreview_config_averager(0);
+ isppreview_config_averager(&isp->isp_prev, 0);
if (config->features & PREV_INVERSE_ALAW)
- isppreview_enable_invalaw(1);
+ isppreview_enable_invalaw(&isp->isp_prev, 1);
else
- isppreview_enable_invalaw(0);
+ isppreview_enable_invalaw(&isp->isp_prev, 0);
if (config->features & PREV_HORZ_MEDIAN_FILTER) {
- isppreview_config_hmed(config->hmf_params);
- isppreview_enable_hmed(1);
+ isppreview_config_hmed(&isp->isp_prev, config->hmf_params);
+ isppreview_enable_hmed(&isp->isp_prev, 1);
} else
- isppreview_enable_hmed(0);
+ isppreview_enable_hmed(&isp->isp_prev, 0);
if (config->features & PREV_DARK_FRAME_SUBTRACT) {
- DPRINTK_PREVIEWER("[%s] darkaddr %08x, darklineoffset %d\n",
- __func__,
- config->drkf_params.addr,
- config->drkf_params.offset);
- isppreview_set_darkaddr(config->drkf_params.addr);
- isppreview_config_darklineoffset(config->drkf_params.offset);
- isppreview_enable_drkframe(1);
+ dev_dbg(prev_dev, "%s: darkaddr %08x, darklineoffset %d\n",
+ __func__,
+ config->drkf_params.addr,
+ config->drkf_params.offset);
+ isppreview_set_darkaddr(&isp->isp_prev,
+ config->drkf_params.addr);
+ isppreview_config_darklineoffset(&isp->isp_prev,
+ config->drkf_params.offset);
+ isppreview_enable_drkframe(&isp->isp_prev, 1);
} else
- isppreview_enable_drkframe(0);
+ isppreview_enable_drkframe(&isp->isp_prev, 0);
if (config->features & PREV_LENS_SHADING) {
- isppreview_config_drkf_shadcomp(config->lens_shading_shift);
- isppreview_enable_shadcomp(1);
+ isppreview_config_drkf_shadcomp(&isp->isp_prev,
+ config->lens_shading_shift);
+ isppreview_enable_shadcomp(&isp->isp_prev, 1);
} else
- isppreview_enable_shadcomp(0);
+ isppreview_enable_shadcomp(&isp->isp_prev, 0);
- if (config->ytable)
- isppreview_set_luma_enhancement(config->ytable);
-
- dev_dbg(prev_dev, "prev_hw_setup L\n");
+ dev_dbg(prev_dev, "%s: Exit\n", __func__);
return 0;
}
@@ -185,26 +182,25 @@
static int prev_validate_params(struct prev_params *params)
{
if (!params) {
- dev_err(prev_dev, "validate_params: error in argument");
+ dev_err(prev_dev, "%s: invalid argument\n", __func__);
goto err_einval;
}
if ((params->features & PREV_AVERAGER) == PREV_AVERAGER) {
if ((params->average != NO_AVE)
- && (params->average != AVE_2_PIX)
- && (params->average != AVE_4_PIX)
- && (params->average != AVE_8_PIX)) {
- dev_err(prev_dev, "validate_params: wrong pix "
- "average\n");
+ && (params->average != AVE_2_PIX)
+ && (params->average != AVE_4_PIX)
+ && (params->average != AVE_8_PIX)) {
+ dev_err(prev_dev, "%s: wrong pix average\n", __func__);
goto err_einval;
} else if (((params->average == AVE_2_PIX)
- && (params->size_params.hsize % 2))
- || ((params->average == AVE_4_PIX)
- && (params->size_params.hsize % 4))
- || ((params->average == AVE_8_PIX)
- && (params->size_params.hsize % 8))) {
- dev_err(prev_dev, "validate_params: "
- "wrong pix average for input size\n");
+ && (params->size_params.hsize % 2))
+ || ((params->average == AVE_4_PIX)
+ && (params->size_params.hsize % 4))
+ || ((params->average == AVE_8_PIX)
+ && (params->size_params.hsize % 8))) {
+ dev_err(prev_dev, "%s: wrong pix average for input"
+ " size\n", __func__);
goto err_einval;
}
}
@@ -212,45 +208,47 @@
if ((params->size_params.pixsize != PREV_INWIDTH_8BIT)
&& (params->size_params.pixsize
!= PREV_INWIDTH_10BIT)) {
- dev_err(prev_dev, "validate_params: wrong pixsize\n");
+ dev_err(prev_dev, "%s: wrong pixsize\n", __func__);
goto err_einval;
}
if (params->size_params.hsize > MAX_IMAGE_WIDTH
|| params->size_params.hsize < 0) {
- dev_err(prev_dev, "validate_params: wrong hsize\n");
+ dev_err(prev_dev, "%s: wrong hsize\n", __func__);
goto err_einval;
}
if (params->size_params.hsize % 32) {
- dev_err(prev_dev, "validate_params: width must be multiple of"
- " 64 bytes\n");
+ dev_err(prev_dev, "%s: width must be multiple of"
+ " 64 bytes\n", __func__);
goto err_einval;
}
if ((params->pix_fmt != YCPOS_YCrYCb)
- && (YCPOS_YCbYCr != params->pix_fmt)
- && (YCPOS_CbYCrY != params->pix_fmt)
- && (YCPOS_CrYCbY != params->pix_fmt)) {
- dev_err(prev_dev, "validate_params: wrong pix_fmt");
+ && (YCPOS_YCbYCr != params->pix_fmt)
+ && (YCPOS_CbYCrY != params->pix_fmt)
+ && (YCPOS_CrYCbY != params->pix_fmt)) {
+ dev_err(prev_dev, "%s: wrong pix_fmt\n", __func__);
goto err_einval;
}
if ((params->features & PREV_DARK_FRAME_SUBTRACT)
- && (params->features
- & PREV_DARK_FRAME_CAPTURE)) {
- dev_err(prev_dev, "validate_params: DARK FRAME CAPTURE and "
- "SUBSTRACT cannot be enabled "
- "at same time\n");
+ && (params->features & PREV_DARK_FRAME_CAPTURE)) {
+ dev_err(prev_dev, "%s: DARK FRAME CAPTURE and SUBSTRACT "
+ "cannot be enabled at same time\n", __func__);
goto err_einval;
}
if ((params->size_params.in_pitch <= 0)
- || (params->size_params.in_pitch % 32)) {
- params->size_params.in_pitch =
- (params->size_params.hsize * 2) & 0xFFE0;
- dev_err(prev_dev, "Error in in_pitch; new value = %d\n",
- params->size_params.in_pitch);
+ || (params->size_params.in_pitch % 32)) {
+ dev_err(prev_dev, "%s: invalid input pitch\n", __func__);
+ goto err_einval;
+ }
+
+ if ((params->size_params.out_pitch <= 0)
+ || (params->size_params.out_pitch % 32)) {
+ dev_err(prev_dev, "%s: invalid output pitch\n", __func__);
+ goto err_einval;
}
return 0;
@@ -283,7 +281,7 @@
{
u32 val;
- val = isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+ val = isp_reg_readl(prevdevice->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
isp_ctrl = val;
@@ -297,9 +295,10 @@
BIT_SET(val, SBL_RD_RAM_EN, 0x1, 0x1);
/* write ISP CTRL register */
- isp_reg_writel(val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+ isp_reg_writel(prevdevice->isp, val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
- prv_wsdr_addr = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
+ prv_wsdr_addr = isp_reg_readl(prevdevice->isp, OMAP3_ISP_IOMEM_PREV,
+ ISPPRV_WSDR_ADDR);
}
/*
@@ -307,9 +306,10 @@
*/
static void prev_unset_isp_ctrl(void)
{
+ struct isp_device *isp = dev_get_drvdata(prevdevice->isp);
u32 val;
- val = isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+ val = isp_reg_readl(prevdevice->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
if (isp_ctrl & ISP_CTRL_SBL_SHARED_RPORTB)
val |= ISP_CTRL_SBL_SHARED_RPORTB;
@@ -321,14 +321,86 @@
val &= ~(1 << SBL_RD_RAM_EN);
/* write ISP CTRL register */
- isp_reg_writel(val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+ isp_reg_writel(prevdevice->isp, val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
/* disable dark frame and shading compensation */
- isppreview_enable_drkframe(0);
- isppreview_enable_shadcomp(0);
+ isppreview_enable_drkframe(&isp->isp_prev, 0);
+ isppreview_enable_shadcomp(&isp->isp_prev, 0);
/* Set output and input adresses to 0 */
- isppreview_set_outaddr(prv_wsdr_addr);
+ isppreview_set_outaddr(&isp->isp_prev, prv_wsdr_addr);
+}
+
+/**
+ * prev_config_size - Set input width and height in previewer registers
+ * @input_w: input width
+ * @inout_h: input height
+ *
+ * Returns 0 if successful, or -EINVAL if the sent parameters are invalid.
+ **/
+static void prev_config_size(u32 input_w, u32 input_h)
+{
+ isp_reg_writel(prevdevice->isp,
+ (0 << ISPPRV_HORZ_INFO_SPH_SHIFT) | (input_w - 1),
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
+
+ isp_reg_writel(prevdevice->isp,
+ (0 << ISPPRV_VERT_INFO_SLV_SHIFT) | (input_h - 1),
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
+
+ isp_reg_writel(prevdevice->isp,
+ (ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT) |
+ (ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT),
+ OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
+}
+
+/**
+ * prev_negotiate_output_size - Calculate previewer engine output size
+ * @device: Structure containing ISP preview wrapper global information
+ * @out_hsize: Return horizontal size
+ * @out_vsize: Return vertical size
+ *
+ * Returns 0 if successful, or -EINVAL if the sent parameters are invalid.
+ **/
+static int prev_negotiate_output_size(struct prev_device *prvdev,
+ u32 *out_hsize, u32 *out_vsize)
+{
+ struct isp_device *isp = dev_get_drvdata(prvdev->isp);
+ int bpp, ret;
+ struct isp_pipeline pipe;
+
+ if (prvdev->params->size_params.pixsize == PREV_INWIDTH_8BIT)
+ bpp = 1;
+ else
+ bpp = 2;
+
+ pipe.prv_in = PRV_RAW_MEM;
+ pipe.prv_out = PREVIEW_MEM;
+ pipe.ccdc_out_w = prvdev->params->size_params.hsize;
+ pipe.ccdc_out_w_img = prvdev->params->size_params.hsize;
+ pipe.ccdc_out_h = prvdev->params->size_params.vsize;
+
+ ret = isppreview_config_datapath(&isp->isp_prev, &pipe);
+ if (ret) {
+ dev_err(prev_dev, "%s: ERROR while configure isp "
+ "preview datapath!\n", __func__);
+ return ret;
+ }
+
+ ret = isppreview_try_pipeline(&isp->isp_prev, &pipe);
+ if (ret) {
+ dev_err(prev_dev, "%s: ERROR while try isp preview size!\n",
+ __func__);
+ return ret;
+ }
+
+ dev_dbg(prev_dev, "%s: try size %dx%d -> %dx%d\n", __func__,
+ pipe.ccdc_out_w_img, pipe.ccdc_out_h,
+ pipe.prv_out_w, pipe.prv_out_h);
+
+ *out_hsize = pipe.prv_out_w_img;
+ *out_vsize = pipe.prv_out_h_img;
+ return 0;
}
/**
@@ -339,111 +411,86 @@
**/
static int prev_do_preview(struct prev_device *device)
{
- int bpp, size;
- int ret = 0;
- u32 out_hsize, out_vsize, out_line_offset;
+ struct isp_device *isp = dev_get_drvdata(device->isp);
+ u32 out_hsize, out_vsize, out_line_offset, in_line_offset;
+ int ret = 0, bpp;
- dev_dbg(prev_dev, "prev_do_preview E\n");
+ dev_dbg(prev_dev, "%s: Enter\n", __func__);
if (!device) {
- dev_err(prev_dev, "preview: invalid parameters\n");
+ dev_err(prev_dev, "%s: invalid argument\n", __func__);
return -EINVAL;
}
prev_set_isp_ctrl(device->params->features);
- isppreview_set_skip(2, 0);
if (device->params->size_params.pixsize == PREV_INWIDTH_8BIT)
bpp = 1;
else
bpp = 2;
- size = device->params->size_params.hsize *
- device->params->size_params.vsize * bpp;
+ out_hsize = device->out_hsize;
+ out_vsize = device->out_vsize;
- isppreview_config_datapath(PRV_RAW_MEM, PREVIEW_MEM);
+ in_line_offset = device->params->size_params.hsize * bpp;
- ret = isppreview_try_size(device->params->size_params.hsize,
- device->params->size_params.vsize,
- &out_hsize, &out_vsize);
-
- if (ret) {
- dev_err(prev_dev, "ERROR while try size!\n");
- goto out;
- }
-
- ret = isppreview_config_inlineoffset(device->params->size_params.hsize
- * bpp);
+ ret = isppreview_config_inlineoffset(&isp->isp_prev, in_line_offset);
if (ret)
goto out;
+ dev_dbg(prev_dev, "%s: out_pitch %d, output width %d, out_hsize %d, "
+ "out_vsize %d\n", __func__,
+ device->params->size_params.out_pitch,
+ device->params->size_params.out_pitch / bpp,
+ out_hsize, out_vsize);
+
out_line_offset = (out_hsize * bpp) & PREV_32BYTES_ALIGN_MASK;
- ret = isppreview_config_outlineoffset(out_line_offset);
+ ret = isppreview_config_outlineoffset(&isp->isp_prev, out_line_offset);
if (ret)
goto out;
- ret = isppreview_config_size(device->params->size_params.hsize,
- device->params->size_params.vsize,
- out_hsize, out_vsize);
- if (ret)
- goto out;
+ prev_config_size(device->params->size_params.hsize,
+ device->params->size_params.vsize);
device->params->drkf_params.addr = device->isp_addr_lsc;
prev_hw_setup(device->params);
- ret = isppreview_set_inaddr(device->isp_addr_read);
+ ret = isppreview_set_inaddr(&isp->isp_prev, device->isp_addr_read);
if (ret)
goto out;
- ret = isppreview_set_outaddr(device->isp_addr_read);
+ ret = isppreview_set_outaddr(&isp->isp_prev, device->isp_addr_read);
if (ret)
goto out;
- isppreview_config_datapath(PRV_RAW_MEM, PREVIEW_MEM);
-
- isppreview_try_size(device->params->size_params.hsize,
- device->params->size_params.vsize,
- &out_hsize,
- &out_vsize);
-
- ret = isppreview_config_inlineoffset(device->params->size_params.hsize
- * bpp);
- if (ret)
- goto out;
-
- out_line_offset = (out_hsize * bpp) & PREV_32BYTES_ALIGN_MASK;
-
- ret = isppreview_config_outlineoffset(out_line_offset);
- if (ret)
- goto out;
-
- ret = isppreview_config_size(device->params->size_params.hsize,
- device->params->size_params.vsize,
- out_hsize, out_vsize);
-
- ret = isp_set_callback(CBK_PREV_DONE, prev_isr, (void *) device,
- (void *) NULL);
+ ret = isp_set_callback(device->isp, CBK_PREV_DONE, prev_isr,
+ (void *) device, (void *) NULL);
if (ret) {
- dev_err(prev_dev, "ERROR while setting Previewer callback!\n");
+ dev_err(prev_dev,
+ "%s: setting previewer callback failed\n", __func__);
goto out;
}
/* Make sure we don't wait for any HS_VS interrupts */
- isp_set_hs_vs(0);
+ isp_set_hs_vs(device->isp, 0);
- isppreview_enable(1);
+ isp_configure_interface(device->isp, &prevwrap_config);
+
+ isp_start(device->isp);
+
+ isppreview_enable(&isp->isp_prev, 1);
wait_for_completion_interruptible(&device->wfc);
- isppreview_enable(0);
+ isppreview_enable(&isp->isp_prev, 0);
- ret = isp_unset_callback(CBK_PREV_DONE);
+ ret = isp_unset_callback(device->isp, CBK_PREV_DONE);
prev_unset_isp_ctrl();
- dev_dbg(prev_dev, "prev_do_preview L\n");
+ dev_dbg(prev_dev, "%s: Exit\n", __func__);
out:
return ret;
}
@@ -459,14 +506,16 @@
struct prev_fh *fh = q->priv_data;
struct prev_device *device = fh->device;
+ dev_dbg(prev_dev, "%s: Enter\n", __func__);
+
if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ispmmu_vunmap(device->isp_addr_read);
+ ispmmu_vunmap(device->isp, device->isp_addr_read);
device->isp_addr_read = 0;
spin_lock(&device->inout_vbq_lock);
vb->state = VIDEOBUF_NEEDS_INIT;
spin_unlock(&device->inout_vbq_lock);
} else if (q->type == V4L2_BUF_TYPE_PRIVATE) {
- ispmmu_vunmap(device->isp_addr_lsc);
+ ispmmu_vunmap(device->isp, device->isp_addr_lsc);
device->isp_addr_lsc = 0;
spin_lock(&device->lsc_vbq_lock);
vb->state = VIDEOBUF_NEEDS_INIT;
@@ -478,7 +527,7 @@
videobuf_dma_free(videobuf_to_dma(vb));
}
- dev_dbg(prev_dev, "previewer_vbq_release\n");
+ dev_dbg(prev_dev, "%s: Exit\n", __func__);
}
/**
@@ -497,6 +546,8 @@
struct prev_device *device = fh->device;
u32 bpp = 1;
+ dev_dbg(prev_dev, "%s: Enter\n", __func__);
+
if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
spin_lock(&device->inout_vbq_lock);
@@ -508,13 +559,15 @@
if (!device->params->size_params.hsize ||
!device->params->size_params.vsize) {
- dev_err(prev_dev, "Can't setup inout buffer size\n");
+ dev_err(prev_dev, "%s: Can't setup input/output "
+ "buffer sizes\n", __func__);
spin_unlock(&device->inout_vbq_lock);
return -EINVAL;
}
if (device->params->size_params.pixsize == PREV_INWIDTH_10BIT)
bpp = 2;
+
*size = prev_bufsize = bpp * device->params->size_params.hsize *
device->params->size_params.vsize;
spin_unlock(&device->inout_vbq_lock);
@@ -528,7 +581,8 @@
if (!device->params->size_params.hsize ||
!device->params->size_params.vsize) {
- dev_err(prev_dev, "Can't setup lsc buffer size\n");
+ dev_err(prev_dev, "%s: Can't setup lsc buffer size\n",
+ __func__);
spin_unlock(&device->lsc_vbq_lock);
return -EINVAL;
}
@@ -543,7 +597,7 @@
return -EINVAL;
}
- dev_dbg(prev_dev, "previewer_vbq_setup\n");
+ dev_dbg(prev_dev, "%s: Exit\n", __func__);
return 0;
}
@@ -566,7 +620,7 @@
unsigned int isp_addr;
struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
- dev_dbg(prev_dev, "previewer_vbq_prepare E\n");
+ dev_dbg(prev_dev, "%s: Enter\n", __func__);
if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
spin_lock(&device->inout_vbq_lock);
@@ -574,11 +628,12 @@
if (vb->baddr) {
vb->size = prev_bufsize;
vb->bsize = prev_bufsize;
- DPRINTK_PREVIEWER("[%s] bsize = %d\n", __func__,
- vb->bsize);
+ dev_dbg(prev_dev, "%s: bsize = %d\n",
+ __func__, vb->bsize);
} else {
spin_unlock(&device->inout_vbq_lock);
- dev_err(prev_dev, "No user buffer allocated\n");
+ dev_err(prev_dev, "%s: No user buffer allocated\n",
+ __func__);
goto out;
}
@@ -588,19 +643,21 @@
spin_unlock(&device->inout_vbq_lock);
if (vb->state == VIDEOBUF_NEEDS_INIT) {
- DPRINTK_PREVIEWER("[%s] baddr = %08x\n", __func__,
- (int)vb->baddr);
+ dev_dbg(prev_dev, "%s: baddr = %08x\n",
+ __func__, (int)vb->baddr);
err = videobuf_iolock(q, vb, NULL);
if (!err) {
- isp_addr = ispmmu_vmap(dma->sglist,
- dma->sglen);
+ isp_addr = ispmmu_vmap(device->isp,
+ dma->sglist,
+ dma->sglen);
if (!isp_addr) {
err = -EIO;
} else {
device->isp_addr_read = isp_addr;
- DPRINTK_PREVIEWER("[%s] isp_addr_read ="
- " %08x\n", __func__, isp_addr);
+ dev_dbg(prev_dev, "%s: isp_addr_read "
+ "= %08x\n",
+ __func__, isp_addr);
}
}
}
@@ -620,11 +677,12 @@
if (vb->baddr) {
vb->size = lsc_bufsize;
vb->bsize = lsc_bufsize;
- DPRINTK_PREVIEWER("[%s] bsize = %d\n", __func__,
- vb->bsize);
+ dev_dbg(prev_dev, "%s: bsize = %d\n",
+ __func__, vb->bsize);
} else {
spin_unlock(&device->lsc_vbq_lock);
- dev_err(prev_dev, "No user buffer allocated\n");
+ dev_err(prev_dev, "%s: No user buffer allocated\n",
+ __func__);
goto out;
}
@@ -634,18 +692,20 @@
spin_unlock(&device->lsc_vbq_lock);
if (vb->state == VIDEOBUF_NEEDS_INIT) {
- DPRINTK_PREVIEWER("[%s] baddr = %08x\n", __func__,
- (int)vb->baddr);
+ dev_dbg(prev_dev, "%s: baddr = %08x\n",
+ __func__, (int)vb->baddr);
err = videobuf_iolock(q, vb, NULL);
if (!err) {
- isp_addr = ispmmu_vmap(dma->sglist,
- dma->sglen);
+ isp_addr = ispmmu_vmap(device->isp,
+ dma->sglist,
+ dma->sglen);
if (!isp_addr) {
err = -EIO;
} else {
device->isp_addr_lsc = isp_addr;
- DPRINTK_PREVIEWER("[%s] isp_addr_lsc ="
- " %08x\n", __func__, isp_addr);
+ dev_dbg(prev_dev, "%s: isp_addr_lsc"
+ "= %08x\n",
+ __func__, isp_addr);
}
}
}
@@ -662,7 +722,7 @@
return -EINVAL;
}
- dev_dbg(prev_dev, "previewer_vbq_prepare L\n");
+ dev_dbg(prev_dev, "%s: Exit\n", __func__);
out:
return err;
}
@@ -684,46 +744,44 @@
**/
static int previewer_open(struct inode *inode, struct file *filp)
{
- int ret = 0;
struct prev_device *device = prevdevice;
- struct prev_params *config = isppreview_get_config();
struct prev_fh *fh;
+ int ret = 0;
+ struct device *isp;
+ struct isp_device *isp_dev;
- if (config == NULL) {
- dev_err(prev_dev, "Unable to initialize default config "
- "from isppreviewer\n\n");
- return -EACCES;
- }
+ if (mutex_lock_interruptible(&device->prevwrap_mutex))
+ return -EINTR;
if (device->opened || (filp->f_flags & O_NONBLOCK)) {
- dev_err(prev_dev, "previewer_open: device is already "
- "opened\n");
- return -EBUSY;
+ dev_err(prev_dev, "%s: Device is already opened\n", __func__);
+ ret = -EBUSY;
+ goto err_open_fh;
}
fh = kzalloc(sizeof(struct prev_fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
+ if (NULL == fh) {
+ ret = -ENOMEM;
+ goto err_open_fh;
+ }
- ret = isp_get();
+ isp = isp_get();
+ if (!isp) {
+ dev_err(prev_dev, "%s: Can't acquire isp core\n", __func__);
+ ret = -EACCES;
+ goto err_isp;
+ }
+ device->isp = isp;
+ isp_dev = dev_get_drvdata(isp);
+ device->params = &isp_dev->isp_prev.params;
+ ret = isppreview_request(&isp_dev->isp_prev);
if (ret < 0) {
- kfree(fh);
- printk(KERN_ERR "Can't enable ISP clocks (ret %d)\n", ret);
- return -EACCES;
+ dev_err(prev_dev, "%s: Can't acquire isp preview\n", __func__);
+ goto err_prev;
}
- ret = isppreview_request();
-
- if (ret) {
- kfree(fh);
- isp_put();
- dev_err(prev_dev, "Can't acquire isppreview\n");
- return ret;
- }
-
- device->params = config;
- device->opened = 1;
+ device->opened = true;
filp->private_data = fh;
fh->inout_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -731,20 +789,27 @@
fh->device = device;
videobuf_queue_sg_init(&fh->inout_vbq, &device->vbq_ops, NULL,
- &device->inout_vbq_lock, fh->inout_type,
- V4L2_FIELD_NONE,
- sizeof(struct videobuf_buffer), fh);
+ &device->inout_vbq_lock, fh->inout_type,
+ V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), fh);
videobuf_queue_sg_init(&fh->lsc_vbq, &device->vbq_ops, NULL,
- &device->lsc_vbq_lock, fh->lsc_type,
- V4L2_FIELD_NONE,
- sizeof(struct videobuf_buffer), fh);
+ &device->lsc_vbq_lock, fh->lsc_type,
+ V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), fh);
init_completion(&device->wfc);
- device->wfc.done = 0;
- mutex_init(&device->prevwrap_mutex);
-
+ device->configured = false;
+ mutex_unlock(&device->prevwrap_mutex);
return 0;
+
+err_prev:
+ isp_put();
+err_isp:
+ kfree(fh);
+err_open_fh:
+ mutex_unlock(&device->prevwrap_mutex);
+ return ret;
}
/**
@@ -758,23 +823,25 @@
{
struct prev_fh *fh = filp->private_data;
struct prev_device *device = fh->device;
+ struct isp_device *isp = dev_get_drvdata(device->isp);
struct videobuf_queue *q1 = &fh->inout_vbq;
struct videobuf_queue *q2 = &fh->lsc_vbq;
- device->opened = 0;
- device->params = NULL;
+ if (mutex_lock_interruptible(&device->prevwrap_mutex))
+ return -EINTR;
+ device->opened = false;
videobuf_mmap_free(q1);
videobuf_mmap_free(q2);
videobuf_queue_cancel(q1);
videobuf_queue_cancel(q2);
- isppreview_free();
+ isppreview_free(&isp->isp_prev);
isp_put();
prev_bufsize = 0;
lsc_bufsize = 0;
filp->private_data = NULL;
+ mutex_unlock(&device->prevwrap_mutex);
kfree(fh);
-
- dev_dbg(prev_dev, "previewer_release\n");
+ dev_dbg(prev_dev, "%s: Exit\n", __func__);
return 0;
}
@@ -792,6 +859,141 @@
}
/**
+ * prev_copy_params - Copy usermode params to kernel.
+ * @usr_params: Pointer to usermode structure
+ * @isp_params: Pointer to kernel structure
+ *
+ * Returns 0 if successful, or negative on fail
+ **/
+static int prev_copy_params(struct prev_params *usr_params,
+ struct prev_params *isp_params)
+{
+ isp_params->features = usr_params->features;
+ isp_params->pix_fmt = usr_params->pix_fmt;
+ isp_params->cfa.cfafmt = usr_params->cfa.cfafmt;
+ isp_params->cfa.cfa_gradthrs_vert = usr_params->cfa.cfa_gradthrs_vert;
+ isp_params->cfa.cfa_gradthrs_horz = usr_params->cfa.cfa_gradthrs_horz;
+
+ if (usr_params->cfa.cfa_table && isp_params->cfa.cfa_table) {
+ if (copy_from_user(isp_params->cfa.cfa_table,
+ usr_params->cfa.cfa_table,
+ ISPPRV_CFA_TBL_SIZE * 4))
+ return -EFAULT;
+ } else {
+ dev_warn(prev_dev,
+ "%s: invalid cfa table pointer (usr: %08x,"
+ " krn: %08x)\n", __func__,
+ (int)usr_params->cfa.cfa_table,
+ (int)isp_params->cfa.cfa_table);
+ }
+
+ isp_params->csup = usr_params->csup;
+
+ if (usr_params->ytable && isp_params->ytable) {
+ if (copy_from_user(isp_params->ytable,
+ usr_params->ytable, ISPPRV_YENH_TBL_SIZE * 4))
+ return -EFAULT;
+ } else {
+ dev_warn(prev_dev,
+ "%s: invalid ytable pointer (usr: %08x, krn: %08x)\n",
+ __func__,
+ (int)usr_params->ytable, (int)isp_params->ytable);
+ }
+
+ isp_params->nf = usr_params->nf;
+ isp_params->dcor = usr_params->dcor;
+
+ if (usr_params->gtable.redtable && isp_params->gtable.redtable) {
+ if (copy_from_user(isp_params->gtable.redtable,
+ usr_params->gtable.redtable,
+ ISPPRV_GAMMA_TBL_SIZE * 4))
+ return -EFAULT;
+ } else {
+ dev_warn(prev_dev,
+ "%s: invalid gtable red pointer (usr: %08x, "
+ "krn: %08x)\n", __func__,
+ (int)usr_params->gtable.redtable,
+ (int)isp_params->gtable.redtable);
+ }
+
+ if (usr_params->gtable.greentable && isp_params->gtable.greentable) {
+ if (copy_from_user(isp_params->gtable.greentable,
+ usr_params->gtable.greentable,
+ ISPPRV_GAMMA_TBL_SIZE * 4))
+ return -EFAULT;
+ } else {
+ dev_warn(prev_dev,
+ "%s: invalid gtable green pointer (usr: %08x,"
+ "krn: %08x)\n", __func__,
+ (int)usr_params->gtable.greentable,
+ (int)isp_params->gtable.greentable);
+ }
+
+ if (usr_params->gtable.bluetable && isp_params->gtable.bluetable) {
+ if (copy_from_user(isp_params->gtable.bluetable,
+ usr_params->gtable.bluetable,
+ ISPPRV_GAMMA_TBL_SIZE * 4))
+ return -EFAULT;
+ } else {
+ dev_warn(prev_dev,
+ "%s: invalid gtable blue pointer (usr: %08x,"
+ " krn: %08x)\n", __func__,
+ (int)usr_params->gtable.bluetable,
+ (int)isp_params->gtable.bluetable);
+ }
+
+ isp_params->wbal = usr_params->wbal;
+ isp_params->blk_adj = usr_params->blk_adj;
+ isp_params->rgb2rgb = usr_params->rgb2rgb;
+ isp_params->rgb2ycbcr = usr_params->rgb2ycbcr;
+ isp_params->hmf_params = usr_params->hmf_params;
+ isp_params->size_params = usr_params->size_params;
+ isp_params->drkf_params = usr_params->drkf_params;
+ isp_params->lens_shading_shift = usr_params->lens_shading_shift;
+ isp_params->average = usr_params->average;
+ isp_params->contrast = usr_params->contrast;
+ isp_params->brightness = usr_params->brightness;
+
+ return 0;
+}
+
+static int prev_get_params(struct prev_params __user *usr_params,
+ struct prev_device *device)
+{
+ struct prev_params usr_params_new;
+ u32 *cfa_table; /* params.cfa.cfa_table */
+ u32 *ytable; /* params.ytable */
+ u32 *redtable; /* params.gtable.redtable */
+ u32 *greentable; /* params.gtable.greentable */
+ u32 *bluetable; /* params.gtable.bluetable */
+
+ if (copy_from_user(&usr_params_new, usr_params,
+ sizeof(struct prev_params)))
+ return -EFAULT;
+
+ /* Backup user pointers */
+ cfa_table = usr_params_new.cfa.cfa_table;
+ ytable = usr_params_new.ytable;
+ redtable = usr_params_new.gtable.redtable;
+ greentable = usr_params_new.gtable.greentable;
+ bluetable = usr_params_new.gtable.bluetable;
+
+ memcpy(&usr_params_new, device->params, sizeof(struct prev_params));
+
+ /* Restore user pointers */
+ usr_params_new.cfa.cfa_table = cfa_table;
+ usr_params_new.ytable = ytable;
+ usr_params_new.gtable.redtable = redtable;
+ usr_params_new.gtable.greentable = greentable;
+ usr_params_new.gtable.bluetable = bluetable;
+
+ if (copy_to_user(usr_params, &usr_params_new,
+ sizeof(struct prev_params)))
+ return -EFAULT;
+ return 0;
+}
+
+/**
* previewer_ioctl - I/O control function for Preview Wrapper
* @inode: Inode structure associated with the Preview Wrapper.
* @file: File structure associated with the Preview Wrapper.
@@ -812,11 +1014,11 @@
struct v4l2_buffer b;
struct v4l2_requestbuffers req;
- dev_dbg(prev_dev, "Entering previewer_ioctl()\n");
+ dev_dbg(prev_dev, "%s: Enter\n", __func__);
if ((_IOC_TYPE(cmd) != PREV_IOC_BASE)
|| (_IOC_NR(cmd) > PREV_IOC_MAXNR)) {
- dev_err(prev_dev, "Bad command Value \n");
+ dev_err(prev_dev, "%s: bad command value\n", __func__);
goto err_minusone;
}
@@ -825,7 +1027,7 @@
else if (_IOC_DIR(cmd) & _IOC_WRITE)
ret = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
if (ret) {
- dev_err(prev_dev, "access denied\n");
+ dev_err(prev_dev, "%s: access denied\n", __func__);
goto err_minusone;
}
@@ -902,44 +1104,46 @@
return -EFAULT;
}
- if (params.ytable && copy_from_user(ytable, params.ytable,
- ISPPRV_YENH_TBL_SIZE*sizeof(u32))) {
- mutex_unlock(&device->prevwrap_mutex);
- return -EFAULT;
+ memcpy(&isppreview_tmp, device->params,
+ sizeof(isppreview_tmp));
+
+ ret = prev_copy_params(¶ms, device->params);
+ if (ret) {
+ memcpy(device->params, &isppreview_tmp,
+ sizeof(isppreview_tmp));
+ dev_err(prev_dev, "%s: copy parameters fail\n",
+ __func__);
+ goto out;
}
- ret = prev_validate_params(¶ms);
+ ret = prev_validate_params(device->params);
if (ret < 0) {
- dev_err(prev_dev, "Error validating parameters!\n");
+ memcpy(device->params, &isppreview_tmp,
+ sizeof(isppreview_tmp));
+ dev_err(prev_dev, "%s: validating parameters fail!\n",
+ __func__);
mutex_unlock(&device->prevwrap_mutex);
goto out;
}
- if (device->params) {
- memcpy(device->params, ¶ms,
- sizeof(struct prev_params));
+ device->configured = true;
- if (params.ytable)
- device->params->ytable = ytable;
- } else {
- mutex_unlock(&device->prevwrap_mutex);
- return -EINVAL;
+ ret = prev_negotiate_output_size(device, &device->out_hsize,
+ &device->out_vsize);
+ if (ret) {
+ dev_err(prev_dev, "%s: negotiate output size fail\n",
+ __func__);
+ ret = -EINVAL;
+ goto out;
}
-
- /* Update the values in Preview module now b/c otherwise when
- * isppreview_try_size() is next called it won't update the
- * output size correctly.
- */
- ret = prev_hw_setup(device->params);
- isppreview_config_datapath(PRV_RAW_MEM, PREVIEW_MEM);
+ dev_dbg(prev_dev, "%s: out_hsize %d, out_vsize %d\n", __func__,
+ device->out_hsize, device->out_vsize);
mutex_unlock(&device->prevwrap_mutex);
break;
case PREV_GET_PARAM:
- if (copy_to_user((struct prev_params *)arg, device->params,
- sizeof(struct prev_params)))
- ret = -EFAULT;
+ prev_get_params((struct prev_params *)arg, device);
break;
case PREV_GET_STATUS:
@@ -967,18 +1171,25 @@
{
struct prev_cropsize outputsize;
+ if (device->configured == false) {
+ ret = -EPERM;
+ dev_err(prev_dev, "%s: not configured yet\n",
+ __func__);
+ break;
+ }
+
ret = prev_calculate_crop(device, &outputsize);
if (ret)
break;
if (copy_to_user((struct prev_cropsize *)arg, &outputsize,
- sizeof(struct prev_cropsize)))
+ sizeof(struct prev_cropsize)))
ret = -EFAULT;
break;
}
default:
- dev_err(prev_dev, "previewer_ioctl: Invalid Command Value\n");
+ dev_err(prev_dev, "%s: invalid command value\n", __func__);
ret = -EINVAL;
}
out:
@@ -997,7 +1208,7 @@
**/
static void previewer_platform_release(struct device *device)
{
- dev_dbg(prev_dev, "previewer_platform_release()\n");
+ dev_dbg(prev_dev, "%s: Enter\n", __func__);
}
static const struct file_operations prev_fops = {
@@ -1068,10 +1279,10 @@
prev_major = register_chrdev(0, OMAP_PREV_NAME, &prev_fops);
if (prev_major < 0) {
- dev_err(prev_dev, OMAP_PREV_NAME ": initialization "
- "failed. could not register character "
- "device\n");
- return -ENODEV;
+ dev_err(prev_dev, OMAP_PREV_NAME ": Initialization "
+ "failed. Could not register character device\n");
+ ret = -ENODEV;
+ goto fail1;
}
ret = platform_driver_register(&omap_previewer_driver);
@@ -1094,13 +1305,14 @@
prev_dev = device_create(prev_class, prev_dev,
MKDEV(prev_major, 0), NULL,
OMAP_PREV_NAME);
- dev_dbg(prev_dev, OMAP_PREV_NAME ": Registered Previewer Wrapper\n");
- device->opened = 0;
+ dev_info(prev_dev, OMAP_PREV_NAME ": Registered preview wrapper\n");
+ device->opened = false;
device->vbq_ops.buf_setup = previewer_vbq_setup;
device->vbq_ops.buf_prepare = previewer_vbq_prepare;
device->vbq_ops.buf_release = previewer_vbq_release;
device->vbq_ops.buf_queue = previewer_vbq_queue;
+ mutex_init(&device->prevwrap_mutex);
spin_lock_init(&device->inout_vbq_lock);
spin_lock_init(&device->lsc_vbq_lock);
prevdevice = device;
@@ -1112,7 +1324,8 @@
platform_driver_unregister(&omap_previewer_driver);
fail2:
unregister_chrdev(prev_major, OMAP_PREV_NAME);
-
+fail1:
+ kfree(device);
return ret;
}
diff --git a/drivers/media/video/isp/omap_previewer.h b/drivers/media/video/isp/omap_previewer.h
index 805cd9c..00dcc07 100644
--- a/drivers/media/video/isp/omap_previewer.h
+++ b/drivers/media/video/isp/omap_previewer.h
@@ -143,6 +143,7 @@
struct prev_device {
struct prev_params *params;
unsigned char opened;
+ unsigned char configured;
struct completion wfc;
struct mutex prevwrap_mutex;
spinlock_t inout_vbq_lock; /* Spinlock for in/out videobuf queues. */
@@ -150,6 +151,9 @@
struct videobuf_queue_ops vbq_ops;
dma_addr_t isp_addr_read;
dma_addr_t isp_addr_lsc;
+ u32 out_hsize;
+ u32 out_vsize;
+ struct device *isp;
};
/**
diff --git a/drivers/media/video/isp/omap_resizer.c b/drivers/media/video/isp/omap_resizer.c
index 128f6da..2bc5755 100644
--- a/drivers/media/video/isp/omap_resizer.c
+++ b/drivers/media/video/isp/omap_resizer.c
@@ -30,9 +30,9 @@
#include <linux/uaccess.h>
#include <media/v4l2-dev.h>
#include <asm/cacheflush.h>
+#include <mach/iovmm.h>
#include "isp.h"
-#include "ispmmu.h"
#include "ispreg.h"
#include "ispresizer.h"
#include <linux/omap_resizer.h>
@@ -41,13 +41,15 @@
/* Defines and Constants*/
#define MAX_CHANNELS 16
-#define MAX_IMAGE_WIDTH 2047
-#define MAX_IMAGE_WIDTH_HIGH 2047
#define ALIGNMENT 16
#define CHANNEL_BUSY 1
#define CHANNEL_FREE 0
#define PIXEL_EVEN 2
#define RATIO_MULTIPLIER 256
+#define MAX_4TAP_OUTWIDTH_3430 3300
+#define MAX_7TAP_OUTWIDTH_3430 1650
+#define MAX_4TAP_OUTWIDTH_3630 4096
+#define MAX_7TAP_OUTWIDTH_3630 2048
/* Bit position Macro */
/* macro for bit set and clear */
#define BITSET(variable, bit) ((variable) | (1 << bit))
@@ -77,16 +79,16 @@
#define COEFF_ADDRESS_OFFSET 0x04
static DECLARE_MUTEX(resz_wrapper_mutex);
+static int multipass_active;
-/* Global structure which contains information about number of channels
- and protection variables */
-struct device_params {
-
- unsigned char opened; /* state of the device */
- struct completion compl_isr; /* Completion for interrupt */
- struct mutex reszwrap_mutex; /* Semaphore for array */
-
- struct videobuf_queue_ops vbq_ops; /* videobuf queue operations */
+static struct isp_interface_config reszwrap_config = {
+ .ccdc_par_ser = ISP_NONE,
+ .dataline_shift = 0,
+ .hsvs_syncdetect = ISPCTRL_SYNC_DETECT_VSRISE,
+ .strobe = 0,
+ .prestrobe = 0,
+ .shutter = 0,
+ .wait_hs_vs = 0,
};
/* Register mapped structure which contains the every register
@@ -184,7 +186,31 @@
enum config_done config_state;
u8 input_buf_index;
u8 output_buf_index;
-
+};
+/* Global structure which contains information about number of channels
+ and protection variables */
+struct device_params {
+ struct rsz_params *params;
+ struct channel_config *config; /* Pointer to channel */
+ struct rsz_mult *multipass; /* Multipass to support */
+ unsigned char opened; /* state of the device */
+ struct completion compl_isr; /* Completion for interrupt */
+ struct mutex reszwrap_mutex; /* Semaphore for array */
+ struct videobuf_queue_ops vbq_ops; /* videobuf queue operations */
+ rsz_callback callback; /* callback function which gets
+ * called when Resizer
+ * finishes resizing
+ */
+ void *callback_arg;
+ u32 in_buf_virt_addr[32];
+ u32 *out_buf_phy_addr[32];
+ u32 out_buf_virt_addr[32];
+ u32 num_video_buffers;
+ dma_addr_t tmp_buf;
+ size_t tmp_buf_size;
+ struct rsz_mult original_multipass;
+ struct resizer_config original_rsz_conf_chan;
+ struct device *isp;
};
/* per-filehandle data structure */
@@ -201,7 +227,6 @@
enum v4l2_buf_type type;
struct videobuf_queue vbq;
struct device_params *device;
-
dma_addr_t isp_addr_read; /* Input/Output address */
dma_addr_t isp_addr_write; /* Input/Output address */
u32 rsz_bufsize; /* channel specific buffersize
@@ -211,8 +236,10 @@
static struct device_params *device_config;
static struct device *rsz_device;
static int rsz_major = -1;
+
/* functions declaration */
-static void rsz_hardware_setup(struct channel_config *rsz_conf_chan);
+static void rsz_hardware_setup(struct device_params *device,
+ struct channel_config *rsz_conf_chan);
static int rsz_set_params(struct rsz_mult *multipass, struct rsz_params *,
struct channel_config *);
static int rsz_get_params(struct rsz_params *, struct channel_config *);
@@ -222,54 +249,65 @@
void *arg2);
static void rsz_calculate_crop(struct channel_config *rsz_conf_chan,
struct rsz_cropsize *cropsize);
-static int rsz_set_multipass(struct rsz_mult *multipass,
- struct channel_config *rsz_conf_chan);
+static int rsz_set_multipass(struct device_params *device,
+ struct rsz_mult *multipass,
+ struct channel_config *rsz_conf_chan);
static int rsz_set_ratio(struct rsz_mult *multipass,
struct channel_config *rsz_conf_chan);
static void rsz_config_ratio(struct rsz_mult *multipass,
struct channel_config *rsz_conf_chan);
+static void rsz_tmp_buf_free(void);
+static u32 rsz_tmp_buf_alloc(size_t size);
+static void rsz_save_multipass_context(void);
+static void rsz_restore_multipass_context(void);
+
+static void isp_enable_interrupts(struct device *dev, int is_raw)
+{
+ isp_reg_writel(dev, IRQ0ENABLE_RSZ_DONE_IRQ,
+ OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
+}
+
/**
* rsz_hardware_setup - Sets hardware configuration registers
* @rsz_conf_chan: Structure containing channel configuration
*
* Set hardware configuration registers
**/
-static void rsz_hardware_setup(struct channel_config *rsz_conf_chan)
+static void rsz_hardware_setup(struct device_params *device,
+ struct channel_config *rsz_conf_chan)
{
int coeffcounter;
int coeffoffset = 0;
down(&resz_wrapper_mutex);
- isp_reg_writel(rsz_conf_chan->register_config.rsz_cnt,
+ isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_cnt,
OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
-
- isp_reg_writel(rsz_conf_chan->register_config.rsz_in_start,
+ isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_in_start,
OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
- isp_reg_writel(rsz_conf_chan->register_config.rsz_in_size,
+ isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_in_size,
OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE);
-
- isp_reg_writel(rsz_conf_chan->register_config.rsz_out_size,
+ isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_out_size,
OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE);
- isp_reg_writel(rsz_conf_chan->register_config.rsz_sdr_inadd,
+ isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_sdr_inadd,
OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
- isp_reg_writel(rsz_conf_chan->register_config.rsz_sdr_inoff,
+ isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_sdr_inoff,
OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
- isp_reg_writel(rsz_conf_chan->register_config.rsz_sdr_outadd,
+ isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_sdr_outadd,
OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
- isp_reg_writel(rsz_conf_chan->register_config.rsz_sdr_outoff,
+ isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_sdr_outoff,
OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
- isp_reg_writel(rsz_conf_chan->register_config.rsz_yehn,
+ isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_yehn,
OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH);
for (coeffcounter = 0; coeffcounter < MAX_COEF_COUNTER;
coeffcounter++) {
- isp_reg_writel(rsz_conf_chan->register_config.
+ isp_reg_writel(device->isp, rsz_conf_chan->register_config.
rsz_coeff_horz[coeffcounter],
OMAP3_ISP_IOMEM_RESZ,
ISPRSZ_HFILT10 + coeffoffset);
- isp_reg_writel(rsz_conf_chan->register_config.
+ isp_reg_writel(device->isp, rsz_conf_chan->register_config.
rsz_coeff_vert[coeffcounter],
OMAP3_ISP_IOMEM_RESZ,
ISPRSZ_VFILT10 + coeffoffset);
@@ -278,6 +316,47 @@
up(&resz_wrapper_mutex);
}
+static void rsz_save_multipass_context()
+{
+ struct channel_config *rsz_conf_chan = device_config->config;
+ struct rsz_mult *multipass = device_config->multipass;
+
+ struct resizer_config *original_rsz_conf_chan
+ = &device_config->original_rsz_conf_chan;
+ struct rsz_mult *original_multipass
+ = &device_config->original_multipass;
+
+ memset(original_rsz_conf_chan,
+ 0, sizeof(struct resizer_config));
+ memcpy(original_rsz_conf_chan,
+ (struct resizer_config *) &rsz_conf_chan->register_config,
+ sizeof(struct resizer_config));
+ memset(original_multipass,
+ 0, sizeof(struct rsz_mult));
+ memcpy(original_multipass,
+ multipass, sizeof(struct rsz_mult));
+
+ return;
+}
+
+static void rsz_restore_multipass_context()
+{
+ struct channel_config *rsz_conf_chan = device_config->config;
+ struct rsz_mult *multipass = device_config->multipass;
+
+ struct resizer_config *original_rsz_conf_chan
+ = &device_config->original_rsz_conf_chan;
+ struct rsz_mult *original_multipass
+ = &device_config->original_multipass;
+
+ memcpy((struct resizer_config *) &rsz_conf_chan->register_config,
+ original_rsz_conf_chan, sizeof(struct resizer_config));
+
+ memcpy(multipass, original_multipass, sizeof(struct rsz_mult));
+
+ return;
+}
+
/**
* rsz_start - Enables Resizer Wrapper
* @device: Structure containing ISP resizer wrapper global information
@@ -294,6 +373,8 @@
int rsz_start(struct rsz_fh *fh)
{
struct channel_config *rsz_conf_chan = fh->config;
+ struct device_params *device = fh->device;
+ struct isp_device *isp = dev_get_drvdata(device->isp);
struct rsz_mult *multipass = fh->multipass;
struct videobuf_queue *q = &fh->vbq;
int ret;
@@ -305,20 +386,24 @@
rsz_conf_chan->status = CHANNEL_BUSY;
- rsz_hardware_setup(rsz_conf_chan);
+ rsz_hardware_setup(device, rsz_conf_chan);
- if (isp_set_callback(CBK_RESZ_DONE, rsz_isr, (void *) NULL,
- (void *)NULL)) {
+ if (isp_set_callback(device->isp, CBK_RESZ_DONE, rsz_isr,
+ (void *)NULL, (void *)NULL)) {
dev_err(rsz_device, "No callback for RSZR\n");
goto err_einval;
}
- /* Make sure we don't wait for any HS_VS interrupts */
- isp_set_hs_vs(0);
+ isp_configure_interface(device->isp, &reszwrap_config);
+
+ isp_start(device->isp);
+
+ isp_enable_interrupts(device->isp, 0);
+
mult:
device_config->compl_isr.done = 0;
- ispresizer_enable(1);
+ ispresizer_enable(&isp->isp_res, 1);
ret = wait_for_completion_interruptible(&device_config->compl_isr);
if (ret != 0) {
@@ -328,16 +413,16 @@
}
if (multipass->active) {
- rsz_set_multipass(multipass, rsz_conf_chan);
+ rsz_set_multipass(device, multipass, rsz_conf_chan);
goto mult;
}
if (fh->isp_addr_read) {
- ispmmu_vunmap(fh->isp_addr_read);
+ ispmmu_vunmap(device->isp, fh->isp_addr_read);
fh->isp_addr_read = 0;
}
if (fh->isp_addr_write) {
- ispmmu_vunmap(fh->isp_addr_write);
+ ispmmu_vunmap(device->isp, fh->isp_addr_write);
fh->isp_addr_write = 0;
}
@@ -357,7 +442,7 @@
videobuf_dma_free(videobuf_to_dma(
q->bufs[rsz_conf_chan->output_buf_index]));
- isp_unset_callback(CBK_RESZ_DONE);
+ isp_unset_callback(device->isp, CBK_RESZ_DONE);
return 0;
err_einval:
@@ -370,8 +455,9 @@
*
* Returns always 0
**/
-static int rsz_set_multipass(struct rsz_mult *multipass,
- struct channel_config *rsz_conf_chan)
+static int rsz_set_multipass(struct device_params *device,
+ struct rsz_mult *multipass,
+ struct channel_config *rsz_conf_chan)
{
multipass->in_hsize = multipass->out_hsize;
multipass->in_vsize = multipass->out_vsize;
@@ -383,9 +469,11 @@
multipass->in_pitch = (multipass->inptyp ? multipass->in_hsize
: (multipass->in_hsize * 2));
+ rsz_conf_chan->register_config.rsz_sdr_inadd =
+ rsz_conf_chan->register_config.rsz_sdr_outadd;
rsz_set_ratio(multipass, rsz_conf_chan);
rsz_config_ratio(multipass, rsz_conf_chan);
- rsz_hardware_setup(rsz_conf_chan);
+ rsz_hardware_setup(device, rsz_conf_chan);
return 0;
}
@@ -549,15 +637,11 @@
static int rsz_set_ratio(struct rsz_mult *multipass,
struct channel_config *rsz_conf_chan)
{
+ struct isp_device *isp = dev_get_drvdata(device_config->isp);
int alignment = 0;
rsz_conf_chan->register_config.rsz_cnt = 0;
- if ((multipass->out_hsize > MAX_IMAGE_WIDTH) ||
- (multipass->out_vsize > MAX_IMAGE_WIDTH)) {
- dev_err(rsz_device, "Invalid output size!");
- goto err_einval;
- }
if (multipass->cbilin) {
rsz_conf_chan->register_config.rsz_cnt =
BITSET(rsz_conf_chan->register_config.rsz_cnt,
@@ -588,20 +672,18 @@
}
}
- multipass->vrsz =
- (multipass->in_vsize * RATIO_MULTIPLIER) / multipass->out_vsize;
- multipass->hrsz =
- (multipass->in_hsize * RATIO_MULTIPLIER) / multipass->out_hsize;
- if (UP_RSZ_RATIO > multipass->vrsz || UP_RSZ_RATIO > multipass->hrsz) {
- dev_err(rsz_device, "Upscaling ratio not supported!");
- goto err_einval;
- }
+
multipass->vrsz = (multipass->in_vsize - NUM_D2TAPS) * RATIO_MULTIPLIER
/ (multipass->out_vsize - 1);
multipass->hrsz = ((multipass->in_hsize - NUM_D2TAPS)
* RATIO_MULTIPLIER) /
(multipass->out_hsize - 1);
+ if (UP_RSZ_RATIO > multipass->vrsz || UP_RSZ_RATIO > multipass->hrsz) {
+ dev_err(rsz_device, "Upscaling ratio not supported!");
+ goto err_einval;
+ }
+
if (multipass->hrsz <= 512) {
multipass->hrsz = (multipass->in_hsize - NUM_TAPS)
* RATIO_MULTIPLIER
@@ -663,17 +745,9 @@
}
}
if (multipass->hrsz >= 64 && multipass->hrsz <= 1024) {
- if (multipass->out_hsize > MAX_IMAGE_WIDTH) {
- dev_err(rsz_device, "wrong width\n");
- goto err_einval;
- }
multipass->active = 0;
} else if (multipass->hrsz > 1024) {
- if (multipass->out_hsize > MAX_IMAGE_WIDTH) {
- dev_err(rsz_device, "wrong width\n");
- goto err_einval;
- }
if (multipass->hstph > NUM_D2PH)
goto err_einval;
multipass->num_htap = 0;
@@ -692,12 +766,37 @@
}
- if (multipass->vrsz > 1024) {
- if (multipass->out_vsize > MAX_IMAGE_WIDTH_HIGH) {
+ /* 4Tap: Check max Output width */
+ if (multipass->vrsz <= 512) {
+ if (isp->revision <= ISP_REVISION_2_0 &&
+ multipass->out_vsize > MAX_4TAP_OUTWIDTH_3430) {
dev_err(rsz_device, "wrong width\n");
goto err_einval;
}
+ if (isp->revision > ISP_REVISION_2_0 &&
+ multipass->out_vsize > MAX_4TAP_OUTWIDTH_3630) {
+ dev_err(rsz_device, "wrong width\n");
+ goto err_einval;
+ }
+ }
+
+ /* 7Tap: Check max Output width */
+ if (multipass->vrsz > 512) {
+ if (isp->revision <= ISP_REVISION_2_0 &&
+ multipass->out_vsize > MAX_7TAP_OUTWIDTH_3430) {
+ dev_err(rsz_device, "wrong width\n");
+ goto err_einval;
+ }
+
+ if (isp->revision > ISP_REVISION_2_0 &&
+ multipass->out_vsize > MAX_7TAP_OUTWIDTH_3630) {
+ dev_err(rsz_device, "wrong width\n");
+ goto err_einval;
+ }
+ }
+
+ if (multipass->vrsz > 1024) {
multipass->out_vsize = multipass->in_vsize * 256 / 1024;
multipass->vrsz = ((multipass->in_vsize - NUM_D2TAPS)
* RATIO_MULTIPLIER)
@@ -999,6 +1098,7 @@
{
int i;
struct rsz_fh *fh = q->priv_data;
+ struct device_params *device = fh->device;
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
struct videobuf_dmabuf *dma = NULL;
@@ -1011,8 +1111,8 @@
videobuf_dma_free(dma);
}
- ispmmu_vunmap(fh->isp_addr_read);
- ispmmu_vunmap(fh->isp_addr_write);
+ ispmmu_vunmap(device->isp, fh->isp_addr_read);
+ ispmmu_vunmap(device->isp, fh->isp_addr_write);
fh->isp_addr_read = 0;
fh->isp_addr_write = 0;
spin_lock(&fh->vbq_lock);
@@ -1085,6 +1185,7 @@
enum v4l2_field field)
{
struct rsz_fh *fh = q->priv_data;
+ struct device_params *device = fh->device;
struct channel_config *rsz_conf_chan = fh->config;
struct rsz_mult *multipass = fh->multipass;
int err = 0;
@@ -1114,7 +1215,8 @@
if (vb->state == VIDEOBUF_NEEDS_INIT) {
err = videobuf_iolock(q, vb, NULL);
if (!err) {
- isp_addr = ispmmu_vmap(dma->sglist, dma->sglen);
+ isp_addr = ispmmu_vmap(device->isp, dma->sglist,
+ dma->sglen);
if (!isp_addr)
err = -EIO;
else {
@@ -1184,6 +1286,7 @@
struct device_params *device = device_config;
struct rsz_params *params;
struct rsz_mult *multipass;
+ struct device *isp;
if ((filp->f_flags & O_NONBLOCK) == O_NONBLOCK) {
printk(KERN_DEBUG "omap-resizer: Device is opened in "
@@ -1192,11 +1295,18 @@
printk(KERN_DEBUG "omap-resizer: Device is opened in blocking "
"mode\n");
}
+
fh = kzalloc(sizeof(struct rsz_fh), GFP_KERNEL);
if (NULL == fh)
return -ENOMEM;
- isp_get();
+ isp = isp_get();
+ if (!isp) {
+ printk(KERN_ERR "Can't enable ISP clocks (ret %d)\n", ret);
+ ret = -EACCES;
+ goto err_resz;
+ }
+ device->isp = isp;
rsz_conf_chan = kzalloc(sizeof(struct channel_config), GFP_KERNEL);
if (rsz_conf_chan == NULL) {
@@ -1249,6 +1359,8 @@
err_enomem1:
kfree(rsz_conf_chan);
err_enomem0:
+ isp_put();
+err_resz:
kfree(fh);
return ret;
}
@@ -1330,6 +1442,7 @@
int ret = 0;
struct rsz_fh *fh = file->private_data;
struct device_params *device = fh->device;
+ struct isp_device *isp = dev_get_drvdata(device->isp);
struct channel_config *rsz_conf_chan = fh->config;
if ((_IOC_TYPE(cmd) != RSZ_IOC_BASE)
@@ -1426,7 +1539,7 @@
struct rsz_status status;
status.chan_busy = rsz_conf_chan->status;
- status.hw_busy = ispresizer_busy();
+ status.hw_busy = ispresizer_busy(&isp->isp_res);
status.src = INPUT_RAM;
if (copy_to_user((struct rsz_status *)arg, &status,
@@ -1437,7 +1550,7 @@
case RSZ_RESIZE:
if (file->f_flags & O_NONBLOCK) {
- if (ispresizer_busy())
+ if (ispresizer_busy(&isp->isp_res))
return -EBUSY;
else {
if (!mutex_trylock(&device->reszwrap_mutex))
@@ -1490,7 +1603,347 @@
};
/**
- * rsz_isr - Interrupt Service Routine for Resizer wrapper
+ * rsz_get_resource - get the Resizer module from the kernel space.
+ * This function will make sure that Resizer module is not used by any other
+ * application. It is equivalent of open() call from user space.
+ * It returns busy if the device is already opened by other application
+ * or ENOMEM if it fails to allocate memory for structures
+ * or 0 if the call is successful.
+ **/
+
+int rsz_get_resource(void)
+{
+ int ret = 0;
+ struct channel_config *rsz_conf_chan;
+ struct device_params *device = device_config;
+ struct rsz_params *params;
+ struct rsz_mult *multipass;
+ struct device *isp;
+
+ if (device->opened) {
+ dev_err(rsz_device, "rsz_get_resource: device is "
+ "already opened\n");
+ return -EBUSY;
+ }
+
+ isp = isp_get();
+ if (!isp) {
+ printk(KERN_ERR "Can't enable ISP clocks (ret %d)\n", ret);
+ return -EACCES;
+ }
+ device->isp = isp;
+
+ rsz_conf_chan = kzalloc(sizeof(struct channel_config), GFP_KERNEL);
+ if (rsz_conf_chan == NULL) {
+ dev_err(rsz_device, "\n Can not allocate memory to config");
+ ret = -ENOMEM;
+ goto err_enomem0;
+ }
+ params = kzalloc(sizeof(struct rsz_params), GFP_KERNEL);
+ if (params == NULL) {
+ dev_warn(rsz_device, "\n Can not allocate memory to params");
+ ret = -ENOMEM;
+ goto err_enomem1;
+ }
+ multipass = kzalloc(sizeof(struct rsz_mult), GFP_KERNEL);
+ if (multipass == NULL) {
+ dev_err(rsz_device, "\n cannot allocate memory to multipass");
+ ret = -ENOMEM;
+ goto err_enomem2;
+ }
+
+ device->params = params;
+ device->config = rsz_conf_chan;
+ device->multipass = multipass;
+ device->opened = 1;
+
+ rsz_conf_chan->config_state = STATE_NOT_CONFIGURED;
+
+ init_completion(&device->compl_isr);
+ mutex_init(&device->reszwrap_mutex);
+
+ return 0;
+err_enomem2:
+ kfree(params);
+err_enomem1:
+ kfree(rsz_conf_chan);
+err_enomem0:
+ isp_put();
+
+ return ret;
+}
+EXPORT_SYMBOL(rsz_get_resource);
+
+/**
+ * rsz_put_resource - release all the resource which were acquired during
+ * rsz_get_resource() call.
+ **/
+void rsz_put_resource(void)
+{
+ struct device_params *device = device_config;
+ struct channel_config *rsz_conf_chan = device->config;
+ struct rsz_params *params = device->params;
+ struct rsz_mult *multipass = device->multipass;
+ struct isp_device *isp = dev_get_drvdata(device->isp);
+ int i = 0;
+
+ if (device->opened != 1)
+ return;
+
+ /* unmap output buffers if allocated */
+ for (i = 0; i < device->num_video_buffers; ++i) {
+ if (device->out_buf_virt_addr[i]) {
+ iommu_kunmap(isp->iommu, device->out_buf_virt_addr[i]);
+ device_config->out_buf_virt_addr[i] = 0;
+ }
+ if (device->in_buf_virt_addr[i]) {
+ iommu_kunmap(isp->iommu, device->in_buf_virt_addr[i]);
+ device_config->in_buf_virt_addr[i] = 0;
+ }
+ }
+
+ if (multipass_active) {
+ rsz_tmp_buf_free();
+ multipass_active = 0;
+ }
+ /* free all memory which was allocate during get() */
+ kfree(rsz_conf_chan);
+ kfree(params);
+ kfree(multipass);
+
+ /* make device available */
+ device->opened = 0;
+ device->params = NULL;
+ device->config = NULL;
+ device->multipass = NULL;
+
+ /* release isp resource*/
+ isp_put();
+
+ return ;
+}
+EXPORT_SYMBOL(rsz_put_resource);
+
+/**
+ * rsz_configure - configure the Resizer parameters
+ * @params: Structure containing the Resizer Wrapper parameters
+ * @callback: callback function to call after resizing is over
+ * @arg1: argument to callback function
+ *
+ * This function can be called from DSS to set the parameter of resizer
+ * in case there is need to downsize the input image through resizer
+ * before calling this function calling driver must already have called
+ * rsz_get_resource() function so that necessory initialization is over.
+ * Returns 0 if successful,
+ **/
+int rsz_configure(struct rsz_params *params, rsz_callback callback,
+ u32 num_video_buffers, void *arg1)
+{
+ int retval;
+ struct channel_config *rsz_conf_chan = device_config->config;
+ struct rsz_mult *multipass = device_config->multipass;
+ size_t tmp_size;
+
+ multipass_active = 0;
+ retval = rsz_set_params(multipass, params, rsz_conf_chan);
+ if (retval != 0)
+ return retval;
+
+ if (device_config->multipass->active) {
+ multipass_active = 1;
+ tmp_size = PAGE_ALIGN(multipass->out_hsize
+ * multipass->out_vsize
+ * (multipass->inptyp ? 1 : 2));
+ rsz_tmp_buf_alloc(tmp_size);
+ rsz_conf_chan->register_config.rsz_sdr_outadd =
+ (u32)device_config->tmp_buf;
+ rsz_save_multipass_context();
+ }
+
+ rsz_hardware_setup(device_config, rsz_conf_chan);
+ device_config->callback = callback;
+ device_config->callback_arg = arg1;
+ device_config->num_video_buffers = num_video_buffers;
+
+ return 0;
+}
+EXPORT_SYMBOL(rsz_configure);
+
+static void rsz_tmp_buf_free(void)
+{
+ struct isp_device *isp = dev_get_drvdata(device_config->isp);
+
+ if (device_config->tmp_buf) {
+ iommu_vfree(isp->iommu, device_config->tmp_buf);
+ device_config->tmp_buf = 0;
+ device_config->tmp_buf_size = 0;
+ }
+}
+static u32 rsz_tmp_buf_alloc(size_t size)
+{
+ struct isp_device *isp = dev_get_drvdata(device_config->isp);
+
+ rsz_tmp_buf_free();
+ printk(KERN_INFO "%s: allocating %d bytes\n", __func__, size);
+
+ device_config->tmp_buf =
+ iommu_vmalloc(isp->iommu, 0, size, IOMMU_FLAG);
+ if (IS_ERR((void *)device_config->tmp_buf)) {
+ printk(KERN_ERR "ispmmu_vmap mapping failed ");
+ return -ENOMEM;
+ }
+ device_config->tmp_buf_size = size;
+
+ return 0;
+}
+
+/** rsz_begin - Function to be called by DSS when resizing of the input image/
+ * buffer is needed
+ * @slot: buffer index where the input image is stored
+ * @output_buffer_index: output buffer index where output of resizer will
+ * be stored
+ * @out_off: The line size in bytes for output buffer. as most probably
+ * this will be VRFB with YUV422 data, it should come 0x2000 as input
+ * @out_phy_add: physical address of the start of output memory area for this
+ * @in_phy_add: physical address of the start of input memory area for this
+ * @in_off:: The line size in bytes for output buffer.
+ * rsz_begin() takes the input buffer index and output buffer index
+ * to start the process of resizing. after resizing is complete,
+ * the callback function will be called with the argument.
+ * Indexes of the input and output buffers are used so that it is faster
+ * and easier to configure the input and output address for the ISP resizer.
+ * As per the current implementation, DSS uses six VRFB contexts for rotation.
+ * for both input and output buffers index and physical address has been taken
+ * as argument. if this buffer is not already mapped to ISP address space we
+ * use physical address to map it, otherwise only the index is used.
+ **/
+int rsz_begin(u32 input_buffer_index, int output_buffer_index,
+ u32 out_off, u32 out_phy_add, u32 in_phy_add, u32 in_off)
+{
+ unsigned int output_size;
+ struct channel_config *rsz_conf_chan = device_config->config;
+ struct isp_device *isp = dev_get_drvdata(device_config->isp);
+
+ if (output_buffer_index >= device_config->num_video_buffers) {
+ dev_err(rsz_device,
+ "ouput buffer index is out of range %d", output_buffer_index);
+ return -EINVAL;
+ }
+
+ if (multipass_active) {
+ rsz_restore_multipass_context();
+ rsz_hardware_setup(device_config, rsz_conf_chan);
+ }
+
+ /* If this output buffer has not been mapped till now then map it */
+ if (!device_config->out_buf_virt_addr[output_buffer_index]) {
+ output_size =
+ (rsz_conf_chan->register_config.rsz_out_size >>
+ ISPRSZ_OUT_SIZE_VERT_SHIFT) * out_off;
+ device_config->out_buf_virt_addr[output_buffer_index] = iommu_kmap(
+ isp->iommu,
+ 0,
+ out_phy_add,
+ output_size,
+ IOMMU_FLAG);
+ if (IS_ERR_VALUE(
+ device_config->out_buf_virt_addr[output_buffer_index])) {
+ dev_err(rsz_device, "Mapping of output buffer failed"
+ "for index \n");
+ return -ENOMEM;
+ }
+ }
+
+ if (!device_config->in_buf_virt_addr[input_buffer_index]) {
+ device_config->in_buf_virt_addr[input_buffer_index] =
+ iommu_kmap(isp->iommu,
+ 0,
+ in_phy_add,
+ in_off,
+ IOMMU_FLAG);
+ if (IS_ERR_VALUE(
+ device_config->in_buf_virt_addr[input_buffer_index])) {
+ dev_err(rsz_device, "Mapping of output buffer failed"
+ "for index \n");
+ return -ENOMEM;
+ }
+ }
+ down(&resz_wrapper_mutex);
+ rsz_conf_chan->register_config.rsz_sdr_inadd =
+ device_config->in_buf_virt_addr[input_buffer_index];
+
+ /* Configure the input and output address with output line size
+ in resizer hardware */
+ isp_reg_writel(device_config->isp,
+ rsz_conf_chan->register_config.rsz_sdr_inadd,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
+
+ if (!multipass_active) {
+ rsz_conf_chan->register_config.rsz_sdr_outoff = out_off;
+ isp_reg_writel(device_config->isp,
+ rsz_conf_chan->register_config.rsz_sdr_outoff,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
+ rsz_conf_chan->register_config.rsz_sdr_outadd =
+ (u32)device_config->\
+ out_buf_virt_addr[output_buffer_index];
+ isp_reg_writel(device_config->isp,
+ rsz_conf_chan->register_config.rsz_sdr_outadd,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
+ }
+
+ up(&resz_wrapper_mutex);
+
+ /* Set ISP callback for the resizing complete even */
+ if (isp_set_callback(device_config->isp,
+ CBK_RESZ_DONE, rsz_isr,
+ (void *) NULL, (void *)NULL)) {
+ dev_err(rsz_device, "No callback for RSZR\n");
+ return -1;
+ }
+
+ /* All settings are done.Enable the resizer */
+
+mult:
+ device_config->compl_isr.done = 0;
+
+ ispresizer_enable(&isp->isp_res, 1);
+ /* Wait for resizing complete event */
+ wait_for_completion_interruptible(&device_config->compl_isr);
+
+ if (device_config->multipass->active) {
+ multipass_active = 1;
+ rsz_set_multipass(device_config,
+ device_config->multipass, rsz_conf_chan);
+ down(&resz_wrapper_mutex);
+ if (!device_config->multipass->active) {
+ rsz_conf_chan->register_config.rsz_sdr_outoff = out_off;
+ isp_reg_writel(device_config->isp,
+ rsz_conf_chan->register_config.rsz_sdr_outoff,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
+
+ rsz_conf_chan->register_config.rsz_sdr_outadd =
+ (u32)device_config->\
+ out_buf_virt_addr[output_buffer_index];
+
+ isp_reg_writel(device_config->isp,
+ rsz_conf_chan->register_config.rsz_sdr_outadd,
+ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
+ }
+ up(&resz_wrapper_mutex);
+ goto mult;
+ }
+ /* Unset the ISP callback function */
+ isp_unset_callback(device_config->isp, CBK_RESZ_DONE);
+
+ /* Callback function for DSS driver */
+ if (device_config->callback)
+ device_config->callback(device_config->callback_arg);
+
+ return 0;
+}
+EXPORT_SYMBOL(rsz_begin);
+
+ /* rsz_isr - Interrupt Service Routine for Resizer wrapper
* @status: ISP IRQ0STATUS register value
* @arg1: Currently not used
* @arg2: Currently not used
@@ -1569,18 +2022,19 @@
{
int ret = 0;
struct device_params *device;
+
device = kzalloc(sizeof(struct device_params), GFP_KERNEL);
if (!device) {
- dev_err(rsz_device, OMAP_REZR_NAME ": could not allocate "
- "memory\n");
+ printk(KERN_ERR "%s : could not allocate "
+ "memory\n", OMAP_REZR_NAME);
return -ENOMEM;
}
ret = alloc_chrdev_region(&dev, 0, 1, OMAP_REZR_NAME);
if (ret < 0) {
- dev_err(rsz_device, OMAP_REZR_NAME ": intialization failed. "
+ printk(KERN_ERR "%s : intialization failed. "
"Could not allocate region "
- "for character device\n");
+ "for character device\n" , OMAP_REZR_NAME);
kfree(device);
return -ENODEV;
}
@@ -1594,8 +2048,8 @@
/* Addding character device */
ret = cdev_add(&c_dev, dev, 1);
if (ret) {
- dev_err(rsz_device, OMAP_REZR_NAME ": Error adding "
- "device - %d\n", ret);
+ printk(KERN_ERR "%s : Error adding "
+ "device - %d\n", OMAP_REZR_NAME, ret);
goto fail2;
}
rsz_major = MAJOR(dev);
@@ -1603,23 +2057,23 @@
/* register driver as a platform driver */
ret = platform_driver_register(&omap_resizer_driver);
if (ret) {
- dev_err(rsz_device, OMAP_REZR_NAME
- ": Failed to register platform driver!\n");
+ printk(KERN_ERR "%s : Failed to "
+ "register platform driver!\n", OMAP_REZR_NAME);
goto fail3;
}
/* Register the drive as a platform device */
ret = platform_device_register(&omap_resizer_device);
if (ret) {
- dev_err(rsz_device, OMAP_REZR_NAME
- ": Failed to register platform device!\n");
+ printk(KERN_ERR "%s : Failed to register "
+ "platform device!\n", OMAP_REZR_NAME);
goto fail4;
}
rsz_class = class_create(THIS_MODULE, OMAP_REZR_NAME);
if (!rsz_class) {
- dev_err(rsz_device, OMAP_REZR_NAME
- ": Failed to create class!\n");
+ printk(KERN_ERR "%s : Failed to "
+ "create class!\n", OMAP_REZR_NAME);
goto fail5;
}
@@ -1627,7 +2081,16 @@
rsz_device = device_create(rsz_class, rsz_device,
MKDEV(rsz_major, 0), NULL,
OMAP_REZR_NAME);
- dev_dbg(rsz_device, OMAP_REZR_NAME ": Registered Resizer Wrapper\n");
+ if (rsz_device)
+ dev_dbg(rsz_device, OMAP_REZR_NAME ":"
+ "Registered Resizer Wrapper\n");
+ else {
+ printk(KERN_ERR "%s : Registered Resizer Wrapper",
+ OMAP_REZR_NAME);
+ ret = -ENODEV;
+ goto fail6;
+ }
+
device->opened = 0;
device->vbq_ops.buf_setup = rsz_vbq_setup;
@@ -1640,6 +2103,8 @@
device_config = device;
return 0;
+fail6:
+ class_destroy(rsz_class);
fail5:
platform_device_unregister(&omap_resizer_device);
fail4:
diff --git a/drivers/media/video/lv8093.c b/drivers/media/video/lv8093.c
index ea3320d..dcd179a 100644
--- a/drivers/media/video/lv8093.c
+++ b/drivers/media/video/lv8093.c
@@ -427,6 +427,54 @@
return lens->pdata->priv_data_set(p);
}
+static int lv8093_power_on(struct lv8093_device *lens)
+{
+ struct i2c_client *c = lens->i2c_client;
+ int rval = -EINVAL;
+
+ if (lens->pdata->power_set)
+ rval = lens->pdata->power_set(V4L2_POWER_ON);
+
+ if (rval < 0) {
+ v4l_err(c, "Unable to set the power state ON\n");
+ return rval;
+ }
+
+ return 0;
+}
+
+static int lv8093_power_off(struct lv8093_device *lens)
+{
+ struct i2c_client *c = lens->i2c_client;
+ int rval = -EINVAL;
+
+ if (lens->pdata->power_set)
+ rval = lens->pdata->power_set(V4L2_POWER_OFF);
+
+ if (rval < 0) {
+ v4l_err(c, "Unable to set the power state OFF\n");
+ return rval;
+ }
+
+ return 0;
+}
+
+static int lv8093_power_standby(struct lv8093_device *lens)
+{
+ struct i2c_client *c = lens->i2c_client;
+ int rval = -EINVAL;
+
+ if (lens->pdata->power_set)
+ rval = lens->pdata->power_set(V4L2_POWER_STANDBY);
+
+ if (rval < 0) {
+ v4l_err(c, "Unable to set the power state STANDBY\n");
+ return rval;
+ }
+
+ return 0;
+}
+
/**
* ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num
* @s: pointer to standard V4L2 device structure
@@ -438,49 +486,84 @@
{
struct lv8093_device *lens = s->priv;
struct i2c_client *c = lens->i2c_client;
- int rval;
+ int rval = 0;
- if (lens->pdata->power_set)
- rval = lens->pdata->power_set(on);
+ switch (on) {
+ case V4L2_POWER_ON:
+ rval = lv8093_power_on(lens);
+ if (rval)
+ goto error;
+
+ if (lens->power_state == V4L2_POWER_STANDBY) {
+ rval = lv8093_reginit(c);
+ if (rval < 0) {
+ v4l_err(c, "Unable to initialize " LV8093_NAME
+ " lens HW\n");
+ lens->state = LENS_NOT_DETECTED;
+ return rval;
+ }
+ }
+ break;
+ case V4L2_POWER_OFF:
+ rval = lv8093_power_off(lens);
+ break;
+ case V4L2_POWER_STANDBY:
+ rval = lv8093_power_standby(lens);
+ break;
+ }
lens->power_state = on;
+error:
+ return rval;
+}
- if ((on == V4L2_POWER_ON) && (lens->state == LENS_NOT_DETECTED)) {
- rval = lv8093_detect(c);
- if (rval < 0) {
- v4l_err(c, "Unable to detect " LV8093_NAME
- " lens HW\n");
- lens->state = LENS_NOT_DETECTED;
- return rval;
- }
- lens->state = LENS_DETECTED;
- pr_info(LV8093_NAME " Lens HW detected\n");
+/**
+ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master. Returns 0 if
+ * lv8093 device could be found, otherwise returns appropriate error.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+ struct lv8093_device *lens = s->priv;
+ struct i2c_client *c = lens->i2c_client;
+ int err;
- rval = lv8093_reginit(c);
- if (rval < 0) {
- v4l_err(c, "Unable to initialize " LV8093_NAME
- " lens HW\n");
- lens->state = LENS_NOT_DETECTED;
- return rval;
- }
+ err = lv8093_power_on(lens);
+ if (err)
+ return -ENODEV;
+
+ err = lv8093_detect(c);
+ if (err < 0) {
+ v4l_err(c, "Unable to detect " LV8093_NAME
+ " lens HW\n");
+ lens->state = LENS_NOT_DETECTED;
+ return err;
+ }
+ lens->state = LENS_DETECTED;
+ pr_info(LV8093_NAME " Lens HW detected\n");
+
+ err = lv8093_reginit(c);
+ if (err < 0) {
+ v4l_err(c, "Unable to initialize " LV8093_NAME
+ " lens HW\n");
+ lens->state = LENS_NOT_DETECTED;
+ return err;
}
- if ((lens->power_state == V4L2_POWER_STANDBY) && (on == V4L2_POWER_ON)
- && (lens->state == LENS_DETECTED)) {
- rval = lv8093_reginit(c);
- if (rval < 0) {
- v4l_err(c, "Unable to initialize " LV8093_NAME
- " lens HW\n");
- lens->state = LENS_NOT_DETECTED;
- return rval;
- }
- }
+ err = lv8093_power_off(lens);
+ if (err)
+ return -ENODEV;
+
return 0;
}
static struct v4l2_int_ioctl_desc lv8093_ioctl_desc[] = {
{.num = vidioc_int_s_power_num,
.func = (v4l2_int_ioctl_func *) ioctl_s_power},
+ { .num = vidioc_int_dev_init_num,
+ .func = (v4l2_int_ioctl_func *)ioctl_dev_init},
{.num = vidioc_int_g_priv_num,
.func = (v4l2_int_ioctl_func *) ioctl_g_priv},
{.num = vidioc_int_queryctrl_num,
diff --git a/drivers/media/video/omap-vout/Kconfig b/drivers/media/video/omap-vout/Kconfig
deleted file mode 100644
index 6a8334e..0000000
--- a/drivers/media/video/omap-vout/Kconfig
+++ /dev/null
@@ -1,8 +0,0 @@
-config VIDEO_OMAP_VIDEOOUT
- tristate "Video out driver"
- depends on VIDEO_DEV && VIDEO_V4L2 && OMAP2_DSS
-
-config VIDEO_OMAP_VIDEOOUT_BUFPOOL
- tristate "Video out driver buffer pool"
- depends on VIDEO_OMAP_VIDEOOUT
-
diff --git a/drivers/media/video/omap-vout/Makefile b/drivers/media/video/omap-vout/Makefile
deleted file mode 100644
index a8e420e..0000000
--- a/drivers/media/video/omap-vout/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-
-vout-objs := omapvout.o omapvout-dss.o omapvout-mem.o omapvout-vbq.o
-
-obj-$(CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL) += omapvout-bp.o
-
-obj-$(CONFIG_VIDEO_OMAP_VIDEOOUT) += vout.o
-
diff --git a/drivers/media/video/omap-vout/omapvout-bp.c b/drivers/media/video/omap-vout/omapvout-bp.c
deleted file mode 100644
index c56f9ed..0000000
--- a/drivers/media/video/omap-vout/omapvout-bp.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-bp.c
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/mm.h>
-
-#include "omapvout.h"
-#include "omapvout-mem.h"
-#include "omapvout-bp.h"
-
-#define OMAPVOUT_BP_MAX_BUFFERS (20)
-
-struct omapvout_bp *omapvout_bp_create(u8 num_bufs, u32 buf_size)
-{
- struct omapvout_bp *bp;
- int num = num_bufs;
- int size;
- int i;
- unsigned long paddr;
- void *vaddr;
- u32 bsize;
-
- if (num > OMAPVOUT_BP_MAX_BUFFERS)
- num = OMAPVOUT_BP_MAX_BUFFERS;
-
- size = sizeof(struct omapvout_bp) +
- (num * sizeof(struct omapvout_bp_entry));
- bp = kzalloc(size, GFP_KERNEL);
- if (!bp)
- return NULL;
-
- mutex_init(&bp->lock);
- mutex_lock(&bp->lock);
-
- bsize = PAGE_ALIGN(buf_size);
- bp->num_entries = num;
- for (i = 0; i < num; i++) {
- if (omapvout_mem_alloc(bsize, &paddr, &vaddr) == 0) {
- bp->buf[i].size = bsize;
- bp->buf[i].phy_addr = paddr;
- bp->buf[i].virt_addr = vaddr;
- }
- }
-
- mutex_unlock(&bp->lock);
-
- return bp;
-}
-
-void omapvout_bp_init(struct omapvout_device *vout)
-{
- struct omapvout_bp *bp = vout->bp;
-
- mutex_lock(&bp->lock);
-
- bp->ref_cnt++;
-
- mutex_unlock(&bp->lock);
-}
-
-void omapvout_bp_destroy(struct omapvout_device *vout)
-{
- struct omapvout_bp *bp = vout->bp;
- int i;
-
- if (bp == NULL)
- return;
-
- vout->bp = NULL;
-
- mutex_lock(&bp->lock);
-
- if (bp->ref_cnt > 0)
- bp->ref_cnt--;
-
- if (bp->ref_cnt > 0) {
- /* Release any buffers still alloc'd to this user */
- for (i = 0; i < bp->num_entries; i++) {
- if (bp->buf[i].size == 0)
- continue;
-
- if (bp->buf[i].in_use && bp->buf[i].user == vout->id)
- bp->buf[i].in_use = 0;
- }
- mutex_unlock(&bp->lock);
- } else {
- /* Destroy everything */
- for (i = 0; i < bp->num_entries; i++) {
- if (bp->buf[i].size == 0)
- continue;
-
- if (bp->buf[i].in_use)
- DBG("Destroying an in-use buffer\n");
-
- omapvout_mem_free(bp->buf[i].phy_addr,
- bp->buf[i].virt_addr,
- bp->buf[i].size);
- }
- mutex_unlock(&bp->lock);
-
- mutex_destroy(&bp->lock);
- kfree(bp);
- }
-}
-
-bool omapvout_is_bp_buffer(struct omapvout_device *vout,
- unsigned long phy_addr)
-{
- struct omapvout_bp *bp = vout->bp;
- int i;
-
- if (!bp)
- return false;
-
- for (i = 0; i < bp->num_entries; i++) {
- if (phy_addr == bp->buf[i].phy_addr)
- return true;
- }
-
- return false;
-}
-
-int omapvout_bp_alloc(struct omapvout_device *vout, u32 req_size,
- unsigned long *phy_addr, void **virt_addr, u32 *size)
-{
- struct omapvout_bp *bp = vout->bp;
- int i;
- int rc = -ENOMEM;
-
- if (!bp)
- return -ENOMEM;
-
- mutex_lock(&bp->lock);
-
- for (i = 0; i < bp->num_entries; i++) {
- if (bp->buf[i].in_use == 0 && bp->buf[i].size >= req_size) {
- bp->buf[i].in_use = 1;
- bp->buf[i].user = vout->id;
- *phy_addr = bp->buf[i].phy_addr;
- *virt_addr = bp->buf[i].virt_addr;
- *size = bp->buf[i].size;
- rc = 0;
- break;
- }
- }
-
- mutex_unlock(&bp->lock);
-
- return rc;
-}
-
-int omapvout_bp_release(struct omapvout_device *vout, unsigned long phy_addr)
-{
- struct omapvout_bp *bp = vout->bp;
- int i;
- int rc = -EINVAL;
-
- mutex_lock(&bp->lock);
-
- for (i = 0; i < bp->num_entries; i++) {
- if (bp->buf[i].phy_addr == phy_addr) {
- if (bp->buf[i].in_use)
- bp->buf[i].in_use = 0;
- else
- DBG("Releasing an unused buffer\n");
-
- /* Found the buffer, so say so */
- rc = 0;
-
- break;
- }
- }
-
- mutex_unlock(&bp->lock);
-
- return rc;
-}
-
diff --git a/drivers/media/video/omap-vout/omapvout-bp.h b/drivers/media/video/omap-vout/omapvout-bp.h
deleted file mode 100644
index 01bfa93..0000000
--- a/drivers/media/video/omap-vout/omapvout-bp.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-bp.h
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifndef __OMAPVOUT_BP_H__
-#define __OMAPVOUT_BP_H__
-
-struct omapvout_bp_entry {
- u32 in_use;
- u32 user;
- u32 size;
- unsigned long phy_addr;
- void *virt_addr;
-};
-
-struct omapvout_bp {
- struct mutex lock; /* Lock for all buffer pool accesses */
- int ref_cnt;
- int num_entries;
- struct omapvout_bp_entry buf[0];
-};
-
-extern struct omapvout_bp *omapvout_bp_create(u8 num_buffers, u32 buf_size);
-extern void omapvout_bp_init(struct omapvout_device *vout);
-extern void omapvout_bp_destroy(struct omapvout_device *vout);
-extern bool omapvout_is_bp_buffer(struct omapvout_device *vout,
- unsigned long phy_addr);
-extern int omapvout_bp_alloc(struct omapvout_device *vout, u32 req_size,
- unsigned long *phy_addr, void **virt_addr, u32 *size);
-extern int omapvout_bp_release(struct omapvout_device *vout,
- unsigned long phy_addr);
-
-#endif /* __OMAPVOUT_BP_H__ */
-
diff --git a/drivers/media/video/omap-vout/omapvout-dss.c b/drivers/media/video/omap-vout/omapvout-dss.c
deleted file mode 100644
index 2f4e016..0000000
--- a/drivers/media/video/omap-vout/omapvout-dss.c
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-dss.c
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * 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/mm.h>
-#include <mach/display.h>
-#include <mach/dma.h>
-#include <mach/vrfb.h>
-
-#include "omapvout.h"
-#include "omapvout-dss.h"
-#include "omapvout-mem.h"
-#include "omapvout-vbq.h"
-
-#define DMA_CHAN_ALLOTED 1
-#define DMA_CHAN_NOT_ALLOTED 0
-
-#define VRFB_TX_TIMEOUT 1000
-
-/*=== Local Functions ==================================================*/
-
-static int omapvout_dss_format_bytespp(u32 pixelformat)
-{
- int bpp = 2;
-
- switch (pixelformat) {
- case V4L2_PIX_FMT_RGB32:
- bpp = 4;
- break;
- case V4L2_PIX_FMT_RGB565:
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_UYVY:
- bpp = 2;
- break;
- }
-
- return bpp;
-}
-
-static enum omap_color_mode omapvout_dss_color_mode(u32 pixelformat)
-{
- enum omap_color_mode mode = OMAP_DSS_COLOR_RGB16;
-
- switch (pixelformat) {
- case V4L2_PIX_FMT_RGB32:
- mode = OMAP_DSS_COLOR_RGB24U;
- break;
- case V4L2_PIX_FMT_RGB565:
- mode = OMAP_DSS_COLOR_RGB16;
- break;
- case V4L2_PIX_FMT_YUYV:
- mode = OMAP_DSS_COLOR_YUV2;
- break;
- case V4L2_PIX_FMT_UYVY:
- mode = OMAP_DSS_COLOR_UYVY;
- break;
- }
-
- return mode;
-}
-
-static int omapvout_dss_calc_offset(struct omapvout_device *vout)
-{
- struct omapvout_dss *dss;
- int rc = 0;
- u32 fmt;
- int bpp;
- int bpp_mult = 1;
- u16 ow, oh;
- int iw, ih;
- int cx, cy, cw, ch;
-
- /* It is assumed that the caller has locked the vout mutex */
-
- fmt = vout->pix.pixelformat;
- bpp = omapvout_dss_format_bytespp(fmt);
- if (fmt == V4L2_PIX_FMT_YUYV || fmt == V4L2_PIX_FMT_UYVY)
- bpp_mult = 2;
-
- iw = vout->pix.width;
- ih = vout->pix.height;
- cx = vout->crop.left;
- cy = vout->crop.top;
- cw = vout->crop.width;
- ch = vout->crop.height;
-
- ow = iw;
- oh = ih;
- omap_vrfb_adjust_size(&ow, &oh, bpp);
- ow = ow - iw;
- oh = oh - ih;
-
- dss = vout->dss;
-
- switch (vout->rotation) {
- case 3: /* 270 degrees */
- dss->foffset = (cx * OMAP_VRFB_LINE_LEN * bpp * bpp_mult)
- + ((oh + (ih - cy - ch)) * bpp * bpp_mult);
- break;
- case 2: /* 180 degrees */
- dss->foffset = ((oh + (ih - cy - ch)) * OMAP_VRFB_LINE_LEN
- * bpp * bpp_mult)
- + ((ow + (iw - cx - cw)) * bpp * bpp_mult);
- break;
- case 1: /* 90 degrees */
- dss->foffset = ((ow + (iw - cx - cw)) * OMAP_VRFB_LINE_LEN
- * bpp * bpp_mult)
- + (cy * bpp * bpp_mult);
- break;
- default:
- case 0: /* 0 degrees */
- dss->foffset = ((cy * iw) + (cx)) * bpp;
- break;
- }
-
- return rc;
-}
-
-static int omapvout_dss_get_overlays(struct omap_overlay **gfx,
- struct omap_overlay **vid1, struct omap_overlay **vid2)
-{
- struct omap_overlay *t;
- int num_ovlys;
- int i;
-
- *gfx = NULL;
- *vid1 = NULL;
- *vid2 = NULL;
- num_ovlys = omap_dss_get_num_overlays();
- for (i = 0; i < num_ovlys; i++) {
- t = omap_dss_get_overlay(i);
-
- switch (t->id) {
- case OMAP_DSS_GFX:
- *gfx = t;
- break;
- case OMAP_DSS_VIDEO1:
- *vid1 = t;
- break;
- case OMAP_DSS_VIDEO2:
- *vid2 = t;
- break;
- }
- }
-
- if (*gfx && *vid1 && *vid2)
- return 0;
-
- return -EINVAL;
-}
-
-/* The algorithm below was cooked up to provide a reasonable global alpha
- * configuration based on the typical use case, which is a single video plane
- * blended with the graphics plane. This algorithm will handle multiple
- * video planes as well, but the thought is that typically the user is not
- * going to want to be forced to set the global alpha value via the graphics
- * plane (the frame buffer), but instead via the video plane.
- *
- * Algorithm:
- * 1) For video1, if video2 is enabled, place the global alpha value set to
- * video2, else set to the graphics plane.
- * 2) For video2, always place the global alpha value set to the graphics
- * plane, but need to be careful to move the video1 alpha value if its
- * already enabled.
- */
-static void omapvout_dss_set_global_alpha(struct omapvout_device *vout)
-{
- struct omap_overlay *gfx, *vid1, *vid2;
- struct omap_overlay_info info;
- u8 alpha;
- u8 t;
-
- /* Invert the requested alpha value since this alpha value is how
- * transparent the video plane is supposed to be, but it is being
- * applied to the plane above.
- */
- alpha = 255 - vout->win.global_alpha;
-
- if (omapvout_dss_get_overlays(&gfx, &vid1, &vid2)) {
- DBG("Not all planes available\n");
- return;
- }
-
- if (vout->dss->overlay->id == OMAP_DSS_VIDEO1) {
- vid2->get_overlay_info(vid2, &info);
- if (info.enabled) {
- info.global_alpha = alpha;
- vid2->set_overlay_info(vid2, &info);
- } else {
- gfx->get_overlay_info(gfx, &info);
- info.global_alpha = alpha;
- gfx->set_overlay_info(gfx, &info);
- }
- } else if (vout->dss->overlay->id == OMAP_DSS_VIDEO2) {
- vid1->get_overlay_info(vid1, &info);
- if (info.enabled) {
- gfx->get_overlay_info(gfx, &info);
- t = info.global_alpha;
- info.global_alpha = alpha;
- gfx->set_overlay_info(gfx, &info);
- vid2->get_overlay_info(vid2, &info);
- info.global_alpha = t;
- vid2->set_overlay_info(vid2, &info);
- } else {
- gfx->get_overlay_info(gfx, &info);
- info.global_alpha = alpha;
- gfx->set_overlay_info(gfx, &info);
- vid2->get_overlay_info(vid2, &info);
- info.global_alpha = 255;
- vid2->set_overlay_info(vid2, &info);
- }
- }
-
-#ifdef DEBUG
- gfx->get_overlay_info(gfx, &info);
- DBG("GFX Alpha = %d\n", info.global_alpha);
- vid2->get_overlay_info(vid2, &info);
- DBG("VID2 Alpha = %d\n", info.global_alpha);
- vid1->get_overlay_info(vid1, &info);
- DBG("VID1 Alpha = %d\n", info.global_alpha);
-#endif
-}
-
-/* This algorithm reverses the changes made in the "_set_" function and
- * returns a flag denoting if alpha should still be enabled.
- *
- * The non-trivial part is to handle the case where both video planes are
- * enabled.
- */
-static bool omapvout_dss_clr_global_alpha(struct omapvout_device *vout)
-{
- struct omap_overlay *gfx, *vid1, *vid2;
- struct omap_overlay_info info;
- bool alpha_en = false;
- u8 t;
-
- if (omapvout_dss_get_overlays(&gfx, &vid1, &vid2)) {
- DBG("Not all planes available\n");
- return false;
- }
-
- if (vout->dss->overlay->id == OMAP_DSS_VIDEO1) {
- vid2->get_overlay_info(vid2, &info);
- if (info.enabled)
- alpha_en = true;
- } else if (vout->dss->overlay->id == OMAP_DSS_VIDEO2) {
- vid1->get_overlay_info(vid1, &info);
- if (info.enabled) {
- alpha_en = true;
-
- /* Set gfx alpha to vid1's alpha */
- vid2->get_overlay_info(vid2, &info);
- t = info.global_alpha;
- gfx->get_overlay_info(gfx, &info);
- info.global_alpha = t;
- gfx->set_overlay_info(gfx, &info);
- }
- }
-
- return alpha_en;
-}
-
-static int omapvout_dss_enable_transparency(struct omapvout_device *vout)
-{
- struct omap_overlay_manager *mgr;
- struct omap_overlay_manager_info m_info;
-
- mgr = vout->dss->overlay->manager;
- if (mgr == NULL)
- return -EINVAL;
-
- if (mgr->set_manager_info == NULL || mgr->get_manager_info == NULL)
- return -EINVAL;
-
- mgr->get_manager_info(mgr, &m_info);
-
- m_info.default_color = vout->bg_color;
-
- if (vout->fbuf.flags & V4L2_FBUF_FLAG_CHROMAKEY) {
- m_info.trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
- m_info.trans_key = vout->win.chromakey;
- m_info.trans_enabled = true;
- } else if (vout->fbuf.flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) {
- m_info.trans_key_type = OMAP_DSS_COLOR_KEY_VID_SRC;
- m_info.trans_key = vout->win.chromakey;
- m_info.trans_enabled = true;
- } else {
- m_info.trans_enabled = false;
- }
-
- if (vout->fbuf.flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) {
- m_info.alpha_enabled = true;
- } else if (vout->fbuf.flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) {
- omapvout_dss_set_global_alpha(vout);
- m_info.alpha_enabled = true;
- } else {
- m_info.alpha_enabled = false;
- }
-
- DBG("Trans Enable = %d\n", m_info.trans_enabled);
- DBG("Trans Mode = %d\n", m_info.trans_key_type);
- DBG("Alpha Enable = %d\n", m_info.alpha_enabled);
-
- mgr->set_manager_info(mgr, &m_info);
-
- return 0;
-}
-
-static int omapvout_dss_disable_transparency(struct omapvout_device *vout)
-{
- struct omap_overlay_manager *mgr;
- struct omap_overlay_manager_info m_info;
-
- mgr = vout->dss->overlay->manager;
- if (mgr == NULL)
- return -EINVAL;
-
- if (mgr->set_manager_info == NULL || mgr->get_manager_info == NULL)
- return -EINVAL;
-
- mgr->get_manager_info(mgr, &m_info);
-
- m_info.alpha_enabled = omapvout_dss_clr_global_alpha(vout);
- m_info.trans_enabled = false;
-
- mgr->set_manager_info(mgr, &m_info);
-
- return 0;
-}
-
-/* This functions wakes up the application once the DMA transfer to
- * VRFB space is completed.
- */
-static void omapvout_dss_vrfb_dma_cb(int lch, u16 ch_status, void *data)
-{
- struct omapvout_dss_vrfb *vrfb;
-
- vrfb = (struct omapvout_dss_vrfb *) data;
-
- vrfb->dma_complete = true;
- wake_up_interruptible(&vrfb->wait);
-}
-
-static int omapvout_dss_acquire_vrfb(struct omapvout_device *vout)
-{
- int rc = 0;
- int size;
- int w, h;
- int max_pixels;
- struct omapvout_dss_vrfb *vrfb;
-
- /* It is assumed that the caller has locked the vout mutex */
-
- vrfb = &vout->dss->vrfb;
- vrfb->dma_id = OMAP_DMA_NO_DEVICE;
- vrfb->dma_ch = -1;
- vrfb->req_status = DMA_CHAN_NOT_ALLOTED;
- vrfb->next = 0;
-
- rc = omap_vrfb_request_ctx(&vrfb->ctx[0]);
- if (rc != 0) {
- DBG("VRFB context allocation 0 failed %d\n", rc);
- goto failed_ctx0;
- }
-
- rc = omap_vrfb_request_ctx(&vrfb->ctx[1]);
- if (rc != 0) {
- DBG("VRFB context allocation 1 failed %d\n", rc);
- goto failed_ctx1;
- }
-
- /* Determine the VFRB buffer size by oversizing for the VRFB */
- w = vout->max_video_width;
- h = vout->max_video_height;
- max_pixels = w * h;
- w += 32; /* Oversize as typical for VRFB */
- h += 32;
- size = PAGE_ALIGN(w * h * (vout->max_video_buffer_size / max_pixels));
- vrfb->size = size;
-
- rc = omapvout_mem_alloc(size, &vrfb->phy_addr[0], &vrfb->virt_addr[0]);
- if (rc != 0) {
- DBG("VRFB buffer alloc 0 failed %d\n", rc);
- goto failed_mem0;
- }
-
- rc = omapvout_mem_alloc(size, &vrfb->phy_addr[1], &vrfb->virt_addr[1]);
- if (rc != 0) {
- DBG("VRFB buffer alloc 1 failed %d\n", rc);
- goto failed_mem1;
- }
-
- rc = omap_request_dma(vrfb->dma_id, "VRFB DMA",
- omapvout_dss_vrfb_dma_cb,
- (void *)vrfb,
- &vrfb->dma_ch);
- if (rc != 0) {
- printk(KERN_INFO "No VRFB DMA channel for %d\n", vout->id);
- goto failed_dma;
- }
-
- vrfb->req_status = DMA_CHAN_ALLOTED;
- init_waitqueue_head(&vrfb->wait);
-
- return rc;
-
-failed_dma:
- omapvout_mem_free(vrfb->phy_addr[1], vrfb->virt_addr[1], size);
-failed_mem1:
- omapvout_mem_free(vrfb->phy_addr[0], vrfb->virt_addr[0], size);
-failed_mem0:
- omap_vrfb_release_ctx(&vrfb->ctx[1]);
-failed_ctx1:
- omap_vrfb_release_ctx(&vrfb->ctx[0]);
-failed_ctx0:
- return rc;
-}
-
-static int omapvout_dss_release_vrfb(struct omapvout_device *vout)
-{
- int rc = 0;
- int size;
- struct omapvout_dss_vrfb *vrfb;
-
- /* It is assumed that the caller has locked the vout mutex */
-
- vrfb = &vout->dss->vrfb;
- if (vrfb->req_status == DMA_CHAN_ALLOTED) {
- vrfb->req_status = DMA_CHAN_NOT_ALLOTED;
- omap_free_dma(vrfb->dma_ch);
- /* FIXME: de-init the wait queue? */
-
- size = vrfb->size;
- omapvout_mem_free(vrfb->phy_addr[0], vrfb->virt_addr[0], size);
- omapvout_mem_free(vrfb->phy_addr[1], vrfb->virt_addr[1], size);
-
- omap_vrfb_release_ctx(&vrfb->ctx[0]);
- omap_vrfb_release_ctx(&vrfb->ctx[1]);
- }
-
- return rc;
-}
-
-static int omapvout_dss_perform_vrfb_dma(struct omapvout_device *vout,
- int buf_idx, bool vrfb_cfg)
-{
- int rc = 0;
- int rot = 0;
- struct omapvout_dss_vrfb *vrfb;
- u32 src_paddr;
- u32 dst_paddr;
-
- /* It is assumed that the caller has locked the vout mutex */
-
- if (vout->dss->vrfb.req_status != DMA_CHAN_ALLOTED)
- return -EINVAL;
-
- vrfb = &vout->dss->vrfb;
-
- if (vrfb_cfg) {
- enum omap_color_mode dss_fmt;
- int bytespp;
- int w, h;
- u32 fmt = vout->pix.pixelformat;
-
- w = vout->crop.width;
- h = vout->crop.height;
-
- dss_fmt = omapvout_dss_color_mode(vout->pix.pixelformat);
- omap_vrfb_setup(&vrfb->ctx[0], vrfb->phy_addr[0],
- w, h, dss_fmt, vout->rotation);
- omap_vrfb_setup(&vrfb->ctx[1], vrfb->phy_addr[1],
- w, h, dss_fmt, vout->rotation);
-
- bytespp = omapvout_dss_format_bytespp(vout->pix.pixelformat);
- vrfb->en = (w * bytespp) / 4; /* 32 bit ES */
- vrfb->fn = h;
- vrfb->dst_ei = 1;
- if (fmt == V4L2_PIX_FMT_YUYV || fmt == V4L2_PIX_FMT_UYVY) {
- vrfb->dst_fi = (OMAP_VRFB_LINE_LEN * bytespp * 2)
- - (vrfb->en * 4) + 1;
- } else {
- vrfb->dst_fi = (OMAP_VRFB_LINE_LEN * bytespp)
- - (vrfb->en * 4) + 1;
- }
- }
-
- switch (vout->rotation) {
- case 1:
- rot = 3;
- break;
- case 3:
- rot = 1;
- break;
- default:
- rot = vout->rotation;
- break;
- }
-
- src_paddr = vout->queue.bufs[buf_idx]->baddr;
- dst_paddr = vrfb->ctx[vrfb->next].paddr[rot];
-
- omap_set_dma_transfer_params(vrfb->dma_ch, OMAP_DMA_DATA_TYPE_S32,
- vrfb->en, vrfb->fn, OMAP_DMA_SYNC_ELEMENT,
- vrfb->dma_id, 0x0);
- omap_set_dma_src_params(vrfb->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
- src_paddr, 0, 0);
- omap_set_dma_src_burst_mode(vrfb->dma_ch, OMAP_DMA_DATA_BURST_16);
- omap_set_dma_dest_params(vrfb->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX,
- dst_paddr, vrfb->dst_ei, vrfb->dst_fi);
- omap_set_dma_dest_burst_mode(vrfb->dma_ch, OMAP_DMA_DATA_BURST_16);
- omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
-
- vrfb->dma_complete = false;
- omap_start_dma(vrfb->dma_ch);
- wait_event_interruptible_timeout(vrfb->wait, vrfb->dma_complete,
- VRFB_TX_TIMEOUT);
-
- if (!vrfb->dma_complete) {
- DBG("VRFB DMA timeout\n");
- omap_stop_dma(vrfb->dma_ch);
- return -EINVAL;
- }
-
- return rc;
-}
-
-static int omapvout_dss_update_overlay(struct omapvout_device *vout,
- int buf_idx)
-{
- struct omap_overlay_info o_info;
- struct omap_overlay *ovly;
- struct omapvout_dss_vrfb *vrfb;
- int rc = 0;
- int rot = vout->rotation;
-
- /* It is assumed that the caller has locked the vout mutex */
-
- /* Populate the overlay info struct and set it */
- ovly = vout->dss->overlay;
- ovly->get_overlay_info(ovly, &o_info);
- o_info.enabled = true;
- vrfb = &vout->dss->vrfb;
- o_info.paddr = vrfb->ctx[vrfb->next].paddr[0];
- o_info.paddr += vout->dss->foffset;
- o_info.vaddr = NULL;
- o_info.screen_width = OMAP_VRFB_LINE_LEN;
- vrfb->next = (vrfb->next) ? 0 : 1;
-
- if (rot == 1 || rot == 3) { /* 90 or 270 degree rotation */
- o_info.width = vout->crop.height;
- o_info.height = vout->crop.width;
- } else {
- o_info.width = vout->crop.width;
- o_info.height = vout->crop.height;
- }
-
- o_info.pos_x = vout->win.w.left & ~1;
- o_info.pos_y = vout->win.w.top & ~1;
- o_info.out_width = vout->win.w.width;
- o_info.out_height = vout->win.w.height;
- o_info.color_mode = omapvout_dss_color_mode(vout->pix.pixelformat);
- o_info.rotation_type = OMAP_DSS_ROT_VRFB;
- o_info.rotation = rot;
- o_info.mirror = false;
-
- rc = ovly->set_overlay_info(ovly, &o_info);
- if (rc) {
- DBG("Failed setting the overlay info %d\n", rc);
- return rc;
- }
-
- rc = ovly->manager->apply(ovly->manager);
- if (rc) {
- DBG("Failed apply to overlay manager %d\n", rc);
- return rc;
- }
-
- rc = ovly->manager->device->update(ovly->manager->device,
- o_info.pos_x, o_info.pos_y,
- o_info.out_width, o_info.out_height);
- if (rc)
- DBG("Overlay update failed %d\n", rc);
-
- return rc;
-}
-
-static void omapvout_dss_mark_buf_done(struct omapvout_device *vout, int idx)
-{
- /* FIXME: Should set the state to VIDEOBUF_DONE here, but since we
- * don't properly DQ yet, this has been hacked to allow no DQ.
- */
- vout->queue.bufs[idx]->state = VIDEOBUF_IDLE;
- wake_up_interruptible(&vout->queue.bufs[idx]->done);
-}
-
-static void omapvout_dss_perform_update(struct work_struct *work)
-{
- struct omapvout_device *vout;
- struct omapvout_dss *dss;
- struct omap_dss_device *dev;
- struct videobuf_buffer *buf;
- int rc;
- int idx = 0;
-
- dss = container_of(work, struct omapvout_dss, work);
- vout = dss->vout;
-
- if (!dss->enabled)
- return;
-
- mutex_lock(&vout->mtx);
-
- dss->working = true;
-
- while (!list_empty(&vout->q_list)) {
-
- buf = list_entry(vout->q_list.next,
- struct videobuf_buffer, queue);
- list_del(&buf->queue);
- buf->state = VIDEOBUF_ACTIVE;
- idx = buf->i;
-
- /*DBG("Processing frame %d\n", idx);*/
-
- if (dss->need_cfg) {
- rc = omapvout_dss_calc_offset(vout);
- if (rc != 0) {
- DBG("Offset calculation failed %d\n", rc);
- goto failed_need_done;
- }
-
- rc = omapvout_dss_enable_transparency(vout);
- if (rc != 0) {
- DBG("Alpha config failed %d\n", rc);
- goto failed_need_done;
- }
- }
-
- rc = omapvout_dss_perform_vrfb_dma(vout, idx, dss->need_cfg);
- if (rc != 0) {
- DBG("VRFB rotation failed %d\n", rc);
- goto failed_need_done;
- }
-
- omapvout_dss_mark_buf_done(vout, idx);
-
- rc = omapvout_dss_update_overlay(vout, idx);
- if (rc != 0) {
- DBG("DSS update failed %d\n", rc);
- goto failed;
- }
-
- dss->need_cfg = false;
-
- mutex_unlock(&vout->mtx);
-
- /* Wait until the new frame is being used. There is no problem
- * doing this here since we are in a worker thread. The mutex
- * is unlocked since the sync may take some time.
- */
- dev = dss->overlay->manager->device;
- if (dev->sync)
- dev->sync(dev);
-
- /* Since the mutex was unlocked, it is possible that the DSS
- * may be disabled when we return, so check for this and exit
- * if so.
- */
- if (!dss->enabled) {
- /* Since the DSS is disabled, this isn't a problem */
- dss->working = false;
-
- /* Clean up the states of the final buffer */
- omapvout_dss_mark_buf_done(vout, idx);
- return;
- }
-
- mutex_lock(&vout->mtx);
- }
-
- dss->working = false;
- mutex_unlock(&vout->mtx);
-
- return;
-
-failed_need_done:
- /* Set the done flag on failures to be sure the buffer can be DQ'd */
- omapvout_dss_mark_buf_done(vout, idx);
-failed:
- dss->working = false;
- mutex_unlock(&vout->mtx);
-}
-
-/*=== Public Functions =================================================*/
-
-int omapvout_dss_init(struct omapvout_device *vout, enum omap_plane plane)
-{
- struct omap_overlay *ovly;
- int rc = 0;
- int i;
- int cnt;
-
- if (vout->dss) {
- rc = -EINVAL;
- goto failed;
- }
-
- vout->dss = kzalloc(sizeof(struct omapvout_dss), GFP_KERNEL);
- if (vout->dss == NULL) {
- rc = -ENOMEM;
- goto failed;
- }
-
- /* Retrieve the desired DSS overlay object */
- vout->dss->overlay = NULL;
- cnt = omap_dss_get_num_overlays();
- for (i = 0; i < cnt; i++) {
- ovly = omap_dss_get_overlay(i);
- if (ovly->id == plane) {
- vout->dss->overlay = ovly;
- break;
- }
- }
-
- if (vout->dss->overlay == NULL) {
- DBG("No overlay %d found\n", plane);
- rc = -ENODEV;
- goto failed_mem;
- }
-
- rc = omapvout_dss_acquire_vrfb(vout);
- if (rc != 0) {
- DBG("VRFB allocation failed\n");
- goto failed_mem;
- }
-
- vout->dss->vout = vout;
-
- return rc;
-
-failed_mem:
- kfree(vout->dss);
-failed:
- return rc;
-}
-
-void omapvout_dss_remove(struct omapvout_device *vout)
-{
- if (vout->dss != NULL) {
- omapvout_dss_release_vrfb(vout);
- kfree(vout->dss);
- }
-}
-
-int omapvout_dss_open(struct omapvout_device *vout, u16 *disp_w, u16 *disp_h)
-{
- struct omap_dss_device *dev;
- int rc = 0;
-
- /* It is assumed that the caller has locked the vout mutex */
-
- if (vout->dss->overlay->manager == NULL) {
- DBG("No manager found\n");
- rc = -ENODEV;
- goto failed;
- }
-
- if (vout->dss->overlay->manager->device == NULL) {
- DBG("No device found\n");
- rc = -ENODEV;
- goto failed;
- }
-
- dev = vout->dss->overlay->manager->device;
-
- /* TODO: Do we need to deal with rotation? */
- dev->get_resolution(dev, disp_w, disp_h);
-
- vout->dss->workqueue = create_singlethread_workqueue("OMAPVOUT-DSS");
- if (vout->dss->workqueue == NULL) {
- rc = -ENOMEM;
- goto failed;
- }
-
- INIT_WORK(&vout->dss->work, omapvout_dss_perform_update);
-
- vout->dss->enabled = false;
-
-failed:
- return rc;
-}
-
-void omapvout_dss_release(struct omapvout_device *vout)
-{
- /* It is assumed that the caller has locked the vout mutex */
-
- if (vout->dss->enabled)
- omapvout_dss_disable(vout);
-
- flush_workqueue(vout->dss->workqueue);
- destroy_workqueue(vout->dss->workqueue);
-}
-
-bool omapvout_dss_is_rotation_supported(struct omapvout_device *vout)
-{
- return vout->dss->vrfb.req_status == DMA_CHAN_ALLOTED;
-}
-
-int omapvout_dss_enable(struct omapvout_device *vout)
-{
- /* It is assumed that the caller has locked the vout mutex */
-
- /* Reset the current frame idx */
- vout->dss->cur_q_idx = -1;
-
- /* Force a reconfiguration */
- vout->dss->need_cfg = true;
-
- vout->dss->enabled = true;
-
- return 0;
-}
-
-void omapvout_dss_disable(struct omapvout_device *vout)
-{
- int rc = 0;
- struct omap_overlay_info o_info;
- struct omap_overlay *ovly;
- struct omap_dss_device *dev;
-
- /* It is assumed that the caller has locked the vout mutex */
-
- memset(&o_info, 0, sizeof(o_info));
- o_info.enabled = false;
-
- vout->dss->enabled = false;
-
- dev = vout->dss->overlay->manager->device;
- if (vout->dss->working && dev->sync) {
- /* Allow the current frame to finish */
- mutex_unlock(&vout->mtx);
- dev->sync(dev);
- mutex_lock(&vout->mtx);
- }
-
- rc = omapvout_dss_disable_transparency(vout);
- if (rc)
- DBG("Disabling transparency failed %d\n", rc);
-
- ovly = vout->dss->overlay;
- rc = ovly->set_overlay_info(ovly, &o_info);
- if (rc)
- DBG("Setting overlay info failed %d\n", rc);
-
- rc = ovly->manager->apply(ovly->manager);
- if (rc)
- DBG("Overlay manager apply failed %d\n", rc);
-
- rc = ovly->manager->device->update(ovly->manager->device,
- 0, 0, vout->disp_width, vout->disp_height);
- if (rc)
- DBG("Display update failed %d\n", rc);
-}
-
-int omapvout_dss_update(struct omapvout_device *vout)
-{
- /* It is assumed that the caller has locked the vout mutex */
-
- if (!vout->dss->enabled) {
- DBG("DSS overlay is not enabled\n");
- return -EINVAL;
- }
-
- if (vout->dss->working) {
- /* Exit quitely, since still working on previous frame */
- /*DBG("DSS busy, handle shortly\n");*/
- return 0;
- }
-
- if (queue_work(vout->dss->workqueue, &vout->dss->work) == 0) {
- DBG("Queuing DSS work failed\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
diff --git a/drivers/media/video/omap-vout/omapvout-dss.h b/drivers/media/video/omap-vout/omapvout-dss.h
deleted file mode 100644
index 3249133..0000000
--- a/drivers/media/video/omap-vout/omapvout-dss.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-dss.h
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * 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 __OMAPVOUT_DSS_H__
-#define __OMAPVOUT_DSS_H__
-
-struct omapvout_dss_vrfb {
- /* Ping-pong buffers and VRFB contexts */
- struct vrfb ctx[2];
- unsigned long phy_addr[2];
- void *virt_addr[2];
- int size;
- int next;
-
- /* VRFB dma config data */
- u32 en;
- u32 fn;
- u32 dst_ei;
- u32 dst_fi;
-
- /* VRFB dma channel data */
- int dma_id;
- int dma_ch;
- int req_status;
- bool dma_complete;
- wait_queue_head_t wait;
-};
-
-struct omapvout_dss {
- struct omap_overlay *overlay;
-
- /* FIXME: This is a minor hack to allow the work callback to
- * gain access to the vout pointer.
- */
- struct omapvout_device *vout;
-
- bool enabled;
- bool need_cfg;
-
- struct omapvout_dss_vrfb vrfb;
- int foffset; /* per frame address offset */
-
- struct work_struct work;
- struct workqueue_struct *workqueue;
- bool working;
-
- int cur_q_idx; /* The current Q frame used by DSS */
-};
-
-/* Driver init/remove time calls */
-extern int omapvout_dss_init(struct omapvout_device *vout,
- enum omap_plane plane);
-extern void omapvout_dss_remove(struct omapvout_device *vout);
-
-/* Driver open/release time calls */
-extern int omapvout_dss_open(struct omapvout_device *vout,
- u16 *disp_w, u16 *disp_h);
-extern void omapvout_dss_release(struct omapvout_device *vout);
-
-/* Driver operation calls */
-extern bool omapvout_dss_is_rotation_supported(struct omapvout_device *vout);
-extern int omapvout_dss_enable(struct omapvout_device *vout);
-extern void omapvout_dss_disable(struct omapvout_device *vout);
-extern int omapvout_dss_update(struct omapvout_device *vout);
-
-#endif /* __OMAPVOUT_DSS_H__ */
-
diff --git a/drivers/media/video/omap-vout/omapvout-mem.c b/drivers/media/video/omap-vout/omapvout-mem.c
deleted file mode 100644
index f63a848..0000000
--- a/drivers/media/video/omap-vout/omapvout-mem.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-mem.c
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * 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/io.h>
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-
-#include <asm/processor.h>
-#include <asm/cacheflush.h>
-#include <asm/page.h>
-
-#include "omapvout.h"
-#include "omapvout-mem.h"
-
-int omapvout_mem_alloc(u32 size, unsigned long *phy_addr, void **virt_addr)
-{
- void *page_addr;
-
- size = PAGE_ALIGN(size);
-
- page_addr = alloc_pages_exact(size, GFP_KERNEL);
- if (!page_addr) {
- printk(KERN_ERR "Failed to allocate pages!\n");
- return -ENOMEM;
- }
-
- *phy_addr = virt_to_phys(page_addr);
- *virt_addr = ioremap_cached(*phy_addr, size);
-
- DBG("mem_alloc: page/%08x; phy/%08lx; virt/%08x; size/%x\n",
- (unsigned int) page_addr, *phy_addr,
- (unsigned int) *virt_addr, size);
-
- return 0;
-}
-
-void omapvout_mem_free(unsigned long phy_addr, void *virt_addr, u32 size)
-{
- void *page_addr;
-
- size = PAGE_ALIGN(size);
- page_addr = __va((void *)phy_addr);
-
- free_pages_exact(page_addr, size);
-
- iounmap(virt_addr);
-}
-
-int omapvout_mem_map(struct vm_area_struct *vma, unsigned long phy_addr)
-{
- struct page *cpage;
- void *pos;
- u32 start;
- u32 size;
-
- vma->vm_flags |= VM_RESERVED;
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- pos = (void *) phy_addr;
- start = vma->vm_start;
- size = (vma->vm_end - vma->vm_start);
-
- while (size > 0) {
- cpage = pfn_to_page(((unsigned int)pos) >> PAGE_SHIFT);
- if (vm_insert_page(vma, start, cpage)) {
- printk(KERN_ERR "Failed to insert page to VMA \n");
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
-
- return 0;
-}
-
-
diff --git a/drivers/media/video/omap-vout/omapvout-mem.h b/drivers/media/video/omap-vout/omapvout-mem.h
deleted file mode 100644
index 6665a15..0000000
--- a/drivers/media/video/omap-vout/omapvout-mem.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-mem.h
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * 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 __OMAPVOUT_MEM_H__
-#define __OMAPVOUT_MEM_H__
-
-extern int omapvout_mem_alloc(u32 size, unsigned long *phy_addr,
- void **virt_addr);
-extern void omapvout_mem_free(unsigned long phy_addr, void *virt_addr,
- u32 size);
-extern int omapvout_mem_map(struct vm_area_struct *vma,
- unsigned long phy_addr);
-
-#endif /* __OMAPVOUT_MEM_H__ */
-
diff --git a/drivers/media/video/omap-vout/omapvout-vbq.c b/drivers/media/video/omap-vout/omapvout-vbq.c
deleted file mode 100644
index d6da499..0000000
--- a/drivers/media/video/omap-vout/omapvout-vbq.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-vbq.c
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- * This file contains the code necessary to interface with the
- * vbq (video buffer queue).
- */
-
-#include <media/videobuf-core.h>
-#include <linux/mm.h>
-
-#include "omapvout.h"
-#include "omapvout-vbq.h"
-#include "omapvout-bp.h"
-#include "omapvout-dss.h"
-#include "omapvout-mem.h"
-
-/*=== Local Functions ==================================================*/
-
-static void omapvout_vbq_vm_open(struct vm_area_struct *vma)
-{
- struct omapvout_device *vout = vma->vm_private_data;
- DBG("vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
- vout->mmap_cnt++;
-}
-
-static void omapvout_vbq_vm_close(struct vm_area_struct *vma)
-{
- struct omapvout_device *vout = vma->vm_private_data;
- DBG("vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
- vout->mmap_cnt--;
-}
-
-static struct vm_operations_struct vm_ops = {
- .open = omapvout_vbq_vm_open,
- .close = omapvout_vbq_vm_close
-};
-
-static void omapvout_acquire_frames(struct omapvout_device *vout,
- int cnt, int size)
-{
- struct omapvout_vbq *vbq;
- int i;
- int fcnt;
- unsigned long paddr;
- void *vaddr;
- u32 fsize;
-
- /* It is assumed that the vout->mtx is locked for this call */
-
- vbq = vout->vbq;
-
- vbq->min_size = 0x7FFFFFF; /* Some large value */
- fcnt = 0;
- for (i = 0; i < cnt; i++) {
-#ifdef CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL
- if (vout->bp && omapvout_bp_alloc(vout, size,
- &paddr, &vaddr, &fsize) == 0) {
- DBG("Alloc'd from the pool\n");
- } else {
-#else
- {
-#endif
- if (omapvout_mem_alloc(size, &paddr, &vaddr)) {
- DBG("Alloc failed %d\n", i);
- break;
- }
- fsize = size;
- }
-
- memset(vaddr, 0, fsize);
-
- vbq->buf[fcnt].size = fsize;
- vbq->buf[fcnt].phy_addr = paddr;
- vbq->buf[fcnt].virt_addr = vaddr;
- vbq->buf[fcnt].released = false;
-
- fcnt++;
-
- if (fsize < vbq->min_size)
- vbq->min_size = fsize;
- }
-
- vbq->cnt = fcnt;
-}
-
-static void omapvout_release_frames(struct omapvout_device *vout)
-{
- struct omapvout_vbq *vbq;
- int i;
- unsigned long paddr;
- void *vaddr;
- u32 size;
-
- /* It is assumed that the vout->mtx is locked for this call */
-
- vbq = vout->vbq;
-
- for (i = 0; i < vbq->cnt; i++) {
- paddr = vbq->buf[i].phy_addr;
- vaddr = vbq->buf[i].virt_addr;
- size = vbq->buf[i].size;
-
-#ifdef CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL
- if (omapvout_is_bp_buffer(vout, paddr)) {
- if (omapvout_bp_release(vout, paddr))
- DBG("Error releasing to the pool\n");
- } else {
-#else
- {
-#endif
- omapvout_mem_free(paddr, vaddr, size);
- }
- }
-
- vbq->cnt = 0;
- vbq->min_size = 0;
- memset(vbq->buf, 0, sizeof(vbq->buf));
-}
-
-static int omapvout_vbq_buf_setup(struct videobuf_queue *q,
- unsigned int *count, unsigned int *size)
-{
- struct omapvout_device *vout;
- struct omapvout_vbq *vbq;
- int cnt = *count;
- int sz;
-
- vout = q->priv_data;
- if (!vout)
- return -EINVAL;
-
- vbq = vout->vbq;
-
- /* It is assumed that the video out format is correctly configured */
- if (vout->pix.sizeimage == 0)
- return -EINVAL;
-
- sz = vout->pix.sizeimage;
-
- /* Use the existing frames if possible */
- if (cnt <= vbq->cnt && sz <= vbq->min_size)
- goto success;
-
- if (cnt > VIDEO_MAX_FRAME)
- cnt = VIDEO_MAX_FRAME;
-
- omapvout_release_frames(vout);
- omapvout_acquire_frames(vout, cnt, sz);
-
- if (vbq->cnt <= 0) {
- DBG("Buffer allocation failed\n");
- return -ENOMEM;
- }
- cnt = vbq->cnt;
-
-success:
- *count = cnt;
- *size = sz;
-
- return 0;
-}
-
-static int omapvout_vbq_buf_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb, enum v4l2_field field)
-{
- struct omapvout_device *vout;
-
- vout = q->priv_data;
- if (!vout)
- return -EINVAL;
-
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- vb->width = vout->pix.width;
- vb->height = vout->pix.height;
- vb->size = vout->pix.sizeimage;
- vb->field = field;
- vb->privsize = 0; /* Reusing for buf seq number */
- }
-
- vb->state = VIDEOBUF_PREPARED;
-
- return 0;
-}
-
-static void omapvout_vbq_buf_queue(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- struct omapvout_device *vout;
-
- vout = q->priv_data;
- if (!vout)
- return;
-
- /* Add it to the incoming queue */
- list_add_tail(&vb->queue, &vout->q_list);
-
- vb->state = VIDEOBUF_QUEUED;
-
- omapvout_dss_update(vout);
-}
-
-static void omapvout_vbq_buf_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- struct omapvout_device *vout;
- int i;
-
- vout = q->priv_data;
- if (!vout)
- return;
-
- if (vout->vbq->cnt <= 0)
- return;
-
- vout->vbq->buf[vb->i].released = true;
-
- for (i = 0; i < vout->vbq->cnt; i++) {
- if (!vout->vbq->buf[i].released)
- break;
- }
- if (i > vout->vbq->cnt) /* All buffers have been released */
- omapvout_release_frames(vout);
-
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static struct videobuf_queue_ops vbq_buf_ops = {
- .buf_setup = omapvout_vbq_buf_setup,
- .buf_prepare = omapvout_vbq_buf_prepare,
- .buf_queue = omapvout_vbq_buf_queue,
- .buf_release = omapvout_vbq_buf_release
-};
-
-static void *omapvout_vbq_alloc(size_t size)
-{
- return kzalloc(size, GFP_KERNEL);
-}
-
-static void *omapvout_vbq_vmalloc(struct videobuf_buffer *buf)
-{
- /* Do nothing */
- return NULL;
-}
-
-static int omapvout_vbq_iolock(struct videobuf_queue *q,
- struct videobuf_buffer *vb, struct v4l2_framebuffer *fbuf)
-{
- /* Do nothing */
- return 0;
-}
-
-static int omapvout_vbq_mmap_op(struct videobuf_queue *q, unsigned int *count,
- unsigned int *size, enum v4l2_memory memory)
-{
- /* Do nothing */
- return 0;
-}
-
-static int omapvout_vbq_sync(struct videobuf_queue *q,
- struct videobuf_buffer *buf)
-{
- /* Do nothing */
- return 0;
-}
-
-static int omapvout_vbq_copy_user(struct videobuf_queue *q, char __user *data,
- size_t count, int nonblocking)
-{
- /* Do nothing */
- return 0;
-}
-
-static int omapvout_vbq_copy_strm(struct videobuf_queue *q, char __user *data,
- size_t count, size_t pos, int vbihack, int nonblocking)
-{
- /* Do nothing */
- return 0;
-}
-
-static int omapvout_vbq_mmap_free(struct videobuf_queue *q)
-{
- /* Do nothing */
- return 0;
-}
-
-static int omapvout_vbq_mmap_mapper(struct videobuf_queue *q,
- struct vm_area_struct *vma)
-{
- struct omapvout_device *vout;
- int rc;
- int idx;
- int cnt;
- u32 offset;
-
- vout = q->priv_data;
- if (!vout)
- return -EINVAL;
-
- cnt = vout->vbq->cnt;
-
- /* look for the buffer to map */
- offset = (vma->vm_pgoff << PAGE_SHIFT);
- for (idx = 0; idx < cnt; idx++) {
- if (q->bufs[idx]->boff == offset)
- break;
- }
-
- if (idx >= cnt) {
- DBG("Invalid offset 0x%lx\n", (unsigned long) offset);
- return -EINVAL;
- }
-
- DBG("omapvout_vbq_mmap %d\n", idx);
-
- vma->vm_ops = &vm_ops;
- vma->vm_private_data = (void *) vout;
-
- rc = omapvout_mem_map(vma, vout->vbq->buf[idx].phy_addr);
- if (rc != 0) {
- DBG("Failed mem_map %d\n", rc);
- return rc;
- }
-
- q->bufs[idx]->baddr = vout->vbq->buf[idx].phy_addr;
-
- return 0;
-}
-
-static struct videobuf_qtype_ops vbq_ops = {
- .magic = MAGIC_QTYPE_OPS,
- .alloc = omapvout_vbq_alloc,
- .vmalloc = omapvout_vbq_vmalloc,
- .iolock = omapvout_vbq_iolock,
- .mmap = omapvout_vbq_mmap_op,
- .sync = omapvout_vbq_sync,
- .video_copy_to_user = omapvout_vbq_copy_user,
- .copy_stream = omapvout_vbq_copy_strm,
- .mmap_free = omapvout_vbq_mmap_free,
- .mmap_mapper = omapvout_vbq_mmap_mapper
-};
-
-/*=== Public Interface Functions =========================================*/
-
-int omapvout_vbq_init(struct omapvout_device *vout)
-{
- struct omapvout_vbq *vbq;
- int rc;
-
- /* It is assumed that the caller has locked the vout mutex */
-
- if (vout->vbq) {
- rc = -EINVAL;
- goto failed;
- }
-
- vout->vbq = kzalloc(sizeof(struct omapvout_vbq), GFP_KERNEL);
- if (vout->vbq == NULL) {
- rc = -ENOMEM;
- goto failed;
- }
-
- vbq = vout->vbq;
-
- vbq->cnt = 0;
- vbq->min_size = 0;
-
- spin_lock_init(&vbq->lock);
- videobuf_queue_core_init(&vout->queue, &vbq_buf_ops, NULL,
- &vbq->lock, V4L2_BUF_TYPE_VIDEO_OUTPUT,
- V4L2_FIELD_NONE, sizeof(struct videobuf_buffer),
- vout, &vbq_ops);
-
- return 0;
-
-failed:
- return rc;
-}
-
-void omapvout_vbq_destroy(struct omapvout_device *vout)
-{
- /* It is assumed that the caller has locked the vout mutex */
-
- if (vout->vbq) {
- omapvout_release_frames(vout);
- kfree(vout->vbq);
- vout->vbq = NULL;
- }
-}
-
-int omapvout_vbq_buf_cnt(struct omapvout_device *vout)
-{
- return vout->vbq->cnt;
-}
-
diff --git a/drivers/media/video/omap-vout/omapvout-vbq.h b/drivers/media/video/omap-vout/omapvout-vbq.h
deleted file mode 100644
index 64fd522..0000000
--- a/drivers/media/video/omap-vout/omapvout-vbq.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-vbq.h
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- * This file contains the code necessary to interface with the
- * vbq (video buffer queue).
- */
-
-#ifndef __OMAPVOUT_VBQ_H__
-#define __OMAPVOUT_VBQ_H__
-
-#include <linux/videodev2.h>
-
-#include "omapvout.h"
-
-struct omapvout_buf {
- u32 size;
- unsigned long phy_addr;
- void *virt_addr;
- bool released;
-};
-
-struct omapvout_vbq {
- spinlock_t lock;
- int cnt; /* number of frames in the queue */
- int min_size; /* smallest frame in the queue */
- struct omapvout_buf buf[VIDEO_MAX_FRAME];
-};
-
-extern int omapvout_vbq_init(struct omapvout_device *vout);
-extern void omapvout_vbq_destroy(struct omapvout_device *vout);
-extern int omapvout_vbq_buf_cnt(struct omapvout_device *vout);
-
-#endif /* __OMAPVOUT_VBQ_H__ */
-
diff --git a/drivers/media/video/omap-vout/omapvout.c b/drivers/media/video/omap-vout/omapvout.c
deleted file mode 100644
index 9b1c38f..0000000
--- a/drivers/media/video/omap-vout/omapvout.c
+++ /dev/null
@@ -1,1232 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout.c
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * 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/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/platform_device.h>
-#include <linux/videodev2.h>
-#include <linux/vmalloc.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-common.h>
-#include <mach/io.h>
-#include <mach/board.h>
-
-#include "omapvout.h"
-#include "omapvout-dss.h"
-#include "omapvout-mem.h"
-#include "omapvout-vbq.h"
-#include "omapvout-bp.h"
-
-#define MODULE_NAME "omapvout"
-
-/* list of image formats supported by OMAP2 video pipelines */
-const static struct v4l2_fmtdesc omap2_formats[] = {
-{
- /* Note: V4L2 defines RGB565 as:
- * Byte 0 Byte 1
- * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
- *
- * We interpret RGB565 as:
- * Byte 0 Byte 1
- * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
- */
- .description = "RGB565, le",
- .pixelformat = V4L2_PIX_FMT_RGB565,
-},
-{
- /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use
- * this for RGB24 unpack mode, the last 8 bits are ignored
- */
- .description = "RGB32, le",
- .pixelformat = V4L2_PIX_FMT_RGB32,
-},
-{
- .description = "YUYV (YUV 4:2:2), packed",
- .pixelformat = V4L2_PIX_FMT_YUYV,
-},
-{
- .description = "UYVY (YUV 4:2:2), packed",
- .pixelformat = V4L2_PIX_FMT_UYVY,
-},
-};
-
-#define NUM_OUTPUT_FORMATS (sizeof(omap2_formats)/sizeof(omap2_formats[0]))
-
-/*=== Local Functions ==================================================*/
-
-static int omapvout_crop_to_size(struct v4l2_rect *rect, int w, int h)
-{
- struct v4l2_rect try;
- int t;
-
- try = *rect;
-
- if (try.left < 0)
- try.left = 0;
- if (try.top < 0)
- try.top = 0;
- if (try.width > w)
- try.width = w;
- if (try.height > h)
- try.height = h;
- t = ((try.left + try.width) - w);
- if (t > 0)
- try.width = w - t;
- t = ((try.top + try.height) - h);
- if (t > 0)
- try.height = h - t;
- try.width &= ~1;
- try.height &= ~1;
-
- if (try.width <= 0 || try.height <= 0)
- return -EINVAL;
-
- *rect = try;
-
- return 0;
-}
-
-static int omapvout_try_pixel_format(struct omapvout_device *vout,
- struct v4l2_pix_format *pix)
-{
- int ifmt;
- int bpp = 0;
-
- if (pix->width > vout->max_video_width)
- pix->width = vout->max_video_width;
-
- if (pix->height > vout->max_video_height)
- pix->height = vout->max_video_height;
-
- for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) {
- if (pix->pixelformat == omap2_formats[ifmt].pixelformat)
- break;
- }
-
- if (ifmt >= NUM_OUTPUT_FORMATS)
- ifmt = 0;
-
- pix->pixelformat = omap2_formats[ifmt].pixelformat;
- pix->field = V4L2_FIELD_NONE;
- pix->priv = 0;
-
- switch (pix->pixelformat) {
- case V4L2_PIX_FMT_RGB565:
- pix->colorspace = V4L2_COLORSPACE_SRGB;
- bpp = 2;
- break;
- case V4L2_PIX_FMT_RGB32:
- pix->colorspace = V4L2_COLORSPACE_SRGB;
- bpp = 4;
- break;
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_UYVY:
- default:
- pix->colorspace = V4L2_COLORSPACE_JPEG;
- bpp = 2;
- break;
- }
-
- pix->bytesperline = pix->width * bpp;
- pix->sizeimage = pix->bytesperline * pix->height;
-
- return 0;
-}
-
-static int omapvout_try_window(struct omapvout_device *vout,
- struct v4l2_window *win)
-{
- int rc = 0;
-
- rc = omapvout_crop_to_size(&win->w, vout->disp_width,
- vout->disp_height);
- if (rc == 0)
- win->field = V4L2_FIELD_NONE;
-
- return rc;
-}
-
-static int omapvout_try_crop(struct omapvout_device *vout,
- struct v4l2_rect *crop)
-{
- return omapvout_crop_to_size(crop, vout->pix.width, vout->pix.height);
-}
-
-/* Make sure the input size, window rectangle, crop rectangle, and rotation
- * parameters together make up a valid configuration for the hardware
- */
-static int omapvout_validate_cfg(struct omapvout_device *vout)
-{
- int rc = 0;
- int win_w, win_h;
- int crp_w, crp_h;
-
- /* Is it assumed:
- * - The rotation value denotes 0, 90, 180, or 270
- * - The input size is valid based on the platform limits
- * - The output rectangle is within the display area
- * - The crop rectangle is within the input frame
- */
-
- /* Validate scaling */
- win_w = vout->win.w.width;
- win_h = vout->win.w.height;
- crp_w = vout->crop.width;
- crp_h = vout->crop.height;
-
- if ( vout->rotation == 0 || vout->rotation == 2 ) {
- win_w = vout->win.w.width;
- win_h = vout->win.w.height;
- } else {
- win_w = vout->win.w.height;
- win_h = vout->win.w.width;
- }
-
- /* Down-scaling */
- if (((win_w < crp_w) && ((win_w * 4) < crp_w)) ||
- ((win_h < crp_w) && ((win_h * 4) < crp_h)))
- rc = -EINVAL;
-
- /* Up-scaling */
- if (((win_w > crp_w) && ((crp_w * 8) < win_w)) ||
- ((win_h > crp_h) && ((crp_h * 8) < win_h)))
- rc = -EINVAL;
-
- return rc;
-}
-
-static void omapvout_free_resources(struct omapvout_device *vout)
-{
- if (vout == NULL)
- return;
-
-#ifdef CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL
- if (vout->bp != NULL)
- omapvout_bp_destroy(vout);
-#endif
-
- video_set_drvdata(&vout->vdev, NULL);
- kfree(vout);
-}
-
-/*=== V4L2 Interface Functions =========================================*/
-
-static int omapvout_open(struct file *file)
-{
- struct omapvout_device *vout;
- u16 w, h;
- int rc;
-
- DBG("omapvout_open\n");
-
- vout = video_drvdata(file);
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- mutex_lock(&vout->mtx);
-
- /* We only support single open */
- if (vout->opened) {
- DBG("Device already opened\n");
- rc = -EBUSY;
- goto failed;
- }
-
- rc = omapvout_dss_open(vout, &w, &h);
- if (rc != 0)
- goto failed;
-
- DBG("Overlay Display %dx%d\n", w, h);
-
- if (w == 0 || h == 0) {
- DBG("Invalid display resolution\n");
- rc = -EINVAL;
- goto failed;
- }
-
- rc = omapvout_vbq_init(vout);
- if (rc != 0)
- goto failed;
-
- vout->disp_width = w;
- vout->disp_height = h;
- vout->opened = 1;
-
- memset(&vout->pix, 0, sizeof(vout->pix));
- vout->pix.width = w;
- vout->pix.height = h;
- vout->pix.field = V4L2_FIELD_NONE;
- vout->pix.pixelformat = V4L2_PIX_FMT_RGB565; /* Arbitrary */
- vout->pix.colorspace = V4L2_COLORSPACE_SRGB; /* Arbitrary */
- vout->pix.bytesperline = w * 2;
- vout->pix.sizeimage = w * h * 2;
-
- memset(&vout->win, 0, sizeof(vout->win));
- vout->win.w.width = w;
- vout->win.w.height = h;
- vout->win.field = V4L2_FIELD_NONE;
-
- memset(&vout->crop, 0, sizeof(vout->crop));
- vout->crop.width = w;
- vout->crop.height = h;
-
- memset(&vout->fbuf, 0, sizeof(vout->fbuf));
-
- vout->rotation = 0;
- vout->bg_color = 0;
-
- vout->mmap_cnt = 0;
-
- mutex_unlock(&vout->mtx);
-
- file->private_data = vout;
-
- return 0;
-
-failed:
- mutex_unlock(&vout->mtx);
- return rc;
-}
-
-static int omapvout_release(struct file *file)
-{
- struct omapvout_device *vout;
-
- DBG("omapvout_release\n");
-
- vout = video_drvdata(file);
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- mutex_lock(&vout->mtx);
-
- if (vout->queue.streaming) {
- omapvout_dss_disable(vout);
- videobuf_streamoff(&vout->queue);
- }
-
- if (vout->mmap_cnt) {
- vout->mmap_cnt = 0;
- DBG("Releasing with non-zero mmap_cnt\n");
- }
-
- omapvout_dss_release(vout);
-
- omapvout_vbq_destroy(vout);
-
- vout->opened = 0;
-
- mutex_unlock(&vout->mtx);
-
- file->private_data = NULL;
-
- return 0;
-}
-
-static int omapvout_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct omapvout_device *vout;
- int rc;
-
- vout = video_drvdata(file);
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- mutex_lock(&vout->mtx);
-
- rc = videobuf_mmap_mapper(&vout->queue, vma);
- if (rc != 0)
- goto failed;
-
- vout->mmap_cnt++;
-
- mutex_unlock(&vout->mtx);
-
- return 0;
-
-failed:
- mutex_unlock(&vout->mtx);
- return rc;
-}
-
-static int omapvout_vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct omapvout_device *vout = priv;
-
- memset(cap, 0, sizeof(*cap));
- strncpy(cap->driver, MODULE_NAME, sizeof(cap->driver));
- strncpy(cap->card, vout->vdev.name, sizeof(cap->card));
- cap->bus_info[0] = '\0';
- cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
-
- return 0;
-}
-
-static int omapvout_vidioc_enum_output(struct file *file, void *priv,
- struct v4l2_output *output)
-{
- int index = output->index;
-
- if (index > 0)
- return -EINVAL;
-
- memset(output, 0, sizeof(*output));
- output->index = index;
-
- strncpy(output->name, "video out", sizeof(output->name));
- output->type = V4L2_OUTPUT_TYPE_MODULATOR;
-
- return 0;
-}
-
-static int omapvout_vidioc_g_output(struct file *file, void *priv,
- unsigned int *i)
-{
- *i = 0;
-
- return 0;
-}
-
-static int omapvout_vidioc_s_output(struct file *file, void *priv,
- unsigned int i)
-{
- if (i > 0)
- return -EINVAL;
-
- return 0;
-}
-
-static int omapvout_vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- int index = f->index;
- enum v4l2_buf_type type = f->type;
-
- if (index >= NUM_OUTPUT_FORMATS)
- return -EINVAL;
-
- memset(f, 0, sizeof(*f));
- f->index = index;
- f->type = type;
- f->flags = omap2_formats[index].flags;
- strncpy(f->description, omap2_formats[index].description,
- sizeof(f->description));
- f->pixelformat = omap2_formats[index].pixelformat;
-
- return 0;
-}
-
-static int omapvout_vidioc_enum_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- /* Same formats as the overlay */
- return omapvout_vidioc_enum_fmt_vid_overlay(file, priv, f);
-}
-
-static int omapvout_vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct omapvout_device *vout = priv;
- struct v4l2_window *win = &f->fmt.win;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- /*
- * The API has a bit of a problem here. We're returning a v4l2_window
- * structure, but that structure contains pointers to variable-sized
- * objects for clipping rectangles and clipping bitmaps. We will just
- * return NULLs for those pointers.
- */
-
- mutex_lock(&vout->mtx);
-
- memset(win, 0, sizeof(*win));
- win->w = vout->win.w;
- win->field = vout->win.field;
- win->chromakey = vout->win.chromakey;
- win->global_alpha = vout->win.global_alpha;
-
- mutex_unlock(&vout->mtx);
-
- return 0;
-}
-
-static int omapvout_vidioc_g_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct omapvout_device *vout = priv;
- struct v4l2_pix_format *pix = &f->fmt.pix;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- mutex_lock(&vout->mtx);
-
- memset(pix, 0, sizeof(*pix));
- *pix = vout->pix;
-
- mutex_unlock(&vout->mtx);
-
- return 0;
-}
-
-static int omapvout_vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct omapvout_device *vout = priv;
- struct v4l2_window *win = &f->fmt.win;
- int rc;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- mutex_lock(&vout->mtx);
-
- rc = omapvout_try_window(vout, win);
-
- mutex_unlock(&vout->mtx);
-
- return rc;
-}
-
-static int omapvout_vidioc_try_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct omapvout_device *vout = priv;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- int rc;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- mutex_lock(&vout->mtx);
-
- rc = omapvout_try_pixel_format(vout, pix);
-
- mutex_unlock(&vout->mtx);
-
- return rc;
-}
-
-static int omapvout_vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct omapvout_device *vout = priv;
- struct v4l2_window *win = &f->fmt.win;
- int rc = 0;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- mutex_lock(&vout->mtx);
-
- if (vout->queue.streaming) {
- rc = -EBUSY;
- goto failed;
- }
-
- rc = omapvout_try_window(vout, win);
- if (rc != 0)
- goto failed;
-
- vout->win.w = win->w;
- vout->win.field = win->field;
- vout->win.chromakey = win->chromakey;
- vout->win.global_alpha = win->global_alpha;
-
- /* Streaming has to be disabled, so config the hardware
- * later when streaming is enabled
- */
-
-failed:
- mutex_unlock(&vout->mtx);
-
- return rc;
-}
-
-static int omapvout_vidioc_s_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct omapvout_device *vout = priv;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- int rc = 0;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- mutex_lock(&vout->mtx);
-
- if (vout->queue.streaming) {
- rc = -EBUSY;
- goto failed;
- }
-
- rc = omapvout_try_pixel_format(vout, pix);
- if (rc != 0)
- goto failed;
-
- memcpy(&vout->pix, pix, sizeof(*pix));
-
- /* Default the cropping rectangle to the input frame size */
- vout->crop.left = 0;
- vout->crop.top = 0;
- vout->crop.width = vout->pix.width;
- vout->crop.height = vout->pix.height;
-
- /* Streaming has to be disabled, so config the hardware
- * later when streaming is enabled
- */
-
-failed:
- mutex_unlock(&vout->mtx);
-
- return rc;
-}
-
-static int omapvout_vidioc_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *ccap)
-{
- struct omapvout_device *vout = priv;
- enum v4l2_buf_type type = ccap->type;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
- return -EINVAL;
-
- mutex_lock(&vout->mtx);
-
- memset(ccap, 0, sizeof(*ccap));
- ccap->type = type;
- ccap->bounds.width = vout->pix.width & ~1;
- ccap->bounds.height = vout->pix.height & ~1;
- ccap->defrect.left = 0;
- ccap->defrect.top = 0;
- ccap->defrect.width = ccap->bounds.width;
- ccap->defrect.left = ccap->bounds.height;
- ccap->pixelaspect.numerator = 1;
- ccap->pixelaspect.denominator = 1;
-
- mutex_unlock(&vout->mtx);
-
- return 0;
-}
-
-static int omapvout_vidioc_g_crop(struct file *file, void *priv,
- struct v4l2_crop *crop)
-{
- struct omapvout_device *vout = priv;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
- return -EINVAL;
-
- mutex_lock(&vout->mtx);
-
- crop->c = vout->crop;
-
- mutex_unlock(&vout->mtx);
-
- return 0;
-}
-
-static int omapvout_vidioc_s_crop(struct file *file, void *priv,
- struct v4l2_crop *crop)
-{
- struct omapvout_device *vout = priv;
- struct v4l2_rect rect = crop->c;
- int rc = 0;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
- return -EINVAL;
-
- mutex_lock(&vout->mtx);
-
- if (vout->queue.streaming) {
- rc = -EBUSY;
- goto failed;
- }
-
- rc = omapvout_try_crop(vout, &rect);
- if (rc != 0)
- goto failed;
-
- vout->crop = rect;
-
- /* Streaming has to be disabled, so config the hardware
- * later when streaming is enabled
- */
-
-failed:
- mutex_unlock(&vout->mtx);
-
- return rc;
-}
-
-static int omapvout_vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *req)
-{
- struct omapvout_device *vout = priv;
- int rc = 0;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- /* A limitation of this implementation */
- if (req->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (req->count == 0) {
- videobuf_queue_cancel(&vout->queue);
- return 0;
- }
-
- mutex_lock(&vout->mtx);
-
- /* Don't allow new buffers when some are still mapped */
- if (vout->mmap_cnt) {
- DBG("Buffers are still mapped\n");
- rc = -EBUSY;
- goto failed;
- }
-
- INIT_LIST_HEAD(&vout->q_list);
-
- videobuf_reqbufs(&vout->queue, req);
-
- mutex_unlock(&vout->mtx);
-
- return 0;
-
-failed:
- mutex_unlock(&vout->mtx);
- return rc;
-}
-
-static int omapvout_vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- struct omapvout_device *vout = priv;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- return videobuf_querybuf(&vout->queue, b);
-}
-
-static int omapvout_vidioc_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- struct omapvout_device *vout = priv;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- DBG("Q'ing Frame %d\n", b->index);
-
- return videobuf_qbuf(&vout->queue, b);
-}
-
-static int omapvout_vidioc_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- struct omapvout_device *vout = priv;
- int block = 0;
- int rc;
-
- if (file->f_flags & O_NONBLOCK)
- block = 1;
-
- rc = videobuf_dqbuf(&vout->queue, b, block);
-
- DBG("DQ'ing Frame %d\n", b->index);
-
- return rc;
-}
-
-static int omapvout_vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct omapvout_device *vout = priv;
- int rc;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- mutex_lock(&vout->mtx);
-
- /* Not sure how else to do this. We can't truly validate the
- * configuration until all of the pieces have been provided, like
- * input, output, crop sizes and rotation. This is the only point
- * where we can be sure the client has provided all the data, thus
- * the only place to make sure we don't cause a DSS failure.
- */
- rc = omapvout_validate_cfg(vout);
- if (rc) {
- DBG("Configuration Validation Failed\n");
- goto failed;
- }
-
- rc = omapvout_dss_enable(vout);
- if (rc) {
- DBG("DSS Enable Failed\n");
- goto failed;
- }
-
- rc = videobuf_streamon(&vout->queue);
- if (rc)
- omapvout_dss_disable(vout);
-
-failed:
- mutex_unlock(&vout->mtx);
-
- return rc;
-}
-
-static int omapvout_vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct omapvout_device *vout = priv;
- int rc = 0;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- mutex_lock(&vout->mtx);
-
- omapvout_dss_disable(vout);
-
- rc = videobuf_streamoff(&vout->queue);
-
- mutex_unlock(&vout->mtx);
-
- return rc;
-}
-
-static int omapvout_vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qctrl)
-{
- switch (qctrl->id) {
- case V4L2_CID_ROTATE:
- v4l2_ctrl_query_fill(qctrl, 0, 270, 90, 0);
- break;
- case V4L2_CID_BG_COLOR:
- v4l2_ctrl_query_fill(qctrl, 0, 0xFFFFFF, 1, 0);
- break;
- default:
- qctrl->name[0] = '\0';
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int omapvout_vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct omapvout_device *vout = priv;
- int rc = 0;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- mutex_lock(&vout->mtx);
-
- switch (ctrl->id) {
- case V4L2_CID_ROTATE:
- ctrl->value = vout->rotation * 90;
- break;
- case V4L2_CID_BG_COLOR:
- ctrl->value = vout->bg_color;
- break;
- default:
- rc = -EINVAL;
- break;
- }
-
- mutex_unlock(&vout->mtx);
-
- return rc;
-}
-
-static int omapvout_vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct omapvout_device *vout = priv;
- int v = ctrl->value;
- int rc = 0;
-
- if (vout == NULL) {
- DBG("Invalid device\n");
- return -ENODEV;
- }
-
- mutex_lock(&vout->mtx);
-
- if (vout->queue.streaming) {
- rc = -EBUSY;
- goto failed;
- }
-
- switch (ctrl->id) {
- case V4L2_CID_ROTATE:
- if (!omapvout_dss_is_rotation_supported(vout) && v != 0) {
- rc = -EINVAL;
- } else if (v == 0 || v == 90 || v == 180 || v == 270) {
- vout->rotation = v / 90;
- } else {
- DBG("Invalid rotation %d\n", v);
- rc = -ERANGE;
- }
- break;
- case V4L2_CID_BG_COLOR:
- if (v < 0 || v > 0xFFFFFF) {
- DBG("Invalid BG color 0x%08lx\n", (unsigned long) v);
- rc = -ERANGE;
- } else {
- vout->bg_color = v;
- }
- break;
- default:
- rc = -EINVAL;
- break;
- }
-
- /* Streaming has to be disabled, so config the hardware
- * later when streaming is enabled
- */
-
-failed:
- mutex_unlock(&vout->mtx);
-
- return rc;
-}
-
-static int omapvout_vidioc_g_fbuf(struct file *file, void *priv,
- struct v4l2_framebuffer *a)
-{
- struct omapvout_device *vout = priv;
-
- mutex_lock(&vout->mtx);
-
- if (vout->dss->overlay->id == OMAP_DSS_VIDEO1) {
- a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
- V4L2_FBUF_CAP_GLOBAL_ALPHA |
- V4L2_FBUF_CAP_CHROMAKEY |
- V4L2_FBUF_CAP_SRC_CHROMAKEY;
- } else {
- a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
- V4L2_FBUF_CAP_LOCAL_ALPHA |
- V4L2_FBUF_CAP_GLOBAL_ALPHA |
- V4L2_FBUF_CAP_CHROMAKEY |
- V4L2_FBUF_CAP_SRC_CHROMAKEY;
- }
- a->flags = vout->fbuf.flags;
- memset(&a->fmt, 0, sizeof(a->fmt));
-
- mutex_unlock(&vout->mtx);
-
- return 0;
-}
-
-static int omapvout_vidioc_s_fbuf(struct file *file, void *priv,
- struct v4l2_framebuffer *a)
-{
- struct omapvout_device *vout = priv;
- int rc = 0;
-
- /* OMAP DSS doesn't support SRC & DST colorkey together */
- if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
- (a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY))
- return -EINVAL;
-
- /* OMAP DSS doesn't support DST colorkey and alpha blending together */
- if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
- (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA))
- return -EINVAL;
-
- mutex_lock(&vout->mtx);
-
- /* OMAP DSS doesn't support local alpha for video 1 */
- if ((vout->dss->overlay->id == OMAP_DSS_VIDEO1) &&
- (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA)) {
- rc = -EINVAL;
- goto failed;
- }
-
- vout->fbuf.flags = a->flags;
-
-failed:
- mutex_unlock(&vout->mtx);
-
- return 0;
-}
-
-/*=== Driver Functions =================================================*/
-
-static struct v4l2_file_operations omapvout_fops = {
- .owner = THIS_MODULE,
- .open = omapvout_open,
- .release = omapvout_release,
- .mmap = omapvout_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops omapvout_ioctl_ops = {
- .vidioc_querycap = omapvout_vidioc_querycap,
- .vidioc_enum_output = omapvout_vidioc_enum_output,
- .vidioc_g_output = omapvout_vidioc_g_output,
- .vidioc_s_output = omapvout_vidioc_s_output,
- .vidioc_enum_fmt_vid_overlay = omapvout_vidioc_enum_fmt_vid_overlay,
- .vidioc_enum_fmt_vid_out = omapvout_vidioc_enum_fmt_vid_out,
- .vidioc_g_fmt_vid_overlay = omapvout_vidioc_g_fmt_vid_overlay,
- .vidioc_g_fmt_vid_out = omapvout_vidioc_g_fmt_vid_out,
- .vidioc_try_fmt_vid_overlay = omapvout_vidioc_try_fmt_vid_overlay,
- .vidioc_try_fmt_vid_out = omapvout_vidioc_try_fmt_vid_out,
- .vidioc_s_fmt_vid_overlay = omapvout_vidioc_s_fmt_vid_overlay,
- .vidioc_s_fmt_vid_out = omapvout_vidioc_s_fmt_vid_out,
- .vidioc_cropcap = omapvout_vidioc_cropcap,
- .vidioc_g_crop = omapvout_vidioc_g_crop,
- .vidioc_s_crop = omapvout_vidioc_s_crop,
- .vidioc_reqbufs = omapvout_vidioc_reqbufs,
- .vidioc_querybuf = omapvout_vidioc_querybuf,
- .vidioc_qbuf = omapvout_vidioc_qbuf,
- .vidioc_dqbuf = omapvout_vidioc_dqbuf,
- .vidioc_streamon = omapvout_vidioc_streamon,
- .vidioc_streamoff = omapvout_vidioc_streamoff,
- .vidioc_queryctrl = omapvout_vidioc_queryctrl,
- .vidioc_g_ctrl = omapvout_vidioc_g_ctrl,
- .vidioc_s_ctrl = omapvout_vidioc_s_ctrl,
- .vidioc_g_fbuf = omapvout_vidioc_g_fbuf,
- .vidioc_s_fbuf = omapvout_vidioc_s_fbuf,
-};
-
-static struct video_device omapvout_devdata = {
- .name = MODULE_NAME,
- .fops = &omapvout_fops,
- .ioctl_ops = &omapvout_ioctl_ops,
- .vfl_type = VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY,
- .release = video_device_release,
- .minor = -1,
-};
-
-static int __init omapvout_probe_device(struct omap_vout_config *cfg,
- struct omapvout_bp *bp,
- enum omap_plane plane, int vid)
-{
- struct omapvout_device *vout = NULL;
- int rc = 0;
-
- DBG("omapvout_probe_device %d %d\n", plane, vid);
-
- vout = kzalloc(sizeof(struct omapvout_device), GFP_KERNEL);
- if (vout == NULL) {
- rc = -ENOMEM;
- goto err0;
- }
-
- mutex_init(&vout->mtx);
-
- vout->max_video_width = cfg->max_width;
- vout->max_video_height = cfg->max_height;
- vout->max_video_buffer_size = cfg->max_buffer_size;
-
- rc = omapvout_dss_init(vout, plane);
- if (rc != 0) {
- printk(KERN_INFO "DSS init failed\n");
- kfree(vout);
- goto err0;
- }
-
-#ifdef CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL
- vout->bp = bp;
- omapvout_bp_init(vout);
-#endif
-
- /* register the V4L2 interface */
- vout->vdev = omapvout_devdata;
- video_set_drvdata(&vout->vdev, vout);
- if (video_register_device(&vout->vdev, VFL_TYPE_GRABBER, vid) < 0) {
- printk(KERN_ERR MODULE_NAME": could not register with V4L2\n");
- rc = -EINVAL;
- goto cleanup;
- }
-
- vout->id = plane;
-
- return 0;
-
-cleanup:
- omapvout_free_resources(vout);
-err0:
- return rc;
-}
-
-/* Some reasonable defaults if the platform does not supply a config */
-static struct omap_vout_config default_cfg = {
- .max_width = 864,
- .max_height = 648,
- .max_buffer_size = 0x112000, /* (w * h * 2) page aligned */
- .num_buffers = 6,
- .num_devices = 2,
- .device_ids = {1, 2},
-};
-
-static int __init omapvout_probe(struct platform_device *pdev)
-{
- struct omapvout_bp *bp = NULL;
- struct omap_vout_config *cfg;
- int i;
- int rc = 0;
- static const enum omap_plane planes[] = {
- OMAP_DSS_VIDEO1,
- OMAP_DSS_VIDEO2,
- };
-
- if (pdev->dev.platform_data) {
- cfg = pdev->dev.platform_data;
- } else {
- DBG("omapvout_probe - using default configuration\n");
- cfg = &default_cfg;
- }
-
- if (cfg->max_width > 2048) /* Hardware limitation */
- cfg->max_width = 2048;
- if (cfg->max_height > 2048) /* Hardware limitation */
- cfg->max_height = 2048;
- if (cfg->num_buffers > 16) /* Arbitrary limitation */
- cfg->num_buffers = 16;
- if (cfg->num_devices > 2) /* Hardware limitation */
- cfg->num_devices = 2;
- for (i = 0; i < cfg->num_devices; i++)
- if (cfg->device_ids[i] > 64)
- cfg->device_ids[i] = -1;
-
-#ifdef CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL
- bp = omapvout_bp_create(cfg->num_buffers, cfg->max_buffer_size);
-#endif
-
- for (i = 0; i < cfg->num_devices; i++) {
- rc = omapvout_probe_device(cfg, bp, planes[i],
- cfg->device_ids[i]);
- if (rc) {
- DBG("omapvout_probe %d failed\n", (i + 1));
- return rc;
- }
- }
-
- return 0;
-}
-
-static int omapvout_remove(struct platform_device *pdev)
-{
- struct omapvout_device *vout = platform_get_drvdata(pdev);
-
- DBG("omapvout_remove\n");
-
- omapvout_dss_remove(vout);
- omapvout_free_resources(vout);
-
- return 0;
-}
-
-static struct platform_driver omapvout_driver = {
- .remove = omapvout_remove,
- .driver = {
- .name = MODULE_NAME,
- },
-};
-
-static int __init omapvout_init(void)
-{
- int rc;
-
- DBG("omapvout_init\n");
-
- rc = platform_driver_probe(&omapvout_driver, omapvout_probe);
- if (rc != 0) {
- printk(KERN_ERR "failed omapvout register/probe %d\n", rc);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void __exit omapvout_exit(void)
-{
- DBG("omapvout_exit\n");
- platform_driver_unregister(&omapvout_driver);
-}
-
-module_init(omapvout_init);
-module_exit(omapvout_exit);
-
-MODULE_AUTHOR("Motorola");
-MODULE_DESCRIPTION("OMAP2/3 Video Out for V4L2");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/video/omap-vout/omapvout.h b/drivers/media/video/omap-vout/omapvout.h
deleted file mode 100644
index d8a376a..0000000
--- a/drivers/media/video/omap-vout/omapvout.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout.h
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * 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 __OMAPVOUT_H__
-#define __OMAPVOUT_H__
-
-#include <linux/mutex.h>
-#include <linux/videodev2.h>
-#include <linux/wait.h>
-#include <mach/display.h>
-#include <mach/vrfb.h>
-#include <media/v4l2-dev.h>
-#include <media/videobuf-core.h>
-
-/*#define DEBUG*/
-#ifdef DEBUG
-#define DBG(format, ...) \
- printk(KERN_DEBUG "OMAPVOUT: " format, ## __VA_ARGS__)
-#else
-#define DBG(format, ...)
-#endif
-
-/* The device structure */
-
-struct omapvout_device {
- struct video_device vdev;
- struct mutex mtx; /* Lock for all device accesses */
- struct video_device *vfd;
-
- int opened;
- int id;
-
- int disp_width;
- int disp_height;
-
- int max_video_width;
- int max_video_height;
- int max_video_buffer_size;
-
- /* Buffer pool */
- struct omapvout_bp *bp;
-
- /* DSS data */
- struct omapvout_dss *dss;
-
- /* V4L2 data */
- int rotation;
- int bg_color;
- struct v4l2_pix_format pix;
- struct v4l2_window win;
- struct v4l2_rect crop;
- struct v4l2_framebuffer fbuf;
-
- /* Frame Q */
- struct videobuf_queue queue;
- struct omapvout_vbq *vbq;
- struct list_head q_list;
-
- /* Don't allow new buffers when some are still mapped */
- int mmap_cnt;
-};
-
-#define vdev_to_omapvout(d) container_of(d, struct omapvout_device, vdev)
-
-#endif /* __OMAPVOUT_H__ */
diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig
new file mode 100644
index 0000000..7687ee9
--- /dev/null
+++ b/drivers/media/video/omap/Kconfig
@@ -0,0 +1,27 @@
+config VIDEO_OMAP_VIDEOLIB
+ tristate "OMAP Video out library"
+ depends on VIDEO_OMAP3_V4L2
+ default VIDEO_OMAP3_V4L2
+
+config VIDEO_OMAP_VIDEOOUT
+ tristate "OMAP Video out driver"
+ select VIDEOBUF_DMA_SG
+ select VIDEOBUF_GEN
+ depends on VIDEO_OMAP3_V4L2
+ default VIDEO_OMAP3_V4L2
+
+choice
+ prompt "TV Mode"
+ default NTSC_M
+
+config NTSC_M
+ bool "Use NTSC_M mode"
+ help
+ Select this option if you want NTSC_M mode on TV
+
+config PAL_BDGHI
+ bool "Use PAL_BDGHI mode"
+ help
+ Select this option if you want PAL_BDGHI mode on TV
+
+endchoice
diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile
new file mode 100644
index 0000000..75e01d3
--- /dev/null
+++ b/drivers/media/video/omap/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_VIDEO_OMAP_VIDEOLIB) += omap_voutlib.o
+obj-$(CONFIG_VIDEO_OMAP_VIDEOOUT) += omap_vout.o
+
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
new file mode 100644
index 0000000..156a6e4
--- /dev/null
+++ b/drivers/media/video/omap/omap_vout.c
@@ -0,0 +1,2922 @@
+/*
+ * drivers/media/video/omap/omap_vout.c
+ *
+ * Copyright (C) 2005-2009 Texas Instruments.
+ *
+ * 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.
+ *
+ * Leveraged code from the OMAP2 camera driver
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP24xx camera controller.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * History:
+ * 20-APR-2006 Khasim Modified VRFB based Rotation,
+ * The image data is always read from 0 degree
+ * view and written
+ * to the virtual space of desired rotation angle
+ * 4-DEC-2006 Jian Changed to support better memory management
+ *
+ * 17-Nov-2008 Hardik Changed to used the new DSS paches by Tomi
+ * Changed driver to use video_ioctl2
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/videodev2.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <media/videobuf-dma-sg.h>
+#include <linux/input.h>
+#include <linux/dma-mapping.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <mach/display.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/semaphore.h>
+#include <linux/omap_resizer.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+#include <mach/dma.h>
+#include <mach/vrfb.h>
+#include <media/v4l2-common.h>
+#include <mach/display.h>
+#include "omap_voutlib.h"
+#include "omap_voutdef.h"
+
+#define OMAP_VIDEO1 0
+#define OMAP_VIDEO2 1
+
+/* configuration macros */
+#define VOUT_NAME "omap_vout"
+
+#define QQVGA_WIDTH 160
+#define QQVGA_HEIGHT 120
+
+#define NUM_OF_VIDEO_CHANNELS 2
+
+#define VID_MAX_WIDTH 1280 /* Largest width */
+#define VID_MAX_HEIGHT 864 /* Largest height */
+#define VID_720P_HEIGHT 720 /* 720p height */
+
+/* Mimimum requirement is 2x2 for DSS */
+#define VID_MIN_WIDTH 2
+#define VID_MIN_HEIGHT 2
+
+/* 2048 x 2048 is max res supported by OMAP display controller */
+#define DMA_CHAN_ALLOTED 1
+#define DMA_CHAN_NOT_ALLOTED 0
+#define MAX_PIXELS_PER_LINE 2048
+#define VRFB_TX_TIMEOUT 1000
+
+#define VDD1_OPP3_FREQ 500000000
+#define VDD1_OPP1_FREQ 125000000
+
+#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_720P_HEIGHT*2)
+
+/* IRQ Bits mask of DSS */
+#define OMAP_VOUT_IRQ_MASK (DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | \
+ DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_FRAMEDONE)
+
+int cacheable_buffers;
+int flushable_buffers;
+
+/* ISP resizer related code*/
+enum {
+ VIDEO_720_ENABLE = 1,
+ VIDEO_720_RESIZER_N_STREAMING,
+ VIDEO_720_DISABLE,
+};
+
+static int flg_720 = VIDEO_720_DISABLE;
+
+struct rsz_params isp_rsz_params;
+int rsz_configured;
+
+static u16 omap_vout_rsz_filter_4_tap_high_quality[] = {
+ 0x0000, 0x0100, 0x0000, 0x0000,
+ 0x03FA, 0x00F6, 0x0010, 0x0000,
+ 0x03F9, 0x00DB, 0x002C, 0x0000,
+ 0x03FB, 0x00B3, 0x0053, 0x03FF,
+ 0x03FD, 0x0082, 0x0084, 0x03FD,
+ 0x03FF, 0x0053, 0x00B3, 0x03FB,
+ 0x0000, 0x002C, 0x00DB, 0x03F9,
+ 0x0000, 0x0010, 0x00F6, 0x03FA
+};
+
+static u16 omap_vout_rsz_filter_7_tap_high_quality[] = {
+ 0x0004, 0x0023, 0x005A, 0x0058,
+ 0x0023, 0x0004, 0x0000, 0x0000,
+ 0x0002, 0x0018, 0x004d, 0x0060,
+ 0x0031, 0x0008, 0x0000, 0x0000,
+ 0x0001, 0x000f, 0x003f, 0x0062,
+ 0x003f, 0x000f, 0x0001, 0x0000,
+ 0x0000, 0x0008, 0x0031, 0x0060,
+ 0x004d, 0x0018, 0x0002, 0x0000
+};
+
+/* End ISP resizer*/
+
+static struct videobuf_queue_ops video_vbq_ops;
+
+static u32 video1_numbuffers = OMAP_VOUT_MAX_BUFFERS;
+static u32 video2_numbuffers = OMAP_VOUT_MAX_BUFFERS;
+static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
+static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
+static u32 vid1_static_vrfb_alloc;
+static u32 vid2_static_vrfb_alloc;
+static int debug;
+struct vout_platform_data *pdata;
+
+/* Module parameters */
+module_param(video1_numbuffers, uint, S_IRUGO);
+MODULE_PARM_DESC(video1_numbuffers, "Number of buffers to be allocated at \
+ init time for Video1 device.");
+
+module_param(video2_numbuffers, uint, S_IRUGO);
+MODULE_PARM_DESC(video2_numbuffers, "Number of buffers to be allocated at \
+ init time for Video2 device.");
+
+module_param(video1_bufsize, uint, S_IRUGO);
+MODULE_PARM_DESC(video1_bufsize, "Size of the buffer to be allocated for \
+ video1 device");
+
+module_param(video2_bufsize, uint, S_IRUGO);
+MODULE_PARM_DESC(video2_bufsize, "Size of the buffer to be allocated for \
+ video2 device");
+
+module_param(vid1_static_vrfb_alloc, bool, S_IRUGO);
+MODULE_PARM_DESC(vid1_static_vrfb_alloc, "Static allocation of the VRFB \
+ buffer for video1 device");
+
+module_param(vid2_static_vrfb_alloc, bool, S_IRUGO);
+MODULE_PARM_DESC(vid2_static_vrfb_alloc, "Static allocation of the VRFB \
+ buffer for video2 device");
+
+module_param(debug, bool, S_IRUGO);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/* Local Helper functions */
+static int omap_vout_create_video_devices(struct platform_device *pdev);
+static int omapvid_apply_changes(struct omap_vout_device *vout);
+static int omapvid_init(struct omap_vout_device *vout, u32 addr);
+static int omapvid_setup_overlay(struct omap_vout_device *vout,
+ struct omap_overlay *ovl, int posx, int posy,
+ int outw, int outh, u32 addr);
+static enum omap_color_mode video_mode_to_dss_mode(struct omap_vout_device
+ *vout);
+static void omap_vout_isr(void *arg, unsigned int irqstatus);
+static void omap_vout_cleanup_device(struct omap_vout_device *vout);
+
+/*
+ * Maximum amount of memory to use for rendering buffers.
+ * Default is enough to four (RGB24) DVI 720P buffers.
+ */
+#define MAX_ALLOWED_VIDBUFFERS 6
+
+/* list of image formats supported by OMAP2 video pipelines */
+const static struct v4l2_fmtdesc omap_formats[] = {
+ {
+ /* Note: V4L2 defines RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
+ *
+ * We interpret RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
+ */
+ .description = "RGB565, le",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ },
+ {
+ /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use
+ * this for RGB24 unpack mode, the last 8 bits are ignored
+ * */
+ .description = "RGB32, le",
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ },
+ {
+ /* Note: V4L2 defines RGB24 as: RGB-8-8-8 we use
+ * this for RGB24 packed mode
+ *
+ */
+ .description = "RGB24, le",
+ .pixelformat = V4L2_PIX_FMT_RGB24,
+ },
+ {
+ .description = "YUYV (YUV 4:2:2), packed",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .description = "UYVY, packed",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+};
+
+#define NUM_OUTPUT_FORMATS (sizeof(omap_formats)/sizeof(omap_formats[0]))
+
+/* Allocate buffers */
+static unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
+{
+ unsigned long virt_addr, addr;
+ u32 size;
+
+ size = PAGE_ALIGN(buf_size);
+ virt_addr = (u32) alloc_pages_exact(size, GFP_KERNEL | GFP_DMA);
+ addr = virt_addr;
+ if (virt_addr) {
+ while (size > 0) {
+ SetPageReserved(virt_to_page(addr));
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ }
+ *phys_addr = (u32) virt_to_phys((void *) virt_addr);
+ return virt_addr;
+}
+
+/* Free buffers */
+static void omap_vout_free_buffer(unsigned long virtaddr, u32 phys_addr,
+ u32 buf_size)
+{
+ unsigned long addr = virtaddr;
+ u32 size;
+
+ size = PAGE_ALIGN(buf_size);
+ while (size > 0) {
+ ClearPageReserved(virt_to_page(addr));
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ free_pages_exact((void *) virtaddr, size);
+}
+
+/* Function for allocating video buffers */
+static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout,
+ int count)
+{
+ int i, j;
+
+ for (i = 0; i < count; i++) {
+ if (!vout->smsshado_virt_addr[i]) {
+ vout->smsshado_virt_addr[i] =
+ omap_vout_alloc_buffer(vout->smsshado_size,
+ &vout->smsshado_phy_addr[i]);
+ }
+ if (!vout->smsshado_virt_addr[i]) {
+ for (j = 0; j < i; j++) {
+ omap_vout_free_buffer(
+ vout->smsshado_virt_addr[j],
+ vout->smsshado_phy_addr[j],
+ vout->smsshado_size);
+ vout->smsshado_virt_addr[j] = 0;
+ vout->smsshado_phy_addr[j] = 0;
+ }
+ count = 0;
+ return -ENOMEM;
+ }
+ memset((void *) vout->smsshado_virt_addr[i], 0,
+ vout->smsshado_size);
+ }
+ return 0;
+}
+
+/* Try format */
+static int omap_vout_try_format(struct v4l2_pix_format *pix,
+ struct v4l2_pix_format *def_pix)
+{
+ int ifmt, bpp = 0;
+
+ if (pix->width > VID_MAX_WIDTH)
+ pix->width = VID_MAX_WIDTH;
+ if (pix->height > VID_MAX_HEIGHT)
+ pix->height = VID_MAX_HEIGHT;
+
+ if (pix->width <= VID_MIN_WIDTH)
+ pix->width = def_pix->width;
+ if (pix->height <= VID_MIN_HEIGHT)
+ pix->height = def_pix->height;
+
+ for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) {
+ if (pix->pixelformat == omap_formats[ifmt].pixelformat)
+ break;
+ }
+
+ if (ifmt == NUM_OUTPUT_FORMATS)
+ ifmt = 0;
+
+ pix->pixelformat = omap_formats[ifmt].pixelformat;
+ pix->field = V4L2_FIELD_ANY;
+ pix->priv = 0;
+
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ default:
+ pix->colorspace = V4L2_COLORSPACE_JPEG;
+ bpp = YUYV_BPP;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB565X:
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ bpp = RGB565_BPP;
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ bpp = RGB24_BPP;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_BGR32:
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ bpp = RGB32_BPP;
+ break;
+ }
+ pix->bytesperline = pix->width * bpp;
+ pix->sizeimage = pix->bytesperline * pix->height;
+ return bpp;
+}
+
+/*
+ * omap_vout_uservirt_to_phys: This inline function is used to convert user
+ * space virtual address to physical address.
+ */
+static inline u32 omap_vout_uservirt_to_phys(u32 virtp)
+{
+ unsigned long physp = 0;
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+
+ vma = find_vma(mm, virtp);
+ /* For kernel direct-mapped memory, take the easy way */
+ if (virtp >= PAGE_OFFSET) {
+ physp = virt_to_phys((void *) virtp);
+ } else if ((vma) && (vma->vm_flags & VM_IO)
+ && (vma->vm_pgoff)) {
+ /* this will catch, kernel-allocated,
+ mmaped-to-usermode addresses */
+ physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
+ } else {
+ /* otherwise, use get_user_pages() for general userland pages */
+ int res, nr_pages = 1;
+ struct page *pages;
+ down_read(¤t->mm->mmap_sem);
+
+ res = get_user_pages(current, current->mm, virtp, nr_pages,
+ 1, 0, &pages, NULL);
+ up_read(¤t->mm->mmap_sem);
+
+ if (res == nr_pages) {
+ physp = __pa(page_address(&pages[0]) +
+ (virtp & ~PAGE_MASK));
+ } else {
+ printk(KERN_WARNING VOUT_NAME
+ "omap_vout_uservirt_to_phys:\
+ get_user_pages failed\n");
+ return 0;
+ }
+ }
+
+ return physp;
+}
+
+/* This function wakes up the application once
+ * the DMA transfer to VRFB space is completed by the
+ * ISP resizer block
+ */
+void omap_vout_isp_rsz_dma_tx_callback(void *arg)
+{
+ struct omap_vout_device *vout;
+ vout = (struct omap_vout_device *) arg;
+
+ vout->vrfb_dma_tx.tx_status = 1;
+ wake_up_interruptible(&vout->vrfb_dma_tx.wait);
+}
+
+/* This functions wakes up the application once
+ * the DMA transfer to VRFB space is completed. */
+static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data)
+{
+ struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data;
+
+ t->tx_status = 1;
+ wake_up_interruptible(&t->wait);
+}
+
+/* Release the VRFB context once the module exits */
+static void omap_vout_release_vrfb(struct omap_vout_device *vout)
+{
+ int i;
+
+ for (i = 0; i < OMAP_VOUT_MAX_VBUF_CTXT; i++)
+ omap_vrfb_release_ctx(&vout->vrfb_context[i]);
+
+ if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) {
+ vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+ omap_free_dma(vout->vrfb_dma_tx.dma_ch);
+ }
+
+}
+
+/* Return true if rotation is 90 or 270 */
+static inline int rotate_90_or_270(int rotation)
+{
+ return rotation == 1 || rotation == 3;
+}
+
+/* Return true if rotation is enabled */
+static inline int rotation_enabled(int rotation)
+{
+ return rotation != -1;
+}
+
+/* Reverse the rotation degree if mirroring is enabled */
+static inline int rotation_with_mirror(int rotation)
+{
+ return (rotation == 1) ? 3 :
+ (rotation == 3) ? 1 :
+ (rotation == 2) ? 0 : 2;
+}
+
+/* Free the V4L2 buffers */
+static void omap_vout_free_buffers(struct omap_vout_device *vout)
+{
+ int i, numbuffers;
+
+ /* Allocate memory for the buffes */
+ numbuffers = (vout->vid) ? video2_numbuffers : video1_numbuffers;
+ vout->buffer_size = (vout->vid) ? video2_bufsize : video1_bufsize;
+
+ for (i = 0; i < numbuffers; i++) {
+ omap_vout_free_buffer(vout->buf_virt_addr[i],
+ vout->buf_phy_addr[i], vout->buffer_size);
+ vout->buf_phy_addr[i] = 0;
+ vout->buf_virt_addr[i] = 0;
+ }
+}
+
+/* Free VRFB buffers */
+static void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
+{
+ int j;
+
+ for (j = 0; j < OMAP_VOUT_MAX_BUFFERS; j++) {
+ omap_vout_free_buffer(vout->smsshado_virt_addr[j],
+ vout->smsshado_phy_addr[j],
+ vout->smsshado_size);
+ vout->smsshado_virt_addr[j] = 0;
+ vout->smsshado_phy_addr[j] = 0;
+ }
+}
+
+/* Allocate the buffers for the VRFB space. Data is copied from V4L2
+ * buffers to the VRFB buffers using the DMA engine.*/
+static int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+ unsigned int *count, unsigned int startindex)
+{
+ int i, j;
+ int buffer_set;
+ u32 width, height;
+
+ /* Allocate the VRFB buffers only if the buffers are not
+ * allocated during init time.
+ */
+ if ((rotation_enabled(vout->rotation)) &&
+ !vout->vrfb_static_allocation) {
+ for (i = 0; i < *count; i++) {
+ buffer_set = vout->smsshado_virt_addr[i];
+ if (!buffer_set) {
+ vout->smsshado_virt_addr[i] =
+ omap_vout_alloc_buffer(
+ vout->smsshado_size,
+ &vout->smsshado_phy_addr[i]);
+ }
+ if (!vout->smsshado_virt_addr[i]) {
+ if (V4L2_MEMORY_MMAP == vout->memory
+ && i >= startindex)
+ break;
+ for (j = 0; j < i; j++) {
+ omap_vout_free_buffer(
+ vout->smsshado_virt_addr[j],
+ vout->smsshado_phy_addr[j],
+ vout->smsshado_size);
+ vout->smsshado_virt_addr[j] = 0;
+ vout->smsshado_phy_addr[j] = 0;
+ }
+ *count = 0;
+ return -ENOMEM;
+ }
+ if (!buffer_set) {
+ memset((void *) vout->smsshado_virt_addr[i], 0,
+ vout->smsshado_size);
+ }
+ }
+ }
+ for (i = 0; i < *count; i++) {
+ if (flg_720 == VIDEO_720_ENABLE) {
+ width = vout->win.w.width;
+ height = vout->win.w.height;
+ } else {
+ width = vout->pix.width;
+ height = vout->pix.height;
+ }
+ omap_vrfb_setup(&vout->vrfb_context[i],
+ vout->smsshado_phy_addr[i],
+ width, height,
+ vout->dss_mode,
+ vout->rotation);
+ }
+ return 0;
+}
+
+/* Convert V4L2 rotation to DSS rotation
+ * V4L2 understand 0, 90, 180, 270.
+ * convert to 0, 1, 2 and 3 repsectively for DSS */
+static int v4l2_rot_to_dss_rot(int v4l2_rotation, int *dss_rotation,
+ int mirror)
+{
+ switch (v4l2_rotation) {
+ case 90:
+ *dss_rotation = 3;
+ return 0;
+ case 180:
+ *dss_rotation = 2;
+ return 0;
+ case 270:
+ *dss_rotation = 1;
+ return 0;
+ case 0:
+ *dss_rotation = 0;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+}
+
+/* Calculate the buffer offsets from which the streaming should
+ * start. This offset calculation is mainly required because of
+ * the VRFB 32 pixels alignment with rotation
+ */
+static int omap_vout_calculate_offset(struct omap_vout_device *vout)
+{
+ struct v4l2_pix_format *pix = &(vout->pix);
+ struct v4l2_rect *crop = &(vout->crop);
+ struct v4l2_window *win = &(vout->win);
+ int rotation;
+ int mirroring = vout->mirror;
+ int vr_ps = 1, ps = 2, temp_ps = 2;
+ int offset = 0, ctop = 0, cleft = 0, line_length = 0;
+ struct omapvideo_info *ovid;
+ struct omap_overlay *ovl;
+ struct omap_dss_device *cur_display;
+ int *cropped_offset = &(vout->cropped_offset);
+
+ if (flg_720 == VIDEO_720_ENABLE) {
+ pix->height = win->w.height;
+ pix->width = win->w.width;
+ crop->height = win->w.height;
+ crop->width = win->w.width;
+ }
+
+ ovid = &(vout->vid_info);
+ ovl = ovid->overlays[0];
+ /* get the display device attached to the overlay */
+ if (!ovl->manager || !ovl->manager->device)
+ return -1;
+ cur_display = ovl->manager->device;
+
+ if ((cur_display->type == OMAP_DISPLAY_TYPE_VENC) &&
+ ((win->w.width == crop->width)
+ && (win->w.height == crop->height)))
+ vout->flicker_filter = 1;
+ else
+ vout->flicker_filter = 0;
+
+ if (1 == vout->mirror)
+ rotation = rotation_with_mirror(vout->rotation);
+ else
+ rotation = vout->rotation;
+
+ if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
+ V4L2_PIX_FMT_UYVY == pix->pixelformat) {
+ if (rotation_enabled(vout->rotation)) {
+ /*
+ * ps - Actual pixel size for YUYV/UYVY for
+ * VRFB/Mirroring is 4 bytes
+ * vr_ps - Virtually pixel size for YUYV/UYVY is
+ * 2 bytes
+ */
+ ps = 4;
+ vr_ps = 2;
+ } else {
+ ps = 2; /* otherwise the pixel size is 2 byte */
+ }
+ } else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) {
+ ps = 4;
+ } else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) {
+ ps = 3;
+ }
+ vout->ps = ps;
+ vout->vr_ps = vr_ps;
+ if (rotation_enabled(vout->rotation)) {
+ line_length = MAX_PIXELS_PER_LINE;
+ ctop = (pix->height - crop->height) - crop->top;
+ cleft = (pix->width - crop->width) - crop->left;
+ } else {
+ line_length = pix->width;
+ }
+ vout->line_length = line_length;
+ switch (rotation) {
+ case 1:
+ offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
+ vout->vrfb_context[0].bytespp;
+ temp_ps = ps / vr_ps;
+ if (mirroring == 0) {
+ *cropped_offset = offset + line_length *
+ temp_ps * cleft + crop->top * temp_ps;
+ } else {
+ *cropped_offset = offset + line_length * temp_ps *
+ cleft + crop->top * temp_ps + (line_length *
+ ((crop->width / (vr_ps)) - 1) * ps);
+ }
+ break;
+ case 2:
+ offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
+ vout->vrfb_context[0].bytespp) +
+ (vout->vrfb_context[0].xoffset *
+ vout->vrfb_context[0].bytespp));
+ if (mirroring == 0) {
+ *cropped_offset = offset + (line_length * ps * ctop) +
+ (cleft / vr_ps) * ps;
+
+ } else {
+ *cropped_offset = offset + (line_length * ps * ctop) +
+ (cleft / vr_ps) * ps + (line_length *
+ (crop->height - 1) * ps);
+ }
+ break;
+ case 3:
+ offset = vout->vrfb_context[0].xoffset *
+ vout->vrfb_context[0].bytespp;
+ temp_ps = ps / vr_ps;
+ if (mirroring == 0) {
+ *cropped_offset = offset + line_length *
+ temp_ps * crop->left + ctop * ps;
+ } else {
+ *cropped_offset = offset + line_length *
+ temp_ps * crop->left + ctop * ps +
+ (line_length * ((crop->width / vr_ps) - 1) *
+ ps);
+ }
+ break;
+ case 0:
+ if (mirroring == 0) {
+ *cropped_offset = (line_length * ps) *
+ crop->top + (crop->left / vr_ps) * ps;
+ } else {
+ *cropped_offset = (line_length * ps) *
+ crop->top + (crop->left / vr_ps) * ps +
+ (line_length * (crop->height - 1) * ps);
+ }
+ break;
+ default:
+ if (mirroring == 0) {
+ *cropped_offset =
+ line_length * ps * crop->top + crop->left * ps;
+ } else {
+ *cropped_offset = (line_length * ps * crop->top) /
+ vr_ps + (crop->left * ps) / vr_ps +
+ ((crop->width / vr_ps) - 1) * ps;
+ }
+ break;
+ }
+ v4l2_dbg(1, debug, vout->dev->driver,
+ "%s Offset:%x\n", __func__, *cropped_offset);
+ return 0;
+}
+
+/* Initialize the overlay structure */
+int omapvid_init(struct omap_vout_device *vout, u32 addr)
+{
+ int r = 0;
+ struct omapvideo_info *ovid = &(vout->vid_info);
+ struct omap_overlay *ovl;
+ int posx, posy;
+ int outw, outh, temp, rotation;
+ int i;
+ struct v4l2_window *win;
+ struct omap_video_timings *timing;
+
+ win = &vout->win;
+ rotation = vout->rotation;
+ for (i = 0; i < ovid->num_overlays; i++) {
+ ovl = ovid->overlays[i];
+ if (!ovl->manager || !ovl->manager->device)
+ return -EINVAL;
+
+ timing = &ovl->manager->device->panel.timings;
+
+ outw = win->w.width;
+ outh = win->w.height;
+ switch (rotation) {
+
+ case 1:
+ /* Invert the height and widht for 90
+ * and 270 degree rotation
+ */
+ temp = outw;
+ outw = outh;
+ outh = temp;
+ posy = (timing->y_res - win->w.width)-
+ win->w.left;
+ posx = win->w.top;
+ break;
+
+ case 2:
+ posx = (timing->x_res - win->w.width) -
+ win->w.left;
+ posy = (timing->y_res - win->w.height) -
+ win->w.top;
+ break;
+
+ case 3:
+ temp = outw;
+ outw = outh;
+ outh = temp;
+ posy = win->w.left;
+ posx = (timing->x_res - win->w.height)
+ - win->w.top;
+ break;
+
+ default:
+ posx = win->w.left;
+ posy = win->w.top;
+ break;
+ }
+
+ r = omapvid_setup_overlay(vout, ovl, posx, posy, outw,
+ outh, addr);
+ if (r)
+ goto err;
+ }
+ return 0;
+err:
+ printk(KERN_WARNING VOUT_NAME "apply_changes failed\n");
+ return r;
+}
+
+/* Apply the changes set the go bit of DSS */
+int omapvid_apply_changes(struct omap_vout_device *vout)
+{
+ struct omapvideo_info *ovid = &(vout->vid_info);
+ struct omap_overlay *ovl;
+ struct omap_dss_device *device;
+ int i;
+
+ for (i = 0; i < ovid->num_overlays; i++) {
+ ovl = ovid->overlays[i];
+ if (!ovl->manager || !ovl->manager->device)
+ return -EINVAL;
+ ovl->manager->apply(ovl->manager);
+ if (ovl->manager->device->update) {
+ device = ovl->manager->device;
+ device->update(device, 0, 0,
+ device->panel.timings.x_res,
+ device->panel.timings.y_res);
+ }
+ }
+ return 0;
+
+}
+
+/* Setup the overlay */
+int omapvid_setup_overlay(struct omap_vout_device *vout,
+ struct omap_overlay *ovl, int posx, int posy, int outw,
+ int outh, u32 addr)
+{
+ int r = 0;
+ enum omap_color_mode mode = 0;
+ int rotation, mirror;
+ int cropheight, cropwidth, pixheight, pixwidth;
+ u32 new_crop_width, new_crop_height, new_pix_width, new_pix_height;
+ struct omap_overlay_info info;
+
+ if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 &&
+ (outw != vout->pix.width || outh != vout->pix.height)) {
+ r = -EINVAL;
+ goto err;
+ }
+
+ vout->dss_mode = video_mode_to_dss_mode(vout);
+
+ if (mode == -EINVAL) {
+ r = -EINVAL;
+ goto err;
+ }
+
+ rotation = vout->rotation;
+ mirror = vout->mirror;
+
+ /* For 720p set the width and height for ISP resizer downscaling*/
+ if (flg_720 == VIDEO_720_ENABLE) {
+ new_crop_width = vout->win.w.width;
+ new_crop_height = vout->win.w.height;
+ new_pix_width = vout->win.w.width;
+ new_pix_height = vout->win.w.height;
+
+ } else {
+ new_crop_width = vout->crop.width;
+ new_crop_height = vout->crop.height;
+ new_pix_width = vout->pix.width;
+ new_pix_height = vout->pix.height;
+ }
+
+ /* Setup the input plane parameters according to
+ * rotation value selected.
+ */
+ if (rotate_90_or_270(vout->rotation)) {
+ cropheight = new_crop_width;
+ cropwidth = new_crop_height;
+ pixheight = new_pix_width;
+ pixwidth = new_pix_height;
+ } else {
+ cropheight = new_crop_height;
+ cropwidth = new_crop_width;
+ pixheight = new_pix_height;
+ pixwidth = new_pix_width;
+ }
+
+ ovl->get_overlay_info(ovl, &info);
+ info.paddr = addr;
+ info.vaddr = NULL;
+ info.width = cropwidth;
+ info.height = cropheight;
+ info.color_mode = vout->dss_mode;
+ info.mirror = mirror;
+ info.pos_x = posx;
+ info.pos_y = posy;
+ info.out_width = outw;
+ info.out_height = outh;
+ if (!rotation_enabled(vout->rotation)) {
+ info.rotation = 0;
+ info.rotation_type = OMAP_DSS_ROT_DMA;
+ info.screen_width = pixwidth;
+ } else {
+ info.rotation = vout->rotation;
+ info.rotation_type = OMAP_DSS_ROT_VRFB;
+ info.screen_width = 2048;
+ }
+
+ v4l2_dbg(1, debug, vout->dev->driver,
+ "%s info.enable=%d info.addr=%x info.width=%d\n info.height=%d \
+ info.color_mode=%d info.rotation=%d info.mirror=%d\n \
+ info.posx=%d info.posy=%d info.out_width = %d info.out_height=%d\n \
+ info.rotation_type=%d info.screen_width=%d\n", __func__, info.enabled,
+ info.paddr, info.width, info.height, info.color_mode, info.rotation,
+ info.mirror, info.pos_x, info.pos_y, info.out_width, info.out_height,
+ info.rotation_type, info.screen_width);
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ goto err;
+
+ return 0;
+err:
+ printk(KERN_WARNING VOUT_NAME "setup_overlay failed\n");
+ return r;
+}
+
+/* convert V4L2 pixel format to DSS pixel format */
+static enum omap_color_mode video_mode_to_dss_mode(struct omap_vout_device
+ *vout)
+{
+ struct v4l2_pix_format *pix = &vout->pix;
+
+ switch (pix->pixelformat) {
+ case 0:
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ return OMAP_DSS_COLOR_YUV2;
+
+ case V4L2_PIX_FMT_UYVY:
+ return OMAP_DSS_COLOR_UYVY;
+
+ case V4L2_PIX_FMT_RGB565:
+ return OMAP_DSS_COLOR_RGB16;
+
+ case V4L2_PIX_FMT_RGB24:
+ return OMAP_DSS_COLOR_RGB24P;
+
+ case V4L2_PIX_FMT_RGB32:
+ return (vout->vid == OMAP_VIDEO1) ?
+ OMAP_DSS_COLOR_RGB24U : OMAP_DSS_COLOR_ARGB32;
+ case V4L2_PIX_FMT_BGR32:
+ return OMAP_DSS_COLOR_RGBX32;
+
+ default:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+/* Video buffer call backs */
+
+/* Buffer setup function is called by videobuf layer when REQBUF ioctl is
+ * called. This is used to setup buffers and return size and count of
+ * buffers allocated. After the call to this buffer, videobuf layer will
+ * setup buffer queue depending on the size and count of buffers
+ */
+static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
+ unsigned int *size)
+{
+ struct omap_vout_device *vout = q->priv_data;
+ int startindex = 0, i, j;
+ u32 phy_addr = 0, virt_addr = 0;
+
+ if (!vout)
+ return -EINVAL;
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
+ return -EINVAL;
+
+ startindex = (vout->vid == OMAP_VIDEO1) ?
+ video1_numbuffers : video2_numbuffers;
+
+ if ((rotation_enabled(vout->rotation)) &&
+ *count > OMAP_VOUT_MAX_BUFFERS)
+ *count = OMAP_VOUT_MAX_BUFFERS;
+
+ /* If rotation is enabled, allocate memory for VRFB space also */
+ if (rotation_enabled(vout->rotation)) {
+ if (omap_vout_vrfb_buffer_setup(vout, count, startindex))
+ return -ENOMEM;
+ }
+
+ if (V4L2_MEMORY_MMAP != vout->memory)
+ return 0;
+
+ /* Now allocated the V4L2 buffers */
+ *size = vout->pix.width * vout->pix.height * vout->bpp;
+ *size = PAGE_ALIGN(*size);
+ startindex = (vout->vid == OMAP_VIDEO1) ?
+ video1_numbuffers : video2_numbuffers;
+ for (i = startindex; i < *count; i++) {
+ vout->buffer_size = *size;
+
+ virt_addr = omap_vout_alloc_buffer(vout->buffer_size,
+ &phy_addr);
+ if (!virt_addr) {
+ if (!rotation_enabled(vout->rotation))
+ break;
+ /* Free the VRFB buffers if no space for V4L2 buffers */
+ for (j = i; j < *count; j++) {
+ omap_vout_free_buffer(
+ vout->smsshado_virt_addr[j],
+ vout->smsshado_phy_addr[j],
+ vout->smsshado_size);
+ vout->smsshado_virt_addr[j] = 0;
+ vout->smsshado_phy_addr[j] = 0;
+ }
+ }
+ vout->buf_virt_addr[i] = virt_addr;
+ vout->buf_phy_addr[i] = phy_addr;
+ }
+ if (startindex < *count)
+ *count = vout->buffer_allocated = i;
+ else
+ *count = vout->buffer_allocated = *count;
+
+ return 0;
+}
+
+/* Free the V4L2 buffers additionally allocated than default
+ * number of buffers and free all the VRFB buffers */
+static void omap_vout_free_allbuffers(struct omap_vout_device *vout)
+{
+ int num_buffers = 0, i;
+
+ num_buffers = (vout->vid == OMAP_VIDEO1) ?
+ video1_numbuffers : video2_numbuffers;
+ for (i = num_buffers; i < vout->buffer_allocated; i++) {
+ if (vout->buf_virt_addr[i]) {
+ omap_vout_free_buffer(vout->buf_virt_addr[i],
+ vout->buf_phy_addr[i], vout->buffer_size);
+ }
+ vout->buf_virt_addr[i] = 0;
+ vout->buf_phy_addr[i] = 0;
+ }
+ /* Free the VRFB buffers only if they are allocated
+ * during reqbufs. Don't free if init time allocated
+ */
+ if (!vout->vrfb_static_allocation) {
+ for (i = 0; i < OMAP_VOUT_MAX_BUFFERS; i++) {
+ if (vout->smsshado_virt_addr[i]) {
+ omap_vout_free_buffer(
+ vout->smsshado_virt_addr[i],
+ vout->smsshado_phy_addr[i],
+ vout->smsshado_size);
+ vout->smsshado_virt_addr[i] = 0;
+ vout->smsshado_phy_addr[i] = 0;
+ }
+ }
+ }
+ vout->buffer_allocated = num_buffers;
+}
+
+/* This function will be called when VIDIOC_QBUF ioctl is called.
+ * It prepare buffers before give out for the display. This function
+ * user space virtual address into physical address if userptr memory
+ * exchange mechanism is used. If rotation is enabled, it copies entire
+ * buffer into VRFB memory space before giving it to the DSS.
+ */
+static int omap_vout_buffer_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct omap_vout_device *vout = q->priv_data;
+ u32 dest_frame_index = 0, src_element_index = 0;
+ u32 dest_element_index = 0, src_frame_index = 0;
+ u32 elem_count = 0, frame_count = 0, pixsize = 2;
+ struct videobuf_dmabuf *dmabuf = NULL;
+ int rotation;
+ int ret = 0;
+
+ rotation = (vout->mirror) ?
+ rotation_with_mirror(vout->rotation) :
+ vout->rotation;
+
+ if (VIDEOBUF_NEEDS_INIT == vb->state) {
+ vb->width = vout->pix.width;
+ vb->height = vout->pix.height;
+ vb->size = vb->width * vb->height * vout->bpp;
+ vb->field = field;
+ }
+ vb->state = VIDEOBUF_PREPARED;
+ /* if user pointer memory mechanism is used, get the physical
+ * address of the buffer
+ */
+ if (V4L2_MEMORY_USERPTR == vb->memory) {
+ if (0 == vb->baddr)
+ return -EINVAL;
+ /* Virtual address */
+ /* priv points to struct videobuf_pci_sg_memory. But we went
+ * pointer to videobuf_dmabuf, which is member of
+ * videobuf_pci_sg_memory */
+ dmabuf = videobuf_to_dma(q->bufs[vb->i]);
+ dmabuf->vmalloc = (void *) vb->baddr;
+
+ /* Physical address */
+ dmabuf->bus_addr =
+ (dma_addr_t) omap_vout_uservirt_to_phys(vb->baddr);
+ }
+
+ dmabuf = videobuf_to_dma(q->bufs[vb->i]);
+ /* Flush only cacheable memory region */
+ if (cacheable_buffers == 1 && flushable_buffers == 1) {
+ dmac_clean_range(dmabuf->vmalloc,
+ dmabuf->vmalloc + vout->buffer_size);
+ outer_clean_range(dmabuf->bus_addr,
+ dmabuf->bus_addr + vout->buffer_size);
+ }
+
+ if (!rotation_enabled(vout->rotation)) {
+
+ vout->queued_buf_addr[vb->i] = (u8 *) dmabuf->bus_addr;
+ return 0;
+ }
+
+ if (flg_720 == VIDEO_720_ENABLE) {
+ flg_720 = VIDEO_720_RESIZER_N_STREAMING;
+
+ /*Start resizing*/
+ ret = rsz_begin(vb->i, vb->i, 8192,
+ (u32)vout->vrfb_context[vb->i].paddr[rotation],
+ vout->buf_phy_addr[vb->i], vout->buffer_size);
+
+ if (ret) {
+ printk(KERN_ERR "<%s> Failed to resize the 720p buffer"
+ " = %d\n", __func__, ret);
+ return ret;
+ }
+
+ flg_720 = VIDEO_720_ENABLE;
+ } else {
+ /* If rotation is enabled, copy input buffer into VRFB
+ * memory space using DMA. We are copying input buffer
+ * into VRFB memory space of desired angle and DSS will
+ * read image VRFB memory for 0 degree angle
+ */
+ pixsize = vout->bpp * vout->vrfb_bpp;
+ /*
+ * DMA transfer in double index mode
+ */
+
+ /* Frame index */
+ dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) -
+ (vout->pix.width * vout->bpp)) + 1;
+
+ /* Source and destination parameters */
+ src_element_index = 0;
+ src_frame_index = 0;
+ dest_element_index = 1;
+ /* Number of elements per frame */
+ elem_count = vout->pix.width * vout->bpp;
+ frame_count = vout->pix.height;
+ vout->vrfb_dma_tx.tx_status = 0;
+ omap_set_dma_transfer_params(vout->vrfb_dma_tx.dma_ch,
+ OMAP_DMA_DATA_TYPE_S32,
+ (elem_count / 4), frame_count,
+ OMAP_DMA_SYNC_ELEMENT,
+ vout->vrfb_dma_tx.dev_id, 0x0);
+ /* src_port required only for OMAP1 */
+ omap_set_dma_src_params(vout->vrfb_dma_tx.dma_ch, 0,
+ OMAP_DMA_AMODE_POST_INC, dmabuf->bus_addr,
+ src_element_index, src_frame_index);
+ /*set dma source burst mode for VRFB */
+ omap_set_dma_src_burst_mode(vout->vrfb_dma_tx.dma_ch,
+ OMAP_DMA_DATA_BURST_16);
+
+ /* dest_port required only for OMAP1 */
+ omap_set_dma_dest_params(vout->vrfb_dma_tx.dma_ch, 0,
+ OMAP_DMA_AMODE_DOUBLE_IDX,
+ vout->vrfb_context[vb->i].paddr[rotation],
+ dest_element_index, dest_frame_index);
+ /*set dma dest burst mode for VRFB */
+ omap_set_dma_dest_burst_mode(vout->vrfb_dma_tx.dma_ch,
+ OMAP_DMA_DATA_BURST_16);
+ omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
+
+ omap_start_dma(vout->vrfb_dma_tx.dma_ch);
+ interruptible_sleep_on_timeout(&vout->vrfb_dma_tx.wait,
+ VRFB_TX_TIMEOUT);
+
+ if (vout->vrfb_dma_tx.tx_status == 0) {
+ omap_stop_dma(vout->vrfb_dma_tx.dma_ch);
+ return -EINVAL;
+ }
+ }
+ /* Store buffers physical address into an array. Addresses
+ * from this array will be used to configure DSS */
+ vout->queued_buf_addr[vb->i] = (u8 *)
+ vout->vrfb_context[vb->i].paddr[0];
+ return 0;
+}
+
+/* Buffer queue funtion will be called from the videobuf layer when _QBUF
+ * ioctl is called. It is used to enqueue buffer, which is ready to be
+ * displayed. */
+static void omap_vout_buffer_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct omap_vout_device *vout = q->priv_data;
+
+ /* Driver is also maintainig a queue. So enqueue buffer in the driver
+ * queue */
+ list_add_tail(&vb->queue, &vout->dma_queue);
+
+ vb->state = VIDEOBUF_PREPARED;
+}
+
+/* Buffer release function is called from videobuf layer to release buffer
+ * which are already allocated */
+static void omap_vout_buffer_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct omap_vout_device *vout = q->priv_data;
+
+ vb->state = VIDEOBUF_NEEDS_INIT;
+
+ if (V4L2_MEMORY_MMAP != vout->memory)
+ return;
+}
+
+/*
+ * File operations
+ */
+static void omap_vout_vm_open(struct vm_area_struct *vma)
+{
+ struct omap_vout_device *vout = vma->vm_private_data;
+
+ v4l2_dbg(1, debug, vout->dev->driver,
+ "vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
+ vout->mmap_count++;
+}
+
+static void omap_vout_vm_close(struct vm_area_struct *vma)
+{
+ struct omap_vout_device *vout = vma->vm_private_data;
+
+ v4l2_dbg(1, debug, vout->dev->driver,
+ "vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
+ vout->mmap_count--;
+}
+
+static struct vm_operations_struct omap_vout_vm_ops = {
+ .open = omap_vout_vm_open,
+ .close = omap_vout_vm_close,
+};
+
+static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct omap_vout_device *vout = file->private_data;
+ struct videobuf_queue *q = &vout->vbq;
+ unsigned long size = (vma->vm_end - vma->vm_start);
+ unsigned long start = vma->vm_start;
+ struct page *cpage;
+ int i;
+ void *pos;
+ struct videobuf_dmabuf *dmabuf = NULL;
+
+ v4l2_dbg(1, debug, vout->dev->driver,
+ " %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__,
+ vma->vm_pgoff, vma->vm_start, vma->vm_end);
+
+ /* look for the buffer to map */
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == q->bufs[i])
+ continue;
+ if (V4L2_MEMORY_MMAP != q->bufs[i]->memory)
+ continue;
+ if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+ break;
+ }
+
+ if (VIDEO_MAX_FRAME == i) {
+ v4l2_dbg(1, debug, vout->dev->driver,
+ "offset invalid [offset=0x%lx]\n",
+ (vma->vm_pgoff << PAGE_SHIFT));
+ return -EINVAL;
+ }
+ q->bufs[i]->baddr = vma->vm_start;
+
+ vma->vm_flags |= VM_RESERVED;
+ if (cacheable_buffers == 0) {
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ printk(KERN_DEBUG "Requested uncached buffers\n");
+ }
+ vma->vm_ops = &omap_vout_vm_ops;
+ vma->vm_private_data = (void *) vout;
+ dmabuf = videobuf_to_dma(q->bufs[i]);
+
+ pos = (void *)(dmabuf->bus_addr);
+
+ while (size > 0) {
+ cpage = pfn_to_page(((unsigned int) pos) >> PAGE_SHIFT);
+ if (vm_insert_page(vma, start, cpage)) {
+ printk(KERN_ERR "vout_mmap: Failed to insert bus_addr"
+ "page to VMA \n");
+ return -EAGAIN;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
+ vout->mmap_count++;
+ v4l2_dbg(1, debug, vout->dev->driver, "Exiting %s\n", __func__);
+ return 0;
+}
+
+static int omap_vout_release(struct file *file)
+{
+
+ struct omap_vout_device *vout = file->private_data;
+ struct videobuf_queue *q;
+ unsigned int t;
+ struct omapvideo_info *ovid;
+ unsigned int r;
+
+ v4l2_dbg(1, debug, vout->dev->driver, "Entering %s\n", __func__);
+ ovid = &(vout->vid_info);
+
+ if (!vout)
+ return 0;
+ q = &vout->vbq;
+
+ /* Disable all the overlay managers connected with this interface */
+ for (t = 0; t < ovid->num_overlays; t++) {
+ struct omap_overlay *ovl = ovid->overlays[t];
+ if (ovl->manager && ovl->manager->device) {
+ struct omap_overlay_info info;
+ ovl->get_overlay_info(ovl, &info);
+ info.enabled = 0;
+ ovl->set_overlay_info(ovl, &info);
+ }
+
+ }
+ /* Turn off the pipeline */
+ r = omapvid_apply_changes(vout);
+ if (r)
+ printk(KERN_WARNING VOUT_NAME "Unable to apply changes\n");
+
+ /* Release the ISP resizer resource if not already done so*/
+ if ((flg_720 == VIDEO_720_ENABLE) ||
+ (flg_720 == VIDEO_720_RESIZER_N_STREAMING)) {
+ rsz_put_resource();
+ flg_720 = VIDEO_720_DISABLE;
+ }
+
+ /* Free all buffers */
+ omap_vout_free_allbuffers(vout);
+ videobuf_mmap_free(q);
+
+ /* Even if apply changes fails we should continue
+ freeing allocated memeory */
+ if (vout->streaming) {
+ omap_dispc_unregister_isr(omap_vout_isr, vout,
+ OMAP_VOUT_IRQ_MASK);
+ vout->streaming = 0;
+
+ videobuf_streamoff(q);
+ videobuf_queue_cancel(q);
+
+ }
+
+ if (vout->mmap_count != 0)
+ vout->mmap_count = 0;
+
+ vout->opened -= 1;
+ file->private_data = NULL;
+
+ if (vout->buffer_allocated)
+ videobuf_mmap_free(q);
+ v4l2_dbg(1, debug, vout->dev->driver, "Exiting %s\n", __func__);
+ return r;
+}
+
+static int omap_vout_open(struct file *file)
+{
+ struct omap_vout_device *vout = NULL;
+ struct videobuf_queue *q;
+
+ vout = video_drvdata(file);
+ v4l2_dbg(1, debug, vout->dev->driver, "Entering %s\n", __func__);
+
+ if (vout == NULL)
+ return -ENODEV;
+
+ /* for now, we only support single open */
+ if (vout->opened)
+ return -EBUSY;
+
+ vout->opened += 1;
+
+ file->private_data = vout;
+ vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+ q = &vout->vbq;
+ video_vbq_ops.buf_setup = omap_vout_buffer_setup;
+ video_vbq_ops.buf_prepare = omap_vout_buffer_prepare;
+ video_vbq_ops.buf_release = omap_vout_buffer_release;
+ video_vbq_ops.buf_queue = omap_vout_buffer_queue;
+ spin_lock_init(&vout->vbq_lock);
+
+ videobuf_queue_sg_init(q, &video_vbq_ops, NULL, &vout->vbq_lock,
+ vout->type, V4L2_FIELD_NONE, sizeof
+ (struct videobuf_buffer), vout);
+ v4l2_dbg(1, debug, vout->dev->driver, "Exiting %s\n", __func__);
+ return 0;
+}
+
+/* V4L2 ioctls */
+static int vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct omap_vout_device *vout = fh;
+
+ strlcpy(cap->driver, VOUT_NAME,
+ sizeof(cap->driver));
+ strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
+ cap->bus_info[0] = '\0';
+ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_fmtdesc *fmt)
+{
+ int index = fmt->index;
+ enum v4l2_buf_type type = fmt->type;
+
+ fmt->index = index;
+ fmt->type = type;
+ if (index >= NUM_OUTPUT_FORMATS)
+ return -EINVAL;
+
+ fmt->flags = omap_formats[index].flags;
+ strlcpy(fmt->description, omap_formats[index].description,
+ sizeof(fmt->description));
+ fmt->pixelformat = omap_formats[index].pixelformat;
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap_vout_device *vout = fh;
+
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ *pix = vout->pix;
+ return 0;
+
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap_vout_device *vout = fh;
+ struct omapvideo_info *ovid;
+ struct omap_overlay *ovl;
+ struct omap_video_timings *timing;
+
+ if (vout->streaming)
+ return -EBUSY;
+
+ ovid = &(vout->vid_info);
+ ovl = ovid->overlays[0];
+
+ if (!ovl->manager || !ovl->manager->device)
+ return -EINVAL;
+ /* get the display device attached to the overlay */
+ timing = &ovl->manager->device->panel.timings;
+
+ vout->fbuf.fmt.height = timing->y_res;
+ vout->fbuf.fmt.width = timing->x_res;
+
+ omap_vout_try_format(&f->fmt.pix, &vout->fbuf.fmt);
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap_vout_device *vout = fh;
+ int bpp;
+ int r;
+ struct omapvideo_info *ovid;
+ struct omap_overlay *ovl;
+ struct omap_video_timings *timing;
+
+ if (vout->streaming)
+ return -EBUSY;
+
+ mutex_lock(&vout->lock);
+
+ /*check for 720p format*/
+ if (vout->pix.height * vout->pix.width == VID_MAX_WIDTH * 720)
+ flg_720 = VIDEO_720_ENABLE;
+ else
+ flg_720 = VIDEO_720_DISABLE;
+
+ ovid = &(vout->vid_info);
+ ovl = ovid->overlays[0];
+
+ /* get the display device attached to the overlay */
+ if (!ovl->manager || !ovl->manager->device) {
+ mutex_unlock(&vout->lock);
+ return -EINVAL;
+ }
+ timing = &ovl->manager->device->panel.timings;
+
+ /* We dont support RGB24-packed mode if vrfb rotation
+ * is enabled*/
+ if ((rotation_enabled(vout->rotation)) &&
+ f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+ mutex_unlock(&vout->lock);
+ return -EINVAL;
+ }
+
+ /* get the framebuffer parameters */
+
+ if (rotate_90_or_270(vout->rotation)) {
+ vout->fbuf.fmt.height = timing->x_res;
+ vout->fbuf.fmt.width = timing->y_res;
+ } else {
+ vout->fbuf.fmt.height = timing->y_res;
+ vout->fbuf.fmt.width = timing->x_res;
+ }
+
+ /* change to samller size is OK */
+
+ bpp = omap_vout_try_format(&f->fmt.pix, &vout->fbuf.fmt);
+ f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp;
+
+ /* try & set the new output format */
+ vout->bpp = bpp;
+ vout->pix = f->fmt.pix;
+ vout->vrfb_bpp = 1;
+
+ /* If YUYV then vrfb bpp is 2, for others its 1 */
+ if (V4L2_PIX_FMT_YUYV == vout->pix.pixelformat ||
+ V4L2_PIX_FMT_UYVY == vout->pix.pixelformat)
+ vout->vrfb_bpp = 2;
+
+ /* set default crop and win */
+ omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win);
+
+ /* Save the changes in the overlay strcuture */
+ r = omapvid_init(vout, 0);
+ if (r) {
+ printk(KERN_ERR VOUT_NAME "failed to change mode\n");
+ mutex_unlock(&vout->lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&vout->lock);
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ int err = -EINVAL;
+ struct omap_vout_device *vout = fh;
+ struct v4l2_window *win = &f->fmt.win;
+
+ err = omap_vout_try_window(&vout->fbuf, win);
+
+ if (err)
+ return err;
+
+ if (vout->vid == OMAP_VIDEO1)
+ win->global_alpha = 255;
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap_vout_device *vout = fh;
+ int err = -EINVAL;
+ struct v4l2_window *win = &f->fmt.win;
+
+ mutex_lock(&vout->lock);
+ if (flg_720 == VIDEO_720_ENABLE) {
+ /* align the output width to 16 bytes
+ * ISP resizer requires the output width to be
+ * aligned to 16 bytes.
+ */
+ win->w.width = ((win->w.width + 0x0f) & ~0x0f);
+ }
+ err = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win);
+ if (err) {
+ mutex_unlock(&vout->lock);
+ return err;
+ }
+ if (vout->vid == OMAP_VIDEO1)
+ vout->win.global_alpha = 255;
+ else
+ vout->win.global_alpha = f->fmt.win.global_alpha;
+
+ vout->win.chromakey = f->fmt.win.chromakey;
+ mutex_unlock(&vout->lock);
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh,
+ struct v4l2_fmtdesc *fmt)
+{
+ int index = fmt->index;
+ enum v4l2_buf_type type = fmt->type;
+
+ fmt->index = index;
+ fmt->type = type;
+ if (index >= NUM_OUTPUT_FORMATS)
+ return -EINVAL;
+
+ fmt->flags = omap_formats[index].flags;
+ strlcpy(fmt->description, omap_formats[index].description,
+ sizeof(fmt->description));
+ fmt->pixelformat = omap_formats[index].pixelformat;
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap_vout_device *vout = fh;
+ struct omap_overlay *ovl;
+ struct omapvideo_info *ovid;
+ struct v4l2_window *win = &f->fmt.win;
+ struct omap_overlay_manager_info info;
+
+ ovid = &(vout->vid_info);
+ ovl = ovid->overlays[0];
+
+ win->w = vout->win.w;
+ win->field = vout->win.field;
+ win->global_alpha = vout->win.global_alpha;
+
+ if (!ovl->manager || !ovl->manager->get_manager_info)
+ return -EINVAL;
+
+ ovl->manager->get_manager_info(ovl->manager, &info);
+ win->chromakey = info.trans_key;
+
+ return 0;
+}
+
+static int vidioc_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ struct omap_vout_device *vout = fh;
+ enum v4l2_buf_type type = cropcap->type;
+ struct v4l2_pix_format *pix = &vout->pix;
+
+ cropcap->type = type;
+ if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ /* Width and height are always even */
+ cropcap->bounds.width = pix->width & ~1;
+ cropcap->bounds.height = pix->height & ~1;
+
+ omap_vout_default_crop(&vout->pix, &vout->fbuf, &cropcap->defrect);
+ cropcap->pixelaspect.numerator = 1;
+ cropcap->pixelaspect.denominator = 1;
+ return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ struct omap_vout_device *vout = fh;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ crop->c = vout->crop;
+ return 0;
+}
+
+static int vidioc_s_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ struct omap_vout_device *vout = fh;
+ int err = -EINVAL;
+ struct omapvideo_info *ovid;
+ struct omap_overlay *ovl;
+ struct omap_video_timings *timing;
+
+ if (vout->streaming)
+ return -EBUSY;
+
+ mutex_lock(&vout->lock);
+ ovid = &(vout->vid_info);
+ ovl = ovid->overlays[0];
+
+ if (!ovl->manager || !ovl->manager->device) {
+ mutex_unlock(&vout->lock);
+ return -EINVAL;
+ }
+ /* get the display device attached to the overlay */
+ timing = &ovl->manager->device->panel.timings;
+
+ if (rotate_90_or_270(vout->rotation)) {
+ vout->fbuf.fmt.height = timing->x_res;
+ vout->fbuf.fmt.width = timing->y_res;
+ } else {
+ vout->fbuf.fmt.height = timing->y_res;
+ vout->fbuf.fmt.width = timing->x_res;
+ }
+
+ if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ err = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win,
+ &vout->fbuf, &crop->c);
+ mutex_unlock(&vout->lock);
+ return err;
+ } else {
+ mutex_unlock(&vout->lock);
+ return -EINVAL;
+ }
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_ROTATE:
+ v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0);
+ break;
+ case V4L2_CID_BG_COLOR:
+ v4l2_ctrl_query_fill(ctrl, 0, 0xFFFFFF, 1, 0);
+ break;
+ case V4L2_CID_VFLIP:
+ v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
+ default:
+ ctrl->name[0] = '\0';
+ return -EINVAL;
+
+ }
+ return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
+{
+ struct omap_vout_device *vout = fh;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ROTATE:
+ ctrl->value = vout->control[0].value;
+ return 0;
+ case V4L2_CID_BG_COLOR:
+ {
+ struct omapvideo_info *ovid;
+ struct omap_overlay *ovl;
+ struct omap_overlay_manager_info info;
+
+ ovid = &(vout->vid_info);
+ ovl = ovid->overlays[0];
+
+ if (!ovl->manager || !ovl->manager->get_manager_info)
+ return -EINVAL;
+
+ ovl->manager->get_manager_info(ovl->manager, &info);
+ ctrl->value = info.default_color;
+ return 0;
+ }
+
+ case V4L2_CID_VFLIP:
+ ctrl->value = vout->control[2].value;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+ struct omap_vout_device *vout = fh;
+
+ switch (a->id) {
+ case V4L2_CID_ROTATE:
+ {
+ int rotation = a->value;
+
+ mutex_lock(&vout->lock);
+ if ((v4l2_rot_to_dss_rot(rotation, &vout->rotation,
+ vout->mirror))) {
+ mutex_unlock(&vout->lock);
+ return -EINVAL;
+ }
+ if (vout->pix.pixelformat == V4L2_PIX_FMT_RGB24 &&
+ rotation_enabled(vout->rotation)) {
+ mutex_unlock(&vout->lock);
+ return -EINVAL;
+ }
+ vout->control[0].value = rotation;
+ mutex_unlock(&vout->lock);
+ return 0;
+ }
+ case V4L2_CID_BG_COLOR:
+ {
+ unsigned int color = a->value;
+ struct omapvideo_info *ovid;
+ struct omap_overlay *ovl;
+ struct omap_overlay_manager_info info;
+ ovid = &(vout->vid_info);
+ ovl = ovid->overlays[0];
+
+ mutex_lock(&vout->lock);
+ if (!ovl->manager || !ovl->manager->get_manager_info) {
+ mutex_unlock(&vout->lock);
+ return -EINVAL;
+ }
+ ovl->manager->get_manager_info(ovl->manager, &info);
+ info.default_color = color;
+ ovl->manager->set_manager_info(ovl->manager, &info);
+
+ vout->control[1].value = color;
+ mutex_unlock(&vout->lock);
+ return 0;
+ }
+ case V4L2_CID_VFLIP:
+ {
+ unsigned int mirror = a->value;
+ struct omapvideo_info *ovid;
+ struct omap_overlay *ovl;
+ ovid = &(vout->vid_info);
+ ovl = ovid->overlays[0];
+
+ mutex_lock(&vout->lock);
+
+ if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+ mutex_unlock(&vout->lock);
+ return -EINVAL;
+ }
+ /* Use VRFB if mirroring is enabled */
+ if (mirror && !rotation_enabled(vout->rotation))
+ vout->rotation = 0;
+ /* Disabled VRFB if mirroring is disabled */
+ if (!mirror && vout->rotation == 0)
+ vout->rotation = -1;
+
+ vout->mirror = mirror;
+ vout->control[2].value = mirror;
+ mutex_unlock(&vout->lock);
+ return 0;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *req)
+{
+ struct omap_vout_device *vout = fh;
+ struct videobuf_queue *q = &(vout->vbq);
+ unsigned int i, num_buffers = 0;
+ int ret = 0;
+ struct videobuf_dmabuf *dmabuf = NULL;
+
+ if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0))
+ return -EINVAL;
+ /* if memory is not mmp or userptr
+ return error */
+ if ((V4L2_MEMORY_MMAP != req->memory) &&
+ (V4L2_MEMORY_USERPTR != req->memory))
+ return -EINVAL;
+
+ mutex_lock(&vout->lock);
+ /* Cannot be requested when streaming is on */
+ if (vout->streaming) {
+ mutex_unlock(&vout->lock);
+ return -EBUSY;
+ }
+
+ /*
+ * struct v4l2_requestbuffers reserved field used to define
+ * cacheable/non-cacheable and flushable/non-flushable buffers
+ * from user space
+ */
+ cacheable_buffers = (req->reserved[0] == 1) ? 1 : 0;
+ flushable_buffers = (req->reserved[1] == 1) ? 1 : 0;
+
+ /*check for 720p format*/
+ if (vout->pix.height * vout->pix.width ==
+ VID_MAX_WIDTH * 720)
+ flg_720 = VIDEO_720_ENABLE;
+ else
+ flg_720 = VIDEO_720_DISABLE;
+
+ /* If buffers are already allocated free them */
+ if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) {
+ if (vout->mmap_count) {
+ mutex_unlock(&vout->lock);
+ return -EBUSY;
+ }
+ num_buffers = (vout->vid == OMAP_VIDEO1) ?
+ video1_numbuffers : video2_numbuffers;
+ for (i = num_buffers; i < vout->buffer_allocated; i++) {
+ dmabuf = videobuf_to_dma(q->bufs[i]);
+ omap_vout_free_buffer((u32)dmabuf->vmalloc,
+ dmabuf->bus_addr, vout->buffer_size);
+ vout->buf_virt_addr[i] = 0;
+ vout->buf_phy_addr[i] = 0;
+ }
+ vout->buffer_allocated = num_buffers;
+ videobuf_mmap_free(q);
+ } else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) {
+ if (vout->buffer_allocated) {
+ videobuf_mmap_free(q);
+ for (i = 0; i < vout->buffer_allocated; i++) {
+ kfree(q->bufs[i]);
+ q->bufs[i] = NULL;
+ }
+ vout->buffer_allocated = 0;
+ }
+ }
+
+ /*store the memory type in data structure */
+ vout->memory = req->memory;
+
+ INIT_LIST_HEAD(&vout->dma_queue);
+
+ /* call videobuf_reqbufs api */
+ ret = videobuf_reqbufs(q, req);
+ if (ret < 0) {
+ mutex_unlock(&vout->lock);
+ return ret;
+ }
+
+ vout->buffer_allocated = req->count;
+ for (i = 0; i < req->count; i++) {
+ dmabuf = videobuf_to_dma(q->bufs[i]);
+ dmabuf->vmalloc = (void *) vout->buf_virt_addr[i];
+ dmabuf->bus_addr = (dma_addr_t) vout->buf_phy_addr[i];
+ dmabuf->sglen = 1;
+ }
+ mutex_unlock(&vout->lock);
+ return 0;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct omap_vout_device *vout = fh;
+
+ return videobuf_querybuf(&(vout->vbq), b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh,
+ struct v4l2_buffer *buffer)
+{
+ struct omap_vout_device *vout = fh;
+ struct videobuf_queue *q = &vout->vbq;
+ int ret, k, num_video_buffers;
+
+ if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) ||
+ (buffer->index >= vout->buffer_allocated) ||
+ (q->bufs[buffer->index]->memory != buffer->memory)) {
+ return -EINVAL;
+ }
+ if (V4L2_MEMORY_USERPTR == buffer->memory) {
+ if ((buffer->length < vout->pix.sizeimage) ||
+ (0 == buffer->m.userptr)) {
+ return -EINVAL;
+ }
+ }
+
+ if ((rotation_enabled(vout->rotation)) &&
+ vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) {
+ printk(KERN_WARNING VOUT_NAME
+ "DMA Channel not allocated for Rotation\n");
+ return -EINVAL;
+ }
+
+ /* get the ISP resizer resource and configure it*/
+ if (flg_720 == VIDEO_720_ENABLE) {
+ if (rsz_configured == 0) {
+ rsz_get_resource();
+
+ isp_rsz_params.in_hsize = vout->pix.width;
+ isp_rsz_params.in_vsize = vout->pix.height;
+ isp_rsz_params.out_hsize = vout->win.w.width;
+ isp_rsz_params.out_vsize = vout->win.w.height;
+
+ isp_rsz_params.in_pitch = isp_rsz_params.in_hsize * 2;
+ isp_rsz_params.inptyp = RSZ_INTYPE_YCBCR422_16BIT;
+ isp_rsz_params.vert_starting_pixel = 0;
+ isp_rsz_params.horz_starting_pixel = 0;
+
+ /* We are going to do downsampling, 0.75x*/
+ isp_rsz_params.cbilin = 0;
+ isp_rsz_params.out_pitch = isp_rsz_params.out_hsize * 2;
+ isp_rsz_params.hstph = 0;
+ isp_rsz_params.vstph = 0;
+ isp_rsz_params.yenh_params.type = 0;
+ isp_rsz_params.yenh_params.gain = 0;
+ isp_rsz_params.yenh_params.slop = 0;
+ isp_rsz_params.yenh_params.core = 0;
+
+ if (vout->pix.pixelformat == V4L2_PIX_FMT_YUYV)
+ isp_rsz_params.pix_fmt = RSZ_PIX_FMT_YUYV;
+ if (vout->pix.pixelformat == V4L2_PIX_FMT_UYVY)
+ isp_rsz_params.pix_fmt = RSZ_PIX_FMT_UYVY;
+
+ /* As we are downsizing, we put */
+ for (k = 0; k < 32; k++)
+ isp_rsz_params.tap4filt_coeffs[k] =
+ omap_vout_rsz_filter_4_tap_high_quality[k];
+ for (k = 0; k < 32; k++)
+ isp_rsz_params.tap7filt_coeffs[k] =
+ omap_vout_rsz_filter_7_tap_high_quality[k];
+
+ num_video_buffers = (vout->vid == OMAP_VIDEO1) ?
+ video1_numbuffers : video2_numbuffers;
+
+ ret = rsz_configure(&isp_rsz_params,
+ omap_vout_isp_rsz_dma_tx_callback,
+ num_video_buffers,
+ (void *)vout);
+ printk(KERN_ERR "<%s>: rsz_configure = %d\n",
+ __func__, ret);
+ if (ret) {
+ printk(KERN_ERR "<%s> failed to configure "
+ "ISP_resizer = %d\n",
+ __func__, ret);
+ return ret;
+ }
+ rsz_configured = 1;
+ }
+ }
+
+ ret = videobuf_qbuf(q, buffer);
+ return ret;
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct omap_vout_device *vout = fh;
+ struct videobuf_queue *q = &vout->vbq;
+ int ret = 0;
+
+ if (!vout->streaming)
+ return -EINVAL;
+
+ if (file->f_flags & O_NONBLOCK)
+ /* Call videobuf_dqbuf for non blocking mode */
+ ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
+ else
+ /* Call videobuf_dqbuf for blocking mode */
+ ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
+ return ret;
+}
+
+static int vidioc_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct omap_vout_device *vout = fh;
+ struct videobuf_queue *q = &vout->vbq;
+ struct vout_platform_data *pdata = (vout->dev)->platform_data;
+ unsigned int count ;
+ u32 addr = 0;
+ int r = 0;
+ int t;
+ struct omapvideo_info *ovid = &(vout->vid_info);
+
+ mutex_lock(&vout->lock);
+
+ if (vout->streaming) {
+ mutex_unlock(&vout->lock);
+ return -EBUSY;
+ }
+
+ r = videobuf_streamon(q);
+ if (r < 0) {
+ mutex_unlock(&vout->lock);
+ return r;
+ }
+
+ if (list_empty(&vout->dma_queue)) {
+ mutex_unlock(&vout->lock);
+ return -EIO;
+ }
+ /* Get the next frame from the buffer queue */
+ vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next,
+ struct videobuf_buffer, queue);
+ /* Remove buffer from the buffer queue */
+ list_del(&vout->cur_frm->queue);
+ /* Mark state of the current frame to active */
+ vout->cur_frm->state = VIDEOBUF_ACTIVE;
+ /* Initialize field_id and started member */
+ vout->field_id = 0;
+
+ /* set flag here. Next QBUF will start DMA */
+ vout->streaming = 1;
+
+ vout->first_int = 1;
+
+ /*check for 720p format*/
+ if (vout->pix.height * vout->pix.width == VID_MAX_WIDTH * 720)
+ flg_720 = VIDEO_720_ENABLE;
+ else
+ flg_720 = VIDEO_720_DISABLE;
+
+ if (omap_vout_calculate_offset(vout)) {
+ mutex_unlock(&vout->lock);
+ return -EINVAL;
+ }
+ addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i]
+ + vout->cropped_offset;
+
+ count = vout->buffer_allocated;
+ omap_vout_vrfb_buffer_setup(vout, &count, 0);
+
+#ifdef CONFIG_PM
+ if (pdata->set_min_bus_tput) {
+ if (cpu_is_omap3630()) {
+ pdata->set_min_bus_tput(vout->dev , OCP_INITIATOR_AGENT,
+ 200 * 1000 * 4);
+ } else {
+ pdata->set_min_bus_tput(vout->dev , OCP_INITIATOR_AGENT,
+ 166 * 1000 * 4);
+ }
+ }
+
+ /*
+ * Setting VDD1 at OPP3 Frequency to get better performance
+ * on streamon.
+ */
+
+ if (pdata->set_vdd1_opp)
+ pdata->set_vdd1_opp(vout->dev, VDD1_OPP3_FREQ);
+#endif
+ omap_dispc_register_isr(omap_vout_isr, vout, OMAP_VOUT_IRQ_MASK);
+
+ for (t = 0; t < ovid->num_overlays; t++) {
+ struct omap_overlay *ovl = ovid->overlays[t];
+ if (ovl->manager && ovl->manager->device) {
+ struct omap_overlay_info info;
+ ovl->get_overlay_info(ovl, &info);
+ info.enabled = 1;
+ info.paddr = addr;
+ if (ovl->set_overlay_info(ovl, &info)) {
+ mutex_unlock(&vout->lock);
+ return -EINVAL;
+ }
+ }
+ }
+
+ /* First save the configuration in ovelray structure */
+ r = omapvid_init(vout, addr);
+ if (r)
+ printk(KERN_ERR VOUT_NAME "failed to set overlay info\n");
+ /* Enable the pipeline and set the Go bit */
+ r = omapvid_apply_changes(vout);
+ if (r)
+ printk(KERN_ERR VOUT_NAME "failed to change mode\n");
+
+ mutex_unlock(&vout->lock);
+ return r;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct omap_vout_device *vout = fh;
+ int t, r = 0;
+ struct omapvideo_info *ovid = &(vout->vid_info);
+ struct vout_platform_data *pdata = (vout->dev)->platform_data;
+
+ if (!vout->streaming)
+ return -EINVAL;
+ if (vout->streaming) {
+ vout->streaming = 0;
+
+ omap_dispc_unregister_isr(omap_vout_isr, vout,
+ OMAP_VOUT_IRQ_MASK);
+
+#ifdef CONFIG_PM
+ if (pdata->set_min_bus_tput)
+ pdata->set_min_bus_tput(vout->dev, OCP_INITIATOR_AGENT,
+ 0);
+ /*
+ * Setting VDD1 at OPP1 when streamoff is called.
+ */
+ if (pdata->set_vdd1_opp)
+ pdata->set_vdd1_opp(vout->dev, VDD1_OPP1_FREQ);
+#endif
+ for (t = 0; t < ovid->num_overlays; t++) {
+ struct omap_overlay *ovl = ovid->overlays[t];
+ if (ovl->manager && ovl->manager->device) {
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+ info.enabled = 0;
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r) {
+ printk(KERN_ERR VOUT_NAME "failed to \
+ update overlay info\n");
+ return r;
+ }
+ }
+ }
+
+ /* Turn of the pipeline */
+ r = omapvid_apply_changes(vout);
+ if (r) {
+ printk(KERN_ERR VOUT_NAME "failed to change mode\n");
+ return r;
+ }
+
+ /*release resizer now */
+ if (flg_720 == VIDEO_720_ENABLE) {
+ printk(KERN_ERR "<%s> rsz_put_resource\n", __func__);
+ flg_720 = VIDEO_720_DISABLE;
+ rsz_configured = 0;
+ rsz_put_resource();
+ }
+
+ videobuf_streamoff(&vout->vbq);
+ videobuf_queue_cancel(&vout->vbq);
+ }
+ return 0;
+}
+
+static int vidioc_s_fbuf(struct file *file, void *fh,
+ struct v4l2_framebuffer *a)
+{
+ struct omap_vout_device *vout = fh;
+ struct omapvideo_info *ovid;
+ struct omap_overlay *ovl;
+ struct omap_overlay_manager_info info;
+ enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
+ int enable = 0;
+
+ ovid = &(vout->vid_info);
+ ovl = ovid->overlays[0];
+
+ /* OMAP DSS doesn't support Source and Destination color
+ key together */
+ if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) &&
+ (a->flags & V4L2_FBUF_FLAG_CHROMAKEY))
+ return -EINVAL;
+ /* OMAP DSS Doesn't support the Destination color key
+ and alpha blending together */
+ if (a->flags & V4L2_FBUF_FLAG_CHROMAKEY &&
+ (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA))
+ return -EINVAL;
+
+ if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)) {
+ vout->fbuf.flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+ key_type = OMAP_DSS_COLOR_KEY_VID_SRC;
+ } else
+ vout->fbuf.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+
+ if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) {
+ vout->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+ key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
+ } else
+ vout->fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY;
+
+ if (a->flags & (V4L2_FBUF_FLAG_CHROMAKEY |
+ V4L2_FBUF_FLAG_SRC_CHROMAKEY))
+ enable = 1;
+ else
+ enable = 0;
+
+ if (ovl->manager && ovl->manager->get_manager_info &&
+ ovl->manager->set_manager_info) {
+ ovl->manager->get_manager_info(ovl->manager, &info);
+ info.trans_enabled = enable;
+ info.trans_key = vout->win.chromakey;
+ ovl->manager->set_manager_info(ovl->manager, &info);
+ }
+
+ if (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) {
+ vout->fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+ enable = 1;
+ } else if (!(a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA)) {
+ vout->fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA;
+ enable = 0;
+ }
+ if (ovl->manager && ovl->manager->get_manager_info &&
+ ovl->manager->set_manager_info) {
+ ovl->manager->get_manager_info(ovl->manager, &info);
+ info.alpha_enabled = enable;
+ ovl->manager->set_manager_info(ovl->manager, &info);
+ }
+
+ return 0;
+}
+
+static int vidioc_g_fbuf(struct file *file, void *fh,
+ struct v4l2_framebuffer *a)
+{
+ struct omap_vout_device *vout = fh;
+ struct omapvideo_info *ovid;
+ struct omap_overlay *ovl;
+ struct omap_overlay_manager_info info;
+
+ ovid = &(vout->vid_info);
+ ovl = ovid->overlays[0];
+
+ a->flags = 0x0;
+
+ a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY
+ | V4L2_FBUF_CAP_SRC_CHROMAKEY;
+
+ if (ovl->manager && ovl->manager->get_manager_info) {
+ ovl->manager->get_manager_info(ovl->manager, &info);
+ if (info.trans_enabled) {
+ if (info.trans_key_type == OMAP_DSS_COLOR_KEY_VID_SRC)
+ a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+ if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST)
+ a->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+
+ }
+ if (info.alpha_enabled)
+ a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops vout_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_fbuf = vidioc_s_fbuf,
+ .vidioc_g_fbuf = vidioc_g_fbuf,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
+ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
+ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
+ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
+ .vidioc_cropcap = vidioc_cropcap,
+ .vidioc_g_crop = vidioc_g_crop,
+ .vidioc_s_crop = vidioc_s_crop,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+};
+
+static const struct v4l2_file_operations omap_vout_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = video_ioctl2,
+ .mmap = omap_vout_mmap,
+ .open = omap_vout_open,
+ .release = omap_vout_release,
+};
+
+/* Init functions used during driver intitalization */
+/* Initial setup of video_data */
+static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
+{
+ struct v4l2_pix_format *pix;
+ struct video_device *vfd;
+ struct v4l2_control *control;
+ struct omap_dss_device *display =
+ vout->vid_info.overlays[0]->manager->device;
+
+ /* set the default pix */
+ pix = &vout->pix;
+
+ /* Set the default picture of QVGA */
+ pix->width = QQVGA_WIDTH;
+ pix->height = QQVGA_HEIGHT;
+
+ /* Default pixel format is RGB 5-6-5 */
+ pix->pixelformat = V4L2_PIX_FMT_RGB565;
+ pix->field = V4L2_FIELD_ANY;
+ pix->bytesperline = pix->width * 2;
+ pix->sizeimage = pix->bytesperline * pix->height;
+ pix->priv = 0;
+ pix->colorspace = V4L2_COLORSPACE_JPEG;
+
+ vout->bpp = RGB565_BPP;
+ vout->fbuf.fmt.width = display->panel.timings.x_res;
+ vout->fbuf.fmt.height = display->panel.timings.y_res;
+
+ /* Set the data structures for the overlay parameters*/
+ vout->win.global_alpha = 255;
+ vout->fbuf.flags = 0;
+ vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA |
+ V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY;
+ vout->win.chromakey = 0;
+
+ omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win);
+
+ /*Disable the rotation. */
+ control = vout->control;
+
+ control[0].id = V4L2_CID_ROTATE;
+ control[0].value = 0;
+ vout->rotation = -1;
+ vout->mirror = 0;
+ vout->vrfb_bpp = 2;
+
+ control[1].id = V4L2_CID_BG_COLOR;
+ control[1].value = 0;
+
+ /* initialize the video_device struct */
+ vfd = vout->vfd = video_device_alloc();
+
+ if (!vfd) {
+ printk(KERN_ERR VOUT_NAME ": could not allocate\
+ video device struct\n");
+ return -ENOMEM;
+ }
+ vfd->release = video_device_release;
+ vfd->ioctl_ops = &vout_ioctl_ops;
+
+ strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
+ vfd->vfl_type = VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY;
+
+ /* need to register for a VID_HARDWARE_* ID in videodev.h */
+ vfd->fops = &omap_vout_fops;
+ mutex_init(&vout->lock);
+
+ vfd->minor = -1;
+ return 0;
+
+}
+
+/* Setup video buffers */
+static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
+ int vid_num)
+{
+ struct omap2video_device *vid_dev = platform_get_drvdata(pdev);
+ struct omap_vout_device *vout;
+ int i, j, r = 0;
+ int image_width, image_height;
+ unsigned numbuffers;
+ struct video_device *vfd;
+ int static_vrfb_allocation = 0, vrfb_num_bufs = OMAP_VOUT_MAX_BUFFERS;
+
+ vout = vid_dev->vouts[vid_num];
+ vfd = vout->vfd;
+
+ numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers;
+ vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize;
+ printk(KERN_INFO VOUT_NAME "Buffer Size = %d\n", vout->buffer_size);
+ for (i = 0; i < numbuffers; i++) {
+ vout->buf_virt_addr[i] =
+ omap_vout_alloc_buffer(vout->buffer_size,
+ (u32 *) &vout->buf_phy_addr[i]);
+ if (!vout->buf_virt_addr[i]) {
+ numbuffers = i;
+ r = -ENOMEM;
+ goto free_buffers;
+ }
+ }
+
+ for (i = 0; i < OMAP_VOUT_MAX_VBUF_CTXT; i++) {
+
+ if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) {
+ printk(KERN_INFO VOUT_NAME ": VRFB Region allocation \
+ for rotation failed\n");
+ r = -ENOMEM;
+ break;
+ }
+ }
+ if (r == -ENOMEM) {
+ for (j = 0; j < i; j++)
+ omap_vrfb_release_ctx(&vout->vrfb_context[j]);
+
+ goto free_buffers;
+ }
+
+ vout->cropped_offset = 0;
+
+ /* Calculate VRFB memory size */
+ /* allocate for worst case size */
+ image_width = VID_MAX_WIDTH / TILE_SIZE;
+ if (VID_MAX_WIDTH % TILE_SIZE)
+ image_width++;
+
+ image_width = image_width * TILE_SIZE;
+ image_height = VID_720P_HEIGHT / TILE_SIZE;
+
+ if (VID_720P_HEIGHT % TILE_SIZE)
+ image_height++;
+
+ image_height = image_height * TILE_SIZE;
+ vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2);
+
+ /*
+ * Request and Initialize DMA, for DMA based VRFB transfer
+ */
+ vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE;
+ vout->vrfb_dma_tx.dma_ch = -1;
+ vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED;
+ r = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX",
+ omap_vout_vrfb_dma_tx_callback,
+ (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch);
+ if (r < 0) {
+ vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+ printk(KERN_INFO VOUT_NAME ": DMA Channel not alloted\
+ for video%d [v4l2]\n", vfd->minor);
+ }
+ init_waitqueue_head(&vout->vrfb_dma_tx.wait);
+
+ /* Allocate VRFB buffers if selected through bootargs */
+ static_vrfb_allocation = (vid_num == 0) ?
+ vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
+
+ /* statically allocated the VRFB buffer is done through
+ commands line aruments */
+ if (static_vrfb_allocation) {
+ if (omap_vout_allocate_vrfb_buffers(vout, vrfb_num_bufs)) {
+ r = -ENOMEM;
+ goto free_buffers;
+ }
+ vout->vrfb_static_allocation = 1;
+ }
+ return 0;
+
+free_buffers:
+ for (i = 0; i < numbuffers; i++) {
+ omap_vout_free_buffer(vout->buf_virt_addr[i],
+ vout->buf_phy_addr[i], vout->buffer_size);
+ vout->buf_virt_addr[i] = 0;
+ vout->buf_phy_addr[i] = 0;
+ }
+ return r;
+
+}
+
+/* Create video out devices */
+static int __init omap_vout_create_video_devices(struct platform_device *pdev)
+{
+ int r = 0, k;
+ struct omap_vout_device *vout;
+ struct video_device *vfd = NULL;
+ struct omap2video_device *vid_dev = platform_get_drvdata(pdev);
+
+ for (k = 0; k < pdev->num_resources; k++) {
+
+ vout = kmalloc(sizeof(struct omap_vout_device), GFP_KERNEL);
+ if (!vout) {
+ printk(KERN_ERR VOUT_NAME ": could not allocate \
+ memory\n");
+ return -ENOMEM;
+ }
+
+ memset(vout, 0, sizeof(struct omap_vout_device));
+
+ vout->dev = &pdev->dev;
+ vout->vid = k;
+ vid_dev->vouts[k] = vout;
+ vout->vid_info.vid_dev = vid_dev;
+ vout->vid_info.overlays[0] = vid_dev->overlays[k + 1];
+ vout->vid_info.num_overlays = 1;
+ vout->vid_info.id = k + 1;
+ vid_dev->num_videos++;
+
+ /* Setup the default configuration for the video devices
+ */
+ if (omap_vout_setup_video_data(vout) != 0) {
+ r = -ENOMEM;
+ goto error;
+ }
+
+ /* Allocate default number of buffers for the video streaming
+ * and reserve the VRFB space for rotation
+ */
+ if (omap_vout_setup_video_bufs(pdev, k) != 0) {
+ r = -ENOMEM;
+ goto error1;
+ }
+
+ /* Register the Video device with V4L2
+ */
+ vfd = vout->vfd;
+ if (video_register_device(vfd, VFL_TYPE_GRABBER, k + 1) < 0) {
+ printk(KERN_ERR VOUT_NAME ": could not register \
+ Video for Linux device\n");
+ vfd->minor = -1;
+ r = -ENODEV;
+ goto error2;
+ }
+ video_set_drvdata(vfd, vout);
+
+ /* Configure the overlay structure */
+ r = omapvid_init(vid_dev->vouts[k], 0);
+
+ if (r)
+ goto error2;
+ else
+ goto success;
+error2:
+ omap_vout_release_vrfb(vout);
+ omap_vout_free_buffers(vout);
+error1:
+ video_device_release(vfd);
+error:
+ kfree(vout);
+ return r;
+
+success:
+ printk(KERN_INFO VOUT_NAME ": registered and initialized\
+ video device %d [v4l2]\n", vfd->minor);
+ if (k == (pdev->num_resources - 1))
+ return 0;
+ }
+ return -ENODEV;
+
+}
+/* Driver functions */
+static int omap_vout_remove(struct platform_device *pdev)
+{
+
+ struct omap2video_device *vid_dev = platform_get_drvdata(pdev);
+ int k;
+
+ for (k = 0; k < pdev->num_resources; k++)
+ omap_vout_cleanup_device(vid_dev->vouts[k]);
+
+ for (k = 0; k < vid_dev->num_displays; k++) {
+ if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED)
+ vid_dev->displays[k]->disable(vid_dev->displays[k]);
+
+ omap_dss_put_device(vid_dev->displays[k]);
+ }
+ kfree(vid_dev);
+ return 0;
+}
+
+static int __init omap_vout_probe(struct platform_device *pdev)
+{
+ int r = 0, i;
+ struct omap2video_device *vid_dev = NULL;
+ struct omap_overlay *ovl;
+ struct omap_dss_device *def_display;
+ struct omap_dss_device *display = NULL;
+
+ if (pdev->num_resources == 0) {
+ dev_err(&pdev->dev, "probed for an unknown device\n");
+ r = -ENODEV;
+ return r;
+ }
+
+ vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL);
+ if (vid_dev == NULL) {
+ r = -ENOMEM;
+ return r;
+ }
+
+ platform_set_drvdata(pdev, vid_dev);
+
+ vid_dev->num_displays = 0;
+ for_each_dss_dev(display) {
+ omap_dss_get_device(display);
+ if (!display) {
+ dev_err(&pdev->dev, "probed for an unknown device\n");
+ r = -EINVAL;
+ goto error0;
+ }
+ vid_dev->displays[vid_dev->num_displays++] = display;
+ }
+
+ if (vid_dev->num_displays == 0) {
+ dev_err(&pdev->dev, "probed for an unknown device\n");
+ r = -EINVAL;
+ goto error0;
+ }
+
+ vid_dev->num_overlays = omap_dss_get_num_overlays();
+ for (i = 0; i < vid_dev->num_overlays; i++)
+ vid_dev->overlays[i] = omap_dss_get_overlay(i);
+
+ vid_dev->num_managers = omap_dss_get_num_overlay_managers();
+ for (i = 0; i < vid_dev->num_managers; i++)
+ vid_dev->managers[i] = omap_dss_get_overlay_manager(i);
+
+ /* Get the Video1 overlay and video2 overlay.
+ * Setup the Display attached to that overlays
+ */
+ for (i = 1; i < 3; i++) {
+ ovl = omap_dss_get_overlay(i);
+ if (ovl->manager && ovl->manager->device) {
+ def_display = ovl->manager->device;
+ } else {
+ dev_err(&pdev->dev, "probed for an unknown device\n");
+ r = -EINVAL;
+ goto error0;
+ }
+ r = def_display->enable(def_display);
+ if (r) {
+ /* Here we are not considering a error as display may be
+ enabled by frame buffer driver */
+ printk(KERN_WARNING VOUT_NAME
+ "Display already enabled\n");
+ }
+ /* set the update mode */
+ if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
+#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
+ if (def_display->set_update_mode)
+ def_display->set_update_mode(def_display,
+ OMAP_DSS_UPDATE_AUTO);
+ if (def_display->enable_te)
+ def_display->enable_te(def_display, 1);
+#else
+ if (def_display->set_update_mode)
+ def_display->set_update_mode(def_display,
+ OMAP_DSS_UPDATE_MANUAL);
+ if (def_display->enable_te)
+ def_display->enable_te(def_display, 0);
+#endif
+ } else {
+ if (def_display->set_update_mode)
+ def_display->set_update_mode(def_display,
+ OMAP_DSS_UPDATE_AUTO);
+ }
+ }
+
+ r = omap_vout_create_video_devices(pdev);
+ if (r)
+ goto error0;
+
+ for (i = 0; i < vid_dev->num_displays; i++) {
+ struct omap_dss_device *display = vid_dev->displays[i];
+
+ if (display->update)
+ display->update(display, 0, 0,
+ display->panel.timings.x_res,
+ display->panel.timings.y_res);
+ }
+ printk(KERN_INFO VOUT_NAME "display->updated\n");
+ return 0;
+
+error0:
+ kfree(vid_dev);
+ return r;
+}
+
+static struct platform_driver omap_vout_driver = {
+ .driver = {
+ .name = VOUT_NAME,
+ },
+ .probe = omap_vout_probe,
+ .remove = omap_vout_remove,
+};
+
+void omap_vout_isr(void *arg, unsigned int irqstatus)
+{
+ int r;
+ struct timeval timevalue;
+ struct omap_vout_device *vout =
+ (struct omap_vout_device *) arg;
+ u32 addr, fid;
+ struct omapvideo_info *ovid;
+ struct omap_overlay *ovl;
+ struct omap_dss_device *cur_display;
+
+ if (!vout->streaming)
+ return;
+
+ ovid = &(vout->vid_info);
+ ovl = ovid->overlays[0];
+ /* get the display device attached to the overlay */
+ if (!ovl->manager || !ovl->manager->device)
+ return;
+ cur_display = ovl->manager->device;
+
+ spin_lock(&vout->vbq_lock);
+ do_gettimeofday(&timevalue);
+ if ((cur_display->type == OMAP_DISPLAY_TYPE_DSI &&
+ irqstatus & DISPC_IRQ_FRAMEDONE) ||
+ ((cur_display->type == OMAP_DISPLAY_TYPE_DPI ||
+ cur_display->type == OMAP_DISPLAY_TYPE_HDMI) &&
+ irqstatus & DISPC_IRQ_VSYNC)) {
+
+ if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
+ vout->cur_frm->ts = timevalue;
+ vout->cur_frm->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&vout->cur_frm->done);
+ vout->cur_frm = vout->next_frm;
+ }
+ vout->first_int = 0;
+ if (list_empty(&vout->dma_queue)) {
+ /* TODO: only update on new frame */
+ omapvid_apply_changes(vout);
+ spin_unlock(&vout->vbq_lock);
+ return;
+ }
+ vout->next_frm = list_entry(vout->dma_queue.next,
+ struct videobuf_buffer, queue);
+ list_del(&vout->next_frm->queue);
+
+ vout->next_frm->state = VIDEOBUF_ACTIVE;
+ addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
+ + vout->cropped_offset;
+ /* First save the configuration in ovelray structure */
+ r = omapvid_init(vout, addr);
+ if (r)
+ printk(KERN_ERR VOUT_NAME "failed to set overlay info\n");
+ /* Enable the pipeline and set the Go bit */
+ r = omapvid_apply_changes(vout);
+ if (r)
+ printk(KERN_ERR VOUT_NAME "failed to change mode\n");
+ } else {
+
+ if (vout->first_int) {
+ vout->first_int = 0;
+ spin_unlock(&vout->vbq_lock);
+ return;
+ }
+ if (irqstatus & DISPC_IRQ_EVSYNC_ODD) {
+ fid = 1;
+ } else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN) {
+ fid = 0;
+ } else {
+ spin_unlock(&vout->vbq_lock);
+ return;
+ }
+ vout->field_id ^= 1;
+ if (fid != vout->field_id) {
+ if (0 == fid)
+ vout->field_id = fid;
+
+ spin_unlock(&vout->vbq_lock);
+ return;
+ }
+ if (0 == fid) {
+ if (vout->cur_frm == vout->next_frm) {
+ spin_unlock(&vout->vbq_lock);
+ return;
+ }
+ vout->cur_frm->ts = timevalue;
+ vout->cur_frm->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&vout->cur_frm->done);
+ vout->cur_frm = vout->next_frm;
+ } else if (1 == fid) {
+ if (list_empty(&vout->dma_queue) ||
+ (vout->cur_frm != vout->next_frm)) {
+ spin_unlock(&vout->vbq_lock);
+ return;
+ }
+ vout->next_frm = list_entry(vout->dma_queue.next,
+ struct videobuf_buffer, queue);
+ list_del(&vout->next_frm->queue);
+
+ vout->next_frm->state = VIDEOBUF_ACTIVE;
+ addr = (unsigned long)
+ vout->queued_buf_addr[vout->next_frm->i] +
+ vout->cropped_offset;
+ /* First save the configuration in ovelray structure */
+ r = omapvid_init(vout, addr);
+ if (r)
+ printk(KERN_ERR VOUT_NAME "failed to set overlay info\n");
+ /* Enable the pipeline and set the Go bit */
+ r = omapvid_apply_changes(vout);
+ if (r)
+ printk(KERN_ERR VOUT_NAME "failed to change mode\n");
+ }
+
+ }
+ spin_unlock(&vout->vbq_lock);
+}
+
+static void omap_vout_cleanup_device(struct omap_vout_device *vout)
+{
+
+ struct video_device *vfd;
+
+ if (!vout)
+ return;
+ vfd = vout->vfd;
+
+ if (vfd) {
+ if (vfd->minor == -1) {
+ /*
+ * The device was never registered, so release the
+ * video_device struct directly.
+ */
+ video_device_release(vfd);
+ } else {
+ /*
+ * The unregister function will release the video_device
+ * struct as well as unregistering it.
+ */
+ video_unregister_device(vfd);
+ }
+ }
+
+ omap_vout_release_vrfb(vout);
+
+ omap_vout_free_buffers(vout);
+ /* Free the VRFB buffer if allocated
+ * init time
+ */
+ if (vout->vrfb_static_allocation)
+ omap_vout_free_vrfb_buffers(vout);
+
+ kfree(vout);
+}
+
+static int __init omap_vout_init(void)
+{
+
+ if (platform_driver_register(&omap_vout_driver) != 0) {
+ printk(KERN_ERR VOUT_NAME ": could not register \
+ Video driver\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void omap_vout_cleanup(void)
+{
+ platform_driver_unregister(&omap_vout_driver);
+}
+
+MODULE_AUTHOR("Texas Instruments.");
+MODULE_DESCRIPTION("OMAP Video for Linux Video out driver");
+MODULE_LICENSE("GPL");
+
+late_initcall(omap_vout_init);
+module_exit(omap_vout_cleanup);
diff --git a/drivers/media/video/omap/omap_voutdef.h b/drivers/media/video/omap/omap_voutdef.h
new file mode 100644
index 0000000..df313c1
--- /dev/null
+++ b/drivers/media/video/omap/omap_voutdef.h
@@ -0,0 +1,153 @@
+/*
+ * drivers/media/video/omap/omap_voutdef.h
+ *
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * 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 OMAP_VOUTDEF_H
+#define OMAP_VOUTDEF_H
+
+#include <mach/display.h>
+#include <mach/omap-pm.h>
+#include <mach/vrfb.h>
+#include <media/videobuf-core.h>
+
+#define YUYV_BPP 2
+#define RGB565_BPP 2
+#define RGB24_BPP 3
+#define RGB32_BPP 4
+#define TILE_SIZE 32
+#define YUYV_VRFB_BPP 2
+#define RGB_VRFB_BPP 1
+#define MAX_CID 3
+
+
+#define OMAP_VOUT_MAX_BUFFERS 6
+
+/*
+ * Currently VBUF context and Data Buffers are mapped 1:1
+ */
+#define OMAP_VOUT_MAX_VBUF_CTXT OMAP_VOUT_MAX_BUFFERS
+/*
+ * This structure is used to store the DMA transfer parameters
+ * for VRFB hidden buffer
+ */
+struct vid_vrfb_dma {
+ int dev_id;
+ int dma_ch;
+ int req_status;
+ int tx_status;
+ wait_queue_head_t wait;
+};
+
+struct omapvideo_info {
+ int id;
+ int num_overlays;
+ struct omap_overlay *overlays[3];
+ struct omap2video_device *vid_dev;
+};
+
+struct omap2video_device {
+ struct device *dev;
+ struct mutex mtx;
+
+ int state;
+
+ int num_videos;
+ struct omap_vout_device *vouts[10];
+
+ int num_displays;
+ struct omap_dss_device *displays[10];
+ int num_overlays;
+ struct omap_overlay *overlays[10];
+ int num_managers;
+ struct omap_overlay_manager *managers[10];
+};
+
+/* per-device data structure */
+struct omap_vout_device {
+
+ struct omapvideo_info vid_info;
+ struct device *dev;
+ struct video_device *vfd;
+ int vid;
+ int opened;
+
+ /* we don't allow to change image fmt/size once buffer has
+ * been allocated
+ */
+ int buffer_allocated;
+ /* allow to reuse previosuly allocated buffer which is big enough */
+ int buffer_size;
+ /* keep buffer info accross opens */
+ unsigned long buf_virt_addr[VIDEO_MAX_FRAME];
+ unsigned long buf_phy_addr[VIDEO_MAX_FRAME];
+ enum omap_color_mode dss_mode;
+
+ /* we don't allow to request new buffer when old buffers are
+ * still mmaped
+ */
+ int mmap_count;
+
+ spinlock_t vbq_lock; /* spinlock for videobuf queues */
+ unsigned long field_count; /* field counter for videobuf_buffer */
+
+ /* non-NULL means streaming is in progress. */
+ bool streaming;
+
+ struct v4l2_pix_format pix;
+ struct v4l2_rect crop;
+ struct v4l2_window win;
+ struct v4l2_framebuffer fbuf;
+
+ /* Lock to protect the shared data structures in ioctl */
+ struct mutex lock;
+
+ /* V4L2 control structure for different control id */
+ struct v4l2_control control[MAX_CID];
+ int rotation;
+ int mirror;
+ int flicker_filter;
+ /* V4L2 control structure for different control id */
+
+ int bpp; /* bytes per pixel */
+ int vrfb_bpp; /* bytes per pixel with respect to VRFB */
+
+ struct vid_vrfb_dma vrfb_dma_tx;
+ unsigned int smsshado_phy_addr[OMAP_VOUT_MAX_BUFFERS];
+ unsigned int smsshado_virt_addr[OMAP_VOUT_MAX_BUFFERS];
+ struct vrfb vrfb_context[OMAP_VOUT_MAX_VBUF_CTXT];
+ bool vrfb_static_allocation;
+ unsigned int smsshado_size;
+ unsigned char pos;
+
+ int ps, vr_ps, line_length, first_int, field_id;
+ enum v4l2_memory memory;
+ struct videobuf_buffer *cur_frm, *next_frm;
+ struct list_head dma_queue;
+ u8 *queued_buf_addr[32];
+ u32 cropped_offset;
+ s32 tv_field1_offset;
+ void *isr_handle;
+
+ /* Buffer queue variabled */
+ struct omap_vout_device *vout;
+ enum v4l2_buf_type type;
+ struct videobuf_queue vbq;
+ int io_allowed;
+
+};
+
+struct vout_platform_data {
+ void (*set_min_bus_tput)(struct device *dev, u8 agent_id,
+ unsigned long r);
+ void (*set_max_mpu_wakeup_lat)(struct device *dev, long t);
+ void (*set_vdd1_opp) (struct device *dev, unsigned long);
+ void (*set_cpu_freq)(unsigned long f);
+};
+
+#endif /* ifndef OMAP_VOUTDEF_H */
diff --git a/drivers/media/video/omap/omap_voutlib.c b/drivers/media/video/omap/omap_voutlib.c
new file mode 100644
index 0000000..5a31884
--- /dev/null
+++ b/drivers/media/video/omap/omap_voutlib.c
@@ -0,0 +1,320 @@
+/*
+ * drivers/media/video/omap/omap_voutlib.c
+ *
+ * Copyright (C) 2005-2009 Texas Instruments.
+ *
+ * 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.
+ *
+ * Based on the OMAP2 camera driver
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP24xx camera controller.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/videodev2.h>
+#include <linux/semaphore.h>
+#include <mach/cpu.h>
+
+/* Return the default overlay cropping rectangle in crop given the image
+ * size in pix and the video display size in fbuf. The default
+ * cropping rectangle is the largest rectangle no larger than the capture size
+ * that will fit on the display. The default cropping rectangle is centered in
+ * the image. All dimensions and offsets are rounded down to even numbers.
+ */
+void omap_vout_default_crop(struct v4l2_pix_format *pix,
+ struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop)
+{
+ crop->width = (pix->width < fbuf->fmt.width) ?
+ pix->width : fbuf->fmt.width;
+ crop->height = (pix->height < fbuf->fmt.height) ?
+ pix->height : fbuf->fmt.height;
+ crop->width &= ~1;
+ crop->height &= ~1;
+ crop->left = ((pix->width - crop->width) >> 1) & ~1;
+ crop->top = ((pix->height - crop->height) >> 1) & ~1;
+}
+EXPORT_SYMBOL_GPL(omap_vout_default_crop);
+
+/* Given a new render window in new_win, adjust the window to the
+ * nearest supported configuration. The adjusted window parameters are
+ * returned in new_win.
+ * Returns zero if succesful, or -EINVAL if the requested window is
+ * impossible and cannot reasonably be adjusted.
+ */
+int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
+ struct v4l2_window *new_win)
+{
+ struct v4l2_rect try_win;
+
+ /* make a working copy of the new_win rectangle */
+ try_win = new_win->w;
+
+ /* adjust the preview window so it fits on the display by clipping any
+ * offscreen areas
+ */
+ if (try_win.left < 0) {
+ try_win.width += try_win.left;
+ try_win.left = 0;
+ }
+ if (try_win.top < 0) {
+ try_win.height += try_win.top;
+ try_win.top = 0;
+ }
+ try_win.width = (try_win.width < fbuf->fmt.width) ?
+ try_win.width : fbuf->fmt.width;
+ try_win.height = (try_win.height < fbuf->fmt.height) ?
+ try_win.height : fbuf->fmt.height;
+ if (try_win.left + try_win.width > fbuf->fmt.width)
+ try_win.width = fbuf->fmt.width - try_win.left;
+ if (try_win.top + try_win.height > fbuf->fmt.height)
+ try_win.height = fbuf->fmt.height - try_win.top;
+ try_win.width &= ~1;
+ try_win.height &= ~1;
+
+ if (try_win.width <= 0 || try_win.height <= 0)
+ return -EINVAL;
+
+ /* We now have a valid preview window, so go with it */
+ new_win->w = try_win;
+ new_win->field = V4L2_FIELD_ANY;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(omap_vout_try_window);
+
+/* Given a new render window in new_win, adjust the window to the
+ * nearest supported configuration. The image cropping window in crop
+ * will also be adjusted if necessary. Preference is given to keeping the
+ * the window as close to the requested configuration as possible. If
+ * successful, new_win, vout->win, and crop are updated.
+ * Returns zero if succesful, or -EINVAL if the requested preview window is
+ * impossible and cannot reasonably be adjusted.
+ */
+int omap_vout_new_window(struct v4l2_rect *crop,
+ struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
+ struct v4l2_window *new_win)
+{
+ int err;
+
+ err = omap_vout_try_window(fbuf, new_win);
+ if (err)
+ return err;
+
+ /* update our preview window */
+ win->w = new_win->w;
+ win->field = new_win->field;
+ win->chromakey = new_win->chromakey;
+
+ if (cpu_is_omap24xx()) {
+ /* adjust the cropping window to allow for resizing
+ * limitations. 24xx allow 8x to 1/2x scaling.
+ */
+ if ((crop->height/win->w.height) >= 2) {
+ /* The maximum vertical downsizing ratio is 2:1 */
+ crop->height = win->w.height * 2;
+ }
+ if ((crop->width/win->w.width) >= 2) {
+ /* The maximum horizontal downsizing ratio is 2:1 */
+ crop->width = win->w.width * 2;
+ }
+ if (crop->width > 768) {
+ /* The OMAP2420 vertical resizing line buffer is 768
+ * pixels wide. If the cropped image is wider than
+ * 768 pixels then it cannot be vertically resized.
+ */
+ if (crop->height != win->w.height)
+ crop->width = 768;
+ }
+ } else if (cpu_is_omap34xx()) {
+ /* adjust the cropping window to allow for resizing
+ * limitations 34xx allow 8x to 1/4x scaling.
+ */
+ if ((crop->height/win->w.height) >= 4) {
+ /* The maximum vertical downsizing ratio is 4:1 */
+ crop->height = win->w.height * 4;
+ }
+ if ((crop->width/win->w.width) >= 4) {
+ /* The maximum horizontal downsizing ratio is 4:1 */
+ crop->width = win->w.width * 4;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(omap_vout_new_window);
+
+/* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to
+ * the nearest supported configuration. The image render window in win will
+ * also be adjusted if necessary. The preview window is adjusted such that the
+ * horizontal and vertical rescaling ratios stay constant. If the render
+ * window would fall outside the display boundaries, the cropping rectangle
+ * will also be adjusted to maintain the rescaling ratios. If successful, crop
+ * and win are updated.
+ * Returns zero if succesful, or -EINVAL if the requested cropping rectangle is
+ * impossible and cannot reasonably be adjusted.
+ */
+int omap_vout_new_crop(struct v4l2_pix_format *pix,
+ struct v4l2_rect *crop, struct v4l2_window *win,
+ struct v4l2_framebuffer *fbuf, const struct v4l2_rect *new_crop)
+{
+ struct v4l2_rect try_crop;
+ unsigned long vresize, hresize;
+
+ /* make a working copy of the new_crop rectangle */
+ try_crop = *new_crop;
+
+ /* adjust the cropping rectangle so it fits in the image */
+ if (try_crop.left < 0) {
+ try_crop.width += try_crop.left;
+ try_crop.left = 0;
+ }
+ if (try_crop.top < 0) {
+ try_crop.height += try_crop.top;
+ try_crop.top = 0;
+ }
+ try_crop.width = (try_crop.width < pix->width) ?
+ try_crop.width : pix->width;
+ try_crop.height = (try_crop.height < pix->height) ?
+ try_crop.height : pix->height;
+ if (try_crop.left + try_crop.width > pix->width)
+ try_crop.width = pix->width - try_crop.left;
+ if (try_crop.top + try_crop.height > pix->height)
+ try_crop.height = pix->height - try_crop.top;
+ try_crop.width &= ~1;
+ try_crop.height &= ~1;
+ if (try_crop.width <= 0 || try_crop.height <= 0)
+ return -EINVAL;
+ if (cpu_is_omap24xx()) {
+ if (crop->height != win->w.height) {
+ /* If we're resizing vertically, we can't support a
+ * crop width wider than 768 pixels.
+ */
+ if (try_crop.width > 768)
+ try_crop.width = 768;
+ }
+ }
+ /* vertical resizing */
+ vresize = (1024 * crop->height) / win->w.height;
+ if (cpu_is_omap24xx()) {
+ if (vresize > 2048)
+ vresize = 2048;
+ } else if (cpu_is_omap34xx()) {
+ if (vresize > 4096)
+ vresize = 4096;
+ }
+ win->w.height = ((1024 * try_crop.height) / vresize) & ~1;
+ if (win->w.height == 0)
+ win->w.height = 2;
+ if (win->w.height + win->w.top > fbuf->fmt.height) {
+ /* We made the preview window extend below the bottom of the
+ * display, so clip it to the display boundary and resize the
+ * cropping height to maintain the vertical resizing ratio.
+ */
+ win->w.height = (fbuf->fmt.height - win->w.top) & ~1;
+ if (try_crop.height == 0)
+ try_crop.height = 2;
+ }
+ /* horizontal resizing */
+ hresize = (1024 * crop->width) / win->w.width;
+ if (cpu_is_omap24xx()) {
+ if (hresize > 2048)
+ hresize = 2048;
+ } else if (cpu_is_omap34xx()) {
+ if (hresize > 4096)
+ hresize = 4096;
+ }
+ win->w.width = ((1024 * try_crop.width) / hresize) & ~1;
+ if (win->w.width == 0)
+ win->w.width = 2;
+ if (win->w.width + win->w.left > fbuf->fmt.width) {
+ /* We made the preview window extend past the right side of the
+ * display, so clip it to the display boundary and resize the
+ * cropping width to maintain the horizontal resizing ratio.
+ */
+ win->w.width = (fbuf->fmt.width - win->w.left) & ~1;
+ if (try_crop.width == 0)
+ try_crop.width = 2;
+ }
+ if (cpu_is_omap24xx()) {
+ /* Check for resizing constraints
+ * 24xx allow 8x to 1/2x scaling.
+ */
+ if ((try_crop.height/win->w.height) >= 2) {
+ /* The maximum vertical downsizing ratio is 2:1 */
+ try_crop.height = win->w.height * 2;
+ }
+ if ((try_crop.width/win->w.width) >= 2) {
+ /* The maximum horizontal downsizing ratio is 2:1 */
+ try_crop.width = win->w.width * 2;
+ }
+ if (try_crop.width > 768) {
+ /* The OMAP2420 vertical resizing line buffer is
+ * 768 pixels wide. If the cropped image is wider
+ * than 768 pixels then it cannot be vertically resized.
+ */
+ if (try_crop.height != win->w.height)
+ try_crop.width = 768;
+ }
+ } else if (cpu_is_omap34xx()) {
+ /* Check for resizing constraints
+ * 34xx allow 8x to 1/4x scaling.
+ */
+ if ((try_crop.height/win->w.height) >= 4) {
+ /* The maximum vertical downsizing ratio is 4:1 */
+ try_crop.height = win->w.height * 4;
+ }
+ if ((try_crop.width/win->w.width) >= 4) {
+ /* The maximum horizontal downsizing ratio is 4:1 */
+ try_crop.width = win->w.width * 4;
+ }
+ }
+ /* update our cropping rectangle and we're done */
+ *crop = try_crop;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(omap_vout_new_crop);
+
+/* Given a new format in pix and fbuf, crop and win
+ * structures are initialized to default values. crop
+ * is initialized to the largest window size that will fit on the display. The
+ * crop window is centered in the image. win is initialized to
+ * the same size as crop and is centered on the display.
+ * All sizes and offsets are constrained to be even numbers.
+ */
+void omap_vout_new_format(struct v4l2_pix_format *pix,
+ struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
+ struct v4l2_window *win)
+{
+ /* crop defines the preview source window in the image capture
+ * buffer
+ */
+ omap_vout_default_crop(pix, fbuf, crop);
+
+ /* win defines the preview target window on the display */
+ win->w.width = crop->width;
+ win->w.height = crop->height;
+ win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1;
+ win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1;
+}
+EXPORT_SYMBOL_GPL(omap_vout_new_format);
+
+MODULE_AUTHOR("Texas Instruments.");
+MODULE_DESCRIPTION("OMAP Video library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/omap/omap_voutlib.h b/drivers/media/video/omap/omap_voutlib.h
new file mode 100644
index 0000000..8ef6e25
--- /dev/null
+++ b/drivers/media/video/omap/omap_voutlib.h
@@ -0,0 +1,34 @@
+/*
+ * drivers/media/video/omap/omap_voutlib.h
+ *
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * 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 OMAP_VOUTLIB_H
+#define OMAP_VOUTLIB_H
+
+extern void omap_vout_default_crop(struct v4l2_pix_format *pix,
+ struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop);
+
+extern int omap_vout_new_crop(struct v4l2_pix_format *pix,
+ struct v4l2_rect *crop, struct v4l2_window *win,
+ struct v4l2_framebuffer *fbuf,
+ const struct v4l2_rect *new_crop);
+
+extern int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
+ struct v4l2_window *new_win);
+
+extern int omap_vout_new_window(struct v4l2_rect *crop,
+ struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
+ struct v4l2_window *new_win);
+
+extern void omap_vout_new_format(struct v4l2_pix_format *pix,
+ struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
+ struct v4l2_window *win);
+#endif /* #ifndef OMAP_LIB_H */
+
diff --git a/drivers/media/video/omap34xxcam.c b/drivers/media/video/omap34xxcam.c
index b7e0e74..1ae6ab1 100644
--- a/drivers/media/video/omap34xxcam.c
+++ b/drivers/media/video/omap34xxcam.c
@@ -32,32 +32,22 @@
*
*/
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/pci.h> /* needed for videobufs */
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
#include <linux/videodev2.h>
#include <linux/version.h>
-#include <linux/platform_device.h>
+#include <linux/ktime.h>
+#include <asm/pgalloc.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include "omap34xxcam.h"
#include "isp/isp.h"
-#include "isp/ispmmu.h"
-#include "isp/ispreg.h"
-#include "isp/ispccdc.h"
-#include "isp/isph3a.h"
-#include "isp/isp_af.h"
-#include "isp/isphist.h"
-#include "isp/isppreview.h"
-#include "isp/ispresizer.h"
#define OMAP34XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
+#define to_omap34xxcam_fh(vfh) \
+ container_of(vfh, struct omap34xxcam_fh, vfh)
+
/* global variables */
static struct omap34xxcam_device *omap34xxcam;
@@ -77,14 +67,23 @@
int mask)
{
int rval = 0, i = 0;
+ int start, end, dir;
BUG_ON(!mutex_is_locked(&vdev->mutex));
-#ifdef OMAP34XXCAM_POWEROFF_DELAY
- vdev->power_state_wish = -1;
-#endif
+ if (power != V4L2_POWER_OFF) {
+ /* Sensor has to be powered on first */
+ start = 0;
+ end = OMAP34XXCAM_SLAVE_FLASH;
+ dir = 1;
+ } else {
+ /* Sensor has to be powered off last */
+ start = OMAP34XXCAM_SLAVE_FLASH;
+ end = 0;
+ dir = -1;
+ }
- for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+ for (i = start; i != end + dir; i += dir) {
if (vdev->slave[i] == v4l2_int_device_dummy())
continue;
@@ -105,7 +104,7 @@
return 0;
out:
- for (i--; i >= 0; i--) {
+ for (i -= dir; i != start - dir; i -= dir) {
if (vdev->slave[i] == v4l2_int_device_dummy())
continue;
@@ -119,51 +118,6 @@
return rval;
}
-#ifdef OMAP34XXCAM_POWEROFF_DELAY
-static void omap34xxcam_slave_power_work(struct work_struct *work)
-{
- struct omap34xxcam_videodev *vdev =
- container_of(work, struct omap34xxcam_videodev, poweroff_work);
-
- mutex_lock(&vdev->mutex);
-
- if (vdev->power_state_wish != -1)
- omap34xxcam_slave_power_set(vdev, vdev->power_state_wish,
- vdev->power_state_mask);
-
- mutex_unlock(&vdev->mutex);
-}
-
-static void omap34xxcam_slave_power_timer(unsigned long ptr)
-{
- struct omap34xxcam_videodev *vdev = (void *)ptr;
-
- schedule_work(&vdev->poweroff_work);
-}
-
-/**
- * omap34xxcam_slave_power_suggest - delayed power state change
- *
- * @vdev: per-video device data structure
- * @power: new power state
- */
-static void omap34xxcam_slave_power_suggest(struct omap34xxcam_videodev *vdev,
- enum v4l2_power power,
- int mask)
-{
- BUG_ON(!mutex_is_locked(&vdev->mutex));
-
- del_timer(&vdev->poweroff_timer);
-
- vdev->power_state_wish = power;
- vdev->power_state_mask = mask;
-
- mod_timer(&vdev->poweroff_timer, jiffies + OMAP34XXCAM_POWEROFF_DELAY);
-}
-#else /* OMAP34XXCAM_POWEROFF_DELAY */
-#define omap34xxcam_slave_power_suggest(a, b, c) do {} while (0)
-#endif /* OMAP34XXCAM_POWEROFF_DELAY */
-
/**
* omap34xxcam_update_vbq - Updates VBQ with completed input buffer
* @vb: ptr. to standard V4L2 video buffer structure
@@ -174,10 +128,12 @@
*/
void omap34xxcam_vbq_complete(struct videobuf_buffer *vb, void *priv)
{
- struct omap34xxcam_fh *fh = priv;
+ struct v4l2_fh *vfh = priv;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
do_gettimeofday(&vb->ts);
- vb->field_count = atomic_add_return(2, &fh->field_count);
+ vb->field_count = atomic_add_return(2, &ofh->field_count);
+ vb->state = VIDEOBUF_DONE;
wake_up(&vb->done);
}
@@ -194,8 +150,9 @@
static int omap34xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
unsigned int *size)
{
- struct omap34xxcam_fh *fh = vbq->priv_data;
- struct omap34xxcam_videodev *vdev = fh->vdev;
+ struct v4l2_fh *vfh = vbq->priv_data;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
if (*cnt <= 0)
*cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
@@ -205,10 +162,65 @@
*size = vdev->pix.sizeimage;
- while (*size * *cnt > fh->vdev->vdev_sensor_config.capture_mem)
+ while (*size * *cnt > ofh->vdev->vdev_sensor_config.capture_mem)
(*cnt)--;
- return isp_vbq_setup(vbq, cnt, size);
+ return isp_vbq_setup(vdev->cam->isp, vbq, cnt, size);
+}
+
+static int omap34xxcam_vb_lock_vma(struct videobuf_buffer *vb, int lock)
+{
+ unsigned long start, end;
+ struct vm_area_struct *vma;
+ int rval = 0;
+
+ if (vb->memory == V4L2_MEMORY_MMAP)
+ return 0;
+
+ if (!current || !current->mm) {
+ /**
+ * We are called from interrupt or workqueue context.
+ *
+ * For locking, we return error.
+ * For unlocking, the subsequent release of
+ * buffer should set things right
+ */
+ if (lock)
+ return -EINVAL;
+ else
+ return 0;
+ }
+
+ end = vb->baddr + vb->bsize;
+
+ down_write(¤t->mm->mmap_sem);
+ spin_lock(¤t->mm->page_table_lock);
+
+ for (start = vb->baddr; ; ) {
+ unsigned int newflags;
+
+ vma = find_vma(current->mm, start);
+ if (!vma || vma->vm_start > start) {
+ rval = -ENOMEM;
+ goto out;
+ }
+
+ newflags = vma->vm_flags | VM_LOCKED;
+ if (!lock)
+ newflags &= ~VM_LOCKED;
+
+ vma->vm_flags = newflags;
+
+ if (vma->vm_end >= end)
+ break;
+
+ start = vma->vm_end;
+ }
+
+out:
+ spin_unlock(¤t->mm->page_table_lock);
+ up_write(¤t->mm->mmap_sem);
+ return rval;
}
/**
@@ -222,8 +234,14 @@
static void omap34xxcam_vbq_release(struct videobuf_queue *vbq,
struct videobuf_buffer *vb)
{
+ struct v4l2_fh *vfh = vbq->priv_data;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct device *isp = vdev->cam->isp;
+
if (!vbq->streaming) {
- isp_vbq_release(vbq, vb);
+ isp_vbq_release(isp, vbq, vb);
+ omap34xxcam_vb_lock_vma(vb, 0);
videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
videobuf_dma_free(videobuf_to_dma(vb));
vb->state = VIDEOBUF_NEEDS_INIT;
@@ -245,8 +263,11 @@
struct videobuf_buffer *vb,
enum v4l2_field field)
{
- struct omap34xxcam_fh *fh = vbq->priv_data;
- struct omap34xxcam_videodev *vdev = fh->vdev;
+ struct v4l2_fh *vfh = vbq->priv_data;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct device *isp = vdev->cam->isp;
+
int err = 0;
/*
@@ -274,13 +295,19 @@
vb->field = field;
if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ err = omap34xxcam_vb_lock_vma(vb, 1);
+ if (err)
+ goto buf_init_err;
+
err = videobuf_iolock(vbq, vb, NULL);
- if (!err) {
- /* isp_addr will be stored locally inside isp code */
- err = isp_vbq_prepare(vbq, vb, field);
- }
+ if (err)
+ goto buf_init_err;
+
+ /* isp_addr will be stored locally inside isp code */
+ err = isp_vbq_prepare(isp, vbq, vb, field);
}
+buf_init_err:
if (!err)
vb->state = VIDEOBUF_PREPARED;
else
@@ -301,11 +328,12 @@
static void omap34xxcam_vbq_queue(struct videobuf_queue *vbq,
struct videobuf_buffer *vb)
{
- struct omap34xxcam_fh *fh = vbq->priv_data;
+ struct v4l2_fh *vfh = vbq->priv_data;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct device *isp = vdev->cam->isp;
- vb->state = VIDEOBUF_ACTIVE;
-
- isp_buf_queue(vb, omap34xxcam_vbq_complete, (void *)fh);
+ isp_buf_queue(isp, vb, omap34xxcam_vbq_complete, (void *)vfh);
}
static struct videobuf_queue_ops omap34xxcam_vbq_ops = {
@@ -329,10 +357,11 @@
*
* Fill in the V4L2 capabliity structure for the camera device
*/
-static int vidioc_querycap(struct file *file, void *fh,
+static int vidioc_querycap(struct file *file, void *_fh,
struct v4l2_capability *cap)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
strlcpy(cap->driver, CAM_SHORT_NAME, sizeof(cap->driver));
@@ -353,10 +382,11 @@
* Fills in enumerate format capabilities information for sensor (if SOC
* sensor attached) or ISP (if raw sensor attached).
*/
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *_fh,
struct v4l2_fmtdesc *f)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
int rval;
@@ -380,10 +410,11 @@
* Fills in format capabilities for sensor (if SOC sensor attached) or ISP
* (if raw sensor attached).
*/
-static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh,
struct v4l2_format *f)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
if (vdev->vdev_sensor == v4l2_int_device_dummy())
@@ -405,6 +436,7 @@
int fmtd_index;
int rval;
struct v4l2_pix_format best_pix_out;
+ struct device *isp = vdev->cam->isp;
if (best_ival->numerator == 0
|| best_ival->denominator == 0)
@@ -412,6 +444,8 @@
fps = best_ival->denominator / best_ival->numerator;
+ memset(best_pix_in, 0, sizeof(*best_pix_in));
+
best_ival->denominator = 0;
best_pix_out.height = INT_MAX >> 1;
best_pix_out.width = best_pix_out.height;
@@ -425,8 +459,8 @@
rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
if (rval)
break;
- dev_info(&vdev->vfd->dev, "trying fmt %8.8x (%d)\n",
- fmtd.pixelformat, fmtd_index);
+ dev_dbg(&vdev->vfd->dev, "trying fmt %8.8x (%d)\n",
+ fmtd.pixelformat, fmtd_index);
/*
* Get supported resolutions.
*/
@@ -447,19 +481,19 @@
pix_tmp_in.width = frms.discrete.width;
pix_tmp_in.height = frms.discrete.height;
pix_tmp_out = *wanted_pix_out;
- rval = isp_try_fmt_cap(&pix_tmp_in, &pix_tmp_out);
+ rval = isp_try_fmt_cap(isp, &pix_tmp_in, &pix_tmp_out);
if (rval)
return rval;
- dev_info(&vdev->vfd->dev, "this w %d\th %d\tfmt %8.8x\t"
- "-> w %d\th %d\t fmt %8.8x"
- "\twanted w %d\th %d\t fmt %8.8x\n",
- pix_tmp_in.width, pix_tmp_in.height,
- pix_tmp_in.pixelformat,
- pix_tmp_out.width, pix_tmp_out.height,
- pix_tmp_out.pixelformat,
- wanted_pix_out->width, wanted_pix_out->height,
- wanted_pix_out->pixelformat);
+ dev_dbg(&vdev->vfd->dev, "this w %d\th %d\tfmt %8.8x\t"
+ "-> w %d\th %d\t fmt %8.8x"
+ "\twanted w %d\th %d\t fmt %8.8x\n",
+ pix_tmp_in.width, pix_tmp_in.height,
+ pix_tmp_in.pixelformat,
+ pix_tmp_out.width, pix_tmp_out.height,
+ pix_tmp_out.pixelformat,
+ wanted_pix_out->width, wanted_pix_out->height,
+ wanted_pix_out->pixelformat);
#define IS_SMALLER_OR_EQUAL(pix1, pix2) \
((pix1)->width + (pix1)->height \
@@ -474,11 +508,11 @@
*/
if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
> SIZE_DIFF(&best_pix_out, wanted_pix_out)) {
- dev_info(&vdev->vfd->dev, "size diff bigger: "
- "w %d\th %d\tw %d\th %d\n",
- pix_tmp_out.width, pix_tmp_out.height,
- best_pix_out.width,
- best_pix_out.height);
+ dev_dbg(&vdev->vfd->dev, "size diff bigger: "
+ "w %d\th %d\tw %d\th %d\n",
+ pix_tmp_out.width, pix_tmp_out.height,
+ best_pix_out.width,
+ best_pix_out.height);
continue;
}
@@ -490,11 +524,11 @@
< SIZE_DIFF(&best_pix_out, wanted_pix_out)) {
/* Force renegotation of fps etc. */
best_ival->denominator = 0;
- dev_info(&vdev->vfd->dev, "renegotiate: "
- "w %d\th %d\tw %d\th %d\n",
- pix_tmp_out.width, pix_tmp_out.height,
- best_pix_out.width,
- best_pix_out.height);
+ dev_dbg(&vdev->vfd->dev, "renegotiate: "
+ "w %d\th %d\tw %d\th %d\n",
+ pix_tmp_out.width, pix_tmp_out.height,
+ best_pix_out.width,
+ best_pix_out.height);
}
for (ival_index = 0; ; ival_index++) {
@@ -512,13 +546,16 @@
if (rval)
break;
- dev_info(&vdev->vfd->dev, "fps %d\n",
- frmi.discrete.denominator
- / frmi.discrete.numerator);
+ dev_dbg(&vdev->vfd->dev, "fps %d\n",
+ frmi.discrete.denominator
+ / frmi.discrete.numerator);
if (best_ival->denominator == 0)
goto do_it_now;
+ if (best_pix_in->width == 0)
+ goto do_it_now;
+
/*
* We aim to use maximum resolution
* from the sensor, provided that the
@@ -530,11 +567,11 @@
/* Select mode with closest fps. */
if (FPS_ABS_DIFF(fps, frmi.discrete)
< FPS_ABS_DIFF(fps, *best_ival)) {
- dev_info(&vdev->vfd->dev, "closer fps: "
- "fps %d\t fps %d\n",
- FPS_ABS_DIFF(fps,
- frmi.discrete),
- FPS_ABS_DIFF(fps, *best_ival));
+ dev_dbg(&vdev->vfd->dev, "closer fps: "
+ "fps %d\t fps %d\n",
+ FPS_ABS_DIFF(fps,
+ frmi.discrete),
+ FPS_ABS_DIFF(fps, *best_ival));
goto do_it_now;
}
@@ -546,16 +583,16 @@
> best_pix_in->width + best_pix_in->height
&& FPS_ABS_DIFF(fps, frmi.discrete)
<= FPS_ABS_DIFF(fps, *best_ival)) {
- dev_info(&vdev->vfd->dev, "bigger res, "
- "same fps: "
- "w %d\th %d\tw %d\th %d\n",
- frmi.width, frmi.height,
- best_pix_in->width,
- best_pix_in->height);
+ dev_dbg(&vdev->vfd->dev, "bigger res, "
+ "same fps: "
+ "w %d\th %d\tw %d\th %d\n",
+ frmi.width, frmi.height,
+ best_pix_in->width,
+ best_pix_in->height);
goto do_it_now;
}
- dev_info(&vdev->vfd->dev, "falling through\n");
+ dev_dbg(&vdev->vfd->dev, "falling through\n");
continue;
@@ -566,14 +603,14 @@
best_pix_in->height = frmi.height;
best_pix_in->pixelformat = frmi.pixel_format;
- dev_info(&vdev->vfd->dev,
- "best_pix_in: w %d\th %d\tfmt %8.8x"
- "\tival %d/%d\n",
- best_pix_in->width,
- best_pix_in->height,
- best_pix_in->pixelformat,
- best_ival->numerator,
- best_ival->denominator);
+ dev_dbg(&vdev->vfd->dev,
+ "best_pix_in: w %d\th %d\tfmt %8.8x"
+ "\tival %d/%d\n",
+ best_pix_in->width,
+ best_pix_in->height,
+ best_pix_in->pixelformat,
+ best_ival->numerator,
+ best_ival->denominator);
}
}
}
@@ -588,7 +625,7 @@
best_pix_in->pixelformat,
best_pix_out.width, best_pix_out.height);
- return isp_try_fmt_cap(best_pix_in, wanted_pix_out);
+ return 0;
}
static int s_pix_parm(struct omap34xxcam_videodev *vdev,
@@ -596,20 +633,23 @@
struct v4l2_pix_format *pix,
struct v4l2_fract *best_ival)
{
+ struct device *isp = vdev->cam->isp;
struct v4l2_streamparm a;
struct v4l2_format fmt;
+ struct v4l2_format old_fmt;
int rval;
rval = try_pix_parm(vdev, best_pix, pix, best_ival);
if (rval)
return rval;
- rval = isp_s_fmt_cap(best_pix, pix);
+ rval = isp_s_fmt_cap(isp, best_pix, pix);
if (rval)
return rval;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix = *best_pix;
+ vidioc_int_g_fmt_cap(vdev->vdev_sensor, &old_fmt);
rval = vidioc_int_s_fmt_cap(vdev->vdev_sensor, &fmt);
if (rval)
return rval;
@@ -630,10 +670,11 @@
* Attempts to set input format with the sensor driver (first) and then the
* ISP. Returns the return code from vidioc_g_fmt_vid_cap().
*/
-static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *_fh,
struct v4l2_format *f)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
struct v4l2_pix_format pix_tmp;
struct v4l2_fract timeperframe;
@@ -671,10 +712,11 @@
* Checks if the given format is supported by the sensor driver and
* by the ISP.
*/
-static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *_fh,
struct v4l2_format *f)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
struct v4l2_pix_format pix_tmp;
struct v4l2_fract timeperframe;
@@ -703,10 +745,11 @@
* Attempts to get a buffer from the buffer queue associated with the
* fh through the video buffer library API.
*/
-static int vidioc_reqbufs(struct file *file, void *fh,
+static int vidioc_reqbufs(struct file *file, void *_fh,
struct v4l2_requestbuffers *b)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
int rval;
@@ -743,9 +786,10 @@
* Attempts to fill in the v4l2_buffer structure for the buffer queue
* associated with the fh through the video buffer library API.
*/
-static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+static int vidioc_querybuf(struct file *file, void *_fh, struct v4l2_buffer *b)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
return videobuf_querybuf(&ofh->vbq, b);
}
@@ -759,9 +803,10 @@
* Attempts to queue the v4l2_buffer on the buffer queue
* associated with the fh through the video buffer library API.
*/
-static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+static int vidioc_qbuf(struct file *file, void *_fh, struct v4l2_buffer *b)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
return videobuf_qbuf(&ofh->vbq, b);
}
@@ -777,33 +822,45 @@
* buffer is a user space buffer, then this function will also requeue it,
* as user does not expect to do this.
*/
-static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+static int vidioc_dqbuf(struct file *file, void *_fh, struct v4l2_buffer *b)
{
- struct omap34xxcam_fh *ofh = fh;
- int rval;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
-videobuf_dqbuf_again:
- rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
-
- /*
- * This is a hack. We don't want to show -EIO to the user
- * space. Requeue the buffer and try again if we're not doing
- * this in non-blocking mode.
- */
- if (rval == -EIO) {
- videobuf_qbuf(&ofh->vbq, b);
- if (!(file->f_flags & O_NONBLOCK))
- goto videobuf_dqbuf_again;
- /*
- * We don't have a videobuf_buffer now --- maybe next
- * time...
- */
- rval = -EAGAIN;
- }
-
- return rval;
+ return videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);;
}
+static void omap34xxcam_event_queue(struct omap34xxcam_fh *fh, u32 type)
+{
+ struct v4l2_event event;
+
+ dev_dbg(&fh->vdev->vfd->dev, "event type %8.8x\n", type);
+
+ event.type = type;
+ ktime_get_ts(&event.timestamp);
+
+ v4l2_event_queue(fh->vdev->vfd, &event);
+}
+
+static void omap34xxcam_event_cb(unsigned long status, int (*arg1)
+ (struct videobuf_buffer *vb), void *arg2)
+{
+ struct v4l2_fh *vfh = (struct v4l2_fh *)arg1;
+ struct omap34xxcam_fh *fh = to_omap34xxcam_fh(vfh);
+
+ if (status & HIST_DONE)
+ omap34xxcam_event_queue(fh, V4L2_EVENT_OMAP3ISP_HIST);
+ if (status & H3A_AWB_DONE)
+ omap34xxcam_event_queue(fh, V4L2_EVENT_OMAP3ISP_AEWB);
+ if (status & H3A_AF_DONE)
+ omap34xxcam_event_queue(fh, V4L2_EVENT_OMAP3ISP_AF);
+ if (status & HS_VS)
+ omap34xxcam_event_queue(fh, V4L2_EVENT_OMAP3ISP_HS_VS);
+
+ wake_up_all(&fh->vdev->poll_event);
+}
+
+
/**
* vidioc_streamon - V4L2 streamon IOCTL handler
* @file: ptr. to system file structure
@@ -814,10 +871,12 @@
* on video buffer streaming through the video buffer library API. Upon
* success the function returns 0, otherwise an error code is returned.
*/
-static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+static int vidioc_streamon(struct file *file, void *_fh, enum v4l2_buf_type i)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct device *isp = vdev->cam->isp;
int rval;
if (vdev->vdev_sensor == v4l2_int_device_dummy())
@@ -830,19 +889,24 @@
}
rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
- OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
+ OMAP34XXCAM_SLAVE_POWER_ALL);
if (rval) {
dev_dbg(&vdev->vfd->dev,
"omap34xxcam_slave_power_set failed\n");
goto out;
}
+ isp_set_callback(isp, CBK_CATCHALL, omap34xxcam_event_cb,
+ (void *)vfh, NULL);
+ isp_start(isp);
+
rval = videobuf_streamon(&ofh->vbq);
- if (rval)
+ if (rval) {
+ isp_stop(isp);
omap34xxcam_slave_power_set(
- vdev, V4L2_POWER_OFF,
- OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
- else
+ vdev, V4L2_POWER_STANDBY,
+ OMAP34XXCAM_SLAVE_POWER_ALL);
+ } else
vdev->streaming = file;
out:
@@ -862,26 +926,27 @@
* off video buffer streaming through the video buffer library API. Upon
* success the function returns 0, otherwise an error code is returned.
*/
-static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+static int vidioc_streamoff(struct file *file, void *_fh, enum v4l2_buf_type i)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct device *isp = vdev->cam->isp;
struct videobuf_queue *q = &ofh->vbq;
int rval;
mutex_lock(&vdev->mutex);
if (vdev->streaming == file)
- isp_stop();
+ isp_stop(isp);
rval = videobuf_streamoff(q);
if (!rval) {
+ isp_unset_callback(isp, CBK_CATCHALL);
vdev->streaming = NULL;
omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
- OMAP34XXCAM_SLAVE_POWER_SENSOR);
- omap34xxcam_slave_power_suggest(vdev, V4L2_POWER_STANDBY,
- OMAP34XXCAM_SLAVE_POWER_LENS);
+ OMAP34XXCAM_SLAVE_POWER_ALL);
}
mutex_unlock(&vdev->mutex);
@@ -897,7 +962,7 @@
*
* Fills in v4l2_input structure. Returns 0.
*/
-static int vidioc_enum_input(struct file *file, void *fh,
+static int vidioc_enum_input(struct file *file, void *_fh,
struct v4l2_input *inp)
{
if (inp->index > 0)
@@ -917,7 +982,7 @@
*
* Sets index to 0.
*/
-static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+static int vidioc_g_input(struct file *file, void *_fh, unsigned int *i)
{
*i = 0;
@@ -932,7 +997,7 @@
*
* 0 is only index supported.
*/
-static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+static int vidioc_s_input(struct file *file, void *_fh, unsigned int i)
{
if (i > 0)
return -EINVAL;
@@ -953,10 +1018,11 @@
* queried and if it does not support the requested control, the request
* is forwarded to the "raw" sensor driver to see if it supports it.
*/
-static int vidioc_queryctrl(struct file *file, void *fh,
+static int vidioc_queryctrl(struct file *file, void *_fh,
struct v4l2_queryctrl *a)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
struct v4l2_queryctrl a_tmp;
int best_slave = -1;
@@ -1018,10 +1084,11 @@
* menu control, the request is forwarded to the "raw" sensor driver to
* see if it supports it.
*/
-static int vidioc_querymenu(struct file *file, void *fh,
+static int vidioc_querymenu(struct file *file, void *_fh,
struct v4l2_querymenu *a)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
int i;
@@ -1036,11 +1103,13 @@
return isp_querymenu(a);
}
-static int vidioc_g_ext_ctrls(struct file *file, void *fh,
+static int vidioc_g_ext_ctrls(struct file *file, void *_fh,
struct v4l2_ext_controls *a)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct device *isp = vdev->cam->isp;
int i, ctrl_idx, rval = 0;
mutex_lock(&vdev->mutex);
@@ -1061,7 +1130,7 @@
}
if (rval)
- rval = isp_g_ctrl(&ctrl);
+ rval = isp_g_ctrl(isp, &ctrl);
if (rval) {
a->error_idx = ctrl_idx;
@@ -1076,11 +1145,13 @@
return rval;
}
-static int vidioc_s_ext_ctrls(struct file *file, void *fh,
+static int vidioc_s_ext_ctrls(struct file *file, void *_fh,
struct v4l2_ext_controls *a)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct device *isp = vdev->cam->isp;
int i, ctrl_idx, rval = 0;
mutex_lock(&vdev->mutex);
@@ -1102,7 +1173,7 @@
}
if (rval)
- rval = isp_s_ctrl(&ctrl);
+ rval = isp_s_ctrl(isp, &ctrl);
if (rval) {
a->error_idx = ctrl_idx;
@@ -1126,9 +1197,11 @@
* If request is for video capture buffer type, handles request by
* forwarding to sensor driver.
*/
-static int vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+static int vidioc_g_parm(struct file *file, void *_fh,
+ struct v4l2_streamparm *a)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
int rval;
@@ -1154,9 +1227,11 @@
* enable the sensor interface with the new parameters. If this fails, it
* reverts back to the previous parameters.
*/
-static int vidioc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+static int vidioc_s_parm(struct file *file, void *_fh,
+ struct v4l2_streamparm *a)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
struct v4l2_pix_format pix_tmp_sensor, pix_tmp;
int rval;
@@ -1195,9 +1270,10 @@
* If using a "smart" sensor, just forwards request to the sensor driver,
* otherwise fills in the v4l2_cropcap values locally.
*/
-static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+static int vidioc_cropcap(struct file *file, void *_fh, struct v4l2_cropcap *a)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
struct v4l2_cropcap *cropcap = a;
int rval;
@@ -1211,6 +1287,7 @@
if (rval && !vdev->vdev_sensor_config.sensor_isp) {
struct v4l2_format f;
+ struct v4l2_rect pixel_size;
/* cropcap failed, try to do this via g_fmt_cap */
rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &f);
@@ -1220,8 +1297,30 @@
cropcap->bounds.width = f.fmt.pix.width;
cropcap->bounds.height = f.fmt.pix.height;
cropcap->defrect = cropcap->bounds;
- cropcap->pixelaspect.numerator = 1;
- cropcap->pixelaspect.denominator = 1;
+ }
+
+ rval = vidioc_int_priv_g_pixelsize(vdev->vdev_sensor,
+ &pixel_size);
+ if (!rval) {
+ if (pixel_size.width && pixel_size.height) {
+ /* Normalize value */
+ while (!((pixel_size.width |
+ pixel_size.height) & 0x01)) {
+
+ pixel_size.width >>= 1;
+ pixel_size.height >>= 1;
+ }
+ cropcap->pixelaspect.numerator =
+ pixel_size.width;
+ cropcap->pixelaspect.denominator =
+ pixel_size.height;
+ } else {
+ dev_err(&vdev->vfd->dev, "Sensor return invalid"
+ " result for pixelsize: %d x %d",
+ pixel_size.width, pixel_size.height);
+ cropcap->pixelaspect.numerator = 1;
+ cropcap->pixelaspect.denominator = 1;
+ }
}
}
@@ -1239,10 +1338,12 @@
* If using a "smart" sensor, just forwards request to the sensor driver,
* otherwise calls the isp functions to fill in current crop values.
*/
-static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+static int vidioc_g_crop(struct file *file, void *_fh, struct v4l2_crop *a)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct device *isp = vdev->cam->isp;
int rval = 0;
if (vdev->vdev_sensor == v4l2_int_device_dummy())
@@ -1253,7 +1354,7 @@
if (vdev->vdev_sensor_config.sensor_isp)
rval = vidioc_int_g_crop(vdev->vdev_sensor, a);
else
- rval = isp_g_crop(a);
+ rval = isp_g_crop(isp, a);
mutex_unlock(&vdev->mutex);
@@ -1269,10 +1370,12 @@
* If using a "smart" sensor, just forwards request to the sensor driver,
* otherwise calls the isp functions to set the current crop values.
*/
-static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+static int vidioc_s_crop(struct file *file, void *_fh, struct v4l2_crop *a)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct device *isp = vdev->cam->isp;
int rval = 0;
if (vdev->vdev_sensor == v4l2_int_device_dummy())
@@ -1283,59 +1386,176 @@
if (vdev->vdev_sensor_config.sensor_isp)
rval = vidioc_int_s_crop(vdev->vdev_sensor, a);
else
- rval = isp_s_crop(a, &vdev->pix);
+ rval = isp_s_crop(isp, a);
mutex_unlock(&vdev->mutex);
return rval;
}
-static int vidioc_enum_framesizes(struct file *file, void *fh,
+static int vidioc_enum_framesizes(struct file *file, void *_fh,
struct v4l2_frmsizeenum *frms)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct v4l2_pix_format pix_in;
+ struct v4l2_pix_format pix_out;
+ struct v4l2_fract ival;
u32 pixel_format;
int rval;
+ if (vdev->vdev_sensor == v4l2_int_device_dummy())
+ return -EINVAL;
+
mutex_lock(&vdev->mutex);
if (vdev->vdev_sensor_config.sensor_isp) {
rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
- } else {
- pixel_format = frms->pixel_format;
- frms->pixel_format = -1; /* ISP does format conversion */
- rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
- frms->pixel_format = pixel_format;
+ goto done;
}
+ pixel_format = frms->pixel_format;
+ frms->pixel_format = -1; /* ISP does format conversion */
+ rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
+ frms->pixel_format = pixel_format;
+
+ if (rval < 0)
+ goto done;
+
+ /* Let the ISP pipeline mangle the frame size as it sees fit. */
+ memset(&pix_out, 0, sizeof(pix_out));
+ pix_out.width = frms->discrete.width;
+ pix_out.height = frms->discrete.height;
+ pix_out.pixelformat = frms->pixel_format;
+
+ ival = vdev->want_timeperframe;
+ rval = try_pix_parm(vdev, &pix_in, &pix_out, &ival);
+ if (rval < 0)
+ goto done;
+
+ frms->discrete.width = pix_out.width;
+ frms->discrete.height = pix_out.height;
+
+done:
mutex_unlock(&vdev->mutex);
return rval;
}
-static int vidioc_enum_frameintervals(struct file *file, void *fh,
+static int vidioc_enum_frameintervals(struct file *file, void *_fh,
struct v4l2_frmivalenum *frmi)
{
- struct omap34xxcam_fh *ofh = fh;
+ struct v4l2_fh *vfh = _fh;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct v4l2_frmsizeenum frms;
+ unsigned int frmi_width;
+ unsigned int frmi_height;
+ unsigned int uninitialized_var(width);
+ unsigned int uninitialized_var(height);
+ unsigned int max_dist;
+ unsigned int dist;
u32 pixel_format;
+ unsigned int i;
int rval;
mutex_lock(&vdev->mutex);
if (vdev->vdev_sensor_config.sensor_isp) {
rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
- } else {
- pixel_format = frmi->pixel_format;
- frmi->pixel_format = -1; /* ISP does format conversion */
- rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
- frmi->pixel_format = pixel_format;
+ goto done;
}
+ /*
+ * Frame size enumeration returned sizes mangled by the ISP.
+ * We can't pass the size directly to the sensor for frame
+ * interval enumeration, as they will not be recognized by the
+ * sensor driver. Enumerate the native sensor sizes and select
+ * the one closest to the requested size.
+ */
+
+ for (i = 0, max_dist = (unsigned int)-1; ; ++i) {
+ frms.index = i;
+ frms.pixel_format = -1;
+ rval = vidioc_int_enum_framesizes(vdev->vdev_sensor,
+ &frms);
+ if (rval < 0)
+ break;
+
+ /*
+ * The distance between frame sizes is the size in
+ * pixels of the non-overlapping regions.
+ */
+ dist = min(frms.discrete.width, frmi->width)
+ * min(frms.discrete.height, frmi->height);
+ dist = frms.discrete.width * frms.discrete.height
+ + frmi->width * frmi->height
+ - 2*dist;
+
+ if (dist < max_dist) {
+ width = frms.discrete.width;
+ height = frms.discrete.height;
+ max_dist = dist;
+ }
+ }
+
+ if (max_dist == (unsigned int)-1) {
+ rval = -EINVAL;
+ goto done;
+ }
+
+ pixel_format = frmi->pixel_format;
+ frmi_width = frmi->width;
+ frmi_height = frmi->height;
+
+ frmi->pixel_format = -1; /* ISP does format conversion */
+ frmi->width = width;
+ frmi->height = height;
+ rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
+
+ frmi->pixel_format = pixel_format;
+ frmi->height = frmi_height;
+ frmi->width = frmi_width;
+
+done:
mutex_unlock(&vdev->mutex);
return rval;
}
+
+int vidioc_dqevent(struct v4l2_fh *vfh, struct v4l2_event *ev)
+{
+ return v4l2_event_dequeue(&vfh->events, ev);
+}
+
+int vidioc_subscribe_event(struct v4l2_fh *vfh,
+ struct v4l2_event_subscription *sub)
+{
+ struct omap34xxcam_fh *fh = to_omap34xxcam_fh(vfh);
+
+ switch (sub->type) {
+ case V4L2_EVENT_OMAP3ISP_AF:
+ case V4L2_EVENT_OMAP3ISP_AEWB:
+ case V4L2_EVENT_OMAP3ISP_HIST:
+ case V4L2_EVENT_OMAP3ISP_HS_VS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return v4l2_event_subscribe(&fh->vfh.events, sub);
+}
+
+int vidioc_unsubscribe_event(struct v4l2_fh *vfh,
+ struct v4l2_event_subscription *sub)
+{
+ struct omap34xxcam_fh *fh = to_omap34xxcam_fh(vfh);
+
+ v4l2_event_unsubscribe(&fh->vfh.events, sub);
+
+ return 0;
+}
+
/**
* vidioc_default - private IOCTL handler
* @file: ptr. to system file structure
@@ -1350,12 +1570,54 @@
* feedback. The request is then passed on to the ISP private IOCTL handler,
* isp_handle_private()
*/
-static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+static long vidioc_default(struct file *file, void *_fh, int cmd, void *arg)
{
- struct omap34xxcam_fh *ofh = file->private_data;
+ struct v4l2_fh *vfh = file->private_data;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct device *isp = vdev->cam->isp;
int rval;
+ if (cmd == VIDIOC_PRIVATE_OMAP34XXCAM_SENSOR_INFO) {
+ u32 pixclk;
+ struct v4l2_rect active_size, full_size, pixel_size;
+ struct omap34xxcam_sensor_info *ret_sensor_info;
+
+ ret_sensor_info = (struct omap34xxcam_sensor_info *)arg;
+ mutex_lock(&vdev->mutex);
+ rval = vidioc_int_priv_g_pixclk(vdev->vdev_sensor, &pixclk);
+ mutex_unlock(&vdev->mutex);
+ if (rval)
+ goto out;
+ mutex_lock(&vdev->mutex);
+ rval = vidioc_int_priv_g_activesize(vdev->vdev_sensor,
+ &active_size);
+ mutex_unlock(&vdev->mutex);
+ if (rval)
+ goto out;
+ mutex_lock(&vdev->mutex);
+ rval = vidioc_int_priv_g_fullsize(vdev->vdev_sensor,
+ &full_size);
+ mutex_unlock(&vdev->mutex);
+ if (rval)
+ goto out;
+ mutex_lock(&vdev->mutex);
+ rval = vidioc_int_priv_g_pixelsize(vdev->vdev_sensor,
+ &pixel_size);
+ mutex_unlock(&vdev->mutex);
+ if (rval)
+ goto out;
+ ret_sensor_info->current_xclk = pixclk;
+ memcpy(&ret_sensor_info->active_size, &active_size,
+ sizeof(struct v4l2_rect));
+ memcpy(&ret_sensor_info->full_size, &full_size,
+ sizeof(struct v4l2_rect));
+ memcpy(&ret_sensor_info->pixel_size, &pixel_size,
+ sizeof(struct v4l2_rect));
+ rval = 0;
+ goto out;
+ }
+
if (vdev->vdev_sensor_config.sensor_isp) {
rval = -EINVAL;
} else {
@@ -1421,9 +1683,7 @@
break;
}
- mutex_lock(&vdev->mutex);
- rval = isp_handle_private(cmd, arg);
- mutex_unlock(&vdev->mutex);
+ rval = isp_handle_private(isp, &vdev->mutex, cmd, arg);
}
out:
return rval;
@@ -1444,31 +1704,29 @@
static unsigned int omap34xxcam_poll(struct file *file,
struct poll_table_struct *wait)
{
- struct omap34xxcam_fh *fh = file->private_data;
- struct omap34xxcam_videodev *vdev = fh->vdev;
- struct videobuf_buffer *vb;
+ struct v4l2_fh *vfh = file->private_data;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+ unsigned int ret = 0;
- mutex_lock(&vdev->mutex);
- if (vdev->streaming != file) {
- mutex_unlock(&vdev->mutex);
- return POLLERR;
+ poll_wait(file, &ofh->vdev->poll_event, wait);
+
+ if (v4l2_event_pending(&vfh->events))
+ ret |= POLLPRI;
+
+ poll_wait(file, &ofh->poll_vb, wait);
+
+ mutex_lock(&ofh->vbq.vb_lock);
+ if (!list_empty(&ofh->vbq.stream)) {
+ struct videobuf_buffer *vb =
+ list_entry(ofh->vbq.stream.next,
+ struct videobuf_buffer, stream);
+ if (vb->state == VIDEOBUF_DONE
+ || vb->state == VIDEOBUF_ERROR)
+ ret |= POLLIN | POLLRDNORM;
}
- mutex_unlock(&vdev->mutex);
+ mutex_unlock(&ofh->vbq.vb_lock);
- mutex_lock(&fh->vbq.vb_lock);
- if (list_empty(&fh->vbq.stream)) {
- mutex_unlock(&fh->vbq.vb_lock);
- return POLLERR;
- }
- vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
- mutex_unlock(&fh->vbq.vb_lock);
-
- poll_wait(file, &vb->done, wait);
-
- if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
- return POLLIN | POLLRDNORM;
-
- return 0;
+ return ret;
}
/**
@@ -1480,8 +1738,10 @@
*/
static int omap34xxcam_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct omap34xxcam_fh *fh = file->private_data;
- return videobuf_mmap_mapper(&fh->vbq, vma);
+ struct v4l2_fh *vfh = file->private_data;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+
+ return videobuf_mmap_mapper(&ofh->vbq, vma);
}
/**
@@ -1502,9 +1762,11 @@
{
int rval = 0;
struct omap34xxcam_videodev *vdev = NULL;
+ struct omap34xxcam_fh *ofh;
struct omap34xxcam_device *cam = omap34xxcam;
- struct omap34xxcam_fh *fh;
- struct v4l2_format format;
+ struct device *isp;
+ struct v4l2_format sensor_format;
+ int first_user = 0;
int i;
for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
@@ -1519,10 +1781,17 @@
if (!vdev || !vdev->vfd)
return -ENODEV;
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (fh == NULL)
+ ofh = kzalloc(sizeof(*ofh), GFP_KERNEL);
+ if (ofh == NULL)
return -ENOMEM;
+ if (v4l2_fh_add(vdev->vfd, &ofh->vfh)) {
+ rval = -ENOMEM;
+ goto out_v4l2_fh_add;
+ }
+
+ ofh->vdev = vdev;
+
mutex_lock(&vdev->mutex);
for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
if (vdev->slave[i] != v4l2_int_device_dummy()
@@ -1536,56 +1805,62 @@
}
if (atomic_inc_return(&vdev->users) == 1) {
- rval = isp_get();
- if (rval < 0) {
+ first_user = 1;
+ isp = isp_get();
+ if (!isp) {
+ rval = -EBUSY;
dev_err(&vdev->vfd->dev, "can't get isp\n");
goto out_isp_get;
}
- if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+ cam->isp = isp;
+ if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
OMAP34XXCAM_SLAVE_POWER_ALL)) {
dev_err(&vdev->vfd->dev, "can't power up slaves\n");
rval = -EBUSY;
goto out_slave_power_set_standby;
}
- omap34xxcam_slave_power_set(
- vdev, V4L2_POWER_STANDBY,
- OMAP34XXCAM_SLAVE_POWER_SENSOR);
- omap34xxcam_slave_power_suggest(
- vdev, V4L2_POWER_STANDBY,
- OMAP34XXCAM_SLAVE_POWER_LENS);
}
- fh->vdev = vdev;
+ if (vdev->vdev_sensor == v4l2_int_device_dummy() || !first_user)
+ goto out_no_pix;
- if (!vdev->pix.width
- && vdev->vdev_sensor != v4l2_int_device_dummy()) {
- memset(&format, 0, sizeof(format));
- if (vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format)) {
+ /* Get the format the sensor is using. */
+ rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &sensor_format);
+ if (rval) {
+ dev_err(&vdev->vfd->dev,
+ "can't get current pix from sensor!\n");
+ goto out_vidioc_int_g_fmt_cap;
+ }
+
+ if (!vdev->pix.width)
+ vdev->pix = sensor_format.fmt.pix;
+
+ if (!vdev->vdev_sensor_config.sensor_isp) {
+ struct v4l2_pix_format pix;
+ struct v4l2_fract timeperframe =
+ vdev->want_timeperframe;
+
+ rval = s_pix_parm(vdev, &pix, &vdev->pix, &timeperframe);
+ if (rval) {
dev_err(&vdev->vfd->dev,
- "can't get current pix from sensor!\n");
- goto out_vidioc_int_g_fmt_cap;
+ "isp doesn't like the sensor!\n");
+ goto out_isp_s_fmt_cap;
}
- if (!vdev->vdev_sensor_config.sensor_isp) {
- struct v4l2_pix_format pix = format.fmt.pix;
- if (isp_s_fmt_cap(&pix, &format.fmt.pix)) {
- dev_err(&vdev->vfd->dev,
- "isp doesn't like the sensor!\n");
- goto out_isp_s_fmt_cap;
- }
- }
- vdev->pix = format.fmt.pix;
}
+out_no_pix:
mutex_unlock(&vdev->mutex);
- file->private_data = fh;
+ file->private_data = &ofh->vfh;
- spin_lock_init(&fh->vbq_lock);
+ spin_lock_init(&ofh->vbq_lock);
- videobuf_queue_sg_init(&fh->vbq, &omap34xxcam_vbq_ops, NULL,
- &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_NONE,
- sizeof(struct videobuf_buffer), fh);
+ videobuf_queue_sg_init(&ofh->vbq, &omap34xxcam_vbq_ops, NULL,
+ &ofh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), &ofh->vfh);
+
+ init_waitqueue_head(&ofh->poll_vb);
return 0;
@@ -1605,7 +1880,10 @@
if (vdev->slave[i] != v4l2_int_device_dummy())
module_put(vdev->slave[i]->module);
- kfree(fh);
+out_v4l2_fh_add:
+ v4l2_fh_del(vdev->vfd, &ofh->vfh);
+
+ kfree(ofh);
return rval;
}
@@ -1625,20 +1903,19 @@
*/
static int omap34xxcam_release(struct file *file)
{
- struct omap34xxcam_fh *fh = file->private_data;
- struct omap34xxcam_videodev *vdev = fh->vdev;
+ struct v4l2_fh *vfh = file->private_data;
+ struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct device *isp = vdev->cam->isp;
int i;
mutex_lock(&vdev->mutex);
if (vdev->streaming == file) {
- isp_stop();
- videobuf_streamoff(&fh->vbq);
- omap34xxcam_slave_power_set(
- vdev, V4L2_POWER_STANDBY,
- OMAP34XXCAM_SLAVE_POWER_SENSOR);
- omap34xxcam_slave_power_suggest(
- vdev, V4L2_POWER_STANDBY,
- OMAP34XXCAM_SLAVE_POWER_LENS);
+ isp_stop(isp);
+ videobuf_streamoff(&ofh->vbq);
+ isp_unset_callback(isp, CBK_CATCHALL);
+ omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
+ OMAP34XXCAM_SLAVE_POWER_ALL);
vdev->streaming = NULL;
}
@@ -1655,7 +1932,9 @@
if (vdev->slave[i] != v4l2_int_device_dummy())
module_put(vdev->slave[i]->module);
- kfree(fh);
+ v4l2_fh_del(vdev->vfd, vfh);
+
+ kfree(ofh);
return 0;
}
@@ -1752,6 +2031,9 @@
.vidioc_s_crop = vidioc_s_crop,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
+ .vidioc_dqevent = vidioc_dqevent,
+ .vidioc_subscribe_event = vidioc_subscribe_event,
+ .vidioc_unsubscribe_event = vidioc_unsubscribe_event,
.vidioc_default = vidioc_default,
};
@@ -1771,6 +2053,7 @@
{
struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
struct omap34xxcam_hw_config hwc;
+ struct device *isp;
int rval;
/* We need to check rval just once. The place is here. */
@@ -1799,17 +2082,18 @@
vdev->slave_config[hwc.dev_type] = hwc;
if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
- rval = isp_get();
- if (rval < 0) {
+ isp = isp_get();
+ if (!isp) {
+ rval = -EBUSY;
printk(KERN_ERR "%s: can't get ISP, "
"sensor init failed\n", __func__);
goto err;
}
+ vdev->cam->isp = isp;
}
- rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
- 1 << hwc.dev_type);
+ rval = vidioc_int_dev_init(s);
if (rval)
- goto err_omap34xxcam_slave_power_set;
+ goto err_omap34xxcam_slave_init;
if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
struct v4l2_format format;
@@ -1824,11 +2108,10 @@
if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
isp_put();
- if (rval)
- goto err;
-
/* Are we the first slave? */
if (vdev->slaves == 1) {
+ init_waitqueue_head(&vdev->poll_event);
+
/* initialize the video_device struct */
vdev->vfd = video_device_alloc();
if (!vdev->vfd) {
@@ -1859,7 +2142,7 @@
return 0;
-err_omap34xxcam_slave_power_set:
+err_omap34xxcam_slave_init:
if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
isp_put();
@@ -1936,11 +2219,6 @@
vdev->vdev_sensor =
vdev->vdev_lens =
vdev->vdev_flash = v4l2_int_device_dummy();
-#ifdef OMAP34XXCAM_POWEROFF_DELAY
- setup_timer(&vdev->poweroff_timer,
- omap34xxcam_slave_power_timer, (unsigned long)vdev);
- INIT_WORK(&vdev->poweroff_work, omap34xxcam_slave_power_work);
-#endif /* OMAP34XXCAM_POWEROFF_DELAY */
if (v4l2_int_device_register(m))
goto err;
diff --git a/drivers/media/video/omap34xxcam.h b/drivers/media/video/omap34xxcam.h
index 9859d15..72ff434 100644
--- a/drivers/media/video/omap34xxcam.h
+++ b/drivers/media/video/omap34xxcam.h
@@ -36,13 +36,12 @@
#define OMAP34XXCAM_H
#include <media/v4l2-int-device.h>
+#include <media/v4l2-fh.h>
#include "isp/isp.h"
#define CAM_NAME "omap34xxcam"
#define CAM_SHORT_NAME "omap3"
-#define OMAP_ISP_AF (1 << 4)
-#define OMAP_ISP_HIST (1 << 5)
#define OMAP34XXCAM_XCLK_NONE -1
#define OMAP34XXCAM_XCLK_A 0
#define OMAP34XXCAM_XCLK_B 1
@@ -61,13 +60,16 @@
#define OMAP34XXCAM_VIDEODEVS 4
-/* #define OMAP34XXCAM_POWEROFF_DELAY (2 * HZ) */
-
struct omap34xxcam_device;
struct omap34xxcam_videodev;
+/**
+ * struct omap34xxcam_sensor_config - struct for vidioc_int_g_priv ioctl
+ * @sensor_isp: Is sensor smart/SOC or raw
+ * @capture_mem: Size limit to mmap buffers.
+ * @ival_default: Default frame interval for sensor.
+ */
struct omap34xxcam_sensor_config {
- int xclk;
int sensor_isp;
u32 capture_mem;
struct v4l2_fract ival_default;
@@ -79,13 +81,6 @@
struct omap34xxcam_flash_config {
};
-/**
- * struct omap34xxcam_hw_config - struct for vidioc_int_g_priv ioctl
- * @xclk: OMAP34XXCAM_XCLK_A or OMAP34XXCAM_XCLK_B
- * @sensor_isp: Is sensor smart/SOC or raw
- * @s_pix_sparm: Access function to set pix and sparm.
- * Pix will override sparm
- */
struct omap34xxcam_hw_config {
int dev_index; /* Index in omap34xxcam_sensors */
int dev_minor; /* Video device minor number */
@@ -107,8 +102,6 @@
* @flash: flash device
* @slaves: how many slaves we have at the moment
* @vfd: our video device
- * @capture_mem: maximum kernel-allocated capture memory
- * @if_u: sensor interface stuff
* @index: index of this structure in cam->vdevs
* @users: how many users we have
* @power_state: Current power state
@@ -119,10 +112,10 @@
* @sensor_config: ISP-speicific sensor configuration
* @lens_config: ISP-speicific lens configuration
* @flash_config: ISP-speicific flash configuration
+ * @streaming: streaming file handle, if streaming is enabled
* @want_timeperframe: Desired timeperframe
* @want_pix: Desired pix
* @pix: Current pix
- * @streaming: streaming file handle, if streaming is enabled
*/
struct omap34xxcam_videodev {
struct mutex mutex; /* serialises access to this structure */
@@ -140,54 +133,32 @@
/*** video device parameters ***/
struct video_device *vfd;
- int capture_mem;
/*** general driver state information ***/
int index;
atomic_t users;
enum v4l2_power power_state[OMAP34XXCAM_SLAVE_FLASH + 1];
-#ifdef OMAP34XXCAM_POWEROFF_DELAY
- enum v4l2_power power_state_wish;
- int power_state_mask;
- struct timer_list poweroff_timer;
- struct work_struct poweroff_work;
-#endif /* OMAP34XXCAM_POWEROFF_DELAY */
-
#define vdev_sensor_config slave_config[OMAP34XXCAM_SLAVE_SENSOR].u.sensor
#define vdev_lens_config slave_config[OMAP34XXCAM_SLAVE_LENS].u.lens
#define vdev_flash_config slave_config[OMAP34XXCAM_SLAVE_FLASH].u.flash
struct omap34xxcam_hw_config slave_config[OMAP34XXCAM_SLAVE_FLASH + 1];
+ wait_queue_head_t poll_event;
+
/*** capture data ***/
struct file *streaming;
struct v4l2_fract want_timeperframe;
struct v4l2_pix_format want_pix;
- spinlock_t pix_lock;
struct v4l2_pix_format pix;
};
/**
* struct omap34xxcam_device - per-device data structure
- * @mutex: mutex serialises access to this structure
- * @sgdma_in_queue: Number or sgdma requests in scatter-gather queue,
- * protected by the lock above.
- * @sgdma: ISP sgdma subsystem information structure
- * @dma_notify: DMA notify flag
- * @dev: device structure
* @vdevs: /dev/video specific structures
- * @fck: camera module fck clock information
- * @ick: camera module ick clock information
*/
struct omap34xxcam_device {
- struct mutex mutex; /* serialises access to this structure */
-
- /*** interfaces and device ***/
struct omap34xxcam_videodev vdevs[OMAP34XXCAM_VIDEODEVS];
-
- /*** camera module clocks ***/
- struct clk *fck;
- struct clk *ick;
- bool sensor_if_enabled;
+ struct device *isp;
};
/**
@@ -199,9 +170,11 @@
*/
struct omap34xxcam_fh {
spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+ struct v4l2_fh vfh;
struct videobuf_queue vbq;
atomic_t field_count;
struct omap34xxcam_videodev *vdev;
+ wait_queue_head_t poll_vb;
};
#endif /* ifndef OMAP34XXCAM_H */
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 110376b..032b232 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -1049,6 +1049,9 @@
case VIDIOC_DBG_G_CHIP_IDENT:
case VIDIOC_G_CHIP_IDENT_OLD:
case VIDIOC_S_HW_FREQ_SEEK:
+ case VIDIOC_DQEVENT:
+ case VIDIOC_SUBSCRIBE_EVENT:
+ case VIDIOC_UNSUBSCRIBE_EVENT:
ret = do_video_ioctl(file, cmd, arg);
break;
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 13f87c2..36de838 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -373,6 +373,10 @@
if (!vdev || !vdev->release)
return -EINVAL;
+ ret = v4l2_fh_init(vdev);
+ if (ret < 0)
+ return ret;
+
/* Part 1: check device type */
switch (type) {
case VFL_TYPE_GRABBER:
@@ -511,6 +515,7 @@
return 0;
cleanup:
+ v4l2_fh_exit(vdev);
mutex_lock(&videodev_lock);
if (vdev->cdev)
cdev_del(vdev->cdev);
@@ -565,6 +570,8 @@
return -EIO;
}
+ v4l2_event_init();
+
return 0;
}
@@ -572,6 +579,8 @@
{
dev_t dev = MKDEV(VIDEO_MAJOR, 0);
+ v4l2_event_exit();
+
class_unregister(&video_class);
unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
}
diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/video/v4l2-event.c
new file mode 100644
index 0000000..5d8d259
--- /dev/null
+++ b/drivers/media/video/v4l2-event.c
@@ -0,0 +1,250 @@
+/*
+ * drivers/media/video/v4l2-event.c
+ *
+ * V4L2 events.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus at maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-event.h>
+
+#include <linux/sched.h>
+
+static struct kmem_cache *event_kmem;
+
+int v4l2_event_init(void)
+{
+ event_kmem = kmem_cache_create("event_kmem",
+ sizeof(struct _v4l2_event), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL);
+
+ if (!event_kmem)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void v4l2_event_exit(void)
+{
+ if (!event_kmem)
+ kmem_cache_destroy(event_kmem);
+
+ event_kmem = NULL;
+}
+
+void v4l2_event_init_fh(struct v4l2_events *events)
+{
+ init_waitqueue_head(&events->wait);
+ spin_lock_init(&events->lock);
+
+ INIT_LIST_HEAD(&events->available);
+ INIT_LIST_HEAD(&events->subscribed);
+
+ atomic_set(&events->navailable, 0);
+ events->sequence = 0;
+};
+
+void v4l2_event_del(struct v4l2_events *events)
+{
+ while (!list_empty(&events->available)) {
+ struct _v4l2_event *ev;
+
+ ev = list_entry(events->available.next,
+ struct _v4l2_event, list);
+
+ list_del(&ev->list);
+
+ kmem_cache_free(event_kmem, ev);
+ }
+
+ while (!list_empty(&events->subscribed)) {
+ struct v4l2_subscribed_event *sub;
+
+ sub = list_entry(events->subscribed.next,
+ struct v4l2_subscribed_event, list);
+
+ list_del(&sub->list);
+
+ kfree(sub);
+ }
+}
+
+int v4l2_event_dequeue(struct v4l2_events *events, struct v4l2_event *event)
+{
+ struct _v4l2_event *ev;
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&events->lock, flags);
+
+ if (list_empty(&events->available)) {
+ spin_unlock_irqrestore(&events->lock, flags);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ev = list_first_entry(&events->available, struct _v4l2_event, list);
+ list_del(&ev->list);
+
+ atomic_dec(&events->navailable);
+ ev->event.count = atomic_read(&events->navailable);
+
+ spin_unlock_irqrestore(&events->lock, flags);
+
+ memcpy(event, &ev->event, sizeof(ev->event));
+
+ kmem_cache_free(event_kmem, ev);
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_dequeue);
+
+static struct v4l2_subscribed_event *__v4l2_event_subscribed(
+ struct v4l2_events *events, u32 type)
+{
+ struct v4l2_subscribed_event *ev;
+
+ list_for_each_entry(ev, &events->subscribed, list) {
+ if (ev->type == type)
+ return ev;
+ }
+
+ return NULL;
+}
+
+struct v4l2_subscribed_event *v4l2_event_subscribed(
+ struct v4l2_events *events, u32 type)
+{
+ struct v4l2_subscribed_event *ev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&events->lock, flags);
+
+ ev = __v4l2_event_subscribed(events, type);
+
+ spin_unlock_irqrestore(&events->lock, flags);
+
+ return ev;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_subscribed);
+
+void v4l2_event_queue(struct video_device *vdev, struct v4l2_event *ev)
+{
+ struct v4l2_fh *fh;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vdev->fh_lock, flags);
+
+ list_for_each_entry(fh, &vdev->fh, list) {
+ struct _v4l2_event *_ev;
+
+ if (atomic_read(&fh->events.navailable) >= V4L2_MAX_EVENTS)
+ continue;
+
+ if (!v4l2_event_subscribed(&fh->events, ev->type))
+ continue;
+
+ _ev = kmem_cache_alloc(event_kmem, GFP_ATOMIC);
+ if (!_ev)
+ continue;
+
+ _ev->event = *ev;
+
+ spin_lock(&fh->events.lock);
+ _ev->event.sequence = fh->events.sequence;
+ fh->events.sequence++;
+ list_add_tail(&_ev->list, &fh->events.available);
+ spin_unlock(&fh->events.lock);
+
+ atomic_inc(&fh->events.navailable);
+
+ wake_up_all(&fh->events.wait);
+ }
+
+ spin_unlock_irqrestore(&vdev->fh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(v4l2_event_queue);
+
+int v4l2_event_pending(struct v4l2_events *events)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&events->lock, flags);
+ ret = !list_empty(&events->available);
+ spin_unlock_irqrestore(&events->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_pending);
+
+int v4l2_event_subscribe(struct v4l2_events *events,
+ struct v4l2_event_subscription *sub)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct v4l2_subscribed_event *ev;
+
+ ev = kmalloc(sizeof(*ev), GFP_KERNEL);
+ if (!ev)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&events->lock, flags);
+
+ if (__v4l2_event_subscribed(events, sub->type) != NULL) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ INIT_LIST_HEAD(&ev->list);
+ ev->type = sub->type;
+
+ list_add(&ev->list, &events->subscribed);
+
+out:
+ spin_unlock_irqrestore(&events->lock, flags);
+
+ if (ret)
+ kfree(ev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_subscribe);
+
+int v4l2_event_unsubscribe(struct v4l2_events *events,
+ struct v4l2_event_subscription *sub)
+{
+ struct v4l2_subscribed_event *ev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&events->lock, flags);
+
+ ev = __v4l2_event_subscribed(events, sub->type);
+
+ if (ev != NULL)
+ list_del(&ev->list);
+
+ spin_unlock_irqrestore(&events->lock, flags);
+
+ return ev == NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_unsubscribe);
diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/video/v4l2-fh.c
new file mode 100644
index 0000000..ee2abb1
--- /dev/null
+++ b/drivers/media/video/v4l2-fh.c
@@ -0,0 +1,68 @@
+/*
+ * drivers/media/video/v4l2-fh.c
+ *
+ * V4L2 file handles.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus at maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+
+int v4l2_fh_add(struct video_device *vdev, struct v4l2_fh *fh)
+{
+ unsigned long flags;
+
+ v4l2_event_init_fh(&fh->events);
+
+ spin_lock_irqsave(&vdev->fh_lock, flags);
+ list_add(&fh->list, &vdev->fh);
+ spin_unlock_irqrestore(&vdev->fh_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_fh_add);
+
+void v4l2_fh_del(struct video_device *vdev, struct v4l2_fh *fh)
+{
+ unsigned long flags;
+
+ v4l2_event_del(&fh->events);
+
+ spin_lock_irqsave(&vdev->fh_lock, flags);
+ list_del(&fh->list);
+ spin_unlock_irqrestore(&vdev->fh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(v4l2_fh_del);
+
+int v4l2_fh_init(struct video_device *vdev)
+{
+ spin_lock_init(&vdev->fh_lock);
+ INIT_LIST_HEAD(&vdev->fh);
+
+ return 0;
+}
+
+void v4l2_fh_exit(struct video_device *vdev)
+{
+}
+
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 52d687b..31b90a0 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -268,6 +268,9 @@
[_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT",
[_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK",
+ [_IOC_NR(VIDIOC_DQEVENT)] = "VIDIOC_DQEVENT",
+ [_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)] = "VIDIOC_SUBSCRIBE_EVENT",
+ [_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT",
#endif
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
@@ -1837,7 +1840,55 @@
}
break;
}
+ case VIDIOC_DQEVENT:
+ {
+ struct v4l2_event *ev = arg;
+ if (!ops->vidioc_dqevent)
+ break;
+
+ ret = ops->vidioc_dqevent(file->private_data, ev);
+ if (ret < 0) {
+ dbgarg(cmd, "no pending events?");
+ break;
+ }
+ dbgarg(cmd,
+ "count=%d, type=0x%08x, sequence=%d, "
+ "timestamp=%lu.%09lu ",
+ ev->count, ev->type, ev->sequence,
+ ev->timestamp.tv_sec, ev->timestamp.tv_nsec);
+ break;
+ }
+ case VIDIOC_SUBSCRIBE_EVENT:
+ {
+ struct v4l2_event_subscription *sub = arg;
+
+ if (!ops->vidioc_subscribe_event)
+ break;
+
+ ret = ops->vidioc_subscribe_event(file->private_data, sub);
+ if (ret < 0) {
+ dbgarg(cmd, "failed, ret=%ld", ret);
+ break;
+ }
+ dbgarg(cmd, "type=0x%8.8x", sub->type);
+ break;
+ }
+ case VIDIOC_UNSUBSCRIBE_EVENT:
+ {
+ struct v4l2_event_subscription *sub = arg;
+
+ if (!ops->vidioc_unsubscribe_event)
+ break;
+
+ ret = ops->vidioc_unsubscribe_event(file->private_data, sub);
+ if (ret < 0) {
+ dbgarg(cmd, "failed, ret=%ld", ret);
+ break;
+ }
+ dbgarg(cmd, "type=0x%8.8x", sub->type);
+ break;
+ }
default:
{
if (!ops->vidioc_default)
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c
index 769b34b..2db2f19 100644
--- a/drivers/mfd/twl4030-core.c
+++ b/drivers/mfd/twl4030-core.c
@@ -756,6 +756,7 @@
int status;
unsigned i;
struct twl4030_platform_data *pdata = client->dev.platform_data;
+ u8 temp;
if (!pdata) {
dev_dbg(&client->dev, "no platform data?\n");
@@ -810,6 +811,16 @@
goto fail;
}
+ /* Disable GAIA I2C Pull-up on I2C1 and I2C4(SR) interface
+ * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
+ * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
+ */
+
+ twl4030_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);
+ temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
+ I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
+ twl4030_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
+
status = add_children(pdata, id->driver_data);
fail:
if (status < 0)
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 07e40dc..d17a844 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -184,7 +184,7 @@
R_P2_SW_EVENTS);
if (machine_is_omap_3430sdp() || machine_is_omap_ldp() ||
- machine_is_omap_zoom2()) {
+ machine_is_omap_zoom2() || machine_is_omap_zoom3()) {
u8 data;
/* Disabling AC charger effect on sleep-active transitions */
err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
@@ -331,6 +331,56 @@
return err;
}
+int twl4030_remove_script(u8 flags)
+{
+ int err;
+
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_1,
+ R_PROTECT_KEY);
+ if (err) {
+ pr_err("twl4030: unable to unlock PROTECT_KEY\n");
+ return err;
+ }
+
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_2,
+ R_PROTECT_KEY);
+ if (err) {
+ pr_err("twl4030: unable to unlock PROTECT_KEY\n");
+ return err;
+ }
+
+ if (flags & TRITON_WRST_SCRIPT) {
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+ END_OF_SCRIPT, R_SEQ_ADD_WARM);
+ if (err)
+ return err;
+ }
+ if (flags & TRITON_WAKEUP12_SCRIPT) {
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+ END_OF_SCRIPT, R_SEQ_ADD_SA12);
+ if (err)
+ return err;
+ }
+ if (flags & TRITON_WAKEUP3_SCRIPT) {
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+ END_OF_SCRIPT, R_SEQ_ADD_S2A3);
+ if (err)
+ return err;
+ }
+ if (flags & TRITON_SLEEP_SCRIPT) {
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+ END_OF_SCRIPT, R_SEQ_ADD_A2S);
+ if (err)
+ return err;
+ }
+
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
+ if (err)
+ pr_err("TWL4030 Unable to relock registers\n");
+
+ return 0;
+}
+
void __init twl4030_power_init(struct twl4030_power_data *triton2_scripts)
{
int err = 0;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index f023fa1..7d4f2dc 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -260,7 +260,26 @@
Creates an rfkill entry in sysfs for power control of Bluetooth
TI wl127x chips.
+config APANIC
+ bool "Android kernel panic diagnostics driver"
+ default n
+ ---help---
+ Driver which handles kernel panics and attempts to write
+ critical debugging data to flash.
+
+config APANIC_PLABEL
+ string "Android panic dump flash partition label"
+ default "kpanic"
+ ---help---
+ If your platform uses a different flash partition label for storing
+ crashdumps, enter it here.
+
+config BUILD_TI_ST
+ tristate "Build option for BT shared Transport driver"
+ default n
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
+source "drivers/misc/ti-st/Kconfig"
endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c09735a..dffdff3 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -25,3 +25,5 @@
obj-$(CONFIG_C2PORT) += c2port/
obj-y += eeprom/
obj-$(CONFIG_WL127X_RFKILL) += wl127x-rfkill.o
+obj-$(CONFIG_APANIC) += apanic.o
+obj-y += ti-st/
diff --git a/drivers/misc/apanic.c b/drivers/misc/apanic.c
new file mode 100644
index 0000000..ca875f8
--- /dev/null
+++ b/drivers/misc/apanic.c
@@ -0,0 +1,606 @@
+/* drivers/misc/apanic.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: San Mehat <san@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/wakelock.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/mtd/mtd.h>
+#include <linux/notifier.h>
+#include <linux/mtd/mtd.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/preempt.h>
+
+extern void ram_console_enable_console(int);
+
+struct panic_header {
+ u32 magic;
+#define PANIC_MAGIC 0xdeadf00d
+
+ u32 version;
+#define PHDR_VERSION 0x01
+
+ u32 console_offset;
+ u32 console_length;
+
+ u32 threads_offset;
+ u32 threads_length;
+};
+
+struct apanic_data {
+ struct mtd_info *mtd;
+ struct panic_header curr;
+ void *bounce;
+ struct proc_dir_entry *apanic_console;
+ struct proc_dir_entry *apanic_threads;
+};
+
+static struct apanic_data drv_ctx;
+static struct work_struct proc_removal_work;
+static DEFINE_MUTEX(drv_mutex);
+
+static unsigned int *apanic_bbt;
+static unsigned int apanic_erase_blocks;
+static unsigned int apanic_good_blocks;
+
+static void set_bb(unsigned int block, unsigned int *bbt)
+{
+ unsigned int flag = 1;
+
+ BUG_ON(block >= apanic_erase_blocks);
+
+ flag = flag << (block%32);
+ apanic_bbt[block/32] |= flag;
+ apanic_good_blocks--;
+}
+
+static unsigned int get_bb(unsigned int block, unsigned int *bbt)
+{
+ unsigned int flag;
+
+ BUG_ON(block >= apanic_erase_blocks);
+
+ flag = 1 << (block%32);
+ return apanic_bbt[block/32] & flag;
+}
+
+static void alloc_bbt(struct mtd_info *mtd, unsigned int *bbt)
+{
+ int bbt_size;
+ apanic_erase_blocks = (mtd->size)>>(mtd->erasesize_shift);
+ bbt_size = (apanic_erase_blocks+32)/32;
+
+ apanic_bbt = kmalloc(bbt_size*4, GFP_KERNEL);
+ memset(apanic_bbt, 0, bbt_size*4);
+ apanic_good_blocks = apanic_erase_blocks;
+}
+static void scan_bbt(struct mtd_info *mtd, unsigned int *bbt)
+{
+ int i;
+
+ for (i = 0; i < apanic_erase_blocks; i++) {
+ if (mtd->block_isbad(mtd, i*mtd->erasesize))
+ set_bb(i, apanic_bbt);
+ }
+}
+
+#define APANIC_INVALID_OFFSET 0xFFFFFFFF
+
+static unsigned int phy_offset(struct mtd_info *mtd, unsigned int offset)
+{
+ unsigned int logic_block = offset>>(mtd->erasesize_shift);
+ unsigned int phy_block;
+ unsigned good_block = 0;
+
+ for (phy_block = 0; phy_block < apanic_erase_blocks; phy_block++) {
+ if (!get_bb(phy_block, apanic_bbt))
+ good_block++;
+ if (good_block == (logic_block + 1))
+ break;
+ }
+
+ if (good_block != (logic_block + 1))
+ return APANIC_INVALID_OFFSET;
+
+ return offset + ((phy_block-logic_block)<<mtd->erasesize_shift);
+}
+
+static void apanic_erase_callback(struct erase_info *done)
+{
+ wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
+ wake_up(wait_q);
+}
+
+static int apanic_proc_read(char *buffer, char **start, off_t offset,
+ int count, int *peof, void *dat)
+{
+ struct apanic_data *ctx = &drv_ctx;
+ size_t file_length;
+ off_t file_offset;
+ unsigned int page_no;
+ off_t page_offset;
+ int rc;
+ size_t len;
+
+ if (!count)
+ return 0;
+
+ mutex_lock(&drv_mutex);
+
+ switch ((int) dat) {
+ case 1: /* apanic_console */
+ file_length = ctx->curr.console_length;
+ file_offset = ctx->curr.console_offset;
+ break;
+ case 2: /* apanic_threads */
+ file_length = ctx->curr.threads_length;
+ file_offset = ctx->curr.threads_offset;
+ break;
+ default:
+ pr_err("Bad dat (%d)\n", (int) dat);
+ mutex_unlock(&drv_mutex);
+ return -EINVAL;
+ }
+
+ if ((offset + count) > file_length) {
+ mutex_unlock(&drv_mutex);
+ return 0;
+ }
+
+ /* We only support reading a maximum of a flash page */
+ if (count > ctx->mtd->writesize)
+ count = ctx->mtd->writesize;
+
+ page_no = (file_offset + offset) / ctx->mtd->writesize;
+ page_offset = (file_offset + offset) % ctx->mtd->writesize;
+
+
+ if (phy_offset(ctx->mtd, (page_no * ctx->mtd->writesize))
+ == APANIC_INVALID_OFFSET) {
+ pr_err("apanic: reading an invalid address\n");
+ mutex_unlock(&drv_mutex);
+ return -EINVAL;
+ }
+ rc = ctx->mtd->read(ctx->mtd,
+ phy_offset(ctx->mtd, (page_no * ctx->mtd->writesize)),
+ ctx->mtd->writesize,
+ &len, ctx->bounce);
+
+ if (page_offset)
+ count -= page_offset;
+ memcpy(buffer, ctx->bounce + page_offset, count);
+
+ *start = count;
+
+ if ((offset + count) == file_length)
+ *peof = 1;
+
+ mutex_unlock(&drv_mutex);
+ return count;
+}
+
+static void mtd_panic_erase(void)
+{
+ struct apanic_data *ctx = &drv_ctx;
+ struct erase_info erase;
+ DECLARE_WAITQUEUE(wait, current);
+ wait_queue_head_t wait_q;
+ int rc, i;
+
+ init_waitqueue_head(&wait_q);
+ erase.mtd = ctx->mtd;
+ erase.callback = apanic_erase_callback;
+ erase.len = ctx->mtd->erasesize;
+ erase.priv = (u_long)&wait_q;
+ for (i = 0; i < ctx->mtd->size; i += ctx->mtd->erasesize) {
+ erase.addr = i;
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&wait_q, &wait);
+
+ if (get_bb(erase.addr>>ctx->mtd->erasesize_shift, apanic_bbt)) {
+ printk(KERN_WARNING
+ "apanic: Skipping erase of bad "
+ "block @%llx\n", erase.addr);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&wait_q, &wait);
+ continue;
+ }
+
+ rc = ctx->mtd->erase(ctx->mtd, &erase);
+ if (rc) {
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&wait_q, &wait);
+ printk(KERN_ERR
+ "apanic: Erase of 0x%llx, 0x%llx failed\n",
+ (unsigned long long) erase.addr,
+ (unsigned long long) erase.len);
+ if (rc == -EIO) {
+ if (ctx->mtd->block_markbad(ctx->mtd,
+ erase.addr)) {
+ printk(KERN_ERR
+ "apanic: Err marking blk bad\n");
+ goto out;
+ }
+ printk(KERN_INFO
+ "apanic: Marked a bad block"
+ " @%llx\n", erase.addr);
+ set_bb(erase.addr>>ctx->mtd->erasesize_shift,
+ apanic_bbt);
+ continue;
+ }
+ goto out;
+ }
+ schedule();
+ remove_wait_queue(&wait_q, &wait);
+ }
+ printk(KERN_DEBUG "apanic: %s partition erased\n",
+ CONFIG_APANIC_PLABEL);
+out:
+ return;
+}
+
+static void apanic_remove_proc_work(struct work_struct *work)
+{
+ struct apanic_data *ctx = &drv_ctx;
+
+ mutex_lock(&drv_mutex);
+ mtd_panic_erase();
+ memset(&ctx->curr, 0, sizeof(struct panic_header));
+ if (ctx->apanic_console) {
+ remove_proc_entry("apanic_console", NULL);
+ ctx->apanic_console = NULL;
+ }
+ if (ctx->apanic_threads) {
+ remove_proc_entry("apanic_threads", NULL);
+ ctx->apanic_threads = NULL;
+ }
+ mutex_unlock(&drv_mutex);
+}
+
+static int apanic_proc_write(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ schedule_work(&proc_removal_work);
+ return count;
+}
+
+static void mtd_panic_notify_add(struct mtd_info *mtd)
+{
+ struct apanic_data *ctx = &drv_ctx;
+ struct panic_header *hdr = ctx->bounce;
+ size_t len;
+ int rc;
+ int proc_entry_created = 0;
+
+ if (strcmp(mtd->name, CONFIG_APANIC_PLABEL))
+ return;
+
+ ctx->mtd = mtd;
+
+ alloc_bbt(mtd, apanic_bbt);
+ scan_bbt(mtd, apanic_bbt);
+
+ if (apanic_good_blocks == 0) {
+ printk(KERN_ERR "apanic: no any good blocks?!\n");
+ goto out_err;
+ }
+
+ rc = mtd->read(mtd, phy_offset(mtd, 0), mtd->writesize,
+ &len, ctx->bounce);
+ if (rc && rc == -EBADMSG) {
+ printk(KERN_WARNING
+ "apanic: Bad ECC on block 0 (ignored)\n");
+ } else if (rc && rc != -EUCLEAN) {
+ printk(KERN_ERR "apanic: Error reading block 0 (%d)\n", rc);
+ goto out_err;
+ }
+
+ if (len != mtd->writesize) {
+ printk(KERN_ERR "apanic: Bad read size (%d)\n", rc);
+ goto out_err;
+ }
+
+ printk(KERN_INFO "apanic: Bound to mtd partition '%s'\n", mtd->name);
+
+ if (hdr->magic != PANIC_MAGIC) {
+ printk(KERN_INFO "apanic: No panic data available\n");
+ mtd_panic_erase();
+ return;
+ }
+
+ if (hdr->version != PHDR_VERSION) {
+ printk(KERN_INFO "apanic: Version mismatch (%d != %d)\n",
+ hdr->version, PHDR_VERSION);
+ mtd_panic_erase();
+ return;
+ }
+
+ memcpy(&ctx->curr, hdr, sizeof(struct panic_header));
+
+ printk(KERN_INFO "apanic: c(%u, %u) t(%u, %u)\n",
+ hdr->console_offset, hdr->console_length,
+ hdr->threads_offset, hdr->threads_length);
+
+ if (hdr->console_length) {
+ ctx->apanic_console = create_proc_entry("apanic_console",
+ S_IFREG | S_IRUGO, NULL);
+ if (!ctx->apanic_console)
+ printk(KERN_ERR "%s: failed creating procfile\n",
+ __func__);
+ else {
+ ctx->apanic_console->read_proc = apanic_proc_read;
+ ctx->apanic_console->write_proc = apanic_proc_write;
+ ctx->apanic_console->size = hdr->console_length;
+ ctx->apanic_console->data = (void *) 1;
+ proc_entry_created = 1;
+ }
+ }
+
+ if (hdr->threads_length) {
+ ctx->apanic_threads = create_proc_entry("apanic_threads",
+ S_IFREG | S_IRUGO, NULL);
+ if (!ctx->apanic_threads)
+ printk(KERN_ERR "%s: failed creating procfile\n",
+ __func__);
+ else {
+ ctx->apanic_threads->read_proc = apanic_proc_read;
+ ctx->apanic_threads->write_proc = apanic_proc_write;
+ ctx->apanic_threads->size = hdr->threads_length;
+ ctx->apanic_threads->data = (void *) 2;
+ proc_entry_created = 1;
+ }
+ }
+
+ if (!proc_entry_created)
+ mtd_panic_erase();
+
+ return;
+out_err:
+ ctx->mtd = NULL;
+}
+
+static void mtd_panic_notify_remove(struct mtd_info *mtd)
+{
+ struct apanic_data *ctx = &drv_ctx;
+ if (mtd == ctx->mtd) {
+ ctx->mtd = NULL;
+ printk(KERN_INFO "apanic: Unbound from %s\n", mtd->name);
+ }
+}
+
+static struct mtd_notifier mtd_panic_notifier = {
+ .add = mtd_panic_notify_add,
+ .remove = mtd_panic_notify_remove,
+};
+
+static int in_panic = 0;
+
+static int apanic_writeflashpage(struct mtd_info *mtd, loff_t to,
+ const u_char *buf)
+{
+ int rc;
+ size_t wlen;
+ int panic = in_interrupt() | in_atomic();
+
+ if (panic && !mtd->panic_write) {
+ printk(KERN_EMERG "%s: No panic_write available\n", __func__);
+ return 0;
+ } else if (!panic && !mtd->write) {
+ printk(KERN_EMERG "%s: No write available\n", __func__);
+ return 0;
+ }
+
+ to = phy_offset(mtd, to);
+ if (to == APANIC_INVALID_OFFSET) {
+ printk(KERN_EMERG "apanic: write to invalid address\n");
+ return 0;
+ }
+
+ if (panic)
+ rc = mtd->panic_write(mtd, to, mtd->writesize, &wlen, buf);
+ else
+ rc = mtd->write(mtd, to, mtd->writesize, &wlen, buf);
+
+ if (rc) {
+ printk(KERN_EMERG
+ "%s: Error writing data to flash (%d)\n",
+ __func__, rc);
+ return rc;
+ }
+
+ return wlen;
+}
+
+extern int log_buf_copy(char *dest, int idx, int len);
+extern void log_buf_clear(void);
+
+/*
+ * Writes the contents of the console to the specified offset in flash.
+ * Returns number of bytes written
+ */
+static int apanic_write_console(struct mtd_info *mtd, unsigned int off)
+{
+ struct apanic_data *ctx = &drv_ctx;
+ int saved_oip;
+ int idx = 0;
+ int rc, rc2;
+ unsigned int last_chunk = 0;
+
+ while (!last_chunk) {
+ saved_oip = oops_in_progress;
+ oops_in_progress = 1;
+ rc = log_buf_copy(ctx->bounce, idx, mtd->writesize);
+ if (rc < 0)
+ break;
+
+ if (rc != mtd->writesize)
+ last_chunk = rc;
+
+ oops_in_progress = saved_oip;
+ if (rc <= 0)
+ break;
+ if (rc != mtd->writesize)
+ memset(ctx->bounce + rc, 0, mtd->writesize - rc);
+
+ rc2 = apanic_writeflashpage(mtd, off, ctx->bounce);
+ if (rc2 <= 0) {
+ printk(KERN_EMERG
+ "apanic: Flash write failed (%d)\n", rc2);
+ return idx;
+ }
+ if (!last_chunk)
+ idx += rc2;
+ else
+ idx += last_chunk;
+ off += rc2;
+ }
+ return idx;
+}
+
+static int apanic(struct notifier_block *this, unsigned long event,
+ void *ptr)
+{
+ struct apanic_data *ctx = &drv_ctx;
+ struct panic_header *hdr = (struct panic_header *) ctx->bounce;
+ int console_offset = 0;
+ int console_len = 0;
+ int threads_offset = 0;
+ int threads_len = 0;
+ int rc;
+
+ if (in_panic)
+ return NOTIFY_DONE;
+ in_panic = 1;
+#ifdef CONFIG_PREEMPT
+ /* Ensure that cond_resched() won't try to preempt anybody */
+ add_preempt_count(PREEMPT_ACTIVE);
+#endif
+ touch_softlockup_watchdog();
+
+ if (!ctx->mtd)
+ goto out;
+
+ if (ctx->curr.magic) {
+ printk(KERN_EMERG "Crash partition in use!\n");
+ goto out;
+ }
+ console_offset = ctx->mtd->writesize;
+
+ /*
+ * Write out the console
+ */
+ console_len = apanic_write_console(ctx->mtd, console_offset);
+ if (console_len < 0) {
+ printk(KERN_EMERG "Error writing console to panic log! (%d)\n",
+ console_len);
+ console_len = 0;
+ }
+
+ /*
+ * Write out all threads
+ */
+ threads_offset = ALIGN(console_offset + console_len,
+ ctx->mtd->writesize);
+ if (!threads_offset)
+ threads_offset = ctx->mtd->writesize;
+
+ ram_console_enable_console(0);
+
+ log_buf_clear();
+ show_state_filter(0);
+ threads_len = apanic_write_console(ctx->mtd, threads_offset);
+ if (threads_len < 0) {
+ printk(KERN_EMERG "Error writing threads to panic log! (%d)\n",
+ threads_len);
+ threads_len = 0;
+ }
+
+ /*
+ * Finally write the panic header
+ */
+ memset(ctx->bounce, 0, PAGE_SIZE);
+ hdr->magic = PANIC_MAGIC;
+ hdr->version = PHDR_VERSION;
+
+ hdr->console_offset = console_offset;
+ hdr->console_length = console_len;
+
+ hdr->threads_offset = threads_offset;
+ hdr->threads_length = threads_len;
+
+ rc = apanic_writeflashpage(ctx->mtd, 0, ctx->bounce);
+ if (rc <= 0) {
+ printk(KERN_EMERG "apanic: Header write failed (%d)\n",
+ rc);
+ goto out;
+ }
+
+ printk(KERN_EMERG "apanic: Panic dump sucessfully written to flash\n");
+
+ out:
+#ifdef CONFIG_PREEMPT
+ sub_preempt_count(PREEMPT_ACTIVE);
+#endif
+ in_panic = 0;
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_blk = {
+ .notifier_call = apanic,
+};
+
+static int panic_dbg_get(void *data, u64 *val)
+{
+ apanic(NULL, 0, NULL);
+ return 0;
+}
+
+static int panic_dbg_set(void *data, u64 val)
+{
+ BUG();
+ return -1;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(panic_dbg_fops, panic_dbg_get, panic_dbg_set, "%llu\n");
+
+int __init apanic_init(void)
+{
+ register_mtd_user(&mtd_panic_notifier);
+ atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
+ debugfs_create_file("apanic", 0644, NULL, NULL, &panic_dbg_fops);
+ memset(&drv_ctx, 0, sizeof(drv_ctx));
+ drv_ctx.bounce = (void *) __get_free_page(GFP_KERNEL);
+ INIT_WORK(&proc_removal_work, apanic_remove_proc_work);
+ printk(KERN_INFO "Android kernel panic handler initialized (bind=%s)\n",
+ CONFIG_APANIC_PLABEL);
+ return 0;
+}
+
+module_init(apanic_init);
diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c
index ec7db34..55c4de8 100644
--- a/drivers/misc/pmem.c
+++ b/drivers/misc/pmem.c
@@ -795,7 +795,7 @@
id = get_id(file);
data = (struct pmem_data *)file->private_data;
- if (!pmem[id].cached)
+ if (!pmem[id].cached || file->f_flags & O_SYNC)
return;
down_read(&data->sem);
diff --git a/drivers/misc/ti-st/Kconfig b/drivers/misc/ti-st/Kconfig
new file mode 100644
index 0000000..25c8203
--- /dev/null
+++ b/drivers/misc/ti-st/Kconfig
@@ -0,0 +1,39 @@
+#
+# TI's shared transport line discipline and the protocol
+# drivers (BT, FM and GPS)
+#
+menu "Texas Instruments shared transport line discipline"
+ config TI_ST
+ tristate "shared transport core driver"
+ select FW_LOADER
+ help
+ This enables the shared transport core driver for TI
+ BT / FM and GPS combo chips.This enables protocol drivers
+ to register themselves with core and send data, the responses
+ are returned to relevant protocol drivers based on their
+ packet types.
+
+ config TI_ST_BT
+ tristate "BlueZ bluetooth driver for ST"
+ select BT
+ select TI_ST
+ help
+ This enables the Bluetooth driver for TI BT/FM/GPS combo devices
+ This makes use of shared transport line discipline core driver to
+ communicate with the BT core of the combo chip.
+
+ config TI_ST_FM
+ tristate "fm driver for ST"
+ select TI_ST
+ help
+ This enables the FM driver for TI BT/FM/GPS combo devices
+ This makes use of shared transport line discipline core driver to
+ communicate with the FM core of the combo chip.
+ config TI_ST_GPS
+ tristate "GPS driver for ST"
+ select TI_ST
+ help
+ This enables the GPS driver for TI BT/FM/GPS combo devices
+ It will provide a character device for TI GPS Host software to access
+ GPS functionality of Connectivity chip via ST driver
+endmenu
diff --git a/drivers/misc/ti-st/Makefile b/drivers/misc/ti-st/Makefile
new file mode 100644
index 0000000..0a33069
--- /dev/null
+++ b/drivers/misc/ti-st/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for TI's shared transport line discipline
+# and it's protocol drivers (BT, FM, GPS)
+#
+obj-$(CONFIG_TI_ST) += st_drv.o
+st_drv-objs := st_core.o st_kim.o st_ll.o
+obj-$(CONFIG_TI_ST_BT) += bt_drv.o
+obj-$(CONFIG_TI_ST_FM) += fm_drv.o
+fm_drv-objs := fmdrv_core.o fmdrv_v4l2.o fmdrv_st.o fmdrv_mixer.o fmdrv_chr.o
+obj-$(CONFIG_TI_ST_GPS) += gps_drv.o
diff --git a/drivers/misc/ti-st/bt_drv.c b/drivers/misc/ti-st/bt_drv.c
new file mode 100644
index 0000000..b8984f2
--- /dev/null
+++ b/drivers/misc/ti-st/bt_drv.c
@@ -0,0 +1,502 @@
+/*
+ * Texas Instrument's Bluetooth Driver For Shared Transport.
+ *
+ * Bluetooth Driver acts as interface between HCI CORE and
+ * TI Shared Transport Layer.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "st.h"
+#include "bt_drv.h"
+
+/* Define this macro to get debug msg */
+#undef DEBUG
+
+#ifdef DEBUG
+#define BT_DRV_DBG(fmt, arg...) printk(KERN_INFO "(btdrv):"fmt"\n" , ## arg)
+#define BTDRV_API_START() printk(KERN_INFO "(btdrv): %s Start\n", \
+ __func__)
+#define BTDRV_API_EXIT(errno) printk(KERN_INFO "(btdrv): %s Exit(%d)\n", \
+ __func__, errno)
+#else
+#define BT_DRV_DBG(fmt, arg...)
+#define BTDRV_API_START()
+#define BTDRV_API_EXIT(errno)
+#endif
+
+#define BT_DRV_ERR(fmt, arg...) printk(KERN_ERR "(btdrv):"fmt"\n" , ## arg)
+
+static int reset;
+static struct hci_st *hst;
+
+/* Increments HCI counters based on pocket ID (cmd,acl,sco) */
+static inline void hci_st_tx_complete(struct hci_st *hst, int pkt_type)
+{
+ struct hci_dev *hdev;
+
+ BTDRV_API_START();
+
+ hdev = hst->hdev;
+
+ /* Update HCI stat counters */
+ switch (pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+
+ case HCI_SCODATA_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+ }
+
+ BTDRV_API_EXIT(0);
+}
+
+/* ------- Interfaces to Shared Transport ------ */
+
+/* Called by ST layer to indicate protocol registration completion
+ * status.hci_st_open() function will wait for signal from this
+ * API when st_register() function returns ST_PENDING.
+ */
+static void hci_st_registration_completion_cb(char data)
+{
+ BTDRV_API_START();
+
+ /* hci_st_open() function needs value of 'data' to know
+ * the registration status(success/fail),So have a back
+ * up of it.
+ */
+ hst->streg_cbdata = data;
+
+ /* Got a feedback from ST for BT driver registration
+ * request.Wackup hci_st_open() function to continue
+ * it's open operation.
+ */
+ complete(&hst->wait_for_btdrv_reg_completion);
+
+ BTDRV_API_EXIT(0);
+}
+
+/* Called by Shared Transport layer when receive data is
+ * available */
+static long hci_st_receive(struct sk_buff *skb)
+{
+ int err;
+ int len;
+
+ BTDRV_API_START();
+
+ err = 0;
+ len = 0;
+
+ if (skb == NULL) {
+ BT_DRV_ERR("Invalid SKB received from ST");
+ BTDRV_API_EXIT(-EFAULT);
+ return -EFAULT;
+ }
+ if (!hst) {
+ kfree_skb(skb);
+ BT_DRV_ERR("Invalid hci_st memory,freeing SKB");
+ BTDRV_API_EXIT(-EFAULT);
+ return -EFAULT;
+ }
+ if (!test_bit(BT_DRV_RUNNING, &hst->flags)) {
+ kfree_skb(skb);
+ BT_DRV_ERR("Device is not running,freeing SKB");
+ BTDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+
+ len = skb->len;
+ skb->dev = (struct net_device *)hst->hdev;
+
+ /* Forward skb to HCI CORE layer */
+ err = hci_recv_frame(skb);
+ if (err) {
+ kfree_skb(skb);
+ BT_DRV_ERR("Unable to push skb to HCI CORE(%d),freeing SKB",
+ err);
+ BTDRV_API_EXIT(err);
+ return err;
+ }
+ hst->hdev->stat.byte_rx += len;
+
+ BTDRV_API_EXIT(0);
+ return 0;
+}
+
+/* ------- Interfaces to HCI layer ------ */
+
+/* Called from HCI core to initialize the device */
+static int hci_st_open(struct hci_dev *hdev)
+{
+ static struct st_proto_s hci_st_proto;
+ unsigned long timeleft;
+ int err;
+
+ BTDRV_API_START();
+
+ err = 0;
+
+ BT_DRV_DBG("%s %p", hdev->name, hdev);
+
+ /* Already registered with ST ? */
+ if (test_bit(BT_ST_REGISTERED, &hst->flags)) {
+ BT_DRV_ERR("Registered with ST already,open called again?");
+ BTDRV_API_EXIT(0);
+ return 0;
+ }
+
+ /* Populate BT driver info required by ST */
+ memset(&hci_st_proto, 0, sizeof(hci_st_proto));
+
+ /* BT driver ID */
+ hci_st_proto.type = ST_BT;
+
+ /* Receive function which called from ST */
+ hci_st_proto.recv = hci_st_receive;
+
+ /* Packet match function may used in future */
+ hci_st_proto.match_packet = NULL;
+
+ /* Callback to be called when registration is pending */
+ hci_st_proto.reg_complete_cb = hci_st_registration_completion_cb;
+
+ /* This is write function pointer of ST. BT driver will make use of this
+ * for sending any packets to chip. ST will assign and give to us, so
+ * make it as NULL */
+ hci_st_proto.write = NULL;
+
+ /* Register with ST layer */
+ err = st_register(&hci_st_proto);
+ if (err == ST_ERR_PENDING) {
+ /* Prepare wait-for-completion handler data structures.
+ * Needed to syncronize this and st_registration_completion_cb()
+ * functions.
+ */
+ init_completion(&hst->wait_for_btdrv_reg_completion);
+
+ /* Reset ST registration callback status flag , this value
+ * will be updated in hci_st_registration_completion_cb()
+ * function whenever it called from ST driver.
+ */
+ hst->streg_cbdata = -EINPROGRESS;
+
+ /* ST is busy with other protocol registration(may be busy with
+ * firmware download).So,Wait till the registration callback
+ * (passed as a argument to st_register() function) getting
+ * called from ST.
+ */
+ BT_DRV_DBG(" %s waiting for reg completion signal from ST",
+ __func__);
+
+ timeleft =
+ wait_for_completion_timeout
+ (&hst->wait_for_btdrv_reg_completion,
+ msecs_to_jiffies(BT_REGISTER_TIMEOUT));
+ if (!timeleft) {
+ BT_DRV_ERR("Timeout(%ld sec),didn't get reg"
+ "completion signal from ST",
+ BT_REGISTER_TIMEOUT / 1000);
+ BTDRV_API_EXIT(-ETIMEDOUT);
+ return -ETIMEDOUT;
+ }
+
+ /* Is ST registration callback called with ERROR value? */
+ if (hst->streg_cbdata != 0) {
+ BT_DRV_ERR("ST reg completion CB called with invalid"
+ "status %d", hst->streg_cbdata);
+ BTDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+ }
+ err = 0;
+ } else if (err == ST_ERR_FAILURE) {
+ BT_DRV_ERR("st_register failed %d", err);
+ BTDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+ }
+
+ /* Do we have proper ST write function? */
+ if (hci_st_proto.write != NULL) {
+ /* We need this pointer for sending any Bluetooth pkts */
+ hst->st_write = hci_st_proto.write;
+ } else {
+ BT_DRV_ERR("failed to get ST write func pointer");
+
+ /* Undo registration with ST */
+ err = st_unregister(ST_BT);
+ if (err < 0)
+ BT_DRV_ERR("st_unregister failed %d", err);
+
+ hst->st_write = NULL;
+ BTDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+ }
+
+ /* Registration with ST layer is completed successfully,
+ * now chip is ready to accept commands from HCI CORE.
+ * Mark HCI Device flag as RUNNING
+ */
+ set_bit(HCI_RUNNING, &hdev->flags);
+
+ /* Registration with ST successful */
+ set_bit(BT_ST_REGISTERED, &hst->flags);
+
+ BTDRV_API_EXIT(err);
+ return err;
+}
+
+/* Close device */
+static int hci_st_close(struct hci_dev *hdev)
+{
+ int err;
+
+ BTDRV_API_START();
+
+ err = 0;
+
+ /* Unregister from ST layer */
+ if (test_and_clear_bit(BT_ST_REGISTERED, &hst->flags)) {
+ err = st_unregister(ST_BT);
+ if (err != ST_SUCCESS) {
+ BT_DRV_ERR("st_unregister failed %d", err);
+ BTDRV_API_EXIT(-EBUSY);
+ return -EBUSY;
+ }
+ }
+
+ hst->st_write = NULL;
+
+ /* ST layer would have moved chip to inactive state.
+ * So,clear HCI device RUNNING flag.
+ */
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) {
+ BTDRV_API_EXIT(0);
+ return 0;
+ }
+
+ BTDRV_API_EXIT(err);
+ return err;
+}
+
+/* Called from HCI CORE , Sends frames to Shared Transport */
+static int hci_st_send_frame(struct sk_buff *skb)
+{
+ struct hci_dev *hdev;
+ struct hci_st *hst;
+ long len;
+
+ BTDRV_API_START();
+
+ if (skb == NULL) {
+ BT_DRV_ERR("Invalid skb received from HCI CORE");
+ BTDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ hdev = (struct hci_dev *)skb->dev;
+ if (!hdev) {
+ BT_DRV_ERR("SKB received for invalid HCI Device (hdev=NULL)");
+ BTDRV_API_EXIT(-ENODEV);
+ return -ENODEV;
+ }
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ BT_DRV_ERR("Device is not running");
+ BTDRV_API_EXIT(-EBUSY);
+ return -EBUSY;
+ }
+
+ hst = (struct hci_st *)hdev->driver_data;
+
+ /* Prepend skb with frame type */
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+ BT_DRV_DBG(" %s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type,
+ skb->len);
+
+ /* Insert skb to shared transport layer's transmit queue.
+ * Freeing skb memory is taken care in shared transport layer,
+ * so don't free skb memory here.
+ */
+ if (!hst->st_write) {
+ kfree_skb(skb);
+ BT_DRV_ERR(" Can't write to ST, st_write null?");
+ BTDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+ }
+ len = hst->st_write(skb);
+ if (len < 0) {
+ /* Something went wrong in st write , free skb memory */
+ kfree_skb(skb);
+ BT_DRV_ERR(" ST write failed (%ld)", len);
+ BTDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+ }
+
+ /* ST accepted our skb. So, Go ahead and do rest */
+ hdev->stat.byte_tx += len;
+ hci_st_tx_complete(hst, bt_cb(skb)->pkt_type);
+
+ BTDRV_API_EXIT(0);
+ return 0;
+}
+
+static void hci_st_destruct(struct hci_dev *hdev)
+{
+ BTDRV_API_START();
+
+ if (!hdev) {
+ BT_DRV_ERR("Destruct called with invalid HCI Device"
+ "(hdev=NULL)");
+ BTDRV_API_EXIT(0);
+ return;
+ }
+
+ BT_DRV_DBG("%s", hdev->name);
+
+ /* free hci_st memory */
+ if (hdev->driver_data != NULL)
+ kfree(hdev->driver_data);
+
+ BTDRV_API_EXIT(0);
+ return;
+}
+
+/* Creates new HCI device */
+static int hci_st_register_dev(struct hci_st *hst)
+{
+ struct hci_dev *hdev;
+
+ BTDRV_API_START();
+
+ /* Initialize and register HCI device */
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ BT_DRV_ERR("Can't allocate HCI device");
+ BTDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ BT_DRV_DBG(" HCI device allocated. hdev= %p", hdev);
+
+ hst->hdev = hdev;
+ hdev->type = HCI_UART;
+ hdev->driver_data = hst;
+ hdev->open = hci_st_open;
+ hdev->close = hci_st_close;
+ hdev->flush = NULL;
+ hdev->send = hci_st_send_frame;
+ hdev->destruct = hci_st_destruct;
+ hdev->owner = THIS_MODULE;
+
+ if (reset)
+ set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+
+ if (hci_register_dev(hdev) < 0) {
+ BT_DRV_ERR("Can't register HCI device");
+ hci_free_dev(hdev);
+ BTDRV_API_EXIT(-ENODEV);
+ return -ENODEV;
+ }
+
+ BT_DRV_DBG(" HCI device registered. hdev= %p", hdev);
+ BTDRV_API_EXIT(0);
+ return 0;
+}
+
+/* ------- Module Init interface ------ */
+
+static int __init bt_drv_init(void)
+{
+ int err;
+
+ BTDRV_API_START();
+
+ err = 0;
+
+ BT_DRV_DBG(" Bluetooth Driver Version %s", VERSION);
+
+ /* Allocate local resource memory */
+ hst = kzalloc(sizeof(struct hci_st), GFP_KERNEL);
+ if (!hst) {
+ BT_DRV_ERR("Can't allocate control structure");
+ BTDRV_API_EXIT(-ENFILE);
+ return -ENFILE;
+ }
+
+ /* Expose "hciX" device to user space */
+ err = hci_st_register_dev(hst);
+ if (err) {
+ /* Release local resource memory */
+ kfree(hst);
+
+ BT_DRV_ERR("Unable to expose hci0 device(%d)", err);
+ BTDRV_API_EXIT(err);
+ return err;
+ }
+ set_bit(BT_DRV_RUNNING, &hst->flags);
+
+ BTDRV_API_EXIT(err);
+ return err;
+}
+
+/* ------- Module Exit interface ------ */
+
+static void __exit bt_drv_exit(void)
+{
+ BTDRV_API_START();
+
+ /* Deallocate local resource's memory */
+ if (hst) {
+ struct hci_dev *hdev = hst->hdev;
+
+ if (hdev == NULL) {
+ BT_DRV_ERR("Invalid hdev memory");
+ kfree(hst);
+ } else {
+ hci_st_close(hdev);
+ if (test_and_clear_bit(BT_DRV_RUNNING, &hst->flags)) {
+ /* Remove HCI device (hciX) created
+ * in module init.
+ */
+ hci_unregister_dev(hdev);
+
+ /* Free HCI device memory */
+ hci_free_dev(hdev);
+ }
+ }
+ }
+ BTDRV_API_EXIT(0);
+}
+
+module_init(bt_drv_init);
+module_exit(bt_drv_exit);
+
+/* ------ Module Info ------ */
+
+module_param(reset, bool, 0644);
+MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
+MODULE_AUTHOR("Raja Mani <raja_mani@ti.com>");
+MODULE_DESCRIPTION("Bluetooth Driver for TI Shared Transport" VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ti-st/bt_drv.h b/drivers/misc/ti-st/bt_drv.h
new file mode 100644
index 0000000..a0beebe
--- /dev/null
+++ b/drivers/misc/ti-st/bt_drv.h
@@ -0,0 +1,61 @@
+/*
+ * Texas Instrument's Bluetooth Driver For Shared Transport.
+ *
+ * Bluetooth Driver acts as interface between HCI CORE and
+ * TI Shared Transport Layer.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _BT_DRV_H
+#define _BT_DRV_H
+
+/* Bluetooth Driver Version */
+#define VERSION "1.0"
+
+/* Defines number of seconds to wait for reg completion
+ * callback getting called from ST (in case,registration
+ * with ST returns PENDING status)
+ */
+#define BT_REGISTER_TIMEOUT msecs_to_jiffies(6000) /* 6 sec */
+
+/* BT driver's local status */
+#define BT_DRV_RUNNING 0
+#define BT_ST_REGISTERED 1
+
+/* BT driver operation structure */
+struct hci_st {
+
+ /* hci device pointer which binds to bt driver */
+ struct hci_dev *hdev;
+
+ /* used locally,to maintain various BT driver status */
+ unsigned long flags;
+
+ /* to hold ST registration callback status */
+ char streg_cbdata;
+
+ /* write function pointer of ST driver */
+ long (*st_write) (struct sk_buff *);
+
+ /* Wait on comepletion handler needed to synchronize
+ * hci_st_open() and hci_st_registration_completion_cb()
+ * functions.*/
+ struct completion wait_for_btdrv_reg_completion;
+};
+
+#endif
diff --git a/drivers/misc/ti-st/fm.h b/drivers/misc/ti-st/fm.h
new file mode 100644
index 0000000..be41453
--- /dev/null
+++ b/drivers/misc/ti-st/fm.h
@@ -0,0 +1,13 @@
+struct fm_event_hdr {
+ unsigned char plen;
+} __attribute__ ((packed));
+
+#define FM_MAX_FRAME_SIZE 0xFF /* TODO: */
+#define FM_EVENT_HDR_SIZE 1 /* size of fm_event_hdr */
+#define ST_FM_CH8_PKT 0x8
+
+/* gps stuff */
+struct gps_event_hdr {
+unsigned char opcode;
+unsigned short plen;
+} __attribute__ ((packed));
diff --git a/drivers/misc/ti-st/fmdrv.h b/drivers/misc/ti-st/fmdrv.h
new file mode 100644
index 0000000..88e95fb
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv.h
@@ -0,0 +1,258 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * Common header for all FM driver sub-modules.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _FM_DRV_H
+#define _FM_DRV_H
+
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+
+/* Driver version */
+#define FM_DRV_VERSION "0.01"
+
+/* Should match with FM_DRV_VERSION */
+#define FM_DRV_RADIO_VERSION KERNEL_VERSION(0, 0, 1)
+
+/* Driver name */
+#define FM_DRV_NAME "ti_fmdrv"
+
+/* Card short name */
+#define FM_DRV_CARD_SHORT_NAME "TI FM Radio"
+
+/* Card long name */
+#define FM_DRV_CARD_LONG_NAME "Texas Instruments FM Radio"
+
+/* Define this macro to get debug msg */
+#ifdef DEBUG
+#define FM_DRV_DBG(fmt, arg...) \
+ pr_info("(fmdrv): "fmt"\n" , ## arg)
+#define FMDRV_API_START() \
+ pr_info("(fmdrv): %s Start\n", __func__)
+#define FMDRV_API_EXIT(errno) \
+ pr_info("(fmdrv): %s Exit(%d)\n", __func__, errno)
+#define FM_DUMP_TXRX_PKT
+#else
+#define FM_DRV_DBG(fmt, arg...)
+#define FMDRV_API_START()
+#define FMDRV_API_EXIT(errno)
+#endif
+
+#define FM_DRV_ERR(fmt, arg...) \
+ pr_err("(fmdrv): "fmt"\n" , ## arg)
+
+#define FM_ST_NOT_CLAIMED 0
+#define FM_ST_CLAIMED 1
+
+#define FM_ST_SUCCESS 0
+#define FM_ST_FAILED -1
+
+/* Flag info */
+#define FM_INTTASK_RUNNING 0
+#define FM_INTTASK_SCHEDULE_PENDING 1
+#define FM_FIRMWARE_DW_INPROGRESS 2
+#define FM_CORE_READY 3
+#define FM_CORE_TRANSPORT_READY 4
+#define FM_AF_SWITCH_INPROGRESS 5
+#define FM_CORE_TX_XMITING 6
+
+/* FM packet TX timeout */
+#define FM_DRV_TX_TIMEOUT (5*HZ) /* 5 seconds */
+
+/* Seek operation timeout */
+#define FM_DRV_RX_SEEK_TIMEOUT (20*HZ) /* 20 seconds */
+
+/* Firmware download option */
+enum {
+ FM_MODE_OFF,
+ FM_MODE_TX,
+ FM_MODE_RX,
+ FM_MODE_ENTRY_MAX
+};
+
+#define FM_RX_RDS_INFO_FIELD_MAX 8 /* 4 Group * 2 Bytes */
+
+/* RX RDS data format */
+struct fm_rdsdata_format {
+ union {
+ struct {
+ unsigned char rdsBuff[FM_RX_RDS_INFO_FIELD_MAX];
+ } groupDataBuff;
+ struct {
+ unsigned short piData;
+ unsigned char blockB_byte1;
+ unsigned char blockB_byte2;
+ unsigned char blockC_byte1;
+ unsigned char blockC_byte2;
+ unsigned char blockD_byte1;
+ unsigned char blockD_byte2;
+ } groupGeneral;
+ struct {
+ unsigned short piData;
+ unsigned char blockB_byte1;
+ unsigned char blockB_byte2;
+ unsigned char firstAf;
+ unsigned char secondAf;
+ unsigned char firstPsByte;
+ unsigned char secondPsByte;
+ } group0A;
+
+ struct {
+ unsigned short piData;
+ unsigned char blockB_byte1;
+ unsigned char blockB_byte2;
+ unsigned short piData2;
+ unsigned char firstPsByte;
+ unsigned char secondPsByte;
+ } group0B;
+ } rdsData;
+};
+
+typedef void (*Int_Handler_ProtoType) (void);
+
+/* FM region (Europe/US, Japan) info */
+struct region_info {
+ unsigned int channel_spacing;
+ unsigned int bottom_frequency;
+ unsigned int top_frequency;
+ unsigned char region_index;
+};
+/* FM Interrupt processing related info */
+struct fm_irq {
+ unsigned char stage_index;
+ unsigned short flag; /* FM interrupt flag */
+ unsigned short mask; /* FM interrupt mask */
+ /* Interrupt process timeout handler */
+ struct timer_list int_timeout_timer;
+ unsigned char irq_service_timeout_retry;
+ Int_Handler_ProtoType *fm_IntActionHandlerTable;
+};
+
+/* RDS info */
+struct fm_rds {
+ unsigned char flag; /* RX RDS on/off status */
+ unsigned char last_block_index; /* Last received RDS block */
+
+ /* RDS buffer */
+ wait_queue_head_t read_queue;
+ unsigned int buf_size; /* Size is always multiple of 3 */
+ unsigned int wr_index;
+ unsigned int rd_index;
+ unsigned char *buffer;
+};
+
+#define FM_RDS_MAX_AF_LIST 25
+
+/* Current RX channel Alternate Frequency cache.
+ * This info is used to switch to other freq (AF)
+ * when current channel signal strengh is below RSSI threshold.
+ */
+struct tuned_station_info {
+ unsigned short picode;
+ unsigned int af_cache[FM_RDS_MAX_AF_LIST];
+ unsigned char no_of_items_in_afcache;
+ unsigned char af_list_max;
+};
+
+/* FM RX mode info */
+struct fm_rx {
+ struct region_info region; /* Current selected band */
+ unsigned int curr_freq; /* Current RX frquency */
+ unsigned char curr_mute_mode; /* Current mute mode */
+ /* RF dependent soft mute mode */
+ unsigned char curr_rf_depend_mute;
+ unsigned short curr_volume; /* Current volume level */
+ short curr_rssi_threshold; /* Current RSSI threshold level */
+ /* Holds the index of the current AF jump */
+ unsigned char cur_Afjump_index;
+ /* Will hold the frequency before the jump */
+ unsigned int freq_before_jump;
+ unsigned char rds_mode; /* RDS operation mode (RDS/RDBS) */
+ unsigned char af_mode; /* Alternate frequency on/off */
+ struct tuned_station_info cur_station_info;
+ struct fm_rds rds;
+};
+
+/*
+ * FM TX RDS data
+ *
+ * @ text_type: is the text following PS or RT
+ * @ text: radio text string which could either be PS or RT
+ * @ af_freq: alternate frequency for Tx
+ * TODO: to be declared in application
+ */
+struct tx_rds {
+ unsigned char text_type;
+ unsigned char text[25];
+ unsigned int af_freq;
+};
+/*
+ * FM TX global data
+ *
+ * @ pwr_lvl: Power Level of the Transmission from mixer control
+ * @ xmit_state: Transmission state = Updated locally upon Start/Stop
+ * @ audio_io: i2S/Analog
+ * @ tx_frq: Transmission frequency
+ */
+struct fmtx_data {
+ unsigned char pwr_lvl;
+ unsigned char xmit_state;
+ unsigned char audio_io;
+ unsigned long tx_frq;
+ struct tx_rds rds;
+};
+
+/* FM driver operation structure */
+struct fmdrv_ops {
+ struct video_device *v4l2dev; /* V4L2 video device pointer */
+ struct snd_card *card; /* Card which holds FM mixer controls */
+ unsigned short asci_id;
+ spinlock_t rds_buff_lock;
+ spinlock_t resp_skb_lock;
+
+ long flag; /* FM driver state machine info */
+
+ struct sk_buff_head rx_q; /* RX queue */
+ struct tasklet_struct rx_task; /* RX Tasklet */
+
+ struct sk_buff_head tx_q; /* TX queue */
+ struct tasklet_struct tx_task; /* TX Tasklet */
+ unsigned long last_tx_jiffies; /* Timestamp of last pkt sent */
+ atomic_t tx_cnt; /* Number of packets can send at a time */
+
+ struct sk_buff *response_skb; /* Response from the chip */
+ /* Main task completion handler */
+ struct completion maintask_completion;
+ /* Opcode of last command sent to the chip */
+ unsigned char last_sent_pkt_opcode;
+ /* Handler used for wakeup when response packet is received */
+ struct completion *response_completion;
+ struct fm_irq irq_info;
+ unsigned char curr_fmmode; /* Current FM chip mode (TX, RX, OFF) */
+ struct fm_rx rx; /* FM receiver info */
+ struct fmtx_data tx_data;
+};
+
+#endif
diff --git a/drivers/misc/ti-st/fmdrv_chr.c b/drivers/misc/ti-st/fmdrv_chr.c
new file mode 100644
index 0000000..8755728
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_chr.c
@@ -0,0 +1,776 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Written by Raghavendra Shenoy (x0099675@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+
+#include <linux/tty.h>
+#include <linux/sched.h>
+
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include <linux/uaccess.h>
+
+#include "fmdrv_st.h"
+#include "fmdrv_chr.h"
+
+/* Structure that has FM character driver data */
+struct fm_chrdrv_ops *fm_chr_dev;
+
+/* File operations structure initialization */
+const struct file_operations fm_chr_ops = {
+ .owner = THIS_MODULE,
+ .fasync = fm_chr_fasync,
+ .open = fm_chr_open,
+ .read = fm_chr_read,
+ .write = fm_chr_write,
+ .poll = fm_chr_poll,
+ .ioctl = fm_chr_ioctl,
+ .release = fm_chr_release,
+};
+
+/* Converting Channel-8 response to Channel-4 response */
+static struct sk_buff *convert2_channel_4(struct sk_buff *ch8_skb)
+{
+ struct evt_cmd_complete *evt;
+ struct sk_buff *ch4_skb;
+
+ unsigned char ncmds; /* num_hci cmds */
+ unsigned char status;
+ unsigned char pkt_type;
+
+ unsigned short opcode;
+ unsigned short hci_vs_opcode;
+
+ unsigned char *ptr, *chan4_mem;
+ unsigned char chan4_index, chan8_index;
+ unsigned char num_hci, param_len, fm_opcode;
+ unsigned char read_write, evt_code, cmd_len, int_len, chan8_cmd_len;
+
+ FM_CHR_DRV_START();
+
+ fm_opcode = read_write = 0;
+ chan8_index = chan4_index = 0;
+ int_len = num_hci = cmd_len = param_len = 0;
+ opcode = 0x0000;
+
+ ptr = NULL;
+ ch4_skb = NULL;
+ chan4_mem = NULL;
+
+ chan8_cmd_len = ch8_skb->data[CHAN8_RESP_CMD_LEN_POS];
+ if ((chan8_cmd_len + CHAN8_RESP_CMD_LEN_SIZE + CHAN8_RESP_TYPE_SIZE) !=
+ ch8_skb->len) {
+ FM_CHR_DRV_ERR(" Channel-8 response length mismatch ");
+
+ return NULL;
+ }
+
+ /* Copy the opcode from Channel-1 command packet.
+ * Channel-8 response packets can only be converted into Channel-4
+ * HCI command complete event packets.
+ *
+ * Mark the packet type as Channel-4 packet type.
+ */
+ evt_code = CHAN4_CMD_COMPLETE_TYPE;
+
+ /* Copy the opcode from Channel-8 reponse packet */
+ fm_opcode = ch8_skb->data[CHAN8_RESP_FM_OPCODE_POS];
+
+ /* Conversion logic for response packets with Power mode opcode */
+ if (fm_opcode == CHAN8_FM_PWR_OPCODE) {
+ ch4_skb = alloc_skb(7, GFP_ATOMIC);
+ if (ch4_skb == NULL) {
+ FM_CHR_DRV_ERR(" SKB allocation failed ");
+ return NULL;
+ }
+
+ /* Copy from Channel-8 reponse packet */
+ pkt_type = CHAN4_PKT_TYPE;
+ evt_code = CHAN4_CMD_COMPLETE_TYPE; /* cmd complete event */
+ ncmds = ch8_skb->data[CHAN8_RESP_NUM_HCI_POS];/* num_hci cmds */
+ param_len = 4; /* fd37 + num hci cmds */
+ hci_vs_opcode = CHAN1_FM_PWR_OPCODE;
+ status = ch8_skb->data[CHAN8_RESP_STATUS_POS];
+
+ /* Copy to Channel-4 response packet */
+ memcpy(skb_put(ch4_skb, 1), &pkt_type, 1);
+ memcpy(skb_put(ch4_skb, 1), &evt_code, 1);
+ memcpy(skb_put(ch4_skb, 1), ¶m_len, 1);
+ memcpy(skb_put(ch4_skb, 1), &ncmds, 1);
+ memcpy(skb_put(ch4_skb, 2), &hci_vs_opcode, 2);
+ memcpy(skb_put(ch4_skb, 1), &status, 1);
+
+ /* Trim the data to specified length */
+ skb_trim(ch4_skb, 7);
+
+ return ch4_skb;
+ }
+
+ /* To accomodate an extra 0 that Channel-4 response sends */
+ ch4_skb = alloc_skb((ch8_skb->len + 1), GFP_ATOMIC);
+ if (ch4_skb == NULL) {
+ FM_CHR_DRV_ERR(" SKB allocation failed ");
+
+ return NULL;
+ }
+ skb_put(ch4_skb, ch8_skb->len + 1);
+
+ /* Copy the command length, NUM_HCI, R/W values from Channl-8 reponse
+ * packet
+ */
+ cmd_len = ch8_skb->data[CHAN8_RESP_CMD_LEN_POS];
+ num_hci = ch8_skb->data[CHAN8_RESP_NUM_HCI_POS];
+ read_write = ch8_skb->data[CHAN8_RESP_RW_POS];
+
+ /* Update Channel-4 response packet's opcode bit */
+ if (read_write == CHAN8_RD_RESP)
+ opcode = CHAN1_READ_OPCODE;
+ else
+ opcode = CHAN1_WRITE_OPCODE;
+
+ param_len = ch8_skb->data[CHAN8_RESP_PARAM_LEN_POS];
+
+ /* Copying the header-data to Channel-4 response packet */
+ ch4_skb->data[CHAN4_TYPE_POS] = CHAN4_PKT_TYPE;
+ ch4_skb->data[CHAN4_EVT_TYPE_POS] = evt_code;
+
+ /* Copying the parameters from Channel-8 response packets to Channel-4
+ * response packets.
+ */
+ evt = (void *)&ch4_skb->data[CHAN4_EVT_POS];
+ evt->opcode = opcode;
+ evt->ncmd = num_hci;
+
+ chan8_index = CHAN8_RESP_PARAM_POS;
+ chan4_index = CHAN4_PARAM_POS;
+
+ /* Allocate memory to copy the parameters. The parameters are
+ * copied from Channel-8 response packet to this memory and then
+ * copied to Channel-4 response packet.
+ */
+ chan4_mem = kzalloc((param_len) * (sizeof(unsigned char)), GFP_ATOMIC);
+
+ if (chan4_mem == NULL) {
+ FM_CHR_DRV_ERR(" chan4_mem == NULL ");
+
+ return ch8_skb;
+ }
+
+ int_len = param_len;
+ ptr = (void *)chan4_mem;
+
+ /* The parameters are copied from Channel-8 response packet to the
+ * intermediate memory location.
+ */
+ while (param_len--) {
+ *ptr = ch8_skb->data[chan8_index];
+ ptr++;
+ chan8_index++;
+ }
+
+ /* Copy the extra 0 */
+ ch4_skb->data[chan4_index] = 0x00;
+ chan4_index++;
+
+ param_len = int_len;
+ ptr = (void *)chan4_mem;
+
+ /* The parameters are copied from intermediate memory location
+ * to Channel-4 response packet.
+ */
+ while (param_len--) {
+ ch4_skb->data[chan4_index++] = *ptr;
+ ptr++;
+ }
+ kfree(chan4_mem);
+ /* plen would be chan8_index - pkt_type - evt code */
+ ch4_skb->data[CHAN4_PLEN_POS] =
+ chan8_index - CHAN4_PKT_TYPE_SIZE - CHAN4_EVT_TYPE_SIZE;
+
+ return ch4_skb;
+
+}
+
+/* Convert the Channel-1 commands into Channel-8 commands */
+static int convert2_channel_8(struct sk_buff *skb)
+{
+ struct hci_command_hdr *hdr;
+
+ unsigned short chan8_index, chan1_index;
+ unsigned char fm_opcode, read_write, num_params, chan1_cmd_len;
+
+ /* FM power ON/OFF commands */
+ unsigned char fm_pwr_on[] = { 0x08, 0x05, 0xFE, 0x00,
+ 0x02, 0x00, 0x01 };
+ unsigned char fm_pwr_off[] = { 0x08, 0x05, 0xFE, 0x00,
+ 0x02, 0x00, 0x00 };
+
+ FM_CHR_DRV_START();
+
+ hdr = NULL;
+ fm_opcode = 0;
+ read_write = 0;
+ num_params = 0;
+ chan8_index = 0;
+ chan1_index = 0;
+
+ chan1_cmd_len = skb->data[CHAN1_CMD_LEN_POS];
+
+ if ((chan1_cmd_len + CHAN1_TYPE_SIZE + CHAN1_OPCODE_SIZE +
+ CHAN1_CMD_LEN_SIZE) != skb->len) {
+ FM_CHR_DRV_ERR(" Channel-1 length mismatch ");
+
+ return -1;
+ }
+
+ /* Copy the opcode from Channel-1 command packet */
+ hdr = (void *)&skb->data[CHAN1_TYPE_POS];
+
+ /* Conversion for commands with Power mode opcode */
+ if (hdr->opcode == CHAN1_FM_PWR_OPCODE) {
+ /* Set skb length to zero and skb tail pointer
+ * to data pointer.
+ */
+ skb_trim(skb, 0);
+
+ /* For FM Power ON command */
+ if (skb->data[CHAN1_FM_OPCODE_POS] == 0x01) {
+ memcpy(skb_put(skb, sizeof(fm_pwr_on)), fm_pwr_on,
+ sizeof(fm_pwr_on));
+ } else {
+ /* For Power OFF command */
+ memcpy(skb_put(skb, sizeof(fm_pwr_off)), fm_pwr_off,
+ sizeof(fm_pwr_off));
+ }
+
+ return 0;
+ }
+
+ /* Copy the parameters from Channel-1 command packet */
+ /* Only the LSB of this value will be used */
+ num_params = skb->data[CHAN1_PARAM_LEN_POS];
+ fm_opcode = skb->data[CHAN1_FM_OPCODE_POS];
+ chan1_index = CHAN1_PARAM_POS;
+
+ /* Copy the Channel-1 header data to Channel-8 header fields */
+ read_write =
+ (hdr->opcode == CHAN1_READ_OPCODE) ? CHAN8_RD_CMD : CHAN8_WR_CMD;
+ skb->data[CHAN8_TYPE_POS] = CHAN8_PKT_TYPE;
+
+ /* cmd_length/skb->data[1] = fm_opcode + read_write + param_len
+ * in addition to num_params
+ */
+ skb->data[CHAN8_FM_OPCODE_POS] = fm_opcode;
+ skb->data[CHAN8_RW_POS] = read_write;
+ chan8_index = CHAN8_PARAM_POS;
+
+ skb->data[CHAN8_CMD_LEN_POS] = num_params + CHAN8_OPCODE_SIZE +
+ CHAN8_RD_WR_SIZE + CHAN8_PARAM_LEN_SIZE;
+
+ /* Copy the Channel-1 parameters to Channel-8 parameter field */
+
+ /* READ command except read_hw_register */
+ if ((read_write == CHAN8_RD_CMD) &&
+ (fm_opcode != CHAN1_HW_REG_OPCODE)) {
+ /* Expected bytes to read */
+ skb->data[CHAN8_PARAM_LEN_POS] = num_params;
+
+ chan8_index = CHAN8_PARAM_POS;
+ skb->data[CHAN8_CMD_LEN_POS] = CHAN8_OPCODE_SIZE +
+ CHAN8_RD_WR_SIZE + CHAN8_PARAM_LEN_SIZE;
+ } else {
+
+ /* skb->data[4] contains length of parameters following */
+ skb->data[CHAN8_PARAM_LEN_POS] = num_params;
+
+ while (num_params) {
+ skb->data[chan8_index] = skb->data[chan1_index];
+ chan8_index++;
+ chan1_index++;
+ num_params--;
+ }
+ }
+
+ skb_trim(skb, chan8_index);
+
+ return 0;
+}
+
+/* Tasklet function which will be scheduled by FM ST sub-module
+ * when data is received
+ */
+long fm_rx_task(void)
+{
+ struct sk_buff *skb;
+
+#ifdef VERBOSE
+ int len;
+#endif
+
+ FM_CHR_DRV_START();
+
+ skb = NULL;
+ spin_lock(&fm_chr_dev->lock);
+
+ if (skb_queue_empty(&fm_chr_dev->rx_q)) {
+ FM_CHR_DRV_ERR(" Rx Queue empty ");
+ spin_unlock(&fm_chr_dev->lock);
+ return FM_CHR_DRV_ERR_FAILURE;
+ }
+
+ /* Dequeue the skb received from the FM_ST interface */
+ skb = skb_dequeue(&fm_chr_dev->rx_q);
+ if (skb == NULL) {
+ FM_CHR_DRV_ERR(" Dequeued skb from Rx queue is NULL ");
+ spin_unlock(&fm_chr_dev->lock);
+ return FM_CHR_DRV_ERR_FAILURE;
+ }
+
+ /* Send a signal to TI FM stack when an Interrupt packet arrives */
+ if (skb->data[CHAN8_RESP_FM_OPCODE_POS] == CHAN8_FM_INTERRUPT) {
+ FM_CHR_DRV_VER(" Interrupt arrived: ");
+
+#ifdef VERBOSE
+ for (len = 0; ((skb) && (len < skb->len)); len++)
+ printk(KERN_INFO " 0x%02x ", skb->data[len]);
+ printk("\n");
+#endif
+
+ kfree_skb(skb);
+
+ /* kill_fasync here - Sends the signal. Check if the queue is
+ * empty. If not, it means that command complete response for
+ * the previous command is not sent to the stack. Don't send
+ * the Signal. Set the SIGNAL_PENDING bit. This bit is cleared
+ * in the read() of the stack, when it reads the command
+ * complete response.
+ */
+ if (likely(skb_queue_empty(&fm_chr_dev->rx_q))) {
+ /* Should come here most often */
+ kill_fasync(&fm_chr_dev->fm_fasync, SIGIO, POLLIN);
+ clear_bit(SIGNAL_PENDING, &fm_chr_dev->state_flags);
+ } else {
+ FM_CHR_DRV_VER(" signal not sent..");
+ set_bit(SIGNAL_PENDING, &fm_chr_dev->state_flags);
+ }
+
+ spin_unlock(&fm_chr_dev->lock);
+
+ return FM_CHR_DRV_SUCCESS;
+ }
+
+ /* Queue it back to the queue if the received packet
+ * is not an interrupt packet
+ */
+ skb_queue_head(&fm_chr_dev->rx_q, skb);
+ wake_up_interruptible(&fm_chr_dev->fm_data_q);
+
+ spin_unlock(&fm_chr_dev->lock);
+
+ return FM_CHR_DRV_SUCCESS;
+}
+
+/* Functions called from the TI-FM stack */
+int fm_chr_fasync(int fd, struct file *file, int on)
+{
+ FM_CHR_DRV_START();
+
+ return fasync_helper(fd, file, on, &fm_chr_dev->fm_fasync);
+}
+
+int fm_chr_open(struct inode *inod, struct file *fil)
+{
+ int err;
+ int err_st_release;
+
+ FM_CHR_DRV_START();
+
+ err = FM_CHR_DRV_SUCCESS;
+ err_st_release = FM_CHR_DRV_SUCCESS;
+
+ /* Check if V4L2 FM device is already using ST driver */
+ if (fm_st_claim() < FM_CHR_DRV_SUCCESS) {
+ FM_CHR_DRV_ERR(" Other FM device is already active ");
+
+ return FM_CHR_DRV_ERR_FAILURE;
+ }
+
+ /* Register with the FM_ST interface, which will register with the
+ * ST driver
+ */
+ err = fm_st_register(&fm_chr_dev->rx_q, &fm_chr_dev->rx_task);
+ if (err < FM_CHR_DRV_SUCCESS) {
+ FM_CHR_DRV_ERR(" Registration with ST Failed ");
+ FM_CHR_DRV_VER(" Releasing FM ST Interface... ");
+
+ err_st_release = fm_st_release();
+ if (err_st_release < FM_CHR_DRV_SUCCESS) {
+ FM_CHR_DRV_ERR(" Failed to release FM ST (%d)",
+ err_st_release);
+
+ return err;
+ }
+ FM_CHR_DRV_VER(" Successfully released FM_ST interface ");
+
+ return err;
+ }
+
+ /* Initialize the wait queue and the Rx tasklets */
+ init_waitqueue_head(&fm_chr_dev->fm_data_q);
+ tasklet_init(&fm_chr_dev->rx_task, (void *)fm_rx_task,
+ (unsigned long)fm_chr_dev);
+
+ FM_CHR_DRV_VER(" st_register completed");
+
+ return FM_CHR_DRV_SUCCESS;
+}
+
+int fm_chr_release(struct inode *inod, struct file *fil)
+{
+ int err;
+
+ FM_CHR_DRV_START();
+
+ err = 0;
+
+ /* Clear the asynchronous notifications to the process linked
+ * with the file descriptor 'fil'
+ */
+ fm_chr_fasync(-1, fil, 0);
+
+ /* Release the tasklets and the queues */
+ tasklet_kill(&fm_chr_dev->rx_task);
+ skb_queue_purge(&fm_chr_dev->rx_q);
+
+ /* Unregister FM with ST driver */
+ err = fm_st_unregister();
+ if (err < FM_CHR_DRV_SUCCESS) {
+ FM_CHR_DRV_ERR(" Unable to unregister from ST ");
+
+ return err;
+ }
+ FM_CHR_DRV_VER(" Successfully unregistered from ST ");
+
+ /* Release FM ST - FM character driver is not using
+ * the ST driver
+ */
+ err = fm_st_release();
+ if (err < FM_CHR_DRV_SUCCESS) {
+ FM_CHR_DRV_ERR(" Failed to release FM ST ");
+
+ return err;
+ }
+ FM_CHR_DRV_VER(" Successfully released FM_ST interface ");
+
+ return FM_CHR_DRV_SUCCESS;
+}
+
+ssize_t fm_chr_write(struct file *fil, const char __user *data,
+ size_t size, loff_t *offset)
+{
+ int err;
+ struct sk_buff *skb;
+
+#ifdef VERBOSE
+ int len;
+#endif
+
+ FM_CHR_DRV_START();
+
+ err = FM_CHR_DRV_SUCCESS;
+
+ if (data[CHAN1_TYPE_POS] != CHAN1_PKT_TYPE) {
+ FM_CHR_DRV_ERR(" Packet type is not Channel-1 ");
+
+ return FM_CHR_DRV_ERR_FAILURE;
+ }
+
+ /* Allocate the SKB */
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (!skb) {
+ FM_CHR_DRV_ERR(" Did not allocate SKB ");
+
+ return FM_CHR_DRV_ERR_FAILURE;
+ }
+
+ /* Forward the data from the user space to ST core */
+ if (copy_from_user(skb_put(skb, size), data, size)) {
+ FM_CHR_DRV_ERR(" Unable to copy from user space");
+ kfree_skb(skb);
+
+ return -EFAULT;
+ }
+#ifdef VERBOSE
+ printk(KERN_INFO "Write: Before conversion\n");
+ for (len = 0; ((skb) && (len < skb->len)); len++)
+ printk(KERN_INFO "0x%02x ", skb->data[len]);
+ printk("\n");
+#endif
+
+ /* Convert the Channel-1 command packet to Channel-8 command packet */
+ if (convert2_channel_8(skb) < 0) {
+ FM_CHR_DRV_ERR(" Conversion to Channel-8 failed ");
+ kfree_skb(skb);
+
+ return FM_CHR_DRV_ERR_FAILURE;
+ }
+#ifdef VERBOSE
+ printk(KERN_INFO "Write: After conversion\n");
+ for (len = 0; ((skb) && (len < skb->len)); len++)
+ printk(KERN_INFO "0x%02x ", skb->data[len]);
+ printk("\n");
+#endif
+
+ /* Write to ST driver through FM_ST interface */
+ err = fm_st_send(skb);
+ if (err < FM_CHR_DRV_SUCCESS) {
+ FM_CHR_DRV_ERR(" Cannot write to ST, fm_st_send failed (%d)",
+ err);
+ kfree_skb(skb);
+
+ return FM_CHR_DRV_ERR_FAILURE;
+ }
+
+ init_waitqueue_head(&fm_chr_dev->fm_data_q);
+
+ return size;
+}
+
+ssize_t fm_chr_read(struct file *fil, char __user *data, size_t size,
+ loff_t *offset)
+{
+ int len;
+ struct sk_buff *skb;
+ struct sk_buff *ch4_skb;
+
+ FM_CHR_DRV_START();
+
+ skb = NULL;
+ ch4_skb = NULL;
+
+ /* Wait till the data is available */
+ if (!wait_event_interruptible_timeout(fm_chr_dev->fm_data_q,
+ !skb_queue_empty
+ (&fm_chr_dev->rx_q), 500)) {
+
+ FM_CHR_DRV_ERR(" Read timed out ");
+
+ return -EAGAIN;
+ }
+ FM_CHR_DRV_VER(" Completed Read wait ");
+
+ spin_lock(&fm_chr_dev->lock);
+
+ /* Dequeue the data from the queue if the data
+ * is already available
+ */
+ if (!skb_queue_empty(&fm_chr_dev->rx_q))
+ skb = skb_dequeue(&fm_chr_dev->rx_q);
+
+ spin_unlock(&fm_chr_dev->lock);
+
+ if (unlikely
+ (skb == NULL || skb->len == 0 || skb->data == NULL
+ || skb->cb[0] != CHAN8_PKT_TYPE)) {
+ FM_CHR_DRV_VER(" Length of the response packet is invalid ");
+ kfree_skb(skb);
+
+ return FM_CHR_DRV_ERR_FAILURE;
+ }
+#ifdef VERBOSE
+ printk(KERN_INFO "Read: Before conversion\n");
+ for (len = 0; len < skb->len; len++)
+ printk(KERN_INFO "0x%02x ", skb->data[len]);
+ printk("\n");
+#endif
+
+ /* Convert if the response packet is of Channel-8 type */
+ if (!skb->data[CHAN8_RESP_CMD_LEN_POS]) {
+ kfree(skb);
+
+ return FM_CHR_DRV_ERR_FAILURE;
+ }
+
+ /* Convert the Channel-8 response packet to Channel-4 response packet */
+ ch4_skb = convert2_channel_4(skb);
+
+ if (ch4_skb == NULL) {
+ FM_CHR_DRV_ERR(" Converted SKB is NULL ");
+ kfree(skb);
+
+ return FM_CHR_DRV_ERR_FAILURE;
+ }
+#ifdef VERBOSE
+ printk(KERN_INFO "Read: After conversion\n");
+ for (len = 0; (ch4_skb != NULL) && len < (ch4_skb->len); len++)
+ printk(KERN_INFO "0x%02x ", ch4_skb->data[len]);
+ printk("\n");
+#endif
+
+ if (size >= ch4_skb->len) {
+ /* Forward the data to the user */
+ if (copy_to_user(data, ch4_skb->data, ch4_skb->len)) {
+ FM_CHR_DRV_ERR(" Unable to copy to user space ");
+ kfree_skb(skb);
+ kfree_skb(ch4_skb);
+ spin_unlock(&fm_chr_dev->lock);
+
+ return -EFAULT;
+ }
+ } else {
+ FM_CHR_DRV_ERR(" Buffer overflow ");
+ kfree_skb(skb);
+ kfree_skb(ch4_skb);
+
+ return -ENOMEM;
+ }
+
+ len = ch4_skb->len;
+ kfree(skb);
+ kfree(ch4_skb);
+
+ /* Clear the pending bit that was set when an interrupt packet had
+ * arrived
+ */
+ if (test_bit(SIGNAL_PENDING, &fm_chr_dev->state_flags)
+ && skb_queue_empty(&fm_chr_dev->rx_q)) {
+ FM_CHR_DRV_DBG(" Sending signal ");
+
+ kill_fasync(&fm_chr_dev->fm_fasync, SIGIO, POLLIN);
+ clear_bit(SIGNAL_PENDING, &fm_chr_dev->state_flags);
+ }
+
+ return len;
+}
+
+unsigned int fm_chr_poll(struct file *file, poll_table * wait)
+{
+ unsigned long mask;
+
+ FM_CHR_DRV_DBG(" inside %s", __func__);
+
+ mask = 0;
+
+ /* Poll and wait */
+ poll_wait(file, &fm_chr_dev->fm_data_q, wait);
+
+ spin_lock(&fm_chr_dev->lock);
+
+ FM_CHR_DRV_VER(" Completed poll ");
+
+ if (!skb_queue_empty(&fm_chr_dev->rx_q))
+ mask |= POLLIN;
+
+ FM_CHR_DRV_VER(" return 0x%02x \n", (unsigned int)mask);
+
+ spin_unlock(&fm_chr_dev->lock);
+
+ return mask;
+}
+
+int fm_chr_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ FM_CHR_DRV_START();
+
+ return FM_CHR_DRV_SUCCESS;
+}
+
+/* FM character driver init: Initializes the FM character driver parametes */
+int fm_chr_init(void)
+{
+ FM_CHR_DRV_START();
+
+ fm_chr_dev = kzalloc(sizeof(struct fm_chrdrv_ops), GFP_ATOMIC);
+
+ if (fm_chr_dev == NULL) {
+ FM_CHR_DRV_ERR
+ (" Cannot allocate memory for FM character driver ");
+
+ return -ENOMEM;
+ }
+
+ skb_queue_head_init(&fm_chr_dev->rx_q);
+
+ /* Initialize wait queue and a flag, so that the
+ * wait queue can be used later
+ */
+ init_completion(&fm_chr_dev->reg_completed);
+ init_waitqueue_head(&fm_chr_dev->fm_data_q);
+
+ /* Expose the device FM_CHAR_DEVICE_NAME to user space
+ * and obtain the major number for the device
+ */
+ fm_chr_dev->fm_chr_major =
+ register_chrdev(0, FM_CHAR_DEVICE_NAME, &fm_chr_ops);
+ FM_CHR_DRV_VER(" allocated %d, %d", fm_chr_dev->fm_chr_major, 0);
+
+ if (fm_chr_dev->fm_chr_major < 0) {
+ FM_CHR_DRV_ERR(" register_chrdev failed ");
+
+ return FM_CHR_DRV_ERR_FAILURE;
+ }
+
+ /* udev */
+ fm_chr_dev->fm_chr_class =
+ class_create(THIS_MODULE, FM_CHAR_DEVICE_NAME);
+ if (IS_ERR(fm_chr_dev->fm_chr_class)) {
+ FM_CHR_DRV_ERR(" Something went wrong in class_create");
+
+ return FM_CHR_DRV_ERR_CLASS;
+ }
+
+ fm_chr_dev->fm_chr_dev =
+ device_create(fm_chr_dev->fm_chr_class, NULL,
+ MKDEV(fm_chr_dev->fm_chr_major, 0), NULL,
+ FM_CHAR_DEVICE_NAME);
+
+ if (IS_ERR(fm_chr_dev->fm_chr_dev)) {
+ FM_CHR_DRV_ERR(" Cannot create the device %s ",
+ FM_CHAR_DEVICE_NAME);
+
+ return -ENODEV;
+ }
+
+ return FM_CHR_DRV_SUCCESS;
+}
+
+/* FM character driver init: Destroys the FM character driver parametes */
+void fm_chr_exit(void)
+{
+ FM_CHR_DRV_START();
+
+ FM_CHR_DRV_VER(" Freeing up %d", fm_chr_dev->fm_chr_major);
+
+ skb_queue_purge(&fm_chr_dev->rx_q);
+ device_destroy(fm_chr_dev->fm_chr_class,
+ MKDEV(fm_chr_dev->fm_chr_major, 0));
+
+ class_unregister(fm_chr_dev->fm_chr_class);
+ class_destroy(fm_chr_dev->fm_chr_class);
+
+ unregister_chrdev(fm_chr_dev->fm_chr_major, FM_CHAR_DEVICE_NAME);
+}
diff --git a/drivers/misc/ti-st/fmdrv_chr.h b/drivers/misc/ti-st/fmdrv_chr.h
new file mode 100644
index 0000000..2b4161b
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_chr.h
@@ -0,0 +1,194 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Written by Raghavendra Shenoy (x0099675@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _FM_CHR_DRV_H
+#define _FM_CHR_DRV_H
+
+/* #define VERBOSE */
+
+/* Debug macros */
+#define FM_CHR_DRV_ERR(fmt, arg...) \
+ pr_err("(fm_chr_drv):"fmt"\n" , ## arg)
+
+#if defined(DEBUG) /* limited debug messages */
+#define FM_CHR_DRV_DBG(fmt, arg...) \
+ pr_info("(fm_chr_drv):"fmt"\n" , ## arg)
+#define FM_CHR_DRV_VER(fmt, arg...)
+#define FM_CHR_DRV_START() \
+ pr_info("(fm_chr_drv): Inside %s\n", __func__)
+#elif defined(VERBOSE) /* very verbose */
+#define FM_CHR_DRV_DBG(fmt, arg...) \
+ pr_info("(fm_chr_drv):"fmt"\n" , ## arg)
+#define FM_CHR_DRV_VER(fmt, arg...) \
+ pr_info("(fm_chr_drv):"fmt"\n" , ## arg)
+#define FM_CHR_DRV_START() \
+ pr_info("(fm_chr_drv): Inside %s\n", __func__)
+#else /* Error msgs only */
+#define FM_CHR_DRV_DBG(fmt, arg...)
+#define FM_CHR_DRV_VER(fmt, arg...)
+#define FM_CHR_DRV_START()
+#endif
+
+/* FM device */
+#define FM_CHAR_DEVICE_NAME "tifm"
+
+/* Macros for packet conversion */
+#define CHAN1_FM_PWR_OPCODE 0xFD37
+#define CHAN1_READ_OPCODE 0xFD33
+#define CHAN1_WRITE_OPCODE 0xFD35
+
+#define CHAN1_HW_REG_OPCODE 0x64
+#define CHAN8_FM_PWR_OPCODE 0xFE
+#define CHAN8_FM_INTERRUPT 0xFF
+#define CHAN8_FM_INTERRUPT_OPCODE 0xF0
+
+/* Packet types */
+#define CHAN1_PKT_TYPE 0x01
+#define CHAN8_PKT_TYPE 0x08
+#define CHAN4_PKT_TYPE 0x04
+#define CHAN4_CMD_COMPLETE_TYPE 0x0E
+
+#define CHAN8_RD_CMD 0x01
+#define CHAN8_WR_CMD 0x00
+
+#define CHAN8_RD_RESP 0x01
+#define CHAN8_WR_RESP 0x00
+
+/* Channel-4 data sizes */
+#define CHAN4_PKT_TYPE_SIZE 1
+#define CHAN4_EVT_TYPE_SIZE 1
+
+/* Channel-8 data sizes */
+#define CHAN8_OPCODE_SIZE 1
+#define CHAN8_RD_WR_SIZE 1
+#define CHAN8_PARAM_LEN_SIZE 1
+
+/* Channel-8 response data sizes */
+#define CHAN8_RESP_TYPE_SIZE 1
+#define CHAN8_RESP_CMD_LEN_SIZE 1
+
+/* HCI-VS data sizes */
+#define CHAN1_TYPE_SIZE 1
+#define CHAN1_OPCODE_SIZE 2
+#define CHAN1_CMD_LEN_SIZE 1
+
+/* HCI-VS data positions */
+#define CHAN1_TYPE_POS 0
+#define CHAN1_OPCODE_POS 1
+#define CHAN1_CMD_LEN_POS 3
+#define CHAN1_FM_OPCODE_POS 4
+#define CHAN1_PARAM_LEN_POS 5
+
+/* Because of an extra Zero appended to param_len */
+#define CHAN1_PARAM_POS 7
+
+/* Channel-8 command positions */
+#define CHAN8_TYPE_POS 0
+#define CHAN8_CMD_LEN_POS 1
+#define CHAN8_FM_OPCODE_POS 2
+#define CHAN8_RW_POS 3
+#define CHAN8_PARAM_LEN_POS 4
+#define CHAN8_PARAM_POS 5
+
+/* Channel-8 response positions */
+#define CHAN8_RESP_CMD_LEN_POS 1
+#define CHAN8_RESP_STATUS_POS 2
+#define CHAN8_RESP_NUM_HCI_POS 3
+#define CHAN8_RESP_FM_OPCODE_POS 4
+#define CHAN8_RESP_RW_POS 5
+#define CHAN8_RESP_PARAM_LEN_POS 6
+#define CHAN8_RESP_PARAM_POS 7
+
+/* Channel-4 data positions */
+#define CHAN4_TYPE_POS 0
+#define CHAN4_EVT_TYPE_POS 1
+#define CHAN4_PLEN_POS 2
+#define CHAN4_EVT_POS 3
+#define CHAN4_PARAM_POS 6
+
+/* Forward declaration file operations */
+void fm_chr_exit(void);
+int fm_chr_init(void);
+
+int fm_chr_fasync(int, struct file *, int);
+
+int fm_chr_open(struct inode *, struct file *);
+int fm_chr_release(struct inode *, struct file *);
+
+ssize_t fm_chr_write(struct file *, const char __user *, size_t, loff_t *);
+ssize_t fm_chr_read(struct file *, char __user *, size_t, loff_t *);
+unsigned int fm_chr_poll(struct file *, poll_table *);
+
+int fm_chr_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+long fm_rx_task(void);
+
+/* List of error codes returned by the FM driver */
+enum {
+ FM_CHR_DRV_ERR_FAILURE = -1, /* check struct */
+ FM_CHR_DRV_SUCCESS,
+ FM_CHR_DRV_ERR_PENDING = -5, /* to call reg_complete_cb */
+ FM_CHR_DRV_ERR_ALREADY, /* already registered */
+ FM_CHR_DRV_ERR_INPROGRESS,
+ FM_CHR_DRV_ERR_NOPROTO, /* protocol not supported */
+ FM_CHR_DRV_ERR_CLASS = -15,
+ FM_CHR_DRV_READ_TIMEOUT,
+};
+
+/* Header structure for HCI command packet */
+struct hci_command_hdr {
+ uint8_t prefix;
+ uint16_t opcode;
+ uint8_t plen;
+} __attribute__ ((packed));
+
+/* Header structure for HCI event packet */
+struct evt_cmd_complete {
+ uint8_t ncmd;
+ uint16_t opcode;
+} __attribute__ ((packed));
+
+/* Flag to send the signal after the command complete
+ * event's skb is removed from the RX queue
+ */
+#define SIGNAL_PENDING 1
+
+/* FM Character driver data */
+struct fm_chrdrv_ops {
+ int fm_chr_major;
+ struct device *fm_chr_dev;
+ struct class *fm_chr_class;
+
+ spinlock_t lock;
+
+ unsigned long state_flags;
+
+ struct sk_buff_head rx_q;
+ struct tasklet_struct rx_task;
+
+ wait_queue_head_t fm_data_q;
+ struct completion reg_completed;
+
+ struct fasync_struct *fm_fasync;
+
+ long (*st_write) (struct sk_buff *);
+};
+
+#endif /*_FM_CHR_DRV_H */
diff --git a/drivers/misc/ti-st/fmdrv_core.c b/drivers/misc/ti-st/fmdrv_core.c
new file mode 100644
index 0000000..cbf3599
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_core.c
@@ -0,0 +1,3715 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * This sub-module of FM driver does,
+ * 1) Forming group of Channel-8 commands to perform particular
+ * functionality (ex., frequency set require more than
+ * one Channel-8 command to be sent to the chip).
+ * 2) Sending each Channel-8 command to the chip and reading
+ * response back over Shared Transport.
+ * 3) Managing TX and RX Queues and Tasklets
+ * 4) Handling FM Interrupt packet and taking appropriate action.
+ * 5) Loading FM firmware to the chip (common, TX, and RX
+ * firmware files based on mode selection)
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include "fmdrv.h"
+#include "fmdrv_v4l2.h"
+#include "fmdrv_core.h"
+#include "fmdrv_st.h"
+#include "fmdrv_mixer.h"
+#include "fmdrv_chr.h"
+
+/* -- FM chip register table -- */
+static struct fm_reg_table fm_reg_info[] = {
+ /* ----- FM RX registers -------*/
+ /* opcode, type(rd/wr), reg name */
+ {0x00, REG_RD, "STEREO_GET"},
+ {0x01, REG_RD, "RSSI_LVL_GET"},
+ {0x02, REG_RD, "IF_COUNT_GET"},
+ {0x03, REG_RD, "FLAG_GET"},
+ {0x04, REG_RD, "RDS_SYNC_GET"},
+ {0x05, REG_RD, "RDS_DATA_GET"},
+ {0x0a, REG_WR, "FREQ_SET"},
+ {0x0a, REG_RD, "FREQ_GET"},
+ {0x0b, REG_WR, "AF_FREQ_SET"},
+ {0x0b, REG_RD, "AF_FREQ_GET"},
+ {0x0c, REG_WR, "MOST_MODE_SET"},
+ {0x0c, REG_RD, "MOST_MODE_GET"},
+ {0x0d, REG_WR, "MOST_BLEND_SET"},
+ {0x0d, REG_RD, "MOST_BLEND_GET"},
+ {0x0e, REG_WR, "DEMPH_MODE_SET"},
+ {0x0e, REG_RD, "DEMPH_MODE_GET"},
+ {0x0f, REG_WR, "SEARCH_LVL_SET"},
+ {0x0f, REG_RD, "SEARCH_LVL_GET"},
+ {0x10, REG_WR, "RX_BAND_SET"},
+ {0x10, REG_RD, "RX_BAND_GET"},
+ {0x11, REG_WR, "MUTE_STATUS_SET"},
+ {0x11, REG_RD, "MUTE_STATUS_GET"},
+ {0x12, REG_WR, "RDS_PAUSE_LVL_SET"},
+ {0x12, REG_RD, "RDS_PAUSE_LVL_GET"},
+ {0x13, REG_WR, "RDS_PAUSE_DUR_SET"},
+ {0x13, REG_RD, "RDS_PAUSE_DUR_GET"},
+ {0x14, REG_WR, "RDS_MEM_SET"},
+ {0x14, REG_RD, "RDS_MEM_GET"},
+ {0x15, REG_WR, "RDS_BLK_B_SET"},
+ {0x15, REG_RD, "RDS_BLK_B_GET"},
+ {0x16, REG_WR, "RDS_MSK_B_SET"},
+ {0x16, REG_RD, "RDS_MSK_B_GET"},
+ {0x17, REG_WR, "RDS_PI_MASK_SET"},
+ {0x17, REG_RD, "RDS_PI_MASK_GET"},
+ {0x18, REG_WR, "RDS_PI_SET"},
+ {0x18, REG_RD, "RDS_PI_GET"},
+ {0x19, REG_WR, "RDS_SYSTEM_SET"},
+ {0x19, REG_RD, "RDS_SYSTEM_GET"},
+ {0x1a, REG_WR, "INT_MASK_SET"},
+ {0x1a, REG_RD, "INT_MASK_GET"},
+ {0x1b, REG_WR, "SRCH_DIR_SET"},
+ {0x1b, REG_RD, "SRCH_DIR_GET"},
+ {0x1c, REG_WR, "VOLUME_SET"},
+ {0x1c, REG_RD, "VOLUME_GET"},
+ {0x1d, REG_WR, "AUDIO_ENABLE(SET)"},
+ {0x1d, REG_RD, "AUDIO_ENABLE(GET)"},
+ {0x1e, REG_WR, "PCM_MODE_SET"},
+ {0x1e, REG_RD, "PCM_MODE_SET"},
+ {0x1f, REG_WR, "I2S_MD_CFG_SET"},
+ {0x1f, REG_RD, "I2S_MD_CFG_GET"},
+ {0x20, REG_WR, "POWER_SET"},
+ {0x20, REG_RD, "POWER_GET"},
+ {0x21, REG_WR, "INTx_CONFIG_SET"},
+ {0x21, REG_RD, "INTx_CONFIG_GET"},
+ {0x22, REG_WR, "PULL_EN_SET"},
+ {0x22, REG_RD, "PULL_EN_GET"},
+ {0x23, REG_WR, "HILO_SET"},
+ {0x23, REG_RD, "HILO_GET"},
+ {0x24, REG_WR, "SWITCH2FREF"},
+ {0x25, REG_WR, "FREQ_DRIFT_REP"},
+ {0x28, REG_RD, "PCE_GET"},
+ {0x29, REG_RD, "FIRM_VER_GET"},
+ {0x2a, REG_RD, "ASIC_VER_GET"},
+ {0x2b, REG_RD, "ASIC_ID_GET"},
+ {0x2c, REG_RD, "MAIN_ID_GET"},
+ {0x2d, REG_WR, "TUNER_MODE_SET"},
+ {0x2e, REG_WR, "STOP_SEARCH"},
+ {0x2f, REG_WR, "RDS_CNTRL_SET"},
+ {0x64, REG_WR, "WR_HW_REG"},
+ {0x65, REG_WR, "CODE_DOWNLOAD"},
+ {0x66, REG_WR, "RESET"},
+ {0xfe, REG_WR, "FM_POWER_MODE(SET)"},
+ {0xff, REG_RD, "FM_INTERRUPT"},
+
+ /* --- FM TX registers ------ */
+ {0x37, REG_WR, "CHANL_SET"},
+ {0x37, REG_RD, "CHANL_GET"},
+ {0x38, REG_WR, "CHANL_BW_SET"},
+ {0x38, REG_RD, "CHANL_BW_GET"},
+ {0x87, REG_WR, "REF_SET"},
+ {0x87, REG_RD, "REF_GET"},
+ {0x5a, REG_WR, "POWER_ENB_SET"},
+ {0x3a, REG_WR, "POWER_ATT_SET"},
+ {0x3a, REG_RD, "POWER_ATT_GET"},
+ {0x3b, REG_WR, "POWER_LEL_SET"},
+ {0x3b, REG_RD, "POWER_LEL_GET"},
+ {0x3c, REG_WR, "AUDIO_DEV_SET"},
+ {0x3c, REG_RD, "AUDIO_DEV_GET"},
+ {0x3d, REG_WR, "PILOT_DEV_SET"},
+ {0x3d, REG_RD, "PILOT_DEV_GET"},
+ {0x3e, REG_WR, "RDS_DEV_SET"},
+ {0x3e, REG_RD, "RDS_DEV_GET"},
+ {0x5b, REG_WR, "PUPD_SET"},
+ {0x3f, REG_WR, "AUDIO_IO_SET"},
+ {0x40, REG_WR, "PREMPH_SET"},
+ {0x40, REG_RD, "PREMPH_GET"},
+ {0x41, REG_WR, "TX_BAND_SET"},
+ {0x41, REG_RD, "TX_BAND_GET"},
+ {0x42, REG_WR, "MONO_SET"},
+ {0x42, REG_RD, "MONO_GET"},
+ {0x5C, REG_WR, "MUTE"},
+ {0x43, REG_WR, "MPX_LMT_ENABLE"},
+ {0x06, REG_RD, "LOCK_GET"},
+ {0x5d, REG_WR, "REF_ERR_SET"},
+ {0x44, REG_WR, "PI_SET"},
+ {0x44, REG_RD, "PI_GET"},
+ {0x45, REG_WR, "TYPE_SET"},
+ {0x45, REG_RD, "TYPE_GET"},
+ {0x46, REG_WR, "PTY_SET"},
+ {0x46, REG_RD, "PTY_GET"},
+ {0x47, REG_WR, "AF_SET"},
+ {0x47, REG_RD, "AF_GET"},
+ {0x48, REG_WR, "DISPLAY_SIZE_SET"},
+ {0x48, REG_RD, "DISPLAY_SIZE_GET"},
+ {0x49, REG_WR, "RDS_MODE_SET"},
+ {0x49, REG_RD, "RDS_MODE_GET"},
+ {0x4a, REG_WR, "DISPLAY_MODE_SET"},
+ {0x4a, REG_RD, "DISPLAY_MODE_GET"},
+ {0x62, REG_WR, "LENGHT_SET"},
+ {0x4b, REG_RD, "LENGHT_GET"},
+ {0x4c, REG_WR, "TOGGLE_AB_SET"},
+ {0x4c, REG_RD, "TOGGLE_AB_GET"},
+ {0x4d, REG_WR, "RDS_REP_SET"},
+ {0x4d, REG_RD, "RDS_REP_GET"},
+ {0x63, REG_WR, "RDS_DATA_SET"},
+ {0x5e, REG_WR, "RDS_DATA_ENB"},
+ {0x4e, REG_WR, "TA_SET"},
+ {0x4e, REG_RD, "TA_GET"},
+ {0x4f, REG_WR, "TP_SET"},
+ {0x4f, REG_RD, "TP_GET"},
+ {0x50, REG_WR, "DI_SET"},
+ {0x50, REG_RD, "DI_GET"},
+ {0x51, REG_WR, "MS_SET"},
+ {0x51, REG_RD, "MS_GET"},
+ {0x52, REG_WR, "PS_SCROLL_SPEED_SET"},
+ {0x52, REG_RD, "PS_SCROLL_SPEED_GET"},
+};
+
+/* Region info */
+static struct region_info region_configs[] = {
+ /* Europe/US */
+ {
+ .channel_spacing = 50, /* 50 KHz */
+ .bottom_frequency = 87500, /* 87.5 MHz */
+ .top_frequency = 108000, /* 108 MHz */
+ .region_index = 0,
+ },
+ /* Japan */
+ {
+ .channel_spacing = 50, /* 50 KHz */
+ .bottom_frequency = 76000, /* 76 MHz */
+ .top_frequency = 90000, /* 90 MHz */
+ .region_index = 1,
+ },
+};
+
+/* Band selection */
+static unsigned char default_radio_region; /* Europe/US */
+module_param(default_radio_region, byte, 0);
+MODULE_PARM_DESC(default_radio_region, "Region: 0=Europe/US, 1=Japan");
+
+/* RDS buffer blocks */
+static unsigned int default_rds_buf = 300;
+module_param(default_rds_buf, uint, 0444);
+MODULE_PARM_DESC(rds_buf, "RDS buffer entries");
+
+/* FM irq handlers forward declaration */
+static void fm_core_irq_send_flag_getcmd(void);
+static void fm_core_irq_handle_flag_getcmd_resp(void);
+static void fm_core_irq_handle_hw_malfunction(void);
+static void fm_core_irq_handle_rds_start(void);
+static void fm_core_irq_send_rdsdata_getcmd(void);
+static void fm_core_irq_handle_rdsdata_getcmd_resp(void);
+static void fm_core_irq_handle_rds_finish(void);
+static void fm_core_irq_handle_tune_op_ended(void);
+static void fm_core_irq_handle_power_enb(void);
+static void fm_core_irq_handle_low_rssi_start(void);
+static void fm_core_irq_afjump_set_pi(void);
+static void fm_core_irq_handle_set_pi_resp(void);
+static void fm_core_irq_afjump_set_pimask(void);
+static void fm_core_irq_handle_set_pimask_resp(void);
+static void fm_core_irq_afjump_setfreq(void);
+static void fm_core_irq_handle_setfreq_resp(void);
+static void fm_core_irq_afjump_enableint(void);
+static void fm_core_irq_afjump_enableint_resp(void);
+static void fm_core_irq_start_afjump(void);
+static void fm_core_irq_handle_start_afjump_resp(void);
+static void fm_core_irq_afjump_rd_freq(void);
+static void fm_core_irq_afjump_rd_freq_resp(void);
+static void fm_core_irq_handle_low_rssi_finish(void);
+static void fm_core_irq_send_intmsk_cmd(void);
+static void fm_core_irq_handle_intmsk_cmd_resp(void);
+
+/* When FM core receives interrupt packet , following handlers
+ * will be executed one after another to service the interrupt(s) */
+
+/* Interrupt handler index */
+enum fm_irq_handler_index{
+
+ FM_SEND_FLAG_GETCMD_INDEX,
+ FM_HANDLE_FLAG_GETCMD_RESP_INDEX,
+
+ /* HW malfunction irq handler */
+ FM_HW_MAL_FUNC_INDEX,
+
+ /* RDS threshold reached irq handler */
+ FM_RDS_START_INDEX,
+ FM_RDS_SEND_RDS_GETCMD_INDEX,
+ FM_RDS_HANDLE_RDS_GETCMD_RESP_INDEX,
+ FM_RDS_FINISH_INDEX,
+
+ /* Tune operation ended irq handler */
+ FM_HW_TUNE_OP_ENDED_INDEX,
+
+ /* TX power enable irq handler */
+ FM_HW_POWER_ENB_INDEX,
+
+ /* Low RSSI irq handler */
+ FM_LOW_RSSI_START_INDEX,
+ FM_AF_JUMP_SETPI_INDEX,
+ FM_AF_JUMP_HANDLE_SETPI_RESP_INDEX,
+ FM_AF_JUMP_SETPI_MASK_INDEX,
+ FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_INDEX,
+ FM_AF_JUMP_SET_AF_FREQ_INDEX,
+ FM_AF_JUMP_HENDLE_SET_AFFREQ_RESP_INDEX,
+ FM_AF_JUMP_ENABLE_INT_INDEX,
+ FM_AF_JUMP_ENABLE_INT_RESP_INDEX,
+ FM_AF_JUMP_START_AFJUMP_INDEX,
+ FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_INDEX,
+ FM_AF_JUMP_RD_FREQ_INDEX,
+ FM_AF_JUMP_RD_FREQ_RESP_INDEX,
+ FM_LOW_RSSI_FINISH_INDEX,
+
+ /* Interrupt process post action */
+ FM_SEND_INTMSK_CMD_INDEX,
+ FM_HANDLE_INTMSK_CMD_RESP_INDEX,
+};
+
+/* FM interrupt handler table */
+static Int_Handler_ProtoType g_IntHandlerTable[] = {
+ fm_core_irq_send_flag_getcmd,
+ fm_core_irq_handle_flag_getcmd_resp,
+
+ /* HW malfunction irq handler */
+ fm_core_irq_handle_hw_malfunction,
+
+ /* RDS threshold reached irq handler */
+ fm_core_irq_handle_rds_start,
+ fm_core_irq_send_rdsdata_getcmd,
+ fm_core_irq_handle_rdsdata_getcmd_resp,
+ fm_core_irq_handle_rds_finish,
+
+ /* Tune operation ended irq handler */
+ fm_core_irq_handle_tune_op_ended,
+
+ /* TX power enable irq handler */
+ fm_core_irq_handle_power_enb,
+
+ /* Low RSSI irq handler */
+ fm_core_irq_handle_low_rssi_start,
+ fm_core_irq_afjump_set_pi,
+ fm_core_irq_handle_set_pi_resp,
+ fm_core_irq_afjump_set_pimask,
+ fm_core_irq_handle_set_pimask_resp,
+ fm_core_irq_afjump_setfreq,
+ fm_core_irq_handle_setfreq_resp,
+ fm_core_irq_afjump_enableint,
+ fm_core_irq_afjump_enableint_resp,
+ fm_core_irq_start_afjump,
+ fm_core_irq_handle_start_afjump_resp,
+ fm_core_irq_afjump_rd_freq,
+ fm_core_irq_afjump_rd_freq_resp,
+ fm_core_irq_handle_low_rssi_finish,
+
+ /* Interrupt process post action */
+ fm_core_irq_send_intmsk_cmd,
+ fm_core_irq_handle_intmsk_cmd_resp
+};
+
+static struct fmdrv_ops *fmdev;
+
+#ifdef FM_DUMP_TXRX_PKT
+
+ /* To dump outgoing FM Channel-8 packets */
+inline void dump_tx_skb_data(struct sk_buff *skb)
+{
+ int len, len_org;
+ char index;
+ struct fm_cmd_msg_hdr *cmd_hdr;
+
+ cmd_hdr = (struct fm_cmd_msg_hdr *)skb->data;
+ printk(KERN_INFO "<<%shdr:%02x len:%02x opcode:%02x type:%s dlen:%02x",
+ fm_cb(skb)->completion ? " " : "*", cmd_hdr->header,
+ cmd_hdr->len, cmd_hdr->fm_opcode,
+ cmd_hdr->rd_wr ? "RD" : "WR", cmd_hdr->dlen);
+
+ len_org = skb->len - FM_CMD_MSG_HDR_SIZE;
+ if (len_org > 0) {
+ printk("\n data(%d): ", cmd_hdr->dlen);
+ len = min(len_org, 14);
+ for (index = 0; index < len; index++)
+ printk("%x ",
+ skb->data[FM_CMD_MSG_HDR_SIZE + index]);
+ printk("%s", (len_org > 14) ? ".." : "");
+ }
+ printk("\n");
+}
+
+ /* To dump incoming FM Channel-8 packets */
+inline void dump_rx_skb_data(struct sk_buff *skb)
+{
+ int len, len_org;
+ char index;
+ struct fm_event_msg_hdr *evt_hdr;
+
+ evt_hdr = (struct fm_event_msg_hdr *)skb->data;
+ printk(KERN_INFO ">> hdr:%02x len:%02x sts:%02x numhci:%02x "
+ "opcode:%02x type:%s dlen:%02x", evt_hdr->header, evt_hdr->len,
+ evt_hdr->status, evt_hdr->num_fm_hci_cmds, evt_hdr->fm_opcode,
+ (evt_hdr->rd_wr) ? "RD" : "WR", evt_hdr->dlen);
+
+ len_org = skb->len - FM_EVT_MSG_HDR_SIZE;
+ if (len_org > 0) {
+ printk("\n data(%d): ", evt_hdr->dlen);
+ len = min(len_org, 14);
+ for (index = 0; index < len; index++)
+ printk("%x ",
+ skb->data[FM_EVT_MSG_HDR_SIZE + index]);
+ printk("%s", (len_org > 14) ? ".." : "");
+ }
+ printk("\n");
+}
+#endif
+
+/* Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for
+ * transmission */
+static int __fm_core_send_cmd(unsigned char fmreg_index, void *payload,
+ int payload_len,
+ struct completion *wait_completion)
+{
+ struct sk_buff *skb;
+ struct fm_cmd_msg_hdr *cmd_hdr;
+ int size;
+
+ FMDRV_API_START();
+
+ if (fmreg_index >= FM_REG_MAX_ENTRIES) {
+ FM_DRV_ERR("Invalid fm register index");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ if (test_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag) &&
+ payload == NULL) {
+ FM_DRV_ERR("Payload data is NULL during firmware download");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ if (!test_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag))
+ size =
+ FM_CMD_MSG_HDR_SIZE + ((payload == NULL) ? 0 : payload_len);
+ else
+ size = payload_len;
+
+ /* Allocate memory for new packet */
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (!skb) {
+ FM_DRV_ERR("No memory to create new SKB");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ /* Don't fill FM header info for the commands which come from
+ * FM firmware file */
+ if (!test_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag) ||
+ test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) {
+ /* Fill command header info */
+ cmd_hdr =
+ (struct fm_cmd_msg_hdr *)skb_put(skb, FM_CMD_MSG_HDR_SIZE);
+ cmd_hdr->header = FM_PKT_LOGICAL_CHAN_NUMBER; /* 0x08 */
+ /* 3 (fm_opcode,rd_wr,dlen) + payload len) */
+ cmd_hdr->len = ((payload == NULL) ? 0 : payload_len) + 3;
+ /* FM opcode */
+ cmd_hdr->fm_opcode = fm_reg_info[fmreg_index].opcode;
+ /* read/write type */
+ cmd_hdr->rd_wr = fm_reg_info[fmreg_index].type;
+ cmd_hdr->dlen = payload_len;
+ fm_cb(skb)->fm_opcode = fm_reg_info[fmreg_index].opcode;
+ } else {
+ fm_cb(skb)->fm_opcode = *((char *)payload + 2);
+ }
+ /* Fill payload data */
+ if (payload != NULL)
+ memcpy(skb_put(skb, payload_len), payload, payload_len);
+
+ /* Fill completion handler TX tasklet needs
+ * this info before sending packet to TX Q */
+ fm_cb(skb)->completion = wait_completion;
+
+ /* Add this new packet to TX Q and schedule TX tasklet */
+ skb_queue_tail(&fmdev->tx_q, skb);
+ tasklet_schedule(&fmdev->tx_task);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Sends FM Channel-8 command to the chip and waits for the reponse */
+int fm_core_send_cmd(unsigned char fmreg_index, void *payload, int payload_len,
+ struct completion *wait_completion, void *reponse,
+ int *reponse_len)
+{
+ struct sk_buff *skb;
+ struct fm_event_msg_hdr *fm_evt_hdr;
+ unsigned long timeleft;
+ unsigned long flags;
+ int ret;
+
+ FMDRV_API_START();
+
+ init_completion(wait_completion);
+ ret = __fm_core_send_cmd(fmreg_index, payload, payload_len,
+ wait_completion);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ /* Wait for the reponse from the chip */
+ timeleft = wait_for_completion_timeout(wait_completion,
+ FM_DRV_TX_TIMEOUT);
+ if (!timeleft) {
+ FM_DRV_ERR("Timeout(%d sec),didn't get reg"
+ "completion signal from RX tasklet",
+ jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+ FMDRV_API_EXIT(-ETIMEDOUT);
+ return -ETIMEDOUT;
+ }
+ if (!fmdev->response_skb) {
+ FM_DRV_ERR("Reponse SKB is missing ");
+ FMDRV_API_EXIT(-EFAULT);
+ return -EFAULT;
+ }
+ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+ skb = fmdev->response_skb;
+ fmdev->response_skb = NULL;
+ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+
+ fm_evt_hdr = (void *)skb->data;
+ if (fm_evt_hdr->status != 0) {
+ FM_DRV_ERR("Received event pkt status(%d) is not zero",
+ fm_evt_hdr->status);
+ kfree_skb(skb);
+ FMDRV_API_EXIT(-EIO);
+ return -EIO;
+ }
+ /* Send reponse data to caller */
+ if (reponse != NULL && reponse_len != NULL && fm_evt_hdr->dlen) {
+ /* Skip header info and copy only response data */
+ skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+ memcpy(reponse, skb->data, fm_evt_hdr->dlen);
+ *reponse_len = fm_evt_hdr->dlen;
+ } else if (reponse_len != NULL && fm_evt_hdr->dlen == 0) {
+ *reponse_len = 0;
+ }
+ kfree_skb(skb);
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Resets RDS cache parameters */
+static inline void fm_core_rx_reset_rds_cache(void)
+{
+ FMDRV_API_START();
+
+ fmdev->rx.rds.flag = FM_RX_RDS_DISABLE;
+ fmdev->rx.rds.last_block_index = 0;
+ fmdev->rx.rds.wr_index = 0;
+ fmdev->rx.rds.rd_index = 0;
+
+ if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
+ fmdev->irq_info.mask |= FM_LEV_EVENT;
+
+ FMDRV_API_EXIT(0)
+}
+
+/* Resets current station info */
+static inline void fm_core_rx_reset_curr_station_info(void)
+{
+ FMDRV_API_START();
+
+ fmdev->rx.cur_station_info.picode = FM_NO_PI_CODE;
+ fmdev->rx.cur_station_info.no_of_items_in_afcache = 0;
+ fmdev->rx.cur_station_info.af_list_max = 0;
+
+ FMDRV_API_EXIT(0);
+}
+
+/* --- Helper functions used in FM interrupt handlers ---*/
+
+static inline char fm_core_check_cmdresp_status(struct sk_buff **skb)
+{
+ struct fm_event_msg_hdr *fm_evt_hdr;
+ unsigned long flags;
+
+ FMDRV_API_START();
+
+ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+ *skb = fmdev->response_skb;
+ fmdev->response_skb = NULL;
+ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+
+ fm_evt_hdr = (void *)(*skb)->data;
+ if (fm_evt_hdr->status != 0) {
+ FM_DRV_ERR("irq : opcode %x response status field is not zero",
+ fm_evt_hdr->fm_opcode);
+ FMDRV_API_EXIT(FM_ST_FAILED);
+ return FM_ST_FAILED;
+ }
+
+ FMDRV_API_EXIT(FM_ST_SUCCESS);
+ return FM_ST_SUCCESS;
+}
+
+/* Interrupt process timeout handler */
+static void fm_core_int_timeout_handler(unsigned long data)
+{
+ FMDRV_API_START();
+
+ FM_DRV_DBG("irq : timeout,trying to re-enable fm interrupts");
+ fmdev->irq_info.irq_service_timeout_retry++;
+
+ /* One of the irq handler did not get proper response from the chip.
+ * So take recovery action here. FM interrupts are disabled in the
+ * beginning of interrupt process. Therefore reset stage index to
+ * re-enable default interrupts. So that next interrupt will be
+ * processed as usual.
+ */
+ if (fmdev->irq_info.irq_service_timeout_retry <=
+ FM_IRQ_TIMEOUT_RETRY_MAX) {
+ fmdev->irq_info.stage_index = FM_SEND_INTMSK_CMD_INDEX;
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+ } else {
+ /* Retry count reached maximum limit.
+ * Stop recovery action (interrupt
+ * reenable process) and reset stage
+ * index & retry count values
+ */
+ fmdev->irq_info.stage_index = 0;
+ fmdev->irq_info.irq_service_timeout_retry = 0;
+ FM_DRV_ERR("Recovery action failed during \
+ irq processing,max retry reached");
+ }
+ FMDRV_API_EXIT(0);
+}
+
+/* --------- FM interrupt handlers ------------*/
+
+static void fm_core_irq_send_flag_getcmd(void)
+{
+ unsigned short flag;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Send FLAG_GET command , to know the source of interrupt */
+ ret = __fm_core_send_cmd(FLAG_GET, NULL, sizeof(flag), NULL);
+ if (ret) {
+ /* Failed to send the cmd , Don't update the stage index &
+ * Trigger the timer to take recovery action */
+ FM_DRV_ERR("irq : failed to send flag_get command,"
+ "initiating irq recovery process");
+ } else
+ fmdev->irq_info.stage_index = FM_HANDLE_FLAG_GETCMD_RESP_INDEX;
+
+ /* Start timer to track timeout */
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_flag_getcmd_resp(void)
+{
+ struct sk_buff *skb;
+ struct fm_event_msg_hdr *fm_evt_hdr;
+ char ret;
+
+ FMDRV_API_START();
+
+ /* Stop timeout timer */
+ del_timer(&fmdev->irq_info.int_timeout_timer);
+
+ ret = fm_core_check_cmdresp_status(&skb);
+ if (ret) {
+ FM_DRV_ERR("Initiating irq recovery process");
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(FM_ST_FAILED);
+ return;
+ }
+ fm_evt_hdr = (void *)skb->data;
+
+ /* Skip header info and copy only response data */
+ skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+ memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen);
+
+ FM_STORE_BE16_TO_LE16(fmdev->irq_info.flag, fmdev->irq_info.flag);
+ FM_DRV_DBG("irq : flag register(0x%x)", fmdev->irq_info.flag);
+
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage_index = FM_HW_MAL_FUNC_INDEX;
+
+ FMDRV_API_EXIT(0);
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+}
+
+static void fm_core_irq_handle_hw_malfunction(void)
+{
+ FMDRV_API_START();
+
+ if (fmdev->irq_info.flag & FM_MAL_EVENT & fmdev->irq_info.mask)
+ FM_DRV_ERR("irq : Hw MAL interrupt received - do nothing");
+
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage_index = FM_RDS_START_INDEX;
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_rds_start(void)
+{
+ FMDRV_API_START();
+
+ if (fmdev->irq_info.flag & FM_RDS_EVENT & fmdev->irq_info.mask) {
+ FM_DRV_DBG("irq : rds threshold reached");
+ fmdev->irq_info.stage_index = FM_RDS_SEND_RDS_GETCMD_INDEX;
+ } else {
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage_index = FM_HW_TUNE_OP_ENDED_INDEX;
+ }
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_send_rdsdata_getcmd(void)
+{
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Send the command to read RDS data from the chip */
+ ret = __fm_core_send_cmd(RDS_DATA_GET, NULL,
+ (FM_RX_RDS_FIFO_THRESHOLD * 3), NULL);
+ if (ret)
+ FM_DRV_ERR("irq : failed to send rds get commandm,"
+ "initiating irq recovery process");
+ else
+ fmdev->irq_info.stage_index =
+ FM_RDS_HANDLE_RDS_GETCMD_RESP_INDEX;
+
+ /* Start timer to track timeout */
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(0);
+}
+
+/* Keeps track of current RX channel AF (Alternate Frequency) */
+static void __fm_core_rx_update_af_cache(unsigned char af)
+{
+ unsigned char index;
+ unsigned int freq;
+ FMDRV_API_START();
+
+ /* First AF indicates the number of AF follows. Reset the list */
+ if ((af >= FM_RDS_1_AF_FOLLOWS) && (af <= FM_RDS_25_AF_FOLLOWS)) {
+ fmdev->rx.cur_station_info.af_list_max =
+ (af - FM_RDS_1_AF_FOLLOWS + 1);
+ fmdev->rx.cur_station_info.no_of_items_in_afcache = 0;
+ FM_DRV_DBG("No of expected AF : %d",
+ fmdev->rx.cur_station_info.af_list_max);
+ } else if (((af >= FM_RDS_MIN_AF)
+ && (fmdev->rx.region.region_index == FM_BAND_EUROPE_US)
+ && (af <= FM_RDS_MAX_AF)) || ((af >= FM_RDS_MIN_AF)
+ && (fmdev->rx.region.
+ region_index ==
+ FM_BAND_JAPAN)
+ && (af <=
+ FM_RDS_MAX_AF_JAPAN))) {
+ freq = fmdev->rx.region.bottom_frequency + (af * 100);
+ /* If the AF is the same
+ * as the tuned station frequency - ignore it
+ */
+ if (freq == fmdev->rx.curr_freq) {
+ FM_DRV_DBG("Current frequency(%d) is \
+ matching with received AF(%d)",
+ fmdev->rx.curr_freq, freq);
+ return;
+ }
+ /* Do check in AF cache */
+ for (index = 0;
+ index < fmdev->rx.cur_station_info.no_of_items_in_afcache;
+ index++) {
+ if (fmdev->rx.cur_station_info.af_cache[index] == freq)
+ break;
+ }
+ /* Reached the limit of the list - ignore the next AF */
+ if (index == fmdev->rx.cur_station_info.af_list_max) {
+ FM_DRV_DBG("AF cache is full");
+ return;
+ }
+
+ /* If we reached the end of the list then
+ * this AF is not in the list - add it
+ */
+ if (index == fmdev->rx.cur_station_info.
+ no_of_items_in_afcache) {
+ FM_DRV_DBG("Storing AF %d into AF cache index %d", freq,
+ index);
+ fmdev->rx.cur_station_info.af_cache[index] = freq;
+ fmdev->rx.cur_station_info.no_of_items_in_afcache++;
+ }
+ }
+ FMDRV_API_EXIT(0);
+}
+
+/* Converts RDS buffer data from big endian format
+ * to little endian format
+ */
+static void __fm_core_rdsparse_swapbytes(struct fm_rdsdata_format *rds_format)
+{
+ unsigned char byte1;
+ unsigned char index = 0;
+ char *rds_buff;
+
+ FMDRV_API_START();
+
+ /* Since in Orca the 2 RDS Data bytes are in little endian and
+ * in Dolphin they are in big endian, the parsing of the RDS data
+ * is chip dependent */
+ if (fmdev->asci_id != 0x6350) {
+ rds_buff = &rds_format->rdsData.groupDataBuff.rdsBuff[0];
+ while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) {
+ byte1 = rds_buff[index];
+ rds_buff[index] = rds_buff[index + 1];
+ rds_buff[index + 1] = byte1;
+ index += 2;
+ }
+ }
+
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_rdsdata_getcmd_resp(void)
+{
+ struct sk_buff *skb;
+ char *rds_data;
+ char metaData;
+ unsigned char type, block_index;
+ unsigned long group_index;
+ struct fm_rdsdata_format rds_format;
+ int rds_len, ret;
+ unsigned short cur_picode;
+ unsigned char tmpbuf[3];
+ unsigned long flags;
+
+ FMDRV_API_START();
+
+ /* Stop timeout timer */
+ del_timer(&fmdev->irq_info.int_timeout_timer);
+
+ ret = fm_core_check_cmdresp_status(&skb);
+ if (ret) {
+ FM_DRV_ERR("Initiating irq recovery process");
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(FM_ST_FAILED);
+ return;
+ }
+ /* Skip header info */
+ skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+ rds_data = skb->data;
+ rds_len = skb->len;
+
+ /* Parse the RDS data */
+ while (rds_len >= FM_RDS_BLOCK_SIZE) {
+ metaData = rds_data[2];
+ /* Get the type:
+ * 0=A, 1=B, 2=C, 3=C', 4=D, 5=E */
+ type = (metaData & 0x07);
+
+ /* Transform the block type
+ * into an index sequence (0, 1, 2, 3, 4) */
+ block_index = (type <= FM_RDS_BLOCK_C ? type : (type - 1));
+ FM_DRV_DBG("Block index:%d(%s) ", block_index,
+ (metaData & FM_RDS_STATUS_ERROR_MASK) ? "Bad" :
+ "Ok");
+ if (((metaData & FM_RDS_STATUS_ERROR_MASK) == 0)
+ && (block_index == FM_RDS_BLOCK_INDEX_A
+ || (block_index == fmdev->rx.rds.last_block_index + 1
+ && block_index <= FM_RDS_BLOCK_INDEX_D))) {
+ /* Skip checkword (control) byte
+ * and copy only data byte */
+ memcpy(&rds_format.rdsData.groupDataBuff.
+ rdsBuff[block_index * (FM_RDS_BLOCK_SIZE - 1)],
+ rds_data, (FM_RDS_BLOCK_SIZE - 1));
+ fmdev->rx.rds.last_block_index = block_index;
+
+ /* If completed a whole group then handle it */
+ if (block_index == FM_RDS_BLOCK_INDEX_D) {
+ FM_DRV_DBG("Good block received");
+ __fm_core_rdsparse_swapbytes(&rds_format);
+
+ /* Extract PI code and store in local cache.
+ * We need this during AF switch processing */
+ cur_picode =
+ FM_BE16_TO_LE16(rds_format.rdsData.
+ groupGeneral.piData);
+ if (fmdev->rx.cur_station_info.picode !=
+ cur_picode)
+ fmdev->rx.cur_station_info.picode =
+ cur_picode;
+ FM_DRV_DBG("picode:%d", cur_picode);
+
+ group_index =
+ (rds_format.rdsData.groupGeneral.
+ blockB_byte1 >> 3);
+ FM_DRV_DBG("Group:%ld%s", group_index / 2,
+ (group_index % 2) ? "B" : "A");
+
+ group_index =
+ 1 << (rds_format.rdsData.groupGeneral.
+ blockB_byte1 >> 3);
+ if (group_index == FM_RDS_GROUP_TYPE_MASK_0A) {
+ __fm_core_rx_update_af_cache
+ (rds_format.rdsData.group0A.
+ firstAf);
+ __fm_core_rx_update_af_cache(rds_format.
+ rdsData.
+ group0A.
+ secondAf);
+ }
+ }
+ } else {
+ FM_DRV_DBG("Block sequence mismatch");
+ fmdev->rx.rds.last_block_index = -1;
+ }
+ rds_len -= FM_RDS_BLOCK_SIZE;
+ rds_data += FM_RDS_BLOCK_SIZE;
+ }
+
+ /* Copy raw rds data to internal rds buffer */
+ rds_data = skb->data;
+ rds_len = skb->len;
+
+ spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
+ while (rds_len > 0) {
+ /* Fill RDS buffer as per V4L2 specification.
+ * Store control byte
+ */
+ type = (rds_data[2] & 0x07);
+ block_index = (type <= FM_RDS_BLOCK_C ? type : (type - 1));
+ tmpbuf[2] = block_index; /* Offset name */
+ tmpbuf[2] |= block_index << 3; /* Received offset */
+
+ /* Store data byte */
+ tmpbuf[0] = rds_data[0];
+ tmpbuf[1] = rds_data[1];
+
+ memcpy(&fmdev->rx.rds.buffer[fmdev->rx.rds.wr_index], &tmpbuf,
+ FM_RDS_BLOCK_SIZE);
+ fmdev->rx.rds.wr_index =
+ (fmdev->rx.rds.wr_index +
+ FM_RDS_BLOCK_SIZE) % fmdev->rx.rds.buf_size;
+
+ /* Check for overflow & start over */
+ if (fmdev->rx.rds.wr_index == fmdev->rx.rds.rd_index) {
+ FM_DRV_DBG("RDS buffer overflow");
+ fmdev->rx.rds.wr_index = 0;
+ fmdev->rx.rds.rd_index = 0;
+ break;
+ }
+ rds_len -= FM_RDS_BLOCK_SIZE;
+ rds_data += FM_RDS_BLOCK_SIZE;
+ }
+ spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
+
+ /* Wakeup read queue */
+ if (fmdev->rx.rds.wr_index != fmdev->rx.rds.rd_index)
+ wake_up_interruptible(&fmdev->rx.rds.read_queue);
+
+ fmdev->irq_info.stage_index = FM_RDS_FINISH_INDEX;
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_rds_finish(void)
+{
+ FMDRV_API_START();
+
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage_index = FM_HW_TUNE_OP_ENDED_INDEX;
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_tune_op_ended(void)
+{
+ FMDRV_API_START();
+
+ if (fmdev->irq_info.flag & (FM_FR_EVENT | FM_BL_EVENT) & fmdev->
+ irq_info.mask) {
+ FM_DRV_DBG("irq : tune ended/bandlimit reached");
+ if (test_and_clear_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag)) {
+ fmdev->irq_info.stage_index = FM_AF_JUMP_RD_FREQ_INDEX;
+ } else {
+ complete(&fmdev->maintask_completion);
+ fmdev->irq_info.stage_index = FM_HW_POWER_ENB_INDEX;
+ }
+ } else
+ fmdev->irq_info.stage_index = FM_HW_POWER_ENB_INDEX;
+
+ FMDRV_API_EXIT(0);
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+}
+
+static void fm_core_irq_handle_power_enb(void)
+{
+ FMDRV_API_START();
+
+ if (fmdev->irq_info.flag & FM_POW_ENB_EVENT) {
+ FM_DRV_DBG("irq : Power Enabled/Disabled");
+ complete(&fmdev->maintask_completion);
+ }
+
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage_index = FM_LOW_RSSI_START_INDEX;
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_low_rssi_start(void)
+{
+ FMDRV_API_START();
+
+ if ((fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) &&
+ (fmdev->irq_info.flag & FM_LEV_EVENT & fmdev->irq_info.mask) &&
+ (fmdev->rx.curr_freq != FM_UNDEFINED_FREQ) &&
+ (fmdev->rx.cur_station_info.no_of_items_in_afcache != 0)) {
+ FM_DRV_DBG("irq : rssi level has fallen below threshold level");
+
+ /* Disable further low RSSI interrupts */
+ fmdev->irq_info.mask &= ~FM_LEV_EVENT;
+
+ fmdev->rx.cur_Afjump_index = 0;
+ fmdev->rx.freq_before_jump = fmdev->rx.curr_freq;
+ fmdev->irq_info.stage_index = FM_AF_JUMP_SETPI_INDEX;
+ } else {
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage_index = FM_SEND_INTMSK_CMD_INDEX;
+ }
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_afjump_set_pi(void)
+{
+ int ret;
+ unsigned short payload;
+
+ FMDRV_API_START();
+
+ /* Set PI code - must be updated if the AF list is not empty */
+ payload = FM_LE16_TO_BE16(fmdev->rx.cur_station_info.picode);
+ ret = __fm_core_send_cmd(RDS_PI_SET, &payload, sizeof(payload), NULL);
+ if (ret)
+ FM_DRV_ERR("irq : failed to set PI,"
+ "initiating irq recovery process");
+ else
+ fmdev->irq_info.stage_index =
+ FM_AF_JUMP_HANDLE_SETPI_RESP_INDEX;
+
+ /* Start timer to track timeout */
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_set_pi_resp(void)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Stop timeout timer */
+ del_timer(&fmdev->irq_info.int_timeout_timer);
+
+ ret = fm_core_check_cmdresp_status(&skb);
+ if (ret) {
+ FM_DRV_ERR("Initiating irq recovery process");
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(FM_ST_FAILED);
+ return;
+ }
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage_index = FM_AF_JUMP_SETPI_MASK_INDEX;
+
+ FMDRV_API_EXIT(0);
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+}
+
+static void fm_core_irq_afjump_set_pimask(void)
+{
+ int ret;
+ unsigned short payload;
+
+ FMDRV_API_START();
+
+ /* Set PI mask.
+ * 0xFFFF = Enable PI code matching
+ * 0x0000 = Disable PI code matching
+ */
+ payload = 0x0000;
+ ret =
+ __fm_core_send_cmd(RDS_PI_MASK_SET, &payload, sizeof(payload),
+ NULL);
+ if (ret < 0)
+ FM_DRV_ERR("irq : failed to set PI mask,"
+ "initiating irq recovery process");
+ else
+ fmdev->irq_info.stage_index =
+ FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_INDEX;
+
+ /* Start timer to track timeout */
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_set_pimask_resp(void)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Stop timeout timer */
+ del_timer(&fmdev->irq_info.int_timeout_timer);
+ ret = fm_core_check_cmdresp_status(&skb);
+ if (ret) {
+ FM_DRV_ERR("Initiating irq recovery process");
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(FM_ST_FAILED);
+ return;
+ }
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage_index = FM_AF_JUMP_SET_AF_FREQ_INDEX;
+ FMDRV_API_EXIT(0);
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+}
+
+static void fm_core_irq_afjump_setfreq(void)
+{
+ unsigned short frq_index;
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ FM_DRV_DBG("Swtiching to %d KHz\n",
+ fmdev->rx.cur_station_info.af_cache[fmdev->rx.cur_Afjump_index]);
+ frq_index =
+ (fmdev->rx.cur_station_info.af_cache[fmdev->rx.cur_Afjump_index] -
+ fmdev->rx.region.bottom_frequency) /
+ fmdev->rx.region.channel_spacing;
+
+ FM_STORE_LE16_TO_BE16(payload, frq_index);
+ ret = __fm_core_send_cmd(AF_FREQ_SET, &payload, sizeof(payload), NULL);
+ if (ret < 0)
+ FM_DRV_ERR("irq : failed to set AF freq,"
+ "initiating irq recovery process");
+ else
+ fmdev->irq_info.stage_index =
+ FM_AF_JUMP_HENDLE_SET_AFFREQ_RESP_INDEX;
+
+ /* Start timer to track timeout */
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_setfreq_resp(void)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Stop timeout timer */
+ del_timer(&fmdev->irq_info.int_timeout_timer);
+ ret = fm_core_check_cmdresp_status(&skb);
+ if (ret) {
+ FM_DRV_ERR("Initiating irq recovery process");
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(FM_ST_FAILED);
+ return;
+ } else {
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage_index = FM_AF_JUMP_ENABLE_INT_INDEX;
+ }
+ FMDRV_API_EXIT(0);
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+}
+
+static void fm_core_irq_afjump_enableint(void)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Enable FR (tuning operation ended) interrupt */
+ payload = FM_LE16_TO_BE16(FM_FR_EVENT);
+ ret = __fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload), NULL);
+ if (ret)
+ FM_DRV_ERR("irq : failed to enable FR interrupt,"
+ "initiating irq recovery process");
+ else
+ fmdev->irq_info.stage_index = FM_AF_JUMP_ENABLE_INT_RESP_INDEX;
+
+ /* Start timer to track timeout */
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_afjump_enableint_resp(void)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Stop timeout timer */
+ del_timer(&fmdev->irq_info.int_timeout_timer);
+ ret = fm_core_check_cmdresp_status(&skb);
+ if (ret) {
+ FM_DRV_ERR("Initiating irq recovery process");
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(FM_ST_FAILED);
+ return;
+ }
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage_index = FM_AF_JUMP_START_AFJUMP_INDEX;
+ FMDRV_API_EXIT(0);
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+}
+
+static void fm_core_irq_start_afjump(void)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Issue AF switch start command to the chip */
+ FM_STORE_LE16_TO_BE16(payload, FM_TUNER_AF_JUMP_MODE);
+ ret =
+ __fm_core_send_cmd(TUNER_MODE_SET, &payload, sizeof(payload), NULL);
+ if (ret)
+ FM_DRV_ERR("irq : failed to start af switch,"
+ "initiating irq recovery process");
+ else
+ fmdev->irq_info.stage_index =
+ FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_INDEX;
+
+ /* Start timer to track timeout */
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_start_afjump_resp(void)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Stop timeout timer */
+ del_timer(&fmdev->irq_info.int_timeout_timer);
+ ret = fm_core_check_cmdresp_status(&skb);
+ if (ret) {
+ FM_DRV_ERR("Initiating irq recovery process");
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(FM_ST_FAILED);
+ return;
+ }
+ fmdev->irq_info.stage_index = FM_SEND_FLAG_GETCMD_INDEX;
+ set_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag);
+ clear_bit(FM_INTTASK_RUNNING, &fmdev->flag);
+
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_afjump_rd_freq(void)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = __fm_core_send_cmd(FREQ_GET, NULL, sizeof(payload), NULL);
+ if (ret)
+ FM_DRV_ERR("irq : failed to read cur freq,"
+ "initiating irq recovery process");
+ else
+ fmdev->irq_info.stage_index = FM_AF_JUMP_RD_FREQ_RESP_INDEX;
+
+ /* Start timer to track timeout */
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_afjump_rd_freq_resp(void)
+{
+ struct sk_buff *skb;
+ unsigned short read_freq;
+ unsigned int curr_freq, jumped_freq;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Stop timeout timer */
+ del_timer(&fmdev->irq_info.int_timeout_timer);
+ ret = fm_core_check_cmdresp_status(&skb);
+ if (ret) {
+ FM_DRV_ERR("Initiating irq recovery process");
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(FM_ST_FAILED);
+ return;
+ }
+ /* Skip header info and copy only response data */
+ skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+ memcpy(&read_freq, skb->data, sizeof(read_freq));
+ read_freq = FM_BE16_TO_LE16(read_freq);
+ curr_freq = fmdev->rx.region.bottom_frequency +
+ ((unsigned int)read_freq * fmdev->rx.region.channel_spacing);
+
+ jumped_freq =
+ fmdev->rx.cur_station_info.af_cache[fmdev->rx.cur_Afjump_index];
+
+ /* If the frequency was changed the jump succeeded */
+ if ((curr_freq != fmdev->rx.freq_before_jump) &&
+ (curr_freq == jumped_freq)) {
+ FM_DRV_DBG("Successfully switched to alternate frequency %d",
+ curr_freq);
+ fmdev->rx.curr_freq = curr_freq;
+
+ /* Reset RDS cache */
+ fm_core_rx_reset_rds_cache();
+
+ /* AF feature is on, enable low level RSSI interrupt */
+ if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
+ fmdev->irq_info.mask |= FM_LEV_EVENT;
+
+ /* Call the next stage of general
+ * interrupts handler to handle other interrupts
+ */
+ fmdev->irq_info.stage_index = FM_LOW_RSSI_FINISH_INDEX;
+ } else { /* jump to the next freq in the AF list */
+
+ /* Go to next index in the AF list */
+ fmdev->rx.cur_Afjump_index++;
+
+ /* If we reached the end of the list - stop searching */
+ if (fmdev->rx.cur_Afjump_index >=
+ fmdev->rx.cur_station_info.no_of_items_in_afcache) {
+ FM_DRV_DBG("AF switch processing failed");
+ /* Call the next stage of general
+ * interrupts handler to handle other interrupts
+ */
+ fmdev->irq_info.stage_index = FM_LOW_RSSI_FINISH_INDEX;
+ } else { /* AF List is not over - try next one */
+
+ FM_DRV_DBG("Trying next frequency in af cache");
+ fmdev->irq_info.stage_index = FM_AF_JUMP_SETPI_INDEX;
+ }
+ }
+ FMDRV_API_EXIT(0);
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+}
+
+static void fm_core_irq_handle_low_rssi_finish(void)
+{
+ FMDRV_API_START();
+
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage_index = FM_SEND_INTMSK_CMD_INDEX;
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index] ();
+
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_send_intmsk_cmd(void)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Re-enable FM interrupts */
+ FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+ ret = __fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload), NULL);
+ if (ret)
+ FM_DRV_ERR("irq : failed to send int_mask_set cmd,"
+ "initiating irq recovery process");
+ else
+ fmdev->irq_info.stage_index = FM_HANDLE_INTMSK_CMD_RESP_INDEX;
+
+ /* Start timer to track timeout */
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_intmsk_cmd_resp(void)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Stop timeout timer */
+ del_timer(&fmdev->irq_info.int_timeout_timer);
+
+ ret = fm_core_check_cmdresp_status(&skb);
+ if (ret) {
+ FM_DRV_ERR("Initiating irq recovery process");
+ mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+ FM_DRV_TX_TIMEOUT);
+ FMDRV_API_EXIT(FM_ST_FAILED);
+ return;
+ }
+ /* This is last function in interrupt table to be executed.
+ * So, reset stage index to 0.
+ */
+ fmdev->irq_info.stage_index = FM_SEND_FLAG_GETCMD_INDEX;
+
+ /* Start processing any pending interrupt */
+ if (test_and_clear_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag)) {
+ FMDRV_API_EXIT(0);
+ fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+ stage_index]
+ ();
+ } else
+ clear_bit(FM_INTTASK_RUNNING, &fmdev->flag);
+
+ FMDRV_API_EXIT(0);
+}
+
+/* --------------- FM TX tasklet -----------------*/
+
+/* FM V4L2 interface and FM mixer control interface layer
+ * schedule this tasklet whenever it wants to transmit FM packet.
+ */
+static void fm_core_tx_tasklet(unsigned long arg)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Check, is there any timeout happenned to last transmitted packet */
+ if (!atomic_read(&fmdev->tx_cnt) &&
+ ((jiffies - fmdev->last_tx_jiffies) > FM_DRV_TX_TIMEOUT)) {
+ FM_DRV_ERR("TX timeout occurred");
+ atomic_set(&fmdev->tx_cnt, 1);
+ }
+ /* Send queued FM TX packets */
+ if (atomic_read(&fmdev->tx_cnt)) {
+ skb = skb_dequeue(&fmdev->tx_q);
+ if (skb) {
+ atomic_dec(&fmdev->tx_cnt);
+ fmdev->last_sent_pkt_opcode = fm_cb(skb)->fm_opcode;
+
+ if (fmdev->response_completion != NULL)
+ FM_DRV_ERR
+ ("Response completion handler is not NULL");
+
+ fmdev->response_completion = fm_cb(skb)->completion;
+#ifdef FM_DUMP_TXRX_PKT
+ dump_tx_skb_data(skb);
+#endif
+ /* Forward SKB to FM ST,
+ * FM ST will internally forward SKB to ST driver.
+ */
+ ret = fm_st_send(skb);
+ if (ret < 0) {
+ fmdev->response_completion = NULL;
+ FM_DRV_ERR
+ ("TX tasklet failed to send skb(%p)", skb);
+ atomic_set(&fmdev->tx_cnt, 1);
+ } else
+ fmdev->last_tx_jiffies = jiffies;
+ }
+ }
+ FMDRV_API_EXIT(0);
+}
+
+/* --------------- FM RX tasklet -----------------*/
+
+/* FM ST will schedule this tasklet whenever it receives
+ * FM packet from ST driver.
+ */
+static void fm_core_rx_tasklet(unsigned long arg)
+{
+ struct fm_event_msg_hdr *fm_evt_hdr;
+ struct sk_buff *skb;
+ unsigned char num_fm_hci_cmds;
+ unsigned long flags;
+
+ FMDRV_API_START();
+
+ /* Process all packets in the RX queue */
+ while ((skb = skb_dequeue(&fmdev->rx_q))) {
+ if (skb->len < sizeof(struct fm_event_msg_hdr)) {
+ FM_DRV_ERR("skb(%p) has only %d bytes"
+ "atleast need %d bytes to decode",
+ skb, skb->len,
+ sizeof(struct fm_event_msg_hdr));
+ kfree_skb(skb);
+ continue;
+ }
+
+ fm_evt_hdr = (void *)skb->data;
+ num_fm_hci_cmds = fm_evt_hdr->num_fm_hci_cmds;
+
+#ifdef FM_DUMP_TXRX_PKT
+ dump_rx_skb_data(skb);
+#endif
+ /* FM interrupt packet? */
+ if (fm_evt_hdr->fm_opcode == fm_reg_info[FM_INTERRUPT].opcode) {
+ /* FM interrupt handler started already? */
+ if (!test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) {
+ set_bit(FM_INTTASK_RUNNING, &fmdev->flag);
+ if (fmdev->irq_info.stage_index != 0) {
+ FM_DRV_ERR("Invalid stage index,"
+ "resetting to zero");
+ fmdev->irq_info.stage_index = 0;
+ }
+
+ /* Execute first function
+ * in interrupt handler table
+ */
+ fmdev->irq_info.fm_IntActionHandlerTable
+ [fmdev->irq_info.stage_index]
+ ();
+ } else {
+ set_bit(FM_INTTASK_SCHEDULE_PENDING,
+ &fmdev->flag);
+ }
+ kfree_skb(skb);
+ }
+ /* Anyone waiting for this with completion handler? */
+ else if (fm_evt_hdr->fm_opcode == fmdev->last_sent_pkt_opcode &&
+ fmdev->response_completion != NULL) {
+ if (fmdev->response_skb != NULL)
+ FM_DRV_ERR("Response SKB pointer is not NULL");
+
+ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+ fmdev->response_skb = skb;
+ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+ complete(fmdev->response_completion);
+
+ fmdev->response_completion = NULL;
+ atomic_set(&fmdev->tx_cnt, 1);
+ }
+ /* Is this for interrupt handler? */
+ else if (fm_evt_hdr->fm_opcode == fmdev->last_sent_pkt_opcode &&
+ fmdev->response_completion == NULL) {
+ if (fmdev->response_skb != NULL)
+ FM_DRV_ERR("Response SKB pointer is not NULL");
+
+ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+ fmdev->response_skb = skb;
+ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+
+ /* Execute interrupt handler where state index points */
+ fmdev->irq_info.fm_IntActionHandlerTable
+ [fmdev->irq_info.stage_index]
+ ();
+
+ kfree_skb(skb);
+ atomic_set(&fmdev->tx_cnt, 1);
+ } else {
+ FM_DRV_ERR("Nobody claimed SKB(%p),purging", skb);
+ }
+
+ /* Check flow control field.
+ * If Num_FM_HCI_Commands field is not zero,
+ * schedule FM TX tasklet.
+ */
+ if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt)) {
+ if (!skb_queue_empty(&fmdev->tx_q))
+ tasklet_schedule(&fmdev->tx_task);
+ }
+ }
+ FMDRV_API_EXIT(0);
+}
+
+/* ----- Fucntions exported to FM V4L2 layer ----- */
+int fm_core_tx_set_stereo_mono(unsigned short mode)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ FM_DRV_DBG("stereo mode: %d", (int)mode);
+
+ /* Set Stereo/Mono mode */
+ FM_STORE_LE16_TO_BE16(payload, (1 - mode));
+ ret = fm_core_send_cmd(MONO_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_tx_set_rds_text(unsigned char *rds_text)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ FM_DRV_DBG("rds_text: %s", rds_text);
+
+ ret = fm_core_send_cmd(RDS_DATA_SET, rds_text, strlen(rds_text),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Scroll mode */
+ FM_STORE_LE16_TO_BE16(payload, (unsigned short)0x1);
+ ret = fm_core_send_cmd(DISPLAY_MODE_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_tx_set_rds_data_mode(unsigned char mode)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ FM_DRV_DBG("data mode: %d", (int)mode);
+
+ /* Setting unique PI TODO: how unique? */
+ FM_STORE_LE16_TO_BE16(payload, (unsigned short)0xcafe);
+ ret = fm_core_send_cmd(PI_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Set decoder id */
+ FM_STORE_LE16_TO_BE16(payload, (unsigned short)0xa);
+ ret = fm_core_send_cmd(DI_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* TODO: RDS_MODE_GET? */
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_tx_set_rds_len(unsigned char type, unsigned short len)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ FM_DRV_DBG("len: %d", (int)len);
+
+ len |= type << 8;
+ FM_STORE_LE16_TO_BE16(payload, len);
+ ret = fm_core_send_cmd(LENGHT_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* TODO: LENGHT_GET? */
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_tx_set_rds_mode(unsigned char rds_en_dis)
+{
+ unsigned short payload;
+ int ret;
+ unsigned char rds_text[] = "Zoom2\n";
+
+ FMDRV_API_START();
+
+ FM_DRV_DBG("rds_en_dis:%d(E:%d, D:%d)", rds_en_dis,
+ FM_RX_RDS_ENABLE, FM_RX_RDS_DISABLE);
+
+ if (rds_en_dis == FM_RX_RDS_ENABLE) {
+ /* Set RDS length */
+ fm_core_tx_set_rds_len(0, strlen(rds_text));
+ /* Set RDS text */
+ fm_core_tx_set_rds_text(rds_text);
+ /* Set RDS mode */
+ fm_core_tx_set_rds_data_mode(0x0);
+ }
+
+ /* Send command to enable RDS */
+ if (rds_en_dis == FM_RX_RDS_ENABLE)
+ FM_STORE_LE16_TO_BE16(payload, 0x01);
+ else
+ FM_STORE_LE16_TO_BE16(payload, 0x00);
+
+ ret = fm_core_send_cmd(RDS_DATA_ENB, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ if (rds_en_dis == FM_RX_RDS_ENABLE) {
+ /* Set RDS length */
+ fm_core_tx_set_rds_len(0, strlen(rds_text));
+ /* Set RDS text */
+ fm_core_tx_set_rds_text(rds_text);
+ }
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_tx_set_radio_text(unsigned char *rds_text, unsigned char rds_type)
+{
+ unsigned short payload;
+ int ret;
+ FMDRV_API_START();
+
+ fm_core_tx_set_rds_mode(0);
+ /* Set RDS length */
+ fm_core_tx_set_rds_len(rds_type, strlen(rds_text));
+ /* Set RDS text */
+ fm_core_tx_set_rds_text(rds_text);
+ /* Set RDS mode */
+ fm_core_tx_set_rds_data_mode(0x0);
+
+ FM_STORE_LE16_TO_BE16(payload, 1);
+ ret = fm_core_send_cmd(RDS_DATA_ENB, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_tx_set_af(unsigned int af)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ FM_DRV_DBG("AF: %d", af);
+
+ /* Set AF */
+ af = (af - 87500) / 100;
+
+ FM_STORE_LE16_TO_BE16(payload, (unsigned short)af);
+ ret = fm_core_send_cmd(TA_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_tx_set_region(unsigned char region_to_set)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ FM_DRV_DBG("region_to_set %ld(Eu/US %d, Jp %d)",
+ (unsigned long)region_to_set, FM_BAND_EUROPE_US,
+ FM_BAND_JAPAN);
+
+ if (region_to_set != FM_BAND_EUROPE_US &&
+ region_to_set != FM_BAND_JAPAN) {
+ FM_DRV_ERR("Invalid band\n");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+
+ /* Send command to set the band */
+ FM_STORE_LE16_TO_BE16(payload, (unsigned short)region_to_set);
+ ret = fm_core_send_cmd(TX_BAND_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_tx_set_mute_mode(unsigned char mute_mode_toset)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ FM_DRV_DBG("tx: mute mode %ld", (unsigned long)mute_mode_toset);
+ FM_STORE_LE16_TO_BE16(payload, mute_mode_toset);
+ ret = fm_core_send_cmd(MUTE, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Set TX Audio I/O */
+static int fm_core_tx_set_audio_io(void)
+{
+ struct fmtx_data *tx = &fmdev->tx_data;
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ FM_DRV_DBG("tx: audio_io %ld ", (long int)tx->audio_io);
+
+ /* Set Audio I/O Enable */
+ FM_STORE_LE16_TO_BE16(payload, tx->audio_io);
+ ret = fm_core_send_cmd(AUDIO_IO_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* TODO: is audio set? */
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Start TX Transmission */
+static int fm_core_tx_xmit(unsigned char new_xmit_state)
+{
+ struct fmtx_data *tx = &fmdev->tx_data;
+ unsigned short payload;
+ unsigned long timeleft;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Enable POWER_ENB interrupts */
+ FM_STORE_LE16_TO_BE16(payload, FM_POW_ENB_EVENT);
+ ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+
+ /* Set Power Enable */
+ FM_STORE_LE16_TO_BE16(payload, new_xmit_state);
+ ret = fm_core_send_cmd(POWER_ENB_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Wait for Power Enabled */
+ init_completion(&fmdev->maintask_completion);
+ timeleft = wait_for_completion_timeout(&fmdev->maintask_completion,
+ FM_DRV_TX_TIMEOUT);
+ if (!timeleft) {
+ FM_DRV_ERR("Timeout(%d sec),didn't get tune ended interrupt",
+ jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+ FMDRV_API_EXIT(-ETIMEDOUT);
+ return -ETIMEDOUT;
+ }
+
+ set_bit(FM_CORE_TX_XMITING, &fmdev->flag);
+ tx->xmit_state = new_xmit_state;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Set TX power level */
+int fm_core_tx_set_pwr_lvl(unsigned char new_pwr_lvl)
+{
+ unsigned short payload;
+ struct fmtx_data *tx = &fmdev->tx_data;
+ int ret;
+
+ FMDRV_API_START();
+
+ FM_DRV_DBG("tx: pwr_level_to_set %ld ", (long int)new_pwr_lvl);
+ /* If the core isn't ready update global variable */
+ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+ tx->pwr_lvl = new_pwr_lvl;
+ return 0;
+ }
+
+ /* Set power level */
+ FM_STORE_LE16_TO_BE16(payload, new_pwr_lvl);
+ ret = fm_core_send_cmd(POWER_LEL_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* TODO: is the power level set? */
+ tx->pwr_lvl = new_pwr_lvl;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Set TX Frequency */
+static int fm_core_tx_set_frequency(unsigned int freq_to_set)
+{
+ struct fmtx_data *tx = &fmdev->tx_data;
+ unsigned short payload, chanl_index;
+ int ret;
+
+ FMDRV_API_START();
+
+ if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) {
+ fm_core_tx_xmit(0);
+ clear_bit(FM_CORE_TX_XMITING, &fmdev->flag);
+ }
+
+ /* Enable FR, BL interrupts */
+ FM_STORE_LE16_TO_BE16(payload, (FM_FR_EVENT | FM_BL_EVENT));
+ ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+
+ tx->tx_frq = (unsigned long)freq_to_set;
+ FM_DRV_DBG("tx: freq_to_set %ld ", (long int)tx->tx_frq);
+
+ chanl_index = freq_to_set / 10;
+ /* Set current tuner channel */
+ FM_STORE_LE16_TO_BE16(payload, chanl_index);
+ ret = fm_core_send_cmd(CHANL_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* TODO:confirm the freq set */
+ fm_core_tx_set_pwr_lvl(tx->pwr_lvl);
+
+ tx->audio_io = 0x01; /* I2S */
+ fm_core_tx_set_audio_io();
+
+ fm_core_tx_xmit(0x01); /* Enable transmission */
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Returns availability of RDS data in internel buffer */
+int fm_core_is_rds_data_available(struct file *file,
+ struct poll_table_struct *pts)
+{
+ FMDRV_API_START();
+
+ poll_wait(file, &fmdev->rx.rds.read_queue, pts);
+ if (fmdev->rx.rds.rd_index != fmdev->rx.rds.wr_index) {
+ FMDRV_API_EXIT(0);
+ return 0;
+ }
+
+ FMDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+}
+
+/* Copies RDS data from internal buffer to user buffer */
+int fm_core_transfer_rds_from_internal_buff(struct file *file,
+ char __user *buf, size_t count)
+{
+ unsigned int block_count;
+ unsigned long flags;
+ int ret;
+ FMDRV_API_START();
+
+ /* Block if no new data available */
+ if (fmdev->rx.rds.wr_index == fmdev->rx.rds.rd_index) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+
+ ret = wait_event_interruptible(fmdev->rx.rds.read_queue,
+ (fmdev->rx.rds.wr_index !=
+ fmdev->rx.rds.rd_index));
+ if (ret) {
+ FMDRV_API_EXIT(-EINTR);
+ return -EINTR;
+ }
+ }
+
+ /* Calculate block count from byte count */
+ count /= 3;
+ block_count = 0;
+ ret = 0;
+
+ spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
+
+ /* Copy RDS blocks from the internal buffer and to user buffer */
+ while (block_count < count) {
+ if (fmdev->rx.rds.wr_index == fmdev->rx.rds.rd_index)
+ break;
+
+ /* Always transfer complete RDS blocks */
+ if (copy_to_user
+ (buf, &fmdev->rx.rds.buffer[fmdev->rx.rds.rd_index],
+ FM_RDS_BLOCK_SIZE))
+ break;
+
+ /* Increment and wrap the read pointer */
+ fmdev->rx.rds.rd_index += FM_RDS_BLOCK_SIZE;
+
+ /* Wrap read pointer */
+ if (fmdev->rx.rds.rd_index >= fmdev->rx.rds.buf_size)
+ fmdev->rx.rds.rd_index = 0;
+
+ /* Increment counters */
+ block_count++;
+ buf += FM_RDS_BLOCK_SIZE;
+ ret += FM_RDS_BLOCK_SIZE;
+ }
+ spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
+ return ret;
+}
+
+/* Checks FM core active status and TX/RX/OFF mode status */
+static inline int fm_core_check_mode(unsigned char mode)
+{
+ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+ FM_DRV_ERR("FM core is not ready");
+ return -EPERM;
+ }
+ if (mode >= FM_MODE_ENTRY_MAX) {
+ FM_DRV_ERR("Invalid fm mode");
+ return -EPERM;
+ }
+ if (fmdev->curr_fmmode != mode) {
+ FM_DRV_ERR("Current mode is not in %s mode",
+ mode ? ((mode == 1) ? "TX" : "RX") : "OFF");
+ return -EPERM;
+ }
+ return 0;
+}
+
+/* Set RX Frequency */
+static int fm_core_rx_set_frequency(unsigned int freq_to_set)
+{
+ unsigned long timeleft;
+ unsigned short payload, curr_frq, frq_index;
+ unsigned int curr_frq_in_khz;
+ int ret, resp_len;
+
+ FMDRV_API_START();
+
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (freq_to_set < fmdev->rx.region.bottom_frequency ||
+ freq_to_set > fmdev->rx.region.top_frequency) {
+ FM_DRV_ERR("Invalid frequency %d", freq_to_set);
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ /* Set audio enable */
+ FM_STORE_LE16_TO_BE16(payload, FM_RX_FM_AUDIO_ENABLE_I2S_AND_ANALOG);
+ ret = fm_core_send_cmd(AUDIO_ENABLE_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Set hilo to automatic selection */
+ FM_STORE_LE16_TO_BE16(payload, FM_RX_IFFREQ_HILO_AUTOMATIC);
+ ret = fm_core_send_cmd(HILO_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Calculate frequency index to write */
+ frq_index = (freq_to_set - fmdev->rx.region.bottom_frequency) /
+ fmdev->rx.region.channel_spacing;
+
+ /* Set frequency index */
+ FM_STORE_LE16_TO_BE16(payload, frq_index);
+ ret = fm_core_send_cmd(FREQ_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Read flags - just to clear any pending interrupts if we had */
+ ret = fm_core_send_cmd(FLAG_GET, NULL, 2,
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Enable FR, BL interrupts */
+ fmdev->irq_info.mask |= (FM_FR_EVENT | FM_BL_EVENT);
+ FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+ ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Start tune */
+ FM_STORE_LE16_TO_BE16(payload, FM_TUNER_PRESET_MODE);
+ ret = fm_core_send_cmd(TUNER_MODE_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Wait for tune ended interrupt */
+ init_completion(&fmdev->maintask_completion);
+ timeleft = wait_for_completion_timeout(&fmdev->maintask_completion,
+ FM_DRV_TX_TIMEOUT);
+ if (!timeleft) {
+ FM_DRV_ERR("Timeout(%d sec),didn't get tune ended interrupt",
+ jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+ FMDRV_API_EXIT(-ETIMEDOUT);
+ return -ETIMEDOUT;
+ }
+
+ /* Read freq back to confirm */
+ ret = fm_core_send_cmd(FREQ_GET, NULL, 2,
+ &fmdev->maintask_completion, &curr_frq,
+ &resp_len);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ curr_frq = FM_BE16_TO_LE16(curr_frq);
+ curr_frq_in_khz = (fmdev->rx.region.bottom_frequency
+ +
+ ((unsigned int)curr_frq *
+ fmdev->rx.region.channel_spacing));
+
+ /* Re-enable default FM interrupts */
+ fmdev->irq_info.mask &= ~(FM_FR_EVENT | FM_BL_EVENT);
+ FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+ ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ if (curr_frq_in_khz != freq_to_set) {
+ FM_DRV_ERR("Current chip frequency(%d) is not matching with"
+ " requested frequency(%d)", curr_frq_in_khz,
+ freq_to_set);
+ FMDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+ }
+
+ /* Update local cache */
+ fmdev->rx.curr_freq = curr_frq_in_khz;
+
+ /* Reset RDS cache and current station pointers */
+ fm_core_rx_reset_rds_cache();
+ fm_core_rx_reset_curr_station_info();
+
+ /* Do we need to reset anything else? */
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_set_frequency(unsigned int freq_to_set)
+{
+ int ret;
+
+ FMDRV_API_START();
+ switch (fmdev->curr_fmmode) {
+ case FM_MODE_RX:
+ ret = fm_core_rx_set_frequency(freq_to_set);
+ break;
+
+ case FM_MODE_TX:
+ ret = fm_core_tx_set_frequency(freq_to_set);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+ FMDRV_API_EXIT(ret);
+ return ret;
+}
+
+int fm_core_get_frequency(unsigned int *cur_tuned_frq)
+{
+ int ret;
+
+ FMDRV_API_START();
+ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+ FM_DRV_ERR("FM core is not ready");
+ FMDRV_API_EXIT(-EPERM);
+ return -EPERM;
+ }
+ if (fmdev->rx.curr_freq == FM_UNDEFINED_FREQ) {
+ FM_DRV_ERR("RX frequency is not set");
+ FMDRV_API_EXIT(-EPERM);
+ return -EPERM;
+ }
+ if (cur_tuned_frq == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ ret = 0;
+ switch (fmdev->curr_fmmode) {
+ case FM_MODE_RX:
+ *cur_tuned_frq = fmdev->rx.curr_freq;
+ ret = 0;
+ break;
+
+ case FM_MODE_TX:
+ *cur_tuned_frq = 0; /* TODO : Change this later */
+ ret = 0;
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+ FMDRV_API_EXIT(ret);
+ return ret;
+}
+
+/* Seek */
+int fm_core_rx_seek(unsigned int seek_upward, unsigned int wrap_around)
+{
+ int resp_len;
+ unsigned short curr_frq, next_frq, last_frq;
+ unsigned short payload, int_reason;
+ char offset;
+ unsigned long timeleft;
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ /* Read the current frequency from chip */
+ ret = fm_core_send_cmd(FREQ_GET, NULL, sizeof(curr_frq),
+ &fmdev->maintask_completion, &curr_frq,
+ &resp_len);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ curr_frq = FM_BE16_TO_LE16(curr_frq);
+
+ last_frq =
+ (fmdev->rx.region.top_frequency - fmdev->rx.region.bottom_frequency)
+ / fmdev->rx.region.channel_spacing;
+
+ /* Check the offset in order to be aligned to the 100KHz steps */
+ offset = curr_frq % 2;
+
+ next_frq = seek_upward ? curr_frq + 2 /* Seek Up */ :
+ curr_frq - 2 /* Seek Down */ ;
+
+ /* Add or subtract offset (0/1) in order
+ * to stay aligned to the 100KHz steps
+ */
+ if ((short)next_frq < 0)
+ next_frq = last_frq - offset;
+ else if (next_frq > last_frq)
+ next_frq = 0 + offset;
+
+ /* Set calculated next frequency to perform seek */
+ FM_STORE_LE16_TO_BE16(payload, next_frq);
+ ret = fm_core_send_cmd(FREQ_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Set search direction (0:Seek Down, 1:Seek Up) */
+ FM_STORE_LE16_TO_BE16(payload, (seek_upward ? FM_SEARCH_DIRECTION_UP :
+ FM_SEARCH_DIRECTION_DOWN));
+ ret = fm_core_send_cmd(SEARCH_DIR_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Read flags - just to clear any pending interrupts if we had */
+ ret = fm_core_send_cmd(FLAG_GET, NULL, 2,
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Enable FR, BL interrupts */
+ fmdev->irq_info.mask |= (FM_FR_EVENT | FM_BL_EVENT);
+ FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+ ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Start seek */
+ FM_STORE_LE16_TO_BE16(payload, FM_TUNER_AUTONOMOUS_SEARCH_MODE);
+ ret = fm_core_send_cmd(TUNER_MODE_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Wait for tune ended/band limit reached interrupt */
+ init_completion(&fmdev->maintask_completion);
+ timeleft = wait_for_completion_timeout(&fmdev->maintask_completion,
+ FM_DRV_RX_SEEK_TIMEOUT);
+ if (!timeleft) {
+ FM_DRV_ERR("Timeout(%d sec),didn't get tune ended interrupt",
+ jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000);
+ FMDRV_API_EXIT(-ETIMEDOUT);
+ return -ETIMEDOUT;
+ }
+ int_reason = fmdev->irq_info.flag & 0x3;
+
+ /* Re-enable default FM interrupts */
+ fmdev->irq_info.mask &= ~(FM_FR_EVENT | FM_BL_EVENT);
+ FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+ ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Read freq to know where operation tune operation stopped */
+ ret = fm_core_send_cmd(FREQ_GET, NULL, 2,
+ &fmdev->maintask_completion, &curr_frq,
+ &resp_len);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ curr_frq = FM_BE16_TO_LE16(curr_frq);
+ fmdev->rx.curr_freq = (fmdev->rx.region.bottom_frequency +
+ ((unsigned int)curr_frq *
+ fmdev->rx.region.channel_spacing));
+
+ /* Reset RDS cache and current station pointers */
+ fm_core_rx_reset_rds_cache();
+ fm_core_rx_reset_curr_station_info();
+
+ /* Return error if band limit is reached */
+ if (int_reason & FM_BL_EVENT) {
+ FM_DRV_DBG("band limit reached\n");
+ FMDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+ }
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Set volume */
+int fm_core_rx_set_volume(unsigned short vol_to_set)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (vol_to_set > FM_RX_VOLUME_MAX) {
+ FM_DRV_ERR("Volume is not within(%d-%d) range",
+ FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX);
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ vol_to_set *= FM_RX_VOLUME_GAIN_STEP;
+
+ FM_STORE_LE16_TO_BE16(payload, vol_to_set);
+ ret = fm_core_send_cmd(VOLUME_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ fmdev->rx.curr_volume = vol_to_set;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Get volume */
+int fm_core_rx_get_volume(unsigned short *curr_vol)
+{
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (curr_vol == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ *curr_vol = fmdev->rx.curr_volume / FM_RX_VOLUME_GAIN_STEP;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Returns current band index (0-Europe/US; 1-Japan) */
+int fm_core_region_get(unsigned char *region)
+{
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (region == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ *region = fmdev->rx.region.region_index;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* To get current band's bottom and top frequency */
+int fm_core_rx_get_currband_lowhigh_freq(unsigned int *bottom_frequency,
+ unsigned int *top_frequency)
+{
+ FMDRV_API_START();
+
+ if (bottom_frequency != NULL)
+ *bottom_frequency = fmdev->rx.region.bottom_frequency;
+
+ if (top_frequency != NULL)
+ *top_frequency = fmdev->rx.region.top_frequency;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Sets band (0-Europe/US; 1-Japan) */
+int fm_core_rx_region_set(unsigned char region_to_set)
+{
+ unsigned short payload;
+ unsigned int new_frq;
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (region_to_set != FM_BAND_EUROPE_US &&
+ region_to_set != FM_BAND_JAPAN) {
+ FM_DRV_ERR("Invalid band\n");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ if (fmdev->rx.region.region_index == region_to_set) {
+ FM_DRV_ERR("Requested band is already configured\n");
+ FMDRV_API_EXIT(-EPERM);
+ return -EPERM;
+ }
+ /* Send cmd to set the band */
+ FM_STORE_LE16_TO_BE16(payload, (unsigned short)region_to_set);
+ ret = fm_core_send_cmd(RX_BAND_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Update local region info cache */
+ memcpy(&fmdev->rx.region, ®ion_configs[region_to_set],
+ sizeof(struct region_info));
+
+ /* Check whether current RX frequency is within band boundary */
+ if (fmdev->curr_fmmode == FM_MODE_RX) {
+ new_frq = 0;
+ if (fmdev->rx.curr_freq < fmdev->rx.region.bottom_frequency)
+ new_frq = fmdev->rx.region.bottom_frequency;
+ else if (fmdev->rx.curr_freq > fmdev->rx.region.top_frequency)
+ new_frq = fmdev->rx.region.top_frequency;
+
+ if (new_frq) {
+ FM_DRV_DBG
+ ("Current freq is not within band limit boundary,"
+ "switching to %d KHz", new_frq);
+ /* Current RX frequency is not
+ * within boundary. So, update it
+ */
+ ret = fm_core_rx_set_frequency(new_frq);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ }
+ }
+
+ /* TODO : Add above boundary check in TX mode also */
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_region_set(unsigned char region_to_set)
+{
+ int ret;
+
+ FMDRV_API_START();
+ switch (fmdev->curr_fmmode) {
+ case FM_MODE_RX:
+ ret = fm_core_rx_region_set(region_to_set);
+ break;
+
+ case FM_MODE_TX:
+ ret = fm_core_tx_set_region(region_to_set);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+ FMDRV_API_EXIT(ret);
+ return ret;
+}
+
+/* Reads current mute mode (Mute Off/On/Attenuate)*/
+int fm_core_rx_get_mute_mode(unsigned char *curr_mute_mode)
+{
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (curr_mute_mode == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ *curr_mute_mode = fmdev->rx.curr_mute_mode;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int __fm_core_config_rx_mute_reg(void)
+{
+ unsigned short payload, muteval;
+ int ret;
+
+ FMDRV_API_START();
+
+ muteval = 0;
+ switch (fmdev->rx.curr_mute_mode) {
+ case FM_MUTE_ON:
+ muteval = FM_RX_MUTE_AC_MUTE_MODE;
+ break;
+ case FM_MUTE_OFF:
+ muteval = FM_RX_MUTE_UNMUTE_MODE;
+ break;
+ case FM_MUTE_ATTENUATE:
+ muteval = FM_RX_MUTE_SOFT_MUTE_FORCE_MODE;
+ break;
+ }
+ if (fmdev->rx.curr_rf_depend_mute == FM_RX_RF_DEPENDENT_MUTE_ON)
+ muteval |= FM_RX_MUTE_RF_DEP_MODE;
+ else
+ muteval &= ~FM_RX_MUTE_RF_DEP_MODE;
+
+ FM_STORE_LE16_TO_BE16(payload, muteval);
+ ret = fm_core_send_cmd(MUTE_STATUS_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Configures mute mode (Mute Off/On/Attenuate) */
+int fm_core_rx_set_mute_mode(unsigned char mute_mode_toset)
+{
+ unsigned char org_state;
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (fmdev->rx.curr_mute_mode == mute_mode_toset) {
+ FMDRV_API_EXIT(0);
+ return 0;
+ }
+ org_state = fmdev->rx.curr_mute_mode;
+ fmdev->rx.curr_mute_mode = mute_mode_toset;
+
+ ret = __fm_core_config_rx_mute_reg();
+ if (ret < 0) {
+ fmdev->rx.curr_mute_mode = org_state;
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_set_mute_mode(unsigned char mute_mode_toset)
+{
+ int ret;
+
+ FMDRV_API_START();
+ switch (fmdev->curr_fmmode) {
+ case FM_MODE_RX:
+ ret = fm_core_rx_set_mute_mode(mute_mode_toset);
+ break;
+
+ case FM_MODE_TX:
+ ret = fm_core_tx_set_mute_mode(mute_mode_toset);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+ FMDRV_API_EXIT(ret);
+ return ret;
+}
+
+/* Gets RF dependent soft mute mode enable/disable status */
+int fm_core_rx_get_rfdepend_softmute(unsigned char *curr_mute_mode)
+{
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (curr_mute_mode == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ *curr_mute_mode = fmdev->rx.curr_rf_depend_mute;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Sets RF dependent soft mute mode */
+int fm_core_rx_set_rfdepend_softmute(unsigned char rfdepend_mute)
+{
+ unsigned char org_state;
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON &&
+ rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) {
+ FM_DRV_ERR("Invalid RF dependent soft mute");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ if (fmdev->rx.curr_rf_depend_mute == rfdepend_mute) {
+ FMDRV_API_EXIT(0);
+ return 0;
+ }
+
+ org_state = fmdev->rx.curr_rf_depend_mute;
+ fmdev->rx.curr_rf_depend_mute = rfdepend_mute;
+
+ ret = __fm_core_config_rx_mute_reg();
+ if (ret < 0) {
+ fmdev->rx.curr_rf_depend_mute = org_state;
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Returns the signal strength level of current channel */
+int fm_core_rx_get_rssi_level(unsigned short *rssilvl)
+{
+ unsigned short curr_rssi_lel;
+ int resp_len;
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (rssilvl == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ /* Read current RSSI level */
+ ret = fm_core_send_cmd(RSSI_LVL_GET, NULL, 2,
+ &fmdev->maintask_completion, &curr_rssi_lel,
+ &resp_len);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ *rssilvl = FM_BE16_TO_LE16(curr_rssi_lel);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Sets the signal strength level that once reached
+ * will stop the auto search process
+ */
+int fm_core_rx_set_rssi_threshold(short rssi_lvl_toset)
+{
+ unsigned short payload;
+ int ret;
+ FMDRV_API_START();
+
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN ||
+ rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) {
+ FM_DRV_ERR("Invalid RSSI threshold level");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ FM_STORE_LE16_TO_BE16(payload, (unsigned short)rssi_lvl_toset);
+ ret = fm_core_send_cmd(SEARCH_LVL_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ fmdev->rx.curr_rssi_threshold = rssi_lvl_toset;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Returns current RX RSSI threshold value */
+int fm_core_rx_get_rssi_threshold(short *curr_rssi_lvl)
+{
+ int ret;
+ FMDRV_API_START();
+
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (curr_rssi_lvl == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ *curr_rssi_lvl = fmdev->rx.curr_rssi_threshold;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Sets RX stereo/mono modes */
+int fm_core_rx_set_stereo_mono(unsigned short mode)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) {
+ FM_DRV_ERR("Invalid mode");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ /* Set stereo/mono mode */
+ FM_STORE_LE16_TO_BE16(payload, (unsigned short)mode);
+ ret = fm_core_send_cmd(MOST_MODE_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Set stereo blending mode */
+ FM_STORE_LE16_TO_BE16(payload, FM_STEREO_SOFT_BLEND);
+ ret = fm_core_send_cmd(MOST_BLEND_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_set_stereo_mono(unsigned short mode)
+{
+ int ret;
+
+ FMDRV_API_START();
+ switch (fmdev->curr_fmmode) {
+ case FM_MODE_RX:
+ ret = fm_core_rx_set_stereo_mono(mode);
+ break;
+
+ case FM_MODE_TX:
+ ret = fm_core_tx_set_stereo_mono(mode);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+ FMDRV_API_EXIT(ret);
+ return ret;
+}
+
+/* Gets current RX stereo/mono mode */
+int fm_core_rx_get_stereo_mono(unsigned short *mode)
+{
+ unsigned short curr_mode;
+ int ret, resp_len;
+
+ FMDRV_API_START();
+
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (mode == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ ret = fm_core_send_cmd(MOST_MODE_GET, NULL, 2,
+ &fmdev->maintask_completion, &curr_mode,
+ &resp_len);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ *mode = FM_BE16_TO_LE16(curr_mode);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Chooses RX de-emphasis filter mode (50us/75us) */
+int fm_core_rx_set_deemphasis_mode(unsigned short mode)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (mode != FM_RX_EMPHASIS_FILTER_50_USEC &&
+ mode != FM_RX_EMPHASIS_FILTER_75_USEC) {
+ FM_DRV_ERR("Invalid rx de-emphasis mode");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ FM_STORE_LE16_TO_BE16(payload, mode);
+ ret = fm_core_send_cmd(DEMPH_MODE_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Gets current RX de-emphasis filter mode */
+int fm_core_rx_get_deemphasis_mode(unsigned short *curr_deemphasis_mode)
+{
+ unsigned short curr_mode;
+ int ret, resp_len;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (curr_deemphasis_mode == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ ret = fm_core_send_cmd(DEMPH_MODE_GET, NULL, 2,
+ &fmdev->maintask_completion, &curr_mode,
+ &resp_len);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ *curr_deemphasis_mode = FM_BE16_TO_LE16(curr_mode);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Enable/Disable RX RDS */
+int fm_core_rx_set_rds_mode(unsigned char rds_en_dis)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (rds_en_dis != FM_RX_RDS_ENABLE && rds_en_dis != FM_RX_RDS_DISABLE) {
+ FM_DRV_ERR("Invalid rds option");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ if (rds_en_dis == FM_RX_RDS_ENABLE
+ && fmdev->rx.rds.flag == FM_RX_RDS_DISABLE) {
+ /* Turn on RX RDS */
+ /* Turn on RDS circuit */
+ FM_STORE_LE16_TO_BE16(payload,
+ FM_RX_POWET_SET_FM_AND_RDS_BLK_ON);
+ ret =
+ fm_core_send_cmd(POWER_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Clear and rest RDS FIFO */
+ FM_STORE_LE16_TO_BE16(payload, FM_RX_RDS_FLUSH_FIFO);
+ ret = fm_core_send_cmd(RDS_CNTRL_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Read flags - just to clear any
+ * pending interrupts if we had
+ */
+ ret = fm_core_send_cmd(FLAG_GET, NULL, 2,
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Set RDS FIFO threshold value */
+ FM_STORE_LE16_TO_BE16(payload, FM_RX_RDS_FIFO_THRESHOLD);
+ ret = fm_core_send_cmd(RDS_MEM_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Enable RDS interrupt */
+ fmdev->irq_info.mask |= FM_RDS_EVENT;
+ FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+ ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Update our local flag */
+ fmdev->rx.rds.flag = FM_RX_RDS_ENABLE;
+ } else if (rds_en_dis == FM_RX_RDS_DISABLE
+ && fmdev->rx.rds.flag == FM_RX_RDS_ENABLE) {
+ /* Turn off RX RDS */
+ /* Turn off RDS circuit */
+ FM_STORE_LE16_TO_BE16(payload, FM_RX_POWER_SET_FM_ON_RDS_OFF);
+ ret = fm_core_send_cmd(POWER_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Reset RDS pointers */
+ fmdev->rx.rds.last_block_index = 0;
+ fmdev->rx.rds.wr_index = 0;
+ fmdev->rx.rds.rd_index = 0;
+ fm_core_rx_reset_curr_station_info();
+
+ /* Update RDS local cache */
+ fmdev->irq_info.mask &= ~(FM_RDS_EVENT);
+ fmdev->rx.rds.flag = FM_RX_RDS_DISABLE;
+ }
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_set_rds_mode(unsigned char rds_en_dis)
+{
+ int ret;
+
+ FMDRV_API_START();
+ switch (fmdev->curr_fmmode) {
+ case FM_MODE_RX:
+ ret = fm_core_rx_set_rds_mode(rds_en_dis);
+ break;
+
+ case FM_MODE_TX:
+ ret = fm_core_tx_set_rds_mode(rds_en_dis);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+ FMDRV_API_EXIT(ret);
+ return ret;
+}
+
+/* Returns current RX RDS enable/disable status */
+int fm_core_rx_get_rds_mode(unsigned char *curr_rds_en_dis)
+{
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (curr_rds_en_dis == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ *curr_rds_en_dis = fmdev->rx.rds.flag;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Sets RDS operation mode (RDS/RDBS) */
+int fm_core_rx_set_rds_system(unsigned char rds_mode)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) {
+ FM_DRV_ERR("Invalid rds mode");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ /* Set RDS operation mode */
+ FM_STORE_LE16_TO_BE16(payload, (unsigned short)rds_mode);
+ ret = fm_core_send_cmd(RDS_SYSTEM_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ fmdev->rx.rds_mode = rds_mode;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Returns current RDS operation mode */
+int fm_core_rx_get_rds_system(unsigned char *rds_mode)
+{
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (rds_mode == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ *rds_mode = fmdev->rx.rds_mode;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Sends power off command to the chip */
+int fm_core_power_down(void)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+ FM_DRV_ERR("FM core is not ready");
+ FMDRV_API_EXIT(-EPERM);
+ return -EPERM;
+ }
+ if (fmdev->curr_fmmode == FM_MODE_OFF) {
+ FM_DRV_ERR("FM chip is already in OFF state");
+ FMDRV_API_EXIT(0);
+ return 0;
+ }
+ /* Disable FM functions over Channel-8 */
+ FM_STORE_LE16_TO_BE16(payload, 0x0);
+ ret = fm_core_send_cmd(FM_POWER_MODE, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ /* Unlink from ST. FM GPIO toggling is taken
+ * care in Shared Transport layer
+ */
+ ret = fm_core_release();
+ if (ret < 0) {
+ FM_DRV_ERR("FM CORE release failed");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Configures Alternate Frequency switch mode */
+int fm_core_rx_set_af_switch(unsigned char af_mode)
+{
+ unsigned short payload;
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON &&
+ af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) {
+ FM_DRV_ERR("Invalid af mode");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ /* Enable/disable low RSSI interrupt based on af_mode */
+ if (af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
+ fmdev->irq_info.mask |= FM_LEV_EVENT;
+ else
+ fmdev->irq_info.mask &= ~FM_LEV_EVENT;
+
+ FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+ ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ FM_CHECK_SEND_CMD_STATUS(ret);
+
+ fmdev->rx.af_mode = af_mode;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Returns Alternate Frequency switch status */
+int fm_core_rx_get_af_switch(unsigned char *af_mode)
+{
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_check_mode(FM_MODE_RX);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (af_mode == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ *af_mode = fmdev->rx.af_mode;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Reads init command from FM firmware file and loads to the chip */
+static int fm_core_download_firmware(const char *firmware_name)
+{
+ const struct firmware *fw_entry;
+ struct bts_header *fw_header;
+ struct bts_action *action;
+ struct bts_action_delay *delay;
+ char *fw_data;
+ int ret, fw_len, cmd_cnt;
+
+ FMDRV_API_START();
+
+ cmd_cnt = 0;
+ set_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag);
+
+ /* Read firmware data */
+ ret = request_firmware(&fw_entry, firmware_name, &fmdev->v4l2dev->dev);
+ if (unlikely(ret)) {
+ FM_DRV_ERR("Unable to read firmware(%s) content\n",
+ firmware_name);
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ FM_DRV_DBG("Firmware(%s) length : %d bytes", firmware_name,
+ fw_entry->size);
+
+ fw_data = (void *)fw_entry->data;
+ fw_len = fw_entry->size;
+
+ /* Check TI's magic number in firmware file */
+ fw_header = (struct bts_header *)fw_data;
+ if (fw_header->magic != FM_FW_FILE_HEADER_MAGIC) {
+ release_firmware(fw_entry);
+ clear_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag);
+ FM_DRV_ERR("%s not a legal TI firmware file", firmware_name);
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ FM_DRV_DBG("Firmware(%s) magic number : 0x%x", firmware_name,
+ fw_header->magic);
+
+ /* Skip file header info , we already verified it */
+ fw_data += sizeof(struct bts_header);
+ fw_len -= sizeof(struct bts_header);
+
+ while (fw_data && fw_len > 0) {
+ action = (struct bts_action *)fw_data;
+
+ switch (action->type) {
+
+ case ACTION_SEND_COMMAND: /* Send */
+
+ /* Send the command to chip */
+ ret = fm_core_send_cmd(0, action->data, action->size,
+ &fmdev->maintask_completion,
+ NULL, NULL);
+ if (unlikely(ret < 0)) {
+ release_firmware(fw_entry);
+ clear_bit(FM_FIRMWARE_DW_INPROGRESS,
+ &fmdev->flag);
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ cmd_cnt++;
+ break;
+
+ case ACTION_DELAY: /* Delay */
+ delay = (struct bts_action_delay *)action->data;
+ mdelay(delay->msec);
+ break;
+ }
+
+ fw_data += (sizeof(struct bts_action) + (action->size));
+ fw_len -= (sizeof(struct bts_action) + (action->size));
+ }
+
+ release_firmware(fw_entry);
+ clear_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag);
+
+ FM_DRV_DBG("Firmare commands(%d) loaded to the chip", cmd_cnt);
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Loads default RX configuration to the chip */
+static int __fm_core_rx_load_default_configuration(void)
+{
+ int ret;
+ FMDRV_API_START();
+
+ /* Set default RX volume level */
+ ret = fm_core_rx_set_volume(FM_DEFAULT_RX_VOLUME);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ /* Set default RX RSSI level threshold */
+ ret = fm_core_rx_set_rssi_threshold(FM_DEFAULT_RSSI_THRESHOLD);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Does FM power on sequence */
+static int fm_core_power_up(unsigned char fw_option)
+{
+ unsigned short payload, asic_id, asic_ver;
+ int resp_len, ret;
+ char fw_name[50];
+
+ FMDRV_API_START();
+ if (fw_option >= FM_MODE_ENTRY_MAX) {
+ FM_DRV_ERR("Invalid firmware download option");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ /* Initialize FM Core. FM GPIO toggling is
+ * taken care in Shared Transport
+ */
+ ret = fm_core_prepare();
+ if (ret < 0) {
+ FM_DRV_ERR("Unable to prepare FM CORE");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ /* Enable Channel-8 communication on chip side. This is must for
+ * reading ASIC ID and ASIC version of the chip.
+ */
+ FM_STORE_LE16_TO_BE16(payload, FM_ENABLE);
+
+ ret = fm_core_send_cmd(FM_POWER_MODE, &payload, sizeof(payload),
+ &fmdev->maintask_completion, NULL, NULL);
+ if (ret < 0) {
+ FM_DRV_ERR("Failed enable FM over Channel 8");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ /* Allow the chip to settle down in Channel-8 mode */
+ msleep(5);
+
+ /* Read ASIC ID */
+ ret = fm_core_send_cmd(ASIC_ID_GET, NULL, sizeof(asic_id),
+ &fmdev->maintask_completion, &asic_id,
+ &resp_len);
+ if (ret < 0) {
+ FM_DRV_ERR("Failed read FM chip ASIC ID");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ /* Read ASIC version */
+ ret = fm_core_send_cmd(ASIC_VER_GET, NULL, sizeof(asic_ver),
+ &fmdev->maintask_completion, &asic_ver,
+ &resp_len);
+ if (ret < 0) {
+ FM_DRV_ERR("Failed read FM chip ASIC Version");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ FM_DRV_DBG("ASIC ID: 0x%x , ASIC Version: %d", FM_BE16_TO_LE16(asic_id),
+ FM_BE16_TO_LE16(asic_ver));
+
+ /* Frame common firmware file name and load init commands */
+ sprintf(fw_name, "%s_%x.%d.bts", FM_FMC_FW_FILE_START,
+ FM_BE16_TO_LE16(asic_id), FM_BE16_TO_LE16(asic_ver));
+ ret = fm_core_download_firmware(fw_name);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ /* Frame TX or RX firmware file name
+ * based on request and load init commands.
+ */
+ sprintf(fw_name, "%s_%x.%d.bts", (fw_option == FM_MODE_RX) ?
+ FM_RX_FW_FILE_START : FM_TX_FW_FILE_START,
+ FM_BE16_TO_LE16(asic_id), FM_BE16_TO_LE16(asic_ver));
+ ret = fm_core_download_firmware(fw_name);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* ----- Fucntions exported to FM mixer control layer ----- */
+
+/* All the functions which are exported from this file
+ * to FM mixer controls layer will check FM Core ready
+ * status. If FM Core is not ready, it will return
+ * immediately with an error.
+ */
+
+/* Set FM Modes(TX, RX, OFF) */
+int fm_core_mode_set(unsigned char fm_mode)
+{
+ int ret;
+
+ FMDRV_API_START();
+
+ if (fm_mode >= FM_MODE_ENTRY_MAX) {
+ FM_DRV_ERR("Invalid FM mode");
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ if (fmdev->curr_fmmode == fm_mode) {
+ FM_DRV_DBG("Already fm is in mode(%d)", fm_mode);
+ FMDRV_API_EXIT(0);
+ return 0;
+ }
+ switch (fm_mode) {
+ case FM_MODE_OFF: /* OFF Mode */
+ ret = fm_core_power_down();
+ if (ret < 0) {
+ FM_DRV_ERR("Failed to set OFF mode");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ break;
+
+ case FM_MODE_TX: /* TX Mode */
+ case FM_MODE_RX: /* RX Mode */
+ /* Power down before switching to TX or RX mode */
+ if (fmdev->curr_fmmode != FM_MODE_OFF) {
+ ret = fm_core_power_down();
+ if (ret < 0) {
+ FM_DRV_ERR("Failed to set OFF mode");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ msleep(30);
+ }
+ /* Load requested mode's firmware */
+ ret = fm_core_power_up(fm_mode);
+ if (ret < 0) {
+ FM_DRV_ERR("Failed to load firmware\n");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ }
+ /* Set current mode */
+ fmdev->curr_fmmode = fm_mode;
+
+ /* Set default configuration */
+ if (fmdev->curr_fmmode == FM_MODE_RX) {
+ FM_DRV_DBG("Loading default rx configuration..\n");
+ ret = __fm_core_rx_load_default_configuration();
+ if (ret < 0) {
+ FM_DRV_ERR("Failed to load default values\n");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ }
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Returns current FM mode (TX, RX, OFF) */
+int fm_core_mode_get(unsigned char *fmmode)
+{
+ FMDRV_API_START();
+
+ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+ FM_DRV_ERR("FM core is not ready");
+ return -EPERM;
+ }
+ if (fmmode == NULL) {
+ FM_DRV_ERR("Invalid memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+
+ *fmmode = fmdev->curr_fmmode;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* ----------------- FM Core Init -------------- */
+
+/* This function will be called from FM V4L2 open function.
+ * This will request FM ST interface to register with ST driver.
+ */
+int fm_core_prepare(void)
+{
+ int ret;
+
+ FMDRV_API_START();
+
+ if (test_bit(FM_CORE_READY, &fmdev->flag)) {
+ FM_DRV_DBG("FM Core is already up");
+ FMDRV_API_EXIT(0);
+ return 0;
+ }
+ if (!test_bit(FM_CORE_TRANSPORT_READY, &fmdev->flag)) {
+ FM_DRV_ERR("FM Core transport is not ready");
+ FMDRV_API_EXIT(-EPERM);
+ return -EPERM;
+ }
+
+ /* Request FM ST to get register with ST driver. Send FM Core RX
+ * queue and RX tasklet pointers to FM ST. FM ST will push
+ * received FM packet into this queue and schedule this RX
+ * tasklet.
+ */
+ ret = fm_st_register(&fmdev->rx_q, &fmdev->rx_task);
+ if (ret < 0) {
+ fm_st_release();
+ FM_DRV_ERR("Unable to register with ST");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ spin_lock_init(&fmdev->rds_buff_lock);
+ spin_lock_init(&fmdev->resp_skb_lock);
+
+ /* Initialize TX queue and TX tasklet */
+ skb_queue_head_init(&fmdev->tx_q);
+ tasklet_init(&fmdev->tx_task, fm_core_tx_tasklet, (unsigned long)fmdev);
+
+ /* Initialize RX Queue and RX tasklet */
+ skb_queue_head_init(&fmdev->rx_q);
+ tasklet_init(&fmdev->rx_task, fm_core_rx_tasklet, (unsigned long)fmdev);
+
+ /* Initialize interrupt related info */
+ fmdev->irq_info.stage_index = 0;
+
+ /* Number of packet can send at a time */
+ atomic_set(&fmdev->tx_cnt, 1);
+
+ fmdev->response_completion = NULL;
+
+ init_timer(&fmdev->irq_info.int_timeout_timer);
+ fmdev->irq_info.int_timeout_timer.function =
+ &fm_core_int_timeout_handler;
+
+ /* Default interrupt bits to be enabled */
+ fmdev->irq_info.mask =
+ FM_MAL_EVENT /*| FM_STIC_EVENT <<Enable this later>> */ ;
+
+ /* Region info */
+ memcpy(&fmdev->rx.region, ®ion_configs[default_radio_region],
+ sizeof(struct region_info));
+
+ fmdev->rx.curr_mute_mode = FM_MUTE_OFF;
+ fmdev->rx.curr_rf_depend_mute = FM_RX_RF_DEPENDENT_MUTE_OFF;
+ fmdev->rx.rds.flag = FM_RX_RDS_DISABLE;
+ fmdev->rx.curr_freq = FM_UNDEFINED_FREQ;
+ fmdev->rx.rds_mode = FM_RDS_SYSTEM_RDS;
+ fmdev->rx.af_mode = FM_RX_RDS_AF_SWITCH_MODE_OFF;
+ fmdev->irq_info.irq_service_timeout_retry = 0;
+
+ /* RDS ring buffer */
+ fm_core_rx_reset_rds_cache();
+ init_waitqueue_head(&fmdev->rx.rds.read_queue);
+
+ /* Current station info */
+ fm_core_rx_reset_curr_station_info();
+
+ /* FM core is ready */
+ set_bit(FM_CORE_READY, &fmdev->flag);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* -------------- FM Core De-Init ------------- */
+
+/* This function will be called from FM V4L2 release function.
+ * This will request FM ST interface to unregister from ST driver.
+ */
+int fm_core_release(void)
+{
+ int ret;
+
+ FMDRV_API_START();
+
+ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+ FM_DRV_DBG("FM Core is already down");
+ FMDRV_API_EXIT(0);
+ return 0;
+ }
+ /* Sevice pending read */
+ wake_up_interruptible(&fmdev->rx.rds.read_queue);
+
+ /* Stop all tasklets */
+ tasklet_kill(&fmdev->tx_task);
+ tasklet_kill(&fmdev->rx_task);
+
+ /* Flush Tx and Rx queues */
+ skb_queue_purge(&fmdev->tx_q);
+ skb_queue_purge(&fmdev->rx_q);
+
+ fmdev->response_completion = NULL;
+ fmdev->rx.curr_freq = 0;
+
+ /* Unlink from Shared Transport driver */
+ ret = fm_st_unregister();
+ if (ret < 0) {
+ FM_DRV_ERR("Unable to unregister from ST");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ FM_DRV_DBG("Successfully unregistered from ST");
+
+ /* Clear FM Core ready flag */
+ clear_bit(FM_CORE_READY, &fmdev->flag);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_setup_transport(void)
+{
+ int ret;
+
+ FMDRV_API_START();
+
+ if (test_bit(FM_CORE_TRANSPORT_READY, &fmdev->flag)) {
+ FM_DRV_ERR("FM Core transport is already up");
+ FMDRV_API_EXIT(0);
+ return 0;
+ }
+ /* Check availabilty of FM ST. If FM ST is already claimed
+ * by FM Char device interface, don't proceed. Both FM Core
+ * and FM Char device interface can't co-exist.
+ */
+ ret = fm_st_claim();
+ if (ret < 0) {
+ FM_DRV_ERR
+ ("FM char device interface is using FM ST, can't coexist");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ set_bit(FM_CORE_TRANSPORT_READY, &fmdev->flag);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_core_release_transport(void)
+{
+ int ret;
+
+ FMDRV_API_START();
+
+ if (!test_bit(FM_CORE_TRANSPORT_READY, &fmdev->flag)) {
+ FM_DRV_ERR("FM Core transport is already down");
+ FMDRV_API_EXIT(0);
+ return 0;
+ }
+
+ /* Release FM ST */
+ ret = fm_st_release();
+ if (ret < 0) {
+ FM_DRV_ERR("Failed to release FM ST");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ clear_bit(FM_CORE_TRANSPORT_READY, &fmdev->flag);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* ----------- Module Init interface --------- */
+
+static int __init fm_drv_init(void)
+{
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = 0;
+
+ FM_DRV_DBG("FM driver version %s", FM_DRV_VERSION);
+
+ /* Allocate local resource memory */
+ fmdev = kzalloc(sizeof(struct fmdrv_ops), GFP_KERNEL);
+ if (!fmdev) {
+ FM_DRV_ERR("Can't allocate operation structure memory");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ fmdev->rx.rds.buf_size = default_rds_buf * FM_RDS_BLOCK_SIZE;
+
+ /* Allocate memory for RDS ring buffer */
+ fmdev->rx.rds.buffer = kzalloc(fmdev->rx.rds.buf_size, GFP_KERNEL);
+ if (fmdev->rx.rds.buffer == NULL) {
+ kfree(fmdev);
+ FM_DRV_ERR("Can't allocate rds ring buffer");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+
+ /* Register with V4L2 subsystem. This will internally
+ * expose '/dev/radio' device to user space.
+ */
+ ret = fm_v4l2_init_video_device(fmdev);
+ if (ret < 0) {
+ kfree(fmdev);
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ /* Register with ALSA subsystem. This will internally expose
+ * set of FM mixer controls via ALSA to user space.
+ */
+ ret = fm_mixer_init(fmdev);
+ if (ret < 0) {
+ /* Unregister from V4L2 subsystem */
+ fm_v4l2_deinit_video_device(fmdev);
+
+ kfree(fmdev);
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ /* Initialize the FM Character driver */
+ ret = fm_chr_init();
+ if (ret < 0) {
+ FM_DRV_ERR("Can't init FM Character driver");
+ FMDRV_API_EXIT(0);
+ return ret;
+ }
+
+ /* Assign interrupt handling table pointer */
+ fmdev->irq_info.fm_IntActionHandlerTable = g_IntHandlerTable;
+
+ /* Default FM driver mode */
+ fmdev->curr_fmmode = FM_MODE_OFF;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* -------- Module Exit interface -------- */
+
+static void __exit fm_drv_exit(void)
+{
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = 0;
+
+ /* Unregister from V4L2 subsystem */
+ ret = fm_v4l2_deinit_video_device(fmdev);
+ if (ret < 0)
+ FM_DRV_ERR("Unable to unregister from V4L2 subsystem(%d)", ret);
+
+ /* Unregister from ALSA subsystem */
+ ret = fm_mixer_deinit(fmdev);
+ if (ret < 0)
+ FM_DRV_ERR("Unable to unregister from ALSA(%d)", ret);
+
+ /* De-initialize the FM Character driver */
+ fm_chr_exit();
+
+ kfree(fmdev->rx.rds.buffer);
+ kfree(fmdev);
+
+ FMDRV_API_EXIT(0);
+}
+
+module_init(fm_drv_init);
+module_exit(fm_drv_exit);
+
+/* ------------- Module Info ------------- */
+
+MODULE_AUTHOR("Raja Mani <raja_mani@ti.com>");
+MODULE_DESCRIPTION("FM Driver for Connectivity chip of Texas Instruments. "
+ FM_DRV_VERSION);
+MODULE_VERSION(FM_DRV_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ti-st/fmdrv_core.h b/drivers/misc/ti-st/fmdrv_core.h
new file mode 100644
index 0000000..687bb29
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_core.h
@@ -0,0 +1,474 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * FM Core module header file
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _FM_CORE_H
+#define _FM_CORE_H
+
+#define REG_RD 0x1
+#define REG_WR 0x0
+
+struct fm_reg_table {
+ unsigned char opcode;
+ unsigned char type;
+ char *name;
+};
+
+/* FM register index */
+enum fm_reg_index {
+ /* FM RX registers */
+ STEREO_GET,
+ RSSI_LVL_GET,
+ IF_COUNT_GET,
+ FLAG_GET,
+ RDS_SYNC_GET,
+ RDS_DATA_GET,
+ FREQ_SET,
+ FREQ_GET,
+ AF_FREQ_SET,
+ AF_FREQ_GET,
+ MOST_MODE_SET,
+ MOST_MODE_GET,
+ MOST_BLEND_SET,
+ MOST_BLEND_GET,
+ DEMPH_MODE_SET,
+ DEMPH_MODE_GET,
+ SEARCH_LVL_SET,
+ SEARCH_LVL_GET,
+ RX_BAND_SET,
+ RX_BAND_GET,
+ MUTE_STATUS_SET,
+ MUTE_STATUS_GET,
+ RDS_PAUSE_LVL_SET,
+ RDS_PAUSE_LVL_GET,
+ RDS_PAUSE_DUR_SET,
+ RDS_PAUSE_DUR_GET,
+ RDS_MEM_SET,
+ RDS_MEM_GET,
+ RDS_BLK_B_SET,
+ RDS_BLK_B_GET,
+ RDS_MSK_B_SET,
+ RDS_MSK_B_GET,
+ RDS_PI_MASK_SET,
+ RDS_PI_MASK_GET,
+ RDS_PI_SET,
+ RDS_PI_GET,
+ RDS_SYSTEM_SET,
+ RDS_SYSTEM_GET,
+ INT_MASK_SET,
+ INT_MASK_GET,
+ SEARCH_DIR_SET,
+ SEARCH_DIR_GET,
+ VOLUME_SET,
+ VOLUME_GET,
+ AUDIO_ENABLE_SET,
+ AUDIO_ENABLE_GET,
+ PCM_MODE_SET,
+ PCM_MODE_GET,
+ I2S_MODE_CONFIG_SET,
+ I2S_MODE_CONFIG_GET,
+ POWER_SET,
+ POWER_GET,
+ INTx_CONFIG_SET,
+ INTx_CONFIG_GET,
+ PULL_EN_SET,
+ PULL_EN_GET,
+ HILO_SET,
+ HILO_GET,
+ SWITCH2FREF,
+ FREQ_DRIFT_REPORT,
+ PCE_GET,
+ FIRM_VER_GET,
+ ASIC_VER_GET,
+ ASIC_ID_GET,
+ MAIN_ID_GET,
+ TUNER_MODE_SET,
+ STOP_SEARCH,
+ RDS_CNTRL_SET,
+ WRITE_HARDWARE_REG,
+ CODE_DOWNLOAD,
+ RESET,
+ FM_POWER_MODE,
+ FM_INTERRUPT,
+
+ /* FM TX registers */
+ CHANL_SET,
+ CHANL_GET,
+ CHANL_BW_SET,
+ CHANL_BW_GET,
+ REF_SET,
+ REF_GET,
+ POWER_ENB_SET,
+ POWER_ATT_SET,
+ POWER_ATT_GET,
+ POWER_LEL_SET,
+ POWER_LEL_GET,
+ AUDIO_DEV_SET,
+ AUDIO_DEV_GET,
+ PILOT_DEV_SET,
+ PILOT_DEV_GET,
+ RDS_DEV_SET,
+ RDS_DEV_GET,
+ PUPD_SET,
+ AUDIO_IO_SET,
+ PREMPH_SET,
+ PREMPH_GET,
+ TX_BAND_SET,
+ TX_BAND_GET,
+ MONO_SET,
+ MONO_GET,
+ MUTE,
+ MPX_LMT_ENABLE,
+ LOCK_GET,
+ REF_ERR_SET,
+ PI_SET,
+ PI_GET,
+ TYPE_SET,
+ TYPE_GET,
+ PTY_SET,
+ PTY_GET,
+ AF_SET,
+ AF_GET,
+ DISPLAY_SIZE_SET,
+ DISPLAY_SIZE_GET,
+ RDS_MODE_SET,
+ RDS_MODE_GET,
+ DISPLAY_MODE_SET,
+ DISPLAY_MODE_GET,
+ LENGHT_SET,
+ LENGHT_GET,
+ TOGGLE_AB_SET,
+ TOGGLE_AB_GET,
+ RDS_REP_SET,
+ RDS_REP_GET,
+ RDS_DATA_SET,
+ RDS_DATA_ENB,
+ TA_SET,
+ TA_GET,
+ TP_SET,
+ TP_GET,
+ DI_SET,
+ DI_GET,
+ MS_SET,
+ MS_GET,
+ PS_SCROLL_SPEED_SET,
+ PS_SCROLL_SPEED_GET,
+
+ FM_REG_MAX_ENTRIES
+};
+
+/* SKB helpers */
+struct fm_skb_cb {
+ __u8 fm_opcode;
+ struct completion *completion;
+};
+
+#define fm_cb(skb) ((struct fm_skb_cb *)(skb->cb))
+
+/* FM Channel-8 command message format */
+struct fm_cmd_msg_hdr {
+ __u8 header; /* Logical Channel-8 */
+ __u8 len; /* Number of bytes follows */
+ __u8 fm_opcode; /* FM Opcode */
+ __u8 rd_wr; /* Read/Write command */
+ __u8 dlen; /* Length of payload */
+} __attribute__ ((packed));
+
+#define FM_CMD_MSG_HDR_SIZE 5 /* sizeof(struct fm_cmd_msg_hdr) */
+
+/* FM Channel-8 event messgage format */
+struct fm_event_msg_hdr {
+ __u8 header; /* Logical Channel-8 */
+ __u8 len; /* Number of bytes follows */
+ __u8 status; /* Event status */
+ __u8 num_fm_hci_cmds; /* Number of pkts the host allowed to send */
+ __u8 fm_opcode; /* FM Opcode */
+ __u8 rd_wr; /* Read/Write command */
+ __u8 dlen; /* Length of payload */
+} __attribute__ ((packed));
+
+#define FM_EVT_MSG_HDR_SIZE 7 /* sizeof(struct fm_event_msg_hdr) */
+
+/* TI's magic number in firmware file */
+#define FM_FW_FILE_HEADER_MAGIC 0x42535442
+
+/* Firmware header */
+struct bts_header {
+ uint32_t magic;
+ uint32_t version;
+ uint8_t future[24];
+ uint8_t actions[0];
+} __attribute__ ((packed));
+
+/* Firmware action */
+struct bts_action {
+ uint16_t type;
+ uint16_t size;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+/* Firmware delay */
+struct bts_action_delay {
+ uint32_t msec;
+} __attribute__ ((packed));
+
+#define ACTION_SEND_COMMAND 1
+#define ACTION_WAIT_EVENT 2
+#define ACTION_SERIAL 3
+#define ACTION_DELAY 4
+#define ACTION_REMARKS 6
+
+/* Converts little endian to big endian */
+#define FM_STORE_LE16_TO_BE16(data, value) \
+ (data = ((value >> 8) | ((value & 0xFF) << 8)))
+#define FM_LE16_TO_BE16(value) (((value >> 8) | ((value & 0xFF) << 8)))
+
+/* Converts big endian to little endian */
+#define FM_STORE_BE16_TO_LE16(data, value) \
+ (data = ((value & 0xFF) << 8) | ((value >> 8)))
+#define FM_BE16_TO_LE16(value) (((value & 0xFF) << 8) | ((value >> 8)))
+
+#define FM_ENABLE 1
+#define FM_DISABLE 0
+
+/* FLAG_GET register bits */
+#define FM_FR_EVENT (1 << 0)
+#define FM_BL_EVENT (1 << 1)
+#define FM_RDS_EVENT (1 << 2)
+#define FM_BBLK_EVENT (1 << 3)
+#define FM_LSYNC_EVENT (1 << 4)
+#define FM_LEV_EVENT (1 << 5)
+#define FM_IFFR_EVENT (1 << 6)
+#define FM_PI_EVENT (1 << 7)
+#define FM_PD_EVENT (1 << 8)
+#define FM_STIC_EVENT (1 << 9)
+#define FM_MAL_EVENT (1 << 10)
+#define FM_POW_ENB_EVENT (1 << 11)
+
+/* Firmware files of the FM, ASIC ID and
+ * ASIC version will be appened to this later
+ */
+#define FM_FMC_FW_FILE_START ("fmc_ch8")
+#define FM_RX_FW_FILE_START ("fm_rx_ch8")
+#define FM_TX_FW_FILE_START ("fm_tx_ch8")
+
+#define FM_CHECK_SEND_CMD_STATUS(ret) \
+ if (ret < 0) {\
+ FMDRV_API_EXIT(ret);\
+ return ret;\
+ }
+#define FM_UNDEFINED_FREQ 0xFFFFFFFF
+
+/* Band types */
+#define FM_BAND_EUROPE_US 0
+#define FM_BAND_JAPAN 1
+
+/* Seek directions */
+#define FM_SEARCH_DIRECTION_DOWN 0
+#define FM_SEARCH_DIRECTION_UP 1
+
+/* Tunner modes */
+#define FM_TUNER_STOP_SEARCH_MODE 0
+#define FM_TUNER_PRESET_MODE 1
+#define FM_TUNER_AUTONOMOUS_SEARCH_MODE 2
+#define FM_TUNER_AF_JUMP_MODE 3
+
+/* Min and Max volume */
+#define FM_RX_VOLUME_MIN 0
+#define FM_RX_VOLUME_MAX 70
+
+/* Volume gain step */
+#define FM_RX_VOLUME_GAIN_STEP 0x370
+
+/* Mute modes */
+#define FM_MUTE_ON 0
+#define FM_MUTE_OFF 1
+#define FM_MUTE_ATTENUATE 2
+
+#define FM_RX_MUTE_UNMUTE_MODE 0x00
+#define FM_RX_MUTE_RF_DEP_MODE 0x01
+#define FM_RX_MUTE_AC_MUTE_MODE 0x02
+#define FM_RX_MUTE_HARD_MUTE_LEFT_MODE 0x04
+#define FM_RX_MUTE_HARD_MUTE_RIGHT_MODE 0x08
+#define FM_RX_MUTE_SOFT_MUTE_FORCE_MODE 0x10
+
+/* RF dependent mute mode */
+#define FM_RX_RF_DEPENDENT_MUTE_ON 1
+#define FM_RX_RF_DEPENDENT_MUTE_OFF 0
+
+/* RSSI threshold min and max */
+#define FM_RX_RSSI_THRESHOLD_MIN -128
+#define FM_RX_RSSI_THRESHOLD_MAX 127
+
+/* Stereo/Mono mode */
+#define FM_STEREO_MODE 0
+#define FM_MONO_MODE 1
+#define FM_STEREO_SOFT_BLEND 1
+
+/* FM RX De-emphasis filter modes */
+#define FM_RX_EMPHASIS_FILTER_50_USEC 0
+#define FM_RX_EMPHASIS_FILTER_75_USEC 1
+
+/* FM RX RDS modes */
+#define FM_RX_RDS_DISABLE 0
+#define FM_RX_RDS_ENABLE 1
+
+#define FM_NO_PI_CODE 0
+
+/* FM and RX RDS block enable/disable */
+#define FM_RX_POWER_SET_FM_ON_RDS_OFF 0x1
+#define FM_RX_POWET_SET_FM_AND_RDS_BLK_ON 0x3
+#define FM_RX_POWET_SET_FM_AND_RDS_BLK_OFF 0x0
+
+/* RX RDS */
+#define FM_RX_RDS_FLUSH_FIFO 0x1
+#define FM_RX_RDS_FIFO_THRESHOLD 64 /* tuples */
+#define FM_RDS_BLOCK_SIZE 3 /* 3 bytes */
+
+/* RDS block types */
+#define FM_RDS_BLOCK_A 0
+#define FM_RDS_BLOCK_B 1
+#define FM_RDS_BLOCK_C 2
+#define FM_RDS_BLOCK_Ctag 3
+#define FM_RDS_BLOCK_D 4
+#define FM_RDS_BLOCK_E 5
+
+#define FM_RDS_BLOCK_INDEX_A 0
+#define FM_RDS_BLOCK_INDEX_B 1
+#define FM_RDS_BLOCK_INDEX_C 2
+#define FM_RDS_BLOCK_INDEX_D 3
+#define FM_RDS_BLOCK_INDEX_UNKNOWN 0xF0
+
+#define FM_RDS_STATUS_ERROR_MASK 0x18
+
+/* Represents an RDS group type & version.
+ * There are 15 groups, each group has 2
+ * versions: A and B.
+ */
+#define FM_RDS_GROUP_TYPE_MASK_0A ((unsigned long)1<<0)
+#define FM_RDS_GROUP_TYPE_MASK_0B ((unsigned long)1<<1)
+#define FM_RDS_GROUP_TYPE_MASK_1A ((unsigned long)1<<2)
+#define FM_RDS_GROUP_TYPE_MASK_1B ((unsigned long)1<<3)
+#define FM_RDS_GROUP_TYPE_MASK_2A ((unsigned long)1<<4)
+#define FM_RDS_GROUP_TYPE_MASK_2B ((unsigned long)1<<5)
+#define FM_RDS_GROUP_TYPE_MASK_3A ((unsigned long)1<<6)
+#define FM_RDS_GROUP_TYPE_MASK_3B ((unsigned long)1<<7)
+#define FM_RDS_GROUP_TYPE_MASK_4A ((unsigned long)1<<8)
+#define FM_RDS_GROUP_TYPE_MASK_4B ((unsigned long)1<<9)
+#define FM_RDS_GROUP_TYPE_MASK_5A ((unsigned long)1<<10)
+#define FM_RDS_GROUP_TYPE_MASK_5B ((unsigned long)1<<11)
+#define FM_RDS_GROUP_TYPE_MASK_6A ((unsigned long)1<<12)
+#define FM_RDS_GROUP_TYPE_MASK_6B ((unsigned long)1<<13)
+#define FM_RDS_GROUP_TYPE_MASK_7A ((unsigned long)1<<14)
+#define FM_RDS_GROUP_TYPE_MASK_7B ((unsigned long)1<<15)
+#define FM_RDS_GROUP_TYPE_MASK_8A ((unsigned long)1<<16)
+#define FM_RDS_GROUP_TYPE_MASK_8B ((unsigned long)1<<17)
+#define FM_RDS_GROUP_TYPE_MASK_9A ((unsigned long)1<<18)
+#define FM_RDS_GROUP_TYPE_MASK_9B ((unsigned long)1<<19)
+#define FM_RDS_GROUP_TYPE_MASK_10A ((unsigned long)1<<20)
+#define FM_RDS_GROUP_TYPE_MASK_10B ((unsigned long)1<<21)
+#define FM_RDS_GROUP_TYPE_MASK_11A ((unsigned long)1<<22)
+#define FM_RDS_GROUP_TYPE_MASK_11B ((unsigned long)1<<23)
+#define FM_RDS_GROUP_TYPE_MASK_12A ((unsigned long)1<<24)
+#define FM_RDS_GROUP_TYPE_MASK_12B ((unsigned long)1<<25)
+#define FM_RDS_GROUP_TYPE_MASK_13A ((unsigned long)1<<26)
+#define FM_RDS_GROUP_TYPE_MASK_13B ((unsigned long)1<<27)
+#define FM_RDS_GROUP_TYPE_MASK_14A ((unsigned long)1<<28)
+#define FM_RDS_GROUP_TYPE_MASK_14B ((unsigned long)1<<29)
+#define FM_RDS_GROUP_TYPE_MASK_15A ((unsigned long)1<<30)
+#define FM_RDS_GROUP_TYPE_MASK_15B ((unsigned long)1<<31)
+
+/* RX Alternate Frequency info */
+#define FM_RDS_MIN_AF 1
+#define FM_RDS_MAX_AF 204
+#define FM_RDS_MAX_AF_JAPAN 140
+#define FM_RDS_1_AF_FOLLOWS 225
+#define FM_RDS_25_AF_FOLLOWS 249
+
+/* RDS system type (RDS/RBDS) */
+#define FM_RDS_SYSTEM_RDS 0
+#define FM_RDS_SYSTEM_RBDS 1
+
+/* AF on/off */
+#define FM_RX_RDS_AF_SWITCH_MODE_ON 1
+#define FM_RX_RDS_AF_SWITCH_MODE_OFF 0
+
+/* Retry count when interrupt process goes wrong */
+#define FM_IRQ_TIMEOUT_RETRY_MAX 5 /* 5 times */
+
+/* Audio IO set values */
+#define FM_RX_FM_AUDIO_ENABLE_I2S 0x01
+#define FM_RX_FM_AUDIO_ENABLE_ANALOG 0x02
+#define FM_RX_FM_AUDIO_ENABLE_I2S_AND_ANALOG 0x03
+#define FM_RX_FM_AUDIO_ENABLE_DISABLE 0x00
+
+/* HI/LO set values */
+#define FM_RX_IFFREQ_TO_HI_SIDE 0x0
+#define FM_RX_IFFREQ_TO_LO_SIDE 0x1
+#define FM_RX_IFFREQ_HILO_AUTOMATIC 0x2
+
+/* Default RX mode configuration. Chip will be configured
+ * with this default values after loading RX firmware.
+ */
+#define FM_DEFAULT_RX_VOLUME 10
+#define FM_DEFAULT_RSSI_THRESHOLD 3
+
+/* Functions exported to FM V4L2 layer */
+int fm_core_prepare(void);
+int fm_core_release(void);
+int fm_core_setup_transport(void);
+int fm_core_release_transport(void);
+int fm_core_is_rds_data_available(struct file *, struct poll_table_struct *);
+int fm_core_transfer_rds_from_internal_buff(struct file *,
+ char __user *, size_t);
+int fm_core_set_frequency(unsigned int);
+int fm_core_get_frequency(unsigned int *);
+int fm_core_rx_get_rssi_level(unsigned short *);
+int fm_core_rx_seek(unsigned int, unsigned int);
+int fm_core_rx_set_volume(unsigned short);
+int fm_core_rx_get_volume(unsigned short *);
+int fm_core_region_get(unsigned char *);
+int fm_core_region_set(unsigned char);
+int fm_core_rx_get_currband_lowhigh_freq(unsigned int *, unsigned int *);
+int fm_core_rx_get_mute_mode(unsigned char *);
+int fm_core_set_mute_mode(unsigned char);
+int fm_core_rx_get_rfdepend_softmute(unsigned char *);
+int fm_core_rx_set_rfdepend_softmute(unsigned char);
+int fm_core_rx_set_rssi_threshold(short);
+int fm_core_rx_get_rssi_threshold(short *);
+int fm_core_set_stereo_mono(unsigned short);
+int fm_core_rx_get_stereo_mono(unsigned short *);
+int fm_core_rx_set_deemphasis_mode(unsigned short);
+int fm_core_rx_get_deemphasis_mode(unsigned short *);
+int fm_core_rx_get_rds_mode(unsigned char *);
+int fm_core_set_rds_mode(unsigned char);
+int fm_core_rx_set_rds_system(unsigned char);
+int fm_core_rx_get_rds_system(unsigned char *);
+int fm_core_rx_set_af_switch(unsigned char);
+int fm_core_rx_get_af_switch(unsigned char *);
+
+int fm_core_mode_set(unsigned char);
+int fm_core_mode_get(unsigned char *);
+
+int fm_core_tx_set_pwr_lvl(unsigned char new_pwr_lvl);
+int fm_core_tx_set_radio_text(unsigned char *, unsigned char);
+int fm_core_tx_set_af(unsigned int);
+#endif
diff --git a/drivers/misc/ti-st/fmdrv_mixer.c b/drivers/misc/ti-st/fmdrv_mixer.c
new file mode 100644
index 0000000..1427853
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_mixer.c
@@ -0,0 +1,725 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * This file manages FM driver's ALSA mixer controls.
+ *
+ * The standard V4L2 subsystem provides limited V4L2 IOCTLs
+ * to perform FM operation. So, this module will expose
+ * some of mixer controls (ex., Band Selection,
+ * FM TX/RX Mode Switch, etc) via ALSA to user space.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <linux/version.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "fmdrv.h"
+#include "fmdrv_mixer.h"
+#include "fmdrv_core.h"
+
+static int fm_mixer_mode_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *fm_modes[] = { "Off", "Tx", "Rx" };
+
+ FMDRV_API_START();
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+ if (uinfo->value.enumerated.item > 2)
+ uinfo->value.enumerated.item = 2;
+ strcpy(uinfo->value.enumerated.name,
+ fm_modes[uinfo->value.enumerated.item]);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret;
+ unsigned char current_fmmode;
+
+ FMDRV_API_START();
+ ret = fm_core_mode_get(¤t_fmmode);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ ucontrol->value.enumerated.item[0] = current_fmmode & 3;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int changed;
+ unsigned char mode;
+ int ret;
+
+ FMDRV_API_START();
+
+ mode = ucontrol->value.integer.value[0] & 3;
+ ret = fm_core_mode_set(mode);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ changed = 1;
+
+ FMDRV_API_EXIT(changed);
+ return changed;
+}
+
+static int fm_mixer_region_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *region[] = { "Europe/US", "Japan" };
+
+ FMDRV_API_START();
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name,
+ region[uinfo->value.enumerated.item]);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_region_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned char region;
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_region_get(®ion);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ ucontrol->value.enumerated.item[0] = region & 0x1;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_region_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret;
+ unsigned char region;
+ int changed;
+
+ FMDRV_API_START();
+
+ region = ucontrol->value.integer.value[0] & 0x1;
+ ret = fm_core_region_set(region);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ changed = 1;
+
+ FMDRV_API_EXIT(changed);
+ return changed;
+}
+
+static int fm_mixer_rfdepend_mute_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *region[] = { "Off", "On" };
+
+ FMDRV_API_START();
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name,
+ region[uinfo->value.enumerated.item]);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rfdepend_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned char en_dis;
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = fm_core_rx_get_rfdepend_softmute(&en_dis);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ ucontrol->value.enumerated.item[0] = en_dis & 0x1;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rfdepend_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned char en_dis;
+ int changed, ret;
+
+ FMDRV_API_START();
+
+ en_dis = ucontrol->value.integer.value[0] & 0x1;
+ ret = fm_core_rx_set_rfdepend_softmute(en_dis);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ changed = 1;
+
+ FMDRV_API_EXIT(changed);
+ return changed;
+}
+
+static int fm_mixer_rssi_level_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ FMDRV_API_START();
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = -16;
+ uinfo->value.integer.max = 15;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rssi_level_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned short curr_rssi_lvl;
+ int ret;
+ FMDRV_API_START();
+
+ ret = fm_core_rx_get_rssi_level(&curr_rssi_lvl);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[0] = curr_rssi_lvl;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rx_rssi_threshold_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ FMDRV_API_START();
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = -16;
+ uinfo->value.integer.max = 15;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rx_rssi_threshold_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ short curr_rssi_threshold;
+ int ret;
+ FMDRV_API_START();
+
+ ret = fm_core_rx_get_rssi_threshold(&curr_rssi_threshold);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ ucontrol->value.integer.value[0] = curr_rssi_threshold;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rx_rssi_threshold_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ short rssi_threshold_toset;
+ int changed, ret;
+
+ FMDRV_API_START();
+
+ rssi_threshold_toset = ucontrol->value.integer.value[0];
+ ret = fm_core_rx_set_rssi_threshold(rssi_threshold_toset);
+ if (ret)
+ return ret;
+
+ changed = 1;
+
+ FMDRV_API_EXIT(changed);
+ return changed;
+}
+
+static int fm_mixer_stereo_mono_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *modes[] = { "Stereo", "Mono" };
+
+ FMDRV_API_START();
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name,
+ modes[uinfo->value.enumerated.item]);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_stereo_mono_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned short mode;
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = fm_core_rx_get_stereo_mono(&mode);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ ucontrol->value.enumerated.item[0] = mode & 0x1;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_stereo_mono_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret;
+ unsigned short mode;
+ int changed;
+
+ FMDRV_API_START();
+
+ mode = ucontrol->value.integer.value[0] & 0x1;
+ ret = fm_core_set_stereo_mono(mode);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ changed = 1;
+
+ FMDRV_API_EXIT(changed);
+ return changed;
+}
+
+static int fm_mixer_rx_deemphasis_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *filter_mode[] = { "50 us", "75 us" };
+
+ FMDRV_API_START();
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name,
+ filter_mode[uinfo->value.enumerated.item]);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rx_deemphasis_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned short mode;
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_rx_get_deemphasis_mode(&mode);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ ucontrol->value.enumerated.item[0] = mode & 0x1;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rx_deemphasis_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret;
+ unsigned short mode;
+ int changed;
+
+ FMDRV_API_START();
+
+ mode = ucontrol->value.integer.value[0] & 0x1;
+ ret = fm_core_rx_set_deemphasis_mode(mode);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ changed = 1;
+
+ FMDRV_API_EXIT(changed);
+ return changed;
+}
+
+static int fm_mixer_rx_rds_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *rds_mode[] = { "Off", "On" };
+
+ FMDRV_API_START();
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name,
+ rds_mode[uinfo->value.enumerated.item]);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rx_rds_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned char rds_onoff;
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_rx_get_rds_mode(&rds_onoff);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ ucontrol->value.enumerated.item[0] = rds_onoff & 0x1;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rx_rds_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret;
+ unsigned char rds_onoff;
+ int changed;
+
+ FMDRV_API_START();
+
+ rds_onoff = ucontrol->value.integer.value[0] & 0x1;
+ ret = fm_core_set_rds_mode(rds_onoff);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ changed = 1;
+
+ FMDRV_API_EXIT(changed);
+ return changed;
+}
+
+static int fm_mixer_rx_rds_opmode_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *rds_mode[] = { "RDS", "RDBS" };
+
+ FMDRV_API_START();
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name,
+ rds_mode[uinfo->value.enumerated.item]);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rx_rds_opmode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned char rds_mode;
+ int ret;
+
+ FMDRV_API_START();
+ ret = fm_core_rx_get_rds_system(&rds_mode);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ ucontrol->value.enumerated.item[0] = rds_mode & 0x1;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rx_rds_opmode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret;
+ unsigned char rds_mode;
+ int changed;
+
+ FMDRV_API_START();
+
+ rds_mode = ucontrol->value.integer.value[0] & 0x1;
+ ret = fm_core_rx_set_rds_system(rds_mode);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ changed = 1;
+
+ FMDRV_API_EXIT(changed);
+ return changed;
+}
+
+static int fm_mixer_rx_af_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *af_mode[] = { "Off", "On" };
+
+ FMDRV_API_START();
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name,
+ af_mode[uinfo->value.enumerated.item]);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rx_af_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned char af_mode;
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = fm_core_rx_get_af_switch(&af_mode);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ ucontrol->value.enumerated.item[0] = af_mode & 0x1;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static int fm_mixer_rx_af_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned char af_mode;
+ int changed, ret;
+
+ FMDRV_API_START();
+
+ af_mode = ucontrol->value.integer.value[0] & 0x1;
+ ret = fm_core_rx_set_af_switch(af_mode);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ changed = 1;
+
+ FMDRV_API_EXIT(changed);
+ return changed;
+}
+
+static struct snd_kcontrol_new snd_fm_controls[] = {
+ {
+ .name = "Mode Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fm_mixer_mode_info,
+ .get = fm_mixer_mode_get,
+ .put = fm_mixer_mode_put,
+ },
+ {
+ .name = "Region Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fm_mixer_region_info,
+ .get = fm_mixer_region_get,
+ .put = fm_mixer_region_put,
+ },
+ {
+ .name = "RF Dependent Mute",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fm_mixer_rfdepend_mute_info,
+ .get = fm_mixer_rfdepend_mute_get,
+ .put = fm_mixer_rfdepend_mute_put,
+ },
+ {
+ .name = "RSSI Level",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .info = fm_mixer_rssi_level_info,
+ .get = fm_mixer_rssi_level_get,
+ },
+ {
+ .name = "RSSI Threshold",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fm_mixer_rx_rssi_threshold_info,
+ .get = fm_mixer_rx_rssi_threshold_get,
+ .put = fm_mixer_rx_rssi_threshold_put,
+ },
+ {
+ .name = "Stereo/Mono",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fm_mixer_stereo_mono_info,
+ .get = fm_mixer_stereo_mono_get,
+ .put = fm_mixer_stereo_mono_put,
+ },
+ {
+ .name = "De-emphasis Filter",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fm_mixer_rx_deemphasis_info,
+ .get = fm_mixer_rx_deemphasis_get,
+ .put = fm_mixer_rx_deemphasis_put,
+ },
+ {
+ .name = "RDS Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fm_mixer_rx_rds_switch_info,
+ .get = fm_mixer_rx_rds_switch_get,
+ .put = fm_mixer_rx_rds_switch_put,
+ },
+ {
+ .name = "RDS Operation Mode",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fm_mixer_rx_rds_opmode_info,
+ .get = fm_mixer_rx_rds_opmode_get,
+ .put = fm_mixer_rx_rds_opmode_put,
+ },
+ {
+ .name = "AF Switch",
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fm_mixer_rx_af_switch_info,
+ .get = fm_mixer_rx_af_switch_get,
+ .put = fm_mixer_rx_af_switch_put,
+ },
+};
+
+int fm_mixer_init(struct fmdrv_ops *fmdev)
+{
+ int idx;
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Allocate new card for FM driver */
+ fmdev->card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0);
+ if (!fmdev->card) {
+ FM_DRV_ERR("No memory to allocate new card");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ fmdev->card->private_data = fmdev;
+
+ /* Add FM mixer controls to the card */
+ strcpy(fmdev->card->mixername, FM_DRV_MIXER_NAME);
+ for (idx = 0; idx < ARRAY_SIZE(snd_fm_controls); idx++) {
+ ret = snd_ctl_add(fmdev->card,
+ snd_ctl_new1(&snd_fm_controls[idx], fmdev));
+ if (ret < 0) {
+ snd_card_free(fmdev->card);
+ FM_DRV_ERR("Failed to add mixer controls");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ }
+
+ /* Register FM card with ALSA */
+ ret = snd_card_register(fmdev->card);
+ if (ret) {
+ snd_card_free(fmdev->card);
+ FM_DRV_ERR("Failed to register new card");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ strcpy(fmdev->card->driver, FM_DRV_NAME);
+ strcpy(fmdev->card->shortname, FM_DRV_CARD_SHORT_NAME);
+ sprintf(fmdev->card->longname, FM_DRV_CARD_LONG_NAME);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_mixer_deinit(struct fmdrv_ops *fmdev)
+{
+ FMDRV_API_START();
+
+ /* Unregister FM card from ALSA */
+ snd_card_free(fmdev->card);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
diff --git a/drivers/misc/ti-st/fmdrv_mixer.h b/drivers/misc/ti-st/fmdrv_mixer.h
new file mode 100644
index 0000000..92dcadf
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_mixer.h
@@ -0,0 +1,30 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _FM_MIXER_H
+#define _FM_MIXER_H
+
+/* FM mixer name */
+#define FM_DRV_MIXER_NAME "tifm_mixer"
+
+int fm_mixer_init(struct fmdrv_ops *fmdev);
+int fm_mixer_deinit(struct fmdrv_ops *fmdev);
+
+#endif
diff --git a/drivers/misc/ti-st/fmdrv_st.c b/drivers/misc/ti-st/fmdrv_st.c
new file mode 100644
index 0000000..383a1e4
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_st.c
@@ -0,0 +1,320 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * This file provide interfaces to Shared Transport.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+
+#include "st.h"
+#include "fmdrv.h"
+#include "fmdrv_st.h"
+
+static char streg_cbdata;
+
+/* Wait on comepletion handler needed to synchronize
+ * fm_st_register() and fm_st_registration_completion_cb()
+ * functions.
+ */
+static struct completion wait_for_fmdrv_reg_completion;
+
+/* Write function pointer of ST driver */
+long (*g_st_write) (struct sk_buff *skb);
+
+/* RX Queue and RX Tasklet pointer */
+static struct sk_buff_head *g_rx_q;
+static struct tasklet_struct *g_rx_task;
+
+/* Flag to maintain whether FM ST is claimed or not */
+static char is_fm_st_claimed;
+
+/* Called from FM Core and FM Char device interface to claim
+ * FM ST. Who ever comes first, ownership of FM ST will be
+ * given to them.
+ */
+int fm_st_claim(void)
+{
+ FMDRV_API_START();
+
+ /* Give ownership of FM ST to first caller */
+ if (is_fm_st_claimed == FM_ST_NOT_CLAIMED) {
+ is_fm_st_claimed = FM_ST_CLAIMED;
+
+ FMDRV_API_EXIT(FM_ST_SUCCESS);
+ return FM_ST_SUCCESS;
+ }
+
+ FM_DRV_DBG("FM ST claimed already");
+
+ FMDRV_API_EXIT(FM_ST_FAILED);
+ return FM_ST_FAILED;
+}
+
+/* Called from FM Core and FM Char device interface
+ * to release FM ST.
+ */
+int fm_st_release(void)
+{
+ FMDRV_API_START();
+
+ /* Release FM ST if it is already claimed */
+ if (is_fm_st_claimed == FM_ST_CLAIMED) {
+ is_fm_st_claimed = FM_ST_NOT_CLAIMED;
+
+ FMDRV_API_EXIT(FM_ST_SUCCESS);
+ return FM_ST_SUCCESS;
+
+ }
+
+ FM_DRV_ERR("FM ST is not claimed,called again?");
+
+ FMDRV_API_EXIT(FM_ST_FAILED);
+ return FM_ST_FAILED;
+}
+
+/* Called by Shared Transport layer when FM packet is
+ * available
+ */
+static long fm_st_receive(struct sk_buff *skb)
+{
+ FMDRV_API_START();
+
+ if (skb == NULL) {
+ FM_DRV_ERR("Invalid SKB received from ST");
+ FMDRV_API_EXIT(-EFAULT);
+ return -EFAULT;
+ }
+
+ /* Is this FM Channel-8 packet? */
+ if (skb->cb[0] != FM_PKT_LOGICAL_CHAN_NUMBER) {
+ FM_DRV_ERR("Received SKB(%p) is not FM Channel 8 pkt", skb);
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+
+ /* One byte is already reserved for Channel-8 in skb,
+ * so prepend skb with Channel-8 packet type byte.
+ */
+ memcpy(skb_push(skb, 1), &skb->cb[0], 1);
+
+ if (g_rx_q != NULL && g_rx_task != NULL) {
+ /* Queue FM packet for FM RX task */
+ skb_queue_tail(g_rx_q, skb);
+ tasklet_schedule(g_rx_task);
+ } else {
+ FM_DRV_ERR
+ ("Invalid RX queue and RX tasklet pointer,puring skb");
+ kfree_skb(skb);
+ FMDRV_API_EXIT(-EFAULT);
+ return -EFAULT;
+ }
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Forwards FM Packets to Shared Transport */
+int fm_st_send(struct sk_buff *skb)
+{
+ long len;
+
+ FMDRV_API_START();
+
+ if (skb == NULL) {
+ FM_DRV_ERR("Invalid skb, can't send");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+
+ /* Is anyone called without claiming FM ST? */
+ if (is_fm_st_claimed == FM_ST_CLAIMED && g_st_write != NULL) {
+ /* Forward FM packet(SKB) to ST for the transmission */
+ len = g_st_write(skb);
+ if (len < 0) {
+ /* Something went wrong in st write , free skb memory */
+ kfree_skb(skb);
+ FM_DRV_ERR(" ST write failed (%ld)", len);
+ FMDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+ }
+ } else { /* Nobody calimed FM ST */
+
+ kfree_skb(skb);
+ FM_DRV_ERR("FM ST is not claimed, Can't send skb");
+ FMDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+ }
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Called by ST layer to indicate protocol registration completion
+ * status. fm_st_register() function will wait for signal from this
+ * API when st_register() function returns ST_PENDING.
+ */
+static void fm_st_registration_completion_cb(char data)
+{
+ FMDRV_API_START();
+
+ /* fm_st_register() function needs value of 'data' to know
+ * the registration status(success/fail). So, have a back
+ * up of it.
+ */
+ streg_cbdata = data;
+
+ /* Got a feedback from ST for FM driver registration
+ * request. Wackup fm_st_register() function to continue
+ * it's open operation.
+ */
+ complete(&wait_for_fmdrv_reg_completion);
+
+ FMDRV_API_EXIT(0);
+}
+
+/* Called from V4L2 RADIO open function (fm_fops_open()) to
+ * register FM driver with Shared Transport
+ */
+int fm_st_register(struct sk_buff_head *rx_q, struct tasklet_struct *rx_task)
+{
+ static struct st_proto_s fm_st_proto;
+ unsigned long timeleft;
+ int ret;
+
+ ret = 0;
+
+ FMDRV_API_START();
+
+ /* Populate FM driver info required by ST */
+ memset(&fm_st_proto, 0, sizeof(fm_st_proto));
+
+ /* FM driver ID */
+ fm_st_proto.type = ST_FM;
+
+ /* Receive function which called from ST */
+ fm_st_proto.recv = fm_st_receive;
+
+ /* Packet match function may used in future */
+ fm_st_proto.match_packet = NULL;
+
+ /* Callback to be called when registration is pending */
+ fm_st_proto.reg_complete_cb = fm_st_registration_completion_cb;
+
+ /* This is write function pointer of ST. BT driver will make use of this
+ * for sending any packets to chip. ST will assign and give to us, so
+ * make it as NULL
+ */
+ fm_st_proto.write = NULL;
+
+ /* Register with ST layer */
+ ret = st_register(&fm_st_proto);
+ if (ret == ST_ERR_PENDING) {
+ /* Prepare wait-for-completion handler data structures.
+ * Needed to syncronize this and
+ * fm_st_registration_completion_cb() functions.
+ */
+ init_completion(&wait_for_fmdrv_reg_completion);
+
+ /* Reset ST registration callback status flag. This value
+ * will be updated in fm_st_registration_completion_cb()
+ * function whenever it is called from ST driver.
+ */
+ streg_cbdata = -EINPROGRESS;
+
+ /* ST is busy with other protocol registration (may be busy with
+ * firmware download). So, wait till the registration callback
+ * (passed as a argument to st_register() function) getting
+ * called from ST.
+ */
+ FM_DRV_DBG(" %s waiting for reg completion signal from ST",
+ __func__);
+
+ timeleft =
+ wait_for_completion_timeout(&wait_for_fmdrv_reg_completion,
+ FM_ST_REGISTER_TIMEOUT);
+ if (!timeleft) {
+ FM_DRV_ERR("Timeout(%d sec), didn't get reg"
+ "completion signal from ST",
+ jiffies_to_msecs(FM_ST_REGISTER_TIMEOUT) /
+ 1000);
+ FMDRV_API_EXIT(-ETIMEDOUT);
+ return -ETIMEDOUT;
+ }
+
+ /* Is ST registration callback called with ERROR value? */
+ if (streg_cbdata != 0) {
+ FM_DRV_ERR("ST reg completion CB called with invalid"
+ "status %d", streg_cbdata);
+ FMDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+ }
+ ret = 0;
+ } else if (ret == ST_ERR_FAILURE) {
+ FM_DRV_ERR("st_register failed %d", ret);
+ FMDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+ }
+
+ /* Do we have proper ST write function? */
+ if (fm_st_proto.write != NULL) {
+ /* We need this pointer for sending any FM pkts */
+ g_st_write = fm_st_proto.write;
+ } else {
+ FM_DRV_ERR("Failed to get ST write func pointer");
+
+ /* Undo registration with ST */
+ ret = st_unregister(ST_FM);
+ if (ret < 0)
+ FM_DRV_ERR("st_unregister failed %d", ret);
+
+ FMDRV_API_EXIT(-EAGAIN);
+ return -EAGAIN;
+ }
+
+ /* Store Rx Q and Rx tasklet pointers. This pointers should
+ * already initialized by caller
+ */
+ g_rx_task = rx_task;
+ g_rx_q = rx_q;
+
+ FMDRV_API_EXIT(ret);
+ return ret;
+}
+
+/* Unregister FM Driver from Shared Transport */
+int fm_st_unregister(void)
+{
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Unregister FM Driver from ST */
+ ret = st_unregister(ST_FM);
+ if (ret != ST_SUCCESS) {
+ FM_DRV_ERR("st_unregister failed %d", ret);
+ FMDRV_API_EXIT(-EBUSY);
+ return -EBUSY;
+ }
+
+ g_rx_task = NULL;
+ g_rx_q = NULL;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
diff --git a/drivers/misc/ti-st/fmdrv_st.h b/drivers/misc/ti-st/fmdrv_st.h
new file mode 100644
index 0000000..86a4007
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_st.h
@@ -0,0 +1,50 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _FM_ST_H
+#define _FM_ST_H
+
+#include <linux/interrupt.h>
+
+/* Defines number of seconds to wait for reg completion
+ * callback getting called from ST (in case, registration
+ * with ST returns PENDING status)
+ */
+#define FM_ST_REGISTER_TIMEOUT msecs_to_jiffies(6000) /* 6 sec */
+
+#define FM_PKT_LOGICAL_CHAN_NUMBER 0x08 /* Logical channel 8 */
+
+/* Claim ownership of FM ST */
+int fm_st_claim(void);
+
+/* To release FM ST */
+int fm_st_release(void);
+
+/* Forwards FM Packets to Shared Transport */
+int fm_st_send(struct sk_buff *skb);
+
+/* Register with Shared Transport */
+int fm_st_register(struct sk_buff_head *rx_q,
+ struct tasklet_struct *rx_task);
+
+/* Unregister from Shared Transport */
+int fm_st_unregister(void);
+
+#endif
diff --git a/drivers/misc/ti-st/fmdrv_v4l2.c b/drivers/misc/ti-st/fmdrv_v4l2.c
new file mode 100644
index 0000000..3fcc0f0
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_v4l2.c
@@ -0,0 +1,581 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * This file provides interfaces to V4L2 subsystem.
+ *
+ * This module registers with V4L2 subsystem as Radio
+ * data system interface (/dev/radio). During the registration,
+ * it will expose two set of function pointers to V4L2 subsystem.
+ *
+ * 1) File operation related API (open, close, read, write, poll...etc).
+ * 2) Set of V4L2 IOCTL complaint API.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "fmdrv.h"
+#include "fmdrv_v4l2.h"
+#include "fmdrv_core.h"
+
+static unsigned char radio_disconnected;
+
+/* Query control */
+static struct v4l2_queryctrl fmdrv_v4l2_queryctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Volume",
+ .minimum = FM_RX_VOLUME_MIN,
+ .maximum = FM_RX_VOLUME_MAX,
+ .step = 1,
+ .default_value = FM_DEFAULT_RX_VOLUME,
+ },
+ {
+ .id = V4L2_CID_AUDIO_BALANCE,
+ .flags = V4L2_CTRL_FLAG_DISABLED,
+ },
+ {
+ .id = V4L2_CID_AUDIO_BASS,
+ .flags = V4L2_CTRL_FLAG_DISABLED,
+ },
+ {
+ .id = V4L2_CID_AUDIO_TREBLE,
+ .flags = V4L2_CTRL_FLAG_DISABLED,
+ },
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 2,
+ .step = 1,
+ .default_value = FM_MUTE_OFF,
+ },
+ {
+ .id = V4L2_CID_AUDIO_LOUDNESS,
+ .flags = V4L2_CTRL_FLAG_DISABLED,
+ },
+};
+
+/* -- V4L2 RADIO (/dev/radioX) device file operation interfaces --- */
+
+/* Read RDS data */
+static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned char rds_mode;
+ int ret, noof_bytes_copied;
+ FMDRV_API_START();
+
+ if (!radio_disconnected) {
+ FM_DRV_ERR("FM device is already disconnected\n");
+ FMDRV_API_EXIT(-EIO);
+ return -EIO;
+ }
+ /* Turn on RDS mode , if it is disabled */
+ ret = fm_core_rx_get_rds_mode(&rds_mode);
+ if (ret) {
+ FM_DRV_ERR("Unable to read current rds mode");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ if (rds_mode == FM_RX_RDS_DISABLE) {
+ ret = fm_core_set_rds_mode(FM_RX_RDS_ENABLE);
+ if (ret < 0) {
+ FM_DRV_ERR("Unable to enable rds mode");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ }
+ /* Copy RDS data from internal buffer to user buffer */
+ noof_bytes_copied =
+ fm_core_transfer_rds_from_internal_buff(file, buf, count);
+
+ FMDRV_API_EXIT(noof_bytes_copied);
+ return noof_bytes_copied;
+}
+
+/* Write RDS data */
+static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
+ size_t count, loff_t *ppos)
+{
+ struct tx_rds rds;
+ int ret;
+ FMDRV_API_START();
+
+ ret = copy_from_user(&rds, buf, sizeof(rds));
+ FM_DRV_DBG("(%d)type: %d, text %s, af %d",
+ ret, rds.text_type, rds.text, rds.af_freq);
+
+ fm_core_tx_set_radio_text(rds.text, rds.text_type);
+ fm_core_tx_set_af(rds.af_freq);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Poll RDS data */
+static unsigned int fm_v4l2_fops_poll(struct file *file,
+ struct poll_table_struct *pts)
+{
+ int ret;
+ FMDRV_API_START();
+
+ ret = fm_core_is_rds_data_available(file, pts);
+ if (!ret) {
+ FMDRV_API_EXIT(POLLIN | POLLRDNORM);
+ return POLLIN | POLLRDNORM;
+ }
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* File Open */
+static int fm_v4l2_fops_open(struct file *file)
+{
+ int ret;
+
+ FMDRV_API_START();
+
+ /* Don't allow multiple open */
+ if (radio_disconnected) {
+ FM_DRV_ERR("FM device is already opened\n");
+ FMDRV_API_EXIT(-EBUSY);
+ return -EBUSY;
+ }
+
+ /* Request FM Core to link with FM ST */
+ ret = fm_core_setup_transport();
+ if (ret) {
+ FM_DRV_ERR("Unable to setup FM Core transport");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ /* Initialize FM Core */
+ ret = fm_core_prepare();
+ if (ret) {
+ FM_DRV_ERR("Unable to prepare FM CORE");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ FM_DRV_DBG("Load FM RX firmware..");
+ /* By default load FM RX firmware */
+ ret = fm_core_mode_set(FM_MODE_RX);
+ if (ret) {
+ FM_DRV_ERR("Unable to load FM RX firmware");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ radio_disconnected = 1;
+ FM_DRV_DBG("FM CORE is ready");
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* File Release */
+static int fm_v4l2_fops_release(struct file *file)
+{
+ int ret;
+
+ FMDRV_API_START();
+
+ if (!radio_disconnected) {
+ FM_DRV_DBG("FM device already closed,close called again?");
+ FMDRV_API_EXIT(0);
+ return 0;
+ }
+
+ FM_DRV_DBG("Turning off..");
+ ret = fm_core_mode_set(FM_MODE_OFF);
+ if (ret) {
+ FM_DRV_ERR("Unable to turn off the chip");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ /* Request FM Core to unlink from ST driver */
+ ret = fm_core_release();
+ if (ret) {
+ FM_DRV_ERR("FM CORE release failed");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ /* Release FM Core transport */
+ ret = fm_core_release_transport();
+ if (ret) {
+ FM_DRV_ERR("Unable to setup FM Core transport");
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ radio_disconnected = 0;
+ FM_DRV_DBG("FM CORE released successfully");
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* V4L2 RADIO (/dev/radioX) device IOCTL interfaces */
+
+/* Query device capabilities */
+static int fm_v4l2_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *capability)
+{
+ FMDRV_API_START();
+
+ strlcpy(capability->driver, FM_DRV_NAME, sizeof(capability->driver));
+ strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME,
+ sizeof(capability->card));
+ sprintf(capability->bus_info, "UART");
+ capability->version = FM_DRV_RADIO_VERSION;
+ capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
+ V4L2_CAP_RADIO | V4L2_CAP_READWRITE | V4L2_CAP_AUDIO;
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Enumerate control items */
+static int fm_v4l2_vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int index;
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = -EINVAL;
+ if (qc->id < V4L2_CID_BASE) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ /* Search control ID and copy its properties */
+ for (index = 0; index < ARRAY_SIZE(fmdrv_v4l2_queryctrl); index++) {
+ if (qc->id && qc->id == fmdrv_v4l2_queryctrl[index].id) {
+ memcpy(qc, &(fmdrv_v4l2_queryctrl[index]), sizeof(*qc));
+ ret = 0;
+ break;
+ }
+ }
+ FMDRV_API_EXIT(ret);
+ return ret;
+}
+
+/* Get the value of a control */
+static int fm_v4l2_vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret;
+ unsigned short curr_vol;
+ unsigned char curr_mute_mode;
+
+ FMDRV_API_START();
+
+ switch (ctrl->id) {
+
+ case V4L2_CID_AUDIO_MUTE: /* get mute mode */
+ ret = fm_core_rx_get_mute_mode(&curr_mute_mode);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ ctrl->value = curr_mute_mode;
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME: /* get volume */
+ ret = fm_core_rx_get_volume(&curr_vol);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ ctrl->value = curr_vol;
+ break;
+ }
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Set the value of a control */
+static int fm_v4l2_vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret;
+ FMDRV_API_START();
+
+ switch (ctrl->id) {
+
+ case V4L2_CID_AUDIO_MUTE: /* set mute */
+ ret = fm_core_set_mute_mode((unsigned char)ctrl->value);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME: /* set volume */
+ ret = fm_core_rx_set_volume((unsigned short)ctrl->value);
+ if (ret < 0) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ break;
+ }
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Get audio attributes */
+static int fm_v4l2_vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+{
+ FMDRV_API_START();
+
+ memset(audio, 0, sizeof(*audio));
+ audio->index = 0;
+ strcpy(audio->name, "Radio");
+ audio->capability = V4L2_AUDCAP_STEREO;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Set audio attributes */
+static int fm_v4l2_vidioc_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+{
+ FMDRV_API_START();
+
+ if (audio->index != 0) {
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Get tuner attributes */
+static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *tuner)
+{
+ unsigned int bottom_frequency;
+ unsigned int top_frequency;
+ unsigned short stereo_mono_mode;
+ unsigned short rssilvl;
+ int ret;
+
+ FMDRV_API_START();
+
+ if (tuner->index != 0) {
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ ret =
+ fm_core_rx_get_currband_lowhigh_freq(&bottom_frequency,
+ &top_frequency);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ ret = fm_core_rx_get_stereo_mono(&stereo_mono_mode);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ ret = fm_core_rx_get_rssi_level(&rssilvl);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ strcpy(tuner->name, "FM");
+ tuner->type = V4L2_TUNER_RADIO;
+ /* Store rangelow and rangehigh freq in unit of 62.5 KHz */
+ tuner->rangelow = (bottom_frequency * 10000) / 625;
+ tuner->rangehigh = (top_frequency * 10000) / 625;
+ tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
+ tuner->audmode = (stereo_mono_mode ?
+ V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO);
+
+ /* Actual rssi value lies in between -128 to +127.
+ * Convert this range from 0 to 255 by adding +128
+ */
+ rssilvl += 128;
+
+ /* Return signal strength value should be within 0 to 65535.
+ * Find out correct signal radio by multiplying (65535/255) = 257
+ */
+ tuner->signal = rssilvl * 257;
+ tuner->afc = 0;
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Set tuner attributes */
+static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *tuner)
+{
+ unsigned short mode;
+ int ret;
+
+ FMDRV_API_START();
+
+ if ((tuner->index != 0) ||
+ (tuner->audmode != V4L2_TUNER_MODE_MONO &&
+ tuner->audmode != V4L2_TUNER_MODE_STEREO)) {
+ FMDRV_API_EXIT(-EINVAL);
+ return -EINVAL;
+ }
+ /* Map V4L2 stereo/mono macro to our local stereo/mono macro */
+ mode = (tuner->audmode == V4L2_TUNER_MODE_STEREO) ?
+ FM_STEREO_MODE : FM_MONO_MODE;
+ ret = fm_core_set_stereo_mono(mode);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Get tuner or modulator radio frequency */
+static int fm_v4l2_vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ int ret;
+ FMDRV_API_START();
+
+ ret = fm_core_get_frequency(&freq->frequency);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Set tuner or modulator radio frequency */
+static int fm_v4l2_vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ int ret;
+ FMDRV_API_START();
+
+ ret = fm_core_set_frequency(freq->frequency);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+/* Set hardware frequency seek */
+static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv,
+ struct v4l2_hw_freq_seek *seek)
+{
+ int ret;
+
+ FMDRV_API_START();
+
+ ret = fm_core_rx_seek(seek->seek_upward, seek->wrap_around);
+ if (ret) {
+ FMDRV_API_EXIT(ret);
+ return ret;
+ }
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+static const struct v4l2_file_operations fm_drv_fops = {
+ .owner = THIS_MODULE,
+ .read = fm_v4l2_fops_read,
+ .write = fm_v4l2_fops_write,
+ .poll = fm_v4l2_fops_poll,
+ .ioctl = video_ioctl2,
+ .open = fm_v4l2_fops_open,
+ .release = fm_v4l2_fops_release,
+};
+
+static const struct v4l2_ioctl_ops fm_drv_ioctl_ops = {
+ .vidioc_querycap = fm_v4l2_vidioc_querycap,
+ .vidioc_queryctrl = fm_v4l2_vidioc_queryctrl,
+ .vidioc_g_ctrl = fm_v4l2_vidioc_g_ctrl,
+ .vidioc_s_ctrl = fm_v4l2_vidioc_s_ctrl,
+ .vidioc_g_audio = fm_v4l2_vidioc_g_audio,
+ .vidioc_s_audio = fm_v4l2_vidioc_s_audio,
+ .vidioc_g_tuner = fm_v4l2_vidioc_g_tuner,
+ .vidioc_s_tuner = fm_v4l2_vidioc_s_tuner,
+ .vidioc_g_frequency = fm_v4l2_vidioc_g_frequency,
+ .vidioc_s_frequency = fm_v4l2_vidioc_s_frequency,
+ .vidioc_s_hw_freq_seek = fm_v4l2_vidioc_s_hw_freq_seek,
+};
+
+/*
+ * V4L2 RADIO device parent structure
+ */
+static struct video_device fm_viddev_template = {
+ .fops = &fm_drv_fops,
+ .ioctl_ops = &fm_drv_ioctl_ops,
+ .name = FM_DRV_NAME,
+ .release = video_device_release,
+};
+
+int fm_v4l2_init_video_device(struct fmdrv_ops *fmdev)
+{
+ FMDRV_API_START();
+
+ /* Allocate new video device */
+ fmdev->v4l2dev = video_device_alloc();
+ if (!fmdev->v4l2dev) {
+ FM_DRV_ERR("Can't allocate video device");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+
+ /* Setup FM driver's V4L2 properties */
+ memcpy(fmdev->v4l2dev, &fm_viddev_template, sizeof(fm_viddev_template));
+
+ video_set_drvdata(fmdev->v4l2dev, fmdev);
+
+ /* Register with V4L2 subsystem as RADIO device */
+ if (video_register_device(fmdev->v4l2dev, VFL_TYPE_RADIO, 0)) {
+ video_device_release(fmdev->v4l2dev);
+ fmdev->v4l2dev = NULL;
+
+ FM_DRV_ERR("Could not register video device");
+ FMDRV_API_EXIT(-ENOMEM);
+ return -ENOMEM;
+ }
+ FMDRV_API_EXIT(0);
+ return 0;
+}
+
+int fm_v4l2_deinit_video_device(struct fmdrv_ops *fmdev)
+{
+ FMDRV_API_START();
+
+ /* Unregister RADIO device from V4L2 subsystem */
+ video_unregister_device(fmdev->v4l2dev);
+
+ FMDRV_API_EXIT(0);
+ return 0;
+}
diff --git a/drivers/misc/ti-st/fmdrv_v4l2.h b/drivers/misc/ti-st/fmdrv_v4l2.h
new file mode 100644
index 0000000..1345a58
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_v4l2.h
@@ -0,0 +1,32 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * FM V4L2 module header.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _FM_V4L2_DRV_H
+#define _FM_V4L2_DRV_H
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+int fm_v4l2_init_video_device(struct fmdrv_ops *fmdev);
+int fm_v4l2_deinit_video_device(struct fmdrv_ops *fmdev);
+
+#endif
diff --git a/drivers/misc/ti-st/gps_drv.c b/drivers/misc/ti-st/gps_drv.c
new file mode 100644
index 0000000..a5abe20
--- /dev/null
+++ b/drivers/misc/ti-st/gps_drv.c
@@ -0,0 +1,714 @@
+/*
+ * GPS Char Driver for Texas Instrument's Connectivity Chip.
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.,59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+
+#include "gps_drv.h"
+#include "st.h"
+
+#define DEVICE_NAME "tigps"
+
+/* Initialization TaskLet for performing GPS Write */
+DECLARE_TASKLET_DISABLED(gpsdrv_tx_tsklet, gpsdrv_tsklet_write, 0);
+
+/* Structure declerations for GPS char Driver Data */
+static struct gpsdrv_data *hgps;
+
+/***********Functions called from ST driver**********************************/
+
+/* gpsdrv_st_recv Function
+ * This is Called in from -- ST Core when a data is received
+ * This is a registered callback with ST core when the gps driver
+ * registers with ST.
+ * Parameters:
+ * @skb : SKB buffer pointer which contains the incoming Ch-9 GPS data.
+ * Returns:
+ * GPS_SUCCESS - On Success
+ * else suitable error code
+ */
+long gpsdrv_st_recv(struct sk_buff *skb)
+{
+ struct gpsdrv_event_hdr gpsdrv_hdr = { 0x00, 0x0000 };
+ GPSDRV_DBG(" Inside %s", __func__);
+
+ /* SKB is NULL */
+ if (NULL == skb) {
+ GPSDRV_ERR("Input SKB is NULL");
+ return GPS_ERR_FAILURE;
+ }
+
+ /* Sanity Check - To Check if the Rx Pkt is Channel -9 or not */
+ if (GPS_CH9_PKT_NUMBER != skb->cb[0]) {
+ GPSDRV_ERR("Input SKB is not a Channel-9 packet");
+ return GPS_ERR_FAILURE;
+ }
+ /* Copy Ch-9 info to local structure */
+ memcpy(&gpsdrv_hdr, skb->data, GPS_CH9_PKT_HDR_SIZE - 1);
+ skb_pull(skb, GPS_CH9_PKT_HDR_SIZE - 1);
+
+ /* check if skb->len and gpsdrv_hdr.plen are equal */
+ if (skb->len != gpsdrv_hdr.plen) {
+ GPSDRV_ERR("Received corrupted packet - Length Mismatch");
+ return -EINVAL;
+ }
+ /* Check the Opcode */
+ if ((gpsdrv_hdr.opcode != GPS_CH9_OP_READ) &&
+ (gpsdrv_hdr.opcode != GPS_CH9_OP_COMPLETED_EVT)) {
+ GPSDRV_ERR("Received corrupted packet - Wrong opcode %x ",
+ gpsdrv_hdr.opcode);
+ return -EINVAL;
+ }
+ /* Strip Channel 9 packet information from SKB only
+ * if the opcode is GPS_CH9_OP_READ and get AI2 packet
+ */
+ if (GPS_CH9_OP_READ == gpsdrv_hdr.opcode) {
+ spin_lock(&hgps->lock);
+ skb_queue_tail(&hgps->rx_list, skb);
+ spin_unlock(&hgps->lock);
+ wake_up_interruptible(&hgps->gpsdrv_data_q);
+ } else {
+ /* Copy Ch-9 info to local structure */
+ memcpy(&hgps->tx_count, skb->data, 1);
+ GPSDRV_VER(" Tx count = %x", hgps->tx_count);
+ /* Check if Tx queue and Tx count not empty */
+ if ((0 != hgps->tx_count) &&
+ (!skb_queue_empty(&hgps->tx_list))) {
+ /* Schedule the Tx-task let */
+ GPSDRV_VER(" Scheduling tasklet to write");
+ tasklet_schedule(&gpsdrv_tx_tsklet);
+ }
+ /* Free the received command complete SKB */
+ kfree(skb);
+ }
+
+ return GPS_SUCCESS;
+
+}
+
+/* gpsdrv_st_cb Function
+ * This is Called in from -- ST Core when the state is pending
+ * during st_register.
+ * This is a registered callback with ST core when the gps driver
+ * registers with ST.
+ *
+ * Parameters:
+ * @data Status update of GPS registration
+ * Returns: NULL
+ */
+void gpsdrv_st_cb(char data)
+{
+ GPSDRV_DBG(" Inside %s", __func__);
+ hgps->streg_cbdata = data; /* ST registration callback status */
+ complete_all(&hgps->gpsdrv_reg_completed);
+ return;
+}
+
+static struct st_proto_s gpsdrv_proto = {
+ .type = ST_GPS,
+ .recv = gpsdrv_st_recv,
+ .reg_complete_cb = gpsdrv_st_cb,
+};
+
+/** gpsdrv_tsklet_write Function
+ * This tasklet function will be scheduled when there is a data in Tx queue
+ * and GPS chip sent an command completion packet with non zero value.
+ *
+ * Parameters:
+ * @data : data passed to tasklet function
+ * Returns : NULL
+ */
+void gpsdrv_tsklet_write(unsigned long data)
+{
+ struct sk_buff *skb = NULL;
+
+ GPSDRV_DBG(" Inside %s", __func__);
+
+ /* Perform sanity check of verifying the status to perform
+ * an st_write
+ */
+ if (((!hgps->st_write) || (0 == hgps->tx_count))
+ || ((skb_queue_empty(&hgps->tx_list)))) {
+ GPSDRV_ERR("Sanity check Failed exiting %s", __func__);
+ return;
+ }
+ /* hgps->tx_list not empty skb already present
+ * dequeue the tx-data and perform a st_write
+ */
+ spin_lock(&hgps->lock);
+ skb = skb_dequeue(&hgps->tx_list);
+ spin_unlock(&hgps->lock);
+ hgps->st_write(skb);
+ hgps->tx_count--;
+
+ /* Check if Tx queue and Tx count not empty */
+ if ((0 != hgps->tx_count) && (!skb_queue_empty(&hgps->tx_list))) {
+ /* Schedule the Tx-task let */
+ tasklet_schedule(&gpsdrv_tx_tsklet);
+ }
+
+ return;
+}
+
+/*********Functions Called from GPS host***************************************/
+
+/** gpsdrv_open Function
+ * This function will perform an register on ST driver.
+ * Parameters :
+ * @file : File pointer for GPS char driver
+ * @inod :
+ * Returns GPS_SUCCESS - on success
+ * else suitable error code
+ */
+int gpsdrv_open(struct inode *inod, struct file *file)
+{
+ int ret = 0;
+ unsigned long timeout = GPSDRV_REG_TIMEOUT;
+
+ GPSDRV_DBG(" Inside %s", __func__);
+
+ /* Check if GPS is already registered with ST */
+ if (test_and_set_bit(GPS_ST_REGISTERED, &hgps->state)) {
+ GPSDRV_ERR("GPS Registered/Registration in progress ,\
+ with ST open called again?");
+ return GPS_ERR_ALREADY;
+ }
+
+ /* Initialize gpsdrv_reg_completed so as to wait for
+ * completion on the same
+ * if st_register returns with a PENDING status
+ */
+ INIT_COMPLETION(hgps->gpsdrv_reg_completed);
+
+ /* Resgister GPS with ST */
+ ret = st_register(&gpsdrv_proto);
+
+ GPSDRV_VER(" st_register returned %d", ret);
+
+ /* If GPS Registration returned with error, then clear GPS_ST_REGISTERED
+ * for future open calls and return the appropriate error code
+ */
+ if (ret < 0 && ret != ST_ERR_PENDING) {
+ GPSDRV_ERR(" st_register failed");
+ clear_bit(GPS_ST_REGISTERED, &hgps->state);
+
+ if (ret == ST_ERR_ALREADY)
+ return GPS_ERR_ALREADY;
+
+ return GPS_ERR_FAILURE;
+ }
+
+ /* if returned status is pending, wait for the completion */
+ if (ret == ST_ERR_PENDING) {
+ GPSDRV_VER(" GPS Register waiting for completion ");
+ timeout =
+ wait_for_completion_timeout(&hgps->gpsdrv_reg_completed,
+ msecs_to_jiffies(timeout));
+ /* Check for timed out condition */
+ if (0 == timeout) {
+ GPSDRV_ERR("st_register timed out");
+ clear_bit(GPS_ST_REGISTERED, &hgps->state);
+ return GPS_ERR_TIMEOUT;
+ }
+
+ if (0 > hgps->streg_cbdata) {
+ GPSDRV_ERR
+ ("GPS Device Registration Failed-ST Reg CB called"
+ "with invalid value %d", hgps->streg_cbdata);
+ clear_bit(GPS_ST_REGISTERED, &hgps->state);
+ return -EAGAIN;
+ }
+ }
+ GPSDRV_DBG(" gps registration complete ");
+
+ /* Assign the write callback pointer */
+ hgps->st_write = gpsdrv_proto.write;
+ hgps->tx_count = 1;
+ tasklet_enable(&gpsdrv_tx_tsklet);
+ set_bit(GPS_ST_RUNNING, &hgps->state);
+
+ return GPS_SUCCESS;
+}
+
+/** gpsdrv_release Function
+ * This function will un-registers from the ST driver.
+ *
+ * Parameters :
+ * @file : File pointer for GPS char driver
+ * @inod :
+ * Returns GPS_SUCCESS - on success
+ * else suitable error code
+ */
+int gpsdrv_release(struct inode *inod, struct file *file)
+{
+ GPSDRV_DBG(" Inside %s", __func__);
+ /* Disabling task-let 1st & then un-reg to avoid
+ * tasklet getting scheduled
+ */
+ tasklet_disable(&gpsdrv_tx_tsklet);
+ /* Cleat registered bit if already registered */
+ if (test_and_clear_bit(GPS_ST_REGISTERED, &hgps->state)) {
+ if (st_unregister(gpsdrv_proto.type) < 0) {
+ GPSDRV_ERR(" st_unregister failed");
+ /* Re-Enable the task-let if un-register fails */
+ tasklet_enable(&gpsdrv_tx_tsklet);
+ return GPS_ERR_FAILURE;
+ }
+ }
+
+ /* Reset Tx count value and st_write function pointer */
+ hgps->tx_count = 0;
+ hgps->st_write = NULL;
+ clear_bit(GPS_ST_RUNNING, &hgps->state);
+ GPSDRV_VER(" st_unregister success");
+
+ return GPS_SUCCESS;
+}
+
+/** gpsdrv_read Function
+ * This function will wait till the data received from the ST driver
+ * and then strips the GPS-Channel-9 header from the
+ * incoming AI2 packet and then send it to GPS host application.
+ *
+ * Parameters :
+ * @file : File pointer for GPS char driver
+ * @data : Data which needs to be passed to APP
+ * @size : Length of the data passesd
+ * offset :
+ * Returns Size of AI2 packet received - on success
+ * else suitable error code
+ */
+ssize_t gpsdrv_read(struct file *file, char __user *data, size_t size,
+ loff_t *offset)
+{
+ int len = 0;
+ struct sk_buff *skb = NULL;
+ unsigned long timeout = GPSDRV_READ_TIMEOUT;
+
+ GPSDRV_DBG(" Inside %s", __func__);
+
+ /* Validate input parameters */
+ if ((NULL == file) || (((NULL == data) || (0 == size)))) {
+ GPSDRV_ERR("Invalid input parameters passed to %s",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* Check if GPS is registered to perform read operation */
+ if (!test_bit(GPS_ST_RUNNING, &hgps->state)) {
+ GPSDRV_ERR("GPS Device is not running");
+ return -EINVAL;
+ }
+
+ /* cannot come here if poll-ed before reading
+ * if not poll-ed wait on the same wait_q
+ */
+ timeout = wait_event_interruptible_timeout(hgps->gpsdrv_data_q,
+ !skb_queue_empty(&hgps->
+ rx_list),
+ msecs_to_jiffies(timeout));
+ /* Check for timed out condition */
+ if (0 == timeout) {
+ GPSDRV_ERR("GPS Device Read timed out");
+ return GPS_ERR_TIMEOUT;
+ }
+
+ GPSDRV_VER(" Read wait completed ");
+
+ /* hgps->rx_list not empty skb already present */
+ spin_lock(&hgps->lock);
+ skb = skb_dequeue(&hgps->rx_list);
+ spin_unlock(&hgps->lock);
+
+ if (!skb) {
+ GPSDRV_ERR("Dequed SKB is NULL?");
+ return GPS_ERR_UNKNOWN;
+ }
+
+ if (skb->len > size) {
+ GPSDRV_ERR("SKB length is Greater than requested size"
+ "Returning the available length of SKB");
+ spin_lock(&hgps->lock);
+ skb_queue_head(&hgps->rx_list, skb);
+ spin_unlock(&hgps->lock);
+ return skb->len;
+ }
+#ifdef VERBOSE
+ for (len = 0; (skb) && (len < skb->len); len++)
+ GPSDRV_DBG(" %x ", skb->data[len]);
+#endif
+
+ /* Forward the data to the user */
+ if (skb->len <= size) {
+ if (copy_to_user(data, skb->data, skb->len)) {
+ GPSDRV_ERR(" Unable to copy to user space");
+ /* Queue the skb back to head */
+ spin_lock(&hgps->lock);
+ skb_queue_head(&hgps->rx_list, skb);
+ spin_unlock(&hgps->lock);
+ return GPS_ERR_CPY_TO_USR;
+ }
+ }
+
+ len = skb->len;
+ kfree(skb);
+ return len;
+}
+
+/** gpsdrv_write Function
+ * This function will pre-pend the GPS-Channel-9 header to the
+ * incoming AI2 packet sent from the GPS host application.
+ *
+ * Parameters :
+ * @file : File pointer for GPS char driver
+ * @data : AI2 packet data from GPS application
+ * @size : Size of the AI2 packet data
+ * @offset :
+ * Returns Size of AI2 packet on success
+ * else suitable error code
+ */
+ssize_t gpsdrv_write(struct file *file, const char __user *data,
+ size_t size, loff_t *offset)
+{
+#ifdef VERBOSE
+ long count = 0;
+#endif
+ unsigned char channel = GPS_CH9_PKT_NUMBER; /* GPS Channel number */
+ /* Initialize gpsdrv_event_hdr with write opcode */
+ struct gpsdrv_event_hdr gpsdrv_hdr = { GPS_CH9_OP_WRITE, 0x0000 };
+ struct sk_buff *skb = NULL;
+
+ GPSDRV_DBG(" Inside %s", __func__);
+
+ /* Validate input parameters */
+ if ((NULL == file) || (((NULL == data) || (0 == size)))) {
+ GPSDRV_ERR("Invalid input parameters passed to %s",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* Check if GPS is registered to perform write operation */
+ if (!test_bit(GPS_ST_RUNNING, &hgps->state)) {
+ GPSDRV_ERR("GPS Device is not running");
+ return -EINVAL;
+ }
+
+ if (!hgps->st_write) {
+ GPSDRV_ERR(" Can't write to ST, hgps->st_write null ?");
+ return -EINVAL;
+ }
+
+ skb = alloc_skb(size + GPS_CH9_PKT_HDR_SIZE, GFP_ATOMIC);
+ /* Validate Created SKB */
+ if (NULL == skb) {
+ GPSDRV_ERR("Error aaloacting SKB");
+ return -ENOMEM;
+ }
+
+ /* Update chnl-9 information with plen=AI2 pckt size which is "size" */
+ gpsdrv_hdr.plen = size;
+
+ /* PrePend Channel-9 header to AI2 packet and write to SKB */
+ memcpy(skb_put(skb, 1), &channel, 1);
+ memcpy(skb_put(skb, GPS_CH9_PKT_HDR_SIZE - 1), &gpsdrv_hdr,
+ GPS_CH9_PKT_HDR_SIZE - 1);
+
+ /* Forward the data from the user space to ST core */
+ if (copy_from_user(skb_put(skb, size), data, size)) {
+ GPSDRV_ERR(" Unable to copy from user space");
+ kfree_skb(skb);
+ return GPS_ERR_CPY_FRM_USR;
+ }
+#ifdef VERBOSE
+ GPSDRV_VER("start data..");
+ for (count = 0; count < size; count++)
+ GPSDRV_VER(" 0x%02x ", skb->data[count]);
+ GPSDRV_VER("\n..end data");
+#endif
+
+ /* Check if data can be sent to GPS chip
+ * If not, add it to queue and that can be sent later
+ */
+ if (0 != hgps->tx_count) {
+ /* If TX Q is empty send current SKB;
+ * else, queue current SKB at end of tx_list queue and
+ * send first SKB in tx_list queue.
+ */
+ if (skb_queue_empty(&hgps->tx_list)) {
+ hgps->st_write(skb);
+ } else {
+ spin_lock(&hgps->lock);
+ skb_queue_tail(&hgps->tx_list, skb);
+ hgps->st_write(skb_dequeue(&hgps->tx_list));
+ spin_unlock(&hgps->lock);
+ }
+
+ hgps->tx_count--;
+ /* Check if Tx queue and Tx count not empty and
+ * schedule wriet tsklet accordingly
+ */
+ if ((0 != hgps->tx_count) &&
+ (!skb_queue_empty(&hgps->tx_list))) {
+ /* Schedule the Tx-task let */
+ tasklet_schedule(&gpsdrv_tx_tsklet);
+ }
+ } else {
+ /* Add it to TX queue */
+ GPSDRV_VER(" SKB added to Tx queue");
+ spin_lock(&hgps->lock);
+ skb_queue_tail(&hgps->tx_list, skb);
+ spin_unlock(&hgps->lock);
+ }
+
+ return size;
+}
+
+/** gpsdrv_ioctl Function
+ * This will peform the functions as directed by the command and command
+ * argument.
+ *
+ * Parameters :
+ * @file : File pointer for GPS char driver
+ * @cmd : IOCTL Command
+ * @arg : Command argument for IOCTL command
+ * Returns GPS_SUCCESS on success
+ * else suitable error code
+ */
+static int gpsdrv_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct sk_buff *skb = NULL;
+ int retCode = GPS_SUCCESS;
+ GPSDRV_DBG(" Inside %s", __func__);
+
+ /* Validate input parameters */
+ if ((NULL == file) || (0 == cmd)) {
+ GPSDRV_ERR("Invalid input parameters passed to %s",
+ __func__);
+ return -EINVAL;
+ }
+ /* Check if GPS is registered to perform IOCTL operation */
+ if (!test_bit(GPS_ST_RUNNING, &hgps->state)) {
+ GPSDRV_ERR("GPS Device is not running");
+ return -EINVAL;
+ }
+
+ switch (cmd) {
+ case TCFLSH:
+ GPSDRV_VER(" IOCTL TCFLSH invoked with %ld argument", arg);
+ spin_lock(&hgps->lock);
+ switch (arg) {
+ /* purge Rx/Tx SKB list queues depending on arg value */
+ case TCIFLUSH:
+ skb_queue_purge(&hgps->rx_list);
+ break;
+ case TCOFLUSH:
+ skb_queue_purge(&hgps->tx_list);
+ break;
+ case TCIOFLUSH:
+ skb_queue_purge(&hgps->rx_list);
+ skb_queue_purge(&hgps->tx_list);
+ break;
+ default:
+ GPSDRV_ERR("Invalid Command passed for tcflush");
+ retCode = -EINVAL;
+ break;
+ }
+ spin_unlock(&hgps->lock);
+ break;
+ case FIONREAD:
+ /* Deque the SKB from the head if rx_list is not empty
+ * And update the argument with skb->len to provide
+ * amount of data
+ * available in the available SKB
+ */
+ spin_lock(&hgps->lock);
+ if (!skb_queue_empty(&hgps->tx_list)) {
+ skb = skb_dequeue(&hgps->rx_list);
+ *(unsigned int *)arg = skb->len;
+ /* Re-Store the SKB for furtur Read operations */
+ skb_queue_head(&hgps->rx_list, skb);
+ } else {
+ *(unsigned int *)arg = 0;
+ }
+ spin_unlock(&hgps->lock);
+ break;
+ default:
+ GPSDRV_DBG("Un-Identified command provided for IOCTL");
+ retCode = -EINVAL;
+ break;
+ }
+
+ return retCode;
+}
+
+/** gpsdrv_poll Function
+ * This function will wait till some data is received to the gps driver from ST
+ *
+ * Parameters :
+ * @file : File pointer for GPS char driver
+ * @wait : POLL wait information
+ * Returns status of POLL on success
+ * else suitable error code
+ */
+static unsigned int gpsdrv_poll(struct file *file, poll_table * wait)
+{
+ unsigned long mask = 0;
+ GPSDRV_DBG(" inside %s", __func__);
+
+ /* Check if GPS is registered to perform read operation */
+ if (!test_bit(GPS_ST_RUNNING, &hgps->state)) {
+ GPSDRV_ERR("GPS Device is not running");
+ return -EINVAL;
+ }
+
+ /* Wait till data is signalled from gpsdrv_st_recv function
+ * with AI2 packet */
+ poll_wait(file, &hgps->gpsdrv_data_q, wait);
+
+ GPSDRV_VER(" Poll wait completed");
+
+ if (!skb_queue_empty(&hgps->rx_list))
+ mask |= POLLIN; /* TODO: check app for mask */
+
+ GPSDRV_DBG(" return 0x%02x \n", (unsigned int)mask);
+ return mask;
+}
+
+/* GPS Char driver function pointers
+ * These functions are called from USER space by pefroming File Operations
+ * on /dev/gps node exposed by this driver during init
+ */
+const struct file_operations gpsdrv_chrdev_ops = {
+ .owner = THIS_MODULE,
+ .open = gpsdrv_open,
+ .read = gpsdrv_read,
+ .write = gpsdrv_write,
+ .ioctl = gpsdrv_ioctl,
+ .poll = gpsdrv_poll,
+ .release = gpsdrv_release,
+};
+
+/*********Functions called during insmod and delmod****************************/
+
+/** gpsdrv_init Function
+ * This function Initializes the gps driver parametes and exposes
+ * /dev/gps node to user space
+ *
+ * Parameters : NULL
+ * Returns GPS_SUCCESS on success
+ * else suitable error code
+ */
+static int __init gpsdrv_init(void)
+{
+ long err = 0;
+
+ GPSDRV_DBG(" Inside %s", __func__);
+
+ /* Allocate local resource memory */
+ hgps = kzalloc(sizeof(struct gpsdrv_data), GFP_KERNEL);
+ if (!(hgps)) {
+ GPSDRV_ERR("Can't allocate GPS data structure");
+ return -ENOMEM;
+ }
+
+ /* Expose the device DEVICE_NAME to user space
+ * And obtain the major number for the device
+ */
+ hgps->gpsdrv_major =
+ register_chrdev(0, DEVICE_NAME, &gpsdrv_chrdev_ops);
+ if (0 > hgps->gpsdrv_major) {
+ err = hgps->gpsdrv_major;
+ GPSDRV_ERR("Error when registering to char dev. Error = %ld.",
+ err);
+ kfree(hgps);
+ return err;
+ }
+ GPSDRV_VER(" %ld: allocated %d, %d", err, hgps->gpsdrv_major, 0);
+
+ /* udev */
+ hgps->gpsdrv_class = class_create(THIS_MODULE, DEVICE_NAME);
+ if (IS_ERR(hgps->gpsdrv_class)) {
+ GPSDRV_ERR(" Something went wrong in class_create");
+ unregister_chrdev(hgps->gpsdrv_major, DEVICE_NAME);
+ kfree(hgps);
+ return GPS_ERR_CLASS;
+ }
+
+ hgps->gpsdrv_dev =
+ device_create(hgps->gpsdrv_class, NULL,
+ MKDEV(hgps->gpsdrv_major, 0), NULL, DEVICE_NAME);
+ if (IS_ERR(hgps->gpsdrv_dev)) {
+ err = PTR_ERR(hgps->gpsdrv_dev);
+ GPSDRV_ERR(" Error in class_create. Error = %ld", err);
+ class_unregister(hgps->gpsdrv_class);
+ class_destroy(hgps->gpsdrv_class);
+ unregister_chrdev(hgps->gpsdrv_major, DEVICE_NAME);
+ kfree(hgps);
+ return err;
+ }
+
+ /* Initialize wait queue, skb queue head and
+ * registration complete strucuture
+ */
+ skb_queue_head_init(&hgps->rx_list);
+ skb_queue_head_init(&hgps->tx_list);
+ init_completion(&hgps->gpsdrv_reg_completed);
+ init_waitqueue_head(&hgps->gpsdrv_data_q);
+ spin_lock_init(&hgps->lock);
+
+ return GPS_SUCCESS;
+}
+
+/** gpsdrv_exit Function
+ * This function Destroys the gps driver parametes and /dev/gps node
+ *
+ * Parameters : NULL
+ * Returns NULL
+ */
+static void __exit gpsdrv_exit(void)
+{
+ GPSDRV_DBG(" Inside %s", __func__);
+ GPSDRV_VER(" Bye.. freeing up %d", hgps->gpsdrv_major);
+
+ skb_queue_purge(&hgps->rx_list);
+ skb_queue_purge(&hgps->tx_list);
+ device_destroy(hgps->gpsdrv_class, MKDEV(hgps->gpsdrv_major, 0));
+
+ class_unregister(hgps->gpsdrv_class);
+ class_destroy(hgps->gpsdrv_class);
+
+ unregister_chrdev(hgps->gpsdrv_major, DEVICE_NAME);
+ tasklet_kill(&gpsdrv_tx_tsklet);
+ kfree(hgps);
+}
+
+module_init(gpsdrv_init);
+module_exit(gpsdrv_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ti-st/gps_drv.h b/drivers/misc/ti-st/gps_drv.h
new file mode 100644
index 0000000..c227163
--- /dev/null
+++ b/drivers/misc/ti-st/gps_drv.h
@@ -0,0 +1,105 @@
+/*
+ * GPS Char Driver for Texas Instrument's Connectivity Chip.
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef GPSDRV_H
+#define GPSDRV_H
+
+#define VERBOSE
+
+/* Debug macros*/
+#define GPSDRV_ERR(fmt, arg...) printk(KERN_ERR "(gpsdrv):"fmt"\n" , ## arg)
+#if defined(DEBUG) /* limited debug messages */
+#define GPSDRV_DBG(fmt, arg...) printk(KERN_INFO "(gpsdrv):"fmt"\n" , ## arg)
+#define GPSDRV_VER(fmt, arg...)
+#elif defined(VERBOSE) /* very verbose */
+#define GPSDRV_DBG(fmt, arg...) printk(KERN_INFO "(gpsdrv):"fmt"\n" , ## arg)
+#define GPSDRV_VER(fmt, arg...) printk(KERN_INFO "(gpsdrv):"fmt"\n" , ## arg)
+#else /* Error msgs only */
+#define GPSDRV_DBG(fmt, arg...)
+#define GPSDRV_VER(fmt, arg...)
+#endif
+
+/* List of error codes returned by the gps driver*/
+enum {
+ GPS_ERR_FAILURE = -1, /* check struct */
+ GPS_SUCCESS,
+ GPS_ERR_PENDING = -5, /* to call reg_complete_cb */
+ GPS_ERR_ALREADY, /* already registered */
+ GPS_ERR_INPROGRESS,
+ GPS_ERR_NOPROTO, /* protocol not supported */
+ GPS_ERR_CLASS = -15,
+ GPS_ERR_CPY_TO_USR,
+ GPS_ERR_CPY_FRM_USR,
+ GPS_ERR_TIMEOUT,
+ GPS_ERR_UNKNOWN,
+};
+
+/* Channel-9 details for GPS */
+#define GPS_CH9_PKT_HDR_SIZE 4
+#define GPS_CH9_PKT_NUMBER 0x9
+#define GPS_CH9_OP_WRITE 0x1
+#define GPS_CH9_OP_READ 0x2
+#define GPS_CH9_OP_COMPLETED_EVT 0x3
+
+/* Macros for Syncronising GPS registration and other R/W/ICTL operations */
+#define GPS_ST_REGISTERED 0
+#define GPS_ST_RUNNING 1
+
+/* Read time out defined to 10 seconds */
+#define GPSDRV_READ_TIMEOUT 10000
+/* Reg time out defined to 6 seconds */
+#define GPSDRV_REG_TIMEOUT 6000
+
+struct gpsdrv_event_hdr {
+ uint8_t opcode;
+ uint16_t plen;
+} __attribute__ ((packed));
+
+/* BT driver operation structure */
+struct gpsdrv_data {
+
+ int gpsdrv_major; /* GPS major number */
+ struct class *gpsdrv_class; /* GPS class during class_create */
+ struct device *gpsdrv_dev; /* GPS dev during device_create */
+ struct completion gpsdrv_reg_completed; /* comepletion handler
+ to synchronize
+ gpsdrv_chrdev_open */
+ unsigned char streg_cbdata; /* ST registration callback status */
+
+ unsigned long state; /* used locally,to maintain various
+ GPS driver status */
+
+ unsigned char tx_count; /* Count value which gives number
+ of Tx GPS commands that can be sent
+ to GPS chip
+ */
+ long (*st_write) (struct sk_buff *skb); /* write function pointer
+ of ST driver */
+ struct sk_buff_head rx_list; /* Rx data SKB queue */
+ struct sk_buff_head tx_list; /* Tx data SKB queue */
+
+ wait_queue_head_t gpsdrv_data_q; /* Used to syncronize read
+ call and poll */
+
+ spinlock_t lock; /* spin lock data for safe-gaurding
+ operations on SKB */
+
+};
+/* Function prototype for TaskLet-Write function */
+void gpsdrv_tsklet_write(unsigned long);
+#endif /*GPS_H */
diff --git a/drivers/misc/ti-st/st.h b/drivers/misc/ti-st/st.h
new file mode 100644
index 0000000..7661e0d
--- /dev/null
+++ b/drivers/misc/ti-st/st.h
@@ -0,0 +1,85 @@
+/*
+ * Shared Transport Header file
+ * To be included by the protocol stack drivers for
+ * Texas Instruments BT,FM and GPS combo chip drivers
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef ST_H
+#define ST_H
+
+#include <linux/skbuff.h>
+/*
+ * st.h
+ */
+
+/* some gpios have active high, others like fm have
+ * active low
+ */
+enum kim_gpio_state {
+ KIM_GPIO_INACTIVE,
+ KIM_GPIO_ACTIVE,
+};
+/*
+ * the list of protocols on chip
+ */
+enum proto_type {
+ ST_BT,
+ ST_FM,
+ ST_GPS,
+ ST_MAX,
+};
+
+enum {
+ ST_ERR_FAILURE = -1, /* check struct */
+ ST_SUCCESS,
+ ST_ERR_PENDING = -5, /* to call reg_complete_cb */
+ ST_ERR_ALREADY, /* already registered */
+ ST_ERR_INPROGRESS,
+ ST_ERR_NOPROTO, /* protocol not supported */
+};
+
+/* per protocol structure
+ * for BT/FM and GPS
+ */
+struct st_proto_s {
+ enum proto_type type;
+/*
+ * to be called by ST when data arrives
+ */
+ long (*recv) (struct sk_buff *);
+/*
+ * for future use, logic now to be in ST
+ */
+ unsigned char (*match_packet) (const unsigned char *data);
+/*
+ * subsequent registration return PENDING,
+ * signalled complete by this callback function
+ */
+ void (*reg_complete_cb) (char data);
+/*
+ * write function, sent in as NULL and to be returned to
+ * protocol drivers
+ */
+ long (*write) (struct sk_buff *skb);
+};
+
+extern long st_register(struct st_proto_s *new_proto);
+extern long st_unregister(enum proto_type type);
+
+#endif /* ST_H */
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
new file mode 100644
index 0000000..b4c7b96
--- /dev/null
+++ b/drivers/misc/ti-st/st_core.c
@@ -0,0 +1,1055 @@
+/*
+ * Shared Transport Line discipline driver Core
+ * This hooks up ST KIM driver and ST LL driver
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+
+/* understand BT, FM and GPS for now */
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+#include "fm.h"
+/*
+ * packet formats for fm and gps
+ * #include "gps.h"
+ */
+#include "st_core.h"
+#include "st_kim.h"
+#include "st_ll.h"
+#include "st.h"
+
+/* all debug macros go in here */
+#define ST_DRV_ERR(fmt, arg...) printk(KERN_ERR "(stc):"fmt"\n" , ## arg)
+#if defined(DEBUG) /* limited debug messages */
+#define ST_DRV_DBG(fmt, arg...) printk(KERN_INFO "(stc):"fmt"\n" , ## arg)
+#define ST_DRV_VER(fmt, arg...)
+#elif defined(VERBOSE) /* very verbose */
+#define ST_DRV_DBG(fmt, arg...) printk(KERN_INFO "(stc):"fmt"\n" , ## arg)
+#define ST_DRV_VER(fmt, arg...) printk(KERN_INFO "(stc):"fmt"\n" , ## arg)
+#else /* error msgs only */
+#define ST_DRV_DBG(fmt, arg...)
+#define ST_DRV_VER(fmt, arg...)
+#endif
+
+#ifdef DEBUG
+/* strings to be used for rfkill entries and by
+ * ST Core to be used for sysfs debug entry
+ */
+#define PROTO_ENTRY(type, name) name
+const unsigned char *protocol_strngs[] = {
+ PROTO_ENTRY(ST_BT, "Bluetooth"),
+ PROTO_ENTRY(ST_FM, "FM"),
+ PROTO_ENTRY(ST_GPS, "GPS"),
+};
+#endif
+/*
+ * local data instances
+ */
+static struct st_data_s *st_gdata;
+/* function pointer pointing to either,
+ * st_kim_recv during registration to receive fw download responses
+ * st_int_recv after registration to receive proto stack responses
+ */
+void (*st_recv) (const unsigned char *data, long count);
+
+/********************************************************************/
+/* internal misc functions */
+bool is_protocol_list_empty(void)
+{
+ unsigned char i = 0;
+ ST_DRV_DBG(" %s ", __func__);
+ spin_lock(&st_gdata->lock);
+ for (i = 0; i < ST_MAX; i++) {
+ if (st_gdata->list[i] != NULL) {
+ spin_unlock(&st_gdata->lock);
+ return ST_NOTEMPTY;
+ }
+ /* not empty */
+ }
+ spin_unlock(&st_gdata->lock);
+ /* list empty */
+ return ST_EMPTY;
+}
+
+/* can be called in from
+ * -- KIM (during fw download)
+ * -- ST Core (during st_write)
+ *
+ * This is the internal write function - a wrapper
+ * to tty->ops->write
+ */
+int st_int_write(const unsigned char *data, int count)
+{
+#ifdef VERBOSE /* for debug */
+ int i;
+#endif
+ struct tty_struct *tty;
+ if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) {
+ ST_DRV_ERR("tty unavailable to perform write");
+ return ST_ERR_FAILURE;
+ }
+ tty = st_gdata->tty;
+#ifdef VERBOSE
+ printk(KERN_ERR "start data.. \n");
+ for (i = 0; i < count; i++) /* no newlines for each datum */
+ printk(" %x", data[i]);
+ printk(KERN_ERR "\n ..end data\n");
+#endif
+
+ return tty->ops->write(tty, data, count);
+
+}
+
+/*
+ * push the skb received to relevant
+ * protocol stacks
+ */
+void st_send_frame(enum proto_type protoid, struct sk_buff *skb)
+{
+ ST_DRV_DBG(" %s(prot:%d) ", __func__, protoid);
+
+ if (unlikely
+ (st_gdata == NULL || skb == NULL
+ || st_gdata->list[protoid] == NULL)) {
+ ST_DRV_ERR("protocol %d not registered, no data to send?",
+ protoid);
+ kfree_skb(skb);
+ return;
+ }
+ /* this cannot fail
+ * this shouldn't take long
+ * - should be just skb_queue_tail for the
+ * protocol stack driver
+ */
+ if (likely(st_gdata->list[protoid]->recv != NULL)) {
+ if (unlikely(st_gdata->list[protoid]->recv(skb)
+ != ST_SUCCESS)) {
+ ST_DRV_ERR(" proto stack %d's ->recv failed", protoid);
+ kfree_skb(skb);
+ return;
+ }
+ } else {
+ ST_DRV_ERR(" proto stack %d's ->recv null", protoid);
+ kfree_skb(skb);
+ }
+ ST_DRV_DBG(" done %s", __func__);
+ return;
+}
+
+/*
+ * to call registration complete callbacks
+ * of all protocol stack drivers
+ */
+void st_reg_complete(char err)
+{
+ unsigned char i = 0;
+ ST_DRV_DBG(" %s ", __func__);
+ for (i = 0; i < ST_MAX; i++) {
+ if (likely(st_gdata != NULL && st_gdata->list[i] != NULL &&
+ st_gdata->list[i]->reg_complete_cb != NULL))
+ st_gdata->list[i]->reg_complete_cb(err);
+ }
+}
+
+static inline int st_check_data_len(int protoid, int len)
+{
+ register int room = skb_tailroom(st_gdata->rx_skb);
+
+ ST_DRV_DBG("len %d room %d", len, room);
+
+ if (!len) {
+ /* Received packet has only packet header and
+ * has zero length payload. So, ask ST CORE to
+ * forward the packet to protocol driver (BT/FM/GPS)
+ */
+ st_send_frame(protoid, st_gdata->rx_skb);
+
+ } else if (len > room) {
+ /* Received packet's payload length is larger.
+ * We can't accommodate it in created skb.
+ */
+ ST_DRV_ERR("Data length is too large len %d room %d", len,
+ room);
+ kfree_skb(st_gdata->rx_skb);
+ } else {
+ /* Packet header has non-zero payload length and
+ * we have enough space in created skb. Lets read
+ * payload data */
+ st_gdata->rx_state = ST_BT_W4_DATA;
+ st_gdata->rx_count = len;
+ return len;
+ }
+
+ /* Change ST state to continue to process next
+ * packet */
+ st_gdata->rx_state = ST_W4_PACKET_TYPE;
+ st_gdata->rx_skb = NULL;
+ st_gdata->rx_count = 0;
+
+ return 0;
+}
+
+/* internal function for action when wake-up ack
+ * received
+ */
+static inline void st_wakeup_ack(unsigned char cmd)
+{
+ register struct sk_buff *waiting_skb;
+ spin_lock(&st_gdata->lock);
+ /* de-Q from waitQ and Q in txQ now that the
+ * chip is awake
+ */
+ while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq)))
+ skb_queue_tail(&st_gdata->txq, waiting_skb);
+
+ /* state forwarded to ST LL */
+ st_ll_sleep_state((unsigned long)cmd);
+ spin_unlock(&st_gdata->lock);
+
+ /* wake up to send the recently copied skbs from waitQ */
+ st_tx_wakeup(st_gdata);
+}
+
+/* Decodes received RAW data and forwards to corresponding
+ * client drivers (Bluetooth,FM,GPS..etc).
+ *
+ */
+void st_int_recv(const unsigned char *data, long count)
+{
+ register char *ptr;
+ struct hci_event_hdr *eh;
+ struct hci_acl_hdr *ah;
+ struct hci_sco_hdr *sh;
+ struct fm_event_hdr *fm;
+ struct gps_event_hdr *gps;
+ register int len = 0, type = 0, dlen = 0;
+ static enum proto_type protoid = ST_MAX;
+
+ ST_DRV_DBG("count %ld rx_state %ld"
+ "rx_count %ld", count, st_gdata->rx_state,
+ st_gdata->rx_count);
+
+ ptr = (char *)data;
+ /* tty_receive sent null ? */
+ if (unlikely(ptr == NULL)) {
+ ST_DRV_ERR(" received null from TTY ");
+ return;
+ }
+
+ /* Decode received bytes here */
+ while (count) {
+ if (st_gdata->rx_count) {
+ len = min_t(unsigned int, st_gdata->rx_count, count);
+ memcpy(skb_put(st_gdata->rx_skb, len), ptr, len);
+ st_gdata->rx_count -= len;
+ count -= len;
+ ptr += len;
+
+ if (st_gdata->rx_count)
+ continue;
+
+ /* Check ST RX state machine , where are we? */
+ switch (st_gdata->rx_state) {
+
+ /* Waiting for complete packet ? */
+ case ST_BT_W4_DATA:
+ ST_DRV_DBG("Complete pkt received");
+
+ /* Ask ST CORE to forward
+ * the packet to protocol driver */
+ st_send_frame(protoid, st_gdata->rx_skb);
+
+ st_gdata->rx_state = ST_W4_PACKET_TYPE;
+ st_gdata->rx_skb = NULL;
+ protoid = ST_MAX; /* is this required ? */
+ continue;
+
+ /* Waiting for Bluetooth event header ? */
+ case ST_BT_W4_EVENT_HDR:
+ eh = (struct hci_event_hdr *)st_gdata->rx_skb->
+ data;
+
+ ST_DRV_DBG("Event header: evt 0x%2.2x"
+ "plen %d", eh->evt, eh->plen);
+
+ st_check_data_len(protoid, eh->plen);
+ continue;
+
+ /* Waiting for Bluetooth acl header ? */
+ case ST_BT_W4_ACL_HDR:
+ ah = (struct hci_acl_hdr *)st_gdata->rx_skb->
+ data;
+ dlen = __le16_to_cpu(ah->dlen);
+
+ ST_DRV_DBG("ACL header: dlen %d", dlen);
+
+ st_check_data_len(protoid, dlen);
+ continue;
+
+ /* Waiting for Bluetooth sco header ? */
+ case ST_BT_W4_SCO_HDR:
+ sh = (struct hci_sco_hdr *)st_gdata->rx_skb->
+ data;
+
+ ST_DRV_DBG("SCO header: dlen %d", sh->dlen);
+
+ st_check_data_len(protoid, sh->dlen);
+ continue;
+ case ST_FM_W4_EVENT_HDR:
+ fm = (struct fm_event_hdr *)st_gdata->rx_skb->
+ data;
+ ST_DRV_DBG("FM Header: ");
+ st_check_data_len(ST_FM, fm->plen);
+ continue;
+ /* TODO : Add GPS packet machine logic here */
+ case ST_GPS_W4_EVENT_HDR:
+ /* [0x09 pkt hdr][R/W byte][2 byte len] */
+ gps = (struct gps_event_hdr *)st_gdata->rx_skb->
+ data;
+ ST_DRV_DBG("GPS Header: ");
+ st_check_data_len(ST_GPS, gps->plen);
+ continue;
+ } /* end of switch rx_state */
+ }
+
+ /* end of if rx_count */
+ /* Check first byte of packet and identify module
+ * owner (BT/FM/GPS) */
+ switch (*ptr) {
+
+ /* Bluetooth event packet? */
+ case HCI_EVENT_PKT:
+ ST_DRV_DBG("Event packet");
+ st_gdata->rx_state = ST_BT_W4_EVENT_HDR;
+ st_gdata->rx_count = HCI_EVENT_HDR_SIZE;
+ type = HCI_EVENT_PKT;
+ protoid = ST_BT;
+ break;
+
+ /* Bluetooth acl packet? */
+ case HCI_ACLDATA_PKT:
+ ST_DRV_DBG("ACL packet");
+ st_gdata->rx_state = ST_BT_W4_ACL_HDR;
+ st_gdata->rx_count = HCI_ACL_HDR_SIZE;
+ type = HCI_ACLDATA_PKT;
+ protoid = ST_BT;
+ break;
+
+ /* Bluetooth sco packet? */
+ case HCI_SCODATA_PKT:
+ ST_DRV_DBG("SCO packet");
+ st_gdata->rx_state = ST_BT_W4_SCO_HDR;
+ st_gdata->rx_count = HCI_SCO_HDR_SIZE;
+ type = HCI_SCODATA_PKT;
+ protoid = ST_BT;
+ break;
+
+ /* Channel 8(FM) packet? */
+ case ST_FM_CH8_PKT:
+ ST_DRV_DBG("FM CH8 packet");
+ type = ST_FM_CH8_PKT;
+ st_gdata->rx_state = ST_FM_W4_EVENT_HDR;
+ st_gdata->rx_count = FM_EVENT_HDR_SIZE;
+ protoid = ST_FM;
+ break;
+
+ /* Channel 9(GPS) packet? */
+ case 0x9: /*ST_LL_GPS_CH9_PKT */
+ ST_DRV_DBG("GPS CH9 packet");
+ type = 0x9; /* ST_LL_GPS_CH9_PKT; */
+ protoid = ST_GPS;
+ st_gdata->rx_state = ST_GPS_W4_EVENT_HDR;
+ st_gdata->rx_count = 3; /* GPS_EVENT_HDR_SIZE -1*/
+ break;
+ case LL_SLEEP_IND:
+ case LL_SLEEP_ACK:
+ case LL_WAKE_UP_IND:
+ /* this takes appropriate action based on
+ * sleep state received --
+ */
+ st_ll_sleep_state(*ptr);
+ ptr++;
+ count--;
+ continue;
+ case LL_WAKE_UP_ACK:
+ /* wake up ack received */
+ st_wakeup_ack(*ptr);
+ ptr++;
+ count--;
+ continue;
+ /* Unknow packet? */
+ default:
+ ST_DRV_ERR("Unknown packet type %2.2x", (__u8) *ptr);
+ ptr++;
+ count--;
+ continue;
+ };
+ ptr++;
+ count--;
+
+ switch (protoid) {
+ case ST_BT:
+ /* Allocate new packet to hold received data */
+ st_gdata->rx_skb =
+ bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!st_gdata->rx_skb) {
+ ST_DRV_ERR("Can't allocate mem for new packet");
+ st_gdata->rx_state = ST_W4_PACKET_TYPE;
+ st_gdata->rx_count = 0;
+ return;
+ }
+ bt_cb(st_gdata->rx_skb)->pkt_type = type;
+ break;
+ case ST_FM: /* for FM */
+ st_gdata->rx_skb =
+ alloc_skb(FM_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!st_gdata->rx_skb) {
+ ST_DRV_ERR("Can't allocate mem for new packet");
+ st_gdata->rx_state = ST_W4_PACKET_TYPE;
+ st_gdata->rx_count = 0;
+ return;
+ }
+ /* place holder 0x08 */
+ skb_reserve(st_gdata->rx_skb, 1);
+ st_gdata->rx_skb->cb[0] = ST_FM_CH8_PKT;
+ break;
+ case ST_GPS:
+ /* for GPS */
+ st_gdata->rx_skb =
+ alloc_skb(100 /*GPS_MAX_FRAME_SIZE */ , GFP_ATOMIC);
+ if (!st_gdata->rx_skb) {
+ ST_DRV_ERR("Can't allocate mem for new packet");
+ st_gdata->rx_state = ST_W4_PACKET_TYPE;
+ st_gdata->rx_count = 0;
+ return;
+ }
+ /* place holder 0x09 */
+ skb_reserve(st_gdata->rx_skb, 1);
+ st_gdata->rx_skb->cb[0] = 0x09; /*ST_GPS_CH9_PKT; */
+ break;
+ case ST_MAX:
+ break;
+ }
+ }
+ ST_DRV_DBG("done %s", __func__);
+ return;
+}
+
+/* internal de-Q function
+ * -- return previous in-completely written skb
+ * or return the skb in the txQ
+ */
+struct sk_buff *st_int_dequeue(struct st_data_s *st_data)
+{
+ struct sk_buff *returning_skb;
+
+ ST_DRV_VER("%s", __func__);
+ /* if the previous skb wasn't written completely
+ */
+ if (st_gdata->tx_skb != NULL) {
+ returning_skb = st_gdata->tx_skb;
+ st_gdata->tx_skb = NULL;
+ return returning_skb;
+ }
+
+ /* de-Q from the txQ always if previous write is complete */
+ return skb_dequeue(&st_gdata->txq);
+}
+
+/* internal Q-ing function
+ * will either Q the skb to txq or the tx_waitq
+ * depending on the ST LL state
+ *
+ * lock the whole func - since ll_getstate and Q-ing should happen
+ * in one-shot
+ */
+void st_int_enqueue(struct sk_buff *skb)
+{
+ unsigned long flags = 0;
+
+ ST_DRV_VER("%s", __func__);
+ /* this function can be invoked in more then one context.
+ * so have a lock */
+ spin_lock_irqsave(&st_gdata->lock, flags);
+
+ switch (st_ll_getstate()) {
+ case ST_LL_AWAKE:
+ ST_DRV_DBG("ST LL is AWAKE, sending normally");
+ skb_queue_tail(&st_gdata->txq, skb);
+ break;
+ case ST_LL_ASLEEP_TO_AWAKE:
+ skb_queue_tail(&st_gdata->tx_waitq, skb);
+ break;
+ case ST_LL_AWAKE_TO_ASLEEP: /* host cannot be in this state */
+ ST_DRV_ERR("ST LL is illegal state(%ld),"
+ "purging received skb.", st_ll_getstate());
+ kfree_skb(skb);
+ break;
+
+ case ST_LL_ASLEEP:
+ /* call a function of ST LL to put data
+ * in tx_waitQ and wake_ind in txQ
+ */
+ skb_queue_tail(&st_gdata->tx_waitq, skb);
+ st_ll_wakeup();
+ break;
+ default:
+ ST_DRV_ERR("ST LL is illegal state(%ld),"
+ "purging received skb.", st_ll_getstate());
+ kfree_skb(skb);
+ break;
+ }
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+ ST_DRV_VER("done %s", __func__);
+ return;
+}
+
+/*
+ * internal wakeup function
+ * called from either
+ * - TTY layer when write's finished
+ * - st_write (in context of the protocol stack)
+ */
+void st_tx_wakeup(struct st_data_s *st_data)
+{
+ struct sk_buff *skb;
+ unsigned long flags; /* for irq save flags */
+ ST_DRV_VER("%s", __func__);
+ /* check for sending & set flag sending here */
+ if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) {
+ ST_DRV_DBG("ST already sending");
+ /* keep sending */
+ set_bit(ST_TX_WAKEUP, &st_data->tx_state);
+ return;
+ /* TX_WAKEUP will be checked in another
+ * context
+ */
+ }
+ do { /* come back if st_tx_wakeup is set */
+ /* woke-up to write */
+ clear_bit(ST_TX_WAKEUP, &st_data->tx_state);
+ while ((skb = st_int_dequeue(st_data))) {
+ int len;
+ spin_lock_irqsave(&st_data->lock, flags);
+ /* enable wake-up from TTY */
+ set_bit(TTY_DO_WRITE_WAKEUP, &st_data->tty->flags);
+ len = st_int_write(skb->data, skb->len);
+ skb_pull(skb, len);
+ /* if skb->len = len as expected, skb->len=0 */
+ if (skb->len) {
+ /* would be the next skb to be sent */
+ st_data->tx_skb = skb;
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+ break;
+ }
+ kfree_skb(skb);
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+ }
+ /* if wake-up is set in another context- restart sending */
+ } while (test_bit(ST_TX_WAKEUP, &st_data->tx_state));
+
+ /* clear flag sending */
+ clear_bit(ST_TX_SENDING, &st_data->tx_state);
+}
+
+/********************************************************************/
+/* functions called from ST KIM
+*/
+void kim_st_list_protocols(char *buf)
+{
+#ifdef DEBUG
+ unsigned char i = ST_MAX;
+#endif
+ spin_lock(&st_gdata->lock);
+#ifdef DEBUG /* more detailed log */
+ for (i = 0; i < ST_MAX; i++) {
+ if (i == 0) {
+ sprintf(buf, "%s is %s", protocol_strngs[i],
+ st_gdata->list[i] !=
+ NULL ? "Registered" : "Unregistered");
+ } else {
+ sprintf(buf, "%s\n%s is %s", buf, protocol_strngs[i],
+ st_gdata->list[i] !=
+ NULL ? "Registered" : "Unregistered");
+ }
+ }
+ sprintf(buf, "%s\n", buf);
+#else /* limited info */
+ sprintf(buf, "BT=%c\nFM=%c\nGPS=%c\n",
+ st_gdata->list[ST_BT] != NULL ? 'R' : 'U',
+ st_gdata->list[ST_FM] != NULL ? 'R' : 'U',
+ st_gdata->list[ST_GPS] != NULL ? 'R' : 'U');
+#endif
+ spin_unlock(&st_gdata->lock);
+}
+
+/********************************************************************/
+/*
+ * functions called from protocol stack drivers
+ * to be EXPORT-ed
+ */
+long st_register(struct st_proto_s *new_proto)
+{
+ long err = ST_SUCCESS;
+ ST_DRV_DBG("%s(%d) ", __func__, new_proto->type);
+ if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL
+ || new_proto->reg_complete_cb == NULL) {
+ ST_DRV_ERR("gdata/new_proto/recv or reg_complete_cb not ready");
+ return ST_ERR_FAILURE;
+ }
+
+ if (new_proto->type < ST_BT || new_proto->type >= ST_MAX) {
+ ST_DRV_ERR("protocol %d not supported", new_proto->type);
+ return ST_ERR_NOPROTO;
+ }
+
+ if (st_gdata->list[new_proto->type] != NULL) {
+ ST_DRV_ERR("protocol %d already registered", new_proto->type);
+ return ST_ERR_ALREADY;
+ }
+
+ /* can be from process context only */
+ spin_lock(&st_gdata->lock);
+
+ if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) {
+ ST_DRV_DBG(" ST_REG_IN_PROGRESS:%d ", new_proto->type);
+ /* fw download in progress */
+ st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
+
+ st_gdata->list[new_proto->type] = new_proto;
+ new_proto->write = st_write;
+
+ set_bit(ST_REG_PENDING, &st_gdata->st_state);
+ spin_unlock(&st_gdata->lock);
+ return ST_ERR_PENDING;
+ } else if (is_protocol_list_empty() == ST_EMPTY) {
+ ST_DRV_DBG(" protocol list empty :%d ", new_proto->type);
+ set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
+ st_recv = st_kim_recv;
+
+ /* release lock previously held - re-locked below */
+ spin_unlock(&st_gdata->lock);
+
+ /* enable the ST LL - to set default chip state */
+ st_ll_enable();
+ /* this may take a while to complete
+ * since it involves BT fw download
+ */
+ err = st_kim_start();
+ if (err != ST_SUCCESS) {
+ clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
+ if ((is_protocol_list_empty() != ST_EMPTY) &&
+ (test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
+ ST_DRV_ERR(" KIM failure complete callback ");
+ st_reg_complete(ST_ERR_FAILURE);
+ }
+
+ return ST_ERR_FAILURE;
+ }
+
+ /* the protocol might require other gpios to be toggled
+ */
+ st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
+
+ clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
+ st_recv = st_int_recv;
+
+ /* this is where all pending registration
+ * are signalled to be complete by calling callback functions
+ */
+ if ((is_protocol_list_empty() != ST_EMPTY) &&
+ (test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
+ ST_DRV_VER(" call reg complete callback ");
+ st_reg_complete(ST_SUCCESS);
+ }
+ clear_bit(ST_REG_PENDING, &st_gdata->st_state);
+
+ /* check for already registered once more,
+ * since the above check is old
+ */
+ if (st_gdata->list[new_proto->type] != NULL) {
+ ST_DRV_ERR(" proto %d already registered ",
+ new_proto->type);
+ return ST_ERR_ALREADY;
+ }
+
+ spin_lock(&st_gdata->lock);
+ st_gdata->list[new_proto->type] = new_proto;
+ new_proto->write = st_write;
+ spin_unlock(&st_gdata->lock);
+ return err;
+ }
+ /* if fw is already downloaded & new stack registers protocol */
+ else {
+ switch (new_proto->type) {
+ case ST_BT:
+ /* do nothing */
+ break;
+ case ST_FM:
+ case ST_GPS:
+ st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
+ break;
+ case ST_MAX:
+ default:
+ ST_DRV_ERR("%d protocol not supported",
+ new_proto->type);
+ err = ST_ERR_NOPROTO;
+ /* something wrong */
+ break;
+ }
+ st_gdata->list[new_proto->type] = new_proto;
+ new_proto->write = st_write;
+
+ /* lock already held before entering else */
+ spin_unlock(&st_gdata->lock);
+ return err;
+ }
+ ST_DRV_DBG("done %s(%d) ", __func__, new_proto->type);
+}
+EXPORT_SYMBOL_GPL(st_register);
+
+/* to unregister a protocol -
+ * to be called from protocol stack driver
+ */
+long st_unregister(enum proto_type type)
+{
+ long err = ST_SUCCESS;
+ ST_DRV_DBG("%s: %d ", __func__, type);
+
+ if (type < ST_BT || type >= ST_MAX) {
+ ST_DRV_ERR(" protocol %d not supported", type);
+ return ST_ERR_NOPROTO;
+ }
+
+ spin_lock(&st_gdata->lock);
+
+ if (st_gdata->list[type] == NULL) {
+ ST_DRV_ERR(" protocol %d not registered", type);
+ spin_unlock(&st_gdata->lock);
+ return ST_ERR_NOPROTO;
+ }
+
+ st_gdata->list[type] = NULL;
+
+ /* kim ignores BT in the below function
+ * and handles the rest, BT is toggled
+ * only in kim_start and kim_stop
+ */
+ st_kim_chip_toggle(type, KIM_GPIO_INACTIVE);
+ spin_unlock(&st_gdata->lock);
+
+ if ((is_protocol_list_empty() == ST_EMPTY) &&
+ (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
+ ST_DRV_DBG(" all protocols unregistered ");
+
+ /* stop traffic on tty */
+ if (st_gdata->tty) {
+ tty_ldisc_flush(st_gdata->tty);
+ stop_tty(st_gdata->tty);
+ }
+
+ /* all protocols now unregistered */
+ st_kim_stop();
+ /* disable ST LL */
+ st_ll_disable();
+ }
+ return err;
+}
+
+/*
+ * called in protocol stack drivers
+ * via the write function pointer
+ */
+long st_write(struct sk_buff *skb)
+{
+#ifdef DEBUG
+ enum proto_type protoid = ST_MAX;
+#endif
+ long len;
+ struct st_data_s *st_data = st_gdata;
+
+ if (unlikely(skb == NULL || st_gdata == NULL
+ || st_gdata->tty == NULL)) {
+ ST_DRV_ERR("data/tty unavailable to perform write");
+ return ST_ERR_FAILURE;
+ }
+#ifdef DEBUG /* open-up skb to read the 1st byte */
+ switch (skb->data[0]) {
+ case HCI_COMMAND_PKT:
+ case HCI_ACLDATA_PKT:
+ case HCI_SCODATA_PKT:
+ protoid = ST_BT;
+ break;
+ case ST_FM_CH8_PKT:
+ protoid = ST_FM;
+ break;
+ case 0x09:
+ protoid = ST_GPS;
+ break;
+ }
+ if (unlikely(st_gdata->list[protoid] == NULL)) {
+ ST_DRV_ERR(" protocol %d not registered, and writing? ",
+ protoid);
+ return ST_ERR_FAILURE;
+ }
+#endif
+ ST_DRV_DBG("%d to be written", skb->len);
+ len = skb->len;
+
+ /* st_ll to decide where to enqueue the skb */
+ st_int_enqueue(skb);
+ /* wake up */
+ st_tx_wakeup(st_data);
+
+ /* return number of bytes written */
+ return len;
+}
+
+/* for protocols making use of shared transport */
+EXPORT_SYMBOL_GPL(st_unregister);
+
+/********************************************************************/
+/*
+ * functions called from TTY layer
+ */
+static int st_tty_open(struct tty_struct *tty)
+{
+ int err = ST_SUCCESS;
+ ST_DRV_DBG("%s ", __func__);
+
+ st_gdata->tty = tty;
+
+ /* don't do an wakeup for now */
+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+
+ /* mem already allocated
+ */
+ tty->receive_room = 65536;
+ /* Flush any pending characters in the driver and discipline. */
+ tty_ldisc_flush(tty);
+ tty_driver_flush_buffer(tty);
+ /*
+ * signal to UIM via KIM that -
+ * installation of N_SHARED ldisc is complete
+ */
+ st_kim_complete();
+ ST_DRV_DBG("done %s", __func__);
+ return err;
+}
+
+static void st_tty_close(struct tty_struct *tty)
+{
+ unsigned char i = ST_MAX;
+ ST_DRV_DBG("%s ", __func__);
+
+ /* TODO:
+ * if a protocol has been registered & line discipline
+ * un-installed for some reason - what should be done ?
+ */
+ spin_lock(&st_gdata->lock);
+ for (i = ST_BT; i < ST_MAX; i++) {
+ if (st_gdata->list[i] != NULL)
+ ST_DRV_ERR("%d not un-registered", i);
+ st_gdata->list[i] = NULL;
+ }
+ spin_unlock(&st_gdata->lock);
+ /*
+ * signal to UIM via KIM that -
+ * N_SHARED ldisc is un-installed
+ */
+ st_kim_complete();
+ st_gdata->tty = NULL;
+ /* Flush any pending characters in the driver and discipline. */
+ tty_ldisc_flush(tty);
+ tty_driver_flush_buffer(tty);
+
+ spin_lock(&st_gdata->lock);
+ /* empty out txq and tx_waitq */
+ skb_queue_purge(&st_gdata->txq);
+ skb_queue_purge(&st_gdata->tx_waitq);
+ /* reset the TTY Rx states of ST */
+ st_gdata->rx_count = 0;
+ st_gdata->rx_state = ST_W4_PACKET_TYPE;
+ kfree_skb(st_gdata->rx_skb);
+ st_gdata->rx_skb = NULL;
+ spin_unlock(&st_gdata->lock);
+
+ ST_DRV_DBG("%s: done ", __func__);
+}
+
+static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
+ char *flags, int count)
+{
+#ifdef VERBOSE
+ long i;
+ printk(KERN_ERR "incoming data...\n");
+ for (i = 0; i < count; i++)
+ printk(" %x", data[i]);
+ printk(KERN_ERR "\n.. data end\n");
+#endif
+
+ /*
+ * if fw download is in progress then route incoming data
+ * to KIM for validation
+ */
+ spin_lock(&st_gdata->lock);
+ st_recv(data, count);
+ spin_unlock(&st_gdata->lock);
+
+ ST_DRV_VER("done %s", __func__);
+}
+
+/* wake-up function called in from the TTY layer
+ * inside the internal wakeup function will be called
+ */
+static void st_tty_wakeup(struct tty_struct *tty)
+{
+ ST_DRV_DBG("%s ", __func__);
+ /* don't do an wakeup for now */
+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+
+ /* call our internal wakeup */
+ st_tx_wakeup((void *)st_gdata);
+}
+
+static void st_tty_flush_buffer(struct tty_struct *tty)
+{
+ ST_DRV_DBG("%s ", __func__);
+
+ kfree_skb(st_gdata->tx_skb);
+ st_gdata->tx_skb = NULL;
+
+ tty->ops->flush_buffer(tty);
+ return;
+}
+
+/********************************************************************/
+static int __init st_core_init(void)
+{
+ long err;
+ static struct tty_ldisc_ops *st_ldisc_ops;
+
+ /* populate and register to TTY line discipline */
+ st_ldisc_ops = kzalloc(sizeof(*st_ldisc_ops), GFP_KERNEL);
+ if (!st_ldisc_ops) {
+ ST_DRV_ERR("no mem to allocate");
+ return -ENOMEM;
+ }
+
+ st_ldisc_ops->magic = TTY_LDISC_MAGIC;
+ st_ldisc_ops->name = "n_st"; /*"n_hci"; */
+ st_ldisc_ops->open = st_tty_open;
+ st_ldisc_ops->close = st_tty_close;
+ st_ldisc_ops->receive_buf = st_tty_receive;
+ st_ldisc_ops->write_wakeup = st_tty_wakeup;
+ st_ldisc_ops->flush_buffer = st_tty_flush_buffer;
+ st_ldisc_ops->owner = THIS_MODULE;
+
+ err = tty_register_ldisc(N_SHARED, st_ldisc_ops);
+ if (err) {
+ ST_DRV_ERR("error registering %d line discipline %ld",
+ N_SHARED, err);
+ kfree(st_ldisc_ops);
+ return err;
+ }
+ ST_DRV_DBG("registered n_shared line discipline");
+
+ st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL);
+ if (!st_gdata) {
+ ST_DRV_ERR("memory allocation failed");
+ err = tty_unregister_ldisc(N_SHARED);
+ if (err)
+ ST_DRV_ERR("unable to un-register ldisc %ld", err);
+ kfree(st_ldisc_ops);
+ err = -ENOMEM;
+ return err;
+ }
+
+ /* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's
+ * will be pushed in this queue for actual transmission.
+ */
+ skb_queue_head_init(&st_gdata->txq);
+ skb_queue_head_init(&st_gdata->tx_waitq);
+
+ /* Locking used in st_int_enqueue() to avoid multiple execution */
+ spin_lock_init(&st_gdata->lock);
+
+ /* ldisc_ops ref to be only used in __exit of module */
+ st_gdata->ldisc_ops = st_ldisc_ops;
+
+ err = st_kim_init();
+ if (err) {
+ ST_DRV_ERR("error during kim initialization(%ld)", err);
+ kfree(st_gdata);
+ err = tty_unregister_ldisc(N_SHARED);
+ if (err)
+ ST_DRV_ERR("unable to un-register ldisc");
+ kfree(st_ldisc_ops);
+ return -1;
+ }
+
+ err = st_ll_init();
+ if (err) {
+ ST_DRV_ERR("error during st_ll initialization(%ld)", err);
+ err = st_kim_deinit();
+ kfree(st_gdata);
+ err = tty_unregister_ldisc(N_SHARED);
+ if (err)
+ ST_DRV_ERR("unable to un-register ldisc");
+ kfree(st_ldisc_ops);
+ return -1;
+ }
+ return 0;
+}
+
+static void __exit st_core_exit(void)
+{
+ long err;
+ /* internal module cleanup */
+ err = st_ll_deinit();
+ if (err)
+ ST_DRV_ERR("error during deinit of ST LL %ld", err);
+ err = st_kim_deinit();
+ if (err)
+ ST_DRV_ERR("error during deinit of ST KIM %ld", err);
+
+ if (st_gdata != NULL) {
+ /* Free ST Tx Qs and skbs */
+ skb_queue_purge(&st_gdata->txq);
+ skb_queue_purge(&st_gdata->tx_waitq);
+ kfree_skb(st_gdata->rx_skb);
+ kfree_skb(st_gdata->tx_skb);
+ /* TTY ldisc cleanup */
+ err = tty_unregister_ldisc(N_SHARED);
+ if (err)
+ ST_DRV_ERR("unable to un-register ldisc %ld", err);
+ kfree(st_gdata->ldisc_ops);
+ /* free the global data pointer */
+ kfree(st_gdata);
+ }
+}
+
+module_init(st_core_init);
+module_exit(st_core_exit);
+MODULE_AUTHOR("Pavan Savoy <pavan_savoy@ti.com>");
+MODULE_DESCRIPTION("Shared Transport Driver for TI BT/FM/GPS combo chips ");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ti-st/st_core.h b/drivers/misc/ti-st/st_core.h
new file mode 100644
index 0000000..b88d1e7
--- /dev/null
+++ b/drivers/misc/ti-st/st_core.h
@@ -0,0 +1,92 @@
+/*
+ * Shared Transport Core header file
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef ST_CORE_H
+#define ST_CORE_H
+
+#include <linux/skbuff.h>
+#include "st.h"
+
+/* states of protocol list */
+#define ST_NOTEMPTY 1
+#define ST_EMPTY 0
+
+/*
+ * possible st_states
+ */
+#define ST_INITIALIZING 1
+#define ST_REG_IN_PROGRESS 2
+#define ST_REG_PENDING 3
+#define ST_WAITING_FOR_RESP 4
+
+/*
+ * local data required for ST/KIM/ST-HCI-LL
+ */
+struct st_data_s {
+ unsigned long st_state;
+/*
+ * an instance of tty_struct & ldisc ops to move around
+ */
+ struct tty_struct *tty;
+ struct tty_ldisc_ops *ldisc_ops;
+/*
+ * the tx skb -
+ * if the skb is already dequeued and the tty failed to write the same
+ * maintain the skb to write in the next transaction
+ */
+ struct sk_buff *tx_skb;
+#define ST_TX_SENDING 1
+#define ST_TX_WAKEUP 2
+ unsigned long tx_state;
+/*
+ * list of protocol registered
+ */
+ struct st_proto_s *list[ST_MAX];
+/*
+ * lock
+ */
+ unsigned long rx_state;
+ unsigned long rx_count;
+ struct sk_buff *rx_skb;
+ struct sk_buff_head txq, tx_waitq;
+ spinlock_t lock; /* ST LL state lock */
+};
+
+/* point this to tty->driver->write or tty->ops->write
+ * depending upon the kernel version
+ */
+int st_int_write(const unsigned char *, int);
+/* internal write function, passed onto protocol drivers
+ * via the write function ptr of protocol struct
+ */
+long st_write(struct sk_buff *);
+/* function to be called from ST-LL
+ */
+void st_ll_send_frame(enum proto_type, struct sk_buff *);
+/* internal wake up function */
+void st_tx_wakeup(struct st_data_s *st_data);
+
+#define GPS_STUB_TEST
+#ifdef GPS_STUB_TEST
+int gps_chrdrv_stub_write(const unsigned char*, int);
+void gps_chrdrv_stub_init(void);
+#endif
+
+#endif /*ST_CORE_H */
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
new file mode 100644
index 0000000..971e0b3
--- /dev/null
+++ b/drivers/misc/ti-st/st_kim.c
@@ -0,0 +1,722 @@
+/*
+ * Shared Transport Line discipline driver Core
+ * Init Manager module responsible for GPIO control
+ * and firmware download
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/gpio.h>
+
+#include <linux/sched.h>
+
+#include "st_kim.h"
+/* understand BT events for fw response */
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+/* all debug macros go in here */
+#define ST_KIM_ERR(fmt, arg...) printk(KERN_ERR "(stk):"fmt"\n" , ## arg)
+#if defined(DEBUG) /* limited debug messages */
+#define ST_KIM_DBG(fmt, arg...) printk(KERN_INFO "(stk):"fmt"\n" , ## arg)
+#define ST_KIM_VER(fmt, arg...)
+#elif defined(VERBOSE) /* very verbose */
+#define ST_KIM_DBG(fmt, arg...) printk(KERN_INFO "(stk):"fmt"\n" , ## arg)
+#define ST_KIM_VER(fmt, arg...) printk(KERN_INFO "(stk):"fmt"\n" , ## arg)
+#else /* error msgs only */
+#define ST_KIM_DBG(fmt, arg...)
+#define ST_KIM_VER(fmt, arg...)
+#endif
+
+static int kim_probe(struct platform_device *pdev);
+static int kim_remove(struct platform_device *pdev);
+static ssize_t show_pid(struct device *dev, struct device_attribute
+ *attr, char *buf);
+static ssize_t store_pid(struct device *dev, struct device_attribute
+ *devattr, char *buf, size_t count);
+static ssize_t show_list(struct device *dev, struct device_attribute
+ *attr, char *buf);
+/* KIM platform device driver structure */
+static struct platform_driver kim_platform_driver = {
+ .probe = kim_probe,
+ .remove = kim_remove,
+ /* TODO: ST driver power management during suspend/resume ?
+ */
+#if 0
+ .suspend = kim_suspend,
+ .resume = kim_resume,
+#endif
+ .driver = {
+ .name = "kim",
+ .owner = THIS_MODULE,
+ },
+};
+
+/* structures specific for sysfs entries */
+static struct kobj_attribute pid_attr =
+__ATTR(pid, 0644, (void *)show_pid, (void *)store_pid);
+
+static struct kobj_attribute list_protocols =
+__ATTR(protocols, 0444, (void *)show_list, NULL);
+
+static struct attribute *uim_attrs[] = {
+ &pid_attr.attr,
+ /* add more debug sysfs entries */
+ &list_protocols.attr,
+ NULL,
+};
+
+static struct attribute_group uim_attr_grp = {
+ .attrs = uim_attrs,
+};
+
+/* strings to be used for rfkill entries and by
+ * ST Core to be used for sysfs debug entry
+ */
+#define PROTO_ENTRY(type, name) name
+const unsigned char *protocol_names[] = {
+ PROTO_ENTRY(ST_BT, "Bluetooth"),
+ PROTO_ENTRY(ST_FM, "FM"),
+ PROTO_ENTRY(ST_GPS, "GPS"),
+};
+
+static struct kim_data_s *kim_gdata;
+
+/**********************************************************************/
+/* internal functions */
+
+/*
+ * function to return whether the firmware response was proper
+ * in case of error don't complete so that waiting for proper
+ * response times out
+ */
+void validate_firmware_response(struct sk_buff *skb)
+{
+ if (unlikely(skb->data[5] != 0)) {
+ ST_KIM_ERR("no proper response during fw download");
+ ST_KIM_ERR("data6 %x", skb->data[5]);
+ return; /* keep waiting for the proper response */
+ }
+ /* becos of all the script being downloaded */
+ complete_all(&kim_gdata->kim_rcvd);
+ kfree_skb(skb);
+}
+
+/* check for data len received inside kim_int_recv
+ * most often hit the last case to update state to waiting for data
+ */
+static inline int kim_check_data_len(int len)
+{
+ register int room = skb_tailroom(kim_gdata->rx_skb);
+
+ ST_KIM_DBG("len %d room %d", len, room);
+
+ if (!len) {
+ validate_firmware_response(kim_gdata->rx_skb);
+ } else if (len > room) {
+ /* Received packet's payload length is larger.
+ * We can't accommodate it in created skb.
+ */
+ ST_KIM_ERR("Data length is too large len %d room %d", len,
+ room);
+ kfree_skb(kim_gdata->rx_skb);
+ } else {
+ /* Packet header has non-zero payload length and
+ * we have enough space in created skb. Lets read
+ * payload data */
+ kim_gdata->rx_state = ST_BT_W4_DATA;
+ kim_gdata->rx_count = len;
+ return len;
+ }
+
+ /* Change ST LL state to continue to process next
+ * packet */
+ kim_gdata->rx_state = ST_W4_PACKET_TYPE;
+ kim_gdata->rx_skb = NULL;
+ kim_gdata->rx_count = 0;
+
+ return 0;
+}
+
+/* receive function called during firmware download
+ * - firmware download responses on different UART drivers
+ * have been observed to come in bursts of different
+ * tty_receive and hence the logic
+ */
+void kim_int_recv(const unsigned char *data, long count)
+{
+ register char *ptr;
+ struct hci_event_hdr *eh;
+ register int len = 0, type = 0;
+
+ ST_KIM_DBG("%s", __func__);
+ /* Decode received bytes here */
+ ptr = (char *)data;
+ if (unlikely(ptr == NULL)) {
+ ST_KIM_ERR(" received null from TTY ");
+ return;
+ }
+ while (count) {
+ if (kim_gdata->rx_count) {
+ len = min_t(unsigned int, kim_gdata->rx_count, count);
+ memcpy(skb_put(kim_gdata->rx_skb, len), ptr, len);
+ kim_gdata->rx_count -= len;
+ count -= len;
+ ptr += len;
+
+ if (kim_gdata->rx_count)
+ continue;
+
+ /* Check ST RX state machine , where are we? */
+ switch (kim_gdata->rx_state) {
+ /* Waiting for complete packet ? */
+ case ST_BT_W4_DATA:
+ ST_KIM_DBG("Complete pkt received");
+ validate_firmware_response(kim_gdata->rx_skb);
+ kim_gdata->rx_state = ST_W4_PACKET_TYPE;
+ kim_gdata->rx_skb = NULL;
+ continue;
+ /* Waiting for Bluetooth event header ? */
+ case ST_BT_W4_EVENT_HDR:
+ eh = (struct hci_event_hdr *)kim_gdata->
+ rx_skb->data;
+ ST_KIM_DBG("Event header: evt 0x%2.2x"
+ "plen %d", eh->evt, eh->plen);
+ kim_check_data_len(eh->plen);
+ continue;
+ } /* end of switch */
+ } /* end of if rx_state */
+ switch (*ptr) {
+ /* Bluetooth event packet? */
+ case HCI_EVENT_PKT:
+ ST_KIM_DBG("Event packet");
+ kim_gdata->rx_state = ST_BT_W4_EVENT_HDR;
+ kim_gdata->rx_count = HCI_EVENT_HDR_SIZE;
+ type = HCI_EVENT_PKT;
+ break;
+ default:
+ ST_KIM_DBG("unknown packet");
+ ptr++;
+ count--;
+ continue;
+ } /* end of switch *ptr */
+ ptr++;
+ count--;
+ kim_gdata->rx_skb =
+ bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!kim_gdata->rx_skb) {
+ ST_KIM_ERR("can't allocate mem for new packet");
+ kim_gdata->rx_state = ST_W4_PACKET_TYPE;
+ kim_gdata->rx_count = 0;
+ return;
+ } /* not necessary in this case */
+ bt_cb(kim_gdata->rx_skb)->pkt_type = type;
+ } /* end of while count */
+ ST_KIM_DBG("done %s", __func__);
+ return;
+}
+
+static long read_local_version(char *bts_scr_name)
+{
+ unsigned short version = 0, chip = 0, min_ver = 0, maj_ver = 0;
+ char read_ver_cmd[] = { 0x01, 0x01, 0x10, 0x00 };
+
+ ST_KIM_DBG("%s", __func__);
+
+ INIT_COMPLETION(kim_gdata->kim_rcvd);
+ if (4 != st_int_write(read_ver_cmd, 4)) {
+ ST_KIM_ERR("kim: couldn't write 4 bytes");
+ return ST_ERR_FAILURE;
+ }
+
+ if (!wait_for_completion_timeout
+ (&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
+ ST_KIM_ERR(" waiting for ver info- timed out ");
+ return ST_ERR_FAILURE;
+ }
+
+ version =
+ MAKEWORD(kim_gdata->resp_buffer[13], kim_gdata->resp_buffer[14]);
+ chip = (version & 0x7C00) >> 10;
+ min_ver = (version & 0x007F);
+ maj_ver = (version & 0x0380) >> 7;
+
+ if (version & 0x8000)
+ maj_ver |= 0x0008;
+
+ sprintf(bts_scr_name, "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver);
+ ST_KIM_DBG("%s", bts_scr_name);
+ return ST_SUCCESS;
+}
+
+/* internal function which parses through the .bts firmware script file
+ * intreprets SEND, DELAY actions only as of now
+ */
+static long download_firmware(void)
+{
+ long err = ST_SUCCESS;
+ long len = 0;
+ register unsigned char *ptr = NULL;
+ register unsigned char *action_ptr = NULL;
+ unsigned char bts_scr_name[30] = { 0 }; /* 30 char long bts scr name? */
+
+ ST_KIM_VER("%s", __func__);
+
+ err = read_local_version(bts_scr_name);
+ if (err != ST_SUCCESS) {
+ ST_KIM_ERR("kim: failed to read local ver");
+ return err;
+ }
+ err =
+ request_firmware(&kim_gdata->fw_entry, bts_scr_name,
+ &kim_gdata->kim_pdev->dev);
+ if (unlikely((err != 0) || (kim_gdata->fw_entry->data == NULL) ||
+ (kim_gdata->fw_entry->size == 0))) {
+ ST_KIM_ERR(" request_firmware failed(errno %ld) for %s", err,
+ bts_scr_name);
+ return ST_ERR_FAILURE;
+ }
+ ptr = (void *)kim_gdata->fw_entry->data;
+ len = kim_gdata->fw_entry->size;
+ /* bts_header to remove out magic number and
+ * version
+ */
+ ptr += sizeof(struct bts_header);
+ len -= sizeof(struct bts_header);
+
+ while (len > 0 && ptr) {
+ ST_KIM_VER(" action size %d, type %d ",
+ ((struct bts_action *)ptr)->size,
+ ((struct bts_action *)ptr)->type);
+
+ switch (((struct bts_action *)ptr)->type) {
+ case ACTION_SEND_COMMAND: /* action send */
+ action_ptr = &(((struct bts_action *)ptr)->data[0]);
+ if (unlikely
+ (((struct hci_command *)action_ptr)->opcode ==
+ 0xFF36)) {
+ /* ignore remote change
+ * baud rate HCI VS command */
+ ST_KIM_ERR
+ (" change remote baud\
+ rate command in firmware");
+ break;
+ }
+
+ INIT_COMPLETION(kim_gdata->kim_rcvd);
+ err = st_int_write(((struct bts_action_send *)
+ action_ptr)->data,
+ ((struct bts_action *)ptr)->size);
+ if (unlikely(err < 0)) {
+ release_firmware(kim_gdata->fw_entry);
+ return ST_ERR_FAILURE;
+ }
+ if (!wait_for_completion_timeout
+ (&kim_gdata->kim_rcvd,
+ msecs_to_jiffies(CMD_RESP_TIME))) {
+ ST_KIM_ERR
+ (" response timeout during fw download ");
+ /* timed out */
+ release_firmware(kim_gdata->fw_entry);
+ return ST_ERR_FAILURE;
+ }
+ break;
+ case ACTION_DELAY: /* sleep */
+ ST_KIM_DBG("sleep command in scr");
+ action_ptr = &(((struct bts_action *)ptr)->data[0]);
+ mdelay(((struct bts_action_delay *)action_ptr)->msec);
+ break;
+ }
+ len =
+ len - (sizeof(struct bts_action) +
+ ((struct bts_action *)ptr)->size);
+ ptr =
+ ptr + sizeof(struct bts_action) +
+ ((struct bts_action *)ptr)->size;
+ }
+ /* fw download complete */
+ release_firmware(kim_gdata->fw_entry);
+ return ST_SUCCESS;
+}
+
+/**********************************************************************/
+/* functions called from ST core */
+
+/* function to toggle the GPIO
+ * needs to know whether the GPIO is active high or active low
+ */
+void st_kim_chip_toggle(enum proto_type type, enum kim_gpio_state state)
+{
+ ST_KIM_DBG(" %s ", __func__);
+
+ if (kim_gdata->gpios[type] == -1) {
+ ST_KIM_DBG(" gpio not requested for protocol %s",
+ protocol_names[type]);
+ return;
+ }
+ switch (type) {
+ case ST_BT:
+ /*Do Nothing */
+ break;
+
+ case ST_FM:
+ if (state == KIM_GPIO_ACTIVE)
+ gpio_set_value(kim_gdata->gpios[ST_FM], GPIO_LOW);
+ else
+ gpio_set_value(kim_gdata->gpios[ST_FM], GPIO_HIGH);
+ break;
+
+ case ST_GPS:
+ if (state == KIM_GPIO_ACTIVE)
+ gpio_set_value(kim_gdata->gpios[ST_GPS], GPIO_HIGH);
+ else
+ gpio_set_value(kim_gdata->gpios[ST_GPS], GPIO_LOW);
+ break;
+
+ case ST_MAX:
+ default:
+ break;
+ }
+
+ return;
+}
+
+/* called from ST Core, when REG_IN_PROGRESS (registration in progress)
+ * can be because of
+ * 1. response to read local version
+ * 2. during send/recv's of firmware download
+ */
+void st_kim_recv(const unsigned char *data, long count)
+{
+ ST_KIM_DBG(" %s ", __func__);
+ /* copy to local buffer */
+ if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) {
+ /* must be the read_ver_cmd */
+ memcpy(kim_gdata->resp_buffer, data, count);
+ complete_all(&kim_gdata->kim_rcvd);
+ return;
+ } else {
+ kim_int_recv(data, count);
+ /* either completes or times out */
+ }
+ return;
+}
+
+/* to signal completion of line discipline installation
+ * called from ST Core, upon tty_open
+ */
+void st_kim_complete(void)
+{
+ complete(&kim_gdata->ldisc_installed);
+}
+
+/* called from ST Core upon 1st registration
+*/
+long st_kim_start(void)
+{
+ long err = ST_SUCCESS;
+ long retry = POR_RETRY_COUNT;
+ ST_KIM_DBG(" %s", __func__);
+
+ do {
+ /* Configure BT nShutdown to HIGH state */
+ gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+ mdelay(5); /* FIXME: a proper toggle */
+ gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_HIGH);
+ mdelay(100);
+
+ /* re-initialize the completion */
+ INIT_COMPLETION(kim_gdata->ldisc_installed);
+ /* send signal to UIM */
+ err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 0);
+ if (err != 0) {
+ ST_KIM_VER(" sending SIGUSR2 to uim failed %ld", err);
+ err = ST_ERR_FAILURE;
+ continue;
+ }
+ /* wait for ldisc to be installed */
+ err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
+ msecs_to_jiffies(LDISC_TIME));
+ if (!err) { /* timeout */
+ ST_KIM_ERR("line disc installation timed out ");
+ err = ST_ERR_FAILURE;
+ continue;
+ } else {
+ /* ldisc installed now */
+ ST_KIM_DBG(" line discipline installed ");
+ err = download_firmware();
+ if (err != ST_SUCCESS) {
+ ST_KIM_ERR("download firmware failed");
+ continue;
+ } else { /* on success don't retry */
+ break;
+ }
+ }
+ } while (retry--);
+ return err;
+}
+
+/* called from ST Core, on the last un-registration
+*/
+long st_kim_stop(void)
+{
+ long err = ST_SUCCESS;
+
+ INIT_COMPLETION(kim_gdata->ldisc_installed);
+ /* send signal to UIM */
+ err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 1);
+ if (err != 0) {
+ ST_KIM_ERR("sending SIGUSR2 to uim failed %ld", err);
+ return ST_ERR_FAILURE;
+ }
+
+ /* wait for ldisc to be un-installed */
+ err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
+ msecs_to_jiffies(LDISC_TIME));
+ if (!err) { /* timeout */
+ ST_KIM_ERR(" timed out waiting for ldisc to be un-installed");
+ return ST_ERR_FAILURE;
+ }
+
+ /* By default configure BT nShutdown to LOW state */
+ gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+ mdelay(1);
+ gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_HIGH);
+ mdelay(1);
+ gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+ return err;
+}
+
+/**********************************************************************/
+/* functions called from subsystems */
+
+/* called when sysfs entry is written to */
+static ssize_t store_pid(struct device *dev, struct device_attribute
+ *devattr, char *buf, size_t count)
+{
+ ST_KIM_DBG("%s: pid %s ", __func__, buf);
+ sscanf(buf, "%ld", &kim_gdata->uim_pid);
+ /* to be made use by kim_start to signal SIGUSR2
+ */
+ return strlen(buf);
+}
+
+/* called when sysfs entry is read from */
+static ssize_t show_pid(struct device *dev, struct device_attribute
+ *attr, char *buf)
+{
+ sprintf(buf, "%ld", kim_gdata->uim_pid);
+ return strlen(buf);
+}
+
+/* called when sysfs entry is read from */
+static ssize_t show_list(struct device *dev, struct device_attribute
+ *attr, char *buf)
+{
+ kim_st_list_protocols(buf);
+ return strlen(buf);
+}
+
+#ifdef LEGACY_RFKILL_SUPPORT
+/* function called from rfkill subsystem, when someone from
+ * user space would write 0/1 on the sysfs entry
+ * /sys/class/rfkill/rfkill0,1,3/state
+ */
+static int kim_toggle_radio(void *data, enum rfkill_state state)
+{
+ enum proto_type type = (enum proto_type)data;
+ ST_KIM_DBG(" %s ", __func__);
+ if (type == ST_BT) {
+ /* Configure BT nShutdown to HIGH state */
+ gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+ mdelay(1); /* FIXME: a proper toggle */
+ gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_HIGH);
+
+ if (state == RFKILL_STATE_SOFT_BLOCKED)
+ gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+ }
+
+ switch (state) {
+ case RFKILL_STATE_UNBLOCKED:
+ st_kim_chip_toggle(type, KIM_GPIO_ACTIVE);
+ break;
+ case RFKILL_STATE_SOFT_BLOCKED:
+ st_kim_chip_toggle(type, KIM_GPIO_INACTIVE);
+ break;
+ default:
+ printk(KERN_ERR "invalid rfkill state %d", state);
+ }
+ return ST_SUCCESS;
+}
+#endif
+
+/**********************************************************************/
+/* functions called from platform device driver subsystem
+ * need to have a relevant platform device entry in the platform's
+ * board-*.c file
+ */
+
+static int kim_probe(struct platform_device *pdev)
+{
+ long status;
+ long proto;
+ long *gpios = pdev->dev.platform_data;
+
+ for (proto = 0; proto < ST_MAX; proto++) {
+ kim_gdata->gpios[proto] = gpios[proto];
+ ST_KIM_VER(" %ld gpio to be requested", gpios[proto]);
+ }
+
+ for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
+ /* Claim the Bluetooth/FM/GPIO
+ * nShutdown gpio from the system
+ */
+ status = gpio_request(gpios[proto], "kim");
+ if (unlikely(status)) {
+ ST_KIM_ERR(" gpio %ld request failed ", gpios[proto]);
+ proto -= 1;
+ while (proto >= 0) {
+ if (gpios[proto] != -1)
+ gpio_free(gpios[proto]);
+ }
+ return status;
+ }
+
+ /* Configure nShutdown GPIO as output=0 */
+ status =
+ gpio_direction_output(gpios[proto], 0);
+ if (unlikely(status)) {
+ ST_KIM_ERR(" unable to configure gpio %ld",
+ gpios[proto]);
+ proto -= 1;
+ while (proto >= 0) {
+ if (gpios[proto] != -1)
+ gpio_free(gpios[proto]);
+ }
+ return status;
+ }
+ }
+ /* pdev to contain BT, FM and GPS enable/N-Shutdown GPIOs
+ * execute request_gpio, set output direction
+ */
+ kim_gdata->kim_kobj = kobject_create_and_add("uim", NULL);
+ /* create the sysfs entry for UIM to put in pid */
+ if (sysfs_create_group(kim_gdata->kim_kobj, &uim_attr_grp)) {
+ ST_KIM_ERR(" sysfs entry creation failed");
+ kobject_put(kim_gdata->kim_kobj);
+ /* free requested GPIOs and fail probe */
+ for (proto = ST_BT; proto < ST_MAX; proto++) {
+ if (gpios[proto] != -1)
+ gpio_free(gpios[proto]);
+ }
+ return -1; /* fail insmod */
+ }
+
+ ST_KIM_DBG(" sysfs entry created ");
+
+ /* get reference of pdev for request_firmware
+ */
+ kim_gdata->kim_pdev = pdev;
+ init_completion(&kim_gdata->kim_rcvd);
+ init_completion(&kim_gdata->ldisc_installed);
+#ifdef LEGACY_RFKILL_SUPPORT
+ for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
+ /* TODO: should all types be rfkill_type_bt ? */
+ kim_gdata->rfkill[proto] = rfkill_allocate(&pdev->dev,
+ RFKILL_TYPE_BLUETOOTH);
+ if (kim_gdata->rfkill[proto] == NULL) {
+ ST_KIM_ERR("cannot create rfkill entry for gpio %ld",
+ gpios[proto]);
+ continue;
+ }
+ kim_gdata->rfkill[proto]->name = protocol_names[proto];
+ kim_gdata->rfkill[proto]->state = RFKILL_STATE_SOFT_BLOCKED;
+ kim_gdata->rfkill[proto]->user_claim_unsupported = 1;
+ kim_gdata->rfkill[proto]->user_claim = 0;
+ /* sending protocol id instead of gpio */
+ kim_gdata->rfkill[proto]->data = (void *)proto;
+ kim_gdata->rfkill[proto]->toggle_radio = kim_toggle_radio;
+ status = rfkill_register(kim_gdata->rfkill[proto]);
+ if (unlikely(status)) {
+ ST_KIM_ERR("rfkill registration failed for gpio %ld",
+ gpios[proto]);
+ rfkill_free(kim_gdata->rfkill[proto]);
+ continue;
+ }
+ ST_KIM_DBG("rfkill entry created for %ld", gpios[proto]);
+ }
+#endif
+ return ST_SUCCESS;
+}
+
+static int kim_remove(struct platform_device *pdev)
+{
+ /* free the GPIOs requested
+ */
+ long *gpios = pdev->dev.platform_data;
+ long proto;
+
+ for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
+ /* Claim the Bluetooth/FM/GPIO
+ * nShutdown gpio from the system
+ */
+ gpio_free(gpios[proto]);
+#ifdef LEGACY_RFKILL_SUPPORT
+ rfkill_unregister(kim_gdata->rfkill[proto]);
+ kim_gdata->rfkill[proto] = NULL;
+#endif
+ }
+ ST_KIM_DBG("kim: GPIO Freed");
+ /* delete the sysfs entries */
+ sysfs_remove_group(kim_gdata->kim_kobj, &uim_attr_grp);
+ kobject_put(kim_gdata->kim_kobj);
+ kim_gdata->kim_pdev = NULL;
+ return ST_SUCCESS;
+}
+
+/**********************************************************************/
+/* entry point for ST KIM module, called in from ST Core */
+
+long st_kim_init(void)
+{
+ long ret = ST_SUCCESS;
+ kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_ATOMIC);
+ if (!kim_gdata) {
+ ST_KIM_ERR("no mem to allocate");
+ return -ENOMEM;
+ }
+ ret = platform_driver_register(&kim_platform_driver);
+ if (ret != 0) {
+ ST_KIM_ERR("platform drv registration failed");
+ return ST_ERR_FAILURE;
+ }
+ return ST_SUCCESS;
+}
+
+long st_kim_deinit(void)
+{
+ /* the following returns void */
+ platform_driver_unregister(&kim_platform_driver);
+ kfree(kim_gdata);
+ kim_gdata = NULL;
+ return ST_SUCCESS;
+}
diff --git a/drivers/misc/ti-st/st_kim.h b/drivers/misc/ti-st/st_kim.h
new file mode 100644
index 0000000..8953290
--- /dev/null
+++ b/drivers/misc/ti-st/st_kim.h
@@ -0,0 +1,151 @@
+/*
+ * Shared Transport Line discipline driver Core
+ * Init Manager Module header file
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef ST_KIM_H
+#define ST_KIM_H
+
+#include <linux/types.h>
+#include "st.h"
+#include "st_core.h"
+#include "st_ll.h"
+#include <linux/rfkill.h>
+
+/* time in msec to wait for
+ * line discipline to be installed
+ */
+#define LDISC_TIME 500
+#define CMD_RESP_TIME 500
+#define MAKEWORD(a, b) ((unsigned short)(((unsigned char)(a)) \
+ | ((unsigned short)((unsigned char)(b))) << 8))
+
+#define GPIO_HIGH 1
+#define GPIO_LOW 0
+
+/* the Power-On-Reset logic, requires to attempt
+ * to download firmware onto chip more than once
+ * since the self-test for chip takes a while
+ */
+#define POR_RETRY_COUNT 5
+/*
+ * legacy rfkill support where-in 3 rfkill
+ * devices are created for the 3 gpios
+ * that ST has requested
+#define LEGACY_RFKILL_SUPPORT
+ */
+/*
+ * header file for ST provided by KIM
+ */
+struct kim_data_s {
+ long uim_pid;
+ struct platform_device *kim_pdev;
+ struct completion kim_rcvd, ldisc_installed;
+ /* MAX len of the .bts firmware script name */
+ char resp_buffer[30];
+ const struct firmware *fw_entry;
+ long gpios[ST_MAX];
+ struct kobject *kim_kobj;
+/* used by kim_int_recv to validate fw response */
+ unsigned long rx_state;
+ unsigned long rx_count;
+ struct sk_buff *rx_skb;
+#ifdef LEGACY_RFKILL_SUPPORT
+ struct rfkill *rfkill[ST_MAX];
+#endif
+};
+
+long st_kim_init(void);
+long st_kim_deinit(void);
+
+long st_kim_start(void);
+long st_kim_stop(void);
+/*
+ * called from st_tty_receive to authenticate fw_download
+ */
+void st_kim_recv(const unsigned char *, long count);
+
+void st_kim_chip_toggle(enum proto_type, enum kim_gpio_state);
+
+void st_kim_complete(void);
+
+/* function called from ST KIM to ST Core, to
+ * list out the protocols registered
+ */
+void kim_st_list_protocols(char *);
+
+/*
+ * BTS headers
+ */
+#define ACTION_SEND_COMMAND 1
+#define ACTION_WAIT_EVENT 2
+#define ACTION_SERIAL 3
+#define ACTION_DELAY 4
+#define ACTION_RUN_SCRIPT 5
+#define ACTION_REMARKS 6
+
+/*
+ * * BRF Firmware header
+ * */
+struct bts_header {
+ uint32_t magic;
+ uint32_t version;
+ uint8_t future[24];
+ uint8_t actions[0];
+} __attribute__ ((packed));
+
+/*
+ * * BRF Actions structure
+ * */
+struct bts_action {
+ uint16_t type;
+ uint16_t size;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+struct bts_action_send {
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+struct bts_action_wait {
+ uint32_t msec;
+ uint32_t size;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+struct bts_action_delay {
+ uint32_t msec;
+} __attribute__ ((packed));
+
+struct bts_action_serial {
+ uint32_t baud;
+ uint32_t flow_control;
+} __attribute__ ((packed));
+
+/* for identifying the change speed HCI VS
+ * command
+ */
+struct hci_command {
+ uint8_t prefix;
+ uint16_t opcode;
+ uint8_t plen;
+ uint32_t speed;
+} __attribute__ ((packed));
+
+
+#endif /* ST_KIM_H */
diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c
new file mode 100644
index 0000000..c6c605c
--- /dev/null
+++ b/drivers/misc/ti-st/st_ll.c
@@ -0,0 +1,174 @@
+/*
+ * Shared Transport driver
+ * HCI-LL module responsible for TI proprietary HCI_LL protocol
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "st_ll.h"
+
+/* all debug macros go in here */
+#define ST_LL_ERR(fmt, arg...) printk(KERN_ERR "(stll):"fmt"\n" , ## arg)
+#if defined(DEBUG) /* limited debug messages */
+#define ST_LL_DBG(fmt, arg...) printk(KERN_INFO "(stll):"fmt"\n" , ## arg)
+#define ST_LL_VER(fmt, arg...)
+#elif defined(VERBOSE) /* very verbose */
+#define ST_LL_DBG(fmt, arg...) printk(KERN_INFO "(stll):"fmt"\n" , ## arg)
+#define ST_LL_VER(fmt, arg...) printk(KERN_INFO "(stll):"fmt"\n" , ## arg)
+#else /* error msgs only */
+#define ST_LL_DBG(fmt, arg...)
+#define ST_LL_VER(fmt, arg...)
+#endif
+
+static struct ll_struct_s *ll;
+
+/**********************************************************************/
+/* internal functions */
+static void send_ll_cmd(unsigned char cmd)
+{
+
+ ST_LL_DBG("%s: writing %x", __func__, cmd);
+ st_int_write(&cmd, 1);
+ return;
+}
+
+static void ll_device_want_to_sleep(void)
+{
+ ST_LL_DBG("%s", __func__);
+ /* sanity check */
+ if (ll->ll_state != ST_LL_AWAKE)
+ ST_LL_ERR("ERR hcill: ST_LL_GO_TO_SLEEP_IND"
+ "in state %ld", ll->ll_state);
+
+ spin_lock(&ll->lock);
+ send_ll_cmd(LL_SLEEP_ACK);
+ /* update state */
+ ll->ll_state = ST_LL_ASLEEP;
+ spin_unlock(&ll->lock);
+}
+
+static void ll_device_want_to_wakeup(void)
+{
+ spin_lock(&ll->lock);
+ /* diff actions in diff states */
+ switch (ll->ll_state) {
+ case ST_LL_ASLEEP:
+ send_ll_cmd(LL_WAKE_UP_ACK); /* send wake_ack */
+ break;
+ case ST_LL_ASLEEP_TO_AWAKE:
+ /* duplicate wake_ind */
+ ST_LL_ERR("duplicate wake_ind while waiting for Wake ack");
+ break;
+ case ST_LL_AWAKE:
+ /* duplicate wake_ind */
+ ST_LL_ERR("duplicate wake_ind already AWAKE");
+ break;
+ case ST_LL_AWAKE_TO_ASLEEP:
+ /* duplicate wake_ind */
+ ST_LL_ERR("duplicate wake_ind");
+ break;
+ }
+ /* update state */
+ ll->ll_state = ST_LL_AWAKE;
+ spin_unlock(&ll->lock);
+}
+
+/**********************************************************************/
+/* functions invoked by ST Core */
+
+/* called when ST Core wants to
+ * enable ST LL */
+void st_ll_enable(void)
+{
+ ll->ll_state = ST_LL_AWAKE;
+}
+
+/* called when ST Core /local module wants to
+ * disable ST LL */
+void st_ll_disable(void)
+{
+ ll->ll_state = ST_LL_INVALID;
+}
+
+/* called when ST Core wants to update the state */
+void st_ll_wakeup(void)
+{
+ if (likely(ll->ll_state != ST_LL_AWAKE)) {
+ send_ll_cmd(LL_WAKE_UP_IND); /* WAKE_IND */
+ ll->ll_state = ST_LL_ASLEEP_TO_AWAKE;
+ } else {
+ /* don't send the duplicate wake_indication */
+ ST_LL_ERR(" Chip already AWAKE ");
+ }
+}
+
+/* called when ST Core wants the state */
+unsigned long st_ll_getstate(void)
+{
+ ST_LL_DBG(" returning state %ld", ll->ll_state);
+ return ll->ll_state;
+}
+
+/* called from ST Core, when a PM related packet arrives */
+unsigned long st_ll_sleep_state(unsigned char cmd)
+{
+ switch (cmd) {
+ case LL_SLEEP_IND: /* sleep ind */
+ ST_LL_DBG("sleep indication recvd");
+ ll_device_want_to_sleep();
+ break;
+ case LL_SLEEP_ACK: /* sleep ack */
+ ST_LL_ERR("sleep ack rcvd: host shouldn't");
+ break;
+ case LL_WAKE_UP_IND: /* wake ind */
+ ST_LL_DBG("wake indication recvd");
+ ll_device_want_to_wakeup();
+ break;
+ case LL_WAKE_UP_ACK: /* wake ack */
+ ST_LL_DBG("wake ack rcvd");
+ ll->ll_state = ST_LL_AWAKE;
+ break;
+ default:
+ ST_LL_ERR(" unknown input/state ");
+ return ST_ERR_FAILURE;
+ }
+ return ST_SUCCESS;
+}
+
+/* Called from ST CORE to initialize ST LL */
+long st_ll_init(void)
+{
+ long err = ST_SUCCESS;
+
+ /* Allocate memory for ST LL private structure */
+ ll = kzalloc(sizeof(*ll), GFP_ATOMIC);
+ if (!ll) {
+ ST_LL_ERR("kzalloc failed to alloc memory for ST LL");
+ err = -ENOMEM;
+ return err;
+ }
+ spin_lock_init(&ll->lock);
+ /* set state to invalid */
+ ll->ll_state = ST_LL_INVALID;
+ return err;
+}
+
+/* Called from ST CORE to de-initialize ST LL */
+long st_ll_deinit(void)
+{
+ kfree(ll);
+ return 0;
+}
diff --git a/drivers/misc/ti-st/st_ll.h b/drivers/misc/ti-st/st_ll.h
new file mode 100644
index 0000000..4cb0d03
--- /dev/null
+++ b/drivers/misc/ti-st/st_ll.h
@@ -0,0 +1,68 @@
+/*
+ * Shared Transport Low Level (ST LL)
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef ST_LL_H
+#define ST_LL_H
+
+#include <linux/skbuff.h>
+#include "st.h"
+#include "st_core.h"
+
+/* ST LL receiver states */
+#define ST_W4_PACKET_TYPE 0
+#define ST_BT_W4_EVENT_HDR 1
+#define ST_BT_W4_ACL_HDR 2
+#define ST_BT_W4_SCO_HDR 3
+#define ST_BT_W4_DATA 4
+#define ST_FM_W4_EVENT_HDR 5
+#define ST_GPS_W4_EVENT_HDR 6
+
+/* ST LL state machines */
+#define ST_LL_ASLEEP 0
+#define ST_LL_ASLEEP_TO_AWAKE 1
+#define ST_LL_AWAKE 2
+#define ST_LL_AWAKE_TO_ASLEEP 3
+#define ST_LL_INVALID 4
+
+#define LL_SLEEP_IND 0x30
+#define LL_SLEEP_ACK 0x31
+#define LL_WAKE_UP_IND 0x32
+#define LL_WAKE_UP_ACK 0x33
+
+/* ST LL private information */
+struct ll_struct_s {
+ unsigned long ll_state; /* ST LL power state */
+ spinlock_t lock;
+};
+
+/* initialize and de-init ST LL */
+long st_ll_init(void);
+long st_ll_deinit(void);
+
+/* enable/disable ST LL along with KIM start/stop
+ * called by ST Core
+ */
+void st_ll_enable(void);
+void st_ll_disable(void);
+
+unsigned long st_ll_getstate(void);
+unsigned long st_ll_sleep_state(unsigned char);
+void st_ll_wakeup(void);
+#endif /* ST_LL_H */
diff --git a/drivers/misc/wl127x-rfkill.c b/drivers/misc/wl127x-rfkill.c
index aa8d462..7e35012 100644
--- a/drivers/misc/wl127x-rfkill.c
+++ b/drivers/misc/wl127x-rfkill.c
@@ -26,10 +26,12 @@
#include <linux/gpio.h>
#include <linux/rfkill.h>
#include <linux/platform_device.h>
+#include <linux/device.h>
#include <linux/wl127x-rfkill.h>
static int wl127x_rfkill_set_power(void *data, enum rfkill_state state)
{
+#ifndef CONFIG_BUILD_TI_ST
int nshutdown_gpio = (int)data;
switch (state) {
@@ -42,6 +44,7 @@
default:
printk(KERN_ERR "invalid rfkill state %d\n", state);
}
+#endif
return 0;
}
@@ -52,6 +55,7 @@
enum rfkill_state default_state = RFKILL_STATE_SOFT_BLOCKED; /* off */
if (pdata->bt_nshutdown_gpio >= 0) {
+#ifndef CONFIG_BUILD_TI_ST
rc = gpio_request(pdata->bt_nshutdown_gpio,
"wl127x_bt_nshutdown_gpio");
if (unlikely(rc))
@@ -60,7 +64,7 @@
rc = gpio_direction_output(pdata->bt_nshutdown_gpio, 0);
if (unlikely(rc))
return rc;
-
+#endif
rfkill_set_default(RFKILL_TYPE_BLUETOOTH, default_state);
wl127x_rfkill_set_power((void *)pdata->bt_nshutdown_gpio,
default_state);
@@ -86,7 +90,7 @@
return rc;
}
}
-
+#ifndef CONFIG_BUILD_TI_ST
if (pdata->fm_enable_gpio >= 0) {
rc = gpio_request(pdata->fm_enable_gpio,
"wl127x_fm_enable_gpio");
@@ -121,7 +125,7 @@
return rc;
}
}
-
+#endif
return 0;
}
@@ -132,15 +136,17 @@
if (pdata->bt_nshutdown_gpio >= 0) {
rfkill_unregister(pdata->rfkill[WL127X_BLUETOOTH]);
rfkill_free(pdata->rfkill[WL127X_BLUETOOTH]);
+#ifndef CONFIG_BUILD_TI_ST
gpio_free(pdata->bt_nshutdown_gpio);
+#endif
}
-
+#ifndef CONFIG_BUILD_TI_ST
if (pdata->fm_enable_gpio >= 0) {
rfkill_unregister(pdata->rfkill[WL127X_FM]);
rfkill_free(pdata->rfkill[WL127X_FM]);
gpio_free(pdata->fm_enable_gpio);
}
-
+#endif
return 0;
}
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 92e2862..c3d8481 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -378,6 +378,8 @@
continue;
}
status = get_card_status(card, req);
+ } else if (disable_multi == 1) {
+ disable_multi = 0;
}
if (brq.cmd.error) {
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index c232d11..8f9186b 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -216,6 +216,24 @@
goto out;
}
+#ifdef CONFIG_HC_Broken_eMMC_ZOOM2
+ /*
+ * Hack: eMMC on Zoom2 seems to have a lower EXT_CSD Rev.
+ * This is incorrect as it is an HC card. The card becomes
+ * unusable if not set to blockaddr mode.
+ * The low level driver sets up the unused bit for MMC2 on Zoom2.
+ * Revert this hack once it is fixed in the card.
+ */
+ if (card->host->unused) {
+ card->ext_csd.sectors =
+ ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+ ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+ ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
+ ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+ if (card->ext_csd.sectors)
+ mmc_card_set_blockaddr(card);
+ } else
+#endif
if (ext_csd_struct >= 2) {
card->ext_csd.sectors =
ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 992b7fa..ad0a1e9 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -109,6 +109,17 @@
If unsure, say N.
+config HC_Broken_eMMC_ZOOM2
+ bool "HC_Broken_eMMC support for Zoom2"
+ depends on OMAP_HS_MMC2 && MACH_OMAP_ZOOM2 || MACH_OMAP_ZOOM3
+ default y
+ help
+ This selects High capacity eMMC support for Zoom2.
+ If you have a Zoom2 board with a broken high capacity eMMC device,
+ say Y here.
+
+ If unsure, say N.
+
config MMC_WBSD
tristate "Winbond W83L51xD SD/MMC Card Interface support"
depends on ISA_DMA_API
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index ce9ec83..a879136 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -77,6 +77,7 @@
#define MSBS (1 << 5)
#define BCE (1 << 1)
#define FOUR_BIT (1 << 1)
+#define DW8 (1 << 5)
#define CC 0x1
#define TC 0x02
#define OD 0x1
@@ -84,7 +85,10 @@
#define CMD_TIMEOUT (1 << 16)
#define DATA_TIMEOUT (1 << 20)
#define CMD_CRC (1 << 17)
+#define CMD_CEB (1 << 18)
+#define CMD_CIE (1 << 19)
#define DATA_CRC (1 << 21)
+#define DATA_DEB (1 << 22)
#define CARD_ERR (1 << 28)
#define STAT_CLEAR 0xFFFFFFFF
#define INIT_STREAM_CMD 0x00000000
@@ -135,6 +139,7 @@
struct clk *dbclk;
struct semaphore sem;
struct work_struct mmc_carddetect_work;
+ struct work_struct mmc_opp_set_work;
void __iomem *base;
resource_size_t mapbase;
unsigned int id;
@@ -152,6 +157,9 @@
int slot_id;
int dbclk_enabled;
int clks_enabled;
+ int inactive;
+ unsigned long max_vdd1_opp;
+ unsigned long min_vdd1_opp;
unsigned off_counter;
spinlock_t clk_lock;
struct timer_list inact_timer;
@@ -382,6 +390,18 @@
resptype = 2;
}
+#ifdef CONFIG_HC_Broken_eMMC_ZOOM2
+ if (host->id == OMAP_MMC2_DEVID) {
+ /*
+ * HACK:
+ * eMMC on Zoom2 seems fail init sequence without this
+ * delay on SWITCH CMD.
+ */
+ if (cmd->opcode == 6)
+ msleep(200);
+ }
+#endif
+
/*
* Unlike OMAP1 controller, the cmdtype does not seem to be based on
* ac, bc, adtc, bcr. Only commands ending an open ended transfer need
@@ -468,6 +488,7 @@
struct mmc_omap_host *host = (struct mmc_omap_host *) data;
omap_hsmmc_disable_clks(host);
+ schedule_work(&host->mmc_opp_set_work);
}
/*
@@ -571,7 +592,9 @@
mmc_omap_report_irq(host, status);
#endif
if ((status & CMD_TIMEOUT) ||
- (status & CMD_CRC)) {
+ (status & CMD_CRC) ||
+ (status & CMD_CEB) ||
+ (status & CMD_CIE)) {
if (host->cmd) {
if (status & CMD_TIMEOUT) {
mmc_omap_reset_controller_fsm(host, SRC);
@@ -587,7 +610,8 @@
}
}
if ((status & DATA_TIMEOUT) ||
- (status & DATA_CRC)) {
+ (status & DATA_CRC) ||
+ (status & DATA_DEB)) {
if (host->data) {
if (status & DATA_TIMEOUT)
mmc_dma_cleanup(host);
@@ -691,6 +715,9 @@
mmc_carddetect_work);
struct omap_mmc_slot_data *slot = &mmc_slot(host);
+ if (host->suspended)
+ return;
+
omap_hsmmc_enable_clks(host);
host->carddetect = slot->card_detect(slot->card_detect_irq);
@@ -704,6 +731,17 @@
}
}
+static void mmc_omap_opp_setup(struct work_struct *work)
+{
+ struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
+ mmc_opp_set_work);
+
+ if (host->pdata->set_vdd1_opp) {
+ host->pdata->set_vdd1_opp(host->dev, host->min_vdd1_opp);
+ host->inactive = 1;
+ }
+}
+
/*
* ISR for handling card insertion and removal
*/
@@ -711,6 +749,9 @@
{
struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;
+ if (host->suspended)
+ return IRQ_HANDLED;
+
schedule_work(&host->mmc_carddetect_work);
return IRQ_HANDLED;
@@ -925,10 +966,16 @@
WARN_ON(host->mrq != NULL);
host->mrq = req;
+ if (host->inactive)
+ if (host->pdata->set_vdd1_opp)
+ host->pdata->set_vdd1_opp(host->dev,
+ host->max_vdd1_opp);
+
+ del_timer_sync(&host->inact_timer);
+ host->inactive = 0;
omap_hsmmc_enable_clks(host);
mmc_omap_prepare_data(host, req);
- del_timer_sync(&host->inact_timer);
mmc_omap_start_command(host, req->cmd, req->data);
}
@@ -940,6 +987,7 @@
u16 dsor = 0;
unsigned long regval;
unsigned long timeout;
+ u32 con;
del_timer_sync(&host->inact_timer);
omap_hsmmc_enable_clks(host);
@@ -968,11 +1016,19 @@
}
switch (mmc->ios.bus_width) {
+ case MMC_BUS_WIDTH_8:
+ OMAP_HSMMC_WRITE(host->base, CON,
+ OMAP_HSMMC_READ(host->base, CON) | DW8);
+ break;
case MMC_BUS_WIDTH_4:
+ OMAP_HSMMC_WRITE(host->base, CON,
+ OMAP_HSMMC_READ(host->base, CON) & ~DW8);
OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
break;
case MMC_BUS_WIDTH_1:
+ OMAP_HSMMC_WRITE(host->base, CON,
+ OMAP_HSMMC_READ(host->base, CON) & ~DW8);
OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
break;
@@ -1027,9 +1083,11 @@
if (ios->power_mode == MMC_POWER_ON)
send_init_stream(host);
+ con = OMAP_HSMMC_READ(host->base, CON);
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
- OMAP_HSMMC_WRITE(host->base, CON,
- OMAP_HSMMC_READ(host->base, CON) | OD);
+ OMAP_HSMMC_WRITE(host->base, CON, con | OD);
+ else
+ OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
omap_hsmmc_disable_clks(host);
}
@@ -1131,6 +1189,24 @@
host->mapbase = res->start;
host->base = ioremap(host->mapbase, SZ_4K);
+ host->max_vdd1_opp = pdata->max_vdd1_opp;
+ host->min_vdd1_opp = pdata->min_vdd1_opp;
+
+#ifdef CONFIG_HC_Broken_eMMC_ZOOM2
+ /*
+ * HACK:
+ * The HC eMMC card on Zoom2 is broken. It reports wrong ext_csd
+ * version. This is a hack to make the eMMC card useble on Zoom2.
+ * Without this hack the MMC core fails to detect the correct size
+ * of the card and hence accesses beyond the detected boundary results
+ * in DATA CRC errors.
+ * Make use of the unused bit to indicate the host controller ID to
+ * the MMC core.
+ */
+ if (host->id == OMAP_MMC2_DEVID)
+ host->mmc->unused = 1;
+#endif
+
#ifdef CONFIG_MMC_EMBEDDED_SDIO
if (pdata->slots[0].embedded_sdio)
mmc_set_embedded_sdio_data(mmc,
@@ -1141,6 +1217,7 @@
#endif
platform_set_drvdata(pdev, host);
INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect);
+ INIT_WORK(&host->mmc_opp_set_work, mmc_omap_opp_setup);
mmc->ops = &mmc_omap_ops;
mmc->f_min = 400000;
@@ -1155,8 +1232,8 @@
host->clks_enabled = 0;
host->off_counter = 0;
+ host->inactive = 0;
- host->clks_enabled = 0;
host->iclk = clk_get(&pdev->dev, "mmchs_ick");
if (IS_ERR(host->iclk)) {
ret = PTR_ERR(host->iclk);
@@ -1193,7 +1270,9 @@
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
- if (pdata->slots[host->slot_id].wires >= 4)
+ if (mmc_slot(host).wires >= 8)
+ mmc->caps |= MMC_CAP_8_BIT_DATA;
+ else if (pdata->slots[host->slot_id].wires >= 4)
mmc->caps |= MMC_CAP_4_BIT_DATA;
/* Only MMC1 supports 3.0V */
@@ -1344,24 +1423,27 @@
return 0;
if (host) {
+ host->suspended = 1;
+ if (host->pdata->suspend) {
+ ret = host->pdata->suspend(&pdev->dev,
+ host->slot_id);
+ if (ret) {
+ dev_dbg(mmc_dev(host->mmc),
+ "Unable to handle MMC board"
+ " level suspend\n");
+ host->suspended = 0;
+ return ret;
+ }
+ }
+ cancel_work_sync(&host->mmc_carddetect_work);
+
ret = mmc_suspend_host(host->mmc, state);
if (ret == 0) {
- host->suspended = 1;
-
omap_hsmmc_enable_clks(host);
OMAP_HSMMC_WRITE(host->base, ISE, 0);
OMAP_HSMMC_WRITE(host->base, IE, 0);
- if (host->pdata->suspend) {
- ret = host->pdata->suspend(&pdev->dev,
- host->slot_id);
- if (ret)
- dev_dbg(mmc_dev(host->mmc),
- "Unable to handle MMC board"
- " level suspend\n");
- }
-
if (host->id == OMAP_MMC1_DEVID
&& !(OMAP_HSMMC_READ(host->base, HCTL)
& SDVSDET)) {
@@ -1377,6 +1459,15 @@
}
omap_hsmmc_disable_clks(host);
+ } else {
+ host->suspended = 0;
+ if (host->pdata->resume) {
+ ret = host->pdata->resume(&pdev->dev,
+ host->slot_id);
+ if (ret)
+ dev_dbg(mmc_dev(host->mmc),
+ "Unmask interrupt failed\n");
+ }
}
}
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index a0e8e0e..c46a59d 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -80,13 +80,22 @@
help
Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms.
-config MTD_NAND_OMAP_HWECC
- bool "OMAP enable hardware ECC"
- depends on MTD_NAND && MTD_NAND_OMAP2
- default n
- help
- The ECC compuatation for the data to be written/read can be either by
- software or omap has Hw ecc engine which calculates it.
+config MTD_NAND_OMAP_PREFETCH
+ bool "GPMC prefetch support for NAND Flash device"
+ depends on MTD_NAND && MTD_NAND_OMAP2
+ default y
+ help
+ The NAND device can be accessed for Read/Write using GPMC PREFETCH engine
+ to improve the performance.
+
+config MTD_NAND_OMAP_PREFETCH_DMA
+ depends on MTD_NAND_OMAP_PREFETCH
+ bool "DMA mode"
+ default n
+ help
+ The GPMC PREFETCH engine can be configured eigther in MPU interrupt mode
+ or in DMA interrupt mode.
+ Say y for DMA mode or MPU mode will be used
config MTD_NAND_OMAP
tristate "NAND Flash device on OMAP H3/H2/P2 boards"
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 8ba3e3e..8d6d033 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2524,11 +2524,13 @@
struct nand_chip *chip = mtd->priv;
int i;
- for (i = 0; i < 2000; i++) {
- if (chip->dev_ready(mtd))
- break;
- mdelay(10);
- }
+ if (chip->state != FL_READY)
+ for (i = 0; i < 40; i++) {
+ if (chip->dev_ready(mtd))
+ break;
+ mdelay(10);
+ }
+ chip->state = FL_READY;
}
static int nand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 9d0acda..d296d40 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -19,7 +19,7 @@
#include <linux/mtd/partitions.h>
#include <linux/io.h>
-#include <asm/dma.h>
+#include <mach/dma.h>
#include <mach/gpmc.h>
#include <mach/nand.h>
@@ -112,6 +112,26 @@
static const char *part_probes[] = { "cmdlinepart", NULL };
#endif
+#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH
+static int use_prefetch = 1;
+
+/* "modprobe ... use_prefetch=0" etc */
+module_param(use_prefetch, bool, 0);
+MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH");
+#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
+static int use_dma = 1;
+
+/* "modprobe ... use_dma=0" etc */
+module_param(use_dma, bool, 0);
+MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
+#else
+const int use_dma;
+#endif
+#else
+const int use_prefetch;
+const int use_dma;
+#endif
+
struct omap_nand_info {
struct nand_hw_control controller;
struct omap_nand_platform_data *pdata;
@@ -119,11 +139,48 @@
struct mtd_partition *parts;
struct nand_chip nand;
struct platform_device *pdev;
+ struct device *dev;
int gpmc_cs;
unsigned long phys_base;
void __iomem *gpmc_cs_baseaddr;
void __iomem *gpmc_baseaddr;
+ void __iomem *nand_pref_fifo_add;
+ struct completion comp;
+ int dma_ch;
+};
+
+static struct nand_ecclayout nand_x8_hw_romcode_oob_64 = {
+ .eccbytes = 12,
+ .eccpos = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+ },
+ .oobfree = {
+ {.offset = 13,
+ .length = 51}
+ }
+};
+
+/* Define some generic bad / good block scan pattern which are used
+ * while scanning a device for factory marked good / bad blocks
+ */
+static uint8_t scan_ff_pattern[] = { 0xff };
+static struct nand_bbt_descr bb_descrip_flashbased = {
+ .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
+ .offs = 0,
+ .len = 1,
+ .pattern = scan_ff_pattern,
+};
+
+static struct nand_ecclayout nand_x16_hw_romcode_oob_64 = {
+ .eccbytes = 12,
+ .eccpos = {
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13
+ },
+ .oobfree = {
+ {.offset = 14,
+ .length = 50}
+ }
};
/*
@@ -160,6 +217,14 @@
{
struct omap_nand_info *info = container_of(mtd,
struct omap_nand_info, mtd);
+ struct omap_nand_platform_data *pdata;
+
+ pdata = info->pdev->dev.platform_data;
+ if (cmd == NAND_CMD_ERASE1) {
+ if (pdata->board_unlock)
+ pdata->board_unlock(mtd, info->dev);
+ }
+
switch (ctrl) {
case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
@@ -188,6 +253,44 @@
}
/*
+ * omap_read_buf8 - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct nand_chip *nand = mtd->priv;
+
+ ioread8_rep(nand->IO_ADDR_R, buf, len);
+}
+
+/**
+ * omap_write_buf8 - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ struct omap_nand_info *info = container_of(mtd,
+ struct omap_nand_info, mtd);
+ struct omap_nand_platform_data *pdata;
+
+ pdata = info->pdev->dev.platform_data;
+ u_char *p = (u_char *)buf;
+
+ if (pdata->board_unlock)
+ pdata->board_unlock(mtd, info->dev);
+
+ while (len--) {
+ iowrite8(*p++, info->nand.IO_ADDR_W);
+ while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
+ GPMC_STATUS) & GPMC_BUF_FULL));
+ }
+}
+
+/*
* omap_read_buf16 - read data from NAND controller into buffer
* @mtd: MTD device structure
* @buf: buffer to store date
@@ -197,7 +300,7 @@
{
struct nand_chip *nand = mtd->priv;
- __raw_readsw(nand->IO_ADDR_R, buf, len / 2);
+ ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
}
/*
@@ -210,18 +313,274 @@
{
struct omap_nand_info *info = container_of(mtd,
struct omap_nand_info, mtd);
+ struct omap_nand_platform_data *pdata;
+
+ pdata = info->pdev->dev.platform_data;
u16 *p = (u16 *) buf;
+ if (pdata->board_unlock)
+ pdata->board_unlock(mtd, info->dev);
+
/* FIXME try bursts of writesw() or DMA ... */
len >>= 1;
while (len--) {
- writew(*p++, info->nand.IO_ADDR_W);
+ iowrite16(*p++, info->nand.IO_ADDR_W);
while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
GPMC_STATUS) & GPMC_BUF_FULL));
}
}
+
+/**
+ * omap_read_buf_pref - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct omap_nand_info *info = container_of(mtd,
+ struct omap_nand_info, mtd);
+ uint32_t pfpw_status = 0, r_count = 0;
+ int ret = 0;
+ u32 *p = (u32 *)buf;
+
+ /* take care of subpage reads */
+ for (; len % 4 != 0; ) {
+ *buf++ = __raw_readb(info->nand.IO_ADDR_R);
+ len--;
+ }
+ p = (u32 *) buf;
+
+ /* configure and start prefetch transfer */
+ ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
+ if (ret) {
+ /* PFPW engine is busy, use cpu copy method */
+ if (info->nand.options & NAND_BUSWIDTH_16)
+ omap_read_buf16(mtd, buf, len);
+ else
+ omap_read_buf8(mtd, buf, len);
+ } else {
+ do {
+ pfpw_status = gpmc_prefetch_status();
+ r_count = ((pfpw_status >> 24) & 0x7F) >> 2;
+ ioread32_rep(info->nand_pref_fifo_add, p, r_count);
+ p += r_count;
+ len -= r_count << 2;
+ } while (len);
+
+ /* disable and stop the PFPW engine */
+ gpmc_prefetch_reset();
+ }
+}
+
+/**
+ * omap_write_buf_pref - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf_pref(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ struct omap_nand_info *info = container_of(mtd,
+ struct omap_nand_info, mtd);
+ struct omap_nand_platform_data *pdata;
+ uint32_t pfpw_status = 0, w_count = 0;
+ int i = 0, ret = 0;
+
+ pdata = info->pdev->dev.platform_data;
+
+ if (pdata->board_unlock)
+ pdata->board_unlock(mtd, info->dev);
+
+ u16 *p = (u16 *) buf;
+
+ /* take care of subpage writes */
+ if (len % 2 != 0) {
+ writeb(*buf, info->nand.IO_ADDR_R);
+ p = (u16 *)(buf + 1);
+ len--;
+ }
+
+ /* configure and start prefetch transfer */
+ ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1);
+ if (ret) {
+ /* PFPW engine is busy, use cpu copy method */
+ if (info->nand.options & NAND_BUSWIDTH_16)
+ omap_write_buf16(mtd, buf, len);
+ else
+ omap_write_buf8(mtd, buf, len);
+ } else {
+ pfpw_status = gpmc_prefetch_status();
+ while (pfpw_status & 0x3FFF) {
+ w_count = ((pfpw_status >> 24) & 0x7F) >> 1;
+ for (i = 0; (i < w_count) && len; i++, len -= 2)
+ iowrite16(*p++, info->nand_pref_fifo_add);
+ pfpw_status = gpmc_prefetch_status();
+ }
+
+ /* disable and stop the PFPW engine */
+ gpmc_prefetch_reset();
+ }
+}
+
+#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
+/*
+ * omap_nand_dma_cb: callback on the completion of dma transfer
+ * @lch: logical channel
+ * @ch_satuts: channel status
+ * @data: pointer to completion data structure
+ */
+static void omap_nand_dma_cb(int lch, u16 ch_status, void *data)
+{
+ complete((struct completion *) data);
+}
+
+/*
+ * omap_nand_dma_transfer: configer and start dma transfer
+ * @mtd: MTD device structure
+ * @addr: virtual address in RAM of source/destination
+ * @len: number of data bytes to be transferred
+ * @is_write: flag for read/write operation
+ */
+static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
+ unsigned int len, int is_write)
+{
+ struct omap_nand_info *info = container_of(mtd,
+ struct omap_nand_info, mtd);
+ uint32_t prefetch_status = 0;
+ enum dma_data_direction dir = is_write ? DMA_TO_DEVICE :
+ DMA_FROM_DEVICE;
+ dma_addr_t dma_addr;
+ int ret;
+
+ /* The fifo depth is 64 bytes. We have a sync at each frame and frame
+ * length is 64 bytes.
+ */
+ int buf_len = len >> 6;
+
+ if (addr >= high_memory) {
+ struct page *p1;
+
+ if (((size_t)addr & PAGE_MASK) !=
+ ((size_t)(addr + len - 1) & PAGE_MASK))
+ goto out_copy;
+ p1 = vmalloc_to_page(addr);
+ if (!p1)
+ goto out_copy;
+ addr = page_address(p1) + ((size_t)addr & ~PAGE_MASK);
+ }
+
+ dma_addr = dma_map_single(&info->pdev->dev, addr, len, dir);
+ if (dma_mapping_error(&info->pdev->dev, dma_addr)) {
+ dev_err(&info->pdev->dev,
+ "Couldn't DMA map a %d byte buffer\n", len);
+ goto out_copy;
+ }
+
+ if (is_write) {
+ omap_set_dma_dest_params(info->dma_ch, 0,
+ OMAP_DMA_AMODE_CONSTANT,
+ info->phys_base, 0, 0);
+ omap_set_dma_src_params(info->dma_ch, 0,
+ OMAP_DMA_AMODE_POST_INC,
+ dma_addr, 0, 0);
+ omap_set_dma_transfer_params(info->dma_ch,
+ OMAP_DMA_DATA_TYPE_S32,
+ 0x10, buf_len, OMAP_DMA_SYNC_FRAME,
+ OMAP24XX_DMA_GPMC, OMAP_DMA_DST_SYNC);
+ } else {
+ omap_set_dma_src_params(info->dma_ch, 0,
+ OMAP_DMA_AMODE_CONSTANT,
+ info->phys_base, 0, 0);
+ omap_set_dma_dest_params(info->dma_ch, 0,
+ OMAP_DMA_AMODE_POST_INC,
+ dma_addr, 0, 0);
+ omap_set_dma_transfer_params(info->dma_ch,
+ OMAP_DMA_DATA_TYPE_S32,
+ 0x10, buf_len, OMAP_DMA_SYNC_FRAME,
+ OMAP24XX_DMA_GPMC, OMAP_DMA_SRC_SYNC);
+ }
+ /* configure and start prefetch transfer */
+ ret = gpmc_prefetch_enable(info->gpmc_cs, 0x1, len, is_write);
+ if (ret)
+ /* PFPW engine is busy, use cpu copy methode */
+ goto out_copy;
+
+ init_completion(&info->comp);
+
+ omap_start_dma(info->dma_ch);
+
+ /* setup and start DMA using dma_addr */
+ wait_for_completion(&info->comp);
+
+ while (0x3fff & (prefetch_status = gpmc_prefetch_status()))
+ ;
+ /* disable and stop the PFPW engine */
+ gpmc_prefetch_reset();
+
+ dma_unmap_single(&info->pdev->dev, dma_addr, len, dir);
+ return 0;
+
+out_copy:
+ if (info->nand.options & NAND_BUSWIDTH_16)
+ is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len)
+ : omap_write_buf16(mtd, (u_char *) addr, len);
+ else
+ is_write == 0 ? omap_read_buf8(mtd, (u_char *) addr, len)
+ : omap_write_buf8(mtd, (u_char *) addr, len);
+ return 0;
+}
+#else
+static void omap_nand_dma_cb(int lch, u16 ch_status, void *data) {}
+static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
+ unsigned int len, int is_write)
+{
+ return 0;
+}
+#endif
+
+/**
+ * omap_read_buf_dma_pref - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
+{
+ if (len <= mtd->oobsize)
+ omap_read_buf_pref(mtd, buf, len);
+ else
+ /* start transfer in DMA mode */
+ omap_nand_dma_transfer(mtd, buf, len, 0x0);
+}
+
+/**
+ * omap_write_buf_dma_pref - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf_dma_pref(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ struct omap_nand_platform_data *pdata;
+ struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+ mtd);
+
+ pdata = info->pdev->dev.platform_data;
+ if (pdata->board_unlock)
+ pdata->board_unlock(mtd, info->dev);
+
+ if (len <= mtd->oobsize)
+ omap_write_buf_pref(mtd, buf, len);
+ else
+ /* start transfer in DMA mode */
+ omap_nand_dma_transfer(mtd, buf, len, 0x1);
+}
+
/*
* omap_verify_buf - Verify chip data against buffer
* @mtd: MTD device structure
@@ -245,7 +604,6 @@
return 0;
}
-#ifdef CONFIG_MTD_NAND_OMAP_HWECC
/*
* omap_hwecc_init-Initialize the Hardware ECC for NAND flash in GPMC controller
* @mtd: MTD device structure
@@ -322,7 +680,6 @@
/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
reg += 4;
- gen_true_ecc(ecc_code-3);
return 0;
}
@@ -364,7 +721,6 @@
__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONFIG);
}
-#endif
/*
* omap_wait - Wait function is called during Program and erase
@@ -392,6 +748,169 @@
return status;
}
+/**
+ * omap_compare_ecc - Detect (2 bits) and correct (1 bit) error in data
+ * @ecc_data1: ecc code from nand spare area
+ * @ecc_data2: ecc code from hardware register obtained from hardware ecc
+ * @page_data: page data
+ *
+ * This function compares two ECC's and indicates if there is an error.
+ * If the error can be corrected it will be corrected to the buffer.
+ */
+static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
+ u8 *ecc_data2, /* read from register */
+ u8 *page_data)
+{
+ uint i;
+ u8 tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
+ u8 comp0_bit[8], comp1_bit[8], comp2_bit[8];
+ u8 ecc_bit[24];
+ u8 ecc_sum = 0;
+ u8 find_bit = 0;
+ uint find_byte = 0;
+ int isEccFF;
+
+ isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF);
+
+ gen_true_ecc(ecc_data1);
+ gen_true_ecc(ecc_data2);
+
+ for (i = 0; i <= 2; i++) {
+ *(ecc_data1 + i) = ~(*(ecc_data1 + i));
+ *(ecc_data2 + i) = ~(*(ecc_data2 + i));
+ }
+
+ for (i = 0; i < 8; i++) {
+ tmp0_bit[i] = *ecc_data1 % 2;
+ *ecc_data1 = *ecc_data1 / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ tmp1_bit[i] = *(ecc_data1 + 1) % 2;
+ *(ecc_data1 + 1) = *(ecc_data1 + 1) / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ tmp2_bit[i] = *(ecc_data1 + 2) % 2;
+ *(ecc_data1 + 2) = *(ecc_data1 + 2) / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ comp0_bit[i] = *ecc_data2 % 2;
+ *ecc_data2 = *ecc_data2 / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ comp1_bit[i] = *(ecc_data2 + 1) % 2;
+ *(ecc_data2 + 1) = *(ecc_data2 + 1) / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ comp2_bit[i] = *(ecc_data2 + 2) % 2;
+ *(ecc_data2 + 2) = *(ecc_data2 + 2) / 2;
+ }
+
+ for (i = 0; i < 6; i++)
+ ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
+
+ for (i = 0; i < 8; i++)
+ ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
+
+ for (i = 0; i < 8; i++)
+ ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
+
+ ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
+ ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
+
+ for (i = 0; i < 24; i++)
+ ecc_sum += ecc_bit[i];
+
+ switch (ecc_sum) {
+ case 0:
+ /* Not reached because this function is not called if
+ * ECC values are equal
+ */
+ return 0;
+
+ case 1:
+ /* Uncorrectable error */
+ DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
+ return -1;
+
+ case 11:
+ /* UN-Correctable error */
+ DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR B\n");
+ return -1;
+
+ case 12:
+ /* Correctable error */
+ find_byte = (ecc_bit[23] << 8) +
+ (ecc_bit[21] << 7) +
+ (ecc_bit[19] << 6) +
+ (ecc_bit[17] << 5) +
+ (ecc_bit[15] << 4) +
+ (ecc_bit[13] << 3) +
+ (ecc_bit[11] << 2) +
+ (ecc_bit[9] << 1) +
+ ecc_bit[7];
+
+ find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
+
+ DEBUG(MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at "
+ "offset: %d, bit: %d\n", find_byte, find_bit);
+
+ page_data[find_byte] ^= (1 << find_bit);
+
+ return 0;
+ default:
+ if (isEccFF) {
+ if (ecc_data2[0] == 0 &&
+ ecc_data2[1] == 0 &&
+ ecc_data2[2] == 0)
+ return 0;
+ }
+ DEBUG(MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n");
+ return -1;
+ }
+}
+/**
+ * omap_correct_data - Compares the ECC read with HW generated ECC
+ * @mtd: MTD device structure
+ * @dat: page data
+ * @read_ecc: ecc read from nand flash
+ * @calc_ecc: ecc read from HW ECC registers
+ *
+ * Compares the ecc read from nand spare area with ECC registers values
+ * and if ECC's mismached, it will call 'omap_compare_ecc' for error detection
+ * and correction.
+ */
+static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+ mtd);
+ int blockCnt = 0, i = 0, ret = 0;
+
+ /* Ex NAND_ECC_HW12_2048 */
+ if ((info->nand.ecc.mode == NAND_ECC_HW) &&
+ (info->nand.ecc.size == 2048))
+ blockCnt = 4;
+ else
+ blockCnt = 1;
+
+ for (i = 0; i < blockCnt; i++) {
+ if (memcmp(read_ecc, calc_ecc, 3) != 0) {
+ ret = omap_compare_ecc(read_ecc, calc_ecc, dat);
+ if (ret < 0)
+ return ret;
+ }
+ read_ecc += 3;
+ calc_ecc += 3;
+ dat += 512;
+ }
+ return 0;
+}
+
/*
* omap_dev_ready - calls the platform specific dev_ready function
* @mtd: MTD device structure
@@ -443,6 +962,7 @@
init_waitqueue_head(&info->controller.wq);
info->pdev = pdev;
+ info->dev = &pdev->dev;
info->gpmc_cs = pdata->cs;
info->gpmc_baseaddr = pdata->gpmc_baseaddr;
@@ -489,12 +1009,6 @@
info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;
info->nand.cmd_ctrl = omap_hwcontrol;
- /* REVISIT: only supports 16-bit NAND flash */
-
- info->nand.read_buf = omap_read_buf16;
- info->nand.write_buf = omap_write_buf16;
- info->nand.verify_buf = omap_verify_buf;
-
/*
* If RDY/BSY line is connected to OMAP then use the omap ready funcrtion
* and the generic nand_wait function which reads the status register
@@ -515,20 +1029,58 @@
== 0x1000)
info->nand.options |= NAND_BUSWIDTH_16;
-#ifdef CONFIG_MTD_NAND_OMAP_HWECC
- info->nand.ecc.bytes = 3;
- info->nand.ecc.size = 512;
- info->nand.ecc.calculate = omap_calculate_ecc;
- info->nand.ecc.hwctl = omap_enable_hwecc;
- info->nand.ecc.correct = nand_correct_data;
- info->nand.ecc.mode = NAND_ECC_HW;
+ if (use_prefetch) {
+ /* copy the virtual address of nand base for fifo access */
+ info->nand_pref_fifo_add = info->nand.IO_ADDR_R;
- /* init HW ECC */
- omap_hwecc_init(&info->mtd);
-#else
- info->nand.ecc.mode = NAND_ECC_SOFT;
- info->nand.ecc.size = 512;
-#endif
+ info->nand.read_buf = omap_read_buf_pref;
+ info->nand.write_buf = omap_write_buf_pref;
+ if (use_dma) {
+ err = omap_request_dma(OMAP24XX_DMA_GPMC, "NAND",
+ omap_nand_dma_cb, &info->comp, &info->dma_ch);
+ if (err < 0) {
+ info->dma_ch = -1;
+ printk(KERN_WARNING "DMA request failed."
+ " Non-dma data transfer mode\n");
+ } else {
+ omap_set_dma_dest_burst_mode(info->dma_ch,
+ OMAP_DMA_DATA_BURST_16);
+ omap_set_dma_src_burst_mode(info->dma_ch,
+ OMAP_DMA_DATA_BURST_16);
+
+ info->nand.read_buf = omap_read_buf_dma_pref;
+ info->nand.write_buf = omap_write_buf_dma_pref;
+ }
+ }
+ } else {
+ if (info->nand.options & NAND_BUSWIDTH_16) {
+ info->nand.read_buf = omap_read_buf16;
+ info->nand.write_buf = omap_write_buf16;
+ } else {
+ info->nand.read_buf = omap_read_buf8;
+ info->nand.write_buf = omap_write_buf8;
+ }
+ }
+ info->nand.verify_buf = omap_verify_buf;
+
+ if (pdata->ecc_opt == 0x1) {
+ info->nand.ecc.bytes = 3;
+ info->nand.ecc.size = 512;
+ if (info->nand.options & NAND_BUSWIDTH_16) {
+ info->nand.ecc.layout = &nand_x16_hw_romcode_oob_64;
+ } else {
+ info->nand.ecc.layout = &nand_x8_hw_romcode_oob_64;
+ info->nand.badblock_pattern = &bb_descrip_flashbased;
+ }
+ info->nand.ecc.calculate = omap_calculate_ecc;
+ info->nand.ecc.hwctl = omap_enable_hwecc;
+ info->nand.ecc.correct = omap_correct_data;
+ info->nand.ecc.mode = NAND_ECC_HW;
+ /* init HW ECC */
+ omap_hwecc_init(&info->mtd);
+ } else {
+ info->nand.ecc.mode = NAND_ECC_SOFT;
+ }
/* DIP switches on some boards change between 8 and 16 bit
* bus widths for flash. Try the other width if the first try fails.
@@ -540,6 +1092,9 @@
goto out_release_mem_region;
}
}
+ /* If the board has an unlock function, use it */
+ if (pdata->unlock != NULL)
+ info->mtd.unlock = pdata->unlock;
#ifdef CONFIG_MTD_PARTITIONS
err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
@@ -571,9 +1126,12 @@
struct omap_nand_info *info = mtd->priv;
platform_set_drvdata(pdev, NULL);
+ if (use_dma)
+ omap_free_dma(info->dma_ch);
+
/* Release NAND device, its internal structures and partitions */
nand_release(&info->mtd);
- iounmap(info->nand.IO_ADDR_R);
+ iounmap(info->nand_pref_fifo_add);
kfree(&info->mtd);
return 0;
}
@@ -620,6 +1178,15 @@
static int __init omap_nand_init(void)
{
printk(KERN_INFO "%s driver initializing\n", DRIVER_NAME);
+
+ /* This check is required if driver is being
+ * loaded run time as a module
+ */
+ if ((1 == use_dma) && (0 == use_prefetch)) {
+ printk(KERN_INFO"Wrong parameters: 'use_dma' can not be 1 "
+ "without use_prefetch'. Prefetch will not be"
+ " used in either mode (mpu or dma)\n");
+ }
return platform_driver_register(&omap_nand_driver);
}
diff --git a/drivers/net/pppolac.c b/drivers/net/pppolac.c
index b4d879d..af3202a 100644
--- a/drivers/net/pppolac.c
+++ b/drivers/net/pppolac.c
@@ -3,7 +3,6 @@
* Driver for PPP on L2TP Access Concentrator / PPPoLAC Socket (RFC 2661)
*
* Copyright (C) 2009 Google, Inc.
- * Author: Chia-chi Yeh <chiachi@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -22,8 +21,10 @@
* only works on IPv4 due to the lack of UDP encapsulation support in IPv6. */
#include <linux/module.h>
+#include <linux/workqueue.h>
#include <linux/skbuff.h>
#include <linux/file.h>
+#include <linux/netdevice.h>
#include <linux/net.h>
#include <linux/udp.h>
#include <linux/ppp_defs.h>
@@ -31,6 +32,7 @@
#include <linux/if_pppox.h>
#include <linux/ppp_channel.h>
#include <net/tcp_states.h>
+#include <asm/uaccess.h>
#define L2TP_CONTROL_BIT 0x80
#define L2TP_LENGTH_BIT 0x40
@@ -51,10 +53,10 @@
return (union unaligned *)ptr;
}
-static int pppolac_recv(struct sock *sk_udp, struct sk_buff *skb)
+static int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb)
{
- struct sock *sk;
- struct pppolac_opt *opt;
+ struct sock *sk = (struct sock *)sk_udp->sk_user_data;
+ struct pppolac_opt *opt = &pppox_sk(sk)->proto.lac;
__u8 bits;
__u8 *ptr;
@@ -64,9 +66,9 @@
/* Put it back if it is a control packet. */
if (skb->data[sizeof(struct udphdr)] & L2TP_CONTROL_BIT)
- return 1;
+ return opt->backlog_rcv(sk_udp, skb);
- /* Now the packet is ours. Skip UDP header. */
+ /* Skip UDP header. */
skb_pull(skb, sizeof(struct udphdr));
/* Check the version. */
@@ -93,26 +95,12 @@
!skb_pull(skb, skb->data[-2] << 8 | skb->data[-1]))
goto drop;
- /* Now ptr is pointing to the tunnel and skb is pointing to the payload.
- * We have to lock sk_udp to prevent sk from being closed. */
- lock_sock(sk_udp);
- sk = sk_udp->sk_user_data;
- if (!sk) {
- release_sock(sk_udp);
- goto drop;
- }
- sock_hold(sk);
- release_sock(sk_udp);
- opt = &pppox_sk(sk)->proto.lac;
-
/* Check the tunnel and the session. */
- if (unaligned(ptr)->u32 != opt->local) {
- sock_put(sk);
+ if (unaligned(ptr)->u32 != opt->local)
goto drop;
- }
- /* Check the sequence if it is present. According to RFC 2661 page 10
- * and 43, the only thing to do is updating opt->sequencing. */
+ /* Check the sequence if it is present. According to RFC 2661 section
+ * 5.4, the only thing to do is to update opt->sequencing. */
opt->sequencing = bits & L2TP_SEQUENCE_BIT;
/* Skip PPP address and control if they are present. */
@@ -124,26 +112,50 @@
if (skb->len >= 1 && skb->data[0] & 1)
skb_push(skb, 1)[0] = 0;
- /* Finally, deliver the packet to PPP channel. We have to lock sk to
- * prevent another thread from calling pppox_unbind_sock(). */
+ /* Finally, deliver the packet to PPP channel. */
skb_orphan(skb);
- lock_sock(sk);
ppp_input(&pppox_sk(sk)->chan, skb);
- release_sock(sk);
- sock_put(sk);
- return 0;
-
+ return NET_RX_SUCCESS;
drop:
kfree_skb(skb);
+ return NET_RX_DROP;
+}
+
+static int pppolac_recv(struct sock *sk_udp, struct sk_buff *skb)
+{
+ sock_hold(sk_udp);
+ sk_receive_skb(sk_udp, skb, 0);
return 0;
}
+static struct sk_buff_head delivery_queue;
+
+static void pppolac_xmit_core(struct work_struct *delivery_work)
+{
+ mm_segment_t old_fs = get_fs();
+ struct sk_buff *skb;
+
+ set_fs(KERNEL_DS);
+ while ((skb = skb_dequeue(&delivery_queue))) {
+ struct sock *sk_udp = skb->sk;
+ struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len};
+ struct msghdr msg = {
+ .msg_iov = (struct iovec *)&iov,
+ .msg_iovlen = 1,
+ .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT,
+ };
+ sk_udp->sk_prot->sendmsg(NULL, sk_udp, &msg, skb->len);
+ kfree_skb(skb);
+ }
+ set_fs(old_fs);
+}
+
+static DECLARE_WORK(delivery_work, pppolac_xmit_core);
+
static int pppolac_xmit(struct ppp_channel *chan, struct sk_buff *skb)
{
struct sock *sk_udp = (struct sock *)chan->private;
struct pppolac_opt *opt = &pppox_sk(sk_udp->sk_user_data)->proto.lac;
- struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT};
- struct kvec iov;
/* Install PPP address and control. */
skb_push(skb, 2);
@@ -166,11 +178,10 @@
skb->data[1] = L2TP_VERSION;
unaligned(&skb->data[2])->u32 = opt->remote;
- /* Now send the packet via UDP socket. */
- iov.iov_base = skb->data;
- iov.iov_len = skb->len;
- kernel_sendmsg(sk_udp->sk_socket, &msg, &iov, 1, skb->len);
- kfree_skb(skb);
+ /* Now send the packet via the delivery queue. */
+ skb_set_owner_w(skb, sk_udp);
+ skb_queue_tail(&delivery_queue, skb);
+ schedule_work(&delivery_work);
return 1;
}
@@ -235,6 +246,7 @@
po->chan.mtu = PPP_MTU - 80;
po->proto.lac.local = unaligned(&addr->local)->u32;
po->proto.lac.remote = unaligned(&addr->remote)->u32;
+ po->proto.lac.backlog_rcv = sk_udp->sk_backlog_rcv;
error = ppp_register_channel(&po->chan);
if (error)
@@ -243,8 +255,8 @@
sk->sk_state = PPPOX_CONNECTED;
udp_sk(sk_udp)->encap_type = UDP_ENCAP_L2TPINUDP;
udp_sk(sk_udp)->encap_rcv = pppolac_recv;
+ sk_udp->sk_backlog_rcv = pppolac_recv_core;
sk_udp->sk_user_data = sk;
-
out:
if (sock_udp) {
release_sock(sk_udp);
@@ -270,12 +282,12 @@
if (sk->sk_state != PPPOX_NONE) {
struct sock *sk_udp = (struct sock *)pppox_sk(sk)->chan.private;
- pppox_unbind_sock(sk);
-
lock_sock(sk_udp);
- sk_udp->sk_user_data = NULL;
+ pppox_unbind_sock(sk);
udp_sk(sk_udp)->encap_type = 0;
udp_sk(sk_udp)->encap_rcv = NULL;
+ sk_udp->sk_backlog_rcv = pppox_sk(sk)->proto.lac.backlog_rcv;
+ sk_udp->sk_user_data = NULL;
release_sock(sk_udp);
sockfd_put(sk_udp->sk_socket);
}
@@ -349,6 +361,8 @@
error = register_pppox_proto(PX_PROTO_OLAC, &pppolac_pppox_proto);
if (error)
proto_unregister(&pppolac_proto);
+ else
+ skb_queue_head_init(&delivery_queue);
return error;
}
diff --git a/drivers/net/pppopns.c b/drivers/net/pppopns.c
index eae4bda..29809712 100644
--- a/drivers/net/pppopns.c
+++ b/drivers/net/pppopns.c
@@ -3,7 +3,6 @@
* Driver for PPP on PPTP Network Server / PPPoPNS Socket (RFC 2637)
*
* Copyright (C) 2009 Google, Inc.
- * Author: Chia-chi Yeh <chiachi@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -22,14 +21,17 @@
* and IPv6. */
#include <linux/module.h>
+#include <linux/workqueue.h>
#include <linux/skbuff.h>
#include <linux/file.h>
+#include <linux/netdevice.h>
#include <linux/net.h>
#include <linux/ppp_defs.h>
#include <linux/if.h>
#include <linux/if_ppp.h>
#include <linux/if_pppox.h>
#include <linux/ppp_channel.h>
+#include <asm/uaccess.h>
#define GRE_HEADER_SIZE 8
@@ -50,76 +52,90 @@
__u32 sequence;
} __attribute__((packed));
-static void pppopns_recv(struct sock *sk_raw, int length)
+static int pppopns_recv_core(struct sock *sk_raw, struct sk_buff *skb)
{
- struct sock *sk;
- struct pppopns_opt *opt;
- struct sk_buff *skb;
+ struct sock *sk = (struct sock *)sk_raw->sk_user_data;
+ struct pppopns_opt *opt = &pppox_sk(sk)->proto.pns;
struct header *hdr;
- /* Lock sk_raw to prevent sk from being closed. */
- lock_sock(sk_raw);
- sk = (struct sock *)sk_raw->sk_user_data;
- if (!sk) {
- release_sock(sk_raw);
- return;
- }
- sock_hold(sk);
- release_sock(sk_raw);
- opt = &pppox_sk(sk)->proto.pns;
+ /* Skip transport header */
+ skb_pull(skb, skb_transport_header(skb) - skb->data);
- /* Process packets from the receive queue. */
- while ((skb = skb_dequeue(&sk_raw->sk_receive_queue))) {
- skb_pull(skb, skb_transport_header(skb) - skb->data);
+ /* Drop the packet if it is too short. */
+ if (skb->len < GRE_HEADER_SIZE)
+ goto drop;
- /* Drop the packet if it is too short. */
- if (skb->len < GRE_HEADER_SIZE)
- goto drop;
-
- /* Check the header. */
- hdr = (struct header *)skb->data;
- if (hdr->type != PPTP_GRE_TYPE || hdr->call != opt->local ||
+ /* Check the header. */
+ hdr = (struct header *)skb->data;
+ if (hdr->type != PPTP_GRE_TYPE || hdr->call != opt->local ||
(hdr->bits & PPTP_GRE_BITS_MASK) != PPTP_GRE_BITS)
- goto drop;
+ goto drop;
- /* Skip all fields including optional ones. */
- if (!skb_pull(skb, GRE_HEADER_SIZE +
- (hdr->bits & PPTP_GRE_SEQ_BIT ? 4 : 0) +
- (hdr->bits & PPTP_GRE_ACK_BIT ? 4 : 0)))
- goto drop;
+ /* Skip all fields including optional ones. */
+ if (!skb_pull(skb, GRE_HEADER_SIZE +
+ (hdr->bits & PPTP_GRE_SEQ_BIT ? 4 : 0) +
+ (hdr->bits & PPTP_GRE_ACK_BIT ? 4 : 0)))
+ goto drop;
- /* Check the length. */
- if (skb->len != ntohs(hdr->length))
- goto drop;
+ /* Check the length. */
+ if (skb->len != ntohs(hdr->length))
+ goto drop;
- /* Skip PPP address and control if they are present. */
- if (skb->len >= 2 && skb->data[0] == PPP_ADDR &&
- skb->data[1] == PPP_CTRL)
- skb_pull(skb, 2);
+ /* Skip PPP address and control if they are present. */
+ if (skb->len >= 2 && skb->data[0] == PPP_ADDR &&
+ skb->data[1] == PPP_CTRL)
+ skb_pull(skb, 2);
- /* Fix PPP protocol if it is compressed. */
- if (skb->len >= 1 && skb->data[0] & 1)
- skb_push(skb, 1)[0] = 0;
+ /* Fix PPP protocol if it is compressed. */
+ if (skb->len >= 1 && skb->data[0] & 1)
+ skb_push(skb, 1)[0] = 0;
- /* Deliver the packet to PPP channel. We have to lock sk to
- * prevent another thread from calling pppox_unbind_sock(). */
- skb_orphan(skb);
- lock_sock(sk);
- ppp_input(&pppox_sk(sk)->chan, skb);
- release_sock(sk);
- continue;
+ /* Finally, deliver the packet to PPP channel. */
+ skb_orphan(skb);
+ ppp_input(&pppox_sk(sk)->chan, skb);
+ return NET_RX_SUCCESS;
drop:
+ kfree_skb(skb);
+ return NET_RX_DROP;
+}
+
+static void pppopns_recv(struct sock *sk_raw, int length)
+{
+ struct sk_buff *skb;
+ while ((skb = skb_dequeue(&sk_raw->sk_receive_queue))) {
+ sock_hold(sk_raw);
+ sk_receive_skb(sk_raw, skb, 0);
+ }
+}
+
+static struct sk_buff_head delivery_queue;
+
+static void pppopns_xmit_core(struct work_struct *delivery_work)
+{
+ mm_segment_t old_fs = get_fs();
+ struct sk_buff *skb;
+
+ set_fs(KERNEL_DS);
+ while ((skb = skb_dequeue(&delivery_queue))) {
+ struct sock *sk_raw = skb->sk;
+ struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len};
+ struct msghdr msg = {
+ .msg_iov = (struct iovec *)&iov,
+ .msg_iovlen = 1,
+ .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT,
+ };
+ sk_raw->sk_prot->sendmsg(NULL, sk_raw, &msg, skb->len);
kfree_skb(skb);
}
- sock_put(sk);
+ set_fs(old_fs);
}
+static DECLARE_WORK(delivery_work, pppopns_xmit_core);
+
static int pppopns_xmit(struct ppp_channel *chan, struct sk_buff *skb)
{
struct sock *sk_raw = (struct sock *)chan->private;
struct pppopns_opt *opt = &pppox_sk(sk_raw->sk_user_data)->proto.pns;
- struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT};
- struct kvec iov;
struct header *hdr;
__u16 length;
@@ -138,11 +154,10 @@
hdr->sequence = htonl(opt->sequence);
opt->sequence++;
- /* Now send the packet via RAW socket. */
- iov.iov_base = skb->data;
- iov.iov_len = skb->len;
- kernel_sendmsg(sk_raw->sk_socket, &msg, &iov, 1, skb->len);
- kfree_skb(skb);
+ /* Now send the packet via the delivery queue. */
+ skb_set_owner_w(skb, sk_raw);
+ skb_queue_tail(&delivery_queue, skb);
+ schedule_work(&delivery_work);
return 1;
}
@@ -208,15 +223,19 @@
po->chan.mtu = PPP_MTU - 80;
po->proto.pns.local = addr->local;
po->proto.pns.remote = addr->remote;
+ po->proto.pns.data_ready = sk_raw->sk_data_ready;
+ po->proto.pns.backlog_rcv = sk_raw->sk_backlog_rcv;
error = ppp_register_channel(&po->chan);
if (error)
goto out;
sk->sk_state = PPPOX_CONNECTED;
- sk_raw->sk_user_data = sk;
+ lock_sock(sk_raw);
sk_raw->sk_data_ready = pppopns_recv;
-
+ sk_raw->sk_backlog_rcv = pppopns_recv_core;
+ sk_raw->sk_user_data = sk;
+ release_sock(sk_raw);
out:
if (sock_tcp)
sockfd_put(sock_tcp);
@@ -241,8 +260,10 @@
if (sk->sk_state != PPPOX_NONE) {
struct sock *sk_raw = (struct sock *)pppox_sk(sk)->chan.private;
- pppox_unbind_sock(sk);
lock_sock(sk_raw);
+ pppox_unbind_sock(sk);
+ sk_raw->sk_data_ready = pppox_sk(sk)->proto.pns.data_ready;
+ sk_raw->sk_backlog_rcv = pppox_sk(sk)->proto.pns.backlog_rcv;
sk_raw->sk_user_data = NULL;
release_sock(sk_raw);
sock_release(sk_raw->sk_socket);
@@ -317,6 +338,8 @@
error = register_pppox_proto(PX_PROTO_OPNS, &pppopns_pppox_proto);
if (error)
proto_unregister(&pppopns_proto);
+ else
+ skb_queue_head_init(&delivery_queue);
return error;
}
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 15376b3..62cf939 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -269,7 +269,7 @@
{
struct smc911x_local *lp = netdev_priv(dev);
unsigned mask, cfg, cr;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
@@ -326,7 +326,7 @@
{
struct smc911x_local *lp = netdev_priv(dev);
unsigned cr;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", CARDNAME, __func__);
@@ -516,7 +516,7 @@
{
struct smc911x_local *lp = netdev_priv(dev);
unsigned int free;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n",
dev->name, __func__);
@@ -790,7 +790,7 @@
{
struct smc911x_local *lp = netdev_priv(dev);
int timeout;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
unsigned int reg;
DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__);
@@ -890,7 +890,7 @@
int my_phy_caps; /* My PHY capabilities */
int my_ad_caps; /* My Advertised capabilities */
int status;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__);
@@ -1011,7 +1011,7 @@
struct smc911x_local *lp = netdev_priv(dev);
unsigned int status, mask, timeout;
unsigned int rx_overrun=0, cr, pkts;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
@@ -1267,7 +1267,7 @@
{
struct smc911x_local *lp = netdev_priv(dev);
int status, mask;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
@@ -1305,7 +1305,7 @@
struct smc911x_local *lp = netdev_priv(dev);
unsigned int multicast_table[2];
unsigned int mcr, update_multicast = 0;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
@@ -1478,7 +1478,7 @@
{
struct smc911x_local *lp = netdev_priv(dev);
int ret, status;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
cmd->maxtxpkt = 1;
@@ -1519,7 +1519,7 @@
{
struct smc911x_local *lp = netdev_priv(dev);
int ret;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
if (lp->phy_type != 0) {
spin_lock_irqsave(&lp->lock, flags);
@@ -1552,7 +1552,7 @@
{
struct smc911x_local *lp = netdev_priv(dev);
int ret = -EINVAL;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
if (lp->phy_type != 0) {
spin_lock_irqsave(&lp->lock, flags);
@@ -1586,7 +1586,7 @@
struct ethtool_regs* regs, void *buf)
{
struct smc911x_local *lp = netdev_priv(dev);
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
u32 reg,i,j=0;
u32 *data = (u32*)buf;
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
index 50fcf11..31eae34 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/smc911x.h
@@ -740,7 +740,7 @@
#define SMC_SET_FIFO_INT(lp, x) SMC_outl( x, lp, FIFO_INT )
#define SMC_SET_FIFO_TDA(lp, x) \
do { \
- unsigned long __flags; \
+ unsigned long uninitialized_var(__flags); \
int __mask; \
local_irq_save(__flags); \
__mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<24); \
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index d1590ac..d603c4e 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -318,7 +318,7 @@
goto out;
}
- SMSC_WARNING(HW, "Timed out waiting for MII write to finish");
+ SMSC_WARNING(HW, "Timed out waiting for MII read to finish");
reg = -EIO;
out:
@@ -730,8 +730,8 @@
* usage is 10/100 indicator */
pdata->gpio_setting = smsc911x_reg_read(pdata,
GPIO_CFG);
- if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_)
- && (!pdata->using_extphy)) {
+ if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_) &&
+ (!pdata->using_extphy)) {
/* Force 10/100 LED off, after saving
* orginal GPIO configuration */
pdata->gpio_orig_setting = pdata->gpio_setting;
@@ -769,7 +769,7 @@
return -ENODEV;
}
- phydev = phy_connect(dev, phydev->dev.bus_id,
+ phydev = phy_connect(dev, dev_name(&phydev->dev),
&smsc911x_phy_adjust_link, 0, pdata->config.phy_interface);
if (IS_ERR(phydev)) {
@@ -778,7 +778,8 @@
}
pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
- dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+ dev->name, phydev->drv->name,
+ dev_name(&phydev->dev), phydev->irq);
/* mask with MAC supported features */
phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
@@ -797,7 +798,7 @@
SMSC_TRACE(HW, "Passed Loop Back Test");
#endif /* USE_PHY_WORK_AROUND */
- SMSC_TRACE(HW, "phy initialised succesfully");
+ SMSC_TRACE(HW, "phy initialised successfully");
return 0;
}
@@ -893,22 +894,22 @@
SMSC_WARNING(HW,
"Packet tag reserved bit is high");
} else {
- if (unlikely(tx_stat & 0x00008000)) {
+ if (unlikely(tx_stat & TX_STS_ES_)) {
dev->stats.tx_errors++;
} else {
dev->stats.tx_packets++;
dev->stats.tx_bytes += (tx_stat >> 16);
}
- if (unlikely(tx_stat & 0x00000100)) {
+ if (unlikely(tx_stat & TX_STS_EXCESS_COL_)) {
dev->stats.collisions += 16;
dev->stats.tx_aborted_errors += 1;
} else {
dev->stats.collisions +=
((tx_stat >> 3) & 0xF);
}
- if (unlikely(tx_stat & 0x00000800))
+ if (unlikely(tx_stat & TX_STS_LOST_CARRIER_))
dev->stats.tx_carrier_errors += 1;
- if (unlikely(tx_stat & 0x00000200)) {
+ if (unlikely(tx_stat & TX_STS_LATE_COL_)) {
dev->stats.collisions++;
dev->stats.tx_aborted_errors++;
}
@@ -922,19 +923,17 @@
{
int crc_err = 0;
- if (unlikely(rxstat & 0x00008000)) {
+ if (unlikely(rxstat & RX_STS_ES_)) {
dev->stats.rx_errors++;
- if (unlikely(rxstat & 0x00000002)) {
+ if (unlikely(rxstat & RX_STS_CRC_ERR_)) {
dev->stats.rx_crc_errors++;
crc_err = 1;
}
}
if (likely(!crc_err)) {
- if (unlikely((rxstat & 0x00001020) == 0x00001020)) {
- /* Frame type indicates length,
- * and length error is set */
+ if (unlikely((rxstat & RX_STS_FRAME_TYPE_) &&
+ (rxstat & RX_STS_LENGTH_ERR_)))
dev->stats.rx_length_errors++;
- }
if (rxstat & RX_STS_MCAST_)
dev->stats.multicast++;
}
@@ -953,7 +952,7 @@
do {
udelay(1);
val = smsc911x_reg_read(pdata, RX_DP_CTRL);
- } while (--timeout && (val & RX_DP_CTRL_RX_FFWD_));
+ } while ((val & RX_DP_CTRL_RX_FFWD_) && --timeout);
if (unlikely(timeout == 0))
SMSC_WARNING(HW, "Timed out waiting for "
@@ -1160,8 +1159,8 @@
/* Make sure EEPROM has finished loading before setting GPIO_CFG */
timeout = 50;
- while ((timeout--) &&
- (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_)) {
+ while ((smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) &&
+ --timeout) {
udelay(10);
}
@@ -1250,7 +1249,7 @@
napi_enable(&pdata->napi);
temp = smsc911x_reg_read(pdata, INT_EN);
- temp |= (INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_);
+ temp |= (INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_ | INT_EN_RXSTOP_INT_EN_);
smsc911x_reg_write(pdata, INT_EN, temp);
spin_lock_irq(&pdata->mac_lock);
@@ -1422,11 +1421,6 @@
/* Request the hardware to stop, then perform the
* update when we get an RX_STOP interrupt */
- smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_);
- temp = smsc911x_reg_read(pdata, INT_EN);
- temp |= INT_EN_RXSTOP_INT_EN_;
- smsc911x_reg_write(pdata, INT_EN, temp);
-
temp = smsc911x_mac_read(pdata, MAC_CR);
temp &= ~(MAC_CR_RXEN_);
smsc911x_mac_write(pdata, MAC_CR, temp);
@@ -1465,9 +1459,6 @@
/* Called when there is a multicast update scheduled and
* it is now safe to complete the update */
SMSC_TRACE(INTR, "RX Stop interrupt");
- temp = smsc911x_reg_read(pdata, INT_EN);
- temp &= (~INT_EN_RXSTOP_INT_EN_);
- smsc911x_reg_write(pdata, INT_EN, temp);
smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_);
smsc911x_rx_multicast_update_workaround(pdata);
serviced = IRQ_HANDLED;
@@ -1662,6 +1653,7 @@
u8 address, u8 data)
{
u32 op = E2P_CMD_EPC_CMD_ERASE_ | address;
+ u32 temp;
int ret;
SMSC_TRACE(DRV, "address 0x%x, data 0x%x", address, data);
@@ -1670,6 +1662,10 @@
if (!ret) {
op = E2P_CMD_EPC_CMD_WRITE_ | address;
smsc911x_reg_write(pdata, E2P_DATA, (u32)data);
+
+ /* Workaround for hardware read-after-write restriction */
+ temp = smsc911x_reg_read(pdata, BYTE_TEST);
+
ret = smsc911x_eeprom_send_cmd(pdata, op);
}
@@ -1746,6 +1742,7 @@
.ndo_do_ioctl = smsc911x_do_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
+ .ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = smsc911x_poll_controller,
#endif
@@ -1882,7 +1879,7 @@
if (!res)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, res->end - res->start);
+ release_mem_region(res->start, resource_size(res));
iounmap(pdata->ioaddr);
@@ -1896,9 +1893,9 @@
struct net_device *dev;
struct smsc911x_data *pdata;
struct smsc911x_platform_config *config = pdev->dev.platform_data;
- struct resource *res;
+ struct resource *res, *irq_res;
unsigned int intcfg = 0;
- int res_size;
+ int res_size, irq_flags;
int retval;
DECLARE_MAC_BUF(mac);
@@ -1921,7 +1918,15 @@
retval = -ENODEV;
goto out_0;
}
- res_size = res->end - res->start;
+ res_size = resource_size(res);
+
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq_res) {
+ pr_warning("%s: Could not allocate irq resource.\n",
+ SMSC_CHIPNAME);
+ retval = -ENODEV;
+ goto out_0;
+ }
if (!request_mem_region(res->start, res_size, SMSC_CHIPNAME)) {
retval = -EBUSY;
@@ -1939,7 +1944,8 @@
pdata = netdev_priv(dev);
- dev->irq = platform_get_irq(pdev, 0);
+ dev->irq = irq_res->start;
+ irq_flags = irq_res->flags & IRQF_TRIGGER_MASK;
pdata->ioaddr = ioremap_nocache(res->start, res_size);
/* copy config parameters across to pdata */
@@ -1972,8 +1978,8 @@
smsc911x_reg_write(pdata, INT_EN, 0);
smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
- retval = request_irq(dev->irq, smsc911x_irqhandler, IRQF_DISABLED,
- dev->name, dev);
+ retval = request_irq(dev->irq, smsc911x_irqhandler,
+ irq_flags | IRQF_SHARED, dev->name, dev);
if (retval) {
SMSC_WARNING(PROBE,
"Unable to claim requested irq: %d", dev->irq);
@@ -2033,8 +2039,7 @@
spin_unlock_irq(&pdata->mac_lock);
- dev_info(&dev->dev, "MAC Address: %s\n",
- print_mac(mac, dev->dev_addr));
+ dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr);
return 0;
@@ -2048,7 +2053,7 @@
out_free_netdev_2:
free_netdev(dev);
out_release_io_1:
- release_mem_region(res->start, res->end - res->start);
+ release_mem_region(res->start, resource_size(res));
out_0:
return retval;
}
diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h
index 2b76654..016360c 100644
--- a/drivers/net/smsc911x.h
+++ b/drivers/net/smsc911x.h
@@ -30,7 +30,7 @@
#define SMSC_NAPI_WEIGHT 16
/* implements a PHY loopback test at initialisation time, to ensure a packet
- * can be succesfully looped back */
+ * can be successfully looped back */
#define USE_PHY_WORK_AROUND
#define DPRINTK(nlevel, klevel, fmt, args...) \
@@ -81,12 +81,19 @@
#define RX_STATUS_FIFO 0x40
#define RX_STS_ES_ 0x00008000
+#define RX_STS_LENGTH_ERR_ 0x00001000
#define RX_STS_MCAST_ 0x00000400
+#define RX_STS_FRAME_TYPE_ 0x00000020
+#define RX_STS_CRC_ERR_ 0x00000002
#define RX_STATUS_FIFO_PEEK 0x44
#define TX_STATUS_FIFO 0x48
#define TX_STS_ES_ 0x00008000
+#define TX_STS_LOST_CARRIER_ 0x00000800
+#define TX_STS_NO_CARRIER_ 0x00000400
+#define TX_STS_LATE_COL_ 0x00000200
+#define TX_STS_EXCESS_COL_ 0x00000100
#define TX_STATUS_FIFO_PEEK 0x4C
diff --git a/drivers/power/twl4030_bci_battery.c b/drivers/power/twl4030_bci_battery.c
index c716e09..a76b3a8 100644
--- a/drivers/power/twl4030_bci_battery.c
+++ b/drivers/power/twl4030_bci_battery.c
@@ -164,6 +164,7 @@
struct power_supply bat;
struct power_supply bk_bat;
+ struct power_supply usb_bat;
struct delayed_work twl4030_bci_monitor_work;
struct delayed_work twl4030_bk_bci_monitor_work;
};
@@ -182,7 +183,7 @@
static inline int twl4030charger_presence_evt(void)
{
int ret;
- u8 chg_sts, set = 0, clear = 0;
+ u8 uninitialized_var(chg_sts), set = 0, clear = 0;
/* read charger power supply status */
ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &chg_sts,
@@ -237,7 +238,7 @@
static int twl4030battery_presence_evt(void)
{
int ret;
- u8 batstsmchg, batstspchg;
+ u8 uninitialized_var(batstsmchg), uninitialized_var(batstspchg);
/* check for the battery presence in main charge*/
ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
@@ -278,7 +279,7 @@
static int twl4030battery_level_evt(void)
{
int ret;
- u8 mfst;
+ u8 uninitialized_var(mfst);
/* checking for threshold event */
ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
@@ -322,7 +323,8 @@
*/
static irqreturn_t twl4030battery_interrupt(int irq, void *_di)
{
- u8 isr1a_val, isr2a_val, clear_2a, clear_1a;
+ u8 uninitialized_var(isr1a_val), uninitialized_var(isr2a_val);
+ u8 clear_2a, clear_1a;
int ret;
#ifdef CONFIG_LOCKDEP
@@ -621,7 +623,7 @@
*/
static int twl4030battery_temperature(void)
{
- u8 val;
+ u8 uninitialized_var(val);
int temp, curr, volt, res, ret;
/* Getting and calculating the thermistor voltage */
@@ -680,7 +682,7 @@
static int twl4030battery_current(void)
{
int ret, curr = read_bci_val(T2_BATTERY_CUR);
- u8 val;
+ u8 uninitialized_var(val);
ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
REG_BCICTL1);
@@ -725,7 +727,7 @@
static int twl4030charger_presence(void)
{
int ret;
- u8 hwsts;
+ u8 uninitialized_var(hwsts);
ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts,
REG_STS_HW_CONDITIONS);
@@ -753,7 +755,7 @@
static int twl4030bci_status(void)
{
int ret;
- u8 status;
+ u8 uninitialized_var(status);
ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
&status, REG_BCIMSTATEC);
@@ -768,7 +770,7 @@
static int read_bci_val(u8 reg)
{
int ret, temp;
- u8 val;
+ u8 uninitialized_var(val);
/* reading MSB */
ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
@@ -861,6 +863,10 @@
POWER_SUPPLY_PROP_VOLTAGE_NOW,
};
+static enum power_supply_property twl4030_usb_battery_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
static void
twl4030_bk_bci_battery_read_status(struct twl4030_bci_device_info *di)
{
@@ -887,13 +893,25 @@
static void
twl4030_bci_battery_update_status(struct twl4030_bci_device_info *di)
{
+ int old_charge_source = di->charge_rsoc;
+
twl4030_bci_battery_read_status(di);
di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
-
if (power_supply_am_i_supplied(&di->bat))
di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
else
di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+
+ /*
+ * Since Charger interrupt only happens for AC plug-in
+ * and not for usb plug-in, we use the next update
+ * cycle to update the status of the power_supply
+ * change to user space.
+ */
+ di->charge_rsoc = usb_charger_flag;
+ if (old_charge_source != di->charge_rsoc)
+ power_supply_changed(&di->usb_bat);
+
}
static void twl4030_bci_battery_work(struct work_struct *work)
@@ -937,6 +955,21 @@
return 0;
}
+static int twl4030_usb_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = usb_charger_flag;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int twl4030_bci_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -1040,6 +1073,20 @@
di->bk_bat.get_property = twl4030_bk_bci_battery_get_property;
di->bk_bat.external_power_changed = NULL;
+ /*
+ * Android expects a battery type POWER_SUPPLY_TYPE_USB
+ * as a usb charger battery. This battery
+ * and its "online" property are used to determine if the
+ * usb cable is plugged in or not.
+ */
+ di->usb_bat.name = "twl4030_bci_usb_src";
+ di->usb_bat.supplied_to = twl4030_bci_supplied_to;
+ di->usb_bat.type = POWER_SUPPLY_TYPE_USB;
+ di->usb_bat.properties = twl4030_usb_battery_props;
+ di->usb_bat.num_properties = ARRAY_SIZE(twl4030_usb_battery_props);
+ di->usb_bat.get_property = twl4030_usb_battery_get_property;
+ di->usb_bat.external_power_changed = NULL;
+
twl4030charger_ac_en(ENABLE);
twl4030charger_usb_en(ENABLE);
twl4030battery_hw_level_en(ENABLE);
@@ -1100,8 +1147,16 @@
twl4030_bk_bci_battery_work);
schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
+ ret = power_supply_register(&pdev->dev, &di->usb_bat);
+ if (ret) {
+ dev_dbg(&pdev->dev, "failed to register usb battery\n");
+ goto usb_batt_failed;
+ }
+
return 0;
+usb_batt_failed:
+ power_supply_unregister(&di->bk_bat);
bk_batt_failed:
power_supply_unregister(&di->bat);
batt_failed:
diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c
index ad35f76..4926d24 100644
--- a/drivers/rtc/rtc-twl4030.c
+++ b/drivers/rtc/rtc-twl4030.c
@@ -189,7 +189,9 @@
{
unsigned char rtc_data[ALL_TIME_REGS + 1];
int ret;
- u8 save_control;
+ u8 uninitialized_var(save_control);
+
+ memset(rtc_data, 0, (ALL_TIME_REGS + 1));
ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
if (ret < 0)
@@ -221,10 +223,12 @@
static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- unsigned char save_control;
+ unsigned char uninitialized_var(save_control);
unsigned char rtc_data[ALL_TIME_REGS + 1];
int ret;
+ memset(rtc_data, 0, (ALL_TIME_REGS + 1));
+
rtc_data[1] = bin2bcd(tm->tm_sec);
rtc_data[2] = bin2bcd(tm->tm_min);
rtc_data[3] = bin2bcd(tm->tm_hour);
@@ -323,7 +327,7 @@
unsigned long events = 0;
int ret = IRQ_NONE;
int res;
- u8 rd_reg;
+ u8 uninitialized_var(rd_reg);
#ifdef CONFIG_LOCKDEP
/* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
@@ -392,7 +396,7 @@
struct rtc_device *rtc;
int ret = 0;
int irq = platform_get_irq(pdev, 0);
- u8 rd_reg;
+ u8 uninitialized_var(rd_reg);
if (irq <= 0)
return -EINVAL;
@@ -495,9 +499,7 @@
{
irqstat = rtc_irq_bits;
- /* REVISIT alarm may need to wake us from sleep */
- mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M |
- BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+ mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
return 0;
}
diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c
index 1a0e74d..ddc6ac6 100644
--- a/drivers/serial/omap-serial.c
+++ b/drivers/serial/omap-serial.c
@@ -32,28 +32,26 @@
#include <linux/serial_core.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
+#include <mach/mux.h>
+#include <mach/control.h>
+#include <linux/wakelock.h>
#include <asm/irq.h>
-#include <asm/dma.h>
#include <mach/dmtimer.h>
#include <mach/omap-serial.h>
#include <mach/gpio.h>
#include <mach/dma.h>
#include <mach/io.h>
-#ifdef CONFIG_OMAP3_PM
-#include <../arch/arm/mach-omap2/ti-compat.h>
-#include <../arch/arm/mach-omap2/prcm-regs.h>
-#endif
unsigned long isr8250_activity;
#define CONSOLE_NAME "console="
#ifdef CONFIG_ARCH_OMAP34XX
-#define OMAP_MDR1_DISABLE 0x07
-#define OMAP_MDR1_MODE13X 0x03
-#define OMAP_MDR1_MODE16X 0x00
+#define OMAP_MDR1_DISABLE 0x07
+#define OMAP_MDR1_MODE13X 0x03
+#define OMAP_MDR1_MODE16X 0x00
#define OMAP_MODE13X_SPEED 230400
#endif
@@ -69,16 +67,16 @@
/*
* We default to IRQ0 for the "no irq" hack. Some
- * machine types want others as well - they're free
+ * machine types want others as well - they're free
* to redefine this in their header file.
*/
#define is_real_interrupt(irq) ((irq) != 0)
-// TBD: move this to header file
+/* TBD: move this to header file */
static u8 uart_dma_tx[MAX_UARTS + 1] =
- { OMAP24XX_DMA_UART1_TX, OMAP24XX_DMA_UART2_TX, OMAP24XX_DMA_UART3_TX };
+ {OMAP24XX_DMA_UART1_TX, OMAP24XX_DMA_UART2_TX, OMAP24XX_DMA_UART3_TX};
static u8 uart_dma_rx[MAX_UARTS + 1] =
- { OMAP24XX_DMA_UART1_RX, OMAP24XX_DMA_UART2_RX, OMAP24XX_DMA_UART3_RX };
+ {OMAP24XX_DMA_UART1_RX, OMAP24XX_DMA_UART2_RX, OMAP24XX_DMA_UART3_RX};
struct uart_omap_dma {
@@ -110,6 +108,7 @@
unsigned char ier;
unsigned char lcr;
unsigned char mcr;
+ unsigned char efr;
int use_dma;
int is_buf_dma_alloced;
/*
@@ -120,22 +119,26 @@
unsigned int lsr_break_flag;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags;
- char name[12];
+ char name[20];
int use_console;
spinlock_t uart_lock;
- char dev_name[50];
};
static struct uart_omap_port *ui[MAX_UARTS + 1];
unsigned int fcr[MAX_UARTS];
+static struct wake_lock omap_serial_wakelock;
/* Forward declaration of dma callback functions */
static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
-static void serial_omap_display_reg(struct uart_port *port);
static void serial_omap_rx_timeout(unsigned long uart_no);
static void serial_omap_start_rxdma(struct uart_omap_port *up);
-int console_detect(char *str){
+#ifdef DEBUG
+static void serial_omap_display_reg(struct uart_port *port);
+#endif
+
+int console_detect(char *str)
+{
extern char *saved_command_line;
char *next, *start = NULL;
int i;
@@ -150,7 +153,6 @@
} else {
next++;
}
-
}
if (!start)
return -EPERM;
@@ -158,8 +160,8 @@
start = strchr(start, '=') + 1;
while (*start != ',') {
str[i++] = *start++;
- if (i > 6){
- printk("Invalid Console Name\n");
+ if (i > 6) {
+ printk(KERN_INFO "Invalid Console Name\n");
return -EPERM;
}
}
@@ -212,7 +214,7 @@
static void serial_omap_stop_rxdma(struct uart_omap_port *up)
{
if (up->uart_dma.rx_dma_state) {
- del_timer(&up->uart_dma.rx_timer);
+ del_timer_sync(&up->uart_dma.rx_timer);
omap_stop_dma(up->uart_dma.rx_dma_channel);
omap_free_dma(up->uart_dma.rx_dma_channel);
up->uart_dma.rx_dma_channel = 0xFF;
@@ -224,7 +226,7 @@
{
struct uart_omap_port *up = (struct uart_omap_port *)port;
- DPRINTK("serial_omap_enable_ms+%d\n",up->pdev->id);
+ DPRINTK("serial_omap_enable_ms+%d\n", up->pdev->id);
up->ier |= UART_IER_MSI;
serial_out(up, UART_IER, up->ier);
}
@@ -234,11 +236,12 @@
struct uart_omap_port *up = (struct uart_omap_port *)port;
if (up->use_dma) {
if (up->uart_dma.tx_dma_channel != 0xFF) {
- /*
- * Check if dma is still active . If yes do nothing , return.
- * Else stop dma
- */
- int status = omap_readl(OMAP34XX_DMA4_BASE + OMAP_DMA4_CCR(up->uart_dma.tx_dma_channel));
+ /*
+ * Check if dma is still active . If yes do nothing,
+ * return. Else stop dma
+ */
+ int status = omap_readl(OMAP34XX_DMA4_BASE +
+ OMAP_DMA4_CCR(up->uart_dma.tx_dma_channel));
if (status & (1 << 7))
return;
omap_stop_dma(up->uart_dma.tx_dma_channel);
@@ -251,13 +254,6 @@
up->ier &= ~UART_IER_THRI;
serial_out(up, UART_IER, up->ier);
}
-#ifdef CONFIG_OMAP3_PM
- if (!up->uart_dma.rx_dma_state) {
- unsigned int tmp;
- tmp = (serial_in(up, UART_OMAP_SYSC) & 0x7) | (2 << 3);
- serial_out(up, UART_OMAP_SYSC, tmp); /* smart-idle */
- }
-#endif
}
static void serial_omap_stop_rx(struct uart_port *port)
@@ -267,6 +263,10 @@
up->ier &= ~UART_IER_RLSI;
up->port.read_status_mask &= ~UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
+ /*Disable the UART CTS wakeup for UART1,UART2*/
+ if ((!port->suspended && (((up->pdev->id - 1) == UART1) ||
+ ((up->pdev->id - 1) == UART2))))
+ omap_uart_cts_wakeup((up->pdev->id - 1), 0);
}
@@ -354,7 +354,6 @@
}
count = up->port.fifosize / 4;
-
do {
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@@ -373,23 +372,13 @@
static void serial_omap_start_tx(struct uart_port *port)
{
struct uart_omap_port *up = (struct uart_omap_port *)port;
-#ifdef CONFIG_OMAP3_PM
- /* Disallow OCP bus idle. UART TX irqs are not seen during
- * bus idle. Alternative is to set kernel timer at fifo
- * drain rate.
- */
- unsigned int tmp;
- tmp = (serial_in(up, UART_OMAP_SYSC) & 0x7) | (1 << 3);
- serial_out(up, UART_OMAP_SYSC, tmp); /* no-idle */
-#endif
-
if (up->use_dma && !(up->port.x_char)) {
struct circ_buf *xmit = &up->port.info->xmit;
- unsigned int start = up->uart_dma.tx_buf_dma_phys + (xmit->tail & (UART_XMIT_SIZE - 1));
- if (uart_circ_empty(xmit) || up->uart_dma.tx_dma_state) {
+ unsigned int start = up->uart_dma.tx_buf_dma_phys +
+ (xmit->tail & (UART_XMIT_SIZE - 1));
+ if (uart_circ_empty(xmit) || up->uart_dma.tx_dma_state)
return;
- }
spin_lock(&(up->uart_dma.tx_lock));
up->uart_dma.tx_dma_state = 1;
spin_unlock(&(up->uart_dma.tx_lock));
@@ -398,21 +387,26 @@
/* It is a circular buffer. See if the buffer has wounded back.
* If yes it will have to be transferred in two separate dma
* transfers */
- if (start + up->uart_dma.tx_buf_size >= up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
- up->uart_dma.tx_buf_size = (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
+ if (start + up->uart_dma.tx_buf_size >=
+ up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
+ up->uart_dma.tx_buf_size =
+ (up->uart_dma.tx_buf_dma_phys +
+ UART_XMIT_SIZE) - start;
- if (up->uart_dma.tx_dma_channel == 0xFF) {
- omap_request_dma(uart_dma_tx[up->pdev->id-1],"UART Tx DMA",
- (void *)uart_tx_dma_callback,up,
- &(up->uart_dma.tx_dma_channel));
- }
+ if (up->uart_dma.tx_dma_channel == 0xFF)
+ omap_request_dma(uart_dma_tx[up->pdev->id-1],
+ "UART Tx DMA",
+ (void *)uart_tx_dma_callback, up,
+ &(up->uart_dma.tx_dma_channel));
omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
- OMAP_DMA_AMODE_CONSTANT, UART_BASE(up->pdev->id - 1), 0,0);
+ OMAP_DMA_AMODE_CONSTANT,
+ UART_BASE(up->pdev->id - 1), 0, 0);
omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
- OMAP_DMA_AMODE_POST_INC, start, 0,0);
+ OMAP_DMA_AMODE_POST_INC, start, 0, 0);
omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
- OMAP_DMA_DATA_TYPE_S8, up->uart_dma.tx_buf_size, 1,
+ OMAP_DMA_DATA_TYPE_S8,
+ up->uart_dma.tx_buf_size, 1,
OMAP_DMA_SYNC_ELEMENT,
uart_dma_tx[(up->pdev->id)-1], 0);
@@ -468,16 +462,13 @@
up->ier &= ~UART_IER_RDI;
serial_out(up, UART_IER, up->ier);
serial_omap_start_rxdma(up);
- }
- else if (lsr & UART_LSR_DR) {
+ } else if (lsr & UART_LSR_DR) {
receive_chars(up, &lsr);
}
check_modem_status(up);
- if ((lsr & UART_LSR_THRE) && (iir & 0x2)) {
+ if ((lsr & UART_LSR_THRE) && (iir & 0x2))
transmit_chars(up);
- }
isr8250_activity = jiffies;
-
return IRQ_HANDLED;
}
@@ -487,7 +478,7 @@
unsigned long flags;
unsigned int ret;
- DPRINTK("serial_omap_tx_empty+%d\n",up->pdev->id);
+ DPRINTK("serial_omap_tx_empty+%d\n", up->pdev->id);
spin_lock_irqsave(&up->port.lock, flags);
ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
spin_unlock_irqrestore(&up->port.lock, flags);
@@ -502,7 +493,7 @@
unsigned int ret;
status = check_modem_status(up);
- DPRINTK("serial_omap_get_mctrl+%d\n",up->pdev->id);
+ DPRINTK("serial_omap_get_mctrl+%d\n", up->pdev->id);
ret = 0;
if (status & UART_MSR_DCD)
@@ -520,8 +511,10 @@
{
struct uart_omap_port *up = (struct uart_omap_port *)port;
unsigned char mcr = 0;
+ u16 efr = 0;
+ u16 lcr = 0;
- DPRINTK("serial_omap_set_mctrl+%d\n",up->pdev->id);
+ DPRINTK("serial_omap_set_mctrl+%d\n", up->pdev->id);
if (mctrl & TIOCM_RTS)
mcr |= UART_MCR_RTS;
if (mctrl & TIOCM_DTR)
@@ -533,8 +526,25 @@
if (mctrl & TIOCM_LOOP)
mcr |= UART_MCR_LOOP;
+ lcr = serial_in(up, UART_LCR);
+ /* Set the CONFIG B Mode to read the EFR */
+ serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+ efr = serial_in(up, UART_EFR);
+ /* The EFR[4] bit to enable the MCR write */
+ serial_out(up, UART_EFR, UART_EFR_ECB);
+ serial_out(up, UART_LCR, 0x0); /* Operational mode */
+
mcr |= up->mcr;
serial_out(up, UART_MCR, mcr);
+
+ /* Set the CONFIG B Mode to read the EFR */
+ serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+ serial_out(up, UART_EFR, efr);
+
+ /* Restore the LCR Value */
+ serial_out(up, UART_LCR, lcr);
+
+ return;
}
static void serial_omap_break_ctl(struct uart_port *port, int break_state)
@@ -542,7 +552,7 @@
struct uart_omap_port *up = (struct uart_omap_port *)port;
unsigned long flags;
- DPRINTK("serial_omap_break_ctl+%d\n",up->pdev->id);
+ DPRINTK("serial_omap_break_ctl+%d\n", up->pdev->id);
spin_lock_irqsave(&up->port.lock, flags);
if (break_state == -1)
up->lcr |= UART_LCR_SBC;
@@ -559,9 +569,14 @@
int irq_flags = 0;
int retval;
+ /*Enable the UART CTS wakeup for UART1,UART2*/
+ if (((up->pdev->id - 1) == UART1) || ((up->pdev->id - 1) == UART2))
+ omap_uart_cts_wakeup((up->pdev->id - 1), 1);
+
+
/* Zoom2 has GPIO_102 connected to Serial device:
- * Active High
- */
+ * Active High
+ */
if (up->port.flags & UPF_TRIGGER_HIGH)
irq_flags |= IRQF_TRIGGER_HIGH;
@@ -571,27 +586,17 @@
/*
* Allocate the IRQ
*/
- retval = request_irq(up->port.irq, serial_omap_irq, irq_flags, up->name, up);
- if (retval) {
+ retval = request_irq(up->port.irq, serial_omap_irq, irq_flags,
+ up->name, up);
+ if (retval)
return retval;
- }
-
- /*
- * Stop the baud clock and disable the UART. UART will be enabled
- * back in set_termios. This is essential for DMA mode operations.
- */
- serial_out(up, UART_LCR, UART_LCR_DLAB);
- serial_out(up, UART_DLL, 0);
- serial_out(up, UART_DLM, 0);
- serial_out(up, UART_LCR, 0);
- serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_DISABLE);
+ DPRINTK("serial_omap_startup+%d\n", up->pdev->id);
/*
* Clear the FIFO buffers and disable them.
* (they will be reenabled in set_termios())
*/
serial_omap_clear_fifos(up);
- serial_out(up, UART_SCR, 0x00);
/* For Hardware flow control */
serial_out(up, UART_MCR, 0x2);
@@ -599,7 +604,8 @@
* Clear the interrupt registers.
*/
(void) serial_in(up, UART_LSR);
- (void) serial_in(up, UART_RX);
+ if (serial_in(up, UART_LSR) & UART_LSR_DR)
+ (void)serial_in(up, UART_RX);
(void) serial_in(up, UART_IIR);
(void) serial_in(up, UART_MSR);
/*
@@ -622,8 +628,6 @@
up->msr_saved_flags = 0;
-
-
if (up->port.flags & UPF_FOURPORT) {
unsigned int icp;
/*
@@ -638,8 +642,9 @@
free_page((unsigned long)up->port.info->xmit.buf);
up->port.info->xmit.buf = NULL;
up->port.info->xmit.buf = dma_alloc_coherent(NULL,
- UART_XMIT_SIZE,
- (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys), 0);
+ UART_XMIT_SIZE,
+ (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
+ 0);
up->is_buf_dma_alloced = 1;
}
init_timer(&(up->uart_dma.rx_timer));
@@ -647,19 +652,18 @@
up->uart_dma.rx_timer.data = up->pdev->id;
/* Currently the buffer size is 4KB. Can increase it later*/
up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
- up->uart_dma.rx_buf_size,
- (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
- serial_omap_start_rxdma(up);
- } else {
- /*
- * Finally, enable interrupts. Note: Modem status interrupts
- * are set via set_termios(), which will be occurring imminently
- * anyway, so we don't enable them here.
- */
- up->ier = UART_IER_RLSI | UART_IER_RDI; //| UART_IER_RTOIE |UART_IER_THRI;
- serial_out(up, UART_IER, up->ier);
+ up->uart_dma.rx_buf_size,
+ (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
}
+ /*
+ * Finally, enable interrupts. Note: Modem status interrupts
+ * are set via set_termios(), which will be occurring imminently
+ * anyway, so we don't enable them here.
+ */
+ up->ier = UART_IER_RLSI | UART_IER_RDI;
+ serial_out(up, UART_IER, up->ier);
+ isr8250_activity = jiffies;
return 0;
}
@@ -668,7 +672,7 @@
struct uart_omap_port *up = (struct uart_omap_port *)port;
unsigned long flags;
- DPRINTK("serial_omap_shutdown+%d\n",up->pdev->id);
+ DPRINTK("serial_omap_shutdown+%d\n", up->pdev->id);
/*
* Disable interrupts from this port
*/
@@ -694,13 +698,15 @@
/*
* Read data port to reset things, and then free the irq
*/
- (void) serial_in(up, UART_RX);
- if (up->use_dma ) {
+ if (serial_in(up, UART_LSR) & UART_LSR_DR)
+ (void)serial_in(up, UART_RX);
+ if (up->use_dma) {
int tmp;
if (up->is_buf_dma_alloced) {
dma_free_coherent(up->port.dev,
UART_XMIT_SIZE,
- up->port.info->xmit.buf, up->uart_dma.tx_buf_dma_phys);
+ up->port.info->xmit.buf,
+ up->uart_dma.tx_buf_dma_phys);
up->port.info->xmit.buf = NULL;
up->is_buf_dma_alloced = 0;
}
@@ -708,7 +714,8 @@
serial_omap_stop_rx(port);
dma_free_coherent(up->port.dev,
up->uart_dma.rx_buf_size,
- up->uart_dma.rx_buf, up->uart_dma.rx_buf_dma_phys);
+ up->uart_dma.rx_buf,
+ up->uart_dma.rx_buf_dma_phys);
up->uart_dma.rx_buf = NULL;
tmp = serial_in(up, UART_OMAP_SYSC) & 0x7;
serial_out(up, UART_OMAP_SYSC, tmp); /* force-idle */
@@ -717,6 +724,65 @@
free_irq(up->port.irq, up);
}
+static inline void
+serial_omap_configure_xonxoff
+ (struct uart_omap_port *up, struct ktermios *termios)
+{
+ unsigned char efr = 0;
+
+ up->lcr = serial_in(up, UART_LCR);
+ serial_out(up, UART_LCR, 0xbf);
+ up->efr = serial_in(up, UART_EFR);
+ serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
+
+ serial_out(up, UART_XON1, termios->c_cc[VSTART]);
+ serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
+
+ /* clear SW control mode bits */
+ efr = up->efr & 0xf0;
+
+ /* IXON Flag:
+ * Enable XON/XOFF flow control on output.
+ * Transmit XON1, XOFF1
+ */
+ if (termios->c_iflag & IXON)
+ efr |= 0x01 << 3;
+
+ /* IXOFF Flag:
+ * Enable XON/XOFF flow control on input.
+ * Receiver compares XON1, XOFF1.
+ */
+ if (termios->c_iflag & IXOFF)
+ efr |= 0x01 << 1;
+
+ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+ serial_out(up, UART_LCR, 0x80);
+
+ up->mcr = serial_in(up, UART_MCR);
+
+ /* IXANY Flag:
+ * Enable any character to restart output.
+ * Operation resumes after receiving any
+ * character after recognition of the XOFF character
+ */
+ if (termios->c_iflag & IXANY)
+ up->mcr |= 1<<5;
+
+ serial_out(up, UART_MCR, up->mcr | 1<<6);
+
+ serial_out(up, UART_LCR, 0xbf);
+ serial_out(up, UART_TI752_TCR, 0x0f);
+ /* Enable special char function UARTi.EFR_REG[5] and
+ * load the new software flow control mode IXON or IXOFF
+ * and restore the UARTi.EFR_REG[4] ENHANCED_EN value.
+ */
+ serial_out(up, UART_EFR, efr | 1<<5);
+ serial_out(up, UART_LCR, 0x80);
+
+ serial_out(up, UART_MCR, up->mcr & ~(1<<6));
+ serial_out(up, UART_LCR, up->lcr);
+}
+
static void
serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
@@ -727,11 +793,6 @@
unsigned long flags;
unsigned int baud, quot;
- serial_out(up, UART_LCR, UART_LCR_DLAB);
- serial_out(up, UART_DLL, 0);
- serial_out(up, UART_DLM, 0);
- serial_out(up, UART_LCR, 0);
- serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_DISABLE);
switch (termios->c_cflag & CSIZE) {
case CS5:
cval = UART_LCR_WLEN5;
@@ -763,9 +824,12 @@
quot = serial_omap_get_divisor(port, baud);
if (up->use_dma)
- fcr[up->pdev->id - 1] = UART_FCR_ENABLE_FIFO | 0x1 << 6 | 0x1 << 4 | UART_FCR_DMA_SELECT;
+ fcr[up->pdev->id - 1] = UART_FCR_ENABLE_FIFO
+ | 0x1 << 6 | 0x1 << 4
+ | UART_FCR_DMA_SELECT;
else
- fcr[up->pdev->id - 1] = UART_FCR_ENABLE_FIFO | 0x1 << 6 | 0x1 << 4;
+ fcr[up->pdev->id - 1] = UART_FCR_ENABLE_FIFO
+ | 0x1 << 6 | 0x1 << 4;
/*
* Ok, we're now changing the port state. Do it with
@@ -814,44 +878,103 @@
up->ier |= UART_IER_MSI;
serial_out(up, UART_IER, up->ier);
- if (termios->c_cflag & CRTSCTS)
- efr |= (UART_EFR_CTS | UART_EFR_RTS);
-
- serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
- serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
-
serial_out(up, UART_LCR, cval); /* reset DLAB */
- up->lcr = cval; /* Save LCR */
- if (up->use_dma)
- serial_out(up, UART_OMAP_SCR , ((1 << 6) | (1 << 7)));
- serial_out(up, UART_LCR, 0xbf); /* Access EFR */
- serial_out(up, UART_EFR, UART_EFR_ECB);
- serial_out(up, UART_LCR, 0x0); /* Access FCR */
- serial_out(up, UART_FCR, fcr[up->pdev->id - 1]);
- serial_out(up, UART_LCR, 0xbf); /* Access EFR */
- serial_out(up, UART_EFR, efr);
- serial_out(up, UART_LCR, cval); /* Access FCR */
+ /*-----------FIFOs and DMA Settings -----------*/
+ serial_out(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_DLL, 0);
+ serial_out(up, UART_DLM, 0);
+ serial_out(up, UART_LCR, 0);
- serial_omap_set_mctrl(&up->port, up->port.mctrl);
+ serial_out(up, UART_LCR, 0xbf); /* Access EFR */
+
+ up->efr = serial_in(up, UART_EFR);
+ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+ serial_out(up, UART_LCR, 0x0); /* Access FCR */
+
/*
- * Clear all the status registers and RX register before
- * enabling UART
+ * old is NULL only if its coming out of Sleep Mode. The up-mcr
+ * would have a stored value in it, use the value itself. If
+ * coming up in a normal working state, the MCR register would
+ * have a valid value, hence read it and then use it.
*/
- (void) serial_in(up, UART_LSR);
- (void) serial_in(up, UART_RX);
- (void) serial_in(up, UART_IIR);
- (void) serial_in(up, UART_MSR);
+ if (NULL != old)
+ up->mcr = serial_in(up, UART_MCR);
+
+ serial_out(up, UART_MCR, up->mcr | 0x40); /* Access TLR*/
+ /* FIFO ENABLE, DMA MODE */
+ serial_out(up, UART_FCR, fcr[up->pdev->id - 1]);
+ serial_out(up, UART_LCR, 0xbf); /* Access EFR */
+
+ if (up->use_dma) {
+ serial_out(up, UART_TI752_TLR, 0x00);
+ serial_out(up, UART_OMAP_SCR, ((1 << 6) | (1 << 7)));
+ }
+
+ serial_out(up, UART_EFR, up->efr);
+ serial_out(up, UART_LCR, 0x80);
+ serial_out(up, UART_MCR, up->mcr); /* Restore TLR */
+
+ /*-----Protocol, Baud Rate, and Interrupt Settings -- */
+
+ serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_DISABLE);
+
+ serial_out(up, UART_LCR, 0xbf); /* Access EFR */
+
+ up->efr = serial_in(up, UART_EFR);
+ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+ serial_out(up, UART_LCR, 0);
+ serial_out(up, UART_IER, 0);
+ serial_out(up, UART_LCR, 0xbf);
+
+ serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
+ serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
+
+ serial_out(up, UART_LCR, 0);
+ serial_out(up, UART_IER, up->ier);
+ serial_out(up, UART_LCR, 0xbf); /* Access EFR */
+
+ serial_out(up, UART_EFR, up->efr);
+ serial_out(up, UART_LCR, cval);
if (baud > 230400 && baud != 3000000)
serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE13X);
else
serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE16X);
- spin_unlock_irqrestore(&up->port.lock, flags);
- DPRINTK("serial_omap_set_termios+%d\n",up->pdev->id);
+ /* Hardware Flow Control Configuration */
+
+ if (termios->c_cflag & CRTSCTS) {
+ efr |= (UART_EFR_CTS | UART_EFR_RTS);
+ serial_out(up, UART_LCR, 0x80);
+
+ up->mcr = serial_in(up, UART_MCR);
+ serial_out(up, UART_MCR, up->mcr | 0x40);
+
+ serial_out(up, UART_LCR, 0xbf); /* Access EFR */
+
+ up->efr = serial_in(up, UART_EFR);
+ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+ serial_out(up, UART_TI752_TCR, 0x0f);
+ serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */
+ serial_out(up, UART_LCR, 0x80);
+ serial_out(up, UART_MCR, up->mcr | 0x02);
+ serial_out(up, UART_LCR, cval);
+ }
+
+ serial_omap_set_mctrl(&up->port, up->port.mctrl);
+ /* ----Software Flow Control Configuration----- */
+ if (termios->c_iflag & (IXON | IXOFF))
+ serial_omap_configure_xonxoff(up, termios);
+
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ DPRINTK("serial_omap_set_termios+%d\n", up->pdev->id);
+
+#ifdef DEBUG
serial_omap_display_reg(port);
+#endif
}
static void
@@ -860,16 +983,22 @@
{
struct uart_omap_port *up = (struct uart_omap_port *)port;
unsigned char efr;
- DPRINTK("serial_omap_pm+%d\n",up->pdev->id);
+ DPRINTK("serial_omap_pm+%d\n", up->pdev->id);
+ DPRINTK(" PM STATE = %d \n", state);
efr = serial_in(up, UART_EFR);
serial_out(up, UART_LCR, 0xBF);
serial_out(up, UART_EFR, efr | UART_EFR_ECB);
serial_out(up, UART_LCR, 0);
- serial_out(up, UART_IER, (state!=0) ? UART_IERX_SLEEP: 0);
+ serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
serial_out(up, UART_LCR, 0xBF);
serial_out(up, UART_EFR, efr);
serial_out(up, UART_LCR, 0);
+ /* Enable module level wake up */
+ serial_out(up, UART_OMAP_WER, 0x7f);
+ /*Holding wakelock for UART*/
+ if (oldstate == 3)
+ wake_lock_timeout(&omap_serial_wakelock, 10*HZ);
}
static void serial_omap_release_port(struct uart_port *port)
@@ -887,7 +1016,7 @@
{
struct uart_omap_port *up = (struct uart_omap_port *)port;
- DPRINTK("serial_omap_config_port+%d\n",up->pdev->id);
+ DPRINTK("serial_omap_config_port+%d\n", up->pdev->id);
up->port.type = PORT_OMAP;
}
@@ -904,7 +1033,7 @@
{
struct uart_omap_port *up = (struct uart_omap_port *)port;
- DPRINTK("serial_omap_type+%d\n",up->pdev->id);
+ DPRINTK("serial_omap_type+%d\n", up->pdev->id);
return up->name;
}
@@ -1074,23 +1203,13 @@
};
static int serial_omap_remove(struct platform_device *dev);
-static int serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
+
+static
+int serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
{
struct uart_omap_port *up = platform_get_drvdata(pdev);
- unsigned int tmp;
-
if (up)
uart_suspend_port(&serial_omap_reg, &up->port);
- if (up->use_dma) {
- /*
- * Silicon Errata i291 workaround.
- * UART Module has to be put in force idle if it is
- * configured in DMA mode and when there is no activity
- * expected.
- */
- tmp = (serial_in(up, UART_OMAP_SYSC) & 0x7);
- serial_out(up, UART_OMAP_SYSC, tmp); /* force-idle */
- }
return 0;
}
@@ -1107,37 +1226,45 @@
{
struct uart_omap_port *up = ui[uart_no - 1];
unsigned int curr_dma_pos;
- curr_dma_pos = omap_readl(OMAP34XX_DMA4_BASE + OMAP_DMA4_CDAC(up->uart_dma.rx_dma_channel));
- if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) || (curr_dma_pos == 0)) {
+ curr_dma_pos = omap_readl(OMAP34XX_DMA4_BASE +
+ OMAP_DMA4_CDAC(up->uart_dma.rx_dma_channel));
+ if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) ||
+ (curr_dma_pos == 0)) {
/*
- * If there is no transfer rx happening for 10sec then stop the dma
- * else just restart the timer. See if 10 sec can be improved.
+ * If there is no transfer rx happening for 3sec
+ * then stop the dma else just restart the timer.
+ * See if 3 sec can be improved.
*/
- if (jiffies_to_msecs(jiffies - isr8250_activity) < 10000)
+ if (jiffies_to_msecs(jiffies - isr8250_activity) < 3000)
mod_timer(&up->uart_dma.rx_timer, jiffies +
usecs_to_jiffies(up->uart_dma.rx_timeout));
else {
- del_timer(&up->uart_dma.rx_timer);
serial_omap_stop_rxdma(up);
up->ier |= UART_IER_RDI;
serial_out(up, UART_IER, up->ier);
}
return;
- }
- else {
- unsigned int curr_transmitted_size = curr_dma_pos - up->uart_dma.prev_rx_dma_pos;
+ } else {
+ unsigned int curr_transmitted_size = curr_dma_pos -
+ up->uart_dma.prev_rx_dma_pos;
up->port.icount.rx += curr_transmitted_size;
- tty_insert_flip_string(up->port.info->port.tty, up->uart_dma.rx_buf + (up->uart_dma.prev_rx_dma_pos - up->uart_dma.rx_buf_dma_phys), curr_transmitted_size);
+ tty_insert_flip_string(up->port.info->port.tty,
+ up->uart_dma.rx_buf +
+ (up->uart_dma.prev_rx_dma_pos -
+ up->uart_dma.rx_buf_dma_phys),
+ curr_transmitted_size);
tty_flip_buffer_push(up->port.info->port.tty);
up->uart_dma.prev_rx_dma_pos = curr_dma_pos;
- if (up->uart_dma.rx_buf_size + up->uart_dma.rx_buf_dma_phys == curr_dma_pos) {
+
+ if (up->uart_dma.rx_buf_size +
+ up->uart_dma.rx_buf_dma_phys == curr_dma_pos)
serial_omap_start_rxdma(up);
- }
else
- mod_timer(&up->uart_dma.rx_timer, jiffies +
- usecs_to_jiffies(up->uart_dma.rx_timeout));
+ mod_timer(&up->uart_dma.rx_timer, jiffies +
+ usecs_to_jiffies(up->uart_dma.rx_timeout));
isr8250_activity = jiffies;
+
}
}
@@ -1148,47 +1275,40 @@
static void serial_omap_start_rxdma(struct uart_omap_port *up)
{
-#ifdef CONFIG_OMAP3_PM
- /* Disallow OCP bus idle. UART TX irqs are not seen during
- * bus idle. Alternative is to set kernel timer at fifo
- * drain rate.
- */
- unsigned int tmp;
- tmp = (serial_in(up, UART_OMAP_SYSC) & 0x7) | (1 << 3);
- serial_out(up, UART_OMAP_SYSC, tmp); /* no-idle */
-#endif
if (up->uart_dma.rx_dma_channel == 0xFF) {
- omap_request_dma(uart_dma_rx[up->pdev->id-1],"UART Rx DMA",
- (void *)uart_rx_dma_callback,up,
+ omap_request_dma(uart_dma_rx[up->pdev->id-1], "UART Rx DMA",
+ (void *)uart_rx_dma_callback, up,
&(up->uart_dma.rx_dma_channel));
+
omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0,
- OMAP_DMA_AMODE_CONSTANT,
- UART_BASE(up->pdev->id - 1), 0, 0);
+ OMAP_DMA_AMODE_CONSTANT,
+ UART_BASE(up->pdev->id - 1), 0, 0);
omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0,
- OMAP_DMA_AMODE_POST_INC,
- up->uart_dma.rx_buf_dma_phys, 0, 0);
+ OMAP_DMA_AMODE_POST_INC,
+ up->uart_dma.rx_buf_dma_phys, 0, 0);
omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel,
- OMAP_DMA_DATA_TYPE_S8,
- up->uart_dma.rx_buf_size, 1,
- OMAP_DMA_SYNC_ELEMENT,
- uart_dma_rx[up->pdev->id-1], 0);
+ OMAP_DMA_DATA_TYPE_S8,
+ up->uart_dma.rx_buf_size, 1,
+ OMAP_DMA_SYNC_ELEMENT,
+ uart_dma_rx[up->pdev->id-1], 0);
}
up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys;
- omap_writel(0, OMAP34XX_DMA4_BASE +
- OMAP_DMA4_CDAC(up->uart_dma.rx_dma_channel));
+ omap_writel(0, OMAP34XX_DMA4_BASE
+ + OMAP_DMA4_CDAC(up->uart_dma.rx_dma_channel));
omap_start_dma(up->uart_dma.rx_dma_channel);
mod_timer(&up->uart_dma.rx_timer, jiffies +
- usecs_to_jiffies(up->uart_dma.rx_timeout));
+ usecs_to_jiffies(up->uart_dma.rx_timeout));
up->uart_dma.rx_dma_state = 1;
+
}
static void serial_omap_continue_tx(struct uart_omap_port *up)
{
struct circ_buf *xmit = &up->port.info->xmit;
- int start = up->uart_dma.tx_buf_dma_phys + (xmit->tail & (UART_XMIT_SIZE - 1));
- if (uart_circ_empty(xmit)) {
- return;
- }
+ int start = up->uart_dma.tx_buf_dma_phys
+ + (xmit->tail & (UART_XMIT_SIZE - 1));
+ if (uart_circ_empty(xmit))
+ return;
up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
/* It is a circular buffer. See if the buffer has wounded back.
@@ -1200,12 +1320,14 @@
up->uart_dma.tx_buf_size =
(up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
- OMAP_DMA_AMODE_CONSTANT, UART_BASE(up->pdev->id - 1), 0,0);
+ OMAP_DMA_AMODE_CONSTANT,
+ UART_BASE(up->pdev->id - 1), 0, 0);
omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
- OMAP_DMA_AMODE_POST_INC, start, 0,0);
+ OMAP_DMA_AMODE_POST_INC, start, 0, 0);
omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
- OMAP_DMA_DATA_TYPE_S8, up->uart_dma.tx_buf_size, 1,
+ OMAP_DMA_DATA_TYPE_S8,
+ up->uart_dma.tx_buf_size, 1,
OMAP_DMA_SYNC_ELEMENT,
uart_dma_tx[(up->pdev->id)-1], 0);
@@ -1216,12 +1338,13 @@
{
struct uart_omap_port *up = (struct uart_omap_port *)data;
struct circ_buf *xmit = &up->port.info->xmit;
- xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & (UART_XMIT_SIZE - 1);
+ xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \
+ (UART_XMIT_SIZE - 1);
up->port.icount.tx += up->uart_dma.tx_buf_size;
/* Revisit: Not sure about the below two steps. Seen some instabilities
- * with them. might not be needed in the DMA path
- */
+ * with them. might not be needed in the DMA path
+ */
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
@@ -1235,8 +1358,8 @@
omap_stop_dma(up->uart_dma.tx_dma_channel);
serial_omap_continue_tx(up);
}
- isr8250_activity = jiffies;
+ isr8250_activity = jiffies;
return;
}
@@ -1284,7 +1407,7 @@
if (pdev->id == 4) {
up->port.membase = ioremap_nocache(mem->start, 0x16 << 1);
up->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP |
- UPF_SHARE_IRQ | UPF_TRIGGER_HIGH;
+ UPF_SHARE_IRQ | UPF_TRIGGER_HIGH;
up->port.uartclk = QUART_CLK;
up->port.regshift = 1;
} else {
@@ -1297,7 +1420,6 @@
up->port.regshift = 2;
}
-
if (pdev->id == (UART1+1)) {
#ifdef CONFIG_SERIAL_OMAP_DMA_UART1
up->use_dma = 1;
@@ -1330,10 +1452,9 @@
up->uart_dma.tx_dma_channel = 0xFF;
up->uart_dma.rx_dma_channel = 0xFF;
}
- if (console_detect(str)){
- printk("Invalid console paramter. UART Library Init Failed!\n");
- return -EPERM;
- }
+ if (console_detect(str))
+ printk(KERN_INFO "Invalid console paramter....\n");
+
up->use_console = 0;
fcr[pdev->id - 1] = 0;
if (!strcmp(str, "ttyS0"))
@@ -1346,15 +1467,15 @@
up->use_console = 1;
else
printk(KERN_INFO
- "!!!!!!!! Unable to recongnize Console UART........\n");
+ "!!!!!!!!! Unable to recongnize Console UART........\n");
ui[pdev->id - 1] = up;
serial_omap_add_console_port(up);
ret = uart_add_one_port(&serial_omap_reg, &up->port);
if (ret != 0)
goto do_release_region;
- platform_set_drvdata(pdev, up);
+ platform_set_drvdata(pdev, up);
return 0;
do_release_region:
release_mem_region(mem->start, (mem->end - mem->start) + 1);
@@ -1366,6 +1487,7 @@
struct uart_omap_port *up = platform_get_drvdata(dev);
platform_set_drvdata(dev, NULL);
+
if (up) {
uart_remove_one_port(&serial_omap_reg, &up->port);
kfree(up);
@@ -1387,6 +1509,8 @@
int __init serial_omap_init(void)
{
int ret;
+ wake_lock_init(&omap_serial_wakelock, WAKE_LOCK_SUSPEND,
+ "omap-serial");
ret = uart_register_driver(&serial_omap_reg);
if (ret != 0)
@@ -1399,16 +1523,17 @@
void __exit serial_omap_exit(void)
{
+ wake_lock_destroy(&omap_serial_wakelock);
platform_driver_unregister(&serial_omap_driver);
uart_unregister_driver(&serial_omap_reg);
}
-#if defined(CONFIG_OMAP3_PM)
-int omap24xx_uart_cts_wakeup(int uart_no, int state)
+int omap_uart_cts_wakeup(int uart_no, int state)
{
- u32 *ptr;
unsigned char lcr, efr;
struct uart_omap_port *up = ui[uart_no];
+ u32 padconf_cts;
+ u16 v;
if (unlikely(uart_no < 0 || uart_no > MAX_UARTS)) {
printk(KERN_INFO "Bad uart id %d \n", uart_no);
@@ -1421,21 +1546,28 @@
*/
switch (uart_no) {
case UART1:
- ptr = (u32 *) (&CONTROL_PADCONF_UART1_CTS);
+ printk(KERN_INFO "Enabling CTS wakeup for UART1");
+ padconf_cts = 0x180;
+ v = omap_ctrl_readw(padconf_cts);
break;
case UART2:
- ptr = (u32 *) (&CONTROL_PADCONF_UART2_CTS);
+ printk(KERN_INFO "Enabling CTS wakeup for UART2");
+ padconf_cts = 0x174;
+ v = omap_ctrl_readw(padconf_cts);
break;
default:
printk(KERN_ERR
"Wakeup on Uart%d is not supported\n", uart_no);
return -EPERM;
}
- *ptr |= (u32)((IO_PAD_WAKEUPENABLE | IO_PAD_OFFPULLUDENABLE |
- IO_PAD_OFFOUTENABLE | IO_PAD_OFFENABLE |
- IO_PAD_INPUTENABLE | IO_PAD_PULLUDENABLE|
- IO_PAD_MUXMODE0)
- );
+
+ v |= ((OMAP3_WAKEUP_EN | OMAP3_OFF_PULL_EN |
+ OMAP3_OFFOUT_VAL | OMAP3_OFFIN_EN |
+ OMAP3_OFF_EN | OMAP2_PULL_UP |
+ OMAP34XX_MUX_MODE0));
+
+ omap_ctrl_writew(v, padconf_cts);
+
/*
* Enable the CTS for module level wakeup
*/
@@ -1444,8 +1576,6 @@
efr = serial_in(up, UART_EFR);
serial_out(up, UART_EFR, efr | UART_EFR_ECB);
serial_out(up, UART_LCR, lcr);
- up->ier |= (1 << 7);
- serial_out(up, UART_IER, up->ier);
serial_out(up, UART_OMAP_WER,
serial_in(up, UART_OMAP_WER) | 0x1);
serial_out(up, UART_LCR, 0xbf);
@@ -1458,20 +1588,23 @@
*/
switch (uart_no) {
case UART1:
- ptr = (u32 *) (&CONTROL_PADCONF_UART1_CTS);
+ padconf_cts = 0x180;
+ v = omap_ctrl_readw(padconf_cts);
break;
case UART2:
- ptr = (u32 *) (&CONTROL_PADCONF_UART2_CTS);
+ padconf_cts = 0x174;
+ v = omap_ctrl_readw(padconf_cts);
break;
default:
printk(KERN_ERR
"Wakeup on Uart%d is not supported\n", uart_no);
return -EPERM;
}
- *ptr &= (u32) (~(IO_PAD_WAKEUPENABLE | IO_PAD_OFFPULLUDENABLE |
- IO_PAD_OFFOUTENABLE | IO_PAD_OFFENABLE |
- IO_PAD_INPUTENABLE | IO_PAD_PULLUDENABLE));
- *ptr |= IO_PAD_MUXMODE7;
+
+ v &= (u32)(~(OMAP3_WAKEUP_EN | OMAP3_OFF_PULL_EN |
+ OMAP3_OFF_EN | OMAP3_OFFIN_EN));
+
+ omap_ctrl_writew(v, padconf_cts);
/*
* Disable the CTS for module level wakeup
@@ -1481,111 +1614,97 @@
efr = serial_in(up, UART_EFR);
serial_out(up, UART_EFR, efr | UART_EFR_ECB);
serial_out(up, UART_LCR, lcr);
- up->ier &= ~(1 << 7);
- serial_out(up, UART_IER, up->ier);
- /* TBD:Do we really want to disable module wake up for this in WER*/
+
+ /* TBD:Do we really want to disable
+ * module wake up for this in WER
+ */
serial_out(up, UART_LCR, 0xbf);
serial_out(up, UART_EFR, efr);
serial_out(up, UART_LCR, lcr);
}
return 0;
}
-EXPORT_SYMBOL(omap24xx_uart_cts_wakeup);
+EXPORT_SYMBOL(omap_uart_cts_wakeup);
+
/**
- * are_driver8250_uarts_active() - Check if any ports managed by this
- * driver are currently busy. This should be called with interrupts
- * disabled.
+ * omap_uart_active() - Check if any ports managed by this
+ * driver are currently busy.
+ * Basically used for DMA mode check before putting it to
+ * force idle mode for errata 2.15 implementation.
*/
-int are_driveromap_uarts_active(int *driver8250_managed)
+
+int omap_uart_active(int num)
{
+ struct uart_omap_port *up = ui[num];
struct circ_buf *xmit;
unsigned int status;
- int j;
- *driver8250_managed = 0x7; /* OMAP has 3 UART instances */
- for (j = 0; j < 3; j++) {
- struct uart_omap_port *up = ui[j];
- /* check ownership of port */
- /* Check only ports managed by this driver and open */
- if((up->port.dev == NULL) || (up->port.type == PORT_UNKNOWN)){
- *driver8250_managed &= ~(1 << j);
- continue;
- }
-
- /* driver owns this port but its closed */
- if (up->port.info == NULL)
- continue;
-
- /* check for recent driver activity */
- /* if from now to last activty < 5 second keep clocks on */
- if ((jiffies_to_msecs(jiffies - isr8250_activity) < 5000))
- return 1;
-
- /* check for any current pending activity */
- /* Any queued work in ring buffer which can be handled still? */
- xmit = &up->port.info->xmit;
- if (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port)))
- return 1;
- status = serial_in(up, UART_LSR);
-
- /* TX hardware not empty/ */
- if (!(status & (UART_LSR_TEMT | UART_LSR_THRE)))
- return 1;
-
- /* Any rx activity? */
- if (status & UART_LSR_DR)
- return 1;
-
- /* Any modem activity */
- status = serial_in(up, UART_MSR);
- if (!((status & UART_MSR_ANY_DELTA) == 0))
- return 1;
- if (up->use_dma) {
- /*
- * Silicon Errata i291 workaround.
- * UART Module has to be put in force idle if it is
- * configured in DMA mode and when there is no activity
- * expected.
- */
- unsigned int tmp;
- tmp = (serial_in(up, UART_OMAP_SYSC) & 0x7);
- serial_out(up, UART_OMAP_SYSC, tmp); /* force-idle */
- }
- }
- if(*driver8250_managed) {
+ /* for DMA mode status of DMA channel
+ * will decide whether uart port can enter sleep
+ * or should we block sleep state.
+ */
+ if (up->use_dma &&
+ (up->uart_dma.tx_dma_channel != 0xFF ||
+ up->uart_dma.rx_dma_channel != 0xFF))
+ return 1;
+ else
return 0;
- }
- return 1;
+
+ /* check for recent driver activity */
+ /* if from now to last activty < 5 second keep clocks on */
+ if ((jiffies_to_msecs(jiffies - isr8250_activity) < 5000))
+ return 1;
+
+ xmit = &up->port.info->xmit;
+ if (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port)))
+ return 1;
+
+ status = serial_in(up, UART_LSR);
+ /* TX hardware not empty */
+ if (!(status & (UART_LSR_TEMT | UART_LSR_THRE)))
+ return 1;
+
+ /* Any rx activity? */
+ if (status & UART_LSR_DR)
+ return 1;
+
+ /* Any modem activity */
+ status = serial_in(up, UART_MSR);
+ if (!((status & UART_MSR_ANY_DELTA) == 0))
+ return 1;
+
+ return 0;
}
-EXPORT_SYMBOL(are_driveromap_uarts_active);
+EXPORT_SYMBOL(omap_uart_active);
-#endif
+#ifdef DEBUG
+#define UART_OMAP_SPR 0x07 /* Scratchpad register */
static void serial_omap_display_reg(struct uart_port *port)
{
struct uart_omap_port *up = (struct uart_omap_port *)port;
unsigned int lcr, efr, mcr, dll, dlh, xon1, xon2, xoff1, xoff2;
unsigned int tcr, tlr, uasr;
- DPRINTK("Register dump for UART%d\n",up->pdev->id);
- DPRINTK("IER_REG=0x%x\n",serial_in(up, UART_IER));
- DPRINTK("IIR_REG=0x%x\n",serial_in(up, UART_IIR));
+ DPRINTK("Register dump for UART%d\n", up->pdev->id);
+ DPRINTK("IER_REG = 0x%x\n", serial_in(up, UART_IER));
+ DPRINTK("IIR_REG = 0x%x\n", serial_in(up, UART_IIR));
lcr = serial_in(up, UART_LCR);
- DPRINTK("LCR_REG=0x%x\n", lcr);
+ DPRINTK("LCR_REG = 0x%x\n", lcr);
mcr = serial_in(up, UART_MCR);
- DPRINTK("MCR_REG=0x%x\n", mcr);
- DPRINTK("LSR_REG=0x%x\n", serial_in(up, UART_LSR));
- DPRINTK("MSR_REG=0x%x\n", serial_in(up, UART_MSR));
- DPRINTK("SPR_REG=0x%x\n", serial_in(up, UART_OMAP_SPR));
- DPRINTK("MDR1_REG=0x%x\n", serial_in(up, UART_OMAP_MDR1));
- DPRINTK("MDR2_REG=0x%x\n", serial_in(up, UART_OMAP_MDR2));
- DPRINTK("SCR_REG=0x%x\n", serial_in(up, UART_OMAP_SCR));
- DPRINTK("SSR_REG=0x%x\n", serial_in(up, UART_OMAP_SSR));
- DPRINTK("MVR_REG=0x%x\n", serial_in(up, UART_OMAP_MVER));
- DPRINTK("SYSC_REG=0x%x\n", serial_in(up, UART_OMAP_SYSC));
- DPRINTK("SYSS_REG=0x%x\n", serial_in(up, UART_OMAP_SYSS));
- DPRINTK("WER_REG=0x%x\n", serial_in(up, UART_OMAP_WER));
+ DPRINTK("MCR_REG = 0x%x\n", mcr);
+ DPRINTK("LSR_REG = 0x%x\n", serial_in(up, UART_LSR));
+ DPRINTK("MSR_REG = 0x%x\n", serial_in(up, UART_MSR));
+ DPRINTK("SPR_REG = 0x%x\n", serial_in(up, UART_OMAP_SPR));
+ DPRINTK("MDR1_REG = 0x%x\n", serial_in(up, UART_OMAP_MDR1));
+ DPRINTK("MDR2_REG = 0x%x\n", serial_in(up, UART_OMAP_MDR2));
+ DPRINTK("SCR_REG = 0x%x\n", serial_in(up, UART_OMAP_SCR));
+ DPRINTK("SSR_REG = 0x%x\n", serial_in(up, UART_OMAP_SSR));
+ DPRINTK("MVR_REG = 0x%x\n", serial_in(up, UART_OMAP_MVER));
+ DPRINTK("SYSC_REG = 0x%x\n", serial_in(up, UART_OMAP_SYSC));
+ DPRINTK("SYSS_REG = 0x%x\n", serial_in(up, UART_OMAP_SYSS));
+ DPRINTK("WER_REG = 0x%x\n", serial_in(up, UART_OMAP_WER));
- serial_out(up,UART_LCR, 0xBF);
+ serial_out(up, UART_LCR, 0xBF);
dll = serial_in(up, UART_DLL);
dlh = serial_in(up, UART_DLM);
efr = serial_in(up, UART_EFR);
@@ -1595,14 +1714,14 @@
serial_out(up, UART_EFR, efr | UART_EFR_ECB);
serial_out(up, UART_LCR, lcr);
serial_out(up, UART_MCR, mcr | UART_MCR_TCRTLR);
- serial_out(up,UART_LCR, 0xBF);
+ serial_out(up, UART_LCR, 0xBF);
tcr = serial_in(up, UART_TI752_TCR);
tlr = serial_in(up, UART_TI752_TLR);
serial_out(up, UART_LCR, lcr);
serial_out(up, UART_MCR, mcr);
- serial_out(up,UART_LCR, 0xBF);
+ serial_out(up, UART_LCR, 0xBF);
xoff1 = serial_in(up, UART_XOFF1);
xoff2 = serial_in(up, UART_XOFF2);
@@ -1612,21 +1731,22 @@
serial_out(up, UART_LCR, lcr);
- DPRINTK("DLL_REG=0x%x\n", dll);
- DPRINTK("DLH_REG=0x%x\n", dlh);
- DPRINTK("EFR_REG=0x%x\n",efr);
+ DPRINTK("DLL_REG = 0x%x\n", dll);
+ DPRINTK("DLH_REG = 0x%x\n", dlh);
+ DPRINTK("EFR_REG = 0x%x\n", efr);
- DPRINTK("XON1_ADDR_REG=0x%x\n",xon1);
- DPRINTK("XON2_ADDR_REG=0x%x\n",xon2);
- DPRINTK("TCR_REG=0x%x\n",tcr);
- DPRINTK("TLR_REG=0x%x\n",tlr);
+ DPRINTK("XON1_ADDR_REG = 0x%x\n", xon1);
+ DPRINTK("XON2_ADDR_REG = 0x%x\n", xon2);
+ DPRINTK("TCR_REG = 0x%x\n", tcr);
+ DPRINTK("TLR_REG = 0x%x\n", tlr);
- DPRINTK("XOFF1_REG=0x%x\n", xoff1);
- DPRINTK("XOFF2_REG=0x%x\n", xoff2);
- DPRINTK("UASR_REG=0x%x\n", uasr);
+ DPRINTK("XOFF1_REG = 0x%x\n", xoff1);
+ DPRINTK("XOFF2_REG = 0x%x\n", xoff2);
+ DPRINTK("UASR_REG = 0x%x\n", uasr);
}
+#endif
subsys_initcall(serial_omap_init);
module_exit(serial_omap_exit);
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index 3da8825..ad86587 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -779,7 +779,6 @@
spi = m->spi;
cs = spi->controller_state;
- omap2_mcspi_set_enable(spi, 1);
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
status = -EINVAL;
@@ -807,6 +806,10 @@
chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
mcspi_write_chconf0(spi, chconf);
+ omap2_mcspi_set_master_mode(mcspi->master);
+
+ omap2_mcspi_set_enable(spi, 1);
+
if (t->len) {
unsigned count;
@@ -835,6 +838,9 @@
omap2_mcspi_force_cs(spi, 0);
cs_active = 0;
}
+ chconf = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+ if (chconf & OMAP2_MCSPI_CHCONF_FORCE)
+ omap2_mcspi_set_enable(spi, 0);
}
/* Restore defaults if they were overriden */
@@ -863,8 +869,8 @@
static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
{
struct omap2_mcspi *mcspi;
- unsigned long flags;
- struct spi_transfer *t;
+ unsigned long uninitialized_var(flags);
+ struct spi_transfer *uninitialized_var(t);
m->actual_length = 0;
m->status = 0;
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
index 3375c1c..0ee25bd 100644
--- a/drivers/staging/android/ram_console.c
+++ b/drivers/staging/android/ram_console.c
@@ -146,6 +146,14 @@
.index = -1,
};
+void ram_console_enable_console(int enabled)
+{
+ if (enabled)
+ ram_console.flags |= CON_ENABLED;
+ else
+ ram_console.flags &= ~CON_ENABLED;
+}
+
static void __init
ram_console_save_old(struct ram_console_buffer *buffer, char *dest)
{
diff --git a/drivers/switch/switch_gpio.c b/drivers/switch/switch_gpio.c
index b5f98ca..d585663 100644
--- a/drivers/switch/switch_gpio.c
+++ b/drivers/switch/switch_gpio.c
@@ -111,7 +111,8 @@
}
ret = request_irq(switch_data->irq, gpio_irq_handler,
- IRQF_TRIGGER_LOW, pdev->name, switch_data);
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ pdev->name, switch_data);
if (ret < 0)
goto err_request_irq;
@@ -163,7 +164,11 @@
platform_driver_unregister(&gpio_switch_driver);
}
+#ifndef MODULE
+late_initcall(gpio_switch_init);
+#else
module_init(gpio_switch_init);
+#endif
module_exit(gpio_switch_exit);
MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index b3d5a23..7f2909a 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -546,10 +546,6 @@
tty->driver_data = acm;
acm->tty = tty;
- /* force low_latency on so that our tty_push actually forces the data through,
- otherwise it is scheduled, and with high data rates data can get lost. */
- tty->low_latency = 1;
-
if (usb_autopm_get_interface(acm->control) < 0)
goto early_bail;
else
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 07fae55..e01b146 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -134,14 +134,35 @@
return adb_function_add(dev->cdev, c);
}
+static int android_setup_config(struct usb_configuration *c,
+ const struct usb_ctrlrequest *ctrl);
+
static struct usb_configuration android_config_driver = {
.label = "android",
.bind = android_bind_config,
+ .setup = android_setup_config,
.bConfigurationValue = 1,
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
.bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
};
+static int android_setup_config(struct usb_configuration *c,
+ const struct usb_ctrlrequest *ctrl)
+{
+ int i;
+ int ret = -EOPNOTSUPP;
+
+ for (i = 0; i < android_config_driver.next_interface_id; i++) {
+ if (android_config_driver.interface[i]->setup) {
+ ret = android_config_driver.interface[i]->setup(
+ android_config_driver.interface[i], ctrl);
+ if (ret >= 0)
+ return ret;
+ }
+ }
+ return ret;
+}
+
static int __init android_bind(struct usb_composite_dev *cdev)
{
struct android_dev *dev = _android_dev;
@@ -173,6 +194,9 @@
strings_dev[STRING_SERIAL_IDX].id = id;
device_desc.iSerialNumber = id;
+ if (gadget->ops->wakeup)
+ android_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+
/* register our configuration */
ret = usb_add_config(cdev, &android_config_driver);
if (ret) {
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 6995a10..5cd5f8c 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -266,7 +266,7 @@
descriptors = f->hs_descriptors;
else
descriptors = f->descriptors;
- if (!descriptors || descriptors[0] == NULL) {
+ if (f->hidden || !descriptors || descriptors[0] == NULL) {
for (; f != config->interface[interfaceCount];) {
interfaceCount++;
c->bNumInterfaces--;
@@ -835,6 +835,25 @@
value = c->setup(c, ctrl);
}
+ /* If the vendor request is not processed (value < 0),
+ * call all device registered configure setup callbacks
+ * to process it.
+ * This is used to handle the following cases:
+ * - vendor request is for the device and arrives before
+ * setconfiguration.
+ * - Some devices are required to handle vendor request before
+ * setconfiguration such as MTP, USBNET.
+ */
+
+ if (value < 0) {
+ struct usb_configuration *cfg;
+
+ list_for_each_entry(cfg, &cdev->configs, list) {
+ if (cfg && cfg->setup)
+ value = cfg->setup(cfg, ctrl);
+ }
+ }
+
goto done;
}
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index d81ce9e..f63f572 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -251,7 +251,6 @@
/* Big enough to hold our biggest descriptor */
#define EP0_BUFSIZE 256
-#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
/* Number of buffers we will use. 2 is enough for double-buffering */
#define NUM_BUFFERS 2
@@ -662,7 +661,7 @@
* and reinitialize our state. */
DBG(fsg, "bulk reset request\n");
raise_exception(fsg, FSG_STATE_RESET);
- value = DELAYED_STATUS;
+ value = 0;
break;
case USB_BULK_GET_MAX_LUN_REQUEST:
@@ -680,6 +679,16 @@
}
}
+ /* respond with data transfer or status phase? */
+ if (value >= 0) {
+ int rc;
+ cdev->req->zero = value < w_length;
+ cdev->req->length = value;
+ rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
+ if (rc < 0)
+ printk("%s setup response queue error\n", __func__);
+ }
+
if (value == -EOPNOTSUPP)
VDBG(fsg,
"unknown class-specific control req "
@@ -2063,8 +2072,12 @@
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
rc = sleep_thread(fsg);
- if (rc)
+ if (rc) {
+ usb_ep_dequeue(fsg->bulk_out, bh->outreq);
+ bh->outreq_busy = 0;
+ bh->state = BUF_STATE_EMPTY;
return rc;
+ }
}
/* Queue a request to read a Bulk-only CBW */
@@ -2135,16 +2148,16 @@
DBG(fsg, "reset interface\n");
reset:
/* Disable the endpoints */
- if (fsg->bulk_in_enabled) {
- DBG(fsg, "usb_ep_disable %s\n", fsg->bulk_in->name);
- usb_ep_disable(fsg->bulk_in);
- fsg->bulk_in_enabled = 0;
- }
- if (fsg->bulk_out_enabled) {
- DBG(fsg, "usb_ep_disable %s\n", fsg->bulk_out->name);
- usb_ep_disable(fsg->bulk_out);
- fsg->bulk_out_enabled = 0;
- }
+ if (fsg->bulk_in_enabled) {
+ DBG(fsg, "usb_ep_disable %s\n", fsg->bulk_in->name);
+ usb_ep_disable(fsg->bulk_in);
+ fsg->bulk_in_enabled = 0;
+ }
+ if (fsg->bulk_out_enabled) {
+ DBG(fsg, "usb_ep_disable %s\n", fsg->bulk_out->name);
+ usb_ep_disable(fsg->bulk_out);
+ fsg->bulk_out_enabled = 0;
+ }
/* Deallocate the requests */
for (i = 0; i < NUM_BUFFERS; ++i) {
@@ -2281,12 +2294,18 @@
}
}
- /* Clear out the controller's fifos */
- if (fsg->bulk_in_enabled)
- usb_ep_fifo_flush(fsg->bulk_in);
- if (fsg->bulk_out_enabled)
- usb_ep_fifo_flush(fsg->bulk_out);
-
+ /*
+ * Do NOT flush the fifo after set_interface()
+ * Otherwise, it results in some data being lost
+ */
+ if ((fsg->state != FSG_STATE_CONFIG_CHANGE) ||
+ (fsg->new_config != 1)) {
+ /* Clear out the controller's fifos */
+ if (fsg->bulk_in_enabled)
+ usb_ep_fifo_flush(fsg->bulk_in);
+ if (fsg->bulk_out_enabled)
+ usb_ep_fifo_flush(fsg->bulk_out);
+ }
/* Reset the I/O buffer states and pointers, the SCSI
* state, and the exception. Then invoke the handler. */
spin_lock_irq(&fsg->lock);
@@ -2924,7 +2943,7 @@
goto err_platform_driver_register;
wake_lock_init(&the_fsg->wake_lock, WAKE_LOCK_SUSPEND,
- "usb_mass_storage");
+ "usb_mass_storage");
fsg->cdev = cdev;
fsg->function.name = shortname;
@@ -2943,6 +2962,7 @@
return 0;
err_usb_add_function:
+ wake_lock_destroy(&the_fsg->wake_lock);
platform_driver_unregister(&fsg_platform_driver);
err_platform_driver_register:
switch_dev_unregister(&the_fsg->sdev);
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 96d65ca..334f7d1 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -54,6 +54,15 @@
#define UETH__VERSION "29-May-2008"
+/*
+ * Override the NET_IP_ALIGN macro to 0 bytes to have destination buffer
+ * aligned at 4 bytes thereby getting alligned adress for DMA access
+ */
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
+#undef NET_IP_ALIGN
+#define NET_IP_ALIGN 0
+#endif
+
struct eth_dev {
/* lock is held while accessing port_usb
* or updating its backlink port_usb->ioport
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 02df795..c8779f8 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -159,6 +159,7 @@
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
+ select ISP1301_HOST if MACH_OMAP_3430SDP
select USB_OTG_UTILS if ARCH_OMAP
---help---
The Open Host Controller Interface (OHCI) is a standard for accessing
@@ -173,6 +174,107 @@
To compile this driver as a module, choose M here: the
module will be called ohci-hcd.
+choice
+ prompt "PHY/TLL mode"
+ depends on USB_OHCI_HCD && ARCH_OMAP34XX
+ ---help---
+ Choose PHY or TLL mode of operation for expansion board 750-2099-001(C)
+ The expansion board has been designed as:
+ Port1 connected to ISP1504
+ Port2 connected to ISP1504
+ Port3 connected to ISP1301
+
+config OMAP_OHCI_PHY_MODE
+ bool "OHCI PHY mode"
+ depends on USB_OHCI_HCD && ARCH_OMAP34XX
+ ---help---
+ OHCI PHY mode or TLL mode of operation to be chosen
+
+config OMAP_OHCI_PHY_MODE_PINS
+ bool "OHCI PHY mode Pins"
+ depends on OMAP_OHCI_PHY_MODE && USB_OHCI_HCD
+ default y
+ ---help---
+ OHCI PHY mode Number of pins
+
+config OMAP_OHCI_PHY_MODE_3PIN
+ bool "phy 3-pin"
+ depends on OMAP_OHCI_PHY_MODE_PINS
+ default y
+ ---help---
+ OHCI PHY 3-pin
+
+config OMAP_OHCI_PHY_MODE_4PIN
+ bool "phy 4-pin"
+ depends on OMAP_OHCI_PHY_MODE_PINS
+ ---help---
+ OHCI PHY 4-pin
+ This is not implemented yet.
+
+config OMAP_OHCI_PHY_MODE_6PIN_DAT_SE0
+ bool "phy 6-pin dat/se0"
+ depends on OMAP_OHCI_PHY_MODE_PINS
+ ---help---
+ OHCI PHY 6-pin dat/se0
+ This is not implemented yet.
+
+config OMAP_OHCI_PHY_MODE_6PIN_DP_DM
+ bool "phy 6-pin dp/dm"
+ depends on OMAP_OHCI_PHY_MODE_PINS
+ ---help---
+ OHCI PHY 6-pin dp/dm
+ This is not implemented yet.
+
+config OMAP_OHCI_TLL_MODE
+ bool "OHCI TLL mode"
+ depends on USB_OHCI_HCD && ARCH_OMAP34XX
+ ---help---
+ OHCI PHY mode or TLL mode of operation to be chosen
+
+config OMAP_OHCI_TLL_MODE_PINS
+ bool "OHCI TLL mode Pins (NOT-IMPLEMENTED)"
+ depends on OMAP_OHCI_TLL_MODE
+ ---help---
+ OHCI TLL mode Number of pins
+
+config OMAP_OHCI_TLL_MODE_2PIN_DAT_SE0
+ bool "phy 2-pin DAT/SE0"
+ depends on OMAP_OHCI_TLL_MODE_PINS
+ ---help---
+ OHCI TLL
+
+config OMAP_OHCI_TLL_MODE_2PIN_DP_DM
+ bool "phy 2-pin DP/DM"
+ depends on OMAP_OHCI_TLL_MODE_PINS
+ ---help---
+ OHCI TLL
+
+config OMAP_OHCI_TLL_MODE_4PIN
+ bool "phy 4-pin"
+ depends on OMAP_OHCI_TLL_MODE_PINS
+ ---help---
+ OHCI TLL
+
+config OMAP_OHCI_TLL_MODE_3PIN
+ bool "phy 3-pin"
+ depends on OMAP_OHCI_TLL_MODE_PINS
+ ---help---
+ OHCI TLL
+
+config OMAP_OHCI_TLL_MODE_6PIN_DAT_SE0
+ bool "phy 6-pin DAT/SE0"
+ depends on OMAP_OHCI_TLL_MODE_PINS
+ ---help---
+ OHCI TLL
+
+config OMAP_OHCI_TLL_MODE_6PIN_DP_DM
+ bool "phy 6-pin DAT/SE0"
+ depends on OMAP_OHCI_TLL_MODE_PINS
+ ---help---
+ OHCI TLL
+endchoice
+
+
config USB_OHCI_HCD_PPC_SOC
bool "OHCI support for on-chip PPC USB controller"
depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 97a53a4..ec082b7 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -567,6 +567,7 @@
unsigned long flags;
int retval = 0;
unsigned selector;
+ u32 runstop;
/*
* FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
@@ -708,6 +709,19 @@
set_bit(wIndex, &ehci->port_c_suspend);
ehci->reset_done[wIndex] = 0;
+ /* Workaround for OMAP errata:
+ * The errata affects suspend-resume and
+ * remote-wakeup. We need to halt the
+ * controller before clearing the resume bit
+ */
+ runstop = ehci_readl(ehci,
+ &ehci->regs->command);
+ ehci_writel(ehci, (runstop & ~1),
+ &ehci->regs->command);
+ (void) ehci_readl(ehci, &ehci->regs->command);
+ handshake(ehci, &ehci->regs->status,
+ STS_HALT, STS_HALT, 2000);
+
/* stop resume signaling */
temp = ehci_readl(ehci, status_reg);
ehci_writel(ehci,
@@ -715,6 +729,11 @@
status_reg);
retval = handshake(ehci, status_reg,
PORT_RESUME, 0, 2000 /* 2msec */);
+
+ ehci_writel(ehci, runstop,
+ &ehci->regs->command);
+ (void) ehci_readl(ehci, &ehci->regs->command);
+
if (retval != 0) {
ehci_err(ehci,
"port %d resume error %d\n",
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index c6b1d02..1933c48 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -54,8 +54,16 @@
* Release the reset after a delay -
* to get the PHY state machine in working state
*/
-
+/* Setting:
+ * Additional switch settings SW4.8=off, S5=1-2, S6=2-3
+ * USB1HS EHCI PHY mode tested on SDP3630-V0-1-0 board using
+ * 750-2099-003(A) daughter card.
+ */
+#ifdef CONFIG_MACH_OMAP_3630SDP
+#define EXT_PHY_RESET_GPIO_PORT1 (126)
+#else
#define EXT_PHY_RESET_GPIO_PORT1 (57)
+#endif
#define EXT_PHY_RESET_GPIO_PORT2 (61)
static int default_usb_port_startup(struct platform_device *dev, int port)
@@ -82,6 +90,7 @@
return r;
}
gpio_direction_output(gpio, 0);
+ gpio_set_value(gpio, 1);
return 0;
}
@@ -140,16 +149,18 @@
static struct omap_usb_port_data default_usb_port_data[] = {
[0] = {
- .flags = OMAP_USB_PORT_FLAG_ENABLED,
- .mode = OMAP_USB_PORT_MODE_UTMI_PHY_6PIN,
+ .flags = (OMAP_USB_PORT_FLAG_ENABLED | \
+ OMAP_USB_PORT_FLAG_AUTOIDLE| \
+ OMAP_USB_PORT_FLAG_NOBITSTUFF),
+ .mode = OMAP_USB_PORT_MODE_ULPI_TLL_SDR,
},
[1] = {
- .flags = OMAP_USB_PORT_FLAG_ENABLED,
- .mode = OMAP_USB_PORT_MODE_ULPI_PHY,
+ .flags = OMAP_USB_PORT_FLAG_AUTOIDLE,
+ .mode = OMAP_USB_PORT_MODE_ULPI_TLL_SDR,
},
[2] = {
- .flags = OMAP_USB_PORT_FLAG_ENABLED,
- .mode = OMAP_USB_PORT_MODE_ULPI_PHY,
+ .flags = OMAP_USB_PORT_FLAG_AUTOIDLE,
+ .mode = OMAP_USB_PORT_MODE_ULPI_TLL_SDR,
},
};
@@ -371,45 +382,6 @@
((char *)hcd_to_ehci(hcd)) +
sizeof(struct ehci_hcd));
- /* Start DPLL5 Programming:
- * Clock Framework is not doing this now:
- * This will be done in clock framework later
- */
- /* Enable DPLL 5 : Based on Input of 13Mhz*/
- cm_write_mod_reg((12 << OMAP3430ES2_PERIPH2_DPLL_DIV_SHIFT)|
- (120 << OMAP3430ES2_PERIPH2_DPLL_MULT_SHIFT),
- PLL_MOD, OMAP3430ES2_CM_CLKSEL4);
-
- cm_write_mod_reg(1 << OMAP3430ES2_DIV_120M_SHIFT,
- PLL_MOD, OMAP3430ES2_CM_CLKSEL5);
-
- cm_write_mod_reg((7 << OMAP3430ES2_PERIPH2_DPLL_FREQSEL_SHIFT) |
- (7 << OMAP3430ES2_EN_PERIPH2_DPLL_SHIFT),
- PLL_MOD, OMAP3430ES2_CM_CLKEN2);
-
- while (!(cm_read_mod_reg(PLL_MOD, CM_IDLEST2) &
- OMAP3430ES2_ST_PERIPH2_CLK_MASK))
- dev_dbg(hcd->self.controller,
- "idlest2 = 0x%x\n",
- cm_read_mod_reg(PLL_MOD, CM_IDLEST2));
- /* End DPLL5 programming */
-
-
- /* PRCM settings for USBHOST:
- * Interface clk un-related to domain transition
- */
- cm_write_mod_reg(0 << OMAP3430ES2_AUTO_USBHOST_SHIFT,
- OMAP3430ES2_USBHOST_MOD, CM_AUTOIDLE);
-
- /* Disable sleep dependency with MPU and IVA */
- cm_write_mod_reg((0 << OMAP3430ES2_EN_MPU_SHIFT) |
- (0 << OMAP3430ES2_EN_IVA2_SHIFT),
- OMAP3430ES2_USBHOST_MOD, OMAP3430_CM_SLEEPDEP);
-
- /* Disable Automatic transition of clock */
- cm_write_mod_reg(0 << OMAP3430ES2_CLKTRCTRL_USBHOST_SHIFT,
- OMAP3430ES2_USBHOST_MOD, CM_CLKSTCTRL);
-
/* Enable Clocks for USBHOST */
ehci_clocks->usbhost_ick_clk = clk_get(&dev->dev,
USBHOST_ICKL);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 5cf5f1e..bf75a84 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1002,7 +1002,10 @@
#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
#endif
-#ifdef CONFIG_ARCH_OMAP
+#ifdef CONFIG_ARCH_OMAP3
+#include "ohci-omap3.c"
+#define PLATFORM_DRIVER ohci_hcd_omap_driver
+#elif defined(CONFIG_ARCH_OMAP)
#include "ohci-omap.c"
#define PLATFORM_DRIVER ohci_hcd_omap_driver
#endif
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
new file mode 100644
index 0000000..7489c4e
--- /dev/null
+++ b/drivers/usb/host/ohci-omap3.c
@@ -0,0 +1,845 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2005 David Brownell
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2007-2009 Texas Instruments
+ * (C) Copyright 2007 Vikram Pandita <vikram.pandita@ti.com>
+ * (C) Copyright 2008 Romit Dasgupta <romit@ti.com>
+ * (C) Copyright 2008-2009 Anand Gadiyar <gadiyar@ti.com>
+ *
+ * OMAP Bus Glue
+ *
+ * Modified for OMAP by Tony Lindgren <tony@atomide.com>
+ * Based on the 2.4 OMAP OHCI driver originally done by MontaVista Software Inc.
+ * and on ohci-sa1111.c by Christopher Hoover <ch@hpl.hp.com>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h> /* IRQF_DISABLED */
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <mach/irqs.h>
+#include <mach/usb.h>
+
+#include "ehci-omap.h"
+
+#ifndef CONFIG_ARCH_OMAP
+#error "This file is OMAP bus glue. CONFIG_OMAP must be defined."
+#endif
+
+extern int usb_disabled(void);
+extern int ocpi_enable(void);
+
+/* Define USBHOST clocks for clock management */
+struct ohci_omap_clock_defs {
+ struct clk *usbhost_ick_clk;
+ struct clk *usbhost2_120m_fck_clk;
+ struct clk *usbhost1_48m_fck_clk;
+ struct clk *usbtll_fck_clk;
+ struct clk *usbtll_ick_clk;
+ unsigned suspended:1;
+ /*
+ * TODO:
+ * host_enabled should be put in separate place.
+ */
+ unsigned host_enabled:1;
+};
+
+static struct ohci_context_registers {
+ u32 usbtll_sysconfig;
+ u32 usbtll_irqenable;
+ u32 tll_shared_conf;
+ u32 tll_channel_conf[3];
+ u8 ulpi_function_ctrl[3];
+ u8 ulpi_interface_ctrl[3];
+ u8 ulpi_otg_ctrl[3];
+ u8 ulpi_usb_int_en_rise[3];
+ u8 ulpi_usb_int_en_fall[3];
+ u8 ulpi_usb_int_status[3];
+ u8 ulpi_vendor_int_en[3];
+ u8 ulpi_vendor_int_status[3];
+} ohci_context;
+
+/* Clock names as per clock framework: May change so keep as #defs */
+#define USBHOST_ICLK "usbhost_ick"
+#define USBHOST_120M_FCLK "usbhost_120m_fck"
+#define USBHOST_48M_FCLK "usbhost_48m_fck"
+#define USBHOST_TLL_ICLK "usbtll_ick"
+#define USBHOST_TLL_FCLK "usbtll_fck"
+
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_omap_init(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ dev_dbg(hcd->self.controller, "starting USB Controller\n");
+
+ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+ /* board init will have already handled HMC and mux setup.
+ * any external transceiver should already be initialized
+ * too, so all configured ports use the right signaling now.
+ */
+
+ return 0;
+}
+
+static void ohci_omap_stop(struct usb_hcd *hcd)
+{
+ dev_dbg(hcd->self.controller, "stopping USB Controller\n");
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ * usb_hcd_omap_probe - initialize OMAP-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ */
+static int usb_hcd_omap_probe(const struct hc_driver *driver,
+ struct platform_device *pdev)
+{
+ int retval;
+ int i;
+ u32 uhh_hostconfig_value;
+ u8 ohci_port_enable_mask = 0;
+ struct usb_hcd *hcd = 0;
+ struct ohci_hcd *ohci;
+ struct ohci_omap_clock_defs *ohci_clocks;
+
+ if (pdev->num_resources != 2) {
+ printk(KERN_ERR "hcd probe: invalid num_resources: %i\n",
+ pdev->num_resources);
+ return -ENODEV;
+ }
+
+ if (pdev->resource[0].flags != IORESOURCE_MEM
+ || pdev->resource[1].flags != IORESOURCE_IRQ) {
+ printk(KERN_ERR "hcd probe: invalid resource type\n");
+ return -ENODEV;
+ }
+
+ hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto err0;
+ }
+
+ ohci_clocks = (struct ohci_omap_clock_defs *)
+ (((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+
+ /* Enable Clocks for USBHOST */
+ ohci_clocks->usbhost_ick_clk = clk_get(&pdev->dev,
+ USBHOST_ICLK);
+ if (IS_ERR(ohci_clocks->usbhost_ick_clk))
+ return PTR_ERR(ohci_clocks->usbhost_ick_clk);
+ clk_enable(ohci_clocks->usbhost_ick_clk);
+
+ ohci_clocks->usbhost2_120m_fck_clk = clk_get(&pdev->dev,
+ USBHOST_120M_FCLK);
+ if (IS_ERR(ohci_clocks->usbhost2_120m_fck_clk)) {
+ clk_disable(ohci_clocks->usbhost_ick_clk);
+ clk_put(ohci_clocks->usbhost_ick_clk);
+ return PTR_ERR(ohci_clocks->usbhost2_120m_fck_clk);
+ }
+ clk_enable(ohci_clocks->usbhost2_120m_fck_clk);
+
+ ohci_clocks->usbhost1_48m_fck_clk = clk_get(&pdev->dev,
+ USBHOST_48M_FCLK);
+ if (IS_ERR(ohci_clocks->usbhost1_48m_fck_clk)) {
+ clk_disable(ohci_clocks->usbhost_ick_clk);
+ clk_put(ohci_clocks->usbhost_ick_clk);
+ clk_disable(ohci_clocks->usbhost2_120m_fck_clk);
+ clk_put(ohci_clocks->usbhost2_120m_fck_clk);
+ return PTR_ERR(ohci_clocks->usbhost1_48m_fck_clk);
+ }
+ clk_enable(ohci_clocks->usbhost1_48m_fck_clk);
+
+ /* Configure TLL for 60Mhz clk for ULPI */
+ ohci_clocks->usbtll_fck_clk = clk_get(&pdev->dev,
+ USBHOST_TLL_FCLK);
+ if (IS_ERR(ohci_clocks->usbtll_fck_clk)) {
+ clk_disable(ohci_clocks->usbhost_ick_clk);
+ clk_put(ohci_clocks->usbhost_ick_clk);
+ clk_disable(ohci_clocks->usbhost2_120m_fck_clk);
+ clk_put(ohci_clocks->usbhost2_120m_fck_clk);
+ clk_disable(ohci_clocks->usbhost1_48m_fck_clk);
+ clk_put(ohci_clocks->usbhost1_48m_fck_clk);
+ return PTR_ERR(ohci_clocks->usbtll_fck_clk);
+ }
+ clk_enable(ohci_clocks->usbtll_fck_clk);
+
+ ohci_clocks->usbtll_ick_clk = clk_get(&pdev->dev,
+ USBHOST_TLL_ICLK);
+ if (IS_ERR(ohci_clocks->usbtll_ick_clk)) {
+ clk_disable(ohci_clocks->usbhost_ick_clk);
+ clk_put(ohci_clocks->usbhost_ick_clk);
+ clk_disable(ohci_clocks->usbhost2_120m_fck_clk);
+ clk_put(ohci_clocks->usbhost2_120m_fck_clk);
+ clk_disable(ohci_clocks->usbhost1_48m_fck_clk);
+ clk_put(ohci_clocks->usbhost1_48m_fck_clk);
+ clk_disable(ohci_clocks->usbtll_fck_clk);
+ clk_put(ohci_clocks->usbtll_fck_clk);
+ return PTR_ERR(ohci_clocks->usbtll_ick_clk);
+ }
+
+ clk_enable(ohci_clocks->usbtll_ick_clk);
+
+ ohci_clocks->suspended = 0;
+
+ /* Disable Auto Idle of USBTLL */
+ cm_write_mod_reg((0 << OMAP3430ES2_AUTO_USBTLL_SHIFT),
+ CORE_MOD, CM_AUTOIDLE3);
+
+ /* Wait for TLL to be Active */
+ while ((cm_read_mod_reg(CORE_MOD, OMAP2430_CM_IDLEST3) &
+ (1 << OMAP3430ES2_ST_USBTLL_SHIFT)));
+
+ /* perform TLL soft reset, and wait until reset is complete */
+ omap_writel(1 << OMAP_USBTLL_SYSCONFIG_SOFTRESET_SHIFT,
+ OMAP_USBTLL_SYSCONFIG);
+ /* Wait for TLL reset to complete */
+ while (!(omap_readl(OMAP_USBTLL_SYSSTATUS) &
+ (1 << OMAP_USBTLL_SYSSTATUS_RESETDONE_SHIFT)));
+
+ /* smart idle mode */
+ omap_writel((1 << OMAP_USBTLL_SYSCONFIG_ENAWAKEUP_SHIFT) |
+ (2 << OMAP_USBTLL_SYSCONFIG_SIDLEMODE_SHIFT) |
+ (0 << OMAP_USBTLL_SYSCONFIG_CACTIVITY_SHIFT) |
+ (1 << OMAP_USBTLL_SYSCONFIG_AUTOIDLE_SHIFT),
+ OMAP_USBTLL_SYSCONFIG);
+
+
+ /* Put UHH in NoIdle/NoStandby mode */
+ omap_writel((1 << OMAP_UHH_SYSCONFIG_AUTOIDLE_SHIFT) |
+ (1 << OMAP_UHH_SYSCONFIG_ENAWAKEUP_SHIFT) |
+ (1 << OMAP_UHH_SYSCONFIG_SIDLEMODE_SHIFT) |
+ (0 << OMAP_UHH_SYSCONFIG_CACTIVITY_SHIFT) |
+ (1 << OMAP_UHH_SYSCONFIG_MIDLEMODE_SHIFT),
+ OMAP_UHH_SYSCONFIG);
+
+#ifdef CONFIG_OMAP_OHCI_PHY_MODE
+ /* TLL in FS-PHY mode operation */
+ uhh_hostconfig_value = (1 << OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN_SHIFT) |
+ (1 << OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN_SHIFT) |
+ (1 << OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN_SHIFT) |
+ (0 << OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN_SHIFT);
+
+ if (omap_rev() >= OMAP3430_REV_ES3_0){
+
+/* For ES 3, we have per-port control for the ULPI Bypass
+ * The ULPI Bypass needs to be set to 0 only if the EHCI PHY Mode
+ * is selected for that port.
+ * Hence it is easier to make it conditional on EHCI_PHY_MODE
+ *
+ * ES 2 does not have per-port control. Hence it is not possible to have
+ * EHCI in PHY Mode and OHCI both working at the same time
+ *
+ * FIXME: This common code should be moved elsewhere
+ *
+ */
+
+#ifndef CONFIG_OMAP_EHCI_PHY_MODE_PORT1
+ uhh_hostconfig_value |=
+ (1 << OMAP_UHH_HOSTCONFIG_P1_ULPI_BYPASS_SHIFT);
+#endif
+
+#ifndef CONFIG_OMAP_EHCI_PHY_MODE_PORT2
+ uhh_hostconfig_value |=
+ (1 << OMAP_UHH_HOSTCONFIG_P2_ULPI_BYPASS_SHIFT);
+#endif
+
+#ifndef CONFIG_OMAP_EHCI_PHY_MODE_PORT3
+ uhh_hostconfig_value |=
+ (1 << OMAP_UHH_HOSTCONFIG_P3_ULPI_BYPASS_SHIFT);
+#endif
+ } else {
+ uhh_hostconfig_value |=
+ (1 << OMAP_UHH_HOSTCONFIG_P1_ULPI_BYPASS_SHIFT);
+ }
+
+ omap_writel(uhh_hostconfig_value, OMAP_UHH_HOSTCONFIG);
+
+#if 0
+ /* Ensure BYPASS bit is not set */
+ while (!(omap_readl(OMAP_UHH_HOSTCONFIG) &
+ (1 << OMAP_UHH_HOSTCONFIG_P3_ULPI_BYPASS_SHIFT)));
+#endif
+
+ pr_debug("Entered UTMI PHY MODE: success");
+
+ /* Program Common TLL register */
+ omap_writel((1 << OMAP_TLL_SHARED_CONF_FCLK_IS_ON_SHIFT) |
+ (1 << OMAP_TLL_SHARED_CONF_USB_DIVRATION_SHIFT) |
+ (0 << OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN_SHIFT) |
+ (0 << OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN_SHFT),
+ OMAP_TLL_SHARED_CONF);
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT1) || \
+ defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT1)
+ ohci_port_enable_mask |= (1 << 0);
+ pr_debug("\n-> 3/4-PIN-PHY-mode of Port1\n");
+#endif
+
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT2) || \
+ defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT2)
+ ohci_port_enable_mask |= (1 << 1);
+#endif
+
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT3) || \
+ defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT3)
+ ohci_port_enable_mask |= (1 << 2);
+#endif
+
+ for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
+
+ /* Enable only required ports */
+ if (!(ohci_port_enable_mask & (1 << i)))
+ continue;
+
+ /* Disable AutoIdle */
+ omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) &
+ ~(1 << OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE_SHIFT),
+ OMAP_TLL_CHANNEL_CONF(i));
+
+ /* Disable BitStuffing */
+ omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) |
+ (1 << OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF_SHIFT),
+ OMAP_TLL_CHANNEL_CONF(i));
+
+ /* SDR Mode */
+ omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) &
+ ~(1 << OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE_SHIFT),
+ OMAP_TLL_CHANNEL_CONF(i));
+
+ /* CHANMODE: UTMI-to-serial FS/LS mode */
+ omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) |
+ (1 << OMAP_TLL_CHANNEL_CONF_CHANMODE_SHIFT),
+ OMAP_TLL_CHANNEL_CONF(i));
+
+#if 0
+ /* Enable port 3 only. Not enabling ports 1 & 2 */
+ if (i != 2)
+ continue;
+#endif
+
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT1) || \
+ defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT2) || \
+ defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT3)
+ pr_debug("\n-> Set:(4-PIN-PHY-mode-Port1)\n");
+ /* FSLSMODE: 4-pin bidirectional PHY */
+ omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) |
+ (3 << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT),
+ OMAP_TLL_CHANNEL_CONF(i));
+#endif
+
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT1) || \
+ defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT2) || \
+ defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT3)
+
+ /* FSLSMODE: 3-pin bidirectional PHY */
+ omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) |
+ (2 << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT),
+ OMAP_TLL_CHANNEL_CONF(i));
+#endif
+
+ omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) |
+ (1<<OMAP_TLL_CHANNEL_CONF_CHANEN_SHIFT),
+ OMAP_TLL_CHANNEL_CONF(i));
+
+ }
+#else
+#error "FS-TLL Not implemented"
+#endif /* CONFIG_OMAP_OHCI_PHY_MODE */
+
+ hcd->rsrc_start = pdev->resource[0].start;
+ hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+ /*
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "request_mem_region failed\n");
+ retval = -EBUSY;
+ goto err1;
+ }
+ */
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_err(&pdev->dev, "can't ioremap OHCI HCD\n");
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+ /*
+ pr_debug("\n\n-->VIRT-OHCI-BASE [0x%x], [0x%x] irq[%d]\n\n",
+ hcd->regs, (unsigned int)io_p2v( 0x48064400 ),
+ pdev->resource[1].start);
+ */
+
+ ohci = hcd_to_ohci(hcd);
+ ohci_hcd_init(ohci);
+
+ ohci_clocks->host_enabled = 1;
+
+ //irq = platform_get_irq(pdev, 0);
+ //if (irq < 0) {
+ // retval = -ENXIO;
+ // goto err3;
+ //}
+ retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED);
+ if (retval)
+ goto err3;
+
+ return 0;
+err3:
+ iounmap(hcd->regs);
+err2:
+// release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+//err1:
+ usb_put_hcd(hcd);
+ clk_disable(ohci_clocks->usbhost_ick_clk);
+ clk_put(ohci_clocks->usbhost_ick_clk);
+ clk_disable(ohci_clocks->usbhost2_120m_fck_clk);
+ clk_put(ohci_clocks->usbhost2_120m_fck_clk);
+ clk_disable(ohci_clocks->usbhost1_48m_fck_clk);
+ clk_put(ohci_clocks->usbhost1_48m_fck_clk);
+ clk_disable(ohci_clocks->usbtll_fck_clk);
+ clk_put(ohci_clocks->usbtll_fck_clk);
+ clk_disable(ohci_clocks->usbtll_ick_clk);
+ clk_put(ohci_clocks->usbtll_ick_clk);
+err0:
+// clk_put(usb_dc_ck);
+// clk_put(usb_host_ck);
+ return retval;
+}
+
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_omap_remove - shutdown processing for OMAP-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_omap_probe(), first invoking
+ * the HCD's stop() method. It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ */
+static inline void
+usb_hcd_omap_remove(struct usb_hcd *hcd, struct platform_device *pdev)
+{
+ struct ohci_omap_clock_defs *ohci_clocks;
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ ohci_clocks = (struct ohci_omap_clock_defs *)
+ (((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+
+ usb_remove_hcd(hcd);
+ if (ohci->transceiver) {
+ (void) otg_set_host(ohci->transceiver, 0);
+ put_device(ohci->transceiver->dev);
+ }
+ iounmap(hcd->regs);
+ //release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ /* Reset OMAP modules for insmod/rmmod to work */
+ omap_writel((1 << 1), OMAP_UHH_SYSCONFIG);
+ while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1 << 0)));
+ while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1 << 1)));
+ while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1 << 2)));
+ pr_debug("UHH RESET DONE OMAP_UHH_SYSSTATUS %x !!\n",
+ omap_readl(OMAP_UHH_SYSSTATUS));
+
+ omap_writel((1<<1), OMAP_USBTLL_SYSCONFIG);
+ while (!(omap_readl(OMAP_USBTLL_SYSSTATUS) & (1<<0)));
+ pr_debug("TLL RESET DONE");
+
+ if (ohci_clocks->usbtll_fck_clk != NULL) {
+ clk_disable(ohci_clocks->usbtll_fck_clk);
+ clk_put(ohci_clocks->usbtll_fck_clk);
+ ohci_clocks->usbtll_fck_clk = NULL;
+ }
+
+ if (ohci_clocks->usbhost_ick_clk != NULL) {
+ clk_disable(ohci_clocks->usbhost_ick_clk);
+ clk_put(ohci_clocks->usbhost_ick_clk);
+ ohci_clocks->usbhost_ick_clk = NULL;
+ }
+
+ if (ohci_clocks->usbhost1_48m_fck_clk != NULL) {
+ clk_disable(ohci_clocks->usbhost1_48m_fck_clk);
+ clk_put(ohci_clocks->usbhost1_48m_fck_clk);
+ ohci_clocks->usbhost1_48m_fck_clk = NULL;
+ }
+
+ if (ohci_clocks->usbhost2_120m_fck_clk != NULL) {
+ clk_disable(ohci_clocks->usbhost2_120m_fck_clk);
+ clk_put(ohci_clocks->usbhost2_120m_fck_clk);
+ ohci_clocks->usbhost2_120m_fck_clk = NULL;
+ }
+
+ if (ohci_clocks->usbtll_ick_clk != NULL) {
+ clk_disable(ohci_clocks->usbtll_ick_clk);
+ clk_put(ohci_clocks->usbtll_ick_clk);
+ ohci_clocks->usbtll_ick_clk = NULL;
+ }
+}
+/*-------------------------------------------------------------------------*/
+
+static int
+ohci_omap_start(struct usb_hcd *hcd)
+{
+ struct omap_usb_config *config;
+ struct ohci_omap_clock_defs *ohci_clocks;
+ int ret;
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ ohci_clocks = (struct ohci_omap_clock_defs *)
+ (((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+
+ if (!ohci_clocks->host_enabled)
+ return 0;
+ config = hcd->self.controller->platform_data;
+#ifdef HACK_OMAP_OHCI /* todo */
+ if (config->otg || config->rwc) {
+ ohci->hc_control = OHCI_CTRL_RWC;
+ writel(OHCI_CTRL_RWC, &ohci->regs->control);
+ }
+#endif
+
+ ohci->hc_control = OHCI_CTRL_RWC;
+ writel(OHCI_CTRL_RWC, &ohci->regs->control);
+ if ((ret = ohci_run(ohci)) < 0) {
+ dev_err(hcd->self.controller, "can't start\n");
+ ohci_stop(hcd);
+ return ret;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+#ifdef CONFIG_OMAP34XX_OFFMODE
+static void ohci_context_save(void)
+{
+ int i;
+
+ if (is_sil_rev_less_than(OMAP3430_REV_ES3_1)) {
+ ohci_context.usbtll_sysconfig =
+ omap_readl(OMAP_USBTLL_SYSCONFIG);
+ ohci_context.usbtll_irqenable =
+ omap_readl(OMAP_USBTLL_IRQENABLE);
+ ohci_context.tll_shared_conf =
+ omap_readl(OMAP_TLL_SHARED_CONF);
+
+ for (i = 0; i < 3; i++) {
+ ohci_context.tll_channel_conf[i] =
+ omap_readl(OMAP_TLL_CHANNEL_CONF(i));
+ ohci_context.ulpi_function_ctrl[i] =
+ omap_readb(OMAP_TLL_ULPI_FUNCTION_CTRL(i));
+ ohci_context.ulpi_interface_ctrl[i] =
+ omap_readb(OMAP_TLL_ULPI_INTERFACE_CTRL(i));
+ ohci_context.ulpi_otg_ctrl[i] =
+ omap_readb(OMAP_TLL_ULPI_OTG_CTRL(i));
+ ohci_context.ulpi_usb_int_en_rise[i] =
+ omap_readb(OMAP_TLL_ULPI_INT_EN_RISE(i));
+ ohci_context.ulpi_usb_int_en_fall[i] =
+ omap_readb(OMAP_TLL_ULPI_INT_EN_FALL(i));
+ ohci_context.ulpi_usb_int_status[i] =
+ omap_readb(OMAP_TLL_ULPI_INT_STATUS(i));
+ }
+ }
+}
+
+static void ohci_context_restore(void)
+{
+ int i;
+
+ if (is_sil_rev_less_than(OMAP3430_REV_ES3_1)) {
+
+#if 0
+ /* FIXME: This was reported as not working. Temporarily
+ * disable this infinite loop pending investigation
+ */
+
+ /* perform TLL soft reset, and wait until reset is complete */
+ omap_writel(1 << OMAP_USBTLL_SYSCONFIG_SOFTRESET_SHIFT,
+ OMAP_USBTLL_SYSCONFIG);
+
+ /* Wait for TLL reset to complete */
+ while (!(omap_readl(OMAP_USBTLL_SYSSTATUS) &
+ (1 << OMAP_USBTLL_SYSSTATUS_RESETDONE_SHIFT)));
+#endif
+
+ omap_writel(ohci_context.usbtll_sysconfig,
+ OMAP_USBTLL_SYSCONFIG);
+ omap_writel(ohci_context.tll_shared_conf,
+ OMAP_TLL_SHARED_CONF);
+
+ for (i = 0; i < 3; i++) {
+
+ omap_writel(ohci_context.tll_channel_conf[i],
+ OMAP_TLL_CHANNEL_CONF(i));
+ omap_writeb(ohci_context.ulpi_interface_ctrl[i],
+ OMAP_TLL_ULPI_INTERFACE_CTRL(i));
+ omap_writeb(ohci_context.ulpi_function_ctrl[i],
+ OMAP_TLL_ULPI_FUNCTION_CTRL(i));
+ omap_writeb(ohci_context.ulpi_otg_ctrl[i],
+ OMAP_TLL_ULPI_OTG_CTRL(i));
+ omap_writeb(ohci_context.ulpi_usb_int_en_rise[i],
+ OMAP_TLL_ULPI_INT_EN_RISE(i));
+ omap_writeb(ohci_context.ulpi_usb_int_en_fall[i],
+ OMAP_TLL_ULPI_INT_EN_FALL(i));
+ omap_writeb(ohci_context.ulpi_usb_int_status[i],
+ OMAP_TLL_ULPI_INT_STATUS(i));
+ }
+ omap_writel(ohci_context.usbtll_irqenable,
+ OMAP_USBTLL_IRQENABLE);
+ }
+}
+#else
+
+static void ohci_context_save(void)
+{
+}
+
+static void ohci_context_restore(void)
+{
+}
+
+#endif /* CONFIG_OMAP34XX_OFFMODE */
+
+static int omap_ohci_bus_suspend(struct usb_hcd *hcd)
+{
+ struct ohci_omap_clock_defs *ohci_clocks;
+ int ret = 0;
+ u32 uhh_sysconfig;
+
+ ohci_clocks = (struct ohci_omap_clock_defs *)
+ (((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+
+ if (!ohci_clocks->suspended) {
+ ret = ohci_bus_suspend(hcd);
+ if (ret)
+ return ret;
+ mdelay(8); /* MSTANDBY assertion delayed by ~8ms */
+
+ /* Need to set ForceStandby,ForceIdle here
+ * else the domain may not be able to transition
+ * back during clk_enable if there was a pending event.
+ */
+
+ uhh_sysconfig = omap_readl(OMAP_UHH_SYSCONFIG);
+ uhh_sysconfig &= ~(3 << OMAP_UHH_SYSCONFIG_MIDLEMODE_SHIFT);
+ uhh_sysconfig &= ~(3 << OMAP_UHH_SYSCONFIG_SIDLEMODE_SHIFT);
+ omap_writel(uhh_sysconfig, OMAP_UHH_SYSCONFIG);
+
+ ohci_context_save();
+ clk_disable(ohci_clocks->usbhost_ick_clk);
+ clk_disable(ohci_clocks->usbhost2_120m_fck_clk);
+ clk_disable(ohci_clocks->usbhost1_48m_fck_clk);
+ clk_disable(ohci_clocks->usbtll_ick_clk);
+ clk_disable(ohci_clocks->usbtll_fck_clk);
+ ohci_clocks->suspended = 1;
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ }
+
+ return ret;
+}
+
+static int omap_ohci_bus_resume(struct usb_hcd *hcd)
+{
+ struct ohci_omap_clock_defs *ohci_clocks;
+ int ret = 0;
+ u32 uhh_sysconfig;
+
+ ohci_clocks = (struct ohci_omap_clock_defs *)
+ (((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+
+ if (ohci_clocks->suspended) {
+ clk_enable(ohci_clocks->usbtll_ick_clk);
+ clk_enable(ohci_clocks->usbtll_fck_clk);
+ ohci_context_restore();
+
+ clk_enable(ohci_clocks->usbhost_ick_clk);
+ clk_enable(ohci_clocks->usbhost2_120m_fck_clk);
+ clk_enable(ohci_clocks->usbhost1_48m_fck_clk);
+ ohci_clocks->suspended = 0;
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ /* Need to set back to NoStandby,Noidle
+ * FIXME: Maybe SmartIdle, SmartStandby will also work
+ */
+
+ uhh_sysconfig = omap_readl(OMAP_UHH_SYSCONFIG);
+ uhh_sysconfig &= ~(3 << OMAP_UHH_SYSCONFIG_MIDLEMODE_SHIFT);
+ uhh_sysconfig &= ~(3 << OMAP_UHH_SYSCONFIG_SIDLEMODE_SHIFT);
+ uhh_sysconfig |= (1 << OMAP_UHH_SYSCONFIG_MIDLEMODE_SHIFT);
+ uhh_sysconfig |= (1 << OMAP_UHH_SYSCONFIG_SIDLEMODE_SHIFT);
+ omap_writel(uhh_sysconfig, OMAP_UHH_SYSCONFIG);
+
+ ret = ohci_bus_resume(hcd);
+ }
+
+ return ret;
+}
+
+static void omap_ohci_shutdown(struct usb_hcd *hcd)
+{
+ struct ohci_omap_clock_defs *ohci_clocks;
+ ohci_clocks = (struct ohci_omap_clock_defs *)
+ (((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+
+ if (ohci_clocks->suspended) {
+ clk_enable(ohci_clocks->usbhost_ick_clk);
+ clk_enable(ohci_clocks->usbtll_ick_clk);
+ clk_enable(ohci_clocks->usbtll_fck_clk);
+ clk_enable(ohci_clocks->usbhost1_48m_fck_clk);
+ clk_enable(ohci_clocks->usbhost2_120m_fck_clk);
+ ohci_clocks->suspended = 0;
+ }
+ ohci_shutdown(hcd);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_omap_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "OMAP OHCI",
+ .hcd_priv_size = sizeof(struct ohci_hcd)
+ + sizeof(struct ohci_omap_clock_defs),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ohci_omap_init,
+ .start = ohci_omap_start,
+ .stop = ohci_omap_stop,
+ .shutdown = omap_ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = omap_ohci_bus_suspend,
+ .bus_resume = omap_ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_omap_drv_probe(struct platform_device *dev)
+{
+ return usb_hcd_omap_probe(&ohci_omap_hc_driver, dev);
+}
+
+static int ohci_hcd_omap_drv_remove(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ohci_omap_clock_defs *ohci_clocks;
+ ohci_clocks = (struct ohci_omap_clock_defs *)
+ (((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+ if (ohci_clocks->suspended) {
+ clk_enable(ohci_clocks->usbhost_ick_clk);
+ clk_enable(ohci_clocks->usbtll_ick_clk);
+ clk_enable(ohci_clocks->usbtll_fck_clk);
+ clk_enable(ohci_clocks->usbhost1_48m_fck_clk);
+ clk_enable(ohci_clocks->usbhost2_120m_fck_clk);
+ ohci_clocks->suspended = 0;
+ }
+ usb_hcd_omap_remove(hcd, dev);
+// platform_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if 0
+
+static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(dev));
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+ omap_ohci_bus_suspend(ohci_to_hcd(ohci));
+ ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
+ dev->dev.power.power_state = PMSG_SUSPEND;
+ return 0;
+}
+
+static int ohci_omap_resume(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ dev->dev.power.power_state = PMSG_ON;
+ ohci_finish_controller_resume(hcd);
+ return 0;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Driver definition to register with the OMAP bus
+ */
+static struct platform_driver ohci_hcd_omap_driver = {
+ .probe = ohci_hcd_omap_drv_probe,
+ .remove = ohci_hcd_omap_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+#if 0
+ .suspend = ohci_omap_suspend,
+ .resume = ohci_omap_resume,
+#endif
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ohci-omap",
+ },
+};
+
+MODULE_ALIAS("platform:ohci");
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 5424b7a..1237c32 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1304,8 +1304,7 @@
#endif
u8 reg;
char *type;
- u16 hwvers, rev_major, rev_minor;
- char aInfo[78], aRevision[32], aDate[12];
+ char aInfo[100], aRevision[32], aDate[12];
void __iomem *mbase = musb->mregs;
int status = 0;
int i;
@@ -1377,11 +1376,10 @@
}
/* log release info */
- hwvers = musb_read_hwvers(mbase);
- rev_major = (hwvers >> 10) & 0x1f;
- rev_minor = hwvers & 0x3ff;
- snprintf(aRevision, 32, "%d.%d%s", rev_major,
- rev_minor, (hwvers & 0x8000) ? "RC" : "");
+ musb->hwvers = musb_read_hwvers(mbase);
+ snprintf(aRevision, 32, "%d.%d%s", MUSB_HWVERS_MAJOR(musb->hwvers),
+ MUSB_HWVERS_MINOR(musb->hwvers),
+ (musb->hwvers & MUSB_HWVERS_RC) ? "RC" : "");
printk(KERN_DEBUG "%s: %sHDRC RTL version %s %s\n",
musb_driver_name, type, aRevision, aDate);
@@ -2142,17 +2140,14 @@
#ifdef CONFIG_PM
-static int musb_suspend(struct platform_device *pdev, pm_message_t message)
+static int musb_suspend_late(struct platform_device *pdev, pm_message_t message)
{
- unsigned long flags;
struct musb *musb = dev_to_musb(&pdev->dev);
if (!musb->clock)
return 0;
- spin_lock_irqsave(&musb->lock, flags);
-
- musb_save_context(musb);
+ musb_platform_save_context(musb);
if (is_peripheral_active(musb)) {
/* FIXME force disconnect unless we know USB will wake
@@ -2168,32 +2163,28 @@
musb->set_clock(musb->clock, 0);
else
clk_disable(musb->clock);
- spin_unlock_irqrestore(&musb->lock, flags);
+
return 0;
}
-static int musb_resume(struct platform_device *pdev)
+static int musb_resume_early(struct platform_device *pdev)
{
- unsigned long flags;
struct musb *musb = dev_to_musb(&pdev->dev);
if (!musb->clock)
return 0;
- spin_lock_irqsave(&musb->lock, flags);
-
if (musb->set_clock)
musb->set_clock(musb->clock, 1);
else
clk_enable(musb->clock);
- musb_restore_context(musb);
+ musb_platform_restore_context(musb);
/* for static cmos like DaVinci, register values were preserved
* unless for some reason the whole soc powered down and we're
* not treating that as a whole-system restart (e.g. swsusp)
*/
- spin_unlock_irqrestore(&musb->lock, flags);
return 0;
}
@@ -2210,8 +2201,8 @@
},
.remove = __devexit_p(musb_remove),
.shutdown = musb_shutdown,
- .suspend = musb_suspend,
- .resume = musb_resume,
+ .suspend_late = musb_suspend_late,
+ .resume_early = musb_resume_early,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index e1d0adc..ef0b9bd 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -309,6 +309,14 @@
struct clk *clock;
irqreturn_t (*isr)(int, void *);
struct work_struct irq_work;
+#define MUSB_HWVERS_MAJOR(x) ((x >> 10) & 0x1f)
+#define MUSB_HWVERS_MINOR(x) (x & 0x3ff)
+#define MUSB_HWVERS_RC 0x8000
+#define MUSB_HWVERS_1300 0x52C
+#define MUSB_HWVERS_1400 0x590
+#define MUSB_HWVERS_1800 0x720
+#define MUSB_HWVERS_2000 0x800
+ u16 hwvers;
/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
#define MUSB_PORT_STAT_RESUME (1 << 31)
@@ -527,8 +535,8 @@
extern irqreturn_t musb_interrupt(struct musb *);
-extern void musb_save_context(struct musb *musb);
-extern void musb_restore_context(struct musb *musb);
+extern void musb_platform_save_context(struct musb *musb);
+extern void musb_platform_restore_context(struct musb *musb);
extern void musb_platform_enable(struct musb *musb);
extern void musb_platform_disable(struct musb *musb);
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 62e5a3e..e11eee4 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -678,8 +678,16 @@
transfer_size);
}
- if (use_dma)
+ if (use_dma) {
return;
+ } else {
+ /* Need to clear DMAENAB for the
+ * backup PIO mode transfer to work
+ */
+ csr &= ~MUSB_RXCSR_DMAENAB;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
+
}
#endif /* Mentor's DMA */
@@ -1516,6 +1524,7 @@
spin_lock_irqsave(&musb->lock, flags);
if (is_on) {
if (!musb->softconnect) {
+ musb_start(musb);
musb->softconnect = 1;
musb_pullup(musb, is_on);
}
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 8662e9e..5c07afb 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -151,6 +151,11 @@
? (1 << MUSB_HSDMA_TRANSMIT_SHIFT)
: 0);
+ if (musb_channel->transmit)
+ controller->tx_active |= (1 << bchannel);
+ else
+ controller->rx_active |= (1 << bchannel);
+
/* address/count */
musb_write_hsdma_addr(mbase, bchannel, dma_addr);
musb_write_hsdma_count(mbase, bchannel, len);
@@ -166,6 +171,8 @@
dma_addr_t dma_addr, u32 len)
{
struct musb_dma_channel *musb_channel = channel->private_data;
+ struct musb_dma_controller *controller = musb_channel->controller;
+ struct musb *musb = controller->private_data;
DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
musb_channel->epnum,
@@ -175,6 +182,26 @@
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
channel->status == MUSB_DMA_STATUS_BUSY);
+ /*
+ * make sure the DMA address is 4 byte aligned, if not
+ * we use the PIO mode for OMAP 3630 and beyond
+ */
+ if ((dma_addr % 4) && (musb->hwvers >= MUSB_HWVERS_1800))
+ return false;
+
+ /* In version 1.4, if two DMA channels are simultaneously
+ * enabled in opposite directions, there is a chance that
+ * the DMA controller will hang. However, it is safe to
+ * have multiple DMA channels enabled in the same direction
+ * at the same time.
+ */
+ if (musb->hwvers == MUSB_HWVERS_1400) {
+ if (musb_channel->transmit && controller->rx_active)
+ return false;
+ else if (!musb_channel->transmit && controller->tx_active)
+ return false;
+ }
+
channel->actual_len = 0;
musb_channel->start_addr = dma_addr;
musb_channel->len = len;
@@ -227,6 +254,11 @@
musb_write_hsdma_addr(mbase, bchannel, 0);
musb_write_hsdma_count(mbase, bchannel, 0);
channel->status = MUSB_DMA_STATUS_FREE;
+
+ if (musb_channel->transmit)
+ musb_channel->controller->tx_active &= ~(1 << bchannel);
+ else
+ musb_channel->controller->rx_active &= ~(1 << bchannel);
}
return 0;
@@ -249,13 +281,32 @@
u8 int_hsdma;
u32 addr;
- u16 csr;
+ u16 csr, count;
spin_lock_irqsave(&musb->lock, flags);
int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR);
- if (!int_hsdma)
- goto done;
+ if (!int_hsdma) {
+ DBG(2, "spurious DMA irq\n");
+
+ for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
+ musb_channel = (struct musb_dma_channel *)
+ &(controller->channel[bchannel]);
+ channel = &musb_channel->channel;
+ if (channel->status == MUSB_DMA_STATUS_BUSY) {
+ count = musb_readw(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel,
+ MUSB_HSDMA_COUNT));
+ if (count == 0)
+ int_hsdma |= (1 << bchannel);
+ }
+ }
+
+ DBG(2, "int_hsdma = 0x%x\n", int_hsdma);
+
+ if (!int_hsdma)
+ goto done;
+ }
for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
if (int_hsdma & (1 << bchannel)) {
@@ -290,6 +341,13 @@
channel->status = MUSB_DMA_STATUS_FREE;
+ if (musb_channel->transmit)
+ controller->tx_active &=
+ ~(1 << bchannel);
+ else
+ controller->rx_active &=
+ ~(1 << bchannel);
+
/* completed */
if ((devctl & MUSB_DEVCTL_HM)
&& (musb_channel->transmit)
diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h
index 1299d92..df87863 100644
--- a/drivers/usb/musb/musbhsdma.h
+++ b/drivers/usb/musb/musbhsdma.h
@@ -146,4 +146,6 @@
u8 channel_count;
u8 used_channels;
u8 irq;
+ u8 tx_active;
+ u8 rx_active;
};
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index c186043..ec8a448 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -37,10 +37,14 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/mux.h>
+#include <mach/omap-pm.h>
#include "musb_core.h"
#include "omap2430.h"
+#define VDD1_OPP3_FREQ 500000000
+#define VDD1_OPP1_FREQ 125000000
+
#ifdef CONFIG_ARCH_OMAP3430
#define get_cpu_rev() 2
#endif
@@ -49,6 +53,10 @@
static struct timer_list musb_idle_timer;
+void musb_link_save_context(struct otg_transceiver *xceiv);
+void musb_link_restore_context(struct otg_transceiver *xceiv);
+void musb_link_force_active(int on);
+
static void musb_do_idle(unsigned long _musb)
{
struct musb *musb = (void *)_musb;
@@ -152,6 +160,17 @@
{
}
+/* Set the MUSB vdd1 opp constraint */
+static void musb_set_opp_constraint(struct musb *musb)
+{
+ struct musb_hdrc_platform_data *pdata =
+ musb->controller->platform_data;
+
+ /* Initialize vdd1 to opp3 constraint */
+ if (pdata->set_vdd1_opp)
+ pdata->set_vdd1_opp(musb->controller, VDD1_OPP3_FREQ);
+}
+
static void omap_set_vbus(struct musb *musb, int is_on)
{
u8 devctl;
@@ -247,13 +266,17 @@
musb->xceiv = *x;
musb_platform_resume(musb);
+ /*
+ * Do Forcestdby here, for the case when kernel boots up
+ * without cable attached, force_active(0) won't be called.
+ */
l = omap_readl(OTG_SYSCONFIG);
- l &= ~ENABLEWAKEUP; /* disable wakeup */
+ l |= ENABLEWAKEUP; /* Enable wakeup */
l &= ~NOSTDBY; /* remove possible nostdby */
- l |= SMARTSTDBY; /* enable smart standby */
+ l |= FORCESTDBY; /* enable smart standby */
l &= ~AUTOIDLE; /* disable auto idle */
l &= ~NOIDLE; /* remove possible noidle */
- l |= SMARTIDLE; /* enable smart idle */
+ l |= FORCEIDLE; /* enable smart idle */
/*
* MUSB AUTOIDLE don't work in 3430.
* Workaround by Richard Woodruff/TI
@@ -280,6 +303,13 @@
musb->xceiv.set_power = omap_set_power;
musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
+ x->link_save_context = musb_link_save_context;
+ x->link_restore_context = musb_link_restore_context;
+ x->link_force_active = musb_link_force_active;
+ x->link = musb;
+
+ otg_put_transceiver(x);
+
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
return 0;
@@ -297,6 +327,7 @@
static struct musb_context_registers {
+ u32 off_counter;
u32 otg_sysconfig, otg_forcestandby;
u8 faddr, power;
@@ -311,12 +342,16 @@
} musb_context;
-void musb_save_context(struct musb *musb)
+void musb_platform_save_context(struct musb *musb)
{
int i;
+ struct musb_hdrc_platform_data *plat = musb->controller->platform_data;
DBG(4, "Saving musb_registers\n");
+ musb_context.off_counter =
+ plat->context_loss_counter(musb->controller);
+
musb_context.otg_sysconfig = omap_readl(OTG_SYSCONFIG);
musb_context.otg_forcestandby = omap_readl(OTG_FORCESTDBY);
@@ -370,7 +405,7 @@
}
-void musb_restore_context(struct musb *musb)
+void musb_platform_restore_context(struct musb *musb)
{
int i;
@@ -439,10 +474,107 @@
}
+void musb_link_save_context(struct otg_transceiver *xceiv)
+{
+ struct musb *musb = xceiv->link;
+
+ struct musb_hdrc_platform_data *pdata =
+ musb->controller->platform_data;
+
+ musb_platform_save_context(musb);
+
+ /* On cable detach remove restriction on CORE domain:
+ * Now core domain can go to off
+ */
+ omap_pm_set_max_mpu_wakeup_lat(musb->controller, -1);
+
+ /* Initialize vdd1 to opp1 constraint */
+ if (pdata->set_vdd1_opp)
+ pdata->set_vdd1_opp(musb->controller, VDD1_OPP1_FREQ);
+}
+
+void musb_link_restore_context(struct otg_transceiver *xceiv)
+{
+ struct musb *musb = xceiv->link;
+ struct musb_hdrc_platform_data *plat =
+ musb->controller->platform_data;
+
+ /* MUSB has no h/w SAR: So restrict CORE domain
+ * from going to OFF mode
+ * So prevent CPUIdle going to C7, restrict to C6
+ */
+ omap_pm_set_max_mpu_wakeup_lat(musb->controller, 6250);
+ musb_set_opp_constraint(musb);
+
+ /* No context restore needed in case
+ * OFF transition has not happened
+ */
+ if (musb_context.off_counter ==
+ plat->context_loss_counter(musb->controller)) {
+ DBG(4,"No context was lost. Not restoring.\n");
+ return;
+ }
+
+ musb_platform_restore_context(musb);
+}
+
+void musb_link_force_active(int enable)
+{
+ u32 l;
+
+ l = omap_readl(OTG_SYSCONFIG);
+
+ /*
+ * We have encountered enumeration problems on the omap3
+ * when power management has been enabled and the device
+ * is transitioning in and out of CORE retention. To
+ * workaround this problem, we force the musb controller
+ * to be always active (no idle/standby) when the usb
+ * cable is attached and inactive (smart idle/standby)
+ * when the cable is removed.
+ */
+ if (enable) {
+ l &= ~SMARTSTDBY; /* disable smart standby */
+ l |= NOSTDBY; /* enable nostdby */
+ l &= ~SMARTIDLE; /* disable smart idle */
+ l |= NOIDLE; /* enable noidle */
+
+ /* Disable Mstandby */
+ omap_writel((omap_readl(OTG_FORCESTDBY) & ~ENABLEFORCE),
+ OTG_FORCESTDBY);
+ } else {
+ /*
+ * When the device is disconnected put the OTG to
+ * Forceidle and Forcestdby. There where known issues
+ * on different custom boards, wherein
+ * the OTG idle ack was broken. May be the OTG senses
+ * some fake activity on the lines.
+ * Also, this might be moved to suspend/resume hooks.
+ * Right now, musb doesn't have suspend/resume hooks
+ * plugged in to LDM.
+ */
+ l |= ENABLEWAKEUP; /* Enable wakeup */
+ l &= ~SMARTSTDBY; /* enable smart standby */
+ l |= FORCESTDBY;
+ l &= ~NOSTDBY; /* disable nostdby */
+ l |= FORCEIDLE;
+ l &= ~NOIDLE; /* disable noidle */
+
+ /* Enable Mstdby */
+ omap_writel((omap_readl(OTG_FORCESTDBY) | ENABLEFORCE),
+ OTG_FORCESTDBY);
+ }
+
+ omap_writel(l, OTG_SYSCONFIG);
+}
+
#else
-#define musb_save_context do {} while (0)
-#define musb_restore_context do {} while (0)
+#define musb_platform_save_context do {} while (0)
+#define musb_platform_restore_context do {} while (0)
+#define musb_link_save_context do {} while (0)
+#define musb_link_restore_context do {} while (0)
+#define musb_link_force_active do {} while (0)
#endif
@@ -502,6 +634,7 @@
int musb_platform_exit(struct musb *musb)
{
+ struct otg_transceiver *x = otg_get_transceiver();
omap_vbus_power(musb, 0 /*off*/, 1);
@@ -510,5 +643,11 @@
clk_put(musb->clock);
musb->clock = 0;
+ x->link_save_context = NULL;
+ x->link_restore_context = NULL;
+ x->link = NULL;
+
+ otg_put_transceiver(x);
+
return 0;
}
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index ee55b44..ce46e94 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -43,7 +43,7 @@
config TWL4030_USB
tristate "TWL4030 USB Transceiver Driver"
- depends on TWL4030_CORE
+ depends on TWL4030_CORE && REGULATOR_TWL4030
select USB_OTG_UTILS
help
Enable this to support the USB OTG transceiver on TWL4030
@@ -51,4 +51,17 @@
This transceiver supports high and full speed devices plus,
in host mode, low speed.
+config ISP1301_HOST
+ bool "Philips ISP1301 in Host mode with OMAP3 OHCI"
+ depends on ARCH_OMAP_OTG && (MACH_OMAP_3430SDP || MACH_OMAP_3630SDP)
+ default y
+ help
+ If you say yes here you get support for the Philips ISP1301
+ USB-On-The-Go transceiver working with the OMAP3 OHCI controller.
+ The ISP1301 is used in products including the 3430SDP development
+ boards for Texas Instruments OMAP3 processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called isp1301_host.
+
endif # USB || OTG
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
index d73c7cf..89c25ad 100644
--- a/drivers/usb/otg/Makefile
+++ b/drivers/usb/otg/Makefile
@@ -9,6 +9,7 @@
obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
+obj-$(CONFIG_ISP1301_HOST) += isp1301_host.o
ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG
ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG
diff --git a/drivers/usb/otg/isp1301_host.c b/drivers/usb/otg/isp1301_host.c
new file mode 100644
index 0000000..578633e
--- /dev/null
+++ b/drivers/usb/otg/isp1301_host.c
@@ -0,0 +1,247 @@
+/*
+ * isp1301_host - ISP 1301 USB transceiver, talking to OMAP OHCI controller
+ *
+ * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004 David Brownell
+ * Copyright (C) 2008 Anand Gadiyar
+ *
+ * Based on isp1301_omap.c
+ *
+ * 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.
+ */
+
+/* The ISP1301 is used with the OHCI controller in the OMAP3430 SDP.
+ * The other isp1301 driver does otg_set_transceiver if CONFIG_OTG is
+ * defined. For the OMAP3, the MUSB controller is the OTG controller
+ * (and therefore CONFIG_OTG would likely be defined) but it very likely
+ * would be used with a different transceiver (TWL4030, ISP1504, ...)
+ *
+ * This driver is a stub driver meant to put the ISP1301 in host mode.
+ * It is based on the original isp1301 driver.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+
+#define DRIVER_VERSION "10 February 2009"
+#define DRIVER_NAME (isp1301_driver.driver.name)
+
+MODULE_DESCRIPTION("ISP1301 USB HOST Transceiver Driver");
+MODULE_LICENSE("GPL");
+
+struct isp1301 {
+ struct i2c_client *client;
+ void (*i2c_release)(struct device *dev);
+
+ int irq_type;
+
+ unsigned working:1;
+
+};
+
+
+
+/*-------------------------------------------------------------------------*/
+
+static struct i2c_driver isp1301_driver;
+
+/* smbus apis are used for portability */
+
+static inline u8 isp1301_get_u8(struct isp1301 *isp, u8 reg)
+{
+ return i2c_smbus_read_byte_data(isp->client, reg + 0);
+}
+
+static inline int isp1301_get_u16(struct isp1301 *isp, u8 reg)
+{
+ return i2c_smbus_read_word_data(isp->client, reg);
+}
+
+static inline int isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
+{
+ return i2c_smbus_write_byte_data(isp->client, reg + 0, bits);
+}
+
+static inline int isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
+{
+ return i2c_smbus_write_byte_data(isp->client, reg + 1, bits);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* identification */
+#define ISP1301_VENDOR_ID 0x00 /* u16 read */
+#define ISP1301_PRODUCT_ID 0x02 /* u16 read */
+#define ISP1301_BCD_DEVICE 0x14 /* u16 read */
+
+#define I2C_VENDOR_ID_PHILIPS 0x04cc
+#define I2C_PRODUCT_ID_PHILIPS_1301 0x1301
+
+/* operational registers */
+#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */
+# define MC1_SPEED (1 << 0)
+# define MC1_SUSPEND (1 << 1)
+# define MC1_DAT_SE0 (1 << 2)
+# define MC1_TRANSPARENT (1 << 3)
+# define MC1_BDIS_ACON_EN (1 << 4)
+# define MC1_OE_INT_EN (1 << 5)
+# define MC1_UART_EN (1 << 6)
+# define MC1_MASK 0x7f
+#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */
+# define MC2_GLOBAL_PWR_DN (1 << 0)
+# define MC2_SPD_SUSP_CTRL (1 << 1)
+# define MC2_BI_DI (1 << 2)
+# define MC2_TRANSP_BDIR0 (1 << 3)
+# define MC2_TRANSP_BDIR1 (1 << 4)
+# define MC2_AUDIO_EN (1 << 5)
+# define MC2_PSW_EN (1 << 6)
+# define MC2_EN2V7 (1 << 7)
+#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */
+# define OTG1_DP_PULLUP (1 << 0)
+# define OTG1_DM_PULLUP (1 << 1)
+# define OTG1_DP_PULLDOWN (1 << 2)
+# define OTG1_DM_PULLDOWN (1 << 3)
+# define OTG1_ID_PULLDOWN (1 << 4)
+# define OTG1_VBUS_DRV (1 << 5)
+# define OTG1_VBUS_DISCHRG (1 << 6)
+# define OTG1_VBUS_CHRG (1 << 7)
+
+#define ISP1301_INTERRUPT_SOURCE 0x08 /* u8 read */
+#define ISP1301_INTERRUPT_LATCH 0x0A /* u8 read, set, +1 clear */
+
+#define ISP1301_INTERRUPT_FALLING 0x0C /* u8 read, set, +1 clear */
+#define ISP1301_INTERRUPT_RISING 0x0E /* u8 read, set, +1 clear */
+
+/*-------------------------------------------------------------------------*/
+
+static void isp1301_release(struct device *dev)
+{
+ struct isp1301 *isp;
+
+ isp = dev_get_drvdata(dev);
+
+ /* ugly -- i2c hijacks our memory hook to wait_for_completion() */
+ if (isp->i2c_release)
+ isp->i2c_release(dev);
+ kfree(isp);
+}
+
+static int __exit isp1301_remove(struct i2c_client *i2c)
+{
+ struct isp1301 *isp;
+
+ isp = i2c_get_clientdata(i2c);
+
+ isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
+ isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
+
+ put_device(&i2c->dev);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __init
+isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+ int status;
+ struct isp1301 *isp;
+
+
+ isp = kzalloc(sizeof *isp, GFP_KERNEL);
+ if (!isp)
+ return 0;
+
+ i2c_set_clientdata(i2c, isp);
+ isp->client = i2c;
+
+ /* verify the chip (shouldn't be necesary) */
+ status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
+ if (status != I2C_VENDOR_ID_PHILIPS) {
+ dev_dbg(&i2c->dev, "not philips id: %d\n", status);
+ goto fail;
+ }
+ status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
+ if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
+ dev_dbg(&i2c->dev, "not isp1301, %d\n", status);
+ goto fail;
+ }
+ isp->i2c_release = i2c->dev.release;
+ i2c->dev.release = isp1301_release;
+
+ /* initial development used chiprev 2.00 */
+ status = i2c_smbus_read_word_data(i2c, ISP1301_BCD_DEVICE);
+ dev_info(&i2c->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n",
+ status >> 8, status & 0xff);
+
+ /* make like power-on reset */
+ isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_MASK);
+
+ isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_BI_DI);
+ isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, ~MC2_BI_DI);
+
+ isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1,
+ OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN);
+ isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1,
+ ~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
+
+ isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, ~0);
+ isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
+ isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
+
+ /* ISP1301 is put in host mode by default for OHCI host */
+
+ isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND);
+ isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
+ isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV);
+ return 0;
+fail:
+ kfree(isp);
+ return -ENODEV;
+}
+
+static const struct i2c_device_id isp1301_id[] = {
+ { "isp1301_host", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, isp1301_id);
+
+static struct i2c_driver isp1301_driver = {
+ .driver = {
+ .name = "isp1301_host",
+ },
+ .probe = isp1301_probe,
+ .remove = __exit_p(isp1301_remove),
+ .id_table = isp1301_id,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init isp_init(void)
+{
+ return i2c_add_driver(&isp1301_driver);
+}
+module_init(isp_init);
+
+static void __exit isp_exit(void)
+{
+ i2c_del_driver(&isp1301_driver);
+}
+module_exit(isp_exit);
+
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index 416e441..734497d 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -34,6 +34,8 @@
#include <linux/delay.h>
#include <linux/usb/otg.h>
#include <linux/i2c/twl4030.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
/* Register defines */
@@ -110,6 +112,9 @@
#define CARKIT_PLS_CTRL_RXPLSEN (1 << 1)
#define CARKIT_PLS_CTRL_TXPLSEN (1 << 0)
+#define CARKIT_ANA_CTRL 0xBB
+#define SEL_MADC_MCPC (1 << 3)
+
#define MCPC_CTRL 0x30
#define MCPC_CTRL_SET 0x31
#define MCPC_CTRL_CLR 0x32
@@ -215,6 +220,7 @@
/* In module TWL4030_MODULE_PM_MASTER */
#define PROTECT_KEY 0x0E
+#define STS_HW_CONDITIONS 0x0F
/* In module TWL4030_MODULE_PM_RECEIVER */
#define VUSB_DEDICATED1 0x7D
@@ -246,6 +252,11 @@
struct otg_transceiver otg;
struct device *dev;
+ /* TWL4030 internal USB regulator supplies */
+ struct regulator *usb1v5;
+ struct regulator *usb1v8;
+ struct regulator *usb3v1;
+
/* for vbus reporting with irqs disabled */
spinlock_t lock;
@@ -344,15 +355,26 @@
int status;
int linkstat = USB_LINK_UNKNOWN;
- /* STS_HW_CONDITIONS */
- status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER, 0x0f);
+ /*
+ * For ID/VBUS sensing, see manual section 15.4.8 ...
+ * except when using only battery backup power, two
+ * comparators produce VBUS_PRES and ID_PRES signals,
+ * which don't match docs elsewhere. But ... BIT(7)
+ * and BIT(2) of STS_HW_CONDITIONS, respectively, do
+ * seem to match up. If either is true the USB_PRES
+ * signal is active, the OTG module is activated, and
+ * its interrupt may be raised (may wake the system).
+ */
+ status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER,
+ STS_HW_CONDITIONS);
if (status < 0)
dev_err(twl->dev, "USB link status err %d\n", status);
- else if (status & BIT(7))
- linkstat = USB_LINK_VBUS;
- else if (status & BIT(2))
- linkstat = USB_LINK_ID;
- else
+ else if (status & (BIT(7) | BIT(2))) {
+ if (status & BIT(2))
+ linkstat = USB_LINK_ID;
+ else
+ linkstat = USB_LINK_VBUS;
+ } else
linkstat = USB_LINK_NONE;
dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
@@ -434,6 +456,18 @@
pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
if (on) {
+ regulator_enable(twl->usb3v1);
+ regulator_enable(twl->usb1v8);
+ /*
+ * Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP
+ * in twl4030) resets the VUSB_DEDICATED2 register. This reset
+ * enables VUSB3V1_SLEEP bit that remaps usb3v1 ACTIVE state to
+ * SLEEP. We work around this by clearing the bit after usv3v1
+ * is re-activated. This ensures that VUSB3V1 is really active.
+ */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0,
+ VUSB_DEDICATED2);
+ regulator_enable(twl->usb1v5);
pwr &= ~PHY_PWR_PHYPWD;
WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
twl4030_usb_write(twl, PHY_CLK_CTRL,
@@ -443,6 +477,9 @@
} else {
pwr |= PHY_PWR_PHYPWD;
WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
+ regulator_disable(twl->usb1v5);
+ regulator_disable(twl->usb1v8);
+ regulator_disable(twl->usb3v1);
}
}
@@ -451,6 +488,9 @@
if (twl->asleep)
return;
+ if (twl->otg.link_save_context)
+ twl->otg.link_save_context(&twl->otg);
+
twl4030_phy_power(twl, 0);
twl->asleep = 1;
}
@@ -466,9 +506,13 @@
if (twl->usb_mode == T2_USB_MODE_ULPI)
twl4030_i2c_access(twl, 0);
twl->asleep = 0;
+
+ if (twl->otg.link_restore_context)
+ twl->otg.link_restore_context(&twl->otg);
+
}
-static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
+static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
{
/* Enable writing to power configuration registers */
twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY);
@@ -480,20 +524,45 @@
/* input to VUSB3V1 LDO is from VBAT, not VBUS */
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
- /* turn on 3.1V regulator */
- twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB3V1_DEV_GRP);
+ /* Initialize 3.1V regulator */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP);
+
+ twl->usb3v1 = regulator_get(twl->dev, "usb3v1");
+ if (IS_ERR(twl->usb3v1))
+ return -ENODEV;
+
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE);
- /* turn on 1.5V regulator */
- twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V5_DEV_GRP);
+ /* Initialize 1.5V regulator */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP);
+
+ twl->usb1v5 = regulator_get(twl->dev, "usb1v5");
+ if (IS_ERR(twl->usb1v5))
+ goto fail1;
+
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
- /* turn on 1.8V regulator */
- twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V8_DEV_GRP);
+ /* Initialize 1.8V regulator */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP);
+
+ twl->usb1v8 = regulator_get(twl->dev, "usb1v8");
+ if (IS_ERR(twl->usb1v8))
+ goto fail2;
+
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
/* disable access to power configuration registers */
twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY);
+
+ return 0;
+
+fail2:
+ regulator_put(twl->usb1v5);
+ twl->usb1v5 = NULL;
+fail1:
+ regulator_put(twl->usb3v1);
+ twl->usb3v1 = NULL;
+ return -ENODEV;
}
static ssize_t twl4030_usb_vbus_show(struct device *dev,
@@ -515,6 +584,7 @@
static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
{
struct twl4030_usb *twl = _twl;
+ struct otg_transceiver x = twl->otg;
int status;
#ifdef CONFIG_LOCKDEP
@@ -539,12 +609,18 @@
* USB_LINK_VBUS state. musb_hdrc won't care until it
* starts to handle softconnect right.
*/
- twl4030charger_usb_en(status == USB_LINK_VBUS);
- if (status == USB_LINK_NONE)
+ if (status == USB_LINK_NONE) {
+ if (x.link_force_active)
+ x.link_force_active(0);
twl4030_phy_suspend(twl, 0);
- else
+ } else {
+ if (x.link_force_active)
+ x.link_force_active(1);
twl4030_phy_resume(twl);
+ }
+
+ twl4030charger_usb_en(status == USB_LINK_VBUS);
}
sysfs_notify(&twl->dev->kobj, NULL, "vbus");
@@ -598,7 +674,7 @@
{
struct twl4030_usb_data *pdata = pdev->dev.platform_data;
struct twl4030_usb *twl;
- int status;
+ int status, err;
if (!pdata) {
dev_dbg(&pdev->dev, "platform_data not available\n");
@@ -622,13 +698,32 @@
/* init spinlock for workqueue */
spin_lock_init(&twl->lock);
- twl4030_usb_ldo_init(twl);
+ err = twl4030_usb_ldo_init(twl);
+ if (err) {
+ dev_err(&pdev->dev, "ldo init failed\n");
+ kfree(twl);
+ return err;
+ }
otg_set_transceiver(&twl->otg);
platform_set_drvdata(pdev, twl);
if (device_create_file(&pdev->dev, &dev_attr_vbus))
dev_warn(&pdev->dev, "could not create sysfs file\n");
+ /*
+ * One time configuration to route MCPC pins to the MADC for
+ * monitoring */
+ regulator_enable(twl->usb3v1);
+ regulator_enable(twl->usb1v8);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0,
+ VUSB_DEDICATED2);
+ regulator_enable(twl->usb1v5);
+ twl4030_usb_write(twl, CARKIT_ANA_CTRL,
+ twl4030_usb_read(twl, CARKIT_ANA_CTRL) | SEL_MADC_MCPC);
+ regulator_disable(twl->usb1v5);
+ regulator_disable(twl->usb1v8);
+ regulator_disable(twl->usb3v1);
+
/* Our job is to use irqs and status from the power module
* to keep the transceiver disabled when nothing's connected.
*
@@ -688,6 +783,9 @@
twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
twl4030_phy_power(twl, 0);
+ regulator_put(twl->usb1v5);
+ regulator_put(twl->usb1v8);
+ regulator_put(twl->usb3v1);
kfree(twl);
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 814909f..e6bf9b2 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -122,12 +122,6 @@
dbg("%s - port %d", __func__, port->number);
- /* force low_latency on so that our tty_push actually forces the data
- through, otherwise it is scheduled, and with high data rates (like
- with OHCI) data can get lost. */
- if (tty)
- tty->low_latency = 1;
-
/* clear the throttle flags */
spin_lock_irqsave(&port->lock, flags);
port->throttled = 0;
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
index 1258741..c0bd726 100644
--- a/drivers/video/omap/Kconfig
+++ b/drivers/video/omap/Kconfig
@@ -14,7 +14,7 @@
config FB_OMAP_LCD_WVGA
bool "Use LCD in VGA mode"
- depends on ARCH_OMAP34XX && MACH_OMAP_ZOOM2
+ depends on ARCH_OMAP34XX && (MACH_OMAP_ZOOM2 || MACH_OMAP_ZOOM3)
choice
depends on FB_OMAP && MACH_OVERO
diff --git a/drivers/video/omap2/displays/panel-zoom2.c b/drivers/video/omap2/displays/panel-zoom2.c
index 3e17375..67cddf6 100644
--- a/drivers/video/omap2/displays/panel-zoom2.c
+++ b/drivers/video/omap2/displays/panel-zoom2.c
@@ -31,6 +31,9 @@
#include <mach/display.h>
+/* Delay between Panel configuration and Panel enabling */
+#define LCD_RST_DELAY 100
+
#define LCD_XRES 800
#define LCD_YRES 480
@@ -41,6 +44,10 @@
/* Current Pixel clock */
#define LCD_PIXEL_CLOCK LCD_PIXCLOCK_MIN
+static int zoom2_spi_resume(struct spi_device *spi);
+static int zoom2_spi_suspend(struct spi_device *spi, pm_message_t mesg);
+
+struct spi_device *zoom2_spi_device;
/*NEC NL8048HL11-01B Manual
* defines HFB, HSW, HBP, VFP, VSW, VBP as shown below
@@ -64,6 +71,11 @@
dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS;
dssdev->panel.timings = zoom2_panel_timings;
+#ifdef CONFIG_FB_OMAP2_32_BPP
+ dssdev->panel.recommended_bpp = 24;
+#else
+ dssdev->panel.recommended_bpp = 16;
+#endif
return 0;
}
@@ -91,12 +103,19 @@
static int zoom2_panel_suspend(struct omap_dss_device *dssdev)
{
+ pm_message_t mesg;
+
+ mesg.event = PM_EVENT_SUSPEND;
zoom2_panel_disable(dssdev);
+ zoom2_spi_suspend(zoom2_spi_device, mesg);
+
return 0;
}
static int zoom2_panel_resume(struct omap_dss_device *dssdev)
{
+ zoom2_spi_resume(zoom2_spi_device);
+ mdelay(LCD_RST_DELAY);
return zoom2_panel_enable(dssdev);
}
@@ -227,6 +246,7 @@
spi->bits_per_word = 32;
spi_setup(spi);
+ zoom2_spi_device = spi;
init_nec_wvga_lcd(spi);
omap_dss_register_driver(&zoom2_driver);
diff --git a/drivers/video/omap2/displays/sil9022.c b/drivers/video/omap2/displays/sil9022.c
index 666fec5..5bde029 100644
--- a/drivers/video/omap2/displays/sil9022.c
+++ b/drivers/video/omap2/displays/sil9022.c
@@ -30,18 +30,22 @@
#include <mach/display.h>
#include <mach/io.h>
+#include <mach/omap-pm.h>
+
+u16 current_descriptor_addrs;
+
static struct i2c_client *sil9022_client;
static struct omap_video_timings omap_dss_hdmi_timings = {
.x_res = HDMI_XRES,
.y_res = HDMI_YRES,
.pixel_clock = HDMI_PIXCLOCK_MAX,
- .hfp = 63,
- .hsw = 255,
- .hbp = 49,
+ .hfp = 110,
+ .hbp = 220,
+ .hsw = 40,
.vfp = 5,
- .vsw = 20,
- .vbp = 4,
+ .vbp = 20,
+ .vsw = 5,
};
static struct hdmi_reg_data hdmi_tpi_audio_config_data[] = {
@@ -135,6 +139,213 @@
0x00
};
+void get_horz_vert_timing_info(u8 *edid)
+{
+ /*HORIZONTAL FRONT PORCH */
+ omap_dss_hdmi_timings.hfp = edid[current_descriptor_addrs + 8];
+ /*HORIZONTAL SYNC WIDTH */
+ omap_dss_hdmi_timings.hsw = edid[current_descriptor_addrs + 9];
+ /*HORIZONTAL BACK PORCH */
+ omap_dss_hdmi_timings.hbp = (((edid[current_descriptor_addrs + 4]
+ & 0x0F) << 8) |
+ edid[current_descriptor_addrs + 3]) -
+ (omap_dss_hdmi_timings.hfp + omap_dss_hdmi_timings.hsw);
+ /*VERTICAL FRONT PORCH */
+ omap_dss_hdmi_timings.vfp = ((edid[current_descriptor_addrs + 10] &
+ 0xF0) >> 4);
+ /*VERTICAL SYNC WIDTH */
+ omap_dss_hdmi_timings.vsw = (edid[current_descriptor_addrs + 10] &
+ 0x0F);
+ /*VERTICAL BACK PORCH */
+ omap_dss_hdmi_timings.vbp = (((edid[current_descriptor_addrs + 7] &
+ 0x0F) << 8) |
+ edid[current_descriptor_addrs + 6]) -
+ (omap_dss_hdmi_timings.vfp + omap_dss_hdmi_timings.vsw);
+
+ dev_dbg(&sil9022_client->dev, "<%s> \n"
+ "hfp = %d\n"
+ "hsw = %d\n"
+ "hbp = %d\n"
+ "vfp = %d\n"
+ "vsw = %d\n"
+ "vbp = %d\n",
+ __func__,
+ omap_dss_hdmi_timings.hfp,
+ omap_dss_hdmi_timings.hsw,
+ omap_dss_hdmi_timings.hbp,
+ omap_dss_hdmi_timings.vfp,
+ omap_dss_hdmi_timings.vsw,
+ omap_dss_hdmi_timings.vbp
+ );
+
+}
+
+/*------------------------------------------------------------------------------
+ | Function : get_edid_timing_data
+ +------------------------------------------------------------------------------
+ | Description : This function gets the resolution information from EDID
+ |
+ | Parameters : void
+ |
+ | Returns : void
+ +----------------------------------------------------------------------------*/
+void get_edid_timing_data(u8 *edid, u16 *pixel_clk, u16 *horizontal_res,
+ u16 *vertical_res)
+{
+ u8 offset, effective_addrs;
+ u8 count;
+ u8 i;
+ u8 flag = false;
+ /*check for 720P timing in block0 */
+ for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) {
+ current_descriptor_addrs =
+ EDID_DESCRIPTOR_BLOCK0_ADDRESS +
+ count * EDID_TIMING_DESCRIPTOR_SIZE;
+ *horizontal_res =
+ (((edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 4 +
+ count * EDID_TIMING_DESCRIPTOR_SIZE] & 0xF0) << 4) |
+ edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 2 +
+ count * EDID_TIMING_DESCRIPTOR_SIZE]);
+ *vertical_res =
+ (((edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 7 +
+ count * EDID_TIMING_DESCRIPTOR_SIZE] & 0xF0) << 4) |
+ edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 5 +
+ count * EDID_TIMING_DESCRIPTOR_SIZE]);
+
+ dev_dbg(&sil9022_client->dev,
+ "<%s> ***Block-0-Timing-descriptor[%d]***\n",
+ __func__, count);
+ for (i = current_descriptor_addrs;
+ i <
+ (current_descriptor_addrs+EDID_TIMING_DESCRIPTOR_SIZE);
+ i++)
+ dev_dbg(&sil9022_client->dev,
+ "%x ==> %x\n", i, edid[i]);
+
+ dev_dbg(&sil9022_client->dev,
+ "<%s>\n"
+ "E-EDID Buffer Index = %d\n"
+ "horizontal_res = %d\n"
+ "vertical_res = %d\n",
+ __func__,
+ current_descriptor_addrs,
+ *horizontal_res,
+ *vertical_res
+ );
+
+ if (*horizontal_res == HDMI_XRES &&
+ *vertical_res == HDMI_YRES) {
+ dev_info(&sil9022_client->dev, "<%s>\nFound EDID Data "
+ "for %d x %dp\n",
+ __func__, *horizontal_res, *vertical_res);
+ flag = true;
+ break;
+ }
+ }
+
+ /*check for the Timing in block1 */
+ if (flag != true) {
+ offset = edid[EDID_DESCRIPTOR_BLOCK1_ADDRESS + 2];
+ if (offset != 0) {
+ effective_addrs = EDID_DESCRIPTOR_BLOCK1_ADDRESS
+ + offset;
+ /*to determine the number of descriptor blocks */
+ for (count = 0;
+ count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR;
+ count++) {
+ current_descriptor_addrs = effective_addrs +
+ count * EDID_TIMING_DESCRIPTOR_SIZE;
+ *horizontal_res =
+ (((edid[effective_addrs + 4 +
+ count*EDID_TIMING_DESCRIPTOR_SIZE] &
+ 0xF0) << 4) |
+ edid[effective_addrs + 2 +
+ count * EDID_TIMING_DESCRIPTOR_SIZE]);
+ *vertical_res =
+ (((edid[effective_addrs + 7 +
+ count*EDID_TIMING_DESCRIPTOR_SIZE] &
+ 0xF0) << 4) |
+ edid[effective_addrs + 5 +
+ count * EDID_TIMING_DESCRIPTOR_SIZE]);
+
+ dev_dbg(&sil9022_client->dev,
+ "<%s> Block1-Timing-descriptor[%d]\n",
+ __func__, count);
+
+ for (i = current_descriptor_addrs;
+ i < (current_descriptor_addrs+
+ EDID_TIMING_DESCRIPTOR_SIZE); i++)
+ dev_dbg(&sil9022_client->dev,
+ "%x ==> %x\n",
+ i, edid[i]);
+
+ dev_dbg(&sil9022_client->dev, "<%s>\n"
+ "current_descriptor = %d\n"
+ "horizontal_res = %d\n"
+ "vertical_res = %d\n",
+ __func__, current_descriptor_addrs,
+ *horizontal_res, *vertical_res);
+
+ if (*horizontal_res == HDMI_XRES &&
+ *vertical_res == HDMI_YRES) {
+ dev_info(&sil9022_client->dev,
+ "<%s> Found EDID Data for "
+ "%d x %dp\n",
+ __func__,
+ *horizontal_res,
+ *vertical_res
+ );
+ flag = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (flag == true) {
+ *pixel_clk = ((edid[current_descriptor_addrs + 1] << 8) |
+ edid[current_descriptor_addrs]);
+
+ omap_dss_hdmi_timings.x_res = *horizontal_res;
+ omap_dss_hdmi_timings.y_res = *vertical_res;
+ omap_dss_hdmi_timings.pixel_clock = *pixel_clk*10;
+ dev_dbg(&sil9022_client->dev,
+ "EDID TIMING DATA supported by zoom2 FOUND\n"
+ "EDID DTD block address = %d\n"
+ "pixel_clk = %d\n"
+ "horizontal res = %d\n"
+ "vertical res = %d\n",
+ current_descriptor_addrs,
+ omap_dss_hdmi_timings.pixel_clock,
+ omap_dss_hdmi_timings.x_res,
+ omap_dss_hdmi_timings.y_res
+ );
+
+ get_horz_vert_timing_info(edid);
+ } else {
+
+ dev_info(&sil9022_client->dev,
+ "<%s>\n"
+ "EDID TIMING DATA supported by zoom2 NOT FOUND\n"
+ "setting default timing values for 720p\n"
+ "pixel_clk = %d\n"
+ "horizontal res = %d\n"
+ "vertical res = %d\n",
+ __func__,
+ omap_dss_hdmi_timings.pixel_clock,
+ omap_dss_hdmi_timings.x_res,
+ omap_dss_hdmi_timings.y_res
+ );
+
+ *pixel_clk = omap_dss_hdmi_timings.pixel_clock;
+ *horizontal_res = omap_dss_hdmi_timings.x_res;
+ *vertical_res = omap_dss_hdmi_timings.y_res;
+ }
+
+
+}
+
+
static int
sil9022_blockwrite_reg(struct i2c_client *client,
u8 reg, u16 alength, u8 *val, u16 *out_len)
@@ -200,12 +411,12 @@
/* High byte goes out first */
data[0] = reg;
+ err = i2c_transfer(client->adapter, msg, 1);
+ dev_dbg(&client->dev, "<%s> i2c Block Read1 at 0x%x, "
+ "*val=%d flags=%d err=%d\n",
+ __func__, data[0], data[1], msg->flags, err);
for (i = 0; i < alength; i++) {
- err = i2c_transfer(client->adapter, msg, 1);
- dev_dbg(&client->dev, "<%s> i2c Block Read1 at 0x%x, "
- "*val=%d flags=%d err=%d\n",
- __func__, data[0], data[1], msg->flags, err);
if (err >= 0) {
mdelay(3);
msg->flags = I2C_M_RD;
@@ -229,7 +440,7 @@
}
*out_len = i;
dev_info(&client->dev, "<%s> i2c Block Read at 0x%x, bytes read = %d\n",
- __func__, reg, *out_len);
+ __func__, client->addr, *out_len);
if (err < 0) {
dev_err(&client->dev, "<%s> ERROR: i2c Read at 0x%x, "
@@ -351,12 +562,36 @@
int err = 0;
u8 val = 0;
int retries = 0;
+ int i = 0;
+ int k = 0;
len = (len < HDMI_EDID_MAX_LENGTH) ? len : HDMI_EDID_MAX_LENGTH;
/* Request DDC bus access to read EDID info from HDTV */
dev_info(&client->dev, "<%s> Reading HDMI EDID\n", __func__);
+ /* Bring transmitter to low-Power state */
+ val = TPI_AVI_POWER_STATE_D2;
+ err = sil9022_write_reg(client, HDMI_TPI_DEVICE_POWER_STATE_DATA, val);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "<%s> ERROR: Failed during bring power state - low.\n",
+ __func__);
+ return err;
+ }
+
+ /* Disable TMDS clock */
+ val = 0x11;
+ err = sil9022_write_reg(client, HDMI_SYS_CTRL_DATA_REG, val);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "<%s> ERROR: Failed during bring power state - low.\n",
+ __func__);
+ return err;
+ }
+
+ val = 0;
+ /* Read TPI system control register*/
err = sil9022_read_reg(client, 1, HDMI_SYS_CTRL_DATA_REG, &val);
if (err < 0) {
dev_err(&client->dev,
@@ -364,6 +599,9 @@
return err;
}
+ /* The host writes 0x1A[2]=1 to request the
+ * DDC(Display Data Channel) bus
+ */
val |= TPI_SYS_CTRL_DDC_BUS_REQUEST;
err = sil9022_write_reg(client, HDMI_SYS_CTRL_DATA_REG, val);
if (err < 0) {
@@ -372,7 +610,7 @@
return err;
}
- /* Poll for bus access granted */
+ /* Poll for bus DDC Bus control to be granted */
dev_info(&client->dev, "<%s> Poll for DDC bus access\n", __func__);
val = 0;
do {
@@ -392,10 +630,9 @@
return err;
}
- /* Read the EDID structure from the monitor I2C address */
memset(p_buffer, 0, len);
- /* I2C SetSlaveAddress to HDMI_I2C_MONITOR_ADDRESS */
-
+ /* change I2C SetSlaveAddress to HDMI_I2C_MONITOR_ADDRESS */
+ /* Read the EDID structure from the monitor I2C address */
client->addr = HDMI_I2C_MONITOR_ADDRESS;
err = sil9022_blockread_reg(client, 1, len,
0x00, p_buffer, out_len);
@@ -406,6 +643,21 @@
return err;
}
+ for (i = 0; i < *out_len; i++) {
+ if ((i / 18) < 3) {
+ dev_dbg(&client->dev, "byte->%02x %x\n",
+ i, p_buffer[i]);
+ continue;
+ }
+ if ((i/18 >= 3 && i/18 <= 6) && (i%18 == 0))
+ dev_dbg(&client->dev, "\n DTD Block %d\n", k++);
+
+ if ((i/18 == 7) && (i%18 == 0))
+ dev_dbg(&client->dev, "\n");
+
+ dev_dbg(&client->dev, "byte->%02x %x\n", i, p_buffer[i]);
+ }
+
/* Release DDC bus access */
client->addr = SI9022_I2CSLAVEADDRESS;
val &= ~(TPI_SYS_CTRL_DDC_BUS_REQUEST | TPI_SYS_CTRL_DDC_BUS_GRANTED);
@@ -535,20 +787,22 @@
}
static int
-hdmi_enable(void)
+hdmi_enable(struct omap_dss_device *dssdev)
{
int err;
u8 val, vals[14];
int i;
u16 out_len = 0;
u8 edid[HDMI_EDID_MAX_LENGTH];
- HDMI_EDID *p_edid = (HDMI_EDID *)edid;
- HDMI_EDID_DTD *p_video_spec = NULL;
- HDMI_EDID_DTD *p_monitor_limits = NULL;
+ u16 horizontal_res;
+ u16 vertical_res;
+ u16 pixel_clk;
+
memset(edid, 0, HDMI_EDID_MAX_LENGTH);
memset(vals, 0, 14);
+
err = hdmi_read_edid(sil9022_client, HDMI_EDID_MAX_LENGTH,
edid, &out_len);
if (err < 0 || out_len == 0) {
@@ -557,29 +811,46 @@
return err;
}
- /* Determine DTD info for the attached monitor */
- for (i = 0; i < HDMI_EDID_MAX_DTDS; i++) {
- if (p_edid->DTD[i].monitor_limits.block_type ==
- HDMI_EDID_DTD_TAG_MONITOR_LIMITS)
- p_monitor_limits = &p_edid->DTD[i];
-
-
- if (p_edid->DTD[i].video.pixel_clock[0] != 0 &&
- p_edid->DTD[i].video.pixel_clock[1] != 0)
- p_video_spec = &p_edid->DTD[i];
- }
+ get_edid_timing_data(edid,
+ &pixel_clk,
+ &horizontal_res,
+ &vertical_res
+ );
/* Fill the TPI Video Mode Data structure */
- vals[0] = p_video_spec->video.pixel_clock[0]; /* Pixel clock */
- vals[1] = p_video_spec->video.pixel_clock[1];
- vals[2] = 60; /* Vertical freq */
- vals[3] = 0;
- vals[4] = p_video_spec->video.horiz_active; /* Horizontal pixels*/
- vals[5] = (p_video_spec->video.horiz_high & 0xF0) >> 4;
- vals[6] = p_video_spec->video.vert_active; /* Vertical pixels */
- vals[7] = (p_video_spec->video.vert_high & 0xF0) >> 4;
+ vals[0] = (pixel_clk & 0xFF); /* Pixel clock */
+ vals[1] = ((pixel_clk & 0xFF00) >> 8);
+ vals[2] = VERTICAL_FREQ; /* Vertical freq */
+ vals[3] = 0x00;
+ vals[4] = (horizontal_res & 0xFF); /* Horizontal pixels*/
+ vals[5] = ((horizontal_res & 0xFF00) >> 8);
+ vals[6] = (vertical_res & 0xFF); /* Vertical pixels */
+ vals[7] = ((vertical_res & 0xFF00) >> 8);
+ dev_info(&sil9022_client->dev, "<%s>\nHDMI Monitor E-EDID Timing Data\n"
+ "horizontal_res = %d\n"
+ "vertical_res = %d\n"
+ "pixel_clk = %d\n"
+ "hfp = %d\n"
+ "hsw = %d\n"
+ "hbp = %d\n"
+ "vfp = %d\n"
+ "vsw = %d\n"
+ "vbp = %d\n",
+ __func__,
+ omap_dss_hdmi_timings.x_res,
+ omap_dss_hdmi_timings.y_res,
+ omap_dss_hdmi_timings.pixel_clock,
+ omap_dss_hdmi_timings.hfp,
+ omap_dss_hdmi_timings.hsw,
+ omap_dss_hdmi_timings.hbp,
+ omap_dss_hdmi_timings.vfp,
+ omap_dss_hdmi_timings.vsw,
+ omap_dss_hdmi_timings.vbp
+ );
+
+ dssdev->panel.timings = omap_dss_hdmi_timings;
/* Write out the TPI Video Mode Data */
out_len = 0;
err = sil9022_blockwrite_reg(sil9022_client,
@@ -836,6 +1107,14 @@
{
int r = 0;
+#ifdef CONFIG_PM
+ struct hdmi_platform_data *pdata = dssdev->dev.platform_data;
+ if (pdata->set_min_bus_tput)
+ pdata->set_min_bus_tput(&sil9022_client->dev,
+ OCP_INITIATOR_AGENT,
+ 166 * 1000 * 4);
+#endif
+
if (dssdev->platform_enable)
r = dssdev->platform_enable(dssdev);
@@ -843,7 +1122,7 @@
if (r)
goto ERROR0;
- r = hdmi_enable();
+ r = hdmi_enable(dssdev);
if (r)
goto ERROR0;
/* wait couple of vsyncs until enabling the LCD */
@@ -856,6 +1135,9 @@
static void hdmi_panel_disable(struct omap_dss_device *dssdev)
{
+#ifdef CONFIG_PM
+ struct hdmi_platform_data *pdata = dssdev->dev.platform_data;
+#endif
hdmi_disable();
/* wait couple of vsyncs until enabling the hdmi */
@@ -863,6 +1145,12 @@
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
+#ifdef CONFIG_PM
+ if (pdata->set_min_bus_tput)
+ pdata->set_min_bus_tput(&sil9022_client->dev,
+ OCP_INITIATOR_AGENT,
+ 0);
+#endif
}
static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
@@ -919,7 +1207,7 @@
return 0;
ERROR1:
- kfree(client);
+ kfree(sil9022_client);
ERROR0:
return err;
}
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index f2ce068..ce82231 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -47,18 +47,26 @@
config OMAP2_DSS_DSI
bool "DSI support"
depends on ARCH_OMAP3
- default n
+ default y
help
MIPI DSI support.
config OMAP2_DSS_USE_DSI_PLL
bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
- default n
+ default y
depends on OMAP2_DSS_DSI
help
Use DSI PLL to generate pixel clock. Currently only for DPI output.
DSI PLL can be used to generate higher and more precise pixel clocks.
+config OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+ bool "Use DSI PLL for HDMI PCLK (EXPERIMENTAL)"
+ default y
+ depends on OMAP2_DSS_DSI
+ help
+ Use DSI PLL to generate HDMI pixel clock. Only for HDMI output.
+ DSI PLL can be used to generate higher and more precise pixel clocks.
+
config OMAP2_DSS_FAKE_VSYNC
bool "Fake VSYNC irq from manual update displays"
default n
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 347fc44..e6d07bd 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -282,10 +282,10 @@
void dss_clk_enable(enum dss_clock clks)
{
- dss_clk_enable_no_ctx(clks);
-
if (cpu_is_omap34xx() && dss_need_ctx_restore())
restore_all_ctx();
+
+ dss_clk_enable_no_ctx(clks);
}
static void dss_clk_disable_no_ctx(enum dss_clock clks)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index d061d75..edec707 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -133,6 +133,14 @@
#define DISPC_MAX_NR_ISRS 8
+
+#define LPR_GFX_FIFO_HIGH_THRES 0xB9C
+#define LPR_GFX_FIFO_LOW_THRES 0x7F8
+#define DISPC_VID_ATTRIBUTES_ENABLE (1 << 0)
+#define DSS_CONTROL_APLL_CLK 1
+static int lpr_enabled;
+static int gfx_in_use;
+
struct omap_dispc_isr_data {
omap_dispc_isr_t isr;
void *arg;
@@ -161,6 +169,7 @@
u32 fifo_size[3];
spinlock_t irq_lock;
+ spinlock_t lpr_lock;
u32 irq_error_mask;
struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
u32 error_irqs;
@@ -170,6 +179,7 @@
} dispc;
static void _omap_dispc_set_irqs(void);
+static int dispc_is_vdma_req(u8 rotation, enum omap_color_mode color_mode);
static inline void dispc_write_reg(const struct dispc_reg idx, u32 val)
{
@@ -546,158 +556,341 @@
dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
}
-static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
- int vscaleup, int five_taps)
+/* New coefficients Begin */
+static void _dispc_set_scale_coef(enum omap_plane plane,
+ u16 orig_width, u16 out_width,
+ u16 orig_height, u16 out_height,
+ int five_taps, bool vdma)
{
- /* Coefficients for horizontal up-sampling */
- static const u32 coef_hup[8] = {
- 0x00800000,
- 0x0D7CF800,
- 0x1E70F5FF,
- 0x335FF5FE,
- 0xF74949F7,
- 0xF55F33FB,
- 0xF5701EFE,
- 0xF87C0DFF,
- };
+ unsigned long reg, mval, rem_ratio;
+ short int vc_3tap[3][8];
+ short int vc[5][8];
+ short int hc[5][8];
+ int i = 0;
- /* Coefficients for horizontal down-sampling */
- static const u32 coef_hdown[8] = {
- 0x24382400,
- 0x28371FFE,
- 0x2C361BFB,
- 0x303516F9,
- 0x11343311,
- 0x1635300C,
- 0x1B362C08,
- 0x1F372804,
- };
+ /* 3-taps vertical filter coefficients */
+ /* Downscaling matrix, if image width > 1024 */
+ const static short int filter_coeff_vc_d[3][8] = {
+ {36, 40, 45, 50, 18, 23, 27, 31},
+ {56, 57, 56, 55, 55, 55, 56, 57},
+ {36, 31, 27, 23, 55, 50, 45, 40} };
- /* Coefficients for horizontal and vertical up-sampling */
- static const u32 coef_hvup[2][8] = {
- {
- 0x00800000,
- 0x037B02FF,
- 0x0C6F05FE,
- 0x205907FB,
- 0x00404000,
- 0x075920FE,
- 0x056F0CFF,
- 0x027B0300,
- },
- {
- 0x00800000,
- 0x0D7CF8FF,
- 0x1E70F5FE,
- 0x335FF5FB,
- 0xF7404000,
- 0xF55F33FE,
- 0xF5701EFF,
- 0xF87C0D00,
- },
- };
+ /* Upscaling matrix, if image width > 1024 */
+ const static short int filter_coeff_vc_u[3][8] = {
+ {0, 16, 32, 48, 0, 0, 0, 0 },
+ {128, 112, 96, 80, 64, 80, 96, 112 },
+ {0, 0, 0, 0, 64, 48, 32, 16 } };
- /* Coefficients for horizontal and vertical down-sampling */
- static const u32 coef_hvdown[2][8] = {
- {
- 0x24382400,
- 0x28391F04,
- 0x2D381B08,
- 0x3237170C,
- 0x123737F7,
- 0x173732F9,
- 0x1B382DFB,
- 0x1F3928FE,
- },
- {
- 0x24382400,
- 0x28371F04,
- 0x2C361B08,
- 0x3035160C,
- 0x113433F7,
- 0x163530F9,
- 0x1B362CFB,
- 0x1F3728FE,
- },
- };
+ /* 5-taps horizontal filter coefficients */
+ /* Downscaling matrix, if image width > 1024 */
+ const static short int filter_coeff_hc_d[5][8] = {
+ {0, 4, 8, 12, -9, -7, -5, -2 },
+ {36, 40, 44, 48, 17, 22, 27, 31 },
+ {56, 55, 54, 53, 52, 53, 54, 55 },
+ {36, 31, 27, 22, 51, 48, 44, 40 },
+ {0, -2, -5, -7, 17, 12, 8, 4 } };
- /* Coefficients for vertical up-sampling */
- static const u32 coef_vup[8] = {
- 0x00000000,
- 0x0000FF00,
- 0x0000FEFF,
- 0x0000FBFE,
- 0x000000F7,
- 0x0000FEFB,
- 0x0000FFFE,
- 0x000000FF,
- };
+ /* Upscaling matrix, if image width > 1024 */
+ const static short int filter_coeff_hc_u[5][8] = {
+ {0, 0, 0, 0, 0, 0, 0, 0 },
+ {0, 16, 32, 48, 0, 0, 0, 0 },
+ {128, 112, 96, 80, 64, 80, 96, 112 },
+ {0, 0, 0, 0, 64, 48, 32, 16 },
+ {0, 0, 0, 0, 0, 0, 0, 0 } };
- /* Coefficients for vertical down-sampling */
- static const u32 coef_vdown[8] = {
- 0x00000000,
- 0x000004FE,
- 0x000008FB,
- 0x00000CF9,
- 0x0000F711,
- 0x0000F90C,
- 0x0000FB08,
- 0x0000FE04,
- };
+ /* Filter coefficients designed for various scaling ratios */
+ /* Below Co-effients are defined for 5 taps as
+ * [0] = VCC22
+ * [1] = VC2
+ * [2] = VC1
+ * [3] = VC0
+ * [4] = VC00
+ */
- const u32 *h_coef;
- const u32 *hv_coef;
- const u32 *hv_coef_mod;
- const u32 *v_coef;
- int i;
+ const static short int filter_coeff_M8[5][8] = {
+ {17, 14, 5, -6, 2, 9, 15, 19},
+ {-20, -4, 17, 47, -18, -27, -30, -27},
+ {134, 127, 121, 105, 81, 105, 121, 127},
+ {-20, -27, -30, -27, 81, 47, 17, -4},
+ {17, 18, 15, 9, -18, -6, 5, 13 } };
- if (hscaleup)
- h_coef = coef_hup;
- else
- h_coef = coef_hdown;
+ const static short int filter_coeff_M9[5][8] = {
+ {8, 1, -9, -18, 14, 17, 17, 14},
+ {-8, 8, 30, 56, -26, -30, -27, -21},
+ {128, 126, 117, 103, 83, 103, 117, 126},
+ {-8, -21, -27, -30, 83, 56, 30, 8},
+ {8, 14, 17, 17, -26, -18, -9, 1} };
- if (vscaleup) {
- hv_coef = coef_hvup[five_taps];
- v_coef = coef_vup;
+ const static short int filter_coeff_M10[5][8] = {
+ {-2, -10, -18, -24, 18, 15, 11, 5},
+ {2, 20, 41, 62, -28, -27, -22, -12},
+ {128, 125, 116, 102, 83, 102, 116, 125},
+ {2, -12, -22, -27, 83, 62, 41, 20},
+ {-2, 5, 11, 15, -28, -24, -18, -10} };
- if (hscaleup)
- hv_coef_mod = NULL;
- else
- hv_coef_mod = coef_hvdown[five_taps];
- } else {
- hv_coef = coef_hvdown[five_taps];
- v_coef = coef_vdown;
+ const static short int filter_coeff_M11[5][8] = {
+ {-12, -19, -24, -27, 14, 9, 3, -4},
+ {12, 30, 49, 67, -26, -22, -15, -3},
+ {128, 124, 115, 101, 83, 101, 115, 124},
+ {12, -3, -15, -22, 83, 67, 49, 30},
+ {-12, -4, 3, 9, -26, -27, -24, -19} };
- if (hscaleup)
- hv_coef_mod = coef_hvup[five_taps];
- else
- hv_coef_mod = NULL;
- }
+ const static short int filter_coeff_M12[5][8] = {
+ {-19, -24, -26, -25, 6, 1, -6, -12},
+ {21, 38, 55, 70, -21, -16, -7, 6},
+ {124, 120, 112, 98, 82, 98, 112, 120},
+ {21, 6, -7, -16, 82, 70, 55, 38},
+ {-19, -12, -6, 1, -21, -25, -26, -24} };
- for (i = 0; i < 8; i++) {
- u32 h, hv;
+ const static short int filter_coeff_M13[5][8] = {
+ {-22, -25, -25, -22, 0, -6, -12, -18 },
+ {27, 43, 58, 71, -17, -10, 0, 13 },
+ {118, 115, 107, 95, 81, 95, 107, 115 },
+ {27, 13, 0, -10, 81, 71, 58, 43 },
+ {-22, -18, -12, -6, -17, -22, -25, -25} };
- h = h_coef[i];
+ const static short int filter_coeff_M14[5][8] = {
+ {-23, -24, -22, -18, -6, -11, -16, -20 },
+ {32, 46, 59, 70, -11, -4, 6, 18 },
+ {110, 108, 101, 91, 78, 91, 101, 108 },
+ {32, 18, 6, -4, 78, 70, 59, 46 },
+ {-23, -20, -16, -11, -11, -18, -22, -24} };
- hv = hv_coef[i];
+ const static short int filter_coeff_M16[5][8] = {
+ {-20, -18, -14, -9, -14, -17, -19, -21},
+ {37, 48, 58, 66, -2, 6, 15, 26},
+ {94, 93, 88, 82, 73, 82, 88, 93},
+ {37, 26, 15, 6, 73, 66, 58, 48},
+ {-20, -21, -19, -17, -2, -9, -14, -18} };
- if (hv_coef_mod) {
- hv &= 0xffffff00;
- hv |= (hv_coef_mod[i] & 0xff);
+ const static short int filter_coeff_M19[5][8] = {
+ {-12, -8, -4, 1, -16, -16, -16, -13},
+ {38, 47, 53, 59, 8, 15, 22, 31},
+ {76, 72, 73, 69, 64, 69, 73, 72},
+ {38, 31, 22, 15, 64, 59, 53, 47},
+ {-12, -14, -16, -16, 8, 1, -4, -9} };
+
+ const static short int filter_coeff_M22[5][8] = {
+ {-6, -1, 3, 8, -14, -13, -11, -7},
+ {37, 44, 48, 53, 13, 19, 25, 32},
+ {66, 61, 63, 61, 58, 61, 63, 61},
+ {37, 32, 25, 19, 58, 53, 48, 44},
+ {-6, -8, -11, -13, 13, 8, 3, -2} };
+
+ const static short int filter_coeff_M26[5][8] = {
+ {1, 4, 8, 13, -10, -8, -5, -2},
+ {36, 40, 44, 48, 18, 22, 27, 31},
+ {54, 55, 54, 53, 51, 53, 54, 55},
+ {36, 31, 27, 22, 51, 48, 44, 40},
+ {1, -2, -5, -8, 18, 13, 8, 4 } };
+
+ const static short int filter_coeff_M32[5][8] = {
+ {7, 10, 14, 17, -4, -1, 1, 4},
+ {34, 37, 39, 42, 21, 24, 28, 31},
+ {46, 46, 46, 46, 45, 46, 46, 46},
+ {34, 31, 27, 24, 45, 42, 39, 37},
+ {7, 4, 1, -1, 21, 17, 14, 10} };
+
+ /* Select the coefficients based on the ratio - height/vertical */
+ if (out_height != 0 && five_taps) {
+ if ((out_height != orig_height) || vdma) {
+ rem_ratio = 0;
+ mval = 8; /* default */
+ rem_ratio = out_height / orig_height ;
+ if (rem_ratio > 1) {
+ mval = 8;
+ DSSDBG("Coefficient class mval = %lu \n", mval);
+ } else {
+ mval = (8 * orig_height) / out_height;
+ }
+
+ switch (mval) {
+ case 8:
+ memcpy(vc, filter_coeff_M8, sizeof(vc));
+ break;
+ case 9:
+ memcpy(vc, filter_coeff_M9, sizeof(vc));
+ break;
+ case 10:
+ memcpy(vc, filter_coeff_M10, sizeof(vc));
+ break;
+ case 11:
+ memcpy(vc, filter_coeff_M11, sizeof(vc));
+ break;
+ case 12:
+ memcpy(vc, filter_coeff_M12, sizeof(vc));
+ break;
+ case 13:
+ memcpy(vc, filter_coeff_M13, sizeof(vc));
+ break;
+ case 14:
+ memcpy(vc, filter_coeff_M14, sizeof(vc));
+ break;
+ case 15:
+ case 16:
+ memcpy(vc, filter_coeff_M16, sizeof(vc));
+ break;
+ case 17:
+ case 18:
+ case 19:
+ memcpy(vc, filter_coeff_M19, sizeof(vc));
+ break;
+ case 20:
+ case 21:
+ case 22:
+ memcpy(vc, filter_coeff_M22, sizeof(vc));
+ break;
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ memcpy(vc, filter_coeff_M26, sizeof(vc));
+ break;
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ memcpy(vc, filter_coeff_M32, sizeof(vc));
+ break;
+ default:
+ DSSDBG("Chosing default M val = 8 \n");
+ memcpy(vc, filter_coeff_M8, sizeof(vc));
+ break;
+ };
}
-
- _dispc_write_firh_reg(plane, i, h);
- _dispc_write_firhv_reg(plane, i, hv);
+ } else if (out_height != 0 && !five_taps) {
+ if (out_height != orig_height) {
+ /* Vertical scaling */
+ if (out_height > orig_height) {
+ DSSDBG("Vertical upscaling \n");
+ memcpy(vc_3tap, filter_coeff_vc_u,
+ sizeof(vc_3tap));
+ } else {
+ DSSDBG("Vertical downscaling \n");
+ memcpy(vc_3tap, filter_coeff_vc_d,
+ sizeof(vc_3tap));
+ }
+ }
}
- if (!five_taps)
- return;
+ /* Select the coefficients based on the ratio - width / horizontal */
+ if (out_width != 0 && five_taps) {
+ if ((out_width != orig_width) || vdma) {
+ rem_ratio = 0;
+ mval = 8; /* default */
+ rem_ratio = out_width / orig_width ;
+ if (rem_ratio > 1)
+ mval = 8;
+ else
+ mval = (8 * orig_width) / out_width;
+
+ switch (mval) {
+ case 8:
+ memcpy(hc, filter_coeff_M8, sizeof(hc));
+ break;
+ case 9:
+ memcpy(hc, filter_coeff_M9, sizeof(hc));
+ break;
+ case 10:
+ memcpy(hc, filter_coeff_M10, sizeof(hc));
+ break;
+ case 11:
+ memcpy(hc, filter_coeff_M11, sizeof(hc));
+ break;
+ case 12:
+ memcpy(hc, filter_coeff_M12, sizeof(hc));
+ break;
+ case 13:
+ memcpy(hc, filter_coeff_M13, sizeof(hc));
+ break;
+ case 14:
+ memcpy(hc, filter_coeff_M14, sizeof(hc));
+ break;
+ case 15:
+ case 16:
+ memcpy(hc, filter_coeff_M16, sizeof(hc));
+ break;
+ case 17:
+ case 18:
+ case 19:
+ memcpy(hc, filter_coeff_M19, sizeof(hc));
+ break;
+ case 20:
+ case 21:
+ case 22:
+ memcpy(hc, filter_coeff_M22, sizeof(hc));
+ break;
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ memcpy(hc, filter_coeff_M26, sizeof(hc));
+ break;
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ memcpy(hc, filter_coeff_M32, sizeof(hc));
+ break;
+ default:
+ DSSDBG("Chosing default M val = 8 \n");
+ memcpy(hc, filter_coeff_M8, sizeof(hc));
+ break;
+ };
+ }
+ } else if (out_width != 0 && !five_taps) {
+ if (out_width != orig_width) {
+ /* Horizontal scaling */
+ if (out_height > orig_height) {
+ DSSDBG("Horizontal upscaling \n");
+ memcpy(hc, filter_coeff_hc_u, sizeof(hc));
+ } else {
+ DSSDBG("Horizontal downscaling \n");
+ memcpy(hc, filter_coeff_hc_d, sizeof(hc));
+ }
+ }
+ }
+
+ /* Pack the coefficients - use fivetaps for all ratios */
for (i = 0; i < 8; i++) {
- u32 v;
- v = v_coef[i];
- _dispc_write_firv_reg(plane, i, v);
+ reg = 0;
+ DSSDBG("Phase i = %d \n", (int)i);
+ reg = ((hc[1][i] & 0xff) << 24)
+ | ((hc[2][i] & 0xff) << 16)
+ | ((hc[3][i] & 0xff) << 8)
+ | (hc[4][i] & 0xff);
+ _dispc_write_firh_reg(plane, i, reg);
+ DSSDBG("H coefficients = 0x%x\n", (int)reg);
+
+ if (!five_taps) {
+ reg = 0;
+ reg = (hc[0][i] & 0xff)
+ | ((vc_3tap[2][i] & 0xff) << 8)
+ | ((vc_3tap[1][i] & 0xff) << 16)
+ | ((vc_3tap[0][i] & 0xff) << 24);
+ _dispc_write_firhv_reg(plane, i, reg);
+ DSSDBG("HV coefficients = 0x%x\n", (int)reg);
+
+ } else {
+ reg = 0;
+ reg = (hc[0][i] & 0xff)
+ | ((vc[3][i] & 0xff) << 8)
+ | ((vc[2][i] & 0xff) << 16)
+ | ((vc[1][i] & 0xff) << 24);
+ _dispc_write_firhv_reg(plane, i, reg);
+ DSSDBG("HV coefficients = 0x%x\n", (int)reg);
+
+ reg = 0;
+ reg = ((vc[0][i] & 0xff) << 8) | (vc[4][i] & 0xff);
+ _dispc_write_firv_reg(plane, i, reg);
+ DSSDBG("V coefficients = 0x%x\n", (int)reg);
+ }
}
}
@@ -1052,12 +1245,16 @@
dispc_write_reg(ac1_reg[plane-1], val);
}
+static void _dispc_set_vdma_attrs(enum omap_plane plane, bool enable)
+{
+ REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 20, 20);
+}
static void _dispc_set_scaling(enum omap_plane plane,
u16 orig_width, u16 orig_height,
u16 out_width, u16 out_height,
bool ilace, bool five_taps,
- bool fieldmode)
+ bool fieldmode, bool vdma)
{
int fir_hinc;
int fir_vinc;
@@ -1071,14 +1268,16 @@
hscaleup = orig_width <= out_width;
vscaleup = orig_height <= out_height;
- _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
+ /* New filter coefficients integration */
+ _dispc_set_scale_coef(plane, orig_width, out_width,
+ orig_height, out_height, five_taps, vdma);
- if (!orig_width || orig_width == out_width)
+ if (!orig_width || (!vdma && (orig_width == out_width)))
fir_hinc = 0;
else
fir_hinc = 1024 * orig_width / out_width;
- if (!orig_height || orig_height == out_height)
+ if (!orig_height || (!vdma && (orig_height == out_height)))
fir_vinc = 0;
else
fir_vinc = 1024 * orig_height / out_height;
@@ -1129,13 +1328,13 @@
vidrot = 2;
break;
case 1:
- vidrot = 1;
+ vidrot = 3;
break;
case 2:
vidrot = 0;
break;
case 3:
- vidrot = 3;
+ vidrot = 1;
break;
}
} else {
@@ -1144,23 +1343,25 @@
vidrot = 0;
break;
case 1:
- vidrot = 1;
+ vidrot = 3;
break;
case 2:
vidrot = 2;
break;
case 3:
- vidrot = 3;
+ vidrot = 1;
break;
}
}
REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
- if (rotation == 1 || rotation == 3)
+ if (!dispc_is_vdma_req(rotation, color_mode) &&
+ (rotation == 1 || rotation == 3))
REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
else
REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
+
} else {
REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
@@ -1485,6 +1686,17 @@
return dispc_pclk_rate() * vf * hf;
}
+static int dispc_is_vdma_req(u8 rotation, enum omap_color_mode color_mode)
+{
+ /* TODO: VDMA support for RGB16 mode */
+ if (cpu_is_omap3630())
+ if ((color_mode == OMAP_DSS_COLOR_YUV2) ||
+ (color_mode == OMAP_DSS_COLOR_UYVY))
+ if ((rotation == 1) || (rotation == 3))
+ return true;
+ return false;
+}
+
void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
{
enable_clocks(1);
@@ -1504,7 +1716,7 @@
u8 global_alpha)
{
const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
- bool five_taps = 0;
+ bool five_taps = 1;
bool fieldmode = 0;
int cconv = 0;
unsigned offset0, offset1;
@@ -1583,8 +1795,6 @@
return -EINVAL;
}
- /* Must use 5-tap filter? */
- five_taps = height > out_height * 2;
if (!five_taps) {
fclk = calc_fclk(width, height,
@@ -1594,10 +1804,12 @@
if (cpu_is_omap34xx() && height > out_height &&
fclk > dispc_fclk_rate())
five_taps = true;
+ if (dispc_is_vdma_req(rotation, color_mode))
+ five_taps = true;
}
if (width > (2048 >> five_taps))
- return -EINVAL;
+ five_taps = 0;
if (five_taps)
fclk = calc_fclk_five_taps(width, height,
@@ -1658,9 +1870,17 @@
_dispc_set_pic_size(plane, width, height);
if (plane != OMAP_DSS_GFX) {
- _dispc_set_scaling(plane, width, height,
- out_width, out_height,
- ilace, five_taps, fieldmode);
+ if (dispc_is_vdma_req(rotation, color_mode)) {
+ _dispc_set_scaling(plane, width, height,
+ out_width, out_height,
+ ilace, five_taps, fieldmode, 1);
+ _dispc_set_vdma_attrs(plane, 1);
+ } else {
+ _dispc_set_scaling(plane, width, height,
+ out_width, out_height,
+ ilace, five_taps, fieldmode, 0);
+ _dispc_set_vdma_attrs(plane, 0);
+ }
_dispc_set_vid_size(plane, out_width, out_height);
_dispc_set_vid_color_conv(plane, cconv);
}
@@ -2373,14 +2593,18 @@
DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
onoff, rf, ieo, ipc, ihs, ivs, acbi, acb);
- l |= FLD_VAL(onoff, 17, 17);
- l |= FLD_VAL(rf, 16, 16);
- l |= FLD_VAL(ieo, 15, 15);
- l |= FLD_VAL(ipc, 14, 14);
- l |= FLD_VAL(ihs, 13, 13);
- l |= FLD_VAL(ivs, 12, 12);
- l |= FLD_VAL(acbi, 11, 8);
- l |= FLD_VAL(acb, 7, 0);
+ if (cpu_is_omap3630()) {
+ l = 0x00033028;
+ } else {
+ l |= FLD_VAL(onoff, 17, 17);
+ l |= FLD_VAL(rf, 16, 16);
+ l |= FLD_VAL(ieo, 15, 15);
+ l |= FLD_VAL(ipc, 14, 14);
+ l |= FLD_VAL(ihs, 13, 13);
+ l |= FLD_VAL(ivs, 12, 12);
+ l |= FLD_VAL(acbi, 11, 8);
+ l |= FLD_VAL(acb, 7, 0);
+ }
enable_clocks(1);
dispc_write_reg(DISPC_POL_FREQ, l);
@@ -2493,8 +2717,16 @@
goto found;
} else if (cpu_is_omap34xx()) {
- for (cur.fck_div = 16; cur.fck_div > 0; --cur.fck_div) {
- cur.fck = prate / cur.fck_div * 2;
+ if (cpu_is_omap3630())
+ cur.fck_div = 32;
+ else
+ cur.fck_div = 16;
+
+ for ( ; cur.fck_div > 0; --cur.fck_div) {
+ if (cpu_is_omap3630())
+ cur.fck = prate / cur.fck_div ;
+ else
+ cur.fck = prate / cur.fck_div * 2;
if (cur.fck > DISPC_MAX_FCK)
continue;
@@ -2708,6 +2940,114 @@
}
EXPORT_SYMBOL(omap_dispc_unregister_isr);
+/* This functions adds the OMAPDSS power saving capability by
+ * FIFO Merge when display is not in use, thus ehancing the DSS for
+ * Screen saver support.
+ */
+int omap_dispc_lpr_enable(void)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct omap_overlay *ovl;
+ int v_attr;
+
+ /* Cannot enable lpr if DSS is inactive */
+ if (!gfx_in_use) {
+ DSSDBG("\nGRX plane in use\n");
+ return -1;
+ }
+
+ spin_lock_irqsave(&dispc.lpr_lock, flags);
+
+ if (lpr_enabled) {
+ DSSDBG("\nLPR is enabled\n");
+ goto lpr_out;
+ }
+
+ /* Check whether LPR can be triggered
+ * - gfx pipeline is routed to LCD
+ * - both video pipelines are disabled (this allows FIFOs merge)
+ */
+
+ ovl = omap_dss_get_overlay(0);
+
+ if (ovl->manager->id != OMAP_DSS_CHANNEL_LCD) {
+ rc = -1;
+ goto lpr_out;
+ }
+
+ v_attr = dispc_read_reg(DISPC_VID_ATTRIBUTES(0)) |
+ dispc_read_reg(DISPC_VID_ATTRIBUTES(1));
+
+ if (v_attr & DISPC_VID_ATTRIBUTES_ENABLE) {
+ rc = -1;
+ goto lpr_out;
+ }
+
+ dispc_setup_plane_fifo(ovl->id, LPR_GFX_FIFO_LOW_THRES,
+ LPR_GFX_FIFO_HIGH_THRES);
+
+ dispc_enable_fifomerge(1);
+
+ /* Enable LCD */
+
+ dispc_enable_lcd_out(1);
+
+ spin_unlock_irqrestore(&dispc.lpr_lock, flags);
+
+ /*Let LPR settings take an effect */
+
+ dispc_go(ovl->manager->id);
+
+ lpr_enabled = 1;
+
+ return 0;
+
+lpr_out:
+ spin_unlock_irqrestore(&dispc.lpr_lock, flags);
+ return rc;
+
+}
+EXPORT_SYMBOL(omap_dispc_lpr_enable);
+
+int omap_dispc_lpr_disable(void)
+{
+ unsigned long flags;
+ struct omap_overlay *ovl;
+ u32 fifo_low, fifo_high;
+ enum omap_burst_size burst_size;
+
+ if (!gfx_in_use)
+ return -1;
+
+ spin_lock_irqsave(&dispc.lpr_lock, flags);
+
+ ovl = omap_dss_get_overlay(0);
+
+ if (!lpr_enabled) {
+ spin_unlock_irqrestore(&dispc.lpr_lock, flags);
+ return 0;
+ }
+ /* Disable Fifo Merge */
+ dispc_enable_fifomerge(0);
+
+ default_get_overlay_fifo_thresholds(ovl->id, dispc.fifo_size[ovl->id],
+ &burst_size, &fifo_low, &fifo_high);
+
+ /* Restore default fifo size*/
+ dispc_setup_plane_fifo(ovl->id, fifo_low, fifo_high);
+
+ lpr_enabled = 0;
+
+ spin_unlock_irqrestore(&dispc.lpr_lock, flags);
+
+ /* Let DSS take an effect */
+ dispc_go(ovl->manager->id);
+
+ return 0;
+}
+EXPORT_SYMBOL(omap_dispc_lpr_disable);
+
#ifdef DEBUG
static void print_irq_status(u32 status)
{
@@ -3134,6 +3474,14 @@
enable_clocks(1);
_dispc_enable_plane(plane, enable);
+
+ if (plane == OMAP_DSS_GFX) {
+ if (enable)
+ gfx_in_use = 1;
+ else
+ gfx_in_use = 0;
+ }
+
enable_clocks(0);
return 0;
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 18fa026..5ca021d 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -277,6 +277,30 @@
return size;
}
+unsigned long lpr_enable;
+extern int omap_dispc_lpr_enable(void);
+extern void omap_dispc_lpr_disable(void);
+
+static ssize_t display_lpr_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+
+ lpr_enable = simple_strtoul(buf, NULL, 0);
+ if (lpr_enable)
+ omap_dispc_lpr_enable();
+ else
+ omap_dispc_lpr_disable();
+
+ return size;
+}
+
+static ssize_t display_lpr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ return snprintf(buf, PAGE_SIZE, "%lu\n", lpr_enable);
+}
+
static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
display_enabled_show, display_enabled_store);
static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR,
@@ -291,6 +315,8 @@
display_mirror_show, display_mirror_store);
static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
display_wss_show, display_wss_store);
+static DEVICE_ATTR(lpr_enable, S_IRUGO|S_IWUSR,
+ display_lpr_show, display_lpr_store);
static struct device_attribute *display_sysfs_attrs[] = {
&dev_attr_enabled,
@@ -300,6 +326,7 @@
&dev_attr_rotate,
&dev_attr_mirror,
&dev_attr_wss,
+ &dev_attr_lpr_enable,
NULL
};
@@ -370,7 +397,7 @@
bool dss_use_replication(struct omap_dss_device *dssdev,
enum omap_color_mode mode)
{
- int bpp;
+ int bpp = 0;
if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
return false;
@@ -381,6 +408,7 @@
switch (dssdev->type) {
case OMAP_DISPLAY_TYPE_DPI:
+ case OMAP_DISPLAY_TYPE_HDMI:
bpp = dssdev->phy.dpi.data_lines;
break;
case OMAP_DISPLAY_TYPE_VENC:
@@ -582,7 +610,7 @@
* of from-device is decremented. */
struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
{
- struct device *dev;
+ struct device *dev = NULL;
struct device *dev_start = NULL;
struct omap_dss_device *dssdev = NULL;
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index b6543c8..46ba42e 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -26,6 +26,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/errno.h>
+#include <linux/i2c/twl4030.h>
#include <mach/board.h>
#include <mach/display.h>
@@ -33,11 +34,28 @@
#include "dss.h"
+/* for enabling VPLL2*/
+#define ENABLE_VPLL2_DEDICATED 0x05
+#define ENABLE_VPLL2_DEV_GRP 0xE0
+#define TWL4030_VPLL2_DEV_GRP 0x33
+#define TWL4030_VPLL2_DEDICATED 0x36
+
static struct {
int update_enabled;
} dpi;
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+static int enable_vpll2_power(int enable)
+{
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ (enable) ? ENABLE_VPLL2_DEDICATED : 0,
+ TWL4030_VPLL2_DEDICATED);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ (enable) ? ENABLE_VPLL2_DEV_GRP : 0,
+ TWL4030_VPLL2_DEV_GRP);
+ return 0;
+}
+
static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
unsigned long *fck, int *lck_div, int *pck_div)
{
@@ -166,7 +184,8 @@
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
dss_clk_enable(DSS_CLK_FCK2);
- r = dsi_pll_init(0, 1);
+ enable_vpll2_power(1);
+ r = dsi_pll_init(1, 1);
if (r)
goto err3;
#endif
@@ -219,6 +238,7 @@
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
dss_select_clk_source(0, 0);
dsi_pll_uninit();
+ enable_vpll2_power(0);
dss_clk_disable(DSS_CLK_FCK2);
#endif
@@ -241,6 +261,13 @@
dispc_enable_lcd_out(0);
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+ dss_select_clk_source(0, 0);
+ dsi_pll_uninit();
+ enable_vpll2_power(0);
+ dss_clk_disable(DSS_CLK_FCK2);
+#endif
+
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
@@ -250,6 +277,7 @@
static int dpi_display_resume(struct omap_dss_device *dssdev)
{
+ int r = 0;
if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
return -EINVAL;
@@ -257,14 +285,44 @@
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+ dss_clk_enable(DSS_CLK_FCK2);
+ enable_vpll2_power(1);
+
+ r = dsi_pll_init(1, 1);
+ if (r)
+ goto err0;
+
+ r = dpi_set_mode(dssdev);
+ if (r)
+ goto err0;
+#endif
+
dispc_enable_lcd_out(1);
- if (dssdev->driver->resume)
- dssdev->driver->resume(dssdev);
+ if (dssdev->driver->resume) {
+ r = dssdev->driver->resume(dssdev);
+ if (r)
+ goto err1;
+ }
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
+
+err1:
+ dispc_enable_lcd_out(0);
+
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+err0:
+ DSSERR("<%s!!> err0: failed to init DSI_PLL = %d\n", __func__, r);
+ dss_select_clk_source(0, 0);
+ dsi_pll_uninit();
+ dss_clk_disable(DSS_CLK_FCK2);
+ enable_vpll2_power(0);
+#endif
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ return r;
}
static void dpi_set_timings(struct omap_dss_device *dssdev,
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index e10882d..6e6b88f0 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -1,8 +1,8 @@
/*
* linux/drivers/video/omap2/dss/hdmi.c
*
- * Copyright (C) 2009 Nokia Corporation
- * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ * Author: srinivas pulukuru <srinivas.pulukuru@ti.com>
*
* hdmi settings from TI's DSS driver
*
@@ -22,21 +22,66 @@
#define DSS_SUBSYS_NAME "HDMI"
#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
+#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/platform_device.h>
+#include <linux/errno.h>
#include <linux/sil9022.h>
+#include <linux/i2c/twl4030.h>
+#include <mach/board.h>
#include <mach/display.h>
+#include <mach/cpu.h>
#include "dss.h"
+/* for enabling VPLL2*/
+#define ENABLE_VPLL2_DEDICATED 0x05
+#define ENABLE_VPLL2_DEV_GRP 0xE0
+#define TWL4030_VPLL2_DEV_GRP 0x33
+#define TWL4030_VPLL2_DEDICATED 0x36
+
struct omap_dss_device *omap_dss_hdmi_device;
+static void hdmi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
+
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+static int enable_vpll2_power(int enable)
+{
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ (enable) ? ENABLE_VPLL2_DEDICATED : 0,
+ TWL4030_VPLL2_DEDICATED);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ (enable) ? ENABLE_VPLL2_DEV_GRP : 0,
+ TWL4030_VPLL2_DEV_GRP);
+ return 0;
+}
+
+static int hdmi_set_dsi_clk(bool is_tft, unsigned long pck_req,
+ unsigned long *fck, int *lck_div, int *pck_div)
+{
+ struct dsi_clock_info cinfo;
+ int r;
+
+ r = dsi_pll_calc_pck(is_tft, pck_req, &cinfo);
+ if (r)
+ return r;
+
+ r = dsi_pll_program(&cinfo);
+ if (r)
+ return r;
+
+ dss_select_clk_source(0, 1);
+
+ dispc_set_lcd_divisor(cinfo.lck_div, cinfo.pck_div);
+
+ *fck = cinfo.dsi1_pll_fclk;
+ *lck_div = cinfo.lck_div;
+ *pck_div = cinfo.pck_div;
+
+ return 0;
+}
+#else
static int hdmi_set_dispc_clk(bool is_tft, unsigned long pck_req,
unsigned long *fck, int *lck_div, int *pck_div)
{
@@ -57,6 +102,8 @@
return 0;
}
+#endif
+
static int hdmi_set_mode(struct omap_dss_device *dssdev)
{
struct omap_video_timings *t = &dssdev->panel.timings;
@@ -73,8 +120,13 @@
is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+ r = hdmi_set_dsi_clk(is_tft, t->pixel_clock * 1000,
+ &fck, &lck_div, &pck_div);
+#else
r = hdmi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
&fck, &lck_div, &pck_div);
+#endif
if (r)
goto err0;
@@ -113,7 +165,6 @@
{
int r = 0;
- DSSDBG("hdmi_enable_display\n");
r = omap_dss_start_device(dssdev);
if (r) {
DSSERR("failed to start device\n");
@@ -132,9 +183,14 @@
if (r)
goto err2;
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
dss_clk_enable(DSS_CLK_FCK2);
- r = dsi_pll_init(0, 1);
+ /* this needs to be done here in order to
+ * get the VPLL2 to power up the DSI PLL module
+ */
+ enable_vpll2_power(1);
+
+ r = dsi_pll_init(1, 1);
if (r)
goto err3;
#endif
@@ -152,12 +208,17 @@
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ /* Default HDMI panel timings may not work for all monitors */
+ /* Reset HDMI panel timings after enabling HDMI. */
+ DSSINFO("Reset HDMI output timings based on monitor E-EDID timings\n");
+ hdmi_set_timings(dssdev, &dssdev->panel.timings);
+
return 0;
err5:
dispc_enable_lcd_out(0);
err4:
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
dsi_pll_uninit();
err3:
dss_clk_disable(DSS_CLK_FCK2);
@@ -185,9 +246,10 @@
dispc_enable_lcd_out(0);
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
dss_select_clk_source(0, 0);
dsi_pll_uninit();
+ enable_vpll2_power(0);
dss_clk_disable(DSS_CLK_FCK2);
#endif
@@ -200,19 +262,23 @@
static int hdmi_display_suspend(struct omap_dss_device *dssdev)
{
- int r = 0;
-
- DSSDBG("hdmi_display_suspend\n");
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return -EINVAL;
- DSSDBG("dpi_display_suspend\n");
+ DSSDBG("hdmi_display_suspend\n");
if (dssdev->driver->suspend)
dssdev->driver->suspend(dssdev);
dispc_enable_lcd_out(0);
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+ dss_select_clk_source(0, 0);
+ dsi_pll_uninit();
+ enable_vpll2_power(0);
+ dss_clk_disable(DSS_CLK_FCK2);
+#endif
+
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
@@ -223,7 +289,6 @@
static int hdmi_display_resume(struct omap_dss_device *dssdev)
{
int r = 0;
-
if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
return -EINVAL;
@@ -231,15 +296,44 @@
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+ dss_clk_enable(DSS_CLK_FCK2);
+ enable_vpll2_power(1);
+
+ r = dsi_pll_init(1, 1);
+ if (r)
+ goto err0;
+
+ r = hdmi_set_mode(dssdev);
+ if (r)
+ goto err0;
+#endif
+
dispc_enable_lcd_out(1);
- if (dssdev->driver->resume)
- dssdev->driver->resume(dssdev);
+ if (dssdev->driver->resume) {
+ r = dssdev->driver->resume(dssdev);
+ if (r)
+ goto err1;
+ }
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
+err1:
+ dispc_enable_lcd_out(0);
+
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+err0:
+ DSSERR("<%s!!> err0: failed to init DSI_PLL = %d\n", __func__, r);
+ dss_select_clk_source(0, 0);
+ dsi_pll_uninit();
+ dss_clk_disable(DSS_CLK_FCK2);
+ enable_vpll2_power(0);
+#endif
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ return r;
}
static void hdmi_get_timings(struct omap_dss_device *dssdev,
@@ -252,6 +346,7 @@
struct omap_video_timings *timings)
{
DSSDBG("hdmi_set_timings\n");
+ dssdev->panel.timings = *timings;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
hdmi_set_mode(dssdev);
dispc_go(OMAP_DSS_CHANNEL_LCD);
@@ -276,7 +371,7 @@
is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
{
struct dsi_clock_info cinfo;
r = dsi_pll_calc_pck(is_tft, timings->pixel_clock * 1000,
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index d64873a..e1b15d8 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -832,7 +832,7 @@
DSSDBGF("%d", channel);
c = &dss_cache.manager_cache[channel];
-
+ dispc_set_default_color(channel, c->default_color);
dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
dispc_enable_trans_key(channel, c->trans_enabled);
dispc_enable_alpha_blending(channel, c->alpha_enabled);
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 9dd2349..69e8a10 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -124,6 +124,7 @@
struct kfifo *cmd_fifo;
spinlock_t cmd_lock;
struct completion cmd_done;
+ struct completion update_done;
atomic_t cmd_fifo_full;
atomic_t cmd_pending;
#ifdef MEASURE_PERF
@@ -419,6 +420,8 @@
/*callback(rfbi.framedone_callback_data);*/
+ complete(&rfbi.update_done);
+
atomic_set(&rfbi.cmd_pending, 0);
process_cmd_fifo();
@@ -1164,6 +1167,7 @@
return -ENOMEM;
init_completion(&rfbi.cmd_done);
+ init_completion(&rfbi.update_done);
atomic_set(&rfbi.cmd_fifo_full, 0);
atomic_set(&rfbi.cmd_pending, 0);
@@ -1208,6 +1212,9 @@
{
int rfbi_module;
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ return 0;
+
if (w == 0 || h == 0)
return 0;
@@ -1233,6 +1240,18 @@
return 0;
}
+static enum omap_dss_update_mode rfbi_display_get_update_mode(
+ struct omap_dss_device *dssdev)
+{
+ return OMAP_DSS_UPDATE_MANUAL;
+}
+
+static int rfbi_display_set_update_mode(struct omap_dss_device *dssdev,
+ enum omap_dss_update_mode mode)
+{
+ return 0;
+}
+
static int rfbi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
{
dssdev->driver->enable_te(dssdev, enable);
@@ -1243,6 +1262,8 @@
{
int r;
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
r = omap_dss_start_device(dssdev);
if (r) {
DSSERR("failed to start device\n");
@@ -1294,6 +1315,51 @@
omap_dss_stop_device(dssdev);
}
+static int rfbi_display_suspend(struct omap_dss_device *dssdev)
+{
+ DSSDBG("rfbi_display_suspend\n");
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ return -EINVAL;
+
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+ wait_for_completion(&rfbi.update_done);
+
+ rfbi_enable_clocks(1);
+
+ /* Bypass mode must be enabled to allow the RFBI module to idle */
+ REG_FLD_MOD(RFBI_CONTROL, 1, 1, 1);
+
+ rfbi_display_disable(dssdev);
+ rfbi_exit();
+
+ rfbi_enable_clocks(0);
+
+ return 0;
+}
+
+static int rfbi_display_resume(struct omap_dss_device *dssdev)
+{
+
+ DSSDBG("rfbi_display_resume\n");
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
+ return -EINVAL;
+
+ rfbi_enable_clocks(1);
+
+ /* Disable Bypass mode again */
+ REG_FLD_MOD(RFBI_CONTROL, 0, 1, 1);
+
+ rfbi_init();
+ rfbi_display_enable(dssdev);
+
+ rfbi_enable_clocks(0);
+
+ return 0;
+}
+
int rfbi_init_display(struct omap_dss_device *dssdev)
{
dssdev->enable = rfbi_display_enable;
@@ -1301,6 +1367,10 @@
dssdev->update = rfbi_display_update;
dssdev->sync = rfbi_display_sync;
dssdev->enable_te = rfbi_display_enable_te;
+ dssdev->get_update_mode = rfbi_display_get_update_mode;
+ dssdev->set_update_mode = rfbi_display_set_update_mode;
+ dssdev->suspend = rfbi_display_suspend;
+ dssdev->resume = rfbi_display_resume;
rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
index 4f66033..c5d44f6 100644
--- a/drivers/video/omap2/omapfb/Kconfig
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -33,3 +33,10 @@
help
Select the number of framebuffers created. OMAP2/3 has 3 overlays
so normally this would be 3.
+
+config FB_OMAP2_32_BPP
+ bool "Support 32 bpp"
+ default n
+ depends on FB_OMAP2
+ help
+ Supports 32 bpp for zoom2 panel.
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 41f1615..30cfd76 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -412,6 +412,9 @@
fix->smem_start = omapfb_get_region_paddr(ofbi);
fix->smem_len = rg->size;
+ fix->mmio_start = DSS_BASE;
+ fix->mmio_len = DSS_SZ_REGS;
+
fix->type = FB_TYPE_PACKED_PIXELS;
if (var->nonstd)
@@ -1284,6 +1287,9 @@
bytespp = 2;
break;
case 24:
+#ifdef CONFIG_FB_OMAP2_32_BPP
+ case 32:
+#endif
bytespp = 4;
break;
default:
@@ -1565,6 +1571,22 @@
return r;
}
+#ifdef CONFIG_HAS_EARLYSUSPEND
+void omapfb_suspend(struct early_suspend *h)
+{
+ struct omapfb_info *fbinfo = container_of(h, struct omapfb_info,
+ early_suspend);
+ omapfb_blank(FB_BLANK_POWERDOWN, fbinfo->fbdev->fbs[fbinfo->id]);
+}
+
+void omapfb_resume(struct early_suspend *h)
+{
+ struct omapfb_info *fbinfo = container_of(h, struct omapfb_info,
+ early_suspend);
+ omapfb_blank(FB_BLANK_UNBLANK, fbinfo->fbdev->fbs[fbinfo->id]);
+}
+#endif
+
/* initialize fb_info, var, fix to something sane based on the display */
int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
{
@@ -1637,6 +1659,9 @@
var->bits_per_pixel = 16;
break;
case 24:
+#ifdef CONFIG_FB_OMAP2_32_BPP
+ case 32:
+#endif
var->bits_per_pixel = 32;
break;
default:
@@ -1664,6 +1689,12 @@
r = fb_alloc_cmap(&fbi->cmap, 256, 0);
if (r)
dev_err(fbdev->dev, "unable to allocate color map memory\n");
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ ofbi->early_suspend.suspend = omapfb_suspend;
+ ofbi->early_suspend.resume = omapfb_resume;
+ ofbi->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+ register_early_suspend(&ofbi->early_suspend);
+#endif
err:
return r;
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
index 6ca8ba6..c4eb5f8 100644
--- a/drivers/video/omap2/omapfb/omapfb.h
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -28,6 +28,7 @@
#endif
#include <mach/display.h>
+#include <linux/earlysuspend.h>
#ifdef DEBUG
extern unsigned int omapfb_debug;
@@ -38,6 +39,9 @@
#define DBG(format, ...)
#endif
+#define DSS_BASE 0x48050000
+#define DSS_SZ_REGS SZ_512
+
#define FB2OFB(fb_info) ((struct omapfb_info *)(fb_info->par))
/* max number of overlays to which a framebuffer data can be direct */
@@ -64,6 +68,9 @@
enum omap_dss_rotation_type rotation_type;
u8 rotation[OMAPFB_MAX_OVL_PER_FB];
bool mirror;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
};
struct omapfb2_device {
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index 53fd148..660ec78 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -172,7 +172,7 @@
{
int ret;
u8 tmp_status;
- unsigned long irqflags;
+ unsigned long uninitialized_var(irqflags);
*status = 0;
@@ -222,7 +222,7 @@
static irqreturn_t hdq_isr(int irq, void *_hdq)
{
struct hdq_data *hdq_data = _hdq;
- unsigned long irqflags;
+ unsigned long uninitialized_var(irqflags);
spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
hdq_data->hdq_irqstatus = hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
@@ -305,7 +305,7 @@
{
int ret = 0;
u8 tmp_status;
- unsigned long irqflags;
+ unsigned long uninitialized_var(irqflags);
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
if (ret < 0) {
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 6d72024..7822309 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -304,10 +304,19 @@
kfree(p);
}
+static int part_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct hd_struct *part = dev_to_part(dev);
+
+ add_uevent_var(env, "PARTN=%u", part->partno);
+ return 0;
+}
+
struct device_type part_type = {
.name = "partition",
.groups = part_attr_groups,
.release = part_release,
+ .uevent = part_uevent,
};
static void delete_partition_rcu_cb(struct rcu_head *head)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 93d926c..54e9cc9 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -258,7 +258,8 @@
if (task->mm != mm)
goto out;
if (task->mm != current->mm &&
- __ptrace_may_access(task, PTRACE_MODE_READ) < 0)
+ __ptrace_may_access(task, PTRACE_MODE_READ) < 0 &&
+ !capable(CAP_SYS_RESOURCE))
goto out;
task_unlock(task);
return mm;
diff --git a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig
index c0e545b..8584450 100644
--- a/fs/yaffs2/Kconfig
+++ b/fs/yaffs2/Kconfig
@@ -154,3 +154,11 @@
but makes look-ups faster.
If unsure, say Y.
+
+config YAFFS_EMPTY_LOST_AND_FOUND
+ bool "Empty lost and found on mount"
+ depends on YAFFS_FS
+ default n
+ help
+ If this is enabled then the contents of lost and found is
+ automatically dumped at mount.
diff --git a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c
index 288b550..7b69a64 100644
--- a/fs/yaffs2/yaffs_checkptrw.c
+++ b/fs/yaffs2/yaffs_checkptrw.c
@@ -43,6 +43,9 @@
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
+
+ dev->nBlockErasures++;
+
if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
dev->nErasedBlocks++;
@@ -127,6 +130,9 @@
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
{
+
+ dev->checkpointOpenForWrite = forWriting;
+
/* Got the functions we need? */
if (!dev->writeChunkWithTagsToNAND ||
!dev->readChunkWithTagsFromNAND ||
@@ -144,9 +150,6 @@
dev->checkpointPageSequence = 0;
-
- dev->checkpointOpenForWrite = forWriting;
-
dev->checkpointByteCount = 0;
dev->checkpointSum = 0;
dev->checkpointXor = 0;
@@ -168,6 +171,9 @@
dev->blocksInCheckpoint = 0;
dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
+ if(!dev->checkpointBlockList)
+ return 0;
+
for (i = 0; i < dev->checkpointMaxBlocks; i++)
dev->checkpointBlockList[i] = -1;
}
@@ -219,6 +225,8 @@
realignedChunk = chunk - dev->chunkOffset;
+ dev->nPageWrites++;
+
dev->writeChunkWithTagsToNAND(dev, realignedChunk,
dev->checkpointBuffer, &tags);
dev->checkpointByteOffset = 0;
@@ -306,6 +314,8 @@
dev->checkpointCurrentChunk;
realignedChunk = chunk - dev->chunkOffset;
+
+ dev->nPageReads++;
/* read in the next chunk */
/* printf("read checkpoint page %d\n",dev->checkpointPage); */
@@ -348,11 +358,14 @@
if (dev->checkpointOpenForWrite) {
if (dev->checkpointByteOffset != 0)
yaffs_CheckpointFlushBuffer(dev);
- } else {
+ } else if(dev->checkpointBlockList){
int i;
for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
- yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
- if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
+ int blk = dev->checkpointBlockList[i];
+ yaffs_BlockInfo *bi = NULL;
+ if( dev->internalStartBlock <= blk && blk <= dev->internalEndBlock)
+ bi = yaffs_GetBlockInfo(dev, blk);
+ if (bi && bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
else {
/* Todo this looks odd... */
@@ -380,15 +393,10 @@
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
{
- /* Erase the first checksum block */
+ /* Erase the checkpoint data */
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));
-
- if (!yaffs_CheckpointSpaceOk(dev))
- return 0;
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
+ dev->blocksInCheckpoint));
return yaffs_CheckpointErase(dev);
}
-
-
-
diff --git a/fs/yaffs2/yaffs_fs.c b/fs/yaffs2/yaffs_fs.c
index 2288eee..4c155ae 100644
--- a/fs/yaffs2/yaffs_fs.c
+++ b/fs/yaffs2/yaffs_fs.c
@@ -163,6 +163,11 @@
#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
#endif
+
+#define update_dir_time(dir) do {\
+ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
+ } while(0)
+
static void yaffs_put_super(struct super_block *sb);
static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
@@ -373,6 +378,122 @@
up(&dev->grossLock);
}
+
+/*-----------------------------------------------------------------*/
+/* Directory search context allows us to unlock access to yaffs during
+ * filldir without causing problems with the directory being modified.
+ * This is similar to the tried and tested mechanism used in yaffs direct.
+ *
+ * A search context iterates along a doubly linked list of siblings in the
+ * directory. If the iterating object is deleted then this would corrupt
+ * the list iteration, likely causing a crash. The search context avoids
+ * this by using the removeObjectCallback to move the search context to the
+ * next object before the object is deleted.
+ *
+ * Many readdirs (and thus seach conexts) may be alive simulateously so
+ * each yaffs_Device has a list of these.
+ *
+ * A seach context lives for the duration of a readdir.
+ *
+ * All these functions must be called while yaffs is locked.
+ */
+
+struct yaffs_SearchContext {
+ yaffs_Device *dev;
+ yaffs_Object *dirObj;
+ yaffs_Object *nextReturn;
+ struct ylist_head others;
+};
+
+/*
+ * yaffs_NewSearch() creates a new search context, initialises it and
+ * adds it to the device's search context list.
+ *
+ * Called at start of readdir.
+ */
+static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_Object *dir)
+{
+ yaffs_Device *dev = dir->myDev;
+ struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
+ if(sc){
+ sc->dirObj = dir;
+ sc->dev = dev;
+ if( ylist_empty(&sc->dirObj->variant.directoryVariant.children))
+ sc->nextReturn = NULL;
+ else
+ sc->nextReturn = ylist_entry(
+ dir->variant.directoryVariant.children.next,
+ yaffs_Object,siblings);
+ YINIT_LIST_HEAD(&sc->others);
+ ylist_add(&sc->others,&dev->searchContexts);
+ }
+ return sc;
+}
+
+/*
+ * yaffs_EndSearch() disposes of a search context and cleans up.
+ */
+static void yaffs_EndSearch(struct yaffs_SearchContext * sc)
+{
+ if(sc){
+ ylist_del(&sc->others);
+ YFREE(sc);
+ }
+}
+
+/*
+ * yaffs_SearchAdvance() moves a search context to the next object.
+ * Called when the search iterates or when an object removal causes
+ * the search context to be moved to the next object.
+ */
+static void yaffs_SearchAdvance(struct yaffs_SearchContext *sc)
+{
+ if(!sc)
+ return;
+
+ if( sc->nextReturn == NULL ||
+ ylist_empty(&sc->dirObj->variant.directoryVariant.children))
+ sc->nextReturn = NULL;
+ else {
+ struct ylist_head *next = sc->nextReturn->siblings.next;
+
+ if( next == &sc->dirObj->variant.directoryVariant.children)
+ sc->nextReturn = NULL; /* end of list */
+ else
+ sc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
+ }
+}
+
+/*
+ * yaffs_RemoveObjectCallback() is called when an object is unlinked.
+ * We check open search contexts and advance any which are currently
+ * on the object being iterated.
+ */
+static void yaffs_RemoveObjectCallback(yaffs_Object *obj)
+{
+
+ struct ylist_head *i;
+ struct yaffs_SearchContext *sc;
+ struct ylist_head *search_contexts = &obj->myDev->searchContexts;
+
+
+ /* Iterate through the directory search contexts.
+ * If any are currently on the object being removed, then advance
+ * the search context to the next object to prevent a hanging pointer.
+ */
+ ylist_for_each(i, search_contexts) {
+ if (i) {
+ sc = ylist_entry(i, struct yaffs_SearchContext,others);
+ if(sc->nextReturn == obj)
+ yaffs_SearchAdvance(sc);
+ }
+ }
+
+}
+
+
+/*-----------------------------------------------------------------*/
+
static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
int buflen)
{
@@ -1075,7 +1196,7 @@
}
yaffs_GrossUnlock(dev);
- return (!nWritten && n) ? -ENOSPC : nWritten;
+ return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
}
/* Space holding and freeing is done to ensure we have space available for write_begin/end */
@@ -1123,10 +1244,11 @@
{
yaffs_Object *obj;
yaffs_Device *dev;
+ struct yaffs_SearchContext *sc;
struct inode *inode = f->f_dentry->d_inode;
unsigned long offset, curoffs;
- struct ylist_head *i;
yaffs_Object *l;
+ int retVal = 0;
char name[YAFFS_MAX_NAME_LENGTH + 1];
@@ -1137,14 +1259,22 @@
offset = f->f_pos;
+ sc = yaffs_NewSearch(obj);
+ if(!sc){
+ retVal = -ENOMEM;
+ goto unlock_out;
+ }
+
T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
if (offset == 0) {
T(YAFFS_TRACE_OS,
("yaffs_readdir: entry . ino %d \n",
(int)inode->i_ino));
+ yaffs_GrossUnlock(dev);
if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
goto out;
+ yaffs_GrossLock(dev);
offset++;
f->f_pos++;
}
@@ -1152,9 +1282,11 @@
T(YAFFS_TRACE_OS,
("yaffs_readdir: entry .. ino %d \n",
(int)f->f_dentry->d_parent->d_inode->i_ino));
+ yaffs_GrossUnlock(dev);
if (filldir(dirent, "..", 2, offset,
f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
goto out;
+ yaffs_GrossLock(dev);
offset++;
f->f_pos++;
}
@@ -1170,10 +1302,12 @@
f->f_version = inode->i_version;
}
- ylist_for_each(i, &obj->variant.directoryVariant.children) {
+ while(sc->nextReturn){
curoffs++;
+ l = sc->nextReturn;
if (curoffs >= offset) {
- l = ylist_entry(i, yaffs_Object, siblings);
+ int this_inode = yaffs_GetObjectInode(l);
+ int this_type = yaffs_GetObjectType(l);
yaffs_GetObjectName(l, name,
YAFFS_MAX_NAME_LENGTH + 1);
@@ -1181,24 +1315,30 @@
("yaffs_readdir: %s inode %d\n", name,
yaffs_GetObjectInode(l)));
+ yaffs_GrossUnlock(dev);
+
if (filldir(dirent,
name,
strlen(name),
offset,
- yaffs_GetObjectInode(l),
- yaffs_GetObjectType(l)) < 0)
- goto up_and_out;
+ this_inode,
+ this_type) < 0)
+ goto out;
+
+ yaffs_GrossLock(dev);
offset++;
f->f_pos++;
}
+ yaffs_SearchAdvance(sc);
}
-up_and_out:
-out:
+unlock_out:
yaffs_GrossUnlock(dev);
+out:
+ yaffs_EndSearch(sc);
- return 0;
+ return retVal;
}
/*
@@ -1286,6 +1426,7 @@
if (obj) {
inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
d_instantiate(dentry, inode);
+ update_dir_time(dir);
T(YAFFS_TRACE_OS,
("yaffs_mknod created object %d count = %d\n",
obj->objectId, atomic_read(&inode->i_count)));
@@ -1339,6 +1480,7 @@
dir->i_version++;
yaffs_GrossUnlock(dev);
mark_inode_dirty(dentry->d_inode);
+ update_dir_time(dir);
return 0;
}
yaffs_GrossUnlock(dev);
@@ -1379,8 +1521,10 @@
yaffs_GrossUnlock(dev);
- if (link)
+ if (link){
+ update_dir_time(dir);
return 0;
+ }
return -EPERM;
}
@@ -1406,6 +1550,7 @@
inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
d_instantiate(dentry, inode);
+ update_dir_time(dir);
T(YAFFS_TRACE_OS, ("symlink created OK\n"));
return 0;
} else {
@@ -1478,7 +1623,10 @@
new_dentry->d_inode->i_nlink--;
mark_inode_dirty(new_dentry->d_inode);
}
-
+
+ update_dir_time(old_dir);
+ if(old_dir != new_dir)
+ update_dir_time(new_dir);
return 0;
} else {
return -ENOTEMPTY;
@@ -1783,6 +1931,8 @@
int skip_checkpoint_read;
int skip_checkpoint_write;
int no_cache;
+ int empty_lost_and_found_overridden;
+ int empty_lost_and_found;
} yaffs_options;
#define MAX_OPT_LEN 20
@@ -1798,6 +1948,9 @@
memset(cur_opt, 0, MAX_OPT_LEN + 1);
p = 0;
+ while (*options_str == ',')
+ options_str++;
+
while (*options_str && *options_str != ',') {
if (p < MAX_OPT_LEN) {
cur_opt[p] = *options_str;
@@ -1817,6 +1970,12 @@
else if (!strcmp(cur_opt, "no-checkpoint")) {
options->skip_checkpoint_read = 1;
options->skip_checkpoint_write = 1;
+ } else if (!strcmp(cur_opt, "empty-lost-and-found-disable")) {
+ options->empty_lost_and_found = 0;
+ options->empty_lost_and_found_overridden = 1;
+ } else if (!strcmp(cur_opt, "empty-lost-and-found-enable")) {
+ options->empty_lost_and_found = 1;
+ options->empty_lost_and_found_overridden = 1;
} else {
printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
cur_opt);
@@ -1922,6 +2081,13 @@
T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
#endif
+
+#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
+ dev->emptyLostAndFound = 1;
+#endif
+ if(options.empty_lost_and_found_overridden)
+ dev->emptyLostAndFound = options.empty_lost_and_found;
+
#ifdef CONFIG_YAFFS_AUTO_YAFFS2
if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
@@ -2084,6 +2250,10 @@
/* we assume this is protected by lock_kernel() in mount/umount */
ylist_add_tail(&dev->devList, &yaffs_dev_list);
+ /* Directory search handling...*/
+ YINIT_LIST_HEAD(&dev->searchContexts);
+ dev->removeObjectCallback = yaffs_RemoveObjectCallback;
+
init_MUTEX(&dev->grossLock);
yaffs_GrossLock(dev);
diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c
index 0de2ad3..968223e 100644
--- a/fs/yaffs2/yaffs_guts.c
+++ b/fs/yaffs2/yaffs_guts.c
@@ -49,6 +49,7 @@
const yaffs_ExtendedTags *tags);
/* Other local prototypes */
+static void yaffs_UpdateParent(yaffs_Object *obj);
static int yaffs_UnlinkObject(yaffs_Object *obj);
static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
@@ -112,7 +113,6 @@
yaffs_FileStructure *fStruct,
__u32 chunkId);
-
/* Function to calculate chunk and offset */
static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
@@ -759,7 +759,7 @@
chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
- chunkIdOk = chunkInRange || obj->hdrChunk == 0;
+ chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
chunkValid = chunkInRange &&
yaffs_CheckChunkBit(dev,
obj->hdrChunk / dev->nChunksPerBlock,
@@ -1544,11 +1544,16 @@
for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
theChunk % dev->nChunksPerBlock)) {
- yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
- tags);
- if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
- /* found it; */
+
+ if(dev->chunkGroupSize == 1)
return theChunk;
+ else {
+ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
+ tags);
+ if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
+ /* found it; */
+ return theChunk;
+ }
}
}
theChunk++;
@@ -2345,6 +2350,7 @@
in = NULL;
}
+ yaffs_UpdateParent(parent);
}
return in;
@@ -2459,6 +2465,8 @@
yaffs_Object *obj = NULL;
yaffs_Object *existingTarget = NULL;
int force = 0;
+ int result;
+ yaffs_Device *dev;
if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
@@ -2466,6 +2474,8 @@
if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
YBUG();
+ dev = oldDir->myDev;
+
#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
/* Special case for case insemsitive systems (eg. WinCE).
* While look-up is case insensitive, the name isn't.
@@ -2475,7 +2485,7 @@
force = 1;
#endif
- else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
+ if(yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
/* ENAMETOOLONG */
return YAFFS_FAIL;
@@ -2493,14 +2503,26 @@
return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
} else if (existingTarget && existingTarget != obj) {
/* Nuke the target first, using shadowing,
- * but only if it isn't the same object
+ * but only if it isn't the same object.
+ *
+ * Note we must disable gc otherwise it can mess up the shadowing.
+ *
*/
+ dev->isDoingGC=1;
yaffs_ChangeObjectName(obj, newDir, newName, force,
existingTarget->objectId);
+ existingTarget->isShadowed = 1;
yaffs_UnlinkObject(existingTarget);
+ dev->isDoingGC=0;
}
- return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+ result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+
+ yaffs_UpdateParent(oldDir);
+ if(newDir != oldDir)
+ yaffs_UpdateParent(newDir);
+
+ return result;
}
return YAFFS_FAIL;
}
@@ -2964,7 +2986,6 @@
isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
- bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
T(YAFFS_TRACE_TRACING,
(TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
@@ -2975,12 +2996,16 @@
/*yaffs_VerifyFreeChunks(dev); */
+ if(bi->blockState == YAFFS_BLOCK_STATE_FULL)
+ bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
+
bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
/* Take off the number of soft deleted entries because
* they're going to get really deleted during GC.
*/
- dev->nFreeChunks -= bi->softDeletions;
+ if(dev->gcChunk == 0) /* first time through for this block */
+ dev->nFreeChunks -= bi->softDeletions;
dev->isDoingGC = 1;
@@ -3096,6 +3121,7 @@
if (tags.chunkId == 0) {
/* It is an object Id,
* We need to nuke the shrinkheader flags first
+ * Also need to clean up shadowing.
* We no longer want the shrinkHeader flag since its work is done
* and if it is left in place it will mess up scanning.
*/
@@ -3104,6 +3130,9 @@
oh = (yaffs_ObjectHeader *)buffer;
oh->isShrink = 0;
tags.extraIsShrinkHeader = 0;
+ oh->shadowsObject = 0;
+ oh->inbandShadowsObject = 0;
+ tags.extraShadows = 0;
yaffs_VerifyObjectHeader(object, oh, &tags, 1);
}
@@ -3624,7 +3653,7 @@
newTags.chunkId = chunkInInode;
newTags.objectId = in->objectId;
newTags.serialNumber =
- (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
+ (prevChunkId > 0) ? prevTags.serialNumber + 1 : 1;
newTags.byteCount = nBytes;
if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
@@ -3640,7 +3669,7 @@
if (newChunkId >= 0) {
yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
- if (prevChunkId >= 0)
+ if (prevChunkId > 0)
yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
yaffs_CheckFileSanity(in);
@@ -3726,7 +3755,7 @@
if (name && *name) {
memset(oh->name, 0, sizeof(oh->name));
yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
- } else if (prevChunkId >= 0)
+ } else if (prevChunkId > 0)
memcpy(oh->name, oldName, sizeof(oh->name));
else
memset(oh->name, 0, sizeof(oh->name));
@@ -3784,13 +3813,13 @@
/* Create new chunk in NAND */
newChunkId =
yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
- (prevChunkId >= 0) ? 1 : 0);
+ (prevChunkId > 0) ? 1 : 0);
if (newChunkId >= 0) {
in->hdrChunk = newChunkId;
- if (prevChunkId >= 0) {
+ if (prevChunkId > 0) {
yaffs_DeleteChunk(dev, prevChunkId, 1,
__LINE__);
}
@@ -5018,11 +5047,13 @@
}
- /* Write a new object header.
+ /* Write a new object header to reflect the resize.
* show we've shrunk the file, if need be
- * Do this only if the file is not in the deleted directories.
+ * Do this only if the file is not in the deleted directories
+ * and is not shadowed.
*/
if (in->parent &&
+ !in->isShadowed &&
in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
in->parent->objectId != YAFFS_OBJECTID_DELETED)
yaffs_UpdateObjectHeader(in, NULL, 0,
@@ -5164,14 +5195,19 @@
}
}
-static int yaffs_DeleteDirectory(yaffs_Object *in)
+static int yaffs_IsNonEmptyDirectory(yaffs_Object *obj)
+{
+ return (obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) &&
+ !(ylist_empty(&obj->variant.directoryVariant.children));
+}
+
+static int yaffs_DeleteDirectory(yaffs_Object *obj)
{
/* First check that the directory is empty. */
- if (ylist_empty(&in->variant.directoryVariant.children))
- return yaffs_DoGenericObjectDeletion(in);
+ if (yaffs_IsNonEmptyDirectory(obj))
+ return YAFFS_FAIL;
- return YAFFS_FAIL;
-
+ return yaffs_DoGenericObjectDeletion(obj);
}
static int yaffs_DeleteSymLink(yaffs_Object *in)
@@ -5230,6 +5266,9 @@
immediateDeletion = 1;
#endif
+ if(obj)
+ yaffs_UpdateParent(obj->parent);
+
if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
return yaffs_DeleteHardLink(obj);
} else if (!ylist_empty(&obj->hardLinks)) {
@@ -5284,7 +5323,9 @@
default:
return YAFFS_FAIL;
}
- } else
+ } else if(yaffs_IsNonEmptyDirectory(obj))
+ return YAFFS_FAIL;
+ else
return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
_Y("unlinked"), 0, 0);
}
@@ -5323,7 +5364,8 @@
/* Handle YAFFS2 case (backward scanning)
* If the shadowed object exists then ignore.
*/
- if (yaffs_FindObjectByNumber(dev, objId))
+ obj = yaffs_FindObjectByNumber(dev, objId);
+ if(obj)
return;
}
@@ -5335,6 +5377,7 @@
YAFFS_OBJECT_TYPE_FILE);
if (!obj)
return;
+ obj->isShadowed = 1;
yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
obj->variant.fileVariant.shrinkSize = 0;
obj->valid = 1; /* So that we don't read any other info for this file */
@@ -5427,6 +5470,125 @@
}
+/*
+ * This code iterates through all the objects making sure that they are rooted.
+ * Any unrooted objects are re-rooted in lost+found.
+ * An object needs to be in one of:
+ * - Directly under deleted, unlinked
+ * - Directly or indirectly under root.
+ *
+ * Note:
+ * This code assumes that we don't ever change the current relationships between
+ * directories:
+ * rootDir->parent == unlinkedDir->parent == deletedDir->parent == NULL
+ * lostNfound->parent == rootDir
+ *
+ * This fixes the problem where directories might have inadvertently been deleted
+ * leaving the object "hanging" without being rooted in the directory tree.
+ */
+
+static int yaffs_HasNULLParent(yaffs_Device *dev, yaffs_Object *obj)
+{
+ return (obj == dev->deletedDir ||
+ obj == dev->unlinkedDir||
+ obj == dev->rootDir);
+}
+
+static void yaffs_FixHangingObjects(yaffs_Device *dev)
+{
+ yaffs_Object *obj;
+ yaffs_Object *parent;
+ int i;
+ struct ylist_head *lh;
+ struct ylist_head *n;
+ int depthLimit;
+ int hanging;
+
+
+ /* Iterate through the objects in each hash entry,
+ * looking at each object.
+ * Make sure it is rooted.
+ */
+
+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+ ylist_for_each_safe(lh, n, &dev->objectBucket[i].list) {
+ if (lh) {
+ obj = ylist_entry(lh, yaffs_Object, hashLink);
+ parent= obj->parent;
+
+ if(yaffs_HasNULLParent(dev,obj)){
+ /* These directories are not hanging */
+ hanging = 0;
+ }
+ else if(!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ hanging = 1;
+ else if(yaffs_HasNULLParent(dev,parent))
+ hanging = 0;
+ else {
+ /*
+ * Need to follow the parent chain to see if it is hanging.
+ */
+ hanging = 0;
+ depthLimit=100;
+
+ while(parent != dev->rootDir &&
+ parent->parent &&
+ parent->parent->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+ depthLimit > 0){
+ parent = parent->parent;
+ depthLimit--;
+ }
+ if(parent != dev->rootDir)
+ hanging = 1;
+ }
+ if(hanging){
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("Hanging object %d moved to lost and found" TENDSTR),
+ obj->objectId));
+ yaffs_AddObjectToDirectory(dev->lostNFoundDir,obj);
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * Delete directory contents for cleaning up lost and found.
+ */
+static void yaffs_DeleteDirectoryContents(yaffs_Object *dir)
+{
+ yaffs_Object *obj;
+ struct ylist_head *lh;
+ struct ylist_head *n;
+
+ if(dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ YBUG();
+
+ ylist_for_each_safe(lh, n, &dir->variant.directoryVariant.children) {
+ if (lh) {
+ obj = ylist_entry(lh, yaffs_Object, siblings);
+ if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
+ yaffs_DeleteDirectoryContents(obj);
+
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("Deleting lost_found object %d" TENDSTR),
+ obj->objectId));
+
+ /* Need to use UnlinkObject since Delete would not handle
+ * hardlinked objects correctly.
+ */
+ yaffs_UnlinkObject(obj);
+ }
+ }
+
+}
+
+static void yaffs_EmptyLostAndFound(yaffs_Device *dev)
+{
+ yaffs_DeleteDirectoryContents(dev->lostNFoundDir);
+}
+
static int yaffs_Scan(yaffs_Device *dev)
{
yaffs_ExtendedTags tags;
@@ -6666,6 +6828,26 @@
}
}
+/*
+ *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new
+ * link (ie. name) is created or deleted in the directory.
+ *
+ * ie.
+ * create dir/a : update dir's mtime/ctime
+ * rm dir/a: update dir's mtime/ctime
+ * modify dir/a: don't update dir's mtimme/ctime
+ */
+
+static void yaffs_UpdateParent(yaffs_Object *obj)
+{
+ if(!obj)
+ return;
+
+ obj->dirty = 1;
+ obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
+
+ yaffs_UpdateObjectHeader(obj,NULL,0,0,0);
+}
static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
{
@@ -6683,11 +6865,10 @@
ylist_del_init(&obj->siblings);
obj->parent = NULL;
-
+
yaffs_VerifyDirectory(parent);
}
-
static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
yaffs_Object *obj)
{
@@ -6781,7 +6962,7 @@
* Do a real check
*/
yaffs_GetObjectName(l, buffer,
- YAFFS_MAX_NAME_LENGTH);
+ YAFFS_MAX_NAME_LENGTH + 1);
if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
return l;
}
@@ -7030,7 +7211,7 @@
{
YCHAR name[257];
- yaffs_GetObjectName(obj, name, 256);
+ yaffs_GetObjectName(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
T(YAFFS_TRACE_ALWAYS,
(TSTR
@@ -7371,6 +7552,9 @@
init_failed = 1;
yaffs_StripDeletedObjects(dev);
+ yaffs_FixHangingObjects(dev);
+ if(dev->emptyLostAndFound)
+ yaffs_EmptyLostAndFound(dev);
}
if (init_failed) {
@@ -7394,6 +7578,9 @@
yaffs_VerifyFreeChunks(dev);
yaffs_VerifyBlocks(dev);
+ /* Clean up any aborted checkpoint data */
+ if (!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
+ yaffs_InvalidateCheckpoint(dev);
T(YAFFS_TRACE_TRACING,
(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h
index a3b1102..1305909 100644
--- a/fs/yaffs2/yaffs_guts.h
+++ b/fs/yaffs2/yaffs_guts.h
@@ -424,6 +424,7 @@
* until the inode is released.
*/
__u8 beingCreated:1; /* This object is still being created so skip some checks. */
+ __u8 isShadowed:1; /* This object is shadowed on the way to being renamed. */
__u8 serial; /* serial number of chunk in NAND. Cached here */
__u16 sum; /* sum of the name to speed searching */
@@ -557,6 +558,8 @@
int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
+ int emptyLostAndFound; /* Flasg to determine if lst+found should be emptied on init */
+
int useNANDECC; /* Flag to decide whether or not to use NANDECC */
void *genericDevice; /* Pointer to device context
@@ -592,8 +595,9 @@
int isYaffs2;
/* The removeObjectCallback function must be supplied by OS flavours that
- * need it. The Linux kernel does not use this, but yaffs direct does use
- * it to implement the faster readdir
+ * need it.
+ * yaffs direct uses it to implement the faster readdir.
+ * Linux uses it to protect the directory during unlocking.
*/
void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
@@ -633,10 +637,14 @@
struct semaphore sem; /* Semaphore for waiting on erasure.*/
struct semaphore grossLock; /* Gross locking semaphore */
+ struct rw_semaphore dirLock; /* Lock the directory structure */
__u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
* at compile time so we have to allocate it.
+
*/
void (*putSuperFunc) (struct super_block *sb);
+ struct ylist_head searchContexts;
+
#endif
int isMounted;
diff --git a/fs/yaffs2/yaffs_mtdif1.c b/fs/yaffs2/yaffs_mtdif1.c
index 1d9311a..bcac470 100644
--- a/fs/yaffs2/yaffs_mtdif1.c
+++ b/fs/yaffs2/yaffs_mtdif1.c
@@ -102,8 +102,6 @@
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
compile_time_assertion(sizeof(yaffs_Tags) == 8);
- dev->nPageWrites++;
-
yaffs_PackTags1(&pt1, etags);
yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
@@ -180,8 +178,6 @@
int retval;
int deleted;
- dev->nPageReads++;
-
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
diff --git a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c
index bd8128c..282a093 100644
--- a/fs/yaffs2/yaffs_mtdif2.c
+++ b/fs/yaffs2/yaffs_mtdif2.c
@@ -52,8 +52,6 @@
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
- dev->nPageWrites++;
-
addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
/* For yaffs2 writing there must be both data and tags.
@@ -116,8 +114,6 @@
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
- dev->nPageReads++;
-
if (dev->inbandTags) {
if (!data) {
diff --git a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c
index ec32761..f6ba4c79 100644
--- a/fs/yaffs2/yaffs_nand.c
+++ b/fs/yaffs2/yaffs_nand.c
@@ -29,6 +29,8 @@
int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
+ dev->nPageReads++;
+
/* If there are no tags provided, use local tags to get prioritised gc working */
if (!tags)
tags = &localTags;
@@ -56,6 +58,9 @@
const __u8 *buffer,
yaffs_ExtendedTags *tags)
{
+
+ dev->nPageWrites++;
+
chunkInNAND -= dev->chunkOffset;
@@ -89,7 +94,7 @@
{
blockNo -= dev->blockOffset;
-;
+
if (dev->markNANDBlockBad)
return dev->markNANDBlockBad(dev, blockNo);
else
@@ -119,8 +124,8 @@
blockInNAND -= dev->blockOffset;
-
dev->nBlockErasures++;
+
result = dev->eraseBlockInNAND(dev, blockInNAND);
return result;
diff --git a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c
index 402537fb..e3173cc 100644
--- a/fs/yaffs2/yaffs_tagscompat.c
+++ b/fs/yaffs2/yaffs_tagscompat.c
@@ -170,7 +170,6 @@
return YAFFS_FAIL;
}
- dev->nPageWrites++;
return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
}
@@ -184,8 +183,6 @@
int retVal;
yaffs_Spare localSpare;
- dev->nPageReads++;
-
if (!spare && data) {
/* If we don't have a real spare, then we use a local one. */
/* Need this for the calculation of the ecc */
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 1610427..83fcfa7 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -252,6 +252,11 @@
void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state);
+#ifdef CONFIG_CPU_FREQ_STAT
+extern void cpufreq_exit_idle(int cpu, unsigned long ticks);
+#else
+#define cpufreq_exit_idle(int cpu, unsigned long ticks) do {} while (0)
+#endif
static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max)
{
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index dcf77fa..3650f32 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -17,7 +17,7 @@
#include <linux/kobject.h>
#include <linux/completion.h>
-#define CPUIDLE_STATE_MAX 8
+#define CPUIDLE_STATE_MAX 16
#define CPUIDLE_NAME_LEN 16
#define CPUIDLE_DESC_LEN 32
@@ -88,6 +88,7 @@
int last_residency;
int state_count;
+ int max_state;
struct cpuidle_state states[CPUIDLE_STATE_MAX];
struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
struct cpuidle_state *last_state;
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index 96c1c38..8e906b7 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -152,6 +152,20 @@
/*----------------------------------------------------------------------*/
+/* Iterface Bit Register (INTBR) offsets
+ * (use TWL4030_MODULE_INTBR)
+ */
+
+#define REG_GPPUPDCTR1 0x0F
+
+/* I2C1 and I2C4(SR) SDA/SCL pull-up control bits */
+
+#define I2C_SCL_CTRL_PU (1 << 0)
+#define I2C_SDA_CTRL_PU (1 << 2)
+#define SR_I2C_SCL_CTRL_PU (1 << 4)
+#define SR_I2C_SDA_CTRL_PU (1 << 6)
+/*----------------------------------------------------------------------*/
+
/*
* Keypad register offsets (use TWL4030_MODULE_KEYPAD)
* ... SIH/interrupt only
@@ -387,6 +401,8 @@
const struct twl4030_resconfig *resource_config;
};
+extern int twl4030_remove_script(u8 flags);
+
struct twl4030_platform_data {
unsigned irq_base, irq_end;
struct twl4030_bci_platform_data *bci;
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index 179d674..9786aa7 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -150,12 +150,15 @@
__u32 remote;
__u16 sequence;
__u8 sequencing;
+ int (*backlog_rcv)(struct sock *sk_udp, struct sk_buff *skb);
};
struct pppopns_opt {
__u16 local;
__u16 remote;
__u32 sequence;
+ void (*data_ready)(struct sock *sk_raw, int length);
+ int (*backlog_rcv)(struct sock *sk_raw, struct sk_buff *skb);
};
#include <net/sock.h>
diff --git a/include/linux/omap_resizer.h b/include/linux/omap_resizer.h
index 5ac0c88..0ae129c 100644
--- a/include/linux/omap_resizer.h
+++ b/include/linux/omap_resizer.h
@@ -48,6 +48,7 @@
*/
};
+typedef void (*rsz_callback) (void *arg1);
/* Structure Definitions */
/* used to luma enhancement options */
@@ -134,3 +135,11 @@
};
#endif
+
+int rsz_get_resource(void);
+void rsz_put_resource(void);
+int rsz_configure(struct rsz_params *params, rsz_callback callback,
+ u32 num_video_buffers, void *arg1);
+int rsz_begin(u32 input_buffer_index,
+ int output_buffer_index, u32 out_off, u32 out_phy_add,
+ u32 in_phy_add, u32 in_off);
diff --git a/include/linux/sil9022.h b/include/linux/sil9022.h
index 439ebee..8543fca 100644
--- a/include/linux/sil9022.h
+++ b/include/linux/sil9022.h
@@ -22,6 +22,7 @@
#define HDMI_XRES 1280
#define HDMI_YRES 720
#define HDMI_PIXCLOCK_MAX 74250
+#define VERTICAL_FREQ 0x3C
#define I2C_M_WR 0
@@ -104,6 +105,12 @@
/* --------------------------------------------------------------------- */
+#define EDID_TIMING_DESCRIPTOR_SIZE 0x12
+#define EDID_DESCRIPTOR_BLOCK0_ADDRESS 0x36
+#define EDID_DESCRIPTOR_BLOCK1_ADDRESS 0x80
+#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4
+#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4
+
/* HDMI Connected States */
#define HDMI_STATE_NOMONITOR 0 /* No HDMI monitor connected*/
#define HDMI_STATE_CONNECTED 1 /* HDMI monitor connected but powered off*/
@@ -698,5 +705,10 @@
u8 value;
} hdmi_reg_data;
+struct hdmi_platform_data {
+ void (*set_min_bus_tput)(struct device *dev,
+ u8 agent_id,
+ unsigned long r);
+};
#endif
diff --git a/include/linux/tty.h b/include/linux/tty.h
index fc39db9..a52c3d0 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -23,7 +23,7 @@
*/
#define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */
#define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */
-#define NR_LDISCS 19
+#define NR_LDISCS 20
/* line disciplines */
#define N_TTY 0
@@ -46,6 +46,7 @@
#define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */
#define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */
#define N_PPS 18 /* Pulse per Second */
+#define N_SHARED 19 /* for TI BT/FM/GPS combo devices*/
/*
* This character is the same as _POSIX_VDISABLE: it cannot be used as
@@ -187,7 +188,7 @@
int (*carrier_raised)(struct tty_port *port);
void (*raise_dtr_rts)(struct tty_port *port);
};
-
+
struct tty_port {
struct tty_struct *tty; /* Back pointer */
const struct tty_port_operations *ops; /* Port operations */
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 935c380..2399007 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -100,6 +100,7 @@
struct usb_descriptor_header **hs_descriptors;
struct usb_configuration *config;
+ int hidden;
/* REVISIT: bind() functions can be marked __init, which
* makes trouble for section mismatch analysis. See if
diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h
index d6aad0e..f94f1d7 100644
--- a/include/linux/usb/musb.h
+++ b/include/linux/usb/musb.h
@@ -81,6 +81,12 @@
/* MUSB configuration-specific details */
struct musb_hdrc_config *config;
+
+ /* MUSB power domain context lost counter */
+ unsigned (*context_loss_counter) (struct device *dev);
+
+ /* MUSB vdd1 opp constraint */
+ void (*set_vdd1_opp) (struct device *dev, unsigned long);
};
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 94df4fe..c3d5c26 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -75,6 +75,18 @@
/* start or continue HNP role switch */
int (*start_hnp)(struct otg_transceiver *otg);
+ /* ask the link to save internal context */
+ void (*link_save_context)(struct otg_transceiver *otg);
+
+ /* ask the link to restore internal context */
+ void (*link_restore_context)(struct otg_transceiver *otg);
+
+ /* ask the link to always be in an active state */
+ void (*link_force_active)(int enable);
+
+ /* pointer to the link driver */
+ void *link;
+
};
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index a25dc7c..b3a70b0 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -323,6 +323,9 @@
* xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb...
*/
#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0')
+#define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0')
+#define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '0')
+#define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0')
/* 10bit raw bayer DPCM compressed to 8 bits */
#define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0')
#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16 BGBG.. GRGR.. */
@@ -798,6 +801,7 @@
#define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */
#define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */
#define V4L2_CTRL_CLASS_CAMERA 0x009a0000 /* Camera class controls */
+#define V4L2_CTRL_CLASS_MODE 0x009b0000 /* Sensor mode information */
#define V4L2_CTRL_ID_MASK (0x0fffffff)
#define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL)
@@ -1135,6 +1139,37 @@
#define V4L2_CID_PRIVACY (V4L2_CID_CAMERA_CLASS_BASE+16)
+/* Flash and privacy (indicator) light controls */
+#define V4L2_CID_FLASH_STROBE (V4L2_CID_CAMERA_CLASS_BASE+13)
+#define V4L2_CID_FLASH_TIMEOUT (V4L2_CID_CAMERA_CLASS_BASE+14)
+#define V4L2_CID_FLASH_INTENSITY (V4L2_CID_CAMERA_CLASS_BASE+15)
+#define V4L2_CID_TORCH_INTENSITY (V4L2_CID_CAMERA_CLASS_BASE+16)
+#define V4L2_CID_INDICATOR_INTENSITY (V4L2_CID_CAMERA_CLASS_BASE+17)
+
+#define V4L2_CID_TEST_PATTERN (V4L2_CTRL_CLASS_CAMERA | 0x107e)
+
+/* SMIA-type sensor information */
+#define V4L2_CID_MODE_CLASS_BASE (V4L2_CTRL_CLASS_MODE | 0x900)
+#define V4L2_CID_MODE_CLASS (V4L2_CTRL_CLASS_MODE | 1)
+#define V4L2_CID_MODE_FRAME_WIDTH (V4L2_CID_MODE_CLASS_BASE+1)
+#define V4L2_CID_MODE_FRAME_HEIGHT (V4L2_CID_MODE_CLASS_BASE+2)
+#define V4L2_CID_MODE_VISIBLE_WIDTH (V4L2_CID_MODE_CLASS_BASE+3)
+#define V4L2_CID_MODE_VISIBLE_HEIGHT (V4L2_CID_MODE_CLASS_BASE+4)
+#define V4L2_CID_MODE_PIXELCLOCK (V4L2_CID_MODE_CLASS_BASE+5)
+#define V4L2_CID_MODE_SENSITIVITY (V4L2_CID_MODE_CLASS_BASE+6)
+
+/* Control IDs specific to the AD5820 driver as defined by V4L2 */
+#define V4L2_CID_FOCUS_AD5820_BASE (V4L2_CTRL_CLASS_CAMERA | 0x10af)
+#define V4L2_CID_FOCUS_AD5820_RAMP_TIME (V4L2_CID_FOCUS_AD5820_BASE+0)
+#define V4L2_CID_FOCUS_AD5820_RAMP_MODE (V4L2_CID_FOCUS_AD5820_BASE+1)
+
+/* Control IDs specific to the ADP1653 flash driver as defined by V4L2 */
+#define V4L2_CID_FLASH_ADP1653_BASE (V4L2_CTRL_CLASS_CAMERA | 0x10f1)
+#define V4L2_CID_FLASH_ADP1653_FAULT_SCP (V4L2_CID_FLASH_ADP1653_BASE+0)
+#define V4L2_CID_FLASH_ADP1653_FAULT_OT (V4L2_CID_FLASH_ADP1653_BASE+1)
+#define V4L2_CID_FLASH_ADP1653_FAULT_TMR (V4L2_CID_FLASH_ADP1653_BASE+2)
+#define V4L2_CID_FLASH_ADP1653_FAULT_OV (V4L2_CID_FLASH_ADP1653_BASE+3)
+
/*
* T U N I N G
*/
@@ -1377,6 +1412,27 @@
};
/*
+ * E V E N T S
+ */
+
+struct v4l2_event {
+ __u32 count;
+ __u32 type;
+ __u32 sequence;
+ struct timespec timestamp;
+ __u32 reserved[9];
+ __u8 data[64];
+};
+
+struct v4l2_event_subscription {
+ __u32 type;
+ __u32 reserved[7];
+};
+
+#define V4L2_EVENT_ALL 0
+#define V4L2_EVENT_PRIVATE_START 0x08000000
+
+/*
* A D V A N C E D D E B U G G I N G
*
* NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS!
@@ -1502,6 +1558,9 @@
#endif
#define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek)
+#define VIDIOC_DQEVENT _IOR('V', 83, struct v4l2_event)
+#define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 84, struct v4l2_event_subscription)
+#define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 85, struct v4l2_event_subscription)
/* Reminder: when adding new ioctls please add support for them to
drivers/media/video/v4l2-compat-ioctl32.c as well! */
diff --git a/include/linux/wl127x-rfkill.h b/include/linux/wl127x-rfkill.h
index 4fad20a..1edec15 100644
--- a/include/linux/wl127x-rfkill.h
+++ b/include/linux/wl127x-rfkill.h
@@ -26,11 +26,10 @@
#include <linux/rfkill.h>
-enum wl127x_devices {
- WL127X_BLUETOOTH = 0,
- WL127X_FM,
- WL127X_MAX_DEV,
-};
+/* wl127x devices */
+#define WL127X_BLUETOOTH 0
+#define WL127X_FM 1
+#define WL127X_MAX_DEV 2
/* Set bt_nshutdown_gpio or fm_enable_gpio to -1 to disable the corresponding
* rfkill driver */
diff --git a/include/media/imx046.h b/include/media/imx046.h
index ecca6fb..7565488 100644
--- a/include/media/imx046.h
+++ b/include/media/imx046.h
@@ -28,17 +28,17 @@
* @priv_data_set: device private data (pointer) access function
*/
struct imx046_platform_data {
- int (*power_set)(struct device*, enum v4l2_power power);
+ int (*power_set)(struct v4l2_int_device *s, enum v4l2_power power);
int (*ifparm)(struct v4l2_ifparm *p);
- int (*priv_data_set)(void *);
- u32 (*set_xclk)(u32 xclk, u8 xclksel);
+ int (*priv_data_set)(struct v4l2_int_device *s, void *);
+ u32 (*set_xclk)(struct v4l2_int_device *s, u32 xclkfreq);
int (*cfg_interface_bridge)(u32);
- int (*csi2_lane_count)(int count);
- int (*csi2_cfg_vp_out_ctrl)(u8 vp_out_ctrl);
- int (*csi2_ctrl_update)(bool);
- int (*csi2_cfg_virtual_id)(u8 ctx, u8 id);
- int (*csi2_ctx_update)(u8 ctx, bool);
- int (*csi2_calc_phy_cfg0)(u32, u32, u32);
+ int (*csi2_lane_count)(struct v4l2_int_device *s, int count);
+ int (*csi2_cfg_vp_out_ctrl)(struct v4l2_int_device *s, u8 vp_out_ctrl);
+ int (*csi2_ctrl_update)(struct v4l2_int_device *s, bool);
+ int (*csi2_cfg_virtual_id)(struct v4l2_int_device *s, u8 ctx, u8 id);
+ int (*csi2_ctx_update)(struct v4l2_int_device *s, u8 ctx, bool);
+ int (*csi2_calc_phy_cfg0)(struct v4l2_int_device *s, u32, u32, u32);
};
#endif /* ifndef IMX046_H */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index e36faab..325c578 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -16,6 +16,8 @@
#include <linux/mutex.h>
#include <linux/videodev2.h>
+#include <media/v4l2-fh.h>
+
#define VIDEO_MAJOR 81
#define VFL_TYPE_GRABBER 0
@@ -75,6 +77,8 @@
/* attribute to differentiate multiple indices on one physical device */
int index;
+ spinlock_t fh_lock; /* Lock for file handle list */
+ struct list_head fh; /* File handle list */
int debug; /* Activates debug level*/
/* Video standard vars */
diff --git a/include/media/v4l2-event.h b/include/media/v4l2-event.h
new file mode 100644
index 0000000..694ffa8
--- /dev/null
+++ b/include/media/v4l2-event.h
@@ -0,0 +1,75 @@
+/*
+ * include/media/v4l2-event.h
+ *
+ * V4L2 events.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus at maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef V4L2_EVENT_H
+#define V4L2_EVENT_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <asm/atomic.h>
+
+#define V4L2_MAX_EVENTS 1024 /* Ought to be enough for everyone. */
+
+struct video_device;
+
+struct _v4l2_event {
+ struct list_head list;
+ struct v4l2_event event;
+};
+
+struct v4l2_events {
+ spinlock_t lock; /* Protect everything here. */
+ struct list_head available;
+ atomic_t navailable;
+ u32 sequence;
+ wait_queue_head_t wait;
+ struct list_head subscribed; /* Subscribed events. */
+};
+
+struct v4l2_subscribed_event {
+ struct list_head list;
+ u32 type;
+};
+
+int v4l2_event_init(void);
+void v4l2_event_exit(void);
+
+void v4l2_event_init_fh(struct v4l2_events *events);
+void v4l2_event_del(struct v4l2_events *events);
+
+int v4l2_event_dequeue(struct v4l2_events *events, struct v4l2_event *event);
+
+struct v4l2_subscribed_event *v4l2_event_subscribed(struct v4l2_events *sub,
+ u32 type);
+
+void v4l2_event_queue(struct video_device *vdev, struct v4l2_event *ev);
+int v4l2_event_pending(struct v4l2_events *events);
+
+int v4l2_event_subscribe(struct v4l2_events *sub,
+ struct v4l2_event_subscription *s);
+int v4l2_event_unsubscribe(struct v4l2_events *sub,
+ struct v4l2_event_subscription *s);
+
+#endif /* V4L2_EVENT_H */
diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h
new file mode 100644
index 0000000..361422b
--- /dev/null
+++ b/include/media/v4l2-fh.h
@@ -0,0 +1,45 @@
+/*
+ * include/media/v4l2-fh.h
+ *
+ * V4L2 file handle.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus at maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef V4L2_FH_H
+#define V4L2_FH_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+#include <media/v4l2-event.h>
+
+struct v4l2_fh {
+ struct list_head list;
+ struct v4l2_events events; /* events, pending and subscribed */
+};
+
+struct video_device;
+
+int v4l2_fh_add(struct video_device *vdev, struct v4l2_fh *fh);
+void v4l2_fh_del(struct video_device *vdev, struct v4l2_fh *fh);
+int v4l2_fh_init(struct video_device *vdev);
+void v4l2_fh_exit(struct video_device *vdev);
+
+#endif /* V4L2_EVENT_H */
diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h
index 2830ae1..158c07c 100644
--- a/include/media/v4l2-int-device.h
+++ b/include/media/v4l2-int-device.h
@@ -232,6 +232,14 @@
*
*/
vidioc_int_priv_start_num = 2000,
+ /* VIDIOC_INT_PRIV_G_PIXCLK */
+ vidioc_int_priv_g_pixclk_num,
+ /* VIDIOC_INT_PRIV_G_ACTIVESIZE */
+ vidioc_int_priv_g_activesize_num,
+ /* VIDIOC_INT_PRIV_G_FULLSIZE */
+ vidioc_int_priv_g_fullsize_num,
+ /* VIDIOC_INT_PRIV_G_PIXELSIZE */
+ vidioc_int_priv_g_pixelsize_num,
};
/*
@@ -310,4 +318,8 @@
V4L2_INT_WRAPPER_0(init);
V4L2_INT_WRAPPER_1(g_chip_ident, int, *);
+V4L2_INT_WRAPPER_1(priv_g_pixclk, u32, *);
+V4L2_INT_WRAPPER_1(priv_g_activesize, struct v4l2_rect, *);
+V4L2_INT_WRAPPER_1(priv_g_fullsize, struct v4l2_rect, *);
+V4L2_INT_WRAPPER_1(priv_g_pixelsize, struct v4l2_rect, *);
#endif
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index b01c044..df8a7aa 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -20,6 +20,8 @@
#include <linux/videodev2.h>
#endif
+struct v4l2_fh;
+
struct v4l2_ioctl_ops {
/* ioctl callbacks */
@@ -238,6 +240,13 @@
int (*vidioc_enum_frameintervals) (struct file *file, void *fh,
struct v4l2_frmivalenum *fival);
+ int (*vidioc_dqevent) (struct v4l2_fh *fh,
+ struct v4l2_event *ev);
+ int (*vidioc_subscribe_event) (struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub);
+ int (*vidioc_unsubscribe_event) (struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub);
+
/* For other private ioctls */
long (*vidioc_default) (struct file *file, void *fh,
int cmd, void *arg);
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 01f9316..ed16efba 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -180,7 +180,8 @@
struct timer_list disc_timer;
struct timer_list idle_timer;
- struct work_struct work;
+ struct work_struct work_add;
+ struct work_struct work_del;
struct device dev;
@@ -350,7 +351,7 @@
if (conn->state == BT_CONNECTED) {
timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
if (!conn->out)
- timeo *= 5;
+ timeo *= 20;
} else
timeo = msecs_to_jiffies(10);
} else
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 24247f7..26c7bab 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -30,6 +30,7 @@
#define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM LRC */
#define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM LRC */
#define SND_SOC_DAIFMT_AC97 5 /* AC97 */
+#define SND_SOC_DAIFMT_I2S_1PHASE 6 /* I2S Single phase mode */
/* left and right justified also known as MSB and LSB respectively */
#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
diff --git a/kernel/module.c b/kernel/module.c
index 1196f5d..1278729 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2288,9 +2288,9 @@
ftrace_release(mod->module_core, mod->core_size);
free_unload:
module_unload_free(mod);
- free_init:
#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
percpu_modfree(mod->refptr);
+ free_init:
#endif
module_free(mod, mod->module_init);
free_core:
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index acbb06d..58548f7 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -225,7 +225,6 @@
/* Caller must acquire the list_lock spinlock */
static void print_active_locks(int type)
{
- unsigned long irqflags;
struct wake_lock *lock;
BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
diff --git a/kernel/printk.c b/kernel/printk.c
index ce492a7..0353ca4 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -44,10 +44,6 @@
#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
-#ifdef CONFIG_DEBUG_LL
-extern void printascii(char *);
-#endif
-
/* printk's without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
@@ -244,6 +240,14 @@
}
/*
+ * Clears the ring-buffer
+ */
+void log_buf_clear(void)
+{
+ logged_chars = 0;
+}
+
+/*
* Copy a range of characters from the log buffer.
*/
int log_buf_copy(char *dest, int idx, int len)
@@ -710,10 +714,6 @@
printed_len += vscnprintf(printk_buf + printed_len,
sizeof(printk_buf) - printed_len, fmt, args);
-#ifdef CONFIG_DEBUG_LL
- printascii(printk_buf);
-#endif
-
/*
* Copy the output into log_buf. If the caller didn't provide
* appropriate log level tags, we insert them here
diff --git a/kernel/sched.c b/kernel/sched.c
index f1e8560..781cf8b 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -53,6 +53,7 @@
#include <linux/rcupdate.h>
#include <linux/cpu.h>
#include <linux/cpuset.h>
+#include <linux/cpufreq.h>
#include <linux/percpu.h>
#include <linux/kthread.h>
#include <linux/proc_fs.h>
@@ -4362,6 +4363,7 @@
*/
void account_idle_ticks(unsigned long ticks)
{
+ cpufreq_exit_idle(smp_processor_id(), ticks);
account_idle_time(jiffies_to_cputime(ticks));
}
@@ -5979,7 +5981,7 @@
unsigned state;
state = p->state ? __ffs(p->state) + 1 : 0;
- printk(KERN_INFO "%-13.13s %c", p->comm,
+ printk(KERN_INFO "%-15.15s %c", p->comm,
state < sizeof(stat_nam) - 1 ? stat_nam[state] : '?');
#if BITS_PER_LONG == 32
if (state == TASK_RUNNING)
diff --git a/lib/genalloc.c b/lib/genalloc.c
index f6d276d..eed2bdb 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -85,7 +85,6 @@
int bit, end_bit;
- write_lock(&pool->lock);
list_for_each_safe(_chunk, _next_chunk, &pool->chunks) {
chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
list_del(&chunk->next_chunk);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 1181db0..e082b89 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -213,6 +213,7 @@
conn->type = type;
conn->mode = HCI_CM_ACTIVE;
conn->state = BT_OPEN;
+ conn->auth_type = HCI_AT_GENERAL_BONDING;
conn->power_save = 1;
@@ -371,6 +372,9 @@
if (acl->state == BT_CONNECTED &&
(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
+ acl->power_save = 1;
+ hci_conn_enter_active_mode(acl);
+
if (lmp_esco_capable(hdev))
hci_setup_sync(sco, acl->handle);
else
@@ -424,12 +428,9 @@
if (sec_level == BT_SECURITY_SDP)
return 1;
- if (sec_level == BT_SECURITY_LOW) {
- if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0)
- return hci_conn_auth(conn, sec_level, auth_type);
- else
- return 1;
- }
+ 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);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index c479592..ffdd6aa 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1647,7 +1647,8 @@
}
if (conn->out && (ev->status == 0x1a || ev->status == 0x1c ||
- ev->status == 0x1f) && conn->attempt < 2) {
+ ev->status == 0x1f || ev->status == 0x10) &&
+ conn->attempt < 2) {
conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
(hdev->esco_type & EDR_ESCO_MASK);
hci_setup_sync(conn, conn->link->handle);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 1a1f916..338686e 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -9,8 +9,7 @@
struct class *bt_class = NULL;
EXPORT_SYMBOL_GPL(bt_class);
-static struct workqueue_struct *btaddconn;
-static struct workqueue_struct *btdelconn;
+static struct workqueue_struct *bluetooth;
static inline char *link_typetostr(int type)
{
@@ -88,9 +87,10 @@
static void add_conn(struct work_struct *work)
{
- struct hci_conn *conn = container_of(work, struct hci_conn, work);
+ struct hci_conn *conn = container_of(work, struct hci_conn, work_add);
- flush_workqueue(btdelconn);
+ /* ensure previous add/del is complete */
+ flush_workqueue(bluetooth);
if (device_add(&conn->dev) < 0) {
BT_ERR("Failed to register connection device");
@@ -114,9 +114,9 @@
device_initialize(&conn->dev);
- INIT_WORK(&conn->work, add_conn);
+ INIT_WORK(&conn->work_add, add_conn);
- queue_work(btaddconn, &conn->work);
+ queue_work(bluetooth, &conn->work_add);
}
/*
@@ -131,9 +131,12 @@
static void del_conn(struct work_struct *work)
{
- struct hci_conn *conn = container_of(work, struct hci_conn, work);
+ struct hci_conn *conn = container_of(work, struct hci_conn, work_del);
struct hci_dev *hdev = conn->hdev;
+ /* ensure previous add/del is complete */
+ flush_workqueue(bluetooth);
+
while (1) {
struct device *dev;
@@ -156,9 +159,9 @@
if (!device_is_registered(&conn->dev))
return;
- INIT_WORK(&conn->work, del_conn);
+ INIT_WORK(&conn->work_del, del_conn);
- queue_work(btdelconn, &conn->work);
+ queue_work(bluetooth, &conn->work_del);
}
static inline char *host_typetostr(int type)
@@ -435,20 +438,13 @@
int __init bt_sysfs_init(void)
{
- btaddconn = create_singlethread_workqueue("btaddconn");
- if (!btaddconn)
+ bluetooth = create_singlethread_workqueue("bluetooth");
+ if (!bluetooth)
return -ENOMEM;
- btdelconn = create_singlethread_workqueue("btdelconn");
- if (!btdelconn) {
- destroy_workqueue(btaddconn);
- return -ENOMEM;
- }
-
bt_class = class_create(THIS_MODULE, "bluetooth");
if (IS_ERR(bt_class)) {
- destroy_workqueue(btdelconn);
- destroy_workqueue(btaddconn);
+ destroy_workqueue(bluetooth);
return PTR_ERR(bt_class);
}
@@ -457,8 +453,7 @@
void bt_sysfs_cleanup(void)
{
- destroy_workqueue(btaddconn);
- destroy_workqueue(btdelconn);
+ destroy_workqueue(bluetooth);
class_destroy(bt_class);
}
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index c109a3a..0b20f99 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1112,7 +1112,8 @@
break;
case BT_DISCONN:
- rfcomm_session_put(s);
+ if (s->sock->sk->sk_state != BT_CLOSED)
+ rfcomm_session_put(s);
break;
}
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index b04e5ad..9fd7221 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1877,10 +1877,19 @@
if (sock_flag(sk, SOCK_DEAD))
continue;
+ sock_hold(sk);
+ spin_unlock_bh(lock);
+
+ local_bh_disable();
+ bh_lock_sock(sk);
sk->sk_err = ETIMEDOUT;
sk->sk_error_report(sk);
- spin_unlock_bh(lock);
+
tcp_done(sk);
+ bh_unlock_sock(sk);
+ local_bh_enable();
+ sock_put(sk);
+
goto restart;
}
spin_unlock_bh(lock);
@@ -2496,4 +2505,3 @@
EXPORT_SYMBOL(tcp_proc_unregister);
#endif
EXPORT_SYMBOL(sysctl_tcp_low_latency);
-
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 8892161..9564bb6 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1539,7 +1539,8 @@
const char *name = strings + sym->st_value;
const char *fmt = strchr(name, '\0') + 1;
char *line = NULL;
- asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt);
+ if (asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt) == -1)
+ fatal("asprintf() with %s failed", name);
NOFAIL(line);
mod->markers[n++] = line;
}
@@ -1959,7 +1960,8 @@
static void add_marker(struct module *mod, const char *name, const char *fmt)
{
char *line = NULL;
- asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt);
+ if (asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt) == -1)
+ fatal("asprintf() with %s failed", name);
NOFAIL(line);
mod->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) *
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 91c250b..97df16a 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -660,6 +660,17 @@
/* Wait ramp delay time + 1, so the VMID can settle */
mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
twl4030->sysclk) + 1);
+
+ /* Disable external mute */
+ if (setup && setup->hs_extmute) {
+ if (setup->set_hs_extmute) {
+ setup->set_hs_extmute(0);
+ } else {
+ hs_pop &= ~TWL4030_EXTMUTE;
+ twl4030_write(codec,
+ TWL4030_REG_HS_POPN_SET, hs_pop);
+ }
+ }
} else {
/* Headset ramp-down _not_ according to
* the TRM, but in a way that it is working */
@@ -676,16 +687,6 @@
hs_pop &= ~TWL4030_VMID_EN;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
}
-
- /* Disable external mute */
- if (setup && setup->hs_extmute) {
- if (setup->set_hs_extmute) {
- setup->set_hs_extmute(0);
- } else {
- hs_pop &= ~TWL4030_EXTMUTE;
- twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
- }
- }
}
static int headsetlpga_event(struct snd_soc_dapm_widget *w,
@@ -1899,12 +1900,16 @@
rval = twl4030_set_rate(codec, params);
if (rval < 0) {
mutex_unlock(&twl4030->mutex);
+ printk(KERN_ERR "twl4030_hw_params: set rate failed, rate = %d\n",
+ params_rate(params));
return rval;
}
rval = twl4030_set_format(codec, params);
if (rval < 0) {
mutex_unlock(&twl4030->mutex);
+ printk(KERN_ERR "twl4030_hw_params: set format failed, format = %d\n",
+ params_format(params));
return rval;
}
@@ -1976,7 +1981,7 @@
return 0;
}
-static int twl4030_set_ext_clock(struct snd_soc_codec *codec, int enable)
+int twl4030_set_ext_clock(struct snd_soc_codec *codec, int enable)
{
u8 old_format, format;
@@ -2002,6 +2007,7 @@
return 0;
}
+EXPORT_SYMBOL_GPL(twl4030_set_ext_clock);
static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
@@ -2329,15 +2335,17 @@
.name = "twl4030",
.playback = {
.stream_name = "HiFi Playback",
- .channels_min = 1,
+ .channels_min = 2,
.channels_max = 4,
- .rates = TWL4030_RATES | SNDRV_PCM_RATE_96000,
+ /*.rates = TWL4030_RATES | SNDRV_PCM_RATE_96000, */
+ .rates = SNDRV_PCM_RATE_44100,
.formats = TWL4030_FORMATS,},
.capture = {
.stream_name = "Capture",
- .channels_min = 1,
+ .channels_min = 2,
.channels_max = 4,
- .rates = TWL4030_RATES,
+ /*.rates = TWL4030_RATES, */
+ .rates = SNDRV_PCM_RATE_44100,
.formats = TWL4030_FORMATS,},
.ops = {
.startup = twl4030_startup,
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
index bece61c..2d83c19 100644
--- a/sound/soc/codecs/twl4030.h
+++ b/sound/soc/codecs/twl4030.h
@@ -275,6 +275,7 @@
extern int twl4030_set_rate(struct snd_soc_codec *, struct snd_pcm_hw_params *);
extern int twl4030_get_clock_divisor(struct snd_soc_codec *,
struct snd_pcm_hw_params *);
+extern int twl4030_set_ext_clock(struct snd_soc_codec *codec, int);
struct twl4030_setup_data {
unsigned int ramp_delay_value;
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 1a0b555..517eaa4 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -74,7 +74,7 @@
config SND_OMAP_SOC_ZOOM2
tristate "SoC Audio support for Zoom2"
- depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_ZOOM2
+ depends on TWL4030_CORE && SND_OMAP_SOC && (MACH_OMAP_ZOOM2 || MACH_OMAP_ZOOM3)
select SND_OMAP_SOC_MCBSP
select SND_SOC_TWL4030
help
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index acd1375..a6d4902 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -42,11 +42,11 @@
unsigned int bus_id;
struct omap_mcbsp_reg_cfg regs;
unsigned int fmt;
+ int clk_id;
/*
- * Flags indicating is the bus already activated and configured by
+ * Flags indicating is the bus already onfigured by
* another substream
*/
- int active;
int configured;
};
@@ -153,12 +153,18 @@
* size in order to avoid underruns in playback startup because
* HW is keeping the DMA request active until FIFO is filled.
*/
- snd_pcm_hw_constraint_minmax(substream->runtime,
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4096, UINT_MAX);
+ else
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 1024, UINT_MAX);
}
- if (!cpu_dai->active)
+ if (!cpu_dai->active) {
err = omap_mcbsp_request(mcbsp_data->bus_id);
+ cpu_dai->active = 1;
+ }
return err;
}
@@ -172,6 +178,7 @@
if (!cpu_dai->active) {
omap_mcbsp_free(mcbsp_data->bus_id);
+ cpu_dai->active = 0;
mcbsp_data->configured = 0;
}
}
@@ -182,21 +189,18 @@
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
- int err = 0;
+ int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (!mcbsp_data->active++)
- omap_mcbsp_start(mcbsp_data->bus_id);
+ case SNDRV_PCM_TRIGGER_RESUME:
+ omap_mcbsp_start(mcbsp_data->bus_id, play, !play);
break;
-
case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (!--mcbsp_data->active)
- omap_mcbsp_stop(mcbsp_data->bus_id);
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ omap_mcbsp_stop(mcbsp_data->bus_id, play, !play);
break;
default:
err = -EINVAL;
@@ -214,9 +218,12 @@
struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
- int wlen, channels, wpf;
- unsigned long port;
- unsigned int format;
+ int uninitialized_var(wlen);
+ int uninitialized_var(channels);
+ int uninitialized_var(wpf);
+ unsigned long uninitialized_var(port);
+ unsigned int uninitialized_var(format);
+ int xfer_size = 0;
if (cpu_class_is_omap1()) {
dma = omap1_dma_reqs[bus_id][substream->stream];
@@ -230,6 +237,25 @@
} else if (cpu_is_omap343x()) {
dma = omap24xx_dma_reqs[bus_id][substream->stream];
port = omap34xx_mcbsp_port[bus_id][substream->stream];
+ xfer_size = omap34xx_mcbsp_thresholds[bus_id]
+ [substream->stream];
+ /* reset the xfer_size to the integral multiple of
+ the buffer size. This is for DMA packet mode transfer */
+ if (xfer_size) {
+ /* struct snd_pcm_runtime *runtime = substream->runtime;*/
+ int buffer_size = params_buffer_size(params);
+ if (xfer_size > buffer_size) {
+ printk(KERN_DEBUG "buffer_size is %d \n",
+ buffer_size);
+ xfer_size = 0;
+ } else {
+ int temp = buffer_size / xfer_size;
+ while (buffer_size % xfer_size) {
+ temp++;
+ xfer_size = buffer_size / (temp);
+ }
+ }
+ }
} else {
return -ENODEV;
}
@@ -237,6 +263,7 @@
substream->stream ? "Audio Capture" : "Audio Playback";
omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
+ omap_mcbsp_dai_dma_params[id][substream->stream].xfer_size = xfer_size;
cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];
if (mcbsp_data->configured) {
@@ -256,6 +283,11 @@
wpf--;
regs->rcr2 |= RFRLEN2(wpf - 1);
regs->xcr2 |= XFRLEN2(wpf - 1);
+ } else if (format == SND_SOC_DAIFMT_I2S_1PHASE) {
+ printk(KERN_DEBUG "Configure McBSP for 1 phase\n");
+ regs->xcr2 &= ~(XPHASE);
+ regs->rcr2 &= ~(RPHASE);
+ wpf--;
}
case 1:
case 4:
@@ -271,11 +303,22 @@
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
/* Set word lengths */
- wlen = 16;
- regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16);
- regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16);
- regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16);
- regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16);
+ if (format == SND_SOC_DAIFMT_I2S_1PHASE) {
+ regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_32);
+ regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32);
+ omap_mcbsp_dai_dma_params[id]
+ [SNDRV_PCM_STREAM_PLAYBACK].dma_word_size = 32;
+ omap_mcbsp_dai_dma_params[id]
+ [SNDRV_PCM_STREAM_CAPTURE].dma_word_size = 32;
+ } else {
+ wlen = 16;
+ regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16);
+ regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16);
+ regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16);
+ regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16);
+ omap_mcbsp_dai_dma_params[id]
+ [substream->stream].dma_word_size = 16;
+ }
break;
default:
/* Unsupported PCM format */
@@ -285,6 +328,7 @@
/* Set FS period and length in terms of bit clock periods */
switch (format) {
case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_I2S_1PHASE:
regs->srgr2 |= FPER(wlen * channels - 1);
regs->srgr1 |= FWID(wlen - 1);
break;
@@ -295,7 +339,18 @@
break;
}
+ regs->xccr |= XDMAEN;
+ regs->wken = XRDYEN;
+ regs->rccr |= RDMAEN;
+
omap_mcbsp_config(bus_id, &mcbsp_data->regs);
+
+ if ((bus_id == 1) && (xfer_size != 0)) {
+ printk(KERN_DEBUG "Configure McBSP TX FIFO threshold to %d\n",
+ xfer_size);
+ omap_mcbsp_set_tx_threshold(bus_id, xfer_size);
+ }
+
mcbsp_data->configured = 1;
return 0;
@@ -323,12 +378,13 @@
regs->rcr2 |= RFIG;
regs->xcr2 |= XFIG;
if (cpu_is_omap2430() || cpu_is_omap34xx()) {
- regs->xccr = DXENDLY(1) | XDMAEN;
- regs->rccr = RFULL_CYCLE | RDMAEN;
+ regs->xccr = DXENDLY(1);
+ regs->rccr = RFULL_CYCLE;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_I2S_1PHASE:
/* 1-bit data delay */
regs->rcr2 |= RDATDLY(1);
regs->xcr2 |= XDATDLY(1);
@@ -476,6 +532,7 @@
case OMAP_MCBSP_SYSCLK_CLKS_FCLK:
case OMAP_MCBSP_SYSCLK_CLKS_EXT:
err = omap_mcbsp_dai_set_clks_src(mcbsp_data, clk_id);
+ mcbsp_data->clk_id = clk_id;
break;
case OMAP_MCBSP_SYSCLK_CLKX_EXT:
@@ -490,6 +547,31 @@
return err;
}
+int omap_mcbsp_dai_suspend(struct snd_soc_dai *cpu_dai)
+{
+ struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+
+ if (cpu_dai->active) {
+ omap_mcbsp_dai_set_clks_src(mcbsp_data, OMAP_MCBSP_SYSCLK_CLKS_FCLK);
+ omap_mcbsp_disable_fclk(mcbsp_data->bus_id);
+ }
+
+ return 0;
+}
+
+int omap_mcbsp_dai_resume(struct snd_soc_dai *cpu_dai)
+{
+ struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+
+ if (cpu_dai->active) {
+ omap_mcbsp_enable_fclk(mcbsp_data->bus_id);
+ omap_mcbsp_config(mcbsp_data->bus_id, &mcbsp_data->regs);
+ omap_mcbsp_dai_set_clks_src(mcbsp_data, mcbsp_data->clk_id);
+ }
+
+ return 0;
+}
+
#define OMAP_MCBSP_DAI_BUILDER(link_id) \
{ \
.name = "omap-mcbsp-dai-"#link_id, \
@@ -506,6 +588,8 @@
.rates = OMAP_MCBSP_RATES, \
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
}, \
+ .suspend = omap_mcbsp_dai_suspend, \
+ .resume = omap_mcbsp_dai_resume, \
.ops = { \
.startup = omap_mcbsp_dai_startup, \
.shutdown = omap_mcbsp_dai_shutdown, \
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 5b3dd1f..78ec86f 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -155,6 +155,17 @@
dma_params.src_start = runtime->dma_addr;
dma_params.dst_start = dma_data->port_addr;
dma_params.dst_port = OMAP_DMA_PORT_MPUI;
+ if (dma_data->dma_word_size == 32) {
+ printk(KERN_DEBUG "playback: 32 bit wordsize, xsize=%d\n",
+ dma_data->xfer_size);
+ if (dma_data->xfer_size != 0) {
+ dma_params.sync_mode = OMAP_DMA_SYNC_PACKET;
+ dma_params.dst_fi = dma_data->xfer_size;
+ } else {
+ dma_params.sync_mode = OMAP_DMA_SYNC_ELEMENT;
+ }
+ dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
+ }
} else {
dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT;
dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC;
@@ -162,6 +173,10 @@
dma_params.src_start = dma_data->port_addr;
dma_params.dst_start = runtime->dma_addr;
dma_params.src_port = OMAP_DMA_PORT_MPUI;
+ if (dma_data->dma_word_size == 32) {
+ printk(KERN_DEBUG "record: Configure for 32 bit word size\n");
+ dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
+ }
}
/*
* Set DMA transfer frame size equal to ALSA period size and frame
@@ -169,12 +184,21 @@
* we can transfer the whole ALSA buffer with single DMA transfer but
* still can get an interrupt at each period bounary
*/
- dma_params.elem_count = snd_pcm_lib_period_bytes(substream) / 2;
+ if (dma_data->dma_word_size == 32)
+ dma_params.elem_count = runtime->period_size;
+ else
+ dma_params.elem_count = snd_pcm_lib_period_bytes(substream) / 2;
dma_params.frame_count = runtime->periods;
omap_set_dma_params(prtd->dma_ch, &dma_params);
omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
+ if (dma_data->xfer_size) {
+ omap_set_dma_src_burst_mode(prtd->dma_ch,
+ OMAP_DMA_DATA_BURST_16);
+ omap_set_dma_dest_burst_mode(prtd->dma_ch,
+ OMAP_DMA_DATA_BURST_16);
+ }
return 0;
}
@@ -182,7 +206,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct omap_runtime_data *prtd = runtime->private_data;
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
int ret = 0;
spin_lock_irqsave(&prtd->lock, flags);
@@ -195,11 +219,15 @@
break;
case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
prtd->period_index = -1;
omap_stop_dma(prtd->dma_ch);
break;
+
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ omap_stop_dma(prtd->dma_ch);
+ omap_disable_lch(prtd->dma_ch);
+ break;
default:
ret = -EINVAL;
}
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
index e4369bd..0262467 100644
--- a/sound/soc/omap/omap-pcm.h
+++ b/sound/soc/omap/omap-pcm.h
@@ -28,6 +28,8 @@
char *name; /* stream identifier */
int dma_req; /* DMA request line */
unsigned long port_addr; /* transmit/receive register */
+ int xfer_size; /* DMA transfer size */
+ int dma_word_size; /* DMA word size 32/16 */
};
extern struct snd_soc_platform omap_soc_platform;
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index c23b792..1053350 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -53,7 +53,7 @@
/* Set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai,
SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_NB_IF |
SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0) {
printk(KERN_ERR "can't set codec DAI configuration\n");
@@ -62,8 +62,8 @@
/* Set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_I2S_1PHASE |
+ SND_SOC_DAIFMT_NB_IF |
SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0) {
printk(KERN_ERR "can't set cpu DAI configuration\n");
@@ -78,11 +78,116 @@
return ret;
}
+ /* enable 256 FS clk for HDMI */
+ ret = twl4030_set_ext_clock(codec_dai->codec, 1);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set 256 FS clock\n");
+ return ret;
+ }
+
+ /* Use external clock for mcBSP2 */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT,
+ 0, SND_SOC_CLOCK_OUT);
+
+ /*
+ * Set headset EXTMUTE signal to ON to make sure we
+ * get correct headset status
+ */
+ gpio_direction_output(ZOOM2_HEADSET_EXTMUTE_GPIO, 1);
+
return 0;
}
+int zoom2_i2s_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret;
+
+ /* Use function clock for mcBSP2 */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_FCLK,
+ 0, SND_SOC_CLOCK_OUT);
+ return 0;
+}
+
+
static struct snd_soc_ops zoom2_i2s_ops = {
.hw_params = zoom2_i2s_hw_params,
+ .hw_free = zoom2_i2s_hw_free,
+};
+
+static int zoom2_hw_voice_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;
+
+ omap_mux_config("MCBSP3_SLAVE");
+
+ /* Set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBS_CFM);
+
+ if (ret) {
+ printk(KERN_ERR "can't set codec DAI configuration\n");
+ return ret;
+ }
+
+ /* set codec Voice IF to application mode*/
+ ret = snd_soc_dai_set_tristate(codec_dai, 0);
+
+ if (ret) {
+ printk(KERN_ERR "can't disable codec VIF tristate\n");
+ return ret;
+ }
+
+ /* Set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+
+ if (ret < 0) {
+ printk(KERN_ERR "can't set cpu DAI configuration\n");
+ return ret;
+ }
+
+ /* Set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set codec system clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int zoom2_hw_voice_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ int ret;
+
+ omap_mux_config("MCBSP3_TRISTATE");
+
+ /* set codec Voice IF to tristate*/
+ ret = snd_soc_dai_set_tristate(codec_dai, 1);
+
+ if (ret) {
+ printk(KERN_ERR "can't set codec VIF tristate\n");
+ return ret;
+ }
+
+ return 0;
+}
+static struct snd_soc_ops zoom2_voice_ops = {
+ .hw_params = zoom2_hw_voice_params,
+ .hw_free = zoom2_hw_voice_free,
};
static int zoom2_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -363,6 +468,14 @@
.ops = &zoom2_i2s_ops,
},
{
+ .name = "TWL4030 VOICE",
+ .stream_name = "TWL4030 Voice",
+ .cpu_dai = &omap_mcbsp_dai[1],
+ .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+ .init = zoom2_twl4030_voice_init,
+ .ops = &zoom2_voice_ops,
+},
+{
.name = "TWL4030_PCM",
.stream_name = "TWL4030_PCM",
.cpu_dai = &omap_mcbsp_dai[1],
@@ -422,10 +535,13 @@
{
int ret;
- if (!machine_is_omap_zoom2()) {
- pr_debug("Not Zoom2!\n");
+
+ if (!(machine_is_omap_zoom2() ||
+ machine_is_omap_zoom3())) {
+ pr_debug("Not Zoom2/3!\n");
return -ENODEV;
}
+
printk(KERN_INFO "Zoom2 SoC init\n");
omap_mux_config("MCBSP2_SLAVE");
@@ -446,7 +562,8 @@
zoom2_snd_devdata.dev = &zoom2_snd_device->dev;
*(unsigned int *)zoom2_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
*(unsigned int *)zoom2_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
- *(unsigned int *)zoom2_dai[2].cpu_dai->private_data = 3; /* McBSP4 */
+ *(unsigned int *)zoom2_dai[2].cpu_dai->private_data = 2; /* McBSP3 */
+ *(unsigned int *)zoom2_dai[3].cpu_dai->private_data = 3; /* McBSP4 */
ret = platform_device_add(zoom2_snd_device);
if (ret)
@@ -456,7 +573,8 @@
gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0);
BUG_ON(gpio_request(ZOOM2_HEADSET_EXTMUTE_GPIO, "ext_mute") < 0);
- gpio_direction_output(ZOOM2_HEADSET_EXTMUTE_GPIO, 0);
+ /* set EXTMUTE on for initial headset detection */
+ gpio_direction_output(ZOOM2_HEADSET_EXTMUTE_GPIO, 1);
return 0;