diff options
Diffstat (limited to 'arch/arm')
38 files changed, 7230 insertions, 71 deletions
diff --git a/arch/arm/configs/tuna_defconfig b/arch/arm/configs/tuna_defconfig new file mode 100644 index 0000000..48713fa --- /dev/null +++ b/arch/arm/configs/tuna_defconfig @@ -0,0 +1,382 @@ +CONFIG_EXPERIMENTAL=y +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_KALLSYMS_ALL=y +CONFIG_ASHMEM=y +# CONFIG_AIO is not set +CONFIG_EMBEDDED=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_ARCH_OMAP=y +CONFIG_OMAP_SMARTREFLEX=y +CONFIG_OMAP_SMARTREFLEX_CLASS3=y +CONFIG_OMAP_RESET_CLOCKS=y +CONFIG_OMAP_TEMP_SENSOR=y +CONFIG_OMAP_REMOTEPROC_MEMPOOL_SIZE=0x0 +# CONFIG_ARCH_OMAP2 is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_MACH_OMAP_4430SDP is not set +CONFIG_OMAP_ALLOW_OSWR=y +CONFIG_ARM_THUMBEE=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +CONFIG_PREEMPT=y +CONFIG_HIGHMEM=y +CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y +CONFIG_CMDLINE="console= mem=1G vmalloc=768M omap_wdt.timer_margin=30 no_console_suspend" +CONFIG_CMDLINE_EXTEND=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_HOTPLUG=y +CONFIG_CPU_IDLE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_MISC=y +CONFIG_WAKELOCK=y +CONFIG_PM_DEBUG=y +CONFIG_SUSPEND_TIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_INET_ESP=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_LOG=y +CONFIG_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_TARGET_LOG=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +CONFIG_PHONET=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +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_HIDP=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +# CONFIG_CFG80211_WEXT is not set +CONFIG_CFG80211_ALLOW_RECONNECT=y +CONFIG_RFKILL=y +CONFIG_RFKILL_INPUT=y +CONFIG_MTD=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_NAND_IDS=y +CONFIG_MTD_ONENAND=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_MISC_DEVICES=y +# CONFIG_ANDROID_PMEM is not set +CONFIG_KERNEL_DEBUGGER_CORE=y +CONFIG_SAMSUNG_JACK=y +CONFIG_UID_STAT=y +CONFIG_BMP180=y +CONFIG_USB_SWITCH_FSA9480=y +CONFIG_OMAP_DIE_TEMP_SENSOR=y +CONFIG_LEDS_AN30259A=y +CONFIG_MPU_SENSORS_TIMERIRQ=y +CONFIG_INV_SENSORS=y +CONFIG_MPU_SENSORS_MPU3050=y +CONFIG_MPU_SENSORS_BMA250=y +CONFIG_MPU_SENSORS_YAS530=y +CONFIG_SEC_MODEM=y +CONFIG_UMTS_LINK_MIPI=y +CONFIG_UMTS_MODEM_XMM6260=y +CONFIG_CDMA_LINK_DPRAM=y +CONFIG_CDMA_MODEM_CBP71=y +CONFIG_LTE_LINK_USB=y +CONFIG_LTE_MODEM_CMC221=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEBUG=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_NETDEVICES=y +CONFIG_IFB=y +CONFIG_TUN=y +CONFIG_WIFI_CONTROL_FUNC=y +CONFIG_BCMDHD=y +CONFIG_BCMDHD_FW_PATH="/system/vendor/firmware/fw_bcmdhd.bin" +CONFIG_PPP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_OMAP4=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ATMEL_MXT=y +CONFIG_TOUCHSCREEN_MMS=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +CONFIG_OPTICAL_GP2A=y +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_HW_RANDOM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_GPIO=y +CONFIG_SPI=y +CONFIG_SPI_OMAP24XX=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_TWL4030=y +CONFIG_POWER_SUPPLY=y +CONFIG_PDA_POWER=y +CONFIG_BATTERY_MAX17040=y +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_OMAP_WATCHDOG=y +CONFIG_TWL6030_POWER=y +CONFIG_TWL6030_PWM=y +CONFIG_TWL6030_MADC=y +CONFIG_REGULATOR_TWL4030=y +CONFIG_MEDIA_SUPPORT=y +# CONFIG_RC_CORE is not set +CONFIG_PVR_SGX=y +CONFIG_PVR_NEED_PVR_DPF=y +CONFIG_PVR_USSE_EDM_STATUS_DEBUG=y +CONFIG_ION=y +CONFIG_ION_OMAP=y +CONFIG_FB=y +CONFIG_SII9234=y +CONFIG_FB_OMAP_BOOTLOADER_INIT=y +CONFIG_OMAP2_DSS=y +CONFIG_OMAP2_VRAM_SIZE=16 +# CONFIG_OMAP2_DSS_DPI is not set +# CONFIG_OMAP2_DSS_VENC is not set +CONFIG_OMAP2_DSS_DSI=y +CONFIG_FB_OMAP2=y +CONFIG_PANEL_S6E8AA0=y +CONFIG_OMAP4_HDCP=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_DISPLAY_SUPPORT=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_OMAP_SOC=y +CONFIG_SND_OMAP_SOC_SDP4430=y +CONFIG_SND_OMAP_SOC_OMAP4_HDMI=y +CONFIG_HID_A4TECH=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_HID_EZKEY=y +CONFIG_HID_KYE=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_QUANTA=y +CONFIG_HID_ROCCAT_KONE=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_WACOM=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_SUSPEND=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_MUSB_HDRC=y +CONFIG_USB_MUSB_OMAP2PLUS=y +CONFIG_USB_MUSB_PERIPHERAL=y +CONFIG_USB_GADGET_MUSB_HDRC=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SERIAL=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_G_ANDROID=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_EMBEDDED_SDIO=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_OMAP=y +CONFIG_MMC_OMAP_HS=y +CONFIG_SWITCH=y +CONFIG_SWITCH_GPIO=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_TWL4030=y +CONFIG_STAGING=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_OMAP_HSI=y +CONFIG_EXT2_FS=y +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_XATTR is not set +# CONFIG_DNOTIFY is not set +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_EFI_PARTITION=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_SPINLOCK_SLEEP=y +CONFIG_DEBUG_INFO=y +CONFIG_SYSCTL_SYSCALL_CHECK=y +# CONFIG_ARM_UNWIND is not set +CONFIG_DEBUG_USER=y +CONFIG_SECURITY_MIDDLEWARE_COMPONENT=y +# CONFIG_SMC_KERNEL_CRYPTO is not set +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRC_CCITT=y diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 1cf7d51..8d3cb45 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -325,6 +325,15 @@ config MACH_OMAP4_PANDA select OMAP_PACKAGE_CBS select REGULATOR_FIXED_VOLTAGE +config MACH_TUNA + bool "Tuna Board" + default y + depends on ARCH_OMAP4 + select OMAP_PACKAGE_CBL + select OMAP_PACKAGE_CBS + select REGULATOR_FIXED_VOLTAGE + select OMAP_TPS6236X + config OMAP3_EMU bool "OMAP3 debugging peripherals" depends on ARCH_OMAP3 diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index c0f2be2..961a34f 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -253,6 +253,22 @@ obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o \ obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o \ hsmmc.o \ omap_phy_internal.o +obj-$(CONFIG_MACH_TUNA) += board-tuna.o \ + hsmmc.o \ + omap_phy_internal.o +obj-$(CONFIG_MACH_TUNA) += board-tuna-display.o +obj-$(CONFIG_MACH_TUNA) += board-tuna-input.o +obj-$(CONFIG_MACH_TUNA) += board-tuna-jack.o +obj-$(CONFIG_MACH_TUNA) += board-tuna-nfc.o +obj-$(CONFIG_MACH_TUNA) += board-tuna-power.o +obj-$(CONFIG_MACH_TUNA) += board-tuna-sensors.o +obj-$(CONFIG_MACH_TUNA) += board-tuna-vibrator.o +obj-$(CONFIG_MACH_TUNA) += board-tuna-wifi.o +obj-$(CONFIG_MACH_TUNA) += board-tuna-bluetooth.o \ + board-tuna-emif.o +obj-$(CONFIG_MACH_TUNA) += board-tuna-connector.o +obj-$(CONFIG_MACH_TUNA) += board-tuna-pogo.o +obj-$(CONFIG_MACH_TUNA) += board-tuna-usbhost.o obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o \ omap_phy_internal.o \ @@ -291,4 +307,5 @@ obj-y += common-board-devices.o obj-$(CONFIG_OMAP_REMOTE_PROC) += remoteproc.o obj-$(CONFIG_OMAP_HSI_DEVICE) += omap_hsi.o +obj-$(CONFIG_SEC_MODEM) += board-tuna-modems.o obj-$(CONFIG_ARCH_OMAP4) += omap_dmm.o diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 4fcd26a..5a00efc 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -680,8 +680,6 @@ void omap4_panda_display_init(void) omap_display_init(&omap4_panda_dss_data); } -extern void __init omap4_panda_android_init(void); - static void __init omap4_panda_init(void) { int package = OMAP_PACKAGE_CBS; @@ -712,7 +710,6 @@ static void __init omap4_panda_init(void) omap_dmm_init(); omap4_panda_display_init(); - } static void __init omap4_panda_map_io(void) diff --git a/arch/arm/mach-omap2/board-tuna-bluetooth.c b/arch/arm/mach-omap2/board-tuna-bluetooth.c new file mode 100644 index 0000000..67a2ac6 --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-bluetooth.c @@ -0,0 +1,306 @@ +/* + * Bluetooth Broadcomm and low power control via GPIO + * + * Copyright (C) 2011 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/hrtimer.h> +#include <linux/irq.h> +#include <linux/rfkill.h> +#include <linux/platform_device.h> +#include <linux/wakelock.h> +#include <asm/mach-types.h> +#include <plat/serial.h> +#include <plat/board-tuna-bluetooth.h> +#include <linux/regulator/driver.h> + +#define BT_REG_GPIO 103 +#define BT_RESET_GPIO 42 + +#define BT_WAKE_GPIO 27 +#define BT_HOST_WAKE_GPIO 177 + +static struct rfkill *bt_rfkill; +static struct regulator *clk32kaudio_reg; +static bool bt_enabled; + +struct bcm_bt_lpm { + int wake; + int host_wake; + + struct hrtimer enter_lpm_timer; + ktime_t enter_lpm_delay; + + struct uart_port *uport; + + struct wake_lock wake_lock; + char wake_lock_name[100]; +} bt_lpm; + +static int bcm4330_bt_rfkill_set_power(void *data, bool blocked) +{ + // rfkill_ops callback. Turn transmitter on when blocked is false + if (!blocked) { + if (clk32kaudio_reg && !bt_enabled) + regulator_enable(clk32kaudio_reg); + + gpio_set_value(BT_REG_GPIO, 1); + gpio_set_value(BT_RESET_GPIO, 1); + + } else { + gpio_set_value(BT_RESET_GPIO, 0); + gpio_set_value(BT_REG_GPIO, 0); + if (clk32kaudio_reg && bt_enabled) + regulator_disable(clk32kaudio_reg); + } + + bt_enabled = !blocked; + + return 0; +} + +static const struct rfkill_ops bcm4330_bt_rfkill_ops = { + .set_block = bcm4330_bt_rfkill_set_power, +}; + +static void set_wake_locked(int wake) +{ + bt_lpm.wake = wake; + + if (!wake) + wake_unlock(&bt_lpm.wake_lock); + + gpio_set_value(BT_WAKE_GPIO, wake); +} + +static enum hrtimer_restart enter_lpm(struct hrtimer *timer) { + unsigned long flags; + spin_lock_irqsave(&bt_lpm.uport->lock, flags); + set_wake_locked(0); + spin_unlock_irqrestore(&bt_lpm.uport->lock, flags); + + return HRTIMER_NORESTART; +} + +void bcm_bt_lpm_exit_lpm_locked(struct uart_port *uport) { + bt_lpm.uport = uport; + + hrtimer_try_to_cancel(&bt_lpm.enter_lpm_timer); + + set_wake_locked(1); + + hrtimer_start(&bt_lpm.enter_lpm_timer, bt_lpm.enter_lpm_delay, + HRTIMER_MODE_REL); +} +EXPORT_SYMBOL(bcm_bt_lpm_exit_lpm_locked); + +static void update_host_wake_locked(int host_wake) +{ + if (host_wake == bt_lpm.host_wake) + return; + + bt_lpm.host_wake = host_wake; + + if (host_wake) { + wake_lock(&bt_lpm.wake_lock); + } else { + // Take a timed wakelock, so that upper layers can take it. + // The chipset deasserts the hostwake lock, when there is no + // more data to send. + wake_lock_timeout(&bt_lpm.wake_lock, HZ/2); + } + +} + +static irqreturn_t host_wake_isr(int irq, void *dev) +{ + int host_wake; + unsigned long flags; + + /* wakeup uart by enabling the uart module */ + omap_uart_wake(2); + + host_wake = gpio_get_value(BT_HOST_WAKE_GPIO); + irq_set_irq_type(irq, host_wake ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); + + if (!bt_lpm.uport) { + bt_lpm.host_wake = host_wake; + return IRQ_HANDLED; + } + + spin_lock_irqsave(&bt_lpm.uport->lock, flags); + update_host_wake_locked(host_wake); + spin_unlock_irqrestore(&bt_lpm.uport->lock, flags); + + return IRQ_HANDLED; +} + +static int bcm_bt_lpm_init(struct platform_device *pdev) +{ + int irq; + int ret; + int rc; + + rc = gpio_request(BT_WAKE_GPIO, "bcm4330_wake_gpio"); + if (unlikely(rc)) { + return rc; + } + + rc = gpio_request(BT_HOST_WAKE_GPIO, "bcm4330_host_wake_gpio"); + if (unlikely(rc)) { + gpio_free(BT_WAKE_GPIO); + return rc; + } + + hrtimer_init(&bt_lpm.enter_lpm_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + bt_lpm.enter_lpm_delay = ktime_set(1, 0); /* 1 sec */ + bt_lpm.enter_lpm_timer.function = enter_lpm; + + bt_lpm.host_wake = 0; + + irq = gpio_to_irq(BT_HOST_WAKE_GPIO); + ret = request_irq(irq, host_wake_isr, IRQF_TRIGGER_HIGH, + "bt host_wake", NULL); + if (ret) { + gpio_free(BT_WAKE_GPIO); + gpio_free(BT_HOST_WAKE_GPIO); + return ret; + } + + ret = irq_set_irq_wake(irq, 1); + if (ret) { + gpio_free(BT_WAKE_GPIO); + gpio_free(BT_HOST_WAKE_GPIO); + return ret; + } + + gpio_direction_output(BT_WAKE_GPIO, 0); + gpio_direction_input(BT_HOST_WAKE_GPIO); + + snprintf(bt_lpm.wake_lock_name, sizeof(bt_lpm.wake_lock_name), + "BTLowPower"); + wake_lock_init(&bt_lpm.wake_lock, WAKE_LOCK_SUSPEND, + bt_lpm.wake_lock_name); + return 0; +} + +static int bcm4330_bluetooth_probe(struct platform_device *pdev) +{ + int rc = 0; + int ret = 0; + + rc = gpio_request(BT_RESET_GPIO, "bcm4330_nreset_gpip"); + if (unlikely(rc)) { + return rc; + } + + rc = gpio_request(BT_REG_GPIO, "bcm4330_nshutdown_gpio"); + if (unlikely(rc)) { + gpio_free(BT_RESET_GPIO); + return rc; + } + + clk32kaudio_reg = regulator_get(0, "clk32kaudio"); + if (IS_ERR(clk32kaudio_reg)) { + pr_err("clk32kaudio reg not found!\n"); + clk32kaudio_reg = NULL; + } + + gpio_direction_output(BT_REG_GPIO, 1); + gpio_direction_output(BT_RESET_GPIO, 1); + + bt_rfkill = rfkill_alloc("bcm4330 Bluetooth", &pdev->dev, + RFKILL_TYPE_BLUETOOTH, &bcm4330_bt_rfkill_ops, + NULL); + + if (unlikely(!bt_rfkill)) { + gpio_free(BT_RESET_GPIO); + gpio_free(BT_REG_GPIO); + return -ENOMEM; + } + + rc = rfkill_register(bt_rfkill); + + if (unlikely(rc)) { + rfkill_destroy(bt_rfkill); + gpio_free(BT_RESET_GPIO); + gpio_free(BT_REG_GPIO); + return -1; + } + + rfkill_set_states(bt_rfkill, true, false); + bcm4330_bt_rfkill_set_power(NULL, true); + + ret = bcm_bt_lpm_init(pdev); + if (ret) { + rfkill_unregister(bt_rfkill); + rfkill_destroy(bt_rfkill); + + gpio_free(BT_RESET_GPIO); + gpio_free(BT_REG_GPIO); + } + + return ret; +} + +static int bcm4330_bluetooth_remove(struct platform_device *pdev) +{ + rfkill_unregister(bt_rfkill); + rfkill_destroy(bt_rfkill); + + gpio_free(BT_REG_GPIO); + gpio_free(BT_RESET_GPIO); + gpio_free(BT_WAKE_GPIO); + gpio_free(BT_HOST_WAKE_GPIO); + regulator_put(clk32kaudio_reg); + + wake_lock_destroy(&bt_lpm.wake_lock); + return 0; +} + +static struct platform_driver bcm4330_bluetooth_platform_driver = { + .probe = bcm4330_bluetooth_probe, + .remove = bcm4330_bluetooth_remove, + .driver = { + .name = "bcm4330_bluetooth", + .owner = THIS_MODULE, + }, +}; + +static int __init bcm4330_bluetooth_init(void) +{ + bt_enabled = false; + return platform_driver_register(&bcm4330_bluetooth_platform_driver); +} + +static void __exit bcm4330_bluetooth_exit(void) +{ + platform_driver_unregister(&bcm4330_bluetooth_platform_driver); +} + + +module_init(bcm4330_bluetooth_init); +module_exit(bcm4330_bluetooth_exit); + +MODULE_ALIAS("platform:bcm4330"); +MODULE_DESCRIPTION("bcm4330_bluetooth"); +MODULE_AUTHOR("Jaikumar Ganesh <jaikumar@google.com>"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-omap2/board-tuna-connector.c b/arch/arm/mach-omap2/board-tuna-connector.c new file mode 100644 index 0000000..9b1f23a --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-connector.c @@ -0,0 +1,774 @@ +/* + * Copyright (C) 2011 Samsung, Inc. + * Copyright (C) 2011 Google Inc. + * + * Author: Adam Hampson <ahampson@sta.samsung.com> + * Dima Zavin <dima@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. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/platform_data/fsa9480.h> +#include <linux/regulator/consumer.h> +#include <linux/usb/otg.h> +#include <linux/delay.h> +#include <linux/sii9234.h> +#include <linux/mutex.h> + +#include <plat/usb.h> + +#include "mux.h" +#include "board-tuna.h" + +#define GPIO_JACK_INT_N 4 +#define GPIO_CP_USB_ON 22 +#define GPIO_MHL_SEL 96 +#define GPIO_AP_SEL 97 +#define GPIO_MUX3_SEL0 139 +#define GPIO_MUX3_SEL1 140 +#define GPIO_USB_ID_SEL 191 +#define GPIO_IF_UART_SEL 101 + +#define GPIO_MHL_RST 161 +#define GPIO_MHL_WAKEUP 64 +#define GPIO_MHL_INT 175 +#define GPIO_HDMI_EN 100 + +#define MUX3_SEL0_AP 1 +#define MUX3_SEL1_AP 1 +#define MUX3_SEL0_MHL 1 +#define MUX3_SEL1_MHL 0 +#define MUX3_SEL0_FSA 0 +#define MUX3_SEL1_FSA 1 + +#define FSA3200_AP_SEL_AP 0 +#define FSA3200_MHL_SEL_AP 0 +#define FSA3200_AP_SEL_FSA 1 +#define FSA3200_MHL_SEL_FSA 0 +#define FSA3200_AP_SEL_MHL 1 +#define FSA3200_MHL_SEL_MHL 1 + +#define USB_ID_SEL_FSA 0 +#define USB_ID_SEL_MHL 1 + +#define IF_UART_SEL_DEFAULT 1 +#define IF_UART_SEL_AP 1 +#define IF_UART_SEL_CP 0 + +#define TUNA_MANUAL_USB_NONE 0 +#define TUNA_MANUAL_USB_MODEM 1 +#define TUNA_MANUAL_USB_AP 2 + +#define TUNA_MANUAL_UART_NONE 0 +#define TUNA_MANUAL_UART_MODEM 1 +#define TUNA_MANUAL_UART_LTE 2 +#define TUNA_MANUAL_UART_AP 3 + +#define TUNA_OTG_ID_FSA9480_PRIO INT_MIN +#define TUNA_OTG_ID_SII9234_PRIO INT_MIN + 1 +#define TUNA_OTG_ID_FSA9480_LAST_PRIO INT_MAX + +struct tuna_otg { + struct otg_transceiver otg; + struct device dev; + + struct regulator *vusb; + struct mutex lock; + + bool reg_on; + int usb_manual_mode; + int uart_manual_mode; + int current_device; +}; +static struct tuna_otg tuna_otg_xceiv; + +enum { + TUNA_USB_MUX_FSA = 0, + TUNA_USB_MUX_MHL, + TUNA_USB_MUX_AP, + NUM_TUNA_USB_MUX, + + TUNA_USB_MUX_DEFAULT = TUNA_USB_MUX_FSA, +}; + +static struct { + int mux3_sel0; + int mux3_sel1; +} tuna_usb_mux_states[] = { + [TUNA_USB_MUX_FSA] = { MUX3_SEL0_FSA, MUX3_SEL1_FSA }, + [TUNA_USB_MUX_MHL] = { MUX3_SEL0_MHL, MUX3_SEL1_MHL }, + [TUNA_USB_MUX_AP] = { MUX3_SEL0_AP, MUX3_SEL1_AP }, +}; + +static struct { + int ap_sel; + int mhl_sel; +} tuna_fsa3200_mux_pair_states[] = { + [TUNA_USB_MUX_FSA] = { FSA3200_AP_SEL_FSA, FSA3200_MHL_SEL_FSA }, + [TUNA_USB_MUX_MHL] = { FSA3200_AP_SEL_MHL, FSA3200_MHL_SEL_MHL }, + [TUNA_USB_MUX_AP] = { FSA3200_AP_SEL_AP, FSA3200_MHL_SEL_AP }, +}; + +static int tuna_usb_id_mux_states[] = { + [TUNA_USB_MUX_FSA] = USB_ID_SEL_FSA, + [TUNA_USB_MUX_MHL] = USB_ID_SEL_MHL, + [TUNA_USB_MUX_AP] = USB_ID_SEL_FSA, +}; + +static ssize_t tuna_otg_usb_sel_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t tuna_otg_usb_sel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size); +static ssize_t tuna_otg_uart_switch_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t tuna_otg_uart_switch_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size); + +static DEVICE_ATTR(usb_sel, S_IRUSR | S_IWUSR, + tuna_otg_usb_sel_show, tuna_otg_usb_sel_store); +static DEVICE_ATTR(uart_sel, S_IRUSR | S_IWUSR, + tuna_otg_uart_switch_show, tuna_otg_uart_switch_store); + +static struct attribute *manual_mode_attributes[] = { + &dev_attr_usb_sel.attr, + &dev_attr_uart_sel.attr, + NULL, +}; + +static const struct attribute_group manual_mode_group = { + .attrs = manual_mode_attributes, +}; + +static void tuna_mux_usb(int state) +{ + BUG_ON(state >= NUM_TUNA_USB_MUX); + + pr_debug("mux to %d\n", state); + gpio_direction_output(GPIO_MUX3_SEL0, + tuna_usb_mux_states[state].mux3_sel0); + gpio_direction_output(GPIO_MUX3_SEL1, + tuna_usb_mux_states[state].mux3_sel1); +} + +static void tuna_mux_usb_id(int state) +{ + BUG_ON(state >= NUM_TUNA_USB_MUX); + + pr_debug("mux to %d\n", state); + gpio_direction_output(GPIO_USB_ID_SEL, tuna_usb_id_mux_states[state]); +} + +static void tuna_fsa3200_mux_pair(int state) +{ + BUG_ON(state >= NUM_TUNA_USB_MUX); + + pr_debug("mux to %d\n", state); + gpio_direction_output(GPIO_AP_SEL, + tuna_fsa3200_mux_pair_states[state].ap_sel); + gpio_direction_output(GPIO_MHL_SEL, + tuna_fsa3200_mux_pair_states[state].mhl_sel); +} + +static void tuna_mux_usb_to_fsa(bool enable) +{ + if (omap4_tuna_get_revision() >= 3) { + tuna_fsa3200_mux_pair(enable ? TUNA_USB_MUX_FSA : + TUNA_USB_MUX_DEFAULT); + } else { + tuna_mux_usb(enable ? TUNA_USB_MUX_FSA : TUNA_USB_MUX_DEFAULT); + + /* When switching ID away from FSA, we want to ensure we switch + * it off FSA, and force it to MHL. Ideally, we'd just say mux + * to default, but FSA is likely the default mux position and + * there's no way to force the ID pin to float to the FSA. + */ + tuna_mux_usb_id(enable ? TUNA_USB_MUX_FSA : TUNA_USB_MUX_MHL); + } +} + +static void tuna_mux_usb_to_mhl(bool enable) +{ + if (omap4_tuna_get_revision() >= 3) { + tuna_fsa3200_mux_pair(enable ? TUNA_USB_MUX_MHL : + TUNA_USB_MUX_DEFAULT); + } else { + tuna_mux_usb(enable ? TUNA_USB_MUX_MHL : TUNA_USB_MUX_DEFAULT); + tuna_mux_usb_id(enable ? TUNA_USB_MUX_MHL : TUNA_USB_MUX_DEFAULT); + } +} + +static void tuna_vusb_enable(struct tuna_otg *tuna_otg, bool enable) +{ + /* delay getting the regulator until later */ + if (IS_ERR_OR_NULL(tuna_otg->vusb)) { + tuna_otg->vusb = regulator_get(&tuna_otg->dev, "vusb"); + if (IS_ERR(tuna_otg->vusb)) { + dev_err(&tuna_otg->dev, "cannot get vusb regulator\n"); + return; + } + } + + if (enable) { + regulator_enable(tuna_otg->vusb); + tuna_otg->reg_on = true; + } else if (tuna_otg->reg_on) { + regulator_disable(tuna_otg->vusb); + tuna_otg->reg_on = false; + } +} + +static void tuna_ap_usb_attach(struct tuna_otg *tuna_otg) +{ + tuna_vusb_enable(tuna_otg, true); + + if (omap4_tuna_get_revision() >= 3) { + tuna_fsa3200_mux_pair(TUNA_USB_MUX_AP); + } else { + tuna_mux_usb(TUNA_USB_MUX_AP); + tuna_mux_usb_id(TUNA_USB_MUX_FSA); + } + + tuna_otg->otg.state = OTG_STATE_B_IDLE; + tuna_otg->otg.default_a = false; + tuna_otg->otg.last_event = USB_EVENT_VBUS; + atomic_notifier_call_chain(&tuna_otg->otg.notifier, + USB_EVENT_VBUS, + tuna_otg->otg.gadget); +} + +static void tuna_ap_usb_detach(struct tuna_otg *tuna_otg) +{ + tuna_vusb_enable(tuna_otg, false); + + tuna_otg->otg.state = OTG_STATE_B_IDLE; + tuna_otg->otg.default_a = false; + tuna_otg->otg.last_event = USB_EVENT_NONE; + atomic_notifier_call_chain(&tuna_otg->otg.notifier, + USB_EVENT_NONE, + tuna_otg->otg.gadget); +} + +static void tuna_cp_usb_attach(struct tuna_otg *tuna_otg) +{ + if (omap4_tuna_get_type() == TUNA_TYPE_MAGURO) + gpio_set_value(GPIO_CP_USB_ON, 1); + + tuna_mux_usb_to_fsa(true); +} + +static void tuna_cp_usb_detach(struct tuna_otg *tuna_otg) +{ + if (omap4_tuna_get_type() == TUNA_TYPE_MAGURO) + gpio_set_value(GPIO_CP_USB_ON, 0); +} + +static void tuna_ap_uart_actions(struct tuna_otg *tuna_otg) +{ + tuna_mux_usb_to_fsa(true); + gpio_set_value(GPIO_IF_UART_SEL, IF_UART_SEL_AP); +} + +static void tuna_cp_uart_actions(struct tuna_otg *tuna_otg) +{ + tuna_mux_usb_to_fsa(true); + gpio_set_value(GPIO_IF_UART_SEL, IF_UART_SEL_CP); +} + +static void tuna_lte_uart_actions(struct tuna_otg *tuna_otg) +{ + tuna_mux_usb_to_fsa(true); + + /* The LTE modem's UART lines are connected to the V_AUDIO_L and + * V_AUDIO_R pins on the FSA9480. The RIL will configure the FSA9480 + * separately to set manual routing. + */ +} + +static void tuna_fsa_usb_detected(int device) +{ + struct tuna_otg *tuna_otg = &tuna_otg_xceiv; + int old_device; + + mutex_lock(&tuna_otg->lock); + + old_device = tuna_otg->current_device; + tuna_otg->current_device = device; + + pr_debug("detected %x\n", device); + switch (device) { + case FSA9480_DETECT_USB: + if (tuna_otg->usb_manual_mode == TUNA_MANUAL_USB_MODEM) + tuna_cp_usb_attach(tuna_otg); + else + tuna_ap_usb_attach(tuna_otg); + break; + case FSA9480_DETECT_CHARGER: + tuna_mux_usb_to_fsa(true); + + tuna_otg->otg.state = OTG_STATE_B_IDLE; + tuna_otg->otg.default_a = false; + tuna_otg->otg.last_event = USB_EVENT_CHARGER; + atomic_notifier_call_chain(&tuna_otg->otg.notifier, + USB_EVENT_CHARGER, + tuna_otg->otg.gadget); + break; + case FSA9480_DETECT_USB_HOST: + tuna_vusb_enable(tuna_otg, true); + + if (omap4_tuna_get_revision() >= 3) { + tuna_fsa3200_mux_pair(TUNA_USB_MUX_AP); + } else { + tuna_mux_usb(TUNA_USB_MUX_AP); + tuna_mux_usb_id(TUNA_USB_MUX_FSA); + } + + tuna_otg->otg.state = OTG_STATE_A_IDLE; + tuna_otg->otg.default_a = true; + tuna_otg->otg.last_event = USB_EVENT_ID; + atomic_notifier_call_chain(&tuna_otg->otg.notifier, + USB_EVENT_ID, + tuna_otg->otg.gadget); + break; + case FSA9480_DETECT_NONE: + tuna_mux_usb_to_fsa(true); + + switch (old_device) { + case FSA9480_DETECT_JIG: + if (tuna_otg->uart_manual_mode == TUNA_MANUAL_UART_NONE) + tuna_ap_uart_actions(tuna_otg); + break; + case FSA9480_DETECT_USB: + if (tuna_otg->usb_manual_mode == TUNA_MANUAL_USB_MODEM) + tuna_cp_usb_detach(tuna_otg); + else + tuna_ap_usb_detach(tuna_otg); + break; + case FSA9480_DETECT_UART: + break; + case FSA9480_DETECT_USB_HOST: + case FSA9480_DETECT_CHARGER: + default: + tuna_ap_usb_detach(tuna_otg); + break; + }; + break; + case FSA9480_DETECT_JIG: + switch (tuna_otg->uart_manual_mode) { + case TUNA_MANUAL_UART_AP: + tuna_ap_uart_actions(tuna_otg); + break; + case TUNA_MANUAL_UART_LTE: + tuna_lte_uart_actions(tuna_otg); + break; + case TUNA_MANUAL_UART_MODEM: + default: + tuna_cp_uart_actions(tuna_otg); + break; + }; + break; + case FSA9480_DETECT_UART: + break; + } + + mutex_unlock(&tuna_otg->lock); +} + +static struct fsa9480_detect_set fsa_detect_sets[] = { + { + .prio = TUNA_OTG_ID_FSA9480_PRIO, + .mask = FSA9480_DETECT_ALL & ~FSA9480_DETECT_USB_HOST, + }, + { + .prio = TUNA_OTG_ID_FSA9480_LAST_PRIO, + .mask = FSA9480_DETECT_USB_HOST, + .fallback = true, + }, +}; + +static struct fsa9480_platform_data tuna_fsa9480_pdata = { + .detect_time = 500, + .detect_sets = fsa_detect_sets, + .num_sets = ARRAY_SIZE(fsa_detect_sets), + + .enable = tuna_mux_usb_to_fsa, + .detected = tuna_fsa_usb_detected, +}; + +static struct i2c_board_info __initdata tuna_connector_i2c4_boardinfo[] = { + { + I2C_BOARD_INFO("fsa9480", 0x4A >> 1), + .irq = OMAP_GPIO_IRQ(GPIO_JACK_INT_N), + .platform_data = &tuna_fsa9480_pdata, + }, +}; + +static int tuna_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host) +{ + otg->host = host; + if (!host) + otg->state = OTG_STATE_UNDEFINED; + return 0; +} + +static int tuna_otg_set_peripheral(struct otg_transceiver *otg, + struct usb_gadget *gadget) +{ + otg->gadget = gadget; + if (!gadget) + otg->state = OTG_STATE_UNDEFINED; + return 0; +} + +static int tuna_otg_set_vbus(struct otg_transceiver *otg, bool enabled) +{ + dev_dbg(otg->dev, "vbus %s\n", enabled ? "on" : "off"); + return 0; +} + +static int tuna_otg_phy_init(struct otg_transceiver *otg) +{ + if (otg->last_event == USB_EVENT_ID) + omap4430_phy_power(otg->dev, 1, 1); + else + omap4430_phy_power(otg->dev, 0, 1); + return 0; +} + +static void tuna_otg_phy_shutdown(struct otg_transceiver *otg) +{ + omap4430_phy_power(otg->dev, 0, 0); +} + +static int tuna_otg_set_suspend(struct otg_transceiver *otg, int suspend) +{ + return omap4430_phy_suspend(otg->dev, suspend); +} + +static ssize_t tuna_otg_usb_sel_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tuna_otg *tuna_otg = dev_get_drvdata(dev); + const char* mode; + + switch (tuna_otg->usb_manual_mode) { + case TUNA_MANUAL_USB_AP: + mode = "PDA"; + break; + case TUNA_MANUAL_USB_MODEM: + mode = "MODEM"; + break; + default: + mode = "NONE"; + }; + + return sprintf(buf, "%s\n", mode); +} + +static ssize_t tuna_otg_usb_sel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tuna_otg *tuna_otg = dev_get_drvdata(dev); + size_t len = strlen(buf); + int old_mode; + + mutex_lock(&tuna_otg->lock); + + old_mode = tuna_otg->usb_manual_mode; + + if (!strncasecmp(buf, "PDA", 3) && len == 4) { + tuna_otg->usb_manual_mode = TUNA_MANUAL_USB_AP; + + /* If we are transitioning from CP USB to AP USB then notify the + * USB stack that is now attached. + */ + if (tuna_otg->current_device == FSA9480_DETECT_USB && + old_mode == TUNA_MANUAL_USB_MODEM) { + tuna_cp_usb_detach(tuna_otg); + tuna_ap_usb_attach(tuna_otg); + } + } else if (!strncasecmp(buf, "MODEM", 5) && len == 6) { + tuna_otg->usb_manual_mode = TUNA_MANUAL_USB_MODEM; + + /* If we are transitioning from AP USB to CP USB then notify the + * USB stack that is has been detached. + */ + if (tuna_otg->current_device == FSA9480_DETECT_USB && + (old_mode == TUNA_MANUAL_USB_AP || + old_mode == TUNA_MANUAL_USB_NONE)) { + tuna_ap_usb_detach(tuna_otg); + tuna_cp_usb_attach(tuna_otg); + } + } else if (!strncasecmp(buf, "NONE", 5) && len == 5) { + tuna_otg->usb_manual_mode = TUNA_MANUAL_USB_NONE; + + /* If we are transitioning from CP USB to AP USB then notify the + * USB stack that it is now attached. + */ + if (tuna_otg->current_device == FSA9480_DETECT_USB && + old_mode == TUNA_MANUAL_USB_MODEM) { + tuna_cp_usb_detach(tuna_otg); + tuna_ap_usb_attach(tuna_otg); + } + } + + mutex_unlock(&tuna_otg->lock); + + return len; +} + +static ssize_t tuna_otg_uart_switch_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tuna_otg *tuna_otg = dev_get_drvdata(dev); + const char* mode; + + switch (tuna_otg->uart_manual_mode) { + case TUNA_MANUAL_UART_AP: + mode = "PDA"; + break; + case TUNA_MANUAL_UART_MODEM: + mode = "MODEM"; + break; + case TUNA_MANUAL_UART_LTE: + mode = "LTEMODEM"; + break; + default: + mode = "NONE"; + }; + + return sprintf(buf, "%s\n", mode); +} + +static ssize_t tuna_otg_uart_switch_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tuna_otg *tuna_otg = dev_get_drvdata(dev); + size_t len = strlen(buf); + + mutex_lock(&tuna_otg->lock); + + if (!strncasecmp(buf, "PDA", 3) && len == 4) { + tuna_otg->uart_manual_mode = TUNA_MANUAL_UART_AP; + + if (tuna_otg->current_device == FSA9480_DETECT_JIG) + tuna_ap_uart_actions(tuna_otg); + } else if (!strncasecmp(buf, "MODEM", 5) && len == 6) { + tuna_otg->uart_manual_mode = TUNA_MANUAL_UART_MODEM; + + if (tuna_otg->current_device == FSA9480_DETECT_JIG) + tuna_cp_uart_actions(tuna_otg); + } else if (!strncasecmp(buf, "LTEMODEM", 8) && len == 9 && + omap4_tuna_get_type() == TUNA_TYPE_TORO) { + tuna_otg->uart_manual_mode = TUNA_MANUAL_UART_LTE; + + if (tuna_otg->current_device == FSA9480_DETECT_JIG) + tuna_lte_uart_actions(tuna_otg); + } else if (!strncasecmp(buf, "NONE", 5) && len == 5) { + tuna_otg->uart_manual_mode = TUNA_MANUAL_UART_NONE; + + if (tuna_otg->current_device == FSA9480_DETECT_JIG) + tuna_ap_uart_actions(tuna_otg); + } + + mutex_unlock(&tuna_otg->lock); + + return len; +} + +#define OMAP_HDMI_HPD_ADDR 0x4A100098 +#define OMAP_HDMI_PULLTYPE_MASK 0x00000010 +static void sii9234_power(int on) +{ + struct omap_mux_partition *p = omap_mux_get("core"); + + u16 mux; + + mux = omap_mux_read(p, OMAP4_CTRL_MODULE_PAD_HDMI_HPD_OFFSET); + + if (on) { + gpio_set_value(GPIO_HDMI_EN, 1); + msleep(20); + gpio_set_value(GPIO_MHL_RST, 1); + + omap_mux_write(p, mux | OMAP_PULL_UP, + OMAP4_CTRL_MODULE_PAD_HDMI_HPD_OFFSET); + } else { + omap_mux_write(p, mux & ~OMAP_PULL_UP, + OMAP4_CTRL_MODULE_PAD_HDMI_HPD_OFFSET); + + gpio_set_value(GPIO_HDMI_EN, 0); + gpio_set_value(GPIO_MHL_RST, 0); + + } +} + +static void sii9234_enable_vbus(bool enable) +{ + +} + +static void sii9234_vbus_present(bool on) +{ + struct tuna_otg *tuna_otg = &tuna_otg_xceiv; + + tuna_otg->otg.state = OTG_STATE_B_IDLE; + tuna_otg->otg.default_a = false; + tuna_otg->otg.last_event = on ? USB_EVENT_VBUS : USB_EVENT_NONE; + atomic_notifier_call_chain(&tuna_otg->otg.notifier, + on ? USB_EVENT_VBUS : USB_EVENT_NONE, + tuna_otg->otg.gadget); +} + +static struct sii9234_platform_data sii9234_pdata = { + .prio = TUNA_OTG_ID_SII9234_PRIO, + .enable = tuna_mux_usb_to_mhl, + .power = sii9234_power, + .enable_vbus = sii9234_enable_vbus, + .vbus_present = sii9234_vbus_present, +}; + +static struct i2c_board_info __initdata tuna_i2c5_boardinfo[] = { + { + I2C_BOARD_INFO("sii9234_mhl_tx", 0x72>>1), + .irq = OMAP_GPIO_IRQ(GPIO_MHL_INT), + .platform_data = &sii9234_pdata, + }, + { + I2C_BOARD_INFO("sii9234_tpi", 0x7A>>1), + .platform_data = &sii9234_pdata, + }, + { + I2C_BOARD_INFO("sii9234_hdmi_rx", 0x92>>1), + .platform_data = &sii9234_pdata, + }, + { + I2C_BOARD_INFO("sii9234_cbus", 0xC8>>1), + .platform_data = &sii9234_pdata, + }, +}; + +int __init omap4_tuna_connector_init(void) +{ + struct tuna_otg *tuna_otg = &tuna_otg_xceiv; + int ret; + + if (omap4_tuna_get_revision() >= 3) { + gpio_request(GPIO_MHL_SEL, "fsa3200_mhl_sel"); + gpio_request(GPIO_AP_SEL, "fsa3200_ap_sel"); + + tuna_fsa3200_mux_pair(TUNA_USB_MUX_DEFAULT); + + omap_mux_init_gpio(GPIO_MHL_SEL, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(GPIO_AP_SEL, OMAP_PIN_OUTPUT); + } else { + gpio_request(GPIO_MUX3_SEL0, "usb_mux3_sel0"); + gpio_request(GPIO_MUX3_SEL1, "usb_mux3_sel1"); + gpio_request(GPIO_USB_ID_SEL, "usb_id_sel"); + + tuna_mux_usb(TUNA_USB_MUX_DEFAULT); + tuna_mux_usb_id(TUNA_USB_MUX_DEFAULT); + + omap_mux_init_gpio(GPIO_MUX3_SEL0, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(GPIO_MUX3_SEL1, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(GPIO_USB_ID_SEL, OMAP_PIN_OUTPUT); + } + + if (omap4_tuna_get_type() == TUNA_TYPE_MAGURO) { + gpio_request(GPIO_CP_USB_ON, "cp_usb_on"); + omap_mux_init_gpio(GPIO_CP_USB_ON, OMAP_PIN_OUTPUT); + gpio_direction_output(GPIO_CP_USB_ON, 0); + } + + omap_mux_init_gpio(GPIO_IF_UART_SEL, OMAP_PIN_OUTPUT); + gpio_request(GPIO_IF_UART_SEL, "uart_sel"); + gpio_direction_output(GPIO_IF_UART_SEL, IF_UART_SEL_DEFAULT); + + omap_mux_init_gpio(GPIO_JACK_INT_N, + OMAP_PIN_INPUT_PULLUP | + OMAP_PIN_OFF_INPUT_PULLUP); + + mutex_init(&tuna_otg->lock); + + device_initialize(&tuna_otg->dev); + dev_set_name(&tuna_otg->dev, "%s", "tuna_otg"); + ret = device_add(&tuna_otg->dev); + if (ret) { + pr_err("%s: cannot reg device '%s' (%d)\n", __func__, + dev_name(&tuna_otg->dev), ret); + return ret; + } + + dev_set_drvdata(&tuna_otg->dev, tuna_otg); + + tuna_otg->otg.dev = &tuna_otg->dev; + tuna_otg->otg.label = "tuna_otg_xceiv"; + tuna_otg->otg.set_host = tuna_otg_set_host; + tuna_otg->otg.set_peripheral = tuna_otg_set_peripheral; + tuna_otg->otg.set_suspend = tuna_otg_set_suspend; + tuna_otg->otg.set_vbus = tuna_otg_set_vbus; + tuna_otg->otg.init = tuna_otg_phy_init; + tuna_otg->otg.shutdown = tuna_otg_phy_shutdown; + + ATOMIC_INIT_NOTIFIER_HEAD(&tuna_otg->otg.notifier); + + ret = otg_set_transceiver(&tuna_otg->otg); + if (ret) + pr_err("tuna_otg: cannot set transceiver (%d)\n", ret); + + omap4430_phy_init(&tuna_otg->dev); + tuna_otg_set_suspend(&tuna_otg->otg, 0); + + i2c_register_board_info(4, tuna_connector_i2c4_boardinfo, + ARRAY_SIZE(tuna_connector_i2c4_boardinfo)); + + ret = sysfs_create_group(&tuna_otg->dev.kobj, &manual_mode_group); + if (ret) + pr_err("tuna_otg: Unable to create manual mode sysfs group" + "(%d)\n", ret); + + gpio_request(GPIO_HDMI_EN, NULL); + omap_mux_init_gpio(GPIO_HDMI_EN, OMAP_PIN_OUTPUT); + gpio_direction_output(GPIO_HDMI_EN, 0); + + gpio_request(GPIO_MHL_RST, NULL); + omap_mux_init_gpio(GPIO_MHL_RST, OMAP_PIN_OUTPUT); + gpio_direction_output(GPIO_MHL_RST, 0); + + gpio_request(GPIO_MHL_INT, NULL); + omap_mux_init_gpio(GPIO_MHL_INT, OMAP_PIN_INPUT); + gpio_direction_input(GPIO_MHL_INT); + + gpio_request(TUNA_GPIO_HDMI_HPD, NULL); + omap_mux_init_gpio(TUNA_GPIO_HDMI_HPD, OMAP_PIN_INPUT | OMAP_PULL_ENA); + gpio_direction_input(TUNA_GPIO_HDMI_HPD); + + i2c_register_board_info(5, tuna_i2c5_boardinfo, + ARRAY_SIZE(tuna_i2c5_boardinfo)); + + return 0; +} diff --git a/arch/arm/mach-omap2/board-tuna-display.c b/arch/arm/mach-omap2/board-tuna-display.c new file mode 100644 index 0000000..f975b08 --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-display.c @@ -0,0 +1,955 @@ +/* Display panel support for Samsung Tuna Board. + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/kernel.h> +#include <linux/omapfb.h> +#include <linux/regulator/consumer.h> + +#include <linux/platform_data/panel-s6e8aa0.h> + +#include <plat/vram.h> + +#include <video/omapdss.h> +#include <video/omap-panel-generic-dpi.h> + +#include "board-tuna.h" +#include "control.h" +#include "mux.h" + +#define TUNA_FB_RAM_SIZE SZ_16M /* ~1280*720*4 * 2 */ + +#define TUNA_GPIO_MLCD_RST 23 + +/* 4.65" Panel ID Info (D1h 1st Para) */ +#define M3 0xA1 +#define SM2 0x12 + +static unsigned int panel_id; +struct regulator *tuna_oled_reg; +struct regulator *tuna_oled_reg_iovcc; + + +static void tuna_oled_set_power(bool enable) +{ + if (IS_ERR_OR_NULL(tuna_oled_reg)) { + tuna_oled_reg = regulator_get(NULL, "vlcd"); + if (IS_ERR_OR_NULL(tuna_oled_reg)) { + pr_err("Can't get vlcd for display!\n"); + return; + } + } + + if (omap4_tuna_get_revision() >= 5) { + if (IS_ERR_OR_NULL(tuna_oled_reg_iovcc)) { + tuna_oled_reg_iovcc = regulator_get(NULL, "vlcd-iovcc"); + if (IS_ERR_OR_NULL(tuna_oled_reg_iovcc)) { + pr_err("Can't get vlcd for display!\n"); + return; + } + } + + if (enable) { + regulator_enable(tuna_oled_reg_iovcc); + regulator_enable(tuna_oled_reg); + } else { + regulator_disable(tuna_oled_reg); + regulator_disable(tuna_oled_reg_iovcc); + } + } else { + if (enable) + regulator_enable(tuna_oled_reg); + else + regulator_disable(tuna_oled_reg); + } +} + +static const struct s6e8aa0_acl_parameters tuna_oled_acl[] = { + { + .cd = 40, + .acl_val = 43, + .regs = { + 0xC1, /* ACL Control2 Register */ + 0x47, + 0x53, + 0x13, + 0x53, + 0x00, + 0x00, + 0x02, + 0xCF, + 0x00, + 0x00, + 0x04, + 0xFF, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + 0x07, + 0x0D, + 0x14, + 0x1A, + 0x20, + 0x26, + 0x2C, + 0x33, + 0x39, + 0x3F, + }, + }, + { + .cd = 300, + .acl_val = 45, + .regs = { + 0xC1, /* ACL Control2 Register */ + 0x47, + 0x53, + 0x13, + 0x53, + 0x00, + 0x00, + 0x02, + 0xCF, + 0x00, + 0x00, + 0x04, + 0xFF, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + 0x07, + 0x0E, + 0x14, + 0x1B, + 0x21, + 0x27, + 0x2E, + 0x34, + 0x3B, + 0x41, + }, + }, +}; + +static const struct s6e8aa0_elvss_parameters tuna_oled_elvss[] = { + { + .cd = 100, + .elvss_val = 0x11, + }, + { + .cd = 160, + .elvss_val = 0x0D, + }, + { + .cd = 200, + .elvss_val = 0x08, + }, + { + .cd = 300, + .elvss_val = 0x00, + }, +}; + +static const u8 tuna_oled_cmd_init_pre0[] = { + 0xF0, + 0x5A, + 0x5A, +}; + +static const u8 tuna_oled_cmd_init_pre1[] = { + 0xF1, + 0x5A, + 0x5A, +}; + +static const u8 tuna_oled_cmd_sleep_out[] = { + 0x11, +}; + +static const u8 tuna_oled_cmd_init_panel_m3[] = { + 0xF8, /* Panel Condition Set */ + 0x3D, /* DOTC[0:1], GTCON[2:4], SS, DOTC_H[6:7] */ + 0x35, /* FLTE[0:7] */ + 0x00, + 0x00, + 0x00, + 0x8D, + 0x00, + 0x4C, /* SCTE[0:7] */ + 0x6E, + 0x10, + 0x27, + 0x7D, /* INTE[0:7] */ + 0x3F, /* INWE[0:7] */ + 0x10, + 0x00, + 0x00, + 0x20, + 0x04, /* E_FLWE_H[0:7] */ + 0x08, /* E_SCTE[0:7] */ + 0x6E, /* E_SCWE[0:7] */ + 0x00, + 0x00, + 0x00, + 0x02, + 0x08, + 0x08, + 0x23, + 0x23, + 0xC0, + 0xC8, /* CLK2_CON[0:2], CLK1_CON[3:5], CLK2_DC, CLK1_DC */ + 0x08, /* INT2_CON[0:2], INT1_CON[3:5], INT2_DC, INT1_DC */ + 0x48, /* BICTLB_CON[0:2], BICTL_CON[3:5], BICTLB_DC, BICTL_DC */ + 0xC1, + 0x00, + 0xC3, /* EM_FLM_CON[0:2], ACL_FLM_CON[3:5], EM_FLM_DC, ACL_FLM_DC */ + 0xFF, /* EM_CLK1B_CON[0:2], EM_CLK1_CON[3:5], EM_CLK1B_DC, EM_CLK1_DC */ + 0xFF, /* EM_CLK2B_CON[0:2], EM_CLK2_CON[3:5], EM_CLK2B_DC, EM_CLK2_DC */ + 0xC8, /* EM_INT2_CON[0:2], EM_INT1_CON[3:5], EM_INT2_DC, EM_INT1_DC */ +}; + +static const u8 tuna_oled_cmd_init_panel_sm2[] = { + 0xF8, /* Panel Condition Set */ + 0x3D, /* DOTC[0:1], GTCON[2:4], SS, DOTC_H[6:7] */ + 0x35, /* FLTE[0:7] */ + 0x00, + 0x00, + 0x00, + 0x93, /* FLWE */ + 0x00, + 0x3C, /* SCTE[0:7] */ + 0x7D, /* SCWE */ + 0x08, /* INTE */ + 0x27, + 0x7D, /* INTE[0:7] */ + 0x3F, /* INWE[0:7] */ + 0x00, /* EMPS */ + 0x00, + 0x00, + 0x20, + 0x04, /* E_FLWE_H[0:7] */ + 0x08, /* E_SCTE[0:7] */ + 0x6E, /* E_SCWE[0:7] */ + 0x00, + 0x00, + 0x00, + 0x02, + 0x08, + 0x08, + 0x23, + 0x23, + 0xC0, + 0xC8, /* CLK2_CON[0:2], CLK1_CON[3:5], CLK2_DC, CLK1_DC */ + 0x08, /* INT2_CON[0:2], INT1_CON[3:5], INT2_DC, INT1_DC */ + 0x48, /* BICTLB_CON[0:2], BICTL_CON[3:5], BICTLB_DC, BICTL_DC */ + 0xC1, + 0x00, + 0xC1, /* EM_FLM_CON[0:2], ACL_FLM_CON[3:5], EM_FLM_DC, ACL_FLM_DC */ + 0xFF, /* EM_CLK1B_CON[0:2], EM_CLK1_CON[3:5], EM_CLK1B_DC, EM_CLK1_DC */ + 0xFF, /* EM_CLK2B_CON[0:2], EM_CLK2_CON[3:5], EM_CLK2B_DC, EM_CLK2_DC */ + 0xC8, /* EM_INT2_CON[0:2], EM_INT1_CON[3:5], EM_INT2_DC, EM_INT1_DC */ +}; + +static const u8 tuna_oled_cmd_init_display[] = { + 0xF2, /* Display Condition set */ + 0x80, /* Display area */ + 0x03, /* VBP : 3 HsYNC */ + 0x0D, /* VFP : 13HSYNC */ +}; + +static const struct s6e8aa0_sequence_entry tuna_oled_seq_display_set_m3[] = { + { + .cmd = tuna_oled_cmd_init_pre0, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_pre0), + }, + { + .cmd = tuna_oled_cmd_sleep_out, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_sleep_out), + }, + { + .cmd = tuna_oled_cmd_init_panel_m3, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_panel_m3), + }, + { + .cmd = tuna_oled_cmd_init_display, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_display), + }, +}; + +static const struct s6e8aa0_sequence_entry tuna_oled_seq_display_set_sm2[] = { + { + .cmd = tuna_oled_cmd_init_pre0, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_pre0), + }, + { + .cmd = tuna_oled_cmd_init_pre1, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_pre1), + }, + { + .cmd = tuna_oled_cmd_sleep_out, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_sleep_out), + }, + { + .cmd = tuna_oled_cmd_init_panel_sm2, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_panel_sm2), + }, + { + .cmd = tuna_oled_cmd_init_display, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_display), + }, +}; + +static const u8 tuna_oled_cmd_gamma_ltps_update[] = { + 0xF7, + 0x03, /* Gamma/LTPS update */ +}; + +static const u8 tuna_oled_cmd_init_post0[] = { + 0xF6, + 0x00, + 0x02, + 0x00, +}; + +static const u8 tuna_oled_cmd_init_post1[] = { + 0xB6, + 0x0C, + 0x02, + 0x03, + 0x32, + 0xFF, + 0x44, + 0x44, + 0xC0, + 0x00, +}; + +static const u8 tuna_oled_cmd_init_post2_m3[] = { + 0xD9, + 0x14, + 0x40, + 0x0C, + 0xCB, + 0xCE, + 0x6E, + 0xC4, + 0x07, /* COLUMN_CHOP, FRAME_CHOP, LINE_CHOP, CHOP_EN */ + 0x40, + 0x40, /* ELVSS_CON : 0 */ + 0xD0, /* ELVSS -4.9V */ + 0x00, + 0x60, + 0x19, +}; + +static const u8 tuna_oled_cmd_power_ctrl_m3[] = { + 0xF4, /* Power Control */ + 0xCF, + 0x0A, + 0x0F, /* Vreg1 : 4.5V(default) */ + 0x10, /* VGH : 5.2v(default) */ + 0x19, /* VGL : -7.0v(default) */ + 0x33, + 0x02, +}; + +static const u8 tuna_oled_cmd_init_post2_sm2[] = { + 0xD9, + 0x14, + 0x40, + 0x0C, + 0xCB, + 0xCE, + 0x6E, + 0xC4, + 0x07, /* COLUMN_CHOP, FRAME_CHOP, LINE_CHOP, CHOP_EN */ + 0x40, + 0x41, /* ELVSS_CON : 1 */ + 0xD0, /* ELVSS -4.9V */ + 0x00, + 0x60, + 0x19, +}; + +static const u8 tuna_oled_cmd_power_ctrl_sm2[] = { + 0xF4, /* Power Control */ + 0xCF, + 0x0A, + 0x12, /* Vreg1 : 4.6V */ + 0x10, /* VGH : 5.2v(default) */ + 0x1E, /* VGL : -8.0v */ + 0x33, + 0x02, +}; + +static const u8 tuna_oled_cmd_display_on[] = { + 0x29, +}; + +static const struct s6e8aa0_sequence_entry tuna_oled_seq_etc_set_m3[] = { + { + .cmd = tuna_oled_cmd_gamma_ltps_update, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_gamma_ltps_update), + }, + { + .cmd = tuna_oled_cmd_init_post0, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_post0), + }, + { + .cmd = tuna_oled_cmd_init_post1, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_post1), + }, + { + .cmd = tuna_oled_cmd_init_post2_m3, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_post2_m3), + }, + { + .cmd = tuna_oled_cmd_power_ctrl_m3, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_power_ctrl_m3), + .msleep = 120, + }, + { + .cmd = tuna_oled_cmd_display_on, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_display_on), + }, +}; + +static const struct s6e8aa0_sequence_entry tuna_oled_seq_etc_set_sm2[] = { + { + .cmd = tuna_oled_cmd_gamma_ltps_update, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_gamma_ltps_update), + }, + { + .cmd = tuna_oled_cmd_init_post0, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_post0), + }, + { + .cmd = tuna_oled_cmd_init_post1, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_post1), + }, + { + .cmd = tuna_oled_cmd_init_post2_sm2, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_init_post2_sm2), + }, + { + .cmd = tuna_oled_cmd_power_ctrl_sm2, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_power_ctrl_sm2), + .msleep = 120, + }, + { + .cmd = tuna_oled_cmd_display_on, + .cmd_len = ARRAY_SIZE(tuna_oled_cmd_display_on), + }, +}; + +static const struct s6e8aa0_gamma_entry tuna_oled_gamma_table_m3[] = { + { BV_0, { 4500000, 4500000, 4500000, }, }, + { 0x00000001, { 4350000, 4350000, 4350000, }, }, + { 0x0001F8F0, { 4320166, 4338185, 4200000, }, }, + { 0x0002F71F, { 4305148, 4332238, 4102500, }, }, + { 0x00038485, { 4296793, 4328930, 4065000, }, }, + { 0x00053C55, { 4270807, 4318639, 3982500, }, }, + { 0x00060EEF, { 4258364, 4313711, 3960000, }, }, + { 0x00075444, { 4239141, 4306099, 3930000, }, }, + { 0x00095733, { 4208717, 4294050, 3892500, }, }, + { 0x000EC060, { 4126874, 4261640, 3810000, }, }, + { 0x00129EAB, { 4068363, 4238469, 3757500, }, }, + { 0x00179214, { 3993478, 4208813, 3720000, }, }, + { 0x001A47A0, { 3952500, 4192586, 3712500, }, }, + { 0x0025E12C, { 3802500, 4123103, 3682500, }, }, + { 0x002D413D, { 3756465, 4078926, 3673450, }, }, + { 0x0035D13F, { 3741586, 4027637, 3659844, }, }, + { 0x00400000, { 3726401, 3966643, 3645758, }, }, + { 0x004C1BF8, { 3710894, 3894110, 3631166, }, }, + { 0x005A827A, { 3695052, 3855649, 3616042, }, }, + { 0x006BA27E, { 3678859, 3823316, 3600360, }, }, + { 0x00800000, { 3662298, 3794488, 3584091, }, }, + { 0x009837F0, { 3645351, 3767841, 3567202, }, }, + { 0x00B504F3, { 3627999, 3742607, 3549662, }, }, + { 0x00D744FD, { 3610220, 3718295, 3531434, }, }, + { 0x01000000, { 3591992, 3694568, 3512481, }, }, + { 0x01306FE1, { 3573291, 3671183, 3492761, }, }, + { 0x016A09E6, { 3554089, 3647957, 3472232, }, }, + { 0x01AE89FA, { 3534358, 3624743, 3450847, }, }, + { 0x02000000, { 3514065, 3601422, 3428554, }, }, + { 0x0260DFC1, { 3493177, 3577893, 3405301, }, }, + { 0x02D413CD, { 3471654, 3554067, 3381029, }, }, + { 0x035D13F3, { 3449455, 3529864, 3355676, }, }, + { 0x04000000, { 3426534, 3505211, 3329174, }, }, + { 0x04C1BF83, { 3402839, 3480034, 3301451, }, }, + { 0x05A8279A, { 3378312, 3454264, 3272429, }, }, + { 0x06BA27E6, { 3352890, 3427831, 3242021, }, }, + { 0x08000000, { 3326501, 3400661, 3210138, }, }, + { 0x09837F05, { 3299062, 3372679, 3176678, }, }, + { 0x0B504F33, { 3270483, 3343804, 3141535, }, }, + { 0x0D744FCD, { 3240658, 3313948, 3104592, }, }, + { 0x10000000, { 3209466, 3283015, 3065722, }, }, + { 0x1306FE0A, { 3176767, 3250899, 3024787, }, }, + { 0x16A09E66, { 3142400, 3217481, 2981638, }, }, + { 0x1AE89F99, { 3106171, 3182624, 2936111, }, }, + { 0x20000000, { 3067855, 3146174, 2888031, }, }, + { 0x260DFC14, { 3027178, 3107951, 2837203, }, }, + { 0x2D413CCD, { 2983809, 3067744, 2783420, }, }, + { 0x35D13F32, { 2937340, 3025303, 2726454, }, }, + { 0x40000000, { 2887259, 2980328, 2666057, }, }, + { 0x4C1BF828, { 2832912, 2932454, 2601961, }, }, + { 0x5A82799A, { 2773444, 2881230, 2533878, }, }, + { 0x6BA27E65, { 2707706, 2826086, 2461495, }, }, + { 0x80000000, { 2639098, 2766291, 2384478, }, }, + { 0x9837F051, { 2560291, 2700878, 2302469, }, }, + { 0xB504F333, { 2472698, 2628531, 2215093, }, }, + { 0xD744FCCA, { 2375331, 2547389, 2121959, }, }, + { 0xFFFFFFFF, { 2266945, 2454682, 2022667, }, }, +}; + +static const struct s6e8aa0_gamma_entry tuna_oled_gamma_table_sm2[] = { + { BV_0, { 4600000, 4600000, 4600000, }, }, + { 0x00000001, { 4561667, 4561667, 4561667, }, }, + { 0x000004C2, { 4102930, 4561654, 4561115, }, }, + { 0x000005A8, { 4093308, 4561651, 3799195, }, }, + { 0x000006BA, { 4083466, 4561645, 3793888, }, }, + { 0x00000800, { 4073413, 4561639, 3788484, }, }, + { 0x00000983, { 4063166, 4561630, 3782992, }, }, + { 0x00000B50, { 4052685, 4561618, 3777391, }, }, + { 0x00000D74, { 4041989, 4561602, 3771689, }, }, + { 0x00001000, { 4031064, 4561582, 3765880, }, }, + { 0x00001307, { 4019915, 4561555, 3759964, }, }, + { 0x000016A1, { 4008527, 4561519, 3753935, }, }, + { 0x00001AE9, { 3996905, 4561472, 3747792, }, }, + { 0x00002000, { 3985042, 4561410, 3741533, }, }, + { 0x0000260E, { 3972926, 4561328, 3735148, }, }, + { 0x00002D41, { 3960557, 4561219, 3728639, }, }, + { 0x000035D1, { 3947926, 4561076, 3721998, }, }, + { 0x00004000, { 3935029, 4560888, 3715222, }, }, + { 0x00004C1C, { 3921862, 4560639, 3708307, }, }, + { 0x00005A82, { 3908420, 4560310, 3701250, }, }, + { 0x00006BA2, { 3894694, 4559877, 3694045, }, }, + { 0x00008000, { 3880678, 4559305, 3686685, }, }, + { 0x00009838, { 3866369, 4558550, 3679168, }, }, + { 0x0000B505, { 3851759, 4557554, 3671487, }, }, + { 0x0000D745, { 3836842, 4556240, 3663637, }, }, + { 0x00010000, { 3821612, 4554507, 3655612, }, }, + { 0x00013070, { 3806062, 4552219, 3647405, }, }, + { 0x00016A0A, { 3790185, 4549200, 3639010, }, }, + { 0x0001AE8A, { 3773975, 4545217, 3630420, }, }, + { 0x00020000, { 3757424, 4539961, 3621628, }, }, + { 0x000260E0, { 3740525, 4533026, 3612625, }, }, + { 0x0002D414, { 3723271, 4523876, 3603405, }, }, + { 0x00035D14, { 3705654, 4511801, 3593959, }, }, + { 0x00040000, { 3687668, 4495869, 3584277, }, }, + { 0x0004C1C0, { 3669303, 4474845, 3574351, }, }, + { 0x0005A828, { 3650553, 4447106, 3564170, }, }, + { 0x0006BA28, { 3631408, 4410503, 3553725, }, }, + { 0x00080000, { 3611862, 4362204, 3543003, }, }, + { 0x0009837F, { 3591904, 4298475, 3531993, }, }, + { 0x000B504F, { 3571527, 4214383, 3520683, }, }, + { 0x000D7450, { 3557593, 4103423, 3509060, }, }, + { 0x00100000, { 3544015, 4010592, 3497110, }, }, + { 0x001306FE, { 3530633, 3962306, 3484817, }, }, + { 0x0016A09E, { 3517328, 3926468, 3472166, }, }, + { 0x001AE8A0, { 3504007, 3896492, 3459141, }, }, + { 0x00200000, { 3490597, 3869832, 3445722, }, }, + { 0x00260DFC, { 3477036, 3845220, 3431893, }, }, + { 0x002D413D, { 3463269, 3821929, 3417630, }, }, + { 0x0035D13F, { 3449251, 3799494, 3402914, }, }, + { 0x00400000, { 3434937, 3777603, 3387721, }, }, + { 0x004C1BF8, { 3420287, 3756027, 3372025, }, }, + { 0x005A827A, { 3405262, 3734596, 3355799, }, }, + { 0x006BA27E, { 3389824, 3713176, 3339016, }, }, + { 0x00800000, { 3373936, 3691658, 3321643, }, }, + { 0x009837F0, { 3357560, 3669948, 3303646, }, }, + { 0x00B504F3, { 3340656, 3647968, 3284991, }, }, + { 0x00D744FD, { 3323186, 3625646, 3265636, }, }, + { 0x01000000, { 3305106, 3602915, 3245540, }, }, + { 0x01306FE1, { 3286372, 3579714, 3224657, }, }, + { 0x016A09E6, { 3266937, 3555983, 3202935, }, }, + { 0x01AE89FA, { 3246751, 3531662, 3180321, }, }, + { 0x02000000, { 3225759, 3506692, 3156754, }, }, + { 0x0260DFC1, { 3203902, 3481011, 3132167, }, }, + { 0x02D413CD, { 3181115, 3454554, 3106490, }, }, + { 0x035D13F3, { 3157329, 3427255, 3079643, }, }, + { 0x04000000, { 3132467, 3399041, 3051538, }, }, + { 0x04C1BF83, { 3106444, 3369833, 3022078, }, }, + { 0x05A8279A, { 3079166, 3339546, 2991155, }, }, + { 0x06BA27E6, { 3050528, 3308086, 2958650, }, }, + { 0x08000000, { 3020414, 3275348, 2924429, }, }, + { 0x09837F05, { 2988694, 3241215, 2888342, }, }, + { 0x0B504F33, { 2955220, 3205555, 2850219, }, }, + { 0x0D744FCD, { 2919827, 3168219, 2809871, }, }, + { 0x10000000, { 2882325, 3129034, 2767081, }, }, + { 0x1306FE0A, { 2842499, 3087803, 2721603, }, }, + { 0x16A09E66, { 2800102, 3044294, 2673154, }, }, + { 0x1AE89F99, { 2754846, 2998238, 2621408, }, }, + { 0x20000000, { 2706399, 2949314, 2565989, }, }, + { 0x260DFC14, { 2654372, 2897137, 2506458, }, }, + { 0x2D413CCD, { 2598304, 2841239, 2442298, }, }, + { 0x35D13F32, { 2537647, 2781048, 2372900, }, }, + { 0x40000000, { 2471743, 2715846, 2297536, }, }, + { 0x4C1BF828, { 2399793, 2644720, 2215328, }, }, + { 0x5A82799A, { 2320814, 2566484, 2125212, }, }, + { 0x6BA27E65, { 2233581, 2479554, 2025874, }, }, + { 0x80000000, { 2136547, 2381755, 1915679, }, }, + { 0x9837F051, { 2027719, 2269975, 1792556, }, }, + { 0xB504F333, { 1904479, 2139541, 1653843, }, }, + { 0xD744FCCA, { 1763299, 1982960, 1496041, }, }, + { 0xFFFFFFFF, { 1599291, 1787064, 1314455, }, }, +}; + +static struct s6e8aa0_factory_calibration_info tuna_oled_factory_info_old = { + .regs = { + [1][0][6] = 0x090, + [1][1][6] = 0x081, + [1][2][6] = 0x0c5, + }, + .brightness = { + [1][6] = BV_255, /* 300 cd/m2 */ + }, + .color_adj = { + /* Convert from 8500K to D65, assuming: + * Rx 0.66950, Ry 0.33100 + * Gx 0.18800, Gy 0.74350 + * Bx 0.14142, By 0.04258 + */ + .mult = { + 2318372099U, + 2117262806U, + 1729744557U, + }, + .rshift = 31, + }, +}; + +static struct s6e8aa0_factory_calibration_info tuna_oled_factory_info_m2t1 = { + .regs = { + [1][0][6] = 0x090, + [1][1][6] = 0x081, + [1][2][6] = 0x0c5, + }, + .brightness = { + [1][6] = BV_255, /* 300 cd/m2 */ + }, +}; + +static struct s6e8aa0_factory_calibration_info tuna_oled_factory_info_8500k = { + .regs = { + [1][0][0] = 0x0f, + [1][1][0] = 0x0f, + [1][2][0] = 0x0f, + + [1][0][1] = 0xcc, + [1][1][1] = 0x9c, + [1][2][1] = 0xd7, + + [1][0][2] = 0xc1, + [1][1][2] = 0xba, + [1][2][2] = 0xc1, + + [1][0][3] = 0xcf, + [1][1][3] = 0xcd, + [1][2][3] = 0xcf, + + [1][0][4] = 0xaa, + [1][1][4] = 0xaa, + [1][2][4] = 0xa7, + + [1][0][5] = 0xbe, + [1][1][5] = 0xbe, + [1][2][5] = 0xba, + + [1][0][6] = 0x090, + [1][1][6] = 0x081, + [1][2][6] = 0x0c5, + }, + .brightness = { + [1][4] = 403193777, /* 28.16275996 cd/m2 */ + [1][6] = BV_255, /* 300 cd/m2 */ + }, + .color_adj = { + /* Convert from 8500K to D65, assuming: + * Rx 0.66950, Ry 0.33100 + * Gx 0.18800, Gy 0.74350 + * Bx 0.14142, By 0.04258 + * + * These values are adjusted down by x 0.9333 to bring + * maximum brightness down from 300 cd/m2 to 280. + */ + .mult = { + 2163736680U, + 1976041377U, + 1614370595U, + }, + .rshift = 31, + }, +}; + +static struct s6e8aa0_factory_calibration_info tuna_oled_factory_info_6500k = { + .regs = { + [1][0][0] = 0x7c, /* sRGB Gamma 300cd, 6500K */ + [1][1][0] = 0x3c, + [1][2][0] = 0x87, + + [1][0][1] = 0xbb, + [1][1][1] = 0xd4, + [1][2][1] = 0xa8, + + [1][0][2] = 0xac, + [1][1][2] = 0xc0, + [1][2][2] = 0xa1, + + [1][0][3] = 0xb8, + [1][1][3] = 0xc8, + [1][2][3] = 0xb2, + + [1][0][4] = 0x8c, + [1][1][4] = 0x9f, + [1][2][4] = 0x84, + + [1][0][5] = 0xa7, + [1][1][5] = 0xb2, + [1][2][5] = 0xa3, + + [1][0][6] = 0x0d8, + [1][1][6] = 0x0bd, + [1][2][6] = 0x0f7, + }, + .brightness = { + [1][1] = BV_15, /* 1.43 cd/m2 */ + [1][2] = BV_35, /* 5.04 cd/m2 */ + [1][3] = BV_59, /* 13.12 cd/m2 */ + [1][4] = BV_87, /* 28.59 cd/m2 */ + [1][5] = BV_171, /* 122.17 cd/m2 */ + [1][6] = BV_255, /* 300 cd/m2 */ + }, + .color_adj = { + /* + * These values are adjusted down by x 0.9333 to bring + * maximum brightness down from 300 cd/m2 to 280. + */ + .mult = { + 2004318071U, + 2004318071U, + 2004318071U, + }, + .rshift = 31, + }, +}; + +static struct panel_s6e8aa0_data tuna_oled_data_m3 = { + .reset_gpio = TUNA_GPIO_MLCD_RST, + .set_power = tuna_oled_set_power, + .seq_display_set = tuna_oled_seq_display_set_m3, + .seq_display_set_size = ARRAY_SIZE(tuna_oled_seq_display_set_m3), + .seq_etc_set = tuna_oled_seq_etc_set_m3, + .seq_etc_set_size = ARRAY_SIZE(tuna_oled_seq_etc_set_m3), + .gamma_table = tuna_oled_gamma_table_m3, + .gamma_table_size = ARRAY_SIZE(tuna_oled_gamma_table_m3), + .factory_info = &tuna_oled_factory_info_8500k, + .acl_table = tuna_oled_acl, + .acl_table_size = ARRAY_SIZE(tuna_oled_acl), + .acl_average = 6, /* use 20 frame Y average accumulation count */ +}; + +static struct panel_s6e8aa0_data tuna_oled_data_sm2 = { + .reset_gpio = TUNA_GPIO_MLCD_RST, + .set_power = tuna_oled_set_power, + .seq_display_set = tuna_oled_seq_display_set_sm2, + .seq_display_set_size = ARRAY_SIZE(tuna_oled_seq_display_set_sm2), + .seq_etc_set = tuna_oled_seq_etc_set_sm2, + .seq_etc_set_size = ARRAY_SIZE(tuna_oled_seq_etc_set_sm2), + .gamma_table = tuna_oled_gamma_table_sm2, + .gamma_table_size = ARRAY_SIZE(tuna_oled_gamma_table_sm2), + .factory_info = &tuna_oled_factory_info_6500k, + .acl_table = tuna_oled_acl, + .acl_table_size = ARRAY_SIZE(tuna_oled_acl), + .acl_average = 6, /* use 20 frame Y average accumulation count */ + .elvss_table = tuna_oled_elvss, + .elvss_table_size = ARRAY_SIZE(tuna_oled_elvss), +}; + +static struct omap_dss_device tuna_oled_device = { + .name = "lcd", + .driver_name = "s6e8aa0", + .type = OMAP_DISPLAY_TYPE_DSI, + .data = &tuna_oled_data_m3, + .phy.dsi = { + .type = OMAP_DSS_DSI_TYPE_VIDEO_MODE, + .clk_lane = 1, + .clk_pol = 0, + .data1_lane = 2, + .data1_pol = 0, + .data2_lane = 3, + .data2_pol = 0, + .data3_lane = 4, + .data3_pol = 0, + .data4_lane = 5, + .data4_pol = 0, + }, + .panel = { + .width_in_um = 58000, + .height_in_um = 102000, + }, + .clocks = { + .dispc = { + .channel = { + .lck_div = 1, /* LCD */ + .pck_div = 2, /* PCD */ + .lcd_clk_src + = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, + }, + .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK, + }, + .dsi = { + .regn = 19, /* DSI_PLL_REGN */ + .regm = 236, /* DSI_PLL_REGM */ + + .regm_dispc = 6, /* PLL_CLK1 (M4) */ + .regm_dsi = 6, /* PLL_CLK2 (M5) */ + .lp_clk_div = 8, /* LPDIV */ + .offset_ddr_clk = 122, /* DDR PRE & DDR POST + * offset increase + */ + + .dsi_fclk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, + }, + }, + + .channel = OMAP_DSS_CHANNEL_LCD, +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT + .skip_init = true, +#else + .skip_init = false, +#endif +}; + +static void tuna_hdmi_mux_init(void) +{ + u32 r; + + /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */ + omap_mux_init_signal("hdmi_hpd.hdmi_hpd", + OMAP_PIN_INPUT_PULLDOWN); + omap_mux_init_signal("gpmc_wait2.gpio_100", + OMAP_PIN_INPUT_PULLDOWN); + omap_mux_init_signal("hdmi_cec.hdmi_cec", + OMAP_PIN_INPUT_PULLUP); + /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */ + omap_mux_init_signal("hdmi_ddc_scl.hdmi_ddc_scl", + OMAP_PIN_INPUT_PULLUP); + omap_mux_init_signal("hdmi_ddc_sda.hdmi_ddc_sda", + OMAP_PIN_INPUT_PULLUP); + + /* strong pullup on DDC lines using unpublished register */ + r = ((1 << 24) | (1 << 28)) ; + omap4_ctrl_pad_writel(r, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_1); + +} + +static struct omap_dss_device tuna_hdmi_device = { + .name = "hdmi", + .driver_name = "hdmi_panel", + .type = OMAP_DISPLAY_TYPE_HDMI, + .clocks = { + .dispc = { + .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK, + }, + .hdmi = { + .regn = 15, + .regm2 = 1, + .max_pixclk_khz = 75000, + }, + }, + .hpd_gpio = TUNA_GPIO_HDMI_HPD, + .channel = OMAP_DSS_CHANNEL_DIGIT, +}; + +static struct omap_dss_device *tuna_dss_devices[] = { + &tuna_oled_device, + &tuna_hdmi_device, +}; + +static struct omap_dss_board_info tuna_dss_data = { + .num_devices = ARRAY_SIZE(tuna_dss_devices), + .devices = tuna_dss_devices, + .default_device = &tuna_oled_device, +}; + +static struct omapfb_platform_data tuna_fb_pdata = { + .mem_desc = { + .region_cnt = 1, + .region = { + [0] = { + .size = TUNA_FB_RAM_SIZE, + }, + }, + }, +}; + +void __init omap4_tuna_display_init(void) +{ + struct panel_s6e8aa0_data *panel; + + if (omap4_tuna_get_revision() == + (omap4_tuna_get_type() == TUNA_TYPE_MAGURO ? 2 : 1)) { + /* + * Older devices were not calibrated the same way as newer + * devices. These values are probably not correct, but the older + * devices tested look closer to the newer devices with these + * values than they do using the same register values as the + * newer devices. + */ + tuna_oled_data_m3.factory_info = &tuna_oled_factory_info_m2t1; + } else if (omap4_tuna_get_revision() <= 1) { + tuna_oled_data_m3.factory_info = &tuna_oled_factory_info_old; + } + + if (panel_id == SM2) + panel = &tuna_oled_data_sm2; + else + panel = &tuna_oled_data_m3; + + tuna_oled_device.data = panel; + + omap4_ctrl_pad_writel(0x1FF80000, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY); + omap_mux_init_gpio(panel->reset_gpio, OMAP_PIN_OUTPUT); + + pr_info("Using %ps\n", panel->factory_info); + + omap_vram_set_sdram_vram(TUNA_FB_RAM_SIZE, 0); + omapfb_set_platform_data(&tuna_fb_pdata); + tuna_hdmi_mux_init(); + omap_display_init(&tuna_dss_data); +} + +static int __init get_panel_id(char *str) +{ + long value; + int ret; + + ret = strict_strtol(str, 0, &value); + if (ret < 0) + return ret; + + panel_id = (unsigned int)value; + return 0; +} +__setup("mms_ts.panel_id=", get_panel_id); + diff --git a/arch/arm/mach-omap2/board-tuna-emif.c b/arch/arm/mach-omap2/board-tuna-emif.c new file mode 100644 index 0000000..f7050ae --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-emif.c @@ -0,0 +1,107 @@ +/* + * LPDDR2 data as per SAMSUNG data sheet + * + * Copyright (C) 2011 Texas Instruments, Inc. + * + * Santosh Shilimkar <santosh.shilimkar@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/init.h> + +#include <mach/emif.h> +#include "board-tuna.h" + +const struct lpddr2_timings lpddr2_samsung_timings_400_mhz = { + .max_freq = 400000000, + .RL = 6, + .tRPab = 21, + .tRCD = 18, + .tWR = 15, + .tRASmin = 42, + .tRRD = 10, + .tWTRx2 = 15, + .tXSR = 140, + .tXPx2 = 15, + .tRFCab = 130, + .tRTPx2 = 15, + .tCKE = 3, + .tCKESR = 15, + .tZQCS = 90, + .tZQCL = 360, + .tZQINIT = 1000, + .tDQSCKMAXx2 = 11, + .tRASmax = 70, + .tFAW = 50 +}; + +const struct lpddr2_timings lpddr2_samsung_timings_200_mhz = { + .max_freq = 200000000, + .RL = 3, + .tRPab = 21, + .tRCD = 18, + .tWR = 15, + .tRASmin = 42, + .tRRD = 10, + .tWTRx2 = 20, + .tXSR = 140, + .tXPx2 = 15, + .tRFCab = 130, + .tRTPx2 = 15, + .tCKE = 3, + .tCKESR = 15, + .tZQCS = 90, + .tZQCL = 360, + .tZQINIT = 1000, + .tDQSCKMAXx2 = 11, + .tRASmax = 70, + .tFAW = 50 +}; + +const struct lpddr2_min_tck lpddr2_samsung_min_tck = { + .tRL = 3, + .tRP_AB = 3, + .tRCD = 3, + .tWR = 3, + .tRAS_MIN = 3, + .tRRD = 2, + .tWTR = 2, + .tXP = 2, + .tRTP = 2, + .tCKE = 3, + .tCKESR = 3, + .tFAW = 8 +}; + +struct lpddr2_device_info lpddr2_samsung_4G_S4_dev = { + .device_timings = { + &lpddr2_samsung_timings_200_mhz, + &lpddr2_samsung_timings_400_mhz + }, + .min_tck = &lpddr2_samsung_min_tck, + .type = LPDDR2_TYPE_S4, + .density = LPDDR2_DENSITY_4Gb, + .io_width = LPDDR2_IO_WIDTH_32 +}; + +/* + * LPDDR2 Configuration Data: + * The memory organisation is as below : + * EMIF1 - CS0 - 4 Gb + * EMIF2 - CS0 - 4 Gb + * -------------------- + * TOTAL - 8 Gb + * + * Same devices installed on EMIF1 and EMIF2 + */ +static __initdata struct emif_device_details emif_devices = { + .cs0_device = &lpddr2_samsung_4G_S4_dev, +}; + +void __init omap4_tuna_emif_init(void) +{ + omap_emif_setup_device_details(&emif_devices, &emif_devices); +} diff --git a/arch/arm/mach-omap2/board-tuna-input.c b/arch/arm/mach-omap2/board-tuna-input.c new file mode 100644 index 0000000..8d4d164 --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-input.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/keyreset.h> +#include <linux/gpio_event.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/i2c/atmel_mxt_ts.h> +#include <linux/platform_data/mms_ts.h> +#include <asm/mach-types.h> +#include <plat/omap4-keypad.h> + +#include "board-tuna.h" +#include "mux.h" + +#define GPIO_TOUCH_EN 19 +#define GPIO_TOUCH_IRQ 46 + +/* touch is on i2c3 */ +#define GPIO_TOUCH_SCL 130 +#define GPIO_TOUCH_SDA 131 + +static int mms_ts_panel_id; + +static struct gpio_event_direct_entry tuna_gpio_keypad_keys_map_high[] = { + { + .code = KEY_POWER, + .gpio = 3, + }, +}; + +static struct gpio_event_input_info tuna_gpio_keypad_keys_info_high = { + .info.func = gpio_event_input_func, + .info.no_suspend = true, + .type = EV_KEY, + .keymap = tuna_gpio_keypad_keys_map_high, + .keymap_size = ARRAY_SIZE(tuna_gpio_keypad_keys_map_high), + .flags = GPIOEDF_ACTIVE_HIGH, +}; + +static struct gpio_event_direct_entry tuna_gpio_keypad_keys_map_low[] = { + { + .code = KEY_VOLUMEDOWN, + .gpio = 8, + }, + { + .code = KEY_VOLUMEUP, + .gpio = 30, + }, +}; + +static struct gpio_event_input_info tuna_gpio_keypad_keys_info_low = { + .info.func = gpio_event_input_func, + .info.no_suspend = true, + .type = EV_KEY, + .keymap = tuna_gpio_keypad_keys_map_low, + .keymap_size = ARRAY_SIZE(tuna_gpio_keypad_keys_map_low), +}; + +static struct gpio_event_info *tuna_gpio_keypad_info[] = { + &tuna_gpio_keypad_keys_info_high.info, + &tuna_gpio_keypad_keys_info_low.info, +}; + +static struct gpio_event_platform_data tuna_gpio_keypad_data = { + .name = "tuna-gpio-keypad", + .info = tuna_gpio_keypad_info, + .info_count = ARRAY_SIZE(tuna_gpio_keypad_info) +}; + +static struct platform_device tuna_gpio_keypad_device = { + .name = GPIO_EVENT_DEV_NAME, + .id = 0, + .dev = { + .platform_data = &tuna_gpio_keypad_data, + }, +}; + +static int melfas_mux_fw_flash(bool to_gpios) +{ + /* TOUCH_EN is always an output */ + if (to_gpios) { + gpio_direction_output(GPIO_TOUCH_IRQ, 0); + omap_mux_set_gpio( + OMAP_PIN_INPUT | OMAP_MUX_MODE3, + GPIO_TOUCH_IRQ); + + gpio_direction_output(GPIO_TOUCH_SCL, 0); + omap_mux_set_gpio(OMAP_PIN_INPUT | OMAP_MUX_MODE3, + GPIO_TOUCH_SCL); + + gpio_direction_output(GPIO_TOUCH_SDA, 0); + omap_mux_set_gpio(OMAP_PIN_INPUT | OMAP_MUX_MODE3, + GPIO_TOUCH_SDA); + } else { + gpio_direction_output(GPIO_TOUCH_IRQ, 1); + gpio_direction_input(GPIO_TOUCH_IRQ); + omap_mux_set_gpio( + OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE3, + GPIO_TOUCH_IRQ); + + gpio_direction_output(GPIO_TOUCH_SCL, 1); + gpio_direction_input(GPIO_TOUCH_SCL); + omap_mux_set_gpio(OMAP_PIN_INPUT | OMAP_MUX_MODE0, + GPIO_TOUCH_SCL); + + gpio_direction_output(GPIO_TOUCH_SDA, 1); + gpio_direction_input(GPIO_TOUCH_SDA); + omap_mux_set_gpio(OMAP_PIN_INPUT | OMAP_MUX_MODE0, + GPIO_TOUCH_SDA); + } + + return 0; +} + +static int __init mms_ts_panel_id_setup(char *str) +{ + mms_ts_panel_id = simple_strtol(str, NULL, 0); + return 1; +} +__setup("mms_ts.panel_id=", mms_ts_panel_id_setup); + +static struct mms_ts_platform_data mms_ts_pdata = { + .max_x = 720, + .max_y = 1280, + .mux_fw_flash = melfas_mux_fw_flash, + .gpio_resetb = GPIO_TOUCH_IRQ, + .gpio_vdd_en = GPIO_TOUCH_EN, + .gpio_scl = GPIO_TOUCH_SCL, + .gpio_sda = GPIO_TOUCH_SDA, +}; + +static struct i2c_board_info __initdata tuna_i2c3_boardinfo_final[] = { + { + I2C_BOARD_INFO("mms_ts", 0x48), + .flags = I2C_CLIENT_WAKE, + .platform_data = &mms_ts_pdata, + .irq = OMAP_GPIO_IRQ(GPIO_TOUCH_IRQ), + }, +}; + +void __init omap4_tuna_input_init(void) +{ + gpio_request(GPIO_TOUCH_IRQ, "tsp_int_n"); + gpio_direction_input(GPIO_TOUCH_IRQ); + omap_mux_init_gpio(GPIO_TOUCH_IRQ, + OMAP_PIN_INPUT_PULLUP); + + gpio_request(GPIO_TOUCH_EN, "tsp_en"); + gpio_direction_output(GPIO_TOUCH_EN, 1); + omap_mux_init_gpio(GPIO_TOUCH_EN, OMAP_PIN_OUTPUT); + gpio_request(GPIO_TOUCH_SCL, "ap_i2c3_scl"); + gpio_request(GPIO_TOUCH_SDA, "ap_i2c3_sda"); + + /* 0x12 == FPCB 3.2 + * 0xa1 == FPCB 3.1 + */ + if (mms_ts_panel_id == 0x12) + mms_ts_pdata.fw_name = "mms144_ts_rev32.fw"; + else + mms_ts_pdata.fw_name = "mms144_ts_rev31.fw"; + + i2c_register_board_info(3, tuna_i2c3_boardinfo_final, + ARRAY_SIZE(tuna_i2c3_boardinfo_final)); + + omap_mux_init_gpio(8, OMAP_PIN_INPUT); + omap_mux_init_gpio(30, OMAP_PIN_INPUT); + + platform_device_register(&tuna_gpio_keypad_device); +} diff --git a/arch/arm/mach-omap2/board-tuna-jack.c b/arch/arm/mach-omap2/board-tuna-jack.c new file mode 100644 index 0000000..b292bce --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-jack.c @@ -0,0 +1,152 @@ +/* Board support file for Samsung Tuna Board. + * + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2010 Texas Instruments + * + * Based on mach-omap2/board-omap4panda.c + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/i2c/twl6030-madc.h> +#include <linux/sec_jack.h> + +#include "mux.h" +#include "board-tuna.h" + +#define GPIO_EAR_MICBIAS_EN 49 +#define GPIO_DET_35 0 +#define GPIO_EAR_SEND_END 1 + +#define ADC_CHANNEL_JACK 2 + +static void sec_jack_set_micbias_state(bool on) +{ + gpio_set_value(GPIO_EAR_MICBIAS_EN, on); +} + +static struct sec_jack_zone sec_jack_zones[] = { + { + /* adc < 50, unstable zone, default to 3pole if it stays + * in this range for a half second (20ms delays, 25 samples) + */ + .adc_high = 50, + .delay_ms = 20, + .check_count = 25, + .jack_type = SEC_HEADSET_3POLE, + }, + { + /* 50 < adc <= 450, unstable zone, default to 3pole if it stays + * in this range for a second (10ms delays, 100 samples) + */ + .adc_high = 450, + .delay_ms = 10, + .check_count = 100, + .jack_type = SEC_HEADSET_3POLE, + }, + { + /* 450 < adc <= 900, unstable zone, default to 4pole if it + * stays in this range for a second (10ms delays, 100 samples) + */ + .adc_high = 900, + .delay_ms = 10, + .check_count = 100, + .jack_type = SEC_HEADSET_4POLE, + }, + { + /* 900 < adc <= 1500, 4 pole zone, default to 4pole if it + * stays in this range for 200ms (20ms delays, 10 samples) + */ + .adc_high = 1500, + .delay_ms = 20, + .check_count = 10, + .jack_type = SEC_HEADSET_4POLE, + }, + { + /* adc > 1500, unstable zone, default to 3pole if it stays + * in this range for a second (10ms delays, 100 samples) + */ + .adc_high = 0x7fffffff, + .delay_ms = 10, + .check_count = 100, + .jack_type = SEC_HEADSET_3POLE, + }, +}; + +/* To support 3-buttons earjack */ +static struct sec_jack_buttons_zone sec_jack_buttons_zones[] = { + { + /* 0 <= adc <= 93, stable zone */ + .code = KEY_MEDIA, + .adc_low = 0, + .adc_high = 93, + }, + { + /* 94 <= adc <= 198, stable zone */ + .code = KEY_PREVIOUSSONG, + .adc_low = 94, + .adc_high = 198, + }, + { + /* 199 <= adc <= 370, stable zone */ + .code = KEY_NEXTSONG, + .adc_low = 199, + .adc_high = 370, + }, +}; + +static int sec_jack_get_adc_value(void) +{ + int value; + + value = twl6030_get_madc_conversion(ADC_CHANNEL_JACK); + return (int)(1800*value) / 1024; +} + +struct sec_jack_platform_data sec_jack_pdata = { + .set_micbias_state = sec_jack_set_micbias_state, + .get_adc_value = sec_jack_get_adc_value, + .zones = sec_jack_zones, + .num_zones = ARRAY_SIZE(sec_jack_zones), + .buttons_zones = sec_jack_buttons_zones, + .num_buttons_zones = ARRAY_SIZE(sec_jack_buttons_zones), + .det_gpio = GPIO_DET_35, + .send_end_gpio = GPIO_EAR_SEND_END, +}; + +static struct platform_device sec_device_jack = { + .name = "sec_jack", + .id = 1, /* will be used also for gpio_event id */ + .dev.platform_data = &sec_jack_pdata, +}; + +void __init omap4_tuna_jack_init(void) +{ + omap_mux_init_signal("sim_io.gpio_wk0", OMAP_PIN_INPUT); + gpio_request(GPIO_DET_35, "det_35_en"); + gpio_direction_input(GPIO_DET_35); + + omap_mux_init_signal("sim_clk.gpio_wk1", OMAP_PIN_INPUT); + gpio_request(GPIO_EAR_SEND_END, "ear_send_end"); + gpio_direction_input(GPIO_EAR_SEND_END); + + omap_mux_init_signal("gpmc_a25.gpio_49", OMAP_PIN_OUTPUT | OMAP_MUX_MODE3); + gpio_request(GPIO_EAR_MICBIAS_EN, "ear_micbias_en"); + gpio_direction_output(GPIO_EAR_MICBIAS_EN, 0); + + gpio_free(GPIO_DET_35); + gpio_free(GPIO_EAR_SEND_END); + platform_device_register(&sec_device_jack); +} diff --git a/arch/arm/mach-omap2/board-tuna-modems.c b/arch/arm/mach-omap2/board-tuna-modems.c new file mode 100755 index 0000000..c244ff9 --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-modems.c @@ -0,0 +1,749 @@ +/* linux/arch/arm/mach-xxxx/board-tuna-modems.c + * Copyright (C) 2010 Samsung Electronics. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/delay.h> + +#include <mach/omap4-common.h> +#include <linux/platform_data/modem.h> +#include "board-tuna.h" +#include "mux.h" + +#define OMAP_GPIO_MIPI_HSI_CP_ON 53 +#define OMAP_GPIO_MIPI_HSI_RESET_REQ_N 50 +#define OMAP_GPIO_MIPI_HSI_CP_RST 15 +#define OMAP_GPIO_MIPI_HSI_PDA_ACTIVE 119 +#define OMAP_GPIO_MIPI_HSI_PHONE_ACTIVE 120 +#define OMAP_GPIO_MIPI_HSI_CP_DUMP_INT 95 +#define OMAP_GPIO_MIPI_HSI_GPS_UART_SEL 164 + +#define OMAP_GPIO_DPRAM_VIA_RST 15 +#define OMAP_GPIO_DPRAM_PDA_ACTIVE 119 +#define OMAP_GPIO_DPRAM_PHONE_ACTIVE 120 +#define OMAP_GPIO_DPRAM_PWRHOLD_OFF 53 +#define OMAP_GPIO_DPRAM_INT_N 62 + +#define OMAP_GPIO_CMC_SPI_CLK_ACK 178 +#define OMAP_GPIO_CMC_SPI_CLK_REQ 164 +#define OMAP_GPIO_CMC_SPI_WAKEUP_INT 134 +#define OMAP_GPIO_LTE_ACTIVE 47 +#define OMAP_GPIO_CMC2AP_INT1 61 +#define OMAP_GPIO_CMC2AP_INT2 160 +#define OMAP_GPIO_AP2CMC_INT1 18 +#define OMAP_GPIO_AP2CMC_INT2 28 +#define OMAP_GPIO_221_PMIC_PWRON 41 +#define OMAP_GPIO_CMC_RST 50 +#define OMAP_GPIO_221_PMIC_PWRHOLD_OFF 163 + +#define DPRAM_START_ADDRESS 0x04000000 +#define DPRAM_SIZE 0x4000 +#define DPRAM_END_ADDRESS (DPRAM_START_ADDRESS + DPRAM_SIZE - 1) + +#define GPMC_CONTROL_BASE_ADDR 0x50000000 +#define GPMC_CONFIG1_1 (GPMC_CONTROL_BASE_ADDR + 0x90) +#define GPMC_CONFIG2_1 (GPMC_CONTROL_BASE_ADDR + 0x94) +#define GPMC_CONFIG3_1 (GPMC_CONTROL_BASE_ADDR + 0x98) +#define GPMC_CONFIG4_1 (GPMC_CONTROL_BASE_ADDR + 0x9C) +#define GPMC_CONFIG5_1 (GPMC_CONTROL_BASE_ADDR + 0xA0) +#define GPMC_CONFIG6_1 (GPMC_CONTROL_BASE_ADDR + 0xA4) +#define GPMC_CONFIG7_1 (GPMC_CONTROL_BASE_ADDR + 0xA8) + +#define DPRAM_GPMC_CONFIG1 0x00001201 +#define DPRAM_GPMC_CONFIG2 0x000f1200 +#define DPRAM_GPMC_CONFIG3 0x44040400 +#define DPRAM_GPMC_CONFIG4 0x0e05f155 +#define DPRAM_GPMC_CONFIG5 0x000e1016 +#define DPRAM_GPMC_CONFIG6 0x060603c3 +#define DPRAM_GPMC_CONFIG7 0x00000F44 + +/* umts target platform data */ +static struct modem_io_t umts_io_devices[] = { + [0] = { + .name = "umts_ipc0", + .id = 0x1, + .format = IPC_FMT, + .io_type = IODEV_MISC, + .link = LINKDEV_MIPI, + }, + [1] = { + .name = "umts_rfs0", + .id = 0x41, + .format = IPC_RFS, + .io_type = IODEV_MISC, + .link = LINKDEV_MIPI, + }, + [2] = { + .name = "rmnet0", + .id = 0x2A, + .format = IPC_RAW, + .io_type = IODEV_NET, + .link = LINKDEV_MIPI, + }, + [3] = { + .name = "umts_boot0", + .id = 0x0, + .format = IPC_BOOT, + .io_type = IODEV_MISC, + .link = LINKDEV_MIPI, + }, + [4] = { + .name = "rmnet1", + .id = 0x2B, + .format = IPC_RAW, + .io_type = IODEV_NET, + .link = LINKDEV_MIPI, + }, + [5] = { + .name = "rmnet2", + .id = 0x2C, + .format = IPC_RAW, + .io_type = IODEV_NET, + .link = LINKDEV_MIPI, + }, + [6] = { + .name = "multipdp", + .id = 0x1, + .format = IPC_MULTI_RAW, + .io_type = IODEV_DUMMY, + .link = LINKDEV_MIPI, + }, + [7] = { + .name = "umts_ramdump0", + .id = 0x0, + .format = IPC_RAMDUMP, + .io_type = IODEV_MISC, + .link = LINKDEV_MIPI, + }, +}; + +static struct modem_data umts_modem_data = { + .name = "xmm6260", + + .gpio_cp_on = OMAP_GPIO_MIPI_HSI_CP_ON, + .gpio_reset_req_n = OMAP_GPIO_MIPI_HSI_RESET_REQ_N, + .gpio_cp_reset = OMAP_GPIO_MIPI_HSI_CP_RST, + .gpio_pda_active = OMAP_GPIO_MIPI_HSI_PDA_ACTIVE, + .gpio_phone_active = OMAP_GPIO_MIPI_HSI_PHONE_ACTIVE, + .gpio_cp_dump_int = OMAP_GPIO_MIPI_HSI_CP_DUMP_INT, + .gpio_flm_uart_sel = OMAP_GPIO_MIPI_HSI_GPS_UART_SEL, + .gpio_cp_warm_reset = 0, + + .modem_type = IMC_XMM6260, + .link_type = LINKDEV_MIPI, + .modem_net = UMTS_NETWORK, + + .num_iodevs = ARRAY_SIZE(umts_io_devices), + .iodevs = umts_io_devices, +}; + +static void umts_modem_cfg_gpio(void) +{ + unsigned gpio_reset_req_n = umts_modem_data.gpio_reset_req_n; + unsigned gpio_cp_on = umts_modem_data.gpio_cp_on; + unsigned gpio_cp_rst = umts_modem_data.gpio_cp_reset; + unsigned gpio_pda_active = umts_modem_data.gpio_pda_active; + unsigned gpio_phone_active = umts_modem_data.gpio_phone_active; + unsigned gpio_cp_dump_int = umts_modem_data.gpio_cp_dump_int; + unsigned gpio_flm_uart_sel = umts_modem_data.gpio_flm_uart_sel; + + /* gpio mux setting */ + omap_mux_init_signal("gpmc_ncs0.gpio_50", OMAP_PIN_OUTPUT); + omap_mux_init_signal("gpmc_ncs3.gpio_53", OMAP_PIN_OUTPUT); + omap_mux_init_signal("dpm_emu4.gpio_15", OMAP_PIN_OUTPUT); + omap_mux_init_signal("abe_dmic_clk1.gpio_119", OMAP_PIN_OUTPUT | + OMAP_PIN_OFF_OUTPUT_LOW); + omap_mux_init_signal("abe_dmic_din1.gpio_120", OMAP_PIN_INPUT); + omap_mux_init_signal("usbb1_ulpitll_dat7.gpio_95", OMAP_PIN_INPUT); + omap_mux_init_signal("usbb2_ulpitll_dat3.gpio_164", OMAP_PIN_OUTPUT); + omap_mux_init_signal("uart3_cts_rctx.uart1_tx", OMAP_PIN_INPUT); + omap_mux_init_signal("mcspi1_cs1.uart1_rx", OMAP_PIN_INPUT); + + if (gpio_reset_req_n) { + gpio_request(gpio_reset_req_n, "RESET_REQ_N"); + gpio_direction_output(gpio_reset_req_n, 0); + } + + if (gpio_cp_on) { + gpio_request(gpio_cp_on, "CP_ON"); + gpio_direction_output(gpio_cp_on, 0); + } + + if (gpio_cp_rst) { + gpio_request(gpio_cp_rst, "CP_RST"); + gpio_direction_output(gpio_cp_rst, 0); + } + + if (gpio_pda_active) { + gpio_request(gpio_pda_active, "PDA_ACTIVE"); + gpio_direction_output(gpio_pda_active, 0); + } + + if (gpio_phone_active) { + gpio_request(gpio_phone_active, "PHONE_ACTIVE"); + gpio_direction_input(gpio_phone_active); + } + + if (gpio_cp_dump_int) { + gpio_request(gpio_cp_dump_int, "CP_DUMP_INT"); + gpio_direction_input(gpio_cp_dump_int); + } + + if (gpio_flm_uart_sel) { + gpio_request(gpio_flm_uart_sel, "GPS_UART_SEL"); + gpio_direction_output(gpio_flm_uart_sel, 1); + } + + if (gpio_phone_active) + irq_set_irq_type( + OMAP_GPIO_IRQ(OMAP_GPIO_MIPI_HSI_PHONE_ACTIVE), + IRQ_TYPE_LEVEL_HIGH); + + pr_debug("umts_modem_cfg_gpio done\n"); +} + +/* To get modem state, register phone active irq using resource */ +static struct resource umts_modem_res[] = { + [0] = { + .name = "umts_phone_active", + .start = OMAP_GPIO_IRQ(OMAP_GPIO_MIPI_HSI_PHONE_ACTIVE), + .end = OMAP_GPIO_IRQ(OMAP_GPIO_MIPI_HSI_PHONE_ACTIVE), + .flags = IORESOURCE_IRQ, + }, +}; + +/* if use more than one modem device, then set id num */ +static struct platform_device umts_modem = { + .name = "modem_if", + .id = -1, + .num_resources = ARRAY_SIZE(umts_modem_res), + .resource = umts_modem_res, + .dev = { + .platform_data = &umts_modem_data, + }, +}; + +static struct modem_io_t cdma_io_devices[] = { + [0] = { + .name = "multipdp", + .id = 0x1, + .format = IPC_MULTI_RAW, + .io_type = IODEV_DUMMY, + .link = LINKDEV_DPRAM, + }, + [1] = { + .name = "cdma_ipc0", + .id = 0x1, + .format = IPC_FMT, + .io_type = IODEV_MISC, + .link = LINKDEV_DPRAM, + }, + [2] = { + .name = "cdma_boot0", + .id = 0x1, + .format = IPC_BOOT, + .io_type = IODEV_MISC, + .link = LINKDEV_DPRAM, + }, + [3] = { + .name = "cdma_rmnet0", + .id = 0x2A, + .format = IPC_RAW, + .io_type = IODEV_NET, + .link = LINKDEV_DPRAM, + }, + [4] = { + .name = "cdma_rmnet1", + .id = 0x2B, + .format = IPC_RAW, + .io_type = IODEV_NET, + .link = LINKDEV_DPRAM, + }, + [5] = { + .name = "cdma_rmnet2", + .id = 0x2C, + .format = IPC_RAW, + .io_type = IODEV_NET, + .link = LINKDEV_DPRAM, + }, + [6] = { + .name = "cdma_rmnet3", + .id = 0x2D, + .format = IPC_RAW, + .io_type = IODEV_NET, + .link = LINKDEV_DPRAM, + }, + [7] = { + .name = "cdma_rmnet4", + .id = 0x27, + .format = IPC_RAW, + .io_type = IODEV_NET, + .link = LINKDEV_DPRAM, + }, + [8] = { + .name = "cdma_rmnet5", /* DM Port io-device */ + .id = 0x3A, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .link = LINKDEV_DPRAM, + }, + [9] = { + .name = "cdma_ramdump0", + .id = 0x1, + .format = IPC_RAMDUMP, + .io_type = IODEV_MISC, + .link = LINKDEV_DPRAM, + }, + [10] = { + .name = "cdma_rmnet6", /* AT CMD io-device */ + .id = 0x31, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .link = LINKDEV_DPRAM, + }, +}; + +/* cdma target platform data */ +static struct modem_data cdma_modem_data = { + .name = "cbp7.1", + + /*ToDo: always power on vbat 3.3v it is not cennected GPIO*/ + .gpio_cp_on = 0, + .gpio_reset_req_n = 0, + .gpio_cp_reset = OMAP_GPIO_DPRAM_VIA_RST, + .gpio_pda_active = OMAP_GPIO_DPRAM_PDA_ACTIVE, + .gpio_phone_active = OMAP_GPIO_DPRAM_PHONE_ACTIVE, + .gpio_cp_dump_int = 0, /*ToDo:*/ + .gpio_cp_warm_reset = 0, + .gpio_cp_off = OMAP_GPIO_DPRAM_PWRHOLD_OFF, + + .modem_type = VIA_CBP71, + .link_type = LINKDEV_DPRAM, + .modem_net = CDMA_NETWORK, + + .num_iodevs = ARRAY_SIZE(cdma_io_devices), + .iodevs = cdma_io_devices, +}; + +static void dpram_cfg_gpio(void) +{ + int nRetry = 0; + int resetdone; + + omap_mux_init_signal("gpmc_ad0", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad1", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad2", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad3", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad4", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad5", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad6", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad7", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad8", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad9", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad10", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad11", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad12", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad13", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad14", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + omap_mux_init_signal("gpmc_ad15", OMAP_PULL_ENA|OMAP_PULL_UP|OMAP_INPUT_EN); + + omap_mux_init_signal("gpmc_nadv_ale", 0); + omap_mux_init_signal("gpmc_nwe", 0); + omap_mux_init_signal("gpmc_nbe0_cle", 0); + omap_mux_init_signal("gpmc_ncs1", 0); + omap_mux_init_signal("gpmc_nbe1", 0); + + omap_mux_init_signal("gpmc_wait1.gpio_62", OMAP_WAKEUP_EN | OMAP_INPUT_EN); + omap_mux_init_signal("dpm_emu3", OMAP_MUX_MODE3); + omap_mux_init_signal("gpmc_ncs3.gpio_53", OMAP_PIN_OUTPUT); + + gpio_request(OMAP_GPIO_DPRAM_INT_N, "dpram_int"); + gpio_direction_input(OMAP_GPIO_DPRAM_INT_N); + irq_set_irq_type(OMAP_GPIO_IRQ(OMAP_GPIO_DPRAM_INT_N), + IRQ_TYPE_LEVEL_LOW); + + /*dpram platform init setting*/ + __raw_writel(0x02, OMAP4_GPMC_IO_ADDRESS((OMAP44XX_GPMC_BASE + 0x10))); + + while (nRetry < 100) { + msleep(20); + resetdone = __raw_readl(OMAP4_GPMC_IO_ADDRESS(OMAP44XX_GPMC_BASE + + 0x14)); + if (resetdone == 0x1) + break; + + nRetry++; + } + + __raw_writel(0x10, OMAP4_GPMC_IO_ADDRESS((OMAP44XX_GPMC_BASE + 0x10))); + + __raw_writel((u32)DPRAM_GPMC_CONFIG1, + OMAP4_GPMC_IO_ADDRESS(GPMC_CONFIG1_1)); + __raw_writel((u32)DPRAM_GPMC_CONFIG2, + OMAP4_GPMC_IO_ADDRESS(GPMC_CONFIG2_1)); + __raw_writel((u32)DPRAM_GPMC_CONFIG3, + OMAP4_GPMC_IO_ADDRESS(GPMC_CONFIG3_1)); + __raw_writel((u32)DPRAM_GPMC_CONFIG4, + OMAP4_GPMC_IO_ADDRESS(GPMC_CONFIG4_1)); + __raw_writel((u32)DPRAM_GPMC_CONFIG5, + OMAP4_GPMC_IO_ADDRESS(GPMC_CONFIG5_1)); + __raw_writel((u32)DPRAM_GPMC_CONFIG6, + OMAP4_GPMC_IO_ADDRESS(GPMC_CONFIG6_1)); + + __raw_writel((u32)0xF04, OMAP4_GPMC_IO_ADDRESS(GPMC_CONFIG7_1)); + msleep(50); + __raw_writel((u32)(0xF04 | 0x040), + OMAP4_GPMC_IO_ADDRESS(GPMC_CONFIG7_1)); +} + +static int dpram_cfg_gpmc_clk(void) +{ + struct clk *dpram_gpmc_ck; + struct clk *dpram_gpmc_ick; + + dpram_gpmc_ck = clk_get(NULL, "gpmc_ck"); + if (IS_ERR(dpram_gpmc_ck)) { + pr_err("Could not get GPMC clock gpmc_ck\n"); + return -ENOENT; + } + clk_enable(dpram_gpmc_ck); + + dpram_gpmc_ick = clk_get(NULL, "gpmc_ick"); + if (IS_ERR(dpram_gpmc_ick)) { + clk_disable(dpram_gpmc_ck); + pr_err("Could not get GPMC clock gpmc_ick\n"); + return -ENOENT; + } + clk_enable(dpram_gpmc_ick); + + return 0; +} + +static void cdma_modem_cfg_gpio(void) +{ + unsigned gpio_cp_rst = cdma_modem_data.gpio_cp_reset; + unsigned gpio_pda_active = cdma_modem_data.gpio_pda_active; + unsigned gpio_phone_active = cdma_modem_data.gpio_phone_active; + unsigned gpio_cp_off = cdma_modem_data.gpio_cp_off; + + dpram_cfg_gpio(); + if (dpram_cfg_gpmc_clk()) { + pr_err("fail to enable GPMC clock\n"); + return; + } + + omap_mux_init_signal("abe_dmic_din1.gpio_120", OMAP_PIN_INPUT); + omap_mux_init_signal("abe_dmic_clk1.gpio_119", OMAP_PIN_OUTPUT | + OMAP_PIN_OFF_OUTPUT_LOW); + + /* gpio mux setting */ + if (gpio_cp_rst) { + gpio_request(gpio_cp_rst, "CP_RST"); + gpio_direction_output(gpio_cp_rst, 0); + } + + if (gpio_pda_active) { + gpio_request(gpio_pda_active, "PDA_ACTIVE"); + gpio_direction_output(gpio_pda_active, 0); + } + + if (gpio_phone_active) { + gpio_request(gpio_phone_active, "PHONE_ACTIVE"); + gpio_direction_input(gpio_phone_active); + } + + if (gpio_cp_off) { + gpio_request(gpio_cp_off, "VIA_OFF"); + gpio_direction_output(gpio_cp_off, 1); + } + + if (gpio_phone_active) + irq_set_irq_type( + OMAP_GPIO_IRQ(OMAP_GPIO_DPRAM_PHONE_ACTIVE), + IRQ_TYPE_LEVEL_HIGH); +} + +static struct resource cdma_modem_res[] = { + [0] = { + .name = "cdma_phone_active", + .start = OMAP_GPIO_IRQ(OMAP_GPIO_DPRAM_PHONE_ACTIVE), + .end = OMAP_GPIO_IRQ(OMAP_GPIO_DPRAM_PHONE_ACTIVE), + .flags = IORESOURCE_IRQ, + }, + [1] = { + .name = "cdma_dpram_int", + .start = OMAP_GPIO_IRQ(OMAP_GPIO_DPRAM_INT_N), + .end = OMAP_GPIO_IRQ(OMAP_GPIO_DPRAM_INT_N), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .name = "cdma_dpram", + .start = DPRAM_START_ADDRESS, + .end = DPRAM_END_ADDRESS, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device cdma_modem = { + .name = "modem_if", + .id = 1, + .num_resources = ARRAY_SIZE(cdma_modem_res), + .resource = cdma_modem_res, + .dev = { + .platform_data = &cdma_modem_data, + }, +}; + +/* lte target platform data */ +static struct modem_io_t lte_io_devices[] = { + [0] = { + .name = "lte_ipc0", + .id = 0x1, + .format = IPC_FMT, + .io_type = IODEV_MISC, + .link = LINKDEV_USB, + }, + [1] = { + .name = "lte_rmnet0", + .id = 0x2A, + .format = IPC_RAW, + .io_type = IODEV_NET, + .link = LINKDEV_USB, + }, + [2] = { + .name = "lte_rfs0", + .id = 0x0, + .format = IPC_RFS, + .io_type = IODEV_MISC, + .link = LINKDEV_USB, + }, + [3] = { + .name = "lte_boot0", + .id = 0x0, + .format = IPC_BOOT, + .io_type = IODEV_MISC, + .link = LINKDEV_USB, + }, + [4] = { + .name = "lte_rmnet1", + .id = 0x2B, + .format = IPC_RAW, + .io_type = IODEV_NET, + .link = LINKDEV_USB, + }, + [5] = { + .name = "lte_rmnet2", + .id = 0x2C, + .format = IPC_RAW, + .io_type = IODEV_NET, + .link = LINKDEV_USB, + }, + [6] = { + .name = "lte_rmnet3", + .id = 0x2D, + .format = IPC_RAW, + .io_type = IODEV_NET, + .link = LINKDEV_USB, + }, + [7] = { + .name = "lte_multipdp", + .id = 0x1, + .format = IPC_MULTI_RAW, + .io_type = IODEV_DUMMY, + .link = LINKDEV_USB, + }, + [8] = { + .name = "lte_rmnet4", /* DM Port io-device */ + .id = 0x3F, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .link = LINKDEV_USB, + }, + [9] = { + .name = "lte_ramdump0", + .id = 0x0, + .format = IPC_RAMDUMP, + .io_type = IODEV_MISC, + .link = LINKDEV_USB, + }, +}; + +/* +Prime vs P4 usage +CMC2AP_INT1 vs CMC2AP_STATUS +AP2CMC_INT1 vs AP2CMC_STATUS +CMC2AP_INT2 vs CMC2AP_WAKEUP +AP2CMC_INT2 vs AP2CMC_WAKEUP +*/ +static struct modem_data lte_modem_data = { + .name = "cmc221", + + .gpio_cp_on = OMAP_GPIO_221_PMIC_PWRON, + .gpio_reset_req_n = 0, + .gpio_cp_reset = OMAP_GPIO_CMC_RST, + .gpio_pda_active = 0,/*NOT YET CONNECTED*/ + .gpio_phone_active = OMAP_GPIO_LTE_ACTIVE, + .gpio_cp_dump_int = OMAP_GPIO_LTE_ACTIVE,/*TO BE CHECKED*/ + + .gpio_cp_warm_reset = 0, +#ifdef CONFIG_LTE_MODEM_CMC221 + .gpio_cp_off = OMAP_GPIO_221_PMIC_PWRHOLD_OFF, + .gpio_slave_wakeup = OMAP_GPIO_AP2CMC_INT2, + .gpio_host_wakeup = OMAP_GPIO_CMC2AP_INT2, + .gpio_host_active = OMAP_GPIO_AP2CMC_INT1, +#endif + + .modem_type = SEC_CMC221, + .link_type = LINKDEV_USB, + .modem_net = LTE_NETWORK, + + .num_iodevs = ARRAY_SIZE(lte_io_devices), + .iodevs = lte_io_devices, +}; + +static void omap_lte_mux_init(void) +{ + pr_debug("[MODEM_IF] %s IN!\n", __func__); + + omap_mux_init_signal("gpmc_a17.gpio_41", OMAP_PIN_OUTPUT); + omap_mux_init_signal("usbb2_ulpitll_dat2.gpio_163", OMAP_PIN_OUTPUT); + omap_mux_init_signal("gpmc_ncs0.gpio_50", OMAP_PIN_OUTPUT); + omap_mux_init_signal("dpm_emu7.gpio_18", OMAP_PIN_OUTPUT); + omap_mux_init_signal("usbb2_ulpitll_nxt.gpio_160", + OMAP_PIN_INPUT | OMAP_PIN_OFF_WAKEUPENABLE); + omap_mux_init_signal("dpm_emu17.gpio_28", OMAP_PIN_OUTPUT); + omap_mux_init_signal("gpmc_a23.gpio_47", OMAP_PIN_INPUT_PULLDOWN); +} + +static void lte_modem_cfg_gpio(void) +{ + unsigned gpio_cp_on = lte_modem_data.gpio_cp_on; + unsigned gpio_cp_rst = lte_modem_data.gpio_cp_reset; + unsigned gpio_phone_active = lte_modem_data.gpio_phone_active; +#ifdef CONFIG_LTE_MODEM_CMC221 + unsigned gpio_cp_off = lte_modem_data.gpio_cp_off; + unsigned gpio_slave_wakeup = lte_modem_data.gpio_slave_wakeup; + unsigned gpio_host_wakeup = lte_modem_data.gpio_host_wakeup; + unsigned gpio_host_active = lte_modem_data.gpio_host_active; +#endif + + omap_lte_mux_init(); + if (gpio_cp_on) { + gpio_request(gpio_cp_on, "LTE_ON"); + gpio_direction_output(gpio_cp_on, 0); + } + + if (gpio_cp_rst) { + gpio_request(gpio_cp_rst, "LTE_RST"); + gpio_direction_output(gpio_cp_rst, 0); + } + + if (gpio_phone_active) { + gpio_request(gpio_phone_active, "LTE_ACTIVE"); + gpio_direction_input(gpio_phone_active); + } + +#ifdef CONFIG_LTE_MODEM_CMC221 + if (gpio_cp_off) { + gpio_request(gpio_cp_off, "LTE_OFF"); + gpio_direction_output(gpio_cp_off, 1); + } + + if (gpio_slave_wakeup) { + gpio_request(gpio_slave_wakeup, "LTE_SLAVE_WAKEUP"); + gpio_direction_output(gpio_slave_wakeup, 0); + } + + if (gpio_host_wakeup) { + gpio_request(gpio_host_wakeup, "LTE_HOST_WAKEUP"); + gpio_direction_input(gpio_host_wakeup); + } + + if (gpio_host_active) { + gpio_request(gpio_host_active, "LTE_HOST_ACTIVE"); + gpio_direction_output(gpio_host_active, 1); + } +#endif +} + +static struct resource lte_modem_res[] = { + [0] = { + .name = "lte_phone_active", + /* phone active irq */ + .start = OMAP_GPIO_IRQ(OMAP_GPIO_LTE_ACTIVE), + .end = OMAP_GPIO_IRQ(OMAP_GPIO_LTE_ACTIVE), + .flags = IORESOURCE_IRQ, + }, + [1] = { + .name = "lte_host_wakeup", + /* host wakeup irq */ + .start = OMAP_GPIO_IRQ(OMAP_GPIO_CMC2AP_INT2), + .end = OMAP_GPIO_IRQ(OMAP_GPIO_CMC2AP_INT2), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device lte_modem_wake = { + .name = "modem_lte_wake", + .id = -1, +}; + +static struct platform_device lte_modem = { + .name = "modem_if", + .id = 2, + .num_resources = ARRAY_SIZE(lte_modem_res), + .resource = lte_modem_res, + .dev = { + .platform_data = <e_modem_data, + }, +}; + +/* lte_modem_wake must be registered before the ehci driver */ +void __init modem_toro_init(void) +{ + lte_modem_wake.dev.platform_data = <e_modem_data; + platform_device_register(<e_modem_wake); +} + +static int __init init_modem(void) +{ + pr_debug("[MODEM_IF] init_modem\n"); + + switch (omap4_tuna_get_type()) { + case TUNA_TYPE_MAGURO: /* HSPA */ + /* umts gpios configuration */ + umts_modem_cfg_gpio(); + platform_device_register(&umts_modem); + break; + + case TUNA_TYPE_TORO: /* LTE */ + /* cdma gpios configuration */ + cdma_modem_cfg_gpio(); + platform_device_register(&cdma_modem); + + /* lte gpios configuration */ + lte_modem_cfg_gpio(); + platform_device_register(<e_modem); + break; + + default: + break; + } + return 0; +} +late_initcall(init_modem); diff --git a/arch/arm/mach-omap2/board-tuna-nfc.c b/arch/arm/mach-omap2/board-tuna-nfc.c new file mode 100644 index 0000000..2294433 --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-nfc.c @@ -0,0 +1,147 @@ +/* Control power to pn544 + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/types.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/printk.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/wakelock.h> +#include <plat/serial.h> + +#include "mux.h" + +#define GPIO_NFC_EN 173 +#define GPIO_NFC_FW 172 +#define GPIO_NFC_IRQ 17 + +#define PWR_OFF 0 +#define PWR_ON 1 +#define PWR_ON_FW 2 + +#define NFC_UART_NUM 4 /* omap_uart_wake() counts from 1 */ + +static unsigned int nfc_power; +static struct wake_lock nfc_wake_lock; + +static void nfc_power_apply(void) { + switch (nfc_power) { + case PWR_OFF: + pr_info("%s OFF\n", __func__); + gpio_set_value(GPIO_NFC_FW, 0); + gpio_set_value(GPIO_NFC_EN, 0); + msleep(60); + break; + case PWR_ON: + pr_info("%s ON\n", __func__); + gpio_set_value(GPIO_NFC_FW, 0); + gpio_set_value(GPIO_NFC_EN, 1); + msleep(20); + break; + case PWR_ON_FW: + pr_info("%s ON (firmware download)\n", __func__); + gpio_set_value(GPIO_NFC_FW, 1); + gpio_set_value(GPIO_NFC_EN, 1); + msleep(20); + gpio_set_value(GPIO_NFC_EN, 0); /* fw mode requires reset */ + msleep(60); + gpio_set_value(GPIO_NFC_EN, 1); + msleep(20); + break; + } +} + +static ssize_t nfc_power_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", nfc_power); +} + +static ssize_t nfc_power_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc; + unsigned int val; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + if (val > PWR_ON_FW) + return -EINVAL; + nfc_power = val; + nfc_power_apply(); + return count; +} + +static DEVICE_ATTR(nfc_power, S_IWUSR | S_IRUGO, nfc_power_show, + nfc_power_store); + +static irqreturn_t nfc_irq_isr(int irq, void *dev) +{ + omap_uart_wake(NFC_UART_NUM); + + /* + * take a 500ms wakelock, to give time for higher layers + * to either take their own wakelock or finish processing + */ + wake_lock_timeout(&nfc_wake_lock, msecs_to_jiffies(500)); + + return IRQ_HANDLED; +} + +void __init omap4_tuna_nfc_init(void) +{ + struct platform_device *pdev; + int irq; + + gpio_request(GPIO_NFC_FW, "nfc_fw"); + gpio_direction_output(GPIO_NFC_FW, 0); + omap_mux_init_gpio(GPIO_NFC_FW, OMAP_PIN_OUTPUT); + + gpio_request(GPIO_NFC_EN, "nfc_en"); + gpio_direction_output(GPIO_NFC_EN, 0); + omap_mux_init_gpio(GPIO_NFC_EN, OMAP_PIN_OUTPUT); + + gpio_request(GPIO_NFC_IRQ, "nfc_irq"); + gpio_direction_input(GPIO_NFC_IRQ); + omap_mux_init_gpio(GPIO_NFC_IRQ, OMAP_PIN_INPUT_PULLUP); + + wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "nfc"); + + irq = gpio_to_irq(GPIO_NFC_IRQ); + if (request_irq(irq, nfc_irq_isr, IRQF_TRIGGER_RISING, "nfc_irq", + NULL)) { + pr_err("%s: request_irq() failed\n", __func__); + return; + } + + if (enable_irq_wake(irq)) { + pr_err("%s: irq_set_irq_wake() failed\n", __func__); + return; + } + + nfc_power = PWR_OFF; + + pdev = platform_device_register_simple("nfc-power", -1, NULL, 0); + if (IS_ERR(pdev)) { + pr_err("%s: platform_device_register_simple() failed\n", __func__); + return; + } + if (device_create_file(&pdev->dev, &dev_attr_nfc_power)) + pr_err("%s: device_create_file() failed\n", __func__); +} diff --git a/arch/arm/mach-omap2/board-tuna-pogo.c b/arch/arm/mach-omap2/board-tuna-pogo.c new file mode 100644 index 0000000..b235a33 --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-pogo.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2011 Samsung, Inc. + * + * Author: Adam Hampson <ahampson@sta.samsung.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. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/switch.h> +#include <linux/wakelock.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/completion.h> + +#include <asm/div64.h> + +#include "mux.h" +#include "control.h" +#include "board-tuna.h" + +#define GPIO_POGO_DATA 121 +#define GPIO_POGO_DET 169 + +/* The below constants are in milliseconds */ +#define POGO_WAKE_PERIOD 100 +#define POGO_ID_PERIOD_TIMEOUT 750 +#define POGO_ID_CARDOCK 100 +#define POGO_ID_DESKDOCK 200 +#define POGO_ENTER_SPDIF_PERIOD 100 +#define POGO_ENTER_SPDIF_WAIT_PERIOD 100 +#define POGO_ID_PERIOD_TOLERANCE 20 + +#define POGO_DOCK_ID_MAX_RETRY 10 + +#define POGO_AUDIO_DISCONNECTED 0 +#define POGO_AUDIO_CONNECTED 2 + +#define POGO_DOCK_UNDOCKED 0 +#define POGO_DOCK_DESK 1 +#define POGO_DOCK_CAR 2 + + +struct tuna_pogo { + struct switch_dev dock_switch; + struct switch_dev audio_switch; + struct wake_lock wake_lock; + struct completion completion; + struct timespec rise_time; + struct timespec fall_time; + int det_irq; + int data_irq; + int dock_type; + bool fall_detected; +}; +static struct tuna_pogo tuna_pogo; + +static void pogo_send_pulse(unsigned int duration_in_ms) +{ + gpio_direction_output(GPIO_POGO_DATA, 1); + msleep(duration_in_ms); + gpio_direction_output(GPIO_POGO_DATA, 0); +} + +static int pogo_read_id_period(struct tuna_pogo *pogo, + unsigned int timeout_in_ms) +{ + struct timespec temp; + int ret; + + pogo->rise_time.tv_sec = 0; + pogo->rise_time.tv_nsec = 0; + pogo->fall_time.tv_sec = 0; + pogo->fall_time.tv_nsec = 0; + pogo->fall_detected = false; + + gpio_direction_input(GPIO_POGO_DATA); + + enable_irq(pogo->data_irq); + + ret = wait_for_completion_timeout(&pogo->completion, + msecs_to_jiffies(timeout_in_ms)); + if (ret <= 0) { + if (!pogo->fall_detected) + pr_debug("No response to wake within timeout\n"); + else + pr_debug("ID period did not conclude within timeout\n"); + disable_irq(pogo->data_irq); + return -1; + } + + temp = timespec_sub(pogo->fall_time, pogo->rise_time); + return temp.tv_nsec / NSEC_PER_MSEC; +} + +static irqreturn_t pogo_det_irq_thread(int irq, void *data) +{ + struct tuna_pogo *pogo = data; + int id_period; + unsigned int retry = 0; + + if (gpio_get_value(GPIO_POGO_DET)) { + wake_lock(&pogo->wake_lock); + + while (gpio_get_value(GPIO_POGO_DET) && + retry++ <= POGO_DOCK_ID_MAX_RETRY) { + + /* Start the detection process by sending a wake pulse + * to the dock. + */ + pogo_send_pulse(POGO_WAKE_PERIOD); + + id_period = pogo_read_id_period(pogo, + POGO_ID_PERIOD_TIMEOUT); + if (id_period == -1) + continue; + + /* The length of the ID period will indicate the type of + * dock that is attached. + */ + if (abs(id_period - POGO_ID_CARDOCK) <= + POGO_ID_PERIOD_TOLERANCE) { + pr_info("POGO Car Dock Detected, ID period" + " %dms\n", + id_period); + pogo->dock_type = POGO_DOCK_CAR; + switch_set_state(&pogo->dock_switch, + POGO_DOCK_CAR); + switch_set_state(&pogo->audio_switch, + POGO_AUDIO_CONNECTED); + break; + } else if (abs(id_period - POGO_ID_DESKDOCK) <= + POGO_ID_PERIOD_TOLERANCE) { + pr_info("POGO Desk Dock Detected, ID period" + " %dms\n", + id_period); + pogo->dock_type = POGO_DOCK_DESK; + switch_set_state(&pogo->dock_switch, + POGO_DOCK_DESK); + switch_set_state(&pogo->audio_switch, + POGO_AUDIO_CONNECTED); + break; + } else { + pr_err("Unknown POGO dock detected, ID period" + " %ums\n", + id_period); + } + } + + if (pogo->dock_type == POGO_DOCK_UNDOCKED) { + wake_unlock(&pogo->wake_lock); + pr_err("Unable to identify pogo dock, giving up\n"); + return IRQ_HANDLED; + } + + /* Instruct the dock to enter SPDIF mode */ + pogo_send_pulse(POGO_ENTER_SPDIF_PERIOD); + + msleep(POGO_ENTER_SPDIF_WAIT_PERIOD); + + omap_mux_set_gpio(OMAP_MUX_MODE2 | OMAP_PIN_OUTPUT, + GPIO_POGO_DATA); + + wake_unlock(&pogo->wake_lock); + } else { + if (pogo->dock_type != POGO_DOCK_UNDOCKED) { + pogo->dock_type = POGO_DOCK_UNDOCKED; + pr_info("POGO Dock Detached\n"); + switch_set_state(&pogo->dock_switch, + POGO_DOCK_UNDOCKED); + switch_set_state(&pogo->audio_switch, + POGO_AUDIO_DISCONNECTED); + } + + omap_mux_set_gpio(OMAP_MUX_MODE3 | OMAP_PIN_INPUT_PULLDOWN, + GPIO_POGO_DATA); + } + + return IRQ_HANDLED; +} + +static irqreturn_t pogo_data_irq(int irq, void *data) +{ + struct tuna_pogo *pogo = data; + + if (gpio_get_value(GPIO_POGO_DATA)) { + ktime_get_ts(&pogo->rise_time); + irq_set_irq_type(pogo->data_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT); + } else { + ktime_get_ts(&pogo->fall_time); + pogo->fall_detected = true; + irq_set_irq_type(pogo->data_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT); + complete(&pogo->completion); + disable_irq_nosync(pogo->data_irq); + } + return IRQ_HANDLED; +} + +void __init omap4_tuna_pogo_init(void) +{ + struct tuna_pogo *pogo = &tuna_pogo; + unsigned int r; + int ret; + + omap_mux_init_signal("usbb2_hsic_data.gpio_169", + OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE3); + + /* The pullup/pulldown controls in the mux register are not the controls + * that you are looking for. The usbb2_hsic_data signal has a separate + * special control in the CONTROL_USBB_HSIC register. + */ + r = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USBB_HSIC); + r &= ~OMAP4_USBB2_HSIC_DATA_WD_MASK; + omap4_ctrl_pad_writel(r, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USBB_HSIC); + + ret = gpio_request(GPIO_POGO_DET, "pogo_det"); + if (ret < 0) + pr_err("request for pogo_det gpio failed, err %d\n", ret); + + gpio_direction_input(GPIO_POGO_DET); + + omap_mux_init_signal("abe_dmic_din2.gpio_121", + OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE3); + ret = gpio_request(GPIO_POGO_DATA, "pogo_data"); + if (ret < 0) + pr_err("request for pogo_data gpio failed, err %d\n", ret); + + gpio_direction_output(GPIO_POGO_DATA, 0); + + pogo->dock_switch.name = "dock"; + + /* The POGO dock does not involve USB but we are reusing the existing + * usb audio switch report the availabilty of SPDIF audio through the + * POGO dock. + */ + pogo->audio_switch.name = "usb_audio"; + + switch_dev_register(&pogo->dock_switch); + + switch_dev_register(&pogo->audio_switch); + + wake_lock_init(&pogo->wake_lock, WAKE_LOCK_IDLE, "pogo"); + + init_completion(&pogo->completion); + + pogo->det_irq = gpio_to_irq(GPIO_POGO_DET); + + ret = request_threaded_irq(pogo->det_irq, NULL, + pogo_det_irq_thread, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "pogo_det", pogo); + if (ret < 0) + pr_err("Unable to register pogo_det interrupt (%d)\n", ret); + + pogo->data_irq = gpio_to_irq(GPIO_POGO_DATA); + + ret = request_irq(pogo->data_irq, pogo_data_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "pogo_data", pogo); + if (ret < 0) + pr_err("Unable to register pogo_data interrupt (%d)\n", ret); + + disable_irq(pogo->data_irq); +} diff --git a/arch/arm/mach-omap2/board-tuna-power.c b/arch/arm/mach-omap2/board-tuna-power.c new file mode 100644 index 0000000..924cc17 --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-power.c @@ -0,0 +1,509 @@ +/* Power support for Samsung Tuna Board. + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/max17040_battery.h> +#include <linux/moduleparam.h> +#include <linux/pda_power.h> +#include <linux/platform_device.h> +#include <linux/i2c/twl6030-madc.h> +#include <linux/delay.h> + +#include <plat/cpu.h> + +#include "board-tuna.h" +#include "mux.h" +#include "pm.h" + +/* These will be different on pre-lunchbox, lunchbox, and final */ +#define GPIO_CHARGING_N 83 +#define GPIO_TA_NCONNECTED 142 +#define GPIO_CHARGE_N 13 +#define GPIO_CHG_CUR_ADJ 102 +#define GPIO_FUEL_ALERT 44 + +#define TPS62361_GPIO 7 +#define ADC_NUM_SAMPLES 5 +#define ADC_LIMIT_ERR_COUNT 5 +#define ISET_ADC_CHANNEL 3 +#define TEMP_ADC_CHANNEL 1 + +#define CHARGE_FULL_ADC 203 + +#define HIGH_BLOCK_TEMP_MAGURO 500 +#define HIGH_RECOVER_TEMP_MAGURO 420 +#define LOW_BLOCK_TEMP_MAGURO (-50) +#define LOW_RECOVER_TEMP_MAGURO 0 + +#define HIGH_BLOCK_TEMP_TORO 470 +#define HIGH_RECOVER_TEMP_TORO 400 +#define LOW_BLOCK_TEMP_TORO (-30) +#define LOW_RECOVER_TEMP_TORO 0 + +/** +** temp_adc_table_data +** @adc_value : thermistor adc value +** @temperature : temperature(C) * 10 +**/ +struct temp_adc_table_data { + int adc_value; + int temperature; +}; + +static DEFINE_SPINLOCK(charge_en_lock); +static int charger_state; + +static struct temp_adc_table_data temper_table_maguro[] = { + /* ADC, Temperature (C/10) */ + { 75, 700 }, + { 78, 690 }, + { 82, 680 }, + { 84, 670 }, + { 87, 660 }, + { 89, 650 }, + { 92, 640 }, + { 95, 630 }, + { 99, 620 }, + { 102, 610 }, + { 105, 600 }, + { 109, 590 }, + { 113, 580 }, + { 117, 570 }, + { 121, 560 }, + { 124, 550 }, + { 127, 540 }, + { 135, 530 }, + { 139, 520 }, + { 143, 510 }, + { 147, 500 }, + { 153, 490 }, + { 158, 480 }, + { 163, 470 }, + { 169, 460 }, + { 175, 450 }, + { 181, 440 }, + { 187, 430 }, + { 193, 420 }, + { 199, 410 }, + { 205, 400 }, + { 212, 390 }, + { 218, 380 }, + { 227, 370 }, + { 233, 360 }, + { 240, 350 }, + { 249, 340 }, + { 258, 330 }, + { 267, 320 }, + { 276, 310 }, + { 285, 300 }, + { 299, 290 }, + { 308, 280 }, + { 313, 270 }, + { 322, 260 }, + { 331, 250 }, + { 342, 240 }, + { 355, 230 }, + { 363, 220 }, + { 373, 210 }, + { 383, 200 }, + { 394, 190 }, + { 407, 180 }, + { 417, 170 }, + { 427, 160 }, + { 437, 150 }, + { 450, 140 }, + { 465, 130 }, + { 475, 120 }, + { 487, 110 }, + { 500, 100 }, + { 514, 90 }, + { 526, 80 }, + { 540, 70 }, + { 552, 60 }, + { 565, 50 }, + { 577, 40 }, + { 589, 30 }, + { 603, 20 }, + { 614, 10 }, + { 628, 0 }, + { 639, (-10) }, + { 664, (-20) }, + { 689, (-30) }, + { 717, (-40) }, + { 744, (-50) }, + { 754, (-60) }, + { 765, (-70) }, + { 776, (-80) }, + { 787, (-90) }, + { 798, (-100) }, +}; + +static struct temp_adc_table_data temper_table_toro[] = { + /* ADC, Temperature (C/10) */ + { 63, 700 }, + { 66, 690 }, + { 67, 680 }, + { 71, 670 }, + { 73, 660 }, + { 75, 650 }, + { 79, 640 }, + { 81, 630 }, + { 83, 620 }, + { 86, 610 }, + { 89, 600 }, + { 92, 590 }, + { 95, 580 }, + { 98, 570 }, + { 102, 560 }, + { 106, 550 }, + { 110, 540 }, + { 114, 530 }, + { 118, 520 }, + { 122, 510 }, + { 126, 500 }, + { 130, 490 }, + { 134, 480 }, + { 139, 470 }, + { 144, 460 }, + { 150, 450 }, + { 155, 440 }, + { 160, 430 }, + { 165, 420 }, + { 171, 410 }, + { 176, 400 }, + { 185, 390 }, + { 191, 380 }, + { 198, 370 }, + { 205, 360 }, + { 211, 350 }, + { 218, 340 }, + { 225, 330 }, + { 232, 320 }, + { 240, 310 }, + { 248, 300 }, + { 256, 290 }, + { 265, 280 }, + { 274, 270 }, + { 283, 260 }, + { 292, 250 }, + { 302, 240 }, + { 313, 230 }, + { 323, 220 }, + { 334, 210 }, + { 344, 200 }, + { 354, 190 }, + { 365, 180 }, + { 375, 170 }, + { 386, 160 }, + { 396, 150 }, + { 410, 140 }, + { 423, 130 }, + { 436, 120 }, + { 449, 110 }, + { 462, 100 }, + { 473, 90 }, + { 484, 80 }, + { 495, 70 }, + { 506, 60 }, + { 517, 50 }, + { 530, 40 }, + { 543, 30 }, + { 557, 20 }, + { 570, 10 }, + { 582, 0 }, + { 596, (-10) }, + { 610, (-20) }, + { 623, (-30) }, + { 636, (-40) }, + { 650, (-50) }, + { 663, (-60) }, + { 676, (-70) }, + { 686, (-80) }, + { 696, (-90) }, + { 716, (-100) }, +}; + +static struct temp_adc_table_data *temper_table = temper_table_maguro; +static int temper_table_size = ARRAY_SIZE(temper_table_maguro); + +static bool enable_sr = true; +module_param(enable_sr, bool, S_IRUSR | S_IRGRP | S_IROTH); + +static struct gpio charger_gpios[] = { + { .gpio = GPIO_CHARGING_N, .flags = GPIOF_IN, .label = "charging_n" }, + { .gpio = GPIO_TA_NCONNECTED, .flags = GPIOF_IN, .label = "charger_n" }, + { .gpio = GPIO_CHARGE_N, .flags = GPIOF_OUT_INIT_HIGH, .label = "charge_n" }, + { .gpio = GPIO_CHG_CUR_ADJ, .flags = GPIOF_OUT_INIT_LOW, .label = "charge_cur_adj" }, +}; + +static int twl6030_get_adc_data(int ch) +{ + int adc_data; + int adc_max = -1; + int adc_min = 1 << 11; + int adc_total = 0; + int i, j; + + for (i = 0; i < ADC_NUM_SAMPLES; i++) { + adc_data = twl6030_get_madc_conversion(ch); + if (adc_data == -EAGAIN) { + for (j = 0; j < ADC_LIMIT_ERR_COUNT; j++) { + msleep(20); + adc_data = twl6030_get_madc_conversion(ch); + if (adc_data > 0) + break; + } + if (j >= ADC_LIMIT_ERR_COUNT) { + pr_err("%s: Retry count exceeded[ch:%d]\n", + __func__, ch); + return adc_data; + } + } else if (adc_data < 0) { + pr_err("%s: Failed read adc value : %d [ch:%d]\n", + __func__, adc_data, ch); + return adc_data; + } + + if (adc_data > adc_max) + adc_max = adc_data; + if (adc_data < adc_min) + adc_min = adc_data; + + adc_total += adc_data; + } + return (adc_total - adc_max - adc_min) / (ADC_NUM_SAMPLES - 2); +} + +static int iset_adc_value(void) +{ + return twl6030_get_adc_data(ISET_ADC_CHANNEL); +} + +static int temp_adc_value(void) +{ + return twl6030_get_adc_data(TEMP_ADC_CHANNEL); +} + +static bool check_charge_full(void) +{ + int ret; + + ret = iset_adc_value(); + if (ret < 0) { + pr_err("%s: invalid iset adc value [%d]\n", + __func__, ret); + return false; + } + pr_debug("%s : iset adc value : %d\n", __func__, ret); + + return ret < CHARGE_FULL_ADC; +} + +static int get_bat_temp_by_adc(int *batt_temp) +{ + int array_size = temper_table_size; + int temp_adc = temp_adc_value(); + int mid; + int left_side = 0; + int right_side = array_size - 1; + int temp = 0; + + if (temp_adc < 0) { + pr_err("%s : Invalid temperature adc value [%d]\n", + __func__, temp_adc); + return temp_adc; + } + + while (left_side <= right_side) { + mid = (left_side + right_side) / 2; + if (mid == 0 || mid == array_size - 1 || + (temper_table[mid].adc_value <= temp_adc && + temper_table[mid+1].adc_value > temp_adc)) { + temp = temper_table[mid].temperature; + break; + } else if (temp_adc - temper_table[mid].adc_value > 0) { + left_side = mid + 1; + } else { + right_side = mid - 1; + } + } + + pr_debug("%s: temp adc : %d, temp : %d\n", __func__, temp_adc, temp); + *batt_temp = temp; + return 0; +} + +static int charger_init(struct device *dev) +{ + return gpio_request_array(charger_gpios, ARRAY_SIZE(charger_gpios)); +} + +static void charger_exit(struct device *dev) +{ + gpio_free_array(charger_gpios, ARRAY_SIZE(charger_gpios)); +} + +static void set_charge_en(int state) +{ + gpio_set_value(GPIO_CHARGE_N, !state); +} + +static void charger_set_charge(int state) +{ + gpio_set_value(GPIO_CHG_CUR_ADJ, !!(state & PDA_POWER_CHARGE_AC)); + spin_lock(&charge_en_lock); + charger_state = state; + set_charge_en(state); + spin_unlock(&charge_en_lock); +} + +static void charger_set_only_charge(int state) +{ + spin_lock(&charge_en_lock); + if (charger_state) + set_charge_en(state); + spin_unlock(&charge_en_lock); + /* CHG_ING_N level changed after set charge_en and 150ms */ + msleep(150); +} + +static int charger_is_online(void) +{ + return !gpio_get_value(GPIO_TA_NCONNECTED); +} + +static int charger_is_charging(void) +{ + return !gpio_get_value(GPIO_CHARGING_N); +} + +static char *tuna_charger_supplied_to[] = { + "battery", +}; + +static const __initdata struct pda_power_pdata charger_pdata = { + .init = charger_init, + .exit = charger_exit, + .set_charge = charger_set_charge, + .wait_for_status = 500, + .wait_for_charger = 500, + .supplied_to = tuna_charger_supplied_to, + .num_supplicants = ARRAY_SIZE(tuna_charger_supplied_to), + .use_otg_notifier = true, +}; + +static struct max17040_platform_data max17043_pdata = { + .charger_online = charger_is_online, + .charger_enable = charger_is_charging, + .allow_charging = charger_set_only_charge, + .skip_reset = true, + .min_capacity = 3, + .is_full_charge = check_charge_full, + .get_bat_temp = get_bat_temp_by_adc, + .high_block_temp = HIGH_BLOCK_TEMP_MAGURO, + .high_recover_temp = HIGH_RECOVER_TEMP_MAGURO, + .low_block_temp = LOW_BLOCK_TEMP_MAGURO, + .low_recover_temp = LOW_RECOVER_TEMP_MAGURO, + .fully_charged_vol = 4150000, + .recharge_vol = 4140000, + .limit_charging_time = 21600, /* 6 hours */ + .limit_recharging_time = 5400, /* 90 min */ +}; + +static const __initdata struct i2c_board_info max17043_i2c[] = { + { + I2C_BOARD_INFO("max17040", (0x6C >> 1)), + .platform_data = &max17043_pdata, + .irq = OMAP_GPIO_IRQ(GPIO_FUEL_ALERT), + } +}; + +void __init omap4_tuna_power_init(void) +{ + struct platform_device *pdev; + int status; + + /* Vsel0 = gpio, vsel1 = gnd */ + status = omap_tps6236x_board_setup(true, TPS62361_GPIO, -1, + OMAP_PIN_OFF_OUTPUT_HIGH, -1); + if (status) + pr_err("TPS62361 initialization failed: %d\n", status); + /* + * Some Tuna devices have a 4430 chip on a 4460 board, manually + * tweak the power tree to the 4460 style with the TPS regulator. + */ + if (cpu_is_omap443x()) { + /* Disable 4430 mapping */ + omap_twl_pmic_update("mpu", CHIP_IS_OMAP443X, 0x0); + omap_twl_pmic_update("core", CHIP_IS_OMAP443X, 0x0); + /* make 4460 map usable for 4430 */ + omap_twl_pmic_update("core", CHIP_IS_OMAP446X, CHIP_IS_OMAP443X); + omap_tps6236x_update("mpu", CHIP_IS_OMAP446X, CHIP_IS_OMAP443X); + } + + /* Update temperature data from board type */ + if (omap4_tuna_get_type() == TUNA_TYPE_TORO) { + temper_table = temper_table_toro; + temper_table_size = ARRAY_SIZE(temper_table_toro); + + max17043_pdata.high_block_temp = HIGH_BLOCK_TEMP_TORO; + max17043_pdata.high_recover_temp = HIGH_RECOVER_TEMP_TORO; + max17043_pdata.low_block_temp = LOW_BLOCK_TEMP_TORO; + max17043_pdata.low_recover_temp = LOW_RECOVER_TEMP_TORO; + } + + /* Update oscillator information */ + if (omap4_tuna_get_revision() <= 0x3) { + /* + * until sample 4 (Toro and Maguro), we used KC2520B38: + * ST = 10ms + * Output Disable time = 100ns + * Output enable time = 5ms + * tstart = 10ms + 5ms = 15ms. + * tshut = 1us (rounded) + */ + omap_pm_set_osc_lp_time(15000, 1); + } else { + /* + * sample 5 onwards (Toro and Maguro), we use SQ200384: + * ST = 10ms + * Output Disable time = 100ns + * Output enable time = 10ms + * tstart = 10ms + 10ms = 20ms. + * tshut = 1us (rounded) + */ + omap_pm_set_osc_lp_time(20000, 1); + } + + omap_mux_init_gpio(charger_gpios[0].gpio, OMAP_PIN_INPUT); + omap_mux_init_gpio(charger_gpios[1].gpio, OMAP_PIN_INPUT); + omap_mux_init_gpio(charger_gpios[2].gpio, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(charger_gpios[3].gpio, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(GPIO_FUEL_ALERT, OMAP_PIN_INPUT); + + pdev = platform_device_register_resndata(NULL, "pda-power", -1, + NULL, 0, &charger_pdata, sizeof(charger_pdata)); + if (IS_ERR_OR_NULL(pdev)) + pr_err("cannot register pda-power\n"); + + i2c_register_board_info(4, max17043_i2c, ARRAY_SIZE(max17043_i2c)); + + if (enable_sr) + omap_enable_smartreflex_on_init(); +} diff --git a/arch/arm/mach-omap2/board-tuna-sensors.c b/arch/arm/mach-omap2/board-tuna-sensors.c new file mode 100755 index 0000000..f818aad --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-sensors.c @@ -0,0 +1,212 @@ +/* Sensor support for Samsung Tuna Board. + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/mpu.h> +#include <linux/gp2a.h> +#include <linux/i2c/twl6030-madc.h> + +#include "mux.h" +#include "board-tuna.h" + +#define GPIO_GYRO_INT 45 +#define GPIO_ACC_INT 122 +#define GPIO_MAG_INT 176 +#define GPIO_PS_ON 25 +#define GPIO_PS_VOUT 21 +#define GPIO_MSENSE_IRQ 157 + +#define GP2A_LIGHT_ADC_CHANNEL 4 + +static int gp2a_light_adc_value(void) +{ + return twl6030_get_madc_conversion(GP2A_LIGHT_ADC_CHANNEL); +} + +static void gp2a_power(bool on) +{ + /* this controls the power supply rail to the gp2a IC */ + gpio_set_value(GPIO_PS_ON, on); +} + +static void gp2a_gpio_init(void) +{ + int ret = gpio_request(GPIO_PS_ON, "gp2a_power_supply_on"); + if (ret) { + pr_err("%s Failed to request gpio gp2a power supply\n", + __func__); + return; + } + /* set power pin to output, initially powered off*/ + ret = gpio_direction_output(GPIO_PS_ON, 0); + if (ret) { + pr_err("%s Failed in gpio_direction_output, value 0 with error %d\n", + __func__, ret); + } +} + +static s8 orientation_back[] = { + -1, 0, 0, + 0, 1, 0, + 0, 0, -1, +}; + +static s8 orientation_back_right_90[] = { + 0, -1, 0, + -1, 0, 0, + 0, 0, -1, +}; + +static s8 orientation_back_left_90[] = { + 0, 1, 0, + 1, 0, 0, + 0, 0, -1, +}; + +static s8 orientation_back_180[] = { + 1, 0, 0, + 0, -1, 0, + 0, 0, -1, +}; + +/* + * A correction matrix for YAS530 + * which takes care of soft iron effect in TORO + */ +static s32 compass_correction_matrix_toro[] = { + 1072, -51, -22, + -30, 910, -4, + -23, -63, 1024, +}; + +static void rotcpy(s8 dst[3 * 3], const s8 src[3 * 3]) +{ + memcpy(dst, src, 3 * 3); +} + +static struct mpu_platform_data mpu_data = { + .int_config = 0x10, + .orientation = { 1, 0, 0, + 0, 1, 0, + 0, 0, 1 }, + /* accel */ + .accel = { + .irq = OMAP_GPIO_IRQ(GPIO_ACC_INT), + .adapt_num = 4, + .bus = EXT_SLAVE_BUS_SECONDARY, + .address = 0x18, + .orientation = { 1, 0, 0, + 0, 1, 0, + 0, 0, 1 }, + }, + /* compass */ + .compass = { + .irq = OMAP_GPIO_IRQ(GPIO_MAG_INT), + .adapt_num = 4, + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x2E, + .orientation = { 1, 0, 0, + 0, 1, 0, + 0, 0, 1 }, + }, +}; + +static struct gp2a_platform_data gp2a_pdata = { + .power = gp2a_power, + .p_out = GPIO_PS_VOUT, + .light_adc_value = gp2a_light_adc_value, +}; + +static struct i2c_board_info __initdata tuna_sensors_i2c4_boardinfo[] = { + { + I2C_BOARD_INFO("mpu3050", 0x68), + .irq = OMAP_GPIO_IRQ(GPIO_GYRO_INT), + .platform_data = &mpu_data, + }, + { + I2C_BOARD_INFO("bma250", 0x18), + .irq = OMAP_GPIO_IRQ(GPIO_ACC_INT), + .platform_data = &mpu_data.accel, + }, + { + I2C_BOARD_INFO("yas530", 0x2e), + .irq = OMAP_GPIO_IRQ(GPIO_MAG_INT), + .platform_data = &mpu_data.compass, + }, + { + I2C_BOARD_INFO("gp2a", 0x44), + .platform_data = &gp2a_pdata, + }, + { + I2C_BOARD_INFO("bmp180", 0x77), + }, +}; + +static void omap4_tuna_fixup_orientations_maguro(int revision) +{ + if (revision >= 3) { + rotcpy(mpu_data.orientation, orientation_back_right_90); + rotcpy(mpu_data.accel.orientation, orientation_back_left_90); + } else if (revision >= 2) { + rotcpy(mpu_data.orientation, orientation_back_right_90); + rotcpy(mpu_data.accel.orientation, orientation_back_180); + } else if (revision == 1) { + rotcpy(mpu_data.accel.orientation, orientation_back_left_90); + } +} + +static void omap4_tuna_fixup_orientations_toro(int revision) +{ + if (revision >= 2) { + rotcpy(mpu_data.orientation, orientation_back_left_90); + rotcpy(mpu_data.accel.orientation, orientation_back); + rotcpy(mpu_data.compass.orientation, orientation_back_180); + } else if (revision >= 1) { + rotcpy(mpu_data.orientation, orientation_back_left_90); + rotcpy(mpu_data.accel.orientation, orientation_back_180); + rotcpy(mpu_data.compass.orientation, orientation_back_left_90); + } +} + +void __init omap4_tuna_sensors_init(void) +{ + omap_mux_init_gpio(GPIO_GYRO_INT, OMAP_PIN_INPUT); + omap_mux_init_gpio(GPIO_ACC_INT, OMAP_PIN_INPUT); + omap_mux_init_gpio(GPIO_MAG_INT, OMAP_PIN_INPUT); + omap_mux_init_gpio(GPIO_PS_ON, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(GPIO_PS_VOUT, OMAP_WAKEUP_EN | OMAP_PIN_INPUT); + + gpio_request(GPIO_GYRO_INT, "GYRO_INT"); + gpio_direction_input(GPIO_GYRO_INT); + gpio_request(GPIO_ACC_INT, "ACC_INT"); + gpio_direction_input(GPIO_ACC_INT); + gpio_request(GPIO_MAG_INT, "MAG_INT"); + gpio_direction_input(GPIO_MAG_INT); + gpio_request(GPIO_MSENSE_IRQ, "MSENSE_IRQ"); + gpio_direction_output(GPIO_MSENSE_IRQ, 1); + /* optical sensor */ + gp2a_gpio_init(); + + if (omap4_tuna_get_type() == TUNA_TYPE_MAGURO) { + omap4_tuna_fixup_orientations_maguro(omap4_tuna_get_revision()); + } else if (omap4_tuna_get_type() == TUNA_TYPE_TORO) { + omap4_tuna_fixup_orientations_toro(omap4_tuna_get_revision()); + mpu_data.compass.private_data = compass_correction_matrix_toro; + } + + i2c_register_board_info(4, tuna_sensors_i2c4_boardinfo, + ARRAY_SIZE(tuna_sensors_i2c4_boardinfo)); +} diff --git a/arch/arm/mach-omap2/board-tuna-usbhost.c b/arch/arm/mach-omap2/board-tuna-usbhost.c new file mode 100644 index 0000000..39905fd --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-usbhost.c @@ -0,0 +1,85 @@ +/* USB Host (EHCI) support for Samsung Tuna Board. + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include <plat/usb.h> + +#include "board-tuna.h" +#include "mux.h" + +#define GPIO_USB3333_RESETB 159 + +static struct usbhs_omap_board_data usbhs_bdata = { + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + .phy_reset = false, + .reset_gpio_port[0] = -EINVAL, + .reset_gpio_port[1] = -EINVAL, + .reset_gpio_port[2] = -EINVAL +}; + +void __init omap4_ehci_init(void) +{ + int ret = 0; + struct clk *phy_ref_clk; + + omap_mux_init_gpio(GPIO_USB3333_RESETB, OMAP_PIN_OUTPUT | + OMAP_PIN_OFF_OUTPUT_HIGH); + + ret = gpio_request(GPIO_USB3333_RESETB, "usb3333_resetb"); + if (ret) { + pr_err("omap: ehci: Cannot request GPIO %d", + GPIO_USB3333_RESETB); + return; + } + gpio_direction_output(GPIO_USB3333_RESETB, 0); + gpio_set_value(GPIO_USB3333_RESETB, 0); + + /* FREF_CLK3 provides the 19.2 MHz reference clock to the PHY */ + omap_mux_init_signal("fref_clk3_out", OMAP_PIN_OUTPUT | OMAP_MUX_MODE0); + + phy_ref_clk = clk_get(NULL, "auxclk3_ck"); + if (IS_ERR(phy_ref_clk)) { + pr_err("omap: ehci: Cannot request auxclk3"); + return; + } + ret = clk_set_rate(phy_ref_clk, 19200000); + if (ret < 0) { + pr_err("omap: ehci: Cannot clk_set_rate auxclk3 err %d", ret); + return; + } + ret = clk_enable(phy_ref_clk); + if (ret < 0) { + pr_err("omap: ehci: Cannot clk_enable auxclk3 err %d", ret); + return; + } + + udelay(100); + gpio_set_value(GPIO_USB3333_RESETB, 1); + + /* Everything went well with phy clock, pass it to ehci driver for + * low power managment now + */ + usbhs_bdata.transceiver_clk[0] = phy_ref_clk; + + usbhs_init(&usbhs_bdata); + + pr_info("usb:ehci initialized"); + return; +} diff --git a/arch/arm/mach-omap2/board-tuna-vibrator.c b/arch/arm/mach-omap2/board-tuna-vibrator.c new file mode 100755 index 0000000..de1d5e7 --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-vibrator.c @@ -0,0 +1,185 @@ +/* arch/arm/mach-omap2/board-tuna-vibrator.c + * + * Copyright (C) 2011 Samsung Electronics Co. Ltd. All Rights Reserved. + * Author: Rom Lemarchand <rlemarchand@sta.samsung.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/hrtimer.h> +#include <linux/gpio.h> +#include <linux/wakelock.h> +#include <linux/mutex.h> +#include <asm/mach-types.h> +#include <plat/dmtimer.h> + +#include <../../../drivers/staging/android/timed_output.h> + +#include "mux.h" +#include "board-tuna.h" + +/* Vibrator enable pin is changed on Rev 05 to block not intended vibration. */ +#define GPIO_MOTOR_EN 162 +#define GPIO_MOTOR_EN_REV05 54 + +#define VIB_GPTIMER_NUM 10 +#define PWM_DUTY_MAX 1450 +#define MAX_TIMEOUT 10000 /* 10s */ + +static struct vibrator { + struct wake_lock wklock; + struct hrtimer timer; + struct mutex lock; + struct omap_dm_timer *gptimer; + bool enabled; + unsigned gpio_en; +} vibdata; + +static void vibrator_off(void) +{ + if (!vibdata.enabled) + return; + omap_dm_timer_stop(vibdata.gptimer); + gpio_set_value(vibdata.gpio_en, 0); + vibdata.enabled = false; + wake_unlock(&vibdata.wklock); +} + +static int vibrator_get_time(struct timed_output_dev *dev) +{ + if (hrtimer_active(&vibdata.timer)) { + ktime_t r = hrtimer_get_remaining(&vibdata.timer); + return ktime_to_ms(r); + } + + return 0; +} + +static void vibrator_enable(struct timed_output_dev *dev, int value) +{ + mutex_lock(&vibdata.lock); + + /* cancel previous timer and set GPIO according to value */ + hrtimer_cancel(&vibdata.timer); + + if (value) { + wake_lock(&vibdata.wklock); + + gpio_set_value(vibdata.gpio_en, 1); + omap_dm_timer_start(vibdata.gptimer); + + vibdata.enabled = true; + + if (value > 0) { + if (value > MAX_TIMEOUT) + value = MAX_TIMEOUT; + + hrtimer_start(&vibdata.timer, + ns_to_ktime((u64)value * NSEC_PER_MSEC), + HRTIMER_MODE_REL); + } + } else { + vibrator_off(); + } + + mutex_unlock(&vibdata.lock); +} + +static struct timed_output_dev to_dev = { + .name = "vibrator", + .get_time = vibrator_get_time, + .enable = vibrator_enable, +}; + +static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer) +{ + vibrator_off(); + return HRTIMER_NORESTART; +} + +static int __init vibrator_init(void) +{ + int ret; + + vibdata.enabled = false; + + hrtimer_init(&vibdata.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + vibdata.timer.function = vibrator_timer_func; + + vibdata.gptimer = omap_dm_timer_request_specific(VIB_GPTIMER_NUM); + if (vibdata.gptimer == NULL) + return -1; + + ret = omap_dm_timer_set_source(vibdata.gptimer, + OMAP_TIMER_SRC_SYS_CLK); + if (ret < 0) + goto err_dm_timer_src; + + omap_dm_timer_set_load(vibdata.gptimer, 1, -PWM_DUTY_MAX); + omap_dm_timer_set_match(vibdata.gptimer, 1, -PWM_DUTY_MAX+10); + omap_dm_timer_set_pwm(vibdata.gptimer, 0, 1, + OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE); + omap_dm_timer_enable(vibdata.gptimer); + omap_dm_timer_write_counter(vibdata.gptimer, -2); + omap_dm_timer_disable(vibdata.gptimer); + + wake_lock_init(&vibdata.wklock, WAKE_LOCK_SUSPEND, "vibrator"); + mutex_init(&vibdata.lock); + + ret = timed_output_dev_register(&to_dev); + if (ret < 0) + goto err_to_dev_reg; + + return 0; + +err_to_dev_reg: + mutex_destroy(&vibdata.lock); + wake_lock_destroy(&vibdata.wklock); + +err_dm_timer_src: + omap_dm_timer_free(vibdata.gptimer); + vibdata.gptimer = NULL; + + return -1; +} + +static int __init omap4_tuna_vibrator_init(void) +{ + int ret; + + if (!machine_is_tuna()) + return 0; + + vibdata.gpio_en = (omap4_tuna_get_revision() >= 5) ? + GPIO_MOTOR_EN_REV05 : GPIO_MOTOR_EN; + + omap_mux_init_gpio(vibdata.gpio_en, OMAP_PIN_OUTPUT | + OMAP_PIN_OFF_OUTPUT_LOW); + omap_mux_init_signal("dpm_emu18.dmtimer10_pwm_evt", OMAP_PIN_OUTPUT); + + ret = gpio_request(vibdata.gpio_en, "vibrator-en"); + if (ret) + return ret; + + gpio_direction_output(vibdata.gpio_en, 0); + + ret = vibrator_init(); + if (ret < 0) + gpio_free(vibdata.gpio_en); + + return ret; +} + +/* + * This is needed because the vibrator is dependent on omap_dm_timers which get + * initialized at device_init time + */ +late_initcall(omap4_tuna_vibrator_init); diff --git a/arch/arm/mach-omap2/board-tuna-wifi.c b/arch/arm/mach-omap2/board-tuna-wifi.c new file mode 100644 index 0000000..2c8909d --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna-wifi.c @@ -0,0 +1,419 @@ +/* + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <asm/mach-types.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/setup.h> +#include <linux/if.h> +#include <linux/skbuff.h> +#include <linux/wlan_plat.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/fixed.h> +#include <plat/mmc.h> + +#include <linux/random.h> +#include <linux/jiffies.h> + +#include "hsmmc.h" +#include "control.h" +#include "mux.h" +#include "board-tuna.h" + +#define GPIO_WLAN_PMENA 104 +#define GPIO_WLAN_IRQ 2 + +#define ATAG_TUNA_MAC 0x57464d41 +/* #define ATAG_TUNA_MAC_DEBUG */ + +#define PREALLOC_WLAN_NUMBER_OF_SECTIONS 4 +#define PREALLOC_WLAN_NUMBER_OF_BUFFERS 160 +#define PREALLOC_WLAN_SECTION_HEADER 24 + +#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128) +#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128) +#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 512) +#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 1024) + +#define WLAN_SKB_BUF_NUM 16 + +static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM]; + +typedef struct wifi_mem_prealloc_struct { + void *mem_ptr; + unsigned long size; +} wifi_mem_prealloc_t; + +static wifi_mem_prealloc_t wifi_mem_array[PREALLOC_WLAN_NUMBER_OF_SECTIONS] = { + { NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER) }, + { NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER) }, + { NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER) }, + { NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER) } +}; + +static void *tuna_wifi_mem_prealloc(int section, unsigned long size) +{ + if (section == PREALLOC_WLAN_NUMBER_OF_SECTIONS) + return wlan_static_skb; + if ((section < 0) || (section > PREALLOC_WLAN_NUMBER_OF_SECTIONS)) + return NULL; + if (wifi_mem_array[section].size < size) + return NULL; + return wifi_mem_array[section].mem_ptr; +} + +int __init tuna_init_wifi_mem(void) +{ + int i; + + for(i=0;( i < WLAN_SKB_BUF_NUM );i++) { + if (i < (WLAN_SKB_BUF_NUM/2)) + wlan_static_skb[i] = dev_alloc_skb(4096); + else + wlan_static_skb[i] = dev_alloc_skb(8192); + } + for(i=0;( i < PREALLOC_WLAN_NUMBER_OF_SECTIONS );i++) { + wifi_mem_array[i].mem_ptr = kmalloc(wifi_mem_array[i].size, + GFP_KERNEL); + if (wifi_mem_array[i].mem_ptr == NULL) + return -ENOMEM; + } + return 0; +} + +static struct resource tuna_wifi_resources[] = { + [0] = { + .name = "bcmdhd_wlan_irq", + .start = OMAP_GPIO_IRQ(GPIO_WLAN_IRQ), + .end = OMAP_GPIO_IRQ(GPIO_WLAN_IRQ), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE, + }, +}; + +#if 0 +/* BCM4329 returns wrong sdio_vsn(1) when we read cccr, + * we use predefined value (sdio_vsn=2) here to initial sdio driver well + */ +static struct embedded_sdio_data tuna_wifi_emb_data = { + .cccr = { + .sdio_vsn = 2, + .multi_block = 1, + .low_speed = 0, + .wide_bus = 0, + .high_power = 1, + .high_speed = 1, + }, +}; +#endif + +static int tuna_wifi_cd = 0; /* WIFI virtual 'card detect' status */ +static void (*wifi_status_cb)(int card_present, void *dev_id); +static void *wifi_status_cb_devid; +static struct regulator *clk32kaudio_reg; + +static int tuna_wifi_status_register( + void (*callback)(int card_present, void *dev_id), + void *dev_id) +{ + if (wifi_status_cb) + return -EAGAIN; + wifi_status_cb = callback; + wifi_status_cb_devid = dev_id; + return 0; +} + +static unsigned int tuna_wifi_status(struct device *dev) +{ + return tuna_wifi_cd; +} + +struct mmc_platform_data tuna_wifi_data = { + .ocr_mask = MMC_VDD_165_195 | MMC_VDD_20_21, + .built_in = 1, + .status = tuna_wifi_status, + .card_present = 0, + .register_status_notify = tuna_wifi_status_register, +}; + +static int tuna_wifi_set_carddetect(int val) +{ + pr_debug("%s: %d\n", __func__, val); + tuna_wifi_cd = val; + if (wifi_status_cb) { + wifi_status_cb(val, wifi_status_cb_devid); + } else + pr_warning("%s: Nobody to notify\n", __func__); + return 0; +} + +static int tuna_wifi_power_state; + +struct fixed_voltage_data { + struct regulator_desc desc; + struct regulator_dev *dev; + int microvolts; + int gpio; + unsigned startup_delay; + bool enable_high; + bool is_enabled; +}; + +static struct regulator_consumer_supply tuna_vmmc5_supply = { + .supply = "vmmc", + .dev_name = "omap_hsmmc.4", +}; + +static struct regulator_init_data tuna_vmmc5 = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &tuna_vmmc5_supply, +}; + +static struct fixed_voltage_config tuna_vwlan = { + .supply_name = "vwl1271", + .microvolts = 2000000, /* 2.0V */ + .gpio = GPIO_WLAN_PMENA, + .startup_delay = 70000, /* 70msec */ + .enable_high = 1, + .enabled_at_boot = 0, + .init_data = &tuna_vmmc5, +}; + +static struct platform_device omap_vwlan_device = { + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &tuna_vwlan, + }, +}; + +static int tuna_wifi_power(int on) +{ + if (!clk32kaudio_reg) { + clk32kaudio_reg = regulator_get(0, "clk32kaudio"); + if (IS_ERR(clk32kaudio_reg)) { + pr_err("%s: clk32kaudio reg not found!\n", __func__); + clk32kaudio_reg = NULL; + } + } + + if (clk32kaudio_reg && on && !tuna_wifi_power_state) + regulator_enable(clk32kaudio_reg); + + pr_debug("%s: %d\n", __func__, on); + mdelay(100); + gpio_set_value(GPIO_WLAN_PMENA, on); + mdelay(200); + + if (clk32kaudio_reg && !on && tuna_wifi_power_state) + regulator_disable(clk32kaudio_reg); + + tuna_wifi_power_state = on; + return 0; +} + +static int tuna_wifi_reset_state; + +static int tuna_wifi_reset(int on) +{ + pr_debug("%s: do nothing\n", __func__); + tuna_wifi_reset_state = on; + return 0; +} + +static unsigned char tuna_mac_addr[IFHWADDRLEN] = { 0,0x90,0x4c,0,0,0 }; + +static int __init tuna_mac_addr_setup(char *str) +{ + char macstr[IFHWADDRLEN*3]; + char *macptr = macstr; + char *token; + int i = 0; + + if (!str) + return 0; + pr_debug("wlan MAC = %s\n", str); + if (strlen(str) >= sizeof(macstr)) + return 0; + strcpy(macstr, str); + + while ((token = strsep(&macptr, ":")) != NULL) { + unsigned long val; + int res; + + if (i >= IFHWADDRLEN) + break; + res = strict_strtoul(token, 0x10, &val); + if (res < 0) + return 0; + tuna_mac_addr[i++] = (u8)val; + } + + return 1; +} + +__setup("androidboot.macaddr=", tuna_mac_addr_setup); + +static int tuna_wifi_get_mac_addr(unsigned char *buf) +{ + int type = omap4_tuna_get_type(); + uint rand_mac; + + if (type != TUNA_TYPE_TORO) + return -EINVAL; + + if (!buf) + return -EFAULT; + + if ((tuna_mac_addr[4] == 0) && (tuna_mac_addr[5] == 0)) { + srandom32((uint)jiffies); + rand_mac = random32(); + tuna_mac_addr[3] = (unsigned char)rand_mac; + tuna_mac_addr[4] = (unsigned char)(rand_mac >> 8); + tuna_mac_addr[5] = (unsigned char)(rand_mac >> 16); + } + memcpy(buf, tuna_mac_addr, IFHWADDRLEN); + return 0; +} + +/* Customized Locale table : OPTIONAL feature */ +#define WLC_CNTRY_BUF_SZ 4 +typedef struct cntry_locales_custom { + char iso_abbrev[WLC_CNTRY_BUF_SZ]; + char custom_locale[WLC_CNTRY_BUF_SZ]; + int custom_locale_rev; +} cntry_locales_custom_t; + +static cntry_locales_custom_t tuna_wifi_translate_custom_table[] = { +/* Table should be filled out based on custom platform regulatory requirement */ + {"", "XY", 4}, /* universal */ + {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ + {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ + {"EU", "EU", 5}, /* European union countries */ + {"AT", "EU", 5}, + {"BE", "EU", 5}, + {"BG", "EU", 5}, + {"CY", "EU", 5}, + {"CZ", "EU", 5}, + {"DK", "EU", 5}, + {"EE", "EU", 5}, + {"FI", "EU", 5}, + {"FR", "EU", 5}, + {"DE", "EU", 5}, + {"GR", "EU", 5}, + {"HU", "EU", 5}, + {"IE", "EU", 5}, + {"IT", "EU", 5}, + {"LV", "EU", 5}, + {"LI", "EU", 5}, + {"LT", "EU", 5}, + {"LU", "EU", 5}, + {"MT", "EU", 5}, + {"NL", "EU", 5}, + {"PL", "EU", 5}, + {"PT", "EU", 5}, + {"RO", "EU", 5}, + {"SK", "EU", 5}, + {"SI", "EU", 5}, + {"ES", "EU", 5}, + {"SE", "EU", 5}, + {"GB", "EU", 5}, /* input ISO "GB" to : EU regrev 05 */ + {"IL", "IL", 0}, + {"CH", "CH", 0}, + {"TR", "TR", 0}, + {"NO", "NO", 0}, + {"KR", "XY", 3}, + {"AU", "XY", 3}, + {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ + {"TW", "XY", 3}, + {"AR", "XY", 3}, + {"MX", "XY", 3} +}; + +static void *tuna_wifi_get_country_code(char *ccode) +{ + int size = ARRAY_SIZE(tuna_wifi_translate_custom_table); + int i; + + if (!ccode) + return NULL; + + for (i = 0; i < size; i++) + if (strcmp(ccode, tuna_wifi_translate_custom_table[i].iso_abbrev) == 0) + return &tuna_wifi_translate_custom_table[i]; + return &tuna_wifi_translate_custom_table[0]; +} + +static struct wifi_platform_data tuna_wifi_control = { + .set_power = tuna_wifi_power, + .set_reset = tuna_wifi_reset, + .set_carddetect = tuna_wifi_set_carddetect, + .mem_prealloc = tuna_wifi_mem_prealloc, + .get_mac_addr = tuna_wifi_get_mac_addr, + .get_country_code = tuna_wifi_get_country_code, +}; + +static struct platform_device tuna_wifi_device = { + .name = "bcmdhd_wlan", + .id = 1, + .num_resources = ARRAY_SIZE(tuna_wifi_resources), + .resource = tuna_wifi_resources, + .dev = { + .platform_data = &tuna_wifi_control, + }, +}; + +static void __init tuna_wlan_gpio(void) +{ + pr_debug("%s: start\n", __func__); + + /* WLAN SDIO: MMC5 CMD */ + omap_mux_init_signal("sdmmc5_cmd", OMAP_PIN_INPUT_PULLUP); + /* WLAN SDIO: MMC5 CLK */ + omap_mux_init_signal("sdmmc5_clk", OMAP_PIN_INPUT_PULLUP); + /* WLAN SDIO: MMC5 DAT[0-3] */ + omap_mux_init_signal("sdmmc5_dat0", OMAP_PIN_INPUT_PULLUP); + omap_mux_init_signal("sdmmc5_dat1", OMAP_PIN_INPUT_PULLUP); + omap_mux_init_signal("sdmmc5_dat2", OMAP_PIN_INPUT_PULLUP); + omap_mux_init_signal("sdmmc5_dat3", OMAP_PIN_INPUT_PULLUP); + /* WLAN OOB - BCM4330 - GPIO 16 or GPIO 2 */ + omap_mux_init_signal("sim_reset.gpio_wk2", OMAP_PIN_INPUT); + omap_mux_init_signal("kpd_row1.safe_mode", 0); + /* WLAN PMENA - GPIO 104 */ + omap_mux_init_signal("gpmc_ncs7.gpio_104", OMAP_PIN_OUTPUT); + /* Enable power to gpio_wk0-gpio_wk2 */ + omap4_ctrl_wk_pad_writel(0xb0000000, + OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_USIMIO); + + /* gpio_enable(GPIO_WLAN_IRQ); */ + gpio_request(GPIO_WLAN_IRQ, "wlan_irq"); + gpio_direction_input(GPIO_WLAN_IRQ); +} + +int __init tuna_wlan_init(void) +{ + pr_debug("%s: start\n", __func__); + + tuna_wlan_gpio(); + tuna_init_wifi_mem(); + platform_device_register(&omap_vwlan_device); + return platform_device_register(&tuna_wifi_device); +} diff --git a/arch/arm/mach-omap2/board-tuna.c b/arch/arm/mach-omap2/board-tuna.c new file mode 100644 index 0000000..3e0ff9a --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna.c @@ -0,0 +1,1362 @@ +/* Board support file for Samsung Tuna Board. + * + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2010 Texas Instruments + * + * Based on mach-omap2/board-omap4panda.c + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/ion.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include <linux/memblock.h> +#include <linux/omap_ion.h> +#include <linux/usb/otg.h> +#include <linux/i2c/twl.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/wl12xx.h> +#include <linux/reboot.h> +#include <linux/memblock.h> +#include <linux/sysfs.h> +#include <linux/uaccess.h> +#include <linux/proc_fs.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> +#include <linux/platform_data/lte_modem_bootloader.h> +#include <plat/mcspi.h> +#include <linux/i2c-gpio.h> + +#include <mach/hardware.h> +#include <mach/omap4-common.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/board-tuna-bluetooth.h> +#include <plat/omap-serial.h> +#include <plat/board.h> +#include <plat/common.h> +#include <plat/cpu.h> +#include <plat/usb.h> +#include <plat/mmc.h> +#include <plat/remoteproc.h> +#include <plat/omap-serial.h> + +#include <mach/id.h> +#include "timer-gp.h" + +#include "omap4-sar-layout.h" +#include "hsmmc.h" +#include "control.h" +#include "mux.h" +#include "board-tuna.h" +#include <mach/dmm.h> + +#define TUNA_RAMCONSOLE_START (PLAT_PHYS_OFFSET + SZ_512M) +#define TUNA_RAMCONSOLE_SIZE SZ_2M + +struct class *sec_class; +EXPORT_SYMBOL(sec_class); + +/* For LTE(CMC221) */ +#define OMAP_GPIO_LTE_ACTIVE 47 +#define OMAP_GPIO_CMC2AP_INT1 61 + +#define GPIO_AUD_PWRON 127 +#define GPIO_AUD_PWRON_TORO_V1 20 + +/* GPS GPIO Setting */ +#define GPIO_AP_AGPS_TSYNC 18 +#define GPIO_GPS_nRST 136 +#define GPIO_GPS_PWR_EN 137 +#define GPIO_GPS_UART_SEL 164 + +#define GPIO_MHL_SCL_18V 99 +#define GPIO_MHL_SDA_18V 98 + +#define REBOOT_FLAG_RECOVERY 0x52564352 +#define REBOOT_FLAG_FASTBOOT 0x54534146 +#define REBOOT_FLAG_NORMAL 0x4D524F4E +#define REBOOT_FLAG_POWER_OFF 0x46464F50 + +#define UART_NUM_FOR_GPS 0 + +static int tuna_hw_rev; + +static struct gpio tuna_hw_rev_gpios[] = { + {76, GPIOF_IN, "hw_rev0"}, + {75, GPIOF_IN, "hw_rev1"}, + {74, GPIOF_IN, "hw_rev2"}, + {73, GPIOF_IN, "hw_rev3"}, + {170, GPIOF_IN, "hw_rev4"}, +}; + +static const char const *omap4_tuna_hw_name_maguro[] = { + [0x00] = "Toro Lunchbox #1", + [0x01] = "Maguro 1st Sample", + [0x02] = "Maguro 2nd Sample", + [0x03] = "Maguro 4th Sample", + [0x05] = "Maguro 5th sample", +}; + +static const char const *omap4_tuna_hw_name_toro[] = { + [0x00] = "Toro Lunchbox #2", + [0x01] = "Toro 1st Sample", + [0x02] = "Toro 2nd Sample", + [0x03] = "Toro 4th Sample", + [0x05] = "Toro 5th Sample", +}; + +int omap4_tuna_get_revision(void) +{ + return tuna_hw_rev & TUNA_REV_MASK; +} + +int omap4_tuna_get_type(void) +{ + return tuna_hw_rev & TUNA_TYPE_MASK; +} + + +static const char *omap4_tuna_hw_rev_name(void) { + const char *ret; + const char **names; + int num; + int rev; + + if (omap4_tuna_get_type() == TUNA_TYPE_MAGURO) { + names = omap4_tuna_hw_name_maguro; + num = ARRAY_SIZE(omap4_tuna_hw_name_maguro); + ret = "Maguro unknown"; + } else { + names = omap4_tuna_hw_name_toro; + num = ARRAY_SIZE(omap4_tuna_hw_name_toro); + ret = "Toro unknown"; + } + + rev = omap4_tuna_get_revision(); + if (rev >= num || !names[rev]) + return ret; + + return names[rev]; +} + +/* + * Store a handy board information string which we can use elsewhere like + * like in panic situation + */ +static char omap4_tuna_bd_info_string[255]; +static void omap4_tuna_init_hw_rev(void) +{ + int ret; + int i; + u32 r; + + /* Disable weak driver pulldown on usbb2_hsic_strobe */ + r = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USBB_HSIC); + r &= ~OMAP4_USBB2_HSIC_STROBE_WD_MASK; + omap4_ctrl_pad_writel(r, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USBB_HSIC); + + ret = gpio_request_array(tuna_hw_rev_gpios, + ARRAY_SIZE(tuna_hw_rev_gpios)); + + BUG_ON(ret); + + for (i = 0; i < ARRAY_SIZE(tuna_hw_rev_gpios); i++) + tuna_hw_rev |= gpio_get_value(tuna_hw_rev_gpios[i].gpio) << i; + + snprintf(omap4_tuna_bd_info_string, + ARRAY_SIZE(omap4_tuna_bd_info_string), + "Tuna HW revision: %02x (%s), cpu %s ES%d.%d ", + tuna_hw_rev, + omap4_tuna_hw_rev_name(), + cpu_is_omap443x() ? "OMAP4430" : "OMAP4460", + (GET_OMAP_REVISION() >> 4) & 0xf, + GET_OMAP_REVISION() & 0xf); + + pr_info("%s\n", omap4_tuna_bd_info_string); + mach_panic_string = omap4_tuna_bd_info_string; +} + +/* wl127x BT, FM, GPS connectivity chip */ +static int wl1271_gpios[] = {46, -1, -1}; +static struct platform_device wl1271_device = { + .name = "kim", + .id = -1, + .dev = { + .platform_data = &wl1271_gpios, + }, +}; + +static struct resource ramconsole_resources[] = { + { + .flags = IORESOURCE_MEM, + .start = TUNA_RAMCONSOLE_START, + .end = TUNA_RAMCONSOLE_START + TUNA_RAMCONSOLE_SIZE - 1, + }, +}; + +static struct platform_device ramconsole_device = { + .name = "ram_console", + .id = -1, + .num_resources = ARRAY_SIZE(ramconsole_resources), + .resource = ramconsole_resources, +}; + +static struct platform_device bcm4330_bluetooth_device = { + .name = "bcm4330_bluetooth", + .id = -1, +}; + +static void __init tuna_bt_init(void) +{ + /* BT_EN - GPIO 104 */ + omap_mux_init_signal("gpmc_ncs6.gpio_103", OMAP_PIN_OUTPUT); + /*BT_nRST - GPIO 42 */ + omap_mux_init_signal("gpmc_a18.gpio_42", OMAP_PIN_OUTPUT); + /* BT_WAKE - GPIO 27 */ + omap_mux_init_signal("dpm_emu16.gpio_27", OMAP_PIN_OUTPUT); + /* BT_HOST_WAKE - GPIO 177 */ + omap_mux_init_signal("kpd_row5.gpio_177", OMAP_WAKEUP_EN | OMAP_PIN_INPUT); +} + +static struct twl4030_madc_platform_data twl6030_madc = { + .irq_line = -1, +}; + +static struct platform_device twl6030_madc_device = { + .name = "twl6030_madc", + .id = -1, + .dev = { + .platform_data = &twl6030_madc, + }, +}; + + +static struct i2c_gpio_platform_data tuna_gpio_i2c5_pdata = { + .sda_pin = GPIO_MHL_SDA_18V, + .scl_pin = GPIO_MHL_SCL_18V, + .udelay = 3, + .timeout = 0, +}; + +static struct platform_device tuna_gpio_i2c5_device = { + .name = "i2c-gpio", + .id = 5, + .dev = { + .platform_data = &tuna_gpio_i2c5_pdata, + } +}; + +#define OMAP_TUNA_ION_HEAP_SECURE_INPUT_SIZE (SZ_1M * 90) +#define OMAP_TUNA_ION_HEAP_TILER_SIZE (SZ_128M - SZ_32M) +#define OMAP_TUNA_ION_HEAP_NONSECURE_TILER_SIZE SZ_32M +#define OMAP_TUNA_ION_HEAP_LARGE_SURFACES_SIZE SZ_32M +#define PHYS_ADDR_SMC_SIZE (SZ_1M * 3) +#define PHYS_ADDR_SMC_MEM (0x80000000 + SZ_1G - PHYS_ADDR_SMC_SIZE) +#define PHYS_ADDR_DUCATI_SIZE (SZ_1M * 105) +#define PHYS_ADDR_DUCATI_MEM (PHYS_ADDR_SMC_MEM - PHYS_ADDR_DUCATI_SIZE -\ + OMAP_TUNA_ION_HEAP_SECURE_INPUT_SIZE) + +static struct ion_platform_data tuna_ion_data = { + .nr = 4, + .heaps = { + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = OMAP_ION_HEAP_SECURE_INPUT, + .name = "secure_input", + .base = PHYS_ADDR_SMC_MEM - + OMAP_TUNA_ION_HEAP_SECURE_INPUT_SIZE, + .size = OMAP_TUNA_ION_HEAP_SECURE_INPUT_SIZE, + }, + { .type = OMAP_ION_HEAP_TYPE_TILER, + .id = OMAP_ION_HEAP_TILER, + .name = "tiler", + .base = PHYS_ADDR_DUCATI_MEM - + OMAP_TUNA_ION_HEAP_TILER_SIZE, + .size = OMAP_TUNA_ION_HEAP_TILER_SIZE, + }, + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = OMAP_ION_HEAP_LARGE_SURFACES, + .name = "large_surfaces", + .base = 0x80000000 + SZ_512M + SZ_2M, + .size = OMAP_TUNA_ION_HEAP_LARGE_SURFACES_SIZE, + }, + { .type = OMAP_ION_HEAP_TYPE_TILER, + .id = OMAP_ION_HEAP_NONSECURE_TILER, + .name = "nonsecure_tiler", + .base = 0x80000000 + SZ_512M + SZ_2M + + OMAP_TUNA_ION_HEAP_LARGE_SURFACES_SIZE, + .size = OMAP_TUNA_ION_HEAP_NONSECURE_TILER_SIZE, + }, + }, +}; + +static struct platform_device tuna_ion_device = { + .name = "ion-omap4", + .id = -1, + .dev = { + .platform_data = &tuna_ion_data, + }, +}; + +static struct platform_device tuna_mcasp_device = { + .name = "omap-mcasp-dai", + .id = 0, +}; + +static struct platform_device tuna_spdif_dit_device = { + .name = "spdif-dit", + .id = 0, +}; + +static struct platform_device *tuna_devices[] __initdata = { + &ramconsole_device, + &wl1271_device, + &bcm4330_bluetooth_device, + &twl6030_madc_device, + &tuna_ion_device, + &tuna_gpio_i2c5_device, + &tuna_mcasp_device, + &tuna_spdif_dit_device, +}; + +/* + * The UART1 is for GPS, and CSR GPS chip should control uart1 rts level + * for gps firmware download. + */ +static int uart1_rts_ctrl_write(struct file *file, const char __user *buffer, + size_t count, loff_t *offs) +{ + char buf[10] = {0,}; + + if (omap4_tuna_get_revision() < TUNA_REV_SAMPLE_4) + return -ENXIO; + if (count > sizeof(buf) - 1) + return -EINVAL; + if (copy_from_user(buf, buffer, count)) + return -EFAULT; + + if (!strncmp(buf, "1", 1)) { + omap_rts_mux_write(OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE7, + UART_NUM_FOR_GPS); + } else if (!strncmp(buf, "0", 1)) { + omap_rts_mux_write(OMAP_PIN_OUTPUT | OMAP_MUX_MODE1, + UART_NUM_FOR_GPS); + } + + return count; +} + +static const struct file_operations uart1_rts_ctrl_proc_fops = { + .write = uart1_rts_ctrl_write, +}; + +static int __init tuna_gps_rts_ctrl_init(void) +{ + struct proc_dir_entry *p_entry; + + p_entry = proc_create("mcspi1_cs3_ctrl", 0666, NULL, + &uart1_rts_ctrl_proc_fops); + + if (!p_entry) + return -ENOMEM; + + return 0; +} + +static void tuna_gsd4t_gps_gpio(void) +{ + /* AP_AGPS_TSYNC - GPIO 18 */ + omap_mux_init_signal("dpm_emu7.gpio_18", OMAP_PIN_OUTPUT); + /* GPS_nRST - GPIO 136 */ + omap_mux_init_signal("mcspi1_simo.gpio_136", OMAP_PIN_OUTPUT); + /* GPS_PWR_EN - GPIO 137 */ + omap_mux_init_signal("mcspi1_cs0.gpio_137", OMAP_PIN_OUTPUT); + /* GPS_UART_SEL - GPIO 164 */ + omap_mux_init_signal("usbb2_ulpitll_dat3.gpio_164", OMAP_PIN_OUTPUT); +} + +static void tuna_gsd4t_gps_init(void) +{ + struct device *gps_dev; + + gps_dev = device_create(sec_class, NULL, 0, NULL, "gps"); + if (IS_ERR(gps_dev)) { + pr_err("Failed to create device(gps)!\n"); + goto err; + } + tuna_gsd4t_gps_gpio(); + + gpio_request(GPIO_AP_AGPS_TSYNC, "AP_AGPS_TSYNC"); + gpio_direction_output(GPIO_AP_AGPS_TSYNC, 0); + + gpio_request(GPIO_GPS_nRST, "GPS_nRST"); + gpio_direction_output(GPIO_GPS_nRST, 1); + + gpio_request(GPIO_GPS_PWR_EN, "GPS_PWR_EN"); + gpio_direction_output(GPIO_GPS_PWR_EN, 0); + + gpio_request(GPIO_GPS_UART_SEL , "GPS_UART_SEL"); + gpio_direction_output(GPIO_GPS_UART_SEL , 0); + + gpio_export(GPIO_GPS_nRST, 1); + gpio_export(GPIO_GPS_PWR_EN, 1); + + gpio_export_link(gps_dev, "GPS_nRST", GPIO_GPS_nRST); + gpio_export_link(gps_dev, "GPS_PWR_EN", GPIO_GPS_PWR_EN); + + tuna_gps_rts_ctrl_init(); + +err: + return; +} + +static int __init sec_common_init(void) +{ + sec_class = class_create(THIS_MODULE, "sec"); + if (IS_ERR(sec_class)) + pr_err("Failed to create class(sec)!\n"); + + return 0; +} + +static void __init tuna_init_early(void) +{ + omap2_init_common_infrastructure(); + omap2_init_common_devices(NULL, NULL); +} + +static struct omap_musb_board_data musb_board_data = { + .interface_type = MUSB_INTERFACE_UTMI, +#ifdef CONFIG_USB_MUSB_OTG + .mode = MUSB_OTG, +#else + .mode = MUSB_PERIPHERAL, +#endif + .power = 100, +}; + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 1, + .nonremovable = true, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .ocr_mask = MMC_VDD_165_195, + .gpio_wp = -EINVAL, + .gpio_cd = -EINVAL, + }, + { + .name = "omap_wlan", + .mmc = 5, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_wp = -EINVAL, + .gpio_cd = -EINVAL, + .ocr_mask = MMC_VDD_165_195 | MMC_VDD_20_21, + .nonremovable = false, + .mmc_data = &tuna_wifi_data, + }, + {} /* Terminator */ +}; + +static struct regulator_consumer_supply tuna_vmmc_supply[] = { + { + .supply = "vmmc", + .dev_name = "omap_hsmmc.0", + }, + { + .supply = "vmmc", + .dev_name = "omap_hsmmc.1", + }, +}; + +static struct regulator_init_data tuna_vaux1 = { + .constraints = { + .min_uV = 3000000, + .max_uV = 3000000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + .always_on = true, + }, +}; + +static struct regulator_init_data tuna_vaux2 = { + .constraints = { + .min_uV = 1200000, + .max_uV = 2800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, +}; + +static struct regulator_consumer_supply tuna_vaux3_supplies[] = { + { + .supply = "vlcd", + }, +}; + +static struct regulator_init_data tuna_vaux3 = { + .constraints = { + .min_uV = 3100000, + .max_uV = 3100000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(tuna_vaux3_supplies), + .consumer_supplies = tuna_vaux3_supplies, +}; + +static struct regulator_init_data tuna_vmmc = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 2, + .consumer_supplies = tuna_vmmc_supply, +}; + +static struct regulator_init_data tuna_vpp = { + .constraints = { + .min_uV = 1800000, + .max_uV = 2500000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, +}; + +static struct regulator_consumer_supply tuna_vusim_supplies[] = { + { + .supply = "vlcd-iovcc", + }, +}; + +static struct regulator_init_data tuna_vusim = { + .constraints = { + .min_uV = 2200000, + .max_uV = 2200000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(tuna_vusim_supplies), + .consumer_supplies = tuna_vusim_supplies, +}; + +static struct regulator_init_data tuna_vana = { + .constraints = { + .min_uV = 2100000, + .max_uV = 2100000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + .always_on = true, + }, +}; + +static struct regulator_consumer_supply tuna_vcxio_supply[] = { + REGULATOR_SUPPLY("vdds_dsi", "omapdss_dss"), + REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"), +}; + +static struct regulator_init_data tuna_vcxio = { + .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 = ARRAY_SIZE(tuna_vcxio_supply), + .consumer_supplies = tuna_vcxio_supply, + +}; + +static struct regulator_consumer_supply tuna_vdac_supply[] = { + { + .supply = "hdmi_vref", + }, +}; + +static struct regulator_init_data tuna_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 = ARRAY_SIZE(tuna_vdac_supply), + .consumer_supplies = tuna_vdac_supply, +}; + +static struct regulator_consumer_supply tuna_vusb_supply[] = { + REGULATOR_SUPPLY("vusb", "tuna_otg"), +}; + +static struct regulator_init_data tuna_vusb = { + .constraints = { + .min_uV = 3300000, + .max_uV = 3300000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(tuna_vusb_supply), + .consumer_supplies = tuna_vusb_supply, +}; + +/* clk32kg is a twl6030 32khz clock modeled as a regulator, used by GPS */ +static struct regulator_init_data tuna_clk32kg = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .always_on = true, + }, +}; + +static struct regulator_consumer_supply tuna_clk32kaudio_supply[] = { + { + .supply = "clk32kaudio", + }, + { + .supply = "twl6040_clk32k", + } +}; + +static struct regulator_init_data tuna_clk32kaudio = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = true, + }, + .num_consumer_supplies = ARRAY_SIZE(tuna_clk32kaudio_supply), + .consumer_supplies = tuna_clk32kaudio_supply, +}; + + +static struct regulator_init_data tuna_vdd3 = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, +}; + +/* + * VMEM is unused. Register it to regulator framework and let it + * be in disabled state. + */ +static struct regulator_init_data tuna_vmem = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, +}; + +static struct regulator_init_data tuna_v2v1 = { + .constraints = { + .min_uV = 2100000, + .max_uV = 2100000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + .always_on = true, + }, +}; + +static struct twl4030_codec_audio_data twl6040_audio = { + /* single-step ramp for headset and handsfree */ + .hs_left_step = 0x0f, + .hs_right_step = 0x0f, + .hf_left_step = 0x1d, + .hf_right_step = 0x1d, + .ep_step = 0x0f, +}; + +static struct twl4030_codec_data twl6040_codec = { + .audio = &twl6040_audio, + .naudint_irq = OMAP44XX_IRQ_SYS_2N, + .irq_base = TWL6040_CODEC_IRQ_BASE, +}; + +static struct twl4030_platform_data tuna_twldata = { + .irq_base = TWL6030_IRQ_BASE, + .irq_end = TWL6030_IRQ_END, + + /* Regulators */ + .vmmc = &tuna_vmmc, + .vpp = &tuna_vpp, + .vusim = &tuna_vusim, + .vana = &tuna_vana, + .vcxio = &tuna_vcxio, + .vdac = &tuna_vdac, + .vusb = &tuna_vusb, + .vaux1 = &tuna_vaux1, + .vaux2 = &tuna_vaux2, + .vaux3 = &tuna_vaux3, + .clk32kg = &tuna_clk32kg, + .clk32kaudio = &tuna_clk32kaudio, + + /* children */ + .codec = &twl6040_codec, + .madc = &twl6030_madc, + + /* SMPS */ + .vdd3 = &tuna_vdd3, + .vmem = &tuna_vmem, + .v2v1 = &tuna_v2v1, +}; + +static void tuna_audio_init(void) +{ + unsigned int aud_pwron; + + /* twl6040 naudint */ + omap_mux_init_signal("sys_nirq2.sys_nirq2", \ + OMAP_PIN_INPUT_PULLUP); + + /* aud_pwron */ + if (omap4_tuna_get_type() == TUNA_TYPE_TORO && + omap4_tuna_get_revision() >= 1) + aud_pwron = GPIO_AUD_PWRON_TORO_V1; + else + aud_pwron = GPIO_AUD_PWRON; + omap_mux_init_gpio(aud_pwron, OMAP_PIN_OUTPUT); + twl6040_codec.audpwron_gpio = aud_pwron; + + omap_mux_init_signal("gpmc_a24.gpio_48", OMAP_PIN_OUTPUT | OMAP_MUX_MODE3); + omap_mux_init_signal("kpd_col3.gpio_171", OMAP_PIN_OUTPUT | OMAP_MUX_MODE3); +} + +static struct i2c_board_info __initdata tuna_i2c1_boardinfo[] = { + { + I2C_BOARD_INFO("twl6030", 0x48), + .flags = I2C_CLIENT_WAKE, + .irq = OMAP44XX_IRQ_SYS_1N, + .platform_data = &tuna_twldata, + }, +}; + +static struct i2c_board_info __initdata tuna_i2c2_boardinfo[] = { + { + I2C_BOARD_INFO("ducati", 0x20), + .irq = OMAP44XX_IRQ_I2C2, + .ext_master = true, + }, +}; + +static struct i2c_board_info __initdata tuna_i2c4_boardinfo[] = { + { + I2C_BOARD_INFO("an30259a", 0x30), + }, +}; + +static int __init tuna_i2c_init(void) +{ + u32 r; + + omap_mux_init_signal("sys_nirq1", OMAP_PIN_INPUT_PULLUP | + OMAP_WAKEUP_EN); + omap_mux_init_signal("i2c1_scl.i2c1_scl", OMAP_PIN_INPUT_PULLUP); + omap_mux_init_signal("i2c1_sda.i2c1_sda", OMAP_PIN_INPUT_PULLUP); + + /* + * This will allow unused regulator to be shutdown. This flag + * should be set in the board file. Before regulators are registered. + */ + regulator_has_full_constraints(); + + /* + * Phoenix Audio IC needs I2C1 to + * start with 400 KHz or less + */ + omap_register_i2c_bus(1, 400, tuna_i2c1_boardinfo, + ARRAY_SIZE(tuna_i2c1_boardinfo)); + omap_register_i2c_bus(2, 400, tuna_i2c2_boardinfo, + ARRAY_SIZE(tuna_i2c2_boardinfo)); + omap_register_i2c_bus(3, 400, NULL, 0); + + /* Disable internal pullup on i2c.4 line: + * as external 2.2K is already present + */ + r = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_0); + r |= (1 << OMAP4_I2C4_SDA_PULLUPRESX_SHIFT); + omap4_ctrl_pad_writel(r, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_0); + + omap_register_i2c_bus(4, 400, NULL, 0); + + /* + * Drive MSECURE high for TWL6030 write access. + */ + omap_mux_init_signal("fref_clk0_out.gpio_wk6", OMAP_PIN_OUTPUT); + gpio_request(6, "msecure"); + gpio_direction_output(6, 1); + + return 0; +} + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + /* camera gpios */ + OMAP4_MUX(MCSPI1_SOMI, + OMAP_MUX_MODE3 | OMAP_PIN_INPUT_PULLDOWN), /* gpio_135 */ + OMAP4_MUX(KPD_COL0, + OMAP_MUX_MODE3 | OMAP_PIN_INPUT_PULLDOWN), /* gpio_173 */ + OMAP4_MUX(GPMC_A19, + OMAP_MUX_MODE3 | OMAP_PIN_INPUT_PULLDOWN), /* gpio_43 */ + /* hwrev */ + OMAP4_MUX(CSI21_DY4, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP4_MUX(CSI21_DX4, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP4_MUX(CSI21_DY3, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP4_MUX(CSI21_DX3, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP4_MUX(USBB2_HSIC_STROBE, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + /* fRom */ + OMAP4_MUX(USBB2_ULPITLL_DAT4, + OMAP_MUX_MODE4 | OMAP_PIN_INPUT), /* mcpsi3_somi */ + OMAP4_MUX(USBB2_ULPITLL_DAT5, + OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLDOWN), /* mcpsi3_cs0 */ + OMAP4_MUX(USBB2_ULPITLL_DAT6, + OMAP_MUX_MODE4 | OMAP_PIN_INPUT), /* mcpsi3_simo */ + OMAP4_MUX(USBB2_ULPITLL_DAT7, + OMAP_MUX_MODE4 | OMAP_PIN_INPUT), /* mcpsi3_clk */ + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; + +static struct omap_board_mux board_wkup_mux[] __initdata = { + /* power button */ + OMAP4_MUX(SIM_CD, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; + +#else +#define board_mux NULL +#define board_wkup_mux NULL +#endif + +/* sample4+ adds gps rts/cts lines */ +static struct omap_device_pad tuna_uart1_pads_sample4[] __initdata = { + { + .name = "mcspi1_cs3.uart1_rts", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE1, + }, + { + .name = "mcspi1_cs2.uart1_cts", + .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE1, + }, + { + .name = "uart3_cts_rctx.uart1_tx", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE1, + }, + { + .name = "mcspi1_cs1.uart1_rx", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE1, + .idle = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE1, + }, +}; + +static struct omap_device_pad tuna_uart1_pads[] __initdata = { + { + .name = "uart3_cts_rctx.uart1_tx", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE1, + }, + { + .name = "mcspi1_cs1.uart1_rx", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE1, + .idle = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE1, + }, +}; + +static struct omap_device_pad tuna_uart2_pads[] __initdata = { + { + .name = "uart2_cts.uart2_cts", + .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0, + }, + { + .name = "uart2_rts.uart2_rts", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0, + }, + { + .name = "uart2_tx.uart2_tx", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0, + }, + { + .name = "uart2_rx.uart2_rx", + .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0, + }, +}; + +static struct omap_device_pad tuna_uart3_pads[] __initdata = { + { + .name = "uart3_tx_irtx.uart3_tx_irtx", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0, + }, + { + .name = "uart3_rx_irrx.uart3_rx_irrx", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = OMAP_PIN_INPUT | OMAP_MUX_MODE0, + .idle = OMAP_PIN_INPUT | OMAP_MUX_MODE0, + }, +}; + +static struct omap_device_pad tuna_uart4_pads[] __initdata = { + { + .name = "uart4_tx.uart4_tx", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0, + }, + { + .name = "uart4_rx.uart4_rx", + .enable = OMAP_PIN_INPUT | OMAP_MUX_MODE0, + }, +}; + +static struct omap_uart_port_info tuna_uart2_info __initdata = { + .use_dma = 0, + .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE, + .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE, + .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT, + .auto_sus_timeout = DEFAULT_AUTOSUSPEND_DELAY, + .wake_peer = bcm_bt_lpm_exit_lpm_locked, + .rts_mux_driver_control = 1, +}; + +static inline void __init board_serial_init(void) +{ + struct omap_device_pad *uart1_pads; + int uart1_pads_sz; + + if (omap4_tuna_get_revision() >= TUNA_REV_SAMPLE_4) { + uart1_pads = tuna_uart1_pads_sample4; + uart1_pads_sz = ARRAY_SIZE(tuna_uart1_pads_sample4); + } else { + uart1_pads = tuna_uart1_pads; + uart1_pads_sz = ARRAY_SIZE(tuna_uart1_pads); + } + + omap_serial_init_port_pads(0, uart1_pads, uart1_pads_sz, NULL); + omap_serial_init_port_pads(1, tuna_uart2_pads, + ARRAY_SIZE(tuna_uart2_pads), &tuna_uart2_info); + omap_serial_init_port_pads(2, tuna_uart3_pads, + ARRAY_SIZE(tuna_uart3_pads), NULL); + omap_serial_init_port_pads(3, tuna_uart4_pads, + ARRAY_SIZE(tuna_uart4_pads), NULL); +} + +/* SPI flash memory in camera module */ +#define F_ROM_SPI_BUS_NUM 3 +#define F_ROM_SPI_CS 0 +#define F_ROM_SPI_SPEED_HZ 24000000 + +static const struct flash_platform_data w25q80_pdata = { + .name = "w25q80", + .type = "w25q80", +}; + +static struct omap2_mcspi_device_config f_rom_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, /* 0: slave, 1: master */ + .swap_datalines = 1, +}; + +static struct spi_board_info tuna_f_rom[] __initdata = { + { + .modalias = "m25p80", + .controller_data = &f_rom_mcspi_config, + .platform_data = &w25q80_pdata, + .bus_num = F_ROM_SPI_BUS_NUM, + .chip_select = F_ROM_SPI_CS, + .max_speed_hz = F_ROM_SPI_SPEED_HZ, + .mode = SPI_MODE_0, + }, +}; + +static void tuna_from_init(void) +{ + int err; + + if (tuna_hw_rev >= 0x07) + f_rom_mcspi_config.swap_datalines = 0; + + err = spi_register_board_info(tuna_f_rom, ARRAY_SIZE(tuna_f_rom)); + if (err) + pr_err("failed to register SPI F-ROM\n"); +} + +/*SPI for LTE modem bootloader*/ +#define LTE_MODEM_SPI_BUS_NUM 4 +#define LTE_MODEM_SPI_CS 0 +#define LTE_MODEM_SPI_MAX_HZ 1500000 + +struct lte_modem_bootloader_platform_data lte_modem_bootloader_pdata = { + .name = "lte_modem_int", + .gpio_lte2ap_status = OMAP_GPIO_CMC2AP_INT1, +}; + +static struct omap2_mcspi_device_config lte_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, /* 0: slave, 1: master */ +}; + +static struct spi_board_info tuna_lte_modem[] __initdata = { + { + .modalias = "lte_modem_spi", + .controller_data = <e_mcspi_config, + .platform_data = <e_modem_bootloader_pdata, + .max_speed_hz = LTE_MODEM_SPI_MAX_HZ, + .bus_num = LTE_MODEM_SPI_BUS_NUM, + .chip_select = LTE_MODEM_SPI_CS, + .mode = SPI_MODE_0, + }, +}; + +static int tuna_notifier_call(struct notifier_block *this, + unsigned long code, void *_cmd) +{ + void __iomem *sar_base; + unsigned int flag = REBOOT_FLAG_NORMAL; + + sar_base = omap4_get_sar_ram_base(); + + if (!sar_base) + return notifier_from_errno(-ENOMEM); + + if (code == SYS_RESTART) { + if (_cmd) { + if (!strcmp(_cmd, "recovery")) + flag = REBOOT_FLAG_RECOVERY; + else if (!strcmp(_cmd, "bootloader")) + flag = REBOOT_FLAG_FASTBOOT; + } + } else if (code == SYS_POWER_OFF) { + flag = REBOOT_FLAG_POWER_OFF; + } + + /* The Samsung LOKE bootloader will look for the boot flag at a fixed + * offset from the end of the 1st SAR bank. + */ + writel(flag, sar_base + SAR_BANK2_OFFSET - 0xC); + + return NOTIFY_DONE; +} + +static struct notifier_block tuna_reboot_notifier = { + .notifier_call = tuna_notifier_call, +}; + +static ssize_t tuna_soc_family_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "OMAP%04x\n", GET_OMAP_TYPE); +} + +static ssize_t tuna_soc_revision_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "ES%d.%d\n", (GET_OMAP_REVISION() >> 4) & 0xf, + GET_OMAP_REVISION() & 0xf); +} + +static ssize_t tuna_soc_die_id_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct omap_die_id oid; + omap_get_die_id(&oid); + return sprintf(buf, "%08X-%08X-%08X-%08X\n", oid.id_3, oid.id_2, + oid.id_1, oid.id_0); +} + +static ssize_t tuna_soc_prod_id_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct omap_die_id oid; + omap_get_production_id(&oid); + return sprintf(buf, "%08X-%08X\n", oid.id_1, oid.id_0); +} + +static ssize_t tuna_soc_msv_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%08X\n", omap_ctrl_readl(0x013c)); +} + +static const char *omap_types[] = { + [OMAP2_DEVICE_TYPE_TEST] = "TST", + [OMAP2_DEVICE_TYPE_EMU] = "EMU", + [OMAP2_DEVICE_TYPE_SEC] = "HS", + [OMAP2_DEVICE_TYPE_GP] = "GP", + [OMAP2_DEVICE_TYPE_BAD] = "BAD", +}; + +static ssize_t tuna_soc_type_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", omap_types[omap_type()]); +} + +#define TUNA_ATTR_RO(_type, _name, _show) \ + struct kobj_attribute tuna_##_type##_prop_attr_##_name = \ + __ATTR(_name, S_IRUGO, _show, NULL) + +static TUNA_ATTR_RO(soc, family, tuna_soc_family_show); +static TUNA_ATTR_RO(soc, revision, tuna_soc_revision_show); +static TUNA_ATTR_RO(soc, type, tuna_soc_type_show); +static TUNA_ATTR_RO(soc, die_id, tuna_soc_die_id_show); +static TUNA_ATTR_RO(soc, production_id, tuna_soc_prod_id_show); +static TUNA_ATTR_RO(soc, msv, tuna_soc_msv_show); + +static struct attribute *tuna_soc_prop_attrs[] = { + &tuna_soc_prop_attr_family.attr, + &tuna_soc_prop_attr_revision.attr, + &tuna_soc_prop_attr_type.attr, + &tuna_soc_prop_attr_die_id.attr, + &tuna_soc_prop_attr_production_id.attr, + &tuna_soc_prop_attr_msv.attr, + NULL, +}; + +static struct attribute_group tuna_soc_prop_attr_group = { + .attrs = tuna_soc_prop_attrs, +}; + +static ssize_t tuna_board_revision_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%s (0x%02x)\n", omap4_tuna_hw_rev_name(), + tuna_hw_rev); +} + +static TUNA_ATTR_RO(board, revision, tuna_board_revision_show); +static struct attribute *tuna_board_prop_attrs[] = { + &tuna_board_prop_attr_revision.attr, + NULL, +}; + +static struct attribute_group tuna_board_prop_attr_group = { + .attrs = tuna_board_prop_attrs, +}; + +static void __init omap4_tuna_create_board_props(void) +{ + struct kobject *board_props_kobj; + struct kobject *soc_kobj; + int ret = 0; + + board_props_kobj = kobject_create_and_add("board_properties", NULL); + if (!board_props_kobj) + goto err_board_obj; + + soc_kobj = kobject_create_and_add("soc", board_props_kobj); + if (!soc_kobj) + goto err_soc_obj; + + ret = sysfs_create_group(board_props_kobj, &tuna_board_prop_attr_group); + if (ret) + goto err_board_sysfs_create; + + ret = sysfs_create_group(soc_kobj, &tuna_soc_prop_attr_group); + if (ret) + goto err_soc_sysfs_create; + + return; + +err_soc_sysfs_create: + sysfs_remove_group(board_props_kobj, &tuna_board_prop_attr_group); +err_board_sysfs_create: + kobject_put(soc_kobj); +err_soc_obj: + kobject_put(board_props_kobj); +err_board_obj: + if (!board_props_kobj || !soc_kobj || ret) + pr_err("failed to create board_properties\n"); +} + +#define HSMMC2_MUX (OMAP_MUX_MODE1 | OMAP_PIN_INPUT_PULLUP) +#define HSMMC1_MUX OMAP_PIN_INPUT_PULLUP + +static void __init omap4_tuna_led_init(void) +{ + i2c_register_board_info(4, tuna_i2c4_boardinfo, + ARRAY_SIZE(tuna_i2c4_boardinfo)); +} + +/* always reboot into charger mode on "power-off". Let the bootloader + * figure out if we should truly power-off or not. + */ +static void tuna_power_off(void) +{ + printk(KERN_EMERG "Rebooting into bootloader for power-off.\n"); + arm_pm_restart('c', NULL); +} + +static void __init tuna_init(void) +{ + int package = OMAP_PACKAGE_CBS; + + if (omap_rev() == OMAP4430_REV_ES1_0) + package = OMAP_PACKAGE_CBL; + omap4_mux_init(board_mux, board_wkup_mux, package); + + omap4_tuna_init_hw_rev(); + + omap4_tuna_emif_init(); + + pm_power_off = tuna_power_off; + + register_reboot_notifier(&tuna_reboot_notifier); + + /* hsmmc d0-d7 */ + omap_mux_init_signal("sdmmc1_dat0.sdmmc1_dat0", HSMMC1_MUX); + omap_mux_init_signal("sdmmc1_dat1.sdmmc1_dat1", HSMMC1_MUX); + omap_mux_init_signal("sdmmc1_dat2.sdmmc1_dat2", HSMMC1_MUX); + omap_mux_init_signal("sdmmc1_dat3.sdmmc1_dat3", HSMMC1_MUX); + omap_mux_init_signal("sdmmc1_dat4.sdmmc1_dat4", HSMMC1_MUX); + omap_mux_init_signal("sdmmc1_dat5.sdmmc1_dat5", HSMMC1_MUX); + omap_mux_init_signal("sdmmc1_dat6.sdmmc1_dat6", HSMMC1_MUX); + omap_mux_init_signal("sdmmc1_dat7.sdmmc1_dat7", HSMMC1_MUX); + /* hsmmc cmd */ + omap_mux_init_signal("sdmmc1_cmd.sdmmc1_cmd", HSMMC1_MUX); + /* hsmmc clk */ + omap_mux_init_signal("sdmmc1_clk.sdmmc1_clk", HSMMC1_MUX); + + gpio_request(158, "emmc_en"); + gpio_direction_output(158, 1); + omap_mux_init_gpio(158, OMAP_PIN_INPUT_PULLUP); + + omap_mux_init_gpio(GPIO_MHL_SDA_18V, OMAP_PIN_INPUT_PULLUP); + omap_mux_init_gpio(GPIO_MHL_SCL_18V, OMAP_PIN_INPUT_PULLUP); + + sec_common_init(); + + if (TUNA_TYPE_TORO == omap4_tuna_get_type()) { + omap_mux_init_signal("gpmc_wait0", + OMAP_MUX_MODE3 | OMAP_PIN_INPUT_PULLDOWN); + gpio_request(OMAP_GPIO_CMC2AP_INT1, "gpio_61"); + gpio_direction_input(OMAP_GPIO_CMC2AP_INT1); + + omap_mux_init_signal("mcspi4_clk", OMAP_MUX_MODE0); + omap_mux_init_signal("mcspi4_simo", OMAP_MUX_MODE0); + omap_mux_init_signal("mcspi4_somi", OMAP_MUX_MODE0); + omap_mux_init_signal("mcspi4_cs0", OMAP_MUX_MODE0); + } + + tuna_wlan_init(); + tuna_audio_init(); + tuna_i2c_init(); + tuna_bt_init(); + tuna_gsd4t_gps_init(); + platform_add_devices(tuna_devices, ARRAY_SIZE(tuna_devices)); + board_serial_init(); + omap2_hsmmc_init(mmc); + usb_musb_init(&musb_board_data); + omap4_tuna_create_board_props(); + if (TUNA_TYPE_TORO == omap4_tuna_get_type()) { + spi_register_board_info(tuna_lte_modem, + ARRAY_SIZE(tuna_lte_modem)); + } + tuna_from_init(); + omap_dmm_init(); + omap4_tuna_display_init(); + omap4_tuna_input_init(); + omap4_tuna_nfc_init(); + omap4_tuna_power_init(); + omap4_tuna_jack_init(); + omap4_tuna_sensors_init(); + omap4_tuna_led_init(); + omap4_tuna_pogo_init(); + omap4_tuna_connector_init(); +#ifdef CONFIG_OMAP_HSI_DEVICE + if (TUNA_TYPE_MAGURO == omap4_tuna_get_type()) + omap_hsi_init(); +#endif +#ifdef CONFIG_USB_EHCI_HCD_OMAP + if (TUNA_TYPE_TORO == omap4_tuna_get_type()) { +#ifdef CONFIG_SEC_MODEM + modem_toro_init(); +#endif + omap4_ehci_init(); + } +#endif +} + +static void __init tuna_map_io(void) +{ + omap2_set_globals_443x(); + omap44xx_map_common_io(); +} + +static void __init tuna_reserve(void) +{ + int i; + int ret; + + /* do the static reservations first */ + memblock_remove(TUNA_RAMCONSOLE_START, TUNA_RAMCONSOLE_SIZE); + memblock_remove(PHYS_ADDR_SMC_MEM, PHYS_ADDR_SMC_SIZE); + memblock_remove(PHYS_ADDR_DUCATI_MEM, PHYS_ADDR_DUCATI_SIZE); + + for (i = 0; i < tuna_ion_data.nr; i++) + if (tuna_ion_data.heaps[i].type == ION_HEAP_TYPE_CARVEOUT || + tuna_ion_data.heaps[i].type == OMAP_ION_HEAP_TYPE_TILER) { + ret = memblock_remove(tuna_ion_data.heaps[i].base, + tuna_ion_data.heaps[i].size); + if (ret) + pr_err("memblock remove of %x@%lx failed\n", + tuna_ion_data.heaps[i].size, + tuna_ion_data.heaps[i].base); + } + + /* ipu needs to recognize secure input buffer area as well */ + omap_ipu_set_static_mempool(PHYS_ADDR_DUCATI_MEM, PHYS_ADDR_DUCATI_SIZE + + OMAP_TUNA_ION_HEAP_SECURE_INPUT_SIZE); + omap_reserve(); +} + +MACHINE_START(TUNA, "Tuna") + /* Maintainer: Google, Inc */ + .boot_params = 0x80000100, + .reserve = tuna_reserve, + .map_io = tuna_map_io, + .init_early = tuna_init_early, + .init_irq = gic_init_irq, + .init_machine = tuna_init, + .timer = &omap_timer, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-tuna.h b/arch/arm/mach-omap2/board-tuna.h new file mode 100644 index 0000000..5f2ec1c --- /dev/null +++ b/arch/arm/mach-omap2/board-tuna.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MACH_OMAP2_BOARD_TUNA_H_ +#define _MACH_OMAP2_BOARD_TUNA_H_ + +#define TUNA_REV_MASK 0xf +#define TUNA_REV_03 0x3 +#define TUNA_REV_SAMPLE_4 0x3 + +#define TUNA_TYPE_TORO 0x10 +#define TUNA_TYPE_MAGURO 0x00 +#define TUNA_TYPE_MASK 0x10 + +#define TUNA_GPIO_HDMI_HPD 63 + +int omap4_tuna_get_revision(void); +int omap4_tuna_get_type(void); +bool omap4_tuna_final_gpios(void); +void omap4_tuna_display_init(void); +void omap4_tuna_input_init(void); +void omap4_tuna_jack_init(void); +void omap4_tuna_nfc_init(void); +void omap4_tuna_power_init(void); +void omap4_tuna_sensors_init(void); +void omap4_tuna_pogo_init(void); +int omap4_tuna_connector_init(void); +int tuna_wlan_init(void); +int omap_hsi_init(void); +void omap4_tuna_emif_init(void); +void omap4_ehci_init(void); +void modem_toro_init(void); + +extern struct mmc_platform_data tuna_wifi_data; +extern struct class *sec_class; + +#endif diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index 94c9f64..a54bf6b 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -164,6 +164,12 @@ int omap4_prcm_freq_update(void) if (i == MAX_FREQ_UPDATE_TIMEOUT) { pr_err("%s: Frequency update failed (call from %pF)\n", __func__, (void *)_RET_IP_); + pr_err("CLKCTRL: EMIF_1=0x%x EMIF_2=0x%x DMM=0x%x\n", + __raw_readl(OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL), + __raw_readl(OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL), + __raw_readl(OMAP4430_CM_MEMIF_DMM_CLKCTRL)); + emif_dump(0); + emif_dump(1); return -1; } diff --git a/arch/arm/mach-omap2/emif.c b/arch/arm/mach-omap2/emif.c index f634083..4905ac4 100644 --- a/arch/arm/mach-omap2/emif.c +++ b/arch/arm/mach-omap2/emif.c @@ -60,6 +60,20 @@ static struct omap_device_pm_latency omap_emif_latency[] = { }, }; +static u32 get_temperature_level(u32 emif_nr); + +void emif_dump(int emif_nr) +{ + void __iomem *base = emif[emif_nr].base; + + printk("EMIF%d s=0x%x is_sys=0x%x is_ll=0x%x temp=0x%02x\n", + emif_nr + 1, + __raw_readl(base + OMAP44XX_EMIF_STATUS), + __raw_readl(base + OMAP44XX_EMIF_IRQSTATUS_SYS), + __raw_readl(base + OMAP44XX_EMIF_IRQSTATUS_LL), + get_temperature_level(emif_nr)); +} + static void do_cancel_out(u32 *num, u32 *den, u32 factor) { while (1) { diff --git a/arch/arm/mach-omap2/include/mach/emif.h b/arch/arm/mach-omap2/include/mach/emif.h index e6860b7..14d0eb7 100644 --- a/arch/arm/mach-omap2/include/mach/emif.h +++ b/arch/arm/mach-omap2/include/mach/emif.h @@ -286,4 +286,5 @@ int omap_emif_setup_device_details( const struct emif_device_details *emif2_devices); void emif_clear_irq(int emif_id); +void emif_dump(int emif_nr); #endif diff --git a/arch/arm/mach-omap2/include/mach/omap4-common.h b/arch/arm/mach-omap2/include/mach/omap4-common.h index 0489ebe..3c1b505 100644 --- a/arch/arm/mach-omap2/include/mach/omap4-common.h +++ b/arch/arm/mach-omap2/include/mach/omap4-common.h @@ -25,6 +25,7 @@ /* * Secure HAL, PPA services available */ +#define PPA_SERVICE_0 0x21 #define PPA_SERVICE_PL310_POR 0x23 #define PPA_SERVICE_DEFAULT_POR_NS_SMP 0x25 /* diff --git a/arch/arm/mach-omap2/include/mach/tf_mshield.h b/arch/arm/mach-omap2/include/mach/tf_mshield.h new file mode 100644 index 0000000..52f98bf --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/tf_mshield.h @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2010 Trusted Logic S.A. + * + * 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. + */ + +#ifdef CONFIG_SECURITY_MIDDLEWARE_COMPONENT +void tf_allocate_workspace(void); +#endif diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index b5c8e80..6694dfb 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -44,6 +44,7 @@ #include "clockdomain.h" #include <plat/omap_hwmod.h> #include <plat/multi.h> +#include <mach/tf_mshield.h> /* * The machine specific code may provide the extra mapping besides the @@ -251,6 +252,9 @@ static void __init _omap2_map_common_io(void) omap2_check_revision(); omap_sram_init(); +#ifdef CONFIG_SECURITY_MIDDLEWARE_COMPONENT + tf_allocate_workspace(); +#endif } #ifdef CONFIG_SOC_OMAP2420 diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 4fbb782..a4aa753 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -45,7 +45,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) { /* Enable NS access to SMP bit for this CPU on HS devices */ if (cpu_is_omap443x() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) - omap4_secure_dispatcher(PPA_SERVICE_DEFAULT_POR_NS_SMP, 4, 0, 0, 0, 0, 0); + omap4_secure_dispatcher(PPA_SERVICE_DEFAULT_POR_NS_SMP, FLAG_START_CRITICAL, 0, 0, 0, 0, 0); /* * If any interrupts are already enabled for the primary diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c index 85a34a5..8264509 100644 --- a/arch/arm/mach-omap2/omap2plus-cpufreq.c +++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c @@ -27,6 +27,7 @@ #include <linux/io.h> #include <linux/opp.h> #include <linux/cpu.h> +#include <linux/earlysuspend.h> #include <asm/system.h> #include <asm/smp_plat.h> @@ -58,8 +59,10 @@ static struct device *mpu_dev; static DEFINE_MUTEX(omap_cpufreq_lock); static unsigned int max_thermal; +static unsigned int max_capped; static unsigned int max_freq; static unsigned int current_target_freq; +static unsigned int screen_off_max_freq; static bool omap_cpufreq_ready; static unsigned int omap_getspeed(unsigned int cpu) @@ -89,6 +92,9 @@ static int omap_cpufreq_scale(unsigned int target_freq, unsigned int cur_freq) if (freqs.new > max_thermal) freqs.new = max_thermal; + if (max_capped && freqs.new > max_capped) + freqs.new = max_capped; + if ((freqs.old == freqs.new) && (cur_freq = freqs.new)) return 0; @@ -244,6 +250,46 @@ static int omap_target(struct cpufreq_policy *policy, return ret; } +static void omap_cpu_early_suspend(struct early_suspend *h) +{ + unsigned int cur; + + mutex_lock(&omap_cpufreq_lock); + + if (screen_off_max_freq) { + max_capped = screen_off_max_freq; + + cur = omap_getspeed(0); + if (cur > max_capped) + omap_cpufreq_scale(max_capped, cur); + } + + mutex_unlock(&omap_cpufreq_lock); +} + +static void omap_cpu_late_resume(struct early_suspend *h) +{ + unsigned int cur; + + mutex_lock(&omap_cpufreq_lock); + + if (max_capped) { + max_capped = 0; + + cur = omap_getspeed(0); + if (cur != current_target_freq) + omap_cpufreq_scale(current_target_freq, cur); + } + + mutex_unlock(&omap_cpufreq_lock); +} + +static struct early_suspend omap_cpu_early_suspend_handler = { + .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN, + .suspend = omap_cpu_early_suspend, + .resume = omap_cpu_late_resume, +}; + static inline void freq_table_free(void) { if (atomic_dec_and_test(&freq_table_users)) @@ -320,8 +366,52 @@ static int omap_cpu_exit(struct cpufreq_policy *policy) return 0; } +static ssize_t show_screen_off_freq(struct cpufreq_policy *policy, char *buf) +{ + return sprintf(buf, "%u\n", screen_off_max_freq); +} + +static ssize_t store_screen_off_freq(struct cpufreq_policy *policy, + const char *buf, size_t count) +{ + unsigned int freq = 0; + int ret; + int index; + + if (!freq_table) + return -EINVAL; + + ret = sscanf(buf, "%u", &freq); + if (ret != 1) + return -EINVAL; + + mutex_lock(&omap_cpufreq_lock); + + ret = cpufreq_frequency_table_target(policy, freq_table, freq, + CPUFREQ_RELATION_H, &index); + if (ret) + goto out; + + screen_off_max_freq = freq_table[index].frequency; + + ret = count; + +out: + mutex_unlock(&omap_cpufreq_lock); + return ret; +} + +struct freq_attr omap_cpufreq_attr_screen_off_freq = { + .attr = { .name = "screen_off_max_freq", + .mode = 0644, + }, + .show = show_screen_off_freq, + .store = store_screen_off_freq, +}; + static struct freq_attr *omap_cpufreq_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, + &omap_cpufreq_attr_screen_off_freq, NULL, }; @@ -360,6 +450,8 @@ static int __init omap_cpufreq_init(void) return -EINVAL; } + register_early_suspend(&omap_cpu_early_suspend_handler); + ret = cpufreq_register_driver(&omap_driver); omap_cpufreq_ready = !ret; return ret; @@ -368,6 +460,8 @@ static int __init omap_cpufreq_init(void) static void __exit omap_cpufreq_exit(void) { cpufreq_unregister_driver(&omap_driver); + + unregister_early_suspend(&omap_cpu_early_suspend_handler); } MODULE_DESCRIPTION("cpufreq driver for OMAP2PLUS SOCs"); diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 9f040c8..b5775a5 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -273,6 +273,7 @@ static int __init omap_barriers_init(void) } core_initcall(omap_barriers_init); +#ifndef CONFIG_SECURITY_MIDDLEWARE_COMPONENT /* * omap4_sec_dispatcher: Routine to dispatch low power secure * service routines @@ -323,3 +324,4 @@ u32 omap4_secure_dispatcher(u32 idx, u32 flag, u32 nargs, u32 arg1, u32 arg2, return ret; } +#endif diff --git a/arch/arm/mach-omap2/omap4-mpuss-lowpower.c b/arch/arm/mach-omap2/omap4-mpuss-lowpower.c index c4855d9..4179e2e 100644 --- a/arch/arm/mach-omap2/omap4-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap4-mpuss-lowpower.c @@ -586,7 +586,7 @@ cpu_prepare: */ wakeup_cpu = hard_smp_processor_id(); set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON); - + omap4_secure_dispatcher(PPA_SERVICE_0, FLAG_START_CRITICAL, 0, 0, 0, 0, 0); if (cpu) gic_restore_ppi(); @@ -625,7 +625,12 @@ cpu_prepare: if ((omap4_device_prev_state_off()) && (omap_type() != OMAP2_DEVICE_TYPE_GP)) { - omap4_secure_dispatcher(0x21, 4, 0, 0, 0, 0, 0); + /* + * Dummy dispatcher call after resuming from off mode. + * Restore the right return Kernel address (with MMU on) for subsequent + * calls to secure ROM after we have hit OFF. + */ + omap4_secure_dispatcher(PPA_SERVICE_0, FLAG_START_CRITICAL, 0, 0, 0, 0, 0); restore_ivahd_tesla_regs(); restore_l3instr_regs(); } diff --git a/arch/arm/mach-omap2/omap_hsi.c b/arch/arm/mach-omap2/omap_hsi.c index ce8fa54..87d8bcf 100644 --- a/arch/arm/mach-omap2/omap_hsi.c +++ b/arch/arm/mach-omap2/omap_hsi.c @@ -25,8 +25,6 @@ #include <linux/notifier.h> #include <linux/hsi_driver_if.h> -#include <asm/clkdev.h> - #include <plat/omap_hsi.h> #include <plat/omap_hwmod.h> #include <plat/omap_device.h> @@ -35,6 +33,8 @@ #include "clock.h" #include "mux.h" #include "control.h" +#include "pm.h" +#include "dvfs.h" static int omap_hsi_wakeup_enable(int hsi_port); static int omap_hsi_wakeup_disable(int hsi_port); @@ -42,8 +42,6 @@ static int omap_hsi_wakeup_disable(int hsi_port); #define OMAP_HSI_PLATFORM_DEVICE_NAME "omap_hsi.0" #define OMAP_HSI_HWMOD_NAME "hsi" #define OMAP_HSI_HWMOD_CLASSNAME "hsi" -#define OMAP_HSI_PADCONF_CAWAKE_PIN "usbb1_ulpitll_clk.hsi1_cawake" -#define OMAP_HSI_PADCONF_CAWAKE_MODE OMAP_MUX_MODE1 #define OMAP_MUX_MODE_MASK 0x7 @@ -85,8 +83,9 @@ static int omap_mux_disable_wakeup(const char *muxname) */ -static struct port_ctx hsi_port_ctx[] = { +static struct hsi_port_ctx omap_hsi_port_ctx[] = { [0] = { + .port_number = 1, .hst.mode = HSI_MODE_FRAME, .hst.flow = HSI_FLOW_SYNCHRONIZED, .hst.frame_size = HSI_FRAMESIZE_DEFAULT, @@ -101,24 +100,28 @@ static struct port_ctx hsi_port_ctx[] = { .hsr.counters = HSI_COUNTERS_FT_DEFAULT | HSI_COUNTERS_TB_DEFAULT | HSI_COUNTERS_FB_DEFAULT, + .cawake_padconf_name = "usbb1_ulpitll_clk.hsi1_cawake", + .cawake_padconf_hsi_mode = OMAP_MUX_MODE1, }, }; -static struct ctrl_ctx hsi_ctx = { +static struct hsi_ctrl_ctx omap_hsi_ctrl_ctx = { .sysconfig = 0, .gdd_gcr = 0, .dll = 0, - .pctx = hsi_port_ctx, + .pctx = omap_hsi_port_ctx, }; static struct hsi_platform_data omap_hsi_platform_data = { - .num_ports = ARRAY_SIZE(hsi_port_ctx), + .num_ports = ARRAY_SIZE(omap_hsi_port_ctx), .hsi_gdd_chan_count = HSI_HSI_DMA_CHANNEL_MAX, .default_hsi_fclk = HSI_DEFAULT_FCLK, - .ctx = &hsi_ctx, + .fifo_mapping_strategy = HSI_FIFO_MAPPING_ALL_PORT1, + .ctx = &omap_hsi_ctrl_ctx, .device_enable = omap_device_enable, .device_idle = omap_device_idle, .device_shutdown = omap_device_shutdown, + .device_scale = omap_device_scale, .wakeup_enable = omap_hsi_wakeup_enable, .wakeup_disable = omap_hsi_wakeup_disable, .wakeup_is_from_hsi = omap_hsi_is_io_wakeup_from_hsi, @@ -167,23 +170,49 @@ static struct hsi_dev *hsi_get_hsi_controller_data(struct platform_device *pd) } /** +* hsi_get_hsi_port_ctx_data - Returns a pointer on the port context +* +* @hsi_port - port number to obtain context. Range [1, 2] +* +* Return value :* If success: pointer on the HSI port context requested +* * else NULL +*/ +static struct hsi_port_ctx *hsi_get_hsi_port_ctx_data(int hsi_port) +{ + int i; + + for (i = 0; i < omap_hsi_platform_data.num_ports; i++) + if (omap_hsi_platform_data.ctx->pctx[i].port_number == hsi_port) + return &omap_hsi_platform_data.ctx->pctx[i]; + + return NULL; +} + +/** * omap_hsi_is_io_pad_hsi - Indicates if IO Pad has been muxed for HSI CAWAKE * +* @hsi_port - port number to check for HSI muxing. Range [1, 2] +* * Return value :* 0 if CAWAKE Padconf has not been found or CAWAKE not muxed for * CAWAKE * * else 1 */ -static int omap_hsi_is_io_pad_hsi(void) +static int omap_hsi_is_io_pad_hsi(int hsi_port) { + struct hsi_port_ctx *port_ctx; u16 val; + port_ctx = hsi_get_hsi_port_ctx_data(hsi_port); + if (!port_ctx) + return 0; + /* Check for IO pad */ - val = omap_mux_read_signal(OMAP_HSI_PADCONF_CAWAKE_PIN); + val = omap_mux_read_signal(port_ctx->cawake_padconf_name); if (val == -ENODEV) return 0; /* Continue only if CAWAKE is muxed */ - if ((val & OMAP_MUX_MODE_MASK) != OMAP_HSI_PADCONF_CAWAKE_MODE) + if ((val & OMAP_MUX_MODE_MASK) != port_ctx->cawake_padconf_hsi_mode) return 0; return 1; @@ -192,49 +221,66 @@ static int omap_hsi_is_io_pad_hsi(void) /** * omap_hsi_is_io_wakeup_from_hsi - Indicates an IO wakeup from HSI CAWAKE * -* Return value :* 0 if CAWAKE Padconf has not been found or no IOWAKEUP event -* occured for CAWAKE -* * else 1 -* TODO : return value should indicate the HSI port which has awaken +* @hsi_port - returns port number which triggered wakeup. Range [1, 2]. +* Only valid if return value is 1 (HSI wakeup detected) +* +* Return value :* false if CAWAKE Padconf has not been found or no IOWAKEUP event +* occured for CAWAKE. +* * true if HSI wakeup detected on port *hsi_port */ -int omap_hsi_is_io_wakeup_from_hsi(void) +bool omap_hsi_is_io_wakeup_from_hsi(int *hsi_port) { + struct hsi_port_ctx *port_ctx; u16 val; + int i; + + for (i = 0; i < omap_hsi_platform_data.num_ports; i++) { + port_ctx = &omap_hsi_platform_data.ctx->pctx[i]; /* Check for IO pad wakeup */ - val = omap_mux_read_signal(OMAP_HSI_PADCONF_CAWAKE_PIN); + val = omap_mux_read_signal(port_ctx->cawake_padconf_name); if (val == -ENODEV) - return 0; + continue; /* Continue only if CAWAKE is muxed */ - if ((val & OMAP_MUX_MODE_MASK) != OMAP_HSI_PADCONF_CAWAKE_MODE) - return 0; + if ((val & OMAP_MUX_MODE_MASK) != + port_ctx->cawake_padconf_hsi_mode) + continue; + + if (val & OMAP44XX_PADCONF_WAKEUPEVENT0) { + *hsi_port = port_ctx->port_number; + return true; + } + } - if (val & OMAP44XX_PADCONF_WAKEUPEVENT0) - return 1; + *hsi_port = 0; - return 0; + return false; } /** * omap_hsi_wakeup_enable - Enable HSI wakeup feature from RET/OFF mode * * @hsi_port - reference to the HSI port onto which enable wakeup feature. +* Range [1, 2] * * Return value :* 0 if CAWAKE has been configured to wakeup platform * * -ENODEV if CAWAKE is not muxed on padconf */ static int omap_hsi_wakeup_enable(int hsi_port) { + struct hsi_port_ctx *port_ctx; int ret = -ENODEV; - if (omap_hsi_is_io_pad_hsi()) - ret = omap_mux_enable_wakeup(OMAP_HSI_PADCONF_CAWAKE_PIN); - else - pr_debug("Trying to enable HSI IO wakeup on non HSI board\n"); - + if (omap_hsi_is_io_pad_hsi(hsi_port)) { + port_ctx = hsi_get_hsi_port_ctx_data(hsi_port); + ret = omap_mux_enable_wakeup(port_ctx->cawake_padconf_name); + omap4_trigger_ioctrl(); + } else { + pr_debug("HSI port %d not muxed, failed to enable IO wakeup\n", + hsi_port); + } - /* TODO: handle hsi_port param and use it to find the correct Pad */ return ret; } @@ -242,21 +288,24 @@ static int omap_hsi_wakeup_enable(int hsi_port) * omap_hsi_wakeup_disable - Disable HSI wakeup feature from RET/OFF mode * * @hsi_port - reference to the HSI port onto which disable wakeup feature. +* Range [1, 2] * * Return value :* 0 if CAWAKE has been configured to not wakeup platform * * -ENODEV if CAWAKE is not muxed on padconf */ static int omap_hsi_wakeup_disable(int hsi_port) { + struct hsi_port_ctx *port_ctx; int ret = -ENODEV; - if (omap_hsi_is_io_pad_hsi()) - ret = omap_mux_disable_wakeup(OMAP_HSI_PADCONF_CAWAKE_PIN); - else - pr_debug("Trying to disable HSI IO wakeup on non HSI board\n"); - - - /* TODO: handle hsi_port param and use it to find the correct Pad */ + if (omap_hsi_is_io_pad_hsi(hsi_port)) { + port_ctx = hsi_get_hsi_port_ctx_data(hsi_port); + ret = omap_mux_disable_wakeup(port_ctx->cawake_padconf_name); + omap4_trigger_ioctrl(); + } else { + pr_debug("HSI port %d not muxed, failed to disable IO wakeup\n", + hsi_port); + } return ret; } @@ -264,6 +313,9 @@ static int omap_hsi_wakeup_disable(int hsi_port) /** * omap_hsi_prepare_suspend - Prepare HSI for suspend mode * +* @hsi_port - reference to the HSI port. Range [1, 2] +* @dev_may_wakeup - value of sysfs flag indicating device wakeup capability +* * Return value :* 0 if CAWAKE padconf has been configured properly * * -ENODEV if CAWAKE is not muxed on padconf. * @@ -281,42 +333,79 @@ int omap_hsi_prepare_suspend(int hsi_port, bool dev_may_wakeup) } /** +* omap_hsi_io_wakeup_check - Check if IO wakeup is from HSI and schedule HSI +* processing tasklet +* +* Return value : * 0 if HSI tasklet scheduled. +* * negative value else. +*/ +int omap_hsi_io_wakeup_check(void) +{ + int hsi_port, ret = -1; + + /* Modem HSI wakeup */ + if (omap_hsi_is_io_wakeup_from_hsi(&hsi_port)) + ret = omap_hsi_wakeup(hsi_port); + + return ret; +} + +/** * omap_hsi_wakeup - Prepare HSI for wakeup from suspend mode (RET/OFF) * -* Return value : 1 if IO wakeup source is HSI -* 0 if IO wakeup source is not HSI. +* @hsi_port - reference to the HSI port which triggered wakeup. +* Range [1, 2] +* +* Return value : * 0 if HSI tasklet scheduled. +* * negative value else. */ int omap_hsi_wakeup(int hsi_port) { static struct platform_device *pdev; static struct hsi_dev *hsi_ctrl; + int i; if (!pdev) { - pdev = hsi_get_hsi_platform_device(); + pdev = hsi_get_hsi_platform_device(); if (!pdev) - return -ENODEV; -} + return -ENODEV; + } if (!device_may_wakeup(&pdev->dev)) { - dev_info(&pdev->dev, "Modem not allowed to wakeup platform"); + dev_info(&pdev->dev, "Modem not allowed to wakeup platform\n"); return -EPERM; } if (!hsi_ctrl) { - hsi_ctrl = hsi_get_hsi_controller_data(pdev); - if (!hsi_ctrl) - return -ENODEV; + hsi_ctrl = hsi_get_hsi_controller_data(pdev); + if (!hsi_ctrl) + return -ENODEV; } - dev_dbg(hsi_ctrl->dev, "Modem wakeup detected from HSI CAWAKE Pad"); + for (i = 0; i < omap_hsi_platform_data.num_ports; i++) { + if (omap_hsi_platform_data.ctx->pctx[i].port_number == hsi_port) + break; + } + + if (i == omap_hsi_platform_data.num_ports) + return -ENODEV; + + + /* Check no other interrupt handler has already scheduled the tasklet */ + if (test_and_set_bit(HSI_FLAGS_TASKLET_LOCK, + &hsi_ctrl->hsi_port[i].flags)) + return -EBUSY; + + dev_dbg(hsi_ctrl->dev, "Modem wakeup detected from HSI CAWAKE Pad port " + "%d\n", hsi_port); /* CAWAKE falling or rising edge detected */ - hsi_ctrl->hsi_port->cawake_off_event = true; - tasklet_hi_schedule(&hsi_ctrl->hsi_port->hsi_tasklet); + hsi_ctrl->hsi_port[i].cawake_off_event = true; + tasklet_hi_schedule(&hsi_ctrl->hsi_port[i].hsi_tasklet); /* Disable interrupt until Bottom Half has cleared */ /* the IRQ status register */ - disable_irq_nosync(hsi_ctrl->hsi_port->irq); + disable_irq_nosync(hsi_ctrl->hsi_port[i].irq); return 0; } diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 12f729d..8c5bb89 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -1059,7 +1059,7 @@ static struct omap_hwmod_class omap44xx_ctrl_module_hwmod_class = { static struct omap_hwmod omap44xx_ctrl_module_core_hwmod; static struct omap_hwmod_irq_info omap44xx_ctrl_module_core_irqs[] = { { .name = "sec_evts", .irq = 8 + OMAP44XX_IRQ_GIC_START }, - { .name = "thermal_alert", .irq = 126 + OMAP44XX_IRQ_GIC_START }, + { .name = "thermal_alert", .irq = 127 + OMAP44XX_IRQ_GIC_START }, }; static struct omap_hwmod_addr_space omap44xx_ctrl_module_core_addrs[] = { @@ -1106,7 +1106,7 @@ static struct omap_hwmod_class omap44xx_thermal_sensor_hwmod_class = { }; static struct omap_hwmod_irq_info omap44xx_thermal_sensor_irqs[] = { - { .name = "thermal_alert", .irq = 126 + OMAP44XX_IRQ_GIC_START }, + { .name = "thermal_alert", .irq = 127 + OMAP44XX_IRQ_GIC_START }, }; static struct omap_hwmod_addr_space omap44xx_thermal_sensor_addrs[] = { diff --git a/arch/arm/mach-omap2/omap_l3_noc.c b/arch/arm/mach-omap2/omap_l3_noc.c index 9d152de..b90bfb0 100644 --- a/arch/arm/mach-omap2/omap_l3_noc.c +++ b/arch/arm/mach-omap2/omap_l3_noc.c @@ -28,11 +28,14 @@ #include <linux/slab.h> #include "omap_l3_noc.h" +#include "board-tuna.h" #define NUM_OF_L3_MASTERS ARRAY_SIZE(l3_masters) static void l3_dump_targ_context(u32 baseaddr) { + extern void print_async_list(void); + pr_err("COREREG : 0x%08x\n", readl(baseaddr + L3_COREREG)); pr_err("VERSIONREG : 0x%08x\n", readl(baseaddr + L3_VERSIONREG)); pr_err("MAINCTLREG : 0x%08x\n", readl(baseaddr + L3_MAINCTLREG)); @@ -50,6 +53,12 @@ static void l3_dump_targ_context(u32 baseaddr) pr_err("CUSTOMINFO_MSTADDR: 0x%08x\n", readl(baseaddr + L3_CUSTOMINFO_MSTADDR)); pr_err("CUSTOMINFO_OPCODE : 0x%08x\n", readl(baseaddr + L3_CUSTOMINFO_OPCODE)); pr_err("ADDRSPACESIZELOG : 0x%08x\n", readl(baseaddr + L3_ADDRSPACESIZELOG)); + + /* Identified as USBHOST EHCI error */ + if ((readl(baseaddr + L3_MSTADDR) == 0xc0) && + (readl(baseaddr + L3_SLVADDR) == 0x3)) + if (omap4_tuna_get_type() == TUNA_TYPE_TORO) + print_async_list(); } /* diff --git a/arch/arm/mach-omap2/opp4xxx_data.c b/arch/arm/mach-omap2/opp4xxx_data.c index 255f132..c0fd100 100644 --- a/arch/arm/mach-omap2/opp4xxx_data.c +++ b/arch/arm/mach-omap2/opp4xxx_data.c @@ -324,8 +324,9 @@ int __init omap4_opp_init(void) if (!r) { if (omap4_has_mpu_1_2ghz()) omap4_mpu_opp_enable(1200000000); - if (omap4_has_mpu_1_5ghz()) - omap4_mpu_opp_enable(1500000000); + /* The tuna PCB doesn't support 1.5GHz, so disable it for now */ + /*if (omap4_has_mpu_1_5ghz()) + omap4_mpu_opp_enable(1500000000);*/ } return r; diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 6cfd501..7025e3a 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -76,8 +76,15 @@ static struct powerdomain *tesla_pwrdm; /* Yet un-named erratum which requires AUTORET to be disabled for IVA PD */ #define OMAP4_PM_ERRATUM_IVA_AUTO_RET_iXXX BIT(1) +/* +* HSI - OMAP4430-2.2BUG00055: +* HSI: DSP Swakeup generated is the same than MPU Swakeup. +* System can’t enter in off mode due to the DSP. +*/ +#define OMAP4_PM_ERRATUM_HSI_SWAKEUP_iXXX BIT(2) + -static u8 pm44xx_errata; +u8 pm44xx_errata; #define is_pm44xx_erratum(erratum) (pm44xx_errata & OMAP4_PM_ERRATUM_##erratum) #define MAX_IOPAD_LATCH_TIME 1000 @@ -872,7 +879,7 @@ static void __init prcm_setup_regs(void) * * Bug ref is HSI-C1BUG00106 : dsp swakeup generated by HSI same as mpu swakeup */ -static void omap_pm_clear_dsp_wake_up(void) +void omap_pm_clear_dsp_wake_up(void) { int ret; int timeout = 10; @@ -927,6 +934,7 @@ static void omap_pm_clear_dsp_wake_up(void) static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) { u32 irqenable_mpu, irqstatus_mpu; + int hsi_port; irqenable_mpu = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, OMAP4_PRM_IRQENABLE_MPU_OFFSET); @@ -936,9 +944,8 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) /* Check if a IO_ST interrupt */ if (irqstatus_mpu & OMAP4430_IO_ST_MASK) { /* Check if HSI caused the IO wakeup */ - if (omap_hsi_is_io_wakeup_from_hsi()) { - omap_pm_clear_dsp_wake_up(); - omap_hsi_wakeup(0); + if (omap_hsi_is_io_wakeup_from_hsi(&hsi_port)) { + omap_hsi_wakeup(hsi_port); } omap_uart_resume_idle(); usbhs_wakeup(); @@ -1044,7 +1051,8 @@ static void __init omap4_pm_setup_errata(void) * all OMAP4 silica */ if (cpu_is_omap44xx()) - pm44xx_errata |= OMAP4_PM_ERRATUM_IVA_AUTO_RET_iXXX; + pm44xx_errata |= OMAP4_PM_ERRATUM_IVA_AUTO_RET_iXXX | + OMAP4_PM_ERRATUM_HSI_SWAKEUP_iXXX; } /** diff --git a/arch/arm/plat-omap/include/plat/board-tuna-bluetooth.h b/arch/arm/plat-omap/include/plat/board-tuna-bluetooth.h new file mode 100644 index 0000000..c74de05 --- /dev/null +++ b/arch/arm/plat-omap/include/plat/board-tuna-bluetooth.h @@ -0,0 +1,30 @@ +/* + * Bluetooth Broadcomm and low power control via GPIO + * + * Copyright (C) 2011 Samsung, Inc. + * Copyright (C) 2011 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __BOARD_TUNA_BLUETOOTH_H__ +#define __BOARD_TUNA_BLUETOOTH_H__ + +#include <linux/serial_core.h> + +extern void bcm_bt_lpm_exit_lpm_locked(struct uart_port *uport); + +#endif /* __BOARD_TUNA_BLUETOOTH_H__ */ diff --git a/arch/arm/plat-omap/include/plat/omap_hsi.h b/arch/arm/plat-omap/include/plat/omap_hsi.h index 1a75ed4..ba2c8e3 100644 --- a/arch/arm/plat-omap/include/plat/omap_hsi.h +++ b/arch/arm/plat-omap/include/plat/omap_hsi.h @@ -259,6 +259,11 @@ #define HSI_HSR_ERROR_TBE (1 << 4) /* HSI only */ #define HSI_HSR_ERROR_RME (1 << 7) /* HSI only */ #define HSI_HSR_ERROR_TME (1 << 11) /* HSI only */ +#define HSI_HSR_ERROR_ALL (HSI_HSR_ERROR_SIG | \ + HSI_HSR_ERROR_FTE | \ + HSI_HSR_ERROR_TBE | \ + HSI_HSR_ERROR_RME | \ + HSI_HSR_ERROR_TME) #define HSI_HSR_ERRORACK_REG(port) (HSI_HSR_BASE(port) + 0x0024) @@ -479,16 +484,15 @@ extern int omap_hsi_config(struct omap_hsi_board_config *hsi_config); #ifdef CONFIG_OMAP_HSI extern int omap_hsi_prepare_suspend(int hsi_port, bool dev_may_wakeup); -extern int omap_hsi_prepare_idle(void); +extern int omap_hsi_io_wakeup_check(void); extern int omap_hsi_wakeup(int hsi_port); -extern int omap_hsi_is_io_wakeup_from_hsi(void); +extern bool omap_hsi_is_io_wakeup_from_hsi(int *hsi_port); #else inline int omap_hsi_prepare_suspend(int hsi_port, bool dev_may_wakeup) { return -ENOSYS; } -inline int omap_hsi_prepare_idle(void) { return -ENOSYS; } +inline int omap_hsi_io_wakeup_check(void) { return -ENOSYS; } inline int omap_hsi_wakeup(int hsi_port) { return -ENOSYS; } -inline int omap_hsi_is_io_wakeup_from_hsi(void) { return -ENOSYS; } - +inline bool omap_hsi_is_io_wakeup_from_hsi(int *hsi_port) { return false; } #endif #endif /* __OMAP_HSI_H__ */ diff --git a/arch/arm/plat-omap/include/plat/uncompress.h b/arch/arm/plat-omap/include/plat/uncompress.h index ac4b60d..cf07178 100644 --- a/arch/arm/plat-omap/include/plat/uncompress.h +++ b/arch/arm/plat-omap/include/plat/uncompress.h @@ -164,6 +164,7 @@ static inline void __arch_decomp_setup(unsigned long arch_id) /* omap4 based boards using UART3 */ DEBUG_LL_OMAP4(3, omap_4430sdp); DEBUG_LL_OMAP4(3, omap4_panda); + DEBUG_LL_OMAP4(3, tuna); /* zoom2/3 external uart */ DEBUG_LL_ZOOM(omap_zoom2); |